Memory viewer now has a Goto command, different memory space modes, and allows viewing/editing specific banks
This commit is contained in:
parent
f9236d12bf
commit
0734e990b3
@ -9,6 +9,9 @@
|
|||||||
@property (strong) IBOutlet NSWindow *mainWindow;
|
@property (strong) IBOutlet NSWindow *mainWindow;
|
||||||
@property (strong) IBOutlet NSView *memoryView;
|
@property (strong) IBOutlet NSView *memoryView;
|
||||||
@property (strong) IBOutlet NSPanel *memoryWindow;
|
@property (strong) IBOutlet NSPanel *memoryWindow;
|
||||||
|
@property (readonly) GB_gameboy_t *gameboy;
|
||||||
|
@property (strong) IBOutlet NSTextField *memoryBankInput;
|
||||||
|
@property (strong) IBOutlet NSToolbarItem *memoryBankItem;
|
||||||
|
|
||||||
-(uint8_t) readMemory:(uint16_t) addr;
|
-(uint8_t) readMemory:(uint16_t) addr;
|
||||||
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
||||||
|
107
Cocoa/Document.m
107
Cocoa/Document.m
@ -8,6 +8,8 @@
|
|||||||
#include "HexFiend/HexFiend.h"
|
#include "HexFiend/HexFiend.h"
|
||||||
#include "GBMemoryByteArray.h"
|
#include "GBMemoryByteArray.h"
|
||||||
|
|
||||||
|
/* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */
|
||||||
|
|
||||||
@interface Document ()
|
@interface Document ()
|
||||||
{
|
{
|
||||||
/* NSTextViews freeze the entire app if they're modified too often and too quickly.
|
/* NSTextViews freeze the entire app if they're modified too often and too quickly.
|
||||||
@ -20,6 +22,7 @@
|
|||||||
HFController *hex_controller;
|
HFController *hex_controller;
|
||||||
|
|
||||||
NSString *lastConsoleInput;
|
NSString *lastConsoleInput;
|
||||||
|
HFLineCountingRepresenter *lineRep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property GBAudioClient *audioClient;
|
@property GBAudioClient *audioClient;
|
||||||
@ -175,6 +178,12 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
|||||||
}
|
}
|
||||||
[self readFromFile:self.fileName ofType:@"gb"];
|
[self readFromFile:self.fileName ofType:@"gb"];
|
||||||
[self start];
|
[self start];
|
||||||
|
|
||||||
|
if (hex_controller) {
|
||||||
|
/* Verify bank sanity, especially when switching models. */
|
||||||
|
[(GBMemoryByteArray *)(hex_controller.byteArray) setSelectedBank:0];
|
||||||
|
[self hexUpdateBank:self.memoryBankInput];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)togglePause:(id)sender
|
- (IBAction)togglePause:(id)sender
|
||||||
@ -221,7 +230,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
|||||||
HFHexTextRepresenter *hexRep = [[HFHexTextRepresenter alloc] init];
|
HFHexTextRepresenter *hexRep = [[HFHexTextRepresenter alloc] init];
|
||||||
HFStringEncodingTextRepresenter *asciiRep = [[HFStringEncodingTextRepresenter alloc] init];
|
HFStringEncodingTextRepresenter *asciiRep = [[HFStringEncodingTextRepresenter alloc] init];
|
||||||
HFVerticalScrollerRepresenter *scrollRep = [[HFVerticalScrollerRepresenter alloc] init];
|
HFVerticalScrollerRepresenter *scrollRep = [[HFVerticalScrollerRepresenter alloc] init];
|
||||||
HFLineCountingRepresenter *lineRep = [[HFLineCountingRepresenter alloc] init];
|
lineRep = [[HFLineCountingRepresenter alloc] init];
|
||||||
HFStatusBarRepresenter *statusRep = [[HFStatusBarRepresenter alloc] init];
|
HFStatusBarRepresenter *statusRep = [[HFStatusBarRepresenter alloc] init];
|
||||||
|
|
||||||
lineRep.lineNumberFormat = HFLineNumberFormatHexadecimal;
|
lineRep.lineNumberFormat = HFLineNumberFormatHexadecimal;
|
||||||
@ -250,6 +259,8 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
|||||||
[layoutView setFrame:layoutViewFrame];
|
[layoutView setFrame:layoutViewFrame];
|
||||||
[layoutView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable | NSViewMaxYMargin];
|
[layoutView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable | NSViewMaxYMargin];
|
||||||
[self.memoryView addSubview:layoutView];
|
[self.memoryView addSubview:layoutView];
|
||||||
|
|
||||||
|
self.memoryBankItem.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)autosavesInPlace {
|
+ (BOOL)autosavesInPlace {
|
||||||
@ -521,7 +532,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
|||||||
- (void) performAtomicBlock: (void (^)())block
|
- (void) performAtomicBlock: (void (^)())block
|
||||||
{
|
{
|
||||||
while (!is_inited);
|
while (!is_inited);
|
||||||
bool was_running = running;
|
bool was_running = running && !gb.debug_stopped;
|
||||||
if (was_running) {
|
if (was_running) {
|
||||||
[self stop];
|
[self stop];
|
||||||
}
|
}
|
||||||
@ -546,4 +557,96 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
|||||||
[self.memoryWindow makeKeyAndOrderFront:sender];
|
[self.memoryWindow makeKeyAndOrderFront:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)hexGoTo:(id)sender
|
||||||
|
{
|
||||||
|
[self performAtomicBlock:^{
|
||||||
|
uint16_t addr;
|
||||||
|
if (GB_debugger_evaluate(&gb, [[sender stringValue] UTF8String], &addr, NULL)) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr -= lineRep.valueOffset;
|
||||||
|
if (addr >= hex_controller.byteArray.length) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[hex_controller setSelectedContentsRanges:@[[HFRangeWrapper withRange:HFRangeMake(addr, 0)]]];
|
||||||
|
[hex_controller _ensureVisibilityOfLocation:addr];
|
||||||
|
[self.memoryWindow makeFirstResponder:self.memoryView.subviews[0].subviews[0]];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)hexUpdateBank:(NSControl *)sender
|
||||||
|
{
|
||||||
|
[self performAtomicBlock:^{
|
||||||
|
uint16_t addr, bank;
|
||||||
|
if (GB_debugger_evaluate(&gb, [[sender stringValue] UTF8String], &addr, &bank)) {
|
||||||
|
NSBeep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bank == (uint16_t) -1) {
|
||||||
|
bank = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t n_banks = 1;
|
||||||
|
switch ([(GBMemoryByteArray *)(hex_controller.byteArray) mode]) {
|
||||||
|
case GBMemoryROM:
|
||||||
|
n_banks = gb.rom_size / 0x4000;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
n_banks = gb.is_cgb ? 2 : 1;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
n_banks = gb.mbc_ram_size / 0x2000;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
n_banks = gb.is_cgb ? 8 : 1;
|
||||||
|
break;
|
||||||
|
case GBMemoryEntireSpace:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank %= n_banks;
|
||||||
|
|
||||||
|
[sender setStringValue:[NSString stringWithFormat:@"$%x", bank]];
|
||||||
|
[(GBMemoryByteArray *)(hex_controller.byteArray) setSelectedBank:bank];
|
||||||
|
[hex_controller reloadData];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)hexUpdateSpace:(NSPopUpButtonCell *)sender
|
||||||
|
{
|
||||||
|
self.memoryBankItem.enabled = [sender indexOfSelectedItem] != GBMemoryEntireSpace;
|
||||||
|
GBMemoryByteArray *byteArray = (GBMemoryByteArray *)(hex_controller.byteArray);
|
||||||
|
[byteArray setMode:(GB_memory_mode_t)[sender indexOfSelectedItem]];
|
||||||
|
switch ((GB_memory_mode_t)[sender indexOfSelectedItem]) {
|
||||||
|
case GBMemoryEntireSpace:
|
||||||
|
case GBMemoryROM:
|
||||||
|
lineRep.valueOffset = 0;
|
||||||
|
byteArray.selectedBank = gb.mbc_rom_bank;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
lineRep.valueOffset = 0x8000;
|
||||||
|
byteArray.selectedBank = gb.cgb_vram_bank;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
lineRep.valueOffset = 0xA000;
|
||||||
|
byteArray.selectedBank = gb.mbc_ram_bank;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
lineRep.valueOffset = 0xC000;
|
||||||
|
byteArray.selectedBank = gb.cgb_ram_bank;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[self.memoryBankInput setStringValue:[NSString stringWithFormat:@"$%x", byteArray.selectedBank]];
|
||||||
|
[hex_controller reloadData];
|
||||||
|
[self.memoryView setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (GB_gameboy_t *) gameboy
|
||||||
|
{
|
||||||
|
return &gb;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
@ -10,6 +10,8 @@
|
|||||||
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
|
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
|
||||||
<outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/>
|
<outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/>
|
||||||
<outlet property="mainWindow" destination="xOd-HO-29H" id="h8M-YB-vcC"/>
|
<outlet property="mainWindow" destination="xOd-HO-29H" id="h8M-YB-vcC"/>
|
||||||
|
<outlet property="memoryBankInput" destination="rdV-q6-hc6" id="KBx-9T-2mX"/>
|
||||||
|
<outlet property="memoryBankItem" destination="bWC-FW-IYP" id="Lf2-dh-z32"/>
|
||||||
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
||||||
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
||||||
<outlet property="view" destination="uqf-pe-VAF" id="HMP-rf-Yqk"/>
|
<outlet property="view" destination="uqf-pe-VAF" id="HMP-rf-Yqk"/>
|
||||||
@ -69,10 +71,10 @@
|
|||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<size key="minSize" width="600" height="376"/>
|
<size key="minSize" width="600" height="376"/>
|
||||||
<size key="maxSize" width="600" height="10000000"/>
|
<size key="maxSize" width="1160" height="10000000"/>
|
||||||
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<size key="minSize" width="600" height="376"/>
|
<size key="minSize" width="600" height="376"/>
|
||||||
<size key="maxSize" width="600" height="10000000"/>
|
<size key="maxSize" width="1160" height="10000000"/>
|
||||||
<allowedInputSourceLocales>
|
<allowedInputSourceLocales>
|
||||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||||
</allowedInputSourceLocales>
|
</allowedInputSourceLocales>
|
||||||
@ -84,7 +86,7 @@
|
|||||||
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
|
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="cwi-6E-rbh">
|
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="cwi-6E-rbh">
|
||||||
<rect key="frame" x="584" y="0.0" width="16" height="376"/>
|
<rect key="frame" x="584" y="0.0" width="16" height="376"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
@ -125,7 +127,79 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="528" height="320"/>
|
<rect key="frame" x="0.0" y="0.0" width="528" height="320"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</view>
|
</view>
|
||||||
<point key="canvasLocation" x="-102" y="60"/>
|
<toolbar key="toolbar" implicitIdentifier="D857E961-E523-4295-83F8-0849316E827C" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="82v-uB-RPi">
|
||||||
|
<allowedToolbarItems>
|
||||||
|
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="WUk-8p-S6B"/>
|
||||||
|
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="E3z-um-6KG"/>
|
||||||
|
<toolbarItem implicitItemIdentifier="4F6AAE25-1E9D-4111-9E5B-91F0792E56CD" label="Address Space" paletteLabel="Address Space" id="VTy-lj-K0H">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<size key="minSize" width="100" height="25"/>
|
||||||
|
<size key="maxSize" width="100" height="25"/>
|
||||||
|
<popUpButton key="view" verticalHuggingPriority="750" id="vfJ-vu-gqJ">
|
||||||
|
<rect key="frame" x="0.0" y="14" width="100" height="25"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bpD-j9-omo">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" id="gTX-6Z-mOH">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Entire Space" id="Zp5-J9-dd3"/>
|
||||||
|
<menuItem title="ROM" tag="1" id="ANn-pq-5SA"/>
|
||||||
|
<menuItem title="Video RAM" tag="2" id="m35-GY-cKE"/>
|
||||||
|
<menuItem title="Cartridge RAM" tag="3" id="AOc-Up-PNm"/>
|
||||||
|
<menuItem title="RAM" tag="4" id="dg4-zf-bo4"/>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
<connections>
|
||||||
|
<action selector="hexUpdateSpace:" target="-2" id="1xc-Wa-RGp"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButtonCell>
|
||||||
|
</popUpButton>
|
||||||
|
</toolbarItem>
|
||||||
|
<toolbarItem implicitItemIdentifier="D16C64D2-2F0D-4033-A1EC-A1E699522ECE" label="Bank" paletteLabel="Bank" id="bWC-FW-IYP">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<size key="minSize" width="64" height="22"/>
|
||||||
|
<size key="maxSize" width="64" height="22"/>
|
||||||
|
<textField key="view" verticalHuggingPriority="750" id="rdV-q6-hc6">
|
||||||
|
<rect key="frame" x="0.0" y="14" width="64" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" id="JCn-Y1-eHS">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="hexUpdateBank:" target="-2" id="Mx9-WI-wgO"/>
|
||||||
|
</connections>
|
||||||
|
</textField>
|
||||||
|
</toolbarItem>
|
||||||
|
<toolbarItem implicitItemIdentifier="F9723DA8-D79F-43AB-876B-783DD0204AA6" label="Go to" paletteLabel="Go to" id="rLO-D7-zRG">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<size key="minSize" width="96" height="22"/>
|
||||||
|
<size key="maxSize" width="128" height="22"/>
|
||||||
|
<textField key="view" verticalHuggingPriority="750" id="EJd-jG-hmH">
|
||||||
|
<rect key="frame" x="0.0" y="14" width="96" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" bezelStyle="round" id="vg5-Nn-abb">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="hexGoTo:" target="-2" id="7WG-8C-SK8"/>
|
||||||
|
</connections>
|
||||||
|
</textField>
|
||||||
|
</toolbarItem>
|
||||||
|
</allowedToolbarItems>
|
||||||
|
<defaultToolbarItems>
|
||||||
|
<toolbarItem reference="VTy-lj-K0H"/>
|
||||||
|
<toolbarItem reference="bWC-FW-IYP"/>
|
||||||
|
<toolbarItem reference="E3z-um-6KG"/>
|
||||||
|
<toolbarItem reference="rLO-D7-zRG"/>
|
||||||
|
</defaultToolbarItems>
|
||||||
|
</toolbar>
|
||||||
|
<point key="canvasLocation" x="-185" y="61"/>
|
||||||
</window>
|
</window>
|
||||||
|
<menuItem title="Cartridge RAM" id="ylM-ah-PNQ"/>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
@ -2,6 +2,16 @@
|
|||||||
#import "HexFiend/HexFiend.h"
|
#import "HexFiend/HexFiend.h"
|
||||||
#import "HexFiend/HFByteArray.h"
|
#import "HexFiend/HFByteArray.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GBMemoryEntireSpace,
|
||||||
|
GBMemoryROM,
|
||||||
|
GBMemoryVRAM,
|
||||||
|
GBMemoryExternalRAM,
|
||||||
|
GBMemoryRAM
|
||||||
|
} GB_memory_mode_t;
|
||||||
|
|
||||||
@interface GBMemoryByteArray : HFByteArray
|
@interface GBMemoryByteArray : HFByteArray
|
||||||
- (instancetype) initWithDocument:(Document *)document;
|
- (instancetype) initWithDocument:(Document *)document;
|
||||||
|
@property uint16_t selectedBank;
|
||||||
|
@property GB_memory_mode_t mode;
|
||||||
@end
|
@end
|
||||||
|
@ -17,16 +17,83 @@
|
|||||||
|
|
||||||
- (unsigned long long)length
|
- (unsigned long long)length
|
||||||
{
|
{
|
||||||
return 0x10000;
|
switch (_mode) {
|
||||||
|
case GBMemoryEntireSpace:
|
||||||
|
return 0x10000;
|
||||||
|
case GBMemoryROM:
|
||||||
|
return 0x8000;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
return 0x2000;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
return 0x2000;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
return 0x2000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)copyBytes:(unsigned char *)dst range:(HFRange)range
|
- (void)copyBytes:(unsigned char *)dst range:(HFRange)range
|
||||||
{
|
{
|
||||||
uint16_t addr = (uint16_t) range.location;
|
__block uint16_t addr = (uint16_t) range.location;
|
||||||
unsigned long long length = range.length;
|
__block unsigned long long length = range.length;
|
||||||
while (length) {
|
if (_mode == GBMemoryEntireSpace) {
|
||||||
*(dst++) = [_document readMemory:addr++];
|
while (length) {
|
||||||
length--;
|
*(dst++) = [_document readMemory:addr++];
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[_document performAtomicBlock:^{
|
||||||
|
unsigned char *_dst = dst;
|
||||||
|
uint16_t bank_backup = 0;
|
||||||
|
GB_gameboy_t *gb = _document.gameboy;
|
||||||
|
switch (_mode) {
|
||||||
|
case GBMemoryROM:
|
||||||
|
bank_backup = gb->mbc_rom_bank;
|
||||||
|
gb->mbc_rom_bank = self.selectedBank;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
bank_backup = gb->cgb_vram_bank;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->cgb_vram_bank = self.selectedBank;
|
||||||
|
}
|
||||||
|
addr += 0x8000;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
bank_backup = gb->mbc_ram_bank;
|
||||||
|
gb->mbc_ram_bank = self.selectedBank;
|
||||||
|
addr += 0xA000;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
bank_backup = gb->cgb_ram_bank;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->cgb_ram_bank = self.selectedBank;
|
||||||
|
}
|
||||||
|
addr += 0xC000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
while (length) {
|
||||||
|
*(_dst++) = [_document readMemory:addr++];
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
switch (_mode) {
|
||||||
|
case GBMemoryROM:
|
||||||
|
gb->mbc_rom_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
gb->cgb_vram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
gb->mbc_ram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
gb->cgb_ram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,15 +116,60 @@
|
|||||||
{
|
{
|
||||||
if (slice.length != lrange.length) return; /* Insertion is not allowed, only overwriting. */
|
if (slice.length != lrange.length) return; /* Insertion is not allowed, only overwriting. */
|
||||||
[_document performAtomicBlock:^{
|
[_document performAtomicBlock:^{
|
||||||
|
uint16_t addr = (uint16_t) lrange.location;
|
||||||
|
uint16_t bank_backup = 0;
|
||||||
|
GB_gameboy_t *gb = _document.gameboy;
|
||||||
|
switch (_mode) {
|
||||||
|
case GBMemoryROM:
|
||||||
|
bank_backup = gb->mbc_rom_bank;
|
||||||
|
gb->mbc_rom_bank = self.selectedBank;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
bank_backup = gb->cgb_vram_bank;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->cgb_vram_bank = self.selectedBank;
|
||||||
|
}
|
||||||
|
addr += 0x8000;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
bank_backup = gb->mbc_ram_bank;
|
||||||
|
gb->mbc_ram_bank = self.selectedBank;
|
||||||
|
addr += 0xA000;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
bank_backup = gb->cgb_ram_bank;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->cgb_ram_bank = self.selectedBank;
|
||||||
|
}
|
||||||
|
addr += 0xC000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
uint8_t values[lrange.length];
|
uint8_t values[lrange.length];
|
||||||
[slice copyBytes:values range:HFRangeMake(0, lrange.length)];
|
[slice copyBytes:values range:HFRangeMake(0, lrange.length)];
|
||||||
uint16_t addr = (uint16_t) lrange.location;
|
|
||||||
uint8_t *src = values;
|
uint8_t *src = values;
|
||||||
unsigned long long length = lrange.length;
|
unsigned long long length = lrange.length;
|
||||||
while (length) {
|
while (length) {
|
||||||
[_document writeMemory:addr++ value:*(src++)];
|
[_document writeMemory:addr++ value:*(src++)];
|
||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
|
switch (_mode) {
|
||||||
|
case GBMemoryROM:
|
||||||
|
gb->mbc_rom_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryVRAM:
|
||||||
|
gb->cgb_vram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryExternalRAM:
|
||||||
|
gb->mbc_ram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
case GBMemoryRAM:
|
||||||
|
gb->cgb_ram_bank = bank_backup;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,11 +333,11 @@ static struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
||||||
unsigned int length, bool *error,
|
size_t length, bool *error,
|
||||||
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value);
|
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value);
|
||||||
|
|
||||||
static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string,
|
static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string,
|
||||||
unsigned int length, bool *error,
|
size_t length, bool *error,
|
||||||
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value)
|
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value)
|
||||||
{
|
{
|
||||||
*error = false;
|
*error = false;
|
||||||
@ -410,19 +410,19 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string,
|
|||||||
case 'p': if (string[1] == 'c') return (lvalue_t){LVALUE_REG16, .register_address = &gb->pc};
|
case 'p': if (string[1] == 'c') return (lvalue_t){LVALUE_REG16, .register_address = &gb->pc};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GB_log(gb, "Unknown register: %.*s\n", length, string);
|
GB_log(gb, "Unknown register: %.*s\n", (unsigned int) length, string);
|
||||||
*error = true;
|
*error = true;
|
||||||
return (lvalue_t){0,};
|
return (lvalue_t){0,};
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_log(gb, "Expression is not an lvalue: %.*s\n", length, string);
|
GB_log(gb, "Expression is not an lvalue: %.*s\n", (unsigned int) length, string);
|
||||||
*error = true;
|
*error = true;
|
||||||
return (lvalue_t){0,};
|
return (lvalue_t){0,};
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ERROR ((value_t){0,})
|
#define ERROR ((value_t){0,})
|
||||||
value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
||||||
unsigned int length, bool *error,
|
size_t length, bool *error,
|
||||||
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value)
|
uint16_t *watchpoint_address, uint8_t *watchpoint_new_value)
|
||||||
{
|
{
|
||||||
*error = false;
|
*error = false;
|
||||||
@ -567,7 +567,7 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
|||||||
return (value_t){true, symbol->bank, symbol->addr};
|
return (value_t){true, symbol->bank, symbol->addr};
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_log(gb, "Unknown register or symbol: %.*s\n", length, string);
|
GB_log(gb, "Unknown register or symbol: %.*s\n", (unsigned int) length, string);
|
||||||
*error = true;
|
*error = true;
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
@ -581,7 +581,7 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string,
|
|||||||
}
|
}
|
||||||
uint16_t literal = (uint16_t) (strtol(string, &end, base));
|
uint16_t literal = (uint16_t) (strtol(string, &end, base));
|
||||||
if (end != string + length) {
|
if (end != string + length) {
|
||||||
GB_log(gb, "Failed to parse: %.*s\n", length, string);
|
GB_log(gb, "Failed to parse: %.*s\n", (unsigned int) length, string);
|
||||||
*error = true;
|
*error = true;
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
@ -1558,4 +1558,18 @@ const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, addr);
|
const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, addr);
|
||||||
if (symbol && symbol->addr == addr) return symbol->name;
|
if (symbol && symbol->addr == addr) return symbol->name;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The public version of debugger_evaluate */
|
||||||
|
bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank)
|
||||||
|
{
|
||||||
|
bool error = false;
|
||||||
|
value_t value = debugger_evaluate(gb, string, strlen(string), &error, NULL, NULL);
|
||||||
|
if (result) {
|
||||||
|
*result = value.value;
|
||||||
|
}
|
||||||
|
if (result_bank) {
|
||||||
|
*result_bank = value.has_bank? value.value : -1;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
@ -11,4 +11,5 @@ void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr);
|
|||||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
||||||
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
||||||
const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr);
|
const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr);
|
||||||
|
bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank); /* result_bank is -1 if unused. */
|
||||||
#endif /* debugger_h */
|
#endif /* debugger_h */
|
||||||
|
@ -367,7 +367,7 @@ You create an HFController via <tt>[[HFController alloc] init]</tt>. After that
|
|||||||
- (unsigned long long)contentsLength;
|
- (unsigned long long)contentsLength;
|
||||||
|
|
||||||
- (void) reloadData;
|
- (void) reloadData;
|
||||||
|
- (void)_ensureVisibilityOfLocation:(unsigned long long)location;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*! A notification posted whenever any of the HFController's properties change. The object is the HFController. The userInfo contains one key, HFControllerChangedPropertiesKey, which contains an NSNumber with the changed properties as a HFControllerPropertyBits bitmask. This is useful for external objects to be notified of changes. HFRepresenters added to the HFController are notified via the controllerDidChange: message.
|
/*! A notification posted whenever any of the HFController's properties change. The object is the HFController. The userInfo contains one key, HFControllerChangedPropertiesKey, which contains an NSNumber with the changed properties as a HFControllerPropertyBits bitmask. This is useful for external objects to be notified of changes. HFRepresenters added to the HFController are notified via the controllerDidChange: message.
|
||||||
|
@ -1796,7 +1796,7 @@ static BOOL rangesAreInAscendingOrder(NSEnumerator *rangeEnumerator) {
|
|||||||
[cachedData release];
|
[cachedData release];
|
||||||
cachedData = nil;
|
cachedData = nil;
|
||||||
[self _updateDisplayedRange];
|
[self _updateDisplayedRange];
|
||||||
[self _addPropertyChangeBits: HFControllerContentValue];
|
[self _addPropertyChangeBits: HFControllerContentValue | HFControllerContentLength];
|
||||||
END_TRANSACTION();
|
END_TRANSACTION();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ static inline int common_prefix_length(const char *a, const char *b) {
|
|||||||
[self getLineNumberFormatString:formatString length:sizeof formatString];
|
[self getLineNumberFormatString:formatString length:sizeof formatString];
|
||||||
|
|
||||||
while (lineCount--) {
|
while (lineCount--) {
|
||||||
int charCount = sprintf(buffer + bufferIndex, formatString, lineValue);
|
int charCount = sprintf(buffer + bufferIndex, formatString, lineValue + self.representer.valueOffset);
|
||||||
HFASSERT(charCount > 0);
|
HFASSERT(charCount > 0);
|
||||||
bufferIndex += charCount;
|
bufferIndex += charCount;
|
||||||
buffer[bufferIndex++] = '\n';
|
buffer[bufferIndex++] = '\n';
|
||||||
|
Loading…
Reference in New Issue
Block a user