UI: Added "reload rom" shortcut, made power cycle preserve ROM content

This commit is contained in:
Sour 2022-10-05 19:48:45 -04:00
parent 2b3b7e11b7
commit a9c269ef2d
24 changed files with 102 additions and 35 deletions

View file

@ -163,7 +163,7 @@ public:
}
}
static constexpr bool IsVolatileRam(MemoryType memType)
static constexpr bool IsRom(MemoryType memType)
{
switch(memType) {
case MemoryType::SnesPrgRom:
@ -172,7 +172,23 @@ public:
case MemoryType::NesPrgRom:
case MemoryType::NesChrRom:
case MemoryType::PcePrgRom:
case MemoryType::DspDataRom:
case MemoryType::DspProgramRom:
case MemoryType::SpcRom:
return true;
default:
return false;
}
}
static constexpr bool IsVolatileRam(MemoryType memType)
{
if(IsRom(memType)) {
return false;
}
switch(memType) {
case MemoryType::NesSaveRam:
case MemoryType::GbCartRam:
case MemoryType::SnesSaveRam:

View file

@ -26,14 +26,6 @@ MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger)
}
}
bool MemoryAccessCounter::IsAddressUninitialized(AddressInfo& addressInfo)
{
if(DebugUtilities::IsVolatileRam(addressInfo.Type)) {
return _counters[(int)addressInfo.Type][addressInfo.Address].WriteStamp == 0;
}
return false;
}
ReadResult MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint64_t masterClock)
{
if(addressInfo.Address < 0) {
@ -41,7 +33,7 @@ ReadResult MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint
}
AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address];
if(counts.WriteStamp == 0 && IsAddressUninitialized(addressInfo)) {
if(counts.WriteStamp == 0 && DebugUtilities::IsVolatileRam(addressInfo.Type)) {
ReadResult result = counts.ReadStamp == 0 ? ReadResult::FirstUninitRead : ReadResult::UninitRead;
counts.ReadStamp = masterClock;
counts.ReadCounter++;

View file

@ -37,8 +37,6 @@ private:
Debugger* _debugger;
bool IsAddressUninitialized(AddressInfo &addressInfo);
public:
MemoryAccessCounter(Debugger *debugger);

View file

@ -382,6 +382,10 @@ bool Emulator::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
_movieManager->Stop();
}
//Keep copy of current memory types, to allow keeping ROM changes when power cycling
ConsoleMemoryInfo originalConsoleMemory[DebugUtilities::GetMemoryTypeCount()] = {};
memcpy(originalConsoleMemory, _consoleMemory, sizeof(_consoleMemory));
unique_ptr<IConsole> console;
LoadRomResult result = LoadRomResult::UnknownType;
TryLoadRom<NesConsole>(romFile, result, console);
@ -437,7 +441,7 @@ bool Emulator::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
pollCounter = console->GetControlManager()->GetPollCounter();
}
_console.reset(console);
InitConsole(console, originalConsoleMemory, forPowerCycle);
//Restore pollcounter (used by movies when a power cycle is in the movie)
_console->GetControlManager()->SetPollCounter(pollCounter);
@ -489,6 +493,23 @@ bool Emulator::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
return true;
}
void Emulator::InitConsole(unique_ptr<IConsole>& newConsole, ConsoleMemoryInfo originalConsoleMemory[], bool preserveRom)
{
if(preserveRom && _console) {
//When power cycling, copy over the content of any ROM memory from the previous instance
magic_enum::enum_for_each<MemoryType>([&](MemoryType memType) {
if(DebugUtilities::IsRom(memType)) {
uint32_t orgSize = originalConsoleMemory[(int)memType].Size;
if(orgSize > 0 && GetMemory(memType).Size == orgSize) {
memcpy(_consoleMemory[(int)memType].Memory, originalConsoleMemory[(int)memType].Memory, orgSize);
}
}
});
}
_console.reset(newConsole);
}
template<typename T>
void Emulator::TryLoadRom(VirtualFile& romFile, LoadRomResult& result, unique_ptr<IConsole>& console)
{

View file

@ -125,6 +125,7 @@ private:
double GetFrameDelay();
template<typename T> void TryLoadRom(VirtualFile& romFile, LoadRomResult& result, unique_ptr<IConsole>& console);
void InitConsole(unique_ptr<IConsole>& newConsole, ConsoleMemoryInfo originalConsoleMemory[], bool preserveRom);
public:
class DebuggerRequest

View file

@ -698,11 +698,13 @@ enum class EmulatorShortcut
Pause,
Reset,
PowerCycle,
ReloadRom,
PowerOff,
Exit,
ExecReset,
ExecPowerCycle,
ExecReloadRom,
ExecPowerOff,
SetScale1x,

View file

@ -136,6 +136,8 @@ bool ShortcutKeyHandler::IsShortcutAllowed(EmulatorShortcut shortcut, uint32_t s
case EmulatorShortcut::ExecReset:
case EmulatorShortcut::PowerCycle:
case EmulatorShortcut::ExecPowerCycle:
case EmulatorShortcut::ReloadRom:
case EmulatorShortcut::ExecReloadRom:
return isRunning && !isNetplayClient && !isMoviePlaying;
case EmulatorShortcut::PowerOff:
@ -226,6 +228,7 @@ void ShortcutKeyHandler::ProcessShortcutPressed(EmulatorShortcut shortcut, uint3
case EmulatorShortcut::ExecReset: _emu->GetSystemActionManager()->Reset(); break;
case EmulatorShortcut::ExecPowerCycle: _emu->GetSystemActionManager()->PowerCycle(); break;
case EmulatorShortcut::ExecReloadRom: _emu->ReloadRom(false); break;
case EmulatorShortcut::ExecPowerOff: _emu->Stop(true); break;
case EmulatorShortcut::FastForward: settings->SetFlag(EmulationFlags::Turbo); break;

BIN
NewUI/Assets/Reload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

View file

@ -68,10 +68,11 @@ namespace Mesen.Config
private void Init()
{
//TODO cleanup old shortcut definitions and DebuggerShortcut enum
//Shared
Add(new() { Shortcut = DebuggerShortcut.IncreaseFontSize, KeyBinding = new(KeyModifiers.Control, Key.OemPlus) });
Add(new() { Shortcut = DebuggerShortcut.DecreaseFontSize, KeyBinding = new(KeyModifiers.Control, Key.OemMinus) });
Add(new() { Shortcut = DebuggerShortcut.ResetFontSize, KeyBinding = new(KeyModifiers.Control, Key.D0) });
//Add(new() { Shortcut = DebuggerShortcut.IncreaseFontSize, KeyBinding = new(KeyModifiers.Control, Key.OemPlus) });
//Add(new() { Shortcut = DebuggerShortcut.DecreaseFontSize, KeyBinding = new(KeyModifiers.Control, Key.OemMinus) });
//Add(new() { Shortcut = DebuggerShortcut.ResetFontSize, KeyBinding = new(KeyModifiers.Control, Key.D0) });
Add(new() { Shortcut = DebuggerShortcut.GoToAddress, KeyBinding = new(KeyModifiers.Control, Key.G) });
@ -79,9 +80,9 @@ namespace Mesen.Config
Add(new() { Shortcut = DebuggerShortcut.FindNext, KeyBinding = new(Key.F3) });
Add(new() { Shortcut = DebuggerShortcut.FindPrev, KeyBinding = new(KeyModifiers.Shift, Key.F3) });
Add(new() { Shortcut = DebuggerShortcut.Undo, KeyBinding = new(KeyModifiers.Control, Key.Z) });
//Add(new() { Shortcut = DebuggerShortcut.Undo, KeyBinding = new(KeyModifiers.Control, Key.Z) });
Add(new() { Shortcut = DebuggerShortcut.Copy, KeyBinding = new(KeyModifiers.Control, Key.C) });
Add(new() { Shortcut = DebuggerShortcut.Cut, KeyBinding = new(KeyModifiers.Control, Key.X) });
//Add(new() { Shortcut = DebuggerShortcut.Cut, KeyBinding = new(KeyModifiers.Control, Key.X) });
Add(new() { Shortcut = DebuggerShortcut.Paste, KeyBinding = new(KeyModifiers.Control, Key.V) });
Add(new() { Shortcut = DebuggerShortcut.SelectAll, KeyBinding = new(KeyModifiers.Control, Key.A) });
@ -126,6 +127,7 @@ namespace Mesen.Config
//Debugger window
Add(new() { Shortcut = DebuggerShortcut.Reset, KeyBinding = new(KeyModifiers.Control, Key.R) });
Add(new() { Shortcut = DebuggerShortcut.PowerCycle, KeyBinding = new(KeyModifiers.Control, Key.T) });
Add(new() { Shortcut = DebuggerShortcut.ReloadRom, KeyBinding = new() });
Add(new() { Shortcut = DebuggerShortcut.ToggleBreakContinue, KeyBinding = new(Key.Escape) });
Add(new() { Shortcut = DebuggerShortcut.Continue, KeyBinding = new(Key.F5) });
@ -160,12 +162,12 @@ namespace Mesen.Config
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_GoToLocation, KeyBinding = new() });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_MoveProgramCounter, KeyBinding = new(KeyModifiers.Control | KeyModifiers.Shift, Key.F10) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditSelectedCode, KeyBinding = new() });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditSourceFile, KeyBinding = new(Key.F4) });
//Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditSourceFile, KeyBinding = new(Key.F4) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditLabel, KeyBinding = new(Key.F2) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_NavigateBack, KeyBinding = new(KeyModifiers.Alt, Key.Left) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_NavigateForward, KeyBinding = new(KeyModifiers.Alt, Key.Right) });
//Add(new() { Shortcut = DebuggerShortcut.CodeWindow_NavigateBack, KeyBinding = new(KeyModifiers.Alt, Key.Left) });
//Add(new() { Shortcut = DebuggerShortcut.CodeWindow_NavigateForward, KeyBinding = new(KeyModifiers.Alt, Key.Right) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_ToggleBreakpoint, KeyBinding = new(Key.F9) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_DisableEnableBreakpoint, KeyBinding = new(KeyModifiers.Control, Key.F9) });
//Add(new() { Shortcut = DebuggerShortcut.CodeWindow_DisableEnableBreakpoint, KeyBinding = new(KeyModifiers.Control, Key.F9) });
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_SwitchView, KeyBinding = new(KeyModifiers.Control, Key.Q) });
Add(new() { Shortcut = DebuggerShortcut.LabelList_Add, KeyBinding = new(Key.Insert) });
@ -188,8 +190,6 @@ namespace Mesen.Config
Add(new() { Shortcut = DebuggerShortcut.BreakpointList_GoToLocation, KeyBinding = new() });
Add(new() { Shortcut = DebuggerShortcut.BreakpointList_Delete, KeyBinding = new(Key.Delete) });
Add(new() { Shortcut = DebuggerShortcut.WatchList_Add, KeyBinding = new(Key.Insert) });
Add(new() { Shortcut = DebuggerShortcut.WatchList_Edit, KeyBinding = new(Key.F2) });
Add(new() { Shortcut = DebuggerShortcut.WatchList_Delete, KeyBinding = new(Key.Delete) });
Add(new() { Shortcut = DebuggerShortcut.WatchList_MoveUp, KeyBinding = new(KeyModifiers.Alt, Key.Up) });
Add(new() { Shortcut = DebuggerShortcut.WatchList_MoveDown, KeyBinding = new(KeyModifiers.Alt, Key.Down) });
@ -325,6 +325,7 @@ namespace Mesen.Config
OpenDebugSettings,
Reset,
PowerCycle,
ReloadRom,
ToggleBreakContinue,
Continue,
Break,

