2017-04-17 17:16:17 +00:00
|
|
|
#define GB_INTERNAL // Todo: Some memory accesses are being done using the struct directly
|
2016-08-12 19:49:17 +00:00
|
|
|
#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
|
|
|
|
{
|
2016-08-19 11:54:54 +00:00
|
|
|
switch (_mode) {
|
|
|
|
case GBMemoryEntireSpace:
|
|
|
|
return 0x10000;
|
|
|
|
case GBMemoryROM:
|
|
|
|
return 0x8000;
|
|
|
|
case GBMemoryVRAM:
|
|
|
|
return 0x2000;
|
|
|
|
case GBMemoryExternalRAM:
|
|
|
|
return 0x2000;
|
|
|
|
case GBMemoryRAM:
|
|
|
|
return 0x2000;
|
|
|
|
}
|
2016-08-12 19:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)copyBytes:(unsigned char *)dst range:(HFRange)range
|
|
|
|
{
|
2016-08-19 11:54:54 +00:00
|
|
|
__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->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);
|
|
|
|
}
|
|
|
|
}];
|
2016-08-12 19:49:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (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:^{
|
2016-08-19 11:54:54 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-08-12 19:49:17 +00:00
|
|
|
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--;
|
|
|
|
}
|
2016-08-19 11:54:54 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-08-12 19:49:17 +00:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|