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,
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,
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
write_serial(fd, cmd, sizeof(cmd));
}
+static const struct iof
+{
+ 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[] =
+{
+ { set_addr8, read_bus8, write_bus8, read_block8, flash_seq_write8 },
+ { set_addr16, read_bus16, write_bus16, read_block16, flash_seq_write16 },
+};
+
+static const struct iof *io = &io_ops[1];
+
+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(int fd, uint32_t addr)
+{
+ // 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, 0x30);
+}
+
// status wait + dummy read to cause a wait?
static uint16_t ry_read(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;
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);
{
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)
" -w <file> [size] flash the cart (file size)\n"
" -e <size> erase (rounds to block size)\n"
" -a <start_address> cart start address (default 0)\n"
+ " -8 8bit flash\n"
" -v verify written data\n"
" -i get info about the flash chip\n"
, argv0);
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;
uint8_t id[2] = { 0, 0 };
invarg(argc, argv, arg);
continue;
}
+ if (!strcmp(argv[arg], "-8")) {
+ io = &io_ops[0];
+ write_step = 1;
+ continue;
+ }
if (!strcmp(argv[arg], "-v")) {
do_verify = 1;
continue;
printf("flashkit id: %02x\n", id[0]);
set_delay(fd, 1);
- write_word(fd, 0, 0xf0); // flash reset
+ io->write_bus(fd, 0, 0xf0); // flash reset
if (do_info || size_e)
read_info(fd);
uint8_t b[2];
set_delay(fd, 0);
printf("writing %ld bytes:\n", size_w);
- for (a = 0; a < size_w; a += 2) {
+ 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);
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));
+ 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) {