From d8c9f66d25cde09570e4f87e354216470b72de7e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 1 Jun 2023 10:50:50 +0200 Subject: [PATCH 01/49] jep106: update to revision JEP106BG May 2023 The original document from Jedec does not report the entry for "21 NXP (Philips)", replaced by "c". It's clearly a typo. Keep the line from JEP106BF.01 for "NXP (Philips)". Change-Id: I30215c4ff08d5f112305cde6ab7a3176cdcef948 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7727 Tested-by: jenkins --- src/helper/jep106.inc | 61 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index cb67b926a3..6c81967659 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -8,7 +8,9 @@ * identification code list, please visit the JEDEC website at www.jedec.org . */ -/* This file is aligned to revision JEP106BF.01 October 2022. */ +/* This file is aligned to revision JEP106BG May 2023. */ + +/* "NXP (Philips)" is reported below, while missing in JEP106BG */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", @@ -86,7 +88,7 @@ [0][0x4a - 1] = "Compaq", [0][0x4b - 1] = "Protocol Engines", [0][0x4c - 1] = "SCI", -[0][0x4d - 1] = "Seiko Instruments", +[0][0x4d - 1] = "ABLIC", [0][0x4e - 1] = "Samsung", [0][0x4f - 1] = "I3 Design System", [0][0x50 - 1] = "Klic", @@ -972,7 +974,7 @@ [7][0x4e - 1] = "Mustang", [7][0x4f - 1] = "Orca Systems", [7][0x50 - 1] = "Passif Semiconductor", -[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc", +[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing)", [7][0x52 - 1] = "Memphis Electronic", [7][0x53 - 1] = "Beckhoff Automation GmbH", [7][0x54 - 1] = "Harmony Semiconductor Corp", @@ -1786,4 +1788,57 @@ [14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd", [14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd", [14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd", +[14][0x0d - 1] = "Pliops Ltd", +[14][0x0e - 1] = "Cix Technology (Shanghai) Co Ltd", +[14][0x0f - 1] = "TeraDevices Inc", +[14][0x10 - 1] = "SpacemiT (Hangzhou)Technology Co Ltd", +[14][0x11 - 1] = "InnoPhase loT Inc", +[14][0x12 - 1] = "InnoPhase loT Inc", +[14][0x13 - 1] = "Yunhight Microelectronics", +[14][0x14 - 1] = "Samnix", +[14][0x15 - 1] = "HKC Storage Co Ltd", +[14][0x16 - 1] = "Chiplego Technology (Shanghai) Co Ltd", +[14][0x17 - 1] = "StoreSkill", +[14][0x18 - 1] = "Shenzhen Astou Technology Company", +[14][0x19 - 1] = "Guangdong LeafFive Technology Limited", +[14][0x1a - 1] = "Jin JuQuan", +[14][0x1b - 1] = "Huaxuan Technology (Shenzhen) Co Ltd", +[14][0x1c - 1] = "Gigastone Corporation", +[14][0x1d - 1] = "Kinsotin", +[14][0x1e - 1] = "PengYing", +[14][0x1f - 1] = "Shenzhen Xunhi Technology Co Ltd", +[14][0x20 - 1] = "FOXX Storage Inc", +[14][0x21 - 1] = "Shanghai Belling Corporation Ltd", +[14][0x22 - 1] = "Glenfy Tech Co Ltd", +[14][0x23 - 1] = "Sahasra Semiconductors Pvt Ltd", +[14][0x24 - 1] = "Chongqing SeekWave Technology Co Ltd", +[14][0x25 - 1] = "Shenzhen Zhixing Intelligent Manufacturing", +[14][0x26 - 1] = "Ethernovia", +[14][0x27 - 1] = "Shenzhen Xinrongda Technology Co Ltd", +[14][0x28 - 1] = "Hangzhou Clounix Technology Limited", +[14][0x29 - 1] = "JGINYUE", +[14][0x2a - 1] = "Shenzhen Xinwei Semiconductor Co Ltd", +[14][0x2b - 1] = "COLORFIRE Technology Co Ltd", +[14][0x2c - 1] = "B LKE", +[14][0x2d - 1] = "ZHUDIAN", +[14][0x2e - 1] = "REECHO", +[14][0x2f - 1] = "Enphase Energy Inc", +[14][0x30 - 1] = "Shenzhen Yingrui Storage Technology Co Ltd", +[14][0x31 - 1] = "Shenzhen Sinomos Semiconductor Technology", +[14][0x32 - 1] = "O2micro International Limited", +[14][0x33 - 1] = "Axelera AI BV", +[14][0x34 - 1] = "Silicon Legend Technology (Suzhou) Co Ltd", +[14][0x35 - 1] = "Suzhou Novosense Microelectronics Co Ltd", +[14][0x36 - 1] = "Pirateman", +[14][0x37 - 1] = "Yangtze MasonSemi", +[14][0x38 - 1] = "Shanghai Yunsilicon Technology Co Ltd", +[14][0x39 - 1] = "Rayson", +[14][0x3a - 1] = "Alphawave IP", +[14][0x3b - 1] = "Shenzhen Visions Chip Electronic Technology", +[14][0x3c - 1] = "KYO Group", +[14][0x3d - 1] = "Shenzhen Aboison Technology Co Ltd", +[14][0x3e - 1] = "Shenzhen JingSheng Semiconducto Co Ltd", +[14][0x3f - 1] = "Shenzhen Dingsheng Technology Co Ltd", +[14][0x40 - 1] = "EVAS Intelligence Co Ltd", +[14][0x41 - 1] = "Kaibright Electronic Technologies", /* EOF */ From 63f4e7c72a27fb828fe1be3003be6a94519e1c12 Mon Sep 17 00:00:00 2001 From: Lorenz Brun Date: Sat, 24 Dec 2022 03:56:22 +0100 Subject: [PATCH 02/49] target/ti-cjtag: make switching to JTAG more reliable The current cJTAG to JTAG switching commands for TI chips are not particularly reliable, especially on chips with accurate timing. On a Raspberry Pi the existing sequence has (depending on cabling and chip) a ~50% chance of working, on a much better-behaved FT2232H it doesn't manage to enable full JTAG at all. This change runs a bunch of test-idle cycles before actually attempting to switch to full JTAG. This makes the switch reliable even at high clock speeds (>100kHz) and from precise sources like the FT2232H. Change-Id: I9293e884bf3e9606d529756ae4483b844d3c39db Reported-by: Phil Wiggum Fixes: https://sourceforge.net/p/openocd/tickets/375/ Signed-off-by: Lorenz Brun Reviewed-on: https://review.openocd.org/c/openocd/+/7419 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti-cjtag.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/tcl/target/ti-cjtag.cfg b/tcl/target/ti-cjtag.cfg index d5e13e269a..97111f1cc4 100644 --- a/tcl/target/ti-cjtag.cfg +++ b/tcl/target/ti-cjtag.cfg @@ -5,6 +5,7 @@ # Read section 6.3 in http://www.ti.com/lit/pdf/swru319 for more information. proc ti_cjtag_to_4pin_jtag {jrc} { # Bypass + runtest 20 irscan $jrc 0x3f -endstate RUN/IDLE # Two zero bit scans and a one bit drshift pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE From eebcf3cff16afbce2c57cf2dba6f562e17713093 Mon Sep 17 00:00:00 2001 From: Marek Vrbka Date: Mon, 5 Jun 2023 08:35:09 +0200 Subject: [PATCH 03/49] riscv/semihosting: Fix ebreak skip on fileio mode This patch fixes skipping the semihosting sequence if the fileio mode is enabled on riscv. This change was tested by me and is in the riscv-openocd fork for a year now. Original merge request: https://github.com/riscv/riscv-openocd/pull/699 Original author: Wu Zhigang zhigang.wu@starfivetech.com https://github.com/wzgpeter Change-Id: Iadaa0a48d1f82d3a7ca168f8a6b656ff6ab78e03 Signed-off-by: Marek Vrbka Reviewed-on: https://review.openocd.org/c/openocd/+/7729 Tested-by: jenkins Reviewed-by: Tim Newsome --- src/target/riscv/riscv_semihosting.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 1bc4e1a166..da237ef337 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -141,16 +141,16 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) } } + /* Resume right after the EBREAK 4 bytes instruction. */ + *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4); + if (*retval != ERROR_OK) + return SEMIHOSTING_ERROR; + /* * Resume target if we are not waiting on a fileio * operation to complete. */ if (semihosting->is_resumable && !semihosting->hit_fileio) { - /* Resume right after the EBREAK 4 bytes instruction. */ - *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4); - if (*retval != ERROR_OK) - return SEMIHOSTING_ERROR; - LOG_DEBUG(" -> HANDLED"); return SEMIHOSTING_HANDLED; } From 6ef75352f1e4a86f66bf98e1792a68345c77f9a7 Mon Sep 17 00:00:00 2001 From: Marek Vrbka Date: Tue, 30 May 2023 15:36:12 +0200 Subject: [PATCH 04/49] semihosting: improve semihosting opcode debug messages This patch introduces function semihosting_opcode_to_str() which converts semihosting opcodes to strings. This function is then used in debug messages to improve log analysis and troubleshooting. Change-Id: Iffea49dae13d6a626ae0db40d379cba3c9ea5bd3 Signed-off-by: Marek Vrbka Reviewed-on: https://review.openocd.org/c/openocd/+/7726 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Jan Matyas --- src/target/semihosting_common.c | 70 +++++++++++++++++++++++++++++++-- src/target/semihosting_common.h | 9 +++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 6c91876c73..107b6d3edc 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -294,6 +294,66 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd) */ static char *semihosting_user_op_params; +const char *semihosting_opcode_to_str(const uint64_t opcode) +{ + switch (opcode) { + case SEMIHOSTING_SYS_CLOSE: + return "CLOSE"; + case SEMIHOSTING_SYS_CLOCK: + return "CLOCK"; + case SEMIHOSTING_SYS_ELAPSED: + return "ELAPSED"; + case SEMIHOSTING_SYS_ERRNO: + return "ERRNO"; + case SEMIHOSTING_SYS_EXIT: + return "EXIT"; + case SEMIHOSTING_SYS_EXIT_EXTENDED: + return "EXIT_EXTENDED"; + case SEMIHOSTING_SYS_FLEN: + return "FLEN"; + case SEMIHOSTING_SYS_GET_CMDLINE: + return "GET_CMDLINE"; + case SEMIHOSTING_SYS_HEAPINFO: + return "HEAPINFO"; + case SEMIHOSTING_SYS_ISERROR: + return "ISERROR"; + case SEMIHOSTING_SYS_ISTTY: + return "ISTTY"; + case SEMIHOSTING_SYS_OPEN: + return "OPEN"; + case SEMIHOSTING_SYS_READ: + return "READ"; + case SEMIHOSTING_SYS_READC: + return "READC"; + case SEMIHOSTING_SYS_REMOVE: + return "REMOVE"; + case SEMIHOSTING_SYS_RENAME: + return "RENAME"; + case SEMIHOSTING_SYS_SEEK: + return "SEEK"; + case SEMIHOSTING_SYS_SYSTEM: + return "SYSTEM"; + case SEMIHOSTING_SYS_TICKFREQ: + return "TICKFREQ"; + case SEMIHOSTING_SYS_TIME: + return "TIME"; + case SEMIHOSTING_SYS_TMPNAM: + return "TMPNAM"; + case SEMIHOSTING_SYS_WRITE: + return "WRITE"; + case SEMIHOSTING_SYS_WRITEC: + return "WRITEC"; + case SEMIHOSTING_SYS_WRITE0: + return "WRITE0"; + case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF: + return "USER_CMD"; + case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END: + return "ARM_RESERVED_CMD"; + default: + return ""; + } +} + /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation @@ -323,8 +383,9 @@ int semihosting_common(struct target *target) /* Enough space to hold 4 long words. */ uint8_t fields[4*8]; - LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op, - semihosting->param); + LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op, + semihosting_opcode_to_str(semihosting->op), + semihosting->param); switch (semihosting->op) { @@ -1470,8 +1531,9 @@ int semihosting_common(struct target *target) retval = target_read_buffer(target, addr, len, (uint8_t *)(semihosting_user_op_params)); if (retval != ERROR_OK) { - LOG_ERROR("Failed to read from target, semihosting op=0x%x", - semihosting->op); + LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)", + semihosting->op, + semihosting_opcode_to_str(semihosting->op)); free(semihosting_user_op_params); semihosting_user_op_params = NULL; return retval; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 7c5f748f43..a1848b4881 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -65,6 +65,8 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + SEMIHOSTING_ARM_RESERVED_START = 0x32, + SEMIHOSTING_ARM_RESERVED_END = 0xFF, SEMIHOSTING_USER_CMD_0X100 = 0x100, /* First user cmd op code */ SEMIHOSTING_USER_CMD_0X107 = 0x107, /* Last supported user cmd op code */ SEMIHOSTING_USER_CMD_0X1FF = 0x1FF, /* Last user cmd op code */ @@ -186,6 +188,13 @@ struct semihosting { int (*post_result)(struct target *target); }; +/** + * @brief Convert the syscall opcode to a human-readable string + * @param[in] opcode Syscall opcode + * @return String representation of syscall opcode + */ +const char *semihosting_opcode_to_str(uint64_t opcode); + int semihosting_common_init(struct target *target, void *setup, void *post_result); int semihosting_common(struct target *target); From 56fd04832abc0ebadc21ee6127be4be9c7b46e15 Mon Sep 17 00:00:00 2001 From: Marek Vrbka Date: Thu, 1 Jun 2023 12:42:03 +0200 Subject: [PATCH 05/49] semihosting: fix handling of errno This patch fixes the handling of errno by setting the sys_errn only if error has actually occurred during the semihosting call. It also fixes few issues where error was not set in the first place. Change-Id: I2fbe562f3ec5e6220b800de04cd33aa1f409c7a0 Signed-off-by: Marek Vrbka Reviewed-on: https://review.openocd.org/c/openocd/+/7730 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Jan Matyas --- src/target/semihosting_common.c | 79 ++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 107b6d3edc..f7acc6092d 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -223,7 +223,10 @@ static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void * return semihosting_redirect_write(semihosting, buf, size); /* default write */ - return write(fd, buf, size); + int result = write(fd, buf, size); + if (result == -1) + semihosting->sys_errno = errno; + return result; } static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size) @@ -268,7 +271,8 @@ static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, /* default read */ ssize_t result = read(fd, buf, size); - semihosting->sys_errno = errno; + if (result == -1) + semihosting->sys_errno = errno; return result; } @@ -449,12 +453,7 @@ int semihosting_common(struct target *target) (fd == 0) ? "stdin" : (fd == 1) ? "stdout" : "stderr"); /* Just pretend success */ - if (semihosting->is_fileio) { - semihosting->result = 0; - } else { - semihosting->result = 0; - semihosting->sys_errno = 0; - } + semihosting->result = 0; break; } /* Close the descriptor */ @@ -464,7 +463,8 @@ int semihosting_common(struct target *target) fileio_info->param_1 = fd; } else { semihosting->result = close(fd); - semihosting->sys_errno = errno; + if (semihosting->result == -1) + semihosting->sys_errno = errno; LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); } } @@ -842,7 +842,8 @@ int semihosting_common(struct target *target) int fd = semihosting_get_field(target, 0, fields); // isatty() on Windows may return any non-zero value if fd is a terminal semihosting->result = isatty(fd) ? 1 : 0; - semihosting->sys_errno = errno; + if (semihosting->result == 0) + semihosting->sys_errno = errno; LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result); } break; @@ -934,14 +935,16 @@ int semihosting_common(struct target *target) semihosting->result = -1; semihosting->sys_errno = EINVAL; } else if (strcmp((char *)fn, ":tt") == 0) { - if (mode == 0) + if (mode == 0) { semihosting->result = 0; - else if (mode == 4) + } else if (mode == 4) { semihosting->result = 1; - else if (mode == 8) + } else if (mode == 8) { semihosting->result = 2; - else + } else { semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } } else { semihosting->hit_fileio = true; fileio_info->identifier = "open"; @@ -956,25 +959,23 @@ int semihosting_common(struct target *target) * - 0-3 ("r") for stdin, * - 4-7 ("w") for stdout, * - 8-11 ("a") for stderr */ + int fd; if (mode < 4) { - int fd = dup(STDIN_FILENO); - semihosting->result = fd; + fd = dup(STDIN_FILENO); semihosting->stdin_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDIN)=%" PRId64, semihosting->result); + LOG_DEBUG("dup(STDIN)=%d", fd); } else if (mode < 8) { - int fd = dup(STDOUT_FILENO); - semihosting->result = fd; + fd = dup(STDOUT_FILENO); semihosting->stdout_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDOUT)=%" PRId64, semihosting->result); + LOG_DEBUG("dup(STDOUT)=%d", fd); } else { - int fd = dup(STDERR_FILENO); - semihosting->result = fd; + fd = dup(STDERR_FILENO); semihosting->stderr_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDERR)=%" PRId64, semihosting->result); + LOG_DEBUG("dup(STDERR)=%d", fd); } + semihosting->result = fd; + if (fd == -1) + semihosting->sys_errno = errno; } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously @@ -982,7 +983,8 @@ int semihosting_common(struct target *target) semihosting->result = open((char *)fn, open_host_modeflags[mode], 0644); - semihosting->sys_errno = errno; + if (semihosting->result == -1) + semihosting->sys_errno = errno; LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); } } @@ -1131,7 +1133,8 @@ int semihosting_common(struct target *target) } fn[len] = 0; semihosting->result = remove((char *)fn); - semihosting->sys_errno = errno; + if (semihosting->result == -1) + semihosting->sys_errno = errno; LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); free(fn); @@ -1200,7 +1203,9 @@ int semihosting_common(struct target *target) fn2[len2] = 0; semihosting->result = rename((char *)fn1, (char *)fn2); - semihosting->sys_errno = errno; + // rename() on Windows returns nonzero on error + if (semihosting->result != 0) + semihosting->sys_errno = errno; LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno); free(fn1); free(fn2); @@ -1245,7 +1250,8 @@ int semihosting_common(struct target *target) fileio_info->param_3 = SEEK_SET; } else { semihosting->result = lseek(fd, pos, SEEK_SET); - semihosting->sys_errno = errno; + if (semihosting->result == -1) + semihosting->sys_errno = errno; LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result); if (semihosting->result == pos) semihosting->result = 0; @@ -1383,7 +1389,6 @@ int semihosting_common(struct target *target) return retval; } semihosting->result = semihosting_write(semihosting, fd, buf, len); - semihosting->sys_errno = errno; LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, fd, addr, @@ -1671,7 +1676,6 @@ static int semihosting_common_fileio_end(struct target *target, int result, semihosting->hit_fileio = false; semihosting->result = result; - semihosting->sys_errno = fileio_errno; /* * Some fileio results do not match up with what the semihosting @@ -1693,6 +1697,17 @@ static int semihosting_common_fileio_end(struct target *target, int result, break; } + bool fileio_failed = false; + if (semihosting->op == SEMIHOSTING_SYS_ISTTY) + fileio_failed = (semihosting->result == 0); + else if (semihosting->op == SEMIHOSTING_SYS_RENAME) + fileio_failed = (semihosting->result != 0); + else + fileio_failed = (semihosting->result == -1); + + if (fileio_failed) + semihosting->sys_errno = fileio_errno; + return semihosting->post_result(target); } From 7335fbdbda6ff353ec878bf740721f2b13dde7ce Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 19 Jun 2023 23:37:08 +0200 Subject: [PATCH 06/49] tcl/board/bemicro: source cycloneiii.cfg from correct path Change-Id: Ib1d1be1067107633949a202a05f7fd06831ba84b Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7751 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/bemicro_cycloneiii.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg index 7781bd5c7c..95dd394fd4 100644 --- a/tcl/board/bemicro_cycloneiii.cfg +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -12,7 +12,7 @@ transport select jtag adapter speed 10000 -source [find cpld/altera-cycloneiii.cfg] +source [find fpga/altera-cycloneiii.cfg] #quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf From 5ae0264055b2d5e5cea024aba2dd291a4d1d4ada Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 3 Jun 2023 20:16:19 +0200 Subject: [PATCH 07/49] pld: give devices a name for referencing in scripts Change-Id: I05e8596ffacdb6cd8da4dd8a40bb460183f4930a Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7728 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 66 ++++++------- src/jtag/startup.tcl | 14 +++ src/pld/efinix.c | 13 ++- src/pld/gatemate.c | 17 ++-- src/pld/gowin.c | 44 ++++----- src/pld/intel.c | 57 +++++------ src/pld/lattice.c | 72 +++++++------- src/pld/pld.c | 166 ++++++++++++++++++++------------- src/pld/pld.h | 11 ++- src/pld/virtex2.c | 29 +++--- tcl/cpld/xilinx-xc6s.cfg | 2 +- tcl/cpld/xilinx-xc7.cfg | 2 +- tcl/cpld/xilinx-xcu.cfg | 2 +- tcl/fpga/altera-arriaii.cfg | 2 +- tcl/fpga/altera-cycloneiii.cfg | 2 +- tcl/fpga/altera-cycloneiv.cfg | 2 +- tcl/fpga/altera-cyclonev.cfg | 2 +- tcl/fpga/efinix_titanium.cfg | 2 +- tcl/fpga/efinix_trion.cfg | 2 +- tcl/fpga/gatemate.cfg | 2 +- tcl/fpga/gowin_gw1n.cfg | 2 +- tcl/fpga/lattice_certus.cfg | 2 +- tcl/fpga/lattice_certuspro.cfg | 2 +- tcl/fpga/lattice_ecp2.cfg | 2 +- tcl/fpga/lattice_ecp3.cfg | 2 +- tcl/fpga/lattice_ecp5.cfg | 2 +- tcl/target/zynq_7000.cfg | 2 +- 27 files changed, 285 insertions(+), 238 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 832047f0ea..7c579e30cd 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8575,22 +8575,24 @@ As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. Also, each such PLD requires a driver. -They are referenced by the number shown by the @command{pld devices} command, -and new PLDs are defined by @command{pld device driver_name}. - -@deffn {Config Command} {pld device} driver_name tap_name [driver_options] -Defines a new PLD device, supported by driver @var{driver_name}, -using the TAP named @var{tap_name}. -The driver may make use of any @var{driver_options} to configure its -behavior. +They are referenced by the name which was given when the pld was created or +the number shown by the @command{pld devices} command. +New PLDs are defined by @command{pld create pld_name driver_name -chain-position tap_name [driver_options]}. + +@deffn {Config Command} {pld create} pld_name driver_name -chain-position tap_name [driver_options] +Creates a new PLD device, supported by driver @var{driver_name}, +assigning @var{pld_name} for further reference. +@code{-chain-position} @var{tap_name} names the TAP +used to access this target. +The driver may make use of any @var{driver_options} to configure its behavior. @end deffn @deffn {Command} {pld devices} -Lists the PLDs and their numbers. +List the known PLDs with their name. @end deffn -@deffn {Command} {pld load} num filename -Loads the file @file{filename} into the PLD identified by @var{num}. +@deffn {Command} {pld load} pld_name filename +Loads the file @file{filename} into the PLD identified by @var{pld_name}. The file format must be inferred by the driver. @end deffn @@ -8600,12 +8602,12 @@ Drivers may support PLD-specific options to the @command{pld device} definition command, and may also define commands usable only with that particular type of PLD. -@deffn {FPGA Driver} {virtex2} [no_jstart] +@deffn {FPGA Driver} {virtex2} [@option{-no_jstart}] Virtex-II is a family of FPGAs sold by Xilinx. This driver can also be used to load Series3, Series6, Series7 and Zynq 7000 devices. It supports the IEEE 1532 standard for In-System Configuration (ISC). -If @var{no_jstart} is non-zero, the JSTART instruction is not used after +If @var{-no_jstart} is given, the JSTART instruction is not used after loading the bitstream. While required for Series2, Series3, and Series6, it breaks bitstream loading on Series7. @@ -8615,38 +8617,38 @@ openocd -f board/digilent_zedboard.cfg -c "init" \ @end example -@deffn {Command} {virtex2 read_stat} num +@deffn {Command} {virtex2 read_stat} pld_name Reads and displays the Virtex-II status register (STAT) -for FPGA @var{num}. +for FPGA @var{pld_name}. @end deffn @end deffn -@deffn {FPGA Driver} {lattice} [family] +@deffn {FPGA Driver} {lattice} [@option{-family} ] The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro by Lattice are supported. This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. -The option @option{family} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). +For the option @option{-family} @var{name} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). -@deffn {Command} {lattice read_status} num +@deffn {Command} {lattice read_status} pld_name Reads and displays the status register -for FPGA @var{num}. +for FPGA @var{pld_name}. @end deffn -@deffn {Command} {lattice read_user} num +@deffn {Command} {lattice read_user} pld_name Reads and displays the user register -for FPGA @var{num}. +for FPGA @var{pld_name}. @end deffn -@deffn {Command} {lattice write_user} num val +@deffn {Command} {lattice write_user} pld_name val Writes the user register. -for FPGA @var{num} with value @var{val}. +for FPGA @var{pld_name} with value @var{val}. @end deffn -@deffn {Command} {lattice set_preload} num length +@deffn {Command} {lattice set_preload} pld_name length Set the length of the register for the preload. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). -The load command for the FPGA @var{num} will use a length for the preload of @var{length}. +The load command for the FPGA @var{pld_name} will use a length for the preload of @var{length}. @end deffn @end deffn @@ -8657,28 +8659,28 @@ This driver can be used to load the bitstream into the FPGA. @end deffn -@deffn {FPGA Driver} {intel} [@option{family}] +@deffn {FPGA Driver} {intel} [@option{-family} ] This driver can be used to load the bitstream into Intel (former Altera) FPGAs. The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported. @c Arria V and Arria 10, MAX II, MAX V, MAX10) -The option @option{family} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. +For the option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families). As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|} -Defines a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}: +Creates a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}: @example -pld device intel cycloneiii.tap cycloneiii +pld create cycloneiii.pld intel -chain-position cycloneiii.tap -family cycloneiii @end example -@deffn {Command} {intel set_bscan} num len -Set boundary scan register length of FPGA @var{num} to @var{len}. This is needed because the +@deffn {Command} {intel set_bscan} pld_name len +Set boundary scan register length of FPGA @var{pld_name} to @var{len}. This is needed because the length can vary between chips with the same JTAG ID. @end deffn -@deffn {Command} {intel set_check_pos} num pos +@deffn {Command} {intel set_check_pos} pld_name pos Selects the position @var{pos} in the boundary-scan register. The bit at this position is checked after loading the bitstream and must be '1', which is the case when no error occurred. With a value of -1 for @var{pos} the check will be omitted. diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index b74775a747..085c89ba17 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -1108,4 +1108,18 @@ proc "am335xgpio led_on_state" {state} { } } +lappend _telnet_autocomplete_skip "pld device" +proc "pld device" {driver tap_name {opt 0}} { + echo "DEPRECATED! use 'pld create ...', not 'pld device ...'" + if {[string is integer -strict $opt]} { + if {$opt == 0} { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name + } else { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -no_jstart + } + } else { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -family $opt + } +} + # END MIGRATION AIDS diff --git a/src/pld/efinix.c b/src/pld/efinix.c index f08439476c..370f184261 100644 --- a/src/pld/efinix.c +++ b/src/pld/efinix.c @@ -188,14 +188,17 @@ static int efinix_load(struct pld_device *pld_device, const char *filename) return retval; } -PLD_DEVICE_COMMAND_HANDLER(efinix_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) { - if (CMD_ARGC != 2) + if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; - struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } @@ -213,6 +216,6 @@ PLD_DEVICE_COMMAND_HANDLER(efinix_pld_device_command) struct pld_driver efinix_pld = { .name = "efinix", - .pld_device_command = &efinix_pld_device_command, + .pld_create_command = &efinix_pld_create_command, .load = &efinix_load, }; diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c index 43b3f02d1d..4ad2665c6a 100644 --- a/src/pld/gatemate.c +++ b/src/pld/gatemate.c @@ -209,22 +209,21 @@ static int gatemate_load(struct pld_device *pld_device, const char *filename) return retval; } -PLD_DEVICE_COMMAND_HANDLER(gatemate_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(gatemate_pld_create_command) { - struct jtag_tap *tap; - - struct gatemate_pld_device *gatemate_info; + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC != 2) + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; - tap = jtag_tap_by_string(CMD_ARGV[1]); + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } - gatemate_info = malloc(sizeof(struct gatemate_pld_device)); + struct gatemate_pld_device *gatemate_info = malloc(sizeof(struct gatemate_pld_device)); if (!gatemate_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; @@ -238,6 +237,6 @@ PLD_DEVICE_COMMAND_HANDLER(gatemate_pld_device_command) struct pld_driver gatemate_pld = { .name = "gatemate", - .pld_device_command = &gatemate_pld_device_command, + .pld_create_command = &gatemate_pld_create_command, .load = &gatemate_load, }; diff --git a/src/pld/gowin.c b/src/pld/gowin.c index 467b799374..ab3582c4c5 100644 --- a/src/pld/gowin.c +++ b/src/pld/gowin.c @@ -451,15 +451,12 @@ static int gowin_reload_command(struct pld_device *pld_device) COMMAND_HANDLER(gowin_read_status_command_handler) { - int dev_id; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -474,15 +471,12 @@ COMMAND_HANDLER(gowin_read_status_command_handler) COMMAND_HANDLER(gowin_read_user_register_command_handler) { - int dev_id; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -497,15 +491,12 @@ COMMAND_HANDLER(gowin_read_user_register_command_handler) COMMAND_HANDLER(gowin_reload_command_handler) { - int dev_id; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -518,19 +509,19 @@ static const struct command_registration gowin_exec_command_handlers[] = { .mode = COMMAND_EXEC, .handler = gowin_read_status_command_handler, .help = "reading status register from FPGA", - .usage = "num_pld", + .usage = "pld_name", }, { .name = "read_user", .mode = COMMAND_EXEC, .handler = gowin_read_user_register_command_handler, .help = "reading user register from FPGA", - .usage = "num_pld", + .usage = "pld_name", }, { .name = "reload", .mode = COMMAND_EXEC, .handler = gowin_reload_command_handler, .help = "reloading bitstream from flash to SRAM", - .usage = "num_pld", + .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; @@ -546,22 +537,21 @@ static const struct command_registration gowin_command_handler[] = { COMMAND_REGISTRATION_DONE }; -PLD_DEVICE_COMMAND_HANDLER(gowin_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(gowin_pld_create_command) { - struct jtag_tap *tap; - - struct gowin_pld_device *gowin_info; + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC != 2) + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; - tap = jtag_tap_by_string(CMD_ARGV[1]); + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } - gowin_info = malloc(sizeof(struct gowin_pld_device)); + struct gowin_pld_device *gowin_info = malloc(sizeof(struct gowin_pld_device)); if (!gowin_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; @@ -576,6 +566,6 @@ PLD_DEVICE_COMMAND_HANDLER(gowin_pld_device_command) struct pld_driver gowin_pld = { .name = "gowin", .commands = gowin_command_handler, - .pld_device_command = &gowin_pld_device_command, + .pld_create_command = &gowin_pld_create_command, .load = &gowin_load_to_sram, }; diff --git a/src/pld/intel.c b/src/pld/intel.c index 119a5695dc..92a790b547 100644 --- a/src/pld/intel.c +++ b/src/pld/intel.c @@ -339,16 +339,14 @@ static int intel_load(struct pld_device *pld_device, const char *filename) COMMAND_HANDLER(intel_set_bscan_command_handler) { - int dev_id; unsigned int boundary_scan_length; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *pld_device = get_pld_device_by_num(dev_id); + struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!pld_device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -366,16 +364,14 @@ COMMAND_HANDLER(intel_set_bscan_command_handler) COMMAND_HANDLER(intel_set_check_pos_command_handler) { - int dev_id; int checkpos; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *pld_device = get_pld_device_by_num(dev_id); + struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!pld_device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -392,42 +388,47 @@ COMMAND_HANDLER(intel_set_check_pos_command_handler) } -PLD_DEVICE_COMMAND_HANDLER(intel_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) { - if (CMD_ARGC < 2 || CMD_ARGC > 3) + if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; - struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); - if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); - return ERROR_FAIL; - } + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); - if (!intel_info) { - LOG_ERROR("Out of memory"); + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } enum intel_family_e family = INTEL_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC == 3) { - if (strcmp(CMD_ARGV[2], "cycloneiii") == 0) { + if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) { family = INTEL_CYCLONEIII; - } else if (strcmp(CMD_ARGV[2], "cycloneiv") == 0) { + } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) { family = INTEL_CYCLONEIV; - } else if (strcmp(CMD_ARGV[2], "cyclonev") == 0) { + } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) { family = INTEL_CYCLONEV; - } else if (strcmp(CMD_ARGV[2], "cyclone10") == 0) { + } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) { family = INTEL_CYCLONE10; - } else if (strcmp(CMD_ARGV[2], "arriaii") == 0) { + } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) { family = INTEL_ARRIAII; } else { command_print(CMD, "unknown family"); - free(intel_info); return ERROR_FAIL; } } + + struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); + if (!intel_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + intel_info->tap = tap; intel_info->boundary_scan_length = 0; intel_info->checkpos = -1; @@ -444,13 +445,13 @@ static const struct command_registration intel_exec_command_handlers[] = { .mode = COMMAND_EXEC, .handler = intel_set_bscan_command_handler, .help = "set boundary scan register length of FPGA", - .usage = "num_pld len", + .usage = "pld_name len", }, { .name = "set_check_pos", .mode = COMMAND_EXEC, .handler = intel_set_check_pos_command_handler, .help = "set check_pos of FPGA", - .usage = "num_pld pos", + .usage = "pld_name pos", }, COMMAND_REGISTRATION_DONE }; @@ -469,6 +470,6 @@ static const struct command_registration intel_command_handler[] = { struct pld_driver intel_pld = { .name = "intel", .commands = intel_command_handler, - .pld_device_command = &intel_pld_device_command, + .pld_create_command = &intel_pld_create_command, .load = &intel_load, }; diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 4ab5f63c0b..63d730677a 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -316,39 +316,46 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen return retval; } -PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command) { - if (CMD_ARGC < 2 || CMD_ARGC > 3) + if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; - struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } - struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device)); - if (!lattice_device) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } /* id is not known yet -> postpone lattice_check_device_family() */ enum lattice_family_e family = LATTICE_UNKNOWN; - if (CMD_ARGC == 3) { - if (strcasecmp(CMD_ARGV[2], "ecp2") == 0) { + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcasecmp(CMD_ARGV[5], "ecp2") == 0) { family = LATTICE_ECP2; - } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) { + } else if (strcasecmp(CMD_ARGV[5], "ecp3") == 0) { family = LATTICE_ECP3; - } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) { + } else if (strcasecmp(CMD_ARGV[5], "ecp5") == 0) { family = LATTICE_ECP5; - } else if (strcasecmp(CMD_ARGV[2], "certus") == 0) { + } else if (strcasecmp(CMD_ARGV[5], "certus") == 0) { family = LATTICE_CERTUS; } else { command_print(CMD, "unknown family"); - free(lattice_device); return ERROR_FAIL; } } + + struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device)); + if (!lattice_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + lattice_device->tap = tap; lattice_device->family = family; lattice_device->preload_length = 0; @@ -360,16 +367,14 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command) COMMAND_HANDLER(lattice_read_usercode_register_command_handler) { - int dev_id; uint32_t usercode; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -390,16 +395,14 @@ COMMAND_HANDLER(lattice_read_usercode_register_command_handler) COMMAND_HANDLER(lattice_set_preload_command_handler) { - int dev_id; unsigned int preload_length; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -417,16 +420,14 @@ COMMAND_HANDLER(lattice_set_preload_command_handler) COMMAND_HANDLER(lattice_write_usercode_register_command_handler) { - int dev_id; uint32_t usercode; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -445,15 +446,12 @@ COMMAND_HANDLER(lattice_write_usercode_register_command_handler) COMMAND_HANDLER(lattice_read_status_command_handler) { - int dev_id; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); - struct pld_device *device = get_pld_device_by_num(dev_id); + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -487,25 +485,25 @@ static const struct command_registration lattice_exec_command_handlers[] = { .mode = COMMAND_EXEC, .handler = lattice_read_status_command_handler, .help = "reading status register from FPGA", - .usage = "num_pld", + .usage = "pld_name", }, { .name = "read_user", .mode = COMMAND_EXEC, .handler = lattice_read_usercode_register_command_handler, .help = "reading usercode register from FPGA", - .usage = "num_pld", + .usage = "pld_name", }, { .name = "write_user", .mode = COMMAND_EXEC, .handler = lattice_write_usercode_register_command_handler, .help = "writing usercode register to FPGA", - .usage = "num_pld value", + .usage = "pld_name value", }, { .name = "set_preload", .mode = COMMAND_EXEC, .handler = lattice_set_preload_command_handler, .help = "set length for preload (device specific)", - .usage = "num_pld value", + .usage = "pld_name value", }, COMMAND_REGISTRATION_DONE }; @@ -524,6 +522,6 @@ static const struct command_registration lattice_command_handler[] = { struct pld_driver lattice_pld = { .name = "lattice", .commands = lattice_command_handler, - .pld_device_command = &lattice_pld_device_command, + .pld_create_command = &lattice_pld_create_command, .load = &lattice_load_command, }; diff --git a/src/pld/pld.c b/src/pld/pld.c index 07b575f94e..c375418a9d 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -34,68 +34,110 @@ struct pld_device *get_pld_device_by_num(int num) int i = 0; for (p = pld_devices; p; p = p->next) { - if (i++ == num) + if (i++ == num) { + LOG_WARNING("DEPRECATED: use pld name \"%s\" instead of number %d", p->name, num); return p; + } } 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; + } + + return NULL; +} - if (CMD_ARGC < 1) +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); +} + +/* @deffn {Config Command} {pld create} pld_name driver -chain-position tap_name [options] +*/ +COMMAND_HANDLER(handle_pld_create_command) +{ + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; - 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 (retval != ERROR_OK) { - 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 (retval != ERROR_OK) { - 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; + 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; + } + } + + 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; @@ -112,7 +154,7 @@ COMMAND_HANDLER(handle_pld_devices_command) } for (p = pld_devices; p; p = p->next) - command_print(CMD, "#%i: %s", i++, p->driver->name); + command_print(CMD, "#%i: %s (driver: %s)", i++, p->name, p->driver->name); return ERROR_OK; } @@ -128,11 +170,9 @@ COMMAND_HANDLER(handle_pld_load_command) 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); + p = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!p) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_OK; } @@ -154,15 +194,15 @@ COMMAND_HANDLER(handle_pld_load_command) retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { - command_print(CMD, "failed loading file %s to pld device %u", - CMD_ARGV[1], dev_id); + 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, "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); } @@ -182,7 +222,7 @@ static const struct command_registration pld_exec_command_handlers[] = { .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 }; @@ -213,11 +253,11 @@ 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", diff --git a/src/pld/pld.h b/src/pld/pld.h index 322b96ec6e..8a2a118319 100644 --- a/src/pld/pld.h +++ b/src/pld/pld.h @@ -12,28 +12,31 @@ struct pld_device; -#define __PLD_DEVICE_COMMAND(name) \ +#define __PLD_CREATE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) struct pld_driver { const char *name; - __PLD_DEVICE_COMMAND((*pld_device_command)); + __PLD_CREATE_COMMAND((*pld_create_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); }; -#define PLD_DEVICE_COMMAND_HANDLER(name) \ - static __PLD_DEVICE_COMMAND(name) +#define PLD_CREATE_COMMAND_HANDLER(name) \ + static __PLD_CREATE_COMMAND(name) struct pld_device { struct pld_driver *driver; void *driver_priv; struct pld_device *next; + char *name; }; int pld_register_commands(struct command_context *cmd_ctx); struct pld_device *get_pld_device_by_num(int num); +struct pld_device *get_pld_device_by_name(const char *name); +struct pld_device *get_pld_device_by_name_or_numstr(const char *str); #define ERROR_PLD_DEVICE_INVALID (-1000) #define ERROR_PLD_FILE_LOAD_FAILED (-1001) diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index fd0725a63a..f044bdae9b 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -233,11 +233,9 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned dev_id; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); - device = get_pld_device_by_num(dev_id); + device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } @@ -252,22 +250,21 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) return ERROR_OK; } -PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command) +PLD_CREATE_COMMAND_HANDLER(virtex2_pld_create_command) { - struct jtag_tap *tap; - - struct virtex2_pld_device *virtex2_info; + if (CMD_ARGC < 4) + return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC < 2) + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; - tap = jtag_tap_by_string(CMD_ARGV[1]); + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } - virtex2_info = malloc(sizeof(struct virtex2_pld_device)); + struct virtex2_pld_device *virtex2_info = malloc(sizeof(struct virtex2_pld_device)); if (!virtex2_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; @@ -275,8 +272,8 @@ PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command) virtex2_info->tap = tap; virtex2_info->no_jstart = 0; - if (CMD_ARGC >= 3) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], virtex2_info->no_jstart); + if (CMD_ARGC >= 5 && strcmp(CMD_ARGV[4], "-no_jstart") == 0) + virtex2_info->no_jstart = 1; pld->driver_priv = virtex2_info; @@ -289,7 +286,7 @@ static const struct command_registration virtex2_exec_command_handlers[] = { .mode = COMMAND_EXEC, .handler = virtex2_handle_read_stat_command, .help = "read status register", - .usage = "pld_num", + .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; @@ -307,6 +304,6 @@ static const struct command_registration virtex2_command_handler[] = { struct pld_driver virtex2_pld = { .name = "virtex2", .commands = virtex2_command_handler, - .pld_device_command = &virtex2_pld_device_command, + .pld_create_command = &virtex2_pld_create_command, .load = &virtex2_load, }; diff --git a/tcl/cpld/xilinx-xc6s.cfg b/tcl/cpld/xilinx-xc6s.cfg index 82b87fb415..33b6d71bbb 100644 --- a/tcl/cpld/xilinx-xc6s.cfg +++ b/tcl/cpld/xilinx-xc6s.cfg @@ -25,7 +25,7 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x0401D093 \ -expected-id 0x0403D093 -pld device virtex2 $_CHIPNAME.tap +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap set XC6S_CFG_IN 0x05 set XC6S_JSHUTDOWN 0x0d diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index 91a07f9eb4..1b1cb80761 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -49,7 +49,7 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ #jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 -pld device virtex2 $_CHIPNAME.tap 1 +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg index 9df696d4ca..8518e96d70 100644 --- a/tcl/cpld/xilinx-xcu.cfg +++ b/tcl/cpld/xilinx-xcu.cfg @@ -54,7 +54,7 @@ set _IRLEN [lindex $_XCU_DATA($CHIP) 1] # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID -pld device virtex2 $_CHIPNAME.tap 1 +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart set XCU_JSHUTDOWN 0x0d set XCU_JPROGRAM 0x0b diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg index ae752dfb16..d59c182070 100644 --- a/tcl/fpga/altera-arriaii.cfg +++ b/tcl/fpga/altera-arriaii.cfg @@ -28,4 +28,4 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x025030dd -expected-id 0x024820dd \ -expected-id 0x025140dd -pld device intel $_CHIPNAME.tap arriaii +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family arriaii diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg index e143572451..d9be6455df 100644 --- a/tcl/fpga/altera-cycloneiii.cfg +++ b/tcl/fpga/altera-cycloneiii.cfg @@ -32,4 +32,4 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x027000dd -expected-id 0x027030dd \ -expected-id 0x027020dd -pld device intel $_CHIPNAME.tap cycloneiii +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiii diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg index 59243cfd09..6a908e8af5 100644 --- a/tcl/fpga/altera-cycloneiv.cfg +++ b/tcl/fpga/altera-cycloneiv.cfg @@ -38,4 +38,4 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x028030dd -expected-id 0x028140dd \ -expected-id 0x028040dd -pld device intel $_CHIPNAME.tap cycloneiv +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiv diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg index 1e9c9c405d..46532a556c 100644 --- a/tcl/fpga/altera-cyclonev.cfg +++ b/tcl/fpga/altera-cyclonev.cfg @@ -44,4 +44,4 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x02d110dd -expected-id 0x02d010dd \ -expected-id 0x02d120dd -expected-id 0x02d020dd -pld device intel $_CHIPNAME.tap cyclonev +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclonev diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg index 681b58fc81..8b356cb853 100644 --- a/tcl/fpga/efinix_titanium.cfg +++ b/tcl/fpga/efinix_titanium.cfg @@ -20,4 +20,4 @@ jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ -expected-id 0x00680A79 \ -expected-id 0x00684A79 -pld device efinix $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg index ecd2edad4f..2b50d8c5dc 100644 --- a/tcl/fpga/efinix_trion.cfg +++ b/tcl/fpga/efinix_trion.cfg @@ -14,4 +14,4 @@ jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ -expected-id 0x00240A79 \ -expected-id 0x00220A79 -pld device efinix $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/gatemate.cfg b/tcl/fpga/gatemate.cfg index cc19fd4c20..e8f338236d 100644 --- a/tcl/fpga/gatemate.cfg +++ b/tcl/fpga/gatemate.cfg @@ -13,4 +13,4 @@ if { [info exists CHIPNAME] } { jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x20000001 -pld device gatemate $_CHIPNAME.tap +pld create $_CHIPNAME.pld gatemate -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/gowin_gw1n.cfg b/tcl/fpga/gowin_gw1n.cfg index 43d66b70eb..5e85066f99 100644 --- a/tcl/fpga/gowin_gw1n.cfg +++ b/tcl/fpga/gowin_gw1n.cfg @@ -26,4 +26,4 @@ jtag newtap $_CHIPNAME tap -irlen 8 -ignore-version \ -expected-id 0x1100181B \ -expected-id 0x0100481B -pld device gowin $_CHIPNAME.tap +pld create $_CHIPNAME.pld gowin -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certus.cfg b/tcl/fpga/lattice_certus.cfg index 95b6e59d8b..9ddb7d8431 100644 --- a/tcl/fpga/lattice_certus.cfg +++ b/tcl/fpga/lattice_certus.cfg @@ -15,4 +15,4 @@ if { [info exists CHIPNAME] } { jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x310F1043 -expected-id 0x310F0043 -pld device lattice $_CHIPNAME.tap +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg index c15a379aea..acaaa57392 100644 --- a/tcl/fpga/lattice_certuspro.cfg +++ b/tcl/fpga/lattice_certuspro.cfg @@ -15,4 +15,4 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x010f4043 # -expected-id 0x01112043 -pld device lattice $_CHIPNAME.tap +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp2.cfg b/tcl/fpga/lattice_ecp2.cfg index a1aa2eff1f..5b01787bdd 100644 --- a/tcl/fpga/lattice_ecp2.cfg +++ b/tcl/fpga/lattice_ecp2.cfg @@ -28,4 +28,4 @@ jtag newtap $_CHIPNAME tap -irlen 8 \ -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 \ -expected-id 0x01273043 -expected-id 0x01275043 -pld device lattice $_CHIPNAME.tap +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp3.cfg b/tcl/fpga/lattice_ecp3.cfg index 7cd5706495..21c8ffa842 100644 --- a/tcl/fpga/lattice_ecp3.cfg +++ b/tcl/fpga/lattice_ecp3.cfg @@ -19,4 +19,4 @@ jtag newtap $_CHIPNAME tap -irlen 8 \ -expected-id 0x01010043 -expected-id 0x01012043 \ -expected-id 0x01014043 -expected-id 0x01015043 -pld device lattice $_CHIPNAME.tap +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp5.cfg b/tcl/fpga/lattice_ecp5.cfg index 41442492e9..cdc63f0c11 100644 --- a/tcl/fpga/lattice_ecp5.cfg +++ b/tcl/fpga/lattice_ecp5.cfg @@ -27,4 +27,4 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \ -expected-id 0x81113043 -pld device lattice $_CHIPNAME.tap +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index a6f8995417..014c4283a5 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -46,7 +46,7 @@ adapter speed 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" -pld device virtex2 zynq_pl.bs 1 +pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b From 9cb09f8cfe4c041333f70be5a6b44a5d7c5be4e0 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 15 Apr 2023 01:13:12 +0200 Subject: [PATCH 08/49] pld/xilinx: make instruction codes configurable Change-Id: I4d2c1fbd4d6007ba8d5c8c687a7c13e25fb6a474 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7713 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 17 ++++++++ src/pld/virtex2.c | 106 ++++++++++++++++++++++++++++++++++++++++------ src/pld/virtex2.h | 14 ++++++ 3 files changed, 125 insertions(+), 12 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 7c579e30cd..05951bbdf9 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8621,6 +8621,23 @@ openocd -f board/digilent_zedboard.cfg -c "init" \ Reads and displays the Virtex-II status register (STAT) for FPGA @var{pld_name}. @end deffn + +@deffn {Command} {virtex2 set_instr_codes} pld_name cfg_out cfg_in jprogb jstart jshutdown [user1 [user2 [user3 [user4]]]] +Change values for boundary scan instructions. Default are values for Virtex 2, devices Virtex 4/5/6 and +SSI devices are using different values. +@var{pld_name} is the name of the pld device. +@var{cfg_out} is the value used to select CFG_OUT instruction. +@var{cfg_in} is the value used to select CFG_IN instruction. +@var{jprogb} is the value used to select JPROGRAM instruction. +@var{jstart} is the value used to select JSTART instruction. +@var{jshutdown} is the value used to select JSHUTDOWN instruction. +@var{user1} to @var{user4} are the intruction used to select the user registers USER1 to USER4. +@end deffn + +@deffn {Command} {virtex2 set_user_codes} pld_name user1 [user2 [user3 [user4]]] +Change values for boundary scan instructions selecting the registers USER1 to USER4. +Description of the arguments can be found at command @command{virtex2 set_instr_codes}. +@end deffn @end deffn diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index f044bdae9b..dfcf4cf343 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -13,12 +13,23 @@ #include "xilinx_bit.h" #include "pld.h" -static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) +static const struct virtex2_command_set virtex2_default_commands = { + .cfg_out = 0x04, + .cfg_in = 0x05, + .jprog_b = 0x0b, + .jstart = 0x0c, + .jshutdown = 0x0d, + .bypass = 0x3f, + .user = {0x02, 0x03}, + .num_user = 2, /* virtex II has only 2 user instructions */ +}; + +static int virtex2_set_instr(struct jtag_tap *tap, uint64_t new_instr) { if (!tap) return ERROR_FAIL; - if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { + if (buf_get_u64(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; @@ -28,7 +39,7 @@ static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) return ERROR_FAIL; } field.out_value = t; - buf_set_u32(t, 0, field.num_bits, new_instr); + buf_set_u64(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); @@ -60,7 +71,7 @@ static int virtex2_send_32(struct pld_device *pld_device, for (i = 0; i < num_words; i++) buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); - int retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); if (retval != ERROR_OK) { free(values); return retval; @@ -89,7 +100,7 @@ static int virtex2_receive_32(struct pld_device *pld_device, scan_field.out_value = NULL; scan_field.in_value = NULL; - int retval = virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */ + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_out); if (retval != ERROR_OK) return retval; @@ -137,7 +148,7 @@ static int virtex2_load_prepare(struct pld_device *pld_device) struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; int retval; - retval = virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); if (retval != ERROR_OK) return retval; @@ -146,7 +157,7 @@ static int virtex2_load_prepare(struct pld_device *pld_device) return retval; jtag_add_sleep(1000); - retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); if (retval != ERROR_OK) return retval; @@ -161,24 +172,24 @@ static int virtex2_load_cleanup(struct pld_device *pld_device) jtag_add_tlr(); if (!(virtex2_info->no_jstart)) { - retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); if (retval != ERROR_OK) return retval; } jtag_add_runtest(13, TAP_IDLE); - retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; - retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; if (!(virtex2_info->no_jstart)) { - retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); if (retval != ERROR_OK) return retval; } jtag_add_runtest(13, TAP_IDLE); - retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; @@ -250,6 +261,62 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) return ERROR_OK; } +COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) +{ + if (CMD_ARGC < 6 || CMD_ARGC > (6 + VIRTEX2_MAX_USER_INSTRUCTIONS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct virtex2_pld_device *virtex2_info = device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + struct virtex2_command_set instr_codes; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], instr_codes.cfg_out); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[2], instr_codes.cfg_in); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], instr_codes.jprog_b); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], instr_codes.jstart); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[5], instr_codes.jshutdown); + instr_codes.bypass = 0xffffffffffffffff; + + unsigned int num_user = CMD_ARGC - 6; + for (unsigned int i = 0; i < num_user; ++i) + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[6 + i], instr_codes.user[i]); + instr_codes.num_user = num_user; + + virtex2_info->command_set = instr_codes; + return ERROR_OK; +} + +COMMAND_HANDLER(virtex2_handle_set_user_codes_command) +{ + if (CMD_ARGC < 2 || CMD_ARGC > (1 + VIRTEX2_MAX_USER_INSTRUCTIONS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct virtex2_pld_device *virtex2_info = device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; + unsigned int num_user = CMD_ARGC - 1; + for (unsigned int i = 0; i < num_user; ++i) + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1 + i], user[i]); + virtex2_info->command_set.num_user = num_user; + memcpy(virtex2_info->command_set.user, user, num_user * sizeof(uint64_t)); + return ERROR_OK; +} + PLD_CREATE_COMMAND_HANDLER(virtex2_pld_create_command) { if (CMD_ARGC < 4) @@ -270,6 +337,7 @@ PLD_CREATE_COMMAND_HANDLER(virtex2_pld_create_command) return ERROR_FAIL; } virtex2_info->tap = tap; + virtex2_info->command_set = virtex2_default_commands; virtex2_info->no_jstart = 0; if (CMD_ARGC >= 5 && strcmp(CMD_ARGV[4], "-no_jstart") == 0) @@ -287,9 +355,23 @@ static const struct command_registration virtex2_exec_command_handlers[] = { .handler = virtex2_handle_read_stat_command, .help = "read status register", .usage = "pld_name", + }, { + .name = "set_instr_codes", + .mode = COMMAND_EXEC, + .handler = virtex2_handle_set_instuction_codes_command, + .help = "set instructions codes used for loading the bitstream/refreshing/jtag-hub", + .usage = "pld_name cfg_out cfg_in jprogb jstart jshutdown" + " [user1 [user2 [user3 [user4]]]]", + }, { + .name = "set_user_codes", + .mode = COMMAND_EXEC, + .handler = virtex2_handle_set_user_codes_command, + .help = "set instructions codes used for jtag-hub", + .usage = "pld_name user1 [user2 [user3 [user4]]]", }, COMMAND_REGISTRATION_DONE }; + static const struct command_registration virtex2_command_handler[] = { { .name = "virtex2", diff --git a/src/pld/virtex2.h b/src/pld/virtex2.h index 05558f709d..b69e3c97a9 100644 --- a/src/pld/virtex2.h +++ b/src/pld/virtex2.h @@ -10,9 +10,23 @@ #include +#define VIRTEX2_MAX_USER_INSTRUCTIONS 4 + +struct virtex2_command_set { + uint64_t cfg_out; + uint64_t cfg_in; + uint64_t jprog_b; + uint64_t jstart; + uint64_t jshutdown; + uint64_t bypass; + uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; + unsigned int num_user; +}; + struct virtex2_pld_device { struct jtag_tap *tap; int no_jstart; + struct virtex2_command_set command_set; }; #endif /* OPENOCD_PLD_VIRTEX2_H */ From d654e523babd26fc8d62a8fa0814c9de84826e0d Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Thu, 17 Nov 2022 02:01:04 +0100 Subject: [PATCH 09/49] tcl/cpld: add config files for more xilinx fpga families Use configurable virtex pld driver to add support for more xilinx fpga families. Change-Id: Iff10c8c511787734fa289bdba15f03131d51e071 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7352 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/cpld/xilinx-xc3s.cfg | 40 +++++++++++++++++++++++ tcl/cpld/xilinx-xc4v.cfg | 31 ++++++++++++++++++ tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg | 22 +++++++++++++ tcl/cpld/xilinx-xc5v.cfg | 41 ++++++++++++++++++++++++ tcl/cpld/xilinx-xc5vfx_100_130_200.cfg | 21 ++++++++++++ tcl/cpld/xilinx-xc6s.cfg | 1 + tcl/cpld/xilinx-xc6v.cfg | 35 ++++++++++++++++++++ tcl/cpld/xilinx-xc7.cfg | 3 +- tcl/target/zynq_7000.cfg | 1 + 9 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 tcl/cpld/xilinx-xc3s.cfg create mode 100644 tcl/cpld/xilinx-xc4v.cfg create mode 100644 tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg create mode 100644 tcl/cpld/xilinx-xc5v.cfg create mode 100644 tcl/cpld/xilinx-xc5vfx_100_130_200.cfg create mode 100644 tcl/cpld/xilinx-xc6v.cfg diff --git a/tcl/cpld/xilinx-xc3s.cfg b/tcl/cpld/xilinx-xc3s.cfg new file mode 100644 index 0000000000..a8867395b1 --- /dev/null +++ b/tcl/cpld/xilinx-xc3s.cfg @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx spartan3 +# https://docs.xilinx.com/v/u/en-US/ug332 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc3s +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x01414093 \ + -expected-id 0x0141C093 \ + -expected-id 0x01428093 \ + -expected-id 0x01434093 \ + -expected-id 0x01440093 \ + -expected-id 0x01448093 \ + -expected-id 0x01450093 \ + -expected-id 0x01C10093 \ + -expected-id 0x01C1A093 \ + -expected-id 0x01C22093 \ + -expected-id 0x01C2E093 \ + -expected-id 0x01C3A093 \ + -expected-id 0x0140C093 \ + -expected-id 0x02210093 \ + -expected-id 0x02218093 \ + -expected-id 0x02220093 \ + -expected-id 0x02228093 \ + -expected-id 0x02230093 \ + -expected-id 0x02610093 \ + -expected-id 0x02618093 \ + -expected-id 0x02620093 \ + -expected-id 0x02628093 \ + -expected-id 0x02630093 \ + -expected-id 0x03840093 \ + -expected-id 0x0384e093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap diff --git a/tcl/cpld/xilinx-xc4v.cfg b/tcl/cpld/xilinx-xc4v.cfg new file mode 100644 index 0000000000..3eb46ebc44 --- /dev/null +++ b/tcl/cpld/xilinx-xc4v.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 4 +# https://docs.xilinx.com/v/u/en-US/ug071 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc4v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x01658093 \ + -expected-id 0x01E58093 \ + -expected-id 0x0167C093 \ + -expected-id 0x02068093 \ + -expected-id 0x01E64093 \ + -expected-id 0x016A4093 \ + -expected-id 0x02088093 \ + -expected-id 0x016B4093 \ + -expected-id 0x020B0093 \ + -expected-id 0x016D8093 \ + -expected-id 0x01700093 \ + -expected-id 0x01718093 \ + -expected-id 0x01734093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg b/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg new file mode 100644 index 0000000000..14dde02703 --- /dev/null +++ b/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 4 +# https://docs.xilinx.com/v/u/en-US/ug071 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc4vfx +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ + -expected-id 0x01E8C093 \ + -expected-id 0x01EB4093 \ + -expected-id 0x01EE4093 \ + -expected-id 0x01F14093 \ + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD +virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 diff --git a/tcl/cpld/xilinx-xc5v.cfg b/tcl/cpld/xilinx-xc5v.cfg new file mode 100644 index 0000000000..f88bbc1e81 --- /dev/null +++ b/tcl/cpld/xilinx-xc5v.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 5 +# https://docs.xilinx.com/v/u/en-US/ug191 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc5v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x0286E093 \ + -expected-id 0x02896093 \ + -expected-id 0x028AE093 \ + -expected-id 0x028D6093 \ + -expected-id 0x028EC093 \ + -expected-id 0x0290C093 \ + -expected-id 0x0295C093 \ + -expected-id 0x02A56093 \ + -expected-id 0x02A6E093 \ + -expected-id 0x02A96093 \ + -expected-id 0x02AAE093 \ + -expected-id 0x02AD6093 \ + -expected-id 0x02AEC093 \ + -expected-id 0x02B0C093 \ + -expected-id 0x02B5C093 \ + -expected-id 0x02E72093 \ + -expected-id 0x02E9A093 \ + -expected-id 0x02ECE093 \ + -expected-id 0x02F3E093 \ + -expected-id 0x03276093 \ + -expected-id 0x032C6093 \ + -expected-id 0x04502093 \ + -expected-id 0x0453E093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg b/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg new file mode 100644 index 0000000000..7420233f48 --- /dev/null +++ b/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 5 +# https://docs.xilinx.com/v/u/en-US/ug191 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc5vfx +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ + -expected-id 0x032D8093 \ + -expected-id 0x03300093 \ + -expected-id 0x03334093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD +virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 diff --git a/tcl/cpld/xilinx-xc6s.cfg b/tcl/cpld/xilinx-xc6s.cfg index 33b6d71bbb..7e32094d48 100644 --- a/tcl/cpld/xilinx-xc6s.cfg +++ b/tcl/cpld/xilinx-xc6s.cfg @@ -26,6 +26,7 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x0403D093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x1A 0x1B set XC6S_CFG_IN 0x05 set XC6S_JSHUTDOWN 0x0d diff --git a/tcl/cpld/xilinx-xc6v.cfg b/tcl/cpld/xilinx-xc6v.cfg new file mode 100644 index 0000000000..d37439c984 --- /dev/null +++ b/tcl/cpld/xilinx-xc6v.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 6 +# https://www.xilinx.com/support/documentation/user_guides/ug360.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc6v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x042A2093 \ + -expected-id 0x042A4093 \ + -expected-id 0x042A8093 \ + -expected-id 0x042AC093 \ + -expected-id 0x04244093 \ + -expected-id 0x0424A093 \ + -expected-id 0x0424C093 \ + -expected-id 0x04250093 \ + -expected-id 0x04252093 \ + -expected-id 0x04256093 \ + -expected-id 0x0423A093 \ + -expected-id 0x04286093 \ + -expected-id 0x04288093 \ + -expected-id 0x042C4093 \ + -expected-id 0x042CA093 \ + -expected-id 0x042CC093 \ + -expected-id 0x042D0093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index 1b1cb80761..93ec049908 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# xilinx series 7 (artix, kintex, virtex) +# xilinx series 7 (spartan, artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf if { [info exists CHIPNAME] } { @@ -50,6 +50,7 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ #jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 014c4283a5..593abd7925 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -47,6 +47,7 @@ ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart +virtex2 set_user_codes $zynq_pl.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b From e95f8e2b25c36fd290c29b4b553da5d16dfc620f Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Wed, 7 Jun 2023 01:11:49 +0200 Subject: [PATCH 10/49] pld/gowin: add missing documentation Add short description for gowin {read_status/read_user/reload} commands. Change-Id: Ib441f3a2c0f00346decdeb505c27afa2630e9b5d Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7736 Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 05951bbdf9..cab30c6af8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8709,6 +8709,21 @@ With a value of -1 for @var{pos} the check will be omitted. This driver can be used to load the bitstream into FPGAs from Gowin. It is possible to program the SRAM. Programming the flash is not supported. The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are supported. + +@deffn {Command} {gowin read_status} pld_name +Reads and displays the status register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {gowin read_user} pld_name +Reads and displays the user register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {gowin reload} pld_name +Load the bitstream from external memory for +FPGA @var{pld_name}. A.k.a. refresh. +@end deffn @end deffn From 373d7eaa706b4895cb94e5f563526aec865c8814 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 15 Apr 2023 01:13:12 +0200 Subject: [PATCH 11/49] pld/virtex2: add program/refresh command Change-Id: If6d237a6f27c4232849f73d08e7ca74276e6d464 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7714 Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 4 ++++ src/pld/virtex2.c | 51 ++++++++++++++++++++++++++++++++++++++++ tcl/cpld/xilinx-xc6s.cfg | 2 ++ tcl/cpld/xilinx-xc7.cfg | 1 + tcl/cpld/xilinx-xcu.cfg | 1 + tcl/target/zynq_7000.cfg | 1 + 6 files changed, 60 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index cab30c6af8..ee67e7582a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8638,6 +8638,10 @@ SSI devices are using different values. Change values for boundary scan instructions selecting the registers USER1 to USER4. Description of the arguments can be found at command @command{virtex2 set_instr_codes}. @end deffn + +@deffn {Command} {virtex2 program} pld_name +Load the bitstream from external memory for FPGA @var{pld_name}. A.k.a. refresh. +@end deffn @end deffn diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index dfcf4cf343..9007a55d27 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -143,6 +143,35 @@ static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status) return retval; } +static int virtex2_program(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jshutdown); + if (retval != ERROR_OK) + return retval; + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); + if (retval != ERROR_OK) + return retval; + + jtag_add_runtest(62000, TAP_IDLE); + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); + if (retval != ERROR_OK) + return retval; + } + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2000, TAP_IDLE); + + return jtag_execute_queue(); +} + static int virtex2_load_prepare(struct pld_device *pld_device) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; @@ -236,6 +265,22 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) return retval; } +COMMAND_HANDLER(virtex2_handle_program_command) +{ + struct pld_device *device; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return virtex2_program(device); +} + COMMAND_HANDLER(virtex2_handle_read_stat_command) { struct pld_device *device; @@ -368,6 +413,12 @@ static const struct command_registration virtex2_exec_command_handlers[] = { .handler = virtex2_handle_set_user_codes_command, .help = "set instructions codes used for jtag-hub", .usage = "pld_name user1 [user2 [user3 [user4]]]", + }, { + .name = "program", + .mode = COMMAND_EXEC, + .handler = virtex2_handle_program_command, + .help = "start loading of configuration (refresh)", + .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; diff --git a/tcl/cpld/xilinx-xc6s.cfg b/tcl/cpld/xilinx-xc6s.cfg index 7e32094d48..92b2605774 100644 --- a/tcl/cpld/xilinx-xc6s.cfg +++ b/tcl/cpld/xilinx-xc6s.cfg @@ -35,6 +35,7 @@ set XC6S_JSTART 0x0c set XC6S_BYPASS 0x3f proc xc6s_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program'" global XC6S_JSHUTDOWN XC6S_JPROGRAM XC6S_JSTART XC6S_BYPASS irscan $tap $XC6S_JSHUTDOWN irscan $tap $XC6S_JPROGRAM @@ -44,6 +45,7 @@ proc xc6s_program {tap} { #xtp038 and xc3sprog approach proc xc6s_program_iprog {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program_iprog'" global XC6S_JSHUTDOWN XC6S_JSTART XC6S_BYPASS XC6S_CFG_IN irscan $tap $XC6S_JSHUTDOWN runtest 16 diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index 93ec049908..ebd76ff6b0 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -58,6 +58,7 @@ set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc xc7_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc7_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg index 8518e96d70..2d74695ed8 100644 --- a/tcl/cpld/xilinx-xcu.cfg +++ b/tcl/cpld/xilinx-xcu.cfg @@ -62,6 +62,7 @@ set XCU_JSTART 0x0c set XCU_BYPASS 0x3f proc xcu_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xcu_program'" global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS irscan $tap $XCU_JSHUTDOWN irscan $tap $XCU_JPROGRAM diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 593abd7925..f5b4478ffc 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -55,6 +55,7 @@ set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc zynqpl_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'zynqpl_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM From a27907aed1cd26bcbaac834343f08146fc8fa1fe Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 15 Apr 2023 01:13:12 +0200 Subject: [PATCH 12/49] ipdbg/pld: ipdbg can get tap and hub/ir from pld driver. To start a ipdbg server one needs to know the tap and the instruction code to reach the IPDBG-Hub. This instruction is vendor/family specific. Knowledge which can be provided by the pld driver. Change-Id: I13eeb9fee895d65cd48544da4704fcc9b528b869 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7369 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 31 +++++++++++--- src/pld/efinix.c | 80 +++++++++++++++++++++++++++++++++++- src/pld/gowin.c | 27 ++++++++++++ src/pld/intel.c | 26 ++++++++++++ src/pld/lattice.c | 27 ++++++++++++ src/pld/pld.h | 6 +++ src/pld/virtex2.c | 21 ++++++++++ src/server/ipdbg.c | 32 ++++++++++++++- tcl/fpga/efinix_titanium.cfg | 2 +- tcl/fpga/efinix_trion.cfg | 2 +- 10 files changed, 245 insertions(+), 9 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ee67e7582a..d99917e0d6 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8674,9 +8674,10 @@ The load command for the FPGA @var{pld_name} will use a length for the preload o @end deffn -@deffn {FPGA Driver} {efinix} +@deffn {FPGA Driver} {efinix} [@option{-family} ] Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration. This driver can be used to load the bitstream into the FPGA. +For the option @option{-family} @var{name} is one of @var{trion|titanium}. @end deffn @@ -11834,7 +11835,7 @@ In a session using JTAG for its transport protocol, OpenOCD supports the functio of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the control-software. For more details see @url{http://ipdbg.org}. -@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}] Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. Command options: @@ -11843,15 +11844,28 @@ Command options: @item @option{-tap @var{tapname}} targeting the TAP @var{tapname}. @item @option{-hub @var{ir_value}} states that the JTAG hub is reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. -@item @option{-port @var{number}} tcp port number where the JTAG-Host is listening. -@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. -@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is only reachable if there is a +@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given. +@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. +@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to shift data through vir can be configured. @end itemize @end deffn +or +@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] +Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server. +With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required. +The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}). + +The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor. +So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command. + +With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate. + +The remaining options are described in the previous command. +@end deffn Examples: @example @@ -11866,6 +11880,13 @@ ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1 Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5). +@example +ipdbg -start -pld xc7.pld -port 5555 -tool 0 +@end example +Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). +The TAP and ir value used to reach the JTAG Hub is given by the pld driver. + + @node Utility Commands @chapter Utility Commands @cindex Utility Commands diff --git a/src/pld/efinix.c b/src/pld/efinix.c index 370f184261..8350cb1a24 100644 --- a/src/pld/efinix.c +++ b/src/pld/efinix.c @@ -16,13 +16,29 @@ #define PROGRAM 0x4 #define ENTERUSER 0x7 +#define USER1 0x8 +#define USER2 0x9 +#define USER3 0xa +#define USER4 0xb + +enum efinix_family_e { + EFINIX_TRION, + EFINIX_TITANIUM, + EFINIX_UNKNOWN +}; #define TRAILING_ZEROS 4000 #define RUNTEST_START_CYCLES 100 #define RUNTEST_FINISH_CYCLES 100 +struct efinix_device { + uint32_t idcode; + int num_user; +}; + struct efinix_pld_device { struct jtag_tap *tap; + enum efinix_family_e family; }; static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename) @@ -188,9 +204,54 @@ static int efinix_load(struct pld_device *pld_device, const char *filename) return retval; } +static int efinix_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct efinix_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (pld_device_info->family == EFINIX_UNKNOWN) { + LOG_ERROR("family unknown, please specify for 'pld create'"); + return ERROR_FAIL; + } + int num_user = 2; /* trion */ + if (pld_device_info->family == EFINIX_TITANIUM) + num_user = 4; + + if (user_num > num_user) { + LOG_ERROR("Devices has only user register 1 to %d", num_user); + return ERROR_FAIL; + } + + switch (user_num) { + case 1: + hub->user_ir_code = USER1; + break; + case 2: + hub->user_ir_code = USER2; + break; + case 3: + hub->user_ir_code = USER3; + break; + case 4: + hub->user_ir_code = USER4; + break; + default: + LOG_ERROR("efinix devices only have user register 1 to %d", num_user); + return ERROR_FAIL; + } + return ERROR_OK; +} + PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) { - if (CMD_ARGC != 4) + if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) @@ -202,12 +263,28 @@ PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) return ERROR_FAIL; } + enum efinix_family_e family = EFINIX_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[5], "trion") == 0) { + family = EFINIX_TRION; + } else if (strcmp(CMD_ARGV[5], "titanium") == 0) { + family = EFINIX_TITANIUM; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; + } + } + struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device)); if (!efinix_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } efinix_info->tap = tap; + efinix_info->family = family; pld->driver_priv = efinix_info; @@ -218,4 +295,5 @@ struct pld_driver efinix_pld = { .name = "efinix", .pld_create_command = &efinix_pld_create_command, .load = &efinix_load, + .get_ipdbg_hub = efinix_get_ipdbg_hub, }; diff --git a/src/pld/gowin.c b/src/pld/gowin.c index ab3582c4c5..c42b2f22c9 100644 --- a/src/pld/gowin.c +++ b/src/pld/gowin.c @@ -29,6 +29,9 @@ #define ERASE_FLASH 0x75 #define ENABLE_2ND_FLASH 0x78 +#define USER1 0x42 +#define USER2 0x43 + #define STAUS_MASK_MEMORY_ERASE BIT(5) #define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7) @@ -449,6 +452,29 @@ static int gowin_reload_command(struct pld_device *pld_device) return gowin_reload(gowin_info->tap); } +static int gowin_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("gowin devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + COMMAND_HANDLER(gowin_read_status_command_handler) { if (CMD_ARGC != 1) @@ -568,4 +594,5 @@ struct pld_driver gowin_pld = { .commands = gowin_command_handler, .pld_create_command = &gowin_pld_create_command, .load = &gowin_load_to_sram, + .get_ipdbg_hub = gowin_get_ipdbg_hub, }; diff --git a/src/pld/intel.c b/src/pld/intel.c index 92a790b547..e5c9273069 100644 --- a/src/pld/intel.c +++ b/src/pld/intel.c @@ -18,6 +18,8 @@ #include "raw_bit.h" #define BYPASS 0x3FF +#define USER0 0x00C +#define USER1 0x00E enum intel_family_e { INTEL_CYCLONEIII, @@ -337,6 +339,29 @@ static int intel_load(struct pld_device *pld_device, const char *filename) return jtag_execute_queue(); } +static int intel_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct intel_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 0) { + hub->user_ir_code = USER0; + } else if (user_num == 1) { + hub->user_ir_code = USER1; + } else { + LOG_ERROR("intel devices only have user register 0 & 1"); + return ERROR_FAIL; + } + return ERROR_OK; +} + COMMAND_HANDLER(intel_set_bscan_command_handler) { unsigned int boundary_scan_length; @@ -472,4 +497,5 @@ struct pld_driver intel_pld = { .commands = intel_command_handler, .pld_create_command = &intel_pld_create_command, .load = &intel_load, + .get_ipdbg_hub = intel_get_ipdbg_hub, }; diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 63d730677a..2075f4490d 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -18,6 +18,9 @@ #include "certus.h" #define PRELOAD 0x1C +#define USER1 0x32 +#define USER2 0x38 + struct lattice_devices_elem { uint32_t id; @@ -316,6 +319,29 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen return retval; } +int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("lattice devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command) { if (CMD_ARGC != 4 && CMD_ARGC != 6) @@ -524,4 +550,5 @@ struct pld_driver lattice_pld = { .commands = lattice_command_handler, .pld_create_command = &lattice_pld_create_command, .load = &lattice_load_command, + .get_ipdbg_hub = lattice_get_ipdbg_hub, }; diff --git a/src/pld/pld.h b/src/pld/pld.h index 8a2a118319..b736e6ae20 100644 --- a/src/pld/pld.h +++ b/src/pld/pld.h @@ -15,11 +15,17 @@ struct pld_device; #define __PLD_CREATE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) +struct pld_ipdbg_hub { + struct jtag_tap *tap; + unsigned int user_ir_code; +}; + struct pld_driver { const char *name; __PLD_CREATE_COMMAND((*pld_create_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); + int (*get_ipdbg_hub)(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub); }; #define PLD_CREATE_COMMAND_HANDLER(name) \ diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index 9007a55d27..a97c7c6d68 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -306,6 +306,26 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) return ERROR_OK; } +static int xilinx_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct virtex2_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + if (user_num < 1 || (unsigned int)user_num > pld_device_info->command_set.num_user) { + LOG_ERROR("device has only user register 1 to %d", pld_device_info->command_set.num_user); + return ERROR_FAIL; + } + + hub->user_ir_code = pld_device_info->command_set.user[user_num - 1]; + return ERROR_OK; +} + COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) { if (CMD_ARGC < 6 || CMD_ARGC > (6 + VIRTEX2_MAX_USER_INSTRUCTIONS)) @@ -439,4 +459,5 @@ struct pld_driver virtex2_pld = { .commands = virtex2_command_handler, .pld_create_command = &virtex2_pld_create_command, .load = &virtex2_load, + .get_ipdbg_hub = xilinx_get_ipdbg_hub, }; diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 69d0f57553..3fae0a98d8 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -10,11 +10,12 @@ #include #include #include +#include #include "ipdbg.h" #define IPDBG_BUFFER_SIZE 16384 -#define IPDBG_MIN_NUM_OF_OPTIONS 4 +#define IPDBG_MIN_NUM_OF_OPTIONS 2 #define IPDBG_MAX_NUM_OF_OPTIONS 14 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 @@ -716,6 +717,7 @@ COMMAND_HANDLER(handle_ipdbg_command) uint32_t virtual_ir_length = 5; uint32_t virtual_ir_value = 0x11; struct ipdbg_virtual_ir_info *virtual_ir = NULL; + int user_num = 1; if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -742,6 +744,34 @@ COMMAND_HANDLER(handle_ipdbg_command) IPDBG_MIN_DR_LENGTH, IPDBG_MAX_DR_LENGTH); return ERROR_FAIL; } + } else if (strcmp(CMD_ARGV[i], "-pld") == 0) { + ++i; + if (i >= CMD_ARGC || CMD_ARGV[i][0] == '-') + return ERROR_COMMAND_SYNTAX_ERROR; + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[i]); + if (!device || !device->driver) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[i]); + return ERROR_FAIL; + } + COMMAND_PARSE_OPTIONAL_NUMBER(int, i, user_num); + struct pld_ipdbg_hub pld_hub; + struct pld_driver *driver = device->driver; + if (!driver->get_ipdbg_hub) { + command_print(CMD, "pld driver has no ipdbg support"); + return ERROR_FAIL; + } + if (driver->get_ipdbg_hub(user_num, device, &pld_hub) != ERROR_OK) { + command_print(CMD, "unable to retrieve hub from pld driver"); + return ERROR_FAIL; + } + if (!pld_hub.tap) { + command_print(CMD, "no tap received from pld driver"); + return ERROR_FAIL; + } + hub_configured = true; + user_instruction = pld_hub.user_ir_code; + tap = pld_hub.tap; + } else if (strcmp(CMD_ARGV[i], "-vir") == 0) { COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_value); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length); diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg index 8b356cb853..3c2cdd71f7 100644 --- a/tcl/fpga/efinix_titanium.cfg +++ b/tcl/fpga/efinix_titanium.cfg @@ -20,4 +20,4 @@ jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ -expected-id 0x00680A79 \ -expected-id 0x00684A79 -pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family titanium diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg index 2b50d8c5dc..1c789f5642 100644 --- a/tcl/fpga/efinix_trion.cfg +++ b/tcl/fpga/efinix_trion.cfg @@ -14,4 +14,4 @@ jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ -expected-id 0x00240A79 \ -expected-id 0x00220A79 -pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family trion From 4a96776178676963a179879624190acea1e26158 Mon Sep 17 00:00:00 2001 From: Laurent LEMELE Date: Tue, 13 Dec 2022 16:12:08 +0100 Subject: [PATCH 13/49] jtag/stlink: add STLINK-V3PWR support STLINK-V3PWR is both a standalone debugger probe compatible with STLINK-V3 and a source measurement unit (SMU). Link: http://www.st.com/stlink-v3pwr This code adds support for the debugger probe functionality. Change-Id: Ib056e55722528f922c5574bb6fbf77e2f2b2b0c1 Signed-off-by: Laurent LEMELE Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7755 Tested-by: jenkins --- contrib/60-openocd.rules | 2 ++ doc/openocd.texi | 8 ++++++- src/jtag/drivers/stlink_usb.c | 45 ++++++++++++++++++++++++++++++++--- tcl/interface/stlink-dap.cfg | 2 +- tcl/interface/stlink.cfg | 2 +- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index bb6f478a1e..fc35fb9b9e 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -99,6 +99,8 @@ ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3755", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3757", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress SuperSpeed Explorer Kit ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0007", MODE="660", GROUP="plugdev", TAG+="uaccess" diff --git a/doc/openocd.texi b/doc/openocd.texi index d99917e0d6..12a8ca56df 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -463,6 +463,12 @@ They only work with STMicroelectronics chips, notably STM32 and STM8. @item @b{STLINK-V3} @* This is available standalone and as part of some kits. @* Link: @url{http://www.st.com/stlink-v3} +@item @b{STLINK-V3PWR} +@* This is available standalone. +Beside the debugger functionality, the probe includes a SMU (source +measurement unit) aimed at analyzing power consumption during code +execution. The SMU is not supported by OpenOCD. +@* Link: @url{http://www.st.com/stlink-v3pwr} @end itemize For info the original ST-LINK enumerates using the mass storage usb class; however, @@ -3184,7 +3190,7 @@ passed as is to the underlying adapter layout handler. @anchor{st_link_dap_interface} @deffn {Interface Driver} {st-link} This is a driver that supports STMicroelectronics adapters ST-LINK/V2 -(from firmware V2J24) and STLINK-V3, thanks to a new API that provides +(from firmware V2J24), STLINK-V3 and STLINK-V3PWR, thanks to a new API that provides directly access the arm ADIv5 DAP. The new API provide access to multiple AP on the same DAP, but the diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index ee629542ba..2c5b63dd6e 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -84,6 +84,8 @@ #define STLINK_V3S_PID (0x374F) #define STLINK_V3_2VCP_PID (0x3753) #define STLINK_V3E_NO_MSD_PID (0x3754) +#define STLINK_V3P_USBLOADER_PID (0x3755) +#define STLINK_V3P_PID (0x3757) /* * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and @@ -1297,8 +1299,8 @@ static int stlink_usb_version(void *handle) break; } - /* STLINK-V3 requires a specific command */ - if (v == 3 && x == 0 && y == 0) { + /* STLINK-V3 & STLINK-V3P require a specific command */ + if (v >= 3 && x == 0 && y == 0) { stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_VERSION_EX; @@ -1414,6 +1416,41 @@ static int stlink_usb_version(void *handle) if (h->version.jtag >= 6) flags |= STLINK_F_HAS_RW8_512BYTES; + break; + case 4: + /* STLINK-V3P use api-v3 */ + h->version.jtag_api = STLINK_JTAG_API_V3; + + /* STLINK-V3P is a superset of ST-LINK/V3 */ + + /* API for trace */ + /* API for target voltage */ + flags |= STLINK_F_HAS_TRACE; + + /* preferred API to get last R/W status */ + flags |= STLINK_F_HAS_GETLASTRWSTATUS2; + + /* API to access DAP registers */ + flags |= STLINK_F_HAS_DAP_REG; + + /* API to read/write memory at 16 bit */ + /* API to write memory without address increment */ + flags |= STLINK_F_HAS_MEM_16BIT; + + /* API required to init AP before any AP access */ + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP */ + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support */ + /* API to read memory without address increment */ + /* Memory R/W supports CSW */ + flags |= STLINK_F_HAS_DPBANKSEL; + + /* 8bit read/write max packet size 512 bytes */ + flags |= STLINK_F_HAS_RW8_512BYTES; + break; default: break; @@ -3402,6 +3439,8 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) case STLINK_V3S_PID: case STLINK_V3_2VCP_PID: case STLINK_V3E_NO_MSD_PID: + case STLINK_V3P_USBLOADER_PID: + case STLINK_V3P_PID: h->version.stlink = 3; h->tx_ep = STLINK_V2_1_TX_EP; h->trace_ep = STLINK_V2_1_TRACE_EP; @@ -3820,7 +3859,7 @@ static int stlink_config_trace(void *handle, bool enabled, return ERROR_FAIL; } - unsigned int max_trace_freq = (h->version.stlink == 3) ? + unsigned int max_trace_freq = (h->version.stlink >= 3) ? STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; /* Only concern ourselves with the frequency if the STlink is processing it. */ diff --git a/tcl/interface/stlink-dap.cfg b/tcl/interface/stlink-dap.cfg index 5c24cbdab7..99c81c180c 100644 --- a/tcl/interface/stlink-dap.cfg +++ b/tcl/interface/stlink-dap.cfg @@ -11,7 +11,7 @@ # adapter driver st-link -st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 +st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # transport select dapdirect_jtag # transport select dapdirect_swd diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index e4906b74ed..8578bf2199 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -8,7 +8,7 @@ adapter driver hla hla_layout stlink hla_device_desc "ST-LINK" -hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 +hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 # devices seem to have serial numbers with unreadable characters. ST-LINK/V2 From 1a3bd45a61626c5184f9d815ad3cbbb050739f25 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Thu, 13 Jul 2023 23:06:14 +0200 Subject: [PATCH 14/49] target/espressif: fix build issue with older gcc versions Compilation on old gcc 4.8.4 fails: error: missing braces around initializer [-Werror=missing-braces] Signed-off-by: Erhan Kurubas Change-Id: Ie8b5747f9e23ba5a82bd7f666846e7286284a338 Reviewed-on: https://review.openocd.org/c/openocd/+/7815 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/espressif/esp32_apptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c index 884224116e..125f366329 100644 --- a/src/target/espressif/esp32_apptrace.c +++ b/src/target/espressif/esp32_apptrace.c @@ -1252,7 +1252,7 @@ static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx) { uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START }; uint32_t fired_target_num = 0; - struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {0}; + struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {{0}}; struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; /* get current block id */ From 659f2e062d2fa2196465d2c3197da316b23285ae Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 15 Apr 2023 01:13:12 +0200 Subject: [PATCH 15/49] tcl/cpld: add config files for virtex-7 devices with ir-length > 6 Adding a single file for each different ir-length. Change-Id: Iba3dd55b91c28fdb4d0cafa1ededd939fe61a267 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7715 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/cpld/xilinx-xc7.cfg | 9 --------- tcl/cpld/xilinx-xc7v.cfg | 37 +++++++++++++++++++++++++++++++++++ tcl/cpld/xilinx-xc7vh580t.cfg | 25 +++++++++++++++++++++++ tcl/cpld/xilinx-xc7vh870t.cfg | 28 ++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 tcl/cpld/xilinx-xc7v.cfg create mode 100644 tcl/cpld/xilinx-xc7vh580t.cfg create mode 100644 tcl/cpld/xilinx-xc7vh870t.cfg diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index ebd76ff6b0..f5b0733749 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -40,15 +40,6 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x03691093 \ -expected-id 0x03696093 -#jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \ -# -expected-id 0x036B3093 -expected-id 0x036B7093 \ -# -expected-id 0x036BB093 -expected-id 0x036BF093 \ -# -expected-id 0x036D5093 - -#jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093 - -#jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 - pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x22 0x23 diff --git a/tcl/cpld/xilinx-xc7v.cfg b/tcl/cpld/xilinx-xc7v.cfg new file mode 100644 index 0000000000..8385948323 --- /dev/null +++ b/tcl/cpld/xilinx-xc7v.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=08e275a0cd3ac38988ca59b002289d77 +# https://bsdl.info/view.htm?sid=44dae65d3cf9593188ca59b002289d77 +# +# this config file is for XC7VX1140T and XC7V2000T only. +# for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7vh870t.cfg or xilinx-xc7.cfg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7v +} + +#0x036D5093: XC7VX1140T +#0x036By093: XC7V2000T +#y = xx11 = 3, 7, B or F + +jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \ + -expected-id 0x036B3093 -expected-id 0x036B7093 \ + -expected-id 0x036BB093 -expected-id 0x036BF093 \ + -expected-id 0x036D5093 + +#CFG_OUT_SLR0 0x124924 +#CFG_IN_SLR0 0x164924 +#CFG_OUT_SLR1 0x904924 +#CFG_IN_SLR1 0x905924 +#CFG_OUT_SLR2 0x924124 +#CFG_IN_SLR2 0x924164 +#CFG_OUT_SLR3 0x924904 +#CFG_IN_SLR3 0x924905 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x2CB2CB 0x30C30C 0x34D34D diff --git a/tcl/cpld/xilinx-xc7vh580t.cfg b/tcl/cpld/xilinx-xc7vh580t.cfg new file mode 100644 index 0000000000..3748049803 --- /dev/null +++ b/tcl/cpld/xilinx-xc7vh580t.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=65c6b2cfe1467b4988ca59b002289d77 +# +# this config file is for xc7vh580t only. +# for other virtex-7 devices use xilinx-xc7vh870t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7vh580t +} + +jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093 + +#CFG_OUT_SLR0 0x0492A0 +#CFG_IN_SLR0 0x0592A0 +#CFG_OUT_SLR1 0x2412A0 +#CFG_IN_SLR1 0x2416A0 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x0B2EA0 0x0C32A0 0x0D36A0 diff --git a/tcl/cpld/xilinx-xc7vh870t.cfg b/tcl/cpld/xilinx-xc7vh870t.cfg new file mode 100644 index 0000000000..25e2e63615 --- /dev/null +++ b/tcl/cpld/xilinx-xc7vh870t.cfg @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=d9ff0bb764df004588ca59b002289d77 +# +# this config file is for xc7vh870t only. +# for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7vh870t +} + +jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 + +#CFG_OUT_SLR0 0x0492A092A0 +#CFG_IN_SLR0 0x0592A092A0 +#CFG_OUT_SLR1 0x2412A092A0 +#CFG_IN_SLR1 0x2416A092A0 +#CFG_OUT_SLR2 0x2492A012A0 +#CFG_IN_SLR2 0x2492A016A0 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFFFFFF 0x3FFFFFFFFF 0x0B2EA02EA0 0x0C32A032A0 0x0D36A036A0 From ddf5e3f90ddf25021cebd95b908491b233c44c59 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Sat, 15 Apr 2023 01:13:12 +0200 Subject: [PATCH 16/49] tcl/ultrascale: add more ultrascale devices Add more ultrascale devices. Set instruction codes for SSI devices such that refresh/program read_stat and user registers will work. Change-Id: Id0a0706f4016eb8a4732725a5b72ae61efd73421 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7716 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/cpld/xilinx-xcu.cfg | 99 ++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg index 2d74695ed8..4d7f26c889 100644 --- a/tcl/cpld/xilinx-xcu.cfg +++ b/tcl/cpld/xilinx-xcu.cfg @@ -12,32 +12,61 @@ if { [info exists CHIPNAME] } { # The various chips in the Ultrascale family have different IR length. # Set $CHIP before including this file to determine the device. array set _XCU_DATA { - XCKU025 {0x03824093 6} - XCKU035 {0x03823093 6} - XCKU040 {0x03822093 6} - XCKU060 {0x03919093 6} - XCKU095 {0x03844093 6} - XCKU3P {0x04A63093 6} - XCKU5P {0x04A62093 6} - XCKU9P {0x0484A093 6} - XCKU11P {0x04A4E093 6} - XCKU13P {0x04A52093 6} - XCKU15P {0x04A56093 6} - XCVU065 {0x03939093 6} - XCVU080 {0x03843093 6} - XCVU095 {0x03842093 6} - XCVU3P {0x04B39093 6} - XCKU085 {0x0380F093 12} - XCKU115 {0x0390D093 12} - XCVU125 {0x0392D093 12} - XCVU5P {0x04B2B093 12} - XCVU7P {0x04B29093 12} - XCVU160 {0x03933093 18} - XCVU190 {0x03931093 18} - XCVU440 {0x0396D093 18} - XCVU9P {0x04B31093 18} - XCVU11P {0x04B49093 18} - XCVU13P {0x04B51093 24} + XCKU025 {0x03824093 6} + XCKU035 {0x03823093 6} + XCKU040 {0x03822093 6} + XCKU060 {0x03919093 6} + XCKU060_CIV {0x0381b093 6} + XCKU095 {0x03844093 6} + XCKU095_CIV {0x03845093 6} + XCKU3P {0x04A63093 6} + XCKU5P {0x04A62093 6} + XCKU9P {0x0484A093 6} + XCKU11P {0x04A4E093 6} + XCKU11P_CIV {0x04A51093 6} + XCKU13P {0x04A52093 6} + XCKU15P {0x04A56093 6} + XCKU15P_CIV {0x04A59093 6} + XCVU065 {0x03939093 6} + XCVU065_CIV {0x0393b093 6} + XCVU080 {0x03843093 6} + XCVU080_CIV {0x03845093 6} + XCVU095 {0x03842093 6} + XCVU2P {0x04aea093 6} + XCVU3P {0x04B39093 6} + XCVU3P_CIV {0x04b3d093 6} + XCAU10P {0x04AC4033 6} + XCAU10P_FFVB676 {0x04AC4093 6} + XCAU15P {0x04AC2033 6} + XCAU15P_FFVB676 {0x04AC2093 6} + XCAU20P {0x04A65093 6} + XCAU25P {0x04A64093 6} + XCKU5P_CIV {0x04A64093 6} + XCKU19P {0x04ACF093 6} + XCKU19P_CIV {0x04AD3093 6} + XCKU085 {0x0380F093 12} + XCKU115 {0x0390D093 12} + XCVU125 {0x0392D093 12} + XCVU125_CIV {0x0392f093 12} + XCVU5P {0x04B2B093 12} + XCVU5P_CIV {0x04b2f093 12} + XCVU7P {0x04B29093 12} + XCVU7P_CIV {0x04b2d093 12} + XCVU160 {0x03933093 18} + XCVU190 {0x03931093 18} + XCVU440 {0x0396D093 18} + XCVU440_CIV {0x0396f093 18} + XCVU9P {0x04B31093 18} + XCVU9P_CIV {0x04b35093 18} + XCVU11P {0x04B49093 18} + XCVU11P_CIV {0x04b4f093 18} + XCU200_FSGD2104 {0x04b37093 18} + XCU250 {0x04b57093 24} + XCVU13P {0x04B51093 24} + XCVU13P_CIV {0x04b55093 24} + XCVU15P {0x04ba3093 24} + XCVU19P {0x04ba1093 24} + XCVU19P_CIV {0x04ba5093 24} } if { ![info exists CHIP] } { @@ -56,6 +85,24 @@ jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# set the correct instruction codes for jtag hub and +# at least the right code for jprogb, jstart and jshutdown for SSI devices +if { $_IRLEN == 6 } { + virtex2 set_user_codes $_CHIPNAME.pld 0x2 0x3 0x22 0x23 +} elseif {$_IRLEN == 12 } { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x905 0x904 0x2cb 0x30c 0x34d + virtex2 set_user_codes $_CHIPNAME.pld 0x0a4 0x0e4 0x8a4 0x8e4 +} elseif {$_IRLEN == 18 } { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x24905 0x24904 0x0b2cb 0x0c30c 0x0d34d + virtex2 set_user_codes $_CHIPNAME.pld 0x000a4 0x000e4 0x008a4 0x008e4 +} else { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x924905 0x924904 0x2cb2cb 0x30c30c 0x34d34d + virtex2 set_user_codes $_CHIPNAME.pld 0x0a4924 0x0e4924 0x8a4924 0x8e4924 +} + set XCU_JSHUTDOWN 0x0d set XCU_JPROGRAM 0x0b set XCU_JSTART 0x0c From 05da04acdaabad77cb0ec0caf1edafd516bb79fa Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 5 Jul 2023 15:25:12 +0200 Subject: [PATCH 17/49] flash/nor/stm32l4x: Add revision 'V' for STM32L4R/S devices See section 57.6.1 in RM0432. Change-Id: Ic4977aee74d1838f420c1d9ff19925d09f8f6e2b Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/7763 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/stm32l4x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 934deec9fd..77a89f53c0 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -326,6 +326,7 @@ static const struct stm32l4_rev stm32g47_g48xx_revs[] = { static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, + { 0x101F, "V" }, }; static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { From 965730dda9e1bbb18b9b954ef63ce9ed22fef73f Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 10 Jul 2023 21:03:10 +0200 Subject: [PATCH 18/49] ipdbg: fix 'double free' in case of failed start Change-Id: Id241d9dd0793095106fea000422617fbef462669 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7770 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/server/ipdbg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 3fae0a98d8..c1bdb29395 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -632,10 +632,8 @@ static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instru } } else { int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub); - if (retval != ERROR_OK) { - free(virtual_ir); + if (retval != ERROR_OK) return retval; - } } struct ipdbg_service *service = NULL; From 886d6c3cbcc4c831d48790c9f1fdb02c8036f79e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 10 Jul 2023 11:59:27 +0200 Subject: [PATCH 19/49] doc:usb_adapters: add lsusb dump of STLINK-V3PWR Add USB VID:PID 0483:3755 and 0483:3757. Change-Id: Iace29fa97f1b8e9d86078b9775561ca525635523 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7768 Tested-by: jenkins --- .../stlink/0483_3755_stlinkv3pwr.txt | 71 +++++ .../stlink/0483_3757_stlinkv3pwr.txt | 253 ++++++++++++++++++ 2 files changed, 324 insertions(+) create mode 100644 doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt create mode 100644 doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt diff --git a/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt b/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt new file mode 100644 index 0000000000..6c7cd6fbf3 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# STLINK-V3PWR standalone in firmware update mode + +Bus 003 Device 054: ID 0483:3755 STMicroelectronics USB2.0 Hub +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3755 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3PWR + iSerial 3 123456780000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 DFU Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Usbloader + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt b/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt new file mode 100644 index 0000000000..0cfd6cf588 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt @@ -0,0 +1,253 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# STLINK-V3PWR standalone + +Bus 003 Device 053: ID 0483:3757 STMicroelectronics USB2.0 Hub +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3757 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3PWR + iSerial 3 123456780000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x00c2 + bNumInterfaces 6 + bConfigurationValue 1 + iConfiguration 4 Default Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 2 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 7 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 8 ST-Link Bridge + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 4 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 9 ST-Link VCP-PWR Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 9 ST-Link VCP-PWR Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 5 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 4 + bSlaveInterface 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 10 ST-Link VCP-PWR Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) From c97b9054d9f52516b529bea58f09e14a4e0d82fd Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 10:17:33 +0200 Subject: [PATCH 20/49] tcl/target: move Espressif shared functions to esp_common.cfg Consolidate commonly used commands and variables from chip config files into functions in esp_common.cfg. This includes "jtag newtap," "target create,"and "configure -event." Enhances code reusability and simplifies maintenance. Signed-off-by: Erhan Kurubas Change-Id: I9e8bf07a4a15d4544ceb564607dea66837381d70 Reviewed-on: https://review.openocd.org/c/openocd/+/7744 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/esp_common.cfg | 185 +++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 3 deletions(-) diff --git a/tcl/target/esp_common.cfg b/tcl/target/esp_common.cfg index 424c0cdff5..ac8cd6a198 100644 --- a/tcl/target/esp_common.cfg +++ b/tcl/target/esp_common.cfg @@ -1,10 +1,189 @@ # SPDX-License-Identifier: GPL-2.0-or-later # + +set CPU_MAX_ADDRESS 0xFFFFFFFF +source [find bitsbytes.tcl] +source [find memory.tcl] +source [find mmr_helpers.tcl] + # Common ESP chips definitions +# Espressif supports only NuttX in the upstream. +# FreeRTOS support is not upstreamed yet. +set _RTOS "hwthread" +if { [info exists ESP_RTOS] } { + set _RTOS "$ESP_RTOS" +} + +# by default current dir (when OOCD has been started) +set _SEMIHOST_BASEDIR "." if { [info exists ESP_SEMIHOST_BASEDIR] } { set _SEMIHOST_BASEDIR $ESP_SEMIHOST_BASEDIR -} else { - # by default current dir (when OOCD has been started) - set _SEMIHOST_BASEDIR "." +} + +proc set_esp_common_variables { } { + global _CHIPNAME _ONLYCPU _ESP_SMP_TARGET + global _CPUNAME_0 _CPUNAME_1 _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 + global _ESP_WDT_DISABLE _ESP_SOC_RESET _ESP_MEMPROT_IS_ENABLED + + # For now we support dual core at most. + if { $_ONLYCPU == 1 && $_ESP_SMP_TARGET == 0} { + set _TARGETNAME_0 $_CHIPNAME + set _CPUNAME_0 cpu + set _TAPNAME_0 $_CHIPNAME.$_CPUNAME_0 + } else { + set _CPUNAME_0 cpu0 + set _CPUNAME_1 cpu1 + set _TARGETNAME_0 $_CHIPNAME.$_CPUNAME_0 + set _TARGETNAME_1 $_CHIPNAME.$_CPUNAME_1 + set _TAPNAME_0 $_TARGETNAME_0 + set _TAPNAME_1 $_TARGETNAME_1 + } + + set _ESP_WDT_DISABLE "${_CHIPNAME}_wdt_disable" + set _ESP_SOC_RESET "${_CHIPNAME}_soc_reset" + set _ESP_MEMPROT_IS_ENABLED "${_CHIPNAME}_memprot_is_enabled" +} + +proc create_esp_jtag { } { + global _CHIPNAME _CPUNAME_0 _CPUNAME_1 _CPUTAPID _ONLYCPU + jtag newtap $_CHIPNAME $_CPUNAME_0 -irlen 5 -expected-id $_CPUTAPID + if { $_ONLYCPU != 1 } { + jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -expected-id $_CPUTAPID + } elseif [info exists _CPUNAME_1] { + jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -disable -expected-id $_CPUTAPID + } +} + +proc create_openocd_targets { } { + global _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 _RTOS _CHIPNAME _ONLYCPU + + target create $_TARGETNAME_0 $_CHIPNAME -chain-position $_TAPNAME_0 -coreid 0 -rtos $_RTOS + if { $_ONLYCPU != 1 } { + target create $_TARGETNAME_1 $_CHIPNAME -chain-position $_TAPNAME_1 -coreid 1 -rtos $_RTOS + target smp $_TARGETNAME_0 $_TARGETNAME_1 + } +} + +proc create_esp_target { ARCH } { + set_esp_common_variables + create_esp_jtag + create_openocd_targets + configure_openocd_events + + if { $ARCH == "xtensa"} { + configure_esp_xtensa_default_settings + } else { + # riscv targets are not upstreamed yet. + # they can be found at the official Espressif fork. + } +} + +#################### Set event handlers and default settings #################### + +proc configure_event_examine_end { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } + } +} + +proc configure_event_reset_assert_post { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event reset-assert-post { + global _ESP_SOC_RESET + $_ESP_SOC_RESET + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event reset-assert-post { + global _ESP_SOC_RESET + $_ESP_SOC_RESET + } + } +} + +proc configure_event_halted { } { + global _TARGETNAME_0 + + $_TARGETNAME_0 configure -event halted { + global _ESP_WDT_DISABLE + $_ESP_WDT_DISABLE + esp halted_event_handler + } +} + +proc configure_event_gdb_attach { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event gdb-attach { + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut + } + # necessary to auto-probe flash bank when GDB is connected and generate proper memory map + halt 1000 + if { [$_ESP_MEMPROT_IS_ENABLED] } { + # 'reset halt' to disable memory protection and allow flasher to work correctly + echo "Memory protection is enabled. Reset target to disable it..." + reset halt + } + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event gdb-attach { + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_1 xtensa smpbreak BreakIn BreakOut + } + # necessary to auto-probe flash bank when GDB is connected + halt 1000 + if { [$_ESP_MEMPROT_IS_ENABLED] } { + # 'reset halt' to disable memory protection and allow flasher to work correctly + echo "Memory protection is enabled. Reset target to disable it..." + reset halt + } + } + } +} + +proc configure_openocd_events { } { + configure_event_examine_end + configure_event_reset_assert_post + configure_event_gdb_attach +} + +proc configure_esp_xtensa_default_settings { } { + global _TARGETNAME_0 _ESP_SMP_BREAK _FLASH_VOLTAGE _CHIPNAME + + $_TARGETNAME_0 xtensa maskisr on + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut + } + + gdb_breakpoint_override hard + + if { [info exists _FLASH_VOLTAGE] } { + $_TARGETNAME_0 $_CHIPNAME flashbootstrap $_FLASH_VOLTAGE + } } From d70fd7c5be74f5f524130c95985670eb57f5d5fa Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 10:25:07 +0200 Subject: [PATCH 21/49] tcl/target: update esp32.cfg to reference shared functions in the esp_common.cfg This commit enhances code reusability, simplifies maintenance, and ensures consistency across all chip configurations by consolidating commonly used commands and variables into the common config file. Signed-off-by: Erhan Kurubas Change-Id: I9181737d83eeba4e983b6a455b8a1523f2576dd2 Reviewed-on: https://review.openocd.org/c/openocd/+/7745 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/esp32.cfg | 94 +++++++------------------------------------- 1 file changed, 15 insertions(+), 79 deletions(-) diff --git a/tcl/target/esp32.cfg b/tcl/target/esp32.cfg index f4c13aa5b9..b30a170247 100644 --- a/tcl/target/esp32.cfg +++ b/tcl/target/esp32.cfg @@ -1,99 +1,35 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# The ESP32 only supports JTAG. -transport select jtag -# Source the ESP common configuration file +# Source the ESP common configuration file. source [find target/esp_common.cfg] -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x120034e5 -} +# Target specific global variables +set _CHIPNAME "esp32" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 3 +set _FLASH_VOLTAGE 3.3 +set _ESP_SMP_TARGET 1 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x3ff5A004 if { [info exists ESP32_ONLYCPU] } { set _ONLYCPU $ESP32_ONLYCPU -} else { - set _ONLYCPU 2 } if { [info exists ESP32_FLASH_VOLTAGE] } { set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE -} else { - set _FLASH_VOLTAGE 3.3 -} - -set _CPU0NAME cpu0 -set _CPU1NAME cpu1 -set _TARGETNAME_0 $_CHIPNAME.$_CPU0NAME -set _TARGETNAME_1 $_CHIPNAME.$_CPU1NAME - -jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 -expected-id $_CPUTAPID -if { $_ONLYCPU != 1 } { - jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -expected-id $_CPUTAPID -} else { - jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -disable -expected-id $_CPUTAPID -} - -# PRO-CPU -target create $_TARGETNAME_0 $_CHIPNAME -endian little -chain-position $_TARGETNAME_0 -coreid 0 -# APP-CPU -if { $_ONLYCPU != 1 } { - target create $_TARGETNAME_1 $_CHIPNAME -endian little -chain-position $_TARGETNAME_1 -coreid 1 - target smp $_TARGETNAME_0 $_TARGETNAME_1 -} - -$_TARGETNAME_0 esp32 flashbootstrap $_FLASH_VOLTAGE -$_TARGETNAME_0 xtensa maskisr on -$_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut -$_TARGETNAME_0 configure -event reset-assert-post { soft_reset_halt } - -$_TARGETNAME_0 configure -event gdb-attach { - $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut - # necessary to auto-probe flash bank when GDB is connected - halt 1000 -} - -if { $_ONLYCPU != 1 } { - $_TARGETNAME_1 configure -event gdb-attach { - $_TARGETNAME_1 xtensa smpbreak BreakIn BreakOut - # necessary to auto-probe flash bank when GDB is connected - halt 1000 - } - $_TARGETNAME_1 configure -event reset-assert-post { soft_reset_halt } } -$_TARGETNAME_0 configure -event examine-end { - # Need to enable to set 'semihosting_basedir' - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } +proc esp32_memprot_is_enabled { } { + return 0 } -if { $_ONLYCPU != 1 } { - $_TARGETNAME_1 configure -event examine-end { - # Need to enable to set 'semihosting_basedir' - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } - } +proc esp32_soc_reset { } { + soft_reset_halt } -gdb_breakpoint_override hard +create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32.cfg] From 93002a86cde9cf95a894bdc099b67d6379e22cd3 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 11:18:31 +0200 Subject: [PATCH 22/49] tcl/target: update esp32s2.cfg to reference shared functions in the esp_common.cfg This commit enhances code reusability, simplifies maintenance, and ensures consistency across all chip configurations by consolidating commonly used commands and variables into the common config file. Signed-off-by: Erhan Kurubas Change-Id: I36c86fe4ebc99928ce48a5bff8cb9580a0fa3ac0 Reviewed-on: https://review.openocd.org/c/openocd/+/7746 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/esp32s2.cfg | 62 ++++++++---------------------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/tcl/target/esp32s2.cfg b/tcl/target/esp32s2.cfg index e478a6d39d..4c1362a346 100644 --- a/tcl/target/esp32s2.cfg +++ b/tcl/target/esp32s2.cfg @@ -1,32 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# The ESP32-S2 only supports JTAG. -transport select jtag -set CPU_MAX_ADDRESS 0xFFFFFFFF -source [find bitsbytes.tcl] -source [find memory.tcl] -source [find mmr_helpers.tcl] -# Source the ESP common configuration file +# Source the ESP common configuration file. source [find target/esp_common.cfg] -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32s2 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x120034e5 -} - -set _TARGETNAME $_CHIPNAME -set _CPUNAME cpu -set _TAPNAME $_CHIPNAME.$_CPUNAME - -jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID +# Target specific global variables +set _CHIPNAME "esp32s2" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x3f41A004 proc esp32s2_memprot_is_enabled { } { # IRAM0, DPORT_PMS_PRO_IRAM0_0_REG @@ -48,33 +33,10 @@ proc esp32s2_memprot_is_enabled { } { return 0 } -target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME - -$_TARGETNAME configure -event gdb-attach { - # necessary to auto-probe flash bank when GDB is connected and generate proper memory map - halt 1000 - if { [esp32s2_memprot_is_enabled] } { - # 'reset halt' to disable memory protection and allow flasher to work correctly - echo "Memory protection is enabled. Reset target to disable it..." - reset halt - } -} - -xtensa maskisr on - -$_TARGETNAME configure -event examine-end { - # Need to enable to set 'semihosting_basedir' - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } +proc esp32s2_soc_reset { } { + soft_reset_halt } -$_TARGETNAME configure -event reset-assert-post { soft_reset_halt } - -gdb_breakpoint_override hard +create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32s2.cfg] From 78daf24a5c29664669bb1d9d7851cbbb90dbc444 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 11:00:22 +0200 Subject: [PATCH 23/49] tcl/target: update esp32s3.cfg to reference shared functions in the esp_common.cfg This commit enhances code reusability, simplifies maintenance, and ensures consistency across all chip configurations by consolidating commonly used commands and variables into the common config file. Signed-off-by: Erhan Kurubas Change-Id: Ifb0122f3b98a767f27746409499733b70fb7d0e8 Reviewed-on: https://review.openocd.org/c/openocd/+/7747 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/esp32s3.cfg | 104 +++++------------------------------------ 1 file changed, 12 insertions(+), 92 deletions(-) diff --git a/tcl/target/esp32s3.cfg b/tcl/target/esp32s3.cfg index 42b2199633..12c166c463 100644 --- a/tcl/target/esp32s3.cfg +++ b/tcl/target/esp32s3.cfg @@ -1,44 +1,20 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# The ESP32-S3 only supports JTAG. -transport select jtag -set CPU_MAX_ADDRESS 0xFFFFFFFF -source [find bitsbytes.tcl] -source [find memory.tcl] -source [find mmr_helpers.tcl] -# Source the ESP common configuration file +# Source the ESP common configuration file. source [find target/esp_common.cfg] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32s3 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x120034e5 -} +# Target specific global variables +set _CHIPNAME "esp32s3" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 3 +set _ESP_SMP_TARGET 1 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x60007044 if { [info exists ESP32_S3_ONLYCPU] } { set _ONLYCPU $ESP32_S3_ONLYCPU -} else { - set _ONLYCPU 2 -} - -set _CPU0NAME cpu0 -set _CPU1NAME cpu1 -set _TARGETNAME_0 $_CHIPNAME.$_CPU0NAME -set _TARGETNAME_1 $_CHIPNAME.$_CPU1NAME - -jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 -expected-id $_CPUTAPID -if { $_ONLYCPU != 1 } { - jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -expected-id $_CPUTAPID -} else { - jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -disable -expected-id $_CPUTAPID } proc esp32s3_memprot_is_enabled { } { @@ -89,66 +65,10 @@ proc esp32s3_memprot_is_enabled { } { return 0 } -# PRO-CPU -target create $_TARGETNAME_0 $_CHIPNAME -endian little -chain-position $_TARGETNAME_0 -coreid 0 -# APP-CPU -if { $_ONLYCPU != 1 } { - target create $_TARGETNAME_1 $_CHIPNAME -endian little -chain-position $_TARGETNAME_1 -coreid 1 - target smp $_TARGETNAME_0 $_TARGETNAME_1 -} - -$_TARGETNAME_0 xtensa maskisr on -$_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut -$_TARGETNAME_0 configure -event examine-end { - # Need to enable to set 'semihosting_basedir' - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } -} - -if { $_ONLYCPU != 1 } { - $_TARGETNAME_1 configure -event examine-end { - # Need to enable to set 'semihosting_basedir' - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } - } -} - -$_TARGETNAME_0 configure -event gdb-attach { - $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut - # necessary to auto-probe flash bank when GDB is connected and generate proper memory map - halt 1000 - if { [esp32s3_memprot_is_enabled] } { - # 'reset halt' to disable memory protection and allow flasher to work correctly - echo "Memory protection is enabled. Reset target to disable it..." - reset halt - } -} -$_TARGETNAME_0 configure -event reset-assert-post { soft_reset_halt } - -if { $_ONLYCPU != 1 } { - $_TARGETNAME_1 configure -event gdb-attach { - $_TARGETNAME_1 xtensa smpbreak BreakIn BreakOut - # necessary to auto-probe flash bank when GDB is connected - halt 1000 - if { [esp32s3_memprot_is_enabled] } { - # 'reset halt' to disable memory protection and allow flasher to work correctly - echo "Memory protection is enabled. Reset target to disable it..." - reset halt - } - } - $_TARGETNAME_1 configure -event reset-assert-post { soft_reset_halt } +proc esp32s3_soc_reset { } { + soft_reset_halt } -gdb_breakpoint_override hard +create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32s3.cfg] From 29b02402ffdcb4fcf04492e4228a303cc02e9658 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 4 Jul 2023 18:40:36 +0200 Subject: [PATCH 24/49] target/esp_xtensa: add xtensa on_halt handler Right after target halt, some activities needs to be done such as printing exception reason, disable wdts and reading debug stubs information. Missing activities will be submitted in the next patches. Signed-off-by: Erhan Kurubas Change-Id: I27aad5614d903f4bd7c8d6dba6bfb0bdb93ed8dc Reviewed-on: https://review.openocd.org/c/openocd/+/7757 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/target/espressif/esp32.c | 5 ++++- src/target/espressif/esp32s2.c | 5 ++++- src/target/espressif/esp32s3.c | 5 ++++- src/target/espressif/esp_xtensa.c | 6 ++++++ src/target/espressif/esp_xtensa.h | 1 + src/target/espressif/esp_xtensa_smp.c | 15 +++++++++++++++ src/target/espressif/esp_xtensa_smp.h | 1 + 7 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 74bbe50bdd..5cc236c36f 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -266,7 +266,10 @@ static int esp32_disable_wdts(struct target *target) static int esp32_on_halt(struct target *target) { - return esp32_disable_wdts(target); + int ret = esp32_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_smp_on_halt(target); + return ret; } static int esp32_arch_state(struct target *target) diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index a11d05f0f2..3628cc0931 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -385,7 +385,10 @@ static int esp32s2_arch_state(struct target *target) static int esp32s2_on_halt(struct target *target) { - return esp32s2_disable_wdts(target); + int ret = esp32s2_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_on_halt(target); + return ret; } static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 485567836b..074155f6a6 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -283,7 +283,10 @@ static int esp32s3_disable_wdts(struct target *target) static int esp32s3_on_halt(struct target *target) { - return esp32s3_disable_wdts(target); + int ret = esp32s3_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_smp_on_halt(target); + return ret; } static int esp32s3_arch_state(struct target *target) diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 44764aeca7..3dfcc0fb2c 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -17,6 +17,12 @@ #include "esp_xtensa.h" #include "esp_semihosting.h" +int esp_xtensa_on_halt(struct target *target) +{ + /* will be used in the next patches */ + return ERROR_OK; +} + int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, struct xtensa_debug_module_config *dm_cfg, diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 8807f0c325..0b06b0395c 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -36,5 +36,6 @@ void esp_xtensa_queue_tdi_idle(struct target *target); int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_poll(struct target *target); +int esp_xtensa_on_halt(struct target *target); #endif /* OPENOCD_TARGET_ESP_XTENSA_H */ diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c index 1d037741da..93c53f15b7 100644 --- a/src/target/espressif/esp_xtensa_smp.c +++ b/src/target/espressif/esp_xtensa_smp.c @@ -112,6 +112,21 @@ int esp_xtensa_smp_soft_reset_halt(struct target *target) return ERROR_OK; } +int esp_xtensa_smp_on_halt(struct target *target) +{ + struct target_list *head; + + if (!target->smp) + return esp_xtensa_on_halt(target); + + foreach_smp_target(head, target->smp_targets) { + int res = esp_xtensa_on_halt(head->target); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid) { struct target_list *head; diff --git a/src/target/espressif/esp_xtensa_smp.h b/src/target/espressif/esp_xtensa_smp.h index aeb1d61f58..4e4f3b3321 100644 --- a/src/target/espressif/esp_xtensa_smp.h +++ b/src/target/espressif/esp_xtensa_smp.h @@ -37,6 +37,7 @@ int esp_xtensa_smp_step(struct target *target, int esp_xtensa_smp_assert_reset(struct target *target); int esp_xtensa_smp_deassert_reset(struct target *target); int esp_xtensa_smp_soft_reset_halt(struct target *target); +int esp_xtensa_smp_on_halt(struct target *target); int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint); int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); int esp_xtensa_smp_handle_target_event(struct target *target, enum target_event event, void *priv); From 9fd754ca4da4111c84385d9b080fb839eac9bc30 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 3 Jul 2023 23:16:52 +0200 Subject: [PATCH 25/49] target/espressif: read entry addresses of pre-defined stub functions Debug stubs functionality provided by ESP IDF allows executing target function in any address. e.g; esp32_cmd_gcov() Signed-off-by: Erhan Kurubas Change-Id: I56d844e5a862c9bf33fdb991b01abb7a76047ca7 Reviewed-on: https://review.openocd.org/c/openocd/+/7758 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/espressif/Makefile.am | 38 ++++----- src/target/espressif/esp.c | 77 ++++++++++++++++++ src/target/espressif/esp.h | 85 ++++++++++++++++++++ src/target/espressif/esp_xtensa.c | 107 +++++++++++++++++++++++++- src/target/espressif/esp_xtensa.h | 3 +- src/target/espressif/esp_xtensa_smp.c | 11 +++ 6 files changed, 300 insertions(+), 21 deletions(-) create mode 100644 src/target/espressif/esp.c create mode 100644 src/target/espressif/esp.h diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am index 14625d4b36..776818ff4d 100644 --- a/src/target/espressif/Makefile.am +++ b/src/target/espressif/Makefile.am @@ -2,21 +2,23 @@ noinst_LTLIBRARIES += %D%/libespressif.la %C%_libespressif_la_SOURCES = \ - %D%/esp_xtensa.c \ - %D%/esp_xtensa.h \ - %D%/esp_xtensa_smp.c \ - %D%/esp_xtensa_smp.h \ - %D%/esp_xtensa_semihosting.c \ - %D%/esp_xtensa_semihosting.h \ - %D%/esp_xtensa_apptrace.c \ - %D%/esp_xtensa_apptrace.h \ - %D%/esp32_apptrace.c \ - %D%/esp32_apptrace.h \ - %D%/esp32.c \ - %D%/esp32s2.c \ - %D%/esp32s3.c \ - %D%/esp32_sysview.c \ - %D%/esp32_sysview.h \ - %D%/segger_sysview.h \ - %D%/esp_semihosting.c \ - %D%/esp_semihosting.h + %D%/esp_xtensa.c \ + %D%/esp_xtensa.h \ + %D%/esp_xtensa_smp.c \ + %D%/esp_xtensa_smp.h \ + %D%/esp_xtensa_semihosting.c \ + %D%/esp_xtensa_semihosting.h \ + %D%/esp_xtensa_apptrace.c \ + %D%/esp_xtensa_apptrace.h \ + %D%/esp32_apptrace.c \ + %D%/esp32_apptrace.h \ + %D%/esp32.c \ + %D%/esp32s2.c \ + %D%/esp32s3.c \ + %D%/esp.c \ + %D%/esp.h \ + %D%/esp32_sysview.c \ + %D%/esp32_sysview.h \ + %D%/segger_sysview.h \ + %D%/esp_semihosting.c \ + %D%/esp_semihosting.h diff --git a/src/target/espressif/esp.c b/src/target/espressif/esp.c new file mode 100644 index 0000000000..9583d6493e --- /dev/null +++ b/src/target/espressif/esp.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Espressif chips common target API for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "target/target.h" +#include "esp.h" + +int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs) +{ + uint32_t table_size, table_start_id, desc_entry_id, gcov_entry_id; + uint32_t entries[ESP_DBG_STUB_ENTRY_MAX] = {0}; + uint8_t entry_buff[sizeof(entries)] = {0}; /* to avoid endiannes issues */ + + LOG_TARGET_DEBUG(target, "Read debug stubs info %" PRIx32 " / %d", dbg_stubs->base, dbg_stubs->entries_count); + + /* First of, read 2 entries to get magic num and table size */ + int res = target_read_buffer(target, dbg_stubs->base, sizeof(uint32_t) * 2, entry_buff); + if (res != ERROR_OK) { + LOG_ERROR("%s: Failed to read first debug stub entry!", target_name(target)); + return res; + } + entries[0] = target_buffer_get_u32(target, entry_buff); + entries[1] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t)); + + if (entries[0] != ESP_DBG_STUB_MAGIC_NUM_VAL) { + /* idf with the old table entry structure */ + table_size = 2; + table_start_id = 0; + desc_entry_id = 0; + gcov_entry_id = 1; + } else { + table_size = entries[1]; + table_start_id = ESP_DBG_STUB_TABLE_START; + desc_entry_id = ESP_DBG_STUB_TABLE_START; + gcov_entry_id = ESP_DBG_STUB_ENTRY_FIRST; + + /* discard unsupported entries */ + if (table_size > ESP_DBG_STUB_ENTRY_MAX) + table_size = ESP_DBG_STUB_ENTRY_MAX; + + /* now read the remaining entries */ + res = target_read_buffer(target, dbg_stubs->base + 2 * sizeof(uint32_t), sizeof(uint32_t) * table_size - 2, + entry_buff + sizeof(uint32_t) * 2); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read debug stubs info!"); + return res; + } + for (unsigned int i = 2; i < table_size; ++i) + entries[i] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t) * i); + + dbg_stubs->entries[ESP_DBG_STUB_CAPABILITIES] = entries[ESP_DBG_STUB_CAPABILITIES]; + } + + dbg_stubs->entries[ESP_DBG_STUB_DESC] = entries[desc_entry_id]; + dbg_stubs->entries[ESP_DBG_STUB_ENTRY_GCOV] = entries[gcov_entry_id]; + + for (enum esp_dbg_stub_id i = ESP_DBG_STUB_DESC; i < ESP_DBG_STUB_ENTRY_MAX; i++) { + LOG_DEBUG("Check dbg stub %d - %x", i, dbg_stubs->entries[i]); + if (dbg_stubs->entries[i]) { + LOG_DEBUG("New dbg stub %d at %x", dbg_stubs->entries_count, dbg_stubs->entries[i]); + dbg_stubs->entries_count++; + } + } + if (dbg_stubs->entries_count < table_size - table_start_id) + LOG_WARNING("Not full dbg stub table %d of %d", dbg_stubs->entries_count, table_size - table_start_id); + + return ERROR_OK; +} diff --git a/src/target/espressif/esp.h b/src/target/espressif/esp.h new file mode 100644 index 0000000000..3ba2b8bcfa --- /dev/null +++ b/src/target/espressif/esp.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Espressif chips common target API for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_H +#define OPENOCD_TARGET_ESP_H + +#include +#include + +/* must be in sync with ESP-IDF version */ +/** Size of the pre-compiled target buffer for stub trampoline. + * @note Must be in sync with ESP-IDF version */ +#define ESP_DBG_STUBS_CODE_BUF_SIZE 32 /* TODO: move this info to esp_dbg_stubs_desc */ +/** Size of the pre-compiled target buffer for stack. + * @note Must be in sync with ESP-IDF version */ +#define ESP_DBG_STUBS_STACK_MIN_SIZE 2048/* TODO: move this info to esp_dbg_stubs_desc */ + +/** + * Debug stubs table entries IDs + * + * @note Must be in sync with ESP-IDF version + */ +enum esp_dbg_stub_id { + ESP_DBG_STUB_ENTRY_MAGIC_NUM, + ESP_DBG_STUB_TABLE_SIZE, + ESP_DBG_STUB_TABLE_START, + ESP_DBG_STUB_DESC = ESP_DBG_STUB_TABLE_START, /*< Stubs descriptor ID */ + ESP_DBG_STUB_ENTRY_FIRST, + ESP_DBG_STUB_ENTRY_GCOV = ESP_DBG_STUB_ENTRY_FIRST, /*< GCOV stub ID */ + ESP_DBG_STUB_CAPABILITIES, + /* add new stub entries here */ + ESP_DBG_STUB_ENTRY_MAX, +}; + +#define ESP_DBG_STUB_MAGIC_NUM_VAL 0xFEEDBEEF +#define ESP_DBG_STUB_CAP_GCOV_THREAD BIT(0) + +/** + * Debug stubs descriptor. ID: ESP_DBG_STUB_DESC + * + * @note Must be in sync with ESP-IDF version + */ +struct esp_dbg_stubs_desc { + /** Address of pre-compiled target buffer for stub trampoline. + * Size of the buffer is ESP_DBG_STUBS_CODE_BUF_SIZE + */ + uint32_t tramp_addr; + /** Pre-compiled target buffer's addr for stack. The size of the buffer is ESP_DBG_STUBS_STACK_MIN_SIZE. + * Target has the buffer which is used for the stack of onboard algorithms. + * If stack size required by algorithm exceeds ESP_DBG_STUBS_STACK_MIN_SIZE, + * it should be allocated using onboard function pointed by 'data_alloc' and + * freed by 'data_free'. They fit to the minimal stack. See below. + */ + uint32_t min_stack_addr; + /** Address of malloc-like function to allocate buffer on target. */ + uint32_t data_alloc; + /** Address of free-like function to free buffer allocated with data_alloc. */ + uint32_t data_free; +}; + +/** + * Debug stubs info. + */ +struct esp_dbg_stubs { + /** Address. */ + uint32_t base; + /** Table contents. */ + uint32_t entries[ESP_DBG_STUB_ENTRY_MAX]; + /** Number of table entries. */ + uint32_t entries_count; + /** Debug stubs decsriptor. */ + struct esp_dbg_stubs_desc desc; +}; + +struct esp_common { + struct esp_dbg_stubs dbg_stubs; +}; + +int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs); + +#endif /* OPENOCD_TARGET_ESP_H */ diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 3dfcc0fb2c..0bd2cdd9dd 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -17,9 +17,46 @@ #include "esp_xtensa.h" #include "esp_semihosting.h" +#define ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(_e_) \ + do { \ + uint32_t __internal_val = (_e_); \ + if (!xtensa_data_addr_valid(target, __internal_val)) { \ + LOG_ERROR("No valid stub data entry found (0x%" PRIx32 ")!", __internal_val); \ + return; \ + } \ + } while (0) + +#define ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(_e_) \ + do { \ + uint32_t __internal_val = (_e_); \ + if (__internal_val == 0) { \ + LOG_ERROR("No valid stub code entry found (0x%" PRIx32 ")!", __internal_val); \ + return; \ + } \ + } while (0) + +static void esp_xtensa_dbgstubs_info_update(struct target *target); +static void esp_xtensa_dbgstubs_addr_check(struct target *target); + +static int esp_xtensa_dbgstubs_restore(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + if (esp_xtensa->esp.dbg_stubs.base == 0) + return ERROR_OK; + + LOG_TARGET_INFO(target, "Restore debug stubs address %" PRIx32, esp_xtensa->esp.dbg_stubs.base); + int res = esp_xtensa_apptrace_status_reg_write(target, esp_xtensa->esp.dbg_stubs.base); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write trace status (%d)!", res); + return res; + } + return ERROR_OK; +} int esp_xtensa_on_halt(struct target *target) { - /* will be used in the next patches */ + /* debug stubs can be used in HALTED state only, so it is OK to get info about them here */ + esp_xtensa_dbgstubs_info_update(target); return ERROR_OK; } @@ -45,6 +82,11 @@ void esp_xtensa_target_deinit(struct target *target) { LOG_DEBUG("start"); + if (target_was_examined(target)) { + int ret = esp_xtensa_dbgstubs_restore(target); + if (ret != ERROR_OK) + return; + } xtensa_target_deinit(target); free(target_to_esp_xtensa(target)); /* same as free(xtensa) */ } @@ -56,7 +98,68 @@ int esp_xtensa_arch_state(struct target *target) int esp_xtensa_poll(struct target *target) { - return xtensa_poll(target); + struct xtensa *xtensa = target_to_xtensa(target); + struct esp_xtensa_common *esp_xtensa_common = target_to_esp_xtensa(target); + + int ret = xtensa_poll(target); + + if (xtensa_dm_power_status_get(&xtensa->dbg_mod) & PWRSTAT_COREWASRESET(xtensa)) { + LOG_TARGET_DEBUG(target, "Clear debug stubs info"); + memset(&esp_xtensa_common->esp.dbg_stubs, 0, sizeof(esp_xtensa_common->esp.dbg_stubs)); + } + if (target->state != TARGET_DEBUG_RUNNING) + esp_xtensa_dbgstubs_addr_check(target); + return ret; +} + +static void esp_xtensa_dbgstubs_addr_check(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + uint32_t vec_addr = 0; + + if (esp_xtensa->esp.dbg_stubs.base != 0) + return; + + int res = esp_xtensa_apptrace_status_reg_read(target, &vec_addr); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read debug stubs address location (%d)!", res); + return; + } + if (xtensa_data_addr_valid(target, vec_addr)) { + LOG_TARGET_INFO(target, "Detected debug stubs @ %" PRIx32, vec_addr); + res = esp_xtensa_apptrace_status_reg_write(target, 0); + if (res != ERROR_OK) + LOG_ERROR("Failed to clear debug stubs address location (%d)!", res); + esp_xtensa->esp.dbg_stubs.base = vec_addr; + } +} + +static void esp_xtensa_dbgstubs_info_update(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + if (esp_xtensa->esp.dbg_stubs.base == 0 || esp_xtensa->esp.dbg_stubs.entries_count != 0) + return; + + int res = esp_dbgstubs_table_read(target, &esp_xtensa->esp.dbg_stubs); + if (res != ERROR_OK) + return; + if (esp_xtensa->esp.dbg_stubs.entries_count == 0) + return; + + /* read debug stubs descriptor */ + ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC]); + res = target_read_buffer(target, esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC], + sizeof(struct esp_dbg_stubs_desc), + (uint8_t *)&esp_xtensa->esp.dbg_stubs.desc); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read debug stubs descriptor (%d)!", res); + return; + } + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.tramp_addr); + ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.desc.min_stack_addr); + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_alloc); + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_free); } int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint) diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 0b06b0395c..00f67a3706 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -10,12 +10,13 @@ #include #include -#include "esp_xtensa.h" #include "esp_semihosting.h" +#include "esp.h" #include "esp_xtensa_apptrace.h" struct esp_xtensa_common { struct xtensa xtensa; /* must be the first element */ + struct esp_common esp; struct esp_semihost_data semihost; struct esp_xtensa_apptrace_info apptrace; }; diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c index 93c53f15b7..1d70be9e3c 100644 --- a/src/target/espressif/esp_xtensa_smp.c +++ b/src/target/espressif/esp_xtensa_smp.c @@ -146,6 +146,7 @@ int esp_xtensa_smp_poll(struct target *target) enum target_state old_state = target->state; struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + uint32_t old_dbg_stubs_base = esp_xtensa->esp.dbg_stubs.base; struct target_list *head; struct target *curr; bool other_core_resume_req = false; @@ -163,6 +164,16 @@ int esp_xtensa_smp_poll(struct target *target) if (ret != ERROR_OK) return ret; + if (esp_xtensa->esp.dbg_stubs.base && old_dbg_stubs_base != esp_xtensa->esp.dbg_stubs.base) { + /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */ + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (curr == target) + continue; + target_to_esp_xtensa(curr)->esp.dbg_stubs.base = esp_xtensa->esp.dbg_stubs.base; + } + } + if (target->smp) { if (target->state == TARGET_RESET) { esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES; From 698adc0c62edf12a5dad25a672e46e9a2e442be3 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 4 Jul 2023 23:22:22 +0200 Subject: [PATCH 26/49] target/espressif: cleanup unused macro definitions Memory region addresses are not in use for now. Signed-off-by: Erhan Kurubas Change-Id: I9a2189e956ae59b56245ec914ab16719df857b2d Reviewed-on: https://review.openocd.org/c/openocd/+/7762 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/espressif/esp32.c | 12 ------------ src/target/espressif/esp32s2.c | 21 --------------------- src/target/espressif/esp32s3.c | 10 ---------- 3 files changed, 43 deletions(-) diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 5cc236c36f..b510f287c3 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -24,20 +24,8 @@ implementation. */ /* ESP32 memory map */ -#define ESP32_DRAM_LOW 0x3ffae000 -#define ESP32_DRAM_HIGH 0x40000000 -#define ESP32_IROM_MASK_LOW 0x40000000 -#define ESP32_IROM_MASK_HIGH 0x40064f00 -#define ESP32_IRAM_LOW 0x40070000 -#define ESP32_IRAM_HIGH 0x400a0000 -#define ESP32_RTC_IRAM_LOW 0x400c0000 -#define ESP32_RTC_IRAM_HIGH 0x400c2000 -#define ESP32_RTC_DRAM_LOW 0x3ff80000 -#define ESP32_RTC_DRAM_HIGH 0x3ff82000 #define ESP32_RTC_DATA_LOW 0x50000000 #define ESP32_RTC_DATA_HIGH 0x50002000 -#define ESP32_EXTRAM_DATA_LOW 0x3f800000 -#define ESP32_EXTRAM_DATA_HIGH 0x3fc00000 #define ESP32_DR_REG_LOW 0x3ff00000 #define ESP32_DR_REG_HIGH 0x3ff71000 #define ESP32_SYS_RAM_LOW 0x60000000UL diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 3628cc0931..dadc130c1a 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -17,33 +17,12 @@ #include "esp_xtensa.h" #include "esp_xtensa_semihosting.h" -/* Overall memory map - * TODO: read memory configuration from target registers */ -#define ESP32_S2_IROM_MASK_LOW 0x40000000 -#define ESP32_S2_IROM_MASK_HIGH 0x40020000 -#define ESP32_S2_IRAM_LOW 0x40020000 -#define ESP32_S2_IRAM_HIGH 0x40070000 -#define ESP32_S2_DRAM_LOW 0x3ffb0000 -#define ESP32_S2_DRAM_HIGH 0x40000000 -#define ESP32_S2_RTC_IRAM_LOW 0x40070000 -#define ESP32_S2_RTC_IRAM_HIGH 0x40072000 -#define ESP32_S2_RTC_DRAM_LOW 0x3ff9e000 -#define ESP32_S2_RTC_DRAM_HIGH 0x3ffa0000 #define ESP32_S2_RTC_DATA_LOW 0x50000000 #define ESP32_S2_RTC_DATA_HIGH 0x50002000 -#define ESP32_S2_EXTRAM_DATA_LOW 0x3f500000 -#define ESP32_S2_EXTRAM_DATA_HIGH 0x3ff80000 #define ESP32_S2_DR_REG_LOW 0x3f400000 #define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC #define ESP32_S2_SYS_RAM_LOW 0x60000000UL #define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL) -/* ESP32-S2 DROM mapping is not contiguous. */ -/* IDF declares this as 0x3F000000..0x3FF80000, but there are peripheral registers mapped to - * 0x3f400000..0x3f4d3FFC. */ -#define ESP32_S2_DROM0_LOW ESP32_S2_DROM_LOW -#define ESP32_S2_DROM0_HIGH ESP32_S2_DR_REG_LOW -#define ESP32_S2_DROM1_LOW ESP32_S2_DR_REG_HIGH -#define ESP32_S2_DROM1_HIGH ESP32_S2_DROM_HIGH /* ESP32 WDT */ #define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1 diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 074155f6a6..5036956ee8 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -24,16 +24,6 @@ implementation. */ /* ESP32_S3 memory map */ -#define ESP32_S3_IRAM_LOW 0x40370000 -#define ESP32_S3_IRAM_HIGH 0x403E0000 -#define ESP32_S3_IROM_MASK_LOW 0x40000000 -#define ESP32_S3_IROM_MASK_HIGH 0x40060000 -#define ESP32_S3_DRAM_LOW 0x3FC88000 -#define ESP32_S3_DRAM_HIGH 0x3FD00000 -#define ESP32_S3_RTC_IRAM_LOW 0x600FE000 -#define ESP32_S3_RTC_IRAM_HIGH 0x60100000 -#define ESP32_S3_RTC_DRAM_LOW 0x600FE000 -#define ESP32_S3_RTC_DRAM_HIGH 0x60100000 #define ESP32_S3_RTC_DATA_LOW 0x50000000 #define ESP32_S3_RTC_DATA_HIGH 0x50002000 #define ESP32_S3_EXTRAM_DATA_LOW 0x3D000000 From 1107af09f1179241224ff0045441caaeeec70b13 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 12:59:19 +0200 Subject: [PATCH 27/49] tcl/interface: add Espressif builtin usb_jtag config file. This config file enables communication over USB-JTAG with ESP32-C3, ESP32-S3, ESP32-H2 and ESP32-C6 chips Signed-off-by: Erhan Kurubas Change-Id: Iceea26972588d8c4919d1f3248684ece48ca9121 Reviewed-on: https://review.openocd.org/c/openocd/+/7748 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/interface/esp_usb_jtag.cfg | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tcl/interface/esp_usb_jtag.cfg diff --git a/tcl/interface/esp_usb_jtag.cfg b/tcl/interface/esp_usb_jtag.cfg new file mode 100644 index 0000000000..40427d0e3e --- /dev/null +++ b/tcl/interface/esp_usb_jtag.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Espressif builtin USB-JTAG adapter +# + +adapter driver esp_usb_jtag + +espusbjtag vid_pid 0x303a 0x1001 +espusbjtag caps_descriptor 0x2000 From 2c57d11c78108c6547f31ca07f1ff672fa855f10 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 18 Jun 2023 13:05:35 +0200 Subject: [PATCH 28/49] tcl/board: add esp32s3-builtin.cfg file Board config file for ESP32-S3, to allow communication with the builtin USB-JTAG adapter. Signed-off-by: Erhan Kurubas Change-Id: I1310f5db30f7df38fe9344f7ba2334611b53863e Reviewed-on: https://review.openocd.org/c/openocd/+/7749 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/board/esp32s3-builtin.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tcl/board/esp32s3-builtin.cfg diff --git a/tcl/board/esp32s3-builtin.cfg b/tcl/board/esp32s3-builtin.cfg new file mode 100644 index 0000000000..353099c98f --- /dev/null +++ b/tcl/board/esp32s3-builtin.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S3 connected via builtin USB-JTAG adapter. +# +# For example, OpenOCD can be started for ESP32-S3 debugging on +# +# openocd -f board/esp32s3-builtin.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] + +adapter speed 40000 From d57b2448eea7fac0d5ccf8b047adf0a57a557cb5 Mon Sep 17 00:00:00 2001 From: Artemiy Volkov Date: Wed, 5 Jul 2023 15:43:08 +0200 Subject: [PATCH 29/49] target/arc: fix off-by-one error in arc_save_context() While not affecting the function's main purpose, an error has crept into arc_save_context() that results in logging wrong register values when the debug level is 3 or more. For instance, when debugging a trivial program and halting at entry to main, the following values are printed to the log: Debug: 2915 2020 arc.c:894 arc_save_context(): Get core register regnum=0, name=r0, value=0x0000000 ... Debug: 2947 2020 arc.c:894 arc_save_context(): Get core register regnum=60, name=lp_count, value=0x900002d8 Debug: 2948 2020 arc.c:894 arc_save_context(): Get core register regnum=63, name=pcl, value=0xffffffff Debug: 2949 2020 arc.c:909 arc_save_context(): Get aux register regnum=64, name=pc, value=0x900000b4 Debug: 2950 2020 arc.c:909 arc_save_context(): Get aux register regnum=65, name=lp_start, value=0x900000bc Debug: 2951 2020 arc.c:909 arc_save_context(): Get aux register regnum=66, name=lp_end, value=0x00080801 Debug: 2952 2020 arc.c:909 arc_save_context(): Get aux register regnum=67, name=status32, value=0xffffffff After the change, the register contents make much more sense: Debug: 2923 3934 arc.c:889 arc_save_context(): Get core register regnum=0, name=r0, value=0x00000000 ... Debug: 2955 3934 arc.c:889 arc_save_context(): Get core register regnum=60, name=lp_count, value=0x00000000 Debug: 2956 3934 arc.c:889 arc_save_context(): Get core register regnum=63, name=pcl, value=0x900002d8 Debug: 2957 3934 arc.c:903 arc_save_context(): Get aux register regnum=64, name=pc, value=0x900002da Debug: 2958 3934 arc.c:903 arc_save_context(): Get aux register regnum=65, name=lp_start, value=0x900000b4 Debug: 2959 3934 arc.c:903 arc_save_context(): Get aux register regnum=66, name=lp_end, value=0x900000bc Debug: 2960 3934 arc.c:903 arc_save_context(): Get aux register regnum=67, name=status32, value=0x00080801 While at it, simplify a couple of expressions. Change-Id: I8f2d79404707fbac4503af45b393ea73f91e6beb Signed-off-by: Artemiy Volkov Reviewed-on: https://review.openocd.org/c/openocd/+/7765 Tested-by: jenkins Reviewed-by: Evgeniy Didin Reviewed-by: Antonio Borneo --- src/target/arc.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/target/arc.c b/src/target/arc.c index 9ae3ae6104..a8de6f36be 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -846,21 +846,17 @@ static int arc_save_context(struct target *target) memset(aux_addrs, 0xff, aux_regs_size); for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; - if (!reg->valid && reg->exist) { - core_addrs[core_cnt] = arc_reg->arch_num; - core_cnt += 1; - } + if (!reg->valid && reg->exist) + core_addrs[core_cnt++] = arc_reg->arch_num; } for (i = arc->num_core_regs; i < regs_to_scan; i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; - if (!reg->valid && reg->exist) { - aux_addrs[aux_cnt] = arc_reg->arch_num; - aux_cnt += 1; - } + if (!reg->valid && reg->exist) + aux_addrs[aux_cnt++] = arc_reg->arch_num; } /* Read data from target. */ @@ -884,30 +880,30 @@ static int arc_save_context(struct target *target) /* Parse core regs */ core_cnt = 0; for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, core_values[core_cnt]); - core_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, core_values[core_cnt]); + core_cnt++; } } /* Parse aux regs */ aux_cnt = 0; for (i = arc->num_core_regs; i < regs_to_scan; i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); - aux_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, aux_values[aux_cnt]); + aux_cnt++; } } From 218f6c0181633057a892a8724c506b10b9f6afaa Mon Sep 17 00:00:00 2001 From: eolson Date: Thu, 22 Jun 2023 13:02:21 -0500 Subject: [PATCH 30/49] target/riscv: Add null pointer check before right shift for bscan tunneling. Change-Id: I5d4764c777f33d48705b3e5273eb840c13cfbfb7 Signed-off-by: eolson Reviewed-on: https://review.openocd.org/c/openocd/+/7814 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Jan Matyas --- src/target/riscv/batch.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 8ec043efb7..d39967e4df 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -115,8 +115,10 @@ int riscv_batch_run(struct riscv_batch *batch) if (bscan_tunnel_ir_width != 0) { /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - for (size_t i = 0; i < batch->used_scans; ++i) - buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1); + for (size_t i = 0; i < batch->used_scans; ++i) { + if ((batch->fields + i)->in_value) + buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1); + } } for (size_t i = 0; i < batch->used_scans; ++i) From 7023deb06a8cac77fe50d341c9e34b80d4fc68fd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 13 Jul 2023 09:38:44 -0700 Subject: [PATCH 31/49] jtag/drivers/xds110: Fix compiler warning. Compiler would complain that `written` was used without being initialized. Simplify the code a little. The number of bytes written is already checked in usb_write(). Signed-off-by: Tim Newsome Change-Id: Ibada85dcccfca6f1269c584cdbc4f2e3b93bb8f3 Reviewed-on: https://review.openocd.org/c/openocd/+/7813 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo Reviewed-by: Jan Matyas --- src/jtag/drivers/xds110.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 371dc88034..717295c73c 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -579,9 +579,6 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) static bool usb_send_command(uint16_t size) { - int written; - bool success = true; - /* Check the packet length */ if (size > USB_PAYLOAD_SIZE) return false; @@ -596,13 +593,7 @@ static bool usb_send_command(uint16_t size) size += 3; /* Send the data via the USB connection */ - success = usb_write(xds110.write_packet, (int)size, &written); - - /* Check if the correct number of bytes was written */ - if (written != (int)size) - success = false; - - return success; + return usb_write(xds110.write_packet, (int)size, NULL); } /*************************************************************************** From a5108240f9e12633fea400f92d96cc75e03c86ca Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 20 Jul 2023 14:52:54 +0200 Subject: [PATCH 32/49] target: fix messages and return values of failed op because not halted Lot of messages was logged as LOG_WARNING, but the operation failed immediately. Sometimes no error message was logged at all. Add missing messages, change warnings to errors. Sometimes ERROR_TARGET_INVALID was returned. Some command handlers returned ERROR_OK! Always return ERROR_TARGET_NOT_HALTED. While on it use LOG_TARGET_ERROR() whenever possible. Prefix command_print() message with 'Error:' to get closer to LOG_TARGET_ERROR() variant. Error message was not added to get() and set() methods of struct xxx_reg_type - the return value is properly checked and a message is logged by the caller in case of ERROR_TARGET_NOT_HALTED. Signed-off-by: Tomas Vanek Change-Id: I2fe4187c6025f0038956ab387edbf3f461c69398 Reviewed-on: https://review.openocd.org/c/openocd/+/7819 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 18 ++++++++------ src/target/arc.c | 12 ++++----- src/target/arc_mem.c | 2 +- src/target/arm11.c | 8 +++--- src/target/arm720t.c | 4 +-- src/target/arm7_9_common.c | 20 +++++++-------- src/target/arm920t.c | 8 +++--- src/target/arm926ejs.c | 4 +-- src/target/arm946e.c | 4 +-- src/target/arm966e.c | 4 +-- src/target/armv4_5.c | 16 ++++++------ src/target/armv4_5_mmu.c | 8 ++++-- src/target/armv7a_cache.c | 4 +-- src/target/armv7m.c | 2 +- src/target/armv8.c | 2 +- src/target/avr32_ap7k.c | 6 ++--- src/target/cortex_a.c | 10 ++++---- src/target/cortex_m.c | 10 ++++---- src/target/dsp563xx.c | 6 ++--- src/target/esirisc.c | 8 ++++-- src/target/hla_target.c | 4 +-- src/target/mips32.c | 6 ++--- src/target/mips_mips64.c | 12 ++++----- src/target/openrisc/or1k.c | 6 ++--- src/target/riscv/riscv.c | 2 +- src/target/stm8.c | 8 +++--- src/target/target.c | 22 ++++++++--------- src/target/xscale.c | 50 +++++++++++++++++++------------------- src/target/xtensa/xtensa.c | 10 ++++---- 29 files changed, 145 insertions(+), 131 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 5a16b3a3bf..5d8a65273f 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -846,8 +846,10 @@ static int aarch64_resume(struct target *target, int current, struct armv8_common *armv8 = target_to_armv8(target); armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* * If this target is part of a SMP group, prepare the others @@ -1095,7 +1097,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2135,7 +2137,7 @@ static int aarch64_write_cpu_memory(struct target *target, uint32_t dscr; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2353,7 +2355,7 @@ static int aarch64_read_cpu_memory(struct target *target, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2790,8 +2792,8 @@ static int aarch64_mmu(struct target *target, int *enabled) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } if (armv8->is_armv8r) *enabled = 0; @@ -3010,8 +3012,10 @@ COMMAND_HANDLER(aarch64_mcrmrc_command) return ERROR_FAIL; } - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; + } if (arm->core_state == ARM_STATE_AARCH64) { command_print(CMD, "%s: not 32-bit arm target", target_name(target)); diff --git a/src/target/arc.c b/src/target/arc.c index a8de6f36be..2ca6be16d2 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1258,7 +1258,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, CHECK_RETVAL(arc_reset_caches_states(target)); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1671,7 +1671,7 @@ static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoi return arc_set_breakpoint(target, breakpoint); } else { - LOG_WARNING(" > core was not halted, please try again."); + LOG_TARGET_ERROR(target, "not halted (add breakpoint)"); return ERROR_TARGET_NOT_HALTED; } } @@ -1683,7 +1683,7 @@ static int arc_remove_breakpoint(struct target *target, if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (remove breakpoint)"); return ERROR_TARGET_NOT_HALTED; } @@ -1905,7 +1905,7 @@ static int arc_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1918,7 +1918,7 @@ static int arc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2006,7 +2006,7 @@ static int arc_step(struct target *target, int current, target_addr_t address, struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c index c4814d2777..3264b663b6 100644 --- a/src/target/arc_mem.c +++ b/src/target/arc_mem.c @@ -162,7 +162,7 @@ int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arm11.c b/src/target/arm11.c index e48bcf30b0..50aaa86f12 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -449,7 +449,7 @@ static int arm11_resume(struct target *target, int current, if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -551,7 +551,7 @@ static int arm11_step(struct target *target, int current, target_state_name(target)); if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -798,7 +798,7 @@ static int arm11_read_memory_inner(struct target *target, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -896,7 +896,7 @@ static int arm11_write_memory_inner(struct target *target, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arm720t.c b/src/target/arm720t.c index c330dfff9f..beab632c25 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -241,8 +241,8 @@ static int arm720t_arch_state(struct target *target) static int arm720_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index f60777dbeb..bbdbc4981c 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -184,7 +184,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break breakpoint->type); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -455,7 +455,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch mask = watchpoint->length - 1; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -524,7 +524,7 @@ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *wat struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1259,7 +1259,7 @@ static int arm7_9_debug_entry(struct target *target) return retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1390,7 +1390,7 @@ static int arm7_9_full_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1506,7 +1506,7 @@ static int arm7_9_restore_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1709,7 +1709,7 @@ int arm7_9_resume(struct target *target, LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1907,7 +1907,7 @@ int arm7_9_step(struct target *target, int current, target_addr_t address, int h int err, retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2118,7 +2118,7 @@ int arm7_9_read_memory(struct target *target, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2291,7 +2291,7 @@ int arm7_9_write_memory(struct target *target, #endif if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arm920t.c b/src/target/arm920t.c index f4c3f42507..53b4d9d15f 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -533,8 +533,8 @@ int arm920t_arch_state(struct target *target) static int arm920_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = target_to_arm920(target)->armv4_5_mmu.mmu_enabled; @@ -1455,9 +1455,9 @@ COMMAND_HANDLER(arm920t_handle_cp15_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for " + command_print(CMD, "Error: target must be stopped for " "\"%s\" command", CMD_NAME); - return ERROR_OK; + return ERROR_TARGET_NOT_HALTED; } /* one argument, read a register. diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index 807d21175d..add90c9978 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -754,8 +754,8 @@ static int arm926ejs_mmu(struct target *target, int *enabled) struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; return ERROR_OK; diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 06dab4e977..03f7e443fb 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -574,7 +574,7 @@ COMMAND_HANDLER(arm946e_handle_cp15) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } @@ -624,7 +624,7 @@ COMMAND_HANDLER(arm946e_handle_idcache) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 3e60172036..8598d29d9b 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -174,8 +174,8 @@ COMMAND_HANDLER(arm966e_handle_cp15_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } /* one or more argument, access a single register (write if second argument is given */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index f35d67a57e..8e3f22417d 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -578,7 +578,7 @@ static int armv4_5_get_core_reg(struct reg *reg) struct target *target = reg_arch_info->target; if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -600,7 +600,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -817,8 +817,8 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (target->state != TARGET_HALTED) { - command_print(CMD, "error: target must be halted for register accesses"); - return ERROR_FAIL; + command_print(CMD, "Error: target must be halted for register accesses"); + return ERROR_TARGET_NOT_HALTED; } if (arm->core_type != ARM_CORE_TYPE_STD) { @@ -833,7 +833,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (!arm->full_context) { - command_print(CMD, "error: target doesn't support %s", + command_print(CMD, "Error: target doesn't support %s", CMD_NAME); return ERROR_FAIL; } @@ -1018,8 +1018,10 @@ COMMAND_HANDLER(handle_armv4_5_mcrmrc) return ERROR_FAIL; } - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; + } int cpnum; uint32_t op1; @@ -1307,7 +1309,7 @@ int armv4_5_run_algorithm_inner(struct target *target, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/armv4_5_mmu.c b/src/target/armv4_5_mmu.c index 9942f49e4d..0c09cb4ca7 100644 --- a/src/target/armv4_5_mmu.c +++ b/src/target/armv4_5_mmu.c @@ -107,8 +107,10 @@ int armv4_5_mmu_read_physical(struct target *target, { int retval; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); @@ -135,8 +137,10 @@ int armv4_5_mmu_write_physical(struct target *target, { int retval; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 995a85611d..e1f0dfafb0 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -22,7 +22,7 @@ static int armv7a_l1_d_cache_sanity_check(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -40,7 +40,7 @@ static int armv7a_l1_i_cache_sanity_check(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 8c9ff902e5..d508af7bf0 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -525,7 +525,7 @@ int armv7m_start_algorithm(struct target *target, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (start target algo)"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/armv8.c b/src/target/armv8.c index e647c3b4cb..d197477ace 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -964,7 +964,7 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, }; if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s not halted", target_name(target)); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index bf1445bf38..bbbf236592 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -309,7 +309,7 @@ static int avr32_ap7k_resume(struct target *target, int current, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -431,7 +431,7 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -471,7 +471,7 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index d9688be13b..abfd6ac5f1 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1147,7 +1147,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2225,7 +2225,7 @@ static int cortex_a_write_cpu_memory(struct target *target, LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2542,7 +2542,7 @@ static int cortex_a_read_cpu_memory(struct target *target, LOG_DEBUG("Reading CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -3183,8 +3183,8 @@ static int cortex_a_mmu(struct target *target, int *enabled) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } if (armv7a->is_armv7r) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ebc3bac999..9541caa792 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1214,7 +1214,7 @@ static int cortex_m_restore_one(struct target *target, bool current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_TARGET_ERROR(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1391,7 +1391,7 @@ static int cortex_m_step(struct target *target, int current, bool isr_timed_out = false; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2092,7 +2092,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2948,8 +2948,8 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC > 0) { diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 8ea2cb6132..5789201547 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -1296,7 +1296,7 @@ static int dsp563xx_step(struct target *target, struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1381,7 +1381,7 @@ static int dsp563xx_run_algorithm(struct target *target, struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } @@ -1705,7 +1705,7 @@ static int dsp563xx_write_memory_core(struct target *target, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/esirisc.c b/src/target/esirisc.c index f86d28d583..561edb255a 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -318,8 +318,10 @@ static int esirisc_flush_caches(struct target *target) LOG_DEBUG("-"); - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } int retval = esirisc_jtag_flush_caches(jtag_info); if (retval != ERROR_OK) { @@ -855,8 +857,10 @@ static int esirisc_resume_or_step(struct target *target, int current, target_add LOG_DEBUG("-"); - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } if (!debug_execution) { target_free_all_working_areas(target); diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 8c35a90cb2..c1bda996ce 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -449,7 +449,7 @@ static int adapter_resume(struct target *target, int current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -538,7 +538,7 @@ static int adapter_step(struct target *target, int current, LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/mips32.c b/src/target/mips32.c index 1a34f737e4..ce16a7b5d6 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -438,7 +438,7 @@ int mips32_run_algorithm(struct target *target, int num_mem_params, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } @@ -921,8 +921,8 @@ COMMAND_HANDLER(mips32_handle_cp0_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } /* two or more argument, access a single register/select (write if third argument is given) */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 640b4c8386..bf6095358f 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -606,7 +606,7 @@ static int mips_mips64_resume(struct target *target, int current, address = mips64_extend_sign(address); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted %d", target->state); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -706,7 +706,7 @@ static int mips_mips64_step(struct target *target, int current, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -804,7 +804,7 @@ static int mips_mips64_remove_breakpoint(struct target *target, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -865,7 +865,7 @@ static int mips_mips64_remove_watchpoint(struct target *target, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -886,7 +886,7 @@ static int mips_mips64_read_memory(struct target *target, uint64_t address, void *t; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted %d", target->state); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1014,7 +1014,7 @@ static int mips_mips64_write_memory(struct target *target, uint64_t address, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index d73bca2109..8c38610805 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -789,7 +789,7 @@ static int or1k_resume_or_step(struct target *target, int current, address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no"); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1026,7 +1026,7 @@ static int or1k_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1053,7 +1053,7 @@ static int or1k_write_memory(struct target *target, target_addr_t address, LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 48391786dc..cb8d04f201 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1840,7 +1840,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/stm8.c b/src/target/stm8.c index 91a59d79cf..ad4a452981 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -994,7 +994,7 @@ static int stm8_resume(struct target *target, int current, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1303,7 +1303,7 @@ static int stm8_step(struct target *target, int current, struct breakpoint *breakpoint = NULL; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1518,7 +1518,7 @@ static int stm8_remove_breakpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1654,7 +1654,7 @@ static int stm8_remove_watchpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/target.c b/src/target/target.c index 5858aa573b..89eaa23d84 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1325,7 +1325,7 @@ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { - LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -1335,7 +1335,7 @@ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add context breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -1345,7 +1345,7 @@ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add hybrid breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -1361,7 +1361,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add watchpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -1375,7 +1375,7 @@ int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (hit watchpoint)"); return ERROR_TARGET_NOT_HALTED; } @@ -1457,7 +1457,7 @@ int target_step(struct target *target, int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (gdb fileio)"); return ERROR_TARGET_NOT_HALTED; } return target->type->get_gdb_fileio_info(target, fileio_info); @@ -1466,7 +1466,7 @@ int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fi int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (gdb fileio end)"); return ERROR_TARGET_NOT_HALTED; } return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); @@ -6666,8 +6666,8 @@ COMMAND_HANDLER(handle_ps_command) struct target *target = get_current_target(CMD_CTX); char *display; if (target->state != TARGET_HALTED) { - LOG_INFO("target not halted !!"); - return ERROR_OK; + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; } if ((target->rtos) && (target->rtos->type) @@ -6698,8 +6698,8 @@ COMMAND_HANDLER(handle_test_mem_access_command) int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_INFO("target not halted !!"); - return ERROR_FAIL; + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC != 1) diff --git a/src/target/xscale.c b/src/target/xscale.c index 066ff8c918..03aa5166ba 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1118,7 +1118,7 @@ static int xscale_resume(struct target *target, int current, LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1382,7 +1382,7 @@ static int xscale_step(struct target *target, int current, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1632,7 +1632,7 @@ static int xscale_full_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1705,7 +1705,7 @@ static int xscale_restore_banked(struct target *target) int i, j; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1781,7 +1781,7 @@ static int xscale_read_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1880,7 +1880,7 @@ static int xscale_write_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2073,7 +2073,7 @@ static int xscale_set_breakpoint(struct target *target, struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2163,7 +2163,7 @@ static int xscale_unset_breakpoint(struct target *target, struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2210,7 +2210,7 @@ static int xscale_remove_breakpoint(struct target *target, struct breakpoint *br struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2232,7 +2232,7 @@ static int xscale_set_watchpoint(struct target *target, uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2336,7 +2336,7 @@ static int xscale_unset_watchpoint(struct target *target, uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2369,7 +2369,7 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2490,7 +2490,7 @@ static int xscale_read_trace(struct target *target) unsigned int num_checkpoints = 0; if (target->state != TARGET_HALTED) { - LOG_WARNING("target must be stopped to read trace data"); + LOG_TARGET_ERROR(target, "must be stopped to read trace data"); return ERROR_TARGET_NOT_HALTED; } @@ -3131,8 +3131,8 @@ static int xscale_mmu(struct target *target, int *enabled) struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = xscale->armv4_5_mmu.mmu_enabled; return ERROR_OK; @@ -3149,8 +3149,8 @@ COMMAND_HANDLER(xscale_handle_mmu_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC >= 1) { @@ -3179,8 +3179,8 @@ COMMAND_HANDLER(xscale_handle_idcache_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } bool icache = false; @@ -3347,8 +3347,8 @@ COMMAND_HANDLER(xscale_handle_trace_buffer_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC >= 1) { @@ -3451,8 +3451,8 @@ COMMAND_HANDLER(xscale_handle_dump_trace_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC < 1) @@ -3514,8 +3514,8 @@ COMMAND_HANDLER(xscale_handle_cp15) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } uint32_t reg_no = 0; struct reg *reg = NULL; diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 431c36a249..431be894b9 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -1541,7 +1541,7 @@ int xtensa_prepare_resume(struct target *target, debug_execution); if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } xtensa->halt_request = false; @@ -1667,7 +1667,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in current, address, handle_breakpoints); if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1941,7 +1941,7 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si bool bswap = xtensa->target->endianness == TARGET_BIG_ENDIAN; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2037,7 +2037,7 @@ int xtensa_write_memory(struct target *target, bool fill_head_tail = false; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2566,7 +2566,7 @@ int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint) xtensa_reg_val_t dbreakcval; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } From bab8b8c9eb7c0e892eaa375cb1f388a75165c627 Mon Sep 17 00:00:00 2001 From: Marek Vrbka Date: Tue, 6 Jun 2023 15:32:09 +0200 Subject: [PATCH 33/49] register: refactor register_cache_invalidate() register_cache_invalidate() is written a way which uses pointer arithmetic, which makes it harder to read. This patch replaces it with more readable way to iterate over array of structs. Change-Id: Ia420f70a3bb6998c690c8c600c71301dca9f9dbf Signed-off-by: Marek Vrbka Reviewed-on: https://review.openocd.org/c/openocd/+/7735 Reviewed-by: Tomas Vanek Tested-by: jenkins Reviewed-by: Jan Matyas --- src/target/register.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/target/register.c b/src/target/register.c index 2287125863..e4f22f8e93 100644 --- a/src/target/register.c +++ b/src/target/register.c @@ -93,9 +93,8 @@ void register_unlink_cache(struct reg_cache **cache_p, const struct reg_cache *c /** Marks the contents of the register cache as invalid (and clean). */ void register_cache_invalidate(struct reg_cache *cache) { - struct reg *reg = cache->reg_list; - - for (unsigned int n = cache->num_regs; n != 0; n--, reg++) { + for (unsigned int n = 0; n < cache->num_regs; n++) { + struct reg *reg = &cache->reg_list[n]; if (!reg->exist) continue; reg->valid = false; From a64928c4e7dd36c57e4a137f93a49522c28f547a Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 24 Jul 2023 01:43:58 +0200 Subject: [PATCH 34/49] pld/virtex2: allow calling set_instr_codes and set_user_codes before 'init' Change-Id: Ib21366b2fdbf33ee06a958e52b725989114751f4 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7821 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/pld/virtex2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index a97c7c6d68..5a8cf9d96e 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -422,14 +422,14 @@ static const struct command_registration virtex2_exec_command_handlers[] = { .usage = "pld_name", }, { .name = "set_instr_codes", - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .handler = virtex2_handle_set_instuction_codes_command, .help = "set instructions codes used for loading the bitstream/refreshing/jtag-hub", .usage = "pld_name cfg_out cfg_in jprogb jstart jshutdown" " [user1 [user2 [user3 [user4]]]]", }, { .name = "set_user_codes", - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .handler = virtex2_handle_set_user_codes_command, .help = "set instructions codes used for jtag-hub", .usage = "pld_name user1 [user2 [user3 [user4]]]", From 2ca6d25eb561d114d3a37ace0922a738e19fcc79 Mon Sep 17 00:00:00 2001 From: Parshintsev Anatoly Date: Wed, 2 Aug 2023 00:46:32 +0300 Subject: [PATCH 35/49] doc: port "0" requests any available port for usage by OpenOCD server Change-Id: I0d38533748898516dce44e81d0bff6bd35ee4aec Signed-off-by: Parshintsev Anatoly Reviewed-on: https://review.openocd.org/c/openocd/+/7842 Reviewed-by: Jan Matyas Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 12a8ca56df..03c5190ada 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2180,6 +2180,9 @@ In such cases, just specify the relevant port number as "disabled". If you disable all access through TCP/IP, you will need to use the command line @option{-pipe} option. +You can request the operating system to select one of the available +ports for the server by specifying the relevant port number as "0". + @anchor{gdb_port} @deffn {Config Command} {gdb_port} [number] @cindex GDB server From 2cd8ebf44d1afd59b524b09561a8bd2f90f0c27a Mon Sep 17 00:00:00 2001 From: Parshintsev Anatoly Date: Fri, 28 Jul 2023 20:41:32 +0300 Subject: [PATCH 36/49] breakpoints: use 64-bit type for watchpoint mask and value This patch changes data types of watchpoint value and mask to allow for 64-bit values match that some architectures (like RISCV) allow. In addition this patch fixes the behavior of watchpoint command to zero-out mask if only data value is provided. Change-Id: I3c7ec1630f03ea9534ec34c0ebe99e08ea56e7f0 Signed-off-by: Parshintsev Anatoly Reviewed-on: https://review.openocd.org/c/openocd/+/7840 Reviewed-by: Antonio Borneo Reviewed-by: Marek Vrbka Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/gdb_server.c | 2 +- src/target/arm7_9_common.c | 9 +++++---- src/target/arm_dpm.c | 2 +- src/target/armv8_dpm.c | 2 +- src/target/breakpoints.c | 4 ++-- src/target/breakpoints.h | 8 +++++--- src/target/cortex_m.c | 22 ++++++++-------------- src/target/target.c | 17 +++++++++++------ src/target/xscale.c | 2 +- src/target/xtensa/xtensa.c | 2 +- 10 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 702dbef499..4a4ea53dc3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1779,7 +1779,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, case 4: { if (packet[0] == 'Z') { - retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu); + retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK); if (retval == ERROR_NOT_IMPLEMENTED) { /* Send empty reply to report that watchpoints of this type are not supported */ gdb_put_packet(connection, "", 0); diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index bbdbc4981c..ad814e0541 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -451,6 +451,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int rw_mask = 1; uint32_t mask; + const uint32_t wp_data_mask = watchpoint->mask; mask = watchpoint->length - 1; @@ -469,8 +470,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], - watchpoint->mask); - if (watchpoint->mask != 0xffffffffu) + wp_data_mask); + if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], @@ -488,8 +489,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], - watchpoint->mask); - if (watchpoint->mask != 0xffffffffu) + wp_data_mask); + if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index fd6fb263fc..ab9b50e230 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -918,7 +918,7 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, uint32_t control; /* this hardware doesn't support data value matching or masking */ - if (wp->value || wp->mask != ~(uint32_t)0) { + if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index d1eefe5b32..9ba6b5453b 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -1210,7 +1210,7 @@ static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, uint32_t control; /* this hardware doesn't support data value matching or masking */ - if (wp->value || wp->mask != ~(uint32_t)0) { + if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index bbaff4e756..4d268cebb3 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -393,7 +393,7 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) } static int watchpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) + uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; @@ -460,7 +460,7 @@ static int watchpoint_add_internal(struct target *target, target_addr_t address, } int watchpoint_add(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) + uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { if (target->smp) { struct target_list *head; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index a9ae484357..d447515bff 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -36,11 +36,13 @@ struct breakpoint { int linked_brp; }; +#define WATCHPOINT_IGNORE_DATA_VALUE_MASK (~(uint64_t)0) + struct watchpoint { target_addr_t address; uint32_t length; - uint32_t mask; - uint32_t value; + uint64_t mask; + uint64_t value; enum watchpoint_rw rw; bool is_set; unsigned int number; @@ -69,7 +71,7 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, - enum watchpoint_rw rw, uint32_t value, uint32_t mask); + enum watchpoint_rw rw, uint64_t value, uint64_t mask); void watchpoint_remove(struct target *target, target_addr_t address); /* report type and address of just hit watchpoint */ diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 9541caa792..987dc9b245 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2046,8 +2046,14 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* hardware doesn't support data value masking */ - if (watchpoint->mask != ~(uint32_t)0) { + /* REVISIT This DWT may well be able to watch for specific data + * values. Requires comparator #1 to set DATAVMATCH and match + * the data, and another comparator (DATAVADDR0) matching addr. + * + * NOTE: hardware doesn't support data value masking, so we'll need + * to check that mask is zero + */ + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -2068,18 +2074,6 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* Caller doesn't seem to be able to describe watching for data - * values of zero; that flags "no value". - * - * REVISIT This DWT may well be able to watch for specific data - * values. Requires comparator #1 to set DATAVMATCH and match - * the data, and another comparator (DATAVADDR0) matching addr. - */ - if (watchpoint->value) { - LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - cortex_m->dwt_comp_available--; LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); diff --git a/src/target/target.c b/src/target/target.c index 89eaa23d84..96f4ae7d3e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4061,8 +4061,8 @@ COMMAND_HANDLER(handle_wp_command) while (watchpoint) { command_print(CMD, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 - ", r/w/a: %i, value: 0x%8.8" PRIx32 - ", mask: 0x%8.8" PRIx32, + ", r/w/a: %i, value: 0x%8.8" PRIx64 + ", mask: 0x%8.8" PRIx64, watchpoint->address, watchpoint->length, (int)watchpoint->rw, @@ -4076,15 +4076,20 @@ COMMAND_HANDLER(handle_wp_command) enum watchpoint_rw type = WPT_ACCESS; target_addr_t addr = 0; uint32_t length = 0; - uint32_t data_value = 0x0; - uint32_t data_mask = 0xffffffff; + uint64_t data_value = 0x0; + uint64_t data_mask = WATCHPOINT_IGNORE_DATA_VALUE_MASK; + bool mask_specified = false; switch (CMD_ARGC) { case 5: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], data_mask); + mask_specified = true; /* fall through */ case 4: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], data_value); + // if user specified only data value without mask - the mask should be 0 + if (!mask_specified) + data_mask = 0; /* fall through */ case 3: switch (CMD_ARGV[2][0]) { diff --git a/src/target/xscale.c b/src/target/xscale.c index 03aa5166ba..fbf43516d0 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -2296,7 +2296,7 @@ static int xscale_add_watchpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if (watchpoint->value) + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) LOG_WARNING("xscale does not support value, mask arguments; ignoring"); /* check that length is a power of two */ diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 431be894b9..c575b534e0 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -2570,7 +2570,7 @@ int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint) return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->mask != ~(uint32_t)0) { + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_TARGET_ERROR(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } From 51be311f73933d8b51938371a989f1130dec3cfc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 18 Jun 2023 12:22:07 +0200 Subject: [PATCH 37/49] LICENSES: Add the LGPL-2.1 license Add the full text of the LGPL 2.1 license to OpenOCD. It was copied directly from: https://spdx.org/licenses/LGPL-2.1.html#licenseText Add the required tags for reference and tooling. Checkpatch-ignore: FSF_MAILING_ADDRESS Change-Id: I081f2197fb3c60e17cd6e3353d38194c720ee8a3 Signed-off-by: Thomas Gleixner Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7743 Tested-by: jenkins Reviewed-by: ahmed BOUDJELIDA --- LICENSES/preferred/LGPL-2.1 | 503 ++++++++++++++++++++++++++++++++++++ Makefile.am | 1 + 2 files changed, 504 insertions(+) create mode 100644 LICENSES/preferred/LGPL-2.1 diff --git a/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 new file mode 100644 index 0000000000..8738a8d578 --- /dev/null +++ b/LICENSES/preferred/LGPL-2.1 @@ -0,0 +1,503 @@ +Valid-License-Identifier: LGPL-2.1-only +Valid-License-Identifier: LGPL-2.1-or-later +SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU Lesser General Public License (LGPL) version 2.1 only' use: + SPDX-License-Identifier: LGPL-2.1-only + For 'GNU Lesser General Public License (LGPL) version 2.1 or any later + version' use: + SPDX-License-Identifier: LGPL-2.1-or-later +License-Text: + +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software +Foundation and other authors who decide to use it. You can use it too, but +we suggest you first think carefully about whether this license or the +ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you have +the freedom to distribute copies of free software (and charge for this +service if you wish); that you receive source code or can get it if you +want it; that you can change the software and use pieces of it in new free +programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you if +you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link other code with the library, you must provide complete object files to +the recipients, so that they can relink them with the library after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license obtained +for a version of the library must be consistent with the full freedom of +use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for certain +libraries in order to permit linking those libraries into non-free +programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a combined +work, a derivative of the original library. The ordinary General Public +License therefore permits such linking only if the entire combination fits +its criteria of freedom. The Lesser General Public License permits more lax +criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a de-facto +standard. To achieve this, non-free programs must be allowed to use the +library. A more frequent case is that a free library does the same job as +widely used non-free libraries. In this case, there is little to gain by +limiting the free library to free software only, so we use the Lesser +General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, as +well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a +modified version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, whereas the latter must be combined with the +library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of this + Lesser General Public License (also called "this License"). Each + licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, complete source code means all the + source code for all modules it contains, plus any associated interface + definition files, plus the scripts used to control compilation and + installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the notices + that refer to this License and to the absence of any warranty; and + distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, + thus forming a work based on the Library, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, and + can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based on + the Library, the distribution of the whole must be on the terms of this + License, whose permissions for other licensees extend to the entire + whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you accompany it with the + complete corresponding machine-readable source code, which must be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange. + + If distribution of object code is made by offering access to copy from a + designated place, then offering equivalent access to copy the source + code from the same place satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a copy + of the library already present on the user's computer system, rather + than copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the user + installs one, as long as the modified version is interface-compatible + with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + distributed need not include anything that is normally distributed (in + either source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable runs, + unless that component itself accompanies the executable. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, from you + under this License will not have their licenses terminated so long as + such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted + herein. You are not responsible for enforcing compliance by third + parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library by all + those who receive copies directly or indirectly through you, then the + only way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply, and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is implemented + by public license practices. Many people have made generous + contributions to the wide range of software distributed through that + system in reliance on consistent application of that system; it is up + to the author/donor to decide if he or she is willing to distribute + software through any other system and a licensee cannot impose that + choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library under this License may add an + explicit geographical distribution limitation excluding those + countries, so that distribution is permitted only in or among countries + not thus excluded. In such case, this License incorporates the + limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of + the Lesser General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in + detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision will be + guided by the two goals of preserving the free status of all + derivatives of our free software and of promoting the sharing and reuse + of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library 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 Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add +information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/Makefile.am b/Makefile.am index fa92da9127..a4f77adc2d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,6 +67,7 @@ EXTRA_DIST += \ LICENSES/preferred/GFDL-1.2 \ LICENSES/preferred/gfdl-1.2.texi.readme \ LICENSES/preferred/GPL-2.0 \ + LICENSES/preferred/LGPL-2.1 \ LICENSES/preferred/MIT \ LICENSES/stand-alone/GPL-3.0 \ tools/logger.pl \ From 3b78b5c1db68841fdc18ee48b6011f4affff2bfd Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 2 Jul 2023 23:48:42 +0200 Subject: [PATCH 38/49] libusb_helper: split error and returned value The USB control transfer can be executed without any data. The libusb API libusb_control_transfer() can thus be called with zero 'size', thus returning zero byte transferred when succeed. The OpenOCD API jtag_libusb_control_transfer() returns zero either in case of transfer error and in case of libusb_control_transfer() returning zero, making impossible discriminating the two cases. Extend jtag_libusb_control_transfer() with separate return value for error code and explicit parameter's pointer for transferred bytes. Make the transferred pointer optional, as many callers do not properly handle the returned value. Use 'int' type pointer for transferred, instead of the 'uint16_t' that would have matched the type of 'size'. This can simplify the caller's code by using a single 'int transferred' variable shared with other jtag_libusb_bulk_read|write, while keeping possible the comparison int vs uint16_t without cast. This change is inspired from commit d612baacaa3f ("jtag_libusb_bulk_read|write: return error code instead of size") Change-Id: I14d9bff3e845675be03465c307a136e69eebc317 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7756 Tested-by: jenkins Reviewed-by: ahmed BOUDJELIDA --- src/jtag/drivers/esp_usb_jtag.c | 19 +++++---- src/jtag/drivers/ft232r.c | 12 +++--- src/jtag/drivers/kitprog.c | 40 +++++++++---------- src/jtag/drivers/libusb_helper.c | 19 +++++---- src/jtag/drivers/libusb_helper.h | 3 +- src/jtag/drivers/opendous.c | 16 ++++++-- src/jtag/drivers/openjtag.c | 26 ++++++------ .../usb_blaster/ublast2_access_libusb.c | 12 ++++-- 8 files changed, 85 insertions(+), 62 deletions(-) diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index dd96f4b395..2ed0f58fd1 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -506,11 +506,13 @@ static int esp_usb_jtag_init(void) * 1- With the minimum size required to get to know the total length of that struct, * 2- Then exactly the length of that struct. */ uint8_t jtag_caps_desc[JTAG_PROTO_CAPS_DATA_LEN]; - int jtag_caps_read_len = jtag_libusb_control_transfer(priv->usb_device, + int jtag_caps_read_len; + r = jtag_libusb_control_transfer(priv->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, esp_usb_jtag_caps, 0, - (char *)jtag_caps_desc, JTAG_PROTO_CAPS_DATA_LEN, LIBUSB_TIMEOUT_MS); - if (jtag_caps_read_len <= 0) { + (char *)jtag_caps_desc, JTAG_PROTO_CAPS_DATA_LEN, LIBUSB_TIMEOUT_MS, + &jtag_caps_read_len); + if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: could not retrieve jtag_caps descriptor!"); goto out; } @@ -580,7 +582,8 @@ static int esp_usb_jtag_init(void) 0, NULL, 0, - LIBUSB_TIMEOUT_MS); + LIBUSB_TIMEOUT_MS, + NULL); return ERROR_OK; @@ -637,7 +640,7 @@ static int esp_usb_jtag_speed(int divisor) LOG_DEBUG("esp_usb_jtag: setting divisor %d", divisor); jtag_libusb_control_transfer(priv->usb_device, - LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_SETDIV, divisor, 0, NULL, 0, LIBUSB_TIMEOUT_MS); + LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_SETDIV, divisor, 0, NULL, 0, LIBUSB_TIMEOUT_MS, NULL); return ERROR_OK; } @@ -648,8 +651,8 @@ COMMAND_HANDLER(esp_usb_jtag_tdo_cmd) if (!priv->usb_device) return ERROR_FAIL; int r = jtag_libusb_control_transfer(priv->usb_device, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_GETTDO, 0, 0, &tdo, 1, LIBUSB_TIMEOUT_MS); - if (r < 1) + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_GETTDO, 0, 0, &tdo, 1, LIBUSB_TIMEOUT_MS, NULL); + if (r != ERROR_OK) return r; command_print(CMD, "%d", tdo); @@ -685,7 +688,7 @@ COMMAND_HANDLER(esp_usb_jtag_setio_cmd) d |= VEND_JTAG_SETIO_SRST; jtag_libusb_control_transfer(priv->usb_device, - 0x40, VEND_JTAG_SETIO, d, 0, NULL, 0, LIBUSB_TIMEOUT_MS); + 0x40, VEND_JTAG_SETIO, d, 0, NULL, 0, LIBUSB_TIMEOUT_MS, NULL); return ERROR_OK; } diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index 1d73af4e5c..c2ec78ad88 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -235,7 +235,7 @@ static int ft232r_speed(int divisor) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000) != 0) { + SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_DEVICE_ERROR; } @@ -266,7 +266,7 @@ static int ft232r_init(void) /* Reset the device. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_RESET, 0, 0, NULL, 0, 1000) != 0) { + SIO_RESET, 0, 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("unable to reset device"); return ERROR_JTAG_INIT_FAILED; } @@ -275,7 +275,7 @@ static int ft232r_init(void) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, (1<usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM, - protocol, &status, 1, 0); + protocol, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -440,11 +440,11 @@ static int kitprog_get_status(void) /* Try a maximum of three times */ for (int i = 0; (i < 3) && (transferred == 0); i++) { - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_READ, (CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); jtag_sleep(1000); } @@ -466,13 +466,13 @@ static int kitprog_set_unknown(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (0x03 << 8) | 0x04, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -491,13 +491,13 @@ static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM, - (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0); + (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -515,13 +515,13 @@ static int kitprog_reset_target(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -539,13 +539,13 @@ static int kitprog_swd_sync(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -563,13 +563,13 @@ static int kitprog_swd_seq(uint8_t seq_type) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM, - seq_type, &status, 1, 0); + seq_type, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } diff --git a/src/jtag/drivers/libusb_helper.c b/src/jtag/drivers/libusb_helper.c index 4b098b482f..c77fe78c28 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -216,17 +216,22 @@ void jtag_libusb_close(struct libusb_device_handle *dev) int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, char *bytes, - uint16_t size, unsigned int timeout) + uint16_t size, unsigned int timeout, int *transferred) { - int transferred = 0; - - transferred = libusb_control_transfer(dev, request_type, request, value, index, + int retval = libusb_control_transfer(dev, request_type, request, value, index, (unsigned char *)bytes, size, timeout); - if (transferred < 0) - transferred = 0; + if (retval < 0) { + LOG_ERROR("libusb_control_transfer error: %s", libusb_error_name(retval)); + if (transferred) + *transferred = 0; + return jtag_libusb_error(retval); + } - return transferred; + if (transferred) + *transferred = retval; + + return ERROR_OK; } int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 799e3e6a91..75f133519a 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -38,7 +38,8 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], void jtag_libusb_close(struct libusb_device_handle *dev); int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, - uint16_t index, char *bytes, uint16_t size, unsigned int timeout); + uint16_t index, char *bytes, uint16_t size, unsigned int timeout, + int *transferred); int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred); int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index ad980bf238..2e1d648147 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -735,7 +735,7 @@ int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, in /* Write data from out_buffer to USB. */ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) { - int result; + int result, transferred; if (out_length > OPENDOUS_OUT_BUFFER_SIZE) { LOG_ERROR("opendous_jtag_write illegal out_length=%d (max=%d)", out_length, OPENDOUS_OUT_BUFFER_SIZE); @@ -748,7 +748,11 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); + FUNC_WRITE_DATA, 0, 0, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, + &transferred); + /* FIXME: propagate error separately from transferred */ + if (result == ERROR_OK) + result = transferred; } else { jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result); @@ -768,6 +772,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) /* Read data from USB into in_buffer. */ int opendous_usb_read(struct opendous_jtag *opendous_jtag) { + int transferred; + #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB read begin"); #endif @@ -775,7 +781,11 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, - FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); + FUNC_READ_DATA, 0, 0, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, + &transferred); + /* FIXME: propagate error separately from transferred */ + if (result == ERROR_OK) + result = transferred; } else { jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result); diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 12ea463302..fe3a8ff7f9 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -239,10 +239,10 @@ static int openjtag_buf_write_cy7c65215( ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_WRITE, size, 0, - NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("vendor command failed, error %d", ret); - return ERROR_JTAG_DEVICE_ERROR; + NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("vendor command failed"); + return ret; } if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, @@ -306,10 +306,10 @@ static int openjtag_buf_read_cy7c65215( ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_READ, qty, 0, - NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("vendor command failed, error %d", ret); - return ERROR_JTAG_DEVICE_ERROR; + NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("vendor command failed"); + return ret; } if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, @@ -455,8 +455,8 @@ static int openjtag_init_cy7c65215(void) ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_ENABLE, - 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { LOG_ERROR("could not enable JTAG module"); goto err; } @@ -466,7 +466,7 @@ static int openjtag_init_cy7c65215(void) err: if (usbh) jtag_libusb_close(usbh); - return ERROR_JTAG_INIT_FAILED; + return ret; } static int openjtag_init(void) @@ -508,8 +508,8 @@ static int openjtag_quit_cy7c65215(void) ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_DISABLE, - 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) LOG_WARNING("could not disable JTAG module"); jtag_libusb_close(usbh); diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index 7f9781869c..f5e0026a7b 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -103,7 +103,8 @@ static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_de 0, (char *)data_ptr, chunk_size, - 100); + 100, + NULL); bytes_remaining -= chunk_size; addr += chunk_size; @@ -154,7 +155,8 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 0, &value, 1, - 100); + 100, + NULL); /* Download all sections in the image to ULINK */ for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) { @@ -175,7 +177,8 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 0, &value, 1, - 100); + 100, + NULL); error_close_firmware: image_close(&ublast2_firmware_image); @@ -245,7 +248,8 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) 0, buffer, 5, - 100); + 100, + NULL); LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer); From 9c91ce8d24d0789a0f25affb73201c9e0a6b89d8 Mon Sep 17 00:00:00 2001 From: Ahmed BOUDJELIDA Date: Fri, 16 Jun 2023 23:19:05 +0200 Subject: [PATCH 39/49] contrib/firmware: add new adapter ANGIE's firmware/bitstream code This is ANGIE's firmware and bitstream code. The 'Embeded C' code is based on the openULINK project. The hdl bitstream source code is for the spartan-6 FPGA included in ANGIE. Since ANGIE has a different microcontroller (EZ-USB FX2) than openULINK (EZ-USB AN2131), the registers file (reg_ezusb.h) has been changed completely, so are the descriptors, interruptions and the endpoints configuration. Change-Id: I70590c7c58bac6f1939c5ffba57e87d86850664d Signed-off-by: Ahmed BOUDJELIDA Reviewed-on: https://review.openocd.org/c/openocd/+/7701 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/firmware/angie/c/Makefile | 75 ++ contrib/firmware/angie/c/README | 37 + contrib/firmware/angie/c/include/delay.h | 50 ++ contrib/firmware/angie/c/include/fx2macros.h | 31 + contrib/firmware/angie/c/include/io.h | 65 ++ contrib/firmware/angie/c/include/jtag.h | 31 + contrib/firmware/angie/c/include/msgtypes.h | 171 ++++ contrib/firmware/angie/c/include/protocol.h | 20 + contrib/firmware/angie/c/include/reg_ezusb.h | 656 +++++++++++++++ contrib/firmware/angie/c/include/serial.h | 47 ++ contrib/firmware/angie/c/include/usb.h | 273 ++++++ contrib/firmware/angie/c/src/USBJmpTb.a51 | 125 +++ contrib/firmware/angie/c/src/delay.c | 49 ++ contrib/firmware/angie/c/src/gpif.c | 98 +++ contrib/firmware/angie/c/src/jtag.c | 674 +++++++++++++++ contrib/firmware/angie/c/src/main.c | 85 ++ contrib/firmware/angie/c/src/protocol.c | 189 +++++ contrib/firmware/angie/c/src/serial.c | 77 ++ contrib/firmware/angie/c/src/usb.c | 784 ++++++++++++++++++ contrib/firmware/angie/hdl/Makefile | 109 +++ contrib/firmware/angie/hdl/README | 18 + contrib/firmware/angie/hdl/set_env.sh | 14 + .../firmware/angie/hdl/src/angie_openocd.ucf | 35 + .../firmware/angie/hdl/src/angie_openocd.vhd | 66 ++ doc/usb_adapters/angie/584e_424e_angie.txt | 68 ++ 25 files changed, 3847 insertions(+) create mode 100644 contrib/firmware/angie/c/Makefile create mode 100644 contrib/firmware/angie/c/README create mode 100644 contrib/firmware/angie/c/include/delay.h create mode 100644 contrib/firmware/angie/c/include/fx2macros.h create mode 100644 contrib/firmware/angie/c/include/io.h create mode 100644 contrib/firmware/angie/c/include/jtag.h create mode 100644 contrib/firmware/angie/c/include/msgtypes.h create mode 100644 contrib/firmware/angie/c/include/protocol.h create mode 100644 contrib/firmware/angie/c/include/reg_ezusb.h create mode 100644 contrib/firmware/angie/c/include/serial.h create mode 100644 contrib/firmware/angie/c/include/usb.h create mode 100644 contrib/firmware/angie/c/src/USBJmpTb.a51 create mode 100644 contrib/firmware/angie/c/src/delay.c create mode 100644 contrib/firmware/angie/c/src/gpif.c create mode 100644 contrib/firmware/angie/c/src/jtag.c create mode 100644 contrib/firmware/angie/c/src/main.c create mode 100644 contrib/firmware/angie/c/src/protocol.c create mode 100644 contrib/firmware/angie/c/src/serial.c create mode 100644 contrib/firmware/angie/c/src/usb.c create mode 100644 contrib/firmware/angie/hdl/Makefile create mode 100644 contrib/firmware/angie/hdl/README create mode 100644 contrib/firmware/angie/hdl/set_env.sh create mode 100644 contrib/firmware/angie/hdl/src/angie_openocd.ucf create mode 100644 contrib/firmware/angie/hdl/src/angie_openocd.vhd create mode 100644 doc/usb_adapters/angie/584e_424e_angie.txt diff --git a/contrib/firmware/angie/c/Makefile b/contrib/firmware/angie/c/Makefile new file mode 100644 index 0000000000..80e8cbe57b --- /dev/null +++ b/contrib/firmware/angie/c/Makefile @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +#**************************************************************************** +# File : Makefile * +# Contents : Code for NanoXplore USB-JTAG ANGIE adapter hardware. * +# Based on openULINK project by: Martin Schmoelzer. * +# Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * +# * +# * +# ***************************************************************************/ + +# Define the name of tools. +PREFIX = + +# Small Device C Compiler: http://sdcc.sourceforge.net/ +CC = $(PREFIX)sdcc + +# 8051 assembler, part of the SDCC software package. +AS = $(PREFIX)sdas8051 + +# SDCC produces quite messy Intel HEX files. This tool is be used to re-format +# those files. It is not required for the firmware download functionality in +# the OpenOCD driver, but the resulting file is smaller. +PACKIHX = $(PREFIX)packihx + +# GNU binutils size. Used to print the size of the IHX file generated by SDCC. +SIZE = size + +# Source and header directories. +SRC_DIR = src +INCLUDE_DIR = include + +CODE_SIZE = 0x3C00 +XRAM_LOC = 0x3C00 +XRAM_SIZE = 0x0400 + +CFLAGS = --std-sdcc99 --opt-code-size --model-small +LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \ + --xram-size $(XRAM_SIZE) --iram-size 256 --model-small + +# list of base object files +OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel serial.rel gpif.rel +HEADERS = $(INCLUDE_DIR)/usb.h \ + $(INCLUDE_DIR)/protocol.h \ + $(INCLUDE_DIR)/jtag.h \ + $(INCLUDE_DIR)/delay.h \ + $(INCLUDE_DIR)/reg_ezusb.h \ + $(INCLUDE_DIR)/io.h \ + $(INCLUDE_DIR)/serial.h \ + $(INCLUDE_DIR)/fx2macros.h \ + $(INCLUDE_DIR)/msgtypes.h + +# Disable all built-in rules. +.SUFFIXES: + +# Targets which are executed even when identically named file is present. +.PHONY: all, clean + +all: angie_firmware.ihx + $(SIZE) angie_firmware.ihx + +angie_firmware.ihx: $(OBJECTS) + $(CC) -mmcs51 $(LDFLAGS) -o $@ $^ + +# Rebuild every C module (there are only 5 of them) if any header changes. +%.rel: $(SRC_DIR)/%.c $(HEADERS) + $(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $< + +%.rel: $(SRC_DIR)/%.a51 + $(AS) -lsgo $@ $< + +clean: + rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lk *.map *.mem + +bin: angie_firmware.ihx + makebin -p angie_firmware.ihx angie_firmware.bin diff --git a/contrib/firmware/angie/c/README b/contrib/firmware/angie/c/README new file mode 100644 index 0000000000..04ed0be2ac --- /dev/null +++ b/contrib/firmware/angie/c/README @@ -0,0 +1,37 @@ +#SPDX-License-Identifier: GPL-2.0-or-later + +This is the ANGIE firmware for ANGIE USB-JTAG adapter. + +The main components of ANGIE adapter are: +- Cypress EZ-USB FX2 microcontroller +- Spartan-6 FPGA +- SRAM memory chip +- Pin headers for various JTAG pin assignments + +To compile the firmware, the SDCC compiler package is required. Most Linux +distributions include SDCC in their official package repositories. The SDCC +source code can be found at http://sdcc.sourceforge.net/ + +Simply type "make hex" in the ANGIE directory to compile the firmware. +"make clean" will remove all generated files except the Intel HEX file +required for downloading the firmware to ANGIE. + +Note that the EZ-USB FX2 microcontroller does not have on-chip flash, +ANGIE include on-board EEPROM memory to store the firmware program of +the FX2, but we are not going to use this method. + +Instead, upon initial connection of the ANGIE adapter to the host PC +via USB, the EZ-USB FX2 core has enough intelligence to act as a +stand-alone USB device, responding to USB control requests and allowing +firmware download via a special VENDOR-type control request. Then, the +EZ-USB microcontroller simulates a disconnect and re-connect to the USB bus. +It may take up to two seconds for the host to recognize the newly connected +device before OpenOCD can proceed to execute JTAG commands. This delay is +only visible when OpenOCD first uses a blank (unconfigured) ANGIE device. + +Once the firmware downloaded, the FX2 microcontroller activate its GPIF mode, +download the Spartan-6 FPGA's bitstream, program the FPGA rapidly, and switch +back to default io mode. + +Once the user disconnects the ANGIE adapter, all its memory contents are lost +and the firmware & bitstream download process has to be executed again. diff --git a/contrib/firmware/angie/c/include/delay.h b/contrib/firmware/angie/c/include/delay.h new file mode 100644 index 0000000000..0397941fe8 --- /dev/null +++ b/contrib/firmware/angie/c/include/delay.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************** + File : delay.h * + Contents : Delays handling header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************/ + +#ifndef __DELAY_H +#define __DELAY_H + +#include + +void syncdelay(uint8_t count); +void delay_5us(void); +void delay_1ms(void); +void delay_us(uint16_t delay); +void delay_ms(uint16_t delay); + +#ifndef _IFREQ +#define _IFREQ 48000 /* IFCLK frequency in kHz */ +#endif + +/* CFREQ can be any one of: 48000, 24000, or 12000 */ +#ifndef _CFREQ +#define _CFREQ 48000 /* CLKOUT frequency in kHz */ +#endif + +#if (_IFREQ < 5000) +#error "_IFREQ too small! Valid Range: 5000 to 48000..." +#endif + +#if (_IFREQ > 48000) +#error "_IFREQ too large! Valid Range: 5000 to 48000..." +#endif + +#if (_CFREQ != 48000) +#if (_CFREQ != 24000) +#if (_CFREQ != 12000) +#error "_CFREQ invalid! Valid values: 48000, 24000, 12000..." +#endif +#endif +#endif + +/* Synchronization Delay formula: see TRM section 15-14 */ +#define _SCYCL (3 * (_CFREQ) + 5 * (_IFREQ) - 1) / (2 * (_IFREQ)) +#endif diff --git a/contrib/firmware/angie/c/include/fx2macros.h b/contrib/firmware/angie/c/include/fx2macros.h new file mode 100644 index 0000000000..9067b56193 --- /dev/null +++ b/contrib/firmware/angie/c/include/fx2macros.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. +*/ + +/*! \file + * Macros for simple common tasks in fx2 firmware. + * */ + +#ifndef FX2MACROS_H +#define FX2MACROS_H + +#include "reg_ezusb.h" + +typedef enum {FALSE = 0, TRUE} BOOL_VALS; + +/** + * \brief Used for getting and setting the CPU clock speed. + **/ +typedef enum {CLK_12M = 0, CLK_24M, CLK_48M} CLK_SPD; + +/** + * \brief Evaluates to a CLK_SPD enum. + **/ +#define CPUFREQ (CLK_SPD)((CPUCS & bmclkspd) >> 3) + +#endif diff --git a/contrib/firmware/angie/c/include/io.h b/contrib/firmware/angie/c/include/io.h new file mode 100644 index 0000000000..35afa626f7 --- /dev/null +++ b/contrib/firmware/angie/c/include/io.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : io.h * + Contents : input/output declaration header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __IO_H +#define __IO_H + +#include "reg_ezusb.h" + +/*************************************************************************** + * JTAG Signals: * + *************************************************************************** + * TMS ....... Test Mode Select * + * TCK ....... Test Clock * + * TDI ....... Test Data Input (from device point of view, not JTAG * + * adapter point of view!) * + * TDO ....... Test Data Output (from device point of view, not JTAG * + * adapter point of view!) * + * TRST ...... Test Reset: Used to reset the TAP Finite State Machine * + * into the Test Logic Reset state * + * SRST ..... Chip Reset * + ***************************************************************************/ + +/* PORT A */ +/* PA0 Not Connected */ +/* PA1 Not Connected */ +#define PIN_RDWR_B IOA2 +#define PIN_CSI_B IOA3 +#define PIN_INIT_B IOA4 +#define PIN_PROGRAM_B IOA5 +/* PA6 Not Connected */ +/* PA7 Not Connected */ + +/* PORT B */ +#define PIN_TRST IOB0 +#define PIN_TMS IOB1 +#define PIN_TCK IOB2 +#define PIN_TDI IOB3 +#define PIN_TDO IOB4 +#define PIN_SRST IOB5 +/* PA6 Not Connected */ +/* PA7 Not Connected */ + +/* JTAG Signals with direction 'OUT' on port B */ +/* PIN_TDI - PIN_TCK - PIN_TMS - PIN_TRST - PIN_SRST */ +#define MASK_PORTB_DIRECTION_OUT (bmbit0 | bmbit1 | bmbit2 | bmbit3 | bmbit5) + +/* PORT C */ // Debug: +#define PIN_T0 IOC0 +#define PIN_T1 IOC1 +#define PIN_T2 IOC2 +#define PIN_T3 IOC3 +#define PIN_T4 IOC4 +/* PC5 Not Connected */ +/* PC6 Not Connected */ +/* PC7 Not Connected */ + +#endif diff --git a/contrib/firmware/angie/c/include/jtag.h b/contrib/firmware/angie/c/include/jtag.h new file mode 100644 index 0000000000..6d5df64805 --- /dev/null +++ b/contrib/firmware/angie/c/include/jtag.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : jtag.h * + Contents : Jtag handling functions header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __JTAG_H +#define __JTAG_H + +#include + +uint16_t jtag_get_signals(void); +void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, + uint8_t scan_io, uint8_t tck, uint8_t tms); +void jtag_clock_tms(uint8_t count, uint8_t sequence); +void jtag_slow_clock_tms(uint8_t count, uint8_t sequence); +void jtag_set_signals(uint8_t low, uint8_t high); +void jtag_clock_tck(uint16_t count); +void jtag_slow_clock_tck(uint16_t count); +void jtag_scan_in(uint8_t out_offset, uint8_t in_offset); +void jtag_scan_out(uint8_t out_offset); +void jtag_scan_io(uint8_t out_offset, uint8_t in_offset); +void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset); +void jtag_slow_scan_out(uint8_t out_offset); +void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset); +#endif diff --git a/contrib/firmware/angie/c/include/msgtypes.h b/contrib/firmware/angie/c/include/msgtypes.h new file mode 100644 index 0000000000..91116904ad --- /dev/null +++ b/contrib/firmware/angie/c/include/msgtypes.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : msgtypes.h * + Contents : Definition of the commands supported by NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +/** + * @file + * Definition of the commands supported by the ANGIE firmware. + * + * Basically, two types of commands can be distinguished: + * - Commands with fixed payload size + * - Commands with variable payload size + * + * SCAN commands (in all variations) carry payloads of variable size, all + * other commands carry payloads of fixed size. + * + * In the case of SCAN commands, the payload size (n) is calculated by + * dividing the scan_size_bits variable by 8, rounding up the result. + * + * Offset zero always contains the command ID. + * + **************************************************************************** + * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + **************************************************************************** + * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * + * * + * OUT: * + * offset 1: tms_count * + * offset 2: tms_sequence * + **************************************************************************** + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * + * * + * OUT: * + * offset 1: low byte of tck_count * + * offset 2: high byte of tck_count * + **************************************************************************** + * CMD_CLOCK_SLEEP_US: * + * * + * OUT: * + * offset 1: low byte of sleep_us * + * offset 2: high byte of sleep_us * + **************************************************************************** + * CMD_CLOCK_SLEEP_MS: * + * * + * OUT: * + * offset 1: low byte of sleep_ms * + * offset 2: high byte of sleep_ms * + **************************************************************************** + * CMD_GET_SIGNALS: * + * * + * IN: * + * offset 0: current state of input signals * + * offset 1: current state of output signals * + **************************************************************************** + * CMD_SET_SIGNALS: * + * * + * OUT: * + * offset 1: signals that should be de-asserted * + * offset 2: signals that should be asserted * + **************************************************************************** + * CMD_CONFIGURE_TCK_FREQ: * + * * + * OUT: * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * + **************************************************************************** + * CMD_SET_LEDS: * + * * + * OUT: * + * offset 1: LED states: * + * Bit 0: turn COM LED on * + * Bit 1: turn RUN LED on * + * Bit 2: turn COM LED off * + * Bit 3: turn RUN LED off * + * Bits 7..4: Reserved * + **************************************************************************** + * CMD_TEST: * + * * + * OUT: * + * offset 1: unused dummy value * + **************************************************************************** + */ + +#ifndef __MSGTYPES_H +#define __MSGTYPES_H + +/* + * Command IDs: + * + * Bits 7..6: Reserved, should always be zero + * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, + * the IDs 0x00..0x1F are commands with variable payload size, + * the IDs 0x20..0x3F are commands with fixed payload size. + */ + +#define CMD_ID_MASK 0x3F + +/* Commands with variable payload size */ +#define CMD_SCAN_IN 0x00 +#define CMD_SLOW_SCAN_IN 0x01 +#define CMD_SCAN_OUT 0x02 +#define CMD_SLOW_SCAN_OUT 0x03 +#define CMD_SCAN_IO 0x04 +#define CMD_SLOW_SCAN_IO 0x05 + +/* Commands with fixed payload size */ +#define CMD_CLOCK_TMS 0x20 +#define CMD_SLOW_CLOCK_TMS 0x21 +#define CMD_CLOCK_TCK 0x22 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A + +/* JTAG signal definition for jtag_get_signals() -- Input signals! */ +#define SIGNAL_TDO 1 + +/* JTAG signal definition for jtag_get_signals() -- Output signals! */ +#define SIGNAL_TDI 8 +#define SIGNAL_TMS 2 +#define SIGNAL_TCK 4 +#define SIGNAL_TRST 1 +#define SIGNAL_SRST 32 + +#endif diff --git a/contrib/firmware/angie/c/include/protocol.h b/contrib/firmware/angie/c/include/protocol.h new file mode 100644 index 0000000000..a12644b27d --- /dev/null +++ b/contrib/firmware/angie/c/include/protocol.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : protocol.h * + Contents : Jtag commands handling protocol header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __PROTOCOL_H +#define __PROTOCOL_H + +#include + +bool execute_command(void); +void command_loop(void); + +#endif diff --git a/contrib/firmware/angie/c/include/reg_ezusb.h b/contrib/firmware/angie/c/include/reg_ezusb.h new file mode 100644 index 0000000000..c22476a1a6 --- /dev/null +++ b/contrib/firmware/angie/c/include/reg_ezusb.h @@ -0,0 +1,656 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : reg_ezusb.h * + Contents : FX2 microcontroller registers file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef REG_EZUSB_H +#define REG_EZUSB_H + +/** + * @file + * All information in this file was taken from the EZ-USB FX2 Technical + * Reference Manual, Cypress Semiconductor, 3901 North First Street + * San Jose, CA 95134 (www.cypress.com). + * + * The EZ-USB Technical Reference Manual is called "EZ-USB FX2 TRM" hereafter. + */ + +/* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */ +#include + +/* Bit vectors */ +#define bmbit0 0x01 +#define bmbit1 0x02 +#define bmbit2 0x04 +#define bmbit3 0x08 +#define bmbit4 0x10 +#define bmbit5 0x20 +#define bmbit6 0x40 +#define bmbit7 0x80 + +/************************************************************************** + ************************ Special Function Registers ********************** + ***************************************************************************/ +SFR(IOA, 0x80); +SBIT(IOA0, 0x80, 0); +SBIT(IOA1, 0x80, 1); +SBIT(IOA2, 0x80, 2); +SBIT(IOA3, 0x80, 3); +SBIT(IOA4, 0x80, 4); +SBIT(IOA5, 0x80, 5); +SBIT(IOA6, 0x80, 6); +SBIT(IOA7, 0x80, 7); + +SFR(SP, 0x81); +SFR(DPL0, 0x82); +SFR(DPH0, 0x83); +SFR(DPL1, 0x84); +SFR(DPL2, 0x85); + +SFR(DPS, 0x86); +#define SEL bmbit0 +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +/* Bit 3 read-only, always reads '0' */ +/* Bit 4 read-only, always reads '0' */ +/* Bit 5 read-only, always reads '0' */ +/* Bit 6 read-only, always reads '0' */ +/* Bit 7 read-only, always reads '0' */ + +SFR(PCON, 0x87); +#define IDLE bmbit0 +#define STOP bmbit1 +#define GF0 bmbit2 +#define GF1 bmbit3 +/* Bit 4 read-only, always reads '1' */ +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 unused */ +#define SMOD0 bmbit7 + +SFR(TCON, 0x88); +SBIT(IT0, 0x88, 0); +SBIT(IE0, 0x88, 1); +SBIT(IT1, 0x88, 2); +SBIT(IE1, 0x88, 3); +SBIT(TR0, 0x88, 4); +SBIT(TF0, 0x88, 5); +SBIT(TR1, 0x88, 6); +SBIT(TF1, 0x88, 7); + +SFR(TMOD, 0x89); +SFR(TL0, 0x8A); +SFR(TL1, 0x8B); +SFR(TH0, 0x8C); +SFR(TH1, 0x8D); + +SFR(CKCON, 0x8E); +#define MD0 bmbit0 +#define MD1 bmbit1 +#define MD2 bmbit2 +#define T0M bmbit3 +#define T1M bmbit4 +#define T2M bmbit5 +/* Bit 6 unused */ +/* Bit 7 unused */ + +SFR(SPC_FNC, 0x8F); +#define BMWRS bmbit0 +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +/* Bit 3 read-only, always reads '0' */ +/* Bit 4 read-only, always reads '0' */ +/* Bit 5 read-only, always reads '0' */ +/* Bit 6 read-only, always reads '0' */ +/* Bit 7 read-only, always reads '0' */ + +SFR(IOB, 0x90); +SBIT(IOB0, 0x90, 0); +SBIT(IOB1, 0x90, 1); +SBIT(IOB2, 0x90, 2); +SBIT(IOB3, 0x90, 3); +SBIT(IOB4, 0x90, 4); +SBIT(IOB5, 0x90, 5); +SBIT(IOB6, 0x90, 6); +SBIT(IOB7, 0x90, 7); + +SFR(EXIF, 0x91); +SBIT(USBINT, 0x91, 4); +SBIT(I2CINT, 0x91, 5); +SBIT(IE4, 0x91, 6); +SBIT(IE5, 0x91, 7); + +SFR(MPAGE, 0x92); +SFR(SCON0, 0x98); +SBIT(RI, 0x98, 0); +SBIT(TI, 0x98, 1); +SBIT(RB8, 0x98, 2); +SBIT(TB8, 0x98, 3); +SBIT(REN, 0x98, 4); +SBIT(SM2, 0x98, 5); +SBIT(SM1, 0x98, 6); +SBIT(SM0, 0x98, 7); + +SFR(SBUF0, 0x99); +SFR(AUTOPTRH1, 0x9A); +SFR(AUTOPTRL1, 0x9B); +SFR(AUTOPTRH2, 0x9D); +SFR(AUTOPTRL2, 0x9E); + +#define AUTOPTR1H AUTOPTRH1 /* for backwards compatibility with examples */ +#define AUTOPTR1L AUTOPTRL1 /* for backwards compatibility with examples */ +#define APTR1H AUTOPTRH1 /* for backwards compatibility with examples */ +#define APTR1L AUTOPTRL1 /* for backwards compatibility with examples */ + +SFR(IOC, 0xA0); +SBIT(IOC0, 0xA0, 0); +SBIT(IOC1, 0xA0, 1); +SBIT(IOC2, 0xA0, 2); +SBIT(IOC3, 0xA0, 3); +SBIT(IOC4, 0xA0, 4); +SBIT(IOC5, 0xA0, 5); +SBIT(IOC6, 0xA0, 6); +SBIT(IOC7, 0xA0, 7); + +SFR(INT2CLR, 0xA1); +SFR(INT4CLR, 0xA2); +SFR(IE, 0xA8); +SBIT(EX0, 0xA8, 0); +SBIT(ET0, 0xA8, 1); +SBIT(EX1, 0xA8, 2); +SBIT(ET1, 0xA8, 3); +SBIT(ES0, 0xA8, 4); +SBIT(ET2, 0xA8, 5); +SBIT(ES1, 0xA8, 6); +SBIT(EA, 0xA8, 7); + +SFR(EP2468STAT, 0xAA); +#define EP8F bmbit7 +#define EP8E bmbit6 +#define EP6F bmbit5 +#define EP6E bmbit4 +#define EP4F bmbit3 +#define EP4E bmbit2 +#define EP2F bmbit1 +#define EP2E bmbit0 + +SFR(EP24FIFOFLGS, 0xAB); +SFR(EP68FIFOFLGS, 0xAC); +SFR(AUTOPTRSETUP, 0xAF); +SFR(IOD, 0xB0); +SBIT(IOD0, 0xB0, 0); +SBIT(IOD1, 0xB0, 1); +SBIT(IOD2, 0xB0, 2); +SBIT(IOD3, 0xB0, 3); +SBIT(IOD4, 0xB0, 4); +SBIT(IOD5, 0xB0, 5); +SBIT(IOD6, 0xB0, 6); +SBIT(IOD7, 0xB0, 7); + +SFR(IOE, 0xB1); +SFR(OEA, 0xB2); +SFR(OEB, 0xB3); +SFR(OEC, 0xB4); +SFR(OED, 0xB5); +SFR(OEE, 0xB6); + +SFR(IP, 0xB8); +SBIT(PX0, 0xB8, 0); +SBIT(PT0, 0xB8, 1); +SBIT(PX1, 0xB8, 2); +SBIT(PT1, 0xB8, 3); +SBIT(PS0, 0xB8, 4); +SBIT(PT2, 0xB8, 5); +SBIT(PS1, 0xB8, 6); +/* Bit 7 read-only, always reads '1' */ + +SFR(EP01STAT, 0xBA); +SFR(GPIFTRIG, 0xBB); +#define BMGPIFDONE bmbit7 +#define BMGPIFREAD bmbit2 +#define GPIF_EP2 0 +#define GPIF_EP4 1 +#define GPIF_EP6 2 +#define GPIF_EP8 3 + +SFR(GPIFSGLDATH, 0xBD); +SFR(GPIFSGLDATLX, 0xBE); +SFR(GPIFSGLDATLNOX, 0xBF); + +SFR(SCON1, 0xC0); +SBIT(RI_1, 0xC0, 0); +SBIT(TI_1, 0xC0, 1); +SBIT(RB8_1, 0xC0, 2); +SBIT(TB8_1, 0xC0, 3); +SBIT(REN_1, 0xC0, 4); +SBIT(SM2_1, 0xC0, 5); +SBIT(SM1_1, 0xC0, 6); +SBIT(SM0_1, 0xC0, 7); + +SFR(SBUF1, 0xC1); +SFR(T2CON, 0xC8); +SBIT(CPRL2, 0xC8, 0); +SBIT(C_T2, 0xC8, 1); +SBIT(TR2, 0xC8, 2); +SBIT(EXEN2, 0xC8, 3); +SBIT(TCLK, 0xC8, 4); +SBIT(RCLK, 0xC8, 5); +SBIT(EXF2, 0xC8, 6); +SBIT(TF2, 0xC8, 7); + +SFR(RCAP2L, 0xCA); +SFR(RCAP2H, 0xCB); +SFR(TL2, 0xCC); +SFR(TH2, 0xCD); +SFR(PSW, 0xD0); +SBIT(P, 0xD0, 0); +SBIT(F1, 0xD0, 1); +SBIT(OV, 0xD0, 2); +SBIT(RS0, 0xD0, 3); +SBIT(RS1, 0xD0, 4); +SBIT(F0, 0xD0, 5); +SBIT(AC, 0xD0, 6); +SBIT(CY, 0xD0, 7); + +SFR(EICON, 0xD8); +/* Bit 0 read-only, always reads '0' */ +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +SBIT(INT6, 0xD8, 3); +SBIT(RESI, 0xD8, 4); +SBIT(ERESI, 0xD8, 5); +/* Bit 6 read-only, always reads '1' */ +SBIT(SMOD1, 0xD8, 7); + +SFR(ACC, 0xE0); +SFR(EIE, 0xE8); +SBIT(EUSB, 0xE8, 0); +SBIT(EI2C, 0xE8, 1); +SBIT(EX4, 0xE8, 2); +SBIT(EX5, 0xE8, 3); +SBIT(EWDI, 0xE8, 4); +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 read-only, always reads '1' */ +/* Bit 7 read-only, always reads '1' */ + +SFR(B, 0xF0); +SFR(EIP, 0xF8); +SBIT(PUSB, 0xF8, 0); +SBIT(PI2C, 0xF8, 1); +SBIT(PX4, 0xF8, 2); +SBIT(PX5, 0xF8, 3); +SBIT(PX6, 0xF8, 4); +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 read-only, always reads '1' */ +/* Bit 7 read-only, always reads '1' */ + +/************************************************************************** + ***************************** XDATA Registers **************************** + ***************************************************************************/ + +SFRX(GPIF_WAVE_DATA, 0xE400); +SFRX(RES_WAVEDATA_END, 0xE480); + +/* General Configuration */ +SFRX(CPUCS, 0xE600); +#define RES8051 bmbit0 +#define CLKOE bmbit1 +#define BMCLKINV bmbit2 +#define bmclkspd0 bmbit3 +#define bmclkspd1 bmbit4 +#define bmclkspd (bmbit4 | bmbit3) +#define BMPRTCSTB bmbit5 + +/* PCON register */ +#define BMSMOD0 bmbit7 + +SFRX(IFCONFIG, 0xE601); +#define BMIFCLKSRC bmbit7 +#define BM3048MHZ bmbit6 +#define BMIFCLKOE bmbit5 +#define BMIFCLKPOL bmbit4 +#define BMASYNC bmbit3 +#define BMGSTATE bmbit2 +#define BMIFCFG1 bmbit1 +#define BMIFCFG0 bmbit0 +#define BMIFCFGMASK (BMIFCFG0 | BMIFCFG1) +#define BMIFGPIF BMIFCFG1 + +SFRX(PINFLAGSAB, 0xE602); +SFRX(PINFLAGSCD, 0xE603); +SFRX(FIFORESET, 0xE604); +#define BMNAKALL bmbit7 + +SFRX(BREAKPT, 0xE605); +#define BMBREAK bmbit3 +#define BMBPPULSE bmbit2 +#define BMBPEN bmbit1 + +SFRX(BPADDRH, 0xE606); +SFRX(BPADDRL, 0xE607); +SFRX(UART230, 0xE608); +SFRX(FIFOPINPOLAR, 0xE609); +SFRX(REVID, 0xE60A); +SFRX(REVCTL, 0xE60B); +#define BMNOAUTOARM bmbit1 +#define BMSKIPCOMMIT bmbit0 + +/* Endpoint Configuration */ +SFRX(EP1OUTCFG, 0xE610); +SFRX(EP1INCFG, 0xE611); +SFRX(EP2CFG, 0xE612); +SFRX(EP4CFG, 0xE613); +SFRX(EP6CFG, 0xE614); +SFRX(EP8CFG, 0xE615); +SFRX(EP2FIFOCFG, 0xE618); +SFRX(EP4FIFOCFG, 0xE619); +SFRX(EP6FIFOCFG, 0xE61A); +SFRX(EP8FIFOCFG, 0xE61B); +#define BMINFM bmbit6 +#define BMOEP bmbit5 +#define BMAUTOOUT bmbit4 +#define BMAUTOIN bmbit3 +#define BMZEROLENIN bmbit2 +#define BMWORDWIDE bmbit0 + +SFRX(EP2AUTOINLENH, 0xE620); +SFRX(EP2AUTOINLENL, 0xE621); +SFRX(EP4AUTOINLENH, 0xE622); +SFRX(EP4AUTOINLENL, 0xE623); +SFRX(EP6AUTOINLENH, 0xE612); +SFRX(EP6AUTOINLENL, 0xE613); +SFRX(EP8AUTOINLENH, 0xE614); +SFRX(EP8AUTOINLENL, 0xE615); +SFRX(EP2FIFOPFH, 0xE630); +SFRX(EP2FIFOPFL, 0xE631); +SFRX(EP4FIFOPFH, 0xE632); +SFRX(EP4FIFOPFL, 0xE633); +SFRX(EP6FIFOPFH, 0xE634); +SFRX(EP6FIFOPFL, 0xE635); +SFRX(EP8FIFOPFH, 0xE636); +SFRX(EP8FIFOPFL, 0xE637); +SFRX(EP2ISOINPKTS, 0xE640); +SFRX(EP4ISOINPKTS, 0xE641); +SFRX(EP6ISOINPKTS, 0xE642); +SFRX(EP8ISOINPKTS, 0xE643); +SFRX(INPKTEND, 0xE648); +SFRX(OUTPKTEND, 0xE649); + +/* Interrupts */ +SFRX(EP2FIFOIE, 0xE650); +SFRX(EP2FIFOIRQ, 0xE651); +SFRX(EP4FIFOIE, 0xE652); +SFRX(EP4FIFOIRQ, 0xE653); +SFRX(EP6FIFOIE, 0xE654); +SFRX(EP6FIFOIRQ, 0xE655); +SFRX(EP8FIFOIE, 0xE656); +SFRX(EP8FIFOIRQ, 0xE657); +SFRX(IBNIE, 0xE658); +SFRX(IBNIRQ, 0xE659); +#define EP0IBN bmbit0 +#define EP1IBN bmbit1 +#define EP2IBN bmbit2 +#define EP4IBN bmbit3 +#define EP6IBN bmbit4 +#define EP8IBN bmbit5 + +SFRX(NAKIE, 0xE65A); +SFRX(NAKIRQ, 0xE65B); +#define EP8PING bmbit7 +#define EP6PING bmbit6 +#define EP4PING bmbit5 +#define EP2PING bmbit4 +#define EP1PING bmbit3 +#define EP0PING bmbit2 +#define IBN bmbit0 + +SFRX(USBIEN, 0xE65C); +SFRX(USBIRQ, 0xE65D); +#define SUDAVI bmbit0 +#define SOFI bmbit1 +#define SUTOKI bmbit2 +#define SUSPI bmbit3 +#define URESI bmbit4 +#define HSGRANT bmbit5 +#define EP0ACK bmbit6 + +SFRX(EPIE, 0xE65E); +SFRX(EPIRQ, 0xE65F); +SFRX(GPIFIE, 0xE660); +SFRX(GPIFIRQ, 0xE661); +SFRX(USBERRIE, 0xE662); +SFRX(USBERRIRQ, 0xE663); +SFRX(ERRCNTLIM, 0xE664); +SFRX(CLRERRCNT, 0xE665); +SFRX(INT2IVEC, 0xE666); +#define I2V0 bmbit2 +#define I2V1 bmbit3 +#define I2V2 bmbit4 +#define I2V3 bmbit5 +#define I2V4 bmbit6 + +SFRX(INT4IVEC, 0xE667); +SFRX(INTSETUP, 0xE668); +#define AV4EN bmbit0 +#define INT4IN bmbit1 +#define AV2EN bmbit3 + +/* Input/Output */ +SFRX(PORTACFG, 0xE670); +#define BMINT0 bmbit0 +#define BMINT1 bmbit1 +#define BMFLAGD bmbit7 + +SFRX(PORTCCFG, 0xE671); +#define BMGPIFA0 bmbit0 +#define BMGPIFA1 bmbit1 +#define BMGPIFA2 bmbit2 +#define BMGPIFA3 bmbit3 +#define BMGPIFA4 bmbit4 +#define BMGPIFA5 bmbit5 +#define BMGPIFA6 bmbit6 +#define BMGPIFA7 bmbit7 + +SFRX(PORTECFG, 0xE672); +#define BMT0OUT bmbit0 +#define BMT1OUT bmbit1 +#define BMT2OUT bmbit2 +#define BMRXD0OUT bmbit3 +#define BMRXD1OUT bmbit4 +#define BMINT6 bmbit5 +#define BMT2EX bmbit6 +#define BMGPIFA8 bmbit7 + +SFRX(I2CS, 0xE678); +#define BMDONE bmbit0 +#define BMACK bmbit1 +#define BMBERR bmbit2 +#define BMID (bmbit4 | bmbit3) +#define BMLASTRD bmbit5 +#define BMSTOP bmbit6 +#define BMSTART bmbit7 + +SFRX(I2DAT, 0xE679); +SFRX(I2CTL, 0xE67A); +#define BMSTOPIE bmbit1 +#define BM400KHZ bmbit0 + +SFRX(XAUTODAT1, 0xE67B); +SFRX(XAUTODAT2, 0xE67C); +#define EXTAUTODAT1 XAUTODAT1 +#define EXTAUTODAT2 XAUTODAT2 + +/* USB Control */ +SFRX(USBCS, 0xE680); +#define SIGRSUME bmbit0 +#define RENUM bmbit1 +#define NOSYNSOF bmbit2 +#define DISCON bmbit3 +#define HSM bmbit7 + +SFRX(SUSPEND, 0xE681); +SFRX(WAKEUPCS, 0xE682); +#define BMWU2 bmbit7 +#define BMWU bmbit6 +#define BMWU2POL bmbit5 +#define BMWUPOL bmbit4 +#define BMDPEN bmbit2 +#define BMWU2EN bmbit1 +#define BMWUEN bmbit0 + +SFRX(TOGCTL, 0xE683); +#define BMTOGCTLEPMASK bmbit3 | bmbit2 | bmbit1 | bmbit0 +#define BMRESETTOGGLE bmbit5 +#define BMSETTOGGLE bmbit6 +#define BMQUERYTOGGLE bmbit7 + +SFRX(USBFRAMEH, 0xE684); +SFRX(USBFRAMEL, 0xE685); +SFRX(MICROFRAME, 0xE686); +SFRX(FNADDR, 0xE687); + +/* Endpoints */ +SFRX(EP0BCH, 0xE68A); +SFRX(EP0BCL, 0xE68B); +SFRX(EP1OUTBC, 0xE68D); +SFRX(EP1INBC, 0xE68F); +SFRX(EP2BCH, 0xE690); +SFRX(EP2BCL, 0xE691); +SFRX(EP4BCH, 0xE694); +SFRX(EP4BCL, 0xE695); +SFRX(EP6BCH, 0xE698); +SFRX(EP6BCL, 0xE699); +SFRX(EP8BCH, 0xE69C); +SFRX(EP8BCL, 0xE69D); +SFRX(EP0CS, 0xE6A0); +#define HSNAK bmbit7 + +SFRX(EP1INCS, 0xE6A2); +SFRX(EP1OUTCS, 0xE6A1); +#define EPSTALL bmbit0 +#define EPBSY bmbit1 + +SFRX(EP2CS, 0xE6A3); +SFRX(EP4CS, 0xE6A4); +SFRX(EP6CS, 0xE6A5); +SFRX(EP8CS, 0xE6A6); +#define BMEPEMPTY bmbit2 +#define BMEPFULL bmbit3 +#define BMNPAK (bmbit6 | bmbit5 | bmbit4) + +SFRX(EP2FIFOFLGS, 0xE6A7); +SFRX(EP4FIFOFLGS, 0xE6A8); +SFRX(EP6FIFOFLGS, 0xE6A9); +SFRX(EP8FIFOFLGS, 0xE6AA); +SFRX(EP2FIFOBCH, 0xE6AB); +SFRX(EP2FIFOBCL, 0xE6AC); +SFRX(EP4FIFOBCH, 0xE6AD); +SFRX(EP4FIFOBCL, 0xE6AE); +SFRX(EP6FIFOBCH, 0xE6AF); +SFRX(EP6FIFOBCL, 0xE6B0); +SFRX(EP8FIFOBCH, 0xE6B1); +SFRX(EP8FIFOBCL, 0xE6B2); +SFRX(SUDPTRH, 0xE6B3); +SFRX(SUDPTRL, 0xE6B4); + +SFRX(SUDPTRCTL, 0xE6B5); +#define BMSDPAUTO bmbit0 + +SFRX(SETUPDAT[8], 0xE6B8); + +/* GPIF */ +SFRX(GPIFWFSELECT, 0xE6C0); +SFRX(GPIFIDLECS, 0xE6C1); +SFRX(GPIFIDLECTL, 0xE6C2); +SFRX(GPIFCTLCFG, 0xE6C3); +SFRX(GPIFADRH, 0xE6C4); +SFRX(GPIFADRL, 0xE6C5); +SFRX(GPIFTCB3, 0xE6CE); +SFRX(GPIFTCB2, 0xE6CF); +SFRX(GPIFTCB1, 0xE6D0); +SFRX(GPIFTCB0, 0xE6D1); + +#define EP2GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP2GPIFTCL GPIFTCB0 +#define EP4GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP4GPIFTCL GPIFTCB0 +#define EP6GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP6GPIFTCL GPIFTCB0 +#define EP8GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP8GPIFTCL GPIFTCB0 + +SFRX(EP2GPIFFLGSEL, 0xE6D2); +SFRX(EP2GPIFPFSTOP, 0xE6D3); +SFRX(EP2GPIFTRIG, 0xE6D4); +SFRX(EP4GPIFFLGSEL, 0xE6DA); +SFRX(EP4GPIFPFSTOP, 0xE6DB); +SFRX(EP4GPIFTRIG, 0xE6DC); +SFRX(EP6GPIFFLGSEL, 0xE6E2); +SFRX(EP6GPIFPFSTOP, 0xE6E3); +SFRX(EP6GPIFTRIG, 0xE6E4); +SFRX(EP8GPIFFLGSEL, 0xE6EA); +SFRX(EP8GPIFPFSTOP, 0xE6EB); +SFRX(EP8GPIFTRIG, 0xE6EC); +SFRX(XGPIFSGLDATH, 0xE6F0); +SFRX(XGPIFSGLDATLX, 0xE6F1); +SFRX(XGPIFSGLDATLNOX, 0xE6F2); +SFRX(GPIFREADYCFG, 0xE6F3); +SFRX(GPIFREADYSTAT, 0xE6F4); +SFRX(GPIFABORT, 0xE6F5); + +// UDMA +SFRX(FLOWSTATE, 0xE6C6); +SFRX(FLOWLOGIC, 0xE6C7); +SFRX(FLOWEQ0CTL, 0xE6C8); +SFRX(FLOWEQ1CTL, 0xE6C9); +SFRX(FLOWHOLDOFF, 0xE6CA); +SFRX(FLOWSTB, 0xE6CB); +SFRX(FLOWSTBEDGE, 0xE6CC); +SFRX(FLOWSTBHPERIOD, 0xE6CD); +SFRX(GPIFHOLDAMOUNT, 0xE60C); +SFRX(UDMACRCH, 0xE67D); +SFRX(UDMACRCL, 0xE67E); +SFRX(UDMACRCQUAL, 0xE67F); + +/* Debug/Test + * The following registers are for Cypress's internal testing purposes only. + * These registers are not documented in the datasheet or the Technical Reference + * Manual as they were not designed for end user application usage + */ +SFRX(DBUG, 0xE6F8); +SFRX(TESTCFG, 0xE6F9); +SFRX(USBTEST, 0xE6FA); +SFRX(CT1, 0xE6FB); +SFRX(CT2, 0xE6FC); +SFRX(CT3, 0xE6FD); +SFRX(CT4, 0xE6FE); + +/* Endpoint Buffers */ +SFRX(EP0BUF[64], 0xE740); +SFRX(EP1INBUF[64], 0xE7C0); +SFRX(EP1OUTBUF[64], 0xE780); +SFRX(EP2FIFOBUF[512], 0xF000); +SFRX(EP4FIFOBUF[512], 0xF400); +SFRX(EP6FIFOBUF[512], 0xF800); +SFRX(EP8FIFOBUF[512], 0xFC00); + +/* Error Correction Code (ECC) Registers (FX2LP/FX1 only) */ +SFRX(ECCCFG, 0xE628); +SFRX(ECCRESET, 0xE629); +SFRX(ECC1B0, 0xE62A); +SFRX(ECC1B1, 0xE62B); +SFRX(ECC1B2, 0xE62C); +SFRX(ECC2B0, 0xE62D); +SFRX(ECC2B1, 0xE62E); +SFRX(ECC2B2, 0xE62F); + +/* Feature Registers (FX2LP/FX1 only) */ +SFRX(GPCR2, 0xE50D); +#define BMFULLSPEEDONLY bmbit4 + +#endif diff --git a/contrib/firmware/angie/c/include/serial.h b/contrib/firmware/angie/c/include/serial.h new file mode 100644 index 0000000000..548c005603 --- /dev/null +++ b/contrib/firmware/angie/c/include/serial.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/** + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. + **/ + +/** \file serial.h + * defines functions to print to a serial console with SIO0 + **/ + +#include "fx2macros.h" +#include +/** + * This function inits sio0 to use T2CON (timer 2) + * See TRM 14.3.4.1 (Table 14-16) + * Certain baud rates have too high an error rate to work. All baud rates are .16% + * except: + * + * 12MHZ 24MHZ + * \li 57600 -6.99% + * \li 38400 -2.34% -2.34% + * \li 19200 -2.34% + * + * Possible Baud rates: + * \li 2400 + * \li 4800 + * \li 9600 + * \li 19200 + * \li 28800 + * \li 38400 + * \li 57600 + * + * Any of these rates should work except 57600 at 12mhz. -2.34% is pushing + * most hardware specs for working. All rates at 48mhz work at .16% + **/ + +void sio0_init(uint32_t baud_rate) __critical; /* baud_rate max should be 57600 since int=2 bytes */ + +/** + * putchar('\\n') or putchar('\\r') both transmit \\r\\n + * Just use one or the other. (This makes terminal echo easy) + **/ +int putchar(char c); +int getchar(void); diff --git a/contrib/firmware/angie/c/include/usb.h b/contrib/firmware/angie/c/include/usb.h new file mode 100644 index 0000000000..0450d1d1c9 --- /dev/null +++ b/contrib/firmware/angie/c/include/usb.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : usb.h * + Contents : usb communication handling header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __USB_H +#define __USB_H + +#include "reg_ezusb.h" +#include +#include + +/* High and Low byte of a word (uint16_t) */ +#define HI8(word) (uint8_t)(((uint16_t)(word) >> 8) & 0xff) +#define LO8(word) (uint8_t)((uint16_t)(word) & 0xff) + +/* Convenience functions */ +#define STALL_EP0() (EP0CS |= EPSTALL) +#define CLEAR_IRQ() (USBINT = 0) + +/*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/ + +/* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */ +#define DESCRIPTOR_TYPE_DEVICE 0x01 +#define DESCRIPTOR_TYPE_CONFIGURATION 0x02 +#define DESCRIPTOR_TYPE_STRING 0x03 +#define DESCRIPTOR_TYPE_INTERFACE 0x04 +#define DESCRIPTOR_TYPE_ENDPOINT 0x05 + +#define STR_DESCR(len, ...) { (len) * 2 + 2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } } + +/** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */ +struct usb_device_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< DEVICE Descriptor Type. */ + uint16_t bcdusb; /**< USB specification release number (BCD). */ + uint8_t bdeviceclass; /**< Class code. */ + uint8_t bdevicesubclass; /**< Subclass code. */ + uint8_t bdeviceprotocol; /**< Protocol code. */ + uint8_t bmaxpacketsize0; /**< Maximum packet size for EP0 (8, 16, 32, 64). */ + uint16_t idvendor; /**< USB Vendor ID. */ + uint16_t idproduct; /**< USB Product ID. */ + uint16_t bcddevice; /**< Device Release Number (BCD). */ + uint8_t imanufacturer; /**< Index of manufacturer string descriptor. */ + uint8_t iproduct; /**< Index of product string descriptor. */ + uint8_t iserialnumber; /**< Index of string descriptor containing serial #. */ + uint8_t bnumconfigurations; /**< Number of possible configurations. */ +}; + +/** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */ +struct usb_config_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< CONFIGURATION descriptor type. */ + uint16_t wtotallength; /**< Combined total length of all descriptors. */ + uint8_t bnuminterfaces; /**< Number of interfaces in this configuration. */ + uint8_t bconfigurationvalue; /**< Value used to select this configuration. */ + uint8_t iconfiguration; /**< Index of configuration string descriptor. */ + uint8_t bmattributes; /**< Configuration characteristics. */ + uint8_t maxpower; /**< Maximum power consumption in 2 mA units. */ +}; + +/** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */ +struct usb_interface_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< INTERFACE descriptor type. */ + uint8_t binterfacenumber; /**< Interface number. */ + uint8_t balternatesetting; /**< Value used to select alternate setting. */ + uint8_t bnumendpoints; /**< Number of endpoints used by this interface. */ + uint8_t binterfaceclass; /**< Class code. */ + uint8_t binterfacesubclass; /**< Subclass code. */ + uint8_t binterfaceprotocol; /**< Protocol code. */ + uint8_t iinterface; /**< Index of interface string descriptor. */ +}; + +/** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */ +struct usb_endpoint_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< ENDPOINT descriptor type. */ + uint8_t bendpointaddress; /**< Endpoint Address: IN/OUT + EP number. */ + uint8_t bmattributes; /**< Endpoint Attributes: BULK/INTR/ISO/CTRL. */ + uint16_t wmaxpacketsize; /**< Maximum packet size for this endpoint. */ + uint8_t binterval; /**< Polling interval (in ms) for this endpoint. */ +}; + +/** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */ +struct usb_language_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< STRING descriptor type. */ + uint16_t wlangid[]; /**< LANGID codes. */ +}; + +/** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */ +struct usb_string_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< STRING descriptor type. */ + uint16_t bstring[]; /**< UNICODE encoded string. */ +}; + +/********************** USB Control Endpoint 0 related *********************/ + +/** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */ +struct setup_data { + uint8_t bmrequesttype; /**< Characteristics of a request. */ + uint8_t brequest; /**< Specific request. */ + uint16_t wvalue; /**< Field that varies according to request. */ + uint16_t windex; /**< Field that varies according to request. */ + uint16_t wlength; /**< Number of bytes to transfer in data stage. */ +}; + +/* External declarations for variables that need to be accessed outside of + * the USB module */ +extern volatile bool ep1_out; +extern volatile bool ep1_in; + +extern volatile __xdata __at 0xE6B8 struct setup_data setup_data; + +/* + * USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2 + * + * Bit 7: Data transfer direction + * 0 = Host-to-device + * 1 = Device-to-host + * Bit 6...5: Type + * 0 = Standard + * 1 = Class + * 2 = Vendor + * 3 = Reserved + * Bit 4...0: Recipient + * 0 = Device + * 1 = Interface + * 2 = Endpoint + * 3 = Other + * 4...31 = Reserved + */ + +#define USB_DIR_OUT 0x00 +#define USB_DIR_IN 0x80 + +#define USB_REQ_TYPE_STANDARD (0x00 << 5) +#define USB_REQ_TYPE_CLASS (0x01 << 5) +#define USB_REQ_TYPE_VENDOR (0x02 << 5) +#define USB_REQ_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* Clear Interface Request */ +#define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Get Configuration Request */ +#define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Get Descriptor Request */ +#define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Get Interface Request */ +#define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) + +/* Get Status Request: See USB 1.1 spec, page 190 */ +#define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Set Address Request is handled by EZ-USB core */ + +/* Set Configuration Request */ +#define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Set Descriptor Request */ +#define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Set Feature Request */ +#define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Set Interface Request */ +#define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) + +/* Synch Frame Request */ +#define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */ +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +/* Value '2' is reserved for future use */ +#define SET_FEATURE 3 +/* Value '4' is reserved for future use */ +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 12 + +/* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */ +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 0 + +/************************** EZ-USB specific stuff **************************/ +/** USB Interrupts. See AN2131-TRM, page 9-4 for details */ +enum usb_isr { + SUDAV_ISR = 13, + SOF_ISR, + SUTOK_ISR, + SUSPEND_ISR, + USBRESET_ISR, + HIGHSPEED_ISR, + EP0ACK_ISR, + STUB_ISR, + EP0IN_ISR, + EP0OUT_ISR, + EP1IN_ISR, + EP1OUT_ISR, + EP2_ISR, + EP4_ISR, + EP6_ISR, + EP8_ISR, + IBN_ISR, + EP0PINGNAK_ISR, + EP1PINGNAK_ISR, + EP2PINGNAK_ISR, + EP4PINGNAK_ISR, + EP6PINGNAK_ISR, + EP8PINGNAK_ISR, + ERRORLIMIT_ISR, + EP2PIDERROR_ISR, + EP4PIDERROR_ISR, + EP6PIDERROR_ISR, + EP8PIDERROR_ISR, + EP2PFLAG_ISR, + EP4PFLAG_ISR, + EP6PFLAG_ISR, + EP8PFLAG_ISR, + EP2EFLAG_ISR, + EP4EFLAG_ISR, + EP6EFLAG_ISR, + EP8EFLAG_ISR, + EP2FFLAG_ISR, + EP4FFLAG_ISR, + EP6FFLAG_ISR, + EP8FFLAG_ISR, + GPIFCOMPLETE_ISR, + GPIFWAVEFORM_ISR +}; + +/*************************** Function Prototypes ***************************/ +__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep); +void usb_reset_data_toggle(uint8_t ep); +bool usb_handle_get_status(void); +bool usb_handle_clear_feature(void); +bool usb_handle_set_feature(void); +bool usb_handle_get_descriptor(void); +void usb_handle_set_interface(void); +void usb_handle_setup_data(void); + +void ep_init(void); +void interrupt_init(void); +void io_init(void); + +#endif diff --git a/contrib/firmware/angie/c/src/USBJmpTb.a51 b/contrib/firmware/angie/c/src/USBJmpTb.a51 new file mode 100644 index 0000000000..13b5f7218b --- /dev/null +++ b/contrib/firmware/angie/c/src/USBJmpTb.a51 @@ -0,0 +1,125 @@ +; SPDX-License-Identifier: GPL-2.0-or-later +;**************************************************************************** +; File : USBJmpTb.a51 * +; Contents : Interruptions vector configuration. * +; Based on openULINK project code by: Martin Schmoelzer. * +; Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * +; * +; * +;**************************************************************************** +.module JUMPTABLE + +.globl USB_AutoVector +.globl USB_Jump_Table + +.globl _sudav_isr, _sof_isr, _sutok_isr, _suspend_isr, _usbreset_isr, _highspeed_isr, _ep0ack_isr, _stub_isr, _ep0in_isr, _ep0out_isr, _ep1in_isr, _ep1out_isr, _ep2_isr, _ep4_isr, _ep6_isr, _ep8_isr, _ibn_isr +.globl _ep0pingnak_isr, _ep1pingnak_isr, _ep2pingnak_isr, _ep4pingnak_isr, _ep6pingnak_isr, _ep8pingnak_isr, _errorlimit_isr, _stub_isr, _stub_isr, _stub_isr, _ep2piderror_isr, _ep4piderror_isr, _ep6piderror_isr, _ep8piderror_isr +.globl _ep2pflag_isr, _ep4pflag_isr, _ep6pflag_isr, _ep8pflag_isr, _ep2eflag_isr, _ep4eflag_isr, _ep6eflag_isr, _ep8eflag_isr, _ep2fflag_isr, _ep4fflag_isr, _ep6fflag_isr, _ep8fflag_isr, _gpifcomplete_isr, _gpifwaveform_isr + +;--------------------------------------------------------------------------; +; Interrupt Vectors ; +;--------------------------------------------------------------------------; +.area USB_JV (ABS,OVR) ; Absolute, Overlay +.org 0x43 ; USB interrupt (INT2) jumps here +USB_AutoVector = #. + 2 + ljmp USB_Jump_Table ; Autovector will replace byte 45 + +;--------------------------------------------------------------------------; +; USB Jump Table ; +;--------------------------------------------------------------------------; +.area USB_JT (ABS) ; Absolute placement +.org 0x0200 ; Place jump table at 0x0200 + +USB_Jump_Table: ; autovector jump table + ljmp _sudav_isr ; (00) Setup Data Available + .db 0 + ljmp _sof_isr ; (04) Start of Frame + .db 0 + ljmp _sutok_isr ; (08) Setup Data Loading + .db 0 + ljmp _suspend_isr ; (0C) Global Suspend + .db 0 + ljmp _usbreset_isr ; (10) USB Reset + .db 0 + ljmp _highspeed_isr ; (14) Entered High Speed + .db 0 + ljmp _ep0ack_isr ; (18) EP0ACK + .db 0 + ljmp _stub_isr ; (1C) Reserved + .db 0 + ljmp _ep0in_isr ; (20) EP0 In + .db 0 + ljmp _ep0out_isr ; (24) EP0 Out + .db 0 + ljmp _ep1in_isr ; (28) EP1 In + .db 0 + ljmp _ep1out_isr ; (2C) EP1 Out + .db 0 + ljmp _ep2_isr ; (30) EP2 In/Out + .db 0 + ljmp _ep4_isr ; (34) EP4 In/Out + .db 0 + ljmp _ep6_isr ; (38) EP6 In/Out + .db 0 + ljmp _ep8_isr ; (3C) EP8 In/Out + .db 0 + ljmp _ibn_isr ; (40) IBN + .db 0 + ljmp _stub_isr ; (44) Reserved + .db 0 + ljmp _ep0pingnak_isr ; (48) EP0 PING NAK + .db 0 + ljmp _ep1pingnak_isr ; (4C) EP1 PING NAK + .db 0 + ljmp _ep2pingnak_isr ; (50) EP2 PING NAK + .db 0 + ljmp _ep4pingnak_isr ; (54) EP4 PING NAK + .db 0 + ljmp _ep6pingnak_isr ; (58) EP6 PING NAK + .db 0 + ljmp _ep8pingnak_isr ; (5C) EP8 PING NAK + .db 0 + ljmp _errorlimit_isr ; (60) Error Limit + .db 0 + ljmp _stub_isr ; (64) Reserved + .db 0 + ljmp _stub_isr ; (68) Reserved + .db 0 + ljmp _stub_isr ; (6C) Reserved + .db 0 + ljmp _ep2piderror_isr ; (70) EP2 ISO Pid Sequence Error + .db 0 + ljmp _ep4piderror_isr ; (74) EP4 ISO Pid Sequence Error + .db 0 + ljmp _ep6piderror_isr ; (78) EP6 ISO Pid Sequence Error + .db 0 + ljmp _ep8piderror_isr ; (7C) EP8 ISO Pid Sequence Error + .db 0 + ljmp _ep2pflag_isr ; (80) EP2 Programmable Flag + .db 0 + ljmp _ep4pflag_isr ; (84) EP4 Programmable Flag + .db 0 + ljmp _ep6pflag_isr ; (88) EP6 Programmable Flag + .db 0 + ljmp _ep8pflag_isr ; (8C) EP8 Programmable Flag + .db 0 + ljmp _ep2eflag_isr ; (90) EP2 Empty Flag + .db 0 + ljmp _ep4eflag_isr ; (94) EP4 Empty Flag + .db 0 + ljmp _ep6eflag_isr ; (98) EP6 Empty Flag + .db 0 + ljmp _ep8eflag_isr ; (9C) EP8 Empty Flag + .db 0 + ljmp _ep2fflag_isr ; (A0) EP2 Full Flag + .db 0 + ljmp _ep4fflag_isr ; (A4) EP4 Full Flag + .db 0 + ljmp _ep6fflag_isr ; (A8) EP6 Full Flag + .db 0 + ljmp _ep8fflag_isr ; (AC) EP8 Full Flag + .db 0 + ljmp _gpifcomplete_isr ; (B0) GPIF Operation Complete + .db 0 + ljmp _gpifwaveform_isr ; (B4) GPIF Waveform + .db 0 diff --git a/contrib/firmware/angie/c/src/delay.c b/contrib/firmware/angie/c/src/delay.c new file mode 100644 index 0000000000..471e160dd4 --- /dev/null +++ b/contrib/firmware/angie/c/src/delay.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/**************************************************************************** + File : delay.c * + Contents : Delays handling fucntions code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "delay.h" +#include + +void syncdelay(uint8_t count) +{ + for (uint8_t i = 0; i < count; i++) + NOP(); +} + +void delay_5us(void) +{ + NOP(); +} + +void delay_1ms(void) +{ + uint16_t i; + + for (i = 0; i < 598; i++) + ; +} + +void delay_us(uint16_t delay) +{ + uint16_t i; + uint16_t maxcount = (delay / 5); + + for (i = 0; i < maxcount; i++) + delay_5us(); +} + +void delay_ms(uint16_t delay) +{ + uint16_t i; + + for (i = 0; i < delay; i++) + delay_1ms(); +} diff --git a/contrib/firmware/angie/c/src/gpif.c b/contrib/firmware/angie/c/src/gpif.c new file mode 100644 index 0000000000..80a9571087 --- /dev/null +++ b/contrib/firmware/angie/c/src/gpif.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + This program configures the General Programmable Interface (GPIF) for FX2. + Please do not modify sections of text which are marked as "DO NOT EDIT ...". +*/ + +/* GPIF Program Code */ + +#include "reg_ezusb.h" +#include "delay.h" + +/****************************** GPIF PROGRAM CODE ********************************/ +/* DO NOT EDIT ... */ +const char wavedata[128] = { +/* Wave 0 */ +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +/* Wave 1 */ +/* LenBr */ 0x88, 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x01, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x07, 0x05, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +/* LFun */ 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x3F, +/* Wave 2 */ +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +/* Wave 3 */ +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +}; +/* END DO NOT EDIT */ + +/* DO NOT EDIT ... */ +const char flowstates[36] = { +/* Wave 0 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 1 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 2 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 3 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +/* END DO NOT EDIT */ + +/* DO NOT EDIT ... */ +const char initdata[7] = { +/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00 +}; +/* END DO NOT EDIT */ + +void gpif_init(void) +{ + uint8_t i; + + IFCONFIG = 0xEE; + + GPIFABORT = 0xFF; /* abort any waveforms pending */ + GPIFREADYCFG = initdata[0]; + GPIFCTLCFG = initdata[1]; + GPIFIDLECS = initdata[2]; + GPIFIDLECTL = initdata[3]; + GPIFWFSELECT = initdata[5]; + GPIFREADYSTAT = initdata[6]; + + /* use dual autopointer feature... */ + AUTOPTRSETUP = 0x07; + + /* source */ + AUTOPTRH1 = (uint8_t)(((uint16_t)(&wavedata) >> 8) & 0xff); + AUTOPTRL1 = (uint8_t)((uint16_t)(&wavedata) & 0xff); + + /* destination */ + AUTOPTRH2 = 0xE4; + AUTOPTRL2 = 0x00; + + /* transfer */ + for (i = 0x00; i < 128; i++) + EXTAUTODAT2 = EXTAUTODAT1; + + /* GPIF address pins update when GPIFADRH/L written */ + syncdelay(3); + GPIFADRH = 0x00; /* bits[7:1] always 0 */ + syncdelay(3); + GPIFADRL = 0x00; /* point to PERIPHERAL address 0x0000 */ + + /* Configure GPIF flowstates registers for Wave 0 of wavedata */ + FLOWSTATE = flowstates[0]; + FLOWLOGIC = flowstates[1]; + FLOWEQ0CTL = flowstates[2]; + FLOWEQ1CTL = flowstates[3]; + FLOWHOLDOFF = flowstates[4]; + FLOWSTB = flowstates[5]; + FLOWSTBEDGE = flowstates[6]; + FLOWSTBHPERIOD = flowstates[7]; +} diff --git a/contrib/firmware/angie/c/src/jtag.c b/contrib/firmware/angie/c/src/jtag.c new file mode 100644 index 0000000000..9a44cd0bfc --- /dev/null +++ b/contrib/firmware/angie/c/src/jtag.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : jtag.c * + Contents : Jtag handling functions code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "jtag.h" +#include "io.h" +#include "msgtypes.h" +#include "reg_ezusb.h" +#include +#include +#include + +/** Delay value for SCAN_IN operations with less than maximum TCK frequency */ +uint8_t delay_scan_in; + +/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ +uint8_t delay_scan_out; + +/** Delay value for SCAN_IO operations with less than maximum TCK frequency */ +uint8_t delay_scan_io; + +/** Delay value for CLOCK_TCK operations with less than maximum frequency */ +uint8_t delay_tck; + +/** Delay value for CLOCK_TMS operations with less than maximum frequency */ +uint8_t delay_tms; + +/** + * Perform JTAG SCAN-IN operation at maximum TCK frequency. + * + * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and + * stored in the EP2 IN buffer. + * + * Maximum achievable TCK frequency is 182 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdo_data, i, j; + + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + + outb_buffer = IOB & ~(bmbit1 | bmbit2 | bmbit3); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdo_data = 0; + + for (j = 0; j < 8; j++) { + IOB = outb_buffer; /* TCK changes here */ + tdo_data = tdo_data >> 1; + IOB = (outb_buffer | bmbit2); + + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + IOB = outb_buffer; /* TCK changes here */ + tdo_data = tdo_data >> 1; + IOB = (outb_buffer | bmbit2); + + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform JTAG SCAN-IN operation at variable TCK frequency. + * + * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and + * stored in the EP2 IN buffer. + * + * Maximum achievable TCK frequency is 113 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdo_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + + outb_buffer = IOB & ~(bmbit3 | bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdo_data = 0; + + for (j = 0; j < 8; j++) { + IOB = outb_buffer; /* TCK changes here */ + for (k = 0; k < delay_scan_in; k++) + ; + tdo_data = tdo_data >> 1; + + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_in; k++) + ; + + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + IOB = outb_buffer; /* TCK changes here */ + for (k = 0; k < delay_scan_in; k++) + ; + tdo_data = tdo_data >> 1; + + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_in; k++) + ; + + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform JTAG SCAN-OUT operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is not sampled. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 142 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + */ +void jtag_scan_out(uint8_t out_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, i, j; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + } + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + } + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Perform JTAG SCAN-OUT operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is not sampled. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 97 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + */ +void jtag_slow_scan_out(uint8_t out_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_out; k++) + ; + } + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_out; k++) + ; + } + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is sampled and stored in the EP2 IN buffer. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 100 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +int it; +void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, tdo_data, i, j; + uint8_t outb_buffer; + + it++; + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is sampled and stored in the EP2 IN buffer. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 78 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, tdo_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_io; k++) + ; + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_io; k++) + ; + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Generate TCK clock cycles. + * + * Maximum achievable TCK frequency is 375 kHz for ANGIE clocked at 24 MHz. + * + * @param count number of TCK clock cycles to generate. + */ +void jtag_clock_tck(uint16_t count) +{ + uint16_t i; + uint8_t outb_buffer = IOB & ~(bmbit2); + + for (i = 0; i < count; i++) { + IOB = outb_buffer; + IOB = outb_buffer | bmbit2; + } +} + +/** + * Generate TCK clock cycles at variable frequency. + * + * Maximum achievable TCK frequency is 166.6 kHz for ANGIE clocked at 24 MHz. + * + * @param count number of TCK clock cycles to generate. + */ +void jtag_slow_clock_tck(uint16_t count) +{ + uint16_t i; + uint8_t j; + uint8_t outb_buffer = IOB & ~(bmbit2); + + for (i = 0; i < count; i++) { + IOB = outb_buffer; + for (j = 0; j < delay_tck; j++) + ; + IOB = outb_buffer | bmbit2; + for (j = 0; j < delay_tck; j++) + ; + } +} + +/** + * Perform TAP FSM state transitions at maximum TCK frequency. + * + * Maximum achievable TCK frequency is 176 kHz for ANGIE clocked at 24 MHz. + * + * @param count the number of state transitions to perform. + * @param sequence the TMS pin levels for each state transition, starting with + * the least-significant bit. + */ +void jtag_clock_tms(uint8_t count, uint8_t sequence) +{ + uint8_t outb_buffer = IOB & ~(bmbit2); + uint8_t i; + + for (i = 0; i < count; i++) { + /* Set TMS pin according to sequence parameter */ + if (sequence & 0x1) + outb_buffer |= bmbit1; + else + outb_buffer &= ~bmbit1; + IOB = outb_buffer; + sequence = sequence >> 1; + IOB = outb_buffer | bmbit2; + } +} + +/** + * Perform TAP-FSM state transitions at less than maximum TCK frequency. + * + * Maximum achievable TCK frequency is 117 kHz for ANGIE clocked at 24 MHz. + * + * @param count the number of state transitions to perform. + * @param sequence the TMS pin levels for each state transition, starting with + * the least-significant bit. + */ +void jtag_slow_clock_tms(uint8_t count, uint8_t sequence) +{ + uint8_t outb_buffer = IOB & ~(bmbit2); + uint8_t i, j; + + for (i = 0; i < count; i++) { + /* Set TMS pin according to sequence parameter */ + if (sequence & 0x1) + outb_buffer |= bmbit1; + else + outb_buffer &= ~bmbit1; + IOB = outb_buffer; + for (j = 0; j < delay_tms; j++) + ; + sequence = sequence >> 1; + IOB = outb_buffer | bmbit2; + for (j = 0; j < delay_tms; j++) + ; + } +} + +uint16_t jtag_get_signals(void) +{ + uint8_t input_signal_state, output_signal_state; + input_signal_state = 0; + output_signal_state = 0; + + /* Get states of input pins */ + if (PIN_TDO) + input_signal_state |= SIGNAL_TDO; + + /* Get states of output pins */ + output_signal_state = IOB & MASK_PORTB_DIRECTION_OUT; + + return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state); +} + +/** + * Set state of JTAG output signals. + * + * @param low signals which should be de-asserted. + * @param high signals which should be asserted. + */ +void jtag_set_signals(uint8_t low, uint8_t high) +{ + IOB &= ~(low & MASK_PORTB_DIRECTION_OUT); + IOB |= (high & MASK_PORTB_DIRECTION_OUT); +} + +/** + * Configure TCK delay parameters. + * + * @param scan_in number of delay cycles in scan_in operations. + * @param scan_out number of delay cycles in scan_out operations. + * @param scan_io number of delay cycles in scan_io operations. + * @param tck number of delay cycles in clock_tck operations. + * @param tms number of delay cycles in clock_tms operations. + */ +void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, + uint8_t scan_io, uint8_t tck, uint8_t tms) +{ + delay_scan_in = scan_in; + delay_scan_out = scan_out; + delay_scan_io = scan_io; + delay_tck = tck; + delay_tms = tms; +} diff --git a/contrib/firmware/angie/c/src/main.c b/contrib/firmware/angie/c/src/main.c new file mode 100644 index 0000000000..9290af2ab5 --- /dev/null +++ b/contrib/firmware/angie/c/src/main.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : main.c * + Contents : main code for NanoXplore USB-JTAG ANGIE adapter * + hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "delay.h" +#include "protocol.h" +#include "reg_ezusb.h" +#include +#include + +extern void sudav_isr(void)__interrupt SUDAV_ISR; +extern void sof_isr(void)__interrupt; +extern void sutok_isr(void)__interrupt; +extern void suspend_isr(void)__interrupt; +extern void usbreset_isr(void)__interrupt; +extern void highspeed_isr(void)__interrupt; +extern void ep0ack_isr(void)__interrupt; +extern void stub_isr(void)__interrupt; +extern void ep0in_isr(void)__interrupt; +extern void ep0out_isr(void)__interrupt; +extern void ep1in_isr(void)__interrupt; +extern void ep1out_isr(void)__interrupt; +extern void ep2_isr(void)__interrupt; +extern void ep4_isr(void)__interrupt; +extern void ep6_isr(void)__interrupt; +extern void ep8_isr(void)__interrupt; +extern void ibn_isr(void)__interrupt; +extern void ep0pingnak_isr(void)__interrupt; +extern void ep1pingnak_isr(void)__interrupt; +extern void ep2pingnak_isr(void)__interrupt; +extern void ep4pingnak_isr(void)__interrupt; +extern void ep6pingnak_isr(void)__interrupt; +extern void ep8pingnak_isr(void)__interrupt; +extern void errorlimit_isr(void)__interrupt; +extern void ep2piderror_isr(void)__interrupt; +extern void ep4piderror_isr(void)__interrupt; +extern void ep6piderror_isr(void)__interrupt; +extern void ep8piderror_isr(void)__interrupt; +extern void ep2pflag_isr(void)__interrupt; +extern void ep4pflag_isr(void)__interrupt; +extern void ep6pflag_isr(void)__interrupt; +extern void ep8pflag_isr(void)__interrupt; +extern void ep2eflag_isr(void)__interrupt; +extern void ep4eflag_isr(void)__interrupt; +extern void ep6eflag_isr(void)__interrupt; +extern void ep8eflag_isr(void)__interrupt; +extern void ep2fflag_isr(void)__interrupt; +extern void ep4fflag_isr(void)__interrupt; +extern void ep6fflag_isr(void)__interrupt; +extern void ep8fflag_isr(void)__interrupt; +extern void gpifcomplete_isr(void)__interrupt; +extern void gpifwaveform_isr(void)__interrupt; + +void gpif_init(void); + +int main(void) +{ + CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */ + sio0_init(57600); /* needed for printf */ + + ep_init(); + gpif_init(); + interrupt_init(); + io_init(); + + /* Perform ReNumeration */ + USBCS |= (DISCON | RENUM); + delay_ms(250); + USBCS &= ~DISCON; + + /* Begin executing command(s). This function never returns. */ + command_loop(); + + /* Never reached, but SDCC complains about missing return statement */ + return 0; +} diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c new file mode 100644 index 0000000000..3f3aaaf362 --- /dev/null +++ b/contrib/firmware/angie/c/src/protocol.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : protocol.c * + Contents : Jtag commands handling protocol code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "protocol.h" +#include "jtag.h" +#include "delay.h" +#include "io.h" +#include "msgtypes.h" +#include "reg_ezusb.h" +#include +#include + +/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */ +volatile uint8_t cmd_id_index; + +/** Number of data bytes already in EP1 Bulk-IN buffer */ +volatile uint8_t payload_index_in; + +/** + * Executes one command and updates global command indexes. + * + * @return true if this command was the last command. + * @return false if there are more commands within the current contents of the + * Bulk EP1-OUT data buffer. + */ +bool execute_command(void) +{ + uint8_t usb_out_bytecount, usb_in_bytecount; + uint16_t signal_state = 0; + uint16_t count; + + /* Most commands do not transfer IN data. To save code space, we write 0 to + * usb_in_bytecount here, then modify it in the switch statement below where + * necessary */ + usb_in_bytecount = 0; + + switch (EP1OUTBUF[cmd_id_index] /* Command ID */) { + case CMD_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_scan_in((cmd_id_index + 1), payload_index_in); + break; + case CMD_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_scan_out(cmd_id_index + 1); + break; + case CMD_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_scan_io((cmd_id_index + 1), payload_index_in); + break; + case CMD_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_clock_tck(count); + break; + case CMD_SLOW_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_slow_scan_out(cmd_id_index + 1); + break; + case CMD_SLOW_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_SLOW_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_slow_clock_tck(count); + break; + case CMD_SLEEP_US: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_us(count); + break; + case CMD_SLEEP_MS: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_ms(count); + break; + case CMD_GET_SIGNALS: + usb_out_bytecount = 0; + usb_in_bytecount = 2; + signal_state = jtag_get_signals(); + EP1INBUF[payload_index_in] = (signal_state >> 8); + EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF); + break; + case CMD_SET_SIGNALS: + usb_out_bytecount = 2; + jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CONFIGURE_TCK_FREQ: + usb_out_bytecount = 5; + jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */ + EP1OUTBUF[cmd_id_index + 2], /* scan_out */ + EP1OUTBUF[cmd_id_index + 3], /* scan_io */ + EP1OUTBUF[cmd_id_index + 4], /* clock_tck */ + EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */ + break; + case CMD_TEST: + usb_out_bytecount = 1; + /* Do nothing... This command is only used to test if the device is ready + * to accept new commands */ + break; + default: + /* Should never be reached */ + usb_out_bytecount = 0; + break; + } + + /* Update EP1 Bulk-IN data byte count */ + payload_index_in += usb_in_bytecount; + + /* Determine if this was the last command */ + if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) { + return true; + /* Line between return and else required by checkpatch: */ + uint8_t a = 0; + } else { + /* Not the last command, update cmd_id_index */ + cmd_id_index += (usb_out_bytecount + 1); + return false; + } +} + +/** + * Forever wait for commands and execute them as they arrive. + */ +void command_loop(void) +{ + bool last_command; + while (1) { + cmd_id_index = 0; + payload_index_in = 0; + + /* Wait until host sends EP1 Bulk-OUT packet */ + while (!ep1_out) + ; + ep1_out = false; + + /* Execute the commands */ + last_command = false; + while (!last_command) + last_command = execute_command(); + + /* Send back EP6 Bulk-IN packet if required */ + if (payload_index_in > 0) { + EP1INBC = payload_index_in; + syncdelay(3); + + while (!ep1_in) + ; + ep1_in = false; + } + + /* Re-arm EP1-OUT after command execution */ + EP1OUTBC = 0; + syncdelay(3); + EP1OUTBC = 0; + syncdelay(3); + } +} diff --git a/contrib/firmware/angie/c/src/serial.c b/contrib/firmware/angie/c/src/serial.c new file mode 100644 index 0000000000..0398cb23cf --- /dev/null +++ b/contrib/firmware/angie/c/src/serial.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/* + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. +*/ + +#include +#include +#include +#include +/** + * using the comp port implies that timer 2 will be used as + * a baud rate generator. (Don't use timer 2) + **/ +void sio0_init(uint32_t baud_rate) __critical +{ + uint16_t hl; /* hl value for reload */ + uint8_t mult; /* multiplier for clock speed */ + uint32_t tmp; /* scratch for mult/divide */ + + mult = (CPUFREQ == CLK_12M) ? 1 : ((CPUFREQ == CLK_24M) ? 2 : 4); + + /* set the clock rate */ + /* use clock 2 */ + RCLK = 1; TCLK = 1; + tmp = mult * 375000L * 2; + tmp /= baud_rate; + tmp += 1; + tmp /= 2; + hl = 0xFFFF - (uint16_t)tmp; + RCAP2H = (uint8_t)(((uint16_t)(hl) >> 8) & 0xff); + + /* seems that the 24/48mhz calculations are always one less than suggested values */ + /* trm table 14-16 */ + RCAP2L = ((uint8_t)((uint16_t)(hl) & 0xff)) + (mult > 0 ? 1 : 0); + + /* start the timer */ + TR2 = 1; + + /* set up the serial port */ + SM0 = 0; SM1 = 1; /* serial mode 1 (asyncronous) */ + SM2 = 0 ; /* has to do with receiving */ + REN = 1 ; /* to enable receiving */ + PCON |= 0x80; /* SET SMOD0, baud rate doubler */ + TI = 1; /* we send initial byte */ +} + +int getchar(void) +{ + char c; + while (!RI) + ; + c = SBUF0; + RI = 0; + return c; +} + +void _transchar(char c) +{ + while (!TI) + ; /* wait for TI=1 */ + TI = 0; + SBUF0 = c; +} + +int putchar (char c) +{ + if (c == '\n') + _transchar('\r'); /* transmit \r\n */ + _transchar(c); + if (c == '\r') + _transchar('\n'); /* transmit \r\n */ + return c; +} diff --git a/contrib/firmware/angie/c/src/usb.c b/contrib/firmware/angie/c/src/usb.c new file mode 100644 index 0000000000..8fd4de6373 --- /dev/null +++ b/contrib/firmware/angie/c/src/usb.c @@ -0,0 +1,784 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : usb.c * + Contents : usb communication handling code for NanoXplore USB-JTAG * + ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "stdint.h" +#include "delay.h" +#include "io.h" +#include "reg_ezusb.h" +#include +#include +#include + +/* Also update external declarations in "include/usb.h" if making changes to + * these variables! + */ +volatile bool ep1_out; +volatile bool ep1_in; + +volatile __xdata __at 0xE6B8 struct setup_data setup_data; + +/* Define number of endpoints (except Control Endpoint 0) in a central place. + * Be sure to include the necessary endpoint descriptors! + */ +#define NUM_ENDPOINTS 3 + +__code struct usb_device_descriptor device_descriptor = { + .blength = sizeof(struct usb_device_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_DEVICE, + .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */ + .bdeviceclass = 0xFF, /* 0xFF = vendor-specific */ + .bdevicesubclass = 0xFF, + .bdeviceprotocol = 0xFF, + .bmaxpacketsize0 = 64, + .idvendor = 0x584e, + .idproduct = 0x424e, + .bcddevice = 0x0000, + .imanufacturer = 1, + .iproduct = 2, + .iserialnumber = 3, + .bnumconfigurations = 1 +}; + +/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */ + +__code struct usb_config_descriptor config_descriptor = { + .blength = sizeof(struct usb_config_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION, + .wtotallength = sizeof(struct usb_config_descriptor) + + sizeof(struct usb_interface_descriptor) + + (NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)), + .bnuminterfaces = 1, + .bconfigurationvalue = 1, + .iconfiguration = 4, /* String describing this configuration */ + .bmattributes = 0x80, /* Only MSB set according to USB spec */ + .maxpower = 50 /* 100 mA */ +}; + +__code struct usb_interface_descriptor interface_descriptor00 = { + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 0, + .balternatesetting = 0, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0xFF, + .binterfacesubclass = 0xFF, + .binterfaceprotocol = 0xFF, + .iinterface = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (1 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 64, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (1 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 64, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (2 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (4 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep6_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (6 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep8_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (8 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_language_descriptor language_descriptor = { + .blength = 4, + .bdescriptortype = DESCRIPTOR_TYPE_STRING, + .wlangid = {0x0409 /* US English */} +}; + +__code struct usb_string_descriptor strmanufacturer = + STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.'); + +__code struct usb_string_descriptor strproduct = + STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); + +__code struct usb_string_descriptor strserialnumber = + STR_DESCR(6, '0', '0', '0', '0', '0', '1'); + +__code struct usb_string_descriptor strconfigdescr = + STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); + +/* Table containing pointers to string descriptors */ +__code struct usb_string_descriptor *__code en_string_descriptors[4] = { + &strmanufacturer, + &strproduct, + &strserialnumber, + &strconfigdescr +}; +void sudav_isr(void)__interrupt SUDAV_ISR +{ + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + USBIRQ = SUDAVI; + EP0CS |= HSNAK; + usb_handle_setup_data(); +} +void sof_isr(void)__interrupt SOF_ISR +{ +} +void sutok_isr(void)__interrupt SUTOK_ISR +{ +} +void suspend_isr(void)__interrupt SUSPEND_ISR +{ +} +void usbreset_isr(void)__interrupt USBRESET_ISR +{ +} +void highspeed_isr(void)__interrupt HIGHSPEED_ISR +{ +} +void ep0ack_isr(void)__interrupt EP0ACK_ISR +{ +} +void stub_isr(void)__interrupt STUB_ISR +{ +} +void ep0in_isr(void)__interrupt EP0IN_ISR +{ +} +void ep0out_isr(void)__interrupt EP0OUT_ISR +{ +} +void ep1in_isr(void)__interrupt EP1IN_ISR +{ + ep1_in = true; + + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x04; /* Clear individual EP1IN IRQ */ +} +void ep1out_isr(void)__interrupt EP1OUT_ISR +{ + ep1_out = true; + + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */ +} +void ep2_isr(void)__interrupt EP2_ISR +{ + ep1_out = false; /* Does nothing but required by the compiler */ +} +void ep4_isr(void)__interrupt EP4_ISR +{ +} +void ep6_isr(void)__interrupt EP6_ISR +{ +} +void ep8_isr(void)__interrupt EP8_ISR +{ +} +void ibn_isr(void)__interrupt IBN_ISR +{ +} +void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR +{ +} +void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR +{ +} +void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR +{ +} +void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR +{ +} +void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR +{ +} +void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR +{ +} +void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR +{ +} +void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR +{ +} +void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR +{ +} +void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR +{ +} +void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR +{ +} +void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR +{ +} +void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR +{ +} +void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR +{ +} +void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR +{ +} +void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR +{ +} +void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR +{ +} +void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR +{ +} +void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR +{ +} +void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR +{ +} +void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR +{ +} +void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR +{ +} +void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR +{ +} +void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR +{ +} +void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR +{ +} + +/** + * Return the control/status register for an endpoint + * + * @param ep endpoint address + * @return on success: pointer to Control & Status register for endpoint + * specified in \a ep + * @return on failure: NULL + */ +__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep) +{ + /* Mask direction bit */ + uint8_t ep_num = ep & ~0x80; + + switch (ep_num) { + case 0: + return &EP0CS; + case 1: + return ep & 0x80 ? &EP1INCS : &EP1OUTCS; + case 2: + return &EP2CS; + case 4: + return &EP4CS; + case 6: + return &EP6CS; + case 8: + return &EP8CS; + default: + return NULL; + } +} + +void usb_reset_data_toggle(uint8_t ep) +{ + /* TOGCTL register: + +----+-----+-----+------+-----+-------+-------+-------+ + | Q | S | R | IO | EP3 | EP2 | EP1 | EP0 | + +----+-----+-----+------+-----+-------+-------+-------+ + + To reset data toggle bits, we have to write the endpoint direction (IN/OUT) + to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a + separate write cycle, the R bit needs to be set. + */ + TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F)); + TOGCTL |= BMRESETTOGGLE; +} + +/** + * Handle GET_STATUS request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_get_status(void) +{ + uint8_t *ep_cs; + switch (setup_data.bmrequesttype) { + case GS_DEVICE: + /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup. + * Byte 1: reserved, reset to zero */ + EP0BUF[0] = 0; + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + case GS_INTERFACE: + /* Always return two zero bytes according to USB 1.1 spec, p. 191 */ + EP0BUF[0] = 0; + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + case GS_ENDPOINT: + /* Get stall bit for endpoint specified in low byte of wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff); + + if (*ep_cs & EPSTALL) + EP0BUF[0] = 0x01; + else + EP0BUF[0] = 0x00; + + /* Second byte sent has to be always zero */ + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + default: + return false; + } + return true; +} + +/** + * Handle CLEAR_FEATURE request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_clear_feature(void) +{ + __xdata uint8_t *ep_cs; + + switch (setup_data.bmrequesttype) { + case CF_DEVICE: + /* Clear remote wakeup not supported: stall EP0 */ + STALL_EP0(); + break; + case CF_ENDPOINT: + if (setup_data.wvalue == 0) { + /* Unstall the endpoint specified in wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex); + if (!ep_cs) + return false; + *ep_cs &= ~EPSTALL; + } else { + /* Unsupported feature, stall EP0 */ + STALL_EP0(); + } + break; + default: + /* Vendor commands... */ + break; + } + return true; +} + +/** + * Handle SET_FEATURE request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_set_feature(void) +{ + __xdata uint8_t *ep_cs; + + switch (setup_data.bmrequesttype) { + case SF_DEVICE: + if (setup_data.wvalue == 2) + return true; + break; + case SF_ENDPOINT: + if (setup_data.wvalue == 0) { + /* Stall the endpoint specified in wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex); + if (!ep_cs) + return false; + *ep_cs |= EPSTALL; + } else { + /* Unsupported endpoint feature */ + return false; + } + break; + default: + /* Vendor commands... */ + break; + } + + return true; +} + +/** + * Handle GET_DESCRIPTOR request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_get_descriptor(void) +{ + __xdata uint8_t descriptor_type; + __xdata uint8_t descriptor_index; + + descriptor_type = (setup_data.wvalue & 0xff00) >> 8; + descriptor_index = setup_data.wvalue & 0x00ff; + + switch (descriptor_type) { + case DESCRIPTOR_TYPE_DEVICE: + SUDPTRH = HI8(&device_descriptor); + SUDPTRL = LO8(&device_descriptor); + break; + case DESCRIPTOR_TYPE_CONFIGURATION: + SUDPTRH = HI8(&config_descriptor); + SUDPTRL = LO8(&config_descriptor); + break; + case DESCRIPTOR_TYPE_STRING: + if (setup_data.windex == 0) { + /* Supply language descriptor */ + SUDPTRH = HI8(&language_descriptor); + SUDPTRL = LO8(&language_descriptor); + } else if (setup_data.windex == 0x0409 /* US English */) { + /* Supply string descriptor */ + SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]); + SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]); + } else { + return false; + } + break; + default: + /* Unsupported descriptor type */ + return false; + } + return true; +} + +/** + * Handle SET_INTERFACE request. + */ +void usb_handle_set_interface(void) +{ + /* Reset Data Toggle */ + usb_reset_data_toggle(USB_DIR_IN | 4); + usb_reset_data_toggle(USB_DIR_OUT | 2); + + /* Unstall & clear busy flag of all valid IN endpoints */ + EP1INCS = 0 | EPBSY; + + /* Unstall all valid OUT endpoints, reset bytecounts */ + EP1OUTCS = 0; + EP1OUTBC = 0; + syncdelay(3); +} + +/* Initialize GPIF interface transfer count */ +void set_gpif_cnt(uint32_t count) +{ + GPIFTCB3 = (uint8_t)(((uint32_t)(count) >> 24) & 0x000000ff); + syncdelay(3); + GPIFTCB2 = (uint8_t)(((uint32_t)(count) >> 16) & 0x000000ff); + syncdelay(3); + GPIFTCB1 = (uint8_t)(((uint32_t)(count) >> 8) & 0x000000ff); + syncdelay(3); + GPIFTCB0 = (uint8_t)((uint32_t)(count) & 0x000000ff); +} + +/* + * Vendor commands handling: +*/ +#define VR_CFGOPEN 0xB0 +#define VR_CFGCLOSE 0xB1 + +uint8_t ix; +uint8_t bcnt; +uint8_t __xdata *eptr; +uint16_t wcnt; +uint32_t __xdata gcnt; +bool usb_handle_send_bitstream(void) +{ + eptr = EP0BUF; /* points to EP0BUF 64-byte register */ + wcnt = setup_data.wlength; /* total transfer count */ + + /* Clear EP0BUF for OUT requests */ + if (setup_data.bmrequesttype & 0x80) { + bcnt = ((wcnt > 64) ? 64 : wcnt); + for (ix = 0; ix < bcnt; ix++) + eptr[ix] = 0; + } + + switch (setup_data.brequest) { + case VR_CFGOPEN: + /* Clear bytecount / to allow new data in / to stops NAKing */ + EP0BCH = 0; + EP0BCL = 0; + while (EP0CS & EPBSY) + ; /* wait to finish transferring in EP0BUF, until not busy */ + gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16) + | ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]); + /* Angie board FPGA bitstream download */ + switch ((setup_data.wvalue) & 0x00C0) { + case 0x00: + PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */ + GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */ + syncdelay(3); + EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */ + syncdelay(3); + PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */ + delay_ms(10); /* FPGA init time < 10mS */ + set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */ + PIN_RDWR_B = 0; + PIN_CSI_B = 0; + GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */ + syncdelay(3); + break; + default: + break; + } + break; + case VR_CFGCLOSE: + ix = 10; + /* wait until GPIF transaction has been completed */ + while ((GPIFTRIG & BMGPIFDONE) == 0) { + if (ix-- == 0) { + printf("GPIF done time out\n"); + break; + } + delay_ms(1); + } + switch ((setup_data.wvalue) & 0x00C0) { + case 0x00: + PIN_CSI_B = 1; + PIN_RDWR_B = 1; + IFCONFIG &= 0xFC; /* Exit gpif mode */ + break; + default: + break; + } + EP0BCH = 0; + EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */ + break; + default: + return true; /* Error: unknown VR command */ + } + return false; /* no error; command handled OK */ +} + +/** + * Handle the arrival of a USB Control Setup Packet. + */ +void usb_handle_setup_data(void) +{ + switch (setup_data.brequest) { + case GET_STATUS: + if (!usb_handle_get_status()) + STALL_EP0(); + break; + case CLEAR_FEATURE: + if (!usb_handle_clear_feature()) + STALL_EP0(); + break; + case 2: case 4: + /* Reserved values */ + STALL_EP0(); + break; + case SET_FEATURE: + if (!usb_handle_set_feature()) + STALL_EP0(); + break; + case SET_ADDRESS: + /* Handled by USB core */ + break; + case SET_DESCRIPTOR: + /* Set Descriptor not supported. */ + STALL_EP0(); + break; + case GET_DESCRIPTOR: + if (!usb_handle_get_descriptor()) + STALL_EP0(); + break; + case GET_CONFIGURATION: + /* ANGIE has only one configuration, return its index */ + EP0BUF[0] = config_descriptor.bconfigurationvalue; + EP0BCH = 0; + EP0BCL = 1; + syncdelay(3); + break; + case SET_CONFIGURATION: + /* ANGIE has only one configuration -> nothing to do */ + break; + case GET_INTERFACE: + /* ANGIE only has one interface, return its number */ + EP0BUF[0] = interface_descriptor00.binterfacenumber; + EP0BCH = 0; + EP0BCL = 1; + syncdelay(3); + break; + case SET_INTERFACE: + usb_handle_set_interface(); + break; + case SYNCH_FRAME: + /* Isochronous endpoints not used -> nothing to do */ + break; + default: + /* if not Vendor command, Stall EndPoint 0 */ + if (usb_handle_send_bitstream()) + STALL_EP0(); + break; + } +} + +/** + * Handle the initialization of endpoints. + */ +void ep_init(void) +{ + EP1INCFG = 0xA0; + syncdelay(3); + EP1OUTCFG = 0xA0; + syncdelay(3); + EP2CFG = 0xA0; + syncdelay(3); + EP4CFG = 0x00; + syncdelay(3); + EP6CFG = 0x00; + syncdelay(3); + EP8CFG = 0x00; + syncdelay(3); + + /* arm EP1-OUT */ + EP1OUTBC = 0; + syncdelay(3); + EP1OUTBC = 0; + syncdelay(3); + + /* arm EP1-IN */ + EP1INBC = 0; + syncdelay(3); + EP1INBC = 0; + syncdelay(3); + + /* Standard procedure to reset FIFOs */ + FIFORESET = BMNAKALL; /* NAK all transfers during the reset */ + syncdelay(3); + FIFORESET = 0x02; /* reset EP2 FIFO */ + syncdelay(3); + FIFORESET = 0x00; /* deactivate the NAK all */ + syncdelay(3); + EP2FIFOCFG = 0x00; + syncdelay(3); + EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */ + syncdelay(3); +} + +/** + * Interrupt initialization. Configures USB interrupts. + */ +void interrupt_init(void) +{ + /* Enable Interrupts */ + EA = 1; + + /* Enable USB interrupt (EIE register) */ + EUSB = 1; + EICON |= 0x20; + + /* Enable INT 2 & 4 Autovectoring */ + INTSETUP |= (AV2EN | AV4EN); + + /* Enable individual EP1OUT&IN interrupts */ + EPIE |= 0x0C; + + /* Clear individual USB interrupt IRQ */ + EPIRQ = 0x0C; + + /* Enable SUDAV interrupt */ + USBIEN |= SUDAVI; + + /* Clear SUDAV interrupt */ + USBIRQ = SUDAVI; +} + +/** + * Handle the initialization of io ports. + */ +void io_init(void) +{ + /* PORT A */ + PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */ + OEA = 0xEF; /* all OUT exept INIT_B IN */ + IOA = 0xFF; + PIN_RDWR_B = 1; + PIN_CSI_B = 1; + PIN_PROGRAM_B = 1; + + /* PORT B */ + OEB = 0xEF; /* all OUT exept TDO */ + IOB = 0xFF; + PIN_TRST = 1; + PIN_TMS = 0; + PIN_TCK = 0; + PIN_TDI = 0; + PIN_SRST = 1; + + /* PORT C */ + PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */ + OEC = 0xEF; + IOC = 0xFF; +} diff --git a/contrib/firmware/angie/hdl/Makefile b/contrib/firmware/angie/hdl/Makefile new file mode 100644 index 0000000000..c2c74a0b80 --- /dev/null +++ b/contrib/firmware/angie/hdl/Makefile @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +# Needed by timing test +export PROJECT := angie_openocd +TARGET_PART := xc6slx9-2tqg144 +export TOPLEVEL := S609 + +# Detects the ROOT dir from the .git marker +sp := +sp += +_walk = $(if $1,$(wildcard /$(subst $(sp),/,$1)/$2) $(call _walk,$(wordlist 2,$(words $1),x $1),$2)) +_find = $(firstword $(call _walk,$(strip $(subst /, ,$1)),$2)) +_ROOT := $(patsubst %/.git,%,$(call _find,$(CURDIR),.git)) + +SHELL := /bin/bash +TOP_DIR := $(realpath $(_ROOT)) +HDL_DIR := $(CURDIR) +SRC_DIR := $(HDL_DIR)/src +TOOLS_DIR := $(TOP_DIR)/tools/build +COMMON_DIR := $(TOP_DIR)/common/hdl +COMMON_HDL_DIR := $(COMMON_DIR)/src +COMMON_LIBS := $(COMMON_DIR)/libs +HDL_BUILD_DIR := $(HDL_DIR)/build +OUTPUT_DIR ?= $(HDL_BUILD_DIR)/output +FINAL_OUTPUT_DIR := $(OUTPUT_DIR)/$(PROJECT) + +# Tools +MKDIR := mkdir -p +CP := cp -f + +HDL_SRC_PATH := $(addprefix $(COMMON_DIR)/ips/, $(HDL_IPS)) $(HDL_DIR) +VHDSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vhd)) +VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.v)) +VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vh)) + +CONSTRAINTS ?= $(SRC_DIR)/$(PROJECT).ucf + +COMMON_OPTS := -intstyle xflow +XST_OPTS := +NGDBUILD_OPTS := +MAP_OPTS := -mt 2 +PAR_OPTS := -mt 4 +BITGEN_OPTS := -g Binary:Yes + +XILINX_PLATFORM := lin64 +PATH := $(PATH):$(XILINX_HOME)/bin/$(XILINX_PLATFORM) + +RUN = @echo -ne "\n\n\e[1;33m======== $(1) ========\e[m\n\n"; \ + cd $(HDL_BUILD_DIR) && $(XILINX_HOME)/bin/$(XILINX_PLATFORM)/$(1) + +compile: $(HDL_BUILD_DIR)/$(PROJECT).bin + +install: $(HDL_BUILD_DIR)/$(PROJECT).bin + $(MKDIR) $(FINAL_OUTPUT_DIR) + $(CP) $(HDL_BUILD_DIR)/$(PROJECT).bin $(FINAL_OUTPUT_DIR) + +clean: + rm -rf $(HDL_BUILD_DIR) + +$(HDL_BUILD_DIR)/$(PROJECT).bin: $(HDL_BUILD_DIR)/$(PROJECT).ncd + $(call RUN,bitgen) $(COMMON_OPTS) $(BITGEN_OPTS) \ + -w $(PROJECT).ncd $(PROJECT).bit + +$(HDL_BUILD_DIR)/$(PROJECT).ncd: $(HDL_BUILD_DIR)/$(PROJECT).map.ncd + $(call RUN,par) $(COMMON_OPTS) $(PAR_OPTS) \ + -w $(PROJECT).map.ncd $(PROJECT).ncd $(PROJECT).pcf + +$(HDL_BUILD_DIR)/$(PROJECT).map.ncd: $(HDL_BUILD_DIR)/$(PROJECT).ngd + $(call RUN,map) $(COMMON_OPTS) $(MAP_OPTS) \ + -p $(TARGET_PART) \ + -w $(PROJECT).ngd -o $(PROJECT).map.ncd $(PROJECT).pcf + +$(HDL_BUILD_DIR)/$(PROJECT).ngd: $(HDL_BUILD_DIR)/$(PROJECT).ngc + $(call RUN,ngdbuild) $(COMMON_OPTS) $(NGDBUILD_OPTS) \ + -p $(TARGET_PART) -uc $(CONSTRAINTS) \ + $(PROJECT).ngc $(PROJECT).ngd + +$(HDL_BUILD_DIR)/$(PROJECT).ngc: $(HDL_BUILD_DIR)/$(PROJECT).prj $(HDL_BUILD_DIR)/$(PROJECT).scr + $(call RUN,xst) $(COMMON_OPTS) -ifn $(PROJECT).scr + +$(HDL_BUILD_DIR)/$(PROJECT).scr: | $(HDL_BUILD_DIR) + @echo "Updating $@" + @mkdir -p $(HDL_BUILD_DIR) + @rm -f $@ + @echo "run" \ + "-ifn $(PROJECT).prj" \ + "-ofn $(PROJECT).ngc" \ + "-ifmt mixed" \ + "$(XST_OPTS)" \ + "-top $(TOPLEVEL)" \ + "-ofmt NGC" \ + "-p $(TARGET_PART)" \ + > $(HDL_BUILD_DIR)/$(PROJECT).scr + +$(HDL_BUILD_DIR)/$(PROJECT).prj: | $(HDL_BUILD_DIR) + @echo "Updating $@" + @rm -f $@ + @$(foreach file,$(VSOURCE),echo "verilog work \"$(file)\"" >> $@;) + @$(foreach file,$(VHDSOURCE),echo "vhdl work \"$(file)\"" >> $@;) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vhd),echo "vhdl $(lib) \"$(file)\"" >> $@;)) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.v),echo "verilog $(lib) \"$(file)\"" >> $@;)) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vh),echo "verilog $(lib) \"$(file)\"" >> $@;)) + +$(HDL_BUILD_DIR): + $(MKDIR) $(HDL_BUILD_DIR) + +.PHONY: clean compile install + diff --git a/contrib/firmware/angie/hdl/README b/contrib/firmware/angie/hdl/README new file mode 100644 index 0000000000..00578ff729 --- /dev/null +++ b/contrib/firmware/angie/hdl/README @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +This is the source code of Nanoxplore USB-JTAG Adapter Angie's bitstream. +This bitstream is for the "xc6slx9-2tqg144" Spartan-6 Xilinx FPGA. + +To generate this bitstream, you need to install Xilinx ISE Webpack 14.7 +You will need to give the ISE software path : export XILINX_HOME=path/to/ise/sw +Please set the enviromnent first by executing the ". ./set_env.sh" + +All you have to do now is to write your vhd and constrains codes. + +One all is setup, you can use the make commands: + make compile : to compile your (.vhd & .ucf) files in the "src" directory + A directory named "build" will be created, which contains all the generated + files including the bitstream file. + + make clean : to delete the build directory. diff --git a/contrib/firmware/angie/hdl/set_env.sh b/contrib/firmware/angie/hdl/set_env.sh new file mode 100644 index 0000000000..60e97375b9 --- /dev/null +++ b/contrib/firmware/angie/hdl/set_env.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +[ -z "${XILINX_HOME}" ] && export XILINX_HOME=/home/software/Xilinx/ISE/14.7/ISE_DS/ISE +export PATH="$XILINX_HOME:$PATH" +echo "SET XILINX_HOME to ${XILINX_HOME}" +# This is needed for isim +XILINX_HOME_BASE=${XILINX_HOME}/.. +for part in common EDK PlanAhead ISE +do + el=${XILINX_HOME_BASE}/${part} + . ${el}/.settings64.sh ${el} +done diff --git a/contrib/firmware/angie/hdl/src/angie_openocd.ucf b/contrib/firmware/angie/hdl/src/angie_openocd.ucf new file mode 100644 index 0000000000..fda3cdaaf1 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/angie_openocd.ucf @@ -0,0 +1,35 @@ +## SPDX-License-Identifier: BSD-3-Clause +##-------------------------------------------------------------------------- +## Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 +## Design Name: NJTAG USB-JTAG Adapter FPGA source code +## Module Name: _angie_openocd.ucf +## Target Device: XC6SLX9-2 TQ144 +## Tool versions: ISE Webpack 13.2 -> 14.2 +## Author: Ahmed BOUDJELIDA nanoXplore SAS +##-------------------------------------------------------------------------- +# WARNING: PullUps on JTAG inputs should be enabled after configuration +# (bitgen option) since the pins are not connected. + +net TRST LOC = 'P48' ; +net TMS LOC = 'P43' ; +net TCK LOC = 'P44' ; +net TDI LOC = 'P45' ; +net TDO LOC = 'P46' ; +net SRST LOC = 'P61' ; +net SI_TDO LOC = 'P16' ; +net SO_TRST LOC = 'P32' ; +net SO_TMS LOC = 'P27' ; +net SO_TCK LOC = 'P30' ; +net SO_TDI LOC = 'P26' ; +net SO_SRST LOC = 'P12' ; +net ST_0 LOC = 'P29' ; +net ST_1 LOC = 'P21' ; +net ST_2 LOC = 'P11' ; +net FTP<0> LOC = 'P121' ; +net FTP<1> LOC = 'P120' ; +net FTP<2> LOC = 'P119' ; +net FTP<3> LOC = 'P116' ; +net FTP<4> LOC = 'P111' ; +net FTP<5> LOC = 'P112' ; +net FTP<6> LOC = 'P115' ; +net FTP<7> LOC = 'P114' ; diff --git a/contrib/firmware/angie/hdl/src/angie_openocd.vhd b/contrib/firmware/angie/hdl/src/angie_openocd.vhd new file mode 100644 index 0000000000..d79c0fecef --- /dev/null +++ b/contrib/firmware/angie/hdl/src/angie_openocd.vhd @@ -0,0 +1,66 @@ +-- SPDX-License-Identifier: BSD-3-Clause +---------------------------------------------------------------------------- +-- Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 +-- Design Name: NJTAG USB-JTAG Adapter FPGA source code +-- Module Name: _angie_openocd.vhd +-- Target Device: XC6SLX9-2 TQ144 +-- Tool versions: ISE Webpack 13.2 -> 14.2 +-- Author: Ahmed BOUDJELIDA nanoXplore SAS +---------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +library UNISIM; +use UNISIM.VComponents.all; + +entity S609 is port( + TRST : in std_logic; + TMS : in std_logic; + TCK : in std_logic; + TDI : in std_logic; + TDO : out std_logic; + SRST : in std_logic; + FTP : out std_logic_vector(7 downto 0); -- Test points + SI_TDO : in std_logic; + ST_0 : out std_logic; + ST_1 : out std_logic; + ST_2 : out std_logic; + SO_TRST : out std_logic; + SO_TMS : out std_logic; + SO_TCK : out std_logic; + SO_TDI : out std_logic; + SO_SRST :out std_logic +); +end S609; + +architecture A_S609 of S609 is +begin + +--Directions: +ST_0 <= '0'; +ST_1 <= '1'; + +--TDO: +TDO <= not SI_TDO; + +--TRST - TCK - TMS - TDI: +SO_TRST <= TRST; +SO_TMS <= TMS; +SO_TCK <= TCK; +SO_TDI <= TDI; +ST_2 <= SRST; +SO_SRST <= '0'; + +--Points de test: +FTP(0) <= TRST; +FTP(1) <= TMS; +FTP(2) <= TCK; +FTP(3) <= TDI; +FTP(5) <= SRST; +FTP(4) <= SI_TDO; +FTP(6) <= '1'; +FTP(7) <= '1'; + +end A_S609; diff --git a/doc/usb_adapters/angie/584e_424e_angie.txt b/doc/usb_adapters/angie/584e_424e_angie.txt new file mode 100644 index 0000000000..8162cbad5a --- /dev/null +++ b/doc/usb_adapters/angie/584e_424e_angie.txt @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +Bus 001 Device 056: ID 584e:424e NanoXplore, SAS. ANGIE Adapter +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 255 Vendor Specific Subclass + bDeviceProtocol 255 Vendor Specific Protocol + bMaxPacketSize0 64 + idVendor 0x584e + idProduct 0x424e + bcdDevice 0.00 + iManufacturer 1 NanoXplore, SAS. + iProduct 2 ANGIE Adapter + iSerial 3 000001 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0027 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 (error) + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 From 94686eea6e982a83e5c1796e8a903bf683ed62e5 Mon Sep 17 00:00:00 2001 From: Ahmed BOUDJELIDA Date: Sat, 17 Jun 2023 01:11:15 +0200 Subject: [PATCH 40/49] jtag/drivers: Add new driver for ANGIE USB-JTAG Adapter This is the driver code for NanoXplore's ANGIE USB-JTAG Adapter. The driver is based on the openULINK project. This driver communicate with ANGIE's firmware in order to establish JTAG protocol to debug the target chip. Since the ANGIE Adapter has a Spartan-6 FPGA in addition to the FX2 microcontroller, the driver adds two functions, one to download the firmware (embedded C) to the FX2, and the second to program the FPGA with its bitstream. Add ANGIE's configuration file to tcl/interface/ Add the device VID/PID to 60-openocd.rules file. Add ANGIE to OpenOCD's documentation Change-Id: Id17111c74073da01450d43d466e11b0cc086691f Signed-off-by: Ahmed BOUDJELIDA Reviewed-on: https://review.openocd.org/c/openocd/+/7702 Reviewed-by: Antonio Borneo Tested-by: jenkins --- configure.ac | 1 + contrib/60-openocd.rules | 4 + doc/openocd.texi | 7 + src/jtag/drivers/Makefile.am | 8 + src/jtag/drivers/angie.c | 2280 ++++++++++++++++++++ src/jtag/drivers/angie/README | 3 + src/jtag/drivers/angie/angie_bitstream.bit | Bin 0 -> 340702 bytes src/jtag/drivers/angie/angie_firmware.bin | Bin 0 -> 9298 bytes src/jtag/drivers/angie/include/msgtypes.h | 172 ++ src/jtag/interface.h | 1 + src/jtag/interfaces.c | 3 + tcl/interface/angie.cfg | 9 + 12 files changed, 2488 insertions(+) create mode 100644 src/jtag/drivers/angie.c create mode 100644 src/jtag/drivers/angie/README create mode 100644 src/jtag/drivers/angie/angie_bitstream.bit create mode 100644 src/jtag/drivers/angie/angie_firmware.bin create mode 100644 src/jtag/drivers/angie/include/msgtypes.h create mode 100644 tcl/interface/angie.cfg diff --git a/configure.ac b/configure.ac index ac2808e1f5..ecf8384bf8 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,7 @@ m4_define([USB1_ADAPTERS], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], + [[angie], [ANGIE Adapter], [ANGIE]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]], diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index fc35fb9b9e..fd88564bdc 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -224,6 +224,10 @@ ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess" +# ANGIE USB-JTAG Adapter +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="424e", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4a55", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Marvell Sheevaplug ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" diff --git a/doc/openocd.texi b/doc/openocd.texi index 03c5190ada..3348e472b0 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -508,6 +508,9 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @item @b{ARM-JTAG-EW} @* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html} +@item @b{angie} +@* Link: @url{https://nanoxplore.org/} + @item @b{Buspirate} @* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/} @@ -2515,6 +2518,10 @@ Optionally sets that option first. @end deffn @end deffn +@deffn {Interface Driver} {angie} +This is the NanoXplore's ANGIE USB-JTAG Adapter. +@end deffn + @deffn {Interface Driver} {arm-jtag-ew} Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 6410f37545..4b2dbc44db 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -10,8 +10,10 @@ noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la %C%_libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS) ULINK_FIRMWARE = %D%/OpenULINK +ANGIE_FILES = %D%/angie EXTRA_DIST += $(ULINK_FIRMWARE) \ + $(ANGIE_FILES) \ %D%/usb_blaster/README.CheapClone \ %D%/Makefile.rlink \ %D%/rlink_call.m4 \ @@ -123,6 +125,12 @@ ulinkdir = $(pkgdatadir)/OpenULINK dist_ulink_DATA = $(ULINK_FIRMWARE)/ulink_firmware.hex %C%_libocdjtagdrivers_la_LIBADD += -lm endif +if ANGIE +DRIVERFILES += %D%/angie.c +angiedir = $(pkgdatadir)/angie +dist_angie_DATA = $(ANGIE_FILES)/angie_firmware.bin $(ANGIE_FILES)/angie_bitstream.bit +%C%_libocdjtagdrivers_la_LIBADD += -lm +endif if VSLLINK DRIVERFILES += %D%/versaloon/usbtoxxx/usbtogpio.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtojtagraw.c diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c new file mode 100644 index 0000000000..35811fb80c --- /dev/null +++ b/src/jtag/drivers/angie.c @@ -0,0 +1,2280 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*************************************************************************** + File : angie.c * + Contents : OpenOCD driver code for NanoXplore USB-JTAG ANGIE * + adapter hardware. * + Based on openULINK driver code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "helper/system.h" +#include +#include +#include +#include +#include "libusb_helper.h" +#include "angie/include/msgtypes.h" + +/** USB Vendor ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_VID 0x584e + +/** USB Product ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_PID 0x424e +#define ANGIE_PID_2 0x4a55 + +/** Address of EZ-USB ANGIE CPU Control & Status register. This register can be + * written by issuing a Control EP0 vendor request. */ +#define CPUCS_REG 0xE600 + +/** USB Control EP0 bRequest: "Firmware Load". */ +#define REQUEST_FIRMWARE_LOAD 0xA0 + +/** Value to write into CPUCS to put EZ-USB ANGIE into reset. */ +#define CPU_RESET 0x01 + +/** Value to write into CPUCS to put EZ-USB ANGIE out of reset. */ +#define CPU_START 0x00 + +/** Base address of firmware in EZ-USB ANGIE code space. */ +#define FIRMWARE_ADDR 0x0000 + +/** USB interface number */ +#define USB_INTERFACE 0 + +/** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ +#define ANGIE_RENUMERATION_DELAY_US 1500000 + +/** Default location of ANGIE firmware image. */ +#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" + +/** Default location of ANGIE firmware image. */ +#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" + +/** Maximum size of a single firmware section. Entire EZ-USB ANGIE code space = 16kB */ +#define SECTION_BUFFERSIZE 16384 + +/** Tuning of OpenOCD SCAN commands split into multiple ANGIE commands. */ +#define SPLIT_SCAN_THRESHOLD 10 + +/** ANGIE hardware type */ +enum angie_type { + ANGIE, +}; + +enum angie_payload_direction { + PAYLOAD_DIRECTION_OUT, + PAYLOAD_DIRECTION_IN +}; + +enum angie_delay_type { + DELAY_CLOCK_TCK, + DELAY_CLOCK_TMS, + DELAY_SCAN_IN, + DELAY_SCAN_OUT, + DELAY_SCAN_IO +}; + +/** + * ANGIE command (ANGIE command queue element). + * + * For the OUT direction payload, things are quite easy: Payload is stored + * in a rather small array (up to 63 bytes), the payload is always allocated + * by the function generating the command and freed by angie_clear_queue(). + * + * For the IN direction payload, things get a little bit more complicated: + * The maximum IN payload size for a single command is 64 bytes. Assume that + * a single OpenOCD command needs to scan 256 bytes. This results in the + * generation of four ANGIE commands. The function generating these + * commands shall allocate an uint8_t[256] array. Each command's #payload_in + * pointer shall point to the corresponding offset where IN data shall be + * placed, while #payload_in_start shall point to the first element of the 256 + * byte array. + * - first command: #payload_in_start + 0 + * - second command: #payload_in_start + 64 + * - third command: #payload_in_start + 128 + * - fourth command: #payload_in_start + 192 + * + * The last command sets #needs_postprocessing to true. + */ +struct angie_cmd { + uint8_t id; /**< ANGIE command ID */ + + uint8_t *payload_out; /**< Pointer where OUT payload shall be stored */ + uint8_t payload_out_size; /**< OUT direction payload size for this command */ + + uint8_t *payload_in_start; /**< Pointer to first element of IN payload array */ + uint8_t *payload_in; /**< Pointer where IN payload shall be stored */ + uint8_t payload_in_size; /**< IN direction payload size for this command */ + + /** Indicates if this command needs post-processing */ + bool needs_postprocessing; + + /** Indicates if angie_clear_queue() should free payload_in_start */ + bool free_payload_in_start; + + /** Pointer to corresponding OpenOCD command for post-processing */ + struct jtag_command *cmd_origin; + + struct angie_cmd *next; /**< Pointer to next command (linked list) */ +}; + +/** Describes one driver instance */ +struct angie { + struct libusb_context *libusb_ctx; + struct libusb_device_handle *usb_device_handle; + enum angie_type type; + + unsigned int ep_in; /**< IN endpoint number */ + unsigned int ep_out; /**< OUT endpoint number */ + + /* delay value for "SLOW_CLOCK commands" in [0:255] range in units of 4 us; + -1 means no need for delay */ + int delay_scan_in; /**< Delay value for SCAN_IN commands */ + int delay_scan_out; /**< Delay value for SCAN_OUT commands */ + int delay_scan_io; /**< Delay value for SCAN_IO commands */ + int delay_clock_tck; /**< Delay value for CLOCK_TMS commands */ + int delay_clock_tms; /**< Delay value for CLOCK_TCK commands */ + + int commands_in_queue; /**< Number of commands in queue */ + struct angie_cmd *queue_start; /**< Pointer to first command in queue */ + struct angie_cmd *queue_end; /**< Pointer to last command in queue */ +}; + +/**************************** Function Prototypes *****************************/ + +/* USB helper functions */ +static int angie_usb_open(struct angie *device); +static int angie_usb_close(struct angie *device); + +/* ANGIE MCU (Cypress EZ-USB) specific functions */ +static int angie_cpu_reset(struct angie *device, char reset_bit); +static int angie_load_firmware_and_renumerate(struct angie *device, const char *filename, + uint32_t delay_us); +static int angie_load_firmware(struct angie *device, const char *filename); +static int angie_load_bitstream(struct angie *device, const char *filename); + +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index); + +/* Generic helper functions */ +static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals); + +/* ANGIE command generation helper functions */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction); + +/* ANGIE command queue helper functions */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction); +static void angie_clear_queue(struct angie *device); +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd); +static int angie_execute_queued_commands(struct angie *device, int timeout_ms); + +static void angie_dump_queue(struct angie *device); + +static int angie_append_scan_cmd(struct angie *device, + enum scan_type scan_type, + int scan_size_bits, + uint8_t *tdi, + uint8_t *tdo_start, + uint8_t *tdo, + uint8_t tms_count_start, + uint8_t tms_sequence_start, + uint8_t tms_count_end, + uint8_t tms_sequence_end, + struct jtag_command *origin, + bool postprocess); +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence); +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count); +static int angie_append_get_signals_cmd(struct angie *device); +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high); +static int angie_append_sleep_cmd(struct angie *device, uint32_t us); +static int angie_append_configure_tck_cmd(struct angie *device, + int delay_scan_in, + int delay_scan_out, + int delay_scan_io, + int delay_tck, + int delay_tms); +static int angie_append_test_cmd(struct angie *device); + +/* ANGIE TCK frequency helper functions */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay); + +/* Interface between ANGIE and OpenOCD */ +static void angie_set_end_state(tap_state_t endstate); +static int angie_queue_statemove(struct angie *device); + +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd); +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd); +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd); +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd); +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd); +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd); + +static int angie_post_process_scan(struct angie_cmd *angie_cmd); +static int angie_post_process_queue(struct angie *device); + +/* adapter driver functions */ +static int angie_execute_queue(void); +static int angie_khz(int khz, int *jtag_speed); +static int angie_speed(int speed); +static int angie_speed_div(int speed, int *khz); +static int angie_init(void); +static int angie_quit(void); +static int angie_reset(int trst, int srst); + +/****************************** Global Variables ******************************/ + +static struct angie *angie_handle; + +/**************************** USB helper functions ****************************/ + +/** + * Opens the ANGIE device + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_open(struct angie *device) +{ + struct libusb_device_handle *usb_device_handle; + const uint16_t vids[] = {ANGIE_VID, ANGIE_VID, 0}; + const uint16_t pids[] = {ANGIE_PID, ANGIE_PID_2, 0}; + + int ret = jtag_libusb_open(vids, pids, &usb_device_handle, NULL); + + if (ret != ERROR_OK) + return ret; + + device->usb_device_handle = usb_device_handle; + device->type = ANGIE; + + return ERROR_OK; +} + +/** + * Releases the ANGIE interface and closes the USB device handle. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_close(struct angie *device) +{ + if (device->usb_device_handle) { + if (libusb_release_interface(device->usb_device_handle, 0) != 0) + return ERROR_FAIL; + + jtag_libusb_close(device->usb_device_handle); + device->usb_device_handle = NULL; + } + return ERROR_OK; +} + +/******************* ANGIE CPU (EZ-USB) specific functions ********************/ + +/** + * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset + * or out of reset. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_cpu_reset(struct angie *device, char reset_bit) +{ + return jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS, NULL); +} + +/** + * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads + * the firmware image, resumes the microcontroller and re-enumerates + * USB devices. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * The usb_handle member will be modified during re-enumeration. + * @param filename path to the Intel HEX file containing the firmware image. + * @param delay_us the delay to wait for the device to re-enumerate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware_and_renumerate(struct angie *device, + const char *filename, uint32_t delay_us) +{ + int ret; + + /* Basic process: After downloading the firmware, the ANGIE will disconnect + * itself and re-connect after a short amount of time so we have to close + * the handle and re-enumerate USB devices */ + + ret = angie_load_firmware(device, filename); + if (ret != ERROR_OK) + return ret; + + ret = angie_usb_close(device); + if (ret != ERROR_OK) + return ret; + + usleep(delay_us); + + return angie_usb_open(device); +} + +/** + * Downloads a firmware image to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Intel HEX file + * containing the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware(struct angie *device, const char *filename) +{ + struct image angie_firmware_image; + int ret; + + ret = angie_cpu_reset(device, CPU_RESET); + if (ret != ERROR_OK) { + LOG_ERROR("Could not halt ANGIE CPU"); + return ret; + } + + angie_firmware_image.base_address = 0; + angie_firmware_image.base_address_set = false; + + ret = image_open(&angie_firmware_image, filename, "bin"); + if (ret != ERROR_OK) { + LOG_ERROR("Could not load firmware image"); + return ret; + } + + /* Download all sections in the image to ANGIE */ + for (unsigned int i = 0; i < angie_firmware_image.num_sections; i++) { + ret = angie_write_firmware_section(device, &angie_firmware_image, i); + if (ret != ERROR_OK) + return ret; + } + + image_close(&angie_firmware_image); + + ret = angie_cpu_reset(device, CPU_START); + if (ret != ERROR_OK) { + LOG_ERROR("Could not restart ANGIE CPU"); + return ret; + } + + return ERROR_OK; +} + +/** + * Downloads a bitstream file to the ANGIE's FPGA through the EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Xilinx .bit file + * containing the bitstream data. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_bitstream(struct angie *device, const char *filename) +{ + int ret, transferred; + const char *bitstream_file_path = filename; + FILE *bitstream_file = NULL; + char *bitstream_data = NULL; + size_t bitstream_size = 0; + + /* CFGopen */ + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB0, 0, 0, NULL, 0, LIBUSB_TIMEOUT_MS, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Failed opencfg"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + /* Open the bitstream file */ + bitstream_file = fopen(bitstream_file_path, "rb"); + if (!bitstream_file) { + LOG_ERROR("Failed to open bitstream file: %s\n", bitstream_file_path); + return ERROR_FAIL; + } + + /* Get the size of the bitstream file */ + fseek(bitstream_file, 0, SEEK_END); + bitstream_size = ftell(bitstream_file); + fseek(bitstream_file, 0, SEEK_SET); + + /* Allocate memory for the bitstream data */ + bitstream_data = malloc(bitstream_size); + if (!bitstream_data) { + LOG_ERROR("Failed to allocate memory for bitstream data."); + fclose(bitstream_file); + return ERROR_FAIL; + } + + /* Read the bitstream data from the file */ + if (fread(bitstream_data, 1, bitstream_size, bitstream_file) != bitstream_size) { + LOG_ERROR("Failed to read bitstream data."); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + } + + /* Send the bitstream data to the microcontroller */ + int actual_length = 0; + ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x02, bitstream_data, bitstream_size, 1000, &actual_length); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to send bitstream data: %s", libusb_strerror(ret)); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + } + + LOG_INFO("Bitstream sent successfully."); + + /* Clean up */ + free(bitstream_data); + fclose(bitstream_file); + + /* CFGclose */ + transferred = 0; + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB1, 0, 0, NULL, 0, LIBUSB_TIMEOUT_MS, &transferred); + if (ret != ERROR_OK) { + LOG_INFO("error cfgclose"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** + * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param firmware_image pointer to the firmware image that contains the section + * which should be sent to the ANGIE's EZ-USB microcontroller. + * @param section_index index of the section within the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index) +{ + int addr, bytes_remaining, chunk_size; + uint8_t data[SECTION_BUFFERSIZE]; + uint8_t *data_ptr = data; + uint16_t size; + size_t size_read; + int ret, transferred; + + size = (uint16_t)firmware_image->sections[section_index].size; + addr = (uint16_t)firmware_image->sections[section_index].base_address; + + LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx16 ")", section_index, addr, + size); + + /* Copy section contents to local buffer */ + ret = image_read_section(firmware_image, section_index, 0, size, data, + &size_read); + + if (ret != ERROR_OK) + return ret; + if (size_read != size) + return ERROR_FAIL; + + bytes_remaining = size; + + /* Send section data in chunks of up to 64 bytes to ANGIE */ + while (bytes_remaining > 0) { + if (bytes_remaining > 64) + chunk_size = 64; + else + chunk_size = bytes_remaining; + + ret = jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (char *)data_ptr, + chunk_size, LIBUSB_TIMEOUT_MS, &transferred); + + if (ret != ERROR_OK) + return ret; + + if (transferred != chunk_size) { + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + bytes_remaining -= chunk_size; + addr += chunk_size; + data_ptr += chunk_size; + } + + return ERROR_OK; +} + +/************************** Generic helper functions **************************/ + +/** + * Print state of interesting signals via LOG_INFO(). + * + * @param input_signals input signal states as returned by CMD_GET_SIGNALS + * @param output_signals output signal states as returned by CMD_GET_SIGNALS + */ +static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals) +{ + LOG_INFO("ANGIE signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i " + "SRST: %i", + (output_signals & SIGNAL_TDI ? 1 : 0), + (input_signals & SIGNAL_TDO ? 1 : 0), + (output_signals & SIGNAL_TMS ? 1 : 0), + (output_signals & SIGNAL_TCK ? 1 : 0), + (output_signals & SIGNAL_TRST ? 1 : 0), + (output_signals & SIGNAL_SRST ? 1 : 0)); +} + +/**************** ANGIE command generation helper functions ***************/ + +/** + * Allocate and initialize space in memory for ANGIE command payload. + * + * @param angie_cmd pointer to command whose payload should be allocated. + * @param size the amount of memory to allocate (bytes). + * @param direction which payload to allocate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction) +{ + uint8_t *payload; + + payload = calloc(size, sizeof(uint8_t)); + + if (!payload) { + LOG_ERROR("Could not allocate ANGIE command payload: out of memory"); + return ERROR_FAIL; + } + + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + if (angie_cmd->payload_out) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } + angie_cmd->payload_out = payload; + angie_cmd->payload_out_size = size; + break; + case PAYLOAD_DIRECTION_IN: + if (angie_cmd->payload_in_start) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } + + angie_cmd->payload_in_start = payload; + angie_cmd->payload_in = payload; + angie_cmd->payload_in_size = size; + + /* By default, free payload_in_start in angie_clear_queue(). Commands + * that do not want this behavior (e. g. split scans) must turn it off + * separately! */ + angie_cmd->free_payload_in_start = true; + + break; + } + + return ERROR_OK; +} + +/****************** ANGIE command queue helper functions ******************/ + +/** + * Get the current number of bytes in the queue, including command IDs. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param direction the transfer direction for which to get byte count. + * @return the number of bytes currently stored in the queue for the specified + * direction. + */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction) +{ + struct angie_cmd *current = device->queue_start; + int sum = 0; + + while (current) { + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ + break; + case PAYLOAD_DIRECTION_IN: + sum += current->payload_in_size; + break; + } + + current = current->next; + } + + return sum; +} + +/** + * Clear the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_clear_queue(struct angie *device) +{ + struct angie_cmd *current = device->queue_start; + struct angie_cmd *next = NULL; + + while (current) { + /* Save pointer to next element */ + next = current->next; + + /* Free payloads: OUT payload can be freed immediately */ + free(current->payload_out); + current->payload_out = NULL; + + /* IN payload MUST be freed ONLY if no other commands use the + * payload_in_start buffer */ + if (current->free_payload_in_start) { + free(current->payload_in_start); + current->payload_in_start = NULL; + current->payload_in = NULL; + } + + /* Free queue element */ + free(current); + + /* Proceed with next element */ + current = next; + } + + device->commands_in_queue = 0; + device->queue_start = NULL; + device->queue_end = NULL; +} + +/** + * Add a command to the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param angie_cmd pointer to command that shall be appended to the ANGIE + * command queue. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd) +{ + int newsize_out, newsize_in; + int ret = ERROR_OK; + + newsize_out = angie_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + + angie_cmd->payload_out_size; + + newsize_in = angie_get_queue_size(device, PAYLOAD_DIRECTION_IN) + + angie_cmd->payload_in_size; + + /* Check if the current command can be appended to the queue */ + if (newsize_out > 64 || newsize_in > 64) { + /* New command does not fit. Execute all commands in queue before starting + * new queue with the current command as first entry. */ + ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); + + if (ret == ERROR_OK) + ret = angie_post_process_queue(device); + + if (ret == ERROR_OK) + angie_clear_queue(device); + } + + if (!device->queue_start) { + /* Queue was empty */ + device->commands_in_queue = 1; + + device->queue_start = angie_cmd; + device->queue_end = angie_cmd; + } else { + /* There are already commands in the queue */ + device->commands_in_queue++; + + device->queue_end->next = angie_cmd; + device->queue_end = angie_cmd; + } + + if (ret != ERROR_OK) + angie_clear_queue(device); + + return ret; +} + +/** + * Sends all queued ANGIE commands to the ANGIE for execution. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param timeout_ms + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queued_commands(struct angie *device, int timeout_ms) +{ + struct angie_cmd *current; + int ret, i, index_out, index_in, count_out, count_in, transferred; + uint8_t buffer[64]; + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) + angie_dump_queue(device); + + index_out = 0; + count_out = 0; + count_in = 0; + + for (current = device->queue_start; current; current = current->next) { + /* Add command to packet */ + buffer[index_out] = current->id; + index_out++; + count_out++; + + for (i = 0; i < current->payload_out_size; i++) + buffer[index_out + i] = current->payload_out[i]; + index_out += current->payload_out_size; + count_in += current->payload_in_size; + count_out += current->payload_out_size; + } + + /* Send packet to ANGIE */ + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_out, + (char *)buffer, count_out, timeout_ms, &transferred); + if (ret != ERROR_OK) + return ret; + if (transferred != count_out) + return ERROR_FAIL; + + /* Wait for response if commands contain IN payload data */ + if (count_in > 0) { + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_in, + (char *)buffer, count_in, timeout_ms, &transferred); + if (ret != ERROR_OK) + return ret; + if (transferred != count_in) + return ERROR_FAIL; + + /* Write back IN payload data */ + index_in = 0; + for (current = device->queue_start; current; current = current->next) { + for (i = 0; i < current->payload_in_size; i++) { + current->payload_in[i] = buffer[index_in]; + index_in++; + } + } + } + return ERROR_OK; +} + +/** + * Convert an ANGIE command ID (\a id) to a human-readable string. + * + * @param id the ANGIE command ID. + * @return the corresponding human-readable string. + */ +static const char *angie_cmd_id_string(uint8_t id) +{ + switch (id) { + case CMD_SCAN_IN: + return "CMD_SCAN_IN"; + case CMD_SLOW_SCAN_IN: + return "CMD_SLOW_SCAN_IN"; + case CMD_SCAN_OUT: + return "CMD_SCAN_OUT"; + case CMD_SLOW_SCAN_OUT: + return "CMD_SLOW_SCAN_OUT"; + case CMD_SCAN_IO: + return "CMD_SCAN_IO"; + case CMD_SLOW_SCAN_IO: + return "CMD_SLOW_SCAN_IO"; + case CMD_CLOCK_TMS: + return "CMD_CLOCK_TMS"; + case CMD_SLOW_CLOCK_TMS: + return "CMD_SLOW_CLOCK_TMS"; + case CMD_CLOCK_TCK: + return "CMD_CLOCK_TCK"; + case CMD_SLOW_CLOCK_TCK: + return "CMD_SLOW_CLOCK_TCK"; + case CMD_SLEEP_US: + return "CMD_SLEEP_US"; + case CMD_SLEEP_MS: + return "CMD_SLEEP_MS"; + case CMD_GET_SIGNALS: + return "CMD_GET_SIGNALS"; + case CMD_SET_SIGNALS: + return "CMD_SET_SIGNALS"; + case CMD_CONFIGURE_TCK_FREQ: + return "CMD_CONFIGURE_TCK_FREQ"; + case CMD_SET_LEDS: + return "CMD_SET_LEDS"; + case CMD_TEST: + return "CMD_TEST"; + default: + return "CMD_UNKNOWN"; + } +} + +/** + * Print one ANGIE command to stdout. + * + * @param angie_cmd pointer to ANGIE command. + */ +static void angie_dump_command(struct angie_cmd *angie_cmd) +{ + char hex[64 * 3]; + for (int i = 0; i < angie_cmd->payload_out_size; i++) + sprintf(hex + 3 * i, "%02" PRIX8 " ", angie_cmd->payload_out[i]); + + hex[3 * angie_cmd->payload_out_size - 1] = 0; + LOG_DEBUG_IO(" %-22s | OUT size = %" PRIi8 ", bytes = %s", + angie_cmd_id_string(angie_cmd->id), angie_cmd->payload_out_size, hex); + + LOG_DEBUG_IO("\n | IN size = %" PRIi8 "\n", angie_cmd->payload_in_size); +} + +/** + * Print the ANGIE command queue to stdout. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_dump_queue(struct angie *device) +{ + struct angie_cmd *current; + + LOG_DEBUG_IO("ANGIE command queue:\n"); + + for (current = device->queue_start; current; current = current->next) + angie_dump_command(current); +} + +/** + * Perform JTAG scan + * + * Creates and appends a JTAG scan command to the ANGIE command queue. + * A JTAG scan consists of three steps: + * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). + * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. + * - Move to the desired end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). + * @param scan_size_bits number of bits to shift into the JTAG chain. + * @param tdi pointer to array containing TDI data. + * @param tdo_start pointer to first element of array where TDO data shall be + * stored. See #angie_cmd for details. + * @param tdo pointer to array where TDO data shall be stored + * @param tms_count_start number of TMS state transitions to perform BEFORE + * shifting data into the JTAG chain. + * @param tms_sequence_start sequence of TMS state transitions that will be + * performed BEFORE shifting data into the JTAG chain. + * @param tms_count_end number of TMS state transitions to perform AFTER + * shifting data into the JTAG chain. + * @param tms_sequence_end sequence of TMS state transitions that will be + * performed AFTER shifting data into the JTAG chain. + * @param origin pointer to OpenOCD command that generated this scan command. + * @param postprocess whether this command needs to be post-processed after + * execution. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_scan_cmd(struct angie *device, enum scan_type scan_type, + int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, + uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, + uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret, i, scan_size_bytes; + uint8_t bits_last_byte; + + if (!cmd) + return ERROR_FAIL; + + /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, + * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ + if (scan_size_bits > (58 * 8)) { + LOG_ERROR("BUG: Tried to create CMD_SCAN_IO ANGIE command with too" + " large payload"); + free(cmd); + return ERROR_FAIL; + } + + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + bits_last_byte = scan_size_bits % 8; + if (bits_last_byte == 0) + bits_last_byte = 8; + + /* Allocate out_payload depending on scan type */ + switch (scan_type) { + case SCAN_IN: + if (device->delay_scan_in < 0) + cmd->id = CMD_SCAN_IN; + else + cmd->id = CMD_SLOW_SCAN_IN; + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_IN); + break; + case SCAN_OUT: + if (device->delay_scan_out < 0) + cmd->id = CMD_SCAN_OUT; + else + cmd->id = CMD_SLOW_SCAN_OUT; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_IO: + if (device->delay_scan_io < 0) + cmd->id = CMD_SCAN_IO; + else + cmd->id = CMD_SLOW_SCAN_IO; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + default: + LOG_ERROR("BUG: 'append scan cmd' encountered an unknown scan type"); + ret = ERROR_FAIL; + break; + } + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + /* Build payload_out that is common to all scan types */ + cmd->payload_out[0] = scan_size_bytes & 0xFF; + cmd->payload_out[1] = bits_last_byte & 0xFF; + cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); + cmd->payload_out[3] = tms_sequence_start; + cmd->payload_out[4] = tms_sequence_end; + + /* Setup payload_out for types with OUT transfer */ + if (scan_type == SCAN_OUT || scan_type == SCAN_IO) { + for (i = 0; i < scan_size_bytes; i++) + cmd->payload_out[i + 5] = tdi[i]; + } + + /* Setup payload_in pointers for types with IN transfer */ + if (scan_type == SCAN_IN || scan_type == SCAN_IO) { + cmd->payload_in_start = tdo_start; + cmd->payload_in = tdo; + cmd->payload_in_size = scan_size_bytes; + } + + cmd->needs_postprocessing = postprocess; + cmd->cmd_origin = origin; + + /* For scan commands, we free payload_in_start only when the command is + * the last in a series of split commands or a stand-alone command */ + cmd->free_payload_in_start = postprocess; + + return angie_append_queue(device, cmd); +} + +/** + * Perform TAP state transitions + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count defines the number of TCK clock cycles generated (up to 8). + * @param sequence defines the TMS pin levels for each state transition. The + * Least-Significant Bit is read first. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + if (device->delay_clock_tms < 0) + cmd->id = CMD_CLOCK_TMS; + else + cmd->id = CMD_SLOW_CLOCK_TMS; + + /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count; + cmd->payload_out[1] = sequence; + + return angie_append_queue(device, cmd); +} + +/** + * Generate a defined amount of TCK clock cycles + * + * All other JTAG signals are left unchanged. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count the number of TCK clock cycles to generate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + if (device->delay_clock_tck < 0) + cmd->id = CMD_CLOCK_TCK; + else + cmd->id = CMD_SLOW_CLOCK_TCK; + + /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count & 0xff; + cmd->payload_out[1] = (count >> 8) & 0xff; + + return angie_append_queue(device, cmd); +} + +/** + * Read JTAG signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_get_signals_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_GET_SIGNALS; + cmd->needs_postprocessing = true; + + /* CMD_GET_SIGNALS has two IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + return angie_append_queue(device, cmd); +} + +/** + * Arbitrarily set JTAG output signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param low defines which signals will be de-asserted. Each bit corresponds + * to a JTAG signal: + * - SIGNAL_TDI + * - SIGNAL_TMS + * - SIGNAL_TCK + * - SIGNAL_TRST + * - SIGNAL_BRKIN + * - SIGNAL_RESET + * - SIGNAL_OCDSE + * @param high defines which signals will be asserted. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_SET_SIGNALS; + + /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = low; + cmd->payload_out[1] = high; + + return angie_append_queue(device, cmd); +} + +/** + * Sleep for a pre-defined number of microseconds + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param us the number microseconds to sleep. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_sleep_cmd(struct angie *device, uint32_t us) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_SLEEP_US; + + /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = us & 0x00ff; + cmd->payload_out[1] = (us >> 8) & 0x00ff; + + return angie_append_queue(device, cmd); +} + +/** + * Set TCK delay counters + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. + * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. + * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. + * @param delay_tck delay count top value in jtag_clock_tck() function. + * @param delay_tms delay count top value in jtag_slow_clock_tms() function. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_configure_tck_cmd(struct angie *device, int delay_scan_in, + int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_CONFIGURE_TCK_FREQ; + + /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero + * IN payload bytes */ + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + if (delay_scan_in < 0) + cmd->payload_out[0] = 0; + else + cmd->payload_out[0] = (uint8_t)delay_scan_in; + + if (delay_scan_out < 0) + cmd->payload_out[1] = 0; + else + cmd->payload_out[1] = (uint8_t)delay_scan_out; + + if (delay_scan_io < 0) + cmd->payload_out[2] = 0; + else + cmd->payload_out[2] = (uint8_t)delay_scan_io; + + if (delay_tck < 0) + cmd->payload_out[3] = 0; + else + cmd->payload_out[3] = (uint8_t)delay_tck; + + if (delay_tms < 0) + cmd->payload_out[4] = 0; + else + cmd->payload_out[4] = (uint8_t)delay_tms; + + return angie_append_queue(device, cmd); +} + +/** + * Test command. Used to check if the ANGIE device is ready to accept new + * commands. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_test_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_TEST; + + /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = 0xAA; + + return angie_append_queue(device, cmd); +} + +/****************** ANGIE TCK frequency helper functions ******************/ + +/** + * Calculate delay values for a given TCK frequency. + * + * The ANGIE firmware uses five different speed values for different + * commands. These speed values are calculated in these functions. + * + * The five different commands which support variable TCK frequency are + * implemented twice in the firmware: + * 1. Maximum possible frequency without any artificial delay + * 2. Variable frequency with artificial linear delay loop + * + * To set the ANGIE to maximum frequency, it is only necessary to use the + * corresponding command IDs. To set the ANGIE to a lower frequency, the + * delay loop top values have to be calculated first. Then, a + * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ANGIE device. + * + * The delay values are described by linear equations: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * Thus, the delay can be calculated as in the following equation: + * x = (t - d) / k + * + * The constants in these equations have been determined and validated by + * measuring the frequency resulting from different delay values. + * + * @param type for which command to calculate the delay value. + * @param f TCK frequency for which to calculate the delay value in Hz. + * @param delay where to store resulting delay value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay) +{ + float t_us, x, x_ceil; + + /* Calculate period of requested TCK frequency */ + t_us = 1000000.0 / f; + + switch (type) { + case DELAY_CLOCK_TCK: + x = (t_us - 6.0) / 4; + break; + case DELAY_CLOCK_TMS: + x = (t_us - 8.5) / 4; + break; + case DELAY_SCAN_IN: + x = (t_us - 8.8308) / 4; + break; + case DELAY_SCAN_OUT: + x = (t_us - 10.527) / 4; + break; + case DELAY_SCAN_IO: + x = (t_us - 13.132) / 4; + break; + default: + return ERROR_FAIL; + break; + } + + /* Check if the delay value is negative. This happens when a frequency is + * requested that is too high for the delay loop implementation. In this + * case, set delay value to zero. */ + if (x < 0) + x = 0; + + /* We need to convert the exact delay value to an integer. Therefore, we + * round the exact value UP to ensure that the resulting frequency is NOT + * higher than the requested frequency. */ + x_ceil = ceilf(x); + + /* Check if the value is within limits */ + if (x_ceil > 255) + return ERROR_FAIL; + + *delay = (int)x_ceil; + + return ERROR_OK; +} + +/** + * Calculate frequency for a given delay value. + * + * Similar to the #angie_calculate_delay function, this function calculates the + * TCK frequency for a given delay value by using linear equations of the form: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * @param type for which command to calculate the delay value. + * @param delay value for which to calculate the resulting TCK frequency. + * @return the resulting TCK frequency + */ +static long angie_calculate_frequency(enum angie_delay_type type, int delay) +{ + float t_us, f_float; + + if (delay > 255) + return 0; + + switch (type) { + case DELAY_CLOCK_TCK: + if (delay < 0) + t_us = 2.666; + else + t_us = (4.0 * delay) + 6.0; + break; + case DELAY_CLOCK_TMS: + if (delay < 0) + t_us = 5.666; + else + t_us = (4.0 * delay) + 8.5; + break; + case DELAY_SCAN_IN: + if (delay < 0) + t_us = 5.5; + else + t_us = (4.0 * delay) + 8.8308; + break; + case DELAY_SCAN_OUT: + if (delay < 0) + t_us = 7.0; + else + t_us = (4.0 * delay) + 10.527; + break; + case DELAY_SCAN_IO: + if (delay < 0) + t_us = 9.926; + else + t_us = (4.0 * delay) + 13.132; + break; + default: + return 0; + } + + f_float = 1000000.0 / t_us; + return roundf(f_float); +} + +/******************* Interface between ANGIE and OpenOCD ******************/ + +/** + * Sets the end state follower (see interface.h) if \a endstate is a stable + * state. + * + * @param endstate the state the end state follower should be set to. + */ +static void angie_set_end_state(tap_state_t endstate) +{ + if (tap_is_state_stable(endstate)) + tap_set_end_state(endstate); + else + LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); +} + +/** + * Move from the current TAP state to the current TAP end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_statemove(struct angie *device) +{ + uint8_t tms_sequence, tms_count; + int ret; + + if (tap_get_state() == tap_get_end_state()) { + /* Do nothing if we are already there */ + return ERROR_OK; + } + + tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + ret = angie_append_clock_tms_cmd(device, tms_count, tms_sequence); + + if (ret == ERROR_OK) + tap_set_state(tap_get_end_state()); + + return ret; +} + +/** + * Perform a scan operation on a JTAG register. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd) +{ + uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; + uint32_t scans_max_payload, bytecount; + uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; + uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; + + uint8_t first_tms_count, first_tms_sequence; + uint8_t last_tms_count, last_tms_sequence; + + uint8_t tms_count_pause, tms_sequence_pause; + uint8_t tms_count_resume, tms_sequence_resume; + + uint8_t tms_count_start, tms_sequence_start; + uint8_t tms_count_end, tms_sequence_end; + + enum scan_type type; + int ret; + + /* Determine scan size */ + scan_size_bits = jtag_scan_size(cmd->cmd.scan); + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + /* Determine scan type (IN/OUT/IO) */ + type = jtag_scan_type(cmd->cmd.scan); + + /* Determine number of scan commands with maximum payload */ + scans_max_payload = scan_size_bytes / 58; + + /* Determine size of last shift command */ + bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); + + /* Allocate TDO buffer if required */ + if (type == SCAN_IN || type == SCAN_IO) { + tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); + + if (!tdo_buffer_start) + return ERROR_FAIL; + + tdo_buffer = tdo_buffer_start; + } + + /* Fill TDI buffer if required */ + if (type == SCAN_OUT || type == SCAN_IO) { + jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); + tdi_buffer = tdi_buffer_start; + } + + /* Get TAP state transitions */ + if (cmd->cmd.scan->ir_scan) { + angie_set_end_state(TAP_IRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_IRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); + } else { + angie_set_end_state(TAP_DRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_DRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); + } + + /* Generate scan commands */ + bytecount = scan_size_bytes; + while (bytecount > 0) { + if (bytecount == scan_size_bytes) { + /* This is the first scan */ + tms_count_start = first_tms_count; + tms_sequence_start = first_tms_sequence; + } else { + /* Resume from previous scan */ + tms_count_start = tms_count_resume; + tms_sequence_start = tms_sequence_resume; + } + + if (bytecount > 58) { /* Full scan, at least one scan will follow */ + tms_count_end = tms_count_pause; + tms_sequence_end = tms_sequence_pause; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + false); + + bytecount -= 58; + + /* Update TDI and TDO buffer pointers */ + if (tdi_buffer_start) + tdi_buffer += 58; + if (tdo_buffer_start) + tdo_buffer += 58; + } else if (bytecount == 58) { /* Full scan, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } else {/* Scan with less than maximum payload, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + bits_last_scan, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } + + if (ret != ERROR_OK) { + free(tdi_buffer_start); + free(tdo_buffer_start); + return ret; + } + } + + free(tdi_buffer_start); + + /* Set current state to the end state requested by the command */ + tap_set_state(cmd->cmd.scan->end_state); + + return ERROR_OK; +} + +/** + * Move the TAP into the Test Logic Reset state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd) +{ + int ret = angie_append_clock_tms_cmd(device, 5, 0xff); + + if (ret == ERROR_OK) + tap_set_state(TAP_RESET); + + return ret; +} + +/** + * Run Test. + * + * Generate TCK clock cycles while remaining + * in the Run-Test/Idle state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd) +{ + int ret; + + /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ + if (tap_get_state() != TAP_IDLE) { + angie_set_end_state(TAP_IDLE); + angie_queue_statemove(device); + } + + /* Generate the clock cycles */ + ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); + if (ret != ERROR_OK) + return ret; + + /* Move to end state specified in command */ + if (cmd->cmd.runtest->end_state != tap_get_state()) { + tap_set_end_state(cmd->cmd.runtest->end_state); + angie_queue_statemove(device); + } + + return ERROR_OK; +} + +/** + * Execute a JTAG_RESET command + * + * @param device + * @param trst indicate if trst signal is activated. + * @param srst indicate if srst signal is activated. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_reset(int trst, int srst) +{ + struct angie *device = angie_handle; + uint8_t low = 0, high = 0; + + if (trst) { + tap_set_state(TAP_RESET); + low |= SIGNAL_TRST; + } else { + high |= SIGNAL_TRST; + } + + if (srst) + low |= SIGNAL_SRST; + else + high |= SIGNAL_SRST; + + int ret = angie_append_set_signals_cmd(device, low, high); + + ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); + if (ret == ERROR_OK) + angie_clear_queue(device); + + return ret; +} + +/** + * Move to one TAP state or several states in succession. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) +{ + int ret, i, num_states, batch_size, state_count; + tap_state_t *path; + uint8_t tms_sequence; + + num_states = cmd->cmd.pathmove->num_states; + path = cmd->cmd.pathmove->path; + state_count = 0; + + while (num_states > 0) { + tms_sequence = 0; + + /* Determine batch size */ + if (num_states >= 8) + batch_size = 8; + else + batch_size = num_states; + + for (i = 0; i < batch_size; i++) { + if (tap_state_transition(tap_get_state(), false) == path[state_count]) { + /* Append '0' transition: clear bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x0); + } else if (tap_state_transition(tap_get_state(), true) + == path[state_count]) { + /* Append '1' transition: set bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x1); + } else { + /* Invalid state transition */ + LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", + tap_state_name(tap_get_state()), + tap_state_name(path[state_count])); + return ERROR_FAIL; + } + + tap_set_state(path[state_count]); + state_count++; + num_states--; + } + + /* Append CLOCK_TMS command to ANGIE command queue */ + LOG_INFO("pathmove batch: count = %i, sequence = 0x%" PRIx8 "", batch_size, tms_sequence); + ret = angie_append_clock_tms_cmd(angie_handle, batch_size, tms_sequence); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Sleep for a specific amount of time. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) +{ + /* IMPORTANT! Due to the time offset in command execution introduced by + * command queueing, this needs to be implemented in the ANGIE device */ + return angie_append_sleep_cmd(device, cmd->cmd.sleep->us); +} + +/** + * Generate TCK cycles while remaining in a stable state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + */ +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) +{ + int ret; + unsigned int num_cycles; + + if (!tap_is_state_stable(tap_get_state())) { + LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); + return ERROR_FAIL; + } + + num_cycles = cmd->cmd.stableclocks->num_cycles; + + /* TMS stays either high (Test Logic Reset state) or low (all other states) */ + if (tap_get_state() == TAP_RESET) + ret = angie_append_set_signals_cmd(device, 0, SIGNAL_TMS); + else + ret = angie_append_set_signals_cmd(device, SIGNAL_TMS, 0); + + if (ret != ERROR_OK) + return ret; + + while (num_cycles > 0) { + if (num_cycles > 0xFFFF) { + /* ANGIE CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ + ret = angie_append_clock_tck_cmd(device, 0xFFFF); + num_cycles -= 0xFFFF; + } else { + ret = angie_append_clock_tck_cmd(device, num_cycles); + num_cycles = 0; + } + + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Post-process JTAG_SCAN command + * + * @param angie_cmd pointer to ANGIE command that shall be processed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_scan(struct angie_cmd *angie_cmd) +{ + struct jtag_command *cmd = angie_cmd->cmd_origin; + int ret; + + switch (jtag_scan_type(cmd->cmd.scan)) { + case SCAN_IN: + case SCAN_IO: + ret = jtag_read_buffer(angie_cmd->payload_in_start, cmd->cmd.scan); + break; + case SCAN_OUT: + /* Nothing to do for OUT scans */ + ret = ERROR_OK; + break; + default: + LOG_ERROR("BUG: angie post process scan encountered an unknown JTAG scan type"); + ret = ERROR_FAIL; + break; + } + + return ret; +} + +/** + * Perform post-processing of commands after ANGIE queue has been executed. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_queue(struct angie *device) +{ + struct angie_cmd *current; + struct jtag_command *openocd_cmd; + int ret; + + current = device->queue_start; + + while (current) { + openocd_cmd = current->cmd_origin; + + /* Check if a corresponding OpenOCD command is stored for this + * ANGIE command */ + if (current->needs_postprocessing && openocd_cmd) { + switch (openocd_cmd->type) { + case JTAG_SCAN: + ret = angie_post_process_scan(current); + break; + case JTAG_TLR_RESET: + case JTAG_RUNTEST: + case JTAG_PATHMOVE: + case JTAG_SLEEP: + case JTAG_STABLECLOCKS: + /* Nothing to do for these commands */ + ret = ERROR_OK; + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: angie post process queue encountered unknown JTAG " + "command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + } + + current = current->next; + } + + return ERROR_OK; +} + +/**************************** JTAG driver functions ***************************/ + +/** + * Executes the JTAG Command Queue. + * + * This is done in three stages: First, all OpenOCD commands are processed into + * queued ANGIE commands. Next, the ANGIE command queue is sent to the + * ANGIE device and data received from the ANGIE device is cached. Finally, + * the post-processing function writes back data to the corresponding OpenOCD + * commands. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + int ret; + + while (cmd) { + switch (cmd->type) { + case JTAG_SCAN: + ret = angie_queue_scan(angie_handle, cmd); + break; + case JTAG_TLR_RESET: + ret = angie_queue_tlr_reset(angie_handle, cmd); + break; + case JTAG_RUNTEST: + ret = angie_queue_runtest(angie_handle, cmd); + break; + case JTAG_PATHMOVE: + ret = angie_queue_pathmove(angie_handle, cmd); + break; + case JTAG_SLEEP: + ret = angie_queue_sleep(angie_handle, cmd); + break; + case JTAG_STABLECLOCKS: + ret = angie_queue_stableclocks(angie_handle, cmd); + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: encountered unknown JTAG command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + + cmd = cmd->next; + } + + if (angie_handle->commands_in_queue > 0) { + ret = angie_execute_queued_commands(angie_handle, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) + return ret; + + ret = angie_post_process_queue(angie_handle); + if (ret != ERROR_OK) + return ret; + + angie_clear_queue(angie_handle); + } + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * @param khz desired JTAG TCK frequency. + * @param jtag_speed where to store corresponding adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_khz(int khz, int *jtag_speed) +{ + int ret; + + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency + * setting can be done independently from all other commands. */ + if (khz >= 375) { + angie_handle->delay_clock_tck = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, + &angie_handle->delay_clock_tck); + if (ret != ERROR_OK) + return ret; + } + + /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the + * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS + * commands, all SCAN commands MUST also use the variable frequency + * implementation! */ + if (khz >= 176) { + angie_handle->delay_clock_tms = -1; + angie_handle->delay_scan_in = -1; + angie_handle->delay_scan_out = -1; + angie_handle->delay_scan_io = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, + &angie_handle->delay_clock_tms); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IN, khz * 1000, + &angie_handle->delay_scan_in); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_OUT, khz * 1000, + &angie_handle->delay_scan_out); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IO, khz * 1000, + &angie_handle->delay_scan_io); + if (ret != ERROR_OK) + return ret; + } + + LOG_DEBUG_IO("ANGIE TCK setup: delay_tck = %i (%li Hz),", + angie_handle->delay_clock_tck, + angie_calculate_frequency(DELAY_CLOCK_TCK, angie_handle->delay_clock_tck)); + LOG_DEBUG_IO(" delay_tms = %i (%li Hz),", + angie_handle->delay_clock_tms, + angie_calculate_frequency(DELAY_CLOCK_TMS, angie_handle->delay_clock_tms)); + LOG_DEBUG_IO(" delay_scan_in = %i (%li Hz),", + angie_handle->delay_scan_in, + angie_calculate_frequency(DELAY_SCAN_IN, angie_handle->delay_scan_in)); + LOG_DEBUG_IO(" delay_scan_out = %i (%li Hz),", + angie_handle->delay_scan_out, + angie_calculate_frequency(DELAY_SCAN_OUT, angie_handle->delay_scan_out)); + LOG_DEBUG_IO(" delay_scan_io = %i (%li Hz),", + angie_handle->delay_scan_io, + angie_calculate_frequency(DELAY_SCAN_IO, angie_handle->delay_scan_io)); + + /* Configure the ANGIE device with the new delay values */ + ret = angie_append_configure_tck_cmd(angie_handle, + angie_handle->delay_scan_in, + angie_handle->delay_scan_out, + angie_handle->delay_scan_io, + angie_handle->delay_clock_tck, + angie_handle->delay_clock_tms); + + if (ret != ERROR_OK) + return ret; + + *jtag_speed = khz; + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed desired adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed(int speed) +{ + int dummy; + + return angie_khz(speed, &dummy); +} + +/** + * Convert adapter-specific speed value to corresponding TCK frequency in kHz. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed adapter-specific speed value. + * @param khz where to store corresponding TCK frequency in kHz. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} + +/** + * Initiates the firmware download to the ANGIE adapter and prepares + * the USB handle. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_init(void) +{ + int ret, transferred; + char str_manufacturer[20]; + bool download_firmware = false; + char dummy[64]; + uint8_t input_signals, output_signals; + + angie_handle = calloc(1, sizeof(struct angie)); + + if (!angie_handle) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + ret = angie_usb_open(angie_handle); + if (ret != ERROR_OK) { + LOG_ERROR("Could not open ANGIE device"); + free(angie_handle); + angie_handle = NULL; + return ret; + } + + /* Get String Descriptor to determine if firmware needs to be loaded */ + ret = libusb_get_string_descriptor_ascii(angie_handle->usb_device_handle, 1, (unsigned char *)str_manufacturer, 20); + if (ret < 0) { + /* Could not get descriptor -> Unconfigured or original Keil firmware */ + download_firmware = true; + } else { + /* We got a String Descriptor, check if it is the correct one */ + if (strncmp(str_manufacturer, "NanoXplore, SAS.", 16) != 0) + download_firmware = true; + } + + if (download_firmware) { + LOG_INFO("Loading ANGIE firmware. This is reversible by power-cycling ANGIE device."); + + if (libusb_claim_interface(angie_handle->usb_device_handle, 0) != ERROR_OK) + LOG_ERROR("Could not claim interface"); + + ret = angie_load_firmware_and_renumerate(angie_handle, + ANGIE_FIRMWARE_FILE, ANGIE_RENUMERATION_DELAY_US); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download firmware and re-numerate ANGIE"); + angie_quit(); + return ret; + } + ret = angie_load_bitstream(angie_handle, ANGIE_BITSTREAM_FILE); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download bitstream"); + angie_quit(); + return ret; + } + } else { + LOG_INFO("ANGIE device is already running ANGIE firmware"); + } + + /* Get ANGIE USB IN/OUT endpoints and claim the interface */ + ret = jtag_libusb_choose_interface(angie_handle->usb_device_handle, + &angie_handle->ep_in, &angie_handle->ep_out, -1, -1, -1, -1); + if (ret != ERROR_OK) { + angie_quit(); + return ret; + } + + /* Initialize ANGIE command queue */ + angie_clear_queue(angie_handle); + + /* Issue one test command with short timeout */ + ret = angie_append_test_cmd(angie_handle); + if (ret != ERROR_OK) { + angie_quit(); + return ret; + } + + ret = angie_execute_queued_commands(angie_handle, 200); + if (ret != ERROR_OK) { + /* Sending test command failed. The ANGIE device may be forever waiting for + * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was + * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ + + ret = jtag_libusb_bulk_write(angie_handle->usb_device_handle, angie_handle->ep_in, + dummy, 64, 200, &transferred); + + if (ret != ERROR_OK || transferred == 0) { + /* Bulk IN transfer failed -> unrecoverable error condition */ + LOG_ERROR("Cannot communicate with ANGIE device. Disconnect ANGIE from " + "the USB port and re-connect, then re-run OpenOCD"); + angie_quit(); + return ERROR_FAIL; + } + /* Successfully received Bulk IN packet -> continue */ + LOG_INFO("Recovered from lost Bulk IN packet"); + } + + angie_clear_queue(angie_handle); + + ret = angie_append_get_signals_cmd(angie_handle); + if (ret != ERROR_OK) { + angie_quit(); + return ret; + } + + ret = angie_execute_queued_commands(angie_handle, 200); + if (ret != ERROR_OK) { + angie_quit(); + return ret; + } + + /* Post-process the single CMD_GET_SIGNALS command */ + input_signals = angie_handle->queue_start->payload_in[0]; + output_signals = angie_handle->queue_start->payload_in[1]; + angie_dump_signal_states(input_signals, output_signals); + + angie_clear_queue(angie_handle); + + return ERROR_OK; +} + +/** + * Closes the USB handle for the ANGIE device. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_quit(void) +{ + int ret = angie_usb_close(angie_handle); + free(angie_handle); + angie_handle = NULL; + + return ret; +} + +static struct jtag_interface angie_interface = { + .execute_queue = angie_execute_queue, +}; + +struct adapter_driver angie_adapter_driver = { + .name = "angie", + .transports = jtag_only, + + .init = angie_init, + .quit = angie_quit, + .reset = angie_reset, + .speed = angie_speed, + .khz = angie_khz, + .speed_div = angie_speed_div, + + .jtag_ops = &angie_interface, +}; diff --git a/src/jtag/drivers/angie/README b/src/jtag/drivers/angie/README new file mode 100644 index 0000000000..c727154c48 --- /dev/null +++ b/src/jtag/drivers/angie/README @@ -0,0 +1,3 @@ +This folder contain only the files needed by ANGIE's driver. +You will find the complete ANGIE's firmware and the bitstream's code source in +contrib/firmware. diff --git a/src/jtag/drivers/angie/angie_bitstream.bit b/src/jtag/drivers/angie/angie_bitstream.bit new file mode 100644 index 0000000000000000000000000000000000000000..9e83e6b69d92a880881baf8d68ab171fb1a3f09e GIT binary patch literal 340702 zcmeI*O>Y~=835p+EF)4r5a-$+N)-WmYe-2+(X<9=peT@AFFCia?F0b|r};Se(8DS~ zfgTO?(%!0L3-mwOIrY}x;QoLh|A1YI9NAuJJ)*SB+2uYf&_mA0JMTP8nOrVOh26Km zU;KnHx*OiT`|#7x9{l$6KR$T)`Mvu;eR%KwFFyY2!IvNX>h|Q(ua{f+eR%VOum14p z=U;#E>Gbe0+zW5)PxcSqoBZs(=_K3_yVJuD52qg%CKrgv_K>D}G$rr&OdTYsHA3;&%w4M*dU`Z+lI<$tC}J4c6mA?%OBkEYM&^Mk!` z^WaX{J{XO{{@t?vsJtAPm#5|BSqKNmKm6apx1rolqECK&a;?l{^qb#>t-t;IMEFpI(pS&o#7GF>Wogzy!K2u-EPM zWY@C5Zp-n7CqRI}wFRcvjvzpv1d5!=E{;udW>C(3EA#xOCqRGz0RjXF5FkK+009C7 z+7S3l8$mCMng8{T(M4(Xqi)=fG%t~5{#TfavnPZoxJ2! z#j;;4FFCBiZtgwB|v}x zfsGd!6^kY2d&hlW|k9bGw4%$Z6?1yd6sK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UATS7l*&tSFkpu`3AV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK%hB+{C_^RxwVKyfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z(gLZ!sFrFE!MXOdvK|Bo5FkK+009C72oNAZfB*pk1PBlyK!5-N0t8kOC=#7hXYo?) zA*6bw+7k(CCP07y0RjXF5FkLH6@gJJQ3YK=U~7fGx)LBjfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5Fl`YfOjZffTD^(PJy{?p3~plT@@H75=*s*knWL~VgSwmxa=BJ&mL0k zwV$9E#|#z`(s5${=F2$uUh|{{L{ac}3%qARnz&v#`{yef}7uWGznTd^3n zTQj=)?UtjOe%Gk3P7y;b-zD0@jBy4f0RjXFTvwpDZh(u&Z-;PUmblZ)mK*^B z1PBlyK!5-N0t5&U*l2;-Mz7A|2oNAZfB*pk1PBlyK!8Ag0q5HD?*kbSAV7cs0RjXF z5FkK+0D*=Db{dW+9039Z2oNAZfB*pk1PBo5n1D0g9or$&AwYlt0RjXF5FkK+009CW z6iA&qPql}T>XB;iAc~X-5FkK+009C72oNAZV9)~2wGVptTRZ^*1PBlyK!5;&o(RNq zaIvhW9qVIRZGV22Z+5=vw5EP!%>dN|2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PJs^U~ZfDZJ%v;zT*vF-`Vo=f1J5E%O%^DR0{EP4Y8~y z8tY?OZGZmBiMk%KK9=Vrs3Aar009C72oM;Qz}BEvYq11gDKL6vt40C@2oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oPvfU?&kg)gD5sN2)!MfMx;&2oNAZfB*pk1PBlyux5eO zk!-5nvGSUCnCS=*AV7cs0RjXF3{oH-nZ&Y+5bI-EZGV2`Qr9Ea$MSpxH3SF{AV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF^ju(WoA-PdN}oVx zfm`+Scjxm6b(zHaSk|va3xVbY-f1qBNCf&SP%IM9_`mP+(QDLKL3tA(K!8Bw0^1=J zjR##J;MPgs*$M;N==!*gpkfjrK;TLO`Jbwnhb!YNrEU-b0t5&UAV7cs0Rp`j$awmq z_jVRQfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D+7Gvy5|_ng9U;1PBlyK!5-N z0-Gc7WOJ5cB?Jf%AV7cs0RjXF5FkLHPXgccDcM2iT7G5SFt*t+mT8p)2oNAZfB=Dh z2>8z6e(Wb%5+Fc;009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZV1os=+Fe`A;oD7KbOHnj5FkK+009C72oNB!1_8&;Yd|&y0RjXF5FkK+009C7 z2oTs5ft}<+Qa$S0Zzdz_Kwww`b-ydaQW)N9Gw%20E5)PXp<6Kl0tC7$ko}vZ%Rit} z@0t5(T7l`lCjpf=Cito{l<+>Ay@6nCry5~1vp9HeK z$kit#xe_2ifB*pk1PBlyKwuLE=C=7J?pJFfK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBo5zQAjvGRJqr8{N;e z*$k`eE>0ZY2|tMS)v~GC<2+5pi*aJyx-#~=ZW-fWHBNNB>iD{GF|SzG^;6$Xfw_YmWTsn=ig*j|9EjgMa&cbUV5La&bEl5&5g(^O5ap zQjxHO5*8q@)cN_ypRR&B!G}EM=NB0z;Va~oCF7K@j5@P%>X$~{IipSze4MA)6DJAi zs&UG%$Xl7`vSdtHCLm;SWw<;p$;G=IE}cv3(zw(vm5X*!F645vZdCR{K=7?+C{S_) zlyH(!yWH(|BRA!y-72@*t#NDJI=92kyCt{BopFEk18PAjYoHVr6^vR^q&)YB8}yL| zeWZcaqiF95nJ%7bt{BU@Y*o>;-k%lcka>SrqC<9g>%S7e)sN_rUQJOHP0{dy30nfW z=e12on|++R>5XPzJKy232)<6BH!WZkL{n>lz7O;y&{II`fYt+T0IC480X+@W2y_7G zUw~c)dIjiJAR_k~&_STrfery3208-t1`uhF&{5z!f!+lASD>E){S4?B&|5&qfldIu z4RjLd6i^q?&w+jc^h=<3P@xx0(ITx3s@m&u8D!WSNEd(IXXqje=FhdfjkMz7j z>k`fw(bYpg+>0IvNhsQHsk~T2g_Xxl_tzenlcKMeqPfIgnbRWvt)R_E{js2LXY zP5@T@F7uH@s~_6^MNG{X5(nP@zGt-4v%;RTdrEU=RCtQSm4%yv9~cUH)sNhD_A^$Z z{kiAWzx?bQ^_#h$#eI`SeJFi1AAKlgaWch#D-ij8y6=bf6=mDI-+9P%EvYMTn0 z5vL|K?eT0J>J#If@zxYEE;~Wyz4?i-GD#E1T@ZX{Ji*?d)10CA7b;qFfz~bpk0P^g z1v=u%`05Hy;BlhEGt!Kj&~6lZ>-2oP1MO4orM*{*bQg=Xmx?q4Me1;y(%6VvRQu?? zly`#mu)t0PdF#R|>Eg;x>C%c$X<&ILjH$Rynby^edXT0U{8mM4A3KW$pNsjLAfkA> ziAfIg{a8S8B$F*bo{>&sdhqG}e4C?PGO9P6<4J&*+LviwoGN zGJ9PfCKHHrd5q={)1D`P;OK|~h1_S?&LycACGcTe&H5{(C7mIlq@_SsijtPN7ml7dYC8Acf0~B0CN25s6w>L8bUy3_Bv?sar6h}y z{_krm##>bLMBctR`W|JBsupNi5q%ddUwRJ+=L;eeZB-M*z#RpPIB^55e#EHmf^nmv z4iidYjzm#Uj^T|le5yApGI^X$8)w@lWIM)dV^}rAMYXA;2~F^+$E8g%Y{(H{S^Zu8 z7m7d65PZ)9ga%mk1}GDttYFA^lKg2=)tSUpV{X z*#rGf!B-1|yc>Yc*V2r{WRelQ^Uuo;&zNm}52d0FZ9TM#)}QWC0e_}P4g6O<8sPuZ zlL603J$I|&NaB=7 z6k%gxSh$IvK=0_=$q5OAFsWw^xuy7{^y%TffBU%I(q3;>H1;ndE^4E_NC#9Q{gEdaQG zTE&zf{qrh*6;XkjX$6)k_mB;Y)QTxtu5cK%sRpDIDG`%Gtzyza37qmDaGxoKkwGW2 z{Y_ktIOL5UX@*!;k6iDk>2D|dXWvjeE$qEhR*~U3Z4<@OO(>9^BBz{8Zbt2@U1(s= z=-|R&;s=O=UAE0LvJ>?U9Sl@*tTM%%fNe$r zyUwV;tBdFUCZ^a@1z(4l5>9TS0YnT4l#VB}D9fD|`5+0DP|A_-38+V}%Lwwl44rfR ziq4fMT`i-NVj^^eNm?i0$Eb3y5J)bLhwgA7OHJy6N?jln&NDCBbgiZq-k5fV`M=e| za3eZ)&kkfd9i+@H>L%1T__Du}+ZS58b#@clg<1uFU+Ng6eq0uEUs4roxrF!isNkYF zV`kJ<{8Aiux<$**LdWmhf%+~w@3lU7?A~TY?eu->-Dt2Ir3`iJ5--`}idA&FII}NR zp4lphv!I+6RXvL{aAz5PpYvW>(n#Vgj_ynSOd1Y~Gv-Ez3P_i1dOQ{`xxfjE{3^L48;hBb8d=ZQ3yi?mb+rt6Lo;+kAdWEfoMG^~*lhru_DUI*6tgi5Gf7X$d5mh#w?yCDCd?rXuYlBR1p_@txbgL5m;N&!YmpC7ApWh;g`B3IFYBC1*z8}1IzNtOzz4CX+ z7~vG~fcTx!e+JG6Zx_yoF52Q1H~~!2t&TwXKm&a?nr1Wv zc_h$HMIn9&pna$%S1MQ#oI%*@!U@d@DC}#i?<$c7QAQAhGi7r}B%0W>;I zw2(U`W_YzQx)aU|eFKLE4_ha-35T3bl7^QXd+A2!j(apcC=j(O|S|Rqh3jJ>z}Wc&AUz(W;W=|wyF|f z@#EcMY7@DS;EQ1HOLQ~Ez8BK2xymrA&OW)uj zSX4SWgOi(B+!yT^x z*Bckd@`)~;aq3%cT?cIc3e%eiwQ=E>a4)#BVf=6hATvQp$SQ!_58q#bDI`oEFhzv< z4KT%oISWh)VO+p0Cd@Yy+ofwd*qqt%D*M_&_H{3N2xct!c6tQgE-9&(Lj_+)Zl=zS zALl=WYqYF8p#N{7ypt&UH(>4}%tydXC(OSClR=n|fw`M7zXQfXm`{MoB+RFhr7_t% zJRL)hnBg569SediAC?uRJXwMc z1yjGc$Q4b{0GfvKM*VqXfxO_L(=_BX`<>|l=d^-UcpHJ&QFtGNiXa)IXTWk?8WwqM zlHMFSDTxlk%o+9OOJh)JCcG#;I_Av_ULq}X$3$si5Tu|b%=0)s!VeIU9FT<893llR zQ1W;hlNyew|KlbxjqY zm#1b82RkalO(MK~`{Q-`AFtQ{cmoI-(_2A77w=l-vbw%!G+*U(t`)A89lRxU^{08l z+x-NsSqmaeZcZ@kx7K(@2h&+@Qx)qnI(XVV1m7v(yeboKOHYQ)IjKVC>GWjGn@*Iz zU3Rkk)av7F*z}ART_8s``!ma_67$u8S;SZ&h#{ky3iOxyoTjVADoRYB9PCK9|Dm;X ze_303`|6f8u)G!6u@ZlO6@Jo+pZcCxenMV*a^0!*T^rgU06HY2<=6;A&5_r6AC=d4 zY#0pMRkWq5H=Ep(S}Ms6ZM&`g=|;2@wf|rjYTxLUx5!m&Wsuzz#Otc@`Wn1pE3W2o zjRS8b%4B;d=Bu%z23N1cHS6)#4NP{oU61X&(LBUq#+_|1P|?#q73}~AVVGcd$7X+dXdSmlNqr-%PnsanfXDvO59RX zWrMGLf!!25aHR=vnm}Vcb}+FTYuP#^)@Ij(#=3katg%wjxCzuSbGz+nWR{xlO$3$n zfLE@Rm6pTVcIzZq2`6r@0+Wk@9+&DOSqk z%py|Wb(vXA%IS&BW2A)fmWJz>h2NKx?p9`%Qa#34m9mH_Bh?K|d01*SDW|KLwMwaH zo($E~(^HxV7_3csK24rG74`?@3Fj)YV)B)J6?^KrM6n`kOs>VX6>rti1L|_S6{mY&Dy4bt$eX!&}Rv{t%Z2_|@H* zUa0)CuKcb(XipT^oRjO%50}(mHgojP)@WF7H%n_82H&NSH*Z8NEh#H0FIjCrz3+#Z z-HaQaA=%ZgVYg6n)sVf|Z!f@GSX|X`Vsm^eNy;PwSP0(+>)qp?4M#fSWXh0fEJOfH zr!{b&V0H^`sJdjkljY}x9D~S(q_%+67CNnpTP$uadB#>C+KAY!n~F^rpSDelj(DRU zzkNYyqQ}`24beIDiJM;)pLxw%IAqf{=I(@3V`Iin)Dng(s)hR)1R*Ou16e7FMD=Fa zC90gy$PAb0mFuCo~?|$U5IK2kStVzi^km2P_`tw?`v|X!tLbf|YAm79m8@D#}3LgD6VP-EUAMq=Gi2 z(@=B)g5vp50spu{!`qKSg*H^^NugF5)E3oB^fanLThUr%M^#YPp-pHu%0OkP5NIyC zLsf`Yq9tf4DuLQUR0;BS#DG*Cnxx7_k-vE;U9}9AgT#^> * + * +*****************************************************************************/ + +/** + * @file + * Definition of the commands supported by the ANGIE firmware. + * + * Basically, two types of commands can be distinguished: + * - Commands with fixed payload size + * - Commands with variable payload size + * + * SCAN commands (in all variations) carry payloads of variable size, all + * other commands carry payloads of fixed size. + * + * In the case of SCAN commands, the payload size (n) is calculated by + * dividing the scan_size_bits variable by 8, rounding up the result. + * + * Offset zero always contains the command ID. + * + **************************************************************************** + * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + **************************************************************************** + * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * + * * + * OUT: * + * offset 1: tms_count * + * offset 2: tms_sequence * + **************************************************************************** + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * + * * + * OUT: * + * offset 1: low byte of tck_count * + * offset 2: high byte of tck_count * + **************************************************************************** + * CMD_CLOCK_SLEEP_US: * + * * + * OUT: * + * offset 1: low byte of sleep_us * + * offset 2: high byte of sleep_us * + **************************************************************************** + * CMD_CLOCK_SLEEP_MS: * + * * + * OUT: * + * offset 1: low byte of sleep_ms * + * offset 2: high byte of sleep_ms * + **************************************************************************** + * CMD_GET_SIGNALS: * + * * + * IN: * + * offset 0: current state of input signals * + * offset 1: current state of output signals * + **************************************************************************** + * CMD_SET_SIGNALS: * + * * + * OUT: * + * offset 1: signals that should be de-asserted * + * offset 2: signals that should be asserted * + **************************************************************************** + * CMD_CONFIGURE_TCK_FREQ: * + * * + * OUT: * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * + **************************************************************************** + * CMD_SET_LEDS: * + * * + * OUT: * + * offset 1: LED states: * + * Bit 0: turn COM LED on * + * Bit 1: turn RUN LED on * + * Bit 2: turn COM LED off * + * Bit 3: turn RUN LED off * + * Bits 7..4: Reserved * + **************************************************************************** + * CMD_TEST: * + * * + * OUT: * + * offset 1: unused dummy value * + **************************************************************************** + */ + +#ifndef __MSGTYPES_H +#define __MSGTYPES_H + +/* + * Command IDs: + * + * Bits 7..6: Reserved, should always be zero + * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, + * the IDs 0x00..0x1F are commands with variable payload size, + * the IDs 0x20..0x3F are commands with fixed payload size. + */ + +#define CMD_ID_MASK 0x3F + +/* Commands with variable payload size */ +#define CMD_SCAN_IN 0x00 +#define CMD_SLOW_SCAN_IN 0x01 +#define CMD_SCAN_OUT 0x02 +#define CMD_SLOW_SCAN_OUT 0x03 +#define CMD_SCAN_IO 0x04 +#define CMD_SLOW_SCAN_IO 0x05 + +/* Commands with fixed payload size */ +#define CMD_CLOCK_TMS 0x20 +#define CMD_SLOW_CLOCK_TMS 0x21 +#define CMD_CLOCK_TCK 0x22 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A + +/* JTAG signal definition for jtag_get_signals() -- Input signals! */ +#define SIGNAL_TDO 1 + +/* JTAG signal definition for jtag_get_signals() -- Output signals! */ +#define SIGNAL_TDI 8 +#define SIGNAL_TMS 2 +#define SIGNAL_TCK 4 +#define SIGNAL_TRST 1 +#define SIGNAL_SRST 32 + +#endif diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 50044935bd..25ae7e8a16 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -364,6 +364,7 @@ int adapter_poll_trace(uint8_t *buf, size_t *size); extern struct adapter_driver am335xgpio_adapter_driver; extern struct adapter_driver amt_jtagaccel_adapter_driver; +extern struct adapter_driver angie_adapter_driver; extern struct adapter_driver armjtagew_adapter_driver; extern struct adapter_driver at91rm9200_adapter_driver; extern struct adapter_driver bcm2835gpio_adapter_driver; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 48a194fd56..aa0ad3ade1 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -96,6 +96,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_ULINK == 1 &ulink_adapter_driver, #endif +#if BUILD_ANGIE == 1 + &angie_adapter_driver, +#endif #if BUILD_ARMJTAGEW == 1 &armjtagew_adapter_driver, #endif diff --git a/tcl/interface/angie.cfg b/tcl/interface/angie.cfg new file mode 100644 index 0000000000..26cbe393b5 --- /dev/null +++ b/tcl/interface/angie.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved +# +# configuration file for ANGIE Adapter from NanoXplore. +# + +adapter driver angie +adapter speed 10000 +reset_config trst_and_srst trst_push_pull srst_open_drain From 8774fd60177623051388bf7371c79ae7bb91a52d Mon Sep 17 00:00:00 2001 From: gudvinr Date: Thu, 27 Jul 2023 15:03:57 +0300 Subject: [PATCH 41/49] tcl/interface/ftdi: support for SIPEED RV-Debugger BL702-based JTAG debugger that emulates FT2232D device Change-Id: Iefbf03645e6d8d154f4b1cad3385b8bc09da37dd Signed-off-by: gudvinr Reviewed-on: https://review.openocd.org/c/openocd/+/7830 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/interface/ftdi/sipeed-rv-debugger.cfg | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tcl/interface/ftdi/sipeed-rv-debugger.cfg diff --git a/tcl/interface/ftdi/sipeed-rv-debugger.cfg b/tcl/interface/ftdi/sipeed-rv-debugger.cfg new file mode 100644 index 0000000000..ca65398c6e --- /dev/null +++ b/tcl/interface/ftdi/sipeed-rv-debugger.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Interface file for BL702-based SIPEED RV Debugger +# + +adapter driver ftdi +adapter speed 6000 + +ftdi device_desc "JTAG Debugger" +ftdi vid_pid 0x0403 0x6010 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 From 3c558fda4bf09b5fd612f05a86da7ad5c47630bb Mon Sep 17 00:00:00 2001 From: Artemiy Volkov Date: Mon, 17 Jul 2023 17:07:28 +0200 Subject: [PATCH 42/49] tcl: add configuration files for the ARC HSDK-4xD board This commit provides startup files for the Synopsys DesignWare ARC HSDK-4xD board. These have been adapted from the corresponding snps_hsdk.cfg files, the only functional change being the JTAG IDs for the new board's CPU cores. Change-Id: I19a0cd13bc09de90cfe2a7cccf1239e459fd8077 Signed-off-by: Artemiy Volkov Reviewed-on: https://review.openocd.org/c/openocd/+/7829 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Evgeniy Didin --- tcl/board/snps_hsdk_4xd.cfg | 19 ++++++++++++++ tcl/target/snps_hsdk_4xd.cfg | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tcl/board/snps_hsdk_4xd.cfg create mode 100644 tcl/target/snps_hsdk_4xd.cfg diff --git a/tcl/board/snps_hsdk_4xd.cfg b/tcl/board/snps_hsdk_4xd.cfg new file mode 100644 index 0000000000..5901533d28 --- /dev/null +++ b/tcl/board/snps_hsdk_4xd.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (C) 2023 Synopsys, Inc. +# Artemiy Volkov + +# Adapted from tcl/board/snps_hsdk.cfg. + +# +# Synopsys DesignWare ARC HSDK Software Development Platform (HS47D cores) +# + +source [find interface/ftdi/snps_sdp.cfg] +adapter speed 10000 + +# ARCs supports only JTAG. +transport select jtag + +# Configure SoC +source [find target/snps_hsdk_4xd.cfg] diff --git a/tcl/target/snps_hsdk_4xd.cfg b/tcl/target/snps_hsdk_4xd.cfg new file mode 100644 index 0000000000..1520e3d7c9 --- /dev/null +++ b/tcl/target/snps_hsdk_4xd.cfg @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (C) 2023 Synopsys, Inc. +# Artemiy Volkov + +# Adapted from tcl/target/snps_hsdk.cfg. + +# +# HS Development Kit SoC. +# +# Contains quad-core ARC HS47D. +# + +source [find cpu/arc/hs.tcl] + +set _coreid 0 +set _dbgbase [expr {$_coreid << 13}] + +# CHIPNAME will be used to choose core family (600, 700 or EM). As far as +# OpenOCD is concerned EM and HS are identical. +set _CHIPNAME arc-em + + +proc setup_cpu {core_index expected_id} { + global _coreid + global _dbgbase + global _CHIPNAME + + set _TARGETNAME $_CHIPNAME.cpu$core_index + jtag newtap $_CHIPNAME cpu$core_index -irlen 4 -ircapture 0x1 -expected-id $expected_id + + target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME + $_TARGETNAME configure -coreid $_coreid + $_TARGETNAME configure -dbgbase $_dbgbase + $_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME" + + arc_hs_init_regs + + $_TARGETNAME arc cache l2 auto 1 + + set _coreid [expr {$_coreid + 1}] + set _dbgbase [expr {$_coreid << 13}] +} + +# OpenOCD discovers JTAG TAPs in reverse order. + +setup_cpu 4 0x100c54b1 +setup_cpu 3 0x100854b1 +setup_cpu 2 0x100454b1 +setup_cpu 1 0x100054b1 From 307a3ca10996283697356a4835f3152dd00a9a0c Mon Sep 17 00:00:00 2001 From: Daniel Goehring Date: Tue, 6 Jun 2023 14:44:13 -0600 Subject: [PATCH 43/49] target/aarch64: add missing aarch64_poll() calls Add missing aarch64_poll() calls to ensure the event TARGET_EVENT_HALTED is called when necessary. This is needed with the poller update introduced in commit 95603fae18f8 ("openocd: revert workarounds for 'expr' syntax change") Signed-off-by: Daniel Goehring Change-Id: I6e91f1b6bc1f0d16e6f0eb76fc67d20111e3afd2 Reviewed-on: https://review.openocd.org/c/openocd/+/7737 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 5d8a65273f..d25c7d30e1 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1091,6 +1091,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres struct armv8_common *armv8 = target_to_armv8(target); struct aarch64_common *aarch64 = target_to_aarch64(target); int saved_retval = ERROR_OK; + int poll_retval; int retval; uint32_t edecr; @@ -1173,6 +1174,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval == ERROR_TARGET_TIMEOUT) saved_retval = aarch64_halt_one(target, HALT_SYNC); + poll_retval = aarch64_poll(target); + /* restore EDECR */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, edecr); @@ -1189,6 +1192,9 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (saved_retval != ERROR_OK) return saved_retval; + if (poll_retval != ERROR_OK) + return poll_retval; + return ERROR_OK; } @@ -2695,6 +2701,9 @@ static int aarch64_examine(struct target *target) if (retval == ERROR_OK) retval = aarch64_init_debug_access(target); + if (retval == ERROR_OK) + retval = aarch64_poll(target); + return retval; } From 1233de5f903bf55c76feaf2d248fbb6fe90365ab Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Tue, 25 Jul 2023 23:31:54 +0200 Subject: [PATCH 44/49] pld: fix sparser warnings Change-Id: I31c5b19cd93ac41b026f824337488c9aa9b12439 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7828 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/pld/lattice.c | 2 +- src/pld/virtex2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 2075f4490d..018cb2693e 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -319,7 +319,7 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen return retval; } -int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +static int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index 5a8cf9d96e..9b4a0979f3 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -347,7 +347,7 @@ COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], instr_codes.jprog_b); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], instr_codes.jstart); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[5], instr_codes.jshutdown); - instr_codes.bypass = 0xffffffffffffffff; + instr_codes.bypass = 0xffffffffffffffffULL; unsigned int num_user = CMD_ARGC - 6; for (unsigned int i = 0; i < num_user; ++i) From c2d44c36d6c43a98afdad324aa46b36ef326452d Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 31 Jul 2023 21:10:52 +0200 Subject: [PATCH 45/49] pld: allow calling of configuration functions before 'init' Change-Id: I7c475fbbf8c13ae227e3393f01528eb180e9de51 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7835 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/pld/intel.c | 4 ++-- src/pld/lattice.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pld/intel.c b/src/pld/intel.c index e5c9273069..ee3097391b 100644 --- a/src/pld/intel.c +++ b/src/pld/intel.c @@ -467,13 +467,13 @@ PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) static const struct command_registration intel_exec_command_handlers[] = { { .name = "set_bscan", - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .handler = intel_set_bscan_command_handler, .help = "set boundary scan register length of FPGA", .usage = "pld_name len", }, { .name = "set_check_pos", - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .handler = intel_set_check_pos_command_handler, .help = "set check_pos of FPGA", .usage = "pld_name pos", diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 018cb2693e..0cd08dd331 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -526,7 +526,7 @@ static const struct command_registration lattice_exec_command_handlers[] = { .usage = "pld_name value", }, { .name = "set_preload", - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .handler = lattice_set_preload_command_handler, .help = "set length for preload (device specific)", .usage = "pld_name value", From 3a3400064a6147c2f2ec93b94b270c30c3147e61 Mon Sep 17 00:00:00 2001 From: Nikolay Dimitrov Date: Thu, 3 Aug 2023 23:50:55 +0300 Subject: [PATCH 46/49] flash/nor/spi: add zetta zd25q16 * Zetta 16 Mbit (2 MiB) SPI flash * Tested on Olimex RP2040-PICO30 and Neo6502 boards Change-Id: I02224dd7a72a9b72f01b31edbd958daa23f28956 Signed-off-by: Nikolay Dimitrov Reviewed-on: https://review.openocd.org/c/openocd/+/7849 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 3bcaa9f613..d559567441 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -171,6 +171,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */ FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), + FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001560ba, 0x100, 0x1000, 0x200000), /* FRAM, no erase commands, no write page or sectors */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), From 2e60e2eca9d06dcb99a4adb81ebe435a72ab0c7f Mon Sep 17 00:00:00 2001 From: Nikolay Dimitrov Date: Fri, 4 Aug 2023 23:56:49 +0300 Subject: [PATCH 47/49] flash/nor/spi: Improve erase performance on zd25q16 Use blocks (64 KiB) instead of sectors (4 KiB) when erasing the zd25Q16 SPI flash memory (thanks to Tomas Vanek!) Change-Id: I969a69ad35f51b84eb3e11b93f0d79db3e98613a Signed-off-by: Nikolay Dimitrov Reviewed-on: https://review.openocd.org/c/openocd/+/7850 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index d559567441..ace274f3dd 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -171,7 +171,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */ FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), - FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001560ba, 0x100, 0x1000, 0x200000), + FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000), /* FRAM, no erase commands, no write page or sectors */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), From a4b4750e3860fae620f51d34a43a655b5ccdd51d Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 2 Aug 2023 21:33:32 +0000 Subject: [PATCH 48/49] efm32: drop unnecessary and incomplete checks There's really no reason to try and add an extra layer of cpu verification here. Change-Id: If8c4aa03754607be6c089f514ae300b09b067ffa Signed-off-by: Karl Palsson Reviewed-on: https://review.openocd.org/c/openocd/+/7844 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/efm32.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 3a49afc9c3..f8e0886570 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -251,18 +251,6 @@ static int efm32x_read_info(struct flash_bank *bank) memset(efm32_info, 0, sizeof(struct efm32_info)); - const struct cortex_m_common *cortex_m = target_to_cm(bank->target); - - switch (cortex_m->core_info->partno) { - case CORTEX_M3_PARTNO: - case CORTEX_M4_PARTNO: - case CORTEX_M0P_PARTNO: - break; - default: - LOG_ERROR("Target is not Cortex-Mx Device"); - return ERROR_FAIL; - } - ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); if (ret != ERROR_OK) return ret; From 05ee88915520d1dd82da94a016a9374a1f3a8129 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 2 Aug 2023 21:38:58 +0000 Subject: [PATCH 49/49] target/cortex_m: check core implementor field Presently, we only look at the Part Number field of the CPUID, and completely ignore the Implmentor field, simply assuming it to be ARM. Parts have since been found, with different implementors, that use overlapping part numbers, causing detection to fail. Expand the "part number" field to be a full implementor+part number, excluding the revision/patch fields, to make checking more reliable. Change-Id: Id81774f829104f57a0c105320d0d2e479fa01522 Signed-off-by: Karl Palsson Reviewed-on: https://review.openocd.org/c/openocd/+/7845 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/flash/nor/stm32f1x.c | 2 +- src/flash/nor/stm32f2x.c | 2 +- src/flash/nor/stm32h7x.c | 2 +- src/flash/nor/stm32l4x.c | 2 +- src/target/arm.h | 5 +++++ src/target/cortex_m.c | 32 ++++++++++++++-------------- src/target/cortex_m.h | 45 ++++++++++++++++++++++++---------------- 7 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index ab1ef2aefe..b3bb843358 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -743,7 +743,7 @@ static int stm32x_get_property_addr(struct target *target, struct stm32x_propert return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m_get_partno_safe(target)) { + switch (cortex_m_get_impl_part(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ addr->device_id = 0x40015800; addr->flash_size = 0x1FFFF7CC; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index dcaf260d97..2e0d158975 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -961,7 +961,7 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) return retval; if ((*device_id & 0xfff) == 0x411 - && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { + && cortex_m_get_impl_part(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 8be8037287..21618b39b8 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -795,7 +795,7 @@ static int stm32x_probe(struct flash_bank *bank) /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; if (device_id == DEVID_STM32H74_H75XX - && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) + && cortex_m_get_impl_part(target) == CORTEX_M4_PARTNO) LOG_WARNING("%s cannot read the flash size register", target_name(target)); else retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 77a89f53c0..4414cf5396 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1682,7 +1682,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1. * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */ - if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && + if (cortex_m_get_impl_part(target) == CORTEX_M0P_PARTNO && armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; diff --git a/src/target/arm.h b/src/target/arm.h index fd61d5f514..f3abd6cbab 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -58,6 +58,11 @@ enum arm_arch { ARM_ARCH_V8M, }; +/** Known ARM implementor IDs */ +enum arm_implementor { + ARM_IMPLEMENTOR_ARM = 0x41, +}; + /** * Represent state of an ARM core. * diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 987dc9b245..87a8845527 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -50,63 +50,63 @@ /* Supported Cortex-M Cores */ static const struct cortex_m_part_info cortex_m_parts[] = { { - .partno = CORTEX_M0_PARTNO, + .impl_part = CORTEX_M0_PARTNO, .name = "Cortex-M0", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M0P_PARTNO, + .impl_part = CORTEX_M0P_PARTNO, .name = "Cortex-M0+", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M1_PARTNO, + .impl_part = CORTEX_M1_PARTNO, .name = "Cortex-M1", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M3_PARTNO, + .impl_part = CORTEX_M3_PARTNO, .name = "Cortex-M3", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { - .partno = CORTEX_M4_PARTNO, + .impl_part = CORTEX_M4_PARTNO, .name = "Cortex-M4", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV4 | CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { - .partno = CORTEX_M7_PARTNO, + .impl_part = CORTEX_M7_PARTNO, .name = "Cortex-M7", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M23_PARTNO, + .impl_part = CORTEX_M23_PARTNO, .name = "Cortex-M23", .arch = ARM_ARCH_V8M, }, { - .partno = CORTEX_M33_PARTNO, + .impl_part = CORTEX_M33_PARTNO, .name = "Cortex-M33", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M35P_PARTNO, + .impl_part = CORTEX_M35P_PARTNO, .name = "Cortex-M35P", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M55_PARTNO, + .impl_part = CORTEX_M55_PARTNO, .name = "Cortex-M55", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = STAR_MC1_PARTNO, + .impl_part = STAR_MC1_PARTNO, .name = "STAR-MC1", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, @@ -2526,18 +2526,18 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - /* Get ARCH and CPU types */ - const enum cortex_m_partno core_partno = (cpuid & ARM_CPUID_PARTNO_MASK) >> ARM_CPUID_PARTNO_POS; + /* Inspect implementor/part to look for recognized cores */ + unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTOR_MASK | ARM_CPUID_PARTNO_MASK); for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { - if (core_partno == cortex_m_parts[n].partno) { + if (impl_part == cortex_m_parts[n].impl_part) { cortex_m->core_info = &cortex_m_parts[n]; break; } } if (!cortex_m->core_info) { - LOG_TARGET_ERROR(target, "Cortex-M PARTNO 0x%x is unrecognized", core_partno); + LOG_TARGET_ERROR(target, "Cortex-M CPUID: 0x%x is unrecognized", cpuid); return ERROR_FAIL; } @@ -2549,7 +2549,7 @@ int cortex_m_examine(struct target *target) (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; - if (core_partno == CORTEX_M7_PARTNO) { + if (impl_part == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index a1c43b56de..806ff59106 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -31,22 +31,31 @@ #define CPUID 0xE000ED00 -#define ARM_CPUID_PARTNO_POS 4 -#define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) +#define ARM_CPUID_IMPLEMENTOR_POS 24 +#define ARM_CPUID_IMPLEMENTOR_MASK (0xFF << ARM_CPUID_IMPLEMENTOR_POS) +#define ARM_CPUID_PARTNO_POS 4 +#define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) -enum cortex_m_partno { +#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTOR_POS) & ARM_CPUID_IMPLEMENTOR_MASK) | \ + (((partno) << ARM_CPUID_PARTNO_POS) & ARM_CPUID_PARTNO_MASK)) + +/** Known Arm Cortex masked CPU Ids + * This includes the implementor and part number, but _not_ the revision or + * patch fields. + */ +enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = 0x132, - CORTEX_M0_PARTNO = 0xC20, - CORTEX_M1_PARTNO = 0xC21, - CORTEX_M3_PARTNO = 0xC23, - CORTEX_M4_PARTNO = 0xC24, - CORTEX_M7_PARTNO = 0xC27, - CORTEX_M0P_PARTNO = 0xC60, - CORTEX_M23_PARTNO = 0xD20, - CORTEX_M33_PARTNO = 0xD21, - CORTEX_M35P_PARTNO = 0xD31, - CORTEX_M55_PARTNO = 0xD22, + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ @@ -55,7 +64,7 @@ enum cortex_m_partno { #define CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K BIT(2) struct cortex_m_part_info { - enum cortex_m_partno partno; + enum cortex_m_impl_part impl_part; const char *name; enum arm_arch arch; uint32_t flags; @@ -292,11 +301,11 @@ target_to_cortex_m_safe(struct target *target) } /** - * @returns cached value of Cortex-M part number + * @returns cached value of the cpuid, masked for implementation and part. * or CORTEX_M_PARTNO_INVALID if the magic number does not match * or core_info is not initialised. */ -static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *target) +static inline enum cortex_m_impl_part cortex_m_get_impl_part(struct target *target) { struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); if (!cortex_m) @@ -305,7 +314,7 @@ static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *targe if (!cortex_m->core_info) return CORTEX_M_PARTNO_INVALID; - return cortex_m->core_info->partno; + return cortex_m->core_info->impl_part; } int cortex_m_examine(struct target *target);