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)
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);
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;
}
}
{
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)
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)
{
printf("usage:\n"
"%s [options]\n"
- " -d <ttydevice> (default /dev/ttyUSB0)\n"
+ " -d <ttydevice> (default %s)\n"
" -r <file> [size] dump the cart (default 4MB)\n"
- " -w <file> [size] flash the cart (file size)\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"
- " -a <start_address> cart start address (default 0)\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"
- , argv0);
+ , argv0, portname);
exit(1);
}
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;
}
continue;
}
+ 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);
+ 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))
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;
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;
- }
+ f_w = open_prep_read(fname_w, &size_w);
if (size_e < size_w)
size_e = size_w;
if (do_verify)
return 1;
}
+ if (fname_ws)
+ f_ws = open_prep_read(fname_ws, &size_ws);
+
setup(fd);
cmd = CMD_RD | PAR_SINGE | PAR_DEV_ID;
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);
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;
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) {