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.