set_addr8(fd, addr >> 1);
}
+static uint32_t lorom_addr(uint32_t a)
+{
+ return ((a & 0x7f8000) << 1) | 0x8000 | (a & 0x7fff);
+}
+
+static void set_addr8l(int fd, uint32_t addr)
+{
+ set_addr8(fd, lorom_addr(addr));
+}
+
static uint16_t read_bus8(int fd, uint32_t addr)
{
uint8_t cmd[7] = {
return ntohs(r);
}
+static uint16_t read_bus8l(int fd, uint32_t addr)
+{
+ return read_bus8(fd, lorom_addr(addr));
+}
+
static void write_bus8(int fd, uint32_t addr, uint16_t d)
{
uint8_t cmd[8] = {
write_serial(fd, cmd, sizeof(cmd));
}
+static void write_bus8l(int fd, uint32_t addr, uint16_t d)
+{
+ write_bus8(fd, lorom_addr(addr), d);
+}
+
static void read_block8(int fd, void *dst, uint32_t size)
{
// PAR_MODE8 does not work, so read as 16bit and throw away MSB
write_serial(fd, cmd, sizeof(cmd));
}
+static void flash_seq_write8l(int fd, uint32_t addr, const uint8_t *d)
+{
+ addr = lorom_addr(addr);
+ uint8_t cmd[] = {
+ // unlock
+ CMD_ADDR, 0,
+ CMD_ADDR, 0x8a,
+ CMD_ADDR, 0xaa,
+ CMD_WR | PAR_SINGE | PAR_MODE8, 0xaa,
+ CMD_ADDR, 0,
+ CMD_ADDR, 0x85,
+ CMD_ADDR, 0x55,
+ CMD_WR | PAR_SINGE | PAR_MODE8, 0x55,
+ // program setup
+ CMD_ADDR, 0,
+ CMD_ADDR, 0x8a,
+ CMD_ADDR, 0xaa,
+ CMD_WR | PAR_SINGE | PAR_MODE8, 0xa0,
+ // program data
+ CMD_ADDR, addr >> 16,
+ CMD_ADDR, addr >> 8,
+ CMD_ADDR, addr >> 0,
+ CMD_WR | PAR_SINGE | PAR_MODE8, *d,
+ CMD_RY
+ };
+
+ write_serial(fd, cmd, sizeof(cmd));
+}
+
+#define N0 ""
+#define N1 "8bit"
+#define N2 "8bit+LoROM"
+#define N3 "8bit+LoROM+adapter"
static const struct iof
{
+ const char *name;
+ int addrs_remapped;
void (*set_addr)(int fd, uint32_t addr);
uint16_t (*read_bus)(int fd, uint32_t addr);
void (*write_bus)(int fd, uint32_t addr, uint16_t d);
}
io_ops[] =
{
- { set_addr8, read_bus8, write_bus8, read_block8, flash_seq_write8 },
- { set_addr16, read_bus16, write_bus16, read_block16, flash_seq_write16 },
+ { N0, 0, set_addr16, read_bus16, write_bus16, read_block16, flash_seq_write16 },
+ { N1, 0, set_addr8, read_bus8, write_bus8, read_block8, flash_seq_write8 },
+ { N2, 1, set_addr8l, read_bus8l, write_bus8l, read_block8, flash_seq_write8l },
};
-static const struct iof *io = &io_ops[1];
+static const struct iof *io = &io_ops[0];
static uint16_t flash_seq_r(int fd, uint8_t cmd, uint32_t addr)
{
return io->read_bus(fd, addr);
}
-static void flash_seq_erase(int fd, uint32_t addr)
+static void flash_seq_erase_d(int fd, uint32_t addr, uint8_t d)
{
// printf("erase %06x\n", addr);
io->write_bus(fd, 0xaaa, 0xaa);
io->write_bus(fd, 0xaaa, 0xaa);
io->write_bus(fd, 0x555, 0x55);
- io->write_bus(fd, addr, 0x30);
+ io->write_bus(fd, addr, d);
+}
+
+static void flash_seq_erase(int fd, uint32_t addr)
+{
+ flash_seq_erase_d(fd, addr, 0x30);
+}
+
+static void flash_seq_erase_full(int fd)
+{
+ flash_seq_erase_d(fd, 0xaaa, 0x10);
}
// status wait + dummy read to cause a wait?
static void usage(const char *argv0)
{
+ size_t i;
+
printf("usage:\n"
"%s [options]\n"
" -d <ttydevice> (default %s)\n"
" -r <file> [size] dump the cart (default 4MB)\n"
" -w <file> [size] program the flash (def. file size)\n"
" -s <file> [size] simple write (SRAM, etc, def. file size)\n"
- " -e <size> erase (rounds to block size)\n"
+ " -e <size> erase (rounds to block size); can specify 'full'\n"
" -a <start_address> read/write start address (default 0)\n"
- " -8 8bit flash\n"
- " -v verify written data\n"
- " -i get info about the flash chip\n"
+ " -m <n> use an address mapper n, one of:\n"
, argv0, portname);
+ for (i = 1; i < sizeof(io_ops) / sizeof(io_ops[0]); i++)
+ printf(
+ " %zd: %s\n", i, io_ops[i].name);
+ printf( " -v verify written data\n"
+ " -i get info about the flash chip\n");
exit(1);
}
return argv[arg];
}
-static uint8_t g_block[0x10000];
-static uint8_t g_block2[0x10000];
+static long getarg_l(int argc, char *argv[], int arg)
+{
+ char *endp = NULL;
+ long r;
+
+ if (arg >= argc)
+ invarg(argc, argv, arg);
+ r = strtol(argv[arg], &endp, 0);
+ if (endp == NULL || *endp != 0)
+ invarg(argc, argv, arg);
+ return r;
+}
+
+// 32K to easily handle SNES LoROM
+static uint8_t g_block[0x8000];
+static uint8_t g_block2[sizeof(g_block)];
int main(int argc, char *argv[])
{
if (!strcmp(argv[arg], "-r")) {
fname_r = getarg(argc, argv, ++arg);
if (arg + 1 < argc && argv[arg + 1][0] != '-') {
- size_r = strtol(argv[++arg], NULL, 0);
+ size_r = getarg_l(argc, argv, ++arg);
if (size_r <= 0)
invarg(argc, argv, arg);
}
if (!strcmp(argv[arg], "-w")) {
fname_w = getarg(argc, argv, ++arg);
if (arg + 1 < argc && argv[arg + 1][0] != '-') {
- size_w = strtol(argv[++arg], NULL, 0);
+ size_w = getarg_l(argc, argv, ++arg);
if (size_w <= 0)
invarg(argc, argv, arg);
}
if (!strcmp(argv[arg], "-s")) {
fname_ws = getarg(argc, argv, ++arg);
if (arg + 1 < argc && argv[arg + 1][0] != '-') {
- size_ws = strtol(argv[++arg], NULL, 0);
+ size_ws = getarg_l(argc, argv, ++arg);
if (size_ws <= 0)
invarg(argc, argv, arg);
}
continue;
}
if (!strcmp(argv[arg], "-a")) {
- address_in = strtol(getarg(argc, argv, ++arg), NULL, 0);
- if (address_in < 0 || (address_in & 1))
+ address_in = getarg_l(argc, argv, ++arg);
+ if (address_in < 0)
invarg(argc, argv, arg);
continue;
}
if (!strcmp(argv[arg], "-e")) {
- size_e = strtol(getarg(argc, argv, ++arg), NULL, 0);
- if (size_e <= 0)
- invarg(argc, argv, arg);
+ arg++;
+ if (!strcmp(getarg(argc, argv, arg), "full"))
+ size_e = -1;
+ else {
+ size_e = getarg_l(argc, argv, arg);
+ if (size_e <= 0)
+ invarg(argc, argv, arg);
+ }
continue;
}
- if (!strcmp(argv[arg], "-8")) {
- io = &io_ops[0];
- write_step = 1;
+ if (!strcmp(argv[arg], "-m")) {
+ long v = getarg_l(argc, argv, ++arg);
+ if ((size_t)v >= sizeof(io_ops) / sizeof(io_ops[0]))
+ invarg(argc, argv, arg);
+ io = &io_ops[v];
+ if (v != 0)
+ write_step = 1;
continue;
}
if (!strcmp(argv[arg], "-v")) {
if (fname_w) {
f_w = open_prep_read(fname_w, &size_w);
- if (size_e < size_w)
+ if (size_e == 0 && io->addrs_remapped)
+ size_e = -1;
+ if (size_e != -1 && size_e < size_w)
size_e = size_w;
if (do_verify)
size_v = size_w;
if (do_info || size_e)
read_info(fd);
- if (size_e) {
+ if (size_e == -1) {
+ printf("performing full erase..."); fflush(stdout);
+ flash_seq_erase_full(fd);
+ rv = ry_read(fd);
+ if (rv != 0xffff) {
+ fprintf(stderr, "\nerase error: %04x\n", rv);
+ return 1;
+ }
+ printf(" done.\n");
+ }
+ else if (size_e) {
// set_delay(fd, 0); // ?
a_blk = get_block_addr(address_in, 0);
end = address_in + size_e;
if (rv != 0xffff) {
fprintf(stderr, "\nerase error: %lx %04x\n",
a_blk, rv);
+ return 1;
}
a_blk = get_block_addr(a_blk, 1);
print_progress(0, blks * sizeof(g_block));
io->set_addr(fd, address_in);
for (done = 0; done < size_r || done < size_v; ) {
+ if (io->addrs_remapped)
+ io->set_addr(fd, address_in + done);
io->read_block(fd, g_block, sizeof(g_block));
if (f_r && done < size_r) {
len = min(size_r - done, sizeof(g_block));