smc.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* sd2snes - SD card based universal cartridge for the SNES
  2. Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
  3. AVR firmware portion
  4. Inspired by and based on code from sd2iec, written by Ingo Korb et al.
  5. See sdcard.c|h, config.h.
  6. FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
  7. see ff.c|h.
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; version 2 of the License only.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. smc.c: SMC file related operations
  19. */
  20. #include <avr/io.h>
  21. #include <util/delay.h>
  22. #include "fileops.h"
  23. #include "config.h"
  24. #include "uart.h"
  25. #include "smc.h"
  26. uint32_t hdr_addr[6] = {0xffb0, 0x101b0, 0x7fb0, 0x81b0, 0x40ffb0, 0x4101b0};
  27. uint8_t countAllASCII(uint8_t* data, int size) {
  28. uint8_t res = 0;
  29. do {
  30. size--;
  31. if(data[size] >= 0x20 && data[size] <= 0x7e) {
  32. res++;
  33. }
  34. } while (size);
  35. return res;
  36. }
  37. uint8_t countAllJISX0201(uint8_t* data, int size) {
  38. uint8_t res = 0;
  39. do {
  40. size--;
  41. if((data[size] >= 0x20 && data[size] <= 0x7e)
  42. ||(data[size] >= 0xa1 && data[size] <= 0xdf)) {
  43. res++;
  44. }
  45. } while (size);
  46. return res;
  47. }
  48. uint8_t isFixed(uint8_t* data, int size, uint8_t value) {
  49. uint8_t res = 1;
  50. do {
  51. size--;
  52. if(data[size] != value) {
  53. res = 0;
  54. }
  55. } while (size);
  56. return res;
  57. }
  58. uint8_t checkChksum(uint16_t cchk, uint16_t chk) {
  59. uint32_t sum = cchk + chk;
  60. uint8_t res = 0;
  61. if(sum==0x0000ffff) {
  62. res = 0x10;
  63. }
  64. return res;
  65. }
  66. void smc_id(snes_romprops_t* props) {
  67. uint8_t score, maxscore=1, score_idx=2; // assume LoROM
  68. snes_header_t* header = &(props->header);
  69. for(uint8_t num = 0; num < 6; num++) {
  70. if(!file_readblock(header, hdr_addr[num], sizeof(snes_header_t))
  71. || file_res) {
  72. // dprintf("uh oh... %d\n", file_res);
  73. // _delay_ms(30);
  74. score = 0;
  75. } else {
  76. score = smc_headerscore(header)/(1+(num&1));
  77. if((file_handle.fsize & 0x2ff) == 0x200) {
  78. if(num&1) {
  79. score+=20;
  80. } else {
  81. score=0;
  82. }
  83. } else {
  84. if(!(num&1)) {
  85. score+=20;
  86. } else {
  87. score=0;
  88. }
  89. }
  90. }
  91. // dprintf("%d: offset = %lX; score = %d\n", num, hdr_addr[num], score);
  92. // _delay_ms(100);
  93. if(score>=maxscore) {
  94. score_idx=num;
  95. maxscore=score;
  96. }
  97. }
  98. if(score_idx & 1) {
  99. props->offset = 0x200;
  100. } else {
  101. props->offset = 0;
  102. }
  103. // restore the chosen one
  104. // dprintf("winner is %d\n", score_idx);
  105. // _delay_ms(30);
  106. file_readblock(header, hdr_addr[score_idx], sizeof(snes_header_t));
  107. switch(header->map & 0xef) {
  108. case 0x20:
  109. props->mapper_id = 1;
  110. break;
  111. case 0x21:
  112. props->mapper_id = 0;
  113. break;
  114. case 0x25:
  115. props->mapper_id = 2;
  116. break;
  117. default: // invalid/unsupported mapper, use header location
  118. switch(score_idx) {
  119. case 0:
  120. case 1:
  121. props->mapper_id = 0;
  122. break;
  123. case 2:
  124. case 3:
  125. props->mapper_id = 1;
  126. break;
  127. case 4:
  128. case 5:
  129. props->mapper_id = 2;
  130. break;
  131. default:
  132. props->mapper_id = 1; // whatever
  133. }
  134. }
  135. if(header->romsize == 0 || header->romsize > 13) {
  136. header->romsize = 13;
  137. }
  138. props->ramsize_bytes = (uint32_t)1024 << header->ramsize;
  139. props->romsize_bytes = (uint32_t)1024 << header->romsize;
  140. props->expramsize_bytes = (uint32_t)1024 << header->expramsize;
  141. // dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
  142. if(props->ramsize_bytes > 32768 || props->ramsize_bytes < 2048) {
  143. props->ramsize_bytes = 0;
  144. }
  145. // dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
  146. f_lseek(&file_handle, 0);
  147. }
  148. uint8_t smc_headerscore(snes_header_t* header) {
  149. uint8_t score=0;
  150. score += countAllASCII(header->maker, sizeof(header->maker));
  151. score += countAllASCII(header->gamecode, sizeof(header->gamecode));
  152. score += isFixed(header->fixed_00, sizeof(header->fixed_00), 0x00);
  153. score += countAllJISX0201(header->name, sizeof(header->name));
  154. score += 3*isFixed(&header->fixed_33, sizeof(header->fixed_33), 0x33);
  155. score += checkChksum(header->cchk, header->chk);
  156. return score;
  157. }