/* Hatari - change.c 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 code handles run-time configuration changes. We keep all our configuration details in a structure called 'ConfigureParams'. Before doing he changes, a backup copy is done of this structure. When the changes are done, these are compared to see whether emulator needs to be rebooted */ const char Change_fileid[] = "Hatari change.c : " __DATE__ " " __TIME__; #include #include "main.h" #include "configuration.h" #include "audio.h" #include "change.h" #include "dialog.h" #include "floppy.h" #include "fdc.h" #include "gemdos.h" #include "hdc.h" #include "ide.h" #include "ioMem.h" #include "joy.h" #include "keymap.h" #include "m68000.h" #include "midi.h" #include "options.h" #include "printer.h" #include "reset.h" #include "rs232.h" #include "screen.h" #include "sound.h" #include "statusbar.h" #include "tos.h" #include "vdi.h" #include "video.h" #include "hatari-glue.h" #if ENABLE_DSP_EMU # include "falcon/dsp.h" #endif #define DEBUG 0 #if DEBUG #define Dprintf(a...) printf(a) #else #define Dprintf(a...) #endif /*-----------------------------------------------------------------------*/ /** * Check if user needs to be warned that changes will take place after reset. * Return true if wants to reset. */ bool Change_DoNeedReset(CNF_PARAMS *current, CNF_PARAMS *changed) { int i; /* Did we change monitor type? If so, must reset */ if (current->Screen.nMonitorType != changed->Screen.nMonitorType && (changed->System.nMachineType == MACHINE_FALCON || current->Screen.nMonitorType == MONITOR_TYPE_MONO || changed->Screen.nMonitorType == MONITOR_TYPE_MONO)) return true; /* Did change to GEM VDI display? */ if (current->Screen.bUseExtVdiResolutions != changed->Screen.bUseExtVdiResolutions) return true; /* Did change GEM resolution or color depth? */ if (changed->Screen.bUseExtVdiResolutions && (current->Screen.nVdiWidth != changed->Screen.nVdiWidth || current->Screen.nVdiHeight != changed->Screen.nVdiHeight || current->Screen.nVdiColors != changed->Screen.nVdiColors)) return true; /* Did change TOS ROM image? */ if (strcmp(changed->Rom.szTosImageFileName, current->Rom.szTosImageFileName)) return true; /* Did change ACSI hard disk image? */ for (i = 0; i < MAX_ACSI_DEVS; i++) { if (changed->Acsi[i].bUseDevice != current->Acsi[i].bUseDevice || (strcmp(changed->Acsi[i].sDeviceFile, current->Acsi[i].sDeviceFile) && changed->Acsi[i].bUseDevice)) return true; } /* Did change IDE master hard disk image? */ if (changed->HardDisk.bUseIdeMasterHardDiskImage != current->HardDisk.bUseIdeMasterHardDiskImage || strcmp(changed->HardDisk.szIdeMasterHardDiskImage, current->HardDisk.szIdeMasterHardDiskImage)) return true; /* Did change IDE slave hard disk image? */ if (changed->HardDisk.bUseIdeSlaveHardDiskImage != current->HardDisk.bUseIdeSlaveHardDiskImage || strcmp(changed->HardDisk.szIdeSlaveHardDiskImage, current->HardDisk.szIdeSlaveHardDiskImage)) return true; /* Did change GEMDOS drive Atari/host location or enabling? */ if (changed->HardDisk.nGemdosDrive != current->HardDisk.nGemdosDrive || changed->HardDisk.bUseHardDiskDirectories != current->HardDisk.bUseHardDiskDirectories || (strcmp(changed->HardDisk.szHardDiskDirectories[0], current->HardDisk.szHardDiskDirectories[0]) && changed->HardDisk.bUseHardDiskDirectories)) return true; /* Did change machine type? */ if (changed->System.nMachineType != current->System.nMachineType) return true; /* did change ST Blitter? */ else if (current->System.nMachineType == MACHINE_ST && current->System.bBlitter != changed->System.bBlitter) return true; #if ENABLE_DSP_EMU /* enabling DSP needs reset (disabling it not) */ if (current->System.nDSPType != DSP_TYPE_EMU && changed->System.nDSPType == DSP_TYPE_EMU) return true; #endif /* did change CPU type? */ if (changed->System.nCpuLevel != current->System.nCpuLevel) return true; #if ENABLE_WINUAE_CPU /* Did change CPU address mode? */ if (changed->System.bAddressSpace24 != current->System.bAddressSpace24) return true; /* Did change CPU prefetch mode? */ if (changed->System.bCompatibleCpu != current->System.bCompatibleCpu) return true; /* Did change CPU cycle exact? */ if (changed->System.bCycleExactCpu != current->System.bCycleExactCpu) return true; /* Did change MMU? */ if (changed->System.bMMU != current->System.bMMU) return true; /* Did change FPU? */ if (changed->System.n_FPUType != current->System.n_FPUType) return true; /* Did change size of TT-RAM? */ if (current->Memory.nTTRamSize != changed->Memory.nTTRamSize) return true; #endif /* Did change size of memory? */ if (current->Memory.nMemorySize != changed->Memory.nMemorySize) return true; /* MIDI related IRQs start/stop needs reset */ if (current->Midi.bEnableMidi != changed->Midi.bEnableMidi) return true; return false; } /*-----------------------------------------------------------------------*/ /** * Copy details back to configuration and perform reset. */ void Change_CopyChangedParamsToConfiguration(CNF_PARAMS *current, CNF_PARAMS *changed, bool bForceReset) { bool NeedReset; bool bReInitGemdosDrive = false; bool bReInitAcsiEmu = false; bool bReInitIDEEmu = false; bool bReInitIoMem = false; bool bScreenModeChange = false; bool bReInitMidi = false; bool bReInitPrinter = false; bool bFloppyInsert[MAX_FLOPPYDRIVES]; int i; Dprintf("Changes for:\n"); /* Do we need to warn user that changes will only take effect after reset? */ if (bForceReset) NeedReset = bForceReset; else NeedReset = Change_DoNeedReset(current, changed); /* Do need to change resolution? Need if change display/overscan settings * (if switch between Colour/Mono cause reset later) or toggle statusbar */ if (!NeedReset && (changed->Screen.nForceBpp != current->Screen.nForceBpp || changed->Screen.bAspectCorrect != current->Screen.bAspectCorrect || changed->Screen.nMaxWidth != current->Screen.nMaxWidth || changed->Screen.nMaxHeight != current->Screen.nMaxHeight || changed->Screen.bAllowOverscan != current->Screen.bAllowOverscan || changed->Screen.bShowStatusbar != current->Screen.bShowStatusbar #if WITH_SDL2 || changed->Screen.nRenderScaleQuality != current->Screen.nRenderScaleQuality || changed->Screen.bUseVsync != current->Screen.bUseVsync #endif )) { Dprintf("- screenmode>\n"); bScreenModeChange = true; } /* Did set new printer parameters? */ if (changed->Printer.bEnablePrinting != current->Printer.bEnablePrinting || strcmp(changed->Printer.szPrintToFileName,current->Printer.szPrintToFileName)) { Dprintf("- printer>\n"); Printer_UnInit(); bReInitPrinter = true; } /* Did set new RS232 parameters? */ if (changed->RS232.bEnableRS232 != current->RS232.bEnableRS232 || strcmp(changed->RS232.szOutFileName, current->RS232.szOutFileName) || strcmp(changed->RS232.szInFileName, current->RS232.szInFileName)) { Dprintf("- RS-232>\n"); RS232_UnInit(); } /* Did stop sound? Or change playback Hz. If so, also stop sound recording */ if (!changed->Sound.bEnableSound || changed->Sound.nPlaybackFreq != current->Sound.nPlaybackFreq) { Dprintf("- sound>\n"); if (Sound_AreWeRecording()) Sound_EndRecording(); Audio_UnInit(); } /* Did change floppy (images)? */ for (i = 0; i < MAX_FLOPPYDRIVES; i++) { /* Log_Printf(LOG_DEBUG, "Old and new disk %c:\n\t%s\n\t%s", 'A'+i, current->DiskImage.szDiskFileName[i], changed->DiskImage.szDiskFileName[i]); */ if (strcmp(changed->DiskImage.szDiskFileName[i], current->DiskImage.szDiskFileName[i]) || strcmp(changed->DiskImage.szDiskZipPath[i], current->DiskImage.szDiskZipPath[i])) bFloppyInsert[i] = true; else bFloppyInsert[i] = false; } if ( changed->DiskImage.EnableDriveA != current->DiskImage.EnableDriveA ) FDC_Drive_Set_Enable ( 0 , changed->DiskImage.EnableDriveA ); if ( changed->DiskImage.EnableDriveB != current->DiskImage.EnableDriveB ) FDC_Drive_Set_Enable ( 1 , changed->DiskImage.EnableDriveB ); if ( changed->DiskImage.DriveA_NumberOfHeads != current->DiskImage.DriveA_NumberOfHeads ) FDC_Drive_Set_NumberOfHeads ( 0 , changed->DiskImage.DriveA_NumberOfHeads ); if ( changed->DiskImage.DriveB_NumberOfHeads != current->DiskImage.DriveB_NumberOfHeads ) FDC_Drive_Set_NumberOfHeads ( 1 , changed->DiskImage.DriveB_NumberOfHeads ); /* Did change GEMDOS drive Atari/host location or enabling? */ if (changed->HardDisk.nGemdosDrive != current->HardDisk.nGemdosDrive || changed->HardDisk.bUseHardDiskDirectories != current->HardDisk.bUseHardDiskDirectories || (strcmp(changed->HardDisk.szHardDiskDirectories[0], current->HardDisk.szHardDiskDirectories[0]) && changed->HardDisk.bUseHardDiskDirectories)) { Dprintf("- gemdos HD>\n"); GemDOS_UnInitDrives(); bReInitGemdosDrive = true; } /* Did change ACSI image? */ for (i = 0; i < MAX_ACSI_DEVS; i++) { if (changed->Acsi[i].bUseDevice != current->Acsi[i].bUseDevice || (strcmp(changed->Acsi[i].sDeviceFile, current->Acsi[i].sDeviceFile) && changed->Acsi[i].bUseDevice)) { Dprintf("- ACSI image %i>\n", i); bReInitAcsiEmu = true; } } if (bReInitAcsiEmu) HDC_UnInit(); /* Did change IDE HD master image? */ if (changed->HardDisk.bUseIdeMasterHardDiskImage != current->HardDisk.bUseIdeMasterHardDiskImage || (strcmp(changed->HardDisk.szIdeMasterHardDiskImage, current->HardDisk.szIdeMasterHardDiskImage) && changed->HardDisk.bUseIdeMasterHardDiskImage)) { Dprintf("- IDE master>\n"); Ide_UnInit(); bReInitIDEEmu = true; } /* Did change IDE HD slave image? */ if (changed->HardDisk.bUseIdeSlaveHardDiskImage != current->HardDisk.bUseIdeSlaveHardDiskImage || (strcmp(changed->HardDisk.szIdeSlaveHardDiskImage, current->HardDisk.szIdeSlaveHardDiskImage) && changed->HardDisk.bUseIdeSlaveHardDiskImage)) { Dprintf("- IDE slave>\n"); Ide_UnInit(); bReInitIDEEmu = true; } /* Did change blitter, rtc or system type? */ if (changed->System.bBlitter != current->System.bBlitter #if ENABLE_DSP_EMU || changed->System.nDSPType != current->System.nDSPType #endif || changed->System.bRealTimeClock != current->System.bRealTimeClock || changed->System.nMachineType != current->System.nMachineType) { Dprintf("- blitter/rtc/dsp/machine>\n"); IoMem_UnInit(); bReInitIoMem = true; } #if ENABLE_DSP_EMU /* Disabled DSP? */ if (current->System.nDSPType == DSP_TYPE_EMU && changed->System.nDSPType != DSP_TYPE_EMU) { Dprintf("- DSP>\n"); DSP_Disable(); } #endif /* Did change MIDI settings? */ if (current->Midi.bEnableMidi != changed->Midi.bEnableMidi || ((strcmp(changed->Midi.sMidiOutFileName, current->Midi.sMidiOutFileName) || strcmp(changed->Midi.sMidiInFileName, current->Midi.sMidiInFileName)) && changed->Midi.bEnableMidi)) { Dprintf("- midi>\n"); Midi_UnInit(); bReInitMidi = true; } /* Copy details to configuration, * so it can be saved out or set on reset */ if (changed != &ConfigureParams) { ConfigureParams = *changed; } /* Copy details to global, if we reset copy them all */ Configuration_Apply(NeedReset); #if ENABLE_DSP_EMU if (current->System.nDSPType != DSP_TYPE_EMU && changed->System.nDSPType == DSP_TYPE_EMU) { Dprintf("- DSP<\n"); DSP_Enable(); } #endif /* Set keyboard remap file */ if (ConfigureParams.Keyboard.nKeymapType == KEYMAP_LOADED) { Dprintf("- keymap<\n"); Keymap_LoadRemapFile(ConfigureParams.Keyboard.szMappingFileName); } /* Mount a new HD image: */ if (bReInitAcsiEmu) { Dprintf("- HD<\n"); HDC_Init(); } /* Mount a new IDE HD master or slave image: */ if (bReInitIDEEmu && (ConfigureParams.HardDisk.bUseIdeMasterHardDiskImage || ConfigureParams.HardDisk.bUseIdeSlaveHardDiskImage)) { Dprintf("- IDE<\n"); Ide_Init(); } /* Insert floppies? */ for (i = 0; i < MAX_FLOPPYDRIVES; i++) { if (bFloppyInsert[i]) { Dprintf("- floppy<\n"); Floppy_InsertDiskIntoDrive(i); } } /* Mount a new GEMDOS drive? */ if (bReInitGemdosDrive && ConfigureParams.HardDisk.bUseHardDiskDirectories) { Dprintf("- gemdos HD<\n"); GemDOS_InitDrives(); } /* Restart audio sub system if necessary: */ if (ConfigureParams.Sound.bEnableSound && !bSoundWorking) { Dprintf("- audio<\n"); Audio_Init(); } /* Re-initialize the RS232 emulation: */ if (ConfigureParams.RS232.bEnableRS232) { Dprintf("- RS-232<\n"); RS232_Init(); } /* Re-init IO memory map? */ if (bReInitIoMem) { Dprintf("- IO mem<\n"); IoMem_Init(); } /* Re-init Printer emulation? */ if (bReInitPrinter) { Dprintf("- printer<\n"); Printer_Init(); } /* Re-init MIDI emulation? */ if (bReInitMidi) { Dprintf("- midi<\n"); Midi_Init(); } /* Force things associated with screen change */ if (bScreenModeChange) { Dprintf("- screenmode<\n"); Screen_ModeChanged(true); } /* Do we need to perform reset? */ if (NeedReset) { Dprintf("- reset\n"); Reset_Cold(); } /* Go into/return from full screen if flagged */ if (!bInFullScreen && ConfigureParams.Screen.bFullScreen) Screen_EnterFullScreen(); else if (bInFullScreen && !ConfigureParams.Screen.bFullScreen) Screen_ReturnFromFullScreen(); /* update statusbar info (CPU, MHz, mem etc) */ Statusbar_UpdateInfo(); Dprintf("done.\n"); } /*-----------------------------------------------------------------------*/ /** * Change given Hatari options * Return false if parsing failed, true otherwise */ static bool Change_Options(int argc, const char *argv[]) { bool bOK; CNF_PARAMS current; Main_PauseEmulation(false); /* get configuration changes */ current = ConfigureParams; ConfigureParams.Screen.bFullScreen = bInFullScreen; bOK = Opt_ParseParameters(argc, argv); /* Check if reset is required and ask user if he really wants to continue */ if (bOK && Change_DoNeedReset(¤t, &ConfigureParams) && current.Log.nAlertDlgLogLevel > LOG_FATAL) { bOK = DlgAlert_Query("The emulated system must be " "reset to apply these changes. " "Apply changes now and reset " "the emulator?"); } /* Copy details to configuration */ if (bOK) { Change_CopyChangedParamsToConfiguration(¤t, &ConfigureParams, false); } else { ConfigureParams = current; } Main_UnPauseEmulation(); return bOK; } /*-----------------------------------------------------------------------*/ /** * Parse given command line and change Hatari options accordingly. * Given string must be stripped and not empty. * Return false if parsing failed or there were no args, true otherwise */ bool Change_ApplyCommandline(char *cmdline) { int i, argc, inarg; const char **argv; bool ret; /* count args */ inarg = argc = 0; for (i = 0; cmdline[i]; i++) { if (isspace((unsigned char)cmdline[i]) && cmdline[i-1] != '\\') { inarg = 0; continue; } if (!inarg) { inarg++; argc++; } } if (!argc) { return false; } /* 2 = "hatari" + NULL */ argv = malloc((argc+2) * sizeof(char*)); if (!argv) { perror("command line alloc"); return false; } /* parse them to array */ fprintf(stderr, "Command line with '%d' arguments:\n", argc); inarg = argc = 0; argv[argc++] = "hatari"; for (i = 0; cmdline[i]; i++) { if (isspace((unsigned char)cmdline[i])) { if (cmdline[i-1] != '\\') { cmdline[i] = '\0'; if (inarg) { fprintf(stderr, "- '%s'\n", argv[argc-1]); } inarg = 0; continue; } else { /* remove quote for space */ memcpy(cmdline+i-1, cmdline+i, strlen(cmdline+i)+1); i--; } } if (!inarg) { argv[argc++] = &(cmdline[i]); inarg++; } } if (inarg) { fprintf(stderr, "- '%s'\n", argv[argc-1]); } argv[argc] = NULL; /* do args */ ret = Change_Options(argc, argv); free((void *)argv); return ret; }