/* * f32x/f32x.c - Simple C8051F326/7 Flash programmer * * Written 2008-2010 by Werner Almesberger * Copyright 2008-2010 Werner Almesberger * * 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. */ #include #include #include #include #include #include #include "c2.h" #include "flash.h" #include "boundary.h" struct chip { const char *name; /* NULL for end of list */ uint8_t dev_id; int max_flash_kb; /* maximum flash size, in kB */ }; struct mem_layout { int flash_kb; /* real flash size, in kB. 0 for end of list */ uint16_t lock_byte; /* location of lock byte */ }; static struct chip chips[] = { { "C8051F320/1", 0x09, 16 }, { "C8051F326/7", 0x0d, 16 }, { "C8051F34x", 0x0f, 64 }, { NULL, } }; static struct mem_layout mem_layouts[] = { { 16, 0x3dff }, { 32, 0x7fff }, { 64, 0xfbff }, { 0, } }; static const struct chip *chip = NULL; static const struct mem_layout *layout = NULL; static size_t file_size; /* ----- flash ------------------------------------------------------------- */ static void dump(const char *title, void *data, size_t size) { int i, j; fprintf(stderr, "%s:\n", title); for (i = 0; i < size; i += 16) { fprintf(stderr, " %04x", i); for (j = 0; j != 16 && i+j < size; j++) fprintf(stderr, " %02x", ((uint8_t *) data)[i+j]); fprintf(stderr, "\n"); } } static void flash_device(void *data, size_t size) { int i; size_t len; uint8_t buf[256]; for (i = 0; i < size; i += 256) fputc('-', stderr); fputc('\r', stderr); flash_init(); flash_device_erase(); for (i = 0; i < size; i += 256) { fputc('*', stderr); fflush(stderr); len = size-i <= 256 ? size-i : 256; flash_block_write(i, data+i, len); } fputc('\r', stderr); for (i = 0; i < size; i += 256) { fputc('#', stderr); fflush(stderr); len = size-i <= 256 ? size-i : 256; flash_block_read(i, buf, len); if (memcmp(buf, data+i, len)) { fprintf(stderr, "compare error at 0x%04x\n", i); dump("Expected", data+i, len); dump("Read", buf, len); exit(1); } } fputc('\n', stderr); } static void do_flash(const char *name) { FILE *file; uint8_t code[16384]; file = fopen(name, "r"); if (!file) { perror(name); exit(1); } file_size = fread(code, 1, sizeof(code), file); (void) fclose(file); flash_device(code, file_size); } /* ----- protect ----------------------------------------------------------- */ static void protect(void) { uint8_t pages, lock_byte; pages = (file_size+511) >> 9; printf("Protecting %d page%s\n", pages, pages == 1 ? "" : "s"); lock_byte = ~pages; flash_block_write(layout->lock_byte, &lock_byte, 1); } /* ----- erase ------------------------------------------------------------- */ static void erase_flash(void) { flash_init(); flash_device_erase(); } /* ----- dump -------------------------------------------------------------- */ static void dump_flash(size_t size) { int i, j; size_t len; uint8_t buf[256], last[256]; int skipping = 0; flash_init(); for (i = 0; i < size; i += 16) { len = size-i <= 16 ? size-i : 16; flash_block_read(i, buf, len); if (i && !memcmp(last, buf, len)) { printf("%04x: *%c", i, skipping ? '\r' : '\n'); fflush(stdout); skipping = 1; continue; } skipping = 0; memcpy(last, buf, len); printf("%04x:", i); for (j = 0; j != len; j++) printf(" %02x", buf[j]); printf(" "); for (j = 0; j != len; j++) printf("%c", buf[j] >= ' ' && buf[j] <= '~' ? buf[j] : '.'); putchar('\n'); fflush(stdout); } } /* ----- identify ---------------------------------------------------------- */ static void identify_chip(uint8_t dev) { const struct chip *p; for (p = chips; p->name; p++) if (p->dev_id == dev) { chip = p; return; } } static void identify(void) { int i, same = 1; uint8_t dev, same_dev; c2_addr_write(0); fprintf(stderr, "Dev"); for (i = 0; i != 10; i++) { dev = c2_data_read(1); fprintf(stderr, " 0x%02x", dev); if (!i) same_dev = dev; else { if (same_dev != dev) same = 0; } } if (!same) { fprintf(stderr, "\ncommunication error\n"); exit(1); } identify_chip(same_dev); c2_addr_write(1); fprintf(stderr, "\nRev"); for (i = 0; i != 10; i++) fprintf(stderr, " 0x%02x", c2_data_read(1)); fprintf(stderr, "\n"); } static void determine_layout(int kb) { if (kb) { if (chip && kb > chip->max_flash_kb) { fprintf(stderr, "chip has only %d kB of flash\n", chip->max_flash_kb); exit(1); } } else { if (chip) kb = chip->max_flash_kb; } if (!kb) return; for (layout = mem_layouts; layout->flash_kb; layout++) if (layout->flash_kb == kb) break; if (!layout->flash_kb) { fprintf(stderr, "no memory layout found for %d kB\n", kb); exit(1); } } /* ----- main -------------------------------------------------------------- */ static void usage(const char *name) { fprintf(stderr, "usage: %s [-n] [-p] [-k flash_kb] file\n" " %s [-n] [-k flash_kb] -d\n" " %s [-n] -e\n" " %s [-n] -b pin_setup\n" " %s [-n]\n\n" " -b pin_setup\n" " Perform a boundary scan. pin_setup sets all 14 pins in this order:\n" " P0_0, P0_1, ..., P0_7, P2_0, ..., P2_5.\n" " Pins can be set to 0, 1, or R (pull-up). Dots can be used to structure\n" " the bit string. Prints what the pins read back (0 or 1) in the same\n" " order, with a dot between P0 and P2.\n" " -d dump Flash content\n" " -e erase whole Flash\n" " -k flash_kb set flash size (16/32/64; default: auto-select)\n" " -n do not provide power to the target (default: do provide power)\n" " -p protect the data after writing\n" "Invocation without argument resets the F32x.\n" , name, name, name, name, name); exit(1); } static void need_layout(void) { if (layout) return; fprintf(stderr, "please specify flash size with -k flash_kB\n"); exit(1); } int main(int argc, char **argv) { enum { mode_default = 0, mode_flash, mode_dump, mode_erase, mode_scan, } mode = mode_default; int do_protect = 0, power = 1, kb = 0; int c; while ((c = getopt(argc, argv, "bdek:np")) != EOF) switch (c) { case 'd': if (mode) usage(*argv); mode = mode_dump; break; case 'e': if (mode) usage(*argv); mode = mode_erase;; break; case 'b': if (mode) usage(*argv); mode = mode_scan;; break; case 'k': kb = atoi(optarg); break; case 'n': power = 0; break; case 'p': do_protect = 1; break; default: usage(*argv); } switch (mode) { case mode_default: switch (argc-optind) { case 0: break; case 1: mode = mode_flash; break; default: usage(*argv); } break; case mode_scan: if (argc != optind+1) usage(*argv); break; default: if (argc != optind) usage(*argv); break; } if (do_protect && mode != mode_flash) usage(*argv); c2_init(power); identify(); determine_layout(kb); if (chip) fprintf(stderr, "%s, ", chip->name); else fprintf(stderr, "unknown chip, "); if (layout) fprintf(stderr, "flash size: %d kB\n", layout->flash_kb); else fprintf(stderr, "flash size unknown\n"); switch (mode) { case mode_default: /* just reset */ break; case mode_dump: need_layout(); dump_flash(layout->lock_byte+2); break; case mode_erase: erase_flash(); break; case mode_flash: if (do_protect) need_layout(); do_flash(argv[optind]); if (do_protect) protect(); identify(); break; case mode_scan: boundary(argv[optind]); break; default: abort(); } c2_reset(); return 0; }