git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

Cocoa/GBMemoryByteArray.m

      1 #import "GBMemoryByteArray.h"
      2 #import "GBCompleteByteSlice.h"
      3 
      4 
      5 @implementation GBMemoryByteArray
      6 {
      7     Document *_document;
      8 }
      9 
     10 - (instancetype) initWithDocument:(Document *)document
     11 {
     12     if ((self = [super init])) {
     13         _document = document;
     14     }
     15     return self;
     16 }
     17 
     18 - (unsigned long long)length
     19 {
     20     switch (_mode) {
     21         case GBMemoryEntireSpace:
     22             return 0x10000;
     23         case GBMemoryROM:
     24             return 0x8000;
     25         case GBMemoryVRAM:
     26             return 0x2000;
     27         case GBMemoryExternalRAM:
     28             return 0x2000;
     29         case GBMemoryRAM:
     30             return 0x2000;
     31     }
     32 }
     33 
     34 - (uint16_t)base
     35 {
     36     switch (_mode) {
     37         case GBMemoryEntireSpace: return 0;
     38         case GBMemoryROM: return 0;
     39         case GBMemoryVRAM: return 0x8000;
     40         case GBMemoryExternalRAM: return 0xA000;
     41         case GBMemoryRAM: return 0xC000;
     42     }
     43 }
     44 
     45 - (void)copyBytes:(unsigned char *)dst range:(HFRange)range
     46 {
     47     // Do everything in 0x1000 chunks, never cross a 0x1000 boundary
     48     if ((range.location & 0xF000) != ((range.location + range.length) & 0xF000)) {
     49         size_t partial = 0x1000 - (range.location & 0xFFF);
     50         [self copyBytes:dst + partial range:HFRangeMake(range.location + partial, range.length - partial)];
     51         range.length = partial;
     52     }
     53     range.location += self.base;
     54     
     55     GB_gameboy_t *gb = _document.gameboy;
     56 
     57     switch (range.location >> 12) {
     58         case 0x0:
     59         case 0x1:
     60         case 0x2:
     61         case 0x3: {
     62             uint16_t bank;
     63             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_ROM0, NULL, &bank);
     64             memcpy(dst, data + bank * 0x4000 + range.location, range.length);
     65             break;
     66         }
     67         case 0x4:
     68         case 0x5:
     69         case 0x6:
     70         case 0x7: {
     71             uint16_t bank;
     72             size_t size;
     73             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_ROM, &size, &bank);
     74             if (_mode != GBMemoryEntireSpace) {
     75                 bank = self.selectedBank & (size / 0x4000 - 1);
     76             }
     77             memcpy(dst, data + bank * 0x4000 + range.location - 0x4000, range.length);
     78             break;
     79         }
     80         case 0x8:
     81         case 0x9: {
     82             uint16_t bank;
     83             size_t size;
     84             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_VRAM, &size, &bank);
     85             if (_mode != GBMemoryEntireSpace) {
     86                 bank = self.selectedBank & (size / 0x2000 - 1);
     87             }
     88             memcpy(dst, data + bank * 0x2000 + range.location - 0x8000, range.length);
     89             break;
     90         }
     91         case 0xA:
     92         case 0xB: {
     93             // Some carts are special, use memory read directly in full mem mode
     94             if (_mode == GBMemoryEntireSpace) {
     95         case 0xF:
     96         slow_path:
     97                 [_document performAtomicBlock:^{
     98                     for (unsigned i = 0; i < range.length; i++) {
     99                         dst[i] = GB_safe_read_memory(gb, range.location + i);
    100                     }
    101                 }];
    102                 break;
    103             }
    104             else {
    105                 uint16_t bank;
    106                 size_t size;
    107                 uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_CART_RAM, &size, &bank);
    108                 bank = self.selectedBank & (size / 0x2000 - 1);
    109                 if (size == 0) {
    110                     memset(dst, 0xFF, range.length);
    111                 }
    112                 else if (range.location + range.length - 0xA000 > size)  {
    113                     goto slow_path;
    114                 }
    115                 else {
    116                     memcpy(dst, data + bank * 0x2000 + range.location - 0xA000, range.length);
    117                 }
    118                 break;
    119             }
    120         }
    121         case 0xC:
    122         case 0xE: {
    123             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
    124             memcpy(dst, data + (range.location & 0xFFF), range.length);
    125             break;
    126         }
    127             
    128         case 0xD: {
    129             uint16_t bank;
    130             size_t size;
    131             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, &size, &bank);
    132             if (_mode != GBMemoryEntireSpace) {
    133                 bank = self.selectedBank & (size / 0x1000 - 1);
    134             }
    135             memcpy(dst, data + bank * 0x1000 + range.location - 0xD000, range.length);
    136             break;
    137         }
    138     }
    139 }
    140 
    141 - (NSArray *)byteSlices
    142 {
    143     return @[[[GBCompleteByteSlice alloc] initWithByteArray:self]];
    144 }
    145 
    146 - (HFByteArray *)subarrayWithRange:(HFRange)range
    147 {
    148     unsigned char arr[range.length];
    149     [self copyBytes:arr range:range];
    150     HFByteArray *ret = [[HFBTreeByteArray alloc] init];
    151     HFFullMemoryByteSlice *slice = [[HFFullMemoryByteSlice alloc] initWithData:[NSData dataWithBytes:arr length:range.length]];
    152     [ret insertByteSlice:slice inRange:HFRangeMake(0, 0)];
    153     return ret;
    154 }
    155 
    156 - (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)range
    157 {
    158     if (slice.length != range.length) return; /* Insertion is not allowed, only overwriting. */
    159     // Do everything in 0x1000 chunks, never cross a 0x1000 boundary
    160     if ((range.location & 0xF000) != ((range.location + range.length) & 0xF000)) {
    161         size_t partial = 0x1000 - (range.location & 0xFFF);
    162         if (slice.length - partial) {
    163             [self insertByteSlice:[slice subsliceWithRange:HFRangeMake(partial, slice.length - partial)]
    164                             inRange:HFRangeMake(range.location + partial, range.length - partial)];
    165         }
    166         range.length = partial;
    167     }
    168     range.location += self.base;
    169     
    170     GB_gameboy_t *gb = _document.gameboy;
    171     
    172     
    173     switch (range.location >> 12) {
    174         case 0x0:
    175         case 0x1:
    176         case 0x2:
    177         case 0x3:
    178         case 0x4:
    179         case 0x5:
    180         case 0x6:
    181         case 0x7: {
    182             uint16_t bank;
    183             size_t size;
    184             uint8_t *data = GB_get_direct_access(gb, range.location < 0x4000? GB_DIRECT_ACCESS_ROM0 : GB_DIRECT_ACCESS_ROM, &size, &bank);
    185             if (_mode != GBMemoryEntireSpace && range.location >= 0x4000) {
    186                 bank = self.selectedBank & (size / 0x4000 - 1);
    187             }
    188             uint8_t sliceData[range.length];
    189             [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    190             memcpy(data + bank * 0x4000 + (range.location & 0x3FFF), sliceData, range.length);
    191             [_document setROMModified];
    192             break;
    193         }
    194         case 0x8:
    195         case 0x9: {
    196             uint16_t bank;
    197             size_t size;
    198             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_VRAM, &size, &bank);
    199             if (_mode != GBMemoryEntireSpace) {
    200                 bank = self.selectedBank & (size / 0x2000 - 1);
    201             }
    202             uint8_t sliceData[range.length];
    203             [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    204             memcpy(data + bank * 0x2000 + range.location - 0x8000, sliceData, range.length);
    205             break;
    206         }
    207         case 0xA:
    208         case 0xB: {
    209             // Some carts are special, use memory write directly in full mem mode
    210             if (_mode == GBMemoryEntireSpace) {
    211         case 0xF:
    212         slow_path:
    213                 [_document performAtomicBlock:^{
    214                     uint8_t sliceData[range.length];
    215                     [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    216                     for (unsigned i = 0; i < range.length; i++) {
    217                         GB_write_memory(gb, range.location + i, sliceData[i]);
    218                     }
    219                 }];
    220                 break;
    221             }
    222             else {
    223                 uint16_t bank;
    224                 size_t size;
    225                 uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_CART_RAM, &size, &bank);
    226                 bank = self.selectedBank & (size / 0x2000 - 1);
    227                 if (size == 0) {
    228                     // Nothing to write to
    229                 }
    230                 else if (range.location + range.length - 0xA000 > size)  {
    231                     goto slow_path;
    232                 }
    233                 else {
    234                     uint8_t sliceData[range.length];
    235                     [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    236                     memcpy(data + bank * 0x2000 + range.location - 0xA000, sliceData, range.length);
    237                 }
    238                 break;
    239             }
    240         }
    241         case 0xC:
    242         case 0xE: {
    243             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
    244             uint8_t sliceData[range.length];
    245             [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    246             memcpy(data + (range.location & 0xFFF), sliceData, range.length);
    247             break;
    248         }
    249             
    250         case 0xD: {
    251             uint16_t bank;
    252             size_t size;
    253             uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, &size, &bank);
    254             if (_mode != GBMemoryEntireSpace) {
    255                 bank = self.selectedBank & (size / 0x1000 - 1);
    256             }
    257             uint8_t sliceData[range.length];
    258             [slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
    259 
    260             memcpy(data + bank * 0x1000 + range.location - 0xD000, sliceData, range.length);
    261             break;
    262         }
    263     }
    264 }
    265 
    266 @end

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.