123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 |
- /*
- cmc.c - Cyan's Megadrive ROM copier support for uCON64
- Copyright (c) 1999 - 2004 Cyan Helkaraxe
- Special thanks to dbjh for helping with the uCON64 integration
- of this software, and providing the wrapping code.
- CMC version: 2.5
- For hardware version 1.x
- Copies Sega Megadrive/Genesis cartridges into .BIN format ROM files.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*
- Additional information:
- This software is distributed in accordance with the GNU General
- Public License. The author of the hardware design/documentation and
- software, Cyan Helkaraxe, retains the copyright over the 'cmc' code
- ('software'), the hardware design and construction documentation itself.
- Cyan grants you the rights of the GNU General Public License over
- the software, as stated above. The copyright does not affect your
- rights in relation to the 'cmc' code under the GNU General Public
- License in any way.
- Cyan Helkaraxe does NOT grant you any rights relating to the hardware
- design/documentation, over and above the right to build the device for
- personal, not-for-profit use. Likewise, the same applies to the ROM
- copier construction documentation, available at
- http://www.emulationzone.org/projects/cyan/docs/ for not-for-profit
- personal use.
- Obviously, feel free to make changes to this software, but if you do so,
- *please* clearly mark the fact it is modified, to avoid confusion.
- A define is provided below this commented area, which should be edited
- as described. This is to inform users which version of the code they are
- using at runtime, and if they encounter a problem, it makes it far easier
- for me to help debug it. I have no evil nefarious intentions. =P
- Obviously, your changes must adhere to the GNU GPL, and please keep the
- copyright, Cyan's name, e-mail and web site address in the comments
- somewhere.
- If you wish to do anything with the hardware design or the documentation
- that goes beyond personal use, get in touch with Cyan first;
- cyan@emulationzone.org
- Disclaimer / Warranty:
- This is to emphasise, not replace, any warranty information provided in
- the GNU GPL or uCON64.
- There is no warranty whatsoever, for either the software or accompanying
- hardware/design/documentation. This software is provided free of charge,
- AS-IS, in the hope that it may be useful.
- Use it at your own risk. The author does not make any guarantee that you
- will be able to use this software or accompanying
- hardware/design/documentation, or that it will perform smoothly. There is
- a possibility that damage or loss (including but not limited to financial
- loss, hardware or software damage, data corruption, privacy violation,
- or personal injury, suffering, legal action, imprisonment or death) may
- arise through the use of this software or the accompanying
- hardware/design/documentation, in addition to many other possible outcomes.
- You take sole responsibility for any outcomes; by using this software or
- accompanying hardware/design/ documentation, you agree that the author will
- not be held responsible for anything that may occur. If your jurisdiction
- does not allow the author to be isolated from responsibility, then you
- must *not* use this software or accompanying hardware/design/documentation.
- The author does not condone software piracy. You may not use this software
- to engage in piracy. The author is not responsible for anything you choose
- to use this software for, although the author strongly recommends that you
- use the software for the purpose for which it was intended to be used --
- primarily as an educational tool, and secondarily to make backup copies of
- your expensive/rare game cartridges, or a similarly harmless and legal
- purpose.
- Note that although the author isn't aware of any patent violations caused
- by this software/hardware/design/documentation, it is possible that
- there may be patents covering parts of this device. It is your
- responsibility to check this before building or using the hardware or
- software, and Cyan may not be held responsible in the event of an
- infringement.
- That being said, if you do encounter any problems with the hardware or
- software, then feel free to get in touch with the author; use the subject
- line 'ROM Copier Technical Support'. No promises or guarantees are made,
- however.
- Also note that the author is not affiliated with anyone involved with uCON64;
- therefore, only correspondence relating to this particular file (the 'cmc'
- code) or the accompanying hardware design should be directed to Cyan.
- If you have more general uCON64 questions, Cyan is *not* the person to ask.
- Likewise, the terms "the author" and "software" in this file (cmc.c, and
- additionally cmc.h), along with similar terms, apply only to Cyan, and the
- CMC software you see in this file. The disclaimer above, for example, relates
- exclusively to the CMC code.
- All trademarks, indicated or otherwise, are the property of their
- respective owners.
- */
- /*
- NOTE!
- Please edit the following line, and remove the word "original" from it
- if you have made any modifications to this file. This reduces user
- confusion.
- */
- #define INTRO_TEXT "Cyan's Megadrive Copier (c) 1999-2004 Cyan Helkaraxe\n" \
- "Software version 2.5, designed for hardware version 1.x\n\n"
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <stdlib.h>
- #include <string.h>
- #include "misc/archive.h"
- #include "misc/bswap.h"
- #include "misc/misc.h"
- #include "misc/parallel.h"
- #include "misc/term.h"
- #include "ucon64.h"
- #include "ucon64_misc.h"
- #include "backup/cmc.h"
- #ifdef USE_PARALLEL
- #define RSLO 0x40 // reset line 1 d7
- #define RSHI 0x01 // reset line 2 d0
- #define CNLO 0x10 // counter line 1 d4
- #define CNHI 0x04 // counter line 2 d2
- #define INLO 0x40 // input 1 ack (int disabled)
- #define INHI 0x10 // input 2 selectin
- #define MBYTE (1024 * 1024)
- #define DEFAULT_SPEED 3
- #ifdef _MSC_VER
- // Visual C++ doesn't allow inline in C source code
- #define inline __inline
- #endif
- /************************
- * Internal functions *
- ************************/
- static inline void
- cyan_write_copier (unsigned char data, unsigned short parport)
- // write a value to the data register of the parallel port
- {
- outportb (parport + PARPORT_DATA, data);
- }
- static inline unsigned char
- cyan_read_copier (unsigned short parport)
- // read a value from the status register of the parallel port
- {
- return inportb (parport + PARPORT_STATUS);
- }
- static inline unsigned char
- cyan_verify_copier (unsigned short parport)
- // read a value back from the data register for verification
- {
- return inportb (parport + PARPORT_DATA);
- }
- /**** non-hardware, non-accessing ****/
- static unsigned long
- cyan_calculate_rom_size (unsigned char *buffer, int test_mode)
- /*
- Calculate the ROM size, by looking at the ROM size entry in the ROM 'header',
- and the overall structure.
- This function always returns a value rounded to a power of two between 128
- kbytes and 4 Mbytes. It also inspects the ROM for 0's or ffh's. If test_mode
- is 1 it causes an error on that condition, frees the buffer and exits.
- */
- {
- unsigned long i = 0x80000000, reported_size;
- // look at reported size
- reported_size = (buffer[0x1a4] << 24) +
- (buffer[0x1a5] << 16) +
- (buffer[0x1a6] << 8) +
- buffer[0x1a7] + 1;
- // cap
- // there is a minimum valid size for ROMs, according to some sources
- if (reported_size < MBIT)
- reported_size = MBIT;
- if (reported_size > 4 * MBYTE)
- reported_size = 4 * MBYTE;
- // round
- if (reported_size & (reported_size - 1))
- {
- while (!(reported_size & 0x80000000))
- {
- i >>= 1;
- reported_size = (reported_size << 1) | 1;
- }
- reported_size = i << 1;
- }
- // calculate real size
- for (i = 2 * MBYTE; i >= 65536; i >>= 1)
- if (memcmp (buffer, buffer + i, i))
- {
- i >>= 1;
- break;
- }
- i <<= 2;
- if (reported_size < i)
- reported_size = i; // pick the safest (largest) of the two
- if (i == MBIT)
- {
- for (i = 0; i < MBIT; i++)
- if ((buffer[i] != 0xff) && (buffer[i] != 0x00))
- break;
- if (i == MBIT)
- {
- FILE *output;
- if (test_mode)
- {
- output = stderr;
- fputs ("\nERROR: ", stderr);
- }
- else
- {
- output = stdout;
- fputs ("\nWARNING: ", stdout);
- }
- // "WARNING: "
- fputs ( "The ROM file appears to consist of nothing but 0x00 / 0xff values.\n"
- " This usually indicates a serious problem. Perhaps your parallel port\n"
- " isn't configured correctly, or there is some problem with the ROM\n"
- " copier. Is it getting power? Is a cartridge inserted? Is it properly\n"
- " attached to the PC?\n",
- output);
- if (test_mode)
- {
- free (buffer);
- exit (1);
- }
- }
- }
- return reported_size;
- }
- static int
- cyan_checksum_rom (unsigned char *buffer)
- // return 0 on success, -1 on failure
- {
- unsigned char *buffer2 = buffer;
- unsigned short reported_sum, running_sum = 0;
- reported_sum = (buffer2[0x18e] << 8) + buffer2[0x18f];
- buffer2 += ((buffer2[0x1a4] << 24) +
- (buffer2[0x1a5] << 16) +
- (buffer2[0x1a6] << 8) +
- (buffer2[0x1a7] & 0xfe)) + 2;
- if (buffer2 > buffer + 4 * MBYTE)
- buffer2 = buffer + 4 * MBYTE;
- buffer += 0x200;
- if (buffer2 < buffer + 2)
- return -1;
- while (buffer2 != buffer)
- {
- running_sum += *--buffer2;
- running_sum += (*--buffer2) << 8;
- }
- return (running_sum & 0xffff) != reported_sum ? -1 : 0;
- }
- static inline unsigned long
- cyan_get_address (unsigned long b)
- // return the true address (word -- 0 - 2 M) based on word input
- {
- return ((b & 0x000800) >> 11) | // bit 0
- ((b & 0x002000) >> 12) | // bit 1
- ((b & 0x004000) >> 12) | // bit 2
- ((b & 0x000020) >> 2) | // bit 3
- ((b & 0x100000) >> 16) | // bit 4
- ((b & 0x020000) >> 12) | // bit 5
- ((b & 0x000400) >> 4) | // bit 6
- ((b & 0x000001) << 7) | // bit 7
- ((b & 0x000002) << 7) | // bit 8
- ((b & 0x000010) << 5) | // bit 9
- ((b & 0x000040) << 4) | // bit 10
- ((b & 0x040000) >> 7) | // bit 11
- ((b & 0x080000) >> 7) | // bit 12
- ((b & 0x000080) << 6) | // bit 13
- ((b & 0x008000) >> 1) | // bit 14
- ((b & 0x010000) >> 1) | // bit 15
- ((b & 0x001000) << 4) | // bit 16
- ((b & 0x000004) << 15) | // bit 17
- ((b & 0x000008) << 15) | // bit 18
- ((b & 0x000200) << 10) | // bit 19
- ((b & 0x000100) << 12); // bit 20
- }
- /**** non-hardware, indirectly accessing ****/
- static inline void
- cyan_delay (int speed, unsigned short parport)
- // Delays a certain amount of time depending on speed selected. 0=long delay,
- // used for reset and hi counter.
- {
- int i, scritch = 0;
- switch (speed)
- {
- case 0:
- for (i = 0; i < 128; i++)
- scritch += cyan_read_copier (parport);
- case 1: // falling through
- for (i = 0; i < 64; i++)
- scritch += cyan_read_copier (parport);
- case 2: // falling through
- for (i = 0; i < 12; i++)
- scritch += cyan_read_copier (parport);
- case 3: // falling through
- scritch += cyan_read_copier (parport);
- scritch += cyan_read_copier (parport);
- }
- }
- static void
- cyan_reset (unsigned short parport)
- // resets the copier
- {
- cyan_delay (0, parport);
- // zero all data outputs first, before going into SPP mode
- cyan_write_copier (0, parport);
- // reset the port to SPP, float all control lines high
- cyan_write_copier (0, parport + PARPORT_CONTROL);
- cyan_delay (0, parport);
- cyan_write_copier (RSLO | RSHI, parport); // both reset lines hi
- cyan_delay (0, parport);
- cyan_write_copier (0, parport); // both reset lines lo
- cyan_delay (0, parport);
- }
- static inline unsigned short
- cyan_get_word (int speed, unsigned short parport)
- // gets a byte pair from the ROM and return two bytes in big endian byte order
- {
- unsigned short value = 0;
- unsigned char tempz;
- cyan_write_copier (0, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= tempz & INLO; // bit 6
- value |= (tempz & INHI) << 8; // bit 12
- cyan_write_copier (CNLO, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) >> 5; // bit 1
- value |= (tempz & INHI) << 9; // bit 13
- cyan_write_copier (0, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) << 3; // bit 9
- value |= (tempz & INHI) << 10; // bit 14
- cyan_write_copier (CNLO, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) >> 1; // bit 5
- value |= (tempz & INHI) << 11; // bit 15
- cyan_write_copier (0, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) >> 4; // bit 2
- value |= (tempz & INHI) << 4; // bit 8
- cyan_write_copier (CNLO, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) << 4; // bit 10
- value |= (tempz & INHI) >> 4; // bit 0
- cyan_write_copier (0, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) >> 2; // bit 4
- value |= (tempz & INHI) << 3; // bit 7
- cyan_write_copier (CNLO, parport);
- cyan_delay (speed, parport);
- tempz = cyan_read_copier (parport);
- value |= (tempz & INLO) >> 3; // bit 3
- value |= (tempz & INHI) << 7; // bit 11
- return me2be_16 (value);
- }
- static inline int
- check_exit (void)
- // check for user abort
- {
- int temp;
- if (ucon64.frontend)
- return 0;
- if (!kbhit ())
- return 0;
- temp = getch ();
- if (temp == 'q' || (temp == 27))
- return 1;
- return 0;
- }
- static unsigned char *
- cyan_read_rom (int speed, unsigned short parport, unsigned char *buffer)
- /*
- Read the ROM and return a pointer to a 4 MB area of memory containing all ROM
- data. Designed to be used from inside cyan_copy_rom(), although it can be
- called elsewhere if a raw (but decoded) dump is required.
- */
- {
- unsigned long q;
- time_t t;
- // allocate the dump area
- if (!buffer)
- if ((buffer = (unsigned char *) malloc (4 * MBYTE)) == NULL)
- {
- fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], 4 * MBYTE);
- exit (1);
- }
- cyan_reset (parport); // reset the copier
- t = time (NULL);
- // copy routine
- for (q = 0; q < 2 * MBYTE; ) // loop through all words
- {
- // get a (16-bit) word from the ROM
- ((unsigned short *) buffer)[cyan_get_address (q)] = cyan_get_word (speed, parport);
- // periodically update progress bar, without hammering ucon64_gauge()
- if (!(q & (0xfff >> (5 - speed))))
- {
- if (check_exit ())
- {
- free (buffer);
- puts ("\n"
- "Copy aborted.\n"
- "Don't forget to turn the ROM copier off and never insert or remove a cartridge\n"
- "with the power on");
- break;
- }
- ucon64_gauge (t, q * 2, 4 * MBYTE);
- }
- if (!(++q & 0x3ff)) // advance loop counter and carry to hi counter (11 bits)
- {
- cyan_delay (0, parport);
- cyan_write_copier (CNHI, parport);
- cyan_delay (0, parport);
- cyan_write_copier (0, parport);
- cyan_delay (0, parport);
- }
- }
- // make sure it's left in a state where it's safe to remove the cart
- cyan_reset (parport);
- if (q != 2 * MBYTE)
- return NULL;
- ucon64_gauge (t, q * 2, 4 * MBYTE); // make the progress bar reach 100%
- return buffer;
- }
- static void
- cyan_test_parport (unsigned short parport)
- // Test the parallel port to see if it appears to be functioning correctly, and
- // terminate if there's an error.
- {
- unsigned short temp;
- cyan_reset (parport);
- fputs ("Basic parallel port test: ", stdout);
- fflush (stdout);
- cyan_write_copier (170, parport);
- cyan_delay (0, parport);
- temp = cyan_verify_copier (parport) & 170;
- cyan_reset (parport);
- // even in unidirectional mode, the parallel port is bidirectional; at
- // least, for a few short moments before the driver IC smokes
- if ((cyan_verify_copier (parport) & 170) != 0 || temp != 170)
- {
- puts ("FAILED");
- fputs ("ERROR: Parallel port error\n"
- " Check that your parallel port is configured properly, in the BIOS, OS,\n"
- " and uCON64, and check for short circuits on the parallel port connector.\n"
- " Also ensure that the ROM copier is getting power, and a cartridge is\n"
- " inserted\n",
- stderr);
- exit (1);
- }
- else
- puts ("Passed");
- // discharge caps to see if we've got power
- cyan_reset (parport);
- cyan_reset (parport);
- cyan_write_copier (CNLO + CNHI, parport);
- cyan_delay (0, parport);
- for (temp = 0; temp < 1000; temp++)
- {
- cyan_write_copier (0, parport);
- cyan_delay (3, parport);
- cyan_write_copier (CNLO + CNHI, parport);
- cyan_delay (3, parport);
- }
- cyan_reset (parport);
- cyan_reset (parport);
- fputs ("Parallel port output test: ", stdout);
- fflush (stdout);
- cyan_write_copier (255, parport);
- cyan_delay (0, parport);
- temp = (cyan_verify_copier (parport) != 255);
- cyan_write_copier (0, parport);
- cyan_delay (0, parport);
- temp |= (cyan_verify_copier (parport) != 0);
- cyan_write_copier (CNLO, parport);
- cyan_delay (0, parport);
- temp |= (cyan_verify_copier (parport) != CNLO);
- cyan_write_copier (CNHI, parport);
- cyan_delay (0, parport);
- temp |= (cyan_verify_copier (parport) != CNHI);
- cyan_write_copier (RSLO, parport);
- cyan_delay (0, parport);
- temp |= (cyan_verify_copier (parport) != RSLO);
- cyan_write_copier (RSHI, parport);
- cyan_delay (0, parport);
- temp |= (cyan_verify_copier (parport) != RSHI);
- cyan_reset (parport);
- // if it's still okay after that, then try reading the first set of inputs
- // with lines high and low
- if (!temp)
- {
- fputs ("Passed\n"
- "Input crosstalk test: ",
- stdout);
- fflush (stdout);
- temp = cyan_read_copier (parport) & (INLO | INHI);
- cyan_write_copier (255 - CNLO, parport);
- cyan_delay (0, parport);
- temp = (temp != (cyan_read_copier (parport) & (INLO | INHI)));
- cyan_reset (parport);
- }
- if (temp)
- {
- puts ("FAILED");
- fputs ("ERROR: Parallel port error\n"
- "Possible causes: ROM copier not getting power (check or replace battery)\n"
- " Short circuit or bad connection (on parallel port or board)\n"
- " Cartridge not inserted properly (or not inserted at all)\n"
- " Parallel port not configured correctly\n"
- " Orange, grey or green wire(s) soldered to the wrong locations\n"
- " Chips inserted backwards\n"
- "NOTE: Don't forget the ROM copier needs to be turned on before starting!\n",
- stderr);
- exit (1);
- }
- else
- puts ("Passed");
- }
- static int
- cyan_test_copier (int test, int speed, unsigned short parport)
- {
- unsigned char *buffer1, *buffer2 = NULL;
- int count = 1;
- fputs (INTRO_TEXT, stdout);
- parport_print_info ();
- switch (test)
- {
- // reliability test -- note: this test may be required to run for 8 hours or more
- case 1:
- printf ("Reliability test mode selected, speed %d\n", speed);
- cyan_test_parport (parport);
- puts ("\n"
- "Entering non-stop reliability test mode (press escape or q to exit, and turn\n"
- "ROM copier off immediately afterwards)\n"
- "\n"
- "Copy process will continue indefinitely until an error is encountered, at\n"
- "which point the program will terminate.\n"
- "A large number of passes suggests that the copier is working reliably at the\n"
- "selected speed\n");
- printf (" P %2d",
- count);
- fflush (stdout);
- if (ucon64.frontend)
- fputc ('\n', stdout);
- buffer1 = cyan_read_rom (speed, parport, NULL);
- if (!buffer1) // user abort
- return 0;
- // detect if ROM is all 0x00 or 0xff and print an error if so
- cyan_calculate_rom_size (buffer1, 1);
- for (;;)
- {
- clear_line (); // remove last gauge
- printf (" Pass %2d OK\n", count);
- count++;
- // verify checksum of first pass
- if (count == 2) // check only in first iteration
- if (cyan_checksum_rom (buffer1)) // verify checksum
- puts ("\n"
- "WARNING: Checksum of ROM does not appear to be correct.\n"
- " This may be normal for this ROM, or it may indicate a bad copy\n");
- printf (" P %2d",
- count);
- fflush (stdout);
- if (ucon64.frontend)
- fputc ('\n', stdout);
- buffer2 = cyan_read_rom (speed, parport, buffer2);
- if (!buffer2)
- {
- free (buffer1);
- return 0;
- }
- if (memcmp (buffer1, buffer2, 4 * MBYTE))
- {
- // error
- printf ("\n"
- "\n"
- "Error detected on pass number %d\n"
- "\n",
- count);
- if (count == 2)
- puts ("A failure this early suggests a critical fault, such as a misconfigured or\n"
- "incompatible parallel port, extremely poor wiring, or power supply problems --\n"
- "you may wish to replace the battery or try another power supply, and use\n"
- "shorter cables.\n"
- "Try lowering the speed and running this test again, as a too high speed can\n"
- "often cause these symptoms.\n"
- "Alternatively, it may have been a one-time glitch; re-run the test to be sure.\n"
- "When (if?) you find a lower speed which works reliably, use that speed for\n"
- "copying ROMs\n");
- else
- puts ("The first couple of passes were successful. This indicates that you have a\n"
- "minor intermittent problem; most likely power supply problems, bad wiring, or\n"
- "some kind of one-time glitch.\n"
- "You may wish to replace the battery or try another power supply, and use\n"
- "shorter cables.\n"
- "Make sure no electrical appliances turn on or off during the copy.\n"
- "Re-run the test to be sure; it's recommended that you use a lower speed\n");
- free (buffer1);
- free (buffer2);
- return 1;
- }
- }
- break;
- // manual test
- case 2:
- cyan_reset (parport);
- cyan_write_copier (CNHI, parport);
- cyan_delay (0, parport);
- cyan_write_copier (0, parport);
- cyan_delay (0, parport);
- if (speed != DEFAULT_SPEED)
- puts ("Ignoring specified speed; test bench mode does not require a speed setting");
- // print screen
- puts ("Entering manual test bench mode\n"
- "\n"
- "Probe the board and verify that the counters are being clocked, and are\n"
- "counting correctly. The upper counter should be one count ahead of the lower\n"
- "counter, with both clocked at the same rate.\n"
- "Inject logic levels into the multiplexers to verify that the data bits are\n"
- "being read correctly:\n"
- "*=high .=low, layout: L H L H L H L H (L=low multiplexer, H=high multiplexer)\n"
- "NOTE: The signals in question are the chip native signals; D0 below corresponds\n"
- "to D0 on the multiplexer, NOT D0 on the cartridge port. Likewise with the\n"
- "address lines. The input lines are in counter order, left to right.\n"
- "Press escape or q to exit; be sure to turn the ROM copier off immediately after\n"
- "exiting, to reset the device.\n"
- "\n"
- "If the above didn't make any sense to you, press escape or q and turn the ROM\n"
- "copier off immediately!\n"
- "This test is designed for advanced users only\n");
- for (;;)
- {
- const char *status[2] = {"* ", ". "};
- fputc ('\r', stdout);
- cyan_write_copier (0, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (CNLO | CNHI, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (0, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (CNLO | CNHI, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (0, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (CNLO | CNHI, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (0, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (CNLO | CNHI, parport);
- cyan_delay (1, parport);
- count = cyan_read_copier (parport);
- fputs (status[((count ^ INLO) >> 6) & 1], stdout);
- fputs (status[((count ^ INHI) >> 4) & 1], stdout);
- cyan_write_copier (0, parport);
- cyan_delay (1, parport);
- fflush (stdout);
- if (check_exit ())
- {
- cyan_reset (parport);
- puts ("\nUser aborted test");
- return 0;
- }
- }
- break;
- default: // cmc_test() should only pass a correct speed value
- fputs ("INTERNAL ERROR: Invalid test number passed to cyan_test_copier()\n", stderr);
- exit (1);
- }
- // return 0;
- }
- static int
- cyan_copy_rom (const char *filename, int speed, unsigned short parport)
- /*
- Copy a ROM file -- this assumes the filename is valid and the file does not
- already exist, since it will blindly try to write (overwrite) the filename you
- give it.
- If the open failed due to an invalid filename or path, it prints an error.
- Speed setting should be between 1-4, 3 is default, and this is verified.
- */
- {
- unsigned long romsize;
- unsigned char *buffer;
- FILE *f;
- fputs (INTRO_TEXT, stdout);
- parport_print_info ();
- if (!strlen (filename))
- {
- fputs ("ERROR: Filename not specified\n"
- " You must specify a filename on the commandline, as follows:\n"
- " ucon64 " OPTION_LONG_S "xcmc dump.bin\n", stderr);
- exit (1);
- }
- printf ("Speed %d selected\n", speed);
- cyan_test_parport (parport);
- printf ("Destination file: %s\n", filename);
- if ((f = fopen (filename, "wb")) == NULL)
- {
- fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
- exit (1);
- }
- fclose (f);
- puts ("NOTE: Dumping copier's full address space (file will be automatically trimmed\n"
- " after dumping)\n"
- "Press escape or q to abort\n");
- buffer = cyan_read_rom (speed, parport, NULL);
- if (!buffer)
- {
- remove (filename);
- exit(0);
- }
- fputc ('\n', stdout);
- romsize = cyan_calculate_rom_size (buffer, 0);
- fputs ("Writing ROM to disk... ", stdout);
- fflush (stdout);
- if ((f = fopen (filename, "wb")) == NULL)
- {
- puts ("FAILED");
- fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
- free (buffer);
- exit (1);
- }
- if (fwrite (buffer, 1, romsize, f) != romsize)
- {
- puts ("FAILED");
- fprintf (stderr, ucon64_msg[WRITE_ERROR], filename);
- free (buffer);
- fclose (f);
- exit (1);
- }
- fclose (f);
- printf ("%d kBytes OK\n"
- "Verifying checksum... ", (int) (romsize / 1024));
- fflush (stdout);
- if (cyan_checksum_rom (buffer))
- {
- puts ("FAILED\n"
- "WARNING: Checksum of ROM does not appear to be correct.\n"
- " This may be normal for this ROM, or it may indicate a bad copy.\n"
- " Please verify the ROM, and consider running a copier test");
- }
- else
- puts ("OK");
- puts ("Copy complete!\n"
- "Don't forget to turn the ROM copier off, and never insert or remove a\n"
- "cartridge with the power on");
- free (buffer);
- return 0;
- }
- #endif // USE_PARALLEL
- /*******************
- * uCON64 wrapping *
- *******************/
- #ifdef USE_PARALLEL
- static st_ucon64_obj_t cmc_obj[] =
- {
- {UCON64_GEN, WF_STOP | WF_NO_ROM},
- {UCON64_GEN, WF_SWITCH}
- };
- #endif
- const st_getopt2_t cmc_usage[] =
- {
- {
- NULL, 0, 0, 0,
- NULL, "Cyan's Megadrive ROM copier"/*"1999-2004 Cyan Helkaraxe"*/,
- NULL
- },
- #ifdef USE_PARALLEL
- {
- "xcmc", 0, 0, UCON64_XCMC,
- NULL, "receive ROM from Cyan's Megadrive ROM copier; " OPTION_LONG_S "port=PORT",
- &cmc_obj[0]
- },
- {
- "xcmct", 1, 0, UCON64_XCMCT,
- "TEST", "run test TEST\n"
- "TEST=1 burn-in reliability test (specify speed)\n"
- "TEST=2 testbench mode (experts only)",
- &cmc_obj[0]
- },
- {
- "xcmcm", 1, 0, UCON64_XCMCM,
- "SPEED", "specify transfer speed\n"
- "SPEED=1 slow (debug)\n"
- "SPEED=2 medium\n"
- "SPEED=3 fast (default)\n" // verify with value of DEFAULT_SPEED
- "SPEED=4 full speed (risky)",
- &cmc_obj[1]
- },
- #endif // USE_PARALLEL
- {NULL, 0, 0, 0, NULL, NULL, NULL}
- };
- #ifdef USE_PARALLEL
- int
- cmc_read_rom (const char *filename, unsigned short parport, int speed)
- {
- #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
- init_conio ();
- if (register_func (deinit_conio) == -1)
- {
- fputs ("ERROR: Could not register function with register_func()\n", stderr);
- exit (1);
- }
- #endif
- if (speed < 1 || speed > 4)
- speed = DEFAULT_SPEED;
- cyan_copy_rom (filename, speed, parport);
- return 0;
- }
- int
- cmc_test (int test, unsigned short parport, int speed)
- {
- #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
- init_conio ();
- if (register_func (deinit_conio) == -1)
- {
- fputs ("ERROR: Could not register function with register_func()\n", stderr);
- exit (1);
- }
- #endif
- if (test < 1 || test > 2)
- {
- fputs ("ERROR: Choose a test between 1 and 2 (inclusive)\n", stderr);
- exit (1);
- }
- if (speed < 1 || speed > 4)
- speed = DEFAULT_SPEED;
- cyan_test_copier (test, speed, parport);
- return 0;
- }
- #endif // USE_PARALLEL
|