cmc.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. /*
  2. cmc.c - Cyan's Megadrive ROM copier support for uCON64
  3. Copyright (c) 1999 - 2004 Cyan Helkaraxe
  4. Special thanks to dbjh for helping with the uCON64 integration
  5. of this software, and providing the wrapping code.
  6. CMC version: 2.5
  7. For hardware version 1.x
  8. Copies Sega Megadrive/Genesis cartridges into .BIN format ROM files.
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. /*
  22. Additional information:
  23. This software is distributed in accordance with the GNU General
  24. Public License. The author of the hardware design/documentation and
  25. software, Cyan Helkaraxe, retains the copyright over the 'cmc' code
  26. ('software'), the hardware design and construction documentation itself.
  27. Cyan grants you the rights of the GNU General Public License over
  28. the software, as stated above. The copyright does not affect your
  29. rights in relation to the 'cmc' code under the GNU General Public
  30. License in any way.
  31. Cyan Helkaraxe does NOT grant you any rights relating to the hardware
  32. design/documentation, over and above the right to build the device for
  33. personal, not-for-profit use. Likewise, the same applies to the ROM
  34. copier construction documentation, available at
  35. http://www.emulationzone.org/projects/cyan/docs/ for not-for-profit
  36. personal use.
  37. Obviously, feel free to make changes to this software, but if you do so,
  38. *please* clearly mark the fact it is modified, to avoid confusion.
  39. A define is provided below this commented area, which should be edited
  40. as described. This is to inform users which version of the code they are
  41. using at runtime, and if they encounter a problem, it makes it far easier
  42. for me to help debug it. I have no evil nefarious intentions. =P
  43. Obviously, your changes must adhere to the GNU GPL, and please keep the
  44. copyright, Cyan's name, e-mail and web site address in the comments
  45. somewhere.
  46. If you wish to do anything with the hardware design or the documentation
  47. that goes beyond personal use, get in touch with Cyan first;
  48. cyan@emulationzone.org
  49. Disclaimer / Warranty:
  50. This is to emphasise, not replace, any warranty information provided in
  51. the GNU GPL or uCON64.
  52. There is no warranty whatsoever, for either the software or accompanying
  53. hardware/design/documentation. This software is provided free of charge,
  54. AS-IS, in the hope that it may be useful.
  55. Use it at your own risk. The author does not make any guarantee that you
  56. will be able to use this software or accompanying
  57. hardware/design/documentation, or that it will perform smoothly. There is
  58. a possibility that damage or loss (including but not limited to financial
  59. loss, hardware or software damage, data corruption, privacy violation,
  60. or personal injury, suffering, legal action, imprisonment or death) may
  61. arise through the use of this software or the accompanying
  62. hardware/design/documentation, in addition to many other possible outcomes.
  63. You take sole responsibility for any outcomes; by using this software or
  64. accompanying hardware/design/ documentation, you agree that the author will
  65. not be held responsible for anything that may occur. If your jurisdiction
  66. does not allow the author to be isolated from responsibility, then you
  67. must *not* use this software or accompanying hardware/design/documentation.
  68. The author does not condone software piracy. You may not use this software
  69. to engage in piracy. The author is not responsible for anything you choose
  70. to use this software for, although the author strongly recommends that you
  71. use the software for the purpose for which it was intended to be used --
  72. primarily as an educational tool, and secondarily to make backup copies of
  73. your expensive/rare game cartridges, or a similarly harmless and legal
  74. purpose.
  75. Note that although the author isn't aware of any patent violations caused
  76. by this software/hardware/design/documentation, it is possible that
  77. there may be patents covering parts of this device. It is your
  78. responsibility to check this before building or using the hardware or
  79. software, and Cyan may not be held responsible in the event of an
  80. infringement.
  81. That being said, if you do encounter any problems with the hardware or
  82. software, then feel free to get in touch with the author; use the subject
  83. line 'ROM Copier Technical Support'. No promises or guarantees are made,
  84. however.
  85. Also note that the author is not affiliated with anyone involved with uCON64;
  86. therefore, only correspondence relating to this particular file (the 'cmc'
  87. code) or the accompanying hardware design should be directed to Cyan.
  88. If you have more general uCON64 questions, Cyan is *not* the person to ask.
  89. Likewise, the terms "the author" and "software" in this file (cmc.c, and
  90. additionally cmc.h), along with similar terms, apply only to Cyan, and the
  91. CMC software you see in this file. The disclaimer above, for example, relates
  92. exclusively to the CMC code.
  93. All trademarks, indicated or otherwise, are the property of their
  94. respective owners.
  95. */
  96. /*
  97. NOTE!
  98. Please edit the following line, and remove the word "original" from it
  99. if you have made any modifications to this file. This reduces user
  100. confusion.
  101. */
  102. #define INTRO_TEXT "Cyan's Megadrive Copier (c) 1999-2004 Cyan Helkaraxe\n" \
  103. "Software version 2.5, designed for hardware version 1.x\n\n"
  104. #ifdef HAVE_CONFIG_H
  105. #include "config.h"
  106. #endif
  107. #include <stdlib.h>
  108. #include <string.h>
  109. #include "misc/archive.h"
  110. #include "misc/bswap.h"
  111. #include "misc/misc.h"
  112. #include "misc/parallel.h"
  113. #include "misc/term.h"
  114. #include "ucon64.h"
  115. #include "ucon64_misc.h"
  116. #include "backup/cmc.h"
  117. #ifdef USE_PARALLEL
  118. #define RSLO 0x40 // reset line 1 d7
  119. #define RSHI 0x01 // reset line 2 d0
  120. #define CNLO 0x10 // counter line 1 d4
  121. #define CNHI 0x04 // counter line 2 d2
  122. #define INLO 0x40 // input 1 ack (int disabled)
  123. #define INHI 0x10 // input 2 selectin
  124. #define MBYTE (1024 * 1024)
  125. #define DEFAULT_SPEED 3
  126. #ifdef _MSC_VER
  127. // Visual C++ doesn't allow inline in C source code
  128. #define inline __inline
  129. #endif
  130. /************************
  131. * Internal functions *
  132. ************************/
  133. static inline void
  134. cyan_write_copier (unsigned char data, unsigned short parport)
  135. // write a value to the data register of the parallel port
  136. {
  137. outportb (parport + PARPORT_DATA, data);
  138. }
  139. static inline unsigned char
  140. cyan_read_copier (unsigned short parport)
  141. // read a value from the status register of the parallel port
  142. {
  143. return inportb (parport + PARPORT_STATUS);
  144. }
  145. static inline unsigned char
  146. cyan_verify_copier (unsigned short parport)
  147. // read a value back from the data register for verification
  148. {
  149. return inportb (parport + PARPORT_DATA);
  150. }
  151. /**** non-hardware, non-accessing ****/
  152. static unsigned long
  153. cyan_calculate_rom_size (unsigned char *buffer, int test_mode)
  154. /*
  155. Calculate the ROM size, by looking at the ROM size entry in the ROM 'header',
  156. and the overall structure.
  157. This function always returns a value rounded to a power of two between 128
  158. kbytes and 4 Mbytes. It also inspects the ROM for 0's or ffh's. If test_mode
  159. is 1 it causes an error on that condition, frees the buffer and exits.
  160. */
  161. {
  162. unsigned long i = 0x80000000, reported_size;
  163. // look at reported size
  164. reported_size = (buffer[0x1a4] << 24) +
  165. (buffer[0x1a5] << 16) +
  166. (buffer[0x1a6] << 8) +
  167. buffer[0x1a7] + 1;
  168. // cap
  169. // there is a minimum valid size for ROMs, according to some sources
  170. if (reported_size < MBIT)
  171. reported_size = MBIT;
  172. if (reported_size > 4 * MBYTE)
  173. reported_size = 4 * MBYTE;
  174. // round
  175. if (reported_size & (reported_size - 1))
  176. {
  177. while (!(reported_size & 0x80000000))
  178. {
  179. i >>= 1;
  180. reported_size = (reported_size << 1) | 1;
  181. }
  182. reported_size = i << 1;
  183. }
  184. // calculate real size
  185. for (i = 2 * MBYTE; i >= 65536; i >>= 1)
  186. if (memcmp (buffer, buffer + i, i))
  187. {
  188. i >>= 1;
  189. break;
  190. }
  191. i <<= 2;
  192. if (reported_size < i)
  193. reported_size = i; // pick the safest (largest) of the two
  194. if (i == MBIT)
  195. {
  196. for (i = 0; i < MBIT; i++)
  197. if ((buffer[i] != 0xff) && (buffer[i] != 0x00))
  198. break;
  199. if (i == MBIT)
  200. {
  201. FILE *output;
  202. if (test_mode)
  203. {
  204. output = stderr;
  205. fputs ("\nERROR: ", stderr);
  206. }
  207. else
  208. {
  209. output = stdout;
  210. fputs ("\nWARNING: ", stdout);
  211. }
  212. // "WARNING: "
  213. fputs ( "The ROM file appears to consist of nothing but 0x00 / 0xff values.\n"
  214. " This usually indicates a serious problem. Perhaps your parallel port\n"
  215. " isn't configured correctly, or there is some problem with the ROM\n"
  216. " copier. Is it getting power? Is a cartridge inserted? Is it properly\n"
  217. " attached to the PC?\n",
  218. output);
  219. if (test_mode)
  220. {
  221. free (buffer);
  222. exit (1);
  223. }
  224. }
  225. }
  226. return reported_size;
  227. }
  228. static int
  229. cyan_checksum_rom (unsigned char *buffer)
  230. // return 0 on success, -1 on failure
  231. {
  232. unsigned char *buffer2 = buffer;
  233. unsigned short reported_sum, running_sum = 0;
  234. reported_sum = (buffer2[0x18e] << 8) + buffer2[0x18f];
  235. buffer2 += ((buffer2[0x1a4] << 24) +
  236. (buffer2[0x1a5] << 16) +
  237. (buffer2[0x1a6] << 8) +
  238. (buffer2[0x1a7] & 0xfe)) + 2;
  239. if (buffer2 > buffer + 4 * MBYTE)
  240. buffer2 = buffer + 4 * MBYTE;
  241. buffer += 0x200;
  242. if (buffer2 < buffer + 2)
  243. return -1;
  244. while (buffer2 != buffer)
  245. {
  246. running_sum += *--buffer2;
  247. running_sum += (*--buffer2) << 8;
  248. }
  249. return (running_sum & 0xffff) != reported_sum ? -1 : 0;
  250. }
  251. static inline unsigned long
  252. cyan_get_address (unsigned long b)
  253. // return the true address (word -- 0 - 2 M) based on word input
  254. {
  255. return ((b & 0x000800) >> 11) | // bit 0
  256. ((b & 0x002000) >> 12) | // bit 1
  257. ((b & 0x004000) >> 12) | // bit 2
  258. ((b & 0x000020) >> 2) | // bit 3
  259. ((b & 0x100000) >> 16) | // bit 4
  260. ((b & 0x020000) >> 12) | // bit 5
  261. ((b & 0x000400) >> 4) | // bit 6
  262. ((b & 0x000001) << 7) | // bit 7
  263. ((b & 0x000002) << 7) | // bit 8
  264. ((b & 0x000010) << 5) | // bit 9
  265. ((b & 0x000040) << 4) | // bit 10
  266. ((b & 0x040000) >> 7) | // bit 11
  267. ((b & 0x080000) >> 7) | // bit 12
  268. ((b & 0x000080) << 6) | // bit 13
  269. ((b & 0x008000) >> 1) | // bit 14
  270. ((b & 0x010000) >> 1) | // bit 15
  271. ((b & 0x001000) << 4) | // bit 16
  272. ((b & 0x000004) << 15) | // bit 17
  273. ((b & 0x000008) << 15) | // bit 18
  274. ((b & 0x000200) << 10) | // bit 19
  275. ((b & 0x000100) << 12); // bit 20
  276. }
  277. /**** non-hardware, indirectly accessing ****/
  278. static inline void
  279. cyan_delay (int speed, unsigned short parport)
  280. // Delays a certain amount of time depending on speed selected. 0=long delay,
  281. // used for reset and hi counter.
  282. {
  283. int i, scritch = 0;
  284. switch (speed)
  285. {
  286. case 0:
  287. for (i = 0; i < 128; i++)
  288. scritch += cyan_read_copier (parport);
  289. case 1: // falling through
  290. for (i = 0; i < 64; i++)
  291. scritch += cyan_read_copier (parport);
  292. case 2: // falling through
  293. for (i = 0; i < 12; i++)
  294. scritch += cyan_read_copier (parport);
  295. case 3: // falling through
  296. scritch += cyan_read_copier (parport);
  297. scritch += cyan_read_copier (parport);
  298. }
  299. }
  300. static void
  301. cyan_reset (unsigned short parport)
  302. // resets the copier
  303. {
  304. cyan_delay (0, parport);
  305. // zero all data outputs first, before going into SPP mode
  306. cyan_write_copier (0, parport);
  307. // reset the port to SPP, float all control lines high
  308. cyan_write_copier (0, parport + PARPORT_CONTROL);
  309. cyan_delay (0, parport);
  310. cyan_write_copier (RSLO | RSHI, parport); // both reset lines hi
  311. cyan_delay (0, parport);
  312. cyan_write_copier (0, parport); // both reset lines lo
  313. cyan_delay (0, parport);
  314. }
  315. static inline unsigned short
  316. cyan_get_word (int speed, unsigned short parport)
  317. // gets a byte pair from the ROM and return two bytes in big endian byte order
  318. {
  319. unsigned short value = 0;
  320. unsigned char tempz;
  321. cyan_write_copier (0, parport);
  322. cyan_delay (speed, parport);
  323. tempz = cyan_read_copier (parport);
  324. value |= tempz & INLO; // bit 6
  325. value |= (tempz & INHI) << 8; // bit 12
  326. cyan_write_copier (CNLO, parport);
  327. cyan_delay (speed, parport);
  328. tempz = cyan_read_copier (parport);
  329. value |= (tempz & INLO) >> 5; // bit 1
  330. value |= (tempz & INHI) << 9; // bit 13
  331. cyan_write_copier (0, parport);
  332. cyan_delay (speed, parport);
  333. tempz = cyan_read_copier (parport);
  334. value |= (tempz & INLO) << 3; // bit 9
  335. value |= (tempz & INHI) << 10; // bit 14
  336. cyan_write_copier (CNLO, parport);
  337. cyan_delay (speed, parport);
  338. tempz = cyan_read_copier (parport);
  339. value |= (tempz & INLO) >> 1; // bit 5
  340. value |= (tempz & INHI) << 11; // bit 15
  341. cyan_write_copier (0, parport);
  342. cyan_delay (speed, parport);
  343. tempz = cyan_read_copier (parport);
  344. value |= (tempz & INLO) >> 4; // bit 2
  345. value |= (tempz & INHI) << 4; // bit 8
  346. cyan_write_copier (CNLO, parport);
  347. cyan_delay (speed, parport);
  348. tempz = cyan_read_copier (parport);
  349. value |= (tempz & INLO) << 4; // bit 10
  350. value |= (tempz & INHI) >> 4; // bit 0
  351. cyan_write_copier (0, parport);
  352. cyan_delay (speed, parport);
  353. tempz = cyan_read_copier (parport);
  354. value |= (tempz & INLO) >> 2; // bit 4
  355. value |= (tempz & INHI) << 3; // bit 7
  356. cyan_write_copier (CNLO, parport);
  357. cyan_delay (speed, parport);
  358. tempz = cyan_read_copier (parport);
  359. value |= (tempz & INLO) >> 3; // bit 3
  360. value |= (tempz & INHI) << 7; // bit 11
  361. return me2be_16 (value);
  362. }
  363. static inline int
  364. check_exit (void)
  365. // check for user abort
  366. {
  367. int temp;
  368. if (ucon64.frontend)
  369. return 0;
  370. if (!kbhit ())
  371. return 0;
  372. temp = getch ();
  373. if (temp == 'q' || (temp == 27))
  374. return 1;
  375. return 0;
  376. }
  377. static unsigned char *
  378. cyan_read_rom (int speed, unsigned short parport, unsigned char *buffer)
  379. /*
  380. Read the ROM and return a pointer to a 4 MB area of memory containing all ROM
  381. data. Designed to be used from inside cyan_copy_rom(), although it can be
  382. called elsewhere if a raw (but decoded) dump is required.
  383. */
  384. {
  385. unsigned long q;
  386. time_t t;
  387. // allocate the dump area
  388. if (!buffer)
  389. if ((buffer = (unsigned char *) malloc (4 * MBYTE)) == NULL)
  390. {
  391. fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], 4 * MBYTE);
  392. exit (1);
  393. }
  394. cyan_reset (parport); // reset the copier
  395. t = time (NULL);
  396. // copy routine
  397. for (q = 0; q < 2 * MBYTE; ) // loop through all words
  398. {
  399. // get a (16-bit) word from the ROM
  400. ((unsigned short *) buffer)[cyan_get_address (q)] = cyan_get_word (speed, parport);
  401. // periodically update progress bar, without hammering ucon64_gauge()
  402. if (!(q & (0xfff >> (5 - speed))))
  403. {
  404. if (check_exit ())
  405. {
  406. free (buffer);
  407. puts ("\n"
  408. "Copy aborted.\n"
  409. "Don't forget to turn the ROM copier off and never insert or remove a cartridge\n"
  410. "with the power on");
  411. break;
  412. }
  413. ucon64_gauge (t, q * 2, 4 * MBYTE);
  414. }
  415. if (!(++q & 0x3ff)) // advance loop counter and carry to hi counter (11 bits)
  416. {
  417. cyan_delay (0, parport);
  418. cyan_write_copier (CNHI, parport);
  419. cyan_delay (0, parport);
  420. cyan_write_copier (0, parport);
  421. cyan_delay (0, parport);
  422. }
  423. }
  424. // make sure it's left in a state where it's safe to remove the cart
  425. cyan_reset (parport);
  426. if (q != 2 * MBYTE)
  427. return NULL;
  428. ucon64_gauge (t, q * 2, 4 * MBYTE); // make the progress bar reach 100%
  429. return buffer;
  430. }
  431. static void
  432. cyan_test_parport (unsigned short parport)
  433. // Test the parallel port to see if it appears to be functioning correctly, and
  434. // terminate if there's an error.
  435. {
  436. unsigned short temp;
  437. cyan_reset (parport);
  438. fputs ("Basic parallel port test: ", stdout);
  439. fflush (stdout);
  440. cyan_write_copier (170, parport);
  441. cyan_delay (0, parport);
  442. temp = cyan_verify_copier (parport) & 170;
  443. cyan_reset (parport);
  444. // even in unidirectional mode, the parallel port is bidirectional; at
  445. // least, for a few short moments before the driver IC smokes
  446. if ((cyan_verify_copier (parport) & 170) != 0 || temp != 170)
  447. {
  448. puts ("FAILED");
  449. fputs ("ERROR: Parallel port error\n"
  450. " Check that your parallel port is configured properly, in the BIOS, OS,\n"
  451. " and uCON64, and check for short circuits on the parallel port connector.\n"
  452. " Also ensure that the ROM copier is getting power, and a cartridge is\n"
  453. " inserted\n",
  454. stderr);
  455. exit (1);
  456. }
  457. else
  458. puts ("Passed");
  459. // discharge caps to see if we've got power
  460. cyan_reset (parport);
  461. cyan_reset (parport);
  462. cyan_write_copier (CNLO + CNHI, parport);
  463. cyan_delay (0, parport);
  464. for (temp = 0; temp < 1000; temp++)
  465. {
  466. cyan_write_copier (0, parport);
  467. cyan_delay (3, parport);
  468. cyan_write_copier (CNLO + CNHI, parport);
  469. cyan_delay (3, parport);
  470. }
  471. cyan_reset (parport);
  472. cyan_reset (parport);
  473. fputs ("Parallel port output test: ", stdout);
  474. fflush (stdout);
  475. cyan_write_copier (255, parport);
  476. cyan_delay (0, parport);
  477. temp = (cyan_verify_copier (parport) != 255);
  478. cyan_write_copier (0, parport);
  479. cyan_delay (0, parport);
  480. temp |= (cyan_verify_copier (parport) != 0);
  481. cyan_write_copier (CNLO, parport);
  482. cyan_delay (0, parport);
  483. temp |= (cyan_verify_copier (parport) != CNLO);
  484. cyan_write_copier (CNHI, parport);
  485. cyan_delay (0, parport);
  486. temp |= (cyan_verify_copier (parport) != CNHI);
  487. cyan_write_copier (RSLO, parport);
  488. cyan_delay (0, parport);
  489. temp |= (cyan_verify_copier (parport) != RSLO);
  490. cyan_write_copier (RSHI, parport);
  491. cyan_delay (0, parport);
  492. temp |= (cyan_verify_copier (parport) != RSHI);
  493. cyan_reset (parport);
  494. // if it's still okay after that, then try reading the first set of inputs
  495. // with lines high and low
  496. if (!temp)
  497. {
  498. fputs ("Passed\n"
  499. "Input crosstalk test: ",
  500. stdout);
  501. fflush (stdout);
  502. temp = cyan_read_copier (parport) & (INLO | INHI);
  503. cyan_write_copier (255 - CNLO, parport);
  504. cyan_delay (0, parport);
  505. temp = (temp != (cyan_read_copier (parport) & (INLO | INHI)));
  506. cyan_reset (parport);
  507. }
  508. if (temp)
  509. {
  510. puts ("FAILED");
  511. fputs ("ERROR: Parallel port error\n"
  512. "Possible causes: ROM copier not getting power (check or replace battery)\n"
  513. " Short circuit or bad connection (on parallel port or board)\n"
  514. " Cartridge not inserted properly (or not inserted at all)\n"
  515. " Parallel port not configured correctly\n"
  516. " Orange, grey or green wire(s) soldered to the wrong locations\n"
  517. " Chips inserted backwards\n"
  518. "NOTE: Don't forget the ROM copier needs to be turned on before starting!\n",
  519. stderr);
  520. exit (1);
  521. }
  522. else
  523. puts ("Passed");
  524. }
  525. static int
  526. cyan_test_copier (int test, int speed, unsigned short parport)
  527. {
  528. unsigned char *buffer1, *buffer2 = NULL;
  529. int count = 1;
  530. fputs (INTRO_TEXT, stdout);
  531. parport_print_info ();
  532. switch (test)
  533. {
  534. // reliability test -- note: this test may be required to run for 8 hours or more
  535. case 1:
  536. printf ("Reliability test mode selected, speed %d\n", speed);
  537. cyan_test_parport (parport);
  538. puts ("\n"
  539. "Entering non-stop reliability test mode (press escape or q to exit, and turn\n"
  540. "ROM copier off immediately afterwards)\n"
  541. "\n"
  542. "Copy process will continue indefinitely until an error is encountered, at\n"
  543. "which point the program will terminate.\n"
  544. "A large number of passes suggests that the copier is working reliably at the\n"
  545. "selected speed\n");
  546. printf (" P %2d",
  547. count);
  548. fflush (stdout);
  549. if (ucon64.frontend)
  550. fputc ('\n', stdout);
  551. buffer1 = cyan_read_rom (speed, parport, NULL);
  552. if (!buffer1) // user abort
  553. return 0;
  554. // detect if ROM is all 0x00 or 0xff and print an error if so
  555. cyan_calculate_rom_size (buffer1, 1);
  556. for (;;)
  557. {
  558. clear_line (); // remove last gauge
  559. printf (" Pass %2d OK\n", count);
  560. count++;
  561. // verify checksum of first pass
  562. if (count == 2) // check only in first iteration
  563. if (cyan_checksum_rom (buffer1)) // verify checksum
  564. puts ("\n"
  565. "WARNING: Checksum of ROM does not appear to be correct.\n"
  566. " This may be normal for this ROM, or it may indicate a bad copy\n");
  567. printf (" P %2d",
  568. count);
  569. fflush (stdout);
  570. if (ucon64.frontend)
  571. fputc ('\n', stdout);
  572. buffer2 = cyan_read_rom (speed, parport, buffer2);
  573. if (!buffer2)
  574. {
  575. free (buffer1);
  576. return 0;
  577. }
  578. if (memcmp (buffer1, buffer2, 4 * MBYTE))
  579. {
  580. // error
  581. printf ("\n"
  582. "\n"
  583. "Error detected on pass number %d\n"
  584. "\n",
  585. count);
  586. if (count == 2)
  587. puts ("A failure this early suggests a critical fault, such as a misconfigured or\n"
  588. "incompatible parallel port, extremely poor wiring, or power supply problems --\n"
  589. "you may wish to replace the battery or try another power supply, and use\n"
  590. "shorter cables.\n"
  591. "Try lowering the speed and running this test again, as a too high speed can\n"
  592. "often cause these symptoms.\n"
  593. "Alternatively, it may have been a one-time glitch; re-run the test to be sure.\n"
  594. "When (if?) you find a lower speed which works reliably, use that speed for\n"
  595. "copying ROMs\n");
  596. else
  597. puts ("The first couple of passes were successful. This indicates that you have a\n"
  598. "minor intermittent problem; most likely power supply problems, bad wiring, or\n"
  599. "some kind of one-time glitch.\n"
  600. "You may wish to replace the battery or try another power supply, and use\n"
  601. "shorter cables.\n"
  602. "Make sure no electrical appliances turn on or off during the copy.\n"
  603. "Re-run the test to be sure; it's recommended that you use a lower speed\n");
  604. free (buffer1);
  605. free (buffer2);
  606. return 1;
  607. }
  608. }
  609. break;
  610. // manual test
  611. case 2:
  612. cyan_reset (parport);
  613. cyan_write_copier (CNHI, parport);
  614. cyan_delay (0, parport);
  615. cyan_write_copier (0, parport);
  616. cyan_delay (0, parport);
  617. if (speed != DEFAULT_SPEED)
  618. puts ("Ignoring specified speed; test bench mode does not require a speed setting");
  619. // print screen
  620. puts ("Entering manual test bench mode\n"
  621. "\n"
  622. "Probe the board and verify that the counters are being clocked, and are\n"
  623. "counting correctly. The upper counter should be one count ahead of the lower\n"
  624. "counter, with both clocked at the same rate.\n"
  625. "Inject logic levels into the multiplexers to verify that the data bits are\n"
  626. "being read correctly:\n"
  627. "*=high .=low, layout: L H L H L H L H (L=low multiplexer, H=high multiplexer)\n"
  628. "NOTE: The signals in question are the chip native signals; D0 below corresponds\n"
  629. "to D0 on the multiplexer, NOT D0 on the cartridge port. Likewise with the\n"
  630. "address lines. The input lines are in counter order, left to right.\n"
  631. "Press escape or q to exit; be sure to turn the ROM copier off immediately after\n"
  632. "exiting, to reset the device.\n"
  633. "\n"
  634. "If the above didn't make any sense to you, press escape or q and turn the ROM\n"
  635. "copier off immediately!\n"
  636. "This test is designed for advanced users only\n");
  637. for (;;)
  638. {
  639. const char *status[2] = {"* ", ". "};
  640. fputc ('\r', stdout);
  641. cyan_write_copier (0, parport);
  642. cyan_delay (1, parport);
  643. count = cyan_read_copier (parport);
  644. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  645. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  646. cyan_write_copier (CNLO | CNHI, parport);
  647. cyan_delay (1, parport);
  648. count = cyan_read_copier (parport);
  649. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  650. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  651. cyan_write_copier (0, parport);
  652. cyan_delay (1, parport);
  653. count = cyan_read_copier (parport);
  654. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  655. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  656. cyan_write_copier (CNLO | CNHI, parport);
  657. cyan_delay (1, parport);
  658. count = cyan_read_copier (parport);
  659. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  660. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  661. cyan_write_copier (0, parport);
  662. cyan_delay (1, parport);
  663. count = cyan_read_copier (parport);
  664. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  665. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  666. cyan_write_copier (CNLO | CNHI, parport);
  667. cyan_delay (1, parport);
  668. count = cyan_read_copier (parport);
  669. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  670. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  671. cyan_write_copier (0, parport);
  672. cyan_delay (1, parport);
  673. count = cyan_read_copier (parport);
  674. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  675. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  676. cyan_write_copier (CNLO | CNHI, parport);
  677. cyan_delay (1, parport);
  678. count = cyan_read_copier (parport);
  679. fputs (status[((count ^ INLO) >> 6) & 1], stdout);
  680. fputs (status[((count ^ INHI) >> 4) & 1], stdout);
  681. cyan_write_copier (0, parport);
  682. cyan_delay (1, parport);
  683. fflush (stdout);
  684. if (check_exit ())
  685. {
  686. cyan_reset (parport);
  687. puts ("\nUser aborted test");
  688. return 0;
  689. }
  690. }
  691. break;
  692. default: // cmc_test() should only pass a correct speed value
  693. fputs ("INTERNAL ERROR: Invalid test number passed to cyan_test_copier()\n", stderr);
  694. exit (1);
  695. }
  696. // return 0;
  697. }
  698. static int
  699. cyan_copy_rom (const char *filename, int speed, unsigned short parport)
  700. /*
  701. Copy a ROM file -- this assumes the filename is valid and the file does not
  702. already exist, since it will blindly try to write (overwrite) the filename you
  703. give it.
  704. If the open failed due to an invalid filename or path, it prints an error.
  705. Speed setting should be between 1-4, 3 is default, and this is verified.
  706. */
  707. {
  708. unsigned long romsize;
  709. unsigned char *buffer;
  710. FILE *f;
  711. fputs (INTRO_TEXT, stdout);
  712. parport_print_info ();
  713. if (!strlen (filename))
  714. {
  715. fputs ("ERROR: Filename not specified\n"
  716. " You must specify a filename on the commandline, as follows:\n"
  717. " ucon64 " OPTION_LONG_S "xcmc dump.bin\n", stderr);
  718. exit (1);
  719. }
  720. printf ("Speed %d selected\n", speed);
  721. cyan_test_parport (parport);
  722. printf ("Destination file: %s\n", filename);
  723. if ((f = fopen (filename, "wb")) == NULL)
  724. {
  725. fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
  726. exit (1);
  727. }
  728. fclose (f);
  729. puts ("NOTE: Dumping copier's full address space (file will be automatically trimmed\n"
  730. " after dumping)\n"
  731. "Press escape or q to abort\n");
  732. buffer = cyan_read_rom (speed, parport, NULL);
  733. if (!buffer)
  734. {
  735. remove (filename);
  736. exit(0);
  737. }
  738. fputc ('\n', stdout);
  739. romsize = cyan_calculate_rom_size (buffer, 0);
  740. fputs ("Writing ROM to disk... ", stdout);
  741. fflush (stdout);
  742. if ((f = fopen (filename, "wb")) == NULL)
  743. {
  744. puts ("FAILED");
  745. fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
  746. free (buffer);
  747. exit (1);
  748. }
  749. if (fwrite (buffer, 1, romsize, f) != romsize)
  750. {
  751. puts ("FAILED");
  752. fprintf (stderr, ucon64_msg[WRITE_ERROR], filename);
  753. free (buffer);
  754. fclose (f);
  755. exit (1);
  756. }
  757. fclose (f);
  758. printf ("%d kBytes OK\n"
  759. "Verifying checksum... ", (int) (romsize / 1024));
  760. fflush (stdout);
  761. if (cyan_checksum_rom (buffer))
  762. {
  763. puts ("FAILED\n"
  764. "WARNING: Checksum of ROM does not appear to be correct.\n"
  765. " This may be normal for this ROM, or it may indicate a bad copy.\n"
  766. " Please verify the ROM, and consider running a copier test");
  767. }
  768. else
  769. puts ("OK");
  770. puts ("Copy complete!\n"
  771. "Don't forget to turn the ROM copier off, and never insert or remove a\n"
  772. "cartridge with the power on");
  773. free (buffer);
  774. return 0;
  775. }
  776. #endif // USE_PARALLEL
  777. /*******************
  778. * uCON64 wrapping *
  779. *******************/
  780. #ifdef USE_PARALLEL
  781. static st_ucon64_obj_t cmc_obj[] =
  782. {
  783. {UCON64_GEN, WF_STOP | WF_NO_ROM},
  784. {UCON64_GEN, WF_SWITCH}
  785. };
  786. #endif
  787. const st_getopt2_t cmc_usage[] =
  788. {
  789. {
  790. NULL, 0, 0, 0,
  791. NULL, "Cyan's Megadrive ROM copier"/*"1999-2004 Cyan Helkaraxe"*/,
  792. NULL
  793. },
  794. #ifdef USE_PARALLEL
  795. {
  796. "xcmc", 0, 0, UCON64_XCMC,
  797. NULL, "receive ROM from Cyan's Megadrive ROM copier; " OPTION_LONG_S "port=PORT",
  798. &cmc_obj[0]
  799. },
  800. {
  801. "xcmct", 1, 0, UCON64_XCMCT,
  802. "TEST", "run test TEST\n"
  803. "TEST=1 burn-in reliability test (specify speed)\n"
  804. "TEST=2 testbench mode (experts only)",
  805. &cmc_obj[0]
  806. },
  807. {
  808. "xcmcm", 1, 0, UCON64_XCMCM,
  809. "SPEED", "specify transfer speed\n"
  810. "SPEED=1 slow (debug)\n"
  811. "SPEED=2 medium\n"
  812. "SPEED=3 fast (default)\n" // verify with value of DEFAULT_SPEED
  813. "SPEED=4 full speed (risky)",
  814. &cmc_obj[1]
  815. },
  816. #endif // USE_PARALLEL
  817. {NULL, 0, 0, 0, NULL, NULL, NULL}
  818. };
  819. #ifdef USE_PARALLEL
  820. int
  821. cmc_read_rom (const char *filename, unsigned short parport, int speed)
  822. {
  823. #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
  824. init_conio ();
  825. if (register_func (deinit_conio) == -1)
  826. {
  827. fputs ("ERROR: Could not register function with register_func()\n", stderr);
  828. exit (1);
  829. }
  830. #endif
  831. if (speed < 1 || speed > 4)
  832. speed = DEFAULT_SPEED;
  833. cyan_copy_rom (filename, speed, parport);
  834. return 0;
  835. }
  836. int
  837. cmc_test (int test, unsigned short parport, int speed)
  838. {
  839. #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
  840. init_conio ();
  841. if (register_func (deinit_conio) == -1)
  842. {
  843. fputs ("ERROR: Could not register function with register_func()\n", stderr);
  844. exit (1);
  845. }
  846. #endif
  847. if (test < 1 || test > 2)
  848. {
  849. fputs ("ERROR: Choose a test between 1 and 2 (inclusive)\n", stderr);
  850. exit (1);
  851. }
  852. if (speed < 1 || speed > 4)
  853. speed = DEFAULT_SPEED;
  854. cyan_test_copier (test, speed, parport);
  855. return 0;
  856. }
  857. #endif // USE_PARALLEL