View file

@ -47,11 +47,13 @@ namespace Mesen.Config.Shortcuts
Pause,
Reset,
PowerCycle,
ReloadRom,
PowerOff,
Exit,
ExecReset,
ExecPowerCycle,
ExecReloadRom,
ExecPowerOff,
SetScale1x,

View file

@ -386,6 +386,9 @@ namespace Mesen.Debugger.Utilities
[IconFile("PowerCycle")]
PowerCycle,
[IconFile("Reload")]
ReloadRom,
[IconFile("Script")]
NewScript,

View file

@ -1,4 +1,5 @@
using Avalonia.Controls;
using Mesen.Config;
using Mesen.Interop;
using Mesen.Utilities;
using System;
@ -17,6 +18,7 @@ namespace Mesen.Debugger.Utilities
return new ContextMenuAction() {
ActionType = ActionType.SaveRomAs,
IsEnabled = () => IsSaveRomSupported(),
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveRomAs),
OnClick = () => SaveRom(wnd, false)
};
}
@ -26,6 +28,7 @@ namespace Mesen.Debugger.Utilities
return new ContextMenuAction() {
ActionType = ActionType.SaveEditsAsIps,
IsEnabled = () => IsSaveRomSupported(),
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveEditAsIps),
OnClick = () => SaveRom(wnd, true)
};
}

