genesis.c 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728
  1. /*
  2. genesis.c - Sega Genesis/Mega Drive support for uCON64
  3. Copyright (c) 1999 - 2001 NoisyB <noisyb@gmx.net>
  4. Copyright (c) 2002 - 2004 dbjh
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. // NOTE: The people at Sega refer to their company as Sega in normal text (not as SEGA)
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #ifdef HAVE_UNISTD_H
  26. #include <unistd.h>
  27. #endif
  28. #include <sys/stat.h>
  29. #include "misc/misc.h"
  30. #include "misc/chksum.h"
  31. #include "misc/file.h"
  32. #ifdef USE_ZLIB
  33. #include "misc/archive.h"
  34. #endif
  35. #include "misc/getopt2.h" // st_getopt2_t
  36. #include "ucon64.h"
  37. #include "ucon64_misc.h"
  38. #include "console/genesis.h"
  39. #include "backup/mgd.h"
  40. #include "backup/smd.h"
  41. #define GENESIS_HEADER_START 256
  42. #define GENESIS_HEADER_LEN (sizeof (st_genesis_header_t))
  43. #define GENESIS_NAME_LEN 48
  44. static int genesis_chksum (unsigned char *rom_buffer);
  45. static unsigned char *load_rom (st_rominfo_t *rominfo, const char *name,
  46. unsigned char *rom_buffer);
  47. static int save_rom (st_rominfo_t *rominfo, const char *name,
  48. unsigned char **buffer, int size);
  49. const st_getopt2_t genesis_usage[] =
  50. {
  51. {
  52. NULL, 0, 0, 0,
  53. NULL, "Genesis/Sega Mega Drive/Sega CD/32X/Nomad"/*"1989/19XX/19XX Sega http://www.sega.com"*/,
  54. NULL
  55. },
  56. {
  57. "gen", 0, 0, UCON64_GEN,
  58. NULL, "force recognition",
  59. &ucon64_wf[WF_OBJ_GEN_SWITCH]
  60. },
  61. {
  62. "int", 0, 0, UCON64_INT,
  63. NULL, "force ROM is in interleaved format (SMD)",
  64. &ucon64_wf[WF_OBJ_ALL_SWITCH]
  65. },
  66. {
  67. "int2", 0, 0, UCON64_INT2,
  68. NULL, "force ROM is in interleaved format 2 (MGD)",
  69. &ucon64_wf[WF_OBJ_ALL_SWITCH]
  70. },
  71. {
  72. "nint", 0, 0, UCON64_NINT,
  73. NULL, "force ROM is not in interleaved format (BIN/RAW)",
  74. &ucon64_wf[WF_OBJ_ALL_SWITCH]
  75. },
  76. {
  77. "n", 1, 0, UCON64_N,
  78. "NEW_NAME", "change foreign ROM name to NEW_NAME",
  79. &ucon64_wf[WF_OBJ_ALL_DEFAULT]
  80. },
  81. {
  82. "n2", 1, 0, UCON64_N2,
  83. "NEW_NAME", "change Japanese ROM name to NEW_NAME",
  84. &ucon64_wf[WF_OBJ_GEN_DEFAULT]
  85. },
  86. {
  87. "smd", 0, 0, UCON64_SMD,
  88. NULL, "convert to Super Magic Drive/SMD",
  89. &ucon64_wf[WF_OBJ_ALL_DEFAULT_NO_SPLIT]
  90. },
  91. {
  92. "smds", 0, 0, UCON64_SMDS,
  93. NULL, "convert emulator (*.srm) SRAM to Super Magic Drive/SMD",
  94. NULL
  95. },
  96. {
  97. "bin", 0, 0, UCON64_BIN,
  98. NULL, "convert to Magicom/BIN/RAW",
  99. &ucon64_wf[WF_OBJ_GEN_DEFAULT_NO_SPLIT]
  100. },
  101. {
  102. "mgd", 0, 0, UCON64_MGD,
  103. NULL, "convert to Multi Game*/MGD2/MGH",
  104. &ucon64_wf[WF_OBJ_ALL_DEFAULT_NO_SPLIT]
  105. },
  106. #if 0
  107. {
  108. "gf", 0, 0, UCON64_GF,
  109. NULL, "convert Sega CD country code to Europe; ROM=$CD_IMAGE",
  110. NULL
  111. },
  112. {
  113. "ga", 0, 0, UCON64_GA,
  114. NULL, "convert Sega CD country code to U.S.A.; ROM=$CD_IMAGE",
  115. NULL
  116. },
  117. {
  118. "gym", 0, 0, UCON64_GYM,
  119. NULL, "convert GYM (Genecyst) sound to WAV; " OPTION_LONG_S "rom=GYMFILE",
  120. NULL
  121. },
  122. {
  123. "cym", 0, 0, UCON64_CYM,
  124. NULL, "convert CYM (Callus emulator) sound to WAV; " OPTION_LONG_S "rom=CYMFILE",
  125. NULL
  126. },
  127. #endif
  128. {
  129. "stp", 0, 0, UCON64_STP,
  130. NULL, "convert SRAM from backup unit for use with an emulator\n"
  131. OPTION_LONG_S "stp just strips the first 512 bytes",
  132. NULL
  133. },
  134. {
  135. "j", 0, 0, UCON64_J,
  136. NULL, "join split ROM",
  137. &ucon64_wf[WF_OBJ_ALL_INIT_PROBE]
  138. },
  139. {
  140. "s", 0, 0, UCON64_S,
  141. NULL, "split ROM; default part size is 8 Mb (4 Mb for SMD)",
  142. &ucon64_wf[WF_OBJ_ALL_DEFAULT_NO_SPLIT]
  143. },
  144. {
  145. "ssize", 1, 0, UCON64_SSIZE,
  146. "SIZE", "specify split part size in Mbit",
  147. &ucon64_wf[WF_OBJ_ALL_SWITCH]
  148. },
  149. {
  150. "f", 0, 0, UCON64_F,
  151. NULL, "remove NTSC/PAL protection",
  152. &ucon64_wf[WF_OBJ_ALL_DEFAULT]
  153. },
  154. {
  155. "chk", 0, 0, UCON64_CHK,
  156. NULL, "fix ROM checksum",
  157. &ucon64_wf[WF_OBJ_ALL_DEFAULT]
  158. },
  159. {
  160. "1991", 0, 0, UCON64_1991,
  161. NULL, "fix old third party ROMs to work with consoles build after\n"
  162. "October 1991 by inserting \"(C) SEGA\" and \"(C)SEGA\"",
  163. &ucon64_wf[WF_OBJ_GEN_DEFAULT]
  164. },
  165. {
  166. "multi", 1, 0, UCON64_MULTI,
  167. "SIZE", "make multi-game file for use with MD-PRO flash card, truncated\n"
  168. "to SIZE Mbit; file with loader must be specified first, then\n"
  169. "all the ROMs, multi-game file to create last",
  170. &ucon64_wf[WF_OBJ_ALL_INIT_PROBE_STOP]
  171. },
  172. {
  173. "region", 1, 0, UCON64_REGION,
  174. "CODE", "enable region function; use with -multi\n"
  175. "CODE=0 force NTSC/Japan for all games\n"
  176. "CODE=1 force NTSC/U.S.A. for all games\n"
  177. "CODE=2 force PAL for all games\n"
  178. "CODE=x use whatever setting games expect",
  179. &ucon64_wf[WF_OBJ_GEN_SWITCH]
  180. },
  181. {NULL, 0, 0, 0, NULL, NULL, NULL}
  182. };
  183. const st_getopt2_t bin_usage[] =
  184. {
  185. {
  186. NULL, 0, 0, 0,
  187. NULL, "Magicom/BIN/RAW",
  188. NULL
  189. },
  190. {NULL, 0, 0, 0, NULL, NULL, NULL}
  191. };
  192. typedef struct st_genesis_header
  193. {
  194. char pad[256];
  195. } st_genesis_header_t;
  196. static st_genesis_header_t genesis_header;
  197. static genesis_file_t type;
  198. static int genesis_rom_size, genesis_has_ram, genesis_tv_standard, genesis_japanese;
  199. genesis_file_t
  200. genesis_get_file_type (void)
  201. {
  202. return type;
  203. }
  204. int
  205. genesis_smd (st_rominfo_t *rominfo)
  206. {
  207. st_smd_header_t header;
  208. char dest_name[FILENAME_MAX];
  209. unsigned char *rom_buffer = NULL;
  210. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  211. return -1;
  212. memset (&header, 0, SMD_HEADER_LEN);
  213. header.size = genesis_rom_size / 16384;
  214. header.id0 = 3;
  215. header.id1 = 0xaa;
  216. header.id2 = 0xbb;
  217. header.type = 6;
  218. strcpy (dest_name, ucon64.rom);
  219. set_suffix (dest_name, ".smd");
  220. ucon64_file_handler (dest_name, NULL, 0);
  221. ucon64_fwrite (&header, 0, SMD_HEADER_LEN, dest_name, "wb");
  222. smd_interleave (rom_buffer, genesis_rom_size);
  223. ucon64_fwrite (rom_buffer, SMD_HEADER_LEN, genesis_rom_size, dest_name, "ab");
  224. free (rom_buffer);
  225. printf (ucon64_msg[WROTE], dest_name);
  226. return 0;
  227. }
  228. int
  229. genesis_smds (void)
  230. {
  231. char dest_name[FILENAME_MAX];
  232. unsigned char buf[32768];
  233. st_smd_header_t header;
  234. memset (&header, 0, SMD_HEADER_LEN);
  235. memset (&buf, 0, 32768);
  236. ucon64_fread (buf, 0, ucon64.file_size, ucon64.rom);
  237. header.id1 = 0xaa;
  238. header.id2 = 0xbb;
  239. header.type = 7; // SRAM file
  240. strcpy (dest_name, ucon64.rom);
  241. set_suffix (dest_name, ".sav");
  242. ucon64_file_handler (dest_name, NULL, 0);
  243. ucon64_fwrite (&header, 0, SMD_HEADER_LEN, dest_name, "wb");
  244. smd_interleave (buf, 32768); // SMD SRAM files are interleaved (Are they? - dbjh)
  245. ucon64_fwrite (buf, SMD_HEADER_LEN, 32768, dest_name, "ab");
  246. printf (ucon64_msg[WROTE], dest_name);
  247. return 0;
  248. }
  249. int
  250. genesis_bin (st_rominfo_t *rominfo)
  251. {
  252. char dest_name[FILENAME_MAX];
  253. unsigned char *rom_buffer = NULL;
  254. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  255. return -1;
  256. strcpy (dest_name, ucon64.rom);
  257. set_suffix (dest_name, ".bin");
  258. ucon64_file_handler (dest_name, NULL, 0);
  259. ucon64_fwrite (rom_buffer, 0, genesis_rom_size, dest_name, "wb");
  260. free (rom_buffer);
  261. printf (ucon64_msg[WROTE], dest_name);
  262. return 0;
  263. }
  264. // see src/backup/mgd.h for the file naming scheme
  265. int
  266. genesis_mgd (st_rominfo_t *rominfo)
  267. {
  268. #define CC (const char)
  269. unsigned char *rom_buffer = NULL;
  270. char dest_name[FILENAME_MAX];
  271. #if 0 // TODO: We need more info about the Multi Game Hunter
  272. int x, y;
  273. char mgh[512], buf[FILENAME_MAX];
  274. const char mghcharset[1024] = {
  275. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  276. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  277. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  278. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  279. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  280. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  281. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  282. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  283. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  284. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  285. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  286. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  287. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  288. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  289. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  290. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  291. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  292. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  293. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  294. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  295. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  296. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  297. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  298. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  299. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  300. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  301. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  302. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  303. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  304. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  305. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  306. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  307. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  308. /* ! */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00,
  309. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  310. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  311. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  312. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  313. /* & */ 0x3c, 0x66, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x02,
  314. /* ' */ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
  315. /* ( */ 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0c, 0x00,
  316. /* ) */ 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00,
  317. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  318. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  319. /* , */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08,
  320. /* - */ 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
  321. /* . */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
  322. /* / */ 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00,
  323. /* 0 */ 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
  324. /* 1 */ 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
  325. /* 2 */ 0x3c, 0x66, 0x06, 0x06, 0x7c, 0x60, 0x7e, 0x00,
  326. /* 3 */ 0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00,
  327. /* 4 */ 0x18, 0x38, 0x58, 0x7c, 0x18, 0x18, 0x3c, 0x00,
  328. /* 5 */ 0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00,
  329. /* 6 */ 0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00,
  330. /* 7 */ 0x7e, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x18, 0x00,
  331. /* 8 */ 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00,
  332. /* 9 */ 0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00,
  333. /* : */ 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00,
  334. /* ; */ 0x00, 0x00, 0x18, 0x00, 0x18, 0x08, 0x00, 0x00,
  335. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  336. /* = */ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00,
  337. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  338. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  339. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  340. /* A */ 0x18, 0x3c, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x00,
  341. /* B */ 0x7c, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x7c, 0x00,
  342. /* C */ 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x00,
  343. /* D */ 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00,
  344. /* E */ 0x7e, 0x60, 0x60, 0x7e, 0x60, 0x60, 0x7e, 0x00,
  345. /* F */ 0x7e, 0x60, 0x60, 0x7e, 0x60, 0x60, 0x60, 0x00,
  346. /* G */ 0x3e, 0x60, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00,
  347. /* H */ 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
  348. /* I */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
  349. /* J */ 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
  350. /* K */ 0x66, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00,
  351. /* L */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00,
  352. /* M */ CC 0xc6, CC 0xee, CC 0xfe, CC 0xd6, CC 0xc6, CC 0xc6, CC 0xc6, 0x00,
  353. /* N */ 0x66, 0x76, 0x7e, 0x7e, 0x6e, 0x66, 0x66, 0x00,
  354. /* O */ 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
  355. /* P */ 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x00,
  356. /* Q */ 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3e, 0x00,
  357. /* R */ 0x7c, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x00,
  358. /* S */ 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00,
  359. /* T */ 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
  360. /* U */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
  361. /* V */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x3c, 0x00,
  362. /* W */ 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x2c, 0x00,
  363. /* X */ 0x66, 0x66, 0x3c, 0x10, 0x3c, 0x66, 0x66, 0x00,
  364. /* Y */ 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00,
  365. /* Z */ 0x7e, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x7e, 0x00,
  366. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  367. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  368. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  369. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  370. /* _ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
  371. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  372. /* a */ 0x00, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
  373. /* b */ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x00,
  374. /* c */ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00,
  375. /* d */ 0x06, 0x06, 0x6e, 0x66, 0x66, 0x66, 0x3e, 0x00,
  376. /* e */ 0x00, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
  377. /* f */ 0x0c, 0x18, 0x18, 0x3c, 0x18, 0x18, 0x3c, 0x00,
  378. /* g */ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3e, 0x06, 0x7c,
  379. /* h */ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x00,
  380. /* i */ 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
  381. /* j */ 0x00, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x6c, 0x38,
  382. /* k */ 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0x00,
  383. /* l */ 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
  384. /* m */ 0x00, 0x00, 0x5c, 0x76, 0x56, 0x56, 0x56, 0x00,
  385. /* n */ 0x00, 0x00, 0x6c, 0x7e, 0x66, 0x66, 0x66, 0x00,
  386. /* o */ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
  387. /* p */ 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60,
  388. /* q */ 0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x06,
  389. /* r */ 0x00, 0x00, 0x18, 0x1a, 0x18, 0x18, 0x3c, 0x00,
  390. /* s */ 0x00, 0x00, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x00,
  391. /* t */ 0x00, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00,
  392. /* u */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00,
  393. /* v */ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x00,
  394. /* w */ 0x00, 0x00, 0x56, 0x56, 0x56, 0x56, 0x7e, 0x00,
  395. /* x */ 0x00, 0x00, 0x66, 0x66, 0x18, 0x66, 0x66, 0x00,
  396. /* y */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x7c,
  397. /* z */ 0x00, 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00,
  398. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  399. /* | */ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
  400. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  401. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  402. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  403. };
  404. #endif
  405. // pad the file to the next valid MGD2 size if it doesn't have a valid size
  406. if (genesis_rom_size <= 1 * MBIT)
  407. genesis_rom_size = 1 * MBIT;
  408. else if (genesis_rom_size <= 2 * MBIT)
  409. genesis_rom_size = 2 * MBIT;
  410. else if (genesis_rom_size <= 4 * MBIT)
  411. genesis_rom_size = 4 * MBIT;
  412. else if (genesis_rom_size <= 8 * MBIT)
  413. genesis_rom_size = 8 * MBIT;
  414. else if (genesis_rom_size <= 16 * MBIT)
  415. genesis_rom_size = 16 * MBIT;
  416. else if (genesis_rom_size <= 20 * MBIT)
  417. genesis_rom_size = 20 * MBIT;
  418. else if (genesis_rom_size <= 24 * MBIT)
  419. genesis_rom_size = 24 * MBIT;
  420. else
  421. genesis_rom_size = 32 * MBIT;
  422. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  423. return -1;
  424. mgd_make_name (ucon64.rom, UCON64_GEN, genesis_rom_size, dest_name);
  425. ucon64_file_handler (dest_name, NULL, OF_FORCE_BASENAME);
  426. mgd_interleave (&rom_buffer, genesis_rom_size);
  427. ucon64_fwrite (rom_buffer, 0, genesis_rom_size, dest_name, "wb");
  428. printf (ucon64_msg[WROTE], dest_name);
  429. free (rom_buffer);
  430. #if 0 // TODO: We need more info about the Multi Game Hunter (and a new option)
  431. // automatically create MGH name file
  432. memset (mgh, 0, sizeof (mgh));
  433. mgh[0] = 'M';
  434. mgh[1] = 'G';
  435. mgh[2] = 'H';
  436. mgh[3] = 0x1a;
  437. mgh[4] = 0x06;
  438. mgh[5] = (char) 0xf0;
  439. mgh[31] = (char) 0xff;
  440. // In addition to the above, uCON also does "memcpy (mgh + 16, "MGH By uCON/chp", 15);"
  441. memcpy (buf, rominfo->name, 15); // copy first 15 bytes (don't use strlen() or strcpy())
  442. for (x = 0; x < 15; x++)
  443. {
  444. for (y = 0; y < 4; y++)
  445. mgh[((x + 2) * 16) + y + 4] = mghcharset[(((unsigned char *) buf)[x] * 8) + y];
  446. for (y = 4; y < 8; y++)
  447. mgh[((x + 2) * 16) + y + 244] = mghcharset[(((unsigned char *) buf)[x] * 8) + y];
  448. }
  449. set_suffix (dest_name, ".mgh");
  450. ucon64_output_fname (dest_name, OF_FORCE_BASENAME);
  451. /*
  452. If a backup would be created it would overwrite the backup of the ROM. The
  453. ROM backup is more important, so we don't write a backup of the MGH file.
  454. */
  455. ucon64_fwrite (mgh, 0, sizeof (mgh), dest_name, "wb");
  456. #endif
  457. mgd_write_index_file ((char *) basename2 (dest_name), 1);
  458. return 0;
  459. }
  460. int
  461. genesis_s (st_rominfo_t *rominfo)
  462. {
  463. st_smd_header_t smd_header;
  464. char dest_name[FILENAME_MAX], *p;
  465. int x, nparts, surplus, size = ucon64.file_size - rominfo->buheader_len,
  466. part_size;
  467. if (UCON64_ISSET (ucon64.part_size))
  468. {
  469. part_size = ucon64.part_size;
  470. // Don't allow too small part sizes, see src/console/snes.c (snes_s())
  471. if (part_size < 4 * MBIT)
  472. {
  473. fprintf (stderr,
  474. "ERROR: Split part size must be larger than or equal to 4 Mbit\n");
  475. return -1;
  476. }
  477. }
  478. else
  479. {
  480. if (type == SMD)
  481. part_size = 4 * MBIT; // SMD uses 4 Mb parts
  482. else
  483. part_size = 8 * MBIT; // MGD and Magicom ("BIN") use
  484. } // 8 Mb parts
  485. if (size <= part_size)
  486. {
  487. printf (
  488. "NOTE: ROM size is smaller than or equal to %d Mbit -- won't be split\n",
  489. part_size / MBIT);
  490. return -1;
  491. }
  492. nparts = size / part_size;
  493. surplus = size % part_size;
  494. if (type == SMD)
  495. {
  496. ucon64_fread (&smd_header, 0, SMD_HEADER_LEN, ucon64.rom);
  497. strcpy (dest_name, ucon64.rom);
  498. set_suffix (dest_name, ".1");
  499. ucon64_output_fname (dest_name, 0);
  500. p = strrchr (dest_name, '.') + 1;
  501. smd_header.size = part_size / 16384;
  502. smd_header.id0 = 3;
  503. // if smd_header.split bit 6 == 0 -> last file of the ROM
  504. smd_header.split |= 0x40;
  505. for (x = 0; x < nparts; x++)
  506. {
  507. if (surplus == 0 && x == nparts - 1)
  508. smd_header.split &= ~0x40; // last file -> clear bit 6
  509. // don't write backups of parts, because one name is used
  510. ucon64_fwrite (&smd_header, 0, SMD_HEADER_LEN, dest_name, "wb");
  511. fcopy (ucon64.rom, x * part_size + rominfo->buheader_len, part_size, dest_name, "ab");
  512. printf (ucon64_msg[WROTE], dest_name);
  513. (*p)++;
  514. }
  515. if (surplus != 0)
  516. {
  517. smd_header.size = surplus / 16384;
  518. smd_header.split &= ~0x40; // last file -> clear bit 6
  519. // don't write backups of parts, because one name is used
  520. ucon64_fwrite (&smd_header, 0, SMD_HEADER_LEN, dest_name, "wb");
  521. fcopy (ucon64.rom, x * part_size + rominfo->buheader_len, surplus, dest_name, "ab");
  522. printf (ucon64_msg[WROTE], dest_name);
  523. }
  524. }
  525. else if (type == MGD_GEN)
  526. {
  527. char suffix[5], *p_index, name[9], *names[16], names_mem[16][9];
  528. int n, offset, size, name_i = 0;
  529. for (n = 0; n < 16; n++)
  530. names[n] = names_mem[n];
  531. mgd_make_name (ucon64.rom, UCON64_GEN, genesis_rom_size, dest_name);
  532. strcpy (suffix, (char *) get_suffix (dest_name));
  533. if ((p = strchr (dest_name, '.')))
  534. *p = 0;
  535. n = strlen (dest_name);
  536. if (n > 7)
  537. n = 7;
  538. dest_name[n] = 'A';
  539. dest_name[n + 1] = 0;
  540. strcpy (name, dest_name);
  541. p_index = &name[n];
  542. strcat (dest_name, suffix);
  543. ucon64_output_fname (dest_name, OF_FORCE_BASENAME);
  544. p = strrchr (dest_name, '.') - 1;
  545. if (surplus)
  546. nparts++;
  547. for (x = 0; x < nparts; x++)
  548. {
  549. offset = x * (part_size / 2);
  550. size = part_size / 2;
  551. if (offset + size > ucon64.file_size / 2)
  552. size = ucon64.file_size / 2 - offset;
  553. // don't write backups of parts, because one name is used
  554. // write first half of file
  555. fcopy (ucon64.rom, offset, size, dest_name, "wb");
  556. // write second half of file; don't do: "(nparts / 2) * part_size"!
  557. fcopy (ucon64.rom, ucon64.file_size / 2 + offset, size, dest_name, "ab");
  558. printf (ucon64_msg[WROTE], dest_name);
  559. (*p)++;
  560. strcpy (names[name_i], name);
  561. name_i++;
  562. (*p_index)++;
  563. }
  564. mgd_write_index_file (names, name_i);
  565. }
  566. else // type == BIN
  567. {
  568. strcpy (dest_name, ucon64.rom);
  569. set_suffix (dest_name, ".r01");
  570. ucon64_output_fname (dest_name, 0);
  571. p = strrchr (dest_name, '.') + 3;
  572. for (x = 0; x < nparts; x++)
  573. {
  574. if (surplus == 0 && x == nparts - 1)
  575. *p = '0'; // last file should have suffix ".r00"
  576. fcopy (ucon64.rom, x * part_size + rominfo->buheader_len, part_size, dest_name, "wb");
  577. printf (ucon64_msg[WROTE], dest_name);
  578. (*p)++;
  579. }
  580. if (surplus != 0)
  581. {
  582. *p = '0';
  583. fcopy (ucon64.rom, x * part_size + rominfo->buheader_len, surplus, dest_name, "wb");
  584. printf (ucon64_msg[WROTE], dest_name);
  585. }
  586. }
  587. return 0;
  588. }
  589. int
  590. genesis_j (st_rominfo_t *rominfo)
  591. {
  592. char src_name[FILENAME_MAX], dest_name[FILENAME_MAX], *p;
  593. int block_size, total_size = 0;
  594. if (type == SMD)
  595. {
  596. unsigned char buf[3];
  597. strcpy (dest_name, ucon64.rom);
  598. set_suffix (dest_name, ".smd");
  599. ucon64_file_handler (dest_name, NULL, 0);
  600. strcpy (src_name, ucon64.rom);
  601. p = strrchr (src_name, '.') + 1;
  602. fcopy (src_name, 0, rominfo->buheader_len, dest_name, "wb");
  603. block_size = ucon64.file_size - rominfo->buheader_len;
  604. while (fcopy (src_name, rominfo->buheader_len, block_size, dest_name, "ab") != -1)
  605. {
  606. printf ("Joined: %s\n", src_name);
  607. total_size += block_size;
  608. (*p)++;
  609. block_size = fsizeof (src_name) - rominfo->buheader_len;
  610. }
  611. if (rominfo->buheader_len)
  612. { // fix header
  613. buf[0] = total_size / 16384; // # 16 kB blocks
  614. buf[1] = 3; // ID 0
  615. buf[2] = 0; // last file -> clear bit 6
  616. ucon64_fwrite (buf, 0, 3, dest_name, "r+b");
  617. buf[0] = 0xaa; // ID 1
  618. buf[1] = 0xbb; // ID 2
  619. buf[2] = 6; // type Genesis
  620. ucon64_fwrite (buf, 8, 3, dest_name, "r+b");
  621. }
  622. printf (ucon64_msg[WROTE], dest_name);
  623. }
  624. else if (type == MGD_GEN)
  625. {
  626. /*
  627. file1 file2 file3 file4
  628. 1/2 3/4 5/6 7/8 (1st half/2nd half)
  629. joined file
  630. 1/3/5/7/2/4/6/8
  631. */
  632. strcpy (dest_name, ucon64.rom);
  633. set_suffix (dest_name, ".tmp"); // users should use -mgd to get
  634. ucon64_file_handler (dest_name, NULL, 0); // a correct name
  635. remove (dest_name);
  636. strcpy (src_name, ucon64.rom);
  637. p = strrchr (src_name, '.') - 1;
  638. block_size = (ucon64.file_size - rominfo->buheader_len) / 2;
  639. while (fcopy (src_name, rominfo->buheader_len, block_size, dest_name, "ab") != -1)
  640. {
  641. (*p)++;
  642. // BUG ALERT: Assume all parts have the same header length
  643. block_size = (fsizeof (src_name) - rominfo->buheader_len) / 2;
  644. }
  645. strcpy (src_name, ucon64.rom);
  646. p = strrchr (src_name, '.') - 1;
  647. block_size = (ucon64.file_size - rominfo->buheader_len) / 2;
  648. while (fcopy (src_name, rominfo->buheader_len + block_size,
  649. block_size, dest_name, "ab") != -1)
  650. {
  651. printf ("Joined: %s\n", src_name); // print this here, not in the
  652. (*p)++; // previous loop
  653. // BUG ALERT: Assume all parts have the same header length
  654. block_size = (fsizeof (src_name) - rominfo->buheader_len) / 2;
  655. }
  656. printf (ucon64_msg[WROTE], dest_name);
  657. }
  658. else if (type == BIN)
  659. {
  660. int tried_r00 = 0;
  661. strcpy (dest_name, ucon64.rom);
  662. set_suffix (dest_name, ".bin");
  663. ucon64_file_handler (dest_name, NULL, 0);
  664. remove (dest_name);
  665. strcpy (src_name, ucon64.rom);
  666. p = strrchr (src_name, '.') + 3;
  667. *(p - 1) = '0'; // be user friendly and avoid confusion
  668. *p = '1'; // (.r01 is first file, not .r00)
  669. block_size = ucon64.file_size - rominfo->buheader_len;
  670. while (fcopy (src_name, rominfo->buheader_len, block_size, dest_name, "ab") != -1)
  671. {
  672. printf ("Joined: %s\n", src_name);
  673. if (tried_r00)
  674. break; // quit after joining last file
  675. (*p)++;
  676. if (!tried_r00 && access (src_name, F_OK) != 0)
  677. { // file does not exist -> try .r00
  678. *p = '0';
  679. tried_r00 = 1;
  680. }
  681. block_size = fsizeof (src_name) - rominfo->buheader_len;
  682. }
  683. printf (ucon64_msg[WROTE], dest_name);
  684. }
  685. return 0;
  686. }
  687. static int
  688. genesis_name (st_rominfo_t *rominfo, const char *name1, const char *name2)
  689. {
  690. unsigned char *rom_buffer = NULL;
  691. char buf[FILENAME_MAX];
  692. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  693. return -1;
  694. if (name1)
  695. {
  696. memset (buf, ' ', GENESIS_NAME_LEN);
  697. strncpy (buf, name1, strlen (name1) > GENESIS_NAME_LEN ?
  698. GENESIS_NAME_LEN : strlen (name1));
  699. memcpy (&rom_buffer[GENESIS_HEADER_START + 32 + GENESIS_NAME_LEN], buf,
  700. GENESIS_NAME_LEN);
  701. }
  702. if (name2)
  703. {
  704. memset (buf, ' ', GENESIS_NAME_LEN);
  705. strncpy (buf, name2, strlen (name2) > GENESIS_NAME_LEN ?
  706. GENESIS_NAME_LEN : strlen (name2));
  707. memcpy (&rom_buffer[GENESIS_HEADER_START + 32], buf, GENESIS_NAME_LEN);
  708. }
  709. strcpy (buf, ucon64.rom);
  710. ucon64_file_handler (buf, NULL, 0);
  711. save_rom (rominfo, buf, &rom_buffer, genesis_rom_size);
  712. free (rom_buffer);
  713. printf (ucon64_msg[WROTE], buf);
  714. return 0;
  715. }
  716. int
  717. genesis_n (st_rominfo_t *rominfo, const char *name)
  718. {
  719. return genesis_name (rominfo, name, NULL);
  720. }
  721. int
  722. genesis_n2 (st_rominfo_t *rominfo, const char *name)
  723. {
  724. return genesis_name (rominfo, NULL, name);
  725. }
  726. int
  727. genesis_1991 (st_rominfo_t *rominfo)
  728. {
  729. return genesis_name (rominfo, "(C)SEGA", "(C) SEGA");
  730. }
  731. int
  732. genesis_chk (st_rominfo_t *rominfo)
  733. {
  734. unsigned char *rom_buffer = NULL;
  735. char dest_name[FILENAME_MAX];
  736. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  737. return -1;
  738. rom_buffer[GENESIS_HEADER_START + 143] = rominfo->current_internal_crc; // low byte of checksum
  739. rom_buffer[GENESIS_HEADER_START + 142] = rominfo->current_internal_crc >> 8; // high byte of checksum
  740. dumper (stdout, &rom_buffer[GENESIS_HEADER_START + 0x8e], 2, GENESIS_HEADER_START + 0x8e, DUMPER_HEX);
  741. strcpy (dest_name, ucon64.rom);
  742. ucon64_file_handler (dest_name, NULL, 0);
  743. save_rom (rominfo, dest_name, &rom_buffer, genesis_rom_size);
  744. free (rom_buffer);
  745. printf (ucon64_msg[WROTE], dest_name);
  746. return 0;
  747. }
  748. static int
  749. genesis_fix_pal_protection (st_rominfo_t *rominfo)
  750. /*
  751. This function searches for PAL protection codes. If it finds one it will
  752. fix the code so that the game will run on a Genesis (NTSC).
  753. */
  754. {
  755. char fname[FILENAME_MAX];
  756. unsigned char *rom_buffer = NULL;
  757. int offset = 0, block_size, n = 0, n_extra_patterns, n2;
  758. st_cm_pattern_t *patterns = NULL;
  759. strcpy (fname, "genpal.txt");
  760. // First try the current directory, then the configuration directory
  761. if (access (fname, F_OK | R_OK) == -1)
  762. sprintf (fname, "%s" FILE_SEPARATOR_S "genpal.txt", ucon64.configdir);
  763. n_extra_patterns = build_cm_patterns (&patterns, fname, ucon64.quiet == -1 ? 1 : 0);
  764. if (n_extra_patterns >= 0)
  765. printf ("Found %d additional code%s in %s\n",
  766. n_extra_patterns, n_extra_patterns != 1 ? "s" : "", fname);
  767. puts ("Attempting to fix PAL protection code...");
  768. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  769. return -1;
  770. while ((n2 = ucon64.file_size - offset) > 0)
  771. {
  772. block_size = n2 >= 16 * 1024 ? 16 * 1024 : n2;
  773. for (n2 = 0; n2 < n_extra_patterns; n2++)
  774. n += change_mem2 ((char *) rom_buffer + offset, block_size,
  775. patterns[n2].search,
  776. patterns[n2].search_size,
  777. patterns[n2].wildcard,
  778. patterns[n2].escape,
  779. patterns[n2].replace,
  780. patterns[n2].replace_size,
  781. patterns[n2].offset,
  782. patterns[n2].sets);
  783. offset += 16 * 1024;
  784. }
  785. cleanup_cm_patterns (&patterns, n_extra_patterns);
  786. strcpy (fname, ucon64.rom);
  787. ucon64_file_handler (fname, NULL, 0);
  788. save_rom (rominfo, fname, &rom_buffer, genesis_rom_size);
  789. free (rom_buffer);
  790. printf ("Found %d pattern%s\n", n, n != 1 ? "s" : "");
  791. printf (ucon64_msg[WROTE], fname);
  792. return n;
  793. }
  794. static int
  795. genesis_fix_ntsc_protection (st_rominfo_t *rominfo)
  796. /*
  797. This function searches for NTSC protection codes. If it finds one it will
  798. fix the code so that the game will run on a Mega Drive (PAL).
  799. */
  800. {
  801. char fname[FILENAME_MAX];
  802. unsigned char *rom_buffer = NULL;
  803. int offset = 0, block_size, n = 0, n_extra_patterns, n2;
  804. st_cm_pattern_t *patterns = NULL;
  805. strcpy (fname, "mdntsc.txt");
  806. // First try the current directory, then the configuration directory
  807. if (access (fname, F_OK | R_OK) == -1)
  808. sprintf (fname, "%s" FILE_SEPARATOR_S "mdntsc.txt", ucon64.configdir);
  809. n_extra_patterns = build_cm_patterns (&patterns, fname, ucon64.quiet == -1 ? 1 : 0);
  810. if (n_extra_patterns >= 0)
  811. printf ("Found %d additional code%s in %s\n",
  812. n_extra_patterns, n_extra_patterns != 1 ? "s" : "", fname);
  813. puts ("Attempting to fix NTSC protection code...");
  814. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  815. return -1;
  816. while ((n2 = ucon64.file_size - offset) > 0)
  817. {
  818. block_size = n2 >= 16 * 1024 ? 16 * 1024 : n2;
  819. for (n2 = 0; n2 < n_extra_patterns; n2++)
  820. n += change_mem2 ((char *) rom_buffer + offset, block_size,
  821. patterns[n2].search,
  822. patterns[n2].search_size,
  823. patterns[n2].wildcard,
  824. patterns[n2].escape,
  825. patterns[n2].replace,
  826. patterns[n2].replace_size,
  827. patterns[n2].offset,
  828. patterns[n2].sets);
  829. offset += 16 * 1024;
  830. }
  831. cleanup_cm_patterns (&patterns, n_extra_patterns);
  832. strcpy (fname, ucon64.rom);
  833. ucon64_file_handler (fname, NULL, 0);
  834. save_rom (rominfo, fname, &rom_buffer, genesis_rom_size);
  835. free (rom_buffer);
  836. printf ("Found %d pattern%s\n", n, n != 1 ? "s" : "");
  837. printf (ucon64_msg[WROTE], fname);
  838. return n;
  839. }
  840. int
  841. genesis_f (st_rominfo_t *rominfo)
  842. {
  843. /*
  844. In the Philipines the television standard is NTSC, but do games made
  845. for the Philipines exist?
  846. Just like with SNES we don't guarantee anything for files that needn't be
  847. fixed/cracked/patched.
  848. */
  849. if (genesis_tv_standard == 0) // NTSC (Japan, U.S.A. or Brazil ('4'))
  850. return genesis_fix_ntsc_protection (rominfo);
  851. else
  852. return genesis_fix_pal_protection (rominfo);
  853. }
  854. unsigned char *
  855. load_rom (st_rominfo_t *rominfo, const char *name, unsigned char *rom_buffer)
  856. {
  857. FILE *file;
  858. int bytesread;
  859. if ((file = fopen (name, "rb")) == NULL)
  860. return NULL;
  861. if (!(rom_buffer = (unsigned char *) malloc (genesis_rom_size)))
  862. {
  863. fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], genesis_rom_size);
  864. fclose (file);
  865. return NULL;
  866. }
  867. fseek (file, rominfo->buheader_len, SEEK_SET); // don't do this only for SMD!
  868. bytesread = fread (rom_buffer, 1, genesis_rom_size, file);
  869. if (bytesread < genesis_rom_size)
  870. memset (rom_buffer + bytesread, 0, genesis_rom_size - bytesread);
  871. if (type != BIN)
  872. {
  873. if (ucon64.fcrc32 == 0)
  874. ucon64.fcrc32 = crc32 (ucon64.fcrc32, rom_buffer, genesis_rom_size);
  875. if (type == SMD)
  876. smd_deinterleave (rom_buffer, bytesread);
  877. else // type == MGD_GEN
  878. mgd_deinterleave (&rom_buffer, bytesread, genesis_rom_size);
  879. }
  880. if (ucon64.crc32 == 0) // calculate the CRC32 only once
  881. ucon64.crc32 = crc32 (0, rom_buffer, bytesread);
  882. fclose (file);
  883. return rom_buffer;
  884. }
  885. int
  886. save_rom (st_rominfo_t *rominfo, const char *name, unsigned char **buffer, int size)
  887. {
  888. if (type == SMD)
  889. {
  890. int n;
  891. /*
  892. Copy the complete backup unit header length, no matter how strange or
  893. how large the size. fcopy() doesn't copy if source and destination are
  894. one and the same. Copying is necessary if source and destination are
  895. different so that we can use "r+b" when writing the contents of buffer
  896. to disk.
  897. */
  898. fcopy (ucon64.rom, 0, rominfo->buheader_len, name, "wb");
  899. smd_interleave (*buffer, size);
  900. n = ucon64_fwrite (*buffer, rominfo->buheader_len, size, name, "r+b");
  901. if (size < (int) (ucon64.file_size - rominfo->buheader_len))
  902. truncate2 (name, rominfo->buheader_len + size);
  903. return n;
  904. }
  905. else if (type == MGD_GEN)
  906. {
  907. mgd_interleave (buffer, size); // allocates new buffer
  908. return ucon64_fwrite (*buffer, 0, size, name, "wb");
  909. }
  910. else // type == BIN
  911. return ucon64_fwrite (*buffer, 0, size, name, "wb");
  912. }
  913. static void
  914. write_game_table_entry (FILE *destfile, int file_no, st_rominfo_t *rominfo,
  915. int totalsize)
  916. {
  917. static int sram_page = 0, file_no_sram = 0;
  918. int n;
  919. unsigned char name[0x1c], flags = 0; // SRAM/region flags: F, D (reserved), E, P, V, T, S1, S0
  920. fseek (destfile, 0x8000 + (file_no - 1) * 0x20, SEEK_SET);
  921. fputc (0xff, destfile); // 0x0 = 0xff
  922. memcpy (name, rominfo->name, 0x1c);
  923. for (n = 0; n < 0x1c; n++)
  924. {
  925. if (!isprint ((int) name[n]))
  926. name[n] = '.';
  927. else
  928. name[n] = toupper (name[n]); // according to Leo, MDPACKU4.BIN
  929. } // only supports upper case characters
  930. fwrite (name, 1, 0x1c, destfile); // 0x1 - 0x1c = name
  931. fputc (0, destfile); // 0x1d = 0
  932. fputc (totalsize / (2 * MBIT), destfile); // 0x1e = bank code
  933. flags = 0x80; // set F (?, default)
  934. if (genesis_has_ram)
  935. {
  936. if (sram_page == 3)
  937. file_no_sram = file_no;
  938. else if (sram_page > 3)
  939. {
  940. printf ("WARNING: This ROM will share SRAM with ROM %d\n", file_no_sram);
  941. sram_page = 3;
  942. }
  943. flags |= sram_page++;
  944. if ((ucon64.file_size - rominfo->buheader_len) <= 16 * MBIT)
  945. flags &= ~0x80; // clear F (<=16 Mb & SRAM)
  946. }
  947. else
  948. flags |= 4; // set T (no SRAM)
  949. /*
  950. J(apan) would probably be a more logical name for bit E(urope). I (dbjh)
  951. base that on information of SamIAm. According to him there are three types
  952. of the console:
  953. American Genesis NTSC/no Japanese switch
  954. Japanese Genesis NTSC/Japanese switch
  955. Mega Drive (rest of the world?) PAL/no Japanese switch
  956. So, besides PAL and NTSC there is the variable whether the console contains
  957. a Japanese "switch". The region function is used to make the game "think"
  958. it's running on another type of console. For example, a Japanese game
  959. running on a (European) Mega Drive should have the P and E bit set to 0.
  960. */
  961. if (UCON64_ISSET (ucon64.region))
  962. {
  963. if (!genesis_japanese)
  964. flags |= 0x20; // set E(urope)
  965. if (genesis_tv_standard == 1)
  966. flags |= 0x10; // set P(AL)
  967. flags |= 8; // set V (enable region function)
  968. }
  969. fputc (flags, destfile); // 0x1f = flags
  970. }
  971. int
  972. genesis_multi (int truncate_size, char *fname)
  973. {
  974. #define BUFSIZE (32 * 1024) // must be a multiple of 16 kB
  975. int n, n_files, file_no, bytestowrite, byteswritten, totalsize = 0, done,
  976. truncated = 0, paddedsize, org_do_not_calc_crc = ucon64.do_not_calc_crc;
  977. struct stat fstate;
  978. FILE *srcfile, *destfile;
  979. char destname[FILENAME_MAX];
  980. unsigned char buffer[BUFSIZE];
  981. if (truncate_size == 0)
  982. {
  983. fprintf (stderr, "ERROR: Can't make multi-game file of 0 bytes\n");
  984. return -1;
  985. }
  986. if (fname != NULL)
  987. {
  988. strcpy(destname, fname);
  989. n_files = ucon64.argc;
  990. }
  991. else
  992. {
  993. strcpy(destname, ucon64.argv[ucon64.argc - 1]);
  994. n_files = ucon64.argc - 1;
  995. }
  996. ucon64_file_handler (destname, NULL, OF_FORCE_BASENAME);
  997. if ((destfile = fopen (destname, "wb")) == NULL)
  998. {
  999. fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], destname);
  1000. return -1;
  1001. }
  1002. // do this check here, because one error message is enough (not for every game)
  1003. if (UCON64_ISSET (ucon64.region))
  1004. switch (ucon64.region)
  1005. {
  1006. case 0: // NTSC/Japan
  1007. case 1: // NTSC/U.S.A.
  1008. case 2: // PAL
  1009. case 256:
  1010. break;
  1011. default:
  1012. printf ("WARNING: Invalid region code specified, using values games expect\n");
  1013. }
  1014. printf ("Creating multi-game file for MD-PRO: %s\n", destname);
  1015. file_no = 0;
  1016. for (n = 1; n < n_files; n++)
  1017. {
  1018. if (access (ucon64.argv[n], F_OK))
  1019. continue; // "file" does not exist (option)
  1020. stat (ucon64.argv[n], &fstate);
  1021. if (!S_ISREG (fstate.st_mode))
  1022. continue;
  1023. if (file_no == 32) // loader + 31 games
  1024. {
  1025. printf ("WARNING: A multi-game file can contain a maximum of 31 games. The other files\n"
  1026. " are ignored.\n");
  1027. break;
  1028. }
  1029. ucon64.console = UCON64_UNKNOWN;
  1030. ucon64.rom = ucon64.argv[n];
  1031. ucon64.file_size = fsizeof (ucon64.rom);
  1032. // DON'T use fstate.st_size, because file could be compressed
  1033. ucon64.rominfo->buheader_len = UCON64_ISSET (ucon64.buheader_len) ?
  1034. ucon64.buheader_len : 0;
  1035. ucon64.rominfo->interleaved = UCON64_ISSET (ucon64.interleaved) ?
  1036. ucon64.interleaved : 0;
  1037. ucon64.do_not_calc_crc = 1;
  1038. if (genesis_init (ucon64.rominfo) != 0)
  1039. printf ("WARNING: %s does not appear to be a Genesis ROM\n", ucon64.rom);
  1040. /*
  1041. NOTE: This is NOT the place to mess with ucon64.console. When this
  1042. function is entered ucon64.console must have been UCON64_GEN. We
  1043. modify ucon64.console temporarily only to be able to help detect
  1044. problems with incorrect files.
  1045. */
  1046. if (UCON64_ISSET (ucon64.region))
  1047. switch (ucon64.region)
  1048. {
  1049. case 0: // NTSC/Japan
  1050. genesis_tv_standard = 0;
  1051. genesis_japanese = 1;
  1052. break;
  1053. case 1: // NTSC/U.S.A.
  1054. genesis_tv_standard = 0;
  1055. genesis_japanese = 0;
  1056. break;
  1057. case 2: // PAL
  1058. genesis_tv_standard = 1;
  1059. genesis_japanese = 0;
  1060. break;
  1061. case 256:
  1062. // Do nothing. Use whatever values we found for genesis_tv_standard and
  1063. // genesis_japanese.
  1064. break;
  1065. // no default case, because we already checked value of ucon64.region
  1066. }
  1067. if ((srcfile = fopen (ucon64.rom, "rb")) == NULL)
  1068. {
  1069. fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], ucon64.rom);
  1070. continue;
  1071. }
  1072. if (ucon64.rominfo->buheader_len)
  1073. fseek (srcfile, ucon64.rominfo->buheader_len, SEEK_SET);
  1074. if (file_no == 0)
  1075. {
  1076. printf ("Loader: %s\n", ucon64.rom);
  1077. if (ucon64.file_size - ucon64.rominfo->buheader_len != MBIT)
  1078. printf ("WARNING: Are you sure %s is a loader binary?\n", ucon64.rom);
  1079. }
  1080. else
  1081. {
  1082. printf ("ROM%d: %s\n", file_no, ucon64.rom);
  1083. write_game_table_entry (destfile, file_no, ucon64.rominfo, totalsize);
  1084. fseek (destfile, totalsize, SEEK_SET); // restore file pointer
  1085. }
  1086. file_no++;
  1087. done = 0;
  1088. byteswritten = 0; // # of bytes written per file
  1089. while (!done)
  1090. {
  1091. if (ucon64.rominfo->interleaved == 2)
  1092. bytestowrite = fread_mgd (buffer, 1, BUFSIZE, srcfile);
  1093. else
  1094. {
  1095. bytestowrite = fread (buffer, 1, BUFSIZE, srcfile);
  1096. if (ucon64.rominfo->interleaved)
  1097. smd_deinterleave (buffer, BUFSIZE);
  1098. // yes, BUFSIZE. bytestowrite might not be n * 16 kB
  1099. }
  1100. if (totalsize + bytestowrite > truncate_size)
  1101. {
  1102. bytestowrite = truncate_size - totalsize;
  1103. done = 1;
  1104. truncated = 1;
  1105. printf ("Output file is %d Mbit, truncating %s, skipping %d bytes\n",
  1106. truncate_size / MBIT, ucon64.rom, ucon64.file_size -
  1107. ucon64.rominfo->buheader_len - (byteswritten + bytestowrite));
  1108. }
  1109. totalsize += bytestowrite;
  1110. if (bytestowrite == 0)
  1111. done = 1;
  1112. fwrite (buffer, 1, bytestowrite, destfile);
  1113. byteswritten += bytestowrite;
  1114. }
  1115. fclose (srcfile);
  1116. if (truncated)
  1117. break;
  1118. // games have to be aligned to (start at) a 2 Mbit boundary
  1119. paddedsize = (totalsize + 2 * MBIT - 1) & ~(2 * MBIT - 1);
  1120. // printf ("paddedsize: %d (%f); totalsize: %d (%f)\n",
  1121. // paddedsize, paddedsize / (1.0 * MBIT), totalsize, totalsize / (1.0 * MBIT));
  1122. if (paddedsize > totalsize)
  1123. {
  1124. // I (dbjh) don't think it is really necessary to pad to the truncate
  1125. // size, but it won't hurt
  1126. if (paddedsize > truncate_size)
  1127. {
  1128. truncated = 1; // not *really* truncated
  1129. paddedsize = truncate_size;
  1130. }
  1131. memset (buffer, 0, BUFSIZE);
  1132. while (totalsize < paddedsize)
  1133. {
  1134. bytestowrite = paddedsize - totalsize > BUFSIZE ?
  1135. BUFSIZE : paddedsize - totalsize;
  1136. fwrite (buffer, 1, bytestowrite, destfile);
  1137. totalsize += bytestowrite;
  1138. }
  1139. }
  1140. if (truncated)
  1141. break;
  1142. }
  1143. // fill the next game table entry
  1144. fseek (destfile, 0x8000 + (file_no - 1) * 0x20, SEEK_SET);
  1145. fputc (0, destfile); // indicate no next game
  1146. fclose (destfile);
  1147. ucon64.console = UCON64_GEN;
  1148. ucon64.do_not_calc_crc = org_do_not_calc_crc;
  1149. return 0;
  1150. }
  1151. static int
  1152. genesis_testinterleaved (st_rominfo_t *rominfo)
  1153. {
  1154. unsigned char buf[16384] = { 0 };
  1155. ucon64_fread (buf, rominfo->buheader_len, 8192 + (GENESIS_HEADER_START + 4) / 2, ucon64.rom);
  1156. if (!memcmp (buf + GENESIS_HEADER_START, "SEGA", 4))
  1157. return 0;
  1158. smd_deinterleave (buf, 16384);
  1159. if (!memcmp (buf + GENESIS_HEADER_START, "SEGA", 4))
  1160. return 1;
  1161. q_fread_mgd (buf, rominfo->buheader_len + GENESIS_HEADER_START, 4, ucon64.rom);
  1162. if (!memcmp (buf, "SEGA", 4))
  1163. return 2;
  1164. return 0; // unknown, act as if it's BIN
  1165. }
  1166. int
  1167. genesis_init (st_rominfo_t *rominfo)
  1168. {
  1169. int result = -1, value = 0, x, y;
  1170. unsigned char *rom_buffer = NULL, buf[MAXBUFSIZE], name[GENESIS_NAME_LEN + 1],
  1171. smd_header_split;
  1172. static char maker[9], country[200]; // 200 characters should be enough for 5 country names
  1173. static const char *genesis_maker[0x100] =
  1174. {
  1175. NULL, "Accolade/Infogrames", "Virgin Games", "Parker Brothers", "Westone",
  1176. NULL, NULL, NULL, NULL, "Westone",
  1177. "Takara", "Taito/Accolade", "Capcom", "Data East", "Namco/Tengen",
  1178. "Sunsoft", "Bandai", "Dempa", "Technosoft", "Technosoft",
  1179. "Asmik", NULL, "Extreme/Micronet", "Vic Tokai", "American Sammy",
  1180. "NCS", "Sigma Enterprises", "Toho", NULL, "Kyugo",
  1181. NULL, NULL, "Wolfteam", "Kaneko", NULL,
  1182. "Toaplan", "Tecmo", NULL, NULL, NULL,
  1183. "Toaplan", "Unipac", "UFL Company Ltd.", "Human", NULL,
  1184. "Game Arts", "Hot-B", "Sage's Creation", "Tengen/Time Warner",
  1185. "Renovation/Telenet",
  1186. "Electronic Arts", NULL, NULL, NULL, NULL,
  1187. "Psygnosis", "Razorsoft", NULL, "Mentrix", NULL,
  1188. "JVC/Victor Musical Industries", NULL, NULL, NULL, "IGS Corp.",
  1189. NULL, NULL, "CRI/Home Data", "Arena", "Virgin Games",
  1190. NULL, "Nichibutsu", NULL, "Soft Vision", "Palsoft",
  1191. NULL, "KOEI", NULL, NULL, "U.S. Gold",
  1192. NULL, "Acclaim/Flying Edge", NULL, "Gametek", NULL,
  1193. NULL, "Absolute", "Mindscape", "Domark", "Parker Brothers",
  1194. NULL, NULL, NULL, "Sony Imagesoft", "Sony Imagesoft",
  1195. "Konami", NULL, "Tradewest/Williams", NULL, "Codemasters",
  1196. "T*HQ Software", "TecMagik", NULL, "Takara", NULL,
  1197. NULL, NULL, NULL, NULL, NULL,
  1198. NULL, NULL, "Hi Tech Entertainment/Designer Software", "Psygnosis", NULL,
  1199. NULL, NULL, NULL, NULL, "Accolade",
  1200. "Code Masters", NULL, NULL, NULL, "Spectrum HoloByte",
  1201. "Interplay", NULL, NULL, NULL, NULL,
  1202. "Activision", NULL, "Shiny & Playmates", NULL, NULL,
  1203. NULL, NULL, NULL, NULL, "Viacom International",
  1204. NULL, NULL, NULL, NULL, "Atlus",
  1205. NULL, NULL, NULL, NULL, NULL,
  1206. NULL, "Infogrames", NULL, NULL, NULL,
  1207. NULL, NULL, NULL, NULL, NULL,
  1208. NULL, "Fox Interactive", NULL, NULL, NULL,
  1209. NULL, NULL, NULL, NULL, NULL,
  1210. NULL, NULL, NULL, NULL, NULL,
  1211. NULL, NULL, NULL, NULL, NULL,
  1212. NULL, NULL, NULL, NULL, NULL,
  1213. NULL, NULL, NULL, NULL, NULL,
  1214. NULL, NULL, NULL, NULL, NULL,
  1215. NULL, NULL, NULL, NULL, NULL,
  1216. NULL, NULL, NULL, NULL, NULL,
  1217. NULL, NULL, NULL, NULL, NULL,
  1218. NULL, NULL, NULL, NULL, NULL,
  1219. NULL, NULL, NULL, NULL, "Psygnosis",
  1220. NULL, NULL, NULL, NULL, NULL,
  1221. NULL, NULL, NULL, NULL, NULL,
  1222. NULL, NULL, NULL, NULL, NULL,
  1223. NULL, NULL, NULL, NULL, "Disney Interactive",
  1224. NULL, NULL, NULL, NULL, NULL,
  1225. NULL, NULL, NULL, NULL, NULL,
  1226. NULL, NULL, NULL, NULL, NULL,
  1227. NULL
  1228. },
  1229. #define GENESIS_COUNTRY_MAX 0x57
  1230. *genesis_country[GENESIS_COUNTRY_MAX] =
  1231. {
  1232. NULL, NULL, NULL, NULL, NULL,
  1233. NULL, NULL, NULL, NULL, NULL,
  1234. NULL, NULL, NULL, NULL, NULL,
  1235. NULL, NULL, NULL, NULL, NULL,
  1236. NULL, NULL, NULL, NULL, NULL,
  1237. NULL, NULL, NULL, NULL, NULL,
  1238. NULL, NULL, NULL, NULL, NULL,
  1239. NULL, NULL, NULL, NULL, NULL,
  1240. NULL, NULL, NULL, NULL, NULL,
  1241. NULL, NULL, NULL, NULL, NULL,
  1242. NULL, NULL, "Brazil", NULL, NULL, // Brazil NTSC
  1243. NULL, "Hong Kong", NULL, NULL, NULL,
  1244. NULL, NULL, NULL, NULL, NULL,
  1245. "Asia", "Brazil", NULL, NULL, "Europe", // Brazil PAL
  1246. "France", NULL, NULL, NULL, "Japan",
  1247. NULL, NULL, NULL, NULL, NULL,
  1248. NULL, NULL, NULL, NULL, NULL,
  1249. "U.S.A.", NULL
  1250. },
  1251. #define GENESIS_IO_MAX 0x58
  1252. *genesis_io[GENESIS_IO_MAX] =
  1253. {
  1254. NULL, NULL, NULL, NULL, NULL,
  1255. NULL, NULL, NULL, NULL, NULL,
  1256. NULL, NULL, NULL, NULL, NULL,
  1257. NULL, NULL, NULL, NULL, NULL,
  1258. NULL, NULL, NULL, NULL, NULL,
  1259. NULL, NULL, NULL, NULL, NULL,
  1260. NULL, NULL, NULL, NULL, NULL,
  1261. NULL, NULL, NULL, NULL, NULL,
  1262. NULL, NULL, NULL, NULL, NULL,
  1263. NULL, NULL, NULL, "Joystick for MS", NULL,
  1264. NULL, NULL, "Team Play", NULL, "6 Button Pad",
  1265. NULL, NULL, NULL, NULL, NULL,
  1266. NULL, NULL, NULL, NULL, NULL,
  1267. NULL, "Control Ball", "CD-ROM", NULL, NULL,
  1268. "Floppy Disk Drive", NULL, NULL, NULL, "3 Button Pad",
  1269. "Keyboard", "Activator", "Mega Mouse", NULL, NULL,
  1270. "Printer", NULL, "Serial RS232C", NULL, "Tablet",
  1271. NULL, "Paddle Controller", NULL
  1272. };
  1273. ucon64_fread (buf, 0, 11, ucon64.rom);
  1274. smd_header_split = buf[2];
  1275. if (buf[8] == 0xaa && buf[9] == 0xbb && buf[10] == 7)
  1276. {
  1277. rominfo->buheader_len = SMD_HEADER_LEN;
  1278. strcpy (rominfo->name, "Name: N/A");
  1279. rominfo->console_usage = NULL;
  1280. rominfo->copier_usage = smd_usage[0].help;
  1281. rominfo->maker = "Publisher: You?";
  1282. rominfo->country = "Country: Your country?";
  1283. rominfo->has_internal_crc = 0;
  1284. strcat (rominfo->misc, "Type: Super Magic Drive SRAM file\n");
  1285. ucon64.split = 0; // SRAM files are never split
  1286. type = SMD;
  1287. return 0; // rest is nonsense for SRAM file
  1288. }
  1289. if (buf[8] == 0xaa && buf[9] == 0xbb && buf[10] == 6)
  1290. {
  1291. type = SMD;
  1292. rominfo->buheader_len = SMD_HEADER_LEN;
  1293. }
  1294. if (UCON64_ISSET (ucon64.buheader_len)) // -hd, -nhd or -hdn option was specified
  1295. rominfo->buheader_len = ucon64.buheader_len;
  1296. rominfo->interleaved = UCON64_ISSET (ucon64.interleaved) ?
  1297. ucon64.interleaved : genesis_testinterleaved (rominfo);
  1298. if (rominfo->interleaved == 0)
  1299. type = BIN;
  1300. else if (rominfo->interleaved == 1)
  1301. type = SMD;
  1302. else if (rominfo->interleaved == 2)
  1303. type = MGD_GEN;
  1304. if (type == SMD)
  1305. {
  1306. genesis_rom_size = ((ucon64.file_size - rominfo->buheader_len) / 16384) * 16384;
  1307. if (genesis_rom_size != ucon64.file_size - rominfo->buheader_len)
  1308. rominfo->data_size = genesis_rom_size;
  1309. memset (buf, 0, 16384);
  1310. ucon64_fread (buf, rominfo->buheader_len,
  1311. 8192 + (GENESIS_HEADER_START + GENESIS_HEADER_LEN) / 2, ucon64.rom);
  1312. smd_deinterleave (buf, 16384); // buf will contain the deinterleaved data
  1313. memcpy (&genesis_header, buf + GENESIS_HEADER_START, GENESIS_HEADER_LEN);
  1314. }
  1315. else if (type == MGD_GEN)
  1316. {
  1317. // We use rominfo->buheader_len to make it user definable. Normally it
  1318. // should be 0 for MGD_GEN.
  1319. genesis_rom_size = ucon64.file_size - rominfo->buheader_len;
  1320. q_fread_mgd (&genesis_header, rominfo->buheader_len + GENESIS_HEADER_START,
  1321. GENESIS_HEADER_LEN, ucon64.rom);
  1322. }
  1323. else // type == BIN
  1324. {
  1325. // We use rominfo->buheader_len to make it user definable.
  1326. genesis_rom_size = ucon64.file_size - rominfo->buheader_len;
  1327. ucon64_fread (&genesis_header, rominfo->buheader_len + GENESIS_HEADER_START,
  1328. GENESIS_HEADER_LEN, ucon64.rom);
  1329. }
  1330. if (!UCON64_ISSET (ucon64.split))
  1331. {
  1332. if (type == SMD)
  1333. {
  1334. // This code does not work for the last part of a file
  1335. int split = 0;
  1336. if (smd_header_split & 0x40)
  1337. split = ucon64_testsplit (ucon64.rom);
  1338. ucon64.split = split; // force displayed info to be correct
  1339. } // if not split (see ucon64.c)
  1340. else if (type == BIN)
  1341. {
  1342. // This code isn't fool-proof, but it's not that important
  1343. const char *ptr = get_suffix (ucon64.rom);
  1344. if (strlen (ptr) == 4 && ptr[1] == 'r' &&
  1345. ptr[2] >= '0' && ptr[2] <= '9' && ptr[3] >= '0' && ptr[3] <= '9')
  1346. {
  1347. int n_parts = 0;
  1348. char fname[FILENAME_MAX], *digits;
  1349. strcpy (fname, ucon64.rom);
  1350. digits = fname + strlen (fname) - 2;
  1351. do
  1352. {
  1353. sprintf (digits, "%02d", n_parts);
  1354. if (access (fname, F_OK) == 0)
  1355. n_parts++;
  1356. else
  1357. break;
  1358. }
  1359. while (n_parts < 100);
  1360. if (n_parts)
  1361. ucon64.split = n_parts;
  1362. }
  1363. }
  1364. }
  1365. if (!memcmp (&OFFSET (genesis_header, 0), "SEGA", 4) ||
  1366. ucon64.console == UCON64_GEN)
  1367. result = 0;
  1368. else
  1369. result = -1;
  1370. rominfo->header_start = GENESIS_HEADER_START;
  1371. rominfo->header_len = GENESIS_HEADER_LEN;
  1372. rominfo->header = &genesis_header;
  1373. // internal ROM name
  1374. memcpy (rominfo->name, &OFFSET (genesis_header, 80), GENESIS_NAME_LEN);
  1375. rominfo->name[GENESIS_NAME_LEN] = 0;
  1376. // ROM maker
  1377. memcpy (maker, &OFFSET (genesis_header, 16), 8);
  1378. if (maker[3] == 'T' && maker[4] == '-')
  1379. {
  1380. sscanf (&maker[5], "%03d", &value);
  1381. rominfo->maker = NULL_TO_UNKNOWN_S (genesis_maker[value & 0xff]);
  1382. }
  1383. else
  1384. {
  1385. // Don't use genesis_maker here. If it would be corrected/updated an
  1386. // incorrect publisher name would be displayed.
  1387. rominfo->maker =
  1388. (!strncmp (maker, "(C)ACLD", 7)) ? "Ballistic" :
  1389. (!strncmp (maker, "(C)AESI", 7)) ? "ASCII" :
  1390. (!strncmp (maker, "(C)ASCI", 7)) ? "ASCII" :
  1391. (!strncmp (maker, "(C)KANEKO", 9)) ? "Kaneko" :
  1392. (!strncmp (maker, "(C)PPP", 6)) ? "Gametek" :
  1393. (!strncmp (maker, "(C)RSI", 6)) ? "Razorsoft" : // or is it "(C)1RSI"?
  1394. (!strncmp (maker, "(C)SEGA", 7)) ? "Sega" :
  1395. (!strncmp (maker, "(C)TREC", 7)) ? "Treco" :
  1396. (!strncmp (maker, "(C)VRGN", 7)) ? "Virgin Games" :
  1397. (!strncmp (maker, "(C)WADN", 7)) ? "Parker Brothers" :
  1398. (!strncmp (maker, "(C)WSTN", 7)) ? "Westone" : NULL;
  1399. if (!rominfo->maker)
  1400. {
  1401. maker[8] = 0;
  1402. rominfo->maker = maker;
  1403. }
  1404. }
  1405. genesis_tv_standard = 1; // default to PAL; NTSC has higher precedence
  1406. genesis_japanese = 0;
  1407. country[0] = 0;
  1408. // ROM country
  1409. for (x = 0; x < 5; x++)
  1410. {
  1411. int country_code = OFFSET (genesis_header, 240 + x);
  1412. if ((x > 0 && country_code == 0) || country_code == ' ')
  1413. continue;
  1414. if (country_code == 'J')
  1415. genesis_japanese = 1;
  1416. if (genesis_japanese || country_code == 'U' || country_code == '4')
  1417. genesis_tv_standard = 0; // Japan, the U.S.A. and Brazil ('4') use NTSC
  1418. strcat (country, NULL_TO_UNKNOWN_S
  1419. (genesis_country[MIN (country_code, GENESIS_COUNTRY_MAX - 1)]));
  1420. strcat (country, ", ");
  1421. }
  1422. x = strlen (country);
  1423. if (x >= 2 && country[x - 2] == ',' && country[x - 1] == ' ')
  1424. country[x - 2] = 0;
  1425. rominfo->country = country;
  1426. // misc stuff
  1427. memcpy (name, &OFFSET (genesis_header, 32), GENESIS_NAME_LEN);
  1428. name[GENESIS_NAME_LEN] = 0;
  1429. sprintf ((char *) buf, "Japanese game name: %s\n", name);
  1430. strcat (rominfo->misc, (char *) buf);
  1431. sprintf ((char *) buf, "Date: %.8s\n", &OFFSET (genesis_header, 24));
  1432. strcat (rominfo->misc, (char *) buf);
  1433. x = (OFFSET (genesis_header, 160) << 24) +
  1434. (OFFSET (genesis_header, 161) << 16) +
  1435. (OFFSET (genesis_header, 162) << 8) +
  1436. OFFSET (genesis_header, 163);
  1437. y = (OFFSET (genesis_header, 164) << 24) +
  1438. (OFFSET (genesis_header, 165) << 16) +
  1439. (OFFSET (genesis_header, 166) << 8) +
  1440. OFFSET (genesis_header, 167);
  1441. sprintf ((char *) buf, "Internal size: %.4f Mb\n", (float) (y - x + 1) / MBIT);
  1442. strcat (rominfo->misc, (char *) buf);
  1443. sprintf ((char *) buf, "ROM start: %08x\n", x);
  1444. strcat (rominfo->misc, (char *) buf);
  1445. sprintf ((char *) buf, "ROM end: %08x\n", y);
  1446. strcat (rominfo->misc, (char *) buf);
  1447. genesis_has_ram = OFFSET (genesis_header, 176) == 'R' &&
  1448. OFFSET (genesis_header, 177) == 'A';
  1449. if (genesis_has_ram)
  1450. {
  1451. x = (OFFSET (genesis_header, 180) << 24) +
  1452. (OFFSET (genesis_header, 181) << 16) +
  1453. (OFFSET (genesis_header, 182) << 8) +
  1454. OFFSET (genesis_header, 183);
  1455. y = (OFFSET (genesis_header, 184) << 24) +
  1456. (OFFSET (genesis_header, 185) << 16) +
  1457. (OFFSET (genesis_header, 186) << 8) +
  1458. OFFSET (genesis_header, 187);
  1459. sprintf ((char *) buf, "Cartridge RAM: Yes, %d kBytes (%s)\n",
  1460. (y - x + 1) >> 10,
  1461. OFFSET (genesis_header, 178) & 0x40 ? "backup" : "non-backup");
  1462. strcat (rominfo->misc, (char *) buf);
  1463. sprintf ((char *) buf, "RAM start: %08x\n", x);
  1464. strcat (rominfo->misc, (char *) buf);
  1465. sprintf ((char *) buf, "RAM end: %08x\n", y);
  1466. strcat (rominfo->misc, (char *) buf);
  1467. }
  1468. else
  1469. strcat (rominfo->misc, "Cartridge RAM: No\n");
  1470. /*
  1471. Only checking for 'G' seems to give better results than checking for "GM".
  1472. "Officially" "GM" indicates it's a game and "Al" that it's educational.
  1473. */
  1474. sprintf ((char *) buf, "Product type: %s\n",
  1475. (OFFSET (genesis_header, 128) == 'G') ? "Game" : "Educational");
  1476. strcat (rominfo->misc, (char *) buf);
  1477. sprintf ((char *) buf, "I/O device(s): %s",
  1478. NULL_TO_UNKNOWN_S (genesis_io[MIN ((int) OFFSET (genesis_header, 144), GENESIS_IO_MAX - 1)]));
  1479. for (x = 0; x < 3; x++)
  1480. {
  1481. const char *io_device = genesis_io[MIN (OFFSET (genesis_header, 145 + x), GENESIS_IO_MAX - 1)];
  1482. if (!io_device)
  1483. continue;
  1484. strcat ((char *) buf, ", ");
  1485. strcat ((char *) buf, io_device);
  1486. }
  1487. strcat ((char *) buf, "\n");
  1488. strcat (rominfo->misc, (char *) buf);
  1489. sprintf ((char *) buf, "Modem data: %.10s\n", &OFFSET (genesis_header, 188));
  1490. strcat (rominfo->misc, (char *) buf);
  1491. sprintf ((char *) buf, "Memo: %.40s\n", &OFFSET (genesis_header, 200));
  1492. strcat (rominfo->misc, (char *) buf);
  1493. sprintf ((char *) buf, "Product code: %.8s\n", &OFFSET (genesis_header, 131));
  1494. strcat (rominfo->misc, (char *) buf);
  1495. sprintf ((char *) buf, "Version: 1.%c%c", OFFSET (genesis_header, 140), OFFSET (genesis_header, 141));
  1496. strcat (rominfo->misc, (char *) buf);
  1497. // internal ROM crc
  1498. if (!UCON64_ISSET (ucon64.do_not_calc_crc) && result == 0)
  1499. {
  1500. if ((rom_buffer = load_rom (rominfo, ucon64.rom, rom_buffer)) == NULL)
  1501. return -1;
  1502. rominfo->has_internal_crc = 1;
  1503. rominfo->internal_crc_len = 2;
  1504. rominfo->current_internal_crc = genesis_chksum (rom_buffer);
  1505. rominfo->internal_crc = OFFSET (genesis_header, 143); // low byte of checksum
  1506. rominfo->internal_crc += (OFFSET (genesis_header, 142)) << 8; // high byte of checksum
  1507. rominfo->internal_crc2[0] = 0;
  1508. free (rom_buffer);
  1509. }
  1510. rominfo->console_usage = genesis_usage[0].help;
  1511. if (type == SMD)
  1512. rominfo->copier_usage = smd_usage[0].help;
  1513. else if (type == MGD_GEN)
  1514. rominfo->copier_usage = mgd_usage[0].help;
  1515. else // type == BIN
  1516. rominfo->copier_usage = bin_usage[0].help;
  1517. return result;
  1518. }
  1519. int
  1520. genesis_chksum (unsigned char *rom_buffer)
  1521. {
  1522. int i, len = genesis_rom_size - 2;
  1523. unsigned short checksum = 0;
  1524. for (i = 512; i <= len; i += 2)
  1525. checksum += (rom_buffer[i] << 8) + (rom_buffer[i + 1]);
  1526. return checksum;
  1527. }