X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fpld%2Fpld.c;h=ef7993c5d4e60080248cf755cd8c4fa6e68a2a70;hp=b2623613e02bdeef5ca180e8f36707af872878d4;hb=HEAD;hpb=16b6b5e7a86353dbc0c4823fe3d772c0faca7c1c diff --git a/src/pld/pld.c b/src/pld/pld.c index b2623613e0..81fb0c4632 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -1,37 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pld.h" +#include #include +#include #include -/* pld drivers - */ -extern struct pld_driver virtex2_pld; - -static struct pld_driver *pld_drivers[] = -{ +static struct pld_driver *pld_drivers[] = { + &efinix_pld, + &gatemate_pld, + &gowin_pld, + &intel_pld, + &lattice_pld, &virtex2_pld, NULL, }; @@ -43,10 +33,9 @@ struct pld_device *get_pld_device_by_num(int num) struct pld_device *p; int i = 0; - for (p = pld_devices; p; p = p->next) - { - if (i++ == num) - { + for (p = pld_devices; p; p = p->next) { + if (i++ == num) { + LOG_WARNING("DEPRECATED: use pld name \"%s\" instead of number %d", p->name, num); return p; } } @@ -54,72 +43,188 @@ struct pld_device *get_pld_device_by_num(int num) return NULL; } -/* pld device [driver_options ...] - */ -COMMAND_HANDLER(handle_pld_device_command) +struct pld_device *get_pld_device_by_name(const char *name) { - int i; - int found = 0; + for (struct pld_device *p = pld_devices; p; p = p->next) { + if (strcmp(p->name, name) == 0) + return p; + } - if (CMD_ARGC < 1) - { + return NULL; +} + +struct pld_device *get_pld_device_by_name_or_numstr(const char *str) +{ + struct pld_device *dev = get_pld_device_by_name(str); + if (dev) + return dev; + + char *end; + unsigned long dev_num = strtoul(str, &end, 0); + if (*end || dev_num > INT_MAX) { + LOG_ERROR("Invalid argument"); + return NULL; + } + + return get_pld_device_by_num(dev_num); +} + + +int pld_has_jtagspi_instruction(struct pld_device *pld_device, bool *has_instruction) +{ + *has_instruction = false; /* default is using a proxy bitstream */ + + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->has_jtagspi_instruction) + return pld_driver->has_jtagspi_instruction(pld_device, has_instruction); + /* else, take the default (proxy bitstream) */ + return ERROR_OK; +} + +int pld_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->get_jtagspi_userircode) + return pld_driver->get_jtagspi_userircode(pld_device, ir); + + return ERROR_FAIL; +} + +int pld_get_jtagspi_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->get_stuff_bits) + return pld_driver->get_stuff_bits(pld_device, facing_read_bits, trailing_write_bits); + + return ERROR_OK; +} + +int pld_connect_spi_to_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->connect_spi_to_jtag) + return pld_driver->connect_spi_to_jtag(pld_device); + + return ERROR_FAIL; +} + +int pld_disconnect_spi_from_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->disconnect_spi_from_jtag) + return pld_driver->disconnect_spi_from_jtag(pld_device); + + return ERROR_FAIL; +} + +COMMAND_HANDLER(handle_pld_create_command) +{ + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_driver *pld_driver = NULL; + + for (int i = 0; pld_drivers[i]; i++) { + if (strcmp(CMD_ARGV[1], pld_drivers[i]->name) == 0) { + pld_driver = pld_drivers[i]; + break; + } } - for (i = 0; pld_drivers[i]; i++) - { - if (strcmp(CMD_ARGV[0], pld_drivers[i]->name) == 0) - { - struct pld_device *p, *c; - - /* register pld specific commands */ - int retval; - if (pld_drivers[i]->commands) { - retval = register_commands(CMD_CTX, NULL, - pld_drivers[i]->commands); - if (ERROR_OK != retval) - { - LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[0]); - return ERROR_FAIL; - } - } - - c = malloc(sizeof(struct pld_device)); - c->driver = pld_drivers[i]; - c->next = NULL; - - retval = CALL_COMMAND_HANDLER( - pld_drivers[i]->pld_device_command, c); - if (ERROR_OK != retval) - { - LOG_ERROR("'%s' driver rejected pld device", - CMD_ARGV[0]); - free(c); - return ERROR_OK; - } - - /* put pld device in linked list */ - if (pld_devices) - { - /* find last pld device */ - for (p = pld_devices; p && p->next; p = p->next); - if (p) - p->next = c; - } - else - { - pld_devices = c; - } - - found = 1; + if (!pld_driver) { + LOG_ERROR("pld driver '%s' not found", CMD_ARGV[1]); + return ERROR_FAIL; /* exit(-1); */ + } + + if (get_pld_device_by_name(CMD_ARGV[0])) { + LOG_ERROR("pld device with name '%s' already exists", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct pld_device *pld_device = malloc(sizeof(struct pld_device)); + if (!pld_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + pld_device->driver = pld_driver; + pld_device->next = NULL; + + int retval = CALL_COMMAND_HANDLER(pld_driver->pld_create_command, pld_device); + if (retval != ERROR_OK) { + LOG_ERROR("'%s' driver rejected pld device", + CMD_ARGV[1]); + free(pld_device); + return ERROR_OK; + } + pld_device->name = strdup(CMD_ARGV[0]); + if (!pld_device->name) { + LOG_ERROR("Out of memory"); + free(pld_device); + return ERROR_FAIL; + } + + /* register pld specific commands */ + if (pld_driver->commands) { + retval = register_commands(CMD_CTX, NULL, pld_driver->commands); + if (retval != ERROR_OK) { + LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[1]); + free(pld_device->name); + free(pld_device); + return ERROR_FAIL; } } - /* no matching pld driver found */ - if (!found) - { - LOG_ERROR("pld driver '%s' not found", CMD_ARGV[0]); - exit(-1); + if (pld_devices) { + /* find last pld device */ + struct pld_device *p = pld_devices; + for (; p && p->next; p = p->next) + ; + if (p) + p->next = pld_device; + } else { + pld_devices = pld_device; } return ERROR_OK; @@ -130,16 +235,13 @@ COMMAND_HANDLER(handle_pld_devices_command) struct pld_device *p; int i = 0; - if (!pld_devices) - { - command_print(CMD_CTX, "no pld devices configured"); + if (!pld_devices) { + command_print(CMD, "no pld devices configured"); return ERROR_OK; } for (p = pld_devices; p; p = p->next) - { - command_print(CMD_CTX, "#%i: %s", i++, p->driver->name); - } + command_print(CMD, "#%i: %s (driver: %s)", i++, p->name, p->driver->name); return ERROR_OK; } @@ -153,35 +255,41 @@ COMMAND_HANDLER(handle_pld_load_command) gettimeofday(&start, NULL); if (CMD_ARGC < 2) - { return ERROR_COMMAND_SYNTAX_ERROR; - } - unsigned dev_id; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); - p = get_pld_device_by_num(dev_id); - if (!p) - { - command_print(CMD_CTX, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + p = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!p) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_OK; } - if ((retval = p->driver->load(p, CMD_ARGV[1])) != ERROR_OK) - { - command_print(CMD_CTX, "failed loading file %s to pld device %u", - CMD_ARGV[1], dev_id); - switch (retval) - { - } - return retval; + struct stat input_stat; + if (stat(CMD_ARGV[1], &input_stat) == -1) { + LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; } - else - { + + if (S_ISDIR(input_stat.st_mode)) { + LOG_ERROR("%s is a directory", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (input_stat.st_size == 0) { + LOG_ERROR("Empty file %s", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + retval = p->driver->load(p, CMD_ARGV[1]); + if (retval != ERROR_OK) { + command_print(CMD, "failed loading file %s to pld device %s", + CMD_ARGV[1], CMD_ARGV[0]); + return retval; + } else { gettimeofday(&end, NULL); timeval_subtract(&duration, &end, &start); - command_print(CMD_CTX, "loaded file %s to pld device %u in %jis %jius", - CMD_ARGV[1], dev_id, + command_print(CMD, "loaded file %s to pld device %s in %jis %jius", + CMD_ARGV[1], CMD_ARGV[0], (intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec); } @@ -194,13 +302,14 @@ static const struct command_registration pld_exec_command_handlers[] = { .handler = handle_pld_devices_command, .mode = COMMAND_EXEC, .help = "list configured pld devices", + .usage = "", }, { .name = "load", .handler = handle_pld_load_command, .mode = COMMAND_EXEC, .help = "load configuration file into PLD", - .usage = "pld_num filename", + .usage = "pld_name filename", }, COMMAND_REGISTRATION_DONE }; @@ -210,8 +319,7 @@ static int pld_init(struct command_context *cmd_ctx) if (!pld_devices) return ERROR_OK; - struct command *parent = command_find_in_context(cmd_ctx, "pld"); - return register_commands(cmd_ctx, parent, pld_exec_command_handlers); + return register_commands(cmd_ctx, "pld", pld_exec_command_handlers); } COMMAND_HANDLER(handle_pld_init_command) @@ -219,9 +327,8 @@ COMMAND_HANDLER(handle_pld_init_command) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - static bool pld_initialized = false; - if (pld_initialized) - { + static bool pld_initialized; + if (pld_initialized) { LOG_INFO("'pld init' has already been called"); return ERROR_OK; } @@ -233,17 +340,18 @@ COMMAND_HANDLER(handle_pld_init_command) static const struct command_registration pld_config_command_handlers[] = { { - .name = "device", + .name = "create", .mode = COMMAND_CONFIG, - .handler = handle_pld_device_command, - .help = "configure a PLD device", - .usage = "driver_name [driver_args ... ]", + .handler = handle_pld_create_command, + .help = "create a PLD device", + .usage = "name.pld driver_name [driver_args ... ]", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_pld_init_command, .help = "initialize PLD devices", + .usage = "" }, COMMAND_REGISTRATION_DONE }; @@ -252,6 +360,7 @@ static const struct command_registration pld_command_handler[] = { .name = "pld", .mode = COMMAND_ANY, .help = "programmable logic device commands", + .usage = "", .chain = pld_config_command_handlers, }, COMMAND_REGISTRATION_DONE