View file

@ -106,9 +106,9 @@ namespace Mesen.Debugger.ViewModels
private void InitShortcutLists()
{
SharedShortcuts = CreateShortcutList(new DebuggerShortcut[] {
DebuggerShortcut.IncreaseFontSize,
DebuggerShortcut.DecreaseFontSize,
DebuggerShortcut.ResetFontSize,
//DebuggerShortcut.IncreaseFontSize,
//DebuggerShortcut.DecreaseFontSize,
//DebuggerShortcut.ResetFontSize,
DebuggerShortcut.ZoomIn,
DebuggerShortcut.ZoomOut,
DebuggerShortcut.SaveAsPng,
@ -116,8 +116,8 @@ namespace Mesen.Debugger.ViewModels
DebuggerShortcut.Find,
DebuggerShortcut.FindNext,
DebuggerShortcut.FindPrev,
DebuggerShortcut.Undo,
DebuggerShortcut.Cut,
//DebuggerShortcut.Undo,
//DebuggerShortcut.Cut,
DebuggerShortcut.Copy,
DebuggerShortcut.Paste,
DebuggerShortcut.SelectAll,
@ -154,8 +154,8 @@ namespace Mesen.Debugger.ViewModels
});
MemoryToolsShortcuts = CreateShortcutList(new DebuggerShortcut[] {
//DebuggerShortcut.MemoryViewer_Freeze,
//DebuggerShortcut.MemoryViewer_Unfreeze,
DebuggerShortcut.MemoryViewer_Freeze,
DebuggerShortcut.MemoryViewer_Unfreeze,
DebuggerShortcut.MemoryViewer_AddToWatch,
DebuggerShortcut.MemoryViewer_EditBreakpoint,
DebuggerShortcut.MemoryViewer_EditLabel,
@ -211,6 +211,7 @@ namespace Mesen.Debugger.ViewModels
DebuggerShortcuts = CreateShortcutList(new DebuggerShortcut[] {
DebuggerShortcut.Reset,
DebuggerShortcut.PowerCycle,
DebuggerShortcut.ReloadRom,
DebuggerShortcut.ToggleBreakContinue,
DebuggerShortcut.Continue,
DebuggerShortcut.Break,
@ -241,7 +242,7 @@ namespace Mesen.Debugger.ViewModels
//DebuggerShortcut.CodeWindow_NavigateBack,
//DebuggerShortcut.CodeWindow_NavigateForward,
DebuggerShortcut.CodeWindow_ToggleBreakpoint,
DebuggerShortcut.CodeWindow_DisableEnableBreakpoint,
//DebuggerShortcut.CodeWindow_DisableEnableBreakpoint,
DebuggerShortcut.CodeWindow_MoveProgramCounter,
DebuggerShortcut.CodeWindow_GoToLocation,
DebuggerShortcut.LabelList_Add,
@ -261,8 +262,8 @@ namespace Mesen.Debugger.ViewModels
DebuggerShortcut.BreakpointList_Edit,
DebuggerShortcut.BreakpointList_GoToLocation,
DebuggerShortcut.BreakpointList_Delete,
DebuggerShortcut.WatchList_Add,
DebuggerShortcut.WatchList_Edit,
//DebuggerShortcut.WatchList_Add,
//DebuggerShortcut.WatchList_Edit,
DebuggerShortcut.WatchList_Delete,
DebuggerShortcut.WatchList_MoveUp,
DebuggerShortcut.WatchList_MoveDown,

View file

@ -687,6 +687,11 @@ namespace Mesen.Debugger.ViewModels
ActionType = ActionType.PowerCycle,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.PowerCycle),
OnClick = () => ShortcutHandler.PowerCycle()
},
new ContextMenuAction() {
ActionType = ActionType.ReloadRom,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.ReloadRom),
OnClick = () => ShortcutHandler.ReloadRom()
}
});
};

