/* gbx.c - Game Boy Xchanger/GBDoctor support for uCON64 Copyright (c) 1999 - 2001 NoisyB Copyright (c) 2001 - 2004 dbjh Based on gbt15.c - Copyright (c) Bung Enterprises 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. */ /******************************************************************** * use parallel EPP/SPP port to r/w game boy cartridge * * * * ai[]=0 w a[7..0] * * ai[]=1 w a[15..8] * * ai[]=2 w control d7=rs,d6=spp,d1=xwe_en,d0=cs_en * * ai[]=3 r/w data * * * * MBC1 * * R/W A000~BFFF RAM SWITCHING BANK(256Kbit) 4 BANKS OF 8Kbyte * * R 4000~7FFF ROM SWITCHING BANK(4Mbit) 32 BANKS OF 128Kbit * * W 2000~3FFF SET ROM BANK (5 BIT) * * R 0000~3FFF FIX ROM BANK 0 * * W 4000~5FFF SET RAM BANK (2 BIT) * * W 0000~1FFF SET 0A ENABLE RAM BANK * * * * MBC2 * * R/W A000~BFFF 512 X 4 BIT RAM * * R 4000~7FFF ROM SWITCHING BANK(2Mbit) 16 BANKS OF 128Kbit * * W 2100 SET ROM BANK (4 BIT) * * R 0000~3FFF FIX ROM BANK 0 * * W 0000 SET 0A ENABLE RAM BANK * * * * MBC5 * * R/W A000~BFFF RAM SWITCHING BANK(1Mbit) 16 BANKS OF 64 Kbit * * R 4000~7FFF ROM SWITCHING BANK(64Mbit) 512 BANKS OF 128Kbit * * W 3000~3FFF SET ROM BANK1(BANK Q8) TOTAL 9 BIT * * W 2000~2FFF SET ROM BANK0(BANK Q7~Q0) * * R 0000~3FFF FIX ROM BANK 0 * * W 4000~7FFF SET RAM BANK (4 BIT) * * W 0000~1FFF SET 0A ENABLE RAM BANK * * * ********************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "misc/archive.h" #include "misc/file.h" #include "misc/misc.h" #include "misc/parallel.h" #include "misc/term.h" #include "ucon64_misc.h" #include "console/gb.h" // GB_NAME_LEN, gb_logodata, #include "backup/gbx.h" // rocket_logodata #ifdef USE_PARALLEL static st_ucon64_obj_t gbx_obj[] = { {UCON64_GB, WF_DEFAULT | WF_STOP | WF_NO_ROM}, {UCON64_GB, WF_STOP | WF_NO_ROM}, {UCON64_GB, WF_SWITCH} }; #endif const st_getopt2_t gbx_usage[] = { { NULL, 0, 0, 0, NULL, "Game Boy Xchanger/GBDoctor"/*"19XX Bung Enterprises Ltd http://www.bung.com.hk"*/, NULL }, #ifdef USE_PARALLEL { "xgbx", 0, 0, UCON64_XGBX, NULL, "send/receive ROM to/from GB Xchanger; " OPTION_LONG_S "port=PORT\n" "receives automatically when ROM does not exist", &gbx_obj[0] }, { "xgbxs", 0, 0, UCON64_XGBXS, NULL, "send/receive SRAM to/from GB Xchanger; " OPTION_LONG_S "port=PORT\n" "receives automatically when SRAM does not exist", &gbx_obj[1] }, { "xgbxb", 1, 0, UCON64_XGBXB, "BANK", "send/receive 64 kbits SRAM to/from GB Xchanger BANK\n" "BANK can be a number from 0 to 15; " OPTION_LONG_S "port=PORT\n" "receives automatically when ROM does not exist", &gbx_obj[1] }, { "xgbxm", 0, 0, UCON64_XGBXM, NULL, "try to enable EPP mode, default is SPP mode", &gbx_obj[2] }, #endif {NULL, 0, 0, 0, NULL, NULL, NULL} }; #ifdef USE_PARALLEL //#define set_ai_write outportb (port_a, 5); // ninit=1, nwrite=0 #define set_data_read outportb (port_a, 0); // ninit=0, nastb=1, nib_sel=0, ndstb=1, nwrite=1 #define set_data_write outportb (port_a, 1); // ninit=0, nastb=1, nib_sel=0, ndstb=1, nwrite=0 //#define set_normal outportb (port_a, 4); // ninit=1, nwrite=1 typedef enum { UNKNOWN_MBC, BUNG, ROM, MBC1, MBC2, MBC3, MBC5, CAMERA, ROCKET } mbc_t; typedef enum { UNKNOWN_EEPROM, WINBOND, MX, INTEL } eeprom_t; static unsigned short port_8, port_9, port_a, port_b, port_c, rocket_game_no; static unsigned char buffer[32768]; static mbc_t mbc_type; static eeprom_t eeprom_type; static parport_mode_t port_mode; static void delay_us (int n_us) // Hmmm, usleep() can be used on UNIX, but default on DOS is delay() which waits // for a number of milliseconds... Better use the same code on all platforms. { volatile int n; int n_max; // it's probably best to use the original strange loop values if (n_us == 10) n_max = 0x2000; else if (n_us == 100) n_max = 0x10000; else if (n_us == 20000) n_max = 0xfffff; else n_max = n_us * 1000; for (n = 0; n < n_max; n++) ; } static void spp_set_ai (unsigned char ai) { set_data_write // outportb (port_a, 1); // nastb=1,nib_sel=0,ndstb=1,nwrite=0 outportb (port_8, ai); // put ai at data bus outportb (port_a, 9); // nastb=0,nib_sel=0,ndstb=1,nwrite=0 outportb (port_a, 1); // nastb=1,nib_sel=0,ndstb=1,nwrite=0 // nastb ~~~~|___|~~~~ } static void spp_write_data (unsigned char data) { // outportb (port_a, 1); // nastb=1,nib_sel=0,ndstb=1,nwrite=0 outportb (port_8, data); // put data at data bus outportb (port_a, 3); // nastb=1,nib_sel=0,ndstb=0,nwrite=0 outportb (port_a, 1); // nastb=1,nib_sel=0,ndstb=1,nwrite=0 // ndstb ~~~~|___|~~~~ } static void spp_set_ai_data (unsigned char ai, unsigned char data) { spp_set_ai (ai); spp_write_data (data); } static unsigned char spp_read_data (void) { unsigned char byte; set_data_read outportb (port_a, 2); // nastb=1,nib_sel=0,ndstb=0,nwrite=1 byte = (inportb (port_9) >> 3) & 0x0f; outportb (port_a, 6); // nastb=1,nib_sel=1,ndstb=0,nwrite=1 byte |= (inportb (port_9) << 1) & 0xf0; outportb (port_a, 0); // nastb=1,nib_sel=0,ndstb=1,nwrite=1 // nibble_sel ___|~~~ and ndstb ~~~~|___|~~~~ return byte; } static void epp_set_ai (unsigned char ai) { set_data_write outportb (port_b, ai); } static void epp_set_ai_data (unsigned char ai, unsigned char data) { epp_set_ai (ai); set_data_write outportb (port_c, data); } static void set_ai (unsigned char ai) { set_data_write if (port_mode == UCON64_SPP) spp_set_ai (ai); else epp_set_ai (ai); } static void set_ai_data (unsigned char ai, unsigned char data) { if (port_mode == UCON64_SPP) spp_set_ai_data (ai, data); // SPP mode else epp_set_ai_data (ai, data); // EPP mode } static void write_data (unsigned char data) { if (port_mode == UCON64_SPP) spp_write_data (data); // SPP write data else outportb (port_c, data); // EPP write data } static unsigned char read_data (void) { if (port_mode == UCON64_SPP) return spp_read_data (); // SPP read data else return inportb (port_c); // EPP read data } static void init_port (void) { #ifndef USE_PPDEV outportb (port_9, 1); // clear EPP time flag #endif set_ai_data ((unsigned char) 2, 0); // rst=0, wei=0(dis.), rdi=0(dis.) set_ai_data ((unsigned char) 2, 0x80); // rst=1, wei=0(dis.), rdi=0(dis.) } static void end_port (void) { set_ai_data ((unsigned char) 2, 0); // rst=0, wei=0(dis.), rdi=0(dis.) outportb (port_a, 4); // ninit=1, nwrite=1 } static void set_adr (unsigned int adr) { set_ai_data ((unsigned char) 0, (unsigned char) adr); // a[7..0] set_ai_data ((unsigned char) 1, (unsigned char) (adr >> 8)); // a[15..8] set_ai (3); set_data_read // ninit=0, nwrite=1 } static void set_adr_long (unsigned int adr, int ignore_xh) // real address { unsigned char xh, h, m, l; set_ai_data ((unsigned char) 2, 0x80); // disable wr/rd inc. l = (unsigned char) adr; // a7-a0 m = (unsigned char) (adr >> 8) & 0x3f; // a13-a8 h = (unsigned char) (adr >> 14) & 0xff; // a21-a13 if (h) m |= 0x40; // > bank 0 if (!ignore_xh) { xh = (unsigned char) (adr >> 22) & 0x7; // max. 256Mbit if (xh) m |= 0x40; // > bank 0 set_adr (0x3000); // write 3000:xh set_data_write write_data (xh); // set ROM bank extend value } set_adr (0x2000); // write 2000:h set_data_write write_data (h); // set ROM bank value set_ai_data ((unsigned char) 1, m); // a[15..8] set_ai_data ((unsigned char) 0, l); // a[7..0] } static void set_bank (unsigned int adr, unsigned char bank) { set_ai_data ((unsigned char) 2, 0x80); // disable inc set_ai_data ((unsigned char) 0, (unsigned char) adr); // a[7..0] set_ai_data ((unsigned char) 1, (unsigned char) ((adr >> 8) & 0x7f)); // a[15..8] set_ai_data ((unsigned char) 3, bank); // write bank no set_data_read // ninit=0, nwrite=1 } static void out_byte_eeprom (unsigned char data) { set_ai_data ((unsigned char) 2, 0x82); // wei enable set_ai (3); // default write mode // set_data_read // ninit=0, nwrite=1 set_data_write write_data (data); // out data set_ai_data ((unsigned char) 2, 0x80); // wei disable set_ai (3); // default write mode } static void out_byte (unsigned char data) { set_ai (3); // set_data_read // ninit=0, nwrite=1 set_data_write write_data (data); // out data } static void out_data (unsigned char h, unsigned char m, unsigned char l, unsigned char data) { // ai[]=2 w control d7=rs,d1=xwe_en,d0=cs_en h = ((h << 2) | (m >> 6)) & 0x1f; // maximum bank is 1f if (h) m = (m & 0x3f) | 0x40; // > bank 0 else m = m & 0x3f; // bank 0 set_adr (0x2000); // write 2000:h set_data_write write_data (h); // set ROM bank value set_ai_data ((unsigned char) 1, m); // a[15..8] set_ai_data ((unsigned char) 0, l); // a[7..0] out_byte_eeprom (data); // write data to EEPROM } static void out_adr2_data (unsigned int adr, unsigned char data) // address shift 1 bit { set_adr_long (adr << 1, 1); // adr x 2 out_byte_eeprom (data); // write data to EEPROM } static void out_adr_data (unsigned int adr, unsigned char data) // real address { set_adr_long (adr, 0); out_byte_eeprom (data); // write data to EEPROM } static void out_adr_data_32k (unsigned int adr, unsigned char data) { set_adr (adr); out_byte_eeprom (data); // write data to EEPROM } static unsigned char read_byte (void) { set_ai (3); // default write mode set_data_read // ninit=0, nwrite=1 return read_data (); } static void enable_protection (void) { // set_bank (0x2000,0); // set bank 0 out_data (0, 0x55, 0x55, 0xaa); // adr2,adr1,adr0,data 05555:aa out_data (0, 0x2a, 0xaa, 0x55); out_data (0, 0x55, 0x55, 0xa0); } /* static void disable_protection (void) { out_data (0, 0x55, 0x55, 0xaa); // adr2,adr1,adr0,data 05555:aa out_data (0, 0x2a, 0xaa, 0x55); out_data (0, 0x55, 0x55, 0x80); out_data (0, 0x55, 0x55, 0xaa); out_data (0, 0x2a, 0xaa, 0x55); out_data (0, 0x55, 0x55, 0x20); delay_us (20000); } */ #if 0 static int data_polling_data (unsigned char last_data) { unsigned int timeout = 0; while (timeout++ < 0x07ffffff) if (((read_byte () ^ last_data) & 0x80) == 0) return 0; return 1; // ready to exit the while loop } #endif static int data_polling (void) { unsigned char predata, currdata; unsigned int timeout = 0; predata = read_byte () & 0x40; while (timeout++ < 0x07ffffff) { currdata = read_byte () & 0x40; if (predata == currdata) return 0; predata = currdata; } return 1; } static void reset_to_read (void) // return to read mode { out_adr2_data (0x5555, 0xaa); // 5555:aa adr2,adr1,adr0,data out_adr2_data (0x2aaa, 0x55); // 2aaa:55 out_adr2_data (0x5555, 0xf0); // 5555:f0 } /* static void read_status_reg_cmd (void) { out_adr2_data (0x5555, 0xaa); // 5555:aa adr2,adr1,adr0,data out_adr2_data (0x2aaa, 0x55); // 2aaa:55 out_adr2_data (0x5555, 0x70); // 5555:70 } */ static int wait_status (void) { unsigned temp = read_byte (); // read first status byte while ((temp & 0xfc) != 0x80) { if ((temp & 0x20) == 0x20 && port_mode == UCON64_SPP) { fputs ("\nERROR: Erase failed\n", stderr); return -1; } if ((temp & 0x10) == 0x10) { fputs ("\nERROR: Programming failed\n", stderr); return -2; } temp = read_data (); } // reset_to_read (); return 0; } static int mx_erase (void) { int retval; out_adr2_data (0x5555, 0xaa); // 5555:aa adr2,adr1,adr0,data out_adr2_data (0x2aaa, 0x55); // 2aaa:55 out_adr2_data (0x5555, 0x80); // 5555:80 out_adr2_data (0x5555, 0xaa); // 5555:aa out_adr2_data (0x2aaa, 0x55); // 2aaa:55 out_adr2_data (0x5555, 0x10); // 5555:10 delay_us (100); // read_status_reg_cmd (); // send read status reg. cmd retval = wait_status () ? -1 : 0; reset_to_read (); return retval; } /* static int win_erase (void) { out_data (0, 0x55, 0x55, 0xaa); // adr2,adr1,adr0,data 05555:aa out_data (0, 0x2a, 0xaa, 0x55); out_data (0, 0x55, 0x55, 0x80); out_data (0, 0x55, 0x55, 0xaa); out_data (0, 0x2a, 0xaa, 0x55); out_data (0, 0x55, 0x55, 0x10); delay_us (20000); if (data_polling ()) { fputs ("ERROR: Erase failed\n", stderr); return -1; } else return 0; } */ static unsigned char intel_read_status (void) { out_adr_data (0, 0x70); // read status command return read_byte (); } static int intel_check_status (void) { unsigned int time_out = 0x8000; while (!(intel_read_status () & 0x80)) { time_out--; if (time_out == 0) { fprintf (stderr, "\nERROR: Intel read status time out\n" " Status = 0x%02x\n", intel_read_status ()); out_adr_data (0, 0x50); // clear status register return -1; } } return 0; } static int intel_block_erase (unsigned int block) { unsigned int time_out = 0x8000; while ((intel_read_status ()) != 0x80) { time_out--; if (time_out == 0) { fprintf (stderr, "\nERROR: Intel block erase time out\n" " Status = 0x%02x\n", intel_read_status ()); return -1; } } out_adr_data (block, 0x20); // block erase out_adr_data (block, 0xd0); // write confirm time_out = 0x8000; while (!(intel_read_status () & 0x80)) { time_out--; if (time_out == 0) { fprintf (stderr, "\nERROR: Intel block erase time out at 0x%x\n" " Status = 0x%02x\n", block, intel_read_status ()); out_adr_data (block, 0x50); // clear status register fprintf (stderr, " Status = 0x%02x\n", intel_read_status ()); return -1; } } if ((intel_read_status ()) == 0x80) return 0; else { fprintf (stderr, "\nERROR: Intel block erase error at 0x%x\n" " Status = 0x%02x\n", block, intel_read_status ()); out_adr_data (block, 0x50); // clear status register fprintf (stderr, " Status = 0x%02x\n", intel_read_status ()); out_adr_data (0x0000, 0xff); // read array return -1; } } /* static int intel_erase (void) { unsigned int block; for (block = 0; block < 64; block++) if (intel_block_erase (block * 0x20000)) return -1; return 0; } static int erase (void) { if (eeprom_type == WINBOND) return win_erase (); else if (eeprom_type == MX) return mx_erase (); else if (eeprom_type == INTEL) return intel_erase (); fputs ("ERROR: Unknown EEPROM type\n", stderr); return -1; } */ static int check_eeprom (void) { int i; // check 4M flash out_adr_data_32k (0x5555, 0xaa); // software product ID entry out_adr_data_32k (0x2aaa, 0x55); out_adr_data_32k (0x5555, 0x80); out_adr_data_32k (0x5555, 0xaa); out_adr_data_32k (0x2aaa, 0x55); out_adr_data_32k (0x5555, 0x60); delay_us (10); set_adr (0); // adr2,adr1,adr0 if (read_byte () == 0xda) // manufacturer code { set_adr (1); // adr2,adr1,adr0 if (read_byte () == 0x46) // device code { out_adr_data_32k (0x5555, 0xaa); // software product ID exit out_adr_data_32k (0x2aaa, 0x55); // adr2,adr1,adr0,data out_adr_data_32k (0x5555, 0xf0); // adr2,adr1,adr0,data eeprom_type = WINBOND; // Winbond 4 Mbit flash return 0; } } // check 16M flash out_adr2_data (0x5555, 0xaa); // 5555:aa software product ID entry out_adr2_data (0x2aaa, 0x55); // 2aaa:55 adr2,adr1,adr0,data out_adr2_data (0x5555, 0x90); // 5555:90 adr2,adr1,adr0,data set_adr (0); // adr2,adr1,adr0 if (read_byte () == 0xc2) // manufacturer code { set_adr (2); // adr2,adr1,adr0 if (read_byte () == 0xf1) // device code { reset_to_read (); // reset to read mode eeprom_type = MX; // MX 16 Mbit flash return 0; } } // check 64M flash reset_to_read (); init_port (); out_adr_data (0x0000, 0x98); // read query for (i = 0; i < 128; i += 2) { set_adr (i); // adr2,adr1,adr0 buffer[i / 2] = read_byte (); } // dumper (stdout, buffer, 64, 0, DUMPER_HEX); if (buffer[0] == 0x89 && buffer[1] == 0x15 && buffer[0x10] == 'Q' && buffer[0x11] == 'R' && buffer[0x12] == 'Y') { out_adr_data (0x0000, 0xff); // read array eeprom_type = INTEL; // Intel 64 Mbit flash return 0; } // eeprom_type = UNKNOWN_EEPROM; return 1; } static void check_mbc (void) // determine memory bank controller type { if (eeprom_type != UNKNOWN_EEPROM) mbc_type = BUNG; else { unsigned char rom_type = buffer[0x47]; if (memcmp (buffer + 4, rocket_logodata, GB_LOGODATA_LEN) == 0) mbc_type = ROCKET; // rom_type == 0x97 || rom_type == 0x99 else if (rom_type == 0) mbc_type = ROM; else if ((rom_type >= 1 && rom_type <= 3) || rom_type == 0xff) mbc_type = MBC1; else if (rom_type == 5 || rom_type == 6) mbc_type = MBC2; else if (rom_type >= 0x0f && rom_type <= 0x13) mbc_type = MBC3; else if (rom_type >= 0x19 && rom_type <= 0x1e) mbc_type = MBC5; else if (rom_type == 0x1f) mbc_type = CAMERA; else mbc_type = UNKNOWN_MBC; } } static int check_card (void) /* 16 kB ROM = 1 bank 8 kB RAM = 1 bank */ { unsigned char sum = 0; char game_name[GB_NAME_LEN + 2]; int gb_name_len, i; puts ("Checking ROM data..."); if (mbc_type == ROCKET) puts ("NOTE: Rocket Games cartridge detected"); else if (memcmp (buffer + 4, gb_logodata, GB_LOGODATA_LEN) != 0) { puts ("WARNING: Cartridge does not contain official Nintendo logo data"); dumper (stdout, buffer, 0x50, 0x100, DUMPER_HEX); } gb_name_len = (buffer[0x43] == 0x80 || buffer[0x43] == 0xc0) ? GB_NAME_LEN : GB_NAME_LEN + 1; memcpy (game_name, buffer + 0x34, gb_name_len); game_name[gb_name_len] = 0; for (i = 0; i < gb_name_len; i++) if (!isprint ((int) game_name[i]) && game_name[i] != 0) game_name[i] = '.'; printf ("Game name: \"%s\"\n", game_name); if (buffer[0x48] > 8) // ROM size printf ("NOTE: Strange ROM size byte value in header (0x%02x)\n", buffer[0x48]); if (buffer[0x49] > 5) // SRAM size printf ("NOTE: Strange RAM size byte value in header (0x%02x)\n", buffer[0x49]); /* // [47] = ROM type if (buffer[0x47] > 0 && buffer[0x47] < 4 && buffer[0x48] > 4) mbc1_exp = 1; // MBC1 8 Mbit/16 Mbit */ for (i = 0x34; i < 0x4d; i++) sum += ~buffer[i]; if (buffer[0x4d] != sum) printf ("NOTE: Incorrect header checksum (0x%02x), should be 0x%02x\n", buffer[0x4d], sum); return (1 << (buffer[0x48] > 8 ? 9 : buffer[0x48])) * 32 * 1024; } static void set_sram_bank (unsigned char bank) // original code only did "set_adr (0x4000); out_byte (bank);" { if (eeprom_type != UNKNOWN_EEPROM) { // flash card set_adr (0x4000); // set SRAM adr out_byte (bank); // SRAM bank 0 // this should be equivalent to the code above: set_bank (0x4000, bank) } else { // game cartridge switch (mbc_type) { case MBC1: set_bank (0x6000, 1); set_bank (0x4000, (unsigned char) (bank & 3)); break; case MBC3: case MBC5: set_bank (0x4000, bank); break; default: break; } } } static void set_bank2 (unsigned int bank) { switch (mbc_type) { case BUNG: case UNKNOWN_MBC: case MBC5: set_bank (0x2000, (unsigned char) bank); if (eeprom_type != WINBOND) set_bank (0x3000, (unsigned char) (bank >> 8)); break; case MBC1: set_bank (0x6000, 0); set_bank (0x2000, (unsigned char) (bank & 0x1f)); set_bank (0x4000, (unsigned char) ((bank >> 5) & 3)); // (bank & 0x60) >> 5 break; case MBC2: set_bank (0x2100, (unsigned char) (bank & 0x0f)); break; case MBC3: set_bank (0x2000, (unsigned char) bank); break; case CAMERA: set_bank (0x4000, (unsigned char) bank); break; case ROCKET: set_bank (0x3f00, (unsigned char) bank); break; default: break; } } static void read_rom_16k (unsigned int bank) // ROM or EEPROM { int idx = 0, i, j; char game_name[GB_NAME_LEN + 2]; set_bank2 (bank); for (j = 0; j < 64; j++) { // 16k bytes = 64 x 256 bytes if (bank) set_ai_data ((unsigned char) 1, (unsigned char) (j | 0x40)); // set adr[15..8] else set_ai_data ((unsigned char) 1, (unsigned char) j); // a[15..0] set_ai_data ((unsigned char) 0, 0); // a[7..0] set_ai_data ((unsigned char) 2, 0x81); // enable read inc. set_ai (3); // read/write data set_data_read for (i = 0; i < 256; i++) // page = 256 buffer[idx + i] = read_data (); idx += 256; /* One can select the game in 2-in-1 cartridges by writing the game number to 0x3fc0. This has been verified for 2 cartridges with ROM type byte value 0x99. Maybe there exist other Rocket Games n-in-1 games with a different ROM type byte value. That's why we don't check for that specific ROM type byte value. */ if (mbc_type == ROCKET && j == 1) if (memcmp (buffer + 0x104, rocket_logodata, GB_LOGODATA_LEN) == 0) { set_adr (0x3fc0); out_byte ((unsigned char) rocket_game_no++); if (bank) { // Reread the last two pages, because the data came from the // previously selected game (data is "mirrored"). This does not // apply to the first game. int k, gb_name_len; idx = 0; for (k = 0; k < 2; k++) { set_ai_data ((unsigned char) 1, (unsigned char) (k | 0x40)); set_ai_data ((unsigned char) 0, 0); set_ai_data ((unsigned char) 2, 0x81); set_ai (3); set_data_read for (i = 0; i < 256; i++) buffer[idx + i] = read_data (); idx += 256; } clear_line (); // remove last gauge gb_name_len = (buffer[0x143] == 0x80 || buffer[0x143] == 0xc0) ? GB_NAME_LEN : GB_NAME_LEN + 1; memcpy (game_name, buffer + 0x134, gb_name_len); game_name[gb_name_len] = 0; for (i = 0; i < gb_name_len; i++) if (!isprint ((int) game_name[i]) && game_name[i] != 0) game_name[i] = '.'; printf ("Found another game: \"%s\"\n\n", game_name); } } } } static int verify_rom_16k (unsigned int bank) // ROM or EEPROM { int idx = 0, i, j; set_bank2 (bank); for (j = 0; j < 64; j++) { // 16k bytes = 64 x 256 bytes if (bank) set_ai_data ((unsigned char) 1, (unsigned char) (j | 0x40)); // set adr[15..8] else set_ai_data ((unsigned char) 1, (unsigned char) j); set_ai_data ((unsigned char) 0, 0); // a[7..0] set_ai_data ((unsigned char) 2, 0x81); // enable read inc. set_ai (3); // read/write data set_data_read for (i = 0; i < 256; i++) if (read_data () != buffer[idx + i]) { printf ("\nWARNING: Verify error at 0x%x\n", (bank * 16384) + (j * 256) + i); return -1; } idx += 256; } return 0; } static int win_write_eeprom_16k (unsigned int bank) { int wr_done, err_cnt, idx = 0, i, j; // disable_protection (); for (j = 0; j < 64; j++) { // 16k bytes = 64 x 256 bytes err_cnt = 16; // retry write counter wr_done = 1; while (wr_done) { enable_protection (); // write 256 bytes set_bank (0x2000, (unsigned char) bank); // for MCB1 16k bank if (bank) set_ai_data ((unsigned char) 1, (unsigned char) (j | 0x40)); // set adr[15..8] else set_ai_data ((unsigned char) 1, (unsigned char) j); set_ai_data ((unsigned char) 0, 0); // a[7..0] // set_ai_data ((unsigned char) 2, 0x82); // enable flash write set_ai_data ((unsigned char) 2, 0x83); // enable flash write inc. set_ai (3); // read/write data // set_ai_data ((unsigned char) 2, 0x80); for (i = 0; i < 256; i++) write_data (buffer[idx + i]); // write data to EEPROM set_ai_data ((unsigned char) 2, 0x80); // disable wr/rd inc. set_ai_data ((unsigned char) 0, 0xff); // point to xxff if (data_polling ()) puts ("\nWARNING: Write error"); // was: "Write error check (d6)" wr_done = 0; // verify 256 bytes set_ai_data ((unsigned char) 0, 0); // a[7..0] set_ai_data ((unsigned char) 2, 0x81); // enable read inc. set_ai (3); // read/write data set_data_read for (i = 0; i < 256; i++) if (read_data () != buffer[idx + i]) { err_cnt--; wr_done = 1; break; } if (err_cnt == 0) { fputs ("\nERROR: Programming failed after retry\n", stderr); return -1; } } idx += 256; } /* enable_protection(); disable_protection(); delay_us (20000); */ return verify_rom_16k (bank); } static void set_page_write (void) // start page write command { out_adr2_data (0x5555, 0xaa); // 5555:aa adr2,adr1,adr0,data out_adr2_data (0x2aaa, 0x55); // 2aaa:55 out_adr2_data (0x5555, 0xa0); // 5555:a0 } static int page_write_128 (unsigned int bank, unsigned char hi_lo, int j, int idx) { int retry = 3, verify_ok, i; while (retry) { set_page_write (); // each page is 128 bytes set_bank (0x2000, (unsigned char) bank); // for MCB1 16k bank if (bank) set_ai_data ((unsigned char) 1, (unsigned char) (j | 0x40)); // set adr[15..8] else set_ai_data ((unsigned char) 1, (unsigned char) j); set_ai_data ((unsigned char) 0, hi_lo); // a[7..0] set_ai_data ((unsigned char) 2, 0x83); // enable flash write inc. set_ai (3); // read/write data for (i = 0; i < 128; i++) write_data (buffer[idx + i]); // write data to EEPROM set_ai_data ((unsigned char) 2, 0x80); // disable wr/rd inc. delay_us (10); // delay is large enough? - dbjh if (wait_status ()) return -1; // wait_status() prints error message // verify data reset_to_read (); // return to read mode verify_ok = 1; // verify OK set_bank (0x2000, (unsigned char) bank); // for MCB1 16k bank if (bank) set_ai_data ((unsigned char) 1, (unsigned char) (j | 0x40)); // set adr[15..8] else set_ai_data ((unsigned char) 1, (unsigned char) j); set_ai_data ((unsigned char) 0, hi_lo); // a[7..0] set_ai_data ((unsigned char) 2, 0x81); // enable inc. set_ai (3); // read/write data set_data_read for (i = 0; i < 128; i++) // page = 128 if (read_data () != buffer[idx + i]) { verify_ok = 0; // verify error break; } if (verify_ok) break; else { retry--; if (retry == 0) { fputs ("\nERROR: Programming failed after retry\n", stderr); return -1; } } } return 0; } static int mx_write_eeprom_16k (unsigned int bank) { int idx = 0, j; for (j = 0; j < 64; j++) { // 16k bytes = 64 x 256 bytes if (page_write_128 (bank, 0, j, idx)) // write first 128 bytes return -1; idx += 128; if (page_write_128 (bank, 0x80, j, idx)) // write second 128 bytes return -1; idx += 128; } reset_to_read (); // return to read mode return verify_rom_16k (bank); } /* static void dump_intel_data (void) { int i; out_adr_data (0, 0xff); // read array command for (i = 0; i < 64; i++) { // read 0x100-0x150 to buffer set_adr (i); buffer[i] = read_data (); } dumper (stdout, buffer, 64, 0, DUMPER_HEX); } static int intel_byte_write_32 (unsigned int block_adr, int idx) { int time_out, i; for (i = 0; i < 32; i++) { out_adr_data (block_adr + idx + i, 0x40); // Write byte command out_adr_data (block_adr + idx + i, buffer[idx + i]); // Write data time_out = 0x8000; if (intel_check_status ()) { fprintf (stderr, "\nERROR: Intel byte write command time out\n" " Status = 0x%02x\n", intel_read_status ()); // dump_intel_data (); return -1; } } if (intel_read_status () == 0x80) return 0; else return -1; // error } */ static int intel_buffer_write_32 (unsigned int block_adr, int idx) { int time_out = 0x80000, i; out_adr_data (block_adr + idx, 0xe8); // Write buffer command set_ai_data ((unsigned char) 2, 0x82); // wei enable set_ai (3); // default write mode // write_data (0xe8); // Write buffer command set_data_read // ninit=0, nwrite=1 while (!(read_data () & 0x80)) { time_out--; if (time_out == 0) { fprintf (stderr, "\nERROR: Intel buffer write command time out\n" " Status = 0x%02x\n", intel_read_status ()); // dump_intel_data (); return -1; } set_data_write write_data (0xe8); // out data set_data_read // out_byte_eeprom (0xe8); // write buffer command } // out_byte_eeprom (0x1f); // set write byte count command write_data (0x1f); // out data set_ai_data ((unsigned char) 2, 0x83); // enable flash write inc. set_ai (3); for (i = 0; i < 32; i++) write_data (buffer[idx + i]); // write data to EEPROM write_data (0xd0); // write confirm command return 0; } static int intel_write_eeprom_16k (unsigned int bank) { unsigned int block_adr = bank << 14; // convert to real address int idx, j; if ((bank & 0x07) == 0) if (intel_block_erase (block_adr)) return -1; // set_adr_long (block_adr, 0); // set real address for (j = 0; j < 512; j++) { // 16k bytes = 512 x 32 bytes idx = j * 32; // if (intel_byte_write_32 (block_adr, idx)) return -1; if (intel_buffer_write_32 (block_adr, idx)) { fprintf (stderr, "\nERROR: Write error\n" " Status = 0x%02x\n", intel_read_status ()); return -1; } } if (intel_check_status ()) { fprintf (stderr, "\nERROR: Intel buffer write command error\n" " Status = 0x%02x\n", intel_read_status ()); // dump_intel_data(); return -1; } if (intel_read_status () != 0x80) return -1; // error out_adr_data (0, 0xff); // read array set_data_read return verify_rom_16k (bank); } static int write_eeprom_16k (unsigned int bank) { if (eeprom_type == WINBOND) // Winbond 4 Mbits EEPROM return win_write_eeprom_16k (bank); if (eeprom_type == MX) // MX 16 Mbits EEPROM return mx_write_eeprom_16k (bank); if (eeprom_type == INTEL) // Intel 64 Mbits EEPROM return intel_write_eeprom_16k (bank); return -1; } static void enable_sram_bank (void) { init_port (); set_adr (0x0000); // write 0x0000:0x0a default read mode out_byte (0x0a); // enable SRAM out_byte (0xc0); // disable SRAM set_adr (0xa000); out_byte (0xa0); // ctr index set_adr (0xa100); // out_byte(0x00); // ram_off,ram_bank_disable,MBC1 out_byte (0xc0); // ram_on,ram_bank_enable,MBC1 set_adr (0x0000); // write 0x0000:0x0a out_byte (0x0a); // enable SRAM } /* static void usage (char *progname) { fprintf (stderr, "Usage: %s [-option] \n", progname); fprintf (stderr, "-l : load ROM file to GB Card.\n"); fprintf (stderr, "-lsa : load 256k/1Mbits sram from PC to GB Card.\n"); fprintf (stderr, "-lsn : load 64kbits sram file from PC to specific sram bank(-n) in GB card.\n"); fprintf (stderr, "-lsc : load 1Mbits sram file from PC to Pocket Camera.\n"); fprintf (stderr, "-b : auto-detect size and backup entire GB Card to PC.\n"); fprintf (stderr, "-ba : backup full 4Mbits/16Mbits GB Card to PC.\n"); fprintf (stderr, "-bsa : retrieve all sram data (256k/1Mbits) from GB Card to PC.\n"); fprintf (stderr, "-bsn : retrieve specific bank(-n) sram data(64kbits) from GB Card to PC.\n"); fprintf (stderr, "-bsc : retrieve 1Mbits sram from Pocket Camera to PC.\n"); fprintf (stderr, "-v : verify file in PC with GB Card.\n"); fprintf (stderr, "-e : erase Flash rom.\n"); fprintf (stderr, "-c : check ROM file header.\n"); exit (2); } */ static int check_port_mode (void) { init_port (); set_ai_data ((unsigned char) 1, 0x12); set_ai_data ((unsigned char) 0, 0x34); set_ai (1); set_data_read // ninit=0, nwrite=1 if (read_data () != 0x12) return 1; set_ai (0); set_data_read // ninit=0, nwrite=1 if (read_data () != 0x34) return 1; end_port (); return 0; } static int check_port (void) { if (ucon64.parport_mode == UCON64_EPP && port_8 != 0x3bc) port_mode = UCON64_EPP; // if port == 0x3bc => no EPP available else port_mode = UCON64_SPP; if (check_port_mode ()) { port_mode = UCON64_SPP; if (check_port_mode ()) return 1; else end_port (); } // If we get here, a GBX was detected if (port_mode == UCON64_EPP) puts ("GBX found. EPP found"); else puts ("GBX found. EPP not found or not enabled - SPP used"); return 0; } #if 0 // not used static void win_id (void) { out_data (0, 0x55, 0x55, 0xaa); // software product ID entry out_data (0, 0x2a, 0xaa, 0x55); // adr2,adr1,adr0,data out_data (0, 0x55, 0x55, 0x80); // adr2,adr1,adr0,data out_data (0, 0x55, 0x55, 0xaa); // adr2,adr1,adr0,data out_data (0, 0x2a, 0xaa, 0x55); // adr2,adr1,adr0,data out_data (0, 0x55, 0x55, 0x60); // adr2,adr1,adr0,data delay_us (10); set_adr (0); // adr2,adr1,adr0 printf ("Manufacturer code: 0x%02x\n", read_byte ()); set_adr (1); // adr2,adr1,adr0 printf ("Device code: 0x%02x\n", read_byte ()); /* set_adr (2); // adr2,adr1,adr0 printf ("First 16 k protection code: 0x%02x\n", read_byte ()); set_bank (0x2000, 0x1f); set_adr (0x7ff2); // adr2,adr1,adr0=0x7fff2 printf("Last 16 k protection code: 0x%02x\n", read_byte ()); */ out_data (0, 0x55, 0x55, 0xaa); // software product ID exit out_data (0, 0x2a, 0xaa, 0x55); // adr2,adr1,adr0,data out_data (0, 0x55, 0x55, 0xf0); // adr2,adr1,adr0,data } static void mx_id (void) { out_adr2_data (0x5555, 0xaa); // software product ID entry out_adr2_data (0x2aaa, 0x55); // adr2,adr1,adr0,data out_adr2_data (0x5555, 0x90); // adr2,adr1,adr0,data set_adr (0); // adr2,adr1,adr0 printf ("Manufacturer code: 0x%02x\n", read_byte ()); set_adr (2); // adr2,adr1,adr0 printf ("Device code: 0x%02x\n", read_byte ()); set_adr (4); // adr2,adr1,adr0 printf ("First 16 k protection code: 0x%02x\n", read_byte ()); reset_to_read (); // reset to read mode } static void intel_id (void) { int i; out_adr_data (0, 0x98); // read query for (i = 0; i < 128; i += 2) { set_adr (i); // adr2,adr1,adr0 buffer[i / 2] = read_byte (); } // dumper (stdout, buffer, 64, 0, DUMPER_HEX); printf ("Manufacture code = 0x%02x\n", buffer[0]); printf ("Device code = 0x%02x\n", buffer[1]); } static void disp_id (void) { if (eeprom_type == WINBOND) win_id (); if (eeprom_type == MX) mx_id (); if (eeprom_type == INTEL) intel_id (); } static void gen_pat (unsigned int offset) { int i; for (i = 0; i < 0x2000; i++) // 8 k words = 16 k bytes ((unsigned short int *) buffer)[i] = i + offset; } static int test_sram_v (int n_banks) { int idx, i, j, bank; enable_sram_bank (); for (bank = 0; bank < n_banks; bank++) { idx = 0; set_sram_bank (bank); gen_pat (bank); for (j = 0; j < 0x20; j++) { // 32 x 256 = 8192 (8 kbytes) set_ai_data ((unsigned char) 1, (unsigned char) (0xa0 + j)); // SRAM at 0xa000-0xbfff set_ai_data ((unsigned char) 0, 0); // a[7..0]=0 set_ai_data ((unsigned char) 2, 0x81); // enable inc set_ai (3); // point to data r/w port set_data_read for (i = 0; i < 256; i++) if (read_data () != buffer[i + idx]) { fputs ("ERROR: SRAM verify error\n", stderr); return -1; } set_ai_data ((unsigned char) 2, 0x80); // disable inc idx += 256; } } return 0; } static int test_sram_wv (int n_banks) { int idx, i, j, bank; enable_sram_bank (); for (bank = 0; bank < n_banks; bank++) { idx = 0; set_sram_bank (bank); gen_pat (bank); // dumper (stdout, buffer, 0x10, 0, DUMPER_HEX); for (j = 0; j < 0x20; j++) { // 32 x 256 = 8192(8kbytes) set_ai_data ((unsigned char) 1, (unsigned char) (0xa0 + j)); // SRAM at 0xa000-0xbfff set_ai_data ((unsigned char) 0, 0); // a[7..0]=0 set_ai_data ((unsigned char) 2, 0x81); // enable inc set_ai (3); // point to data r/w port set_data_write for (i = 0; i < 256; i++) write_data (buffer[i + idx]); set_ai_data ((unsigned char) 2, 0x80); // disable inc idx += 256; } } return test_sram_v (n_banks); } int cart_type = 0; // should be set to value of ROM[0x147] static void set_rom_bank (unsigned char bank) { // cart_type < 4 is MCB1, other is MCB2 if (cart_type < 4) set_bank (0x2000, bank); // for MCB1 else set_bank (0x2100, bank); // for MCB2 } static void try_read (void) { int i; set_ai_data ((unsigned char) 0, 0); // a[7..0]=0 set_ai_data ((unsigned char) 1, 0x40); set_ai_data ((unsigned char) 2, 0x81); // enable inc set_ai (3); // point to data r/w port for (i = 0; i < 16; i++) buffer[i] = read_data (); dumper (stdout, buffer, 16, 0, DUMPER_HEX); } static void try_read0 (void) { int j; set_rom_bank (1); for (j = 0; j < 4; j++) { set_sram_bank ((unsigned char) j); try_read (); } set_bank (0x6000, (unsigned char) 1); puts ("6000:1"); for (j = 0; j < 4; j++) { set_sram_bank ((unsigned char) j); try_read (); } set_bank (0x6000, (unsigned char) 0); puts ("6000:0"); for (j = 0; j < 4; j++) { set_sram_bank ((unsigned char) j); try_read (); } } static void test_intel (void) { int i; out_adr2_data (0x0000, 0x90); // software product ID entry for (i = 0; i < 128; i += 2) { set_adr (i); // adr2,adr1,adr0 buffer[i / 2] = read_byte (); } dumper (stdout, buffer, 64, 0, DUMPER_HEX); out_adr2_data (0x0000, 0x70); // read status register printf ("Status register = 0x%02x\n", read_byte ()); } static void gbx_init (unsigned short parport, int read_header); static int verify_card_from_file (const char *filename, unsigned int parport) { unsigned int bank, n_banks, filesize; FILE *file; time_t starttime; gbx_init (parport, 1); filesize = fsizeof (filename); if ((filesize < 0x8000) || (filesize & 0x7fff) || (filesize > 64 * MBIT)) { fputs ("ERROR: File size error\n", stderr); exit (1); } if ((file = fopen (filename, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename); exit (1); } n_banks = (filesize / 0x8000) * 2; // how many 16k banks (rounded starttime = time (NULL); // down to 32k boundary) for (bank = 0; bank < n_banks; bank++) { if (fread (buffer, 1, 0x4000, file) != 0x4000) { fprintf (stderr, ucon64_msg[READ_ERROR], filename); fclose (file); exit (1); } /* if (bank == 0) { // [0x147] = ROM type; [0x148] = ROM size if (buffer[0x147] > 0 && buffer[0x147] < 4 && buffer[0x148] > 4) mbc1_exp = 1; // MBC1 8 Mbit/16 Mbit } */ if (verify_eeprom_16k (bank)) { printf ("Verify card error at bank 0x%x\n", bank); fclose (file); exit (1); } ucon64_gauge (starttime, (bank + 1) * 0x4000, filesize); } fclose (file); puts ("\nVerify card OK"); return 0; } #endif static void gbx_init (unsigned short parport, int read_header) { int i; eeprom_type = UNKNOWN_EEPROM; rocket_game_no = 0; port_8 = parport; port_9 = parport + 1; port_a = parport + 2; port_b = parport + 3; port_c = parport + 4; parport_print_info (); if (check_port () != 0) { fputs ("ERROR: GBX not found or not turned on\n", stderr); exit (1); } init_port (); check_eeprom (); if (read_header) for (i = 0x100; i < 0x150; i++) { // read 0x100-0x150 to buffer set_adr (i); buffer[i - 0x100] = read_data (); } /* buffer is undefined if read_header == 0. This is not a problem as read_header is only 0 if a flash card should be programmed (gbx_write_rom()). In that case check_mbc() won't use buffer. */ check_mbc (); } int gbx_read_rom (const char *filename, unsigned short parport) { unsigned int bank, n_banks, rom_size, n_bytes = 0, totalbytes; time_t starttime; FILE *file; gbx_init (parport, 1); rom_size = check_card (); if ((file = fopen (filename, "wb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename); end_port (); exit (1); } /* 0 256 kbit = 32 kB = 2 banks 1 512 kbit = 64 kB = 4 banks 2 1 Mbit = 128 kB = 8 banks 3 2 Mbit = 256 kB = 16 banks 4 4 Mbit = 512 kB = 32 banks 5 8 Mbit = 1 MB = 64 banks 6 16 Mbit = 2 MB = 128 banks */ n_banks = rom_size / (16 * 1024); if (eeprom_type == WINBOND) n_banks = 32; // backup 4 Mbit if (eeprom_type == MX) n_banks = 128; // backup 16 Mbit if (eeprom_type == INTEL) n_banks = 512; // backup 64 Mbit totalbytes = n_banks * 16 * 1024; printf ("Receive: %d Bytes (%.4f Mb)\n\n", totalbytes, (float) totalbytes / MBIT); starttime = time (NULL); for (bank = 0; bank < n_banks; bank++) { read_rom_16k (bank); if (verify_rom_16k (bank)) printf ("Verify card error at bank 0x%x\n", bank); fwrite (buffer, 1, 0x4000, file); n_bytes += 16 * 1024; ucon64_gauge (starttime, n_bytes, totalbytes); } fclose (file); end_port (); return 0; } int gbx_write_rom (const char *filename, unsigned short parport) { int bank, n_banks, n_bytes = 0; time_t starttime; FILE *file; gbx_init (parport, 0); if (eeprom_type == UNKNOWN_EEPROM) { fputs ("ERROR: Unknown EEPROM type\n", stderr); end_port (); exit (1); } if ((ucon64.file_size < 0x8000) || (ucon64.file_size & 0x7fff) || (ucon64.file_size > 64 * MBIT)) { fputs ("ERROR: File size error\n", stderr); exit (1); } n_banks = (ucon64.file_size / 0x8000) * 2; // how many 16k banks (rounded // down to 32k boundary) if (eeprom_type == MX) if (mx_erase ()) // erase 16M flash { // wait_status() prints error message end_port (); exit (1); } if ((file = fopen (filename, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename); end_port (); exit (1); } printf ("Send: %d Bytes (%.4f Mb)\n\n", n_banks * 0x4000, (float) (n_banks * 0x4000) / MBIT); starttime = time (NULL); for (bank = 0; bank < n_banks; bank++) { if (fread (buffer, 1, 0x4000, file) != 0x4000) { fprintf (stderr, ucon64_msg[READ_ERROR], filename); fclose (file); end_port (); exit (1); } if (write_eeprom_16k (bank)) { fprintf (stderr, "ERROR: Write card error at bank 0x%x\n", bank); fclose (file); end_port (); exit (1); } n_bytes += 0x4000; ucon64_gauge (starttime, n_bytes, ucon64.file_size); } #if 0 // write_eeprom_16k() already calls verify_rom_16k() (indirectly)... clear_line (); // remove last gauge puts ("Verifying card...\n"); fseek (file, 0, SEEK_SET); n_bytes = 0; starttime = time (NULL); for (bank = 0; bank < n_banks; bank++) { if (fread (buffer, 1, 0x4000, file) != 0x4000) { fprintf (stderr, ucon64_msg[READ_ERROR], filename); fclose (file); end_port (); exit (1); } if (verify_rom_16k (bank)) { fprintf (stderr, "ERROR: Verify card error at bank 0x%x\n", bank); fclose (file); end_port (); exit (1); } n_bytes += 0x4000; ucon64_gauge (starttime, n_bytes, ucon64.file_size); } #endif fclose (file); end_port (); return 0; } static int sram_size_banks (int pocket_camera, unsigned char sram_size_byte) { int n_banks; if (eeprom_type == UNKNOWN_EEPROM) { // it seems reasonable that eeprom_type == UNKNOWN_EEPROM when a pocket // camera (1 Mbit SRAM) is plugged in the GBX if (pocket_camera) n_banks = 16; else // no flash card, must be game cartridge { int x = (sram_size_byte & 7) << 1; if (x > 5) x = 6; if (x) x = 1 << (x - 1); // SRAM size in kB n_banks = (x + 8192 - 1) / 8192; // round up to 1 bank if it's 2 kB } } else { // if eeprom_type != UNKNOWN_EEPROM, it has to be WINBOND, MX or INTEL (no // need to set n_banks to a default value) if (eeprom_type == WINBOND) n_banks = 4; // 4 x 8 kB = 32 kB else // if (eeprom_type == MX || eeprom_type == INTEL) n_banks = 16; // 16 x 8 kB = 128 kB } return n_banks; } int gbx_read_sram (const char *filename, unsigned short parport, int start_bank) { int bank, n_banks, n_bytes = 0, totalbytes, idx, i, j; time_t starttime; FILE *file; gbx_init (parport, 1); n_banks = sram_size_banks (buffer[0x47] == 0x1f, buffer[0x49]); if (!n_banks) { fputs ("ERROR: No SRAM available\n", stderr); end_port (); exit (1); } if (start_bank == -1) start_bank = 0; else { if (start_bank >= n_banks) { fprintf (stderr, "ERROR: Bank must be a value 0 - %d (for this card)\n", n_banks - 1); end_port (); exit (1); } n_banks = 1; } if ((file = fopen (filename, "wb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename); end_port (); exit (1); } memset (buffer, 0, 8192); totalbytes = n_banks * 8192; printf ("Receive: %d Bytes (%.4f Mb)\n\n", totalbytes, (float) totalbytes / MBIT); enable_sram_bank (); starttime = time (NULL); for (bank = start_bank; bank < start_bank + n_banks; bank++) { idx = 0; set_sram_bank ((unsigned char) bank); for (j = 0; j < 32; j++) { // 32 x 256 = 8192 (8 kbytes) set_ai_data ((unsigned char) 1, (unsigned char) (0xa0 + j)); // SRAM at 0xa000-0xbfff set_ai_data ((unsigned char) 0, 0); // a[7..0]=0 set_ai_data ((unsigned char) 2, 0x81); // enable inc set_ai (3); // point to data r/w port set_data_read for (i = 0; i < 256; i++) buffer[idx + i] = read_data (); set_ai_data ((unsigned char) 2, 0x80); // disable inc idx += 256; } fwrite (buffer, 1, 8192, file); n_bytes += 8192; ucon64_gauge (starttime, n_bytes, totalbytes); } fclose (file); end_port (); return 0; } int gbx_write_sram (const char *filename, unsigned short parport, int start_bank) { int bank, n_banks, n_bytes = 0, totalbytes, idx, i, j; time_t starttime; FILE *file; gbx_init (parport, 1); n_banks = sram_size_banks (buffer[0x47] == 0x1f, buffer[0x49]); if (!n_banks) { fputs ("ERROR: No SRAM to write to\n", stderr); end_port (); exit (1); } if (start_bank == -1) { start_bank = 0; n_banks = MIN (n_banks, (ucon64.file_size + 8192 - 1) / 8192); // "+ 8192 - 1" to round up } else { if (start_bank >= n_banks) { fprintf (stderr, "ERROR: Bank must be a value 0 - %d (for this card)\n", n_banks - 1); end_port (); exit (1); } n_banks = 1; } if ((file = fopen (filename, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename); end_port (); exit (1); } memset (buffer, 0, 8192); totalbytes = n_banks * 8192; // yes, we _send_ totalbytes bytes printf ("Send: %d Bytes (%.4f Mb)\n\n", totalbytes, (float) totalbytes / MBIT); enable_sram_bank (); starttime = time (NULL); for (bank = start_bank; bank < start_bank + n_banks; bank++) { idx = 0; if (!fread (buffer, 1, 8192, file)) { // handle/allow files that are not an exact multiple of 8 kB fprintf (stderr, ucon64_msg[READ_ERROR], filename); fclose (file); end_port (); exit (1); } set_sram_bank ((unsigned char) bank); for (j = 0; j < 32; j++) { // 32 x 256 = 8192 (8 kbytes) set_ai_data ((unsigned char) 1, (unsigned char) (0xa0 + j)); // SRAM at 0xa000-0xbfff set_ai_data ((unsigned char) 0, 0); // a[7..0]=0 set_ai_data ((unsigned char) 2, 0x81); // enable inc set_ai (3); // point to data r/w port set_data_write for (i = 0; i < 256; i++) write_data (buffer[idx + i]); set_ai_data ((unsigned char) 2, 0x80); // disable inc idx += 256; } n_bytes += 8192; ucon64_gauge (starttime, n_bytes, totalbytes); } fclose (file); end_port (); return 0; } #endif // USE_PARALLEL