--- hatari/src/uae-cpu/hatari-glue.c 2019/04/01 07:11:00 1.1.1.7 +++ hatari/src/uae-cpu/hatari-glue.c 2019/04/09 08:57:02 1.1.1.21 @@ -1,195 +1,284 @@ /* Hatari - hatari-glue.c - This file is distributed under the GNU Public License, version 2 or at - your option any later version. Read the file gpl.txt for details. + This file is distributed under the GNU General Public License, version 2 + or at your option any later version. Read the file gpl.txt for details. This file contains some code to glue the UAE CPU core to the rest of the emulator and Hatari's "illegal" opcodes. */ -static char rcsid[] = "Hatari $Id: hatari-glue.c,v 1.1.1.7 2019/04/01 07:11:00 root Exp $"; +const char HatariGlue_fileid[] = "Hatari hatari-glue.c : " __DATE__ " " __TIME__; #include -#include "../includes/main.h" -#include "../includes/int.h" -#include "../includes/tos.h" -#include "../includes/gemdos.h" -#include "../includes/cart.h" -#include "../includes/vdi.h" -#include "../includes/stMemory.h" +#include "main.h" +#include "configuration.h" +#include "cycInt.h" +#include "tos.h" +#include "gemdos.h" +#include "natfeats.h" +#include "cart.h" +#include "vdi.h" +#include "stMemory.h" +#include "ikbd.h" +#include "screen.h" +#include "video.h" +#include "psg.h" +#include "mfp.h" +#include "fdc.h" #include "sysdeps.h" #include "maccess.h" #include "memory.h" +#include "m68000.h" #include "newcpu.h" - -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif +#include "hatari-glue.h" -int illegal_mem = FALSE; -int address_space_24 = TRUE; -int cpu_level = 0; /* 68000 (default) */ -int cpu_compatible = FALSE; +struct uae_prefs currprefs, changed_prefs; -int requestedInterrupt = -1; +int pendingInterrupts = 0; -/* Reset custom chips */ +/** + * Reset custom chips + * In case the RESET instruction is called, we must reset all the peripherals + * connected to the CPU's reset pin. + */ void customreset(void) { - requestedInterrupt = -1; + pendingInterrupts = 0; + + /* Reset the IKBD */ + IKBD_Reset ( false ); + + /* Reseting the GLUE video chip should also set freq/res register to 0 */ + Video_Reset_Glue (); + + /* Reset the YM2149 (stop any sound) */ + PSG_Reset (); + + /* Reset the MFP */ + MFP_Reset (); + + /* Reset the FDC */ + FDC_Reset ( false ); } -/* Return interrupt number (1 - 7), -1 means no interrupt. */ +/** + * Return interrupt number (1 - 7), -1 means no interrupt. + * Note that the interrupt stays pending if it can't be executed yet + * due to the interrupt level field in the SR. + */ int intlev(void) { - int ret = requestedInterrupt; - requestedInterrupt = -1; + /* There are only VBL and HBL autovector interrupts in the ST... */ + assert((pendingInterrupts & ~((1<<4)|(1<<2))) == 0); + +#if 0 + if (pendingInterrupts & (1 << 4)) /* VBL interrupt? */ + { + if (regs.intmask < 4) + pendingInterrupts &= ~(1 << 4); + return 4; + } + else if (pendingInterrupts & (1 << 2)) /* HBL interrupt? */ + { + if (regs.intmask < 2) + pendingInterrupts &= ~(1 << 2); + return 2; + } +#else + if ( pendingInterrupts & (1 << 4) ) /* VBL interrupt ? */ + return 4; + else if ( pendingInterrupts & (1 << 2) ) /* HBL interrupt ? */ + return 2; +#endif - return ret; + return -1; } -/* Initialize 680x0 emulation */ +/** + * Initialize 680x0 emulation + */ int Init680x0(void) { - /* Note: memory_init() is now done in tos.c */ + currprefs.cpu_level = changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel; + currprefs.cpu_compatible = changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu; + currprefs.address_space_24 = changed_prefs.address_space_24 = true; - init_m68k(); - return TRUE; + init_m68k(); + + return true; } -/* Deinitialize 680x0 emulation */ +/** + * Deinitialize 680x0 emulation + */ void Exit680x0(void) { - memory_uninit(); -} - + memory_uninit(); -/* Reset and start 680x0 emulation */ -void Start680x0(void) -{ - m68k_reset(); - m68k_go(TRUE); + free(table68k); + table68k = NULL; } -/* Check if the CPU type has been changed */ -void check_prefs_changed_cpu(int new_level, int new_compatible) +/** + * Execute a 'NOP' opcode (increment PC by 2 bytes and take care + * of prefetch at the CPU level depending on the current CPU mode) + * This is used to return from Gemdos / Natfeats interception, by ignoring + * the intercepted opcode and executing a NOP instead once the work has been done. + */ +static void CpuDoNOP ( void ) { - if(cpu_level!=new_level || cpu_compatible!=new_compatible) - { - cpu_level = new_level; - cpu_compatible = new_compatible; - set_special(SPCFLAG_MODE_CHANGE); - if (table68k) - build_cpufunctbl (); - } + (*cpufunctbl[0X4E71])(0x4E71); } -/* ----------------------------------------------------------------------- */ -/* - This function will be called at system init by the cartridge routine - (after gemdos init, before booting floppies). - - The GEMDOS vector (#$84) is setup and we also initialize the connected - drive mask and Line-A variables (for an extended VDI resolution) from here. -*/ -unsigned long OpCode_SysInit(uae_u32 opcode) +/** + * Check if the CPU type has been changed + */ +void check_prefs_changed_cpu(void) { - /* Initialize the connected drive mask */ - STMemory_WriteLong(0x4c2, ConnectedDriveMask); - - if(!bInitGemDOS) - { - /* Init on boot - see cartimg.c */ - GemDOS_Boot(); - - /* We use this to get pointer to Line-A structure details - * (to fix for extended VDI res) */ - LineABase = regs.regs[0]; /* D0 */ - FontBase = regs.regs[9]; /* A1 */ - VDI_LineA(); - } - - m68k_incpc(2); - fill_prefetch_0(); - return 4; + if (currprefs.cpu_level != changed_prefs.cpu_level + || currprefs.cpu_compatible != changed_prefs.cpu_compatible) + { + currprefs.cpu_level = changed_prefs.cpu_level; + currprefs.cpu_compatible = changed_prefs.cpu_compatible; + set_special(SPCFLAG_MODE_CHANGE); + build_cpufunctbl (); + } } -/* ----------------------------------------------------------------------- */ -/* - Re-direct execution to old GEMDOS calls, used in 'cart.s' -*/ -unsigned long OpCode_OldGemDos(uae_u32 opcode) +/** + * Check whether PC is currently in ROM cartridge space - used + * to test whether our "illegal" Hatari opcodes should be handled + * or whether they are just "normal" illegal opcodes. + */ +static bool is_cart_pc(void) { - m68k_setpc( STMemory_ReadLong(CART_OLDGEMDOS) ); - fill_prefetch_0(); - return 4; + Uint32 pc = M68000_GetPC() & 0x00ffffff; + return pc >= 0xfa0000 && pc < 0xfc0000; } -/* ----------------------------------------------------------------------- */ -/* - Intercept GEMDOS calls - - Used for GEMDOS HD emulation (see gemdos.c). -*/ -unsigned long OpCode_GemDos(uae_u32 opcode) +/** + * This function will be called at system init by the cartridge routine + * (after gemdos init, before booting floppies). + * The GEMDOS vector (#$84) is setup and we also initialize the connected + * drive mask and Line-A variables (for an extended VDI resolution) from here. + */ +unsigned long OpCode_SysInit(uae_u32 opcode) { - GemDOS_OpCode(); /* handler code in gemdos.c */ - - m68k_incpc(2); - fill_prefetch_0(); - return 4; + if (is_cart_pc()) + { + /* Add any drives mapped by TOS in the interim */ + ConnectedDriveMask |= STMemory_ReadLong(0x4c2); + /* Initialize the connected drive mask */ + STMemory_WriteLong(0x4c2, ConnectedDriveMask); + + /* Init on boot - see cart.c */ + GemDOS_Boot(); + + /* Update LineA for extended VDI res + * D0: LineA base, A1: Font base + */ + VDI_LineA(regs.regs[0], regs.regs[9]); + + CpuDoNOP (); + } + else + { + LOG_TRACE(TRACE_OS_GEMDOS | TRACE_OS_BASE | TRACE_OS_VDI | TRACE_OS_AES, + "SYSINIT opcode invoked outside of cartridge space\n"); + /* illegal instruction */ + op_illg(opcode); + fill_prefetch_0(); + } + + return 4; } -/* ----------------------------------------------------------------------- */ -/* - Modify TimerD in GEMDos to gain more desktop performance - - Obviously, we need to emulate all timers correctly but GemDOS set's up Timer D at a very - high rate(every couple of instructions). The interrupts isn't enabled but WinSTon still - needs to process the interrupt table and this HALVES our frame rate!!! (It causes a cache - reload each time). Some games actually reference this timer but don't set it up(eg Paradroid, - Speedball I) so we simply intercept the Timer D setup code in GemDOS and fix the numbers - with more 'laid-back' values. This still keeps 100% compatibility -*/ -#if 0 /* This is now done by intercepting the Timer-D hardware registers */ -unsigned long OpCode_TimerD(uae_u32 opcode) +/** + * Intercept GEMDOS calls. + * Used for GEMDOS HD emulation (see gemdos.c). + */ +unsigned long OpCode_GemDos(uae_u32 opcode) { - /*fprintf(stderr, "OpCode_TimerD handled\n");*/ - m68k_dreg(regs,0)=3; /* 3 = Select Timer D */ - m68k_dreg(regs,1)=7; /* 1 = /4 for 9600 baud(used /200) */ - m68k_dreg(regs,2)=100; /* 2 = 9600 baud(100) */ - m68k_incpc(2); - fill_prefetch_0(); - return 4; + if (is_cart_pc()) + { + GemDOS_OpCode(); /* handler code in gemdos.c */ + CpuDoNOP(); + } + else + { + LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS opcode invoked outside of cartridge space\n"); + /* illegal instruction */ + op_illg(opcode); + fill_prefetch_0(); + } + + return 4; } -#endif -/*-----------------------------------------------------------------------*/ -/* - This is called after completion of each VDI call -*/ +/** + * This is called after completion of each VDI call + */ unsigned long OpCode_VDI(uae_u32 opcode) { - VDI_Complete(); + /* this is valid only after VDI trap, called from cartridge code */ + if (VDI_OldPC && is_cart_pc()) + { + VDI_Complete(); + + /* Set PC back to where originated from to continue instruction decoding */ + m68k_setpc(VDI_OldPC); + VDI_OldPC = 0; + } + else + { + LOG_TRACE(TRACE_OS_VDI, "VDI opcode invoked outside of cartridge space\n"); + /* illegal instruction */ + op_illg(opcode); + } + fill_prefetch_0(); + return 4; +} - /* Set PC back to where originated from to continue instruction decoding */ - m68k_setpc(VDI_OldPC); - fill_prefetch_0(); - return 4; +/** + * Emulator Native Features ID opcode interception. + */ +unsigned long OpCode_NatFeat_ID(uae_u32 opcode) +{ + Uint32 stack = Regs[REG_A7] + SIZE_LONG; /* skip return address */ + + if (NatFeat_ID(stack, &(Regs[REG_D0]))) { + CpuDoNOP (); + } + return 4; +} + +/** + * Emulator Native Features call opcode interception. + */ +unsigned long OpCode_NatFeat_Call(uae_u32 opcode) +{ + Uint32 stack = Regs[REG_A7] + SIZE_LONG; /* skip return address */ + Uint16 SR = M68000_GetSR(); + bool super; + + super = ((SR & SR_SUPERMODE) == SR_SUPERMODE); + if (NatFeat_Call(stack, super, &(Regs[REG_D0]))) { + CpuDoNOP (); + } + return 4; }