View file

@ -128,6 +128,7 @@ namespace Mesen.Debugger.ViewModels
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.ExportToPng,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveAsPng),
OnClick = () => picViewer.ExportToPng()
}
});

View file

@ -79,6 +79,7 @@ public class TileEditorViewModel : DisposableViewModel
FileMenuActions = AddDisposables(new List<object>() {
new ContextMenuAction() {
ActionType = ActionType.ExportToPng,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveAsPng),
OnClick = () => picViewer.ExportToPng()
},
new ContextMenuSeparator(),

View file

@ -174,6 +174,7 @@ namespace Mesen.Debugger.ViewModels
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.ExportToPng,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveAsPng),
OnClick = () => picViewer.ExportToPng()
}
});

View file

@ -213,6 +213,7 @@ namespace Mesen.Debugger.ViewModels
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.ExportToPng,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.SaveAsPng),
OnClick = () => _picViewer.ExportToPng()
}
});

View file

@ -377,7 +377,7 @@ namespace Mesen.Debugger.Windows
SetCursorPosition(addr.Type, addr.Address);
}
},
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.MemoryViewer_ViewInDebugger)
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.MemoryViewer_ViewInMemoryType)
};
}

View file

@ -42,6 +42,7 @@ namespace Mesen.Interop
public static void Reset() { Task.Run(() => EmuApi.ExecuteShortcut(new ExecuteShortcutParams() { Shortcut = EmulatorShortcut.ExecReset })); }
public static void PowerCycle() { Task.Run(() => EmuApi.ExecuteShortcut(new ExecuteShortcutParams() { Shortcut = EmulatorShortcut.ExecPowerCycle })); }
public static void PowerOff() { Task.Run(() => EmuApi.ExecuteShortcut(new ExecuteShortcutParams() { Shortcut = EmulatorShortcut.ExecPowerOff })); }
public static void ReloadRom() { Task.Run(() => EmuApi.ExecuteShortcut(new ExecuteShortcutParams() { Shortcut = EmulatorShortcut.ExecReloadRom })); }
[DllImport(DllPath)] public static extern void Pause();
[DllImport(DllPath)] public static extern void Resume();

