Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/cartridge/markup.cpp
2 views
1
#ifdef CARTRIDGE_CPP
2
3
void Cartridge::parse_markup(const char *markup) {
4
mapping.reset();
5
information.nss.setting.reset();
6
7
XML::Document document(markup);
8
auto &cartridge = document["cartridge"];
9
region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;
10
11
parse_markup_rom(cartridge["rom"]);
12
parse_markup_ram(cartridge["ram"]);
13
parse_markup_nss(cartridge["nss"]);
14
parse_markup_icd2(cartridge["icd2"]);
15
parse_markup_sa1(cartridge["sa1"]);
16
parse_markup_superfx(cartridge["superfx"]);
17
parse_markup_necdsp(cartridge["necdsp"]);
18
parse_markup_hitachidsp(cartridge["hitachidsp"]);
19
parse_markup_armdsp(cartridge["armdsp"]);
20
parse_markup_bsx(cartridge["bsx"]);
21
parse_markup_sufamiturbo(cartridge["sufamiturbo"]);
22
parse_markup_srtc(cartridge["srtc"]);
23
parse_markup_sdd1(cartridge["sdd1"]);
24
parse_markup_spc7110(cartridge["spc7110"]);
25
parse_markup_obc1(cartridge["obc1"]);
26
parse_markup_msu1(cartridge["msu1"]);
27
parse_markup_link(cartridge["link"]);
28
}
29
30
//
31
32
void Cartridge::parse_markup_map(Mapping &m, XML::Node &map) {
33
m.offset = numeral(map["offset"].data);
34
m.size = numeral(map["size"].data);
35
36
string data = map["mode"].data;
37
if(data == "direct") m.mode = Bus::MapMode::Direct;
38
if(data == "linear") m.mode = Bus::MapMode::Linear;
39
if(data == "shadow") m.mode = Bus::MapMode::Shadow;
40
41
lstring part;
42
part.split(":", map["address"].data);
43
if(part.size() != 2) return;
44
45
lstring subpart;
46
subpart.split("-", part[0]);
47
if(subpart.size() == 1) {
48
m.banklo = hex(subpart[0]);
49
m.bankhi = m.banklo;
50
} else if(subpart.size() == 2) {
51
m.banklo = hex(subpart[0]);
52
m.bankhi = hex(subpart[1]);
53
}
54
55
subpart.split("-", part[1]);
56
if(subpart.size() == 1) {
57
m.addrlo = hex(subpart[0]);
58
m.addrhi = m.addrlo;
59
} else if(subpart.size() == 2) {
60
m.addrlo = hex(subpart[0]);
61
m.addrhi = hex(subpart[1]);
62
}
63
}
64
65
uint8 Cartridge::rom_read(unsigned addr)
66
{
67
cdlInfo.set(eCDLog_AddrType_CARTROM, addr);
68
return rom.read(addr);
69
}
70
void Cartridge::rom_write(unsigned addr, uint8 n)
71
{
72
rom.write(addr,n);
73
}
74
75
uint8 Cartridge::ram_read(unsigned addr)
76
{
77
cdlInfo.set(eCDLog_AddrType_CARTRAM, addr);
78
return ram.read(addr);
79
}
80
void Cartridge::ram_write(unsigned addr, uint8 n)
81
{
82
ram.write(addr, n);
83
}
84
85
void Cartridge::parse_markup_rom(XML::Node &root) {
86
if(root.exists() == false) return;
87
for(auto &node : root) {
88
if(node.name != "map") continue;
89
Mapping m({&Cartridge::rom_read, this}, {&Cartridge::rom_write, this});
90
parse_markup_map(m, node);
91
if(m.size == 0) m.size = rom.size();
92
mapping.append(m);
93
}
94
}
95
96
void Cartridge::parse_markup_ram(XML::Node &root) {
97
if(root.exists() == false) return;
98
ram_size = numeral(root["size"].data);
99
for(auto &node : root) {
100
Mapping m({ &Cartridge::ram_read, this }, { &Cartridge::ram_write, this });
101
parse_markup_map(m, node);
102
if(m.size == 0) m.size = ram_size;
103
mapping.append(m);
104
}
105
}
106
107
void Cartridge::parse_markup_nss(XML::Node &root) {
108
if(root.exists() == false) return;
109
has_nss_dip = true;
110
for(auto &node : root) {
111
if(node.name != "setting") continue;
112
unsigned number = information.nss.setting.size();
113
if(number >= 16) break; //more than 16 DIP switches is not physically possible
114
115
information.nss.option[number].reset();
116
information.nss.setting.append(node["name"].data);
117
for(auto &leaf : node) {
118
if(leaf.name != "option") continue;
119
string name = leaf["name"].data;
120
unsigned value = numeral(leaf["value"].data);
121
information.nss.option[number].append({ hex<4>(value), ":", name });
122
}
123
}
124
}
125
126
void Cartridge::parse_markup_icd2(XML::Node &root) {
127
#if defined(GAMEBOY)
128
if(root.exists() == false) return;
129
if(mode.value != Mode::SuperGameBoy) return;
130
131
icd2.revision = max(1, numeral(root["revision"].data));
132
133
for(auto &node : root) {
134
if(node.name != "map") continue;
135
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
136
parse_markup_map(m, node);
137
mapping.append(m);
138
}
139
#endif
140
}
141
142
void Cartridge::parse_markup_superfx(XML::Node &root) {
143
if(root.exists() == false) return;
144
has_superfx = true;
145
146
for(auto &node : root) {
147
if(node.name == "rom") {
148
for(auto &leaf : node) {
149
if(leaf.name != "map") continue;
150
Mapping m(superfx.rom);
151
parse_markup_map(m, leaf);
152
mapping.append(m);
153
}
154
}
155
if(node.name == "ram") {
156
for(auto &leaf : node) {
157
if(leaf.name == "size") {
158
ram_size = numeral(leaf.data);
159
continue;
160
}
161
if(leaf.name != "map") continue;
162
Mapping m(superfx.ram);
163
parse_markup_map(m, leaf);
164
if(m.size == 0) m.size = ram_size;
165
mapping.append(m);
166
}
167
}
168
if(node.name == "mmio") {
169
for(auto &leaf : node) {
170
if(leaf.name != "map") continue;
171
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
172
parse_markup_map(m, leaf);
173
mapping.append(m);
174
}
175
}
176
}
177
}
178
179
void Cartridge::parse_markup_sa1(XML::Node &root) {
180
if(root.exists() == false) return;
181
has_sa1 = true;
182
183
auto &mcurom = root["mcu"]["rom"];
184
auto &mcuram = root["mcu"]["ram"];
185
auto &iram = root["iram"];
186
auto &bwram = root["bwram"];
187
auto &mmio = root["mmio"];
188
189
for(auto &node : mcurom) {
190
if(node.name != "map") continue;
191
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
192
parse_markup_map(m, node);
193
mapping.append(m);
194
}
195
196
for(auto &node : mcuram) {
197
if(node.name != "map") continue;
198
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
199
parse_markup_map(m, node);
200
mapping.append(m);
201
}
202
203
for(auto &node : iram) {
204
if(node.name != "map") continue;
205
Mapping m(sa1.cpuiram);
206
parse_markup_map(m, node);
207
if(m.size == 0) m.size = 2048;
208
mapping.append(m);
209
}
210
211
ram_size = numeral(bwram["size"].data);
212
for(auto &node : bwram) {
213
if(node.name != "map") continue;
214
Mapping m(sa1.cpubwram);
215
parse_markup_map(m, node);
216
if(m.size == 0) m.size = ram_size;
217
mapping.append(m);
218
}
219
220
for(auto &node : mmio) {
221
if(node.name != "map") continue;
222
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
223
parse_markup_map(m, node);
224
mapping.append(m);
225
}
226
}
227
228
void Cartridge::parse_markup_necdsp(XML::Node &root) {
229
if(root.exists() == false) return;
230
has_necdsp = true;
231
232
for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
233
for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
234
235
necdsp.frequency = numeral(root["frequency"].data);
236
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
237
necdsp.revision
238
= root["model"].data == "uPD7725" ? NECDSP::Revision::uPD7725
239
: root["model"].data == "uPD96050" ? NECDSP::Revision::uPD96050
240
: NECDSP::Revision::uPD7725;
241
string firmware = root["firmware"].data;
242
string sha256 = root["sha256"].data;
243
244
string path = interface()->path(Slot::Base, firmware);
245
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
246
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
247
unsigned filesize = promsize * 3 + dromsize * 2;
248
249
file fp;
250
if(fp.open(path, file::mode::read) == false) {
251
interface()->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
252
} else if(fp.size() != filesize) {
253
interface()->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
254
fp.close();
255
} else {
256
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readl(3);
257
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readl(2);
258
259
if(!sha256.empty()) {
260
//XML file specified SHA256 sum for program. Verify file matches the hash.
261
fp.seek(0);
262
//uint8_t data[filesize]; //test
263
uint8_t *data = (uint8_t*)alloca(filesize);
264
fp.read(data, filesize);
265
266
if(sha256 != nall::sha256(data, filesize)) {
267
interface()->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });
268
}
269
}
270
271
fp.close();
272
}
273
274
for(auto &node : root) {
275
if(node.name == "dr") {
276
for(auto &leaf : node) {
277
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
278
parse_markup_map(m, leaf);
279
mapping.append(m);
280
}
281
}
282
if(node.name == "sr") {
283
for(auto &leaf : node) {
284
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
285
parse_markup_map(m, leaf);
286
mapping.append(m);
287
}
288
}
289
if(node.name == "dp") {
290
for(auto &leaf : node) {
291
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
292
parse_markup_map(m, leaf);
293
mapping.append(m);
294
}
295
}
296
}
297
}
298
299
void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
300
if(root.exists() == false) return;
301
has_hitachidsp = true;
302
303
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
304
305
hitachidsp.frequency = numeral(root["frequency"].data);
306
if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000;
307
string firmware = root["firmware"].data;
308
string sha256 = root["sha256"].data;
309
310
string path = interface()->path(Slot::Base, firmware);
311
file fp;
312
if(fp.open(path, file::mode::read) == false) {
313
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
314
} else if(fp.size() != 1024 * 3) {
315
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
316
fp.close();
317
} else {
318
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
319
320
if(!sha256.empty()) {
321
//XML file specified SHA256 sum for program. Verify file matches the hash.
322
fp.seek(0);
323
uint8 data[3072];
324
fp.read(data, 3072);
325
326
if(sha256 != nall::sha256(data, 3072)) {
327
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
328
}
329
}
330
331
fp.close();
332
}
333
334
for(auto &node : root) {
335
if(node.name == "rom") {
336
for(auto &leaf : node) {
337
if(leaf.name != "map") continue;
338
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
339
parse_markup_map(m, leaf);
340
mapping.append(m);
341
}
342
}
343
if(node.name == "mmio") {
344
for(auto &leaf : node) {
345
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
346
parse_markup_map(m, leaf);
347
mapping.append(m);
348
}
349
}
350
}
351
}
352
353
void Cartridge::parse_markup_armdsp(XML::Node &root) {
354
if(root.exists() == false) return;
355
has_armdsp = true;
356
357
string firmware = root["firmware"].data;
358
string sha256 = root["sha256"].data;
359
360
string path = interface()->path(Slot::Base, firmware);
361
file fp;
362
if(fp.open(path, file::mode::read) == false) {
363
interface()->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });
364
} else if(fp.size() != 160 * 1024) {
365
interface()->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });
366
fp.close();
367
} else {
368
fp.read(armdsp.firmware, fp.size());
369
370
if(!sha256.empty()) {
371
if(sha256 != nall::sha256(armdsp.firmware, fp.size())) {
372
interface()->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });
373
}
374
}
375
376
fp.close();
377
}
378
379
for(auto &node : root) {
380
if(node.name != "map") continue;
381
Mapping m({ &ArmDSP::mmio_read, &armdsp }, { &ArmDSP::mmio_write, &armdsp });
382
parse_markup_map(m, node);
383
mapping.append(m);
384
}
385
}
386
387
void Cartridge::parse_markup_bsx(XML::Node &root) {
388
if(root.exists() == false) return;
389
if(mode.value != Mode::BsxSlotted && mode.value != Mode::Bsx) return;
390
has_bsx_slot = true;
391
392
for(auto &node : root["slot"]) {
393
if(node.name != "map") continue;
394
Mapping m(bsxflash.memory);
395
parse_markup_map(m, node);
396
mapping.append(m);
397
}
398
399
for(auto &node : root["mmio"]) {
400
if(node.name != "map") continue;
401
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
402
parse_markup_map(m, node);
403
mapping.append(m);
404
}
405
406
for(auto &node : root["mcu"]) {
407
if(node.name != "map") continue;
408
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
409
parse_markup_map(m, node);
410
mapping.append(m);
411
}
412
}
413
414
void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
415
if(root.exists() == false) return;
416
if(mode.value != Mode::SufamiTurbo) return;
417
418
for(auto &slot : root) {
419
if(slot.name != "slot") continue;
420
bool slotid = slot["id"].data == "A" ? 0 : slot["id"].data == "B" ? 1 : 0;
421
for(auto &node : slot) {
422
if(node.name == "rom") {
423
for(auto &leaf : node) {
424
if(leaf.name != "map") continue;
425
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
426
Mapping m(memory);
427
parse_markup_map(m, leaf);
428
if(m.size == 0) m.size = memory.size();
429
if(m.size) mapping.append(m);
430
}
431
}
432
if(node.name == "ram") {
433
unsigned ram_size = numeral(node["size"].data);
434
for(auto &leaf : node) {
435
if(leaf.name != "map") continue;
436
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
437
Mapping m(memory);
438
parse_markup_map(m, leaf);
439
if(m.size == 0) m.size = ram_size;
440
if(m.size) mapping.append(m);
441
}
442
}
443
}
444
}
445
}
446
447
void Cartridge::parse_markup_srtc(XML::Node &root) {
448
if(root.exists() == false) return;
449
has_srtc = true;
450
451
for(auto &node : root) {
452
if(node.name != "map") continue;
453
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
454
parse_markup_map(m, node);
455
mapping.append(m);
456
}
457
}
458
459
void Cartridge::parse_markup_sdd1(XML::Node &root) {
460
if(root.exists() == false) return;
461
has_sdd1 = true;
462
463
for(auto &node : root["mmio"]) {
464
if(node.name != "map") continue;
465
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
466
parse_markup_map(m, node);
467
mapping.append(m);
468
}
469
470
for(auto &node : root["mcu"]) {
471
if(node.name != "map") continue;
472
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
473
parse_markup_map(m, node);
474
mapping.append(m);
475
}
476
}
477
478
void Cartridge::parse_markup_spc7110(XML::Node &root) {
479
if(root.exists() == false) return;
480
has_spc7110 = true;
481
has_spc7110rtc = root["rtc"].exists();
482
483
auto &ram = root["ram"];
484
auto &mmio = root["mmio"];
485
auto &mcu = root["mcu"];
486
auto &dcu = root["dcu"];
487
auto &rtc = root["rtc"];
488
489
ram_size = numeral(ram["size"].data);
490
for(auto &node : ram) {
491
if(node.name != "map") continue;
492
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
493
parse_markup_map(m, node);
494
mapping.append(m);
495
}
496
497
for(auto &node : mmio) {
498
if(node.name != "map") continue;
499
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
500
parse_markup_map(m, node);
501
mapping.append(m);
502
}
503
504
spc7110.data_rom_offset = numeral(mcu["offset"].data);
505
if(spc7110.data_rom_offset == 0) spc7110.data_rom_offset = 0x100000;
506
for(auto &node : mcu) {
507
if(node.name != "map") continue;
508
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
509
parse_markup_map(m, node);
510
mapping.append(m);
511
}
512
513
for(auto &node : dcu) {
514
if(node.name != "map") continue;
515
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
516
parse_markup_map(m, node);
517
mapping.append(m);
518
}
519
520
for(auto &node : rtc) {
521
if(node.name != "map") continue;
522
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
523
parse_markup_map(m, node);
524
mapping.append(m);
525
}
526
}
527
528
void Cartridge::parse_markup_obc1(XML::Node &root) {
529
if(root.exists() == false) return;
530
has_obc1 = true;
531
532
for(auto &node : root) {
533
if(node.name != "map") continue;
534
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
535
parse_markup_map(m, node);
536
mapping.append(m);
537
}
538
}
539
540
void Cartridge::parse_markup_msu1(XML::Node &root) {
541
if(root.exists() == false) {
542
has_msu1 = file::exists(interface()->path(Cartridge::Slot::Base, "msu1.rom"));
543
if(has_msu1) {
544
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
545
m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007;
546
mapping.append(m);
547
m.banklo = 0x80, m.bankhi = 0xbf, m.addrlo = 0x2000, m.addrhi = 0x2007;
548
mapping.append(m);
549
}
550
return;
551
}
552
553
has_msu1 = true;
554
555
for(auto &node : root) {
556
if(node.name != "map") continue;
557
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
558
parse_markup_map(m, node);
559
mapping.append(m);
560
}
561
}
562
563
void Cartridge::parse_markup_link(XML::Node &root) {
564
if(root.exists() == false) return;
565
has_link = true;
566
567
link.frequency = max(1, numeral(root["frequency"].data));
568
link.program = root["program"].data;
569
570
for(auto &node : root) {
571
if(node.name != "map") continue;
572
Mapping m({ &Link::read, &link }, { &Link::write, &link });
573
parse_markup_map(m, node);
574
mapping.append(m);
575
}
576
}
577
578
Cartridge::Mapping::Mapping() {
579
mode = Bus::MapMode::Direct;
580
banklo = bankhi = addrlo = addrhi = offset = size = 0;
581
}
582
583
Cartridge::Mapping::Mapping(Memory &memory) {
584
read = { &Memory::read, &memory };
585
write = { &Memory::write, &memory };
586
mode = Bus::MapMode::Direct;
587
banklo = bankhi = addrlo = addrhi = offset = size = 0;
588
}
589
590
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
591
read = read_;
592
write = write_;
593
mode = Bus::MapMode::Direct;
594
banklo = bankhi = addrlo = addrhi = offset = size = 0;
595
}
596
597
#endif
598
599