sameduck/Cocoa/GBMemoryByteArray.m
2020-11-15 17:49:44 +02:00

172 lines
5.1 KiB
Objective-C

#define GB_INTERNAL // Todo: Some memory accesses are being done using the struct directly
#import "GBMemoryByteArray.h"
#import "GBCompleteByteSlice.h"
@implementation GBMemoryByteArray
{
Document *_document;
}
- (instancetype) initWithDocument:(Document *)document
{
if ((self = [super init])) {
_document = document;
}
return self;
}
- (unsigned long long)length
{
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
{
__block uint16_t addr = (uint16_t) range.location;
__block unsigned long long length = range.length;
if (_mode == GBMemoryEntireSpace) {
while (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)) {
gb->cgb_vram_bank = self.selectedBank;
}
addr += 0x8000;
break;
case GBMemoryExternalRAM:
addr += 0xA000;
break;
case GBMemoryRAM:
bank_backup = gb->cgb_ram_bank;
if (GB_is_cgb(gb)) {
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:
break;
case GBMemoryRAM:
gb->cgb_ram_bank = bank_backup;
break;
default:
assert(false);
}
}];
}
}
- (NSArray *)byteSlices
{
return @[[[GBCompleteByteSlice alloc] initWithByteArray:self]];
}
- (HFByteArray *)subarrayWithRange:(HFRange)range
{
unsigned char arr[range.length];
[self copyBytes:arr range:range];
HFByteArray *ret = [[HFBTreeByteArray alloc] init];
HFFullMemoryByteSlice *slice = [[HFFullMemoryByteSlice alloc] initWithData:[NSData dataWithBytes:arr length:range.length]];
[ret insertByteSlice:slice inRange:HFRangeMake(0, 0)];
return ret;
}
- (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)lrange
{
if (slice.length != lrange.length) return; /* Insertion is not allowed, only overwriting. */
[_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)) {
gb->cgb_vram_bank = self.selectedBank;
}
addr += 0x8000;
break;
case GBMemoryExternalRAM:
addr += 0xA000;
break;
case GBMemoryRAM:
bank_backup = gb->cgb_ram_bank;
if (GB_is_cgb(gb)) {
gb->cgb_ram_bank = self.selectedBank;
}
addr += 0xC000;
break;
default:
break;
}
uint8_t values[lrange.length];
[slice copyBytes:values range:HFRangeMake(0, lrange.length)];
uint8_t *src = values;
unsigned long long length = lrange.length;
while (length) {
[_document writeMemory:addr++ value:*(src++)];
length--;
}
switch (_mode) {
case GBMemoryROM:
gb->mbc_rom_bank = bank_backup;
break;
case GBMemoryVRAM:
gb->cgb_vram_bank = bank_backup;
break;
case GBMemoryExternalRAM:
break;
case GBMemoryRAM:
gb->cgb_ram_bank = bank_backup;
break;
default:
break;
}
}];
}
@end