📄 jdev_main.pas
字号:
if Assigned(dwarf) then dwarf.Free; dwarf := nil;
if Assigned(elf) then elf.Free; elf := nil;
try
// Load the file into the core
stream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone);
case typ of
ftROM: begin
GetMem(data, stream.size);
stream.Read(data^, stream.size);
vmInsertCartridge(data, stream.size);
FreeMem(data, stream.size);
cartLoaded := true;
stream.Free;
end;
ftMultiboot: begin
vmLockMemory(banks);
stream.Read(banks.exwram^, Min(stream.size, $40000));
banks.wram^[$7FFA] := 1;
vmUnlockMemory(banks);
stream.Free;
end;
ftELF: begin
cartLoaded := true;
// Create and build an elf class out of the file
elf := TELFFile.Create(stream);
elf.Build;
// Flatten the elf into a binary
size := elf.Flatten(data);
vmInsertCartridge(data, size);
dwarf := ProcessDWARF(elf, ExtractFilePath(filename));
stream.Free;
end;
ftSaveState: LoadSavestate(filename, stream);
else
stream.Free;
end;
ReassertBreakpoints;
except on
e: Exception do begin
logWriteLn('Error: ' + e.Message);
e.Free;
end;
end;
// Reset user interface stuff
isActive := autorunROMs;
fps := 0;
lastRomFilename := filename;
if typ <> ftSavestate then begin
vmReset;
LoadCartInfo;
if typ = ftMultiboot then begin
vmSetRegister(r15, $02000000)
end else
if autopatchLogo then PatchHeader;
end;
// Update the observer display
if mruList.IndexOf(lastRomFilename) = -1 then begin
mruList.Insert(0, lastRomFilename);
if mruList.Count > 10 then mruList.Delete(10);
RebuildMRUList;
end;
Caption := 'Mappy VM [' + ExtractFileName(lastROMFilename) + ']';
UpdateObservers;
// Initialize the file watcher
lastFileAge := FileAge(filename);
fileWatcher.Directory := ExtractFilePath(filename);
fileWatcher.Start;
Result := true;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.clockTimer(Sender: TObject);
begin
//
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.OnIdle(Sender: TObject; var Done: Boolean);
var
cycles, delta: integer;
token: TvmProfileToken;
t0, tslf: uint32;
begin
Done := true;
if clockMutex then Exit;
if not coreLoaded then Exit;
clockMutex := true;
timeBeginPeriod(1);
tslf := timeGetTime;
repeat
if isActive then begin
// If we're meant to do automatic updates, and there is a rom loaded, then lets rock
// Start the fps processing
token := vmStartProfile;
vmRenderFrame;
cycles := vmStopProfile(token);
ExecuteCleanup;
UpdateObservers;
repeat until timeGetTime-tslf > msBetweenFrames;
// Update the framerate
t0 := timeGetTime;
delta := t0-tslf;
tslf := t0;
if delta <> 0 then begin
fps := 0.95*fps + 0.05*(1000/delta)*(cycles/(1232*228));
if sysSound.frequency > 0 then
vmSetAudioRate(max(trunc((fps * 16777216) / (sysSound.frequency*59.727)), 64));
end;
if capturing then
status.Panels[0].Text := ' Status: Capturing'
else
status.Panels[0].Text := ' Status: Running';
status.Panels[1].Text := Format(' FPS: %.1f (%.0f%% optimal)', [fps, 100*fps/59.727])
end else begin
status.Panels[0].Text := ' Status: Paused';
if Copy(status.Panels[1].Text, 1, 4) = ' FPS' then status.Panels[1].Text := '';
end;
sysSound.enabled := isActive and appFocused and mToggleSoundEnabled.Checked;
Application.ProcessMessages;
until Application.Terminated or not isActive;
timeEndPeriod(1);
clockMutex := false;
end;
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.LoadCore(filename: string);
var
i: integer;
ini: TIniFile;
item: TMenuItem;
st: string;
ws: TWindowState;
begin
ini := TIniFile.Create(appIniFile);
vmLoadCore(PChar(filename));
// Video Setup
InitVideo;
vmSetOnVideo(OnVideoReady);
vmSetOnConsole(OnConsoleReady);
ws := TWindowState(Min(2, Max(0, ini.ReadInteger('Video Options', 'WindowState', Ord(wsNormal)))));
if ws <> wsMaximized then begin
ClientWidth := ini.ReadInteger('Video Options', 'ScreenWidth', 240);
ClientHeight := status.height + ini.ReadInteger('Video Options', 'ScreenHeight', 160);
Left := ini.ReadInteger('Video Options', 'Left', Left);
Top := ini.ReadInteger('Video Options', 'Top', Top);
end else begin
ClientWidth := 240;
ClientHeight := status.height + 160;
end;
WindowState := ws;
LoadVideoOptions(ini);
// Audio Setup
sysSound := TDirectSoundDriver.Create;
LoadAudioOptions(ini);
sysSound.Available := true;
// Joypad Setup
LoadJoypadOptions(ini);
// Debug Setup
LoadDebugOptions(ini);
// General Setup
LoadGeneralOptions(ini);
// Reset the CPU
vmReset;
// Filenames
lastRomFilename := ini.ReadString('Filenames', 'LastImage', '');
lastScreenshotFilename := ini.ReadString('Filenames', 'LastScreenshot', '');
if not FileExists(lastRomFilename) then lastRomFilename := '';
if not FileExists(lastScreenshotFilename) then lastScreenshotFilename := '';
mruList.Clear;
for i := 0 to 9 do begin
st := ini.ReadString('Filenames', 'Recent' + IntToStr(i), '');
if FileExists(st) then mruList.Insert(i, st);
end;
RebuildMRUList;
// Open any previously opened viewers
for i := 0 to menuViewers.Count - 1 do begin
item := TMenuItem(menuViewers.Items[i]);
if ini.ReadBool(StripHotKey(item.Caption), 'Opened', false) then
CreateObserver(StripHotKey(item.Caption), item);
end;
// Close the .INI file
ini.Free;
Application.OnActivate := OnActivateApp;
Application.OnDeactivate := OnDeactivateApp;
Application.OnIdle := OnIdle;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.UnloadCore;
var
ini: TIniFile;
i: integer;
st: string;
begin
ini := TIniFile.Create(appIniFile);
// Video Setup
vmSetOnVideo(nil);
SaveVideoOptions(ini);
FreeVideo;
ini.WriteInteger('Video Options', 'WindowState', Ord(WindowState));
ini.WriteInteger('Video Options', 'ScreenWidth', ClientWidth);
ini.WriteInteger('Video Options', 'ScreenHeight', ClientHeight - status.height);
ini.WriteInteger('Video Options', 'Left', Left);
ini.WriteInteger('Video Options', 'Top', Top);
// Audio Setup
SaveAudioOptions(ini);
sysSound.Free;
// Joypad Setup
SaveJoypadOptions(ini);
// Debug Setup
SaveDebugOptions(ini);
// General Setup
SaveGeneralOptions(ini);
// Observers
for i := 0 to menuViewers.Count - 1 do begin
st := StripHotKey(TMenuItem(menuViewers.Items[i]).Caption);
ini.WriteBool(st, 'Opened', FindObserver(st) <> nil);
end;
// Filenames
ini.WriteString('Filenames', 'LastImage', lastRomFilename);
ini.WriteString('Filenames', 'LastScreenshot', lastScreenshotFilename);
for i := 0 to 9 do begin
if i < mruList.Count then st := mruList.Strings[i] else st := '';
ini.WriteString('Filenames', 'Recent' + IntToStr(i), st);
end;
mruList.Clear;
RebuildMRUList;
CloseObservers;
// Unload the core
vmSetOnConsole(nil);
vmUnloadCore;
ini.Free;
Application.OnActivate := nil;
Application.OnDeactivate := nil;
Application.OnIdle := nil;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.LoadCartInfo;
var
size: integer;
data: PByteArray;
stream: TFileStream;
name: string;
banks: TvmMemoryLock1;
begin
name := ChangeFileExt(lastRomFilename, '.sav');
if FileExists(name) then begin
logWriteLn('Loading cartridge info from ' + ExtractFileName(name));
stream := TFileStream.Create(name, fmOpenRead or fmShareDenyNone);
size := stream.Size;
GetMem(data, size);
stream.Read(data^, size);
vmLockMemory(banks);
vmSetCartInfo(size, data);
vmUnlockMemory(banks);
FreeMem(data, size);
stream.Free;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.SaveCartInfo;
var
size: integer;
data: pointer;
stream: TFileStream;
name: string;
begin
size := vmGetCartInfo(nil);
if size > 0 then begin
name := ChangeFileExt(lastRomFilename, '.sav');
logWriteLn('Saving cartridge info to ' + ExtractFileName(name));
GetMem(data, size);
vmGetCartInfo(data);
stream := TFileStream.Create(name, fmCreate);
stream.Write(data^, size);
stream.Free;
FreeMem(data, size);
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.mNothingnessClick(Sender: TObject);
var
list: TStringList;
i: integer;
begin
Beep;
list := TStringList.Create;
SaveTranslation(self, list);
for i := 0 to observerList.count - 1 do
SaveTranslation((observerList.Items[i] as TCpuObserver), list);
SaveTranslation(jdevModify, list);
SaveTranslation(jdevDisasmDialog, list);
SaveTranslation(jdevCaptureForm, list);
SaveTranslation(dbgFindPattern, list);
list.SaveToFile(ExtractFilePath(ParamStr(0)) + 'American English.trs');
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.LoadNewCore(Sender: TObject);
begin
openDialog.Filter := 'Mappy VM Cores|*.core|All files|*.*';
openDialog.DefaultExt := 'core';
openDialog.FileName := ExtractFilePath(ParamStr(0)) + 'core\standard.core';
if openDialog.Execute then
if FileExists(openDialog.Filename) then begin
UnloadCore;
LoadCore(openDialog.Filename);
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.SaveSavestate(Sender: TObject);
var
size: integer;
save: PvmSavestate;
stream: TFileStream;
st: string;
begin
saveDialog.Filter := 'Maypy VM Savestates|*.jst|All files|*.*';
saveDialog.filename := ChangeFileExt(lastRomFilename, '.jst');
saveDialog.DefaultExt := 'jst';
if saveDialog.Execute then begin
size := vmSaveState(nil);
if size > 0 then begin
GetMem(save, size);
vmSaveState(save);
if save^.cartLoaded then begin
st := ExtractFileName(lastRomFilename);
if st <> '' then begin
Move(st[1], save^.filename, Min(Length(st), 255));
save^.filename[Min(Length(st), 255)] := #0;
save^.crc := CrcROM;
end;
end;
stream := TFileStream.Create(saveDialog.Filename, fmCreate);
stream.Write(save^, size);
stream.Free;
FreeMem(save, size);
end;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.DwarfDebugger1Click(Sender: TObject);
begin
jdevDwarfDebug.Show;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.RebuildMRUList;
var
i: integer;
begin
mReopenFile.Clear;
for i := 0 to mruList.Count - 1 do begin
mReopenFile.Add(NewItem(mruList.Strings[i], 0, false, true, LoadRecent, i, 'mruitem'+IntToStr(i)));
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.RebuildPluginList;
var
i: integer;
plugin: PvmPluginHeader;
item: TMenuItem;
begin
for i := 0 to plugins.Count - 1 do begin
plugin := @(TPlugin(plugins.items[i]).header);
item := NewItem(plugin^.triggerCaption, 0, false, true, OnTriggerPluginClick, i, 'triggerPlugin'+IntToStr(i));
item.Tag := i;
mTools.Add(item);
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevMain.OnTriggerPluginClick(Sender: TObject);
begin
TriggerPlugin(TMenuItem(Sender).Tag);
end;
//////////////////////////////////////////////////////////////////////
initialization
msBetweenFrames := 0;
end.
//////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -