📄 observerhexeditor.pas
字号:
//////////////////////////////////////////////////////////////////////
// //
// observerHexEditor.pas: Memory viewer and editor //
// //
// The contents of this file are subject to the Bottled Light //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a //
// copy of the License at http://www.bottledlight.com/BLPL/ //
// //
// Software distributed under the License is distributed on an //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or //
// implied. See the License for the specific language governing //
// rights and limitations under the License. //
// //
// The Original Code is the Mappy VM User Interface, released //
// April 1st, 2003. The Initial Developer of the Original Code is //
// Bottled Light, Inc. Portions created by Bottled Light, Inc. are //
// Copyright (C) 2001-2003 Bottled Light, Inc. All Rights Reserved. //
// //
// Author(s): //
// Michael Noland (joat), michael@bottledlight.com //
// //
// Changelog: //
// 1.0: First public release (April 1st, 2003) //
// //
// Notes: //
// None at present. //
// //
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
unit observerHexEditor; //////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IniFiles, CpuObservers, Menus, debugFindPattern,
Math, console, nexus, AddressSpace, ComCtrls, ToolWin;
//////////////////////////////////////////////////////////////////////
type
THexEditorMode = (hemStream, hemByte, hemHalfword, hemWord);
TjdevHexEditor = class(TCpuObserver)
scrollbar: TScrollBar;
popupMenu: TPopupMenu;
mBrowseTo: TMenuItem;
mReturntoPC: TMenuItem;
N2: TMenuItem;
mDisplayBIOS: TMenuItem;
mDisplayExWRAM: TMenuItem;
mDisplayWRAM: TMenuItem;
mDisplayPalette: TMenuItem;
mDisplayOAM: TMenuItem;
mDisplayVRAM: TMenuItem;
mDisplayROM: TMenuItem;
editor: TEdit;
mViewStack: TMenuItem;
mDisplaySRAM: TMenuItem;
saveDialog: TSaveDialog;
openDialog: TOpenDialog;
toolbar: TToolBar;
Spacer1: TToolButton;
rbByte: TRadioButton;
rbHalfword: TRadioButton;
rbWord: TRadioButton;
Spacer2: TToolButton;
eAddress: TComboBox;
bGoto: TToolButton;
rbStream: TRadioButton;
bTools: TToolButton;
mFindPattern: TMenuItem;
mFindAgain: TMenuItem;
N1: TMenuItem;
mLoadIntoMemory: TMenuItem;
mSaveMemory: TMenuItem;
N3: TMenuItem;
bHelp: TToolButton;
bFind: TToolButton;
fontDialog: TFontDialog;
N4: TMenuItem;
mChangeFont: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure scrollbarChange(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure editorKeyPress(Sender: TObject; var Key: Char);
procedure ChangeDisplayMode(Sender: TObject);
procedure ChangeCurrentBank(Sender: TObject);
procedure GotoAddress(Sender: TObject);
procedure addressKeyPress(Sender: TObject; var Key: Char);
procedure BrowseTo(Sender: TObject);
procedure ReturnToPC(Sender: TObject);
procedure ReturnToSP(Sender: TObject);
procedure DisplayBIOS(Sender: TObject);
procedure DisplayExWRAM(Sender: TObject);
procedure DisplayWRAM(Sender: TObject);
procedure DisplayPalette(Sender: TObject);
procedure DisplayVRAM(Sender: TObject);
procedure DisplayOAM(Sender: TObject);
procedure DisplayROM(Sender: TObject);
procedure DisplaySRAM(Sender: TObject);
procedure LoadRawMemory(Sender: TObject);
procedure SaveRawMemory(Sender: TObject);
procedure FindPattern(Sender: TObject);
procedure FindPatternAgain(Sender: TObject);
procedure ShowMenu(Sender: TObject);
procedure ShowHelp(Sender: TObject);
procedure ChangeFont(Sender: TObject);
procedure FormDestroy(Sender: TObject);
protected
FEditingAt: uint32;
findingAgain: boolean;
baseAddress: uint32;
fontString: string;
displayMode: THexEditorMode;
procedure FinishEditing;
procedure SetAddress(addr: uint32);
public
procedure UpdateObserver; override;
class function OCaption: string; override;
procedure LoadSettings(ini: TIniFile); override;
procedure SaveSettings(ini: TIniFile); override;
end;
//////////////////////////////////////////////////////////////////////
var
jdevHexEditor: TjdevHexEditor;
//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
{$R *.DFM}
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormCreate(Sender: TObject);
begin
HelpContext := LinkHelp('memory_editor.html');
editor.visible := false;
findingAgain := false;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormShow(Sender: TObject);
begin
eAddress.Text := '$' + IntToHex(vmCurrentPC, 8);
SetAddress(vmCurrentPC);
if fontString <> '' then StringToFont(fontString, Font);
// Load the translation
LoadTranslation(self, translation);
end;
//////////////////////////////////////////////////////////////////////
class function TjdevHexEditor.OCaption: string;
begin
Result := 'Memory Editor';
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.UpdateObserver;
var
addr: uint32;
i, y: integer;
data: array[0..16] of byte;
st: string;
mirror: boolean;
numLines: integer;
cartSize1, cartSize2: uint32;
banks: TvmMemoryLock1;
begin
Constraints.MinWidth := 0;
Constraints.MaxWidth := 0;
case displayMode of
hemStream: ClientWidth := canvas.TextWidth('@')*(28 + 32) + scrollbar.width;
hemByte: ClientWidth := canvas.TextWidth('@')*(28 + 47) + scrollbar.width;
hemHalfword: ClientWidth := canvas.TextWidth('@')*(28 + 39) + scrollbar.width;
hemWord: ClientWidth := canvas.TextWidth('@')*(28 + 35) + scrollbar.width;
end;
Constraints.MinWidth := Width;
Constraints.MaxWidth := Width;
numLines := 0;
y := toolbar.height;
addr := baseAddress;
while (y < clientHeight) and (addr < $10000000) do begin
st := IntToHex(addr, 8) + ' ';
// addr := addr and $0FFFFFFF;
vmLockMemory(banks);
cartSize1 := Min(banks.romsize, 1 shl 24);
cartSize2 := banks.romsize - cartSize1;
vmUnlockMemory(banks);
case (addr shr 24) and $F of
$0,$1: mirror := addr >= $00000000 + SYSTEM_ROM_MASK;
$2: mirror := addr > $02000000 + EX_WRAM_MASK;
$3: mirror := addr > $03000000 + WRAM_MASK;
$5: mirror := addr > $05000000 + PALETTE_MASK;
$6: mirror := addr >= $06014000;
$7: mirror := addr > $07000000 + OAM_MASK;
$8: mirror := addr >= $08000000 + cartSize1;
$A: mirror := addr >= $0A000000 + cartSize1;
$C: mirror := addr >= $0C000000 + cartSize1;
$9: mirror := addr >= $09000000 + cartSize2;
$B: mirror := addr >= $0B000000 + cartSize2;
$D: mirror := addr >= $0D000000 + cartSize2;
$E: mirror := addr > $0E000000 + SRAM_MASK;
$F: mirror := addr > $0F000000 + SRAM_MASK;
else
mirror := false;
end;
canvas.brush.Color := clBtnFace;
if mirror then
canvas.Font.Color := clGrayText
else
canvas.Font.Color := clBtnText;
// Get the data
case displayMode of
hemStream: begin
st := st + ' ';
for i := 0 to 15 do begin
data[i] := vmReadByte(addr);
Inc(addr);
st := st + IntToHex(data[i], 2);
end;
end;
hemByte: for i := 0 to 15 do begin
data[i] := vmReadByte(addr);
Inc(addr);
st := st + ' ' + IntToHex(data[i], 2);
end;
hemHalfword: for i := 0 to 15 do begin
data[i] := vmReadByte(addr);
Inc(addr);
if i and 1 = 1 then st := st + ' ' + IntToHex(Puint16(@(data[i and not 1]))^, 4);
end;
hemWord: for i := 0 to 15 do begin
data[i] := vmReadByte(addr);
Inc(addr);
if i and 3 = 3 then st := st + ' ' + IntToHex(Puint32(@(data[i and not 3]))^, 8);
end;
end;
// Add the ASCII dump on the right
for i := 0 to 15 do if data[i] < 32 then data[i] := Ord('.');
data[16] := 0;
st := st + ' ' + Pchar(@(data[0]));
// Draw it
canvas.TextOut(0, y, st);
y := y + canvas.TextHeight(st);
Inc(numLines);
end;
scrollbar.LargeChange := Max(numLines-1, 1)*16;
if (addr > $10000000) and (st <> '') then begin
numLines := Height div canvas.TextHeight(st)-1;
baseAddress := $10000000 - uint32(Max(numLines, 1)*16);
Repaint;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormPaint(Sender: TObject);
begin
// Font.Assign(hexEditorFont);
// editor.Font.Assign(hexEditorFont);
if not editor.visible then editor.Top := -editor.height;
editor.Width := canvas.TextWidth('@')*2;
editor.Height := canvas.TextHeight('@');
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormResize(Sender: TObject);
begin
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
SetAddress(Min(scrollbar.Position + 16, scrollbar.Max));
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
SetAddress(Max(scrollbar.Position - 16, scrollbar.Min));
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.SetAddress(addr: uint32);
begin
scrollbar.Position := addr and $0FFFFFF0;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.scrollbarChange(Sender: TObject);
begin
if uint32(scrollbar.Position) <> baseAddress then FinishEditing;
baseAddress := scrollbar.Position;
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
w, h: integer;
begin
if editor.visible then
FinishEditing
else if Button = mbLeft then begin
w := canvas.TextWidth('@');
h := canvas.TextHeight('@');
Y := (Y-toolbar.height) div h;
X := X div w - 10;
case displayMode of
hemStream: begin
X := X div 2;
if (X >= 0) and (X < 16) then begin
FEditingAt := baseAddress + uint32(Y*16 + X);
editor.text := '';
editor.Left := (X*2+10)*w;
editor.Top := h*Y + toolbar.height;
editor.Visible := true;
end;
end;
hemByte: if X and 3 <> 3 then begin
X := X div 3;
if (X >= 0) and (X < 16) then begin
FEditingAt := baseAddress + uint32(Y*16 + X);
editor.text := '';
editor.Left := (X*3+10)*w;
editor.Top := h*Y + toolbar.height;
editor.Visible := true;
end;
end;
hemHalfword: if X mod 5 <> 4 then begin
X := (X-((X+1) div 5)) div 2;
if (X >= 0) and (X < 16) then begin
FEditingAt := baseAddress + uint32(Y*16 + X xor 1);
editor.text := '';
editor.Left := ((X shr 1)*5 + (X and 1)*2 + 10)*w;
editor.Top := h*Y + toolbar.height;
editor.Visible := true;
end;
end;
hemWord: if X mod 9 <> 8 then begin
X := (X-((X+1) div 9)) div 2;
if (X >= 0) and (X < 16) then begin
FEditingAt := baseAddress + uint32(Y*16 + X xor 3);
editor.text := '';
editor.Left := ((X shr 2)*9 + (X and 3)*2 + 10)*w;
editor.Top := h*Y + toolbar.height;
editor.Visible := true;
end;
end;
end;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.editorKeyPress(Sender: TObject; var Key: Char);
begin
if (key = #10) or (key = #13) then begin
FinishEditing;
Key := #0;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevHexEditor.FinishEditing;
var
st: string;
begin
if editor.visible then begin
st := Trim(editor.Text);
if (Length(st) > 0) and (st[1] <> '$') then st := '$' + st;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -