diff --git a/modules/script/script.c b/modules/script/script.c index 882e87e..f29975e 100644 --- a/modules/script/script.c +++ b/modules/script/script.c @@ -39,6 +39,7 @@ #include "os_interface/os_interface.h" #include "fpga/fpga.h" #include "bscan_spi/bscan_spi.h" +#include "spi_flash/spi_flash.h" #include "env.h" @@ -2997,6 +2998,140 @@ static int cmd_bscan_jedec(script_ctx *ctx, char *line) return JTAG_CORE_NO_ERROR; } +/* Adapt the BSCAN proxy to the spi_flash transport callback. */ +struct flash_proxy_ctx { + jtag_core *jc; + const fpga_target *t; +}; +static int flash_proxy_xfer(void *c, const uint8_t *tx, size_t txlen, + uint8_t *rx, size_t rxlen) +{ + struct flash_proxy_ctx *p = (struct flash_proxy_ctx *)c; + return bscan_spi_xfer(p->jc, p->t, tx, txlen, rx, rxlen); +} + +/* Look up the FPGA target for a chain device and wire a spi_flash over + * the proxy. Returns 0 and fills *sf/*pc, or prints an error and returns + * a JTAG_CORE_* code. */ +static int flash_setup(script_ctx *ctx, int device, + spi_flash *sf, struct flash_proxy_ctx *pc) +{ + jtag_core *jc = (jtag_core *)ctx->app_ctx; + unsigned long idcode; + const fpga_target *t; + + if (jtagcore_get_number_of_devices(jc) <= 0) { + ctx->script_printf(ctx, MSG_ERROR, "No device on the chain. Run jtag_autoinit first.\n"); + return JTAG_CORE_NOT_FOUND; + } + idcode = jtagcore_get_dev_id(jc, device); + t = fpga_lookup_by_idcode(idcode); + if (!t) { + ctx->script_printf(ctx, MSG_ERROR, "Device %d IDCODE 0x%.8lX not in FPGA registry\n", device, idcode); + return JTAG_CORE_NOT_FOUND; + } + pc->jc = jc; + pc->t = t; + memset(sf, 0, sizeof(*sf)); + sf->xfer = flash_proxy_xfer; + sf->ctx = pc; + return JTAG_CORE_NO_ERROR; +} + +const char *cmd_flash_detect_help[] = { + "", + "Identify the SPI flash behind the loaded BSCAN proxy: read its JEDEC", + "ID and match the built-in chip database. Requires a proxy loaded.", + ""}; +static int cmd_flash_detect(script_ctx *ctx, char *line) +{ + char dev_txt[DEFAULT_BUFLEN]; + struct flash_proxy_ctx pc; + spi_flash sf; + int device, r; + + if (get_param(ctx, line, 1, dev_txt) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_detect \n"); + return JTAG_CORE_BAD_PARAMETER; + } + device = (int)strtoul(dev_txt, NULL, 0); + if ((r = flash_setup(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; + + r = spi_flash_detect(&sf); + if (r < 0) { + ctx->script_printf(ctx, MSG_ERROR, "spi_flash_detect failed (proxy not loaded?)\n"); + return JTAG_CORE_IO_ERROR; + } + ctx->script_printf(ctx, MSG_INFO_0, "JEDEC ID: %.2X %.2X %.2X\n", + sf.jedec[0], sf.jedec[1], sf.jedec[2]); + ctx->last_data_value = (sf.jedec[0] << 16) | (sf.jedec[1] << 8) | sf.jedec[2]; + if (!sf.chip) { + ctx->script_printf(ctx, MSG_WARNING, "Flash not in database — add it to spi_flash.c\n"); + return JTAG_CORE_NO_ERROR; + } + ctx->script_printf(ctx, MSG_INFO_0, + "Flash: %s - %u MB, page %u B, sector %u B, %d-byte address\n", + sf.chip->name, sf.chip->size_bytes / (1024u * 1024u), + sf.chip->page_size, sf.chip->sector_size, sf.chip->addr_bytes); + return JTAG_CORE_NO_ERROR; +} + +const char *cmd_flash_read_help[] = { + " ", + "Read bytes from the SPI flash at (hex) and hex-dump them.", + "Read-only. Requires a proxy loaded and a flash recognised by flash_detect.", + ""}; +static int cmd_flash_read(script_ctx *ctx, char *line) +{ + char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN]; + struct flash_proxy_ctx pc; + spi_flash sf; + uint8_t *buf; + uint32_t addr; + size_t len, i; + int device, r; + + if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || + get_param(ctx, line, 3, len_txt) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_read \n"); + return JTAG_CORE_BAD_PARAMETER; + } + device = (int)strtoul(dev_txt, NULL, 0); + addr = (uint32_t)strtoul(addr_txt, NULL, 0); + len = (size_t)strtoul(len_txt, NULL, 0); + if (len == 0) return JTAG_CORE_NO_ERROR; + if (len > 65536) { + ctx->script_printf(ctx, MSG_ERROR, "flash_read: len capped at 65536 for an interactive dump\n"); + return JTAG_CORE_BAD_PARAMETER; + } + if ((r = flash_setup(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; + + if (spi_flash_detect(&sf) < 0 || !sf.chip) { + ctx->script_printf(ctx, MSG_ERROR, "Flash not detected/known — run flash_detect first.\n"); + return JTAG_CORE_NOT_FOUND; + } + + buf = malloc(len); + if (!buf) return JTAG_CORE_BAD_PARAMETER; + if (spi_flash_read(&sf, addr, buf, len) < 0) { + free(buf); + ctx->script_printf(ctx, MSG_ERROR, "spi_flash_read failed\n"); + return JTAG_CORE_IO_ERROR; + } + + for (i = 0; i < len; i += 16) { + char linebuf[16 * 3 + 16]; + size_t j, pos = 0; + pos += (size_t)snprintf(linebuf + pos, sizeof(linebuf) - pos, "%.8X: ", (unsigned)(addr + i)); + for (j = 0; j < 16 && (i + j) < len; j++) { + pos += (size_t)snprintf(linebuf + pos, sizeof(linebuf) - pos, "%.2X ", buf[i + j]); + } + ctx->script_printf(ctx, MSG_INFO_0, "%s\n", linebuf); + } + free(buf); + return JTAG_CORE_NO_ERROR; +} + cmd_list script_commands_list[] = { {"print", cmd_print, cmd_print_help}, @@ -3045,6 +3180,8 @@ cmd_list script_commands_list[] = {"bscan_shift_dr", cmd_bscan_shift_dr, cmd_bscan_shift_dr_help}, {"bscan_load_bitstream", cmd_bscan_load_bitstream, cmd_bscan_load_bitstream_help}, {"bscan_jedec", cmd_bscan_jedec, cmd_bscan_jedec_help}, + {"flash_detect", cmd_flash_detect, cmd_flash_detect_help}, + {"flash_read", cmd_flash_read, cmd_flash_read_help}, {0, 0}}; ///////////////////////////////////////////////////////////////////////////////