View file

@ -1534,6 +1534,7 @@
<Message ID="ConfirmReset">Are you sure you want to reset?</Message>
<Message ID="ConfirmPowerCycle">Are you sure you want to power cycle?</Message>
<Message ID="ConfirmReloadRom">Are you sure you want to reload the ROM from the disk?</Message>
<Message ID="ConfirmPowerOff">Are you sure you want to power off?</Message>
<Message ID="ConfirmExit">Are you sure you want to exit?</Message>
@ -1578,6 +1579,7 @@
<Value ID="Pause">Pause</Value>
<Value ID="Reset">Reset</Value>
<Value ID="PowerCycle">Power Cycle</Value>
<Value ID="ReloadRom">Reload ROM</Value>
<Value ID="PowerOff">Power Off</Value>
<Value ID="Exit">Exit</Value>
<Value ID="TakeScreenshot">Take Screenshot</Value>
@ -2724,6 +2726,7 @@
<Value ID="OpenPaletteViewer">Open Palette Viewer</Value>
<Value ID="Reset">Reset</Value>
<Value ID="PowerCycle">Power Cycle</Value>
<Value ID="ReloadRom">Reload ROM</Value>
<Value ID="ToggleBreakContinue">Toggle break/continue</Value>
<Value ID="Continue">Continue</Value>
<Value ID="Break">Break</Value>
@ -2904,6 +2907,7 @@
<Value ID="Break">Break</Value>
<Value ID="Reset">Reset</Value>
<Value ID="PowerCycle">Power Cycle</Value>
<Value ID="ReloadRom">Reload ROM</Value>
<Value ID="StepInto">Step Into</Value>
<Value ID="StepOut">Step Out</Value>
<Value ID="StepOver">Step Over</Value>

View file

@ -38,6 +38,7 @@ namespace Mesen.Utilities
switch(shortcut) {
case EmulatorShortcut.Reset: Reset(); break;
case EmulatorShortcut.PowerCycle: PowerCycle(); break;
case EmulatorShortcut.ReloadRom: ReloadRom(); break;
case EmulatorShortcut.PowerOff: PowerOff(); break;
case EmulatorShortcut.Exit: _mainWindow.Close(); break;
@ -446,6 +447,13 @@ namespace Mesen.Utilities
}
}
public static async void ReloadRom()
{
if(!ConfigManager.Config.Preferences.ConfirmExitResetPower || await MesenMsgBox.Show(null, "ConfirmReloadRom", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
EmuApi.ReloadRom();
}
}
public static async void PowerOff()
{
if(!ConfigManager.Config.Preferences.ConfirmExitResetPower || await MesenMsgBox.Show(null, "ConfirmPowerOff", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {

View file

@ -218,6 +218,7 @@ namespace Mesen.ViewModels
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.Reset) { ActionType = ActionType.Reset },
new MainMenuAction(EmulatorShortcut.PowerCycle) { ActionType = ActionType.PowerCycle },
new MainMenuAction(EmulatorShortcut.ReloadRom) { ActionType = ActionType.ReloadRom },
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.PowerOff) { ActionType = ActionType.PowerOff },

View file

@ -32,6 +32,7 @@ namespace Mesen.ViewModels
EmulatorShortcut.Pause,
EmulatorShortcut.Reset,
EmulatorShortcut.PowerCycle,
EmulatorShortcut.ReloadRom,
EmulatorShortcut.PowerOff,
EmulatorShortcut.Exit,