X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=flashkit-mdc.git;a=blobdiff_plain;f=flashkit.c;h=a2ebdb85c2c1ce4bfe53a3aa16b154a0c0d12a6a;hp=3e687fceebc1e22f7803fc00aa612829356c7bfe;hb=5a2c48a5be076f5d40c52d9053f113fff8639a72;hpb=d9502b8d6241a5886e08c32797f917e9d475bef0 diff --git a/flashkit.c b/flashkit.c index 3e687fc..a2ebdb8 100644 --- a/flashkit.c +++ b/flashkit.c @@ -48,7 +48,7 @@ enum dev_cmd { CMD_RY = 4, CMD_DELAY = 5, }; -#define PAR_MODE8 (1 << 4) +#define PAR_MODE8 (1 << 4) /* but still drives noth LWR and UWR */ #define PAR_DEV_ID (1 << 5) #define PAR_SINGE (1 << 6) #define PAR_INC (1 << 7) @@ -119,17 +119,38 @@ static int read_serial(int fd, void *data, size_t size) return 0; } -static void set_addr(int fd, uint32_t addr) +/* addr arg is always byte address */ +static void set_addr8(int fd, uint32_t addr) { uint8_t cmd[6] = { - CMD_ADDR, addr >> 17, - CMD_ADDR, addr >> 9, - CMD_ADDR, addr >> 1 + CMD_ADDR, addr >> 16, + CMD_ADDR, addr >> 8, + CMD_ADDR, addr >> 0 + }; + write_serial(fd, cmd, sizeof(cmd)); +} + +static void set_addr16(int fd, uint32_t addr) +{ + set_addr8(fd, addr >> 1); +} + +static uint16_t read_bus8(int fd, uint32_t addr) +{ + uint8_t cmd[7] = { + CMD_ADDR, addr >> 16, + CMD_ADDR, addr >> 8, + CMD_ADDR, addr >> 0, + CMD_RD | PAR_SINGE | PAR_MODE8 }; + uint8_t r; + write_serial(fd, cmd, sizeof(cmd)); + read_serial(fd, &r, sizeof(r)); + return r; } -static uint16_t read_word(int fd, uint32_t addr) +static uint16_t read_bus16(int fd, uint32_t addr) { uint8_t cmd[7] = { CMD_ADDR, addr >> 17, @@ -144,7 +165,20 @@ static uint16_t read_word(int fd, uint32_t addr) return ntohs(r); } -static void write_word(int fd, uint32_t addr, uint16_t d) +static void write_bus8(int fd, uint32_t addr, uint16_t d) +{ + uint8_t cmd[8] = { + CMD_ADDR, addr >> 16, + CMD_ADDR, addr >> 8, + CMD_ADDR, addr >> 0, + CMD_WR | PAR_SINGE | PAR_MODE8, + d + }; + + write_serial(fd, cmd, sizeof(cmd)); +} + +static void write_bus16(int fd, uint32_t addr, uint16_t d) { uint8_t cmd[9] = { CMD_ADDR, addr >> 17, @@ -157,42 +191,71 @@ static void write_word(int fd, uint32_t addr, uint16_t d) write_serial(fd, cmd, sizeof(cmd)); } -static void read_block(int fd, void *dst, uint32_t size) +static void read_block8(int fd, void *dst, uint32_t size) { + // PAR_MODE8 does not work, so read as 16bit and throw away MSB + uint8_t tmp[0x10000], *d8 = dst; uint8_t cmd[5] = { - CMD_LEN, size >> 9, - CMD_LEN, size >> 1, + CMD_LEN, size >> 8, + CMD_LEN, size >> 0, CMD_RD | PAR_INC }; + int i; assert(size <= 0x10000); write_serial(fd, cmd, sizeof(cmd)); read_serial(fd, dst, size); + read_serial(fd, tmp, size); + + for (i = 0; i < size / 2; i++) + d8[i] = d8[i * 2 + 1]; + d8 += size / 2; + for (i = 0; i < size / 2; i++) + d8[i] = tmp[i * 2 + 1]; } -static uint16_t flash_seq_r(int fd, uint8_t cmd, uint32_t addr) +static void read_block16(int fd, void *dst, uint32_t size) { - // unlock - write_word(fd, 0xaaa, 0xaa); - write_word(fd, 0x555, 0x55); + uint8_t cmd[5] = { + CMD_LEN, size >> 9, + CMD_LEN, size >> 1, + CMD_RD | PAR_INC + }; - write_word(fd, 0xaaa, cmd); - return read_word(fd, addr); + assert(size <= 0x10000); + write_serial(fd, cmd, sizeof(cmd)); + read_serial(fd, dst, size); } -static void flash_seq_erase(int fd, uint32_t addr) +static void flash_seq_write8(int fd, uint32_t addr, const uint8_t *d) { - // printf("erase %06x\n", addr); - write_word(fd, 0xaaa, 0xaa); - write_word(fd, 0x555, 0x55); - write_word(fd, 0xaaa, 0x80); + uint8_t cmd[] = { + // unlock + CMD_ADDR, 0, + CMD_ADDR, 0x0a, + CMD_ADDR, 0xaa, + CMD_WR | PAR_SINGE | PAR_MODE8, 0xaa, + CMD_ADDR, 0, + CMD_ADDR, 0x05, + CMD_ADDR, 0x55, + CMD_WR | PAR_SINGE | PAR_MODE8, 0x55, + // program setup + CMD_ADDR, 0, + CMD_ADDR, 0x0a, + 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_word(fd, 0xaaa, 0xaa); - write_word(fd, 0x555, 0x55); - write_word(fd, addr, 0x30); + write_serial(fd, cmd, sizeof(cmd)); } -static void flash_seq_write(int fd, uint32_t addr, uint8_t *d) +static void flash_seq_write16(int fd, uint32_t addr, const uint8_t *d) { uint8_t cmd[] = { // unlock @@ -220,6 +283,204 @@ static void flash_seq_write(int fd, uint32_t addr, uint8_t *d) write_serial(fd, cmd, sizeof(cmd)); } +// -- 8bit+LoROM -- + +static uint32_t lorom_rom_addr(uint32_t a) +{ + return ((a & 0x7f8000) << 1) | 0x8000 | (a & 0x7fff); +} + +static void set_addr8l(int fd, uint32_t a) +{ + set_addr8(fd, lorom_rom_addr(a)); +} + +static uint16_t read_bus8l(int fd, uint32_t a) +{ + return read_bus8(fd, lorom_rom_addr(a)); +} + +static void write_bus8l(int fd, uint32_t a, uint16_t d) +{ + write_bus8(fd, lorom_rom_addr(a), d); +} + +static void flash_seq_write8l(int fd, uint32_t a, const uint8_t *d) +{ + a = lorom_rom_addr(a); + 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, a >> 16, + CMD_ADDR, a >> 8, + CMD_ADDR, a >> 0, + CMD_WR | PAR_SINGE | PAR_MODE8, *d, + CMD_RY + }; + + write_serial(fd, cmd, sizeof(cmd)); +} + +// -- 8bit+LoROM+adapter -- + +static uint32_t do_flipflops(int fd, uint32_t a) +{ + static uint32_t abits_now = ~0u; // A23, A22, A21 + uint32_t abits = (a >> 21) & 7; + + if (abits != abits_now) { + // printf("flipflops: %x->%x\n", abits_now, abits); + write_bus16(fd, 0xa13000, abits); + abits_now = abits; + } + return a & 0x1fffff; +} + +static void set_addr8la(int fd, uint32_t a) +{ + set_addr8(fd, do_flipflops(fd, lorom_rom_addr(a))); +} + +static uint16_t read_bus8la(int fd, uint32_t a) +{ + return read_bus8(fd, do_flipflops(fd, lorom_rom_addr(a))); +} + +static void write_bus8la(int fd, uint32_t a, uint16_t d) +{ + write_bus8(fd, do_flipflops(fd, lorom_rom_addr(a)), d); +} + +static void flash_seq_write8la(int fd, uint32_t a, const uint8_t *d) +{ + // we should clear flipflops for the flash commands, but this + // doesn't seem to be necessary as the flash chip seems to + // ignore the upper bits when looking for commands, and this + // extra clearing would slow things down + a = do_flipflops(fd, lorom_rom_addr(a)); + 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, a >> 16, + CMD_ADDR, a >> 8, + CMD_ADDR, a >> 0, + CMD_WR | PAR_SINGE | PAR_MODE8, *d, + CMD_RY + }; + + write_serial(fd, cmd, sizeof(cmd)); +} + +// -- 8bit+LoROM+adapter+sram -- + +static uint32_t lorom_sram_addr(uint32_t a) +{ + return a | 0x600000; +} + +static void set_addr8las(int fd, uint32_t a) +{ + set_addr8(fd, do_flipflops(fd, lorom_sram_addr(a))); +} + +static uint16_t read_bus8las(int fd, uint32_t a) +{ + return read_bus8(fd, do_flipflops(fd, lorom_sram_addr(a))); +} + +static void write_bus8las(int fd, uint32_t a, uint16_t d) +{ + write_bus8(fd, do_flipflops(fd, lorom_sram_addr(a)), d); +} + +static void flash_seq_write8las(int fd, uint32_t a, const uint8_t *d) +{ +} + +#define N0 "" +#define N1 "8bit" +#define N2 "8bit+LoROM" +#define N3 "8bit+LoROM+adapter" +#define N4 "8bit+LoROM+adapter+sram" +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); + void (*read_block)(int fd, void *dst, uint32_t size); + void (*flash_seq_write)(int fd, uint32_t addr, const uint8_t *d); +} +io_ops[] = +{ + { 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 }, + { N3, 1, set_addr8la, read_bus8la, write_bus8la, read_block8, flash_seq_write8la }, + { N4, 0, set_addr8las, read_bus8las, write_bus8las, read_block8, flash_seq_write8las }, +}; + +static const struct iof *io = &io_ops[0]; + +static uint16_t flash_seq_r(int fd, uint8_t cmd, uint32_t addr) +{ + // unlock + io->write_bus(fd, 0xaaa, 0xaa); + io->write_bus(fd, 0x555, 0x55); + + io->write_bus(fd, 0xaaa, cmd); + return io->read_bus(fd, 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, 0x555, 0x55); + io->write_bus(fd, 0xaaa, 0x80); + + io->write_bus(fd, 0xaaa, 0xaa); + io->write_bus(fd, 0x555, 0x55); + 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 uint16_t ry_read(int fd) { @@ -259,29 +520,29 @@ static void read_info(int fd) uint32_t i, a; info.mid = flash_seq_r(fd, 0x90, 0); // autoselect - info.did = read_word(fd, 2); + info.did = io->read_bus(fd, 2); // could enter CFI directly, but there seems to be a "stack" // of modes, so 2 exits would be needed - write_word(fd, 0, 0xf0); + io->write_bus(fd, 0, 0xf0); - write_word(fd, 0xaa, 0x98); // CFI Query - resp[0] = read_word(fd, 0x20); - resp[1] = read_word(fd, 0x22); - resp[2] = read_word(fd, 0x24); + io->write_bus(fd, 0xaa, 0x98); // CFI Query + resp[0] = io->read_bus(fd, 0x20); + resp[1] = io->read_bus(fd, 0x22); + resp[2] = io->read_bus(fd, 0x24); if (memcmp(resp, qry, sizeof(resp))) { fprintf(stderr, "unexpected CFI response: %04x %04x %04x\n", resp[0], resp[1], resp[2]); exit(1); } - info.size = 1u << read_word(fd, 0x4e); - info.region_cnt = read_word(fd, 0x58); + info.size = 1u << io->read_bus(fd, 0x4e); + info.region_cnt = io->read_bus(fd, 0x58); assert(0 < info.region_cnt && info.region_cnt <= 4); for (i = 0, a = 0x5a; i < info.region_cnt; i++, a += 8) { - info.region[i].block_count = read_word(fd, a + 0) + 1; - info.region[i].block_count += read_word(fd, a + 2) << 8; - info.region[i].block_size = read_word(fd, a + 4) << 8; - info.region[i].block_size |= read_word(fd, a + 6) << 16; + info.region[i].block_count = io->read_bus(fd, a + 0) + 1; + info.region[i].block_count += io->read_bus(fd, a + 2) << 8; + info.region[i].block_size = io->read_bus(fd, a + 4) << 8; + info.region[i].block_size |= io->read_bus(fd, a + 6) << 16; info.region[i].start = total; info.region[i].size = info.region[i].block_size * info.region[i].block_count; @@ -289,7 +550,7 @@ static void read_info(int fd) total += info.region[i].size; } - write_word(fd, 0, 0xf0); // flash reset + io->write_bus(fd, 0, 0xf0); // flash reset printf("Flash info:\n"); printf("Manufacturer ID: %04x\n", info.mid); @@ -305,17 +566,23 @@ static void read_info(int fd) static uint32_t get_block_addr(uint32_t addr, uint32_t blk_offset) { - uint32_t i; + uint32_t i, base, faddr; assert(info.region_cnt); + assert(info.size); + + // get a flash address to allow mapper hardware + faddr = addr & (info.size - 1); + base = addr & ~(info.size - 1); + for (i = 0; i < info.region_cnt; i++) { - if (info.region[i].start <= addr - && addr < info.region[i].start + info.region[i].size) + if (info.region[i].start <= faddr + && faddr < info.region[i].start + info.region[i].size) { - uint32_t blk = (addr - info.region[i].start) + uint32_t blk = (faddr - info.region[i].start) / info.region[i].block_size + blk_offset; - return info.region[i].start + return base + info.region[i].start + blk * info.region[i].block_size; } } @@ -328,10 +595,7 @@ static void print_progress(uint32_t done, uint32_t total) { int i, step; - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */ - printf("\b\b\b\b\b\b"); - printf("%06x/%06x |", done, total); + printf("\r%06x/%06x |", done, total); step = (total + 19) / 20; for (i = step; i <= total; i += step) @@ -342,18 +606,52 @@ static void print_progress(uint32_t done, uint32_t total) fputc('\n', stdout); } +static FILE *open_prep_read(const char *fname, long *size) +{ + FILE *f = fopen(fname, "rb"); + if (!f) { + fprintf(stderr, "fopen %s: ", fname); + perror(""); + exit(1); + } + if (*size <= 0) { + fseek(f, 0, SEEK_END); + *size = ftell(f); + fseek(f, 0, SEEK_SET); + } + if (*size <= 0) { + fprintf(stderr, "size of %s is %ld\n", fname, *size); + exit(1); + } + return f; +} + +static const char *portname = +#ifdef __APPLE__ + "/dev/cu.usbserial-AL0254JM"; +#else + "/dev/ttyUSB0"; +#endif + static void usage(const char *argv0) { + size_t i; + printf("usage:\n" "%s [options]\n" - " -d (default /dev/ttyUSB0)\n" + " -d (default %s)\n" " -r [size] dump the cart (default 4MB)\n" - " -w [size] flash the cart (file size)\n" - " -e erase (rounds to block size)\n" - " -a cart start address (default 0)\n" - " -v verify written data\n" - " -i get info about the flash chip\n" - , argv0); + " -w [size] program the flash (def. file size)\n" + " -s [size] simple write (SRAM, etc, def. file size)\n" + " -e erase (rounds to block size); can specify 'full'\n" + " -a read/write start address (default 0)\n" + " -m 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); } @@ -373,24 +671,41 @@ static void *getarg(int argc, char *argv[], int arg) 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[]) { - const char *portname = "/dev/ttyUSB0"; const char *fname_w = NULL; const char *fname_r = NULL; + const char *fname_ws = NULL; long size_w = 0; long size_r = 0; + long size_ws = 0; long size_e = 0; long size_v = 0; long len, address_in = 0; long a, a_blk, end; int do_info = 0; int do_verify = 0; + int write_step = 2; FILE *f_w = NULL; FILE *f_r = NULL; + FILE *f_ws = NULL; uint8_t id[2] = { 0, 0 }; uint8_t cmd; uint16_t rv; @@ -408,7 +723,7 @@ 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); } @@ -417,22 +732,45 @@ int main(int argc, char *argv[]) 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); } continue; } + if (!strcmp(argv[arg], "-s")) { + fname_ws = getarg(argc, argv, ++arg); + if (arg + 1 < argc && argv[arg + 1][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) + 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], "-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")) { @@ -450,23 +788,10 @@ int main(int argc, char *argv[]) size_r = 0x400000; if (fname_w) { - f_w = fopen(fname_w, "rb"); - if (!f_w) { - fprintf(stderr, "fopen %s: ", fname_w); - perror(""); - return 1; - } - if (size_w <= 0) { - fseek(f_w, 0, SEEK_END); - size_w = ftell(f_w); - fseek(f_w, 0, SEEK_SET); - } - if (size_w <= 0) { - fprintf(stderr, "size of %s is %ld\n", - fname_w, size_w); - return 1; - } - if (size_e < size_w) + f_w = open_prep_read(fname_w, &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; @@ -479,6 +804,9 @@ int main(int argc, char *argv[]) return 1; } + if (fname_ws) + f_ws = open_prep_read(fname_ws, &size_ws); + setup(fd); cmd = CMD_RD | PAR_SINGE | PAR_DEV_ID; @@ -491,12 +819,24 @@ int main(int argc, char *argv[]) printf("flashkit id: %02x\n", id[0]); set_delay(fd, 1); - write_word(fd, 0, 0xf0); // flash reset + + if (do_info || size_e || f_w) + io->write_bus(fd, 0, 0xf0); // flash reset 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; @@ -509,6 +849,7 @@ int main(int argc, char *argv[]) if (rv != 0xffff) { fprintf(stderr, "\nerase error: %lx %04x\n", a_blk, rv); + return 1; } a_blk = get_block_addr(a_blk, 1); @@ -519,30 +860,51 @@ int main(int argc, char *argv[]) if (f_w != NULL) { uint8_t b[2]; set_delay(fd, 0); - printf("writing %ld bytes:\n", size_w); - for (a = 0; a < size_w; a += 2) { + printf("flashing %ld bytes:\n", size_w); + for (a = 0; a < size_w; a += write_step) { ssize_t r; b[1] = 0xff; - len = min(size_w - a, 2); + len = min(size_w - a, write_step); r = fread(b, 1, len, f_w); if (r != len) { perror("\nfread"); return 1; } - flash_seq_write(fd, address_in + a, b); + io->flash_seq_write(fd, address_in + a, b); - if (!(a & 0x3fe)) + if (!(a & 0x3ff)) print_progress(a, size_w); } print_progress(a, size_w); rv = ry_read(fd); - if (rv != ((b[0] << 8) | b[1])) + if (write_step == 2 && rv != ((b[0] << 8) | b[1])) fprintf(stderr, "warning: last bytes: %04x %02x%02x\n", rv, b[0], b[1]); rewind(f_w); set_delay(fd, 1); } + if (f_ws != NULL) { + printf("writing %ld bytes:\n", size_ws); + for (a = 0; a < size_ws; a += write_step) { + uint16_t b = 0xffff; + ssize_t r; + + len = min(size_ws - a, write_step); + r = fread(&b, 1, len, f_ws); + if (r != len) { + perror("\nfread"); + return 1; + } + if (write_step == 2) + b = htons(b); + io->write_bus(fd, address_in + a, b); + + if (!(a & 0x3ff)) + print_progress(a, size_ws); + } + print_progress(a, size_ws); + } if (fname_r || size_v) { long blks, blks_v, done, verify_diff = 0; @@ -561,9 +923,11 @@ int main(int argc, char *argv[]) printf("reading %ld bytes:\n", max(size_r, size_v)); print_progress(0, blks * sizeof(g_block)); - set_addr(fd, address_in); + io->set_addr(fd, address_in); for (done = 0; done < size_r || done < size_v; ) { - read_block(fd, g_block, sizeof(g_block)); + 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)); if (fwrite(g_block, 1, len, f_r) != len) {