1672 lines
40 KiB
C
1672 lines
40 KiB
C
/*
|
|
fal.c - Flash Linker Advance support for uCON64
|
|
|
|
Copyright (c) 2001 Jeff Frohwein
|
|
Copyright (c) 2001 NoisyB <noisyb@gmx.net>
|
|
Copyright (c) 2001 - 2004 dbjh
|
|
|
|
|
|
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.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include "misc/misc.h"
|
|
#include "misc/itypes.h"
|
|
#ifdef USE_ZLIB
|
|
#include "misc/archive.h"
|
|
#endif
|
|
#include "misc/getopt2.h" // st_getopt2_t
|
|
#include "ucon64.h"
|
|
#include "ucon64_misc.h"
|
|
#include "fal.h"
|
|
#include "misc/parallel.h"
|
|
#include "console/gba.h"
|
|
|
|
|
|
const st_getopt2_t fal_usage[] =
|
|
{
|
|
{
|
|
NULL, 0, 0, 0,
|
|
NULL, "Flash Advance Linker"/*"2001 Visoly http://www.visoly.com"*/,
|
|
NULL
|
|
},
|
|
#ifdef USE_PARALLEL
|
|
{
|
|
"xfal", 0, 0, UCON64_XFAL,
|
|
NULL, "send/receive ROM to/from Flash Advance Linker; " OPTION_LONG_S "port=PORT\n"
|
|
"receives automatically (32 Mbits) when ROM does not exist",
|
|
&ucon64_wf[WF_OBJ_GBA_DEFAULT_STOP_NO_ROM]
|
|
},
|
|
{
|
|
"xfalmulti", 1, 0, UCON64_XFALMULTI, // send only
|
|
"SIZE", "send multiple ROMs to Flash Advance Linker (makes temporary\n"
|
|
"multi-game file truncated to SIZE Mbit); specify a loader in\n"
|
|
"the configuration file; " OPTION_LONG_S "port=PORT",
|
|
&ucon64_wf[WF_OBJ_GBA_DEFAULT_STOP]
|
|
},
|
|
{
|
|
"xfalc", 1, 0, UCON64_XFALC,
|
|
"N", "receive N Mbits of ROM from Flash Advance Linker; " OPTION_LONG_S "port=PORT\n"
|
|
"N can be 8, 16, 32, 64, 128 or 256",
|
|
&ucon64_wf[WF_OBJ_GBA_STOP_NO_ROM]
|
|
},
|
|
{
|
|
"xfals", 0, 0, UCON64_XFALS,
|
|
NULL, "send/receive SRAM to/from Flash Advance Linker; " OPTION_LONG_S "port=PORT\n"
|
|
"receives automatically when SRAM does not exist",
|
|
&ucon64_wf[WF_OBJ_GBA_STOP_NO_ROM]
|
|
},
|
|
{
|
|
"xfalb", 1, 0, UCON64_XFALB,
|
|
"BANK", "send/receive SRAM to/from Flash Advance Linker BANK\n"
|
|
"BANK can be 1, 2, 3 or 4; " OPTION_LONG_S "port=PORT\n"
|
|
"receives automatically when SRAM does not exist",
|
|
&ucon64_wf[WF_OBJ_GBA_STOP_NO_ROM]
|
|
},
|
|
{
|
|
"xfalm", 0, 0, UCON64_XFALM,
|
|
NULL, "try to enable EPP mode, default is SPP mode",
|
|
&ucon64_wf[WF_OBJ_GBA_SWITCH]
|
|
},
|
|
#endif // USE_PARALLEL
|
|
{NULL, 0, 0, 0, NULL, NULL, NULL}
|
|
};
|
|
|
|
|
|
#ifdef USE_PARALLEL
|
|
|
|
/********************************************************/
|
|
/* Flash Linker Advance */
|
|
/* by Jeff Frohwein, 2001-Jun-28 */
|
|
/* Compiled with DJGPP & linux */
|
|
/********************************************************/
|
|
// V1.0 - 01/06/28 - Original release
|
|
// V1.1 - 01/06/29 - Add -w option to slow down I/O transfer for some.
|
|
// V1.11 - 01/06/30 - Set ECP chipsets to proper parallel port mode.
|
|
// V1.2 - 01/07/23 - Fixed programming bug for Visoly carts.
|
|
// - Only the first block was getting erased.
|
|
// - -v option now appears on help (-h) menu.
|
|
// - -v & -s options now work properly after fixing a bug.
|
|
// V1.3 - 01/07/24 - Added support for Visoly turbo carts.
|
|
// V1.4 - 01/07/27 - Added support for longer filenames.
|
|
// - Fixed bug where files the size of the cart overwrite
|
|
// the first 16 half-words of the cart. Thnx goes to
|
|
// Richard W for the code fix. Thanks Richard!
|
|
// Fixed random lockup bug when programming Turbo carts.
|
|
// Added -n option. Header is now repaired by default.
|
|
// V1.5 - 01/09/25 - Added error retries/checking for older Visoly carts.
|
|
// - Odd length files no longer give a verify error on last byte+1 location.
|
|
// V1.6 - 01/11/11 - Made IRQ 7 instead of 5 and DMA 3 instead of 1 default
|
|
// - linux values. (Thanks to Massimiliano Marsiglietti.)
|
|
// - Added -D & -I to allow linux to change IRQ & DMA defaults.
|
|
// - Added LPT3 support.
|
|
// - Added error checking for space between switch & parameters.
|
|
// - Added -2 options for faster operation for some EPP ports.
|
|
// V1.7 - 01/11/13 - Added -b option to backup game save SRAM or game save Flash.
|
|
// - Added -r option to restore game save SRAM. (No flash support.)
|
|
// V1.71 - 01/11/23 - Fixed bug introduced in v1.7 where -d option printed out twice.
|
|
// V1.72 - 01/12/12 - Force 0x96 at location 0xb2 in header since it's required.
|
|
|
|
// To compile source on linux:
|
|
// cc -o fl fl.c -O2
|
|
// You must have root access to run this under linux.
|
|
//
|
|
// NOTE: This file is filled with cr+lf line terminators. This may
|
|
// lead to unhelpful and weird error messages with gcc for linux.
|
|
// Strip out the cr characters to prevent this problem. The following
|
|
// unix command line will work for that:
|
|
// tr -d \\r < dosfile > unixfile
|
|
// On some unix distributions you can also use the following command:
|
|
// dos2unix
|
|
// (Thanks to Massimiliano Marsiglietti for locating this problem.)
|
|
|
|
// RAM Detect notes for dev. (Just ignore!)
|
|
//-----------------------------------------
|
|
// To detect backup type.
|
|
// 1. First check for eeprom.
|
|
// 2. Read byte from 0xe000000.
|
|
// 3. Write new byte to 0xe000000.
|
|
// 4. If diff, write back data & exit with SRAM detect flag.
|
|
// 5. If no diff get device Manuf ID for flash.
|
|
// 6. If no Manuf ID detected then report no cart backup available.
|
|
|
|
#define outpb(p, v) outportb((unsigned short) (p), (unsigned char) (v)); iodelay()
|
|
#define inpb(p) inportb((unsigned short) (p))
|
|
#define outpw(p, v) outportw((unsigned short) (p), (unsigned char) (v)); iodelay()
|
|
#define inpw(p) inportw((unsigned short) (p))
|
|
|
|
//#define HEADER_LENGTH 0xc0
|
|
//#define OUTBUFLEN 256 // Must be a multiple of 2! (ex:64,128,256...)
|
|
|
|
#define INTEL28F_BLOCKERASE 0x20
|
|
#define INTEL28F_CLEARSR 0x50
|
|
#define INTEL28F_CONFIRM 0xD0
|
|
#define INTEL28F_QUIRY 0x98
|
|
#define INTEL28F_READARRAY 0xff
|
|
#define INTEL28F_READSR 0x70
|
|
#define INTEL28F_RIC 0x90
|
|
#define INTEL28F_WRTOBUF 0xe8
|
|
|
|
#define SHARP28F_BLOCKERASE 0x20
|
|
#define SHARP28F_CONFIRM 0xD0
|
|
#define SHARP28F_READARRAY 0xff
|
|
#define SHARP28F_WORDWRITE 0x10
|
|
|
|
#define u8 unsigned char
|
|
#define u16 unsigned short int
|
|
#define u32 unsigned int
|
|
#define u64 unsigned long long int
|
|
// u64 is needed to compile cartlib.c without warnings on Linux/x86_64
|
|
#define CONST_U8 const unsigned char
|
|
|
|
|
|
// ***Global Variables ***
|
|
|
|
//int WaitDelay,WaitNCDelay;
|
|
unsigned SPPDataPort;
|
|
unsigned SPPStatPort;
|
|
unsigned SPPCtrlPort;
|
|
unsigned EPPAddrPort;
|
|
unsigned EPPDataPort;
|
|
unsigned ECPRegECR;
|
|
|
|
// prototypes
|
|
void WriteFlash (int addr, int data);
|
|
int ReadFlash (int addr);
|
|
void iodelay (void);
|
|
int PPReadWord (void);
|
|
void PPWriteWord (int i);
|
|
void SetCartAddr (int addr);
|
|
void l4021d0 (int i);
|
|
void l40226c (void);
|
|
|
|
#define FLINKER 1
|
|
|
|
#include "cartlib.c"
|
|
|
|
|
|
static int debug, verbose, DataSize16, Device, EPPMode, RepairHeader,
|
|
VisolyTurbo, WaitDelay, FileHeader[0xc0], HeaderBad, Complement = 0;
|
|
|
|
|
|
void
|
|
iodelay (void)
|
|
{
|
|
volatile int i;
|
|
for (i = 0; i < WaitDelay; i++)
|
|
{
|
|
i++;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ProgramExit (int code)
|
|
{
|
|
exit (code);
|
|
}
|
|
|
|
|
|
#if 0
|
|
void
|
|
usage (char *name)
|
|
{
|
|
char _small[255];
|
|
char smaller[255];
|
|
int i = 0;
|
|
|
|
strcpy (_small, name);
|
|
|
|
#if 0
|
|
if (strchr (name, '.') != NULL)
|
|
_small[strlen (_small) - 4] = 0; /* remove trailing file type */
|
|
#endif
|
|
|
|
while ((_small[strlen (_small) - i] != 0x2f) && /* loop until we find a / */
|
|
((strlen (_small) - i) > 0))
|
|
i++;
|
|
|
|
if ((strlen (_small) - i) == 0)
|
|
i++;
|
|
|
|
strcpy (smaller, (char *) (&_small[strlen (_small) - i + 1]));
|
|
|
|
fprintf (stderr, "GBA FLinker v1.72 by Jeff F.\n");
|
|
fprintf (stderr, "Usage: %s [options]\n", smaller);
|
|
|
|
fprintf (stderr,
|
|
"\t-2 Use 16bit EPP data path for faster operation (default=8bit)\n");
|
|
fprintf (stderr,
|
|
"\t-b o s file Backup game save SRAM or Flash to file\n");
|
|
fprintf (stderr, "\t (o = Bank Number [1-4])\n");
|
|
fprintf (stderr, "\t (s=1 - Backup 32K bytes to file.)\n");
|
|
fprintf (stderr, "\t (s=2 - Backup 64K bytes to file.)\n");
|
|
fprintf (stderr, "\t (s=3 - Backup 128K bytes to file.)\n");
|
|
fprintf (stderr, "\t (s=4 - Backup 256K bytes to file.)\n");
|
|
fprintf (stderr,
|
|
"\t-c n Specify chip size in mbits (8,16,32,64,128,256) (default=32)\n");
|
|
fprintf (stderr,
|
|
"\t-d n Dump 256 bytes of ROM to screen (default: n=0)\n");
|
|
fprintf (stderr, "\t-h This help screen\n");
|
|
fprintf (stderr,
|
|
"\t-l n Specify the parallel port to use (default is 1 = LPT1)\n");
|
|
// fprintf (stderr, "\t-m\tSet Standard Parallel Port (SPP) mode (default = EPP)\n");
|
|
fprintf (stderr,
|
|
"\t-n Do not repair incorrect header (default = repair header)\n");
|
|
fprintf (stderr, "\t-p file Program flash cart with file\n");
|
|
fprintf (stderr,
|
|
"\t-r o file Restore game save SRAM from file (No save flash support)\n");
|
|
fprintf (stderr, "\t (o = Bank Number [1-4])\n");
|
|
fprintf (stderr,
|
|
"\t-s file Save the cart into a file (Use -c to specify size)\n");
|
|
fprintf (stderr, "\t-v file Verify flash cart with file\n");
|
|
fprintf (stderr, "\t-w n Add delay to make transfer more reliable\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
InitPort (int port)
|
|
{
|
|
// uCON64 comment: see the comment in fal_main() where port is initialised
|
|
SPPDataPort = port;
|
|
SPPStatPort = SPPDataPort + 1;
|
|
SPPCtrlPort = SPPDataPort + 2;
|
|
EPPAddrPort = SPPDataPort + 3;
|
|
EPPDataPort = SPPDataPort + 4;
|
|
ECPRegECR = SPPDataPort + 0x402;
|
|
}
|
|
|
|
|
|
void
|
|
l4020a4 (int reg)
|
|
{
|
|
outpb (SPPCtrlPort, 1);
|
|
outpb (SPPDataPort, reg);
|
|
outpb (SPPCtrlPort, 9);
|
|
outpb (SPPCtrlPort, 1);
|
|
}
|
|
|
|
|
|
void
|
|
SPPWriteByte (int i) // l4020dc
|
|
{
|
|
outpb (SPPDataPort, i);
|
|
outpb (SPPCtrlPort, 3);
|
|
outpb (SPPCtrlPort, 1);
|
|
}
|
|
|
|
|
|
void
|
|
l402108 (int reg, int adr)
|
|
{
|
|
l4020a4 (reg);
|
|
SPPWriteByte (adr);
|
|
}
|
|
|
|
|
|
int
|
|
SPPReadByte (void) // 402124
|
|
{
|
|
int v;
|
|
|
|
outpb (SPPCtrlPort, 0);
|
|
outpb (SPPCtrlPort, 2);
|
|
v = ((inpb (SPPStatPort)) >> 3) & 0xf;
|
|
outpb (SPPCtrlPort, 6);
|
|
v += (((inpb (SPPStatPort)) << 1) & 0xf0);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
void
|
|
l402188 (int reg)
|
|
{
|
|
outpb (SPPCtrlPort, 1);
|
|
outpb (EPPAddrPort, reg);
|
|
}
|
|
|
|
|
|
void
|
|
l4021a8 (int reg, int adr)
|
|
{
|
|
l402188 (reg);
|
|
outpb (SPPCtrlPort, 1);
|
|
outpb (EPPDataPort, adr);
|
|
}
|
|
|
|
|
|
void
|
|
l4021d0 (int i)
|
|
{
|
|
outpb (SPPCtrlPort, 1);
|
|
|
|
if (EPPMode)
|
|
l402188 (i);
|
|
else
|
|
l4020a4 (i);
|
|
}
|
|
|
|
|
|
void
|
|
l402200 (int reg, int adr)
|
|
{
|
|
if (EPPMode)
|
|
l4021a8 (reg, adr);
|
|
else
|
|
l402108 (reg, adr);
|
|
}
|
|
|
|
|
|
void
|
|
l402234 (void)
|
|
{
|
|
if (EPPMode)
|
|
l402200 (4, 0x83);
|
|
else
|
|
l402200 (4, 0xc3);
|
|
}
|
|
|
|
|
|
void
|
|
l40226c (void)
|
|
{
|
|
if (EPPMode)
|
|
l402200 (4, 7);
|
|
else
|
|
l402200 (4, 0x47);
|
|
}
|
|
|
|
|
|
void
|
|
PPWriteByte (int i) // 4022d0
|
|
{
|
|
if (EPPMode)
|
|
{
|
|
outpb (EPPDataPort, i);
|
|
}
|
|
else
|
|
SPPWriteByte (i);
|
|
}
|
|
|
|
|
|
void
|
|
PPWriteWord (int i) // 4022d0
|
|
{
|
|
if (EPPMode)
|
|
{
|
|
if (DataSize16)
|
|
{
|
|
outpw (EPPDataPort, i);
|
|
}
|
|
else
|
|
{
|
|
outpb (EPPDataPort, i);
|
|
outpb (EPPDataPort, (i >> 8));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SPPWriteByte (i);
|
|
SPPWriteByte (i >> 8);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
PPReadByte (void) // 40234c
|
|
{
|
|
int v;
|
|
|
|
if (EPPMode)
|
|
v = inpb (EPPDataPort);
|
|
else
|
|
v = SPPReadByte ();
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
int
|
|
PPReadWord (void) // 402368 // ReadFlash
|
|
{
|
|
int v = 0;
|
|
|
|
if (EPPMode)
|
|
{
|
|
if (DataSize16)
|
|
v = inpw (EPPDataPort);
|
|
else
|
|
{
|
|
v = inpb (EPPDataPort);
|
|
v += (inpb (EPPDataPort) << 8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v = SPPReadByte (); //402124
|
|
v += (SPPReadByte () << 8);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
|
|
void
|
|
SetCartAddr (int addr) // 4023cc
|
|
{
|
|
l402200 (2, addr >> 16);
|
|
l402200 (1, addr >> 8);
|
|
l402200 (0, addr);
|
|
}
|
|
|
|
|
|
void
|
|
WriteFlash (int addr, int data) // 402414
|
|
{
|
|
SetCartAddr (addr);
|
|
l4021d0 (3);
|
|
PPWriteWord (data);
|
|
}
|
|
|
|
|
|
int
|
|
ReadFlash (int addr)
|
|
{
|
|
SetCartAddr (addr);
|
|
l4021d0 (3);
|
|
outpb (SPPCtrlPort, 0);
|
|
return PPReadWord ();
|
|
}
|
|
|
|
|
|
void
|
|
l402684 (void)
|
|
{
|
|
#ifndef USE_PPDEV
|
|
outpb (SPPStatPort, 1); // clear EPP time flag
|
|
#endif
|
|
l40226c ();
|
|
}
|
|
|
|
|
|
int
|
|
LookForLinker (void) // 4026a8
|
|
{
|
|
l402684 ();
|
|
l402200 (2, 0x12);
|
|
l402200 (1, 0x34);
|
|
l402200 (0, 0x56);
|
|
l4021d0 (2);
|
|
outpb (SPPCtrlPort, 0);
|
|
if (PPReadByte () != 0x12) // 40234c
|
|
return 0;
|
|
|
|
l4021d0 (1);
|
|
outpb (SPPCtrlPort, 0);
|
|
if (PPReadByte () != 0x34)
|
|
return 0;
|
|
|
|
l4021d0 (0);
|
|
outpb (SPPCtrlPort, 0);
|
|
if (PPReadByte () != 0x56)
|
|
return 0;
|
|
|
|
outpb (SPPCtrlPort, 4);
|
|
return 1;
|
|
}
|
|
|
|
|
|
void
|
|
LinkerInit (void) // 4027c4
|
|
{
|
|
int linker_found = 0;
|
|
|
|
/*
|
|
uCON64 comment:
|
|
Accessing I/O ports with addresses higher than 0x3ff causes an access
|
|
violation under Windows XP (NT/2000) for _Windows_ executables without the
|
|
use of an appropriate I/O port driver. UserPort is an example of an
|
|
*inappropriate* I/O port driver, because it enables access to I/O ports up
|
|
to 0x3ff. For some (ridiculous) reason, DOS executables are allowed to
|
|
_access_ at least the ECP register this code uses. That doesn't mean it
|
|
will result in the expected behaviour like enabling EPP.
|
|
*/
|
|
if (EPPMode)
|
|
{
|
|
/*
|
|
Writing to the ECP register seems to have no effect on my PC (which
|
|
supports ECP, used appropriate BIOS setting). Tested under Windows XP
|
|
with Windows executables (Cygwin, VC++ and MinGW) - dbjh
|
|
*/
|
|
#ifndef USE_PPDEV
|
|
outpb (ECPRegECR, 4); // set EPP mode for ECP chipsets
|
|
#endif
|
|
if (LookForLinker ())
|
|
{
|
|
// Linker found using EPP mode.
|
|
linker_found = 1;
|
|
puts ("Linker found. EPP found");
|
|
|
|
if (SPPDataPort == 0x3bc)
|
|
return;
|
|
outpb (SPPCtrlPort, 4);
|
|
}
|
|
}
|
|
if (!linker_found)
|
|
{
|
|
// Look for linker in SPP mode.
|
|
#ifndef USE_PPDEV
|
|
if (EPPMode)
|
|
outpb (ECPRegECR, 0); // set SPP mode for ECP chipsets
|
|
#endif
|
|
|
|
EPPMode = 0;
|
|
if (LookForLinker ())
|
|
puts ("Linker found. EPP not found or not enabled - SPP used");
|
|
else
|
|
{
|
|
fputs ("ERROR: Flash Advance Linker not found or not turned on\n",
|
|
stderr);
|
|
ProgramExit (1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
ReadStatusRegister (int addr) // 402dd8
|
|
{
|
|
int v;
|
|
WriteFlash (addr, INTEL28F_READSR);
|
|
outpb (SPPCtrlPort, 0);
|
|
v = PPReadWord (); // & 0xff;
|
|
v = PPReadWord (); // & 0xff;
|
|
return v;
|
|
}
|
|
|
|
|
|
// StartOffSet: 1 = 0, 2 = 64k, 3 = 128k, 4 = 192k
|
|
// Size: 1 = 32k, 2 = 64k, 3 = 128k, 4 = 256k
|
|
void
|
|
BackupSRAM (FILE *fp, int StartOS, int Size) // 4046f4
|
|
{
|
|
int j, k, v;
|
|
int m;
|
|
int n = 1 << (Size - 1);
|
|
int size = n * 32 * 1024, bytesread = 0;
|
|
time_t starttime;
|
|
|
|
printf ("Receive: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
|
|
|
|
starttime = time (NULL);
|
|
for (m = ((StartOS - 1) << 1); m < (((StartOS - 1) << 1) + n); m++)
|
|
{
|
|
if ((m & 1) == 0)
|
|
{
|
|
SetVisolyBackupRWMode (m >> 1);
|
|
l402234 ();
|
|
}
|
|
|
|
// Backup a 32k byte chunk
|
|
for (j = 0; j < 0x80; j++)
|
|
{
|
|
l402200 (0, 0);
|
|
l402200 (1, j + (0x80 * (m & 1)));
|
|
l402200 (2, 0);
|
|
l4021d0 (3);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
for (k = 0; k < 0x100; k++)
|
|
{
|
|
v = PPReadByte ();
|
|
fputc (v, fp);
|
|
}
|
|
bytesread += 256;
|
|
if ((bytesread & 0x1fff) == 0) // call ucon64_gauge() after receiving 8 kB
|
|
ucon64_gauge (starttime, bytesread, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// StartOffSet: 1 = 0, 2 = 64k, 3 = 128k, 4 = 192k
|
|
void
|
|
RestoreSRAM (FILE *fp, int StartOS)
|
|
{
|
|
int i;
|
|
int j, k;
|
|
int m = ((StartOS - 1) << 1);
|
|
int byteswritten = 0;
|
|
time_t starttime;
|
|
|
|
printf ("Send: %d Bytes (%.4f Mb)\n\n", ucon64.file_size,
|
|
(float) ucon64.file_size / MBIT);
|
|
|
|
starttime = time (NULL);
|
|
i = fgetc (fp);
|
|
while (!feof (fp))
|
|
{
|
|
if ((m & 1) == 0)
|
|
{
|
|
SetVisolyBackupRWMode (m >> 1);
|
|
l402234 ();
|
|
}
|
|
|
|
// Restore a 32k byte chunk
|
|
for (j = 0; j < 0x80; j++)
|
|
{
|
|
l402200 (0, 0);
|
|
l402200 (1, j + (0x80 * (m & 1)));
|
|
l402200 (2, 0);
|
|
l4021d0 (3);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
for (k = 0; k < 0x100; k++)
|
|
{
|
|
PPWriteByte (i);
|
|
i = fgetc (fp);
|
|
}
|
|
byteswritten += 256;
|
|
if ((byteswritten & 0x1fff) == 0) // call ucon64_gauge() after sending 8 kB
|
|
ucon64_gauge (starttime, byteswritten, ucon64.file_size);
|
|
}
|
|
m++;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BackupROM (FILE *fp, int SizekW)
|
|
{
|
|
u16 valw;
|
|
u32 i, j;
|
|
int size = SizekW << 1, bytesread = 0;
|
|
time_t starttime;
|
|
|
|
printf ("Receive: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
|
|
|
|
WriteFlash (0, INTEL28F_READARRAY); // Set flash (intel 28F640J3A) Read Mode
|
|
|
|
starttime = time (NULL);
|
|
for (i = 0; i < (u32) (SizekW >> 8); i++)
|
|
{
|
|
SetCartAddr (i << 8); // Set cart base addr to 0
|
|
l4021d0 (3);
|
|
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
valw = PPReadWord ();
|
|
fputc (valw & 0xff, fp);
|
|
fputc (valw >> 8, fp);
|
|
}
|
|
bytesread += 256 << 1; // 256 words
|
|
if ((bytesread & 0xffff) == 0) // call ucon64_gauge() after receiving 64 kB
|
|
ucon64_gauge (starttime, bytesread, size);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
dump (u8 BaseAdr)
|
|
{
|
|
// unsigned char low, high;
|
|
int i;
|
|
u8 First = 1;
|
|
u16 v;
|
|
u8 val1, val2;
|
|
u8 Display[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
WriteFlash (0, INTEL28F_READARRAY); // Set flash (intel 28F640J3A) Read Mode
|
|
|
|
SetCartAddr (BaseAdr << 7); // Set cart base addr to read
|
|
l4021d0 (3);
|
|
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
for (i = 0; i < 128; i++)
|
|
{
|
|
if (First == 1)
|
|
{
|
|
if (i * 2 < 256)
|
|
fputc ('0', stdout);
|
|
if (i * 2 < 16)
|
|
fputc ('0', stdout);
|
|
printf ("%hx - ", (i * 2));
|
|
First = 0;
|
|
}
|
|
|
|
v = PPReadWord ();
|
|
val2 = v >> 8;
|
|
val1 = v & 255;
|
|
|
|
if ((val1 > 31) & (val1 < 127))
|
|
Display[(i & 7) * 2] = val1;
|
|
else
|
|
Display[(i & 7) * 2] = 46;
|
|
|
|
if (val1 < 16)
|
|
fputc ('0', stdout);
|
|
printf ("%hx ", val1);
|
|
|
|
if ((val2 > 31) & (val2 < 127))
|
|
|
|
Display[(i & 7) * 2 + 1] = val2;
|
|
else
|
|
Display[(i & 7) * 2 + 1] = 46;
|
|
|
|
if (val2 < 16)
|
|
fputc ('0', stdout);
|
|
printf ("%hx ", val2);
|
|
|
|
if ((i & 7) == 7)
|
|
{
|
|
First = 1;
|
|
printf (" %3s\n", (&Display[0]));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CheckForFC (void)
|
|
{
|
|
LinkerInit ();
|
|
|
|
SetVisolyFlashRWMode ();
|
|
Device = CartTypeDetect ();
|
|
VisolyTurbo = 0;
|
|
|
|
printf ("Device ID = 0x%x: ", Device);
|
|
|
|
switch (Device)
|
|
{
|
|
case 0x16:
|
|
fputs ("FA 32M (i28F320J3A)", stdout);
|
|
break;
|
|
case 0x17:
|
|
fputs ("FA 64M (i28F640J3A)", stdout);
|
|
break;
|
|
case 0x18:
|
|
fputs ("FA 128M (i28F128J3A)", stdout);
|
|
break;
|
|
case 0x2e:
|
|
fputs ("Standard ROM", stdout);
|
|
break;
|
|
case 0x96:
|
|
fputs ("Turbo FA 64M (2 x i28F320J3A)", stdout);
|
|
VisolyTurbo = 1;
|
|
break;
|
|
case 0x97:
|
|
fputs ("Turbo FA 128M (2 x i28F640J3A)", stdout);
|
|
VisolyTurbo = 1;
|
|
break;
|
|
case 0x98:
|
|
fputs ("Turbo FA 256M (2 x i28F128J3A", stdout);
|
|
VisolyTurbo = 1;
|
|
break;
|
|
case 0xdc:
|
|
fputs ("Hudson", stdout);
|
|
break;
|
|
case 0xe2:
|
|
fputs ("Nintendo Flash Card (LH28F320BJE)", stdout);
|
|
break;
|
|
default:
|
|
fputs ("Unknown", stdout);
|
|
break;
|
|
}
|
|
fputc ('\n', stdout);
|
|
}
|
|
|
|
|
|
int
|
|
GetFileByte (FILE *fp)
|
|
{
|
|
static int FilePos = 0;
|
|
int i = 0;
|
|
|
|
if (RepairHeader)
|
|
{
|
|
// Set file pointer just past header
|
|
if (FilePos == 0)
|
|
for (i = 0; i < 0xa0; i++)
|
|
(void) fgetc (fp);
|
|
|
|
if (FilePos < 0xa0)
|
|
{
|
|
if ((HeaderBad) && (FilePos > 3))
|
|
i = gba_logodata[FilePos - 4]; // GoodHeader[FilePos];
|
|
else
|
|
i = FileHeader[FilePos];
|
|
}
|
|
else if ((FilePos == 0xb2) || (FilePos == 0xbd))
|
|
{
|
|
if (FilePos == 0xb2)
|
|
i = 0x96; // Required
|
|
else
|
|
i = Complement;
|
|
(void) fgetc (fp); // Discard file value
|
|
}
|
|
else
|
|
i = fgetc (fp);
|
|
}
|
|
else
|
|
i = fgetc (fp);
|
|
|
|
FilePos++;
|
|
return i;
|
|
}
|
|
|
|
|
|
int
|
|
GetFileSize2 (FILE *fp)
|
|
/*
|
|
The name "GetFileSize" conflicts with a Windows function.
|
|
For some odd reason Jeff Frohwein returned the file size minus 1. I (dbjh)
|
|
guess that's a bug. I disabled the (terribly inefficient) file size code
|
|
because uCON64 already determined the file size at this point.
|
|
*/
|
|
{
|
|
int FileSize;
|
|
|
|
if (RepairHeader)
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
FileSize = 0;
|
|
while (!feof (fp) && (FileSize < 0xc0))
|
|
FileHeader[FileSize++] = fgetc (fp);
|
|
|
|
if (feof (fp))
|
|
{
|
|
fputs ("ERROR: File must be 192 bytes or larger\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
HeaderBad = 0;
|
|
i = 4;
|
|
while (i < 0xa0) //9c)
|
|
{
|
|
if (FileHeader[i] != gba_logodata[i - 4]) // GoodHeader[i]
|
|
HeaderBad = 1;
|
|
i++;
|
|
}
|
|
if (HeaderBad)
|
|
puts ("NOTE: Fixing logo area");
|
|
|
|
Complement = 0;
|
|
FileHeader[0xb2] = 0x96; // Required
|
|
for (j = 0xa0; j < 0xbd; j++)
|
|
Complement += FileHeader[j];
|
|
Complement = (0 - (0x19 + Complement)) & 0xff;
|
|
//printf("[Complement = 0x%x]", (int)Complement);
|
|
//printf("[HeaderComp = 0x%x]", (int)FileHeader[0xbd]);
|
|
if (FileHeader[0xbd] != Complement)
|
|
puts ("NOTE: Fixing complement check");
|
|
|
|
rewind (fp);
|
|
}
|
|
else
|
|
rewind (fp);
|
|
|
|
return ucon64.file_size;
|
|
}
|
|
|
|
|
|
// Program older (non-Turbo) Visoly flash card
|
|
// (Single flash chip)
|
|
void
|
|
ProgramNonTurboIntelFlash (FILE *fp)
|
|
{
|
|
int i, j, k;
|
|
int addr = 0;
|
|
int FileSize;
|
|
int Ready = 0;
|
|
int Timeout;
|
|
time_t starttime;
|
|
|
|
// Get file size
|
|
FileSize = GetFileSize2 (fp);
|
|
|
|
puts ("Erasing Visoly non-turbo flash card...");
|
|
|
|
// Erase as many 128k blocks as are required
|
|
Ready = EraseNonTurboFABlocks (0, ((FileSize - 1) >> 17) + 1);
|
|
|
|
clear_line (); // remove "erase gauge"
|
|
if (Ready)
|
|
{
|
|
printf ("Send: %d Bytes (%.4f Mb)\n\n", FileSize, (float) FileSize / MBIT);
|
|
|
|
//403018
|
|
starttime = time (NULL);
|
|
j = GetFileByte (fp);
|
|
|
|
while (!feof (fp))
|
|
{
|
|
Ready = 0;
|
|
Timeout = 0x4000;
|
|
|
|
while ((Ready == 0) && (Timeout != 0))
|
|
{
|
|
WriteFlash (addr, INTEL28F_WRTOBUF);
|
|
outpb (SPPCtrlPort, 0);
|
|
Ready = PPReadWord () & 0x80;
|
|
|
|
Timeout--;
|
|
}
|
|
|
|
if (Ready)
|
|
{
|
|
WriteFlash (addr, 15); // Write 15+1 16bit words
|
|
|
|
SetCartAddr (addr); // Set cart base addr to 0
|
|
l4021d0 (3);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
k = j;
|
|
if (j != EOF)
|
|
j = GetFileByte (fp);
|
|
k += (j << 8);
|
|
PPWriteWord (k);
|
|
|
|
if (j != EOF)
|
|
j = GetFileByte (fp);
|
|
}
|
|
|
|
addr += 16;
|
|
if ((addr & 0x3fff) == 0) // call ucon64_gauge() after sending 32 kB
|
|
ucon64_gauge (starttime, addr << 1, FileSize);
|
|
|
|
PPWriteWord (INTEL28F_CONFIRM); // Comfirm block write
|
|
|
|
Ready = 0;
|
|
Timeout = 0x4000;
|
|
|
|
while ((Ready == 0) && (Timeout != 0))
|
|
{
|
|
WriteFlash (0, INTEL28F_READSR);
|
|
outpb (SPPCtrlPort, 0);
|
|
i = PPReadWord () & 0xff;
|
|
Ready = i & 0x80;
|
|
|
|
Timeout--;
|
|
}
|
|
|
|
if (Ready)
|
|
{
|
|
if (i & 0x7f)
|
|
{
|
|
// One or more status register error bits are set
|
|
outpb (SPPCtrlPort, 1);
|
|
WriteFlash (0, INTEL28F_CLEARSR);
|
|
Ready = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outpb (SPPCtrlPort, 1);
|
|
WriteFlash (0, INTEL28F_CLEARSR);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
clear_line (); // remove last gauge
|
|
ucon64_gauge (starttime, addr << 1, FileSize); // make gauge reach 100% when size % 32 k != 0
|
|
WriteFlash (0, INTEL28F_READARRAY);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
if (Ready)
|
|
;
|
|
else
|
|
fputs ("\nERROR: Flash card write failed\n", stderr);
|
|
}
|
|
else
|
|
fputs ("\nERROR: Flash card erase failed\n", stderr);
|
|
}
|
|
|
|
|
|
// Program newer (Turbo) Visoly flash card
|
|
// (Dual chip / Interleave)
|
|
void
|
|
ProgramTurboIntelFlash (FILE *fp)
|
|
{
|
|
int i, j = 0;
|
|
int k; //z;
|
|
int addr = 0;
|
|
int done1, done2;
|
|
int FileSize;
|
|
int Timeout;
|
|
int Ready; //= 0;
|
|
time_t starttime;
|
|
|
|
// Get file size
|
|
FileSize = GetFileSize2 (fp);
|
|
|
|
puts ("Erasing Visoly turbo flash card...");
|
|
|
|
// Erase as many 256k blocks as are required
|
|
Ready = EraseTurboFABlocks (0, ((FileSize - 1) >> 18) + 1);
|
|
|
|
clear_line (); // remove "erase gauge"
|
|
if (Ready)
|
|
{
|
|
printf ("Send: %d Bytes (%.4f Mb)\n\n", FileSize, (float) FileSize / MBIT);
|
|
|
|
//403018
|
|
starttime = time (NULL);
|
|
j = GetFileByte (fp);
|
|
|
|
while (!feof (fp))
|
|
{
|
|
done1 = 0;
|
|
done2 = 0;
|
|
Ready = 0;
|
|
Timeout = 0x4000;
|
|
|
|
while ((!Ready) && (Timeout != 0))
|
|
{
|
|
if (done1 == 0)
|
|
WriteFlash (addr + 0, INTEL28F_WRTOBUF);
|
|
if (done2 == 0)
|
|
WriteFlash (addr + 1, INTEL28F_WRTOBUF);
|
|
|
|
SetCartAddr (addr); // Set cart base addr
|
|
l4021d0 (3);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
done1 = PPReadWord () & 0x80;
|
|
done2 = PPReadWord () & 0x80;
|
|
Ready = ((done1 + done2) == 0x100);
|
|
|
|
Timeout--;
|
|
}
|
|
|
|
if (Ready)
|
|
{
|
|
WriteFlash (addr, 15); // Write 15+1 16bit words
|
|
PPWriteWord (15);
|
|
|
|
SetCartAddr (addr); // Set cart base addr
|
|
l4021d0 (3);
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
k = j;
|
|
if (j != EOF)
|
|
j = GetFileByte (fp);
|
|
k += (j << 8);
|
|
PPWriteWord (k);
|
|
|
|
if (j != EOF)
|
|
j = GetFileByte (fp);
|
|
}
|
|
addr += 32;
|
|
if ((addr & 0x3fff) == 0) // call ucon64_gauge() after sending 32 kB
|
|
ucon64_gauge (starttime, addr << 1, FileSize);
|
|
PPWriteWord (INTEL28F_CONFIRM); // Comfirm block write
|
|
PPWriteWord (INTEL28F_CONFIRM); // Comfirm block write
|
|
|
|
Ready = 0;
|
|
Timeout = 0x4000;
|
|
k = 0;
|
|
|
|
while (((k & 0x8080) != 0x8080) && (Timeout != 0))
|
|
{
|
|
outpb (SPPCtrlPort, 0);
|
|
k = PPReadWord () & 0xff;
|
|
k += ((PPReadWord () & 0xff) << 8);
|
|
Ready = (k == 0x8080);
|
|
|
|
Timeout--;
|
|
}
|
|
|
|
if (!Ready)
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
clear_line (); // remove last gauge
|
|
ucon64_gauge (starttime, addr << 1, FileSize); // make gauge reach 100% when size % 32 k != 0
|
|
WriteFlash (0, INTEL28F_READARRAY);
|
|
outpb (SPPCtrlPort, 0);
|
|
WriteFlash (1, INTEL28F_READARRAY);
|
|
outpb (SPPCtrlPort, 0);
|
|
|
|
if (Ready)
|
|
;
|
|
else
|
|
{
|
|
WriteFlash (0, INTEL28F_CLEARSR);
|
|
PPWriteWord (INTEL28F_CLEARSR);
|
|
fputs ("\nERROR: Flash card write failed\n", stderr);
|
|
}
|
|
}
|
|
else
|
|
fputs ("\nERROR: Flash card erase failed\n", stderr);
|
|
}
|
|
|
|
|
|
// Program official Nintendo flash card
|
|
void
|
|
ProgramSharpFlash (FILE *fp)
|
|
{
|
|
int i, j;
|
|
int k = 0;
|
|
int addr = 0;
|
|
int FileSize;
|
|
int Ready;
|
|
time_t starttime;
|
|
|
|
// Get file size
|
|
FileSize = GetFileSize2 (fp);
|
|
|
|
puts ("Erasing Nintendo flash card...");
|
|
|
|
// Erase as many 64k blocks as are required
|
|
Ready = EraseNintendoFlashBlocks (0, ((FileSize - 1) >> 16) + 1);
|
|
|
|
clear_line (); // remove "erase gauge"
|
|
if (Ready)
|
|
{
|
|
printf ("Send: %d Bytes (%.4f Mb)\n\n", FileSize, (float) FileSize / MBIT);
|
|
|
|
starttime = time (NULL);
|
|
j = GetFileByte (fp);
|
|
|
|
while (!feof (fp))
|
|
{
|
|
if (j != EOF)
|
|
k = GetFileByte (fp);
|
|
|
|
i = ((k & 0xff) << 8) + (j & 0xff);
|
|
|
|
while ((ReadStatusRegister (0) & 0x80) == 0)
|
|
;
|
|
|
|
WriteFlash (addr, SHARP28F_WORDWRITE);
|
|
WriteFlash (addr, i);
|
|
addr += 1;
|
|
|
|
j = GetFileByte (fp);
|
|
if ((addr & 0x3fff) == 0) // call ucon64_gauge() after sending 32 kB
|
|
ucon64_gauge (starttime, addr << 1, FileSize);
|
|
}
|
|
|
|
clear_line (); // remove last gauge
|
|
ucon64_gauge (starttime, addr << 1, FileSize); // make gauge reach 100% when size % 32 k != 0
|
|
WriteFlash (0, INTEL28F_READARRAY);
|
|
outpb (SPPCtrlPort, 0);
|
|
}
|
|
else
|
|
fputs ("\nERROR: Flash card erase failed\n", stderr);
|
|
}
|
|
|
|
|
|
#if 0 // not used
|
|
void
|
|
VerifyFlash (FILE *fp)
|
|
{
|
|
int addr = 0;
|
|
int CompareFail = 0;
|
|
int k = 0;
|
|
int i, j, m, n;
|
|
|
|
WriteFlash (0, INTEL28F_READARRAY); // Set flash (intel 28F640J3A) Read Mode
|
|
|
|
j = 0;
|
|
while (!feof (fp))
|
|
{
|
|
j = fgetc (fp);
|
|
if (j != EOF)
|
|
{
|
|
if ((addr & 0x1ff) == 0)
|
|
{
|
|
SetCartAddr (addr >> 1); // Set cart base addr to read
|
|
l4021d0 (3);
|
|
|
|
outpb (SPPCtrlPort, 0);
|
|
}
|
|
|
|
k = fgetc (fp);
|
|
|
|
i = PPReadWord ();
|
|
m = i & 0xff;
|
|
n = i >> 8;
|
|
|
|
if (m != j)
|
|
{
|
|
printf ("Address %x - Cartridge %x: File %hx\n", addr, m, j);
|
|
CompareFail = 1;
|
|
}
|
|
if ((n != k) && (k != EOF))
|
|
{
|
|
printf ("Address %x - Cartridge %x: File %hx\n", addr + 1, n,
|
|
k);
|
|
CompareFail = 1;
|
|
}
|
|
addr += 2;
|
|
}
|
|
}
|
|
|
|
// Correct verify length if at EOF
|
|
if (k == EOF)
|
|
addr--;
|
|
|
|
if (CompareFail == 0)
|
|
printf ("%d bytes compared OK\n", addr);
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
SpaceCheck (char c)
|
|
{
|
|
if (c != 0)
|
|
{
|
|
fputs ("ERROR: Space required between option and parameter\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
fal_main (int argc, char **argv)
|
|
{
|
|
int arg, i;
|
|
u8 Base = 0;
|
|
FILE *fp;
|
|
char fname[128], fname2[128];
|
|
int OptB = 0;
|
|
int OptD = 0;
|
|
int OptP = 0;
|
|
int OptR = 0;
|
|
int OptS = 0;
|
|
int OptV = 0;
|
|
int OptZ = 0;
|
|
int port = 0x378;
|
|
int ChipSize = 32;
|
|
int BackupMemOffset = 0;
|
|
int BackupMemSize = 0;
|
|
|
|
if (argc < 2)
|
|
{
|
|
// usage (argv[0]);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
debug = 0;
|
|
verbose = 1;
|
|
EPPMode = 0; // uCON64 comment: use the most compatible setting as default
|
|
DataSize16 = 0;
|
|
WaitDelay = 0;
|
|
VisolyTurbo = 0;
|
|
RepairHeader = 1;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] != '-')
|
|
{
|
|
// usage (argv[0]);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
switch (argv[arg][1])
|
|
{
|
|
case 'b':
|
|
SpaceCheck (argv[arg][2]);
|
|
BackupMemOffset = *(char *) argv[++arg] - 0x30;
|
|
SpaceCheck (argv[arg][1]);
|
|
BackupMemSize = *(char *) argv[++arg] - 0x30;
|
|
|
|
if ((BackupMemSize < 1) || (BackupMemSize > 4) ||
|
|
(BackupMemOffset < 1) || (BackupMemOffset > 4))
|
|
{
|
|
fputs ("ERROR: -b parameter values must be between 1-4\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
SpaceCheck (argv[arg][1]);
|
|
strcpy (fname, argv[++arg]);
|
|
OptB = 1;
|
|
break;
|
|
case '2':
|
|
// 16-bit EPP support enable (doesn't work with
|
|
// "Turbo FA 128M (2 x i28F640J3A)" - dbjh)
|
|
DataSize16 = 1;
|
|
break;
|
|
case 'c':
|
|
// Set cart size
|
|
SpaceCheck (argv[arg][2]);
|
|
ChipSize = (u16) (atoi (argv[++arg]));
|
|
if ((ChipSize != 8) &&
|
|
(ChipSize != 16) &&
|
|
(ChipSize != 32) &&
|
|
(ChipSize != 64) && (ChipSize != 128) && (ChipSize != 256))
|
|
{
|
|
fputs ("ERROR: Chip size must be 8,16,32,64,128 or 256\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
break;
|
|
case 'd':
|
|
// Dump 256 bytes to screen
|
|
SpaceCheck (argv[arg][2]);
|
|
if (argv[++arg] != NULL)
|
|
Base = (u8) (atoi (argv[arg]));
|
|
printf ("Base address: %hx\n", Base * 256);
|
|
OptD = 1;
|
|
break;
|
|
case 's':
|
|
// Backup flash cart
|
|
SpaceCheck (argv[arg][2]);
|
|
strcpy (fname, argv[++arg]);
|
|
OptS = 1;
|
|
break;
|
|
case 'p':
|
|
// Program flash cart
|
|
SpaceCheck (argv[arg][2]);
|
|
strcpy (fname, argv[++arg]);
|
|
OptP = 1;
|
|
break;
|
|
case 'r':
|
|
SpaceCheck (argv[arg][2]);
|
|
BackupMemOffset = *(char *) argv[++arg] - 0x30;
|
|
if ((BackupMemOffset < 1) || (BackupMemOffset > 4))
|
|
{
|
|
fputs ("ERROR: -r parameter value must be between 1-4\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
SpaceCheck (argv[arg][1]);
|
|
strcpy (fname, argv[++arg]);
|
|
OptR = 1;
|
|
break;
|
|
case 'v':
|
|
// Verify flash cart
|
|
SpaceCheck (argv[arg][2]);
|
|
strcpy (fname2, argv[++arg]);
|
|
OptV = 1;
|
|
break;
|
|
case 'l':
|
|
SpaceCheck (argv[arg][2]);
|
|
i = atoi (argv[++arg]);
|
|
/*
|
|
uCON64 comment: we want to support non-standard parallel port
|
|
addresses too. So, instead of passing a number from 1 to 4, we pass
|
|
the address itself
|
|
*/
|
|
port = i;
|
|
break;
|
|
case 'm':
|
|
// uCON64 comment: See comment in LinkerInit(). Note that we reverse
|
|
// the meaning compared to the original code.
|
|
EPPMode = 1; // Set EPP mode
|
|
break;
|
|
case 'n':
|
|
// Don't repair header
|
|
RepairHeader = 0;
|
|
break;
|
|
case 'w':
|
|
SpaceCheck (argv[arg][2]);
|
|
WaitDelay = atoi (argv[++arg]);
|
|
break;
|
|
case 'z':
|
|
OptZ = 1;
|
|
break;
|
|
default:
|
|
// usage (argv[0]);
|
|
ProgramExit (1);
|
|
}
|
|
}
|
|
|
|
InitPort (port);
|
|
|
|
CheckForFC ();
|
|
|
|
if (OptB)
|
|
{
|
|
//DumpSRAM ();
|
|
if ((fp = fopen (fname, "wb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], fname);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
BackupSRAM (fp, BackupMemOffset, BackupMemSize);
|
|
fputc ('\n', stdout);
|
|
fclose (fp);
|
|
}
|
|
|
|
if (OptD)
|
|
dump (Base);
|
|
|
|
if ((OptP) && ((Device == 0) || (Device == 0x2e) || (Device == 0xff)))
|
|
{
|
|
fputs ("ERROR: Device type not recognized as programmable\n", stderr);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
if (OptR)
|
|
{
|
|
if ((fp = fopen (fname, "rb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], fname);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
RestoreSRAM (fp, BackupMemOffset);
|
|
fputc ('\n', stdout);
|
|
fclose (fp);
|
|
}
|
|
|
|
if (OptP)
|
|
{
|
|
if ((fp = fopen (fname, "rb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], fname);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
if (Device == 0xe2)
|
|
ProgramSharpFlash (fp);
|
|
else
|
|
{
|
|
if (VisolyTurbo)
|
|
ProgramTurboIntelFlash (fp);
|
|
else
|
|
ProgramNonTurboIntelFlash (fp);
|
|
}
|
|
fputc ('\n', stdout);
|
|
fclose (fp);
|
|
}
|
|
|
|
if (OptS)
|
|
{
|
|
if ((fp = fopen (fname, "wb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], fname);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
BackupROM (fp, ChipSize << 16);
|
|
fputc ('\n', stdout);
|
|
fclose (fp);
|
|
}
|
|
|
|
#if 0
|
|
if (OptV)
|
|
{
|
|
if ((fp = fopen (fname2, "rb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], fname2);
|
|
ProgramExit (1);
|
|
}
|
|
|
|
VerifyFlash (fp);
|
|
fclose (fp);
|
|
}
|
|
#endif
|
|
|
|
ProgramExit (0);
|
|
exit (0);
|
|
}
|
|
|
|
|
|
/*
|
|
It will save you some work if you don't fully integrate the code above with
|
|
uCON64's code, because it is a project separate from the uCON64 project.
|
|
*/
|
|
int fal_argc = 0;
|
|
char *fal_argv[128];
|
|
|
|
void
|
|
fal_args (unsigned int parport)
|
|
{
|
|
char parport_str[80];
|
|
|
|
parport_print_info ();
|
|
|
|
fal_argv[fal_argc++] = "fl";
|
|
fal_argv[fal_argc++] = "-l";
|
|
sprintf (parport_str, "%d", parport); // don't use %x, as Jeff Frohwein uses atoi()
|
|
fal_argv[fal_argc++] = parport_str;
|
|
|
|
if (ucon64.parport_mode == UCON64_EPP)
|
|
fal_argv[fal_argc++] = "-m";
|
|
}
|
|
|
|
|
|
int
|
|
fal_read_rom (const char *filename, unsigned int parport, int size)
|
|
{
|
|
char size_str[80];
|
|
|
|
fal_args (parport);
|
|
|
|
fal_argv[fal_argc++] = "-c";
|
|
if (size != 8 && size != 16 && size != 32 && size != 64 && size != 128 &&
|
|
size != 256)
|
|
{
|
|
fputs ("ERROR: Invalid argument for -xfalc=n\n"
|
|
" n can be 8, 16, 32, 64, 128 or 256\n", stderr);
|
|
exit (1);
|
|
}
|
|
sprintf (size_str, "%d", size);
|
|
fal_argv[fal_argc++] = size_str;
|
|
fal_argv[fal_argc++] = "-s";
|
|
fal_argv[fal_argc++] = (char *) filename; // this is safe (FAL code
|
|
// doesn't modify argv)
|
|
if (!fal_main (fal_argc, fal_argv))
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
fal_write_rom (const char *filename, unsigned int parport)
|
|
{
|
|
fal_args (parport);
|
|
|
|
fal_argv[fal_argc++] = "-p";
|
|
fal_argv[fal_argc++] = (char *) filename;
|
|
|
|
if (!fal_main (fal_argc, fal_argv))
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
fal_read_sram (const char *filename, unsigned int parport, int bank)
|
|
{
|
|
char bank_str[2];
|
|
|
|
fal_args (parport);
|
|
|
|
fal_argv[fal_argc++] = "-b";
|
|
if (bank == UCON64_UNKNOWN)
|
|
{
|
|
fal_argv[fal_argc++] = "1";
|
|
fal_argv[fal_argc++] = "4"; // 256 kB
|
|
}
|
|
else
|
|
{
|
|
if (bank < 1 || bank > 4)
|
|
{
|
|
fputs ("ERROR: Bank must be 1, 2, 3 or 4\n", stderr);
|
|
exit (1);
|
|
}
|
|
bank_str[0] = '0' + bank;
|
|
bank_str[1] = 0; // terminate string
|
|
fal_argv[fal_argc++] = bank_str;
|
|
fal_argv[fal_argc++] = "2"; // 64 kB
|
|
}
|
|
fal_argv[fal_argc++] = (char *) filename;
|
|
|
|
if (!fal_main (fal_argc, fal_argv))
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
fal_write_sram (const char *filename, unsigned int parport, int bank)
|
|
{
|
|
char bank_str[2];
|
|
|
|
fal_args (parport);
|
|
|
|
fal_argv[fal_argc++] = "-r";
|
|
if (bank == UCON64_UNKNOWN)
|
|
fal_argv[fal_argc++] = "1";
|
|
else
|
|
{
|
|
if (bank < 1 || bank > 4)
|
|
{
|
|
fputs ("ERROR: Bank must be 1, 2, 3 or 4\n", stderr);
|
|
exit (1);
|
|
}
|
|
bank_str[0] = '0' + bank;
|
|
bank_str[1] = 0; // terminate string
|
|
fal_argv[fal_argc++] = bank_str;
|
|
}
|
|
fal_argv[fal_argc++] = (char *) filename;
|
|
|
|
if (!fal_main (fal_argc, fal_argv))
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
#endif // USE_PARALLEL
|