cart_header.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #ifdef CART_CPP
  2. void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const {
  3. info.reset();
  4. unsigned index = find_header(data, size);
  5. //=======================
  6. //detect BS-X flash carts
  7. //=======================
  8. if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
  9. if(data[index + 0x14] == 0x00) {
  10. const uint8_t n15 = data[index + 0x15];
  11. if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
  12. if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
  13. info.type = TypeBsx;
  14. info.mapper = BSXROM;
  15. info.region = NTSC; //BS-X only released in Japan
  16. return;
  17. }
  18. }
  19. }
  20. }
  21. //=========================
  22. //detect Sufami Turbo carts
  23. //=========================
  24. if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
  25. if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
  26. info.type = TypeSufamiTurboBios;
  27. } else {
  28. info.type = TypeSufamiTurbo;
  29. }
  30. info.mapper = STROM;
  31. info.region = NTSC; //Sufami Turbo only released in Japan
  32. return; //RAM size handled internally by load_cart_st();
  33. }
  34. //=====================
  35. //detect standard carts
  36. //=====================
  37. const uint8 mapper = data[index + Mapper];
  38. const uint8 rom_type = data[index + RomType];
  39. const uint8 rom_size = data[index + RomSize];
  40. const uint8 company = data[index + Company];
  41. const uint8 region = data[index + CartRegion] & 0x7f;
  42. //detect presence of BS-X flash cartridge connector (reads extended header information)
  43. if(data[index - 14] == 'Z') {
  44. if(data[index - 11] == 'J') {
  45. uint8 n13 = data[index - 13];
  46. if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
  47. if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
  48. info.bsx_slot = true;
  49. }
  50. }
  51. }
  52. }
  53. if(info.bsx_slot == true) {
  54. if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
  55. //BS-X base cart
  56. info.type = TypeBsxBios;
  57. info.mapper = BSXROM;
  58. info.region = NTSC; //BS-X only released in Japan
  59. return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
  60. } else {
  61. info.type = TypeBsxSlotted;
  62. info.mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
  63. }
  64. } else {
  65. //standard cart
  66. info.type = TypeNormal;
  67. if(index == 0x7fc0 && size >= 0x401000) {
  68. info.mapper = ExLoROM;
  69. } else if(index == 0x7fc0 && mapper == 0x32) {
  70. info.mapper = ExLoROM;
  71. } else if(index == 0x7fc0) {
  72. info.mapper = LoROM;
  73. } else if(index == 0xffc0) {
  74. info.mapper = HiROM;
  75. } else { //index == 0x40ffc0
  76. info.mapper = ExHiROM;
  77. }
  78. }
  79. if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
  80. info.superfx = true;
  81. }
  82. if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) {
  83. info.sa1 = true;
  84. }
  85. if(mapper == 0x35 && rom_type == 0x55) {
  86. info.srtc = true;
  87. }
  88. if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
  89. info.sdd1 = true;
  90. }
  91. if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
  92. info.spc7110 = true;
  93. info.spc7110rtc = (rom_type == 0xf9);
  94. info.mapper = SPC7110ROM;
  95. }
  96. if(mapper == 0x20 && rom_type == 0xf3) {
  97. info.cx4 = true;
  98. }
  99. if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
  100. info.dsp1 = true;
  101. }
  102. if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
  103. info.dsp1 = true;
  104. }
  105. if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
  106. info.dsp1 = true;
  107. }
  108. if(info.dsp1 == true) {
  109. if((mapper & 0x2f) == 0x20 && size <= 0x100000) {
  110. info.dsp1_mapper = DSP1LoROM1MB;
  111. } else if((mapper & 0x2f) == 0x20) {
  112. info.dsp1_mapper = DSP1LoROM2MB;
  113. } else if((mapper & 0x2f) == 0x21) {
  114. info.dsp1_mapper = DSP1HiROM;
  115. }
  116. }
  117. if(mapper == 0x20 && rom_type == 0x05) {
  118. info.dsp2 = true;
  119. }
  120. if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
  121. info.dsp3 = true;
  122. }
  123. if(mapper == 0x30 && rom_type == 0x03) {
  124. info.dsp4 = true;
  125. }
  126. if(mapper == 0x30 && rom_type == 0x25) {
  127. info.obc1 = true;
  128. }
  129. if(mapper == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
  130. info.st010 = true;
  131. }
  132. if(mapper == 0x30 && rom_type == 0xf6 && rom_size < 10) {
  133. info.st011 = true;
  134. }
  135. if(mapper == 0x30 && rom_type == 0xf5) {
  136. info.st018 = true;
  137. }
  138. if(data[index + RamSize] & 7) {
  139. info.ram_size = 1024 << (data[index + RamSize] & 7);
  140. } else {
  141. info.ram_size = 0;
  142. }
  143. //0, 1, 13 = NTSC; 2 - 12 = PAL
  144. info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
  145. }
  146. unsigned Cartridge::find_header(const uint8_t *data, unsigned size) const {
  147. unsigned score_lo = score_header(data, size, 0x007fc0);
  148. unsigned score_hi = score_header(data, size, 0x00ffc0);
  149. unsigned score_ex = score_header(data, size, 0x40ffc0);
  150. if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
  151. if(score_lo >= score_hi && score_lo >= score_ex) {
  152. return 0x007fc0;
  153. } else if(score_hi >= score_ex) {
  154. return 0x00ffc0;
  155. } else {
  156. return 0x40ffc0;
  157. }
  158. }
  159. unsigned Cartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) const {
  160. if(size < addr + 64) return 0; //image too small to contain header at this location?
  161. int score = 0;
  162. uint16 resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
  163. uint16 checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
  164. uint16 complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
  165. uint8 resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
  166. uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
  167. //$00:[000-7fff] contains uninitialized RAM and MMIO.
  168. //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
  169. if(resetvector < 0x8000) return 0;
  170. //some images duplicate the header in multiple locations, and others have completely
  171. //invalid header information that cannot be relied upon.
  172. //below code will analyze the first opcode executed at the specified reset vector to
  173. //determine the probability that this is the correct header.
  174. //most likely opcodes
  175. if(resetop == 0x78 //sei
  176. || resetop == 0x18 //clc (clc; xce)
  177. || resetop == 0x38 //sec (sec; xce)
  178. || resetop == 0x9c //stz $nnnn (stz $4200)
  179. || resetop == 0x4c //jmp $nnnn
  180. || resetop == 0x5c //jml $nnnnnn
  181. ) score += 8;
  182. //plausible opcodes
  183. if(resetop == 0xc2 //rep #$nn
  184. || resetop == 0xe2 //sep #$nn
  185. || resetop == 0xad //lda $nnnn
  186. || resetop == 0xae //ldx $nnnn
  187. || resetop == 0xac //ldy $nnnn
  188. || resetop == 0xaf //lda $nnnnnn
  189. || resetop == 0xa9 //lda #$nn
  190. || resetop == 0xa2 //ldx #$nn
  191. || resetop == 0xa0 //ldy #$nn
  192. || resetop == 0x20 //jsr $nnnn
  193. || resetop == 0x22 //jsl $nnnnnn
  194. ) score += 4;
  195. //implausible opcodes
  196. if(resetop == 0x40 //rti
  197. || resetop == 0x60 //rts
  198. || resetop == 0x6b //rtl
  199. || resetop == 0xcd //cmp $nnnn
  200. || resetop == 0xec //cpx $nnnn
  201. || resetop == 0xcc //cpy $nnnn
  202. ) score -= 4;
  203. //least likely opcodes
  204. if(resetop == 0x00 //brk #$nn
  205. || resetop == 0x02 //cop #$nn
  206. || resetop == 0xdb //stp
  207. || resetop == 0x42 //wdm
  208. || resetop == 0xff //sbc $nnnnnn,x
  209. ) score -= 8;
  210. //at times, both the header and reset vector's first opcode will match ...
  211. //fallback and rely on info validity in these cases to determine more likely header.
  212. //a valid checksum is the biggest indicator of a valid header.
  213. if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
  214. if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
  215. if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
  216. if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
  217. if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
  218. if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
  219. if(data[addr + RomType] < 0x08) score++;
  220. if(data[addr + RomSize] < 0x10) score++;
  221. if(data[addr + RamSize] < 0x08) score++;
  222. if(data[addr + CartRegion] < 14) score++;
  223. if(score < 0) score = 0;
  224. return score;
  225. }
  226. #endif