diff --git a/BasiliskII/src/Unix/CMakeLists.txt b/BasiliskII/src/Unix/CMakeLists.txt index e222edc3..0711d0d7 100644 --- a/BasiliskII/src/Unix/CMakeLists.txt +++ b/BasiliskII/src/Unix/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.0.0) project(BasiliskII) -if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt) - if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) - endif() -endif() +# if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt) +# if (NOT CMAKE_BUILD_TYPE) +# set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) +# endif() +# endif() find_package(SDL2 REQUIRED) find_library(COREFOUNDATION_LIBRARY CoreFoundation) @@ -21,7 +21,9 @@ add_custom_command(OUTPUT cpudefs.cpp add_executable(gencpu ../uae_cpu/gencpu.c ../uae_cpu/readcpu.cpp cpudefs.cpp) #add_custom_command(OUTPUT cpuemu.cpp cpustbl.cpp cpufunctbl.cpp COMMAND gencpu DEPENDS gencpu) -add_custom_command(OUTPUT cpuemu.cpp cpuemu_nf.cpp cpustbl.cpp cpustbl_nf.cpp COMMAND gencpu DEPENDS gencpu) +# add_custom_command(OUTPUT cpuemu.cpp cpuemu_nf.cpp cpustbl.cpp cpustbl_nf.cpp COMMAND gencpu DEPENDS gencpu) +# add_custom_command(OUTPUT cpuemu.cpp cpuemu_nf.cpp cpustbl.cpp cpustbl_nf.cpp COMMAND gencpu DEPENDS gencpu) +add_custom_command(OUTPUT cpuemu.cpp cpustbl.cpp cpufunctbl.cpp COMMAND gencpu DEPENDS gencpu) add_executable(gencomp ../uae_cpu/compiler/gencomp.c ../uae_cpu/readcpu.cpp cpudefs.cpp) @@ -88,12 +90,11 @@ set(BasiliskII_SRCS cpustbl.cpp cpudefs.cpp cpuemu.cpp + cpufunctbl.cpp compemu.cpp compstbl.cpp ../uae_cpu/compiler/compemu_support.cpp ../uae_cpu/compiler/compemu_fpp.cpp - cpustbl_nf.cpp - cpuemu_nf.cpp #addressing mode =direct -DDIRECT_ADDRESSING #includes ) @@ -101,7 +102,7 @@ set(BasiliskII_SRCS add_executable(BasiliskII ${BasiliskII_SRCS}) set_source_files_properties(${BasiliskII_SRCS} - PROPERTIES COMPILE_FLAGS "-DDIRECT_ADDRESSING -DCPU_x86_64 -DFIXED_ADDRESSING -DCPU_64_BIT -DNOFLAGS_SUPPORT -DFPU_IEEE -DUSE_JIT -DJIT -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS -DWINUAE_ARANYM -DUSE_JIT_FPU -DUSE_INLINING -DDATADIR=\\\".\\\"") + PROPERTIES COMPILE_FLAGS "-DDIRECT_ADDRESSING -DCPU_x86_64 -DFIXED_ADDRESSING -DCPU_64_BIT -DFPU_IEEE -DUSE_JIT -DJIT -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS -DWINUAE_ARANYM -DUSE_JIT_FPU -DUSE_INLINING -DDATADIR=\\\".\\\"") # set_property(SOURCE compemu_support.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -O0 ") diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index 6d17121f..f7dcc682 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -58,6 +58,7 @@ using std::string; #if USE_JIT extern void (*flush_icache)(void); // from compemu_support.cpp +extern bool UseJIT; #endif @@ -181,8 +182,8 @@ static void sigsegv_dump_state(sigsegv_info_t *sip) fprintf(stderr, " [IP=%p]", fault_instruction); fprintf(stderr, "\n"); #if EMULATED_68K - extern void m68k_dumpstate (uaecptr *); - m68k_dumpstate(0); + extern void m68k_dumpstate (FILE *, uaecptr *); + m68k_dumpstate(stderr, 0); #endif #if USE_JIT && JIT_DEBUG extern void compiler_dumpstate(void); diff --git a/BasiliskII/src/Unix/sysdeps.h b/BasiliskII/src/Unix/sysdeps.h index b25ee042..1a1f12a8 100644 --- a/BasiliskII/src/Unix/sysdeps.h +++ b/BasiliskII/src/Unix/sysdeps.h @@ -419,6 +419,13 @@ static inline uae_u32 do_byteswap_16(uae_u32 v) # define REGPARAM #endif #define REGPARAM2 + +#if __GNUC__ < 3 +# define __builtin_expect(foo,bar) (foo) +#endif +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define ALWAYS_INLINE inline __attribute__((always_inline)) #define memptr uint32 diff --git a/BasiliskII/src/emul_op.cpp b/BasiliskII/src/emul_op.cpp index 549d1de0..25679f70 100644 --- a/BasiliskII/src/emul_op.cpp +++ b/BasiliskII/src/emul_op.cpp @@ -51,7 +51,7 @@ * Execute EMUL_OP opcode (called by 68k emulator or Illegal Instruction trap handler) */ -void EmulOp(uint16 opcode, M68kRegisters *r) +bool EmulOp(uint16 opcode, M68kRegisters *r) { D(bug("EmulOp %04x\n", opcode)); switch (opcode) { @@ -68,12 +68,12 @@ void EmulOp(uint16 opcode, M68kRegisters *r) VideoQuitFullScreen(); QuitEmulator(); - break; + return false; } case M68K_EMUL_OP_SHUTDOWN: // Quit emulator QuitEmulator(); - break; + return false; case M68K_EMUL_OP_RESET: { // MacOS reset D(bug("*** RESET ***\n")); @@ -101,7 +101,7 @@ void EmulOp(uint16 opcode, M68kRegisters *r) r->a[1] = ROMBaseMac + UniversalInfo; // UniversalInfo r->a[6] = boot_globs; // BootGlobs r->a[7] = RAMBaseMac + 0x10000; // Boot stack - break; + return false; } case M68K_EMUL_OP_CLKNOMEM: { // Clock/PRAM operations @@ -570,6 +570,8 @@ void EmulOp(uint16 opcode, M68kRegisters *r) r->sr); QuitEmulator(); - break; + return false; } + + return true; } diff --git a/BasiliskII/src/include/emul_op.h b/BasiliskII/src/include/emul_op.h index b6d3a1e6..5774a580 100644 --- a/BasiliskII/src/include/emul_op.h +++ b/BasiliskII/src/include/emul_op.h @@ -94,6 +94,6 @@ enum { }; // Functions -extern void EmulOp(uint16 opcode, struct M68kRegisters *r); // Execute EMUL_OP opcode (called by 68k emulator or Line-F trap handler) +extern bool EmulOp(uint16 opcode, struct M68kRegisters *r); // Execute EMUL_OP opcode (called by 68k emulator or Line-F trap handler) #endif diff --git a/BasiliskII/src/include/main.h b/BasiliskII/src/include/main.h index 1ba7b6ac..9a78cf6e 100644 --- a/BasiliskII/src/include/main.h +++ b/BasiliskII/src/include/main.h @@ -34,8 +34,10 @@ extern bool TwentyFourBitAddressing; // 68k register structure (for Execute68k()) struct M68kRegisters { uint32 d[8]; - uint32 a[8]; + memptr a[8]; uint16 sr; + memptr usp, isp, msp; + memptr pc; }; // General functions diff --git a/BasiliskII/src/uae_cpu/Makefile.am b/BasiliskII/src/uae_cpu/Makefile.am new file mode 100644 index 00000000..fa42287d --- /dev/null +++ b/BasiliskII/src/uae_cpu/Makefile.am @@ -0,0 +1,80 @@ +# +# Note: this Makefile only contains rules for the source +# generator tools. +# + +# +# suppress warnings about overriding LDFLAGS and CPPFLAGS +# +AUTOMAKE_OPTIONS = -Wno-gnu + +AM_CPPFLAGS = $(DEFINES) \ + "-I$(srcdir)/../include" \ + "-I$(srcdir)/../Unix" \ + "-I$(builddir)/.." \ + "-I$(builddir)" \ + "-I$(srcdir)" + +CC = $(CC_FOR_BUILD) +CXX = $(CXX_FOR_BUILD) + +LDFLAGS = $(LDFLAGS_FOR_BUILD) +CPPFLAGS = $(CPPFLAGS_FOR_BUILD) +CFLAGS = $(CFLAGS_FOR_BUILD) +CXXFLAGS = $(CXXFLAGS_FOR_BUILD) +LIBS=-lm + +CFLAGS_NOWARN = $(DBGSP) +AM_CFLAGS = $(CFLAGS_NOWARN) $(WFLAGS) +AM_CXXFLAGS = $(CFLAGS_NOWARN) $(WFLAGS) + +noinst_PROGRAMS = build68k gencpu +if USE_JIT +noinst_PROGRAMS += gencomp +endif + +BUILT_SOURCES = \ + cpudefs.cpp \ + cpuemu.cpp \ + cpustbl.cpp \ + cpufunctbl.cpp \ + cputbl.h \ + $(empty) + +build68k_SOURCES = build68k.c +gencpu_SOURCES = gencpu.c m68k.h readcpu.cpp readcpu.h cpudefs.cpp +gencomp_SOURCES = +if GENCOMP_ARCH_X86 +gencomp_SOURCES += compiler/gencomp.c +endif +if GENCOMP_ARCH_ARM +gencomp_SOURCES += compiler/gencomp_arm.c +endif +gencomp_SOURCES += readcpu.cpp cpudefs.cpp + +if USE_JIT +BUILT_SOURCES += compemu.cpp compstbl.cpp comptbl.h +endif + + +cpudefs.cpp: build68k$(EXEEXT) $(srcdir)/table68k + $(AM_V_GEN)./build68k <$(srcdir)/table68k > $@ +cpuemu.cpp: gencpu$(EXEEXT) + $(AM_V_GEN)./gencpu$(EXEEXT) +cpustbl.cpp cpufunctbl.cpp cputbl.h: cpuemu.cpp +compemu.cpp: gencomp$(EXEEXT) + $(AM_V_GEN)./gencomp$(EXEEXT) +compstbl.cpp comptbl.h: compemu.cpp + +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = \ + table68k \ + compiler/codegen_arm.cpp compiler/codegen_arm.h \ + compiler/compemu_midfunc_arm.cpp compiler/compemu_midfunc_arm.h \ + compiler/compemu_midfunc_arm2.cpp compiler/compemu_midfunc_arm2.h \ + compiler/test_codegen_arm.c \ + compiler/codegen_x86.cpp compiler/codegen_x86.h \ + compiler/compemu_midfunc_x86.cpp compiler/compemu_midfunc_x86.h \ + compiler/test_codegen_x86.cpp \ + $(empty) diff --git a/BasiliskII/src/uae_cpu/aranym_glue.cpp b/BasiliskII/src/uae_cpu/aranym_glue.cpp new file mode 100644 index 00000000..02f7b149 --- /dev/null +++ b/BasiliskII/src/uae_cpu/aranym_glue.cpp @@ -0,0 +1,326 @@ +/* + * aranym_glue.cpp - CPU interface + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include "cpu_emulation.h" +#include "newcpu.h" +#include "hardware.h" +#include "scc.h" +#include "input.h" +#ifdef USE_JIT +# include "compiler/compemu.h" +#endif +#include "nf_objs.h" + +#include "debug.h" + +// RAM and ROM pointers +memptr RAMBase = 0; // RAM base (Atari address space) gb-- init is important +uint8 *RAMBaseHost; // RAM base (host address space) +uint32 RAMSize = 0x00e00000; // Size of RAM + +memptr ROMBase = 0x00e00000; // ROM base (Atari address space) +uint8 *ROMBaseHost; // ROM base (host address space) +uint32 ROMSize = 0x00100000; // Size of ROM + +uint32 RealROMSize; // Real size of ROM + +memptr HWBase = 0x00f00000; // HW base (Atari address space) +uint8 *HWBaseHost; // HW base (host address space) +uint32 HWSize = 0x00100000; // Size of HW space + +memptr FastRAMBase = 0x01000000; // Fast-RAM base (Atari address space) +uint8 *FastRAMBaseHost; // Fast-RAM base (host address space) + +#ifdef HW_SIGSEGV +uint8 *FakeIOBaseHost; +#endif + +#ifdef FIXED_VIDEORAM +memptr VideoRAMBase = ARANYMVRAMSTART; // VideoRAM base (Atari address space) +#else +memptr VideoRAMBase; // VideoRAM base (Atari address space) +#endif +uint8 *VideoRAMBaseHost;// VideoRAM base (host address space) +//uint32 VideoRAMSize; // Size of VideoRAM + +#ifndef NOT_MALLOC +uintptr MEMBaseDiff; // Global offset between a Atari address and its Host equivalent +uintptr ROMBaseDiff; +uintptr FastRAMBaseDiff; +#endif + +uintptr VMEMBaseDiff; // Global offset between a Atari VideoRAM address and /dev/fb0 mmap + + +#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) +SDL_mutex *spcflags_lock; +#endif +#if defined(ENABLE_REALSTOP) +SDL_cond *stop_condition; +#endif + + +/* + * Initialize 680x0 emulation + */ + +bool InitMEM() { + InitMEMBaseDiff(RAMBaseHost, RAMBase); + InitROMBaseDiff(ROMBaseHost, ROMBase); + InitFastRAMBaseDiff(FastRAMBaseHost, FastRAMBase); + InitVMEMBaseDiff(VideoRAMBaseHost, VideoRAMBase); + return true; +} + +bool Init680x0(void) +{ + init_m68k(); + +#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) + if ((spcflags_lock = SDL_CreateMutex()) == NULL) { + panicbug("Error by SDL_CreateMutex()"); + exit(EXIT_FAILURE); + } +#endif + +#if ENABLE_REALSTOP + if ((stop_condition = SDL_CreateCond()) == NULL) { + panicbug("Error by SDL_CreateCond()"); + exit(EXIT_FAILURE); + } +#endif + +#ifdef USE_JIT + if (bx_options.jit.jit) compiler_init(); +#endif + return true; +} + +/* + * Instr. RESET + */ + +void AtariReset(void) +{ + // reset Atari hardware here + HWReset(); + // reset NatFeats here + NFReset(); + // reset the input devices (input.cpp) + InputReset(); + +} + +/* + * Reset CPU + */ + +void Reset680x0(void) +{ + m68k_reset(); +} + +/* + * Deinitialize 680x0 emulation + */ + +void Exit680x0(void) +{ +#ifdef USE_JIT + if (bx_options.jit.jit) compiler_exit(); +#endif + exit_m68k(); +} + + +/* + * Reset and start 680x0 emulation + */ + +void Start680x0(void) +{ + m68k_reset(); +#ifdef USE_JIT + if (bx_options.jit.jit) { + m68k_compile_execute(); + } + else +#endif + m68k_execute(); +} + +/* + * Restart running 680x0 emulation safely from different thread + */ +void Restart680x0(void) +{ + quit_program = 2; + TriggerNMI(); +} + +/* + * Quit 680x0 emulation safely from different thread + */ +void Quit680x0(void) +{ + quit_program = 1; + TriggerNMI(); +} + + +int MFPdoInterrupt(void) +{ + return getMFP()->doInterrupt(); +} + +int SCCdoInterrupt(void) +{ + return getSCC()->doInterrupt(); +} + +/* + * Trigger interrupts + */ +void TriggerInternalIRQ(void) +{ + SPCFLAGS_SET( SPCFLAG_INTERNAL_IRQ ); +} + +void TriggerInt3(void) +{ + SPCFLAGS_SET( SPCFLAG_INT3 ); +} + +void TriggerVBL(void) +{ + SPCFLAGS_SET( SPCFLAG_VBL ); +} + +void TriggerInt5(void) +{ + SPCFLAGS_SET( SPCFLAG_INT5 ); +} + +void TriggerSCC(bool enable) +{ + if (enable) + SPCFLAGS_SET( SPCFLAG_SCC ); + else + SPCFLAGS_CLEAR( SPCFLAG_SCC ); +} + +void TriggerMFP(bool enable) +{ + if (enable) + SPCFLAGS_SET( SPCFLAG_MFP ); + else + SPCFLAGS_CLEAR( SPCFLAG_MFP ); +} + +void TriggerNMI(void) +{ + SPCFLAGS_SET( SPCFLAG_BRK ); // use _BRK for NMI +} + +#ifndef REBOOT_OR_HALT +#define REBOOT_OR_HALT 0 // halt by default +#endif + +#if REBOOT_OR_HALT == 1 +# define CPU_MSG "CPU: Rebooting" +# define CPU_ACTION Restart680x0() +#else +# define CPU_MSG "CPU: Halting" +# define CPU_ACTION Quit680x0() +#endif + +#ifdef ENABLE_EPSLIMITER + +#ifndef EPS_LIMIT +# define EPS_LIMIT 10000 /* this might be too high if ARAnyM is slowed down by printing the bus errors on console */ +#endif + +void check_eps_limit(uaecptr pc) +{ + static long last_exception_time=-1; + static long exception_per_sec=0; + static long exception_per_sec_pc=0; + static uaecptr prevpc = 0; + + if (bx_options.cpu.eps_enabled) { + if (last_exception_time == -1) { + last_exception_time = SDL_GetTicks(); + } + + exception_per_sec++; + + if (pc == prevpc) { + /* BUS ERRORs occur at the same PC - watch out! */ + exception_per_sec_pc++; + } + else { + exception_per_sec_pc = 0; + prevpc = pc; + } + + if (SDL_GetTicks() - last_exception_time > 1000) { + last_exception_time = SDL_GetTicks(); + if (exception_per_sec_pc > bx_options.cpu.eps_max || + exception_per_sec > EPS_LIMIT /* make it configurable */) { + panicbug("CPU: Exception per second limit reached: %ld/%ld", + exception_per_sec_pc, exception_per_sec); + /* would be cool to open SDL dialog here: */ + /* [Exception per seconds limit reached. XXXXX exception + occured in the last second. The limit is set to YYYYY + in your config file. Do you want to continue emulation, + reset ARAnyM or quit ?][Continue] [Reset] [Quit] + */ + panicbug(CPU_MSG); + CPU_ACTION; + } + exception_per_sec = 0; + exception_per_sec_pc = 0; + } + } +} +#endif + +void report_double_bus_error() +{ + panicbug("CPU: Double bus fault detected !"); + /* would be cool to open SDL dialog here: */ + /* [Double bus fault detected. The emulated system crashed badly. + Do you want to reset ARAnyM or quit ?] [Reset] [Quit]" + */ + panicbug(CPU_MSG); + CPU_ACTION; +} + +#ifdef FLIGHT_RECORDER +extern bool cpu_flight_recorder_active; +void cpu_flight_recorder(int activate) { cpu_flight_recorder_active = activate; } +#endif diff --git a/BasiliskII/src/uae_cpu/basilisk_glue.cpp b/BasiliskII/src/uae_cpu/basilisk_glue.cpp index 6bfadb9d..9a794b48 100644 --- a/BasiliskII/src/uae_cpu/basilisk_glue.cpp +++ b/BasiliskII/src/uae_cpu/basilisk_glue.cpp @@ -56,8 +56,12 @@ uintptr MEMBaseDiff; // Global offset between a Mac address and its Host equiva bool UseJIT = false; #endif +// #if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) +B2_mutex *spcflags_lock = NULL; +// #endif + // From newcpu.cpp -extern bool quit_program; +extern int quit_program; /* @@ -66,6 +70,7 @@ extern bool quit_program; bool Init680x0(void) { + spcflags_lock = B2_create_mutex(); #if REAL_ADDRESSING // Mac address space = host address space RAMBaseMac = (uintptr)RAMBaseHost; @@ -159,7 +164,8 @@ void TriggerInterrupt(void) void TriggerNMI(void) { - SPCFLAGS_SET( SPCFLAG_BRK ); // use _BRK for NMI + //!! not implemented yet + // SPCFLAGS_SET( SPCFLAG_BRK ); // use _BRK for NMI } @@ -200,7 +206,7 @@ void Execute68kTrap(uint16 trap, struct M68kRegisters *r) // Execute trap m68k_setpc(m68k_areg(regs, 7)); fill_prefetch_0(); - quit_program = false; + quit_program = 0; m68k_execute(); // Clean up stack @@ -215,7 +221,7 @@ void Execute68kTrap(uint16 trap, struct M68kRegisters *r) r->d[i] = m68k_dreg(regs, i); for (i=0; i<7; i++) r->a[i] = m68k_areg(regs, i); - quit_program = false; + quit_program = 0; } @@ -247,7 +253,7 @@ void Execute68k(uint32 addr, struct M68kRegisters *r) // Execute routine m68k_setpc(addr); fill_prefetch_0(); - quit_program = false; + quit_program = 0; m68k_execute(); // Clean up stack @@ -262,5 +268,18 @@ void Execute68k(uint32 addr, struct M68kRegisters *r) r->d[i] = m68k_dreg(regs, i); for (i=0; i<7; i++) r->a[i] = m68k_areg(regs, i); - quit_program = false; + quit_program = 0; +} + +void report_double_bus_error() +{ +#if 0 + panicbug("CPU: Double bus fault detected !"); + /* would be cool to open SDL dialog here: */ + /* [Double bus fault detected. The emulated system crashed badly. + Do you want to reset ARAnyM or quit ?] [Reset] [Quit]" + */ + panicbug(CPU_MSG); + CPU_ACTION; +#endif } diff --git a/BasiliskII/src/uae_cpu/build68k.c b/BasiliskII/src/uae_cpu/build68k.c index 8ec3ab55..e996758d 100644 --- a/BasiliskII/src/uae_cpu/build68k.c +++ b/BasiliskII/src/uae_cpu/build68k.c @@ -1,32 +1,44 @@ +/* + * build68k.c - m68k CPU builder + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ /* * UAE - The Un*x Amiga Emulator * * Read 68000 CPU specs from file "table68k" and build table68k.c * * Copyright 1995,1996 Bernd Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include - -#include "sysdeps.h" #include "readcpu.h" +#include +#include +#include +#include +#include +#undef abort + static FILE *tablef; static int nextch = 0; @@ -65,15 +77,15 @@ static int nextchtohex(void) } } -int main(int argc, char **argv) +int main() { int no_insns = 0; printf ("#include \"sysdeps.h\"\n"); printf ("#include \"readcpu.h\"\n"); printf ("struct instr_def defs68k[] = {\n"); -#ifdef WIN32 - tablef = fopen(argc > 1 ? argv[1] : "table68k","r"); +#if 0 + tablef = fopen("table68k","r"); if (tablef == NULL) { fprintf(stderr, "table68k not found\n"); exit(1); @@ -122,8 +134,8 @@ int main(int argc, char **argv) case 'r': currbit = bitr; break; case 'R': currbit = bitR; break; case 'z': currbit = bitz; break; - case 'E': currbit = bitE; break; - case 'p': currbit = bitp; break; + case 'E': currbit = bitE; break; + case 'p': currbit = bitp; break; default: abort(); } if (!(bitmask & 1)) { @@ -138,6 +150,7 @@ int main(int argc, char **argv) patbits[i] = nextch; getnextch(); } + (void) patbits; while (isspace(nextch) || nextch == ':') /* Get CPU and privilege level */ getnextch(); @@ -172,6 +185,8 @@ int main(int argc, char **argv) getnextch(); switch(nextch){ case '-': flagset[i] = fa_unset; break; + case '/': flagset[i] = fa_isjmp; break; + case '+': flagset[i] = fa_isbranch; break; case '0': flagset[i] = fa_zero; break; case '1': flagset[i] = fa_one; break; case 'x': flagset[i] = fa_dontcare; break; @@ -191,6 +206,8 @@ int main(int argc, char **argv) getnextch(); switch(nextch){ case '-': flaguse[i] = fu_unused; break; + case '/': flaguse[i] = fu_isjmp; break; + case '+': flaguse[i] = fu_maybecc; break; case '?': flaguse[i] = fu_unknown; break; default: flaguse[i] = fu_used; break; } @@ -235,7 +252,7 @@ int main(int argc, char **argv) if (nextch != ':') abort(); - fgets(opcstr, 250, tablef); + assert(fgets(opcstr, 250, tablef) != NULL); getnextch(); { int j; @@ -243,12 +260,12 @@ int main(int argc, char **argv) char *opstrp = opcstr, *osendp; int slen = 0; - while (isspace(*opstrp)) + while (isspace((int)*opstrp)) opstrp++; osendp = opstrp; while (*osendp) { - if (!isspace (*osendp)) + if (!isspace ((int)*osendp)) slen = osendp - opstrp + 1; osendp++; } @@ -271,6 +288,5 @@ int main(int argc, char **argv) } } printf("};\nint n_defs68k = %d;\n", no_insns); - fflush(stdout); return 0; } diff --git a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp index 9b178c0f..8932e61d 100644 --- a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp +++ b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp @@ -273,7 +273,7 @@ uae_u8* comp_pc_p; #else // External variables // newcpu.cpp -extern bool quit_program; +extern int quit_program; #endif // gb-- Extra data for Basilisk II/JIT @@ -2718,8 +2718,7 @@ void compiler_init(void) jit_log(" : separate blockinfo allocation : %s", str_on_off(USE_SEPARATE_BIA)); // Build compiler tables - read_table68k(); - do_merges(); + init_table68k (); build_comp(); #endif @@ -4157,7 +4156,9 @@ void build_comp(void) int count; #ifdef WINUAE_ARANYM unsigned int cpu_level = 4; // 68040 +#if 0 const struct cputbl *nfctbl = op_smalltbl_0_nf; +#endif #else #ifdef NOFLAGS_SUPPORT struct comptbl *nfctbl = (currprefs.cpu_level >= 5 ? op_smalltbl_0_nf diff --git a/BasiliskII/src/uae_cpu/compiler/gencomp.c b/BasiliskII/src/uae_cpu/compiler/gencomp.c index 712d7873..202774ac 100644 --- a/BasiliskII/src/uae_cpu/compiler/gencomp.c +++ b/BasiliskII/src/uae_cpu/compiler/gencomp.c @@ -3228,8 +3228,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine int main(void) #endif { - read_table68k (); - do_merges (); + init_table68k (); opcode_map = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc (sizeof (int) * nr_cpuop_funcs); diff --git a/BasiliskII/src/uae_cpu/compiler/gencomp_arm.c b/BasiliskII/src/uae_cpu/compiler/gencomp_arm.c index 7ec9ff76..913361ab 100644 --- a/BasiliskII/src/uae_cpu/compiler/gencomp_arm.c +++ b/BasiliskII/src/uae_cpu/compiler/gencomp_arm.c @@ -5025,8 +5025,7 @@ void cygwin_mingw_abort() int main(void) { - read_table68k(); - do_merges(); + init_table68k (); opcode_map = (int *) malloc(sizeof(int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc(sizeof(int) * nr_cpuop_funcs); diff --git a/BasiliskII/src/uae_cpu/cpu_emulation.h b/BasiliskII/src/uae_cpu/cpu_emulation.h index cd588ec1..b014be79 100644 --- a/BasiliskII/src/uae_cpu/cpu_emulation.h +++ b/BasiliskII/src/uae_cpu/cpu_emulation.h @@ -1,52 +1,170 @@ /* - * cpu_emulation.h - Definitions for Basilisk II CPU emulation module (UAE 0.8.10 version) + * cpu_emulation.h - CPU interface * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2005 Milan Jurik of ARAnyM dev team (see AUTHORS) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Inspired by Christian Bauer's Basilisk II * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CPU_EMULATION_H #define CPU_EMULATION_H -#include - - /* * Memory system */ +#if 0 +#include "sysdeps.h" +#include "memory.h" +#include "tools.h" +#endif + // RAM and ROM pointers (allocated and set by main_*.cpp) +#if 0 +extern memptr RAMBase; // RAM base (Atari address space), does not include Low Mem when != 0 +#else extern uint32 RAMBaseMac; // RAM base (Mac address space), does not include Low Mem when != 0 -extern uint8 *RAMBaseHost; // RAM base (host address space) -extern uint32 RAMSize; // Size of RAM - +#endif +extern uint8 *RAMBaseHost; // RAM base (host address space) +extern uint32 RAMSize; // Size of RAM +#if 0 +extern memptr ROMBase; // ROM base (Atari address space) +#else extern uint32 ROMBaseMac; // ROM base (Mac address space) -extern uint8 *ROMBaseHost; // ROM base (host address space) -extern uint32 ROMSize; // Size of ROM +#endif +extern uint8 *ROMBaseHost; // ROM base (host address space) +extern uint32 ROMSize; // Size of ROM +#if 0 +extern uint32 RealROMSize; // Real size of ROM +extern memptr HWBase; // HW base (Atari address space) +extern uint8 *HWBaseHost; // HW base (host address space) +extern uint32 HWSize; // Size of HW space -#if !REAL_ADDRESSING && !DIRECT_ADDRESSING -// If we are not using real or direct addressing, the Mac frame buffer gets -// mapped to this location. The memory must be allocated by VideoInit(). -// If multiple monitors are used, they must share the frame buffer +extern memptr FastRAMBase; // Fast-RAM base (Atari address space) +extern uint8 *FastRAMBaseHost; // Fast-RAM base (host address space) +extern memptr VideoRAMBase; // VideoRAM base (Atari address space) +extern uint8 *VideoRAMBaseHost; // VideoRAM base (host address space) + +#ifdef HW_SIGSEGV +extern uint8 *FakeIOBaseHost; +#endif + +#ifdef RAMENDNEEDED +# define RAMEnd 0x01000000 // Not accessible top of memory +#else +# define RAMEnd 0 +#endif +#endif +#if !REAL_ADDRESSING +// If we are not using real addressing, the Mac frame buffer gets mapped to this location +// The memory must be allocated by VideoInit(). If multiple monitors are used, they must +// share the frame buffer const uint32 MacFrameBaseMac = 0xa0000000; extern uint8 *MacFrameBaseHost; // Frame buffer base (host address space) extern uint32 MacFrameSize; // Size of frame buffer -#endif extern int MacFrameLayout; // Frame buffer layout (see defines below) +#endif +#if 0 +// Atari memory access functions +// Direct access to CPU address space +// For HW operations +// Read/WriteAtariIntXX +// +static inline uint64 ReadAtariInt64(memptr addr) {return phys_get_quad(addr);} +static inline uint32 ReadAtariInt32(memptr addr) {return phys_get_long(addr);} +static inline uint16 ReadAtariInt16(memptr addr) {return phys_get_word(addr);} +static inline uint8 ReadAtariInt8(memptr addr) {return phys_get_byte(addr);} +static inline void WriteAtariInt64(memptr addr, uint64 q) {phys_put_quad(addr, q);} +static inline void WriteAtariInt32(memptr addr, uint32 l) {phys_put_long(addr, l);} +static inline void WriteAtariInt16(memptr addr, uint16 w) {phys_put_word(addr, w);} +static inline void WriteAtariInt8(memptr addr, uint8 b) {phys_put_byte(addr, b);} + +// Direct access to allocated memory +// Ignores HW checks, so that be carefull +// Read/WriteHWMemIntXX +// +static inline uint32 ReadHWMemInt32(memptr addr) {return do_get_mem_long((uae_u32 *)phys_get_real_address(addr));} +static inline uint16 ReadHWMemInt16(memptr addr) {return do_get_mem_word((uae_u16 *)phys_get_real_address(addr));} +static inline uint8 ReadHWMemInt8(memptr addr) {return do_get_mem_byte((uae_u8 *)phys_get_real_address(addr));} +static inline void WriteHWMemInt32(memptr addr, uint32 l) {do_put_mem_long((uae_u32 *)phys_get_real_address(addr), l);} +static inline void WriteHWMemInt16(memptr addr, uint16 w) {do_put_mem_word((uae_u16 *)phys_get_real_address(addr), w);} +static inline void WriteHWMemInt8(memptr addr, uint8 b) {do_put_mem_byte((uae_u8 *)phys_get_real_address(addr), b);} + +// Indirect access to CPU address space +// Uses MMU if available +// For SW operations +// Only data space +// Read/WriteIntXX +// +static inline uint64 ReadInt64(memptr addr) {return get_quad(addr);} +static inline uint32 ReadInt32(memptr addr) {return get_long(addr);} +static inline uint16 ReadInt16(memptr addr) {return get_word(addr);} +static inline uint8 ReadInt8(memptr addr) {return get_byte(addr);} +static inline void WriteInt64(memptr addr, uint64 q) {put_quad(addr, q);} +static inline void WriteInt32(memptr addr, uint32 l) {put_long(addr, l);} +static inline void WriteInt16(memptr addr, uint16 w) {put_word(addr, w);} +static inline void WriteInt8(memptr addr, uint8 b) {put_byte(addr, b);} + +#ifdef EXTENDED_SIGSEGV +extern int in_handler; +#ifdef NO_NESTED_SIGSEGV +extern JMP_BUF sigsegv_env; +# define BUS_ERROR(a) \ +{ \ + regs.mmu_fault_addr=(a); \ + if (in_handler) \ + { \ + in_handler = 0; \ + LONGJMP(sigsegv_env, 1); \ + } \ + else { \ + breakpt(); \ + THROW(2); \ + } \ +} +#else /* NO_NESTED_SIGSEGV */ +# define BUS_ERROR(a) \ +{ \ + regs.mmu_fault_addr=(a); \ + in_handler = 0; \ + breakpt(); \ + THROW(2); \ +} +#endif /* NO_NESTED_SIGSEGV */ +#else /* EXTENDED_SIGSEGV */ +# define BUS_ERROR(a) \ +{ \ + regs.mmu_fault_addr=(a); \ + breakpt(); \ + THROW(2); \ +} +#endif /* EXTENDED_SIGSEGV */ + +// For address validation +static inline bool ValidAtariAddr(memptr addr, bool write, uint32 len) { return phys_valid_address(addr, write, len); } +static inline bool ValidAddr(memptr addr, bool write, uint32 len) { return valid_address(addr, write, len); } + +// Helper functions for usual memory operations +static inline uint8 *Atari2HostAddr(memptr addr) {return phys_get_real_address(addr);} +#endif // Possible frame buffer layouts enum { FLAYOUT_NONE, // No frame buffer @@ -73,30 +191,73 @@ static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {ret static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return memcpy(Mac2HostAddr(dest), Mac2HostAddr(src), n);} +// From newcpu.cpp +extern int quit_program; +extern int exit_val; + /* * 680x0 emulation */ // Initialization -extern bool Init680x0(void); // This routine may want to look at CPUType/FPUType to set up the apropriate emulation +#if 0 +extern bool InitMEM(); +#endif +extern bool Init680x0(void); +#if 0 +extern void Reset680x0(void); +#endif extern void Exit680x0(void); -extern void InitFrameBufferMapping(void); - -// 680x0 dynamic recompilation activation flag -#if USE_JIT -extern bool UseJIT; -#else -const bool UseJIT = false; +#if 0 +extern void AtariReset(void); #endif // 680x0 emulation functions struct M68kRegisters; -extern void Start680x0(void); // Reset and start 680x0 +extern void Start680x0(void); // Reset and start 680x0 +#if 0 +extern void Restart680x0(void); // Restart running 680x0 +extern void Quit680x0(void); // Quit 680x0 +#endif + extern "C" void Execute68k(uint32 addr, M68kRegisters *r); // Execute 68k code from EMUL_OP routine extern "C" void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute MacOS 68k trap from EMUL_OP routine // Interrupt functions -extern void TriggerInterrupt(void); // Trigger interrupt level 1 (InterruptFlag must be set first) -extern void TriggerNMI(void); // Trigger interrupt level 7 +#if 0 +extern int MFPdoInterrupt(void); +extern int SCCdoInterrupt(void); +extern void TriggerInternalIRQ(void); +extern void TriggerInt3(void); // Trigger interrupt level 3 +extern void TriggerVBL(void); // Trigger interrupt level 4 +extern void TriggerInt5(void); // Trigger interrupt level 5 +extern void TriggerSCC(bool); // Trigger interrupt level 5 +extern void TriggerMFP(bool); // Trigger interrupt level 6 +#endif +extern void TriggerInterrupt(void); // Trigger interrupt level 1 (InterruptFlag must be set first) +extern void TriggerNMI(void); // Trigger interrupt level 7 + +#if 0 +#ifdef FLIGHT_RECORDER +extern void cpu_flight_recorder(int); +extern void dump_flight_recorder(void); +#endif +#endif + +// CPU looping handlers +void check_eps_limit(uaecptr); +void report_double_bus_error(void); + +#if 0 +// This function will be removed +static inline uaecptr showPC(void) { return m68k_getpc(); } // for debugging only +#endif + +extern int intlev(void); +static inline void AtariReset(void) {} #endif + +/* +vim:ts=4:sw=4: +*/ diff --git a/BasiliskII/src/uae_cpu/cpudefsa.cpp b/BasiliskII/src/uae_cpu/cpudefsa.cpp new file mode 100644 index 00000000..ad7d6979 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpudefsa.cpp @@ -0,0 +1,5 @@ +/* + * cpudefs.cpp must be compiled twice, once for the generator program + * and once for the actual executable + */ +#include "cpudefs.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu1.cpp b/BasiliskII/src/uae_cpu/cpuemu1.cpp new file mode 100644 index 00000000..089eefd4 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu1.cpp @@ -0,0 +1,2 @@ +#define PART_1 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu1_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu1_nf.cpp new file mode 100644 index 00000000..58acf444 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu1_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_1 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu2.cpp b/BasiliskII/src/uae_cpu/cpuemu2.cpp new file mode 100644 index 00000000..1e18b587 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu2.cpp @@ -0,0 +1,2 @@ +#define PART_2 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu2_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu2_nf.cpp new file mode 100644 index 00000000..8e5136c4 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu2_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_2 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu3.cpp b/BasiliskII/src/uae_cpu/cpuemu3.cpp new file mode 100644 index 00000000..0385e2f0 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu3.cpp @@ -0,0 +1,2 @@ +#define PART_3 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu3_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu3_nf.cpp new file mode 100644 index 00000000..6565dc8c --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu3_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_3 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu4.cpp b/BasiliskII/src/uae_cpu/cpuemu4.cpp new file mode 100644 index 00000000..13d27e7a --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu4.cpp @@ -0,0 +1,2 @@ +#define PART_4 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu4_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu4_nf.cpp new file mode 100644 index 00000000..a16c36cb --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu4_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_4 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu5.cpp b/BasiliskII/src/uae_cpu/cpuemu5.cpp new file mode 100644 index 00000000..9b33a654 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu5.cpp @@ -0,0 +1,2 @@ +#define PART_5 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu5_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu5_nf.cpp new file mode 100644 index 00000000..5bf24360 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu5_nf.cpp @@ -0,0 +1,4 @@ +#define NOFLAGS 1 +#define PART_5 +#include "cpuemu.cpp" + diff --git a/BasiliskII/src/uae_cpu/cpuemu6.cpp b/BasiliskII/src/uae_cpu/cpuemu6.cpp new file mode 100644 index 00000000..e4b1efb0 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu6.cpp @@ -0,0 +1,2 @@ +#define PART_6 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu6_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu6_nf.cpp new file mode 100644 index 00000000..7afe15d4 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu6_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_6 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu7.cpp b/BasiliskII/src/uae_cpu/cpuemu7.cpp new file mode 100644 index 00000000..faec7ef8 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu7.cpp @@ -0,0 +1,2 @@ +#define PART_7 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu7_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu7_nf.cpp new file mode 100644 index 00000000..1e404dea --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu7_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_7 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu8.cpp b/BasiliskII/src/uae_cpu/cpuemu8.cpp new file mode 100644 index 00000000..c4efcfa3 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu8.cpp @@ -0,0 +1,2 @@ +#define PART_8 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpuemu8_nf.cpp b/BasiliskII/src/uae_cpu/cpuemu8_nf.cpp new file mode 100644 index 00000000..7c7f8f6e --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpuemu8_nf.cpp @@ -0,0 +1,3 @@ +#define NOFLAGS 1 +#define PART_8 +#include "cpuemu.cpp" diff --git a/BasiliskII/src/uae_cpu/cpufunctbla.cpp b/BasiliskII/src/uae_cpu/cpufunctbla.cpp new file mode 100644 index 00000000..17dd0d3f --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpufunctbla.cpp @@ -0,0 +1,5 @@ +/* + * cpufunctbl.cpp must be compiled twice, once for the generator program + * and once for the actual executable + */ +#include "cpufunctbl.cpp" diff --git a/BasiliskII/src/uae_cpu/cpummu.cpp b/BasiliskII/src/uae_cpu/cpummu.cpp new file mode 100644 index 00000000..1a3bd91a --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpummu.cpp @@ -0,0 +1,1096 @@ +/* + * cpummu.cpp - MMU emulation + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by UAE MMU patch + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define DEBUG 0 +#include "sysdeps.h" + +#include "cpummu.h" +#include "memory.h" +#include "newcpu.h" +#include "debug.h" +#ifdef USE_JIT +# include "compiler/compemu.h" +#endif + +#define DBG_MMU_VERBOSE 1 +#define DBG_MMU_SANITY 1 + +#ifdef FULLMMU + +mmu_atc_l1_array atc_l1[2]; +mmu_atc_l1_array *current_atc; +struct mmu_atc_line atc_l2[2][ATC_L2_SIZE]; + +# ifdef ATC_STATS +static unsigned int mmu_atc_hits[ATC_L2_SIZE]; +# endif + + +static void mmu_dump_ttr(const char * label, uae_u32 ttr) +{ + DUNUSED(label); +#if DEBUG + uae_u32 from_addr, to_addr; + + from_addr = ttr & MMU_TTR_LOGICAL_BASE; + to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8; + + D(bug("%s: [%08x] %08x - %08x enabled=%d supervisor=%d wp=%d cm=%02d", + label, ttr, + from_addr, to_addr, + ttr & MMU_TTR_BIT_ENABLED ? 1 : 0, + (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT, + ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0, + (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT + )); +#else + DUNUSED(ttr); +#endif +} + +void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode) +{ + uae_u32 * ttr; + uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0; + uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1; + + if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0) + ttr = ttr1; + else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0) + ttr = ttr0; + else + return; + + *ttr = baseaddr & MMU_TTR_LOGICAL_BASE; + *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8; + *ttr |= MMU_TTR_BIT_ENABLED; + + D(bug("MMU: map transparent mapping of %08x", *ttr)); +} + +/* check if an address matches a ttr */ +static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, int super) +{ + if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */ + uae_u8 msb, mask; + + msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24; + mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16; + + if (!(msb & ~mask)) { + + if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) { + if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) { + return TTR_NO_MATCH; + } + } + + return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH; + } + } + return TTR_NO_MATCH; +} + +static inline int mmu_match_ttr(uaecptr addr, int super, int data) +{ + int res; + + if (data) { + res = mmu_do_match_ttr(regs.dtt0, addr, super); + if (res == TTR_NO_MATCH) + res = mmu_do_match_ttr(regs.dtt1, addr, super); + } else { + res = mmu_do_match_ttr(regs.itt0, addr, super); + if (res == TTR_NO_MATCH) + res = mmu_do_match_ttr(regs.itt1, addr, super); + } + return res; +} + +#if DEBUG +/* {{{ mmu_dump_table */ +static void mmu_dump_table(const char * label, uaecptr root_ptr) +{ + DUNUSED(label); + const int ROOT_TABLE_SIZE = 128, + PTR_TABLE_SIZE = 128, + PAGE_TABLE_SIZE = regs.mmu_pagesize_8k ? 32 : 64, + ROOT_INDEX_SHIFT = 25, + PTR_INDEX_SHIFT = 18; + const uae_u32 ptr_addr_mask = (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4); + const uae_u32 page_addr_mask = (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4); + const uae_u32 page_ur_mask = (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4); + const uae_u32 page_size = (regs.mmu_pagesize_8k ? (1 << 13) : (1 << 12)); + int root_idx, ptr_idx, page_idx; + uae_u32 root_des, ptr_des, page_des; + uaecptr ptr_des_addr, page_addr, + root_log, ptr_log, page_log; + + D(bug("%s: root=%x", label, root_ptr)); + + for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) { + root_des = phys_get_long(root_ptr + (root_idx << 2)); + + if ((root_des & 2) == 0) + continue; /* invalid */ + + D(bug("ROOT: %03d U=%d W=%d UDT=%02d", root_idx, + root_des & 8 ? 1 : 0, + root_des & 4 ? 1 : 0, + root_des & 3 + )); + + root_log = root_idx << ROOT_INDEX_SHIFT; + + ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK; + + for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) { + struct { + uaecptr log, phys; + int start_idx, n_pages; /* number of pages covered by this entry */ + uae_u32 match; + } page_info[PAGE_TABLE_SIZE]; + int n_pages_used; + + ptr_des = phys_get_long(ptr_des_addr + (ptr_idx << 2)); + ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT); + + if ((ptr_des & 2) == 0) + continue; /* invalid */ + + page_addr = ptr_des & ptr_addr_mask; + + n_pages_used = -1; + for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) { + + page_des = phys_get_long(page_addr + (page_idx << 2)); + page_log = ptr_log | (page_idx * page_size); + + switch (page_des & 3) { + case 0: /* invalid */ + continue; + case 1: case 3: /* resident */ + case 2: /* indirect */ + if (n_pages_used == -1 || + (page_info[n_pages_used].match & ~page_addr_mask) != (page_des & ~page_addr_mask) || + page_info[n_pages_used].phys + (page_info[n_pages_used].n_pages * page_size) != (page_des & page_addr_mask)) + { + /* use the next entry */ + n_pages_used++; + + page_info[n_pages_used].match = page_des; + page_info[n_pages_used].n_pages = 1; + page_info[n_pages_used].start_idx = page_idx; + page_info[n_pages_used].log = page_log; + page_info[n_pages_used].phys = page_des & page_addr_mask; + } else { + page_info[n_pages_used].n_pages++; + } + break; + } + } + + if (n_pages_used == -1) + continue; + + D(bug(" PTR: %03d U=%d W=%d UDT=%02d", ptr_idx, + ptr_des & 8 ? 1 : 0, + ptr_des & 4 ? 1 : 0, + ptr_des & 3 + )); + + + for (page_idx = 0; page_idx <= n_pages_used; page_idx++) { + page_des = page_info[page_idx].match; + + if ((page_des & MMU_PDT_MASK) == 2) { + D(bug(" PAGE: %03d-%03d log=%08x INDIRECT --> addr=%08x", + page_info[page_idx].start_idx, + page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, + page_info[page_idx].log, + page_des & MMU_PAGE_INDIRECT_MASK + )); + + } else { + D(bug(" PAGE: %03d-%03d log=%08x addr=%08x UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d", + page_info[page_idx].start_idx, + page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, + page_info[page_idx].log, + page_info[page_idx].phys, + (page_des & page_ur_mask) >> MMU_PAGE_UR_SHIFT, + page_des & MMU_DES_GLOBAL ? 1 : 0, + (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT, + page_des & MMU_DES_SUPER ? 1 : 0, + (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT, + page_des & MMU_DES_MODIFIED ? 1 : 0, + page_des & MMU_DES_USED ? 1 : 0, + page_des & MMU_DES_WP ? 1 : 0 + )); + } + } + } + + } +} +/* }}} */ +#endif + +/* {{{ mmu_dump_atc */ +void mmu_dump_atc(void) +{ + int i, j; + for (i = 0; i < 2; i++) { + for (j = 0; j < ATC_L2_SIZE; j++) { + if (atc_l2[i][j].tag == 0x8000) + continue; + D(bug("ATC[%02d] G=%d TT=%d M=%d WP=%d VD=%d VI=%d tag=%08x --> phys=%08x", + j, atc_l2[i][j].global, atc_l2[i][j].tt, atc_l2[i][j].modified, + atc_l2[i][j].write_protect, atc_l2[i][j].valid_data, atc_l2[i][j].valid_inst, + atc_l2[i][j].tag, atc_l2[i][j].phys)); + } + } +} +/* }}} */ + +/* {{{ mmu_dump_tables */ +void mmu_dump_tables(void) +{ + D(bug("URP: %08x SRP: %08x MMUSR: %x TC: %x", regs.urp, regs.srp, regs.mmusr, regs.tc)); + mmu_dump_ttr("DTT0", regs.dtt0); + mmu_dump_ttr("DTT1", regs.dtt1); + mmu_dump_ttr("ITT0", regs.itt0); + mmu_dump_ttr("ITT1", regs.itt1); + mmu_dump_atc(); + //mmu_dump_table("SRP", regs.srp); +} +/* }}} */ + +static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, int super, int write); + +static ALWAYS_INLINE int mmu_get_fc(bool super, bool data) +{ + return (super ? 4 : 0) | (data ? 1 : 2); +} + +static void mmu_bus_error(uaecptr addr, int fc, int write, int size) +{ + uae_u16 ssw = 0; + + ssw |= fc & MMU_SSW_TM; /* Copy TM */ + switch (size) { + case sz_byte: + ssw |= MMU_SSW_SIZE_B; + break; + case sz_word: + ssw |= MMU_SSW_SIZE_W; + break; + case sz_long: + ssw |= MMU_SSW_SIZE_L; + break; + } + + regs.wb3_status = write ? 0x80 | ssw : 0; + if (!write) + ssw |= MMU_SSW_RW; + + regs.mmu_fault_addr = addr; + regs.mmu_ssw = ssw | MMU_SSW_ATC; + + D(bug("BUS ERROR: fc=%d w=%d log=%08x ssw=%04x", fc, write, addr, ssw)); + + breakpt(); + THROW(2); +} + +/* + * Update the atc line for a given address by doing a mmu lookup. + */ +static uaecptr mmu_fill_atc_l2(uaecptr addr, int super, int data, int write, + struct mmu_atc_line *l) +{ + int res; + uae_u32 desc; + + l->tag = ATC_TAG(addr); + l->hw = l->bus_fault = 0; + + /* check ttr0 */ + res = mmu_match_ttr(addr, super, data); + if (res != TTR_NO_MATCH) { + l->tt = 1; + if (data) { + l->valid_data = 1; + l->valid_inst = mmu_match_ttr(addr, super, 0) == res; + } else { + l->valid_inst = 1; + l->valid_data = mmu_match_ttr(addr, super, 1) == res; + } + l->global = 1; + l->modified = 1; + l->write_protect = (res == TTR_NO_WRITE); + l->phys = 0; + + return 0; + } + + l->tt = 0; + if (!regs.mmu_enabled) { + l->valid_data = l->valid_inst = 1; + l->global = 1; + l->modified = 1; + l->write_protect = 0; + l->phys = 0; + return 0; + } + + SAVE_EXCEPTION; + TRY(prb) { + desc = mmu_lookup_pagetable(addr, super, write); + D(bug("translate: %x,%u,%u,%u -> %x", addr, super, write, data, desc)); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + /* bus error during table search */ + desc = 0; + goto fail; + } + + if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) { + fail: + l->valid_data = l->valid_inst = 0; + l->global = 0; + } else { + l->valid_data = l->valid_inst = 1; + if (regs.mmu_pagesize_8k) + l->phys = (desc & ~0x1fff) - (addr & ~0x1fff); + else + l->phys = (desc & ~0xfff) - (addr & ~0xfff); + l->global = (desc & MMU_MMUSR_G) != 0; + l->modified = (desc & MMU_MMUSR_M) != 0; + l->write_protect = (desc & MMU_MMUSR_W) != 0; + } + + return desc; +} + +static ALWAYS_INLINE bool +mmu_fill_atc_l1(uaecptr addr, int super, int data, int write, + struct mmu_atc_line *l1) +{ + int idx = ATC_L2_INDEX(addr); + int tag = ATC_TAG(addr); + struct mmu_atc_line *l = &atc_l2[super][idx]; + uaecptr phys_addr; + + if (l->tag != tag) { + restart: + mmu_fill_atc_l2(addr, super, data, write, l); + } + if (!(data ? l->valid_data : l->valid_inst)) { + D(bug("MMU: non-resident page (%x,%x,%x)!", addr, regs.pc, regs.fault_pc)); + goto fail; + } + if (write) { + if (l->write_protect) { + D(bug("MMU: write protected (via %s) %x", l->tt ? "ttr" : "atc", addr)); + goto fail; + } + if (!l->modified) + goto restart; + } + *l1 = *l; + + phys_addr = addr + l1->phys; + if ((phys_addr & 0xfff00000) == 0x00f00000) { + l1->hw = 1; + goto fail; + } + if ((phys_addr & 0xfff00000) == 0xfff00000) { + l1->hw = 1; + l1->phys -= 0xff000000; + goto fail; + } + + if (!test_ram_boundary(phys_addr, 1, super, write)) { + l1->bus_fault = 1; + goto fail; + } + + return true; + +fail: + l1->tag = ~l1->tag; + return false; +} + +uaecptr mmu_translate(uaecptr addr, int super, int data, int write) +{ + struct mmu_atc_line *l; + + l = &atc_l2[super][ATC_L2_INDEX(addr)]; + mmu_fill_atc_l2(addr, super, data, write, l); + if (!(data ? l->valid_data : l->valid_inst)) + { + breakpt(); + THROW(2); + } + + return addr + l->phys; +} + +/* + * Lookup the address by walking the page table and updating + * the page descriptors accordingly. Returns the found descriptor + * or produces a bus error. + */ +static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, int super, int write) +{ + uae_u32 desc, desc_addr, wp; + int i; + + wp = 0; + desc = super ? regs.srp : regs.urp; + + /* fetch root table descriptor */ + i = (addr >> 23) & 0x1fc; + desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; + desc = phys_get_long(desc_addr); + if ((desc & 2) == 0) { + D(bug("MMU: invalid root descriptor for %x", addr)); + return 0; + } + + wp |= desc; + if ((desc & MMU_DES_USED) == 0) + phys_put_long(desc_addr, desc | MMU_DES_USED); + + /* fetch pointer table descriptor */ + i = (addr >> 16) & 0x1fc; + desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; + desc = phys_get_long(desc_addr); + if ((desc & 2) == 0) { + D(bug("MMU: invalid ptr descriptor for %x", addr)); + return 0; + } + wp |= desc; + if ((desc & MMU_DES_USED) == 0) + phys_put_long(desc_addr, desc | MMU_DES_USED); + + /* fetch page table descriptor */ + if (regs.mmu_pagesize_8k) { + i = (addr >> 11) & 0x7c; + desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) | i; + } else { + i = (addr >> 10) & 0xfc; + desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) | i; + } + + desc = phys_get_long(desc_addr); + if ((desc & 3) == 2) { + /* indirect */ + desc_addr = desc & MMU_PAGE_INDIRECT_MASK; + desc = phys_get_long(desc_addr); + } + if ((desc & 1) == 0) { + D(bug("MMU: invalid page descriptor log=%08x desc=%08x @%08x", addr, desc, desc_addr)); + return desc; + } + + desc |= wp & MMU_DES_WP; + if (write) { + if (desc & MMU_DES_WP) { + if ((desc & MMU_DES_USED) == 0) { + desc |= MMU_DES_USED; + phys_put_long(desc_addr, desc); + } + } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) != + (MMU_DES_USED|MMU_DES_MODIFIED)) { + desc |= MMU_DES_USED|MMU_DES_MODIFIED; + phys_put_long(desc_addr, desc); + } + } else { + if ((desc & MMU_DES_USED) == 0) { + desc |= MMU_DES_USED; + phys_put_long(desc_addr, desc); + } + } + return desc; +} + +uae_u16 mmu_get_word_unaligned(uaecptr addr, int data) +{ + uae_u16 res; + + res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8; + SAVE_EXCEPTION; + TRY(prb) { + res |= mmu_get_byte(addr + 1, data, sz_word); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + return res; +} + +uae_u32 mmu_get_long_unaligned(uaecptr addr, int data) +{ + uae_u32 res; + + if (likely(!(addr & 1))) { + res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16; + SAVE_EXCEPTION; + TRY(prb) { + res |= mmu_get_word(addr + 2, data, sz_long); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + } else { + res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8; + SAVE_EXCEPTION; + TRY(prb) { + res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8; + res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8; + res |= mmu_get_byte(addr + 3, data, sz_long); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + } + return res; +} + +uae_u8 mmu_get_byte_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) + return HWget_b(cl->phys + addr); + mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); + return 0; + } + + if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) + goto redo; + + return do_get_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl)); +} + +uae_u16 mmu_get_word_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) + return HWget_w(cl->phys + addr); + mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); + return 0; + } + + if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) + goto redo; + + return do_get_mem_word((uae_u16 *)mmu_get_real_address(addr, cl)); +} + +uae_u32 mmu_get_long_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) + return HWget_l(cl->phys + addr); + mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); + return 0; + } + + if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) + goto redo; + + return do_get_mem_long((uae_u32 *)mmu_get_real_address(addr, cl)); +} + + +uae_u64 mmu_get_quad_slow(uaecptr addr, int super, int data, + struct mmu_atc_line *cl) +{ + uae_u64 h = mmu_get_long_slow(addr, super, data, sz_long, cl); + uae_u64 l = mmu_get_long_slow(addr + 4, super, data, sz_long, cl); + return (h << 32) | l; +} + +REGPARAM2 void mmu_put_long_unaligned(uaecptr addr, uae_u32 val, int data) +{ + SAVE_EXCEPTION; + TRY(prb) { + if (likely(!(addr & 1))) { + mmu_put_word(addr, val >> 16, data, sz_long); + mmu_put_word(addr + 2, val, data, sz_long); + } else { + mmu_put_byte(addr, val >> 24, data, sz_long); + mmu_put_byte(addr + 1, val >> 16, data, sz_long); + mmu_put_byte(addr + 2, val >> 8, data, sz_long); + mmu_put_byte(addr + 3, val, data, sz_long); + } + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.wb3_data = val; + if (regs.mmu_fault_addr != addr) { + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + } + breakpt(); + THROW_AGAIN(prb); + } +} + +REGPARAM2 void mmu_put_word_unaligned(uaecptr addr, uae_u16 val, int data) +{ + SAVE_EXCEPTION; + TRY(prb) { + mmu_put_byte(addr, val >> 8, data, sz_word); + mmu_put_byte(addr + 1, val, data, sz_word); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.wb3_data = val; + if (regs.mmu_fault_addr != addr) { + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + } + breakpt(); + THROW_AGAIN(prb); + } +} + +REGPARAM2 void mmu_put_byte_slow(uaecptr addr, uae_u8 val, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) { + HWput_b(cl->phys + addr, val); + return; + } + regs.wb3_data = val; + mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); + return; + } + + if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) + goto redo; + + do_put_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl), val); +} + +REGPARAM2 void mmu_put_word_slow(uaecptr addr, uae_u16 val, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) { + HWput_w(cl->phys + addr, val); + return; + } + regs.wb3_data = val; + mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); + return; + } + + if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) + goto redo; + + do_put_mem_word((uae_u16 *)mmu_get_real_address(addr, cl), val); +} + +REGPARAM2 void mmu_put_long_slow(uaecptr addr, uae_u32 val, int super, int data, + int size, struct mmu_atc_line *cl) +{ + uae_u32 tag = ATC_TAG(addr); + + if (cl->tag == (uae_u16)~tag) { + redo: + if (cl->hw) { + HWput_l(cl->phys + addr, val); + return; + } + regs.wb3_data = val; + mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); + return; + } + + if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) + goto redo; + + do_put_mem_long((uae_u32 *)mmu_get_real_address(addr, cl), val); +} + +REGPARAM2 void mmu_put_quad_slow(uaecptr addr, uae_u64 val, int super, int data, + struct mmu_atc_line *cl) +{ + mmu_put_long_slow(addr, (uae_u32)(val >> 32), super, data, sz_long, cl); + mmu_put_long_slow(addr + 4, (uae_u32)(val), super, data, sz_long, cl); +} + +uae_u32 sfc_get_long(uaecptr addr) +{ + int super = (regs.sfc & 4) != 0; + int data = (regs.sfc & 3) != 2; + uae_u32 res; + + if (likely(!is_unaligned(addr, 4))) + return mmu_get_user_long(addr, super, data, sz_long); + + if (likely(!(addr & 1))) { + res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16; + SAVE_EXCEPTION; + TRY(prb) { + res |= mmu_get_user_word(addr + 2, super, data, sz_long); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + } else { + res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8; + SAVE_EXCEPTION; + TRY(prb) { + res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8; + res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8; + res |= mmu_get_user_byte(addr + 3, super, data, sz_long); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + } + return res; +} + +uae_u16 sfc_get_word(uaecptr addr) +{ + int super = (regs.sfc & 4) != 0; + int data = (regs.sfc & 3) != 2; + uae_u16 res; + + if (likely(!is_unaligned(addr, 2))) + return mmu_get_user_word(addr, super, data, sz_word); + + res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8; + SAVE_EXCEPTION; + TRY(prb) { + res |= mmu_get_user_byte(addr + 1, super, data, sz_word); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + breakpt(); + THROW_AGAIN(prb); + } + return res; +} + +uae_u8 sfc_get_byte(uaecptr addr) +{ + int super = (regs.sfc & 4) != 0; + int data = (regs.sfc & 3) != 2; + + return mmu_get_user_byte(addr, super, data, sz_byte); +} + +void dfc_put_long(uaecptr addr, uae_u32 val) +{ + int super = (regs.dfc & 4) != 0; + int data = (regs.dfc & 3) != 2; + + SAVE_EXCEPTION; + TRY(prb) { + if (likely(!is_unaligned(addr, 4))) + mmu_put_user_long(addr, val, super, data, sz_long); + else if (likely(!(addr & 1))) { + mmu_put_user_word(addr, val >> 16, super, data, sz_long); + mmu_put_user_word(addr + 2, val, super, data, sz_long); + } else { + mmu_put_user_byte(addr, val >> 24, super, data, sz_long); + mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long); + mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long); + mmu_put_user_byte(addr + 3, val, super, data, sz_long); + } + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.wb3_data = val; + if (regs.mmu_fault_addr != addr) { + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + } + breakpt(); + THROW_AGAIN(prb); + } +} + +void dfc_put_word(uaecptr addr, uae_u16 val) +{ + int super = (regs.dfc & 4) != 0; + int data = (regs.dfc & 3) != 2; + + SAVE_EXCEPTION; + TRY(prb) { + if (likely(!is_unaligned(addr, 2))) + mmu_put_user_word(addr, val, super, data, sz_word); + else { + mmu_put_user_byte(addr, val >> 8, super, data, sz_word); + mmu_put_user_byte(addr + 1, val, super, data, sz_word); + } + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.wb3_data = val; + if (regs.mmu_fault_addr != addr) { + regs.mmu_fault_addr = addr; + regs.mmu_ssw |= MMU_SSW_MA; + } + breakpt(); + THROW_AGAIN(prb); + } +} + +void dfc_put_byte(uaecptr addr, uae_u8 val) +{ + int super = (regs.dfc & 4) != 0; + int data = (regs.dfc & 3) != 2; + + SAVE_EXCEPTION; + TRY(prb) { + mmu_put_user_byte(addr, val, super, data, sz_byte); + RESTORE_EXCEPTION; + } + CATCH(prb) { + RESTORE_EXCEPTION; + regs.wb3_data = val; + breakpt(); + THROW_AGAIN(prb); + } +} + +void mmu_op(uae_u32 opcode, uae_u16 extra) +{ + int super = (regs.dfc & 4) != 0; + DUNUSED(extra); + if ((opcode & 0xFE0) == 0x0500) { + int regno, glob; + //D(didflush = 0); + uae_u32 addr; + /* PFLUSH */ + regno = opcode & 7; + glob = (opcode & 8) != 0; + + if (opcode & 16) { + D(bug("pflusha(%u,%u)", glob, regs.dfc)); + mmu_flush_atc_all(glob); + } else { + addr = m68k_areg(regs, regno); + D(bug("pflush(%u,%u,%x)", glob, regs.dfc, addr)); + mmu_flush_atc(addr, super, glob); + } + flush_internals(); +#ifdef USE_JIT + flush_icache(); +#endif + } else if ((opcode & 0x0FD8) == 0x548) { + int write, regno; + uae_u32 addr; + + regno = opcode & 7; + write = (opcode & 32) == 0; + addr = m68k_areg(regs, regno); + //bug("ptest(%u,%u,%x)", write, regs.dfc, addr); + D(bug("PTEST%c (A%d) %08x DFC=%d", write ? 'W' : 'R', regno, addr, regs.dfc)); + mmu_flush_atc(addr, super, true); + SAVE_EXCEPTION; + TRY(prb) { + struct mmu_atc_line *l; + uae_u32 desc; + bool data = (regs.dfc & 3) != 2; + + l = &atc_l2[super][ATC_L2_INDEX(addr)]; + desc = mmu_fill_atc_l2(addr, super, data, write, l); + if (!(data ? l->valid_data : l->valid_inst)) + regs.mmusr = MMU_MMUSR_B; + else if (l->tt) + regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R; + else { + regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S| + MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W); + regs.mmusr |= MMU_MMUSR_R; + } + } + CATCH(prb) { + regs.mmusr = MMU_MMUSR_B; + } + RESTORE_EXCEPTION; + D(bug("PTEST result: mmusr %08x", regs.mmusr)); + } else + op_illg (opcode); +} + +void mmu_flush_atc(uaecptr addr, bool super, bool global) +{ + struct mmu_atc_line *l; + int i, j; + + l = atc_l1[super][0][0]; + i = ATC_L1_INDEX(addr); + for (j = 0; j < 4; j++) { + if (global || !l[i].global) + l[i].tag = 0x8000; + l += ATC_L1_SIZE; + } + if (regs.mmu_pagesize_8k) { + i = ATC_L1_INDEX(addr) ^ 1; + for (j = 0; j < 4; j++) { + if (global || !l[i].global) + l[i].tag = 0x8000; + l += ATC_L1_SIZE; + } + } + l = atc_l2[super]; + i = ATC_L2_INDEX(addr); + if (global || !l[i].global) + l[i].tag = 0x8000; + if (regs.mmu_pagesize_8k) { + i ^= 1; + if (global || !l[i].global) + l[i].tag = 0x8000; + } +} + +void mmu_flush_atc_all(bool global) +{ + struct mmu_atc_line *l; + unsigned int i; + + l = atc_l1[0][0][0]; + for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) { + if (global || !l->global) + l->tag = 0x8000; + } + + l = atc_l2[0]; + for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) { + if (global || !l->global) + l->tag = 0x8000; + } +} + +void mmu_reset(void) +{ + mmu_flush_atc_all(true); + + regs.urp = regs.srp = 0; + regs.itt0 = regs.itt1 = 0; + regs.dtt0 = regs.dtt1 = 0; + regs.mmusr = 0; +} + + +void mmu_set_tc(uae_u16 tc) +{ + if (regs.tc == tc) + return; + + regs.tc = tc; + regs.mmu_enabled = tc & 0x8000 ? 1 : 0; + regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0; + mmu_flush_atc_all(true); + + D(bug("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k)); +} + +void mmu_set_super(bool super) +{ + current_atc = &atc_l1[super]; +} + +#else + +void mmu_op(uae_u32 opcode, uae_u16 /*extra*/) +{ + if ((opcode & 0xFE0) == 0x0500) { + /* PFLUSH instruction */ + flush_internals(); + } else if ((opcode & 0x0FD8) == 0x548) { + /* PTEST instruction */ + } else + op_illg(opcode); +} + +#endif + +/* +vim:ts=4:sw=4: +*/ diff --git a/BasiliskII/src/uae_cpu/cpummu.h b/BasiliskII/src/uae_cpu/cpummu.h new file mode 100644 index 00000000..01359f6f --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpummu.h @@ -0,0 +1,267 @@ +/* + * cpummu.h - MMU emulation + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by UAE MMU patch + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CPUMMU_H +#define CPUMMU_H + +#include "registers.h" + +# include + +#define MMU_TEST_PTEST 1 +#define MMU_TEST_VERBOSE 2 +#define MMU_TEST_FORCE_TABLE_SEARCH 4 +#define MMU_TEST_NO_BUSERR 8 + +extern void mmu_dump_tables(void); + +#define MMU_TTR_LOGICAL_BASE 0xff000000 +#define MMU_TTR_LOGICAL_MASK 0x00ff0000 +#define MMU_TTR_BIT_ENABLED (1 << 15) +#define MMU_TTR_BIT_SFIELD_ENABLED (1 << 14) +#define MMU_TTR_BIT_SFIELD_SUPER (1 << 13) +#define MMU_TTR_SFIELD_SHIFT 13 +#define MMU_TTR_UX_MASK ((1 << 9) | (1 << 8)) +#define MMU_TTR_UX_SHIFT 8 +#define MMU_TTR_CACHE_MASK ((1 << 6) | (1 << 5)) +#define MMU_TTR_CACHE_SHIFT 5 +#define MMU_TTR_BIT_WRITE_PROTECT (1 << 2) + +#define MMU_UDT_MASK 3 +#define MMU_PDT_MASK 3 + +#define MMU_DES_WP 4 +#define MMU_DES_USED 8 + +/* page descriptors only */ +#define MMU_DES_MODIFIED 16 +#define MMU_DES_SUPER (1 << 7) +#define MMU_DES_GLOBAL (1 << 10) + +#define MMU_ROOT_PTR_ADDR_MASK 0xfffffe00 +#define MMU_PTR_PAGE_ADDR_MASK_8 0xffffff80 +#define MMU_PTR_PAGE_ADDR_MASK_4 0xffffff00 + +#define MMU_PAGE_INDIRECT_MASK 0xfffffffc +#define MMU_PAGE_ADDR_MASK_8 0xffffe000 +#define MMU_PAGE_ADDR_MASK_4 0xfffff000 +#define MMU_PAGE_UR_MASK_8 ((1 << 12) | (1 << 11)) +#define MMU_PAGE_UR_MASK_4 (1 << 11) +#define MMU_PAGE_UR_SHIFT 11 + +#define MMU_MMUSR_ADDR_MASK 0xfffff000 +#define MMU_MMUSR_B (1 << 11) +#define MMU_MMUSR_G (1 << 10) +#define MMU_MMUSR_U1 (1 << 9) +#define MMU_MMUSR_U0 (1 << 8) +#define MMU_MMUSR_Ux (MMU_MMUSR_U1 | MMU_MMUSR_U0) +#define MMU_MMUSR_S (1 << 7) +#define MMU_MMUSR_CM ((1 << 6) | ( 1 << 5)) +#define MMU_MMUSR_M (1 << 4) +#define MMU_MMUSR_W (1 << 2) +#define MMU_MMUSR_T (1 << 1) +#define MMU_MMUSR_R (1 << 0) + +/* special status word (access error stack frame) */ +#define MMU_SSW_TM 0x0007 +#define MMU_SSW_TT 0x0018 +#define MMU_SSW_SIZE 0x0060 +#define MMU_SSW_SIZE_B 0x0020 +#define MMU_SSW_SIZE_W 0x0040 +#define MMU_SSW_SIZE_L 0x0000 +#define MMU_SSW_RW 0x0100 +#define MMU_SSW_LK 0x0200 +#define MMU_SSW_ATC 0x0400 +#define MMU_SSW_MA 0x0800 + +#define TTR_I0 4 +#define TTR_I1 5 +#define TTR_D0 6 +#define TTR_D1 7 + +#define TTR_NO_MATCH 0 +#define TTR_NO_WRITE 1 +#define TTR_OK_MATCH 2 + +struct mmu_atc_line { + uae_u16 tag; + unsigned tt : 1; + unsigned valid_data : 1; + unsigned valid_inst : 1; + unsigned global : 1; + unsigned modified : 1; + unsigned write_protect : 1; + unsigned hw : 1; + unsigned bus_fault : 1; + uaecptr phys; +}; + +/* + * We don't need to store the whole logical address in the atc cache, as part of + * it is encoded as index into the cache. 14 bits of the address are stored in + * the tag, this means at least 6 bits must go into the index. The upper two + * bits of the tag define the type of data in the atc line: + * - 00: a normal memory address + * - 11: invalid memory address or hardware access + * (generated via ~ATC_TAG(addr) in the slow path) + * - 10: empty atc line + */ + +#define ATC_TAG_SHIFT 18 +#define ATC_TAG(addr) ((uae_u32)(addr) >> ATC_TAG_SHIFT) + + +#define ATC_L1_SIZE_LOG 8 +#define ATC_L1_SIZE (1 << ATC_L1_SIZE_LOG) + +#define ATC_L1_INDEX(addr) (((addr) >> 12) % ATC_L1_SIZE) + +/* + * first level atc cache + * indexed by [super][data][rw][idx] + */ + +typedef struct mmu_atc_line mmu_atc_l1_array[2][2][ATC_L1_SIZE]; +extern mmu_atc_l1_array atc_l1[2]; +extern mmu_atc_l1_array *current_atc; + +#define ATC_L2_SIZE_LOG 12 +#define ATC_L2_SIZE (1 << ATC_L2_SIZE_LOG) + +#define ATC_L2_INDEX(addr) ((((addr) >> 12) ^ ((addr) >> (32 - ATC_L2_SIZE_LOG))) % ATC_L2_SIZE) + +extern struct mmu_atc_line atc_l2[2][ATC_L2_SIZE]; + +/* + * lookup address in the level 1 atc cache, + * the data and write arguments are constant in the common, + * thus allows gcc to generate a constant offset. + */ +static ALWAYS_INLINE int mmu_lookup(uaecptr addr, bool data, bool write, + struct mmu_atc_line **cl) +{ + addr >>= 12; + *cl = &(*current_atc)[data][write][addr % ATC_L1_SIZE]; + return (*cl)->tag == addr >> (ATC_TAG_SHIFT - 12); +} + +/* + * similiar to mmu_user_lookup, but for the use of the moves instruction + */ +static ALWAYS_INLINE int mmu_user_lookup(uaecptr addr, bool super, bool data, + bool write, struct mmu_atc_line **cl) +{ + addr >>= 12; + *cl = &atc_l1[super][data][write][addr % ATC_L1_SIZE]; + return (*cl)->tag == addr >> (ATC_TAG_SHIFT - 12); +} + +extern REGPARAM2 uae_u16 mmu_get_word_unaligned(uaecptr addr, int data); +extern REGPARAM2 uae_u32 mmu_get_long_unaligned(uaecptr addr, int data); + +extern REGPARAM2 uae_u8 mmu_get_byte_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 uae_u16 mmu_get_word_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 uae_u32 mmu_get_long_slow(uaecptr addr, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 uae_u64 mmu_get_quad_slow(uaecptr addr, int super, int data, + struct mmu_atc_line *cl); + +extern REGPARAM2 void mmu_put_word_unaligned(uaecptr addr, uae_u16 val, int data); +extern REGPARAM2 void mmu_put_long_unaligned(uaecptr addr, uae_u32 val, int data); + +extern REGPARAM2 void mmu_put_byte_slow(uaecptr addr, uae_u8 val, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 void mmu_put_word_slow(uaecptr addr, uae_u16 val, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 void mmu_put_long_slow(uaecptr addr, uae_u32 val, int super, int data, + int size, struct mmu_atc_line *cl); +extern REGPARAM2 void mmu_put_quad_slow(uaecptr addr, uae_u64 val, int super, int data, + struct mmu_atc_line *cl); + +extern void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode); + +static inline void mmu_set_ttr(int regno, uae_u32 val) +{ + uae_u32 * ttr; + switch(regno) { + case TTR_I0: ttr = ®s.itt0; break; + case TTR_I1: ttr = ®s.itt1; break; + case TTR_D0: ttr = ®s.dtt0; break; + case TTR_D1: ttr = ®s.dtt1; break; + default: abort(); + } + *ttr = val; +} + +static inline void mmu_set_mmusr(uae_u32 val) +{ + regs.mmusr = val; +} + +#define FC_DATA (regs.s ? 5 : 1) +#define FC_INST (regs.s ? 6 : 2) + +extern uaecptr REGPARAM2 mmu_translate(uaecptr addr, int super, int data, int write); + +extern uae_u32 REGPARAM2 sfc_get_long(uaecptr addr); +extern uae_u16 REGPARAM2 sfc_get_word(uaecptr addr); +extern uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr); +extern void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val); +extern void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val); +extern void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val); + + +extern void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global); +extern void REGPARAM2 mmu_flush_atc_all(bool global); +extern void REGPARAM2 mmu_op(uae_u32 opcode, uae_u16 extra); + +#ifdef FULLMMU + +extern void REGPARAM2 mmu_reset(void); +extern void REGPARAM2 mmu_set_tc(uae_u16 tc); +extern void REGPARAM2 mmu_set_super(bool super); + +#else + +static inline void mmu_reset(void) +{ +} + +static inline void mmu_set_tc(uae_u16 /*tc*/) +{ +} + +static inline void mmu_set_super(bool /*super*/) +{ +} + +#endif + +#endif /* CPUMMU_H */ +/* +vim:ts=4:sw=4: +*/ diff --git a/BasiliskII/src/uae_cpu/cpustbl_nf.cpp b/BasiliskII/src/uae_cpu/cpustbl_nf.cpp new file mode 100644 index 00000000..0ea66010 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpustbl_nf.cpp @@ -0,0 +1,2 @@ +#define NOFLAGS 1 +#include "cpustbl.cpp" diff --git a/BasiliskII/src/uae_cpu/cpustbla.cpp b/BasiliskII/src/uae_cpu/cpustbla.cpp new file mode 100644 index 00000000..f3f8e320 --- /dev/null +++ b/BasiliskII/src/uae_cpu/cpustbla.cpp @@ -0,0 +1,5 @@ +/* + * cpustbl.cpp must be compiled twice, once for the generator program + * and once for the actual executable + */ +#include "cpustbl.cpp" diff --git a/BasiliskII/src/uae_cpu/debug.cpp b/BasiliskII/src/uae_cpu/debug.cpp new file mode 100644 index 00000000..8b2f14e0 --- /dev/null +++ b/BasiliskII/src/uae_cpu/debug.cpp @@ -0,0 +1,82 @@ +/* + * debug.cpp - CPU debugger + * + * Copyright (c) 2001-2010 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Bernd Schmidt's UAE + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * UAE - The Un*x Amiga Emulator + * + * Debugger + * + * (c) 1995 Bernd Schmidt + * + */ + +#include "sysdeps.h" + +#include "memory.h" +#include "newcpu.h" +#include "debug.h" + +#include "input.h" +#include "cpu_emulation.h" + +#include "main.h" + +static int debugger_active = 0; +int debugging = 0; +int irqindebug = 0; + +int ignore_irq = 0; + + +void activate_debugger (void) +{ +#ifdef DEBUGGER + ndebug::do_skip = false; +#endif + debugger_active = 1; + SPCFLAGS_SET( SPCFLAG_BRK ); + debugging = 1; + /* use_debugger = 1; */ +} + +void deactivate_debugger(void) +{ + debugging = 0; + debugger_active = 0; +} + +void debug (void) +{ + if (ignore_irq && regs.s && !regs.m ) { + SPCFLAGS_SET( SPCFLAG_BRK ); + return; + } +#ifdef DEBUGGER + ndebug::run(); +#endif +} + +/* +vim:ts=4:sw=4: +*/ diff --git a/BasiliskII/src/uae_cpu/fpu/core.h b/BasiliskII/src/uae_cpu/fpu/core.h index 66358a2d..2eccc4d2 100644 --- a/BasiliskII/src/uae_cpu/fpu/core.h +++ b/BasiliskII/src/uae_cpu/fpu/core.h @@ -1,28 +1,33 @@ /* - * fpu/core.h - base fpu context definition + * fpu/core.h - base fpu context definition * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_CORE_H @@ -34,11 +39,15 @@ /* Always use x87 FPU stack on IA-32. */ #if defined(X86_ASSEMBLY) #define USE_X87_ASSEMBLY 1 +#ifndef USE_JIT_FPU +#define ACCURATE_SIN_COS_TAN 1 +#endif #endif /* Only use x87 FPU on x86-64 if long double precision is requested. */ -#if defined(X86_64_ASSEMBLY) && USE_LONG_DOUBLE +#if defined(X86_64_ASSEMBLY) && defined(USE_LONG_DOUBLE) #define USE_X87_ASSEMBLY 1 +#define ACCURATE_SIN_COS_TAN 1 #endif /* ========================================================================== */ @@ -65,10 +74,7 @@ struct fpu_t { /* --- Floating-Point Control Register --- */ /* ---------------------------------------------------------------------- */ - struct { - /* Exception Enable Byte */ - uae_u32 exception_enable; #define FPCR_EXCEPTION_ENABLE 0x0000ff00 #define FPCR_EXCEPTION_BSUN 0x00008000 #define FPCR_EXCEPTION_SNAN 0x00004000 @@ -83,21 +89,19 @@ struct fpu_t { #define FPCR_MODE_CONTROL 0x000000ff /* Rounding precision */ - uae_u32 rounding_precision; #define FPCR_ROUNDING_PRECISION 0x000000c0 #define FPCR_PRECISION_SINGLE 0x00000040 #define FPCR_PRECISION_DOUBLE 0x00000080 #define FPCR_PRECISION_EXTENDED 0x00000000 /* Rounding mode */ - uae_u32 rounding_mode; #define FPCR_ROUNDING_MODE 0x00000030 #define FPCR_ROUND_NEAR 0x00000000 #define FPCR_ROUND_ZERO 0x00000010 #define FPCR_ROUND_MINF 0x00000020 #define FPCR_ROUND_PINF 0x00000030 - } fpcr; + uae_u32 fpcr; /* ---------------------------------------------------------------------- */ /* --- Floating-Point Status Register --- */ @@ -107,7 +111,7 @@ struct fpu_t { /* Floating-Point Condition Code Byte */ uae_u32 condition_codes; - #define FPSR_CCB 0xff000000 + #define FPSR_CCB 0x0f000000 #define FPSR_CCB_NEGATIVE 0x08000000 #define FPSR_CCB_ZERO 0x04000000 #define FPSR_CCB_INFINITY 0x02000000 @@ -133,7 +137,7 @@ struct fpu_t { /* Accrued Exception Byte */ uae_u32 accrued_exception; - #define FPSR_ACCRUED_EXCEPTION 0x000000ff + #define FPSR_ACCRUED_EXCEPTION 0x000000f8 #define FPSR_ACCR_IOP 0x00000080 #define FPSR_ACCR_OVFL 0x00000040 #define FPSR_ACCR_UNFL 0x00000020 @@ -219,7 +223,7 @@ struct fpu_t { extern fpu_t fpu; /* Return the address of a particular register */ -inline fpu_register * const fpu_register_address(int i) +inline fpu_register * fpu_register_address(int i) { return &fpu.registers[i]; } /* Dump functions for m68k_dumpstate */ @@ -227,16 +231,16 @@ extern void fpu_dump_registers(void); extern void fpu_dump_flags(void); /* Accessors to FPU Control Register */ -static inline uae_u32 get_fpcr(void); -static inline void set_fpcr(uae_u32 new_fpcr); +//static inline uae_u32 get_fpcr(void); +//static inline void set_fpcr(uae_u32 new_fpcr); /* Accessors to FPU Status Register */ -static inline uae_u32 get_fpsr(void); -static inline void set_fpsr(uae_u32 new_fpsr); +//static inline uae_u32 get_fpsr(void); +//static inline void set_fpsr(uae_u32 new_fpsr); /* Accessors to FPU Instruction Address Register */ -static inline uae_u32 get_fpiar(); -static inline void set_fpiar(uae_u32 new_fpiar); +//static inline uae_u32 get_fpiar(); +//static inline void set_fpiar(uae_u32 new_fpiar); /* Initialization / Finalization */ extern void fpu_init(bool integral_68040); @@ -254,6 +258,6 @@ void fpuop_scc(uae_u32 opcode, uae_u32 extra) REGPARAM; /* Floating-point system control operations */ void fpuop_save(uae_u32 opcode) REGPARAM; void fpuop_restore(uae_u32 opcode) REGPARAM; -void fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) REGPARAM; +void fpuop_trapcc(uae_u32 opcode, uaecptr oldpc, uae_u32 extra) REGPARAM; #endif /* FPU_CORE_H */ diff --git a/BasiliskII/src/uae_cpu/fpu/exceptions.cpp b/BasiliskII/src/uae_cpu/fpu/exceptions.cpp index 6aa6431a..2a597997 100644 --- a/BasiliskII/src/uae_cpu/fpu/exceptions.cpp +++ b/BasiliskII/src/uae_cpu/fpu/exceptions.cpp @@ -1,28 +1,33 @@ /* - * fpu/exceptions.cpp - system-dependant FPU exceptions management + * fpu/exceptions.cpp - system-dependant FPU exceptions management * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #undef PRIVATE diff --git a/BasiliskII/src/uae_cpu/fpu/exceptions.h b/BasiliskII/src/uae_cpu/fpu/exceptions.h index 8c69a69d..f943da04 100644 --- a/BasiliskII/src/uae_cpu/fpu/exceptions.h +++ b/BasiliskII/src/uae_cpu/fpu/exceptions.h @@ -1,28 +1,33 @@ /* - * fpu/exceptions.h - system-dependant FPU exceptions management + * fpu/exceptions.h - system-dependant FPU exceptions management * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_EXCEPTIONS_H diff --git a/BasiliskII/src/uae_cpu/fpu/flags.cpp b/BasiliskII/src/uae_cpu/fpu/flags.cpp index 2eabef85..4b0972df 100644 --- a/BasiliskII/src/uae_cpu/fpu/flags.cpp +++ b/BasiliskII/src/uae_cpu/fpu/flags.cpp @@ -1,28 +1,33 @@ /* - * fpu/flags.cpp - Floating-point flags + * fpu/flags.cpp - Floating-point flags * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ diff --git a/BasiliskII/src/uae_cpu/fpu/flags.h b/BasiliskII/src/uae_cpu/fpu/flags.h index 7c0c5b74..de25a2b6 100644 --- a/BasiliskII/src/uae_cpu/fpu/flags.h +++ b/BasiliskII/src/uae_cpu/fpu/flags.h @@ -1,28 +1,33 @@ /* - * fpu/flags.h - Floating-point flags + * fpu/flags.h - Floating-point flags * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_FLAGS_H @@ -112,7 +117,7 @@ PRIVATE inline void FFPU set_fpccr(uae_u32 new_fpcond) /* Make FPSR according to the value passed in argument */ PRIVATE inline void FFPU make_fpsr(fpu_register const & r) - { uae_u16 sw; __asm__ __volatile__ ("fxam\n\tfnstsw %0" : "=r" (sw) : "f" (r)); FPU fpsr.condition_codes = sw; } + { uae_u16 sw; __asm__ __volatile__ ("fxam\n\tfnstsw %0" : "=a" (sw) : "f" (r)); FPU fpsr.condition_codes = sw; } /* Return the corresponding ID of the current floating-point condition codes */ /* NOTE: only valid for evaluation of a condition */ @@ -181,27 +186,27 @@ PRIVATE inline uae_u32 FFPU get_fpccr(void) uae_u32 fpccr = 0; if (isnan(FPU result)) fpccr |= FPSR_CCB_NAN; - else if (FPU result == 0.0) - fpccr |= FPSR_CCB_ZERO; - else if (FPU result < 0.0) - fpccr |= FPSR_CCB_NEGATIVE; - if (isinf(FPU result)) + else if (isinf(FPU result)) fpccr |= FPSR_CCB_INFINITY; + else if (iszero(FPU result)) + fpccr |= FPSR_CCB_ZERO; + if (isneg(FPU result)) + fpccr |= FPSR_CCB_NEGATIVE; return fpccr; } /* M68k to native floating-point condition codes - SELF */ PRIVATE inline void FFPU set_fpccr(uae_u32 new_fpcond) { + bool negative = (new_fpcond & FPSR_CCB_NEGATIVE) != 0; if (new_fpcond & FPSR_CCB_NAN) - make_nan(FPU result); + make_nan(FPU result, negative); + else if (new_fpcond & FPSR_CCB_INFINITY) + make_inf(FPU result, negative); else if (new_fpcond & FPSR_CCB_ZERO) - FPU result = 0.0; - else if (new_fpcond & FPSR_CCB_NEGATIVE) - FPU result = -1.0; + make_zero(FPU result, negative); else - FPU result = +1.0; - /* gb-- where is Infinity ? */ + FPU result = negative ? -1.0 : +1.0; } /* Make FPSR according to the value passed in argument */ @@ -217,7 +222,7 @@ PRIVATE inline void FFPU make_fpsr(fpu_register const & r) /* -------------------------------------------------------------------------- */ /* Return the address of the floating-point condition codes register */ -static inline uae_u32 * const FFPU address_of_fpccr(void) +static inline uae_u32 * FFPU address_of_fpccr(void) { return ((uae_u32 *)& FPU fpsr.condition_codes); } #endif /* FPU_FLAGS_H */ diff --git a/BasiliskII/src/uae_cpu/fpu/fpu.h b/BasiliskII/src/uae_cpu/fpu/fpu.h index 3940a75b..d1fe6dd2 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu.h +++ b/BasiliskII/src/uae_cpu/fpu/fpu.h @@ -1,28 +1,33 @@ /* - * fpu/fpu.h - public header + * fpu/fpu.h - public header * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_PUBLIC_HEADER_H @@ -46,4 +51,9 @@ #include "fpu/types.h" #include "fpu/core.h" +void fpu_set_fpsr(uae_u32 new_fpsr); +uae_u32 fpu_get_fpsr(void); +void fpu_set_fpcr(uae_u32 new_fpcr); +uae_u32 fpu_get_fpcr(void); + #endif /* FPU_PUBLIC_HEADER_H */ diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp b/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp index f5a1aeb4..c76d56e6 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp +++ b/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp @@ -1,31 +1,42 @@ /* - * fpu/fpu_ieee.cpp + * fpu_ieee.cpp - the IEEE FPU * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2008 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * MC68881/68040 fpu emulation * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* + * UAE - The Un*x Amiga Emulator + * + * MC68881/MC68040 emulation + * + * Copyright 1996 Herman ten Brugge + * + * * Following fixes by Lauri Pesonen, July 1999: * * FMOVEM list handling: @@ -87,7 +98,7 @@ */ #include "sysdeps.h" -#include +#include #include "memory.h" #include "readcpu.h" #include "newcpu.h" @@ -130,6 +141,24 @@ fpu_t fpu; #include "fpu/exceptions.cpp" #include "fpu/rounding.cpp" +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) +#define LD(x) x ## L +#ifdef HAVE_POWL +#define POWL(x, y) powl(x, y) +#else +#define POWL(x, y) pow(x, y) +#endif +#ifdef HAVE_LOG10L +#define LOG10L(x) log10l(x) +#else +#define LOG10L(x) log10(x) +#endif +#else +#define LD(x) x +#define POWL(x, y) pow(x, y) +#define LOG10L(x) log10(x) +#endif + /* -------------------------------------------------------------------------- */ /* --- Debugging --- */ /* -------------------------------------------------------------------------- */ @@ -152,9 +181,9 @@ PUBLIC void FFPU fpu_dump_flags(void) (get_fpsr() & FPSR_CCB_NAN) != 0); } +#if FPU_DEBUG && FPU_DUMP_REGISTERS PRIVATE void FFPU dump_registers(const char * str) { -#if FPU_DEBUG && FPU_DUMP_REGISTERS char temp_str[512]; sprintf(temp_str, "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\n", @@ -164,12 +193,15 @@ PRIVATE void FFPU dump_registers(const char * str) fpu_get_register(6), fpu_get_register(7) ); fpu_debug((temp_str)); +#else +PRIVATE void FFPU dump_registers(const char *) +{ #endif } +#if FPU_DEBUG && FPU_DUMP_FIRST_BYTES PRIVATE void FFPU dump_first_bytes(uae_u8 * buffer, uae_s32 actual) { -#if FPU_DEBUG && FPU_DUMP_FIRST_BYTES char temp_buf1[256], temp_buf2[10]; int bytes = sizeof(temp_buf1)/3-1-3; if (actual < bytes) @@ -183,6 +215,9 @@ PRIVATE void FFPU dump_first_bytes(uae_u8 * buffer, uae_s32 actual) strcat(temp_buf1, "\n"); fpu_debug((temp_buf1)); +#else + PRIVATE void FFPU dump_first_bytes(uae_u8 *, uae_s32) +{ #endif } @@ -200,11 +235,12 @@ PRIVATE inline fpu_register FFPU make_single(uae_u32 value) #if 1 // Use a single, otherwise some checks for NaN, Inf, Zero would have to // be performed - fpu_single result = 0; // = 0 to workaround a compiler bug on SPARC - fp_declare_init_shape(srp, result, single); - srp->ieee.negative = (value >> 31) & 1; - srp->ieee.exponent = (value >> 23) & FP_SINGLE_EXP_MAX; - srp->ieee.mantissa = value & 0x007fffff; + fpu_single result = 0; + fp_declare_init_shape(srp, single); + srp.ieee.negative = (value >> 31) & 1; + srp.ieee.exponent = (value >> 23) & FP_SINGLE_EXP_MAX; + srp.ieee.mantissa = value & 0x007fffff; + result = srp.value; fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); return result; #elif 0 /* Original code */ @@ -212,13 +248,13 @@ PRIVATE inline fpu_register FFPU make_single(uae_u32 value) return (0.0); fpu_register result; - uae_u32 * p = (uae_u32 *)&result; + fpu_register_parts *p = (fpu_register_parts *)&result; uae_u32 sign = (value & 0x80000000); uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127; - p[FLO] = value << 29; - p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); + p->parts[FLO] = value << 29; + p->parts[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); @@ -231,10 +267,11 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) { #if 1 fpu_single input = (fpu_single) src; - fp_declare_init_shape(sip, input, single); - uae_u32 result = (sip->ieee.negative << 31) - | (sip->ieee.exponent << 23) - | sip->ieee.mantissa; + fp_declare_init_shape(sip, single); + sip.value = input; + uae_u32 result = (sip.ieee.negative << 31) + | (sip.ieee.exponent << 23) + | sip.ieee.mantissa; fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); return result; #elif 0 /* Original code */ @@ -242,10 +279,10 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) return 0; uae_u32 result; - uae_u32 *p = (uae_u32 *)&src; + fpu_register_parts const *p = (fpu_register_parts const *)&src; - uae_u32 sign = (p[FHI] & 0x80000000); - uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20; + uae_u32 sign = (p->parts[FHI] & 0x80000000); + uae_u32 exp = (p->parts[FHI] & 0x7FF00000) >> 20; if(exp + 127 < 1023) { exp = 0; @@ -255,7 +292,7 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) exp = exp + 127 - 1023; } - result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29); + result = sign | (exp << 23) | ((p->parts[FHI] & 0x000FFFFF) << 3) | (p->parts[FLO] >> 29); fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); @@ -268,36 +305,34 @@ PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u { // is it zero? if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) - return 0.0; + return (wrd1 & 0x80000000) ? -0.0 : 0.0; fpu_register result; -#if USE_QUAD_DOUBLE +#if defined(USE_QUAD_DOUBLE) // is it NaN? - if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { - make_nan(result); + if ((wrd1 & 0x7fff0000) == 0x7fff0000 && ((wrd2 & 0x7fffffff) != 0 || wrd3 != 0)) { + make_nan(result, (wrd1 & 0x80000000) != 0); return result; } // is it inf? - if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { - if ((wrd1 & 0x80000000) == 0) - make_inf_positive(result); - else - make_inf_negative(result); + if ((wrd1 & 0x7ffff000) == 0x7fff0000 && (wrd2 & 0x7fffffff) == 0 && wrd3 == 0) { + make_inf(result, (wrd1 & 0x80000000) != 0); return result; } - fp_declare_init_shape(srp, result, extended); - srp->ieee.negative = (wrd1 >> 31) & 1; - srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; - srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; - srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); - srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; - srp->ieee.mantissa3 = 0; -#elif USE_LONG_DOUBLE - fp_declare_init_shape(srp, result, extended); - srp->ieee.negative = (wrd1 >> 31) & 1; - srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; - srp->ieee.mantissa0 = wrd2; - srp->ieee.mantissa1 = wrd3; + fp_declare_init_shape(srp, extended); + srp.ieee.negative = (wrd1 >> 31) & 1; + srp.ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; + srp.ieee.mantissa0 = (wrd2 >> 16) & 0xffff; + srp.ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); + srp.ieee.mantissa2 = (wrd3 & 0xffff) << 16; + srp.ieee.mantissa3 = 0; +#elif defined(USE_LONG_DOUBLE) + fp_declare_init_shape(srp, extended); + srp.ieee.negative = (wrd1 >> 31) & 1; + srp.ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; + srp.ieee.mantissa0 = wrd2; + srp.ieee.mantissa1 = wrd3; + #else uae_u32 sgn = (wrd1 >> 31) & 1; uae_u32 exp = (wrd1 >> 16) & 0x7fff; @@ -326,13 +361,14 @@ PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; - fp_declare_init_shape(srp, result, double); - srp->ieee.negative = sgn; - srp->ieee.exponent = exp; + fp_declare_init_shape(srp, double); + srp.ieee.negative = sgn; + srp.ieee.exponent = exp; // drop the explicit integer bit - srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; - srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); + srp.ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; + srp.ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); #endif + result = srp.value; fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); return result; } @@ -347,37 +383,34 @@ PRIVATE inline void FFPU make_extended_no_normalize( ) { // is it zero? - if ((wrd1 && 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { - make_zero_positive(result); + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { + make_zero(result, (wrd1 & 0x80000000) != 0); return; } // is it NaN? - if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { - make_nan(result); + if ((wrd1 & 0x7fff0000) == 0x7fff0000 && ((wrd2 & 0x7fffffff) != 0 || wrd3 != 0)) { + make_nan(result, (wrd1 & 0x80000000) != 0); return; } -#if USE_QUAD_DOUBLE +#if defined(USE_QUAD_DOUBLE) // is it inf? - if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { - if ((wrd1 & 0x80000000) == 0) - make_inf_positive(result); - else - make_inf_negative(result); + if ((wrd1 & 0x7ffff000) == 0x7fff0000 && (wrd2 & 0x7fffffff) == 0 && wrd3 == 0) { + make_inf(result, (wrd1 & 0x80000000) != 0); return; } - fp_declare_init_shape(srp, result, extended); - srp->ieee.negative = (wrd1 >> 31) & 1; - srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; - srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; - srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); - srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; - srp->ieee.mantissa3 = 0; -#elif USE_LONG_DOUBLE - fp_declare_init_shape(srp, result, extended); - srp->ieee.negative = (wrd1 >> 31) & 1; - srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; - srp->ieee.mantissa0 = wrd2; - srp->ieee.mantissa1 = wrd3; + fp_declare_init_shape(srp, extended); + srp.ieee.negative = (wrd1 >> 31) & 1; + srp.ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; + srp.ieee.mantissa0 = (wrd2 >> 16) & 0xffff; + srp.ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); + srp.ieee.mantissa2 = (wrd3 & 0xffff) << 16; + srp.ieee.mantissa3 = 0; +#elif defined(USE_LONG_DOUBLE) + fp_declare_init_shape(srp, extended); + srp.ieee.negative = (wrd1 >> 31) & 1; + srp.ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; + srp.ieee.mantissa0 = wrd2; + srp.ieee.mantissa1 = wrd3; #else uae_u32 exp = (wrd1 >> 16) & 0x7fff; if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) @@ -387,13 +420,14 @@ PRIVATE inline void FFPU make_extended_no_normalize( else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; - fp_declare_init_shape(srp, result, double); - srp->ieee.negative = (wrd1 >> 31) & 1; - srp->ieee.exponent = exp; + fp_declare_init_shape(srp, double); + srp.ieee.negative = (wrd1 >> 31) & 1; + srp.ieee.exponent = exp; // drop the explicit integer bit - srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; - srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); + srp.ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; + srp.ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); #endif + result = srp.value; fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); } @@ -406,41 +440,43 @@ PRIVATE inline void FFPU extract_extended(fpu_register const & src, *wrd1 = *wrd2 = *wrd3 = 0; return; } -#if USE_QUAD_DOUBLE +#if defined(USE_QUAD_DOUBLE) // FIXME: deal with denormals? - fp_declare_init_shape(srp, src, extended); - *wrd1 = (srp->ieee.negative << 31) | (srp->ieee.exponent << 16); + fp_declare_init_shape(srp, extended); + srp.value = src; + *wrd1 = (srp.ieee.negative << 31) | (srp.ieee.exponent << 16); // always set the explicit integer bit. - *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 15) | ((srp->ieee.mantissa1 & 0xfffe0000) >> 17); - *wrd3 = (srp->ieee.mantissa1 << 15) | ((srp->ieee.mantissa2 & 0xfffe0000) >> 17); -#elif USE_LONG_DOUBLE - uae_u32 *p = (uae_u32 *)&src; + *wrd2 = 0x80000000 | (srp.ieee.mantissa0 << 15) | ((srp.ieee.mantissa1 & 0xfffe0000) >> 17); + *wrd3 = (srp.ieee.mantissa1 << 15) | ((srp.ieee.mantissa2 & 0xfffe0000) >> 17); +#elif defined(USE_LONG_DOUBLE) + fpu_register_parts p = { src }; #ifdef WORDS_BIGENDIAN - *wrd1 = p[0]; - *wrd2 = p[1]; - *wrd3 = p[2]; + *wrd1 = p.parts[0]; + *wrd2 = p.parts[1]; + *wrd3 = p.parts[2]; #else - *wrd3 = p[0]; - *wrd2 = p[1]; - *wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; + *wrd3 = p.parts[0]; + *wrd2 = p.parts[1]; + *wrd1 = (p.parts[2] & 0xffff) << 16; #endif #else - fp_declare_init_shape(srp, src, double); + fp_declare_init_shape(srp, double); + srp.value = src; fpu_debug(("extract_extended (%d,%d,%X,%X)\n", - srp->ieee.negative , srp->ieee.exponent, - srp->ieee.mantissa0, srp->ieee.mantissa1)); + srp.ieee.negative , srp.ieee.exponent, + srp.ieee.mantissa0, srp.ieee.mantissa1)); - uae_u32 exp = srp->ieee.exponent; + uae_u32 exp = srp.ieee.exponent; if (exp == FP_DOUBLE_EXP_MAX) exp = FP_EXTENDED_EXP_MAX; else exp += FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS; - *wrd1 = (srp->ieee.negative << 31) | (exp << 16); + *wrd1 = (srp.ieee.negative << 31) | (exp << 16); // always set the explicit integer bit. - *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 11) | ((srp->ieee.mantissa1 & 0xffe00000) >> 21); - *wrd3 = srp->ieee.mantissa1 << 11; + *wrd2 = 0x80000000 | (srp.ieee.mantissa0 << 11) | ((srp.ieee.mantissa1 & 0xffe00000) >> 21); + *wrd3 = srp.ieee.mantissa1 << 11; #endif fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } @@ -486,41 +522,88 @@ PRIVATE inline void FFPU extract_double(fpu_register const & src, // to_pack PRIVATE inline fpu_register FFPU make_packed(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { - fpu_double d; - char *cp; - char str[100]; + fpu_register d; + bool sm = (wrd1 & 0x80000000) != 0; + bool se = (wrd1 & 0x40000000) != 0; + int exp = (wrd1 & 0x7fff0000) >> 16; + unsigned int dig; + fpu_register pwr; + + if (exp == 0x7fff) + { + if ((wrd2 & 0x7fffffff) == 0 && wrd3 == 0) + { + make_inf(d, sm); + } else + { + make_nan(d, sm); + } + return d; + } + dig = wrd1 & 0x0000000f; + if (dig == 0 && wrd2 == 0 && wrd3 == 0) + { + make_zero(d, sm); + return d; + } - cp = str; - if (wrd1 & 0x80000000) - *cp++ = '-'; - *cp++ = (char)((wrd1 & 0xf) + '0'); - *cp++ = '.'; - *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0'); - *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0'); - *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0'); - *cp++ = 'E'; - if (wrd1 & 0x40000000) - *cp++ = '-'; - *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0'); - *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0'); - *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0'); - *cp = 0; - sscanf(str, "%le", &d); + /* + * Convert the bcd exponent to binary by successive adds and + * muls. Set the sign according to SE. Subtract 16 to compensate + * for the mantissa which is to be interpreted as 17 integer + * digits, rather than 1 integer and 16 fraction digits. + * Note: this operation can never overflow. + */ + exp = ((wrd1 >> 24) & 0xf); + exp = exp * 10 + ((wrd1 >> 20) & 0xf); + exp = exp * 10 + ((wrd1 >> 16) & 0xf); + if (se) + exp = -exp; + /* sub to compensate for shift of mant */ + exp = exp - 16; + + /* + * Convert the bcd mantissa to binary by successive + * adds and muls. Set the sign according to SM. + * The mantissa digits will be converted with the decimal point + * assumed following the least-significant digit. + * Note: this operation can never overflow. + */ + d = wrd1 & 0xf; + d = (d * LD(10.0)) + ((wrd2 >> 28) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 24) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 20) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 16) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 12) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 8) & 0xf); + d = (d * LD(10.0)) + ((wrd2 >> 4) & 0xf); + d = (d * LD(10.0)) + ((wrd2 ) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 28) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 24) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 20) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 16) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 12) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 8) & 0xf); + d = (d * LD(10.0)) + ((wrd3 >> 4) & 0xf); + d = (d * LD(10.0)) + ((wrd3 ) & 0xf); - fpu_debug(("make_packed str = %s\n",str)); + /* Check the sign of the mant and make the value in fp0 the same sign. */ + if (sm) + d = -d; + + /* + * Calculate power-of-ten factor from exponent. + */ + if (exp < 0) + { + exp = -exp; + pwr = POWL(LD(10.0), exp); + d = d / pwr; + } else + { + pwr = POWL(LD(10.0), exp); + d = d * pwr; + } fpu_debug(("make_packed(%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)d)); return d; @@ -529,52 +612,88 @@ PRIVATE inline fpu_register FFPU make_packed(uae_u32 wrd1, uae_u32 wrd2, uae_u32 // from_pack PRIVATE inline void FFPU extract_packed(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { - int i; - int t; - char *cp; - char str[100]; - - sprintf(str, "%.16e", src); - - fpu_debug(("extract_packed(%.04f,%s)\n",(double)src,str)); - - cp = str; + fpu_register pwr; + int exp; + fpu_register d; + bool sm, se; + int dig; + *wrd1 = *wrd2 = *wrd3 = 0; - if (*cp == '-') { - cp++; - *wrd1 = 0x80000000; - } - if (*cp == '+') - cp++; - *wrd1 |= (*cp++ - '0'); - if (*cp == '.') - cp++; - for (i = 0; i < 8; i++) { - *wrd2 <<= 4; - if (*cp >= '0' && *cp <= '9') - *wrd2 |= *cp++ - '0'; - } - for (i = 0; i < 8; i++) { - *wrd3 <<= 4; - if (*cp >= '0' && *cp <= '9') - *wrd3 |= *cp++ - '0'; - } - if (*cp == 'e' || *cp == 'E') { - cp++; - if (*cp == '-') { - cp++; - *wrd1 |= 0x40000000; - } - if (*cp == '+') - cp++; - t = 0; - for (i = 0; i < 3; i++) { - if (*cp >= '0' && *cp <= '9') - t = (t << 4) | (*cp++ - '0'); - } - *wrd1 |= t << 16; + + d = src; + sm = false; + if (isneg(src)) + { + d = -d; + sm = true; } + if (isnan(src)) + { + *wrd1 = sm ? 0xffff0000 : 0x7fff0000; + *wrd2 = 0xffffffff; + *wrd3 = 0xffffffff; + return; + } + if (isinf(src)) + { + *wrd1 = sm ? 0xffff0000 : 0x7fff0000; + *wrd2 = *wrd3 = 0; + return; + } + if (iszero(src)) + { + *wrd1 = sm ? 0x80000000 : 0x00000000; + *wrd2 = *wrd3 = 0; + return; + } + sm = false; + if (isneg(src)) + { + d = -d; + sm = true; + } + exp = (int)floor(LOG10L(d)); + se = false; + if (exp < 0) + { + exp = -exp; + se = true; + pwr = POWL(LD(10.0), exp); + d = d * pwr; + } else + { + pwr = POWL(LD(10.0), exp); + d = d / pwr; + } + dig = (int)d; d = LD(10) * (d - dig); *wrd1 |= dig; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 28; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 24; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 20; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 16; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 12; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 8; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig << 4; + dig = (int)d; d = LD(10) * (d - dig); *wrd2 |= dig; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 28; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 24; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 20; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 16; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 12; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 8; + dig = (int)d; d = LD(10) * (d - dig); *wrd3 |= dig << 4; + dig = (int)d; *wrd3 |= dig; + + dig = (exp / 100) % 10; + *wrd1 |= dig << 24; + dig = (exp / 10) % 10; + *wrd1 |= dig << 20; + dig = (exp) % 10; + *wrd1 |= dig << 16; + if (sm) + *wrd1 |= 0x80000000; + if (se) + *wrd1 |= 0x40000000; fpu_debug(("extract_packed(%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } @@ -628,11 +747,9 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe break; case 3: ad = m68k_areg (regs, reg); - m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: - m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; - ad = m68k_areg (regs, reg); + ad = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); @@ -673,8 +790,8 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe fpu_debug(("get_fp_value m68k_getpc()=%X\n",m68k_getpc())); fpu_debug(("get_fp_value ad=%X\n",ad)); fpu_debug(("get_fp_value get_long (ad)=%X\n",get_long (ad))); - dump_first_bytes( get_real_address(ad)-64, 64 ); - dump_first_bytes( get_real_address(ad), 64 ); + //dump_first_bytes( get_real_address(ad, 0, 0)-64, 64 ); + //dump_first_bytes( get_real_address(ad, 0, 0), 64 ); switch (size) { case 0: @@ -721,15 +838,24 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe return 0; } + switch (mode) { + case 3: + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; + case 4: + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + break; + } + // fpu_debug(("get_fp_value result = %.04f\n",(float)src)); return 1; } /* Convert the FP value to integer according to the current m68k rounding mode */ -PRIVATE inline uae_s32 FFPU toint(fpu_register const & src) +PRIVATE inline fpu_register FFPU fp_doround(fpu_register const & src) { fpu_register result; - switch (get_fpcr() & 0x30) { + switch (get_fpcr() & FPCR_ROUNDING_MODE) { case FPCR_ROUND_ZERO: result = fp_round_to_zero(src); break; @@ -746,7 +872,12 @@ PRIVATE inline uae_s32 FFPU toint(fpu_register const & src) result = src; /* should never be reached */ break; } - return (uae_s32)result; + return result; +} + +PRIVATE inline uae_s32 FFPU toint(fpu_register const & src) +{ + return (uae_s32)fp_doround(src); } PRIVATE inline int FFPU put_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register const & value) @@ -951,7 +1082,7 @@ PRIVATE inline int FFPU fpp_cond(int condition) if (NaN) N = Z = 0; - switch (condition) { + switch (condition & 0x1f) { case 0x00: CONDRET("False",0); case 0x01: CONDRET("Equal",Z); case 0x02: CONDRET("Ordered Greater Than",!(NaN || Z || N)); @@ -1021,7 +1152,7 @@ void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) { fpu_debug(("fscc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); - uae_u32 ad; + uae_u32 ad = 0; int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (m68k_getpc () - 4); @@ -1039,11 +1170,11 @@ void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) put_byte(ad, cc ? 0xff : 0x00); } -void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) +void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc, uae_u32 extra) { - fpu_debug(("ftrapcc_opp %X at %08lx\n", (uae_u32)opcode, m68k_getpc ())); + fpu_debug(("ftrapcc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); - int cc = fpp_cond(opcode & 0x3f); + int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (oldpc); op_illg (opcode); @@ -1075,7 +1206,7 @@ void FFPU fpuop_save(uae_u32 opcode) { fpu_debug(("fsave_opp at %08lx\n", m68k_getpc ())); - uae_u32 ad; + uae_u32 ad = 0; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; int i; @@ -1136,7 +1267,7 @@ void FFPU fpuop_restore(uae_u32 opcode) { fpu_debug(("frestore_opp at %08lx\n", m68k_getpc ())); - uae_u32 ad; + uae_u32 ad = 0; uae_u32 d; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; @@ -1256,8 +1387,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) if ((opcode & 0x38) == 0) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - m68k_dreg (regs, opcode & 7) = get_fpcr() & 0xFFFF; + m68k_dreg (regs, opcode & 7) = get_fpcr(); fpu_debug(("FMOVEM FPU fpcr (%X) -> D%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { @@ -1283,13 +1413,11 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) fpu_debug(("FMOVEM D%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address)); } } -// } else if ((opcode & 0x38) == 1) { } else if ((opcode & 0x38) == 8) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - m68k_areg (regs, opcode & 7) = get_fpcr() & 0xFFFF; + m68k_areg (regs, opcode & 7) = get_fpcr(); fpu_debug(("FMOVEM FPU fpcr (%X) -> A%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { @@ -1333,7 +1461,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) } else if (extra & 0x2000) { /* FMOVEM FPP->memory */ - uae_u32 ad; + uae_u32 ad = 0; int incr = 0; if (get_fp_ad(opcode, &ad) == 0) { @@ -1352,8 +1480,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) } ad -= incr; if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - put_long (ad, get_fpcr() & 0xFFFF); + put_long (ad, get_fpcr()); fpu_debug(("FMOVEM FPU fpcr (%X) -> mem %X\n", get_fpcr(), ad )); ad += 4; } @@ -1375,7 +1502,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) } else { /* FMOVEM memory->FPP */ - uae_u32 ad; + uae_u32 ad = 0; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); @@ -1421,7 +1548,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) return; case 6: case 7: { - uae_u32 ad, list = 0; + uae_u32 ad = 0, list = 0; int incr = 0; if (extra & 0x2000) { /* FMOVEM FPP->memory */ @@ -1568,27 +1695,27 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) switch (extra & 0x7f) { case 0x00: // FPU registers[reg] = 4.0 * atan(1.0); - FPU registers[reg] = 3.1415926535897932384626433832795; + FPU registers[reg] = LD(3.1415926535897932384626433832795029); fpu_debug(("FP const: Pi\n")); break; case 0x0b: // FPU registers[reg] = log10 (2.0); - FPU registers[reg] = 0.30102999566398119521373889472449; + FPU registers[reg] = LD(0.30102999566398119521); // 0.3010299956639811952137388947244930L fpu_debug(("FP const: Log 10 (2)\n")); break; case 0x0c: // FPU registers[reg] = exp (1.0); - FPU registers[reg] = 2.7182818284590452353602874713527; + FPU registers[reg] = LD(2.7182818284590452353); // 2.7182818284590452353602874713526625L fpu_debug(("FP const: e\n")); break; case 0x0d: // FPU registers[reg] = log (exp (1.0)) / log (2.0); - FPU registers[reg] = 1.4426950408889634073599246810019; + FPU registers[reg] = LD(1.4426950408889634073599246810019); fpu_debug(("FP const: Log 2 (e)\n")); break; case 0x0e: // FPU registers[reg] = log (exp (1.0)) / log (10.0); - FPU registers[reg] = 0.43429448190325182765112891891661; + FPU registers[reg] = LD(0.4342944819032518276511289189166051); fpu_debug(("FP const: Log 10 (e)\n")); break; case 0x0f: @@ -1597,73 +1724,79 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x30: // FPU registers[reg] = log (2.0); - FPU registers[reg] = 0.69314718055994530941723212145818; + FPU registers[reg] = LD(0.6931471805599453094172321214581766); fpu_debug(("FP const: ln(2)\n")); break; case 0x31: // FPU registers[reg] = log (10.0); - FPU registers[reg] = 2.3025850929940456840179914546844; + FPU registers[reg] = LD(2.3025850929940456840179914546843642); fpu_debug(("FP const: ln(10)\n")); break; case 0x32: - // ?? - FPU registers[reg] = 1.0e0; + FPU registers[reg] = LD(1.0e0); fpu_debug(("FP const: 1.0e0\n")); break; case 0x33: - FPU registers[reg] = 1.0e1; + FPU registers[reg] = LD(1.0e1); fpu_debug(("FP const: 1.0e1\n")); break; case 0x34: - FPU registers[reg] = 1.0e2; + FPU registers[reg] = LD(1.0e2); fpu_debug(("FP const: 1.0e2\n")); break; case 0x35: - FPU registers[reg] = 1.0e4; + FPU registers[reg] = LD(1.0e4); fpu_debug(("FP const: 1.0e4\n")); break; case 0x36: - FPU registers[reg] = 1.0e8; + FPU registers[reg] = LD(1.0e8); fpu_debug(("FP const: 1.0e8\n")); break; case 0x37: - FPU registers[reg] = 1.0e16; + FPU registers[reg] = LD(1.0e16); fpu_debug(("FP const: 1.0e16\n")); break; case 0x38: - FPU registers[reg] = 1.0e32; + FPU registers[reg] = LD(1.0e32); fpu_debug(("FP const: 1.0e32\n")); break; case 0x39: - FPU registers[reg] = 1.0e64; + FPU registers[reg] = LD(1.0e64); fpu_debug(("FP const: 1.0e64\n")); break; case 0x3a: - FPU registers[reg] = 1.0e128; + FPU registers[reg] = LD(1.0e128); fpu_debug(("FP const: 1.0e128\n")); break; case 0x3b: - FPU registers[reg] = 1.0e256; + FPU registers[reg] = LD(1.0e256); fpu_debug(("FP const: 1.0e256\n")); break; -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) case 0x3c: - FPU registers[reg] = 1.0e512L; + FPU registers[reg] = LD(1.0e512); fpu_debug(("FP const: 1.0e512\n")); break; case 0x3d: - FPU registers[reg] = 1.0e1024L; + FPU registers[reg] = LD(1.0e1024); fpu_debug(("FP const: 1.0e1024\n")); break; case 0x3e: - FPU registers[reg] = 1.0e2048L; + FPU registers[reg] = LD(1.0e2048); fpu_debug(("FP const: 1.0e2048\n")); break; case 0x3f: - FPU registers[reg] = 1.0e4096L; + FPU registers[reg] = LD(1.0e4096); fpu_debug(("FP const: 1.0e4096\n")); -#endif break; +#else + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + make_inf(FPU registers[reg], false); + break; +#endif default: m68k_setpc (m68k_getpc () - 4); op_illg (opcode); @@ -1761,34 +1894,22 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) fpu_debug(("FMUL %.04f\n",(double)src)); get_dest_flags(FPU registers[reg]); get_source_flags(src); - if(fl_dest.in_range && fl_source.in_range) { + if (fl_dest.in_range && fl_source.in_range) { if ((extra & 0x7f) == 0x63) FPU registers[reg] = (float)(FPU registers[reg] * src); else FPU registers[reg] = (double)(FPU registers[reg] * src); } else if (fl_dest.nan || fl_source.nan || - fl_dest.zero && fl_source.infinity || - fl_dest.infinity && fl_source.zero ) { - make_nan( FPU registers[reg] ); + (fl_dest.zero && fl_source.infinity) || + (fl_dest.infinity && fl_source.zero) ) { + make_nan( FPU registers[reg], fl_dest.negative ); } else if (fl_dest.zero || fl_source.zero ) { - if (fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_zero_negative(FPU registers[reg]); - } - else { - make_zero_positive(FPU registers[reg]); - } + make_zero(FPU registers[reg], fl_dest.negative != fl_source.negative); } else { - if( fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_inf_negative(FPU registers[reg]); - } - else { - make_inf_positive(FPU registers[reg]); - } + make_inf(FPU registers[reg], fl_dest.negative != fl_source.negative); } make_fpsr(FPU registers[reg]); break; @@ -1809,43 +1930,68 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) make_fpsr(FPU registers[reg]); break; case 0x01: /* FINT */ + /* + * FIXME: in round-to-nearest, x87 + * uses round-to-odd, but m68k round-to-even rule + */ fpu_debug(("FINT %.04f\n",(double)src)); - FPU registers[reg] = toint(src); + if (isinf(src)) + FPU registers[reg] = src; + else + FPU registers[reg] = fp_doround(src); make_fpsr(FPU registers[reg]); break; case 0x02: /* FSINH */ fpu_debug(("FSINH %.04f\n",(double)src)); - FPU registers[reg] = fp_sinh (src); + if (isinf(src)) + FPU registers[reg] = src; + else + FPU registers[reg] = fp_sinh (src); make_fpsr(FPU registers[reg]); break; case 0x03: /* FINTRZ */ fpu_debug(("FINTRZ %.04f\n",(double)src)); - FPU registers[reg] = fp_round_to_zero(src); + if (isinf(src)) + FPU registers[reg] = src; + else + FPU registers[reg] = fp_round_to_zero(src); make_fpsr(FPU registers[reg]); break; case 0x04: /* FSQRT */ fpu_debug(("FSQRT %.04f\n",(double)src)); - FPU registers[reg] = fp_sqrt (src); + if (isinf(src) && !isneg(src)) + FPU registers[reg] = src; + else + FPU registers[reg] = fp_sqrt (src); make_fpsr(FPU registers[reg]); break; case 0x06: /* FLOGNP1 */ fpu_debug(("FLOGNP1 %.04f\n",(double)src)); - FPU registers[reg] = fp_log (src + 1.0); + if (isinf(src) && !isneg(src)) + make_inf(FPU registers[reg], false); + else + FPU registers[reg] = fp_log1p (src); make_fpsr(FPU registers[reg]); break; case 0x08: /* FETOXM1 */ fpu_debug(("FETOXM1 %.04f\n",(double)src)); - FPU registers[reg] = fp_exp (src) - 1.0; + FPU registers[reg] = fp_expm1 (src); make_fpsr(FPU registers[reg]); break; case 0x09: /* FTANH */ fpu_debug(("FTANH %.04f\n",(double)src)); - FPU registers[reg] = fp_tanh (src); + if (isinf(src)) + FPU registers[reg] = isneg(src) ? LD(-1.0) : LD(1.0); + else + FPU registers[reg] = fp_tanh (src); make_fpsr(FPU registers[reg]); break; case 0x0a: /* FATAN */ fpu_debug(("FATAN %.04f\n",(double)src)); - FPU registers[reg] = fp_atan (src); + if (isinf(src)) + FPU registers[reg] = isneg (src) ? LD(-1.570796326794896619231321691639751442) : LD(1.570796326794896619231321691639751442); + else + FPU registers[reg] = fp_atan (src); make_fpsr(FPU registers[reg]); break; case 0x0c: /* FASIN */ @@ -1870,32 +2016,65 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x10: /* FETOX */ fpu_debug(("FETOX %.04f\n",(double)src)); - FPU registers[reg] = fp_exp (src); + if (isinf(src)) + { + make_zero(FPU registers[reg], isneg(src)); + } else + { + FPU registers[reg] = fp_exp (src); + } make_fpsr(FPU registers[reg]); break; case 0x11: /* FTWOTOX */ fpu_debug(("FTWOTOX %.04f\n",(double)src)); - FPU registers[reg] = fp_pow(2.0, src); + if (isinf(src)) + { + if (isneg(src)) + make_zero(FPU registers[reg], false); + else + make_inf(FPU registers[reg], true); + } else + { + FPU registers[reg] = fp_pow2(src); + } make_fpsr(FPU registers[reg]); break; case 0x12: /* FTENTOX */ fpu_debug(("FTENTOX %.04f\n",(double)src)); - FPU registers[reg] = fp_pow(10.0, src); + if (isinf(src)) + { + if (isneg(src)) + make_zero(FPU registers[reg], false); + else + make_inf(FPU registers[reg], true); + } else + { + FPU registers[reg] = fp_pow10(src); + } make_fpsr(FPU registers[reg]); break; case 0x14: /* FLOGN */ fpu_debug(("FLOGN %.04f\n",(double)src)); - FPU registers[reg] = fp_log (src); + if (isinf(src) && !isneg(src)) + make_inf(FPU registers[reg], false); + else + FPU registers[reg] = fp_log (src); make_fpsr(FPU registers[reg]); break; case 0x15: /* FLOG10 */ fpu_debug(("FLOG10 %.04f\n",(double)src)); - FPU registers[reg] = fp_log10 (src); + if (isinf(src) && !isneg(src)) + make_inf(FPU registers[reg], false); + else + FPU registers[reg] = fp_log10 (src); make_fpsr(FPU registers[reg]); break; case 0x16: /* FLOG2 */ fpu_debug(("FLOG2 %.04f\n",(double)src)); - FPU registers[reg] = fp_log (src) / fp_log (2.0); + if (isinf(src) && !isneg(src)) + make_inf(FPU registers[reg], false); + else + FPU registers[reg] = fp_log2 (src); make_fpsr(FPU registers[reg]); break; case 0x18: /* FABS */ @@ -1905,12 +2084,21 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x19: /* FCOSH */ fpu_debug(("FCOSH %.04f\n",(double)src)); - FPU registers[reg] = fp_cosh(src); + if (isinf(src)) + { + make_inf(FPU registers[reg], false); + } else + { + FPU registers[reg] = fp_cosh(src); + } make_fpsr(FPU registers[reg]); break; case 0x1a: /* FNEG */ fpu_debug(("FNEG %.04f\n",(double)src)); - FPU registers[reg] = -src; + if (iszero(src)) + make_zero(FPU registers[reg], !isneg(src)); + else + FPU registers[reg] = -src; make_fpsr(FPU registers[reg]); break; case 0x1c: /* FACOS */ @@ -1926,20 +2114,24 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) case 0x1e: /* FGETEXP */ fpu_debug(("FGETEXP %.04f\n",(double)src)); if( isinf(src) ) { - make_nan( FPU registers[reg] ); + make_nan( FPU registers[reg], isneg(src) ); + } + else if( iszero(src) ) { + make_zero(FPU registers[reg], isneg(src)); } else { + /* FIXME: subnormals not supported */ FPU registers[reg] = fast_fgetexp( src ); } make_fpsr(FPU registers[reg]); break; case 0x1f: /* FGETMAN */ fpu_debug(("FGETMAN %.04f\n",(double)src)); - if( src == 0 ) { - FPU registers[reg] = 0; + if( iszero(src)) { + make_zero(FPU registers[reg], isneg(src)); } - else if( isinf(src) ) { - make_nan( FPU registers[reg] ); + else if( isinf(src) || isnan(src) ) { + make_nan( FPU registers[reg], 0 ); } else { FPU registers[reg] = src; @@ -1949,7 +2141,28 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x20: /* FDIV */ fpu_debug(("FDIV %.04f\n",(double)src)); - FPU registers[reg] /= src; + if (isnan(src) || isnan(FPU registers[reg])) + { + make_nan(FPU registers[reg], false); + } else if (isinf(src)) + { + if (isinf(FPU registers[reg])) + make_nan(FPU registers[reg], false); + else + make_zero(FPU registers[reg], isneg(src) != isneg(FPU registers[reg])); + } else if (isinf(FPU registers[reg])) + { + if (isinf(src)) + make_nan(FPU registers[reg], false); + else + make_inf(FPU registers[reg], isneg(src) != isneg(FPU registers[reg])); + } else if (iszero(FPU registers[reg]) && !iszero(src)) + { + make_zero(FPU registers[reg], isneg(FPU registers[reg]) != isneg(src)); + } else + { + FPU registers[reg] /= src; + } make_fpsr(FPU registers[reg]); break; case 0x21: /* FMOD */ @@ -1967,31 +2180,23 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) fpu_debug(("FMUL %.04f\n",(double)src)); get_dest_flags(FPU registers[reg]); get_source_flags(src); - if(fl_dest.in_range && fl_source.in_range) { + if (fl_dest.in_range && fl_source.in_range) { FPU registers[reg] *= src; + if (unlikely(isinf(FPU registers[reg]))) + { + make_inf(FPU registers[reg], isneg(FPU registers[reg])); + } } else if (fl_dest.nan || fl_source.nan || - fl_dest.zero && fl_source.infinity || - fl_dest.infinity && fl_source.zero ) { - make_nan( FPU registers[reg] ); + (fl_dest.zero && fl_source.infinity) || + (fl_dest.infinity && fl_source.zero) ) { + make_nan( FPU registers[reg], fl_dest.negative ); } else if (fl_dest.zero || fl_source.zero ) { - if (fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_zero_negative(FPU registers[reg]); - } - else { - make_zero_positive(FPU registers[reg]); - } + make_zero(FPU registers[reg], fl_dest.negative != fl_source.negative); } else { - if( fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_inf_negative(FPU registers[reg]); - } - else { - make_inf_positive(FPU registers[reg]); - } + make_inf(FPU registers[reg], fl_dest.negative != fl_source.negative); } make_fpsr(FPU registers[reg]); break; @@ -2022,24 +2227,49 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) // an overflow or underflow always results. // Here (int) cast is okay. int scale_factor = (int)fp_round_to_zero(src); -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, FPU registers[reg], extended); - sxp->ieee.exponent += scale_factor; +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = FPU registers[reg]; + int exp = sxp.ieee.exponent; + exp += scale_factor; + if (scale_factor >= FP_EXTENDED_EXP_MAX || exp >= FP_EXTENDED_EXP_MAX) /* overflow */ + { + make_inf(FPU registers[reg], isneg(FPU registers[reg])); + FPU fpsr.exception_status |= FPSR_EXCEPTION_OVFL; + } else if (scale_factor < -FP_EXTENDED_EXP_MAX || exp <= -64) /* underflow */ + { + make_zero(FPU registers[reg], isneg(FPU registers[reg])); + FPU fpsr.exception_status |= FPSR_EXCEPTION_UNFL; + } else if (exp >= 0) /* normal result */ + { + sxp.ieee.exponent = exp; + FPU registers[reg] = sxp.value; + } else /* subnormal result */ + { + exp += 64; + sxp.ieee.exponent = exp; + sxp.value = sxp.value * 5.421010862427522170037e-20L; /* 2^-64 */ + } #else - fp_declare_init_shape(sxp, FPU registers[reg], double); - uae_u32 exp = sxp->ieee.exponent + scale_factor; + fp_declare_init_shape(sxp, double); + sxp.value = FPU registers[reg]; + uae_u32 exp = sxp.ieee.exponent + scale_factor; if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) exp = 0; else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) exp = FP_DOUBLE_EXP_MAX; else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; - sxp->ieee.exponent = exp; + sxp.ieee.exponent = exp; + FPU registers[reg] = sxp.value; #endif } - else if (fl_source.infinity) { + else if (fl_source.infinity || fl_source.nan) { // Returns NaN for any Infinity source - make_nan( FPU registers[reg] ); + make_nan( FPU registers[reg], fl_source.negative ); + } else { + // source was zero, or dest was inf or nan + // in either case, dest is unchanged } make_fpsr(FPU registers[reg]); break; @@ -2050,12 +2280,52 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x28: /* FSUB */ fpu_debug(("FSUB %.04f\n",(double)src)); - FPU registers[reg] -= src; + if (isnan(src) || isnan(FPU registers[reg])) + { + make_nan(FPU registers[reg], false); + } else if (isinf(src)) + { + if (isinf(FPU registers[reg]) && isneg(src) == isneg(FPU registers[reg])) + make_nan(FPU registers[reg], false); + else + make_inf(FPU registers[reg], isneg(src)); + } else if (isinf(FPU registers[reg])) + { + if (isinf(src) && isneg(src) == isneg(FPU registers[reg])) + make_nan(FPU registers[reg], false); + else + make_inf(FPU registers[reg], isneg(FPU registers[reg])); + } else + { + FPU registers[reg] -= src; + } make_fpsr(FPU registers[reg]); break; case 0x22: /* FADD */ fpu_debug(("FADD %.04f\n",(double)src)); - FPU registers[reg] += src; + /* + * WTF. inf + some value generates NaN on x87, + * but we need inf in most cases + */ + if (isnan(src) || isnan(FPU registers[reg])) + { + make_nan(FPU registers[reg], false); + } else if (isinf(src)) + { + if (isinf(FPU registers[reg]) && isneg(src) != isneg(FPU registers[reg])) + make_nan(FPU registers[reg], false); + else + make_inf(FPU registers[reg], isneg(src)); + } else if (isinf(FPU registers[reg])) + { + if (isinf(src) && isneg(src) != isneg(FPU registers[reg])) + make_nan(FPU registers[reg], false); + else + make_inf(FPU registers[reg], isneg(FPU registers[reg])); + } else + { + FPU registers[reg] += src; + } make_fpsr(FPU registers[reg]); break; case 0x30: /* FSINCOS */ @@ -2068,6 +2338,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) case 0x37: fpu_debug(("FSINCOS %.04f\n",(double)src)); // Cosine must be calculated first if same register + // note: no need to use special sincos() function here; compiler will optimize that anyway FPU registers[extra & 7] = fp_cos(src); FPU registers[reg] = fp_sin (src); // Set FPU fpsr according to the sine result @@ -2076,7 +2347,17 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) case 0x38: /* FCMP */ fpu_debug(("FCMP %.04f\n",(double)src)); set_fpsr(0); - make_fpsr(FPU registers[reg] - src); + if (isinf(FPU registers[reg])) + { + if (isinf(src) && isneg(FPU registers[reg]) == isneg (src)) + make_fpsr(0); + else + make_fpsr(FPU registers[reg]); + } + else if (isinf(src)) + make_fpsr(-src); + else + make_fpsr(FPU registers[reg] - src); break; case 0x3a: /* FTST */ fpu_debug(("FTST %.04f\n",(double)src)); @@ -2100,6 +2381,27 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) dump_registers( "END "); } + +void fpu_set_fpsr(uae_u32 new_fpsr) +{ + set_fpsr(new_fpsr); +} + +uae_u32 fpu_get_fpsr(void) +{ + return get_fpsr(); +} + +void fpu_set_fpcr(uae_u32 new_fpcr) +{ + set_fpcr(new_fpcr); +} + +uae_u32 fpu_get_fpcr(void) +{ + return get_fpcr(); +} + /* -------------------------- Initialization -------------------------- */ PRIVATE uae_u8 m_fpu_state_original[108]; // 90/94/108 @@ -2136,7 +2438,7 @@ PUBLIC void FFPU fpu_init (bool integral_68040) FPU result = 1; for (int i = 0; i < 8; i++) - make_nan(FPU registers[i]); + make_nan(FPU registers[i], false); } PUBLIC void FFPU fpu_exit (void) diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_ieee.h b/BasiliskII/src/uae_cpu/fpu/fpu_ieee.h index 89501956..5735874c 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_ieee.h +++ b/BasiliskII/src/uae_cpu/fpu/fpu_ieee.h @@ -1,28 +1,33 @@ /* - * fpu/fpu_uae.h - Extra Definitions for the old UAE FPU core + * fpu/fpu_ieee.h - Extra Definitions for the IEEE FPU core * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_IEEE_H @@ -54,13 +59,11 @@ PRIVATE double_flags fl_dest; PRIVATE inline void FFPU get_dest_flags(fpu_register const & r); PRIVATE inline void FFPU get_source_flags(fpu_register const & r); -PRIVATE inline void FFPU make_nan(fpu_register & r); -PRIVATE inline void FFPU make_zero_positive(fpu_register & r); -PRIVATE inline void FFPU make_zero_negative(fpu_register & r); -PRIVATE inline void FFPU make_inf_positive(fpu_register & r); -PRIVATE inline void FFPU make_inf_negative(fpu_register & r); +PRIVATE inline void FFPU make_nan(fpu_register & r, bool negative); +PRIVATE inline void FFPU make_zero(fpu_register & r, bool negative); +PRIVATE inline void FFPU make_inf(fpu_register & r, bool negative); -PRIVATE inline void FFPU fast_scale(fpu_register & r, int add); +// MJ PRIVATE inline void FFPU fast_scale(fpu_register & r, int add); PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r); // May be optimized for particular processors diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_mpfr.cpp b/BasiliskII/src/uae_cpu/fpu/fpu_mpfr.cpp new file mode 100644 index 00000000..4eda14ca --- /dev/null +++ b/BasiliskII/src/uae_cpu/fpu/fpu_mpfr.cpp @@ -0,0 +1,2110 @@ +/* + * fpu_mpfr.cpp - emulate 68881/68040 fpu with mpfr + * + * Copyright (c) 2012, 2013 Andreas Schwab + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include +#include "memory.h" +#include "readcpu.h" +#include "newcpu.h" +#include "main.h" +#define FPU_IMPLEMENTATION +#include "fpu/fpu.h" + +#include "fpu/flags.h" +#include "fpu/exceptions.h" +#include "fpu/rounding.h" +#include "fpu/impl.h" + +#define SINGLE_PREC 24 +#define SINGLE_MIN_EXP -126 +#define SINGLE_MAX_EXP 127 +#define SINGLE_BIAS 127 +#define DOUBLE_PREC 53 +#define DOUBLE_MIN_EXP -1022 +#define DOUBLE_MAX_EXP 1023 +#define DOUBLE_BIAS 1023 +#define EXTENDED_PREC 64 +#define EXTENDED_MIN_EXP -16383 +#define EXTENDED_MAX_EXP 16383 +#define EXTENDED_BIAS 16383 + +fpu_t fpu; +// The constant ROM +// Constants 48 to 63 are mapped to index 16 to 31 +const int num_fpu_constants = 32; +static mpfr_t fpu_constant_rom[num_fpu_constants]; +#define FPU_CONSTANT_ONE fpu_constant_rom[18] +// Exceptions generated during execution in addition to the ones +// maintained by mpfr +static uae_u32 cur_exceptions; +static uaecptr cur_instruction_address; + +static void +set_format (int prec) +{ + // MPFR represents numbers as 0.m*2^e + switch (prec) + { + case SINGLE_PREC: + mpfr_set_emin (SINGLE_MIN_EXP + 1 - (SINGLE_PREC - 1)); + mpfr_set_emax (SINGLE_MAX_EXP + 1); + break; + case DOUBLE_PREC: + mpfr_set_emin (DOUBLE_MIN_EXP + 1 - (DOUBLE_PREC - 1)); + mpfr_set_emax (DOUBLE_MAX_EXP + 1); + break; + case EXTENDED_PREC: + mpfr_set_emin (EXTENDED_MIN_EXP + 1 - (EXTENDED_PREC - 1)); + mpfr_set_emax (EXTENDED_MAX_EXP + 1); + break; + } +} + +static mpfr_rnd_t +get_cur_rnd () +{ + switch (get_rounding_mode ()) + { + default: + case FPCR_ROUND_NEAR: + return MPFR_RNDN; + case FPCR_ROUND_ZERO: + return MPFR_RNDZ; + case FPCR_ROUND_MINF: + return MPFR_RNDD; + case FPCR_ROUND_PINF: + return MPFR_RNDU; + } +} + +static mpfr_prec_t +get_cur_prec () +{ + switch (get_rounding_precision ()) + { + default: + case FPCR_PRECISION_EXTENDED: + return EXTENDED_PREC; + case FPCR_PRECISION_SINGLE: + return SINGLE_PREC; + case FPCR_PRECISION_DOUBLE: + return DOUBLE_PREC; + } +} + +#define DEFAULT_NAN_BITS 0xffffffffffffffffULL + +static void +set_nan (fpu_register ®, uae_u64 nan_bits, int nan_sign) +{ + mpfr_set_nan (reg.f); + reg.nan_bits = nan_bits; + reg.nan_sign = nan_sign; +} + +static void +set_nan (fpu_register ®) +{ + set_nan (reg, DEFAULT_NAN_BITS, 0); +} + +static bool fpu_inited; + +void +fpu_init (bool integral_68040) +{ + fpu.is_integral = integral_68040; + + mpfr_set_default_prec (EXTENDED_PREC); + mpfr_set_default_rounding_mode (MPFR_RNDN); + set_format (EXTENDED_PREC); + + for (int i = 0; i < 8; i++) + mpfr_init (fpu.registers[i].f); + mpfr_init (fpu.result.f); + + // Initialize constant ROM + for (int i = 0; i < num_fpu_constants; i++) + mpfr_init (fpu_constant_rom[i]); + + // 0: pi + mpfr_const_pi (fpu_constant_rom[0], MPFR_RNDN); + // 11: log10 (2) + mpfr_set_ui (fpu_constant_rom[11], 2, MPFR_RNDN); + mpfr_log10 (fpu_constant_rom[11], fpu_constant_rom[11], MPFR_RNDZ); + // 12: e + mpfr_set_ui (fpu_constant_rom[12], 1, MPFR_RNDN); + mpfr_exp (fpu_constant_rom[12], fpu_constant_rom[12], MPFR_RNDZ); + // 13: log2 (e) + mpfr_log2 (fpu_constant_rom[13], fpu_constant_rom[12], MPFR_RNDU); + // 14: log10 (e) + mpfr_log10 (fpu_constant_rom[14], fpu_constant_rom[12], MPFR_RNDU); + // 15: 0 + mpfr_set_zero (fpu_constant_rom[15], 0); + // 48: ln (2) + mpfr_const_log2 (fpu_constant_rom[16], MPFR_RNDN); + // 49: ln (10) + mpfr_set_ui (fpu_constant_rom[17], 10, MPFR_RNDN); + mpfr_log (fpu_constant_rom[17], fpu_constant_rom[17], MPFR_RNDN); + // 50 to 63: powers of 10 + mpfr_set_ui (fpu_constant_rom[18], 1, MPFR_RNDN); + for (int i = 19; i < 32; i++) + { + mpfr_set_ui (fpu_constant_rom[i], 1L << (i - 19) , MPFR_RNDN); + mpfr_exp10 (fpu_constant_rom[i], fpu_constant_rom[i], MPFR_RNDN); + } + + fpu_inited = true; + + fpu_reset (); +} + +void +fpu_exit () +{ + if (!fpu_inited) return; + + for (int i = 0; i < 8; i++) + mpfr_clear (fpu.registers[i].f); + mpfr_clear (fpu.result.f); + for (int i = 0; i < num_fpu_constants; i++) + mpfr_clear (fpu_constant_rom[i]); +} + +void +fpu_reset () +{ + set_fpcr (0); + set_fpsr (0); + fpu.instruction_address = 0; + + for (int i = 0; i < 8; i++) + set_nan (fpu.registers[i]); +} + +fpu_register::operator long double () +{ + return mpfr_get_ld (f, MPFR_RNDN); +} + +fpu_register & +fpu_register::operator= (long double x) +{ + mpfr_set_ld (f, x, MPFR_RNDN); + nan_bits = DEFAULT_NAN_BITS; + nan_sign = 0; + return *this; +} + +static bool +get_fp_addr (uae_u32 opcode, uae_u32 *addr, bool write) +{ + uaecptr pc; + int mode; + int reg; + + mode = (opcode >> 3) & 7; + reg = opcode & 7; + switch (mode) + { + case 0: + case 1: + return false; + case 2: + *addr = m68k_areg (regs, reg); + break; + case 3: + *addr = m68k_areg (regs, reg); + break; + case 4: + *addr = m68k_areg (regs, reg); + break; + case 5: + *addr = m68k_areg (regs, reg) + (uae_s16) next_iword(); + break; + case 6: + *addr = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); + break; + case 7: + switch (reg) + { + case 0: + *addr = (uae_s16) next_iword(); + break; + case 1: + *addr = next_ilong(); + break; + case 2: + if (write) + return false; + pc = m68k_getpc (); + *addr = pc + (uae_s16) next_iword(); + break; + case 3: + if (write) + return false; + pc = m68k_getpc (); + *addr = get_disp_ea_020 (pc, next_iword()); + break; + default: + return false; + } + } + return true; +} + +static void +set_from_single (fpu_register &value, uae_u32 data) +{ + int s = data >> 31; + int e = (data >> 23) & 0xff; + uae_u32 m = data & 0x7fffff; + + if (e == 0xff) + { + if (m != 0) + { + if (!(m & 0x400000)) + cur_exceptions |= FPSR_EXCEPTION_SNAN; + set_nan (value, (uae_u64) (m | 0xc00000) << (32 + 8), s); + } + else + mpfr_set_inf (value.f, 0); + } + else + { + if (e != 0) + // Add integer bit + m |= 0x800000; + else + e++; + // Remove bias + e -= SINGLE_BIAS; + mpfr_set_ui_2exp (value.f, m, e - (SINGLE_PREC - 1), MPFR_RNDN); + } + mpfr_setsign (value.f, value.f, s, MPFR_RNDN); +} + +static void +set_from_double (fpu_register &value, uae_u32 words[2]) +{ + int s = words[0] >> 31; + int e = (words[0] >> 20) & 0x7ff; + uae_u32 m = words[0] & 0xfffff; + + if (e == 0x7ff) + { + if ((m | words[1]) != 0) + { + if (!(m & 0x80000)) + cur_exceptions |= FPSR_EXCEPTION_SNAN; + set_nan (value, (((uae_u64) (m | 0x180000) << (32 + 11)) + | ((uae_u64) words[1] << 11)), s); + } + else + mpfr_set_inf (value.f, 0); + } + else + { + if (e != 0) + // Add integer bit + m |= 0x100000; + else + e++; + // Remove bias + e -= DOUBLE_BIAS; + mpfr_set_uj_2exp (value.f, ((uintmax_t) m << 32) | words[1], + e - (DOUBLE_PREC - 1), MPFR_RNDN); + } + mpfr_setsign (value.f, value.f, s, MPFR_RNDN); +} + +static void +set_from_extended (fpu_register &value, uae_u32 words[3], bool check_snan) +{ + int s = words[0] >> 31; + int e = (words[0] >> 16) & 0x7fff; + + if (e == 0x7fff) + { + if (((words[1] & 0x7fffffff) | words[2]) != 0) + { + if (check_snan) + { + if ((words[1] & 0x40000000) == 0) + cur_exceptions |= FPSR_EXCEPTION_SNAN; + words[1] |= 0x40000000; + } + set_nan (value, ((uae_u64) words[1] << 32) | words[2], s); + } + else + mpfr_set_inf (value.f, 0); + } + else + { + // Remove bias + e -= EXTENDED_BIAS; + mpfr_set_uj_2exp (value.f, ((uintmax_t) words[1] << 32) | words[2], + e - (EXTENDED_PREC - 1), MPFR_RNDN); + } + mpfr_setsign (value.f, value.f, s, MPFR_RNDN); +} + +#define from_bcd(d) ((d) < 10 ? (d) : (d) - 10) + +static void +set_from_packed (fpu_register &value, uae_u32 words[3]) +{ + char str[32], *p = str; + int sm = words[0] >> 31; + int se = (words[0] >> 30) & 1; + int i; + + if (((words[0] >> 16) & 0x7fff) == 0x7fff) + { + if ((words[1] | words[2]) != 0) + { + if ((words[1] & 0x40000000) == 0) + cur_exceptions |= FPSR_EXCEPTION_SNAN; + set_nan (value, ((uae_u64) (words[1] | 0x40000000) << 32) | words[2], + sm); + } + else + mpfr_set_inf (value.f, 0); + } + else + { + if (sm) + *p++ = '-'; + *p++ = from_bcd (words[0] & 15) + '0'; + *p++ = '.'; + for (i = 0; i < 8; i++) + { + p[i] = from_bcd ((words[1] >> (28 - i * 4)) & 15) + '0'; + p[i + 8] = from_bcd ((words[2] >> (28 - i * 4)) & 15) + '0'; + } + p += 16; + *p++ = 'e'; + if (se) + *p++ = '-'; + *p++ = from_bcd ((words[0] >> 24) & 15) + '0'; + *p++ = from_bcd ((words[0] >> 20) & 15) + '0'; + *p++ = from_bcd ((words[0] >> 16) & 15) + '0'; + *p = 0; + mpfr_set_str (value.f, str, 10, MPFR_RNDN); + } + mpfr_setsign (value.f, value.f, sm, MPFR_RNDN); +} + +static bool +get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register &value) +{ + int mode, reg, size; + uaecptr pc; + uae_u32 addr; + uae_u32 words[3]; + static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; + static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; + + if ((extra & 0x4000) == 0) + { + mpfr_set (value.f, fpu.registers[(extra >> 10) & 7].f, MPFR_RNDN); + value.nan_bits = fpu.registers[(extra >> 10) & 7].nan_bits; + value.nan_sign = fpu.registers[(extra >> 10) & 7].nan_sign; + /* Check for SNaN. */ + if (mpfr_nan_p (value.f) && (value.nan_bits & (1ULL << 62)) == 0) + { + value.nan_bits |= 1ULL << 62; + cur_exceptions |= FPSR_EXCEPTION_SNAN; + } + return true; + } + mode = (opcode >> 3) & 7; + reg = opcode & 7; + size = (extra >> 10) & 7; + switch (mode) + { + case 0: + switch (size) + { + case 6: + mpfr_set_si (value.f, (uae_s8) m68k_dreg (regs, reg), MPFR_RNDN); + break; + case 4: + mpfr_set_si (value.f, (uae_s16) m68k_dreg (regs, reg), MPFR_RNDN); + break; + case 0: + mpfr_set_si (value.f, (uae_s32) m68k_dreg (regs, reg), MPFR_RNDN); + break; + case 1: + set_from_single (value, m68k_dreg (regs, reg)); + break; + default: + return false; + } + return true; + case 1: + return false; + case 2: + case 3: + addr = m68k_areg (regs, reg); + break; + case 4: + addr = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]); + break; + case 5: + addr = m68k_areg (regs, reg) + (uae_s16) next_iword (); + break; + case 6: + addr = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ()); + break; + case 7: + switch (reg) + { + case 0: + addr = (uae_s16) next_iword (); + break; + case 1: + addr = next_ilong (); + break; + case 2: + pc = m68k_getpc (); + addr = pc + (uae_s16) next_iword (); + break; + case 3: + pc = m68k_getpc (); + addr = get_disp_ea_020 (pc, next_iword ()); + break; + case 4: + addr = m68k_getpc (); + m68k_incpc (sz2[size]); + if (size == 6) // Immediate byte + addr++; + break; + default: + return false; + } + } + + switch (size) + { + case 0: + mpfr_set_si (value.f, (uae_s32) get_long (addr), MPFR_RNDN); + break; + case 1: + set_from_single (value, get_long (addr)); + break; + case 2: + words[0] = get_long (addr); + words[1] = get_long (addr + 4); + words[2] = get_long (addr + 8); + set_from_extended (value, words, true); + break; + case 3: + words[0] = get_long (addr); + words[1] = get_long (addr + 4); + words[2] = get_long (addr + 8); + set_from_packed (value, words); + break; + case 4: + mpfr_set_si (value.f, (uae_s16) get_word (addr), MPFR_RNDN); + break; + case 5: + words[0] = get_long (addr); + words[1] = get_long (addr + 4); + set_from_double (value, words); + break; + case 6: + mpfr_set_si (value.f, (uae_s8) get_byte (addr), MPFR_RNDN); + break; + default: + return false; + } + + switch (mode) + { + case 3: + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; + case 4: + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + break; + } + + return true; +} + +static void +update_exceptions () +{ + uae_u32 exc, aexc; + + exc = cur_exceptions; + // Add any mpfr detected exceptions + if (mpfr_underflow_p ()) + exc |= FPSR_EXCEPTION_UNFL; + if (mpfr_overflow_p ()) + exc |= FPSR_EXCEPTION_OVFL; + if (mpfr_inexflag_p ()) + exc |= FPSR_EXCEPTION_INEX2; + set_exception_status (exc); + + aexc = get_accrued_exception (); + if (exc & (FPSR_EXCEPTION_SNAN|FPSR_EXCEPTION_OPERR)) + aexc |= FPSR_ACCR_IOP; + if (exc & FPSR_EXCEPTION_OVFL) + aexc |= FPSR_ACCR_OVFL; + if ((exc & (FPSR_EXCEPTION_UNFL|FPSR_EXCEPTION_INEX2)) + == (FPSR_EXCEPTION_UNFL|FPSR_EXCEPTION_INEX2)) + aexc |= FPSR_ACCR_UNFL; + if (exc & FPSR_EXCEPTION_DZ) + aexc |= FPSR_ACCR_DZ; + if (exc & (FPSR_EXCEPTION_INEX1|FPSR_EXCEPTION_INEX2|FPSR_EXCEPTION_OVFL)) + aexc |= FPSR_ACCR_INEX; + set_accrued_exception (aexc); + + if ((fpu.fpcr & exc) != 0) + { + fpu.instruction_address = cur_instruction_address; + // TODO: raise exceptions + // Problem: FPSP040 depends on proper FPU stack frames, it would suffer + // undefined behaviour with our dummy FSAVE implementation + } +} + +static void +set_fp_register (int reg, mpfr_t value, uae_u64 nan_bits, int nan_sign, + int t, mpfr_rnd_t rnd, bool do_flags) +{ + mpfr_subnormalize (value, t, rnd); + mpfr_set (fpu.registers[reg].f, value, rnd); + fpu.registers[reg].nan_bits = nan_bits; + fpu.registers[reg].nan_sign = nan_sign; + if (do_flags) + { + uae_u32 flags = 0; + + if (mpfr_zero_p (fpu.registers[reg].f)) + flags |= FPSR_CCB_ZERO; + if (mpfr_signbit (fpu.registers[reg].f)) + flags |= FPSR_CCB_NEGATIVE; + if (mpfr_nan_p (fpu.registers[reg].f)) + flags |= FPSR_CCB_NAN; + if (mpfr_inf_p (fpu.registers[reg].f)) + flags |= FPSR_CCB_INFINITY; + set_fpccr (flags); + } +} + +static void +set_fp_register (int reg, mpfr_t value, int t, mpfr_rnd_t rnd, bool do_flags) +{ + set_fp_register (reg, value, DEFAULT_NAN_BITS, 0, t, rnd, do_flags); +} + +static void +set_fp_register (int reg, fpu_register &value, int t, mpfr_rnd_t rnd, + bool do_flags) +{ + set_fp_register (reg, value.f, value.nan_bits, value.nan_sign, t, rnd, + do_flags); +} + +static uae_u32 +extract_to_single (fpu_register &value) +{ + uae_u32 word; + int t; + mpfr_rnd_t rnd = get_cur_rnd (); + MPFR_DECL_INIT (single, SINGLE_PREC); + + set_format (SINGLE_PREC); + // Round to single + t = mpfr_set (single, value.f, rnd); + t = mpfr_check_range (single, t, rnd); + mpfr_subnormalize (single, t, rnd); + set_format (EXTENDED_PREC); + + if (mpfr_inf_p (single)) + word = 0x7f800000; + else if (mpfr_nan_p (single)) + { + if ((value.nan_bits & (1ULL << 62)) == 0) + { + value.nan_bits |= 1ULL << 62; + cur_exceptions |= FPSR_EXCEPTION_SNAN; + } + word = 0x7f800000 | ((value.nan_bits >> (32 + 8)) & 0x7fffff); + if (value.nan_sign) + word |= 0x80000000; + } + else if (mpfr_zero_p (single)) + word = 0; + else + { + int e; + mpz_t f; + mpz_init (f); + word = 0; + // Get exponent and mantissa + e = mpfr_get_z_2exp (f, single); + // Move binary point + e += SINGLE_PREC - 1; + // Add bias + e += SINGLE_BIAS; + if (e <= 0) + { + // Denormalized number + mpz_tdiv_q_2exp (f, f, -e + 1); + e = 0; + } + mpz_export (&word, 0, 1, 4, 0, 0, f); + // Remove integer bit + word &= 0x7fffff; + word |= e << 23; + mpz_clear (f); + } + if (mpfr_signbit (single)) + word |= 0x80000000; + return word; +} + +static void +extract_to_double (fpu_register &value, uint32_t *words) +{ + int t; + mpfr_rnd_t rnd = get_cur_rnd (); + MPFR_DECL_INIT (dbl, DOUBLE_PREC); + + set_format (DOUBLE_PREC); + // Round to double + t = mpfr_set (dbl, value.f, rnd); + t = mpfr_check_range (dbl, t, rnd); + mpfr_subnormalize (dbl, t, rnd); + set_format (EXTENDED_PREC); + + if (mpfr_inf_p (dbl)) + { + words[0] = 0x7ff00000; + words[1] = 0; + } + else if (mpfr_nan_p (dbl)) + { + if ((value.nan_bits & (1ULL << 62)) == 0) + { + value.nan_bits |= 1ULL << 62; + cur_exceptions |= FPSR_EXCEPTION_SNAN; + } + words[0] = 0x7ff00000 | ((value.nan_bits >> (32 + 11)) & 0xfffff); + words[1] = value.nan_bits >> 11; + if (value.nan_sign) + words[0] |= 0x80000000; + } + else if (mpfr_zero_p (dbl)) + { + words[0] = 0; + words[1] = 0; + } + else + { + int e, off = 0; + mpz_t f; + mpz_init (f); + words[0] = words[1] = 0; + // Get exponent and mantissa + e = mpfr_get_z_2exp (f, dbl); + // Move binary point + e += DOUBLE_PREC - 1; + // Add bias + e += DOUBLE_BIAS; + if (e <= 0) + { + // Denormalized number + mpz_tdiv_q_2exp (f, f, -e + 1); + if (e <= -20) + // No more than 32 bits left + off = 1; + e = 0; + } + mpz_export (&words[off], 0, 1, 4, 0, 0, f); + // Remove integer bit + words[0] &= 0xfffff; + words[0] |= e << 20; + mpz_clear (f); + } + if (mpfr_signbit (dbl)) + words[0] |= 0x80000000; +} + +static void +extract_to_extended (fpu_register &value, uint32_t *words) +{ + if (mpfr_inf_p (value.f)) + { + words[0] = 0x7fff0000; + words[1] = 0; + words[2] = 0; + } + else if (mpfr_nan_p (value.f)) + { + words[0] = 0x7fff0000; + words[1] = value.nan_bits >> 32; + words[2] = value.nan_bits; + if (value.nan_sign) + words[0] |= 0x80000000; + } + else if (mpfr_zero_p (value.f)) + { + words[0] = 0; + words[1] = 0; + words[2] = 0; + } + else + { + int e, off = 0; + mpz_t f; + + mpz_init (f); + words[0] = words[1] = words[2] = 0; + // Get exponent and mantissa + e = mpfr_get_z_2exp (f, value.f); + // Move binary point + e += EXTENDED_PREC - 1; + // Add bias + e += EXTENDED_BIAS; + if (e < 0) + { + // Denormalized number + mpz_tdiv_q_2exp (f, f, -e); + if (e <= -32) + // No more than 32 bits left + off = 1; + e = 0; + } + mpz_export (&words[1 + off], 0, 1, 4, 0, 0, f); + words[0] = e << 16; + mpz_clear (f); + } + if (mpfr_signbit (value.f)) + words[0] |= 0x80000000; +} + +static void +extract_to_packed (fpu_register &value, int k, uae_u32 *words) +{ + if (mpfr_inf_p (value.f)) + { + words[0] = 0x7fff0000; + words[1] = 0; + words[2] = 0; + } + else if (mpfr_nan_p (value.f)) + { + words[0] = 0x7fff0000; + words[1] = value.nan_bits >> 32; + words[2] = value.nan_bits; + if (value.nan_sign) + words[0] |= 0x80000000; + } + else if (mpfr_zero_p (value.f)) + { + words[0] = 0; + words[1] = 0; + words[2] = 0; + } + else + { + char str[100], *p = str; + mpfr_exp_t e; + mpfr_rnd_t rnd = get_cur_rnd (); + + words[0] = words[1] = words[2] = 0; + if (k >= 64) + k -= 128; + else if (k >= 18) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + if (k <= 0) + { + MPFR_DECL_INIT (temp, 16); + + mpfr_log10 (temp, value.f, rnd); + k = mpfr_get_si (temp, MPFR_RNDZ) - k + 1; + } + if (k <= 0) + k = 1; + else if (k >= 18) + k = 17; + mpfr_get_str (str, &e, 10, k, value.f, rnd); + e--; + if (*p == '-') + p++; + // Pad to 17 digits + while (k < 17) + p[k++] = '0'; + if (e < 0) + { + words[0] |= 0x40000000; + e = -e; + } + words[0] |= (e % 10) << 16; + e /= 10; + words[0] |= (e % 10) << 20; + e /= 10; + words[0] |= (e % 10) << 24; + e /= 10; + if (e) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + words[0] |= e << 12; + words[0] |= *p++ & 15; + for (k = 0; k < 8; k++) + words[1] = (words[1] << 4) | (*p++ & 15); + for (k = 0; k < 8; k++) + words[2] = (words[2] << 4) | (*p++ & 15); + + } + if (mpfr_signbit (value.f)) + words[0] |= 0x80000000; +} + +static long +extract_to_integer (mpfr_t value, long min, long max) +{ + long result; + mpfr_rnd_t rnd = get_cur_rnd (); + + if (mpfr_fits_slong_p (value, rnd)) + { + result = mpfr_get_si (value, rnd); + if (result > max) + { + result = max; + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (result < min) + { + result = min; + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + } + else + { + if (!mpfr_signbit (value)) + result = max; + else + result = min; + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + return result; +} + +static bool +fpuop_fmove_memory (uae_u32 opcode, uae_u32 extra) +{ + int mode, reg, size; + uaecptr pc; + uae_u32 addr; + uae_u32 words[3]; + static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; + static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; + + mpfr_clear_flags (); + cur_exceptions = 0; + mode = (opcode >> 3) & 7; + reg = opcode & 7; + size = (extra >> 10) & 7; + fpu_register &value = fpu.registers[(extra >> 7) & 7]; + + switch (mode) + { + case 0: + switch (size) + { + case 0: + m68k_dreg (regs, reg) = extract_to_integer (value.f, -0x7fffffff-1, 0x7fffffff); + break; + case 1: + m68k_dreg (regs, reg) = extract_to_single (value); + break; + case 4: + m68k_dreg (regs, reg) &= ~0xffff; + m68k_dreg (regs, reg) |= extract_to_integer (value.f, -32768, 32767) & 0xffff; + break; + case 6: + m68k_dreg (regs, reg) &= ~0xff; + m68k_dreg (regs, reg) |= extract_to_integer (value.f, -128, 127) & 0xff; + break; + default: + return false; + } + update_exceptions (); + return true; + case 1: + return false; + case 2: + addr = m68k_areg (regs, reg); + break; + case 3: + addr = m68k_areg (regs, reg); + break; + case 4: + addr = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]); + break; + case 5: + addr = m68k_areg (regs, reg) + (uae_s16) next_iword(); + break; + case 6: + addr = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); + break; + case 7: + switch (reg) + { + case 0: + addr = (uae_s16) next_iword(); + break; + case 1: + addr = next_ilong(); + break; + case 2: + pc = m68k_getpc (); + addr = pc + (uae_s16) next_iword(); + break; + case 3: + pc = m68k_getpc (); + addr = get_disp_ea_020 (pc, next_iword ()); + break; + case 4: + addr = m68k_getpc (); + m68k_incpc (sz2[size]); + break; + default: + return false; + } + } + + switch (size) + { + case 0: + put_long (addr, extract_to_integer (value.f, -0x7fffffff-1, 0x7fffffff)); + break; + case 1: + put_long (addr, extract_to_single (value)); + break; + case 2: + extract_to_extended (value, words); + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + put_long (addr + 8, words[2]); + break; + case 3: + extract_to_packed (value, extra & 0x7f, words); + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + put_long (addr + 8, words[2]); + break; + case 4: + put_word (addr, extract_to_integer (value.f, -32768, 32767)); + break; + case 5: + extract_to_double (value, words); + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + break; + case 6: + put_byte (addr, extract_to_integer (value.f, -128, 127)); + break; + case 7: + extract_to_packed (value, m68k_dreg (regs, (extra >> 4) & 7) & 0x7f, words); + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + put_long (addr + 8, words[2]); + break; + } + + switch (mode) + { + case 3: + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; + case 4: + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + break; + } + + update_exceptions (); + return true; +} + +static bool +fpuop_fmovem_control (uae_u32 opcode, uae_u32 extra) +{ + int list, mode, reg; + uae_u32 addr; + + list = (extra >> 10) & 7; + mode = (opcode >> 3) & 7; + reg = opcode & 7; + + if (list == 0) + return false; + + if (extra & 0x2000) + { + // FMOVEM to + if (mode == 0) + { + switch (list) + { + case 1: + m68k_dreg (regs, reg) = fpu.instruction_address; + break; + case 2: + m68k_dreg (regs, reg) = get_fpsr (); + break; + case 4: + m68k_dreg (regs, reg) = get_fpcr (); + break; + default: + return false; + } + } + else if (mode == 1) + { + if (list != 1) + return false; + m68k_areg (regs, reg) = fpu.instruction_address; + } + else + { + int nwords; + + if (!get_fp_addr (opcode, &addr, true)) + return false; + nwords = (list & 1) + ((list >> 1) & 1) + ((list >> 2) & 1); + if (mode == 4) + addr -= nwords * 4; + if (list & 4) + { + put_long (addr, get_fpcr ()); + addr += 4; + } + if (list & 2) + { + put_long (addr, get_fpsr ()); + addr += 4; + } + if (list & 1) + { + put_long (addr, fpu.instruction_address); + addr += 4; + } + if (mode == 4) + m68k_areg (regs, reg) = addr - nwords * 4; + else if (mode == 3) + m68k_areg (regs, reg) = addr; + } + } + else + { + // FMOVEM from + + if (mode == 0) + { + switch (list) + { + case 1: + fpu.instruction_address = m68k_dreg (regs, reg); + break; + case 2: + set_fpsr (m68k_dreg (regs, reg)); + break; + case 4: + set_fpcr (m68k_dreg (regs, reg)); + break; + default: + return false; + } + } + else if (mode == 1) + { + if (list != 1) + return false; + fpu.instruction_address = m68k_areg (regs, reg); + } + else if ((opcode & 077) == 074) + { + switch (list) + { + case 1: + fpu.instruction_address = next_ilong (); + break; + case 2: + set_fpsr (next_ilong ()); + break; + case 4: + set_fpcr (next_ilong ()); + break; + default: + return false; + } + } + else + { + int nwords; + + if (!get_fp_addr (opcode, &addr, false)) + return false; + nwords = (list & 1) + ((list >> 1) & 1) + ((list >> 2) & 1); + if (mode == 4) + addr -= nwords * 4; + if (list & 4) + { + set_fpcr (get_long (addr)); + addr += 4; + } + if (list & 2) + { + set_fpsr (get_long (addr)); + addr += 4; + } + if (list & 1) + { + fpu.instruction_address = get_long (addr); + addr += 4; + } + if (mode == 4) + m68k_areg (regs, reg) = addr - nwords * 4; + else if (mode == 3) + m68k_areg (regs, reg) = addr; + } + } + + return true; +} + +static bool +fpuop_fmovem_register (uae_u32 opcode, uae_u32 extra) +{ + uae_u32 addr; + uae_u32 words[3]; + int list; + int i; + + set_format (EXTENDED_PREC); + if (!get_fp_addr (opcode, &addr, extra & 0x2000)) + return false; + if (extra & 0x800) + list = m68k_dreg (regs, (extra >> 4) & 7) & 0xff; + else + list = extra & 0xff; + + if (extra & 0x2000) + { + // FMOVEM to memory + + switch (opcode & 070) + { + case 030: + return false; + case 040: + if (extra & 0x1000) + return false; + for (i = 7; i >= 0; i--) + if (list & (1 << i)) + { + extract_to_extended (fpu.registers[i], words); + addr -= 12; + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + put_long (addr + 8, words[2]); + } + m68k_areg (regs, opcode & 7) = addr; + break; + default: + if ((extra & 0x1000) == 0) + return false; + for (i = 0; i < 8; i++) + if (list & (0x80 >> i)) + { + extract_to_extended (fpu.registers[i], words); + put_long (addr, words[0]); + put_long (addr + 4, words[1]); + put_long (addr + 8, words[2]); + addr += 12; + } + if ((opcode & 070) == 030) + m68k_areg (regs, opcode & 7) = addr; + break; + } + } + else + { + // FMOVEM from memory + + if ((opcode & 070) == 040) + return false; + + if ((extra & 0x1000) == 0) + return false; + for (i = 0; i < 8; i++) + if (list & (0x80 >> i)) + { + words[0] = get_long (addr); + words[1] = get_long (addr + 4); + words[2] = get_long (addr + 8); + addr += 12; + set_from_extended (fpu.registers[i], words, false); + } + if ((opcode & 070) == 030) + m68k_areg (regs, opcode & 7) = addr; + } + return true; +} + +static int +do_getexp (mpfr_t value, mpfr_rnd_t rnd) +{ + int t = 0; + + if (mpfr_inf_p (value)) + { + mpfr_set_nan (value); + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (!mpfr_nan_p (value) && !mpfr_zero_p (value)) + t = mpfr_set_si (value, mpfr_get_exp (value) - 1, rnd); + return t; +} + +static int +do_getman (mpfr_t value) +{ + if (mpfr_inf_p (value)) + { + mpfr_set_nan (value); + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (!mpfr_nan_p (value) && !mpfr_zero_p (value)) + mpfr_set_exp (value, 1); + return 0; +} + +static int +do_scale (mpfr_t value, mpfr_t reg, mpfr_rnd_t rnd) +{ + long scale; + int t = 0; + + if (mpfr_nan_p (value)) + ; + else if (mpfr_inf_p (value)) + { + mpfr_set_nan (value); + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (mpfr_fits_slong_p (value, rnd)) + { + scale = mpfr_get_si (value, MPFR_RNDZ); + mpfr_clear_inexflag (); + t = mpfr_mul_2si (value, reg, scale, rnd); + } + else + mpfr_set_inf (value, -mpfr_signbit (value)); + return t; +} + +static int +do_remainder (mpfr_t value, mpfr_t reg, mpfr_rnd_t rnd) +{ + long quo; + int t = 0; + + if (mpfr_nan_p (value) || mpfr_nan_p (reg)) + ; + else if (mpfr_zero_p (value) || mpfr_inf_p (reg)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_remquo (value, &quo, reg, value, rnd); + if (quo < 0) + quo = (-quo & 0x7f) | 0x80; + else + quo &= 0x7f; + fpu.fpsr.quotient = quo << 16; + return t; +} + +// Unfortunately, mpfr_fmod does not return the quotient bits, so we +// have to reimplement it here +static int +mpfr_rem1 (mpfr_t rem, int *quo, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd) +{ + mpfr_exp_t ex, ey; + int inex, sign, signx = mpfr_signbit (x); + mpz_t mx, my, r; + + mpz_init (mx); + mpz_init (my); + mpz_init (r); + + ex = mpfr_get_z_2exp (mx, x); /* x = mx*2^ex */ + ey = mpfr_get_z_2exp (my, y); /* y = my*2^ey */ + + /* to get rid of sign problems, we compute it separately: + quo(-x,-y) = quo(x,y), rem(-x,-y) = -rem(x,y) + quo(-x,y) = -quo(x,y), rem(-x,y) = -rem(x,y) + thus quo = sign(x/y)*quo(|x|,|y|), rem = sign(x)*rem(|x|,|y|) */ + sign = (signx != mpfr_signbit (y)); + mpz_abs (mx, mx); + mpz_abs (my, my); + + /* divide my by 2^k if possible to make operations mod my easier */ + { + unsigned long k = mpz_scan1 (my, 0); + ey += k; + mpz_fdiv_q_2exp (my, my, k); + } + + if (ex <= ey) + { + /* q = x/y = mx/(my*2^(ey-ex)) */ + mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ + /* 0 <= |r| <= |my|, r has the same sign as mx */ + mpz_tdiv_qr (mx, r, mx, my); + /* mx is the quotient */ + mpz_tdiv_r_2exp (mx, mx, 7); + *quo = mpz_get_si (mx); + } + else /* ex > ey */ + { + /* to get the low 7 more bits of the quotient, we first compute + R = X mod Y*2^7, where X and Y are defined below. Then the + low 7 of the quotient are floor(R/Y). */ + mpz_mul_2exp (my, my, 7); /* 2^7*Y */ + + mpz_set_ui (r, 2); + mpz_powm_ui (r, r, ex - ey, my); /* 2^(ex-ey) mod my */ + mpz_mul (r, r, mx); + mpz_mod (r, r, my); + + /* now 0 <= r < 2^7*Y */ + mpz_fdiv_q_2exp (my, my, 7); /* back to Y */ + mpz_tdiv_qr (mx, r, r, my); + /* oldr = mx*my + newr */ + *quo = mpz_get_si (mx); + + /* now 0 <= |r| < |my| */ + } + + if (mpz_cmp_ui (r, 0) == 0) + { + inex = mpfr_set_ui (rem, 0, MPFR_RNDN); + /* take into account sign of x */ + if (signx) + mpfr_neg (rem, rem, MPFR_RNDN); + } + else + { + /* take into account sign of x */ + if (signx) + mpz_neg (r, r); + inex = mpfr_set_z_2exp (rem, r, ex > ey ? ey : ex, rnd); + } + + if (sign) + *quo |= 0x80; + + mpz_clear (mx); + mpz_clear (my); + mpz_clear (r); + + return inex; +} + +static int +do_fmod (mpfr_t value, mpfr_t reg, mpfr_rnd_t rnd) +{ + int t = 0; + + if (mpfr_nan_p (value) || mpfr_nan_p (reg)) + mpfr_set_nan (value); + else if (mpfr_zero_p (value) || mpfr_inf_p (reg)) + { + mpfr_set_nan (value); + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (mpfr_zero_p (reg) || mpfr_inf_p (value)) + { + fpu.fpsr.quotient = 0; + t = mpfr_set (value, reg, rnd); + } + else + { + int quo; + + t = mpfr_rem1 (value, &quo, reg, value, rnd); + fpu.fpsr.quotient = quo << 16; + } + return t; +} + +static void +do_fcmp (mpfr_t source, mpfr_t dest) +{ + uae_u32 flags = 0; + + if (mpfr_nan_p (source) || mpfr_nan_p (dest)) + flags |= FPSR_CCB_NAN; + else + { + int cmp = mpfr_cmp (dest, source); + if (cmp < 0) + flags |= FPSR_CCB_NEGATIVE; + else if (cmp == 0) + { + flags |= FPSR_CCB_ZERO; + if ((mpfr_zero_p (dest) || mpfr_inf_p (dest)) && mpfr_signbit (dest)) + flags |= FPSR_CCB_NEGATIVE; + } + } + set_fpccr (flags); +} + +static void +do_ftst (mpfr_t value) +{ + uae_u32 flags = 0; + + if (mpfr_signbit (value)) + flags |= FPSR_CCB_NEGATIVE; + if (mpfr_nan_p (value)) + flags |= FPSR_CCB_NAN; + else if (mpfr_zero_p (value)) + flags |= FPSR_CCB_ZERO; + else if (mpfr_inf_p (value)) + flags |= FPSR_CCB_INFINITY; + set_fpccr (flags); +} + +static bool +fpuop_general (uae_u32 opcode, uae_u32 extra) +{ + mpfr_prec_t prec = get_cur_prec (); + mpfr_rnd_t rnd = get_cur_rnd (); + int reg = (extra >> 7) & 7; + int t = 0; + fpu_register value; + bool ret; + + mpfr_init2 (value.f, prec); + value.nan_bits = DEFAULT_NAN_BITS; + value.nan_sign = 0; + + mpfr_clear_flags (); + set_format (prec); + cur_exceptions = 0; + cur_instruction_address = m68k_getpc () - 4; + if ((extra & 0xfc00) == 0x5c00) + { + // FMOVECR + int rom_index = extra & 0x7f; + if (rom_index == 0 || (rom_index >= 11 && rom_index <= 15)) + t = mpfr_set (value.f, fpu_constant_rom[rom_index], rnd); + else if (rom_index >= 48 && rom_index <= 63) + t = mpfr_set (value.f, fpu_constant_rom[rom_index - 32], rnd); + else + mpfr_set_zero (value.f, 0); + set_fp_register (reg, value, t, rnd, true); + } + else if (extra & 0x40) + { + static const char valid[64] = + { + 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 0, 0 + }; + + if (extra & 4) + // FD... + prec = DOUBLE_PREC; + else + // FS... + prec = SINGLE_PREC; + set_format (prec); + MPFR_DECL_INIT (value2, prec); + + if (!fpu.is_integral) + { + ret = false; + goto out; + } + if (!valid[extra & 0x3b]) + { + ret = false; + goto out; + } + if (!get_fp_value (opcode, extra, value)) + { + ret = false; + goto out; + } + + switch (extra & 0x3f) + { + case 0: // FSMOVE + case 4: // FDMOVE + mpfr_set (value2, value.f, rnd); + break; + case 1: // FSSQRT + case 5: // FDSQRT + if (mpfr_sgn (value.f) < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sqrt (value2, value.f, rnd); + break; + case 24: // FSABS + case 28: // FDABS + t = mpfr_abs (value2, value.f, rnd); + break; + case 26: // FSNEG + case 30: // FDNEG + t = mpfr_neg (value2, value.f, rnd); + break; + case 32: // FSDIV + case 36: // FDDIV + if (mpfr_zero_p (value.f)) + { + if (mpfr_regular_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_zero_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (mpfr_inf_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_div (value2, fpu.registers[reg].f, value.f, rnd); + break; + case 34: // FSADD + case 38: // FDADD + if (mpfr_inf_p (fpu.registers[reg].f) && mpfr_inf_p (value.f) + && mpfr_signbit (fpu.registers[reg].f) != mpfr_signbit (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_add (value2, fpu.registers[reg].f, value.f, rnd); + break; + case 35: // FSMUL + case 39: // FDMUL + if ((mpfr_zero_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + || (mpfr_inf_p (value.f) && mpfr_zero_p (fpu.registers[reg].f))) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_mul (value2, fpu.registers[reg].f, value.f, rnd); + break; + case 40: // FSSUB + case 44: // FDSUB + if (mpfr_inf_p (fpu.registers[reg].f) && mpfr_inf_p (value.f) + && mpfr_signbit (fpu.registers[reg].f) == mpfr_signbit (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sub (value2, fpu.registers[reg].f, value.f, rnd); + break; + } + set_fp_register (reg, value2, t, rnd, true); + } + else if ((extra & 0x30) == 0x30) + { + if ((extra & 15) > 10 || (extra & 15) == 9) + { + ret = false; + goto out; + } + if (!get_fp_value (opcode, extra, value)) + { + ret = false; + goto out; + } + + if ((extra & 15) < 8) + { + // FSINCOS + int reg2 = extra & 7; + MPFR_DECL_INIT (value2, prec); + + if (mpfr_inf_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sin_cos (value.f, value2, value.f, rnd); + if (reg2 != reg) + set_fp_register (reg2, value2, t >> 2, rnd, false); + set_fp_register (reg, value, t & 3, rnd, true); + } + else if ((extra & 15) == 8) + // FCMP + do_fcmp (value.f, fpu.registers[reg].f); + else + // FTST + do_ftst (value.f); + } + else + { + static const char valid[64] = + { + 1, 1, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1 + }; + if (!valid[extra & 0x3f]) + { + ret = false; + goto out; + } + if (!get_fp_value (opcode, extra, value)) + { + ret = false; + goto out; + } + + switch (extra & 0x3f) + { + case 0: // FMOVE + break; + case 1: // FINT + t = mpfr_rint (value.f, value.f, rnd); + break; + case 2: // FSINH + t = mpfr_sinh (value.f, value.f, rnd); + break; + case 3: // FINTRZ + t = mpfr_rint (value.f, value.f, MPFR_RNDZ); + break; + case 4: // FSQRT + if (mpfr_sgn (value.f) < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sqrt (value.f, value.f, rnd); + break; + case 6: // FLOGNP1 + if (!mpfr_nan_p (value.f)) + { + int cmp = mpfr_cmp_si (value.f, -1); + if (cmp == 0) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (cmp < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + t = mpfr_log1p (value.f, value.f, rnd); + break; + case 8: // FETOXM1 + t = mpfr_expm1 (value.f, value.f, rnd); + break; + case 9: // FTANH + t = mpfr_tanh (value.f, value.f, rnd); + break; + case 10: // FATAN + t = mpfr_atan (value.f, value.f, rnd); + break; + case 12: // FASIN + if (mpfr_cmpabs (value.f, FPU_CONSTANT_ONE) > 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_asin (value.f, value.f, rnd); + break; + case 13: // FATANH + if (mpfr_cmpabs (value.f, FPU_CONSTANT_ONE) > 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_atanh (value.f, value.f, rnd); + break; + case 14: // FSIN + if (mpfr_inf_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sin (value.f, value.f, rnd); + break; + case 15: // FTAN + if (mpfr_inf_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_tan (value.f, value.f, rnd); + break; + case 16: // FETOX + t = mpfr_exp (value.f, value.f, rnd); + break; + case 17: // FTWOTOX + t = mpfr_ui_pow (value.f, 2, value.f, rnd); + break; + case 18: // FTENTOX + t = mpfr_ui_pow (value.f, 10, value.f, rnd); + break; + case 20: // FLOGN + if (mpfr_zero_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_sgn (value.f) < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_log (value.f, value.f, rnd); + break; + case 21: // FLOG10 + if (mpfr_zero_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_sgn (value.f) < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_log10 (value.f, value.f, rnd); + break; + case 22: // FLOG2 + if (mpfr_zero_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_sgn (value.f) < 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_log2 (value.f, value.f, rnd); + break; + case 24: // FABS + t = mpfr_abs (value.f, value.f, rnd); + value.nan_sign = 0; + break; + case 25: // FCOSH + t = mpfr_cosh (value.f, value.f, rnd); + break; + case 26: // FNEG + t = mpfr_neg (value.f, value.f, rnd); + value.nan_sign = !value.nan_sign; + break; + case 28: // FACOS + if (mpfr_cmpabs (value.f, FPU_CONSTANT_ONE) > 0) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_acos (value.f, value.f, rnd); + break; + case 29: // FCOS + if (mpfr_inf_p (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_cos (value.f, value.f, rnd); + break; + case 30: // FGETEXP + t = do_getexp (value.f, rnd); + break; + case 31: // FGETMAN + t = do_getman (value.f); + break; + case 32: // FDIV + if (mpfr_zero_p (value.f)) + { + if (mpfr_regular_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_zero_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (mpfr_inf_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_div (value.f, fpu.registers[reg].f, value.f, rnd); + break; + case 33: // FMOD + t = do_fmod (value.f, fpu.registers[reg].f, rnd); + break; + case 34: // FADD + if (mpfr_inf_p (fpu.registers[reg].f) && mpfr_inf_p (value.f) + && mpfr_signbit (fpu.registers[reg].f) != mpfr_signbit (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_add (value.f, fpu.registers[reg].f, value.f, rnd); + break; + case 35: // FMUL + if ((mpfr_zero_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + || (mpfr_inf_p (value.f) && mpfr_zero_p (fpu.registers[reg].f))) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_mul (value.f, fpu.registers[reg].f, value.f, rnd); + break; + case 36: // FSGLDIV + { + MPFR_DECL_INIT (value2, SINGLE_PREC); + + set_format (SINGLE_PREC); + if (mpfr_zero_p (value.f)) + { + if (mpfr_regular_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_DZ; + else if (mpfr_zero_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + } + else if (mpfr_inf_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_div (value2, fpu.registers[reg].f, value.f, rnd); + mpfr_set (value.f, value2, rnd); + } + break; + case 37: // FREM + t = do_remainder (value.f, fpu.registers[reg].f, rnd); + break; + case 38: // FSCALE + t = do_scale (value.f, fpu.registers[reg].f, rnd); + break; + case 39: // FSGLMUL + { + MPFR_DECL_INIT (value2, SINGLE_PREC); + + set_format (SINGLE_PREC); + if ((mpfr_zero_p (value.f) && mpfr_inf_p (fpu.registers[reg].f)) + || (mpfr_inf_p (value.f) && mpfr_zero_p (fpu.registers[reg].f))) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_mul (value2, fpu.registers[reg].f, value.f, rnd); + mpfr_set (value.f, value2, rnd); + } + break; + case 40: // FSUB + if (mpfr_inf_p (fpu.registers[reg].f) && mpfr_inf_p (value.f) + && mpfr_signbit (fpu.registers[reg].f) == mpfr_signbit (value.f)) + cur_exceptions |= FPSR_EXCEPTION_OPERR; + t = mpfr_sub (value.f, fpu.registers[reg].f, value.f, rnd); + break; + } + set_fp_register (reg, value, t, rnd, true); + } + update_exceptions (); + ret = true; + out: + mpfr_clear (value.f); + return ret; +} + +void +fpuop_arithmetic (uae_u32 opcode, uae_u32 extra) +{ + bool valid; + + switch ((extra >> 13) & 7) + { + case 3: + valid = fpuop_fmove_memory (opcode, extra); + break; + case 4: + case 5: + valid = fpuop_fmovem_control (opcode, extra); + break; + case 6: + case 7: + valid = fpuop_fmovem_register (opcode, extra); + break; + case 0: + case 2: + valid = fpuop_general (opcode, extra); + break; + default: + valid = false; + break; + } + + if (!valid) + { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } +} + +static bool +check_fp_cond (uae_u32 pred) +{ + uae_u32 fpcc = get_fpccr (); + + if ((pred & 16) != 0 && (fpcc & FPSR_CCB_NAN) != 0) + { + // IEEE non-aware test + set_exception_status (get_exception_status () | FPSR_EXCEPTION_BSUN); + set_accrued_exception (get_accrued_exception () | FPSR_ACCR_IOP); + } + + switch (pred & 15) + { + case 0: // F / SF + return false; + case 1: // EQ /SEQ + return (fpcc & FPSR_CCB_ZERO) != 0; + case 2: // OGT / GT + return (fpcc & (FPSR_CCB_NAN | FPSR_CCB_ZERO | FPSR_CCB_NEGATIVE)) == 0; + case 3: // OGE / GE + return (fpcc & FPSR_CCB_ZERO) != 0 || (fpcc & (FPSR_CCB_NAN | FPSR_CCB_NEGATIVE)) == 0; + case 4: // OLT / LT + return (fpcc & (FPSR_CCB_NEGATIVE | FPSR_CCB_NAN | FPSR_CCB_ZERO)) == FPSR_CCB_NEGATIVE; + case 5: // OLE / LE + return (fpcc & FPSR_CCB_ZERO) != 0 || (fpcc & (FPSR_CCB_NEGATIVE | FPSR_CCB_NAN)) == FPSR_CCB_NEGATIVE; + case 6: // OGL / GL + return (fpcc & (FPSR_CCB_NAN | FPSR_CCB_ZERO)) == 0; + case 7: // OR / GLE + return (fpcc & FPSR_CCB_NAN) == 0; + case 8: // UN / NGLE + return (fpcc & FPSR_CCB_NAN) != 0; + case 9: // UEQ / NGL + return (fpcc & (FPSR_CCB_NAN | FPSR_CCB_ZERO)) != 0; + case 10: // UGT / NLE + return (fpcc & FPSR_CCB_NAN) != 0 || (fpcc & (FPSR_CCB_NEGATIVE | FPSR_CCB_ZERO)) == 0; + case 11: // UGE / NLT + return (fpcc & (FPSR_CCB_NEGATIVE | FPSR_CCB_NAN | FPSR_CCB_ZERO)) != FPSR_CCB_NEGATIVE; + case 12: // ULT / NGE + return (fpcc & FPSR_CCB_NAN) != 0 || (fpcc & (FPSR_CCB_NEGATIVE | FPSR_CCB_ZERO)) == FPSR_CCB_NEGATIVE; + case 13: // ULE / NGT + return (fpcc & (FPSR_CCB_NAN | FPSR_CCB_ZERO | FPSR_CCB_NEGATIVE)) != 0; + case 14: // NE / SNE + return (fpcc & FPSR_CCB_ZERO) == 0; + case 15: // T / ST + return true; + default: + return false; + } +} + +void +fpuop_bcc (uae_u32 opcode, uaecptr pc, uae_u32 disp) +{ + if (check_fp_cond (opcode)) + { + if (!(opcode & (1 << 6))) + disp = (uae_s16) disp; + m68k_setpc (pc + disp); + } +} + +void +fpuop_scc (uae_u32 opcode, uae_u32 extra) +{ + uae_u32 addr; + int value = check_fp_cond (extra) ? 0xff : 0; + if ((opcode & 070) == 0) + { + int reg = opcode & 7; + m68k_dreg (regs, reg) = (m68k_dreg (regs, reg) & ~0xff) | value; + } + else if (!get_fp_addr (opcode, &addr, true)) + { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } + else + { + switch (opcode & 070) + { + case 030: + m68k_areg (regs, opcode & 7) += (opcode & 7) == 7 ? 2 : 1; + break; + case 040: + addr -= (opcode & 7) == 7 ? 2 : 1; + m68k_areg (regs, opcode & 7) = addr; + } + put_byte (addr, value); + } +} + +void +fpuop_dbcc (uae_u32 opcode, uae_u32 extra) +{ + uaecptr pc = m68k_getpc (); + uae_s16 disp = next_iword (); + + if (!check_fp_cond (extra)) + { + int reg = opcode & 7; + uae_u16 cnt = (m68k_dreg (regs, reg) & 0xffff) - 1; + m68k_dreg (regs, reg) = (m68k_dreg (regs, reg) & ~0xffff) | cnt; + if (cnt != 0xffff) + m68k_setpc (pc + disp); + } +} + +void +fpuop_trapcc (uae_u32, uaecptr oldpc, uae_u32 extra) +{ + if (check_fp_cond (extra)) + Exception (7, oldpc - 2); +} + +void +fpuop_save (uae_u32 opcode) +{ + uae_u32 addr; + + if ((opcode & 070) == 030 + || !get_fp_addr (opcode, &addr, true)) + { + m68k_setpc (m68k_getpc () - 2); + op_illg (opcode); + return; + } + + if (fpu.is_integral) + { + // 4 byte 68040 IDLE frame + // FIXME: generate proper FPU stack frames that does not result + // in undefined behaviour from FPSP040 + if ((opcode & 070) == 040) + { + addr -= 4; + m68k_areg (regs, opcode & 7) = addr; + } + put_long (addr, 0x41000000); + } + else + { + // 28 byte 68881 IDLE frame + if ((opcode & 070) == 040) + { + addr -= 28; + m68k_areg (regs, opcode & 7) = addr; + } + put_long (addr, 0x1f180000); + for (int i = 0; i < 6; i++) + { + addr += 4; + put_long (addr, 0); + } + } +} + +void +fpuop_restore (uae_u32 opcode) +{ + uae_u32 addr; + uae_u32 format; + + if ((opcode & 070) == 040 + || !get_fp_addr (opcode, &addr, false)) + { + m68k_setpc (m68k_getpc () - 2); + op_illg (opcode); + return; + } + + format = get_long (addr); + addr += 4; + if ((format & 0xff000000) == 0) + // NULL frame + fpu_reset (); + else + addr += (format & 0xff0000) >> 16; + if ((opcode & 070) == 030) + m68k_areg (regs, opcode & 7) = addr; +} + +void fpu_set_fpsr(uae_u32 new_fpsr) +{ + set_fpsr(new_fpsr); +} + +uae_u32 fpu_get_fpsr(void) +{ + return get_fpsr(); +} + +void fpu_set_fpcr(uae_u32 new_fpcr) +{ + set_fpcr(new_fpcr); +} + +uae_u32 fpu_get_fpcr(void) +{ + return get_fpcr(); +} diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp b/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp index ffc784a5..ca4b841d 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp +++ b/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp @@ -1,31 +1,42 @@ /* - * fpu/fpu_uae.cpp + * fpu/fpu_uae.cpp - the old UAE FPU * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * MC68881/68040 fpu emulation * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Copyright 1996 Herman ten Brugge + * + * * Following fixes by Lauri Pesonen, July 1999: * * FMOVEM list handling: @@ -86,9 +97,8 @@ * - Precision rounding single/double */ + #include "sysdeps.h" -#include -#include #include "memory.h" #include "readcpu.h" #include "newcpu.h" @@ -97,6 +107,17 @@ #include "fpu/fpu.h" #include "fpu/fpu_uae.h" +#ifdef HAVE_NEW_HEADERS +#define _GLIBCPP_USE_C99 1 +# include +# include +using namespace __gnu_cxx; +#undef _GLIBCPP_USE_C99 +#else +# include +# include +#endif + /* Global FPU context */ fpu_t fpu; @@ -166,8 +187,8 @@ PUBLIC void FFPU dump_registers(const char * str) sprintf(temp_str, "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\n", str, - get_register(0), get_register(1), get_register(2), get_register(3), - get_register(4), get_register(5), get_register(6), get_register(7) ); + fpu_get_register(0), fpu_get_register(1), fpu_get_register(2), fpu_get_register(3), + fpu_get_register(4), fpu_get_register(5), fpu_get_register(6), fpu_get_register(7) ); fpu_debug((temp_str)); } @@ -195,9 +216,7 @@ PUBLIC void FFPU dump_registers(const char *) { } -PUBLIC void FFPU dump_first_bytes(uae_u8 *, uae_s32) -{ -} +#define dump_first_bytes(a,b) #endif @@ -219,10 +238,10 @@ PRIVATE inline fpu_register FFPU round_to_nearest(fpu_register const & x) PRIVATE inline bool FFPU do_isnan(fpu_register const & r) { - uae_u32 * p = (uae_u32 *)&r; - if ((p[FHI] & 0x7FF00000) == 0x7FF00000) { + fpu_register_parts const p = { r }; + if ((p.parts[FHI] & 0x7FF00000) == 0x7FF00000) { // logical or is faster here. - if ((p[FHI] & 0x000FFFFF) || p[FLO]) { + if ((p.parts[FHI] & 0x000FFFFF) || p.parts[FLO]) { return true; } } @@ -235,8 +254,8 @@ PRIVATE inline bool FFPU do_isnan(fpu_register const & r) PRIVATE inline bool FFPU do_isinf(fpu_register const & r) { - uae_u32 * p = (uae_u32 *)&r; - if (((p[FHI] & 0x7FF00000) == 0x7FF00000) && p[FLO] == 0) { + fpu_register_parts const p = { r }; + if ((p.parts[FHI] & 0x7FF00000) == 0x7FF00000 && p.parts[FLO] == 0) { return true; } return false; @@ -248,8 +267,8 @@ PRIVATE inline bool FFPU do_isinf(fpu_register const & r) PRIVATE inline bool FFPU do_isneg(fpu_register const & r) { - uae_u32 * p = (uae_u32 *)&r; - return ((p[FHI] & 0x80000000) != 0); + fpu_register_parts const p = { r }; + return ((p.parts[FHI] & 0x80000000) != 0); } #ifndef HAVE_ISZERO @@ -258,8 +277,8 @@ PRIVATE inline bool FFPU do_isneg(fpu_register const & r) PRIVATE inline bool FFPU do_iszero(fpu_register const & r) { - uae_u32 * p = (uae_u32 *)&r; - return (((p[FHI] & 0x7FF00000) == 0) && p[FLO] == 0); + fpu_register_parts const p = { r }; + return (((p.parts[FHI] & 0x7FF00000) == 0) && p.parts[FLO] == 0); } // May be optimized for particular processors @@ -293,77 +312,70 @@ PRIVATE inline void FFPU get_source_flags(fpu_register const & r) fl_source.in_range = !fl_source.zero && !fl_source.infinity && !fl_source.nan; } -PRIVATE inline void FFPU make_nan(fpu_register & r) +PRIVATE inline void FFPU make_nan(fpu_register & r, bool negative) { - uae_u32 * const p = (uae_u32 *)&r; - p[FLO] = 0xffffffff; - p[FHI] = 0x7fffffff; + fpu_register_parts p; + p.parts[FLO] = 0xffffffff; + p.parts[FHI] = negative ? 0xffffffff : 0x7fffffff; + r = p.val; } -PRIVATE inline void FFPU make_zero_positive(fpu_register & r) +PRIVATE inline void FFPU make_zero(fpu_register & r, bool negative) { - uae_u32 * const p = (uae_u32 *)&r; - p[FLO] = p[FHI] = 0; + fpu_register_parts p; + p.parts[FLO] = 0; + p.parts[FHI] = negative ? 0x80000000 : 0; + r = p.val; } -PRIVATE inline void FFPU make_zero_negative(fpu_register & r) +PRIVATE inline void FFPU make_inf(fpu_register & r, bool negative) { - uae_u32 * const p = (uae_u32 *)&r; - p[FLO] = 0; - p[FHI] = 0x80000000; -} - -PRIVATE inline void FFPU make_inf_positive(fpu_register & r) -{ - uae_u32 * const p = (uae_u32 *)&r; - p[FLO] = 0; - p[FHI] = 0x7FF00000; -} - -PRIVATE inline void FFPU make_inf_negative(fpu_register & r) -{ - uae_u32 * const p = (uae_u32 *)&r; - p[FLO] = 0; - p[FHI] = 0xFFF00000; + fpu_register_parts p; + p.parts[FLO] = 0; + p.parts[FHI] = negative ? 0xFFF00000 : 0x7FF00000; + r = p.val; } PRIVATE inline void FFPU fast_scale(fpu_register & r, int add) { - uae_u32 * const p = (uae_u32 *)&r; - int exp = (p[FHI] & 0x7FF00000) >> 20; + fpu_register_parts p = { r }; + int exp = (p.parts[FHI] & 0x7FF00000) >> 20; // TODO: overflow flags exp += add; if(exp >= 2047) { - make_inf_positive(r); + make_inf(r, false); + return; } else if(exp < 0) { // keep sign (+/- 0) - p[FHI] &= 0x80000000; + p.parts[FHI] &= 0x80000000; } else { - p[FHI] = (p[FHI] & 0x800FFFFF) | ((uae_u32)exp << 20); + p.parts[FHI] = (p.parts[FHI] & 0x800FFFFF) | ((uae_u32)exp << 20); } + r = p.val; } PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r) { - uae_u32 * const p = (uae_u32 *)&r; - int exp = (p[FHI] & 0x7FF00000) >> 20; + fpu_register_parts const p = { r }; + int exp = (p.parts[FHI] & 0x7FF00000) >> 20; return( exp - 1023 ); } // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r) { - uae_u32 * const p = (uae_u32 *)&r; - p[FHI] = (p[FHI] & 0x800FFFFF) | 0x3FF00000; + fpu_register_parts p = { r }; + p.parts[FHI] = (p.parts[FHI] & 0x800FFFFF) | 0x3FF00000; + r = p.val; } // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_register const & rb) { - uae_u32 * const a = (uae_u32 *)&ra; - uae_u32 * const b = (uae_u32 *)&rb; - return (((a[FHI] ^ b[FHI]) & 0x80000000) ? FPSR_QUOTIENT_SIGN : 0); + fpu_register_parts const a = { ra }; + fpu_register_parts const b = { rb }; + return (((a.parts[FHI] ^ b.parts[FHI]) & 0x80000000) ? FPSR_QUOTIENT_SIGN : 0); } // Quotient Byte is loaded with the sign and least significant @@ -381,13 +393,15 @@ PRIVATE inline fpu_register FFPU make_single(uae_u32 value) return (0.0); fpu_register result; - uae_u32 * p = (uae_u32 *)&result; + fpu_register_parts p; uae_u32 sign = (value & 0x80000000); uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127; - p[FLO] = value << 29; - p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); + p.parts[FLO] = value << 29; + p.parts[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); + + result = p.val; fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); @@ -401,10 +415,10 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) return 0; uae_u32 result; - uae_u32 *p = (uae_u32 *)&src; + fpu_register_parts const p = { src }; - uae_u32 sign = (p[FHI] & 0x80000000); - uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20; + uae_u32 sign = (p.parts[FHI] & 0x80000000); + uae_u32 exp = (p.parts[FHI] & 0x7FF00000) >> 20; if(exp + 127 < 1023) { exp = 0; @@ -414,7 +428,7 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) exp = exp + 127 - 1023; } - result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29); + result = sign | (exp << 23) | ((p.parts[FHI] & 0x000FFFFF) << 3) | (p.parts[FLO] >> 29); fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); @@ -428,8 +442,8 @@ PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u return 0.0; fpu_register result; - uae_u32 *p = (uae_u32 *)&result; - + fpu_register_parts p; + uae_u32 sign = wrd1 & 0x80000000; uae_u32 exp = (wrd1 >> 16) & 0x7fff; @@ -466,8 +480,10 @@ PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u } // drop the explicit integer bit. - p[FLO] = (wrd2 << 21) | (wrd3 >> 11); - p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); + p.parts[FLO] = (wrd2 << 21) | (wrd3 >> 11); + p.parts[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); + + result = p.val; fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); @@ -485,14 +501,14 @@ PRIVATE inline void FFPU make_extended_no_normalize( { // Is it zero? if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { - make_zero_positive(result); + make_zero(result, false); return; } // Is it NaN? if( (wrd1 & 0x7FFF0000) == 0x7FFF0000 ) { if( (wrd1 & 0x0000FFFF) || wrd2 || wrd3 ) { - make_nan(result); + make_nan(result, (wrd1 & 0x80000000) != 0); return; } } @@ -511,11 +527,13 @@ PRIVATE inline void FFPU make_extended_no_normalize( } // drop the explicit integer bit. - uae_u32 *p = (uae_u32 *)&result; - p[FLO] = (wrd2 << 21) | (wrd3 >> 11); - p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); + fpu_register_parts p; + p.parts[FLO] = (wrd2 << 21) | (wrd3 >> 11); + p.parts[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); - fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(float)(*(double *)p))); + result = p.val; + + fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); } // from_exten @@ -527,14 +545,14 @@ PRIVATE inline void FFPU extract_extended(fpu_register const & src, *wrd1 = *wrd2 = *wrd3 = 0; return; } - - uae_u32 *p = (uae_u32 *)&src; - - fpu_debug(("extract_extended (%X,%X)\n",p[FLO],p[FHI])); - uae_u32 sign = p[FHI] & 0x80000000; + fpu_register_parts const p = { src }; + + fpu_debug(("extract_extended (%X,%X)\n",p.parts[FLO],p.parts[FHI])); - uae_u32 exp = ((p[FHI] >> 20) & 0x7ff); + uae_u32 sign = p.parts[FHI] & 0x80000000; + + uae_u32 exp = ((p.parts[FHI] >> 20) & 0x7ff); // Check for maximum if(exp == 0x7FF) { exp = 0x7FFF; @@ -544,8 +562,8 @@ PRIVATE inline void FFPU extract_extended(fpu_register const & src, *wrd1 = sign | (exp << 16); // always set the explicit integer bit. - *wrd2 = 0x80000000 | ((p[FHI] & 0x000FFFFF) << 11) | ((p[FLO] & 0xFFE00000) >> 21); - *wrd3 = p[FLO] << 11; + *wrd2 = 0x80000000 | ((p.parts[FHI] & 0x000FFFFF) << 11) | ((p.parts[FLO] & 0xFFE00000) >> 21); + *wrd3 = p.parts[FLO] << 11; fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } @@ -557,9 +575,11 @@ PRIVATE inline fpu_register FFPU make_double(uae_u32 wrd1, uae_u32 wrd2) return 0.0; fpu_register result; - uae_u32 *p = (uae_u32 *)&result; - p[FLO] = wrd2; - p[FHI] = wrd1; + fpu_register_parts p; + p.parts[FLO] = wrd2; + p.parts[FHI] = wrd1; + + result = p.val; fpu_debug(("make_double (%X,%X) = %.04f\n",wrd1,wrd2,(double)result)); @@ -577,9 +597,9 @@ PRIVATE inline void FFPU extract_double(fpu_register const & src, return; } */ - uae_u32 *p = (uae_u32 *)&src; - *wrd2 = p[FLO]; - *wrd1 = p[FHI]; + fpu_register_parts const p = { src }; + *wrd2 = p.parts[FLO]; + *wrd1 = p.parts[FHI]; fpu_debug(("extract_double (%.04f) = %X,%X\n",(double)src,*wrd1,*wrd2)); } @@ -590,8 +610,8 @@ PRIVATE inline void FFPU extract_double(fpu_register const & src, PRIVATE inline void FFPU make_fpsr(fpu_register const & r) { FPU fpsr.condition_codes - = ((r == 0.0) ? NATIVE_FFLAG_ZERO : 0) - | ((r < 0.0) ? NATIVE_FFLAG_NEGATIVE : 0) + = (iszero(r) ? NATIVE_FFLAG_ZERO : 0) + | (isneg(r) ? NATIVE_FFLAG_NEGATIVE : 0) ; } #endif @@ -622,25 +642,25 @@ PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) fpu_register src0 = src; #endif - if (src == 0.0) + if (src == 0.0) return 0; - if (src < 0) { + if (src < 0) { tmp = 0x80000000; src = -src; - } else { + } else { tmp = 0; - } - frac = frexp (src, &expon); - frac += 0.5 / 16777216.0; - if (frac >= 1.0) { + } + frac = frexp (src, &expon); + frac += 0.5 / 16777216.0; + if (frac >= 1.0) { frac /= 2.0; expon++; - } + } result = tmp | (((expon + 127 - 1) & 0xff) << 23) | (((int) (frac * 16777216.0)) & 0x7fffff); // fpu_debug(("extract_single (%.04f) = %X\n",(float)src0,result)); - return (result); + return (result); } // to exten @@ -895,11 +915,9 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe break; case 3: ad = m68k_areg (regs, reg); - m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: - m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; - ad = m68k_areg (regs, reg); + ad = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); @@ -940,8 +958,8 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe fpu_debug(("get_fp_value m68k_getpc()=%X\n",m68k_getpc())); fpu_debug(("get_fp_value ad=%X\n",ad)); fpu_debug(("get_fp_value get_long (ad)=%X\n",get_long (ad))); - dump_first_bytes( get_real_address(ad)-64, 64 ); - dump_first_bytes( get_real_address(ad), 64 ); + dump_first_bytes( get_real_address(ad, 0, 0)-64, 64 ); + dump_first_bytes( get_real_address(ad, 0, 0), 64 ); switch (size) { case 0: @@ -988,6 +1006,15 @@ PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_registe return 0; } + switch (mode) { + case 3: + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; + case 4: + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + break; + } + // fpu_debug(("get_fp_value result = %.04f\n",(float)src)); return 1; } @@ -1204,7 +1231,7 @@ PRIVATE inline int FFPU fpp_cond(int condition) #if 0 return fpcctrue(condition); #else - switch (condition) { + switch (condition & 0x1f) { case 0x00: CONDRET("False",0); case 0x01: CONDRET("Equal",Z); case 0x02: CONDRET("Ordered Greater Than",!(NaN || Z || N)); @@ -1299,11 +1326,11 @@ void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) put_byte(ad, cc ? 0xff : 0x00); } -void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) +void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc, uae_u32 extra) { - fpu_debug(("ftrapcc_opp %X at %08lx\n", (uae_u32)opcode, m68k_getpc ())); + fpu_debug(("ftrapcc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); - int cc = fpp_cond(opcode & 0x3f); + int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (oldpc); op_illg (opcode); @@ -1516,8 +1543,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) if ((opcode & 0x38) == 0) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - m68k_dreg (regs, opcode & 7) = get_fpcr() & 0xFFFF; + m68k_dreg (regs, opcode & 7) = get_fpcr(); fpu_debug(("FMOVEM FPU fpcr (%X) -> D%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { @@ -1548,8 +1574,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) else if ((opcode & 0x38) == 8) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - m68k_areg (regs, opcode & 7) = get_fpcr() & 0xFFFF; + m68k_areg (regs, opcode & 7) = get_fpcr(); fpu_debug(("FMOVEM FPU fpcr (%X) -> A%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { @@ -1612,8 +1637,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) } ad -= incr; if (extra & 0x1000) { - // according to the manual, the msb bits are always zero. - put_long (ad, get_fpcr() & 0xFFFF); + put_long (ad, get_fpcr()); fpu_debug(("FMOVEM FPU fpcr (%X) -> mem %X\n", get_fpcr(), ad )); ad += 4; } @@ -1906,6 +1930,8 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) FPU registers[reg] = 1.0e256; fpu_debug(("FP const: 1.0e256\n")); break; + + // Valid for 64 bits only (see fpu.cpp) #if 0 case 0x3c: FPU registers[reg] = 1.0e512; @@ -1942,7 +1968,114 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) return; } fpu_debug(("returned from get_fp_value m68k_getpc()=%X\n",m68k_getpc())); +#if 0 // MJ added, not tested now + if (FPU is_integral) { + // 68040-specific operations + switch (extra & 0x7f) { + case 0x40: /* FSMOVE */ + fpu_debug(("FSMOVE %.04f\n",(double)src)); + FPU registers[reg] = (float)src; + make_fpsr(FPU registers[reg]); + break; + case 0x44: /* FDMOVE */ + fpu_debug(("FDMOVE %.04f\n",(double)src)); + FPU registers[reg] = (double)src; + make_fpsr(FPU registers[reg]); + break; + case 0x41: /* FSSQRT */ + fpu_debug(("FSQRT %.04f\n",(double)src)); + FPU registers[reg] = (float)sqrt (src); + make_fpsr(FPU registers[reg]); + break; + case 0x45: /* FDSQRT */ + fpu_debug(("FSQRT %.04f\n",(double)src)); + FPU registers[reg] = (double)sqrt (src); + make_fpsr(FPU registers[reg]); + break; + case 0x58: /* FSABS */ + fpu_debug(("FSABS %.04f\n",(double)src)); + FPU registers[reg] = (float)fabs(src); + make_fpsr(FPU registers[reg]); + break; + case 0x5c: /* FDABS */ + fpu_debug(("FDABS %.04f\n",(double)src)); + FPU registers[reg] = (double)fabs(src); + make_fpsr(FPU registers[reg]); + break; + case 0x5a: /* FSNEG */ + fpu_debug(("FSNEG %.04f\n",(double)src)); + FPU registers[reg] = (float)-src; + make_fpsr(FPU registers[reg]); + break; + case 0x5e: /* FDNEG */ + fpu_debug(("FDNEG %.04f\n",(double)src)); + FPU registers[reg] = (double)-src; + make_fpsr(FPU registers[reg]); + break; + case 0x60: /* FSDIV */ + fpu_debug(("FSDIV %.04f\n",(double)src)); + FPU registers[reg] = (float)(FPU registers[reg] / src); + make_fpsr(FPU registers[reg]); + break; + case 0x64: /* FDDIV */ + fpu_debug(("FDDIV %.04f\n",(double)src)); + FPU registers[reg] = (double)(FPU registers[reg] / src); + make_fpsr(FPU registers[reg]); + break; + case 0x62: /* FSADD */ + fpu_debug(("FSADD %.04f\n",(double)src)); + FPU registers[reg] = (float)(FPU registers[reg] + src); + make_fpsr(FPU registers[reg]); + break; + case 0x66: /* FDADD */ + fpu_debug(("FDADD %.04f\n",(double)src)); + FPU registers[reg] = (double)(FPU registers[reg] + src); + make_fpsr(FPU registers[reg]); + break; + case 0x68: /* FSSUB */ + fpu_debug(("FSSUB %.04f\n",(double)src)); + FPU registers[reg] = (float)(FPU registers[reg] - src); + make_fpsr(FPU registers[reg]); + break; + case 0x6c: /* FDSUB */ + fpu_debug(("FDSUB %.04f\n",(double)src)); + FPU registers[reg] = (double)(FPU registers[reg] - src); + make_fpsr(FPU registers[reg]); + break; + case 0x63: /* FSMUL */ + case 0x67: /* FDMUL */ + get_dest_flags(FPU registers[reg]); + get_source_flags(src); + if(fl_dest.in_range && fl_source.in_range) { + if ((extra & 0x7f) == 0x63) + FPU registers[reg] = (float)(FPU registers[reg] * src); + else + FPU registers[reg] = (double)(FPU registers[reg] * src); + } + else if (fl_dest.nan || fl_source.nan || + fl_dest.zero && fl_source.infinity || + fl_dest.infinity && fl_source.zero ) { + make_nan( FPU registers[reg], fl_dest.negative ); + } + else if (fl_dest.zero || fl_source.zero ) { + make_zero(FPU registers[reg], fl_dest.negative != fl_source.negative); + } + else { + make_inf(FPU registers[reg], fl_dest.negative != fl_source.negative); + } + make_fpsr(FPU registers[reg]); + break; + default: + // Continue decode-execute 6888x instructions below + goto process_6888x_instructions; + } + fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc())); + dump_registers( "END "); + return; + } + process_6888x_instructions: +#endif switch (extra & 0x7f) { case 0x00: /* FMOVE */ fpu_debug(("FMOVE %.04f\n",(double)src)); @@ -1954,7 +2087,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) fpu_debug(("FINT %.04f\n",(double)src)); // FPU registers[reg] = (int) (src + 0.5); // FIXME: use native rounding mode flags - switch (get_fpcr() & 0x30) { + switch (get_fpcr() & FPCR_ROUNDING_MODE) { case FPCR_ROUND_ZERO: FPU registers[reg] = round_to_zero(src); break; @@ -2075,7 +2208,10 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) break; case 0x1a: /* FNEG */ fpu_debug(("FNEG %.04f\n",(double)src)); - FPU registers[reg] = -src; + if (iszero(src)) + make_zero(FPU registers[reg], !isneg(src)); + else + FPU registers[reg] = -src; make_fpsr(FPU registers[reg]); break; case 0x1c: /* FACOS */ @@ -2092,7 +2228,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) fpu_debug(("FGETEXP %.04f\n",(double)src)); #if FPU_HAVE_IEEE_DOUBLE if( isinf(src) ) { - make_nan( FPU registers[reg] ); + make_nan( FPU registers[reg], isneg(src) ); } else { FPU registers[reg] = fast_fgetexp( src ); @@ -2116,7 +2252,7 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) FPU registers[reg] = 0; } else if( isinf(src) ) { - make_nan( FPU registers[reg] ); + make_nan( FPU registers[reg], isneg(src) ); } else { FPU registers[reg] = src; @@ -2166,27 +2302,15 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) FPU registers[reg] *= src; } else if (fl_dest.nan || fl_source.nan || - fl_dest.zero && fl_source.infinity || - fl_dest.infinity && fl_source.zero ) { - make_nan( FPU registers[reg] ); + (fl_dest.zero && fl_source.infinity) || + (fl_dest.infinity && fl_source.zero) ) { + make_nan( FPU registers[reg], fl_dest.negative ); } else if (fl_dest.zero || fl_source.zero ) { - if (fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_zero_negative(FPU registers[reg]); - } - else { - make_zero_positive(FPU registers[reg]); - } + make_zero(FPU registers[reg], fl_dest.negative != fl_source.negative); } else { - if( fl_dest.negative && !fl_source.negative || - !fl_dest.negative && fl_source.negative) { - make_inf_negative(FPU registers[reg]); - } - else { - make_inf_positive(FPU registers[reg]); - } + make_inf(FPU registers[reg], fl_dest.negative != fl_source.negative); } #else fpu_debug(("FMUL %.04f\n",(double)src)); @@ -2223,8 +2347,8 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) // Overflow, underflow #if FPU_HAVE_IEEE_DOUBLE - if( isinf(FPU registers[reg]) ) { - make_nan( FPU registers[reg] ); + if( isinf(src) ) { + make_nan( FPU registers[reg], isneg(src) ); } else { // When the absolute value of the source operand is >= 2^14, @@ -2336,6 +2460,27 @@ void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) dump_registers( "END "); } + +void fpu_set_fpsr(uae_u32 new_fpsr) +{ + set_fpsr(new_fpsr); +} + +uae_u32 fpu_get_fpsr(void) +{ + return get_fpsr(); +} + +void fpu_set_fpcr(uae_u32 new_fpcr) +{ + set_fpcr(new_fpcr); +} + +uae_u32 fpu_get_fpcr(void) +{ + return get_fpcr(); +} + /* -------------------------- Initialization -------------------------- */ void FFPU fpu_init (bool integral_68040) diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_uae.h b/BasiliskII/src/uae_cpu/fpu/fpu_uae.h index 7fc4ebbd..822fc220 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_uae.h +++ b/BasiliskII/src/uae_cpu/fpu/fpu_uae.h @@ -1,28 +1,33 @@ /* - * fpu/fpu_uae.h - Extra Definitions for the old UAE FPU core + * fpu/fpu_uae.h - Extra Definitions for the old UAE FPU core * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_UAE_H @@ -78,11 +83,9 @@ PRIVATE inline bool FFPU do_isinf(fpu_register const & r); PRIVATE inline bool FFPU do_isneg(fpu_register const & r); PRIVATE inline bool FFPU do_iszero(fpu_register const & r); -PRIVATE inline void FFPU make_nan(fpu_register & r); -PRIVATE inline void FFPU make_zero_positive(fpu_register & r); -PRIVATE inline void FFPU make_zero_negative(fpu_register & r); -PRIVATE inline void FFPU make_inf_positive(fpu_register & r); -PRIVATE inline void FFPU make_inf_negative(fpu_register & r); +PRIVATE inline void FFPU make_nan(fpu_register & r, bool negative); +PRIVATE inline void FFPU make_zero(fpu_register & r, bool negative); +PRIVATE inline void FFPU make_inf(fpu_register & r, bool negative); PRIVATE inline void FFPU fast_scale(fpu_register & r, int add); PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r); diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp b/BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp index 70e59086..29af7ddb 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp +++ b/BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp @@ -1,27 +1,33 @@ /* - * fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86. + * fpu/fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86. * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * Based on UAE FPU, original copyright 1996 Herman ten Brugge, - * rewritten for x86 by Lauri Pesonen 1999-2000, - * accomodated to GCC's Extended Asm syntax by Gwenole Beauchesne 2000. + * MC68881/68040 fpu emulation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * Interface @@ -134,10 +140,8 @@ * */ -#include -#include -#include -#include +# include +# include #include "sysdeps.h" #include "memory.h" @@ -238,8 +242,6 @@ PUBLIC void FFPU fpu_dump_flags(void) #include "debug.h" #if FPU_DEBUG -#undef __inline__ -#define __inline__ PRIVATE void FFPU dump_first_bytes_buf(char *b, uae_u8* buf, uae_s32 actual) { @@ -390,7 +392,7 @@ PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *) /* ---------------------------- Status functions ---------------------------- */ -PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN () +PRIVATE void inline FFPU SET_BSUN_ON_NAN () { if( (x86_status_word & (SW_Z_I_NAN_MASK)) == SW_NAN ) { x86_status_word |= SW_FAKE_BSUN; @@ -398,7 +400,7 @@ PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN () } } -PRIVATE void __inline__ FFPU build_ex_status () +PRIVATE void inline FFPU build_ex_status () { if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX @@ -415,20 +417,20 @@ When the FPU creates a NAN, the NAN always contains the same bit pattern in the mantissa. All bits of the mantissa are ones for any precision. When the user creates a NAN, any nonzero bit pattern can be stored in the mantissa. */ -PRIVATE __inline__ void FFPU MAKE_NAN (fpu_register & f) +PRIVATE inline void FFPU MAKE_NAN (fpu_register & f, bool negative) { // Make it non-signaling. uae_u8 * p = (uae_u8 *) &f; memset( p, 0xFF, sizeof(fpu_register) - 1 ); - p[9] = 0x7F; + p[9] = negative ? 0xff : 0x7F; } /* For single- and double-precision infinities the fraction is a zero. -For extended-precision infinities, the mantissa’s MSB, the explicit +For extended-precision infinities, the mantissa�s MSB, the explicit integer bit, can be either one or zero. */ -PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f) +PRIVATE inline uae_u32 FFPU IS_INFINITY (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { @@ -439,7 +441,7 @@ PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f) return(0); } -PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f) +PRIVATE inline uae_u32 FFPU IS_NAN (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { @@ -450,7 +452,7 @@ PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f) return(0); } -PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f) +PRIVATE inline uae_u32 FFPU IS_ZERO (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return *((uae_u32 *)p) == 0 && @@ -458,34 +460,34 @@ PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f) ( *((uae_u16 *)&p[8]) & 0x7FFF ) == 0; } -PRIVATE __inline__ void FFPU MAKE_INF_POSITIVE (fpu_register & f) +PRIVATE inline void FFPU MAKE_INF_POSITIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0x7FFF; } -PRIVATE __inline__ void FFPU MAKE_INF_NEGATIVE (fpu_register & f) +PRIVATE inline void FFPU MAKE_INF_NEGATIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0xFFFF; } -PRIVATE __inline__ void FFPU MAKE_ZERO_POSITIVE (fpu_register & f) +PRIVATE inline void FFPU MAKE_ZERO_POSITIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); } -PRIVATE __inline__ void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f) +PRIVATE inline void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); *((uae_u32 *)&p[4]) = 0x80000000; } -PRIVATE __inline__ uae_u32 FFPU IS_NEGATIVE (fpu_register const & f) +PRIVATE inline uae_u32 FFPU IS_NEGATIVE (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return( (p[9] & 0x80) != 0 ); @@ -900,6 +902,34 @@ PRIVATE void FFPU do_fmove ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fmove"); } +PRIVATE void FFPU do_fsmove ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fsmove"); +} + +PRIVATE void FFPU do_fdmove ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fdmove"); +} + /* PRIVATE void FFPU do_fmove_no_status ( fpu_register & dest, fpu_register const & src ) { @@ -1023,6 +1053,50 @@ PRIVATE void FFPU do_fsqrt ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fsqrt"); } +PRIVATE void FFPU do_fssqrt ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fsqrt \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fssqrt"); +} + +PRIVATE void FFPU do_fdsqrt ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fsqrt \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdsqrt"); +} + PRIVATE void FFPU do_ftst ( fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -1311,6 +1385,48 @@ PRIVATE void FFPU do_fabs ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fabs"); } +PRIVATE void FFPU do_fsabs ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fabs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + // x86 fabs should not rise any exceptions (except stack underflow) + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsabs"); +} + +PRIVATE void FFPU do_fdabs ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fabs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + // x86 fabs should not rise any exceptions (except stack underflow) + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdabs"); +} + PRIVATE void FFPU do_fneg ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -1341,6 +1457,48 @@ PRIVATE void FFPU do_fneg ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fneg"); } +PRIVATE void FFPU do_fsneg ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fchs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + // x86 fchs should not rise any exceptions (except stack underflow) + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsneg"); +} + +PRIVATE void FFPU do_fdneg ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fchs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "=m" (dest) + : "m" (src) + ); + // x86 fchs should not rise any exceptions (except stack underflow) + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdneg"); +} + PRIVATE void FFPU do_fcos ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -1466,6 +1624,50 @@ PRIVATE void FFPU do_fdiv ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fdiv"); } +PRIVATE void FFPU do_fsdiv ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fdiv %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsdiv"); +} + +PRIVATE void FFPU do_fddiv ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fdiv %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fddiv"); +} + // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. // Quotient Byte is loaded with the sign and least significant @@ -1851,6 +2053,48 @@ PRIVATE void FFPU do_fadd ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fadd"); } +PRIVATE void FFPU do_fsadd ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fadd \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsadd"); +} + +PRIVATE void FFPU do_fdadd ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fadd \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdadd"); +} + PRIVATE void FFPU do_fmul ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -1882,6 +2126,48 @@ PRIVATE void FFPU do_fmul ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fmul"); } +PRIVATE void FFPU do_fsmul ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fmul \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsmul"); +} + +PRIVATE void FFPU do_fdmul ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fmul \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdmul"); +} + PRIVATE void FFPU do_fsgldiv ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -2040,6 +2326,52 @@ PRIVATE void FFPU do_fsub ( fpu_register & dest, fpu_register const & src ) FPU_CONSISTENCY_CHECK_STOP("do_fsub"); } +PRIVATE void FFPU do_fssub ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fsub %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fssub"); +} + +PRIVATE void FFPU do_fdsub ( fpu_register & dest, fpu_register const & src ) +{ + FPU_CONSISTENCY_CHECK_START(); + __asm__ __volatile__( + "fldt %2\n" + "fldt %1\n" + "fsub %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (x86_status_word), "+m" (dest) + : "m" (src) + ); + if(x86_status_word & SW_EXCEPTION_MASK) { +// _asm FNCLEX + __asm__ __volatile__("fnclex"); + x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + x86_status_word_accrued |= x86_status_word; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdsub"); +} + PRIVATE void FFPU do_fsincos ( fpu_register & dest_sin, fpu_register & dest_cos, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); @@ -2284,11 +2616,9 @@ PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src break; case 3: ad = m68k_areg (regs, reg); - m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: - m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; - ad = m68k_areg (regs, reg); + ad = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); @@ -2387,6 +2717,15 @@ PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src return 0; } + switch (mode) { + case 3: + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; + case 4: + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + break; + } + // D(bug("get_fp_value result = %.04f\r\n",(float)src)); return 1; @@ -2612,7 +2951,7 @@ PRIVATE int FFPU fpp_cond(uae_u32 opcode, int condition) #define I ((x86_status_word & (SW_Z_I_NAN_MASK)) == (SW_I)) #define NotANumber ((x86_status_word & (SW_Z_I_NAN_MASK)) == SW_NAN) - switch (condition) { + switch (condition & 0x1f) { // Common Tests, no BSUN case 0x01: CONDRET("Equal",Z); @@ -2757,11 +3096,11 @@ PUBLIC void REGPARAM2 FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) } } -PUBLIC void REGPARAM2 FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) +PUBLIC void REGPARAM2 FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc, uae_u32 extra) { int cc; - D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ())); + D(bug("ftrapcc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); #if I3_ON_FTRAPCC #error "FIXME: _asm int 3" @@ -2769,7 +3108,7 @@ PUBLIC void REGPARAM2 FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) #endif // This must be broken. - cc = fpp_cond(opcode, opcode & 0x3f); + cc = fpp_cond(opcode, extra & 0x3f); if (cc < 0) { m68k_setpc (oldpc); @@ -2856,7 +3195,7 @@ PRIVATE void FFPU do_null_frestore () { // A null-restore operation sets FP7-FP0 positive, nonsignaling NANs. for( int i=0; i<8; i++ ) { - MAKE_NAN( FPU registers[i] ); + MAKE_NAN( FPU registers[i], false ); } FPU instruction_address = 0; @@ -4646,6 +4985,249 @@ PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4096( uae_u32 opcode, uae_u32 } +/* -------------------------- 040 ALU -------------------------- */ +PRIVATE void REGPARAM2 FFPU fpuop_do_fsmove( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSMOVE %s\r\n",etos(src))); + do_fsmove( FPU registers[reg], src ); + build_ex_status(); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdmove( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDMOVE %s\r\n",etos(src))); + do_fdmove( FPU registers[reg], src ); + build_ex_status(); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fssqrt( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSSQRT %s\r\n",etos(src))); + do_fssqrt( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdsqrt( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDSQRT %s\r\n",etos(src))); + do_fdsqrt( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fsabs( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSABS %s\r\n",etos(src))); + do_fsabs( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdabs( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDABS %s\r\n",etos(src))); + do_fdabs( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fsneg( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSNEG %s\r\n",etos(src))); + do_fsneg( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdneg( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDNEG %s\r\n",etos(src))); + do_fdneg( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fsdiv( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSDIV %s\r\n",etos(src))); + do_fsdiv( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fddiv( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDDIV %s\r\n",etos(src))); + do_fddiv( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fsadd( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSADD %s\r\n",etos(src))); + do_fsadd( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdadd( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDADD %s\r\n",etos(src))); + do_fdadd( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fssub( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSSUB %s\r\n",etos(src))); + do_fssub( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdsub( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FDSUB %s\r\n",etos(src))); + do_fdsub( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fsmul( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSMUL %s\r\n",etos(src))); + do_fsmul( FPU registers[reg], src ); + dump_registers( "END "); +} + +PRIVATE void REGPARAM2 FFPU fpuop_do_fdmul( uae_u32 opcode, uae_u32 extra ) +{ + int reg = (extra >> 7) & 7; + fpu_register src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_registers( "END "); + return; + } + D(bug("FSMUL %s\r\n",etos(src))); + do_fsmul( FPU registers[reg], src ); + dump_registers( "END "); +} + /* ---------------------------- ALU ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_do_fmove( uae_u32 opcode, uae_u32 extra ) @@ -5037,7 +5619,7 @@ PRIVATE void REGPARAM2 FFPU fpuop_do_fgetexp( uae_u32 opcode, uae_u32 extra ) D(bug("FGETEXP %s\r\n",etos(src))); if( IS_INFINITY(src) ) { - MAKE_NAN( FPU registers[reg] ); + MAKE_NAN( FPU registers[reg], IS_NEGATIVE(src) ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { @@ -5058,7 +5640,7 @@ PRIVATE void REGPARAM2 FFPU fpuop_do_fgetman( uae_u32 opcode, uae_u32 extra ) } D(bug("FGETMAN %s\r\n",etos(src))); if( IS_INFINITY(src) ) { - MAKE_NAN( FPU registers[reg] ); + MAKE_NAN( FPU registers[reg], IS_NEGATIVE(src) ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { @@ -5186,7 +5768,7 @@ PRIVATE void REGPARAM2 FFPU fpuop_do_fscale( uae_u32 opcode, uae_u32 extra ) } D(bug("FSCALE %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); if( IS_INFINITY(FPU registers[reg]) ) { - MAKE_NAN( FPU registers[reg] ); + MAKE_NAN( FPU registers[reg], IS_NEGATIVE(FPU registers[reg]) ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { @@ -5744,6 +6326,61 @@ PRIVATE void FFPU build_fpp_opp_lookup_table () } break; } + + if (FPU is_integral) { + switch (extra & 0x7f) { + case 0x40: + fpufunctbl[mask] = & FFPU fpuop_do_fsmove; + break; + case 0x44: + fpufunctbl[mask] = & FFPU fpuop_do_fdmove; + break; + case 0x41: + fpufunctbl[mask] = & FFPU fpuop_do_fssqrt; + break; + case 0x45: + fpufunctbl[mask] = & FFPU fpuop_do_fdsqrt; + break; + case 0x58: + fpufunctbl[mask] = & FFPU fpuop_do_fsabs; + break; + case 0x5c: + fpufunctbl[mask] = & FFPU fpuop_do_fdabs; + break; + case 0x5a: + fpufunctbl[mask] = & FFPU fpuop_do_fsneg; + break; + case 0x5e: + fpufunctbl[mask] = & FFPU fpuop_do_fdneg; + break; + case 0x60: + fpufunctbl[mask] = & FFPU fpuop_do_fsdiv; + break; + case 0x64: + fpufunctbl[mask] = & FFPU fpuop_do_fddiv; + break; + case 0x62: + fpufunctbl[mask] = & FFPU fpuop_do_fsadd; + break; + case 0x66: + fpufunctbl[mask] = & FFPU fpuop_do_fdadd; + break; + case 0x68: + fpufunctbl[mask] = & FFPU fpuop_do_fssub; + break; + case 0x6c: + fpufunctbl[mask] = & FFPU fpuop_do_fdsub; + break; + case 0x63: + fpufunctbl[mask] = & FFPU fpuop_do_fsmul; + break; + case 0x67: + fpufunctbl[mask] = & FFPU fpuop_do_fdmul; + break; + default: + break; + } + } switch (extra & 0x7f) { case 0x00: @@ -6033,6 +6670,26 @@ PRIVATE void FFPU do_fld1 ( fpu_register & dest ) } +void fpu_set_fpsr(uae_u32 new_fpsr) +{ + set_fpsr(new_fpsr); +} + +uae_u32 fpu_get_fpsr(void) +{ + return get_fpsr(); +} + +void fpu_set_fpcr(uae_u32 new_fpcr) +{ + set_fpcr(new_fpcr); +} + +uae_u32 fpu_get_fpcr(void) +{ + return get_fpcr(); +} + /* ---------------------------- MAIN INIT ---------------------------- */ #ifdef HAVE_SIGACTION @@ -6079,11 +6736,15 @@ PUBLIC void FFPU fpu_init( bool integral_68040 ) FPU fpsr.quotient = 0; for( int i=0; i<8; i++ ) { - MAKE_NAN( FPU registers[i] ); + MAKE_NAN( FPU registers[i], false ); } build_fpp_opp_lookup_table(); +/* _asm { + FNINIT + FLDCW x86_control_word + } */ __asm__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); do_fldpi( const_pi ); @@ -6111,6 +6772,10 @@ PUBLIC void FFPU fpu_init( bool integral_68040 ) set_constant( const_1e4096, "1.0e4096", 1.0e256, 10000 ); // Just in case. +/* _asm { + FNINIT + FLDCW x86_control_word + } */ __asm__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); } diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_x86.h b/BasiliskII/src/uae_cpu/fpu/fpu_x86.h index 96f1d959..c42bfa91 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_x86.h +++ b/BasiliskII/src/uae_cpu/fpu/fpu_x86.h @@ -1,28 +1,33 @@ /* - * fpu/fpu_x86.h - Extra Definitions for the X86 assembly FPU core + * fpu/fpu_x86.h - Extra Definitions for the X86 assembly FPU core * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_X86_H @@ -94,17 +99,17 @@ PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void); PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *name); // Get special floating-point value class -PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f); -PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f); -PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f); -PRIVATE __inline__ uae_u32 FFPU IS_NEGATIVE (fpu_register const & f); +PRIVATE inline uae_u32 FFPU IS_INFINITY (fpu_register const & f); +PRIVATE inline uae_u32 FFPU IS_NAN (fpu_register const & f); +PRIVATE inline uae_u32 FFPU IS_ZERO (fpu_register const & f); +PRIVATE inline uae_u32 FFPU IS_NEGATIVE (fpu_register const & f); // Make a special floating-point value -PRIVATE __inline__ void FFPU MAKE_NAN (fpu_register & f); -PRIVATE __inline__ void FFPU MAKE_INF_POSITIVE (fpu_register & f); -PRIVATE __inline__ void FFPU MAKE_INF_NEGATIVE (fpu_register & f); -PRIVATE __inline__ void FFPU MAKE_ZERO_POSITIVE (fpu_register & f); -PRIVATE __inline__ void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f); +PRIVATE inline void FFPU MAKE_NAN (fpu_register & f, bool negative); +PRIVATE inline void FFPU MAKE_INF_POSITIVE (fpu_register & f); +PRIVATE inline void FFPU MAKE_INF_NEGATIVE (fpu_register & f); +PRIVATE inline void FFPU MAKE_ZERO_POSITIVE (fpu_register & f); +PRIVATE inline void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f); // Conversion from extended floating-point values PRIVATE uae_s32 FFPU extended_to_signed_32 ( fpu_register const & f ) REGPARAM; @@ -342,6 +347,24 @@ PRIVATE void REGPARAM2 FFPU fpuop_do_fsincos( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fcmp( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftst( uae_u32 opcode, uae_u32 extra ); +// 040 +PRIVATE void REGPARAM2 FFPU fpuop_do_fsmove( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdmove( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fssqrt( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdsqrt( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fsabs( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdabs( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fsneg( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdneg( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fsdiv( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fddiv( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fsadd( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdadd( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fssub( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdsub( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fsmul( uae_u32 opcode, uae_u32 extra ); +PRIVATE void REGPARAM2 FFPU fpuop_do_fdmul( uae_u32 opcode, uae_u32 extra ); + // Get & Put floating-point values PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src) REGPARAM; PRIVATE int FFPU put_fp_value (fpu_register const & value, uae_u32 opcode, uae_u32 extra) REGPARAM; @@ -351,9 +374,9 @@ PRIVATE int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad) REGPARAM; PRIVATE int FFPU fpp_cond(uae_u32 opcode, int condition) REGPARAM; // Misc functions -PRIVATE void __inline__ FFPU set_host_fpu_control_word (); -PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN (); -PRIVATE void __inline__ FFPU build_ex_status (); +PRIVATE void inline FFPU set_host_fpu_control_word (); +PRIVATE void inline FFPU SET_BSUN_ON_NAN (); +PRIVATE void inline FFPU build_ex_status (); PRIVATE void FFPU do_null_frestore (); PRIVATE void FFPU build_fpp_opp_lookup_table (); PRIVATE void FFPU set_constant ( fpu_register & f, char *name, double value, uae_s32 mult ); diff --git a/BasiliskII/src/uae_cpu/fpu/fpu_x86_asm.h b/BasiliskII/src/uae_cpu/fpu/fpu_x86_asm.h index ecdecfbc..6e5a3766 100644 --- a/BasiliskII/src/uae_cpu/fpu/fpu_x86_asm.h +++ b/BasiliskII/src/uae_cpu/fpu/fpu_x86_asm.h @@ -1,3 +1,35 @@ +/* + * fpu/fpu_x86_asm.h - Extra Definitions for the X86 assembly FPU core + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * MC68881/68040 fpu emulation + * + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #define DEFINE_X86_MACRO(name, value) \ asm(".local " #name "\n\t" #name " = " #value) diff --git a/BasiliskII/src/uae_cpu/fpu/impl.h b/BasiliskII/src/uae_cpu/fpu/impl.h index c79d1f3f..ec5648a9 100644 --- a/BasiliskII/src/uae_cpu/fpu/impl.h +++ b/BasiliskII/src/uae_cpu/fpu/impl.h @@ -1,28 +1,38 @@ /* * fpu/impl.h - extra functions and inline implementations * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_IMPL_H @@ -101,14 +111,16 @@ static inline void FFPU set_fpsr(uae_u32 new_fpsr) /* Return the floating-point control register in m68k format */ static inline uae_u32 FFPU get_fpcr(void) { - uae_u32 rounding_precision = get_rounding_precision(); - uae_u32 rounding_mode = get_rounding_mode(); - return (rounding_precision | rounding_mode); + // according to the manual, the msb bits are always zero. + // According to Toni Wilen, on '040 the least + // significant 4 bits are not masked out + return FPU fpcr & (CPUType == 4 ? 0xffff : 0xfff0); } /* Set the floating-point control register from an m68k format */ static inline void FFPU set_fpcr(uae_u32 new_fpcr) { + FPU fpcr = new_fpcr; set_rounding_precision ( new_fpcr & FPCR_ROUNDING_PRECISION); set_rounding_mode ( new_fpcr & FPCR_ROUNDING_MODE ); set_host_control_word(); @@ -123,9 +135,8 @@ static inline void FFPU set_fpcr(uae_u32 new_fpcr) /* Retrieve a floating-point register value and convert it to double precision */ static inline double FFPU fpu_get_register(int r) { - double f; - __asm__ __volatile__("fldt %1\n\tfstpl %0" : "=m" (f) : "m" (FPU registers[r])); - return f; + /* only used for debug output; no need for any fancy asm here */ + return FPU registers[r]; } #endif diff --git a/BasiliskII/src/uae_cpu/fpu/mathlib.cpp b/BasiliskII/src/uae_cpu/fpu/mathlib.cpp index eabb376e..c9616927 100644 --- a/BasiliskII/src/uae_cpu/fpu/mathlib.cpp +++ b/BasiliskII/src/uae_cpu/fpu/mathlib.cpp @@ -1,28 +1,33 @@ /* * fpu/mathlib.cpp - Floating-point math support library * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2001 Lauri Pesonen - * New framework, copyright 2000-2001 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ @@ -40,6 +45,7 @@ #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) +#if !defined(HAVE_EXP10L) && !defined(HAVE_POW10L) PRIVATE fpu_extended fp_do_pow(fpu_extended x, fpu_extended y) { fpu_extended value, exponent; @@ -82,7 +88,9 @@ PRIVATE fpu_extended fp_do_pow(fpu_extended x, fpu_extended y) __asm__ __volatile__("fscale" : "=t" (value) : "0" (value), "u" (exponent)); return value; } +#endif +#ifndef HAVE_LOG1PL PRIVATE fpu_extended fp_do_log1p(fpu_extended x) { // TODO: handle NaN and +inf/-inf @@ -96,5 +104,6 @@ PRIVATE fpu_extended fp_do_log1p(fpu_extended x) __asm__ __volatile__("fldln2; fxch; fyl2x" : "=t" (value) : "0" (x + 1.0)); return value; } +#endif #endif diff --git a/BasiliskII/src/uae_cpu/fpu/mathlib.h b/BasiliskII/src/uae_cpu/fpu/mathlib.h index 2363af56..26e47ff8 100644 --- a/BasiliskII/src/uae_cpu/fpu/mathlib.h +++ b/BasiliskII/src/uae_cpu/fpu/mathlib.h @@ -1,28 +1,33 @@ /* - * fpu/mathlib.h - Floating-point math support library + * fpu/mathlib.h - Floating-point math support library * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2001 Lauri Pesonen - * New framework, copyright 2000-2001 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_MATHLIB_H @@ -49,22 +54,7 @@ // Use ISO C99 extended-precision math functions (glibc 2.1+) #define FPU_USE_ISO_C99 1 -// NOTE: this is irrelevant on Win32 platforms since the MS libraries -// don't support extended-precision floating-point computations -#if defined(WIN32) && USE_LONG_DOUBLE -#undef FPU_USE_ISO_C99 -#endif - -// Use faster implementation of math functions, but this could cause -// some incorrect results (?) -#ifdef _MSC_VER -// MSVC uses intrinsics for all of the math functions, so it should still be fast -#define FPU_FAST_MATH 0 -#else -#define FPU_FAST_MATH 1 -#endif - -#if FPU_USE_ISO_C99 +#if defined(FPU_USE_ISO_C99) // NOTE: no prior shall be included at this point #define __USE_ISOC99 1 // for glibc 2.2.X and newer #define __USE_ISOC9X 1 // for glibc 2.1.X @@ -147,7 +137,7 @@ union fpu_double_shape { unsigned int mantissa0:20; unsigned int mantissa1:32; #else -# if HOST_FLOAT_WORDS_BIG_ENDIAN +# if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int mantissa0:20; unsigned int exponent:11; unsigned int negative:1; @@ -172,7 +162,7 @@ union fpu_double_shape { unsigned int mantissa0:19; unsigned int mantissa1:32; #else -# if HOST_FLOAT_WORDS_BIG_ENDIAN +# if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int mantissa0:19; unsigned int quiet_nan:1; unsigned int exponent:11; @@ -191,7 +181,7 @@ union fpu_double_shape { /* This format is used to extract the sign_exponent and mantissa parts only */ struct { -#if HOST_FLOAT_WORDS_BIG_ENDIAN +#if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int msw:32; unsigned int lsw:32; #else @@ -215,7 +205,7 @@ union fpu_extended_shape { unsigned int mantissa0:32; unsigned int mantissa1:32; #else -# if HOST_FLOAT_WORDS_BIG_ENDIAN +# if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; @@ -242,7 +232,7 @@ union fpu_extended_shape { unsigned int mantissa0:30; unsigned int mantissa1:32; #else -# if HOST_FLOAT_WORDS_BIG_ENDIAN +# if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; @@ -264,7 +254,7 @@ union fpu_extended_shape { /* This format is used to extract the sign_exponent and mantissa parts only */ struct { -#if HOST_FLOAT_WORDS_BIG_ENDIAN +#if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int sign_exponent:16; unsigned int empty:16; unsigned int msw:32; @@ -310,7 +300,7 @@ union fpu_extended_shape { unsigned int exponent:15; unsigned int quiet_nan:1; unsigned int mantissa0:15; - unsigned int mantissa1:30; + unsigned int mantissa1:32; unsigned int mantissa2:32; unsigned int mantissa3:32; #else @@ -325,7 +315,7 @@ union fpu_extended_shape { } ieee_nan; /* This format is used to extract the sign_exponent and mantissa parts only */ -#if HOST_FLOAT_WORDS_BIG_ENDIAN +#if defined(HOST_FLOAT_WORDS_BIG_ENDIAN) && HOST_FLOAT_WORDS_BIG_ENDIAN struct { uae_u64 msw; uae_u64 lsw; @@ -351,9 +341,9 @@ union fpu_extended_shape { }; #endif -// Declare and initialize a pointer to a shape of the requested FP type -#define fp_declare_init_shape(psvar, rfvar, ftype) \ - fpu_ ## ftype ## _shape * psvar = (fpu_ ## ftype ## _shape *)( &rfvar ) +// Declare a shape of the requested FP type +#define fp_declare_init_shape(psvar, ftype) \ + fpu_ ## ftype ## _shape psvar /* -------------------------------------------------------------------------- */ /* --- Extra Math Functions --- */ @@ -370,47 +360,51 @@ union fpu_extended_shape { PRIVATE inline bool FFPU fp_do_isnan(fpu_register const & r) { #ifdef BRANCHES_ARE_EXPENSIVE -#ifndef USE_LONG_DOUBLE - fp_declare_init_shape(sxp, r, double); - uae_s32 hx = sxp->parts.msw; - uae_s32 lx = sxp->parts.lsw; +#if !defined(USE_LONG_DOUBLE) + fp_declare_init_shape(sxp, double); + sxp.value = r; + uae_s32 hx = sxp.parts.msw; + uae_s32 lx = sxp.parts.lsw; hx &= 0x7fffffff; hx |= (uae_u32)(lx | (-lx)) >> 31; hx = 0x7ff00000 - hx; - return (((uae_u32)hx) >> 31) != 0; -#elif USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - uae_s64 hx = sxp->parts64.msw; - uae_s64 lx = sxp->parts64.lsw; + return (int)(((uae_u32)hx) >> 31); +#elif defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + uae_s64 hx = sxp.parts64.msw; + uae_s64 lx = sxp.parts64.lsw; hx &= 0x7fffffffffffffffLL; hx |= (uae_u64)(lx | (-lx)) >> 63; hx = 0x7fff000000000000LL - hx; - return ((uae_u64)hx >> 63) != 0; + return (int)((uae_u64)hx >> 63); #else - fp_declare_init_shape(sxp, r, extended); - uae_s32 se = sxp->parts.sign_exponent; - uae_s32 hx = sxp->parts.msw; - uae_s32 lx = sxp->parts.lsw; + fp_declare_init_shape(sxp, extended); + sxp.value = r; + uae_s32 se = sxp.parts.sign_exponent; + uae_s32 hx = sxp.parts.msw; + uae_s32 lx = sxp.parts.lsw; se = (se & 0x7fff) << 1; lx |= hx & 0x7fffffff; se |= (uae_u32)(lx | (-lx)) >> 31; se = 0xfffe - se; - // TODO: check whether rshift count is 16 or 31 - return (((uae_u32)(se)) >> 16) != 0; + return (int)(((uae_u32)(se)) >> 31); #endif #else -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - return (sxp->ieee_nan.exponent == FP_EXTENDED_EXP_MAX) +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + return (sxp.ieee.exponent == FP_EXTENDED_EXP_MAX) #else - fp_declare_init_shape(sxp, r, double); - return (sxp->ieee_nan.exponent == FP_DOUBLE_EXP_MAX) + fp_declare_init_shape(sxp, double); + sxp.value = r; + return (sxp.ieee.exponent == FP_DOUBLE_EXP_MAX) #endif - && (sxp->ieee_nan.mantissa0 != 0) - && (sxp->ieee_nan.mantissa1 != 0) + && (sxp.ieee.mantissa0 & 0x7fffffff) != 0 + && sxp.ieee.mantissa1 != 0 #ifdef USE_QUAD_DOUBLE - && (sxp->ieee_nan.mantissa2 != 0) - && (sxp->ieee_nan.mantissa3 != 0) + && sxp.ieee.mantissa2 != 0 + && sxp.ieee.mantissa3 != 0 #endif ; #endif @@ -426,50 +420,62 @@ PRIVATE inline bool FFPU fp_do_isnan(fpu_register const & r) PRIVATE inline bool FFPU fp_do_isinf(fpu_register const & r) { #ifdef BRANCHES_ARE_EXPENSIVE -#ifndef USE_LONG_DOUBLE - fp_declare_init_shape(sxp, r, double); - uae_s32 hx = sxp->parts.msw; - uae_s32 lx = sxp->parts.lsw; +#if !defined(USE_LONG_DOUBLE) + fp_declare_init_shape(sxp, double); + sxp.value = r; + uae_s32 hx = sxp.parts.msw; + uae_s32 lx = sxp.parts.lsw; lx |= (hx & 0x7fffffff) ^ 0x7ff00000; lx |= -lx; - return (~(lx >> 31) & (hx >> 30)) != 0; -#elif USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - uae_s64 hx = sxp->parts64.msw; - uae_s64 lx = sxp->parts64.lsw; + return ~(lx >> 31) & (hx >> 30); +#elif defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + uae_s64 hx = sxp.parts64.msw; + uae_s64 lx = sxp.parts64.lsw; lx |= (hx & 0x7fffffffffffffffLL) ^ 0x7fff000000000000LL; lx |= -lx; - return (~(lx >> 63) & (hx >> 62)) != 0; + return ~(lx >> 63) & (hx >> 62); #else - fp_declare_init_shape(sxp, r, extended); - uae_s32 se = sxp->parts.sign_exponent; - uae_s32 hx = sxp->parts.msw; - uae_s32 lx = sxp->parts.lsw; + fp_declare_init_shape(sxp, extended); + sxp.value = r; + /* NOTE: This function should work for both m68k and native INFs. */ +#if 0 + uae_s32 se = sxp.parts.sign_exponent; + uae_s32 hx = sxp.parts.msw; + uae_s32 lx = sxp.parts.lsw; /* This additional ^ 0x80000000 is necessary because in Intel's internal representation of the implicit one is explicit. NOTE: anyway, this is equivalent to & 0x7fffffff in that case. */ -#ifdef __i386__ +#ifdef CPU_i386 lx |= (hx ^ 0x80000000) | ((se & 0x7fff) ^ 0x7fff); #else lx |= (hx & 0x7fffffff) | ((se & 0x7fff) ^ 0x7fff); #endif lx |= -lx; se &= 0x8000; - return (~(lx >> 31) & (1 - (se >> 14))) != 0; + return ~(lx >> 31) & (1 - (se >> 14)); +#else + return sxp.ieee.exponent == FP_EXTENDED_EXP_MAX + && (sxp.ieee.mantissa0 & 0x7fffffff) == 0 + && sxp.ieee.mantissa1 == 0; +#endif #endif #else -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - return (sxp->ieee_nan.exponent == FP_EXTENDED_EXP_MAX) +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + return (sxp.ieee_nan.exponent == FP_EXTENDED_EXP_MAX) #else - fp_declare_init_shape(sxp, r, double); - return (sxp->ieee_nan.exponent == FP_DOUBLE_EXP_MAX) + fp_declare_init_shape(sxp, double); + sxp.value = r; + return (sxp.ieee_nan.exponent == FP_DOUBLE_EXP_MAX) #endif - && (sxp->ieee_nan.mantissa0 == 0) - && (sxp->ieee_nan.mantissa1 == 0) + && (sxp.ieee.mantissa0 & 0x7fffffff) == 0 + && sxp.ieee.mantissa1 == 0 #ifdef USE_QUAD_DOUBLE - && (sxp->ieee_nan.mantissa2 == 0) - && (sxp->ieee_nan.mantissa3 == 0) + && sxp.ieee.mantissa2 == 0 + && sxp.ieee.mantissa3 == 0 #endif ; #endif @@ -480,12 +486,13 @@ PRIVATE inline bool FFPU fp_do_isinf(fpu_register const & r) PRIVATE inline bool FFPU fp_do_isneg(fpu_register const & r) { -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); #else - fp_declare_init_shape(sxp, r, double); + fp_declare_init_shape(sxp, double); #endif - return sxp->ieee.negative; + sxp.value = r; + return sxp.ieee.negative; } #undef iszero @@ -494,17 +501,18 @@ PRIVATE inline bool FFPU fp_do_isneg(fpu_register const & r) PRIVATE inline bool FFPU fp_do_iszero(fpu_register const & r) { // TODO: BRANCHES_ARE_EXPENSIVE -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); #else - fp_declare_init_shape(sxp, r, double); + fp_declare_init_shape(sxp, double); #endif - return (sxp->ieee.exponent == 0) - && (sxp->ieee.mantissa0 == 0) - && (sxp->ieee.mantissa1 == 0) + sxp.value = r; + return (sxp.ieee.exponent == 0) + && (sxp.ieee.mantissa0 == 0) + && (sxp.ieee.mantissa1 == 0) #ifdef USE_QUAD_DOUBLE - && (sxp->ieee.mantissa2 == 0) - && (sxp->ieee.mantissa3 == 0) + && (sxp.ieee.mantissa2 == 0) + && (sxp.ieee.mantissa3 == 0) #endif ; } @@ -527,158 +535,155 @@ PRIVATE inline void FFPU get_source_flags(fpu_register const & r) fl_source.in_range = !fl_source.zero && !fl_source.infinity && !fl_source.nan; } -PRIVATE inline void FFPU make_nan(fpu_register & r) +PRIVATE inline void FFPU make_nan(fpu_register & r, bool negative) { - // FIXME: is that correct ? -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - sxp->ieee.exponent = FP_EXTENDED_EXP_MAX; - sxp->ieee.mantissa0 = 0xffffffff; +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.ieee.exponent = FP_EXTENDED_EXP_MAX; + sxp.ieee.empty = 0; + sxp.ieee.mantissa0 = 0xffffffff; #else - fp_declare_init_shape(sxp, r, double); - sxp->ieee.exponent = FP_DOUBLE_EXP_MAX; - sxp->ieee.mantissa0 = 0xfffff; + fp_declare_init_shape(sxp, double); + sxp.ieee.exponent = FP_DOUBLE_EXP_MAX; + sxp.ieee.mantissa0 = 0xfffff; #endif - sxp->ieee.mantissa1 = 0xffffffff; + sxp.ieee.mantissa1 = 0xffffffff; #ifdef USE_QUAD_DOUBLE - sxp->ieee.mantissa2 = 0xffffffff; - sxp->ieee.mantissa3 = 0xffffffff; + sxp.ieee.mantissa2 = 0xffffffff; + sxp.ieee.mantissa3 = 0xffffffff; #endif + sxp.ieee.negative = negative; + r = sxp.value; } -PRIVATE inline void FFPU make_zero_positive(fpu_register & r) +PRIVATE inline void FFPU make_zero(fpu_register & r, bool negative) { #if 1 - r = +0.0; + r = negative ? -0.0 : +0.0; #else -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.ieee.empty = 0; #else - fp_declare_init_shape(sxp, r, double); + fp_declare_init_shape(sxp, double); #endif - sxp->ieee.negative = 0; - sxp->ieee.exponent = 0; - sxp->ieee.mantissa0 = 0; - sxp->ieee.mantissa1 = 0; + sxp.ieee.negative = negative; + sxp.ieee.exponent = 0; + sxp.ieee.mantissa0 = 0; + sxp.ieee.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE - sxp->ieee.mantissa2 = 0; - sxp->ieee.mantissa3 = 0; + sxp.ieee.mantissa2 = 0; + sxp.ieee.mantissa3 = 0; #endif + r = sxp.value; #endif } -PRIVATE inline void FFPU make_zero_negative(fpu_register & r) +PRIVATE inline void FFPU make_inf(fpu_register & r, bool negative) { -#if 1 - r = -0.0; +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.ieee.exponent = FP_EXTENDED_EXP_MAX; + sxp.ieee.mantissa0 = 0x80000000; + sxp.ieee.empty = 0; #else -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); -#else - fp_declare_init_shape(sxp, r, double); + fp_declare_init_shape(sxp, double); + sxp.ieee.exponent = FP_DOUBLE_EXP_MAX; + sxp.ieee.mantissa0 = 0; #endif - sxp->ieee.negative = 1; - sxp->ieee.exponent = 0; - sxp->ieee.mantissa0 = 0; - sxp->ieee.mantissa1 = 0; + sxp.ieee.negative = negative; + sxp.ieee.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE - sxp->ieee.mantissa2 = 0; - sxp->ieee.mantissa3 = 0; -#endif -#endif -} - -PRIVATE inline void FFPU make_inf_positive(fpu_register & r) -{ -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; -#else - fp_declare_init_shape(sxp, r, double); - sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; -#endif - sxp->ieee_nan.negative = 0; - sxp->ieee_nan.mantissa0 = 0; - sxp->ieee_nan.mantissa1 = 0; -#ifdef USE_QUAD_DOUBLE - sxp->ieee_nan.mantissa2 = 0; - sxp->ieee_nan.mantissa3 = 0; -#endif -} - -PRIVATE inline void FFPU make_inf_negative(fpu_register & r) -{ -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; -#else - fp_declare_init_shape(sxp, r, double); - sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; -#endif - sxp->ieee_nan.negative = 1; - sxp->ieee_nan.mantissa0 = 0; - sxp->ieee_nan.mantissa1 = 0; -#ifdef USE_QUAD_DOUBLE - sxp->ieee_nan.mantissa2 = 0; - sxp->ieee_nan.mantissa3 = 0; + sxp.ieee.mantissa2 = 0; + sxp.ieee.mantissa3 = 0; #endif + r = sxp.value; } PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r) { -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - return (sxp->ieee.exponent - FP_EXTENDED_EXP_BIAS); +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + return ((int) sxp.ieee.exponent - FP_EXTENDED_EXP_BIAS); #else - fp_declare_init_shape(sxp, r, double); - return (sxp->ieee.exponent - FP_DOUBLE_EXP_BIAS); + fp_declare_init_shape(sxp, double); + sxp.value = r; + return ((int) sxp.ieee.exponent - FP_DOUBLE_EXP_BIAS); #endif } // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r) { -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, r, extended); - sxp->ieee.exponent = FP_EXTENDED_EXP_BIAS; +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = r; + sxp.ieee.exponent = FP_EXTENDED_EXP_BIAS; #else - fp_declare_init_shape(sxp, r, double); - sxp->ieee.exponent = FP_DOUBLE_EXP_BIAS; + fp_declare_init_shape(sxp, double); + sxp.value = r; + sxp.ieee.exponent = FP_DOUBLE_EXP_BIAS; #endif + r = sxp.value; } // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_register const & rb) { -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sap, ra, extended); - fp_declare_init_shape(sbp, rb, extended); +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sap, extended); + fp_declare_init_shape(sbp, extended); #else - fp_declare_init_shape(sap, ra, double); - fp_declare_init_shape(sbp, rb, double); + fp_declare_init_shape(sap, double); + fp_declare_init_shape(sbp, double); #endif - return ((sap->ieee.negative ^ sbp->ieee.negative) ? FPSR_QUOTIENT_SIGN : 0); + sap.value = ra; + sbp.value = rb; + return ((sap.ieee.negative ^ sbp.ieee.negative) ? FPSR_QUOTIENT_SIGN : 0); } /* -------------------------------------------------------------------------- */ /* --- Math functions --- */ /* -------------------------------------------------------------------------- */ -#if FPU_USE_ISO_C99 -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE +#if defined(FPU_USE_ISO_C99) && (defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE)) # ifdef HAVE_LOGL # define fp_log logl # endif +# ifdef HAVE_LOG1PL +# define fp_log1p log1pl +# endif +# ifdef HAVE_EXPM1L +# define fp_expm1 expm1l +# endif # ifdef HAVE_LOG10L # define fp_log10 log10l # endif +# ifdef HAVE_LOG2L +# define fp_log2 log2l +# endif # ifdef HAVE_EXPL # define fp_exp expl # endif # ifdef HAVE_POWL # define fp_pow powl # endif +# if defined(HAVE_EXP10L) +# define fp_pow10 exp10l +# elif defined(HAVE_POW10L) +# define fp_pow10 pow10l +# else +# define fp_pow10(x) fp_pow(LD(10.0), x) +# endif +# if defined(HAVE_EXP2L) +# define fp_pow2 exp2l +# elif defined(HAVE_POW2L) +# define fp_pow2 pow2l +# else +# define fp_pow2(x) fp_pow(LD(2.0), x) +# endif # ifdef HAVE_FABSL # define fp_fabs fabsl # endif @@ -732,15 +737,38 @@ PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_regis #ifndef fp_log # define fp_log log #endif +#ifndef fp_log1p +# define fp_log1p log1p +#endif +#ifndef fp_expm1 +# define fp_expm1 expm1 +#endif #ifndef fp_log10 # define fp_log10 log10 #endif +#ifndef fp_log2 +# define fp_log2 log2 +#endif #ifndef fp_exp # define fp_exp exp #endif #ifndef fp_pow # define fp_pow pow #endif +#ifndef fp_pow10 +# ifdef HAVE_POW10 +# define fp_pow10 pow10 +# else +# define fp_pow10 exp10 +# endif +#endif +#ifndef fp_pow2 +# ifdef HAVE_POW2 +# define fp_pow2 pow2 +# else +# define fp_pow2 exp2 +# endif +#endif #ifndef fp_fabs # define fp_fabs fabs #endif @@ -790,48 +818,43 @@ PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_regis # define fp_ceil ceil #endif -#elif defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) +#if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) // Assembly optimized support functions. Taken from glibc 2.2.2 #undef fp_log #define fp_log fp_do_log -#if !FPU_FAST_MATH -PRIVATE fpu_extended fp_do_log(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_log(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fldln2; fxch; fyl2x" : "=t" (value) : "0" (x) : "st(1)"); return value; } -#endif #undef fp_log10 #define fp_log10 fp_do_log10 -#if !FPU_FAST_MATH -// FIXME: unimplemented -PRIVATE fpu_extended fp_do_log10(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_log10(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fldlg2; fxch; fyl2x" : "=t" (value) : "0" (x) : "st(1)"); return value; } -#endif +#if !defined(HAVE_EXPL) #undef fp_exp #define fp_exp fp_do_exp -#if !FPU_FAST_MATH -// FIXME: unimplemented -PRIVATE fpu_extended fp_do_exp(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_exp(fpu_extended x) { fpu_extended value, exponent; + if (isinf(x)) + { + if(isneg(x)) + return 0.; + else + return x; + } __asm__ __volatile__("fldl2e # e^x = 2^(x * log2(e))\n\t" "fmul %%st(1) # x * log2(e)\n\t" "fst %%st(1)\n\t" @@ -846,10 +869,12 @@ PRIVATE inline fpu_extended fp_do_exp(fpu_extended x) } #endif +#if !defined(HAVE_EXP10L) && !defined(HAVE_POW10L) #undef fp_pow #define fp_pow fp_do_pow PRIVATE fpu_extended fp_do_pow(fpu_extended x, fpu_extended y); +#endif #undef fp_fabs #define fp_fabs fp_do_fabs @@ -871,6 +896,7 @@ PRIVATE inline fpu_extended fp_do_sqrt(fpu_extended x) return value; } +#ifndef ACCURATE_SIN_COS_TAN #undef fp_sin #define fp_sin fp_do_sin @@ -896,18 +922,27 @@ PRIVATE inline fpu_extended fp_do_cos(fpu_extended x) PRIVATE inline fpu_extended fp_do_tan(fpu_extended x) { - fpu_extended value; - __asm__ __volatile__("fptan" : "=t" (value) : "0" (x)); + fpu_extended value, value2; + __asm__ __volatile__("fptan" : "=t" (value2), "=u" (value) : "0" (x)); return value; } +#endif /* ACCURATE_SIN_COS_TAN */ +#ifndef HAVE_EXPM1L #undef fp_expm1 #define fp_expm1 fp_do_expm1 // Returns: exp(X) - 1.0 PRIVATE inline fpu_extended fp_do_expm1(fpu_extended x) { - fpu_extended value, exponent, temp; + fpu_extended value, exponent, temp, temp2; + if (isinf(x)) + { + if(isneg(x)) + return -1.; + else + return x; + } __asm__ __volatile__("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" "fmul %%st(1) # x * log2(e)\n\t" "fst %%st(1)\n\t" @@ -917,51 +952,52 @@ PRIVATE inline fpu_extended fp_do_expm1(fpu_extended x) "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" : "=t" (value), "=u" (exponent) : "0" (x)); - __asm__ __volatile__("fscale" : "=t" (temp) : "0" (1.0), "u" (exponent)); + __asm__ __volatile__("fld1 \n\t" + "fscale \n\t" + : "=t" (temp), "=u" (temp2) : "0" (exponent)); temp -= 1.0; return temp + value ? temp + value : x; } +#endif #undef fp_sgn1 #define fp_sgn1 fp_do_sgn1 PRIVATE inline fpu_extended fp_do_sgn1(fpu_extended x) { -#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE - fp_declare_init_shape(sxp, x, extended); - sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; - sxp->ieee_nan.one = 1; +#if defined(USE_LONG_DOUBLE) || defined(USE_QUAD_DOUBLE) + fp_declare_init_shape(sxp, extended); + sxp.value = x; + sxp.ieee_nan.exponent = FP_EXTENDED_EXP_MAX>>1; + sxp.ieee_nan.one = 1; #else - fp_declare_init_shape(sxp, x, double); - sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; + fp_declare_init_shape(sxp, double); + sxp.value = x; + sxp.ieee_nan.exponent = FP_DOUBLE_EXP_MAX>>1; #endif - sxp->ieee_nan.quiet_nan = 0; - sxp->ieee_nan.mantissa0 = 0; - sxp->ieee_nan.mantissa1 = 0; + sxp.ieee_nan.quiet_nan = 0; + sxp.ieee_nan.mantissa0 = 0; + sxp.ieee_nan.mantissa1 = 0; + x = sxp.value; return x; } +#ifndef HAVE_SINHL #undef fp_sinh #define fp_sinh fp_do_sinh -#if !FPU_FAST_MATH -// FIXME: unimplemented -PRIVATE fpu_extended fp_do_sinh(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_sinh(fpu_extended x) { + if (isinf(x)) return x; fpu_extended exm1 = fp_expm1(fp_fabs(x)); return 0.5 * (exm1 / (exm1 + 1.0) + exm1) * fp_sgn1(x); } #endif +#ifndef HAVE_COSHL #undef fp_cosh #define fp_cosh fp_do_cosh -#if !FPU_FAST_MATH -// FIXME: unimplemented -PRIVATE fpu_extended fp_do_cosh(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_cosh(fpu_extended x) { fpu_extended ex = fp_exp(x); @@ -969,13 +1005,10 @@ PRIVATE inline fpu_extended fp_do_cosh(fpu_extended x) } #endif +#ifndef HAVE_TANHL #undef fp_tanh #define fp_tanh fp_do_tanh -#if !FPU_FAST_MATH -// FIXME: unimplemented -PRIVATE fpu_extended fp_do_tanh(fpu_extended x); -#else PRIVATE inline fpu_extended fp_do_tanh(fpu_extended x) { fpu_extended exm1 = fp_expm1(-fp_fabs(x + x)); @@ -993,6 +1026,7 @@ PRIVATE inline fpu_extended fp_do_atan2(fpu_extended y, fpu_extended x) return value; } +#ifndef HAVE_ASINL #undef fp_asin #define fp_asin fp_do_asin @@ -1000,7 +1034,9 @@ PRIVATE inline fpu_extended fp_do_asin(fpu_extended x) { return fp_atan2(x, fp_sqrt(1.0 - x * x)); } +#endif +#ifndef HAVE_ACOSL #undef fp_acos #define fp_acos fp_do_acos @@ -1008,6 +1044,7 @@ PRIVATE inline fpu_extended fp_do_acos(fpu_extended x) { return fp_atan2(fp_sqrt(1.0 - x * x), x); } +#endif #undef fp_atan #define fp_atan fp_do_atan @@ -1019,12 +1056,15 @@ PRIVATE inline fpu_extended fp_do_atan(fpu_extended x) return value; } +#ifndef HAVE_LOG1PL #undef fp_log1p #define fp_log1p fp_do_log1p // Returns: ln(1.0 + X) PRIVATE fpu_extended fp_do_log1p(fpu_extended x); +#endif +#ifndef HAVE_ASINHL #undef fp_asinh #define fp_asinh fp_do_asinh @@ -1033,7 +1073,9 @@ PRIVATE inline fpu_extended fp_do_asinh(fpu_extended x) fpu_extended y = fp_fabs(x); return (fp_log1p(y * y / (fp_sqrt(y * y + 1.0) + 1.0) + y) * fp_sgn1(x)); } +#endif +#ifndef HAVE_ACOSHL #undef fp_acosh #define fp_acosh fp_do_acosh @@ -1041,7 +1083,9 @@ PRIVATE inline fpu_extended fp_do_acosh(fpu_extended x) { return fp_log(x + fp_sqrt(x - 1.0) * fp_sqrt(x + 1.0)); } +#endif +#ifndef HAVE_ATANHL #undef fp_atanh #define fp_atanh fp_do_atanh @@ -1050,69 +1094,87 @@ PRIVATE inline fpu_extended fp_do_atanh(fpu_extended x) fpu_extended y = fp_fabs(x); return -0.5 * fp_log1p(-(y + y) / (1.0 + y)) * fp_sgn1(x); } +#endif -#undef fp_floor -#define fp_floor fp_do_floor -PRIVATE inline fpu_extended fp_do_floor(fpu_extended x) -{ - volatile unsigned int cw; - __asm__ __volatile__("fnstcw %0" : "=m" (cw)); - volatile unsigned int cw_temp = (cw & 0xf3ff) | 0x0400; // rounding down - __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); - fpu_extended value; - __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); - __asm__ __volatile__("fldcw %0" : : "m" (cw)); - return value; +/* + * LLVM 2.9 crashes on first definition, + * clang with LLVM 3.x crashes on 2nd definition... sigh + */ +#if defined(__clang__) || !defined(__llvm__) +#define DEFINE_ROUND_FUNC(rounding_mode_str, rounding_mode) \ +PRIVATE inline fpu_extended fp_do_round_to_ ## rounding_mode_str(fpu_extended __x) \ +{ \ + register long double __value; \ + register int __ignore; \ + volatile unsigned short __cw; \ + volatile unsigned short __cwtmp; \ + __asm __volatile ("fnstcw %3\n\t" \ + "movzwl %3, %1\n\t" \ + "andl $0xf3ff, %1\n\t" \ + "orl %5, %1\n\t" \ + "movw %w1, %2\n\t" \ + "fldcw %2\n\t" \ + "frndint\n\t" \ + "fldcw %3" \ + : "=t" (__value), "=&q" (__ignore), "=m" (__cwtmp), \ + "=m" (__cw) \ + : "0" (__x), "i"(rounding_mode)); \ + return __value; \ } - -#undef fp_ceil -#define fp_ceil fp_do_ceil - -PRIVATE inline fpu_extended fp_do_ceil(fpu_extended x) -{ - volatile unsigned int cw; - __asm__ __volatile__("fnstcw %0" : "=m" (cw)); - volatile unsigned int cw_temp = (cw & 0xf3ff) | 0x0800; // rounding up - __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); - fpu_extended value; - __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); - __asm__ __volatile__("fldcw %0" : : "m" (cw)); - return value; -} - +#else #define DEFINE_ROUND_FUNC(rounding_mode_str, rounding_mode) \ PRIVATE inline fpu_extended fp_do_round_to_ ## rounding_mode_str(fpu_extended x) \ { \ - volatile unsigned int cw; \ + volatile unsigned short cw; \ __asm__ __volatile__("fnstcw %0" : "=m" (cw)); \ - volatile unsigned int cw_temp = (cw & 0xf3ff) | (rounding_mode); \ + volatile unsigned short cw_temp = (cw & 0xf3ff) | (rounding_mode); \ __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); \ fpu_extended value; \ __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); \ __asm__ __volatile__("fldcw %0" : : "m" (cw)); \ return value; \ } +#endif #undef fp_round_to_minus_infinity +#ifdef HAVE_FLOORL +#define fp_round_to_minus_infinity floorl +#else #define fp_round_to_minus_infinity fp_do_round_to_minus_infinity - -DEFINE_ROUND_FUNC(minus_infinity, 0x400) +DEFINE_ROUND_FUNC(minus_infinity, CW_RC_DOWN) +#endif #undef fp_round_to_plus_infinity +#ifdef HAVE_CEILL +#define fp_round_to_plus_infinity ceill +#else #define fp_round_to_plus_infinity fp_do_round_to_plus_infinity - -DEFINE_ROUND_FUNC(plus_infinity, 0x800) +DEFINE_ROUND_FUNC(plus_infinity, CW_RC_UP) +#endif #undef fp_round_to_zero +#ifdef HAVE_TRUNCL +#define fp_round_to_zero truncl +#else #define fp_round_to_zero fp_do_round_to_zero - -DEFINE_ROUND_FUNC(zero, 0xc00) +DEFINE_ROUND_FUNC(zero, CW_RC_ZERO) +#endif #undef fp_round_to_nearest +#ifdef HAVE_ROUNDL +#define fp_round_to_nearest roundl +#else #define fp_round_to_nearest fp_do_round_to_nearest +DEFINE_ROUND_FUNC(nearest, CW_RC_NEAR) +#endif + +#undef fp_ceil +#define fp_ceil fp_do_round_to_plus_infinity + +#undef fp_floor +#define fp_floor fp_do_round_to_minus_infinity -DEFINE_ROUND_FUNC(nearest, 0x000) #endif /* USE_X87_ASSEMBLY */ diff --git a/BasiliskII/src/uae_cpu/fpu/rounding.cpp b/BasiliskII/src/uae_cpu/fpu/rounding.cpp index 1f8b3618..9942d4e8 100644 --- a/BasiliskII/src/uae_cpu/fpu/rounding.cpp +++ b/BasiliskII/src/uae_cpu/fpu/rounding.cpp @@ -1,28 +1,33 @@ /* - * fpu/rounding.cpp - system-dependant FPU rounding mode and precision + * fpu/rounding.cpp - system-dependant FPU rounding mode and precision * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #undef PRIVATE diff --git a/BasiliskII/src/uae_cpu/fpu/rounding.h b/BasiliskII/src/uae_cpu/fpu/rounding.h index 67db5519..aa2c9ced 100644 --- a/BasiliskII/src/uae_cpu/fpu/rounding.h +++ b/BasiliskII/src/uae_cpu/fpu/rounding.h @@ -1,28 +1,33 @@ /* - * fpu/rounding.h - system-dependant FPU rounding mode and precision + * fpu/rounding.h - system-dependant FPU rounding mode and precision * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_ROUNDING_H @@ -106,8 +111,8 @@ PRIVATE inline void set_host_control_word(void) */ x86_control_word = (x86_control_word & ~(X86_ROUNDING_MODE|X86_ROUNDING_PRECISION)) - | x86_control_word_rm_mac2host[(FPU fpcr.rounding_mode & FPCR_ROUNDING_MODE) >> 4] - | x86_control_word_rp_mac2host[(FPU fpcr.rounding_precision & FPCR_ROUNDING_PRECISION) >> 6] + | x86_control_word_rm_mac2host[(FPU fpcr & FPCR_ROUNDING_MODE) >> 4] + | x86_control_word_rp_mac2host[(FPU fpcr & FPCR_ROUNDING_PRECISION) >> 6] ; __asm__ __volatile__("fldcw %0" : : "m" (x86_control_word)); } @@ -131,11 +136,11 @@ PRIVATE inline void set_host_control_word(void) /* Return the current rounding mode in m68k format */ static inline uae_u32 FFPU get_rounding_mode(void) - { return FPU fpcr.rounding_mode; } + { return FPU fpcr & FPCR_ROUNDING_MODE; } /* Convert and set to native rounding mode */ -static inline void FFPU set_rounding_mode(uae_u32 new_rounding_mode) - { FPU fpcr.rounding_mode = new_rounding_mode; } +static inline void FFPU set_rounding_mode(uae_u32 /* new_rounding_mode */ ) + { } #endif @@ -143,11 +148,11 @@ static inline void FFPU set_rounding_mode(uae_u32 new_rounding_mode) /* Return the current rounding precision in m68k format */ static inline uae_u32 FFPU get_rounding_precision(void) - { return FPU fpcr.rounding_precision; } + { return FPU fpcr & FPCR_ROUNDING_PRECISION; } /* Convert and set to native rounding precision */ -static inline void FFPU set_rounding_precision(uae_u32 new_rounding_precision) - { FPU fpcr.rounding_precision = new_rounding_precision; } +static inline void FFPU set_rounding_precision(uae_u32 /* new_rounding_precision */) + { } #endif diff --git a/BasiliskII/src/uae_cpu/fpu/types.h b/BasiliskII/src/uae_cpu/fpu/types.h index 778567a9..50e07ec2 100644 --- a/BasiliskII/src/uae_cpu/fpu/types.h +++ b/BasiliskII/src/uae_cpu/fpu/types.h @@ -1,28 +1,33 @@ /* - * types.h - basic types for fpu registers + * fpu/types.h - basic types for fpu registers * - * Basilisk II (C) 1997-2008 Christian Bauer + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * MC68881/68040 fpu emulation - * - * Original UAE FPU, copyright 1996 Herman ten Brugge - * Rewrite for x86, copyright 1999-2000 Lauri Pesonen - * New framework, copyright 2000 Gwenole Beauchesne - * Adapted for JIT compilation (c) Bernd Meyer, 2000 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MC68881/68040 fpu emulation * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Original UAE FPU, copyright 1996 Herman ten Brugge + * Rewrite for x86, copyright 1999-2001 Lauri Pesonen + * New framework, copyright 2000-2001 Gwenole Beauchesne + * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FPU_TYPES_H @@ -106,9 +111,11 @@ typedef uae_f32 fpu_single; #elif defined(FPU_IEEE) -// #if HOST_FLOAT_FORMAT != IEEE_FLOAT_FORMAT -// #error "No IEEE float format, you lose." -// #endif +#if 0 +#if HOST_FLOAT_FORMAT != IEEE_FLOAT_FORMAT +#error "No IEEE float format, you lose." +#endif +#endif /* 4-byte floats */ #if SIZEOF_FLOAT == 4 @@ -133,7 +140,7 @@ typedef long double uae_f64; typedef long double uae_f96; typedef uae_f96 fpu_register; #define USE_LONG_DOUBLE 1 -#elif SIZEOF_LONG_DOUBLE == 16 && (defined(__i386__) || defined(__x86_64__)) +#elif SIZEOF_LONG_DOUBLE == 16 && (defined(CPU_i386) || defined(CPU_x86_64) || defined(CPU_ia64)) /* Long doubles on x86-64 are really held in old x87 FPU stack. */ typedef long double uae_f128; typedef uae_f128 fpu_register; @@ -154,6 +161,23 @@ typedef fpu_register fpu_extended; typedef uae_f64 fpu_double; typedef uae_f32 fpu_single; +#elif defined(FPU_MPFR) + +#include + +struct fpu_register { + mpfr_t f; + uae_u64 nan_bits; + int nan_sign; + operator long double (); + fpu_register &operator=(long double); +}; + #endif +union fpu_register_parts { + fpu_register val; + uae_u32 parts[sizeof(fpu_register) / 4]; +}; + #endif /* FPU_TYPES_H */ diff --git a/BasiliskII/src/uae_cpu/gencpu.c b/BasiliskII/src/uae_cpu/gencpu.c index 5ab3895a..e28c370a 100644 --- a/BasiliskII/src/uae_cpu/gencpu.c +++ b/BasiliskII/src/uae_cpu/gencpu.c @@ -1,3 +1,27 @@ +/* + * gencpu.c - m68k emulation generator + * + * Copyright (c) 2009 ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ /* * UAE - The Un*x Amiga Emulator * @@ -14,42 +38,26 @@ * take care of this. * * Copyright 1995, 1996 Bernd Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ +#define CC_FOR_BUILD 1 + +#include "sysdeps.h" +#include "readcpu.h" + #include #include #include #include - -#include "sysdeps.h" -#include "readcpu.h" - -#if defined(SPARC_V8_ASSEMBLY) || defined(SPARC_V9_ASSEMBLY) -#define SPARC_ASSEMBLY 0 -#endif +#include +#undef abort #define BOOL_TYPE "int" - -/* Define the minimal 680x0 where NV flags are not affected by xBCD instructions. */ -#define xBCD_KEEPS_NV_FLAGS 4 +#define VERIFY_MMU_GENAMODE 0 static FILE *headerfile; static FILE *stblfile; +static FILE *functblfile; static int using_prefetch; static int using_exception_3; @@ -65,6 +73,23 @@ static int *opcode_next_clev; static int *opcode_last_postfix; static unsigned long *counts; +#define GENA_GETV_NO_FETCH 0 +#define GENA_GETV_FETCH 1 +#define GENA_GETV_FETCH_ALIGN 2 +#define GENA_MOVEM_DO_INC 0 +#define GENA_MOVEM_NO_INC 1 +#define GENA_MOVEM_MOVE16 2 + +#define XLATE_LOG 0 +#define XLATE_PHYS 1 +#define XLATE_SFC 2 +#define XLATE_DFC 3 +static char * mem_prefix[4] = { "", "phys_", "sfc_", "dfc_" }; + +/* Define the minimal 680x0 where NV flags are not affected by xBCD instructions. */ +#define xBCD_KEEPS_N_FLAG 4 +#define xBCD_KEEPS_V_FLAG 3 + static void read_counts (void) { FILE *file; @@ -75,7 +100,8 @@ static void read_counts (void) file = fopen ("frequent.68k", "r"); if (file) { - fscanf (file, "Total: %lu\n", &total); + int c = fscanf (file, "Total: %lu\n", &total); + assert(c == 1); while (fscanf (file, "%lx: %lu %s\n", &opcode, &count, name) == 3) { opcode_next_clev[nr] = 4; opcode_last_postfix[nr] = -1; @@ -106,7 +132,6 @@ static int need_endlabel; static int n_braces = 0; static int m68k_pc_offset = 0; -static int insn_n_cycles; static void start_brace (void) { @@ -159,9 +184,8 @@ static const char *gen_nextilong (void) { static char buffer[80]; int r = m68k_pc_offset; - m68k_pc_offset += 4; - insn_n_cycles += 4; + m68k_pc_offset += 4; if (using_prefetch) sprintf (buffer, "get_ilong_prefetch(%d)", r); @@ -174,9 +198,8 @@ static const char *gen_nextiword (void) { static char buffer[80]; int r = m68k_pc_offset; - m68k_pc_offset += 2; - insn_n_cycles += 2; + m68k_pc_offset += 2; if (using_prefetch) sprintf (buffer, "get_iword_prefetch(%d)", r); @@ -191,8 +214,6 @@ static const char *gen_nextibyte (void) int r = m68k_pc_offset; m68k_pc_offset += 2; - insn_n_cycles += 2; - if (using_prefetch) sprintf (buffer, "get_ibyte_prefetch(%d)", r); else @@ -214,9 +235,22 @@ static void fill_prefetch_2 (void) static void swap_opcode (void) { - printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); - printf ("\topcode = ((opcode << 8) & 0xFF00) | ((opcode >> 8) & 0xFF);\n"); - printf ("#endif\n"); + printf("#if defined(HAVE_GET_WORD_UNSWAPPED) && !defined(FULLMMU)\n"); + printf ("\topcode = do_byteswap_16(opcode);\n"); + printf("#endif\n"); +} + +static void real_opcode (int *have) +{ + if (!*have) + { + printf("#if defined(HAVE_GET_WORD_UNSWAPPED) && !defined(FULLMMU)\n"); + printf ("\tuae_u32 real_opcode = do_byteswap_16(opcode);\n"); + printf("#else\n"); + printf ("\tuae_u32 real_opcode = opcode;\n"); + printf("#endif\n"); + *have = 1; + } } static void sync_m68k_pc (void) @@ -238,33 +272,49 @@ static void sync_m68k_pc (void) m68k_pc_offset = 0; } +static void gen_set_fault_pc (void) +{ + sync_m68k_pc(); + printf ("regs.fault_pc = m68k_getpc ();\n"); + m68k_pc_offset = 0; +} + /* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0, * the calling routine handles Apdi and Aipi modes. * gb-- movem == 2 means the same thing but for a MOVE16 instruction */ -static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem) + +/* fixup indicates if we want to fix up adress registers in pre decrement + * or post increment mode now (0) or later (1). A value of 2 will then be + * used to do the actual fix up. This allows to do all memory readings + * before any register is modified, and so to rerun operation without + * side effect in case a bus fault is generated by any memory access. + * XJ - 2006/11/13 */ +static void genamode2 (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem, int xlateflag, int fixup) { + if (fixup != 2) + { start_brace (); switch (mode) { case Dreg: if (movem) abort (); - if (getv == 1) + if (getv == GENA_GETV_FETCH) switch (size) { case sz_byte: -#if defined(AMIGA) && !defined(WARPUP) + printf("\n#if defined(AMIGA) && !defined(WARPUP)\n"); /* sam: I don't know why gcc.2.7.2.1 produces a code worse */ /* if it is not done like that: */ printf ("\tuae_s8 %s = ((uae_u8*)&m68k_dreg(regs, %s))[3];\n", name, reg); -#else + printf("#else\n"); printf ("\tuae_s8 %s = m68k_dreg(regs, %s);\n", name, reg); -#endif + printf("#endif\n"); break; case sz_word: -#if defined(AMIGA) && !defined(WARPUP) + printf("\n#if defined(AMIGA) && !defined(WARPUP)\n"); printf ("\tuae_s16 %s = ((uae_s16*)&m68k_dreg(regs, %s))[1];\n", name, reg); -#else + printf("#else\n"); printf ("\tuae_s16 %s = m68k_dreg(regs, %s);\n", name, reg); -#endif + printf("#endif\n"); break; case sz_long: printf ("\tuae_s32 %s = m68k_dreg(regs, %s);\n", name, reg); @@ -276,7 +326,7 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge case Areg: if (movem) abort (); - if (getv == 1) + if (getv == GENA_GETV_FETCH) switch (size) { case sz_word: printf ("\tuae_s16 %s = m68k_areg(regs, %s);\n", name, reg); @@ -303,10 +353,16 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge printf ("\tuaecptr %sa = m68k_areg(regs, %s) - areg_byteinc[%s];\n", name, reg, reg); break; case sz_word: - printf ("\tuaecptr %sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 2); + if (movem) + printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg); + else + printf ("\tuaecptr %sa = m68k_areg(regs, %s) - 2;\n", name, reg); break; case sz_long: - printf ("\tuaecptr %sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 4); + if (movem) + printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg); + else + printf ("\tuaecptr %sa = m68k_areg(regs, %s) - 4;\n", name, reg); break; default: abort (); @@ -351,7 +407,7 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge printf ("\tuaecptr %sa = %s;\n", name, gen_nextilong ()); break; case imm: - if (getv != 1) + if (getv != GENA_GETV_FETCH) abort (); switch (size) { case sz_byte: @@ -368,22 +424,22 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge } return; case imm0: - if (getv != 1) + if (getv != GENA_GETV_FETCH) abort (); printf ("\tuae_s8 %s = %s;\n", name, gen_nextibyte ()); return; case imm1: - if (getv != 1) + if (getv != GENA_GETV_FETCH) abort (); printf ("\tuae_s16 %s = %s;\n", name, gen_nextiword ()); return; case imm2: - if (getv != 1) + if (getv != GENA_GETV_FETCH) abort (); printf ("\tuae_s32 %s = %s;\n", name, gen_nextilong ()); return; case immi: - if (getv != 1) + if (getv != GENA_GETV_FETCH) abort (); printf ("\tuae_u32 %s = %s;\n", name, reg); return; @@ -394,7 +450,7 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge /* We get here for all non-reg non-immediate addressing modes to * actually fetch the value. */ - if (using_exception_3 && getv != 0 && size != sz_byte) { + if (using_exception_3 && getv != GENA_GETV_NO_FETCH && size != sz_byte) { printf ("\tif ((%sa & 1) != 0) {\n", name); printf ("\t\tlast_fault_for_exception_3 = %sa;\n", name); printf ("\t\tlast_op_for_exception_3 = opcode;\n"); @@ -406,20 +462,29 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge start_brace (); } - if (getv == 1) { + if (getv == GENA_GETV_FETCH) { switch (size) { - case sz_byte: insn_n_cycles += 2; break; - case sz_word: insn_n_cycles += 2; break; - case sz_long: insn_n_cycles += 4; break; + case sz_byte: break; + case sz_word: break; + case sz_long: break; default: abort (); } start_brace (); + printf("\n#ifdef FULLMMU\n"); switch (size) { - case sz_byte: printf ("\tuae_s8 %s = get_byte(%sa);\n", name, name); break; - case sz_word: printf ("\tuae_s16 %s = get_word(%sa);\n", name, name); break; - case sz_long: printf ("\tuae_s32 %s = get_long(%sa);\n", name, name); break; + case sz_byte: printf ("\tuae_s8 %s = %sget_byte(%sa);\n", name, mem_prefix[xlateflag], name); break; + case sz_word: printf ("\tuae_s16 %s = %sget_word(%sa);\n", name, mem_prefix[xlateflag], name); break; + case sz_long: printf ("\tuae_s32 %s = %sget_long(%sa);\n", name, mem_prefix[xlateflag], name); break; default: abort (); } + printf("#else\n"); + switch (size) { + case sz_byte: printf ("\tuae_s8 %s = phys_get_byte(%sa);\n", name, name); break; + case sz_word: printf ("\tuae_s16 %s = phys_get_word(%sa);\n", name, name); break; + case sz_long: printf ("\tuae_s32 %s = phys_get_long(%sa);\n", name, name); break; + default: abort (); + } + printf("#endif\n"); } /* We now might have to fix up the register for pre-dec or post-inc @@ -427,6 +492,12 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge if (!movem) switch (mode) { case Aipi: + if (fixup == 1) + { + printf ("\tfixup.flag = 1;\n"); + printf ("\tfixup.reg = %s;\n", reg); + printf ("\tfixup.value = m68k_areg(regs, %s);\n", reg); + } switch (size) { case sz_byte: printf ("\tm68k_areg(regs, %s) += areg_byteinc[%s];\n", reg, reg); @@ -442,14 +513,39 @@ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int ge } break; case Apdi: + if (fixup == 1) + { + printf ("\tfixup.flag = 1;\n"); + printf ("\tfixup.reg = %s;\n", reg); + printf ("\tfixup.value = m68k_areg(regs, %s);\n", reg); + } printf ("\tm68k_areg (regs, %s) = %sa;\n", reg, name); break; default: break; } + + } + else /* (fixup != 2) */ + { + if (!movem) + switch (mode) { + case Aipi: + case Apdi: + printf ("\tfixup.flag = 0;\n"); + break; + default: + break; + } + } } -static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to) +static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem, int xlateflag) +{ + genamode2 (mode, reg, size, name, getv, movem, xlateflag, 0); +} + +static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to, int xlateflag) { switch (mode) { case Dreg: @@ -489,28 +585,32 @@ static void genastore (char *from, amodes mode, char *reg, wordsizes size, char case absl: case PC16: case PC8r: - if (using_prefetch) - sync_m68k_pc (); + gen_set_fault_pc (); + printf("#ifdef FULLMMU\n"); switch (size) { case sz_byte: - insn_n_cycles += 2; + printf ("\t%sput_byte(%sa,%s);\n", mem_prefix[xlateflag], to, from); + printf("#else\n"); printf ("\tput_byte(%sa,%s);\n", to, from); break; case sz_word: - insn_n_cycles += 2; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) abort (); + printf ("\t%sput_word(%sa,%s);\n", mem_prefix[xlateflag], to, from); + printf("#else\n"); printf ("\tput_word(%sa,%s);\n", to, from); break; case sz_long: - insn_n_cycles += 4; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) abort (); + printf ("\t%sput_long(%sa,%s);\n", mem_prefix[xlateflag], to, from); + printf("#else\n"); printf ("\tput_long(%sa,%s);\n", to, from); break; default: abort (); } + printf("#endif\n"); break; case imm: case imm0: @@ -526,23 +626,33 @@ static void genastore (char *from, amodes mode, char *reg, wordsizes size, char static void genmovemel (uae_u16 opcode) { - char getcode[100]; + char getcode1[100]; + char getcode2[100]; int size = table68k[opcode].size == sz_long ? 4 : 2; - + if (table68k[opcode].size == sz_long) { - strcpy (getcode, "get_long(srca)"); + strcpy (getcode1, ""); + strcpy (getcode2, "get_long(srca)"); } else { - strcpy (getcode, "(uae_s32)(uae_s16)get_word(srca)"); + strcpy (getcode1, "(uae_s32)(uae_s16)"); + strcpy (getcode2, "get_word(srca)"); } printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); printf ("\tunsigned int dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); - genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); + genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_NO_INC, XLATE_LOG); start_brace (); - printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s; srca += %d; dmask = movem_next[dmask]; }\n", - getcode, size); - printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s; srca += %d; amask = movem_next[amask]; }\n", - getcode, size); + printf("\n#ifdef FULLMMU\n"); + printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s%s; srca += %d; dmask = movem_next[dmask]; }\n", + getcode1, getcode2, size); + printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s%s; srca += %d; amask = movem_next[amask]; }\n", + getcode1, getcode2, size); + printf("#else\n"); + printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %sphys_%s; srca += %d; dmask = movem_next[dmask]; }\n", + getcode1, getcode2, size); + printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %sphys_%s; srca += %d; amask = movem_next[amask]; }\n", + getcode1, getcode2, size); + printf("#endif\n"); if (table68k[opcode].dmode == Aipi) printf ("\tm68k_areg(regs, dstreg) = srca;\n"); @@ -552,6 +662,7 @@ static void genmovemle (uae_u16 opcode) { char putcode[100]; int size = table68k[opcode].size == sz_long ? 4 : 2; + if (table68k[opcode].size == sz_long) { strcpy (putcode, "put_long(srca,"); } else { @@ -559,24 +670,38 @@ static void genmovemle (uae_u16 opcode) } printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); - genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); - if (using_prefetch) - sync_m68k_pc (); + genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", + GENA_GETV_FETCH_ALIGN, GENA_MOVEM_NO_INC, XLATE_LOG); + sync_m68k_pc (); start_brace (); if (table68k[opcode].dmode == Apdi) { printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n"); + printf("#ifdef FULLMMU\n"); printf ("\twhile (amask) { srca -= %d; %s m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n", size, putcode); printf ("\twhile (dmask) { srca -= %d; %s m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n", size, putcode); + printf("#else\n"); + printf ("\twhile (amask) { srca -= %d; phys_%s m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n", + size, putcode); + printf ("\twhile (dmask) { srca -= %d; phys_%s m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n", + size, putcode); + printf("#endif\n"); printf ("\tm68k_areg(regs, dstreg) = srca;\n"); } else { printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); + printf("#ifdef FULLMMU\n"); printf ("\twhile (dmask) { %s m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n", putcode, size); printf ("\twhile (amask) { %s m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n", putcode, size); + printf("#else\n"); + printf ("\twhile (dmask) { phys_%s m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n", + putcode, size); + printf ("\twhile (amask) { phys_%s m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n", + putcode, size); + printf("#endif\n"); } } @@ -649,12 +774,10 @@ static void genflags_normal (flagtypes type, wordsizes size, char *value, char * break; case flag_add: - start_brace (); printf ("uae_u32 %s = %s + %s;\n", value, dstr, sstr); break; case flag_sub: case flag_cmp: - start_brace (); printf ("uae_u32 %s = %s - %s;\n", value, dstr, sstr); break; } @@ -673,7 +796,6 @@ static void genflags_normal (flagtypes type, wordsizes size, char *value, char * case flag_cmp: case flag_av: case flag_sv: - start_brace (); printf ("\t" BOOL_TYPE " flgs = %s < 0;\n", sstr); printf ("\t" BOOL_TYPE " flgo = %s < 0;\n", dstr); printf ("\t" BOOL_TYPE " flgn = %s < 0;\n", vstr); @@ -697,10 +819,10 @@ static void genflags_normal (flagtypes type, wordsizes size, char *value, char * printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); break; case flag_z: - printf ("\tSET_ZFLG (GET_ZFLG() & (%s == 0));\n", vstr); + printf ("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); break; case flag_zn: - printf ("\tSET_ZFLG (GET_ZFLG() & (%s == 0));\n", vstr); + printf ("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); printf ("\tSET_NFLG (%s < 0);\n", vstr); break; case flag_add: @@ -741,11 +863,13 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch /* Temporarily deleted 68k/ARM flag optimizations. I'd prefer to have them in the appropriate m68k.h files and use just one copy of this code here. The API can be changed if necessary. */ -#ifdef OPTIMIZED_FLAGS + int done = 0; + + start_brace (); + printf("\n#ifdef OPTIMIZED_FLAGS\n"); switch (type) { case flag_add: case flag_sub: - start_brace (); printf ("\tuae_u32 %s;\n", value); break; default: @@ -755,7 +879,7 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch /* At least some of those casts are fairly important! */ switch (type) { case flag_logical_noclobber: - printf ("\t{uae_u32 oldcznv = GET_CZNV & ~(FLAGVAL_Z | FLAGVAL_N);\n"); + printf ("\t{uae_u32 oldcznv = GET_CZNV() & ~(FLAGVAL_Z | FLAGVAL_N);\n"); if (strcmp (value, "0") == 0) { printf ("\tSET_CZNV (olcznv | FLAGVAL_Z);\n"); } else { @@ -767,8 +891,9 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch printf ("\tIOR_CZNV (oldcznv);\n"); } printf ("\t}\n"); - return; - + done = 1; + break; + case flag_logical: if (strcmp (value, "0") == 0) { printf ("\tSET_CZNV (FLAGVAL_Z);\n"); @@ -779,7 +904,8 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch case sz_long: printf ("\toptflag_testl ((uae_s32)(%s));\n", value); break; } } - return; + done = 1; + break; case flag_add: switch (size) { @@ -787,7 +913,8 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch case sz_word: printf ("\toptflag_addw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; case sz_long: printf ("\toptflag_addl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; } - return; + done = 1; + break; case flag_sub: switch (size) { @@ -795,7 +922,8 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch case sz_word: printf ("\toptflag_subw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; case sz_long: printf ("\toptflag_subl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; } - return; + done = 1; + break; case flag_cmp: switch (size) { @@ -803,13 +931,19 @@ static void genflags (flagtypes type, wordsizes size, char *value, char *src, ch case sz_word: printf ("\toptflag_cmpw ((uae_s16)(%s), (uae_s16)(%s));\n", src, dst); break; case sz_long: printf ("\toptflag_cmpl ((uae_s32)(%s), (uae_s32)(%s));\n", src, dst); break; } - return; + done = 1; + break; default: break; } -#endif + if (done) + printf("#else\n"); + else + printf("#endif\n"); genflags_normal (type, size, value, src, dst); + if (done) + printf("#endif\n"); } static void force_range_for_rox (const char *var, wordsizes size) @@ -837,7 +971,7 @@ static const char *cmask (wordsizes size) case sz_byte: return "0x80"; case sz_word: return "0x8000"; case sz_long: return "0x80000000"; - default: abort (); + default: abort (); return NULL; } } @@ -849,11 +983,10 @@ static int source_is_imm1_8 (struct instr *i) static void gen_opcode (unsigned long int opcode) { struct instr *curi = table68k + opcode; - insn_n_cycles = 2; start_brace (); #if 0 - printf ("uae_u8 *m68k_pc = regs.pc_p;\n"); + printf ("uae_u8 *m68k_pc = m68k_getpc();\n"); #endif m68k_pc_offset = 2; switch (curi->plev) { @@ -883,16 +1016,16 @@ static void gen_opcode (unsigned long int opcode) case i_OR: case i_AND: case i_EOR: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tsrc %c= dst;\n", curi->mnemo == i_OR ? '|' : curi->mnemo == i_AND ? '&' : '^'); genflags (flag_logical, curi->size, "src", "", ""); - genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("src", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_ORSR: case i_EORSR: printf ("\tMakeSR();\n"); - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) { printf ("\tsrc &= 0xFF;\n"); } @@ -901,7 +1034,7 @@ static void gen_opcode (unsigned long int opcode) break; case i_ANDSR: printf ("\tMakeSR();\n"); - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) { printf ("\tsrc |= 0xFF00;\n"); } @@ -909,81 +1042,89 @@ static void gen_opcode (unsigned long int opcode) printf ("\tMakeFromSR();\n"); break; case i_SUB: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); genflags (flag_sub, curi->size, "newv", "src", "dst"); - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_SUBA: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 newv = dst - src;\n"); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); break; case i_SUBX: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); start_brace (); - printf ("\tuae_u32 newv = dst - src - (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u32 newv = dst - src - (GET_XFLG () ? 1 : 0);\n"); genflags (flag_subx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_SBCD: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); start_brace (); - printf ("\tuae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG () ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (dst & 0xF0) - (src & 0xF0);\n"); printf ("\tuae_u16 newv, tmp_newv;\n"); printf ("\tint bcd = 0;\n"); printf ("\tnewv = tmp_newv = newv_hi + newv_lo;\n"); printf ("\tif (newv_lo & 0xF0) { newv -= 6; bcd = 6; };\n"); - printf ("\tif ((((dst & 0xFF) - (src & 0xFF) - (GET_XFLG() ? 1 : 0)) & 0x100) > 0xFF) { newv -= 0x60; }\n"); - printf ("\tSET_CFLG ((((dst & 0xFF) - (src & 0xFF) - bcd - (GET_XFLG() ? 1 : 0)) & 0x300) > 0xFF);\n"); + printf ("\tif ((((dst & 0xFF) - (src & 0xFF) - (GET_XFLG () ? 1 : 0)) & 0x100) > 0xFF) { newv -= 0x60; }\n"); + printf ("\tSET_CFLG ((((dst & 0xFF) - (src & 0xFF) - bcd - (GET_XFLG () ? 1 : 0)) & 0x300) > 0xFF);\n"); duplicate_carry (); - /* Manual says bits NV are undefined though a real 68040 don't change them */ - if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { - if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) - next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; - genflags (flag_z, curi->size, "newv", "", ""); + /* Manual says bits NV are undefined though a real 68030 doesn't change V and 68040/060 don't change both */ + if (cpu_level >= xBCD_KEEPS_N_FLAG) { + if (next_cpu_level < xBCD_KEEPS_N_FLAG) + next_cpu_level = xBCD_KEEPS_N_FLAG - 1; + genflags (flag_z, curi->size, "newv", "", ""); + } else { + genflags (flag_zn, curi->size, "newv", "", ""); } - else { - genflags (flag_zn, curi->size, "newv", "", ""); - printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n"); + if (cpu_level >= xBCD_KEEPS_V_FLAG) { + if (next_cpu_level < xBCD_KEEPS_V_FLAG) + next_cpu_level = xBCD_KEEPS_V_FLAG - 1; + } else { + printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n"); } - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_ADD: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); genflags (flag_add, curi->size, "newv", "src", "dst"); - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_ADDA: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 newv = dst + src;\n"); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); break; case i_ADDX: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); start_brace (); - printf ("\tuae_u32 newv = dst + src + (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u32 newv = dst + src + (GET_XFLG () ? 1 : 0);\n"); genflags (flag_addx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_ABCD: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); start_brace (); - printf ("\tuae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG () ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (src & 0xF0) + (dst & 0xF0);\n"); printf ("\tuae_u16 newv, tmp_newv;\n"); printf ("\tint cflg;\n"); @@ -993,75 +1134,85 @@ static void gen_opcode (unsigned long int opcode) printf ("\tif (cflg) newv += 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry (); - /* Manual says bits NV are undefined though a real 68040 don't change them */ - if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { - if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) - next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; - genflags (flag_z, curi->size, "newv", "", ""); + /* Manual says bits NV are undefined though a real 68030 doesn't change V and 68040/060 don't change both */ + if (cpu_level >= xBCD_KEEPS_N_FLAG) { + if (next_cpu_level < xBCD_KEEPS_N_FLAG) + next_cpu_level = xBCD_KEEPS_N_FLAG - 1; + genflags (flag_z, curi->size, "newv", "", ""); + } else { + genflags (flag_zn, curi->size, "newv", "", ""); } - else { - genflags (flag_zn, curi->size, "newv", "", ""); - printf ("\tSET_VFLG ((tmp_newv & 0x80) == 0 && (newv & 0x80) != 0);\n"); + if (cpu_level >= xBCD_KEEPS_V_FLAG) { + if (next_cpu_level < xBCD_KEEPS_V_FLAG) + next_cpu_level = xBCD_KEEPS_V_FLAG - 1; + } else { + printf ("\tSET_VFLG ((tmp_newv & 0x80) == 0 && (newv & 0x80) != 0);\n"); } - genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("newv", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_NEG: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); genflags (flag_sub, curi->size, "dst", "src", "0"); - genastore ("dst", curi->smode, "srcreg", curi->size, "src"); + genastore ("dst", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_NEGX: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); - printf ("\tuae_u32 newv = 0 - src - (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u32 newv = 0 - src - (GET_XFLG () ? 1 : 0);\n"); genflags (flag_subx, curi->size, "newv", "src", "0"); genflags (flag_zn, curi->size, "newv", "", ""); - genastore ("newv", curi->smode, "srcreg", curi->size, "src"); + genastore ("newv", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_NBCD: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); - printf ("\tuae_u16 newv_lo = - (src & 0xF) - (GET_XFLG() ? 1 : 0);\n"); + printf ("\tuae_u16 newv_lo = - (src & 0xF) - (GET_XFLG () ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = - (src & 0xF0);\n"); printf ("\tuae_u16 newv;\n"); - printf ("\tint cflg;\n"); + printf ("\tint cflg, tmp_newv;\n"); + printf ("\ttmp_newv = newv_hi + newv_lo;\n"); printf ("\tif (newv_lo > 9) { newv_lo -= 6; }\n"); printf ("\tnewv = newv_hi + newv_lo;\n"); printf ("\tcflg = (newv & 0x1F0) > 0x90;\n"); printf ("\tif (cflg) newv -= 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry(); - /* Manual says bits NV are undefined though a real 68040 don't change them */ - if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { - if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) - next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; - genflags (flag_z, curi->size, "newv", "", ""); + /* Manual says bits NV are undefined though a real 68030 doesn't change V and 68040/060 don't change both */ + if (cpu_level >= xBCD_KEEPS_N_FLAG) { + if (next_cpu_level < xBCD_KEEPS_N_FLAG) + next_cpu_level = xBCD_KEEPS_N_FLAG - 1; + genflags (flag_z, curi->size, "newv", "", ""); + } else { + genflags (flag_zn, curi->size, "newv", "", ""); } - else { - genflags (flag_zn, curi->size, "newv", "", ""); + if (cpu_level >= xBCD_KEEPS_V_FLAG) { + if (next_cpu_level < xBCD_KEEPS_V_FLAG) + next_cpu_level = xBCD_KEEPS_V_FLAG - 1; + } else { + printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n"); } - genastore ("newv", curi->smode, "srcreg", curi->size, "src"); + genastore ("newv", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_CLR: - genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); genflags (flag_logical, curi->size, "0", "", ""); - genastore ("0", curi->smode, "srcreg", curi->size, "src"); + genastore ("0", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_NOT: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 dst = ~src;\n"); genflags (flag_logical, curi->size, "dst", "", ""); - genastore ("dst", curi->smode, "srcreg", curi->size, "src"); + genastore ("dst", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_TST: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); genflags (flag_logical, curi->size, "src", "", ""); break; case i_BTST: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else @@ -1069,55 +1220,55 @@ static void gen_opcode (unsigned long int opcode) printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); break; case i_BCHG: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tdst ^= (1 << src);\n"); printf ("\tSET_ZFLG (((uae_u32)dst & (1 << src)) >> src);\n"); - genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("dst", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_BCLR: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst &= ~(1 << src);\n"); - genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("dst", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_BSET: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst |= (1 << src);\n"); - genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("dst", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_CMPM: case i_CMP: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); genflags (flag_cmp, curi->size, "newv", "src", "dst"); break; case i_CMPA: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); genflags (flag_cmp, sz_long, "newv", "src", "dst"); break; /* The next two are coded a little unconventional, but they are doing * weird things... */ case i_MVPRM: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tuaecptr memp = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); if (curi->size == sz_word) { @@ -1129,41 +1280,45 @@ static void gen_opcode (unsigned long int opcode) break; case i_MVPMR: printf ("\tuaecptr memp = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_word) { - printf ("\tuae_u16 val = (get_byte(memp) << 8) + get_byte(memp + 2);\n"); + printf ("\tuae_u16 val = get_byte(memp) << 8;\n"); + printf ("\t val |= get_byte(memp + 2);\n"); } else { - printf ("\tuae_u32 val = (get_byte(memp) << 24) + (get_byte(memp + 2) << 16)\n"); - printf (" + (get_byte(memp + 4) << 8) + get_byte(memp + 6);\n"); + printf ("\tuae_u32 val = get_byte(memp) << 24;\n"); + printf ("\t val |= get_byte(memp + 2) << 16;\n"); + printf ("\t val |= get_byte(memp + 4) << 8;\n"); + printf ("\t val |= get_byte(memp + 6);\n"); } - genastore ("val", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("val", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_MOVE: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); genflags (flag_logical, curi->size, "src", "", ""); - genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("src", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_MOVEA: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_word) { printf ("\tuae_u32 val = (uae_s32)(uae_s16)src;\n"); } else { printf ("\tuae_u32 val = src;\n"); } - genastore ("val", curi->dmode, "dstreg", sz_long, "dst"); + genastore ("val", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); break; case i_MVSR2: - genamode (curi->smode, "srcreg", sz_word, "src", 2, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tMakeSR();\n"); if (curi->size == sz_byte) - genastore ("regs.sr & 0xff", curi->smode, "srcreg", sz_word, "src"); + genastore ("regs.sr & 0xff", curi->smode, "srcreg", sz_word, "src", XLATE_LOG); else - genastore ("regs.sr", curi->smode, "srcreg", sz_word, "src"); + genastore ("regs.sr", curi->smode, "srcreg", sz_word, "src", XLATE_LOG); break; case i_MV2SR: - genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); if (curi->size == sz_byte) printf ("\tMakeSR();\n\tregs.sr &= 0xFF00;\n\tregs.sr |= src & 0xFF;\n"); else { @@ -1172,66 +1327,84 @@ static void gen_opcode (unsigned long int opcode) printf ("\tMakeFromSR();\n"); break; case i_SWAP: - genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); + genamode (curi->smode, "srcreg", sz_long, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 dst = ((src >> 16)&0xFFFF) | ((src&0xFFFF)<<16);\n"); genflags (flag_logical, sz_long, "dst", "", ""); - genastore ("dst", curi->smode, "srcreg", sz_long, "src"); + genastore ("dst", curi->smode, "srcreg", sz_long, "src", XLATE_LOG); break; case i_EXG: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); - genastore ("dst", curi->smode, "srcreg", curi->size, "src"); - genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("dst", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); + genastore ("src", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_EXT: - genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); + genamode (curi->smode, "srcreg", sz_long, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { - case sz_byte: printf ("\tuae_u32 dst = (uae_s32)(uae_s8)src;\n"); break; - case sz_word: printf ("\tuae_u16 dst = (uae_s16)(uae_s8)src;\n"); break; - case sz_long: printf ("\tuae_u32 dst = (uae_s32)(uae_s16)src;\n"); break; - default: abort (); + case sz_byte: printf ("\tuae_u32 dst = (uae_s32)(uae_s8)src;\n"); break; + case sz_word: printf ("\tuae_u16 dst = (uae_s16)(uae_s8)src;\n"); break; + case sz_long: printf ("\tuae_u32 dst = (uae_s32)(uae_s16)src;\n"); break; + default: abort (); } genflags (flag_logical, curi->size == sz_word ? sz_word : sz_long, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", - curi->size == sz_word ? sz_word : sz_long, "src"); + curi->size == sz_word ? sz_word : sz_long, "src", XLATE_LOG); break; case i_MVMEL: - genmovemel ((uae_u16)opcode); + genmovemel (opcode); break; case i_MVMLE: - genmovemle ((uae_u16)opcode); + genmovemle (opcode); break; case i_TRAP: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - sync_m68k_pc (); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + gen_set_fault_pc (); printf ("\tException(src+32,0);\n"); - m68k_pc_offset = 0; break; case i_MVR2USP: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tregs.usp = src;\n"); break; case i_MVUSP2R: - genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); - genastore ("regs.usp", curi->smode, "srcreg", curi->size, "src"); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("regs.usp", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_RESET: + printf ("\tAtariReset();\n"); break; case i_NOP: break; case i_STOP: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - printf ("\tregs.sr = src;\n"); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + /* + * STOP undocumented features: + * if SR is not set: + * 68000 (68010?): Update SR, increase PC and then cause privilege violation exception (handled in newcpu) + * 68000 (68010?): Traced STOP also runs 4 cycles faster. + * 68020 68030: STOP works normally + * 68040 68060: Immediate privilege violation exception + */ + printf ("\tuae_u16 sr = src;\n"); + if (cpu_level >= 4) { + printf("\tif (!(sr & 0x2000)) {\n"); + printf ("m68k_incpc(%d);\n", m68k_pc_offset); + printf("\t\tException(8,0); goto %s;\n", endlabelstr); + printf("\t}\n"); + } + printf("\tregs.sr = sr;\n"); printf ("\tMakeFromSR();\n"); printf ("\tm68k_setstopped(1);\n"); + sync_m68k_pc (); + /* STOP does not prefetch anything */ + /* did_prefetch = -1; */ break; case i_RTE: if (cpu_level == 0) { - genamode (Aipi, "7", sz_word, "sr", 1, 0); - genamode (Aipi, "7", sz_long, "pc", 1, 0); + genamode (Aipi, "7", sz_word, "sr", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Aipi, "7", sz_long, "pc", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tregs.sr = sr; m68k_setpc_rte(pc);\n"); fill_prefetch_0 (); printf ("\tMakeFromSR();\n"); @@ -1240,15 +1413,14 @@ static void gen_opcode (unsigned long int opcode) if (next_cpu_level < 0) next_cpu_level = 0; printf ("\tuae_u16 newsr; uae_u32 newpc; for (;;) {\n"); - genamode (Aipi, "7", sz_word, "sr", 1, 0); - genamode (Aipi, "7", sz_long, "pc", 1, 0); - genamode (Aipi, "7", sz_word, "format", 1, 0); + genamode (Aipi, "7", sz_word, "sr", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Aipi, "7", sz_long, "pc", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Aipi, "7", sz_word, "format", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tnewsr = sr; newpc = pc;\n"); printf ("\tif ((format & 0xF000) == 0x0000) { break; }\n"); printf ("\telse if ((format & 0xF000) == 0x1000) { ; }\n"); printf ("\telse if ((format & 0xF000) == 0x2000) { m68k_areg(regs, 7) += 4; break; }\n"); - /* gb-- the next two lines are deleted in Bernie's gencpu.c */ - printf ("\telse if ((format & 0xF000) == 0x3000) { m68k_areg(regs, 7) += 4; break; }\n"); +// printf ("\telse if ((format & 0xF000) == 0x3000) { m68k_areg(regs, 7) += 4; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x7000) { m68k_areg(regs, 7) += 52; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x8000) { m68k_areg(regs, 7) += 50; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x9000) { m68k_areg(regs, 7) += 12; break; }\n"); @@ -1266,8 +1438,8 @@ static void gen_opcode (unsigned long int opcode) m68k_pc_offset = 0; break; case i_RTD: - genamode (Aipi, "7", sz_long, "pc", 1, 0); - genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "offs", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Aipi, "7", sz_long, "pc", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tm68k_areg(regs, 7) += offs;\n"); printf ("\tm68k_setpc_rte(pc);\n"); fill_prefetch_0 (); @@ -1275,18 +1447,18 @@ static void gen_opcode (unsigned long int opcode) m68k_pc_offset = 0; break; case i_LINK: - genamode (Apdi, "7", sz_long, "old", 2, 0); - genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); - genastore ("src", Apdi, "7", sz_long, "old"); - genastore ("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src"); - genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); + genamode (curi->dmode, "dstreg", curi->size, "offs", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Apdi, "7", sz_long, "old", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->smode, "srcreg", sz_long, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src", XLATE_LOG); printf ("\tm68k_areg(regs, 7) += offs;\n"); + genastore ("src", Apdi, "7", sz_long, "old", XLATE_LOG); break; case i_UNLK: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tm68k_areg(regs, 7) = src;\n"); - genamode (Aipi, "7", sz_long, "old", 1, 0); - genastore ("old", curi->smode, "srcreg", curi->size, "src"); + genamode (Aipi, "7", sz_long, "old", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("old", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_RTS: printf ("\tm68k_do_rts();\n"); @@ -1294,14 +1466,16 @@ static void gen_opcode (unsigned long int opcode) m68k_pc_offset = 0; break; case i_TRAPV: + printf ("\tuaecptr oldpc = m68k_getpc();\n"); sync_m68k_pc (); - printf ("\tif (GET_VFLG()) { Exception(7,m68k_getpc()); goto %s; }\n", endlabelstr); + printf ("\tif (GET_VFLG ()) { Exception(7,oldpc); goto %s; }\n", endlabelstr); need_endlabel = 1; break; case i_RTR: printf ("\tMakeSR();\n"); - genamode (Aipi, "7", sz_word, "sr", 1, 0); - genamode (Aipi, "7", sz_long, "pc", 1, 0); + genamode2 (Aipi, "7", sz_word, "sr", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 1); + genamode (Aipi, "7", sz_long, "pc", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode2 (Aipi, "7", sz_word, "sr", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG, 2); printf ("\tregs.sr &= 0xFF00; sr &= 0xFF;\n"); printf ("\tregs.sr |= sr; m68k_setpc(pc);\n"); fill_prefetch_0 (); @@ -1309,19 +1483,19 @@ static void gen_opcode (unsigned long int opcode) m68k_pc_offset = 0; break; case i_JSR: - genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_NO_FETCH, GENA_MOVEM_DO_INC, XLATE_PHYS); printf ("\tm68k_do_jsr(m68k_getpc() + %d, srca);\n", m68k_pc_offset); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_JMP: - genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_NO_FETCH, GENA_MOVEM_DO_INC, XLATE_PHYS); printf ("\tm68k_setpc(srca);\n"); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_BSR: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_PHYS); printf ("\tuae_s32 s = (uae_s32)src + 2;\n"); if (using_exception_3) { printf ("\tif (src & 1) {\n"); @@ -1336,18 +1510,6 @@ static void gen_opcode (unsigned long int opcode) m68k_pc_offset = 0; break; case i_Bcc: - if (0 && !using_prefetch && !using_exception_3 && (cpu_level >= 2)) { - /* gb-- variant probably more favorable to compiler optimizations - also assumes no prefetch buffer is used - Hmm, that would make sense with processors capable of conditional moves */ - if (curi->size == sz_long && next_cpu_level < 1) - next_cpu_level = 1; - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - printf ("\tm68k_incpc (cctrue(%d) ? ((uae_s32)src + 2) : %d);\n", curi->cc, m68k_pc_offset); - m68k_pc_offset = 0; - } - else { - /* original code for branch instructions */ if (curi->size == sz_long) { if (cpu_level < 2) { printf ("\tm68k_incpc(2);\n"); @@ -1361,8 +1523,8 @@ static void gen_opcode (unsigned long int opcode) next_cpu_level = 1; } } - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - printf ("\tif (!cctrue(%d)) goto didnt_jump;\n", curi->cc); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_PHYS); + printf ("\tif (!cctrue(%d)) goto didnt_jump_%lx;\n", curi->cc, opcode); if (using_exception_3) { printf ("\tif (src & 1) {\n"); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); @@ -1374,26 +1536,25 @@ static void gen_opcode (unsigned long int opcode) printf ("\tm68k_incpc ((uae_s32)src + 2);\n"); fill_prefetch_0 (); printf ("return;\n"); - printf ("didnt_jump:;\n"); + printf ("didnt_jump_%lx:;\n", opcode); need_endlabel = 1; - } break; case i_LEA: - genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); - genastore ("srca", curi->dmode, "dstreg", curi->size, "dst"); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_NO_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("srca", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); break; case i_PEA: - genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); - genamode (Apdi, "7", sz_long, "dst", 2, 0); - genastore ("srca", Apdi, "7", sz_long, "dst"); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_NO_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (Apdi, "7", sz_long, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); + genastore ("srca", Apdi, "7", sz_long, "dst", XLATE_LOG); break; case i_DBcc: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "offs", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tif (!cctrue(%d)) {\n", curi->cc); - genastore ("(src-1)", curi->smode, "srcreg", curi->size, "src"); + genastore ("(src-1)", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); printf ("\t\tif (src) {\n"); if (using_exception_3) { @@ -1412,15 +1573,15 @@ static void gen_opcode (unsigned long int opcode) need_endlabel = 1; break; case i_Scc: - genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tint val = cctrue(%d) ? 0xff : 0;\n", curi->cc); - genastore ("val", curi->smode, "srcreg", curi->size, "src"); + genastore ("val", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_DIVU: printf ("\tuaecptr oldpc = m68k_getpc();\n"); - genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); /* Clear V flag when dividing by zero - Alcatraz Odyssey demo depends * on this (actually, it's doing a DIVS). */ @@ -1432,16 +1593,15 @@ static void gen_opcode (unsigned long int opcode) printf ("\tif (newv > 0xffff) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else\n\t{\n"); genflags (flag_logical, sz_word, "newv", "", ""); printf ("\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n"); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); printf ("\t}\n"); printf ("\t}\n"); - insn_n_cycles += 68; need_endlabel = 1; break; case i_DIVS: printf ("\tuaecptr oldpc = m68k_getpc();\n"); - genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); printf ("\tif (src == 0) { SET_VFLG (0); Exception(5,oldpc); goto %s; } else {\n", endlabelstr); printf ("\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n"); @@ -1450,34 +1610,31 @@ static void gen_opcode (unsigned long int opcode) printf ("\tif (((uae_s16)rem < 0) != ((uae_s32)dst < 0)) rem = -rem;\n"); genflags (flag_logical, sz_word, "newv", "", ""); printf ("\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n"); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); printf ("\t}\n"); printf ("\t}\n"); - insn_n_cycles += 72; need_endlabel = 1; break; case i_MULU: - genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_word, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 newv = (uae_u32)(uae_u16)dst * (uae_u32)(uae_u16)src;\n"); genflags (flag_logical, sz_long, "newv", "", ""); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); - insn_n_cycles += 32; + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); break; case i_MULS: - genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); - genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); + genamode (curi->smode, "srcreg", sz_word, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_word, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tuae_u32 newv = (uae_s32)(uae_s16)dst * (uae_s32)(uae_s16)src;\n"); genflags (flag_logical, sz_long, "newv", "", ""); - genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); - insn_n_cycles += 32; + genastore ("newv", curi->dmode, "dstreg", sz_long, "dst", XLATE_LOG); break; case i_CHK: printf ("\tuaecptr oldpc = m68k_getpc();\n"); - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tif ((uae_s32)dst < 0) { SET_NFLG (1); Exception(6,oldpc); goto %s; }\n", endlabelstr); printf ("\telse if (dst > src) { SET_NFLG (0); Exception(6,oldpc); goto %s; }\n", endlabelstr); need_endlabel = 1; @@ -1485,8 +1642,8 @@ static void gen_opcode (unsigned long int opcode) case i_CHK2: printf ("\tuaecptr oldpc = m68k_getpc();\n"); - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\t{uae_s32 upper,lower,reg = regs.regs[(extra >> 12) & 15];\n"); switch (curi->size) { case sz_byte: @@ -1505,13 +1662,13 @@ static void gen_opcode (unsigned long int opcode) } printf ("\tSET_ZFLG (upper == reg || lower == reg);\n"); printf ("\tSET_CFLG_ALWAYS (lower <= upper ? reg < lower || reg > upper : reg > upper || reg < lower);\n"); - printf ("\tif ((extra & 0x800) && GET_CFLG()) { Exception(6,oldpc); goto %s; }\n}\n", endlabelstr); + printf ("\tif ((extra & 0x800) && GET_CFLG ()) { Exception(6,oldpc); goto %s; }\n}\n", endlabelstr); need_endlabel = 1; break; case i_ASR: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1523,7 +1680,7 @@ static void gen_opcode (unsigned long int opcode) printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV();\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); - printf ("\t\tval = %s & (uae_u32)-(uae_s32)sign;\n", bit_mask (curi->size)); + printf ("\t\tval = %s & (uae_u32)-sign;\n", bit_mask (curi->size)); printf ("\t\tSET_CFLG (sign);\n"); duplicate_carry (); if (source_is_imm1_8 (curi)) @@ -1534,17 +1691,17 @@ static void gen_opcode (unsigned long int opcode) printf ("\t\tSET_CFLG (val & 1);\n"); duplicate_carry (); printf ("\t\tval >>= 1;\n"); - printf ("\t\tval |= (%s << (%d - cnt)) & (uae_u32)-(uae_s32)sign;\n", + printf ("\t\tval |= (%s << (%d - cnt)) & (uae_u32)-sign;\n", bit_mask (curi->size), bit_size (curi->size)); printf ("\t\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ASL: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1576,11 +1733,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\t\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_LSR: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1605,11 +1762,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\t\tval >>= 1;\n"); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_LSL: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1635,11 +1792,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ROL: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1662,11 +1819,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tSET_CFLG (val & 1);\n"); printf ("}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ROR: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1689,11 +1846,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ROXL: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1713,17 +1870,17 @@ static void gen_opcode (unsigned long int opcode) printf ("\t{\n\tuae_u32 carry;\n"); printf ("\tuae_u32 loval = val >> (%d - cnt);\n", bit_size (curi->size) - 1); printf ("\tcarry = loval & 1;\n"); - printf ("\tval = (((val << 1) | GET_XFLG()) << cnt) | (loval >> 1);\n"); + printf ("\tval = (((val << 1) | GET_XFLG ()) << cnt) | (loval >> 1);\n"); printf ("\tSET_XFLG (carry);\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t} }\n"); - printf ("\tSET_CFLG (GET_XFLG());\n"); + printf ("\tSET_CFLG (GET_XFLG ());\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ROXR: - genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "cnt", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1741,7 +1898,7 @@ static void gen_opcode (unsigned long int opcode) } printf ("\tcnt--;\n"); printf ("\t{\n\tuae_u32 carry;\n"); - printf ("\tuae_u32 hival = (val << 1) | GET_XFLG();\n"); + printf ("\tuae_u32 hival = (val << 1) | GET_XFLG ();\n"); printf ("\thival <<= (%d - cnt);\n", bit_size (curi->size) - 1); printf ("\tval >>= cnt;\n"); printf ("\tcarry = val & 1;\n"); @@ -1750,12 +1907,12 @@ static void gen_opcode (unsigned long int opcode) printf ("\tSET_XFLG (carry);\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t} }\n"); - printf ("\tSET_CFLG (GET_XFLG());\n"); + printf ("\tSET_CFLG (GET_XFLG ());\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); - genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + genastore ("val", curi->dmode, "dstreg", curi->size, "data", XLATE_LOG); break; case i_ASRW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1769,10 +1926,10 @@ static void gen_opcode (unsigned long int opcode) genflags (flag_logical, curi->size, "val", "", ""); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry (); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_ASLW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1788,11 +1945,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tSET_CFLG (sign != 0);\n"); duplicate_carry (); - printf ("\tSET_VFLG (GET_VFLG() | (sign2 != sign));\n"); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + printf ("\tSET_VFLG (GET_VFLG () | (sign2 != sign));\n"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_LSRW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; @@ -1805,10 +1962,10 @@ static void gen_opcode (unsigned long int opcode) genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); duplicate_carry (); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_LSLW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; @@ -1821,10 +1978,10 @@ static void gen_opcode (unsigned long int opcode) genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_ROLW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; @@ -1837,10 +1994,10 @@ static void gen_opcode (unsigned long int opcode) printf ("\tif (carry) val |= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_RORW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; @@ -1853,10 +2010,10 @@ static void gen_opcode (unsigned long int opcode) printf ("\tif (carry) val |= %s;\n", cmask (curi->size)); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_ROXLW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; @@ -1866,14 +2023,14 @@ static void gen_opcode (unsigned long int opcode) } printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size)); printf ("\tval <<= 1;\n"); - printf ("\tif (GET_XFLG()) val |= 1;\n"); + printf ("\tif (GET_XFLG ()) val |= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_ROXRW: - genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "data", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; @@ -1883,107 +2040,133 @@ static void gen_opcode (unsigned long int opcode) } printf ("\tuae_u32 carry = val & 1;\n"); printf ("\tval >>= 1;\n"); - printf ("\tif (GET_XFLG()) val |= %s;\n", cmask (curi->size)); + printf ("\tif (GET_XFLG ()) val |= %s;\n", cmask (curi->size)); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); duplicate_carry (); - genastore ("val", curi->smode, "srcreg", curi->size, "data"); + genastore ("val", curi->smode, "srcreg", curi->size, "data", XLATE_LOG); break; case i_MOVEC2: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tint regno = (src >> 12) & 15;\n"); printf ("\tuae_u32 *regp = regs.regs + regno;\n"); - printf ("\tif (! m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr); + printf ("\tif (!m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr); break; case i_MOVE2C: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tint regno = (src >> 12) & 15;\n"); printf ("\tuae_u32 *regp = regs.regs + regno;\n"); - printf ("\tif (! m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr); + printf ("\tif (!m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr); break; case i_CAS: { int old_brace_level; - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); printf ("\tint ru = (src >> 6) & 7;\n"); printf ("\tint rc = src & 7;\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc)", "dst"); - printf ("\tif (GET_ZFLG())"); + sync_m68k_pc (); + printf ("\tif (GET_ZFLG ())"); old_brace_level = n_braces; start_brace (); - genastore ("(m68k_dreg(regs, ru))", curi->dmode, "dstreg", curi->size, "dst"); + genastore ("(m68k_dreg(regs, ru))", curi->dmode, "dstreg", curi->size, "dst", XLATE_LOG); pop_braces (old_brace_level); printf ("else"); start_brace (); - printf ("m68k_dreg(regs, rc) = dst;\n"); + switch (curi->size) { + case sz_byte: + printf ("\tm68k_dreg(regs, rc) = (m68k_dreg(regs, rc) & ~0xff) | (dst & 0xff);\n"); + break; + case sz_word: + printf ("\tm68k_dreg(regs, rc) = (m68k_dreg(regs, rc) & ~0xffff) | (dst & 0xffff);\n"); + break; + default: + printf ("\tm68k_dreg(regs, rc) = dst;\n"); + break; + } pop_braces (old_brace_level); } break; case i_CAS2: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); printf ("\tuae_u32 rn1 = regs.regs[(extra >> 28) & 15];\n"); printf ("\tuae_u32 rn2 = regs.regs[(extra >> 12) & 15];\n"); if (curi->size == sz_word) { int old_brace_level = n_braces; + printf ("\tuae_u32 rc1 = (extra >> 16) & 7;\n"); + printf ("\tuae_u32 rc2 = extra & 7;\n"); printf ("\tuae_u16 dst1 = get_word(rn1), dst2 = get_word(rn2);\n"); - genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1"); - printf ("\tif (GET_ZFLG()) {\n"); - genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2"); - printf ("\tif (GET_ZFLG()) {\n"); + genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc1)", "dst1"); + printf ("\tif (GET_ZFLG ()) {\n"); + genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc2)", "dst2"); + printf ("\tif (GET_ZFLG ()) {\n"); printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n"); - printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n"); + printf ("\tput_word(rn2, m68k_dreg(regs, (extra >> 6) & 7));\n"); printf ("\t}}\n"); pop_braces (old_brace_level); - printf ("\tif (! GET_ZFLG()) {\n"); - printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = (m68k_dreg(regs, (extra >> 22) & 7) & ~0xffff) | (dst1 & 0xffff);\n"); - printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = (m68k_dreg(regs, (extra >> 6) & 7) & ~0xffff) | (dst2 & 0xffff);\n"); + printf ("\tif (! GET_ZFLG ()) {\n"); + printf ("\tm68k_dreg(regs, rc2) = (m68k_dreg(regs, rc2) & ~0xffff) | (dst2 & 0xffff);\n"); + printf ("\tm68k_dreg(regs, rc1) = (m68k_dreg(regs, rc1) & ~0xffff) | (dst1 & 0xffff);\n"); printf ("\t}\n"); } else { int old_brace_level = n_braces; + printf ("\tuae_u32 rc1 = (extra >> 16) & 7;\n"); + printf ("\tuae_u32 rc2 = extra & 7;\n"); printf ("\tuae_u32 dst1 = get_long(rn1), dst2 = get_long(rn2);\n"); - genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1"); - printf ("\tif (GET_ZFLG()) {\n"); - genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2"); - printf ("\tif (GET_ZFLG()) {\n"); + genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc1)", "dst1"); + printf ("\tif (GET_ZFLG ()) {\n"); + genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc2)", "dst2"); + printf ("\tif (GET_ZFLG ()) {\n"); printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n"); - printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n"); + printf ("\tput_long(rn2, m68k_dreg(regs, (extra >> 6) & 7));\n"); printf ("\t}}\n"); pop_braces (old_brace_level); - printf ("\tif (! GET_ZFLG()) {\n"); - printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = dst1;\n"); - printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = dst2;\n"); + printf ("\tif (! GET_ZFLG ()) {\n"); + printf ("\tm68k_dreg(regs, rc2) = dst2;\n"); + printf ("\tm68k_dreg(regs, rc1) = dst1;\n"); printf ("\t}\n"); } break; - case i_MOVES: /* ignore DFC and SFC because we have no MMU */ + case i_MOVES: { - int old_brace_level; - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); - printf ("\tif (extra & 0x800)\n"); - old_brace_level = n_braces; - start_brace (); - printf ("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); - genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); - genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); - pop_braces (old_brace_level); - printf ("else"); - start_brace (); - genamode (curi->dmode, "dstreg", curi->size, "src", 1, 0); - printf ("\tif (extra & 0x8000) {\n"); - switch (curi->size) { - case sz_byte: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break; - case sz_word: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s16)src;\n"); break; - case sz_long: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = src;\n"); break; - default: abort (); - } - printf ("\t} else {\n"); - genastore ("src", Dreg, "(extra >> 12) & 7", curi->size, ""); - printf ("\t}\n"); - pop_braces (old_brace_level); + int old_brace_level; + + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + start_brace(); + printf ("\tif (extra & 0x0800)\n"); /* from reg to ea */ + { + int old_m68k_pc_offset = m68k_pc_offset; + /* use DFC */ + old_brace_level = n_braces; + start_brace (); + printf ("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_DFC); + genastore ("src", curi->dmode, "dstreg", curi->size, "dst", XLATE_DFC); + pop_braces (old_brace_level); + m68k_pc_offset = old_m68k_pc_offset; + } + printf ("else"); /* from ea to reg */ + { + /* use SFC */ + start_brace (); + genamode (curi->dmode, "dstreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_SFC); + printf ("\tif (extra & 0x8000) {\n"); /* address/data */ + switch (curi->size) { + case sz_byte: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break; + case sz_word: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s16)src;\n"); break; + case sz_long: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = src;\n"); break; + default: abort (); + } + printf ("\t} else {\n"); + genastore ("src", Dreg, "(extra >> 12) & 7", curi->size, "", XLATE_LOG); + printf ("\t}\n"); + sync_m68k_pc(); + pop_braces (old_brace_level); + } } break; case i_BKPT: /* only needed for hardware emulators */ @@ -1999,23 +2182,23 @@ static void gen_opcode (unsigned long int opcode) printf ("\top_illg(opcode);\n"); break; case i_TRAPcc: + printf ("\tuaecptr oldpc = m68k_getpc();\n"); if (curi->smode != am_unknown && curi->smode != am_illg) - genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0); - printf ("\tif (cctrue(%d)) { Exception(7,m68k_getpc()); goto %s; }\n", curi->cc, endlabelstr); + genamode (curi->smode, "srcreg", curi->size, "dummy", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + sync_m68k_pc (); + printf ("\tif (cctrue(%d)) { Exception(7,oldpc); goto %s; }\n", curi->cc, endlabelstr); need_endlabel = 1; break; case i_DIVL: - sync_m68k_pc (); - start_brace (); printf ("\tuaecptr oldpc = m68k_getpc();\n"); - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); printf ("\tm68k_divl(opcode, dst, extra, oldpc);\n"); break; case i_MULL: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "dst", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); printf ("\tm68k_mull(opcode, dst, extra);\n"); break; @@ -2027,34 +2210,37 @@ static void gen_opcode (unsigned long int opcode) case i_BFFFO: case i_BFSET: case i_BFINS: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); - genamode (curi->dmode, "dstreg", sz_long, "dst", 2, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); + genamode (curi->dmode, "dstreg", sz_long, "dst", GENA_GETV_FETCH_ALIGN, GENA_MOVEM_DO_INC, XLATE_LOG); start_brace (); + printf ("\tuae_u32 bdata[2];"); printf ("\tuae_s32 offset = extra & 0x800 ? m68k_dreg(regs, (extra >> 6) & 7) : (extra >> 6) & 0x1f;\n"); printf ("\tint width = (((extra & 0x20 ? m68k_dreg(regs, extra & 7) : extra) -1) & 0x1f) +1;\n"); if (curi->dmode == Dreg) { - printf ("\tuae_u32 tmp = m68k_dreg(regs, dstreg) << (offset & 0x1f);\n"); + printf ("\tuae_u32 tmp = m68k_dreg(regs, dstreg);\n"); + printf ("\toffset &= 0x1f;\n"); + printf ("\ttmp = (tmp << offset) | (tmp >> (32 - offset));\n"); + printf ("\tbdata[0] = tmp & ((1 << (32 - width)) - 1);\n"); } else { - printf ("\tuae_u32 tmp,bf0,bf1;\n"); - printf ("\tdsta += (offset >> 3) | (offset & 0x80000000 ? ~0x1fffffff : 0);\n"); - printf ("\tbf0 = get_long(dsta);bf1 = get_byte(dsta+4) & 0xff;\n"); - printf ("\ttmp = (bf0 << (offset & 7)) | (bf1 >> (8 - (offset & 7)));\n"); + printf ("\tuae_u32 tmp;\n"); + printf ("\tdsta += offset >> 3;\n"); + printf ("\ttmp = get_bitfield(dsta, bdata, offset, width);\n"); } - printf ("\ttmp >>= (32 - width);\n"); - printf ("\tSET_NFLG_ALWAYS (tmp & (1 << (width-1)) ? 1 : 0);\n"); + printf ("\tSET_NFLG_ALWAYS (((uae_s32)tmp) < 0 ? 1 : 0);\n"); + if (curi->mnemo == i_BFEXTS) + printf ("\ttmp = (uae_s32)tmp >> (32 - width);\n"); + else + printf ("\ttmp >>= (32 - width);\n"); printf ("\tSET_ZFLG (tmp == 0); SET_VFLG (0); SET_CFLG (0);\n"); switch (curi->mnemo) { case i_BFTST: break; case i_BFEXTU: + case i_BFEXTS: printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n"); break; case i_BFCHG: - printf ("\ttmp = ~tmp;\n"); - break; - case i_BFEXTS: - printf ("\tif (GET_NFLG()) tmp |= width == 32 ? 0 : (-1 << width);\n"); - printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n"); + printf ("\ttmp = tmp ^ (0xffffffffu >> (32 - width));\n"); break; case i_BFCLR: printf ("\ttmp = 0;\n"); @@ -2065,10 +2251,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = offset;\n"); break; case i_BFSET: - printf ("\ttmp = 0xffffffff;\n"); + printf ("\ttmp = 0xffffffffu >> (32 - width);\n"); break; case i_BFINS: printf ("\ttmp = m68k_dreg(regs, (extra >> 12) & 7);\n"); + printf ("\ttmp = tmp & (0xffffffffu >> (32 - width));\n"); printf ("\tSET_NFLG_ALWAYS (tmp & (1 << (width - 1)) ? 1 : 0);\n"); printf ("\tSET_ZFLG (tmp == 0);\n"); break; @@ -2078,26 +2265,12 @@ static void gen_opcode (unsigned long int opcode) if (curi->mnemo == i_BFCHG || curi->mnemo == i_BFCLR || curi->mnemo == i_BFSET - || curi->mnemo == i_BFINS) - { - printf ("\ttmp <<= (32 - width);\n"); + || curi->mnemo == i_BFINS) { if (curi->dmode == Dreg) { - printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & ((offset & 0x1f) == 0 ? 0 :\n"); - printf ("\t\t(0xffffffff << (32 - (offset & 0x1f))))) |\n"); - printf ("\t\t(tmp >> (offset & 0x1f)) |\n"); - printf ("\t\t(((offset & 0x1f) + width) >= 32 ? 0 :\n"); - printf (" (m68k_dreg(regs, dstreg) & ((uae_u32)0xffffffff >> ((offset & 0x1f) + width))));\n"); + printf ("\ttmp = bdata[0] | (tmp << (32 - width));\n"); + printf ("\tm68k_dreg(regs, dstreg) = (tmp >> offset) | (tmp << (32 - offset));\n"); } else { - printf ("\tbf0 = (bf0 & (0xff000000 << (8 - (offset & 7)))) |\n"); - printf ("\t\t(tmp >> (offset & 7)) |\n"); - printf ("\t\t(((offset & 7) + width) >= 32 ? 0 :\n"); - printf ("\t\t (bf0 & ((uae_u32)0xffffffff >> ((offset & 7) + width))));\n"); - printf ("\tput_long(dsta,bf0 );\n"); - printf ("\tif (((offset & 7) + width) > 32) {\n"); - printf ("\t\tbf1 = (bf1 & (0xff >> (width - 32 + (offset & 7)))) |\n"); - printf ("\t\t\t(tmp << (8 - (offset & 7)));\n"); - printf ("\t\tput_byte(dsta+4,bf1);\n"); - printf ("\t}\n"); + printf ("\tput_bitfield(dsta, bdata, tmp, offset, width);\n"); } } break; @@ -2107,11 +2280,11 @@ static void gen_opcode (unsigned long int opcode) printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffffff00) | ((val >> 4) & 0xf0) | (val & 0xf);\n"); } else { printf ("\tuae_u16 val;\n"); - printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); - printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n"); - printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); - printf ("\tval = (val | ((uae_u16)get_byte(m68k_areg(regs, srcreg)) << 8)) + %s;\n", gen_nextiword ()); + printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg) - areg_byteinc[srcreg]);\n"); + printf ("\tval = (val | ((uae_u16)get_byte(m68k_areg(regs, srcreg) - 2 * areg_byteinc[srcreg]) << 8)) + %s;\n", gen_nextiword ()); + printf ("\tm68k_areg(regs, srcreg) -= 2;\n"); printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); + gen_set_fault_pc (); printf ("\tput_byte(m68k_areg(regs, dstreg),((val >> 4) & 0xf0) | (val & 0xf));\n"); } break; @@ -2122,57 +2295,57 @@ static void gen_opcode (unsigned long int opcode) printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffff0000) | (val & 0xffff);\n"); } else { printf ("\tuae_u16 val;\n"); - printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); - printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n"); + printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg) - areg_byteinc[srcreg]);\n"); printf ("\tval = (((val << 4) & 0xf00) | (val & 0xf)) + %s;\n", gen_nextiword ()); - printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); - printf ("\tput_byte(m68k_areg(regs, dstreg),val);\n"); - printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); - printf ("\tput_byte(m68k_areg(regs, dstreg),val >> 8);\n"); + printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); + printf ("\tm68k_areg(regs, dstreg) -= 2;\n"); + gen_set_fault_pc (); + printf ("\tput_word(m68k_areg(regs, dstreg), val);\n"); } break; case i_TAS: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "src", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); genflags (flag_logical, curi->size, "src", "", ""); printf ("\tsrc |= 0x80;\n"); - genastore ("src", curi->smode, "srcreg", curi->size, "src"); + genastore ("src", curi->smode, "srcreg", curi->size, "src", XLATE_LOG); break; case i_FPP: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_arithmetic(opcode, extra);\n"); break; case i_FDBcc: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_dbcc(opcode, extra);\n"); break; case i_FScc: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); - printf ("\tfpuop_scc(opcode,extra);\n"); + printf ("\tfpuop_scc(opcode, extra);\n"); break; case i_FTRAPcc: sync_m68k_pc (); start_brace (); printf ("\tuaecptr oldpc = m68k_getpc();\n"); + printf ("\tuae_u16 extra = %s;\n", gen_nextiword()); if (curi->smode != am_unknown && curi->smode != am_illg) - genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "dummy", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); - printf ("\tfpuop_trapcc(opcode,oldpc);\n"); + printf ("\tfpuop_trapcc(opcode, oldpc, extra);\n"); break; case i_FBcc: sync_m68k_pc (); start_brace (); printf ("\tuaecptr pc = m68k_getpc();\n"); - genamode (curi->dmode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->dmode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); - printf ("\tfpuop_bcc(opcode,pc,extra);\n"); + printf ("\tfpuop_bcc(opcode, pc, extra);\n"); break; case i_FSAVE: sync_m68k_pc (); @@ -2185,89 +2358,104 @@ static void gen_opcode (unsigned long int opcode) printf ("\tfpuop_restore(opcode);\n"); break; case i_CINVL: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_CINVP: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_CINVA: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_CPUSHL: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_CPUSHP: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_CPUSHA: - printf("\n#ifdef USE_JIT\n"); + printf ("\tflush_internals();\n"); + printf("#ifdef USE_JIT\n"); printf ("\tif (opcode&0x80)\n" "\t\tflush_icache();\n"); printf("#endif\n"); break; case i_MOVE16: - if ((opcode & 0xfff8) == 0xf620) { - /* MOVE16 (Ax)+,(Ay)+ */ - printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n"); - printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword()); - printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n"); - printf ("\tput_long(memd, get_long(mems));\n"); - printf ("\tput_long(memd+4, get_long(mems+4));\n"); - printf ("\tput_long(memd+8, get_long(mems+8));\n"); - printf ("\tput_long(memd+12, get_long(mems+12));\n"); - printf ("\tif (srcreg != dstreg)\n"); - printf ("\tm68k_areg(regs, srcreg) += 16;\n"); - printf ("\tm68k_areg(regs, dstreg) += 16;\n"); - } - else { - /* Other variants */ - genamode (curi->smode, "srcreg", curi->size, "mems", 0, 2); - genamode (curi->dmode, "dstreg", curi->size, "memd", 0, 2); - printf ("\tmemsa &= ~15;\n"); - printf ("\tmemda &= ~15;\n"); - printf ("\tput_long(memda, get_long(memsa));\n"); - printf ("\tput_long(memda+4, get_long(memsa+4));\n"); - printf ("\tput_long(memda+8, get_long(memsa+8));\n"); - printf ("\tput_long(memda+12, get_long(memsa+12));\n"); - if ((opcode & 0xfff8) == 0xf600) - printf ("\tm68k_areg(regs, srcreg) += 16;\n"); - else if ((opcode & 0xfff8) == 0xf608) - printf ("\tm68k_areg(regs, dstreg) += 16;\n"); - } - break; + if ((opcode & 0xfff8) == 0xf620) { + /* MOVE16 (Ax)+,(Ay)+ */ + printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n"); + printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword()); + printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n"); + printf ("\tput_long(memd, get_long(mems));\n"); + printf ("\tput_long(memd+4, get_long(mems+4));\n"); + printf ("\tput_long(memd+8, get_long(mems+8));\n"); + printf ("\tput_long(memd+12, get_long(mems+12));\n"); + printf ("\tif (srcreg != dstreg)\n"); + printf ("\tm68k_areg(regs, srcreg) += 16;\n"); + printf ("\tm68k_areg(regs, dstreg) += 16;\n"); + } else { + /* Other variants */ + genamode (curi->smode, "srcreg", curi->size, "mems", GENA_GETV_NO_FETCH, GENA_MOVEM_MOVE16, XLATE_LOG); + genamode (curi->dmode, "dstreg", curi->size, "memd", GENA_GETV_NO_FETCH, GENA_MOVEM_MOVE16, XLATE_LOG); + printf ("\tmemsa &= ~15;\n"); + printf ("\tmemda &= ~15;\n"); + printf ("\tput_long(memda, get_long(memsa));\n"); + printf ("\tput_long(memda+4, get_long(memsa+4));\n"); + printf ("\tput_long(memda+8, get_long(memsa+8));\n"); + printf ("\tput_long(memda+12, get_long(memsa+12));\n"); + if ((opcode & 0xfff8) == 0xf600) + printf ("\tm68k_areg(regs, srcreg) += 16;\n"); + else if ((opcode & 0xfff8) == 0xf608) + printf ("\tm68k_areg(regs, dstreg) += 16;\n"); + } + break; case i_MMUOP: - genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); + genamode (curi->smode, "srcreg", curi->size, "extra", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, XLATE_LOG); sync_m68k_pc (); swap_opcode (); printf ("\tmmu_op(opcode,extra);\n"); break; - - case i_EMULOP_RETURN: + + case i_EMULOP_RETURN: printf ("\tm68k_emulop_return();\n"); m68k_pc_offset = 0; break; - case i_EMULOP: + case i_EMULOP: printf ("\n"); swap_opcode (); printf ("\tm68k_emulop(opcode);\n"); break; - + + case i_NATFEAT_ID: + printf ("\n"); + printf ("\tm68k_natfeat_id();\n"); + break; + + case i_NATFEAT_CALL: + printf ("\n"); + printf ("\tm68k_natfeat_call();\n"); + break; + default: abort (); break; @@ -2279,73 +2467,194 @@ static void gen_opcode (unsigned long int opcode) static void generate_includes (FILE * f) { fprintf (f, "#include \"sysdeps.h\"\n"); - fprintf (f, "#include \"m68k.h\"\n"); fprintf (f, "#include \"memory.h\"\n"); fprintf (f, "#include \"readcpu.h\"\n"); fprintf (f, "#include \"newcpu.h\"\n"); + fprintf (f, "#ifdef USE_JIT\n"); fprintf (f, "#include \"compiler/compemu.h\"\n"); + fprintf (f, "#endif\n"); fprintf (f, "#include \"fpu/fpu.h\"\n"); fprintf (f, "#include \"cputbl.h\"\n"); + fprintf (f, "#include \"cpu_emulation.h\"\n"); + fprintf (f, "#include \"debug.h\"\n"); + + fprintf (f, "#define SET_CFLG_ALWAYS(x) SET_CFLG(x)\n"); + fprintf (f, "#define SET_NFLG_ALWAYS(x) SET_NFLG(x)\n"); + fprintf (f, "#define CPUFUNC_FF(x) x##_ff\n"); + fprintf (f, "#define CPUFUNC_NF(x) x##_nf\n"); + fprintf (f, "#define CPUFUNC(x) CPUFUNC_FF(x)\n"); - fprintf (f, "#define SET_CFLG_ALWAYS(x) SET_CFLG(x)\n"); - fprintf (f, "#define SET_NFLG_ALWAYS(x) SET_NFLG(x)\n"); - fprintf (f, "#define CPUFUNC_FF(x) x##_ff\n"); - fprintf (f, "#define CPUFUNC_NF(x) x##_nf\n"); - fprintf (f, "#define CPUFUNC(x) CPUFUNC_FF(x)\n"); - - fprintf (f, "#ifdef NOFLAGS\n"); - fprintf (f, "# include \"noflags.h\"\n"); - fprintf (f, "#endif\n"); + fprintf (f, "#ifdef NOFLAGS\n"); + fprintf (f, "# include \"noflags.h\"\n"); + fprintf (f, "#endif\n"); } static int postfix; +struct gencputbl { + char handler[80]; + uae_u16 specific; + uae_u16 opcode; + int namei; +}; +struct gencputbl cpustbl[65536]; +static int n_cpustbl; + +static char *decodeEA (amodes mode, wordsizes size) +{ + static char buffer[80]; + + buffer[0] = 0; + switch (mode){ + case Dreg: + strcpy (buffer,"Dn"); + break; + case Areg: + strcpy (buffer,"An"); + break; + case Aind: + strcpy (buffer,"(An)"); + break; + case Aipi: + strcpy (buffer,"(An)+"); + break; + case Apdi: + strcpy (buffer,"-(An)"); + break; + case Ad16: + strcpy (buffer,"(d16,An)"); + break; + case Ad8r: + strcpy (buffer,"(d8,An,Xn)"); + break; + case PC16: + strcpy (buffer,"(d16,PC)"); + break; + case PC8r: + strcpy (buffer,"(d8,PC,Xn)"); + break; + case absw: + strcpy (buffer,"(xxx).W"); + break; + case absl: + strcpy (buffer,"(xxx).L"); + break; + case imm: + switch (size){ + case sz_byte: + strcpy (buffer,"#.B"); + break; + case sz_word: + strcpy (buffer,"#.W"); + break; + case sz_long: + strcpy (buffer,"#.L"); + break; + default: + break; + } + break; + case imm0: + strcpy (buffer,"#.B"); + break; + case imm1: + strcpy (buffer,"#.W"); + break; + case imm2: + strcpy (buffer,"#.L"); + break; + case immi: + strcpy (buffer,"#"); + break; + + default: + break; + } + return buffer; +} + +static char *outopcode (const char *name, int opcode) +{ + static char out[100]; + struct instr *ins; + + ins = &table68k[opcode]; + strcpy (out, name); + if (ins->smode == immi) + strcat (out, "Q"); + if (ins->size == sz_byte) + strcat (out,".B"); + if (ins->size == sz_word) + strcat (out,".W"); + if (ins->size == sz_long) + strcat (out,".L"); + strcat (out," "); + if (ins->suse) + strcat (out, decodeEA (ins->smode, ins->size)); + if (ins->duse) { + if (ins->suse) strcat (out,","); + strcat (out, decodeEA (ins->dmode, ins->size)); + } + return out; +} + + static void generate_one_opcode (int rp) { + int i; uae_u16 smsk, dmsk; - long int opcode = opcode_map[rp]; - const char *opcode_str; + int opcode = opcode_map[rp]; + int have_realopcode = 0; + const char *name; if (table68k[opcode].mnemo == i_ILLG - || table68k[opcode].clev > (unsigned)cpu_level) + || table68k[opcode].clev > cpu_level) return; + for (i = 0; lookuptab[i].name[0]; i++) { + if (table68k[opcode].mnemo == lookuptab[i].mnemo) + break; + } + if (table68k[opcode].handler != -1) return; - opcode_str = get_instruction_string (opcode); - + name = lookuptab[i].name; if (opcode_next_clev[rp] != cpu_level) { - if (table68k[opcode].flagdead == 0) - /* force to the "ff" variant since the instruction doesn't set at all the condition codes */ - fprintf (stblfile, "{ CPUFUNC_FF(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp], - opcode, opcode_str); - else - fprintf (stblfile, "{ CPUFUNC(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp], - opcode, opcode_str); + sprintf(cpustbl[n_cpustbl].handler, "CPUFUNC(op_%x_%d)", opcode, opcode_last_postfix[rp]); + cpustbl[n_cpustbl].specific = 0; + cpustbl[n_cpustbl].opcode = opcode; + cpustbl[n_cpustbl].namei = i; + fprintf (stblfile, "{ %s, %d, %d }, /* %s */\n", cpustbl[n_cpustbl].handler, cpustbl[n_cpustbl].specific, opcode, name); + n_cpustbl++; return; } - + if (table68k[opcode].flagdead == 0) /* force to the "ff" variant since the instruction doesn't set at all the condition codes */ - fprintf (stblfile, "{ CPUFUNC_FF(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, opcode_str); + sprintf (cpustbl[n_cpustbl].handler, "CPUFUNC_FF(op_%x_%d)", opcode, postfix); else - fprintf (stblfile, "{ CPUFUNC(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, opcode_str); + sprintf (cpustbl[n_cpustbl].handler, "CPUFUNC(op_%x_%d)", opcode, postfix); + cpustbl[n_cpustbl].specific = 0; + cpustbl[n_cpustbl].opcode = opcode; + cpustbl[n_cpustbl].namei = i; + fprintf (stblfile, "{ %s, %d, %d }, /* %s */\n", cpustbl[n_cpustbl].handler, cpustbl[n_cpustbl].specific, opcode, name); + n_cpustbl++; - fprintf (headerfile, "extern cpuop_func op_%lx_%d_nf;\n", opcode, postfix); - fprintf (headerfile, "extern cpuop_func op_%lx_%d_ff;\n", opcode, postfix); - + fprintf (headerfile, "extern cpuop_func op_%x_%d_nf;\n", opcode, postfix); + fprintf (headerfile, "extern cpuop_func op_%x_%d_ff;\n", opcode, postfix); + + printf ("/* %s */\n", outopcode (name, opcode)); + printf ("void REGPARAM2 CPUFUNC(op_%x_%d)(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, name); + printf ("\tcpuop_begin();\n"); /* gb-- The "nf" variant for an instruction that doesn't set the condition codes at all is the same as the "ff" variant, so we don't need the "nf" variant to be compiled since it is mapped to the "ff" variant in the smalltbl. */ - if (table68k[opcode].flagdead == 0) + if (table68k[opcode].flagdead == 0) printf ("#ifndef NOFLAGS\n"); - printf ("void REGPARAM2 CPUFUNC(op_%lx_%d)(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, opcode_str); - printf ("\tcpuop_begin();\n"); - switch (table68k[opcode].stype) { case 0: smsk = 7; break; case 1: smsk = 255; break; @@ -2353,8 +2662,8 @@ static void generate_one_opcode (int rp) case 3: smsk = 7; break; case 4: smsk = 7; break; case 5: smsk = 63; break; - case 6: smsk = 255; break; - case 7: smsk = 3; break; + case 6: smsk = 255; break; + case 7: smsk = 3; break; default: abort (); } dmsk = 7; @@ -2385,38 +2694,17 @@ static void generate_one_opcode (int rp) if (pos < 8 && (smsk >> (8 - pos)) != 0) abort (); #endif - printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); - - if (pos < 8 && (smsk >> (8 - pos)) != 0) - sprintf (source, "(((opcode >> %d) | (opcode << %d)) & %d)", - pos ^ 8, 8 - pos, dmsk); - else if (pos != 8) - sprintf (source, "((opcode >> %d) & %d)", pos ^ 8, smsk); - else - sprintf (source, "(opcode & %d)", smsk); - - if (table68k[opcode].stype == 3) - printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); - else if (table68k[opcode].stype == 1) - printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); - else - printf ("\tuae_u32 srcreg = %s;\n", source); - - printf ("#else\n"); - + real_opcode(&have_realopcode); if (pos) - sprintf (source, "((opcode >> %d) & %d)", pos, smsk); + sprintf (source, "((real_opcode >> %d) & %d)", pos, smsk); else - sprintf (source, "(opcode & %d)", smsk); - + sprintf (source, "(real_opcode & %d)", smsk); if (table68k[opcode].stype == 3) printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); else if (table68k[opcode].stype == 1) printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); else printf ("\tuae_u32 srcreg = %s;\n", source); - - printf ("#endif\n"); } } if (table68k[opcode].duse @@ -2436,27 +2724,13 @@ static void generate_one_opcode (int rp) /* Check that we can do the little endian optimization safely. */ if (pos < 8 && (dmsk >> (8 - pos)) != 0) abort (); -#endif - printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); - - if (pos < 8 && (dmsk >> (8 - pos)) != 0) - printf ("\tuae_u32 dstreg = ((opcode >> %d) | (opcode << %d)) & %d;\n", - pos ^ 8, 8 - pos, dmsk); - else if (pos != 8) - printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", - pos ^ 8, dmsk); - else - printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); - - printf ("#else\n"); - +#endif + real_opcode(&have_realopcode); if (pos) - printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", + printf ("\tuae_u32 dstreg = (real_opcode >> %d) & %d;\n", pos, dmsk); else - printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); - - printf ("#endif\n"); + printf ("\tuae_u32 dstreg = real_opcode & %d;\n", dmsk); } } need_endlabel = 0; @@ -2465,10 +2739,10 @@ static void generate_one_opcode (int rp) gen_opcode (opcode); if (need_endlabel) printf ("%s: ;\n", endlabelstr); - printf ("\tcpuop_end();\n"); - printf ("}\n"); - if (table68k[opcode].flagdead == 0) + if (table68k[opcode].flagdead == 0) printf ("\n#endif\n"); + printf ("\tcpuop_end();\n"); + printf ("}\n"); opcode_next_clev[rp] = next_cpu_level; opcode_last_postfix[rp] = postfix; } @@ -2479,36 +2753,18 @@ static void generate_func (void) using_prefetch = 0; using_exception_3 = 0; -#if !USE_PREFETCH_BUFFER - /* gb-- No need for a prefetch buffer, nor exception 3 handling */ - /* Anyway, Basilisk2 does not use the op_smalltbl_5 table... */ - for (i = 0; i <= 4; i++) { -#else - for (i = 0; i < 6; i++) { -#endif - cpu_level = 4 - i; - if (i == 5) { - cpu_level = 0; - using_prefetch = 1; - using_exception_3 = 1; - for (rp = 0; rp < nr_cpuop_funcs; rp++) - opcode_next_clev[rp] = 0; - } - postfix = i; - fprintf (stblfile, "struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); - /* Disable spurious warnings. */ - printf ("\n" - "#ifdef _MSC_VER\n" - "#pragma warning(disable:4102) /* unreferenced label */\n" - "#endif\n"); + for (i = 0; i < 1; i++) { + cpu_level = 4 - i; + postfix = i; + fprintf (stblfile, "const struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); /* sam: this is for people with low memory (eg. me :)) */ printf ("\n" - "#if !defined(PART_1) && !defined(PART_2) && " - "!defined(PART_3) && !defined(PART_4) && " - "!defined(PART_5) && !defined(PART_6) && " - "!defined(PART_7) && !defined(PART_8)" + "#if !defined(PART_1) && !defined(PART_2) && " + "!defined(PART_3) && !defined(PART_4) && " + "!defined(PART_5) && !defined(PART_6) && " + "!defined(PART_7) && !defined(PART_8)" "\n" "#define PART_1 1\n" "#define PART_2 1\n" @@ -2519,8 +2775,8 @@ static void generate_func (void) "#define PART_7 1\n" "#define PART_8 1\n" "#endif\n\n"); - rp = 0; + n_cpustbl = 0; for(j=1;j<=8;++j) { int k = (j*nr_cpuop_funcs)/8; printf ("#ifdef PART_%d\n",j); @@ -2528,16 +2784,90 @@ static void generate_func (void) generate_one_opcode (rp); printf ("#endif\n\n"); } - fprintf (stblfile, "{ 0, 0, 0 }};\n"); } } -int main (int argc, char **argv) +static struct { + const char *handler; + const char *name; +} cpufunctbl[65536]; +static char const op_illg_1[] = "op_illg_1"; +static char const illegal[] = "ILLEGAL"; + +static void generate_functbl (void) { - FILE *out; - read_table68k (); - do_merges (); + int i; + unsigned int opcode; + int cpu_level = 4; + struct gencputbl *tbl = cpustbl; + + for (opcode = 0; opcode < 65536; opcode++) + { + cpufunctbl[opcode].handler = op_illg_1; + cpufunctbl[opcode].name = illegal; + } + for (i = 0; i < n_cpustbl; i++) + { + if (! tbl[i].specific) + { + cpufunctbl[tbl[i].opcode].handler = tbl[i].handler; + cpufunctbl[tbl[i].opcode].name = lookuptab[tbl[i].namei].name; + } + } + for (opcode = 0; opcode < 65536; opcode++) + { + const char *f; + + if (table68k[opcode].mnemo == i_ILLG || (unsigned)table68k[opcode].clev > (unsigned)cpu_level) + continue; + + if (table68k[opcode].handler != -1) + { + f = cpufunctbl[table68k[opcode].handler].handler; + if (f == op_illg_1) + abort(); + cpufunctbl[opcode].handler = f; + cpufunctbl[opcode].name = cpufunctbl[table68k[opcode].handler].name; + } + } + for (i = 0; i < n_cpustbl; i++) + { + if (tbl[i].specific) + { + cpufunctbl[tbl[i].opcode].handler = tbl[i].handler; + cpufunctbl[tbl[i].opcode].name = lookuptab[tbl[i].namei].name; + } + } + + fprintf(functblfile, "\n"); + fprintf(functblfile, "cpuop_func *cpufunctbl[65536] = {\n"); + fprintf(functblfile, "#if !defined(HAVE_GET_WORD_UNSWAPPED) || defined(FULLMMU)\n"); + for (opcode = 0; opcode < 65536; opcode++) + { + fprintf(functblfile, "\t%s%s /* %s */\n", cpufunctbl[opcode].handler, opcode < 65535 ? "," : "", cpufunctbl[opcode].name); + } + fprintf(functblfile, "#else\n"); + for (opcode = 0; opcode < 65536; opcode++) + { + unsigned int map = do_byteswap_16(opcode); + fprintf(functblfile, "\t%s%s /* %s */\n", cpufunctbl[map].handler, opcode < 65535 ? "," : "", cpufunctbl[map].name); + } + fprintf(functblfile, "#endif\n"); + fprintf(functblfile, "};\n"); +} + +#if (defined(OS_cygwin) || defined(OS_mingw)) && defined(EXTENDED_SIGSEGV) +void cygwin_mingw_abort() +{ +#undef abort + abort(); +} +#endif + +int main(void) +{ + init_table68k (); opcode_map = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc (sizeof (int) * nr_cpuop_funcs); @@ -2549,32 +2879,28 @@ int main (int argc, char **argv) * cputbl.h that way), but cpuopti can't cope. That could be fixed, but * I don't dare to touch the 68k version. */ - headerfile = fopen ("cputbl.h", "w"); - stblfile = fopen ("cpustbl.cpp", "w"); - out = freopen ("cpuemu.cpp", "w", stdout); + if ((headerfile = fopen ("cputbl.h", "wb")) == NULL) + abort(); + if ((stblfile = fopen ("cpustbl.cpp", "wb")) == NULL) + abort(); + if ((functblfile = fopen ("cpufunctbl.cpp", "wb")) == NULL) + abort(); + if (freopen ("cpuemu.cpp", "wb", stdout) == NULL) + abort(); generate_includes (stdout); + fprintf(stdout, "#ifdef HAVE_CFLAG_NO_REDZONE\n"); + fprintf(stdout, "#ifndef NOFLAGS\n"); + fprintf(stdout, "#pragma GCC option \"-mno-red-zone\"\n"); + fprintf(stdout, "#endif\n"); + fprintf(stdout, "#endif\n"); generate_includes (stblfile); - + generate_includes (functblfile); generate_func (); - + generate_functbl (); free (table68k); - fclose (headerfile); - fclose (stblfile); - fflush (out); - - /* For build systems (IDEs mainly) that don't make it easy to compile the - * same file twice with different settings. */ - stblfile = fopen ("cpustbl_nf.cpp", "w"); - out = freopen ("cpuemu_nf.cpp", "w", stdout); - - fprintf (stblfile, "#define NOFLAGS\n"); - fprintf (stblfile, "#include \"cpustbl.cpp\"\n"); - fclose (stblfile); - - printf ("#define NOFLAGS\n"); - printf ("#include \"cpuemu.cpp\"\n"); - fflush (out); - + fclose(headerfile); + fclose(stblfile); + fclose(functblfile); return 0; } diff --git a/BasiliskII/src/uae_cpu/m68k.h b/BasiliskII/src/uae_cpu/m68k.h index d4d28484..6a434daf 100644 --- a/BasiliskII/src/uae_cpu/m68k.h +++ b/BasiliskII/src/uae_cpu/m68k.h @@ -1,24 +1,35 @@ -/* - * UAE - The Un*x Amiga Emulator +/* + * m68k.h - machine dependent bits + * + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) * - * MC68000 emulation - machine dependent bits + * Inspired by Christian Bauer's Basilisk II * - * Copyright 1996 Bernd Schmidt + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is free software; you can redistribute it and/or modify + * ARAnyM is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * ARAnyM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with ARAnyM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation - machine dependent bits + * + * Copyright 1996 Bernd Schmidt + * + */ #ifndef M68K_FLAGS_H #define M68K_FLAGS_H diff --git a/BasiliskII/src/uae_cpu/memory-uae.h b/BasiliskII/src/uae_cpu/memory-uae.h new file mode 100644 index 00000000..c93aeb37 --- /dev/null +++ b/BasiliskII/src/uae_cpu/memory-uae.h @@ -0,0 +1,606 @@ +/* + * memory.h - memory management + * + * Copyright (c) 2001-2006 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II + * + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ARAnyM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ARAnyM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /* + * UAE - The Un*x Amiga Emulator + * + * memory management + * + * Copyright 1995 Bernd Schmidt + */ + +#ifndef UAE_MEMORY_H +#define UAE_MEMORY_H + +#include "sysdeps.h" +#include "string.h" +#include "hardware.h" +#include "parameters.h" +#include "registers.h" +#include "cpummu.h" +#include "readcpu.h" + +# include + +// newcpu.h +extern void Exception (int, uaecptr); +#ifdef EXCEPTIONS_VIA_LONGJMP + extern JMP_BUF excep_env; + #define SAVE_EXCEPTION \ + JMP_BUF excep_env_old; \ + memcpy(excep_env_old, excep_env, sizeof(JMP_BUF)) + #define RESTORE_EXCEPTION \ + memcpy(excep_env, excep_env_old, sizeof(JMP_BUF)) + #define TRY(var) int var = SETJMP(excep_env); if (!var) + #define CATCH(var) else + #define THROW(n) LONGJMP(excep_env, n) + #define THROW_AGAIN(var) LONGJMP(excep_env, var) + #define VOLATILE volatile +#else + struct m68k_exception { + int prb; + m68k_exception (int exc) : prb (exc) {} + operator int() { return prb; } + }; + #define SAVE_EXCEPTION + #define RESTORE_EXCEPTION + #define TRY(var) try + #define CATCH(var) catch(m68k_exception var) + #define THROW(n) throw m68k_exception(n) + #define THROW_AGAIN(var) throw + #define VOLATILE +#endif /* EXCEPTIONS_VIA_LONGJMP */ +extern int in_exception_2; + +#define STRAM_END 0x0e00000UL // should be replaced by global ROMBase as soon as ROMBase will be a constant +#define ROM_END 0x0e80000UL // should be replaced by ROMBase + RealROMSize if we are going to work with larger TOS ROMs than 512 kilobytes +#define FastRAM_BEGIN 0x1000000UL // should be replaced by global FastRAMBase as soon as FastRAMBase will be a constant +#ifdef FixedSizeFastRAM +#define FastRAM_SIZE (FixedSizeFastRAM * 1024 * 1024) +#else +#define FastRAM_SIZE FastRAMSize +#endif + +#ifdef FIXED_VIDEORAM +#define ARANYMVRAMSTART 0xf0000000UL +#endif + +#define ARANYMVRAMSIZE 0x00100000 // should be a variable to protect VGA card offscreen memory + +#ifdef FIXED_VIDEORAM +extern uintptr VMEMBaseDiff; +#else +extern uae_u32 VideoRAMBase; +#endif + +#ifdef ARAM_PAGE_CHECK +extern uaecptr pc_page, read_page, write_page; +extern uintptr pc_offset, read_offset, write_offset; +# ifdef PROTECT2K +# define ARAM_PAGE_MASK 0x7ff +# else +# ifdef FULLMMU +# define ARAM_PAGE_MASK 0xfff +# else +# define ARAM_PAGE_MASK 0xfffff +# endif +# endif +#endif + +extern uintptr MEMBaseDiff; +extern uintptr ROMBaseDiff; +extern uintptr FastRAMBaseDiff; +# define InitMEMBaseDiff(va, ra) (MEMBaseDiff = (uintptr)(va) - (uintptr)(ra)) +# define InitROMBaseDiff(va, ra) (ROMBaseDiff = (uintptr)(va) - (uintptr)(ra)) +# define InitFastRAMBaseDiff(va, ra) (FastRAMBaseDiff = (uintptr)(va) - (uintptr)(ra)) + +#ifdef FIXED_VIDEORAM +#define InitVMEMBaseDiff(va, ra) (VMEMBaseDiff = (uintptr)(va) - (uintptr)(ra)) +#else +#define InitVMEMBaseDiff(va, ra) (ra = (uintptr)(va) + MEMBaseDiff) +#endif + +extern "C" void breakpt(void); + + +static inline uae_u64 do_get_mem_quad(uae_u64 *a) {return SDL_SwapBE64(*a);} +static inline void do_put_mem_quad(uae_u64 *a, uae_u64 v) {*a = SDL_SwapBE64(v);} + + +#ifndef NOCHECKBOUNDARY +static ALWAYS_INLINE bool test_ram_boundary(uaecptr addr, int size, bool super, bool write) +{ + if (addr <= (FastRAM_BEGIN + FastRAM_SIZE - size)) { +#ifdef PROTECT2K + // protect first 2kB of RAM - access in supervisor mode only + if (!super && addr < 0x00000800UL) + return false; +#endif + // check for write access to protected areas: + // - first two longwords of ST-RAM are non-writable (ROM shadow) + // - non-writable area between end of ST-RAM and begin of FastRAM + if (!write || addr >= FastRAM_BEGIN || (addr >= 8 && addr <= (STRAM_END - size))) + return true; + } +#ifdef FIXED_VIDEORAM + return addr >= ARANYMVRAMSTART && addr <= (ARANYMVRAMSTART + ARANYMVRAMSIZE - size); +#else + return addr >= VideoRAMBase && addr <= (VideoRAMBase + ARANYMVRAMSIZE - size); +#endif +} +/* + * "size" is the size of the memory access (byte = 1, word = 2, long = 4) + */ +static ALWAYS_INLINE void check_ram_boundary(uaecptr addr, int size, bool write) +{ + if (test_ram_boundary(addr, size, regs.s, write)) + return; + + // D(bug("BUS ERROR %s at $%x\n", (write ? "writing" : "reading"), addr)); + regs.mmu_fault_addr = addr; + regs.mmu_ssw = ((size & 3) << 5) | (write ? 0 : (1 << 8)); + breakpt(); + THROW(2); +} + +#else +static inline bool test_ram_boundary(uaecptr, int, bool, bool) { return 1; } +static inline void check_ram_boundary(uaecptr, int, bool) { } +#endif + +#ifdef FIXED_VIDEORAM +# define do_get_real_address(a) ((uae_u8 *)(((uaecptr)(a) < ARANYMVRAMSTART) ? ((uaecptr)(a) + MEMBaseDiff) : ((uaecptr)(a) + VMEMBaseDiff))) +#else +# define do_get_real_address(a) ((uae_u8 *)((uintptr)(a) + MEMBaseDiff)) +#endif + +static inline uae_u8 *phys_get_real_address(uaecptr addr) +{ + return do_get_real_address(addr); +} + +#ifndef NOCHECKBOUNDARY +static inline bool phys_valid_address(uaecptr addr, bool write, int sz) +{ + return test_ram_boundary(addr, sz, regs.s, write); +} +#else +static inline bool phys_valid_address(uaecptr, bool, int) { return true; } +#endif + +static inline uae_u64 phys_get_quad(uaecptr addr) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ read_page) <= ARAM_PAGE_MASK)) + return do_get_mem_quad((uae_u64*)(addr + read_offset)); +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) return HWget_l(addr); /* TODO: must be HWget_q */ +#endif + check_ram_boundary(addr, 8, false); + uae_u64 * const m = (uae_u64 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + read_page = addr; + read_offset = (uintptr)m - (uintptr)addr; +#endif + return do_get_mem_quad(m); +} + +static inline uae_u32 phys_get_long(uaecptr addr) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ read_page) <= ARAM_PAGE_MASK)) + return do_get_mem_long((uae_u32*)(addr + read_offset)); +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) return HWget_l(addr); +#endif + check_ram_boundary(addr, 4, false); + uae_u32 * const m = (uae_u32 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + read_page = addr; + read_offset = (uintptr)m - (uintptr)addr; +#endif + return do_get_mem_long(m); +} + +static inline uae_u32 phys_get_word(uaecptr addr) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ read_page) <= ARAM_PAGE_MASK)) + return do_get_mem_word((uae_u16*)(addr + read_offset)); +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) return HWget_w(addr); +#endif + check_ram_boundary(addr, 2, false); + uae_u16 * const m = (uae_u16 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + read_page = addr; + read_offset = (uintptr)m - (uintptr)addr; +#endif + return do_get_mem_word(m); +} + +static inline uae_u32 phys_get_byte(uaecptr addr) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ read_page) <= ARAM_PAGE_MASK)) + return do_get_mem_byte((uae_u8*)(addr + read_offset)); +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) return HWget_b(addr); +#endif + check_ram_boundary(addr, 1, false); + uae_u8 * const m = (uae_u8 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + read_page = addr; + read_offset = (uintptr)m - (uintptr)addr; +#endif + return do_get_mem_byte(m); +} + +static inline void phys_put_quad(uaecptr addr, uae_u64 l) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ write_page) <= ARAM_PAGE_MASK)) { + do_put_mem_quad((uae_u64*)(addr + write_offset), l); + return; + } +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) { + HWput_l(addr, l); /* TODO: must be HWput_q */ + return; + } +#endif + check_ram_boundary(addr, 8, true); + uae_u64 * const m = (uae_u64 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + write_page = addr; + write_offset = (uintptr)m - (uintptr)addr; +#endif + do_put_mem_quad(m, l); +} + +static inline void phys_put_long(uaecptr addr, uae_u32 l) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ write_page) <= ARAM_PAGE_MASK)) { + do_put_mem_long((uae_u32*)(addr + write_offset), l); + return; + } +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) { + HWput_l(addr, l); + return; + } +#endif + check_ram_boundary(addr, 4, true); + uae_u32 * const m = (uae_u32 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + write_page = addr; + write_offset = (uintptr)m - (uintptr)addr; +#endif + do_put_mem_long(m, l); +} + +static inline void phys_put_word(uaecptr addr, uae_u32 w) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ write_page) <= ARAM_PAGE_MASK)) { + do_put_mem_word((uae_u16*)(addr + write_offset), w); + return; + } +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) { + HWput_w(addr, w); + return; + } +#endif + check_ram_boundary(addr, 2, true); + uae_u16 * const m = (uae_u16 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + write_page = addr; + write_offset = (uintptr)m - (uintptr)addr; +#endif + do_put_mem_word(m, w); +} + +static inline void phys_put_byte(uaecptr addr, uae_u32 b) +{ +#ifdef ARAM_PAGE_CHECK + if (((addr ^ write_page) <= ARAM_PAGE_MASK)) { + do_put_mem_byte((uae_u8*)(addr + write_offset), b); + return; + } +#endif +#ifndef HW_SIGSEGV + addr = addr < 0xff000000 ? addr : addr & 0x00ffffff; + if ((addr & 0xfff00000) == 0x00f00000) { + HWput_b(addr, b); + return; + } +#endif + check_ram_boundary(addr, 1, true); + uae_u8 * const m = (uae_u8 *)phys_get_real_address(addr); +#ifdef ARAM_PAGE_CHECK + write_page = addr; + write_offset = (uintptr)m - (uintptr)addr; +#endif + do_put_mem_byte(m, b); +} + +#ifdef FULLMMU +static ALWAYS_INLINE bool is_unaligned(uaecptr addr, int size) +{ + return unlikely((addr & (size - 1)) && (addr ^ (addr + size - 1)) & 0x1000); +} + +static ALWAYS_INLINE uae_u8 *mmu_get_real_address(uaecptr addr, struct mmu_atc_line *cl) +{ + return do_get_real_address(cl->phys + addr); +} + +static ALWAYS_INLINE uae_u32 mmu_get_quad(uaecptr addr, int data) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 0, &cl))) + return do_get_mem_quad((uae_u64 *)mmu_get_real_address(addr, cl)); + return mmu_get_quad_slow(addr, regs.s, data, cl); +} + +static ALWAYS_INLINE uae_u64 get_quad(uaecptr addr) +{ + return mmu_get_quad(addr, 1); +} + +static ALWAYS_INLINE uae_u32 mmu_get_long(uaecptr addr, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 0, &cl))) + return do_get_mem_long((uae_u32 *)mmu_get_real_address(addr, cl)); + return mmu_get_long_slow(addr, regs.s, data, size, cl); +} + +static ALWAYS_INLINE uae_u32 get_long(uaecptr addr) +{ + if (unlikely(is_unaligned(addr, 4))) + return mmu_get_long_unaligned(addr, 1); + return mmu_get_long(addr, 1, sz_long); +} + +static ALWAYS_INLINE uae_u16 mmu_get_word(uaecptr addr, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 0, &cl))) + return do_get_mem_word((uae_u16 *)mmu_get_real_address(addr, cl)); + return mmu_get_word_slow(addr, regs.s, data, size, cl); +} + +static ALWAYS_INLINE uae_u16 get_word(uaecptr addr) +{ + if (unlikely(is_unaligned(addr, 2))) + return mmu_get_word_unaligned(addr, 1); + return mmu_get_word(addr, 1, sz_word); +} + +static ALWAYS_INLINE uae_u8 mmu_get_byte(uaecptr addr, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 0, &cl))) + return do_get_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl)); + return mmu_get_byte_slow(addr, regs.s, data, size, cl); +} + +static ALWAYS_INLINE uae_u8 get_byte(uaecptr addr) +{ + return mmu_get_byte(addr, 1, sz_byte); +} + +static ALWAYS_INLINE void mmu_put_quad(uaecptr addr, uae_u64 val, int data) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 1, &cl))) + do_put_mem_quad((uae_u64 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_quad_slow(addr, val, regs.s, data, cl); +} + +static ALWAYS_INLINE void put_quad(uaecptr addr, uae_u32 val) +{ + mmu_put_quad(addr, val, 1); +} + +static ALWAYS_INLINE void mmu_put_long(uaecptr addr, uae_u32 val, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 1, &cl))) + do_put_mem_long((uae_u32 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_long_slow(addr, val, regs.s, data, size, cl); +} + +static ALWAYS_INLINE void put_long(uaecptr addr, uae_u32 val) +{ + if (unlikely(is_unaligned(addr, 4))) + mmu_put_long_unaligned(addr, val, 1); + else + mmu_put_long(addr, val, 1, sz_long); +} + +static ALWAYS_INLINE void mmu_put_word(uaecptr addr, uae_u16 val, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 1, &cl))) + do_put_mem_word((uae_u16 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_word_slow(addr, val, regs.s, data, size, cl); +} + +static ALWAYS_INLINE void put_word(uaecptr addr, uae_u16 val) +{ + if (unlikely(is_unaligned(addr, 2))) + mmu_put_word_unaligned(addr, val, 1); + else + mmu_put_word(addr, val, 1, sz_word); +} + +static ALWAYS_INLINE void mmu_put_byte(uaecptr addr, uae_u8 val, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_lookup(addr, data, 1, &cl))) + do_put_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_byte_slow(addr, val, regs.s, data, size, cl); +} + +static ALWAYS_INLINE void put_byte(uaecptr addr, uae_u8 val) +{ + mmu_put_byte(addr, val, 1, sz_byte); +} + +static inline uae_u8 *get_real_address(uaecptr addr, int write, int sz) +{ + (void)sz; + return phys_get_real_address(mmu_translate(addr, regs.s, 1, write)); +} + +static ALWAYS_INLINE uae_u32 mmu_get_user_long(uaecptr addr, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 0, &cl))) + return do_get_mem_long((uae_u32 *)mmu_get_real_address(addr, cl)); + return mmu_get_long_slow(addr, super, data, size, cl); +} + +static ALWAYS_INLINE uae_u16 mmu_get_user_word(uaecptr addr, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 0, &cl))) + return do_get_mem_word((uae_u16 *)mmu_get_real_address(addr, cl)); + return mmu_get_word_slow(addr, super, data, size, cl); +} + +static ALWAYS_INLINE uae_u8 mmu_get_user_byte(uaecptr addr, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 0, &cl))) + return do_get_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl)); + return mmu_get_byte_slow(addr, super, data, size, cl); +} + +static ALWAYS_INLINE void mmu_put_user_long(uaecptr addr, uae_u32 val, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 1, &cl))) + do_put_mem_long((uae_u32 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_long_slow(addr, val, super, data, size, cl); +} + +static ALWAYS_INLINE void mmu_put_user_word(uaecptr addr, uae_u16 val, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 1, &cl))) + do_put_mem_word((uae_u16 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_word_slow(addr, val, super, data, size, cl); +} + +static ALWAYS_INLINE void mmu_put_user_byte(uaecptr addr, uae_u8 val, int super, int data, int size) +{ + struct mmu_atc_line *cl; + + if (likely(mmu_user_lookup(addr, super, data, 1, &cl))) + do_put_mem_byte((uae_u8 *)mmu_get_real_address(addr, cl), val); + else + mmu_put_byte_slow(addr, val, super, data, size, cl); +} + +static inline bool valid_address(uaecptr addr, bool write, int sz) +{ + SAVE_EXCEPTION; + TRY(prb) { + (void)sz; + check_ram_boundary(mmu_translate(addr, regs.s, 1, (write ? 1 : 0)), sz, write); + RESTORE_EXCEPTION; + return true; + } + CATCH(prb) { + RESTORE_EXCEPTION; + return false; + } +} + +#else + +# define get_quad(a) phys_get_quad(a) +# define get_long(a) phys_get_long(a) +# define get_word(a) phys_get_word(a) +# define get_byte(a) phys_get_byte(a) +# define put_quad(a,b) phys_put_quad(a,b) +# define put_long(a,b) phys_put_long(a,b) +# define put_word(a,b) phys_put_word(a,b) +# define put_byte(a,b) phys_put_byte(a,b) +# define get_real_address(a,w,s) phys_get_real_address(a) + +#define valid_address(a,w,s) phys_valid_address(a,w,s) +#endif + +static inline void flush_internals() { +#ifdef ARAM_PAGE_CHECK + pc_page = 0xeeeeeeee; + read_page = 0xeeeeeeee; + write_page = 0xeeeeeeee; +#endif +} + +#endif /* MEMORY_H */ + +/* +vim:ts=4:sw=4: +*/ diff --git a/BasiliskII/src/uae_cpu/memory.cpp b/BasiliskII/src/uae_cpu/memory.cpp index 7483f506..e56f993d 100644 --- a/BasiliskII/src/uae_cpu/memory.cpp +++ b/BasiliskII/src/uae_cpu/memory.cpp @@ -1,642 +1,59 @@ /* - * UAE - The Un*x Amiga Emulator + * memory.cpp - memory management * - * Memory management + * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * (c) 1995 Bernd Schmidt + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is free software; you can redistribute it and/or modify + * ARAnyM is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * ARAnyM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with ARAnyM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include + /* + * UAE - The Un*x Amiga Emulator + * + * Memory management + * + * (c) 1995 Bernd Schmidt + */ #include "sysdeps.h" -#include "cpu_emulation.h" -#include "main.h" -#include "video.h" - -#include "m68k.h" #include "memory.h" -#include "readcpu.h" -#include "newcpu.h" +#define DEBUG 0 +#include "debug.h" -#if !REAL_ADDRESSING && !DIRECT_ADDRESSING - -static bool illegal_mem = false; - -#ifdef SAVE_MEMORY_BANKS -addrbank *mem_banks[65536]; -#else -addrbank mem_banks[65536]; +#ifdef ARAM_PAGE_CHECK +uaecptr pc_page = 0xeeeeeeee; +uintptr pc_offset = 0; +uaecptr read_page = 0xeeeeeeee; +uintptr read_offset = 0; +uaecptr write_page = 0xeeeeeeee; +uintptr write_offset = 0; #endif -#ifdef WORDS_BIGENDIAN -# define swap_words(X) (X) -#else -# define swap_words(X) (((X) >> 16) | ((X) << 16)) -#endif - -#ifdef NO_INLINE_MEMORY_ACCESS -uae_u32 longget (uaecptr addr) +extern "C" void breakpt(void) { - return call_mem_get_func (get_mem_bank (addr).lget, addr); -} -uae_u32 wordget (uaecptr addr) -{ - return call_mem_get_func (get_mem_bank (addr).wget, addr); -} -uae_u32 byteget (uaecptr addr) -{ - return call_mem_get_func (get_mem_bank (addr).bget, addr); -} -void longput (uaecptr addr, uae_u32 l) -{ - call_mem_put_func (get_mem_bank (addr).lput, addr, l); -} -void wordput (uaecptr addr, uae_u32 w) -{ - call_mem_put_func (get_mem_bank (addr).wput, addr, w); -} -void byteput (uaecptr addr, uae_u32 b) -{ - call_mem_put_func (get_mem_bank (addr).bput, addr, b); -} -#endif - -/* A dummy bank that only contains zeros */ - -static uae_u32 REGPARAM2 dummy_lget (uaecptr) REGPARAM; -static uae_u32 REGPARAM2 dummy_wget (uaecptr) REGPARAM; -static uae_u32 REGPARAM2 dummy_bget (uaecptr) REGPARAM; -static void REGPARAM2 dummy_lput (uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 dummy_wput (uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 dummy_bput (uaecptr, uae_u32) REGPARAM; - -uae_u32 REGPARAM2 dummy_lget (uaecptr addr) -{ - if (illegal_mem) - write_log ("Illegal lget at %08x\n", addr); - - return 0; + // bug("bus err: pc=%08x, sp=%08x, addr=%08x", m68k_getpc(), regs.regs[15], regs.mmu_fault_addr); } -uae_u32 REGPARAM2 dummy_wget (uaecptr addr) -{ - if (illegal_mem) - write_log ("Illegal wget at %08x\n", addr); +#if !KNOWN_ALLOC && !NORMAL_ADDRESSING +// This part need rewrite for ARAnyM !! +// It can be taken from hatari. - return 0; -} - -uae_u32 REGPARAM2 dummy_bget (uaecptr addr) -{ - if (illegal_mem) - write_log ("Illegal bget at %08x\n", addr); - - return 0; -} - -void REGPARAM2 dummy_lput (uaecptr addr, uae_u32 l) -{ - if (illegal_mem) - write_log ("Illegal lput at %08x\n", addr); -} -void REGPARAM2 dummy_wput (uaecptr addr, uae_u32 w) -{ - if (illegal_mem) - write_log ("Illegal wput at %08x\n", addr); -} -void REGPARAM2 dummy_bput (uaecptr addr, uae_u32 b) -{ - if (illegal_mem) - write_log ("Illegal bput at %08x\n", addr); -} - -/* Mac RAM (32 bit addressing) */ - -static uae_u32 REGPARAM2 ram_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 ram_wget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 ram_bget(uaecptr) REGPARAM; -static void REGPARAM2 ram_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 ram_wput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 ram_bput(uaecptr, uae_u32) REGPARAM; -static uae_u8 *REGPARAM2 ram_xlate(uaecptr addr) REGPARAM; - -static uintptr RAMBaseDiff; // RAMBaseHost - RAMBaseMac - -uae_u32 REGPARAM2 ram_lget(uaecptr addr) -{ - uae_u32 *m; - m = (uae_u32 *)(RAMBaseDiff + addr); - return do_get_mem_long(m); -} - -uae_u32 REGPARAM2 ram_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(RAMBaseDiff + addr); - return do_get_mem_word(m); -} - -uae_u32 REGPARAM2 ram_bget(uaecptr addr) -{ - return (uae_u32)*(uae_u8 *)(RAMBaseDiff + addr); -} - -void REGPARAM2 ram_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(RAMBaseDiff + addr); - do_put_mem_long(m, l); -} - -void REGPARAM2 ram_wput(uaecptr addr, uae_u32 w) -{ - uae_u16 *m; - m = (uae_u16 *)(RAMBaseDiff + addr); - do_put_mem_word(m, w); -} - -void REGPARAM2 ram_bput(uaecptr addr, uae_u32 b) -{ - *(uae_u8 *)(RAMBaseDiff + addr) = b; -} - -uae_u8 *REGPARAM2 ram_xlate(uaecptr addr) -{ - return (uae_u8 *)(RAMBaseDiff + addr); -} - -/* Mac RAM (24 bit addressing) */ - -static uae_u32 REGPARAM2 ram24_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 ram24_wget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 ram24_bget(uaecptr) REGPARAM; -static void REGPARAM2 ram24_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 ram24_wput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 ram24_bput(uaecptr, uae_u32) REGPARAM; -static uae_u8 *REGPARAM2 ram24_xlate(uaecptr addr) REGPARAM; - -uae_u32 REGPARAM2 ram24_lget(uaecptr addr) -{ - uae_u32 *m; - m = (uae_u32 *)(RAMBaseDiff + (addr & 0xffffff)); - return do_get_mem_long(m); -} - -uae_u32 REGPARAM2 ram24_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(RAMBaseDiff + (addr & 0xffffff)); - return do_get_mem_word(m); -} - -uae_u32 REGPARAM2 ram24_bget(uaecptr addr) -{ - return (uae_u32)*(uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)); -} - -void REGPARAM2 ram24_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(RAMBaseDiff + (addr & 0xffffff)); - do_put_mem_long(m, l); -} - -void REGPARAM2 ram24_wput(uaecptr addr, uae_u32 w) -{ - uae_u16 *m; - m = (uae_u16 *)(RAMBaseDiff + (addr & 0xffffff)); - do_put_mem_word(m, w); -} - -void REGPARAM2 ram24_bput(uaecptr addr, uae_u32 b) -{ - *(uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)) = b; -} - -uae_u8 *REGPARAM2 ram24_xlate(uaecptr addr) -{ - return (uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)); -} - -/* Mac ROM (32 bit addressing) */ - -static uae_u32 REGPARAM2 rom_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 rom_wget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 rom_bget(uaecptr) REGPARAM; -static void REGPARAM2 rom_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 rom_wput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 rom_bput(uaecptr, uae_u32) REGPARAM; -static uae_u8 *REGPARAM2 rom_xlate(uaecptr addr) REGPARAM; - -static uintptr ROMBaseDiff; // ROMBaseHost - ROMBaseMac - -uae_u32 REGPARAM2 rom_lget(uaecptr addr) -{ - uae_u32 *m; - m = (uae_u32 *)(ROMBaseDiff + addr); - return do_get_mem_long(m); -} - -uae_u32 REGPARAM2 rom_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(ROMBaseDiff + addr); - return do_get_mem_word(m); -} - -uae_u32 REGPARAM2 rom_bget(uaecptr addr) -{ - return (uae_u32)*(uae_u8 *)(ROMBaseDiff + addr); -} - -void REGPARAM2 rom_lput(uaecptr addr, uae_u32 b) -{ - if (illegal_mem) - write_log ("Illegal ROM lput at %08x\n", addr); -} - -void REGPARAM2 rom_wput(uaecptr addr, uae_u32 b) -{ - if (illegal_mem) - write_log ("Illegal ROM wput at %08x\n", addr); -} - -void REGPARAM2 rom_bput(uaecptr addr, uae_u32 b) -{ - if (illegal_mem) - write_log ("Illegal ROM bput at %08x\n", addr); -} - -uae_u8 *REGPARAM2 rom_xlate(uaecptr addr) -{ - return (uae_u8 *)(ROMBaseDiff + addr); -} - -/* Mac ROM (24 bit addressing) */ - -static uae_u32 REGPARAM2 rom24_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 rom24_wget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 rom24_bget(uaecptr) REGPARAM; -static uae_u8 *REGPARAM2 rom24_xlate(uaecptr addr) REGPARAM; - -uae_u32 REGPARAM2 rom24_lget(uaecptr addr) -{ - uae_u32 *m; - m = (uae_u32 *)(ROMBaseDiff + (addr & 0xffffff)); - return do_get_mem_long(m); -} - -uae_u32 REGPARAM2 rom24_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(ROMBaseDiff + (addr & 0xffffff)); - return do_get_mem_word(m); -} - -uae_u32 REGPARAM2 rom24_bget(uaecptr addr) -{ - return (uae_u32)*(uae_u8 *)(ROMBaseDiff + (addr & 0xffffff)); -} - -uae_u8 *REGPARAM2 rom24_xlate(uaecptr addr) -{ - return (uae_u8 *)(ROMBaseDiff + (addr & 0xffffff)); -} - -/* Frame buffer */ - -static uae_u32 REGPARAM2 frame_direct_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 frame_direct_wget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 frame_direct_bget(uaecptr) REGPARAM; -static void REGPARAM2 frame_direct_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 frame_direct_wput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 frame_direct_bput(uaecptr, uae_u32) REGPARAM; - -static uae_u32 REGPARAM2 frame_host_555_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 frame_host_555_wget(uaecptr) REGPARAM; -static void REGPARAM2 frame_host_555_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 frame_host_555_wput(uaecptr, uae_u32) REGPARAM; - -static uae_u32 REGPARAM2 frame_host_565_lget(uaecptr) REGPARAM; -static uae_u32 REGPARAM2 frame_host_565_wget(uaecptr) REGPARAM; -static void REGPARAM2 frame_host_565_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 frame_host_565_wput(uaecptr, uae_u32) REGPARAM; - -static uae_u32 REGPARAM2 frame_host_888_lget(uaecptr) REGPARAM; -static void REGPARAM2 frame_host_888_lput(uaecptr, uae_u32) REGPARAM; - -static uae_u8 *REGPARAM2 frame_xlate(uaecptr addr) REGPARAM; - -static uintptr FrameBaseDiff; // MacFrameBaseHost - MacFrameBaseMac - -uae_u32 REGPARAM2 frame_direct_lget(uaecptr addr) -{ - uae_u32 *m; - m = (uae_u32 *)(FrameBaseDiff + addr); - return do_get_mem_long(m); -} - -uae_u32 REGPARAM2 frame_direct_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(FrameBaseDiff + addr); - return do_get_mem_word(m); -} - -uae_u32 REGPARAM2 frame_direct_bget(uaecptr addr) -{ - return (uae_u32)*(uae_u8 *)(FrameBaseDiff + addr); -} - -void REGPARAM2 frame_direct_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(FrameBaseDiff + addr); - do_put_mem_long(m, l); -} - -void REGPARAM2 frame_direct_wput(uaecptr addr, uae_u32 w) -{ - uae_u16 *m; - m = (uae_u16 *)(FrameBaseDiff + addr); - do_put_mem_word(m, w); -} - -void REGPARAM2 frame_direct_bput(uaecptr addr, uae_u32 b) -{ - *(uae_u8 *)(FrameBaseDiff + addr) = b; -} - -uae_u32 REGPARAM2 frame_host_555_lget(uaecptr addr) -{ - uae_u32 *m, l; - m = (uae_u32 *)(FrameBaseDiff + addr); - l = *m; - return swap_words(l); -} - -uae_u32 REGPARAM2 frame_host_555_wget(uaecptr addr) -{ - uae_u16 *m; - m = (uae_u16 *)(FrameBaseDiff + addr); - return *m; -} - -void REGPARAM2 frame_host_555_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(FrameBaseDiff + addr); - *m = swap_words(l); -} - -void REGPARAM2 frame_host_555_wput(uaecptr addr, uae_u32 w) -{ - uae_u16 *m; - m = (uae_u16 *)(FrameBaseDiff + addr); - *m = w; -} - -uae_u32 REGPARAM2 frame_host_565_lget(uaecptr addr) -{ - uae_u32 *m, l; - m = (uae_u32 *)(FrameBaseDiff + addr); - l = *m; - l = (l & 0x001f001f) | ((l >> 1) & 0x7fe07fe0); - return swap_words(l); -} - -uae_u32 REGPARAM2 frame_host_565_wget(uaecptr addr) -{ - uae_u16 *m, w; - m = (uae_u16 *)(FrameBaseDiff + addr); - w = *m; - return (w & 0x1f) | ((w >> 1) & 0x7fe0); -} - -void REGPARAM2 frame_host_565_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(FrameBaseDiff + addr); - l = (l & 0x001f001f) | ((l << 1) & 0xffc0ffc0); - *m = swap_words(l); -} - -void REGPARAM2 frame_host_565_wput(uaecptr addr, uae_u32 w) -{ - uae_u16 *m; - m = (uae_u16 *)(FrameBaseDiff + addr); - *m = (w & 0x1f) | ((w << 1) & 0xffc0); -} - -uae_u32 REGPARAM2 frame_host_888_lget(uaecptr addr) -{ - uae_u32 *m, l; - m = (uae_u32 *)(FrameBaseDiff + addr); - return *m; -} - -void REGPARAM2 frame_host_888_lput(uaecptr addr, uae_u32 l) -{ - uae_u32 *m; - m = (uae_u32 *)(MacFrameBaseHost + addr - MacFrameBaseMac); - *m = l; -} - -uae_u8 *REGPARAM2 frame_xlate(uaecptr addr) -{ - return (uae_u8 *)(FrameBaseDiff + addr); -} - -/* Mac framebuffer RAM (24 bit addressing) - * - * This works by duplicating appropriate writes to the 32-bit - * address-space framebuffer. - */ - -static void REGPARAM2 fram24_lput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 fram24_wput(uaecptr, uae_u32) REGPARAM; -static void REGPARAM2 fram24_bput(uaecptr, uae_u32) REGPARAM; - -void REGPARAM2 fram24_lput(uaecptr addr, uae_u32 l) -{ - uaecptr page_off = addr & 0xffff; - if (0xa700 <= page_off && page_off < 0xfc80) { - uae_u32 *fm; - fm = (uae_u32 *)(MacFrameBaseHost + page_off - 0xa700); - do_put_mem_long(fm, l); - } - - uae_u32 *m; - m = (uae_u32 *)(RAMBaseDiff + (addr & 0xffffff)); - do_put_mem_long(m, l); -} - -void REGPARAM2 fram24_wput(uaecptr addr, uae_u32 w) -{ - uaecptr page_off = addr & 0xffff; - if (0xa700 <= page_off && page_off < 0xfc80) { - uae_u16 *fm; - fm = (uae_u16 *)(MacFrameBaseHost + page_off - 0xa700); - do_put_mem_word(fm, w); - } - - uae_u16 *m; - m = (uae_u16 *)(RAMBaseDiff + (addr & 0xffffff)); - do_put_mem_word(m, w); -} - -void REGPARAM2 fram24_bput(uaecptr addr, uae_u32 b) -{ - uaecptr page_off = addr & 0xffff; - if (0xa700 <= page_off && page_off < 0xfc80) { - *(uae_u8 *)(MacFrameBaseHost + page_off - 0xa700) = b; - } - - *(uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)) = b; -} - -/* Default memory access functions */ - -uae_u8 *REGPARAM2 default_xlate (uaecptr a) -{ - write_log("Your Mac program just did something terribly stupid\n"); - return NULL; -} - -/* Address banks */ - -addrbank dummy_bank = { - dummy_lget, dummy_wget, dummy_bget, - dummy_lput, dummy_wput, dummy_bput, - default_xlate -}; - -addrbank ram_bank = { - ram_lget, ram_wget, ram_bget, - ram_lput, ram_wput, ram_bput, - ram_xlate -}; - -addrbank ram24_bank = { - ram24_lget, ram24_wget, ram24_bget, - ram24_lput, ram24_wput, ram24_bput, - ram24_xlate -}; - -addrbank rom_bank = { - rom_lget, rom_wget, rom_bget, - rom_lput, rom_wput, rom_bput, - rom_xlate -}; - -addrbank rom24_bank = { - rom24_lget, rom24_wget, rom24_bget, - rom_lput, rom_wput, rom_bput, - rom24_xlate -}; - -addrbank frame_direct_bank = { - frame_direct_lget, frame_direct_wget, frame_direct_bget, - frame_direct_lput, frame_direct_wput, frame_direct_bput, - frame_xlate -}; - -addrbank frame_host_555_bank = { - frame_host_555_lget, frame_host_555_wget, frame_direct_bget, - frame_host_555_lput, frame_host_555_wput, frame_direct_bput, - frame_xlate -}; - -addrbank frame_host_565_bank = { - frame_host_565_lget, frame_host_565_wget, frame_direct_bget, - frame_host_565_lput, frame_host_565_wput, frame_direct_bput, - frame_xlate -}; - -addrbank frame_host_888_bank = { - frame_host_888_lget, frame_direct_wget, frame_direct_bget, - frame_host_888_lput, frame_direct_wput, frame_direct_bput, - frame_xlate -}; - -addrbank fram24_bank = { - ram24_lget, ram24_wget, ram24_bget, - fram24_lput, fram24_wput, fram24_bput, - ram24_xlate -}; - -void memory_init(void) -{ - for(long i=0; i<65536; i++) - put_mem_bank(i<<16, &dummy_bank); - - // Limit RAM size to not overlap ROM - uint32 ram_size = RAMSize > ROMBaseMac ? ROMBaseMac : RAMSize; - - RAMBaseDiff = (uintptr)RAMBaseHost - (uintptr)RAMBaseMac; - ROMBaseDiff = (uintptr)ROMBaseHost - (uintptr)ROMBaseMac; - FrameBaseDiff = (uintptr)MacFrameBaseHost - (uintptr)MacFrameBaseMac; - - // Map RAM, ROM and display - if (TwentyFourBitAddressing) { - map_banks(&ram24_bank, RAMBaseMac >> 16, ram_size >> 16); - map_banks(&rom24_bank, ROMBaseMac >> 16, ROMSize >> 16); - - // Map frame buffer at end of RAM. - map_banks(&fram24_bank, ((RAMBaseMac + ram_size) >> 16) - 1, 1); - } else { - map_banks(&ram_bank, RAMBaseMac >> 16, ram_size >> 16); - map_banks(&rom_bank, ROMBaseMac >> 16, ROMSize >> 16); - - // Map frame buffer - switch (MacFrameLayout) { - case FLAYOUT_DIRECT: - map_banks(&frame_direct_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); - break; - case FLAYOUT_HOST_555: - map_banks(&frame_host_555_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); - break; - case FLAYOUT_HOST_565: - map_banks(&frame_host_565_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); - break; - case FLAYOUT_HOST_888: - map_banks(&frame_host_888_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); - break; - } - } -} - -void map_banks(addrbank *bank, int start, int size) -{ - int bnr; - unsigned long int hioffs = 0, endhioffs = 0x100; - - if (start >= 0x100) { - for (bnr = start; bnr < start + size; bnr++) - put_mem_bank (bnr << 16, bank); - return; - } - if (TwentyFourBitAddressing) endhioffs = 0x10000; - for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) - for (bnr = start; bnr < start+size; bnr++) - put_mem_bank((bnr + hioffs) << 16, bank); -} - -#endif /* !REAL_ADDRESSING && !DIRECT_ADDRESSING */ +#error Not prepared for your platform, maybe you need memory banks from hatari +#endif /* !KNOWN_ALLOC && !NORMAL_ADDRESSING */ diff --git a/BasiliskII/src/uae_cpu/memory.h b/BasiliskII/src/uae_cpu/memory.h index 26b3c5f1..f7bab41d 100644 --- a/BasiliskII/src/uae_cpu/memory.h +++ b/BasiliskII/src/uae_cpu/memory.h @@ -23,6 +23,10 @@ #ifndef UAE_MEMORY_H #define UAE_MEMORY_H +#if DIRECT_ADDRESSING +extern uintptr MEMBaseDiff; +#endif + extern void Exception (int, uaecptr); #ifdef EXCEPTIONS_VIA_LONGJMP extern JMP_BUF excep_env; @@ -50,109 +54,8 @@ extern void Exception (int, uaecptr); #define THROW_AGAIN(var) throw #define VOLATILE #endif /* EXCEPTIONS_VIA_LONGJMP */ -extern int in_exception_2; -#if !DIRECT_ADDRESSING && !REAL_ADDRESSING - -/* Enabling this adds one additional native memory reference per 68k memory - * access, but saves one shift (on the x86). Enabling this is probably - * better for the cache. My favourite benchmark (PP2) doesn't show a - * difference, so I leave this enabled. */ - -#if 1 || defined SAVE_MEMORY -#define SAVE_MEMORY_BANKS -#endif - -typedef uae_u32 (REGPARAM2 *mem_get_func)(uaecptr) REGPARAM; -typedef void (REGPARAM2 *mem_put_func)(uaecptr, uae_u32) REGPARAM; -typedef uae_u8 *(REGPARAM2 *xlate_func)(uaecptr) REGPARAM; - -#undef DIRECT_MEMFUNCS_SUCCESSFUL - -#ifndef CAN_MAP_MEMORY -#undef USE_COMPILER -#endif - -#if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY) -#define USE_MAPPED_MEMORY -#endif - -typedef struct { - /* These ones should be self-explanatory... */ - mem_get_func lget, wget, bget; - mem_put_func lput, wput, bput; - /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can - * be used to address memory without calling the wget/wput functions. - * This doesn't work for all memory banks, so this function may call - * abort(). */ - xlate_func xlateaddr; -} addrbank; - -extern uae_u8 filesysory[65536]; - -extern addrbank ram_bank; // Mac RAM -extern addrbank rom_bank; // Mac ROM -extern addrbank frame_bank; // Frame buffer - -/* Default memory access functions */ - -extern uae_u8 *REGPARAM2 default_xlate(uaecptr addr) REGPARAM; - -#define bankindex(addr) (((uaecptr)(addr)) >> 16) - -#ifdef SAVE_MEMORY_BANKS -extern addrbank *mem_banks[65536]; -#define get_mem_bank(addr) (*mem_banks[bankindex(addr)]) -#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = (b)) -#else -extern addrbank mem_banks[65536]; -#define get_mem_bank(addr) (mem_banks[bankindex(addr)]) -#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = *(b)) -#endif - -extern void memory_init(void); -extern void map_banks(addrbank *bank, int first, int count); - -#ifndef NO_INLINE_MEMORY_ACCESS - -#define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr)) -#define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr)) -#define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr)) -#define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l)) -#define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w)) -#define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b)) - -#else - -extern uae_u32 longget(uaecptr addr); -extern uae_u32 wordget(uaecptr addr); -extern uae_u32 byteget(uaecptr addr); -extern void longput(uaecptr addr, uae_u32 l); -extern void wordput(uaecptr addr, uae_u32 w); -extern void byteput(uaecptr addr, uae_u32 b); - -#endif - -#ifndef MD_HAVE_MEM_1_FUNCS - -#define longget_1 longget -#define wordget_1 wordget -#define byteget_1 byteget -#define longput_1 longput -#define wordput_1 wordput -#define byteput_1 byteput - -#endif - -#endif /* !DIRECT_ADDRESSING && !REAL_ADDRESSING */ - -#if REAL_ADDRESSING -const uintptr MEMBaseDiff = 0; -#elif DIRECT_ADDRESSING -extern uintptr MEMBaseDiff; -#endif - -#if REAL_ADDRESSING || DIRECT_ADDRESSING +#if DIRECT_ADDRESSING static __inline__ uae_u8 *do_get_real_address(uaecptr addr) { return (uae_u8 *)MEMBaseDiff + addr; @@ -166,71 +69,57 @@ static __inline__ uae_u32 get_long(uaecptr addr) uae_u32 * const m = (uae_u32 *)do_get_real_address(addr); return do_get_mem_long(m); } +#define phys_get_long get_long static __inline__ uae_u32 get_word(uaecptr addr) { uae_u16 * const m = (uae_u16 *)do_get_real_address(addr); return do_get_mem_word(m); } +#define phys_get_word get_word static __inline__ uae_u32 get_byte(uaecptr addr) { uae_u8 * const m = (uae_u8 *)do_get_real_address(addr); return do_get_mem_byte(m); } +#define phys_get_byte get_byte static __inline__ void put_long(uaecptr addr, uae_u32 l) { uae_u32 * const m = (uae_u32 *)do_get_real_address(addr); do_put_mem_long(m, l); } +#define phys_put_long put_long static __inline__ void put_word(uaecptr addr, uae_u32 w) { uae_u16 * const m = (uae_u16 *)do_get_real_address(addr); do_put_mem_word(m, w); } +#define phys_put_word put_word static __inline__ void put_byte(uaecptr addr, uae_u32 b) { uae_u8 * const m = (uae_u8 *)do_get_real_address(addr); do_put_mem_byte(m, b); } +#define phys_put_byte put_byte static __inline__ uae_u8 *get_real_address(uaecptr addr) { return do_get_real_address(addr); } +static inline uae_u8 *get_real_address(uaecptr addr, int write, int sz) +{ + return do_get_real_address(addr); +} +static inline uae_u8 *phys_get_real_address(uaecptr addr) +{ + return do_get_real_address(addr); +} static __inline__ uae_u32 get_virtual_address(uae_u8 *addr) { return do_get_virtual_address(addr); } -#else -static __inline__ uae_u32 get_long(uaecptr addr) -{ - return longget_1(addr); -} -static __inline__ uae_u32 get_word(uaecptr addr) -{ - return wordget_1(addr); -} -static __inline__ uae_u32 get_byte(uaecptr addr) -{ - return byteget_1(addr); -} -static __inline__ void put_long(uaecptr addr, uae_u32 l) -{ - longput_1(addr, l); -} -static __inline__ void put_word(uaecptr addr, uae_u32 w) -{ - wordput_1(addr, w); -} -static __inline__ void put_byte(uaecptr addr, uae_u32 b) -{ - byteput_1(addr, b); -} -static __inline__ uae_u8 *get_real_address(uaecptr addr) -{ - return get_mem_bank(addr).xlateaddr(addr); -} -/* gb-- deliberately not implemented since it shall not be used... */ -extern uae_u32 get_virtual_address(uae_u8 *addr); -#endif /* DIRECT_ADDRESSING || REAL_ADDRESSING */ +#endif /* DIRECT_ADDRESSING */ + +static __inline__ void check_ram_boundary(uaecptr addr, int size, bool write) {} +static inline void flush_internals() {} #endif /* MEMORY_H */ diff --git a/BasiliskII/src/uae_cpu/newcpu.cpp b/BasiliskII/src/uae_cpu/newcpu.cpp index dc109422..351a0de3 100644 --- a/BasiliskII/src/uae_cpu/newcpu.cpp +++ b/BasiliskII/src/uae_cpu/newcpu.cpp @@ -1,51 +1,80 @@ /* - * UAE - The Un*x Amiga Emulator + * newcpu.cpp - CPU emulation * - * MC68000 emulation + * Copyright (c) 2010 ARAnyM dev team (see AUTHORS) + * * - * (c) 1995 Bernd Schmidt + * Inspired by Christian Bauer's Basilisk II * - * This program is free software; you can redistribute it and/or modify + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. + * + * ARAnyM is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * ARAnyM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with ARAnyM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * (c) 1995 Bernd Schmidt + */ #include "sysdeps.h" +#include #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" - -extern int intlev(void); // From baisilisk_glue.cpp - #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" -#include "compiler/compemu.h" +#ifdef USE_JIT +# include "compiler/compemu.h" +#endif #include "fpu/fpu.h" - -#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) -B2_mutex *spcflags_lock = NULL; +#include "cpummu.h" +#if 0 +#include "natfeats.h" +#include "disasm-glue.h" +#endif +#if USE_JIT +extern bool UseJIT; #endif -bool quit_program = false; +#include + +#define DEBUG 0 +#include "debug.h" + +#define SANITY_CHECK_ATC 1 + +struct fixup fixup = {0, 0, 0}; + +int quit_program = 0; +int exit_val = 0; + +// For instruction $7139 +bool cpu_debugging = false; + struct flag_struct regflags; +/* LongJump buffers */ +#ifdef EXCEPTIONS_VIA_LONGJMP +JMP_BUF excep_env; +#endif /* Opcode of faulting instruction */ uae_u16 last_op_for_exception_3; /* PC at fault time */ @@ -60,19 +89,34 @@ int movem_index1[256]; int movem_index2[256]; int movem_next[256]; -cpuop_func *cpufunctbl[65536]; +#ifdef FLIGHT_RECORDER + +// feel free to edit the following defines to customize the dump +#define FRLOG_HOTKEY 1 /* 1 = dump only when hotkey is held down */ +#define FRLOG_ALL 1 /* 1 = dump continuously to ever growing log */ +#define FRLOG_IRQ 0 /* 1 = dump also CPU in interrupts */ +#define FRLOG_REGS 0 /* 1 = dump also all data/address registers */ +#define FRLOG_SIZE 8192 /* this many instructions in single dump */ -#if FLIGHT_RECORDER struct rec_step { - uae_u32 pc; -#if FLIGHT_RECORDER >= 2 uae_u32 d[8]; uae_u32 a[8]; -#endif + uae_u32 pc; + uae_u16 sr; + uae_u32 usp; + uae_u32 msp; + uae_u32 isp; + uae_u16 instr; }; -const int LOG_SIZE = 32768; -static rec_step log[LOG_SIZE]; +bool cpu_flight_recorder_active = false; + +#if FRLOG_ALL +const int LOG_SIZE = 10; +#else +const int LOG_SIZE = FRLOG_SIZE; +#endif +static rec_step frlog[LOG_SIZE]; static int log_ptr = -1; // First time initialization static const char *log_filename(void) @@ -81,848 +125,568 @@ static const char *log_filename(void) return name ? name : "log.68k"; } -void m68k_record_step(uaecptr pc) -{ -#if FLIGHT_RECORDER >= 2 - /* XXX: if LSB is set, we are recording from generated code and we - don't support registers recording yet. */ - if ((pc & 1) == 0) { - for (int i = 0; i < 8; i++) { - log[log_ptr].d[i] = m68k_dreg(regs, i); - log[log_ptr].a[i] = m68k_areg(regs, i); - } - } -#endif - log[log_ptr].pc = pc; - log_ptr = (log_ptr + 1) % LOG_SIZE; -} - -static void dump_log(void) +void dump_flight_recorder(void) { +#if FRLOG_ALL + FILE *f = fopen(log_filename(), "a"); +#else FILE *f = fopen(log_filename(), "w"); +#endif if (f == NULL) return; for (int i = 0; i < LOG_SIZE; i++) { int j = (i + log_ptr) % LOG_SIZE; - uae_u32 pc = log[j].pc & ~1; - fprintf(f, "pc %08x", pc); -#if FLIGHT_RECORDER >= 2 - fprintf(f, "\n"); - if ((log[j].pc & 1) == 0) { - fprintf(f, "d0 %08x d1 %08x d2 %08x d3 %08x\n", log[j].d[0], log[j].d[1], log[j].d[2], log[j].d[3]); - fprintf(f, "d4 %08x d5 %08x d6 %08x d7 %08x\n", log[j].d[4], log[j].d[5], log[j].d[6], log[j].d[7]); - fprintf(f, "a0 %08x a1 %08x a2 %08x a3 %08x\n", log[j].a[0], log[j].a[1], log[j].a[2], log[j].a[3]); - fprintf(f, "a4 %08x a5 %08x a6 %08x a7 %08x\n", log[j].a[4], log[j].a[5], log[j].a[6], log[j].a[7]); - } -#else - fprintf(f, " | "); -#endif -#if ENABLE_MON - disass_68k(f, pc); + fprintf(f, "pc %08x instr %04x sr %04x usp %08x msp %08x isp %08x\n", frlog[j].pc, frlog[j].instr, frlog[j].sr, frlog[j].usp, frlog[j].msp, frlog[j].isp); + // adding a simple opcode -> assembler conversion table would help +#if FRLOG_REGS + fprintf(f, "d0 %08x d1 %08x d2 %08x d3 %08x\n", frlog[j].d[0], frlog[j].d[1], frlog[j].d[2], frlog[j].d[3]); + fprintf(f, "d4 %08x d5 %08x d6 %08x d7 %08x\n", frlog[j].d[4], frlog[j].d[5], frlog[j].d[6], frlog[j].d[7]); + fprintf(f, "a0 %08x a1 %08x a2 %08x a3 %08x\n", frlog[j].a[0], frlog[j].a[1], frlog[j].a[2], frlog[j].a[3]); + fprintf(f, "a4 %08x a5 %08x a6 %08x a7 %08x\n", frlog[j].a[4], frlog[j].a[5], frlog[j].a[6], frlog[j].a[7]); #endif + m68k_disasm(f, frlog[j].pc, NULL, 1); } fclose(f); } -#endif -#if ENABLE_MON -static void dump_regs(void) +void m68k_record_step(uaecptr pc, int opcode) { - m68k_dumpstate(NULL); -} -#endif + static bool last_state = false; -#define COUNT_INSTRS 0 +#if FRLOG_HOTKEY + if (! cpu_flight_recorder_active) { + if (last_state) { + // dump log out + dump_flight_recorder(); -#if COUNT_INSTRS -static unsigned long int instrcount[65536]; -static uae_u16 opcodenums[65536]; - -static int compfn (const void *el1, const void *el2) -{ - return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2]; -} - -static char *icountfilename (void) -{ - char *name = getenv ("INSNCOUNT"); - if (name) - return name; - return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount"; -} - -void dump_counts (void) -{ - FILE *f = fopen (icountfilename (), "w"); - unsigned long int total; - int i; - - write_log ("Writing instruction count file...\n"); - for (i = 0; i < 65536; i++) { - opcodenums[i] = i; - total += instrcount[i]; + // remember last state + last_state = false; + } + return; } - qsort (opcodenums, 65536, sizeof(uae_u16), compfn); - - fprintf (f, "Total: %lu\n", total); - for (i=0; i < 65536; i++) { - unsigned long int cnt = instrcount[opcodenums[i]]; - struct instr *dp; - struct mnemolookup *lookup; - if (!cnt) - break; - dp = table68k + opcodenums[i]; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) - ; - fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name); - } - fclose (f); -} -#else -void dump_counts (void) -{ -} #endif + if (! last_state) { + // reset old log + log_ptr = 0; + memset(frlog, 0, sizeof(frlog)); + // remember last state + last_state = true; + } + +#if FRLOG_REGS + for (int i = 0; i < 8; i++) { + frlog[log_ptr].d[i] = m68k_dreg(regs, i); + frlog[log_ptr].a[i] = m68k_areg(regs, i); + } +#endif + frlog[log_ptr].pc = pc; + + MakeSR(); +#if ! FRLOG_IRQ + // is CPU in interrupt handler? Quit if should not be logged. + if (regs.s && !regs.m) return; +#endif + frlog[log_ptr].sr = regs.sr; + frlog[log_ptr].usp = regs.usp; + frlog[log_ptr].msp = regs.msp; + frlog[log_ptr].isp = regs.isp; + frlog[log_ptr].instr = opcode; + + log_ptr = (log_ptr + 1) % LOG_SIZE; +#if FRLOG_ALL + if (log_ptr == 0) dump_flight_recorder(); +#endif +} +#endif /* FLIGHT_RECORDER */ + int broken_in; -static __inline__ unsigned int cft_map (unsigned int f) +static inline unsigned int cft_map (unsigned int f) { -#ifndef HAVE_GET_WORD_UNSWAPPED - return f; +#if !defined(HAVE_GET_WORD_UNSWAPPED) || defined(FULLMMU) + return f; #else - return ((f >> 8) & 255) | ((f & 255) << 8); + return do_byteswap_16(f); #endif } -void REGPARAM2 op_illg_1 (uae_u32 opcode) REGPARAM; - void REGPARAM2 op_illg_1 (uae_u32 opcode) { - op_illg (cft_map (opcode)); + op_illg (cft_map (opcode)); } -static void build_cpufunctbl (void) -{ - int i; - unsigned long opcode; - unsigned int cpu_level = 0; // 68000 (default) - if (CPUType == 4) - cpu_level = 4; // 68040 with FPU - else { - if (FPUType) - cpu_level = 3; // 68020 with FPU - else if (CPUType >= 2) - cpu_level = 2; // 68020 - else if (CPUType == 1) - cpu_level = 1; - } - struct cputbl *tbl = ( - cpu_level == 4 ? op_smalltbl_0_ff - : cpu_level == 3 ? op_smalltbl_1_ff - : cpu_level == 2 ? op_smalltbl_2_ff - : cpu_level == 1 ? op_smalltbl_3_ff - : op_smalltbl_4_ff); - - for (opcode = 0; opcode < 65536; opcode++) - cpufunctbl[cft_map (opcode)] = op_illg_1; - for (i = 0; tbl[i].handler != NULL; i++) { - if (! tbl[i].specific) - cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler; - } - for (opcode = 0; opcode < 65536; opcode++) { - cpuop_func *f; - - if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) - continue; - - if (table68k[opcode].handler != -1) { - f = cpufunctbl[cft_map (table68k[opcode].handler)]; - if (f == op_illg_1) - abort(); - cpufunctbl[cft_map (opcode)] = f; - } - } - for (i = 0; tbl[i].handler != NULL; i++) { - if (tbl[i].specific) - cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler; - } -} void init_m68k (void) { - int i; + int i; - for (i = 0 ; i < 256 ; i++) { - int j; - for (j = 0 ; j < 8 ; j++) { - if (i & (1 << j)) break; - } - movem_index1[i] = j; - movem_index2[i] = 7-j; - movem_next[i] = i & (~(1 << j)); + for (i = 0 ; i < 256 ; i++) { + int j; + for (j = 0 ; j < 8 ; j++) { + if (i & (1 << j)) break; } -#if COUNT_INSTRS - { - FILE *f = fopen (icountfilename (), "r"); - memset (instrcount, 0, sizeof instrcount); - if (f) { - uae_u32 opcode, count, total; - char name[20]; - write_log ("Reading instruction count file...\n"); - fscanf (f, "Total: %lu\n", &total); - while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) { - instrcount[opcode] = count; - } - fclose(f); - } - } -#endif - read_table68k (); - do_merges (); - - build_cpufunctbl (); - -#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) - spcflags_lock = B2_create_mutex(); -#endif - fpu_init(CPUType == 4); + movem_index1[i] = j; + movem_index2[i] = 7-j; + movem_next[i] = i & (~(1 << j)); + } + fpu_init (CPUType == 4); } void exit_m68k (void) { fpu_exit (); -#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) - B2_delete_mutex(spcflags_lock); -#endif } -struct regstruct regs, lastint_regs; -static struct regstruct regs_backup[16]; -static int backup_pointer = 0; -static long int m68kpc_offset; -int lastint_no; +struct regstruct regs; +// MJ static struct regstruct regs_backup[16]; +// MJ static int backup_pointer = 0; -#if REAL_ADDRESSING || DIRECT_ADDRESSING -#define get_ibyte_1(o) get_byte(get_virtual_address(regs.pc_p) + (o) + 1) -#define get_iword_1(o) get_word(get_virtual_address(regs.pc_p) + (o)) -#define get_ilong_1(o) get_long(get_virtual_address(regs.pc_p) + (o)) + +#ifdef FULLMMU +static inline uae_u8 get_ibyte_1(uae_u32 o) +{ + return get_ibyte(o); +} +static inline uae_u16 get_iword_1(uae_u32 o) +{ + return get_iword(o); +} +static inline uae_u32 get_ilong_1(uae_u32 o) +{ + return get_ilong(o); +} #else -#define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) -#define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) -#define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) +# define get_ibyte_1(o) get_byte(m68k_getpc() + (o) + 1) +# define get_iword_1(o) get_word(m68k_getpc() + (o)) +# define get_ilong_1(o) get_long(m68k_getpc() + (o)) #endif -uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf) +/* + * extract bitfield data from memory and return it in the MSBs + * bdata caches the unmodified data for put_bitfield() + */ +uae_u32 get_bitfield(uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) { - uae_u16 dp; - uae_s8 disp8; - uae_s16 disp16; - int r; - uae_u32 dispreg; - uaecptr addr; - uae_s32 offset = 0; - char buffer[80]; + uae_u32 tmp, res, mask; - switch (mode){ - case Dreg: - sprintf (buffer,"D%d", reg); + offset &= 7; + mask = 0xffffffffu << (32 - width); + switch ((offset + width + 7) >> 3) { + case 1: + tmp = get_byte(src); + res = tmp << (24 + offset); + bdata[0] = tmp & ~(mask >> (24 + offset)); break; - case Areg: - sprintf (buffer,"A%d", reg); + case 2: + tmp = get_word(src); + res = tmp << (16 + offset); + bdata[0] = tmp & ~(mask >> (16 + offset)); break; - case Aind: - sprintf (buffer,"(A%d)", reg); + case 3: + tmp = get_word(src); + res = tmp << (16 + offset); + bdata[0] = tmp & ~(mask >> (16 + offset)); + tmp = get_byte(src + 2); + res |= tmp << (8 + offset); + bdata[1] = tmp & ~(mask >> (8 + offset)); break; - case Aipi: - sprintf (buffer,"(A%d)+", reg); + case 4: + tmp = get_long(src); + res = tmp << offset; + bdata[0] = tmp & ~(mask >> offset); break; - case Apdi: - sprintf (buffer,"-(A%d)", reg); - break; - case Ad16: - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr = m68k_areg(regs,reg) + (uae_s16)disp16; - sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff, - (unsigned long)addr); - break; - case Ad8r: - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0, disp = 0; - uae_s32 base = m68k_areg(regs,reg); - char name[10]; - sprintf (name,"A%d, ",reg); - if (dp & 0x80) { base = 0; name[0] = 0; } - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if (dp & 3) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - sprintf (buffer,"(%s%c%d.%c*%d+%d)+%d == $%08lx", name, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), - disp,outer, - (unsigned long)addr); - } else { - addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg; - sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), disp8, - (unsigned long)addr); - } - break; - case PC16: - addr = m68k_getpc () + m68kpc_offset; - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr += (uae_s16)disp16; - sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr); - break; - case PC8r: - addr = m68k_getpc () + m68kpc_offset; - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0,disp = 0; - uae_s32 base = addr; - char name[10]; - sprintf (name,"PC, "); - if (dp & 0x80) { base = 0; name[0] = 0; } - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if (dp & 3) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - sprintf (buffer,"(%s%c%d.%c*%d+%d)+%d == $%08lx", name, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), - disp,outer, - (unsigned long)addr); - } else { - addr += (uae_s32)((uae_s8)disp8) + dispreg; - sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', - (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), - disp8, (unsigned long)addr); - } - break; - case absw: - sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); - m68kpc_offset += 2; - break; - case absl: - sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset)); - m68kpc_offset += 4; - break; - case imm: - switch (size){ - case sz_byte: - sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff)); - m68kpc_offset += 2; - break; - case sz_word: - sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff)); - m68kpc_offset += 2; - break; - case sz_long: - sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); - m68kpc_offset += 4; - break; - default: - break; - } - break; - case imm0: - offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff)); - break; - case imm1: - offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff)); - break; - case imm2: - offset = (uae_s32)get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - sprintf (buffer,"#$%08lx", (unsigned long)offset); - break; - case immi: - offset = (uae_s32)(uae_s8)(reg & 0xff); - sprintf (buffer,"#$%08lx", (unsigned long)offset); + case 5: + tmp = get_long(src); + res = tmp << offset; + bdata[0] = tmp & ~(mask >> offset); + tmp = get_byte(src + 4); + res |= tmp >> (8 - offset); + bdata[1] = tmp & ~(mask << (8 - offset)); break; default: + /* Panic? */ + res = 0; break; } - if (buf == 0) - printf ("%s", buffer); - else - strcat (buf, buffer); - return offset; + return res; } -/* The plan is that this will take over the job of exception 3 handling - - * the CPU emulation functions will just do a longjmp to m68k_go whenever - * they hit an odd address. */ -static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val) +/* + * write bitfield data (in the LSBs) back to memory, upper bits + * must be cleared already. + */ +void put_bitfield(uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) { - uae_u16 dp; - uae_s8 disp8; - uae_s16 disp16; - int r; - uae_u32 dispreg; - uaecptr addr; - uae_s32 offset = 0; - - switch (mode){ - case Dreg: - *val = m68k_dreg (regs, reg); - return 1; - case Areg: - *val = m68k_areg (regs, reg); - return 1; - - case Aind: - case Aipi: - addr = m68k_areg (regs, reg); + offset = (offset & 7) + width; + switch ((offset + 7) >> 3) { + case 1: + put_byte(dst, bdata[0] | (val << (8 - offset))); break; - case Apdi: - addr = m68k_areg (regs, reg); + case 2: + put_word(dst, bdata[0] | (val << (16 - offset))); break; - case Ad16: - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr = m68k_areg(regs,reg) + (uae_s16)disp16; + case 3: + put_word(dst, bdata[0] | (val >> (offset - 16))); + put_byte(dst + 2, bdata[1] | (val << (24 - offset))); break; - case Ad8r: - addr = m68k_areg (regs, reg); -d8r_common: - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0, disp = 0; - uae_s32 base = addr; - if (dp & 0x80) base = 0; - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if (dp & 3) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - } else { - addr += (uae_s32)((uae_s8)disp8) + dispreg; - } + case 4: + put_long(dst, bdata[0] | (val << (32 - offset))); break; - case PC16: - addr = m68k_getpc () + m68kpc_offset; - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr += (uae_s16)disp16; - break; - case PC8r: - addr = m68k_getpc () + m68kpc_offset; - goto d8r_common; - case absw: - addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - break; - case absl: - addr = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - break; - case imm: - switch (size){ - case sz_byte: - *val = get_iword_1 (m68kpc_offset) & 0xff; - m68kpc_offset += 2; - break; - case sz_word: - *val = get_iword_1 (m68kpc_offset) & 0xffff; - m68kpc_offset += 2; - break; - case sz_long: - *val = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - break; - default: - break; - } - return 1; - case imm0: - *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - return 1; - case imm1: - *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - return 1; - case imm2: - *val = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - return 1; - case immi: - *val = (uae_s32)(uae_s8)(reg & 0xff); - return 1; - default: - addr = 0; + case 5: + put_long(dst, bdata[0] | (val >> (offset - 32))); + put_byte(dst + 4, bdata[1] | (val << (40 - offset))); break; } - if ((addr & 1) == 0) - return 1; - - last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset; - last_fault_for_exception_3 = addr; - return 0; } uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp) { - int reg = (dp >> 12) & 15; - uae_s32 regd = regs.regs[reg]; - if ((dp & 0x800) == 0) - regd = (uae_s32)(uae_s16)regd; - regd <<= (dp >> 9) & 3; - if (dp & 0x100) { - uae_s32 outer = 0; - if (dp & 0x80) base = 0; - if (dp & 0x40) regd = 0; + int reg = (dp >> 12) & 15; + uae_s32 regd = regs.regs[reg]; + if ((dp & 0x800) == 0) + regd = (uae_s32)(uae_s16)regd; + regd <<= (dp >> 9) & 3; + if (dp & 0x100) { + uae_s32 outer = 0; + if (dp & 0x80) base = 0; + if (dp & 0x40) regd = 0; - if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword(); - if ((dp & 0x30) == 0x30) base += next_ilong(); + if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword(); + if ((dp & 0x30) == 0x30) base += next_ilong(); - if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword(); - if ((dp & 0x3) == 0x3) outer = next_ilong(); + if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword(); + if ((dp & 0x3) == 0x3) outer = next_ilong(); - if ((dp & 0x4) == 0) base += regd; - if (dp & 0x3) base = get_long (base); - if (dp & 0x4) base += regd; + if ((dp & 0x4) == 0) base += regd; + if (dp & 0x3) base = get_long (base); + if (dp & 0x4) base += regd; - return base + outer; - } else { - return base + (uae_s32)((uae_s8)dp) + regd; - } + return base + outer; + } else { + return base + (uae_s32)((uae_s8)dp) + regd; + } } uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp) { - int reg = (dp >> 12) & 15; - uae_s32 regd = regs.regs[reg]; + int reg = (dp >> 12) & 15; + uae_s32 regd = regs.regs[reg]; #if 1 - if ((dp & 0x800) == 0) - regd = (uae_s32)(uae_s16)regd; - return base + (uae_s8)dp + regd; + if ((dp & 0x800) == 0) + regd = (uae_s32)(uae_s16)regd; + return base + (uae_s8)dp + regd; #else - /* Branch-free code... benchmark this again now that - * things are no longer inline. */ - uae_s32 regd16; - uae_u32 mask; - mask = ((dp & 0x800) >> 11) - 1; - regd16 = (uae_s32)(uae_s16)regd; - regd16 &= mask; - mask = ~mask; - base += (uae_s8)dp; - regd &= mask; - regd |= regd16; - return base + regd; + /* Branch-free code... benchmark this again now that + * things are no longer inline. */ + uae_s32 regd16; + uae_u32 mask; + mask = ((dp & 0x800) >> 11) - 1; + regd16 = (uae_s32)(uae_s16)regd; + regd16 &= mask; + mask = ~mask; + base += (uae_s8)dp; + regd &= mask; + regd |= regd16; + return base + regd; #endif } void MakeSR (void) { #if 0 - assert((regs.t1 & 1) == regs.t1); - assert((regs.t0 & 1) == regs.t0); - assert((regs.s & 1) == regs.s); - assert((regs.m & 1) == regs.m); - assert((XFLG & 1) == XFLG); - assert((NFLG & 1) == NFLG); - assert((ZFLG & 1) == ZFLG); - assert((VFLG & 1) == VFLG); - assert((CFLG & 1) == CFLG); + assert((regs.t1 & 1) == regs.t1); + assert((regs.t0 & 1) == regs.t0); + assert((regs.s & 1) == regs.s); + assert((regs.m & 1) == regs.m); + assert((XFLG & 1) == XFLG); + assert((NFLG & 1) == NFLG); + assert((ZFLG & 1) == ZFLG); + assert((VFLG & 1) == VFLG); + assert((CFLG & 1) == CFLG); #endif - regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) - | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) - | (GET_XFLG() << 4) | (GET_NFLG() << 3) | (GET_ZFLG() << 2) | (GET_VFLG() << 1) - | GET_CFLG()); + regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) + | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) + | (GET_XFLG() << 4) | (GET_NFLG() << 3) | (GET_ZFLG() << 2) | (GET_VFLG() << 1) + | GET_CFLG()); } void MakeFromSR (void) { - int oldm = regs.m; - int olds = regs.s; + int oldm = regs.m; + int olds = regs.s; - regs.t1 = (regs.sr >> 15) & 1; - regs.t0 = (regs.sr >> 14) & 1; - regs.s = (regs.sr >> 13) & 1; - regs.m = (regs.sr >> 12) & 1; - regs.intmask = (regs.sr >> 8) & 7; - SET_XFLG ((regs.sr >> 4) & 1); - SET_NFLG ((regs.sr >> 3) & 1); - SET_ZFLG ((regs.sr >> 2) & 1); - SET_VFLG ((regs.sr >> 1) & 1); - SET_CFLG (regs.sr & 1); - if (CPUType >= 2) { - if (olds != regs.s) { - if (olds) { - if (oldm) - regs.msp = m68k_areg(regs, 7); - else - regs.isp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.usp; - } else { - regs.usp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; - } - } else if (olds && oldm != regs.m) { - if (oldm) { - regs.msp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.isp; - } else { - regs.isp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.msp; - } - } - } else { - if (olds != regs.s) { - if (olds) { - regs.isp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.usp; - } else { - regs.usp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.isp; - } - } + regs.t1 = (regs.sr >> 15) & 1; + regs.t0 = (regs.sr >> 14) & 1; + regs.s = (regs.sr >> 13) & 1; + mmu_set_super(regs.s); + regs.m = (regs.sr >> 12) & 1; + regs.intmask = (regs.sr >> 8) & 7; + SET_XFLG ((regs.sr >> 4) & 1); + SET_NFLG ((regs.sr >> 3) & 1); + SET_ZFLG ((regs.sr >> 2) & 1); + SET_VFLG ((regs.sr >> 1) & 1); + SET_CFLG (regs.sr & 1); + if (olds != regs.s) { + if (olds) { + if (oldm) + regs.msp = m68k_areg(regs, 7); + else + regs.isp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.usp; + } else { + regs.usp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; + } + } else if (olds && oldm != regs.m) { + if (oldm) { + regs.msp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.isp; + } else { + regs.isp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.msp; + } } - SPCFLAGS_SET( SPCFLAG_INT ); - if (regs.t1 || regs.t0) - SPCFLAGS_SET( SPCFLAG_TRACE ); - else - /* Keep SPCFLAG_DOTRACE, we still want a trace exception for - SR-modifying instructions (including STOP). */ - SPCFLAGS_CLEAR( SPCFLAG_TRACE ); + // SPCFLAGS_SET( SPCFLAG_INT ); + SPCFLAGS_SET( SPCFLAG_INT ); + if (regs.t1 || regs.t0) + SPCFLAGS_SET( SPCFLAG_TRACE ); + else + SPCFLAGS_CLEAR( SPCFLAG_TRACE ); } +/* for building exception frames */ +static inline void exc_push_word(uae_u16 w) +{ + m68k_areg(regs, 7) -= 2; + put_word(m68k_areg(regs, 7), w); +} +static inline void exc_push_long(uae_u32 l) +{ + m68k_areg(regs, 7) -= 4; + put_long (m68k_areg(regs, 7), l); +} + +static inline void exc_make_frame( + int format, + uae_u16 sr, + uae_u32 currpc, + int nr, + uae_u32 x0, + uae_u32 x1 +) +{ + switch(format) { + case 4: + exc_push_long(x1); + exc_push_long(x0); + break; + case 3: + case 2: + exc_push_long(x0); + break; + } + + exc_push_word((format << 12) + (nr * 4)); /* format | vector */ + exc_push_long(currpc); + exc_push_word(sr); +} + +#ifdef EXCEPTIONS_VIA_LONGJMP +static int building_bus_fault_stack_frame=0; +#endif + void Exception(int nr, uaecptr oldpc) { - uae_u32 currpc = m68k_getpc (); - MakeSR(); - if (!regs.s) { - regs.usp = m68k_areg(regs, 7); - if (CPUType >= 2) - m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; - else - m68k_areg(regs, 7) = regs.isp; - regs.s = 1; + uae_u32 currpc = m68k_getpc (); + MakeSR(); + + if (fixup.flag) + { + m68k_areg(regs, fixup.reg) = fixup.value; + fixup.flag = 0; + } + + if (!regs.s) { + regs.usp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; + regs.s = 1; + mmu_set_super(1); + } + + if (nr == 2) { + /* BUS ERROR handler begins */ +#ifdef ENABLE_EPSLIMITER + check_eps_limit(currpc); +#endif + // panicbug("Exception Nr. %d CPC: %08x NPC: %08x SP=%08x Addr: %08x", nr, currpc, get_long (regs.vbr + 4*nr), m68k_areg(regs, 7), regs.mmu_fault_addr); +#ifdef EXCEPTIONS_VIA_LONGJMP + if (!building_bus_fault_stack_frame) +#else + try +#endif + { +#ifdef EXCEPTIONS_VIA_LONGJMP + building_bus_fault_stack_frame= 1; +#endif + /* 68040 */ + exc_push_long(0); /* PD3 */ + exc_push_long(0); /* PD2 */ + exc_push_long(0); /* PD1 */ + exc_push_long(0); /* PD0/WB1D */ + exc_push_long(0); /* WB1A */ + exc_push_long(0); /* WB2D */ + exc_push_long(0); /* WB2A */ + exc_push_long(regs.wb3_data); /* WB3D */ + exc_push_long(regs.mmu_fault_addr); /* WB3A */ + exc_push_long(regs.mmu_fault_addr); + exc_push_word(0); /* WB1S */ + exc_push_word(0); /* WB2S */ + exc_push_word(regs.wb3_status); /* WB3S */ + regs.wb3_status = 0; + exc_push_word(regs.mmu_ssw); + exc_push_long(regs.mmu_fault_addr); /* EA */ + exc_make_frame(7, regs.sr, regs.fault_pc, 2, 0, 0); + } - if (CPUType > 0) { - if (nr == 2 || nr == 3) { - int i; - /* @@@ this is probably wrong (?) */ - for (i = 0 ; i < 12 ; i++) { - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), 0); - } - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), 0xa000 + nr * 4); - } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { - m68k_areg(regs, 7) -= 4; - put_long (m68k_areg(regs, 7), oldpc); - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), 0x2000 + nr * 4); - } else if (regs.m && nr >= 24 && nr < 32) { - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), nr * 4); - m68k_areg(regs, 7) -= 4; - put_long (m68k_areg(regs, 7), currpc); - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), regs.sr); - regs.sr |= (1 << 13); - regs.msp = m68k_areg(regs, 7); - m68k_areg(regs, 7) = regs.isp; - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), 0x1000 + nr * 4); - } else { - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), nr * 4); - } - } else { - if (nr == 2 || nr == 3) { - m68k_areg(regs, 7) -= 12; - /* ??????? */ - if (nr == 3) { - put_long (m68k_areg(regs, 7), last_fault_for_exception_3); - put_word (m68k_areg(regs, 7)+4, last_op_for_exception_3); - put_long (m68k_areg(regs, 7)+8, last_addr_for_exception_3); - } - write_log ("Exception!\n"); - goto kludge_me_do; - } - } - m68k_areg(regs, 7) -= 4; - put_long (m68k_areg(regs, 7), currpc); -kludge_me_do: - m68k_areg(regs, 7) -= 2; - put_word (m68k_areg(regs, 7), regs.sr); - m68k_setpc (get_long (regs.vbr + 4*nr)); - SPCFLAGS_SET( SPCFLAG_JIT_END_COMPILE ); - fill_prefetch_0 (); - regs.t1 = regs.t0 = regs.m = 0; - SPCFLAGS_CLEAR( SPCFLAG_TRACE | SPCFLAG_DOTRACE ); +#ifdef EXCEPTIONS_VIA_LONGJMP + else +#else + catch (m68k_exception) +#endif + { + report_double_bus_error(); +#ifdef EXCEPTIONS_VIA_LONGJMP + building_bus_fault_stack_frame= 0; +#endif + return; + } + +#ifdef EXCEPTIONS_VIA_LONGJMP + building_bus_fault_stack_frame= 0; +#endif + /* end of BUS ERROR handler */ + } else if (nr == 3) { + exc_make_frame(2, regs.sr, last_addr_for_exception_3, nr, + last_fault_for_exception_3 & 0xfffffffe, 0); + } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { + /* div by zero, CHK, TRAP or TRACE */ + exc_make_frame(2, regs.sr, currpc, nr, oldpc, 0); + } else if (regs.m && nr >= 24 && nr < 32) { + /* interrupts! */ + exc_make_frame(0, regs.sr, currpc, nr, 0, 0); + regs.sr |= (1 << 13); + regs.msp = m68k_areg(regs, 7); + m68k_areg(regs, 7) = regs.isp; + + exc_make_frame(1, /* throwaway */ + regs.sr, currpc, nr, 0, 0); + } else { + exc_make_frame(0, regs.sr, currpc, nr, 0, 0); + } + m68k_setpc (get_long (regs.vbr + 4*nr)); + SPCFLAGS_SET( SPCFLAG_JIT_END_COMPILE ); + fill_prefetch_0 (); + regs.t1 = regs.t0 = regs.m = 0; + SPCFLAGS_CLEAR(SPCFLAG_TRACE | SPCFLAG_DOTRACE); } static void Interrupt(int nr) { - assert(nr < 8 && nr >= 0); - lastint_regs = regs; - lastint_no = nr; - Exception(nr+24, 0); + assert(nr < 8 && nr >= 0); + Exception(nr+24, 0); - regs.intmask = nr; - SPCFLAGS_SET( SPCFLAG_INT ); + regs.intmask = nr; + // why the hell the SPCFLAG_INT is to be set??? (joy) + // regs.spcflags |= SPCFLAG_INT; (disabled by joy) + SPCFLAGS_SET( SPCFLAG_INT ); } -static int caar, cacr, tc, itt0, itt1, dtt0, dtt1, mmusr, urp, srp; - -static int movec_illg (int regno) +static void SCCInterrupt(int nr) { - switch (CPUType) { - case 1: - if ((regno & 0x7ff) <= 1) - return 0; - break; - case 2: - case 3: - if ((regno & 0x7ff) <= 2) - return 0; - if (regno == 3 || regno == 4) - return 0; - break; - case 4: - if ((regno & 0x7ff) <= 7) { - if (regno != 0x802) - return 0; - } - break; - } - return 1; + // fprintf(stderr, "CPU: in SCCInterrupt\n"); + Exception(nr, 0); + + regs.intmask = 5;// ex 5 +} + +static void MFPInterrupt(int nr) +{ + // fprintf(stderr, "CPU: in MFPInterrupt\n"); + Exception(nr, 0); + + regs.intmask = 6; } int m68k_move2c (int regno, uae_u32 *regp) { - if (movec_illg (regno)) { - op_illg (0x4E7B); - return 0; - } else { - switch (regno) { - case 0: regs.sfc = *regp & 7; break; - case 1: regs.dfc = *regp & 7; break; - case 2: - regs.cacr = *regp & (CPUType < 4 ? 0x3 : 0x80008000); -#if USE_JIT - set_cache_state(regs.cacr & 0x8000); - if (*regp & 0x08) { /* Just to be on the safe side */ - flush_icache(); - } + switch (regno) { + case 0: regs.sfc = *regp & 7; break; + case 1: regs.dfc = *regp & 7; break; + case 2: regs.cacr = *regp & 0x80008000; +#ifdef USE_JIT + set_cache_state(regs.cacr & 0x8000); + if (*regp & 0x08) { /* Just to be on the safe side */ + flush_icache(); + } #endif - break; - case 3: tc = *regp & 0xc000; break; - case 4: itt0 = *regp & 0xffffe364; break; - case 5: itt1 = *regp & 0xffffe364; break; - case 6: dtt0 = *regp & 0xffffe364; break; - case 7: dtt1 = *regp & 0xffffe364; break; - case 0x800: regs.usp = *regp; break; - case 0x801: regs.vbr = *regp; break; - case 0x802: caar = *regp &0xfc; break; - case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; - case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; - case 0x805: mmusr = *regp; break; - case 0x806: urp = *regp; break; - case 0x807: srp = *regp; break; - default: - op_illg (0x4E7B); - return 0; - } + break; + case 3: mmu_set_tc(*regp & 0xc000); break; + case 4: + case 5: + case 6: + case 7: mmu_set_ttr(regno, *regp & 0xffffe364); break; + case 0x800: regs.usp = *regp; break; + case 0x801: regs.vbr = *regp; break; + case 0x802: regs.caar = *regp & 0xfc; break; + case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; + case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; + case 0x805: mmu_set_mmusr(*regp); break; + case 0x806: regs.urp = *regp & MMU_ROOT_PTR_ADDR_MASK; break; + case 0x807: regs.srp = *regp & MMU_ROOT_PTR_ADDR_MASK; break; + default: + op_illg (0x4E7B); + return 0; } - return 1; + return 1; } int m68k_movec2 (int regno, uae_u32 *regp) { - if (movec_illg (regno)) - { - op_illg (0x4E7A); - return 0; - } else { - switch (regno) { - case 0: *regp = regs.sfc; break; - case 1: *regp = regs.dfc; break; - case 2: *regp = cacr; break; - case 3: *regp = tc; break; - case 4: *regp = itt0; break; - case 5: *regp = itt1; break; - case 6: *regp = dtt0; break; - case 7: *regp = dtt1; break; - case 0x800: *regp = regs.usp; break; - case 0x801: *regp = regs.vbr; break; - case 0x802: *regp = caar; break; - case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; - case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; - case 0x805: *regp = mmusr; break; - case 0x806: *regp = urp; break; - case 0x807: *regp = srp; break; - default: - op_illg (0x4E7A); - return 0; - } + switch (regno) { + case 0: *regp = regs.sfc; break; + case 1: *regp = regs.dfc; break; + case 2: *regp = regs.cacr; break; + case 3: *regp = regs.tc; break; + case 4: *regp = regs.itt0; break; + case 5: *regp = regs.itt1; break; + case 6: *regp = regs.dtt0; break; + case 7: *regp = regs.dtt1; break; + case 0x800: *regp = regs.usp; break; + case 0x801: *regp = regs.vbr; break; + case 0x802: *regp = regs.caar; break; + case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; + case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; + case 0x805: *regp = regs.mmusr; break; + case 0x806: *regp = regs.urp; break; + case 0x807: *regp = regs.srp; break; + default: + op_illg (0x4E7A); + return 0; } - return 1; + return 1; } -static __inline__ int +#if !defined(uae_s64) +static inline int div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) { uae_u32 q = 0, cbit = 0; int i; if (div <= src_hi) { - return 1; + return 1; } for (i = 0 ; i < 32 ; i++) { cbit = src_hi & 0x80000000ul; @@ -939,129 +703,131 @@ div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem = src_hi; return 0; } +#endif -void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc) +void m68k_divl (uae_u32 /*opcode*/, uae_u32 src, uae_u16 extra, uaecptr oldpc) { #if defined(uae_s64) - if (src == 0) { - Exception (5, oldpc); - return; - } - if (extra & 0x800) { - /* signed variant */ - uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); - uae_s64 quot, rem; + if (src == 0) { + Exception (5, oldpc); + return; + } + if (extra & 0x800) { + /* signed variant */ + uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); + uae_s64 quot, rem; - if (extra & 0x400) { - a &= 0xffffffffu; - a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32; - } - rem = a % (uae_s64)(uae_s32)src; - quot = a / (uae_s64)(uae_s32)src; - if ((quot & UVAL64(0xffffffff80000000)) != 0 - && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) - { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg(regs, extra & 7) = (uae_u32)rem; - m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)quot; - } + if (extra & 0x400) { + a &= 0xffffffffu; + a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32; + } + rem = a % (uae_s64)(uae_s32)src; + quot = a / (uae_s64)(uae_s32)src; + if ((quot & UVAL64(0xffffffff80000000)) != 0 + && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) + { + SET_VFLG (1); + SET_NFLG (1); + SET_CFLG (0); } else { - /* unsigned */ - uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); - uae_u64 quot, rem; - - if (extra & 0x400) { - a &= 0xffffffffu; - a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32; - } - rem = a % (uae_u64)src; - quot = a / (uae_u64)src; - if (quot > 0xffffffffu) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg(regs, extra & 7) = (uae_u32)rem; - m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)quot; - } + if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (((uae_s32)quot) == 0); + SET_NFLG (((uae_s32)quot) < 0); + m68k_dreg(regs, extra & 7) = rem; + m68k_dreg(regs, (extra >> 12) & 7) = quot; } + } else { + /* unsigned */ + uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); + uae_u64 quot, rem; + + if (extra & 0x400) { + a &= 0xffffffffu; + a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32; + } + rem = a % (uae_u64)src; + quot = a / (uae_u64)src; + if (quot > 0xffffffffu) { + SET_VFLG (1); + SET_NFLG (1); + SET_CFLG (0); + } else { + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (((uae_s32)quot) == 0); + SET_NFLG (((uae_s32)quot) < 0); + m68k_dreg(regs, extra & 7) = rem; + m68k_dreg(regs, (extra >> 12) & 7) = quot; + } + } #else - if (src == 0) { - Exception (5, oldpc); - return; - } - if (extra & 0x800) { - /* signed variant */ - uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); - uae_s32 hi = lo < 0 ? -1 : 0; - uae_s32 save_high; - uae_u32 quot, rem; - uae_u32 sign; + if (src == 0) { + Exception (5, oldpc); + return; + } + if (extra & 0x800) { + /* signed variant */ + uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); + uae_s32 hi = lo < 0 ? -1 : 0; + uae_s32 save_high; + uae_u32 quot, rem; + uae_u32 sign; - if (extra & 0x400) { - hi = (uae_s32)m68k_dreg(regs, extra & 7); - } - save_high = hi; - sign = (hi ^ src); - if (hi < 0) { - hi = ~hi; - lo = -lo; - if (lo == 0) hi++; - } - if ((uae_s32)src < 0) src = -src; - if (div_unsigned(hi, lo, src, ", &rem) || - (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - if (sign & 0x80000000) quot = -quot; - if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg(regs, extra & 7) = rem; - m68k_dreg(regs, (extra >> 12) & 7) = quot; - } + if (extra & 0x400) { + hi = (uae_s32)m68k_dreg(regs, extra & 7); + } + save_high = hi; + sign = (hi ^ src); + if (hi < 0) { + hi = ~hi; + lo = -lo; + if (lo == 0) hi++; + } + if ((uae_s32)src < 0) src = -src; + if (div_unsigned(hi, lo, src, ", &rem) || + (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { + SET_VFLG (1); + SET_NFLG (1); + SET_CFLG (0); } else { - /* unsigned */ - uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7); - uae_u32 hi = 0; - uae_u32 quot, rem; - - if (extra & 0x400) { - hi = (uae_u32)m68k_dreg(regs, extra & 7); - } - if (div_unsigned(hi, lo, src, ", &rem)) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg(regs, extra & 7) = rem; - m68k_dreg(regs, (extra >> 12) & 7) = quot; - } + if (sign & 0x80000000) quot = -quot; + if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (((uae_s32)quot) == 0); + SET_NFLG (((uae_s32)quot) < 0); + m68k_dreg(regs, extra & 7) = rem; + m68k_dreg(regs, (extra >> 12) & 7) = quot; } + } else { + /* unsigned */ + uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7); + uae_u32 hi = 0; + uae_u32 quot, rem; + + if (extra & 0x400) { + hi = (uae_u32)m68k_dreg(regs, extra & 7); + } + if (div_unsigned(hi, lo, src, ", &rem)) { + SET_VFLG (1); + SET_NFLG (1); + SET_CFLG (0); + } else { + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (((uae_s32)quot) == 0); + SET_NFLG (((uae_s32)quot) < 0); + m68k_dreg(regs, extra & 7) = rem; + m68k_dreg(regs, (extra >> 12) & 7) = quot; + } + } #endif } -static __inline__ void +#if !defined(uae_s64) +static inline void mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) { uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); @@ -1079,148 +845,198 @@ mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) *dst_lo = lo; *dst_hi = r3; } +#endif -void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) +void m68k_mull (uae_u32 /*opcode*/, uae_u32 src, uae_u16 extra) { #if defined(uae_s64) - if (extra & 0x800) { - /* signed variant */ - uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); + if (extra & 0x800) { + /* signed variant */ + uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); - a *= (uae_s64)(uae_s32)src; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (a == 0); - SET_NFLG (a < 0); - if (extra & 0x400) - m68k_dreg(regs, extra & 7) = a >> 32; - else if ((a & UVAL64(0xffffffff80000000)) != 0 - && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) - { - SET_VFLG (1); - } - m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; - } else { - /* unsigned */ - uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); - - a *= (uae_u64)src; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (a == 0); - SET_NFLG (((uae_s64)a) < 0); - if (extra & 0x400) - m68k_dreg(regs, extra & 7) = a >> 32; - else if ((a & UVAL64(0xffffffff00000000)) != 0) { - SET_VFLG (1); - } - m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; + a *= (uae_s64)(uae_s32)src; + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (a == 0); + SET_NFLG (a < 0); + if (extra & 0x400) + m68k_dreg(regs, extra & 7) = a >> 32; + else if ((a & UVAL64(0xffffffff80000000)) != 0 + && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) + { + SET_VFLG (1); } + m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; + } else { + /* unsigned */ + uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); + + a *= (uae_u64)src; + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (a == 0); + SET_NFLG (((uae_s64)a) < 0); + if (extra & 0x400) + m68k_dreg(regs, extra & 7) = a >> 32; + else if ((a & UVAL64(0xffffffff00000000)) != 0) { + SET_VFLG (1); + } + m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; + } #else - if (extra & 0x800) { - /* signed variant */ - uae_s32 src1,src2; - uae_u32 dst_lo,dst_hi; - uae_u32 sign; + if (extra & 0x800) { + /* signed variant */ + uae_s32 src1,src2; + uae_u32 dst_lo,dst_hi; + uae_u32 sign; - src1 = (uae_s32)src; - src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); - sign = (src1 ^ src2); - if (src1 < 0) src1 = -src1; - if (src2 < 0) src2 = -src2; - mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo); - if (sign & 0x80000000) { - dst_hi = ~dst_hi; - dst_lo = -dst_lo; - if (dst_lo == 0) dst_hi++; - } - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (dst_hi == 0 && dst_lo == 0); - SET_NFLG (((uae_s32)dst_hi) < 0); - if (extra & 0x400) - m68k_dreg(regs, extra & 7) = dst_hi; - else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) - && ((dst_hi & 0xffffffff) != 0xffffffff - || (dst_lo & 0x80000000) != 0x80000000)) - { - SET_VFLG (1); - } - m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; - } else { - /* unsigned */ - uae_u32 dst_lo,dst_hi; - - mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo); - - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (dst_hi == 0 && dst_lo == 0); - SET_NFLG (((uae_s32)dst_hi) < 0); - if (extra & 0x400) - m68k_dreg(regs, extra & 7) = dst_hi; - else if (dst_hi != 0) { - SET_VFLG (1); - } - m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; + src1 = (uae_s32)src; + src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); + sign = (src1 ^ src2); + if (src1 < 0) src1 = -src1; + if (src2 < 0) src2 = -src2; + mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo); + if (sign & 0x80000000) { + dst_hi = ~dst_hi; + dst_lo = -dst_lo; + if (dst_lo == 0) dst_hi++; } + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (dst_hi == 0 && dst_lo == 0); + SET_NFLG (((uae_s32)dst_hi) < 0); + if (extra & 0x400) + m68k_dreg(regs, extra & 7) = dst_hi; + else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) + && ((dst_hi & 0xffffffff) != 0xffffffff + || (dst_lo & 0x80000000) != 0x80000000)) + { + SET_VFLG (1); + } + m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; + } else { + /* unsigned */ + uae_u32 dst_lo,dst_hi; + + mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo); + + SET_VFLG (0); + SET_CFLG (0); + SET_ZFLG (dst_hi == 0 && dst_lo == 0); + SET_NFLG (((uae_s32)dst_hi) < 0); + if (extra & 0x400) + m68k_dreg(regs, extra & 7) = dst_hi; + else if (dst_hi != 0) { + SET_VFLG (1); + } + m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; + } #endif } -static const char* ccnames[] = -{ "T ","F ","HI","LS","CC","CS","NE","EQ", - "VC","VS","PL","MI","GE","LT","GT","LE" }; // If value is greater than zero, this means we are still processing an EmulOp // because the counter is incremented only in m68k_execute(), i.e. interpretive // execution only +#ifdef USE_JIT static int m68k_execute_depth = 0; +#endif void m68k_reset (void) { - m68k_areg (regs, 7) = 0x2000; - m68k_setpc (ROMBaseMac + 0x2a); - fill_prefetch_0 (); - regs.s = 1; - regs.m = 0; - regs.stopped = 0; - regs.t1 = 0; - regs.t0 = 0; - SET_ZFLG (0); - SET_XFLG (0); - SET_CFLG (0); - SET_VFLG (0); - SET_NFLG (0); - SPCFLAGS_INIT( 0 ); - regs.intmask = 7; - regs.vbr = regs.sfc = regs.dfc = 0; - fpu_reset(); + regs.s = 1; + regs.m = 0; + regs.stopped = 0; + regs.t1 = 0; + regs.t0 = 0; + SET_ZFLG (0); + SET_XFLG (0); + SET_CFLG (0); + SET_VFLG (0); + SET_NFLG (0); + SPCFLAGS_INIT( 0 ); + regs.intmask = 7; + regs.vbr = regs.sfc = regs.dfc = 0; -#if FLIGHT_RECORDER + // need to ensure the following order of initialization is correct + // (it is definitely better than what it was before this commit + // since it was reading from 0x00000000 in User mode and with active MMU) + mmu_set_tc(regs.tc & ~0x8000); /* disable mmu */ + m68k_areg (regs, 7) = phys_get_long(0x00000000); +#if 0 + m68k_setpc (phys_get_long(0x00000004)); +#else + m68k_setpc (ROMBaseMac + 0x2a); +#endif + fill_prefetch_0 (); + + /* gb-- moved into {fpp,fpu_x86}.cpp::fpu_init() + regs.fpcr = regs.fpsr = regs.fpiar = 0; */ + fpu_reset(); +#if 0 + // MMU + mmu_reset(); + mmu_set_super(1); + // Cache + regs.cacr = 0; + regs.caar = 0; +#endif +#ifdef FLIGHT_RECORDER log_ptr = 0; - memset(log, 0, sizeof(log)); -#endif - -#if ENABLE_MON - static bool first_time = true; - if (first_time) { - first_time = false; - mon_add_command("regs", dump_regs, "regs Dump m68k emulator registers\n"); -#if FLIGHT_RECORDER - // Install "log" command in mon - mon_add_command("log", dump_log, "log Dump m68k emulation log\n"); -#endif - } + memset(frlog, 0, sizeof(frlog)); #endif } void m68k_emulop_return(void) { SPCFLAGS_SET( SPCFLAG_BRK ); - quit_program = true; + quit_program = 1; +} + +static void save_regs(struct M68kRegisters &r) +{ + int i; + + for (i=0; i<8; i++) { + r.d[i] = m68k_dreg(regs, i); + r.a[i] = m68k_areg(regs, i); + } + r.pc = m68k_getpc(); + MakeSR(); + r.sr = regs.sr; + r.isp = regs.isp; + r.usp = regs.usp; + r.msp = regs.msp; + if ((r.sr & 0x2000) == 0) + r.usp = r.a[7]; + else if ((r.sr & 0x1000) != 0) + r.msp = r.a[7]; + else + r.isp = r.a[7]; +} + +static void restore_regs(struct M68kRegisters &r) +{ + int i; + + for (i=0; i<8; i++) { + m68k_dreg(regs, i) = r.d[i]; + m68k_areg(regs, i) = r.a[i]; + } + regs.isp = r.isp; + regs.usp = r.usp; + regs.msp = r.msp; + regs.sr = r.sr; + MakeFromSR(); } void m68k_emulop(uae_u32 opcode) { +#if 0 + struct M68kRegisters r; + save_regs(r); + if (EmulOp(opcode, &r)) + restore_regs(r); +#else struct M68kRegisters r; int i; @@ -1237,6 +1053,135 @@ void m68k_emulop(uae_u32 opcode) } regs.sr = r.sr; MakeFromSR(); +#endif +} + +#if 0 +void m68k_natfeat_id(void) +{ + struct M68kRegisters r; + + /* is it really necessary to save all registers? */ + save_regs(r); + + memptr stack = r.a[7] + 4; /* skip return address */ + r.d[0] = nf_get_id(stack); + + restore_regs(r); +} + +void m68k_natfeat_call(void) +{ + struct M68kRegisters r; + + /* is it really necessary to save all registers? */ + save_regs(r); + + memptr stack = r.a[7] + 4; /* skip return address */ + bool isSupervisorMode = ((r.sr & 0x2000) == 0x2000); + r.d[0] = nf_call(stack, isSupervisorMode); + + restore_regs(r); +} +#endif + +static int m68k_call(uae_u32 pc) +{ + VOLATILE int exc = 0; + m68k_setpc(pc); + TRY(prb) { +#ifdef USE_JIT + if (UseJIT) { + exec_nostats(); + // m68k_do_compile_execute(); + // The above call to m68k_do_compile_execute fails with BadAccess in sigsegv_handler (MAC, if it is executed after the first compile_block) + // (NULL pointer to addr_instr). + // Call exec_nostats avoids calling compile_block, because stack modification is only temporary + // which will fill up compile cache with BOGUS data. + // we can call exec_nostats directly, do our code, and return back here. + } + else +#endif + m68k_do_execute(); + } + CATCH(prb) { + exc = int(prb); + } + return exc; +} + +static uae_u32 m68k_alloca(int size) +{ + uae_u32 sp = (m68k_areg(regs, 7) - size) & ~1; + m68k_areg(regs, 7) = sp; + if ((regs.sr & 0x2000) == 0) + regs.usp = sp; + else if ((regs.sr & 0x1000) != 0) + regs.msp = sp; + else + regs.isp = sp; + return sp; +} + +#if 0 +uae_u32 linea68000(volatile uae_u16 opcode) +{ + sigjmp_buf jmp; + struct M68kRegisters r; + volatile uae_u32 abase = 0; + + SAVE_EXCEPTION; + save_regs(r); + + const int sz = 8 + sizeof(void *); + volatile uae_u32 sp = 0; + uae_u32 backup[(sz + 3) / 4]; + + if (sigsetjmp(jmp, 1) == 0) + { + void *p = jmp; + uae_u8 *sp_p; + int exc; + + sp = m68k_alloca(sz); + memcpy(backup, phys_get_real_address(sp), sz); + + WriteHWMemInt16(sp, opcode); + WriteHWMemInt16(sp + 2, 0xa0ff); + WriteHWMemInt32(sp + 4, 13); + sp_p = phys_get_real_address(sp + 8); + *((void **)sp_p) = p; + if ((exc = m68k_call(sp)) != 0) + { + panicbug("exception %d in LINEA", exc); + m68k_dreg(regs, 0) = 0; + } + } else + { + abase = m68k_dreg(regs, 0); + } + + if (sp) { + memcpy(phys_get_real_address(sp), backup, sz); + } + restore_regs(r); + m68k_setpc(r.pc); + RESTORE_EXCEPTION; + return abase; +} +#endif + + +static void rts68000() +{ + uae_u32 SP = m68k_getpc() + 6; + sigjmp_buf *p; + uae_u8 *sp_p = phys_get_real_address(SP); + + p = (sigjmp_buf *)(*((void **)sp_p)); + SP += sizeof(void *); + m68k_areg(regs, 7) = SP; + siglongjmp(*p, 1); } void REGPARAM2 op_illg (uae_u32 opcode) @@ -1244,6 +1189,19 @@ void REGPARAM2 op_illg (uae_u32 opcode) uaecptr pc = m68k_getpc (); if ((opcode & 0xF000) == 0xA000) { +#if 0 + if (opcode == 0xa0ff) + { + uae_u32 call = ReadHWMemInt32(pc + 2); + switch (call) + { + case 13: + rts68000(); + return; + } + m68k_setpc(pc + 6); + } +#endif Exception(0xA,0); return; } @@ -1253,8 +1211,8 @@ void REGPARAM2 op_illg (uae_u32 opcode) return; } - write_log ("Illegal instruction: %04x at %08x\n", opcode, pc); -#if USE_JIT && JIT_DEBUG + D(bug("Illegal instruction: %04x at %08x", opcode, pc)); +#if defined(USE_JIT) && defined(JIT_DEBUG) compiler_dumpstate(); #endif @@ -1262,62 +1220,119 @@ void REGPARAM2 op_illg (uae_u32 opcode) return; } -void mmu_op(uae_u32 opcode, uae_u16 extra) -{ - if ((opcode & 0xFE0) == 0x0500) { - /* PFLUSH */ - mmusr = 0; -#ifdef USE_JIT - flush_icache(); -#endif - } else if ((opcode & 0x0FD8) == 0x548) { - /* PTEST */ - } else - op_illg (opcode); -} - -static int n_insns = 0, n_spcinsns = 0; - static uaecptr last_trace_ad = 0; static void do_trace (void) { - if (regs.t0 && CPUType >= 2) { - uae_u16 opcode; - /* should also include TRAP, CHK, SR modification FPcc */ - /* probably never used so why bother */ - /* We can afford this to be inefficient... */ - m68k_setpc (m68k_getpc ()); - fill_prefetch_0 (); - opcode = get_word(m68k_getpc()); - if (opcode == 0x4e72 /* RTE */ - || opcode == 0x4e74 /* RTD */ - || opcode == 0x4e75 /* RTS */ - || opcode == 0x4e77 /* RTR */ - || opcode == 0x4e76 /* TRAPV */ - || (opcode & 0xffc0) == 0x4e80 /* JSR */ - || (opcode & 0xffc0) == 0x4ec0 /* JMP */ - || (opcode & 0xff00) == 0x6100 /* BSR */ - || ((opcode & 0xf000) == 0x6000 /* Bcc */ - && cctrue((opcode >> 8) & 0xf)) - || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ - && !cctrue((opcode >> 8) & 0xf) - && (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) - { - last_trace_ad = m68k_getpc (); - SPCFLAGS_CLEAR( SPCFLAG_TRACE ); - SPCFLAGS_SET( SPCFLAG_DOTRACE ); - } - } else if (regs.t1) { - last_trace_ad = m68k_getpc (); - SPCFLAGS_CLEAR( SPCFLAG_TRACE ); - SPCFLAGS_SET( SPCFLAG_DOTRACE ); + if (regs.t0) { + uae_u16 opcode; + /* should also include TRAP, CHK, SR modification FPcc */ + /* probably never used so why bother */ + /* We can afford this to be inefficient... */ + m68k_setpc (m68k_getpc ()); + fill_prefetch_0 (); + opcode = get_word(m68k_getpc()); + if (opcode == 0x4e72 /* RTE */ + || opcode == 0x4e74 /* RTD */ + || opcode == 0x4e75 /* RTS */ + || opcode == 0x4e77 /* RTR */ + || opcode == 0x4e76 /* TRAPV */ + || (opcode & 0xffc0) == 0x4e80 /* JSR */ + || (opcode & 0xffc0) == 0x4ec0 /* JMP */ + || (opcode & 0xff00) == 0x6100 /* BSR */ + || ((opcode & 0xf000) == 0x6000 /* Bcc */ + && cctrue((opcode >> 8) & 0xf)) + || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ + && !cctrue((opcode >> 8) & 0xf) + && (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) + { + last_trace_ad = m68k_getpc (); + SPCFLAGS_CLEAR( SPCFLAG_TRACE ); + SPCFLAGS_SET( SPCFLAG_DOTRACE ); } + } else if (regs.t1) { + last_trace_ad = m68k_getpc (); + SPCFLAGS_CLEAR( SPCFLAG_TRACE ); + SPCFLAGS_SET( SPCFLAG_DOTRACE ); + } } -int m68k_do_specialties (void) +#if 0 +#define SERVE_VBL_MFP(resetStop) \ +{ \ + if (SPCFLAGS_TEST( SPCFLAG_INT3|SPCFLAG_VBL|SPCFLAG_INT5|SPCFLAG_SCC|SPCFLAG_MFP )) { \ + if (SPCFLAGS_TEST( SPCFLAG_INT3 )) { \ + if (3 > regs.intmask) { \ + Interrupt(3); \ + regs.stopped = 0; \ + SPCFLAGS_CLEAR( SPCFLAG_INT3 ); \ + if (resetStop) \ + SPCFLAGS_CLEAR( SPCFLAG_STOP ); \ + } \ + } \ + if (SPCFLAGS_TEST( SPCFLAG_VBL )) { \ + if (4 > regs.intmask) { \ + Interrupt(4); \ + regs.stopped = 0; \ + SPCFLAGS_CLEAR( SPCFLAG_VBL ); \ + if (resetStop) \ + SPCFLAGS_CLEAR( SPCFLAG_STOP ); \ + } \ + } \ + if (SPCFLAGS_TEST( SPCFLAG_INT5 )) { \ + if (5 > regs.intmask) { \ + Interrupt(5); \ + regs.stopped = 0; \ + SPCFLAGS_CLEAR( SPCFLAG_INT5 ); \ + if (resetStop) \ + SPCFLAGS_CLEAR( SPCFLAG_STOP ); \ + } \ + } \ + if (SPCFLAGS_TEST( SPCFLAG_SCC )) { \ + if (5 > regs.intmask) { \ + int vector_number=SCCdoInterrupt(); \ + if(vector_number){ \ + SCCInterrupt(vector_number); \ + regs.stopped = 0; \ + SPCFLAGS_CLEAR( SPCFLAG_SCC); \ + if (resetStop) \ + SPCFLAGS_CLEAR( SPCFLAG_STOP ); \ + } \ + else \ + SPCFLAGS_CLEAR( SPCFLAG_SCC ); \ + } \ + } \ + if (SPCFLAGS_TEST( SPCFLAG_MFP )) { \ + if (6 > regs.intmask) { \ + int vector_number = MFPdoInterrupt(); \ + if (vector_number) { \ + MFPInterrupt(vector_number); \ + regs.stopped = 0; \ + if (resetStop) \ + SPCFLAGS_CLEAR( SPCFLAG_STOP ); \ + } \ + else \ + SPCFLAGS_CLEAR( SPCFLAG_MFP ); \ + } \ + } \ + } \ +} + +#define SERVE_INTERNAL_IRQ() \ +{ \ + if (SPCFLAGS_TEST( SPCFLAG_INTERNAL_IRQ )) { \ + SPCFLAGS_CLEAR( SPCFLAG_INTERNAL_IRQ ); \ + invoke200HzInterrupt(); \ + } \ +} +#endif + +int m68k_do_specialties(void) { -#if USE_JIT +#if 0 + SERVE_INTERNAL_IRQ(); +#endif +#ifdef USE_JIT // Block was compiled SPCFLAGS_CLEAR( SPCFLAG_JIT_END_COMPILE ); @@ -1328,11 +1343,39 @@ int m68k_do_specialties (void) if ((m68k_execute_depth == 0) && SPCFLAGS_TEST( SPCFLAG_JIT_EXEC_RETURN )) SPCFLAGS_CLEAR( SPCFLAG_JIT_EXEC_RETURN ); #endif - + /*n_spcinsns++;*/ if (SPCFLAGS_TEST( SPCFLAG_DOTRACE )) { Exception (9,last_trace_ad); } +#if 0 /* not for ARAnyM; emulating 040 only */ + if ((regs.spcflags & SPCFLAG_STOP) && 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. + m68k_unset_stop(); + Exception(8, 0); + } +#endif while (SPCFLAGS_TEST( SPCFLAG_STOP )) { + //TODO: Check +#if 0 + if ((regs.sr & 0x700) == 0x700) + { + panicbug("STOPed with interrupts disabled, exiting; pc=$%08x", m68k_getpc()); + m68k_dumpstate (stderr, NULL); + quit_program = 1; +#ifdef FULL_HISTORY + ndebug::showHistory(20, false); + m68k_dumpstate (stderr, NULL); +#endif + return 1; + } +#endif +#if 0 + // give unused time slices back to OS + SleepAndWait(); +#endif if (SPCFLAGS_TEST( SPCFLAG_INT | SPCFLAG_DOINT )){ SPCFLAGS_CLEAR( SPCFLAG_INT | SPCFLAG_DOINT ); int intr = intlev (); @@ -1342,10 +1385,30 @@ int m68k_do_specialties (void) SPCFLAGS_CLEAR( SPCFLAG_STOP ); } } + +#if 0 + SERVE_INTERNAL_IRQ(); + SERVE_VBL_MFP(true); +#endif +#if 0 + if (SPCFLAGS_TEST( SPCFLAG_BRK )) + break; +#endif } if (SPCFLAGS_TEST( SPCFLAG_TRACE )) do_trace (); +#if 0 + SERVE_VBL_MFP(false); +#endif + +/* +// do not understand the INT vs DOINT stuff so I disabled it (joy) + if (regs.spcflags & SPCFLAG_INT) { + regs.spcflags &= ~SPCFLAG_INT; + regs.spcflags |= SPCFLAG_DOINT; + } +*/ if (SPCFLAGS_TEST( SPCFLAG_DOINT )) { SPCFLAGS_CLEAR( SPCFLAG_DOINT ); int intr = intlev (); @@ -1354,159 +1417,213 @@ int m68k_do_specialties (void) regs.stopped = 0; } } + if (SPCFLAGS_TEST( SPCFLAG_INT )) { SPCFLAGS_CLEAR( SPCFLAG_INT ); SPCFLAGS_SET( SPCFLAG_DOINT ); } - if (SPCFLAGS_TEST( SPCFLAG_BRK )) { - SPCFLAGS_CLEAR( SPCFLAG_BRK ); + + if (SPCFLAGS_TEST( SPCFLAG_BRK /*| SPCFLAG_MODE_CHANGE*/ )) { + SPCFLAGS_CLEAR( SPCFLAG_BRK /*| SPCFLAG_MODE_CHANGE*/ ); return 1; } + return 0; } void m68k_do_execute (void) { - for (;;) { - uae_u32 opcode = GET_OPCODE; -#if FLIGHT_RECORDER - m68k_record_step(m68k_getpc()); + uae_u32 pc; + uae_u32 opcode; + for (;;) { + regs.fault_pc = pc = m68k_getpc(); +#ifdef FULL_HISTORY +#ifdef NEED_TO_DEBUG_BADLY + history[lasthist] = regs; + historyf[lasthist] = regflags; +#else + history[lasthist] = m68k_getpc(); #endif - (*cpufunctbl[opcode])(opcode); - cpu_check_ticks(); - if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) { - if (m68k_do_specialties()) - return; - } + if (++lasthist == MAX_HIST) lasthist = 0; + if (lasthist == firsthist) { + if (++firsthist == MAX_HIST) firsthist = 0; } +#endif + +#ifndef FULLMMU +#ifdef ARAM_PAGE_CHECK + if (((pc ^ pc_page) > ARAM_PAGE_MASK)) { + check_ram_boundary(pc, 2, false); + pc_page = pc; + pc_offset = (uintptr)get_real_address(pc, 0, sz_word) - pc; + } +#else + check_ram_boundary(pc, 2, false); +#endif +#endif + opcode = GET_OPCODE; +#ifdef FLIGHT_RECORDER + m68k_record_step(m68k_getpc(), cft_map(opcode)); +#endif + (*cpufunctbl[opcode])(opcode); + cpu_check_ticks(); + regs.fault_pc = m68k_getpc(); + + if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) { + if (m68k_do_specialties()) + return; + } + } } void m68k_execute (void) { -#if USE_JIT - ++m68k_execute_depth; +#ifdef USE_JIT + m68k_execute_depth++; #endif +#ifdef DEBUGGER + VOLATILE bool after_exception = false; +#endif + +setjmpagain: + TRY(prb) { for (;;) { - if (quit_program) - break; - m68k_do_execute(); + if (quit_program > 0) { + if (quit_program == 1) { +#ifdef FLIGHT_RECORDER + dump_flight_recorder(); +#endif + break; + } + quit_program = 0; + m68k_reset (); + } +#ifdef DEBUGGER + if (debugging && !after_exception) debug(); + after_exception = false; +#endif + m68k_do_execute(); } -#if USE_JIT - --m68k_execute_depth; + } + CATCH(prb) { + Exception(prb, 0); +#ifdef DEBUGGER + after_exception = true; +#endif + goto setjmpagain; + } + +#ifdef USE_JIT + m68k_execute_depth--; #endif } -static void m68k_verify (uaecptr addr, uaecptr *nextpc) +void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt) { - uae_u32 opcode, val; - struct instr *dp; +#ifdef HAVE_DISASM_M68K + char buf[256]; + int size; - opcode = get_iword_1(0); - last_op_for_exception_3 = opcode; - m68kpc_offset = 2; - - if (cpufunctbl[cft_map (opcode)] == op_illg_1) { - opcode = 0x4AFC; - } - dp = table68k + opcode; - - if (dp->suse) { - if (!verify_ea (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, &val)) { - Exception (3, 0); - return; - } - } - if (dp->duse) { - if (!verify_ea (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, &val)) { - Exception (3, 0); - return; - } + disasm_info.memory_vma = addr; + while (cnt-- > 0) { + size = m68k_disasm_to_buf(&disasm_info, buf, 1); + fprintf(f, "%s\n", buf); + if (size < 0) + break; } + if (nextpc) + *nextpc = disasm_info.memory_vma; +#else + if (nextpc) + *nextpc = addr; + (void) f; + (void) cnt; +#endif } -void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt) +#ifdef DEBUGGER +void newm68k_disasm(FILE *f, uaecptr addr, uaecptr *nextpc, unsigned int cnt) { - uaecptr newpc = 0; - m68kpc_offset = addr - m68k_getpc (); - while (cnt-- > 0) { - char instrname[20],*ccpt; - int opwords; - uae_u32 opcode; - struct mnemolookup *lookup; - struct instr *dp; - printf ("%08lx: ", m68k_getpc () + m68kpc_offset); - for (opwords = 0; opwords < 5; opwords++){ - printf ("%04x ", get_iword_1 (m68kpc_offset + opwords*2)); - } - opcode = get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - if (cpufunctbl[cft_map (opcode)] == op_illg_1) { - opcode = 0x4AFC; - } - dp = table68k + opcode; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) - ; +#ifdef HAVE_DISASM_M68K + char buf[256]; - strcpy (instrname, lookup->name); - ccpt = strstr (instrname, "cc"); - if (ccpt != 0) { - strncpy (ccpt, ccnames[dp->cc], 2); - } - printf ("%s", instrname); - switch (dp->size){ - case sz_byte: printf (".B "); break; - case sz_word: printf (".W "); break; - case sz_long: printf (".L "); break; - default: printf (" "); break; - } - - if (dp->suse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0); - } - if (dp->suse && dp->duse) - printf (","); - if (dp->duse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 0); - } - if (ccpt != 0) { - if (cctrue(dp->cc)) - printf (" == %08x (TRUE)", newpc); - else - printf (" == %08x (FALSE)", newpc); - } else if ((opcode & 0xff00) == 0x6100) /* BSR */ - printf (" == %08x", newpc); - printf ("\n"); - } - if (nextpc) - *nextpc = m68k_getpc () + m68kpc_offset; + disasm_info.memory_vma = addr; + if (cnt == 0) { + m68k_disasm_to_buf(&disasm_info, buf, 1); + } else { + while (cnt-- > 0) { + m68k_disasm_to_buf(&disasm_info, buf, 1); + fprintf(f, "%s\n", buf); + } + } + if (nextpc) + *nextpc = disasm_info.memory_vma; +#else + if (nextpc) + *nextpc = addr; + (void) cnt; +#endif } -void m68k_dumpstate (uaecptr *nextpc) -{ - int i; - for (i = 0; i < 8; i++){ - printf ("D%d: %08x ", i, m68k_dreg(regs, i)); - if ((i & 3) == 3) printf ("\n"); - } - for (i = 0; i < 8; i++){ - printf ("A%d: %08x ", i, m68k_areg(regs, i)); - if ((i & 3) == 3) printf ("\n"); - } - if (regs.s == 0) regs.usp = m68k_areg(regs, 7); - if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7); - if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7); - printf ("USP=%08x ISP=%08x MSP=%08x VBR=%08x\n", - regs.usp,regs.isp,regs.msp,regs.vbr); - printf ("T=%d%d S=%d M=%d X=%ld N=%ld Z=%ld V=%ld C=%ld IMASK=%d\n", - regs.t1, regs.t0, regs.s, regs.m, - GET_XFLG(), GET_NFLG(), GET_ZFLG(), GET_VFLG(), GET_CFLG(), regs.intmask); +#endif /* DEBUGGER */ - fpu_dump_registers(); - fpu_dump_flags(); +#ifdef FULL_HISTORY +void showDisasm(uaecptr addr) { +#ifdef HAVE_DISASM_M68K + char buf[256]; - m68k_disasm(m68k_getpc (), nextpc, 1); - if (nextpc) - printf ("next PC: %08x\n", *nextpc); + disasm_info.memory_vma = addr; + m68k_disasm_to_buf(&disasm_info, buf, 1); + bug("%s", buf); +#else + (void) addr; +#endif +} +#endif /* FULL_HISTORY */ + +void m68k_dumpstate (FILE *out, uaecptr *nextpc) +{ + int i; + for (i = 0; i < 8; i++){ + fprintf (out, "D%d: %08lx ", i, (unsigned long)m68k_dreg(regs, i)); + if ((i & 3) == 3) fprintf (out, "\n"); + } + for (i = 0; i < 8; i++){ + fprintf (out, "A%d: %08lx ", i, (unsigned long)m68k_areg(regs, i)); + if ((i & 3) == 3) fprintf (out, "\n"); + } + if (regs.s == 0) regs.usp = m68k_areg(regs, 7); + if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7); + if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7); + fprintf (out, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n", + (unsigned long)regs.usp, (unsigned long)regs.isp, + (unsigned long)regs.msp, (unsigned long)regs.vbr); + fprintf (out, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d TCE=%d TCP=%d\n", + regs.t1, regs.t0, regs.s, regs.m, + (int)GET_XFLG(), (int)GET_NFLG(), (int)GET_ZFLG(), (int)GET_VFLG(), (int)GET_CFLG(), regs.intmask, + regs.mmu_enabled, regs.mmu_pagesize_8k); + fprintf (out, "CACR=%08lx CAAR=%08lx URP=%08lx SRP=%08lx\n", + (unsigned long)regs.cacr, + (unsigned long)regs.caar, + (unsigned long)regs.urp, + (unsigned long)regs.srp); + fprintf (out, "DTT0=%08lx DTT1=%08lx ITT0=%08lx ITT1=%08lx\n", + (unsigned long)regs.dtt0, + (unsigned long)regs.dtt1, + (unsigned long)regs.itt0, + (unsigned long)regs.itt1); + for (i = 0; i < 8; i++){ + fprintf (out, "FP%d: %g ", i, (double)fpu.registers[i]); + if ((i & 3) == 3) fprintf (out, "\n"); + } +#if 0 + fprintf (out, "N=%d Z=%d I=%d NAN=%d\n", + (regs.fpsr & 0x8000000) != 0, + (regs.fpsr & 0x4000000) != 0, + (regs.fpsr & 0x2000000) != 0, + (regs.fpsr & 0x1000000) != 0); +#endif + m68k_disasm(out, m68k_getpc (), nextpc, 1); + if (nextpc) + fprintf (out, "next PC: %08lx\n", (unsigned long)*nextpc); } diff --git a/BasiliskII/src/uae_cpu/newcpu.h b/BasiliskII/src/uae_cpu/newcpu.h index 97731f59..13a51b82 100644 --- a/BasiliskII/src/uae_cpu/newcpu.h +++ b/BasiliskII/src/uae_cpu/newcpu.h @@ -1,41 +1,51 @@ /* - * UAE - The Un*x Amiga Emulator + * newcpu.h - CPU emulation * - * MC68000 emulation + * Copyright (c) 2009 ARAnyM dev team (see AUTHORS) + * + * Inspired by Christian Bauer's Basilisk II * - * Copyright 1995 Bernd Schmidt + * This file is part of the ARAnyM project which builds a new and powerful + * TOS/FreeMiNT compatible virtual machine running on almost any hardware. * - * This program is free software; you can redistribute it and/or modify + * ARAnyM is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * ARAnyM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with ARAnyM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * Copyright 1995 Bernd Schmidt + */ #ifndef NEWCPU_H #define NEWCPU_H -#ifndef FLIGHT_RECORDER -#define FLIGHT_RECORDER 0 -#endif - -#include "m68k.h" -#include "readcpu.h" +#include "sysdeps.h" +#include "registers.h" #include "spcflags.h" +#include "m68k.h" +#include "memory.h" -#if ENABLE_MON -#include "mon.h" -#include "mon_disass.h" -#endif +# include +extern struct fixup { + int flag; + uae_u32 reg; + uaecptr value; +}fixup; extern int areg_byteinc[]; extern int imm8_table[]; @@ -57,27 +67,25 @@ extern int broken_in; #endif #define cpuop_begin() do { cpuop_tag("begin"); } while (0) -#define cpuop_end() do { cpuop_tag("end"); } while (0) +#define cpuop_end() do { cpuop_tag("end"); } while (0) typedef void REGPARAM2 cpuop_func (uae_u32) REGPARAM; - + struct cputbl { cpuop_func *handler; uae_u16 specific; uae_u16 opcode; }; -extern cpuop_func *cpufunctbl[65536] ASM_SYM("cpufunctbl"); +extern cpuop_func *cpufunctbl[65536]; -#if USE_JIT +#ifdef USE_JIT typedef void compop_func (uae_u32) REGPARAM; -//NOTE: The "opcode" and "specific" fields were switched in the original source code! - struct comptbl { compop_func *handler; - uae_u32 opcode; - uae_u32 specific; + uae_u32 opcode; + uae_u32 specific; #define COMP_OPCODE_ISJUMP 0x0001 #define COMP_OPCODE_LONG_OPCODE 0x0002 #define COMP_OPCODE_CMOV 0x0004 @@ -88,151 +96,84 @@ struct comptbl { #endif extern void REGPARAM2 op_illg (uae_u32) REGPARAM; -extern void m68k_dumpstate(uaecptr *nextpc); - -typedef char flagtype; - -// struct regstruct { -// uae_u32 regs[16]; - -// uae_u32 pc; -// uae_u8 * pc_p; -// uae_u8 * pc_oldp; - -// spcflags_t spcflags; -// int intmask; - -// uae_u32 vbr, sfc, dfc; -// uaecptr usp, isp, msp; -// uae_u16 sr; -// flagtype t1; -// flagtype t0; -// flagtype s; -// flagtype m; -// flagtype x; -// flagtype stopped; - -// #if USE_PREFETCH_BUFFER -// /* Fellow sources say this is 4 longwords. That's impossible. It needs -// * to be at least a longword. The HRM has some cryptic comment about two -// * instructions being on the same longword boundary. -// * The way this is implemented now seems like a good compromise. -// */ -// uae_u32 prefetch; -// #endif -// }; - -struct regstruct -{ - uae_u32 regs[16]; - uaecptr usp,isp,msp; - uae_u16 sr; - flagtype t1; - flagtype t0; - flagtype s; - flagtype m; - flagtype x; - flagtype stopped; - int intmask; - - uae_u32 pc; - uae_u32 fault_pc; - uae_u8 *pc_p; - uae_u8 *pc_oldp; - - uae_u32 vbr,sfc,dfc; - - volatile uae_u32 spcflags; - -#if 1 - uae_u32 kick_mask; - - /* Fellow sources say this is 4 longwords. That's impossible. It needs - * to be at least a longword. The HRM has some cryptic comment about two - * instructions being on the same longword boundary. - * The way this is implemented now seems like a good compromise. - */ - uae_u32 prefetch; -#endif - - /* MMU reg*/ - uae_u32 urp,srp; - uae_u32 tc; - - int mmu_enabled; /* flagtype tce; */ - int mmu_pagesize_8k; /* flagtype tcp; */ - - uae_u32 dtt0,dtt1,itt0,itt1; - uae_u32 mmusr; - - uae_u32 mmu_fslw, mmu_fault_addr; - uae_u16 mmu_ssw; - uae_u32 wb3_data; - uae_u16 wb3_status; - - /* Cache reg*/ - uae_u32 cacr,caar; -}; - -extern regstruct regs, lastint_regs; #define m68k_dreg(r,num) ((r).regs[(num)]) #define m68k_areg(r,num) (((r).regs + 8)[(num)]) -#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1)) -#define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o))) -#define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o))) +#ifdef FULLMMU +static ALWAYS_INLINE uae_u8 get_ibyte(uae_u32 o) +{ + return mmu_get_byte(m68k_getpc() + o + 1, 0, sz_byte); +} +static ALWAYS_INLINE uae_u16 get_iword(uae_u32 o) +{ + return mmu_get_word(m68k_getpc() + o, 0, sz_word); +} +static ALWAYS_INLINE uae_u32 get_ilong(uae_u32 o) +{ + uaecptr addr = m68k_getpc() + o; + + if (unlikely(is_unaligned(addr, 4))) + return mmu_get_long_unaligned(addr, 0); + return mmu_get_long(addr, 0, sz_long); +} -#ifdef HAVE_GET_WORD_UNSWAPPED -#define GET_OPCODE (do_get_mem_word_unswapped (regs.pc_p)) #else -#define GET_OPCODE (get_iword (0)) +#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(get_real_address(m68k_getpc(), 0, sz_byte) + (o) + 1)) +#define get_iword(o) do_get_mem_word((uae_u16 *)(get_real_address(m68k_getpc(), 0, sz_word) + (o))) +#define get_ilong(o) do_get_mem_long((uae_u32 *)(get_real_address(m68k_getpc(), 0, sz_long) + (o))) #endif -#if USE_PREFETCH_BUFFER -static __inline__ uae_u32 get_ibyte_prefetch (uae_s32 o) +#if 0 +static inline uae_u32 get_ibyte_prefetch (uae_s32 o) { if (o > 3 || o < 0) - return do_get_mem_byte((uae_u8 *)(regs.pc_p + o + 1)); + return do_get_mem_byte((uae_u8 *)(do_get_real_address(regs.pcp, false, false) + o + 1)); return do_get_mem_byte((uae_u8 *)(((uae_u8 *)®s.prefetch) + o + 1)); } -static __inline__ uae_u32 get_iword_prefetch (uae_s32 o) +static inline uae_u32 get_iword_prefetch (uae_s32 o) { if (o > 3 || o < 0) - return do_get_mem_word((uae_u16 *)(regs.pc_p + o)); + return do_get_mem_word((uae_u16 *)(do_get_real_address(regs.pcp, false, false) + o)); return do_get_mem_word((uae_u16 *)(((uae_u8 *)®s.prefetch) + o)); } -static __inline__ uae_u32 get_ilong_prefetch (uae_s32 o) +static inline uae_u32 get_ilong_prefetch (uae_s32 o) { if (o > 3 || o < 0) - return do_get_mem_long((uae_u32 *)(regs.pc_p + o)); + return do_get_mem_long((uae_u32 *)(do_get_real_address(regs.pcp, false, false) + o)); if (o == 0) return do_get_mem_long(®s.prefetch); - return (do_get_mem_word (((uae_u16 *)®s.prefetch) + 1) << 16) | do_get_mem_word ((uae_u16 *)(regs.pc_p + 4)); + return (do_get_mem_word (((uae_u16 *)®s.prefetch) + 1) << 16) | do_get_mem_word ((uae_u16 *)(do_get_real_address(regs.pcp, false, false) + 4)); } #endif -static __inline__ void fill_prefetch_0 (void) +#ifdef FULLMMU +#define m68k_incpc(o) (regs.pc += (o)) +#else +#define m68k_incpc(o) (regs.pc_p += (o)) +#endif + +static inline void fill_prefetch_0 (void) { #if USE_PREFETCH_BUFFER uae_u32 r; #ifdef UNALIGNED_PROFITABLE - r = *(uae_u32 *)regs.pc_p; + r = *(uae_u32 *)do_get_real_address(m68k_getpc(), false, false); regs.prefetch = r; #else - r = do_get_mem_long ((uae_u32 *)regs.pc_p); + r = do_get_mem_long ((uae_u32 *)do_get_real_address(m68k_getpc(), false, false)); do_put_mem_long (®s.prefetch, r); #endif #endif } #if 0 -static __inline__ void fill_prefetch_2 (void) +static inline void fill_prefetch_2 (void) { uae_u32 r = do_get_mem_long (®s.prefetch) << 16; - uae_u32 r2 = do_get_mem_word (((uae_u16 *)regs.pc_p) + 1); + uae_u32 r2 = do_get_mem_word (((uae_u16 *)do_get_real_address(regs.pcp, false, false)) + 1); r |= r2; do_put_mem_long (®s.prefetch, r); } @@ -240,115 +181,92 @@ static __inline__ void fill_prefetch_2 (void) #define fill_prefetch_2 fill_prefetch_0 #endif -static __inline__ uaecptr m68k_getpc (void) -{ -#if REAL_ADDRESSING || DIRECT_ADDRESSING - return get_virtual_address(regs.pc_p); -#else - return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp); -#endif -} - -static __inline__ void m68k_setpc (uaecptr newpc) -{ -#if ENABLE_MON - uae_u32 previous_pc = m68k_getpc(); -#endif - -#if REAL_ADDRESSING || DIRECT_ADDRESSING - regs.pc_p = get_real_address(newpc); -#else - regs.pc_p = regs.pc_oldp = get_real_address(newpc); - regs.pc = newpc; -#endif - -#if ENABLE_MON - if (IS_BREAK_POINT(newpc)) { - printf("Stopped at break point address: %08x. Last PC: %08x\n", newpc, previous_pc); - m68k_dumpstate(NULL); - const char *arg[4] = {"mon", "-m", "-r", NULL}; - mon(3, arg); - } -#endif // end of #if ENABLE_MON -} - -static __inline__ void m68k_incpc (uae_s32 delta) -{ -#if ENABLE_MON - uae_u32 previous_pc = m68k_getpc(); -#endif - regs.pc_p += (delta); -#if ENABLE_MON - uaecptr next_pc = m68k_getpc(); - if (IS_BREAK_POINT(next_pc)) { - printf("Stopped at break point address: %08x. Last PC: %08x\n", next_pc, previous_pc); - m68k_dumpstate(NULL); - const char *arg[4] = {"mon", "-m", "-r", NULL}; - mon(3, arg); - } -#endif // end of #if ENABLE_MON -} - /* These are only used by the 68020/68881 code, and therefore don't * need to handle prefetch. */ -static __inline__ uae_u32 next_ibyte (void) +static inline uae_u32 next_ibyte (void) { uae_u32 r = get_ibyte (0); m68k_incpc (2); return r; } -static __inline__ uae_u32 next_iword (void) +static inline uae_u32 next_iword (void) { uae_u32 r = get_iword (0); m68k_incpc (2); return r; } -static __inline__ uae_u32 next_ilong (void) +static inline uae_u32 next_ilong (void) { uae_u32 r = get_ilong (0); m68k_incpc (4); return r; } +static inline void m68k_setpc (uaecptr newpc) +{ +#ifndef FULLMMU + regs.pc_p = regs.pc_oldp = get_real_address(newpc, 0, sz_word); +#endif + regs.fault_pc = regs.pc = newpc; +} + #define m68k_setpc_fast m68k_setpc #define m68k_setpc_bcc m68k_setpc #define m68k_setpc_rte m68k_setpc -static __inline__ void m68k_do_rts(void) +static inline void m68k_do_rts(void) { - m68k_setpc(get_long(m68k_areg(regs, 7))); - m68k_areg(regs, 7) += 4; + m68k_setpc(get_long(m68k_areg(regs, 7))); + m68k_areg(regs, 7) += 4; } -static __inline__ void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) +static inline void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) { - m68k_areg(regs, 7) -= 4; - put_long(m68k_areg(regs, 7), oldpc); - m68k_incpc(offset); + put_long(m68k_areg(regs, 7) - 4, oldpc); + m68k_areg(regs, 7) -= 4; + m68k_incpc(offset); } -static __inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest) +static inline void m68k_do_jsr(uaecptr oldpc, uaecptr dest) { - m68k_areg(regs, 7) -= 4; - put_long(m68k_areg(regs, 7), oldpc); - m68k_setpc(dest); + put_long(m68k_areg(regs, 7) - 4, oldpc); + m68k_areg(regs, 7) -= 4; + m68k_setpc(dest); } -static __inline__ void m68k_setstopped (int stop) +static inline void m68k_setstopped (int stop) { regs.stopped = stop; /* A traced STOP instruction drops through immediately without actually stopping. */ - if (stop && (regs.spcflags & SPCFLAG_DOTRACE) == 0) - SPCFLAGS_SET( SPCFLAG_STOP ); + if (stop && !( SPCFLAGS_TEST( SPCFLAG_DOTRACE ))) + SPCFLAGS_SET( SPCFLAG_STOP ); } -extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp); -extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp); +#ifdef FULLMMU +# define GET_OPCODE (get_iword (0)) +#elif defined ARAM_PAGE_CHECK +# ifdef HAVE_GET_WORD_UNSWAPPED +# define GET_OPCODE (do_get_mem_word_unswapped((uae_u16*)(pc + pc_offset))); +# else +# define GET_OPCODE (do_get_mem_word((uae_u16*)(pc + pc_offset))); +# endif +#else +# ifdef HAVE_GET_WORD_UNSWAPPED +# define GET_OPCODE (do_get_mem_word_unswapped ((uae_u16*)get_real_address(m68k_getpc(), 0, sz_word))) +# else +# define GET_OPCODE (get_iword (0)) +# endif +#endif + +extern REGPARAM uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp); +extern REGPARAM uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp); +extern REGPARAM uae_u32 get_bitfield(uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width); +extern REGPARAM void put_bitfield(uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width); + -extern uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf); extern void MakeSR (void); extern void MakeFromSR (void); @@ -360,15 +278,19 @@ extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr); extern void m68k_mull (uae_u32, uae_u32, uae_u16); extern void m68k_emulop (uae_u32); extern void m68k_emulop_return (void); +extern void m68k_natfeat_id(void); +extern void m68k_natfeat_call(void); extern void init_m68k (void); extern void exit_m68k (void); -extern void m68k_dumpstate (uaecptr *); -extern void m68k_disasm (uaecptr, uaecptr *, int); +extern void m68k_dumpstate (FILE *, uaecptr *); +extern void m68k_disasm (FILE *, uaecptr, uaecptr *, int); +extern void newm68k_disasm(FILE *, uaecptr, uaecptr *, unsigned int); +extern void showDisasm(uaecptr); extern void m68k_reset (void); extern void m68k_enter_debugger(void); extern int m68k_do_specialties(void); - -extern void mmu_op (uae_u32, uae_u16); +extern void m68k_instr_set(void); +uae_u32 linea68000(uae_u16 opcode); /* Opcode of faulting instruction */ extern uae_u16 last_op_for_exception_3; @@ -379,24 +301,19 @@ extern uaecptr last_fault_for_exception_3; #define CPU_OP_NAME(a) op ## a -/* 68020 + 68881 */ -extern struct cputbl op_smalltbl_0_ff[]; -/* 68020 */ -extern struct cputbl op_smalltbl_1_ff[]; -/* 68010 */ -extern struct cputbl op_smalltbl_2_ff[]; -/* 68000 */ -extern struct cputbl op_smalltbl_3_ff[]; -/* 68000 slow but compatible. */ -extern struct cputbl op_smalltbl_4_ff[]; +/* 68040+ 68881 */ +extern const struct cputbl op_smalltbl_0_ff[]; +extern const struct cputbl op_smalltbl_0_nf[]; -#if FLIGHT_RECORDER -extern void m68k_record_step(uaecptr) REGPARAM; +#ifdef FLIGHT_RECORDER +extern void m68k_record_step(uaecptr, int); #endif + extern void m68k_do_execute(void); extern void m68k_execute(void); -#if USE_JIT +#ifdef USE_JIT extern void m68k_compile_execute(void); +extern void m68k_do_compile_execute(void); #endif #ifdef USE_CPU_EMUL_SERVICES extern int32 emulated_ticks; @@ -411,5 +328,7 @@ static inline void cpu_check_ticks(void) #define cpu_check_ticks() #define cpu_do_check_ticks() #endif - + +cpuop_func op_illg_1; + #endif /* NEWCPU_H */ diff --git a/BasiliskII/src/uae_cpu/noflags.h b/BasiliskII/src/uae_cpu/noflags.h index e87d22b4..e3b7a3a5 100644 --- a/BasiliskII/src/uae_cpu/noflags.h +++ b/BasiliskII/src/uae_cpu/noflags.h @@ -33,13 +33,13 @@ #define NOFLAGS_CMP 0 #undef SET_NFLG_ALWAYS -static __inline__ void SET_NFLG_ALWAYS(uae_u32 x) +static inline void SET_NFLG_ALWAYS(uae_u32 x) { SET_NFLG(x); /* This has not yet been redefined */ } #undef SET_CFLG_ALWAYS -static __inline__ void SET_CFLG_ALWAYS(uae_u32 x) +static inline void SET_CFLG_ALWAYS(uae_u32 x) { SET_CFLG(x); /* This has not yet been redefined */ } @@ -62,13 +62,13 @@ static __inline__ void SET_CFLG_ALWAYS(uae_u32 x) #define SET_XFLG(y) do {uae_u32 dummy=(y); } while (0) #undef CLEAR_CZNV -#define CLEAR_CZNV() do {} while (0) +#define CLEAR_CZNV() #undef IOR_CZNV #define IOR_CZNV(y) do {uae_u32 dummy=(y); } while (0) #undef SET_CZNV #define SET_CZNV(y) do {uae_u32 dummy=(y); } while (0) #undef COPY_CARRY -#define COPY_CARRY() do {} while (0) +#define COPY_CARRY() #ifdef optflag_testl #undef optflag_testl diff --git a/BasiliskII/src/uae_cpu/readcpu.cpp b/BasiliskII/src/uae_cpu/readcpu.cpp index 3fccdfb7..742e0be5 100644 --- a/BasiliskII/src/uae_cpu/readcpu.cpp +++ b/BasiliskII/src/uae_cpu/readcpu.cpp @@ -1,34 +1,30 @@ +/* 2002 MJ */ /* * UAE - The Un*x Amiga Emulator * * Read 68000 CPU specs from file "table68k" * * Copyright 1995,1996 Bernd Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include -#include - #include "sysdeps.h" #include "readcpu.h" +#include +#include +#include +#include + +using std::strncmp; +using std::abort; +using std::fprintf; +using std::strcmp; +using std::strlen; +using std::malloc; + int nr_cpuop_funcs; +struct instr *table68k; +static int readcpu_mismatch; struct mnemolookup lookuptab[] = { { i_ILLG, "ILLEGAL" }, @@ -153,16 +149,19 @@ struct mnemolookup lookuptab[] = { { i_CPUSHA, "CPUSHA" }, { i_MOVE16, "MOVE16" }, - { i_EMULOP_RETURN, "EMULOP_RETURN" }, - { i_EMULOP, "EMULOP" }, - + { i_EMULOP_RETURN, "EMULOP_RETURN" }, + { i_EMULOP, "EMULOP" }, + { i_MMUOP, "MMUOP" }, + + {i_NATFEAT_ID, "NATFEAT_ID" }, + {i_NATFEAT_CALL, "NATFEAT_CALL" }, + { i_ILLG, "" }, }; -struct instr *table68k; -static __inline__ amodes mode_from_str (const char *str) +static inline amodes mode_from_str (const char *str) { if (strncmp (str, "Dreg", 4) == 0) return Dreg; if (strncmp (str, "Areg", 4) == 0) return Areg; @@ -180,7 +179,7 @@ static __inline__ amodes mode_from_str (const char *str) return (amodes)0; } -static __inline__ amodes mode_from_mr (int mode, int reg) +static inline amodes mode_from_mr (int mode, int reg) { switch (mode) { case 0: return Dreg; @@ -215,31 +214,32 @@ static void build_insn (int insn) int i, n; int flaglive = 0, flagdead = 0; - int cflow = 0; + int cflow = 0; id = defs68k[insn]; - // Control flow information - cflow = id.cflow; - - // Mask of flags set/used - unsigned char flags_set(0), flags_used(0); - - for (i = 0, n = 4; i < 5; i++, n--) { - switch (id.flaginfo[i].flagset) { - case fa_unset: case fa_isjmp: break; - default: flags_set |= (1 << n); - } - - switch (id.flaginfo[i].flaguse) { - case fu_unused: case fu_isjmp: break; - default: flags_used |= (1 << n); - } + // Control flow information + cflow = id.cflow; + + // Mask of flags set/used + unsigned char flags_set(0), flags_used(0); + + for (i = 0, n = 4; i < 5; i++, n--) { + switch (id.flaginfo[i].flagset) { + case fa_unset: case fa_isjmp: break; + default: flags_set |= (1 << n); } - + + switch (id.flaginfo[i].flaguse) { + case fu_unused: case fu_isjmp: break; + default: flags_used |= (1 << n); + } + } + for (i = 0; i < 5; i++) { switch (id.flaginfo[i].flagset){ case fa_unset: break; + case fa_isjmp: break; case fa_zero: flagdead |= 1 << i; break; case fa_one: flagdead |= 1 << i; break; case fa_dontcare: flagdead |= 1 << i; break; @@ -252,6 +252,8 @@ static void build_insn (int insn) for (i = 0; i < 5; i++) { switch (id.flaginfo[i].flaguse) { case fu_unused: break; + case fu_isjmp: flaglive |= 1 << i; break; + case fu_maybecc: flaglive |= 1 << i; break; case fu_unknown: flaglive = -1; goto out2; case fu_used: flaglive |= 1 << i; break; } @@ -306,6 +308,7 @@ static void build_insn (int insn) continue; if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff)) continue; + if (bitcnt[bitE] && (bitval[bitE] == 0x00)) continue; @@ -346,9 +349,9 @@ static void build_insn (int insn) } } mnp++; - if ((unsigned)mnp >= sizeof(mnemonic) - 1) { - mnemonic[sizeof(mnemonic) - 1] = 0; - fprintf(stderr, "Instruction %s overflow\n", mnemonic); + if ((unsigned)mnp >= (sizeof(mnemonic)-1)) { + mnemonic[sizeof(mnemonic)-1] = '\0'; + fprintf(stderr, "WTF!!! Instruction '%s' overflow\n", mnemonic); abort(); } } @@ -379,6 +382,7 @@ static void build_insn (int insn) case 'A': srcmode = Areg; switch (opcstr[pos++]) { + case 'l': srcmode = absl; break; case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; default: abort(); @@ -388,9 +392,11 @@ static void build_insn (int insn) case 'P': srcmode = Aipi; pos++; break; } break; +#if 0 case 'L': srcmode = absl; break; +#endif case '#': switch (opcstr[pos++]) { case 'z': srcmode = imm; break; @@ -436,7 +442,7 @@ static void build_insn (int insn) srcpos = bitpos[bitK]; } break; - case 'E': srcmode = immi; srcreg = bitval[bitE]; + case 'E': srcmode = immi; srcreg = bitval[bitE]; if (CPU_EMU_SIZE < 5) { // gb-- what is CPU_EMU_SIZE used for ?? /* 1..255 */ srcgather = 1; @@ -444,8 +450,8 @@ static void build_insn (int insn) srcpos = bitpos[bitE]; } break; - case 'p': srcmode = immi; srcreg = bitval[bitp]; - if (CPU_EMU_SIZE < 5) { + case 'p': srcmode = immi; srcreg = bitval[bitp]; + if (CPU_EMU_SIZE < 5) { // gb-- what is CPU_EMU_SIZE used for ?? /* 0..3 */ srcgather = 1; srctype = 7; @@ -582,21 +588,22 @@ static void build_insn (int insn) case 'A': destmode = Areg; switch (opcstr[pos++]) { + case 'l': destmode = absl; break; case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; - case 'x': destreg = 0; dstgather = 0; dstpos = 0; break; + case 'x': destreg = 0; dstgather = 0; dstpos = 0; break; default: abort(); } - if (dstpos < 0 || dstpos >= 32) - abort(); switch (opcstr[pos]) { case 'p': destmode = Apdi; pos++; break; case 'P': destmode = Aipi; pos++; break; } break; +#if 0 case 'L': destmode = absl; break; +#endif case '#': switch (opcstr[pos++]) { case 'z': destmode = imm; break; @@ -767,7 +774,7 @@ static void build_insn (int insn) table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse; } #endif - + // Fix flags used information for Scc, Bcc, TRAPcc, DBcc instructions if ( table68k[opc].mnemo == i_Scc || table68k[opc].mnemo == i_Bcc @@ -795,7 +802,7 @@ static void build_insn (int insn) case 15:flags_used = 0x0E; break; /* LE */ } } - + #if 1 /* gb-- flagdead and flaglive would not have correct information */ table68k[opc].flagdead = flags_set; @@ -811,22 +818,6 @@ static void build_insn (int insn) } -void read_table68k (void) -{ - int i; - - table68k = (struct instr *)malloc (65536 * sizeof (struct instr)); - for (i = 0; i < 65536; i++) { - table68k[i].mnemo = i_ILLG; - table68k[i].handler = -1; - } - for (i = 0; i < n_defs68k; i++) { - build_insn (i); - } -} - -static int mismatch; - static void handle_merges (long int opcode) { uae_u16 smsk; @@ -851,9 +842,9 @@ static void handle_merges (long int opcode) case 5: smsk = 63; sbitdst = 64; break; case 6: - smsk = 255; sbitdst = 256; break; + smsk = 255; sbitdst = 256; break; case 7: - smsk = 3; sbitdst = 4; break; + smsk = 3; sbitdst = 4; break; default: smsk = 0; sbitdst = 0; abort(); @@ -869,7 +860,7 @@ static void handle_merges (long int opcode) } for (srcreg=0; srcreg < sbitdst; srcreg++) { for (dstreg=0; dstreg < dstend; dstreg++) { - uae_u16 code = uae_u16(opcode); + uae_u16 code = opcode; code = (code & ~smsk) | (srcreg << table68k[opcode].spos); code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos); @@ -882,20 +873,20 @@ static void handle_merges (long int opcode) || table68k[code].suse != table68k[opcode].suse || table68k[code].duse != table68k[opcode].duse) { - mismatch++; continue; + readcpu_mismatch++; continue; } if (table68k[opcode].suse && (table68k[opcode].spos != table68k[code].spos || table68k[opcode].smode != table68k[code].smode || table68k[opcode].stype != table68k[code].stype)) { - mismatch++; continue; + readcpu_mismatch++; continue; } if (table68k[opcode].duse && (table68k[opcode].dpos != table68k[code].dpos || table68k[opcode].dmode != table68k[code].dmode)) { - mismatch++; continue; + readcpu_mismatch++; continue; } if (code != opcode) @@ -904,11 +895,11 @@ static void handle_merges (long int opcode) } } -void do_merges (void) +static void do_merges (void) { long int opcode; int nr = 0; - mismatch = 0; + readcpu_mismatch = 0; for (opcode = 0; opcode < 65536; opcode++) { if (table68k[opcode].handler != -1 || table68k[opcode].mnemo == i_ILLG) continue; @@ -918,116 +909,26 @@ void do_merges (void) nr_cpuop_funcs = nr; } -int get_no_mismatches (void) -{ - return mismatch; -} -const char *get_instruction_name (unsigned int opcode) +void init_table68k (void) { - struct instr *ins = &table68k[opcode]; - for (int i = 0; lookuptab[i].name[0]; i++) { - if (ins->mnemo == lookuptab[i].mnemo) - return lookuptab[i].name; + int i; + + free(table68k); + table68k = (struct instr *)malloc (65536 * sizeof (struct instr)); + for (i = 0; i < 65536; i++) { + table68k[i].mnemo = i_ILLG; + table68k[i].handler = -1; } - abort(); - return NULL; -} - -static char *get_ea_string (amodes mode, wordsizes size) -{ - static char buffer[80]; - - buffer[0] = 0; - switch (mode){ - case Dreg: - strcpy (buffer,"Dn"); - break; - case Areg: - strcpy (buffer,"An"); - break; - case Aind: - strcpy (buffer,"(An)"); - break; - case Aipi: - strcpy (buffer,"(An)+"); - break; - case Apdi: - strcpy (buffer,"-(An)"); - break; - case Ad16: - strcpy (buffer,"(d16,An)"); - break; - case Ad8r: - strcpy (buffer,"(d8,An,Xn)"); - break; - case PC16: - strcpy (buffer,"(d16,PC)"); - break; - case PC8r: - strcpy (buffer,"(d8,PC,Xn)"); - break; - case absw: - strcpy (buffer,"(xxx).W"); - break; - case absl: - strcpy (buffer,"(xxx).L"); - break; - case imm: - switch (size){ - case sz_byte: - strcpy (buffer,"#.B"); - break; - case sz_word: - strcpy (buffer,"#.W"); - break; - case sz_long: - strcpy (buffer,"#.L"); - break; - default: - break; - } - break; - case imm0: - strcpy (buffer,"#.B"); - break; - case imm1: - strcpy (buffer,"#.W"); - break; - case imm2: - strcpy (buffer,"#.L"); - break; - case immi: - strcpy (buffer,"#"); - break; - - default: - break; + for (i = 0; i < n_defs68k; i++) { + build_insn (i); } - return buffer; + do_merges(); } -const char *get_instruction_string (unsigned int opcode) + +void exit_table68k (void) { - static char out[100]; - struct instr *ins; - - strcpy (out, get_instruction_name (opcode)); - - ins = &table68k[opcode]; - if (ins->size == sz_byte) - strcat (out,".B"); - if (ins->size == sz_word) - strcat (out,".W"); - if (ins->size == sz_long) - strcat (out,".L"); - strcat (out," "); - if (ins->suse) - strcat (out, get_ea_string (amodes(ins->smode), wordsizes(ins->size))); - if (ins->duse) { - if (ins->suse) - strcat (out,","); - strcat (out, get_ea_string (amodes(ins->dmode), wordsizes(ins->size))); - } - return out; + free(table68k); + table68k = NULL; } diff --git a/BasiliskII/src/uae_cpu/readcpu.h b/BasiliskII/src/uae_cpu/readcpu.h index 6fba3c39..3bdc0cd6 100644 --- a/BasiliskII/src/uae_cpu/readcpu.h +++ b/BasiliskII/src/uae_cpu/readcpu.h @@ -1,16 +1,16 @@ -#ifndef READCPU_H -#define READCPU_H +#ifndef UAE_READCPU_H +#define UAE_READCPU_H #ifdef __cplusplus extern "C" { #endif -ENUMDECL { +typedef enum { Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r, absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg -} ENUMNAME (amodes); +} amodes; -ENUMDECL { +typedef enum { i_ILLG, i_OR, i_AND, i_EOR, i_ORSR, i_ANDSR, i_EORSR, @@ -35,43 +35,42 @@ ENUMDECL { i_PACK, i_UNPK, i_TAS, i_BKPT, i_CALLM, i_RTM, i_TRAPcc, i_MOVES, i_FPP, i_FDBcc, i_FScc, i_FTRAPcc, i_FBcc, i_FSAVE, i_FRESTORE, i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16, - i_MMUOP, - i_EMULOP_RETURN, i_EMULOP -} ENUMNAME (instrmnem); + i_MMUOP, i_EMULOP_RETURN, i_EMULOP, i_NATFEAT_ID, i_NATFEAT_CALL +} instrmnem; extern struct mnemolookup { instrmnem mnemo; const char *name; } lookuptab[]; -ENUMDECL { +typedef enum { sz_byte, sz_word, sz_long -} ENUMNAME (wordsizes); +} wordsizes; -ENUMDECL { - fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp -} ENUMNAME (flagaffect); +typedef enum { + fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp, + fa_isbranch +} flagaffect; -ENUMDECL { +typedef enum { fu_used, fu_unused, fu_maybecc, fu_unknown, fu_isjmp -} ENUMNAME (flaguse); +} flaguse; -ENUMDECL { - fl_normal = 0, +typedef enum { + fl_normal = 0, fl_branch = 1, - fl_jump = 2, - fl_return = 3, - fl_trap = 4, - fl_const_jump = 8, - - /* Instructions that can trap don't mark the end of a block */ - fl_end_block = 3 -} ENUMNAME (cflow_t); + fl_jump = 2, + fl_return = 3, + fl_trap = 4, + fl_const_jump = 8, + /* Instructions that can trap don't mark the end of a block */ + fl_end_block = 3 +} cflow_t; -ENUMDECL { +typedef enum { bit0, bit1, bitc, bitC, bitf, biti, bitI, bitj, bitJ, bitk, bitK, bits, bitS, bitd, bitD, bitr, bitR, bitz, bitE, bitp, lastbit -} ENUMNAME (bitvals); +} bitvals; struct instr_def { unsigned int bits; @@ -84,7 +83,7 @@ struct instr_def { unsigned int flaguse:3; unsigned int flagset:3; } flaginfo[5]; - unsigned char cflow; + unsigned char cflow; unsigned char sduse; const char *opcstr; }; @@ -103,28 +102,24 @@ extern struct instr { unsigned int mnemo:8; unsigned int cc:4; unsigned int plev:2; - unsigned int size:2; - unsigned int smode:5; + wordsizes size:2; + amodes smode:5; unsigned int stype:3; - unsigned int dmode:5; + amodes dmode:5; unsigned int suse:1; unsigned int duse:1; unsigned int unused1:1; unsigned int clev:3; - unsigned int cflow:3; + unsigned int cflow:3; unsigned int unused2:2; } *table68k; -extern void read_table68k (void); -extern void do_merges (void); -extern int get_no_mismatches (void); +extern void init_table68k(void); +extern void exit_table68k(void); extern int nr_cpuop_funcs; -extern const char *get_instruction_name (unsigned int opcode); -extern const char *get_instruction_string (unsigned int opcode); - #ifdef __cplusplus } #endif -#endif /* READCPU_H */ +#endif diff --git a/BasiliskII/src/uae_cpu/readcpua.cpp b/BasiliskII/src/uae_cpu/readcpua.cpp new file mode 100644 index 00000000..521c241f --- /dev/null +++ b/BasiliskII/src/uae_cpu/readcpua.cpp @@ -0,0 +1,5 @@ +/* + * readcpu.cpp must be compiled twice, once for the generator program + * and once for the actual executable + */ +#include "readcpu.cpp" diff --git a/BasiliskII/src/uae_cpu/registers.h b/BasiliskII/src/uae_cpu/registers.h new file mode 100644 index 00000000..c3459719 --- /dev/null +++ b/BasiliskII/src/uae_cpu/registers.h @@ -0,0 +1,116 @@ +/* 2001 MJ */ + +#ifndef REGISTERS_H +#define REGISTERS_H + +#include "sysdeps.h" +#include "spcflags.h" +typedef char flagtype; + + +struct xttrx { + uae_u32 log_addr_base : 8; + uae_u32 log_addr_mask : 8; + uae_u32 enable : 1; + uae_u32 s_field : 2; + uae_u32 : 3; + uae_u32 usr1 : 1; + uae_u32 usr0 : 1; + uae_u32 : 1; + uae_u32 cmode : 2; + uae_u32 : 2; + uae_u32 write : 1; + uae_u32 : 2; +}; + +struct mmusr_t { + uae_u32 phys_addr : 20; + uae_u32 bus_err : 1; + uae_u32 global : 1; + uae_u32 usr1 : 1; + uae_u32 usr0 : 1; + uae_u32 super : 1; + uae_u32 cmode : 2; + uae_u32 modif : 1; + uae_u32 : 1; + uae_u32 write : 1; + uae_u32 ttrhit : 1; + uae_u32 resident : 1; +}; + +struct log_addr4 { + uae_u32 rif : 7; + uae_u32 pif : 7; + uae_u32 paif : 6; + uae_u32 poff : 12; +}; + +struct log_addr8 { + uae_u32 rif : 7; + uae_u32 pif : 7; + uae_u32 paif : 5; + uae_u32 poff : 13; +}; + +extern struct regstruct +{ + uae_u32 regs[16]; + uaecptr usp,isp,msp; + uae_u16 sr; + flagtype t1; + flagtype t0; + flagtype s; + flagtype m; + flagtype x; + flagtype stopped; + int intmask; + + uae_u32 pc; + uae_u32 fault_pc; + uae_u8 *pc_p; + uae_u8 *pc_oldp; + + uae_u32 vbr,sfc,dfc; + + volatile uae_u32 spcflags; + +#if 0 + uae_u32 kick_mask; + + /* Fellow sources say this is 4 longwords. That's impossible. It needs + * to be at least a longword. The HRM has some cryptic comment about two + * instructions being on the same longword boundary. + * The way this is implemented now seems like a good compromise. + */ + uae_u32 prefetch; +#endif + + /* MMU reg*/ + uae_u32 urp,srp; + uae_u32 tc; + + int mmu_enabled; /* flagtype tce; */ + int mmu_pagesize_8k; /* flagtype tcp; */ + + uae_u32 dtt0,dtt1,itt0,itt1; + uae_u32 mmusr; + + uae_u32 mmu_fslw, mmu_fault_addr; + uae_u16 mmu_ssw; + uae_u32 wb3_data; + uae_u16 wb3_status; + + /* Cache reg*/ + uae_u32 cacr,caar; +} regs; + +static inline uaecptr m68k_getpc (void) +{ +#ifdef FULLMMU + return regs.pc; +#else + return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp); +#endif +} + +#endif diff --git a/BasiliskII/src/uae_cpu/spcflags.h b/BasiliskII/src/uae_cpu/spcflags.h index 3c3fc032..eb465e72 100644 --- a/BasiliskII/src/uae_cpu/spcflags.h +++ b/BasiliskII/src/uae_cpu/spcflags.h @@ -1,92 +1,78 @@ -/* - * UAE - The Un*x Amiga Emulator - * - * MC68000 emulation - * - * Copyright 1995 Bernd Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * Copyright 1995 Bernd Schmidt + */ #ifndef SPCFLAGS_H #define SPCFLAGS_H -typedef uae_u32 spcflags_t; +#if 0 +#include "SDL_compat.h" +#endif enum { - SPCFLAG_STOP = 0x01, - SPCFLAG_INT = 0x02, - SPCFLAG_BRK = 0x04, - SPCFLAG_TRACE = 0x08, - SPCFLAG_DOTRACE = 0x10, - SPCFLAG_DOINT = 0x20, -#if USE_JIT - SPCFLAG_JIT_END_COMPILE = 0x40, - SPCFLAG_JIT_EXEC_RETURN = 0x80, + SPCFLAG_STOP = 0x01, +#if 0 + SPCFLAG_INTERNAL_IRQ = 0x02, #else - SPCFLAG_JIT_END_COMPILE = 0, - SPCFLAG_JIT_EXEC_RETURN = 0, + SPCFLAG_INT = 0x02, #endif - - SPCFLAG_ALL = SPCFLAG_STOP - | SPCFLAG_INT - | SPCFLAG_BRK - | SPCFLAG_TRACE - | SPCFLAG_DOTRACE - | SPCFLAG_DOINT - | SPCFLAG_JIT_END_COMPILE - | SPCFLAG_JIT_EXEC_RETURN - , - + SPCFLAG_BRK = 0x04, + SPCFLAG_TRACE = 0x08, + SPCFLAG_DOTRACE = 0x10, + SPCFLAG_DOINT = 0x20, +#ifdef USE_JIT + SPCFLAG_JIT_END_COMPILE = 0x40, + SPCFLAG_JIT_EXEC_RETURN = 0x80, +#else + SPCFLAG_JIT_END_COMPILE = 0, + SPCFLAG_JIT_EXEC_RETURN = 0, +#endif + SPCFLAG_VBL = 0x100, + SPCFLAG_MFP = 0x200, + SPCFLAG_INT3 = 0x800, + SPCFLAG_INT5 = 0x1000, + SPCFLAG_SCC = 0x2000, +// SPCFLAG_MODE_CHANGE = 0x4000, + SPCFLAG_ALL = SPCFLAG_STOP +#if 0 + | SPCFLAG_INTERNAL_IRQ +#else + | SPCFLAG_INT +#endif + | SPCFLAG_BRK + | SPCFLAG_TRACE + | SPCFLAG_DOTRACE + | SPCFLAG_DOINT + | SPCFLAG_JIT_END_COMPILE + | SPCFLAG_JIT_EXEC_RETURN + | SPCFLAG_INT3 + | SPCFLAG_VBL + | SPCFLAG_INT5 + | SPCFLAG_SCC + | SPCFLAG_MFP + , + SPCFLAG_ALL_BUT_EXEC_RETURN = SPCFLAG_ALL & ~SPCFLAG_JIT_EXEC_RETURN + }; +#if 0 +#define SPCFLAGS_TEST(m) \ + (regs.spcflags & (m)) +#else #define SPCFLAGS_TEST(m) \ ((regs.spcflags & (m)) != 0) +#endif /* Macro only used in m68k_reset() */ #define SPCFLAGS_INIT(m) do { \ regs.spcflags = (m); \ } while (0) -#if !(ENABLE_EXCLUSIVE_SPCFLAGS) - -#define SPCFLAGS_SET(m) do { \ - regs.spcflags |= (m); \ -} while (0) - -#define SPCFLAGS_CLEAR(m) do { \ - regs.spcflags &= ~(m); \ -} while (0) - -#elif defined(X86_ASSEMBLY) - -#define HAVE_HARDWARE_LOCKS - -#define SPCFLAGS_SET(m) do { \ - __asm__ __volatile__("lock\n\torl %1,%0" : "=m" (regs.spcflags) : "i" ((m))); \ -} while (0) - -#define SPCFLAGS_CLEAR(m) do { \ - __asm__ __volatile__("lock\n\tandl %1,%0" : "=m" (regs.spcflags) : "i" (~(m))); \ -} while (0) - -#else - -#undef HAVE_HARDWARE_LOCKS - #include "main.h" extern B2_mutex *spcflags_lock; @@ -99,9 +85,91 @@ extern B2_mutex *spcflags_lock; #define SPCFLAGS_CLEAR(m) do { \ B2_lock_mutex(spcflags_lock); \ regs.spcflags &= ~(m); \ - B2_unlock_mutex(spcflags_lock); \ + B2_unlock_mutex(spcflags_lock); \ } while (0) +#define SleepAndWait() usleep(1000); + +#if 0 +#ifndef ENABLE_EXCLUSIVE_SPCFLAGS + +#define SPCFLAGS_SET(m) do { \ + regs.spcflags |= (m); \ +} while (0) + +#define SPCFLAGS_CLEAR(m) do { \ + regs.spcflags &= ~(m); \ +} while (0) + +#if 0 +#define SleepAndWait() usleep(1000) +#endif + +#elif defined(X86_ASSEMBLY) +// #elif (defined(CPU_i386) || defined(CPU_x86_64)) && defined(X86_ASSEMBLY) && !defined(ENABLE_REALSTOP) + +// #define HAVE_HARDWARE_LOCKS 1 +#define HAVE_HARDWARE_LOCKS + +#define SPCFLAGS_SET(m) do { \ + __asm__ __volatile__("lock\n\torl %1,%0" : "=m" (regs.spcflags) : "i" ((m))); \ +} while (0) + +#define SPCFLAGS_CLEAR(m) do { \ + __asm__ __volatile__("lock\n\tandl %1,%0" : "=m" (regs.spcflags) : "i" (~(m))); \ +} while (0) + +// #define SleepAndWait() usleep(1000) + +// #elif !defined(ENABLE_REALSTOP) + +// #undef HAVE_HARDWARE_LOCKS +// extern SDL_mutex *spcflags_lock; + +// #define SPCFLAGS_SET(m) do { \ +// SDL_LockMutex(spcflags_lock); \ +// regs.spcflags |= (m); \ +// SDL_UnlockMutex(spcflags_lock); \ +// } while (0) + +// #define SPCFLAGS_CLEAR(m) do { \ +// SDL_LockMutex(spcflags_lock); \ +// regs.spcflags &= ~(m); \ +// SDL_UnlockMutex(spcflags_lock); \ +// } while (0) + +// #define SleepAndWait() usleep(1000) + +#else +/// Full STOP instruction implementation (default configuration) + +#undef HAVE_HARDWARE_LOCKS +#if 0 +extern SDL_mutex *spcflags_lock; +extern SDL_cond *stop_condition; + +#define SPCFLAGS_SET(m) do { \ + SDL_LockMutex(spcflags_lock); \ + regs.spcflags |= (m); \ + if (regs.spcflags & SPCFLAG_STOP) \ + SDL_CondSignal(stop_condition); \ + SDL_UnlockMutex(spcflags_lock); \ +} while (0) + +#define SPCFLAGS_CLEAR(m) do { \ + SDL_LockMutex(spcflags_lock); \ + regs.spcflags &= ~(m); \ + SDL_UnlockMutex(spcflags_lock); \ +} while (0) + +#define SleepAndWait() do { \ + SDL_LockMutex(spcflags_lock); \ + SDL_CondWait(stop_condition, spcflags_lock); \ + SDL_UnlockMutex(spcflags_lock); \ +} while (0) +#endif + +#endif #endif #endif /* SPCFLAGS_H */ diff --git a/BasiliskII/src/uae_cpu/table68k b/BasiliskII/src/uae_cpu/table68k index ab9eabe1..7405bd31 100644 --- a/BasiliskII/src/uae_cpu/table68k +++ b/BasiliskII/src/uae_cpu/table68k @@ -10,7 +10,7 @@ % J: immediate 0..15 % k: immediate 0..7 % K: immediate 0..63 -% p: immediate 0..3 (CINV and CPUSH instructions: Cache Field) +% p: immediate 0..3 (CINV and CPUSH: cache field) % s: source mode % S: source reg % d: dest mode @@ -28,14 +28,15 @@ % ArP: --> (Ar)+ % L: --> (xxx.L) % -% Fields on a line: -% 16 chars bitpattern : -% CPU level / privilege level : +% Fields on a line: +% 16 chars bitpattern : +% CPU level / privildge level : % CPU level 0: 68000 % 1: 68010 % 2: 68020 % 3: 68020/68881 % 4: 68040 +% 5: 68060 % privilege level 0: not privileged % 1: unprivileged only on 68000 (check regs.s) % 2: privileged (check regs.s) @@ -46,8 +47,10 @@ % 0 means flag reset % 1 means flag set % ? means programmer was too lazy to check or instruction may trap -% everything else means flag set/used +% + means instruction is conditional branch (ignored, only for sync) +% / means instruction is unconditional branch/call (ignored, only for sync) % x means flag is unknown and well-behaved programs shouldn't check it +% everything else means flag set/used % % Control flow % two letters, combination of @@ -108,7 +111,7 @@ 0011 DDDd ddss sSSS:00:-----:-----:--:12: MOVEA.W s,d[Areg] 0011 DDDd ddss sSSS:00:-NZ00:-----:--:12: MOVE.W s,d[!Areg] -0100 0000 zzdd dDDD:00:XxZxC:X-Z--:--:30: NEGX.z d[!Areg] +0100 0000 zzdd dDDD:00:XNZVC:X-Z--:--:30: NEGX.z d[!Areg] 0100 0000 11dd dDDD:01:-----:XNZVC:T-:10: MVSR2.W d[!Areg] 0100 0010 zzdd dDDD:00:-0100:-----:--:20: CLR.z d[!Areg] 0100 0010 11dd dDDD:10:-----:XNZVC:--:10: MVSR2.B d[!Areg] @@ -119,13 +122,13 @@ 0100 1000 0000 1rrr:20:-----:-----:--:31: LINK.L Ar,#2 0100 1000 00dd dDDD:00:X?Z?C:X-Z--:--:30: NBCD.B d[!Areg] 0100 1000 0100 1kkk:20:-----:-----:T-:10: BKPT #k -0100 1000 01ss sSSS:00:-NZ00:-----:--:30: SWAP.W s[Dreg] +0100 1000 01ss sSSS:00:-NZ00:-----:--:30: SWAP.W s[Dreg] 0100 1000 01ss sSSS:00:-----:-----:--:00: PEA.L s[!Dreg,Areg,Aipi,Apdi,Immd] -0100 1000 10dd dDDD:00:-NZ00:-----:--:30: EXT.W d[Dreg] +0100 1000 10dd dDDD:00:-NZ00:-----:--:30: EXT.W d[Dreg] 0100 1000 10dd dDDD:00:-----:-----:--:02: MVMLE.W #1,d[!Dreg,Areg,Aipi] -0100 1000 11dd dDDD:00:-NZ00:-----:--:30: EXT.L d[Dreg] +0100 1000 11dd dDDD:00:-NZ00:-----:--:30: EXT.L d[Dreg] 0100 1000 11dd dDDD:00:-----:-----:--:02: MVMLE.L #1,d[!Dreg,Areg,Aipi] -0100 1001 11dd dDDD:00:-NZ00:-----:--:30: EXT.B d[Dreg] +0100 1001 11dd dDDD:00:-NZ00:-----:--:30: EXT.B d[Dreg] 0100 1010 zzss sSSS:00:-NZ00:-----:--:10: TST.z s 0100 1010 11dd dDDD:00:-NZ00:-----:--:30: TAS.B d[!Areg] 0100 1010 1111 1100:00:-----:-----:T-:00: ILLEGAL @@ -148,21 +151,24 @@ 0100 1110 0111 0111:00:XNZVC:-----:-R:00: RTR 0100 1110 0111 1010:12:-----:-----:T-:10: MOVEC2 #1 0100 1110 0111 1011:12:-----:-----:T-:10: MOVE2C #1 -0100 1110 10ss sSSS:00:-----:-----:-J:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd] +0100 1110 10ss sSSS:00://///://///:-J:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd] 0100 rrr1 00ss sSSS:00:-N???:-----:T-:11: CHK.L s[!Areg],Dr 0100 rrr1 10ss sSSS:00:-N???:-----:T-:11: CHK.W s[!Areg],Dr -0100 1110 11ss sSSS:00:-----:-----:-J:80: JMP.L s[!Dreg,Areg,Aipi,Apdi,Immd] +0100 1110 11ss sSSS:00://///://///:-J:80: JMP.L s[!Dreg,Areg,Aipi,Apdi,Immd] 0100 rrr1 11ss sSSS:00:-----:-----:--:02: LEA.L s[!Dreg,Areg,Aipi,Apdi,Immd],Ar -0101 jjj0 01dd dDDD:00:-----:-----:--:13: ADDA.W #j,d[Areg] -0101 jjj0 10dd dDDD:00:-----:-----:--:13: ADDA.L #j,d[Areg] +% This variant of ADDQ is word and long sized only +0101 jjj0 01dd dDDD:00:-----:-----:--:13: ADDA.W #j,d[Areg] +0101 jjj0 10dd dDDD:00:-----:-----:--:13: ADDA.L #j,d[Areg] 0101 jjj0 zzdd dDDD:00:XNZVC:-----:--:13: ADD.z #j,d[!Areg] -0101 jjj1 01dd dDDD:00:-----:-----:--:13: SUBA.W #j,d[Areg] -0101 jjj1 10dd dDDD:00:-----:-----:--:13: SUBA.L #j,d[Areg] + +% This variant of SUBQ is word and long sized only +0101 jjj1 01dd dDDD:00:-----:-----:--:13: SUBA.W #j,d[Areg] +0101 jjj1 10dd dDDD:00:-----:-----:--:13: SUBA.L #j,d[Areg] 0101 jjj1 zzdd dDDD:00:XNZVC:-----:--:13: SUB.z #j,d[!Areg] -0101 cccc 1100 1rrr:00:-----:-????:-B:31: DBcc.W Dr,#1 -0101 cccc 11dd dDDD:00:-----:-????:--:20: Scc.B d[!Areg] +0101 cccc 1100 1rrr:00:-----:-++++:-B:31: DBcc.W Dr,#1 +0101 cccc 11dd dDDD:00:-----:-++++:--:20: Scc.B d[!Areg] 0101 cccc 1111 1010:20:-----:-????:T-:10: TRAPcc #1 0101 cccc 1111 1011:20:-----:-????:T-:10: TRAPcc #2 0101 cccc 1111 1100:20:-----:-????:T-:00: TRAPcc @@ -170,30 +176,30 @@ % Bxx.L is 68020 only, but setting the CPU level to 2 would give illegal % instruction exceptions when compiling a 68000 only emulation, which isn't % what we want either. -0110 0001 0000 0000:00:-----:-----:-B:40: BSR.W #1 -0110 0001 IIII IIII:00:-----:-----:-B:40: BSR.B #i -0110 0001 1111 1111:00:-----:-----:-B:40: BSR.L #2 -0110 CCCC 0000 0000:00:-----:-????:-B:40: Bcc.W #1 -0110 CCCC IIII IIII:00:-----:-????:-B:40: Bcc.B #i -0110 CCCC 1111 1111:00:-----:-????:-B:40: Bcc.L #2 +0110 0001 0000 0000:00://///://///:-B:40: BSR.W #1 +0110 0001 IIII IIII:00://///://///:-B:40: BSR.B #i +0110 0001 1111 1111:00://///://///:-B:40: BSR.L #2 +0110 CCCC 0000 0000:00:-----:-++++:-B:40: Bcc.W #1 +0110 CCCC IIII IIII:00:-----:-++++:-B:40: Bcc.B #i +0110 CCCC 1111 1111:00:-----:-++++:-B:40: Bcc.L #2 0111 rrr0 iiii iiii:00:-NZ00:-----:--:12: MOVE.L #i,Dr 1000 rrr0 zzss sSSS:00:-NZ00:-----:--:13: OR.z s[!Areg],Dr 1000 rrr0 11ss sSSS:00:-NZV0:-----:T-:13: DIVU.W s[!Areg],Dr -1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: SBCD.B d[Dreg],Dr -1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: SBCD.B d[Areg-Apdi],Arp +1000 rrr1 00dd dDDD:00:X?Z?C:X-Z--:--:13: SBCD.B d[Dreg],Dr +1000 rrr1 00dd dDDD:00:X?Z?C:X-Z--:--:13: SBCD.B d[Areg-Apdi],Arp 1000 rrr1 zzdd dDDD:00:-NZ00:-----:--:13: OR.z Dr,d[!Areg,Dreg] -1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Dreg],Dr -1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Areg-Apdi],Arp -1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Dreg],Dr -1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Areg-Apdi],Arp +1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Dreg],Dr +1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Areg-Apdi],Arp +1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Dreg],Dr +1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Areg-Apdi],Arp 1000 rrr1 11ss sSSS:00:-NZV0:-----:T-:13: DIVS.W s[!Areg],Dr 1001 rrr0 zzss sSSS:00:XNZVC:-----:--:13: SUB.z s,Dr 1001 rrr0 11ss sSSS:00:-----:-----:--:13: SUBA.W s,Ar -1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Dreg],Dr -1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Areg-Apdi],Arp +1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Dreg],Dr +1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Areg-Apdi],Arp 1001 rrr1 zzdd dDDD:00:XNZVC:-----:--:13: SUB.z Dr,d[!Areg,Dreg] 1001 rrr1 11ss sSSS:00:-----:-----:--:13: SUBA.L s,Ar @@ -205,18 +211,18 @@ 1100 rrr0 zzss sSSS:00:-NZ00:-----:--:13: AND.z s[!Areg],Dr 1100 rrr0 11ss sSSS:00:-NZ00:-----:--:13: MULU.W s[!Areg],Dr -1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: ABCD.B d[Dreg],Dr -1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: ABCD.B d[Areg-Apdi],Arp +1100 rrr1 00dd dDDD:00:X?Z?C:X-Z--:--:13: ABCD.B d[Dreg],Dr +1100 rrr1 00dd dDDD:00:X?Z?C:X-Z--:--:13: ABCD.B d[Areg-Apdi],Arp 1100 rrr1 zzdd dDDD:00:-NZ00:-----:--:13: AND.z Dr,d[!Areg,Dreg] -1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Dreg] -1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Ar,d[Areg] -1100 rrr1 10dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Areg] +1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Dreg] +1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Ar,d[Areg] +1100 rrr1 10dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Areg] 1100 rrr1 11ss sSSS:00:-NZ00:-----:--:13: MULS.W s[!Areg],Dr 1101 rrr0 zzss sSSS:00:XNZVC:-----:--:13: ADD.z s,Dr 1101 rrr0 11ss sSSS:00:-----:-----:--:13: ADDA.W s,Ar -1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Dreg],Dr -1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Areg-Apdi],Arp +1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Dreg],Dr +1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Areg-Apdi],Arp 1101 rrr1 zzdd dDDD:00:XNZVC:-----:--:13: ADD.z Dr,d[!Areg,Dreg] 1101 rrr1 11ss sSSS:00:-----:-----:--:13: ADDA.L s,Ar @@ -224,8 +230,8 @@ 1110 jjjf zz00 1RRR:00:XNZ0C:-----:--:13: LSf.z #j,DR 1110 jjjf zz01 0RRR:00:XNZ0C:X----:--:13: ROXf.z #j,DR 1110 jjjf zz01 1RRR:00:-NZ0C:-----:--:13: ROf.z #j,DR -1110 rrrf zz10 0RRR:00:XNZVC:-----:--:13: ASf.z Dr,DR -1110 rrrf zz10 1RRR:00:XNZ0C:-----:--:13: LSf.z Dr,DR +1110 rrrf zz10 0RRR:00:XNZVC:X----:--:13: ASf.z Dr,DR +1110 rrrf zz10 1RRR:00:XNZ0C:X----:--:13: LSf.z Dr,DR 1110 rrrf zz11 0RRR:00:XNZ0C:X----:--:13: ROXf.z Dr,DR 1110 rrrf zz11 1RRR:00:-NZ0C:-----:--:13: ROf.z Dr,DR 1110 000f 11dd dDDD:00:XNZVC:-----:--:13: ASfW.W d[!Dreg,Areg] @@ -255,7 +261,6 @@ 1111 0011 01ss sSSS:32:-----:-----:--:10: FRESTORE s[!Dreg,Areg,Apdi,Immd] % 68040 instructions -1111 0101 iiii iSSS:40:-----:-----:T-:11: MMUOP #i,s 1111 0100 pp00 1rrr:42:-----:-----:T-:02: CINVL #p,Ar 1111 0100 pp01 0rrr:42:-----:-----:T-:02: CINVP #p,Ar 1111 0100 pp01 1rrr:42:-----:-----:T-:00: CINVA #p @@ -264,11 +269,19 @@ 1111 0100 pp11 1rrr:42:-----:-----:T-:00: CPUSHA #p % destination register number is encoded in the following word 1111 0110 0010 0rrr:40:-----:-----:--:12: MOVE16 ArP,AxP -1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Dreg-Aipi],L -1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 L,d[Areg-Aipi] -1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Aind],L -1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 L,d[Aipi-Aind] +1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Dreg-Aipi],Al +1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 Al,d[Areg-Aipi] +1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Aind],Al +1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 Al,d[Aipi-Aind] -% EmulOp instructions -0111 0001 0000 0000:00:-----:-----:-R:00: EMULOP_RETURN -0111 0001 EEEE EEEE:00:-----:-----:-J:10: EMULOP #E +% MMU disabled +% 1111 0101 iiii iSSS:42:?????:?????:T-:11: MMUOP #i,s + +% EmulOp instructions (used by linux68k) +0111 0001 0000 0000:02:-----:XNZVC:-R:00: EMULOP_RETURN +0111 0001 EEEE EEEE:00:-----:XNZVC:-J:10: EMULOP #E + +% NatFea instructions (do I have the srcaddr correct?) +% NatFeat disabled +% 0111 0011 0000 0000:00:-----:XNZVC:-J:00: NATFEAT_ID +% 0111 0011 0000 0001:00:-----:XNZVC:-J:00: NATFEAT_CALL