From aad87180586a43500f8af1cf79255c7293bb258b Mon Sep 17 00:00:00 2001 From: Doug Brunner Date: Mon, 25 Oct 2021 10:15:07 -0700 Subject: [PATCH 001/186] flash/nor/efr32: fixed lockbits and user data Changed flash driver to support writing to the user data page, as well as to any portion of the lockbits page above 512 bytes (the amount used for the actual page lock words). The top part of the lockbits page is used on at least the EFR32xG1 chips for the SiLabs bootloader encryption keys. As presented to the user, the lockbits page is the same size as the other pages, but any attempt to write to its low 512 bytes is an error. To enforce this, efr32x_write is renamed to efm32x_priv_write and a wrapper function is provided in its place. If the user erases the lockbits page, the driver rewrites the cached lock words after the erase. When the driver erases the lockbits page in order to update the lock words, it first takes a copy of anything stored in the top part of the page, and re-programs it after the erase operation. There are now multiple instances of flash_bank for each target, and the flash_bank instances must share their cached lock words to operate as intended. Therefore, when a bank is created, the global flash bank list is used to find any other banks that share the same target. Since some banks in the global list are invalid at the time free_driver_priv is called, reference counting is used to decide when to free driver_priv. To avoid the need to find the lockbits flash_bank from another flash_bank, efm32x_priv_write and efm32x_erase_page now take an absolute address. There didn't seem to be any reason to prohibit unprotecting individual flash pages, so that limitation is removed from efm32x_protect(). This addresses ticket #185. Valgrind-clean, except for 2x 4kiB not freed/still reachable blocks that were allocated by libudev. No new Clang analyzer warnings, no new sanitizer warnings. Signed-off-by: Doug Brunner Change-Id: Ifb22e6149939d893f386706e99b928691ec1d41b Reviewed-on: https://review.openocd.org/c/openocd/+/6665 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Tomas Vanek --- doc/openocd.texi | 15 ++- src/flash/nor/efm32.c | 304 ++++++++++++++++++++++++++++++------------ tcl/target/efm32.cfg | 2 + 3 files changed, 235 insertions(+), 86 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 8e5058538..4d5a844af 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6351,13 +6351,22 @@ flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME @end deffn @deffn {Flash Driver} {efm32} -All members of the EFM32 microcontroller family from Energy Micro include -internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes -a number of these chips using the chip identification register, and +All members of the EFM32/EFR32 microcontroller family from Energy Micro (now Silicon Labs) +include internal flash and use Arm Cortex-M3 or Cortex-M4 cores. The driver automatically +recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME @end example +It supports writing to the user data page, as well as the portion of the lockbits page +past 512 bytes on chips with larger page sizes. The latter is used by the SiLabs +bootloader/AppLoader system for encryption keys. Setting protection on these pages is +currently not supported. +@example +flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME +flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME +@end example + A special feature of efm32 controllers is that it is possible to completely disable the debug interface by writing the correct values to the 'Debug Lock Word'. OpenOCD supports this via the following command: diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index fb4b09624..653878ae7 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -14,6 +14,9 @@ * Copyright (C) 2014 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * + * Copyright (C) 2021 Doug Brunner * + * doug.a.brunner@gmail.com * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -45,13 +48,16 @@ #define EFM32_FLASH_WDATAREADY_TMO 100 #define EFM32_FLASH_WRITE_TMO 100 +#define EFM32_FLASH_BASE 0 + /* size in bytes, not words; must fit all Gecko devices */ -#define LOCKBITS_PAGE_SZ 512 +#define LOCKWORDS_SZ 512 #define EFM32_MSC_INFO_BASE 0x0fe00000 #define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) +#define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_LOCK_BITS+LOCKWORDS_SZ) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) /* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */ @@ -83,6 +89,27 @@ #define EFM32_MSC_REG_LOCK_SERIES1 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 +enum efm32_bank_index { + EFM32_BANK_INDEX_MAIN, + EFM32_BANK_INDEX_USER_DATA, + EFM32_BANK_INDEX_LOCK_BITS, + EFM32_N_BANKS +}; + +static int efm32x_get_bank_index(target_addr_t base) +{ + switch (base) { + case EFM32_FLASH_BASE: + return EFM32_BANK_INDEX_MAIN; + case EFM32_MSC_USER_DATA: + return EFM32_BANK_INDEX_USER_DATA; + case EFM32_MSC_LOCK_BITS: + return EFM32_BANK_INDEX_LOCK_BITS; + default: + return ERROR_FAIL; + } +} + struct efm32_family_data { int family_id; const char *name; @@ -98,13 +125,6 @@ struct efm32_family_data { uint32_t msc_regbase; }; -struct efm32x_flash_bank { - bool probed; - uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; - uint32_t reg_base; - uint32_t reg_lock; -}; - struct efm32_info { const struct efm32_family_data *family_data; uint16_t flash_sz_kib; @@ -115,6 +135,15 @@ struct efm32_info { uint16_t page_size; }; +struct efm32x_flash_chip { + struct efm32_info info; + bool probed[EFM32_N_BANKS]; + uint32_t lb_page[LOCKWORDS_SZ/4]; + uint32_t reg_base; + uint32_t reg_lock; + uint32_t refcount; +}; + static const struct efm32_family_data efm32_families[] = { { 16, "EFR32MG1P Mighty", .series = 1 }, { 17, "EFR32MG1B Mighty", .series = 1 }, @@ -175,9 +204,12 @@ static const struct efm32_family_data efm32_families[] = { { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, }; +const struct flash_driver efm32_flash; -static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count); +static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t addr, uint32_t count); + +static int efm32x_write_only_lockbits(struct flash_bank *bank); static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz) { @@ -207,7 +239,7 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t *value) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_read_u32(bank->target, base + offset, value); @@ -216,18 +248,18 @@ static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t value) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_write_u32(bank->target, base + offset, value); } -static int efm32x_read_info(struct flash_bank *bank, - struct efm32_info *efm32_info) +static int efm32x_read_info(struct flash_bank *bank) { int ret; uint32_t cpuid = 0; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_info *efm32_info = &(efm32x_info->info); memset(efm32_info, 0, sizeof(struct efm32_info)); @@ -327,20 +359,61 @@ static int efm32x_read_info(struct flash_bank *bank, /* flash bank efm32 0 0 */ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) { - struct efm32x_flash_bank *efm32x_info; + struct efm32x_flash_chip *efm32x_info = NULL; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - efm32x_info = malloc(sizeof(struct efm32x_flash_bank)); + int bank_index = efm32x_get_bank_index(bank->base); + if (bank_index < 0) { + LOG_ERROR("Flash bank with base address %" PRIx32 " is not supported", + (uint32_t) bank->base); + return ERROR_FAIL; + } + /* look for an existing flash structure matching target */ + for (struct flash_bank *bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver == &efm32_flash + && bank_iter->target == bank->target + && bank->driver_priv) { + efm32x_info = bank->driver_priv; + break; + } + } + + if (!efm32x_info) { + /* target not matched, make a new one */ + efm32x_info = calloc(1, sizeof(struct efm32x_flash_chip)); + + memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); + } + + ++efm32x_info->refcount; bank->driver_priv = efm32x_info; - efm32x_info->probed = false; - memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); return ERROR_OK; } +/** + * Remove flash structure corresponding to this bank, + * if and only if it's not used by any others + */ +static void efm32x_free_driver_priv(struct flash_bank *bank) +{ + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + if (efm32x_info) { + /* Use ref count to determine if it can be freed; scanning bank list doesn't work, + * because this function can be called after some banks in the list have been + * already destroyed */ + --efm32x_info->refcount; + if (efm32x_info->refcount == 0) { + free(efm32x_info); + bank->driver_priv = NULL; + } + } +} + /* set or reset given bits in a register */ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, uint32_t bitmask, int set) @@ -368,7 +441,7 @@ static int efm32x_set_wren(struct flash_bank *bank, int write_enable) static int efm32x_msc_lock(struct flash_bank *bank, int lock) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } @@ -416,7 +489,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) */ int ret = 0; uint32_t status = 0; - addr += bank->base; LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); @@ -470,20 +542,28 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first, } for (unsigned int i = first; i <= last; i++) { - ret = efm32x_erase_page(bank, bank->sectors[i].offset); + ret = efm32x_erase_page(bank, bank->base + bank->sectors[i].offset); if (ret != ERROR_OK) LOG_ERROR("Failed to erase page %d", i); } ret = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); + if (ret != ERROR_OK) + return ret; + + if (bank->base == EFM32_MSC_LOCK_BITS) { + ret = efm32x_write_only_lockbits(bank); + if (ret != ERROR_OK) + LOG_ERROR("Failed to restore lockbits after erase"); + } return ret; } static int efm32x_read_lock_data(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct target *target = bank->target; int data_size = 0; uint32_t *ptr = NULL; @@ -557,35 +637,84 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ERROR_OK; } +static int efm32x_write_only_lockbits(struct flash_bank *bank) +{ + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + return efm32x_priv_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ); +} + static int efm32x_write_lock_data(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = 0; + /* Preserve any data written to the high portion of the lockbits page */ + assert(efm32x_info->info.page_size >= LOCKWORDS_SZ); + uint32_t extra_bytes = efm32x_info->info.page_size - LOCKWORDS_SZ; + uint8_t *extra_data = NULL; + if (extra_bytes) { + extra_data = malloc(extra_bytes); + ret = target_read_buffer(bank->target, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes, extra_data); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read extra contents of LB page"); + free(extra_data); + return ret; + } + } + ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS); if (ret != ERROR_OK) { LOG_ERROR("Failed to erase LB page"); + if (extra_data) + free(extra_data); return ret; } - return efm32x_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, - LOCKBITS_PAGE_SZ); + if (extra_data) { + ret = efm32x_priv_write(bank, extra_data, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes); + free(extra_data); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to restore extra contents of LB page"); + return ret; + } + } + + return efm32x_write_only_lockbits(bank); } static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - uint32_t dw = efm32x_info->lb_page[page >> 5]; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + uint32_t dw = 0; uint32_t mask = 0; - mask = 1 << (page & 0x1f); + switch (bank->base) { + case EFM32_FLASH_BASE: + dw = efm32x_info->lb_page[page >> 5]; + mask = 1 << (page & 0x1f); + break; + case EFM32_MSC_USER_DATA: + dw = efm32x_info->lb_page[126]; + mask = 0x1; + break; + case EFM32_MSC_LOCK_BITS: + dw = efm32x_info->lb_page[126]; + mask = 0x2; + break; + } return (dw & mask) ? 0 : 1; } static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + if (bank->base != EFM32_FLASH_BASE) { + LOG_ERROR("Locking user and lockbits pages is not supported yet"); + return ERROR_FAIL; + } + uint32_t *dw = &efm32x_info->lb_page[page >> 5]; uint32_t mask = 0; @@ -605,11 +734,6 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, struct target *target = bank->target; int ret = 0; - if (!set) { - LOG_ERROR("Erase device data to reset page locks"); - return ERROR_FAIL; - } - if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -633,16 +757,15 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, } static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, - uint32_t offset, uint32_t count) + uint32_t address, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ @@ -864,8 +987,8 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ERROR_OK; } -static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t addr, uint32_t count) { struct target *target = bank->target; uint8_t *new_buffer = NULL; @@ -875,9 +998,9 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x3) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte " - "alignment", offset); + if (addr & 0x3) { + LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte " + "alignment", addr); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } @@ -906,7 +1029,7 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, goto cleanup; /* try using a block write */ - retval = efm32x_write_block(bank, buffer, offset, words_remaining); + retval = efm32x_write_block(bank, buffer, addr, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -918,13 +1041,13 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); - retval = efm32x_write_word(bank, offset, value); + retval = efm32x_write_word(bank, addr, value); if (retval != ERROR_OK) goto reset_pg_and_lock; words_remaining--; buffer += 4; - offset += 4; + addr += 4; } } @@ -939,63 +1062,77 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } +static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + if (bank->base == EFM32_MSC_LOCK_BITS && offset < LOCKWORDS_SZ) { + LOG_ERROR("Cannot write to lock words"); + return ERROR_FAIL; + } + return efm32x_priv_write(bank, buffer, bank->base + offset, count); +} + static int efm32x_probe(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - struct efm32_info efm32_mcu_info; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_info *efm32_mcu_info = &(efm32x_info->info); int ret; - uint32_t base_address = 0x00000000; - efm32x_info->probed = false; - memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); + int bank_index = efm32x_get_bank_index(bank->base); + assert(bank_index >= 0); - ret = efm32x_read_info(bank, &efm32_mcu_info); + efm32x_info->probed[bank_index] = false; + memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); + + ret = efm32x_read_info(bank); if (ret != ERROR_OK) return ret; LOG_INFO("detected part: %s Gecko, rev %d", - efm32_mcu_info.family_data->name, efm32_mcu_info.prod_rev); - LOG_INFO("flash size = %dkbytes", efm32_mcu_info.flash_sz_kib); - LOG_INFO("flash page size = %dbytes", efm32_mcu_info.page_size); - - assert(efm32_mcu_info.page_size != 0); - - int num_pages = efm32_mcu_info.flash_sz_kib * 1024 / - efm32_mcu_info.page_size; + efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev); + LOG_INFO("flash size = %dkbytes", efm32_mcu_info->flash_sz_kib); + LOG_INFO("flash page size = %dbytes", efm32_mcu_info->page_size); - assert(num_pages > 0); + assert(efm32_mcu_info->page_size != 0); free(bank->sectors); bank->sectors = NULL; - bank->base = base_address; - bank->size = (num_pages * efm32_mcu_info.page_size); - bank->num_sectors = num_pages; - - ret = efm32x_read_lock_data(bank); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to read LB data"); - return ret; - } - - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + if (bank->base == EFM32_FLASH_BASE) { + bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / + efm32_mcu_info->page_size; + assert(bank->num_sectors > 0); - for (int i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * efm32_mcu_info.page_size; - bank->sectors[i].size = efm32_mcu_info.page_size; + ret = efm32x_read_lock_data(bank); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read LB data"); + return ret; + } + } else + bank->num_sectors = 1; + bank->size = bank->num_sectors * efm32_mcu_info->page_size; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + + for (uint32_t i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * efm32_mcu_info->page_size; + bank->sectors[i].size = efm32_mcu_info->page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - efm32x_info->probed = true; + efm32x_info->probed[bank_index] = true; return ERROR_OK; } static int efm32x_auto_probe(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - if (efm32x_info->probed) + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + int bank_index = efm32x_get_bank_index(bank->base); + assert(bank_index >= 0); + + if (efm32x_info->probed[bank_index]) return ERROR_OK; return efm32x_probe(bank); } @@ -1026,16 +1163,17 @@ static int efm32x_protect_check(struct flash_bank *bank) static int get_efm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { - struct efm32_info info; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret; - ret = efm32x_read_info(bank, &info); + ret = efm32x_read_info(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read EFM32 info"); return ret; } - command_print_sameline(cmd, "%s Gecko, rev %d", info.family_data->name, info.prod_rev); + command_print_sameline(cmd, "%s Gecko, rev %d", efm32x_info->info.family_data->name, + efm32x_info->info.prod_rev); return ERROR_OK; } @@ -1051,7 +1189,7 @@ COMMAND_HANDLER(efm32x_handle_debuglock_command) if (retval != ERROR_OK) return retval; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; target = bank->target; @@ -1110,5 +1248,5 @@ const struct flash_driver efm32_flash = { .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, - .free_driver_priv = default_flash_free_driver_priv, + .free_driver_priv = efm32x_free_driver_priv, }; diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index c789efc72..d2e4eb329 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -43,6 +43,8 @@ $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME +flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME +flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to From 5a8d32fcb92f179445da6d3f7b0ceeec4efbcc6f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 12 Jan 2022 17:59:12 +0100 Subject: [PATCH 002/186] doc: use the new jimtcl syntax for 'expr' With jimtcl 0.81 the syntax of the TCL command 'expr' requires the multiple arguments to be within curly brackets. Update the examples in the documentation to follow the new syntax. While there, split one example to avoid it to exceed the line size during pdf document generation. Change-Id: I91cca419f8273415ccb0c2ce369fc6ac476e34e5 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6809 Tested-by: jenkins --- doc/manual/primer/tcl.txt | 2 +- doc/openocd.texi | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/doc/manual/primer/tcl.txt b/doc/manual/primer/tcl.txt index 868a75ba0..eba2f552d 100644 --- a/doc/manual/primer/tcl.txt +++ b/doc/manual/primer/tcl.txt @@ -174,7 +174,7 @@ them. It is similar to this bash statement. EXPORT vn=`date` LINE 2 & 3 - set $vn [expr (1024 * $x)] + set $vn [expr {1024 * $x}] global $vn In line 1, we dynamically created a variable name. Here, we are diff --git a/doc/openocd.texi b/doc/openocd.texi index 4d5a844af..cee54ebf7 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2009,9 +2009,9 @@ proc setc15 @{regs value@} @{ echo [format "set p15 0x%04x, 0x%08x" $regs $value] - arm mcr 15 [expr ($regs>>12)&0x7] \ - [expr ($regs>>0)&0xf] [expr ($regs>>4)&0xf] \ - [expr ($regs>>8)&0x7] $value + arm mcr 15 [expr @{($regs >> 12) & 0x7@}] \ + [expr @{($regs >> 0) & 0xf@}] [expr @{($regs >> 4) & 0xf@}] \ + [expr @{($regs >> 8) & 0x7@}] $value @} @end example @@ -3157,7 +3157,9 @@ the target's supply voltage. The result can be converted to Volts (ignoring the most significant bytes, always zero) @example > set a [st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -> echo [expr 2*1.2*([lindex $a 4]+256*[lindex $a 5])/([lindex $a 0]+256*[lindex $a 1])] +> set n [expr @{[lindex $a 4] + 256 * [lindex $a 5]@}] +> set d [expr @{[lindex $a 0] + 256 * [lindex $a 1]@}] +> echo [expr @{2 * 1.2 * $n / $d@}] 3.24891518738 @end example @end deffn @@ -4523,13 +4525,13 @@ where the mask bit is 1. The following example sets HPROT3 (cacheable) and leaves the rest of the pattern intact. It configures memory access through DCache on Cortex-M7. @example -set CSW_HPROT3_CACHEABLE [expr 1 << 27] +set CSW_HPROT3_CACHEABLE [expr @{1 << 27@}] samv.dap apcsw $CSW_HPROT3_CACHEABLE $CSW_HPROT3_CACHEABLE @end example Another example clears SPROT bit and leaves the rest of pattern intact: @example -set CSW_SPROT [expr 1 << 30] +set CSW_SPROT [expr @{1 << 30@}] samv.dap apcsw 0 $CSW_SPROT @end example @@ -8620,7 +8622,7 @@ In addition the following arguments may be specified: proc load_image_bin @{fname foffset address length @} @{ # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. - load_image $fname [expr $address - $foffset] bin \ + load_image $fname [expr @{$address - $foffset@}] bin \ $address $length @} @end example @@ -10402,7 +10404,7 @@ trivial challenge-response protocol could be implemented as follows in a configuration file, immediately following @command{init}: @example set challenge [riscv authdata_read] -riscv authdata_write [expr $challenge + 1] +riscv authdata_write [expr @{$challenge + 1@}] @end example @deffn {Command} {riscv authdata_read} @@ -12111,7 +12113,7 @@ it reads a file and executes as a script. @example set x 6 set y 7 - puts [format "The answer: %d" [expr $x * $y]] + puts [format "The answer: %d" [expr @{$x * $y@}]] @end example @enumerate @item The SET command creates 2 variables, X and Y. @@ -12182,13 +12184,13 @@ proc myproc @{ @} @{ @b{Dynamic variable creation} @example # Dynamically create a bunch of variables. -for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr $x + 1]@} @{ +for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr @{$x + 1@}]@} @{ # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. - set $vn [expr (1 << $x)] + set $vn [expr @{1 << $x@}] @} @end example @b{Dynamic proc/command creation} From 1536e249f2c23399f3443f8351647ea3faa5112e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 14 Nov 2021 22:36:46 +0100 Subject: [PATCH 003/186] aarch64: dump a message when CTI is missing If the CTI is not specified OpenOCD fails target's examination without indicating the reason. Drop an error message about the missing CTI. Change-Id: I344537fb21cf38785796ba938e71890e04135509 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6788 Tested-by: jenkins --- src/target/aarch64.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index fc6bd6b30..30ef54792 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2635,8 +2635,10 @@ static int aarch64_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); - if (!pc->cti) + if (!pc->cti) { + LOG_TARGET_ERROR(target, "CTI not specified"); return ERROR_FAIL; + } armv8->cti = pc->cti; From 492ac453ab6b97280030fe6161dfcac3d84b36ce Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 24 Dec 2021 15:15:18 +0100 Subject: [PATCH 004/186] log: fix memory leak when log to file is enabled When log to file is enabled, the file is not closed by OpenOCD at exit. This is reported by Valgrind as a memory leak that is still reachable, as the internal buffers of 'FILE *log_output' are freed by the automatic fclose() at exit. Close the log file before exit. Change-Id: Id472c0d04462035254a9b49ecb0a4037263c6f6f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6789 Tested-by: jenkins --- src/helper/log.c | 9 +++++++++ src/helper/log.h | 1 + src/openocd.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/helper/log.c b/src/helper/log.c index caa0a66bf..686560742 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -302,6 +302,15 @@ void log_init(void) start = last_time = timeval_ms(); } +void log_exit(void) +{ + if (log_output && log_output != stderr) { + /* Close log file, if it was open and wasn't stderr. */ + fclose(log_output); + } + log_output = NULL; +} + int set_log_output(struct command_context *cmd_ctx, FILE *output) { log_output = output; diff --git a/src/helper/log.h b/src/helper/log.h index 621d467b4..f0378ae79 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -72,6 +72,7 @@ __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); * Initialize logging module. Call during program startup. */ void log_init(void); +void log_exit(void); int set_log_output(struct command_context *cmd_ctx, FILE *output); int log_register_commands(struct command_context *cmd_ctx); diff --git a/src/openocd.c b/src/openocd.c index 0292ba445..3c96d3214 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -437,6 +437,8 @@ int openocd_main(int argc, char *argv[]) rtt_exit(); free_config(); + log_exit(); + if (ret == ERROR_FAIL) return EXIT_FAILURE; else if (ret != ERROR_OK) From e3bda57982ed87bd4d5faace5ea669848f3fe556 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 23 Dec 2021 11:05:56 +0100 Subject: [PATCH 005/186] target: use target_event_name() We have the API target_event_name(). Use it to improve code readability. Change-Id: Ic48d2227bdefe9af05aff99a871a45e0612e5254 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6790 Tested-by: jenkins --- src/target/target.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index e9cbe39b7..7cdd8d830 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1834,7 +1834,7 @@ int target_call_event_callbacks(struct target *target, enum target_event event) } LOG_DEBUG("target event %i (%s) for core %s", event, - jim_nvp_value2name_simple(nvp_target_event, event)->name, + target_event_name(event), target_name(target)); target_handle_event(target, event); @@ -4816,7 +4816,7 @@ void target_handle_event(struct target *target, enum target_event e) target_name(target), target_type_name(target), e, - jim_nvp_value2name_simple(nvp_target_event, e)->name, + target_event_name(e), Jim_GetString(teap->body, NULL)); /* Override current target by the target an event @@ -4840,7 +4840,7 @@ void target_handle_event(struct target *target, enum target_event e) if (retval != JIM_OK) { Jim_MakeErrorMessage(teap->interp); LOG_USER("Error executing event %s on target %s:\n%s", - jim_nvp_value2name_simple(nvp_target_event, e)->name, + target_event_name(e), target_name(target), Jim_GetString(Jim_GetResult(teap->interp), NULL)); /* clean both error code and stacktrace before return */ @@ -5503,9 +5503,9 @@ COMMAND_HANDLER(handle_target_event_list) command_print(CMD, "------------------------- | " "----------------------------------------"); while (teap) { - struct jim_nvp *opt = jim_nvp_value2name_simple(nvp_target_event, teap->event); command_print(CMD, "%-25s | %s", - opt->name, Jim_GetString(teap->body, NULL)); + target_event_name(teap->event), + Jim_GetString(teap->body, NULL)); teap = teap->next; } command_print(CMD, "***END***"); From 666ff828b2024235694e4a0b47bf360b6ce6bcd7 Mon Sep 17 00:00:00 2001 From: Adrien Grassein Date: Thu, 6 Jan 2022 19:06:47 +0100 Subject: [PATCH 006/186] jtag: Add an option to ignore the bypass bit Some CPU wrongly indicate the bypas bit in the codeid. It's the case of the NanoXplore NG-ULTRA chip that export a configurable (and potentially invalid) ID for one of its component. Add an option to ignore it. Signed-off-by: Adrien Grassein Change-Id: Ic59743f23bfc4d4e23da0e8535fec8ca9e87ff1a Reviewed-on: https://review.openocd.org/c/openocd/+/6802 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Oleksij Rempel --- doc/openocd.texi | 4 ++++ src/jtag/core.c | 2 +- src/jtag/hla/hla_tcl.c | 2 ++ src/jtag/jtag.h | 3 +++ src/jtag/tcl.c | 6 ++++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index cee54ebf7..ed92eb4ec 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4153,6 +4153,10 @@ option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. +@item @code{-ignore-bypass} +@*Specify this to ignore the 'bypass' bit of the idcode. Some vendor put +an invalid idcode regarding this bit. Specify this to ignore this bit and +to not consider this tap in bypass mode. @item @code{-ircapture} @var{NUMBER} @*The bit pattern loaded by the TAP into the JTAG shift register on entry to the @sc{ircapture} state, such as 0x01. diff --git a/src/jtag/core.c b/src/jtag/core.c index 29ab6cc1c..bbc9877ee 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1273,7 +1273,7 @@ static int jtag_examine_chain(void) jtag_tap_init(tap); } - if ((idcode & 1) == 0) { + if ((idcode & 1) == 0 && !tap->ignore_bypass) { /* Zero for LSB indicates a device in bypass */ LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%" PRIx32 ")", tap->dotted_name, idcode); diff --git a/src/jtag/hla/hla_tcl.c b/src/jtag/hla/hla_tcl.c index 5aa330145..6b206d231 100644 --- a/src/jtag/hla/hla_tcl.c +++ b/src/jtag/hla/hla_tcl.c @@ -59,6 +59,7 @@ static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi #define NTAP_OPT_DISABLED 4 #define NTAP_OPT_EXPECTED_ID 5 #define NTAP_OPT_VERSION 6 +#define NTAP_OPT_BYPASS 7 static int jim_hl_newtap_cmd(struct jim_getopt_info *goi) { @@ -75,6 +76,7 @@ static int jim_hl_newtap_cmd(struct jim_getopt_info *goi) { .name = "-disable", .value = NTAP_OPT_DISABLED }, { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, + { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, { .name = NULL, .value = -1}, }; diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index d7d7d977c..def594ee3 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -135,6 +135,9 @@ struct jtag_tap { /** Flag saying whether to ignore version field in expected_ids[] */ bool ignore_version; + /** Flag saying whether to ignore the bypass bit in the code */ + bool ignore_bypass; + /** current instruction */ uint8_t *cur_instr; /** Bypass register selected */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 566c406b9..e6e976d77 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -470,6 +470,7 @@ static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi #define NTAP_OPT_DISABLED 4 #define NTAP_OPT_EXPECTED_ID 5 #define NTAP_OPT_VERSION 6 +#define NTAP_OPT_BYPASS 7 static int jim_newtap_ir_param(struct jim_nvp *n, struct jim_getopt_info *goi, struct jtag_tap *tap) @@ -532,6 +533,7 @@ static int jim_newtap_cmd(struct jim_getopt_info *goi) { .name = "-disable", .value = NTAP_OPT_DISABLED }, { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, + { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, { .name = NULL, .value = -1 }, }; @@ -617,6 +619,9 @@ static int jim_newtap_cmd(struct jim_getopt_info *goi) case NTAP_OPT_VERSION: tap->ignore_version = true; break; + case NTAP_OPT_BYPASS: + tap->ignore_bypass = true; + break; } /* switch (n->value) */ } /* while (goi->argc) */ @@ -887,6 +892,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " + "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, From 6f3daf38c76db24422023c42f66d128cedb32813 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 27 Jan 2022 10:00:06 -0800 Subject: [PATCH 007/186] Fix small memory leak. (#672) Change-Id: Ia11ab9bcf860f770ea64ad867102c74b898f6b66 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1c7d55996..ec6821d14 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2291,9 +2291,11 @@ static int init_target(struct command_context *cmd_ctx, generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; + if (generic_info->version_specific == NULL) { + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + } generic_info->sample_memory = sample_memory; riscv013_info_t *info = get_info(target); From efb0b116dac19f511003a28e4cec9723693b9c2b Mon Sep 17 00:00:00 2001 From: Hans-Erik Floryd Date: Fri, 21 Jan 2022 12:07:56 +0100 Subject: [PATCH 008/186] flash/nor/atsame5: add LAN9255 devices Support Microchip LAN9255 devices with embedded SAME53J MCU. Signed-off-by: Hans-Erik Floryd Change-Id: Ia811c593bf7cf73e588d32873c68eb67c6fafad7 Reviewed-on: https://review.openocd.org/c/openocd/+/6811 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/flash/nor/atsame5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index 9ab0e8113..fbf0fb2ed 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -146,6 +146,9 @@ static const struct samd_part same53_parts[] = { { 0x04, "SAME53J20A", 1024, 256 }, { 0x05, "SAME53J19A", 512, 192 }, { 0x06, "SAME53J18A", 256, 128 }, + { 0x55, "LAN9255/ZMX020", 1024, 256 }, + { 0x56, "LAN9255/ZMX019", 512, 192 }, + { 0x57, "LAN9255/ZMX018", 256, 128 }, }; /* Known SAME54 parts. */ From 5e0cc43838b898a125d7028ee1ec3c033c3b24c1 Mon Sep 17 00:00:00 2001 From: Hans-Erik Floryd Date: Fri, 21 Jan 2022 12:13:12 +0100 Subject: [PATCH 009/186] tcl/board: Add EVB-LAN9255 config Config for EVB-LAN9255, tested using Atmel-ICE debugger on J10 connector. Signed-off-by: Hans-Erik Floryd Change-Id: I8bcf779e9363499a98aa0b7d10819c53da6a19e7 Reviewed-on: https://review.openocd.org/c/openocd/+/6812 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/evb-lan9255.cfg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tcl/board/evb-lan9255.cfg diff --git a/tcl/board/evb-lan9255.cfg b/tcl/board/evb-lan9255.cfg new file mode 100644 index 000000000..3fd6f603b --- /dev/null +++ b/tcl/board/evb-lan9255.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip LAN9255 evaluation board +# https://www.microchip.com/en-us/development-tool/EV25Y25A +# + +set CHIPNAME same53 + +source [find target/atsame5x.cfg] + +reset_config srst_only From 93f2276cdd99ad9e9d844150553621ea5d8524dd Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Wed, 12 Jan 2022 09:41:13 +0100 Subject: [PATCH 010/186] aarch64: support for aarch32 ARM_MODE_UND Fix: unrecognized psr mode: 0x1b cannot read system control register in this mode: (UNRECOGNIZED : 0x1b) Change-Id: I4dc3e72f90d57e52c0fe63cb59a7529a398757b3 Signed-off-by: Julien Massot Change-Id: Ifa5d21ae97492fde9e8c79ee7d99d8a2a871b1b5 Reviewed-on: https://review.openocd.org/c/openocd/+/6808 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 3 +++ src/target/armv8.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 30ef54792..d11fd943b 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -102,6 +102,7 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -180,6 +181,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -1049,6 +1051,7 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; diff --git a/src/target/armv8.c b/src/target/armv8.c index 26116bb33..2de115712 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -77,6 +77,10 @@ static const struct { .name = "HYP", .psr = ARM_MODE_HYP, }, + { + .name = "UND", + .psr = ARM_MODE_UND, + }, { .name = "SYS", .psr = ARM_MODE_SYS, From 6541233aa78d40200092920ec4a72e3917ae3b6d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 8 Jul 2021 17:43:00 -0700 Subject: [PATCH 011/186] Combine register lists of smp targets. This is helpful when you want to pretend to gdb that your heterogeneous multicore system is homogeneous, because gdb cannot handle heterogeneous systems. This won't always works, but works fine if e.g. one of the cores has an FPU while the other does not. (Specifically, HiFive Unleashed has 1 core with no FPU, plus 4 cores with an FPU.) Signed-off-by: Tim Newsome Change-Id: I05ff4c28646778fbc00327bc510be064bfe6c9f0 Reviewed-on: https://review.openocd.org/c/openocd/+/6362 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 106 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 7c853730f..b6f4a8264 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2259,6 +2259,108 @@ static int get_reg_features_list(struct target *target, char const **feature_lis return ERROR_OK; } +/* Create a register list that's the union of all the registers of the SMP + * group this target is in. If the target is not part of an SMP group, this + * returns the same as target_get_gdb_reg_list_noread(). + */ +static int smp_reg_list_noread(struct target *target, + struct reg **combined_list[], int *combined_list_size, + enum target_register_class reg_class) +{ + if (!target->smp) + return target_get_gdb_reg_list_noread(target, combined_list, + combined_list_size, REG_CLASS_ALL); + + unsigned int combined_allocated = 256; + *combined_list = malloc(combined_allocated * sizeof(struct reg *)); + if (*combined_list == NULL) { + LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + return ERROR_FAIL; + } + *combined_list_size = 0; + + struct target_list *head; + foreach_smp_target(head, target->head) { + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(*combined_list); + return result; + } + for (int i = 0; i < reg_list_size; i++) { + bool found = false; + struct reg *a = reg_list[i]; + if (a->exist) { + /* Nested loop makes this O(n^2), but this entire function with + * 5 RISC-V targets takes just 2ms on my computer. Fast enough + * for me. */ + for (int j = 0; j < *combined_list_size; j++) { + struct reg *b = (*combined_list)[j]; + if (!strcmp(a->name, b->name)) { + found = true; + if (a->size != b->size) { + LOG_ERROR("SMP register %s is %d bits on one " + "target, but %d bits on another target.", + a->name, a->size, b->size); + free(reg_list); + free(*combined_list); + return ERROR_FAIL; + } + break; + } + } + if (!found) { + LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); + if (*combined_list_size >= (int) combined_allocated) { + combined_allocated *= 2; + *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *)); + if (*combined_list == NULL) { + LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + return ERROR_FAIL; + } + } + (*combined_list)[*combined_list_size] = a; + (*combined_list_size)++; + } + } + } + free(reg_list); + } + + /* Now warn the user about any registers that weren't found in every target. */ + foreach_smp_target(head, target->head) { + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(*combined_list); + return result; + } + for (int i = 0; i < *combined_list_size; i++) { + bool found = false; + struct reg *a = (*combined_list)[i]; + for (int j = 0; j < reg_list_size; j++) { + struct reg *b = reg_list[j]; + if (b->exist && !strcmp(a->name, b->name)) { + found = true; + break; + } + } + if (!found) { + LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " + "this register does exist.", + a->name, target_name(head->target)); + } + } + free(reg_list); + } + + return ERROR_OK; +} + static int gdb_generate_target_description(struct target *target, char **tdesc_out) { int retval = ERROR_OK; @@ -2272,8 +2374,8 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int size = 0; - retval = target_get_gdb_reg_list_noread(target, ®_list, - ®_list_size, REG_CLASS_ALL); + retval = smp_reg_list_noread(target, ®_list, ®_list_size, + REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); From dbbac5f11d662ab0827a997aa5d173fd62c51708 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 9 Jan 2022 23:18:13 +0200 Subject: [PATCH 012/186] semihosting: use open mode flags from GDB, not from sys/stat.h Values defined in sys/stat.h are not guaranteed to match the constants defined by the GDB remote protocol, which are defined in https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags. On my local system (Manjaro 21.2.1 x86_64), for example, O_TRUNC is defined as 0x40, whereas GDB requires it to be 0x400, causing all "w" file open modes to misbehave. This patch has been tested with STM32F446. Change-Id: Ifb2c740fd689e71d6f1a4bde1edaecd76fdca910 Signed-off-by: Pavel Kirienko Reviewed-on: https://review.openocd.org/c/openocd/+/6804 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/semihosting_common.c | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 1b65e126c..8d3f66ca5 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -52,19 +52,35 @@ #include #include +/** + * It is not possible to use O_... flags defined in sys/stat.h because they + * are not guaranteed to match the values defined by the GDB Remote Protocol. + * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags + */ +enum { + TARGET_O_RDONLY = 0x000, + TARGET_O_WRONLY = 0x001, + TARGET_O_RDWR = 0x002, + TARGET_O_APPEND = 0x008, + TARGET_O_CREAT = 0x200, + TARGET_O_TRUNC = 0x400, + /* O_EXCL=0x800 is not required in this implementation. */ +}; + +/* GDB remote protocol does not differentiate between text and binary open modes. */ static const int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + TARGET_O_RDONLY, + TARGET_O_RDONLY, + TARGET_O_RDWR, + TARGET_O_RDWR, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; static int semihosting_common_fileio_info(struct target *target, From 52ca5d198e3b4a0565e810ff4b5545dfac39cec9 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 31 Jan 2022 09:23:38 -0800 Subject: [PATCH 013/186] Ask the RTOS which target to set swbp on. (#673) This lets the RTOS pick the "current" target, which matters if address translation differs between threads. Change-Id: I5b5510ab6a06621589c902f42a91562055817dc4 Signed-off-by: Tim Newsome --- src/rtos/hwthread.c | 9 +++++++++ src/rtos/rtos.c | 8 ++++++++ src/rtos/rtos.h | 9 +++++++++ src/target/breakpoints.c | 15 +++++++++------ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index a8f1b594e..4b8e22b10 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -43,6 +43,8 @@ static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer); static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer); +struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, + uint32_t length, enum breakpoint_type type); #define HW_THREAD_NAME_STR_SIZE (32) @@ -66,6 +68,7 @@ const struct rtos_type hwthread_rtos = { .needs_fake_step = hwthread_needs_fake_step, .read_buffer = hwthread_read_buffer, .write_buffer = hwthread_write_buffer, + .swbp_target = hwthread_swbp_target }; struct hwthread_params { @@ -444,3 +447,9 @@ static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, return target_write_buffer(curr, address, size, buffer); } + +struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, + uint32_t length, enum breakpoint_type type) +{ + return hwthread_find_thread(rtos->target, rtos->current_thread); +} diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index fafbda231..8141658c7 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -836,3 +836,11 @@ int rtos_write_buffer(struct target *target, target_addr_t address, return target->rtos->type->write_buffer(target->rtos, address, size, buffer); return ERROR_NOT_IMPLEMENTED; } + +struct target *rtos_swbp_target(struct target *target, target_addr_t address, + uint32_t length, enum breakpoint_type type) +{ + if (target->rtos->type->swbp_target) + return target->rtos->type->swbp_target(target->rtos, address, length, type); + return target; +} diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 2e41c1465..0cad6eefc 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -20,6 +20,7 @@ #define OPENOCD_RTOS_RTOS_H #include "server/server.h" +#include "target/breakpoints.h" #include "target/target.h" #include @@ -103,6 +104,12 @@ struct rtos_type { uint8_t *buffer); int (*write_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer); + /* When a software breakpoint is set, it is set on only one target, + * because we assume memory is shared across them. By default this is the + * first target in the SMP group. Override this function to have + * breakpoint_add() use a different target. */ + struct target * (*swbp_target)(struct rtos *rtos, target_addr_t address, + uint32_t length, enum breakpoint_type type); }; struct stack_register_offset { @@ -166,5 +173,7 @@ int rtos_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); int rtos_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); +struct target *rtos_swbp_target(struct target *target, target_addr_t address, + uint32_t length, enum breakpoint_type type); #endif /* OPENOCD_RTOS_RTOS_H */ diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index dd901ef25..938a7ecce 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -26,6 +26,7 @@ #include "target.h" #include #include "breakpoints.h" +#include "rtos/rtos.h" static const char * const breakpoint_type_strings[] = { "hardware", @@ -218,14 +219,16 @@ int breakpoint_add(struct target *target, { int retval = ERROR_OK; if (target->smp) { - struct target_list *head; - struct target *curr; - head = target->head; - if (type == BKPT_SOFT) - return breakpoint_add_internal(head->target, address, length, type); + struct target_list *head = target->head; + if (type == BKPT_SOFT) { + struct target *curr = head->target; + if (target->rtos) + curr = rtos_swbp_target(target, address, length, type); + return breakpoint_add_internal(curr, address, length, type); + } while (head) { - curr = head->target; + struct target *curr = head->target; retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; From 5ab74bde06541ce199390ead348a3e107ee9c0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Dud=C3=A1s?= Date: Wed, 24 Nov 2021 17:13:50 +0100 Subject: [PATCH 014/186] semihosting: User defined operation, Tcl command exec on host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling a portion (0x100 - 0x107) of the user defined semihosting operation number range (0x100 - 0x1FF) to be processed with the help of the existing target event mechanism, to implement a general-purpose Tcl interface for the target available on the host, via semihosting interface. Example usage: - The user configures a Tcl command as a callback for one of the newly defined events (semihosting-user-cmd-0x10X) in the configuration file. - The target can make a semihosting call with , passing optional parameters for the call. If there is no callback registered to the user defined operation number, nothing happens. Example usage: Configure RTT automatically with the exact, linked control block location from target. Signed-off-by: Zoltán Dudás Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247 Reviewed-on: https://review.openocd.org/c/openocd/+/6748 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: Antonio Borneo --- doc/openocd.texi | 27 +++++++ src/target/arm_semihosting.c | 7 +- src/target/riscv/riscv_semihosting.c | 4 +- src/target/semihosting_common.c | 104 ++++++++++++++++++++++++++- src/target/semihosting_common.h | 6 ++ src/target/target.c | 9 +++ src/target/target.h | 9 +++ 7 files changed, 162 insertions(+), 4 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ed92eb4ec..e2c495473 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5185,6 +5185,22 @@ when reset disables PLLs needed to use a fast clock. @* After single-step has completed @item @b{trace-config} @* After target hardware trace configuration was changed +@item @b{semihosting-user-cmd-0x100} +@* The target made a semihosting call with user-defined operation number 0x100 +@item @b{semihosting-user-cmd-0x101} +@* The target made a semihosting call with user-defined operation number 0x101 +@item @b{semihosting-user-cmd-0x102} +@* The target made a semihosting call with user-defined operation number 0x102 +@item @b{semihosting-user-cmd-0x103} +@* The target made a semihosting call with user-defined operation number 0x103 +@item @b{semihosting-user-cmd-0x104} +@* The target made a semihosting call with user-defined operation number 0x104 +@item @b{semihosting-user-cmd-0x105} +@* The target made a semihosting call with user-defined operation number 0x105 +@item @b{semihosting-user-cmd-0x106} +@* The target made a semihosting call with user-defined operation number 0x106 +@item @b{semihosting-user-cmd-0x107} +@* The target made a semihosting call with user-defined operation number 0x107 @end itemize @quotation Note @@ -9241,6 +9257,17 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn +@deffn {Command} {arm semihosting_read_user_param} +@cindex ARM semihosting +Read parameter of the semihosting call from the target. Usable in +semihosting-user-cmd-0x10* event handlers, returning a string. + +When the target makes semihosting call with operation number from range 0x100- +0x107, an optional string parameter can be passed to the server. This parameter +is valid during the run of the event handlers and is accessible with this +command. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 792474acf..507d1cd2c 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -367,10 +367,13 @@ int arm_semihosting(struct target *target, int *retval) } /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); + LOG_ERROR("Failed semihosting operation (0x%02X)", + semihosting->op); return 0; } } else { diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index b347212d3..1dd8e7791 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -140,7 +140,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) semihosting->word_size_bytes = riscv_xlen(target) / 8; /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 8d3f66ca5..9e60de572 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -154,6 +154,12 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +/** + * User operation parameter string storage buffer. Contains valid data when the + * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. + */ +static char *semihosting_user_op_params; + /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation @@ -183,7 +189,7 @@ 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, (int)semihosting->op, + LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); switch (semihosting->op) { @@ -1278,6 +1284,71 @@ int semihosting_common(struct target *target) } break; + case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107: + /** + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, only 0x100-0x107 are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + { + assert(!semihosting_user_op_params); + + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read fields for user defined command" + " op=0x%x", semihosting->op); + return retval; + } + + uint64_t addr = semihosting_get_field(target, 0, fields); + + size_t len = semihosting_get_field(target, 1, fields); + if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { + LOG_ERROR("The maximum length for user defined command " + "parameter is %u, received length is %zu (op=0x%x)", + SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + len, + semihosting->op); + return ERROR_FAIL; + } + + semihosting_user_op_params = malloc(len + 1); + if (!semihosting_user_op_params) + return ERROR_FAIL; + semihosting_user_op_params[len] = 0; + + 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); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + return retval; + } + + target_handle_event(target, semihosting->op); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + + semihosting->result = 0; + break; + } + + case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* * Returns the number of elapsed target ticks since execution @@ -1624,6 +1695,30 @@ COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct semihosting *semihosting = target->semihosting; + + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!semihosting->is_active) { + LOG_ERROR("semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (!semihosting_user_op_params) { + LOG_ERROR("This command is usable only from a registered user " + "semihosting event callback."); + return ERROR_FAIL; + } + + command_print_sameline(CMD, "%s", semihosting_user_op_params); + + return ERROR_OK; +} + const struct command_registration semihosting_common_handlers[] = { { "semihosting", @@ -1653,5 +1748,12 @@ const struct command_registration semihosting_common_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, + { + "semihosting_read_user_param", + .handler = handle_common_semihosting_read_user_param_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "read parameters in semihosting-user-cmd-0x10X callbacks", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index b83464ed5..6eb9ca252 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -75,8 +75,14 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + 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 */ }; +/** Maximum allowed Tcl command segment length in bytes*/ +#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024) + /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). diff --git a/src/target/target.c b/src/target/target.c index 7cdd8d830..acfbd3df5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -236,6 +236,15 @@ static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" }, + { .name = NULL, .value = -1 } }; diff --git a/src/target/target.h b/src/target/target.h index 6ef8f10e0..974630f17 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -294,6 +294,15 @@ enum target_event { TARGET_EVENT_GDB_FLASH_WRITE_END, TARGET_EVENT_TRACE_CONFIG, + + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107, }; struct target_event_action { From f6ffede8b62e7092141d54e75238fde1ee00d0c2 Mon Sep 17 00:00:00 2001 From: Greg Savin Date: Mon, 7 Feb 2022 09:28:31 -0800 Subject: [PATCH 015/186] fix missing thread ID in stop reply when smp-configured hart (but not hart 0) single-stepped (#675) --- src/rtos/rtos.c | 24 ++++++++++++++++++++++-- src/rtos/rtos.h | 1 + src/server/gdb_server.c | 13 ++++++++----- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 8141658c7..b9adf0a25 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -22,6 +22,7 @@ #include "rtos.h" #include "target/target.h" +#include "target/smp.h" #include "helper/log.h" #include "helper/binarybuffer.h" #include "server/gdb_server.h" @@ -789,10 +790,29 @@ static int rtos_try_next(struct target *target) return 1; } -int rtos_update_threads(struct target *target) +struct rtos *rtos_of_target(struct target *target) { + /* Primarily consider the rtos field of the target itself, secondarily consider + * rtos field SMP leader target, then consider rtos field of any other target in the SMP group. + * Otherwise NULL return means that no associated non-zero rtos field could be found. */ + + struct target_list *pos; + if ((target->rtos) && (target->rtos->type)) - target->rtos->type->update_threads(target->rtos); + return target->rtos; + + foreach_smp_target(pos, target->head) + if ((pos->target->rtos) && (pos->target->rtos->type)) + return pos->target->rtos; + + return NULL; +} + +int rtos_update_threads(struct target *target) +{ + struct rtos *rtos = rtos_of_target(target); + if (rtos) + rtos->type->update_threads(rtos); return ERROR_OK; } diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 0cad6eefc..828fd26ae 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -175,5 +175,6 @@ int rtos_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); struct target *rtos_swbp_target(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); +struct rtos *rtos_of_target(struct target *target); #endif /* OPENOCD_RTOS_RTOS_H */ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 0269e5895..20cf67092 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -778,9 +778,12 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00"); } else { struct target *ct; - if (target->rtos) { - target->rtos->current_threadid = target->rtos->current_thread; - target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); + struct rtos *rtos; + + rtos = rtos_of_target(target); + if (rtos) { + rtos->current_threadid = rtos->current_thread; + rtos->gdb_target_for_threadid(connection, rtos->current_threadid, &ct); } else { ct = target; } @@ -817,9 +820,9 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } current_thread[0] = '\0'; - if (target->rtos) + if (rtos) snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";", - target->rtos->current_thread); + rtos->current_thread); sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); From 9fe791ba4a6228013a61a52c16e556c427264ebb Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Wed, 9 Feb 2022 21:36:58 +0100 Subject: [PATCH 016/186] riscv: fix remove_trigger return code for unavailable hw bp slot --- src/target/riscv/riscv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 09c1939fe..5a6fc0024 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -927,7 +927,7 @@ static int remove_trigger(struct target *target, struct trigger *trigger) if (i >= r->trigger_count) { LOG_ERROR("Couldn't find the hardware resources used by hardware " "trigger."); - return ERROR_FAIL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i, trigger->unique_id); From c3a864cfd628670c9bf1a7aba0ae9e6e389ad163 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 10 Feb 2022 10:28:51 -0800 Subject: [PATCH 017/186] .gitmodules: switch away from repo.or.cz Manually applying https://review.openocd.org/c/openocd/+/6834 (which hasn't merged yet) since repo.or.cz is down often enough that it's affecting development. Change-Id: Idb337c799662f3e0fa72379c59c52a61a048044e Signed-off-by: Tim Newsome --- .gitmodules | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index feb8014b9..f2da17ed7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ +[submodule "tools/git2cl"] + path = tools/git2cl + url = https://git.savannah.nongnu.org/git/git2cl.git [submodule "jimtcl"] path = jimtcl url = https://github.com/msteveb/jimtcl.git -[submodule "tools/git2cl"] - path = tools/git2cl - url = https://repo.or.cz/git2cl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink - url = https://repo.or.cz/libjaylink.git + url = https://gitlab.zapb.de/libjaylink/libjaylink.git From feb83b78b7d66248217b14cda4a5d1b8306a4a4a Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Fri, 11 Feb 2022 08:16:10 +0100 Subject: [PATCH 018/186] fix progbuf cache: invalidate it when needed This commit relates to progbuf cache, implemented in https://github.com/riscv/riscv-openocd/pull/381 Make sure the cache gets invalidated when the progbuf contents change via other means. I've identified two such cases where the invalidation is required: 1) When the user manually tinkers with the progbuf registers (TCL command "riscv dmi_write") 2) When program buffer is used as a scratch memory (scratch_write64()) Change-Id: Ie7ffb0fccda63297de894ab919d09082ea21cfae Signed-off-by: Jan Matyas --- src/target/riscv/riscv-013.c | 15 +++++++++++++++ src/target/riscv/riscv.c | 18 ++++++++++++++---- src/target/riscv/riscv.h | 1 + 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ec6821d14..9ed2d2f53 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -52,6 +52,7 @@ static int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index); +static int riscv013_invalidate_cached_debug_buffer(struct target *target); static int riscv013_execute_debug_buffer(struct target *target); static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); @@ -1248,6 +1249,7 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, case SPACE_DMI_PROGBUF: dmi_write(target, DM_PROGBUF0 + scratch->debug_address, value); dmi_write(target, DM_PROGBUF1 + scratch->debug_address, value >> 32); + riscv013_invalidate_cached_debug_buffer(target); break; case SPACE_DMI_RAM: { @@ -2278,6 +2280,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->read_debug_buffer = &riscv013_read_debug_buffer; generic_info->write_debug_buffer = &riscv013_write_debug_buffer; generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; + generic_info->invalidate_cached_debug_buffer = &riscv013_invalidate_cached_debug_buffer; generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; @@ -4337,6 +4340,18 @@ riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) return value; } +int riscv013_invalidate_cached_debug_buffer(struct target *target) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "Invalidating progbuf cache"); + for (unsigned int i = 0; i < 15; i++) + dm->progbuf_cache[i] = 0; + return ERROR_OK; +} + int riscv013_execute_debug_buffer(struct target *target) { uint32_t run_program = 0; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 09c1939fe..783d937f7 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2795,11 +2795,21 @@ COMMAND_HANDLER(riscv_dmi_write) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); if (r->dmi_write) { - return r->dmi_write(target, address, value); - } else { - LOG_ERROR("dmi_write is not implemented for this target."); - return ERROR_FAIL; + /* Perform the DMI write */ + int retval = r->dmi_write(target, address, value); + + /* If the user tinkered with progbuf registers, we need to + drop our cached copy of the progbuf */ + if (address >= DM_PROGBUF0 && address <= DM_PROGBUF15) { + if (r->invalidate_cached_debug_buffer) + r->invalidate_cached_debug_buffer(target); + } + + return retval; } + + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; } COMMAND_HANDLER(riscv_test_sba_config_reg) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 531c896b9..f1104e35b 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -161,6 +161,7 @@ typedef struct { riscv_insn_t d); riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); int (*execute_debug_buffer)(struct target *target); + int (*invalidate_cached_debug_buffer)(struct target *target); int (*dmi_write_u64_bits)(struct target *target); void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d); void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); From 8274cc58c1a1b44ac23fd542f136d9265c6c3252 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Mon, 14 Feb 2022 14:10:17 +0100 Subject: [PATCH 019/186] fix progbuf cache: another two cases for invalidation Continuation of the previous patch. There are two more cases when progbuf cache in OpenOCD shall be invalidated: - When OpenOCD resets the debug module undergoes reset (dmactive=0), e.g. during target examination - When the user manually performs that very same operation (via riscv dmi_write) Change-Id: I53f8f08250eeedcbd55ab4361d5665370b063680 Signed-off-by: Jan Matyas --- src/target/riscv/riscv-013.c | 5 ++++- src/target/riscv/riscv.c | 11 ++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9ed2d2f53..62866dcfd 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1568,6 +1568,9 @@ static int examine(struct target *target) dmi_write(target, DM_DMCONTROL, 0); dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); dm->was_reset = true; + + /* The DM gets reset, so forget any cached progbuf entries. */ + riscv013_invalidate_cached_debug_buffer(target); } dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | @@ -2371,7 +2374,7 @@ static int assert_reset(struct target *target) /* The DM might have gotten reset if OpenOCD called us in some reset that * involves SRST being toggled. So clear our cache which may be out of * date. */ - memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache)); + riscv013_invalidate_cached_debug_buffer(target); return ERROR_OK; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 783d937f7..7be42ef5e 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2798,9 +2798,14 @@ COMMAND_HANDLER(riscv_dmi_write) /* Perform the DMI write */ int retval = r->dmi_write(target, address, value); - /* If the user tinkered with progbuf registers, we need to - drop our cached copy of the progbuf */ - if (address >= DM_PROGBUF0 && address <= DM_PROGBUF15) { + /* Invalidate our cached progbuf copy: + - if the user tinkered directly with a progbuf register + - if debug module was reset, in which case progbuf registers + may not retain their value. + */ + bool progbufTouched = (address >= DM_PROGBUF0 && address <= DM_PROGBUF15); + bool dmDeactivated = (address == DM_DMCONTROL && (value & DM_DMCONTROL_DMACTIVE) == 0); + if (progbufTouched || dmDeactivated) { if (r->invalidate_cached_debug_buffer) r->invalidate_cached_debug_buffer(target); } From 16cc853bcfbcc8dba6eadd91b434c05387034c0a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 16 Dec 2021 01:59:14 +0100 Subject: [PATCH 020/186] target/smp: use a struct list_head to hold the smp targets Instead of reinventing a simply linked list, reuse the list helper for the list of targets in a smp cluster. Using the existing helper, that implements a double linked list, makes trivial going through the list in reverse order. Change-Id: Ib36ad2955f15cd2a601b0b9e36ca6d948b12d00f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6783 Tested-by: jenkins --- src/rtos/hwthread.c | 8 +-- src/rtos/linux.c | 16 ++---- src/server/gdb_server.c | 11 ++--- src/target/aarch64.c | 15 +++--- src/target/armv7a.c | 9 ++-- src/target/armv7a_cache.c | 9 ++-- src/target/armv7a_cache_l2x.c | 9 ++-- src/target/armv8_cache.c | 8 ++- src/target/breakpoints.c | 93 +++++++++++++++-------------------- src/target/cortex_a.c | 26 ++++------ src/target/mips_m4k.c | 22 +++------ src/target/riscv/riscv.c | 23 ++++----- src/target/smp.c | 10 ++-- src/target/smp.h | 3 +- src/target/target.c | 44 +++++++++-------- src/target/target.h | 6 ++- 16 files changed, 135 insertions(+), 177 deletions(-) diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 3702b0b47..7c998861f 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -23,6 +23,7 @@ #include "target/target.h" #include "target/target_type.h" #include "target/register.h" +#include #include "rtos.h" #include "helper/log.h" #include "helper/types.h" @@ -107,7 +108,7 @@ static int hwthread_update_threads(struct rtos *rtos) /* determine the number of "threads" */ if (target->smp) { - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -123,7 +124,7 @@ static int hwthread_update_threads(struct rtos *rtos) if (target->smp) { /* loop over all threads */ - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -218,7 +219,8 @@ static struct target *hwthread_find_thread(struct target *target, int64_t thread if (!target) return NULL; if (target->smp) { - for (struct target_list *head = target->head; head; head = head->next) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { if (thread_id == threadid_from_target(head->target)) return head->target; } diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 84b4c6524..d147c1cf0 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -30,6 +30,7 @@ #include "rtos.h" #include "rtos_standard_stackings.h" #include +#include #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 @@ -191,16 +192,14 @@ static int linux_os_thread_reg_list(struct rtos *rtos, /* search target to perform the access */ struct reg **gdb_reg_list; struct target_list *head; - head = target->head; found = 0; - do { + foreach_smp_target(head, target->smp_targets) { if (head->target->coreid == next->core_id) { target = head->target; found = 1; break; } - head = head->next; - } while (head); + } if (found == 0) { LOG_ERROR @@ -397,7 +396,6 @@ static int get_name(struct target *target, struct threads *t) static int get_current(struct target *target, int create) { struct target_list *head; - head = target->head; uint8_t *buf; uint32_t val; uint32_t ti_addr; @@ -413,7 +411,7 @@ static int get_current(struct target *target, int create) ctt = ctt->next; } - while (head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list; int reg_list_size; int retval; @@ -474,7 +472,6 @@ static int get_current(struct target *target, int create) } free(reg_list); - head = head->next; } free(buffer); @@ -1394,9 +1391,8 @@ static int linux_os_smp_init(struct target *target) struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos->rtos_specific_params; @@ -1413,8 +1409,6 @@ static int linux_os_smp_init(struct target *target) os_linux->nr_cpus++; free(smp_os_linux); } - - head = head->next; } return ERROR_OK; diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b6f4a8264..537670c52 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2280,7 +2280,7 @@ static int smp_reg_list_noread(struct target *target, *combined_list_size = 0; struct target_list *head; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -2330,7 +2330,7 @@ static int smp_reg_list_noread(struct target *target, } /* Now warn the user about any registers that weren't found in every target. */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -3659,13 +3659,10 @@ static int gdb_target_start(struct target *target, const char *port) /* initialize all targets gdb service with the same pointer */ { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) curr->gdb_service = gdb_service; - head = head->next; } } return ret; diff --git a/src/target/aarch64.c b/src/target/aarch64.c index d11fd943b..a45322d2f 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -333,15 +333,14 @@ static int aarch64_wait_halt_one(struct target *target) static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; - struct target_list *head = target->head; + struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); - head = head->next; if (exc_target && curr == target) continue; @@ -430,7 +429,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) struct target_list *head; struct target *curr; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; @@ -480,7 +479,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* poll all targets in the group, but skip the target that serves GDB */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -745,7 +744,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint struct target *first = NULL; uint64_t address; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ @@ -800,7 +799,7 @@ static int aarch64_step_restart_smp(struct target *target) struct target *curr = target; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -888,7 +887,7 @@ static int aarch64_resume(struct target *target, int current, struct target_list *head; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 2259fa560..d564f19ae 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -38,6 +38,7 @@ #include "arm_opcodes.h" #include "target.h" #include "target_type.h" +#include "smp.h" static void armv7a_show_fault_registers(struct target *target) { @@ -193,8 +194,7 @@ int armv7a_read_ttbcr(struct target *target) static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); @@ -207,15 +207,14 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_ERROR("smp target : outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return JIM_OK; } diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 4078fdde2..ba6f076f0 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -26,6 +26,7 @@ #include "armv7a_cache.h" #include #include "arm_opcodes.h" +#include "smp.h" static int armv7a_l1_d_cache_sanity_check(struct target *target) { @@ -138,14 +139,10 @@ int armv7a_cache_auto_flush_all_data(struct target *target) if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) retval = armv7a_l1_d_cache_clean_inval_all(curr); - - head = head->next; } } else retval = armv7a_l1_d_cache_clean_inval_all(target); diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index 6b42fae53..c26d05173 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -27,6 +27,7 @@ #include #include "target.h" #include "target_type.h" +#include "smp.h" static int arm7a_l2x_sanity_check(struct target *target) { @@ -194,8 +195,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -210,8 +210,8 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t /* initialize all targets in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -220,7 +220,6 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t } armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return ERROR_OK; } diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index f05ac07cd..5b58d3f9f 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -23,6 +23,7 @@ #include "armv8_cache.h" #include "armv8_dpm.h" #include "armv8_opcodes.h" +#include "smp.h" /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 @@ -250,15 +251,12 @@ static int armv8_flush_all_data(struct target *target) /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) { LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); retval = _armv8_flush_all_data(curr); } - head = head->next; } } else retval = _armv8_flush_all_data(target); diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index dd901ef25..8439ff395 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -26,6 +26,7 @@ #include "target.h" #include #include "breakpoints.h" +#include "smp.h" static const char * const breakpoint_type_strings[] = { "hardware", @@ -216,22 +217,22 @@ int breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - if (type == BKPT_SOFT) + + if (type == BKPT_SOFT) { + head = list_first_entry(target->smp_targets, struct target_list, lh); return breakpoint_add_internal(head->target, address, length, type); + } - while (head) { - curr = head->target; - retval = breakpoint_add_internal(curr, address, length, type); + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return breakpoint_add_internal(target, address, length, type); } @@ -242,19 +243,17 @@ int context_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = context_breakpoint_add_internal(curr, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return context_breakpoint_add_internal(target, asid, length, type); } @@ -266,19 +265,17 @@ int hybrid_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else return hybrid_breakpoint_add_internal(target, address, asid, length, type); } @@ -345,12 +342,10 @@ void breakpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_breakpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_breakpoints += breakpoint_remove_internal(curr, address); - head = head->next; } if (!num_breakpoints) LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); @@ -363,12 +358,10 @@ void breakpoint_remove_all(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_remove_all_internal(curr); - head = head->next; } } else { breakpoint_remove_all_internal(target); @@ -387,12 +380,10 @@ void breakpoint_clear_target(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_clear_target_internal(curr); - head = head->next; } } else { breakpoint_clear_target_internal(target); @@ -482,21 +473,17 @@ 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) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = watchpoint_add_internal(curr, address, length, rw, value, - mask); + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return watchpoint_add_internal(target, address, length, rw, value, mask); @@ -549,12 +536,10 @@ void watchpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_watchpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_watchpoints += watchpoint_remove_internal(curr, address); - head = head->next; } if (num_watchpoints == 0) LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bf65544f5..272411359 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -639,14 +639,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -656,14 +653,12 @@ static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED) && target_was_examined(curr)) retval += cortex_a_halt(curr); - head = head->next; } return retval; } @@ -684,7 +679,7 @@ static int update_halt_gdb(struct target *target) if (target->gdb_service) gdb_target = target->gdb_service->target; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -951,11 +946,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; - struct target *curr; target_addr_t address; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ @@ -963,8 +957,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index ca4416981..8627bce6e 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -128,14 +128,11 @@ static int mips_m4k_debug_entry(struct target *target) static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -144,11 +141,10 @@ static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) ret = mips_m4k_halt(curr); @@ -156,7 +152,6 @@ static int mips_m4k_halt_smp(struct target *target) LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid); retval = ret; } - head = head->next; } return retval; } @@ -414,12 +409,10 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, @@ -431,7 +424,6 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han retval = ret; } } - head = head->next; } return retval; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index c9840fe50..931f76290 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -13,6 +13,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" +#include #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" @@ -1232,13 +1233,14 @@ int riscv_halt(struct target *target) int result = ERROR_OK; if (target->smp) { - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_prep(t) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1247,7 +1249,7 @@ int riscv_halt(struct target *target) } } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_finish(t) != ERROR_OK) return ERROR_FAIL; @@ -1469,14 +1471,15 @@ int riscv_resume( LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); int result = ERROR_OK; if (target->smp && !single_hart) { - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1486,7 +1489,7 @@ int riscv_resume( } } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t) != ERROR_OK) return ERROR_FAIL; @@ -2180,9 +2183,8 @@ int riscv_openocd_poll(struct target *target) unsigned halts_discovered = 0; unsigned should_remain_halted = 0; unsigned should_resume = 0; - unsigned i = 0; - for (struct target_list *list = target->head; list; - list = list->next, i++) { + struct target_list *list; + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; riscv_info_t *r = riscv_info(t); enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); @@ -2242,8 +2244,7 @@ int riscv_openocd_poll(struct target *target) } /* Sample memory if any target is running. */ - for (struct target_list *list = target->head; list; - list = list->next, i++) { + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; if (t->state == TARGET_RUNNING) { sample_memory(target); diff --git a/src/target/smp.c b/src/target/smp.c index 518f6e458..3e1ded8bc 100644 --- a/src/target/smp.c +++ b/src/target/smp.c @@ -111,18 +111,18 @@ COMMAND_HANDLER(default_handle_smp_command) } if (!strcmp(CMD_ARGV[0], "on")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 1; return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "off")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 0; /* fixes the target display to the debugger */ - if (target->head) + if (!list_empty(target->smp_targets)) target->gdb_service->target = target; return ERROR_OK; @@ -135,9 +135,7 @@ COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; - struct target_list *head; - head = target->head; - if (head) { + if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); diff --git a/src/target/smp.h b/src/target/smp.h index 3338240ad..46fc55f75 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -19,10 +19,11 @@ #ifndef OPENOCD_TARGET_SMP_H #define OPENOCD_TARGET_SMP_H +#include #include "server/server.h" #define foreach_smp_target(pos, head) \ - for (pos = head; (pos); pos = pos->next) + list_for_each_entry(pos, head, lh) extern const struct command_registration smp_command_handlers[]; diff --git a/src/target/target.c b/src/target/target.c index acfbd3df5..6250d3031 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -56,6 +56,7 @@ #include "rtos/rtos.h" #include "transport/transport.h" #include "arm_cti.h" +#include "smp.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -159,6 +160,7 @@ static int64_t target_timer_next_event_value; static LIST_HEAD(target_reset_callback_list); static LIST_HEAD(target_trace_callback_list); static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static LIST_HEAD(empty_smp_targets); static const struct jim_nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, @@ -2272,13 +2274,15 @@ static void target_destroy(struct target *target) /* release the targets SMP list */ if (target->smp) { - struct target_list *head = target->head; - while (head) { - struct target_list *pos = head->next; + struct target_list *head, *tmp; + + list_for_each_entry_safe(head, tmp, target->smp_targets, lh) { + list_del(&head->lh); head->target->smp = 0; free(head); - head = pos; } + if (target->smp_targets != &empty_smp_targets) + free(target->smp_targets); target->smp = 0; } @@ -5786,6 +5790,9 @@ static int target_create(struct jim_getopt_info *goi) return JIM_ERR; } + /* set empty smp cluster */ + target->smp_targets = &empty_smp_targets; + /* set target number */ target->target_number = new_target_number(); @@ -5998,9 +6005,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) const char *targetname; int retval, len; struct target *target = NULL; - struct target_list *head, *curr, *new; - curr = NULL; - head = NULL; + struct target_list *head, *new; retval = 0; LOG_DEBUG("%d", argc); @@ -6009,6 +6014,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) * argv[3] ... */ + struct list_head *lh = malloc(sizeof(*lh)); + if (!lh) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + INIT_LIST_HEAD(lh); + for (i = 1; i < argc; i++) { targetname = Jim_GetString(argv[i], &len); @@ -6017,24 +6029,14 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (target) { new = malloc(sizeof(struct target_list)); new->target = target; - new->next = NULL; - if (!head) { - head = new; - curr = head; - } else { - curr->next = new; - curr = new; - } + list_add_tail(&new->lh, lh); } } /* now parse the list of cpu and put the target in smp mode*/ - curr = head; - - while (curr) { - target = curr->target; + foreach_smp_target(head, lh) { + target = head->target; target->smp = 1; - target->head = head; - curr = curr->next; + target->smp_targets = lh; } if (target && target->rtos) diff --git a/src/target/target.h b/src/target/target.h index 974630f17..1f1a35420 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -201,7 +201,9 @@ struct target { * and must be detected when symbols are offered */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ - struct target_list *head; + struct list_head *smp_targets; /* list all targets in this smp group/cluster + * The head of the list is shared between the + * cluster, thus here there is a pointer */ /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing @@ -220,8 +222,8 @@ struct target { }; struct target_list { + struct list_head lh; struct target *target; - struct target_list *next; }; struct gdb_fileio_info { From a11fe473eaee235a51dba7900c08cc7629ed2794 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 16 Dec 2021 11:25:32 +0100 Subject: [PATCH 021/186] helper/list: add list_for_each_entry_direction() Use a bool flag to specify if the list should be forward or backward iterated. Change-Id: Ied19d049f46cdcb7f50137d459cc7c02014526bc Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6784 Tested-by: jenkins --- src/helper/list.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/helper/list.h b/src/helper/list.h index a7cd4ad37..552a3202a 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -656,6 +656,20 @@ static inline void list_splice_tail_init(struct list_head *list, !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) +/** + * list_for_each_entry_direction - iterate forward/backward over list of given type + * @param forward the iterate direction, true for forward, false for backward. + * @param pos the type * to use as a loop cursor. + * @param head the head for your list. + * @param member the name of the list_head within the struct. + */ +#define list_for_each_entry_direction(forward, pos, head, member) \ + for (pos = forward ? list_first_entry(head, typeof(*pos), member) \ + : list_last_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = forward ? list_next_entry(pos, member) \ + : list_prev_entry(pos, member)) + /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @param pos the type * to use as a start point From 49c40a75292b1f76fa0d4bad91c993d9f7a618cf Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 16 Dec 2021 12:54:35 +0100 Subject: [PATCH 022/186] target/riscv: revive 'riscv resume_order' This functionality was lost in [1], which was merged as commit 615709d14049 ("Upstream a whole host of RISC-V changes."). Now it works as expected again. Add convenience macro foreach_smp_target_direction(). Link: [1] https://github.com/riscv/riscv-openocd/pull/567 Change-Id: I1545fa6b45b8a07e27c8ff9dcdcfa2fc4f950cd1 Signed-off-by: Tim Newsome Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6785 Tested-by: jenkins --- src/target/riscv/riscv.c | 9 ++++++--- src/target/smp.h | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 931f76290..367506dde 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1472,14 +1472,16 @@ int riscv_resume( int result = ERROR_OK; if (target->smp && !single_hart) { struct target_list *tlist; - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1489,7 +1491,8 @@ int riscv_resume( } } - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/smp.h b/src/target/smp.h index 46fc55f75..490a49310 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -25,6 +25,9 @@ #define foreach_smp_target(pos, head) \ list_for_each_entry(pos, head, lh) +#define foreach_smp_target_direction(forward, pos, head) \ + list_for_each_entry_direction(forward, pos, head, lh) + extern const struct command_registration smp_command_handlers[]; int gdb_read_smp_packet(struct connection *connection, From 2a2636f138dc40be3fff06cb7bf1f126d906e0a1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 23 Jan 2022 00:37:10 +0100 Subject: [PATCH 023/186] doxygen: fix some function prototype description Change-Id: I49311a643ea73143839d2f6bde976cfd76f8c67f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6830 Tested-by: jenkins --- src/jtag/drivers/jlink.c | 2 -- src/jtag/drivers/ulink.c | 2 -- src/jtag/jtag.h | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index fdf4ae778..5c218742b 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -114,8 +114,6 @@ static int jlink_flush(void); * @param in A pointer to store TDO data to, if NULL the data will be discarded. * @param in_offset A bit offset for TDO data. * @param length Amount of bits to transfer out and in. - * - * @retval This function doesn't return any value. */ static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 3ae5cac62..20a036a78 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -604,8 +604,6 @@ static int ulink_get_queue_size(struct ulink *device, * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL */ static void ulink_clear_queue(struct ulink *device) { diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index def594ee3..4ec2f1e31 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -546,7 +546,8 @@ int jtag_srst_asserted(int *srst_asserted); * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. - * @returns Nothing, but calls jtag_set_error() on any error. + * + * returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); From f998a2aaf19c14b46fd7f7dd50607a0904f40bd3 Mon Sep 17 00:00:00 2001 From: Jacek Wuwer Date: Tue, 6 Apr 2021 20:08:11 +0200 Subject: [PATCH 024/186] Cadence virtual debug interface (vdebug) integration Change-Id: I1bc105b3addc3f34161c2356c482ff3011e3f2cc Signed-off-by: Jacek Wuwer Reviewed-on: https://review.openocd.org/c/openocd/+/6097 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: zapb Reviewed-by: Antonio Borneo --- configure.ac | 15 +- doc/openocd.texi | 41 ++ src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/vdebug.c | 1076 ++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/board/vd_a53x2_jtag.cfg | 31 + tcl/board/vd_m4_jtag.cfg | 30 + tcl/board/vd_pulpissimo_jtag.cfg | 32 + tcl/board/vd_swerv_jtag.cfg | 32 + tcl/interface/vdebug.cfg | 33 + tcl/target/vd_aarch64.cfg | 37 + tcl/target/vd_cortex_m.cfg | 12 + tcl/target/vd_riscv.cfg | 18 + 13 files changed, 1364 insertions(+), 2 deletions(-) create mode 100644 src/jtag/drivers/vdebug.c create mode 100644 tcl/board/vd_a53x2_jtag.cfg create mode 100644 tcl/board/vd_m4_jtag.cfg create mode 100644 tcl/board/vd_pulpissimo_jtag.cfg create mode 100644 tcl/board/vd_swerv_jtag.cfg create mode 100644 tcl/interface/vdebug.cfg create mode 100644 tcl/target/vd_aarch64.cfg create mode 100644 tcl/target/vd_cortex_m.cfg create mode 100644 tcl/target/vd_riscv.cfg diff --git a/configure.ac b/configure.ac index a178284ee..68fff45c1 100644 --- a/configure.ac +++ b/configure.ac @@ -274,6 +274,10 @@ AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) +AC_ARG_ENABLE([vdebug], + AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), + [build_vdebug=$enableval], [build_vdebug=no]) + AC_ARG_ENABLE([jtag_dpi], AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) @@ -513,6 +517,12 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_vdebug" = "xyes"], [ + AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) +], [ + AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) +]) + AS_IF([test "x$build_jtag_dpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) ], [ @@ -688,8 +698,9 @@ AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) -AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o "x$build_jtag_vpi" = "xyes"]) -AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dpi" = "xyes"]) +AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) +AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) diff --git a/doc/openocd.texi b/doc/openocd.texi index e2c495473..fd4a81da2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -588,6 +588,12 @@ produced, PDF schematics are easily found and it is easy to make. @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} +@item @b{vdebug} +@* A driver for Cadence virtual Debug Interface to emulated or simulated targets. +It implements a client connecting to the vdebug server, which in turn communicates +with the emulated or simulated RTL model through a transactor. The current version +supports only JTAG as a transport, but other virtual transports, like DAP are planned. + @item @b{jtag_dpi} @* A JTAG driver acting as a client for the SystemVerilog Direct Programming Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG @@ -3345,6 +3351,41 @@ This value is only used with the standard variant. @end deffn +@deffn {Interface Driver} {vdebug} +Cadence Virtual Debug Interface driver. + +@deffn {Config Command} {vdebug server} host:port +Specifies the host and TCP port number where the vdebug server runs. +@end deffn + +@deffn {Config Command} {vdebug batching} value +Specifies the batching method for the vdebug request. Possible values are +0 for no batching +1 or wr to batch write transactions together (default) +2 or rw to batch both read and write transactions +@end deffn + +@deffn {Config Command} {vdebug polling} min max +Takes two values, representing the polling interval in ms. Lower values mean faster +debugger responsiveness, but lower emulation performance. The minimum should be +around 10, maximum should not exceed 1000, which is the default gdb and keepalive +timeout value. +@end deffn + +@deffn {Config Command} {vdebug bfm_path} path clk_period +Specifies the hierarchical path and input clk period of the vdebug BFM in the design. +The hierarchical path uses Verilog notation top.inst.inst +The clock period must include the unit, for instance 40ns. +@end deffn + +@deffn {Config Command} {vdebug mem_path} path base size +Specifies the hierarchical path to the design memory instance for backdoor access. +Up to 4 memories can be specified. The hierarchical path uses Verilog notation. +The base specifies start address in the design address space, size its size in bytes. +Both values can use hexadecimal notation with prefix 0x. +@end deffn +@end deffn + @deffn {Interface Driver} {jtag_dpi} SystemVerilog Direct Programming Interface (DPI) compatible driver for JTAG devices in emulation. The driver acts as a client for the SystemVerilog diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index c2161523d..887f99bcd 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -75,6 +75,9 @@ endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif +if VDEBUG +DRIVERFILES += %D%/vdebug.c +endif if JTAG_DPI DRIVERFILES += %D%/jtag_dpi.c endif diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c new file mode 100644 index 000000000..a81740cb1 --- /dev/null +++ b/src/jtag/drivers/vdebug.c @@ -0,0 +1,1076 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/*---------------------------------------------------------------------------- + * Copyright 2020-2021 Cadence Design Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *---------------------------------------------------------------------------- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------- +*/ + +/*! + * @file + * + * @brief the virtual debug interface provides a connection between a sw debugger + * and the simulated, emulated core over a soft connection, implemented by DPI + * The vdebug debug driver currently supports JTAG transport + * TODO: implement support and test big endian platforms + * +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#ifdef HAVE_UNISTD_H +#include /* close */ +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#endif +#include +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include + +#include "jtag/interface.h" +#include "jtag/commands.h" +#include "transport/transport.h" +#include "helper/time_support.h" +#include "helper/replacements.h" +#include "helper/log.h" + +#define VD_VERSION 43 +#define VD_BUFFER_LEN 4024 +#define VD_CHEADER_LEN 24 +#define VD_SHEADER_LEN 16 + +#define VD_MAX_MEMORIES 4 +#define VD_POLL_INTERVAL 500 +#define VD_SCALE_PSTOMS 1000000000 + +/** + * @brief List of transactor types + */ +enum { + VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */ + VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */ + VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */ + VD_BFM_APB = 0x0004, /* transactor AMBA APB */ + VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */ + VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */ + VD_BFM_SWD = 0x0007, /* transactor serial SWD */ +}; + +/** + * @brief List of signals that can be read or written by the debugger + */ +enum { + VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */ + VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */ + VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */ + VD_SIG_RESET = 0x0008, /* DUT reset; rst */ + VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */ + VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */ + VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */ + VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */ + VD_SIG_BUF = 0x1000, /* memory buffer; mem */ +}; + +/** + * @brief List of errors + */ +enum { + VD_ERR_NONE = 0x0000, /* no error */ + VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */ + VD_ERR_USAGE = 0x0101, /* incorrect usage */ + VD_ERR_PARAM = 0x0102, /* incorrect parameter */ + VD_ERR_CONFIG = 0x0107, /* incorrect configuration */ + VD_ERR_NO_MEMORY = 0x0104, /* out of memory */ + VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */ + VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */ + VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */ + VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */ + VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */ + VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */ + VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */ + VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */ + VD_ERR_LOCKED = 0x0202, /* device locked */ + VD_ERR_NOT_RUN = 0x0204, /* transactor not running */ + VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */ + VD_ERR_LICENSE = 0x0206, /* cannot check out the license */ + VD_ERR_VERSION = 0x0207, /* transactor version mismatch */ + VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */ + VD_ERR_NO_POWER = 0x0302, /* power out error */ + VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */ + VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */ + VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */ + VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */ +}; + +enum { + VD_CMD_OPEN = 0x01, + VD_CMD_CLOSE = 0x02, + VD_CMD_CONNECT = 0x04, + VD_CMD_DISCONNECT = 0x05, + VD_CMD_WAIT = 0x09, + VD_CMD_SIGSET = 0x0a, + VD_CMD_SIGGET = 0x0b, + VD_CMD_JTAGCLOCK = 0x0f, + VD_CMD_JTAGSHTAP = 0x1a, + VD_CMD_MEMOPEN = 0x21, + VD_CMD_MEMCLOSE = 0x22, + VD_CMD_MEMWRITE = 0x23, +}; + +enum { + VD_BATCH_NO = 0, + VD_BATCH_WO = 1, + VD_BATCH_WR = 2, +}; + +struct vd_shm { + struct { /* VD_CHEADER_LEN written by client */ + uint8_t cmd; /* 000; command */ + uint8_t type; /* 001; interface type */ + uint16_t waddr; /* 002; write pointer */ + uint16_t wbytes; /* 004; data bytes */ + uint16_t rbytes; /* 006; data bytes to read */ + uint16_t wwords; /* 008; data words */ + uint16_t rwords; /* 00a; data words to read */ + uint32_t rwdata; /* 00c; read/write data */ + uint32_t offset; /* 010; address offset */ + uint16_t offseth; /* 014; address offset 47:32 */ + uint16_t wid; /* 016; request id*/ + }; + union { /* 018; */ + uint8_t wd8[VD_BUFFER_LEN]; + uint16_t wd16[VD_BUFFER_LEN / 2]; + uint32_t wd32[VD_BUFFER_LEN / 4]; + uint64_t wd64[VD_BUFFER_LEN / 8]; + }; + struct { /* VD_SHEADER_LEN written by server */ + uint16_t rid; /* fd0: request id read */ + uint16_t awords; /* fd2: actual data words read back */ + int32_t status; /* fd4; */ + uint64_t duttime; /* fd8; */ + }; + union { /* fe0: */ + uint8_t rd8[VD_BUFFER_LEN]; + uint16_t rd16[VD_BUFFER_LEN / 2]; + uint32_t rd32[VD_BUFFER_LEN / 4]; + uint64_t rd64[VD_BUFFER_LEN / 8]; + }; + uint32_t state; /* 1f98; connection state */ + uint32_t count; /* 1f9c; */ + uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */ +}; + +struct vd_client { + uint8_t trans_batch; + bool trans_first; + bool trans_last; + uint8_t mem_ndx; + uint8_t buf_width; + uint8_t addr_bits; + uint8_t bfm_type; + uint16_t sig_read; + uint16_t sig_write; + uint32_t bfm_period; + uint32_t mem_base[VD_MAX_MEMORIES]; + uint32_t mem_size[VD_MAX_MEMORIES]; + uint32_t mem_width[VD_MAX_MEMORIES]; + uint32_t mem_depth[VD_MAX_MEMORIES]; + uint16_t server_port; + uint32_t poll_cycles; + uint32_t poll_min; + uint32_t poll_max; + uint32_t targ_time; + int hsocket; + char server_name[32]; + char bfm_path[128]; + char mem_path[VD_MAX_MEMORIES][128]; + uint8_t *tdo; +}; + +struct vd_jtag_hdr { + uint64_t tlen:24; + uint64_t post:3; + uint64_t pre:3; + uint64_t cmd:2; + uint64_t wlen:16; + uint64_t rlen:16; +}; + +static struct vd_shm *pbuf; +static struct vd_client vdc; + +static int vdebug_socket_error(void) +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static int vdebug_socket_open(char *server_addr, uint32_t port) +{ + int hsock; + int rc = 0; + uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */ + struct addrinfo *ainfo = NULL; + struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; + +#ifdef _WIN32 + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock == INVALID_SOCKET) + rc = vdebug_socket_error(); +#else + uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */ + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock < 0) + rc = errno; + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) + rc = errno; +#endif + else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + + if (rc) { + LOG_ERROR("socket_open: cannot set socket option, error %d", rc); + } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) { + LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); + rc = VD_ERR_SOC_ADDR; + } else { + ((struct sockaddr_in *)(ainfo->ai_addr))->sin_port = htons(port); + if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) { + LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error()); + rc = VD_ERR_SOC_CONN; + } + } + + if (rc) { + close_socket(hsock); + hsock = 0; + } + + if (ainfo) + freeaddrinfo(ainfo); + + return hsock; +} + +static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) +{ + int rc; + int dreceived = 0; + int offset = (uint8_t *)&pmem->rid - &pmem->cmd; + int to_receive = VD_SHEADER_LEN + pmem->rbytes; + char *pb = (char *)pmem; + + do { + rc = recv(hsock, pb + offset, to_receive, 0); + if (rc <= 0) { + LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0); + return rc; + } + to_receive -= rc; + offset += rc; + LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive); + dreceived += rc; + } while (to_receive); + + return dreceived; +} + +static int vdebug_socket_send(int hsock, struct vd_shm *pmem) +{ + int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0); + if (rc <= 0) + LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error()); + else + LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc); + + return rc; +} + +static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) +{ + if (!hsock) + return VD_ERR_SOC_OPEN; + int st = vdebug_socket_send(hsock, pmem); + if (st <= 0) + return VD_ERR_SOC_SEND; + + int rd = vdebug_socket_receive(hsock, pmem); + if (rd <= 0) + return VD_ERR_SOC_RECV; + + int rc = pmem->status; + LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d", + pmem->cmd, st, rd, rc); + + return rc; +} + +int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) +{ + uint8_t num_pre, num_post, tdi, tms; + unsigned int num, anum, bytes, hwords, words; + unsigned int req, waddr, rwords; + int64_t ts, te; + uint8_t *tdo; + int rc; + struct vd_jtag_hdr *hdr; + + req = 0; /* beginning of request */ + waddr = 0; + rwords = 0; + pm->wbytes = pm->wwords * vdc.buf_width; + pm->rbytes = pm->rwords * vdc.buf_width; + ts = timeval_ms(); + rc = vdebug_wait_server(hsock, pm); + while (!rc && (req < count)) { /* loop over requests to read data and print out */ + hdr = (struct vd_jtag_hdr *)&pm->wd8[waddr * 4]; + hwords = hdr->wlen; + words = hdr->rlen; + anum = hdr->tlen; + num_pre = hdr->pre; + num_post = hdr->post; + if (num_post) + num = anum - num_pre - num_post + 1; + else + num = anum - num_pre; + bytes = (num + 7) / 8; + vdc.trans_last = (req + 1) < count ? 0 : 1; + vdc.trans_first = waddr ? 0 : 1; + if (hdr->cmd == 3) { /* read */ + tdo = vdc.tdo; + for (unsigned int j = 0; j < bytes; j++) { + tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre)); + LOG_DEBUG_IO("%04x D0[%02x]:%02x", pm->wid - count + req, j, tdo[j]); + } + rwords += words; /* read data offset */ + } else { + tdo = NULL; + } + waddr += sizeof(struct vd_jtag_hdr) / 4; /* waddr past header */ + tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre)); + tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre)); + LOG_DEBUG("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", + pm->wid - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), + waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd)); + waddr += hwords * 2; /* start of next request */ + req += 1; + } + + if (rc) { + LOG_ERROR("0x%x executing transaction", rc); + rc = ERROR_FAIL; + } + + te = timeval_ms(); + vdc.targ_time += (uint32_t)(te - ts); + pm->offseth = 0; /* reset buffer write address */ + pm->offset = 0; + pm->rwords = 0; + pm->waddr = 0; + + return rc; +} + +static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, + uint8_t type, uint32_t period_ps, uint32_t sig_mask) +{ + int rc = VD_ERR_NOT_OPEN; + + pm->cmd = VD_CMD_OPEN; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + rc = vdebug_wait_server(hsock, pm); + if (rc != 0) { /* communication problem */ + LOG_ERROR("0x%x connecting to server", rc); + } else if (pm->rid < pm->wid) { + LOG_ERROR("server version %d too old for the client %d", pm->rid, pm->wid); + pm->cmd = VD_CMD_CLOSE; /* let server close the connection */ + vdebug_wait_server(hsock, pm); + rc = VD_ERR_VERSION; + } else { + pm->cmd = VD_CMD_CONNECT; + pm->type = type; /* BFM type to connect to, here JTAG */ + pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16); + pm->wbytes = strlen(path) + 1; + pm->rbytes = 12; + pm->wid = 0; /* reset wid for transaction ID */ + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes + 1); + rc = vdebug_wait_server(hsock, pm); + vdc.sig_read = pm->rwdata >> 16; /* signal read mask */ + vdc.sig_write = pm->rwdata; /* signal write mask */ + vdc.bfm_period = period_ps; + vdc.buf_width = pm->rd32[0] / 8;/* access width in bytes */ + vdc.addr_bits = pm->rd32[2]; /* supported address bits */ + } + + if (rc) { + LOG_ERROR("0x%x connecting to BFM %s", rc, path); + return ERROR_FAIL; + } + + LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", + path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width, + vdc.buf_width, vdc.sig_read, vdc.sig_write); + + return ERROR_OK; +} + +static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type) +{ + pm->cmd = VD_CMD_DISCONNECT; + pm->type = type; /* BFM type, here JTAG */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + pm->cmd = VD_CMD_CLOSE; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("type %0x", type); + + return ERROR_OK; +} + +static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) +{ + if (cycles) { + pm->cmd = VD_CMD_WAIT; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = cycles; /* clock sycles to wait */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles); + return ERROR_FAIL; + } + LOG_DEBUG("%d cycles", cycles); + } + + return ERROR_OK; +} + +static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) +{ + pm->cmd = VD_CMD_SIGSET; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = (write_mask << 16) | (value & 0xffff); /* mask and value of signals to set */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask); + return ERROR_FAIL; + } + + LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value); + + return ERROR_OK; +} + +static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) +{ + pm->cmd = VD_CMD_JTAGCLOCK; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = value; /* divider value */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting jtag_clock", rc); + return ERROR_FAIL; + } + + LOG_DEBUG("setting jtag clock divider to %" PRIx32, value); + + return ERROR_OK; +} + +static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, + const uint8_t tms_pre, uint32_t num, const uint8_t *tdi, + uint8_t num_post, const uint8_t tms_post, uint8_t *tdo, + uint8_t f_last) +{ + const uint32_t tobits = 8; + uint16_t bytes, hwords, anum, words, waddr; + int rc = 0; + + pm->cmd = VD_CMD_JTAGSHTAP; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO) || tdo; + if (vdc.trans_first) + waddr = 0; /* reset buffer offset */ + else + waddr = pm->offseth; /* continue from the previous transaction */ + if (num_post) /* actual number of bits to shift */ + anum = num + num_pre + num_post - 1; + else + anum = num + num_pre; + hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */ + words = (hwords + 1) / 2; /* in 8B TDO words to read */ + bytes = (num + 7) / 8; /* data only portion in bytes */ + /* buffer overflow check and flush */ + if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords + 64 > VD_BUFFER_LEN) { + vdc.trans_last = 1; /* force flush within 64B of buffer end */ + } else if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords > VD_BUFFER_LEN) { + /* this req does not fit, discard it */ + LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift", + pm->wid, anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); + rc = ERROR_FAIL; + } + + if (!rc && anum) { + uint16_t i, j; + struct vd_jtag_hdr *hdr = (struct vd_jtag_hdr *)&pm->wd8[4 * waddr]; /* 8 bytes header */ + hdr->cmd = (tdo ? 3 : 1); /* R and W bits */ + hdr->pre = num_pre; + hdr->post = num_post; + hdr->tlen = anum; + hdr->wlen = hwords; + hdr->rlen = words; + pm->wid++; /* transaction ID */ + waddr += 2; /* waddr past header */ + /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */ + pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0); + pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */ + if (num + num_pre <= 8) /* and tms_post for num <=4 */ + pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1)); + for (i = 1, j = 4 * waddr; i < bytes; i++) { + if (i == bytes - 1 && num + num_pre <= bytes * tobits) + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); + else + pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */ + if (!tdi) /* placing 4 bytes of TDI bits into low word */ + pm->wd8[j + i] = 0x0; + else + pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre)); + if (i % 4 == 3) + j += 4; + } + + if (tdi) + if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */ + pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */ + + if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */ + pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */ + /* in case exactly 1 additional byte needed */ + } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) { + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */ + } else { /* in case 2 additional bytes, tms_post split */ + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */ + if (i % 4 == 3) /* next byte is in the next 32b word */ + pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + else /* next byte is in the same 32b word */ + pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + } + + if (tdo) { + pm->rwords += words; /* keep track of the words to read */ + vdc.tdo = tdo; + } + pm->wwords = waddr / 2 + hwords; /* payload size *2 to include both TDI and TMS data */ + pm->waddr++; + } + + if (!waddr) /* flush issued, but buffer empty */ + ; + else if (!vdc.trans_last) /* buffered request */ + pm->offseth = waddr + hwords * 2; /* offset for next transaction, must be even */ + else /* execute batch of requests */ + rc = vdebug_run_jtag_queue(hsock, pm, pm->waddr); + vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ + + return rc; +} + +static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx) +{ + int rc; + + if (!path) + return ERROR_OK; + + pm->cmd = VD_CMD_MEMOPEN; + pm->wbytes = strlen(path) + 1; /* includes terminating 0 */ + pm->rbytes = 8; + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes); + rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x opening memory %s", rc, path); + } else if (ndx != pm->rd16[1]) { + LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd16[1]); + } else { + vdc.mem_width[ndx] = pm->rd16[0] / 8; /* memory width in bytes */ + vdc.mem_depth[ndx] = pm->rd32[1]; /* memory depth in words */ + LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path, + vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]); + } + + return ERROR_OK; +} + +static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) +{ + pm->cmd = VD_CMD_MEMCLOSE; + pm->rwdata = ndx; /* which memory */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]); +} + +static int vdebug_init(void) +{ + vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); + pbuf = calloc(1, sizeof(struct vd_shm)); + if (!pbuf) { + close_socket(vdc.hsocket); + vdc.hsocket = 0; + LOG_ERROR("cannot allocate %lu bytes", sizeof(struct vd_shm)); + return ERROR_FAIL; + } + if (vdc.hsocket <= 0) { + free(pbuf); + pbuf = NULL; + LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16, + vdc.server_name, vdc.server_port); + return ERROR_FAIL; + } + vdc.trans_first = 1; + vdc.poll_cycles = vdc.poll_max; + uint32_t sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV; + int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask); + if (rc != 0) { + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.bfm_path, rc); + close_socket(vdc.hsocket); + vdc.hsocket = 0; + free(pbuf); + pbuf = NULL; + } else { + for (uint8_t i = 0; i < vdc.mem_ndx; i++) { + rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i); + if (rc != 0) + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.mem_path[i], rc); + } + + LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, + VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); + } + + return rc; +} + +static int vdebug_quit(void) +{ + for (uint8_t i = 0; i < vdc.mem_ndx; i++) + if (vdc.mem_width[i]) + vdebug_mem_close(vdc.hsocket, pbuf, i); + int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type); + LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION, + vdc.bfm_path, vdc.server_name, vdc.server_port, rc); + if (vdc.hsocket) + close_socket(vdc.hsocket); + free(pbuf); + pbuf = NULL; + + return ERROR_OK; +} + +static int vdebug_reset(int trst, int srst) +{ + uint16_t sig_val = 0xffff; + uint16_t sig_mask = 0; + + sig_mask |= VD_SIG_RESET; + if (srst) + sig_val &= ~VD_SIG_RESET;/* active low */ + if (transport_is_jtag()) { + sig_mask |= VD_SIG_TRST; + if (trst) + sig_val &= ~VD_SIG_TRST; /* active low */ + } + + LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val); + int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val); + if (rc == 0) + rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */ + + return rc; +} + +static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) +{ + LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t *)tms); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) +{ + uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; + LOG_INFO("path num states %d", cmd->num_states); + + memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); + + for (uint8_t i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + buf_set_u32(tms, i, 1, 1); + tap_set_state(cmd->path[i]); + } + + return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush); +} + +static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state); + if (cur != state) { + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush); + tap_set_state(state); + } + + return rc; +} + +static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); + uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); + int num_bits = jtag_scan_size(cmd); + LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", + num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); + for (int i = 0; i < cmd->num_fields; i++) { + uint8_t cur_num_pre = i == 0 ? num_pre : 0; + uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; + uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; + uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0; + uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0; + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre, + cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, + cmd->fields[i].in_value, cur_flush); + if (rc) + break; + } + + if (cur != cmd->end_state) + tap_set_state(cmd->end_state); + + return rc; +} + +static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) +{ + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state); + int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); + if (cur != state) + tap_set_state(state); + + return rc; +} + +static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) +{ + LOG_INFO("stab len:%d state cur:%x", num, tap_get_state()); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_sleep(int us) +{ + LOG_INFO("sleep %d us", us); + + return vdebug_wait(vdc.hsocket, pbuf, us / 1000); +} + +static int vdebug_jtag_speed(int speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = clkmax / speed; + LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval); + + return vdebug_jtag_clock(vdc.hsocket, pbuf, divval); +} + +static int vdebug_jtag_khz(int khz, int *jtag_speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = khz ? clkmax / khz : 1; + *jtag_speed = clkmax / divval; + LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz); + + return ERROR_OK; +} + +static int vdebug_jtag_div(int speed, int *khz) +{ + *khz = speed; + LOG_DEBUG("div khz:%d from speed:%d", *khz, speed); + + return ERROR_OK; +} + +static int vdebug_jtag_execute_queue(void) +{ + int rc = ERROR_OK; + + for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RUNTEST: + rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next); + break; + case JTAG_STABLECLOCKS: + rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next); + break; + case JTAG_TLR_RESET: + rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next); + break; + case JTAG_PATHMOVE: + rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next); + break; + case JTAG_TMS: + rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next); + break; + case JTAG_SLEEP: + rc = vdebug_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next); + break; + default: + LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type); + rc = ERROR_FAIL; + } + } + + return rc; +} + +COMMAND_HANDLER(vdebug_set_server) +{ + if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *pchar = strchr(CMD_ARGV[0], ':'); + *pchar = '\0'; + strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1); + int port = atoi(++pchar); + if (port < 0 || port > UINT16_MAX) { + LOG_ERROR("invalid port number %d specified", port); + return ERROR_COMMAND_SYNTAX_ERROR; + } + vdc.server_port = port; + LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_bfm) +{ + char prefix; + + if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2)) + return ERROR_COMMAND_SYNTAX_ERROR; + + strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1); + switch (prefix) { + case 'u': + vdc.bfm_period *= 1000000; + break; + case 'n': + vdc.bfm_period *= 1000; + break; + case 'p': + default: + break; + } + vdc.bfm_type = VD_BFM_JTAG; + LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_mem) +{ + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (vdc.mem_ndx >= VD_MAX_MEMORIES) { + LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); + return ERROR_FAIL; + } + + strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]); + LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx], + vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]); + vdc.mem_ndx++; + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_batching) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (isdigit((unsigned char)CMD_ARGV[0][0])) + vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2)); + else if (CMD_ARGV[0][0] == 'r') + vdc.trans_batch = VD_BATCH_WR; + else if (CMD_ARGV[0][0] == 'w') + vdc.trans_batch = VD_BATCH_WO; + else + vdc.trans_batch = VD_BATCH_NO; + LOG_DEBUG("batching: set to %u", vdc.trans_batch); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_polling) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + vdc.poll_min = atoi(CMD_ARGV[0]); + vdc.poll_max = atoi(CMD_ARGV[1]); + LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max); + + return ERROR_OK; +} + +static const struct command_registration vdebug_command_handlers[] = { + { + .name = "server", + .handler = &vdebug_set_server, + .mode = COMMAND_CONFIG, + .help = "set the vdebug server name or address", + .usage = "", + }, + { + .name = "bfm_path", + .handler = &vdebug_set_bfm, + .mode = COMMAND_CONFIG, + .help = "set the vdebug BFM hierarchical path", + .usage = " ", + }, + { + .name = "mem_path", + .handler = &vdebug_set_mem, + .mode = COMMAND_ANY, + .help = "set the design memory for the code load", + .usage = " ", + }, + { + .name = "batching", + .handler = &vdebug_set_batching, + .mode = COMMAND_CONFIG, + .help = "set the transaction batching no|wr|rd [0|1|2]", + .usage = "", + }, + { + .name = "polling", + .handler = &vdebug_set_polling, + .mode = COMMAND_CONFIG, + .help = "set the polling pause, executing hardware cycles between min and max", + .usage = " ", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration vdebug_command[] = { + { + .name = "vdebug", + .chain = vdebug_command_handlers, + .mode = COMMAND_ANY, + .help = "vdebug command group", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface vdebug_jtag_ops = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = vdebug_jtag_execute_queue, +}; + +struct adapter_driver vdebug_adapter_driver = { + .name = "vdebug", + .transports = jtag_only, + .speed = vdebug_jtag_speed, + .khz = vdebug_jtag_khz, + .speed_div = vdebug_jtag_div, + .commands = vdebug_command, + .init = vdebug_init, + .quit = vdebug_quit, + .reset = vdebug_reset, + .jtag_ops = &vdebug_jtag_ops, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 63faa9561..ddf70cc24 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -57,6 +57,9 @@ extern struct adapter_driver usb_blaster_adapter_driver; #if BUILD_JTAG_VPI == 1 extern struct adapter_driver jtag_vpi_adapter_driver; #endif +#if BUILD_VDEBUG == 1 +extern struct adapter_driver vdebug_adapter_driver; +#endif #if BUILD_JTAG_DPI == 1 extern struct adapter_driver jtag_dpi_adapter_driver; #endif @@ -168,6 +171,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, +#endif #if BUILD_JTAG_DPI == 1 &jtag_dpi_adapter_driver, #endif diff --git a/tcl/board/vd_a53x2_jtag.cfg b/tcl/board/vd_a53x2_jtag.cfg new file mode 100644 index 000000000..869bc4db0 --- /dev/null +++ b/tcl/board/vd_a53x2_jtag.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through JTAG + +source [find interface/vdebug.cfg] + +set _CORES 2 +set _CHIPNAME a53 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x1000000 +set _CPUTAPID 0x5ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_m4_jtag.cfg b/tcl/board/vd_m4_jtag.cfg new file mode 100644 index 000000000..ca21476d2 --- /dev/null +++ b/tcl/board/vd_m4_jtag.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m4 through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME m4 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 +set _CPUTAPID 0x4ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 25000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 20ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg new file mode 100644 index 000000000..69dd9e6db --- /dev/null +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV Ibex core with Pulpissimo through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME ibex +set _HARTID 0x20 +set _CPUTAPID 0x249511c3 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 12500 +adapter srst delay 10 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 40ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/board/vd_swerv_jtag.cfg b/tcl/board/vd_swerv_jtag.cfg new file mode 100644 index 000000000..ff6c6835f --- /dev/null +++ b/tcl/board/vd_swerv_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV swerv core with Swerv through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME rv32 +set _HARTID 0x00 +set _CPUTAPID 0x1000008b +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg new file mode 100644 index 000000000..9cca6aaab --- /dev/null +++ b/tcl/interface/vdebug.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface + +if { [info exists VDEBUGHOST] } { + set _VDEBUGHOST $VDEBUGHOST +} else { + set _VDEBUGHOST localhost +} +if { [info exists VDEBUGPORT] } { + set _VDEBUGPORT $VDEBUGPORT +} else { + set _VDEBUGPORT 8192 +} + +adapter driver vdebug +# vdebug server:port +vdebug server $_VDEBUGHOST:$_VDEBUGPORT + +# example config debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# example config listen on all interfaces, disable tcl/telnet server +bindto 0.0.0.0 +#gdb_port 3333 +#telnet_port disabled +tcl_port disabled + +# transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw +vdebug batching 1 + +# Polling values +vdebug polling 100 1000 \ No newline at end of file diff --git a/tcl/target/vd_aarch64.cfg b/tcl/target/vd_aarch64.cfg new file mode 100644 index 000000000..619134aa6 --- /dev/null +++ b/tcl/target/vd_aarch64.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm v8 64b Cortex A + +if {![info exists _CORES]} { + set _CORES 1 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME aarch64 +} +set _TARGETNAME $_CHIPNAME.cpu +set _CTINAME $_CHIPNAME.cti + +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME +$_CHIPNAME.dap apsel 1 + +for { set _core 0 } { $_core < $_CORES } { incr _core } \ +{ + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + set _smp_command "target smp $_TARGETNAME.$_core" + } + eval $_command +} +eval $_smp_command + +# default target is core 0 +targets $_TARGETNAME.0 diff --git a/tcl/target/vd_cortex_m.cfg b/tcl/target/vd_cortex_m.cfg new file mode 100644 index 000000000..4d7b0df26 --- /dev/null +++ b/tcl/target/vd_cortex_m.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# ARM Cortex M + +if {![info exists _CHIPNAME]} { + set _CHIPNAME cortex_m +} +set _TARGETNAME $_CHIPNAME.cpu + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg new file mode 100644 index 000000000..b42b25a3a --- /dev/null +++ b/tcl/target/vd_riscv.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV core + +if {![info exists _HARTID]} { + set _HARTID 0x00 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME riscv +} +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 +# prefer to use sba for system bus access +riscv set_prefer_sba on From 7307fd0e3faa7b3e060a722775c532bcb7f70057 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 27 Jan 2022 14:30:58 -0800 Subject: [PATCH 025/186] gdb_server: Include thread name as XML attribute Explicitly providing a thread name in the "thread" element produces better thread visualizations in downstream tools like IDEs. Signed-off-by: Ben McMorran Change-Id: I102c14ddb8b87757fa474de8e3a3f6a1cfe10d98 Reviewed-on: https://review.openocd.org/c/openocd/+/6828 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 537670c52..95720e561 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2619,8 +2619,14 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou if (!thread_detail->exists) continue; - xml_printf(&retval, &thread_list, &pos, &size, - "", thread_detail->threadid); + if (thread_detail->thread_name_str) + xml_printf(&retval, &thread_list, &pos, &size, + "", + thread_detail->threadid, + thread_detail->thread_name_str); + else + xml_printf(&retval, &thread_list, &pos, &size, + "", thread_detail->threadid); if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, From 2c0a65baa2f17a15fcb5bb014e5dda33fecddaf8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 27 Jan 2022 10:00:06 -0800 Subject: [PATCH 026/186] Fix small memory leak. See https://github.com/riscv/riscv-openocd/pull/672 Change-Id: Ia11ab9bcf860f770ea64ad867102c74b898f6b66 Signed-off-by: Tim Newsome Reviewed-on: https://review.openocd.org/c/openocd/+/6831 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo --- src/target/riscv/riscv-013.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 7af460241..2b9179d53 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2308,9 +2308,11 @@ static int init_target(struct command_context *cmd_ctx, generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; + if (!generic_info->version_specific) { + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + } generic_info->sample_memory = sample_memory; riscv013_info_t *info = get_info(target); From 37d506ae55587ecb6f20f56bc9b5a6f5edc1872f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 2 Feb 2022 23:55:50 +0100 Subject: [PATCH 027/186] server: remove remaining crust from dropped eCos code Commit 39650e2273bc ("ecosboard: delete bit-rotted eCos code") has removed eCos code but has left some empty function that was used during non-eCos build to replace eCos mutex. Drop the functions and the file that contain them. Change-Id: I31bc0237ea699c11bd70921660f960ee406ffa80 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6835 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/Makefile.am | 1 - src/server/server.c | 2 -- src/server/server.h | 9 --------- src/server/server_stubs.c | 30 ------------------------------ 4 files changed, 42 deletions(-) delete mode 100644 src/server/server_stubs.c diff --git a/src/server/Makefile.am b/src/server/Makefile.am index fb5248bfd..e3699f181 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -6,7 +6,6 @@ noinst_LTLIBRARIES += %D%/libserver.la %D%/server.h \ %D%/telnet_server.h \ %D%/gdb_server.h \ - %D%/server_stubs.c \ %D%/tcl_server.c \ %D%/tcl_server.h \ %D%/rtt_server.c \ diff --git a/src/server/server.c b/src/server/server.c index 3f579bfc6..1569f5a2c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -487,10 +487,8 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - openocd_sleep_prelude(); kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); - openocd_sleep_postlude(); } if (retval == -1) { diff --git a/src/server/server.h b/src/server/server.h index de18d2b4b..bacd1116a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -97,15 +97,6 @@ int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_prelude(void); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_postlude(void); - /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. diff --git a/src/server/server_stubs.c b/src/server/server_stubs.c deleted file mode 100644 index a4c017289..000000000 --- a/src/server/server_stubs.c +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "server.h" - -void openocd_sleep_prelude(void) -{ - /* no-op */ -} -void openocd_sleep_postlude(void) -{ - /* no-op */ -} From 254883597f2487f6e75e10c36991149679e21870 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 27 Jan 2022 14:45:16 -0800 Subject: [PATCH 028/186] rtos: threadx: Add hla_target support for ThreadX Tested with an AZ3166 dev board (which uses the STM32F412ZGT6) running the Azure RTOS ThreadX demonstration system. Signed-off-by: Ben McMorran Change-Id: I44c8f7701d9f1aaa872274166321cd7d34fb1855 Reviewed-on: https://review.openocd.org/c/openocd/+/6829 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/ThreadX.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 441b7abc5..4161e63fa 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -175,6 +175,18 @@ static const struct threadx_params threadx_params_list[] = { get_stacking_info_arm926ejs, /* fn_get_stacking_info */ is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */ }, + { + "hla_target", /* target_name */ + 4, /* pointer_width; */ + 8, /* thread_stack_offset; */ + 40, /* thread_name_offset; */ + 48, /* thread_state_offset; */ + 136, /* thread_next_offset */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + 1, /* stacking_info_nb */ + NULL, /* fn_get_stacking_info */ + NULL, /* fn_is_thread_id_valid */ + }, }; enum threadx_symbol_values { From 94e7535be85a7bd5905dec68b6eae9a98aae0d7e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 2 Feb 2022 13:46:46 +0100 Subject: [PATCH 029/186] .gitmodules: switch away from repo.or.cz The host repo.or.cz is often offline, creating issues for cloning and building OpenOCD from scratch. Already 'jimtcl' developer has dropped repo.or.cz, triggering the OpenOCD commit 861e75f54efb ("jimtcl: switch to github"). Change also the link of the remaining submodules 'git2cl' and 'libjaylink' to their respective main repository. Change-Id: Ib513237427635359ce36a480a8f2060e2fb12ba4 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6834 Tested-by: jenkins Reviewed-by: zapb --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 23ffa2543..f2da17ed7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "tools/git2cl"] path = tools/git2cl - url = https://repo.or.cz/git2cl.git + url = https://git.savannah.nongnu.org/git/git2cl.git [submodule "jimtcl"] path = jimtcl url = https://github.com/msteveb/jimtcl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink - url = https://repo.or.cz/libjaylink.git + url = https://gitlab.zapb.de/libjaylink/libjaylink.git From 64f3f8877e9dbedf7b80ea3d544e5a6a5b17ed61 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas <43336369+erhankur@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:02:07 +0100 Subject: [PATCH 030/186] riscv: call debug_execution related events (#679) Change-Id: Ice7cdc816f3e568a6ba2db8f9101903b8f7a08ce Signed-off-by: Erhan Kurubas --- src/target/riscv/riscv.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 882869477..91d1020da 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1490,13 +1490,14 @@ static int resume_go(struct target *target, int current, return result; } -static int resume_finish(struct target *target) +static int resume_finish(struct target *target, int debug_execution) { register_cache_invalidate(target->reg_cache); - target->state = TARGET_RUNNING; + target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; - return target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + return target_call_event_callbacks(target, + debug_execution ? TARGET_EVENT_DEBUG_RESUMED : TARGET_EVENT_RESUMED); } /* Return a newly allocated target list, that contains the same targets as in @@ -1566,7 +1567,7 @@ int riscv_resume( for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) { struct target *t = tlist->target; - if (resume_finish(t) != ERROR_OK) + if (resume_finish(t, debug_execution) != ERROR_OK) result = ERROR_FAIL; } @@ -1580,7 +1581,7 @@ int riscv_resume( if (resume_go(target, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; - if (resume_finish(target) != ERROR_OK) + if (resume_finish(target, debug_execution) != ERROR_OK) return ERROR_FAIL; } @@ -1975,7 +1976,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); - if (riscv_resume(target, 0, entry_point, 0, 0, true) != ERROR_OK) + if (riscv_resume(target, 0, entry_point, 0, 1, true) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); @@ -2177,7 +2178,7 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) LOG_DEBUG(" triggered a halt"); r->on_halt(target); return RPH_DISCOVERED_HALTED; - } else if (target->state != TARGET_RUNNING && !halted) { + } else if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING && !halted) { LOG_DEBUG(" triggered running"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2239,6 +2240,7 @@ int riscv_openocd_poll(struct target *target) { LOG_DEBUG("polling all harts"); int halted_hart = -1; + enum target_state old_state = target->state; if (target->smp) { unsigned halts_discovered = 0; @@ -2354,7 +2356,10 @@ int riscv_openocd_poll(struct target *target) return retval; } } else { - target_call_event_callbacks(target, TARGET_EVENT_HALTED); + if (old_state == TARGET_DEBUG_RUNNING) + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + else + target_call_event_callbacks(target, TARGET_EVENT_HALTED); } return ERROR_OK; From 29912328f07d562281e8a0db8855c8362afba546 Mon Sep 17 00:00:00 2001 From: Simon Johansson Date: Mon, 17 Jan 2022 13:30:59 +0100 Subject: [PATCH 031/186] flash/nor/stm32f2x: Fix erase of bank 2 sectors This commit corrects the erase function for stm32f2x when dealing with sectors in bank 2, for STM32F42x/43x devices with 1MB flash. On STM32F42x/43x with 1MB flash in dual bank configuration, the sector numbering is not consecutive. The last sector in bank 1 is number 7, and the first sector in bank 2 is number 12. The sector indices used by openocd, however, _are_ consecutive (0 to 15 in this case). The arguments "first" and "last" to stm32x_erase() are of this type, and so the logic surrounding sector numbers needed to be corrected. Since the two banks in dual bank mode have the same number of sectors, a sector index in bank 2 is larger than or equal to half the total number of sectors. Change-Id: I15260f8a86d9002769a1ae1c40ebdf62142dae18 Signed-off-by: Simon Johansson Reviewed-on: https://review.openocd.org/c/openocd/+/6810 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f2x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index d3e7d709c..aa0363232 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -636,8 +636,8 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) { unsigned int snb; - if (stm32x_info->has_large_mem && i >= 12) - snb = (i - 12) | 0x10; + if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2)) + snb = (i - (bank->num_sectors / 2)) | 0x10; else snb = i; From 10b5ac9ccb2b51b5aad01e4cb02be84fea3ebc62 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 24 Nov 2021 19:05:21 +0100 Subject: [PATCH 032/186] target/cortex_m: fix target_to_cm() helper The third parameter of container_of() should point to the same member as target->arch_info points to, struct arm. It worked just because struct arm is the first member in struct armv7m_common. If you move arm member from the first place, OpenOCD fails heavily. Change-Id: I0c0a5221490945563e17a0a34d99a603f1d6c2ff Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6749 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index c2f836a35..cabe405ce 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -251,7 +251,7 @@ static inline struct cortex_m_common * target_to_cm(struct target *target) { return container_of(target->arch_info, - struct cortex_m_common, armv7m); + struct cortex_m_common, armv7m.arm); } static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) From e4ba76a003ce4a2336eade806a04a278c376d0b6 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 24 Nov 2021 22:11:13 +0100 Subject: [PATCH 033/186] target/armv7m,cortex_m: introduce checked arch_info cast routines target_to_armv7m() and target_to_cm() do not match the magic number so they are not suitable for use outside of target driver code. Add checked versions of pointer getters. Match the magic number to ensure the returned value points to struct of the correct type. Change-Id: If90ef7e969ef04f0f2103e0da29dcbe8e1ac1c0d Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6750 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/armv7m.h | 37 +++++++++++++++++++++++++++++++++++-- src/target/cortex_m.h | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index d33e57492..9ac121ac3 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -255,15 +255,48 @@ struct armv7m_common { void (*pre_restore_context)(struct target *target); }; +static inline bool is_armv7m(const struct armv7m_common *armv7m) +{ + return armv7m->common_magic == ARMV7M_COMMON_MAGIC; +} + +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(const struct armv7m_common *armv7m) +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct armv7m_common * +target_to_armv7m_safe(struct target *target) { - return armv7m->common_magic == ARMV7M_COMMON_MAGIC; + if (!target) + return NULL; + + if (!target->arch_info) + return NULL; + + /* Check the parent type first to prevent peeking memory too far + * from arch_info pointer */ + if (!is_arm(target_to_arm(target))) + return NULL; + + struct armv7m_common *armv7m = target_to_armv7m(target); + if (!is_armv7m(armv7m)) + return NULL; + + return armv7m; } struct armv7m_algorithm { diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index cabe405ce..8fb34f46c 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -247,13 +247,6 @@ struct cortex_m_common { bool maskints_erratum; }; -static inline struct cortex_m_common * -target_to_cm(struct target *target) -{ - return container_of(target->arch_info, - struct cortex_m_common, armv7m.arm); -} - static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; @@ -267,6 +260,40 @@ static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cor return !cortex_m->armv7m.is_hla_target; } +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ +static inline struct cortex_m_common * +target_to_cm(struct target *target) +{ + return container_of(target->arch_info, + struct cortex_m_common, armv7m.arm); +} + +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct cortex_m_common * +target_to_cortex_m_safe(struct target *target) +{ + /* Check the parent types first to prevent peeking memory too far + * from arch_info pointer */ + if (!target_to_armv7m_safe(target)) + return NULL; + + struct cortex_m_common *cortex_m = target_to_cm(target); + if (!is_cortex_m_or_hla(cortex_m)) + return NULL; + + return cortex_m; +} + int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); From b53f5c257185e5410622ed72790affb1bda88248 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 25 Nov 2021 06:13:31 +0100 Subject: [PATCH 034/186] target/cortex_m: add Cortex-M part number getter The getter checks the magic numbers in arch_info to detect eventual type mismatch. Change-Id: I61134b05310a97ae9831517d0516c7b4240d35a5 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6751 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI --- src/target/cortex_m.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 8fb34f46c..555401416 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -46,6 +46,7 @@ #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) enum cortex_m_partno { + CORTEX_M_PARTNO_INVALID, CORTEX_M0_PARTNO = 0xC20, CORTEX_M1_PARTNO = 0xC21, CORTEX_M3_PARTNO = 0xC23, @@ -294,6 +295,23 @@ target_to_cortex_m_safe(struct target *target) return cortex_m; } +/** + * @returns cached value of Cortex-M part number + * 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) +{ + struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); + if (!cortex_m) + return CORTEX_M_PARTNO_INVALID; + + if (!cortex_m->core_info) + return CORTEX_M_PARTNO_INVALID; + + return cortex_m->core_info->partno; +} + int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); From 13cd75b6ecfd8d9cf04e56b182b6a162ad50247c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 25 Nov 2021 06:24:52 +0100 Subject: [PATCH 035/186] flash/nor/stm32xx: fix segfault accessing Cortex-M part number Some of STM32 flash drivers read Cortex-M part number from cortex_m->core_info. In corner cases the core_info pointer was observed uninitialised even if target_was_examined() returned true. See also [1] Use the new and safe helper to get Cortex-M part number. While on it switch also target_to_cm()/target_to_armv7m() to the safe versions. This prevents a crash when the flash bank is misconfigured with non-Cortex-M target. Add missing checks for target_was_examined() to flash probes. [1] 6545: fix crash in case cortex_m->core_info is not set https://review.openocd.org/c/openocd/+/6545 Change-Id: If2471af74ebfe22f14442f48ae109b2e1bb5fa3b Signed-off-by: Tomas Vanek Fixes: f5898bd93ff8 (flash/stm32fxx.c: do not read CPUID as this info is stored in cortex_m_common) Reviewed-on: https://review.openocd.org/c/openocd/+/6752 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 10 ++++------ src/flash/nor/stm32f2x.c | 9 +++++++-- src/flash/nor/stm32h7x.c | 9 +++++++-- src/flash/nor/stm32l4x.c | 27 +++++++++++++++++++++------ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 90cee6412..29a3b7e06 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -622,15 +622,14 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t device_id_register = 0; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ device_id_register = 0x40015800; break; @@ -659,15 +658,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t flash_size_reg; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ flash_size_reg = 0x1FFFF7CC; break; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index aa0363232..58edca7e1 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -966,14 +966,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) * Only effects Rev A silicon */ struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; - if ((*device_id & 0xfff) == 0x411 && cortex_m->core_info->partno == CORTEX_M4_PARTNO) { + if ((*device_id & 0xfff) == 0x411 + && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); @@ -1011,6 +1011,11 @@ static int stm32x_probe(struct flash_bank *bank) bank->num_prot_blocks = 0; bank->prot_blocks = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + /* if explicitly called out as OTP bank, short circuit probe */ if (stm32x_is_otp(bank)) { if (stm32x_otp_is_f7(bank)) { diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index d3f17b2b1..6d3149f94 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -759,7 +759,6 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; @@ -767,6 +766,11 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->probed = false; stm32x_info->part_info = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); if (retval != ERROR_OK) return retval; @@ -800,7 +804,8 @@ static int stm32x_probe(struct flash_bank *bank) /* get flash size from target */ /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; - if (device_id == DEVID_STM32H74_H75XX && cortex_m->core_info->partno == CORTEX_M4_PARTNO) + if (device_id == DEVID_STM32H74_H75XX + && cortex_m_get_partno_safe(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 e5100a015..fa8924ed3 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1633,12 +1633,13 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { int retval; + struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { - retval = target_read_u32(bank->target, dbgmcu_idcode[i], id); + retval = target_read_u32(target, dbgmcu_idcode[i], id); if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) return ERROR_OK; } @@ -1647,12 +1648,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1, * to solve this read the UID64 (IEEE 64-bit unique device ID register) */ - struct cortex_m_common *cortex_m = target_to_cm(bank->target); + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } /* 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->core_info->partno == CORTEX_M0P_PARTNO && - cortex_m->armv7m.debug_ap && cortex_m->armv7m.debug_ap->ap_num == 1) { + if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && + armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; /* UID64 is contains @@ -1662,7 +1667,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx */ - retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids); + retval = target_read_u32(target, UID64_IDS, &uid64_ids); if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) { /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ *id = DEVID_STM32WLE_WL5XX; @@ -1700,11 +1705,21 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank) static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct armv7m_common *armv7m = target_to_armv7m(target); struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; uint16_t flash_size_kb = 0xffff; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } + stm32l4_info->probed = false; /* read stm32 device id registers */ From d673521c39dcf82ce4c2e6d9d4dcdc7460c09fbe Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:40:24 -0500 Subject: [PATCH 036/186] cpld: altera-epm240: Add additional IDCODEs This adds some additional IDCODEs from the datasheet. It also adds support for customizing the tap name. Signed-off-by: Sean Anderson Change-Id: I7cda10b92c229b61836c12cd9ca410de358ede2e Reviewed-on: https://review.openocd.org/c/openocd/+/6846 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/cpld/altera-epm240.cfg | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 62f2b73b7..6e10188ca 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,6 +1,19 @@ # Altera MAXII EPM240T100C CPLD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME epm240 +} + # see MAX II Device Handbook # Table 3-3: 32-Bit MAX II Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0001 000 0110 1110 1 -jtag newtap epm240 tap -expected-id 0x020a10dd -irlen 10 +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020a10dd \ + -expected-id 0x020a20dd \ + -expected-id 0x020a30dd \ + -expected-id 0x020a40dd \ + -expected-id 0x020a50dd \ + -expected-id 0x020a60dd From b61eae1962f008627f4593cfda9b3431e4c3c016 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:43:30 -0500 Subject: [PATCH 037/186] cpld: altera-epm240: Increase adapter speed According to the datasheet, the minimum clock period with Vccio1 = 1.5V (the lowest voltage supported) is 143ns, or around 6MHz. Set the default adapter speed to 5 MHz. Signed-off-by: Sean Anderson Change-Id: I21cad33fa7f1e25e81f43b5d2214d1fa4ec924de Reviewed-on: https://review.openocd.org/c/openocd/+/6847 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/cpld/altera-epm240.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 6e10188ca..ece02bbef 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -17,3 +17,7 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020a40dd \ -expected-id 0x020a50dd \ -expected-id 0x020a60dd + +# 200ns seems like a good speed +# c.f. Table 5-34: MAX II JTAG Timing Parameters +adapter speed 5000 From 3fcfe4f196f6c333ee0ba2078af9cfa3eb896761 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:45:32 -0500 Subject: [PATCH 038/186] target: Add support for ls1088a The LS1088A is an octo-core aarch64 processor from NXP in the layerscape family. The JTAG is undocumented, but I was able to figure things out from the output of `dap info`. This is the first in-tree example of using the hwthread rtos (as far as I know), so hopefully it can serve as an example to other developers. There are some ETMs, but I was unable to try them out because I got 'invalid command name "etm"' when trying to test things out. Signed-off-by: Sean Anderson Change-Id: I9b0791d27d8c41170a413a8d86431107a85feba2 Reviewed-on: https://review.openocd.org/c/openocd/+/6848 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1088a.cfg | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tcl/target/ls1088a.cfg diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg new file mode 100644 index 000000000..136ee77a3 --- /dev/null +++ b/tcl/target/ls1088a.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1088a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +set _CPU_BASE 0x81000000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 8} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +targets $_CHIPNAME.cpu0 + +# Seems to work OK in testing +adapter speed 10000 From d1278660afcb3315fe74def3c2ca51cf28424963 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 14 Feb 2022 17:53:11 -0500 Subject: [PATCH 039/186] target: ls1088a: Add service processor Normally the service processor is not necessary for debugging. However, if you are using the hard-coded RCW or your boot source is otherwise corrupt, then the general purpose processors will never be released from hold-off. This will cause GDB to become confused if it tries to attach, since they will appear to be running arm32 processors. To deal with this, we can release the CPUs manually with the BRRL register. This register cannot be written to from the axi target, so we need to do it from the service processor target. This involves halting the service processor, modifying the register, and then resuming it again. We try and determine what state the service processor was in to avoid resuming it if it was already halted. The reset vector for the general purpose processors is determined by the boot logation pointer registers in the device configuration unit. Normally these are set using pre-boot initialization commands, but if they are not set then they default to 0. This will cause the CPU to almost immediately hit an illegal instruction. This is fine because we will almost certainly want to attach to the processor and load a program anyway. I considered adding this as an event handler for either gdb-attach or reset-init. However, this command shouldn't be necessary most of the time, and so I don't think we should run it automatically. Signed-off-by: Sean Anderson Change-Id: I1b725292d8a11274d03af5313dc83678e10e944c Reviewed-on: https://review.openocd.org/c/openocd/+/6850 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1088a.cfg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg index 136ee77a3..f9ae9a134 100644 --- a/tcl/target/ls1088a.cfg +++ b/tcl/target/ls1088a.cfg @@ -36,6 +36,38 @@ for {set i 0} {$i < 8} {incr i} { target smp {*}$_TARGETS +# Service processor +target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 + +# Normally you will not need to call this, but if you are using the hard-coded +# Reset Configuration Word (RCW) you will need to call this manually. The CPU's +# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit +# instructions. This will cause the CPU to almost immediately execute an +# illegal instruction. +# +# This code is idempotent; releasing a released CPU has no effect, although it +# will halt/resume the service processor. +add_help_text release_cpu "Release a cpu which is held off" +proc release_cpu {cpu} { + set RST_BRRL 0x1e60060 + + set old [target current] + targets $::_CHIPNAME.sp + set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] + if {$not_halted} { + halt + } + + # Release the cpu; it will start executing something bogus + mem2array regs 32 $RST_BRRL 1 + mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + + if {$not_halted} { + resume + } + targets $old +} + targets $_CHIPNAME.cpu0 # Seems to work OK in testing From e84be7088d5972ddd9bf502f8f66ac3b06ed3dda Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:50:09 -0500 Subject: [PATCH 040/186] board: Add NXP LS1088ARDB This adds a board file for the NXP LS1088ARDB. This only covers the "primary" JTAG header J55, and not the PCIe header (J91). The only oddity is that the LS1088A and CPLD are muxed by adding/removing a jumper from J48. Unfortunately, it doesn't look like OpenOCD supports this CPLD beyond determining the irlen, so it's not very useful. Those who are interested in experimenting can define CWTAP to access the CPLD, but the default is to access the CPU. Signed-off-by: Sean Anderson Change-Id: Ia07436a534f86bd907aa5fe2a78a326a27855a24 Reviewed-on: https://review.openocd.org/c/openocd/+/6849 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/nxp_rdb-ls1088a.cfg | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tcl/board/nxp_rdb-ls1088a.cfg diff --git a/tcl/board/nxp_rdb-ls1088a.cfg b/tcl/board/nxp_rdb-ls1088a.cfg new file mode 100644 index 000000000..40483f2d6 --- /dev/null +++ b/tcl/board/nxp_rdb-ls1088a.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088ARDB (Reference Design Board) +# This is for the "main" JTAG connector J55 + +transport select jtag +reset_config srst_only + +# To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command +# line. At the time of this writing, programming is unsupported. +if { [info exists CWTAP] } { + source [find cpld/altera-epm240.cfg] +} else { + source [find target/ls1088a.cfg] +} From bc50b8f1b299991851d4ff3eb30f583ed6aa530b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Feb 2022 16:16:31 +0100 Subject: [PATCH 041/186] gdb_server: fix double free Commit 6541233aa78d ("Combine register lists of smp targets.") unconditionally assigns the output pointers of the function smp_reg_list_noread(), even if the function fails and returns error. This causes a double free from the caller, that has assigned NULL to the pointers to simplify the error handling. Use local variables in smp_reg_list_noread() and assign the output pointers only on success. Change-Id: Ic0fd2f26520566cf322f0190780e15637c01cfae Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6852 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome --- src/server/gdb_server.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 95720e561..f8a1aac83 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2272,12 +2272,12 @@ static int smp_reg_list_noread(struct target *target, combined_list_size, REG_CLASS_ALL); unsigned int combined_allocated = 256; - *combined_list = malloc(combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { + struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *)); + if (!local_list) { LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } - *combined_list_size = 0; + unsigned int local_list_size = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { @@ -2286,7 +2286,7 @@ static int smp_reg_list_noread(struct target *target, int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { - free(*combined_list); + free(local_list); return result; } for (int i = 0; i < reg_list_size; i++) { @@ -2296,8 +2296,8 @@ static int smp_reg_list_noread(struct target *target, /* Nested loop makes this O(n^2), but this entire function with * 5 RISC-V targets takes just 2ms on my computer. Fast enough * for me. */ - for (int j = 0; j < *combined_list_size; j++) { - struct reg *b = (*combined_list)[j]; + for (unsigned int j = 0; j < local_list_size; j++) { + struct reg *b = local_list[j]; if (!strcmp(a->name, b->name)) { found = true; if (a->size != b->size) { @@ -2305,7 +2305,7 @@ static int smp_reg_list_noread(struct target *target, "target, but %d bits on another target.", a->name, a->size, b->size); free(reg_list); - free(*combined_list); + free(local_list); return ERROR_FAIL; } break; @@ -2313,16 +2313,16 @@ static int smp_reg_list_noread(struct target *target, } if (!found) { LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); - if (*combined_list_size >= (int) combined_allocated) { + if (local_list_size >= combined_allocated) { combined_allocated *= 2; - *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { + local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); + if (!local_list) { LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } } - (*combined_list)[*combined_list_size] = a; - (*combined_list_size)++; + local_list[local_list_size] = a; + local_list_size++; } } } @@ -2336,12 +2336,12 @@ static int smp_reg_list_noread(struct target *target, int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { - free(*combined_list); + free(local_list); return result; } - for (int i = 0; i < *combined_list_size; i++) { + for (unsigned int i = 0; i < local_list_size; i++) { bool found = false; - struct reg *a = (*combined_list)[i]; + struct reg *a = local_list[i]; for (int j = 0; j < reg_list_size; j++) { struct reg *b = reg_list[j]; if (b->exist && !strcmp(a->name, b->name)) { @@ -2358,6 +2358,8 @@ static int smp_reg_list_noread(struct target *target, free(reg_list); } + *combined_list = local_list; + *combined_list_size = local_list_size; return ERROR_OK; } From 103b1d68db5038edd9e8878c798525715590f4e1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Feb 2022 16:56:42 +0100 Subject: [PATCH 042/186] gdb_server: check target examined while combining reg list Commit 6541233aa78d ("Combine register lists of smp targets.") assumes that all the targets in the SMP cluster are already examined and unconditionally call target_get_gdb_reg_list_noread() that will in turn return error if the target is not examined yet. Skip targets not examined yet. Add an additional check in case the register list cannot be built, e.g. because no target in the SMP cluster is examined. This should never happen, but it's better to play safe. Change-Id: I8609815c3d5144790fb05a870cb0c931540aef8a Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6853 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome --- src/server/gdb_server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f8a1aac83..4dee7e864 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2281,6 +2281,9 @@ static int smp_reg_list_noread(struct target *target, struct target_list *head; foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -2329,8 +2332,17 @@ static int smp_reg_list_noread(struct target *target, free(reg_list); } + if (local_list_size == 0) { + LOG_ERROR("Unable to get register list"); + free(local_list); + return ERROR_FAIL; + } + /* Now warn the user about any registers that weren't found in every target. */ foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, From 8b740af10dd37b08c27588f34942154b817bf6fc Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 28 Feb 2022 10:29:44 +0100 Subject: [PATCH 043/186] flash/stm32l4x: fix maybe-uninitialized compiler error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 we get: error: ‘retval’ may be used uninitialized in this function fixes: 13cd75b6ecfd (flash/nor/stm32xx: fix segfault accessing Cortex-M part number) Change-Id: I897c40c5d2233f50a5385d251ebfa536023e5cf7 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6861 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- src/flash/nor/stm32l4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fa8924ed3..fd0338899 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1632,7 +1632,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { - int retval; + int retval = ERROR_OK; struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ From 87c0cda00fad8ec5c42e0efb3789a2ac8808d5bc Mon Sep 17 00:00:00 2001 From: Erhan Kurubas <43336369+erhankur@users.noreply.github.com> Date: Tue, 1 Mar 2022 19:05:54 +0100 Subject: [PATCH 044/186] riscv: implement maskisr steponly command (#681) * riscv: implement maskisr steponly command Change-Id: I1a3b666d466b064460c3acc307a36485ce165601 Signed-off-by: Erhan Kurubas * riscv: restore triggers and irq mask inside step function Change-Id: I4e1b0665f4f2f75e42a6191c61634bdfa19ae2fb Signed-off-by: Erhan Kurubas * doc: update for riscv set_maskisr command Change-Id: Ia7d3a6df846cfc4568d79558f719e93f038aee9b Signed-off-by: Erhan Kurubas --- doc/openocd.texi | 7 ++ src/target/riscv/riscv.c | 153 +++++++++++++++++++++++++++++++-------- src/target/riscv/riscv.h | 12 +++ 3 files changed, 140 insertions(+), 32 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 9e2f5e8f2..a94e4be29 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10424,6 +10424,13 @@ tunneled DR scan consists of: @end deffn +@deffn {Command} {riscv set_maskisr} [@option{off}|@option{steponly}] +Selects whether interrupts will be disabled when single stepping. The default configuration is @option{off}. +This feature is only useful on hardware that always steps into interrupts and doesn't support dcsr.stepie=0. +Keep in mind, disabling the option does not guarantee that single stepping will go into interrupt handlers. +To make that happen, dcsr.stepie would have to be written to 1 as well. +@end deffn + @deffn {Command} {riscv set_ebreakm} on|off Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 91d1020da..cba4bf92f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1953,26 +1953,11 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, } } - /* Disable Interrupts before attempting to run the algorithm. */ uint64_t current_mstatus; - uint8_t mstatus_bytes[8] = { 0 }; - - LOG_DEBUG("Disabling Interrupts"); - struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - "mstatus", true); - if (!reg_mstatus) { - LOG_ERROR("Couldn't find mstatus!"); + uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; + if (riscv_interrupts_disable(target, irq_disabled_mask, ¤t_mstatus) != ERROR_OK) return ERROR_FAIL; - } - - reg_mstatus->type->get(reg_mstatus); - current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); - uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; - buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus, - ie_mask, 0)); - - reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); @@ -2028,9 +2013,8 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, } /* Restore Interrupts */ - LOG_DEBUG("Restoring Interrupts"); - buf_set_u64(mstatus_bytes, 0, info->xlen, current_mstatus); - reg_mstatus->type->set(reg_mstatus, mstatus_bytes); + if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) + return ERROR_FAIL; /* Restore registers */ uint8_t buf[8] = { 0 }; @@ -2366,7 +2350,7 @@ int riscv_openocd_poll(struct target *target) } int riscv_openocd_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { LOG_DEBUG("stepping rtos hart"); @@ -2377,23 +2361,48 @@ int riscv_openocd_step(struct target *target, int current, if (disable_triggers(target, trigger_state) != ERROR_OK) return ERROR_FAIL; - int out = riscv_step_rtos_hart(target); - if (out != ERROR_OK) { + bool success = true; + uint64_t current_mstatus; + RISCV_INFO(info); + + if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) { + /* Disable Interrupts before stepping. */ + uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; + if (riscv_interrupts_disable(target, irq_disabled_mask, + ¤t_mstatus) != ERROR_OK) { + success = false; + LOG_ERROR("unable to disable interrupts"); + goto _exit; + } + } + + if (riscv_step_rtos_hart(target) != ERROR_OK) { + success = false; LOG_ERROR("unable to step rtos hart"); - return out; } register_cache_invalidate(target->reg_cache); - if (enable_triggers(target, trigger_state) != ERROR_OK) - return ERROR_FAIL; + if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) + if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) { + success = false; + LOG_ERROR("unable to restore interrupts"); + } - target->state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - target->state = TARGET_HALTED; - target->debug_reason = DBG_REASON_SINGLESTEP; - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - return out; +_exit: + if (enable_triggers(target, trigger_state) != ERROR_OK) { + success = false; + LOG_ERROR("unable to enable triggers"); + } + + if (success) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + return success ? ERROR_OK : ERROR_FAIL; } /* Command Handlers */ @@ -2936,6 +2945,31 @@ COMMAND_HANDLER(riscv_use_bscan_tunnel) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_maskisr) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + + static const struct jim_nvp nvp_maskisr_modes[] = { + { .name = "off", .value = RISCV_ISRMASK_OFF }, + { .name = "steponly", .value = RISCV_ISRMASK_STEPONLY }, + { .name = NULL, .value = -1 }, + }; + const struct jim_nvp *n; + + if (CMD_ARGC > 0) { + n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + if (!n->name) + return ERROR_COMMAND_SYNTAX_ERROR; + info->isrmask_mode = n->value; + } else { + n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode); + command_print(CMD, "riscv interrupt mask %s", n->name); + } + + return ERROR_OK; +} + COMMAND_HANDLER(riscv_set_enable_virt2phys) { if (CMD_ARGC != 1) { @@ -3345,6 +3379,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " "1: DATA_REGISTER}" }, + { + .name = "set_maskisr", + .handler = riscv_set_maskisr, + .mode = COMMAND_EXEC, + .help = "mask riscv interrupts", + .usage = "['off'|'steponly']", + }, { .name = "set_enable_virt2phys", .handler = riscv_set_enable_virt2phys, @@ -3489,6 +3530,8 @@ void riscv_info_init(struct target *target, riscv_info_t *r) r->xlen = -1; + r->isrmask_mode = RISCV_ISRMASK_OFF; + r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF; r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; @@ -3520,6 +3563,52 @@ static int riscv_resume_go_all_harts(struct target *target) return ERROR_OK; } +int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t *old_mstatus) +{ + LOG_DEBUG("Disabling Interrupts"); + struct reg *reg_mstatus = register_get_by_name(target->reg_cache, + "mstatus", true); + if (!reg_mstatus) { + LOG_ERROR("Couldn't find mstatus!"); + return ERROR_FAIL; + } + + int retval = reg_mstatus->type->get(reg_mstatus); + if (retval != ERROR_OK) + return retval; + + RISCV_INFO(info); + uint8_t mstatus_bytes[8] = { 0 }; + uint64_t current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); + buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus, + irq_mask, 0)); + + retval = reg_mstatus->type->set(reg_mstatus, mstatus_bytes); + if (retval != ERROR_OK) + return retval; + + if (old_mstatus) + *old_mstatus = current_mstatus; + + return ERROR_OK; +} + +int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) +{ + LOG_DEBUG("Restore Interrupts"); + struct reg *reg_mstatus = register_get_by_name(target->reg_cache, + "mstatus", true); + if (!reg_mstatus) { + LOG_ERROR("Couldn't find mstatus!"); + return ERROR_FAIL; + } + + RISCV_INFO(info); + uint8_t mstatus_bytes[8]; + buf_set_u64(mstatus_bytes, 0, info->xlen, old_mstatus); + return reg_mstatus->type->set(reg_mstatus, mstatus_bytes); +} + int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index f1104e35b..5dc2152c6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -56,6 +56,13 @@ enum riscv_halt_reason { RISCV_HALT_ERROR }; +enum riscv_isrmasking_mode { + /* RISCV_ISRMASK_AUTO, */ /* not supported yet */ + RISCV_ISRMASK_OFF, + /* RISCV_ISRMASK_ON, */ /* not supported yet */ + RISCV_ISRMASK_STEPONLY, +}; + typedef struct { struct target *target; unsigned custom_number; @@ -135,6 +142,8 @@ typedef struct { /* This target was selected using hasel. */ bool selected; + enum riscv_isrmasking_mode isrmask_mode; + /* Helper functions that target the various RISC-V debug spec * implementations. */ int (*get_register)(struct target *target, riscv_reg_t *value, int regid); @@ -403,4 +412,7 @@ void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *fie int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); +int riscv_interrupts_disable(struct target *target, uint64_t ie_mask, uint64_t *old_mstatus); +int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus); + #endif From 9e097d0fc423f1c6a1a198e660224bb951a5c2bb Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 3 Mar 2022 10:03:55 -0800 Subject: [PATCH 045/186] From upstream (#684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * flash/nor/atsame5: add LAN9255 devices Support Microchip LAN9255 devices with embedded SAME53J MCU. Signed-off-by: Hans-Erik Floryd Change-Id: Ia811c593bf7cf73e588d32873c68eb67c6fafad7 Reviewed-on: https://review.openocd.org/c/openocd/+/6811 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek * tcl/board: Add EVB-LAN9255 config Config for EVB-LAN9255, tested using Atmel-ICE debugger on J10 connector. Signed-off-by: Hans-Erik Floryd Change-Id: I8bcf779e9363499a98aa0b7d10819c53da6a19e7 Reviewed-on: https://review.openocd.org/c/openocd/+/6812 Tested-by: jenkins Reviewed-by: Antonio Borneo * aarch64: support for aarch32 ARM_MODE_UND Fix: unrecognized psr mode: 0x1b cannot read system control register in this mode: (UNRECOGNIZED : 0x1b) Change-Id: I4dc3e72f90d57e52c0fe63cb59a7529a398757b3 Signed-off-by: Julien Massot Change-Id: Ifa5d21ae97492fde9e8c79ee7d99d8a2a871b1b5 Reviewed-on: https://review.openocd.org/c/openocd/+/6808 Tested-by: jenkins Reviewed-by: Antonio Borneo * Combine register lists of smp targets. This is helpful when you want to pretend to gdb that your heterogeneous multicore system is homogeneous, because gdb cannot handle heterogeneous systems. This won't always works, but works fine if e.g. one of the cores has an FPU while the other does not. (Specifically, HiFive Unleashed has 1 core with no FPU, plus 4 cores with an FPU.) Signed-off-by: Tim Newsome Change-Id: I05ff4c28646778fbc00327bc510be064bfe6c9f0 Reviewed-on: https://review.openocd.org/c/openocd/+/6362 Tested-by: jenkins Reviewed-by: Antonio Borneo * semihosting: use open mode flags from GDB, not from sys/stat.h Values defined in sys/stat.h are not guaranteed to match the constants defined by the GDB remote protocol, which are defined in https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags. On my local system (Manjaro 21.2.1 x86_64), for example, O_TRUNC is defined as 0x40, whereas GDB requires it to be 0x400, causing all "w" file open modes to misbehave. This patch has been tested with STM32F446. Change-Id: Ifb2c740fd689e71d6f1a4bde1edaecd76fdca910 Signed-off-by: Pavel Kirienko Reviewed-on: https://review.openocd.org/c/openocd/+/6804 Tested-by: jenkins Reviewed-by: Antonio Borneo * semihosting: User defined operation, Tcl command exec on host Enabling a portion (0x100 - 0x107) of the user defined semihosting operation number range (0x100 - 0x1FF) to be processed with the help of the existing target event mechanism, to implement a general-purpose Tcl interface for the target available on the host, via semihosting interface. Example usage: - The user configures a Tcl command as a callback for one of the newly defined events (semihosting-user-cmd-0x10X) in the configuration file. - The target can make a semihosting call with , passing optional parameters for the call. If there is no callback registered to the user defined operation number, nothing happens. Example usage: Configure RTT automatically with the exact, linked control block location from target. Signed-off-by: Zoltán Dudás Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247 Reviewed-on: https://review.openocd.org/c/openocd/+/6748 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: Antonio Borneo * target/smp: use a struct list_head to hold the smp targets Instead of reinventing a simply linked list, reuse the list helper for the list of targets in a smp cluster. Using the existing helper, that implements a double linked list, makes trivial going through the list in reverse order. Change-Id: Ib36ad2955f15cd2a601b0b9e36ca6d948b12d00f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6783 Tested-by: jenkins * helper/list: add list_for_each_entry_direction() Use a bool flag to specify if the list should be forward or backward iterated. Change-Id: Ied19d049f46cdcb7f50137d459cc7c02014526bc Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6784 Tested-by: jenkins * target/riscv: revive 'riscv resume_order' This functionality was lost in [1], which was merged as commit 615709d14049 ("Upstream a whole host of RISC-V changes."). Now it works as expected again. Add convenience macro foreach_smp_target_direction(). Link: [1] https://github.com/riscv/riscv-openocd/pull/567 Change-Id: I1545fa6b45b8a07e27c8ff9dcdcfa2fc4f950cd1 Signed-off-by: Tim Newsome Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6785 Tested-by: jenkins * doxygen: fix some function prototype description Change-Id: I49311a643ea73143839d2f6bde976cfd76f8c67f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6830 Tested-by: jenkins * Cadence virtual debug interface (vdebug) integration Change-Id: I1bc105b3addc3f34161c2356c482ff3011e3f2cc Signed-off-by: Jacek Wuwer Reviewed-on: https://review.openocd.org/c/openocd/+/6097 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: zapb Reviewed-by: Antonio Borneo * gdb_server: Include thread name as XML attribute Explicitly providing a thread name in the "thread" element produces better thread visualizations in downstream tools like IDEs. Signed-off-by: Ben McMorran Change-Id: I102c14ddb8b87757fa474de8e3a3f6a1cfe10d98 Reviewed-on: https://review.openocd.org/c/openocd/+/6828 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo * Fix small memory leak. See https://github.com/riscv/riscv-openocd/pull/672 Change-Id: Ia11ab9bcf860f770ea64ad867102c74b898f6b66 Signed-off-by: Tim Newsome Reviewed-on: https://review.openocd.org/c/openocd/+/6831 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo * server: remove remaining crust from dropped eCos code Commit 39650e2273bc ("ecosboard: delete bit-rotted eCos code") has removed eCos code but has left some empty function that was used during non-eCos build to replace eCos mutex. Drop the functions and the file that contain them. Change-Id: I31bc0237ea699c11bd70921660f960ee406ffa80 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6835 Tested-by: jenkins Reviewed-by: Tomas Vanek * rtos: threadx: Add hla_target support for ThreadX Tested with an AZ3166 dev board (which uses the STM32F412ZGT6) running the Azure RTOS ThreadX demonstration system. Signed-off-by: Ben McMorran Change-Id: I44c8f7701d9f1aaa872274166321cd7d34fb1855 Reviewed-on: https://review.openocd.org/c/openocd/+/6829 Tested-by: jenkins Reviewed-by: Antonio Borneo * .gitmodules: switch away from repo.or.cz The host repo.or.cz is often offline, creating issues for cloning and building OpenOCD from scratch. Already 'jimtcl' developer has dropped repo.or.cz, triggering the OpenOCD commit 861e75f54efb ("jimtcl: switch to github"). Change also the link of the remaining submodules 'git2cl' and 'libjaylink' to their respective main repository. Change-Id: Ib513237427635359ce36a480a8f2060e2fb12ba4 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6834 Tested-by: jenkins Reviewed-by: zapb * flash/nor/stm32f2x: Fix erase of bank 2 sectors This commit corrects the erase function for stm32f2x when dealing with sectors in bank 2, for STM32F42x/43x devices with 1MB flash. On STM32F42x/43x with 1MB flash in dual bank configuration, the sector numbering is not consecutive. The last sector in bank 1 is number 7, and the first sector in bank 2 is number 12. The sector indices used by openocd, however, _are_ consecutive (0 to 15 in this case). The arguments "first" and "last" to stm32x_erase() are of this type, and so the logic surrounding sector numbers needed to be corrected. Since the two banks in dual bank mode have the same number of sectors, a sector index in bank 2 is larger than or equal to half the total number of sectors. Change-Id: I15260f8a86d9002769a1ae1c40ebdf62142dae18 Signed-off-by: Simon Johansson Reviewed-on: https://review.openocd.org/c/openocd/+/6810 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI * target/cortex_m: fix target_to_cm() helper The third parameter of container_of() should point to the same member as target->arch_info points to, struct arm. It worked just because struct arm is the first member in struct armv7m_common. If you move arm member from the first place, OpenOCD fails heavily. Change-Id: I0c0a5221490945563e17a0a34d99a603f1d6c2ff Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6749 Tested-by: jenkins Reviewed-by: Antonio Borneo * target/armv7m,cortex_m: introduce checked arch_info cast routines target_to_armv7m() and target_to_cm() do not match the magic number so they are not suitable for use outside of target driver code. Add checked versions of pointer getters. Match the magic number to ensure the returned value points to struct of the correct type. Change-Id: If90ef7e969ef04f0f2103e0da29dcbe8e1ac1c0d Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6750 Tested-by: jenkins Reviewed-by: Antonio Borneo * target/cortex_m: add Cortex-M part number getter The getter checks the magic numbers in arch_info to detect eventual type mismatch. Change-Id: I61134b05310a97ae9831517d0516c7b4240d35a5 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6751 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI * flash/nor/stm32xx: fix segfault accessing Cortex-M part number Some of STM32 flash drivers read Cortex-M part number from cortex_m->core_info. In corner cases the core_info pointer was observed uninitialised even if target_was_examined() returned true. See also [1] Use the new and safe helper to get Cortex-M part number. While on it switch also target_to_cm()/target_to_armv7m() to the safe versions. This prevents a crash when the flash bank is misconfigured with non-Cortex-M target. Add missing checks for target_was_examined() to flash probes. [1] 6545: fix crash in case cortex_m->core_info is not set https://review.openocd.org/c/openocd/+/6545 Change-Id: If2471af74ebfe22f14442f48ae109b2e1bb5fa3b Signed-off-by: Tomas Vanek Fixes: f5898bd93ff8 (flash/stm32fxx.c: do not read CPUID as this info is stored in cortex_m_common) Reviewed-on: https://review.openocd.org/c/openocd/+/6752 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI * cpld: altera-epm240: Add additional IDCODEs This adds some additional IDCODEs from the datasheet. It also adds support for customizing the tap name. Signed-off-by: Sean Anderson Change-Id: I7cda10b92c229b61836c12cd9ca410de358ede2e Reviewed-on: https://review.openocd.org/c/openocd/+/6846 Tested-by: jenkins Reviewed-by: Antonio Borneo * cpld: altera-epm240: Increase adapter speed According to the datasheet, the minimum clock period with Vccio1 = 1.5V (the lowest voltage supported) is 143ns, or around 6MHz. Set the default adapter speed to 5 MHz. Signed-off-by: Sean Anderson Change-Id: I21cad33fa7f1e25e81f43b5d2214d1fa4ec924de Reviewed-on: https://review.openocd.org/c/openocd/+/6847 Tested-by: jenkins Reviewed-by: Antonio Borneo * target: Add support for ls1088a The LS1088A is an octo-core aarch64 processor from NXP in the layerscape family. The JTAG is undocumented, but I was able to figure things out from the output of `dap info`. This is the first in-tree example of using the hwthread rtos (as far as I know), so hopefully it can serve as an example to other developers. There are some ETMs, but I was unable to try them out because I got 'invalid command name "etm"' when trying to test things out. Signed-off-by: Sean Anderson Change-Id: I9b0791d27d8c41170a413a8d86431107a85feba2 Reviewed-on: https://review.openocd.org/c/openocd/+/6848 Tested-by: jenkins Reviewed-by: Antonio Borneo * target: ls1088a: Add service processor Normally the service processor is not necessary for debugging. However, if you are using the hard-coded RCW or your boot source is otherwise corrupt, then the general purpose processors will never be released from hold-off. This will cause GDB to become confused if it tries to attach, since they will appear to be running arm32 processors. To deal with this, we can release the CPUs manually with the BRRL register. This register cannot be written to from the axi target, so we need to do it from the service processor target. This involves halting the service processor, modifying the register, and then resuming it again. We try and determine what state the service processor was in to avoid resuming it if it was already halted. The reset vector for the general purpose processors is determined by the boot logation pointer registers in the device configuration unit. Normally these are set using pre-boot initialization commands, but if they are not set then they default to 0. This will cause the CPU to almost immediately hit an illegal instruction. This is fine because we will almost certainly want to attach to the processor and load a program anyway. I considered adding this as an event handler for either gdb-attach or reset-init. However, this command shouldn't be necessary most of the time, and so I don't think we should run it automatically. Signed-off-by: Sean Anderson Change-Id: I1b725292d8a11274d03af5313dc83678e10e944c Reviewed-on: https://review.openocd.org/c/openocd/+/6850 Tested-by: jenkins Reviewed-by: Antonio Borneo * board: Add NXP LS1088ARDB This adds a board file for the NXP LS1088ARDB. This only covers the "primary" JTAG header J55, and not the PCIe header (J91). The only oddity is that the LS1088A and CPLD are muxed by adding/removing a jumper from J48. Unfortunately, it doesn't look like OpenOCD supports this CPLD beyond determining the irlen, so it's not very useful. Those who are interested in experimenting can define CWTAP to access the CPLD, but the default is to access the CPU. Signed-off-by: Sean Anderson Change-Id: Ia07436a534f86bd907aa5fe2a78a326a27855a24 Reviewed-on: https://review.openocd.org/c/openocd/+/6849 Tested-by: jenkins Reviewed-by: Antonio Borneo * gdb_server: fix double free Commit 6541233aa78d ("Combine register lists of smp targets.") unconditionally assigns the output pointers of the function smp_reg_list_noread(), even if the function fails and returns error. This causes a double free from the caller, that has assigned NULL to the pointers to simplify the error handling. Use local variables in smp_reg_list_noread() and assign the output pointers only on success. Change-Id: Ic0fd2f26520566cf322f0190780e15637c01cfae Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6852 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome * gdb_server: check target examined while combining reg list Commit 6541233aa78d ("Combine register lists of smp targets.") assumes that all the targets in the SMP cluster are already examined and unconditionally call target_get_gdb_reg_list_noread() that will in turn return error if the target is not examined yet. Skip targets not examined yet. Add an additional check in case the register list cannot be built, e.g. because no target in the SMP cluster is examined. This should never happen, but it's better to play safe. Change-Id: I8609815c3d5144790fb05a870cb0c931540aef8a Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6853 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome * flash/stm32l4x: fix maybe-uninitialized compiler error using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 we get: error: ‘retval’ may be used uninitialized in this function fixes: 13cd75b6ecfd (flash/nor/stm32xx: fix segfault accessing Cortex-M part number) Change-Id: I897c40c5d2233f50a5385d251ebfa536023e5cf7 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6861 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo * Fix build. Change-Id: Ia60246246dd859d75659a43d1c59588dbb274d46 Signed-off-by: Tim Newsome Co-authored-by: Hans-Erik Floryd Co-authored-by: Julien Massot Co-authored-by: Pavel Kirienko Co-authored-by: Zoltán Dudás Co-authored-by: Antonio Borneo Co-authored-by: Jacek Wuwer Co-authored-by: Ben McMorran Co-authored-by: Simon Johansson Co-authored-by: Tomas Vanek Co-authored-by: Sean Anderson Co-authored-by: Tarek BOCHKATI --- configure.ac | 15 +- doc/openocd.texi | 68 ++ src/flash/nor/atsame5.c | 3 + src/flash/nor/stm32f1x.c | 10 +- src/flash/nor/stm32f2x.c | 13 +- src/flash/nor/stm32h7x.c | 9 +- src/flash/nor/stm32l4x.c | 29 +- src/helper/list.h | 14 + src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/jlink.c | 2 - src/jtag/drivers/ulink.c | 2 - src/jtag/drivers/vdebug.c | 1076 ++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + src/jtag/jtag.h | 3 +- src/rtos/ThreadX.c | 12 + src/rtos/hwthread.c | 8 +- src/rtos/linux.c | 16 +- src/rtos/rtos.c | 2 +- src/server/Makefile.am | 1 - src/server/gdb_server.c | 93 ++- src/server/server.c | 2 - src/server/server.h | 9 - src/server/server_stubs.c | 30 - src/target/aarch64.c | 18 +- src/target/arm_semihosting.c | 7 +- src/target/armv7a.c | 9 +- src/target/armv7a_cache.c | 9 +- src/target/armv7a_cache_l2x.c | 9 +- src/target/armv7m.h | 37 +- src/target/armv8.c | 4 + src/target/armv8_cache.c | 8 +- src/target/breakpoints.c | 88 +-- src/target/cortex_a.c | 26 +- src/target/cortex_m.h | 59 +- src/target/mips_m4k.c | 22 +- src/target/riscv/riscv-013.c | 2 +- src/target/riscv/riscv.c | 62 +- src/target/riscv/riscv_semihosting.c | 4 +- src/target/semihosting_common.c | 144 +++- src/target/semihosting_common.h | 6 + src/target/smp.c | 10 +- src/target/smp.h | 6 +- src/target/target.c | 54 +- src/target/target.h | 15 +- tcl/board/evb-lan9255.cfg | 11 + tcl/board/nxp_rdb-ls1088a.cfg | 14 + tcl/board/vd_a53x2_jtag.cfg | 31 + tcl/board/vd_m4_jtag.cfg | 30 + tcl/board/vd_pulpissimo_jtag.cfg | 32 + tcl/board/vd_swerv_jtag.cfg | 32 + tcl/cpld/altera-epm240.cfg | 19 +- tcl/interface/vdebug.cfg | 33 + tcl/target/ls1088a.cfg | 74 ++ tcl/target/vd_aarch64.cfg | 37 + tcl/target/vd_cortex_m.cfg | 12 + tcl/target/vd_riscv.cfg | 18 + 56 files changed, 2046 insertions(+), 322 deletions(-) create mode 100644 src/jtag/drivers/vdebug.c delete mode 100644 src/server/server_stubs.c create mode 100644 tcl/board/evb-lan9255.cfg create mode 100644 tcl/board/nxp_rdb-ls1088a.cfg create mode 100644 tcl/board/vd_a53x2_jtag.cfg create mode 100644 tcl/board/vd_m4_jtag.cfg create mode 100644 tcl/board/vd_pulpissimo_jtag.cfg create mode 100644 tcl/board/vd_swerv_jtag.cfg create mode 100644 tcl/interface/vdebug.cfg create mode 100644 tcl/target/ls1088a.cfg create mode 100644 tcl/target/vd_aarch64.cfg create mode 100644 tcl/target/vd_cortex_m.cfg create mode 100644 tcl/target/vd_riscv.cfg diff --git a/configure.ac b/configure.ac index f969680f5..f70dc2fb5 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,10 @@ AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) +AC_ARG_ENABLE([vdebug], + AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), + [build_vdebug=$enableval], [build_vdebug=no]) + AC_ARG_ENABLE([jtag_dpi], AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) @@ -514,6 +518,12 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_vdebug" = "xyes"], [ + AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) +], [ + AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) +]) + AS_IF([test "x$build_jtag_dpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) ], [ @@ -689,8 +699,9 @@ AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) -AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o "x$build_jtag_vpi" = "xyes"]) -AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dpi" = "xyes"]) +AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) +AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) diff --git a/doc/openocd.texi b/doc/openocd.texi index a94e4be29..f826a0b7f 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -588,6 +588,12 @@ produced, PDF schematics are easily found and it is easy to make. @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} +@item @b{vdebug} +@* A driver for Cadence virtual Debug Interface to emulated or simulated targets. +It implements a client connecting to the vdebug server, which in turn communicates +with the emulated or simulated RTL model through a transactor. The current version +supports only JTAG as a transport, but other virtual transports, like DAP are planned. + @item @b{jtag_dpi} @* A JTAG driver acting as a client for the SystemVerilog Direct Programming Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG @@ -3345,6 +3351,41 @@ This value is only used with the standard variant. @end deffn +@deffn {Interface Driver} {vdebug} +Cadence Virtual Debug Interface driver. + +@deffn {Config Command} {vdebug server} host:port +Specifies the host and TCP port number where the vdebug server runs. +@end deffn + +@deffn {Config Command} {vdebug batching} value +Specifies the batching method for the vdebug request. Possible values are +0 for no batching +1 or wr to batch write transactions together (default) +2 or rw to batch both read and write transactions +@end deffn + +@deffn {Config Command} {vdebug polling} min max +Takes two values, representing the polling interval in ms. Lower values mean faster +debugger responsiveness, but lower emulation performance. The minimum should be +around 10, maximum should not exceed 1000, which is the default gdb and keepalive +timeout value. +@end deffn + +@deffn {Config Command} {vdebug bfm_path} path clk_period +Specifies the hierarchical path and input clk period of the vdebug BFM in the design. +The hierarchical path uses Verilog notation top.inst.inst +The clock period must include the unit, for instance 40ns. +@end deffn + +@deffn {Config Command} {vdebug mem_path} path base size +Specifies the hierarchical path to the design memory instance for backdoor access. +Up to 4 memories can be specified. The hierarchical path uses Verilog notation. +The base specifies start address in the design address space, size its size in bytes. +Both values can use hexadecimal notation with prefix 0x. +@end deffn +@end deffn + @deffn {Interface Driver} {jtag_dpi} SystemVerilog Direct Programming Interface (DPI) compatible driver for JTAG devices in emulation. The driver acts as a client for the SystemVerilog @@ -5185,6 +5226,22 @@ when reset disables PLLs needed to use a fast clock. @* After single-step has completed @item @b{trace-config} @* After target hardware trace configuration was changed +@item @b{semihosting-user-cmd-0x100} +@* The target made a semihosting call with user-defined operation number 0x100 +@item @b{semihosting-user-cmd-0x101} +@* The target made a semihosting call with user-defined operation number 0x101 +@item @b{semihosting-user-cmd-0x102} +@* The target made a semihosting call with user-defined operation number 0x102 +@item @b{semihosting-user-cmd-0x103} +@* The target made a semihosting call with user-defined operation number 0x103 +@item @b{semihosting-user-cmd-0x104} +@* The target made a semihosting call with user-defined operation number 0x104 +@item @b{semihosting-user-cmd-0x105} +@* The target made a semihosting call with user-defined operation number 0x105 +@item @b{semihosting-user-cmd-0x106} +@* The target made a semihosting call with user-defined operation number 0x106 +@item @b{semihosting-user-cmd-0x107} +@* The target made a semihosting call with user-defined operation number 0x107 @end itemize @quotation Note @@ -9241,6 +9298,17 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn +@deffn {Command} {arm semihosting_read_user_param} +@cindex ARM semihosting +Read parameter of the semihosting call from the target. Usable in +semihosting-user-cmd-0x10* event handlers, returning a string. + +When the target makes semihosting call with operation number from range 0x100- +0x107, an optional string parameter can be passed to the server. This parameter +is valid during the run of the event handlers and is accessible with this +command. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index 9ab0e8113..fbf0fb2ed 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -146,6 +146,9 @@ static const struct samd_part same53_parts[] = { { 0x04, "SAME53J20A", 1024, 256 }, { 0x05, "SAME53J19A", 512, 192 }, { 0x06, "SAME53J18A", 256, 128 }, + { 0x55, "LAN9255/ZMX020", 1024, 256 }, + { 0x56, "LAN9255/ZMX019", 512, 192 }, + { 0x57, "LAN9255/ZMX018", 256, 128 }, }; /* Known SAME54 parts. */ diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 90cee6412..29a3b7e06 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -622,15 +622,14 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t device_id_register = 0; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ device_id_register = 0x40015800; break; @@ -659,15 +658,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t flash_size_reg; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ flash_size_reg = 0x1FFFF7CC; break; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index d3e7d709c..58edca7e1 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -636,8 +636,8 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) { unsigned int snb; - if (stm32x_info->has_large_mem && i >= 12) - snb = (i - 12) | 0x10; + if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2)) + snb = (i - (bank->num_sectors / 2)) | 0x10; else snb = i; @@ -966,14 +966,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) * Only effects Rev A silicon */ struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; - if ((*device_id & 0xfff) == 0x411 && cortex_m->core_info->partno == CORTEX_M4_PARTNO) { + if ((*device_id & 0xfff) == 0x411 + && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); @@ -1011,6 +1011,11 @@ static int stm32x_probe(struct flash_bank *bank) bank->num_prot_blocks = 0; bank->prot_blocks = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + /* if explicitly called out as OTP bank, short circuit probe */ if (stm32x_is_otp(bank)) { if (stm32x_otp_is_f7(bank)) { diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index d3f17b2b1..6d3149f94 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -759,7 +759,6 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; @@ -767,6 +766,11 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->probed = false; stm32x_info->part_info = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); if (retval != ERROR_OK) return retval; @@ -800,7 +804,8 @@ static int stm32x_probe(struct flash_bank *bank) /* get flash size from target */ /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; - if (device_id == DEVID_STM32H74_H75XX && cortex_m->core_info->partno == CORTEX_M4_PARTNO) + if (device_id == DEVID_STM32H74_H75XX + && cortex_m_get_partno_safe(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 e5100a015..fd0338899 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1632,13 +1632,14 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { - int retval; + int retval = ERROR_OK; + struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { - retval = target_read_u32(bank->target, dbgmcu_idcode[i], id); + retval = target_read_u32(target, dbgmcu_idcode[i], id); if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) return ERROR_OK; } @@ -1647,12 +1648,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1, * to solve this read the UID64 (IEEE 64-bit unique device ID register) */ - struct cortex_m_common *cortex_m = target_to_cm(bank->target); + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } /* 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->core_info->partno == CORTEX_M0P_PARTNO && - cortex_m->armv7m.debug_ap && cortex_m->armv7m.debug_ap->ap_num == 1) { + if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && + armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; /* UID64 is contains @@ -1662,7 +1667,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx */ - retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids); + retval = target_read_u32(target, UID64_IDS, &uid64_ids); if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) { /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ *id = DEVID_STM32WLE_WL5XX; @@ -1700,11 +1705,21 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank) static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct armv7m_common *armv7m = target_to_armv7m(target); struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; uint16_t flash_size_kb = 0xffff; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } + stm32l4_info->probed = false; /* read stm32 device id registers */ diff --git a/src/helper/list.h b/src/helper/list.h index a7cd4ad37..552a3202a 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -656,6 +656,20 @@ static inline void list_splice_tail_init(struct list_head *list, !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) +/** + * list_for_each_entry_direction - iterate forward/backward over list of given type + * @param forward the iterate direction, true for forward, false for backward. + * @param pos the type * to use as a loop cursor. + * @param head the head for your list. + * @param member the name of the list_head within the struct. + */ +#define list_for_each_entry_direction(forward, pos, head, member) \ + for (pos = forward ? list_first_entry(head, typeof(*pos), member) \ + : list_last_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = forward ? list_next_entry(pos, member) \ + : list_prev_entry(pos, member)) + /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @param pos the type * to use as a start point diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index c2161523d..887f99bcd 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -75,6 +75,9 @@ endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif +if VDEBUG +DRIVERFILES += %D%/vdebug.c +endif if JTAG_DPI DRIVERFILES += %D%/jtag_dpi.c endif diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index fdf4ae778..5c218742b 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -114,8 +114,6 @@ static int jlink_flush(void); * @param in A pointer to store TDO data to, if NULL the data will be discarded. * @param in_offset A bit offset for TDO data. * @param length Amount of bits to transfer out and in. - * - * @retval This function doesn't return any value. */ static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 3ae5cac62..20a036a78 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -604,8 +604,6 @@ static int ulink_get_queue_size(struct ulink *device, * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL */ static void ulink_clear_queue(struct ulink *device) { diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c new file mode 100644 index 000000000..a81740cb1 --- /dev/null +++ b/src/jtag/drivers/vdebug.c @@ -0,0 +1,1076 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/*---------------------------------------------------------------------------- + * Copyright 2020-2021 Cadence Design Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *---------------------------------------------------------------------------- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------- +*/ + +/*! + * @file + * + * @brief the virtual debug interface provides a connection between a sw debugger + * and the simulated, emulated core over a soft connection, implemented by DPI + * The vdebug debug driver currently supports JTAG transport + * TODO: implement support and test big endian platforms + * +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#ifdef HAVE_UNISTD_H +#include /* close */ +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#endif +#include +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include + +#include "jtag/interface.h" +#include "jtag/commands.h" +#include "transport/transport.h" +#include "helper/time_support.h" +#include "helper/replacements.h" +#include "helper/log.h" + +#define VD_VERSION 43 +#define VD_BUFFER_LEN 4024 +#define VD_CHEADER_LEN 24 +#define VD_SHEADER_LEN 16 + +#define VD_MAX_MEMORIES 4 +#define VD_POLL_INTERVAL 500 +#define VD_SCALE_PSTOMS 1000000000 + +/** + * @brief List of transactor types + */ +enum { + VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */ + VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */ + VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */ + VD_BFM_APB = 0x0004, /* transactor AMBA APB */ + VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */ + VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */ + VD_BFM_SWD = 0x0007, /* transactor serial SWD */ +}; + +/** + * @brief List of signals that can be read or written by the debugger + */ +enum { + VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */ + VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */ + VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */ + VD_SIG_RESET = 0x0008, /* DUT reset; rst */ + VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */ + VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */ + VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */ + VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */ + VD_SIG_BUF = 0x1000, /* memory buffer; mem */ +}; + +/** + * @brief List of errors + */ +enum { + VD_ERR_NONE = 0x0000, /* no error */ + VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */ + VD_ERR_USAGE = 0x0101, /* incorrect usage */ + VD_ERR_PARAM = 0x0102, /* incorrect parameter */ + VD_ERR_CONFIG = 0x0107, /* incorrect configuration */ + VD_ERR_NO_MEMORY = 0x0104, /* out of memory */ + VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */ + VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */ + VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */ + VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */ + VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */ + VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */ + VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */ + VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */ + VD_ERR_LOCKED = 0x0202, /* device locked */ + VD_ERR_NOT_RUN = 0x0204, /* transactor not running */ + VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */ + VD_ERR_LICENSE = 0x0206, /* cannot check out the license */ + VD_ERR_VERSION = 0x0207, /* transactor version mismatch */ + VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */ + VD_ERR_NO_POWER = 0x0302, /* power out error */ + VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */ + VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */ + VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */ + VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */ +}; + +enum { + VD_CMD_OPEN = 0x01, + VD_CMD_CLOSE = 0x02, + VD_CMD_CONNECT = 0x04, + VD_CMD_DISCONNECT = 0x05, + VD_CMD_WAIT = 0x09, + VD_CMD_SIGSET = 0x0a, + VD_CMD_SIGGET = 0x0b, + VD_CMD_JTAGCLOCK = 0x0f, + VD_CMD_JTAGSHTAP = 0x1a, + VD_CMD_MEMOPEN = 0x21, + VD_CMD_MEMCLOSE = 0x22, + VD_CMD_MEMWRITE = 0x23, +}; + +enum { + VD_BATCH_NO = 0, + VD_BATCH_WO = 1, + VD_BATCH_WR = 2, +}; + +struct vd_shm { + struct { /* VD_CHEADER_LEN written by client */ + uint8_t cmd; /* 000; command */ + uint8_t type; /* 001; interface type */ + uint16_t waddr; /* 002; write pointer */ + uint16_t wbytes; /* 004; data bytes */ + uint16_t rbytes; /* 006; data bytes to read */ + uint16_t wwords; /* 008; data words */ + uint16_t rwords; /* 00a; data words to read */ + uint32_t rwdata; /* 00c; read/write data */ + uint32_t offset; /* 010; address offset */ + uint16_t offseth; /* 014; address offset 47:32 */ + uint16_t wid; /* 016; request id*/ + }; + union { /* 018; */ + uint8_t wd8[VD_BUFFER_LEN]; + uint16_t wd16[VD_BUFFER_LEN / 2]; + uint32_t wd32[VD_BUFFER_LEN / 4]; + uint64_t wd64[VD_BUFFER_LEN / 8]; + }; + struct { /* VD_SHEADER_LEN written by server */ + uint16_t rid; /* fd0: request id read */ + uint16_t awords; /* fd2: actual data words read back */ + int32_t status; /* fd4; */ + uint64_t duttime; /* fd8; */ + }; + union { /* fe0: */ + uint8_t rd8[VD_BUFFER_LEN]; + uint16_t rd16[VD_BUFFER_LEN / 2]; + uint32_t rd32[VD_BUFFER_LEN / 4]; + uint64_t rd64[VD_BUFFER_LEN / 8]; + }; + uint32_t state; /* 1f98; connection state */ + uint32_t count; /* 1f9c; */ + uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */ +}; + +struct vd_client { + uint8_t trans_batch; + bool trans_first; + bool trans_last; + uint8_t mem_ndx; + uint8_t buf_width; + uint8_t addr_bits; + uint8_t bfm_type; + uint16_t sig_read; + uint16_t sig_write; + uint32_t bfm_period; + uint32_t mem_base[VD_MAX_MEMORIES]; + uint32_t mem_size[VD_MAX_MEMORIES]; + uint32_t mem_width[VD_MAX_MEMORIES]; + uint32_t mem_depth[VD_MAX_MEMORIES]; + uint16_t server_port; + uint32_t poll_cycles; + uint32_t poll_min; + uint32_t poll_max; + uint32_t targ_time; + int hsocket; + char server_name[32]; + char bfm_path[128]; + char mem_path[VD_MAX_MEMORIES][128]; + uint8_t *tdo; +}; + +struct vd_jtag_hdr { + uint64_t tlen:24; + uint64_t post:3; + uint64_t pre:3; + uint64_t cmd:2; + uint64_t wlen:16; + uint64_t rlen:16; +}; + +static struct vd_shm *pbuf; +static struct vd_client vdc; + +static int vdebug_socket_error(void) +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static int vdebug_socket_open(char *server_addr, uint32_t port) +{ + int hsock; + int rc = 0; + uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */ + struct addrinfo *ainfo = NULL; + struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; + +#ifdef _WIN32 + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock == INVALID_SOCKET) + rc = vdebug_socket_error(); +#else + uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */ + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock < 0) + rc = errno; + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) + rc = errno; +#endif + else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + + if (rc) { + LOG_ERROR("socket_open: cannot set socket option, error %d", rc); + } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) { + LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); + rc = VD_ERR_SOC_ADDR; + } else { + ((struct sockaddr_in *)(ainfo->ai_addr))->sin_port = htons(port); + if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) { + LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error()); + rc = VD_ERR_SOC_CONN; + } + } + + if (rc) { + close_socket(hsock); + hsock = 0; + } + + if (ainfo) + freeaddrinfo(ainfo); + + return hsock; +} + +static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) +{ + int rc; + int dreceived = 0; + int offset = (uint8_t *)&pmem->rid - &pmem->cmd; + int to_receive = VD_SHEADER_LEN + pmem->rbytes; + char *pb = (char *)pmem; + + do { + rc = recv(hsock, pb + offset, to_receive, 0); + if (rc <= 0) { + LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0); + return rc; + } + to_receive -= rc; + offset += rc; + LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive); + dreceived += rc; + } while (to_receive); + + return dreceived; +} + +static int vdebug_socket_send(int hsock, struct vd_shm *pmem) +{ + int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0); + if (rc <= 0) + LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error()); + else + LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc); + + return rc; +} + +static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) +{ + if (!hsock) + return VD_ERR_SOC_OPEN; + int st = vdebug_socket_send(hsock, pmem); + if (st <= 0) + return VD_ERR_SOC_SEND; + + int rd = vdebug_socket_receive(hsock, pmem); + if (rd <= 0) + return VD_ERR_SOC_RECV; + + int rc = pmem->status; + LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d", + pmem->cmd, st, rd, rc); + + return rc; +} + +int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) +{ + uint8_t num_pre, num_post, tdi, tms; + unsigned int num, anum, bytes, hwords, words; + unsigned int req, waddr, rwords; + int64_t ts, te; + uint8_t *tdo; + int rc; + struct vd_jtag_hdr *hdr; + + req = 0; /* beginning of request */ + waddr = 0; + rwords = 0; + pm->wbytes = pm->wwords * vdc.buf_width; + pm->rbytes = pm->rwords * vdc.buf_width; + ts = timeval_ms(); + rc = vdebug_wait_server(hsock, pm); + while (!rc && (req < count)) { /* loop over requests to read data and print out */ + hdr = (struct vd_jtag_hdr *)&pm->wd8[waddr * 4]; + hwords = hdr->wlen; + words = hdr->rlen; + anum = hdr->tlen; + num_pre = hdr->pre; + num_post = hdr->post; + if (num_post) + num = anum - num_pre - num_post + 1; + else + num = anum - num_pre; + bytes = (num + 7) / 8; + vdc.trans_last = (req + 1) < count ? 0 : 1; + vdc.trans_first = waddr ? 0 : 1; + if (hdr->cmd == 3) { /* read */ + tdo = vdc.tdo; + for (unsigned int j = 0; j < bytes; j++) { + tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre)); + LOG_DEBUG_IO("%04x D0[%02x]:%02x", pm->wid - count + req, j, tdo[j]); + } + rwords += words; /* read data offset */ + } else { + tdo = NULL; + } + waddr += sizeof(struct vd_jtag_hdr) / 4; /* waddr past header */ + tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre)); + tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre)); + LOG_DEBUG("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", + pm->wid - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), + waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd)); + waddr += hwords * 2; /* start of next request */ + req += 1; + } + + if (rc) { + LOG_ERROR("0x%x executing transaction", rc); + rc = ERROR_FAIL; + } + + te = timeval_ms(); + vdc.targ_time += (uint32_t)(te - ts); + pm->offseth = 0; /* reset buffer write address */ + pm->offset = 0; + pm->rwords = 0; + pm->waddr = 0; + + return rc; +} + +static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, + uint8_t type, uint32_t period_ps, uint32_t sig_mask) +{ + int rc = VD_ERR_NOT_OPEN; + + pm->cmd = VD_CMD_OPEN; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + rc = vdebug_wait_server(hsock, pm); + if (rc != 0) { /* communication problem */ + LOG_ERROR("0x%x connecting to server", rc); + } else if (pm->rid < pm->wid) { + LOG_ERROR("server version %d too old for the client %d", pm->rid, pm->wid); + pm->cmd = VD_CMD_CLOSE; /* let server close the connection */ + vdebug_wait_server(hsock, pm); + rc = VD_ERR_VERSION; + } else { + pm->cmd = VD_CMD_CONNECT; + pm->type = type; /* BFM type to connect to, here JTAG */ + pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16); + pm->wbytes = strlen(path) + 1; + pm->rbytes = 12; + pm->wid = 0; /* reset wid for transaction ID */ + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes + 1); + rc = vdebug_wait_server(hsock, pm); + vdc.sig_read = pm->rwdata >> 16; /* signal read mask */ + vdc.sig_write = pm->rwdata; /* signal write mask */ + vdc.bfm_period = period_ps; + vdc.buf_width = pm->rd32[0] / 8;/* access width in bytes */ + vdc.addr_bits = pm->rd32[2]; /* supported address bits */ + } + + if (rc) { + LOG_ERROR("0x%x connecting to BFM %s", rc, path); + return ERROR_FAIL; + } + + LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", + path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width, + vdc.buf_width, vdc.sig_read, vdc.sig_write); + + return ERROR_OK; +} + +static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type) +{ + pm->cmd = VD_CMD_DISCONNECT; + pm->type = type; /* BFM type, here JTAG */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + pm->cmd = VD_CMD_CLOSE; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("type %0x", type); + + return ERROR_OK; +} + +static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) +{ + if (cycles) { + pm->cmd = VD_CMD_WAIT; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = cycles; /* clock sycles to wait */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles); + return ERROR_FAIL; + } + LOG_DEBUG("%d cycles", cycles); + } + + return ERROR_OK; +} + +static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) +{ + pm->cmd = VD_CMD_SIGSET; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = (write_mask << 16) | (value & 0xffff); /* mask and value of signals to set */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask); + return ERROR_FAIL; + } + + LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value); + + return ERROR_OK; +} + +static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) +{ + pm->cmd = VD_CMD_JTAGCLOCK; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = value; /* divider value */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting jtag_clock", rc); + return ERROR_FAIL; + } + + LOG_DEBUG("setting jtag clock divider to %" PRIx32, value); + + return ERROR_OK; +} + +static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, + const uint8_t tms_pre, uint32_t num, const uint8_t *tdi, + uint8_t num_post, const uint8_t tms_post, uint8_t *tdo, + uint8_t f_last) +{ + const uint32_t tobits = 8; + uint16_t bytes, hwords, anum, words, waddr; + int rc = 0; + + pm->cmd = VD_CMD_JTAGSHTAP; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO) || tdo; + if (vdc.trans_first) + waddr = 0; /* reset buffer offset */ + else + waddr = pm->offseth; /* continue from the previous transaction */ + if (num_post) /* actual number of bits to shift */ + anum = num + num_pre + num_post - 1; + else + anum = num + num_pre; + hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */ + words = (hwords + 1) / 2; /* in 8B TDO words to read */ + bytes = (num + 7) / 8; /* data only portion in bytes */ + /* buffer overflow check and flush */ + if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords + 64 > VD_BUFFER_LEN) { + vdc.trans_last = 1; /* force flush within 64B of buffer end */ + } else if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords > VD_BUFFER_LEN) { + /* this req does not fit, discard it */ + LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift", + pm->wid, anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); + rc = ERROR_FAIL; + } + + if (!rc && anum) { + uint16_t i, j; + struct vd_jtag_hdr *hdr = (struct vd_jtag_hdr *)&pm->wd8[4 * waddr]; /* 8 bytes header */ + hdr->cmd = (tdo ? 3 : 1); /* R and W bits */ + hdr->pre = num_pre; + hdr->post = num_post; + hdr->tlen = anum; + hdr->wlen = hwords; + hdr->rlen = words; + pm->wid++; /* transaction ID */ + waddr += 2; /* waddr past header */ + /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */ + pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0); + pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */ + if (num + num_pre <= 8) /* and tms_post for num <=4 */ + pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1)); + for (i = 1, j = 4 * waddr; i < bytes; i++) { + if (i == bytes - 1 && num + num_pre <= bytes * tobits) + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); + else + pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */ + if (!tdi) /* placing 4 bytes of TDI bits into low word */ + pm->wd8[j + i] = 0x0; + else + pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre)); + if (i % 4 == 3) + j += 4; + } + + if (tdi) + if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */ + pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */ + + if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */ + pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */ + /* in case exactly 1 additional byte needed */ + } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) { + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */ + } else { /* in case 2 additional bytes, tms_post split */ + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */ + if (i % 4 == 3) /* next byte is in the next 32b word */ + pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + else /* next byte is in the same 32b word */ + pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + } + + if (tdo) { + pm->rwords += words; /* keep track of the words to read */ + vdc.tdo = tdo; + } + pm->wwords = waddr / 2 + hwords; /* payload size *2 to include both TDI and TMS data */ + pm->waddr++; + } + + if (!waddr) /* flush issued, but buffer empty */ + ; + else if (!vdc.trans_last) /* buffered request */ + pm->offseth = waddr + hwords * 2; /* offset for next transaction, must be even */ + else /* execute batch of requests */ + rc = vdebug_run_jtag_queue(hsock, pm, pm->waddr); + vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ + + return rc; +} + +static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx) +{ + int rc; + + if (!path) + return ERROR_OK; + + pm->cmd = VD_CMD_MEMOPEN; + pm->wbytes = strlen(path) + 1; /* includes terminating 0 */ + pm->rbytes = 8; + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes); + rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x opening memory %s", rc, path); + } else if (ndx != pm->rd16[1]) { + LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd16[1]); + } else { + vdc.mem_width[ndx] = pm->rd16[0] / 8; /* memory width in bytes */ + vdc.mem_depth[ndx] = pm->rd32[1]; /* memory depth in words */ + LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path, + vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]); + } + + return ERROR_OK; +} + +static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) +{ + pm->cmd = VD_CMD_MEMCLOSE; + pm->rwdata = ndx; /* which memory */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]); +} + +static int vdebug_init(void) +{ + vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); + pbuf = calloc(1, sizeof(struct vd_shm)); + if (!pbuf) { + close_socket(vdc.hsocket); + vdc.hsocket = 0; + LOG_ERROR("cannot allocate %lu bytes", sizeof(struct vd_shm)); + return ERROR_FAIL; + } + if (vdc.hsocket <= 0) { + free(pbuf); + pbuf = NULL; + LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16, + vdc.server_name, vdc.server_port); + return ERROR_FAIL; + } + vdc.trans_first = 1; + vdc.poll_cycles = vdc.poll_max; + uint32_t sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV; + int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask); + if (rc != 0) { + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.bfm_path, rc); + close_socket(vdc.hsocket); + vdc.hsocket = 0; + free(pbuf); + pbuf = NULL; + } else { + for (uint8_t i = 0; i < vdc.mem_ndx; i++) { + rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i); + if (rc != 0) + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.mem_path[i], rc); + } + + LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, + VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); + } + + return rc; +} + +static int vdebug_quit(void) +{ + for (uint8_t i = 0; i < vdc.mem_ndx; i++) + if (vdc.mem_width[i]) + vdebug_mem_close(vdc.hsocket, pbuf, i); + int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type); + LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION, + vdc.bfm_path, vdc.server_name, vdc.server_port, rc); + if (vdc.hsocket) + close_socket(vdc.hsocket); + free(pbuf); + pbuf = NULL; + + return ERROR_OK; +} + +static int vdebug_reset(int trst, int srst) +{ + uint16_t sig_val = 0xffff; + uint16_t sig_mask = 0; + + sig_mask |= VD_SIG_RESET; + if (srst) + sig_val &= ~VD_SIG_RESET;/* active low */ + if (transport_is_jtag()) { + sig_mask |= VD_SIG_TRST; + if (trst) + sig_val &= ~VD_SIG_TRST; /* active low */ + } + + LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val); + int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val); + if (rc == 0) + rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */ + + return rc; +} + +static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) +{ + LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t *)tms); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) +{ + uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; + LOG_INFO("path num states %d", cmd->num_states); + + memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); + + for (uint8_t i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + buf_set_u32(tms, i, 1, 1); + tap_set_state(cmd->path[i]); + } + + return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush); +} + +static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state); + if (cur != state) { + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush); + tap_set_state(state); + } + + return rc; +} + +static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); + uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); + int num_bits = jtag_scan_size(cmd); + LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", + num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); + for (int i = 0; i < cmd->num_fields; i++) { + uint8_t cur_num_pre = i == 0 ? num_pre : 0; + uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; + uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; + uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0; + uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0; + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre, + cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, + cmd->fields[i].in_value, cur_flush); + if (rc) + break; + } + + if (cur != cmd->end_state) + tap_set_state(cmd->end_state); + + return rc; +} + +static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) +{ + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state); + int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); + if (cur != state) + tap_set_state(state); + + return rc; +} + +static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) +{ + LOG_INFO("stab len:%d state cur:%x", num, tap_get_state()); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_sleep(int us) +{ + LOG_INFO("sleep %d us", us); + + return vdebug_wait(vdc.hsocket, pbuf, us / 1000); +} + +static int vdebug_jtag_speed(int speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = clkmax / speed; + LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval); + + return vdebug_jtag_clock(vdc.hsocket, pbuf, divval); +} + +static int vdebug_jtag_khz(int khz, int *jtag_speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = khz ? clkmax / khz : 1; + *jtag_speed = clkmax / divval; + LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz); + + return ERROR_OK; +} + +static int vdebug_jtag_div(int speed, int *khz) +{ + *khz = speed; + LOG_DEBUG("div khz:%d from speed:%d", *khz, speed); + + return ERROR_OK; +} + +static int vdebug_jtag_execute_queue(void) +{ + int rc = ERROR_OK; + + for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RUNTEST: + rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next); + break; + case JTAG_STABLECLOCKS: + rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next); + break; + case JTAG_TLR_RESET: + rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next); + break; + case JTAG_PATHMOVE: + rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next); + break; + case JTAG_TMS: + rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next); + break; + case JTAG_SLEEP: + rc = vdebug_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next); + break; + default: + LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type); + rc = ERROR_FAIL; + } + } + + return rc; +} + +COMMAND_HANDLER(vdebug_set_server) +{ + if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *pchar = strchr(CMD_ARGV[0], ':'); + *pchar = '\0'; + strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1); + int port = atoi(++pchar); + if (port < 0 || port > UINT16_MAX) { + LOG_ERROR("invalid port number %d specified", port); + return ERROR_COMMAND_SYNTAX_ERROR; + } + vdc.server_port = port; + LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_bfm) +{ + char prefix; + + if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2)) + return ERROR_COMMAND_SYNTAX_ERROR; + + strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1); + switch (prefix) { + case 'u': + vdc.bfm_period *= 1000000; + break; + case 'n': + vdc.bfm_period *= 1000; + break; + case 'p': + default: + break; + } + vdc.bfm_type = VD_BFM_JTAG; + LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_mem) +{ + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (vdc.mem_ndx >= VD_MAX_MEMORIES) { + LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); + return ERROR_FAIL; + } + + strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]); + LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx], + vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]); + vdc.mem_ndx++; + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_batching) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (isdigit((unsigned char)CMD_ARGV[0][0])) + vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2)); + else if (CMD_ARGV[0][0] == 'r') + vdc.trans_batch = VD_BATCH_WR; + else if (CMD_ARGV[0][0] == 'w') + vdc.trans_batch = VD_BATCH_WO; + else + vdc.trans_batch = VD_BATCH_NO; + LOG_DEBUG("batching: set to %u", vdc.trans_batch); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_polling) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + vdc.poll_min = atoi(CMD_ARGV[0]); + vdc.poll_max = atoi(CMD_ARGV[1]); + LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max); + + return ERROR_OK; +} + +static const struct command_registration vdebug_command_handlers[] = { + { + .name = "server", + .handler = &vdebug_set_server, + .mode = COMMAND_CONFIG, + .help = "set the vdebug server name or address", + .usage = "", + }, + { + .name = "bfm_path", + .handler = &vdebug_set_bfm, + .mode = COMMAND_CONFIG, + .help = "set the vdebug BFM hierarchical path", + .usage = " ", + }, + { + .name = "mem_path", + .handler = &vdebug_set_mem, + .mode = COMMAND_ANY, + .help = "set the design memory for the code load", + .usage = " ", + }, + { + .name = "batching", + .handler = &vdebug_set_batching, + .mode = COMMAND_CONFIG, + .help = "set the transaction batching no|wr|rd [0|1|2]", + .usage = "", + }, + { + .name = "polling", + .handler = &vdebug_set_polling, + .mode = COMMAND_CONFIG, + .help = "set the polling pause, executing hardware cycles between min and max", + .usage = " ", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration vdebug_command[] = { + { + .name = "vdebug", + .chain = vdebug_command_handlers, + .mode = COMMAND_ANY, + .help = "vdebug command group", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface vdebug_jtag_ops = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = vdebug_jtag_execute_queue, +}; + +struct adapter_driver vdebug_adapter_driver = { + .name = "vdebug", + .transports = jtag_only, + .speed = vdebug_jtag_speed, + .khz = vdebug_jtag_khz, + .speed_div = vdebug_jtag_div, + .commands = vdebug_command, + .init = vdebug_init, + .quit = vdebug_quit, + .reset = vdebug_reset, + .jtag_ops = &vdebug_jtag_ops, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 63faa9561..ddf70cc24 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -57,6 +57,9 @@ extern struct adapter_driver usb_blaster_adapter_driver; #if BUILD_JTAG_VPI == 1 extern struct adapter_driver jtag_vpi_adapter_driver; #endif +#if BUILD_VDEBUG == 1 +extern struct adapter_driver vdebug_adapter_driver; +#endif #if BUILD_JTAG_DPI == 1 extern struct adapter_driver jtag_dpi_adapter_driver; #endif @@ -168,6 +171,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, +#endif #if BUILD_JTAG_DPI == 1 &jtag_dpi_adapter_driver, #endif diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index def594ee3..4ec2f1e31 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -546,7 +546,8 @@ int jtag_srst_asserted(int *srst_asserted); * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. - * @returns Nothing, but calls jtag_set_error() on any error. + * + * returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 441b7abc5..4161e63fa 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -175,6 +175,18 @@ static const struct threadx_params threadx_params_list[] = { get_stacking_info_arm926ejs, /* fn_get_stacking_info */ is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */ }, + { + "hla_target", /* target_name */ + 4, /* pointer_width; */ + 8, /* thread_stack_offset; */ + 40, /* thread_name_offset; */ + 48, /* thread_state_offset; */ + 136, /* thread_next_offset */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + 1, /* stacking_info_nb */ + NULL, /* fn_get_stacking_info */ + NULL, /* fn_is_thread_id_valid */ + }, }; enum threadx_symbol_values { diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 4b8e22b10..b7d5c5f58 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -23,6 +23,7 @@ #include "target/target.h" #include "target/target_type.h" #include "target/register.h" +#include #include "rtos.h" #include "helper/log.h" #include "helper/types.h" @@ -109,7 +110,7 @@ static int hwthread_update_threads(struct rtos *rtos) /* determine the number of "threads" */ if (target->smp) { - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -130,7 +131,7 @@ static int hwthread_update_threads(struct rtos *rtos) if (target->smp) { /* loop over all threads */ - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -225,7 +226,8 @@ static struct target *hwthread_find_thread(struct target *target, int64_t thread if (!target) return NULL; if (target->smp) { - for (struct target_list *head = target->head; head; head = head->next) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { if (thread_id == threadid_from_target(head->target)) return head->target; } diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 84b4c6524..d147c1cf0 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -30,6 +30,7 @@ #include "rtos.h" #include "rtos_standard_stackings.h" #include +#include #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 @@ -191,16 +192,14 @@ static int linux_os_thread_reg_list(struct rtos *rtos, /* search target to perform the access */ struct reg **gdb_reg_list; struct target_list *head; - head = target->head; found = 0; - do { + foreach_smp_target(head, target->smp_targets) { if (head->target->coreid == next->core_id) { target = head->target; found = 1; break; } - head = head->next; - } while (head); + } if (found == 0) { LOG_ERROR @@ -397,7 +396,6 @@ static int get_name(struct target *target, struct threads *t) static int get_current(struct target *target, int create) { struct target_list *head; - head = target->head; uint8_t *buf; uint32_t val; uint32_t ti_addr; @@ -413,7 +411,7 @@ static int get_current(struct target *target, int create) ctt = ctt->next; } - while (head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list; int reg_list_size; int retval; @@ -474,7 +472,6 @@ static int get_current(struct target *target, int create) } free(reg_list); - head = head->next; } free(buffer); @@ -1394,9 +1391,8 @@ static int linux_os_smp_init(struct target *target) struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos->rtos_specific_params; @@ -1413,8 +1409,6 @@ static int linux_os_smp_init(struct target *target) os_linux->nr_cpus++; free(smp_os_linux); } - - head = head->next; } return ERROR_OK; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index b9adf0a25..2091e1b44 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -801,7 +801,7 @@ struct rtos *rtos_of_target(struct target *target) if ((target->rtos) && (target->rtos->type)) return target->rtos; - foreach_smp_target(pos, target->head) + foreach_smp_target(pos, target->smp_targets) if ((pos->target->rtos) && (pos->target->rtos->type)) return pos->target->rtos; diff --git a/src/server/Makefile.am b/src/server/Makefile.am index fb5248bfd..e3699f181 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -6,7 +6,6 @@ noinst_LTLIBRARIES += %D%/libserver.la %D%/server.h \ %D%/telnet_server.h \ %D%/gdb_server.h \ - %D%/server_stubs.c \ %D%/tcl_server.c \ %D%/tcl_server.h \ %D%/rtt_server.c \ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 20cf67092..4db305cde 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2276,21 +2276,25 @@ static int smp_reg_list_noread(struct target *target, return target_get_gdb_reg_list_noread(target, combined_list, combined_list_size, REG_CLASS_ALL); - int combined_allocated = 256; - *combined_list = malloc(combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { - LOG_ERROR("malloc(%d) failed", (int) (combined_allocated * sizeof(struct reg *))); + unsigned int combined_allocated = 256; + struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *)); + if (!local_list) { + LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } - *combined_list_size = 0; + unsigned int local_list_size = 0; + struct target_list *head; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { - free(*combined_list); + free(local_list); return result; } for (int i = 0; i < reg_list_size; i++) { @@ -2300,8 +2304,8 @@ static int smp_reg_list_noread(struct target *target, /* Nested loop makes this O(n^2), but this entire function with * 5 RISC-V targets takes just 2ms on my computer. Fast enough * for me. */ - for (int j = 0; j < *combined_list_size; j++) { - struct reg *b = (*combined_list)[j]; + for (unsigned int j = 0; j < local_list_size; j++) { + struct reg *b = local_list[j]; if (!strcmp(a->name, b->name)) { found = true; if (a->size != b->size) { @@ -2309,7 +2313,7 @@ static int smp_reg_list_noread(struct target *target, "target, but %d bits on another target.", a->name, a->size, b->size); free(reg_list); - free(*combined_list); + free(local_list); return ERROR_FAIL; } break; @@ -2317,22 +2321,62 @@ static int smp_reg_list_noread(struct target *target, } if (!found) { LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); - if (*combined_list_size >= combined_allocated) { + if (local_list_size >= combined_allocated) { combined_allocated *= 2; - *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { - LOG_ERROR("realloc(%d) failed", (int) (combined_allocated * sizeof(struct reg *))); + local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); + if (!local_list) { + LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } } - (*combined_list)[*combined_list_size] = a; - (*combined_list_size)++; + local_list[local_list_size] = a; + local_list_size++; } } } free(reg_list); } + if (local_list_size == 0) { + LOG_ERROR("Unable to get register list"); + free(local_list); + return ERROR_FAIL; + } + + /* Now warn the user about any registers that weren't found in every target. */ + foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(local_list); + return result; + } + for (unsigned int i = 0; i < local_list_size; i++) { + bool found = false; + struct reg *a = local_list[i]; + for (int j = 0; j < reg_list_size; j++) { + struct reg *b = reg_list[j]; + if (b->exist && !strcmp(a->name, b->name)) { + found = true; + break; + } + } + if (!found) { + LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " + "this register does exist.", + a->name, target_name(head->target)); + } + } + free(reg_list); + } + + *combined_list = local_list; + *combined_list_size = local_list_size; return ERROR_OK; } @@ -2595,8 +2639,14 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou if (!thread_detail->exists) continue; - xml_printf(&retval, &thread_list, &pos, &size, - "", thread_detail->threadid); + if (thread_detail->thread_name_str) + xml_printf(&retval, &thread_list, &pos, &size, + "", + thread_detail->threadid, + thread_detail->thread_name_str); + else + xml_printf(&retval, &thread_list, &pos, &size, + "", thread_detail->threadid); if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, @@ -3652,13 +3702,10 @@ static int gdb_target_start(struct target *target, const char *port) /* initialize all targets gdb service with the same pointer */ { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) curr->gdb_service = gdb_service; - head = head->next; } } return ret; diff --git a/src/server/server.c b/src/server/server.c index 3f579bfc6..1569f5a2c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -487,10 +487,8 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - openocd_sleep_prelude(); kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); - openocd_sleep_postlude(); } if (retval == -1) { diff --git a/src/server/server.h b/src/server/server.h index de18d2b4b..bacd1116a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -97,15 +97,6 @@ int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_prelude(void); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_postlude(void); - /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. diff --git a/src/server/server_stubs.c b/src/server/server_stubs.c deleted file mode 100644 index a4c017289..000000000 --- a/src/server/server_stubs.c +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "server.h" - -void openocd_sleep_prelude(void) -{ - /* no-op */ -} -void openocd_sleep_postlude(void) -{ - /* no-op */ -} diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 30ef54792..a45322d2f 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -102,6 +102,7 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -180,6 +181,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -331,15 +333,14 @@ static int aarch64_wait_halt_one(struct target *target) static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; - struct target_list *head = target->head; + struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); - head = head->next; if (exc_target && curr == target) continue; @@ -428,7 +429,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) struct target_list *head; struct target *curr; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; @@ -478,7 +479,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* poll all targets in the group, but skip the target that serves GDB */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -743,7 +744,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint struct target *first = NULL; uint64_t address; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ @@ -798,7 +799,7 @@ static int aarch64_step_restart_smp(struct target *target) struct target *curr = target; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -886,7 +887,7 @@ static int aarch64_resume(struct target *target, int current, struct target_list *head; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -1049,6 +1050,7 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 792474acf..507d1cd2c 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -367,10 +367,13 @@ int arm_semihosting(struct target *target, int *retval) } /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); + LOG_ERROR("Failed semihosting operation (0x%02X)", + semihosting->op); return 0; } } else { diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 2259fa560..d564f19ae 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -38,6 +38,7 @@ #include "arm_opcodes.h" #include "target.h" #include "target_type.h" +#include "smp.h" static void armv7a_show_fault_registers(struct target *target) { @@ -193,8 +194,7 @@ int armv7a_read_ttbcr(struct target *target) static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); @@ -207,15 +207,14 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_ERROR("smp target : outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return JIM_OK; } diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 4078fdde2..ba6f076f0 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -26,6 +26,7 @@ #include "armv7a_cache.h" #include #include "arm_opcodes.h" +#include "smp.h" static int armv7a_l1_d_cache_sanity_check(struct target *target) { @@ -138,14 +139,10 @@ int armv7a_cache_auto_flush_all_data(struct target *target) if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) retval = armv7a_l1_d_cache_clean_inval_all(curr); - - head = head->next; } } else retval = armv7a_l1_d_cache_clean_inval_all(target); diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index 6b42fae53..c26d05173 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -27,6 +27,7 @@ #include #include "target.h" #include "target_type.h" +#include "smp.h" static int arm7a_l2x_sanity_check(struct target *target) { @@ -194,8 +195,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -210,8 +210,8 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t /* initialize all targets in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -220,7 +220,6 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t } armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return ERROR_OK; } diff --git a/src/target/armv7m.h b/src/target/armv7m.h index d33e57492..9ac121ac3 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -255,15 +255,48 @@ struct armv7m_common { void (*pre_restore_context)(struct target *target); }; +static inline bool is_armv7m(const struct armv7m_common *armv7m) +{ + return armv7m->common_magic == ARMV7M_COMMON_MAGIC; +} + +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(const struct armv7m_common *armv7m) +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct armv7m_common * +target_to_armv7m_safe(struct target *target) { - return armv7m->common_magic == ARMV7M_COMMON_MAGIC; + if (!target) + return NULL; + + if (!target->arch_info) + return NULL; + + /* Check the parent type first to prevent peeking memory too far + * from arch_info pointer */ + if (!is_arm(target_to_arm(target))) + return NULL; + + struct armv7m_common *armv7m = target_to_armv7m(target); + if (!is_armv7m(armv7m)) + return NULL; + + return armv7m; } struct armv7m_algorithm { diff --git a/src/target/armv8.c b/src/target/armv8.c index 26116bb33..2de115712 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -77,6 +77,10 @@ static const struct { .name = "HYP", .psr = ARM_MODE_HYP, }, + { + .name = "UND", + .psr = ARM_MODE_UND, + }, { .name = "SYS", .psr = ARM_MODE_SYS, diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index f05ac07cd..5b58d3f9f 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -23,6 +23,7 @@ #include "armv8_cache.h" #include "armv8_dpm.h" #include "armv8_opcodes.h" +#include "smp.h" /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 @@ -250,15 +251,12 @@ static int armv8_flush_all_data(struct target *target) /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) { LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); retval = _armv8_flush_all_data(curr); } - head = head->next; } } else retval = _armv8_flush_all_data(target); diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 938a7ecce..44c7a2c71 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -27,6 +27,7 @@ #include #include "breakpoints.h" #include "rtos/rtos.h" +#include "smp.h" static const char * const breakpoint_type_strings[] = { "hardware", @@ -217,24 +218,25 @@ int breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { - struct target_list *head = target->head; + struct target_list *head; + if (type == BKPT_SOFT) { + head = list_first_entry(target->smp_targets, struct target_list, lh); struct target *curr = head->target; if (target->rtos) curr = rtos_swbp_target(target, address, length, type); return breakpoint_add_internal(curr, address, length, type); } - while (head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - retval = breakpoint_add_internal(curr, address, length, type); + int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return breakpoint_add_internal(target, address, length, type); } @@ -245,19 +247,17 @@ int context_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = context_breakpoint_add_internal(curr, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return context_breakpoint_add_internal(target, asid, length, type); } @@ -269,19 +269,17 @@ int hybrid_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else return hybrid_breakpoint_add_internal(target, address, asid, length, type); } @@ -348,12 +346,10 @@ void breakpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_breakpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_breakpoints += breakpoint_remove_internal(curr, address); - head = head->next; } if (!num_breakpoints) LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); @@ -366,12 +362,10 @@ void breakpoint_remove_all(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_remove_all_internal(curr); - head = head->next; } } else { breakpoint_remove_all_internal(target); @@ -390,12 +384,10 @@ void breakpoint_clear_target(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_clear_target_internal(curr); - head = head->next; } } else { breakpoint_clear_target_internal(target); @@ -485,21 +477,17 @@ 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) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = watchpoint_add_internal(curr, address, length, rw, value, - mask); + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return watchpoint_add_internal(target, address, length, rw, value, mask); @@ -552,12 +540,10 @@ void watchpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_watchpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_watchpoints += watchpoint_remove_internal(curr, address); - head = head->next; } if (num_watchpoints == 0) LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bf65544f5..272411359 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -639,14 +639,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -656,14 +653,12 @@ static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED) && target_was_examined(curr)) retval += cortex_a_halt(curr); - head = head->next; } return retval; } @@ -684,7 +679,7 @@ static int update_halt_gdb(struct target *target) if (target->gdb_service) gdb_target = target->gdb_service->target; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -951,11 +946,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; - struct target *curr; target_addr_t address; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ @@ -963,8 +957,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index c2f836a35..555401416 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -46,6 +46,7 @@ #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) enum cortex_m_partno { + CORTEX_M_PARTNO_INVALID, CORTEX_M0_PARTNO = 0xC20, CORTEX_M1_PARTNO = 0xC21, CORTEX_M3_PARTNO = 0xC23, @@ -247,13 +248,6 @@ struct cortex_m_common { bool maskints_erratum; }; -static inline struct cortex_m_common * -target_to_cm(struct target *target) -{ - return container_of(target->arch_info, - struct cortex_m_common, armv7m); -} - static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; @@ -267,6 +261,57 @@ static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cor return !cortex_m->armv7m.is_hla_target; } +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ +static inline struct cortex_m_common * +target_to_cm(struct target *target) +{ + return container_of(target->arch_info, + struct cortex_m_common, armv7m.arm); +} + +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct cortex_m_common * +target_to_cortex_m_safe(struct target *target) +{ + /* Check the parent types first to prevent peeking memory too far + * from arch_info pointer */ + if (!target_to_armv7m_safe(target)) + return NULL; + + struct cortex_m_common *cortex_m = target_to_cm(target); + if (!is_cortex_m_or_hla(cortex_m)) + return NULL; + + return cortex_m; +} + +/** + * @returns cached value of Cortex-M part number + * 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) +{ + struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); + if (!cortex_m) + return CORTEX_M_PARTNO_INVALID; + + if (!cortex_m->core_info) + return CORTEX_M_PARTNO_INVALID; + + return cortex_m->core_info->partno; +} + int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index ca4416981..8627bce6e 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -128,14 +128,11 @@ static int mips_m4k_debug_entry(struct target *target) static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -144,11 +141,10 @@ static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) ret = mips_m4k_halt(curr); @@ -156,7 +152,6 @@ static int mips_m4k_halt_smp(struct target *target) LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid); retval = ret; } - head = head->next; } return retval; } @@ -414,12 +409,10 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, @@ -431,7 +424,6 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han retval = ret; } } - head = head->next; } return retval; } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 62866dcfd..553cc3955 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2297,7 +2297,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; - if (generic_info->version_specific == NULL) { + if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index cba4bf92f..cc38bd4c7 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -13,6 +13,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" +#include #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" @@ -1296,13 +1297,14 @@ int riscv_halt(struct target *target) int result = ERROR_OK; if (target->smp) { - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_prep(t) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1311,7 +1313,7 @@ int riscv_halt(struct target *target) } } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_finish(t) != ERROR_OK) return ERROR_FAIL; @@ -1500,32 +1502,6 @@ static int resume_finish(struct target *target, int debug_execution) debug_execution ? TARGET_EVENT_DEBUG_RESUMED : TARGET_EVENT_RESUMED); } -/* Return a newly allocated target list, that contains the same targets as in - * tlist bit in the opposite order. */ -static struct target_list *tlist_reverse(struct target_list *tlist) -{ - struct target_list *previous = NULL; - struct target_list *reversed = NULL; - for (struct target_list *node = tlist; node; node = node->next) { - reversed = calloc(1, sizeof(struct target_list)); - reversed->target = node->target; - reversed->next = previous; - previous = reversed; - } - return reversed; -} - -/* Free a target list, but not the targets that are referenced. */ -static void tlist_free(struct target_list *tlist) -{ - struct target_list *node = tlist; - while (node) { - struct target_list *previous = node; - node = node->next; - free(previous); - } -} - /** * @par single_hart When true, only resume a single hart even if SMP is * configured. This is used to run algorithms on just one hart. @@ -1541,21 +1517,17 @@ int riscv_resume( LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); int result = ERROR_OK; if (target->smp && !single_hart) { - struct target_list *ordered_tlist; - - if (resume_order == RO_REVERSED) - ordered_tlist = tlist_reverse(target->head); - else - ordered_tlist = target->head; - - for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1565,15 +1537,13 @@ int riscv_resume( } } - for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - if (resume_order == RO_REVERSED) - tlist_free(ordered_tlist); - } else { if (resume_prep(target, current, address, handle_breakpoints, debug_execution) != ERROR_OK) @@ -2230,9 +2200,8 @@ int riscv_openocd_poll(struct target *target) unsigned halts_discovered = 0; unsigned should_remain_halted = 0; unsigned should_resume = 0; - unsigned i = 0; - for (struct target_list *list = target->head; list; - list = list->next, i++) { + struct target_list *list; + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; if (!target_was_examined(t)) continue; @@ -2294,8 +2263,7 @@ int riscv_openocd_poll(struct target *target) } /* Sample memory if any target is running. */ - for (struct target_list *list = target->head; list; - list = list->next, i++) { + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; if (t->state == TARGET_RUNNING) { sample_memory(target); diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index b347212d3..1dd8e7791 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -140,7 +140,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) semihosting->word_size_bytes = riscv_xlen(target) / 8; /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 1b65e126c..9e60de572 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -52,19 +52,35 @@ #include #include +/** + * It is not possible to use O_... flags defined in sys/stat.h because they + * are not guaranteed to match the values defined by the GDB Remote Protocol. + * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags + */ +enum { + TARGET_O_RDONLY = 0x000, + TARGET_O_WRONLY = 0x001, + TARGET_O_RDWR = 0x002, + TARGET_O_APPEND = 0x008, + TARGET_O_CREAT = 0x200, + TARGET_O_TRUNC = 0x400, + /* O_EXCL=0x800 is not required in this implementation. */ +}; + +/* GDB remote protocol does not differentiate between text and binary open modes. */ static const int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + TARGET_O_RDONLY, + TARGET_O_RDONLY, + TARGET_O_RDWR, + TARGET_O_RDWR, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; static int semihosting_common_fileio_info(struct target *target, @@ -138,6 +154,12 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +/** + * User operation parameter string storage buffer. Contains valid data when the + * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. + */ +static char *semihosting_user_op_params; + /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation @@ -167,7 +189,7 @@ 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, (int)semihosting->op, + LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); switch (semihosting->op) { @@ -1262,6 +1284,71 @@ int semihosting_common(struct target *target) } break; + case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107: + /** + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, only 0x100-0x107 are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + { + assert(!semihosting_user_op_params); + + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read fields for user defined command" + " op=0x%x", semihosting->op); + return retval; + } + + uint64_t addr = semihosting_get_field(target, 0, fields); + + size_t len = semihosting_get_field(target, 1, fields); + if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { + LOG_ERROR("The maximum length for user defined command " + "parameter is %u, received length is %zu (op=0x%x)", + SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + len, + semihosting->op); + return ERROR_FAIL; + } + + semihosting_user_op_params = malloc(len + 1); + if (!semihosting_user_op_params) + return ERROR_FAIL; + semihosting_user_op_params[len] = 0; + + 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); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + return retval; + } + + target_handle_event(target, semihosting->op); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + + semihosting->result = 0; + break; + } + + case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* * Returns the number of elapsed target ticks since execution @@ -1608,6 +1695,30 @@ COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct semihosting *semihosting = target->semihosting; + + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!semihosting->is_active) { + LOG_ERROR("semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (!semihosting_user_op_params) { + LOG_ERROR("This command is usable only from a registered user " + "semihosting event callback."); + return ERROR_FAIL; + } + + command_print_sameline(CMD, "%s", semihosting_user_op_params); + + return ERROR_OK; +} + const struct command_registration semihosting_common_handlers[] = { { "semihosting", @@ -1637,5 +1748,12 @@ const struct command_registration semihosting_common_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, + { + "semihosting_read_user_param", + .handler = handle_common_semihosting_read_user_param_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "read parameters in semihosting-user-cmd-0x10X callbacks", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index b83464ed5..6eb9ca252 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -75,8 +75,14 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + 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 */ }; +/** Maximum allowed Tcl command segment length in bytes*/ +#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024) + /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). diff --git a/src/target/smp.c b/src/target/smp.c index 518f6e458..3e1ded8bc 100644 --- a/src/target/smp.c +++ b/src/target/smp.c @@ -111,18 +111,18 @@ COMMAND_HANDLER(default_handle_smp_command) } if (!strcmp(CMD_ARGV[0], "on")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 1; return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "off")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 0; /* fixes the target display to the debugger */ - if (target->head) + if (!list_empty(target->smp_targets)) target->gdb_service->target = target; return ERROR_OK; @@ -135,9 +135,7 @@ COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; - struct target_list *head; - head = target->head; - if (head) { + if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); diff --git a/src/target/smp.h b/src/target/smp.h index 3338240ad..490a49310 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -19,10 +19,14 @@ #ifndef OPENOCD_TARGET_SMP_H #define OPENOCD_TARGET_SMP_H +#include #include "server/server.h" #define foreach_smp_target(pos, head) \ - for (pos = head; (pos); pos = pos->next) + list_for_each_entry(pos, head, lh) + +#define foreach_smp_target_direction(forward, pos, head) \ + list_for_each_entry_direction(forward, pos, head, lh) extern const struct command_registration smp_command_handlers[]; diff --git a/src/target/target.c b/src/target/target.c index 1b112119e..1959bbe0b 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -56,6 +56,7 @@ #include "rtos/rtos.h" #include "transport/transport.h" #include "arm_cti.h" +#include "smp.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -159,6 +160,7 @@ static int64_t target_timer_next_event_value; static LIST_HEAD(target_reset_callback_list); static LIST_HEAD(target_trace_callback_list); static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static LIST_HEAD(empty_smp_targets); static const struct jim_nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, @@ -236,6 +238,15 @@ static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" }, + { .name = NULL, .value = -1 } }; @@ -2272,13 +2283,15 @@ static void target_destroy(struct target *target) /* release the targets SMP list */ if (target->smp) { - struct target_list *head = target->head; - while (head) { - struct target_list *pos = head->next; + struct target_list *head, *tmp; + + list_for_each_entry_safe(head, tmp, target->smp_targets, lh) { + list_del(&head->lh); head->target->smp = 0; free(head); - head = pos; } + if (target->smp_targets != &empty_smp_targets) + free(target->smp_targets); target->smp = 0; } @@ -5782,6 +5795,9 @@ static int target_create(struct jim_getopt_info *goi) return JIM_ERR; } + /* set empty smp cluster */ + target->smp_targets = &empty_smp_targets; + /* set target number */ target->target_number = new_target_number(); @@ -5995,9 +6011,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) int retval, len; static int smp_group = 1; struct target *target = NULL; - struct target_list *head, *curr, *new; - curr = NULL; - head = NULL; + struct target_list *head, *new; retval = 0; LOG_DEBUG("%d", argc); @@ -6006,6 +6020,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) * argv[3] ... */ + struct list_head *lh = malloc(sizeof(*lh)); + if (!lh) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + INIT_LIST_HEAD(lh); + for (i = 1; i < argc; i++) { targetname = Jim_GetString(argv[i], &len); @@ -6014,24 +6035,15 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (target) { new = malloc(sizeof(struct target_list)); new->target = target; - new->next = NULL; - if (!head) { - head = new; - curr = head; - } else { - curr->next = new; - curr = new; - } + list_add_tail(&new->lh, lh); } } /* now parse the list of cpu and put the target in smp mode*/ - curr = head; - - while (curr) { - target = curr->target; + foreach_smp_target(head, lh) { + target = head->target; target->smp = smp_group; - target->head = head; - curr = curr->next; + target->smp = 1; + target->smp_targets = lh; } smp_group++; diff --git a/src/target/target.h b/src/target/target.h index 6903b5ffa..4b494d8d5 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -201,7 +201,9 @@ struct target { * and must be detected when symbols are offered */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ - struct target_list *head; + struct list_head *smp_targets; /* list all targets in this smp group/cluster + * The head of the list is shared between the + * cluster, thus here there is a pointer */ /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing @@ -220,8 +222,8 @@ struct target { }; struct target_list { + struct list_head lh; struct target *target; - struct target_list *next; }; struct gdb_fileio_info { @@ -294,6 +296,15 @@ enum target_event { TARGET_EVENT_GDB_FLASH_WRITE_END, TARGET_EVENT_TRACE_CONFIG, + + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107, }; struct target_event_action { diff --git a/tcl/board/evb-lan9255.cfg b/tcl/board/evb-lan9255.cfg new file mode 100644 index 000000000..3fd6f603b --- /dev/null +++ b/tcl/board/evb-lan9255.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip LAN9255 evaluation board +# https://www.microchip.com/en-us/development-tool/EV25Y25A +# + +set CHIPNAME same53 + +source [find target/atsame5x.cfg] + +reset_config srst_only diff --git a/tcl/board/nxp_rdb-ls1088a.cfg b/tcl/board/nxp_rdb-ls1088a.cfg new file mode 100644 index 000000000..40483f2d6 --- /dev/null +++ b/tcl/board/nxp_rdb-ls1088a.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088ARDB (Reference Design Board) +# This is for the "main" JTAG connector J55 + +transport select jtag +reset_config srst_only + +# To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command +# line. At the time of this writing, programming is unsupported. +if { [info exists CWTAP] } { + source [find cpld/altera-epm240.cfg] +} else { + source [find target/ls1088a.cfg] +} diff --git a/tcl/board/vd_a53x2_jtag.cfg b/tcl/board/vd_a53x2_jtag.cfg new file mode 100644 index 000000000..869bc4db0 --- /dev/null +++ b/tcl/board/vd_a53x2_jtag.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through JTAG + +source [find interface/vdebug.cfg] + +set _CORES 2 +set _CHIPNAME a53 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x1000000 +set _CPUTAPID 0x5ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_m4_jtag.cfg b/tcl/board/vd_m4_jtag.cfg new file mode 100644 index 000000000..ca21476d2 --- /dev/null +++ b/tcl/board/vd_m4_jtag.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m4 through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME m4 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 +set _CPUTAPID 0x4ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 25000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 20ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg new file mode 100644 index 000000000..69dd9e6db --- /dev/null +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV Ibex core with Pulpissimo through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME ibex +set _HARTID 0x20 +set _CPUTAPID 0x249511c3 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 12500 +adapter srst delay 10 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 40ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/board/vd_swerv_jtag.cfg b/tcl/board/vd_swerv_jtag.cfg new file mode 100644 index 000000000..ff6c6835f --- /dev/null +++ b/tcl/board/vd_swerv_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV swerv core with Swerv through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME rv32 +set _HARTID 0x00 +set _CPUTAPID 0x1000008b +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 62f2b73b7..ece02bbef 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,6 +1,23 @@ # Altera MAXII EPM240T100C CPLD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME epm240 +} + # see MAX II Device Handbook # Table 3-3: 32-Bit MAX II Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0001 000 0110 1110 1 -jtag newtap epm240 tap -expected-id 0x020a10dd -irlen 10 +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020a10dd \ + -expected-id 0x020a20dd \ + -expected-id 0x020a30dd \ + -expected-id 0x020a40dd \ + -expected-id 0x020a50dd \ + -expected-id 0x020a60dd + +# 200ns seems like a good speed +# c.f. Table 5-34: MAX II JTAG Timing Parameters +adapter speed 5000 diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg new file mode 100644 index 000000000..9cca6aaab --- /dev/null +++ b/tcl/interface/vdebug.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface + +if { [info exists VDEBUGHOST] } { + set _VDEBUGHOST $VDEBUGHOST +} else { + set _VDEBUGHOST localhost +} +if { [info exists VDEBUGPORT] } { + set _VDEBUGPORT $VDEBUGPORT +} else { + set _VDEBUGPORT 8192 +} + +adapter driver vdebug +# vdebug server:port +vdebug server $_VDEBUGHOST:$_VDEBUGPORT + +# example config debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# example config listen on all interfaces, disable tcl/telnet server +bindto 0.0.0.0 +#gdb_port 3333 +#telnet_port disabled +tcl_port disabled + +# transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw +vdebug batching 1 + +# Polling values +vdebug polling 100 1000 \ No newline at end of file diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg new file mode 100644 index 000000000..f9ae9a134 --- /dev/null +++ b/tcl/target/ls1088a.cfg @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1088a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +set _CPU_BASE 0x81000000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 8} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +# Service processor +target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 + +# Normally you will not need to call this, but if you are using the hard-coded +# Reset Configuration Word (RCW) you will need to call this manually. The CPU's +# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit +# instructions. This will cause the CPU to almost immediately execute an +# illegal instruction. +# +# This code is idempotent; releasing a released CPU has no effect, although it +# will halt/resume the service processor. +add_help_text release_cpu "Release a cpu which is held off" +proc release_cpu {cpu} { + set RST_BRRL 0x1e60060 + + set old [target current] + targets $::_CHIPNAME.sp + set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] + if {$not_halted} { + halt + } + + # Release the cpu; it will start executing something bogus + mem2array regs 32 $RST_BRRL 1 + mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + + if {$not_halted} { + resume + } + targets $old +} + +targets $_CHIPNAME.cpu0 + +# Seems to work OK in testing +adapter speed 10000 diff --git a/tcl/target/vd_aarch64.cfg b/tcl/target/vd_aarch64.cfg new file mode 100644 index 000000000..619134aa6 --- /dev/null +++ b/tcl/target/vd_aarch64.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm v8 64b Cortex A + +if {![info exists _CORES]} { + set _CORES 1 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME aarch64 +} +set _TARGETNAME $_CHIPNAME.cpu +set _CTINAME $_CHIPNAME.cti + +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME +$_CHIPNAME.dap apsel 1 + +for { set _core 0 } { $_core < $_CORES } { incr _core } \ +{ + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + set _smp_command "target smp $_TARGETNAME.$_core" + } + eval $_command +} +eval $_smp_command + +# default target is core 0 +targets $_TARGETNAME.0 diff --git a/tcl/target/vd_cortex_m.cfg b/tcl/target/vd_cortex_m.cfg new file mode 100644 index 000000000..4d7b0df26 --- /dev/null +++ b/tcl/target/vd_cortex_m.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# ARM Cortex M + +if {![info exists _CHIPNAME]} { + set _CHIPNAME cortex_m +} +set _TARGETNAME $_CHIPNAME.cpu + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg new file mode 100644 index 000000000..b42b25a3a --- /dev/null +++ b/tcl/target/vd_riscv.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV core + +if {![info exists _HARTID]} { + set _HARTID 0x00 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME riscv +} +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 +# prefer to use sba for system bus access +riscv set_prefer_sba on From da7328010165be6e0188100e79b9dab5c362e13b Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 4 Jun 2021 15:04:54 +0200 Subject: [PATCH 046/186] target/tcl: Add set_reg function Change-Id: I97a01b93046cb7af289792489f77f5580312585a Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5313 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 30 +++++++++++++++++++++ src/target/target.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index fd4a81da2..c0df9c9ac 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5003,6 +5003,21 @@ and neither store nor return those values. @end itemize @end deffn +@deffn {Command} {$target_name set_reg} dict +Set register values of the target. + +@itemize +@item @var{dict} ... Tcl dictionary with pairs of register names and values. +@end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8491,6 +8506,21 @@ Debug and trace infrastructure: @end example @end deffn +@deffn {Command} {set_reg} dict +Set register values of the target. + +@itemize +@item @var{dict} ... Tcl dictionary with pairs of register names and values. +@end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index 6250d3031..1d26cb91c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4863,6 +4863,57 @@ void target_handle_event(struct target *target, enum target_event e) } } +static int target_jim_set_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "dict"); + return JIM_ERR; + } + + int tmp; + Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); + + if (!dict) + return JIM_ERR; + + const unsigned int length = tmp; + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + const struct target *target = get_current_target(cmd_ctx); + + for (unsigned int i = 0; i < length; i += 2) { + const char *reg_name = Jim_String(dict[i]); + const char *reg_value = Jim_String(dict[i + 1]); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); + + if (!buf) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); + int retval = reg->type->set(reg, buf); + free(buf); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", + reg_value, reg_name); + return JIM_ERR; + } + } + + return JIM_OK; +} + /** * Returns true only if the target has a handler for the specified event. */ @@ -5645,6 +5696,13 @@ static const struct command_registration target_instance_command_handlers[] = { "from target memory", .usage = "arrayname bitwidth address count", }, + { + .name = "set_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", + }, { .name = "eventlist", .handler = handle_target_event_list, @@ -6727,6 +6785,13 @@ static const struct command_registration target_exec_command_handlers[] = { "and write the 8/16/32 bit values", .usage = "arrayname bitwidth address count", }, + { + .name = "set_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", + }, { .name = "reset_nag", .handler = handle_target_reset_nag, From e8e62c5aca494fa17a5e543831b8eef3740c9b1d Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 4 Jun 2021 15:05:17 +0200 Subject: [PATCH 047/186] target/tcl: Add get_reg function Change-Id: Id1be9554d1df2c07cec3161a0fd3a586fdf18246 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5312 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 36 ++++++++++++++++ src/target/target.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index c0df9c9ac..2bfa0deae 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5018,6 +5018,24 @@ set_reg @{pc 0 sp 0x1000@} @end example @end deffn +@deffn {Command} {$target_name get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. + +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8521,6 +8539,24 @@ set_reg @{pc 0 sp 0x1000@} @end example @end deffn +@deffn {Command} {get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. + +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index 1d26cb91c..b72dc53e3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4863,6 +4863,93 @@ void target_handle_event(struct target *target, enum target_event e) } } +static int target_jim_get_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + bool force = false; + + if (argc == 3) { + const char *option = Jim_GetString(argv[1], NULL); + + if (!strcmp(option, "-force")) { + argc--; + argv++; + force = true; + } else { + Jim_SetResultFormatted(interp, "invalid option '%s'", option); + return JIM_ERR; + } + } + + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "[-force] list"); + return JIM_ERR; + } + + const int length = Jim_ListLength(interp, argv[1]); + + Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0); + + if (!result_dict) + return JIM_ERR; + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + const struct target *target = get_current_target(cmd_ctx); + + for (int i = 0; i < length; i++) { + Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i); + + if (!elem) + return JIM_ERR; + + const char *reg_name = Jim_String(elem); + + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + if (force) { + int retval = reg->type->get(reg); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to read register '%s'", + reg_name); + return JIM_ERR; + } + } + + char *reg_value = buf_to_hex_str(reg->value, reg->size); + + if (!reg_value) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + char *tmp = alloc_printf("0x%s", reg_value); + + free(reg_value); + + if (!tmp) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + Jim_DictAddElement(interp, result_dict, elem, + Jim_NewStringObj(interp, tmp, -1)); + + free(tmp); + } + + Jim_SetResult(interp, result_dict); + + return JIM_OK; +} + static int target_jim_set_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { @@ -5696,6 +5783,13 @@ static const struct command_registration target_instance_command_handlers[] = { "from target memory", .usage = "arrayname bitwidth address count", }, + { + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, { .name = "set_reg", .mode = COMMAND_EXEC, @@ -6785,6 +6879,13 @@ static const struct command_registration target_exec_command_handlers[] = { "and write the 8/16/32 bit values", .usage = "arrayname bitwidth address count", }, + { + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, { .name = "set_reg", .mode = COMMAND_EXEC, From 29e2a7451638d5706daf13b12211b49baafa3c42 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 22 Jun 2021 11:47:26 +0200 Subject: [PATCH 048/186] target/arm_tpiu: Make error message easier to understand Change-Id: Idddc31e34a67641c32d041c89d01fe2126ec5ddb Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6328 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_tpiu_swo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 024521364..387ad9e9e 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -886,7 +886,8 @@ static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *o /* does this command exist? */ cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE); if (cmd) { - Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name); + Jim_SetResultFormatted(interp, "cannot create TPIU object because a command with name '%s' already exists", + obj->name); return JIM_ERR; } From 4a4ca07da7b53e589afe2f79d03787d89faf1d33 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 22 Jun 2021 12:59:01 +0200 Subject: [PATCH 049/186] target/arm_tpiu: Fix 'tpiu create' parameter check The current implementation crashes when executing 'tpiu create' without an object name due to an invalid memory access. Pass 'argv' instead 'goi.argv' to fix the problem. While at it, match the style of the error message to the style used for other Tcl commands. Especially, make the 'name' parameter mandatory. Change-Id: Ib2b233f8556934af61608ae93d6405585c2c40b7 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6329 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/target/arm_tpiu_swo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 387ad9e9e..3738a3bf2 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -916,7 +916,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 1) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options..."); + Jim_WrongNumArgs(interp, 1, argv, "name ?option option ...?"); return JIM_ERR; } From 2586fec922ae9ea9bea345f40598e0367934d22c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 26 Feb 2022 14:31:11 +0100 Subject: [PATCH 050/186] target/arm_tpiu: Fix usage of 'tpiu create' Change-Id: I1ffad65a9e6d76f4d7fbbe249d8af3beb7e7692b Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6860 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_tpiu_swo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 3738a3bf2..bfe908142 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -1161,7 +1161,7 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { .name = "create", .mode = COMMAND_ANY, .jim_handler = jim_arm_tpiu_swo_create, - .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]", + .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", .help = "Creates a new TPIU or SWO object", }, { From 57c1e491801c6e67cb8b429bcf5c0ecf1bcef27b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 17:10:12 +0100 Subject: [PATCH 051/186] flash/stm32f1x,f2x: fix endianess in slow fallback flash write Use target_write_memory() instead of target_write_u16() Change-Id: I2389fe7a5fa18c9bc9c1aad8b8ddd64608bf2566 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6705 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- src/flash/nor/stm32f1x.c | 5 +---- src/flash/nor/stm32f2x.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 29a3b7e06..6972bae2d 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -592,10 +592,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - retval = target_write_u16(target, bank->base + offset, value); + retval = target_write_memory(target, bank->base + offset, 2, 1, buffer); if (retval != ERROR_OK) goto reset_pg_and_lock; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 58edca7e1..622ef3423 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -856,15 +856,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, Wait for the BSY bit to be cleared */ while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_16); if (retval != ERROR_OK) return retval; - retval = target_write_u16(target, address, value); + retval = target_write_memory(target, address, 2, 1, buffer + bytes_written); if (retval != ERROR_OK) return retval; From f583f338b086ed3a1cd471e1fd8ef99589a64dae Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 22 Sep 2021 16:15:55 +0100 Subject: [PATCH 052/186] tcl/stm32l5x|u5x: refactor common tcl code both stm32l5x and stm32u5x configs are almost identical except clock config. while at there rename target procs to avoid issues with JTAG daisy chaining. Change-Id: Ibbb1dfeb91a7f8d5d45744cf57dca2877f60e0c5 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6596 Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/target/stm32l5x.cfg | 162 +------------------------------- tcl/target/stm32u5x.cfg | 163 +-------------------------------- tcl/target/stm32x5x_common.cfg | 154 +++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 315 deletions(-) create mode 100644 tcl/target/stm32x5x_common.cfg diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg index 0616df1cb..c43b699d2 100644 --- a/tcl/target/stm32l5x.cfg +++ b/tcl/target/stm32l5x.cfg @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32l5x family +# stm32l5x devices support both JTAG and SWD transports. -# -# stm32l5 devices support both JTAG and SWD transports. -# source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -14,78 +12,10 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32l5x } -set _ENDIAN little +source [find target/stm32x5x_common.cfg] -# Work-area is a space in RAM used for flash programming -# By default use 64kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x10000 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0438 - # RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers - # Corresponds to Cortex®-M33 JTAG debug port ID code - set _CPUTAPID 0x0ba04477 - } { - # SWD IDCODE (single drop, arm) - set _CPUTAPID 0x0be12477 - } -} - -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu - -if {[using_jtag]} { - jtag newtap $_CHIPNAME bs -irlen 5 -} - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap - -# use non-secure RAM by default -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -# create sec/ns flash and otp memories (sizes will be probed) -flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME - -# Common knowledges tells JTAG speed should be <= F_CPU/6. -# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on -# the safe side. -# -# Note that there is a pretty wide band where things are -# more or less stable, see http://openocd.zylin.com/#/c/3366/ -adapter speed 500 - -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -proc is_secure {} { - # read Debug Security Control and Status Regsiter (DSCSR) and check CDS (bit 16) - set DSCSR [mrw 0xE000EE08] - return [expr {($DSCSR & (1 << 16)) != 0}] -} - -proc clock_config_110_mhz {} { - set offset [expr {[is_secure] ? 0x10000000 : 0}] +proc stm32l5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL # RCC_APB1ENR1 = PWREN mww [expr {0x40021058 + $offset}] 0x10000000 @@ -111,90 +41,8 @@ proc clock_config_110_mhz {} { while {([mrw [expr {0x40021008 + $offset}]] & 0x0C) != 0x0C} {} } -proc ahb_ap_non_secure_access {} { - # SPROT=1=Non Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 -} - -proc ahb_ap_secure_access {} { - # SPROT=0=Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 -} - $_TARGETNAME configure -event reset-init { - clock_config_110_mhz + stm32l5x_clock_config # Boost JTAG frequency adapter speed 4000 } - -$_TARGETNAME configure -event reset-start { - # Reset clock is MSI (4 MHz) - adapter speed 480 -} - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP - mmw 0xE0044004 0x00000006 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0044008 0x00001800 0 -} - -$_TARGETNAME configure -event halted { - set secure [is_secure] - - if {$secure} { - set secure_str "Secure" - ahb_ap_secure_access - } else { - set secure_str "Non-Secure" - ahb_ap_non_secure_access - } - - # print the secure state only when it changes - set _TARGETNAME [target current] - global $_TARGETNAME.secure - - if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { - echo "CPU in $secure_str state" - # update saved security state - set $_TARGETNAME.secure $secure - } -} - -$_TARGETNAME configure -event gdb-flash-erase-start { - set use_secure_workarea 0 - # check if FLASH_OPTR.TZEN is enabled - set FLASH_OPTR [mrw 0x40022040] - if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { - echo "TZEN option bit disabled" - ahb_ap_non_secure_access - } { - ahb_ap_secure_access - echo "TZEN option bit enabled" - - # check if FLASH_OPTR.RDP is not Level 0.5 - if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { - set use_secure_workarea 1 - } - } - - set workarea_addr [$_TARGETNAME cget -work-area-phys] - echo "workarea_addr $workarea_addr" - - if {$use_secure_workarea} { - set workarea_addr [expr {$workarea_addr | 0x10000000}] - } { - set workarea_addr [expr {$workarea_addr & ~0x10000000}] - } - - $_TARGETNAME configure -work-area-phys $workarea_addr -} - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0044004 0x00000020 0 -} diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg index 2c2c0e037..b627d4180 100644 --- a/tcl/target/stm32u5x.cfg +++ b/tcl/target/stm32u5x.cfg @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32u5x family +# stm32u5x devices support both JTAG and SWD transports. -# -# stm32u5 devices support both JTAG and SWD transports. -# source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -14,78 +12,10 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32u5x } -set _ENDIAN little +source [find target/stm32x5x_common.cfg] -# Work-area is a space in RAM used for flash programming -# By default use 64kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x10000 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0438 - # RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers - # Corresponds to Cortex®-M33 JTAG debug port ID code - set _CPUTAPID 0x0ba04477 - } { - # SWD IDCODE (single drop, arm) - set _CPUTAPID 0x0be12477 - } -} - -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu - -if {[using_jtag]} { - jtag newtap $_CHIPNAME bs -irlen 5 -} - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap - -# use non-secure RAM by default -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -# create sec/ns flash and otp memories (sizes will be probed) -flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME - -# Common knowledges tells JTAG speed should be <= F_CPU/6. -# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on -# the safe side. -# -# Note that there is a pretty wide band where things are -# more or less stable, see http://openocd.zylin.com/#/c/3366/ -adapter speed 500 - -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -proc is_secure {} { - # read Debug Security Control and Status Regsiter (DSCSR) and check CDS (bit 16) - set DSCSR [mrw 0xE000EE08] - return [expr {($DSCSR & (1 << 16)) != 0}] -} - -proc clock_config_160_mhz {} { - set offset [expr {[is_secure] ? 0x10000000 : 0}] +proc stm32u5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is at MSI 4MHz after reset, set MCU freq at 160 MHz with PLL # Enable voltage range 1 for frequency above 100 Mhz @@ -117,91 +47,8 @@ proc clock_config_160_mhz {} { while {([mrw [expr {0x46020C1C + $offset}]] & 0x0C) != 0x0C} {} } -proc ahb_ap_non_secure_access {} { - # SPROT=1=Non Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 -} - -proc ahb_ap_secure_access {} { - # SPROT=0=Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 -} - $_TARGETNAME configure -event reset-init { - clock_config_160_mhz + stm32u5x_clock_config # Boost JTAG frequency adapter speed 4000 } - -$_TARGETNAME configure -event reset-start { - # Reset clock is MSI (4 MHz) - adapter speed 480 -} - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP - mmw 0xE0044004 0x00000006 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0044008 0x00001800 0 -} - -$_TARGETNAME configure -event halted { - set secure [is_secure] - - if {$secure} { - set secure_str "Secure" - ahb_ap_secure_access - } else { - set secure_str "Non-Secure" - ahb_ap_non_secure_access - } - - # print the secure state only when it changes - set _TARGETNAME [target current] - global $_TARGETNAME.secure - - if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { - echo "CPU in $secure_str state" - # update saved security state - set $_TARGETNAME.secure $secure - } -} - -$_TARGETNAME configure -event gdb-flash-erase-start { - set use_secure_workarea 0 - # check if FLASH_OPTR.TZEN is enabled - set FLASH_OPTR [mrw 0x40022040] - if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { - echo "TZEN option bit disabled" - ahb_ap_non_secure_access - } else { - ahb_ap_secure_access - echo "TZEN option bit enabled" - - # check if FLASH_OPTR.RDP is not Level 0.5 - if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { - set use_secure_workarea 1 - } - } - - set _TARGETNAME [target current] - set workarea_addr [$_TARGETNAME cget -work-area-phys] - echo "workarea_addr $workarea_addr" - - if {$use_secure_workarea} { - set workarea_addr [expr {$workarea_addr | 0x10000000}] - } else { - set workarea_addr [expr {$workarea_addr & ~0x10000000}] - } - - $_TARGETNAME configure -work-area-phys $workarea_addr -} - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0044004 0x00000020 0 -} diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg new file mode 100644 index 000000000..276d0cca0 --- /dev/null +++ b/tcl/target/stm32x5x_common.cfg @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# common script for stm32l5x and stm32u5x families + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers + # Corresponds to Cortex®-M33 JTAG debug port ID code + set _CPUTAPID 0x0ba04477 + } { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0be12477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +# use non-secure RAM by default +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# create sec/ns flash and otp memories (sizes will be probed) +flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME + +# Common knowledge tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://review.openocd.org/3366 +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc stm32x5x_is_secure {} { + # read Debug Security Control and Status Register (DSCSR) and check CDS (bit 16) + set DSCSR [mrw 0xE000EE08] + return [expr {($DSCSR & (1 << 16)) != 0}] +} + +proc stm32x5x_ahb_ap_non_secure_access {} { + # SPROT=1=Non Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 +} + +proc stm32x5x_ahb_ap_secure_access {} { + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 480 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 0x00001800 0 +} + +$_TARGETNAME configure -event halted { + set secure [stm32x5x_is_secure] + + if {$secure} { + set secure_str "Secure" + stm32x5x_ahb_ap_secure_access + } else { + set secure_str "Non-Secure" + stm32x5x_ahb_ap_non_secure_access + } + + # print the secure state only when it changes + set _TARGETNAME [target current] + global $_TARGETNAME.secure + + if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { + echo "CPU in $secure_str state" + # update saved security state + set $_TARGETNAME.secure $secure + } +} + +$_TARGETNAME configure -event gdb-flash-erase-start { + set use_secure_workarea 0 + # check if FLASH_OPTR.TZEN is enabled + set FLASH_OPTR [mrw 0x40022040] + if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { + echo "TZEN option bit disabled" + stm32x5x_ahb_ap_non_secure_access + } else { + stm32x5x_ahb_ap_secure_access + echo "TZEN option bit enabled" + + # check if FLASH_OPTR.RDP is not Level 0.5 + if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { + set use_secure_workarea 1 + } + } + + set _TARGETNAME [target current] + set workarea_addr [$_TARGETNAME cget -work-area-phys] + echo "workarea_addr $workarea_addr" + + if {$use_secure_workarea} { + set workarea_addr [expr {$workarea_addr | 0x10000000}] + } else { + set workarea_addr [expr {$workarea_addr & ~0x10000000}] + } + + $_TARGETNAME configure -work-area-phys $workarea_addr +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0044004 0x00000020 0 +} From 4906176c77d70e89a7e1f7da54e4088c5966207f Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Fri, 25 Feb 2022 17:05:03 +0100 Subject: [PATCH 053/186] cortex_m: use LOG_TARGET_XXX Change-Id: I8be0f67442644031e6e8df3090d81af195caf82b Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6672 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 210 +++++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 106 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 7125e9e83..108f7e790 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -185,7 +185,7 @@ static int cortex_m_load_core_reg_u32(struct target *target, break; cortex_m->slow_register_read = true; /* Polling (still) needed. */ if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { - LOG_ERROR("Timeout waiting for DCRDR transfer ready"); + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); @@ -223,7 +223,7 @@ static int cortex_m_slow_read_all_regs(struct target *target) } if (!cortex_m->slow_register_read) - LOG_DEBUG("Switching back to fast register reads"); + LOG_TARGET_DEBUG(target, "Switching back to fast register reads"); return ERROR_OK; } @@ -319,7 +319,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) for (unsigned int i = 0; i < wi; i++) { if ((dhcsr[i] & S_REGRDY) == 0) { not_ready = true; - LOG_DEBUG("Register %u was not ready during fast read", i); + LOG_TARGET_DEBUG(target, "Register %u was not ready during fast read", i); } cortex_m_cumulate_dhcsr_sticky(cortex_m, dhcsr[i]); } @@ -330,7 +330,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) return ERROR_TIMEOUT_REACHED; } - LOG_DEBUG("read %u 32-bit registers", wi); + LOG_TARGET_DEBUG(target, "read %u 32-bit registers", wi); unsigned int ri = 0; /* read index from r_vals array */ for (reg_id = 0; reg_id < num_regs; reg_id++) { @@ -403,7 +403,7 @@ static int cortex_m_store_core_reg_u32(struct target *target, if (cortex_m->dcb_dhcsr & S_REGRDY) break; if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { - LOG_ERROR("Timeout waiting for DCRDR transfer ready"); + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); @@ -528,7 +528,7 @@ static int cortex_m_clear_halt(struct target *target) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); return ERROR_OK; } @@ -550,7 +550,7 @@ static int cortex_m_single_step_core(struct target *target) retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, "single step"); /* restore dhcsr reg */ cortex_m_clear_halt(target); @@ -590,7 +590,7 @@ static int cortex_m_endreset_event(struct target *target) retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; - LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); + LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); @@ -629,7 +629,7 @@ static int cortex_m_endreset_event(struct target *target) /* Enable FPB */ retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } @@ -766,7 +766,7 @@ static int cortex_m_examine_exception_reason(struct target *target) } retval = dap_run(swjdp); if (retval == ERROR_OK) - LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, armv7m_exception_string(armv7m->exception_number), shcsr, except_sr, cfsr, except_ar); @@ -782,7 +782,7 @@ static int cortex_m_debug_entry(struct target *target) struct arm *arm = &armv7m->arm; struct reg *r; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, " "); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ @@ -815,7 +815,7 @@ static int cortex_m_debug_entry(struct target *target) retval = cortex_m_fast_read_all_regs(target); if (retval == ERROR_TIMEOUT_REACHED) { cortex_m->slow_register_read = true; - LOG_DEBUG("Switched to slow register read"); + LOG_TARGET_DEBUG(target, "Switched to slow register read"); } } @@ -855,7 +855,8 @@ static int cortex_m_debug_entry(struct target *target) if (armv7m->exception_number) cortex_m_examine_exception_reason(target); - LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", + LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32 + ", cpu in %s state, target->state: %s", arm_mode_name(arm->core_mode), buf_get_u32(arm->pc->value, 0, 32), secure_state ? "Secure" : "Non-Secure", @@ -889,8 +890,7 @@ static int cortex_m_poll(struct target *target) * section B1.5.15 "Unrecoverable exception cases". */ if (cortex_m->dcb_dhcsr & S_LOCKUP) { - LOG_ERROR("%s -- clearing lockup after double fault", - target_name(target)); + LOG_TARGET_ERROR(target, "clearing lockup after double fault"); cortex_m_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; @@ -909,7 +909,7 @@ static int cortex_m_poll(struct target *target) cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; if (target->state != TARGET_RESET) { target->state = TARGET_RESET; - LOG_INFO("%s: external reset detected", target_name(target)); + LOG_TARGET_INFO(target, "external reset detected"); } return ERROR_OK; } @@ -918,7 +918,7 @@ static int cortex_m_poll(struct target *target) /* Cannot switch context while running so endreset is * called with target->state == TARGET_RESET */ - LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Exit from reset with dcb_dhcsr 0x%" PRIx32, cortex_m->dcb_dhcsr); retval = cortex_m_endreset_event(target); if (retval != ERROR_OK) { @@ -943,7 +943,6 @@ static int cortex_m_poll(struct target *target) target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) { - LOG_DEBUG(" "); retval = cortex_m_debug_entry(target); if (retval != ERROR_OK) return retval; @@ -971,7 +970,7 @@ static int cortex_m_poll(struct target *target) register_cache_invalidate(armv7m->arm.core_cache); target->state = TARGET_RUNNING; - LOG_WARNING("%s: external resume detected", target_name(target)); + LOG_TARGET_WARNING(target, "external resume detected"); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); retval = ERROR_OK; } @@ -984,20 +983,19 @@ static int cortex_m_poll(struct target *target) static int cortex_m_halt(struct target *target) { - LOG_DEBUG("target->state: %s", - target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { - LOG_DEBUG("target was already halted"); + LOG_TARGET_DEBUG(target, "target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) - LOG_WARNING("target was in unknown state when halt was requested"); + LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { - LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); + LOG_TARGET_ERROR(target, "can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence @@ -1031,10 +1029,10 @@ static int cortex_m_soft_reset_halt(struct target *target) * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); + LOG_TARGET_DEBUG(target, "soft_reset_halt is discouraged, please use 'reset halt' instead."); if (!cortex_m->vectreset_supported) { - LOG_ERROR("VECTRESET is not supported on this Cortex-M core"); + LOG_TARGET_ERROR(target, "VECTRESET is not supported on this Cortex-M core"); return ERROR_FAIL; } @@ -1068,15 +1066,16 @@ static int cortex_m_soft_reset_halt(struct target *target) return retval; if ((cortex_m->dcb_dhcsr & S_HALT) && (cortex_m->nvic_dfsr & DFSR_VCATCH)) { - LOG_DEBUG("system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, - cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, + cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); cortex_m_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; - } else - LOG_DEBUG("waiting for system reset-halt, " + } else { + LOG_TARGET_DEBUG(target, "waiting for system reset-halt, " "DHCSR 0x%08" PRIx32 ", %d ms", cortex_m->dcb_dhcsr, timeout); + } } timeout++; alive_sleep(1); @@ -1106,7 +1105,7 @@ static int cortex_m_resume(struct target *target, int current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1170,7 +1169,7 @@ static int cortex_m_resume(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", + LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); cortex_m_unset_breakpoint(target, breakpoint); @@ -1191,11 +1190,11 @@ static int cortex_m_resume(struct target *target, int current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + LOG_TARGET_DEBUG(target, "target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + LOG_TARGET_DEBUG(target, "target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; @@ -1214,7 +1213,7 @@ static int cortex_m_step(struct target *target, int current, bool isr_timed_out = false; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1287,7 +1286,7 @@ static int cortex_m_step(struct target *target, int current, * */ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) { - LOG_DEBUG("Stepping over next instruction with interrupts disabled"); + LOG_TARGET_DEBUG(target, "Stepping over next instruction with interrupts disabled"); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ @@ -1318,7 +1317,7 @@ static int cortex_m_step(struct target *target, int current, cortex_m_set_maskints_for_halt(target); } else { /* Start the core */ - LOG_DEBUG("Starting core to serve pending interrupts"); + LOG_TARGET_DEBUG(target, "Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP); @@ -1342,7 +1341,7 @@ static int cortex_m_step(struct target *target, int current, } if (isr_timed_out) { - LOG_DEBUG("Interrupt handlers didn't complete within time, " + LOG_TARGET_DEBUG(target, "Interrupt handlers didn't complete within time, " "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ @@ -1377,7 +1376,7 @@ static int cortex_m_step(struct target *target, int current, return ERROR_OK; } - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1386,7 +1385,7 @@ static int cortex_m_step(struct target *target, int current, return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1399,7 +1398,7 @@ static int cortex_m_assert_reset(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config; - LOG_DEBUG("target->state: %s", + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); @@ -1423,10 +1422,10 @@ static int cortex_m_assert_reset(struct target *target) if (jtag_reset_config & RESET_HAS_SRST) { adapter_assert_reset(); if (target->reset_halt) - LOG_ERROR("Target not examined, will not halt after reset!"); + LOG_TARGET_ERROR(target, "Target not examined, will not halt after reset!"); return ERROR_OK; } else { - LOG_ERROR("Target not examined, reset NOT asserted!"); + LOG_TARGET_ERROR(target, "Target not examined, reset NOT asserted!"); return ERROR_FAIL; } } @@ -1473,7 +1472,7 @@ static int cortex_m_assert_reset(struct target *target) retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK || retval2 != ERROR_OK) - LOG_INFO("AP write error, reset will not halt"); + LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } if (jtag_reset_config & RESET_HAS_SRST) { @@ -1493,15 +1492,15 @@ static int cortex_m_assert_reset(struct target *target) if (!cortex_m->vectreset_supported && reset_config == CORTEX_M_RESET_VECTRESET) { reset_config = CORTEX_M_RESET_SYSRESETREQ; - LOG_WARNING("VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); - LOG_WARNING("Set 'cortex_m reset_config sysresetreq'."); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); + LOG_TARGET_WARNING(target, "Set 'cortex_m reset_config sysresetreq'."); } - LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) + LOG_TARGET_DEBUG(target, "Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); if (reset_config == CORTEX_M_RESET_VECTRESET) { - LOG_WARNING("Only resetting the Cortex-M core, use a reset-init event " + LOG_TARGET_WARNING(target, "Only resetting the Cortex-M core, use a reset-init event " "handler to reset any peripherals or configure hardware srst support."); } @@ -1510,11 +1509,11 @@ static int cortex_m_assert_reset(struct target *target) AIRCR_VECTKEY | ((reset_config == CORTEX_M_RESET_SYSRESETREQ) ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET)); if (retval3 != ERROR_OK) - LOG_DEBUG("Ignoring AP write error right after reset"); + LOG_TARGET_DEBUG(target, "Ignoring AP write error right after reset"); retval3 = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval3 != ERROR_OK) { - LOG_ERROR("DP initialisation failed"); + LOG_TARGET_ERROR(target, "DP initialisation failed"); /* The error return value must not be propagated in this case. * SYSRESETREQ or VECTRESET have been possibly triggered * so reset processing should continue */ @@ -1550,7 +1549,7 @@ static int cortex_m_deassert_reset(struct target *target) { struct armv7m_common *armv7m = &target_to_cm(target)->armv7m; - LOG_DEBUG("target->state: %s", + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); /* deassert reset lines */ @@ -1564,7 +1563,7 @@ static int cortex_m_deassert_reset(struct target *target) int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval != ERROR_OK) { - LOG_ERROR("DP initialisation failed"); + LOG_TARGET_ERROR(target, "DP initialisation failed"); return retval; } } @@ -1580,7 +1579,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (breakpoint->set) { - LOG_WARNING("breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); + LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } @@ -1589,35 +1588,36 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) fp_num++; if (fp_num >= cortex_m->fp_num_code) { - LOG_ERROR("Can not find free FPB Comparator!"); + LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = fp_num + 1; fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { - LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE"); + LOG_TARGET_ERROR(target, "Cortex-M Flash Patch Breakpoint rev.1 " + "cannot handle HW breakpoint above address 0x1FFFFFFE"); return ERROR_FAIL; } uint32_t hilo; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1; } else if (cortex_m->fp_rev > 1) { - LOG_ERROR("Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); + LOG_TARGET_ERROR(target, "Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); return ERROR_FAIL; } comparator_list[fp_num].used = true; comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); - LOG_DEBUG("fpc_num %i fpcr_value 0x%" PRIx32 "", + LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m->fpb_enabled) { - LOG_DEBUG("FPB wasn't enabled, do it now"); + LOG_TARGET_DEBUG(target, "FPB wasn't enabled, do it now"); retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } @@ -1646,7 +1646,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->set = true; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1663,11 +1663,11 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (breakpoint->set <= 0) { - LOG_WARNING("breakpoint not set"); + LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1677,7 +1677,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi if (breakpoint->type == BKPT_HARD) { unsigned int fp_num = breakpoint->set - 1; if (fp_num >= cortex_m->fp_num_code) { - LOG_DEBUG("Invalid FP Comparator number in breakpoint"); + LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; } comparator_list[fp_num].used = false; @@ -1700,12 +1700,12 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->length == 3) { - LOG_DEBUG("Using a two byte breakpoint for 32bit Thumb-2 request"); + LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; } if ((breakpoint->length != 2)) { - LOG_INFO("only breakpoints of two bytes length supported"); + LOG_TARGET_INFO(target, "only breakpoints of two bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1737,7 +1737,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat comparator++, dwt_num++) continue; if (dwt_num >= cortex_m->dwt_num_comp) { - LOG_ERROR("Can not find free DWT Comparator"); + LOG_TARGET_ERROR(target, "Can not find free DWT Comparator"); return ERROR_FAIL; } comparator->used = true; @@ -1795,7 +1795,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - LOG_DEBUG("Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", watchpoint->unique_id, dwt_num, (unsigned) comparator->comp, (unsigned) comparator->mask, @@ -1809,19 +1809,19 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w struct cortex_m_dwt_comparator *comparator; if (watchpoint->set <= 0) { - LOG_WARNING("watchpoint (wpid: %d) not set", + LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } unsigned int dwt_num = watchpoint->set - 1; - LOG_DEBUG("Watchpoint (ID %d) DWT%d address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); if (dwt_num >= cortex_m->dwt_num_comp) { - LOG_DEBUG("Invalid DWT Comparator number in watchpoint"); + LOG_TARGET_DEBUG(target, "Invalid DWT Comparator number in watchpoint"); return ERROR_OK; } @@ -1841,13 +1841,13 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint struct cortex_m_common *cortex_m = target_to_cm(target); if (cortex_m->dwt_comp_available < 1) { - LOG_DEBUG("no comparators?"); + LOG_TARGET_DEBUG(target, "no comparators?"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware doesn't support data value masking */ if (watchpoint->mask != ~(uint32_t)0) { - LOG_DEBUG("watchpoint value masks not supported"); + LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1859,11 +1859,11 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint break; } if (mask == 16) { - LOG_DEBUG("unsupported watchpoint length"); + LOG_TARGET_DEBUG(target, "unsupported watchpoint length"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->address & ((1 << mask) - 1)) { - LOG_DEBUG("watchpoint address is unaligned"); + LOG_TARGET_DEBUG(target, "watchpoint address is unaligned"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1875,12 +1875,12 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint * the data, and another comparator (DATAVADDR0) matching addr. */ if (watchpoint->value) { - LOG_DEBUG("data value watchpoint not YET supported"); + LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cortex_m->dwt_comp_available--; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } @@ -1891,7 +1891,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_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1899,7 +1899,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } @@ -2004,18 +2004,18 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, retval = target_read_u32(target, DWT_PCSR, ®_value); if (retval != ERROR_OK) { - LOG_ERROR("Error while reading PCSR"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } if (reg_value == 0) { - LOG_INFO("PCSR sampling not supported on this processor."); + LOG_TARGET_INFO(target, "PCSR sampling not supported on this processor."); return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); - LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); + LOG_TARGET_INFO(target, "Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); /* Make sure the target is running */ target_poll(target); @@ -2023,7 +2023,7 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { - LOG_ERROR("Error while resuming target"); + LOG_TARGET_ERROR(target, "Error while resuming target"); return retval; } @@ -2044,14 +2044,14 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, } if (retval != ERROR_OK) { - LOG_ERROR("Error while reading PCSR"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } gettimeofday(&now, NULL); if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { - LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); + LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } } @@ -2162,14 +2162,14 @@ static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target int reg; target_read_u32(target, DWT_CTRL, &dwtcr); - LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr); + LOG_TARGET_DEBUG(target, "DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { - LOG_DEBUG("no DWT"); + LOG_TARGET_DEBUG(target, "no DWT"); return; } target_read_u32(target, DWT_DEVARCH, &cm->dwt_devarch); - LOG_DEBUG("DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); + LOG_TARGET_DEBUG(target, "DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); cm->dwt_num_comp = (dwtcr >> 28) & 0xF; cm->dwt_comp_available = cm->dwt_num_comp; @@ -2178,7 +2178,7 @@ static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target if (!cm->dwt_comparator_list) { fail0: cm->dwt_num_comp = 0; - LOG_ERROR("out of mem"); + LOG_TARGET_ERROR(target, "out of mem"); return; } @@ -2216,7 +2216,7 @@ static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target *register_get_last_cache_p(&target->reg_cache) = cache; cm->dwt_cache = cache; - LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", + LOG_TARGET_DEBUG(target, "DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", dwtcr, cm->dwt_num_comp, (dwtcr & (0xf << 24)) ? " only" : "/trigger"); @@ -2283,7 +2283,7 @@ int cortex_m_examine(struct target *target) /* Search for the MEM-AP */ retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); if (retval != ERROR_OK) { - LOG_ERROR("Could not find MEM-AP to control the core"); + LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core"); return retval; } } else { @@ -2316,14 +2316,13 @@ int cortex_m_examine(struct target *target) } if (!cortex_m->core_info) { - LOG_ERROR("Cortex-M PARTNO 0x%x is unrecognized", core_partno); + LOG_TARGET_ERROR(target, "Cortex-M PARTNO 0x%x is unrecognized", core_partno); return ERROR_FAIL; } armv7m->arm.arch = cortex_m->core_info->arch; - LOG_INFO("%s: %s r%" PRId8 "p%" PRId8 " processor detected", - target_name(target), + LOG_TARGET_INFO(target, "%s r%" PRId8 "p%" PRId8 " processor detected", cortex_m->core_info->name, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); @@ -2334,11 +2333,11 @@ int cortex_m_examine(struct target *target) rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { - LOG_WARNING("Silicon bug: single stepping may enter pending exception handler!"); + LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } } - LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); + LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { target_read_u32(target, MVFR0, &mvfr0); @@ -2346,7 +2345,7 @@ int cortex_m_examine(struct target *target) /* test for floating point feature on Cortex-M4 */ if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) { - LOG_DEBUG("%s floating point feature FPv4_SP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv4_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV4_SP; } } else if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV5) { @@ -2355,10 +2354,10 @@ int cortex_m_examine(struct target *target) /* test for floating point features on Cortex-M7 */ if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) { - LOG_DEBUG("%s floating point feature FPv5_SP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_SP; } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) { - LOG_DEBUG("%s floating point feature FPv5_DP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_DP; } } @@ -2428,7 +2427,7 @@ int cortex_m_examine(struct target *target) /* make sure we clear any breakpoints enabled on the target */ target_write_u32(target, cortex_m->fp_comparator_list[i].fpcr_address, 0); } - LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", + LOG_TARGET_DEBUG(target, "FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m->fp_num_code, cortex_m->fp_num_lit); @@ -2438,8 +2437,7 @@ int cortex_m_examine(struct target *target) cortex_m_dwt_setup(cortex_m, target); /* These hardware breakpoints only work for code in flash! */ - LOG_INFO("%s: target has %d breakpoints, %d watchpoints", - target_name(target), + LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints", cortex_m->fp_num_code, cortex_m->dwt_num_comp); } @@ -2462,7 +2460,7 @@ static int cortex_m_dcc_read(struct target *target, uint8_t *value, uint8_t *ctr *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); - LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl); + LOG_TARGET_DEBUG(target, "data 0x%x ctrl 0x%x", *value, *ctrl); /* write ack back to software dcc register * signify we have read data */ @@ -2569,7 +2567,7 @@ static int cortex_m_target_create(struct target *target, Jim_Interp *interp) struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); if (!cortex_m) { - LOG_ERROR("No memory creating target"); + LOG_TARGET_ERROR(target, "No memory creating target"); return ERROR_FAIL; } @@ -2626,7 +2624,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) return retval; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "Target not examined yet"); return ERROR_FAIL; } @@ -2655,7 +2653,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) break; } if (i == ARRAY_SIZE(vec_ids)) { - LOG_ERROR("No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); + LOG_TARGET_ERROR(target, "No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -2745,7 +2743,7 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) else if (strcmp(*CMD_ARGV, "vectreset") == 0) { if (target_was_examined(target) && !cortex_m->vectreset_supported) - LOG_WARNING("VECTRESET is not supported on your Cortex-M core!"); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); else cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; From 2b17a128841c9431f17aaad844f416eccd24f63f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 08:34:42 -0500 Subject: [PATCH 054/186] tcl/target/ti_k3: Remove args from m3 and m4_up args serve no purpose, so drop them. Signed-off-by: Nishanth Menon Change-Id: I136394307016453d576cf524b0f02227ba26ef8a Reviewed-on: https://review.openocd.org/c/openocd/+/6626 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index d2aa53160..325ee0004 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -152,7 +152,7 @@ cti create $_CTINAME.m3 -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTI target create $_TARGETNAME.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine $_TARGETNAME.m3 configure -event reset-assert { } -proc m3_up { args } { +proc m3_up {} { # To access M3, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 0] 0x00190000 @@ -245,7 +245,7 @@ if { $_mcu_m4_cores != 0 } { target create $_TARGETNAME.m4 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine $_TARGETNAME.m4 configure -event reset-assert { } - proc m4_up { args } { + proc m4_up {} { # To access M4, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 0] 0x00190000 From c280c9835705a7d104996569068826a73b665010 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 22:48:34 -0500 Subject: [PATCH 055/186] tcl/target/ti_k3: Add a gdb-attach event hook for m3 and m4 Add gdb-attach event to call the "up" function of m3 and m4 allowing for more seamless integration with gdb for end users. We still retain _up functions for non-gdb functionality. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior Suggested-by: Antonio Borneo Signed-off-by: Nishanth Menon Change-Id: I2e51fdbd8756f156551e589c748c3a338afa655c Reviewed-on: https://review.openocd.org/c/openocd/+/6615 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 325ee0004..8fb71482c 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -161,6 +161,12 @@ proc m3_up {} { $::_TARGETNAME.m3 arp_examine } +$_TARGETNAME.m3 configure -event gdb-attach { + m3_up + # gdb-attach default rule + halt 1000 +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -253,4 +259,10 @@ if { $_mcu_m4_cores != 0 } { $::_TARGETNAME.m4 arp_examine } + + $_TARGETNAME.m4 configure -event gdb-attach { + m4_up + # gdb-attach default rule + halt 1000 + } } From 77b02b89ae689867bb38e11d3fa6ff59c8d22357 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 23:02:23 -0500 Subject: [PATCH 056/186] tcl/target/ti_k3: Rename m3 target as sysctrl The M3 is the system controller of the system. Lets rename it to make clear what we are debugging - esp when multiple MCUs are present in the system. Signed-off-by: Nishanth Menon Change-Id: I4cd03b6068b8ce140fd254f9dd88151c4c7006d7 Reviewed-on: https://review.openocd.org/c/openocd/+/6618 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 8fb71482c..ee4a5c8b3 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -27,11 +27,11 @@ if { [info exists V8_SMP_DEBUG] } { # Common Definitions -# CM3 the very first processor - all current SoCs have it. +# System Controller is the very first processor - all current SoCs have it. set CM3_CTIBASE {0x3C016000} -# M3 power-ap unlock offsets -set _m3_ap_unlock_offsets {0xf0 0x44} +# sysctrl power-ap unlock offsets +set _sysctrl_ap_unlock_offsets {0xf0 0x44} # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 @@ -70,8 +70,8 @@ switch $_soc { set _main1_r5_cores 0 set _main1_base_core_id 0 - # M3 power-ap unlock offsets - set _m3_ap_unlock_offsets {0xf0 0x50} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x50} } am642 { set _CHIPNAME am642 @@ -147,22 +147,22 @@ set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti -# M3 is always present -cti create $_CTINAME.m3 -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] -target create $_TARGETNAME.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine -$_TARGETNAME.m3 configure -event reset-assert { } +# sysctrl is always present +cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] +target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine +$_TARGETNAME.sysctrl configure -event reset-assert { } -proc m3_up {} { - # To access M3, we need to enable the JTAG access for the same. +proc sysctrl_up {} { + # To access sysctrl, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked - $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 0] 0x00190000 - $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 1] 0x00102098 + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 1] 0x00102098 - $::_TARGETNAME.m3 arp_examine + $::_TARGETNAME.sysctrl arp_examine } -$_TARGETNAME.m3 configure -event gdb-attach { - m3_up +$_TARGETNAME.sysctrl configure -event gdb-attach { + sysctrl_up # gdb-attach default rule halt 1000 } From 4ddca7dd7186a908397570a25f7ad7454bab3a20 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 23:18:09 -0500 Subject: [PATCH 057/186] tcl/target/ti_k3: Rename m4 target as general purpose mcu The MCU is present on few of the SoCs and is meant as General Purpose (GP) MCU of the system. Lets rename it to make clear what we are debugging - esp when multiple MCUs are present in the system. Signed-off-by: Nishanth Menon Change-Id: I16132d321daf6e9b1d893fe6f92026d5aa9eb152 Reviewed-on: https://review.openocd.org/c/openocd/+/6619 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index ee4a5c8b3..e397d2255 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -43,13 +43,13 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} -# Finally an M4F +# Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} -# M4 may be present on some very few SoCs -set _mcu_m4_cores 0 -# M4 power-ap unlock offsets -set _m4_ap_unlock_offsets {0xf0 0x60} +# General Purpose MCU (M4) may be present on some very few SoCs +set _gp_mcu_cores 0 +# General Purpose MCU power-ap unlock offsets +set _gp_mcu_ap_unlock_offsets {0xf0 0x60} # Set configuration overrides for each SOC switch $_soc { @@ -95,7 +95,7 @@ switch $_soc { set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} # M4 processor - set _mcu_m4_cores 1 + set _gp_mcu_cores 1 } j721e { set _CHIPNAME j721e @@ -246,22 +246,22 @@ if { $_main1_r5_cores != 0 } { } } -if { $_mcu_m4_cores != 0 } { - cti create $_CTINAME.m4 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] - target create $_TARGETNAME.m4 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine - $_TARGETNAME.m4 configure -event reset-assert { } +if { $_gp_mcu_cores != 0 } { + cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] + target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + $_TARGETNAME.gp_mcu configure -event reset-assert { } - proc m4_up {} { - # To access M4, we need to enable the JTAG access for the same. + proc gp_mcu_up {} { + # To access GP MCU, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked - $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 0] 0x00190000 - $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 1] 0x00102098 + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 1] 0x00102098 - $::_TARGETNAME.m4 arp_examine + $::_TARGETNAME.gp_mcu arp_examine } - $_TARGETNAME.m4 configure -event gdb-attach { - m4_up + $_TARGETNAME.gp_mcu configure -event gdb-attach { + gp_mcu_up # gdb-attach default rule halt 1000 } From 4b12c9e8c507a1ba748de32c9ab9f3e7654c22b4 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 09:03:49 -0500 Subject: [PATCH 058/186] tcl/target/ti_k3: Rename R5 targets to be more descriptive R5 targets are currently named r5.0..n and the only way for user to determine the actual type is external documentation. Lets just rename the target names to make them descriptive to not require external documentation for finding which R5 to connect to. NOTE: we leave the _mcu_r5_cores _main0_r5_cores _main1_r5_cores alone for now to allow existing startup proc functions to work, but we will drop it in the follow on patch. Previously: Info : starting gdb server for j721e.cpu.r5.0 on 3336 Info : Listening on port 3336 for gdb connections Info : starting gdb server for j721e.cpu.r5.1 on 3337 Info : Listening on port 3337 for gdb connections Info : starting gdb server for j721e.cpu.r5.2 on 3338 Info : Listening on port 3338 for gdb connections Info : starting gdb server for j721e.cpu.r5.3 on 3339 Info : Listening on port 3339 for gdb connections Info : starting gdb server for j721e.cpu.r5.4 on 3340 Info : Listening on port 3340 for gdb connections Info : starting gdb server for j721e.cpu.r5.5 on 3341 Info : Listening on port 3341 for gdb connections With this patch: Info : starting gdb server for j721e.cpu.mcu_r5.0 on 3336 Info : Listening on port 3336 for gdb connections Info : starting gdb server for j721e.cpu.mcu_r5.1 on 3337 Info : Listening on port 3337 for gdb connections Info : starting gdb server for j721e.cpu.main0_r5.0 on 3338 Info : Listening on port 3338 for gdb connections Info : starting gdb server for j721e.cpu.main0_r5.1 on 3339 Info : Listening on port 3339 for gdb connections Info : starting gdb server for j721e.cpu.main1_r5.0 on 3340 Info : Listening on port 3340 for gdb connections Info : starting gdb server for j721e.cpu.main1_r5.1 on 3341 Info : Listening on port 3341 for gdb connections Signed-off-by: Nishanth Menon Change-Id: I2989efe3ae3e16754f98fa1dc9363ec4c898f7c3 Reviewed-on: https://review.openocd.org/c/openocd/+/6627 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index e397d2255..6c2c2e1da 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -42,6 +42,7 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} # (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} +set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} @@ -64,11 +65,9 @@ switch $_soc { # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 0 - set _main0_base_core_id 0 set _main1_r5_cores 0 - set _main1_base_core_id 0 + set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} @@ -86,11 +85,9 @@ switch $_soc { # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 set _mcu_r5_cores 0 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 0 set _main1_r5_cores 2 - set _main1_base_core_id 2 + set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} @@ -107,11 +104,8 @@ switch $_soc { # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 2 set _main1_r5_cores 2 - set _main1_base_core_id 4 } j7200 { set _CHIPNAME j7200 @@ -124,11 +118,8 @@ switch $_soc { # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 2 set _main1_r5_cores 0 - set _main1_base_core_id 0 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} @@ -208,20 +199,20 @@ if { $_v8_smp_debug == 0 } { } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { - cti create $_CTINAME.r5.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + set _r5_name [lindex $R5_NAMES $_core] + cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core - target create $_TARGETNAME.r5.$_core cortex_r4 -dap $_CHIPNAME.dap \ + target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine } if { $_mcu_r5_cores != 0 } { proc mcu_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_mcu_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.mcu_r5.$_core arp_examine + $::_TARGETNAME.mcu_r5.$_core cortex_r4 dbginit } } } @@ -229,9 +220,8 @@ if { $_mcu_r5_cores != 0 } { if { $_main0_r5_cores != 0 } { proc main0_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_main0_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.main0_r5.$_core arp_examine + $::_TARGETNAME.main0_r5.$_core cortex_r4 dbginit } } } @@ -239,9 +229,8 @@ if { $_main0_r5_cores != 0 } { if { $_main1_r5_cores != 0 } { proc main1_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_main1_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.main1_r5.$_core arp_examine + $::_TARGETNAME.main1_r5.$_core cortex_r4 dbginit } } } From 3ba2b515b528094b43d5be5056b9e52f1dc33969 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 09:20:34 -0500 Subject: [PATCH 059/186] tcl/target/ti_k3: Add a gdb-attach event hook for r5 and simplify startup function Since we can detect the type of target as well, make the attach function name generic for the follow on cleanup patch on armv8 to use as well. Lets introduce gdb-attach event in a much cleaner fashion. We can introduce a simpler r5_up function since we now have more descriptive core names making the individual descriptive procs redundant. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior Signed-off-by: Nishanth Menon Change-Id: I31506bb2b86e63638082640eb72aa7c4c9575e93 Reviewed-on: https://review.openocd.org/c/openocd/+/6617 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 50 ++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 6c2c2e1da..883197b14 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -64,9 +64,6 @@ switch $_soc { # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 - set _mcu_r5_cores 2 - set _main0_r5_cores 0 - set _main1_r5_cores 0 set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets @@ -84,9 +81,6 @@ switch $_soc { # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 - set _mcu_r5_cores 0 - set _main0_r5_cores 2 - set _main1_r5_cores 2 set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} @@ -103,9 +97,6 @@ switch $_soc { # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 - set _mcu_r5_cores 2 - set _main0_r5_cores 2 - set _main1_r5_cores 2 } j7200 { set _CHIPNAME j7200 @@ -117,9 +108,6 @@ switch $_soc { # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 - set _mcu_r5_cores 2 - set _main0_r5_cores 2 - set _main1_r5_cores 0 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} @@ -158,6 +146,14 @@ $_TARGETNAME.sysctrl configure -event gdb-attach { halt 1000 } +proc _cpu_no_smp_up {} { + set _current_target [target current] + set _current_type [$_current_target cget -type] + + $_current_target arp_examine + $_current_target $_current_type dbginit +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -206,32 +202,18 @@ for { set _core 0 } { $_core < $_r5_cores } { incr _core } { # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine -} -if { $_mcu_r5_cores != 0 } { - proc mcu_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.mcu_r5.$_core arp_examine - $::_TARGETNAME.mcu_r5.$_core cortex_r4 dbginit - } - } -} - -if { $_main0_r5_cores != 0 } { - proc main0_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.main0_r5.$_core arp_examine - $::_TARGETNAME.main0_r5.$_core cortex_r4 dbginit - } + $_TARGETNAME.$_r5_name configure -event gdb-attach { + _cpu_no_smp_up + # gdb-attach default rule + halt 1000 } } -if { $_main1_r5_cores != 0 } { - proc main1_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.main1_r5.$_core arp_examine - $::_TARGETNAME.main1_r5.$_core cortex_r4 dbginit - } +proc r5_up { args } { + foreach _core $args { + targets $_core + _cpu_no_smp_up } } From 4ea21b95f9562ae13ef200461180bc72bbad8926 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 1 Mar 2022 09:09:55 -0600 Subject: [PATCH 060/186] tcl/target/ti_k3: Add a gdb-attach event hook for armv8 and simplify startup function Since we can detect the type of target as well, reuse the _cpu_no_smp_up function name and use the target name to simplify the _up function and maintain consistency with what we introduced for r5. Lets introduce gdb-attach event in a much cleaner fashion. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior While at it, fix a minor type of s/are/as in "Set Default target are core 0" and simplify the foreach usage. Signed-off-by: Nishanth Menon Change-Id: I3259b7c3ae4c71b06d921edfaefe17c03bb673dc Reviewed-on: https://review.openocd.org/c/openocd/+/6616 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 883197b14..f2267ca12 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -154,6 +154,16 @@ proc _cpu_no_smp_up {} { $_current_target $_current_type dbginit } +proc _armv8_smp_up {} { + for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { + $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on + } + # Set Default target as core 0 + targets $::_TARGETNAME.$::_armv8_cpu_name.0 +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -165,6 +175,20 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" + + if { $_v8_smp_debug == 0 } { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _cpu_no_smp_up + # gdb-attach default rule + halt 1000 + } + } else { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _armv8_smp_up + # gdb-attach default rule + halt 1000 + } + } } # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs @@ -174,22 +198,15 @@ set _armv8_smp_cmd "$_armv8_cpu_name"_smp if { $_v8_smp_debug == 0 } { proc $_armv8_up_cmd { args } { - foreach { _core } [set args] { - $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + foreach _core $args { + targets $_core + _cpu_no_smp_up } } } else { proc $_armv8_smp_cmd { args } { - for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { - $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on - } - # Set Default target are core 0 - targets $::_TARGETNAME.$::_armv8_cpu_name.0 + _armv8_smp_up } - # Declare SMP target smp $:::_v8_smp_targets } From 9f1b4bbe706b3df40793a9573d7f6471a2442222 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 14 Oct 2021 09:55:49 -0500 Subject: [PATCH 061/186] tcl/target/ti_k3: Add J721S2 SoC Add support for the latest in TI k3 family J721S2 SoC. For further details, see http://www.ti.com/lit/pdf/spruj28 Signed-off-by: Nishanth Menon Change-Id: I608ab4513ffb6b5c4166ba423e7d0dddbbb3bbfd Reviewed-on: https://review.openocd.org/c/openocd/+/6796 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index f2267ca12..604083758 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -114,6 +114,26 @@ switch $_soc { # M3 CTI base set CM3_CTIBASE {0x20001000} } + j721s2 { + set _CHIPNAME j721s2 + set _K3_DAP_TAPID 0x0bb7502f + + # J721s2 has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J721s2 has 3 clusters of 2 R5 cores each. + set _r5_cores 6 + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # M4 processor + set _gp_mcu_cores 1 + set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} + } default { echo "'$_soc' is invalid!" } From de4f52179c513cba194079f9fe1ce3a0532bdc9f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 14 Oct 2021 09:57:22 -0500 Subject: [PATCH 062/186] tcl/board: Add J721s2 EVM basic support Add basic connection details with J721s2 EVM. For further details, see https://www.ti.com/lit/zip/sprr439 Signed-off-by: Nishanth Menon Change-Id: I68f8818c492ea6e07c14f2da305671c26da801cb Reviewed-on: https://review.openocd.org/c/openocd/+/6797 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/ti_j721s2evm.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tcl/board/ti_j721s2evm.cfg diff --git a/tcl/board/ti_j721s2evm.cfg b/tcl/board/ti_j721s2evm.cfg new file mode 100644 index 000000000..72418b57b --- /dev/null +++ b/tcl/board/ti_j721s2evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J721s2 EVM +# Link(SoM): https://www.ti.com/lit/zip/sprr439 +# + +# J721s2 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j721s2 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 From d323fa1d194c8b18ec7d8284e5c8a33ac2b77f07 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 3 Jan 2022 13:23:38 -0600 Subject: [PATCH 063/186] tcl/target/ti_k3: Add AM625 SoC Add support for the latest in TI k3 family AM625 SoC. For further details, see https://www.ti.com/lit/pdf/spruiv7 Signed-off-by: Nishanth Menon Change-Id: Ia54d0eab1c30a973afb1c2c61f4c5a72d29d9b78 Reviewed-on: https://review.openocd.org/c/openocd/+/6798 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 604083758..254bb6971 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -88,6 +88,31 @@ switch $_soc { # M4 processor set _gp_mcu_cores 1 } + am625 { + set _CHIPNAME am625 + set _K3_DAP_TAPID 0x0bb7e02f + + # AM625 has 1 clusters of 4 A53 cores. + set _armv8_cpu_name a53 + set _armv8_cores 4 + set ARMV8_DBGBASE {0x90010000 0x90110000 0x90210000 0x90310000} + set ARMV8_CTIBASE {0x90020000 0x90120000 0x90220000 0x90320000} + + # AM625 has 1 cluster of 1 R5s core. + set _r5_cores 1 + set R5_NAMES {main0_r5.0} + set R5_DBGBASE {0x9d410000} + set R5_CTIBASE {0x9d418000} + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # M4 processor + set _gp_mcu_cores 1 + set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} + } j721e { set _CHIPNAME j721e set _K3_DAP_TAPID 0x0bb6402f From 5ffc397278b877000f88dbe0f750b0a1611338a4 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 3 Jan 2022 13:25:28 -0600 Subject: [PATCH 064/186] tcl/board: Add AM625 EVM basic support Add basic connection details with am625 EVM/SK For further details, see https://www.ti.com/lit/zip/sprr448 Signed-off-by: Nishanth Menon Change-Id: Ibd23203ea98e34d03d2f55dac3565aa15aad744b Reviewed-on: https://review.openocd.org/c/openocd/+/6799 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/ti_am625evm.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tcl/board/ti_am625evm.cfg diff --git a/tcl/board/ti_am625evm.cfg b/tcl/board/ti_am625evm.cfg new file mode 100644 index 000000000..4906fd096 --- /dev/null +++ b/tcl/board/ti_am625evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021-2022 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am625 EVM/SK +# Link: https://www.ti.com/lit/zip/sprr448 +# + +# AM625 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am625 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 From 9a6417e03595e1194f125ca33d2b60b8eac9a512 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 1 Mar 2022 23:21:20 +0100 Subject: [PATCH 065/186] tcl: don't use 'set' to retrieve the value of a variable Original TLC syntax uses 'set varname' to retrieve the value of variable 'varname'. Such archaic syntax is still valid, but the shorter '$varname' makes the code easier to read. Replace 'set varname' with '$varname'. While there, remove some useless curly brackets. Change-Id: I27310e8c05afe56ea8bd0e41d4ae2c34447b725c Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6863 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/lemaker_hikey.cfg | 2 +- tcl/board/tocoding_poplar.cfg | 2 +- tcl/target/bluefield.cfg | 2 +- tcl/target/xilinx_zynqmp.cfg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tcl/board/lemaker_hikey.cfg b/tcl/board/lemaker_hikey.cfg index ee677c34b..325b6fdda 100644 --- a/tcl/board/lemaker_hikey.cfg +++ b/tcl/board/lemaker_hikey.cfg @@ -17,7 +17,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg index 6d2e6354e..36d5aec47 100644 --- a/tcl/board/tocoding_poplar.cfg +++ b/tcl/board/tocoding_poplar.cfg @@ -19,7 +19,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/target/bluefield.cfg b/tcl/target/bluefield.cfg index 62b1e3165..dcebb2fb1 100644 --- a/tcl/target/bluefield.cfg +++ b/tcl/target/bluefield.cfg @@ -72,7 +72,7 @@ proc core_up { args } { global _TARGETNAME # Examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/target/xilinx_zynqmp.cfg b/tcl/target/xilinx_zynqmp.cfg index e66289a70..2df7a4ff9 100644 --- a/tcl/target/xilinx_zynqmp.cfg +++ b/tcl/target/xilinx_zynqmp.cfg @@ -99,7 +99,7 @@ targets $_TARGETNAME.0 proc core_up { args } { global _TARGETNAME - foreach { core } [set args] { + foreach core $args { $_TARGETNAME.$core arp_examine } } From 6883567d5f734040a40c4b2c2d739fa432132cb2 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Fri, 4 Feb 2022 14:44:24 +0100 Subject: [PATCH 066/186] jtag_vpi: Minor cleanup in jtag_vpi driver Multiple smaller items addressed in jtag_vpi: - Several log prints adjusted to make them more clear to the user. - Ensured that command handlers return ERROR_COMMAND_SYNTAX_ERROR on incorrect number of arguments. - Fix in "jtag_vpi set_address": Leave the previously set address intact on error. Do not revert it to default. - Minor update of help messages for the TCL commands. - Updated macro names: SERVER_ADDRESS --> DEFAULT_SERVER_ADDRESS, the same for SERVER_PORT Change-Id: Ibe386403a179adab5edb69c77fa408aef55701bd Signed-off-by: Jan Matyas Reviewed-on: https://review.openocd.org/c/openocd/+/6845 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/jtag/drivers/jtag_vpi.c | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 0fc688edf..eb53a5b06 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -38,8 +38,8 @@ #define NO_TAP_SHIFT 0 #define TAP_SHIFT 1 -#define SERVER_ADDRESS "127.0.0.1" -#define SERVER_PORT 5555 +#define DEFAULT_SERVER_ADDRESS "127.0.0.1" +#define DEFAULT_SERVER_PORT 5555 #define XFERT_MAX_SIZE 512 @@ -50,7 +50,7 @@ #define CMD_STOP_SIMU 4 /* jtag_vpi server port and address to connect to */ -static int server_port = SERVER_PORT; +static int server_port = DEFAULT_SERVER_PORT; static char *server_address; /* Send CMD_STOP_SIMU to server when OpenOCD exits? */ @@ -551,7 +551,7 @@ static int jtag_vpi_init(void) serv_addr.sin_port = htons(server_port); if (!server_address) - server_address = strdup(SERVER_ADDRESS); + server_address = strdup(DEFAULT_SERVER_ADDRESS); serv_addr.sin_addr.s_addr = inet_addr(server_address); @@ -604,27 +604,28 @@ static int jtag_vpi_quit(void) COMMAND_HANDLER(jtag_vpi_set_port) { - if (CMD_ARGC == 0) - LOG_WARNING("You need to set a port number"); - else - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + if (CMD_ARGC == 0) { + LOG_ERROR("Command \"jtag_vpi set_port\" expects 1 argument (TCP port number)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - LOG_INFO("Set server port to %u", server_port); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + LOG_INFO("jtag_vpi: server port set to %u", server_port); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_address) { - free(server_address); if (CMD_ARGC == 0) { - LOG_WARNING("You need to set an address"); - server_address = strdup(SERVER_ADDRESS); - } else - server_address = strdup(CMD_ARGV[0]); + LOG_ERROR("Command \"jtag_vpi set_address\" expects 1 argument (IP address)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - LOG_INFO("Set server address to %s", server_address); + free(server_address); + server_address = strdup(CMD_ARGV[0]); + LOG_INFO("jtag_vpi: server address set to %s", server_address); return ERROR_OK; } @@ -632,11 +633,11 @@ COMMAND_HANDLER(jtag_vpi_set_address) COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) { if (CMD_ARGC != 1) { - LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)"); + LOG_ERROR("Command \"jtag_vpi stop_sim_on_exit\" expects 1 argument (on|off)"); return ERROR_COMMAND_SYNTAX_ERROR; - } else { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); return ERROR_OK; } @@ -645,14 +646,14 @@ static const struct command_registration jtag_vpi_subcommand_handlers[] = { .name = "set_port", .handler = &jtag_vpi_set_port, .mode = COMMAND_CONFIG, - .help = "set the port of the VPI server", + .help = "set the TCP port number of the jtag_vpi server (default: 5555)", .usage = "tcp_port_num", }, { .name = "set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, - .help = "set the address of the VPI server", + .help = "set the IP address of the jtag_vpi server (default: 127.0.0.1)", .usage = "ipv4_addr", }, { From 6673f90e08ac7fb079403dfe7011779349559f0c Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Thu, 24 Feb 2022 15:18:53 +0100 Subject: [PATCH 067/186] flash/stm32h7x: fix FLASH_WPSN_PRG mask used for protection STM32H7Ax/7Bx devices have a different WPSN mask (0xFFFFFFFF), (0xFF for STM32H74x/75x and STM32H72x/73x devices). And when supporting STM32H7Ax/7Bx devices, stm32x_protect() was not updated accordingly. Change-Id: I081217af3e5ed815b67bfdfec7f4ebaa3152a865 Signed-off-by: Tarek BOCHKATI Fixes: 0b7eca17691a (flash/stm32h7x: add support of STM32H7Ax/H7Bx devices) Reviewed-on: https://review.openocd.org/c/openocd/+/6858 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/stm32h7x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 6d3149f94..d2914eb39 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -531,6 +531,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t protection; if (target->state != TARGET_HALTED) { @@ -553,7 +554,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } /* apply WRPSN mask */ - protection &= 0xff; + protection &= stm32x_info->part_info->wps_mask; LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); From b6e4d1aa041a119ac6e6576cc8920bf22d1badf5 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 3 Mar 2022 20:56:57 +0100 Subject: [PATCH 068/186] flash/nor/sim3x: Fix typo Change-Id: I2143c81d44b49bed9585c4aaee2bb6e2165345f2 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6869 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/sim3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 2938ed1ab..891383860 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -983,7 +983,7 @@ COMMAND_HANDLER(sim3x_lock) if (!dap) { /* Used debug interface doesn't support direct DAP access */ - LOG_INFO("Target can't by unlocked by this debug interface"); + LOG_INFO("Target can't be unlocked by this debug interface"); /* Core check */ ret = target_read_u32(target, CPUID, &val); From 1c22c5a82b248b7209fdc904e733b9fa29307c48 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 3 Mar 2022 20:35:10 +0100 Subject: [PATCH 069/186] flash/nor/efm32: Use Cortex-M 'core_info' field Change-Id: I5e477036e5cb7518c35df88878d53261311deb40 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6868 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/efm32.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 653878ae7..2c5a5020e 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -257,23 +257,19 @@ static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, static int efm32x_read_info(struct flash_bank *bank) { int ret; - uint32_t cpuid = 0; struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct efm32_info *efm32_info = &(efm32x_info->info); memset(efm32_info, 0, sizeof(struct efm32_info)); - ret = target_read_u32(bank->target, CPUID, &cpuid); - if (ret != ERROR_OK) - return ret; + const struct cortex_m_common *cortex_m = target_to_cm(bank->target); - if (((cpuid >> 4) & 0xfff) == 0xc23) { - /* Cortex-M3 device */ - } else if (((cpuid >> 4) & 0xfff) == 0xc24) { - /* Cortex-M4 device (WONDER GECKO) */ - } else if (((cpuid >> 4) & 0xfff) == 0xc60) { - /* Cortex-M0+ device */ - } else { + 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; } From 5b70c1f679755677c925b4e6dd2c3d8be4715717 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 21 Feb 2022 14:06:51 -0500 Subject: [PATCH 070/186] target: Add LS1046A The LS1046A is a quad-core processor from NXP in the layerscape family. This SoC is a bit tricky to program: while the AArch64 CPUs are little-endian, most of the peripherals are big-endian. Care must be taken when interpreting memory reads/writes. This processor is in the same family as the ls1012a, so the setup is similar. If you use OpenOCD to attach early in the boot process, only the cpu0 may be available. Trying to halt other CPUs will fail. To avoid this, defer examination of cpus 1-3, and provide a core_up helper (like e.g. zynqmp). Signed-off-by: Sean Anderson Change-Id: If5a1a9441fb35fea3e05dc708b42e0cb3bbf2a54 Reviewed-on: https://review.openocd.org/c/openocd/+/6854 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1046a.cfg | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tcl/target/ls1046a.cfg diff --git a/tcl/target/ls1046a.cfg b/tcl/target/ls1046a.cfg new file mode 100644 index 000000000..3d96a994e --- /dev/null +++ b/tcl/target/ls1046a.cfg @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1046a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +if { [info exists SAP_TAPID] } { + set _SAP_TAPID $SAP_TAPID +} else { + set _SAP_TAPID 0x06b3001d +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +set _CPU_BASE 0x80400000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 4} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + -coreid $i {*}[expr {$i ? {-defer-examine} : {-rtos hwthread} }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID +target create $_CHIPNAME.sap ls1_sap -chain-position $_CHIPNAME.sap -endian big + +proc core_up { args } { + foreach core $args { + $::_CHIPNAME.cpu$core arp_examine + } +} + +targets $_CHIPNAME.cpu0 + +adapter speed 10000 From 5b9da0eed215386b856c3168ff712f9af483c0c6 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 21 Feb 2022 14:53:46 -0500 Subject: [PATCH 071/186] board: Add LS1046ARDB This adds support for the LS1046A Reference Design Board. There are several JTAG headers accessable once the case is opened, but this config is for the externally-accessable CMSIS DAP. Signed-off-by: Sean Anderson Change-Id: I0f83470da3758f0c4512ce47348c4db7de17b27e Reviewed-on: https://review.openocd.org/c/openocd/+/6855 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/nxp_rdb-ls1046a.cfg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tcl/board/nxp_rdb-ls1046a.cfg diff --git a/tcl/board/nxp_rdb-ls1046a.cfg b/tcl/board/nxp_rdb-ls1046a.cfg new file mode 100644 index 000000000..fde1829fb --- /dev/null +++ b/tcl/board/nxp_rdb-ls1046a.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046ARDB (Reference Design Board) +# This is for the "console" USB port on the front panel +# You must ensure that SW4-7 is in the "off" position + +# NXP K20 +# The firmware implements the old CMSIS-DAP v1 USB HID interface +# You must pass --enable-cmsis-dap to ./configure to enable it +source [find interface/cmsis-dap.cfg] + +transport select jtag +reset_config srst_only + +source [find target/ls1046a.cfg] + +# The adapter can't handle 10MHz +adapter speed 5000 From c5a23e96878d50b64b3d6ee4e52b37f58daaa17f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 5 Mar 2022 14:00:04 +0100 Subject: [PATCH 072/186] jimtcl: add configure flag for build maintainer mode When jimtcl is built in maintainer mode, it runs extra tests at exit to look for memory leak due to jim objects not properly freed either through Jim_IncrRefCount()/Jim_DecrRefCount() or by passing it to a jim API. Add optional OpenOCD configure flag '--enable-jimtcl-maintainer' to enable jimtcl maintainer mode. Modify the implementation of macro AX_CONFIG_SUBDIR_OPTION to allow expanding a variable passed as second argument. Change-Id: Id1a39b25cee3773b172faf70803fa150182f0cd6 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6871 Tested-by: jenkins Reviewed-by: zapb --- config_subdir.m4 | 2 +- configure.ac | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/config_subdir.m4 b/config_subdir.m4 index 45a1c6c4f..2be590e44 100644 --- a/config_subdir.m4 +++ b/config_subdir.m4 @@ -7,6 +7,6 @@ AC_DEFUN([AX_CONFIG_SUBDIR_OPTION], AC_CONFIG_SUBDIRS([$1]) m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu], -[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" $2 "'\$'@"' > "$srcdir/$1/configure.gnu" +[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" '"$2"' "'\$'@"' > "$srcdir/$1/configure.gnu" ]) ]) diff --git a/configure.ac b/configure.ac index 68fff45c1..15d7229a4 100644 --- a/configure.ac +++ b/configure.ac @@ -354,6 +354,10 @@ AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) +AC_ARG_ENABLE([jimtcl-maintainer], + AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]), + [use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no]) + AC_ARG_ENABLE([internal-libjaylink], AS_HELP_STRING([--disable-internal-libjaylink], [Disable building internal libjaylink]), @@ -550,7 +554,12 @@ AS_IF([test "x$enable_buspirate" != "xno"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ - AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) + AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ + jimtcl_config_options="--disable-install-jim --maintainer" + ], [ + jimtcl_config_options="--disable-install-jim" + ]) + AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) From 38183dc856fdb7e69c8407911ff16383f4b12247 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 7 Jun 2021 16:55:24 +0200 Subject: [PATCH 073/186] target/tcl: Add 'read_memory' and 'write_memory' These functions are meant as replacement for 'mem2array' and 'array2mem'. The main benefits of these new functions are: * They do not use Tcl arrays but lists which makes it easier to parse (generate) the data. See the Python Tcl RPC code in contrib as a negative example. * They do not operate on Tcl variables but instead return (accept) the Tcl list directly. This makes the C and Tcl code base smaller and cleaner. * The code is slightly more performant when reading / writing large amount of data. Tested with a simple Python Tcl RPC benchmark. Change-Id: Ibd6ece3360c0d002abaadc37f078b10a8bb606f8 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6307 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 78 +++++++++++ src/target/target.c | 321 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 399 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2bfa0deae..f9acedf69 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5036,6 +5036,45 @@ get_reg @{pc sp@} @end example @end deffn +@deffn {Command} {$target_name write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {$target_name read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8557,6 +8596,45 @@ get_reg @{pc sp@} @end example @end deffn +@deffn {Command} {write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index b72dc53e3..473538ab7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4604,6 +4604,161 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, return e; } +static int target_jim_read_memory(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + /* + * argv[1] = memory address + * argv[2] = desired element width in bits + * argv[3] = number of elements to read + * argv[4] = optional "phys" + */ + + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 1, argv, "address width count ['phys']"); + return JIM_ERR; + } + + /* Arg 1: Memory address. */ + jim_wide wide_addr; + int e; + e = Jim_GetWide(interp, argv[1], &wide_addr); + + if (e != JIM_OK) + return e; + + target_addr_t addr = (target_addr_t)wide_addr; + + /* Arg 2: Bit width of one element. */ + long l; + e = Jim_GetLong(interp, argv[2], &l); + + if (e != JIM_OK) + return e; + + const unsigned int width_bits = l; + + /* Arg 3: Number of elements to read. */ + e = Jim_GetLong(interp, argv[3], &l); + + if (e != JIM_OK) + return e; + + size_t count = l; + + /* Arg 4: Optional 'phys'. */ + bool is_phys = false; + + if (argc > 4) { + const char *phys = Jim_GetString(argv[4], NULL); + + if (strcmp(phys, "phys")) { + Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); + return JIM_ERR; + } + + is_phys = true; + } + + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); + return JIM_ERR; + } + + const unsigned int width = width_bits / 8; + + if ((addr + (count * width)) < addr) { + Jim_SetResultString(interp, "read_memory: addr + count wraps to zero", -1); + return JIM_ERR; + } + + if (count > 65536) { + Jim_SetResultString(interp, "read_memory: too large read request, exeeds 64K elements", -1); + return JIM_ERR; + } + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + struct target *target = get_current_target(cmd_ctx); + + const size_t buffersize = 4096; + uint8_t *buffer = malloc(buffersize); + + if (!buffer) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + Jim_Obj *result_list = Jim_NewListObj(interp, NULL, 0); + Jim_IncrRefCount(result_list); + + while (count > 0) { + const unsigned int max_chunk_len = buffersize / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + int retval; + + if (is_phys) + retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); + else + retval = target_read_memory(target, addr, width, chunk_len, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + Jim_SetResultString(interp, "read_memory: failed to read memory", -1); + e = JIM_ERR; + break; + } + + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; + + switch (width) { + case 8: + v = target_buffer_get_u64(target, &buffer[i * width]); + break; + case 4: + v = target_buffer_get_u32(target, &buffer[i * width]); + break; + case 2: + v = target_buffer_get_u16(target, &buffer[i * width]); + break; + case 1: + v = buffer[i]; + break; + } + + char value_buf[11]; + snprintf(value_buf, sizeof(value_buf), "0x%" PRIx64, v); + + Jim_ListAppendElement(interp, result_list, + Jim_NewStringObj(interp, value_buf, -1)); + } + + count -= chunk_len; + addr += chunk_len * width; + } + + free(buffer); + + if (e != JIM_OK) { + Jim_DecrRefCount(interp, result_list); + return e; + } + + Jim_SetResult(interp, result_list); + Jim_DecrRefCount(interp, result_list); + + return JIM_OK; +} + static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val) { char *namebuf = alloc_printf("%s(%zu)", varname, idx); @@ -4814,6 +4969,144 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, return e; } +static int target_jim_write_memory(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + /* + * argv[1] = memory address + * argv[2] = desired element width in bits + * argv[3] = list of data to write + * argv[4] = optional "phys" + */ + + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); + return JIM_ERR; + } + + /* Arg 1: Memory address. */ + int e; + jim_wide wide_addr; + e = Jim_GetWide(interp, argv[1], &wide_addr); + + if (e != JIM_OK) + return e; + + target_addr_t addr = (target_addr_t)wide_addr; + + /* Arg 2: Bit width of one element. */ + long l; + e = Jim_GetLong(interp, argv[2], &l); + + if (e != JIM_OK) + return e; + + const unsigned int width_bits = l; + size_t count = Jim_ListLength(interp, argv[3]); + + /* Arg 4: Optional 'phys'. */ + bool is_phys = false; + + if (argc > 4) { + const char *phys = Jim_GetString(argv[4], NULL); + + if (strcmp(phys, "phys")) { + Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); + return JIM_ERR; + } + + is_phys = true; + } + + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); + return JIM_ERR; + } + + const unsigned int width = width_bits / 8; + + if ((addr + (count * width)) < addr) { + Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); + return JIM_ERR; + } + + if (count > 65536) { + Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); + return JIM_ERR; + } + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + struct target *target = get_current_target(cmd_ctx); + + const size_t buffersize = 4096; + uint8_t *buffer = malloc(buffersize); + + if (!buffer) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + size_t j = 0; + + while (count > 0) { + const unsigned int max_chunk_len = buffersize / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + for (size_t i = 0; i < chunk_len; i++, j++) { + Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); + jim_wide element_wide; + Jim_GetWide(interp, tmp, &element_wide); + + const uint64_t v = element_wide; + + switch (width) { + case 8: + target_buffer_set_u64(target, &buffer[i * width], v); + break; + case 4: + target_buffer_set_u32(target, &buffer[i * width], v); + break; + case 2: + target_buffer_set_u16(target, &buffer[i * width], v); + break; + case 1: + buffer[i] = v & 0x0ff; + break; + } + } + + count -= chunk_len; + + int retval; + + if (is_phys) + retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); + else + retval = target_write_memory(target, addr, width, chunk_len, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + Jim_SetResultString(interp, "write_memory: failed to write memory", -1); + e = JIM_ERR; + break; + } + + addr += chunk_len * width; + } + + free(buffer); + + return e; +} + /* FIX? should we propagate errors here rather than printing them * and continuing? */ @@ -5797,6 +6090,20 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "Set target register values", .usage = "dict", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", + }, { .name = "eventlist", .handler = handle_target_event_list, @@ -6893,6 +7200,20 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "Set target register values", .usage = "dict", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", + }, { .name = "reset_nag", .handler = handle_target_reset_nag, From e370e06b724f6e3a0fdd8611a3d461c2cc15735c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 7 Jun 2021 14:40:30 +0200 Subject: [PATCH 074/186] target: Deprecate 'array2mem' and 'mem2array'' Replace 'mem2array' and 'array2mem' with a Tcl wrapper that internally uses 'read_memory' and 'write_memory'. The target-specific 'mem2array' and 'array2mem' functions remain for now. Change-Id: If24c22a76ac72d4c26916a95f7f17902b41b6d9e Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6308 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 39 ++++-------------------------- src/target/startup.tcl | 26 ++++++++++++++++++++ src/target/target.c | 54 ++++-------------------------------------- 3 files changed, 35 insertions(+), 84 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f9acedf69..0cd9621ff 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4980,29 +4980,6 @@ use these to deal with specific reset cases. They are not otherwise documented here. @end deffn -@deffn {Command} {$target_name array2mem} arrayname width address count -@deffnx {Command} {$target_name mem2array} arrayname width address count -These provide an efficient script-oriented interface to memory. -The @code{array2mem} primitive writes bytes, halfwords, words -or double-words; while @code{mem2array} reads them. -In both cases, the TCL side uses an array, and -the target side uses raw memory. - -The efficiency comes from enabling the use of -bulk JTAG data transfer operations. -The script orientation comes from working with data -values that are packaged for use by TCL scripts; -@command{mdw} type primitives only print data they retrieve, -and neither store nor return those values. - -@itemize -@item @var{arrayname} ... is the name of an array variable -@item @var{width} ... is 8/16/32/64 - indicating the memory access size -@item @var{address} ... is the target memory address -@item @var{count} ... is the number of elements to process -@end itemize -@end deffn - @deffn {Command} {$target_name set_reg} dict Set register values of the target. @@ -5142,8 +5119,8 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn @deffn {Command} {$target_name mwd} [phys] addr doubleword [count] @@ -8772,8 +8749,8 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn @deffn {Command} {mwd} [phys] addr doubleword [count] @@ -11681,13 +11658,7 @@ should be passed in to the proc in question. By "low-level", we mean commands that a human would typically not invoke directly. -@itemize @bullet -@item @b{mem2array} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Read memory and return as a Tcl array for script processing -@item @b{array2mem} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Convert a Tcl array to memory locations and write the values +@itemize @item @b{flash banks} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> <@var{bus_width}> <@var{target}> [@option{driver options} ...] Return information about the flash banks diff --git a/src/target/startup.tcl b/src/target/startup.tcl index cd98d68e4..0e46992b7 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -206,6 +206,32 @@ proc init_target_events {} { proc init_board {} { } +proc mem2array {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'read_memory' not 'mem2array'" + + upvar $arrayname $arrayname + set $arrayname "" + set i 0 + + foreach elem [read_memory $address $bitwidth $count {*}$phys] { + set ${arrayname}($i) $elem + incr i + } +} + +proc array2mem {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'write_memory' not 'array2mem'" + + upvar $arrayname $arrayname + set data "" + + for {set i 0} {$i < $count} {incr i} { + lappend data [expr $${arrayname}($i)] + } + + write_memory $address $bitwidth $data {*}$phys +} + # smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615 lappend _telnet_autocomplete_skip "aarch64 smp_on" proc "aarch64 smp_on" {args} { diff --git a/src/target/target.c b/src/target/target.c index 473538ab7..7b8271339 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4431,27 +4431,12 @@ static int new_u64_array_element(Jim_Interp *interp, const char *varname, int id return result; } -static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); - if (!target) { - LOG_ERROR("mem2array: no current target"); - return JIM_ERR; - } - - return target_mem2array(interp, target, argc - 1, argv + 1); -} - static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; + LOG_WARNING("DEPRECATED! use 'read_memory' not 'mem2array'"); + /* argv[0] = name of array to receive the data * argv[1] = desired element width in bits * argv[2] = memory address @@ -4784,28 +4769,13 @@ static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t return result; } -static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); - if (!target) { - LOG_ERROR("array2mem: no current target"); - return JIM_ERR; - } - - return target_array2mem(interp, target, argc-1, argv + 1); -} - static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; + LOG_WARNING("DEPRECATED! use 'write_memory' not 'array2mem'"); + /* argv[0] = name of array from which to read the data * argv[1] = desired element width in bits * argv[2] = memory address @@ -7170,22 +7140,6 @@ static const struct command_registration target_exec_command_handlers[] = { .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, - { - .name = "mem2array", - .mode = COMMAND_EXEC, - .jim_handler = jim_mem2array, - .help = "read 8/16/32 bit memory and return as a TCL array " - "for script processing", - .usage = "arrayname bitwidth address count", - }, - { - .name = "array2mem", - .mode = COMMAND_EXEC, - .jim_handler = jim_array2mem, - .help = "convert a TCL array to memory locations " - "and write the 8/16/32 bit values", - .usage = "arrayname bitwidth address count", - }, { .name = "get_reg", .mode = COMMAND_EXEC, From be0d68eb66b513ef406ffa83102f89a8f4602914 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Feb 2022 15:44:58 +0100 Subject: [PATCH 075/186] Remove all occurrences of 'mem2array' and 'array2mem' Replace deprecated commands 'mem2array' and 'array2mem' with new Tcl commands 'read_memory' and 'write_memory'. Change-Id: I116d995995396133ca782b14cce02bd1ab917a4e Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6859 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/rpc_examples/ocd_rpc_example.py | 18 ++----- tcl/board/at91cap7a-stk-sdram.cfg | 3 +- tcl/board/at91sam9g20-ek.cfg | 4 +- tcl/board/embedded-artists_lpc2478-32.cfg | 4 +- tcl/board/hilscher_nxhx10.cfg | 4 +- tcl/board/icnova_sam9g45_sodimm.cfg | 4 +- tcl/chip/atmel/at91/aic.tcl | 20 ++++---- tcl/cpu/arc/common.tcl | 5 +- tcl/mem_helper.tcl | 12 ++--- tcl/memory.tcl | 60 +++++++++-------------- tcl/target/c100helper.tcl | 24 +++++---- tcl/target/hilscher_netx500.cfg | 4 +- tcl/target/psoc4.cfg | 18 +++---- tcl/target/stm32h7x.cfg | 4 +- tcl/target/stm32mp15x.cfg | 4 +- tcl/target/stm32wlx.cfg | 4 +- tcl/target/ti_cc3220sf.cfg | 8 +-- testing/examples/cortex/cm3-ftest.cfg | 2 +- 18 files changed, 79 insertions(+), 123 deletions(-) diff --git a/contrib/rpc_examples/ocd_rpc_example.py b/contrib/rpc_examples/ocd_rpc_example.py index 3470d848b..e6146f617 100755 --- a/contrib/rpc_examples/ocd_rpc_example.py +++ b/contrib/rpc_examples/ocd_rpc_example.py @@ -95,24 +95,16 @@ def readVariable(self, address): return None if (len(raw) < 2) else strToHex(raw[1]) def readMemory(self, wordLen, address, n): - self.send("array unset output") # better to clear the array before - self.send("mem2array output %d 0x%x %d" % (wordLen, address, n)) - - output = [*map(int, self.send("return $output").split(" "))] - d = dict([tuple(output[i:i + 2]) for i in range(0, len(output), 2)]) - - return [d[k] for k in sorted(d.keys())] + output = self.send("read_memory 0x%x %d %d" % (address, wordLen, n)) + return [*map(lambda x: int(x, 16), output.split(" "))] def writeVariable(self, address, value): assert value is not None self.send("mww 0x%x 0x%x" % (address, value)) - def writeMemory(self, wordLen, address, n, data): - array = " ".join(["%d 0x%x" % (a, b) for a, b in enumerate(data)]) - - self.send("array unset 1986ве1т") # better to clear the array before - self.send("array set 1986ве1т { %s }" % array) - self.send("array2mem 1986ве1т 0x%x %s %d" % (wordLen, address, n)) + def writeMemory(self, wordLen, address, data): + data = "{" + ' '.join(['0x%x' % x for x in data]) + "}" + self.send("write_memory 0x%x %d %s" % (address, wordLen, data)) if __name__ == "__main__": diff --git a/tcl/board/at91cap7a-stk-sdram.cfg b/tcl/board/at91cap7a-stk-sdram.cfg index 8a371e064..182a4067f 100644 --- a/tcl/board/at91cap7a-stk-sdram.cfg +++ b/tcl/board/at91cap7a-stk-sdram.cfg @@ -32,8 +32,7 @@ $_TARGETNAME configure -event reset-start { } proc peek32 {address} { - mem2array t 32 $address 1 - return $t(0) + return [read_memory $address 32 1] } # Wait for an expression to be true with a timeout diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index e1cbb9120..04d9a197c 100644 --- a/tcl/board/at91sam9g20-ek.cfg +++ b/tcl/board/at91sam9g20-ek.cfg @@ -40,9 +40,7 @@ at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g20_reset_start { } { diff --git a/tcl/board/embedded-artists_lpc2478-32.cfg b/tcl/board/embedded-artists_lpc2478-32.cfg index 38f5e1b8e..a73d83263 100644 --- a/tcl/board/embedded-artists_lpc2478-32.cfg +++ b/tcl/board/embedded-artists_lpc2478-32.cfg @@ -8,9 +8,7 @@ source [find target/lpc2478.cfg] # Helper # proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc init_board {} { diff --git a/tcl/board/hilscher_nxhx10.cfg b/tcl/board/hilscher_nxhx10.cfg index 1875dacc0..6e2eba79e 100644 --- a/tcl/board/hilscher_nxhx10.cfg +++ b/tcl/board/hilscher_nxhx10.cfg @@ -26,9 +26,7 @@ proc flash_init { } { } proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } proc init_clocks { } { diff --git a/tcl/board/icnova_sam9g45_sodimm.cfg b/tcl/board/icnova_sam9g45_sodimm.cfg index 8a0736b1f..91e0107c2 100644 --- a/tcl/board/icnova_sam9g45_sodimm.cfg +++ b/tcl/board/icnova_sam9g45_sodimm.cfg @@ -43,9 +43,7 @@ flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g45_start { } { diff --git a/tcl/chip/atmel/at91/aic.tcl b/tcl/chip/atmel/at91/aic.tcl index b0b100270..8b8a48f3b 100644 --- a/tcl/chip/atmel/at91/aic.tcl +++ b/tcl/chip/atmel/at91/aic.tcl @@ -54,36 +54,36 @@ proc show_AIC_IMR_helper { NAME ADDR VAL } { proc show_AIC { } { global AIC_SMR - if [catch { mem2array aaa 32 $AIC_SMR [expr {32 * 4}] } msg ] { + if [catch { set aaa [read_memory $AIC_SMR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SMR] } echo "AIC_SMR: Mode & Type" global AT91C_ID for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } global AIC_SVR - if [catch { mem2array aaa 32 $AIC_SVR [expr {32 * 4}] } msg ] { + if [catch { set aaa [read_memory $AIC_SVR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SVR] } echo "AIC_SVR: Vectors" for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } diff --git a/tcl/cpu/arc/common.tcl b/tcl/cpu/arc/common.tcl index e9a915717..b31e31a34 100644 --- a/tcl/cpu/arc/common.tcl +++ b/tcl/cpu/arc/common.tcl @@ -29,9 +29,8 @@ proc arc_common_reset { {target ""} } { # vector located at the interrupt vector base address, which is the first # entry (offset 0x00) in the vector table. set int_vector_base [arc jtag get-aux-reg 0x25] - set start_pc "" - mem2array start_pc 32 $int_vector_base 1 - arc jtag set-aux-reg 0x6 $start_pc(0) + set start_pc [read_memory $int_vector_base 32 1] + arc jtag set-aux-reg 0x6 $start_pc # It is OK to do uncached writes - register cache will be invalidated by # the reset_assert() function. diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl index 9ea285a22..1c860119a 100644 --- a/tcl/mem_helper.tcl +++ b/tcl/mem_helper.tcl @@ -2,9 +2,7 @@ # mrw: "memory read word", returns value of $reg proc mrw {reg} { - set value "" - mem2array value 32 $reg 1 - return $value(0) + return [read_memory $reg 32 1] } add_usage_text mrw "address" @@ -12,9 +10,7 @@ add_help_text mrw "Returns value of word in memory." # mrh: "memory read halfword", returns value of $reg proc mrh {reg} { - set value "" - mem2array value 16 $reg 1 - return $value(0) + return [read_memory $reg 16 1] } add_usage_text mrh "address" @@ -22,9 +18,7 @@ add_help_text mrh "Returns value of halfword in memory." # mrb: "memory read byte", returns value of $reg proc mrb {reg} { - set value "" - mem2array value 8 $reg 1 - return $value(0) + return [read_memory $reg 8 1] } add_usage_text mrb "address" diff --git a/tcl/memory.tcl b/tcl/memory.tcl index 8d50ba853..ac273451d 100644 --- a/tcl/memory.tcl +++ b/tcl/memory.tcl @@ -79,108 +79,96 @@ proc address_info { ADDRESS } { } proc memread32 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA } msg ] { + return $DATA } else { error "memwrite8: $msg" } } proc memread32_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1 phys] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1 phys] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1 phys] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA phys } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA phys } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA phys } msg ] { + return $DATA } else { error "memwrite8: $msg" } diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index bdcfd8cf5..ecd7edf11 100644 --- a/tcl/target/c100helper.tcl +++ b/tcl/target/c100helper.tcl @@ -29,9 +29,7 @@ source [find mem_helper.tcl] # read a 64-bit register (memory mapped) proc mr64bit {reg} { - set value "" - mem2array value 32 $reg 2 - return $value + return [read_memory $reg 32 2] } @@ -117,19 +115,19 @@ proc showAmbaClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_AHB_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_AHB_CLK_CNTRL [mrw $CLKCORE_AHB_CLK_CNTRL]] - mem2array value 32 $CLKCORE_AHB_CLK_CNTRL 1 + set value [read_memory $CLKCORE_AHB_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr {($value(0) & $PLL_CLK_BYPASS) >> 24}] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr {($value(0) & 0x0001F0000) >> 16}] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr {($value(0) & 0x00000007F)}] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr {($value(0) & 0x000000300) >> 8}] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Amba PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } @@ -192,19 +190,19 @@ proc showArmClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_ARM_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_ARM_CLK_CNTRL [mrw $CLKCORE_ARM_CLK_CNTRL]] - mem2array value 32 $CLKCORE_ARM_CLK_CNTRL 1 + set value [read_memory $CLKCORE_ARM_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr {($value(0) & $PLL_CLK_BYPASS) >> 24}] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr {($value(0) & 0x0001F0000) >> 16}] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr {($value(0) & 0x00000007F)}] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr {($value(0) & 0x000000300) >> 8}] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Arm PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } diff --git a/tcl/target/hilscher_netx500.cfg b/tcl/target/hilscher_netx500.cfg index 6d919f9dd..131bef221 100644 --- a/tcl/target/hilscher_netx500.cfg +++ b/tcl/target/hilscher_netx500.cfg @@ -26,9 +26,7 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } # This function must be called on netX100/500 right after halt diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index cffcbc753..40f2fcab3 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -74,22 +74,22 @@ if {![using_hla]} { } proc psoc4_get_family_id {} { - set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"] + set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}] if { $err } { return 0 } - if { [expr {$romtable_pid(0) & 0xffffff00 }] - || [expr {$romtable_pid(1) & 0xffffff00 }] - || [expr {$romtable_pid(2) & 0xffffff00 }] } { + if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }] + || [expr {[lindex $romtable_pid 1] & 0xffffff00 }] + || [expr {[lindex $romtable_pid 2] & 0xffffff00 }] } { echo "Unexpected data in ROMTABLE" return 0 } - set designer_id [expr {(( $romtable_pid(1) & 0xf0 ) >> 4) | (( $romtable_pid(2) & 0xf ) << 4 ) }] + set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $romtable_pid 2] & 0xf ) << 4 ) }] if { $designer_id != 0xb4 } { echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] return 0 } - set family_id [expr {( $romtable_pid(0) & 0xff ) | (( $romtable_pid(1) & 0xf ) << 8 ) }] + set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }] return $family_id } @@ -193,9 +193,9 @@ proc ocd_process_reset_inner { MODE } { } # Set registers to reset vector values - mem2array value 32 0 2 - reg pc [expr {$value(1) & 0xfffffffe} ] - reg msp $value(0) + set value [read_memory 0x0 32 2] + reg pc [expr {[lindex $value 1] & 0xfffffffe}] + reg msp [lindex $value 0] if { $PSOC4_TEST_MODE_WORKAROUND } { catch { mww $TEST_MODE 0 } diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index f2a5c42c6..ca685c2f2 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -232,9 +232,7 @@ if {[set $_CHIPNAME.DUAL_CORE]} { # like mrw, but with target selection proc stm32h7x_mrw {used_target reg} { - set value "" - $used_target mem2array value 32 $reg 1 - return $value(0) + return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index 639fbabe0..afd5d2413 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/stm32mp15x.cfg @@ -109,8 +109,8 @@ proc toggle_cpu0_dbg_claim0 {} { } proc detect_cpu1 {} { - $::_CHIPNAME.ap1 mem2array cpu1_prsr 32 0xE00D2314 1 - set dual_core [expr {$cpu1_prsr(0) & 1}] + set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] + set dual_core [expr {$cpu1_prsr & 1}] if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg index fafe9bcba..75f6f0288 100644 --- a/tcl/target/stm32wlx.cfg +++ b/tcl/target/stm32wlx.cfg @@ -156,9 +156,7 @@ proc stm32wlx_get_chipname {} { # like mrw, but with target selection proc stm32wlx_mrw {used_target reg} { - set value "" - $used_target mem2array value 32 $reg 1 - return $value(0) + return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti_cc3220sf.cfg index 74269aa66..c0a7b568d 100644 --- a/tcl/target/ti_cc3220sf.cfg +++ b/tcl/target/ti_cc3220sf.cfg @@ -26,11 +26,11 @@ proc ocd_process_reset_inner { MODE } { soft_reset_halt # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 - mem2array boot 32 0x01000800 2 + set boot [read_memory 0x01000800 32 2] - reg msp $boot(0) - reg psp $boot(0) - reg pc $boot(1) + reg msp [lindex $boot 0] + reg psp [lindex $boot 0] + reg pc [lindex $boot 1] if { 0 == [string compare $MODE run ] } { resume diff --git a/testing/examples/cortex/cm3-ftest.cfg b/testing/examples/cortex/cm3-ftest.cfg index 6f3fa5c81..02c8da11a 100644 --- a/testing/examples/cortex/cm3-ftest.cfg +++ b/testing/examples/cortex/cm3-ftest.cfg @@ -50,7 +50,7 @@ proc load_and_run { name halfwords n_instr } { echo "# code to trigger $name vector" set addr 0x20000000 - # array2mem should be faster, though we'd need to + # write_memory should be faster, though we'd need to # compute the resulting $addr ourselves foreach opcode $halfwords { mwh $addr $opcode From f732956b031cdab47e8784ee01ea9c8d5e185e6e Mon Sep 17 00:00:00 2001 From: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Date: Thu, 17 Mar 2022 18:01:34 +0100 Subject: [PATCH 076/186] Fix & improvements in Linux Build workflow (#686) * Fix of Linux Build workflow: add missing apt-get update Change-Id: I69cd1693b2ad5405574affe5b85e5c4c9c76e278 Signed-off-by: Jan Matyas * Minor improvements in Linux Build workflow - Use parallel build (use -j for make) - Check that the resulting OpenOCD executable can actually be launched (call openocd --version) Change-Id: I6b8c56688a39cae436986954fbd517082dc8160d Signed-off-by: Jan Matyas --- .github/workflows/linux-build.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 74028d54b..9664ca68d 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -12,11 +12,15 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v2 - - run: sudo apt-get install clang gcc-multilib + - name: Install required packages (apt-get) + run: | + sudo apt-get update + sudo apt-get install clang gcc-multilib - run: ./bootstrap - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --disable-target64 - - run: make + - run: make -j`nproc` - run: file src/openocd | grep 32-bit + - run: src/openocd --version # 64-bit, gcc @@ -28,8 +32,12 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v2 - - run: sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev + - name: Install required packages (apt-get) + run: | + sudo apt-get update + sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev - run: ./bootstrap - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-oscan1 - - run: make + - run: make -j`nproc` - run: file src/openocd | grep 64-bit + - run: src/openocd --version From 15a72fa644739633ccd071fab840876971228f05 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Jan 2022 23:57:38 +0100 Subject: [PATCH 077/186] server: fix: remove kept_alive() from server loop The kept_alive() action is specific of a server that enjoyed an unscheduled keep_alive and want to communicate it to the keep alive logic to reschedule next keep_alive(). In server loop we are not expected to call kept_alive(). Remove it! This call was erroneously added in commit 94e75e0c06c4. Later, commit 7442b26d45dc properly added the same call in gdb_put_packet(), but incorrectly left the older in place. Change-Id: If476410f870eebfbdaccdb1366ba2e9254e2fdf6 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6836 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server/server.c b/src/server/server.c index 1569f5a2c..3f2970152 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -487,7 +487,6 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } From 36e29f49e1582c4fe32e3e02600c8a49129551e5 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 11:34:12 +0100 Subject: [PATCH 078/186] log: drop global current_time The value of this variable is not shared across functions, so the variable can be local. Change-Id: I00b0444209e81c07bb57fb732f47052ad0596728 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6837 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/helper/log.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/helper/log.c b/src/helper/log.c index 686560742..12f1790e9 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -47,7 +47,6 @@ static FILE *log_output; static struct log_callback *log_callbacks; static int64_t last_time; -static int64_t current_time; static int64_t start; @@ -440,8 +439,7 @@ static void gdb_timeout_warning(int64_t delta_time) void keep_alive(void) { - current_time = timeval_ms(); - + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { @@ -469,7 +467,7 @@ void keep_alive(void) /* reset keep alive timer without sending message */ void kept_alive(void) { - current_time = timeval_ms(); + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; From 99c77806fea2625dfa2b5a3234267634d0342388 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Jan 2022 18:42:33 +0100 Subject: [PATCH 079/186] server: change prototype of add_service() To easily add new methods to a service, pass all the methods through a struct. While there, drop the typedef for the methods and add currently unused new methods to support keep-alive and connections during keep-alive. No change in functionality. Change-Id: I2b5e7140db95021f6e7201e9d631ee340c60b453 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6838 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/gdb_server.c | 13 +++++++++--- src/server/ipdbg.c | 12 +++++++++-- src/server/rtt_server.c | 12 +++++++++-- src/server/server.c | 23 +++++++++----------- src/server/server.h | 36 +++++++++++++++++++++++--------- src/server/tcl_server.c | 13 +++++++++--- src/server/telnet_server.c | 12 +++++++++-- src/target/arm_tpiu_swo.c | 15 +++++++++---- src/target/openrisc/jsp_server.c | 17 ++++++++------- 9 files changed, 107 insertions(+), 46 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 4dee7e864..b76a3ef7d 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3657,6 +3657,15 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +static const struct service_driver gdb_service_driver = { + .name = "gdb", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = gdb_new_connection, + .input_handler = gdb_input, + .connection_closed_handler = gdb_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int gdb_target_start(struct target *target, const char *port) { struct gdb_service *gdb_service; @@ -3673,9 +3682,7 @@ static int gdb_target_start(struct target *target, const char *port) gdb_service->core[1] = -1; target->gdb_service = gdb_service; - ret = add_service("gdb", - port, target->gdb_max_connections, &gdb_new_connection, &gdb_input, - &gdb_connection_closed, gdb_service); + ret = add_service(&gdb_service_driver, port, target->gdb_max_connections, gdb_service); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index ec2fae8c0..3bbcf0714 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -587,6 +587,15 @@ static int ipdbg_on_connection_closed(struct connection *connection) return ipdbg_stop_polling(connection->service->priv); } +static const struct service_driver ipdbg_service_driver = { + .name = "ipdbg", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = ipdbg_on_new_connection, + .input_handler = ipdbg_on_connection_input, + .connection_closed_handler = ipdbg_on_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) { @@ -618,8 +627,7 @@ static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instru char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port); - retval = add_service("ipdbg", port_str_buffer, 1, &ipdbg_on_new_connection, - &ipdbg_on_connection_input, &ipdbg_on_connection_closed, service); + retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service); if (retval == ERROR_OK) { ipdbg_add_service(service); if (hub->active_services == 0 && hub->active_connections == 0) diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index d49e4d000..c7141c0e0 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -110,6 +110,15 @@ static int rtt_input(struct connection *connection) return ERROR_OK; } +static const struct service_driver rtt_service_driver = { + .name = "rtt", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = rtt_new_connection, + .input_handler = rtt_input, + .connection_closed_handler = rtt_connection_closed, + .keep_client_alive_handler = NULL, +}; + COMMAND_HANDLER(handle_rtt_start_command) { int ret; @@ -125,8 +134,7 @@ COMMAND_HANDLER(handle_rtt_start_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); - ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, - rtt_new_connection, rtt_input, rtt_connection_closed, service); + ret = add_service(&rtt_service_driver, CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, service); if (ret != ERROR_OK) { free(service); diff --git a/src/server/server.c b/src/server/server.c index 3f2970152..4ec196728 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -205,13 +205,8 @@ static void free_service(struct service *c) free(c); } -int add_service(char *name, - const char *port, - int max_connections, - new_connection_handler_t new_connection_handler, - input_handler_t input_handler, - connection_closed_handler_t connection_closed_handler, - void *priv) +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv) { struct service *c, **p; struct hostent *hp; @@ -219,14 +214,16 @@ int add_service(char *name, c = malloc(sizeof(struct service)); - c->name = strdup(name); + c->name = strdup(driver->name); c->port = strdup(port); c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */ c->fd = -1; c->connections = NULL; - c->new_connection = new_connection_handler; - c->input = input_handler; - c->connection_closed = connection_closed_handler; + c->new_connection_during_keep_alive = driver->new_connection_during_keep_alive_handler; + c->new_connection = driver->new_connection_handler; + c->input = driver->input_handler; + c->connection_closed = driver->connection_closed_handler; + c->keep_client_alive = driver->keep_client_alive_handler; c->priv = priv; c->next = NULL; long portnumber; @@ -278,7 +275,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", c->name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; @@ -309,7 +306,7 @@ int add_service(char *name, socklen_t addr_in_size = sizeof(addr_in); if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0) LOG_INFO("Listening on port %hu for %s connections", - ntohs(addr_in.sin_port), name); + ntohs(addr_in.sin_port), c->name); } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); diff --git a/src/server/server.h b/src/server/server.h index bacd1116a..00f1a428f 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -55,9 +55,25 @@ struct connection { struct connection *next; }; -typedef int (*new_connection_handler_t)(struct connection *connection); -typedef int (*input_handler_t)(struct connection *connection); -typedef int (*connection_closed_handler_t)(struct connection *connection); +struct service_driver { + /** the name of the server */ + const char *name; + /** optional minimal setup to accept a connection during keep-alive */ + int (*new_connection_during_keep_alive_handler)(struct connection *connection); + /** + * complete code to accept a new connection. + * If 'new_connection_during_keep_alive_handler' above is present, this can be + * either called alone during the server_loop, or after the function above. + * Check the implementation in gdb_server. + * */ + int (*new_connection_handler)(struct connection *connection); + /** callback to handle incoming data */ + int (*input_handler)(struct connection *connection); + /** callback to tear down the connection */ + int (*connection_closed_handler)(struct connection *connection); + /** called periodically to send keep-alive messages on the connection */ + void (*keep_client_alive_handler)(struct connection *connection); +}; struct service { char *name; @@ -68,17 +84,17 @@ struct service { struct sockaddr_in sin; int max_connections; struct connection *connections; - new_connection_handler_t new_connection; - input_handler_t input; - connection_closed_handler_t connection_closed; + int (*new_connection_during_keep_alive)(struct connection *connection); + int (*new_connection)(struct connection *connection); + int (*input)(struct connection *connection); + int (*connection_closed)(struct connection *connection); + void (*keep_client_alive)(struct connection *connection); void *priv; struct service *next; }; -int add_service(char *name, const char *port, - int max_connections, new_connection_handler_t new_connection_handler, - input_handler_t in_handler, connection_closed_handler_t close_handler, - void *priv); +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv); int remove_service(const char *name, const char *port); int server_host_os_entry(void); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index e08823224..458d7eada 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -276,6 +276,15 @@ static int tcl_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver tcl_service_driver = { + .name = "tcl", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = tcl_new_connection, + .input_handler = tcl_input, + .connection_closed_handler = tcl_closed, + .keep_client_alive_handler = NULL, +}; + int tcl_init(void) { if (strcmp(tcl_port, "disabled") == 0) { @@ -283,9 +292,7 @@ int tcl_init(void) return ERROR_OK; } - return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED, - &tcl_new_connection, &tcl_input, - &tcl_closed, NULL); + return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL); } COMMAND_HANDLER(handle_tcl_port_command) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 2ebcff163..791a1a548 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -946,6 +946,15 @@ static int telnet_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver telnet_service_driver = { + .name = "telnet", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = telnet_new_connection, + .input_handler = telnet_input, + .connection_closed_handler = telnet_connection_closed, + .keep_client_alive_handler = NULL, +}; + int telnet_init(char *banner) { if (strcmp(telnet_port, "disabled") == 0) { @@ -963,8 +972,7 @@ int telnet_init(char *banner) telnet_service->banner = banner; - int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, - telnet_new_connection, telnet_input, telnet_connection_closed, + int ret = add_service(&telnet_service_driver, telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_service); if (ret != ERROR_OK) { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index bfe908142..a0eba6782 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -582,6 +582,15 @@ static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap, return mem_ap_read_atomic_u32(tpiu_ap, address, value); } +static const struct service_driver arm_tpiu_swo_service_driver = { + .name = "tpiu_swo_trace", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = arm_tpiu_swo_service_new_connection, + .input_handler = arm_tpiu_swo_service_input, + .connection_closed_handler = arm_tpiu_swo_service_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command *c = jim_to_command(interp); @@ -700,10 +709,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const } priv->obj = obj; LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]); - retval = add_service("tpiu_swo_trace", &obj->out_filename[1], - CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection, - arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed, - priv); + retval = add_service(&arm_tpiu_swo_service_driver, &obj->out_filename[1], + CONNECTION_LIMIT_UNLIMITED, priv); if (retval != ERROR_OK) { LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]); return JIM_ERR; diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index e0a4475cf..54c969424 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -195,19 +195,22 @@ static int jsp_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver jsp_service_driver = { + .name = "jsp", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = jsp_new_connection, + .input_handler = jsp_input, + .connection_closed_handler = jsp_connection_closed, + .keep_client_alive_handler = NULL, +}; + int jsp_init(struct or1k_jtag *jtag_info, char *banner) { struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service)); jsp_service->banner = banner; jsp_service->jtag_info = jtag_info; - return add_service("jsp", - jsp_port, - 1, - jsp_new_connection, - jsp_input, - jsp_connection_closed, - jsp_service); + return add_service(&jsp_service_driver, jsp_port, 1, jsp_service); } COMMAND_HANDLER(handle_jsp_port_command) From 5c26fd7ab8916d25cb876487d39ec45e3c936d55 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 10:08:29 +0100 Subject: [PATCH 080/186] gdb_server: simplify logic to enable/disable gdb_log_callback() GDB client cannot always display generic messages from OpenOCD. The callback gdb_log_callback() is continuously added and removed to follow the GDB status and thus enabling/disabling sending the OpenOCD output to GDB. While this is a nice stress test for log_{add,remove}_callback(), it is also a waste of computational resources that could impact the speed of OpenOCD during GDB user interactions. Add a connection-level flag to enable/disable the log callback and simply change the flag instead of adding/removing the callback. Use an enum for the flag instead of a bool. This improves code readability and allows setting other states, e.g. keep-alive through asynchronous notification https://review.openocd.org/4828/ Change-Id: I072d3c6928dedfd0cef0abe7acf9bdd4b89dbf5b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6839 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/gdb_server.c | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b76a3ef7d..b47e312a3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -61,6 +61,13 @@ * found in most modern embedded processors. */ +enum gdb_output_flag { + /* GDB doesn't accept 'O' packets */ + GDB_OUTPUT_NO, + /* GDB accepts 'O' packets */ + GDB_OUTPUT_ALL, +}; + struct target_desc_format { char *tdesc; uint32_t tdesc_length; @@ -97,6 +104,8 @@ struct gdb_connection { struct target_desc_format target_desc; /* temporarily used for thread list support */ char *thread_list; + /* flag to mask the output from gdb_log_callback() */ + enum gdb_output_flag output_flag; }; #if 0 @@ -478,7 +487,7 @@ static int gdb_put_packet_inner(struct connection *connection, break; else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; @@ -489,7 +498,7 @@ static int gdb_put_packet_inner(struct connection *connection, break; else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -932,7 +941,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec */ if (gdb_connection->frontend_state == TARGET_RUNNING) { /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; /* check fileio first */ if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK) @@ -992,6 +1001,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->target_desc.tdesc = NULL; gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; + gdb_connection->output_flag = GDB_OUTPUT_NO; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -1076,6 +1086,8 @@ static int gdb_new_connection(struct connection *connection) * register callback to be informed about target events */ target_register_event_callback(gdb_target_callback_event_handler, connection); + log_add_callback(gdb_log_callback, connection); + return ERROR_OK; } @@ -2728,7 +2740,7 @@ static int gdb_query_packet(struct connection *connection, cmd[len] = 0; /* We want to print all debug output to GDB connection */ - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_timer_callbacks_now(); /* some commands need to know the GDB connection, make note of current * GDB connection. */ @@ -2736,7 +2748,7 @@ static int gdb_query_packet(struct connection *connection, command_run_line(cmd_ctx, cmd); current_gdb_connection = NULL; target_call_timer_callbacks_now(); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); } gdb_put_packet(connection, "OK", 2); @@ -2917,7 +2929,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == 'c') { gdb_running_type = 'c'; LOG_DEBUG("target %s continue", target_name(target)); - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) LOG_INFO("target %s was not halted when resume was requested", target_name(target)); @@ -3006,7 +3018,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); /* @@ -3027,7 +3039,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p "T05thread:%016"PRIx64";", thread_id); gdb_put_packet(connection, sig_reply, sig_reply_len); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; return true; } @@ -3039,7 +3051,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); gdb_sig_halted(connection); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; return true; @@ -3057,7 +3069,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p /* send back signal information */ gdb_signal_reply(ct, connection); /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; } else { @@ -3387,6 +3399,10 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; + if (gdb_con->output_flag == GDB_OUTPUT_NO) + /* No out allowed */ + return; + if (gdb_con->busy) { /* do not reply this using the O packet */ return; @@ -3489,7 +3505,7 @@ static int gdb_input_inner(struct connection *connection) case 's': { gdb_thread_packet(connection, packet, packet_size); - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; if (gdb_con->mem_write_error) { LOG_ERROR("Memory write failure!"); @@ -3532,7 +3548,7 @@ static int gdb_input_inner(struct connection *connection) gdb_sig_halted(connection); /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; } else { /* We're running/stepping, in which case we can * forward log output until the target is halted @@ -3604,7 +3620,7 @@ static int gdb_input_inner(struct connection *connection) * Fretcode,errno,Ctrl-C flag;call-specific attachment */ gdb_con->frontend_state = TARGET_RUNNING; - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; gdb_fileio_response_packet(connection, packet, packet_size); break; From 4e5dbecd9b1ac780181e04f8b51a4cd133c4cdbe Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 10:51:49 +0100 Subject: [PATCH 081/186] keep-alive: drop link with log framework OpenOCD implements the GDB keep-alive by sending empty strings as output for GDB client. This has been implemented as part of the log framework, creating an odd dependency. Move the keep-alive notifications out of log framework. For the moment, keep keep_alive() inside log.c, but it should be moved in server.c This should also fix an old issue with KDE Konsole when tab alert for activity is enabled. The empty strings is sent to all the connections, including telnet, and causes the tab running OpenOCD telnet to continuously show activity even when no new text is printed. Anyway, I cannot replicate this issue anymore. Change-Id: Iebb00b00fb74b3c9665d9e1ddd3c055275bfbd43 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6840 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/helper/log.c | 36 ++++++++++++++++-------------------- src/server/gdb_server.c | 24 +++++++++++++++++++++++- src/server/server.c | 8 ++++++++ src/server/server.h | 2 ++ 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/helper/log.c b/src/helper/log.c index 12f1790e9..106d22867 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -30,6 +30,7 @@ #include "command.h" #include "replacements.h" #include "time_support.h" +#include #include @@ -110,32 +111,27 @@ static void log_puts(enum log_levels level, if (f) file = f + 1; - if (strlen(string) > 0) { - if (debug_level >= LOG_LVL_DEBUG) { - /* print with count and time information */ - int64_t t = timeval_ms() - start; + if (debug_level >= LOG_LVL_DEBUG) { + /* print with count and time information */ + int64_t t = timeval_ms() - start; #ifdef _DEBUG_FREE_SPACE_ - struct mallinfo info; - info = mallinfo(); + struct mallinfo info; + info = mallinfo(); #endif - fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" + fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" #ifdef _DEBUG_FREE_SPACE_ - " %d" + " %d" #endif - ": %s", log_strings[level + 1], count, t, file, line, function, + ": %s", log_strings[level + 1], count, t, file, line, function, #ifdef _DEBUG_FREE_SPACE_ - info.fordblks, + info.fordblks, #endif - string); - } else { - /* if we are using gdb through pipes then we do not want any output - * to the pipe otherwise we get repeated strings */ - fprintf(log_output, "%s%s", - (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); - } + string); } else { - /* Empty strings are sent to log callbacks to keep e.g. gdbserver alive, here we do - *nothing. */ + /* if we are using gdb through pipes then we do not want any output + * to the pipe otherwise we get repeated strings */ + fprintf(log_output, "%s%s", + (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); } fflush(log_output); @@ -452,7 +448,7 @@ void keep_alive(void) last_time = current_time; /* this will keep the GDB connection alive */ - LOG_USER_N("%s", ""); + server_keep_clients_alive(); /* DANGER!!!! do not add code to invoke e.g. target event processing, * jim timer processing, etc. it can cause infinite recursion + diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b47e312a3..f5736196e 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3673,13 +3673,35 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +static void gdb_keep_client_alive(struct connection *connection) +{ + struct gdb_connection *gdb_con = connection->priv; + + if (gdb_con->busy) { + /* do not send packets, retry asap */ + return; + } + + switch (gdb_con->output_flag) { + case GDB_OUTPUT_NO: + /* no need for keep-alive */ + break; + case GDB_OUTPUT_ALL: + /* send an empty O packet */ + gdb_output_con(connection, ""); + break; + default: + break; + } +} + static const struct service_driver gdb_service_driver = { .name = "gdb", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = gdb_new_connection, .input_handler = gdb_input, .connection_closed_handler = gdb_connection_closed, - .keep_client_alive_handler = NULL, + .keep_client_alive_handler = gdb_keep_client_alive, }; static int gdb_target_start(struct target *target, const char *port) diff --git a/src/server/server.c b/src/server/server.c index 4ec196728..dd408048c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -421,6 +421,14 @@ static int remove_services(void) return ERROR_OK; } +void server_keep_clients_alive(void) +{ + for (struct service *s = services; s; s = s->next) + if (s->keep_client_alive) + for (struct connection *c = s->connections; c; c = c->next) + s->keep_client_alive(c); +} + int server_loop(struct command_context *command_context) { struct service *service; diff --git a/src/server/server.h b/src/server/server.h index 00f1a428f..a6b1963a6 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -106,6 +106,8 @@ int server_quit(void); void server_free(void); void exit_on_signal(int sig); +void server_keep_clients_alive(void); + int server_loop(struct command_context *command_context); int server_register_commands(struct command_context *context); From b9526f1401271a00dd72cf7ec8bded32e77d41ff Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 6 Apr 2020 13:30:26 +0100 Subject: [PATCH 082/186] semihosting: permit redirection of semihosting I/O to TCP This command permits the usage of a TCP port to perform debug and stdio operations: - debug : READC, WRITEC and WRITE0 - stdio : READ, WRITE This will permit the separation of semihosting message from OpenOCD log, and separate semihosting messages per core. syntax: arm semihosting_redirect (disable | tcp [debug|stdio|all]) this allows to select which operations to be performed via TCP (debug, stdio or all (default)). Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. tested using netcat on ubuntu Change-Id: I37053463667ba109d52429d4f98bc98d0ede298d Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/5562 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 11 ++ src/target/semihosting_common.c | 332 ++++++++++++++++++++++++++++++-- src/target/semihosting_common.h | 17 ++ 3 files changed, 343 insertions(+), 17 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 0cd9621ff..1b6d06302 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9370,6 +9370,17 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn +@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} +[@option{debug}|@option{stdio}|@option{all}) +@cindex ARM semihosting +Redirect semihosting messages to a specified TCP port. + +This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE) +semihosting operations to the specified TCP port. +The command allows to select which type of operations to redirect (debug, stdio, all (default)). +Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. +@end deffn + @deffn {Command} {arm semihosting_cmdline} [@option{enable}|@option{disable}] @cindex ARM semihosting Set the command line to be passed to the debugger. diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 9e60de572..38035e493 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -129,6 +129,11 @@ int semihosting_common_init(struct target *target, void *setup, } semihosting->is_active = false; + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + semihosting->tcp_connection = NULL; + semihosting->stdin_fd = -1; + semihosting->stdout_fd = -1; + semihosting->stderr_fd = -1; semihosting->is_fileio = false; semihosting->hit_fileio = false; semihosting->is_resumable = false; @@ -154,6 +159,141 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +struct semihosting_tcp_service { + struct semihosting *semihosting; + char *name; + int error; +}; + +static bool semihosting_is_redirected(struct semihosting *semihosting, int fd) +{ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE) + return false; + + bool is_read_op = false; + + switch (semihosting->op) { + /* check debug semihosting operations: READC, WRITEC and WRITE0 */ + case SEMIHOSTING_SYS_READC: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITEC: + case SEMIHOSTING_SYS_WRITE0: + /* debug operations are redirected when CFG is either DEBUG or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO) + return false; + break; + + /* check stdio semihosting operations: READ and WRITE */ + case SEMIHOSTING_SYS_READ: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITE: + /* stdio operations are redirected when CFG is either STDIO or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG) + return false; + break; + + default: + return false; + } + + if (is_read_op) + return fd == semihosting->stdin_fd; + + /* write operation */ + return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd; +} + +static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + int retval = connection_write(semihosting->tcp_connection, buf, size); + + if (retval < 0) + log_socket_error(service->name); + + return retval; +} + +static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, buf, size); + + /* default write */ + return write(fd, buf, size); +} + +static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + service->error = ERROR_OK; + semihosting->tcp_connection->input_pending = true; + + int retval = connection_read(semihosting->tcp_connection, buf, size); + + if (retval <= 0) + service->error = ERROR_SERVER_REMOTE_CLOSED; + + if (retval < 0) + log_socket_error(service->name); + + semihosting->tcp_connection->input_pending = false; + + return retval; +} + +static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, &c, 1); + + /* default putchar */ + return putchar(c); +} + +static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_read(semihosting, buf, size); + + /* default read */ + ssize_t result = read(fd, buf, size); + semihosting->sys_errno = errno; + + return result; +} + +static inline int semihosting_getchar(struct semihosting *semihosting, int fd) +{ + if (semihosting_is_redirected(semihosting, fd)) { + unsigned char c; + + if (semihosting_redirect_read(semihosting, &c, 1) > 0) + return c; + + return EOF; + } + + /* default getchar */ + return getchar(); +} + /** * User operation parameter string storage buffer. Contains valid data when the * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. @@ -756,20 +896,23 @@ int semihosting_common(struct target *target) * - 4-7 ("w") for stdout, * - 8-11 ("a") for stderr */ if (mode < 4) { - semihosting->result = dup( - STDIN_FILENO); + int fd = dup(STDIN_FILENO); + semihosting->result = fd; + semihosting->stdin_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDIN)=%d", (int)semihosting->result); } else if (mode < 8) { - semihosting->result = dup( - STDOUT_FILENO); + int fd = dup(STDOUT_FILENO); + semihosting->result = fd; + semihosting->stdout_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDOUT)=%d", (int)semihosting->result); } else { - semihosting->result = dup( - STDERR_FILENO); + int fd = dup(STDERR_FILENO); + semihosting->result = fd; + semihosting->stderr_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDERR)=%d", (int)semihosting->result); @@ -845,8 +988,7 @@ int semihosting_common(struct target *target) semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { - semihosting->result = read(fd, buf, len); - semihosting->sys_errno = errno; + semihosting->result = semihosting_read(semihosting, fd, buf, len); LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d", fd, addr, @@ -886,7 +1028,7 @@ int semihosting_common(struct target *target) LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } - semihosting->result = getchar(); + semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); LOG_DEBUG("getchar()=%d", (int)semihosting->result); break; @@ -1189,7 +1331,7 @@ int semihosting_common(struct target *target) free(buf); return retval; } - semihosting->result = write(fd, buf, len); + semihosting->result = semihosting_write(semihosting, fd, buf, len); semihosting->sys_errno = errno; LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d", fd, @@ -1234,7 +1376,7 @@ int semihosting_common(struct target *target) retval = target_read_memory(target, addr, 1, 1, &c); if (retval != ERROR_OK) return retval; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); semihosting->result = 0; } break; @@ -1278,7 +1420,7 @@ int semihosting_common(struct target *target) return retval; if (!c) break; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); } while (1); semihosting->result = 0; } @@ -1557,6 +1699,70 @@ static void semihosting_set_field(struct target *target, uint64_t value, target_buffer_set_u32(target, fields + (index * 4), value); } +/* ------------------------------------------------------------------------- + * Semihosting redirect over TCP structs and functions */ + +static int semihosting_service_new_connection_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + service->semihosting->tcp_connection = connection; + + return ERROR_OK; +} + +static int semihosting_service_input_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + + if (!connection->input_pending) { + /* consume received data, not for semihosting IO */ + const int buf_len = 100; + char buf[buf_len]; + int bytes_read = connection_read(connection, buf, buf_len); + + if (bytes_read == 0) { + return ERROR_SERVER_REMOTE_CLOSED; + } else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + } else if (service->error != ERROR_OK) { + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int semihosting_service_connection_closed_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + if (service) { + free(service->name); + free(service); + } + + return ERROR_OK; +} + +static void semihosting_tcp_close_cnx(struct semihosting *semihosting) +{ + if (!semihosting->tcp_connection) + return; + + struct service *service = semihosting->tcp_connection->service; + remove_service(service->name, service->port); + semihosting->tcp_connection = NULL; + +} + +static const struct service_driver semihosting_service_driver = { + .name = "semihosting", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = semihosting_service_new_connection_handler, + .input_handler = semihosting_service_input_handler, + .connection_closed_handler = semihosting_service_connection_closed_handler, + .keep_client_alive_handler = NULL, +}; /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ @@ -1602,6 +1808,91 @@ COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_redirect_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (target == NULL) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + command_print(CMD, "semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + enum semihosting_redirect_config cfg; + const char *port; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[0], "disable") == 0) { + cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + port = CMD_ARGV[1]; + + cfg = SEMIHOSTING_REDIRECT_CFG_ALL; + if (CMD_ARGC == 3) { + if (strcmp(CMD_ARGV[2], "debug") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG; + else if (strcmp(CMD_ARGV[2], "stdio") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_STDIO; + else if (strcmp(CMD_ARGV[2], "all") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + semihosting_tcp_close_cnx(semihosting); + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + + if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) { + struct semihosting_tcp_service *service = + calloc(1, sizeof(struct semihosting_tcp_service)); + if (!service) { + LOG_ERROR("Failed to allocate semihosting TCP service."); + return ERROR_FAIL; + } + + service->semihosting = semihosting; + + service->name = alloc_printf("%s semihosting service", target_name(target)); + if (!service->name) { + LOG_ERROR("Out of memory"); + free(service); + return ERROR_FAIL; + } + + int ret = add_service(&semihosting_service_driver, + port, 1, service); + + if (ret != ERROR_OK) { + LOG_ERROR("failed to initialize %s", service->name); + free(service->name); + free(service); + return ERROR_FAIL; + } + } + + semihosting->redirect_cfg = cfg; + + return ERROR_OK; +} + COMMAND_HANDLER(handle_common_semihosting_fileio_command) { struct target *target = get_current_target(CMD_CTX); @@ -1721,35 +2012,42 @@ COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) const struct command_registration semihosting_common_handlers[] = { { - "semihosting", + .name = "semihosting", .handler = handle_common_semihosting_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, { - "semihosting_cmdline", + .name = "semihosting_redirect", + .handler = handle_common_semihosting_redirect_command, + .mode = COMMAND_EXEC, + .usage = "(disable | tcp ['debug'|'stdio'|'all'])", + .help = "redirect semihosting IO", + }, + { + .name = "semihosting_cmdline", .handler = handle_common_semihosting_cmdline, .mode = COMMAND_EXEC, .usage = "arguments", .help = "command line arguments to be passed to program", }, { - "semihosting_fileio", + .name = "semihosting_fileio", .handler = handle_common_semihosting_fileio_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting fileio operations", }, { - "semihosting_resexit", + .name = "semihosting_resexit", .handler = handle_common_semihosting_resumable_exit_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, { - "semihosting_read_user_param", + .name = "semihosting_read_user_param", .handler = handle_common_semihosting_read_user_param_command, .mode = COMMAND_EXEC, .usage = "", diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 6eb9ca252..459faf656 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -26,6 +26,7 @@ #include #include #include "helper/replacements.h" +#include /* * According to: @@ -95,6 +96,13 @@ enum semihosting_reported_exceptions { ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35), }; +enum semihosting_redirect_config { + SEMIHOSTING_REDIRECT_CFG_NONE, + SEMIHOSTING_REDIRECT_CFG_DEBUG, + SEMIHOSTING_REDIRECT_CFG_STDIO, + SEMIHOSTING_REDIRECT_CFG_ALL, +}; + struct target; /* @@ -105,6 +113,15 @@ struct semihosting { /** A flag reporting whether semihosting is active. */ bool is_active; + /** Semihosting STDIO file descriptors */ + int stdin_fd, stdout_fd, stderr_fd; + + /** redirection configuration, NONE by default */ + enum semihosting_redirect_config redirect_cfg; + + /** Handle to redirect semihosting print via tcp */ + struct connection *tcp_connection; + /** A flag reporting whether semihosting fileio is active. */ bool is_fileio; From 414c469cdaef60eeea02dc54a94eb904555cf35d Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 2 Feb 2022 23:28:50 +0100 Subject: [PATCH 083/186] stlink: enable queuing with stlink-server API v3 ST-Link Server 2.1.0-1 fixes concurrency issue with RW_MISC command Starting from this version the ST-Link Server API is now v3. In this change we save the ST-Link Server version, and check if the API is greater or equal to 3 to enable the queuing. Change-Id: I239eb81024700514c607a269b66651f457206faa Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6876 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/stlink_usb.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 2f61bf946..325848f86 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -156,6 +156,13 @@ struct stlink_usb_priv_s { struct libusb_transfer *trans; }; +struct stlink_tcp_version { + uint32_t api; + uint32_t major; + uint32_t minor; + uint32_t build; +}; + struct stlink_tcp_priv_s { /** */ int fd; @@ -169,6 +176,8 @@ struct stlink_tcp_priv_s { uint8_t *send_buf; /** */ uint8_t *recv_buf; + /** */ + struct stlink_tcp_version version; }; struct stlink_backend_s { @@ -3532,16 +3541,19 @@ static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) return ERROR_FAIL; } - uint32_t api_ver = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); - uint32_t ver_major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); - uint32_t ver_minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); - uint32_t ver_build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); + h->tcp_backend_priv.version.api = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); + h->tcp_backend_priv.version.major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + h->tcp_backend_priv.version.minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); + h->tcp_backend_priv.version.build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); LOG_INFO("stlink-server API v%d, version %d.%d.%d", - api_ver, ver_major, ver_minor, ver_build); + h->tcp_backend_priv.version.api, + h->tcp_backend_priv.version.major, + h->tcp_backend_priv.version.minor, + h->tcp_backend_priv.version.build); /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server * to crash in windows: select a safe default value (1K) */ - if (api_ver < 2) + if (h->tcp_backend_priv.version.api < 2) h->max_mem_packet = (1 << 10); /* refresh stlink list (re-enumerate) */ @@ -4468,11 +4480,12 @@ static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue * if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) return 0; /* - * RW_MISC sequence doesn't lock the st-link, so are not safe in shared mode. + * Before stlink-server API v3, RW_MISC sequence doesn't lock the st-link, + * so are not safe in shared mode. * Don't use it with TCP backend to prevent any issue in case of sharing. * This further degrades the performance, on top of TCP server overhead. */ - if (h->backend == &stlink_tcp_backend) + if (h->backend == &stlink_tcp_backend && h->tcp_backend_priv.version.api < 3) return 0; for (i = 0; i < len; i++) { From 9cdbe61aab418bdf75bc443b16ce4cdf96732e3e Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Thu, 16 Sep 2021 17:47:31 +0100 Subject: [PATCH 084/186] tcl/stm32u5x: fix clock config used at 'reset init' Change-Id: If004a04b93be47439809ea3fa336b14de7a12277 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6597 Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/target/stm32u5x.cfg | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg index b627d4180..44b51e2b6 100644 --- a/tcl/target/stm32u5x.cfg +++ b/tcl/target/stm32u5x.cfg @@ -22,21 +22,24 @@ proc stm32u5x_clock_config {} { # RCC_AHB3ENR = PWREN mww [expr {0x46020C94 + $offset}] 0x00000004 # delay for register clock enable (read back reg) - mrw [expr {0x56020C94 + $offset}] + mrw [expr {0x46020C94 + $offset}] # PWR_VOSR : VOS Range 1 - mww [expr {0x4602080C + $offset}] 0x00030000 - # delay for register write (read back reg) - mrw [expr {0x4602080C + $offset}] + mmw [expr {0x4602080C + $offset}] 0x00030000 0 + # while !(PWR_VOSR & VOSRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00008000)} {} # FLASH_ACR : 4 WS for 160 MHz HCLK mww [expr {0x40022000 + $offset}] 0x00000004 - # RCC_PLL1CFGR => PLL1M=0000=/1, PLL1SRC=MSI 4MHz - mww [expr {0x46020C28 + $offset}] 0x00000001 + # RCC_PLL1CFGR => PLL1MBOOST=0, PLL1M=0=/1, PLL1FRACEN=0, PLL1SRC=MSI 4MHz + # PLL1REN=1, PLL1RGE => VCOInputRange=PLLInputRange_4_8 + mww [expr {0x46020C28 + $offset}] 0x00040009 + # Enable EPOD Booster + mmw [expr {0x4602080C + $offset}] 0x00040000 0 + # while !(PWR_VOSR & BOOSTRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00004000)} {} # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 # fVCO = 4 x 80 /1 = 320 # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz - mmw [expr {0x46020C34 + $offset}] 0x0000004F 0 - # RCC_PLL1CFGR => PLL1REN=1 - mmw [expr {0x46020C28 + $offset}] 0x00040000 0 + mww [expr {0x46020C34 + $offset}] 0x0101024F # RCC_CR |= PLL1ON mmw [expr {0x46020C00 + $offset}] 0x01000000 0 # while !(RCC_CR & PLL1RDY) From ab43721be6ff7470ff8b9771c95c1d5661a5a689 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 28 Feb 2022 13:55:26 +0100 Subject: [PATCH 085/186] flash/stm32l4x: fix auto-probe when RDP is promoted from 0 to 0.5 Considering this use case: (using STM32 L5 or U5) 1- first probe : TZEN enabled, RDP level 0 flash_regs_base |= STM32L5_REGS_SEC_OFFSET => 0x50022000 2- the user promotes the RDP to level 0.5 3- the second probe, fails to read OPTR using secure flags_regs_base: used OPTR address is 0x50022040 Step 3 fails because when RDP is level 0.5, we should use Non-Secure flash registers. To fix this, always use NS flash regs to read OPTR in probe functions. Fixes: 80d323c6e82b (flash/stm32l4x: introduce auto-probe when OPTR is changed) Change-Id: I296aa633972b0c410b927488c999584a07b912d3 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6864 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/stm32l4x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fd0338899..7b35a0635 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1757,7 +1757,7 @@ static int stm32l4_probe(struct flash_bank *bank) * Ask the flash infrastructure to ensure required alignment */ bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width; - /* initialise the flash registers layout */ + /* Initialize the flash registers layout */ if (part_info->flags & F_HAS_L5_FLASH_REGS) stm32l4_info->flash_regs = stm32l5_ns_flash_regs; else @@ -1770,7 +1770,7 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_sync_rdp_tzen(bank); - /* for devices with trustzone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ + /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { if (part_info->flags & F_HAS_L5_FLASH_REGS) { stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET; @@ -2046,8 +2046,19 @@ static int stm32l4_auto_probe(struct flash_bank *bank) if (stm32l4_info->probed) { uint32_t optr_cur; + /* save flash_regs_base */ + uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base; + + /* for devices with TrustZone, use NS flash registers to read OPTR */ + if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) + stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET; + /* read flash option register and re-probe if optr value is changed */ int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur); + + /* restore saved flash_regs_base */ + stm32l4_info->flash_regs_base = saved_flash_regs_base; + if (retval != ERROR_OK) return retval; From fb43f1ff4e2f0638110ffcc4e63bee8b5361db64 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 13 Jun 2021 11:21:18 +0200 Subject: [PATCH 086/186] target: Rework 'set' variable of break-/watchpoints The 'set' variable name suggests a boolean data type which determines whether a breakpoint (or watchpoint) is active. However, it is also used to store the number of the breakpoint. This encoding leads to inconsistent value assignments: boolean and integer values are mixed. Also, associated hardware comparator numbers, which are usually numbered from 0, cannot be used directly. An additional offset is required to store the comparator numbers. In order to make the code more readable and the value assignment more consistent, change the variable name to 'is_set', its data type to 'bool' and introduce a dedicated variable for the break-/watchpoint number. In order to make the review easier, the data types of various related variables (e.g. number of breakpoints) are not changed. While at it, fix a few coding style issues. Change-Id: I2193f5639247cce6b80580d4c1c6afee916aeb82 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6319 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 48 +++++++++++++++++------------------ src/target/arc.c | 38 ++++++++++++++-------------- src/target/arm7_9_common.c | 49 ++++++++++++++++++------------------ src/target/arm_dpm.c | 6 ++--- src/target/armv8_dpm.c | 6 ++--- src/target/breakpoints.c | 6 ++--- src/target/breakpoints.h | 18 +++++++++++-- src/target/cortex_a.c | 48 +++++++++++++++++------------------ src/target/cortex_m.c | 42 +++++++++++++++---------------- src/target/esirisc.c | 16 ++++++------ src/target/lakemont.c | 4 +-- src/target/mips_m4k.c | 34 ++++++++++++------------- src/target/mips_mips64.c | 33 ++++++++++++------------ src/target/nds32.c | 2 +- src/target/nds32_v3_common.c | 6 ++--- src/target/openrisc/or1k.c | 8 +++--- src/target/riscv/riscv.c | 14 +++++------ src/target/stm8.c | 34 ++++++++++++------------- src/target/target.c | 16 ++++++------ src/target/x86_32_common.c | 30 +++++++++++----------- src/target/xscale.c | 42 ++++++++++++++++--------------- 21 files changed, 258 insertions(+), 242 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index a45322d2f..8838da927 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1236,7 +1236,7 @@ static int aarch64_set_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1249,7 +1249,7 @@ static int aarch64_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1333,7 +1333,7 @@ static int aarch64_set_breakpoint(struct target *target, breakpoint->address & 0xFFFFFFFFFFFFFFFE, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } /* Ensure that halting debug mode is enable */ @@ -1357,7 +1357,7 @@ static int aarch64_set_context_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1371,7 +1371,7 @@ static int aarch64_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) @@ -1410,7 +1410,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1435,7 +1435,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; + breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) @@ -1490,16 +1490,16 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; + int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1549,12 +1549,12 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br return retval; breakpoint->linked_brp = 0; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1579,7 +1579,7 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { @@ -1611,7 +1611,7 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br breakpoint->address & 0xFFFFFFFFFFFFFFFE, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1676,7 +1676,7 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { aarch64_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available++; @@ -1696,7 +1696,7 @@ static int aarch64_set_watchpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1764,7 +1764,7 @@ static int aarch64_set_watchpoint(struct target *target, } wp_list[wp_i].used = 1; - watchpoint->set = wp_i + 1; + watchpoint_set(watchpoint, wp_i); return ERROR_OK; } @@ -1773,18 +1773,18 @@ static int aarch64_set_watchpoint(struct target *target, static int aarch64_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { - int retval, wp_i; + int retval; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - wp_i = watchpoint->set - 1; - if ((wp_i < 0) || (wp_i >= aarch64->wp_num)) { + int wp_i = watchpoint->number; + if (wp_i >= aarch64->wp_num) { LOG_DEBUG("Invalid WP number in watchpoint"); return ERROR_OK; } @@ -1809,7 +1809,7 @@ static int aarch64_unset_watchpoint(struct target *target, (uint32_t)wp_list[wp_i].value); if (retval != ERROR_OK) return retval; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -1837,7 +1837,7 @@ static int aarch64_remove_watchpoint(struct target *target, { struct aarch64_common *aarch64 = target_to_aarch64(target); - if (watchpoint->set) { + if (watchpoint->is_set) { aarch64_unset_watchpoint(target, watchpoint); aarch64->wp_num_available++; } diff --git a/src/target/arc.c b/src/target/arc.c index 4b546c3b4..471f16a98 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1500,7 +1500,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1542,7 +1542,7 @@ static int arc_set_breakpoint(struct target *target, return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 64; /* Any nice value but 0 */ + breakpoint->is_set = true; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; @@ -1563,7 +1563,7 @@ static int arc_set_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); ap_list[bp_num].used = 1; ap_list[bp_num].bp_value = breakpoint->address; ap_list[bp_num].type = ARC_AP_BREAKPOINT; @@ -1588,7 +1588,7 @@ static int arc_unset_breakpoint(struct target *target, { int retval = ERROR_OK; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1633,14 +1633,14 @@ static int arc_unset_breakpoint(struct target *target, LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 0; + breakpoint->is_set = false; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - unsigned int bp_num = breakpoint->set - 1; + unsigned int bp_num = breakpoint->number; - if ((breakpoint->set == 0) || (bp_num >= arc->actionpoints_num)) { + if (bp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; @@ -1650,11 +1650,11 @@ static int arc_unset_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = 0; + breakpoint->is_set = false; ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; - LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %i", + LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { @@ -1684,7 +1684,7 @@ static int arc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { - if (breakpoint->set) + if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { LOG_WARNING("target not halted"); @@ -1818,7 +1818,7 @@ static int arc_set_watchpoint(struct target *target, struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1859,7 +1859,7 @@ static int arc_set_watchpoint(struct target *target, watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); ap_list[wp_num].used = 1; ap_list[wp_num].bp_value = watchpoint->address; ap_list[wp_num].type = ARC_AP_WATCHPOINT; @@ -1878,13 +1878,13 @@ static int arc_unset_watchpoint(struct target *target, struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - unsigned int wp_num = watchpoint->set - 1; - if ((watchpoint->set == 0) || (wp_num >= arc->actionpoints_num)) { + unsigned int wp_num = watchpoint->number; + if (wp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, wp_num, watchpoint->unique_id); return ERROR_OK; @@ -1894,7 +1894,7 @@ static int arc_unset_watchpoint(struct target *target, watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { - watchpoint->set = 0; + watchpoint->is_set = false; ap_list[wp_num].used = 0; ap_list[wp_num].bp_value = 0; @@ -1926,7 +1926,7 @@ static int arc_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint)); return ERROR_OK; @@ -1953,8 +1953,8 @@ static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_wat watchpoint = watchpoint->next) { if (actionpoint->bp_value == watchpoint->address) { *hit_watchpoint = watchpoint; - LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %i", - watchpoint->unique_id, watchpoint->set - 1); + LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", + watchpoint->unique_id, watchpoint->number); return ERROR_OK; } } diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index cf77a81a7..da047c3d0 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -93,19 +93,20 @@ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *br { if (!arm7_9->wp0_used) { arm7_9->wp0_used = 1; - breakpoint->set = 1; + breakpoint_hw_set(breakpoint, 0); arm7_9->wp_available--; } else if (!arm7_9->wp1_used) { arm7_9->wp1_used = 1; - breakpoint->set = 2; + breakpoint_hw_set(breakpoint, 1); arm7_9->wp_available--; - } else + } else { LOG_ERROR("BUG: no hardware comparator available"); + } - LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %d", + LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %u", breakpoint->unique_id, breakpoint->address, - breakpoint->set); + breakpoint->number); } /** @@ -203,16 +204,16 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break uint32_t mask = (breakpoint->length == 4) ? 0x3u : 0x1u; /* reassign a hw breakpoint */ - if (breakpoint->set == 0) + if (!breakpoint->is_set) arm7_9_assign_wp(arm7_9, breakpoint); - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->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], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->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], 0xffffffffu); @@ -226,7 +227,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break retval = jtag_execute_queue(); } else if (breakpoint->type == BKPT_SOFT) { /* did we already set this breakpoint? */ - if (breakpoint->set) + if (breakpoint->is_set) return ERROR_OK; if (breakpoint->length == 4) { @@ -277,7 +278,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break arm7_9->sw_breakpoint_count++; - breakpoint->set = 1; + breakpoint->is_set = true; } return retval; @@ -304,7 +305,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre breakpoint->unique_id, breakpoint->address); - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -312,18 +313,18 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre if (breakpoint->type == BKPT_HARD) { LOG_DEBUG("BPID: %" PRIu32 " Releasing hw wp: %d", breakpoint->unique_id, - breakpoint->set); - if (breakpoint->set == 1) { + breakpoint->is_set); + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); arm7_9->wp0_used = 0; arm7_9->wp_available++; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->wp1_used = 0; arm7_9->wp_available++; } retval = jtag_execute_queue(); - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -368,7 +369,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre EICE_W1_CONTROL_VALUE], 0); } - breakpoint->set = 0; + breakpoint->is_set = false; } return retval; @@ -491,7 +492,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 1; + watchpoint_set(watchpoint, 1); arm7_9->wp0_used = 2; } else if (!arm7_9->wp1_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], @@ -510,7 +511,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 2; + watchpoint_set(watchpoint, 2); arm7_9->wp1_used = 2; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -538,25 +539,25 @@ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *wat return ERROR_TARGET_NOT_HALTED; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -597,7 +598,7 @@ int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoin int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); - if (watchpoint->set) { + if (watchpoint->is_set) { retval = arm7_9_unset_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -1684,7 +1685,7 @@ static void arm7_9_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) arm7_9_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 3e55e2e3a..e60ef225d 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -398,7 +398,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) * or running debugger code. */ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -473,7 +473,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -485,7 +485,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 188e58822..765f1b777 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -818,7 +818,7 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) * or running debugger code. */ static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -892,7 +892,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -904,7 +904,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 8439ff395..79c68fea8 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -71,7 +71,7 @@ static int breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -134,7 +134,7 @@ static int context_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -188,7 +188,7 @@ static int hybrid_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index b4a3511d2..b97be718c 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -39,7 +39,8 @@ struct breakpoint { uint32_t asid; int length; enum breakpoint_type type; - int set; + bool is_set; + unsigned int number; uint8_t *orig_instr; struct breakpoint *next; uint32_t unique_id; @@ -52,7 +53,8 @@ struct watchpoint { uint32_t mask; uint32_t value; enum watchpoint_rw rw; - int set; + bool is_set; + unsigned int number; struct watchpoint *next; int unique_id; }; @@ -69,6 +71,12 @@ void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); +inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) +{ + breakpoint->is_set = true; + breakpoint->number = hw_number; +} + void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, @@ -79,4 +87,10 @@ void watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address); +inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) +{ + watchpoint->is_set = true; + watchpoint->number = number; +} + #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 272411359..2dc109108 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1185,7 +1185,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; - stepbreakpoint.set = 0; + stepbreakpoint.is_set = false; /* Disable interrupts during single step if requested */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { @@ -1265,7 +1265,7 @@ static int cortex_a_set_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1277,7 +1277,7 @@ static int cortex_a_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1342,7 +1342,7 @@ static int cortex_a_set_breakpoint(struct target *target, armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1359,7 +1359,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1373,7 +1373,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; @@ -1411,7 +1411,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1436,7 +1436,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; + breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) @@ -1485,16 +1485,16 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; + int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1533,12 +1533,12 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b if (retval != ERROR_OK) return retval; breakpoint->linked_brp = 0; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1557,7 +1557,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { @@ -1589,7 +1589,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1655,7 +1655,7 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { cortex_a_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available++; @@ -1688,7 +1688,7 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return retval; } @@ -1741,7 +1741,7 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat break; } - watchpoint->set = wrp_i + 1; + watchpoint_set(watchpoint, wrp_i); control = (address_mask << 24) | (byte_address_select << 5) | (load_store_access_control << 3) | @@ -1784,13 +1784,13 @@ static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *w struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wrp_i = watchpoint->set - 1; - if (wrp_i < 0 || wrp_i >= cortex_a->wrp_num) { + int wrp_i = watchpoint->number; + if (wrp_i >= cortex_a->wrp_num) { LOG_DEBUG("Invalid WRP number in watchpoint"); return ERROR_OK; } @@ -1809,7 +1809,7 @@ static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *w wrp_list[wrp_i].value); if (retval != ERROR_OK) return retval; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -1851,7 +1851,7 @@ static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint * { struct cortex_a_common *cortex_a = target_to_cortex_a(target); - if (watchpoint->set) { + if (watchpoint->is_set) { cortex_a->wrp_num_available++; cortex_a_unset_watchpoint(target, watchpoint); } diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 108f7e790..344cfcf61 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1090,7 +1090,7 @@ void cortex_m_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) cortex_m_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1578,7 +1578,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } @@ -1591,7 +1591,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = fp_num + 1; + breakpoint_hw_set(breakpoint, fp_num); fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { @@ -1643,15 +1643,15 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint code); if (retval != ERROR_OK) return retval; - breakpoint->set = true; + breakpoint->is_set = true; } - LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); return ERROR_OK; } @@ -1662,20 +1662,20 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (breakpoint->set <= 0) { + if (!breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } - LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); if (breakpoint->type == BKPT_HARD) { - unsigned int fp_num = breakpoint->set - 1; + unsigned int fp_num = breakpoint->number; if (fp_num >= cortex_m->fp_num_code) { LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; @@ -1692,7 +1692,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi if (retval != ERROR_OK) return retval; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -1714,7 +1714,7 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) return ERROR_OK; return cortex_m_unset_breakpoint(target, breakpoint); @@ -1741,7 +1741,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat return ERROR_FAIL; } comparator->used = true; - watchpoint->set = dwt_num + 1; + watchpoint_set(watchpoint, dwt_num); comparator->comp = watchpoint->address; target_write_u32(target, comparator->dwt_comparator_address + 0, @@ -1808,15 +1808,15 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_dwt_comparator *comparator; - if (watchpoint->set <= 0) { + if (!watchpoint->is_set) { LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } - unsigned int dwt_num = watchpoint->set - 1; + unsigned int dwt_num = watchpoint->number; - LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); @@ -1831,7 +1831,7 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -1895,7 +1895,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; @@ -1912,10 +1912,10 @@ int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watch struct cortex_m_common *cortex_m = target_to_cm(target); for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { - if (!wp->set) + if (!wp->is_set) continue; - unsigned int dwt_num = wp->set - 1; + unsigned int dwt_num = wp->number; struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num; uint32_t dwt_function; @@ -1939,7 +1939,7 @@ void cortex_m_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (!watchpoint->set) + if (!watchpoint->is_set) cortex_m_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/esirisc.c b/src/target/esirisc.c index e49f5f659..aadd111ee 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -504,7 +504,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_index + 1; + breakpoint_hw_set(breakpoint, bp_index); esirisc->breakpoints_p[bp_index] = breakpoint; /* specify instruction breakpoint address */ @@ -540,7 +540,7 @@ static int esirisc_add_breakpoints(struct target *target) LOG_DEBUG("-"); while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) esirisc_add_breakpoint(target, breakpoint); breakpoint = breakpoint->next; @@ -553,7 +553,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int bp_index = breakpoint->set - 1; + unsigned int bp_index = breakpoint->number; uint32_t ibc; int retval; @@ -575,7 +575,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b } esirisc->breakpoints_p[bp_index] = NULL; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -630,7 +630,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc return ERROR_FAIL; } - watchpoint->set = wp_index + 1; + watchpoint_set(watchpoint, wp_index); esirisc->watchpoints_p[wp_index] = watchpoint; /* specify data breakpoint address */ @@ -724,7 +724,7 @@ static int esirisc_add_watchpoints(struct target *target) LOG_DEBUG("-"); while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) esirisc_add_watchpoint(target, watchpoint); watchpoint = watchpoint->next; @@ -737,7 +737,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int wp_index = watchpoint->set - 1; + unsigned int wp_index = watchpoint->number; uint32_t dbc; int retval; @@ -759,7 +759,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w } esirisc->watchpoints_p[wp_index] = NULL; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } diff --git a/src/target/lakemont.c b/src/target/lakemont.c index e46ee5cf8..230f53fe0 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -1024,10 +1024,10 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, /* if breakpoints are enabled, we need to redirect these into probe mode */ struct breakpoint *activeswbp = t->breakpoints; - while (activeswbp && activeswbp->set == 0) + while (activeswbp && !activeswbp->is_set) activeswbp = activeswbp->next; struct watchpoint *activehwbp = t->watchpoints; - while (activehwbp && activehwbp->set == 0) + while (activehwbp && !activehwbp->is_set) activehwbp = activehwbp->next; if (activeswbp || activehwbp) buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 8627bce6e..860119345 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -593,7 +593,7 @@ static void mips_m4k_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) mips_m4k_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -607,7 +607,7 @@ static int mips_m4k_set_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -622,7 +622,7 @@ static int mips_m4k_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; @@ -724,7 +724,7 @@ static int mips_m4k_set_breakpoint(struct target *target, } } - breakpoint->set = 20; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -739,14 +739,14 @@ static int mips_m4k_unset_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= mips32->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -813,7 +813,7 @@ static int mips_m4k_unset_breakpoint(struct target *target, } } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -851,7 +851,7 @@ static int mips_m4k_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) mips_m4k_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -875,7 +875,7 @@ static int mips_m4k_set_watchpoint(struct target *target, int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -911,7 +911,7 @@ static int mips_m4k_set_watchpoint(struct target *target, LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } - watchpoint->set = wp_num + 1; + watchpoint->number = wp_num; comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; @@ -946,13 +946,13 @@ static int mips_m4k_unset_watchpoint(struct target *target, struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips32->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -960,7 +960,7 @@ static int mips_m4k_unset_watchpoint(struct target *target, comparator_list[wp_num].bp_value = 0; target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbc_offs, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -991,7 +991,7 @@ static int mips_m4k_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) mips_m4k_unset_watchpoint(target, watchpoint); mips32->num_data_bpoints_avail++; @@ -1005,7 +1005,7 @@ static void mips_m4k_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) mips_m4k_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 56b0194e7..5d821d7cb 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -346,7 +346,7 @@ static int mips_mips64_set_breakpoint(struct target *target, { int retval; - if (bp->set) { + if (bp->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -373,7 +373,7 @@ static int mips_mips64_set_breakpoint(struct target *target, return retval; } - bp->set = true; + bp->is_set = true; return ERROR_OK; } @@ -385,7 +385,7 @@ static int mips_mips64_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (bp) { - if (!bp->set) { + if (!bp->is_set) { retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; @@ -413,7 +413,7 @@ static int mips_mips64_set_watchpoint(struct target *target, int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -451,7 +451,7 @@ static int mips_mips64_set_watchpoint(struct target *target, } c = &cl[wp_num]; - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); c->used = true; c->bp_value = watchpoint->address; @@ -491,7 +491,7 @@ static int mips_mips64_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) { + if (!watchpoint->is_set) { retval = mips_mips64_set_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -506,11 +506,10 @@ static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->inst_break_list; - int bp_num; - bp_num = bp->set - 1; + int bp_num = bp->number; - if ((bp_num < 0) || (bp_num >= mips64->num_inst_bpoints)) { + if (bp_num >= mips64->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", bp->unique_id); return ERROR_OK; @@ -568,7 +567,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, /* get pointers to arch-specific information */ int retval; - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -594,7 +593,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, return retval; } - bp->set = false; + bp->is_set = false; return ERROR_OK; } @@ -815,7 +814,7 @@ static int mips_mips64_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (bp->set) + if (bp->is_set) retval = mips_mips64_unset_breakpoint(target, bp); if (bp->type == BKPT_HARD) @@ -831,20 +830,20 @@ static int mips_mips64_unset_watchpoint(struct target *target, struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips64->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips64->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; comparator_list[wp_num].bp_value = 0; target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -876,7 +875,7 @@ static int mips_mips64_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) retval = mips_mips64_unset_watchpoint(target, watchpoint); mips64->num_data_bpoints_avail++; diff --git a/src/target/nds32.c b/src/target/nds32.c index 12340ac2c..f0fb74d31 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -1653,7 +1653,7 @@ int nds32_init_arch_info(struct target *target, struct nds32 *nds32) nds32->syscall_break.asid = 0; nds32->syscall_break.length = 4; - nds32->syscall_break.set = 0; + nds32->syscall_break.is_set = false; nds32->syscall_break.orig_instr = NULL; nds32->syscall_break.next = NULL; nds32->syscall_break.unique_id = 0x515CAll + target->target_number; diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c index b0c3de622..8ff8e30c6 100644 --- a/src/target/nds32_v3_common.c +++ b/src/target/nds32_v3_common.c @@ -78,12 +78,12 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) struct breakpoint *syscall_break = &(nds32->syscall_break); if (nds32->virtual_hosting) { - if (syscall_break->set) { + if (syscall_break->is_set) { /** disable virtual hosting */ /* remove breakpoint at syscall entry */ target_remove_breakpoint(nds32->target, syscall_break); - syscall_break->set = 0; + syscall_break->is_set = false; uint32_t value_pc; nds32_get_mapped_reg(nds32, PC, &value_pc); @@ -209,7 +209,7 @@ static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoin syscall_break->address = syscall_address; syscall_break->type = BKPT_SOFT; - syscall_break->set = 1; + syscall_break->is_set = true; target_add_breakpoint(target, syscall_break); } diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 8fbcd9620..77fa15d50 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -923,9 +923,9 @@ static int or1k_add_breakpoint(struct target *target, struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; - LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) @@ -981,9 +981,9 @@ static int or1k_remove_breakpoint(struct target *target, struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 367506dde..a266f5da3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -903,7 +903,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = true; + breakpoint->is_set = true; return ERROR_OK; } @@ -963,7 +963,7 @@ int riscv_remove_breakpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -990,7 +990,7 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) int result = add_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = true; + watchpoint->is_set = true; return ERROR_OK; } @@ -1006,7 +1006,7 @@ int riscv_remove_watchpoint(struct target *target, int result = remove_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -1338,9 +1338,9 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { - LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); - state[i] = watchpoint->set; - if (watchpoint->set) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set); + state[i] = watchpoint->is_set; + if (watchpoint->is_set) { if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; } diff --git a/src/target/stm8.c b/src/target/stm8.c index 21fc8c54f..4102082ff 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1370,7 +1370,7 @@ static void stm8_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) stm8_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1383,7 +1383,7 @@ static int stm8_set_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1398,7 +1398,7 @@ static int stm8_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = true; comparator_list[bp_num].bp_value = breakpoint->address; comparator_list[bp_num].type = HWBRK_EXEC; @@ -1435,7 +1435,7 @@ static int stm8_set_breakpoint(struct target *target, } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = 1; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1476,14 +1476,14 @@ static int stm8_unset_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -1517,7 +1517,7 @@ static int stm8_unset_breakpoint(struct target *target, } else return ERROR_FAIL; } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1533,7 +1533,7 @@ static int stm8_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) stm8_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -1550,7 +1550,7 @@ static int stm8_set_watchpoint(struct target *target, int wp_num = 0; int ret; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1593,7 +1593,7 @@ static int stm8_set_watchpoint(struct target *target, return ret; } - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, @@ -1627,7 +1627,7 @@ static void stm8_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) stm8_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1640,18 +1640,18 @@ static int stm8_unset_watchpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid hw comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; - watchpoint->set = 0; + watchpoint->is_set = false; stm8_set_hwbreak(target, comparator_list); @@ -1669,7 +1669,7 @@ static int stm8_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) stm8_unset_watchpoint(target, watchpoint); stm8->num_hw_bpoints_avail++; diff --git a/src/target/target.c b/src/target/target.c index 7b8271339..690526eb7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3967,26 +3967,26 @@ static int handle_bp_command_list(struct command_invocation *cmd) if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, breakpoint->length); - command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s", + command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, 0x%s", breakpoint->address, breakpoint->length, - breakpoint->set, buf); + buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) - command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %u", breakpoint->asid, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", + command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); command_print(cmd, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else - command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", + command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); } breakpoint = breakpoint->next; diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index a009bfe92..d119be148 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -862,7 +862,7 @@ int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp) { if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (wp->set) + if (wp->is_set) unset_watchpoint(t, wp); return ERROR_OK; } @@ -883,7 +883,7 @@ int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp) LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (bp->set) + if (bp->is_set) unset_breakpoint(t, bp); return ERROR_OK; @@ -995,7 +995,7 @@ static int set_hwbp(struct target *t, struct breakpoint *bp) } if (set_debug_regs(t, bp->address, hwbp_num, DR7_BP_EXECUTE, 1) != ERROR_OK) return ERROR_FAIL; - bp->set = hwbp_num + 1; + breakpoint_hw_set(bp, hwbp_num); debug_reg_list[hwbp_num].used = 1; debug_reg_list[hwbp_num].bp_value = bp->address; LOG_USER("%s hardware breakpoint %" PRIu32 " set at 0x%08" PRIx32 " (hwreg=%" PRIu8 ")", __func__, @@ -1007,9 +1007,9 @@ static int unset_hwbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; - int hwbp_num = bp->set - 1; + int hwbp_num = bp->number; - if ((hwbp_num < 0) || (hwbp_num >= x86_32->num_hw_bpoints)) { + if (hwbp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s invalid breakpoint number=%d, bpid=%" PRIu32, __func__, hwbp_num, bp->unique_id); return ERROR_OK; @@ -1055,7 +1055,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) __func__, readback, *bp->orig_instr); return ERROR_FAIL; } - bp->set = SW_BP_OPCODE; /* just non 0 */ + bp->is_set = true; /* add the memory patch */ struct swbp_mem_patch *new_patch = malloc(sizeof(struct swbp_mem_patch)); @@ -1134,7 +1134,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) int error = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (bp->set) { + if (bp->is_set) { LOG_ERROR("breakpoint already set"); return error; } @@ -1164,7 +1164,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) static int unset_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1182,7 +1182,7 @@ static int unset_breakpoint(struct target *t, struct breakpoint *bp) return ERROR_FAIL; } } - bp->set = 0; + bp->is_set = false; return ERROR_OK; } @@ -1193,7 +1193,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) int wp_num = 0; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (wp->set) { + if (wp->is_set) { LOG_ERROR("%s watchpoint already set", __func__); return ERROR_OK; } @@ -1233,7 +1233,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); break; } - wp->set = wp_num + 1; + watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; debug_reg_list[wp_num].bp_value = wp->address; LOG_USER("'%s' watchpoint %d set at " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", @@ -1248,13 +1248,13 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (!wp->set) { + if (!wp->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = wp->set - 1; - if ((wp_num < 0) || (wp_num >= x86_32->num_hw_bpoints)) { + int wp_num = wp->number; + if (wp_num >= x86_32->num_hw_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -1263,7 +1263,7 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) debug_reg_list[wp_num].used = 0; debug_reg_list[wp_num].bp_value = 0; - wp->set = 0; + wp->is_set = false; LOG_USER("'%s' watchpoint %d removed from " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? diff --git a/src/target/xscale.c b/src/target/xscale.c index dd383b6e4..78bd09922 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1087,7 +1087,7 @@ static void xscale_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) xscale_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1099,7 +1099,7 @@ static void xscale_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) xscale_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1506,7 +1506,7 @@ static int xscale_deassert_reset(struct target *target) /* mark all hardware breakpoints as unset */ while (breakpoint) { if (breakpoint->type == BKPT_HARD) - breakpoint->set = 0; + breakpoint->is_set = false; breakpoint = breakpoint->next; } @@ -2088,7 +2088,7 @@ static int xscale_set_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -2098,11 +2098,13 @@ static int xscale_set_breakpoint(struct target *target, if (!xscale->ibcr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); xscale->ibcr0_used = 1; - breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + /* breakpoint set on first breakpoint register */ + breakpoint_hw_set(breakpoint, 0); } else if (!xscale->ibcr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); xscale->ibcr1_used = 1; - breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + /* breakpoint set on second breakpoint register */ + breakpoint_hw_set(breakpoint, 1); } else {/* bug: availability previously verified in xscale_add_breakpoint() */ LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -2133,7 +2135,7 @@ static int xscale_set_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 1; + breakpoint->is_set = true; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2176,20 +2178,20 @@ static int xscale_unset_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); xscale->ibcr0_used = 0; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); xscale->ibcr1_used = 0; } - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -2203,7 +2205,7 @@ static int xscale_unset_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 0; + breakpoint->is_set = false; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2223,7 +2225,7 @@ static int xscale_remove_breakpoint(struct target *target, struct breakpoint *br return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) xscale_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -2279,13 +2281,13 @@ static int xscale_set_watchpoint(struct target *target, xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); dbcon_value |= enable; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 1; + watchpoint_set(watchpoint, 0); xscale->dbr0_used = 1; } else if (!xscale->dbr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); dbcon_value |= enable << 2; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 2; + watchpoint_set(watchpoint, 1); xscale->dbr1_used = 1; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -2349,12 +2351,12 @@ static int xscale_unset_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 0) { if (watchpoint->length > 4) { dbcon_value &= ~0x103; /* clear DBCON[M] as well */ xscale->dbr1_used = 0; /* DBR1 was used for mask */ @@ -2363,12 +2365,12 @@ static int xscale_unset_watchpoint(struct target *target, xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 1) { dbcon_value &= ~0xc; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -2382,7 +2384,7 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) xscale_unset_watchpoint(target, watchpoint); if (watchpoint->length > 4) From 92c4e634d7bb9d3fb27d9a0ca332925c7318a574 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Mar 2022 10:56:01 +0100 Subject: [PATCH 087/186] breakpoints: fix build on -fno-inline Some configuration of GCC could default to -fno-inline, causing the build to fail after commit fb43f1ff4e2f ("target: Rework 'set' variable of break-/watchpoints"). Switch the new inline functions to 'static inline', as it's widely used in the rest of the code. Change-Id: I8bf31045a137bd34ed825f4b2a9338eb3c70046d Signed-off-by: Antonio Borneo Fixes: fb43f1ff4e2f ("target: Rework 'set' variable of break-/watchpoints") Reviewed-on: https://review.openocd.org/c/openocd/+/6881 Tested-by: jenkins --- src/target/breakpoints.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index b97be718c..0a5949594 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -71,7 +71,7 @@ void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); -inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) +static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) { breakpoint->is_set = true; breakpoint->number = hw_number; @@ -87,7 +87,7 @@ void watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address); -inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) +static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) { watchpoint->is_set = true; watchpoint->number = number; From 0a70e59cb86deed71fd92ceffdd233478e237ebb Mon Sep 17 00:00:00 2001 From: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Date: Wed, 23 Mar 2022 17:47:57 +0100 Subject: [PATCH 088/186] Fix: Set proper debug_reason in deassert_reset() (#687) * Fix checkpatch workflow: ignore changes in .github/ Ignore changes in .github/ directory when running checkpatch. Checkpatch emits false alarms on substrings "CC:" found in *.yml workflow files, apparently thinking it is a "Cc:" signature in commit message. Change-Id: Id977d5a8838797e4676758066af4825651c41a87 * Fix: Set proper debug_reason in deassert_reset() The issue was visible for example when user's .cfg file ended with "reset halt" command: In such case, the hart would remain halted but the debug_reason would not be updated and may retain an incorrect value, e.g. DBG_REASON_NOTHALTED. In such cases, gdb_last_signal() would provide an incorrect reply to GDB. Change-Id: Ie6f050295fb5cbe9db38b189c4bc385662acf5b4 Signed-off-by: Jan Matyas * Fix checkpatch workflow: add 'apt-get update' Change-Id: Ic5843ec86d16a187d01970a3253caade3d13b7ab Signed-off-by: Jan Matyas --- .github/workflows/checkpatch.yml | 16 +++++++++++----- src/target/riscv/riscv-013.c | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml index 0c120c0f2..c9ec78d59 100644 --- a/.github/workflows/checkpatch.yml +++ b/.github/workflows/checkpatch.yml @@ -1,6 +1,6 @@ on: pull_request -name: Check Code Style +name: Check Code Style (checkpatch) jobs: check: @@ -13,9 +13,15 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 50 - - run: sudo apt-get install patchutils + - name: Install required packages (apt-get) + run: | + sudo apt-get update + sudo apt-get install patchutils - name: Run checkpatch run: | - git diff -U20 HEAD~40 | \ - filterdiff -x "a/src/jtag/drivers/libjaylink/*" -x "a/tools/git2cl/*" | \ - ./tools/scripts/checkpatch.pl --no-signoff - + git diff -U20 HEAD~40 \ + | filterdiff \ + -x "a/src/jtag/drivers/libjaylink/*" \ + -x "a/tools/git2cl/*" \ + -x "a/.github/*" \ + | ./tools/scripts/checkpatch.pl --no-signoff - diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 553cc3955..b719fa4f5 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2436,6 +2436,7 @@ static int deassert_reset(struct target *target) } } target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { /* Ack reset. */ From 2cafa8be7320266756dd92a40d174cbc01487c15 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 4 Mar 2022 09:26:19 +0100 Subject: [PATCH 089/186] semihosting: fix mode flags for local host open() Commit dbbac5f11d66 ("semihosting: use open mode flags from GDB, not from sys/stat.h") fixes the conversion of the mode flags from ARM semihosting encoding for SEMIHOSTING_SYS_OPEN to GDB mapping for open(). Doing this, it breaks the conversion to local host's OS mapping for open(). Split the conversion array to one for GDB and one for local host. The local host conversion array is taken directly from the old code. Change-Id: I385321ddd32c3ac5cf6da3f1ce9eff76b05dd527 Fixes: dbbac5f11d66 ("semihosting: use open mode flags from GDB, not from sys/stat.h") Signed-off-by: Antonio Borneo Reported-by: Erhan Kurubas Reviewed-on: https://review.openocd.org/c/openocd/+/6870 Tested-by: jenkins --- src/target/semihosting_common.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 38035e493..bc1f417ef 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -68,7 +68,7 @@ enum { }; /* GDB remote protocol does not differentiate between text and binary open modes. */ -static const int open_modeflags[12] = { +static const int open_gdb_modeflags[12] = { TARGET_O_RDONLY, TARGET_O_RDONLY, TARGET_O_RDWR, @@ -83,6 +83,21 @@ static const int open_modeflags[12] = { TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; +static const int open_host_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; + static int semihosting_common_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); static int semihosting_common_fileio_end(struct target *target, int result, @@ -886,7 +901,7 @@ int semihosting_common(struct target *target) fileio_info->identifier = "open"; fileio_info->param_1 = addr; fileio_info->param_2 = len; - fileio_info->param_3 = open_modeflags[mode]; + fileio_info->param_3 = open_gdb_modeflags[mode]; fileio_info->param_4 = 0644; } } else { @@ -922,7 +937,7 @@ int semihosting_common(struct target *target) * otherwise it will fail to reopen a previously * written file */ semihosting->result = open((char *)fn, - open_modeflags[mode], + open_host_modeflags[mode], 0644); semihosting->sys_errno = errno; LOG_DEBUG("open('%s')=%d", fn, From 1b716b9d0d42409f5ee8855f084720ff579a7737 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 28 Nov 2019 18:00:11 +0100 Subject: [PATCH 090/186] tcl/tools: Add function to measure the speed of ARM Cortex-M devices Tested on an EFM32PG12 Starter Kit. Change-Id: I2cbc36fe0d2ad2089bf8c1e7d2260daaae4ddbb4 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5353 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/tools/test_cpu_speed.tcl | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tcl/tools/test_cpu_speed.tcl diff --git a/tcl/tools/test_cpu_speed.tcl b/tcl/tools/test_cpu_speed.tcl new file mode 100644 index 000000000..cef2bbbd7 --- /dev/null +++ b/tcl/tools/test_cpu_speed.tcl @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Description: +# Measure the CPU clock frequency of an ARM Cortex-M based device. +# +# Return: +# The CPU clock frequency in Hz. A negative value indicates that the loop +# counter was saturated. +# +# Note: +# You may need to adapt the number of cycles for your device. +# +add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device" +add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]} +proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { + set loop_counter_start 0xffffffff + + halt + + # Backup registers and memory. + set backup_regs [get_reg -force {pc r0 xPSR}] + set backup_mem [read_memory $address 16 3] + + # We place the following code at the given address to measure the + # CPU clock frequency: + # + # 3801: subs r0, #1 + # d1fd: bne #-2 + # e7fe: b #-4 + write_memory $address 16 {0x3801 0xd1fd 0xe7fe} + + set_reg "pc $address r0 $loop_counter_start" + resume + sleep $timeout + halt + + # Get the loop counter value from register r0. + set loop_counter_end [dict values [get_reg r0]] + set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}] + + # Restore registers and memory. + set_reg $backup_regs + write_memory $address 16 $backup_mem + + if { [expr {$loop_counter_end == 0}] } { + return -1 + } + + return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}] +} From 00d4699d0b559a0bb3e739a78f3ce1c5731f8dea Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 9 Jun 2021 11:27:57 +0200 Subject: [PATCH 091/186] arm_tpiu_swo: fix autodetection of SWO pin frequency While the documentation reports that SWO pin frequency can be omitted to let the adapter autodetect the value, the code wrongly drops an error when pin frequency is not specified. Don't require the pin frequency to be set at "enable", but verify that the adapter has properly changes it to a valid value. Change-Id: I3dfbe3256e8887ef4f03512769b06381cdc9db0d Signed-off-by: Antonio Borneo Reported-by: Karl Palsson Fixes: 184724d14e12 ("arm_tpiu_swo: add support for independent TPIU and SWO") Reviewed-on: https://review.openocd.org/c/openocd/+/6310 Tested-by: jenkins Reviewed-by: zapb --- src/target/arm_tpiu_swo.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index a0eba6782..fba3fec4f 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -625,10 +625,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) - if (!obj->swo_pin_freq) { - LOG_ERROR("SWO pin frequency not set"); - return JIM_ERR; - } + if (!obj->swo_pin_freq) + LOG_DEBUG("SWO pin frequency not set, will be autodetected by the adapter"); struct target *target = get_current_target(cmd_ctx); @@ -731,6 +729,17 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_ERR; } + if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) + if (!swo_pin_freq) { + if (obj->swo_pin_freq) + LOG_ERROR("Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); + else + LOG_ERROR("Adapter does not support auto-detection of SWO pin frequency nor a default value"); + + arm_tpiu_swo_close_output(obj); + return JIM_ERR; + } + if (obj->swo_pin_freq != swo_pin_freq) LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq); obj->swo_pin_freq = swo_pin_freq; From 3fa695be2401c88dbd93b2c9dad1c098a948c4ca Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Feb 2022 11:39:15 +0100 Subject: [PATCH 092/186] openocd: include config.h in every file .c Including config.h as first is required for every C file. Add it to the C files that still miss it. Change-Id: I1a210e7d3a854958a85a290b086ad8a9f5176425 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6856 Tested-by: jenkins --- src/helper/jim-nvp.c | 4 ++++ src/rtos/chromium-ec.c | 4 ++++ src/rtt/rtt.c | 4 ++++ src/rtt/tcl.c | 4 ++++ src/server/rtt_server.c | 4 ++++ src/target/rtt.c | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/src/helper/jim-nvp.c b/src/helper/jim-nvp.c index 738ed7943..0409a83cd 100644 --- a/src/helper/jim-nvp.c +++ b/src/helper/jim-nvp.c @@ -41,6 +41,10 @@ * official policies, either expressed or implied, of the Jim Tcl Project. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "jim-nvp.h" #include diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index 1c8f4e3f4..2f1a0cf3c 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -7,6 +7,10 @@ * Chromium-EC RTOS Task Awareness */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index bf3cca51b..3da3cce81 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index f5abf2e5e..4a34d8b98 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index c7141c0e0..3850c2687 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include diff --git a/src/target/rtt.c b/src/target/rtt.c index 7e556e1cb..41830213d 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include From 6c9dd1c6ba9fba806ed7ed6f6ecb59723beb9cad Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Feb 2022 11:30:56 +0100 Subject: [PATCH 093/186] helper/bits: add BIT_ULL and GENMASK macros To support 64 bits bit and masks Replace local definition of BIT in rtos/chromium-ec Change-Id: I1f268d6e8790f1b07bf798680b797878ce81064b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6857 Tested-by: jenkins --- src/helper/bits.h | 4 ++++ src/rtos/chromium-ec.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helper/bits.h b/src/helper/bits.h index 00d3c0270..6151b3340 100644 --- a/src/helper/bits.h +++ b/src/helper/bits.h @@ -28,8 +28,12 @@ #include #define BIT(nr) (1UL << (nr)) +#define BIT_ULL(nr) (1ULL << (nr)) #define BITS_PER_BYTE 8 #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define BITS_PER_LONG_LONG (BITS_PER_BYTE * sizeof(long long)) +#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index 2f1a0cf3c..95a228d0d 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -11,6 +11,7 @@ #include "config.h" #endif +#include #include #include #include @@ -20,7 +21,6 @@ #define CROS_EC_MAX_TASKS 32 #define CROS_EC_MAX_NAME 200 #define CROS_EC_IDLE_STRING "<< idle >>" -#define BIT(x) (1 << (x)) struct chromium_ec_params { const char *target_name; From 017d3ddafbfac459a799f7e60613312c61fa3195 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Thu, 17 Mar 2022 14:27:58 +0100 Subject: [PATCH 094/186] gdb_server: Improve logging of GDB-remote packets - Print also the target name, not just the packet contents. This is important when there are more GDB servers (more debug-able targets) active in one OpenOCD session. - Log also the received Ctrl-C requests coming from GDB (one byte 0x3), ACKs ("+") and NACKs ("-"). - Do not print zero-length incoming packets (this occurred when Ctrl-C packets were received). - Removed a stray apostrophe "'" that got printed in gdb_log_outgoing_packet() Signed-off-by: Jan Matyas Change-Id: If68fe0a8aa635165d0bbe6fa0e48a4645a02da67 Reviewed-on: https://review.openocd.org/c/openocd/+/6879 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 45 ++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f5736196e..82c8ce92b 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -371,11 +371,13 @@ static int gdb_write(struct connection *connection, void *data, int len) return ERROR_SERVER_REMOTE_CLOSED; } -static void gdb_log_incoming_packet(char *packet) +static void gdb_log_incoming_packet(struct connection *connection, char *packet) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; + struct target *target = get_target_from_connection(connection); + /* Avoid dumping non-printable characters to the terminal */ const unsigned packet_len = strlen(packet); const char *nonprint = find_nonprint_char(packet, packet_len); @@ -389,25 +391,31 @@ static void gdb_log_incoming_packet(char *packet) if (packet_prefix_printable) { const unsigned int prefix_len = colon - packet + 1; /* + 1 to include the ':' */ const unsigned int payload_len = packet_len - prefix_len; - LOG_DEBUG("received packet: %.*s", prefix_len, packet, payload_len); + LOG_TARGET_DEBUG(target, "received packet: %.*s", prefix_len, + packet, payload_len); } else { - LOG_DEBUG("received packet: ", packet_len); + LOG_TARGET_DEBUG(target, "received packet: ", packet_len); } } else { /* All chars printable, dump the packet as is */ - LOG_DEBUG("received packet: %s", packet); + LOG_TARGET_DEBUG(target, "received packet: %s", packet); } } -static void gdb_log_outgoing_packet(char *packet_buf, unsigned int packet_len, unsigned char checksum) +static void gdb_log_outgoing_packet(struct connection *connection, char *packet_buf, + unsigned int packet_len, unsigned char checksum) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; + struct target *target = get_target_from_connection(connection); + if (find_nonprint_char(packet_buf, packet_len)) - LOG_DEBUG("sending packet: $#%2.2x", packet_len, checksum); + LOG_TARGET_DEBUG(target, "sending packet: $#%2.2x", + packet_len, checksum); else - LOG_DEBUG("sending packet: $%.*s#%2.2x'", packet_len, packet_buf, checksum); + LOG_TARGET_DEBUG(target, "sending packet: $%.*s#%2.2x", packet_len, packet_buf, + checksum); } static int gdb_put_packet_inner(struct connection *connection, @@ -450,7 +458,7 @@ static int gdb_put_packet_inner(struct connection *connection, #endif while (1) { - gdb_log_outgoing_packet(buffer, len, my_checksum); + gdb_log_outgoing_packet(connection, buffer, len, my_checksum); char local_buffer[1024]; local_buffer[0] = '$'; @@ -483,22 +491,27 @@ static int gdb_put_packet_inner(struct connection *connection, if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; + gdb_log_incoming_packet(connection, ""); retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -675,6 +688,7 @@ static int gdb_get_packet_inner(struct connection *connection, case '$': break; case '+': + gdb_log_incoming_packet(connection, "+"); /* According to the GDB documentation * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html): * "gdb sends a final `+` acknowledgment of the stub's `OK` @@ -692,9 +706,11 @@ static int gdb_get_packet_inner(struct connection *connection, } break; case '-': + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: + gdb_log_incoming_packet(connection, ""); gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; @@ -3452,9 +3468,10 @@ static int gdb_input_inner(struct connection *connection) /* terminate with zero */ gdb_packet_buffer[packet_size] = '\0'; - gdb_log_incoming_packet(gdb_packet_buffer); - if (packet_size > 0) { + + gdb_log_incoming_packet(connection, gdb_packet_buffer); + retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ From f0d8c3b0e024d045262ba50a516a3bd66bf22686 Mon Sep 17 00:00:00 2001 From: Gabor Csapo Date: Fri, 18 Mar 2022 18:11:49 +0800 Subject: [PATCH 095/186] libusb_helper.h: Increase USB timeout When we debug a target that works as a USB device, halting the target causes the USB communication with the USB host to become unresponsive. The host will try to reconnect/reset/setup the unresponsive device during which communication with other devices on the same USB bus can get stalled for several seconds. If the JTAG adapter is on the same bus, we need to make sure openOCD will wait for packets at least as long as the host USB stack. Otherwise the USB stack might deliver a valid packet, but openOCD would ignore it due to the timeout. The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. Use this value in all libusb calls. HID API might have a libusb backend and would probably be victim to the same bug, so it should use this timeout, too. Ticket: https://sourceforge.net/p/openocd/tickets/343/ Signed-off-by: Gabor Csapo Change-Id: Ia3dc1356e676fe550f57a4c72f7a24ba296b6af2 Reviewed-on: https://review.openocd.org/c/openocd/+/6882 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/cmsis_dap.c | 15 +++++++-------- src/jtag/drivers/libusb_helper.h | 14 ++++++++++++++ src/jtag/drivers/nulink_usb.c | 4 +++- src/jtag/drivers/rlink.c | 30 ++++++++++++++---------------- src/jtag/drivers/stlink_usb.c | 4 ++-- src/jtag/drivers/ti_icdi_usb.c | 4 ++-- src/jtag/drivers/ulink.c | 11 ++++------- 7 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index e7562d087..4621fdc99 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -48,6 +48,7 @@ #include #include "cmsis_dap.h" +#include "libusb_helper.h" static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { #if BUILD_CMSIS_DAP_USB == 1 @@ -79,8 +80,6 @@ static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; static int cmsis_dap_backend = -1; static bool swd_mode; -#define USB_TIMEOUT 1000 - /* CMSIS-DAP General Commands */ #define CMD_DAP_INFO 0x00 #define CMD_DAP_LED 0x01 @@ -360,12 +359,12 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) } uint8_t current_cmd = cmsis_dap_handle->command[0]; - int retval = dap->backend->write(dap, txlen, USB_TIMEOUT); + int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ - retval = dap->backend->read(dap, USB_TIMEOUT); + retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; @@ -826,7 +825,7 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) } } - int retval = dap->backend->write(dap, idx, USB_TIMEOUT); + int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); if (retval < 0) { queued_retval = retval; goto skip; @@ -854,7 +853,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) /* get reply */ int retval = dap->backend->read(dap, timeout_ms); - if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < USB_TIMEOUT) + if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < LIBUSB_TIMEOUT_MS) return; if (retval <= 0) { @@ -929,7 +928,7 @@ static int cmsis_dap_swd_run_queue(void) cmsis_dap_swd_write_from_queue(cmsis_dap_handle); while (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); pending_fifo_put_idx = 0; pending_fifo_get_idx = 0; @@ -953,7 +952,7 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) cmsis_dap_swd_write_from_queue(cmsis_dap_handle); if (pending_fifo_block_count >= cmsis_dap_handle->packet_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); } if (queued_retval != ERROR_OK) diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 2ddb246b3..9d51464a7 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -22,6 +22,20 @@ #include +/* When we debug a target that works as a USB device, halting the target causes the + * USB communication with the USB host to become unresponsive. The host will try + * to reconnect/reset/setup the unresponsive device during which communication + * with other devices on the same USB bus can get stalled for several seconds. + * If the JTAG adapter is on the same bus, we need to make sure openOCD will wait + * for packets at least as long as the host USB stack. Otherwise the USB stack + * might deliver a valid packet, but openOCD would ignore it due to the timeout. + * The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. + * + * Use this value in all libusb calls. HID API might have a libusb backend and + * would probably be victim to the same bug, so it should use this timeout, too. + */ +#define LIBUSB_TIMEOUT_MS (6000) + /* this callback should return a non NULL value only when the serial could not * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device, diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index d4b8b53bc..84a4420e8 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -33,7 +33,9 @@ #include -#define NULINK_READ_TIMEOUT 1000 +#include "libusb_helper.h" + +#define NULINK_READ_TIMEOUT LIBUSB_TIMEOUT_MS #define NULINK_HID_MAX_SIZE (64) #define NULINK2_HID_MAX_SIZE (1024) diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 73be3c57e..0cf9dbbb2 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -59,8 +59,6 @@ #define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) #define USB_EP2BANK_SIZE (512) -#define USB_TIMEOUT_MS (3 * 1000) - #define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) #define ST7_PD_NBUSY_LED ST7_PD0 @@ -133,7 +131,7 @@ static int ep1_generic_commandl(struct libusb_device_handle *hdev_param, size_t hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -176,7 +174,7 @@ static ssize_t ep1_memory_read( usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -186,7 +184,7 @@ static ssize_t ep1_memory_read( usb_ret = jtag_libusb_bulk_read( hdev_param, USB_EP1IN_ADDR, (char *)buffer, length, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -241,7 +239,7 @@ static ssize_t ep1_memory_write(struct libusb_device_handle *hdev_param, uint16_ usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -432,7 +430,7 @@ static int dtc_start_download(void) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK) @@ -462,7 +460,7 @@ static int dtc_start_download(void) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -488,7 +486,7 @@ static int dtc_run_download( hdev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) @@ -512,7 +510,7 @@ static int dtc_run_download( hdev_param, USB_EP1IN_ADDR, &dtc_status, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) @@ -533,7 +531,7 @@ static int dtc_run_download( hdev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -954,7 +952,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -990,7 +988,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -1021,7 +1019,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -1576,7 +1574,7 @@ static int rlink_init(void) jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -1601,7 +1599,7 @@ static int rlink_init(void) jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 325848f86..2785d9b96 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -71,8 +71,8 @@ #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 -#define STLINK_WRITE_TIMEOUT 1000 -#define STLINK_READ_TIMEOUT 1000 +#define STLINK_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define STLINK_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index c94a1102f..e48d0e269 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -37,8 +37,8 @@ #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 -#define ICDI_WRITE_TIMEOUT 1000 -#define ICDI_READ_TIMEOUT 1000 +#define ICDI_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define ICDI_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define ICDI_PACKET_SIZE 2048 #define PACKET_START "$" diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 20a036a78..50609a64b 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -56,9 +56,6 @@ /** USB interface number */ #define USB_INTERFACE 0 -/** libusb timeout in ms */ -#define USB_TIMEOUT 5000 - /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ #define ULINK_RENUMERATION_DELAY 1500000 @@ -335,7 +332,7 @@ static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) ret = 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, USB_TIMEOUT); + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS); /* usb_control_msg() returns the number of bytes transferred during the * DATA stage of the control transfer - must be exactly 1 in this case! */ @@ -478,7 +475,7 @@ static int ulink_write_firmware_section(struct ulink *device, ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (unsigned char *)data_ptr, - chunk_size, USB_TIMEOUT); + chunk_size, LIBUSB_TIMEOUT_MS); if (ret != (int)chunk_size) { /* Abort if libusb sent less data than requested */ @@ -662,7 +659,7 @@ static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) 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 = ulink_execute_queued_commands(device, USB_TIMEOUT); + ret = ulink_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); if (ret == ERROR_OK) ret = ulink_post_process_queue(device); @@ -1960,7 +1957,7 @@ static int ulink_execute_queue(void) } if (ulink_handle->commands_in_queue > 0) { - ret = ulink_execute_queued_commands(ulink_handle, USB_TIMEOUT); + ret = ulink_execute_queued_commands(ulink_handle, LIBUSB_TIMEOUT_MS); if (ret != ERROR_OK) return ret; From c3b9ae6977a5c1c5d3252ea430ed19d0fc98fde7 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Mar 2022 16:08:56 +0100 Subject: [PATCH 096/186] drivers/cmsis-dap: Remove stray whitespace Change-Id: I7b60f9e87af2f582864ce94198d0343acf7d45f2 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6883 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/jtag/drivers/cmsis_dap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 4621fdc99..63407be42 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -209,7 +209,7 @@ static bool swd_mode; * None as yet... */ static const char * const info_caps_str[INFO_CAPS__NUM_CAPS] = { - "SWD supported", + "SWD supported", "JTAG supported", "SWO-UART supported", "SWO-MANCHESTER supported", From 7c6d379cf4434c69a977af4f417fe1ab1f3f9178 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Mar 2022 16:22:16 +0100 Subject: [PATCH 097/186] tcl/board: Add NXP FRDM-K64F Change-Id: I4b8fbfb2948c4295c2a34d641dd59a73c512d9fa Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6884 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- tcl/board/nxp_frdm-k64f.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tcl/board/nxp_frdm-k64f.cfg diff --git a/tcl/board/nxp_frdm-k64f.cfg b/tcl/board/nxp_frdm-k64f.cfg new file mode 100644 index 000000000..1581c9594 --- /dev/null +++ b/tcl/board/nxp_frdm-k64f.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is an NXP Freedom eval board with a single MK64FN1M0VLL12 chip. +# https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F +# + +source [find interface/cmsis-dap.cfg] + +# Set working area to 16 KiB +set WORKAREASIZE 0x4000 + +set CHIPNAME k64f +reset_config srst_only + +source [find target/kx.cfg] From 78b56e25c217338519d51818dce663742c783da9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 Apr 2022 16:58:35 +0200 Subject: [PATCH 098/186] riscv: Increase batch allocation size to improve transfer speed. (#689) Change-Id: I4cd1479f4d2f7b63cd594f5cef9d6b3d877d9015 Signed-off-by: Charles Papon --- src/target/riscv/riscv-013.c | 6 +++--- src/target/riscv/riscv.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b719fa4f5..63b40c687 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -3151,7 +3151,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres * dm_data0 contains[read_addr-size*2] */ - struct riscv_batch *batch = riscv_batch_alloc(target, 32, + struct riscv_batch *batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE, info->dmi_busy_delay + info->ac_busy_delay); if (!batch) return ERROR_FAIL; @@ -3649,7 +3649,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, struct riscv_batch *batch = riscv_batch_alloc( target, - 32, + RISCV_BATCH_ALLOC_SIZE, info->dmi_busy_delay + info->bus_master_write_delay); if (!batch) return ERROR_FAIL; @@ -3843,7 +3843,7 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, struct riscv_batch *batch = riscv_batch_alloc( target, - 32, + RISCV_BATCH_ALLOC_SIZE, info->dmi_busy_delay + info->ac_busy_delay); if (!batch) goto error; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 5dc2152c6..f3b753038 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -29,6 +29,8 @@ struct riscv_program; #define RISCV_NUM_MEM_ACCESS_METHODS 3 +#define RISCV_BATCH_ALLOC_SIZE 128 + extern struct target_type riscv011_target; extern struct target_type riscv013_target; From b7fdcd5e85eb4a9f69347ce7e6d1d1011078481e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Apr 2022 11:16:32 -0700 Subject: [PATCH 099/186] Fix build. Change-Id: Ied627f264a46e64f82a81b54e70daac2ebc0b708 Signed-off-by: Tim Newsome --- src/target/semihosting_common.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 9141c883e..bc1f417ef 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -315,12 +315,6 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd) */ static char *semihosting_user_op_params; -/** - * User operation parameter string storage buffer. Contains valid data when the - * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. - */ -static char *semihosting_user_op_params; - /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation From dd532e87c038ecd988b8bf83d6b1cf4515d5d2c9 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 17:51:09 +0100 Subject: [PATCH 100/186] flash/nor/stm32f1x: allow write fallback for flash options Mostly refactoring. Rename original stm32x_write_block() to stm32x_write_block_async() as it uses target async algo. Introduce new stm32x_write_block() and move slow, host controlled fallback flash write there. The change allows stm32x_write_options() to use slow flash write fallback. While on it rename variables where halfword count is stored. Change-Id: I386ae15cf052b1490461ed8f7eea5b4403d466f7 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6706 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 84 ++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 6972bae2d..139f10ea8 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -131,7 +131,7 @@ struct stm32x_flash_bank { static int stm32x_mass_erase(struct flash_bank *bank); static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count); + uint32_t address, uint32_t hwords_count); /* flash bank stm32x 0 0 */ @@ -329,12 +329,14 @@ static int stm32x_write_options(struct flash_bank *bank) target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); + /* Block write is preferred in favour of operation with ancient ST-Link + * firmwares without 16-bit memory access. See + * 480: flash: stm32f1x: write option bytes using the loader + * https://review.openocd.org/c/openocd/+/480 + */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - LOG_ERROR("working area required to erase options bytes"); + if (retval != ERROR_OK) return retval; - } retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); if (retval != ERROR_OK) @@ -442,8 +444,8 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, return stm32x_write_options(bank); } -static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count) +static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; @@ -493,7 +495,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, hwords_count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); @@ -501,7 +503,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - retval = target_run_flash_async_algorithm(target, buffer, count, 2, + retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, 5, reg_params, source->address, source->size, @@ -537,6 +539,40 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } +/** Writes a block to flash either using target algorithm + * or use fallback, host controlled halfword-by-halfword access. + * Flash controller must be unlocked before this call. + */ +static int stm32x_write_block(struct flash_bank *bank, + const uint8_t *buffer, uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + + /* try using a block write - on ARM architecture or... */ + int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) single halfword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + + while (hwords_count > 0) { + retval = target_write_memory(target, address, 2, 1, buffer); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) + return retval; + + hwords_count--; + buffer += 2; + address += 2; + } + } + return retval; +} + static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -568,7 +604,6 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, new_buffer[count++] = 0xff; } - uint32_t words_remaining = count / 2; int retval, retval2; /* unlock flash registers */ @@ -577,34 +612,15 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - goto cleanup; + goto reset_pg_and_lock; + /* enable flash programming */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) - goto cleanup; - - /* try using a block write */ - retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining); - - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single halfword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - - while (words_remaining > 0) { - retval = target_write_memory(target, bank->base + offset, 2, 1, buffer); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - retval = stm32x_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; + goto reset_pg_and_lock; - words_remaining--; - buffer += 2; - offset += 2; - } - } + /* write to flash */ + retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2); reset_pg_and_lock: retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); From 10f933915d3234cda56f55752a14ec6c4734a6fd Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 18:26:53 +0100 Subject: [PATCH 101/186] flash/nor/stm32f1x: remove write alignment code Use flash infrastructure to ensure writes are halfword aligned. Change-Id: Iddca3a256ace3486a23e1a9cb6a31c7a91ee58bf Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6707 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 139f10ea8..664524b03 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -151,6 +151,9 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_bank_size = bank->size; + /* The flash write must be aligned to a halfword boundary */ + bank->write_start_alignment = bank->write_end_alignment = 2; + return ERROR_OK; } @@ -548,6 +551,11 @@ static int stm32x_write_block(struct flash_bank *bank, { struct target *target = bank->target; + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(address % 2 == 0); + /* try using a block write - on ARM architecture or... */ int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); @@ -577,39 +585,24 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - /* If there's an odd number of bytes, the data has to be padded. Duplicate - * the buffer and use the normal code path with a single block write since - * it's probably cheaper than to special case the last odd write using - * discrete accesses. */ - if (count & 1) { - new_buffer = malloc(count + 1); - if (!new_buffer) { - LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write, padding with 0xff"); - buffer = memcpy(new_buffer, buffer, count); - new_buffer[count++] = 0xff; - } + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(offset % 2 == 0); + assert(count % 2 == 0); int retval, retval2; /* unlock flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) - goto cleanup; + return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto reset_pg_and_lock; @@ -627,8 +620,6 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval == ERROR_OK) retval = retval2; -cleanup: - free(new_buffer); return retval; } From e3f4ea0b574d952672d57792895a91065aa7a569 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 19:04:05 +0100 Subject: [PATCH 102/186] flash/nor/stm32f1x: tidy up async algo supporting code Use target_get_working_area_avail() instead of try-fail iteration. Call destroy_reg_param() in a for cycle. Change-Id: I1891d1ffdea99010c6ab66b9578400b9d7922e20 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6708 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 47 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 664524b03..f4b1daa56 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -452,12 +452,11 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; - struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; - int retval = ERROR_OK; + int retval; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32f1x.inc" @@ -478,19 +477,28 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff } /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + /* Normally we allocate all available working area. + * MIN shrinks buffer_size if the size of the written block is smaller. + * MAX prevents using async algo if the available working area is smaller + * than 256, the following allocation fails with + * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place. + */ + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always 32-bit word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + struct reg_param reg_params[5]; + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ @@ -508,7 +516,7 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -530,15 +538,12 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff } } + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - return retval; } From b801452d42c189a13f6cc1ff769fc98bededc7c5 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 19:41:05 +0100 Subject: [PATCH 103/186] flash/nor/stm32f1x: unify flash error reporting stm32x_wait_status_busy() has two side effects in case of flash programming error: - reports error - clears error bit in status register Use stm32x_wait_status_busy() to report also flash error during target algo flash write. While on it use more descriptive error codes in stm32x_wait_status_busy(). Change-Id: I6e1cffc2aa5411b918a23ed62d5194910888a9d1 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6709 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index f4b1daa56..26231e9cb 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -185,19 +185,19 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); - return ERROR_FAIL; + return ERROR_FLASH_BUSY; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("stm32x device protected"); - retval = ERROR_FAIL; + retval = ERROR_FLASH_PROTECTED; } if (status & FLASH_PGERR) { - LOG_ERROR("stm32x device programming failed"); - retval = ERROR_FAIL; + LOG_ERROR("stm32x device programming failed / flash not erased"); + retval = ERROR_FLASH_OPERATION_FAILED; } /* Clear but report errors */ @@ -522,20 +522,18 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); - - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { - LOG_ERROR("flash memory not erased before writing"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR); - } + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits. + * + * Target algo returns flash status in r0 only if properly finished. + * It is safer to re-read status register. + */ + int retval2 = stm32x_wait_status_busy(bank, 5); + if (retval2 != ERROR_OK) + retval = retval2; - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { - LOG_ERROR("flash memory write protected"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR); - } + LOG_ERROR("flash write failed just before address 0x%"PRIx32, + buf_get_u32(reg_params[4].value, 0, 32)); } for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) From e83eeb44aa96e380f46d37980b8b76a908757dc6 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 20:12:53 +0100 Subject: [PATCH 104/186] flash/nor/stm32f1x: lock flash in case of error The current code locks the flash controller in case of error during flash write only. An error in other flash operations may cause the flash is left unlocked. Implement locking also after error in erase, mass erase, options write and erase. Change-Id: I26c2ed7914e7847122306f29b777b9eefd1dc580 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6710 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 85 ++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 26231e9cb..8e66af368 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -261,36 +261,39 @@ static int stm32x_erase_options(struct flash_bank *bank) int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* erase option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* clear read protection option byte * this will also force a device unlock if set */ stm32x_info->option_bytes.rdp = stm32x_info->default_rdp; return ERROR_OK; + +flash_lock: + target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + return retval; } static int stm32x_write_options(struct flash_bank *bank) @@ -306,20 +309,20 @@ static int stm32x_write_options(struct flash_bank *bank) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* program option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; uint8_t opt_bytes[16]; @@ -338,14 +341,14 @@ static int stm32x_write_options(struct flash_bank *bank) * https://review.openocd.org/c/openocd/+/480 */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect_check(struct flash_bank *bank) @@ -389,31 +392,33 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; for (unsigned int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + goto flash_lock; } - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, @@ -1483,8 +1488,10 @@ COMMAND_HANDLER(stm32x_handle_options_load_command) if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + (void)target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); return retval; + } /* force re-load of option bytes - generates software reset */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH); @@ -1509,26 +1516,26 @@ static int stm32x_mass_erase(struct flash_bank *bank) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* mass erase flash memory */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) From 9d737af35126c3a857e1c6a3356ab3879e92b6eb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Apr 2022 19:16:47 +0200 Subject: [PATCH 105/186] riscv: Add a option to specify the JTAG TAP tunnel IR (#690) * riscv: Add a option to specify the JTAG TAP IR used to access the bscan tunnel. Change-Id: Ice8798823313e2177e75473e62b06e7da74bbba2 Signed-off-by: Charles Papon * risc-v: Add litex doc about the set_bscan_tunnel_ir command Change-Id: I1237213f32886d20fc7d60d5ca1e2124953eaeda Signed-off-by: Dolu1990 * risc-v: remove tunnel ir length assert when ir is set by the user Change-Id: I2b33fc6205f37461ff1bd15601b460a2467ea32b Signed-off-by: Dolu1990 * Open riscv: Add a option to specify the JTAG TAP tunnel IR Typo Co-authored-by: Tim Newsome * riscv: Add a option to specify the JTAG TAP tunnel IR typo Co-authored-by: Tim Newsome Co-authored-by: Tim Newsome --- doc/openocd.texi | 5 +++++ src/target/riscv/riscv.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index a4fa6847e..187028749 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10624,6 +10624,11 @@ tunneled DR scan consists of: @end deffn +@deffn {Command} {riscv set_bscan_tunnel_ir} value +Allows the use_bscan_tunnel feature to target non Xilinx device by +specifying the JTAG TAP IR used to access the bscan tunnel. +@end deffn + @deffn {Command} {riscv set_maskisr} [@option{off}|@option{steponly}] Selects whether interrupts will be disabled when single stepping. The default configuration is @option{off}. This feature is only useful on hardware that always steps into interrupts and doesn't support dcsr.stepie=0. diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 484db7485..bde85b5d4 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -129,6 +129,7 @@ struct scan_field select_idcode = { bscan_tunnel_type_t bscan_tunnel_type; int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ +static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */ static const uint8_t bscan_zero[4] = {0}; static const uint8_t bscan_one[4] = {1}; @@ -450,8 +451,12 @@ static int riscv_init_target(struct command_context *cmd_ctx, select_idcode.num_bits = target->tap->ir_length; if (bscan_tunnel_ir_width != 0) { - assert(target->tap->ir_length >= 6); - uint32_t ir_user4_raw = 0x23 << (target->tap->ir_length - 6); + uint32_t ir_user4_raw = bscan_tunnel_ir_id; + /* Provide a default value which target some Xilinx FPGA USER4 IR */ + if (ir_user4_raw == 0) { + assert(target->tap->ir_length >= 6); + ir_user4_raw = 0x23 << (target->tap->ir_length - 6); + } ir_user4[0] = (uint8_t)ir_user4_raw; ir_user4[1] = (uint8_t)(ir_user4_raw >>= 8); ir_user4[2] = (uint8_t)(ir_user4_raw >>= 8); @@ -2913,6 +2918,24 @@ COMMAND_HANDLER(riscv_use_bscan_tunnel) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_bscan_tunnel_ir) +{ + int ir_id = 0; + + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ir_id); + } + + LOG_INFO("Bscan tunnel IR 0x%x selected", ir_id); + + bscan_tunnel_ir_id = ir_id; + return ERROR_OK; +} + + COMMAND_HANDLER(riscv_set_maskisr) { struct target *target = get_current_target(CMD_CTX); @@ -3347,6 +3370,15 @@ static const struct command_registration riscv_exec_command_handlers[] = { "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " "1: DATA_REGISTER}" }, + { + .name = "set_bscan_tunnel_ir", + .handler = riscv_set_bscan_tunnel_ir, + .mode = COMMAND_ANY, + .usage = "value", + .help = "Specify the JTAG TAP IR used to access the bscan tunnel. " + "By default it is 0x23 << (ir_length - 6), which map some " + "Xilinx FPGA (IR USER4)" + }, { .name = "set_maskisr", .handler = riscv_set_maskisr, From 2e5df83de7f2bceeeab762f24d1a15a850d75d9e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Mar 2022 15:30:16 +0100 Subject: [PATCH 106/186] nds32: deprecate it, together with aice adapter driver The target nds32 and its companion adapter aice have not received any real improvement since 2013. It has been hard to keep them aligned during the evolution of OpenOCD code, with no way for maintainers to really check if they are still working. No real documentation is present for them in OpenOCD. The arch nds32 has been dropped from Linux kernel v5.18-rc1. Deprecate both nds32 target and aice adapter with the target of dropping them for v0.13.0. Remove automatic build of aice, forcing user to select it. Change-Id: Ib465d676246fa3b4e95c3d399ba9a5cf1f8b3baf Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6887 Reviewed-by: Tomas Vanek Tested-by: jenkins --- configure.ac | 10 ++++++++-- doc/openocd.texi | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 15d7229a4..7037656ae 100644 --- a/configure.ac +++ b/configure.ac @@ -122,8 +122,10 @@ m4_define([USB1_ADAPTERS], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], - [[usbprog], [USBProg JTAG Programmer], [USBPROG]], - [[aice], [Andes JTAG Programmer], [AICE]]]) + [[usbprog], [USBProg JTAG Programmer], [USBPROG]]]) + +m4_define([DEPRECATED_USB1_ADAPTERS], + [[[aice], [Andes JTAG Programmer (deprecated)], [AICE]]]) m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], @@ -256,6 +258,8 @@ AC_ARG_ADAPTERS([ LIBJAYLINK_ADAPTERS ],[auto]) +AC_ARG_ADAPTERS([DEPRECATED_USB1_ADAPTERS],[no]) + AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) @@ -660,6 +664,7 @@ m4_define([PROCESS_ADAPTERS], [ ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) +PROCESS_ADAPTERS([DEPRECATED_USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) @@ -798,6 +803,7 @@ echo echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, + DEPRECATED_USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, diff --git a/doc/openocd.texi b/doc/openocd.texi index 1b6d06302..121873522 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4728,9 +4728,9 @@ specified, @xref{gdbportoverride,,option -gdb-port}.), and a fake ARM core will be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. -@item @code{nds32_v2} -- this is an Andes NDS32 v2 core. -@item @code{nds32_v3} -- this is an Andes NDS32 v3 core. -@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core. +@item @code{nds32_v2} -- this is an Andes NDS32 v2 core (deprecated; would be removed in v0.13.0). +@item @code{nds32_v3} -- this is an Andes NDS32 v3 core (deprecated; would be removed in v0.13.0). +@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core (deprecated; would be removed in v0.13.0). @item @code{or1k} -- this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: @itemize @minus From a5035849d671fc7821b7b864f0e103d6a0521915 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 18:59:49 +0200 Subject: [PATCH 107/186] tcl/target/stm32f4x: fix name Change-Id: I9baa79d8cf402991e6638c255a91728b8a77020c Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6930 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- tcl/target/stm32f4x.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 2228de72f..aa2816e76 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -1,7 +1,7 @@ # script for stm32f4x family # -# stm32 devices support both JTAG and SWD transports. +# stm32f4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] From d47aaf6d92788efc90c6d3379d58132e7ddfa781 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 19:02:21 +0200 Subject: [PATCH 108/186] tcl/target/stm32l4x: set default WORKAREASIZE to smallest device Change-Id: Ia8bfb664ff28bd0579492032ce513b010e71c593 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6931 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- tcl/target/stm32l4x.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 589979193..103d741e2 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -15,11 +15,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# Smallest current target has 64kB ram, use 32kB by default to avoid surprises +# By default use 40kB (Available RAM in smallest device STM32L412) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x8000 + set _WORKAREASIZE 0xa000 } #jtag scan chain From 7ca770cbf9ecda1fe603379f6973a70ec9e913a7 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 19:04:50 +0200 Subject: [PATCH 109/186] tcl/target/stm32l4x: switch to new TPIU/SWO support Change-Id: I3362fa7292eae7a3ba119cf6183f8bc4cbd5cbd4 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6932 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/stm32l4x.cfg | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 103d741e2..dec2b2760 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -38,6 +38,8 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } @@ -88,6 +90,37 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +proc proc_post_enable {_chipname} { + targets $_chipname.cpu + + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + switch [$_chipname.tpiu cget -port-width] { + 1 { + mmw 0xE0042004 0x00000060 0x000000c0 + mmw 0x48001020 0x00000000 0x0000ff00 + mmw 0x48001000 0x000000a0 0x000000f0 + mmw 0x48001008 0x000000f0 0x00000000 + } + 2 { + mmw 0xE0042004 0x000000a0 0x000000c0 + mmw 0x48001020 0x00000000 0x000fff00 + mmw 0x48001000 0x000002a0 0x000003f0 + mmw 0x48001008 0x000003f0 0x00000000 + } + 4 { + mmw 0xE0042004 0x000000e0 0x000000c0 + mmw 0x48001020 0x00000000 0x0fffff00 + mmw 0x48001000 0x00002aa0 0x00003ff0 + mmw 0x48001008 0x00003ff0 0x00000000 + } + } + } else { + mmw 0xE0042004 0x00000020 0x000000c0 + } +} + +$_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" + $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz). # Use MSI 24 MHz clock, compliant even with VOS == 2. @@ -111,10 +144,3 @@ $_TARGETNAME configure -event examine-end { # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0042004 0x00000020 0 -} From d8c81d72540a9e6a9f59412686332379ece1618f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 17 Apr 2022 16:01:24 +0200 Subject: [PATCH 110/186] tcl/target/stm32l4x: align format/order/comments with stm32f4x Change-Id: Ie97bb2f56b582bc735c238af5f160fcb28a61eb0 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6933 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/stm32l4x.cfg | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index dec2b2760..9bd7e37ba 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -49,8 +49,9 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] @@ -90,6 +91,16 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0042008 0x00001800 0 +} + proc proc_post_enable {_chipname} { targets $_chipname.cpu @@ -127,6 +138,7 @@ $_TARGETNAME configure -event reset-init { # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 + # Boost JTAG frequency adapter speed 4000 } @@ -135,12 +147,3 @@ $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP - mmw 0xE0042004 0x00000007 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0042008 0x00001800 0 -} From 5ebb1bdea1dfff9cce430bd17d08e340eea38e03 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 30 Mar 2022 23:55:04 +0200 Subject: [PATCH 111/186] server/gdb: fix return of gdb remote monitor command Current implementation for gdb remote monitor command uses the command_run_line() to execute the command. While command_run_line() has several advantages, it unfortunately hides the error codes and outputs the result of the command through LOG_USER(), which is not what gdb requires. See 'qRcmd' in https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html Replace command_run_line() with Jim_EvalObj() and parse the output to provide the proper result to gdb. Can be tested by defining in OpenOCD: proc a {} {return hello} proc b {} {return -code 4} proc c {} {return -code 4 "This is an error!"} then by executing in gdb console: monitor a monitor b monitor c monitor foo Change-Id: I1b85554d59221560e97861a499e16764e70c1172 Signed-off-by: Antonio Borneo Reported-by: Torbjorn Svensson Reviewed-on: https://review.openocd.org/c/openocd/+/6886 Tested-by: jenkins --- src/server/gdb_server.c | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 82c8ce92b..fcc87fba1 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2761,11 +2761,52 @@ static int gdb_query_packet(struct connection *connection, /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; - command_run_line(cmd_ctx, cmd); + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = target; + + int retval = Jim_EvalObj(cmd_ctx->interp, Jim_NewStringObj(cmd_ctx->interp, cmd, -1)); + + cmd_ctx->current_target_override = saved_target_override; current_gdb_connection = NULL; target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); + if (retval == JIM_RETURN) + retval = cmd_ctx->interp->returnCode; + int lenmsg; + const char *cretmsg = Jim_GetString(Jim_GetResult(cmd_ctx->interp), &lenmsg); + char *retmsg; + if (lenmsg && cretmsg[lenmsg - 1] != '\n') { + retmsg = alloc_printf("%s\n", cretmsg); + lenmsg++; + } else { + retmsg = strdup(cretmsg); + } + if (!retmsg) + return ERROR_GDB_BUFFER_TOO_SMALL; + + if (retval == JIM_OK) { + if (lenmsg) { + char *hex_buffer = malloc(lenmsg * 2 + 1); + if (!hex_buffer) { + free(retmsg); + return ERROR_GDB_BUFFER_TOO_SMALL; + } + + size_t pkt_len = hexify(hex_buffer, (const uint8_t *)retmsg, lenmsg, + lenmsg * 2 + 1); + gdb_put_packet(connection, hex_buffer, pkt_len); + free(hex_buffer); + } else { + gdb_put_packet(connection, "OK", 2); + } + } else { + if (lenmsg) + gdb_output_con(connection, retmsg); + gdb_send_error(connection, retval); + } + free(retmsg); + return ERROR_OK; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; From a213397323585188ad2622de7eb9d5fcddee7a02 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Tue, 12 Apr 2022 13:33:51 +0200 Subject: [PATCH 112/186] target/image: fix - p_flags field in ELF64 segment headers is 64 bits wide Fixed the reading of p_flags in ELF64 segment headers - that field is 64 bits wide. Change-Id: I053ca57d36efb54b7c638484acd6c7a2fbcbd05a Signed-off-by: Jan Matyas Reviewed-on: https://review.openocd.org/c/openocd/+/6927 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/image.c | 4 ++-- src/target/image.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/target/image.c b/src/target/image.c index eafa73eaa..130ea6c1f 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -596,7 +596,7 @@ static int image_elf64_read_headers(struct image *image) image->sections[j].base_address = field64(elf, elf->segments64[i].p_paddr); image->sections[j].private = &elf->segments64[i]; - image->sections[j].flags = field32(elf, elf->segments64[i].p_flags); + image->sections[j].flags = field64(elf, elf->segments64[i].p_flags); j++; } } @@ -1168,7 +1168,7 @@ int image_read_section(struct image *image, return ERROR_OK; } -int image_add_section(struct image *image, target_addr_t base, uint32_t size, int flags, uint8_t const *data) +int image_add_section(struct image *image, target_addr_t base, uint32_t size, uint64_t flags, uint8_t const *data) { struct imagesection *section; diff --git a/src/target/image.h b/src/target/image.h index 5b5d11f6b..bf06064ac 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -52,7 +52,7 @@ enum image_type { struct imagesection { target_addr_t base_address; uint32_t size; - int flags; + uint64_t flags; void *private; /* private data */ }; @@ -108,7 +108,7 @@ int image_read_section(struct image *image, int section, target_addr_t offset, void image_close(struct image *image); int image_add_section(struct image *image, target_addr_t base, uint32_t size, - int flags, uint8_t const *data); + uint64_t flags, uint8_t const *data); int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); From a26ee5344cf70e068265ac2f03a2915fae070e14 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Fri, 4 Feb 2022 09:11:39 +0100 Subject: [PATCH 113/186] rtos: zephyr: do not use deprecated symbols name Zephyr plan to remove openocd specific symbols in favour of more generic one. These generic symbols has been introduced in Zephyr 2.6. Signed-off-by: Julien Massot Change-Id: I89418c9c378fb8b8baa29763fc6f1b6e652dc7ef Reviewed-on: https://review.openocd.org/c/openocd/+/6844 Tested-by: jenkins Reviewed-by: Stephanos Ioannidis Reviewed-by: Antonio Borneo --- src/rtos/zephyr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtos/zephyr.c b/src/rtos/zephyr.c index 630511636..7f3325fea 100644 --- a/src/rtos/zephyr.c +++ b/src/rtos/zephyr.c @@ -375,15 +375,15 @@ static const struct symbol_table_elem zephyr_symbol_list[] = { .optional = false }, { - .symbol_name = "_kernel_openocd_offsets", + .symbol_name = "_kernel_thread_info_offsets", .optional = false }, { - .symbol_name = "_kernel_openocd_size_t_size", + .symbol_name = "_kernel_thread_info_size_t_size", .optional = false }, { - .symbol_name = "_kernel_openocd_num_offsets", + .symbol_name = "_kernel_thread_info_num_offsets", .optional = true }, { From f2b4897773a1c9db185dfb61d474055559fd507a Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 12:23:48 +0100 Subject: [PATCH 114/186] flash/stm32f1x: add support for RISC-V GigaDevice GD32VF103 The device has compatible flash macro with STM32F1 family, reuse stm32f1x driver code. Detect non-ARM target - for simplicy test target type name 'riscv' and the address has 32 bits. In case of RISC-V CPU use simple chunked write algo - async algo cannot be used as the core implemented in this device doesn't allow memory access while running. Change-Id: Ie3886fbd8573652691f91a02335812a7300689f7 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6704 Tested-by: jenkins Reviewed-by: Tim Newsome --- contrib/loaders/flash/gd32vf103/Makefile | 28 +++ contrib/loaders/flash/gd32vf103/gd32vf103.c | 33 +++ contrib/loaders/flash/gd32vf103/gd32vf103.inc | 4 + doc/openocd.texi | 1 + src/flash/nor/stm32f1x.c | 205 ++++++++++++++---- 5 files changed, 227 insertions(+), 44 deletions(-) create mode 100644 contrib/loaders/flash/gd32vf103/Makefile create mode 100644 contrib/loaders/flash/gd32vf103/gd32vf103.c create mode 100644 contrib/loaders/flash/gd32vf103/gd32vf103.inc diff --git a/contrib/loaders/flash/gd32vf103/Makefile b/contrib/loaders/flash/gd32vf103/Makefile new file mode 100644 index 000000000..2c34e08c0 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/Makefile @@ -0,0 +1,28 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= riscv-none-embed- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -march=rv32i -mabi=ilp32 -static -nostartfiles -nostdlib -Os -g -fPIC + +all: gd32vf103.inc + +.PHONY: clean + +%.elf: %.c + $(CC) $(CFLAGS) $< -o $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.lst *.bin *.inc diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.c b/contrib/loaders/flash/gd32vf103/gd32vf103.c new file mode 100644 index 000000000..69225a026 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include + +#define FLASH_BSY (1 << 0) +#define FLASH_PGERR (1 << 2) +#define FLASH_WRPRTERR (1 << 4) + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) __attribute__((naked)); + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) +{ + do { + *target_addr = *buffer++; + + register uint32_t sr; + do { + sr = *flash_sr; + } while (sr & FLASH_BSY); + + if (sr & (FLASH_PGERR | FLASH_WRPRTERR)) + break; + + target_addr++; + } while (--hwords_count); + asm("ebreak"); +} diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.inc b/contrib/loaders/flash/gd32vf103/gd32vf103.inc new file mode 100644 index 000000000..05eabff21 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.inc @@ -0,0 +1,4 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x83,0x57,0x06,0x00,0x13,0x06,0x26,0x00,0x23,0x90,0xf6,0x00,0x83,0x27,0x05,0x00, +0x13,0xf7,0x17,0x00,0xe3,0x1c,0x07,0xfe,0x93,0xf7,0x47,0x01,0x63,0x98,0x07,0x00, +0x93,0x85,0xf5,0xff,0x93,0x86,0x26,0x00,0xe3,0x9c,0x05,0xfc,0x73,0x00,0x10,0x00, diff --git a/doc/openocd.texi b/doc/openocd.texi index 121873522..d55002733 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7293,6 +7293,7 @@ applied to all of them. All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores. +The driver also works with GD32VF103 powered by RISC-V core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 8e66af368..dea8df759 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -26,6 +26,8 @@ #include "config.h" #endif +#include + #include "imp.h" #include #include @@ -129,7 +131,6 @@ struct stm32x_flash_bank { }; static int stm32x_mass_erase(struct flash_bank *bank); -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count); @@ -550,6 +551,109 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff return retval; } +static int stm32x_write_block_riscv(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + uint32_t buffer_size; + struct working_area *write_algorithm; + struct working_area *source; + static const uint8_t gd32vf103_flash_write_code[] = { +#include "../../../contrib/loaders/flash/gd32vf103/gd32vf103.inc" + }; + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(gd32vf103_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + int retval = target_write_buffer(target, write_algorithm->address, + sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + return retval; + } + + /* memory buffer */ + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + struct reg_param reg_params[4]; + + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */ + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ + init_reg_param(®_params[3], "a3", 32, PARAM_IN_OUT); /* target address */ + + while (hwords_count > 0) { + uint32_t thisrun_hwords = source->size / 2; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_hwords > hwords_count) + thisrun_hwords = hwords_count; + + /* Write data to buffer */ + retval = target_write_buffer(target, source->address, + thisrun_hwords * 2, buffer); + if (retval != ERROR_OK) + break; + + buf_set_u32(reg_params[0].value, 0, 32, stm32x_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_hwords); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, address); + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + write_algorithm->address, + write_algorithm->address + sizeof(gd32vf103_flash_write_code) - 4, + 10000, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + write_algorithm->address, retval); + break; + } + + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits + */ + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[3].value, 0, 32)); + break; + } + + /* Update counters */ + buffer += thisrun_hwords * 2; + address += thisrun_hwords * 2; + hwords_count -= thisrun_hwords; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + return retval; +} + /** Writes a block to flash either using target algorithm * or use fallback, host controlled halfword-by-halfword access. * Flash controller must be unlocked before this call. @@ -564,8 +668,15 @@ static int stm32x_write_block(struct flash_bank *bank, */ assert(address % 2 == 0); - /* try using a block write - on ARM architecture or... */ - int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + int retval; + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + /* try using a block write - on ARM architecture or... */ + retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + } else { + /* ... RISC-V architecture */ + retval = stm32x_write_block_riscv(bank, buffer, address, hwords_count); + } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -631,11 +742,13 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - struct target *target = bank->target; - uint32_t device_id_register = 0; +struct stm32x_property_addr { + uint32_t device_id; + uint32_t flash_size; +}; +static int stm32x_get_property_addr(struct target *target, struct stm32x_property_addr *addr) +{ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; @@ -643,63 +756,61 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M3_PARTNO: /* STM32F1x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; case CORTEX_M4_PARTNO: /* STM32F3x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M23_PARTNO: /* GD32E23x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + case CORTEX_M_PARTNO_INVALID: + /* Check for GD32VF103 with RISC-V CPU */ + if (strcmp(target_type_name(target), "riscv") == 0 + && target_address_bits(target) == 32) { + /* There is nothing like arm common_magic in riscv_info_t + * check text name of target and if target is 32-bit + */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + } + /* fallthrough */ default: LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } +} - /* read stm32 device id register */ - int retval = target_read_u32(target, device_id_register, device_id); +static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + struct target *target = bank->target; + struct stm32x_property_addr addr; + + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u32(target, addr.device_id, device_id); } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - uint32_t flash_size_reg; - - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_TARGET_NOT_EXAMINED; - } - - switch (cortex_m_get_partno_safe(target)) { - case CORTEX_M0_PARTNO: /* STM32F0x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M3_PARTNO: /* STM32F1x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - case CORTEX_M4_PARTNO: /* STM32F3x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M23_PARTNO: /* GD32E23x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - default: - LOG_ERROR("Cannot identify target as a stm32x"); - return ERROR_FAIL; - } + struct stm32x_property_addr addr; - int retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u16(target, addr.flash_size, flash_size_in_kb); } static int stm32x_probe(struct flash_bank *bank) @@ -790,6 +901,8 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; break; + case 0x1906: /* gd32vf103 */ + break; case 0x1909: /* gd32e23x */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; @@ -1005,6 +1118,10 @@ static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *c device_str = "GD32F3x0"; break; + case 0x1906: + device_str = "GD32VF103"; + break; + case 0x1909: /* gd32e23x */ device_str = "GD32E23x"; break; From 1c07229f8ca72e0f244e2289cefa28b65e21e774 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 17 Nov 2021 17:33:29 +0100 Subject: [PATCH 115/186] tcl/target/gd32vf103: add flash bank The flash is compatible with stm32f1x, reuse the driver. Extend the size of work area to RAM size of the smallest device. Stop watchdogs before flash programming. Change-Id: I67a7654a6e196f9d4b2409edaa7990c53334437e Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6711 Tested-by: jenkins Reviewed-by: Tim Newsome --- tcl/target/gd32vf103.cfg | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg index 0f4dcf375..cfc64783f 100644 --- a/tcl/target/gd32vf103.cfg +++ b/tcl/target/gd32vf103.cfg @@ -4,6 +4,8 @@ # https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ # +source [find mem_helper.tcl] + transport select jtag if { [info exists CHIPNAME] } { @@ -12,10 +14,11 @@ if { [info exists CHIPNAME] } { set _CHIPNAME gd32vf103 } +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x800 + set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d @@ -24,3 +27,14 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME + +# DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU +# does not allow the debugger to access memory. +# Stop watchdogs at least before flash programming. +$_TARGETNAME configure -event reset-init { + # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP + mmw 0xE0042004 0x00000300 0 +} From 9de084e0067a86b8040f8ea2c3f46dff0b9e6a70 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 30 Nov 2021 10:33:41 +0100 Subject: [PATCH 116/186] flash/nor/stm32f1x: add can_load_options flag for GD32F1x0, F3x0 and E23x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to GigaDevice user manuals the devices have OBRLD bit in FMC_CTL register which is functionally compatible with OBL_LAUNCH @ FLASH_CR of STM32 counterparts. Change-Id: I84d231b38815fcb6452fd73b9153b269cce3b737 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6759 Tested-by: jenkins Reviewed-by: Andrzej Sierżęga --- src/flash/nor/stm32f1x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index dea8df759..c750ff080 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -896,10 +896,12 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; break; case 0x1704: /* gd32f3x0 */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; + stm32x_info->can_load_options = true; break; case 0x1906: /* gd32vf103 */ break; @@ -907,6 +909,7 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; break; } break; From bd266161ca0d8b99adc72320b2e2427993763f8a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 10:48:10 -0700 Subject: [PATCH 117/186] Fix typo in comment. Change-Id: If847aaedc704857f30220da8d6af703f1b57ad1d --- src/target/riscv/riscv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index f3b753038..59680de78 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -216,7 +216,7 @@ typedef struct { struct reg_data_type_union vector_union; struct reg_data_type type_vector; - /* Set when trigger registers are changed by the user. This indicates we eed + /* Set when trigger registers are changed by the user. This indicates we need * to beware that we may hit a trigger that we didn't realize had been set. */ bool manual_hwbp_set; From e8b05455e21079d0e0698235bf4b85bda6023875 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 12:41:13 -0700 Subject: [PATCH 118/186] Make watchpoint.unique_id a uint32_t Now it matches breakpoint.unique_id. Change-Id: I06f24b2cede2ee56bdeac8666b5235f923b18659 --- src/target/breakpoints.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 0a5949594..fc5b50b18 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -56,7 +56,7 @@ struct watchpoint { bool is_set; unsigned int number; struct watchpoint *next; - int unique_id; + uint32_t unique_id; }; void breakpoint_clear_target(struct target *target); From dc320d26f03d2a9932947c3eb2f065bd35c80f44 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 12:46:09 -0700 Subject: [PATCH 119/186] Small code cleanup. Change-Id: I563b7c62494987287b13d9ed52a923e6f49a64be --- src/target/riscv/riscv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 484db7485..174568fbe 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1025,8 +1025,6 @@ int riscv_remove_watchpoint(struct target *target, * and new value. */ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { - struct watchpoint *wp = target->watchpoints; - LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target)); /*TODO instead of disassembling the instruction that we think caused the @@ -1081,6 +1079,7 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi return ERROR_FAIL; } + struct watchpoint *wp = target->watchpoints; while (wp) { /*TODO support length/mask */ if (wp->address == mem_addr) { From a6f32126846a4094c60c60b31393b9e1ab0b22fe Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 12:58:09 -0700 Subject: [PATCH 120/186] Create riscv_hit_trigger_hit_bit() function. This goes through the triggers OpenOCD set to find out if one of them has the hit bit set. Change-Id: I5b9f1c19273c7d40392a0cc278277ca6c94d2eae --- src/target/riscv/riscv.c | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 174568fbe..51ec64cbb 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1017,6 +1017,67 @@ int riscv_remove_watchpoint(struct target *target, return ERROR_OK; } +/** + * Look at the trigger hit bits to find out which trigger is the reason we're + * halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is + * ~0, no match was found. + */ +static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) +{ + RISCV_INFO(r); + + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + + *unique_id = ~0; + for (unsigned int i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == -1) + continue; + + if (riscv_set_register(target, GDB_REGNO_TSELECT, i) != ERROR_OK) + return ERROR_FAIL; + + uint64_t tdata1; + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + + uint64_t hit_mask = 0; + switch (type) { + case 1: + /* Doesn't support hit bit. */ + break; + case 2: + hit_mask = CSR_MCONTROL_HIT; + break; + case 6: + hit_mask = CSR_MCONTROL6_HIT; + break; + default: + LOG_DEBUG("trigger %d has unknown type %d", i, type); + continue; + } + + /* Note: If we ever use chained triggers, then this logic needs + * to be changed to ignore triggers that are not the last one in + * the chain. */ + if (tdata1 & hit_mask) { + LOG_DEBUG("Trigger %d (unique_id=%d) has hit bit set.", i, r->trigger_unique_id[i]); + if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) + return ERROR_FAIL; + + *unique_id = r->trigger_unique_id[i]; + break; + } + } + + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + /* Sets *hit_watchpoint to the first watchpoint identified as causing the * current halt. * From edcfcab8903afa96563a31852266b7bc265f32ee Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 12:58:57 -0700 Subject: [PATCH 121/186] Add trigger_hit field to riscv_info Change-Id: If4e1b5c37da4ab9301d91f41ba4789662b677a29 --- src/target/riscv/riscv.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 59680de78..59fdb38a9 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -124,6 +124,10 @@ typedef struct { * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; + /* The unique id of the trigger that caused the most recent halt. If the + * most recent halt was not caused by a trigger, then this is -1. */ + uint32_t trigger_hit; + /* The number of entries in the debug buffer. */ int debug_buffer_size; From 68e41dc1c8cc3815290a6997763f19a2dd52324a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 12:59:43 -0700 Subject: [PATCH 122/186] Remove empty line. Change-Id: Id00bfd73363e60e109b339e86d620c1ed7d5198a --- src/target/riscv/riscv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 51ec64cbb..a03de6cfe 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1159,7 +1159,6 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi return ERROR_FAIL; } - static int oldriscv_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { From d67a5bf0645f099f1d6457e4007ddb22b38a744b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 13:00:47 -0700 Subject: [PATCH 123/186] During polling, check which trigger has `hit` set. Change-Id: If226810ed930e5d7a2bab277a9f5b0f3ded86ffa --- src/target/riscv/riscv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a03de6cfe..ee5838191 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1252,11 +1252,15 @@ int riscv_flush_registers(struct target *target) /* Convert: RISC-V hart's halt reason --> OpenOCD's generic debug reason */ int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) { + RISCV_INFO(r); + r->trigger_hit = -1; switch (halt_reason) { case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; case RISCV_HALT_TRIGGER: + if (riscv_hit_trigger_hit_bit(target, &r->trigger_hit) != ERROR_OK) + return ERROR_FAIL; target->debug_reason = DBG_REASON_WATCHPOINT; break; case RISCV_HALT_INTERRUPT: From 73199226dfaf2df1c009509358c3a48fc3b0970d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 13:01:14 -0700 Subject: [PATCH 124/186] Report some triggers as hardware breakpoints. Instead of reporting them all as watchpoints. Change-Id: If43d282a168f64f8fed6f659bcebbe2ef72f23e9 --- src/target/riscv/riscv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index ee5838191..26824a999 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1262,6 +1262,11 @@ int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) if (riscv_hit_trigger_hit_bit(target, &r->trigger_hit) != ERROR_OK) return ERROR_FAIL; target->debug_reason = DBG_REASON_WATCHPOINT; + /* Check if we hit a hardware breakpoint. */ + for (struct breakpoint *bp = target->breakpoints; bp; bp = bp->next) { + if (bp->unique_id == r->trigger_hit) + target->debug_reason = DBG_REASON_BREAKPOINT; + } break; case RISCV_HALT_INTERRUPT: case RISCV_HALT_GROUP: From 1979ad5594ba1ebf1f5e0876f780c4c1c8f187cb Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Apr 2022 13:02:00 -0700 Subject: [PATCH 125/186] If we know which trigger hit, don't disassemble. Change-Id: I1d7b6ffa91b0557e2e74e544e4b35033ed3e3553 Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 26824a999..4ab6d9965 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1086,12 +1086,19 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) * and new value. */ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { + RISCV_INFO(r); + LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target)); - /*TODO instead of disassembling the instruction that we think caused the - * trigger, check the hit bit of each watchpoint first. The hit bit is - * simpler and more reliable to check but as it is optional and relatively - * new, not all hardware will implement it */ + /* If we identified which trigger caused the halt earlier, then just use + * that. */ + for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { + if (wp->unique_id == r->trigger_hit) { + *hit_watchpoint = wp; + return ERROR_OK; + } + } + riscv_reg_t dpc; riscv_get_register(target, &dpc, GDB_REGNO_DPC); const uint8_t length = 4; From 20adf85f3484ee7137f2c11a491a6929b342d1f5 Mon Sep 17 00:00:00 2001 From: Steve Marple Date: Tue, 12 Apr 2022 18:25:40 +0100 Subject: [PATCH 126/186] linuxgpiod: add SWDIO buffer The SWDIO buffer requires a direction pin to select input or output direction. Output is selected by a high logic level (matches bcm2835gpio driver). Change-Id: I240cb99a5dfea08121bb33d4b5e2108ce7597468 Signed-off-by: Steve Marple Reviewed-on: https://review.openocd.org/c/openocd/+/6936 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/linuxgpiod.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 9f9f27a9f..288035f2e 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -27,6 +27,7 @@ static int trst_gpio = -1; static int srst_gpio = -1; static int swclk_gpio = -1; static int swdio_gpio = -1; +static int swdio_dir_gpio = -1; static int led_gpio = -1; static int gpiochip = -1; static int tck_gpiochip = -1; @@ -37,6 +38,7 @@ static int trst_gpiochip = -1; static int srst_gpiochip = -1; static int swclk_gpiochip = -1; static int swdio_gpiochip = -1; +static int swdio_dir_gpiochip = -1; static int led_gpiochip = -1; static struct gpiod_chip *gpiod_chip_tck; @@ -47,6 +49,7 @@ static struct gpiod_chip *gpiod_chip_trst; static struct gpiod_chip *gpiod_chip_srst; static struct gpiod_chip *gpiod_chip_swclk; static struct gpiod_chip *gpiod_chip_swdio; +static struct gpiod_chip *gpiod_chip_swdio_dir; static struct gpiod_chip *gpiod_chip_led; static struct gpiod_line *gpiod_tck; @@ -56,6 +59,7 @@ static struct gpiod_line *gpiod_tdo; static struct gpiod_line *gpiod_trst; static struct gpiod_line *gpiod_swclk; static struct gpiod_line *gpiod_swdio; +static struct gpiod_line *gpiod_swdio_dir; static struct gpiod_line *gpiod_srst; static struct gpiod_line *gpiod_led; @@ -63,6 +67,7 @@ static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; +static bool swdio_dir_is_active_high = true; /* Bitbang interface read of TDO */ static bb_value_t linuxgpiod_read(void) @@ -152,6 +157,11 @@ static void linuxgpiod_swdio_drive(bool is_output) gpiod_line_release(gpiod_swdio); if (is_output) { + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 1 : 0); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); if (retval < 0) LOG_WARNING("Fail request_output line swdio"); @@ -159,6 +169,11 @@ static void linuxgpiod_swdio_drive(bool is_output) retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD"); if (retval < 0) LOG_WARNING("Fail request_input line swdio"); + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 0 : 1); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } } last_stored = false; @@ -297,6 +312,8 @@ static int linuxgpiod_quit(void) gpiod_chip_close(gpiod_chip_srst); if (gpiod_chip_swdio != NULL) gpiod_chip_close(gpiod_chip_swdio); + if (gpiod_chip_swdio_dir != NULL) + gpiod_chip_close(gpiod_chip_swdio_dir); if (gpiod_chip_swclk != NULL) gpiod_chip_close(gpiod_chip_swclk); if (gpiod_chip_trst != NULL) @@ -451,10 +468,26 @@ static int linuxgpiod_init(void) goto out_error; } + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_chip_swdio_dir = gpiod_chip_open_by_number(swdio_dir_gpiochip); + if (!gpiod_chip_swdio_dir) { + LOG_ERROR("Cannot open LinuxGPIOD swdio_dir_gpiochip %d", swdio_dir_gpiochip); + goto out_error; + } + } + gpiod_swclk = helper_get_output_line("swclk", gpiod_chip_swclk, swclk_gpio, 1); if (!gpiod_swclk) goto out_error; + /* Set buffer direction before making SWDIO an output */ + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_swdio_dir = helper_get_output_line("swdio_dir", gpiod_chip_swdio_dir, swdio_dir_gpio, + swdio_dir_is_active_high ? 1 : 0); + if (!gpiod_swdio_dir) + goto out_error; + } + gpiod_swdio = helper_get_output_line("swdio", gpiod_chip_swdio, swdio_gpio, 1); if (!gpiod_swdio) goto out_error; @@ -593,6 +626,12 @@ COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) &swdio_gpio); } +COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio_dir) +{ + return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio_dir", &swdio_dir_gpiochip, + &swdio_dir_gpio); +} + COMMAND_HANDLER(linuxgpiod_handle_gpionum_led) { return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "led", &led_gpiochip, @@ -611,6 +650,7 @@ COMMAND_HANDLER(linuxgpiod_handle_gpiochip) srst_gpiochip = gpiochip; swclk_gpiochip = gpiochip; swdio_gpiochip = gpiochip; + swdio_dir_gpiochip = gpiochip; led_gpiochip = gpiochip; } @@ -689,6 +729,13 @@ static const struct command_registration linuxgpiod_subcommand_handlers[] = { .help = "gpio chip number (optional) and gpio number for swdio.", .usage = "[chip] swdio", }, + { + .name = "swdio_dir_num", + .handler = linuxgpiod_handle_swd_gpionum_swdio_dir, + .mode = COMMAND_CONFIG, + .help = "gpio chip number (optional) and gpio number for swdio_dir.", + .usage = "[chip] swdio_dir", + }, { .name = "led_num", .handler = linuxgpiod_handle_gpionum_led, From 9eddc21a585a813d7675d9d4ad07c5d8c97dee9b Mon Sep 17 00:00:00 2001 From: Steve Marple Date: Tue, 19 Apr 2022 23:29:55 +0100 Subject: [PATCH 127/186] bcm2835gpio: Make buffer an output before the GPIO connected to it The correct ordering is required to prevent two outputs connected together. Change-Id: I634a9ca7e0ccf337d1723011b8aee1f2d81efbcf Signed-off-by: Steve Marple Reviewed-on: https://review.openocd.org/c/openocd/+/6937 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/bcm2835gpio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index fd6c28b96..b7a4d998c 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -565,6 +565,13 @@ static int bcm2835gpio_init(void) } if (transport_is_swd()) { + /* Make buffer an output before the GPIO connected to it */ + if (swdio_dir_gpio != -1) { + swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio); + GPIO_SET = 1 << swdio_dir_gpio; + OUT_GPIO(swdio_dir_gpio); + } + swclk_gpio_mode = MODE_GPIO(swclk_gpio); swdio_gpio_mode = MODE_GPIO(swdio_gpio); @@ -580,12 +587,6 @@ static int bcm2835gpio_init(void) OUT_GPIO(srst_gpio); } - if (swdio_dir_gpio != -1) { - swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio); - GPIO_SET = 1 << swdio_dir_gpio; - OUT_GPIO(swdio_dir_gpio); - } - LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); From 8789513fa94ff54f08eaffedce0cc6c38f44311d Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 23 Apr 2022 13:13:06 +0200 Subject: [PATCH 128/186] target/arm_cti: Fix error handling in 'cti create' Handle JIM_CONTINUE return value of adiv5_jim_mem_ap_spot_configure(), otherwise OpenOCD silently quits when an unknown option is provided. Change-Id: I9b1351c0911e74999d8dd1260ede9760088510d7 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6944 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_cti.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index c776e9c2a..96927bf94 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -435,8 +435,13 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) /* parse config or cget options ... */ while (goi->argc > 0) { int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi); + + if (e == JIM_CONTINUE) + Jim_SetResultFormatted(goi->interp, "unknown option '%s'", + Jim_String(goi->argv[0])); + if (e != JIM_OK) - return e; + return JIM_ERR; } if (!cti->spot.dap) { From 12d1ad0c75298d56827debcacc83c679bfbe9ac2 Mon Sep 17 00:00:00 2001 From: fatalc Date: Mon, 25 Apr 2022 12:06:10 +0800 Subject: [PATCH 129/186] target/disassembler: update capstone include path to on macos (homebrew base) `pkg-config --cflags capstone` output with `-I/opt/homebrew/Cellar/capstone/4.0.2/include/capstone` gcc not find headers on parent "include" path, causes build error `fatal error: 'capstone/capstone.h' file not found` it's ok to change to for all platforms. Signed-off-by: fatalc Change-Id: Ia2e2058024d4fc1a57a8b4ea847c664d74f67efb Reviewed-on: https://review.openocd.org/c/openocd/+/6946 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/a64_disassembler.c | 2 +- src/target/arm_disassembler.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/a64_disassembler.c b/src/target/a64_disassembler.c index bd78129dd..58ddf603e 100644 --- a/src/target/a64_disassembler.c +++ b/src/target/a64_disassembler.c @@ -26,7 +26,7 @@ #if HAVE_CAPSTONE -#include +#include static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) { diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 661859379..d3d27a93c 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -27,7 +27,7 @@ #include #if HAVE_CAPSTONE -#include +#include #endif /* From 66335683fec62ac89da48d64932fd9d082314225 Mon Sep 17 00:00:00 2001 From: jihongbin Date: Fri, 29 Apr 2022 17:03:15 +0800 Subject: [PATCH 130/186] drivers/cmsis-dap: Correct the DAP protocol parameter parsing error Fixes: 01030fb89354 (drivers/cmsis-dap: tidy up buffer access) Change-Id: Id192d3930a89980d641058b6444d12caec19ce6f Signed-off-by: Hongbin Ji Reviewed-on: https://review.openocd.org/c/openocd/+/6954 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo Reviewed-by: jihongbin --- src/jtag/drivers/cmsis_dap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 63407be42..eaa65abc6 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1405,18 +1405,18 @@ static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) for (int i = 0; i < cmdlen; ++i) printf(" %02x", cmd[i]); printf("\n"); - switch (cmd[1]) { + switch (cmd[0]) { case CMD_DAP_JTAG_SEQ: { - printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[1], cmd[2]); + printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); /* - * #2 = number of sequences - * #3 = sequence info 1 - * #4...4+n_bytes-1 = sequence 1 + * #1 = number of sequences + * #2 = sequence info 1 + * #3...4+n_bytes-1 = sequence 1 * #4+n_bytes = sequence info 2 * #5+n_bytes = sequence 2 (single bit) */ - int pos = 3; - for (int seq = 0; seq < cmd[2]; ++seq) { + int pos = 2; + for (int seq = 0; seq < cmd[1]; ++seq) { uint8_t info = cmd[pos++]; int len = info & DAP_JTAG_SEQ_TCK; if (len == 0) From 8e1064f1fec5b15957c552526c49f42c41be5b6d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 3 May 2022 13:44:25 -0700 Subject: [PATCH 131/186] Remove gd32vf103 flash driver. Per mainline, use stm32f1x instead. Tested that this is working. Change-Id: Icda4b2a39e06e2adf9bbfb984bd578347f43d7d1 Signed-off-by: Tim Newsome --- src/flash/nor/Makefile.am | 1 - src/flash/nor/drivers.c | 2 - src/flash/nor/gd32vf103.c | 1344 ------------------------------------- 3 files changed, 1347 deletions(-) delete mode 100644 src/flash/nor/gd32vf103.c diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index a09174448..a5ef42210 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -66,7 +66,6 @@ NOR_DRIVERS = \ %D%/stm32lx.c \ %D%/stm32l4x.c \ %D%/stm32h7x.c \ - %D%/gd32vf103.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index dc966ed94..3e35c0954 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -44,7 +44,6 @@ extern const struct flash_driver faux_flash; extern const struct flash_driver fm3_flash; extern const struct flash_driver fm4_flash; extern const struct flash_driver fespi_flash; -extern const struct flash_driver gd32vf103_flash; extern const struct flash_driver jtagspi_flash; extern const struct flash_driver kinetis_flash; extern const struct flash_driver kinetis_ke_flash; @@ -153,7 +152,6 @@ static const struct flash_driver * const flash_drivers[] = { &stm32lx_flash, &stm32l4x_flash, &stm32h7x_flash, - &gd32vf103_flash, &stmsmi_flash, &stmqspi_flash, &str7x_flash, diff --git a/src/flash/nor/gd32vf103.c b/src/flash/nor/gd32vf103.c deleted file mode 100644 index 562f41e7b..000000000 --- a/src/flash/nor/gd32vf103.c +++ /dev/null @@ -1,1344 +0,0 @@ -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "imp.h" -#include -#include - -/* gd32vf103 register locations */ - -#define FLASH_REG_BASE_B0 0x40022000 -#define FLASH_REG_BASE_B1 0x40022040 - -#define FMC_WS 0x00 -#define FMC_KEY 0x04 -#define FMC_OBKEY 0x08 -#define FMC_STAT 0x0C -#define FMC_CTL 0x10 -#define FMC_ADDR 0x14 -#define FMC_OBSTAT 0x1C - -/* TODO: Check if code using these really should be hard coded to bank 0. - * There are valid cases, on dual flash devices the protection of the - * second bank is done on the bank0 reg's. */ -#define FMC_WS_B0 0x40022000 -#define FMC_KEY_B0 0x40022004 -#define FMC_OBKEY_B0 0x40022008 -#define FMC_STAT_B0 0x4002200C -#define FMC_CTL_B0 0x40022010 -#define FMC_ADDR_B0 0x40022014 -#define FMC_OBSTAT_B0 0x4002201C -#define FMC_WP_B0 0x40022020 - -/* option byte location */ - -#define FMC_OB_RDP 0x1FFFF800 - -/* FMC_CTL register bits */ - -#define FMC_CTL_PG (1 << 0) -#define FMC_CTL_PER (1 << 1) -#define FMC_CTL_MER (1 << 2) -#define FMC_CTL_OBPG (1 << 4) -#define FMC_CTL_OBER (1 << 5) -#define FMC_CTL_START (1 << 6) -#define FMC_CTL_LK (1 << 7) -#define FMC_CTL_OBWEN (1 << 9) - -/* FMC_STAT register bits */ - -#define FMC_STAT_BUSY (1 << 0) -#define FMC_STAT_PGERR (1 << 2) -#define FMC_STAT_WPERR (1 << 4) -#define FMC_STAT_ENDF (1 << 5) - -/* FMC_OBSTAT bit definitions (reading) */ - -#define FMC_OBSTAT_OBERR 0 -#define FMC_OBSTAT_SPC 1 -#define FMC_OBSTAT_WDG_SW 2 -#define FMC_OBSTAT_RST_DSLEEP 3 -#define FMC_OBSTAT_RST_STDBY 4 -#define FMC_OBSTAT_BB 5 /* dual flash bank only */ - -/* register unlock keys */ - -#define UNLOCK_KEY0 0x45670123 -#define UNLOCK_KEY1 0xCDEF89AB - -/* timeout values */ - -#define FLASH_WRITE_TIMEOUT 500 -#define FLASH_ERASE_TIMEOUT 5000 - -struct gd32vf103_options { - uint16_t RDP; - uint16_t user_options; - uint16_t user_data; - uint16_t protection[4]; -}; - -struct gd32vf103_flash_bank { - struct gd32vf103_options option_bytes; - int ppage_size; - int probed; - - bool has_dual_banks; - /* used to access dual flash bank gd32vf103 */ - uint32_t register_base; - uint16_t default_rdp; - int user_data_offset; - int option_offset; - uint32_t user_bank_size; -}; - -static int gd32vf103_mass_erase(struct flash_bank *bank); -static int get_gd32vf103_info(struct flash_bank *bank, struct command_invocation *cmd); -static int gd32vf103_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count); - -/* flash bank gd32vf103 0 0 - */ -FLASH_BANK_COMMAND_HANDLER(gd32vf103_flash_bank_command) -{ - struct gd32vf103_flash_bank *gd32vf103_info; - - if (CMD_ARGC < 6) - return ERROR_COMMAND_SYNTAX_ERROR; - - gd32vf103_info = malloc(sizeof(struct gd32vf103_flash_bank)); - - bank->driver_priv = gd32vf103_info; - gd32vf103_info->probed = 0; - gd32vf103_info->has_dual_banks = false; - gd32vf103_info->register_base = FLASH_REG_BASE_B0; - gd32vf103_info->user_bank_size = bank->size; - - return ERROR_OK; -} - -static inline int gd32vf103_get_flash_reg(struct flash_bank *bank, uint32_t reg) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - return reg + gd32vf103_info->register_base; -} - -static inline int gd32vf103_get_flash_status(struct flash_bank *bank, uint32_t *status) -{ - struct target *target = bank->target; - return target_read_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), status); -} - -static int gd32vf103_wait_status_busy(struct flash_bank *bank, int timeout) -{ - struct target *target = bank->target; - uint32_t status; - int retval = ERROR_OK; - - /* wait for busy to clear */ - for (;;) { - retval = gd32vf103_get_flash_status(bank, &status); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); - if ((status & FMC_STAT_BUSY) == 0) - break; - if (timeout-- <= 0) { - LOG_ERROR("timed out waiting for flash"); - return ERROR_FAIL; - } - alive_sleep(1); - } - - if (status & FMC_STAT_WPERR) { - LOG_ERROR("gd32vf103 device protected"); - retval = ERROR_FAIL; - } - - if (status & FMC_STAT_PGERR) { - LOG_ERROR("gd32vf103 device programming failed"); - retval = ERROR_FAIL; - } - - /* Clear but report errors */ - if (status & (FMC_STAT_WPERR | FMC_STAT_PGERR)) { - /* If this operation fails, we ignore it and report the original - * retval - */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), - FMC_STAT_WPERR | FMC_STAT_PGERR); - } - return retval; -} - -static int gd32vf103_check_operation_supported(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - - /* if we have a dual flash bank device then - * we need to perform option byte stuff on bank0 only */ - if (gd32vf103_info->register_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Operation's must use bank0"); - return ERROR_FLASH_OPERATION_FAILED; - } - - return ERROR_OK; -} - -static int gd32vf103_read_options(struct flash_bank *bank) -{ - uint32_t optiondata; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* read current option bytes */ - int retval = target_read_u32(target, FMC_OBSTAT_B0, &optiondata); - if (retval != ERROR_OK) - return retval; - - gd32vf103_info->option_bytes.user_options = (optiondata >> gd32vf103_info->option_offset >> 2) & 0xffff; - gd32vf103_info->option_bytes.user_data = (optiondata >> gd32vf103_info->user_data_offset) & 0xffff; - gd32vf103_info->option_bytes.RDP = (optiondata & (1 << FMC_OBSTAT_SPC)) ? 0xFFFF : 0x5AA5; - - if (optiondata & (1 << FMC_OBSTAT_SPC)) - LOG_INFO("Device Security Bit Set"); - - /* each bit refers to a 4bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &optiondata); - if (retval != ERROR_OK) - return retval; - - gd32vf103_info->option_bytes.protection[0] = (uint16_t)optiondata; - gd32vf103_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); - gd32vf103_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); - gd32vf103_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); - - return ERROR_OK; -} - -static int gd32vf103_erase_options(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* read current options */ - gd32vf103_read_options(bank); - - /* unlock flash registers */ - int retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* unlock option flash registers */ - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* erase option bytes */ - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBER | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBER | FMC_CTL_START | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - /* clear readout protection and complementary option bytes - * this will also force a device unlock if set */ - gd32vf103_info->option_bytes.RDP = gd32vf103_info->default_rdp; - - return ERROR_OK; -} - -static int gd32vf103_write_options(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* unlock flash registers */ - int retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* unlock option flash registers */ - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* program option bytes */ - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBPG | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - - uint8_t opt_bytes[16]; - - target_buffer_set_u16(target, opt_bytes, gd32vf103_info->option_bytes.RDP); /* SPC */ - target_buffer_set_u16(target, opt_bytes + 2, gd32vf103_info->option_bytes.user_options); /* USER */ - target_buffer_set_u16(target, opt_bytes + 4, gd32vf103_info->option_bytes.user_data & 0xff); /* DATA[7:0] */ - target_buffer_set_u16(target, opt_bytes + 6, (gd32vf103_info->option_bytes.user_data >> 8) & 0xff); /* DATA[15:8] */ - target_buffer_set_u16(target, opt_bytes + 8, gd32vf103_info->option_bytes.protection[0]); /* WP[7:0] */ - target_buffer_set_u16(target, opt_bytes + 10, gd32vf103_info->option_bytes.protection[1]); /* WP[15:8] */ - target_buffer_set_u16(target, opt_bytes + 12, gd32vf103_info->option_bytes.protection[2]); /* WP[23:16] */ - target_buffer_set_u16(target, opt_bytes + 14, gd32vf103_info->option_bytes.protection[3]); /* WP[31:24] */ - - uint32_t offset = FMC_OB_RDP - bank->base; - retval = gd32vf103_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - LOG_ERROR("working area required to erase options bytes"); - return retval; - } - - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -static int gd32vf103_protect_check(struct flash_bank *bank) -{ - struct target *target = bank->target; - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - - uint32_t protection; - int i; - int num_bits; - int set; - - int retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &protection); - if (retval != ERROR_OK) - return retval; - - /* medium density - each protection bit is for 4 * 1K pages - * high density - each protection bit is for 2 * 2K pages */ - num_bits = (bank->num_sectors / gd32vf103_info->ppage_size); - - if (gd32vf103_info->ppage_size == 2) { - /* high density flash/connectivity line protection */ - - set = 1; - - if (protection & (1 << 31)) - set = 0; - - /* bit 31 controls sector 62 - 255 protection for high density - * bit 31 controls sector 62 - 127 protection for connectivity line */ - for (unsigned s = 62; s < bank->num_sectors; s++) - bank->sectors[s].is_protected = set; - - if (bank->num_sectors > 61) - num_bits = 31; - - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (int s = 0; s < gd32vf103_info->ppage_size; s++) - bank->sectors[(i * gd32vf103_info->ppage_size) + s].is_protected = set; - } - } else { - /* low/medium density flash protection */ - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (int s = 0; s < gd32vf103_info->ppage_size; s++) - bank->sectors[(i * gd32vf103_info->ppage_size) + s].is_protected = set; - } - } - - return ERROR_OK; -} - -static int gd32vf103_erase(struct flash_bank *bank, unsigned first, unsigned last) -{ - struct target *target = bank->target; - uint32_t optiondata; - uint32_t obstat; - - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - gd32vf103_info = bank->driver_priv; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - target_read_u32(target, FMC_WP_B0, &optiondata); - target_read_u32(target, FMC_OBSTAT_B0, &obstat); - if ((0xFFFFFFFF != optiondata) || ((obstat & 0x2) != 0)) { - gd32vf103_erase_options(bank); - optiondata = 0xFFFFFFFF; - gd32vf103_info->option_bytes.RDP = 0x5AA5; - gd32vf103_info->option_bytes.protection[0] = (uint16_t)optiondata; - gd32vf103_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); - gd32vf103_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); - gd32vf103_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); - - gd32vf103_write_options(bank); - LOG_INFO(" Unlock flash Sucess !!! Pls Reset Platfrom !!\n"); - return ERROR_FAIL; - } - if ((first == 0) && (last == (bank->num_sectors - 1))) - return gd32vf103_mass_erase(bank); - - /* unlock flash registers */ - int retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - for (unsigned i = first; i <= last; i++) { - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PER); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_ADDR), - bank->base + bank->sectors[i].offset); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, - gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PER | FMC_CTL_START); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - bank->sectors[i].is_erased = 1; - } - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -static int gd32vf103_protect(struct flash_bank *bank, int set, unsigned first, unsigned last) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; - int reg, bit; - int status; - uint32_t protection; - - gd32vf103_info = bank->driver_priv; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if ((first % gd32vf103_info->ppage_size) != 0) { - LOG_WARNING("aligned start protect sector to a %d sector boundary", - gd32vf103_info->ppage_size); - first = first - (first % gd32vf103_info->ppage_size); - } - if (((last + 1) % gd32vf103_info->ppage_size) != 0) { - LOG_WARNING("aligned end protect sector to a %d sector boundary", - gd32vf103_info->ppage_size); - last++; - last = last - (last % gd32vf103_info->ppage_size); - last--; - } - - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &protection); - if (retval != ERROR_OK) - return retval; - - prot_reg[0] = (uint16_t)protection; - prot_reg[1] = (uint16_t)(protection >> 8); - prot_reg[2] = (uint16_t)(protection >> 16); - prot_reg[3] = (uint16_t)(protection >> 24); - - if (gd32vf103_info->ppage_size == 2) { - /* high density flash */ - - /* bit 7 controls sector 62 - 255 protection */ - if (last > 61) { - if (set) - prot_reg[3] &= ~(1 << 7); - else - prot_reg[3] |= (1 << 7); - } - - if (first > 61) - first = 62; - if (last > 61) - last = 61; - - for (unsigned i = first; i <= last; i++) { - reg = (i / gd32vf103_info->ppage_size) / 8; - bit = (i / gd32vf103_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } - } else { - /* medium density flash */ - for (unsigned i = first; i <= last; i++) { - reg = (i / gd32vf103_info->ppage_size) / 8; - bit = (i / gd32vf103_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } - } - - status = gd32vf103_erase_options(bank); - if (status != ERROR_OK) - return status; - - gd32vf103_info->option_bytes.protection[0] = prot_reg[0]; - gd32vf103_info->option_bytes.protection[1] = prot_reg[1]; - gd32vf103_info->option_bytes.protection[2] = prot_reg[2]; - gd32vf103_info->option_bytes.protection[3] = prot_reg[3]; - - return gd32vf103_write_options(bank); -} - -static int gd32vf103_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t buffer_size = 16384; - struct working_area *write_algorithm; - struct working_area *source; - uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; - int retval = ERROR_OK; - - static const uint8_t gd32vf103_flash_write_code[] = { -#include "../../../contrib/loaders/flash/gd32v/gd32vf103.inc" - }; - - /* flash write code */ - if (target_alloc_working_area(target, sizeof(gd32vf103_flash_write_code), - &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - retval = target_write_buffer(target, write_algorithm->address, - sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); - if (retval != ERROR_OK) { - target_free_working_area(target, write_algorithm); - return retval; - } - - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - } - - init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ - init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ - init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ - init_reg_param(®_params[3], "a3", 32, PARAM_OUT); /* buffer end */ - init_reg_param(®_params[4], "a4", 32, PARAM_IN_OUT); /* target address */ - - - uint32_t wp_addr = source->address; - uint32_t rp_addr = source->address + 4; - uint32_t fifo_start_addr = source->address + 8; - uint32_t fifo_end_addr = source->address + source->size; - - uint32_t wp = fifo_start_addr; - uint32_t rp = fifo_start_addr; - uint32_t thisrun_bytes = fifo_end_addr-fifo_start_addr-2; /* (2:block size) */ - - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - return retval; - - while (count > 0) { - retval = target_read_u32(target, rp_addr, &rp); - if (retval != ERROR_OK) { - LOG_ERROR("failed to get read pointer"); - break; - } - - if (wp != rp) { - LOG_ERROR("Failed to write flash ;; rp = 0x%x ;;; wp = 0x%x", rp, wp); - break; - } - wp = fifo_start_addr; - rp = fifo_start_addr; - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - break; - /* Limit to the amount of data we actually want to write */ - if (thisrun_bytes > count * 2) - thisrun_bytes = count * 2; - - /* Write data to fifo */ - retval = target_write_buffer(target, wp, thisrun_bytes, buffer); - if (retval != ERROR_OK) - break; - - /* Update counters and wrap write pointer */ - buffer += thisrun_bytes; - count -= thisrun_bytes / 2; - rp = fifo_start_addr; - wp = fifo_start_addr+thisrun_bytes; - - /* Store updated write pointer to target */ - retval = target_write_u32(target, wp_addr, wp); - if (retval != ERROR_OK) - break; - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - return retval; - - buf_set_u32(reg_params[0].value, 0, 32, gd32vf103_info->register_base); - buf_set_u32(reg_params[1].value, 0, 32, thisrun_bytes/2); - buf_set_u32(reg_params[2].value, 0, 32, source->address); - buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[4].value, 0, 32, address); - - retval = target_run_algorithm(target, 0, NULL, 5, reg_params, - write_algorithm->address, write_algorithm->address+4, - 10000, NULL); - - if (retval != ERROR_OK) { - LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", - write_algorithm->address, retval); - return retval; - } - address += thisrun_bytes; - - } - - - if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); - - if (buf_get_u32(reg_params[0].value, 0, 32) & FMC_STAT_PGERR) { - LOG_ERROR("flash memory not erased before writing"); - /* Clear but report errors */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), FMC_STAT_PGERR); - } - - if (buf_get_u32(reg_params[0].value, 0, 32) & FMC_STAT_WPERR) { - LOG_ERROR("flash memory write protected"); - /* Clear but report errors */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), FMC_STAT_WPERR); - } - } - - target_free_working_area(target, source); - target_free_working_area(target, write_algorithm); - - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - - return retval; -} - -static int gd32vf103_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct target *target = bank->target; - uint8_t *new_buffer = NULL; - - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - /* If there's an odd number of bytes, the data has to be padded. Duplicate - * the buffer and use the normal code path with a single block write since - * it's probably cheaper than to special case the last odd write using - * discrete accesses. */ - if (count & 1) { - new_buffer = malloc(count + 1); - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write, padding with 0xff"); - buffer = memcpy(new_buffer, buffer, count); - new_buffer[count++] = 0xff; - } - - uint32_t words_remaining = count / 2; - int retval, retval2; - - /* unlock flash registers */ - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - goto cleanup; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - goto cleanup; - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PG); - if (retval != ERROR_OK) - goto cleanup; - - /* try using a block write */ - retval = gd32vf103_write_block(bank, buffer, offset, words_remaining); - - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single halfword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - - while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - retval = target_write_u16(target, bank->base + offset, value); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - retval = gd32vf103_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - words_remaining--; - buffer += 2; - offset += 2; - } - } - -reset_pg_and_lock: - retval2 = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval == ERROR_OK) - retval = retval2; - -cleanup: - if (new_buffer) - free(new_buffer); - - return retval; -} - -static int gd32vf103_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - - struct target *target = bank->target; - uint32_t device_id_register = 0xE0042000; - /* read GD32VF103 device id register */ - int retval = target_read_u32(target, device_id_register, device_id); - if (retval != ERROR_OK) - return retval; - - return retval; -} - -static int gd32vf103_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) -{ - struct target *target = bank->target; - uint32_t flash_size_reg = 0x1FFFF7E0; - - int retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); - if (retval != ERROR_OK) - return retval; - - return retval; -} - -static int gd32vf103_probe(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - int i; - uint16_t flash_size_in_kb; - uint16_t max_flash_size_in_kb; - uint32_t device_id; - int page_size; - uint32_t base_address = 0x08000000; - - gd32vf103_info->probed = 0; - gd32vf103_info->register_base = FLASH_REG_BASE_B0; - gd32vf103_info->user_data_offset = 10; - gd32vf103_info->option_offset = 0; - - /* default factory protection level */ - gd32vf103_info->default_rdp = 0x5AA5; - - /* read gd32vf103 device id register */ - int retval = gd32vf103_get_device_id(bank, &device_id); - if (retval != ERROR_OK) - return retval; - - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); - - /* set page size, protection granularity and max flash size depending on family */ - switch (device_id & 0xfff) { - case 0x410: - case 0x418: /* connectivity line density */ - page_size = 1024; - gd32vf103_info->ppage_size = 4; - max_flash_size_in_kb = 128; - break; - default: - LOG_WARNING("Cannot identify target as a gd32vf103 family."); - return ERROR_FAIL; - } - - /* get flash size from target. */ - retval = gd32vf103_get_flash_size(bank, &flash_size_in_kb); - LOG_INFO("flash_size_in_kb = 0x%08" PRIx32 "", flash_size_in_kb); - /* failed reading flash size or flash size invalid, default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { - LOG_WARNING("gd32vf103 flash size failed, probe inaccurate - assuming %dk flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; - } - - if (gd32vf103_info->has_dual_banks) { - /* split reported size into matching bank */ - if (bank->base != 0x08080000) { - /* bank 0 will be fixed 512k */ - flash_size_in_kb = 512; - } else { - flash_size_in_kb -= 512; - /* bank1 also uses a register offset */ - gd32vf103_info->register_base = FLASH_REG_BASE_B1; - base_address = 0x08080000; - } - } - - /* if the user sets the size manually then ignore the probed value - * this allows us to work around devices that have a invalid flash size register value */ - if (gd32vf103_info->user_bank_size) { - LOG_INFO("ignoring flash probed value, using configured bank size"); - flash_size_in_kb = gd32vf103_info->user_bank_size / 1024; - } - - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); - - /* did we assign flash size? */ - assert(flash_size_in_kb != 0xffff); - - /* calculate numbers of pages */ - int num_pages = flash_size_in_kb * 1024 / page_size; - - /* check that calculation result makes sense */ - assert(num_pages > 0); - - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - - bank->base = base_address; - bank->size = (num_pages * page_size); - bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - - for (i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * page_size; - bank->sectors[i].size = page_size; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 1; - } - - gd32vf103_info->probed = 1; - - return ERROR_OK; -} - -static int gd32vf103_auto_probe(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - if (gd32vf103_info->probed) - return ERROR_OK; - return gd32vf103_probe(bank); -} - -static int get_gd32vf103_info(struct flash_bank *bank, struct command_invocation *cmd) -{ - uint32_t dbgmcu_idcode; - - /* read gd32vf103 device id register */ - int retval = gd32vf103_get_device_id(bank, &dbgmcu_idcode); - if (retval != ERROR_OK) - return retval; - - uint16_t device_id = dbgmcu_idcode & 0xfff; - uint16_t rev_id = dbgmcu_idcode >> 16; - const char *device_str; - const char *rev_str = NULL; - - switch (device_id) { - - case 0x418: - device_str = "gd32vf103 (gdm32501)"; - - switch (rev_id) { - case 0x1000: - rev_str = "A"; - break; - - case 0x1001: - rev_str = "B"; - break; - } - break; - default: - command_print_sameline(cmd, "Cannot identify target as a GD32VF103 x\n"); - return ERROR_FAIL; - } - - if (rev_str != NULL) - command_print_sameline(cmd, "%s - Rev: %s\n", device_str, rev_str); - else - command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)\n", device_str, rev_id); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_lock_command) -{ - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to erase options"); - return ERROR_OK; - } - - /* set readout protection */ - gd32vf103_info->option_bytes.RDP = 0; - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to lock device"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 locked"); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_unlock_command) -{ - struct target *target = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to unlock device"); - return ERROR_OK; - } - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to lock device"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 unlocked.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect."); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_options_read_command) -{ - uint32_t optionbyte; - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - retval = target_read_u32(target, FMC_OBSTAT_B0, &optionbyte); - if (retval != ERROR_OK) - return retval; - command_print(CMD, "Option Byte: 0x%" PRIx32 "", optionbyte); - - int user_data = optionbyte; - - if (optionbyte >> FMC_OBSTAT_OBERR & 1) - command_print(CMD, "Option Byte Complement Error"); - - if (optionbyte >> FMC_OBSTAT_SPC & 1) - command_print(CMD, "Readout Protection On"); - else - command_print(CMD, "Readout Protection Off"); - - /* user option bytes are offset depending on variant */ - optionbyte >>= gd32vf103_info->option_offset; - - if (optionbyte >> FMC_OBSTAT_WDG_SW & 1) - command_print(CMD, "Software Watchdog"); - else - command_print(CMD, "Hardware Watchdog"); - - if (optionbyte >> FMC_OBSTAT_RST_DSLEEP & 1) - command_print(CMD, "Stop: No reset generated"); - else - command_print(CMD, "Stop: Reset generated"); - - if (optionbyte >> FMC_OBSTAT_RST_STDBY & 1) - command_print(CMD, "Standby: No reset generated"); - else - command_print(CMD, "Standby: Reset generated"); - - if (gd32vf103_info->has_dual_banks) { - if (optionbyte >> FMC_OBSTAT_BB & 1) - command_print(CMD, "Boot: Bank 0"); - else - command_print(CMD, "Boot: Bank 1"); - } - - command_print(CMD, "User Option0: 0x%02" PRIx8, - (uint8_t)((user_data >> gd32vf103_info->user_data_offset) & 0xff)); - command_print(CMD, "User Option1: 0x%02" PRIx8, - (uint8_t)((user_data >> (gd32vf103_info->user_data_offset + 8)) & 0xff)); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_options_write_command) -{ - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - uint16_t optionbyte; - - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - retval = gd32vf103_read_options(bank); - if (ERROR_OK != retval) - return retval; - - /* start with current options */ - optionbyte = gd32vf103_info->option_bytes.user_options; - - /* skip over flash bank */ - CMD_ARGC--; - CMD_ARGV++; - - while (CMD_ARGC) { - if (strcmp("SWWDG", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 0); - else if (strcmp("HWWDG", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 0); - else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 1); - else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 1); - else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 2); - else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 2); - else if (gd32vf103_info->has_dual_banks) { - if (strcmp("BOOT0", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 3); - else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 3); - else - return ERROR_COMMAND_SYNTAX_ERROR; - } else - return ERROR_COMMAND_SYNTAX_ERROR; - CMD_ARGC--; - CMD_ARGV++; - } - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to erase options"); - return ERROR_OK; - } - - gd32vf103_info->option_bytes.user_options = optionbyte; - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to write options"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 write options complete.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect."); - - return ERROR_OK; -} - -static int gd32vf103_mass_erase(struct flash_bank *bank) -{ - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* unlock option flash registers */ - int retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* mass erase flash memory */ - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_MER); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), - FMC_CTL_MER | FMC_CTL_START); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_mass_erase_command) -{ - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - retval = gd32vf103_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - - command_print(CMD, "gd32vf103 mass erase complete"); - } else - command_print(CMD, "gd32vf103 mass erase failed"); - - return retval; -} - -static const struct command_registration gd32vf103_exec_command_handlers[] = { - { - .name = "lock", - .handler = gd32vf103_handle_lock_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Lock entire flash device.", - }, - { - .name = "unlock", - .handler = gd32vf103_handle_unlock_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Unlock entire protected flash device.", - }, - { - .name = "mass_erase", - .handler = gd32vf103_handle_mass_erase_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Erase entire flash device.", - }, - { - .name = "options_read", - .handler = gd32vf103_handle_options_read_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Read and display device option byte.", - }, - { - .name = "options_write", - .handler = gd32vf103_handle_options_write_command, - .mode = COMMAND_EXEC, - .usage = "bank_id ('SWWDG'|'HWWDG') " - "('RSTSTNDBY'|'NORSTSTNDBY') " - "('RSTSTOP'|'NORSTSTOP')", - .help = "Replace bits in device option byte.", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration gd32vf103_command_handlers[] = { - { - .name = "gd32vf103", - .mode = COMMAND_ANY, - .help = "gd32vf103 flash command group", - .usage = "", - .chain = gd32vf103_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct flash_driver gd32vf103_flash = { - .name = "gd32vf103", - .commands = gd32vf103_command_handlers, - .flash_bank_command = gd32vf103_flash_bank_command, - .erase = gd32vf103_erase, - .protect = gd32vf103_protect, - .write = gd32vf103_write, - .read = default_flash_read, - .probe = gd32vf103_probe, - .auto_probe = gd32vf103_auto_probe, - .erase_check = default_flash_blank_check, - .protect_check = gd32vf103_protect_check, - .info = get_gd32vf103_info, - .free_driver_priv = default_flash_free_driver_priv, -}; From 3cac5d279eefc7a0300745dc48d7704527a93b6b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 4 May 2022 16:17:08 +0200 Subject: [PATCH 132/186] server/gdb: fix gdb remote monitor cmd on multi-target Commit 5ebb1bdea1df ("server/gdb: fix return of gdb remote monitor command") replaces the call to command_run_line() with call to Jim_EvalObj() but does not properly set the "context". In multi-target environment, his can cause the erroneously execution of the command on the wrong target. Copy from the code in command_run_line() the proper setup before executing Jim_EvalObj(). Change-Id: I56738c80779082ca146a06c01bc30e28bc835fd3 Signed-off-by: Antonio Borneo Reported-by: Bohdan Tymkiv Fixes: 5ebb1bdea1df ("server/gdb: fix return of gdb remote monitor command") --- src/server/gdb_server.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index da6552703..cdb26f245 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2756,6 +2756,7 @@ static int gdb_query_packet(struct connection *connection, if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { + Jim_Interp *interp = cmd_ctx->interp; char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); @@ -2768,20 +2769,31 @@ static int gdb_query_packet(struct connection *connection, /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; + struct target *saved_target_override = cmd_ctx->current_target_override; - cmd_ctx->current_target_override = target; + cmd_ctx->current_target_override = NULL; - int retval = Jim_EvalObj(cmd_ctx->interp, Jim_NewStringObj(cmd_ctx->interp, cmd, -1)); + struct command_context *old_context = Jim_GetAssocData(interp, "context"); + Jim_DeleteAssocData(interp, "context"); + int retval = Jim_SetAssocData(interp, "context", NULL, cmd_ctx); + if (retval == JIM_OK) { + retval = Jim_EvalObj(interp, Jim_NewStringObj(interp, cmd, -1)); + Jim_DeleteAssocData(interp, "context"); + } + int inner_retval = Jim_SetAssocData(interp, "context", NULL, old_context); + if (retval == JIM_OK) + retval = inner_retval; cmd_ctx->current_target_override = saved_target_override; + current_gdb_connection = NULL; target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); if (retval == JIM_RETURN) - retval = cmd_ctx->interp->returnCode; + retval = interp->returnCode; int lenmsg; - const char *cretmsg = Jim_GetString(Jim_GetResult(cmd_ctx->interp), &lenmsg); + const char *cretmsg = Jim_GetString(Jim_GetResult(interp), &lenmsg); char *retmsg; if (lenmsg && cretmsg[lenmsg - 1] != '\n') { retmsg = alloc_printf("%s\n", cretmsg); From a2c569f3be430ca4b75d4e02297f34801c3e2741 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 4 May 2022 10:11:39 -0700 Subject: [PATCH 133/186] Try to fix capstone build for win32. Change-Id: I77dd0679c24ca8cec2158ec4da71faa4a7740491 Signed-off-by: Tim Newsome --- .github/workflows/snapshot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index c53b1944b..d4749d6d3 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -55,6 +55,7 @@ jobs: LIBUSB1_CONFIG: --enable-shared --disable-static HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" + CAPSTONE_CFLAGS: -I$(CAPSTONE_SRC)/include/capstone run: | # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG OPENOCD_TAG="`git tag --points-at HEAD`" From a408bdc8db1acfbf37c399668cdf370838645d63 Mon Sep 17 00:00:00 2001 From: wzgpeter Date: Tue, 17 May 2022 00:57:22 +0800 Subject: [PATCH 134/186] fix: semihosting_fileio display the unsupported info (#699) the abnormal info display below: semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 semihosting: unsupported call 0 the PC did not plus 4 before resume, which cause this abnormal info popup. Change-Id: I15c1e7426f1925e78f607c566976f9352216506f Signed-off-by: Wu Zhigang Co-authored-by: Wu Zhigang --- 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 1dd8e7791..2c53813ee 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -155,16 +155,16 @@ semihosting_result_t 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 SEMI_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 SEMI_ERROR; - LOG_DEBUG(" -> HANDLED"); return SEMI_HANDLED; } From 6047fedc6315d39df5e729155085e70464d8b40c Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 16 May 2022 10:17:04 -0700 Subject: [PATCH 135/186] Change set_haltgroup() to more general set_group() (#697) * Change set_haltgroup() to more general set_group() Change-Id: Ib91a252ac63604e54b756f70c549ccd47241fd10 Signed-off-by: Tim Newsome * Properly use enum. Change-Id: I0edef6053fac388db38a22fe7557623fa93ec705 Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> * Style changes suggested in review. Change-Id: I29e83d3dbef09cb971ec0355aff733191a6e4679 Signed-off-by: Tim Newsome Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> --- src/target/riscv/riscv-013.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 63b40c687..7eb206f3d 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1503,15 +1503,22 @@ static void deinit_target(struct target *target) info->version_specific = NULL; } -static int set_haltgroup(struct target *target, bool *supported) +typedef enum { + HALTGROUP, + RESUMEGROUP +} grouptype_t; +static int set_group(struct target *target, bool *supported, unsigned group, grouptype_t grouptype) { - uint32_t write = set_field(DM_DMCS2_HGWRITE, DM_DMCS2_GROUP, target->smp); - if (dmi_write(target, DM_DMCS2, write) != ERROR_OK) + uint32_t write_val = DM_DMCS2_HGWRITE; + assert(group <= 31); + write_val = set_field(write_val, DM_DMCS2_GROUP, group); + write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 1 : 0); + if (dmi_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; - uint32_t read; - if (dmi_read(target, &read, DM_DMCS2) != ERROR_OK) + uint32_t read_val; + if (dmi_read(target, &read_val, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; - *supported = get_field(read, DM_DMCS2_GROUP) == (unsigned)target->smp; + *supported = get_field(read_val, DM_DMCS2_GROUP) == group; return ERROR_OK; } @@ -1754,7 +1761,7 @@ static int examine(struct target *target) if (target->smp) { bool haltgroup_supported; - if (set_haltgroup(target, &haltgroup_supported) != ERROR_OK) + if (set_group(target, &haltgroup_supported, target->smp, HALTGROUP) != ERROR_OK) return ERROR_FAIL; if (haltgroup_supported) LOG_INFO("Core %d made part of halt group %d.", target->coreid, From 0fada024948f55da74b0b6828a8c1cdf51e36762 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 May 2022 09:40:22 -0700 Subject: [PATCH 136/186] Correctly set target->smp. (#701) This was broken by #684. Thanks to Jan for noticing. Change-Id: I6ce115a6a333b93d7edb3ee44daae3f618d092e6 Signed-off-by: Tim Newsome --- src/target/target.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 6cbfc6e2e..7d3861ab5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -6471,7 +6471,6 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) foreach_smp_target(head, lh) { target = head->target; target->smp = smp_group; - target->smp = 1; target->smp_targets = lh; } smp_group++; From 5c34da1415719ac62108fec1bcec5f61e7d6059e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 25 May 2022 10:08:43 -0700 Subject: [PATCH 137/186] Use new debug_defines.h (#703) * Update debug_defines from the spec. Now it includes constants for field values, so use them instead of duplicating that here. Change-Id: I2fca6e89f25123c39d4bf483b8244e47aefb0f88 * Remove unused #defines Change-Id: Id20351851c9ed2c3aa82ccf8c04b604bef11692a * Use debug spec constants in a few more places Change-Id: Ic4578729c89e3c6a26a72772e1635c5345bd6a52 Signed-off-by: Tim Newsome * Use macros for trigger action types. Which were added with the very latest debug_defines.h. Change-Id: I47f73e11d2ec529c720f2e1df05f7b0d3026e43a Signed-off-by: Tim Newsome --- src/target/riscv/debug_defines.h | 2376 ++++++++++++++++++------------ src/target/riscv/riscv-013.c | 17 +- src/target/riscv/riscv.c | 116 +- 3 files changed, 1468 insertions(+), 1041 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 5c9eef4ea..1c7459261 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -1,6 +1,6 @@ /* * This file is auto-generated by running 'make debug_defines.h' in - * https://github.com/riscv/riscv-debug-spec/ (3dfe4f7) + * https://github.com/riscv/riscv-debug-spec/ (182b9c4) * License: Creative Commons Attribution 4.0 International Public License (CC BY 4.0) */ @@ -8,15 +8,15 @@ /* * Identifies the release version of this part. */ -#define DTM_IDCODE_VERSION_OFFSET 28 +#define DTM_IDCODE_VERSION_OFFSET 0x1c #define DTM_IDCODE_VERSION_LENGTH 4 -#define DTM_IDCODE_VERSION (0xfU << DTM_IDCODE_VERSION_OFFSET) +#define DTM_IDCODE_VERSION 0xf0000000U /* * Identifies the designer's part number of this part. */ -#define DTM_IDCODE_PARTNUMBER_OFFSET 12 -#define DTM_IDCODE_PARTNUMBER_LENGTH 16 -#define DTM_IDCODE_PARTNUMBER (0xffffU << DTM_IDCODE_PARTNUMBER_OFFSET) +#define DTM_IDCODE_PARTNUMBER_OFFSET 0xc +#define DTM_IDCODE_PARTNUMBER_LENGTH 0x10 +#define DTM_IDCODE_PARTNUMBER 0xffff000 /* * Identifies the designer/manufacturer of this part. Bits 6:0 must be * bits 6:0 of the designer/manufacturer's Identification Code as @@ -25,11 +25,11 @@ * Identification Code. */ #define DTM_IDCODE_MANUFID_OFFSET 1 -#define DTM_IDCODE_MANUFID_LENGTH 11 -#define DTM_IDCODE_MANUFID (0x7ffU << DTM_IDCODE_MANUFID_OFFSET) +#define DTM_IDCODE_MANUFID_LENGTH 0xb +#define DTM_IDCODE_MANUFID 0xffe #define DTM_IDCODE_1_OFFSET 0 #define DTM_IDCODE_1_LENGTH 1 -#define DTM_IDCODE_1 (0x1U << DTM_IDCODE_1_OFFSET) +#define DTM_IDCODE_1 1 #define DTM_DTMCS 0x10 /* * Writing 1 to this bit does a hard reset of the DTM, @@ -40,16 +40,16 @@ * complete (e.g. a reset condition caused an inflight DMI transaction to * be cancelled). */ -#define DTM_DTMCS_DMIHARDRESET_OFFSET 17 +#define DTM_DTMCS_DMIHARDRESET_OFFSET 0x11 #define DTM_DTMCS_DMIHARDRESET_LENGTH 1 -#define DTM_DTMCS_DMIHARDRESET (0x1U << DTM_DTMCS_DMIHARDRESET_OFFSET) +#define DTM_DTMCS_DMIHARDRESET 0x20000 /* * Writing 1 to this bit clears the sticky error state, but does * not affect outstanding DMI transactions. */ -#define DTM_DTMCS_DMIRESET_OFFSET 16 +#define DTM_DTMCS_DMIRESET_OFFSET 0x10 #define DTM_DTMCS_DMIRESET_LENGTH 1 -#define DTM_DTMCS_DMIRESET (0x1U << DTM_DTMCS_DMIRESET_OFFSET) +#define DTM_DTMCS_DMIRESET 0x10000 /* * This is a hint to the debugger of the minimum number of * cycles a debugger should spend in @@ -65,76 +65,89 @@ * * And so on. */ -#define DTM_DTMCS_IDLE_OFFSET 12 +#define DTM_DTMCS_IDLE_OFFSET 0xc #define DTM_DTMCS_IDLE_LENGTH 3 -#define DTM_DTMCS_IDLE (0x7U << DTM_DTMCS_IDLE_OFFSET) +#define DTM_DTMCS_IDLE 0x7000 /* - * 0: No error. - * - * 1: Reserved. Interpret the same as 2. - * - * 2: An operation failed (resulted in \FdtmDmiOp of 2). - * - * 3: An operation was attempted while a DMI access was still in - * progress (resulted in \FdtmDmiOp of 3). + * Read-only alias of \FdtmDmiOp. */ -#define DTM_DTMCS_DMISTAT_OFFSET 10 +#define DTM_DTMCS_DMISTAT_OFFSET 0xa #define DTM_DTMCS_DMISTAT_LENGTH 2 -#define DTM_DTMCS_DMISTAT (0x3U << DTM_DTMCS_DMISTAT_OFFSET) +#define DTM_DTMCS_DMISTAT 0xc00 /* * The size of \FdmSbaddressZeroAddress in \RdtmDmi. */ #define DTM_DTMCS_ABITS_OFFSET 4 #define DTM_DTMCS_ABITS_LENGTH 6 -#define DTM_DTMCS_ABITS (0x3fU << DTM_DTMCS_ABITS_OFFSET) -/* - * 0: Version described in spec version 0.11. - * - * 1: Version described in spec versions 0.13 and 1.0. - * - * 15: Version not described in any available version of this spec. - */ +#define DTM_DTMCS_ABITS 0x3f0 #define DTM_DTMCS_VERSION_OFFSET 0 #define DTM_DTMCS_VERSION_LENGTH 4 -#define DTM_DTMCS_VERSION (0xfU << DTM_DTMCS_VERSION_OFFSET) +#define DTM_DTMCS_VERSION 0xf +/* + * 0.11: Version described in spec version 0.11. + */ +#define DTM_DTMCS_VERSION_0_11 0 +/* + * 1.0: Version described in spec versions 0.13 and 1.0. + */ +#define DTM_DTMCS_VERSION_1_0 1 +/* + * custom: Version not described in any available version of this spec. + */ +#define DTM_DTMCS_VERSION_CUSTOM 15 #define DTM_DMI 0x11 /* * Address used for DMI access. In Update-DR this value is used * to access the DM over the DMI. */ -#define DTM_DMI_ADDRESS_OFFSET 34 -#define DTM_DMI_ADDRESS_LENGTH abits -#define DTM_DMI_ADDRESS (((1L << abits) - 1) << DTM_DMI_ADDRESS_OFFSET) +#define DTM_DMI_ADDRESS_OFFSET 0x22 +#define DTM_DMI_ADDRESS_LENGTH(abits) abits +#define DTM_DMI_ADDRESS(abits) ((0x400000000ULL * (1ULL<misa & (1 << ('S' - 'A'))) - tdata1 |= MCONTROL_S; + tdata1 |= CSR_MCONTROL_S; if (r->misa & (1 << ('U' - 'A'))) - tdata1 |= MCONTROL_U; + tdata1 |= CSR_MCONTROL_U; if (trigger->execute) - tdata1 |= MCONTROL_EXECUTE; + tdata1 |= CSR_MCONTROL_EXECUTE; if (trigger->read) - tdata1 |= MCONTROL_LOAD; + tdata1 |= CSR_MCONTROL_LOAD; if (trigger->write) - tdata1 |= MCONTROL_STORE; + tdata1 |= CSR_MCONTROL_STORE; riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); @@ -653,10 +577,10 @@ static int maybe_add_trigger_t6(struct target *target, } /* address/data match trigger */ - tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); + tdata1 |= CSR_MCONTROL6_DMODE(riscv_xlen(target)); tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, - MCONTROL_ACTION_DEBUG_MODE); - tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, MCONTROL_MATCH_EQUAL); + CSR_MCONTROL6_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL); tdata1 |= CSR_MCONTROL6_M; if (r->misa & (1 << ('H' - 'A'))) tdata1 |= CSR_MCONTROL6_VS | CSR_MCONTROL6_VU; @@ -715,7 +639,7 @@ static int add_trigger(struct target *target, struct trigger *trigger) int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; - int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); result = ERROR_OK; switch (type) { @@ -1046,7 +970,7 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) uint64_t tdata1; if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; - int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); uint64_t hit_mask = 0; switch (type) { @@ -1447,7 +1371,7 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) riscv_reg_t tdata1; if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; - if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) { + if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) { state[t] = tdata1; if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; @@ -4036,7 +3960,7 @@ int riscv_enumerate_triggers(struct target *target) if (result != ERROR_OK) return result; - int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); if (type == 0) break; switch (type) { @@ -4046,11 +3970,11 @@ int riscv_enumerate_triggers(struct target *target) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; case 2: - if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) + if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; case 6: - if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) + if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; } From 9906763b89c405a5ad9dd5a7aca45fdcca9061ee Mon Sep 17 00:00:00 2001 From: Huaqi Fang <578567190@qq.com> Date: Wed, 1 Jun 2022 23:55:12 +0800 Subject: [PATCH 138/186] flash: redirect gd32vf103 driver to stm32f1x (#704) * flash: redirect gd32vf103 driver to stm32f1x Signed-off-by: Huaqi Fang <578567190@qq.com> * flash: add warning message to use stm32f1x instead of gd32vf103 Signed-off-by: Huaqi Fang <578567190@qq.com> Reviewed-by: Tim Newsome Reviewed-by: Jan Matyas --- src/flash/nor/drivers.c | 2 ++ src/flash/nor/stm32f1x.c | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3e35c0954..387fc71f1 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -44,6 +44,7 @@ extern const struct flash_driver faux_flash; extern const struct flash_driver fm3_flash; extern const struct flash_driver fm4_flash; extern const struct flash_driver fespi_flash; +extern const struct flash_driver gd32vf103_flash; extern const struct flash_driver jtagspi_flash; extern const struct flash_driver kinetis_flash; extern const struct flash_driver kinetis_ke_flash; @@ -119,6 +120,7 @@ static const struct flash_driver * const flash_drivers[] = { &fm3_flash, &fm4_flash, &fespi_flash, + &gd32vf103_flash, &jtagspi_flash, &kinetis_flash, &kinetis_ke_flash, diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index c750ff080..b5b10af4c 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -1751,3 +1751,55 @@ const struct flash_driver stm32f1x_flash = { .info = get_stm32x_info, .free_driver_priv = default_flash_free_driver_priv, }; + +/* flash bank gd32vf103 0 0 + */ +FLASH_BANK_COMMAND_HANDLER(gd32vf103_flash_bank_command) +{ + struct stm32x_flash_bank *stm32x_info; + + LOG_WARNING("DEPRECATED: The gd32vf103 flash target will be removed in June of 2023, please use stm32f1x instead."); + /* The reset code are just copy from stm32x_flash_bank_command function */ + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); + + bank->driver_priv = stm32x_info; + stm32x_info->probed = false; + stm32x_info->has_dual_banks = false; + stm32x_info->can_load_options = false; + stm32x_info->register_base = FLASH_REG_BASE_B0; + stm32x_info->user_bank_size = bank->size; + + /* The flash write must be aligned to a halfword boundary */ + bank->write_start_alignment = bank->write_end_alignment = 2; + return ERROR_OK; +} + +static const struct command_registration gd32vf103_command_handlers[] = { + { + .name = "gd32vf103", + .mode = COMMAND_ANY, + .help = "gd32vf103 flash command group (identical to flash commands from stm32f1x)", + .usage = "", + .chain = stm32f1x_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver gd32vf103_flash = { + .name = "gd32vf103", + .commands = gd32vf103_command_handlers, + .flash_bank_command = gd32vf103_flash_bank_command, + .erase = stm32x_erase, + .protect = stm32x_protect, + .write = stm32x_write, + .read = default_flash_read, + .probe = stm32x_probe, + .auto_probe = stm32x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = stm32x_protect_check, + .info = get_stm32x_info, + .free_driver_priv = default_flash_free_driver_priv, +}; From 40458f6b251c943b76792d6a2bf8c7633636a935 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas <43336369+erhankur@users.noreply.github.com> Date: Mon, 6 Jun 2022 17:39:05 +0200 Subject: [PATCH 139/186] tcl: add Espressif riscv targets (ESP32-C2 & ESP32-C3) (#706) Change-Id: I48fead33f5fd5890a7724cd5f500f2d14e2a5ffa Signed-off-by: Erhan Kurubas --- doc/openocd.texi | 2 + tcl/board/esp32c2-ftdi.cfg | 21 +++++++ tcl/board/esp32c3-ftdi.cfg | 21 +++++++ tcl/target/esp32c2.cfg | 111 ++++++++++++++++++++++++++++++++++++ tcl/target/esp32c3.cfg | 113 +++++++++++++++++++++++++++++++++++++ tcl/target/esp_common.cfg | 16 ++++++ 6 files changed, 284 insertions(+) create mode 100644 tcl/board/esp32c2-ftdi.cfg create mode 100644 tcl/board/esp32c3-ftdi.cfg create mode 100644 tcl/target/esp32c2.cfg create mode 100644 tcl/target/esp32c3.cfg create mode 100644 tcl/target/esp_common.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index ac7ad886c..850b91474 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4714,6 +4714,8 @@ compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores @item @code{dsp5680xx} -- implements Freescale's 5680x DSP. @item @code{esirisc} -- this is an EnSilica eSi-RISC core. The current implementation supports eSi-32xx cores. +@item @code{esp32c2} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core. @item @code{fa526} -- resembles arm920 (w/o Thumb). @item @code{feroceon} -- resembles arm926. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. diff --git a/tcl/board/esp32c2-ftdi.cfg b/tcl/board/esp32c2-ftdi.cfg new file mode 100644 index 000000000..bc2b82f5a --- /dev/null +++ b/tcl/board/esp32c2-ftdi.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-C2 connected via ESP-Prog. +# +# For example, OpenOCD can be started for ESP32-C2 debugging on +# +# openocd -f board/esp32c2-ftdi.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +# Source the ESP32-C2 configuration file +source [find target/esp32c2.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/esp32c3-ftdi.cfg b/tcl/board/esp32c3-ftdi.cfg new file mode 100644 index 000000000..55953742c --- /dev/null +++ b/tcl/board/esp32c3-ftdi.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-C3 connected via ESP-Prog. +# +# For example, OpenOCD can be started for ESP32-C3 debugging on +# +# openocd -f board/esp32c3-ftdi.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +# Source the ESP32-C3 configuration file +source [find target/esp32c3.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/target/esp32c2.cfg b/tcl/target/esp32c2.cfg new file mode 100644 index 000000000..2af6dd292 --- /dev/null +++ b/tcl/target/esp32c2.cfg @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# The ESP32-C2 only supports JTAG. +transport select jtag + +# Source the ESP common configuration file +source [find target/esp_common.cfg] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME esp32c2 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0000cc25 +} + +set _TARGETNAME $_CHIPNAME +set _CPUNAME cpu +set _TAPNAME $_CHIPNAME.$_CPUNAME + +jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID + +proc esp32c2_wdt_disable { } { + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Timer Group 0 WDT + mww 0x6001f064 0x50D83AA1 + mww 0x6001F048 0 + # RTC WDT + mww 0x6000809C 0x50D83AA1 + mww 0x60008084 0 + # SWD + mww 0x600080A4 0x8F1D312A + mww 0x600080A0 0x84B00000 +} + +# This is almost identical with the esp32c3_soc_reset. +# Will be refactored with the other common settings. +proc esp32c2_soc_reset { } { + # This procedure does "digital system reset", i.e. resets + # all the peripherals except for the RTC block. + # It is called from reset-assert-post target event callback, + # after assert_reset procedure was called. + # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, + # temporarily take it out of reset. Save the dmcontrol state before + # doing so. + riscv dmi_write 0x10 0x80000001 + # Trigger the reset + mww 0x60008000 0x9c00a000 + # Workaround for stuck in cpu start during calibration. + # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration + mww 0x6001F068 0 + # Wait for the reset to happen + sleep 10 + poll + # Disable the watchdogs again + esp32c2_wdt_disable + + # Here debugger reads allresumeack and allhalted bits as set (0x330a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write 0x10 0x40000001 + + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write 0x10 0x80000003 +} + +if { $_RTOS == "none" } { + target create $_TARGETNAME riscv -chain-position $_TAPNAME +} else { + target create $_TARGETNAME riscv -chain-position $_TAPNAME -rtos $_RTOS +} + +$_TARGETNAME configure -event reset-assert-post { esp32c2_soc_reset } +$_TARGETNAME configure -event halted { + esp32c2_wdt_disable +} +$_TARGETNAME configure -event examine-end { + # Need this to handle 'apptrace init' syscall correctly because semihosting is not enabled by default + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + # TODO: cherry-pick from upstream + # https://review.openocd.org/c/openocd/+/6888 + # https://review.openocd.org/c/openocd/+/7005 + # arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } +} +$_TARGETNAME configure -event gdb-attach { + halt 1000 + # by default mask interrupts while stepping + riscv set_maskisr steponly +} + +gdb_breakpoint_override hard + +riscv set_reset_timeout_sec 2 +riscv set_command_timeout_sec 5 +riscv set_mem_access sysbus progbuf abstract +riscv set_ebreakm on +riscv set_ebreaks on +riscv set_ebreaku on diff --git a/tcl/target/esp32c3.cfg b/tcl/target/esp32c3.cfg new file mode 100644 index 000000000..ecb9bdf53 --- /dev/null +++ b/tcl/target/esp32c3.cfg @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# The ESP32-C3 only supports JTAG. +transport select jtag + +# Source the ESP common configuration file +source [find target/esp_common.cfg] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME esp32c3 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x00005c25 +} + +set _TARGETNAME $_CHIPNAME +set _CPUNAME cpu +set _TAPNAME $_CHIPNAME.$_CPUNAME + +jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID + +proc esp32c3_wdt_disable { } { + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Timer Group 0 & 1 WDTs + mww 0x6001f064 0x50D83AA1 + mww 0x6001F048 0 + mww 0x60020064 0x50D83AA1 + mww 0x60020048 0 + # RTC WDT + mww 0x600080a8 0x50D83AA1 + mww 0x60008090 0 + # SWD + mww 0x600080b0 0x8F1D312A + mww 0x600080ac 0x84B00000 +} + +# This is almost identical with the esp32c2_soc_reset. +# Will be refactored with the other common settings. +proc esp32c3_soc_reset { } { + # This procedure does "digital system reset", i.e. resets + # all the peripherals except for the RTC block. + # It is called from reset-assert-post target event callback, + # after assert_reset procedure was called. + # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, + # temporarily take it out of reset. Save the dmcontrol state before + # doing so. + riscv dmi_write 0x10 0x80000001 + # Trigger the reset + mww 0x60008000 0x9c00a000 + # Workaround for stuck in cpu start during calibration. + # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration + mww 0x6001F068 0 + # Wait for the reset to happen + sleep 10 + poll + # Disable the watchdogs again + esp32c3_wdt_disable + + # Here debugger reads allresumeack and allhalted bits as set (0x330a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write 0x10 0x40000001 + + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write 0x10 0x80000003 +} + +if { $_RTOS == "none" } { + target create $_TARGETNAME riscv -chain-position $_TAPNAME +} else { + target create $_TARGETNAME riscv -chain-position $_TAPNAME -rtos $_RTOS +} + +$_TARGETNAME configure -event reset-assert-post { esp32c3_soc_reset } +$_TARGETNAME configure -event halted { + esp32c3_wdt_disable +} +$_TARGETNAME configure -event examine-end { + # Need this to handle 'apptrace init' syscall correctly because semihosting is not enabled by default + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + # TODO: cherry-pick from upstream + # https://review.openocd.org/c/openocd/+/6888 + # https://review.openocd.org/c/openocd/+/7005 + # arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } +} +$_TARGETNAME configure -event gdb-attach { + halt 1000 + # by default mask interrupts while stepping + riscv set_maskisr steponly +} + +gdb_breakpoint_override hard + +riscv set_reset_timeout_sec 2 +riscv set_command_timeout_sec 5 +riscv set_mem_access sysbus progbuf abstract +riscv set_ebreakm on +riscv set_ebreaks on +riscv set_ebreaku on diff --git a/tcl/target/esp_common.cfg b/tcl/target/esp_common.cfg new file mode 100644 index 000000000..c02bcb2b7 --- /dev/null +++ b/tcl/target/esp_common.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Common ESP chips definitions + +if { [info exists ESP_RTOS] } { + set _RTOS "$ESP_RTOS" +} else { + set _RTOS "FreeRTOS" +} + +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 "." +} From a2da8221872ae6d69369a8a03553450c942b559b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 8 Jun 2022 13:11:21 -0700 Subject: [PATCH 140/186] Document `ftdi oscan1_mode` (#705) Change-Id: I29b001bc6b9f29f1976aac3f02e15e4490707a4b Signed-off-by: Tim Newsome --- doc/openocd.texi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 850b91474..73f53c212 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2582,6 +2582,13 @@ minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. @end deffn +@deffn {Command} {ftdi oscan1_mode} on|off +Enable or disable OSCAN1 mode. This mode is intended for use with an adapter, +such as the ARM-JTAG-SWD by Olimex, that sits in between the FTDI chip and the +target. The adapter uses the normal JTAG signals to control TCKC and TMSC +(bidirectional) signals used in 2-wire cJTAG. +@end deffn + @deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] Creates a signal with the specified @var{name}, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO From d85a4e8098ba5fba5eb982dd53b4b46fa4f1ebce Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 15 Jun 2022 10:22:19 -0700 Subject: [PATCH 141/186] Remove unused code. (#707) Change-Id: I3961a62c0c51200ff3241265d9ea3e69492bdc4e Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 151ea159d..6e1da941a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2201,7 +2201,6 @@ int riscv_openocd_poll(struct target *target) enum target_state old_state = target->state; if (target->smp) { - unsigned halts_discovered = 0; unsigned should_remain_halted = 0; unsigned should_resume = 0; struct target_list *list; @@ -2219,7 +2218,6 @@ int riscv_openocd_poll(struct target *target) t->debug_reason = DBG_REASON_NOTHALTED; break; case RPH_DISCOVERED_HALTED: - halts_discovered++; t->state = TARGET_HALTED; enum riscv_halt_reason halt_reason = riscv_halt_reason(t, r->current_hartid); From 6d359afde45dba69d2fc2d6fc3f90e32050f8fbf Mon Sep 17 00:00:00 2001 From: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Date: Thu, 16 Jun 2022 18:58:45 +0200 Subject: [PATCH 142/186] Fix: Prevent segfault in riscv_invalidate_register_cache for non-examined targets. (#692) The segfault could be triggered if: - At least one target failed to get examined (therefore does not have the register cache set up yet), - and "reset" TCL command was issued, which internally tries to invalidate the register cache. Minor cleanup: "registers_initialized" member removed from riscv_info_t because it is not used anywhere. Change-Id: I6288c0d4343ef6a330fb2a6b49d388e7eafa32a2 Signed-off-by: Jan Matyas --- src/target/riscv/riscv.c | 8 ++++---- src/target/riscv/riscv.h | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6e1da941a..9f126b9cd 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -3519,7 +3519,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r) { memset(r, 0, sizeof(*r)); r->dtm_version = 1; - r->registers_initialized = false; r->current_hartid = target->coreid; r->version_specific = NULL; @@ -3664,7 +3663,10 @@ int riscv_set_current_hartid(struct target *target, int hartid) void riscv_invalidate_register_cache(struct target *target) { - RISCV_INFO(r); + /* Do not invalidate the register cache if it is not yet set up + * (e.g. when the target failed to get examined). */ + if (!target->reg_cache) + return; LOG_DEBUG("[%d]", target->coreid); register_cache_invalidate(target->reg_cache); @@ -3672,8 +3674,6 @@ void riscv_invalidate_register_cache(struct target *target) struct reg *reg = &target->reg_cache->reg_list[i]; reg->valid = false; } - - r->registers_initialized = true; } int riscv_current_hartid(const struct target *target) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 59fdb38a9..898d8b5c0 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -131,9 +131,6 @@ typedef struct { /* The number of entries in the debug buffer. */ int debug_buffer_size; - /* This avoids invalidating the register cache too often. */ - bool registers_initialized; - /* This hart contains an implicit ebreak at the end of the program buffer. */ bool impebreak; From 8488e4e863f6a465189d7dd3e6d94ccc4c493eb4 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 23 Jun 2022 08:06:14 -0700 Subject: [PATCH 143/186] Convert filter_openocd_log.py to use python3. (#709) Change-Id: Ie7b42bcc3462b737cbff369ac8d3a71322699aaa Signed-off-by: Tim Newsome --- tools/filter_openocd_log.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/filter_openocd_log.py b/tools/filter_openocd_log.py index cd38efdb4..076be20db 100755 --- a/tools/filter_openocd_log.py +++ b/tools/filter_openocd_log.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import re @@ -38,7 +38,7 @@ def shorten_buffer(outfd, buf, current_repetition): # Look for repeated sequences... repetitions = [] - for length in range(1, len(buf)/2): + for length in range(1, int(len(buf)/2)): # Is there a repeating sequence of `length` lines? matched_lines = 0 for i, entry in enumerate(buf[length:]): @@ -52,7 +52,7 @@ def shorten_buffer(outfd, buf, current_repetition): if repetitions: repetitions.sort(key=lambda entry: (entry[0] * (entry[1] / entry[0]), -entry[1])) matched_lines, length = repetitions[-1] - repeated = matched_lines / length + repeated = int(matched_lines / length) if repeated * length >= 3: sequence = buf[:length] del buf[:repeated * length] @@ -74,9 +74,9 @@ def shorten_buffer(outfd, buf, current_repetition): buf.pop(0) if length_before <= len(buf): - print "Buffer:" + print("Buffer:") for entry in buf: - print "%r" % entry[0] + print("%r" % entry[0]) assert False return None From aaf0620479bf8958040ab6483a579244584c9904 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 8 Jul 2022 13:02:13 -0700 Subject: [PATCH 144/186] Update with latest encoding from riscv-opcodes (#710) This gets us the new license header, which was requested upstream. Change-Id: I992b4f3bb230edb9f281e2278dd41c712098ed4c Signed-off-by: Tim Newsome --- src/target/riscv/encoding.h | 7919 ++++++++++++++++++----------------- 1 file changed, 4059 insertions(+), 3860 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index 4445f0bd2..f7ad4622a 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,9 +1,9 @@ -/* - * This file is auto-generated by running 'make ../riscv-openocd/src/target/riscv/encoding.h' in - * https://github.com/riscv/riscv-opcodes (6c34f60) - */ -/* See LICENSE for license details. */ +/* +* This file is auto-generated by running 'make' in +* https://github.com/riscv/riscv-opcodes (d2bbcb8) +*/ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ #ifndef RISCV_CSR_ENCODING_H #define RISCV_CSR_ENCODING_H @@ -149,6 +149,37 @@ #define SIP_SSIP MIP_SSIP #define SIP_STIP MIP_STIP +#define MENVCFG_FIOM 0x00000001 +#define MENVCFG_CBIE 0x00000030 +#define MENVCFG_CBCFE 0x00000040 +#define MENVCFG_CBZE 0x00000080 +#define MENVCFG_PBMTE 0x4000000000000000 +#define MENVCFG_STCE 0x8000000000000000 + +#define MENVCFGH_PBMTE 0x40000000 +#define MENVCFGH_STCE 0x80000000 + +#define HENVCFG_FIOM 0x00000001 +#define HENVCFG_CBIE 0x00000030 +#define HENVCFG_CBCFE 0x00000040 +#define HENVCFG_CBZE 0x00000080 +#define HENVCFG_PBMTE 0x4000000000000000 +#define HENVCFG_STCE 0x8000000000000000 + +#define HENVCFGH_PBMTE 0x40000000 +#define HENVCFGH_STCE 0x80000000 + +#define SENVCFG_FIOM 0x00000001 +#define SENVCFG_CBIE 0x00000030 +#define SENVCFG_CBCFE 0x00000040 +#define SENVCFG_CBZE 0x00000080 + +#define MSECCFG_MML 0x00000001 +#define MSECCFG_MMWP 0x00000002 +#define MSECCFG_RLB 0x00000004 +#define MSECCFG_USEED 0x00000100 +#define MSECCFG_SSEED 0x00000200 + #define PRV_U 0 #define PRV_S 1 #define PRV_M 3 @@ -181,6 +212,7 @@ #define HGATP_MODE_SV32X4 1 #define HGATP_MODE_SV39X4 8 #define HGATP_MODE_SV48X4 9 +#define HGATP_MODE_SV57X4 10 #define PMP_R 0x01 #define PMP_W 0x02 @@ -278,3797 +310,3306 @@ #endif #endif -/* Automatically generated by parse_opcodes. */ + +/* Automatically generated by parse_opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H -#define MATCH_SLLI_RV32 0x1013 -#define MASK_SLLI_RV32 0xfe00707f -#define MATCH_SRLI_RV32 0x5013 -#define MASK_SRLI_RV32 0xfe00707f -#define MATCH_SRAI_RV32 0x40005013 -#define MASK_SRAI_RV32 0xfe00707f -#define MATCH_FRFLAGS 0x102073 -#define MASK_FRFLAGS 0xfffff07f -#define MATCH_FSFLAGS 0x101073 -#define MASK_FSFLAGS 0xfff0707f -#define MATCH_FSFLAGSI 0x105073 -#define MASK_FSFLAGSI 0xfff0707f -#define MATCH_FRRM 0x202073 -#define MASK_FRRM 0xfffff07f -#define MATCH_FSRM 0x201073 -#define MASK_FSRM 0xfff0707f -#define MATCH_FSRMI 0x205073 -#define MASK_FSRMI 0xfff0707f -#define MATCH_FSCSR 0x301073 -#define MASK_FSCSR 0xfff0707f -#define MATCH_FRCSR 0x302073 -#define MASK_FRCSR 0xfffff07f -#define MATCH_RDCYCLE 0xc0002073 -#define MASK_RDCYCLE 0xfffff07f -#define MATCH_RDTIME 0xc0102073 -#define MASK_RDTIME 0xfffff07f -#define MATCH_RDINSTRET 0xc0202073 -#define MASK_RDINSTRET 0xfffff07f -#define MATCH_RDCYCLEH 0xc8002073 -#define MASK_RDCYCLEH 0xfffff07f -#define MATCH_RDTIMEH 0xc8102073 -#define MASK_RDTIMEH 0xfffff07f -#define MATCH_RDINSTRETH 0xc8202073 -#define MASK_RDINSTRETH 0xfffff07f -#define MATCH_SCALL 0x73 -#define MASK_SCALL 0xffffffff -#define MATCH_SBREAK 0x100073 -#define MASK_SBREAK 0xffffffff -#define MATCH_FMV_X_S 0xe0000053 -#define MASK_FMV_X_S 0xfff0707f -#define MATCH_FMV_S_X 0xf0000053 -#define MASK_FMV_S_X 0xfff0707f -#define MATCH_FENCE_TSO 0x8330000f -#define MASK_FENCE_TSO 0xfff0707f -#define MATCH_PAUSE 0x100000f -#define MASK_PAUSE 0xffffffff -#define MATCH_BEQ 0x63 -#define MASK_BEQ 0x707f -#define MATCH_BNE 0x1063 -#define MASK_BNE 0x707f -#define MATCH_BLT 0x4063 -#define MASK_BLT 0x707f -#define MATCH_BGE 0x5063 -#define MASK_BGE 0x707f -#define MATCH_BLTU 0x6063 -#define MASK_BLTU 0x707f -#define MATCH_BGEU 0x7063 -#define MASK_BGEU 0x707f -#define MATCH_JALR 0x67 -#define MASK_JALR 0x707f -#define MATCH_JAL 0x6f -#define MASK_JAL 0x7f -#define MATCH_LUI 0x37 -#define MASK_LUI 0x7f -#define MATCH_AUIPC 0x17 -#define MASK_AUIPC 0x7f -#define MATCH_ADDI 0x13 -#define MASK_ADDI 0x707f -#define MATCH_SLTI 0x2013 -#define MASK_SLTI 0x707f -#define MATCH_SLTIU 0x3013 -#define MASK_SLTIU 0x707f -#define MATCH_XORI 0x4013 -#define MASK_XORI 0x707f -#define MATCH_ORI 0x6013 -#define MASK_ORI 0x707f -#define MATCH_ANDI 0x7013 -#define MASK_ANDI 0x707f #define MATCH_ADD 0x33 -#define MASK_ADD 0xfe00707f -#define MATCH_SUB 0x40000033 -#define MASK_SUB 0xfe00707f -#define MATCH_SLL 0x1033 -#define MASK_SLL 0xfe00707f -#define MATCH_SLT 0x2033 -#define MASK_SLT 0xfe00707f -#define MATCH_SLTU 0x3033 -#define MASK_SLTU 0xfe00707f -#define MATCH_XOR 0x4033 -#define MASK_XOR 0xfe00707f -#define MATCH_SRL 0x5033 -#define MASK_SRL 0xfe00707f -#define MATCH_SRA 0x40005033 -#define MASK_SRA 0xfe00707f -#define MATCH_OR 0x6033 -#define MASK_OR 0xfe00707f -#define MATCH_AND 0x7033 -#define MASK_AND 0xfe00707f -#define MATCH_LB 0x3 -#define MASK_LB 0x707f -#define MATCH_LH 0x1003 -#define MASK_LH 0x707f -#define MATCH_LW 0x2003 -#define MASK_LW 0x707f -#define MATCH_LBU 0x4003 -#define MASK_LBU 0x707f -#define MATCH_LHU 0x5003 -#define MASK_LHU 0x707f -#define MATCH_SB 0x23 -#define MASK_SB 0x707f -#define MATCH_SH 0x1023 -#define MASK_SH 0x707f -#define MATCH_SW 0x2023 -#define MASK_SW 0x707f -#define MATCH_FENCE 0xf -#define MASK_FENCE 0x707f -#define MATCH_FENCE_I 0x100f -#define MASK_FENCE_I 0x707f +#define MASK_ADD 0xfe00707f +#define MATCH_ADD16 0x40000077 +#define MASK_ADD16 0xfe00707f +#define MATCH_ADD32 0x40002077 +#define MASK_ADD32 0xfe00707f +#define MATCH_ADD64 0xc0001077 +#define MASK_ADD64 0xfe00707f +#define MATCH_ADD8 0x48000077 +#define MASK_ADD8 0xfe00707f +#define MATCH_ADD_UW 0x800003b +#define MASK_ADD_UW 0xfe00707f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f #define MATCH_ADDIW 0x1b -#define MASK_ADDIW 0x707f -#define MATCH_SLLIW 0x101b -#define MASK_SLLIW 0xfe00707f -#define MATCH_SRLIW 0x501b -#define MASK_SRLIW 0xfe00707f -#define MATCH_SRAIW 0x4000501b -#define MASK_SRAIW 0xfe00707f +#define MASK_ADDIW 0x707f #define MATCH_ADDW 0x3b -#define MASK_ADDW 0xfe00707f -#define MATCH_SUBW 0x4000003b -#define MASK_SUBW 0xfe00707f -#define MATCH_SLLW 0x103b -#define MASK_SLLW 0xfe00707f -#define MATCH_SRLW 0x503b -#define MASK_SRLW 0xfe00707f -#define MATCH_SRAW 0x4000503b -#define MASK_SRAW 0xfe00707f -#define MATCH_LD 0x3003 -#define MASK_LD 0x707f -#define MATCH_LWU 0x6003 -#define MASK_LWU 0x707f -#define MATCH_SD 0x3023 -#define MASK_SD 0x707f -#define MATCH_SLLI 0x1013 -#define MASK_SLLI 0xfc00707f -#define MATCH_SRLI 0x5013 -#define MASK_SRLI 0xfc00707f -#define MATCH_SRAI 0x40005013 -#define MASK_SRAI 0xfc00707f -#define MATCH_MUL 0x2000033 -#define MASK_MUL 0xfe00707f -#define MATCH_MULH 0x2001033 -#define MASK_MULH 0xfe00707f -#define MATCH_MULHSU 0x2002033 -#define MASK_MULHSU 0xfe00707f -#define MATCH_MULHU 0x2003033 -#define MASK_MULHU 0xfe00707f -#define MATCH_DIV 0x2004033 -#define MASK_DIV 0xfe00707f -#define MATCH_DIVU 0x2005033 -#define MASK_DIVU 0xfe00707f -#define MATCH_REM 0x2006033 -#define MASK_REM 0xfe00707f -#define MATCH_REMU 0x2007033 -#define MASK_REMU 0xfe00707f -#define MATCH_MULW 0x200003b -#define MASK_MULW 0xfe00707f -#define MATCH_DIVW 0x200403b -#define MASK_DIVW 0xfe00707f -#define MATCH_DIVUW 0x200503b -#define MASK_DIVUW 0xfe00707f -#define MATCH_REMW 0x200603b -#define MASK_REMW 0xfe00707f -#define MATCH_REMUW 0x200703b -#define MASK_REMUW 0xfe00707f +#define MASK_ADDW 0xfe00707f +#define MATCH_AES32DSI 0x2a000033 +#define MASK_AES32DSI 0x3e00707f +#define MATCH_AES32DSMI 0x2e000033 +#define MASK_AES32DSMI 0x3e00707f +#define MATCH_AES32ESI 0x22000033 +#define MASK_AES32ESI 0x3e00707f +#define MATCH_AES32ESMI 0x26000033 +#define MASK_AES32ESMI 0x3e00707f +#define MATCH_AES64DS 0x3a000033 +#define MASK_AES64DS 0xfe00707f +#define MATCH_AES64DSM 0x3e000033 +#define MASK_AES64DSM 0xfe00707f +#define MATCH_AES64ES 0x32000033 +#define MASK_AES64ES 0xfe00707f +#define MATCH_AES64ESM 0x36000033 +#define MASK_AES64ESM 0xfe00707f +#define MATCH_AES64IM 0x30001013 +#define MASK_AES64IM 0xfff0707f +#define MATCH_AES64KS1I 0x31001013 +#define MASK_AES64KS1I 0xff00707f +#define MATCH_AES64KS2 0x7e000033 +#define MASK_AES64KS2 0xfe00707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f #define MATCH_AMOADD_W 0x202f -#define MASK_AMOADD_W 0xf800707f -#define MATCH_AMOXOR_W 0x2000202f -#define MASK_AMOXOR_W 0xf800707f -#define MATCH_AMOOR_W 0x4000202f -#define MASK_AMOOR_W 0xf800707f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f #define MATCH_AMOAND_W 0x6000202f -#define MASK_AMOAND_W 0xf800707f -#define MATCH_AMOMIN_W 0x8000202f -#define MASK_AMOMIN_W 0xf800707f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f #define MATCH_AMOMAX_W 0xa000202f -#define MASK_AMOMAX_W 0xf800707f -#define MATCH_AMOMINU_W 0xc000202f -#define MASK_AMOMINU_W 0xf800707f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f #define MATCH_AMOMAXU_W 0xe000202f -#define MASK_AMOMAXU_W 0xf800707f -#define MATCH_AMOSWAP_W 0x800202f -#define MASK_AMOSWAP_W 0xf800707f -#define MATCH_LR_W 0x1000202f -#define MASK_LR_W 0xf9f0707f -#define MATCH_SC_W 0x1800202f -#define MASK_SC_W 0xf800707f -#define MATCH_AMOADD_D 0x302f -#define MASK_AMOADD_D 0xf800707f -#define MATCH_AMOXOR_D 0x2000302f -#define MASK_AMOXOR_D 0xf800707f -#define MATCH_AMOOR_D 0x4000302f -#define MASK_AMOOR_D 0xf800707f -#define MATCH_AMOAND_D 0x6000302f -#define MASK_AMOAND_D 0xf800707f +#define MASK_AMOMAXU_W 0xf800707f #define MATCH_AMOMIN_D 0x8000302f -#define MASK_AMOMIN_D 0xf800707f -#define MATCH_AMOMAX_D 0xa000302f -#define MASK_AMOMAX_D 0xf800707f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f #define MATCH_AMOMINU_D 0xc000302f -#define MASK_AMOMINU_D 0xf800707f -#define MATCH_AMOMAXU_D 0xe000302f -#define MASK_AMOMAXU_D 0xf800707f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f #define MATCH_AMOSWAP_D 0x800302f -#define MASK_AMOSWAP_D 0xf800707f -#define MATCH_LR_D 0x1000302f -#define MASK_LR_D 0xf9f0707f -#define MATCH_SC_D 0x1800302f -#define MASK_SC_D 0xf800707f -#define MATCH_HFENCE_VVMA 0x22000073 -#define MASK_HFENCE_VVMA 0xfe007fff -#define MATCH_HFENCE_GVMA 0x62000073 -#define MASK_HFENCE_GVMA 0xfe007fff -#define MATCH_HLV_B 0x60004073 -#define MASK_HLV_B 0xfff0707f -#define MATCH_HLV_BU 0x60104073 -#define MASK_HLV_BU 0xfff0707f -#define MATCH_HLV_H 0x64004073 -#define MASK_HLV_H 0xfff0707f -#define MATCH_HLV_HU 0x64104073 -#define MASK_HLV_HU 0xfff0707f -#define MATCH_HLVX_HU 0x64304073 -#define MASK_HLVX_HU 0xfff0707f -#define MATCH_HLV_W 0x68004073 -#define MASK_HLV_W 0xfff0707f -#define MATCH_HLVX_WU 0x68304073 -#define MASK_HLVX_WU 0xfff0707f -#define MATCH_HSV_B 0x62004073 -#define MASK_HSV_B 0xfe007fff -#define MATCH_HSV_H 0x66004073 -#define MASK_HSV_H 0xfe007fff -#define MATCH_HSV_W 0x6a004073 -#define MASK_HSV_W 0xfe007fff -#define MATCH_HLV_WU 0x68104073 -#define MASK_HLV_WU 0xfff0707f -#define MATCH_HLV_D 0x6c004073 -#define MASK_HLV_D 0xfff0707f -#define MATCH_HSV_D 0x6e004073 -#define MASK_HSV_D 0xfe007fff -#define MATCH_FADD_S 0x53 -#define MASK_FADD_S 0xfe00007f -#define MATCH_FSUB_S 0x8000053 -#define MASK_FSUB_S 0xfe00007f -#define MATCH_FMUL_S 0x10000053 -#define MASK_FMUL_S 0xfe00007f -#define MATCH_FDIV_S 0x18000053 -#define MASK_FDIV_S 0xfe00007f -#define MATCH_FSGNJ_S 0x20000053 -#define MASK_FSGNJ_S 0xfe00707f -#define MATCH_FSGNJN_S 0x20001053 -#define MASK_FSGNJN_S 0xfe00707f -#define MATCH_FSGNJX_S 0x20002053 -#define MASK_FSGNJX_S 0xfe00707f -#define MATCH_FMIN_S 0x28000053 -#define MASK_FMIN_S 0xfe00707f -#define MATCH_FMAX_S 0x28001053 -#define MASK_FMAX_S 0xfe00707f -#define MATCH_FSQRT_S 0x58000053 -#define MASK_FSQRT_S 0xfff0007f -#define MATCH_FLE_S 0xa0000053 -#define MASK_FLE_S 0xfe00707f -#define MATCH_FLT_S 0xa0001053 -#define MASK_FLT_S 0xfe00707f -#define MATCH_FEQ_S 0xa0002053 -#define MASK_FEQ_S 0xfe00707f -#define MATCH_FCVT_W_S 0xc0000053 -#define MASK_FCVT_W_S 0xfff0007f -#define MATCH_FCVT_WU_S 0xc0100053 -#define MASK_FCVT_WU_S 0xfff0007f -#define MATCH_FMV_X_W 0xe0000053 -#define MASK_FMV_X_W 0xfff0707f -#define MATCH_FCLASS_S 0xe0001053 -#define MASK_FCLASS_S 0xfff0707f -#define MATCH_FCVT_S_W 0xd0000053 -#define MASK_FCVT_S_W 0xfff0007f -#define MATCH_FCVT_S_WU 0xd0100053 -#define MASK_FCVT_S_WU 0xfff0007f -#define MATCH_FMV_W_X 0xf0000053 -#define MASK_FMV_W_X 0xfff0707f -#define MATCH_FLW 0x2007 -#define MASK_FLW 0x707f -#define MATCH_FSW 0x2027 -#define MASK_FSW 0x707f -#define MATCH_FMADD_S 0x43 -#define MASK_FMADD_S 0x600007f -#define MATCH_FMSUB_S 0x47 -#define MASK_FMSUB_S 0x600007f -#define MATCH_FNMSUB_S 0x4b -#define MASK_FNMSUB_S 0x600007f -#define MATCH_FNMADD_S 0x4f -#define MASK_FNMADD_S 0x600007f -#define MATCH_FCVT_L_S 0xc0200053 -#define MASK_FCVT_L_S 0xfff0007f -#define MATCH_FCVT_LU_S 0xc0300053 -#define MASK_FCVT_LU_S 0xfff0007f -#define MATCH_FCVT_S_L 0xd0200053 -#define MASK_FCVT_S_L 0xfff0007f -#define MATCH_FCVT_S_LU 0xd0300053 -#define MASK_FCVT_S_LU 0xfff0007f -#define MATCH_FADD_D 0x2000053 -#define MASK_FADD_D 0xfe00007f -#define MATCH_FSUB_D 0xa000053 -#define MASK_FSUB_D 0xfe00007f -#define MATCH_FMUL_D 0x12000053 -#define MASK_FMUL_D 0xfe00007f -#define MATCH_FDIV_D 0x1a000053 -#define MASK_FDIV_D 0xfe00007f -#define MATCH_FSGNJ_D 0x22000053 -#define MASK_FSGNJ_D 0xfe00707f -#define MATCH_FSGNJN_D 0x22001053 -#define MASK_FSGNJN_D 0xfe00707f -#define MATCH_FSGNJX_D 0x22002053 -#define MASK_FSGNJX_D 0xfe00707f -#define MATCH_FMIN_D 0x2a000053 -#define MASK_FMIN_D 0xfe00707f -#define MATCH_FMAX_D 0x2a001053 -#define MASK_FMAX_D 0xfe00707f -#define MATCH_FCVT_S_D 0x40100053 -#define MASK_FCVT_S_D 0xfff0007f -#define MATCH_FCVT_D_S 0x42000053 -#define MASK_FCVT_D_S 0xfff0007f -#define MATCH_FSQRT_D 0x5a000053 -#define MASK_FSQRT_D 0xfff0007f -#define MATCH_FLE_D 0xa2000053 -#define MASK_FLE_D 0xfe00707f -#define MATCH_FLT_D 0xa2001053 -#define MASK_FLT_D 0xfe00707f -#define MATCH_FEQ_D 0xa2002053 -#define MASK_FEQ_D 0xfe00707f -#define MATCH_FCVT_W_D 0xc2000053 -#define MASK_FCVT_W_D 0xfff0007f -#define MATCH_FCVT_WU_D 0xc2100053 -#define MASK_FCVT_WU_D 0xfff0007f -#define MATCH_FCLASS_D 0xe2001053 -#define MASK_FCLASS_D 0xfff0707f -#define MATCH_FCVT_D_W 0xd2000053 -#define MASK_FCVT_D_W 0xfff0007f -#define MATCH_FCVT_D_WU 0xd2100053 -#define MASK_FCVT_D_WU 0xfff0007f -#define MATCH_FLD 0x3007 -#define MASK_FLD 0x707f -#define MATCH_FSD 0x3027 -#define MASK_FSD 0x707f -#define MATCH_FMADD_D 0x2000043 -#define MASK_FMADD_D 0x600007f -#define MATCH_FMSUB_D 0x2000047 -#define MASK_FMSUB_D 0x600007f -#define MATCH_FNMSUB_D 0x200004b -#define MASK_FNMSUB_D 0x600007f -#define MATCH_FNMADD_D 0x200004f -#define MASK_FNMADD_D 0x600007f -#define MATCH_FCVT_L_D 0xc2200053 -#define MASK_FCVT_L_D 0xfff0007f -#define MATCH_FCVT_LU_D 0xc2300053 -#define MASK_FCVT_LU_D 0xfff0007f -#define MATCH_FMV_X_D 0xe2000053 -#define MASK_FMV_X_D 0xfff0707f -#define MATCH_FCVT_D_L 0xd2200053 -#define MASK_FCVT_D_L 0xfff0007f -#define MATCH_FCVT_D_LU 0xd2300053 -#define MASK_FCVT_D_LU 0xfff0007f -#define MATCH_FMV_D_X 0xf2000053 -#define MASK_FMV_D_X 0xfff0707f -#define MATCH_FADD_Q 0x6000053 -#define MASK_FADD_Q 0xfe00007f -#define MATCH_FSUB_Q 0xe000053 -#define MASK_FSUB_Q 0xfe00007f -#define MATCH_FMUL_Q 0x16000053 -#define MASK_FMUL_Q 0xfe00007f -#define MATCH_FDIV_Q 0x1e000053 -#define MASK_FDIV_Q 0xfe00007f -#define MATCH_FSGNJ_Q 0x26000053 -#define MASK_FSGNJ_Q 0xfe00707f -#define MATCH_FSGNJN_Q 0x26001053 -#define MASK_FSGNJN_Q 0xfe00707f -#define MATCH_FSGNJX_Q 0x26002053 -#define MASK_FSGNJX_Q 0xfe00707f -#define MATCH_FMIN_Q 0x2e000053 -#define MASK_FMIN_Q 0xfe00707f -#define MATCH_FMAX_Q 0x2e001053 -#define MASK_FMAX_Q 0xfe00707f -#define MATCH_FCVT_S_Q 0x40300053 -#define MASK_FCVT_S_Q 0xfff0007f -#define MATCH_FCVT_Q_S 0x46000053 -#define MASK_FCVT_Q_S 0xfff0007f -#define MATCH_FCVT_D_Q 0x42300053 -#define MASK_FCVT_D_Q 0xfff0007f -#define MATCH_FCVT_Q_D 0x46100053 -#define MASK_FCVT_Q_D 0xfff0007f -#define MATCH_FSQRT_Q 0x5e000053 -#define MASK_FSQRT_Q 0xfff0007f -#define MATCH_FLE_Q 0xa6000053 -#define MASK_FLE_Q 0xfe00707f -#define MATCH_FLT_Q 0xa6001053 -#define MASK_FLT_Q 0xfe00707f -#define MATCH_FEQ_Q 0xa6002053 -#define MASK_FEQ_Q 0xfe00707f -#define MATCH_FCVT_W_Q 0xc6000053 -#define MASK_FCVT_W_Q 0xfff0007f -#define MATCH_FCVT_WU_Q 0xc6100053 -#define MASK_FCVT_WU_Q 0xfff0007f -#define MATCH_FCLASS_Q 0xe6001053 -#define MASK_FCLASS_Q 0xfff0707f -#define MATCH_FCVT_Q_W 0xd6000053 -#define MASK_FCVT_Q_W 0xfff0007f -#define MATCH_FCVT_Q_WU 0xd6100053 -#define MASK_FCVT_Q_WU 0xfff0007f -#define MATCH_FLQ 0x4007 -#define MASK_FLQ 0x707f -#define MATCH_FSQ 0x4027 -#define MASK_FSQ 0x707f -#define MATCH_FMADD_Q 0x6000043 -#define MASK_FMADD_Q 0x600007f -#define MATCH_FMSUB_Q 0x6000047 -#define MASK_FMSUB_Q 0x600007f -#define MATCH_FNMSUB_Q 0x600004b -#define MASK_FNMSUB_Q 0x600007f -#define MATCH_FNMADD_Q 0x600004f -#define MASK_FNMADD_Q 0x600007f -#define MATCH_FCVT_L_Q 0xc6200053 -#define MASK_FCVT_L_Q 0xfff0007f -#define MATCH_FCVT_LU_Q 0xc6300053 -#define MASK_FCVT_LU_Q 0xfff0007f -#define MATCH_FCVT_Q_L 0xd6200053 -#define MASK_FCVT_Q_L 0xfff0007f -#define MATCH_FCVT_Q_LU 0xd6300053 -#define MASK_FCVT_Q_LU 0xfff0007f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f #define MATCH_ANDN 0x40007033 -#define MASK_ANDN 0xfe00707f -#define MATCH_ORN 0x40006033 -#define MASK_ORN 0xfe00707f -#define MATCH_XNOR 0x40004033 -#define MASK_XNOR 0xfe00707f -#define MATCH_SLO 0x20001033 -#define MASK_SLO 0xfe00707f -#define MATCH_SRO 0x20005033 -#define MASK_SRO 0xfe00707f -#define MATCH_ROL 0x60001033 -#define MASK_ROL 0xfe00707f -#define MATCH_ROR 0x60005033 -#define MASK_ROR 0xfe00707f +#define MASK_ANDN 0xfe00707f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_AVE 0xe0000077 +#define MASK_AVE 0xfe00707f #define MATCH_BCLR 0x48001033 -#define MASK_BCLR 0xfe00707f -#define MATCH_BSET 0x28001033 -#define MASK_BSET 0xfe00707f -#define MATCH_BINV 0x68001033 -#define MASK_BINV 0xfe00707f -#define MATCH_BEXT 0x48005033 -#define MASK_BEXT 0xfe00707f -#define MATCH_GORC 0x28005033 -#define MASK_GORC 0xfe00707f -#define MATCH_GREV 0x68005033 -#define MASK_GREV 0xfe00707f -#define MATCH_SLOI 0x20001013 -#define MASK_SLOI 0xfc00707f -#define MATCH_SROI 0x20005013 -#define MASK_SROI 0xfc00707f -#define MATCH_RORI 0x60005013 -#define MASK_RORI 0xfc00707f +#define MASK_BCLR 0xfe00707f #define MATCH_BCLRI 0x48001013 -#define MASK_BCLRI 0xfc00707f -#define MATCH_BSETI 0x28001013 -#define MASK_BSETI 0xfc00707f -#define MATCH_BINVI 0x68001013 -#define MASK_BINVI 0xfc00707f +#define MASK_BCLRI 0xfc00707f +#define MATCH_BCOMPRESS 0x8006033 +#define MASK_BCOMPRESS 0xfe00707f +#define MATCH_BCOMPRESSW 0x800603b +#define MASK_BCOMPRESSW 0xfe00707f +#define MATCH_BDECOMPRESS 0x48006033 +#define MASK_BDECOMPRESS 0xfe00707f +#define MATCH_BDECOMPRESSW 0x4800603b +#define MASK_BDECOMPRESSW 0xfe00707f +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BEXT 0x48005033 +#define MASK_BEXT 0xfe00707f #define MATCH_BEXTI 0x48005013 -#define MASK_BEXTI 0xfc00707f -#define MATCH_GORCI 0x28005013 -#define MASK_GORCI 0xfc00707f -#define MATCH_GREVI 0x68005013 -#define MASK_GREVI 0xfc00707f -#define MATCH_CMIX 0x6001033 -#define MASK_CMIX 0x600707f -#define MATCH_CMOV 0x6005033 -#define MASK_CMOV 0x600707f -#define MATCH_FSL 0x4001033 -#define MASK_FSL 0x600707f -#define MATCH_FSR 0x4005033 -#define MASK_FSR 0x600707f -#define MATCH_FSRI 0x4005013 -#define MASK_FSRI 0x400707f -#define MATCH_CLZ 0x60001013 -#define MASK_CLZ 0xfff0707f -#define MATCH_CTZ 0x60101013 -#define MASK_CTZ 0xfff0707f -#define MATCH_CPOP 0x60201013 -#define MASK_CPOP 0xfff0707f -#define MATCH_SEXT_B 0x60401013 -#define MASK_SEXT_B 0xfff0707f -#define MATCH_SEXT_H 0x60501013 -#define MASK_SEXT_H 0xfff0707f -#define MATCH_CRC32_B 0x61001013 -#define MASK_CRC32_B 0xfff0707f -#define MATCH_CRC32_H 0x61101013 -#define MASK_CRC32_H 0xfff0707f -#define MATCH_CRC32_W 0x61201013 -#define MASK_CRC32_W 0xfff0707f -#define MATCH_CRC32C_B 0x61801013 -#define MASK_CRC32C_B 0xfff0707f -#define MATCH_CRC32C_H 0x61901013 -#define MASK_CRC32C_H 0xfff0707f -#define MATCH_CRC32C_W 0x61a01013 -#define MASK_CRC32C_W 0xfff0707f -#define MATCH_SH1ADD 0x20002033 -#define MASK_SH1ADD 0xfe00707f -#define MATCH_SH2ADD 0x20004033 -#define MASK_SH2ADD 0xfe00707f -#define MATCH_SH3ADD 0x20006033 -#define MASK_SH3ADD 0xfe00707f -#define MATCH_CLMUL 0xa001033 -#define MASK_CLMUL 0xfe00707f -#define MATCH_CLMULR 0xa002033 -#define MASK_CLMULR 0xfe00707f -#define MATCH_CLMULH 0xa003033 -#define MASK_CLMULH 0xfe00707f -#define MATCH_MIN 0xa004033 -#define MASK_MIN 0xfe00707f -#define MATCH_MINU 0xa005033 -#define MASK_MINU 0xfe00707f -#define MATCH_MAX 0xa006033 -#define MASK_MAX 0xfe00707f -#define MATCH_MAXU 0xa007033 -#define MASK_MAXU 0xfe00707f -#define MATCH_SHFL 0x8001033 -#define MASK_SHFL 0xfe00707f -#define MATCH_UNSHFL 0x8005033 -#define MASK_UNSHFL 0xfe00707f -#define MATCH_BCOMPRESS 0x8006033 -#define MASK_BCOMPRESS 0xfe00707f -#define MATCH_BDECOMPRESS 0x48006033 -#define MASK_BDECOMPRESS 0xfe00707f -#define MATCH_PACK 0x8004033 -#define MASK_PACK 0xfe00707f -#define MATCH_PACKU 0x48004033 -#define MASK_PACKU 0xfe00707f -#define MATCH_PACKH 0x8007033 -#define MASK_PACKH 0xfe00707f +#define MASK_BEXTI 0xfc00707f #define MATCH_BFP 0x48007033 -#define MASK_BFP 0xfe00707f -#define MATCH_SHFLI 0x8001013 -#define MASK_SHFLI 0xfe00707f -#define MATCH_UNSHFLI 0x8005013 -#define MASK_UNSHFLI 0xfe00707f -#define MATCH_XPERM4 0x28002033 -#define MASK_XPERM4 0xfe00707f -#define MATCH_XPERM8 0x28004033 -#define MASK_XPERM8 0xfe00707f -#define MATCH_XPERM16 0x28006033 -#define MASK_XPERM16 0xfe00707f +#define MASK_BFP 0xfe00707f +#define MATCH_BFPW 0x4800703b +#define MASK_BFPW 0xfe00707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_BINV 0x68001033 +#define MASK_BINV 0xfe00707f +#define MATCH_BINVI 0x68001013 +#define MASK_BINVI 0xfc00707f +#define MATCH_BITREV 0xe6000077 +#define MASK_BITREV 0xfe00707f +#define MATCH_BITREVI 0xe8000077 +#define MASK_BITREVI 0xfc00707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f #define MATCH_BMATFLIP 0x60301013 -#define MASK_BMATFLIP 0xfff0707f -#define MATCH_CRC32_D 0x61301013 -#define MASK_CRC32_D 0xfff0707f -#define MATCH_CRC32C_D 0x61b01013 -#define MASK_CRC32C_D 0xfff0707f +#define MASK_BMATFLIP 0xfff0707f #define MATCH_BMATOR 0x8003033 -#define MASK_BMATOR 0xfe00707f +#define MASK_BMATOR 0xfe00707f #define MATCH_BMATXOR 0x48003033 -#define MASK_BMATXOR 0xfe00707f -#define MATCH_SLLI_UW 0x800101b -#define MASK_SLLI_UW 0xfc00707f -#define MATCH_ADD_UW 0x800003b -#define MASK_ADD_UW 0xfe00707f -#define MATCH_SLOW 0x2000103b -#define MASK_SLOW 0xfe00707f -#define MATCH_SROW 0x2000503b -#define MASK_SROW 0xfe00707f -#define MATCH_ROLW 0x6000103b -#define MASK_ROLW 0xfe00707f -#define MATCH_RORW 0x6000503b -#define MASK_RORW 0xfe00707f -#define MATCH_SBCLRW 0x4800103b -#define MASK_SBCLRW 0xfe00707f -#define MATCH_SBSETW 0x2800103b -#define MASK_SBSETW 0xfe00707f -#define MATCH_SBINVW 0x6800103b -#define MASK_SBINVW 0xfe00707f -#define MATCH_SBEXTW 0x4800503b -#define MASK_SBEXTW 0xfe00707f -#define MATCH_GORCW 0x2800503b -#define MASK_GORCW 0xfe00707f -#define MATCH_GREVW 0x6800503b -#define MASK_GREVW 0xfe00707f -#define MATCH_SLOIW 0x2000101b -#define MASK_SLOIW 0xfe00707f -#define MATCH_SROIW 0x2000501b -#define MASK_SROIW 0xfe00707f -#define MATCH_RORIW 0x6000501b -#define MASK_RORIW 0xfe00707f -#define MATCH_SBCLRIW 0x4800101b -#define MASK_SBCLRIW 0xfe00707f -#define MATCH_SBSETIW 0x2800101b -#define MASK_SBSETIW 0xfe00707f -#define MATCH_SBINVIW 0x6800101b -#define MASK_SBINVIW 0xfe00707f -#define MATCH_GORCIW 0x2800501b -#define MASK_GORCIW 0xfe00707f -#define MATCH_GREVIW 0x6800501b -#define MASK_GREVIW 0xfe00707f -#define MATCH_FSLW 0x400103b -#define MASK_FSLW 0x600707f -#define MATCH_FSRW 0x400503b -#define MASK_FSRW 0x600707f -#define MATCH_FSRIW 0x400501b -#define MASK_FSRIW 0x600707f -#define MATCH_CLZW 0x6000101b -#define MASK_CLZW 0xfff0707f -#define MATCH_CTZW 0x6010101b -#define MASK_CTZW 0xfff0707f -#define MATCH_CPOPW 0x6020101b -#define MASK_CPOPW 0xfff0707f -#define MATCH_SH1ADD_UW 0x2000203b -#define MASK_SH1ADD_UW 0xfe00707f -#define MATCH_SH2ADD_UW 0x2000403b -#define MASK_SH2ADD_UW 0xfe00707f -#define MATCH_SH3ADD_UW 0x2000603b -#define MASK_SH3ADD_UW 0xfe00707f -#define MATCH_SHFLW 0x800103b -#define MASK_SHFLW 0xfe00707f -#define MATCH_UNSHFLW 0x800503b -#define MASK_UNSHFLW 0xfe00707f -#define MATCH_BCOMPRESSW 0x800603b -#define MASK_BCOMPRESSW 0xfe00707f -#define MATCH_BDECOMPRESSW 0x4800603b -#define MASK_BDECOMPRESSW 0xfe00707f -#define MATCH_PACKW 0x800403b -#define MASK_PACKW 0xfe00707f -#define MATCH_PACKUW 0x4800403b -#define MASK_PACKUW 0xfe00707f -#define MATCH_BFPW 0x4800703b -#define MASK_BFPW 0xfe00707f -#define MATCH_XPERM32 0x28000033 -#define MASK_XPERM32 0xfe00707f -#define MATCH_ECALL 0x73 -#define MASK_ECALL 0xffffffff -#define MATCH_EBREAK 0x100073 -#define MASK_EBREAK 0xffffffff -#define MATCH_SRET 0x10200073 -#define MASK_SRET 0xffffffff -#define MATCH_MRET 0x30200073 -#define MASK_MRET 0xffffffff -#define MATCH_DRET 0x7b200073 -#define MASK_DRET 0xffffffff -#define MATCH_SFENCE_VMA 0x12000073 -#define MASK_SFENCE_VMA 0xfe007fff -#define MATCH_WFI 0x10500073 -#define MASK_WFI 0xffffffff -#define MATCH_CSRRW 0x1073 -#define MASK_CSRRW 0x707f -#define MATCH_CSRRS 0x2073 -#define MASK_CSRRS 0x707f -#define MATCH_CSRRC 0x3073 -#define MASK_CSRRC 0x707f -#define MATCH_CSRRWI 0x5073 -#define MASK_CSRRWI 0x707f -#define MATCH_CSRRSI 0x6073 -#define MASK_CSRRSI 0x707f -#define MATCH_CSRRCI 0x7073 -#define MASK_CSRRCI 0x707f -#define MATCH_SINVAL_VMA 0x16000073 -#define MASK_SINVAL_VMA 0xfe007fff -#define MATCH_SFENCE_W_INVAL 0x18000073 -#define MASK_SFENCE_W_INVAL 0xffffffff -#define MATCH_SFENCE_INVAL_IR 0x18100073 -#define MASK_SFENCE_INVAL_IR 0xffffffff -#define MATCH_HINVAL_VVMA 0x36000073 -#define MASK_HINVAL_VVMA 0xfe007fff -#define MATCH_HINVAL_GVMA 0x76000073 -#define MASK_HINVAL_GVMA 0xfe007fff -#define MATCH_FADD_H 0x4000053 -#define MASK_FADD_H 0xfe00007f -#define MATCH_FSUB_H 0xc000053 -#define MASK_FSUB_H 0xfe00007f -#define MATCH_FMUL_H 0x14000053 -#define MASK_FMUL_H 0xfe00007f -#define MATCH_FDIV_H 0x1c000053 -#define MASK_FDIV_H 0xfe00007f -#define MATCH_FSGNJ_H 0x24000053 -#define MASK_FSGNJ_H 0xfe00707f -#define MATCH_FSGNJN_H 0x24001053 -#define MASK_FSGNJN_H 0xfe00707f -#define MATCH_FSGNJX_H 0x24002053 -#define MASK_FSGNJX_H 0xfe00707f -#define MATCH_FMIN_H 0x2c000053 -#define MASK_FMIN_H 0xfe00707f -#define MATCH_FMAX_H 0x2c001053 -#define MASK_FMAX_H 0xfe00707f -#define MATCH_FCVT_H_S 0x44000053 -#define MASK_FCVT_H_S 0xfff0007f -#define MATCH_FCVT_S_H 0x40200053 -#define MASK_FCVT_S_H 0xfff0007f -#define MATCH_FSQRT_H 0x5c000053 -#define MASK_FSQRT_H 0xfff0007f -#define MATCH_FLE_H 0xa4000053 -#define MASK_FLE_H 0xfe00707f -#define MATCH_FLT_H 0xa4001053 -#define MASK_FLT_H 0xfe00707f -#define MATCH_FEQ_H 0xa4002053 -#define MASK_FEQ_H 0xfe00707f -#define MATCH_FCVT_W_H 0xc4000053 -#define MASK_FCVT_W_H 0xfff0007f -#define MATCH_FCVT_WU_H 0xc4100053 -#define MASK_FCVT_WU_H 0xfff0007f -#define MATCH_FMV_X_H 0xe4000053 -#define MASK_FMV_X_H 0xfff0707f -#define MATCH_FCLASS_H 0xe4001053 -#define MASK_FCLASS_H 0xfff0707f -#define MATCH_FCVT_H_W 0xd4000053 -#define MASK_FCVT_H_W 0xfff0007f -#define MATCH_FCVT_H_WU 0xd4100053 -#define MASK_FCVT_H_WU 0xfff0007f -#define MATCH_FMV_H_X 0xf4000053 -#define MASK_FMV_H_X 0xfff0707f -#define MATCH_FLH 0x1007 -#define MASK_FLH 0x707f -#define MATCH_FSH 0x1027 -#define MASK_FSH 0x707f -#define MATCH_FMADD_H 0x4000043 -#define MASK_FMADD_H 0x600007f -#define MATCH_FMSUB_H 0x4000047 -#define MASK_FMSUB_H 0x600007f -#define MATCH_FNMSUB_H 0x400004b -#define MASK_FNMSUB_H 0x600007f -#define MATCH_FNMADD_H 0x400004f -#define MASK_FNMADD_H 0x600007f -#define MATCH_FCVT_H_D 0x44100053 -#define MASK_FCVT_H_D 0xfff0007f -#define MATCH_FCVT_D_H 0x42200053 -#define MASK_FCVT_D_H 0xfff0007f -#define MATCH_FCVT_H_Q 0x44300053 -#define MASK_FCVT_H_Q 0xfff0007f -#define MATCH_FCVT_Q_H 0x46200053 -#define MASK_FCVT_Q_H 0xfff0007f -#define MATCH_FCVT_L_H 0xc4200053 -#define MASK_FCVT_L_H 0xfff0007f -#define MATCH_FCVT_LU_H 0xc4300053 -#define MASK_FCVT_LU_H 0xfff0007f -#define MATCH_FCVT_H_L 0xd4200053 -#define MASK_FCVT_H_L 0xfff0007f -#define MATCH_FCVT_H_LU 0xd4300053 -#define MASK_FCVT_H_LU 0xfff0007f -#define MATCH_SM4ED 0x30000033 -#define MASK_SM4ED 0x3e00707f -#define MATCH_SM4KS 0x34000033 -#define MASK_SM4KS 0x3e00707f -#define MATCH_SM3P0 0x10801013 -#define MASK_SM3P0 0xfff0707f -#define MATCH_SM3P1 0x10901013 -#define MASK_SM3P1 0xfff0707f -#define MATCH_SHA256SUM0 0x10001013 -#define MASK_SHA256SUM0 0xfff0707f -#define MATCH_SHA256SUM1 0x10101013 -#define MASK_SHA256SUM1 0xfff0707f -#define MATCH_SHA256SIG0 0x10201013 -#define MASK_SHA256SIG0 0xfff0707f -#define MATCH_SHA256SIG1 0x10301013 -#define MASK_SHA256SIG1 0xfff0707f -#define MATCH_AES32ESMI 0x26000033 -#define MASK_AES32ESMI 0x3e00707f -#define MATCH_AES32ESI 0x22000033 -#define MASK_AES32ESI 0x3e00707f -#define MATCH_AES32DSMI 0x2e000033 -#define MASK_AES32DSMI 0x3e00707f -#define MATCH_AES32DSI 0x2a000033 -#define MASK_AES32DSI 0x3e00707f -#define MATCH_SHA512SUM0R 0x50000033 -#define MASK_SHA512SUM0R 0xfe00707f -#define MATCH_SHA512SUM1R 0x52000033 -#define MASK_SHA512SUM1R 0xfe00707f -#define MATCH_SHA512SIG0L 0x54000033 -#define MASK_SHA512SIG0L 0xfe00707f -#define MATCH_SHA512SIG0H 0x5c000033 -#define MASK_SHA512SIG0H 0xfe00707f -#define MATCH_SHA512SIG1L 0x56000033 -#define MASK_SHA512SIG1L 0xfe00707f -#define MATCH_SHA512SIG1H 0x5e000033 -#define MASK_SHA512SIG1H 0xfe00707f -#define MATCH_AES64KS1I 0x31001013 -#define MASK_AES64KS1I 0xff00707f -#define MATCH_AES64IM 0x30001013 -#define MASK_AES64IM 0xfff0707f -#define MATCH_AES64KS2 0x7e000033 -#define MASK_AES64KS2 0xfe00707f -#define MATCH_AES64ESM 0x36000033 -#define MASK_AES64ESM 0xfe00707f -#define MATCH_AES64ES 0x32000033 -#define MASK_AES64ES 0xfe00707f -#define MATCH_AES64DSM 0x3e000033 -#define MASK_AES64DSM 0xfe00707f -#define MATCH_AES64DS 0x3a000033 -#define MASK_AES64DS 0xfe00707f -#define MATCH_SHA512SUM0 0x10401013 -#define MASK_SHA512SUM0 0xfff0707f -#define MATCH_SHA512SUM1 0x10501013 -#define MASK_SHA512SUM1 0xfff0707f -#define MATCH_SHA512SIG0 0x10601013 -#define MASK_SHA512SIG0 0xfff0707f -#define MATCH_SHA512SIG1 0x10701013 -#define MASK_SHA512SIG1 0xfff0707f -#define MATCH_C_NOP 0x1 -#define MASK_C_NOP 0xffff +#define MASK_BMATXOR 0xfe00707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BPICK 0x3077 +#define MASK_BPICK 0x600707f +#define MATCH_BSET 0x28001033 +#define MASK_BSET 0xfe00707f +#define MATCH_BSETI 0x28001013 +#define MASK_BSETI 0xfc00707f +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 #define MATCH_C_ADDI16SP 0x6101 -#define MASK_C_ADDI16SP 0xef83 -#define MATCH_C_JR 0x8002 -#define MASK_C_JR 0xf07f -#define MATCH_C_JALR 0x9002 -#define MASK_C_JALR 0xf07f -#define MATCH_C_EBREAK 0x9002 -#define MASK_C_EBREAK 0xffff +#define MASK_C_ADDI16SP 0xef83 #define MATCH_C_ADDI4SPN 0x0 -#define MASK_C_ADDI4SPN 0xe003 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff #define MATCH_C_FLD 0x2000 -#define MASK_C_FLD 0xe003 -#define MATCH_C_LW 0x4000 -#define MASK_C_LW 0xe003 +#define MASK_C_FLD 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 #define MATCH_C_FLW 0x6000 -#define MASK_C_FLW 0xe003 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 #define MATCH_C_FSD 0xa000 -#define MASK_C_FSD 0xe003 -#define MATCH_C_SW 0xc000 -#define MASK_C_SW 0xe003 +#define MASK_C_FSD 0xe003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 #define MATCH_C_FSW 0xe000 -#define MASK_C_FSW 0xe003 -#define MATCH_C_ADDI 0x1 -#define MASK_C_ADDI 0xe003 +#define MASK_C_FSW 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 #define MATCH_C_JAL 0x2001 -#define MASK_C_JAL 0xe003 +#define MASK_C_JAL 0xe003 +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 #define MATCH_C_LI 0x4001 -#define MASK_C_LI 0xe003 +#define MASK_C_LI 0xe003 #define MATCH_C_LUI 0x6001 -#define MASK_C_LUI 0xe003 -#define MATCH_C_SRLI 0x8001 -#define MASK_C_SRLI 0xec03 -#define MATCH_C_SRAI 0x8401 -#define MASK_C_SRAI 0xec03 -#define MATCH_C_ANDI 0x8801 -#define MASK_C_ANDI 0xec03 -#define MATCH_C_SUB 0x8c01 -#define MASK_C_SUB 0xfc63 -#define MATCH_C_XOR 0x8c21 -#define MASK_C_XOR 0xfc63 -#define MATCH_C_OR 0x8c41 -#define MASK_C_OR 0xfc63 -#define MATCH_C_AND 0x8c61 -#define MASK_C_AND 0xfc63 -#define MATCH_C_J 0xa001 -#define MASK_C_J 0xe003 -#define MATCH_C_BEQZ 0xc001 -#define MASK_C_BEQZ 0xe003 -#define MATCH_C_BNEZ 0xe001 -#define MASK_C_BNEZ 0xe003 -#define MATCH_C_SLLI 0x2 -#define MASK_C_SLLI 0xe003 -#define MATCH_C_FLDSP 0x2002 -#define MASK_C_FLDSP 0xe003 +#define MASK_C_LUI 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 #define MATCH_C_LWSP 0x4002 -#define MASK_C_LWSP 0xe003 -#define MATCH_C_FLWSP 0x6002 -#define MASK_C_FLWSP 0xe003 +#define MASK_C_LWSP 0xe003 #define MATCH_C_MV 0x8002 -#define MASK_C_MV 0xf003 -#define MATCH_C_ADD 0x9002 -#define MASK_C_ADD 0xf003 -#define MATCH_C_FSDSP 0xa002 -#define MASK_C_FSDSP 0xe003 -#define MATCH_C_SWSP 0xc002 -#define MASK_C_SWSP 0xe003 -#define MATCH_C_FSWSP 0xe002 -#define MASK_C_FSWSP 0xe003 -#define MATCH_C_SRLI_RV32 0x8001 -#define MASK_C_SRLI_RV32 0xfc03 -#define MATCH_C_SRAI_RV32 0x8401 -#define MASK_C_SRAI_RV32 0xfc03 -#define MATCH_C_SLLI_RV32 0x2 -#define MASK_C_SLLI_RV32 0xf003 -#define MATCH_C_LD 0x6000 -#define MASK_C_LD 0xe003 +#define MASK_C_MV 0xf003 +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xef83 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 #define MATCH_C_SD 0xe000 -#define MASK_C_SD 0xe003 -#define MATCH_C_SUBW 0x9c01 -#define MASK_C_SUBW 0xfc63 -#define MATCH_C_ADDW 0x9c21 -#define MASK_C_ADDW 0xfc63 -#define MATCH_C_ADDIW 0x2001 -#define MASK_C_ADDIW 0xe003 -#define MATCH_C_LDSP 0x6002 -#define MASK_C_LDSP 0xe003 +#define MASK_C_SD 0xe003 #define MATCH_C_SDSP 0xe002 -#define MASK_C_SDSP 0xe003 -#define MATCH_CUSTOM0 0xb -#define MASK_CUSTOM0 0x707f -#define MATCH_CUSTOM0_RS1 0x200b -#define MASK_CUSTOM0_RS1 0x707f -#define MATCH_CUSTOM0_RS1_RS2 0x300b -#define MASK_CUSTOM0_RS1_RS2 0x707f -#define MATCH_CUSTOM0_RD 0x400b -#define MASK_CUSTOM0_RD 0x707f -#define MATCH_CUSTOM0_RD_RS1 0x600b -#define MASK_CUSTOM0_RD_RS1 0x707f -#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b -#define MASK_CUSTOM0_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM1 0x2b -#define MASK_CUSTOM1 0x707f -#define MATCH_CUSTOM1_RS1 0x202b -#define MASK_CUSTOM1_RS1 0x707f -#define MATCH_CUSTOM1_RS1_RS2 0x302b -#define MASK_CUSTOM1_RS1_RS2 0x707f -#define MATCH_CUSTOM1_RD 0x402b -#define MASK_CUSTOM1_RD 0x707f -#define MATCH_CUSTOM1_RD_RS1 0x602b -#define MASK_CUSTOM1_RD_RS1 0x707f -#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b -#define MASK_CUSTOM1_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM2 0x5b -#define MASK_CUSTOM2 0x707f -#define MATCH_CUSTOM2_RS1 0x205b -#define MASK_CUSTOM2_RS1 0x707f -#define MATCH_CUSTOM2_RS1_RS2 0x305b -#define MASK_CUSTOM2_RS1_RS2 0x707f -#define MATCH_CUSTOM2_RD 0x405b -#define MASK_CUSTOM2_RD 0x707f -#define MATCH_CUSTOM2_RD_RS1 0x605b -#define MASK_CUSTOM2_RD_RS1 0x707f -#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b -#define MASK_CUSTOM2_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM3 0x7b -#define MASK_CUSTOM3 0x707f -#define MATCH_CUSTOM3_RS1 0x207b -#define MASK_CUSTOM3_RS1 0x707f -#define MATCH_CUSTOM3_RS1_RS2 0x307b -#define MASK_CUSTOM3_RS1_RS2 0x707f -#define MATCH_CUSTOM3_RD 0x407b -#define MASK_CUSTOM3_RD 0x707f -#define MATCH_CUSTOM3_RD_RS1 0x607b -#define MASK_CUSTOM3_RD_RS1 0x707f -#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b -#define MASK_CUSTOM3_RD_RS1_RS2 0x707f -#define MATCH_VSETIVLI 0xc0007057 -#define MASK_VSETIVLI 0xc000707f -#define MATCH_VSETVLI 0x7057 -#define MASK_VSETVLI 0x8000707f -#define MATCH_VSETVL 0x80007057 -#define MASK_VSETVL 0xfe00707f -#define MATCH_VLM_V 0x2b00007 -#define MASK_VLM_V 0xfff0707f -#define MATCH_VSM_V 0x2b00027 -#define MASK_VSM_V 0xfff0707f -#define MATCH_VLE8_V 0x7 -#define MASK_VLE8_V 0x1df0707f -#define MATCH_VLE16_V 0x5007 -#define MASK_VLE16_V 0x1df0707f -#define MATCH_VLE32_V 0x6007 -#define MASK_VLE32_V 0x1df0707f -#define MATCH_VLE64_V 0x7007 -#define MASK_VLE64_V 0x1df0707f -#define MATCH_VLE128_V 0x10000007 -#define MASK_VLE128_V 0x1df0707f -#define MATCH_VLE256_V 0x10005007 -#define MASK_VLE256_V 0x1df0707f -#define MATCH_VLE512_V 0x10006007 -#define MASK_VLE512_V 0x1df0707f -#define MATCH_VLE1024_V 0x10007007 -#define MASK_VLE1024_V 0x1df0707f -#define MATCH_VSE8_V 0x27 -#define MASK_VSE8_V 0x1df0707f -#define MATCH_VSE16_V 0x5027 -#define MASK_VSE16_V 0x1df0707f -#define MATCH_VSE32_V 0x6027 -#define MASK_VSE32_V 0x1df0707f -#define MATCH_VSE64_V 0x7027 -#define MASK_VSE64_V 0x1df0707f -#define MATCH_VSE128_V 0x10000027 -#define MASK_VSE128_V 0x1df0707f -#define MATCH_VSE256_V 0x10005027 -#define MASK_VSE256_V 0x1df0707f -#define MATCH_VSE512_V 0x10006027 -#define MASK_VSE512_V 0x1df0707f -#define MATCH_VSE1024_V 0x10007027 -#define MASK_VSE1024_V 0x1df0707f -#define MATCH_VLUXEI8_V 0x4000007 -#define MASK_VLUXEI8_V 0x1c00707f -#define MATCH_VLUXEI16_V 0x4005007 -#define MASK_VLUXEI16_V 0x1c00707f -#define MATCH_VLUXEI32_V 0x4006007 -#define MASK_VLUXEI32_V 0x1c00707f -#define MATCH_VLUXEI64_V 0x4007007 -#define MASK_VLUXEI64_V 0x1c00707f -#define MATCH_VLUXEI128_V 0x14000007 -#define MASK_VLUXEI128_V 0x1c00707f -#define MATCH_VLUXEI256_V 0x14005007 -#define MASK_VLUXEI256_V 0x1c00707f -#define MATCH_VLUXEI512_V 0x14006007 -#define MASK_VLUXEI512_V 0x1c00707f -#define MATCH_VLUXEI1024_V 0x14007007 -#define MASK_VLUXEI1024_V 0x1c00707f -#define MATCH_VSUXEI8_V 0x4000027 -#define MASK_VSUXEI8_V 0x1c00707f -#define MATCH_VSUXEI16_V 0x4005027 -#define MASK_VSUXEI16_V 0x1c00707f -#define MATCH_VSUXEI32_V 0x4006027 -#define MASK_VSUXEI32_V 0x1c00707f -#define MATCH_VSUXEI64_V 0x4007027 -#define MASK_VSUXEI64_V 0x1c00707f -#define MATCH_VSUXEI128_V 0x14000027 -#define MASK_VSUXEI128_V 0x1c00707f -#define MATCH_VSUXEI256_V 0x14005027 -#define MASK_VSUXEI256_V 0x1c00707f -#define MATCH_VSUXEI512_V 0x14006027 -#define MASK_VSUXEI512_V 0x1c00707f -#define MATCH_VSUXEI1024_V 0x14007027 -#define MASK_VSUXEI1024_V 0x1c00707f -#define MATCH_VLSE8_V 0x8000007 -#define MASK_VLSE8_V 0x1c00707f -#define MATCH_VLSE16_V 0x8005007 -#define MASK_VLSE16_V 0x1c00707f -#define MATCH_VLSE32_V 0x8006007 -#define MASK_VLSE32_V 0x1c00707f -#define MATCH_VLSE64_V 0x8007007 -#define MASK_VLSE64_V 0x1c00707f -#define MATCH_VLSE128_V 0x18000007 -#define MASK_VLSE128_V 0x1c00707f -#define MATCH_VLSE256_V 0x18005007 -#define MASK_VLSE256_V 0x1c00707f -#define MATCH_VLSE512_V 0x18006007 -#define MASK_VLSE512_V 0x1c00707f -#define MATCH_VLSE1024_V 0x18007007 -#define MASK_VLSE1024_V 0x1c00707f -#define MATCH_VSSE8_V 0x8000027 -#define MASK_VSSE8_V 0x1c00707f -#define MATCH_VSSE16_V 0x8005027 -#define MASK_VSSE16_V 0x1c00707f -#define MATCH_VSSE32_V 0x8006027 -#define MASK_VSSE32_V 0x1c00707f -#define MATCH_VSSE64_V 0x8007027 -#define MASK_VSSE64_V 0x1c00707f -#define MATCH_VSSE128_V 0x18000027 -#define MASK_VSSE128_V 0x1c00707f -#define MATCH_VSSE256_V 0x18005027 -#define MASK_VSSE256_V 0x1c00707f -#define MATCH_VSSE512_V 0x18006027 -#define MASK_VSSE512_V 0x1c00707f -#define MATCH_VSSE1024_V 0x18007027 -#define MASK_VSSE1024_V 0x1c00707f -#define MATCH_VLOXEI8_V 0xc000007 -#define MASK_VLOXEI8_V 0x1c00707f -#define MATCH_VLOXEI16_V 0xc005007 -#define MASK_VLOXEI16_V 0x1c00707f -#define MATCH_VLOXEI32_V 0xc006007 -#define MASK_VLOXEI32_V 0x1c00707f -#define MATCH_VLOXEI64_V 0xc007007 -#define MASK_VLOXEI64_V 0x1c00707f -#define MATCH_VLOXEI128_V 0x1c000007 -#define MASK_VLOXEI128_V 0x1c00707f -#define MATCH_VLOXEI256_V 0x1c005007 -#define MASK_VLOXEI256_V 0x1c00707f -#define MATCH_VLOXEI512_V 0x1c006007 -#define MASK_VLOXEI512_V 0x1c00707f -#define MATCH_VLOXEI1024_V 0x1c007007 -#define MASK_VLOXEI1024_V 0x1c00707f -#define MATCH_VSOXEI8_V 0xc000027 -#define MASK_VSOXEI8_V 0x1c00707f -#define MATCH_VSOXEI16_V 0xc005027 -#define MASK_VSOXEI16_V 0x1c00707f -#define MATCH_VSOXEI32_V 0xc006027 -#define MASK_VSOXEI32_V 0x1c00707f -#define MATCH_VSOXEI64_V 0xc007027 -#define MASK_VSOXEI64_V 0x1c00707f -#define MATCH_VSOXEI128_V 0x1c000027 -#define MASK_VSOXEI128_V 0x1c00707f -#define MATCH_VSOXEI256_V 0x1c005027 -#define MASK_VSOXEI256_V 0x1c00707f -#define MATCH_VSOXEI512_V 0x1c006027 -#define MASK_VSOXEI512_V 0x1c00707f -#define MATCH_VSOXEI1024_V 0x1c007027 -#define MASK_VSOXEI1024_V 0x1c00707f -#define MATCH_VLE8FF_V 0x1000007 -#define MASK_VLE8FF_V 0x1df0707f -#define MATCH_VLE16FF_V 0x1005007 -#define MASK_VLE16FF_V 0x1df0707f -#define MATCH_VLE32FF_V 0x1006007 -#define MASK_VLE32FF_V 0x1df0707f -#define MATCH_VLE64FF_V 0x1007007 -#define MASK_VLE64FF_V 0x1df0707f -#define MATCH_VLE128FF_V 0x11000007 -#define MASK_VLE128FF_V 0x1df0707f -#define MATCH_VLE256FF_V 0x11005007 -#define MASK_VLE256FF_V 0x1df0707f -#define MATCH_VLE512FF_V 0x11006007 -#define MASK_VLE512FF_V 0x1df0707f -#define MATCH_VLE1024FF_V 0x11007007 -#define MASK_VLE1024FF_V 0x1df0707f -#define MATCH_VL1RE8_V 0x2800007 -#define MASK_VL1RE8_V 0xfff0707f -#define MATCH_VL1RE16_V 0x2805007 -#define MASK_VL1RE16_V 0xfff0707f -#define MATCH_VL1RE32_V 0x2806007 -#define MASK_VL1RE32_V 0xfff0707f -#define MATCH_VL1RE64_V 0x2807007 -#define MASK_VL1RE64_V 0xfff0707f -#define MATCH_VL2RE8_V 0x22800007 -#define MASK_VL2RE8_V 0xfff0707f -#define MATCH_VL2RE16_V 0x22805007 -#define MASK_VL2RE16_V 0xfff0707f -#define MATCH_VL2RE32_V 0x22806007 -#define MASK_VL2RE32_V 0xfff0707f -#define MATCH_VL2RE64_V 0x22807007 -#define MASK_VL2RE64_V 0xfff0707f -#define MATCH_VL4RE8_V 0x62800007 -#define MASK_VL4RE8_V 0xfff0707f -#define MATCH_VL4RE16_V 0x62805007 -#define MASK_VL4RE16_V 0xfff0707f -#define MATCH_VL4RE32_V 0x62806007 -#define MASK_VL4RE32_V 0xfff0707f -#define MATCH_VL4RE64_V 0x62807007 -#define MASK_VL4RE64_V 0xfff0707f -#define MATCH_VL8RE8_V 0xe2800007 -#define MASK_VL8RE8_V 0xfff0707f -#define MATCH_VL8RE16_V 0xe2805007 -#define MASK_VL8RE16_V 0xfff0707f -#define MATCH_VL8RE32_V 0xe2806007 -#define MASK_VL8RE32_V 0xfff0707f -#define MATCH_VL8RE64_V 0xe2807007 -#define MASK_VL8RE64_V 0xfff0707f -#define MATCH_VS1R_V 0x2800027 -#define MASK_VS1R_V 0xfff0707f -#define MATCH_VS2R_V 0x22800027 -#define MASK_VS2R_V 0xfff0707f -#define MATCH_VS4R_V 0x62800027 -#define MASK_VS4R_V 0xfff0707f -#define MATCH_VS8R_V 0xe2800027 -#define MASK_VS8R_V 0xfff0707f -#define MATCH_VFADD_VF 0x5057 -#define MASK_VFADD_VF 0xfc00707f -#define MATCH_VFSUB_VF 0x8005057 -#define MASK_VFSUB_VF 0xfc00707f -#define MATCH_VFMIN_VF 0x10005057 -#define MASK_VFMIN_VF 0xfc00707f -#define MATCH_VFMAX_VF 0x18005057 -#define MASK_VFMAX_VF 0xfc00707f -#define MATCH_VFSGNJ_VF 0x20005057 -#define MASK_VFSGNJ_VF 0xfc00707f -#define MATCH_VFSGNJN_VF 0x24005057 -#define MASK_VFSGNJN_VF 0xfc00707f -#define MATCH_VFSGNJX_VF 0x28005057 -#define MASK_VFSGNJX_VF 0xfc00707f -#define MATCH_VFSLIDE1UP_VF 0x38005057 -#define MASK_VFSLIDE1UP_VF 0xfc00707f -#define MATCH_VFSLIDE1DOWN_VF 0x3c005057 -#define MASK_VFSLIDE1DOWN_VF 0xfc00707f -#define MATCH_VFMV_S_F 0x42005057 -#define MASK_VFMV_S_F 0xfff0707f -#define MATCH_VFMERGE_VFM 0x5c005057 -#define MASK_VFMERGE_VFM 0xfe00707f -#define MATCH_VFMV_V_F 0x5e005057 -#define MASK_VFMV_V_F 0xfff0707f -#define MATCH_VMFEQ_VF 0x60005057 -#define MASK_VMFEQ_VF 0xfc00707f -#define MATCH_VMFLE_VF 0x64005057 -#define MASK_VMFLE_VF 0xfc00707f -#define MATCH_VMFLT_VF 0x6c005057 -#define MASK_VMFLT_VF 0xfc00707f -#define MATCH_VMFNE_VF 0x70005057 -#define MASK_VMFNE_VF 0xfc00707f -#define MATCH_VMFGT_VF 0x74005057 -#define MASK_VMFGT_VF 0xfc00707f -#define MATCH_VMFGE_VF 0x7c005057 -#define MASK_VMFGE_VF 0xfc00707f -#define MATCH_VFDIV_VF 0x80005057 -#define MASK_VFDIV_VF 0xfc00707f -#define MATCH_VFRDIV_VF 0x84005057 -#define MASK_VFRDIV_VF 0xfc00707f -#define MATCH_VFMUL_VF 0x90005057 -#define MASK_VFMUL_VF 0xfc00707f -#define MATCH_VFRSUB_VF 0x9c005057 -#define MASK_VFRSUB_VF 0xfc00707f -#define MATCH_VFMADD_VF 0xa0005057 -#define MASK_VFMADD_VF 0xfc00707f -#define MATCH_VFNMADD_VF 0xa4005057 -#define MASK_VFNMADD_VF 0xfc00707f -#define MATCH_VFMSUB_VF 0xa8005057 -#define MASK_VFMSUB_VF 0xfc00707f -#define MATCH_VFNMSUB_VF 0xac005057 -#define MASK_VFNMSUB_VF 0xfc00707f -#define MATCH_VFMACC_VF 0xb0005057 -#define MASK_VFMACC_VF 0xfc00707f -#define MATCH_VFNMACC_VF 0xb4005057 -#define MASK_VFNMACC_VF 0xfc00707f -#define MATCH_VFMSAC_VF 0xb8005057 -#define MASK_VFMSAC_VF 0xfc00707f -#define MATCH_VFNMSAC_VF 0xbc005057 -#define MASK_VFNMSAC_VF 0xfc00707f -#define MATCH_VFWADD_VF 0xc0005057 -#define MASK_VFWADD_VF 0xfc00707f -#define MATCH_VFWSUB_VF 0xc8005057 -#define MASK_VFWSUB_VF 0xfc00707f -#define MATCH_VFWADD_WF 0xd0005057 -#define MASK_VFWADD_WF 0xfc00707f -#define MATCH_VFWSUB_WF 0xd8005057 -#define MASK_VFWSUB_WF 0xfc00707f -#define MATCH_VFWMUL_VF 0xe0005057 -#define MASK_VFWMUL_VF 0xfc00707f -#define MATCH_VFWMACC_VF 0xf0005057 -#define MASK_VFWMACC_VF 0xfc00707f -#define MATCH_VFWNMACC_VF 0xf4005057 -#define MASK_VFWNMACC_VF 0xfc00707f -#define MATCH_VFWMSAC_VF 0xf8005057 -#define MASK_VFWMSAC_VF 0xfc00707f -#define MATCH_VFWNMSAC_VF 0xfc005057 -#define MASK_VFWNMSAC_VF 0xfc00707f -#define MATCH_VFADD_VV 0x1057 -#define MASK_VFADD_VV 0xfc00707f -#define MATCH_VFREDUSUM_VS 0x4001057 -#define MASK_VFREDUSUM_VS 0xfc00707f -#define MATCH_VFSUB_VV 0x8001057 -#define MASK_VFSUB_VV 0xfc00707f -#define MATCH_VFREDOSUM_VS 0xc001057 -#define MASK_VFREDOSUM_VS 0xfc00707f -#define MATCH_VFMIN_VV 0x10001057 -#define MASK_VFMIN_VV 0xfc00707f -#define MATCH_VFREDMIN_VS 0x14001057 -#define MASK_VFREDMIN_VS 0xfc00707f -#define MATCH_VFMAX_VV 0x18001057 -#define MASK_VFMAX_VV 0xfc00707f -#define MATCH_VFREDMAX_VS 0x1c001057 -#define MASK_VFREDMAX_VS 0xfc00707f -#define MATCH_VFSGNJ_VV 0x20001057 -#define MASK_VFSGNJ_VV 0xfc00707f -#define MATCH_VFSGNJN_VV 0x24001057 -#define MASK_VFSGNJN_VV 0xfc00707f -#define MATCH_VFSGNJX_VV 0x28001057 -#define MASK_VFSGNJX_VV 0xfc00707f -#define MATCH_VFMV_F_S 0x42001057 -#define MASK_VFMV_F_S 0xfe0ff07f -#define MATCH_VMFEQ_VV 0x60001057 -#define MASK_VMFEQ_VV 0xfc00707f -#define MATCH_VMFLE_VV 0x64001057 -#define MASK_VMFLE_VV 0xfc00707f -#define MATCH_VMFLT_VV 0x6c001057 -#define MASK_VMFLT_VV 0xfc00707f -#define MATCH_VMFNE_VV 0x70001057 -#define MASK_VMFNE_VV 0xfc00707f -#define MATCH_VFDIV_VV 0x80001057 -#define MASK_VFDIV_VV 0xfc00707f -#define MATCH_VFMUL_VV 0x90001057 -#define MASK_VFMUL_VV 0xfc00707f -#define MATCH_VFMADD_VV 0xa0001057 -#define MASK_VFMADD_VV 0xfc00707f -#define MATCH_VFNMADD_VV 0xa4001057 -#define MASK_VFNMADD_VV 0xfc00707f -#define MATCH_VFMSUB_VV 0xa8001057 -#define MASK_VFMSUB_VV 0xfc00707f -#define MATCH_VFNMSUB_VV 0xac001057 -#define MASK_VFNMSUB_VV 0xfc00707f -#define MATCH_VFMACC_VV 0xb0001057 -#define MASK_VFMACC_VV 0xfc00707f -#define MATCH_VFNMACC_VV 0xb4001057 -#define MASK_VFNMACC_VV 0xfc00707f -#define MATCH_VFMSAC_VV 0xb8001057 -#define MASK_VFMSAC_VV 0xfc00707f -#define MATCH_VFNMSAC_VV 0xbc001057 -#define MASK_VFNMSAC_VV 0xfc00707f -#define MATCH_VFCVT_XU_F_V 0x48001057 -#define MASK_VFCVT_XU_F_V 0xfc0ff07f -#define MATCH_VFCVT_X_F_V 0x48009057 -#define MASK_VFCVT_X_F_V 0xfc0ff07f -#define MATCH_VFCVT_F_XU_V 0x48011057 -#define MASK_VFCVT_F_XU_V 0xfc0ff07f -#define MATCH_VFCVT_F_X_V 0x48019057 -#define MASK_VFCVT_F_X_V 0xfc0ff07f -#define MATCH_VFCVT_RTZ_XU_F_V 0x48031057 -#define MASK_VFCVT_RTZ_XU_F_V 0xfc0ff07f -#define MATCH_VFCVT_RTZ_X_F_V 0x48039057 -#define MASK_VFCVT_RTZ_X_F_V 0xfc0ff07f -#define MATCH_VFWCVT_XU_F_V 0x48041057 -#define MASK_VFWCVT_XU_F_V 0xfc0ff07f -#define MATCH_VFWCVT_X_F_V 0x48049057 -#define MASK_VFWCVT_X_F_V 0xfc0ff07f -#define MATCH_VFWCVT_F_XU_V 0x48051057 -#define MASK_VFWCVT_F_XU_V 0xfc0ff07f -#define MATCH_VFWCVT_F_X_V 0x48059057 -#define MASK_VFWCVT_F_X_V 0xfc0ff07f -#define MATCH_VFWCVT_F_F_V 0x48061057 -#define MASK_VFWCVT_F_F_V 0xfc0ff07f -#define MATCH_VFWCVT_RTZ_XU_F_V 0x48071057 -#define MASK_VFWCVT_RTZ_XU_F_V 0xfc0ff07f -#define MATCH_VFWCVT_RTZ_X_F_V 0x48079057 -#define MASK_VFWCVT_RTZ_X_F_V 0xfc0ff07f -#define MATCH_VFNCVT_XU_F_W 0x48081057 -#define MASK_VFNCVT_XU_F_W 0xfc0ff07f -#define MATCH_VFNCVT_X_F_W 0x48089057 -#define MASK_VFNCVT_X_F_W 0xfc0ff07f -#define MATCH_VFNCVT_F_XU_W 0x48091057 -#define MASK_VFNCVT_F_XU_W 0xfc0ff07f -#define MATCH_VFNCVT_F_X_W 0x48099057 -#define MASK_VFNCVT_F_X_W 0xfc0ff07f -#define MATCH_VFNCVT_F_F_W 0x480a1057 -#define MASK_VFNCVT_F_F_W 0xfc0ff07f -#define MATCH_VFNCVT_ROD_F_F_W 0x480a9057 -#define MASK_VFNCVT_ROD_F_F_W 0xfc0ff07f -#define MATCH_VFNCVT_RTZ_XU_F_W 0x480b1057 -#define MASK_VFNCVT_RTZ_XU_F_W 0xfc0ff07f -#define MATCH_VFNCVT_RTZ_X_F_W 0x480b9057 -#define MASK_VFNCVT_RTZ_X_F_W 0xfc0ff07f -#define MATCH_VFSQRT_V 0x4c001057 -#define MASK_VFSQRT_V 0xfc0ff07f -#define MATCH_VFRSQRT7_V 0x4c021057 -#define MASK_VFRSQRT7_V 0xfc0ff07f -#define MATCH_VFREC7_V 0x4c029057 -#define MASK_VFREC7_V 0xfc0ff07f -#define MATCH_VFCLASS_V 0x4c081057 -#define MASK_VFCLASS_V 0xfc0ff07f -#define MATCH_VFWADD_VV 0xc0001057 -#define MASK_VFWADD_VV 0xfc00707f -#define MATCH_VFWREDUSUM_VS 0xc4001057 -#define MASK_VFWREDUSUM_VS 0xfc00707f -#define MATCH_VFWSUB_VV 0xc8001057 -#define MASK_VFWSUB_VV 0xfc00707f -#define MATCH_VFWREDOSUM_VS 0xcc001057 -#define MASK_VFWREDOSUM_VS 0xfc00707f -#define MATCH_VFWADD_WV 0xd0001057 -#define MASK_VFWADD_WV 0xfc00707f -#define MATCH_VFWSUB_WV 0xd8001057 -#define MASK_VFWSUB_WV 0xfc00707f -#define MATCH_VFWMUL_VV 0xe0001057 -#define MASK_VFWMUL_VV 0xfc00707f -#define MATCH_VFWMACC_VV 0xf0001057 -#define MASK_VFWMACC_VV 0xfc00707f -#define MATCH_VFWNMACC_VV 0xf4001057 -#define MASK_VFWNMACC_VV 0xfc00707f -#define MATCH_VFWMSAC_VV 0xf8001057 -#define MASK_VFWMSAC_VV 0xfc00707f -#define MATCH_VFWNMSAC_VV 0xfc001057 -#define MASK_VFWNMSAC_VV 0xfc00707f -#define MATCH_VADD_VX 0x4057 -#define MASK_VADD_VX 0xfc00707f -#define MATCH_VSUB_VX 0x8004057 -#define MASK_VSUB_VX 0xfc00707f -#define MATCH_VRSUB_VX 0xc004057 -#define MASK_VRSUB_VX 0xfc00707f -#define MATCH_VMINU_VX 0x10004057 -#define MASK_VMINU_VX 0xfc00707f -#define MATCH_VMIN_VX 0x14004057 -#define MASK_VMIN_VX 0xfc00707f -#define MATCH_VMAXU_VX 0x18004057 -#define MASK_VMAXU_VX 0xfc00707f -#define MATCH_VMAX_VX 0x1c004057 -#define MASK_VMAX_VX 0xfc00707f -#define MATCH_VAND_VX 0x24004057 -#define MASK_VAND_VX 0xfc00707f -#define MATCH_VOR_VX 0x28004057 -#define MASK_VOR_VX 0xfc00707f -#define MATCH_VXOR_VX 0x2c004057 -#define MASK_VXOR_VX 0xfc00707f -#define MATCH_VRGATHER_VX 0x30004057 -#define MASK_VRGATHER_VX 0xfc00707f -#define MATCH_VSLIDEUP_VX 0x38004057 -#define MASK_VSLIDEUP_VX 0xfc00707f -#define MATCH_VSLIDEDOWN_VX 0x3c004057 -#define MASK_VSLIDEDOWN_VX 0xfc00707f -#define MATCH_VADC_VXM 0x40004057 -#define MASK_VADC_VXM 0xfe00707f -#define MATCH_VMADC_VXM 0x44004057 -#define MASK_VMADC_VXM 0xfe00707f -#define MATCH_VMADC_VX 0x46004057 -#define MASK_VMADC_VX 0xfe00707f -#define MATCH_VSBC_VXM 0x48004057 -#define MASK_VSBC_VXM 0xfe00707f -#define MATCH_VMSBC_VXM 0x4c004057 -#define MASK_VMSBC_VXM 0xfe00707f -#define MATCH_VMSBC_VX 0x4e004057 -#define MASK_VMSBC_VX 0xfe00707f -#define MATCH_VMERGE_VXM 0x5c004057 -#define MASK_VMERGE_VXM 0xfe00707f -#define MATCH_VMV_V_X 0x5e004057 -#define MASK_VMV_V_X 0xfff0707f -#define MATCH_VMSEQ_VX 0x60004057 -#define MASK_VMSEQ_VX 0xfc00707f -#define MATCH_VMSNE_VX 0x64004057 -#define MASK_VMSNE_VX 0xfc00707f -#define MATCH_VMSLTU_VX 0x68004057 -#define MASK_VMSLTU_VX 0xfc00707f -#define MATCH_VMSLT_VX 0x6c004057 -#define MASK_VMSLT_VX 0xfc00707f -#define MATCH_VMSLEU_VX 0x70004057 -#define MASK_VMSLEU_VX 0xfc00707f -#define MATCH_VMSLE_VX 0x74004057 -#define MASK_VMSLE_VX 0xfc00707f -#define MATCH_VMSGTU_VX 0x78004057 -#define MASK_VMSGTU_VX 0xfc00707f -#define MATCH_VMSGT_VX 0x7c004057 -#define MASK_VMSGT_VX 0xfc00707f -#define MATCH_VSADDU_VX 0x80004057 -#define MASK_VSADDU_VX 0xfc00707f -#define MATCH_VSADD_VX 0x84004057 -#define MASK_VSADD_VX 0xfc00707f -#define MATCH_VSSUBU_VX 0x88004057 -#define MASK_VSSUBU_VX 0xfc00707f -#define MATCH_VSSUB_VX 0x8c004057 -#define MASK_VSSUB_VX 0xfc00707f -#define MATCH_VSLL_VX 0x94004057 -#define MASK_VSLL_VX 0xfc00707f -#define MATCH_VSMUL_VX 0x9c004057 -#define MASK_VSMUL_VX 0xfc00707f -#define MATCH_VSRL_VX 0xa0004057 -#define MASK_VSRL_VX 0xfc00707f -#define MATCH_VSRA_VX 0xa4004057 -#define MASK_VSRA_VX 0xfc00707f -#define MATCH_VSSRL_VX 0xa8004057 -#define MASK_VSSRL_VX 0xfc00707f -#define MATCH_VSSRA_VX 0xac004057 -#define MASK_VSSRA_VX 0xfc00707f -#define MATCH_VNSRL_WX 0xb0004057 -#define MASK_VNSRL_WX 0xfc00707f -#define MATCH_VNSRA_WX 0xb4004057 -#define MASK_VNSRA_WX 0xfc00707f -#define MATCH_VNCLIPU_WX 0xb8004057 -#define MASK_VNCLIPU_WX 0xfc00707f -#define MATCH_VNCLIP_WX 0xbc004057 -#define MASK_VNCLIP_WX 0xfc00707f -#define MATCH_VADD_VV 0x57 -#define MASK_VADD_VV 0xfc00707f -#define MATCH_VSUB_VV 0x8000057 -#define MASK_VSUB_VV 0xfc00707f -#define MATCH_VMINU_VV 0x10000057 -#define MASK_VMINU_VV 0xfc00707f -#define MATCH_VMIN_VV 0x14000057 -#define MASK_VMIN_VV 0xfc00707f -#define MATCH_VMAXU_VV 0x18000057 -#define MASK_VMAXU_VV 0xfc00707f -#define MATCH_VMAX_VV 0x1c000057 -#define MASK_VMAX_VV 0xfc00707f -#define MATCH_VAND_VV 0x24000057 -#define MASK_VAND_VV 0xfc00707f -#define MATCH_VOR_VV 0x28000057 -#define MASK_VOR_VV 0xfc00707f -#define MATCH_VXOR_VV 0x2c000057 -#define MASK_VXOR_VV 0xfc00707f -#define MATCH_VRGATHER_VV 0x30000057 -#define MASK_VRGATHER_VV 0xfc00707f -#define MATCH_VRGATHEREI16_VV 0x38000057 -#define MASK_VRGATHEREI16_VV 0xfc00707f -#define MATCH_VADC_VVM 0x40000057 -#define MASK_VADC_VVM 0xfe00707f -#define MATCH_VMADC_VVM 0x44000057 -#define MASK_VMADC_VVM 0xfe00707f -#define MATCH_VMADC_VV 0x46000057 -#define MASK_VMADC_VV 0xfe00707f -#define MATCH_VSBC_VVM 0x48000057 -#define MASK_VSBC_VVM 0xfe00707f -#define MATCH_VMSBC_VVM 0x4c000057 -#define MASK_VMSBC_VVM 0xfe00707f -#define MATCH_VMSBC_VV 0x4e000057 -#define MASK_VMSBC_VV 0xfe00707f -#define MATCH_VMERGE_VVM 0x5c000057 -#define MASK_VMERGE_VVM 0xfe00707f -#define MATCH_VMV_V_V 0x5e000057 -#define MASK_VMV_V_V 0xfff0707f -#define MATCH_VMSEQ_VV 0x60000057 -#define MASK_VMSEQ_VV 0xfc00707f -#define MATCH_VMSNE_VV 0x64000057 -#define MASK_VMSNE_VV 0xfc00707f -#define MATCH_VMSLTU_VV 0x68000057 -#define MASK_VMSLTU_VV 0xfc00707f -#define MATCH_VMSLT_VV 0x6c000057 -#define MASK_VMSLT_VV 0xfc00707f -#define MATCH_VMSLEU_VV 0x70000057 -#define MASK_VMSLEU_VV 0xfc00707f -#define MATCH_VMSLE_VV 0x74000057 -#define MASK_VMSLE_VV 0xfc00707f -#define MATCH_VSADDU_VV 0x80000057 -#define MASK_VSADDU_VV 0xfc00707f -#define MATCH_VSADD_VV 0x84000057 -#define MASK_VSADD_VV 0xfc00707f -#define MATCH_VSSUBU_VV 0x88000057 -#define MASK_VSSUBU_VV 0xfc00707f -#define MATCH_VSSUB_VV 0x8c000057 -#define MASK_VSSUB_VV 0xfc00707f -#define MATCH_VSLL_VV 0x94000057 -#define MASK_VSLL_VV 0xfc00707f -#define MATCH_VSMUL_VV 0x9c000057 -#define MASK_VSMUL_VV 0xfc00707f -#define MATCH_VSRL_VV 0xa0000057 -#define MASK_VSRL_VV 0xfc00707f -#define MATCH_VSRA_VV 0xa4000057 -#define MASK_VSRA_VV 0xfc00707f -#define MATCH_VSSRL_VV 0xa8000057 -#define MASK_VSSRL_VV 0xfc00707f -#define MATCH_VSSRA_VV 0xac000057 -#define MASK_VSSRA_VV 0xfc00707f -#define MATCH_VNSRL_WV 0xb0000057 -#define MASK_VNSRL_WV 0xfc00707f -#define MATCH_VNSRA_WV 0xb4000057 -#define MASK_VNSRA_WV 0xfc00707f -#define MATCH_VNCLIPU_WV 0xb8000057 -#define MASK_VNCLIPU_WV 0xfc00707f -#define MATCH_VNCLIP_WV 0xbc000057 -#define MASK_VNCLIP_WV 0xfc00707f -#define MATCH_VWREDSUMU_VS 0xc0000057 -#define MASK_VWREDSUMU_VS 0xfc00707f -#define MATCH_VWREDSUM_VS 0xc4000057 -#define MASK_VWREDSUM_VS 0xfc00707f -#define MATCH_VADD_VI 0x3057 -#define MASK_VADD_VI 0xfc00707f -#define MATCH_VRSUB_VI 0xc003057 -#define MASK_VRSUB_VI 0xfc00707f -#define MATCH_VAND_VI 0x24003057 -#define MASK_VAND_VI 0xfc00707f -#define MATCH_VOR_VI 0x28003057 -#define MASK_VOR_VI 0xfc00707f -#define MATCH_VXOR_VI 0x2c003057 -#define MASK_VXOR_VI 0xfc00707f -#define MATCH_VRGATHER_VI 0x30003057 -#define MASK_VRGATHER_VI 0xfc00707f -#define MATCH_VSLIDEUP_VI 0x38003057 -#define MASK_VSLIDEUP_VI 0xfc00707f -#define MATCH_VSLIDEDOWN_VI 0x3c003057 -#define MASK_VSLIDEDOWN_VI 0xfc00707f -#define MATCH_VADC_VIM 0x40003057 -#define MASK_VADC_VIM 0xfe00707f -#define MATCH_VMADC_VIM 0x44003057 -#define MASK_VMADC_VIM 0xfe00707f -#define MATCH_VMADC_VI 0x46003057 -#define MASK_VMADC_VI 0xfe00707f -#define MATCH_VMERGE_VIM 0x5c003057 -#define MASK_VMERGE_VIM 0xfe00707f -#define MATCH_VMV_V_I 0x5e003057 -#define MASK_VMV_V_I 0xfff0707f -#define MATCH_VMSEQ_VI 0x60003057 -#define MASK_VMSEQ_VI 0xfc00707f -#define MATCH_VMSNE_VI 0x64003057 -#define MASK_VMSNE_VI 0xfc00707f -#define MATCH_VMSLEU_VI 0x70003057 -#define MASK_VMSLEU_VI 0xfc00707f -#define MATCH_VMSLE_VI 0x74003057 -#define MASK_VMSLE_VI 0xfc00707f -#define MATCH_VMSGTU_VI 0x78003057 -#define MASK_VMSGTU_VI 0xfc00707f -#define MATCH_VMSGT_VI 0x7c003057 -#define MASK_VMSGT_VI 0xfc00707f -#define MATCH_VSADDU_VI 0x80003057 -#define MASK_VSADDU_VI 0xfc00707f -#define MATCH_VSADD_VI 0x84003057 -#define MASK_VSADD_VI 0xfc00707f -#define MATCH_VSLL_VI 0x94003057 -#define MASK_VSLL_VI 0xfc00707f -#define MATCH_VMV1R_V 0x9e003057 -#define MASK_VMV1R_V 0xfe0ff07f -#define MATCH_VMV2R_V 0x9e00b057 -#define MASK_VMV2R_V 0xfe0ff07f -#define MATCH_VMV4R_V 0x9e01b057 -#define MASK_VMV4R_V 0xfe0ff07f -#define MATCH_VMV8R_V 0x9e03b057 -#define MASK_VMV8R_V 0xfe0ff07f -#define MATCH_VSRL_VI 0xa0003057 -#define MASK_VSRL_VI 0xfc00707f -#define MATCH_VSRA_VI 0xa4003057 -#define MASK_VSRA_VI 0xfc00707f -#define MATCH_VSSRL_VI 0xa8003057 -#define MASK_VSSRL_VI 0xfc00707f -#define MATCH_VSSRA_VI 0xac003057 -#define MASK_VSSRA_VI 0xfc00707f -#define MATCH_VNSRL_WI 0xb0003057 -#define MASK_VNSRL_WI 0xfc00707f -#define MATCH_VNSRA_WI 0xb4003057 -#define MASK_VNSRA_WI 0xfc00707f -#define MATCH_VNCLIPU_WI 0xb8003057 -#define MASK_VNCLIPU_WI 0xfc00707f -#define MATCH_VNCLIP_WI 0xbc003057 -#define MASK_VNCLIP_WI 0xfc00707f -#define MATCH_VREDSUM_VS 0x2057 -#define MASK_VREDSUM_VS 0xfc00707f -#define MATCH_VREDAND_VS 0x4002057 -#define MASK_VREDAND_VS 0xfc00707f -#define MATCH_VREDOR_VS 0x8002057 -#define MASK_VREDOR_VS 0xfc00707f -#define MATCH_VREDXOR_VS 0xc002057 -#define MASK_VREDXOR_VS 0xfc00707f -#define MATCH_VREDMINU_VS 0x10002057 -#define MASK_VREDMINU_VS 0xfc00707f -#define MATCH_VREDMIN_VS 0x14002057 -#define MASK_VREDMIN_VS 0xfc00707f -#define MATCH_VREDMAXU_VS 0x18002057 -#define MASK_VREDMAXU_VS 0xfc00707f -#define MATCH_VREDMAX_VS 0x1c002057 -#define MASK_VREDMAX_VS 0xfc00707f -#define MATCH_VAADDU_VV 0x20002057 -#define MASK_VAADDU_VV 0xfc00707f -#define MATCH_VAADD_VV 0x24002057 -#define MASK_VAADD_VV 0xfc00707f -#define MATCH_VASUBU_VV 0x28002057 -#define MASK_VASUBU_VV 0xfc00707f -#define MATCH_VASUB_VV 0x2c002057 -#define MASK_VASUB_VV 0xfc00707f -#define MATCH_VMV_X_S 0x42002057 -#define MASK_VMV_X_S 0xfe0ff07f -#define MATCH_VZEXT_VF8 0x48012057 -#define MASK_VZEXT_VF8 0xfc0ff07f -#define MATCH_VSEXT_VF8 0x4801a057 -#define MASK_VSEXT_VF8 0xfc0ff07f -#define MATCH_VZEXT_VF4 0x48022057 -#define MASK_VZEXT_VF4 0xfc0ff07f -#define MATCH_VSEXT_VF4 0x4802a057 -#define MASK_VSEXT_VF4 0xfc0ff07f -#define MATCH_VZEXT_VF2 0x48032057 -#define MASK_VZEXT_VF2 0xfc0ff07f -#define MATCH_VSEXT_VF2 0x4803a057 -#define MASK_VSEXT_VF2 0xfc0ff07f -#define MATCH_VCOMPRESS_VM 0x5e002057 -#define MASK_VCOMPRESS_VM 0xfe00707f -#define MATCH_VMANDNOT_MM 0x60002057 -#define MASK_VMANDNOT_MM 0xfc00707f -#define MATCH_VMAND_MM 0x64002057 -#define MASK_VMAND_MM 0xfc00707f -#define MATCH_VMOR_MM 0x68002057 -#define MASK_VMOR_MM 0xfc00707f -#define MATCH_VMXOR_MM 0x6c002057 -#define MASK_VMXOR_MM 0xfc00707f -#define MATCH_VMORNOT_MM 0x70002057 -#define MASK_VMORNOT_MM 0xfc00707f -#define MATCH_VMNAND_MM 0x74002057 -#define MASK_VMNAND_MM 0xfc00707f -#define MATCH_VMNOR_MM 0x78002057 -#define MASK_VMNOR_MM 0xfc00707f -#define MATCH_VMXNOR_MM 0x7c002057 -#define MASK_VMXNOR_MM 0xfc00707f -#define MATCH_VMSBF_M 0x5000a057 -#define MASK_VMSBF_M 0xfc0ff07f -#define MATCH_VMSOF_M 0x50012057 -#define MASK_VMSOF_M 0xfc0ff07f -#define MATCH_VMSIF_M 0x5001a057 -#define MASK_VMSIF_M 0xfc0ff07f -#define MATCH_VIOTA_M 0x50082057 -#define MASK_VIOTA_M 0xfc0ff07f -#define MATCH_VID_V 0x5008a057 -#define MASK_VID_V 0xfdfff07f -#define MATCH_VCPOP_M 0x40082057 -#define MASK_VCPOP_M 0xfc0ff07f -#define MATCH_VFIRST_M 0x4008a057 -#define MASK_VFIRST_M 0xfc0ff07f -#define MATCH_VDIVU_VV 0x80002057 -#define MASK_VDIVU_VV 0xfc00707f -#define MATCH_VDIV_VV 0x84002057 -#define MASK_VDIV_VV 0xfc00707f -#define MATCH_VREMU_VV 0x88002057 -#define MASK_VREMU_VV 0xfc00707f -#define MATCH_VREM_VV 0x8c002057 -#define MASK_VREM_VV 0xfc00707f -#define MATCH_VMULHU_VV 0x90002057 -#define MASK_VMULHU_VV 0xfc00707f -#define MATCH_VMUL_VV 0x94002057 -#define MASK_VMUL_VV 0xfc00707f -#define MATCH_VMULHSU_VV 0x98002057 -#define MASK_VMULHSU_VV 0xfc00707f -#define MATCH_VMULH_VV 0x9c002057 -#define MASK_VMULH_VV 0xfc00707f -#define MATCH_VMADD_VV 0xa4002057 -#define MASK_VMADD_VV 0xfc00707f -#define MATCH_VNMSUB_VV 0xac002057 -#define MASK_VNMSUB_VV 0xfc00707f -#define MATCH_VMACC_VV 0xb4002057 -#define MASK_VMACC_VV 0xfc00707f -#define MATCH_VNMSAC_VV 0xbc002057 -#define MASK_VNMSAC_VV 0xfc00707f -#define MATCH_VWADDU_VV 0xc0002057 -#define MASK_VWADDU_VV 0xfc00707f -#define MATCH_VWADD_VV 0xc4002057 -#define MASK_VWADD_VV 0xfc00707f -#define MATCH_VWSUBU_VV 0xc8002057 -#define MASK_VWSUBU_VV 0xfc00707f -#define MATCH_VWSUB_VV 0xcc002057 -#define MASK_VWSUB_VV 0xfc00707f -#define MATCH_VWADDU_WV 0xd0002057 -#define MASK_VWADDU_WV 0xfc00707f -#define MATCH_VWADD_WV 0xd4002057 -#define MASK_VWADD_WV 0xfc00707f -#define MATCH_VWSUBU_WV 0xd8002057 -#define MASK_VWSUBU_WV 0xfc00707f -#define MATCH_VWSUB_WV 0xdc002057 -#define MASK_VWSUB_WV 0xfc00707f -#define MATCH_VWMULU_VV 0xe0002057 -#define MASK_VWMULU_VV 0xfc00707f -#define MATCH_VWMULSU_VV 0xe8002057 -#define MASK_VWMULSU_VV 0xfc00707f -#define MATCH_VWMUL_VV 0xec002057 -#define MASK_VWMUL_VV 0xfc00707f -#define MATCH_VWMACCU_VV 0xf0002057 -#define MASK_VWMACCU_VV 0xfc00707f -#define MATCH_VWMACC_VV 0xf4002057 -#define MASK_VWMACC_VV 0xfc00707f -#define MATCH_VWMACCSU_VV 0xfc002057 -#define MASK_VWMACCSU_VV 0xfc00707f -#define MATCH_VAADDU_VX 0x20006057 -#define MASK_VAADDU_VX 0xfc00707f -#define MATCH_VAADD_VX 0x24006057 -#define MASK_VAADD_VX 0xfc00707f -#define MATCH_VASUBU_VX 0x28006057 -#define MASK_VASUBU_VX 0xfc00707f -#define MATCH_VASUB_VX 0x2c006057 -#define MASK_VASUB_VX 0xfc00707f -#define MATCH_VMV_S_X 0x42006057 -#define MASK_VMV_S_X 0xfff0707f -#define MATCH_VSLIDE1UP_VX 0x38006057 -#define MASK_VSLIDE1UP_VX 0xfc00707f -#define MATCH_VSLIDE1DOWN_VX 0x3c006057 -#define MASK_VSLIDE1DOWN_VX 0xfc00707f -#define MATCH_VDIVU_VX 0x80006057 -#define MASK_VDIVU_VX 0xfc00707f -#define MATCH_VDIV_VX 0x84006057 -#define MASK_VDIV_VX 0xfc00707f -#define MATCH_VREMU_VX 0x88006057 -#define MASK_VREMU_VX 0xfc00707f -#define MATCH_VREM_VX 0x8c006057 -#define MASK_VREM_VX 0xfc00707f -#define MATCH_VMULHU_VX 0x90006057 -#define MASK_VMULHU_VX 0xfc00707f -#define MATCH_VMUL_VX 0x94006057 -#define MASK_VMUL_VX 0xfc00707f -#define MATCH_VMULHSU_VX 0x98006057 -#define MASK_VMULHSU_VX 0xfc00707f -#define MATCH_VMULH_VX 0x9c006057 -#define MASK_VMULH_VX 0xfc00707f -#define MATCH_VMADD_VX 0xa4006057 -#define MASK_VMADD_VX 0xfc00707f -#define MATCH_VNMSUB_VX 0xac006057 -#define MASK_VNMSUB_VX 0xfc00707f -#define MATCH_VMACC_VX 0xb4006057 -#define MASK_VMACC_VX 0xfc00707f -#define MATCH_VNMSAC_VX 0xbc006057 -#define MASK_VNMSAC_VX 0xfc00707f -#define MATCH_VWADDU_VX 0xc0006057 -#define MASK_VWADDU_VX 0xfc00707f -#define MATCH_VWADD_VX 0xc4006057 -#define MASK_VWADD_VX 0xfc00707f -#define MATCH_VWSUBU_VX 0xc8006057 -#define MASK_VWSUBU_VX 0xfc00707f -#define MATCH_VWSUB_VX 0xcc006057 -#define MASK_VWSUB_VX 0xfc00707f -#define MATCH_VWADDU_WX 0xd0006057 -#define MASK_VWADDU_WX 0xfc00707f -#define MATCH_VWADD_WX 0xd4006057 -#define MASK_VWADD_WX 0xfc00707f -#define MATCH_VWSUBU_WX 0xd8006057 -#define MASK_VWSUBU_WX 0xfc00707f -#define MATCH_VWSUB_WX 0xdc006057 -#define MASK_VWSUB_WX 0xfc00707f -#define MATCH_VWMULU_VX 0xe0006057 -#define MASK_VWMULU_VX 0xfc00707f -#define MATCH_VWMULSU_VX 0xe8006057 -#define MASK_VWMULSU_VX 0xfc00707f -#define MATCH_VWMUL_VX 0xec006057 -#define MASK_VWMUL_VX 0xfc00707f -#define MATCH_VWMACCU_VX 0xf0006057 -#define MASK_VWMACCU_VX 0xfc00707f -#define MATCH_VWMACC_VX 0xf4006057 -#define MASK_VWMACC_VX 0xfc00707f -#define MATCH_VWMACCUS_VX 0xf8006057 -#define MASK_VWMACCUS_VX 0xfc00707f -#define MATCH_VWMACCSU_VX 0xfc006057 -#define MASK_VWMACCSU_VX 0xfc00707f -#define MATCH_VAMOSWAPEI8_V 0x800002f -#define MASK_VAMOSWAPEI8_V 0xf800707f -#define MATCH_VAMOADDEI8_V 0x2f -#define MASK_VAMOADDEI8_V 0xf800707f -#define MATCH_VAMOXOREI8_V 0x2000002f -#define MASK_VAMOXOREI8_V 0xf800707f -#define MATCH_VAMOANDEI8_V 0x6000002f -#define MASK_VAMOANDEI8_V 0xf800707f -#define MATCH_VAMOOREI8_V 0x4000002f -#define MASK_VAMOOREI8_V 0xf800707f -#define MATCH_VAMOMINEI8_V 0x8000002f -#define MASK_VAMOMINEI8_V 0xf800707f -#define MATCH_VAMOMAXEI8_V 0xa000002f -#define MASK_VAMOMAXEI8_V 0xf800707f -#define MATCH_VAMOMINUEI8_V 0xc000002f -#define MASK_VAMOMINUEI8_V 0xf800707f -#define MATCH_VAMOMAXUEI8_V 0xe000002f -#define MASK_VAMOMAXUEI8_V 0xf800707f -#define MATCH_VAMOSWAPEI16_V 0x800502f -#define MASK_VAMOSWAPEI16_V 0xf800707f -#define MATCH_VAMOADDEI16_V 0x502f -#define MASK_VAMOADDEI16_V 0xf800707f -#define MATCH_VAMOXOREI16_V 0x2000502f -#define MASK_VAMOXOREI16_V 0xf800707f -#define MATCH_VAMOANDEI16_V 0x6000502f -#define MASK_VAMOANDEI16_V 0xf800707f -#define MATCH_VAMOOREI16_V 0x4000502f -#define MASK_VAMOOREI16_V 0xf800707f -#define MATCH_VAMOMINEI16_V 0x8000502f -#define MASK_VAMOMINEI16_V 0xf800707f -#define MATCH_VAMOMAXEI16_V 0xa000502f -#define MASK_VAMOMAXEI16_V 0xf800707f -#define MATCH_VAMOMINUEI16_V 0xc000502f -#define MASK_VAMOMINUEI16_V 0xf800707f -#define MATCH_VAMOMAXUEI16_V 0xe000502f -#define MASK_VAMOMAXUEI16_V 0xf800707f -#define MATCH_VAMOSWAPEI32_V 0x800602f -#define MASK_VAMOSWAPEI32_V 0xf800707f -#define MATCH_VAMOADDEI32_V 0x602f -#define MASK_VAMOADDEI32_V 0xf800707f -#define MATCH_VAMOXOREI32_V 0x2000602f -#define MASK_VAMOXOREI32_V 0xf800707f -#define MATCH_VAMOANDEI32_V 0x6000602f -#define MASK_VAMOANDEI32_V 0xf800707f -#define MATCH_VAMOOREI32_V 0x4000602f -#define MASK_VAMOOREI32_V 0xf800707f -#define MATCH_VAMOMINEI32_V 0x8000602f -#define MASK_VAMOMINEI32_V 0xf800707f -#define MATCH_VAMOMAXEI32_V 0xa000602f -#define MASK_VAMOMAXEI32_V 0xf800707f -#define MATCH_VAMOMINUEI32_V 0xc000602f -#define MASK_VAMOMINUEI32_V 0xf800707f -#define MATCH_VAMOMAXUEI32_V 0xe000602f -#define MASK_VAMOMAXUEI32_V 0xf800707f -#define MATCH_VAMOSWAPEI64_V 0x800702f -#define MASK_VAMOSWAPEI64_V 0xf800707f -#define MATCH_VAMOADDEI64_V 0x702f -#define MASK_VAMOADDEI64_V 0xf800707f -#define MATCH_VAMOXOREI64_V 0x2000702f -#define MASK_VAMOXOREI64_V 0xf800707f -#define MATCH_VAMOANDEI64_V 0x6000702f -#define MASK_VAMOANDEI64_V 0xf800707f -#define MATCH_VAMOOREI64_V 0x4000702f -#define MASK_VAMOOREI64_V 0xf800707f -#define MATCH_VAMOMINEI64_V 0x8000702f -#define MASK_VAMOMINEI64_V 0xf800707f -#define MATCH_VAMOMAXEI64_V 0xa000702f -#define MASK_VAMOMAXEI64_V 0xf800707f -#define MATCH_VAMOMINUEI64_V 0xc000702f -#define MASK_VAMOMINUEI64_V 0xf800707f -#define MATCH_VAMOMAXUEI64_V 0xe000702f -#define MASK_VAMOMAXUEI64_V 0xf800707f -#define MATCH_ADD8 0x48000077 -#define MASK_ADD8 0xfe00707f -#define MATCH_ADD16 0x40000077 -#define MASK_ADD16 0xfe00707f -#define MATCH_ADD64 0xc0001077 -#define MASK_ADD64 0xfe00707f -#define MATCH_AVE 0xe0000077 -#define MASK_AVE 0xfe00707f -#define MATCH_BITREV 0xe6000077 -#define MASK_BITREV 0xfe00707f -#define MATCH_BITREVI 0xe8000077 -#define MASK_BITREVI 0xfc00707f -#define MATCH_BPICK 0x3077 -#define MASK_BPICK 0x600707f -#define MATCH_CLRS8 0xae000077 -#define MASK_CLRS8 0xfff0707f -#define MATCH_CLRS16 0xae800077 -#define MASK_CLRS16 0xfff0707f -#define MATCH_CLRS32 0xaf800077 -#define MASK_CLRS32 0xfff0707f -#define MATCH_CLO8 0xae300077 -#define MASK_CLO8 0xfff0707f -#define MATCH_CLO16 0xaeb00077 -#define MASK_CLO16 0xfff0707f -#define MATCH_CLO32 0xafb00077 -#define MASK_CLO32 0xfff0707f -#define MATCH_CLZ8 0xae100077 -#define MASK_CLZ8 0xfff0707f -#define MATCH_CLZ16 0xae900077 -#define MASK_CLZ16 0xfff0707f -#define MATCH_CLZ32 0xaf900077 -#define MASK_CLZ32 0xfff0707f -#define MATCH_CMPEQ8 0x4e000077 -#define MASK_CMPEQ8 0xfe00707f -#define MATCH_CMPEQ16 0x4c000077 -#define MASK_CMPEQ16 0xfe00707f -#define MATCH_CRAS16 0x44000077 -#define MASK_CRAS16 0xfe00707f -#define MATCH_CRSA16 0x46000077 -#define MASK_CRSA16 0xfe00707f -#define MATCH_INSB 0xac000077 -#define MASK_INSB 0xff80707f -#define MATCH_KABS8 0xad000077 -#define MASK_KABS8 0xfff0707f -#define MATCH_KABS16 0xad100077 -#define MASK_KABS16 0xfff0707f -#define MATCH_KABSW 0xad400077 -#define MASK_KABSW 0xfff0707f -#define MATCH_KADD8 0x18000077 -#define MASK_KADD8 0xfe00707f -#define MATCH_KADD16 0x10000077 -#define MASK_KADD16 0xfe00707f -#define MATCH_KADD64 0x90001077 -#define MASK_KADD64 0xfe00707f -#define MATCH_KADDH 0x4001077 -#define MASK_KADDH 0xfe00707f -#define MATCH_KADDW 0x1077 -#define MASK_KADDW 0xfe00707f -#define MATCH_KCRAS16 0x14000077 -#define MASK_KCRAS16 0xfe00707f -#define MATCH_KCRSA16 0x16000077 -#define MASK_KCRSA16 0xfe00707f -#define MATCH_KDMBB 0xa001077 -#define MASK_KDMBB 0xfe00707f -#define MATCH_KDMBT 0x1a001077 -#define MASK_KDMBT 0xfe00707f -#define MATCH_KDMTT 0x2a001077 -#define MASK_KDMTT 0xfe00707f -#define MATCH_KDMABB 0xd2001077 -#define MASK_KDMABB 0xfe00707f -#define MATCH_KDMABT 0xe2001077 -#define MASK_KDMABT 0xfe00707f -#define MATCH_KDMATT 0xf2001077 -#define MASK_KDMATT 0xfe00707f -#define MATCH_KHM8 0x8e000077 -#define MASK_KHM8 0xfe00707f -#define MATCH_KHMX8 0x9e000077 -#define MASK_KHMX8 0xfe00707f -#define MATCH_KHM16 0x86000077 -#define MASK_KHM16 0xfe00707f -#define MATCH_KHMX16 0x96000077 -#define MASK_KHMX16 0xfe00707f -#define MATCH_KHMBB 0xc001077 -#define MASK_KHMBB 0xfe00707f -#define MATCH_KHMBT 0x1c001077 -#define MASK_KHMBT 0xfe00707f -#define MATCH_KHMTT 0x2c001077 -#define MASK_KHMTT 0xfe00707f -#define MATCH_KMABB 0x5a001077 -#define MASK_KMABB 0xfe00707f -#define MATCH_KMABT 0x6a001077 -#define MASK_KMABT 0xfe00707f -#define MATCH_KMATT 0x7a001077 -#define MASK_KMATT 0xfe00707f -#define MATCH_KMADA 0x48001077 -#define MASK_KMADA 0xfe00707f -#define MATCH_KMAXDA 0x4a001077 -#define MASK_KMAXDA 0xfe00707f -#define MATCH_KMADS 0x5c001077 -#define MASK_KMADS 0xfe00707f -#define MATCH_KMADRS 0x6c001077 -#define MASK_KMADRS 0xfe00707f -#define MATCH_KMAXDS 0x7c001077 -#define MASK_KMAXDS 0xfe00707f -#define MATCH_KMAR64 0x94001077 -#define MASK_KMAR64 0xfe00707f -#define MATCH_KMDA 0x38001077 -#define MASK_KMDA 0xfe00707f -#define MATCH_KMXDA 0x3a001077 -#define MASK_KMXDA 0xfe00707f -#define MATCH_KMMAC 0x60001077 -#define MASK_KMMAC 0xfe00707f -#define MATCH_KMMAC_U 0x70001077 -#define MASK_KMMAC_U 0xfe00707f -#define MATCH_KMMAWB 0x46001077 -#define MASK_KMMAWB 0xfe00707f -#define MATCH_KMMAWB_U 0x56001077 -#define MASK_KMMAWB_U 0xfe00707f -#define MATCH_KMMAWB2 0xce001077 -#define MASK_KMMAWB2 0xfe00707f -#define MATCH_KMMAWB2_U 0xde001077 -#define MASK_KMMAWB2_U 0xfe00707f -#define MATCH_KMMAWT 0x66001077 -#define MASK_KMMAWT 0xfe00707f -#define MATCH_KMMAWT_U 0x76001077 -#define MASK_KMMAWT_U 0xfe00707f -#define MATCH_KMMAWT2 0xee001077 -#define MASK_KMMAWT2 0xfe00707f -#define MATCH_KMMAWT2_U 0xfe001077 -#define MASK_KMMAWT2_U 0xfe00707f -#define MATCH_KMMSB 0x42001077 -#define MASK_KMMSB 0xfe00707f -#define MATCH_KMMSB_U 0x52001077 -#define MASK_KMMSB_U 0xfe00707f -#define MATCH_KMMWB2 0x8e001077 -#define MASK_KMMWB2 0xfe00707f -#define MATCH_KMMWB2_U 0x9e001077 -#define MASK_KMMWB2_U 0xfe00707f -#define MATCH_KMMWT2 0xae001077 -#define MASK_KMMWT2 0xfe00707f -#define MATCH_KMMWT2_U 0xbe001077 -#define MASK_KMMWT2_U 0xfe00707f -#define MATCH_KMSDA 0x4c001077 -#define MASK_KMSDA 0xfe00707f -#define MATCH_KMSXDA 0x4e001077 -#define MASK_KMSXDA 0xfe00707f -#define MATCH_KMSR64 0x96001077 -#define MASK_KMSR64 0xfe00707f -#define MATCH_KSLLW 0x26001077 -#define MASK_KSLLW 0xfe00707f -#define MATCH_KSLLIW 0x36001077 -#define MASK_KSLLIW 0xfe00707f -#define MATCH_KSLL8 0x6c000077 -#define MASK_KSLL8 0xfe00707f -#define MATCH_KSLLI8 0x7c800077 -#define MASK_KSLLI8 0xff80707f -#define MATCH_KSLL16 0x64000077 -#define MASK_KSLL16 0xfe00707f -#define MATCH_KSLLI16 0x75000077 -#define MASK_KSLLI16 0xff00707f -#define MATCH_KSLRA8 0x5e000077 -#define MASK_KSLRA8 0xfe00707f -#define MATCH_KSLRA8_U 0x6e000077 -#define MASK_KSLRA8_U 0xfe00707f -#define MATCH_KSLRA16 0x56000077 -#define MASK_KSLRA16 0xfe00707f -#define MATCH_KSLRA16_U 0x66000077 -#define MASK_KSLRA16_U 0xfe00707f -#define MATCH_KSLRAW 0x6e001077 -#define MASK_KSLRAW 0xfe00707f -#define MATCH_KSLRAW_U 0x7e001077 -#define MASK_KSLRAW_U 0xfe00707f -#define MATCH_KSTAS16 0xc4002077 -#define MASK_KSTAS16 0xfe00707f -#define MATCH_KSTSA16 0xc6002077 -#define MASK_KSTSA16 0xfe00707f -#define MATCH_KSUB8 0x1a000077 -#define MASK_KSUB8 0xfe00707f -#define MATCH_KSUB16 0x12000077 -#define MASK_KSUB16 0xfe00707f -#define MATCH_KSUB64 0x92001077 -#define MASK_KSUB64 0xfe00707f -#define MATCH_KSUBH 0x6001077 -#define MASK_KSUBH 0xfe00707f -#define MATCH_KSUBW 0x2001077 -#define MASK_KSUBW 0xfe00707f -#define MATCH_KWMMUL 0x62001077 -#define MASK_KWMMUL 0xfe00707f -#define MATCH_KWMMUL_U 0x72001077 -#define MASK_KWMMUL_U 0xfe00707f -#define MATCH_MADDR32 0xc4001077 -#define MASK_MADDR32 0xfe00707f -#define MATCH_MAXW 0xf2000077 -#define MASK_MAXW 0xfe00707f -#define MATCH_MINW 0xf0000077 -#define MASK_MINW 0xfe00707f -#define MATCH_MSUBR32 0xc6001077 -#define MASK_MSUBR32 0xfe00707f -#define MATCH_MULR64 0xf0001077 -#define MASK_MULR64 0xfe00707f -#define MATCH_MULSR64 0xe0001077 -#define MASK_MULSR64 0xfe00707f -#define MATCH_PBSAD 0xfc000077 -#define MASK_PBSAD 0xfe00707f -#define MATCH_PBSADA 0xfe000077 -#define MASK_PBSADA 0xfe00707f -#define MATCH_PKBB16 0xe001077 -#define MASK_PKBB16 0xfe00707f -#define MATCH_PKBT16 0x1e001077 -#define MASK_PKBT16 0xfe00707f -#define MATCH_PKTT16 0x2e001077 -#define MASK_PKTT16 0xfe00707f -#define MATCH_PKTB16 0x3e001077 -#define MASK_PKTB16 0xfe00707f -#define MATCH_RADD8 0x8000077 -#define MASK_RADD8 0xfe00707f -#define MATCH_RADD16 0x77 -#define MASK_RADD16 0xfe00707f -#define MATCH_RADD64 0x80001077 -#define MASK_RADD64 0xfe00707f -#define MATCH_RADDW 0x20001077 -#define MASK_RADDW 0xfe00707f -#define MATCH_RCRAS16 0x4000077 -#define MASK_RCRAS16 0xfe00707f -#define MATCH_RCRSA16 0x6000077 -#define MASK_RCRSA16 0xfe00707f -#define MATCH_RSTAS16 0xb4002077 -#define MASK_RSTAS16 0xfe00707f -#define MATCH_RSTSA16 0xb6002077 -#define MASK_RSTSA16 0xfe00707f -#define MATCH_RSUB8 0xa000077 -#define MASK_RSUB8 0xfe00707f -#define MATCH_RSUB16 0x2000077 -#define MASK_RSUB16 0xfe00707f -#define MATCH_RSUB64 0x82001077 -#define MASK_RSUB64 0xfe00707f -#define MATCH_RSUBW 0x22001077 -#define MASK_RSUBW 0xfe00707f -#define MATCH_SCLIP8 0x8c000077 -#define MASK_SCLIP8 0xff80707f -#define MATCH_SCLIP16 0x84000077 -#define MASK_SCLIP16 0xff00707f -#define MATCH_SCLIP32 0xe4000077 -#define MASK_SCLIP32 0xfe00707f -#define MATCH_SCMPLE8 0x1e000077 -#define MASK_SCMPLE8 0xfe00707f -#define MATCH_SCMPLE16 0x1c000077 -#define MASK_SCMPLE16 0xfe00707f -#define MATCH_SCMPLT8 0xe000077 -#define MASK_SCMPLT8 0xfe00707f -#define MATCH_SCMPLT16 0xc000077 -#define MASK_SCMPLT16 0xfe00707f -#define MATCH_SLL8 0x5c000077 -#define MASK_SLL8 0xfe00707f -#define MATCH_SLLI8 0x7c000077 -#define MASK_SLLI8 0xff80707f -#define MATCH_SLL16 0x54000077 -#define MASK_SLL16 0xfe00707f -#define MATCH_SLLI16 0x74000077 -#define MASK_SLLI16 0xff00707f -#define MATCH_SMAL 0x5e001077 -#define MASK_SMAL 0xfe00707f -#define MATCH_SMALBB 0x88001077 -#define MASK_SMALBB 0xfe00707f -#define MATCH_SMALBT 0x98001077 -#define MASK_SMALBT 0xfe00707f -#define MATCH_SMALTT 0xa8001077 -#define MASK_SMALTT 0xfe00707f -#define MATCH_SMALDA 0x8c001077 -#define MASK_SMALDA 0xfe00707f -#define MATCH_SMALXDA 0x9c001077 -#define MASK_SMALXDA 0xfe00707f -#define MATCH_SMALDS 0x8a001077 -#define MASK_SMALDS 0xfe00707f -#define MATCH_SMALDRS 0x9a001077 -#define MASK_SMALDRS 0xfe00707f -#define MATCH_SMALXDS 0xaa001077 -#define MASK_SMALXDS 0xfe00707f -#define MATCH_SMAR64 0x84001077 -#define MASK_SMAR64 0xfe00707f -#define MATCH_SMAQA 0xc8000077 -#define MASK_SMAQA 0xfe00707f -#define MATCH_SMAQA_SU 0xca000077 -#define MASK_SMAQA_SU 0xfe00707f -#define MATCH_SMAX8 0x8a000077 -#define MASK_SMAX8 0xfe00707f -#define MATCH_SMAX16 0x82000077 -#define MASK_SMAX16 0xfe00707f -#define MATCH_SMBB16 0x8001077 -#define MASK_SMBB16 0xfe00707f -#define MATCH_SMBT16 0x18001077 -#define MASK_SMBT16 0xfe00707f -#define MATCH_SMTT16 0x28001077 -#define MASK_SMTT16 0xfe00707f -#define MATCH_SMDS 0x58001077 -#define MASK_SMDS 0xfe00707f -#define MATCH_SMDRS 0x68001077 -#define MASK_SMDRS 0xfe00707f -#define MATCH_SMXDS 0x78001077 -#define MASK_SMXDS 0xfe00707f -#define MATCH_SMIN8 0x88000077 -#define MASK_SMIN8 0xfe00707f -#define MATCH_SMIN16 0x80000077 -#define MASK_SMIN16 0xfe00707f -#define MATCH_SMMUL 0x40001077 -#define MASK_SMMUL 0xfe00707f -#define MATCH_SMMUL_U 0x50001077 -#define MASK_SMMUL_U 0xfe00707f -#define MATCH_SMMWB 0x44001077 -#define MASK_SMMWB 0xfe00707f -#define MATCH_SMMWB_U 0x54001077 -#define MASK_SMMWB_U 0xfe00707f -#define MATCH_SMMWT 0x64001077 -#define MASK_SMMWT 0xfe00707f -#define MATCH_SMMWT_U 0x74001077 -#define MASK_SMMWT_U 0xfe00707f -#define MATCH_SMSLDA 0xac001077 -#define MASK_SMSLDA 0xfe00707f -#define MATCH_SMSLXDA 0xbc001077 -#define MASK_SMSLXDA 0xfe00707f -#define MATCH_SMSR64 0x86001077 -#define MASK_SMSR64 0xfe00707f -#define MATCH_SMUL8 0xa8000077 -#define MASK_SMUL8 0xfe00707f -#define MATCH_SMULX8 0xaa000077 -#define MASK_SMULX8 0xfe00707f -#define MATCH_SMUL16 0xa0000077 -#define MASK_SMUL16 0xfe00707f -#define MATCH_SMULX16 0xa2000077 -#define MASK_SMULX16 0xfe00707f -#define MATCH_SRA_U 0x24001077 -#define MASK_SRA_U 0xfe00707f -#define MATCH_SRAI_U 0xd4001077 -#define MASK_SRAI_U 0xfc00707f -#define MATCH_SRA8 0x58000077 -#define MASK_SRA8 0xfe00707f -#define MATCH_SRA8_U 0x68000077 -#define MASK_SRA8_U 0xfe00707f -#define MATCH_SRAI8 0x78000077 -#define MASK_SRAI8 0xff80707f -#define MATCH_SRAI8_U 0x78800077 -#define MASK_SRAI8_U 0xff80707f -#define MATCH_SRA16 0x50000077 -#define MASK_SRA16 0xfe00707f -#define MATCH_SRA16_U 0x60000077 -#define MASK_SRA16_U 0xfe00707f -#define MATCH_SRAI16 0x70000077 -#define MASK_SRAI16 0xff00707f -#define MATCH_SRAI16_U 0x71000077 -#define MASK_SRAI16_U 0xff00707f -#define MATCH_SRL8 0x5a000077 -#define MASK_SRL8 0xfe00707f -#define MATCH_SRL8_U 0x6a000077 -#define MASK_SRL8_U 0xfe00707f -#define MATCH_SRLI8 0x7a000077 -#define MASK_SRLI8 0xff80707f -#define MATCH_SRLI8_U 0x7a800077 -#define MASK_SRLI8_U 0xff80707f -#define MATCH_SRL16 0x52000077 -#define MASK_SRL16 0xfe00707f -#define MATCH_SRL16_U 0x62000077 -#define MASK_SRL16_U 0xfe00707f -#define MATCH_SRLI16 0x72000077 -#define MASK_SRLI16 0xff00707f -#define MATCH_SRLI16_U 0x73000077 -#define MASK_SRLI16_U 0xff00707f -#define MATCH_STAS16 0xf4002077 -#define MASK_STAS16 0xfe00707f -#define MATCH_STSA16 0xf6002077 -#define MASK_STSA16 0xfe00707f -#define MATCH_SUB8 0x4a000077 -#define MASK_SUB8 0xfe00707f -#define MATCH_SUB16 0x42000077 -#define MASK_SUB16 0xfe00707f -#define MATCH_SUB64 0xc2001077 -#define MASK_SUB64 0xfe00707f -#define MATCH_SUNPKD810 0xac800077 -#define MASK_SUNPKD810 0xfff0707f -#define MATCH_SUNPKD820 0xac900077 -#define MASK_SUNPKD820 0xfff0707f -#define MATCH_SUNPKD830 0xaca00077 -#define MASK_SUNPKD830 0xfff0707f -#define MATCH_SUNPKD831 0xacb00077 -#define MASK_SUNPKD831 0xfff0707f -#define MATCH_SUNPKD832 0xad300077 -#define MASK_SUNPKD832 0xfff0707f -#define MATCH_SWAP8 0xad800077 -#define MASK_SWAP8 0xfff0707f -#define MATCH_UCLIP8 0x8d000077 -#define MASK_UCLIP8 0xff80707f -#define MATCH_UCLIP16 0x85000077 -#define MASK_UCLIP16 0xff00707f -#define MATCH_UCLIP32 0xf4000077 -#define MASK_UCLIP32 0xfe00707f -#define MATCH_UCMPLE8 0x3e000077 -#define MASK_UCMPLE8 0xfe00707f -#define MATCH_UCMPLE16 0x3c000077 -#define MASK_UCMPLE16 0xfe00707f -#define MATCH_UCMPLT8 0x2e000077 -#define MASK_UCMPLT8 0xfe00707f -#define MATCH_UCMPLT16 0x2c000077 -#define MASK_UCMPLT16 0xfe00707f -#define MATCH_UKADD8 0x38000077 -#define MASK_UKADD8 0xfe00707f -#define MATCH_UKADD16 0x30000077 -#define MASK_UKADD16 0xfe00707f -#define MATCH_UKADD64 0xb0001077 -#define MASK_UKADD64 0xfe00707f -#define MATCH_UKADDH 0x14001077 -#define MASK_UKADDH 0xfe00707f -#define MATCH_UKADDW 0x10001077 -#define MASK_UKADDW 0xfe00707f -#define MATCH_UKCRAS16 0x34000077 -#define MASK_UKCRAS16 0xfe00707f -#define MATCH_UKCRSA16 0x36000077 -#define MASK_UKCRSA16 0xfe00707f -#define MATCH_UKMAR64 0xb4001077 -#define MASK_UKMAR64 0xfe00707f -#define MATCH_UKMSR64 0xb6001077 -#define MASK_UKMSR64 0xfe00707f -#define MATCH_UKSTAS16 0xe4002077 -#define MASK_UKSTAS16 0xfe00707f -#define MATCH_UKSTSA16 0xe6002077 -#define MASK_UKSTSA16 0xfe00707f -#define MATCH_UKSUB8 0x3a000077 -#define MASK_UKSUB8 0xfe00707f -#define MATCH_UKSUB16 0x32000077 -#define MASK_UKSUB16 0xfe00707f -#define MATCH_UKSUB64 0xb2001077 -#define MASK_UKSUB64 0xfe00707f -#define MATCH_UKSUBH 0x16001077 -#define MASK_UKSUBH 0xfe00707f -#define MATCH_UKSUBW 0x12001077 -#define MASK_UKSUBW 0xfe00707f -#define MATCH_UMAR64 0xa4001077 -#define MASK_UMAR64 0xfe00707f -#define MATCH_UMAQA 0xcc000077 -#define MASK_UMAQA 0xfe00707f -#define MATCH_UMAX8 0x9a000077 -#define MASK_UMAX8 0xfe00707f -#define MATCH_UMAX16 0x92000077 -#define MASK_UMAX16 0xfe00707f -#define MATCH_UMIN8 0x98000077 -#define MASK_UMIN8 0xfe00707f -#define MATCH_UMIN16 0x90000077 -#define MASK_UMIN16 0xfe00707f -#define MATCH_UMSR64 0xa6001077 -#define MASK_UMSR64 0xfe00707f -#define MATCH_UMUL8 0xb8000077 -#define MASK_UMUL8 0xfe00707f -#define MATCH_UMULX8 0xba000077 -#define MASK_UMULX8 0xfe00707f -#define MATCH_UMUL16 0xb0000077 -#define MASK_UMUL16 0xfe00707f -#define MATCH_UMULX16 0xb2000077 -#define MASK_UMULX16 0xfe00707f -#define MATCH_URADD8 0x28000077 -#define MASK_URADD8 0xfe00707f -#define MATCH_URADD16 0x20000077 -#define MASK_URADD16 0xfe00707f -#define MATCH_URADD64 0xa0001077 -#define MASK_URADD64 0xfe00707f -#define MATCH_URADDW 0x30001077 -#define MASK_URADDW 0xfe00707f -#define MATCH_URCRAS16 0x24000077 -#define MASK_URCRAS16 0xfe00707f -#define MATCH_URCRSA16 0x26000077 -#define MASK_URCRSA16 0xfe00707f -#define MATCH_URSTAS16 0xd4002077 -#define MASK_URSTAS16 0xfe00707f -#define MATCH_URSTSA16 0xd6002077 -#define MASK_URSTSA16 0xfe00707f -#define MATCH_URSUB8 0x2a000077 -#define MASK_URSUB8 0xfe00707f -#define MATCH_URSUB16 0x22000077 -#define MASK_URSUB16 0xfe00707f -#define MATCH_URSUB64 0xa2001077 -#define MASK_URSUB64 0xfe00707f -#define MATCH_URSUBW 0x32001077 -#define MASK_URSUBW 0xfe00707f -#define MATCH_WEXTI 0xde000077 -#define MASK_WEXTI 0xfe00707f -#define MATCH_WEXT 0xce000077 -#define MASK_WEXT 0xfe00707f -#define MATCH_ZUNPKD810 0xacc00077 -#define MASK_ZUNPKD810 0xfff0707f -#define MATCH_ZUNPKD820 0xacd00077 -#define MASK_ZUNPKD820 0xfff0707f -#define MATCH_ZUNPKD830 0xace00077 -#define MASK_ZUNPKD830 0xfff0707f -#define MATCH_ZUNPKD831 0xacf00077 -#define MASK_ZUNPKD831 0xfff0707f -#define MATCH_ZUNPKD832 0xad700077 -#define MASK_ZUNPKD832 0xfff0707f -#define MATCH_ADD32 0x40002077 -#define MASK_ADD32 0xfe00707f -#define MATCH_CRAS32 0x44002077 -#define MASK_CRAS32 0xfe00707f -#define MATCH_CRSA32 0x46002077 -#define MASK_CRSA32 0xfe00707f -#define MATCH_KABS32 0xad200077 -#define MASK_KABS32 0xfff0707f -#define MATCH_KADD32 0x10002077 -#define MASK_KADD32 0xfe00707f -#define MATCH_KCRAS32 0x14002077 -#define MASK_KCRAS32 0xfe00707f -#define MATCH_KCRSA32 0x16002077 -#define MASK_KCRSA32 0xfe00707f -#define MATCH_KDMBB16 0xda001077 -#define MASK_KDMBB16 0xfe00707f -#define MATCH_KDMBT16 0xea001077 -#define MASK_KDMBT16 0xfe00707f -#define MATCH_KDMTT16 0xfa001077 -#define MASK_KDMTT16 0xfe00707f -#define MATCH_KDMABB16 0xd8001077 -#define MASK_KDMABB16 0xfe00707f -#define MATCH_KDMABT16 0xe8001077 -#define MASK_KDMABT16 0xfe00707f -#define MATCH_KDMATT16 0xf8001077 -#define MASK_KDMATT16 0xfe00707f -#define MATCH_KHMBB16 0xdc001077 -#define MASK_KHMBB16 0xfe00707f -#define MATCH_KHMBT16 0xec001077 -#define MASK_KHMBT16 0xfe00707f -#define MATCH_KHMTT16 0xfc001077 -#define MASK_KHMTT16 0xfe00707f -#define MATCH_KMABB32 0x5a002077 -#define MASK_KMABB32 0xfe00707f -#define MATCH_KMABT32 0x6a002077 -#define MASK_KMABT32 0xfe00707f -#define MATCH_KMATT32 0x7a002077 -#define MASK_KMATT32 0xfe00707f -#define MATCH_KMAXDA32 0x4a002077 -#define MASK_KMAXDA32 0xfe00707f -#define MATCH_KMDA32 0x38002077 -#define MASK_KMDA32 0xfe00707f -#define MATCH_KMXDA32 0x3a002077 -#define MASK_KMXDA32 0xfe00707f -#define MATCH_KMADS32 0x5c002077 -#define MASK_KMADS32 0xfe00707f -#define MATCH_KMADRS32 0x6c002077 -#define MASK_KMADRS32 0xfe00707f -#define MATCH_KMAXDS32 0x7c002077 -#define MASK_KMAXDS32 0xfe00707f -#define MATCH_KMSDA32 0x4c002077 -#define MASK_KMSDA32 0xfe00707f -#define MATCH_KMSXDA32 0x4e002077 -#define MASK_KMSXDA32 0xfe00707f -#define MATCH_KSLL32 0x64002077 -#define MASK_KSLL32 0xfe00707f -#define MATCH_KSLLI32 0x84002077 -#define MASK_KSLLI32 0xfe00707f -#define MATCH_KSLRA32 0x56002077 -#define MASK_KSLRA32 0xfe00707f -#define MATCH_KSLRA32_U 0x66002077 -#define MASK_KSLRA32_U 0xfe00707f -#define MATCH_KSTAS32 0xc0002077 -#define MASK_KSTAS32 0xfe00707f -#define MATCH_KSTSA32 0xc2002077 -#define MASK_KSTSA32 0xfe00707f -#define MATCH_KSUB32 0x12002077 -#define MASK_KSUB32 0xfe00707f -#define MATCH_PKBB32 0xe002077 -#define MASK_PKBB32 0xfe00707f -#define MATCH_PKBT32 0x1e002077 -#define MASK_PKBT32 0xfe00707f -#define MATCH_PKTT32 0x2e002077 -#define MASK_PKTT32 0xfe00707f -#define MATCH_PKTB32 0x3e002077 -#define MASK_PKTB32 0xfe00707f -#define MATCH_RADD32 0x2077 -#define MASK_RADD32 0xfe00707f -#define MATCH_RCRAS32 0x4002077 -#define MASK_RCRAS32 0xfe00707f -#define MATCH_RCRSA32 0x6002077 -#define MASK_RCRSA32 0xfe00707f -#define MATCH_RSTAS32 0xb0002077 -#define MASK_RSTAS32 0xfe00707f -#define MATCH_RSTSA32 0xb2002077 -#define MASK_RSTSA32 0xfe00707f -#define MATCH_RSUB32 0x2002077 -#define MASK_RSUB32 0xfe00707f -#define MATCH_SLL32 0x54002077 -#define MASK_SLL32 0xfe00707f -#define MATCH_SLLI32 0x74002077 -#define MASK_SLLI32 0xfe00707f -#define MATCH_SMAX32 0x92002077 -#define MASK_SMAX32 0xfe00707f -#define MATCH_SMBT32 0x18002077 -#define MASK_SMBT32 0xfe00707f -#define MATCH_SMTT32 0x28002077 -#define MASK_SMTT32 0xfe00707f -#define MATCH_SMDS32 0x58002077 -#define MASK_SMDS32 0xfe00707f -#define MATCH_SMDRS32 0x68002077 -#define MASK_SMDRS32 0xfe00707f -#define MATCH_SMXDS32 0x78002077 -#define MASK_SMXDS32 0xfe00707f -#define MATCH_SMIN32 0x90002077 -#define MASK_SMIN32 0xfe00707f -#define MATCH_SRA32 0x50002077 -#define MASK_SRA32 0xfe00707f -#define MATCH_SRA32_U 0x60002077 -#define MASK_SRA32_U 0xfe00707f -#define MATCH_SRAI32 0x70002077 -#define MASK_SRAI32 0xfe00707f -#define MATCH_SRAI32_U 0x80002077 -#define MASK_SRAI32_U 0xfe00707f -#define MATCH_SRAIW_U 0x34001077 -#define MASK_SRAIW_U 0xfe00707f -#define MATCH_SRL32 0x52002077 -#define MASK_SRL32 0xfe00707f -#define MATCH_SRL32_U 0x62002077 -#define MASK_SRL32_U 0xfe00707f -#define MATCH_SRLI32 0x72002077 -#define MASK_SRLI32 0xfe00707f -#define MATCH_SRLI32_U 0x82002077 -#define MASK_SRLI32_U 0xfe00707f -#define MATCH_STAS32 0xf0002077 -#define MASK_STAS32 0xfe00707f -#define MATCH_STSA32 0xf2002077 -#define MASK_STSA32 0xfe00707f -#define MATCH_SUB32 0x42002077 -#define MASK_SUB32 0xfe00707f -#define MATCH_UKADD32 0x30002077 -#define MASK_UKADD32 0xfe00707f -#define MATCH_UKCRAS32 0x34002077 -#define MASK_UKCRAS32 0xfe00707f -#define MATCH_UKCRSA32 0x36002077 -#define MASK_UKCRSA32 0xfe00707f -#define MATCH_UKSTAS32 0xe0002077 -#define MASK_UKSTAS32 0xfe00707f -#define MATCH_UKSTSA32 0xe2002077 -#define MASK_UKSTSA32 0xfe00707f -#define MATCH_UKSUB32 0x32002077 -#define MASK_UKSUB32 0xfe00707f -#define MATCH_UMAX32 0xa2002077 -#define MASK_UMAX32 0xfe00707f -#define MATCH_UMIN32 0xa0002077 -#define MASK_UMIN32 0xfe00707f -#define MATCH_URADD32 0x20002077 -#define MASK_URADD32 0xfe00707f -#define MATCH_URCRAS32 0x24002077 -#define MASK_URCRAS32 0xfe00707f -#define MATCH_URCRSA32 0x26002077 -#define MASK_URCRSA32 0xfe00707f -#define MATCH_URSTAS32 0xd0002077 -#define MASK_URSTAS32 0xfe00707f -#define MATCH_URSTSA32 0xd2002077 -#define MASK_URSTSA32 0xfe00707f -#define MATCH_URSUB32 0x22002077 -#define MASK_URSUB32 0xfe00707f -#define MATCH_VMVNFR_V 0x9e003057 -#define MASK_VMVNFR_V 0xfe00707f -#define MATCH_VL1R_V 0x2800007 -#define MASK_VL1R_V 0xfff0707f -#define MATCH_VL2R_V 0x6805007 -#define MASK_VL2R_V 0xfff0707f -#define MATCH_VL4R_V 0xe806007 -#define MASK_VL4R_V 0xfff0707f -#define MATCH_VL8R_V 0x1e807007 -#define MASK_VL8R_V 0xfff0707f -#define MATCH_VLE1_V 0x2b00007 -#define MASK_VLE1_V 0xfff0707f -#define MATCH_VSE1_V 0x2b00027 -#define MASK_VSE1_V 0xfff0707f -#define MATCH_VFREDSUM_VS 0x4001057 -#define MASK_VFREDSUM_VS 0xfc00707f -#define MATCH_VFWREDSUM_VS 0xc4001057 -#define MASK_VFWREDSUM_VS 0xfc00707f -#define MATCH_VPOPC_M 0x40082057 -#define MASK_VPOPC_M 0xfc0ff07f -#define CSR_FFLAGS 0x1 -#define CSR_FRM 0x2 -#define CSR_FCSR 0x3 -#define CSR_VSTART 0x8 -#define CSR_VXSAT 0x9 -#define CSR_VXRM 0xa -#define CSR_VCSR 0xf -#define CSR_SEED 0x15 -#define CSR_CYCLE 0xc00 -#define CSR_TIME 0xc01 -#define CSR_INSTRET 0xc02 -#define CSR_HPMCOUNTER3 0xc03 -#define CSR_HPMCOUNTER4 0xc04 -#define CSR_HPMCOUNTER5 0xc05 -#define CSR_HPMCOUNTER6 0xc06 -#define CSR_HPMCOUNTER7 0xc07 -#define CSR_HPMCOUNTER8 0xc08 -#define CSR_HPMCOUNTER9 0xc09 -#define CSR_HPMCOUNTER10 0xc0a -#define CSR_HPMCOUNTER11 0xc0b -#define CSR_HPMCOUNTER12 0xc0c -#define CSR_HPMCOUNTER13 0xc0d -#define CSR_HPMCOUNTER14 0xc0e -#define CSR_HPMCOUNTER15 0xc0f -#define CSR_HPMCOUNTER16 0xc10 -#define CSR_HPMCOUNTER17 0xc11 -#define CSR_HPMCOUNTER18 0xc12 -#define CSR_HPMCOUNTER19 0xc13 -#define CSR_HPMCOUNTER20 0xc14 -#define CSR_HPMCOUNTER21 0xc15 -#define CSR_HPMCOUNTER22 0xc16 -#define CSR_HPMCOUNTER23 0xc17 -#define CSR_HPMCOUNTER24 0xc18 -#define CSR_HPMCOUNTER25 0xc19 -#define CSR_HPMCOUNTER26 0xc1a -#define CSR_HPMCOUNTER27 0xc1b -#define CSR_HPMCOUNTER28 0xc1c -#define CSR_HPMCOUNTER29 0xc1d -#define CSR_HPMCOUNTER30 0xc1e -#define CSR_HPMCOUNTER31 0xc1f -#define CSR_VL 0xc20 -#define CSR_VTYPE 0xc21 -#define CSR_VLENB 0xc22 -#define CSR_SSTATUS 0x100 -#define CSR_SEDELEG 0x102 -#define CSR_SIDELEG 0x103 -#define CSR_SIE 0x104 -#define CSR_STVEC 0x105 -#define CSR_SCOUNTEREN 0x106 -#define CSR_SSCRATCH 0x140 -#define CSR_SEPC 0x141 -#define CSR_SCAUSE 0x142 -#define CSR_STVAL 0x143 -#define CSR_SIP 0x144 -#define CSR_SATP 0x180 -#define CSR_SCONTEXT 0x5a8 -#define CSR_VSSTATUS 0x200 -#define CSR_VSIE 0x204 -#define CSR_VSTVEC 0x205 -#define CSR_VSSCRATCH 0x240 -#define CSR_VSEPC 0x241 -#define CSR_VSCAUSE 0x242 -#define CSR_VSTVAL 0x243 -#define CSR_VSIP 0x244 -#define CSR_VSATP 0x280 -#define CSR_HSTATUS 0x600 -#define CSR_HEDELEG 0x602 -#define CSR_HIDELEG 0x603 -#define CSR_HIE 0x604 -#define CSR_HTIMEDELTA 0x605 -#define CSR_HCOUNTEREN 0x606 -#define CSR_HGEIE 0x607 -#define CSR_HTVAL 0x643 -#define CSR_HIP 0x644 -#define CSR_HVIP 0x645 -#define CSR_HTINST 0x64a -#define CSR_HGATP 0x680 -#define CSR_HCONTEXT 0x6a8 -#define CSR_HGEIP 0xe12 -#define CSR_UTVT 0x7 -#define CSR_UNXTI 0x45 -#define CSR_UINTSTATUS 0x46 -#define CSR_USCRATCHCSW 0x48 -#define CSR_USCRATCHCSWL 0x49 -#define CSR_STVT 0x107 -#define CSR_SNXTI 0x145 -#define CSR_SINTSTATUS 0x146 -#define CSR_SSCRATCHCSW 0x148 -#define CSR_SSCRATCHCSWL 0x149 -#define CSR_MTVT 0x307 -#define CSR_MNXTI 0x345 -#define CSR_MINTSTATUS 0x346 -#define CSR_MSCRATCHCSW 0x348 -#define CSR_MSCRATCHCSWL 0x349 -#define CSR_MSTATUS 0x300 -#define CSR_MISA 0x301 -#define CSR_MEDELEG 0x302 -#define CSR_MIDELEG 0x303 -#define CSR_MIE 0x304 -#define CSR_MTVEC 0x305 -#define CSR_MCOUNTEREN 0x306 -#define CSR_MCOUNTINHIBIT 0x320 -#define CSR_MSCRATCH 0x340 -#define CSR_MEPC 0x341 -#define CSR_MCAUSE 0x342 -#define CSR_MTVAL 0x343 -#define CSR_MIP 0x344 -#define CSR_MTINST 0x34a -#define CSR_MTVAL2 0x34b -#define CSR_PMPCFG0 0x3a0 -#define CSR_PMPCFG1 0x3a1 -#define CSR_PMPCFG2 0x3a2 -#define CSR_PMPCFG3 0x3a3 -#define CSR_PMPADDR0 0x3b0 -#define CSR_PMPADDR1 0x3b1 -#define CSR_PMPADDR2 0x3b2 -#define CSR_PMPADDR3 0x3b3 -#define CSR_PMPADDR4 0x3b4 -#define CSR_PMPADDR5 0x3b5 -#define CSR_PMPADDR6 0x3b6 -#define CSR_PMPADDR7 0x3b7 -#define CSR_PMPADDR8 0x3b8 -#define CSR_PMPADDR9 0x3b9 -#define CSR_PMPADDR10 0x3ba -#define CSR_PMPADDR11 0x3bb -#define CSR_PMPADDR12 0x3bc -#define CSR_PMPADDR13 0x3bd -#define CSR_PMPADDR14 0x3be -#define CSR_PMPADDR15 0x3bf -#define CSR_TSELECT 0x7a0 -#define CSR_TDATA1 0x7a1 -#define CSR_TDATA2 0x7a2 -#define CSR_TDATA3 0x7a3 -#define CSR_TINFO 0x7a4 -#define CSR_TCONTROL 0x7a5 -#define CSR_MCONTEXT 0x7a8 -#define CSR_MSCONTEXT 0x7aa -#define CSR_DCSR 0x7b0 -#define CSR_DPC 0x7b1 -#define CSR_DSCRATCH0 0x7b2 -#define CSR_DSCRATCH1 0x7b3 -#define CSR_MCYCLE 0xb00 -#define CSR_MINSTRET 0xb02 -#define CSR_MHPMCOUNTER3 0xb03 -#define CSR_MHPMCOUNTER4 0xb04 -#define CSR_MHPMCOUNTER5 0xb05 -#define CSR_MHPMCOUNTER6 0xb06 -#define CSR_MHPMCOUNTER7 0xb07 -#define CSR_MHPMCOUNTER8 0xb08 -#define CSR_MHPMCOUNTER9 0xb09 -#define CSR_MHPMCOUNTER10 0xb0a -#define CSR_MHPMCOUNTER11 0xb0b -#define CSR_MHPMCOUNTER12 0xb0c -#define CSR_MHPMCOUNTER13 0xb0d -#define CSR_MHPMCOUNTER14 0xb0e -#define CSR_MHPMCOUNTER15 0xb0f -#define CSR_MHPMCOUNTER16 0xb10 -#define CSR_MHPMCOUNTER17 0xb11 -#define CSR_MHPMCOUNTER18 0xb12 -#define CSR_MHPMCOUNTER19 0xb13 -#define CSR_MHPMCOUNTER20 0xb14 -#define CSR_MHPMCOUNTER21 0xb15 -#define CSR_MHPMCOUNTER22 0xb16 -#define CSR_MHPMCOUNTER23 0xb17 -#define CSR_MHPMCOUNTER24 0xb18 -#define CSR_MHPMCOUNTER25 0xb19 -#define CSR_MHPMCOUNTER26 0xb1a -#define CSR_MHPMCOUNTER27 0xb1b -#define CSR_MHPMCOUNTER28 0xb1c -#define CSR_MHPMCOUNTER29 0xb1d -#define CSR_MHPMCOUNTER30 0xb1e -#define CSR_MHPMCOUNTER31 0xb1f -#define CSR_MHPMEVENT3 0x323 -#define CSR_MHPMEVENT4 0x324 -#define CSR_MHPMEVENT5 0x325 -#define CSR_MHPMEVENT6 0x326 -#define CSR_MHPMEVENT7 0x327 -#define CSR_MHPMEVENT8 0x328 -#define CSR_MHPMEVENT9 0x329 -#define CSR_MHPMEVENT10 0x32a -#define CSR_MHPMEVENT11 0x32b -#define CSR_MHPMEVENT12 0x32c -#define CSR_MHPMEVENT13 0x32d -#define CSR_MHPMEVENT14 0x32e -#define CSR_MHPMEVENT15 0x32f -#define CSR_MHPMEVENT16 0x330 -#define CSR_MHPMEVENT17 0x331 -#define CSR_MHPMEVENT18 0x332 -#define CSR_MHPMEVENT19 0x333 -#define CSR_MHPMEVENT20 0x334 -#define CSR_MHPMEVENT21 0x335 -#define CSR_MHPMEVENT22 0x336 -#define CSR_MHPMEVENT23 0x337 -#define CSR_MHPMEVENT24 0x338 -#define CSR_MHPMEVENT25 0x339 -#define CSR_MHPMEVENT26 0x33a -#define CSR_MHPMEVENT27 0x33b -#define CSR_MHPMEVENT28 0x33c -#define CSR_MHPMEVENT29 0x33d -#define CSR_MHPMEVENT30 0x33e -#define CSR_MHPMEVENT31 0x33f -#define CSR_MVENDORID 0xf11 -#define CSR_MARCHID 0xf12 -#define CSR_MIMPID 0xf13 -#define CSR_MHARTID 0xf14 -#define CSR_HTIMEDELTAH 0x615 -#define CSR_CYCLEH 0xc80 -#define CSR_TIMEH 0xc81 -#define CSR_INSTRETH 0xc82 -#define CSR_HPMCOUNTER3H 0xc83 -#define CSR_HPMCOUNTER4H 0xc84 -#define CSR_HPMCOUNTER5H 0xc85 -#define CSR_HPMCOUNTER6H 0xc86 -#define CSR_HPMCOUNTER7H 0xc87 -#define CSR_HPMCOUNTER8H 0xc88 -#define CSR_HPMCOUNTER9H 0xc89 -#define CSR_HPMCOUNTER10H 0xc8a -#define CSR_HPMCOUNTER11H 0xc8b -#define CSR_HPMCOUNTER12H 0xc8c -#define CSR_HPMCOUNTER13H 0xc8d -#define CSR_HPMCOUNTER14H 0xc8e -#define CSR_HPMCOUNTER15H 0xc8f -#define CSR_HPMCOUNTER16H 0xc90 -#define CSR_HPMCOUNTER17H 0xc91 -#define CSR_HPMCOUNTER18H 0xc92 -#define CSR_HPMCOUNTER19H 0xc93 -#define CSR_HPMCOUNTER20H 0xc94 -#define CSR_HPMCOUNTER21H 0xc95 -#define CSR_HPMCOUNTER22H 0xc96 -#define CSR_HPMCOUNTER23H 0xc97 -#define CSR_HPMCOUNTER24H 0xc98 -#define CSR_HPMCOUNTER25H 0xc99 -#define CSR_HPMCOUNTER26H 0xc9a -#define CSR_HPMCOUNTER27H 0xc9b -#define CSR_HPMCOUNTER28H 0xc9c -#define CSR_HPMCOUNTER29H 0xc9d -#define CSR_HPMCOUNTER30H 0xc9e -#define CSR_HPMCOUNTER31H 0xc9f -#define CSR_MSTATUSH 0x310 -#define CSR_MCYCLEH 0xb80 -#define CSR_MINSTRETH 0xb82 -#define CSR_MHPMCOUNTER3H 0xb83 -#define CSR_MHPMCOUNTER4H 0xb84 -#define CSR_MHPMCOUNTER5H 0xb85 -#define CSR_MHPMCOUNTER6H 0xb86 -#define CSR_MHPMCOUNTER7H 0xb87 -#define CSR_MHPMCOUNTER8H 0xb88 -#define CSR_MHPMCOUNTER9H 0xb89 -#define CSR_MHPMCOUNTER10H 0xb8a -#define CSR_MHPMCOUNTER11H 0xb8b -#define CSR_MHPMCOUNTER12H 0xb8c -#define CSR_MHPMCOUNTER13H 0xb8d -#define CSR_MHPMCOUNTER14H 0xb8e -#define CSR_MHPMCOUNTER15H 0xb8f -#define CSR_MHPMCOUNTER16H 0xb90 -#define CSR_MHPMCOUNTER17H 0xb91 -#define CSR_MHPMCOUNTER18H 0xb92 -#define CSR_MHPMCOUNTER19H 0xb93 -#define CSR_MHPMCOUNTER20H 0xb94 -#define CSR_MHPMCOUNTER21H 0xb95 -#define CSR_MHPMCOUNTER22H 0xb96 -#define CSR_MHPMCOUNTER23H 0xb97 -#define CSR_MHPMCOUNTER24H 0xb98 -#define CSR_MHPMCOUNTER25H 0xb99 -#define CSR_MHPMCOUNTER26H 0xb9a -#define CSR_MHPMCOUNTER27H 0xb9b -#define CSR_MHPMCOUNTER28H 0xb9c -#define CSR_MHPMCOUNTER29H 0xb9d -#define CSR_MHPMCOUNTER30H 0xb9e -#define CSR_MHPMCOUNTER31H 0xb9f -#define CAUSE_MISALIGNED_FETCH 0x0 -#define CAUSE_FETCH_ACCESS 0x1 -#define CAUSE_ILLEGAL_INSTRUCTION 0x2 -#define CAUSE_BREAKPOINT 0x3 -#define CAUSE_MISALIGNED_LOAD 0x4 -#define CAUSE_LOAD_ACCESS 0x5 -#define CAUSE_MISALIGNED_STORE 0x6 -#define CAUSE_STORE_ACCESS 0x7 -#define CAUSE_USER_ECALL 0x8 -#define CAUSE_SUPERVISOR_ECALL 0x9 -#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa -#define CAUSE_MACHINE_ECALL 0xb -#define CAUSE_FETCH_PAGE_FAULT 0xc -#define CAUSE_LOAD_PAGE_FAULT 0xd -#define CAUSE_STORE_PAGE_FAULT 0xf -#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 -#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 -#define CAUSE_VIRTUAL_INSTRUCTION 0x16 -#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 -#endif -#ifdef DECLARE_INSN -DECLARE_INSN(slli_rv32, MATCH_SLLI_RV32, MASK_SLLI_RV32) -DECLARE_INSN(srli_rv32, MATCH_SRLI_RV32, MASK_SRLI_RV32) -DECLARE_INSN(srai_rv32, MATCH_SRAI_RV32, MASK_SRAI_RV32) -DECLARE_INSN(frflags, MATCH_FRFLAGS, MASK_FRFLAGS) -DECLARE_INSN(fsflags, MATCH_FSFLAGS, MASK_FSFLAGS) -DECLARE_INSN(fsflagsi, MATCH_FSFLAGSI, MASK_FSFLAGSI) -DECLARE_INSN(frrm, MATCH_FRRM, MASK_FRRM) -DECLARE_INSN(fsrm, MATCH_FSRM, MASK_FSRM) -DECLARE_INSN(fsrmi, MATCH_FSRMI, MASK_FSRMI) -DECLARE_INSN(fscsr, MATCH_FSCSR, MASK_FSCSR) -DECLARE_INSN(frcsr, MATCH_FRCSR, MASK_FRCSR) -DECLARE_INSN(rdcycle, MATCH_RDCYCLE, MASK_RDCYCLE) -DECLARE_INSN(rdtime, MATCH_RDTIME, MASK_RDTIME) -DECLARE_INSN(rdinstret, MATCH_RDINSTRET, MASK_RDINSTRET) -DECLARE_INSN(rdcycleh, MATCH_RDCYCLEH, MASK_RDCYCLEH) -DECLARE_INSN(rdtimeh, MATCH_RDTIMEH, MASK_RDTIMEH) -DECLARE_INSN(rdinstreth, MATCH_RDINSTRETH, MASK_RDINSTRETH) -DECLARE_INSN(scall, MATCH_SCALL, MASK_SCALL) -DECLARE_INSN(sbreak, MATCH_SBREAK, MASK_SBREAK) -DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) -DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) -DECLARE_INSN(fence_tso, MATCH_FENCE_TSO, MASK_FENCE_TSO) -DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) -DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) -DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) -DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) -DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) -DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) -DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) -DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) -DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) -DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) -DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) -DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) -DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) -DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) -DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) -DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) -DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) -DECLARE_INSN(add, MATCH_ADD, MASK_ADD) -DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) -DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) -DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) -DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) -DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) -DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) -DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) -DECLARE_INSN(or, MATCH_OR, MASK_OR) -DECLARE_INSN(and, MATCH_AND, MASK_AND) -DECLARE_INSN(lb, MATCH_LB, MASK_LB) -DECLARE_INSN(lh, MATCH_LH, MASK_LH) -DECLARE_INSN(lw, MATCH_LW, MASK_LW) -DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) -DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) -DECLARE_INSN(sb, MATCH_SB, MASK_SB) -DECLARE_INSN(sh, MATCH_SH, MASK_SH) -DECLARE_INSN(sw, MATCH_SW, MASK_SW) -DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) -DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) -DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) -DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) -DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) -DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) -DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) -DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) -DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) -DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) -DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) -DECLARE_INSN(ld, MATCH_LD, MASK_LD) -DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) -DECLARE_INSN(sd, MATCH_SD, MASK_SD) -DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) -DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) -DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) -DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) -DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) -DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) -DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) -DECLARE_INSN(div, MATCH_DIV, MASK_DIV) -DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) -DECLARE_INSN(rem, MATCH_REM, MASK_REM) -DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) -DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) -DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) -DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) -DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) -DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) -DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) -DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) -DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) -DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) -DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) -DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) -DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) -DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) -DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) -DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) -DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) -DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) -DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) -DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) -DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) -DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) -DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) -DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) -DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) -DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) -DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) -DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) -DECLARE_INSN(hfence_vvma, MATCH_HFENCE_VVMA, MASK_HFENCE_VVMA) -DECLARE_INSN(hfence_gvma, MATCH_HFENCE_GVMA, MASK_HFENCE_GVMA) -DECLARE_INSN(hlv_b, MATCH_HLV_B, MASK_HLV_B) -DECLARE_INSN(hlv_bu, MATCH_HLV_BU, MASK_HLV_BU) -DECLARE_INSN(hlv_h, MATCH_HLV_H, MASK_HLV_H) -DECLARE_INSN(hlv_hu, MATCH_HLV_HU, MASK_HLV_HU) -DECLARE_INSN(hlvx_hu, MATCH_HLVX_HU, MASK_HLVX_HU) -DECLARE_INSN(hlv_w, MATCH_HLV_W, MASK_HLV_W) -DECLARE_INSN(hlvx_wu, MATCH_HLVX_WU, MASK_HLVX_WU) -DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B) -DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) -DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) -DECLARE_INSN(hlv_wu, MATCH_HLV_WU, MASK_HLV_WU) -DECLARE_INSN(hlv_d, MATCH_HLV_D, MASK_HLV_D) -DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D) -DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) -DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) -DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) -DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) -DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) -DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) -DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) -DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) -DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) -DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) -DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) -DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) -DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) -DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) -DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) -DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) -DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) -DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) -DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) -DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) -DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) -DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) -DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) -DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) -DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) -DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) -DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) -DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) -DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) -DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) -DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) -DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) -DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) -DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) -DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) -DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) -DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) -DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) -DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) -DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) -DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) -DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) -DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) -DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) -DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) -DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) -DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) -DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) -DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) -DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) -DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) -DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) -DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) -DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) -DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) -DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) -DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) -DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) -DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) -DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) -DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) -DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) -DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) -DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) -DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) -DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) -DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) -DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) -DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) -DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) -DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) -DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) -DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) -DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) -DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) -DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) -DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) -DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) -DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) -DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) -DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) -DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) -DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) -DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) -DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) -DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) -DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) -DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) -DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) -DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) -DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) -DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) -DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) -DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) -DECLARE_INSN(andn, MATCH_ANDN, MASK_ANDN) -DECLARE_INSN(orn, MATCH_ORN, MASK_ORN) -DECLARE_INSN(xnor, MATCH_XNOR, MASK_XNOR) -DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) -DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) -DECLARE_INSN(rol, MATCH_ROL, MASK_ROL) -DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) -DECLARE_INSN(bclr, MATCH_BCLR, MASK_BCLR) -DECLARE_INSN(bset, MATCH_BSET, MASK_BSET) -DECLARE_INSN(binv, MATCH_BINV, MASK_BINV) -DECLARE_INSN(bext, MATCH_BEXT, MASK_BEXT) -DECLARE_INSN(gorc, MATCH_GORC, MASK_GORC) -DECLARE_INSN(grev, MATCH_GREV, MASK_GREV) -DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) -DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) -DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) -DECLARE_INSN(bclri, MATCH_BCLRI, MASK_BCLRI) -DECLARE_INSN(bseti, MATCH_BSETI, MASK_BSETI) -DECLARE_INSN(binvi, MATCH_BINVI, MASK_BINVI) -DECLARE_INSN(bexti, MATCH_BEXTI, MASK_BEXTI) -DECLARE_INSN(gorci, MATCH_GORCI, MASK_GORCI) -DECLARE_INSN(grevi, MATCH_GREVI, MASK_GREVI) -DECLARE_INSN(cmix, MATCH_CMIX, MASK_CMIX) -DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) -DECLARE_INSN(fsl, MATCH_FSL, MASK_FSL) -DECLARE_INSN(fsr, MATCH_FSR, MASK_FSR) -DECLARE_INSN(fsri, MATCH_FSRI, MASK_FSRI) -DECLARE_INSN(clz, MATCH_CLZ, MASK_CLZ) -DECLARE_INSN(ctz, MATCH_CTZ, MASK_CTZ) -DECLARE_INSN(cpop, MATCH_CPOP, MASK_CPOP) -DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) -DECLARE_INSN(sext_h, MATCH_SEXT_H, MASK_SEXT_H) -DECLARE_INSN(crc32_b, MATCH_CRC32_B, MASK_CRC32_B) -DECLARE_INSN(crc32_h, MATCH_CRC32_H, MASK_CRC32_H) -DECLARE_INSN(crc32_w, MATCH_CRC32_W, MASK_CRC32_W) -DECLARE_INSN(crc32c_b, MATCH_CRC32C_B, MASK_CRC32C_B) -DECLARE_INSN(crc32c_h, MATCH_CRC32C_H, MASK_CRC32C_H) -DECLARE_INSN(crc32c_w, MATCH_CRC32C_W, MASK_CRC32C_W) -DECLARE_INSN(sh1add, MATCH_SH1ADD, MASK_SH1ADD) -DECLARE_INSN(sh2add, MATCH_SH2ADD, MASK_SH2ADD) -DECLARE_INSN(sh3add, MATCH_SH3ADD, MASK_SH3ADD) -DECLARE_INSN(clmul, MATCH_CLMUL, MASK_CLMUL) -DECLARE_INSN(clmulr, MATCH_CLMULR, MASK_CLMULR) -DECLARE_INSN(clmulh, MATCH_CLMULH, MASK_CLMULH) -DECLARE_INSN(min, MATCH_MIN, MASK_MIN) -DECLARE_INSN(minu, MATCH_MINU, MASK_MINU) -DECLARE_INSN(max, MATCH_MAX, MASK_MAX) -DECLARE_INSN(maxu, MATCH_MAXU, MASK_MAXU) -DECLARE_INSN(shfl, MATCH_SHFL, MASK_SHFL) -DECLARE_INSN(unshfl, MATCH_UNSHFL, MASK_UNSHFL) -DECLARE_INSN(bcompress, MATCH_BCOMPRESS, MASK_BCOMPRESS) -DECLARE_INSN(bdecompress, MATCH_BDECOMPRESS, MASK_BDECOMPRESS) -DECLARE_INSN(pack, MATCH_PACK, MASK_PACK) -DECLARE_INSN(packu, MATCH_PACKU, MASK_PACKU) -DECLARE_INSN(packh, MATCH_PACKH, MASK_PACKH) -DECLARE_INSN(bfp, MATCH_BFP, MASK_BFP) -DECLARE_INSN(shfli, MATCH_SHFLI, MASK_SHFLI) -DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) -DECLARE_INSN(xperm4, MATCH_XPERM4, MASK_XPERM4) -DECLARE_INSN(xperm8, MATCH_XPERM8, MASK_XPERM8) -DECLARE_INSN(xperm16, MATCH_XPERM16, MASK_XPERM16) -DECLARE_INSN(bmatflip, MATCH_BMATFLIP, MASK_BMATFLIP) -DECLARE_INSN(crc32_d, MATCH_CRC32_D, MASK_CRC32_D) -DECLARE_INSN(crc32c_d, MATCH_CRC32C_D, MASK_CRC32C_D) -DECLARE_INSN(bmator, MATCH_BMATOR, MASK_BMATOR) -DECLARE_INSN(bmatxor, MATCH_BMATXOR, MASK_BMATXOR) -DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) -DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) -DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) -DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) -DECLARE_INSN(rolw, MATCH_ROLW, MASK_ROLW) -DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) -DECLARE_INSN(sbclrw, MATCH_SBCLRW, MASK_SBCLRW) -DECLARE_INSN(sbsetw, MATCH_SBSETW, MASK_SBSETW) -DECLARE_INSN(sbinvw, MATCH_SBINVW, MASK_SBINVW) -DECLARE_INSN(sbextw, MATCH_SBEXTW, MASK_SBEXTW) -DECLARE_INSN(gorcw, MATCH_GORCW, MASK_GORCW) -DECLARE_INSN(grevw, MATCH_GREVW, MASK_GREVW) -DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) -DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) -DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) -DECLARE_INSN(sbclriw, MATCH_SBCLRIW, MASK_SBCLRIW) -DECLARE_INSN(sbsetiw, MATCH_SBSETIW, MASK_SBSETIW) -DECLARE_INSN(sbinviw, MATCH_SBINVIW, MASK_SBINVIW) -DECLARE_INSN(gorciw, MATCH_GORCIW, MASK_GORCIW) -DECLARE_INSN(greviw, MATCH_GREVIW, MASK_GREVIW) -DECLARE_INSN(fslw, MATCH_FSLW, MASK_FSLW) -DECLARE_INSN(fsrw, MATCH_FSRW, MASK_FSRW) -DECLARE_INSN(fsriw, MATCH_FSRIW, MASK_FSRIW) -DECLARE_INSN(clzw, MATCH_CLZW, MASK_CLZW) -DECLARE_INSN(ctzw, MATCH_CTZW, MASK_CTZW) -DECLARE_INSN(cpopw, MATCH_CPOPW, MASK_CPOPW) -DECLARE_INSN(sh1add_uw, MATCH_SH1ADD_UW, MASK_SH1ADD_UW) -DECLARE_INSN(sh2add_uw, MATCH_SH2ADD_UW, MASK_SH2ADD_UW) -DECLARE_INSN(sh3add_uw, MATCH_SH3ADD_UW, MASK_SH3ADD_UW) -DECLARE_INSN(shflw, MATCH_SHFLW, MASK_SHFLW) -DECLARE_INSN(unshflw, MATCH_UNSHFLW, MASK_UNSHFLW) -DECLARE_INSN(bcompressw, MATCH_BCOMPRESSW, MASK_BCOMPRESSW) -DECLARE_INSN(bdecompressw, MATCH_BDECOMPRESSW, MASK_BDECOMPRESSW) -DECLARE_INSN(packw, MATCH_PACKW, MASK_PACKW) -DECLARE_INSN(packuw, MATCH_PACKUW, MASK_PACKUW) -DECLARE_INSN(bfpw, MATCH_BFPW, MASK_BFPW) -DECLARE_INSN(xperm32, MATCH_XPERM32, MASK_XPERM32) -DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) -DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) -DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) -DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) -DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) -DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) -DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) -DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) -DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) -DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) -DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) -DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) -DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) -DECLARE_INSN(sinval_vma, MATCH_SINVAL_VMA, MASK_SINVAL_VMA) -DECLARE_INSN(sfence_w_inval, MATCH_SFENCE_W_INVAL, MASK_SFENCE_W_INVAL) -DECLARE_INSN(sfence_inval_ir, MATCH_SFENCE_INVAL_IR, MASK_SFENCE_INVAL_IR) -DECLARE_INSN(hinval_vvma, MATCH_HINVAL_VVMA, MASK_HINVAL_VVMA) -DECLARE_INSN(hinval_gvma, MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA) -DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H) -DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H) -DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H) -DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H) -DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H) -DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H) -DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H) -DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H) -DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H) -DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S) -DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H) -DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H) -DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H) -DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H) -DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H) -DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H) -DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H) -DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H) -DECLARE_INSN(fclass_h, MATCH_FCLASS_H, MASK_FCLASS_H) -DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W) -DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU) -DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X) -DECLARE_INSN(flh, MATCH_FLH, MASK_FLH) -DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH) -DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H) -DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H) -DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H) -DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H) -DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D) -DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H) -DECLARE_INSN(fcvt_h_q, MATCH_FCVT_H_Q, MASK_FCVT_H_Q) -DECLARE_INSN(fcvt_q_h, MATCH_FCVT_Q_H, MASK_FCVT_Q_H) -DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H) -DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H) -DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L) -DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU) -DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) -DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) -DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) -DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) -DECLARE_INSN(sha256sum0, MATCH_SHA256SUM0, MASK_SHA256SUM0) -DECLARE_INSN(sha256sum1, MATCH_SHA256SUM1, MASK_SHA256SUM1) -DECLARE_INSN(sha256sig0, MATCH_SHA256SIG0, MASK_SHA256SIG0) -DECLARE_INSN(sha256sig1, MATCH_SHA256SIG1, MASK_SHA256SIG1) -DECLARE_INSN(aes32esmi, MATCH_AES32ESMI, MASK_AES32ESMI) -DECLARE_INSN(aes32esi, MATCH_AES32ESI, MASK_AES32ESI) -DECLARE_INSN(aes32dsmi, MATCH_AES32DSMI, MASK_AES32DSMI) -DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) -DECLARE_INSN(sha512sum0r, MATCH_SHA512SUM0R, MASK_SHA512SUM0R) -DECLARE_INSN(sha512sum1r, MATCH_SHA512SUM1R, MASK_SHA512SUM1R) -DECLARE_INSN(sha512sig0l, MATCH_SHA512SIG0L, MASK_SHA512SIG0L) -DECLARE_INSN(sha512sig0h, MATCH_SHA512SIG0H, MASK_SHA512SIG0H) -DECLARE_INSN(sha512sig1l, MATCH_SHA512SIG1L, MASK_SHA512SIG1L) -DECLARE_INSN(sha512sig1h, MATCH_SHA512SIG1H, MASK_SHA512SIG1H) -DECLARE_INSN(aes64ks1i, MATCH_AES64KS1I, MASK_AES64KS1I) -DECLARE_INSN(aes64im, MATCH_AES64IM, MASK_AES64IM) -DECLARE_INSN(aes64ks2, MATCH_AES64KS2, MASK_AES64KS2) -DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM) -DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES) -DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM) -DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS) -DECLARE_INSN(sha512sum0, MATCH_SHA512SUM0, MASK_SHA512SUM0) -DECLARE_INSN(sha512sum1, MATCH_SHA512SUM1, MASK_SHA512SUM1) -DECLARE_INSN(sha512sig0, MATCH_SHA512SIG0, MASK_SHA512SIG0) -DECLARE_INSN(sha512sig1, MATCH_SHA512SIG1, MASK_SHA512SIG1) -DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) -DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) -DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) -DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) -DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) -DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) -DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) -DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) -DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) -DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) -DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) -DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) -DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) -DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) -DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) -DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) -DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) -DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) -DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) -DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) -DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) -DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) -DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) -DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) -DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) -DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) -DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) -DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) -DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) -DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) -DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) -DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) -DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) -DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) -DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) -DECLARE_INSN(c_srli_rv32, MATCH_C_SRLI_RV32, MASK_C_SRLI_RV32) -DECLARE_INSN(c_srai_rv32, MATCH_C_SRAI_RV32, MASK_C_SRAI_RV32) -DECLARE_INSN(c_slli_rv32, MATCH_C_SLLI_RV32, MASK_C_SLLI_RV32) -DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) -DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) -DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) -DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) -DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) -DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) -DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) -DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) -DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) -DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) -DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) -DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) -DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) -DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) -DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) -DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) -DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) -DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) -DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) -DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) -DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) -DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) -DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) -DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) -DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) -DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) -DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) -DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) -DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) -DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) -DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) -DECLARE_INSN(vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI) -DECLARE_INSN(vsetvli, MATCH_VSETVLI, MASK_VSETVLI) -DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL) -DECLARE_INSN(vlm_v, MATCH_VLM_V, MASK_VLM_V) -DECLARE_INSN(vsm_v, MATCH_VSM_V, MASK_VSM_V) -DECLARE_INSN(vle8_v, MATCH_VLE8_V, MASK_VLE8_V) -DECLARE_INSN(vle16_v, MATCH_VLE16_V, MASK_VLE16_V) -DECLARE_INSN(vle32_v, MATCH_VLE32_V, MASK_VLE32_V) -DECLARE_INSN(vle64_v, MATCH_VLE64_V, MASK_VLE64_V) -DECLARE_INSN(vle128_v, MATCH_VLE128_V, MASK_VLE128_V) -DECLARE_INSN(vle256_v, MATCH_VLE256_V, MASK_VLE256_V) -DECLARE_INSN(vle512_v, MATCH_VLE512_V, MASK_VLE512_V) -DECLARE_INSN(vle1024_v, MATCH_VLE1024_V, MASK_VLE1024_V) -DECLARE_INSN(vse8_v, MATCH_VSE8_V, MASK_VSE8_V) -DECLARE_INSN(vse16_v, MATCH_VSE16_V, MASK_VSE16_V) -DECLARE_INSN(vse32_v, MATCH_VSE32_V, MASK_VSE32_V) -DECLARE_INSN(vse64_v, MATCH_VSE64_V, MASK_VSE64_V) -DECLARE_INSN(vse128_v, MATCH_VSE128_V, MASK_VSE128_V) -DECLARE_INSN(vse256_v, MATCH_VSE256_V, MASK_VSE256_V) -DECLARE_INSN(vse512_v, MATCH_VSE512_V, MASK_VSE512_V) -DECLARE_INSN(vse1024_v, MATCH_VSE1024_V, MASK_VSE1024_V) -DECLARE_INSN(vluxei8_v, MATCH_VLUXEI8_V, MASK_VLUXEI8_V) -DECLARE_INSN(vluxei16_v, MATCH_VLUXEI16_V, MASK_VLUXEI16_V) -DECLARE_INSN(vluxei32_v, MATCH_VLUXEI32_V, MASK_VLUXEI32_V) -DECLARE_INSN(vluxei64_v, MATCH_VLUXEI64_V, MASK_VLUXEI64_V) -DECLARE_INSN(vluxei128_v, MATCH_VLUXEI128_V, MASK_VLUXEI128_V) -DECLARE_INSN(vluxei256_v, MATCH_VLUXEI256_V, MASK_VLUXEI256_V) -DECLARE_INSN(vluxei512_v, MATCH_VLUXEI512_V, MASK_VLUXEI512_V) -DECLARE_INSN(vluxei1024_v, MATCH_VLUXEI1024_V, MASK_VLUXEI1024_V) -DECLARE_INSN(vsuxei8_v, MATCH_VSUXEI8_V, MASK_VSUXEI8_V) -DECLARE_INSN(vsuxei16_v, MATCH_VSUXEI16_V, MASK_VSUXEI16_V) -DECLARE_INSN(vsuxei32_v, MATCH_VSUXEI32_V, MASK_VSUXEI32_V) -DECLARE_INSN(vsuxei64_v, MATCH_VSUXEI64_V, MASK_VSUXEI64_V) -DECLARE_INSN(vsuxei128_v, MATCH_VSUXEI128_V, MASK_VSUXEI128_V) -DECLARE_INSN(vsuxei256_v, MATCH_VSUXEI256_V, MASK_VSUXEI256_V) -DECLARE_INSN(vsuxei512_v, MATCH_VSUXEI512_V, MASK_VSUXEI512_V) -DECLARE_INSN(vsuxei1024_v, MATCH_VSUXEI1024_V, MASK_VSUXEI1024_V) -DECLARE_INSN(vlse8_v, MATCH_VLSE8_V, MASK_VLSE8_V) -DECLARE_INSN(vlse16_v, MATCH_VLSE16_V, MASK_VLSE16_V) -DECLARE_INSN(vlse32_v, MATCH_VLSE32_V, MASK_VLSE32_V) -DECLARE_INSN(vlse64_v, MATCH_VLSE64_V, MASK_VLSE64_V) -DECLARE_INSN(vlse128_v, MATCH_VLSE128_V, MASK_VLSE128_V) -DECLARE_INSN(vlse256_v, MATCH_VLSE256_V, MASK_VLSE256_V) -DECLARE_INSN(vlse512_v, MATCH_VLSE512_V, MASK_VLSE512_V) -DECLARE_INSN(vlse1024_v, MATCH_VLSE1024_V, MASK_VLSE1024_V) -DECLARE_INSN(vsse8_v, MATCH_VSSE8_V, MASK_VSSE8_V) -DECLARE_INSN(vsse16_v, MATCH_VSSE16_V, MASK_VSSE16_V) -DECLARE_INSN(vsse32_v, MATCH_VSSE32_V, MASK_VSSE32_V) -DECLARE_INSN(vsse64_v, MATCH_VSSE64_V, MASK_VSSE64_V) -DECLARE_INSN(vsse128_v, MATCH_VSSE128_V, MASK_VSSE128_V) -DECLARE_INSN(vsse256_v, MATCH_VSSE256_V, MASK_VSSE256_V) -DECLARE_INSN(vsse512_v, MATCH_VSSE512_V, MASK_VSSE512_V) -DECLARE_INSN(vsse1024_v, MATCH_VSSE1024_V, MASK_VSSE1024_V) -DECLARE_INSN(vloxei8_v, MATCH_VLOXEI8_V, MASK_VLOXEI8_V) -DECLARE_INSN(vloxei16_v, MATCH_VLOXEI16_V, MASK_VLOXEI16_V) -DECLARE_INSN(vloxei32_v, MATCH_VLOXEI32_V, MASK_VLOXEI32_V) -DECLARE_INSN(vloxei64_v, MATCH_VLOXEI64_V, MASK_VLOXEI64_V) -DECLARE_INSN(vloxei128_v, MATCH_VLOXEI128_V, MASK_VLOXEI128_V) -DECLARE_INSN(vloxei256_v, MATCH_VLOXEI256_V, MASK_VLOXEI256_V) -DECLARE_INSN(vloxei512_v, MATCH_VLOXEI512_V, MASK_VLOXEI512_V) -DECLARE_INSN(vloxei1024_v, MATCH_VLOXEI1024_V, MASK_VLOXEI1024_V) -DECLARE_INSN(vsoxei8_v, MATCH_VSOXEI8_V, MASK_VSOXEI8_V) -DECLARE_INSN(vsoxei16_v, MATCH_VSOXEI16_V, MASK_VSOXEI16_V) -DECLARE_INSN(vsoxei32_v, MATCH_VSOXEI32_V, MASK_VSOXEI32_V) -DECLARE_INSN(vsoxei64_v, MATCH_VSOXEI64_V, MASK_VSOXEI64_V) -DECLARE_INSN(vsoxei128_v, MATCH_VSOXEI128_V, MASK_VSOXEI128_V) -DECLARE_INSN(vsoxei256_v, MATCH_VSOXEI256_V, MASK_VSOXEI256_V) -DECLARE_INSN(vsoxei512_v, MATCH_VSOXEI512_V, MASK_VSOXEI512_V) -DECLARE_INSN(vsoxei1024_v, MATCH_VSOXEI1024_V, MASK_VSOXEI1024_V) -DECLARE_INSN(vle8ff_v, MATCH_VLE8FF_V, MASK_VLE8FF_V) -DECLARE_INSN(vle16ff_v, MATCH_VLE16FF_V, MASK_VLE16FF_V) -DECLARE_INSN(vle32ff_v, MATCH_VLE32FF_V, MASK_VLE32FF_V) -DECLARE_INSN(vle64ff_v, MATCH_VLE64FF_V, MASK_VLE64FF_V) -DECLARE_INSN(vle128ff_v, MATCH_VLE128FF_V, MASK_VLE128FF_V) -DECLARE_INSN(vle256ff_v, MATCH_VLE256FF_V, MASK_VLE256FF_V) -DECLARE_INSN(vle512ff_v, MATCH_VLE512FF_V, MASK_VLE512FF_V) -DECLARE_INSN(vle1024ff_v, MATCH_VLE1024FF_V, MASK_VLE1024FF_V) -DECLARE_INSN(vl1re8_v, MATCH_VL1RE8_V, MASK_VL1RE8_V) -DECLARE_INSN(vl1re16_v, MATCH_VL1RE16_V, MASK_VL1RE16_V) -DECLARE_INSN(vl1re32_v, MATCH_VL1RE32_V, MASK_VL1RE32_V) -DECLARE_INSN(vl1re64_v, MATCH_VL1RE64_V, MASK_VL1RE64_V) -DECLARE_INSN(vl2re8_v, MATCH_VL2RE8_V, MASK_VL2RE8_V) -DECLARE_INSN(vl2re16_v, MATCH_VL2RE16_V, MASK_VL2RE16_V) -DECLARE_INSN(vl2re32_v, MATCH_VL2RE32_V, MASK_VL2RE32_V) -DECLARE_INSN(vl2re64_v, MATCH_VL2RE64_V, MASK_VL2RE64_V) -DECLARE_INSN(vl4re8_v, MATCH_VL4RE8_V, MASK_VL4RE8_V) -DECLARE_INSN(vl4re16_v, MATCH_VL4RE16_V, MASK_VL4RE16_V) -DECLARE_INSN(vl4re32_v, MATCH_VL4RE32_V, MASK_VL4RE32_V) -DECLARE_INSN(vl4re64_v, MATCH_VL4RE64_V, MASK_VL4RE64_V) -DECLARE_INSN(vl8re8_v, MATCH_VL8RE8_V, MASK_VL8RE8_V) -DECLARE_INSN(vl8re16_v, MATCH_VL8RE16_V, MASK_VL8RE16_V) -DECLARE_INSN(vl8re32_v, MATCH_VL8RE32_V, MASK_VL8RE32_V) -DECLARE_INSN(vl8re64_v, MATCH_VL8RE64_V, MASK_VL8RE64_V) -DECLARE_INSN(vs1r_v, MATCH_VS1R_V, MASK_VS1R_V) -DECLARE_INSN(vs2r_v, MATCH_VS2R_V, MASK_VS2R_V) -DECLARE_INSN(vs4r_v, MATCH_VS4R_V, MASK_VS4R_V) -DECLARE_INSN(vs8r_v, MATCH_VS8R_V, MASK_VS8R_V) -DECLARE_INSN(vfadd_vf, MATCH_VFADD_VF, MASK_VFADD_VF) -DECLARE_INSN(vfsub_vf, MATCH_VFSUB_VF, MASK_VFSUB_VF) -DECLARE_INSN(vfmin_vf, MATCH_VFMIN_VF, MASK_VFMIN_VF) -DECLARE_INSN(vfmax_vf, MATCH_VFMAX_VF, MASK_VFMAX_VF) -DECLARE_INSN(vfsgnj_vf, MATCH_VFSGNJ_VF, MASK_VFSGNJ_VF) -DECLARE_INSN(vfsgnjn_vf, MATCH_VFSGNJN_VF, MASK_VFSGNJN_VF) -DECLARE_INSN(vfsgnjx_vf, MATCH_VFSGNJX_VF, MASK_VFSGNJX_VF) -DECLARE_INSN(vfslide1up_vf, MATCH_VFSLIDE1UP_VF, MASK_VFSLIDE1UP_VF) -DECLARE_INSN(vfslide1down_vf, MATCH_VFSLIDE1DOWN_VF, MASK_VFSLIDE1DOWN_VF) -DECLARE_INSN(vfmv_s_f, MATCH_VFMV_S_F, MASK_VFMV_S_F) -DECLARE_INSN(vfmerge_vfm, MATCH_VFMERGE_VFM, MASK_VFMERGE_VFM) -DECLARE_INSN(vfmv_v_f, MATCH_VFMV_V_F, MASK_VFMV_V_F) -DECLARE_INSN(vmfeq_vf, MATCH_VMFEQ_VF, MASK_VMFEQ_VF) -DECLARE_INSN(vmfle_vf, MATCH_VMFLE_VF, MASK_VMFLE_VF) -DECLARE_INSN(vmflt_vf, MATCH_VMFLT_VF, MASK_VMFLT_VF) -DECLARE_INSN(vmfne_vf, MATCH_VMFNE_VF, MASK_VMFNE_VF) -DECLARE_INSN(vmfgt_vf, MATCH_VMFGT_VF, MASK_VMFGT_VF) -DECLARE_INSN(vmfge_vf, MATCH_VMFGE_VF, MASK_VMFGE_VF) -DECLARE_INSN(vfdiv_vf, MATCH_VFDIV_VF, MASK_VFDIV_VF) -DECLARE_INSN(vfrdiv_vf, MATCH_VFRDIV_VF, MASK_VFRDIV_VF) -DECLARE_INSN(vfmul_vf, MATCH_VFMUL_VF, MASK_VFMUL_VF) -DECLARE_INSN(vfrsub_vf, MATCH_VFRSUB_VF, MASK_VFRSUB_VF) -DECLARE_INSN(vfmadd_vf, MATCH_VFMADD_VF, MASK_VFMADD_VF) -DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) -DECLARE_INSN(vfmsub_vf, MATCH_VFMSUB_VF, MASK_VFMSUB_VF) -DECLARE_INSN(vfnmsub_vf, MATCH_VFNMSUB_VF, MASK_VFNMSUB_VF) -DECLARE_INSN(vfmacc_vf, MATCH_VFMACC_VF, MASK_VFMACC_VF) -DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) -DECLARE_INSN(vfmsac_vf, MATCH_VFMSAC_VF, MASK_VFMSAC_VF) -DECLARE_INSN(vfnmsac_vf, MATCH_VFNMSAC_VF, MASK_VFNMSAC_VF) -DECLARE_INSN(vfwadd_vf, MATCH_VFWADD_VF, MASK_VFWADD_VF) -DECLARE_INSN(vfwsub_vf, MATCH_VFWSUB_VF, MASK_VFWSUB_VF) -DECLARE_INSN(vfwadd_wf, MATCH_VFWADD_WF, MASK_VFWADD_WF) -DECLARE_INSN(vfwsub_wf, MATCH_VFWSUB_WF, MASK_VFWSUB_WF) -DECLARE_INSN(vfwmul_vf, MATCH_VFWMUL_VF, MASK_VFWMUL_VF) -DECLARE_INSN(vfwmacc_vf, MATCH_VFWMACC_VF, MASK_VFWMACC_VF) -DECLARE_INSN(vfwnmacc_vf, MATCH_VFWNMACC_VF, MASK_VFWNMACC_VF) -DECLARE_INSN(vfwmsac_vf, MATCH_VFWMSAC_VF, MASK_VFWMSAC_VF) -DECLARE_INSN(vfwnmsac_vf, MATCH_VFWNMSAC_VF, MASK_VFWNMSAC_VF) -DECLARE_INSN(vfadd_vv, MATCH_VFADD_VV, MASK_VFADD_VV) -DECLARE_INSN(vfredusum_vs, MATCH_VFREDUSUM_VS, MASK_VFREDUSUM_VS) -DECLARE_INSN(vfsub_vv, MATCH_VFSUB_VV, MASK_VFSUB_VV) -DECLARE_INSN(vfredosum_vs, MATCH_VFREDOSUM_VS, MASK_VFREDOSUM_VS) -DECLARE_INSN(vfmin_vv, MATCH_VFMIN_VV, MASK_VFMIN_VV) -DECLARE_INSN(vfredmin_vs, MATCH_VFREDMIN_VS, MASK_VFREDMIN_VS) -DECLARE_INSN(vfmax_vv, MATCH_VFMAX_VV, MASK_VFMAX_VV) -DECLARE_INSN(vfredmax_vs, MATCH_VFREDMAX_VS, MASK_VFREDMAX_VS) -DECLARE_INSN(vfsgnj_vv, MATCH_VFSGNJ_VV, MASK_VFSGNJ_VV) -DECLARE_INSN(vfsgnjn_vv, MATCH_VFSGNJN_VV, MASK_VFSGNJN_VV) -DECLARE_INSN(vfsgnjx_vv, MATCH_VFSGNJX_VV, MASK_VFSGNJX_VV) -DECLARE_INSN(vfmv_f_s, MATCH_VFMV_F_S, MASK_VFMV_F_S) -DECLARE_INSN(vmfeq_vv, MATCH_VMFEQ_VV, MASK_VMFEQ_VV) -DECLARE_INSN(vmfle_vv, MATCH_VMFLE_VV, MASK_VMFLE_VV) -DECLARE_INSN(vmflt_vv, MATCH_VMFLT_VV, MASK_VMFLT_VV) -DECLARE_INSN(vmfne_vv, MATCH_VMFNE_VV, MASK_VMFNE_VV) -DECLARE_INSN(vfdiv_vv, MATCH_VFDIV_VV, MASK_VFDIV_VV) -DECLARE_INSN(vfmul_vv, MATCH_VFMUL_VV, MASK_VFMUL_VV) -DECLARE_INSN(vfmadd_vv, MATCH_VFMADD_VV, MASK_VFMADD_VV) -DECLARE_INSN(vfnmadd_vv, MATCH_VFNMADD_VV, MASK_VFNMADD_VV) -DECLARE_INSN(vfmsub_vv, MATCH_VFMSUB_VV, MASK_VFMSUB_VV) -DECLARE_INSN(vfnmsub_vv, MATCH_VFNMSUB_VV, MASK_VFNMSUB_VV) -DECLARE_INSN(vfmacc_vv, MATCH_VFMACC_VV, MASK_VFMACC_VV) -DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) -DECLARE_INSN(vfmsac_vv, MATCH_VFMSAC_VV, MASK_VFMSAC_VV) -DECLARE_INSN(vfnmsac_vv, MATCH_VFNMSAC_VV, MASK_VFNMSAC_VV) -DECLARE_INSN(vfcvt_xu_f_v, MATCH_VFCVT_XU_F_V, MASK_VFCVT_XU_F_V) -DECLARE_INSN(vfcvt_x_f_v, MATCH_VFCVT_X_F_V, MASK_VFCVT_X_F_V) -DECLARE_INSN(vfcvt_f_xu_v, MATCH_VFCVT_F_XU_V, MASK_VFCVT_F_XU_V) -DECLARE_INSN(vfcvt_f_x_v, MATCH_VFCVT_F_X_V, MASK_VFCVT_F_X_V) -DECLARE_INSN(vfcvt_rtz_xu_f_v, MATCH_VFCVT_RTZ_XU_F_V, MASK_VFCVT_RTZ_XU_F_V) -DECLARE_INSN(vfcvt_rtz_x_f_v, MATCH_VFCVT_RTZ_X_F_V, MASK_VFCVT_RTZ_X_F_V) -DECLARE_INSN(vfwcvt_xu_f_v, MATCH_VFWCVT_XU_F_V, MASK_VFWCVT_XU_F_V) -DECLARE_INSN(vfwcvt_x_f_v, MATCH_VFWCVT_X_F_V, MASK_VFWCVT_X_F_V) -DECLARE_INSN(vfwcvt_f_xu_v, MATCH_VFWCVT_F_XU_V, MASK_VFWCVT_F_XU_V) -DECLARE_INSN(vfwcvt_f_x_v, MATCH_VFWCVT_F_X_V, MASK_VFWCVT_F_X_V) -DECLARE_INSN(vfwcvt_f_f_v, MATCH_VFWCVT_F_F_V, MASK_VFWCVT_F_F_V) -DECLARE_INSN(vfwcvt_rtz_xu_f_v, MATCH_VFWCVT_RTZ_XU_F_V, MASK_VFWCVT_RTZ_XU_F_V) -DECLARE_INSN(vfwcvt_rtz_x_f_v, MATCH_VFWCVT_RTZ_X_F_V, MASK_VFWCVT_RTZ_X_F_V) -DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) -DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) -DECLARE_INSN(vfncvt_f_xu_w, MATCH_VFNCVT_F_XU_W, MASK_VFNCVT_F_XU_W) -DECLARE_INSN(vfncvt_f_x_w, MATCH_VFNCVT_F_X_W, MASK_VFNCVT_F_X_W) -DECLARE_INSN(vfncvt_f_f_w, MATCH_VFNCVT_F_F_W, MASK_VFNCVT_F_F_W) -DECLARE_INSN(vfncvt_rod_f_f_w, MATCH_VFNCVT_ROD_F_F_W, MASK_VFNCVT_ROD_F_F_W) -DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) -DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) -DECLARE_INSN(vfsqrt_v, MATCH_VFSQRT_V, MASK_VFSQRT_V) -DECLARE_INSN(vfrsqrt7_v, MATCH_VFRSQRT7_V, MASK_VFRSQRT7_V) -DECLARE_INSN(vfrec7_v, MATCH_VFREC7_V, MASK_VFREC7_V) -DECLARE_INSN(vfclass_v, MATCH_VFCLASS_V, MASK_VFCLASS_V) -DECLARE_INSN(vfwadd_vv, MATCH_VFWADD_VV, MASK_VFWADD_VV) -DECLARE_INSN(vfwredusum_vs, MATCH_VFWREDUSUM_VS, MASK_VFWREDUSUM_VS) -DECLARE_INSN(vfwsub_vv, MATCH_VFWSUB_VV, MASK_VFWSUB_VV) -DECLARE_INSN(vfwredosum_vs, MATCH_VFWREDOSUM_VS, MASK_VFWREDOSUM_VS) -DECLARE_INSN(vfwadd_wv, MATCH_VFWADD_WV, MASK_VFWADD_WV) -DECLARE_INSN(vfwsub_wv, MATCH_VFWSUB_WV, MASK_VFWSUB_WV) -DECLARE_INSN(vfwmul_vv, MATCH_VFWMUL_VV, MASK_VFWMUL_VV) -DECLARE_INSN(vfwmacc_vv, MATCH_VFWMACC_VV, MASK_VFWMACC_VV) -DECLARE_INSN(vfwnmacc_vv, MATCH_VFWNMACC_VV, MASK_VFWNMACC_VV) -DECLARE_INSN(vfwmsac_vv, MATCH_VFWMSAC_VV, MASK_VFWMSAC_VV) -DECLARE_INSN(vfwnmsac_vv, MATCH_VFWNMSAC_VV, MASK_VFWNMSAC_VV) -DECLARE_INSN(vadd_vx, MATCH_VADD_VX, MASK_VADD_VX) -DECLARE_INSN(vsub_vx, MATCH_VSUB_VX, MASK_VSUB_VX) -DECLARE_INSN(vrsub_vx, MATCH_VRSUB_VX, MASK_VRSUB_VX) -DECLARE_INSN(vminu_vx, MATCH_VMINU_VX, MASK_VMINU_VX) -DECLARE_INSN(vmin_vx, MATCH_VMIN_VX, MASK_VMIN_VX) -DECLARE_INSN(vmaxu_vx, MATCH_VMAXU_VX, MASK_VMAXU_VX) -DECLARE_INSN(vmax_vx, MATCH_VMAX_VX, MASK_VMAX_VX) -DECLARE_INSN(vand_vx, MATCH_VAND_VX, MASK_VAND_VX) -DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) -DECLARE_INSN(vxor_vx, MATCH_VXOR_VX, MASK_VXOR_VX) -DECLARE_INSN(vrgather_vx, MATCH_VRGATHER_VX, MASK_VRGATHER_VX) -DECLARE_INSN(vslideup_vx, MATCH_VSLIDEUP_VX, MASK_VSLIDEUP_VX) -DECLARE_INSN(vslidedown_vx, MATCH_VSLIDEDOWN_VX, MASK_VSLIDEDOWN_VX) -DECLARE_INSN(vadc_vxm, MATCH_VADC_VXM, MASK_VADC_VXM) -DECLARE_INSN(vmadc_vxm, MATCH_VMADC_VXM, MASK_VMADC_VXM) -DECLARE_INSN(vmadc_vx, MATCH_VMADC_VX, MASK_VMADC_VX) -DECLARE_INSN(vsbc_vxm, MATCH_VSBC_VXM, MASK_VSBC_VXM) -DECLARE_INSN(vmsbc_vxm, MATCH_VMSBC_VXM, MASK_VMSBC_VXM) -DECLARE_INSN(vmsbc_vx, MATCH_VMSBC_VX, MASK_VMSBC_VX) -DECLARE_INSN(vmerge_vxm, MATCH_VMERGE_VXM, MASK_VMERGE_VXM) -DECLARE_INSN(vmv_v_x, MATCH_VMV_V_X, MASK_VMV_V_X) -DECLARE_INSN(vmseq_vx, MATCH_VMSEQ_VX, MASK_VMSEQ_VX) -DECLARE_INSN(vmsne_vx, MATCH_VMSNE_VX, MASK_VMSNE_VX) -DECLARE_INSN(vmsltu_vx, MATCH_VMSLTU_VX, MASK_VMSLTU_VX) -DECLARE_INSN(vmslt_vx, MATCH_VMSLT_VX, MASK_VMSLT_VX) -DECLARE_INSN(vmsleu_vx, MATCH_VMSLEU_VX, MASK_VMSLEU_VX) -DECLARE_INSN(vmsle_vx, MATCH_VMSLE_VX, MASK_VMSLE_VX) -DECLARE_INSN(vmsgtu_vx, MATCH_VMSGTU_VX, MASK_VMSGTU_VX) -DECLARE_INSN(vmsgt_vx, MATCH_VMSGT_VX, MASK_VMSGT_VX) -DECLARE_INSN(vsaddu_vx, MATCH_VSADDU_VX, MASK_VSADDU_VX) -DECLARE_INSN(vsadd_vx, MATCH_VSADD_VX, MASK_VSADD_VX) -DECLARE_INSN(vssubu_vx, MATCH_VSSUBU_VX, MASK_VSSUBU_VX) -DECLARE_INSN(vssub_vx, MATCH_VSSUB_VX, MASK_VSSUB_VX) -DECLARE_INSN(vsll_vx, MATCH_VSLL_VX, MASK_VSLL_VX) -DECLARE_INSN(vsmul_vx, MATCH_VSMUL_VX, MASK_VSMUL_VX) -DECLARE_INSN(vsrl_vx, MATCH_VSRL_VX, MASK_VSRL_VX) -DECLARE_INSN(vsra_vx, MATCH_VSRA_VX, MASK_VSRA_VX) -DECLARE_INSN(vssrl_vx, MATCH_VSSRL_VX, MASK_VSSRL_VX) -DECLARE_INSN(vssra_vx, MATCH_VSSRA_VX, MASK_VSSRA_VX) -DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) -DECLARE_INSN(vnsra_wx, MATCH_VNSRA_WX, MASK_VNSRA_WX) -DECLARE_INSN(vnclipu_wx, MATCH_VNCLIPU_WX, MASK_VNCLIPU_WX) -DECLARE_INSN(vnclip_wx, MATCH_VNCLIP_WX, MASK_VNCLIP_WX) -DECLARE_INSN(vadd_vv, MATCH_VADD_VV, MASK_VADD_VV) -DECLARE_INSN(vsub_vv, MATCH_VSUB_VV, MASK_VSUB_VV) -DECLARE_INSN(vminu_vv, MATCH_VMINU_VV, MASK_VMINU_VV) -DECLARE_INSN(vmin_vv, MATCH_VMIN_VV, MASK_VMIN_VV) -DECLARE_INSN(vmaxu_vv, MATCH_VMAXU_VV, MASK_VMAXU_VV) -DECLARE_INSN(vmax_vv, MATCH_VMAX_VV, MASK_VMAX_VV) -DECLARE_INSN(vand_vv, MATCH_VAND_VV, MASK_VAND_VV) -DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) -DECLARE_INSN(vxor_vv, MATCH_VXOR_VV, MASK_VXOR_VV) -DECLARE_INSN(vrgather_vv, MATCH_VRGATHER_VV, MASK_VRGATHER_VV) -DECLARE_INSN(vrgatherei16_vv, MATCH_VRGATHEREI16_VV, MASK_VRGATHEREI16_VV) -DECLARE_INSN(vadc_vvm, MATCH_VADC_VVM, MASK_VADC_VVM) -DECLARE_INSN(vmadc_vvm, MATCH_VMADC_VVM, MASK_VMADC_VVM) -DECLARE_INSN(vmadc_vv, MATCH_VMADC_VV, MASK_VMADC_VV) -DECLARE_INSN(vsbc_vvm, MATCH_VSBC_VVM, MASK_VSBC_VVM) -DECLARE_INSN(vmsbc_vvm, MATCH_VMSBC_VVM, MASK_VMSBC_VVM) -DECLARE_INSN(vmsbc_vv, MATCH_VMSBC_VV, MASK_VMSBC_VV) -DECLARE_INSN(vmerge_vvm, MATCH_VMERGE_VVM, MASK_VMERGE_VVM) -DECLARE_INSN(vmv_v_v, MATCH_VMV_V_V, MASK_VMV_V_V) -DECLARE_INSN(vmseq_vv, MATCH_VMSEQ_VV, MASK_VMSEQ_VV) -DECLARE_INSN(vmsne_vv, MATCH_VMSNE_VV, MASK_VMSNE_VV) -DECLARE_INSN(vmsltu_vv, MATCH_VMSLTU_VV, MASK_VMSLTU_VV) -DECLARE_INSN(vmslt_vv, MATCH_VMSLT_VV, MASK_VMSLT_VV) -DECLARE_INSN(vmsleu_vv, MATCH_VMSLEU_VV, MASK_VMSLEU_VV) -DECLARE_INSN(vmsle_vv, MATCH_VMSLE_VV, MASK_VMSLE_VV) -DECLARE_INSN(vsaddu_vv, MATCH_VSADDU_VV, MASK_VSADDU_VV) -DECLARE_INSN(vsadd_vv, MATCH_VSADD_VV, MASK_VSADD_VV) -DECLARE_INSN(vssubu_vv, MATCH_VSSUBU_VV, MASK_VSSUBU_VV) -DECLARE_INSN(vssub_vv, MATCH_VSSUB_VV, MASK_VSSUB_VV) -DECLARE_INSN(vsll_vv, MATCH_VSLL_VV, MASK_VSLL_VV) -DECLARE_INSN(vsmul_vv, MATCH_VSMUL_VV, MASK_VSMUL_VV) -DECLARE_INSN(vsrl_vv, MATCH_VSRL_VV, MASK_VSRL_VV) -DECLARE_INSN(vsra_vv, MATCH_VSRA_VV, MASK_VSRA_VV) -DECLARE_INSN(vssrl_vv, MATCH_VSSRL_VV, MASK_VSSRL_VV) -DECLARE_INSN(vssra_vv, MATCH_VSSRA_VV, MASK_VSSRA_VV) -DECLARE_INSN(vnsrl_wv, MATCH_VNSRL_WV, MASK_VNSRL_WV) -DECLARE_INSN(vnsra_wv, MATCH_VNSRA_WV, MASK_VNSRA_WV) -DECLARE_INSN(vnclipu_wv, MATCH_VNCLIPU_WV, MASK_VNCLIPU_WV) -DECLARE_INSN(vnclip_wv, MATCH_VNCLIP_WV, MASK_VNCLIP_WV) -DECLARE_INSN(vwredsumu_vs, MATCH_VWREDSUMU_VS, MASK_VWREDSUMU_VS) -DECLARE_INSN(vwredsum_vs, MATCH_VWREDSUM_VS, MASK_VWREDSUM_VS) -DECLARE_INSN(vadd_vi, MATCH_VADD_VI, MASK_VADD_VI) -DECLARE_INSN(vrsub_vi, MATCH_VRSUB_VI, MASK_VRSUB_VI) -DECLARE_INSN(vand_vi, MATCH_VAND_VI, MASK_VAND_VI) -DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) -DECLARE_INSN(vxor_vi, MATCH_VXOR_VI, MASK_VXOR_VI) -DECLARE_INSN(vrgather_vi, MATCH_VRGATHER_VI, MASK_VRGATHER_VI) -DECLARE_INSN(vslideup_vi, MATCH_VSLIDEUP_VI, MASK_VSLIDEUP_VI) -DECLARE_INSN(vslidedown_vi, MATCH_VSLIDEDOWN_VI, MASK_VSLIDEDOWN_VI) -DECLARE_INSN(vadc_vim, MATCH_VADC_VIM, MASK_VADC_VIM) -DECLARE_INSN(vmadc_vim, MATCH_VMADC_VIM, MASK_VMADC_VIM) -DECLARE_INSN(vmadc_vi, MATCH_VMADC_VI, MASK_VMADC_VI) -DECLARE_INSN(vmerge_vim, MATCH_VMERGE_VIM, MASK_VMERGE_VIM) -DECLARE_INSN(vmv_v_i, MATCH_VMV_V_I, MASK_VMV_V_I) -DECLARE_INSN(vmseq_vi, MATCH_VMSEQ_VI, MASK_VMSEQ_VI) -DECLARE_INSN(vmsne_vi, MATCH_VMSNE_VI, MASK_VMSNE_VI) -DECLARE_INSN(vmsleu_vi, MATCH_VMSLEU_VI, MASK_VMSLEU_VI) -DECLARE_INSN(vmsle_vi, MATCH_VMSLE_VI, MASK_VMSLE_VI) -DECLARE_INSN(vmsgtu_vi, MATCH_VMSGTU_VI, MASK_VMSGTU_VI) -DECLARE_INSN(vmsgt_vi, MATCH_VMSGT_VI, MASK_VMSGT_VI) -DECLARE_INSN(vsaddu_vi, MATCH_VSADDU_VI, MASK_VSADDU_VI) -DECLARE_INSN(vsadd_vi, MATCH_VSADD_VI, MASK_VSADD_VI) -DECLARE_INSN(vsll_vi, MATCH_VSLL_VI, MASK_VSLL_VI) -DECLARE_INSN(vmv1r_v, MATCH_VMV1R_V, MASK_VMV1R_V) -DECLARE_INSN(vmv2r_v, MATCH_VMV2R_V, MASK_VMV2R_V) -DECLARE_INSN(vmv4r_v, MATCH_VMV4R_V, MASK_VMV4R_V) -DECLARE_INSN(vmv8r_v, MATCH_VMV8R_V, MASK_VMV8R_V) -DECLARE_INSN(vsrl_vi, MATCH_VSRL_VI, MASK_VSRL_VI) -DECLARE_INSN(vsra_vi, MATCH_VSRA_VI, MASK_VSRA_VI) -DECLARE_INSN(vssrl_vi, MATCH_VSSRL_VI, MASK_VSSRL_VI) -DECLARE_INSN(vssra_vi, MATCH_VSSRA_VI, MASK_VSSRA_VI) -DECLARE_INSN(vnsrl_wi, MATCH_VNSRL_WI, MASK_VNSRL_WI) -DECLARE_INSN(vnsra_wi, MATCH_VNSRA_WI, MASK_VNSRA_WI) -DECLARE_INSN(vnclipu_wi, MATCH_VNCLIPU_WI, MASK_VNCLIPU_WI) -DECLARE_INSN(vnclip_wi, MATCH_VNCLIP_WI, MASK_VNCLIP_WI) -DECLARE_INSN(vredsum_vs, MATCH_VREDSUM_VS, MASK_VREDSUM_VS) -DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) -DECLARE_INSN(vredor_vs, MATCH_VREDOR_VS, MASK_VREDOR_VS) -DECLARE_INSN(vredxor_vs, MATCH_VREDXOR_VS, MASK_VREDXOR_VS) -DECLARE_INSN(vredminu_vs, MATCH_VREDMINU_VS, MASK_VREDMINU_VS) -DECLARE_INSN(vredmin_vs, MATCH_VREDMIN_VS, MASK_VREDMIN_VS) -DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) -DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) -DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) -DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) -DECLARE_INSN(vasubu_vv, MATCH_VASUBU_VV, MASK_VASUBU_VV) -DECLARE_INSN(vasub_vv, MATCH_VASUB_VV, MASK_VASUB_VV) -DECLARE_INSN(vmv_x_s, MATCH_VMV_X_S, MASK_VMV_X_S) -DECLARE_INSN(vzext_vf8, MATCH_VZEXT_VF8, MASK_VZEXT_VF8) -DECLARE_INSN(vsext_vf8, MATCH_VSEXT_VF8, MASK_VSEXT_VF8) -DECLARE_INSN(vzext_vf4, MATCH_VZEXT_VF4, MASK_VZEXT_VF4) -DECLARE_INSN(vsext_vf4, MATCH_VSEXT_VF4, MASK_VSEXT_VF4) -DECLARE_INSN(vzext_vf2, MATCH_VZEXT_VF2, MASK_VZEXT_VF2) -DECLARE_INSN(vsext_vf2, MATCH_VSEXT_VF2, MASK_VSEXT_VF2) -DECLARE_INSN(vcompress_vm, MATCH_VCOMPRESS_VM, MASK_VCOMPRESS_VM) -DECLARE_INSN(vmandnot_mm, MATCH_VMANDNOT_MM, MASK_VMANDNOT_MM) -DECLARE_INSN(vmand_mm, MATCH_VMAND_MM, MASK_VMAND_MM) -DECLARE_INSN(vmor_mm, MATCH_VMOR_MM, MASK_VMOR_MM) -DECLARE_INSN(vmxor_mm, MATCH_VMXOR_MM, MASK_VMXOR_MM) -DECLARE_INSN(vmornot_mm, MATCH_VMORNOT_MM, MASK_VMORNOT_MM) -DECLARE_INSN(vmnand_mm, MATCH_VMNAND_MM, MASK_VMNAND_MM) -DECLARE_INSN(vmnor_mm, MATCH_VMNOR_MM, MASK_VMNOR_MM) -DECLARE_INSN(vmxnor_mm, MATCH_VMXNOR_MM, MASK_VMXNOR_MM) -DECLARE_INSN(vmsbf_m, MATCH_VMSBF_M, MASK_VMSBF_M) -DECLARE_INSN(vmsof_m, MATCH_VMSOF_M, MASK_VMSOF_M) -DECLARE_INSN(vmsif_m, MATCH_VMSIF_M, MASK_VMSIF_M) -DECLARE_INSN(viota_m, MATCH_VIOTA_M, MASK_VIOTA_M) -DECLARE_INSN(vid_v, MATCH_VID_V, MASK_VID_V) -DECLARE_INSN(vcpop_m, MATCH_VCPOP_M, MASK_VCPOP_M) -DECLARE_INSN(vfirst_m, MATCH_VFIRST_M, MASK_VFIRST_M) -DECLARE_INSN(vdivu_vv, MATCH_VDIVU_VV, MASK_VDIVU_VV) -DECLARE_INSN(vdiv_vv, MATCH_VDIV_VV, MASK_VDIV_VV) -DECLARE_INSN(vremu_vv, MATCH_VREMU_VV, MASK_VREMU_VV) -DECLARE_INSN(vrem_vv, MATCH_VREM_VV, MASK_VREM_VV) -DECLARE_INSN(vmulhu_vv, MATCH_VMULHU_VV, MASK_VMULHU_VV) -DECLARE_INSN(vmul_vv, MATCH_VMUL_VV, MASK_VMUL_VV) -DECLARE_INSN(vmulhsu_vv, MATCH_VMULHSU_VV, MASK_VMULHSU_VV) -DECLARE_INSN(vmulh_vv, MATCH_VMULH_VV, MASK_VMULH_VV) -DECLARE_INSN(vmadd_vv, MATCH_VMADD_VV, MASK_VMADD_VV) -DECLARE_INSN(vnmsub_vv, MATCH_VNMSUB_VV, MASK_VNMSUB_VV) -DECLARE_INSN(vmacc_vv, MATCH_VMACC_VV, MASK_VMACC_VV) -DECLARE_INSN(vnmsac_vv, MATCH_VNMSAC_VV, MASK_VNMSAC_VV) -DECLARE_INSN(vwaddu_vv, MATCH_VWADDU_VV, MASK_VWADDU_VV) -DECLARE_INSN(vwadd_vv, MATCH_VWADD_VV, MASK_VWADD_VV) -DECLARE_INSN(vwsubu_vv, MATCH_VWSUBU_VV, MASK_VWSUBU_VV) -DECLARE_INSN(vwsub_vv, MATCH_VWSUB_VV, MASK_VWSUB_VV) -DECLARE_INSN(vwaddu_wv, MATCH_VWADDU_WV, MASK_VWADDU_WV) -DECLARE_INSN(vwadd_wv, MATCH_VWADD_WV, MASK_VWADD_WV) -DECLARE_INSN(vwsubu_wv, MATCH_VWSUBU_WV, MASK_VWSUBU_WV) -DECLARE_INSN(vwsub_wv, MATCH_VWSUB_WV, MASK_VWSUB_WV) -DECLARE_INSN(vwmulu_vv, MATCH_VWMULU_VV, MASK_VWMULU_VV) -DECLARE_INSN(vwmulsu_vv, MATCH_VWMULSU_VV, MASK_VWMULSU_VV) -DECLARE_INSN(vwmul_vv, MATCH_VWMUL_VV, MASK_VWMUL_VV) -DECLARE_INSN(vwmaccu_vv, MATCH_VWMACCU_VV, MASK_VWMACCU_VV) -DECLARE_INSN(vwmacc_vv, MATCH_VWMACC_VV, MASK_VWMACC_VV) -DECLARE_INSN(vwmaccsu_vv, MATCH_VWMACCSU_VV, MASK_VWMACCSU_VV) -DECLARE_INSN(vaaddu_vx, MATCH_VAADDU_VX, MASK_VAADDU_VX) -DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) -DECLARE_INSN(vasubu_vx, MATCH_VASUBU_VX, MASK_VASUBU_VX) -DECLARE_INSN(vasub_vx, MATCH_VASUB_VX, MASK_VASUB_VX) -DECLARE_INSN(vmv_s_x, MATCH_VMV_S_X, MASK_VMV_S_X) -DECLARE_INSN(vslide1up_vx, MATCH_VSLIDE1UP_VX, MASK_VSLIDE1UP_VX) -DECLARE_INSN(vslide1down_vx, MATCH_VSLIDE1DOWN_VX, MASK_VSLIDE1DOWN_VX) -DECLARE_INSN(vdivu_vx, MATCH_VDIVU_VX, MASK_VDIVU_VX) -DECLARE_INSN(vdiv_vx, MATCH_VDIV_VX, MASK_VDIV_VX) -DECLARE_INSN(vremu_vx, MATCH_VREMU_VX, MASK_VREMU_VX) -DECLARE_INSN(vrem_vx, MATCH_VREM_VX, MASK_VREM_VX) -DECLARE_INSN(vmulhu_vx, MATCH_VMULHU_VX, MASK_VMULHU_VX) -DECLARE_INSN(vmul_vx, MATCH_VMUL_VX, MASK_VMUL_VX) -DECLARE_INSN(vmulhsu_vx, MATCH_VMULHSU_VX, MASK_VMULHSU_VX) -DECLARE_INSN(vmulh_vx, MATCH_VMULH_VX, MASK_VMULH_VX) -DECLARE_INSN(vmadd_vx, MATCH_VMADD_VX, MASK_VMADD_VX) -DECLARE_INSN(vnmsub_vx, MATCH_VNMSUB_VX, MASK_VNMSUB_VX) -DECLARE_INSN(vmacc_vx, MATCH_VMACC_VX, MASK_VMACC_VX) -DECLARE_INSN(vnmsac_vx, MATCH_VNMSAC_VX, MASK_VNMSAC_VX) -DECLARE_INSN(vwaddu_vx, MATCH_VWADDU_VX, MASK_VWADDU_VX) -DECLARE_INSN(vwadd_vx, MATCH_VWADD_VX, MASK_VWADD_VX) -DECLARE_INSN(vwsubu_vx, MATCH_VWSUBU_VX, MASK_VWSUBU_VX) -DECLARE_INSN(vwsub_vx, MATCH_VWSUB_VX, MASK_VWSUB_VX) -DECLARE_INSN(vwaddu_wx, MATCH_VWADDU_WX, MASK_VWADDU_WX) -DECLARE_INSN(vwadd_wx, MATCH_VWADD_WX, MASK_VWADD_WX) -DECLARE_INSN(vwsubu_wx, MATCH_VWSUBU_WX, MASK_VWSUBU_WX) -DECLARE_INSN(vwsub_wx, MATCH_VWSUB_WX, MASK_VWSUB_WX) -DECLARE_INSN(vwmulu_vx, MATCH_VWMULU_VX, MASK_VWMULU_VX) -DECLARE_INSN(vwmulsu_vx, MATCH_VWMULSU_VX, MASK_VWMULSU_VX) -DECLARE_INSN(vwmul_vx, MATCH_VWMUL_VX, MASK_VWMUL_VX) -DECLARE_INSN(vwmaccu_vx, MATCH_VWMACCU_VX, MASK_VWMACCU_VX) -DECLARE_INSN(vwmacc_vx, MATCH_VWMACC_VX, MASK_VWMACC_VX) -DECLARE_INSN(vwmaccus_vx, MATCH_VWMACCUS_VX, MASK_VWMACCUS_VX) -DECLARE_INSN(vwmaccsu_vx, MATCH_VWMACCSU_VX, MASK_VWMACCSU_VX) -DECLARE_INSN(vamoswapei8_v, MATCH_VAMOSWAPEI8_V, MASK_VAMOSWAPEI8_V) -DECLARE_INSN(vamoaddei8_v, MATCH_VAMOADDEI8_V, MASK_VAMOADDEI8_V) -DECLARE_INSN(vamoxorei8_v, MATCH_VAMOXOREI8_V, MASK_VAMOXOREI8_V) -DECLARE_INSN(vamoandei8_v, MATCH_VAMOANDEI8_V, MASK_VAMOANDEI8_V) -DECLARE_INSN(vamoorei8_v, MATCH_VAMOOREI8_V, MASK_VAMOOREI8_V) -DECLARE_INSN(vamominei8_v, MATCH_VAMOMINEI8_V, MASK_VAMOMINEI8_V) -DECLARE_INSN(vamomaxei8_v, MATCH_VAMOMAXEI8_V, MASK_VAMOMAXEI8_V) -DECLARE_INSN(vamominuei8_v, MATCH_VAMOMINUEI8_V, MASK_VAMOMINUEI8_V) -DECLARE_INSN(vamomaxuei8_v, MATCH_VAMOMAXUEI8_V, MASK_VAMOMAXUEI8_V) -DECLARE_INSN(vamoswapei16_v, MATCH_VAMOSWAPEI16_V, MASK_VAMOSWAPEI16_V) -DECLARE_INSN(vamoaddei16_v, MATCH_VAMOADDEI16_V, MASK_VAMOADDEI16_V) -DECLARE_INSN(vamoxorei16_v, MATCH_VAMOXOREI16_V, MASK_VAMOXOREI16_V) -DECLARE_INSN(vamoandei16_v, MATCH_VAMOANDEI16_V, MASK_VAMOANDEI16_V) -DECLARE_INSN(vamoorei16_v, MATCH_VAMOOREI16_V, MASK_VAMOOREI16_V) -DECLARE_INSN(vamominei16_v, MATCH_VAMOMINEI16_V, MASK_VAMOMINEI16_V) -DECLARE_INSN(vamomaxei16_v, MATCH_VAMOMAXEI16_V, MASK_VAMOMAXEI16_V) -DECLARE_INSN(vamominuei16_v, MATCH_VAMOMINUEI16_V, MASK_VAMOMINUEI16_V) -DECLARE_INSN(vamomaxuei16_v, MATCH_VAMOMAXUEI16_V, MASK_VAMOMAXUEI16_V) -DECLARE_INSN(vamoswapei32_v, MATCH_VAMOSWAPEI32_V, MASK_VAMOSWAPEI32_V) -DECLARE_INSN(vamoaddei32_v, MATCH_VAMOADDEI32_V, MASK_VAMOADDEI32_V) -DECLARE_INSN(vamoxorei32_v, MATCH_VAMOXOREI32_V, MASK_VAMOXOREI32_V) -DECLARE_INSN(vamoandei32_v, MATCH_VAMOANDEI32_V, MASK_VAMOANDEI32_V) -DECLARE_INSN(vamoorei32_v, MATCH_VAMOOREI32_V, MASK_VAMOOREI32_V) -DECLARE_INSN(vamominei32_v, MATCH_VAMOMINEI32_V, MASK_VAMOMINEI32_V) -DECLARE_INSN(vamomaxei32_v, MATCH_VAMOMAXEI32_V, MASK_VAMOMAXEI32_V) -DECLARE_INSN(vamominuei32_v, MATCH_VAMOMINUEI32_V, MASK_VAMOMINUEI32_V) -DECLARE_INSN(vamomaxuei32_v, MATCH_VAMOMAXUEI32_V, MASK_VAMOMAXUEI32_V) -DECLARE_INSN(vamoswapei64_v, MATCH_VAMOSWAPEI64_V, MASK_VAMOSWAPEI64_V) -DECLARE_INSN(vamoaddei64_v, MATCH_VAMOADDEI64_V, MASK_VAMOADDEI64_V) -DECLARE_INSN(vamoxorei64_v, MATCH_VAMOXOREI64_V, MASK_VAMOXOREI64_V) -DECLARE_INSN(vamoandei64_v, MATCH_VAMOANDEI64_V, MASK_VAMOANDEI64_V) -DECLARE_INSN(vamoorei64_v, MATCH_VAMOOREI64_V, MASK_VAMOOREI64_V) -DECLARE_INSN(vamominei64_v, MATCH_VAMOMINEI64_V, MASK_VAMOMINEI64_V) -DECLARE_INSN(vamomaxei64_v, MATCH_VAMOMAXEI64_V, MASK_VAMOMAXEI64_V) -DECLARE_INSN(vamominuei64_v, MATCH_VAMOMINUEI64_V, MASK_VAMOMINUEI64_V) -DECLARE_INSN(vamomaxuei64_v, MATCH_VAMOMAXUEI64_V, MASK_VAMOMAXUEI64_V) -DECLARE_INSN(add8, MATCH_ADD8, MASK_ADD8) +#define MASK_C_SDSP 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_CBO_CLEAN 0x10200f +#define MASK_CBO_CLEAN 0xfff07fff +#define MATCH_CBO_FLUSH 0x20200f +#define MASK_CBO_FLUSH 0xfff07fff +#define MATCH_CBO_INVAL 0x200f +#define MASK_CBO_INVAL 0xfff07fff +#define MATCH_CBO_ZERO 0x40200f +#define MASK_CBO_ZERO 0xfff07fff +#define MATCH_CLMUL 0xa001033 +#define MASK_CLMUL 0xfe00707f +#define MATCH_CLMULH 0xa003033 +#define MASK_CLMULH 0xfe00707f +#define MATCH_CLMULR 0xa002033 +#define MASK_CLMULR 0xfe00707f +#define MATCH_CLO16 0xaeb00077 +#define MASK_CLO16 0xfff0707f +#define MATCH_CLO32 0xafb00077 +#define MASK_CLO32 0xfff0707f +#define MATCH_CLO8 0xae300077 +#define MASK_CLO8 0xfff0707f +#define MATCH_CLRS16 0xae800077 +#define MASK_CLRS16 0xfff0707f +#define MATCH_CLRS32 0xaf800077 +#define MASK_CLRS32 0xfff0707f +#define MATCH_CLRS8 0xae000077 +#define MASK_CLRS8 0xfff0707f +#define MATCH_CLZ 0x60001013 +#define MASK_CLZ 0xfff0707f +#define MATCH_CLZ16 0xae900077 +#define MASK_CLZ16 0xfff0707f +#define MATCH_CLZ32 0xaf900077 +#define MASK_CLZ32 0xfff0707f +#define MATCH_CLZ8 0xae100077 +#define MASK_CLZ8 0xfff0707f +#define MATCH_CLZW 0x6000101b +#define MASK_CLZW 0xfff0707f +#define MATCH_CMIX 0x6001033 +#define MASK_CMIX 0x600707f +#define MATCH_CMOV 0x6005033 +#define MASK_CMOV 0x600707f +#define MATCH_CMPEQ16 0x4c000077 +#define MASK_CMPEQ16 0xfe00707f +#define MATCH_CMPEQ8 0x4e000077 +#define MASK_CMPEQ8 0xfe00707f +#define MATCH_CPOP 0x60201013 +#define MASK_CPOP 0xfff0707f +#define MATCH_CPOPW 0x6020101b +#define MASK_CPOPW 0xfff0707f +#define MATCH_CRAS16 0x44000077 +#define MASK_CRAS16 0xfe00707f +#define MATCH_CRAS32 0x44002077 +#define MASK_CRAS32 0xfe00707f +#define MATCH_CRC32_B 0x61001013 +#define MASK_CRC32_B 0xfff0707f +#define MATCH_CRC32_D 0x61301013 +#define MASK_CRC32_D 0xfff0707f +#define MATCH_CRC32_H 0x61101013 +#define MASK_CRC32_H 0xfff0707f +#define MATCH_CRC32_W 0x61201013 +#define MASK_CRC32_W 0xfff0707f +#define MATCH_CRC32C_B 0x61801013 +#define MASK_CRC32C_B 0xfff0707f +#define MATCH_CRC32C_D 0x61b01013 +#define MASK_CRC32C_D 0xfff0707f +#define MATCH_CRC32C_H 0x61901013 +#define MASK_CRC32C_H 0xfff0707f +#define MATCH_CRC32C_W 0x61a01013 +#define MASK_CRC32C_W 0xfff0707f +#define MATCH_CRSA16 0x46000077 +#define MASK_CRSA16 0xfe00707f +#define MATCH_CRSA32 0x46002077 +#define MASK_CRSA32 0xfe00707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CTZ 0x60101013 +#define MASK_CTZ 0xfff0707f +#define MATCH_CTZW 0x6010101b +#define MASK_CTZW 0xfff0707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FADD_H 0x4000053 +#define MASK_FADD_H 0xfe00007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCLASS_H 0xe4001053 +#define MASK_FCLASS_H 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_D_H 0x42200053 +#define MASK_FCVT_D_H 0xfff0007f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_H_D 0x44100053 +#define MASK_FCVT_H_D 0xfff0007f +#define MATCH_FCVT_H_L 0xd4200053 +#define MASK_FCVT_H_L 0xfff0007f +#define MATCH_FCVT_H_LU 0xd4300053 +#define MASK_FCVT_H_LU 0xfff0007f +#define MATCH_FCVT_H_Q 0x44300053 +#define MASK_FCVT_H_Q 0xfff0007f +#define MATCH_FCVT_H_S 0x44000053 +#define MASK_FCVT_H_S 0xfff0007f +#define MATCH_FCVT_H_W 0xd4000053 +#define MASK_FCVT_H_W 0xfff0007f +#define MATCH_FCVT_H_WU 0xd4100053 +#define MASK_FCVT_H_WU 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_L_H 0xc4200053 +#define MASK_FCVT_L_H 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FCVT_LU_H 0xc4300053 +#define MASK_FCVT_LU_H 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FCVT_Q_H 0x46200053 +#define MASK_FCVT_Q_H 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_S_H 0x40200053 +#define MASK_FCVT_S_H 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_W_H 0xc4000053 +#define MASK_FCVT_W_H 0xfff0007f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_WU_H 0xc4100053 +#define MASK_FCVT_WU_H 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FDIV_H 0x1c000053 +#define MASK_FDIV_H 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FEQ_H 0xa4002053 +#define MASK_FEQ_H 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLE_H 0xa4000053 +#define MASK_FLE_H 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLH 0x1007 +#define MASK_FLH 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FLT_H 0xa4001053 +#define MASK_FLT_H 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMADD_H 0x4000043 +#define MASK_FMADD_H 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FMAX_H 0x2c001053 +#define MASK_FMAX_H 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMIN_H 0x2c000053 +#define MASK_FMIN_H 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FMSUB_H 0x4000047 +#define MASK_FMSUB_H 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FMUL_H 0x14000053 +#define MASK_FMUL_H 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FMV_H_X 0xf4000053 +#define MASK_FMV_H_X 0xfff0707f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FMV_X_H 0xe4000053 +#define MASK_FMV_X_H 0xfff0707f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FNMADD_H 0x400004f +#define MASK_FNMADD_H 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMSUB_H 0x400004b +#define MASK_FNMSUB_H 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJ_H 0x24000053 +#define MASK_FSGNJ_H 0xfe00707f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJN_H 0x24001053 +#define MASK_FSGNJN_H 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FSGNJX_H 0x24002053 +#define MASK_FSGNJX_H 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FSH 0x1027 +#define MASK_FSH 0x707f +#define MATCH_FSL 0x4001033 +#define MASK_FSL 0x600707f +#define MATCH_FSLW 0x400103b +#define MASK_FSLW 0x600707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FSQRT_H 0x5c000053 +#define MASK_FSQRT_H 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FSR 0x4005033 +#define MASK_FSR 0x600707f +#define MATCH_FSRI 0x4005013 +#define MASK_FSRI 0x400707f +#define MATCH_FSRIW 0x400501b +#define MASK_FSRIW 0x600707f +#define MATCH_FSRW 0x400503b +#define MASK_FSRW 0x600707f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FSUB_H 0xc000053 +#define MASK_FSUB_H 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_GORC 0x28005033 +#define MASK_GORC 0xfe00707f +#define MATCH_GORCI 0x28005013 +#define MASK_GORCI 0xfc00707f +#define MATCH_GORCIW 0x2800501b +#define MASK_GORCIW 0xfe00707f +#define MATCH_GORCW 0x2800503b +#define MASK_GORCW 0xfe00707f +#define MATCH_GREV 0x68005033 +#define MASK_GREV 0xfe00707f +#define MATCH_GREVI 0x68005013 +#define MASK_GREVI 0xfc00707f +#define MATCH_GREVIW 0x6800501b +#define MASK_GREVIW 0xfe00707f +#define MATCH_GREVW 0x6800503b +#define MASK_GREVW 0xfe00707f +#define MATCH_HFENCE_GVMA 0x62000073 +#define MASK_HFENCE_GVMA 0xfe007fff +#define MATCH_HFENCE_VVMA 0x22000073 +#define MASK_HFENCE_VVMA 0xfe007fff +#define MATCH_HINVAL_GVMA 0x66000073 +#define MASK_HINVAL_GVMA 0xfe007fff +#define MATCH_HINVAL_VVMA 0x26000073 +#define MASK_HINVAL_VVMA 0xfe007fff +#define MATCH_HLV_B 0x60004073 +#define MASK_HLV_B 0xfff0707f +#define MATCH_HLV_BU 0x60104073 +#define MASK_HLV_BU 0xfff0707f +#define MATCH_HLV_D 0x6c004073 +#define MASK_HLV_D 0xfff0707f +#define MATCH_HLV_H 0x64004073 +#define MASK_HLV_H 0xfff0707f +#define MATCH_HLV_HU 0x64104073 +#define MASK_HLV_HU 0xfff0707f +#define MATCH_HLV_W 0x68004073 +#define MASK_HLV_W 0xfff0707f +#define MATCH_HLV_WU 0x68104073 +#define MASK_HLV_WU 0xfff0707f +#define MATCH_HLVX_HU 0x64304073 +#define MASK_HLVX_HU 0xfff0707f +#define MATCH_HLVX_WU 0x68304073 +#define MASK_HLVX_WU 0xfff0707f +#define MATCH_HSV_B 0x62004073 +#define MASK_HSV_B 0xfe007fff +#define MATCH_HSV_D 0x6e004073 +#define MASK_HSV_D 0xfe007fff +#define MATCH_HSV_H 0x66004073 +#define MASK_HSV_H 0xfe007fff +#define MATCH_HSV_W 0x6a004073 +#define MASK_HSV_W 0xfe007fff +#define MATCH_INSB 0xac000077 +#define MASK_INSB 0xff80707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_KABS16 0xad100077 +#define MASK_KABS16 0xfff0707f +#define MATCH_KABS32 0xad200077 +#define MASK_KABS32 0xfff0707f +#define MATCH_KABS8 0xad000077 +#define MASK_KABS8 0xfff0707f +#define MATCH_KABSW 0xad400077 +#define MASK_KABSW 0xfff0707f +#define MATCH_KADD16 0x10000077 +#define MASK_KADD16 0xfe00707f +#define MATCH_KADD32 0x10002077 +#define MASK_KADD32 0xfe00707f +#define MATCH_KADD64 0x90001077 +#define MASK_KADD64 0xfe00707f +#define MATCH_KADD8 0x18000077 +#define MASK_KADD8 0xfe00707f +#define MATCH_KADDH 0x4001077 +#define MASK_KADDH 0xfe00707f +#define MATCH_KADDW 0x1077 +#define MASK_KADDW 0xfe00707f +#define MATCH_KCRAS16 0x14000077 +#define MASK_KCRAS16 0xfe00707f +#define MATCH_KCRAS32 0x14002077 +#define MASK_KCRAS32 0xfe00707f +#define MATCH_KCRSA16 0x16000077 +#define MASK_KCRSA16 0xfe00707f +#define MATCH_KCRSA32 0x16002077 +#define MASK_KCRSA32 0xfe00707f +#define MATCH_KDMABB 0xd2001077 +#define MASK_KDMABB 0xfe00707f +#define MATCH_KDMABB16 0xd8001077 +#define MASK_KDMABB16 0xfe00707f +#define MATCH_KDMABT 0xe2001077 +#define MASK_KDMABT 0xfe00707f +#define MATCH_KDMABT16 0xe8001077 +#define MASK_KDMABT16 0xfe00707f +#define MATCH_KDMATT 0xf2001077 +#define MASK_KDMATT 0xfe00707f +#define MATCH_KDMATT16 0xf8001077 +#define MASK_KDMATT16 0xfe00707f +#define MATCH_KDMBB 0xa001077 +#define MASK_KDMBB 0xfe00707f +#define MATCH_KDMBB16 0xda001077 +#define MASK_KDMBB16 0xfe00707f +#define MATCH_KDMBT 0x1a001077 +#define MASK_KDMBT 0xfe00707f +#define MATCH_KDMBT16 0xea001077 +#define MASK_KDMBT16 0xfe00707f +#define MATCH_KDMTT 0x2a001077 +#define MASK_KDMTT 0xfe00707f +#define MATCH_KDMTT16 0xfa001077 +#define MASK_KDMTT16 0xfe00707f +#define MATCH_KHM16 0x86000077 +#define MASK_KHM16 0xfe00707f +#define MATCH_KHM8 0x8e000077 +#define MASK_KHM8 0xfe00707f +#define MATCH_KHMBB 0xc001077 +#define MASK_KHMBB 0xfe00707f +#define MATCH_KHMBB16 0xdc001077 +#define MASK_KHMBB16 0xfe00707f +#define MATCH_KHMBT 0x1c001077 +#define MASK_KHMBT 0xfe00707f +#define MATCH_KHMBT16 0xec001077 +#define MASK_KHMBT16 0xfe00707f +#define MATCH_KHMTT 0x2c001077 +#define MASK_KHMTT 0xfe00707f +#define MATCH_KHMTT16 0xfc001077 +#define MASK_KHMTT16 0xfe00707f +#define MATCH_KHMX16 0x96000077 +#define MASK_KHMX16 0xfe00707f +#define MATCH_KHMX8 0x9e000077 +#define MASK_KHMX8 0xfe00707f +#define MATCH_KMABB 0x5a001077 +#define MASK_KMABB 0xfe00707f +#define MATCH_KMABB32 0x5a002077 +#define MASK_KMABB32 0xfe00707f +#define MATCH_KMABT 0x6a001077 +#define MASK_KMABT 0xfe00707f +#define MATCH_KMABT32 0x6a002077 +#define MASK_KMABT32 0xfe00707f +#define MATCH_KMADA 0x48001077 +#define MASK_KMADA 0xfe00707f +#define MATCH_KMADRS 0x6c001077 +#define MASK_KMADRS 0xfe00707f +#define MATCH_KMADRS32 0x6c002077 +#define MASK_KMADRS32 0xfe00707f +#define MATCH_KMADS 0x5c001077 +#define MASK_KMADS 0xfe00707f +#define MATCH_KMADS32 0x5c002077 +#define MASK_KMADS32 0xfe00707f +#define MATCH_KMAR64 0x94001077 +#define MASK_KMAR64 0xfe00707f +#define MATCH_KMATT 0x7a001077 +#define MASK_KMATT 0xfe00707f +#define MATCH_KMATT32 0x7a002077 +#define MASK_KMATT32 0xfe00707f +#define MATCH_KMAXDA 0x4a001077 +#define MASK_KMAXDA 0xfe00707f +#define MATCH_KMAXDA32 0x4a002077 +#define MASK_KMAXDA32 0xfe00707f +#define MATCH_KMAXDS 0x7c001077 +#define MASK_KMAXDS 0xfe00707f +#define MATCH_KMAXDS32 0x7c002077 +#define MASK_KMAXDS32 0xfe00707f +#define MATCH_KMDA 0x38001077 +#define MASK_KMDA 0xfe00707f +#define MATCH_KMDA32 0x38002077 +#define MASK_KMDA32 0xfe00707f +#define MATCH_KMMAC 0x60001077 +#define MASK_KMMAC 0xfe00707f +#define MATCH_KMMAC_U 0x70001077 +#define MASK_KMMAC_U 0xfe00707f +#define MATCH_KMMAWB 0x46001077 +#define MASK_KMMAWB 0xfe00707f +#define MATCH_KMMAWB2 0xce001077 +#define MASK_KMMAWB2 0xfe00707f +#define MATCH_KMMAWB2_U 0xde001077 +#define MASK_KMMAWB2_U 0xfe00707f +#define MATCH_KMMAWB_U 0x56001077 +#define MASK_KMMAWB_U 0xfe00707f +#define MATCH_KMMAWT 0x66001077 +#define MASK_KMMAWT 0xfe00707f +#define MATCH_KMMAWT2 0xee001077 +#define MASK_KMMAWT2 0xfe00707f +#define MATCH_KMMAWT2_U 0xfe001077 +#define MASK_KMMAWT2_U 0xfe00707f +#define MATCH_KMMAWT_U 0x76001077 +#define MASK_KMMAWT_U 0xfe00707f +#define MATCH_KMMSB 0x42001077 +#define MASK_KMMSB 0xfe00707f +#define MATCH_KMMSB_U 0x52001077 +#define MASK_KMMSB_U 0xfe00707f +#define MATCH_KMMWB2 0x8e001077 +#define MASK_KMMWB2 0xfe00707f +#define MATCH_KMMWB2_U 0x9e001077 +#define MASK_KMMWB2_U 0xfe00707f +#define MATCH_KMMWT2 0xae001077 +#define MASK_KMMWT2 0xfe00707f +#define MATCH_KMMWT2_U 0xbe001077 +#define MASK_KMMWT2_U 0xfe00707f +#define MATCH_KMSDA 0x4c001077 +#define MASK_KMSDA 0xfe00707f +#define MATCH_KMSDA32 0x4c002077 +#define MASK_KMSDA32 0xfe00707f +#define MATCH_KMSR64 0x96001077 +#define MASK_KMSR64 0xfe00707f +#define MATCH_KMSXDA 0x4e001077 +#define MASK_KMSXDA 0xfe00707f +#define MATCH_KMSXDA32 0x4e002077 +#define MASK_KMSXDA32 0xfe00707f +#define MATCH_KMXDA 0x3a001077 +#define MASK_KMXDA 0xfe00707f +#define MATCH_KMXDA32 0x3a002077 +#define MASK_KMXDA32 0xfe00707f +#define MATCH_KSLL16 0x64000077 +#define MASK_KSLL16 0xfe00707f +#define MATCH_KSLL32 0x64002077 +#define MASK_KSLL32 0xfe00707f +#define MATCH_KSLL8 0x6c000077 +#define MASK_KSLL8 0xfe00707f +#define MATCH_KSLLI16 0x75000077 +#define MASK_KSLLI16 0xff00707f +#define MATCH_KSLLI32 0x84002077 +#define MASK_KSLLI32 0xfe00707f +#define MATCH_KSLLI8 0x7c800077 +#define MASK_KSLLI8 0xff80707f +#define MATCH_KSLLIW 0x36001077 +#define MASK_KSLLIW 0xfe00707f +#define MATCH_KSLLW 0x26001077 +#define MASK_KSLLW 0xfe00707f +#define MATCH_KSLRA16 0x56000077 +#define MASK_KSLRA16 0xfe00707f +#define MATCH_KSLRA16_U 0x66000077 +#define MASK_KSLRA16_U 0xfe00707f +#define MATCH_KSLRA32 0x56002077 +#define MASK_KSLRA32 0xfe00707f +#define MATCH_KSLRA32_U 0x66002077 +#define MASK_KSLRA32_U 0xfe00707f +#define MATCH_KSLRA8 0x5e000077 +#define MASK_KSLRA8 0xfe00707f +#define MATCH_KSLRA8_U 0x6e000077 +#define MASK_KSLRA8_U 0xfe00707f +#define MATCH_KSLRAW 0x6e001077 +#define MASK_KSLRAW 0xfe00707f +#define MATCH_KSLRAW_U 0x7e001077 +#define MASK_KSLRAW_U 0xfe00707f +#define MATCH_KSTAS16 0xc4002077 +#define MASK_KSTAS16 0xfe00707f +#define MATCH_KSTAS32 0xc0002077 +#define MASK_KSTAS32 0xfe00707f +#define MATCH_KSTSA16 0xc6002077 +#define MASK_KSTSA16 0xfe00707f +#define MATCH_KSTSA32 0xc2002077 +#define MASK_KSTSA32 0xfe00707f +#define MATCH_KSUB16 0x12000077 +#define MASK_KSUB16 0xfe00707f +#define MATCH_KSUB32 0x12002077 +#define MASK_KSUB32 0xfe00707f +#define MATCH_KSUB64 0x92001077 +#define MASK_KSUB64 0xfe00707f +#define MATCH_KSUB8 0x1a000077 +#define MASK_KSUB8 0xfe00707f +#define MATCH_KSUBH 0x6001077 +#define MASK_KSUBH 0xfe00707f +#define MATCH_KSUBW 0x2001077 +#define MASK_KSUBW 0xfe00707f +#define MATCH_KWMMUL 0x62001077 +#define MASK_KWMMUL 0xfe00707f +#define MATCH_KWMMUL_U 0x72001077 +#define MASK_KWMMUL_U 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_MADDR32 0xc4001077 +#define MASK_MADDR32 0xfe00707f +#define MATCH_MAX 0xa006033 +#define MASK_MAX 0xfe00707f +#define MATCH_MAXU 0xa007033 +#define MASK_MAXU 0xfe00707f +#define MATCH_MAXW 0xf2000077 +#define MASK_MAXW 0xfe00707f +#define MATCH_MIN 0xa004033 +#define MASK_MIN 0xfe00707f +#define MATCH_MINU 0xa005033 +#define MASK_MINU 0xfe00707f +#define MATCH_MINW 0xf0000077 +#define MASK_MINW 0xfe00707f +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_MSUBR32 0xc6001077 +#define MASK_MSUBR32 0xfe00707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_MULR64 0xf0001077 +#define MASK_MULR64 0xfe00707f +#define MATCH_MULSR64 0xe0001077 +#define MASK_MULSR64 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ORN 0x40006033 +#define MASK_ORN 0xfe00707f +#define MATCH_PACK 0x8004033 +#define MASK_PACK 0xfe00707f +#define MATCH_PACKH 0x8007033 +#define MASK_PACKH 0xfe00707f +#define MATCH_PACKU 0x48004033 +#define MASK_PACKU 0xfe00707f +#define MATCH_PACKUW 0x4800403b +#define MASK_PACKUW 0xfe00707f +#define MATCH_PACKW 0x800403b +#define MASK_PACKW 0xfe00707f +#define MATCH_PAUSE 0x100000f +#define MASK_PAUSE 0xffffffff +#define MATCH_PBSAD 0xfc000077 +#define MASK_PBSAD 0xfe00707f +#define MATCH_PBSADA 0xfe000077 +#define MASK_PBSADA 0xfe00707f +#define MATCH_PKBB16 0xe001077 +#define MASK_PKBB16 0xfe00707f +#define MATCH_PKBB32 0xe002077 +#define MASK_PKBB32 0xfe00707f +#define MATCH_PKBT16 0x1e001077 +#define MASK_PKBT16 0xfe00707f +#define MATCH_PKBT32 0x1e002077 +#define MASK_PKBT32 0xfe00707f +#define MATCH_PKTB16 0x3e001077 +#define MASK_PKTB16 0xfe00707f +#define MATCH_PKTB32 0x3e002077 +#define MASK_PKTB32 0xfe00707f +#define MATCH_PKTT16 0x2e001077 +#define MASK_PKTT16 0xfe00707f +#define MATCH_PKTT32 0x2e002077 +#define MASK_PKTT32 0xfe00707f +#define MATCH_PREFETCH_I 0x6013 +#define MASK_PREFETCH_I 0x1f07fff +#define MATCH_PREFETCH_R 0x106013 +#define MASK_PREFETCH_R 0x1f07fff +#define MATCH_PREFETCH_W 0x306013 +#define MASK_PREFETCH_W 0x1f07fff +#define MATCH_RADD16 0x77 +#define MASK_RADD16 0xfe00707f +#define MATCH_RADD32 0x2077 +#define MASK_RADD32 0xfe00707f +#define MATCH_RADD64 0x80001077 +#define MASK_RADD64 0xfe00707f +#define MATCH_RADD8 0x8000077 +#define MASK_RADD8 0xfe00707f +#define MATCH_RADDW 0x20001077 +#define MASK_RADDW 0xfe00707f +#define MATCH_RCRAS16 0x4000077 +#define MASK_RCRAS16 0xfe00707f +#define MATCH_RCRAS32 0x4002077 +#define MASK_RCRAS32 0xfe00707f +#define MATCH_RCRSA16 0x6000077 +#define MASK_RCRSA16 0xfe00707f +#define MATCH_RCRSA32 0x6002077 +#define MASK_RCRSA32 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_ROL 0x60001033 +#define MASK_ROL 0xfe00707f +#define MATCH_ROLW 0x6000103b +#define MASK_ROLW 0xfe00707f +#define MATCH_ROR 0x60005033 +#define MASK_ROR 0xfe00707f +#define MATCH_RORI 0x60005013 +#define MASK_RORI 0xfc00707f +#define MATCH_RORIW 0x6000501b +#define MASK_RORIW 0xfe00707f +#define MATCH_RORW 0x6000503b +#define MASK_RORW 0xfe00707f +#define MATCH_RSTAS16 0xb4002077 +#define MASK_RSTAS16 0xfe00707f +#define MATCH_RSTAS32 0xb0002077 +#define MASK_RSTAS32 0xfe00707f +#define MATCH_RSTSA16 0xb6002077 +#define MASK_RSTSA16 0xfe00707f +#define MATCH_RSTSA32 0xb2002077 +#define MASK_RSTSA32 0xfe00707f +#define MATCH_RSUB16 0x2000077 +#define MASK_RSUB16 0xfe00707f +#define MATCH_RSUB32 0x2002077 +#define MASK_RSUB32 0xfe00707f +#define MATCH_RSUB64 0x82001077 +#define MASK_RSUB64 0xfe00707f +#define MATCH_RSUB8 0xa000077 +#define MASK_RSUB8 0xfe00707f +#define MATCH_RSUBW 0x22001077 +#define MASK_RSUBW 0xfe00707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_SCLIP16 0x84000077 +#define MASK_SCLIP16 0xff00707f +#define MATCH_SCLIP32 0xe4000077 +#define MASK_SCLIP32 0xfe00707f +#define MATCH_SCLIP8 0x8c000077 +#define MASK_SCLIP8 0xff80707f +#define MATCH_SCMPLE16 0x1c000077 +#define MASK_SCMPLE16 0xfe00707f +#define MATCH_SCMPLE8 0x1e000077 +#define MASK_SCMPLE8 0xfe00707f +#define MATCH_SCMPLT16 0xc000077 +#define MASK_SCMPLT16 0xfe00707f +#define MATCH_SCMPLT8 0xe000077 +#define MASK_SCMPLT8 0xfe00707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_SEXT_B 0x60401013 +#define MASK_SEXT_B 0xfff0707f +#define MATCH_SEXT_H 0x60501013 +#define MASK_SEXT_H 0xfff0707f +#define MATCH_SFENCE_INVAL_IR 0x18100073 +#define MASK_SFENCE_INVAL_IR 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_SFENCE_W_INVAL 0x18000073 +#define MASK_SFENCE_W_INVAL 0xffffffff +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SH1ADD 0x20002033 +#define MASK_SH1ADD 0xfe00707f +#define MATCH_SH1ADD_UW 0x2000203b +#define MASK_SH1ADD_UW 0xfe00707f +#define MATCH_SH2ADD 0x20004033 +#define MASK_SH2ADD 0xfe00707f +#define MATCH_SH2ADD_UW 0x2000403b +#define MASK_SH2ADD_UW 0xfe00707f +#define MATCH_SH3ADD 0x20006033 +#define MASK_SH3ADD 0xfe00707f +#define MATCH_SH3ADD_UW 0x2000603b +#define MASK_SH3ADD_UW 0xfe00707f +#define MATCH_SHA256SIG0 0x10201013 +#define MASK_SHA256SIG0 0xfff0707f +#define MATCH_SHA256SIG1 0x10301013 +#define MASK_SHA256SIG1 0xfff0707f +#define MATCH_SHA256SUM0 0x10001013 +#define MASK_SHA256SUM0 0xfff0707f +#define MATCH_SHA256SUM1 0x10101013 +#define MASK_SHA256SUM1 0xfff0707f +#define MATCH_SHA512SIG0 0x10601013 +#define MASK_SHA512SIG0 0xfff0707f +#define MATCH_SHA512SIG0H 0x5c000033 +#define MASK_SHA512SIG0H 0xfe00707f +#define MATCH_SHA512SIG0L 0x54000033 +#define MASK_SHA512SIG0L 0xfe00707f +#define MATCH_SHA512SIG1 0x10701013 +#define MASK_SHA512SIG1 0xfff0707f +#define MATCH_SHA512SIG1H 0x5e000033 +#define MASK_SHA512SIG1H 0xfe00707f +#define MATCH_SHA512SIG1L 0x56000033 +#define MASK_SHA512SIG1L 0xfe00707f +#define MATCH_SHA512SUM0 0x10401013 +#define MASK_SHA512SUM0 0xfff0707f +#define MATCH_SHA512SUM0R 0x50000033 +#define MASK_SHA512SUM0R 0xfe00707f +#define MATCH_SHA512SUM1 0x10501013 +#define MASK_SHA512SUM1 0xfff0707f +#define MATCH_SHA512SUM1R 0x52000033 +#define MASK_SHA512SUM1R 0xfe00707f +#define MATCH_SHFL 0x8001033 +#define MASK_SHFL 0xfe00707f +#define MATCH_SHFLI 0x8001013 +#define MASK_SHFLI 0xfe00707f +#define MATCH_SHFLW 0x800103b +#define MASK_SHFLW 0xfe00707f +#define MATCH_SINVAL_VMA 0x16000073 +#define MASK_SINVAL_VMA 0xfe007fff +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLL16 0x54000077 +#define MASK_SLL16 0xfe00707f +#define MATCH_SLL32 0x54002077 +#define MASK_SLL32 0xfe00707f +#define MATCH_SLL8 0x5c000077 +#define MASK_SLL8 0xfe00707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLLI16 0x74000077 +#define MASK_SLLI16 0xff00707f +#define MATCH_SLLI32 0x74002077 +#define MASK_SLLI32 0xfe00707f +#define MATCH_SLLI8 0x7c000077 +#define MASK_SLLI8 0xff80707f +#define MATCH_SLLI_UW 0x800101b +#define MASK_SLLI_UW 0xfc00707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SLO 0x20001033 +#define MASK_SLO 0xfe00707f +#define MATCH_SLOI 0x20001013 +#define MASK_SLOI 0xfc00707f +#define MATCH_SLOIW 0x2000101b +#define MASK_SLOIW 0xfe00707f +#define MATCH_SLOW 0x2000103b +#define MASK_SLOW 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_SM3P0 0x10801013 +#define MASK_SM3P0 0xfff0707f +#define MATCH_SM3P1 0x10901013 +#define MASK_SM3P1 0xfff0707f +#define MATCH_SM4ED 0x30000033 +#define MASK_SM4ED 0x3e00707f +#define MATCH_SM4KS 0x34000033 +#define MASK_SM4KS 0x3e00707f +#define MATCH_SMAL 0x5e001077 +#define MASK_SMAL 0xfe00707f +#define MATCH_SMALBB 0x88001077 +#define MASK_SMALBB 0xfe00707f +#define MATCH_SMALBT 0x98001077 +#define MASK_SMALBT 0xfe00707f +#define MATCH_SMALDA 0x8c001077 +#define MASK_SMALDA 0xfe00707f +#define MATCH_SMALDRS 0x9a001077 +#define MASK_SMALDRS 0xfe00707f +#define MATCH_SMALDS 0x8a001077 +#define MASK_SMALDS 0xfe00707f +#define MATCH_SMALTT 0xa8001077 +#define MASK_SMALTT 0xfe00707f +#define MATCH_SMALXDA 0x9c001077 +#define MASK_SMALXDA 0xfe00707f +#define MATCH_SMALXDS 0xaa001077 +#define MASK_SMALXDS 0xfe00707f +#define MATCH_SMAQA 0xc8000077 +#define MASK_SMAQA 0xfe00707f +#define MATCH_SMAQA_SU 0xca000077 +#define MASK_SMAQA_SU 0xfe00707f +#define MATCH_SMAR64 0x84001077 +#define MASK_SMAR64 0xfe00707f +#define MATCH_SMAX16 0x82000077 +#define MASK_SMAX16 0xfe00707f +#define MATCH_SMAX32 0x92002077 +#define MASK_SMAX32 0xfe00707f +#define MATCH_SMAX8 0x8a000077 +#define MASK_SMAX8 0xfe00707f +#define MATCH_SMBB16 0x8001077 +#define MASK_SMBB16 0xfe00707f +#define MATCH_SMBT16 0x18001077 +#define MASK_SMBT16 0xfe00707f +#define MATCH_SMBT32 0x18002077 +#define MASK_SMBT32 0xfe00707f +#define MATCH_SMDRS 0x68001077 +#define MASK_SMDRS 0xfe00707f +#define MATCH_SMDRS32 0x68002077 +#define MASK_SMDRS32 0xfe00707f +#define MATCH_SMDS 0x58001077 +#define MASK_SMDS 0xfe00707f +#define MATCH_SMDS32 0x58002077 +#define MASK_SMDS32 0xfe00707f +#define MATCH_SMIN16 0x80000077 +#define MASK_SMIN16 0xfe00707f +#define MATCH_SMIN32 0x90002077 +#define MASK_SMIN32 0xfe00707f +#define MATCH_SMIN8 0x88000077 +#define MASK_SMIN8 0xfe00707f +#define MATCH_SMMUL 0x40001077 +#define MASK_SMMUL 0xfe00707f +#define MATCH_SMMUL_U 0x50001077 +#define MASK_SMMUL_U 0xfe00707f +#define MATCH_SMMWB 0x44001077 +#define MASK_SMMWB 0xfe00707f +#define MATCH_SMMWB_U 0x54001077 +#define MASK_SMMWB_U 0xfe00707f +#define MATCH_SMMWT 0x64001077 +#define MASK_SMMWT 0xfe00707f +#define MATCH_SMMWT_U 0x74001077 +#define MASK_SMMWT_U 0xfe00707f +#define MATCH_SMSLDA 0xac001077 +#define MASK_SMSLDA 0xfe00707f +#define MATCH_SMSLXDA 0xbc001077 +#define MASK_SMSLXDA 0xfe00707f +#define MATCH_SMSR64 0x86001077 +#define MASK_SMSR64 0xfe00707f +#define MATCH_SMTT16 0x28001077 +#define MASK_SMTT16 0xfe00707f +#define MATCH_SMTT32 0x28002077 +#define MASK_SMTT32 0xfe00707f +#define MATCH_SMUL16 0xa0000077 +#define MASK_SMUL16 0xfe00707f +#define MATCH_SMUL8 0xa8000077 +#define MASK_SMUL8 0xfe00707f +#define MATCH_SMULX16 0xa2000077 +#define MASK_SMULX16 0xfe00707f +#define MATCH_SMULX8 0xaa000077 +#define MASK_SMULX8 0xfe00707f +#define MATCH_SMXDS 0x78001077 +#define MASK_SMXDS 0xfe00707f +#define MATCH_SMXDS32 0x78002077 +#define MASK_SMXDS32 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_SRA16 0x50000077 +#define MASK_SRA16 0xfe00707f +#define MATCH_SRA16_U 0x60000077 +#define MASK_SRA16_U 0xfe00707f +#define MATCH_SRA32 0x50002077 +#define MASK_SRA32 0xfe00707f +#define MATCH_SRA32_U 0x60002077 +#define MASK_SRA32_U 0xfe00707f +#define MATCH_SRA8 0x58000077 +#define MASK_SRA8 0xfe00707f +#define MATCH_SRA8_U 0x68000077 +#define MASK_SRA8_U 0xfe00707f +#define MATCH_SRA_U 0x24001077 +#define MASK_SRA_U 0xfe00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_SRAI16 0x70000077 +#define MASK_SRAI16 0xff00707f +#define MATCH_SRAI16_U 0x71000077 +#define MASK_SRAI16_U 0xff00707f +#define MATCH_SRAI32 0x70002077 +#define MASK_SRAI32 0xfe00707f +#define MATCH_SRAI32_U 0x80002077 +#define MASK_SRAI32_U 0xfe00707f +#define MATCH_SRAI8 0x78000077 +#define MASK_SRAI8 0xff80707f +#define MATCH_SRAI8_U 0x78800077 +#define MASK_SRAI8_U 0xff80707f +#define MATCH_SRAI_U 0xd4001077 +#define MASK_SRAI_U 0xfc00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_SRAIW_U 0x34001077 +#define MASK_SRAIW_U 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRL16 0x52000077 +#define MASK_SRL16 0xfe00707f +#define MATCH_SRL16_U 0x62000077 +#define MASK_SRL16_U 0xfe00707f +#define MATCH_SRL32 0x52002077 +#define MASK_SRL32 0xfe00707f +#define MATCH_SRL32_U 0x62002077 +#define MASK_SRL32_U 0xfe00707f +#define MATCH_SRL8 0x5a000077 +#define MASK_SRL8 0xfe00707f +#define MATCH_SRL8_U 0x6a000077 +#define MASK_SRL8_U 0xfe00707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRLI16 0x72000077 +#define MASK_SRLI16 0xff00707f +#define MATCH_SRLI16_U 0x73000077 +#define MASK_SRLI16_U 0xff00707f +#define MATCH_SRLI32 0x72002077 +#define MASK_SRLI32 0xfe00707f +#define MATCH_SRLI32_U 0x82002077 +#define MASK_SRLI32_U 0xfe00707f +#define MATCH_SRLI8 0x7a000077 +#define MASK_SRLI8 0xff80707f +#define MATCH_SRLI8_U 0x7a800077 +#define MASK_SRLI8_U 0xff80707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRO 0x20005033 +#define MASK_SRO 0xfe00707f +#define MATCH_SROI 0x20005013 +#define MASK_SROI 0xfc00707f +#define MATCH_SROIW 0x2000501b +#define MASK_SROIW 0xfe00707f +#define MATCH_SROW 0x2000503b +#define MASK_SROW 0xfe00707f +#define MATCH_STAS16 0xf4002077 +#define MASK_STAS16 0xfe00707f +#define MATCH_STAS32 0xf0002077 +#define MASK_STAS32 0xfe00707f +#define MATCH_STSA16 0xf6002077 +#define MASK_STSA16 0xfe00707f +#define MATCH_STSA32 0xf2002077 +#define MASK_STSA32 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SUB16 0x42000077 +#define MASK_SUB16 0xfe00707f +#define MATCH_SUB32 0x42002077 +#define MASK_SUB32 0xfe00707f +#define MATCH_SUB64 0xc2001077 +#define MASK_SUB64 0xfe00707f +#define MATCH_SUB8 0x4a000077 +#define MASK_SUB8 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SUNPKD810 0xac800077 +#define MASK_SUNPKD810 0xfff0707f +#define MATCH_SUNPKD820 0xac900077 +#define MASK_SUNPKD820 0xfff0707f +#define MATCH_SUNPKD830 0xaca00077 +#define MASK_SUNPKD830 0xfff0707f +#define MATCH_SUNPKD831 0xacb00077 +#define MASK_SUNPKD831 0xfff0707f +#define MATCH_SUNPKD832 0xad300077 +#define MASK_SUNPKD832 0xfff0707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_SWAP8 0xad800077 +#define MASK_SWAP8 0xfff0707f +#define MATCH_UCLIP16 0x85000077 +#define MASK_UCLIP16 0xff00707f +#define MATCH_UCLIP32 0xf4000077 +#define MASK_UCLIP32 0xfe00707f +#define MATCH_UCLIP8 0x8d000077 +#define MASK_UCLIP8 0xff80707f +#define MATCH_UCMPLE16 0x3c000077 +#define MASK_UCMPLE16 0xfe00707f +#define MATCH_UCMPLE8 0x3e000077 +#define MASK_UCMPLE8 0xfe00707f +#define MATCH_UCMPLT16 0x2c000077 +#define MASK_UCMPLT16 0xfe00707f +#define MATCH_UCMPLT8 0x2e000077 +#define MASK_UCMPLT8 0xfe00707f +#define MATCH_UKADD16 0x30000077 +#define MASK_UKADD16 0xfe00707f +#define MATCH_UKADD32 0x30002077 +#define MASK_UKADD32 0xfe00707f +#define MATCH_UKADD64 0xb0001077 +#define MASK_UKADD64 0xfe00707f +#define MATCH_UKADD8 0x38000077 +#define MASK_UKADD8 0xfe00707f +#define MATCH_UKADDH 0x14001077 +#define MASK_UKADDH 0xfe00707f +#define MATCH_UKADDW 0x10001077 +#define MASK_UKADDW 0xfe00707f +#define MATCH_UKCRAS16 0x34000077 +#define MASK_UKCRAS16 0xfe00707f +#define MATCH_UKCRAS32 0x34002077 +#define MASK_UKCRAS32 0xfe00707f +#define MATCH_UKCRSA16 0x36000077 +#define MASK_UKCRSA16 0xfe00707f +#define MATCH_UKCRSA32 0x36002077 +#define MASK_UKCRSA32 0xfe00707f +#define MATCH_UKMAR64 0xb4001077 +#define MASK_UKMAR64 0xfe00707f +#define MATCH_UKMSR64 0xb6001077 +#define MASK_UKMSR64 0xfe00707f +#define MATCH_UKSTAS16 0xe4002077 +#define MASK_UKSTAS16 0xfe00707f +#define MATCH_UKSTAS32 0xe0002077 +#define MASK_UKSTAS32 0xfe00707f +#define MATCH_UKSTSA16 0xe6002077 +#define MASK_UKSTSA16 0xfe00707f +#define MATCH_UKSTSA32 0xe2002077 +#define MASK_UKSTSA32 0xfe00707f +#define MATCH_UKSUB16 0x32000077 +#define MASK_UKSUB16 0xfe00707f +#define MATCH_UKSUB32 0x32002077 +#define MASK_UKSUB32 0xfe00707f +#define MATCH_UKSUB64 0xb2001077 +#define MASK_UKSUB64 0xfe00707f +#define MATCH_UKSUB8 0x3a000077 +#define MASK_UKSUB8 0xfe00707f +#define MATCH_UKSUBH 0x16001077 +#define MASK_UKSUBH 0xfe00707f +#define MATCH_UKSUBW 0x12001077 +#define MASK_UKSUBW 0xfe00707f +#define MATCH_UMAQA 0xcc000077 +#define MASK_UMAQA 0xfe00707f +#define MATCH_UMAR64 0xa4001077 +#define MASK_UMAR64 0xfe00707f +#define MATCH_UMAX16 0x92000077 +#define MASK_UMAX16 0xfe00707f +#define MATCH_UMAX32 0xa2002077 +#define MASK_UMAX32 0xfe00707f +#define MATCH_UMAX8 0x9a000077 +#define MASK_UMAX8 0xfe00707f +#define MATCH_UMIN16 0x90000077 +#define MASK_UMIN16 0xfe00707f +#define MATCH_UMIN32 0xa0002077 +#define MASK_UMIN32 0xfe00707f +#define MATCH_UMIN8 0x98000077 +#define MASK_UMIN8 0xfe00707f +#define MATCH_UMSR64 0xa6001077 +#define MASK_UMSR64 0xfe00707f +#define MATCH_UMUL16 0xb0000077 +#define MASK_UMUL16 0xfe00707f +#define MATCH_UMUL8 0xb8000077 +#define MASK_UMUL8 0xfe00707f +#define MATCH_UMULX16 0xb2000077 +#define MASK_UMULX16 0xfe00707f +#define MATCH_UMULX8 0xba000077 +#define MASK_UMULX8 0xfe00707f +#define MATCH_UNSHFL 0x8005033 +#define MASK_UNSHFL 0xfe00707f +#define MATCH_UNSHFLI 0x8005013 +#define MASK_UNSHFLI 0xfe00707f +#define MATCH_UNSHFLW 0x800503b +#define MASK_UNSHFLW 0xfe00707f +#define MATCH_URADD16 0x20000077 +#define MASK_URADD16 0xfe00707f +#define MATCH_URADD32 0x20002077 +#define MASK_URADD32 0xfe00707f +#define MATCH_URADD64 0xa0001077 +#define MASK_URADD64 0xfe00707f +#define MATCH_URADD8 0x28000077 +#define MASK_URADD8 0xfe00707f +#define MATCH_URADDW 0x30001077 +#define MASK_URADDW 0xfe00707f +#define MATCH_URCRAS16 0x24000077 +#define MASK_URCRAS16 0xfe00707f +#define MATCH_URCRAS32 0x24002077 +#define MASK_URCRAS32 0xfe00707f +#define MATCH_URCRSA16 0x26000077 +#define MASK_URCRSA16 0xfe00707f +#define MATCH_URCRSA32 0x26002077 +#define MASK_URCRSA32 0xfe00707f +#define MATCH_URSTAS16 0xd4002077 +#define MASK_URSTAS16 0xfe00707f +#define MATCH_URSTAS32 0xd0002077 +#define MASK_URSTAS32 0xfe00707f +#define MATCH_URSTSA16 0xd6002077 +#define MASK_URSTSA16 0xfe00707f +#define MATCH_URSTSA32 0xd2002077 +#define MASK_URSTSA32 0xfe00707f +#define MATCH_URSUB16 0x22000077 +#define MASK_URSUB16 0xfe00707f +#define MATCH_URSUB32 0x22002077 +#define MASK_URSUB32 0xfe00707f +#define MATCH_URSUB64 0xa2001077 +#define MASK_URSUB64 0xfe00707f +#define MATCH_URSUB8 0x2a000077 +#define MASK_URSUB8 0xfe00707f +#define MATCH_URSUBW 0x32001077 +#define MASK_URSUBW 0xfe00707f +#define MATCH_VAADD_VV 0x24002057 +#define MASK_VAADD_VV 0xfc00707f +#define MATCH_VAADD_VX 0x24006057 +#define MASK_VAADD_VX 0xfc00707f +#define MATCH_VAADDU_VV 0x20002057 +#define MASK_VAADDU_VV 0xfc00707f +#define MATCH_VAADDU_VX 0x20006057 +#define MASK_VAADDU_VX 0xfc00707f +#define MATCH_VADC_VIM 0x40003057 +#define MASK_VADC_VIM 0xfe00707f +#define MATCH_VADC_VVM 0x40000057 +#define MASK_VADC_VVM 0xfe00707f +#define MATCH_VADC_VXM 0x40004057 +#define MASK_VADC_VXM 0xfe00707f +#define MATCH_VADD_VI 0x3057 +#define MASK_VADD_VI 0xfc00707f +#define MATCH_VADD_VV 0x57 +#define MASK_VADD_VV 0xfc00707f +#define MATCH_VADD_VX 0x4057 +#define MASK_VADD_VX 0xfc00707f +#define MATCH_VAMOADDEI16_V 0x502f +#define MASK_VAMOADDEI16_V 0xf800707f +#define MATCH_VAMOADDEI32_V 0x602f +#define MASK_VAMOADDEI32_V 0xf800707f +#define MATCH_VAMOADDEI64_V 0x702f +#define MASK_VAMOADDEI64_V 0xf800707f +#define MATCH_VAMOADDEI8_V 0x2f +#define MASK_VAMOADDEI8_V 0xf800707f +#define MATCH_VAMOANDEI16_V 0x6000502f +#define MASK_VAMOANDEI16_V 0xf800707f +#define MATCH_VAMOANDEI32_V 0x6000602f +#define MASK_VAMOANDEI32_V 0xf800707f +#define MATCH_VAMOANDEI64_V 0x6000702f +#define MASK_VAMOANDEI64_V 0xf800707f +#define MATCH_VAMOANDEI8_V 0x6000002f +#define MASK_VAMOANDEI8_V 0xf800707f +#define MATCH_VAMOMAXEI16_V 0xa000502f +#define MASK_VAMOMAXEI16_V 0xf800707f +#define MATCH_VAMOMAXEI32_V 0xa000602f +#define MASK_VAMOMAXEI32_V 0xf800707f +#define MATCH_VAMOMAXEI64_V 0xa000702f +#define MASK_VAMOMAXEI64_V 0xf800707f +#define MATCH_VAMOMAXEI8_V 0xa000002f +#define MASK_VAMOMAXEI8_V 0xf800707f +#define MATCH_VAMOMAXUEI16_V 0xe000502f +#define MASK_VAMOMAXUEI16_V 0xf800707f +#define MATCH_VAMOMAXUEI32_V 0xe000602f +#define MASK_VAMOMAXUEI32_V 0xf800707f +#define MATCH_VAMOMAXUEI64_V 0xe000702f +#define MASK_VAMOMAXUEI64_V 0xf800707f +#define MATCH_VAMOMAXUEI8_V 0xe000002f +#define MASK_VAMOMAXUEI8_V 0xf800707f +#define MATCH_VAMOMINEI16_V 0x8000502f +#define MASK_VAMOMINEI16_V 0xf800707f +#define MATCH_VAMOMINEI32_V 0x8000602f +#define MASK_VAMOMINEI32_V 0xf800707f +#define MATCH_VAMOMINEI64_V 0x8000702f +#define MASK_VAMOMINEI64_V 0xf800707f +#define MATCH_VAMOMINEI8_V 0x8000002f +#define MASK_VAMOMINEI8_V 0xf800707f +#define MATCH_VAMOMINUEI16_V 0xc000502f +#define MASK_VAMOMINUEI16_V 0xf800707f +#define MATCH_VAMOMINUEI32_V 0xc000602f +#define MASK_VAMOMINUEI32_V 0xf800707f +#define MATCH_VAMOMINUEI64_V 0xc000702f +#define MASK_VAMOMINUEI64_V 0xf800707f +#define MATCH_VAMOMINUEI8_V 0xc000002f +#define MASK_VAMOMINUEI8_V 0xf800707f +#define MATCH_VAMOOREI16_V 0x4000502f +#define MASK_VAMOOREI16_V 0xf800707f +#define MATCH_VAMOOREI32_V 0x4000602f +#define MASK_VAMOOREI32_V 0xf800707f +#define MATCH_VAMOOREI64_V 0x4000702f +#define MASK_VAMOOREI64_V 0xf800707f +#define MATCH_VAMOOREI8_V 0x4000002f +#define MASK_VAMOOREI8_V 0xf800707f +#define MATCH_VAMOSWAPEI16_V 0x800502f +#define MASK_VAMOSWAPEI16_V 0xf800707f +#define MATCH_VAMOSWAPEI32_V 0x800602f +#define MASK_VAMOSWAPEI32_V 0xf800707f +#define MATCH_VAMOSWAPEI64_V 0x800702f +#define MASK_VAMOSWAPEI64_V 0xf800707f +#define MATCH_VAMOSWAPEI8_V 0x800002f +#define MASK_VAMOSWAPEI8_V 0xf800707f +#define MATCH_VAMOXOREI16_V 0x2000502f +#define MASK_VAMOXOREI16_V 0xf800707f +#define MATCH_VAMOXOREI32_V 0x2000602f +#define MASK_VAMOXOREI32_V 0xf800707f +#define MATCH_VAMOXOREI64_V 0x2000702f +#define MASK_VAMOXOREI64_V 0xf800707f +#define MATCH_VAMOXOREI8_V 0x2000002f +#define MASK_VAMOXOREI8_V 0xf800707f +#define MATCH_VAND_VI 0x24003057 +#define MASK_VAND_VI 0xfc00707f +#define MATCH_VAND_VV 0x24000057 +#define MASK_VAND_VV 0xfc00707f +#define MATCH_VAND_VX 0x24004057 +#define MASK_VAND_VX 0xfc00707f +#define MATCH_VASUB_VV 0x2c002057 +#define MASK_VASUB_VV 0xfc00707f +#define MATCH_VASUB_VX 0x2c006057 +#define MASK_VASUB_VX 0xfc00707f +#define MATCH_VASUBU_VV 0x28002057 +#define MASK_VASUBU_VV 0xfc00707f +#define MATCH_VASUBU_VX 0x28006057 +#define MASK_VASUBU_VX 0xfc00707f +#define MATCH_VCOMPRESS_VM 0x5e002057 +#define MASK_VCOMPRESS_VM 0xfe00707f +#define MATCH_VCPOP_M 0x40082057 +#define MASK_VCPOP_M 0xfc0ff07f +#define MATCH_VDIV_VV 0x84002057 +#define MASK_VDIV_VV 0xfc00707f +#define MATCH_VDIV_VX 0x84006057 +#define MASK_VDIV_VX 0xfc00707f +#define MATCH_VDIVU_VV 0x80002057 +#define MASK_VDIVU_VV 0xfc00707f +#define MATCH_VDIVU_VX 0x80006057 +#define MASK_VDIVU_VX 0xfc00707f +#define MATCH_VFADD_VF 0x5057 +#define MASK_VFADD_VF 0xfc00707f +#define MATCH_VFADD_VV 0x1057 +#define MASK_VFADD_VV 0xfc00707f +#define MATCH_VFCLASS_V 0x4c081057 +#define MASK_VFCLASS_V 0xfc0ff07f +#define MATCH_VFCVT_F_X_V 0x48019057 +#define MASK_VFCVT_F_X_V 0xfc0ff07f +#define MATCH_VFCVT_F_XU_V 0x48011057 +#define MASK_VFCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_X_F_V 0x48039057 +#define MASK_VFCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_XU_F_V 0x48031057 +#define MASK_VFCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFCVT_X_F_V 0x48009057 +#define MASK_VFCVT_X_F_V 0xfc0ff07f +#define MATCH_VFCVT_XU_F_V 0x48001057 +#define MASK_VFCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFDIV_VF 0x80005057 +#define MASK_VFDIV_VF 0xfc00707f +#define MATCH_VFDIV_VV 0x80001057 +#define MASK_VFDIV_VV 0xfc00707f +#define MATCH_VFIRST_M 0x4008a057 +#define MASK_VFIRST_M 0xfc0ff07f +#define MATCH_VFMACC_VF 0xb0005057 +#define MASK_VFMACC_VF 0xfc00707f +#define MATCH_VFMACC_VV 0xb0001057 +#define MASK_VFMACC_VV 0xfc00707f +#define MATCH_VFMADD_VF 0xa0005057 +#define MASK_VFMADD_VF 0xfc00707f +#define MATCH_VFMADD_VV 0xa0001057 +#define MASK_VFMADD_VV 0xfc00707f +#define MATCH_VFMAX_VF 0x18005057 +#define MASK_VFMAX_VF 0xfc00707f +#define MATCH_VFMAX_VV 0x18001057 +#define MASK_VFMAX_VV 0xfc00707f +#define MATCH_VFMERGE_VFM 0x5c005057 +#define MASK_VFMERGE_VFM 0xfe00707f +#define MATCH_VFMIN_VF 0x10005057 +#define MASK_VFMIN_VF 0xfc00707f +#define MATCH_VFMIN_VV 0x10001057 +#define MASK_VFMIN_VV 0xfc00707f +#define MATCH_VFMSAC_VF 0xb8005057 +#define MASK_VFMSAC_VF 0xfc00707f +#define MATCH_VFMSAC_VV 0xb8001057 +#define MASK_VFMSAC_VV 0xfc00707f +#define MATCH_VFMSUB_VF 0xa8005057 +#define MASK_VFMSUB_VF 0xfc00707f +#define MATCH_VFMSUB_VV 0xa8001057 +#define MASK_VFMSUB_VV 0xfc00707f +#define MATCH_VFMUL_VF 0x90005057 +#define MASK_VFMUL_VF 0xfc00707f +#define MATCH_VFMUL_VV 0x90001057 +#define MASK_VFMUL_VV 0xfc00707f +#define MATCH_VFMV_F_S 0x42001057 +#define MASK_VFMV_F_S 0xfe0ff07f +#define MATCH_VFMV_S_F 0x42005057 +#define MASK_VFMV_S_F 0xfff0707f +#define MATCH_VFMV_V_F 0x5e005057 +#define MASK_VFMV_V_F 0xfff0707f +#define MATCH_VFNCVT_F_F_W 0x480a1057 +#define MASK_VFNCVT_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_F_X_W 0x48099057 +#define MASK_VFNCVT_F_X_W 0xfc0ff07f +#define MATCH_VFNCVT_F_XU_W 0x48091057 +#define MASK_VFNCVT_F_XU_W 0xfc0ff07f +#define MATCH_VFNCVT_ROD_F_F_W 0x480a9057 +#define MASK_VFNCVT_ROD_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_X_F_W 0x480b9057 +#define MASK_VFNCVT_RTZ_X_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_XU_F_W 0x480b1057 +#define MASK_VFNCVT_RTZ_XU_F_W 0xfc0ff07f +#define MATCH_VFNCVT_X_F_W 0x48089057 +#define MASK_VFNCVT_X_F_W 0xfc0ff07f +#define MATCH_VFNCVT_XU_F_W 0x48081057 +#define MASK_VFNCVT_XU_F_W 0xfc0ff07f +#define MATCH_VFNMACC_VF 0xb4005057 +#define MASK_VFNMACC_VF 0xfc00707f +#define MATCH_VFNMACC_VV 0xb4001057 +#define MASK_VFNMACC_VV 0xfc00707f +#define MATCH_VFNMADD_VF 0xa4005057 +#define MASK_VFNMADD_VF 0xfc00707f +#define MATCH_VFNMADD_VV 0xa4001057 +#define MASK_VFNMADD_VV 0xfc00707f +#define MATCH_VFNMSAC_VF 0xbc005057 +#define MASK_VFNMSAC_VF 0xfc00707f +#define MATCH_VFNMSAC_VV 0xbc001057 +#define MASK_VFNMSAC_VV 0xfc00707f +#define MATCH_VFNMSUB_VF 0xac005057 +#define MASK_VFNMSUB_VF 0xfc00707f +#define MATCH_VFNMSUB_VV 0xac001057 +#define MASK_VFNMSUB_VV 0xfc00707f +#define MATCH_VFRDIV_VF 0x84005057 +#define MASK_VFRDIV_VF 0xfc00707f +#define MATCH_VFREC7_V 0x4c029057 +#define MASK_VFREC7_V 0xfc0ff07f +#define MATCH_VFREDMAX_VS 0x1c001057 +#define MASK_VFREDMAX_VS 0xfc00707f +#define MATCH_VFREDMIN_VS 0x14001057 +#define MASK_VFREDMIN_VS 0xfc00707f +#define MATCH_VFREDOSUM_VS 0xc001057 +#define MASK_VFREDOSUM_VS 0xfc00707f +#define MATCH_VFREDUSUM_VS 0x4001057 +#define MASK_VFREDUSUM_VS 0xfc00707f +#define MATCH_VFRSQRT7_V 0x4c021057 +#define MASK_VFRSQRT7_V 0xfc0ff07f +#define MATCH_VFRSUB_VF 0x9c005057 +#define MASK_VFRSUB_VF 0xfc00707f +#define MATCH_VFSGNJ_VF 0x20005057 +#define MASK_VFSGNJ_VF 0xfc00707f +#define MATCH_VFSGNJ_VV 0x20001057 +#define MASK_VFSGNJ_VV 0xfc00707f +#define MATCH_VFSGNJN_VF 0x24005057 +#define MASK_VFSGNJN_VF 0xfc00707f +#define MATCH_VFSGNJN_VV 0x24001057 +#define MASK_VFSGNJN_VV 0xfc00707f +#define MATCH_VFSGNJX_VF 0x28005057 +#define MASK_VFSGNJX_VF 0xfc00707f +#define MATCH_VFSGNJX_VV 0x28001057 +#define MASK_VFSGNJX_VV 0xfc00707f +#define MATCH_VFSLIDE1DOWN_VF 0x3c005057 +#define MASK_VFSLIDE1DOWN_VF 0xfc00707f +#define MATCH_VFSLIDE1UP_VF 0x38005057 +#define MASK_VFSLIDE1UP_VF 0xfc00707f +#define MATCH_VFSQRT_V 0x4c001057 +#define MASK_VFSQRT_V 0xfc0ff07f +#define MATCH_VFSUB_VF 0x8005057 +#define MASK_VFSUB_VF 0xfc00707f +#define MATCH_VFSUB_VV 0x8001057 +#define MASK_VFSUB_VV 0xfc00707f +#define MATCH_VFWADD_VF 0xc0005057 +#define MASK_VFWADD_VF 0xfc00707f +#define MATCH_VFWADD_VV 0xc0001057 +#define MASK_VFWADD_VV 0xfc00707f +#define MATCH_VFWADD_WF 0xd0005057 +#define MASK_VFWADD_WF 0xfc00707f +#define MATCH_VFWADD_WV 0xd0001057 +#define MASK_VFWADD_WV 0xfc00707f +#define MATCH_VFWCVT_F_F_V 0x48061057 +#define MASK_VFWCVT_F_F_V 0xfc0ff07f +#define MATCH_VFWCVT_F_X_V 0x48059057 +#define MASK_VFWCVT_F_X_V 0xfc0ff07f +#define MATCH_VFWCVT_F_XU_V 0x48051057 +#define MASK_VFWCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_X_F_V 0x48079057 +#define MASK_VFWCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_XU_F_V 0x48071057 +#define MASK_VFWCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFWCVT_X_F_V 0x48049057 +#define MASK_VFWCVT_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_XU_F_V 0x48041057 +#define MASK_VFWCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFWMACC_VF 0xf0005057 +#define MASK_VFWMACC_VF 0xfc00707f +#define MATCH_VFWMACC_VV 0xf0001057 +#define MASK_VFWMACC_VV 0xfc00707f +#define MATCH_VFWMSAC_VF 0xf8005057 +#define MASK_VFWMSAC_VF 0xfc00707f +#define MATCH_VFWMSAC_VV 0xf8001057 +#define MASK_VFWMSAC_VV 0xfc00707f +#define MATCH_VFWMUL_VF 0xe0005057 +#define MASK_VFWMUL_VF 0xfc00707f +#define MATCH_VFWMUL_VV 0xe0001057 +#define MASK_VFWMUL_VV 0xfc00707f +#define MATCH_VFWNMACC_VF 0xf4005057 +#define MASK_VFWNMACC_VF 0xfc00707f +#define MATCH_VFWNMACC_VV 0xf4001057 +#define MASK_VFWNMACC_VV 0xfc00707f +#define MATCH_VFWNMSAC_VF 0xfc005057 +#define MASK_VFWNMSAC_VF 0xfc00707f +#define MATCH_VFWNMSAC_VV 0xfc001057 +#define MASK_VFWNMSAC_VV 0xfc00707f +#define MATCH_VFWREDOSUM_VS 0xcc001057 +#define MASK_VFWREDOSUM_VS 0xfc00707f +#define MATCH_VFWREDUSUM_VS 0xc4001057 +#define MASK_VFWREDUSUM_VS 0xfc00707f +#define MATCH_VFWSUB_VF 0xc8005057 +#define MASK_VFWSUB_VF 0xfc00707f +#define MATCH_VFWSUB_VV 0xc8001057 +#define MASK_VFWSUB_VV 0xfc00707f +#define MATCH_VFWSUB_WF 0xd8005057 +#define MASK_VFWSUB_WF 0xfc00707f +#define MATCH_VFWSUB_WV 0xd8001057 +#define MASK_VFWSUB_WV 0xfc00707f +#define MATCH_VID_V 0x5008a057 +#define MASK_VID_V 0xfdfff07f +#define MATCH_VIOTA_M 0x50082057 +#define MASK_VIOTA_M 0xfc0ff07f +#define MATCH_VL1RE16_V 0x2805007 +#define MASK_VL1RE16_V 0xfff0707f +#define MATCH_VL1RE32_V 0x2806007 +#define MASK_VL1RE32_V 0xfff0707f +#define MATCH_VL1RE64_V 0x2807007 +#define MASK_VL1RE64_V 0xfff0707f +#define MATCH_VL1RE8_V 0x2800007 +#define MASK_VL1RE8_V 0xfff0707f +#define MATCH_VL2RE16_V 0x22805007 +#define MASK_VL2RE16_V 0xfff0707f +#define MATCH_VL2RE32_V 0x22806007 +#define MASK_VL2RE32_V 0xfff0707f +#define MATCH_VL2RE64_V 0x22807007 +#define MASK_VL2RE64_V 0xfff0707f +#define MATCH_VL2RE8_V 0x22800007 +#define MASK_VL2RE8_V 0xfff0707f +#define MATCH_VL4RE16_V 0x62805007 +#define MASK_VL4RE16_V 0xfff0707f +#define MATCH_VL4RE32_V 0x62806007 +#define MASK_VL4RE32_V 0xfff0707f +#define MATCH_VL4RE64_V 0x62807007 +#define MASK_VL4RE64_V 0xfff0707f +#define MATCH_VL4RE8_V 0x62800007 +#define MASK_VL4RE8_V 0xfff0707f +#define MATCH_VL8RE16_V 0xe2805007 +#define MASK_VL8RE16_V 0xfff0707f +#define MATCH_VL8RE32_V 0xe2806007 +#define MASK_VL8RE32_V 0xfff0707f +#define MATCH_VL8RE64_V 0xe2807007 +#define MASK_VL8RE64_V 0xfff0707f +#define MATCH_VL8RE8_V 0xe2800007 +#define MASK_VL8RE8_V 0xfff0707f +#define MATCH_VLE1024_V 0x10007007 +#define MASK_VLE1024_V 0x1df0707f +#define MATCH_VLE1024FF_V 0x11007007 +#define MASK_VLE1024FF_V 0x1df0707f +#define MATCH_VLE128_V 0x10000007 +#define MASK_VLE128_V 0x1df0707f +#define MATCH_VLE128FF_V 0x11000007 +#define MASK_VLE128FF_V 0x1df0707f +#define MATCH_VLE16_V 0x5007 +#define MASK_VLE16_V 0x1df0707f +#define MATCH_VLE16FF_V 0x1005007 +#define MASK_VLE16FF_V 0x1df0707f +#define MATCH_VLE256_V 0x10005007 +#define MASK_VLE256_V 0x1df0707f +#define MATCH_VLE256FF_V 0x11005007 +#define MASK_VLE256FF_V 0x1df0707f +#define MATCH_VLE32_V 0x6007 +#define MASK_VLE32_V 0x1df0707f +#define MATCH_VLE32FF_V 0x1006007 +#define MASK_VLE32FF_V 0x1df0707f +#define MATCH_VLE512_V 0x10006007 +#define MASK_VLE512_V 0x1df0707f +#define MATCH_VLE512FF_V 0x11006007 +#define MASK_VLE512FF_V 0x1df0707f +#define MATCH_VLE64_V 0x7007 +#define MASK_VLE64_V 0x1df0707f +#define MATCH_VLE64FF_V 0x1007007 +#define MASK_VLE64FF_V 0x1df0707f +#define MATCH_VLE8_V 0x7 +#define MASK_VLE8_V 0x1df0707f +#define MATCH_VLE8FF_V 0x1000007 +#define MASK_VLE8FF_V 0x1df0707f +#define MATCH_VLM_V 0x2b00007 +#define MASK_VLM_V 0xfff0707f +#define MATCH_VLOXEI1024_V 0x1c007007 +#define MASK_VLOXEI1024_V 0x1c00707f +#define MATCH_VLOXEI128_V 0x1c000007 +#define MASK_VLOXEI128_V 0x1c00707f +#define MATCH_VLOXEI16_V 0xc005007 +#define MASK_VLOXEI16_V 0x1c00707f +#define MATCH_VLOXEI256_V 0x1c005007 +#define MASK_VLOXEI256_V 0x1c00707f +#define MATCH_VLOXEI32_V 0xc006007 +#define MASK_VLOXEI32_V 0x1c00707f +#define MATCH_VLOXEI512_V 0x1c006007 +#define MASK_VLOXEI512_V 0x1c00707f +#define MATCH_VLOXEI64_V 0xc007007 +#define MASK_VLOXEI64_V 0x1c00707f +#define MATCH_VLOXEI8_V 0xc000007 +#define MASK_VLOXEI8_V 0x1c00707f +#define MATCH_VLSE1024_V 0x18007007 +#define MASK_VLSE1024_V 0x1c00707f +#define MATCH_VLSE128_V 0x18000007 +#define MASK_VLSE128_V 0x1c00707f +#define MATCH_VLSE16_V 0x8005007 +#define MASK_VLSE16_V 0x1c00707f +#define MATCH_VLSE256_V 0x18005007 +#define MASK_VLSE256_V 0x1c00707f +#define MATCH_VLSE32_V 0x8006007 +#define MASK_VLSE32_V 0x1c00707f +#define MATCH_VLSE512_V 0x18006007 +#define MASK_VLSE512_V 0x1c00707f +#define MATCH_VLSE64_V 0x8007007 +#define MASK_VLSE64_V 0x1c00707f +#define MATCH_VLSE8_V 0x8000007 +#define MASK_VLSE8_V 0x1c00707f +#define MATCH_VLUXEI1024_V 0x14007007 +#define MASK_VLUXEI1024_V 0x1c00707f +#define MATCH_VLUXEI128_V 0x14000007 +#define MASK_VLUXEI128_V 0x1c00707f +#define MATCH_VLUXEI16_V 0x4005007 +#define MASK_VLUXEI16_V 0x1c00707f +#define MATCH_VLUXEI256_V 0x14005007 +#define MASK_VLUXEI256_V 0x1c00707f +#define MATCH_VLUXEI32_V 0x4006007 +#define MASK_VLUXEI32_V 0x1c00707f +#define MATCH_VLUXEI512_V 0x14006007 +#define MASK_VLUXEI512_V 0x1c00707f +#define MATCH_VLUXEI64_V 0x4007007 +#define MASK_VLUXEI64_V 0x1c00707f +#define MATCH_VLUXEI8_V 0x4000007 +#define MASK_VLUXEI8_V 0x1c00707f +#define MATCH_VMACC_VV 0xb4002057 +#define MASK_VMACC_VV 0xfc00707f +#define MATCH_VMACC_VX 0xb4006057 +#define MASK_VMACC_VX 0xfc00707f +#define MATCH_VMADC_VI 0x46003057 +#define MASK_VMADC_VI 0xfe00707f +#define MATCH_VMADC_VIM 0x44003057 +#define MASK_VMADC_VIM 0xfe00707f +#define MATCH_VMADC_VV 0x46000057 +#define MASK_VMADC_VV 0xfe00707f +#define MATCH_VMADC_VVM 0x44000057 +#define MASK_VMADC_VVM 0xfe00707f +#define MATCH_VMADC_VX 0x46004057 +#define MASK_VMADC_VX 0xfe00707f +#define MATCH_VMADC_VXM 0x44004057 +#define MASK_VMADC_VXM 0xfe00707f +#define MATCH_VMADD_VV 0xa4002057 +#define MASK_VMADD_VV 0xfc00707f +#define MATCH_VMADD_VX 0xa4006057 +#define MASK_VMADD_VX 0xfc00707f +#define MATCH_VMAND_MM 0x64002057 +#define MASK_VMAND_MM 0xfc00707f +#define MATCH_VMANDN_MM 0x60002057 +#define MASK_VMANDN_MM 0xfc00707f +#define MATCH_VMAX_VV 0x1c000057 +#define MASK_VMAX_VV 0xfc00707f +#define MATCH_VMAX_VX 0x1c004057 +#define MASK_VMAX_VX 0xfc00707f +#define MATCH_VMAXU_VV 0x18000057 +#define MASK_VMAXU_VV 0xfc00707f +#define MATCH_VMAXU_VX 0x18004057 +#define MASK_VMAXU_VX 0xfc00707f +#define MATCH_VMERGE_VIM 0x5c003057 +#define MASK_VMERGE_VIM 0xfe00707f +#define MATCH_VMERGE_VVM 0x5c000057 +#define MASK_VMERGE_VVM 0xfe00707f +#define MATCH_VMERGE_VXM 0x5c004057 +#define MASK_VMERGE_VXM 0xfe00707f +#define MATCH_VMFEQ_VF 0x60005057 +#define MASK_VMFEQ_VF 0xfc00707f +#define MATCH_VMFEQ_VV 0x60001057 +#define MASK_VMFEQ_VV 0xfc00707f +#define MATCH_VMFGE_VF 0x7c005057 +#define MASK_VMFGE_VF 0xfc00707f +#define MATCH_VMFGT_VF 0x74005057 +#define MASK_VMFGT_VF 0xfc00707f +#define MATCH_VMFLE_VF 0x64005057 +#define MASK_VMFLE_VF 0xfc00707f +#define MATCH_VMFLE_VV 0x64001057 +#define MASK_VMFLE_VV 0xfc00707f +#define MATCH_VMFLT_VF 0x6c005057 +#define MASK_VMFLT_VF 0xfc00707f +#define MATCH_VMFLT_VV 0x6c001057 +#define MASK_VMFLT_VV 0xfc00707f +#define MATCH_VMFNE_VF 0x70005057 +#define MASK_VMFNE_VF 0xfc00707f +#define MATCH_VMFNE_VV 0x70001057 +#define MASK_VMFNE_VV 0xfc00707f +#define MATCH_VMIN_VV 0x14000057 +#define MASK_VMIN_VV 0xfc00707f +#define MATCH_VMIN_VX 0x14004057 +#define MASK_VMIN_VX 0xfc00707f +#define MATCH_VMINU_VV 0x10000057 +#define MASK_VMINU_VV 0xfc00707f +#define MATCH_VMINU_VX 0x10004057 +#define MASK_VMINU_VX 0xfc00707f +#define MATCH_VMNAND_MM 0x74002057 +#define MASK_VMNAND_MM 0xfc00707f +#define MATCH_VMNOR_MM 0x78002057 +#define MASK_VMNOR_MM 0xfc00707f +#define MATCH_VMOR_MM 0x68002057 +#define MASK_VMOR_MM 0xfc00707f +#define MATCH_VMORN_MM 0x70002057 +#define MASK_VMORN_MM 0xfc00707f +#define MATCH_VMSBC_VV 0x4e000057 +#define MASK_VMSBC_VV 0xfe00707f +#define MATCH_VMSBC_VVM 0x4c000057 +#define MASK_VMSBC_VVM 0xfe00707f +#define MATCH_VMSBC_VX 0x4e004057 +#define MASK_VMSBC_VX 0xfe00707f +#define MATCH_VMSBC_VXM 0x4c004057 +#define MASK_VMSBC_VXM 0xfe00707f +#define MATCH_VMSBF_M 0x5000a057 +#define MASK_VMSBF_M 0xfc0ff07f +#define MATCH_VMSEQ_VI 0x60003057 +#define MASK_VMSEQ_VI 0xfc00707f +#define MATCH_VMSEQ_VV 0x60000057 +#define MASK_VMSEQ_VV 0xfc00707f +#define MATCH_VMSEQ_VX 0x60004057 +#define MASK_VMSEQ_VX 0xfc00707f +#define MATCH_VMSGT_VI 0x7c003057 +#define MASK_VMSGT_VI 0xfc00707f +#define MATCH_VMSGT_VX 0x7c004057 +#define MASK_VMSGT_VX 0xfc00707f +#define MATCH_VMSGTU_VI 0x78003057 +#define MASK_VMSGTU_VI 0xfc00707f +#define MATCH_VMSGTU_VX 0x78004057 +#define MASK_VMSGTU_VX 0xfc00707f +#define MATCH_VMSIF_M 0x5001a057 +#define MASK_VMSIF_M 0xfc0ff07f +#define MATCH_VMSLE_VI 0x74003057 +#define MASK_VMSLE_VI 0xfc00707f +#define MATCH_VMSLE_VV 0x74000057 +#define MASK_VMSLE_VV 0xfc00707f +#define MATCH_VMSLE_VX 0x74004057 +#define MASK_VMSLE_VX 0xfc00707f +#define MATCH_VMSLEU_VI 0x70003057 +#define MASK_VMSLEU_VI 0xfc00707f +#define MATCH_VMSLEU_VV 0x70000057 +#define MASK_VMSLEU_VV 0xfc00707f +#define MATCH_VMSLEU_VX 0x70004057 +#define MASK_VMSLEU_VX 0xfc00707f +#define MATCH_VMSLT_VV 0x6c000057 +#define MASK_VMSLT_VV 0xfc00707f +#define MATCH_VMSLT_VX 0x6c004057 +#define MASK_VMSLT_VX 0xfc00707f +#define MATCH_VMSLTU_VV 0x68000057 +#define MASK_VMSLTU_VV 0xfc00707f +#define MATCH_VMSLTU_VX 0x68004057 +#define MASK_VMSLTU_VX 0xfc00707f +#define MATCH_VMSNE_VI 0x64003057 +#define MASK_VMSNE_VI 0xfc00707f +#define MATCH_VMSNE_VV 0x64000057 +#define MASK_VMSNE_VV 0xfc00707f +#define MATCH_VMSNE_VX 0x64004057 +#define MASK_VMSNE_VX 0xfc00707f +#define MATCH_VMSOF_M 0x50012057 +#define MASK_VMSOF_M 0xfc0ff07f +#define MATCH_VMUL_VV 0x94002057 +#define MASK_VMUL_VV 0xfc00707f +#define MATCH_VMUL_VX 0x94006057 +#define MASK_VMUL_VX 0xfc00707f +#define MATCH_VMULH_VV 0x9c002057 +#define MASK_VMULH_VV 0xfc00707f +#define MATCH_VMULH_VX 0x9c006057 +#define MASK_VMULH_VX 0xfc00707f +#define MATCH_VMULHSU_VV 0x98002057 +#define MASK_VMULHSU_VV 0xfc00707f +#define MATCH_VMULHSU_VX 0x98006057 +#define MASK_VMULHSU_VX 0xfc00707f +#define MATCH_VMULHU_VV 0x90002057 +#define MASK_VMULHU_VV 0xfc00707f +#define MATCH_VMULHU_VX 0x90006057 +#define MASK_VMULHU_VX 0xfc00707f +#define MATCH_VMV1R_V 0x9e003057 +#define MASK_VMV1R_V 0xfe0ff07f +#define MATCH_VMV2R_V 0x9e00b057 +#define MASK_VMV2R_V 0xfe0ff07f +#define MATCH_VMV4R_V 0x9e01b057 +#define MASK_VMV4R_V 0xfe0ff07f +#define MATCH_VMV8R_V 0x9e03b057 +#define MASK_VMV8R_V 0xfe0ff07f +#define MATCH_VMV_S_X 0x42006057 +#define MASK_VMV_S_X 0xfff0707f +#define MATCH_VMV_V_I 0x5e003057 +#define MASK_VMV_V_I 0xfff0707f +#define MATCH_VMV_V_V 0x5e000057 +#define MASK_VMV_V_V 0xfff0707f +#define MATCH_VMV_V_X 0x5e004057 +#define MASK_VMV_V_X 0xfff0707f +#define MATCH_VMV_X_S 0x42002057 +#define MASK_VMV_X_S 0xfe0ff07f +#define MATCH_VMXNOR_MM 0x7c002057 +#define MASK_VMXNOR_MM 0xfc00707f +#define MATCH_VMXOR_MM 0x6c002057 +#define MASK_VMXOR_MM 0xfc00707f +#define MATCH_VNCLIP_WI 0xbc003057 +#define MASK_VNCLIP_WI 0xfc00707f +#define MATCH_VNCLIP_WV 0xbc000057 +#define MASK_VNCLIP_WV 0xfc00707f +#define MATCH_VNCLIP_WX 0xbc004057 +#define MASK_VNCLIP_WX 0xfc00707f +#define MATCH_VNCLIPU_WI 0xb8003057 +#define MASK_VNCLIPU_WI 0xfc00707f +#define MATCH_VNCLIPU_WV 0xb8000057 +#define MASK_VNCLIPU_WV 0xfc00707f +#define MATCH_VNCLIPU_WX 0xb8004057 +#define MASK_VNCLIPU_WX 0xfc00707f +#define MATCH_VNMSAC_VV 0xbc002057 +#define MASK_VNMSAC_VV 0xfc00707f +#define MATCH_VNMSAC_VX 0xbc006057 +#define MASK_VNMSAC_VX 0xfc00707f +#define MATCH_VNMSUB_VV 0xac002057 +#define MASK_VNMSUB_VV 0xfc00707f +#define MATCH_VNMSUB_VX 0xac006057 +#define MASK_VNMSUB_VX 0xfc00707f +#define MATCH_VNSRA_WI 0xb4003057 +#define MASK_VNSRA_WI 0xfc00707f +#define MATCH_VNSRA_WV 0xb4000057 +#define MASK_VNSRA_WV 0xfc00707f +#define MATCH_VNSRA_WX 0xb4004057 +#define MASK_VNSRA_WX 0xfc00707f +#define MATCH_VNSRL_WI 0xb0003057 +#define MASK_VNSRL_WI 0xfc00707f +#define MATCH_VNSRL_WV 0xb0000057 +#define MASK_VNSRL_WV 0xfc00707f +#define MATCH_VNSRL_WX 0xb0004057 +#define MASK_VNSRL_WX 0xfc00707f +#define MATCH_VOR_VI 0x28003057 +#define MASK_VOR_VI 0xfc00707f +#define MATCH_VOR_VV 0x28000057 +#define MASK_VOR_VV 0xfc00707f +#define MATCH_VOR_VX 0x28004057 +#define MASK_VOR_VX 0xfc00707f +#define MATCH_VREDAND_VS 0x4002057 +#define MASK_VREDAND_VS 0xfc00707f +#define MATCH_VREDMAX_VS 0x1c002057 +#define MASK_VREDMAX_VS 0xfc00707f +#define MATCH_VREDMAXU_VS 0x18002057 +#define MASK_VREDMAXU_VS 0xfc00707f +#define MATCH_VREDMIN_VS 0x14002057 +#define MASK_VREDMIN_VS 0xfc00707f +#define MATCH_VREDMINU_VS 0x10002057 +#define MASK_VREDMINU_VS 0xfc00707f +#define MATCH_VREDOR_VS 0x8002057 +#define MASK_VREDOR_VS 0xfc00707f +#define MATCH_VREDSUM_VS 0x2057 +#define MASK_VREDSUM_VS 0xfc00707f +#define MATCH_VREDXOR_VS 0xc002057 +#define MASK_VREDXOR_VS 0xfc00707f +#define MATCH_VREM_VV 0x8c002057 +#define MASK_VREM_VV 0xfc00707f +#define MATCH_VREM_VX 0x8c006057 +#define MASK_VREM_VX 0xfc00707f +#define MATCH_VREMU_VV 0x88002057 +#define MASK_VREMU_VV 0xfc00707f +#define MATCH_VREMU_VX 0x88006057 +#define MASK_VREMU_VX 0xfc00707f +#define MATCH_VRGATHER_VI 0x30003057 +#define MASK_VRGATHER_VI 0xfc00707f +#define MATCH_VRGATHER_VV 0x30000057 +#define MASK_VRGATHER_VV 0xfc00707f +#define MATCH_VRGATHER_VX 0x30004057 +#define MASK_VRGATHER_VX 0xfc00707f +#define MATCH_VRGATHEREI16_VV 0x38000057 +#define MASK_VRGATHEREI16_VV 0xfc00707f +#define MATCH_VRSUB_VI 0xc003057 +#define MASK_VRSUB_VI 0xfc00707f +#define MATCH_VRSUB_VX 0xc004057 +#define MASK_VRSUB_VX 0xfc00707f +#define MATCH_VS1R_V 0x2800027 +#define MASK_VS1R_V 0xfff0707f +#define MATCH_VS2R_V 0x22800027 +#define MASK_VS2R_V 0xfff0707f +#define MATCH_VS4R_V 0x62800027 +#define MASK_VS4R_V 0xfff0707f +#define MATCH_VS8R_V 0xe2800027 +#define MASK_VS8R_V 0xfff0707f +#define MATCH_VSADD_VI 0x84003057 +#define MASK_VSADD_VI 0xfc00707f +#define MATCH_VSADD_VV 0x84000057 +#define MASK_VSADD_VV 0xfc00707f +#define MATCH_VSADD_VX 0x84004057 +#define MASK_VSADD_VX 0xfc00707f +#define MATCH_VSADDU_VI 0x80003057 +#define MASK_VSADDU_VI 0xfc00707f +#define MATCH_VSADDU_VV 0x80000057 +#define MASK_VSADDU_VV 0xfc00707f +#define MATCH_VSADDU_VX 0x80004057 +#define MASK_VSADDU_VX 0xfc00707f +#define MATCH_VSBC_VVM 0x48000057 +#define MASK_VSBC_VVM 0xfe00707f +#define MATCH_VSBC_VXM 0x48004057 +#define MASK_VSBC_VXM 0xfe00707f +#define MATCH_VSE1024_V 0x10007027 +#define MASK_VSE1024_V 0x1df0707f +#define MATCH_VSE128_V 0x10000027 +#define MASK_VSE128_V 0x1df0707f +#define MATCH_VSE16_V 0x5027 +#define MASK_VSE16_V 0x1df0707f +#define MATCH_VSE256_V 0x10005027 +#define MASK_VSE256_V 0x1df0707f +#define MATCH_VSE32_V 0x6027 +#define MASK_VSE32_V 0x1df0707f +#define MATCH_VSE512_V 0x10006027 +#define MASK_VSE512_V 0x1df0707f +#define MATCH_VSE64_V 0x7027 +#define MASK_VSE64_V 0x1df0707f +#define MATCH_VSE8_V 0x27 +#define MASK_VSE8_V 0x1df0707f +#define MATCH_VSETIVLI 0xc0007057 +#define MASK_VSETIVLI 0xc000707f +#define MATCH_VSETVL 0x80007057 +#define MASK_VSETVL 0xfe00707f +#define MATCH_VSETVLI 0x7057 +#define MASK_VSETVLI 0x8000707f +#define MATCH_VSEXT_VF2 0x4803a057 +#define MASK_VSEXT_VF2 0xfc0ff07f +#define MATCH_VSEXT_VF4 0x4802a057 +#define MASK_VSEXT_VF4 0xfc0ff07f +#define MATCH_VSEXT_VF8 0x4801a057 +#define MASK_VSEXT_VF8 0xfc0ff07f +#define MATCH_VSLIDE1DOWN_VX 0x3c006057 +#define MASK_VSLIDE1DOWN_VX 0xfc00707f +#define MATCH_VSLIDE1UP_VX 0x38006057 +#define MASK_VSLIDE1UP_VX 0xfc00707f +#define MATCH_VSLIDEDOWN_VI 0x3c003057 +#define MASK_VSLIDEDOWN_VI 0xfc00707f +#define MATCH_VSLIDEDOWN_VX 0x3c004057 +#define MASK_VSLIDEDOWN_VX 0xfc00707f +#define MATCH_VSLIDEUP_VI 0x38003057 +#define MASK_VSLIDEUP_VI 0xfc00707f +#define MATCH_VSLIDEUP_VX 0x38004057 +#define MASK_VSLIDEUP_VX 0xfc00707f +#define MATCH_VSLL_VI 0x94003057 +#define MASK_VSLL_VI 0xfc00707f +#define MATCH_VSLL_VV 0x94000057 +#define MASK_VSLL_VV 0xfc00707f +#define MATCH_VSLL_VX 0x94004057 +#define MASK_VSLL_VX 0xfc00707f +#define MATCH_VSM_V 0x2b00027 +#define MASK_VSM_V 0xfff0707f +#define MATCH_VSMUL_VV 0x9c000057 +#define MASK_VSMUL_VV 0xfc00707f +#define MATCH_VSMUL_VX 0x9c004057 +#define MASK_VSMUL_VX 0xfc00707f +#define MATCH_VSOXEI1024_V 0x1c007027 +#define MASK_VSOXEI1024_V 0x1c00707f +#define MATCH_VSOXEI128_V 0x1c000027 +#define MASK_VSOXEI128_V 0x1c00707f +#define MATCH_VSOXEI16_V 0xc005027 +#define MASK_VSOXEI16_V 0x1c00707f +#define MATCH_VSOXEI256_V 0x1c005027 +#define MASK_VSOXEI256_V 0x1c00707f +#define MATCH_VSOXEI32_V 0xc006027 +#define MASK_VSOXEI32_V 0x1c00707f +#define MATCH_VSOXEI512_V 0x1c006027 +#define MASK_VSOXEI512_V 0x1c00707f +#define MATCH_VSOXEI64_V 0xc007027 +#define MASK_VSOXEI64_V 0x1c00707f +#define MATCH_VSOXEI8_V 0xc000027 +#define MASK_VSOXEI8_V 0x1c00707f +#define MATCH_VSRA_VI 0xa4003057 +#define MASK_VSRA_VI 0xfc00707f +#define MATCH_VSRA_VV 0xa4000057 +#define MASK_VSRA_VV 0xfc00707f +#define MATCH_VSRA_VX 0xa4004057 +#define MASK_VSRA_VX 0xfc00707f +#define MATCH_VSRL_VI 0xa0003057 +#define MASK_VSRL_VI 0xfc00707f +#define MATCH_VSRL_VV 0xa0000057 +#define MASK_VSRL_VV 0xfc00707f +#define MATCH_VSRL_VX 0xa0004057 +#define MASK_VSRL_VX 0xfc00707f +#define MATCH_VSSE1024_V 0x18007027 +#define MASK_VSSE1024_V 0x1c00707f +#define MATCH_VSSE128_V 0x18000027 +#define MASK_VSSE128_V 0x1c00707f +#define MATCH_VSSE16_V 0x8005027 +#define MASK_VSSE16_V 0x1c00707f +#define MATCH_VSSE256_V 0x18005027 +#define MASK_VSSE256_V 0x1c00707f +#define MATCH_VSSE32_V 0x8006027 +#define MASK_VSSE32_V 0x1c00707f +#define MATCH_VSSE512_V 0x18006027 +#define MASK_VSSE512_V 0x1c00707f +#define MATCH_VSSE64_V 0x8007027 +#define MASK_VSSE64_V 0x1c00707f +#define MATCH_VSSE8_V 0x8000027 +#define MASK_VSSE8_V 0x1c00707f +#define MATCH_VSSRA_VI 0xac003057 +#define MASK_VSSRA_VI 0xfc00707f +#define MATCH_VSSRA_VV 0xac000057 +#define MASK_VSSRA_VV 0xfc00707f +#define MATCH_VSSRA_VX 0xac004057 +#define MASK_VSSRA_VX 0xfc00707f +#define MATCH_VSSRL_VI 0xa8003057 +#define MASK_VSSRL_VI 0xfc00707f +#define MATCH_VSSRL_VV 0xa8000057 +#define MASK_VSSRL_VV 0xfc00707f +#define MATCH_VSSRL_VX 0xa8004057 +#define MASK_VSSRL_VX 0xfc00707f +#define MATCH_VSSUB_VV 0x8c000057 +#define MASK_VSSUB_VV 0xfc00707f +#define MATCH_VSSUB_VX 0x8c004057 +#define MASK_VSSUB_VX 0xfc00707f +#define MATCH_VSSUBU_VV 0x88000057 +#define MASK_VSSUBU_VV 0xfc00707f +#define MATCH_VSSUBU_VX 0x88004057 +#define MASK_VSSUBU_VX 0xfc00707f +#define MATCH_VSUB_VV 0x8000057 +#define MASK_VSUB_VV 0xfc00707f +#define MATCH_VSUB_VX 0x8004057 +#define MASK_VSUB_VX 0xfc00707f +#define MATCH_VSUXEI1024_V 0x14007027 +#define MASK_VSUXEI1024_V 0x1c00707f +#define MATCH_VSUXEI128_V 0x14000027 +#define MASK_VSUXEI128_V 0x1c00707f +#define MATCH_VSUXEI16_V 0x4005027 +#define MASK_VSUXEI16_V 0x1c00707f +#define MATCH_VSUXEI256_V 0x14005027 +#define MASK_VSUXEI256_V 0x1c00707f +#define MATCH_VSUXEI32_V 0x4006027 +#define MASK_VSUXEI32_V 0x1c00707f +#define MATCH_VSUXEI512_V 0x14006027 +#define MASK_VSUXEI512_V 0x1c00707f +#define MATCH_VSUXEI64_V 0x4007027 +#define MASK_VSUXEI64_V 0x1c00707f +#define MATCH_VSUXEI8_V 0x4000027 +#define MASK_VSUXEI8_V 0x1c00707f +#define MATCH_VWADD_VV 0xc4002057 +#define MASK_VWADD_VV 0xfc00707f +#define MATCH_VWADD_VX 0xc4006057 +#define MASK_VWADD_VX 0xfc00707f +#define MATCH_VWADD_WV 0xd4002057 +#define MASK_VWADD_WV 0xfc00707f +#define MATCH_VWADD_WX 0xd4006057 +#define MASK_VWADD_WX 0xfc00707f +#define MATCH_VWADDU_VV 0xc0002057 +#define MASK_VWADDU_VV 0xfc00707f +#define MATCH_VWADDU_VX 0xc0006057 +#define MASK_VWADDU_VX 0xfc00707f +#define MATCH_VWADDU_WV 0xd0002057 +#define MASK_VWADDU_WV 0xfc00707f +#define MATCH_VWADDU_WX 0xd0006057 +#define MASK_VWADDU_WX 0xfc00707f +#define MATCH_VWMACC_VV 0xf4002057 +#define MASK_VWMACC_VV 0xfc00707f +#define MATCH_VWMACC_VX 0xf4006057 +#define MASK_VWMACC_VX 0xfc00707f +#define MATCH_VWMACCSU_VV 0xfc002057 +#define MASK_VWMACCSU_VV 0xfc00707f +#define MATCH_VWMACCSU_VX 0xfc006057 +#define MASK_VWMACCSU_VX 0xfc00707f +#define MATCH_VWMACCU_VV 0xf0002057 +#define MASK_VWMACCU_VV 0xfc00707f +#define MATCH_VWMACCU_VX 0xf0006057 +#define MASK_VWMACCU_VX 0xfc00707f +#define MATCH_VWMACCUS_VX 0xf8006057 +#define MASK_VWMACCUS_VX 0xfc00707f +#define MATCH_VWMUL_VV 0xec002057 +#define MASK_VWMUL_VV 0xfc00707f +#define MATCH_VWMUL_VX 0xec006057 +#define MASK_VWMUL_VX 0xfc00707f +#define MATCH_VWMULSU_VV 0xe8002057 +#define MASK_VWMULSU_VV 0xfc00707f +#define MATCH_VWMULSU_VX 0xe8006057 +#define MASK_VWMULSU_VX 0xfc00707f +#define MATCH_VWMULU_VV 0xe0002057 +#define MASK_VWMULU_VV 0xfc00707f +#define MATCH_VWMULU_VX 0xe0006057 +#define MASK_VWMULU_VX 0xfc00707f +#define MATCH_VWREDSUM_VS 0xc4000057 +#define MASK_VWREDSUM_VS 0xfc00707f +#define MATCH_VWREDSUMU_VS 0xc0000057 +#define MASK_VWREDSUMU_VS 0xfc00707f +#define MATCH_VWSUB_VV 0xcc002057 +#define MASK_VWSUB_VV 0xfc00707f +#define MATCH_VWSUB_VX 0xcc006057 +#define MASK_VWSUB_VX 0xfc00707f +#define MATCH_VWSUB_WV 0xdc002057 +#define MASK_VWSUB_WV 0xfc00707f +#define MATCH_VWSUB_WX 0xdc006057 +#define MASK_VWSUB_WX 0xfc00707f +#define MATCH_VWSUBU_VV 0xc8002057 +#define MASK_VWSUBU_VV 0xfc00707f +#define MATCH_VWSUBU_VX 0xc8006057 +#define MASK_VWSUBU_VX 0xfc00707f +#define MATCH_VWSUBU_WV 0xd8002057 +#define MASK_VWSUBU_WV 0xfc00707f +#define MATCH_VWSUBU_WX 0xd8006057 +#define MASK_VWSUBU_WX 0xfc00707f +#define MATCH_VXOR_VI 0x2c003057 +#define MASK_VXOR_VI 0xfc00707f +#define MATCH_VXOR_VV 0x2c000057 +#define MASK_VXOR_VV 0xfc00707f +#define MATCH_VXOR_VX 0x2c004057 +#define MASK_VXOR_VX 0xfc00707f +#define MATCH_VZEXT_VF2 0x48032057 +#define MASK_VZEXT_VF2 0xfc0ff07f +#define MATCH_VZEXT_VF4 0x48022057 +#define MASK_VZEXT_VF4 0xfc0ff07f +#define MATCH_VZEXT_VF8 0x48012057 +#define MASK_VZEXT_VF8 0xfc0ff07f +#define MATCH_WEXT 0xce000077 +#define MASK_WEXT 0xfe00707f +#define MATCH_WEXTI 0xde000077 +#define MASK_WEXTI 0xfe00707f +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_WRS_NTO 0xd00073 +#define MASK_WRS_NTO 0xffffffff +#define MATCH_WRS_STO 0x1d00073 +#define MASK_WRS_STO 0xffffffff +#define MATCH_XNOR 0x40004033 +#define MASK_XNOR 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_XPERM16 0x28006033 +#define MASK_XPERM16 0xfe00707f +#define MATCH_XPERM32 0x28000033 +#define MASK_XPERM32 0xfe00707f +#define MATCH_XPERM4 0x28002033 +#define MASK_XPERM4 0xfe00707f +#define MATCH_XPERM8 0x28004033 +#define MASK_XPERM8 0xfe00707f +#define MATCH_ZUNPKD810 0xacc00077 +#define MASK_ZUNPKD810 0xfff0707f +#define MATCH_ZUNPKD820 0xacd00077 +#define MASK_ZUNPKD820 0xfff0707f +#define MATCH_ZUNPKD830 0xace00077 +#define MASK_ZUNPKD830 0xfff0707f +#define MATCH_ZUNPKD831 0xacf00077 +#define MASK_ZUNPKD831 0xfff0707f +#define MATCH_ZUNPKD832 0xad700077 +#define MASK_ZUNPKD832 0xfff0707f + +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_VSTART 0x8 +#define CSR_VXSAT 0x9 +#define CSR_VXRM 0xa +#define CSR_VCSR 0xf +#define CSR_SEED 0x15 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 +#define CSR_VLENB 0xc22 +#define CSR_SSTATUS 0x100 +#define CSR_SEDELEG 0x102 +#define CSR_SIDELEG 0x103 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SENVCFG 0x10a +#define CSR_SSTATEEN0 0x10c +#define CSR_SSTATEEN1 0x10d +#define CSR_SSTATEEN2 0x10e +#define CSR_SSTATEEN3 0x10f +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_STIMECMP 0x14d +#define CSR_SATP 0x180 +#define CSR_SCONTEXT 0x5a8 +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSTIMECMP 0x24d +#define CSR_VSATP 0x280 +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 +#define CSR_HENVCFG 0x60a +#define CSR_HSTATEEN0 0x60c +#define CSR_HSTATEEN1 0x60d +#define CSR_HSTATEEN2 0x60e +#define CSR_HSTATEEN3 0x60f +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64a +#define CSR_HGATP 0x680 +#define CSR_HCONTEXT 0x6a8 +#define CSR_HGEIP 0xe12 +#define CSR_SCOUNTOVF 0xda0 +#define CSR_UTVT 0x7 +#define CSR_UNXTI 0x45 +#define CSR_UINTSTATUS 0x46 +#define CSR_USCRATCHCSW 0x48 +#define CSR_USCRATCHCSWL 0x49 +#define CSR_STVT 0x107 +#define CSR_SNXTI 0x145 +#define CSR_SINTSTATUS 0x146 +#define CSR_SSCRATCHCSW 0x148 +#define CSR_SSCRATCHCSWL 0x149 +#define CSR_MTVT 0x307 +#define CSR_MNXTI 0x345 +#define CSR_MINTSTATUS 0x346 +#define CSR_MSCRATCHCSW 0x348 +#define CSR_MSCRATCHCSWL 0x349 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MENVCFG 0x30a +#define CSR_MSTATEEN0 0x30c +#define CSR_MSTATEEN1 0x30d +#define CSR_MSTATEEN2 0x30e +#define CSR_MSTATEEN3 0x30f +#define CSR_MCOUNTINHIBIT 0x320 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_MTINST 0x34a +#define CSR_MTVAL2 0x34b +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPCFG4 0x3a4 +#define CSR_PMPCFG5 0x3a5 +#define CSR_PMPCFG6 0x3a6 +#define CSR_PMPCFG7 0x3a7 +#define CSR_PMPCFG8 0x3a8 +#define CSR_PMPCFG9 0x3a9 +#define CSR_PMPCFG10 0x3aa +#define CSR_PMPCFG11 0x3ab +#define CSR_PMPCFG12 0x3ac +#define CSR_PMPCFG13 0x3ad +#define CSR_PMPCFG14 0x3ae +#define CSR_PMPCFG15 0x3af +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_PMPADDR16 0x3c0 +#define CSR_PMPADDR17 0x3c1 +#define CSR_PMPADDR18 0x3c2 +#define CSR_PMPADDR19 0x3c3 +#define CSR_PMPADDR20 0x3c4 +#define CSR_PMPADDR21 0x3c5 +#define CSR_PMPADDR22 0x3c6 +#define CSR_PMPADDR23 0x3c7 +#define CSR_PMPADDR24 0x3c8 +#define CSR_PMPADDR25 0x3c9 +#define CSR_PMPADDR26 0x3ca +#define CSR_PMPADDR27 0x3cb +#define CSR_PMPADDR28 0x3cc +#define CSR_PMPADDR29 0x3cd +#define CSR_PMPADDR30 0x3ce +#define CSR_PMPADDR31 0x3cf +#define CSR_PMPADDR32 0x3d0 +#define CSR_PMPADDR33 0x3d1 +#define CSR_PMPADDR34 0x3d2 +#define CSR_PMPADDR35 0x3d3 +#define CSR_PMPADDR36 0x3d4 +#define CSR_PMPADDR37 0x3d5 +#define CSR_PMPADDR38 0x3d6 +#define CSR_PMPADDR39 0x3d7 +#define CSR_PMPADDR40 0x3d8 +#define CSR_PMPADDR41 0x3d9 +#define CSR_PMPADDR42 0x3da +#define CSR_PMPADDR43 0x3db +#define CSR_PMPADDR44 0x3dc +#define CSR_PMPADDR45 0x3dd +#define CSR_PMPADDR46 0x3de +#define CSR_PMPADDR47 0x3df +#define CSR_PMPADDR48 0x3e0 +#define CSR_PMPADDR49 0x3e1 +#define CSR_PMPADDR50 0x3e2 +#define CSR_PMPADDR51 0x3e3 +#define CSR_PMPADDR52 0x3e4 +#define CSR_PMPADDR53 0x3e5 +#define CSR_PMPADDR54 0x3e6 +#define CSR_PMPADDR55 0x3e7 +#define CSR_PMPADDR56 0x3e8 +#define CSR_PMPADDR57 0x3e9 +#define CSR_PMPADDR58 0x3ea +#define CSR_PMPADDR59 0x3eb +#define CSR_PMPADDR60 0x3ec +#define CSR_PMPADDR61 0x3ed +#define CSR_PMPADDR62 0x3ee +#define CSR_PMPADDR63 0x3ef +#define CSR_MSECCFG 0x747 +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 +#define CSR_TCONTROL 0x7a5 +#define CSR_MCONTEXT 0x7a8 +#define CSR_MSCONTEXT 0x7aa +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH0 0x7b2 +#define CSR_DSCRATCH1 0x7b3 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_MCONFIGPTR 0xf15 +#define CSR_STIMECMPH 0x15d +#define CSR_VSTIMECMPH 0x25d +#define CSR_HTIMEDELTAH 0x615 +#define CSR_HENVCFGH 0x61a +#define CSR_HSTATEEN0H 0x61c +#define CSR_HSTATEEN1H 0x61d +#define CSR_HSTATEEN2H 0x61e +#define CSR_HSTATEEN3H 0x61f +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MSTATUSH 0x310 +#define CSR_MENVCFGH 0x31a +#define CSR_MSTATEEN0H 0x31c +#define CSR_MSTATEEN1H 0x31d +#define CSR_MSTATEEN2H 0x31e +#define CSR_MSTATEEN3H 0x31f +#define CSR_MHPMEVENT3H 0x723 +#define CSR_MHPMEVENT4H 0x724 +#define CSR_MHPMEVENT5H 0x725 +#define CSR_MHPMEVENT6H 0x726 +#define CSR_MHPMEVENT7H 0x727 +#define CSR_MHPMEVENT8H 0x728 +#define CSR_MHPMEVENT9H 0x729 +#define CSR_MHPMEVENT10H 0x72a +#define CSR_MHPMEVENT11H 0x72b +#define CSR_MHPMEVENT12H 0x72c +#define CSR_MHPMEVENT13H 0x72d +#define CSR_MHPMEVENT14H 0x72e +#define CSR_MHPMEVENT15H 0x72f +#define CSR_MHPMEVENT16H 0x730 +#define CSR_MHPMEVENT17H 0x731 +#define CSR_MHPMEVENT18H 0x732 +#define CSR_MHPMEVENT19H 0x733 +#define CSR_MHPMEVENT20H 0x734 +#define CSR_MHPMEVENT21H 0x735 +#define CSR_MHPMEVENT22H 0x736 +#define CSR_MHPMEVENT23H 0x737 +#define CSR_MHPMEVENT24H 0x738 +#define CSR_MHPMEVENT25H 0x739 +#define CSR_MHPMEVENT26H 0x73a +#define CSR_MHPMEVENT27H 0x73b +#define CSR_MHPMEVENT28H 0x73c +#define CSR_MHPMEVENT29H 0x73d +#define CSR_MHPMEVENT30H 0x73e +#define CSR_MHPMEVENT31H 0x73f +#define CSR_MSECCFGH 0x757 +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f + +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 +#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 +#define CAUSE_VIRTUAL_INSTRUCTION 0x16 +#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 + +#define INSN_FIELD_RD 0xf80 +#define INSN_FIELD_RT 0xf8000 +#define INSN_FIELD_RS1 0xf8000 +#define INSN_FIELD_RS2 0x1f00000 +#define INSN_FIELD_RS3 0xf8000000 +#define INSN_FIELD_AQRL 0x6000000 +#define INSN_FIELD_AQ 0x4000000 +#define INSN_FIELD_RL 0x2000000 +#define INSN_FIELD_FM 0xf0000000 +#define INSN_FIELD_PRED 0xf000000 +#define INSN_FIELD_SUCC 0xf00000 +#define INSN_FIELD_RM 0x7000 +#define INSN_FIELD_FUNCT3 0x7000 +#define INSN_FIELD_FUNCT2 0x6000000 +#define INSN_FIELD_IMM20 0xfffff000 +#define INSN_FIELD_JIMM20 0xfffff000 +#define INSN_FIELD_IMM12 0xfff00000 +#define INSN_FIELD_CSR 0xfff00000 +#define INSN_FIELD_IMM12HI 0xfe000000 +#define INSN_FIELD_BIMM12HI 0xfe000000 +#define INSN_FIELD_IMM12LO 0xf80 +#define INSN_FIELD_BIMM12LO 0xf80 +#define INSN_FIELD_ZIMM 0xf8000 +#define INSN_FIELD_SHAMT 0x7f00000 +#define INSN_FIELD_SHAMTW 0x1f00000 +#define INSN_FIELD_SHAMTW4 0xf00000 +#define INSN_FIELD_SHAMTD 0x3f00000 +#define INSN_FIELD_BS 0xc0000000 +#define INSN_FIELD_RNUM 0xf00000 +#define INSN_FIELD_RC 0x3e000000 +#define INSN_FIELD_IMM2 0x300000 +#define INSN_FIELD_IMM3 0x700000 +#define INSN_FIELD_IMM4 0xf00000 +#define INSN_FIELD_IMM5 0x1f00000 +#define INSN_FIELD_IMM6 0x3f00000 +#define INSN_FIELD_OPCODE 0x7f +#define INSN_FIELD_FUNCT7 0xfe000000 +#define INSN_FIELD_VD 0xf80 +#define INSN_FIELD_VS3 0xf80 +#define INSN_FIELD_VS1 0xf8000 +#define INSN_FIELD_VS2 0x1f00000 +#define INSN_FIELD_VM 0x2000000 +#define INSN_FIELD_WD 0x4000000 +#define INSN_FIELD_AMOOP 0xf8000000 +#define INSN_FIELD_NF 0xe0000000 +#define INSN_FIELD_SIMM5 0xf8000 +#define INSN_FIELD_ZIMM10 0x3ff00000 +#define INSN_FIELD_ZIMM11 0x7ff00000 +#define INSN_FIELD_C_NZUIMM10 0x1fe0 +#define INSN_FIELD_C_UIMM7LO 0x60 +#define INSN_FIELD_C_UIMM7HI 0x1c00 +#define INSN_FIELD_C_UIMM8LO 0x60 +#define INSN_FIELD_C_UIMM8HI 0x1c00 +#define INSN_FIELD_C_UIMM9LO 0x60 +#define INSN_FIELD_C_UIMM9HI 0x1c00 +#define INSN_FIELD_C_NZIMM6LO 0x7c +#define INSN_FIELD_C_NZIMM6HI 0x1000 +#define INSN_FIELD_C_IMM6LO 0x7c +#define INSN_FIELD_C_IMM6HI 0x1000 +#define INSN_FIELD_C_NZIMM10HI 0x1000 +#define INSN_FIELD_C_NZIMM10LO 0x7c +#define INSN_FIELD_C_NZIMM18HI 0x1000 +#define INSN_FIELD_C_NZIMM18LO 0x7c +#define INSN_FIELD_C_IMM12 0x1ffc +#define INSN_FIELD_C_BIMM9LO 0x7c +#define INSN_FIELD_C_BIMM9HI 0x1c00 +#define INSN_FIELD_C_NZUIMM5 0x7c +#define INSN_FIELD_C_NZUIMM6LO 0x7c +#define INSN_FIELD_C_NZUIMM6HI 0x1000 +#define INSN_FIELD_C_UIMM8SPLO 0x7c +#define INSN_FIELD_C_UIMM8SPHI 0x1000 +#define INSN_FIELD_C_UIMM8SP_S 0x1f80 +#define INSN_FIELD_C_UIMM10SPLO 0x7c +#define INSN_FIELD_C_UIMM10SPHI 0x1000 +#define INSN_FIELD_C_UIMM9SPLO 0x7c +#define INSN_FIELD_C_UIMM9SPHI 0x1000 +#define INSN_FIELD_C_UIMM10SP_S 0x1f80 +#define INSN_FIELD_C_UIMM9SP_S 0x1f80 +#define INSN_FIELD_RS1_P 0x380 +#define INSN_FIELD_RS2_P 0x1c +#define INSN_FIELD_RD_P 0x1c +#define INSN_FIELD_RD_RS1_N0 0xf80 +#define INSN_FIELD_RD_RS1_P 0x380 +#define INSN_FIELD_RD_RS1 0xf80 +#define INSN_FIELD_RD_N2 0xf80 +#define INSN_FIELD_RD_N0 0xf80 +#define INSN_FIELD_RS1_N0 0xf80 +#define INSN_FIELD_C_RS2_N0 0x7c +#define INSN_FIELD_C_RS1_N0 0xf80 +#define INSN_FIELD_C_RS2 0x7c +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) DECLARE_INSN(add16, MATCH_ADD16, MASK_ADD16) +DECLARE_INSN(add32, MATCH_ADD32, MASK_ADD32) DECLARE_INSN(add64, MATCH_ADD64, MASK_ADD64) +DECLARE_INSN(add8, MATCH_ADD8, MASK_ADD8) +DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) +DECLARE_INSN(aes32dsmi, MATCH_AES32DSMI, MASK_AES32DSMI) +DECLARE_INSN(aes32esi, MATCH_AES32ESI, MASK_AES32ESI) +DECLARE_INSN(aes32esmi, MATCH_AES32ESMI, MASK_AES32ESMI) +DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS) +DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM) +DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES) +DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM) +DECLARE_INSN(aes64im, MATCH_AES64IM, MASK_AES64IM) +DECLARE_INSN(aes64ks1i, MATCH_AES64KS1I, MASK_AES64KS1I) +DECLARE_INSN(aes64ks2, MATCH_AES64KS2, MASK_AES64KS2) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(andn, MATCH_ANDN, MASK_ANDN) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) DECLARE_INSN(ave, MATCH_AVE, MASK_AVE) +DECLARE_INSN(bclr, MATCH_BCLR, MASK_BCLR) +DECLARE_INSN(bclri, MATCH_BCLRI, MASK_BCLRI) +DECLARE_INSN(bcompress, MATCH_BCOMPRESS, MASK_BCOMPRESS) +DECLARE_INSN(bcompressw, MATCH_BCOMPRESSW, MASK_BCOMPRESSW) +DECLARE_INSN(bdecompress, MATCH_BDECOMPRESS, MASK_BDECOMPRESS) +DECLARE_INSN(bdecompressw, MATCH_BDECOMPRESSW, MASK_BDECOMPRESSW) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bext, MATCH_BEXT, MASK_BEXT) +DECLARE_INSN(bexti, MATCH_BEXTI, MASK_BEXTI) +DECLARE_INSN(bfp, MATCH_BFP, MASK_BFP) +DECLARE_INSN(bfpw, MATCH_BFPW, MASK_BFPW) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(binv, MATCH_BINV, MASK_BINV) +DECLARE_INSN(binvi, MATCH_BINVI, MASK_BINVI) DECLARE_INSN(bitrev, MATCH_BITREV, MASK_BITREV) DECLARE_INSN(bitrevi, MATCH_BITREVI, MASK_BITREVI) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bmatflip, MATCH_BMATFLIP, MASK_BMATFLIP) +DECLARE_INSN(bmator, MATCH_BMATOR, MASK_BMATOR) +DECLARE_INSN(bmatxor, MATCH_BMATXOR, MASK_BMATXOR) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) DECLARE_INSN(bpick, MATCH_BPICK, MASK_BPICK) -DECLARE_INSN(clrs8, MATCH_CLRS8, MASK_CLRS8) -DECLARE_INSN(clrs16, MATCH_CLRS16, MASK_CLRS16) -DECLARE_INSN(clrs32, MATCH_CLRS32, MASK_CLRS32) -DECLARE_INSN(clo8, MATCH_CLO8, MASK_CLO8) +DECLARE_INSN(bset, MATCH_BSET, MASK_BSET) +DECLARE_INSN(bseti, MATCH_BSETI, MASK_BSETI) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(cbo_clean, MATCH_CBO_CLEAN, MASK_CBO_CLEAN) +DECLARE_INSN(cbo_flush, MATCH_CBO_FLUSH, MASK_CBO_FLUSH) +DECLARE_INSN(cbo_inval, MATCH_CBO_INVAL, MASK_CBO_INVAL) +DECLARE_INSN(cbo_zero, MATCH_CBO_ZERO, MASK_CBO_ZERO) +DECLARE_INSN(clmul, MATCH_CLMUL, MASK_CLMUL) +DECLARE_INSN(clmulh, MATCH_CLMULH, MASK_CLMULH) +DECLARE_INSN(clmulr, MATCH_CLMULR, MASK_CLMULR) DECLARE_INSN(clo16, MATCH_CLO16, MASK_CLO16) DECLARE_INSN(clo32, MATCH_CLO32, MASK_CLO32) -DECLARE_INSN(clz8, MATCH_CLZ8, MASK_CLZ8) +DECLARE_INSN(clo8, MATCH_CLO8, MASK_CLO8) +DECLARE_INSN(clrs16, MATCH_CLRS16, MASK_CLRS16) +DECLARE_INSN(clrs32, MATCH_CLRS32, MASK_CLRS32) +DECLARE_INSN(clrs8, MATCH_CLRS8, MASK_CLRS8) +DECLARE_INSN(clz, MATCH_CLZ, MASK_CLZ) DECLARE_INSN(clz16, MATCH_CLZ16, MASK_CLZ16) DECLARE_INSN(clz32, MATCH_CLZ32, MASK_CLZ32) -DECLARE_INSN(cmpeq8, MATCH_CMPEQ8, MASK_CMPEQ8) +DECLARE_INSN(clz8, MATCH_CLZ8, MASK_CLZ8) +DECLARE_INSN(clzw, MATCH_CLZW, MASK_CLZW) +DECLARE_INSN(cmix, MATCH_CMIX, MASK_CMIX) +DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) DECLARE_INSN(cmpeq16, MATCH_CMPEQ16, MASK_CMPEQ16) +DECLARE_INSN(cmpeq8, MATCH_CMPEQ8, MASK_CMPEQ8) +DECLARE_INSN(cpop, MATCH_CPOP, MASK_CPOP) +DECLARE_INSN(cpopw, MATCH_CPOPW, MASK_CPOPW) DECLARE_INSN(cras16, MATCH_CRAS16, MASK_CRAS16) +DECLARE_INSN(cras32, MATCH_CRAS32, MASK_CRAS32) +DECLARE_INSN(crc32_b, MATCH_CRC32_B, MASK_CRC32_B) +DECLARE_INSN(crc32_d, MATCH_CRC32_D, MASK_CRC32_D) +DECLARE_INSN(crc32_h, MATCH_CRC32_H, MASK_CRC32_H) +DECLARE_INSN(crc32_w, MATCH_CRC32_W, MASK_CRC32_W) +DECLARE_INSN(crc32c_b, MATCH_CRC32C_B, MASK_CRC32C_B) +DECLARE_INSN(crc32c_d, MATCH_CRC32C_D, MASK_CRC32C_D) +DECLARE_INSN(crc32c_h, MATCH_CRC32C_H, MASK_CRC32C_H) +DECLARE_INSN(crc32c_w, MATCH_CRC32C_W, MASK_CRC32C_W) DECLARE_INSN(crsa16, MATCH_CRSA16, MASK_CRSA16) +DECLARE_INSN(crsa32, MATCH_CRSA32, MASK_CRSA32) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(ctz, MATCH_CTZ, MASK_CTZ) +DECLARE_INSN(ctzw, MATCH_CTZW, MASK_CTZW) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fclass_h, MATCH_FCLASS_H, MASK_FCLASS_H) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D) +DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L) +DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU) +DECLARE_INSN(fcvt_h_q, MATCH_FCVT_H_Q, MASK_FCVT_H_Q) +DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S) +DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W) +DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fcvt_q_h, MATCH_FCVT_Q_H, MASK_FCVT_Q_H) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flh, MATCH_FLH, MASK_FLH) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH) +DECLARE_INSN(fsl, MATCH_FSL, MASK_FSL) +DECLARE_INSN(fslw, MATCH_FSLW, MASK_FSLW) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fsr, MATCH_FSR, MASK_FSR) +DECLARE_INSN(fsri, MATCH_FSRI, MASK_FSRI) +DECLARE_INSN(fsriw, MATCH_FSRIW, MASK_FSRIW) +DECLARE_INSN(fsrw, MATCH_FSRW, MASK_FSRW) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(gorc, MATCH_GORC, MASK_GORC) +DECLARE_INSN(gorci, MATCH_GORCI, MASK_GORCI) +DECLARE_INSN(gorciw, MATCH_GORCIW, MASK_GORCIW) +DECLARE_INSN(gorcw, MATCH_GORCW, MASK_GORCW) +DECLARE_INSN(grev, MATCH_GREV, MASK_GREV) +DECLARE_INSN(grevi, MATCH_GREVI, MASK_GREVI) +DECLARE_INSN(greviw, MATCH_GREVIW, MASK_GREVIW) +DECLARE_INSN(grevw, MATCH_GREVW, MASK_GREVW) +DECLARE_INSN(hfence_gvma, MATCH_HFENCE_GVMA, MASK_HFENCE_GVMA) +DECLARE_INSN(hfence_vvma, MATCH_HFENCE_VVMA, MASK_HFENCE_VVMA) +DECLARE_INSN(hinval_gvma, MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA) +DECLARE_INSN(hinval_vvma, MATCH_HINVAL_VVMA, MASK_HINVAL_VVMA) +DECLARE_INSN(hlv_b, MATCH_HLV_B, MASK_HLV_B) +DECLARE_INSN(hlv_bu, MATCH_HLV_BU, MASK_HLV_BU) +DECLARE_INSN(hlv_d, MATCH_HLV_D, MASK_HLV_D) +DECLARE_INSN(hlv_h, MATCH_HLV_H, MASK_HLV_H) +DECLARE_INSN(hlv_hu, MATCH_HLV_HU, MASK_HLV_HU) +DECLARE_INSN(hlv_w, MATCH_HLV_W, MASK_HLV_W) +DECLARE_INSN(hlv_wu, MATCH_HLV_WU, MASK_HLV_WU) +DECLARE_INSN(hlvx_hu, MATCH_HLVX_HU, MASK_HLVX_HU) +DECLARE_INSN(hlvx_wu, MATCH_HLVX_WU, MASK_HLVX_WU) +DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B) +DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D) +DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) +DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) DECLARE_INSN(insb, MATCH_INSB, MASK_INSB) -DECLARE_INSN(kabs8, MATCH_KABS8, MASK_KABS8) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) DECLARE_INSN(kabs16, MATCH_KABS16, MASK_KABS16) +DECLARE_INSN(kabs32, MATCH_KABS32, MASK_KABS32) +DECLARE_INSN(kabs8, MATCH_KABS8, MASK_KABS8) DECLARE_INSN(kabsw, MATCH_KABSW, MASK_KABSW) -DECLARE_INSN(kadd8, MATCH_KADD8, MASK_KADD8) DECLARE_INSN(kadd16, MATCH_KADD16, MASK_KADD16) +DECLARE_INSN(kadd32, MATCH_KADD32, MASK_KADD32) DECLARE_INSN(kadd64, MATCH_KADD64, MASK_KADD64) +DECLARE_INSN(kadd8, MATCH_KADD8, MASK_KADD8) DECLARE_INSN(kaddh, MATCH_KADDH, MASK_KADDH) DECLARE_INSN(kaddw, MATCH_KADDW, MASK_KADDW) DECLARE_INSN(kcras16, MATCH_KCRAS16, MASK_KCRAS16) +DECLARE_INSN(kcras32, MATCH_KCRAS32, MASK_KCRAS32) DECLARE_INSN(kcrsa16, MATCH_KCRSA16, MASK_KCRSA16) -DECLARE_INSN(kdmbb, MATCH_KDMBB, MASK_KDMBB) -DECLARE_INSN(kdmbt, MATCH_KDMBT, MASK_KDMBT) -DECLARE_INSN(kdmtt, MATCH_KDMTT, MASK_KDMTT) +DECLARE_INSN(kcrsa32, MATCH_KCRSA32, MASK_KCRSA32) DECLARE_INSN(kdmabb, MATCH_KDMABB, MASK_KDMABB) +DECLARE_INSN(kdmabb16, MATCH_KDMABB16, MASK_KDMABB16) DECLARE_INSN(kdmabt, MATCH_KDMABT, MASK_KDMABT) +DECLARE_INSN(kdmabt16, MATCH_KDMABT16, MASK_KDMABT16) DECLARE_INSN(kdmatt, MATCH_KDMATT, MASK_KDMATT) -DECLARE_INSN(khm8, MATCH_KHM8, MASK_KHM8) -DECLARE_INSN(khmx8, MATCH_KHMX8, MASK_KHMX8) +DECLARE_INSN(kdmatt16, MATCH_KDMATT16, MASK_KDMATT16) +DECLARE_INSN(kdmbb, MATCH_KDMBB, MASK_KDMBB) +DECLARE_INSN(kdmbb16, MATCH_KDMBB16, MASK_KDMBB16) +DECLARE_INSN(kdmbt, MATCH_KDMBT, MASK_KDMBT) +DECLARE_INSN(kdmbt16, MATCH_KDMBT16, MASK_KDMBT16) +DECLARE_INSN(kdmtt, MATCH_KDMTT, MASK_KDMTT) +DECLARE_INSN(kdmtt16, MATCH_KDMTT16, MASK_KDMTT16) DECLARE_INSN(khm16, MATCH_KHM16, MASK_KHM16) -DECLARE_INSN(khmx16, MATCH_KHMX16, MASK_KHMX16) +DECLARE_INSN(khm8, MATCH_KHM8, MASK_KHM8) DECLARE_INSN(khmbb, MATCH_KHMBB, MASK_KHMBB) +DECLARE_INSN(khmbb16, MATCH_KHMBB16, MASK_KHMBB16) DECLARE_INSN(khmbt, MATCH_KHMBT, MASK_KHMBT) +DECLARE_INSN(khmbt16, MATCH_KHMBT16, MASK_KHMBT16) DECLARE_INSN(khmtt, MATCH_KHMTT, MASK_KHMTT) +DECLARE_INSN(khmtt16, MATCH_KHMTT16, MASK_KHMTT16) +DECLARE_INSN(khmx16, MATCH_KHMX16, MASK_KHMX16) +DECLARE_INSN(khmx8, MATCH_KHMX8, MASK_KHMX8) DECLARE_INSN(kmabb, MATCH_KMABB, MASK_KMABB) +DECLARE_INSN(kmabb32, MATCH_KMABB32, MASK_KMABB32) DECLARE_INSN(kmabt, MATCH_KMABT, MASK_KMABT) -DECLARE_INSN(kmatt, MATCH_KMATT, MASK_KMATT) +DECLARE_INSN(kmabt32, MATCH_KMABT32, MASK_KMABT32) DECLARE_INSN(kmada, MATCH_KMADA, MASK_KMADA) -DECLARE_INSN(kmaxda, MATCH_KMAXDA, MASK_KMAXDA) -DECLARE_INSN(kmads, MATCH_KMADS, MASK_KMADS) DECLARE_INSN(kmadrs, MATCH_KMADRS, MASK_KMADRS) -DECLARE_INSN(kmaxds, MATCH_KMAXDS, MASK_KMAXDS) +DECLARE_INSN(kmadrs32, MATCH_KMADRS32, MASK_KMADRS32) +DECLARE_INSN(kmads, MATCH_KMADS, MASK_KMADS) +DECLARE_INSN(kmads32, MATCH_KMADS32, MASK_KMADS32) DECLARE_INSN(kmar64, MATCH_KMAR64, MASK_KMAR64) +DECLARE_INSN(kmatt, MATCH_KMATT, MASK_KMATT) +DECLARE_INSN(kmatt32, MATCH_KMATT32, MASK_KMATT32) +DECLARE_INSN(kmaxda, MATCH_KMAXDA, MASK_KMAXDA) +DECLARE_INSN(kmaxda32, MATCH_KMAXDA32, MASK_KMAXDA32) +DECLARE_INSN(kmaxds, MATCH_KMAXDS, MASK_KMAXDS) +DECLARE_INSN(kmaxds32, MATCH_KMAXDS32, MASK_KMAXDS32) DECLARE_INSN(kmda, MATCH_KMDA, MASK_KMDA) -DECLARE_INSN(kmxda, MATCH_KMXDA, MASK_KMXDA) +DECLARE_INSN(kmda32, MATCH_KMDA32, MASK_KMDA32) DECLARE_INSN(kmmac, MATCH_KMMAC, MASK_KMMAC) DECLARE_INSN(kmmac_u, MATCH_KMMAC_U, MASK_KMMAC_U) DECLARE_INSN(kmmawb, MATCH_KMMAWB, MASK_KMMAWB) -DECLARE_INSN(kmmawb_u, MATCH_KMMAWB_U, MASK_KMMAWB_U) DECLARE_INSN(kmmawb2, MATCH_KMMAWB2, MASK_KMMAWB2) DECLARE_INSN(kmmawb2_u, MATCH_KMMAWB2_U, MASK_KMMAWB2_U) +DECLARE_INSN(kmmawb_u, MATCH_KMMAWB_U, MASK_KMMAWB_U) DECLARE_INSN(kmmawt, MATCH_KMMAWT, MASK_KMMAWT) -DECLARE_INSN(kmmawt_u, MATCH_KMMAWT_U, MASK_KMMAWT_U) DECLARE_INSN(kmmawt2, MATCH_KMMAWT2, MASK_KMMAWT2) DECLARE_INSN(kmmawt2_u, MATCH_KMMAWT2_U, MASK_KMMAWT2_U) +DECLARE_INSN(kmmawt_u, MATCH_KMMAWT_U, MASK_KMMAWT_U) DECLARE_INSN(kmmsb, MATCH_KMMSB, MASK_KMMSB) DECLARE_INSN(kmmsb_u, MATCH_KMMSB_U, MASK_KMMSB_U) DECLARE_INSN(kmmwb2, MATCH_KMMWB2, MASK_KMMWB2) @@ -4076,86 +3617,205 @@ DECLARE_INSN(kmmwb2_u, MATCH_KMMWB2_U, MASK_KMMWB2_U) DECLARE_INSN(kmmwt2, MATCH_KMMWT2, MASK_KMMWT2) DECLARE_INSN(kmmwt2_u, MATCH_KMMWT2_U, MASK_KMMWT2_U) DECLARE_INSN(kmsda, MATCH_KMSDA, MASK_KMSDA) -DECLARE_INSN(kmsxda, MATCH_KMSXDA, MASK_KMSXDA) +DECLARE_INSN(kmsda32, MATCH_KMSDA32, MASK_KMSDA32) DECLARE_INSN(kmsr64, MATCH_KMSR64, MASK_KMSR64) -DECLARE_INSN(ksllw, MATCH_KSLLW, MASK_KSLLW) -DECLARE_INSN(kslliw, MATCH_KSLLIW, MASK_KSLLIW) -DECLARE_INSN(ksll8, MATCH_KSLL8, MASK_KSLL8) -DECLARE_INSN(kslli8, MATCH_KSLLI8, MASK_KSLLI8) +DECLARE_INSN(kmsxda, MATCH_KMSXDA, MASK_KMSXDA) +DECLARE_INSN(kmsxda32, MATCH_KMSXDA32, MASK_KMSXDA32) +DECLARE_INSN(kmxda, MATCH_KMXDA, MASK_KMXDA) +DECLARE_INSN(kmxda32, MATCH_KMXDA32, MASK_KMXDA32) DECLARE_INSN(ksll16, MATCH_KSLL16, MASK_KSLL16) +DECLARE_INSN(ksll32, MATCH_KSLL32, MASK_KSLL32) +DECLARE_INSN(ksll8, MATCH_KSLL8, MASK_KSLL8) DECLARE_INSN(kslli16, MATCH_KSLLI16, MASK_KSLLI16) -DECLARE_INSN(kslra8, MATCH_KSLRA8, MASK_KSLRA8) -DECLARE_INSN(kslra8_u, MATCH_KSLRA8_U, MASK_KSLRA8_U) +DECLARE_INSN(kslli32, MATCH_KSLLI32, MASK_KSLLI32) +DECLARE_INSN(kslli8, MATCH_KSLLI8, MASK_KSLLI8) +DECLARE_INSN(kslliw, MATCH_KSLLIW, MASK_KSLLIW) +DECLARE_INSN(ksllw, MATCH_KSLLW, MASK_KSLLW) DECLARE_INSN(kslra16, MATCH_KSLRA16, MASK_KSLRA16) DECLARE_INSN(kslra16_u, MATCH_KSLRA16_U, MASK_KSLRA16_U) +DECLARE_INSN(kslra32, MATCH_KSLRA32, MASK_KSLRA32) +DECLARE_INSN(kslra32_u, MATCH_KSLRA32_U, MASK_KSLRA32_U) +DECLARE_INSN(kslra8, MATCH_KSLRA8, MASK_KSLRA8) +DECLARE_INSN(kslra8_u, MATCH_KSLRA8_U, MASK_KSLRA8_U) DECLARE_INSN(kslraw, MATCH_KSLRAW, MASK_KSLRAW) DECLARE_INSN(kslraw_u, MATCH_KSLRAW_U, MASK_KSLRAW_U) DECLARE_INSN(kstas16, MATCH_KSTAS16, MASK_KSTAS16) +DECLARE_INSN(kstas32, MATCH_KSTAS32, MASK_KSTAS32) DECLARE_INSN(kstsa16, MATCH_KSTSA16, MASK_KSTSA16) -DECLARE_INSN(ksub8, MATCH_KSUB8, MASK_KSUB8) +DECLARE_INSN(kstsa32, MATCH_KSTSA32, MASK_KSTSA32) DECLARE_INSN(ksub16, MATCH_KSUB16, MASK_KSUB16) +DECLARE_INSN(ksub32, MATCH_KSUB32, MASK_KSUB32) DECLARE_INSN(ksub64, MATCH_KSUB64, MASK_KSUB64) +DECLARE_INSN(ksub8, MATCH_KSUB8, MASK_KSUB8) DECLARE_INSN(ksubh, MATCH_KSUBH, MASK_KSUBH) DECLARE_INSN(ksubw, MATCH_KSUBW, MASK_KSUBW) DECLARE_INSN(kwmmul, MATCH_KWMMUL, MASK_KWMMUL) DECLARE_INSN(kwmmul_u, MATCH_KWMMUL_U, MASK_KWMMUL_U) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) DECLARE_INSN(maddr32, MATCH_MADDR32, MASK_MADDR32) +DECLARE_INSN(max, MATCH_MAX, MASK_MAX) +DECLARE_INSN(maxu, MATCH_MAXU, MASK_MAXU) DECLARE_INSN(maxw, MATCH_MAXW, MASK_MAXW) +DECLARE_INSN(min, MATCH_MIN, MASK_MIN) +DECLARE_INSN(minu, MATCH_MINU, MASK_MINU) DECLARE_INSN(minw, MATCH_MINW, MASK_MINW) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) DECLARE_INSN(msubr32, MATCH_MSUBR32, MASK_MSUBR32) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) DECLARE_INSN(mulr64, MATCH_MULR64, MASK_MULR64) DECLARE_INSN(mulsr64, MATCH_MULSR64, MASK_MULSR64) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(orn, MATCH_ORN, MASK_ORN) +DECLARE_INSN(pack, MATCH_PACK, MASK_PACK) +DECLARE_INSN(packh, MATCH_PACKH, MASK_PACKH) +DECLARE_INSN(packu, MATCH_PACKU, MASK_PACKU) +DECLARE_INSN(packuw, MATCH_PACKUW, MASK_PACKUW) +DECLARE_INSN(packw, MATCH_PACKW, MASK_PACKW) +DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) DECLARE_INSN(pbsad, MATCH_PBSAD, MASK_PBSAD) DECLARE_INSN(pbsada, MATCH_PBSADA, MASK_PBSADA) DECLARE_INSN(pkbb16, MATCH_PKBB16, MASK_PKBB16) +DECLARE_INSN(pkbb32, MATCH_PKBB32, MASK_PKBB32) DECLARE_INSN(pkbt16, MATCH_PKBT16, MASK_PKBT16) -DECLARE_INSN(pktt16, MATCH_PKTT16, MASK_PKTT16) +DECLARE_INSN(pkbt32, MATCH_PKBT32, MASK_PKBT32) DECLARE_INSN(pktb16, MATCH_PKTB16, MASK_PKTB16) -DECLARE_INSN(radd8, MATCH_RADD8, MASK_RADD8) +DECLARE_INSN(pktb32, MATCH_PKTB32, MASK_PKTB32) +DECLARE_INSN(pktt16, MATCH_PKTT16, MASK_PKTT16) +DECLARE_INSN(pktt32, MATCH_PKTT32, MASK_PKTT32) +DECLARE_INSN(prefetch_i, MATCH_PREFETCH_I, MASK_PREFETCH_I) +DECLARE_INSN(prefetch_r, MATCH_PREFETCH_R, MASK_PREFETCH_R) +DECLARE_INSN(prefetch_w, MATCH_PREFETCH_W, MASK_PREFETCH_W) DECLARE_INSN(radd16, MATCH_RADD16, MASK_RADD16) +DECLARE_INSN(radd32, MATCH_RADD32, MASK_RADD32) DECLARE_INSN(radd64, MATCH_RADD64, MASK_RADD64) +DECLARE_INSN(radd8, MATCH_RADD8, MASK_RADD8) DECLARE_INSN(raddw, MATCH_RADDW, MASK_RADDW) DECLARE_INSN(rcras16, MATCH_RCRAS16, MASK_RCRAS16) +DECLARE_INSN(rcras32, MATCH_RCRAS32, MASK_RCRAS32) DECLARE_INSN(rcrsa16, MATCH_RCRSA16, MASK_RCRSA16) +DECLARE_INSN(rcrsa32, MATCH_RCRSA32, MASK_RCRSA32) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(rol, MATCH_ROL, MASK_ROL) +DECLARE_INSN(rolw, MATCH_ROLW, MASK_ROLW) +DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) +DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) +DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) +DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) DECLARE_INSN(rstas16, MATCH_RSTAS16, MASK_RSTAS16) +DECLARE_INSN(rstas32, MATCH_RSTAS32, MASK_RSTAS32) DECLARE_INSN(rstsa16, MATCH_RSTSA16, MASK_RSTSA16) -DECLARE_INSN(rsub8, MATCH_RSUB8, MASK_RSUB8) +DECLARE_INSN(rstsa32, MATCH_RSTSA32, MASK_RSTSA32) DECLARE_INSN(rsub16, MATCH_RSUB16, MASK_RSUB16) +DECLARE_INSN(rsub32, MATCH_RSUB32, MASK_RSUB32) DECLARE_INSN(rsub64, MATCH_RSUB64, MASK_RSUB64) +DECLARE_INSN(rsub8, MATCH_RSUB8, MASK_RSUB8) DECLARE_INSN(rsubw, MATCH_RSUBW, MASK_RSUBW) -DECLARE_INSN(sclip8, MATCH_SCLIP8, MASK_SCLIP8) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) DECLARE_INSN(sclip16, MATCH_SCLIP16, MASK_SCLIP16) DECLARE_INSN(sclip32, MATCH_SCLIP32, MASK_SCLIP32) -DECLARE_INSN(scmple8, MATCH_SCMPLE8, MASK_SCMPLE8) +DECLARE_INSN(sclip8, MATCH_SCLIP8, MASK_SCLIP8) DECLARE_INSN(scmple16, MATCH_SCMPLE16, MASK_SCMPLE16) -DECLARE_INSN(scmplt8, MATCH_SCMPLT8, MASK_SCMPLT8) +DECLARE_INSN(scmple8, MATCH_SCMPLE8, MASK_SCMPLE8) DECLARE_INSN(scmplt16, MATCH_SCMPLT16, MASK_SCMPLT16) -DECLARE_INSN(sll8, MATCH_SLL8, MASK_SLL8) -DECLARE_INSN(slli8, MATCH_SLLI8, MASK_SLLI8) +DECLARE_INSN(scmplt8, MATCH_SCMPLT8, MASK_SCMPLT8) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) +DECLARE_INSN(sext_h, MATCH_SEXT_H, MASK_SEXT_H) +DECLARE_INSN(sfence_inval_ir, MATCH_SFENCE_INVAL_IR, MASK_SFENCE_INVAL_IR) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(sfence_w_inval, MATCH_SFENCE_W_INVAL, MASK_SFENCE_W_INVAL) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sh1add, MATCH_SH1ADD, MASK_SH1ADD) +DECLARE_INSN(sh1add_uw, MATCH_SH1ADD_UW, MASK_SH1ADD_UW) +DECLARE_INSN(sh2add, MATCH_SH2ADD, MASK_SH2ADD) +DECLARE_INSN(sh2add_uw, MATCH_SH2ADD_UW, MASK_SH2ADD_UW) +DECLARE_INSN(sh3add, MATCH_SH3ADD, MASK_SH3ADD) +DECLARE_INSN(sh3add_uw, MATCH_SH3ADD_UW, MASK_SH3ADD_UW) +DECLARE_INSN(sha256sig0, MATCH_SHA256SIG0, MASK_SHA256SIG0) +DECLARE_INSN(sha256sig1, MATCH_SHA256SIG1, MASK_SHA256SIG1) +DECLARE_INSN(sha256sum0, MATCH_SHA256SUM0, MASK_SHA256SUM0) +DECLARE_INSN(sha256sum1, MATCH_SHA256SUM1, MASK_SHA256SUM1) +DECLARE_INSN(sha512sig0, MATCH_SHA512SIG0, MASK_SHA512SIG0) +DECLARE_INSN(sha512sig0h, MATCH_SHA512SIG0H, MASK_SHA512SIG0H) +DECLARE_INSN(sha512sig0l, MATCH_SHA512SIG0L, MASK_SHA512SIG0L) +DECLARE_INSN(sha512sig1, MATCH_SHA512SIG1, MASK_SHA512SIG1) +DECLARE_INSN(sha512sig1h, MATCH_SHA512SIG1H, MASK_SHA512SIG1H) +DECLARE_INSN(sha512sig1l, MATCH_SHA512SIG1L, MASK_SHA512SIG1L) +DECLARE_INSN(sha512sum0, MATCH_SHA512SUM0, MASK_SHA512SUM0) +DECLARE_INSN(sha512sum0r, MATCH_SHA512SUM0R, MASK_SHA512SUM0R) +DECLARE_INSN(sha512sum1, MATCH_SHA512SUM1, MASK_SHA512SUM1) +DECLARE_INSN(sha512sum1r, MATCH_SHA512SUM1R, MASK_SHA512SUM1R) +DECLARE_INSN(shfl, MATCH_SHFL, MASK_SHFL) +DECLARE_INSN(shfli, MATCH_SHFLI, MASK_SHFLI) +DECLARE_INSN(shflw, MATCH_SHFLW, MASK_SHFLW) +DECLARE_INSN(sinval_vma, MATCH_SINVAL_VMA, MASK_SINVAL_VMA) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) DECLARE_INSN(sll16, MATCH_SLL16, MASK_SLL16) +DECLARE_INSN(sll32, MATCH_SLL32, MASK_SLL32) +DECLARE_INSN(sll8, MATCH_SLL8, MASK_SLL8) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) DECLARE_INSN(slli16, MATCH_SLLI16, MASK_SLLI16) +DECLARE_INSN(slli32, MATCH_SLLI32, MASK_SLLI32) +DECLARE_INSN(slli8, MATCH_SLLI8, MASK_SLLI8) +DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) +DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) +DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) +DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) +DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) +DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) +DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) DECLARE_INSN(smal, MATCH_SMAL, MASK_SMAL) DECLARE_INSN(smalbb, MATCH_SMALBB, MASK_SMALBB) DECLARE_INSN(smalbt, MATCH_SMALBT, MASK_SMALBT) -DECLARE_INSN(smaltt, MATCH_SMALTT, MASK_SMALTT) DECLARE_INSN(smalda, MATCH_SMALDA, MASK_SMALDA) -DECLARE_INSN(smalxda, MATCH_SMALXDA, MASK_SMALXDA) -DECLARE_INSN(smalds, MATCH_SMALDS, MASK_SMALDS) DECLARE_INSN(smaldrs, MATCH_SMALDRS, MASK_SMALDRS) +DECLARE_INSN(smalds, MATCH_SMALDS, MASK_SMALDS) +DECLARE_INSN(smaltt, MATCH_SMALTT, MASK_SMALTT) +DECLARE_INSN(smalxda, MATCH_SMALXDA, MASK_SMALXDA) DECLARE_INSN(smalxds, MATCH_SMALXDS, MASK_SMALXDS) -DECLARE_INSN(smar64, MATCH_SMAR64, MASK_SMAR64) DECLARE_INSN(smaqa, MATCH_SMAQA, MASK_SMAQA) DECLARE_INSN(smaqa_su, MATCH_SMAQA_SU, MASK_SMAQA_SU) -DECLARE_INSN(smax8, MATCH_SMAX8, MASK_SMAX8) +DECLARE_INSN(smar64, MATCH_SMAR64, MASK_SMAR64) DECLARE_INSN(smax16, MATCH_SMAX16, MASK_SMAX16) +DECLARE_INSN(smax32, MATCH_SMAX32, MASK_SMAX32) +DECLARE_INSN(smax8, MATCH_SMAX8, MASK_SMAX8) DECLARE_INSN(smbb16, MATCH_SMBB16, MASK_SMBB16) DECLARE_INSN(smbt16, MATCH_SMBT16, MASK_SMBT16) -DECLARE_INSN(smtt16, MATCH_SMTT16, MASK_SMTT16) -DECLARE_INSN(smds, MATCH_SMDS, MASK_SMDS) +DECLARE_INSN(smbt32, MATCH_SMBT32, MASK_SMBT32) DECLARE_INSN(smdrs, MATCH_SMDRS, MASK_SMDRS) -DECLARE_INSN(smxds, MATCH_SMXDS, MASK_SMXDS) -DECLARE_INSN(smin8, MATCH_SMIN8, MASK_SMIN8) +DECLARE_INSN(smdrs32, MATCH_SMDRS32, MASK_SMDRS32) +DECLARE_INSN(smds, MATCH_SMDS, MASK_SMDS) +DECLARE_INSN(smds32, MATCH_SMDS32, MASK_SMDS32) DECLARE_INSN(smin16, MATCH_SMIN16, MASK_SMIN16) +DECLARE_INSN(smin32, MATCH_SMIN32, MASK_SMIN32) +DECLARE_INSN(smin8, MATCH_SMIN8, MASK_SMIN8) DECLARE_INSN(smmul, MATCH_SMMUL, MASK_SMMUL) DECLARE_INSN(smmul_u, MATCH_SMMUL_U, MASK_SMMUL_U) DECLARE_INSN(smmwb, MATCH_SMMWB, MASK_SMMWB) @@ -4165,181 +3825,598 @@ DECLARE_INSN(smmwt_u, MATCH_SMMWT_U, MASK_SMMWT_U) DECLARE_INSN(smslda, MATCH_SMSLDA, MASK_SMSLDA) DECLARE_INSN(smslxda, MATCH_SMSLXDA, MASK_SMSLXDA) DECLARE_INSN(smsr64, MATCH_SMSR64, MASK_SMSR64) -DECLARE_INSN(smul8, MATCH_SMUL8, MASK_SMUL8) -DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) +DECLARE_INSN(smtt16, MATCH_SMTT16, MASK_SMTT16) +DECLARE_INSN(smtt32, MATCH_SMTT32, MASK_SMTT32) DECLARE_INSN(smul16, MATCH_SMUL16, MASK_SMUL16) +DECLARE_INSN(smul8, MATCH_SMUL8, MASK_SMUL8) DECLARE_INSN(smulx16, MATCH_SMULX16, MASK_SMULX16) -DECLARE_INSN(sra_u, MATCH_SRA_U, MASK_SRA_U) -DECLARE_INSN(srai_u, MATCH_SRAI_U, MASK_SRAI_U) -DECLARE_INSN(sra8, MATCH_SRA8, MASK_SRA8) -DECLARE_INSN(sra8_u, MATCH_SRA8_U, MASK_SRA8_U) -DECLARE_INSN(srai8, MATCH_SRAI8, MASK_SRAI8) -DECLARE_INSN(srai8_u, MATCH_SRAI8_U, MASK_SRAI8_U) +DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) +DECLARE_INSN(smxds, MATCH_SMXDS, MASK_SMXDS) +DECLARE_INSN(smxds32, MATCH_SMXDS32, MASK_SMXDS32) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(sra16, MATCH_SRA16, MASK_SRA16) DECLARE_INSN(sra16_u, MATCH_SRA16_U, MASK_SRA16_U) +DECLARE_INSN(sra32, MATCH_SRA32, MASK_SRA32) +DECLARE_INSN(sra32_u, MATCH_SRA32_U, MASK_SRA32_U) +DECLARE_INSN(sra8, MATCH_SRA8, MASK_SRA8) +DECLARE_INSN(sra8_u, MATCH_SRA8_U, MASK_SRA8_U) +DECLARE_INSN(sra_u, MATCH_SRA_U, MASK_SRA_U) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(srai16, MATCH_SRAI16, MASK_SRAI16) DECLARE_INSN(srai16_u, MATCH_SRAI16_U, MASK_SRAI16_U) -DECLARE_INSN(srl8, MATCH_SRL8, MASK_SRL8) -DECLARE_INSN(srl8_u, MATCH_SRL8_U, MASK_SRL8_U) -DECLARE_INSN(srli8, MATCH_SRLI8, MASK_SRLI8) -DECLARE_INSN(srli8_u, MATCH_SRLI8_U, MASK_SRLI8_U) +DECLARE_INSN(srai32, MATCH_SRAI32, MASK_SRAI32) +DECLARE_INSN(srai32_u, MATCH_SRAI32_U, MASK_SRAI32_U) +DECLARE_INSN(srai8, MATCH_SRAI8, MASK_SRAI8) +DECLARE_INSN(srai8_u, MATCH_SRAI8_U, MASK_SRAI8_U) +DECLARE_INSN(srai_u, MATCH_SRAI_U, MASK_SRAI_U) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(sraiw_u, MATCH_SRAIW_U, MASK_SRAIW_U) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) DECLARE_INSN(srl16, MATCH_SRL16, MASK_SRL16) DECLARE_INSN(srl16_u, MATCH_SRL16_U, MASK_SRL16_U) +DECLARE_INSN(srl32, MATCH_SRL32, MASK_SRL32) +DECLARE_INSN(srl32_u, MATCH_SRL32_U, MASK_SRL32_U) +DECLARE_INSN(srl8, MATCH_SRL8, MASK_SRL8) +DECLARE_INSN(srl8_u, MATCH_SRL8_U, MASK_SRL8_U) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srli16, MATCH_SRLI16, MASK_SRLI16) DECLARE_INSN(srli16_u, MATCH_SRLI16_U, MASK_SRLI16_U) +DECLARE_INSN(srli32, MATCH_SRLI32, MASK_SRLI32) +DECLARE_INSN(srli32_u, MATCH_SRLI32_U, MASK_SRLI32_U) +DECLARE_INSN(srli8, MATCH_SRLI8, MASK_SRLI8) +DECLARE_INSN(srli8_u, MATCH_SRLI8_U, MASK_SRLI8_U) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) +DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) +DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) +DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) DECLARE_INSN(stas16, MATCH_STAS16, MASK_STAS16) +DECLARE_INSN(stas32, MATCH_STAS32, MASK_STAS32) DECLARE_INSN(stsa16, MATCH_STSA16, MASK_STSA16) -DECLARE_INSN(sub8, MATCH_SUB8, MASK_SUB8) +DECLARE_INSN(stsa32, MATCH_STSA32, MASK_STSA32) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) DECLARE_INSN(sub16, MATCH_SUB16, MASK_SUB16) +DECLARE_INSN(sub32, MATCH_SUB32, MASK_SUB32) DECLARE_INSN(sub64, MATCH_SUB64, MASK_SUB64) +DECLARE_INSN(sub8, MATCH_SUB8, MASK_SUB8) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sunpkd810, MATCH_SUNPKD810, MASK_SUNPKD810) DECLARE_INSN(sunpkd820, MATCH_SUNPKD820, MASK_SUNPKD820) DECLARE_INSN(sunpkd830, MATCH_SUNPKD830, MASK_SUNPKD830) DECLARE_INSN(sunpkd831, MATCH_SUNPKD831, MASK_SUNPKD831) DECLARE_INSN(sunpkd832, MATCH_SUNPKD832, MASK_SUNPKD832) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) DECLARE_INSN(swap8, MATCH_SWAP8, MASK_SWAP8) -DECLARE_INSN(uclip8, MATCH_UCLIP8, MASK_UCLIP8) DECLARE_INSN(uclip16, MATCH_UCLIP16, MASK_UCLIP16) DECLARE_INSN(uclip32, MATCH_UCLIP32, MASK_UCLIP32) -DECLARE_INSN(ucmple8, MATCH_UCMPLE8, MASK_UCMPLE8) +DECLARE_INSN(uclip8, MATCH_UCLIP8, MASK_UCLIP8) DECLARE_INSN(ucmple16, MATCH_UCMPLE16, MASK_UCMPLE16) -DECLARE_INSN(ucmplt8, MATCH_UCMPLT8, MASK_UCMPLT8) +DECLARE_INSN(ucmple8, MATCH_UCMPLE8, MASK_UCMPLE8) DECLARE_INSN(ucmplt16, MATCH_UCMPLT16, MASK_UCMPLT16) -DECLARE_INSN(ukadd8, MATCH_UKADD8, MASK_UKADD8) +DECLARE_INSN(ucmplt8, MATCH_UCMPLT8, MASK_UCMPLT8) DECLARE_INSN(ukadd16, MATCH_UKADD16, MASK_UKADD16) +DECLARE_INSN(ukadd32, MATCH_UKADD32, MASK_UKADD32) DECLARE_INSN(ukadd64, MATCH_UKADD64, MASK_UKADD64) +DECLARE_INSN(ukadd8, MATCH_UKADD8, MASK_UKADD8) DECLARE_INSN(ukaddh, MATCH_UKADDH, MASK_UKADDH) DECLARE_INSN(ukaddw, MATCH_UKADDW, MASK_UKADDW) DECLARE_INSN(ukcras16, MATCH_UKCRAS16, MASK_UKCRAS16) +DECLARE_INSN(ukcras32, MATCH_UKCRAS32, MASK_UKCRAS32) DECLARE_INSN(ukcrsa16, MATCH_UKCRSA16, MASK_UKCRSA16) +DECLARE_INSN(ukcrsa32, MATCH_UKCRSA32, MASK_UKCRSA32) DECLARE_INSN(ukmar64, MATCH_UKMAR64, MASK_UKMAR64) DECLARE_INSN(ukmsr64, MATCH_UKMSR64, MASK_UKMSR64) DECLARE_INSN(ukstas16, MATCH_UKSTAS16, MASK_UKSTAS16) +DECLARE_INSN(ukstas32, MATCH_UKSTAS32, MASK_UKSTAS32) DECLARE_INSN(ukstsa16, MATCH_UKSTSA16, MASK_UKSTSA16) -DECLARE_INSN(uksub8, MATCH_UKSUB8, MASK_UKSUB8) +DECLARE_INSN(ukstsa32, MATCH_UKSTSA32, MASK_UKSTSA32) DECLARE_INSN(uksub16, MATCH_UKSUB16, MASK_UKSUB16) +DECLARE_INSN(uksub32, MATCH_UKSUB32, MASK_UKSUB32) DECLARE_INSN(uksub64, MATCH_UKSUB64, MASK_UKSUB64) +DECLARE_INSN(uksub8, MATCH_UKSUB8, MASK_UKSUB8) DECLARE_INSN(uksubh, MATCH_UKSUBH, MASK_UKSUBH) DECLARE_INSN(uksubw, MATCH_UKSUBW, MASK_UKSUBW) -DECLARE_INSN(umar64, MATCH_UMAR64, MASK_UMAR64) DECLARE_INSN(umaqa, MATCH_UMAQA, MASK_UMAQA) -DECLARE_INSN(umax8, MATCH_UMAX8, MASK_UMAX8) +DECLARE_INSN(umar64, MATCH_UMAR64, MASK_UMAR64) DECLARE_INSN(umax16, MATCH_UMAX16, MASK_UMAX16) -DECLARE_INSN(umin8, MATCH_UMIN8, MASK_UMIN8) +DECLARE_INSN(umax32, MATCH_UMAX32, MASK_UMAX32) +DECLARE_INSN(umax8, MATCH_UMAX8, MASK_UMAX8) DECLARE_INSN(umin16, MATCH_UMIN16, MASK_UMIN16) +DECLARE_INSN(umin32, MATCH_UMIN32, MASK_UMIN32) +DECLARE_INSN(umin8, MATCH_UMIN8, MASK_UMIN8) DECLARE_INSN(umsr64, MATCH_UMSR64, MASK_UMSR64) -DECLARE_INSN(umul8, MATCH_UMUL8, MASK_UMUL8) -DECLARE_INSN(umulx8, MATCH_UMULX8, MASK_UMULX8) DECLARE_INSN(umul16, MATCH_UMUL16, MASK_UMUL16) +DECLARE_INSN(umul8, MATCH_UMUL8, MASK_UMUL8) DECLARE_INSN(umulx16, MATCH_UMULX16, MASK_UMULX16) -DECLARE_INSN(uradd8, MATCH_URADD8, MASK_URADD8) +DECLARE_INSN(umulx8, MATCH_UMULX8, MASK_UMULX8) +DECLARE_INSN(unshfl, MATCH_UNSHFL, MASK_UNSHFL) +DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) +DECLARE_INSN(unshflw, MATCH_UNSHFLW, MASK_UNSHFLW) DECLARE_INSN(uradd16, MATCH_URADD16, MASK_URADD16) +DECLARE_INSN(uradd32, MATCH_URADD32, MASK_URADD32) DECLARE_INSN(uradd64, MATCH_URADD64, MASK_URADD64) +DECLARE_INSN(uradd8, MATCH_URADD8, MASK_URADD8) DECLARE_INSN(uraddw, MATCH_URADDW, MASK_URADDW) DECLARE_INSN(urcras16, MATCH_URCRAS16, MASK_URCRAS16) +DECLARE_INSN(urcras32, MATCH_URCRAS32, MASK_URCRAS32) DECLARE_INSN(urcrsa16, MATCH_URCRSA16, MASK_URCRSA16) +DECLARE_INSN(urcrsa32, MATCH_URCRSA32, MASK_URCRSA32) DECLARE_INSN(urstas16, MATCH_URSTAS16, MASK_URSTAS16) +DECLARE_INSN(urstas32, MATCH_URSTAS32, MASK_URSTAS32) DECLARE_INSN(urstsa16, MATCH_URSTSA16, MASK_URSTSA16) -DECLARE_INSN(ursub8, MATCH_URSUB8, MASK_URSUB8) +DECLARE_INSN(urstsa32, MATCH_URSTSA32, MASK_URSTSA32) DECLARE_INSN(ursub16, MATCH_URSUB16, MASK_URSUB16) +DECLARE_INSN(ursub32, MATCH_URSUB32, MASK_URSUB32) DECLARE_INSN(ursub64, MATCH_URSUB64, MASK_URSUB64) +DECLARE_INSN(ursub8, MATCH_URSUB8, MASK_URSUB8) DECLARE_INSN(ursubw, MATCH_URSUBW, MASK_URSUBW) -DECLARE_INSN(wexti, MATCH_WEXTI, MASK_WEXTI) +DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) +DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) +DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) +DECLARE_INSN(vaaddu_vx, MATCH_VAADDU_VX, MASK_VAADDU_VX) +DECLARE_INSN(vadc_vim, MATCH_VADC_VIM, MASK_VADC_VIM) +DECLARE_INSN(vadc_vvm, MATCH_VADC_VVM, MASK_VADC_VVM) +DECLARE_INSN(vadc_vxm, MATCH_VADC_VXM, MASK_VADC_VXM) +DECLARE_INSN(vadd_vi, MATCH_VADD_VI, MASK_VADD_VI) +DECLARE_INSN(vadd_vv, MATCH_VADD_VV, MASK_VADD_VV) +DECLARE_INSN(vadd_vx, MATCH_VADD_VX, MASK_VADD_VX) +DECLARE_INSN(vamoaddei16_v, MATCH_VAMOADDEI16_V, MASK_VAMOADDEI16_V) +DECLARE_INSN(vamoaddei32_v, MATCH_VAMOADDEI32_V, MASK_VAMOADDEI32_V) +DECLARE_INSN(vamoaddei64_v, MATCH_VAMOADDEI64_V, MASK_VAMOADDEI64_V) +DECLARE_INSN(vamoaddei8_v, MATCH_VAMOADDEI8_V, MASK_VAMOADDEI8_V) +DECLARE_INSN(vamoandei16_v, MATCH_VAMOANDEI16_V, MASK_VAMOANDEI16_V) +DECLARE_INSN(vamoandei32_v, MATCH_VAMOANDEI32_V, MASK_VAMOANDEI32_V) +DECLARE_INSN(vamoandei64_v, MATCH_VAMOANDEI64_V, MASK_VAMOANDEI64_V) +DECLARE_INSN(vamoandei8_v, MATCH_VAMOANDEI8_V, MASK_VAMOANDEI8_V) +DECLARE_INSN(vamomaxei16_v, MATCH_VAMOMAXEI16_V, MASK_VAMOMAXEI16_V) +DECLARE_INSN(vamomaxei32_v, MATCH_VAMOMAXEI32_V, MASK_VAMOMAXEI32_V) +DECLARE_INSN(vamomaxei64_v, MATCH_VAMOMAXEI64_V, MASK_VAMOMAXEI64_V) +DECLARE_INSN(vamomaxei8_v, MATCH_VAMOMAXEI8_V, MASK_VAMOMAXEI8_V) +DECLARE_INSN(vamomaxuei16_v, MATCH_VAMOMAXUEI16_V, MASK_VAMOMAXUEI16_V) +DECLARE_INSN(vamomaxuei32_v, MATCH_VAMOMAXUEI32_V, MASK_VAMOMAXUEI32_V) +DECLARE_INSN(vamomaxuei64_v, MATCH_VAMOMAXUEI64_V, MASK_VAMOMAXUEI64_V) +DECLARE_INSN(vamomaxuei8_v, MATCH_VAMOMAXUEI8_V, MASK_VAMOMAXUEI8_V) +DECLARE_INSN(vamominei16_v, MATCH_VAMOMINEI16_V, MASK_VAMOMINEI16_V) +DECLARE_INSN(vamominei32_v, MATCH_VAMOMINEI32_V, MASK_VAMOMINEI32_V) +DECLARE_INSN(vamominei64_v, MATCH_VAMOMINEI64_V, MASK_VAMOMINEI64_V) +DECLARE_INSN(vamominei8_v, MATCH_VAMOMINEI8_V, MASK_VAMOMINEI8_V) +DECLARE_INSN(vamominuei16_v, MATCH_VAMOMINUEI16_V, MASK_VAMOMINUEI16_V) +DECLARE_INSN(vamominuei32_v, MATCH_VAMOMINUEI32_V, MASK_VAMOMINUEI32_V) +DECLARE_INSN(vamominuei64_v, MATCH_VAMOMINUEI64_V, MASK_VAMOMINUEI64_V) +DECLARE_INSN(vamominuei8_v, MATCH_VAMOMINUEI8_V, MASK_VAMOMINUEI8_V) +DECLARE_INSN(vamoorei16_v, MATCH_VAMOOREI16_V, MASK_VAMOOREI16_V) +DECLARE_INSN(vamoorei32_v, MATCH_VAMOOREI32_V, MASK_VAMOOREI32_V) +DECLARE_INSN(vamoorei64_v, MATCH_VAMOOREI64_V, MASK_VAMOOREI64_V) +DECLARE_INSN(vamoorei8_v, MATCH_VAMOOREI8_V, MASK_VAMOOREI8_V) +DECLARE_INSN(vamoswapei16_v, MATCH_VAMOSWAPEI16_V, MASK_VAMOSWAPEI16_V) +DECLARE_INSN(vamoswapei32_v, MATCH_VAMOSWAPEI32_V, MASK_VAMOSWAPEI32_V) +DECLARE_INSN(vamoswapei64_v, MATCH_VAMOSWAPEI64_V, MASK_VAMOSWAPEI64_V) +DECLARE_INSN(vamoswapei8_v, MATCH_VAMOSWAPEI8_V, MASK_VAMOSWAPEI8_V) +DECLARE_INSN(vamoxorei16_v, MATCH_VAMOXOREI16_V, MASK_VAMOXOREI16_V) +DECLARE_INSN(vamoxorei32_v, MATCH_VAMOXOREI32_V, MASK_VAMOXOREI32_V) +DECLARE_INSN(vamoxorei64_v, MATCH_VAMOXOREI64_V, MASK_VAMOXOREI64_V) +DECLARE_INSN(vamoxorei8_v, MATCH_VAMOXOREI8_V, MASK_VAMOXOREI8_V) +DECLARE_INSN(vand_vi, MATCH_VAND_VI, MASK_VAND_VI) +DECLARE_INSN(vand_vv, MATCH_VAND_VV, MASK_VAND_VV) +DECLARE_INSN(vand_vx, MATCH_VAND_VX, MASK_VAND_VX) +DECLARE_INSN(vasub_vv, MATCH_VASUB_VV, MASK_VASUB_VV) +DECLARE_INSN(vasub_vx, MATCH_VASUB_VX, MASK_VASUB_VX) +DECLARE_INSN(vasubu_vv, MATCH_VASUBU_VV, MASK_VASUBU_VV) +DECLARE_INSN(vasubu_vx, MATCH_VASUBU_VX, MASK_VASUBU_VX) +DECLARE_INSN(vcompress_vm, MATCH_VCOMPRESS_VM, MASK_VCOMPRESS_VM) +DECLARE_INSN(vcpop_m, MATCH_VCPOP_M, MASK_VCPOP_M) +DECLARE_INSN(vdiv_vv, MATCH_VDIV_VV, MASK_VDIV_VV) +DECLARE_INSN(vdiv_vx, MATCH_VDIV_VX, MASK_VDIV_VX) +DECLARE_INSN(vdivu_vv, MATCH_VDIVU_VV, MASK_VDIVU_VV) +DECLARE_INSN(vdivu_vx, MATCH_VDIVU_VX, MASK_VDIVU_VX) +DECLARE_INSN(vfadd_vf, MATCH_VFADD_VF, MASK_VFADD_VF) +DECLARE_INSN(vfadd_vv, MATCH_VFADD_VV, MASK_VFADD_VV) +DECLARE_INSN(vfclass_v, MATCH_VFCLASS_V, MASK_VFCLASS_V) +DECLARE_INSN(vfcvt_f_x_v, MATCH_VFCVT_F_X_V, MASK_VFCVT_F_X_V) +DECLARE_INSN(vfcvt_f_xu_v, MATCH_VFCVT_F_XU_V, MASK_VFCVT_F_XU_V) +DECLARE_INSN(vfcvt_rtz_x_f_v, MATCH_VFCVT_RTZ_X_F_V, MASK_VFCVT_RTZ_X_F_V) +DECLARE_INSN(vfcvt_rtz_xu_f_v, MATCH_VFCVT_RTZ_XU_F_V, MASK_VFCVT_RTZ_XU_F_V) +DECLARE_INSN(vfcvt_x_f_v, MATCH_VFCVT_X_F_V, MASK_VFCVT_X_F_V) +DECLARE_INSN(vfcvt_xu_f_v, MATCH_VFCVT_XU_F_V, MASK_VFCVT_XU_F_V) +DECLARE_INSN(vfdiv_vf, MATCH_VFDIV_VF, MASK_VFDIV_VF) +DECLARE_INSN(vfdiv_vv, MATCH_VFDIV_VV, MASK_VFDIV_VV) +DECLARE_INSN(vfirst_m, MATCH_VFIRST_M, MASK_VFIRST_M) +DECLARE_INSN(vfmacc_vf, MATCH_VFMACC_VF, MASK_VFMACC_VF) +DECLARE_INSN(vfmacc_vv, MATCH_VFMACC_VV, MASK_VFMACC_VV) +DECLARE_INSN(vfmadd_vf, MATCH_VFMADD_VF, MASK_VFMADD_VF) +DECLARE_INSN(vfmadd_vv, MATCH_VFMADD_VV, MASK_VFMADD_VV) +DECLARE_INSN(vfmax_vf, MATCH_VFMAX_VF, MASK_VFMAX_VF) +DECLARE_INSN(vfmax_vv, MATCH_VFMAX_VV, MASK_VFMAX_VV) +DECLARE_INSN(vfmerge_vfm, MATCH_VFMERGE_VFM, MASK_VFMERGE_VFM) +DECLARE_INSN(vfmin_vf, MATCH_VFMIN_VF, MASK_VFMIN_VF) +DECLARE_INSN(vfmin_vv, MATCH_VFMIN_VV, MASK_VFMIN_VV) +DECLARE_INSN(vfmsac_vf, MATCH_VFMSAC_VF, MASK_VFMSAC_VF) +DECLARE_INSN(vfmsac_vv, MATCH_VFMSAC_VV, MASK_VFMSAC_VV) +DECLARE_INSN(vfmsub_vf, MATCH_VFMSUB_VF, MASK_VFMSUB_VF) +DECLARE_INSN(vfmsub_vv, MATCH_VFMSUB_VV, MASK_VFMSUB_VV) +DECLARE_INSN(vfmul_vf, MATCH_VFMUL_VF, MASK_VFMUL_VF) +DECLARE_INSN(vfmul_vv, MATCH_VFMUL_VV, MASK_VFMUL_VV) +DECLARE_INSN(vfmv_f_s, MATCH_VFMV_F_S, MASK_VFMV_F_S) +DECLARE_INSN(vfmv_s_f, MATCH_VFMV_S_F, MASK_VFMV_S_F) +DECLARE_INSN(vfmv_v_f, MATCH_VFMV_V_F, MASK_VFMV_V_F) +DECLARE_INSN(vfncvt_f_f_w, MATCH_VFNCVT_F_F_W, MASK_VFNCVT_F_F_W) +DECLARE_INSN(vfncvt_f_x_w, MATCH_VFNCVT_F_X_W, MASK_VFNCVT_F_X_W) +DECLARE_INSN(vfncvt_f_xu_w, MATCH_VFNCVT_F_XU_W, MASK_VFNCVT_F_XU_W) +DECLARE_INSN(vfncvt_rod_f_f_w, MATCH_VFNCVT_ROD_F_F_W, MASK_VFNCVT_ROD_F_F_W) +DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) +DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) +DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) +DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) +DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) +DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) +DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) +DECLARE_INSN(vfnmadd_vv, MATCH_VFNMADD_VV, MASK_VFNMADD_VV) +DECLARE_INSN(vfnmsac_vf, MATCH_VFNMSAC_VF, MASK_VFNMSAC_VF) +DECLARE_INSN(vfnmsac_vv, MATCH_VFNMSAC_VV, MASK_VFNMSAC_VV) +DECLARE_INSN(vfnmsub_vf, MATCH_VFNMSUB_VF, MASK_VFNMSUB_VF) +DECLARE_INSN(vfnmsub_vv, MATCH_VFNMSUB_VV, MASK_VFNMSUB_VV) +DECLARE_INSN(vfrdiv_vf, MATCH_VFRDIV_VF, MASK_VFRDIV_VF) +DECLARE_INSN(vfrec7_v, MATCH_VFREC7_V, MASK_VFREC7_V) +DECLARE_INSN(vfredmax_vs, MATCH_VFREDMAX_VS, MASK_VFREDMAX_VS) +DECLARE_INSN(vfredmin_vs, MATCH_VFREDMIN_VS, MASK_VFREDMIN_VS) +DECLARE_INSN(vfredosum_vs, MATCH_VFREDOSUM_VS, MASK_VFREDOSUM_VS) +DECLARE_INSN(vfredusum_vs, MATCH_VFREDUSUM_VS, MASK_VFREDUSUM_VS) +DECLARE_INSN(vfrsqrt7_v, MATCH_VFRSQRT7_V, MASK_VFRSQRT7_V) +DECLARE_INSN(vfrsub_vf, MATCH_VFRSUB_VF, MASK_VFRSUB_VF) +DECLARE_INSN(vfsgnj_vf, MATCH_VFSGNJ_VF, MASK_VFSGNJ_VF) +DECLARE_INSN(vfsgnj_vv, MATCH_VFSGNJ_VV, MASK_VFSGNJ_VV) +DECLARE_INSN(vfsgnjn_vf, MATCH_VFSGNJN_VF, MASK_VFSGNJN_VF) +DECLARE_INSN(vfsgnjn_vv, MATCH_VFSGNJN_VV, MASK_VFSGNJN_VV) +DECLARE_INSN(vfsgnjx_vf, MATCH_VFSGNJX_VF, MASK_VFSGNJX_VF) +DECLARE_INSN(vfsgnjx_vv, MATCH_VFSGNJX_VV, MASK_VFSGNJX_VV) +DECLARE_INSN(vfslide1down_vf, MATCH_VFSLIDE1DOWN_VF, MASK_VFSLIDE1DOWN_VF) +DECLARE_INSN(vfslide1up_vf, MATCH_VFSLIDE1UP_VF, MASK_VFSLIDE1UP_VF) +DECLARE_INSN(vfsqrt_v, MATCH_VFSQRT_V, MASK_VFSQRT_V) +DECLARE_INSN(vfsub_vf, MATCH_VFSUB_VF, MASK_VFSUB_VF) +DECLARE_INSN(vfsub_vv, MATCH_VFSUB_VV, MASK_VFSUB_VV) +DECLARE_INSN(vfwadd_vf, MATCH_VFWADD_VF, MASK_VFWADD_VF) +DECLARE_INSN(vfwadd_vv, MATCH_VFWADD_VV, MASK_VFWADD_VV) +DECLARE_INSN(vfwadd_wf, MATCH_VFWADD_WF, MASK_VFWADD_WF) +DECLARE_INSN(vfwadd_wv, MATCH_VFWADD_WV, MASK_VFWADD_WV) +DECLARE_INSN(vfwcvt_f_f_v, MATCH_VFWCVT_F_F_V, MASK_VFWCVT_F_F_V) +DECLARE_INSN(vfwcvt_f_x_v, MATCH_VFWCVT_F_X_V, MASK_VFWCVT_F_X_V) +DECLARE_INSN(vfwcvt_f_xu_v, MATCH_VFWCVT_F_XU_V, MASK_VFWCVT_F_XU_V) +DECLARE_INSN(vfwcvt_rtz_x_f_v, MATCH_VFWCVT_RTZ_X_F_V, MASK_VFWCVT_RTZ_X_F_V) +DECLARE_INSN(vfwcvt_rtz_xu_f_v, MATCH_VFWCVT_RTZ_XU_F_V, MASK_VFWCVT_RTZ_XU_F_V) +DECLARE_INSN(vfwcvt_x_f_v, MATCH_VFWCVT_X_F_V, MASK_VFWCVT_X_F_V) +DECLARE_INSN(vfwcvt_xu_f_v, MATCH_VFWCVT_XU_F_V, MASK_VFWCVT_XU_F_V) +DECLARE_INSN(vfwmacc_vf, MATCH_VFWMACC_VF, MASK_VFWMACC_VF) +DECLARE_INSN(vfwmacc_vv, MATCH_VFWMACC_VV, MASK_VFWMACC_VV) +DECLARE_INSN(vfwmsac_vf, MATCH_VFWMSAC_VF, MASK_VFWMSAC_VF) +DECLARE_INSN(vfwmsac_vv, MATCH_VFWMSAC_VV, MASK_VFWMSAC_VV) +DECLARE_INSN(vfwmul_vf, MATCH_VFWMUL_VF, MASK_VFWMUL_VF) +DECLARE_INSN(vfwmul_vv, MATCH_VFWMUL_VV, MASK_VFWMUL_VV) +DECLARE_INSN(vfwnmacc_vf, MATCH_VFWNMACC_VF, MASK_VFWNMACC_VF) +DECLARE_INSN(vfwnmacc_vv, MATCH_VFWNMACC_VV, MASK_VFWNMACC_VV) +DECLARE_INSN(vfwnmsac_vf, MATCH_VFWNMSAC_VF, MASK_VFWNMSAC_VF) +DECLARE_INSN(vfwnmsac_vv, MATCH_VFWNMSAC_VV, MASK_VFWNMSAC_VV) +DECLARE_INSN(vfwredosum_vs, MATCH_VFWREDOSUM_VS, MASK_VFWREDOSUM_VS) +DECLARE_INSN(vfwredusum_vs, MATCH_VFWREDUSUM_VS, MASK_VFWREDUSUM_VS) +DECLARE_INSN(vfwsub_vf, MATCH_VFWSUB_VF, MASK_VFWSUB_VF) +DECLARE_INSN(vfwsub_vv, MATCH_VFWSUB_VV, MASK_VFWSUB_VV) +DECLARE_INSN(vfwsub_wf, MATCH_VFWSUB_WF, MASK_VFWSUB_WF) +DECLARE_INSN(vfwsub_wv, MATCH_VFWSUB_WV, MASK_VFWSUB_WV) +DECLARE_INSN(vid_v, MATCH_VID_V, MASK_VID_V) +DECLARE_INSN(viota_m, MATCH_VIOTA_M, MASK_VIOTA_M) +DECLARE_INSN(vl1re16_v, MATCH_VL1RE16_V, MASK_VL1RE16_V) +DECLARE_INSN(vl1re32_v, MATCH_VL1RE32_V, MASK_VL1RE32_V) +DECLARE_INSN(vl1re64_v, MATCH_VL1RE64_V, MASK_VL1RE64_V) +DECLARE_INSN(vl1re8_v, MATCH_VL1RE8_V, MASK_VL1RE8_V) +DECLARE_INSN(vl2re16_v, MATCH_VL2RE16_V, MASK_VL2RE16_V) +DECLARE_INSN(vl2re32_v, MATCH_VL2RE32_V, MASK_VL2RE32_V) +DECLARE_INSN(vl2re64_v, MATCH_VL2RE64_V, MASK_VL2RE64_V) +DECLARE_INSN(vl2re8_v, MATCH_VL2RE8_V, MASK_VL2RE8_V) +DECLARE_INSN(vl4re16_v, MATCH_VL4RE16_V, MASK_VL4RE16_V) +DECLARE_INSN(vl4re32_v, MATCH_VL4RE32_V, MASK_VL4RE32_V) +DECLARE_INSN(vl4re64_v, MATCH_VL4RE64_V, MASK_VL4RE64_V) +DECLARE_INSN(vl4re8_v, MATCH_VL4RE8_V, MASK_VL4RE8_V) +DECLARE_INSN(vl8re16_v, MATCH_VL8RE16_V, MASK_VL8RE16_V) +DECLARE_INSN(vl8re32_v, MATCH_VL8RE32_V, MASK_VL8RE32_V) +DECLARE_INSN(vl8re64_v, MATCH_VL8RE64_V, MASK_VL8RE64_V) +DECLARE_INSN(vl8re8_v, MATCH_VL8RE8_V, MASK_VL8RE8_V) +DECLARE_INSN(vle1024_v, MATCH_VLE1024_V, MASK_VLE1024_V) +DECLARE_INSN(vle1024ff_v, MATCH_VLE1024FF_V, MASK_VLE1024FF_V) +DECLARE_INSN(vle128_v, MATCH_VLE128_V, MASK_VLE128_V) +DECLARE_INSN(vle128ff_v, MATCH_VLE128FF_V, MASK_VLE128FF_V) +DECLARE_INSN(vle16_v, MATCH_VLE16_V, MASK_VLE16_V) +DECLARE_INSN(vle16ff_v, MATCH_VLE16FF_V, MASK_VLE16FF_V) +DECLARE_INSN(vle256_v, MATCH_VLE256_V, MASK_VLE256_V) +DECLARE_INSN(vle256ff_v, MATCH_VLE256FF_V, MASK_VLE256FF_V) +DECLARE_INSN(vle32_v, MATCH_VLE32_V, MASK_VLE32_V) +DECLARE_INSN(vle32ff_v, MATCH_VLE32FF_V, MASK_VLE32FF_V) +DECLARE_INSN(vle512_v, MATCH_VLE512_V, MASK_VLE512_V) +DECLARE_INSN(vle512ff_v, MATCH_VLE512FF_V, MASK_VLE512FF_V) +DECLARE_INSN(vle64_v, MATCH_VLE64_V, MASK_VLE64_V) +DECLARE_INSN(vle64ff_v, MATCH_VLE64FF_V, MASK_VLE64FF_V) +DECLARE_INSN(vle8_v, MATCH_VLE8_V, MASK_VLE8_V) +DECLARE_INSN(vle8ff_v, MATCH_VLE8FF_V, MASK_VLE8FF_V) +DECLARE_INSN(vlm_v, MATCH_VLM_V, MASK_VLM_V) +DECLARE_INSN(vloxei1024_v, MATCH_VLOXEI1024_V, MASK_VLOXEI1024_V) +DECLARE_INSN(vloxei128_v, MATCH_VLOXEI128_V, MASK_VLOXEI128_V) +DECLARE_INSN(vloxei16_v, MATCH_VLOXEI16_V, MASK_VLOXEI16_V) +DECLARE_INSN(vloxei256_v, MATCH_VLOXEI256_V, MASK_VLOXEI256_V) +DECLARE_INSN(vloxei32_v, MATCH_VLOXEI32_V, MASK_VLOXEI32_V) +DECLARE_INSN(vloxei512_v, MATCH_VLOXEI512_V, MASK_VLOXEI512_V) +DECLARE_INSN(vloxei64_v, MATCH_VLOXEI64_V, MASK_VLOXEI64_V) +DECLARE_INSN(vloxei8_v, MATCH_VLOXEI8_V, MASK_VLOXEI8_V) +DECLARE_INSN(vlse1024_v, MATCH_VLSE1024_V, MASK_VLSE1024_V) +DECLARE_INSN(vlse128_v, MATCH_VLSE128_V, MASK_VLSE128_V) +DECLARE_INSN(vlse16_v, MATCH_VLSE16_V, MASK_VLSE16_V) +DECLARE_INSN(vlse256_v, MATCH_VLSE256_V, MASK_VLSE256_V) +DECLARE_INSN(vlse32_v, MATCH_VLSE32_V, MASK_VLSE32_V) +DECLARE_INSN(vlse512_v, MATCH_VLSE512_V, MASK_VLSE512_V) +DECLARE_INSN(vlse64_v, MATCH_VLSE64_V, MASK_VLSE64_V) +DECLARE_INSN(vlse8_v, MATCH_VLSE8_V, MASK_VLSE8_V) +DECLARE_INSN(vluxei1024_v, MATCH_VLUXEI1024_V, MASK_VLUXEI1024_V) +DECLARE_INSN(vluxei128_v, MATCH_VLUXEI128_V, MASK_VLUXEI128_V) +DECLARE_INSN(vluxei16_v, MATCH_VLUXEI16_V, MASK_VLUXEI16_V) +DECLARE_INSN(vluxei256_v, MATCH_VLUXEI256_V, MASK_VLUXEI256_V) +DECLARE_INSN(vluxei32_v, MATCH_VLUXEI32_V, MASK_VLUXEI32_V) +DECLARE_INSN(vluxei512_v, MATCH_VLUXEI512_V, MASK_VLUXEI512_V) +DECLARE_INSN(vluxei64_v, MATCH_VLUXEI64_V, MASK_VLUXEI64_V) +DECLARE_INSN(vluxei8_v, MATCH_VLUXEI8_V, MASK_VLUXEI8_V) +DECLARE_INSN(vmacc_vv, MATCH_VMACC_VV, MASK_VMACC_VV) +DECLARE_INSN(vmacc_vx, MATCH_VMACC_VX, MASK_VMACC_VX) +DECLARE_INSN(vmadc_vi, MATCH_VMADC_VI, MASK_VMADC_VI) +DECLARE_INSN(vmadc_vim, MATCH_VMADC_VIM, MASK_VMADC_VIM) +DECLARE_INSN(vmadc_vv, MATCH_VMADC_VV, MASK_VMADC_VV) +DECLARE_INSN(vmadc_vvm, MATCH_VMADC_VVM, MASK_VMADC_VVM) +DECLARE_INSN(vmadc_vx, MATCH_VMADC_VX, MASK_VMADC_VX) +DECLARE_INSN(vmadc_vxm, MATCH_VMADC_VXM, MASK_VMADC_VXM) +DECLARE_INSN(vmadd_vv, MATCH_VMADD_VV, MASK_VMADD_VV) +DECLARE_INSN(vmadd_vx, MATCH_VMADD_VX, MASK_VMADD_VX) +DECLARE_INSN(vmand_mm, MATCH_VMAND_MM, MASK_VMAND_MM) +DECLARE_INSN(vmandn_mm, MATCH_VMANDN_MM, MASK_VMANDN_MM) +DECLARE_INSN(vmax_vv, MATCH_VMAX_VV, MASK_VMAX_VV) +DECLARE_INSN(vmax_vx, MATCH_VMAX_VX, MASK_VMAX_VX) +DECLARE_INSN(vmaxu_vv, MATCH_VMAXU_VV, MASK_VMAXU_VV) +DECLARE_INSN(vmaxu_vx, MATCH_VMAXU_VX, MASK_VMAXU_VX) +DECLARE_INSN(vmerge_vim, MATCH_VMERGE_VIM, MASK_VMERGE_VIM) +DECLARE_INSN(vmerge_vvm, MATCH_VMERGE_VVM, MASK_VMERGE_VVM) +DECLARE_INSN(vmerge_vxm, MATCH_VMERGE_VXM, MASK_VMERGE_VXM) +DECLARE_INSN(vmfeq_vf, MATCH_VMFEQ_VF, MASK_VMFEQ_VF) +DECLARE_INSN(vmfeq_vv, MATCH_VMFEQ_VV, MASK_VMFEQ_VV) +DECLARE_INSN(vmfge_vf, MATCH_VMFGE_VF, MASK_VMFGE_VF) +DECLARE_INSN(vmfgt_vf, MATCH_VMFGT_VF, MASK_VMFGT_VF) +DECLARE_INSN(vmfle_vf, MATCH_VMFLE_VF, MASK_VMFLE_VF) +DECLARE_INSN(vmfle_vv, MATCH_VMFLE_VV, MASK_VMFLE_VV) +DECLARE_INSN(vmflt_vf, MATCH_VMFLT_VF, MASK_VMFLT_VF) +DECLARE_INSN(vmflt_vv, MATCH_VMFLT_VV, MASK_VMFLT_VV) +DECLARE_INSN(vmfne_vf, MATCH_VMFNE_VF, MASK_VMFNE_VF) +DECLARE_INSN(vmfne_vv, MATCH_VMFNE_VV, MASK_VMFNE_VV) +DECLARE_INSN(vmin_vv, MATCH_VMIN_VV, MASK_VMIN_VV) +DECLARE_INSN(vmin_vx, MATCH_VMIN_VX, MASK_VMIN_VX) +DECLARE_INSN(vminu_vv, MATCH_VMINU_VV, MASK_VMINU_VV) +DECLARE_INSN(vminu_vx, MATCH_VMINU_VX, MASK_VMINU_VX) +DECLARE_INSN(vmnand_mm, MATCH_VMNAND_MM, MASK_VMNAND_MM) +DECLARE_INSN(vmnor_mm, MATCH_VMNOR_MM, MASK_VMNOR_MM) +DECLARE_INSN(vmor_mm, MATCH_VMOR_MM, MASK_VMOR_MM) +DECLARE_INSN(vmorn_mm, MATCH_VMORN_MM, MASK_VMORN_MM) +DECLARE_INSN(vmsbc_vv, MATCH_VMSBC_VV, MASK_VMSBC_VV) +DECLARE_INSN(vmsbc_vvm, MATCH_VMSBC_VVM, MASK_VMSBC_VVM) +DECLARE_INSN(vmsbc_vx, MATCH_VMSBC_VX, MASK_VMSBC_VX) +DECLARE_INSN(vmsbc_vxm, MATCH_VMSBC_VXM, MASK_VMSBC_VXM) +DECLARE_INSN(vmsbf_m, MATCH_VMSBF_M, MASK_VMSBF_M) +DECLARE_INSN(vmseq_vi, MATCH_VMSEQ_VI, MASK_VMSEQ_VI) +DECLARE_INSN(vmseq_vv, MATCH_VMSEQ_VV, MASK_VMSEQ_VV) +DECLARE_INSN(vmseq_vx, MATCH_VMSEQ_VX, MASK_VMSEQ_VX) +DECLARE_INSN(vmsgt_vi, MATCH_VMSGT_VI, MASK_VMSGT_VI) +DECLARE_INSN(vmsgt_vx, MATCH_VMSGT_VX, MASK_VMSGT_VX) +DECLARE_INSN(vmsgtu_vi, MATCH_VMSGTU_VI, MASK_VMSGTU_VI) +DECLARE_INSN(vmsgtu_vx, MATCH_VMSGTU_VX, MASK_VMSGTU_VX) +DECLARE_INSN(vmsif_m, MATCH_VMSIF_M, MASK_VMSIF_M) +DECLARE_INSN(vmsle_vi, MATCH_VMSLE_VI, MASK_VMSLE_VI) +DECLARE_INSN(vmsle_vv, MATCH_VMSLE_VV, MASK_VMSLE_VV) +DECLARE_INSN(vmsle_vx, MATCH_VMSLE_VX, MASK_VMSLE_VX) +DECLARE_INSN(vmsleu_vi, MATCH_VMSLEU_VI, MASK_VMSLEU_VI) +DECLARE_INSN(vmsleu_vv, MATCH_VMSLEU_VV, MASK_VMSLEU_VV) +DECLARE_INSN(vmsleu_vx, MATCH_VMSLEU_VX, MASK_VMSLEU_VX) +DECLARE_INSN(vmslt_vv, MATCH_VMSLT_VV, MASK_VMSLT_VV) +DECLARE_INSN(vmslt_vx, MATCH_VMSLT_VX, MASK_VMSLT_VX) +DECLARE_INSN(vmsltu_vv, MATCH_VMSLTU_VV, MASK_VMSLTU_VV) +DECLARE_INSN(vmsltu_vx, MATCH_VMSLTU_VX, MASK_VMSLTU_VX) +DECLARE_INSN(vmsne_vi, MATCH_VMSNE_VI, MASK_VMSNE_VI) +DECLARE_INSN(vmsne_vv, MATCH_VMSNE_VV, MASK_VMSNE_VV) +DECLARE_INSN(vmsne_vx, MATCH_VMSNE_VX, MASK_VMSNE_VX) +DECLARE_INSN(vmsof_m, MATCH_VMSOF_M, MASK_VMSOF_M) +DECLARE_INSN(vmul_vv, MATCH_VMUL_VV, MASK_VMUL_VV) +DECLARE_INSN(vmul_vx, MATCH_VMUL_VX, MASK_VMUL_VX) +DECLARE_INSN(vmulh_vv, MATCH_VMULH_VV, MASK_VMULH_VV) +DECLARE_INSN(vmulh_vx, MATCH_VMULH_VX, MASK_VMULH_VX) +DECLARE_INSN(vmulhsu_vv, MATCH_VMULHSU_VV, MASK_VMULHSU_VV) +DECLARE_INSN(vmulhsu_vx, MATCH_VMULHSU_VX, MASK_VMULHSU_VX) +DECLARE_INSN(vmulhu_vv, MATCH_VMULHU_VV, MASK_VMULHU_VV) +DECLARE_INSN(vmulhu_vx, MATCH_VMULHU_VX, MASK_VMULHU_VX) +DECLARE_INSN(vmv1r_v, MATCH_VMV1R_V, MASK_VMV1R_V) +DECLARE_INSN(vmv2r_v, MATCH_VMV2R_V, MASK_VMV2R_V) +DECLARE_INSN(vmv4r_v, MATCH_VMV4R_V, MASK_VMV4R_V) +DECLARE_INSN(vmv8r_v, MATCH_VMV8R_V, MASK_VMV8R_V) +DECLARE_INSN(vmv_s_x, MATCH_VMV_S_X, MASK_VMV_S_X) +DECLARE_INSN(vmv_v_i, MATCH_VMV_V_I, MASK_VMV_V_I) +DECLARE_INSN(vmv_v_v, MATCH_VMV_V_V, MASK_VMV_V_V) +DECLARE_INSN(vmv_v_x, MATCH_VMV_V_X, MASK_VMV_V_X) +DECLARE_INSN(vmv_x_s, MATCH_VMV_X_S, MASK_VMV_X_S) +DECLARE_INSN(vmxnor_mm, MATCH_VMXNOR_MM, MASK_VMXNOR_MM) +DECLARE_INSN(vmxor_mm, MATCH_VMXOR_MM, MASK_VMXOR_MM) +DECLARE_INSN(vnclip_wi, MATCH_VNCLIP_WI, MASK_VNCLIP_WI) +DECLARE_INSN(vnclip_wv, MATCH_VNCLIP_WV, MASK_VNCLIP_WV) +DECLARE_INSN(vnclip_wx, MATCH_VNCLIP_WX, MASK_VNCLIP_WX) +DECLARE_INSN(vnclipu_wi, MATCH_VNCLIPU_WI, MASK_VNCLIPU_WI) +DECLARE_INSN(vnclipu_wv, MATCH_VNCLIPU_WV, MASK_VNCLIPU_WV) +DECLARE_INSN(vnclipu_wx, MATCH_VNCLIPU_WX, MASK_VNCLIPU_WX) +DECLARE_INSN(vnmsac_vv, MATCH_VNMSAC_VV, MASK_VNMSAC_VV) +DECLARE_INSN(vnmsac_vx, MATCH_VNMSAC_VX, MASK_VNMSAC_VX) +DECLARE_INSN(vnmsub_vv, MATCH_VNMSUB_VV, MASK_VNMSUB_VV) +DECLARE_INSN(vnmsub_vx, MATCH_VNMSUB_VX, MASK_VNMSUB_VX) +DECLARE_INSN(vnsra_wi, MATCH_VNSRA_WI, MASK_VNSRA_WI) +DECLARE_INSN(vnsra_wv, MATCH_VNSRA_WV, MASK_VNSRA_WV) +DECLARE_INSN(vnsra_wx, MATCH_VNSRA_WX, MASK_VNSRA_WX) +DECLARE_INSN(vnsrl_wi, MATCH_VNSRL_WI, MASK_VNSRL_WI) +DECLARE_INSN(vnsrl_wv, MATCH_VNSRL_WV, MASK_VNSRL_WV) +DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) +DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) +DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) +DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) +DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) +DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) +DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) +DECLARE_INSN(vredmin_vs, MATCH_VREDMIN_VS, MASK_VREDMIN_VS) +DECLARE_INSN(vredminu_vs, MATCH_VREDMINU_VS, MASK_VREDMINU_VS) +DECLARE_INSN(vredor_vs, MATCH_VREDOR_VS, MASK_VREDOR_VS) +DECLARE_INSN(vredsum_vs, MATCH_VREDSUM_VS, MASK_VREDSUM_VS) +DECLARE_INSN(vredxor_vs, MATCH_VREDXOR_VS, MASK_VREDXOR_VS) +DECLARE_INSN(vrem_vv, MATCH_VREM_VV, MASK_VREM_VV) +DECLARE_INSN(vrem_vx, MATCH_VREM_VX, MASK_VREM_VX) +DECLARE_INSN(vremu_vv, MATCH_VREMU_VV, MASK_VREMU_VV) +DECLARE_INSN(vremu_vx, MATCH_VREMU_VX, MASK_VREMU_VX) +DECLARE_INSN(vrgather_vi, MATCH_VRGATHER_VI, MASK_VRGATHER_VI) +DECLARE_INSN(vrgather_vv, MATCH_VRGATHER_VV, MASK_VRGATHER_VV) +DECLARE_INSN(vrgather_vx, MATCH_VRGATHER_VX, MASK_VRGATHER_VX) +DECLARE_INSN(vrgatherei16_vv, MATCH_VRGATHEREI16_VV, MASK_VRGATHEREI16_VV) +DECLARE_INSN(vrsub_vi, MATCH_VRSUB_VI, MASK_VRSUB_VI) +DECLARE_INSN(vrsub_vx, MATCH_VRSUB_VX, MASK_VRSUB_VX) +DECLARE_INSN(vs1r_v, MATCH_VS1R_V, MASK_VS1R_V) +DECLARE_INSN(vs2r_v, MATCH_VS2R_V, MASK_VS2R_V) +DECLARE_INSN(vs4r_v, MATCH_VS4R_V, MASK_VS4R_V) +DECLARE_INSN(vs8r_v, MATCH_VS8R_V, MASK_VS8R_V) +DECLARE_INSN(vsadd_vi, MATCH_VSADD_VI, MASK_VSADD_VI) +DECLARE_INSN(vsadd_vv, MATCH_VSADD_VV, MASK_VSADD_VV) +DECLARE_INSN(vsadd_vx, MATCH_VSADD_VX, MASK_VSADD_VX) +DECLARE_INSN(vsaddu_vi, MATCH_VSADDU_VI, MASK_VSADDU_VI) +DECLARE_INSN(vsaddu_vv, MATCH_VSADDU_VV, MASK_VSADDU_VV) +DECLARE_INSN(vsaddu_vx, MATCH_VSADDU_VX, MASK_VSADDU_VX) +DECLARE_INSN(vsbc_vvm, MATCH_VSBC_VVM, MASK_VSBC_VVM) +DECLARE_INSN(vsbc_vxm, MATCH_VSBC_VXM, MASK_VSBC_VXM) +DECLARE_INSN(vse1024_v, MATCH_VSE1024_V, MASK_VSE1024_V) +DECLARE_INSN(vse128_v, MATCH_VSE128_V, MASK_VSE128_V) +DECLARE_INSN(vse16_v, MATCH_VSE16_V, MASK_VSE16_V) +DECLARE_INSN(vse256_v, MATCH_VSE256_V, MASK_VSE256_V) +DECLARE_INSN(vse32_v, MATCH_VSE32_V, MASK_VSE32_V) +DECLARE_INSN(vse512_v, MATCH_VSE512_V, MASK_VSE512_V) +DECLARE_INSN(vse64_v, MATCH_VSE64_V, MASK_VSE64_V) +DECLARE_INSN(vse8_v, MATCH_VSE8_V, MASK_VSE8_V) +DECLARE_INSN(vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI) +DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL) +DECLARE_INSN(vsetvli, MATCH_VSETVLI, MASK_VSETVLI) +DECLARE_INSN(vsext_vf2, MATCH_VSEXT_VF2, MASK_VSEXT_VF2) +DECLARE_INSN(vsext_vf4, MATCH_VSEXT_VF4, MASK_VSEXT_VF4) +DECLARE_INSN(vsext_vf8, MATCH_VSEXT_VF8, MASK_VSEXT_VF8) +DECLARE_INSN(vslide1down_vx, MATCH_VSLIDE1DOWN_VX, MASK_VSLIDE1DOWN_VX) +DECLARE_INSN(vslide1up_vx, MATCH_VSLIDE1UP_VX, MASK_VSLIDE1UP_VX) +DECLARE_INSN(vslidedown_vi, MATCH_VSLIDEDOWN_VI, MASK_VSLIDEDOWN_VI) +DECLARE_INSN(vslidedown_vx, MATCH_VSLIDEDOWN_VX, MASK_VSLIDEDOWN_VX) +DECLARE_INSN(vslideup_vi, MATCH_VSLIDEUP_VI, MASK_VSLIDEUP_VI) +DECLARE_INSN(vslideup_vx, MATCH_VSLIDEUP_VX, MASK_VSLIDEUP_VX) +DECLARE_INSN(vsll_vi, MATCH_VSLL_VI, MASK_VSLL_VI) +DECLARE_INSN(vsll_vv, MATCH_VSLL_VV, MASK_VSLL_VV) +DECLARE_INSN(vsll_vx, MATCH_VSLL_VX, MASK_VSLL_VX) +DECLARE_INSN(vsm_v, MATCH_VSM_V, MASK_VSM_V) +DECLARE_INSN(vsmul_vv, MATCH_VSMUL_VV, MASK_VSMUL_VV) +DECLARE_INSN(vsmul_vx, MATCH_VSMUL_VX, MASK_VSMUL_VX) +DECLARE_INSN(vsoxei1024_v, MATCH_VSOXEI1024_V, MASK_VSOXEI1024_V) +DECLARE_INSN(vsoxei128_v, MATCH_VSOXEI128_V, MASK_VSOXEI128_V) +DECLARE_INSN(vsoxei16_v, MATCH_VSOXEI16_V, MASK_VSOXEI16_V) +DECLARE_INSN(vsoxei256_v, MATCH_VSOXEI256_V, MASK_VSOXEI256_V) +DECLARE_INSN(vsoxei32_v, MATCH_VSOXEI32_V, MASK_VSOXEI32_V) +DECLARE_INSN(vsoxei512_v, MATCH_VSOXEI512_V, MASK_VSOXEI512_V) +DECLARE_INSN(vsoxei64_v, MATCH_VSOXEI64_V, MASK_VSOXEI64_V) +DECLARE_INSN(vsoxei8_v, MATCH_VSOXEI8_V, MASK_VSOXEI8_V) +DECLARE_INSN(vsra_vi, MATCH_VSRA_VI, MASK_VSRA_VI) +DECLARE_INSN(vsra_vv, MATCH_VSRA_VV, MASK_VSRA_VV) +DECLARE_INSN(vsra_vx, MATCH_VSRA_VX, MASK_VSRA_VX) +DECLARE_INSN(vsrl_vi, MATCH_VSRL_VI, MASK_VSRL_VI) +DECLARE_INSN(vsrl_vv, MATCH_VSRL_VV, MASK_VSRL_VV) +DECLARE_INSN(vsrl_vx, MATCH_VSRL_VX, MASK_VSRL_VX) +DECLARE_INSN(vsse1024_v, MATCH_VSSE1024_V, MASK_VSSE1024_V) +DECLARE_INSN(vsse128_v, MATCH_VSSE128_V, MASK_VSSE128_V) +DECLARE_INSN(vsse16_v, MATCH_VSSE16_V, MASK_VSSE16_V) +DECLARE_INSN(vsse256_v, MATCH_VSSE256_V, MASK_VSSE256_V) +DECLARE_INSN(vsse32_v, MATCH_VSSE32_V, MASK_VSSE32_V) +DECLARE_INSN(vsse512_v, MATCH_VSSE512_V, MASK_VSSE512_V) +DECLARE_INSN(vsse64_v, MATCH_VSSE64_V, MASK_VSSE64_V) +DECLARE_INSN(vsse8_v, MATCH_VSSE8_V, MASK_VSSE8_V) +DECLARE_INSN(vssra_vi, MATCH_VSSRA_VI, MASK_VSSRA_VI) +DECLARE_INSN(vssra_vv, MATCH_VSSRA_VV, MASK_VSSRA_VV) +DECLARE_INSN(vssra_vx, MATCH_VSSRA_VX, MASK_VSSRA_VX) +DECLARE_INSN(vssrl_vi, MATCH_VSSRL_VI, MASK_VSSRL_VI) +DECLARE_INSN(vssrl_vv, MATCH_VSSRL_VV, MASK_VSSRL_VV) +DECLARE_INSN(vssrl_vx, MATCH_VSSRL_VX, MASK_VSSRL_VX) +DECLARE_INSN(vssub_vv, MATCH_VSSUB_VV, MASK_VSSUB_VV) +DECLARE_INSN(vssub_vx, MATCH_VSSUB_VX, MASK_VSSUB_VX) +DECLARE_INSN(vssubu_vv, MATCH_VSSUBU_VV, MASK_VSSUBU_VV) +DECLARE_INSN(vssubu_vx, MATCH_VSSUBU_VX, MASK_VSSUBU_VX) +DECLARE_INSN(vsub_vv, MATCH_VSUB_VV, MASK_VSUB_VV) +DECLARE_INSN(vsub_vx, MATCH_VSUB_VX, MASK_VSUB_VX) +DECLARE_INSN(vsuxei1024_v, MATCH_VSUXEI1024_V, MASK_VSUXEI1024_V) +DECLARE_INSN(vsuxei128_v, MATCH_VSUXEI128_V, MASK_VSUXEI128_V) +DECLARE_INSN(vsuxei16_v, MATCH_VSUXEI16_V, MASK_VSUXEI16_V) +DECLARE_INSN(vsuxei256_v, MATCH_VSUXEI256_V, MASK_VSUXEI256_V) +DECLARE_INSN(vsuxei32_v, MATCH_VSUXEI32_V, MASK_VSUXEI32_V) +DECLARE_INSN(vsuxei512_v, MATCH_VSUXEI512_V, MASK_VSUXEI512_V) +DECLARE_INSN(vsuxei64_v, MATCH_VSUXEI64_V, MASK_VSUXEI64_V) +DECLARE_INSN(vsuxei8_v, MATCH_VSUXEI8_V, MASK_VSUXEI8_V) +DECLARE_INSN(vwadd_vv, MATCH_VWADD_VV, MASK_VWADD_VV) +DECLARE_INSN(vwadd_vx, MATCH_VWADD_VX, MASK_VWADD_VX) +DECLARE_INSN(vwadd_wv, MATCH_VWADD_WV, MASK_VWADD_WV) +DECLARE_INSN(vwadd_wx, MATCH_VWADD_WX, MASK_VWADD_WX) +DECLARE_INSN(vwaddu_vv, MATCH_VWADDU_VV, MASK_VWADDU_VV) +DECLARE_INSN(vwaddu_vx, MATCH_VWADDU_VX, MASK_VWADDU_VX) +DECLARE_INSN(vwaddu_wv, MATCH_VWADDU_WV, MASK_VWADDU_WV) +DECLARE_INSN(vwaddu_wx, MATCH_VWADDU_WX, MASK_VWADDU_WX) +DECLARE_INSN(vwmacc_vv, MATCH_VWMACC_VV, MASK_VWMACC_VV) +DECLARE_INSN(vwmacc_vx, MATCH_VWMACC_VX, MASK_VWMACC_VX) +DECLARE_INSN(vwmaccsu_vv, MATCH_VWMACCSU_VV, MASK_VWMACCSU_VV) +DECLARE_INSN(vwmaccsu_vx, MATCH_VWMACCSU_VX, MASK_VWMACCSU_VX) +DECLARE_INSN(vwmaccu_vv, MATCH_VWMACCU_VV, MASK_VWMACCU_VV) +DECLARE_INSN(vwmaccu_vx, MATCH_VWMACCU_VX, MASK_VWMACCU_VX) +DECLARE_INSN(vwmaccus_vx, MATCH_VWMACCUS_VX, MASK_VWMACCUS_VX) +DECLARE_INSN(vwmul_vv, MATCH_VWMUL_VV, MASK_VWMUL_VV) +DECLARE_INSN(vwmul_vx, MATCH_VWMUL_VX, MASK_VWMUL_VX) +DECLARE_INSN(vwmulsu_vv, MATCH_VWMULSU_VV, MASK_VWMULSU_VV) +DECLARE_INSN(vwmulsu_vx, MATCH_VWMULSU_VX, MASK_VWMULSU_VX) +DECLARE_INSN(vwmulu_vv, MATCH_VWMULU_VV, MASK_VWMULU_VV) +DECLARE_INSN(vwmulu_vx, MATCH_VWMULU_VX, MASK_VWMULU_VX) +DECLARE_INSN(vwredsum_vs, MATCH_VWREDSUM_VS, MASK_VWREDSUM_VS) +DECLARE_INSN(vwredsumu_vs, MATCH_VWREDSUMU_VS, MASK_VWREDSUMU_VS) +DECLARE_INSN(vwsub_vv, MATCH_VWSUB_VV, MASK_VWSUB_VV) +DECLARE_INSN(vwsub_vx, MATCH_VWSUB_VX, MASK_VWSUB_VX) +DECLARE_INSN(vwsub_wv, MATCH_VWSUB_WV, MASK_VWSUB_WV) +DECLARE_INSN(vwsub_wx, MATCH_VWSUB_WX, MASK_VWSUB_WX) +DECLARE_INSN(vwsubu_vv, MATCH_VWSUBU_VV, MASK_VWSUBU_VV) +DECLARE_INSN(vwsubu_vx, MATCH_VWSUBU_VX, MASK_VWSUBU_VX) +DECLARE_INSN(vwsubu_wv, MATCH_VWSUBU_WV, MASK_VWSUBU_WV) +DECLARE_INSN(vwsubu_wx, MATCH_VWSUBU_WX, MASK_VWSUBU_WX) +DECLARE_INSN(vxor_vi, MATCH_VXOR_VI, MASK_VXOR_VI) +DECLARE_INSN(vxor_vv, MATCH_VXOR_VV, MASK_VXOR_VV) +DECLARE_INSN(vxor_vx, MATCH_VXOR_VX, MASK_VXOR_VX) +DECLARE_INSN(vzext_vf2, MATCH_VZEXT_VF2, MASK_VZEXT_VF2) +DECLARE_INSN(vzext_vf4, MATCH_VZEXT_VF4, MASK_VZEXT_VF4) +DECLARE_INSN(vzext_vf8, MATCH_VZEXT_VF8, MASK_VZEXT_VF8) DECLARE_INSN(wext, MATCH_WEXT, MASK_WEXT) +DECLARE_INSN(wexti, MATCH_WEXTI, MASK_WEXTI) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(wrs_nto, MATCH_WRS_NTO, MASK_WRS_NTO) +DECLARE_INSN(wrs_sto, MATCH_WRS_STO, MASK_WRS_STO) +DECLARE_INSN(xnor, MATCH_XNOR, MASK_XNOR) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(xperm16, MATCH_XPERM16, MASK_XPERM16) +DECLARE_INSN(xperm32, MATCH_XPERM32, MASK_XPERM32) +DECLARE_INSN(xperm4, MATCH_XPERM4, MASK_XPERM4) +DECLARE_INSN(xperm8, MATCH_XPERM8, MASK_XPERM8) DECLARE_INSN(zunpkd810, MATCH_ZUNPKD810, MASK_ZUNPKD810) DECLARE_INSN(zunpkd820, MATCH_ZUNPKD820, MASK_ZUNPKD820) DECLARE_INSN(zunpkd830, MATCH_ZUNPKD830, MASK_ZUNPKD830) DECLARE_INSN(zunpkd831, MATCH_ZUNPKD831, MASK_ZUNPKD831) DECLARE_INSN(zunpkd832, MATCH_ZUNPKD832, MASK_ZUNPKD832) -DECLARE_INSN(add32, MATCH_ADD32, MASK_ADD32) -DECLARE_INSN(cras32, MATCH_CRAS32, MASK_CRAS32) -DECLARE_INSN(crsa32, MATCH_CRSA32, MASK_CRSA32) -DECLARE_INSN(kabs32, MATCH_KABS32, MASK_KABS32) -DECLARE_INSN(kadd32, MATCH_KADD32, MASK_KADD32) -DECLARE_INSN(kcras32, MATCH_KCRAS32, MASK_KCRAS32) -DECLARE_INSN(kcrsa32, MATCH_KCRSA32, MASK_KCRSA32) -DECLARE_INSN(kdmbb16, MATCH_KDMBB16, MASK_KDMBB16) -DECLARE_INSN(kdmbt16, MATCH_KDMBT16, MASK_KDMBT16) -DECLARE_INSN(kdmtt16, MATCH_KDMTT16, MASK_KDMTT16) -DECLARE_INSN(kdmabb16, MATCH_KDMABB16, MASK_KDMABB16) -DECLARE_INSN(kdmabt16, MATCH_KDMABT16, MASK_KDMABT16) -DECLARE_INSN(kdmatt16, MATCH_KDMATT16, MASK_KDMATT16) -DECLARE_INSN(khmbb16, MATCH_KHMBB16, MASK_KHMBB16) -DECLARE_INSN(khmbt16, MATCH_KHMBT16, MASK_KHMBT16) -DECLARE_INSN(khmtt16, MATCH_KHMTT16, MASK_KHMTT16) -DECLARE_INSN(kmabb32, MATCH_KMABB32, MASK_KMABB32) -DECLARE_INSN(kmabt32, MATCH_KMABT32, MASK_KMABT32) -DECLARE_INSN(kmatt32, MATCH_KMATT32, MASK_KMATT32) -DECLARE_INSN(kmaxda32, MATCH_KMAXDA32, MASK_KMAXDA32) -DECLARE_INSN(kmda32, MATCH_KMDA32, MASK_KMDA32) -DECLARE_INSN(kmxda32, MATCH_KMXDA32, MASK_KMXDA32) -DECLARE_INSN(kmads32, MATCH_KMADS32, MASK_KMADS32) -DECLARE_INSN(kmadrs32, MATCH_KMADRS32, MASK_KMADRS32) -DECLARE_INSN(kmaxds32, MATCH_KMAXDS32, MASK_KMAXDS32) -DECLARE_INSN(kmsda32, MATCH_KMSDA32, MASK_KMSDA32) -DECLARE_INSN(kmsxda32, MATCH_KMSXDA32, MASK_KMSXDA32) -DECLARE_INSN(ksll32, MATCH_KSLL32, MASK_KSLL32) -DECLARE_INSN(kslli32, MATCH_KSLLI32, MASK_KSLLI32) -DECLARE_INSN(kslra32, MATCH_KSLRA32, MASK_KSLRA32) -DECLARE_INSN(kslra32_u, MATCH_KSLRA32_U, MASK_KSLRA32_U) -DECLARE_INSN(kstas32, MATCH_KSTAS32, MASK_KSTAS32) -DECLARE_INSN(kstsa32, MATCH_KSTSA32, MASK_KSTSA32) -DECLARE_INSN(ksub32, MATCH_KSUB32, MASK_KSUB32) -DECLARE_INSN(pkbb32, MATCH_PKBB32, MASK_PKBB32) -DECLARE_INSN(pkbt32, MATCH_PKBT32, MASK_PKBT32) -DECLARE_INSN(pktt32, MATCH_PKTT32, MASK_PKTT32) -DECLARE_INSN(pktb32, MATCH_PKTB32, MASK_PKTB32) -DECLARE_INSN(radd32, MATCH_RADD32, MASK_RADD32) -DECLARE_INSN(rcras32, MATCH_RCRAS32, MASK_RCRAS32) -DECLARE_INSN(rcrsa32, MATCH_RCRSA32, MASK_RCRSA32) -DECLARE_INSN(rstas32, MATCH_RSTAS32, MASK_RSTAS32) -DECLARE_INSN(rstsa32, MATCH_RSTSA32, MASK_RSTSA32) -DECLARE_INSN(rsub32, MATCH_RSUB32, MASK_RSUB32) -DECLARE_INSN(sll32, MATCH_SLL32, MASK_SLL32) -DECLARE_INSN(slli32, MATCH_SLLI32, MASK_SLLI32) -DECLARE_INSN(smax32, MATCH_SMAX32, MASK_SMAX32) -DECLARE_INSN(smbt32, MATCH_SMBT32, MASK_SMBT32) -DECLARE_INSN(smtt32, MATCH_SMTT32, MASK_SMTT32) -DECLARE_INSN(smds32, MATCH_SMDS32, MASK_SMDS32) -DECLARE_INSN(smdrs32, MATCH_SMDRS32, MASK_SMDRS32) -DECLARE_INSN(smxds32, MATCH_SMXDS32, MASK_SMXDS32) -DECLARE_INSN(smin32, MATCH_SMIN32, MASK_SMIN32) -DECLARE_INSN(sra32, MATCH_SRA32, MASK_SRA32) -DECLARE_INSN(sra32_u, MATCH_SRA32_U, MASK_SRA32_U) -DECLARE_INSN(srai32, MATCH_SRAI32, MASK_SRAI32) -DECLARE_INSN(srai32_u, MATCH_SRAI32_U, MASK_SRAI32_U) -DECLARE_INSN(sraiw_u, MATCH_SRAIW_U, MASK_SRAIW_U) -DECLARE_INSN(srl32, MATCH_SRL32, MASK_SRL32) -DECLARE_INSN(srl32_u, MATCH_SRL32_U, MASK_SRL32_U) -DECLARE_INSN(srli32, MATCH_SRLI32, MASK_SRLI32) -DECLARE_INSN(srli32_u, MATCH_SRLI32_U, MASK_SRLI32_U) -DECLARE_INSN(stas32, MATCH_STAS32, MASK_STAS32) -DECLARE_INSN(stsa32, MATCH_STSA32, MASK_STSA32) -DECLARE_INSN(sub32, MATCH_SUB32, MASK_SUB32) -DECLARE_INSN(ukadd32, MATCH_UKADD32, MASK_UKADD32) -DECLARE_INSN(ukcras32, MATCH_UKCRAS32, MASK_UKCRAS32) -DECLARE_INSN(ukcrsa32, MATCH_UKCRSA32, MASK_UKCRSA32) -DECLARE_INSN(ukstas32, MATCH_UKSTAS32, MASK_UKSTAS32) -DECLARE_INSN(ukstsa32, MATCH_UKSTSA32, MASK_UKSTSA32) -DECLARE_INSN(uksub32, MATCH_UKSUB32, MASK_UKSUB32) -DECLARE_INSN(umax32, MATCH_UMAX32, MASK_UMAX32) -DECLARE_INSN(umin32, MATCH_UMIN32, MASK_UMIN32) -DECLARE_INSN(uradd32, MATCH_URADD32, MASK_URADD32) -DECLARE_INSN(urcras32, MATCH_URCRAS32, MASK_URCRAS32) -DECLARE_INSN(urcrsa32, MATCH_URCRSA32, MASK_URCRSA32) -DECLARE_INSN(urstas32, MATCH_URSTAS32, MASK_URSTAS32) -DECLARE_INSN(urstsa32, MATCH_URSTSA32, MASK_URSTSA32) -DECLARE_INSN(ursub32, MATCH_URSUB32, MASK_URSUB32) -DECLARE_INSN(vmvnfr_v, MATCH_VMVNFR_V, MASK_VMVNFR_V) -DECLARE_INSN(vl1r_v, MATCH_VL1R_V, MASK_VL1R_V) -DECLARE_INSN(vl2r_v, MATCH_VL2R_V, MASK_VL2R_V) -DECLARE_INSN(vl4r_v, MATCH_VL4R_V, MASK_VL4R_V) -DECLARE_INSN(vl8r_v, MATCH_VL8R_V, MASK_VL8R_V) -DECLARE_INSN(vle1_v, MATCH_VLE1_V, MASK_VLE1_V) -DECLARE_INSN(vse1_v, MATCH_VSE1_V, MASK_VSE1_V) -DECLARE_INSN(vfredsum_vs, MATCH_VFREDSUM_VS, MASK_VFREDSUM_VS) -DECLARE_INSN(vfwredsum_vs, MATCH_VFWREDSUM_VS, MASK_VFWREDSUM_VS) -DECLARE_INSN(vpopc_m, MATCH_VPOPC_M, MASK_VPOPC_M) #endif #ifdef DECLARE_CSR DECLARE_CSR(fflags, CSR_FFLAGS) @@ -4391,11 +4468,17 @@ DECLARE_CSR(sideleg, CSR_SIDELEG) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(senvcfg, CSR_SENVCFG) +DECLARE_CSR(sstateen0, CSR_SSTATEEN0) +DECLARE_CSR(sstateen1, CSR_SSTATEEN1) +DECLARE_CSR(sstateen2, CSR_SSTATEEN2) +DECLARE_CSR(sstateen3, CSR_SSTATEEN3) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(stimecmp, CSR_STIMECMP) DECLARE_CSR(satp, CSR_SATP) DECLARE_CSR(scontext, CSR_SCONTEXT) DECLARE_CSR(vsstatus, CSR_VSSTATUS) @@ -4406,6 +4489,7 @@ DECLARE_CSR(vsepc, CSR_VSEPC) DECLARE_CSR(vscause, CSR_VSCAUSE) DECLARE_CSR(vstval, CSR_VSTVAL) DECLARE_CSR(vsip, CSR_VSIP) +DECLARE_CSR(vstimecmp, CSR_VSTIMECMP) DECLARE_CSR(vsatp, CSR_VSATP) DECLARE_CSR(hstatus, CSR_HSTATUS) DECLARE_CSR(hedeleg, CSR_HEDELEG) @@ -4414,6 +4498,11 @@ DECLARE_CSR(hie, CSR_HIE) DECLARE_CSR(htimedelta, CSR_HTIMEDELTA) DECLARE_CSR(hcounteren, CSR_HCOUNTEREN) DECLARE_CSR(hgeie, CSR_HGEIE) +DECLARE_CSR(henvcfg, CSR_HENVCFG) +DECLARE_CSR(hstateen0, CSR_HSTATEEN0) +DECLARE_CSR(hstateen1, CSR_HSTATEEN1) +DECLARE_CSR(hstateen2, CSR_HSTATEEN2) +DECLARE_CSR(hstateen3, CSR_HSTATEEN3) DECLARE_CSR(htval, CSR_HTVAL) DECLARE_CSR(hip, CSR_HIP) DECLARE_CSR(hvip, CSR_HVIP) @@ -4421,6 +4510,7 @@ DECLARE_CSR(htinst, CSR_HTINST) DECLARE_CSR(hgatp, CSR_HGATP) DECLARE_CSR(hcontext, CSR_HCONTEXT) DECLARE_CSR(hgeip, CSR_HGEIP) +DECLARE_CSR(scountovf, CSR_SCOUNTOVF) DECLARE_CSR(utvt, CSR_UTVT) DECLARE_CSR(unxti, CSR_UNXTI) DECLARE_CSR(uintstatus, CSR_UINTSTATUS) @@ -4443,6 +4533,11 @@ DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(menvcfg, CSR_MENVCFG) +DECLARE_CSR(mstateen0, CSR_MSTATEEN0) +DECLARE_CSR(mstateen1, CSR_MSTATEEN1) +DECLARE_CSR(mstateen2, CSR_MSTATEEN2) +DECLARE_CSR(mstateen3, CSR_MSTATEEN3) DECLARE_CSR(mcountinhibit, CSR_MCOUNTINHIBIT) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) @@ -4455,6 +4550,18 @@ DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpcfg4, CSR_PMPCFG4) +DECLARE_CSR(pmpcfg5, CSR_PMPCFG5) +DECLARE_CSR(pmpcfg6, CSR_PMPCFG6) +DECLARE_CSR(pmpcfg7, CSR_PMPCFG7) +DECLARE_CSR(pmpcfg8, CSR_PMPCFG8) +DECLARE_CSR(pmpcfg9, CSR_PMPCFG9) +DECLARE_CSR(pmpcfg10, CSR_PMPCFG10) +DECLARE_CSR(pmpcfg11, CSR_PMPCFG11) +DECLARE_CSR(pmpcfg12, CSR_PMPCFG12) +DECLARE_CSR(pmpcfg13, CSR_PMPCFG13) +DECLARE_CSR(pmpcfg14, CSR_PMPCFG14) +DECLARE_CSR(pmpcfg15, CSR_PMPCFG15) DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) @@ -4471,6 +4578,55 @@ DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(pmpaddr16, CSR_PMPADDR16) +DECLARE_CSR(pmpaddr17, CSR_PMPADDR17) +DECLARE_CSR(pmpaddr18, CSR_PMPADDR18) +DECLARE_CSR(pmpaddr19, CSR_PMPADDR19) +DECLARE_CSR(pmpaddr20, CSR_PMPADDR20) +DECLARE_CSR(pmpaddr21, CSR_PMPADDR21) +DECLARE_CSR(pmpaddr22, CSR_PMPADDR22) +DECLARE_CSR(pmpaddr23, CSR_PMPADDR23) +DECLARE_CSR(pmpaddr24, CSR_PMPADDR24) +DECLARE_CSR(pmpaddr25, CSR_PMPADDR25) +DECLARE_CSR(pmpaddr26, CSR_PMPADDR26) +DECLARE_CSR(pmpaddr27, CSR_PMPADDR27) +DECLARE_CSR(pmpaddr28, CSR_PMPADDR28) +DECLARE_CSR(pmpaddr29, CSR_PMPADDR29) +DECLARE_CSR(pmpaddr30, CSR_PMPADDR30) +DECLARE_CSR(pmpaddr31, CSR_PMPADDR31) +DECLARE_CSR(pmpaddr32, CSR_PMPADDR32) +DECLARE_CSR(pmpaddr33, CSR_PMPADDR33) +DECLARE_CSR(pmpaddr34, CSR_PMPADDR34) +DECLARE_CSR(pmpaddr35, CSR_PMPADDR35) +DECLARE_CSR(pmpaddr36, CSR_PMPADDR36) +DECLARE_CSR(pmpaddr37, CSR_PMPADDR37) +DECLARE_CSR(pmpaddr38, CSR_PMPADDR38) +DECLARE_CSR(pmpaddr39, CSR_PMPADDR39) +DECLARE_CSR(pmpaddr40, CSR_PMPADDR40) +DECLARE_CSR(pmpaddr41, CSR_PMPADDR41) +DECLARE_CSR(pmpaddr42, CSR_PMPADDR42) +DECLARE_CSR(pmpaddr43, CSR_PMPADDR43) +DECLARE_CSR(pmpaddr44, CSR_PMPADDR44) +DECLARE_CSR(pmpaddr45, CSR_PMPADDR45) +DECLARE_CSR(pmpaddr46, CSR_PMPADDR46) +DECLARE_CSR(pmpaddr47, CSR_PMPADDR47) +DECLARE_CSR(pmpaddr48, CSR_PMPADDR48) +DECLARE_CSR(pmpaddr49, CSR_PMPADDR49) +DECLARE_CSR(pmpaddr50, CSR_PMPADDR50) +DECLARE_CSR(pmpaddr51, CSR_PMPADDR51) +DECLARE_CSR(pmpaddr52, CSR_PMPADDR52) +DECLARE_CSR(pmpaddr53, CSR_PMPADDR53) +DECLARE_CSR(pmpaddr54, CSR_PMPADDR54) +DECLARE_CSR(pmpaddr55, CSR_PMPADDR55) +DECLARE_CSR(pmpaddr56, CSR_PMPADDR56) +DECLARE_CSR(pmpaddr57, CSR_PMPADDR57) +DECLARE_CSR(pmpaddr58, CSR_PMPADDR58) +DECLARE_CSR(pmpaddr59, CSR_PMPADDR59) +DECLARE_CSR(pmpaddr60, CSR_PMPADDR60) +DECLARE_CSR(pmpaddr61, CSR_PMPADDR61) +DECLARE_CSR(pmpaddr62, CSR_PMPADDR62) +DECLARE_CSR(pmpaddr63, CSR_PMPADDR63) +DECLARE_CSR(mseccfg, CSR_MSECCFG) DECLARE_CSR(tselect, CSR_TSELECT) DECLARE_CSR(tdata1, CSR_TDATA1) DECLARE_CSR(tdata2, CSR_TDATA2) @@ -4547,7 +4703,15 @@ DECLARE_CSR(mvendorid, CSR_MVENDORID) DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(mconfigptr, CSR_MCONFIGPTR) +DECLARE_CSR(stimecmph, CSR_STIMECMPH) +DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) +DECLARE_CSR(henvcfgh, CSR_HENVCFGH) +DECLARE_CSR(hstateen0h, CSR_HSTATEEN0H) +DECLARE_CSR(hstateen1h, CSR_HSTATEEN1H) +DECLARE_CSR(hstateen2h, CSR_HSTATEEN2H) +DECLARE_CSR(hstateen3h, CSR_HSTATEEN3H) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) DECLARE_CSR(instreth, CSR_INSTRETH) @@ -4581,6 +4745,41 @@ DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) DECLARE_CSR(mstatush, CSR_MSTATUSH) +DECLARE_CSR(menvcfgh, CSR_MENVCFGH) +DECLARE_CSR(mstateen0h, CSR_MSTATEEN0H) +DECLARE_CSR(mstateen1h, CSR_MSTATEEN1H) +DECLARE_CSR(mstateen2h, CSR_MSTATEEN2H) +DECLARE_CSR(mstateen3h, CSR_MSTATEEN3H) +DECLARE_CSR(mhpmevent3h, CSR_MHPMEVENT3H) +DECLARE_CSR(mhpmevent4h, CSR_MHPMEVENT4H) +DECLARE_CSR(mhpmevent5h, CSR_MHPMEVENT5H) +DECLARE_CSR(mhpmevent6h, CSR_MHPMEVENT6H) +DECLARE_CSR(mhpmevent7h, CSR_MHPMEVENT7H) +DECLARE_CSR(mhpmevent8h, CSR_MHPMEVENT8H) +DECLARE_CSR(mhpmevent9h, CSR_MHPMEVENT9H) +DECLARE_CSR(mhpmevent10h, CSR_MHPMEVENT10H) +DECLARE_CSR(mhpmevent11h, CSR_MHPMEVENT11H) +DECLARE_CSR(mhpmevent12h, CSR_MHPMEVENT12H) +DECLARE_CSR(mhpmevent13h, CSR_MHPMEVENT13H) +DECLARE_CSR(mhpmevent14h, CSR_MHPMEVENT14H) +DECLARE_CSR(mhpmevent15h, CSR_MHPMEVENT15H) +DECLARE_CSR(mhpmevent16h, CSR_MHPMEVENT16H) +DECLARE_CSR(mhpmevent17h, CSR_MHPMEVENT17H) +DECLARE_CSR(mhpmevent18h, CSR_MHPMEVENT18H) +DECLARE_CSR(mhpmevent19h, CSR_MHPMEVENT19H) +DECLARE_CSR(mhpmevent20h, CSR_MHPMEVENT20H) +DECLARE_CSR(mhpmevent21h, CSR_MHPMEVENT21H) +DECLARE_CSR(mhpmevent22h, CSR_MHPMEVENT22H) +DECLARE_CSR(mhpmevent23h, CSR_MHPMEVENT23H) +DECLARE_CSR(mhpmevent24h, CSR_MHPMEVENT24H) +DECLARE_CSR(mhpmevent25h, CSR_MHPMEVENT25H) +DECLARE_CSR(mhpmevent26h, CSR_MHPMEVENT26H) +DECLARE_CSR(mhpmevent27h, CSR_MHPMEVENT27H) +DECLARE_CSR(mhpmevent28h, CSR_MHPMEVENT28H) +DECLARE_CSR(mhpmevent29h, CSR_MHPMEVENT29H) +DECLARE_CSR(mhpmevent30h, CSR_MHPMEVENT30H) +DECLARE_CSR(mhpmevent31h, CSR_MHPMEVENT31H) +DECLARE_CSR(mseccfgh, CSR_MSECCFGH) DECLARE_CSR(mcycleh, CSR_MCYCLEH) DECLARE_CSR(minstreth, CSR_MINSTRETH) DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) From 969f112321361065e9f8671c4b04ea510e8d06e2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 18 Jul 2022 09:20:22 -0700 Subject: [PATCH 145/186] Update debug_defines.h. (#711) This one doesn't have the license in there, which means now it's acceptable to GPLv2 again. Change-Id: I8ba27801172ffa955470d2627fa656cad282ee99 Signed-off-by: Tim Newsome --- src/target/riscv/debug_defines.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 1c7459261..8113d4766 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -1,7 +1,6 @@ /* * This file is auto-generated by running 'make debug_defines.h' in - * https://github.com/riscv/riscv-debug-spec/ (182b9c4) - * License: Creative Commons Attribution 4.0 International Public License (CC BY 4.0) + * https://github.com/riscv/riscv-debug-spec/ (d749752) */ #define DTM_IDCODE 0x01 @@ -313,36 +312,35 @@ * * When there are multiple reasons to enter Debug Mode in a single * cycle, hardware should set \FcsrDcsrCause to the cause with the highest - * priority. + * priority. See table~\ref{tab:dcsrcausepriority} for priorities. */ #define CSR_DCSR_CAUSE_OFFSET 6 #define CSR_DCSR_CAUSE_LENGTH 3 #define CSR_DCSR_CAUSE 0x1c0 /* - * ebreak: An {\tt ebreak} instruction was executed. (priority 3) + * ebreak: An {\tt ebreak} instruction was executed. */ #define CSR_DCSR_CAUSE_EBREAK 1 /* - * trigger: A Trigger Module trigger fired with action=1. (priority 4) + * trigger: A Trigger Module trigger fired with action=1. */ #define CSR_DCSR_CAUSE_TRIGGER 2 /* * haltreq: The debugger requested entry to Debug Mode using \FdmDmcontrolHaltreq. - * (priority 1) */ #define CSR_DCSR_CAUSE_HALTREQ 3 /* - * step: The hart single stepped because \FcsrDcsrStep was set. (priority 0, lowest) + * step: The hart single stepped because \FcsrDcsrStep was set. */ #define CSR_DCSR_CAUSE_STEP 4 /* * resethaltreq: The hart halted directly out of reset due to \Fresethaltreq. It - * is also acceptable to report 3 when this happens. (priority 2) + * is also acceptable to report 3 when this happens. */ #define CSR_DCSR_CAUSE_RESETHALTREQ 5 /* - * group: The hart halted because it's part of a halt group. (priority 5, - * highest) Harts may report 3 for this cause instead. + * group: The hart halted because it's part of a halt group. + * Harts may report 3 for this cause instead. */ #define CSR_DCSR_CAUSE_GROUP 6 /* From 793def24c50d361695bc35f6fac3f9839ec3ac0f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 25 Jul 2022 15:54:49 -0700 Subject: [PATCH 146/186] Properly set dmcs2.grouptype. (#712) In #697 this had gotten inverted. Change-Id: Id86e2cfee0d15c1f05846c1fd5ac83dde26575a2 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index e1ee5ef43..fec994d28 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1505,7 +1505,7 @@ static int set_group(struct target *target, bool *supported, unsigned group, gro uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); write_val = set_field(write_val, DM_DMCS2_GROUP, group); - write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 1 : 0); + write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 0 : 1); if (dmi_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; uint32_t read_val; From 52177592f9d3afc6a008f8e1b321cf74e823018f Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov <109669442+en-sc@users.noreply.github.com> Date: Mon, 1 Aug 2022 18:46:36 +0300 Subject: [PATCH 147/186] Fix overflow issue in write_memory_progbuf (#714) If range's upper bound was equal to 2^64 or the range was wrapping around 0 (which is perfectly legal), writes were not performed due to riscv_addr_t overflow. --- src/target/riscv/riscv-013.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index fec994d28..32b9cf7ff 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -3834,10 +3834,10 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, riscv_program_write(&program); riscv_addr_t cur_addr = address; - riscv_addr_t fin_addr = address + (count * size); + riscv_addr_t distance = (riscv_addr_t)count * size; bool setup_needed = true; - LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); - while (cur_addr < fin_addr) { + LOG_DEBUG("writing until final address 0x%016" PRIx64, cur_addr + distance); + while (cur_addr - address < distance) { LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, cur_addr); @@ -3849,14 +3849,12 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, goto error; /* To write another word, we put it in S1 and execute the program. */ - unsigned start = (cur_addr - address) / size; - for (unsigned i = start; i < count; ++i) { - unsigned offset = size*i; + for (riscv_addr_t offset = cur_addr - address; offset < distance; offset += size) { const uint8_t *t_buffer = buffer + offset; uint64_t value = buf_get_u64(t_buffer, 0, 8 * size); - log_memory_access(address + offset, value, size, false); + log_memory_access(cur_addr, value, size, false); cur_addr += size; if (setup_needed) { From fb523552d2244e948c4a87599cb13171c1bf631a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 18 Aug 2022 10:10:49 -0700 Subject: [PATCH 148/186] Update encoding.h again. (#713) Now we get the license comment on the first line, which is required. Change-Id: I54414db3c89ee6027e159ce9348459bc923b8595 Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome --- src/target/riscv/encoding.h | 102 +++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index f7ad4622a..c046b8b2f 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,9 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* -* This file is auto-generated by running 'make' in -* https://github.com/riscv/riscv-opcodes (d2bbcb8) -*/ -/* SPDX-License-Identifier: BSD-3-Clause-Clear */ + * This file is auto-generated by running 'make' in + * https://github.com/riscv/riscv-opcodes (8ab2df7) + */ #ifndef RISCV_CSR_ENCODING_H #define RISCV_CSR_ENCODING_H @@ -139,6 +139,7 @@ #define MIP_VSEIP (1 << IRQ_VS_EXT) #define MIP_MEIP (1 << IRQ_M_EXT) #define MIP_SGEIP (1 << IRQ_S_GEXT) +#define MIP_LCOFIP (1 << IRQ_LCOF) #define MIP_S_MASK (MIP_SSIP | MIP_STIP | MIP_SEIP) #define MIP_VS_MASK (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) @@ -159,6 +160,30 @@ #define MENVCFGH_PBMTE 0x40000000 #define MENVCFGH_STCE 0x80000000 +#define MSTATEEN0_CS 0x00000001 +#define MSTATEEN0_FCSR 0x00000002 +#define MSTATEEN0_HCONTEXT 0x0200000000000000 +#define MSTATEEN0_HENVCFG 0x4000000000000000 +#define MSTATEEN_HSTATEEN 0x8000000000000000 + +#define MSTATEEN0H_HCONTEXT 0x02000000 +#define MSTATEEN0H_HENVCFG 0x40000000 +#define MSTATEENH_HSTATEEN 0x80000000 + +#define MHPMEVENT_VUINH 0x0400000000000000 +#define MHPMEVENT_VSINH 0x0800000000000000 +#define MHPMEVENT_UINH 0x1000000000000000 +#define MHPMEVENT_SINH 0x2000000000000000 +#define MHPMEVENT_MINH 0x4000000000000000 +#define MHPMEVENT_OF 0x8000000000000000 + +#define MHPMEVENTH_VUINH 0x04000000 +#define MHPMEVENTH_VSINH 0x08000000 +#define MHPMEVENTH_UINH 0x10000000 +#define MHPMEVENTH_SINH 0x20000000 +#define MHPMEVENTH_MINH 0x40000000 +#define MHPMEVENTH_OF 0x80000000 + #define HENVCFG_FIOM 0x00000001 #define HENVCFG_CBIE 0x00000030 #define HENVCFG_CBCFE 0x00000040 @@ -169,11 +194,24 @@ #define HENVCFGH_PBMTE 0x40000000 #define HENVCFGH_STCE 0x80000000 +#define HSTATEEN0_CS 0x00000001 +#define HSTATEEN0_FCSR 0x00000002 +#define HSTATEEN0_SCONTEXT 0x0200000000000000 +#define HSTATEEN0_SENVCFG 0x4000000000000000 +#define HSTATEEN_SSTATEEN 0x8000000000000000 + +#define HSTATEEN0H_SCONTEXT 0x02000000 +#define HSTATEEN0H_SENVCFG 0x40000000 +#define HSTATEENH_SSTATEEN 0x80000000 + #define SENVCFG_FIOM 0x00000001 #define SENVCFG_CBIE 0x00000030 #define SENVCFG_CBCFE 0x00000040 #define SENVCFG_CBZE 0x00000080 +#define SSTATEEN0_CS 0x00000001 +#define SSTATEEN0_FCSR 0x00000002 + #define MSECCFG_MML 0x00000001 #define MSECCFG_MMWP 0x00000002 #define MSECCFG_RLB 0x00000004 @@ -239,7 +277,7 @@ #define IRQ_M_EXT 11 #define IRQ_S_GEXT 12 #define IRQ_COP 12 -#define IRQ_HOST 13 +#define IRQ_LCOF 13 /* page table entry (PTE) fields */ #define PTE_V 0x001 /* Valid */ @@ -326,8 +364,12 @@ #define MASK_ADD8 0xfe00707f #define MATCH_ADD_UW 0x800003b #define MASK_ADD_UW 0xfe00707f +#define MATCH_ADDD 0x7b +#define MASK_ADDD 0xfe00707f #define MATCH_ADDI 0x13 #define MASK_ADDI 0x707f +#define MATCH_ADDID 0x5b +#define MASK_ADDID 0x707f #define MATCH_ADDIW 0x1b #define MASK_ADDIW 0x707f #define MATCH_ADDW 0x3b @@ -504,6 +546,10 @@ #define MASK_C_LDSP 0xe003 #define MATCH_C_LI 0x4001 #define MASK_C_LI 0xe003 +#define MATCH_C_LQ 0x2000 +#define MASK_C_LQ 0xe003 +#define MATCH_C_LQSP 0x2002 +#define MASK_C_LQSP 0xe003 #define MATCH_C_LUI 0x6001 #define MASK_C_LUI 0xe003 #define MATCH_C_LW 0x4000 @@ -522,6 +568,10 @@ #define MASK_C_SDSP 0xe003 #define MATCH_C_SLLI 0x2 #define MASK_C_SLLI 0xe003 +#define MATCH_C_SQ 0xa000 +#define MASK_C_SQ 0xe003 +#define MATCH_C_SQSP 0xa002 +#define MASK_C_SQSP 0xe003 #define MATCH_C_SRAI 0x8401 #define MASK_C_SRAI 0xec03 #define MATCH_C_SRLI 0x8001 @@ -1186,10 +1236,14 @@ #define MASK_LBU 0x707f #define MATCH_LD 0x3003 #define MASK_LD 0x707f +#define MATCH_LDU 0x7003 +#define MASK_LDU 0x707f #define MATCH_LH 0x1003 #define MASK_LH 0x707f #define MATCH_LHU 0x5003 #define MASK_LHU 0x707f +#define MATCH_LQ 0x300f +#define MASK_LQ 0x707f #define MATCH_LR_D 0x1000302f #define MASK_LR_D 0xf9f0707f #define MATCH_LR_W 0x1000202f @@ -1422,8 +1476,10 @@ #define MASK_SLL32 0xfe00707f #define MATCH_SLL8 0x5c000077 #define MASK_SLL8 0xfe00707f +#define MATCH_SLLD 0x107b +#define MASK_SLLD 0xfe00707f #define MATCH_SLLI 0x1013 -#define MASK_SLLI 0xfc00707f +#define MASK_SLLI 0xf800707f #define MATCH_SLLI16 0x74000077 #define MASK_SLLI16 0xff00707f #define MATCH_SLLI32 0x74002077 @@ -1432,6 +1488,8 @@ #define MASK_SLLI8 0xff80707f #define MATCH_SLLI_UW 0x800101b #define MASK_SLLI_UW 0xfc00707f +#define MATCH_SLLID 0x105b +#define MASK_SLLID 0xfc00707f #define MATCH_SLLIW 0x101b #define MASK_SLLIW 0xfe00707f #define MATCH_SLLW 0x103b @@ -1544,6 +1602,8 @@ #define MASK_SMXDS 0xfe00707f #define MATCH_SMXDS32 0x78002077 #define MASK_SMXDS32 0xfe00707f +#define MATCH_SQ 0x4023 +#define MASK_SQ 0x707f #define MATCH_SRA 0x40005033 #define MASK_SRA 0xfe00707f #define MATCH_SRA16 0x50000077 @@ -1560,8 +1620,10 @@ #define MASK_SRA8_U 0xfe00707f #define MATCH_SRA_U 0x24001077 #define MASK_SRA_U 0xfe00707f +#define MATCH_SRAD 0x4000507b +#define MASK_SRAD 0xfe00707f #define MATCH_SRAI 0x40005013 -#define MASK_SRAI 0xfc00707f +#define MASK_SRAI 0xf800707f #define MATCH_SRAI16 0x70000077 #define MASK_SRAI16 0xff00707f #define MATCH_SRAI16_U 0x71000077 @@ -1576,6 +1638,8 @@ #define MASK_SRAI8_U 0xff80707f #define MATCH_SRAI_U 0xd4001077 #define MASK_SRAI_U 0xfc00707f +#define MATCH_SRAID 0x4000505b +#define MASK_SRAID 0xfc00707f #define MATCH_SRAIW 0x4000501b #define MASK_SRAIW 0xfe00707f #define MATCH_SRAIW_U 0x34001077 @@ -1598,8 +1662,10 @@ #define MASK_SRL8 0xfe00707f #define MATCH_SRL8_U 0x6a000077 #define MASK_SRL8_U 0xfe00707f +#define MATCH_SRLD 0x507b +#define MASK_SRLD 0xfe00707f #define MATCH_SRLI 0x5013 -#define MASK_SRLI 0xfc00707f +#define MASK_SRLI 0xf800707f #define MATCH_SRLI16 0x72000077 #define MASK_SRLI16 0xff00707f #define MATCH_SRLI16_U 0x73000077 @@ -1612,6 +1678,8 @@ #define MASK_SRLI8 0xff80707f #define MATCH_SRLI8_U 0x7a800077 #define MASK_SRLI8_U 0xff80707f +#define MATCH_SRLID 0x505b +#define MASK_SRLID 0xfc00707f #define MATCH_SRLIW 0x501b #define MASK_SRLIW 0xfe00707f #define MATCH_SRLW 0x503b @@ -1642,6 +1710,8 @@ #define MASK_SUB64 0xfe00707f #define MATCH_SUB8 0x4a000077 #define MASK_SUB8 0xfe00707f +#define MATCH_SUBD 0x4000007b +#define MASK_SUBD 0xfe00707f #define MATCH_SUBW 0x4000003b #define MASK_SUBW 0xfe00707f #define MATCH_SUNPKD810 0xac800077 @@ -3224,7 +3294,9 @@ DECLARE_INSN(add32, MATCH_ADD32, MASK_ADD32) DECLARE_INSN(add64, MATCH_ADD64, MASK_ADD64) DECLARE_INSN(add8, MATCH_ADD8, MASK_ADD8) DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) +DECLARE_INSN(addd, MATCH_ADDD, MASK_ADDD) DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(addid, MATCH_ADDID, MASK_ADDID) DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) @@ -3313,6 +3385,8 @@ DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lq, MATCH_C_LQ, MASK_C_LQ) +DECLARE_INSN(c_lqsp, MATCH_C_LQSP, MASK_C_LQSP) DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) @@ -3322,6 +3396,8 @@ DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_sq, MATCH_C_SQ, MASK_C_SQ) +DECLARE_INSN(c_sqsp, MATCH_C_SQSP, MASK_C_SQSP) DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) @@ -3654,8 +3730,10 @@ DECLARE_INSN(kwmmul_u, MATCH_KWMMUL_U, MASK_KWMMUL_U) DECLARE_INSN(lb, MATCH_LB, MASK_LB) DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(ldu, MATCH_LDU, MASK_LDU) DECLARE_INSN(lh, MATCH_LH, MASK_LH) DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lq, MATCH_LQ, MASK_LQ) DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) @@ -3772,11 +3850,13 @@ DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) DECLARE_INSN(sll16, MATCH_SLL16, MASK_SLL16) DECLARE_INSN(sll32, MATCH_SLL32, MASK_SLL32) DECLARE_INSN(sll8, MATCH_SLL8, MASK_SLL8) +DECLARE_INSN(slld, MATCH_SLLD, MASK_SLLD) DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) DECLARE_INSN(slli16, MATCH_SLLI16, MASK_SLLI16) DECLARE_INSN(slli32, MATCH_SLLI32, MASK_SLLI32) DECLARE_INSN(slli8, MATCH_SLLI8, MASK_SLLI8) DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) +DECLARE_INSN(sllid, MATCH_SLLID, MASK_SLLID) DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) @@ -3833,6 +3913,7 @@ DECLARE_INSN(smulx16, MATCH_SMULX16, MASK_SMULX16) DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) DECLARE_INSN(smxds, MATCH_SMXDS, MASK_SMXDS) DECLARE_INSN(smxds32, MATCH_SMXDS32, MASK_SMXDS32) +DECLARE_INSN(sq, MATCH_SQ, MASK_SQ) DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(sra16, MATCH_SRA16, MASK_SRA16) DECLARE_INSN(sra16_u, MATCH_SRA16_U, MASK_SRA16_U) @@ -3841,6 +3922,7 @@ DECLARE_INSN(sra32_u, MATCH_SRA32_U, MASK_SRA32_U) DECLARE_INSN(sra8, MATCH_SRA8, MASK_SRA8) DECLARE_INSN(sra8_u, MATCH_SRA8_U, MASK_SRA8_U) DECLARE_INSN(sra_u, MATCH_SRA_U, MASK_SRA_U) +DECLARE_INSN(srad, MATCH_SRAD, MASK_SRAD) DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(srai16, MATCH_SRAI16, MASK_SRAI16) DECLARE_INSN(srai16_u, MATCH_SRAI16_U, MASK_SRAI16_U) @@ -3849,6 +3931,7 @@ DECLARE_INSN(srai32_u, MATCH_SRAI32_U, MASK_SRAI32_U) DECLARE_INSN(srai8, MATCH_SRAI8, MASK_SRAI8) DECLARE_INSN(srai8_u, MATCH_SRAI8_U, MASK_SRAI8_U) DECLARE_INSN(srai_u, MATCH_SRAI_U, MASK_SRAI_U) +DECLARE_INSN(sraid, MATCH_SRAID, MASK_SRAID) DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) DECLARE_INSN(sraiw_u, MATCH_SRAIW_U, MASK_SRAIW_U) DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) @@ -3860,6 +3943,7 @@ DECLARE_INSN(srl32, MATCH_SRL32, MASK_SRL32) DECLARE_INSN(srl32_u, MATCH_SRL32_U, MASK_SRL32_U) DECLARE_INSN(srl8, MATCH_SRL8, MASK_SRL8) DECLARE_INSN(srl8_u, MATCH_SRL8_U, MASK_SRL8_U) +DECLARE_INSN(srld, MATCH_SRLD, MASK_SRLD) DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srli16, MATCH_SRLI16, MASK_SRLI16) DECLARE_INSN(srli16_u, MATCH_SRLI16_U, MASK_SRLI16_U) @@ -3867,6 +3951,7 @@ DECLARE_INSN(srli32, MATCH_SRLI32, MASK_SRLI32) DECLARE_INSN(srli32_u, MATCH_SRLI32_U, MASK_SRLI32_U) DECLARE_INSN(srli8, MATCH_SRLI8, MASK_SRLI8) DECLARE_INSN(srli8_u, MATCH_SRLI8_U, MASK_SRLI8_U) +DECLARE_INSN(srlid, MATCH_SRLID, MASK_SRLID) DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) @@ -3882,6 +3967,7 @@ DECLARE_INSN(sub16, MATCH_SUB16, MASK_SUB16) DECLARE_INSN(sub32, MATCH_SUB32, MASK_SUB32) DECLARE_INSN(sub64, MATCH_SUB64, MASK_SUB64) DECLARE_INSN(sub8, MATCH_SUB8, MASK_SUB8) +DECLARE_INSN(subd, MATCH_SUBD, MASK_SUBD) DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sunpkd810, MATCH_SUNPKD810, MASK_SUNPKD810) DECLARE_INSN(sunpkd820, MATCH_SUNPKD820, MASK_SUNPKD820) From 7a1694796902776c3ed0a2256b80c4a7f77db4ff Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 22 Aug 2022 08:56:44 -0700 Subject: [PATCH 149/186] encoding.h license changed to BSD-3-Clause (#717) See https://github.com/riscv/riscv-opcodes/pull/139 Change-Id: I77ae5ab369e6cde26ad44d177dcae38c0fbe08ef Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome --- src/target/riscv/encoding.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index c046b8b2f..4c25316aa 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (8ab2df7) + * https://github.com/riscv/riscv-opcodes (0e5bcb5) */ #ifndef RISCV_CSR_ENCODING_H From 7c0ca4dd535667774c49a762dbb2b25c7da224dd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 25 Aug 2022 11:04:46 -0700 Subject: [PATCH 150/186] Add copyright line to encoding.h. (#718) Hopefully this will be the final version. Change-Id: Ib2f8cd6f613c5e0f8e8bf7a16c3edbf2d9b439b2 Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome --- src/target/riscv/encoding.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index 4c25316aa..c2da4e676 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2022 RISC-V International */ + /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (0e5bcb5) + * https://github.com/riscv/riscv-opcodes (dcdf8d3) */ #ifndef RISCV_CSR_ENCODING_H From 04020c19d0a63039f446cd45106f38431aa6d7bd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Sep 2022 10:47:15 -0700 Subject: [PATCH 151/186] Remove rtos.gdb_v_packet. (#722) It was a left-over from `-rtos riscv` and isn't used. Change-Id: Ie7e380600cd1331c6d382f654474270efad9f127 Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome --- src/rtos/rtos.c | 1 - src/rtos/rtos.h | 1 - src/server/gdb_server.c | 5 ----- 3 files changed, 7 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 2091e1b44..d73e5db12 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -98,7 +98,6 @@ static int os_alloc(struct target *target, struct rtos_type *ostype, /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; - os->gdb_v_packet = NULL; os->gdb_target_for_threadid = rtos_target_for_threadid; os->cmd_ctx = cmd_ctx; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 828fd26ae..745bea7bb 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -58,7 +58,6 @@ struct rtos { struct thread_detail *thread_details; int thread_count; int (*gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size); - int (*gdb_v_packet)(struct connection *connection, char const *packet, int packet_size); int (*gdb_target_for_threadid)(struct connection *connection, threadid_t thread_id, struct target **p_target); void *rtos_specific_params; /* Populated in rtos.c, so that individual RTOSes can register commands. */ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index cdb26f245..086fd1121 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3268,11 +3268,6 @@ static int gdb_v_packet(struct connection *connection, int result; struct target *target = get_target_from_connection(connection); - if (target->rtos != NULL && target->rtos->gdb_v_packet != NULL) { - int out = target->rtos->gdb_v_packet(connection, packet, packet_size); - if (out != GDB_THREAD_PACKET_NOT_CONSUMED) - return out; - } if (strncmp(packet, "vCont", 5) == 0) { bool handled; From 911d68ef25ab6996110cc618279b600fe82591e5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 9 Sep 2022 09:57:39 -0700 Subject: [PATCH 152/186] Don't read dmcontrol to set hartsel (#723) * Don't read dmcontrol to set hartsel We already know what dmcontrol should be. This addresses a long-standing TODO. In a toy test, this reduced the number of scans by 10+%. (Most of those are probably in poll(), so don't actually affect perceived performance.) Change-Id: I18e5ca391f0f5fb35f30d44dfef834e5a66aee20 Signed-off-by: Tim Newsome * Make code easier to read Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> --- src/target/riscv/riscv-013.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 32b9cf7ff..24895e9ef 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -4110,10 +4110,7 @@ static int riscv013_select_current_hart(struct target *target) if (r->current_hartid == dm->current_hartid) return ERROR_OK; - uint32_t dmcontrol; - /* TODO: can't we just "dmcontrol = DMI_DMACTIVE"? */ - if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) - return ERROR_FAIL; + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); int result = dmi_write(target, DM_DMCONTROL, dmcontrol); dm->current_hartid = r->current_hartid; From 8832d4be97ee4291f1f06ae06d69f35902305ab8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 13 Sep 2022 10:17:56 -0700 Subject: [PATCH 153/186] Add error message when dmstatus read times out. Otherwise OpenOCD simply doesn't work without giving any indication why. Change-Id: I21703fc1a0d9bed2f59da95f8a8395fe139484a4 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 24895e9ef..a2d887e0b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -701,8 +701,14 @@ int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, int dmstatus_read(struct target *target, uint32_t *dmstatus, bool authenticated) { - return dmstatus_read_timeout(target, dmstatus, authenticated, + int result = dmstatus_read_timeout(target, dmstatus, authenticated, riscv_command_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) + LOG_TARGET_ERROR(target, "DMSTATUS read didn't complete in %d seconds. The target is " + "either really slow or broken. You could increase the " + "timeout with `riscv set_command_timeout_sec`.", + riscv_command_timeout_sec); + return result; } static void increase_ac_busy_delay(struct target *target) From 639e68a621b7ae8c4a296ca7e45b47075268fded Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 15 Sep 2022 11:41:33 -0700 Subject: [PATCH 154/186] Make poll backoff time based. Requested in https://review.openocd.org/c/openocd/+/6964. I'm making the change here so I have a chance to test it properly before pushing it upstream. A nice effect of this change is that we avoid some unnecessary polling early on when gdb is connecting and we would poll once every time we send gdb a qXfer packet. Change-Id: I4bdb9f05839e8c1e01ff6dde49d6589595418095 Signed-off-by: Tim Newsome --- src/target/target.c | 61 +++++++++++++++++++++------------------------ src/target/target.h | 7 ++++-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 7d3861ab5..3a5651309 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3046,44 +3046,41 @@ static int handle_target(void *priv) is_jtag_poll_safe() && target; target = target->next) { - if (!target->tap->enabled) + /* This function only gets called every polling_interval, so + * allow some slack in the time comparison. Otherwise, if we + * schedule for now+polling_interval, the next poll won't + * actually happen until a polling_interval later. */ + if (!target->tap->enabled || + power_dropout || + srst_asserted || + timeval_ms() + polling_interval / 2 < target->backoff.next_attempt) continue; - if (target->backoff.times > target->backoff.count) { - /* do not poll this time as we failed previously */ - target->backoff.count++; - continue; + /* polling may fail silently until the target has been examined */ + retval = target_poll(target); + if (retval == ERROR_OK) { + target->backoff.interval = polling_interval; + } else { + /* Increase interval between polling up to 5000ms */ + target->backoff.interval = MAX(polling_interval, + MIN(target->backoff.interval * 2 + 1, 5000)); + /* Tell GDB to halt the debugger. This allows the user to run + * monitor commands to handle the situation. */ + target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } - target->backoff.count = 0; + target->backoff.next_attempt = timeval_ms() + target->backoff.interval; + LOG_TARGET_DEBUG(target, "target_poll() -> %d, next attempt in %dms", + retval, target->backoff.interval); - /* only poll target if we've got power and srst isn't asserted */ - if (!power_dropout && !srst_asserted) { - /* polling may fail silently until the target has been examined */ - retval = target_poll(target); + if (retval != ERROR_OK && examine_attempted) { + target_reset_examined(target); + retval = target_examine_one(target); if (retval != ERROR_OK) { - /* 100ms polling interval. Increase interval between polling up to 5000ms */ - if (target->backoff.times * polling_interval < 5000) - target->backoff.times = MIN(target->backoff.times * 2 + 1, - 5000 / polling_interval); - - /* Tell GDB to halt the debugger. This allows the user to - * run monitor commands to handle the situation. - */ - target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); - } - if (target->backoff.times > 0 && examine_attempted) { - LOG_DEBUG("[%s] Polling failed, trying to reexamine", target_name(target)); - target_reset_examined(target); - retval = target_examine_one(target); - if (retval != ERROR_OK) { - LOG_DEBUG("[%s] Examination failed, GDB will be halted. Polling again in %dms", - target_name(target), target->backoff.times * polling_interval); - return retval; - } + LOG_TARGET_DEBUG(target, "Examination failed, GDB will be halted. " + "Polling again in %dms", + target->backoff.interval); + return retval; } - - /* Since we succeeded, we reset backoff count */ - target->backoff.times = 0; } } diff --git a/src/target/target.h b/src/target/target.h index 4b494d8d5..726a14d3f 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -117,8 +117,8 @@ struct gdb_service { /* target back off timer */ struct backoff_timer { - int times; - int count; + int64_t next_attempt; + unsigned int interval; }; /* split target registers into multiple class */ @@ -199,6 +199,9 @@ struct target { struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ + /* Track when next to poll(). If polling is failing, we don't want to + * poll too quickly because we'll just overwhelm the user with error + * messages. */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ struct list_head *smp_targets; /* list all targets in this smp group/cluster From 4004db5d3a7e767aa4a6b7fddf92ac3370670c79 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 16 Sep 2022 16:51:57 -0700 Subject: [PATCH 155/186] Make polling_interval unsigned. Hopefully fixes win32 build. Change-Id: I13d6d475f03bada96b2eb943f2c16df05413d34f Signed-off-by: Tim Newsome --- src/target/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 3a5651309..35c5be8f6 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -159,7 +159,7 @@ static struct target_timer_callback *target_timer_callbacks; static int64_t target_timer_next_event_value; static LIST_HEAD(target_reset_callback_list); static LIST_HEAD(target_trace_callback_list); -static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static const unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; static LIST_HEAD(empty_smp_targets); static const struct jim_nvp nvp_assert[] = { From 89746e111b11ea6cb5cc2cb76edfc4e31ff88038 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 19 Sep 2022 09:43:51 -0700 Subject: [PATCH 156/186] Fix comment indent. Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome --- src/target/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 35c5be8f6..e663fff63 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3065,7 +3065,7 @@ static int handle_target(void *priv) target->backoff.interval = MAX(polling_interval, MIN(target->backoff.interval * 2 + 1, 5000)); /* Tell GDB to halt the debugger. This allows the user to run - * monitor commands to handle the situation. */ + * monitor commands to handle the situation. */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } target->backoff.next_attempt = timeval_ms() + target->backoff.interval; From fa1abc63d22a9b6511a73025bd7e80d5b7d411af Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 19 Sep 2022 09:44:10 -0700 Subject: [PATCH 157/186] Add explanatory comment. Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome --- src/target/target.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/target.c b/src/target/target.c index e663fff63..5e2fe8cda 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3059,6 +3059,7 @@ static int handle_target(void *priv) /* polling may fail silently until the target has been examined */ retval = target_poll(target); if (retval == ERROR_OK) { + /* Polling succeeded, reset the back-off interval */ target->backoff.interval = polling_interval; } else { /* Increase interval between polling up to 5000ms */ From b7738370b75543870c4cbb15061b8e7b38887e9e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 19 Sep 2022 09:48:09 -0700 Subject: [PATCH 158/186] Make large if() more readable. Change-Id: Ie43400387ab9f290e744ebaa09786612237e6c7e Signed-off-by: Tim Newsome --- src/target/target.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 5e2fe8cda..5867149a7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3050,10 +3050,8 @@ static int handle_target(void *priv) * allow some slack in the time comparison. Otherwise, if we * schedule for now+polling_interval, the next poll won't * actually happen until a polling_interval later. */ - if (!target->tap->enabled || - power_dropout || - srst_asserted || - timeval_ms() + polling_interval / 2 < target->backoff.next_attempt) + const bool poll_needed = timeval_ms() + polling_interval / 2 >= target->backoff.next_attempt; + if (!target->tap->enabled || power_dropout || srst_asserted || !poll_needed) continue; /* polling may fail silently until the target has been examined */ From 671d99b89bebe74a4d8f8ef198e7b52c15388c3e Mon Sep 17 00:00:00 2001 From: mrv96 Date: Mon, 19 Sep 2022 14:27:10 +0200 Subject: [PATCH 159/186] Support for custom TMSC buffer Signed-off-by: mrv96 --- src/jtag/drivers/ftdi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 2ecff7f86..9eb199487 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -808,6 +808,8 @@ static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, u static const uint8_t zero; static const uint8_t one = 1; + struct signal *tmsc_en = find_signal_by_name("TMSC_EN"); + LOG_DEBUG_IO("oscan1_mpsse_clock_data: %sout %d bits", in ? "in" : "", length); for (unsigned i = 0; i < length; i++) { @@ -833,8 +835,14 @@ static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, u mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, false, mode); } + if (tmsc_en) + ftdi_set_signal(tmsc_en, '0'); /* put TMSC in high impedance */ + /* drive another TCK without driving TMSC (TDO cycle) */ mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, false, mode); + + if (tmsc_en) + ftdi_set_signal(tmsc_en, '1'); /* drive again TMSC */ } } @@ -845,6 +853,8 @@ static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, static const uint8_t zero; static const uint8_t one = 1; + struct signal *tmsc_en = find_signal_by_name("TMSC_EN"); + LOG_DEBUG_IO("oscan1_mpsse_clock_tms_cs: %sout %d bits, tdi=%d", in ? "in" : "", length, tdi); for (unsigned i = 0; i < length; i++) { @@ -871,8 +881,14 @@ static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, (tmsbit != 0), mode); } + if (tmsc_en) + ftdi_set_signal(tmsc_en, '0'); /* put TMSC in high impedance */ + /* drive another TCK without driving TMSC (TDO cycle) */ mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, false, mode); + + if (tmsc_en) + ftdi_set_signal(tmsc_en, '1'); /* drive again TMSC */ } } From c96a24a30775689a928d22d30c3c43cda38b8b94 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Mon, 19 Sep 2022 23:47:39 +0200 Subject: [PATCH 160/186] Add Digilent JTAG-HS2 cJTAG configuration Signed-off-by: mrv96 --- tcl/interface/ftdi/digilent-hs2-cjtag.cfg | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tcl/interface/ftdi/digilent-hs2-cjtag.cfg diff --git a/tcl/interface/ftdi/digilent-hs2-cjtag.cfg b/tcl/interface/ftdi/digilent-hs2-cjtag.cfg new file mode 100644 index 000000000..067f66465 --- /dev/null +++ b/tcl/interface/ftdi/digilent-hs2-cjtag.cfg @@ -0,0 +1,19 @@ +# this supports JTAG-HS2 (and apparently Nexys4 as well) + +adapter driver ftdi +ftdi device_desc "Digilent Adept USB Device" +ftdi vid_pid 0x0403 0x6014 + +ftdi channel 0 +ftdi layout_init 0xc0e8 0xe0eb + +reset_config none + +# These signals are used for cJTAG escape sequence on initialization only +ftdi layout_signal TCK -data 0x0001 +ftdi layout_signal TDI -data 0x0002 +ftdi layout_signal TDO -input 0x0004 +ftdi layout_signal TMS -data 0x0008 +ftdi layout_signal JTAG_SEL -ndata 0xc000 + +ftdi layout_signal TMSC_EN -data 0x0020 From 3c5be531dfe40d67199ffbb57c28b7bd96651923 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 22 Sep 2022 09:58:24 -0700 Subject: [PATCH 161/186] Don't use const on temporary variable. It's not part of OpenOCD style: https://review.openocd.org/c/openocd/+/6319/5..10/src/target/aarch64.c#b1500 Change-Id: Ifb612a942507ca5ed8cac3e3ec59e0e14b0298ed Signed-off-by: Tim Newsome --- src/target/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 5867149a7..927329a64 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3050,7 +3050,7 @@ static int handle_target(void *priv) * allow some slack in the time comparison. Otherwise, if we * schedule for now+polling_interval, the next poll won't * actually happen until a polling_interval later. */ - const bool poll_needed = timeval_ms() + polling_interval / 2 >= target->backoff.next_attempt; + bool poll_needed = timeval_ms() + polling_interval / 2 >= target->backoff.next_attempt; if (!target->tap->enabled || power_dropout || srst_asserted || !poll_needed) continue; From 4b0379fa16d170d99f2bb303acb972ed92310bbf Mon Sep 17 00:00:00 2001 From: mrv96 Date: Mon, 19 Sep 2022 23:47:50 +0200 Subject: [PATCH 162/186] Improve oSCAN1 documentation Signed-off-by: mrv96 --- doc/openocd.texi | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 73f53c212..6aa1c49ed 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2583,10 +2583,23 @@ and initially asserted reset signals. @end deffn @deffn {Command} {ftdi oscan1_mode} on|off -Enable or disable OSCAN1 mode. This mode is intended for use with an adapter, +Enable or disable OScan1 mode. This mode is intended for use with an adapter, such as the ARM-JTAG-SWD by Olimex, that sits in between the FTDI chip and the -target. The adapter uses the normal JTAG signals to control TCKC and TMSC -(bidirectional) signals used in 2-wire cJTAG. +target. The cJTAG prococol is composed of two wires: TCKC (clock) and TMSC (data). +TMSC is a bidirectional signal which is time-multiplexed alternating TDI, TMS and +TDO. The multiplexing is achieved by a tri-state buffer which puts TMSC in Hi-Z +when the device is supposed to take the control of the line (TDO phase). + +The ARM-JTAG-SWD adapter uses standard TRST and TMS signals to control TMSC +direction. TRST is used by the adapter as selector for the multiplexers which set +the JTAG probe in 2-wire mode. Whatever signal is used for this purpose, it must +be defined with the name JTAG_SEL using @command{ftdi layout_signal}. JTAG_SEL is +set to 0 during OScan1 initialization. + +Some JTAG probes like the Digilent JTAG-HS2, support cJTAG by using a +separate pin to control when TMS is driven onto TMSC. You can use such +probes by defining the signal TMSC_EN using +@command{ftdi layout_signal TMSC_EN -data }. @end deffn @deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] From 137141249b33cf1b2a471b959e07173ee8238fa1 Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov Date: Wed, 21 Sep 2022 10:07:39 +0300 Subject: [PATCH 163/186] Propagate error code in register_read/write_direct In some cases error code returned by riscv_program_insert was ignored --- src/target/riscv/riscv-013.c | 37 ++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a2d887e0b..9c12489b9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1323,7 +1323,9 @@ static int register_write_direct(struct target *target, unsigned number, /* There are no instructions to move all the bits from a register, so * we need to use some scratch RAM. */ use_scratch = true; - riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)); + if (riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)) + != ERROR_OK) + return ERROR_FAIL; if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) return ERROR_FAIL; @@ -1341,10 +1343,15 @@ static int register_write_direct(struct target *target, unsigned number, } else { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) - riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); - else - riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); + if (riscv_supports_extension(target, 'D')) { + if (riscv_program_insert(&program, + fmv_d_x(number - GDB_REGNO_FPR0, S0) != ERROR_OK)) + return ERROR_FAIL; + } else { + if (riscv_program_insert(&program, + fmv_w_x(number - GDB_REGNO_FPR0, S0) != ERROR_OK)) + return ERROR_FAIL; + } } else if (number == GDB_REGNO_VTYPE) { if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; @@ -1363,7 +1370,8 @@ static int register_write_direct(struct target *target, unsigned number, if (riscv_program_insert(&program, vsetvl(ZERO, S0, S1)) != ERROR_OK) return ERROR_FAIL; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - riscv_program_csrw(&program, S0, number); + if (riscv_program_csrw(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); return ERROR_FAIL; @@ -1417,9 +1425,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ - riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, - 0)); - + if (riscv_program_insert(&program, + fsd(number - GDB_REGNO_FPR0, S0, 0)) != ERROR_OK) + return ERROR_FAIL; if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) return ERROR_FAIL; use_scratch = true; @@ -1430,12 +1438,17 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } } else if (riscv_supports_extension(target, 'D')) { - riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + if (riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)) != + ERROR_OK) + return ERROR_FAIL; } else { - riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); + if (riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)) != + ERROR_OK) + return ERROR_FAIL; } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - riscv_program_csrr(&program, S0, number); + if (riscv_program_csrr(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; } else { LOG_ERROR("Unsupported register: %s", gdb_regno_name(number)); return ERROR_FAIL; From fb7c8b310ae3b754d23122ebd8f0e752c4b6a181 Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov Date: Fri, 29 Jul 2022 11:27:06 +0300 Subject: [PATCH 164/186] Remove incorrect debug_log in wait_for_idle According to RISC-V External Debug Support Version 0.13.2 (paragraph 3.12.6), cmderr field contains a valid value only if busy is 0, so it is incorrect to analize it on timeout. --- src/target/riscv/riscv-013.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a2d887e0b..23d3aafc9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -748,20 +748,6 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) if (time(NULL) - start > riscv_command_timeout_sec) { info->cmderr = get_field(*abstractcs, DM_ABSTRACTCS_CMDERR); - if (info->cmderr != CMDERR_NONE) { - const char *errors[8] = { - "none", - "busy", - "not supported", - "exception", - "halt/resume", - "reserved", - "reserved", - "other" }; - - LOG_ERROR("Abstract command ended in error '%s' (abstractcs=0x%x)", - errors[info->cmderr], *abstractcs); - } LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", From 550a66e72094bc59b33fd2f020bf78acf731f60c Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 29 Sep 2022 15:09:49 -0700 Subject: [PATCH 165/186] Use LOG_TARGET_FOO() functions in more places. (#731) Change-Id: Id2266dbfb6209bf0676f28e7383a12705ce2a70e Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome --- src/rtos/rtos.c | 7 ++--- src/target/riscv/riscv-013.c | 53 ++++++++++++++++-------------------- src/target/riscv/riscv.c | 17 +++++------- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index d73e5db12..b82ecb338 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -573,10 +573,9 @@ int rtos_get_gdb_reg_list(struct connection *connection) struct rtos_reg *reg_list; int num_regs; - LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64 - ", target->rtos->current_thread=0x%" PRIx64 "\r\n", - current_threadid, - target->rtos->current_thread); + LOG_TARGET_DEBUG(target, "RTOS: getting register list for thread 0x%" PRIx64 + ", target->rtos->current_thread=0x%" PRIx64, + current_threadid, target->rtos->current_thread); int retval = target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 91dffd757..90824c6b4 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1282,8 +1282,7 @@ static bool has_sufficient_progbuf(struct target *target, unsigned size) static int register_write_direct(struct target *target, unsigned number, uint64_t value) { - LOG_DEBUG("{%d} %s <- 0x%" PRIx64, riscv_current_hartid(target), - gdb_regno_name(number), value); + LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(number), value); int result = register_write_abstract(target, number, value, register_size(target, number)); @@ -1459,10 +1458,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } - if (result == ERROR_OK) { - LOG_DEBUG("{%d} %s = 0x%" PRIx64, riscv_current_hartid(target), - gdb_regno_name(number), *value); - } + if (result == ERROR_OK) + LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(number), *value); return result; } @@ -1697,8 +1694,8 @@ static int examine(struct target *target) bool halted = riscv_is_halted(target); if (!halted) { if (riscv013_halt_go(target) != ERROR_OK) { - LOG_ERROR("[%s] Fatal: Hart %d failed to halt during examine()", - target_name(target), r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()", + info->index); return ERROR_FAIL; } } @@ -1717,16 +1714,16 @@ static int examine(struct target *target) * need to take care of this manually. */ uint64_t s0, s1; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) { - LOG_ERROR("Fatal: Failed to read s0 from hart %d.", r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); return ERROR_FAIL; } if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) { - LOG_ERROR("Fatal: Failed to read s1 from hart %d.", r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); return ERROR_FAIL; } if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { - LOG_ERROR("Fatal: Failed to read MISA from hart %d.", r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA."); return ERROR_FAIL; } @@ -1741,16 +1738,15 @@ static int examine(struct target *target) /* Display this as early as possible to help people who are using * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, - r->misa); + LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); /* Restore s0 and s1. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) { - LOG_ERROR("Fatal: Failed to write s0 back to hart %d.", r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0."); return ERROR_FAIL; } if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) { - LOG_ERROR("Fatal: Failed to write s1 back to hart %d.", r->current_hartid); + LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1."); return ERROR_FAIL; } @@ -1772,10 +1768,9 @@ static int examine(struct target *target) /* Some regression suites rely on seeing 'Examined RISC-V core' to know * when they can connect with gdb/telnet. * We will need to update those suites if we want to change that text. */ - LOG_INFO("Examined RISC-V core; found %d harts", + LOG_TARGET_INFO(target, "Examined RISC-V core; found %d harts", riscv_count_harts(target)); - LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, - r->misa); + LOG_TARGET_INFO(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); return ERROR_OK; } @@ -4057,7 +4052,7 @@ static int riscv013_get_register(struct target *target, if (rid == GDB_REGNO_PC) { /* TODO: move this into riscv.c. */ result = register_read_direct(target, value, GDB_REGNO_DPC); - LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value); + LOG_TARGET_DEBUG(target, "read PC from DPC: 0x%" PRIx64, *value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; /* TODO: move this into riscv.c. */ @@ -4076,17 +4071,17 @@ static int riscv013_get_register(struct target *target, static int riscv013_set_register(struct target *target, int rid, uint64_t value) { riscv013_select_current_hart(target); - LOG_DEBUG("[%d] writing 0x%" PRIx64 " to register %s", - target->coreid, value, gdb_regno_name(rid)); + LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", + value, gdb_regno_name(rid)); if (rid <= GDB_REGNO_XPR31) { return register_write_direct(target, rid, value); } else if (rid == GDB_REGNO_PC) { - LOG_DEBUG("[%d] writing PC to DPC: 0x%" PRIx64, target->coreid, value); + LOG_TARGET_DEBUG(target, "writing PC to DPC: 0x%" PRIx64, value); register_write_direct(target, GDB_REGNO_DPC, value); uint64_t actual_value; register_read_direct(target, &actual_value, GDB_REGNO_DPC); - LOG_DEBUG("[%d] actual DPC written: 0x%016" PRIx64, target->coreid, actual_value); + LOG_TARGET_DEBUG(target, " actual DPC written: 0x%016" PRIx64, actual_value); if (value != actual_value) { LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " "value (0x%" PRIx64 ")", value, actual_value); @@ -4207,8 +4202,8 @@ static int riscv013_halt_go(struct target *target) if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; - LOG_ERROR("[%s] Unable to halt hart %d. dmcontrol=0x%08x, dmstatus=0x%08x", - target_name(target), r->current_hartid, dmcontrol, dmstatus); + LOG_TARGET_ERROR(target, "Unable to halt. dmcontrol=0x%08x, dmstatus=0x%08x", + dmcontrol, dmstatus); return ERROR_FAIL; } @@ -4296,7 +4291,7 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) if (result != ERROR_OK) return RISCV_HALT_UNKNOWN; - LOG_DEBUG("dcsr.cause: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); + LOG_TARGET_DEBUG(target, "dcsr.cause: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_EBREAK: @@ -4782,11 +4777,11 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step, bool use_hasel) { RISCV_INFO(r); - LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); if (!riscv_is_halted(target)) { LOG_ERROR("Hart %d is not halted!", r->current_hartid); return ERROR_FAIL; } + LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step); if (riscv_flush_registers(target) != ERROR_OK) return ERROR_FAIL; @@ -4817,10 +4812,10 @@ static int riscv013_step_or_resume_current_hart(struct target *target, dmi_write(target, DM_DMCONTROL, dmcontrol); - LOG_ERROR("unable to resume hart %d", r->current_hartid); + LOG_TARGET_ERROR(target, "unable to resume"); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - LOG_ERROR(" dmstatus =0x%08x", dmstatus); + LOG_TARGET_ERROR(target, " dmstatus=0x%08x", dmstatus); if (step) { LOG_ERROR(" was stepping, halting"); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9f126b9cd..d7b5f4805 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -796,7 +796,7 @@ int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { - LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, breakpoint->address); + LOG_TARGET_DEBUG(target, "@0x%" TARGET_PRIxADDR, breakpoint->address); assert(breakpoint); if (breakpoint->type == BKPT_SOFT) { /** @todo check RVC for size/alignment */ @@ -1017,7 +1017,7 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi { RISCV_INFO(r); - LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target)); + LOG_TARGET_DEBUG(target, "Hit Watchpoint"); /* If we identified which trigger caused the halt earlier, then just use * that. */ @@ -1297,7 +1297,7 @@ int riscv_halt(struct target *target) return tt->halt(target); } - LOG_DEBUG("[%d] halting all harts", target->coreid); + LOG_TARGET_DEBUG(target, "halting all harts"); int result = ERROR_OK; if (target->smp) { @@ -1443,7 +1443,7 @@ static int resume_prep(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { RISCV_INFO(r); - LOG_DEBUG("[%d]", target->coreid); + LOG_TARGET_DEBUG(target, "target->state=%d", target->state); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); @@ -1806,9 +1806,7 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class, bool read) { - RISCV_INFO(r); - LOG_DEBUG("[%s] {%d} reg_class=%d, read=%d", - target_name(target), r->current_hartid, reg_class, read); + LOG_TARGET_DEBUG(target, "reg_class=%d, read=%d", reg_class, read); if (!target->reg_cache) { LOG_ERROR("Target not initialized. Return ERROR_FAIL."); @@ -2118,8 +2116,7 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) if (riscv_set_current_hartid(target, hartid) != ERROR_OK) return RPH_ERROR; - LOG_DEBUG("[%s] polling hart %d, target->state=%d", target_name(target), - hartid, target->state); + LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state); /* If OpenOCD thinks we're running but this hart is halted then it's time * to raise an event. */ @@ -3544,7 +3541,7 @@ static int riscv_resume_go_all_harts(struct target *target) { RISCV_INFO(r); - LOG_DEBUG("[%s] resuming hart", target_name(target)); + LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { From 84365e65e5c1f914e8597a49e172ffbd093bd33a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 23 Sep 2022 11:32:42 -0700 Subject: [PATCH 166/186] Remove riscv_info_t.current_hartid This was used to track which hart a given operation must apply to. But we already have a target associated with each operation, and from there we can find the desired hart id. dm013_info_t already tracks current_hartid (meaning which hart ID is currently selected by the DM). This makes the code simpler to understand. Also it turns out we don't need to make sure the correct hart ID is currently selected because there are only a few real entry points. Change-Id: Ibe8d5e156523397f245edd6ec0a5df3239b717bf Signed-off-by: Tim Newsome --- src/target/riscv/riscv-011.c | 1 - src/target/riscv/riscv-013.c | 104 +++++++++++++++++++++-------------- src/target/riscv/riscv.c | 83 +++++----------------------- src/target/riscv/riscv.h | 12 +--- 4 files changed, 79 insertions(+), 121 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index e0f92d41c..d999ab397 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1590,7 +1590,6 @@ static int examine(struct target *target) return result; target_set_examined(target); - riscv_set_current_hartid(target, 0); for (size_t i = 0; i < 32; ++i) reg_cache_set(target, i, -1); LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 90824c6b4..494eeaa20 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -38,7 +38,7 @@ static void riscv013_clear_abstract_error(struct target *target); static int riscv013_get_register(struct target *target, riscv_reg_t *value, int rid); static int riscv013_set_register(struct target *target, int regid, uint64_t value); -static int riscv013_select_current_hart(struct target *target); +static int dm013_select_hart(struct target *target, int hart_index); static int riscv013_halt_prep(struct target *target); static int riscv013_halt_go(struct target *target); static int riscv013_resume_go(struct target *target); @@ -139,8 +139,12 @@ typedef struct { bool was_reset; /* Targets that are connected to this DM. */ struct list_head target_list; - /* The currently selected hartid on this DM. */ + /* Contains the ID of the hart that is currently selected by this DM. + * (If multiple harts are selected this is meaningless, and that corner case + * is not currently handled well.) + */ int current_hartid; + bool hasel_supported; /* The program buffer stores executable code. 0 is an illegal instruction, @@ -758,6 +762,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) } } +static int dm013_select_target(struct target *target) +{ + riscv013_info_t *info = get_info(target); + return dm013_select_hart(target, info->index); +} + static int execute_abstract_command(struct target *target, uint32_t command) { RISCV013_INFO(info); @@ -1384,6 +1394,9 @@ static int register_write_direct(struct target *target, unsigned number, /** Actually read registers from the target right now. */ static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) { + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + int result = register_read_abstract(target, value, number, register_size(target, number)); @@ -1659,8 +1672,7 @@ static int examine(struct target *target) /* Before doing anything else we must first enumerate the harts. */ if (dm->hart_count < 0) { for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { - r->current_hartid = i; - if (riscv013_select_current_hart(target) != ERROR_OK) + if (dm013_select_hart(target, i) != ERROR_OK) return ERROR_FAIL; uint32_t s; @@ -1678,8 +1690,6 @@ static int examine(struct target *target) LOG_DEBUG("Detected %d harts.", dm->hart_count); } - r->current_hartid = target->coreid; - if (dm->hart_count == 0) { LOG_ERROR("No harts found!"); return ERROR_FAIL; @@ -1688,7 +1698,7 @@ static int examine(struct target *target) /* Don't call any riscv_* functions until after we've counted the number of * cores and initialized registers. */ - if (riscv013_select_current_hart(target) != ERROR_OK) + if (dm013_select_hart(target, info->index) != ERROR_OK) return ERROR_FAIL; bool halted = riscv_is_halted(target); @@ -1948,7 +1958,7 @@ static int riscv013_get_register_buf(struct target *target, { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); - if (riscv_select_current_hart(target) != ERROR_OK) + if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) @@ -2004,7 +2014,7 @@ static int riscv013_set_register_buf(struct target *target, { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); - if (riscv_select_current_hart(target) != ERROR_OK) + if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) @@ -2270,7 +2280,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->set_register = &riscv013_set_register; generic_info->get_register_buf = &riscv013_get_register_buf; generic_info->set_register_buf = &riscv013_set_register_buf; - generic_info->select_current_hart = &riscv013_select_current_hart; + generic_info->select_target = &dm013_select_target; generic_info->is_halted = &riscv013_is_halted; generic_info->resume_go = &riscv013_resume_go; generic_info->step_current_hart = &riscv013_step_current_hart; @@ -2329,7 +2339,7 @@ static int init_target(struct command_context *cmd_ctx, static int assert_reset(struct target *target) { - RISCV_INFO(r); + RISCV013_INFO(info); select_dmi(target); @@ -2347,7 +2357,7 @@ static int assert_reset(struct target *target) /* Set haltreq for each hart. */ uint32_t control = control_base; - control = set_hartsel(control_base, target->coreid); + control = set_hartsel(control_base, info->index); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DM_DMCONTROL, control); @@ -2358,7 +2368,7 @@ static int assert_reset(struct target *target) } else { /* Reset just this hart. */ - uint32_t control = set_hartsel(control_base, r->current_hartid); + uint32_t control = set_hartsel(control_base, info->index); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_NDMRESET, 1); @@ -2381,7 +2391,6 @@ static int assert_reset(struct target *target) static int deassert_reset(struct target *target) { - RISCV_INFO(r); RISCV013_INFO(info); select_dmi(target); @@ -2389,22 +2398,21 @@ static int deassert_reset(struct target *target) uint32_t control = 0; control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); - dmi_write(target, DM_DMCONTROL, - set_hartsel(control, r->current_hartid)); + dmi_write(target, DM_DMCONTROL, set_hartsel(control, info->index)); uint32_t dmstatus; int dmi_busy_delay = info->dmi_busy_delay; time_t start = time(NULL); - for (int i = 0; i < riscv_count_harts(target); ++i) { - int index = i; + for (unsigned int i = 0; i < riscv_count_harts(target); ++i) { + unsigned int index = i; if (target->rtos) { - if (index != target->coreid) + if (index != info->index) continue; dmi_write(target, DM_DMCONTROL, set_hartsel(control, index)); } else { - index = r->current_hartid; + index = info->index; } LOG_DEBUG("Waiting for hart %d to come out of reset.", index); @@ -2454,6 +2462,9 @@ static int deassert_reset(struct target *target) static int execute_fence(struct target *target) { + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ { @@ -3416,6 +3427,9 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + select_dmi(target); memset(buffer, 0, count*size); @@ -4045,7 +4059,7 @@ static int riscv013_get_register(struct target *target, LOG_DEBUG("[%s] reading register %s", target_name(target), gdb_regno_name(rid)); - if (riscv_select_current_hart(target) != ERROR_OK) + if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; int result = ERROR_OK; @@ -4070,7 +4084,8 @@ static int riscv013_get_register(struct target *target, static int riscv013_set_register(struct target *target, int rid, uint64_t value) { - riscv013_select_current_hart(target); + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", value, gdb_regno_name(rid)); @@ -4100,21 +4115,23 @@ static int riscv013_set_register(struct target *target, int rid, uint64_t value) return ERROR_OK; } -static int riscv013_select_current_hart(struct target *target) +static int dm013_select_hart(struct target *target, int hart_index) { - RISCV_INFO(r); - dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; - if (r->current_hartid == dm->current_hartid) + if (hart_index == dm->current_hartid) return ERROR_OK; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; - dmcontrol = set_hartsel(dmcontrol, r->current_hartid); - int result = dmi_write(target, DM_DMCONTROL, dmcontrol); - dm->current_hartid = r->current_hartid; - return result; + dmcontrol = set_hartsel(dmcontrol, hart_index); + if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { + /* Who knows what the state is? */ + dm->current_hartid = -2; + return ERROR_FAIL; + } + dm->current_hartid = hart_index; + return ERROR_OK; } /* Select all harts that were prepped and that are selectable, clearing the @@ -4128,6 +4145,7 @@ static int select_prepped_harts(struct target *target, bool *use_hasel) RISCV_INFO(r); r->prepped = false; *use_hasel = false; + dm013_select_target(target); return ERROR_OK; } @@ -4178,18 +4196,19 @@ static int riscv013_halt_prep(struct target *target) static int riscv013_halt_go(struct target *target) { + RISCV013_INFO(info); + bool use_hasel = false; if (select_prepped_harts(target, &use_hasel) != ERROR_OK) return ERROR_FAIL; - RISCV_INFO(r); - LOG_DEBUG("halting hart %d", r->current_hartid); + LOG_TARGET_DEBUG(target, "halting hart"); /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; if (use_hasel) dmcontrol |= DM_DMCONTROL_HASEL; - dmcontrol = set_hartsel(dmcontrol, r->current_hartid); + dmcontrol = set_hartsel(dmcontrol, info->index); dmi_write(target, DM_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) if (riscv_is_halted(target)) @@ -4258,20 +4277,23 @@ static int riscv013_on_halt(struct target *target) static bool riscv013_is_halted(struct target *target) { + RISCV013_INFO(info); + uint32_t dmstatus; + if (dm013_select_target(target) != ERROR_OK) + return false; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return false; if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL)) - LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target)); + LOG_TARGET_ERROR(target, "Hart is unavailable."); if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT)) - LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target)); + LOG_TARGET_ERROR(target, "Hart doesn't exist."); if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { - int hartid = riscv_current_hartid(target); - LOG_INFO("Hart %d unexpectedly reset!", hartid); + LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; - dmcontrol = set_hartsel(dmcontrol, hartid); + dmcontrol = set_hartsel(dmcontrol, info->index); /* If we had been halted when we reset, request another halt. If we * ended up running out of reset, then the user will (hopefully) get a * message that a reset happened, that the target is running, and then @@ -4776,9 +4798,8 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) static int riscv013_step_or_resume_current_hart(struct target *target, bool step, bool use_hasel) { - RISCV_INFO(r); if (!riscv_is_halted(target)) { - LOG_ERROR("Hart %d is not halted!", r->current_hartid); + LOG_TARGET_ERROR(target, "Hart is not halted!"); return ERROR_FAIL; } LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step); @@ -4786,11 +4807,12 @@ static int riscv013_step_or_resume_current_hart(struct target *target, if (riscv_flush_registers(target) != ERROR_OK) return ERROR_FAIL; + dm013_info_t *dm = get_dm(target); /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; if (use_hasel) dmcontrol |= DM_DMCONTROL_HASEL; - dmcontrol = set_hartsel(dmcontrol, r->current_hartid); + dmcontrol = set_hartsel(dmcontrol, dm->current_hartid); dmi_write(target, DM_DMCONTROL, dmcontrol); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index d7b5f4805..4a1145bb6 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1155,11 +1155,6 @@ static int old_or_new_riscv_poll(struct target *target) return riscv_openocd_poll(target); } -int riscv_select_current_hart(struct target *target) -{ - return riscv_set_current_hartid(target, target->coreid); -} - int riscv_flush_registers(struct target *target) { RISCV_INFO(r); @@ -1228,14 +1223,11 @@ int halt_prep(struct target *target) LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target), target->debug_reason); - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; if (riscv_is_halted(target)) { LOG_DEBUG("[%s] Hart is already halted (debug_reason=%d).", target_name(target), target->debug_reason); if (target->debug_reason == DBG_REASON_NOTHALTED) { - enum riscv_halt_reason halt_reason = - riscv_halt_reason(target, r->current_hartid); + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); if (set_debug_reason(target, halt_reason) != ERROR_OK) return ERROR_FAIL; } @@ -1252,8 +1244,6 @@ int riscv_halt_go_all_harts(struct target *target) { RISCV_INFO(r); - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; if (riscv_is_halted(target)) { LOG_DEBUG("[%s] Hart is already halted.", target_name(target)); } else { @@ -1464,8 +1454,6 @@ static int resume_prep(struct target *target, int current, } if (r->is_halted) { - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; if (r->resume_prep(target) != ERROR_OK) return ERROR_FAIL; } @@ -1738,8 +1726,6 @@ static int riscv_read_phys_memory(struct target *target, target_addr_t phys_addr uint32_t size, uint32_t count, uint8_t *buffer) { RISCV_INFO(r); - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; return r->read_memory(target, phys_address, size, count, buffer, size); } @@ -1751,9 +1737,6 @@ static int riscv_read_memory(struct target *target, target_addr_t address, return ERROR_OK; } - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; - target_addr_t physical_addr; if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) address = physical_addr; @@ -1765,8 +1748,6 @@ static int riscv_read_memory(struct target *target, target_addr_t address, static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; struct target_type *tt = get_target_type(target); return tt->write_memory(target, phys_address, size, count, buffer); } @@ -1779,9 +1760,6 @@ static int riscv_write_memory(struct target *target, target_addr_t address, return ERROR_OK; } - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; - target_addr_t physical_addr; if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) address = physical_addr; @@ -1813,9 +1791,6 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, return ERROR_FAIL; } - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; - switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = 33; @@ -1971,9 +1946,9 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return result; } - /* The current hart id might have been changed in poll(). */ - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; + /* TODO: The current hart id might have been changed in poll(). */ + /* if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; */ if (reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; @@ -2113,8 +2088,6 @@ enum riscv_poll_hart { static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) { RISCV_INFO(r); - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) - return RPH_ERROR; LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state); @@ -2194,7 +2167,6 @@ int sample_memory(struct target *target) int riscv_openocd_poll(struct target *target) { LOG_DEBUG("polling all harts"); - int halted_hart = -1; enum target_state old_state = target->state; if (target->smp) { @@ -2205,8 +2177,7 @@ int riscv_openocd_poll(struct target *target) struct target *t = list->target; if (!target_was_examined(t)) continue; - riscv_info_t *r = riscv_info(t); - enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); + enum riscv_poll_hart out = riscv_poll_hart(t, t->coreid); switch (out) { case RPH_NO_CHANGE: break; @@ -2217,7 +2188,7 @@ int riscv_openocd_poll(struct target *target) case RPH_DISCOVERED_HALTED: t->state = TARGET_HALTED; enum riscv_halt_reason halt_reason = - riscv_halt_reason(t, r->current_hartid); + riscv_halt_reason(t); if (set_debug_reason(t, halt_reason) != ERROR_OK) return ERROR_FAIL; @@ -2273,8 +2244,7 @@ int riscv_openocd_poll(struct target *target) return ERROR_OK; } else { - enum riscv_poll_hart out = riscv_poll_hart(target, - riscv_current_hartid(target)); + enum riscv_poll_hart out = riscv_poll_hart(target, target->coreid); if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) { if (target->state == TARGET_RUNNING) sample_memory(target); @@ -2283,10 +2253,10 @@ int riscv_openocd_poll(struct target *target) return ERROR_FAIL; } - halted_hart = riscv_current_hartid(target); - LOG_DEBUG(" hart %d halted", halted_hart); + LOG_TARGET_DEBUG(target, "hart halted"); - enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart); + target->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); if (set_debug_reason(target, halt_reason) != ERROR_OK) return ERROR_FAIL; target->state = TARGET_HALTED; @@ -3516,7 +3486,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r) { memset(r, 0, sizeof(*r)); r->dtm_version = 1; - r->current_hartid = target->coreid; r->version_specific = NULL; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); @@ -3542,8 +3511,6 @@ static int riscv_resume_go_all_harts(struct target *target) RISCV_INFO(r); LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state); - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; if (riscv_is_halted(target)) { if (r->resume_go(target) != ERROR_OK) return ERROR_FAIL; @@ -3605,8 +3572,6 @@ int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; LOG_DEBUG("[%s] stepping", target_name(target)); if (!riscv_is_halted(target)) { @@ -3643,21 +3608,6 @@ unsigned riscv_xlen(const struct target *target) return r->xlen; } -int riscv_set_current_hartid(struct target *target, int hartid) -{ - RISCV_INFO(r); - if (!r->select_current_hart) - return ERROR_OK; - - int previous_hartid = riscv_current_hartid(target); - r->current_hartid = hartid; - LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid); - if (r->select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - void riscv_invalidate_register_cache(struct target *target) { /* Do not invalidate the register cache if it is not yet set up @@ -3673,13 +3623,8 @@ void riscv_invalidate_register_cache(struct target *target) } } -int riscv_current_hartid(const struct target *target) -{ - RISCV_INFO(r); - return r->current_hartid; -} -int riscv_count_harts(struct target *target) +unsigned int riscv_count_harts(struct target *target) { if (!target) return 1; @@ -3846,12 +3791,10 @@ bool riscv_is_halted(struct target *target) return r->is_halted(target); } -enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) +enum riscv_halt_reason riscv_halt_reason(struct target *target) { RISCV_INFO(r); - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) - return RISCV_HALT_ERROR; - if (!riscv_is_halted(target)) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Hart is not halted!"); return RISCV_HALT_UNKNOWN; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 898d8b5c0..74eff7007 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -99,12 +99,6 @@ typedef struct { struct command_context *cmd_ctx; void *version_specific; - /* The hart that is currently being debugged. Note that this is - * different than the hartid that the RTOS is expected to use. This - * one will change all the time, it's more of a global argument to - * every function than an actual */ - int current_hartid; - /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ char *reg_names; @@ -154,7 +148,7 @@ typedef struct { int (*get_register_buf)(struct target *target, uint8_t *buf, int regno); int (*set_register_buf)(struct target *target, int regno, const uint8_t *buf); - int (*select_current_hart)(struct target *target); + int (*select_target)(struct target *target); bool (*is_halted)(struct target *target); /* Resume this target, as well as every other prepped target that can be * resumed near-simultaneously. Clear the prepped flag on any target that @@ -354,7 +348,7 @@ int riscv_current_hartid(const struct target *target); /* Lists the number of harts in the system, which are assumed to be * consecutive and start with mhartid=0. */ -int riscv_count_harts(struct target *target); +unsigned int riscv_count_harts(struct target *target); /** Set register, updating the cache. */ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); @@ -370,7 +364,7 @@ int riscv_flush_registers(struct target *target); /* Checks the state of the current hart -- "is_halted" checks the actual * on-device register. */ bool riscv_is_halted(struct target *target); -enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); +enum riscv_halt_reason riscv_halt_reason(struct target *target); /* These helper functions let the generic program interface get target-specific * information. */ From b70ccf297fcaa6aae6e12460f8cbf4a477b34197 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 30 Sep 2022 11:25:55 +0200 Subject: [PATCH 167/186] OScan1 code cleanup - change OSCAN1 to OScan1 - fix spacing --- configure.ac | 2 +- src/jtag/drivers/ftdi.c | 236 ++++++++++++++++++++-------------------- 2 files changed, 119 insertions(+), 119 deletions(-) diff --git a/configure.ac b/configure.ac index 3245eccc4..340e59d7f 100644 --- a/configure.ac +++ b/configure.ac @@ -110,7 +110,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], - [[ftdi_oscan1], [cJTAG OSCAN1 tunneled thru MPSSE], [FTDI_OSCAN1]], + [[ftdi_oscan1], [cJTAG OScan1 tunneled thru MPSSE], [FTDI_OSCAN1]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 9eb199487..3cd67c71c 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -107,16 +107,16 @@ static bool swd_mode; #if BUILD_FTDI_OSCAN1 == 1 /* - The cJTAG 2-wire OSCAN1 protocol, in lieu of 4-wire JTAG, is a configuration option + The cJTAG 2-wire OScan1 protocol, in lieu of 4-wire JTAG, is a configuration option for some SoCs. An FTDI-based adapter that can be configured to appropriately drive - the bidirectional pin TMSC is able to drive OSCAN1 protocol. For example, an Olimex + the bidirectional pin TMSC is able to drive OScan1 protocol. For example, an Olimex ARM-USB-TINY-H with the ARM-JTAG-SWD adapter, connected to a cJTAG-enabled target board is such a topology. A TCK cycle with TMS=1/TDI=N translates to a TMSC output of N, and a TCK cycle with TMS=0 translates to a TMSC input from the target back - to the adapter/probe. The OSCAN1 protocol uses 3 TCK cycles to generate the data flow - that is equivalent to that of a single TCK cycle in 4-wire JTAG. The OSCAN1-related + to the adapter/probe. The OScan1 protocol uses 3 TCK cycles to generate the data flow + that is equivalent to that of a single TCK cycle in 4-wire JTAG. The OScan1-related code in this module translates IR/DR scan commanads and JTAG state traversal commands - to the two-wire clocking and signaling of OSCAN1 protocol, if placed into oscan1 mode + to the two-wire clocking and signaling of OScan1 protocol, if placed into OScan1 mode during initialization. */ static void oscan1_reset_online_activate(void); @@ -670,7 +670,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) switch (cmd->type) { case JTAG_RESET: #if BUILD_FTDI_OSCAN1 == 1 - oscan1_reset_online_activate(); /* put the target back into OSCAN1 mode */ + oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ #endif break; case JTAG_RUNTEST: @@ -679,7 +679,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) case JTAG_TLR_RESET: ftdi_execute_statemove(cmd); #if BUILD_FTDI_OSCAN1 == 1 - oscan1_reset_online_activate(); /* put the target back into OSCAN1 mode */ + oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ #endif break; case JTAG_PATHMOVE: @@ -763,7 +763,7 @@ static int ftdi_initialize(void) } else if (oscan1_mode) { struct signal *sig = find_signal_by_name("JTAG_SEL"); if (!sig) { - LOG_ERROR("OSCAN1 mode is active but JTAG_SEL signal is not defined"); + LOG_ERROR("OScan1 mode is active but JTAG_SEL signal is not defined"); return ERROR_JTAG_INIT_FAILED; } /* A dummy JTAG_SEL would have zero mask */ @@ -816,7 +816,7 @@ static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, u int bitnum; uint8_t bit; - /* OSCAN1 uses 3 separate clocks */ + /* OScan1 uses 3 separate clocks */ /* drive TMSC to the *negation* of the desired TDI value */ bitnum = out_offset + i; @@ -862,7 +862,7 @@ static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, uint8_t tmsbit; uint8_t tdibit; - /* OSCAN1 uses 3 separate clocks */ + /* OScan1 uses 3 separate clocks */ /* drive TMSC to the *negation* of the desired TDI value */ tdibit = tdi ? 0 : 1; @@ -921,114 +921,114 @@ static void oscan1_reset_online_activate(void) uint16_t tdovalue; static const struct { - int8_t tck; - int8_t tms; - int8_t tdi; + int8_t tck; + int8_t tms; + int8_t tdi; } sequence[] = { - /* TCK=0, TMS=1, TDI=0 (drive TMSC to 0 baseline) */ - {'0', '1', '0'}, - - /* Drive cJTAG escape sequence for TAP reset - 8 TMSC edges */ - /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */ - {'0', '1', '0'}, - - /* 3 TCK pulses for padding */ - /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ - {'0', '1', '0'}, - - /* Drive cJTAG escape sequence for SELECT */ - /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0, TAP reset that was just setup occurs here too) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ - {'1', '1', '1'}, - /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */ - {'0', '1', '0'}, - - /* Drive cJTAG escape sequence for activation */ - /* TCK=1, TMS=1, TDI=0 (rising edge TCK with TMSC still 0... online mode activated... also OAC bit0==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... OAC bit1==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */ - {'0', '1', '1'}, - /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit2==1) */ - {'1', '1', '1'}, - /* TCK=0, TMS=1, TDI=1 (falling edge TCK, TMSC stays high) */ - {'0', '1', '1'}, - /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit3==1) */ - {'1', '1', '1'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit0==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit1==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit2==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */ - {'0', '1', '1'}, - /* TCK=1, TMS=1, TDI=1 (rising edge TCK... EC bit3==1) */ - {'1', '1', '1'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit0==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit1==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit2==0) */ - {'1', '1', '0'}, - /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ - {'0', '1', '0'}, - /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit3==0) */ - {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (drive TMSC to 0 baseline) */ + {'0', '1', '0'}, + + /* Drive cJTAG escape sequence for TAP reset - 8 TMSC edges */ + /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */ + {'0', '1', '0'}, + + /* 3 TCK pulses for padding */ + /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */ + {'0', '1', '0'}, + + /* Drive cJTAG escape sequence for SELECT */ + /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0, TAP reset that was just setup occurs here too) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */ + {'1', '1', '1'}, + /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */ + {'0', '1', '0'}, + + /* Drive cJTAG escape sequence for activation */ + /* TCK=1, TMS=1, TDI=0 (rising edge TCK with TMSC still 0... online mode activated... also OAC bit0==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... OAC bit1==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */ + {'0', '1', '1'}, + /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit2==1) */ + {'1', '1', '1'}, + /* TCK=0, TMS=1, TDI=1 (falling edge TCK, TMSC stays high) */ + {'0', '1', '1'}, + /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit3==1) */ + {'1', '1', '1'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit0==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit1==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit2==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */ + {'0', '1', '1'}, + /* TCK=1, TMS=1, TDI=1 (rising edge TCK... EC bit3==1) */ + {'1', '1', '1'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit0==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit1==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit2==0) */ + {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, + /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit3==0) */ + {'1', '1', '0'}, }; @@ -1356,7 +1356,7 @@ static const struct command_registration ftdi_subcommand_handlers[] = { .name = "oscan1_mode", .handler = &ftdi_handle_oscan1_mode_command, .mode = COMMAND_ANY, - .help = "set to 'on' to use OSCAN1 mode for signaling, otherwise 'off' (default is 'off')", + .help = "set to 'on' to use OScan1 mode for signaling, otherwise 'off' (default is 'off')", .usage = "(on|off)", }, #endif From f61098c2258c2ca81fd7c0ed943c36f6a82c5d49 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 30 Sep 2022 11:27:22 +0200 Subject: [PATCH 168/186] Rename ftdi_oscan1 to ftdi_cjtag --- .github/workflows/linux-build.yml | 2 +- configure.ac | 2 +- src/jtag/drivers/ftdi.c | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 9664ca68d..f566d8c90 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -37,7 +37,7 @@ jobs: sudo apt-get update sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev - run: ./bootstrap - - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-oscan1 + - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag - run: make -j`nproc` - run: file src/openocd | grep 64-bit - run: src/openocd --version diff --git a/configure.ac b/configure.ac index 340e59d7f..adf601f13 100644 --- a/configure.ac +++ b/configure.ac @@ -110,7 +110,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], - [[ftdi_oscan1], [cJTAG OScan1 tunneled thru MPSSE], [FTDI_OSCAN1]], + [[ftdi_cjtag], [cJTAG (OScan1) tunneled thru MPSSE], [FTDI_CJTAG]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 3cd67c71c..1025b95fc 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -85,7 +85,7 @@ /* FTDI access library includes */ #include "mpsse.h" -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 #define DO_CLOCK_DATA clock_data #define DO_CLOCK_TMS_CS clock_tms_cs #define DO_CLOCK_TMS_CS_OUT clock_tms_cs_out @@ -105,7 +105,7 @@ static uint8_t ftdi_jtag_mode = JTAG_MODE; static bool swd_mode; -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 /* The cJTAG 2-wire OScan1 protocol, in lieu of 4-wire JTAG, is a configuration option for some SoCs. An FTDI-based adapter that can be configured to appropriately drive @@ -275,7 +275,7 @@ static int ftdi_get_signal(const struct signal *s, uint16_t *value_out) return ERROR_OK; } -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 static void clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { @@ -669,7 +669,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_RESET: -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ #endif break; @@ -678,7 +678,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) break; case JTAG_TLR_RESET: ftdi_execute_statemove(cmd); -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ #endif break; @@ -759,7 +759,7 @@ static int ftdi_initialize(void) /* A dummy SWD_EN would have zero mask */ if (sig->data_mask) ftdi_set_signal(sig, '1'); -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 } else if (oscan1_mode) { struct signal *sig = find_signal_by_name("JTAG_SEL"); if (!sig) { @@ -801,7 +801,7 @@ static int ftdi_quit(void) return ERROR_OK; } -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { @@ -900,7 +900,7 @@ static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t * } -static void oscan1_set_tck_tms_tdi(struct signal *tck, char tckvalue, struct signal *tms, +static void cjtag_set_tck_tms_tdi(struct signal *tck, char tckvalue, struct signal *tms, char tmsvalue, struct signal *tdi, char tdivalue) { ftdi_set_signal(tms, tmsvalue); @@ -1058,12 +1058,12 @@ static void oscan1_reset_online_activate(void) /* Send the sequence to the adapter */ for (size_t i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++) - oscan1_set_tck_tms_tdi(tck, sequence[i].tck, tms, sequence[i].tms, tdi, sequence[i].tdi); + cjtag_set_tck_tms_tdi(tck, sequence[i].tck, tms, sequence[i].tms, tdi, sequence[i].tdi); ftdi_get_signal(tdo, &tdovalue); /* Just to force a flush */ } -#endif /* #if BUILD_FTDI_OSCAN1 == 1 */ +#endif /* #if BUILD_FTDI_CJTAG == 1 */ COMMAND_HANDLER(ftdi_handle_device_desc_command) { @@ -1276,7 +1276,7 @@ COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) return ERROR_OK; } -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 COMMAND_HANDLER(ftdi_handle_oscan1_mode_command) { if (CMD_ARGC > 1) @@ -1351,7 +1351,7 @@ static const struct command_registration ftdi_subcommand_handlers[] = { "allow signalling speed increase)", .usage = "(rising|falling)", }, -#if BUILD_FTDI_OSCAN1 == 1 +#if BUILD_FTDI_CJTAG == 1 { .name = "oscan1_mode", .handler = &ftdi_handle_oscan1_mode_command, From bd5649dfbe10a79f72bee2ee48cf24c10de7b5d8 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 30 Sep 2022 11:53:35 +0200 Subject: [PATCH 169/186] Support cJTAG JScan3 mode --- configure.ac | 2 +- doc/openocd.texi | 9 ++++++ src/jtag/drivers/ftdi.c | 72 +++++++++++++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index adf601f13..081e7744d 100644 --- a/configure.ac +++ b/configure.ac @@ -110,7 +110,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], - [[ftdi_cjtag], [cJTAG (OScan1) tunneled thru MPSSE], [FTDI_CJTAG]], + [[ftdi_cjtag], [cJTAG (OScan1, JScan3) tunneled thru MPSSE], [FTDI_CJTAG]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], diff --git a/doc/openocd.texi b/doc/openocd.texi index 6aa1c49ed..e671b80b5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2602,6 +2602,15 @@ probes by defining the signal TMSC_EN using @command{ftdi layout_signal TMSC_EN -data }. @end deffn +@deffn {Command} {ftdi jscan3_mode} on|off +Enable or disable JScan3 mode. This mode uses the classic 4-wire JTAG protocol +in chips whose JTAG port is only compliant with the cJTAG standard (IEEE 1149.7). + +Since cJTAG needs a 2-wire escape sequence to select the operating mode, +a cJTAG adapter like ARM-JTAG-SWD by Olimex is still required. This means +that a cJTAG probe configuration script must be used too. +@end deffn + @deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] Creates a signal with the specified @var{name}, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 1025b95fc..d1ee9327b 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -106,6 +106,10 @@ static uint8_t ftdi_jtag_mode = JTAG_MODE; static bool swd_mode; #if BUILD_FTDI_CJTAG == 1 +#define ESCAPE_SEQ_OAC_BIT2 28 + +static void cjtag_reset_online_activate(void); + /* The cJTAG 2-wire OScan1 protocol, in lieu of 4-wire JTAG, is a configuration option for some SoCs. An FTDI-based adapter that can be configured to appropriately drive @@ -119,7 +123,6 @@ static bool swd_mode; to the two-wire clocking and signaling of OScan1 protocol, if placed into OScan1 mode during initialization. */ -static void oscan1_reset_online_activate(void); static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode); static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, @@ -128,6 +131,11 @@ static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t * unsigned length, bool tdi, uint8_t mode); static bool oscan1_mode; + +/* + The cJTAG 4-wire JScan3 allows to use standard JTAG protocol with cJTAG hardware +*/ +static bool jscan3_mode; #endif #define MAX_USB_IDS 8 @@ -670,7 +678,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) switch (cmd->type) { case JTAG_RESET: #if BUILD_FTDI_CJTAG == 1 - oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ + cjtag_reset_online_activate(); /* put the target back into selected cJTAG mode */ #endif break; case JTAG_RUNTEST: @@ -679,7 +687,7 @@ static void ftdi_execute_command(struct jtag_command *cmd) case JTAG_TLR_RESET: ftdi_execute_statemove(cmd); #if BUILD_FTDI_CJTAG == 1 - oscan1_reset_online_activate(); /* put the target back into OScan1 mode */ + cjtag_reset_online_activate(); /* put the target back into selected cJTAG mode */ #endif break; case JTAG_PATHMOVE: @@ -760,15 +768,19 @@ static int ftdi_initialize(void) if (sig->data_mask) ftdi_set_signal(sig, '1'); #if BUILD_FTDI_CJTAG == 1 - } else if (oscan1_mode) { + } else if (oscan1_mode || jscan3_mode) { struct signal *sig = find_signal_by_name("JTAG_SEL"); if (!sig) { - LOG_ERROR("OScan1 mode is active but JTAG_SEL signal is not defined"); + LOG_ERROR("A cJTAG mode is active but JTAG_SEL signal is not defined"); return ERROR_JTAG_INIT_FAILED; } /* A dummy JTAG_SEL would have zero mask */ if (sig->data_mask) ftdi_set_signal(sig, '0'); + else if (jscan3_mode) { + LOG_ERROR("In JScan3 mode JTAG_SEL signal cannot be dummy, data mask needed"); + return ERROR_JTAG_INIT_FAILED; + } #endif } @@ -908,11 +920,11 @@ static void cjtag_set_tck_tms_tdi(struct signal *tck, char tckvalue, struct sign ftdi_set_signal(tck, tckvalue); } -static void oscan1_reset_online_activate(void) +static void cjtag_reset_online_activate(void) { - /* After TAP reset, the OSCAN1-to-JTAG adapter is in offline and - non-activated state. Escape sequences are needed to bring - the TAP online and activated into OSCAN1 mode. */ + /* After TAP reset, the cJTAG-to-JTAG adapter is in offline and + non-activated state. Escape sequences are needed to bring the + TAP online and activated into the desired working mode. */ struct signal *tck = find_signal_by_name("TCK"); struct signal *tdi = find_signal_by_name("TDI"); @@ -920,7 +932,7 @@ static void oscan1_reset_online_activate(void) struct signal *tdo = find_signal_by_name("TDO"); uint16_t tdovalue; - static const struct { + static struct { int8_t tck; int8_t tms; int8_t tdi; @@ -982,7 +994,7 @@ static void oscan1_reset_online_activate(void) /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */ {'0', '1', '0'}, - /* Drive cJTAG escape sequence for activation */ + /* Drive cJTAG escape sequence for OScan1 activation -- OAC = 1100 -> 2 wires -- */ /* TCK=1, TMS=1, TDI=0 (rising edge TCK with TMSC still 0... online mode activated... also OAC bit0==0) */ {'1', '1', '0'}, /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ @@ -1029,12 +1041,17 @@ static void oscan1_reset_online_activate(void) {'0', '1', '0'}, /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit3==0) */ {'1', '1', '0'}, + /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */ + {'0', '1', '0'}, }; + if (!oscan1_mode && !jscan3_mode) + return; /* Nothing to do */ - if (!oscan1_mode) + if (oscan1_mode && jscan3_mode) { + LOG_ERROR("Both oscan1_mode and jscan3_mode are \"on\". At most one of them can be enabled."); return; - + } if (!tck) { LOG_ERROR("Can't run cJTAG online/activate escape sequences: TCK signal is not defined"); @@ -1056,10 +1073,20 @@ static void oscan1_reset_online_activate(void) return; } + if (jscan3_mode) { + /* Update the sequence above to enable JScan3 instead of OScan1 */ + sequence[ESCAPE_SEQ_OAC_BIT2].tdi = '0'; + sequence[ESCAPE_SEQ_OAC_BIT2+1].tdi = '0'; + } + /* Send the sequence to the adapter */ for (size_t i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++) cjtag_set_tck_tms_tdi(tck, sequence[i].tck, tms, sequence[i].tms, tdi, sequence[i].tdi); + /* If JScan3 mode, configure cJTAG adapter to 4-wire */ + if (jscan3_mode) + ftdi_set_signal(find_signal_by_name("JTAG_SEL"), '1'); + ftdi_get_signal(tdo, &tdovalue); /* Just to force a flush */ } @@ -1288,6 +1315,18 @@ COMMAND_HANDLER(ftdi_handle_oscan1_mode_command) command_print(CMD, "oscan1 mode: %s.", oscan1_mode ? "on" : "off"); return ERROR_OK; } + +COMMAND_HANDLER(ftdi_handle_jscan3_mode_command) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1) + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], jscan3_mode); + + command_print(CMD, "jscan3 mode: %s.", jscan3_mode ? "on" : "off"); + return ERROR_OK; +} #endif static const struct command_registration ftdi_subcommand_handlers[] = { @@ -1359,6 +1398,13 @@ static const struct command_registration ftdi_subcommand_handlers[] = { .help = "set to 'on' to use OScan1 mode for signaling, otherwise 'off' (default is 'off')", .usage = "(on|off)", }, + { + .name = "jscan3_mode", + .handler = &ftdi_handle_jscan3_mode_command, + .mode = COMMAND_ANY, + .help = "set to 'on' to use JScan3 mode for signaling, otherwise 'off' (default is 'off')", + .usage = "(on|off)", + }, #endif COMMAND_REGISTRATION_DONE }; From 088a3596a034a1bbe1e07483914d94fa0cad6ea0 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 30 Sep 2022 11:54:11 +0200 Subject: [PATCH 170/186] Use TMSC_EN signal for cJTAG escape seq if defined Signed-off-by: mrv96 --- src/jtag/drivers/ftdi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index d1ee9327b..895c55def 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -930,6 +930,7 @@ static void cjtag_reset_online_activate(void) struct signal *tdi = find_signal_by_name("TDI"); struct signal *tms = find_signal_by_name("TMS"); struct signal *tdo = find_signal_by_name("TDO"); + struct signal *tmsc_en = find_signal_by_name("TMSC_EN"); uint16_t tdovalue; static struct { @@ -1079,6 +1080,10 @@ static void cjtag_reset_online_activate(void) sequence[ESCAPE_SEQ_OAC_BIT2+1].tdi = '0'; } + /* if defined TMSC_EN, replace tms with it */ + if (tmsc_en) + tms = tmsc_en; + /* Send the sequence to the adapter */ for (size_t i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++) cjtag_set_tck_tms_tdi(tck, sequence[i].tck, tms, sequence[i].tms, tdi, sequence[i].tdi); From 0f12a0100757378099f0ec0678ed1d222fadbc76 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 4 Oct 2022 15:31:09 -0700 Subject: [PATCH 171/186] riscv: Minor formatting cleanup. Change-Id: I0256fd047d8369ca7b327172225a9d1f827673c5 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 494eeaa20..6a96e927d 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2467,15 +2467,13 @@ static int execute_fence(struct target *target) /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ - { - struct riscv_program program; - riscv_program_init(&program, target); - riscv_program_fence_i(&program); - riscv_program_fence(&program); - int result = riscv_program_exec(&program, target); - if (result != ERROR_OK) - LOG_DEBUG("Unable to execute pre-fence"); - } + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_fence_i(&program); + riscv_program_fence(&program); + int result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + LOG_TARGET_DEBUG(target, "Unable to execute pre-fence"); return ERROR_OK; } From 342ca4a8326ee3e4d3edaae45a228e8b4219b45e Mon Sep 17 00:00:00 2001 From: mrv96 Date: Wed, 5 Oct 2022 17:49:26 +0200 Subject: [PATCH 172/186] Fix Digilent JTAG-HS2 cJTAG configuration script Signed-off-by: mrv96 --- tcl/interface/ftdi/digilent-hs2-cjtag.cfg | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tcl/interface/ftdi/digilent-hs2-cjtag.cfg b/tcl/interface/ftdi/digilent-hs2-cjtag.cfg index 067f66465..3daf46185 100644 --- a/tcl/interface/ftdi/digilent-hs2-cjtag.cfg +++ b/tcl/interface/ftdi/digilent-hs2-cjtag.cfg @@ -1,11 +1,9 @@ -# this supports JTAG-HS2 (and apparently Nexys4 as well) - adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 -ftdi layout_init 0xc0e8 0xe0eb +ftdi layout_init 0x60e8 0x60eb reset_config none @@ -14,6 +12,6 @@ ftdi layout_signal TCK -data 0x0001 ftdi layout_signal TDI -data 0x0002 ftdi layout_signal TDO -input 0x0004 ftdi layout_signal TMS -data 0x0008 -ftdi layout_signal JTAG_SEL -ndata 0xc000 +ftdi layout_signal JTAG_SEL -ndata 0x6000 -oe 0x6000 -ftdi layout_signal TMSC_EN -data 0x0020 +ftdi layout_signal TMSC_EN -data 0x0020 -oe 0x0020 From 01ae0f2122b4754693fb30e9510c62aad787056f Mon Sep 17 00:00:00 2001 From: Dmitry Ryzhov Date: Fri, 7 Oct 2022 16:34:59 +0300 Subject: [PATCH 173/186] Fix incorrect braces caused by #732 --- src/target/riscv/riscv-013.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6a96e927d..9febdd9f8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1340,11 +1340,11 @@ static int register_write_direct(struct target *target, unsigned number, if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (riscv_supports_extension(target, 'D')) { if (riscv_program_insert(&program, - fmv_d_x(number - GDB_REGNO_FPR0, S0) != ERROR_OK)) + fmv_d_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) return ERROR_FAIL; } else { if (riscv_program_insert(&program, - fmv_w_x(number - GDB_REGNO_FPR0, S0) != ERROR_OK)) + fmv_w_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) return ERROR_FAIL; } } else if (number == GDB_REGNO_VTYPE) { From 29983fd98dcc9a8e3d89b086537345b72b9fc1a3 Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 7 Oct 2022 14:50:03 +0200 Subject: [PATCH 174/186] (Re)Init cJTAG only after trst (not after srst) --- src/jtag/drivers/ftdi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 895c55def..97f810424 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -676,18 +676,19 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd) static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_RESET: #if BUILD_FTDI_CJTAG == 1 - cjtag_reset_online_activate(); /* put the target back into selected cJTAG mode */ -#endif + case JTAG_RESET: + if (cmd->cmd.reset->trst) + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ break; +#endif case JTAG_RUNTEST: ftdi_execute_runtest(cmd); break; case JTAG_TLR_RESET: ftdi_execute_statemove(cmd); #if BUILD_FTDI_CJTAG == 1 - cjtag_reset_online_activate(); /* put the target back into selected cJTAG mode */ + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ #endif break; case JTAG_PATHMOVE: From 0c6121d92abdf1e602f1a944873b7c9b62aa8c8c Mon Sep 17 00:00:00 2001 From: mrv96 Date: Fri, 7 Oct 2022 16:07:33 +0200 Subject: [PATCH 175/186] (Re)Init cJTAG before move JTAG to reset state Signed-off-by: mrv96 --- src/jtag/drivers/ftdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 97f810424..16cb0274b 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -686,10 +686,10 @@ static void ftdi_execute_command(struct jtag_command *cmd) ftdi_execute_runtest(cmd); break; case JTAG_TLR_RESET: - ftdi_execute_statemove(cmd); #if BUILD_FTDI_CJTAG == 1 cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ #endif + ftdi_execute_statemove(cmd); break; case JTAG_PATHMOVE: ftdi_execute_pathmove(cmd); From 4270857a76ccc5b840bf229ccb972e5d57b030b6 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 6 Oct 2022 10:45:05 -0700 Subject: [PATCH 176/186] target/riscv: Clean up halt_go for multiple harts. Also add an early exit for if any harts are unavailable. Change-Id: I0875d4d213c9faf87b219d8d57e440881366c8f8 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9febdd9f8..19fe2ada8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -4208,14 +4208,19 @@ static int riscv013_halt_go(struct target *target) dmcontrol |= DM_DMCONTROL_HASEL; dmcontrol = set_hartsel(dmcontrol, info->index); dmi_write(target, DM_DMCONTROL, dmcontrol); - for (size_t i = 0; i < 256; ++i) - if (riscv_is_halted(target)) - break; - - if (!riscv_is_halted(target)) { - uint32_t dmstatus; + uint32_t dmstatus; + for (size_t i = 0; i < 256; ++i) { if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; + /* When no harts are running, there's no point in continuing this loop. */ + if (!get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) + break; + } + + /* We declare success if no harts are running. One or more of them may be + * unavailable, though. */ + + if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) { if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; From bed28d5ec7c8cbc8ff22d059d954d20802df152b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 5 Oct 2022 11:51:00 -0700 Subject: [PATCH 177/186] filter_openocd: Prefer high repetitions. I'd rather see "these 10 lines were repeated 100 times" than "these 100 lines were repeated 10 times." Change-Id: I88fcf86b10c5fb0ba1d19b21fe054065da90fedd Signed-off-by: Tim Newsome --- tools/filter_openocd_log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/filter_openocd_log.py b/tools/filter_openocd_log.py index 076be20db..666e166dd 100755 --- a/tools/filter_openocd_log.py +++ b/tools/filter_openocd_log.py @@ -50,7 +50,7 @@ def shorten_buffer(outfd, buf, current_repetition): repetitions.append((matched_lines + length, length)) if repetitions: - repetitions.sort(key=lambda entry: (entry[0] * (entry[1] / entry[0]), -entry[1])) + repetitions.sort(key=lambda entry: -entry[1]) matched_lines, length = repetitions[-1] repeated = int(matched_lines / length) if repeated * length >= 3: From a50b280558cc2908f43dba600461aca256bfbf10 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 12 Oct 2022 08:57:00 -0700 Subject: [PATCH 178/186] Properly track selecting multiple harts at once. (#743) * Properly track selecting multiple harts at once. use_hasel is a bit of a hack. Change-Id: Ia589ebc16bca32038d915df9988361b88e940917 Signed-off-by: Tim Newsome * Clarifying comment. Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome * Rename set_hartsel to set_dmcontrol_hartsel Change-Id: Iab28531281aa6fc604ec7d34974ed444ea9ea850 * Make set_dmcontrol_hartsel() more idiomatic. Change-Id: I56a885043c515359e33b9c8a03aed637c81d1486 * Use constant for multiple harts instead of -1. Change-Id: Iefeaf74202f2b4918d21f15f7ff7ca514175b8fb Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> --- src/target/riscv/riscv-013.c | 123 ++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 19fe2ada8..bc5b262ca 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,7 +31,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step); static int riscv013_step_or_resume_current_hart(struct target *target, - bool step, bool use_hasel); + bool step); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ @@ -129,6 +129,8 @@ typedef enum { YNM_NO } yes_no_maybe_t; +#define HART_INDEX_MULTIPLE -1 + typedef struct { struct list_head list; int abs_chain_position; @@ -140,9 +142,7 @@ typedef struct { /* Targets that are connected to this DM. */ struct list_head target_list; /* Contains the ID of the hart that is currently selected by this DM. - * (If multiple harts are selected this is meaningless, and that corner case - * is not currently handled well.) - */ + * If multiple harts are selected this is HART_INDEX_MULTIPLE. */ int current_hartid; bool hasel_supported; @@ -216,6 +216,9 @@ typedef struct { /* DM that provides access to this target. */ dm013_info_t *dm; + + /* This target was selected using hasel. */ + bool selected; } riscv013_info_t; LIST_HEAD(dm_list); @@ -256,7 +259,7 @@ dm013_info_t *get_dm(struct target *target) if (!dm) return NULL; dm->abs_chain_position = abs_chain_position; - dm->current_hartid = -1; + dm->current_hartid = 0; dm->hart_count = -1; INIT_LIST_HEAD(&dm->target_list); list_add(&dm->list, &dm_list); @@ -279,16 +282,21 @@ dm013_info_t *get_dm(struct target *target) return dm; } -static uint32_t set_hartsel(uint32_t initial, uint32_t index) +static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) { - initial &= ~DM_DMCONTROL_HARTSELLO; - initial &= ~DM_DMCONTROL_HARTSELHI; - - uint32_t index_lo = index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); - initial |= index_lo << DM_DMCONTROL_HARTSELLO_OFFSET; - uint32_t index_hi = index >> DM_DMCONTROL_HARTSELLO_LENGTH; - assert(index_hi < 1 << DM_DMCONTROL_HARTSELHI_LENGTH); - initial |= index_hi << DM_DMCONTROL_HARTSELHI_OFFSET; + if (hart_index >= 0) { + initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_SINGLE); + uint32_t index_lo = hart_index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); + initial = set_field(initial, DM_DMCONTROL_HARTSELLO, index_lo); + uint32_t index_hi = hart_index >> DM_DMCONTROL_HARTSELLO_LENGTH; + assert(index_hi < (1 << DM_DMCONTROL_HARTSELHI_LENGTH)); + initial = set_field(initial, DM_DMCONTROL_HARTSELHI, index_hi); + } else if (hart_index == HART_INDEX_MULTIPLE) { + initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_MULTIPLE); + /* TODO: https://github.com/riscv/riscv-openocd/issues/748 */ + initial = set_field(initial, DM_DMCONTROL_HARTSELLO, 0); + initial = set_field(initial, DM_DMCONTROL_HARTSELHI, 0); + } return initial; } @@ -1684,7 +1692,7 @@ static int examine(struct target *target) if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) dmi_write(target, DM_DMCONTROL, - set_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); + set_dmcontrol_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); } LOG_DEBUG("Detected %d harts.", dm->hart_count); @@ -1703,6 +1711,7 @@ static int examine(struct target *target) bool halted = riscv_is_halted(target); if (!halted) { + r->prepped = true; if (riscv013_halt_go(target) != ERROR_OK) { LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()", info->index); @@ -1761,7 +1770,7 @@ static int examine(struct target *target) } if (!halted) - riscv013_step_or_resume_current_hart(target, false, false); + riscv013_step_or_resume_current_hart(target, false); if (target->smp) { bool haltgroup_supported; @@ -2357,7 +2366,7 @@ static int assert_reset(struct target *target) /* Set haltreq for each hart. */ uint32_t control = control_base; - control = set_hartsel(control_base, info->index); + control = set_dmcontrol_hartsel(control_base, info->index); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DM_DMCONTROL, control); @@ -2368,7 +2377,7 @@ static int assert_reset(struct target *target) } else { /* Reset just this hart. */ - uint32_t control = set_hartsel(control_base, info->index); + uint32_t control = set_dmcontrol_hartsel(control_base, info->index); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_NDMRESET, 1); @@ -2398,7 +2407,7 @@ static int deassert_reset(struct target *target) uint32_t control = 0; control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); - dmi_write(target, DM_DMCONTROL, set_hartsel(control, info->index)); + dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index)); uint32_t dmstatus; int dmi_busy_delay = info->dmi_busy_delay; @@ -2410,7 +2419,7 @@ static int deassert_reset(struct target *target) if (index != info->index) continue; dmi_write(target, DM_DMCONTROL, - set_hartsel(control, index)); + set_dmcontrol_hartsel(control, index)); } else { index = info->index; } @@ -2449,7 +2458,7 @@ static int deassert_reset(struct target *target) if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { /* Ack reset. */ dmi_write(target, DM_DMCONTROL, - set_hartsel(control, index) | + set_dmcontrol_hartsel(control, index) | DM_DMCONTROL_ACKHAVERESET); } @@ -4122,7 +4131,7 @@ static int dm013_select_hart(struct target *target, int hart_index) return ERROR_OK; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; - dmcontrol = set_hartsel(dmcontrol, hart_index); + dmcontrol = set_dmcontrol_hartsel(dmcontrol, hart_index); if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { /* Who knows what the state is? */ dm->current_hartid = -2; @@ -4134,15 +4143,14 @@ static int dm013_select_hart(struct target *target, int hart_index) /* Select all harts that were prepped and that are selectable, clearing the * prepped flag on the harts that actually were selected. */ -static int select_prepped_harts(struct target *target, bool *use_hasel) +static int select_prepped_harts(struct target *target) { + RISCV_INFO(r); dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (!dm->hasel_supported) { - RISCV_INFO(r); r->prepped = false; - *use_hasel = false; dm013_select_target(target); return ERROR_OK; } @@ -4155,27 +4163,33 @@ static int select_prepped_harts(struct target *target, bool *use_hasel) target_list_t *entry; unsigned total_selected = 0; + unsigned int selected_index = 0; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; - riscv_info_t *r = riscv_info(t); - riscv013_info_t *info = get_info(t); - unsigned index = info->index; - LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped); - r->selected = r->prepped; - if (r->prepped) { + riscv_info_t *info = riscv_info(t); + riscv013_info_t *info_013 = get_info(t); + unsigned index = info_013->index; + LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, info->prepped); + if (info->prepped) { + info_013->selected = true; hawindow[index / 32] |= 1 << (index % 32); - r->prepped = false; + info->prepped = false; total_selected++; + selected_index = index; } - index++; } - /* Don't use hasel if we only need to talk to one hart. */ - if (total_selected <= 1) { - *use_hasel = false; - return ERROR_OK; + if (total_selected == 0) { + LOG_TARGET_ERROR(target, "No harts were prepped!"); + return ERROR_FAIL; + } else if (total_selected == 1) { + /* Don't use hasel if we only need to talk to one hart. */ + return dm013_select_hart(target, selected_index); } + if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) + return ERROR_FAIL; + for (unsigned i = 0; i < hawindow_count; i++) { if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) return ERROR_FAIL; @@ -4183,7 +4197,6 @@ static int select_prepped_harts(struct target *target, bool *use_hasel) return ERROR_FAIL; } - *use_hasel = true; return ERROR_OK; } @@ -4194,19 +4207,18 @@ static int riscv013_halt_prep(struct target *target) static int riscv013_halt_go(struct target *target) { - RISCV013_INFO(info); + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; - bool use_hasel = false; - if (select_prepped_harts(target, &use_hasel) != ERROR_OK) + if (select_prepped_harts(target) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "halting hart"); /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; - if (use_hasel) - dmcontrol |= DM_DMCONTROL_HASEL; - dmcontrol = set_hartsel(dmcontrol, info->index); + dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); dmi_write(target, DM_DMCONTROL, dmcontrol); uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { @@ -4232,11 +4244,8 @@ static int riscv013_halt_go(struct target *target) dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); dmi_write(target, DM_DMCONTROL, dmcontrol); - if (use_hasel) { + if (dm->current_hartid == HART_INDEX_MULTIPLE) { target_list_t *entry; - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; t->state = TARGET_HALTED; @@ -4251,16 +4260,15 @@ static int riscv013_halt_go(struct target *target) static int riscv013_resume_go(struct target *target) { - bool use_hasel = false; - if (select_prepped_harts(target, &use_hasel) != ERROR_OK) + if (select_prepped_harts(target) != ERROR_OK) return ERROR_FAIL; - return riscv013_step_or_resume_current_hart(target, false, use_hasel); + return riscv013_step_or_resume_current_hart(target, false); } static int riscv013_step_current_hart(struct target *target) { - return riscv013_step_or_resume_current_hart(target, true, false); + return riscv013_step_or_resume_current_hart(target, true); } static int riscv013_resume_prep(struct target *target) @@ -4296,7 +4304,7 @@ static bool riscv013_is_halted(struct target *target) /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; - dmcontrol = set_hartsel(dmcontrol, info->index); + dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index); /* If we had been halted when we reset, request another halt. If we * ended up running out of reset, then the user will (hopefully) get a * message that a reset happened, that the target is running, and then @@ -4799,9 +4807,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) } static int riscv013_step_or_resume_current_hart(struct target *target, - bool step, bool use_hasel) + bool step) { - if (!riscv_is_halted(target)) { + if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Hart is not halted!"); return ERROR_FAIL; } @@ -4813,12 +4821,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target, dm013_info_t *dm = get_dm(target); /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; - if (use_hasel) - dmcontrol |= DM_DMCONTROL_HASEL; - dmcontrol = set_hartsel(dmcontrol, dm->current_hartid); + dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); dmi_write(target, DM_DMCONTROL, dmcontrol); - dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); uint32_t dmstatus; From fe5c7d7a3525897b045b9accc39c200f4f051e9e Mon Sep 17 00:00:00 2001 From: Anatoly Parshintsev <114445139+aap-sc@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:40:16 +0300 Subject: [PATCH 179/186] [riscv] step operation handler should respect handle_breakpoints parameter (#741) * [riscv] step operation handler should respect handle_breakpoints parameter When step operation is requested the OpenOCD frontend (like gdb server or TCL server) has an option to control how existing breakpoints are handled upon step. Some OpenOCD frontends (like gdbserver) may choose to disable special handling of existing breakpoints - thus handle_breakpoints is set to 0, while others (like TCL server) expect target handler to temporary disable the matching breakpoint to allow the step operation to complete successfully. In the current implementation handle_breakpoints parameter was ignored by target-specific handler. Thus, the following sequence of commands: ``` halt bp 4 step ``` Resulted in *step* operation to not change PC because of bp match. This commit addresses this issue. * Adjusted calls to logging facilities (addressed review comments) Co-authored-by: Tim Newsome Signed-off-by: Anatoly Parshintsev <114445139+aap-sc@users.noreply.github.com> Signed-off-by: Anatoly Parshintsev <114445139+aap-sc@users.noreply.github.com> Co-authored-by: Tim Newsome --- src/target/riscv/riscv.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 4a1145bb6..9a1e55ccb 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2289,10 +2289,24 @@ int riscv_openocd_poll(struct target *target) int riscv_openocd_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { - LOG_DEBUG("stepping rtos hart"); + LOG_TARGET_DEBUG(target, "stepping hart"); - if (!current) - riscv_set_register(target, GDB_REGNO_PC, address); + if (!current) { + if (riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK) + return ERROR_FAIL; + } + + struct breakpoint *breakpoint = NULL; + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + if (current) { + if (riscv_get_register(target, &address, GDB_REGNO_PC) != ERROR_OK) + return ERROR_FAIL; + } + breakpoint = breakpoint_find(target, address); + if (breakpoint && (riscv_remove_breakpoint(target, breakpoint) != ERROR_OK)) + return ERROR_FAIL; + } riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; if (disable_triggers(target, trigger_state) != ERROR_OK) @@ -2332,6 +2346,11 @@ int riscv_openocd_step(struct target *target, int current, LOG_ERROR("unable to enable triggers"); } + if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { + success = false; + LOG_TARGET_ERROR(target, "unable to restore the disabled breakpoint"); + } + if (success) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); From 9eb07f258e7ae8c4a38b349481d27b0207c35100 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 21 Oct 2022 09:16:54 -0700 Subject: [PATCH 180/186] target/riscv: Correctly set target->state in deassert_reset (#750) * target/riscv: Correctly set target->state in deassert_reset This bug didn't lead to problems, but it would with some upcoming changes. Change-Id: I552acbae9977150c4c9e573f8852033bc80fcebb Signed-off-by: Tim Newsome * Keep debug_reason in sync with state Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome Signed-off-by: Tim Newsome Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> --- src/target/riscv/riscv-013.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index bc5b262ca..bcd694a1b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2452,8 +2452,13 @@ static int deassert_reset(struct target *target) return ERROR_FAIL; } } - target->state = TARGET_HALTED; - target->debug_reason = DBG_REASON_DBGRQ; + if (target->reset_halt) { + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + } else { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { /* Ack reset. */ From fc0342607639bb120ddad507815c8d3b0123485a Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Thu, 24 Aug 2023 11:00:32 -0400 Subject: [PATCH 181/186] Apply changes from WCH release 1.80 --- .github/workflows/checkpatch.yml | 27 - .github/workflows/linux-build.yml | 43 - .github/workflows/snapshot.yml | 83 - configure.ac | 22 + src/flash/nor/Makefile.am | 2 + src/flash/nor/drivers.c | 5 +- src/flash/nor/tcl.c | 39 +- src/flash/nor/wcharm.c | 897 ++++++ src/flash/nor/wchriscv.c | 324 +++ src/helper/command.c | 1 + src/jtag/Makefile.am | 2 + src/jtag/core.c | 6 +- src/jtag/drivers/Makefile.am | 8 + src/jtag/drivers/ch347.c | 852 ++++++ src/jtag/drivers/wlinke.c | 2043 ++++++++++++++ src/jtag/interface.h | 5 +- src/jtag/interfaces.c | 13 + src/jtag/sdi.c | 131 + src/jtag/sdi.h | 14 + src/server/gdb_server.c | 32 +- src/target/Makefile.am | 5 + src/target/armv7m.c | 10 +- src/target/riscv/gdb_regs.h | 2 +- src/target/riscv/riscv.c | 5 +- src/target/target.c | 28 +- src/target/wch_riscv-013.c | 4300 +++++++++++++++++++++++++++++ src/target/wch_riscv.c | 3028 ++++++++++++++++++++ src/target/wch_riscv.h | 26 + src/transport/transport.h | 2 +- 29 files changed, 11777 insertions(+), 178 deletions(-) delete mode 100644 .github/workflows/checkpatch.yml delete mode 100644 .github/workflows/linux-build.yml delete mode 100644 .github/workflows/snapshot.yml mode change 100644 => 100755 src/flash/nor/Makefile.am mode change 100644 => 100755 src/flash/nor/drivers.c mode change 100644 => 100755 src/flash/nor/tcl.c create mode 100755 src/flash/nor/wcharm.c create mode 100755 src/flash/nor/wchriscv.c mode change 100644 => 100755 src/helper/command.c mode change 100644 => 100755 src/jtag/Makefile.am mode change 100644 => 100755 src/jtag/core.c mode change 100644 => 100755 src/jtag/drivers/Makefile.am create mode 100644 src/jtag/drivers/ch347.c create mode 100755 src/jtag/drivers/wlinke.c mode change 100644 => 100755 src/jtag/interface.h mode change 100644 => 100755 src/jtag/interfaces.c create mode 100755 src/jtag/sdi.c create mode 100755 src/jtag/sdi.h mode change 100644 => 100755 src/server/gdb_server.c mode change 100644 => 100755 src/target/Makefile.am mode change 100644 => 100755 src/target/armv7m.c mode change 100644 => 100755 src/target/riscv/gdb_regs.h mode change 100644 => 100755 src/target/riscv/riscv.c mode change 100644 => 100755 src/target/target.c create mode 100755 src/target/wch_riscv-013.c create mode 100755 src/target/wch_riscv.c create mode 100755 src/target/wch_riscv.h mode change 100644 => 100755 src/transport/transport.h diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml deleted file mode 100644 index c9ec78d59..000000000 --- a/.github/workflows/checkpatch.yml +++ /dev/null @@ -1,27 +0,0 @@ -on: pull_request - -name: Check Code Style (checkpatch) - -jobs: - check: - runs-on: ubuntu-latest - env: - DL_DIR: ../downloads - BUILD_DIR: ../build - steps: - - name: Checkout Code - uses: actions/checkout@v2 - with: - fetch-depth: 50 - - name: Install required packages (apt-get) - run: | - sudo apt-get update - sudo apt-get install patchutils - - name: Run checkpatch - run: | - git diff -U20 HEAD~40 \ - | filterdiff \ - -x "a/src/jtag/drivers/libjaylink/*" \ - -x "a/tools/git2cl/*" \ - -x "a/.github/*" \ - | ./tools/scripts/checkpatch.pl --no-signoff - diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml deleted file mode 100644 index f566d8c90..000000000 --- a/.github/workflows/linux-build.yml +++ /dev/null @@ -1,43 +0,0 @@ -on: pull_request - -name: Linux Build - -jobs: - # 32-bit, clang - build32: - runs-on: ubuntu-latest - env: - CFLAGS: -m32 - CC: clang - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Install required packages (apt-get) - run: | - sudo apt-get update - sudo apt-get install clang gcc-multilib - - run: ./bootstrap - - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --disable-target64 - - run: make -j`nproc` - - run: file src/openocd | grep 32-bit - - run: src/openocd --version - - - # 64-bit, gcc - build64: - runs-on: ubuntu-latest - env: - CFLAGS: -m64 - CC: gcc - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Install required packages (apt-get) - run: | - sudo apt-get update - sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev - - run: ./bootstrap - - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag - - run: make -j`nproc` - - run: file src/openocd | grep 64-bit - - run: src/openocd --version diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml deleted file mode 100644 index d4749d6d3..000000000 --- a/.github/workflows/snapshot.yml +++ /dev/null @@ -1,83 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# Copyright (C) 2020 by Tarek BOUCHKATI - -on: pull_request - -name: OpenOCD Snapshot - -jobs: - package: - runs-on: [ubuntu-18.04] - env: - DL_DIR: ../downloads - BUILD_DIR: ../build - steps: - - name: Install needed packages - run: | - sudo apt-get update - sudo apt-get install autotools-dev autoconf automake libtool pkg-config cmake texinfo texlive g++-mingw-w64-i686 - - name: Checkout Code - uses: actions/checkout@v1 - - run: ./bootstrap - - name: Prepare libusb1 - env: - LIBUSB1_VER: 1.0.24 - run: | - mkdir -p $DL_DIR && cd $DL_DIR - wget "https://github.com/libusb/libusb/releases/download/v${LIBUSB1_VER}/libusb-${LIBUSB1_VER}.tar.bz2" - tar -xjf libusb-${LIBUSB1_VER}.tar.bz2 - echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV - - name: Prepare hidapi - env: - HIDAPI_VER: 0.10.1 - run: | - mkdir -p $DL_DIR && cd $DL_DIR - wget "https://github.com/libusb/hidapi/archive/hidapi-${HIDAPI_VER}.tar.gz" - tar -xzf hidapi-${HIDAPI_VER}.tar.gz - cd hidapi-hidapi-${HIDAPI_VER} - ./bootstrap - echo "HIDAPI_SRC=$PWD" >> $GITHUB_ENV - - name: Prepare capstone - env: - CAPSTONE_VER: 4.0.2 - run: | - mkdir -p $DL_DIR && cd $DL_DIR - CAPSTONE_NAME=${CAPSTONE_VER} - CAPSTONE_FOLDER=capstone-${CAPSTONE_VER} - wget "https://github.com/aquynh/capstone/archive/${CAPSTONE_VER}.tar.gz" - tar -xzf ${CAPSTONE_VER}.tar.gz - echo "CAPSTONE_SRC=$PWD/capstone-${CAPSTONE_VER}" >> $GITHUB_ENV - - name: Package OpenOCD for windows - env: - MAKE_JOBS: 2 - HOST: i686-w64-mingw32 - LIBUSB1_CONFIG: --enable-shared --disable-static - HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui - CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" - CAPSTONE_CFLAGS: -I$(CAPSTONE_SRC)/include/capstone - run: | - # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG - OPENOCD_TAG="`git tag --points-at HEAD`" - [ -z $OPENOCD_TAG ] && OPENOCD_TAG="`git rev-parse --short HEAD`" - # check if there is tag pointing at HEAD, if so the release will have the same name as the tag, - # otherwise it will be named 'latest' - RELEASE_NAME="`git tag --points-at HEAD`" - [ -z $RELEASE_NAME ] && RELEASE_NAME="latest" - [[ $RELEASE_NAME = "latest" ]] && IS_PRE_RELEASE="true" || IS_PRE_RELEASE="false" - # set env and call cross-build.sh - export OPENOCD_TAG=$OPENOCD_TAG - export OPENOCD_SRC=$PWD - export OPENOCD_CONFIG="" - mkdir -p $BUILD_DIR && cd $BUILD_DIR - bash $OPENOCD_SRC/contrib/cross-build.sh $HOST - # add missing dlls - cd $HOST-root/usr - cp `$HOST-gcc --print-file-name=libwinpthread-1.dll` ./bin/ - cp `$HOST-gcc --print-file-name=libgcc_s_sjlj-1.dll` ./bin/ - # prepare the artifact - ARTIFACT="openocd-${OPENOCD_TAG}-${HOST}.tar.gz" - tar -czf $ARTIFACT * - echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV - echo "IS_PRE_RELEASE=$IS_PRE_RELEASE" >> $GITHUB_ENV - echo "ARTIFACT_PATH=$PWD/$ARTIFACT" >> $GITHUB_ENV diff --git a/configure.ac b/configure.ac index 081e7744d..e84bcca74 100644 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,8 @@ m4_define([USB1_ADAPTERS], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], + [[wlinke], [ WLINKE Programmer], [WLINKE]], + [[ch347], [ CH347 Programmer], [CH347]], [[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]], @@ -279,6 +281,12 @@ AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) +AC_ARG_ENABLE([wlinke], + AS_HELP_STRING([--enable-wlinke], [Enable building support for WLINKE]), + [build_wlinke=$enableval], [build_wlinke=no]) +AC_ARG_ENABLE([ch347], + AS_HELP_STRING([--enable-ch347], [Enable building support for CH347]), + [build_ch347=$enableval], [build_ch347=no]) AC_ARG_ENABLE([vdebug], AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), [build_vdebug=$enableval], [build_vdebug=no]) @@ -526,6 +534,18 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_wlinke" = "xyes"], [ + AC_DEFINE([BUILD_WLINKE], [1], [1 if you want WLINKE.]) +], [ + AC_DEFINE([BUILD_WLINKE], [0], [0 if you don't want WLINKE.]) +]) + +AS_IF([test "x$build_ch347" = "xyes"], [ + AC_DEFINE([BUILD_CH347], [1], [1 if you want CH347.]) +], [ + AC_DEFINE([BUILD_CH347], [0], [0 if you don't want CH347.]) +]) + AS_IF([test "x$build_vdebug" = "xyes"], [ AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) ], [ @@ -714,6 +734,8 @@ AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([WLINKE], [test "x$build_wlinke" = "xyes" -o "x$build_wlinke" = "xyes"]) +AM_CONDITIONAL([CH347], [test "x$build_ch347" = "xyes" -o "x$build_ch347" = "xyes"]) AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am old mode 100644 new mode 100755 index a5ef42210..8f00a9e60 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -75,6 +75,8 @@ NOR_DRIVERS = \ %D%/w600.c \ %D%/xcf.c \ %D%/xmc1xxx.c \ + %D%/wchriscv.c \ + %D%/wcharm.c \ %D%/xmc4xxx.c NORHEADERS = \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c old mode 100644 new mode 100755 index 387fc71f1..b94113a39 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -90,7 +90,8 @@ extern const struct flash_driver w600_flash; extern const struct flash_driver xcf_flash; extern const struct flash_driver xmc1xxx_flash; extern const struct flash_driver xmc4xxx_flash; - +extern const struct flash_driver wch_riscv_flash; +extern const struct flash_driver wch_arm_flash; /** * The list of built-in flash drivers. * @todo Make this dynamically extendable with loadable modules. @@ -166,6 +167,8 @@ static const struct flash_driver * const flash_drivers[] = { &xmc1xxx_flash, &xmc4xxx_flash, &w600_flash, + &wch_riscv_flash, + &wch_arm_flash, NULL, }; diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c old mode 100644 new mode 100755 index 05db31435..17bf32512 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -29,7 +29,9 @@ * @file * Implements Tcl commands used to access NOR flash facilities. */ - +extern int wlnik_protect_check(void); +extern char riscvchip; +extern void wlink_softreset(void); static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index, struct flash_bank **bank, bool do_probe) { @@ -400,6 +402,34 @@ COMMAND_HANDLER(handle_flash_protect_command) return retval; } +COMMAND_HANDLER(handle_flash_protect_check_command){ + + struct flash_bank *p; + int retval; + int num_blocks; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); + if (retval != ERROR_OK) + return retval; + if (strncmp(p->driver->name, "wch_riscv", 9) == 0){ + if(riscvchip==1) + wlink_softreset(); + if((riscvchip==1)||(riscvchip==5)||(riscvchip==6)||(riscvchip==9)||(riscvchip==0x0c)||(riscvchip==0x0e)){ + int retval=wlnik_protect_check(); + if(retval==4) + LOG_INFO("Code Read-Protect Status Enable"); + else + LOG_INFO("Code Read-Protect status Disable"); + + }else{ + LOG_ERROR("This chip do not support function"); + return ERROR_OK; + } + } + return ERROR_OK; +} + + COMMAND_HANDLER(handle_flash_write_image_command) { struct target *target = get_current_target(CMD_CTX); @@ -1240,6 +1270,13 @@ static const struct command_registration flash_exec_command_handlers[] = { .usage = "bank_id value", .help = "Set default flash padded value", }, + { + .name = "protect_check", + .handler = handle_flash_protect_check_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/wcharm.c b/src/flash/nor/wcharm.c new file mode 100755 index 000000000..5403674d4 --- /dev/null +++ b/src/flash/nor/wcharm.c @@ -0,0 +1,897 @@ +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * Copyright (C) 2011 by Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include + +/* ch32x register locations */ + +#define FLASH_REG_BASE_B0 0x40022000 +#define FLASH_REG_BASE_B1 0x40022040 + +#define ch32_FLASH_ACR 0x00 +#define ch32_FLASH_KEYR 0x04 +#define ch32_FLASH_OPTKEYR 0x08 +#define ch32_FLASH_SR 0x0C +#define ch32_FLASH_CR 0x10 +#define ch32_FLASH_AR 0x14 +#define ch32_FLASH_OBR 0x1C +#define ch32_FLASH_WRPR 0x20 +#define CH32_FLASH_MODEKEYP 0x24 //chf103�����Ĵ��� + +/* TODO: Check if code using these really should be hard coded to bank 0. + * There are valid cases, on dual flash devices the protection of the + * second bank is done on the bank0 reg's. */ +#define ch32_FLASH_ACR_B0 0x40022000 +#define ch32_FLASH_KEYR_B0 0x40022004 +#define ch32_FLASH_OPTKEYR_B0 0x40022008 +#define ch32_FLASH_SR_B0 0x4002200C +#define ch32_FLASH_CR_B0 0x40022010 +#define ch32_FLASH_AR_B0 0x40022014 +#define ch32_FLASH_OBR_B0 0x4002201C +#define ch32_FLASH_WRPR_B0 0x40022020 + +/* option byte location */ + +#define ch32_OB_RDP 0x1FFFF800 +#define ch32_OB_USER 0x1FFFF802 +#define ch32_OB_DATA0 0x1FFFF804 +#define ch32_OB_DATA1 0x1FFFF806 +#define ch32_OB_WRP0 0x1FFFF808 +#define ch32_OB_WRP1 0x1FFFF80A +#define ch32_OB_WRP2 0x1FFFF80C +#define ch32_OB_WRP3 0x1FFFF80E + +/* FLASH_CR register bits */ + +#define FLASH_PG (1 << 0) +#define FLASH_PER (1 << 1) +#define FLASH_MER (1 << 2) +#define FLASH_OPTPG (1 << 4) +#define FLASH_OPTER (1 << 5) +#define FLASH_STRT (1 << 6) +#define FLASH_LOCK (1 << 7) +#define FLASH_OPTWRE (1 << 9) +#define FLASH_OBL_LAUNCH (1 << 13) /* except ch32f1x series */ + +/* CHf��Flash_CR�Ĵ���������λ */ +#define FLASH_PAGE_PROGRAM 0x00010000 //ҳ��̣�128Byteһҳ�� +#define FLASH_PAGE_ERASE 0x00020000 //ҳ������128Byteһҳ�� +#define FLASH_STD_PAGE_ERASE 0x00000002 //��׼ҳ������1024Byte һҳ�� +#define FLASH_STD_PAGE_PRG 0x00000001 //��׼ҳ��̣�1024Byte һҳ�� +#define FLASH_BUF_LOAD 0x00040000 //�������ݵ�FLASH�ڲ������� +#define FLASH_BUF_RTS 0x00080000 //FLASH�ڲ���������λ + + + +/* FLASH_SR register bits */ + +#define FLASH_BSY (1 << 0) +#define FLASH_PGERR (1 << 2) +#define FLASH_WRPRTERR (1 << 4) +#define FLASH_EOP (1 << 5) + +/* ch32_FLASH_OBR bit definitions (reading) */ + +#define OPT_ERROR 0 +#define OPT_READOUT 1 +#define OPT_RDWDGSW 2 +#define OPT_RDRSTSTOP 3 +#define OPT_RDRSTSTDBY 4 +#define OPT_BFB2 5 /* dual flash bank only */ + +/* register unlock keys */ + +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* timeout values */ + +#define FLASH_WRITE_TIMEOUT 10 +#define FLASH_ERASE_TIMEOUT 1000 + +int wch_arm_chip; +static const uint8_t ch32f2_flash_write_code[] = { + 0x80, 0xB4, 0x89, 0xB0, 0x00, 0xAF, 0x78, 0x60, 0x39, 0x60, 0x7B, 0x68, 0xBB, 0x61, 0x35, 0x4B, + 0xFB, 0x61, 0x3B, 0x68, 0xFF, 0x33, 0x1B, 0x0A, 0x3B, 0x61, 0x33, 0x4B, 0x1B, 0x69, 0x32, 0x4A, + 0x43, 0xF4, 0x80, 0x33, 0x13, 0x61, 0x30, 0x4B, 0x1B, 0x69, 0x2F, 0x4A, 0x43, 0xF4, 0x80, 0x33, + 0x13, 0x61, 0x00, 0xBF, 0x2C, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x01, 0x03, 0x00, 0x2B, 0xF9, 0xD1, + 0xBB, 0x69, 0x7B, 0x61, 0x40, 0x23, 0xFB, 0x60, 0x12, 0xE0, 0xFB, 0x69, 0x1A, 0x1D, 0xFA, 0x61, + 0x7A, 0x69, 0x1B, 0x68, 0x13, 0x60, 0x7B, 0x69, 0x04, 0x33, 0x7B, 0x61, 0xFB, 0x68, 0x01, 0x3B, + 0xFB, 0x60, 0x00, 0xBF, 0x20, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x02, 0x03, 0x00, 0x2B, 0xF9, 0xD1, + 0xFB, 0x68, 0x00, 0x2B, 0xE9, 0xD1, 0x1C, 0x4B, 0x1B, 0x69, 0x1B, 0x4A, 0x43, 0xF4, 0x00, 0x13, + 0x13, 0x61, 0x00, 0xBF, 0x18, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x01, 0x03, 0x00, 0x2B, 0xF9, 0xD1, + 0x15, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x10, 0x03, 0x00, 0x2B, 0x0D, 0xD0, 0x12, 0x4B, 0xDB, 0x68, + 0x11, 0x4A, 0x43, 0xF0, 0x10, 0x03, 0xD3, 0x60, 0x0F, 0x4B, 0x1B, 0x69, 0x0E, 0x4A, 0x23, 0xF4, + 0x80, 0x33, 0x13, 0x61, 0x08, 0x23, 0x0F, 0xE0, 0xBB, 0x69, 0x03, 0xF5, 0x80, 0x73, 0xBB, 0x61, + 0x3B, 0x69, 0x01, 0x3B, 0x3B, 0x61, 0x00, 0x2B, 0xAD, 0xD1, 0x07, 0x4B, 0x1B, 0x69, 0x06, 0x4A, + 0x23, 0xF4, 0x80, 0x33, 0x13, 0x61, 0x00, 0x23, 0x18, 0x46, 0x24, 0x37, 0xBD, 0x46, 0x80, 0xBC, + 0x00, 0xBE, 0x00, 0xBF, 0x00, 0x10, 0x00, 0x20, 0x00, 0x20, 0x02, 0x40, +}; +static const uint8_t ch32f1_flash_write_code[]= +{ + 0x80, 0xB4, 0x89, 0xB0, 0x00, 0xAF, 0x78, 0x60, 0x39, 0x60, 0x7B, 0x68, 0xBB, 0x61, 0x42, 0x4B, + 0xFB, 0x61, 0x3B, 0x68, 0x7F, 0x33, 0xDB, 0x09, 0x3B, 0x61, 0x40, 0x4B, 0x1B, 0x69, 0x3F, 0x4A, + 0x43, 0xF4, 0x80, 0x33, 0x13, 0x61, 0x3D, 0x4B, 0x1B, 0x69, 0x3C, 0x4A, 0x43, 0xF4, 0x00, 0x23, + 0x13, 0x61, 0x00, 0xBF, 0x39, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x01, 0x03, 0x00, 0x2B, 0xF9, 0xD1, + 0xBB, 0x69, 0x7B, 0x61, 0x08, 0x23, 0xFB, 0x60, 0xFB, 0x69, 0x1A, 0x1D, 0xFA, 0x61, 0x7A, 0x69, + 0x1B, 0x68, 0x13, 0x60, 0xFB, 0x69, 0x1A, 0x1D, 0xFA, 0x61, 0x7A, 0x69, 0x04, 0x32, 0x1B, 0x68, + 0x13, 0x60, 0xFB, 0x69, 0x1A, 0x1D, 0xFA, 0x61, 0x7A, 0x69, 0x08, 0x32, 0x1B, 0x68, 0x13, 0x60, + 0xFB, 0x69, 0x1A, 0x1D, 0xFA, 0x61, 0x7A, 0x69, 0x0C, 0x32, 0x1B, 0x68, 0x13, 0x60, 0x27, 0x4B, + 0x1B, 0x69, 0x26, 0x4A, 0x43, 0xF4, 0x80, 0x23, 0x13, 0x61, 0x00, 0xBF, 0x23, 0x4B, 0xDB, 0x68, + 0x03, 0xF0, 0x01, 0x03, 0x00, 0x2B, 0xF9, 0xD1, 0x7B, 0x69, 0x10, 0x33, 0x7B, 0x61, 0xFB, 0x68, + 0x01, 0x3B, 0xFB, 0x60, 0x00, 0x2B, 0xCF, 0xD1, 0x1C, 0x4A, 0xBB, 0x69, 0x53, 0x61, 0x1B, 0x4B, + 0x1B, 0x69, 0x1A, 0x4A, 0x43, 0xF0, 0x40, 0x03, 0x13, 0x61, 0x00, 0xBF, 0x17, 0x4B, 0xDB, 0x68, + 0x03, 0xF0, 0x01, 0x03, 0x00, 0x2B, 0xF9, 0xD1, 0x14, 0x4B, 0xDB, 0x68, 0x03, 0xF0, 0x14, 0x03, + 0x00, 0x2B, 0x0D, 0xD0, 0x11, 0x4B, 0xDB, 0x68, 0x10, 0x4A, 0x43, 0xF0, 0x14, 0x03, 0xD3, 0x60, + 0x0E, 0x4B, 0x1B, 0x69, 0x0D, 0x4A, 0x23, 0xF4, 0x50, 0x23, 0x13, 0x61, 0x08, 0x23, 0x0E, 0xE0, + 0xBB, 0x69, 0x80, 0x33, 0xBB, 0x61, 0x3B, 0x69, 0x01, 0x3B, 0x3B, 0x61, 0x00, 0x2B, 0x92, 0xD1, + 0x06, 0x4B, 0x1B, 0x69, 0x05, 0x4A, 0x23, 0xF4, 0x50, 0x23, 0x13, 0x61, 0x00, 0x23, 0x18, 0x46, + 0x24, 0x37, 0xBD, 0x46, 0x80, 0xBC, 0x00, 0xBE, 0x00, 0x10, 0x00, 0x20, 0x00, 0x20, 0x02, 0x40, + +}; + +struct ch32x_options { + uint8_t rdp; + uint8_t user; + uint16_t data; + uint32_t protection; +}; + +struct ch32x_flash_bank { + struct ch32x_options option_bytes; + int ppage_size; + int probed; + + bool has_dual_banks; + /* used to access dual flash bank ch32xl */ + bool can_load_options; + uint32_t register_base; + uint8_t default_rdp; + int user_data_offset; + int option_offset; + uint32_t user_bank_size; +}; + + + + +static int ch32x_mass_erase(struct flash_bank *bank); +static int ch32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); +static int ch32x_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t count); + +/* flash bank ch32x 0 0 + */ +FLASH_BANK_COMMAND_HANDLER(ch32x_flash_bank_command) +{ + struct ch32x_flash_bank *ch32x_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + ch32x_info = malloc(sizeof(struct ch32x_flash_bank)); + + bank->driver_priv = ch32x_info; + ch32x_info->probed = 0; + ch32x_info->has_dual_banks = false; + ch32x_info->can_load_options = false; + ch32x_info->register_base = FLASH_REG_BASE_B0; + ch32x_info->user_bank_size = bank->size; + + return ERROR_OK; +} +static int get_ch32x_info(struct flash_bank *bank, char *buf, int buf_size) +{ + return ERROR_OK; +} +static inline int ch32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +{ + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + return reg + ch32x_info->register_base; +} + +static inline int ch32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + struct target *target = bank->target; + return target_read_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_SR), status); +} + +static int ch32x_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + uint32_t status; + int retval = ERROR_OK; + + /* wait for busy to clear */ + for (;;) { + retval = ch32x_get_flash_status(bank, &status); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("status: 0x%" PRIx32 "", status); + if ((status & FLASH_BSY) == 0) + break; + if (timeout-- <= 0) { + LOG_ERROR("timed out waiting for flash"); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & FLASH_WRPRTERR) { + LOG_ERROR("ch32x device protected"); + retval = ERROR_FAIL; + } + + if (status & FLASH_PGERR) { + LOG_ERROR("ch32x device programming failed"); + retval = ERROR_FAIL; + } + + /* Clear but report errors */ + if (status & (FLASH_WRPRTERR | FLASH_PGERR)) { + /* If this operation fails, we ignore it and report the original + * retval + */ + target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_SR), + FLASH_WRPRTERR | FLASH_PGERR); + } + return retval; +} + +static int ch32x_check_operation_supported(struct flash_bank *bank) +{ + + + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + + /* if we have a dual flash bank device then + * we need to perform option byte stuff on bank0 only */ + if (ch32x_info->register_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Operation's must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int ch32x_read_options(struct flash_bank *bank) +{ + + + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t option_bytes; + int retval; + + /* read user and read protection option bytes */ + retval = target_read_u32(target, ch32_OB_RDP, &option_bytes); + if (retval != ERROR_OK) + return retval; + + ch32x_info->option_bytes.rdp = option_bytes & 0xFF; + ch32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF; + + /* read user data option bytes */ + retval = target_read_u32(target, ch32_OB_DATA0, &option_bytes); + if (retval != ERROR_OK) + return retval; + + ch32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + + /* read write protection option bytes */ + retval = target_read_u32(target, ch32_OB_WRP0, &option_bytes); + if (retval != ERROR_OK) + return retval; + + ch32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + + retval = target_read_u32(target, ch32_OB_WRP2, &option_bytes); + if (retval != ERROR_OK) + return retval; + + ch32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16; + + return ERROR_OK; +} + +static int ch32x_erase_options(struct flash_bank *bank) +{ + + uint32_t option_bytes; + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + struct target *target = bank->target; + + /* read current options */ + ch32x_read_options(bank); + + /* unlock flash registers */ + int retval = target_write_u32(target, ch32_FLASH_KEYR_B0, KEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, ch32_FLASH_KEYR_B0, KEY2); + if (retval != ERROR_OK) + return retval; + + /* unlock option flash registers */ + retval = target_write_u32(target, ch32_FLASH_OPTKEYR_B0, KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_OPTKEYR_B0, KEY2); + if (retval != ERROR_OK) + return retval; + + /* erase option bytes */ + retval = target_write_u32(target, ch32_FLASH_CR_B0, FLASH_OPTER); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_OB_RDP,((ch32x_info->option_bytes.rdp & 0xffff0000)| ch32x_info->default_rdp) ); + if (retval != ERROR_OK) + return retval; + + ch32x_info->option_bytes.rdp = ch32x_info->default_rdp; + + retval = ch32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + for(int i=0;i<8;i++){ + retval = target_write_u16(target, ch32_OB_RDP+16*i,0xffff ); + if (retval != ERROR_OK) + return retval; + } + retval = target_read_u32(target, ch32_FLASH_CR_B0, &option_bytes); + if (retval != ERROR_OK) + return retval; + option_bytes &=0xffffffef; + + retval = target_write_u32(target, ch32_FLASH_CR_B0, option_bytes); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int ch32x_write_options(struct flash_bank *bank) +{ + + + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + struct target *target = bank->target; + uint16_t pbuf[8]; + uint32_t option_bytes; + ch32x_info = bank->driver_priv; + + /* unlock flash registers */ + int retval = target_write_u32(target, ch32_FLASH_KEYR_B0, KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_KEYR_B0, KEY2); + if (retval != ERROR_OK) + return retval; + + /* unlock option flash registers */ + retval = target_write_u32(target, ch32_FLASH_OPTKEYR_B0, KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_OPTKEYR_B0, KEY2); + if (retval != ERROR_OK) + return retval; + + /* program option bytes */ + for(int i=0;i<8;i++){ + retval = target_read_u16(target, ch32_OB_RDP+ 16*i , pbuf[i]); + if (retval != ERROR_OK) + return retval; + } + if(ch32x_info->option_bytes.protection) + pbuf[0]=0x5aa5; + else + pbuf[0]=0x00ff; + + retval = target_write_u32(target, ch32_FLASH_CR_B0, FLASH_OPTER); + if (retval != ERROR_OK) + return retval; + for(int i=0;i<8;i++){ + retval = target_write_u16(target, ch32_OB_RDP+16*i,pbuf[i]); + if (retval != ERROR_OK) + return retval; + } + retval = target_read_u32(target, ch32_FLASH_CR_B0, &option_bytes); + if (retval != ERROR_OK) + return retval; + option_bytes &=0xffffffef; + + retval = target_write_u32(target, ch32_FLASH_CR_B0, option_bytes); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int ch32x_protect_check(struct flash_bank *bank) +{ + + + struct target *target = bank->target; + uint32_t protection; + + int retval = ch32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + + /* medium density - each bit refers to a 4 sector protection block + * high density - each bit refers to a 2 sector protection block + * bit 31 refers to all remaining sectors in a bank */ + retval = target_read_u32(target, ch32_FLASH_WRPR_B0, &protection); + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < bank->num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = (protection & (1 << i)) ? 0 : 1; + + return ERROR_OK; +} + +static int ch32x_erase(struct flash_bank *bank, int first, int last) +{ + + + struct target *target = bank->target; + int i; + uint32_t cr_reg; uint32_t sr_reg; + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* unlock flash registers */ + + int retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + + retval = target_read_u32(target, ch32_FLASH_CR_B0, &cr_reg); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_CR_B0, cr_reg | FLASH_MER); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, ch32_FLASH_CR_B0, &cr_reg); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_CR_B0, cr_reg | FLASH_STRT); + if (retval != ERROR_OK) + return retval; + + + retval = ch32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + + retval = target_read_u32(target, ch32_FLASH_CR_B0, &cr_reg); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32_FLASH_CR_B0, (cr_reg)&(~(1<<2))); + if (retval != ERROR_OK) + return retval; + alive_sleep(300); + + return ERROR_OK; +} + +static int ch32x_protect(struct flash_bank *bank, int set, int first, int last) +{ + + struct target *target = bank->target; + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = ch32x_check_operation_supported(bank); + if (retval != ERROR_OK) + return retval; + + retval = ch32x_erase_options(bank); + if (retval != ERROR_OK) { + LOG_ERROR("ch32x failed to erase options"); + return retval; + } + + for (int i = first; i <= last; i++) { + if (set) + ch32x_info->option_bytes.protection &= ~(1 << i); + else + ch32x_info->option_bytes.protection |= (1 << i); + } + + return ch32x_write_options(bank); +} + +static int ch32x_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t count) +{ + + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t buffer_size = 16384; + struct working_area *write_algorithm; + struct working_area *source; + struct reg_param reg_params[4]; + struct armv7m_algorithm armv7m_info; + uint32_t basaddr=0x08000000; + uint32_t pagesize=0x100; + uint32_t sp=0x20002800; + int retval = ERROR_OK; + uint8_t ch32x_flash_write_code[320]={0}; + uint8_t bufpage[256]; + if(wch_arm_chip==1) + memcpy(ch32x_flash_write_code,ch32f1_flash_write_code,sizeof(ch32f1_flash_write_code)); + else + memcpy(ch32x_flash_write_code,ch32f2_flash_write_code,sizeof(ch32f2_flash_write_code)); + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(ch32x_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(ch32x_flash_write_code) , ch32x_flash_write_code); + LOG_INFO("write_algorithm->address%x",write_algorithm->address); + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + return retval; + } + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* flash base (in), status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* buffer start */ + + buf_set_u32(reg_params[0].value, 0, 32, basaddr); + buf_set_u32(reg_params[1].value, 0, 32, pagesize ); + buf_set_u32(reg_params[2].value, 0, 32, sp); + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + int mod =address%256; + int len=count+mod; + uint8_t *buffer1; + uint8_t *buffer2; + int loop=0; + if(mod){ + if(address<256) + address=0; + else + address-=mod; + + buffer1=malloc(len); + buffer2=malloc(mod); + + target_read_memory(bank->target,address,1,mod,buffer2); + memcpy(buffer1,buffer2,mod); + memcpy(&buffer1[mod],buffer,count); + }else{ + buffer1=malloc(len); + memcpy(buffer1,buffer,count); + } + while(len>0){ + buf_set_u32(reg_params[0].value, 0, 32, basaddr); + if(len<256){ + memset(bufpage,0xff,256); + memcpy(bufpage,buffer1+loop*256,len); + }else + memcpy(bufpage,buffer1+loop*256,256); + target_write_buffer(target, 0x20001000,256,bufpage); + retval=target_run_algorithm(target,0,NULL,3,reg_params,0x20000000,0,100000,&armv7m_info); + len-=256; + loop++; + basaddr +=256; + + } + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[4].value, 0, 32)); + + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { + LOG_ERROR("flash memory not erased before writing"); + /* Clear but report errors */ + target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_SR), FLASH_PGERR); + } + + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { + LOG_ERROR("flash memory write protected"); + /* Clear but report errors */ + target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_SR), FLASH_WRPRTERR); + } + } + + // target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + + return retval; +} + +static int ch32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + + struct target *target = bank->target; + uint8_t *new_buffer = NULL; + uint32_t choffset=offset; + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset & 0x1) { + LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + int retval; + + /* unlock flash registers */ + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + retval=target_write_u32(target,ch32x_get_flash_reg(bank, CH32_FLASH_MODEKEYP) , KEY1); + if (retval != ERROR_OK) + return retval; //��������ģʽ + retval =target_write_u32(target, ch32x_get_flash_reg(bank, CH32_FLASH_MODEKEYP), KEY2); + if (retval != ERROR_OK) + return retval; + + retval = ch32x_write_block(bank, buffer, bank->base + offset, count); + + return retval; +} + +static int ch32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + + struct target *target = bank->target; + int retval = target_read_u32(target, 0x1ffff884, device_id); + if (retval != ERROR_OK) + return retval; + if(*device_id >>24 ==0x20){ + wch_arm_chip=1; + return ERROR_OK; + } + retval = target_read_u32(target, 0x1ffff704, device_id); + if (retval != ERROR_OK) + return retval; + if((*device_id >>20 ==0x203)||(*device_id >>20 ==0x205)||(*device_id >>20 ==0x207)||(*device_id >>20 ==0x208)){ + wch_arm_chip=2; + return ERROR_OK; + + } + return ERROR_FAIL; + +} + +static int ch32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) +{ + struct target *target = bank->target; + uint32_t cpuid, flash_size_reg; + uint32_t temp; + int retval = target_read_u32(target, 0x1ffff7e0, flash_size_in_kb); + if (retval != ERROR_OK) + return retval; + + return retval; + +} + +static int ch32x_probe(struct flash_bank *bank) +{ + + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + uint16_t flash_size_in_kb; + uint16_t max_flash_size_in_kb; + uint32_t device_id; + int page_size; + uint32_t base_address = 0x08000000; + uint32_t rid=0; + ch32x_info->probed = 0; + ch32x_info->register_base = FLASH_REG_BASE_B0; + ch32x_info->user_data_offset = 10; + ch32x_info->option_offset = 0; + + /* default factory read protection level 0 */ + ch32x_info->default_rdp = 0xA5; + + /* read ch32 device id register */ + int retval = ch32x_get_device_id(bank, &device_id); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + + page_size = 1024; + ch32x_info->ppage_size = 4; + max_flash_size_in_kb = 128; + + /* get flash size from target. */ + retval = ch32x_get_flash_size(bank, &flash_size_in_kb); + + /* failed reading flash size or flash size invalid (early silicon), + * default to max target family */ + if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { + //LOG_WARNING("ch32 flash size failed, probe inaccurate - assuming %dk flash", + //max_flash_size_in_kb); + flash_size_in_kb = max_flash_size_in_kb; + } + + if (ch32x_info->has_dual_banks) { + /* split reported size into matching bank */ + if (bank->base != 0x08080000) { + /* bank 0 will be fixed 512k */ + flash_size_in_kb = 512; + } else { + flash_size_in_kb -= 512; + /* bank1 also uses a register offset */ + ch32x_info->register_base = FLASH_REG_BASE_B1; + base_address = 0x08080000; + } + } + LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + + /* did we assign flash size? */ + assert(flash_size_in_kb != 0xffff); + + /* calculate numbers of pages */ + int num_pages = flash_size_in_kb * 1024 / page_size; + + /* check that calculation result makes sense */ + assert(num_pages > 0); + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + if (bank->prot_blocks) { + free(bank->prot_blocks); + bank->prot_blocks = NULL; + } + + bank->base = base_address; + bank->size = (num_pages * page_size); + + bank->num_sectors = num_pages; + bank->sectors = alloc_block_array(0, page_size, num_pages); + if (!bank->sectors) + return ERROR_FAIL; + + /* calculate number of write protection blocks */ + int num_prot_blocks = num_pages / ch32x_info->ppage_size; + if (num_prot_blocks > 32) + num_prot_blocks = 32; + + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = alloc_block_array(0, ch32x_info->ppage_size * page_size, num_prot_blocks); + if (!bank->prot_blocks) + return ERROR_FAIL; + + if (num_prot_blocks == 32) + bank->prot_blocks[31].size = (num_pages - (31 * ch32x_info->ppage_size)) * page_size; + + ch32x_info->probed = 1; + + return ERROR_OK; +} + +static int ch32x_auto_probe(struct flash_bank *bank) +{ + struct ch32x_flash_bank *ch32x_info = bank->driver_priv; + if (ch32x_info->probed) + return ERROR_OK; + return ch32x_probe(bank); +} +static int ch32x_mass_erase(struct flash_bank *bank) +{ + + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* unlock option flash registers */ + int retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory */ + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_CR), FLASH_MER); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_CR), + FLASH_MER | FLASH_STRT); + if (retval != ERROR_OK) + return retval; + + retval = ch32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, ch32x_get_flash_reg(bank, ch32_FLASH_CR), FLASH_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + + +static const struct command_registration ch32x_command_handlers[] = { + { + .name = "ch32f1x", + .mode = COMMAND_ANY, + .help = "ch32f1x flash command group", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver wch_arm_flash = { + .name = "wch_arm", + .commands = ch32x_command_handlers, + .flash_bank_command = ch32x_flash_bank_command, + .erase = ch32x_erase, + .protect = ch32x_protect, + .write = ch32x_write, + .read = default_flash_read, + .probe = ch32x_probe, + .auto_probe = ch32x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = ch32x_protect_check, + .info = get_ch32x_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/wchriscv.c b/src/flash/nor/wchriscv.c new file mode 100755 index 000000000..6246daf0e --- /dev/null +++ b/src/flash/nor/wchriscv.c @@ -0,0 +1,324 @@ +/*************************************************************************** + * WCH RISC-V mcu :CH32V103X CH32V20X CH32V30X CH56X CH57X CH58X * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +extern int wlink_erase(void); +extern unsigned char riscvchip; +extern void wlink_reset(); +extern void wlink_chip_reset(void); +extern void wlink_getromram(uint32_t *rom, uint32_t *ram); +extern int wlink_write(const uint8_t *buffer, uint32_t offset, uint32_t count); +extern bool noloadflag; +extern int wlink_flash_protect(bool stat); +extern int wlnik_protect_check(void); +extern void wlink_clean(void); +extern unsigned long wlink_address; +extern bool pageerase; +int writeloop =0 ; +extern unsigned int chip_type; +bool flash_unfreeze=false; +struct ch32vx_options +{ + uint8_t rdp; + uint8_t user; + uint16_t data; + uint32_t protection; +}; + +struct ch32vx_flash_bank +{ + struct ch32vx_options option_bytes; + int ppage_size; + int probed; + + bool has_dual_banks; + bool can_load_options; + uint32_t register_base; + uint8_t default_rdp; + int user_data_offset; + int option_offset; + uint32_t user_bank_size; +}; + +FLASH_BANK_COMMAND_HANDLER(ch32vx_flash_bank_command) +{ + struct ch32vx_flash_bank *ch32vx_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + ch32vx_info = malloc(sizeof(struct ch32vx_flash_bank)); + + bank->driver_priv = ch32vx_info; + ch32vx_info->probed = 0; + ch32vx_info->has_dual_banks = false; + ch32vx_info->can_load_options = false; + ch32vx_info->user_bank_size = bank->size; + + return ERROR_OK; +} +static int ch32x_protect(struct flash_bank *bank, int set, int first, int last) +{ + + if ((riscvchip == 1) || (riscvchip == 5) || (riscvchip == 6) || (riscvchip == 9) || (riscvchip ==0x0c)||(riscvchip==0x0e)) + { + int retval = wlink_flash_protect(set); + if (retval == ERROR_OK) + { + if (set) + LOG_INFO("Success to Enable Read-Protect"); + else + LOG_INFO("Success to Disable Read-Protect"); + return ERROR_OK; + } + else + { + LOG_ERROR("Operation Failed"); + return ERROR_FAIL; + } + } + else + { + LOG_ERROR("This chip do not support function"); + return ERROR_FAIL; + } +} + +static int ch32vx_erase(struct flash_bank *bank, int first, int last) +{ + if (pageerase) + return ERROR_OK; + if ((riscvchip == 5) || (riscvchip == 6) || (riscvchip == 9)|| (riscvchip == 0x0c)||(riscvchip==0x0e)) + { + int retval = wlnik_protect_check(); + if (retval == 4) + { + LOG_ERROR("Read-Protect Status Currently Enabled"); + return ERROR_FAIL; + } + } + if (noloadflag) + return ERROR_OK; + + int ret = wlink_erase(); + target_halt(bank->target); + if (ret) + return ERROR_OK; + else + return ERROR_FAIL; + return ERROR_OK; +} + + +static int ch32vx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + + struct target *target = bank->target; + if (((riscvchip == 5) || (riscvchip == 6) || (riscvchip == 9)|| (riscvchip == 0x0c)||(riscvchip==0x0e)) && (writeloop==0)) + { + int retval = wlnik_protect_check(); + if (retval == 4) + { + LOG_ERROR("Read-Protect Status Currently Enabled"); + return ERROR_FAIL; + } + } + if (noloadflag) + return ERROR_OK; + + if(writeloop) + wlink_clean(); + int ret = 0; + int mod = offset % 256; + if (mod) + { + if (offset < 256) + offset = 0; + else + offset -= mod; + uint8_t *buffer1; + uint8_t *buffer2; + buffer1 = malloc(count + mod); + buffer2 = malloc(mod); + target_read_memory(bank->target, offset, 1, mod, buffer2); + memcpy(buffer1, buffer2, mod); + memcpy(&buffer1[mod], buffer, count); + ret = wlink_write(buffer1, offset, count + mod); + } + else + { + target_halt(target); + ret = wlink_write(buffer, offset, count); + } + wlink_chip_reset(); + writeloop++; + return ret; +} + +static int ch32vx_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + if ((riscvchip != 0x02) && (riscvchip != 0x03)&& (riscvchip != 0x07)&& (riscvchip != 0x0b)) + { + struct target *target = bank->target; + int retval = target_read_u32(target, 0x1ffff7e8, device_id); + if (retval != ERROR_OK) + return retval; + } + return ERROR_OK; +} + +static int ch32vx_get_flash_size(struct flash_bank *bank, uint32_t *flash_size_in_kb) +{ + + struct target *target = bank->target; + if(riscvchip == 0x09) + { + *flash_size_in_kb = 0x7fffe; + return ERROR_OK; + + + } + if ((riscvchip == 0x02) || (riscvchip == 0x03) || (riscvchip == 0x07)|| (riscvchip == 0x0b)) + { + if((chip_type ==0x71000000) || (chip_type ==0x81000000) || (chip_type ==0x91000000)) + *flash_size_in_kb = 192; + else + *flash_size_in_kb = 448; + return ERROR_OK; + } + if (riscvchip == 0x0c) + { + if(chip_type==0x03570601) + *flash_size_in_kb = 48; + *flash_size_in_kb = 62; + return ERROR_OK; + } + if (riscvchip == 0x0e) + { + if(chip_type==0x10370700) + *flash_size_in_kb = 32; + *flash_size_in_kb = 64; + return ERROR_OK; + } + int retval = target_read_u16(target, 0x1ffff7e0, flash_size_in_kb); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int ch32vx_probe(struct flash_bank *bank) +{ + struct ch32vx_flash_bank *ch32vx_info = bank->driver_priv; + uint16_t delfault_max_flash_size = 512; + uint32_t flash_size_in_kb; + uint32_t device_id = 0; + uint32_t rom = 0; + uint32_t ram = 0; + int page_size; + uint32_t base_address = (uint32_t)wlink_address; + uint32_t rid = 0; + ch32vx_info->probed = 0; + + /* read ch32 device id register */ + int retval = ch32vx_get_device_id(bank, &device_id); + if (retval != ERROR_OK) + return retval; + if (device_id) + LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + page_size = 1024; + ch32vx_info->ppage_size = 4; + + /* get flash size from target. */ + retval = ch32vx_get_flash_size(bank, &flash_size_in_kb); + + if ((flash_size_in_kb)&&(!flash_unfreeze)&&(riscvchip !=0x09)) + LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + else + flash_size_in_kb = delfault_max_flash_size; + if ((riscvchip == 0x05) || (riscvchip == 0x06)) + { + wlink_getromram(&rom, &ram); + if ((rom != 0) && (ram != 0)) + LOG_INFO("ROM %d kbytes RAM %d kbytes", rom, ram); + } + // /* calculate numbers of pages */ + int num_pages = flash_size_in_kb * 1024 / page_size; + bank->base = base_address; + bank->size = (num_pages * page_size); + bank->num_sectors = num_pages; + bank->sectors = alloc_block_array(0, page_size, num_pages); + ch32vx_info->probed = 1; + + return ERROR_OK; +} + +static int ch32vx_auto_probe(struct flash_bank *bank) +{ + + struct ch32vx_flash_bank *ch32vx_info = bank->driver_priv; + if (ch32vx_info->probed) + return ERROR_OK; + return ch32vx_probe(bank); +} + +COMMAND_HANDLER(ch32vx_handle_unfreeze_command) +{ + + flash_unfreeze=true; + return ERROR_OK; +} + + +static const struct command_registration ch32vx_exec_command_handlers[] = { + { + .name = "unfreeze", + .handler = ch32vx_handle_unfreeze_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "unfreeze entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; +static const struct command_registration ch32vx_command_handlers[] = { + { + .name = "wch_riscv", + .mode = COMMAND_ANY, + .help = "wch_riscv flash command group", + .usage = "", + .chain = ch32vx_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE}; + +const struct flash_driver wch_riscv_flash = { + .name = "wch_riscv", + .commands = ch32vx_command_handlers, + .flash_bank_command = ch32vx_flash_bank_command, + .erase = ch32vx_erase, + .protect = ch32x_protect, + .write = ch32vx_write, + .read = default_flash_read, + .probe = ch32vx_probe, + .auto_probe = ch32vx_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/helper/command.c b/src/helper/command.c old mode 100644 new mode 100755 index 1e769d719..b2d6a76af --- a/src/helper/command.c +++ b/src/helper/command.c @@ -497,6 +497,7 @@ void command_print(struct command_invocation *cmd, const char *format, ...) * * The latter bit isn't precisely neat, but will do for now. */ + Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1); /* We already printed it above * command_output_text(context, string); */ diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am old mode 100644 new mode 100755 index 23424f5a2..7a95178f9 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -24,6 +24,7 @@ include %D%/drivers/Makefile.am %D%/interfaces.c \ %D%/tcl.c \ %D%/swim.c \ + %D%/sdi.c \ %D%/commands.h \ %D%/interface.h \ %D%/interfaces.h \ @@ -31,6 +32,7 @@ include %D%/drivers/Makefile.am %D%/jtag.h \ %D%/swd.h \ %D%/swim.h \ + %D%/sdi.h \ %D%/tcl.h STARTUP_TCL_SRCS += %D%/startup.tcl diff --git a/src/jtag/core.c b/src/jtag/core.c old mode 100644 new mode 100755 index bbc9877ee..d171c77af --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1847,7 +1847,7 @@ int adapter_resets(int trst, int srst) return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() || - transport_is_swim()) { + transport_is_swim()|| transport_is_sdi()) { if (trst == TRST_ASSERT) { LOG_ERROR("transport %s has no trst signal", get_current_transport()->name); @@ -1881,7 +1881,7 @@ int adapter_assert_reset(void) return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || - transport_is_swim()) + transport_is_swim()|| transport_is_sdi()) return adapter_system_reset(1); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", @@ -1898,7 +1898,7 @@ int adapter_deassert_reset(void) return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || - transport_is_swim()) + transport_is_swim()|| transport_is_sdi()) return adapter_system_reset(0); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am old mode 100644 new mode 100755 index 887f99bcd..984bb141d --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -185,6 +185,14 @@ endif if XDS110 DRIVERFILES += %D%/xds110.c endif +if WLINKE +DRIVERFILES += %D%/wlinke.c +endif +if CH347 +DRIVERFILES += %D%/ch347.c +endif + + DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c new file mode 100644 index 000000000..a352e4789 --- /dev/null +++ b/src/jtag/drivers/ch347.c @@ -0,0 +1,852 @@ +/*************************************************************************** * + * Driver for CH347-JTAG interface V1.0 * + * * + * Copyright (C) 2022 Nanjing Qinheng Microelectronics Co., Ltd. * + * Web: http://wch.cn * + * Author: WCH@TECH53 * + * * + * CH347 is a high-speed USB bus converter chip that provides UART, I2C * + * and SPI synchronous serial ports and JTAG interface through USB bus. * + * * + * The USB2.0 to JTAG scheme based on CH347 can be used to build * + * customized USB high-speed JTAG debugger and other products. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +/* project specific includes */ +#include +#include +#include +#include + +/* system includes */ +#include +#include +#include +#include +#include + +#define JTAGIO_STA_OUT_TDI (0x10) +#define JTAGIO_STA_OUT_TMS (0x02) +#define JTAGIO_STA_OUT_TCK (0x01) + +#define TDI_H JTAGIO_STA_OUT_TDI +#define TDI_L 0 +#define TMS_H JTAGIO_STA_OUT_TMS +#define TMS_L 0 +#define TCK_H JTAGIO_STA_OUT_TCK +#define TCK_L 0 + +#define KHZ(n) ((n)*UINT64_C(1000)) +#define MHZ(n) ((n)*UINT64_C(1000000)) +#define GHZ(n) ((n)*UINT64_C(1000000000)) + +#define HW_TDO_BUF_SIZE 4096 +#define SF_PACKET_BUF_SIZE 51200 //命令包长度 +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 // USB高速时每个命令包内包含数据长度 +#define USBC_PACKET_USBHS 512 // USB高速时单包最大数据长度 + +#define CH347_CMD_HEADER 3 //协议包头长度 + +// 协议传输格式:CMD(1字节)+ Length(2字节)+ Data +#define CH347_CMD_INFO_RD 0xCA //参数获取,用于获取固件版本、JTAG接口相关参数等 +#define CH347_CMD_JTAG_INIT 0xD0 // JTAG接口初始化命令 +#define CH347_CMD_JTAG_BIT_OP 0xD1 // JTAG接口引脚位控制命令 +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 // JTAG接口引脚位控制并读取命令 +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 // JTAG接口数据移位命令 +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 // JTAG接口数据移位并读取命令 + +#pragma pack(1) + +typedef struct _CH347_info { // 记录CH347引脚状态 + int TMS; + int TDI; + int TCK; + + int buffer_idx; + uint8_t buffer[HW_TDO_BUF_SIZE]; +} _CH347_Info; + +#pragma pack() + +#ifdef _WIN32 +#include +typedef int(__stdcall *pCH347OpenDevice)(unsigned long iIndex); +typedef void(__stdcall *pCH347CloseDevice)(unsigned long iIndex); +typedef unsigned long(__stdcall *pCH347SetTimeout)(unsigned long iIndex, // 指定设备序号 + unsigned long iWriteTimeout, // 指定USB写出数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值) + unsigned long iReadTimeout); // 指定USB读取数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值) +typedef unsigned long(__stdcall *pCH347WriteData)(unsigned long iIndex, // 指定设备序号 + void *oBuffer, // 指向一个足够大的缓冲区,用于保存描述符 + unsigned long *ioLength); // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度 +typedef unsigned long(__stdcall *pCH347ReadData)(unsigned long iIndex, // 指定设备序号 + void *oBuffer, // 指向一个足够大的缓冲区,用于保存描述符 + unsigned long *ioLength); // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度 +typedef unsigned long(__stdcall *pCH347Jtag_INIT)(unsigned long iIndex, // 指定设备序号 + unsigned char iClockRate); // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度 +HMODULE uhModule; +BOOL ugOpen; +unsigned long ugIndex; +pCH347OpenDevice CH347OpenDevice; +pCH347CloseDevice CH347CloseDevice; +pCH347SetTimeout CH347SetTimeout; +pCH347ReadData CH347ReadData; +pCH347WriteData CH347WriteData; +pCH347Jtag_INIT CH347Jtag_INIT; +#elif defined(__linux__) +#include +bool ugOpen; +unsigned long ugIndex = 0; +#endif + +int DevIsOpened; // 设备是否打开 +bool UsbHighDev = true; +unsigned long USBC_PACKET; + +_CH347_Info ch347 = {0, 0, 0, 0, ""}; // 初始化设备结构状态 + +/** + * HexToString - Hex转换字符串函数 + * @param buf 指向一个缓冲区,放置准备转换的Hex数据 + * @param size 指向需要转换数据的长度单元 + * + * @return 返回转换后字符串 + */ +static char *HexToString(uint8_t *buf, uint32_t size) +{ + uint32_t i; + char *str = calloc(size * 2 + 1, 1); + + for (i = 0; i < size; i++) + sprintf(str + 2 * i, "%02x ", buf[i]); + return str; +} + +/** + * CH347_Write - CH347 写方法 + * @param oBuffer 指向一个缓冲区,放置准备写出的数据 + * @param ioLength 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度 + * + * @return 写成功返回1,失败返回0 + */ +static int CH347_Write(void *oBuffer, unsigned long *ioLength) +{ + int ret = -1; + unsigned long wlength = *ioLength, WI; + + if (*ioLength >= HW_TDO_BUF_SIZE) + wlength = HW_TDO_BUF_SIZE; + WI = 0; + while (1) { + ret = CH347WriteData(ugIndex, oBuffer + WI, &wlength); + LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, wlength, HexToString((uint8_t *)oBuffer, wlength), (uint32_t)wlength); + WI += wlength; + if (WI >= *ioLength) + break; + if ((*ioLength - WI) > HW_TDO_BUF_SIZE) + wlength = HW_TDO_BUF_SIZE; + else + wlength = *ioLength - WI; + } + + *ioLength = WI; + return ret; +} + +/** + * CH347_Read - CH347 读方法 + * @param oBuffer 指向一个足够大的缓冲区,用于保存读取的数据 + * @param ioLength 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度 + * + * @return 读成功返回1,失败返回0 + */ +static int CH347_Read(void *oBuffer, unsigned long *ioLength) +{ + unsigned long rlength = *ioLength; + // 单次读取最大允许读取4096B数据,超过则按4096B进行计算 + if (rlength > HW_TDO_BUF_SIZE) + rlength = HW_TDO_BUF_SIZE; + + if (!CH347ReadData(ugIndex, oBuffer, &rlength)) + { + LOG_ERROR("CH347_Read read data failure."); + return false; + } + + LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, rlength, HexToString((uint8_t *)oBuffer, rlength), (uint32_t)rlength); + *ioLength = rlength; + return true; +} + +/** + * CH347_ClockTms - 功能函数,用于在TCK的上升沿改变TMS值,使其Tap状态切换 + * @param BitBangPkt 协议包 + * @param tms 需要改变的TMS值 + * @param BI 协议包长度 + * + * @return 返回协议包长度 + */ +static unsigned long CH347_ClockTms(unsigned char *BitBangPkt, int tms, unsigned long BI) +{ + unsigned char cmd = 0; + + if (tms == 1) + cmd = TMS_H; + else + cmd = TMS_L; + + BitBangPkt[BI++] = cmd | TDI_H | TCK_L; + BitBangPkt[BI++] = cmd | TDI_H | TCK_H; + + ch347.TMS = cmd; + ch347.TDI = TDI_H; + ch347.TCK = TCK_H; + + return BI; +} + +/** + * CH347_IdleClock - 功能函数,确保时钟处于拉低状态 + * @param BitBangPkt 协议包 + * @param BI 协议包长度 + * + * @return 返回协议包长度 + */ +static unsigned long CH347_IdleClock(unsigned char *BitBangPkt, unsigned long BI) +{ + unsigned char byte = 0; + byte |= ch347.TMS ? TMS_H : TMS_L; + byte |= ch347.TDI ? TDI_H : TDI_L; + BitBangPkt[BI++] = byte; + + return BI; +} + +/** + * CH347_TmsChange - 功能函数,通过改变TMS的值来进行状态切换 + * @param tmsValue 需要进行切换的TMS值按切换顺序组成一字节数据 + * @param step 需要读取tmsValue值的位值数 + * @param skip 从tmsValue的skip位处开始计数到step + * + */ +static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip) +{ + int i; + unsigned long BI, retlen, TxLen; + unsigned char BitBangPkt[4096] = ""; + + BI = CH347_CMD_HEADER; + retlen = CH347_CMD_HEADER; + LOG_DEBUG_IO("(TMS Value: %02x..., step = %d, skip = %d)", tmsValue[0], step, skip); + + for (i = skip; i < step; i++) { + retlen = CH347_ClockTms(BitBangPkt, (tmsValue[i / 8] >> (i % 8)) & 0x01, BI); + BI = retlen; + } + BI = CH347_IdleClock(BitBangPkt, BI); + BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP; + BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER; + BitBangPkt[2] = 0; + + TxLen = BI; + + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("JTAG Write send usb data failure."); + return; + } +} + +/** + * CH347_TMS - 由ch347_execute_queue调用 + * @param cmd 上层传递命令参数 + * + */ +static void CH347_TMS(struct tms_command *cmd) +{ + LOG_DEBUG_IO("(step: %d)", cmd->num_bits); + CH347_TmsChange(cmd->bits, cmd->num_bits, 0); +} + +/** + * CH347_Reset - CH347 复位Tap状态函数 + * @brief 连续六个以上TCK且TMS为高将可将状态机置为Test-Logic Reset状态 + * + */ +static int CH347_Reset(void) +{ + unsigned char BitBang[512] = "", BI, i; + unsigned long TxLen; + + BI = CH347_CMD_HEADER; + for (i = 0; i < 7; i++) { + BitBang[BI++] = TMS_H | TDI_H | TCK_L; + BitBang[BI++] = TMS_H | TDI_H | TCK_H; + } + BitBang[BI++] = TMS_H | TDI_H | TCK_L; + + BitBang[0] = CH347_CMD_JTAG_BIT_OP; + BitBang[1] = BI - CH347_CMD_HEADER; + BitBang[2] = 0; + + TxLen = BI; + + if (!CH347_Write(BitBang, &TxLen) && (TxLen != BI)) { + LOG_ERROR("JTAG_Init send usb data failure."); + return false; + } + return true; +} + +/** + * CH347_MovePath - 获取当前Tap状态并切换至cmd传递下去的状态TMS值 + * @param cmd 上层传递命令参数 + * + */ +static void CH347_MovePath(struct pathmove_command *cmd) +{ + int i; + unsigned long BI, retlen = 0, TxLen; + unsigned char BitBangPkt[4096] = ""; + + BI = CH347_CMD_HEADER; + + LOG_DEBUG_IO("(num_states=%d, last_state=%d)", + cmd->num_states, cmd->path[cmd->num_states - 1]); + + for (i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) + retlen = CH347_ClockTms(BitBangPkt, 0, BI); + BI = retlen; + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + retlen = CH347_ClockTms(BitBangPkt, 1, BI); + BI = retlen; + tap_set_state(cmd->path[i]); + } + + BI = CH347_IdleClock(BitBangPkt, BI); + BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP; + BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER; + BitBangPkt[2] = 0; + + TxLen = BI; + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("JTAG Write send usb data failure."); + return; + } +} + +/** + * CH347_MoveState - 切换Tap状态至目标状态stat + * @param stat 预切换目标路径 + * @param skip 需跳过的位数 + * + */ +static void CH347_MoveState(tap_state_t state, int skip) +{ + uint8_t tms_scan; + int tms_len; + + LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), + tap_state_name(state)); + if (tap_get_state() == state) + return; + tms_scan = tap_get_tms_path(tap_get_state(), state); + tms_len = tap_get_tms_path_len(tap_get_state(), state); + CH347_TmsChange(&tms_scan, tms_len, skip); + tap_set_state(state); +} + +/** + * CH347_WriteRead - CH347 批量读写函数 + * @param bits 此次进行读写数据 + * @param nb_bits 传入数据长度 + * @param scan 传入数据的传输方式来确定是否执行数据读取 + * + */ +static void CH347_WriteRead(uint8_t *bits, int nb_bits, enum scan_type scan) +{ + // uint32_t delay = 1000000; + int nb8 = nb_bits / 8; + int nb1 = nb_bits % 8; + int i; + bool IsRead = false; + uint8_t TMS_Bit, TDI_Bit = 0; + uint8_t *tdos = calloc(1, nb_bits / 8 + 32); + static uint8_t BitBangPkt[SF_PACKET_BUF_SIZE]; + static uint8_t byte0[SF_PACKET_BUF_SIZE]; + unsigned char temp[512] = ""; + unsigned char temp_a[512] = ""; + unsigned long BI = 0, TxLen, RxLen, DI, DII, PktDataLen, DLen; + int ret = ERROR_OK; + + // 最后一个TDI位将会按照位带模式输出,其nb1确保不为0,使其能在TMS变化时输出最后1bit数据 + if (nb8 > 0 && nb1 == 0) { + nb8--; + nb1 = 8; + } + + IsRead = (scan == SCAN_IN || scan == SCAN_IO); + DI = BI = 0; + while (DI < (unsigned long)nb8) { + // 构建数据包 + if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS) + PktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS; + else + PktDataLen = nb8 - DI; + + DII = PktDataLen; + + if (IsRead) + BitBangPkt[BI++] = CH347_CMD_JTAG_DATA_SHIFT_RD; + else + BitBangPkt[BI++] = CH347_CMD_JTAG_DATA_SHIFT; + + BitBangPkt[BI++] = (uint8_t)(PktDataLen >> 0) & 0xFF; + BitBangPkt[BI++] = (uint8_t)(PktDataLen >> 8) & 0xFF; + + if (bits) + memcpy(&BitBangPkt[BI], &bits[DI], PktDataLen); + else + memcpy(&BitBangPkt[BI], byte0, PktDataLen); + BI += PktDataLen; + + // 若需回读数据则判断当前BI值进行命令下发 + if (IsRead) { + TxLen = BI; + + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("CH347_WriteRead write usb data failure."); + return; + } + BI = 0; + + ret = ERROR_OK; + while (ret == ERROR_OK && PktDataLen > 0) { + RxLen = PktDataLen + CH347_CMD_HEADER; + if (!(ret = CH347_Read(temp, &RxLen))) { + LOG_ERROR("CH347_WriteRead read usb data failure.\n"); + return; + } + + if (RxLen != TxLen) { + if (!(ret = CH347_Read(temp_a, &TxLen))) { + LOG_ERROR("CH347_WriteRead read usb data failure.\n"); + return; + } + memcpy(&temp[RxLen], temp_a, TxLen); + RxLen += TxLen; + } + + if (RxLen != 0) + memcpy(&tdos[DI], &temp[CH347_CMD_HEADER], (RxLen - CH347_CMD_HEADER)); + PktDataLen -= RxLen; + } + } + + DI += DII; + + // 在传输过程中,若不回读则根据命令包长度将要达到饱和时将命令下发 + if (((SF_PACKET_BUF_SIZE - BI) < USBC_PACKET || (SF_PACKET_BUF_SIZE - BI) == USBC_PACKET)) { + TxLen = BI; + + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("CH347_WriteRead send usb data failure."); + return; + } + BI = 0; + } + } + + // 清空while循环中剩余的命令 + if (BI > 0) { + TxLen = BI; + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("CH347_WriteRead send usb data failure."); + return; + } + BI = 0; + } + + // 构建输出最后1位TDI数据的命令包 + if (bits) { + BitBangPkt[BI++] = IsRead ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP; + DLen = (nb1 * 2) + 1; + BitBangPkt[BI++] = (uint8_t)(DLen >> 0) & 0xFF; + BitBangPkt[BI++] = (uint8_t)(DLen >> 8) & 0xFF; + TMS_Bit = TMS_L; + + for (i = 0; i < nb1; i++) { + if ((bits[nb8] >> i) & 1) + TDI_Bit = TDI_H; + else + TDI_Bit = TDI_L; + + if ((i + 1) == nb1) //最后一位在Exit1-DR状态输出 + TMS_Bit = TMS_H; + BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_L; + BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_H; + } + BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_L; + } + + // 读取Bit-Bang模式下的最后一字节数据 + if (nb1 && IsRead) { + TxLen = BI; + + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("CH347_WriteRead send usb data failure."); + return; + } + BI = 0; + + RxLen = TxLen + CH347_CMD_HEADER; + if (!(ret = CH347_Read(temp, &RxLen))) { + LOG_ERROR("CH347_WriteRead read usb data failure."); + return; + } + + for (i = 0; ret == true && i < nb1; i++) { + if (temp[CH347_CMD_HEADER + i] & 1) + tdos[nb8] |= (1 << i); + else + tdos[nb8] &= ~(1 << i); + } + } + + // 清空此次批量读写函数中未处理命令 + if (BI > 0) { + TxLen = BI; + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("CH347_WriteRead send usb data failure."); + return; + } + BI = 0; + } + + if (bits) { + memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8)); + } + + free(tdos); + LOG_DEBUG_IO("bits %d str value: [%s].\n", DIV_ROUND_UP(nb_bits, 8), HexToString(bits, DIV_ROUND_UP(nb_bits, 8))); + + // 将TCK、TDI拉低为低电平,因TDI采样在TCK上升沿,若状态未改变,则TDI采样将可能发生在TCK下降沿 + BI = CH347_CMD_HEADER; + BI = CH347_IdleClock(BitBangPkt, BI); + + BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP; + BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER; + BitBangPkt[2] = 0; + + TxLen = BI; + + if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) { + LOG_ERROR("JTAG Write send usb data failure."); + return; + } +} + +static void CH347_RunTest(int cycles, tap_state_t state) +{ + LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); + CH347_MoveState(TAP_IDLE, 0); + + CH347_WriteRead(NULL, cycles, SCAN_OUT); + CH347_MoveState(state, 0); +} + +static void CH347_TableClocks(int cycles) +{ + LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); + CH347_WriteRead(NULL, cycles, SCAN_OUT); +} + +/** + * CH347_Scan - 切换至SHIFT-DR或者SHIFT-IR状态进行扫描 + * @param cmd 上层传递命令参数 + * + * @return 成功返回ERROR_OK + */ +static int CH347_Scan(struct scan_command *cmd) +{ + int scan_bits; + uint8_t *buf = NULL; + enum scan_type type; + int ret = ERROR_OK; + static const char *const type2str[] = {"", "SCAN_IN", "SCAN_OUT", "SCAN_IO"}; + char *log_buf = NULL; + + type = jtag_scan_type(cmd); + scan_bits = jtag_build_buffer(cmd, &buf); + + if (cmd->ir_scan) + CH347_MoveState(TAP_IRSHIFT, 0); + else + CH347_MoveState(TAP_DRSHIFT, 0); + + log_buf = HexToString(buf, DIV_ROUND_UP(scan_bits, 8)); + LOG_DEBUG_IO("Scan"); + LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, + cmd->ir_scan ? "IRSCAN" : "DRSCAN", + type2str[type], + scan_bits, log_buf, cmd->end_state); + + free(log_buf); + + CH347_WriteRead(buf, scan_bits, type); + + ret = jtag_read_buffer(buf, cmd); + free(buf); + + CH347_MoveState(cmd->end_state, 1); + + return ret; +} + +static void CH347_Sleep(int us) +{ + LOG_DEBUG_IO("%s(us=%d)", __func__, us); + jtag_sleep(us); +} + +static int ch347_execute_queue(void) +{ + struct jtag_command *cmd; + static int first_call = 1; + int ret = ERROR_OK; + + if (first_call) { + first_call--; + CH347_Reset(); + } + + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; + cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RESET: + CH347_Reset(); + break; + case JTAG_RUNTEST: + CH347_RunTest(cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + break; + case JTAG_STABLECLOCKS: + CH347_TableClocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + CH347_MoveState(cmd->cmd.statemove->end_state, 0); + break; + case JTAG_PATHMOVE: + CH347_MovePath(cmd->cmd.pathmove); + break; + case JTAG_TMS: + CH347_TMS(cmd->cmd.tms); + break; + case JTAG_SLEEP: + CH347_Sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + ret = CH347_Scan(cmd->cmd.scan); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; + } + } + return ret; +} + +/** + * ch347_init - CH347 初始化函数 + * + * 执行工作: + * 初始化动态库函数 + * 打开设备 + * @return 成功返回0,失败返回ERROR_FAIL + */ +static int ch347_init(void) +{ + unsigned char clearBuffer[4096] = ""; + unsigned long RxLen = 4096; +#ifdef _WIN32 + //printf("%s-%d-WIN32\n", __func__, __LINE__); + if (uhModule == 0) { + uhModule = LoadLibrary("CH347DLL.DLL"); + if (uhModule) { + CH347OpenDevice = (pCH347OpenDevice)GetProcAddress(uhModule, "CH347OpenDevice"); + CH347CloseDevice = (pCH347CloseDevice)GetProcAddress(uhModule, "CH347CloseDevice"); + CH347ReadData = (pCH347ReadData)GetProcAddress(uhModule, "CH347ReadData"); + CH347WriteData = (pCH347WriteData)GetProcAddress(uhModule, "CH347WriteData"); + CH347SetTimeout = (pCH347SetTimeout)GetProcAddress(uhModule, "CH347SetTimeout"); + CH347Jtag_INIT = (pCH347Jtag_INIT)GetProcAddress(uhModule, "CH347Jtag_INIT"); + if (CH347OpenDevice == NULL || CH347CloseDevice == NULL || CH347SetTimeout == NULL || CH347ReadData == NULL || CH347WriteData == NULL || CH347Jtag_INIT == NULL) { + LOG_ERROR("Jtag_init error "); + return ERROR_FAIL; + } + } + } + DevIsOpened = CH347OpenDevice(ugIndex); +#elif defined(__linux__) + //printf("%s-%d-LINUX\n", __func__, __LINE__); + DevIsOpened = CH347OpenDevice(ugIndex); + ugIndex = DevIsOpened; +#endif + if (!DevIsOpened) { + LOG_ERROR("CH347 Open Error."); + return ERROR_FAIL; + } + + USBC_PACKET = USBC_PACKET_USBHS; // 默认为USB2.0高速,其单次传输USB包大小512字节 + + if (!CH347_Read(clearBuffer, &RxLen)) { + LOG_ERROR("CH347 clear Buffer Error."); + return ERROR_FAIL; + } + + // CH347SetTimeout(ugIndex, 5000, 5000); + + tap_set_state(TAP_RESET); + return 0; +} + +/** + * ch347_quit - CH347 设备释放函数 + * + * 执行工作: + * 复位JTAG引脚信号 + * 关闭 + * @return 一直返回0 + */ +static int ch347_quit(void) +{ + // 退出前将信号线全部设置为低电平 + unsigned long retlen = 5; + unsigned char byte[5] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, 0x00, 0x00}; + + CH347_Write(byte, &retlen); + + if (DevIsOpened) { + CH347CloseDevice(ugIndex); + LOG_INFO("Close the CH347."); + DevIsOpened = false; + } + return 0; +} + +/** + * ch347_speed - CH347 TCK频率设置 + * @param speed 设置的频率大小 + * @return 成功返回ERROR_OK,失败返回FALSE + */ +static int ch347_speed(int speed) +{ + unsigned long i = 0; + int retval = -1; + int speed_clock[6] = {MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)}; + + for (i = 0; i < (sizeof(speed_clock) / sizeof(int)); i++) { + if ((speed >= speed_clock[i]) && (speed <= speed_clock[i + 1])) { + retval = CH347Jtag_INIT(ugIndex, i + 1); + if (!retval) { + LOG_ERROR("Couldn't set CH347 TCK speed"); + return retval; + } else { + break; + } + } else if (speed < speed_clock[0]) { + retval = CH347Jtag_INIT(ugIndex, 0); + if (!retval) { + LOG_ERROR("Couldn't set CH347 TCK speed"); + return retval; + } else { + break; + } + } + } + + return ERROR_OK; +} + +static int ch347_speed_div(int speed, int *khz) +{ + *khz = speed / 1000; + return ERROR_OK; +} + +static int ch347_khz(int khz, int *jtag_speed) +{ + if (khz == 0) { + LOG_ERROR("Couldn't support the adapter speed"); + return ERROR_FAIL; + } + *jtag_speed = khz * 1000; + return ERROR_OK; +} + +COMMAND_HANDLER(ch347_handle_vid_pid_command) +{ + // TODO + return ERROR_OK; +} + +static const struct command_registration ch347_subcommand_handlers[] = { + { + .name = "vid_pid", + .handler = ch347_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "", + .usage = "", + }, + COMMAND_REGISTRATION_DONE}; + +static const struct command_registration ch347_command_handlers[] = { + { + .name = "ch347", + .mode = COMMAND_ANY, + .help = "perform ch347 management", + .chain = ch347_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE}; + +static struct jtag_interface ch347_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ch347_execute_queue, +}; + +struct adapter_driver ch347_adapter_driver = { + .name = "ch347", + .transports = jtag_only, + .commands = ch347_command_handlers, + + .init = ch347_init, + .quit = ch347_quit, + .speed = ch347_speed, + .khz = ch347_khz, + .speed_div = ch347_speed_div, + + .jtag_ops = &ch347_interface, +}; \ No newline at end of file diff --git a/src/jtag/drivers/wlinke.c b/src/jtag/drivers/wlinke.c new file mode 100755 index 000000000..fdbe6ad6d --- /dev/null +++ b/src/jtag/drivers/wlinke.c @@ -0,0 +1,2043 @@ +/* + * WCH_LINLK port debug driver for WCH RISC-V mcu : + CH32V103X;CH32V20X,CH32V30X;CH56X;CH57X;CH58X + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include "cmsis_dap.h" +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include "hidapi.h" +typedef int(__stdcall *pCH375OpenDevice)(unsigned long iIndex); +typedef void(__stdcall *pCH375CloseDevice)(unsigned long iIndex); +typedef unsigned long(__stdcall *pCH375SetTimeout)(unsigned long iIndex, + unsigned long iWriteTimeout, + unsigned long iReadTimeout); +typedef unsigned long(__stdcall *pCH375ReadEndP)(unsigned long iIndex, + unsigned long iPipeNum, + void *iBuffer, + unsigned long *ioLength); +typedef unsigned long(__stdcall *pCH375WriteEndP)(unsigned long iIndex, + unsigned long iPipeNum, + void *iBuffer, + unsigned long *ioLength); +HMODULE hModule = 0; +BOOL gOpen = FALSE; +ULONG gIndex = 0; +pCH375OpenDevice pOpenDev; +pCH375CloseDevice pCloseDev; +pCH375SetTimeout pSetTimeout; +pCH375ReadEndP pReadData; +pCH375WriteEndP pWriteData; +#else +#include "libusb_helper.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +int gIndex = 0; +static const uint16_t wlink_vids[] = {0x1a86, 0}; +static const uint16_t wlink_pids[] = {0x8010, 0}; +struct jtag_libusb_device_handle *wfd = NULL; +int pWriteData(int dev, int endpoint, unsigned char *buf, unsigned long *length) +{ + int ret, pr; + length = (int *)length; + ret = jtag_libusb_bulk_write(wfd, endpoint, buf, *length, 3000, &pr); + if (ret == ERROR_OK) + return 1; + else + return ret; +} +int pReadData(int dev, int endpoint, unsigned char *buf, unsigned long *length) +{ + int ret, pr; + length = (int *)length; + if (endpoint == 1) + { + ret = jtag_libusb_bulk_read(wfd, 0x81, buf, *length, 3000, &pr); + } + else + { + ret = jtag_libusb_bulk_read(wfd, 0x82, buf, *length, 3000, &pr); + } + if (ret == ERROR_OK) + return 1; + else + return ret; +} +#endif +unsigned long wlink_address = 0; +bool wlink549 = false; +bool wlinkw = false; +bool wlinke = false; +bool pageerase = false; +bool powstat =false ; +int iocontrol =0; +unsigned long poutput = -1; +// bool protectcheck=false; +unsigned char riscvchip; +unsigned int chip_type; +unsigned long chipiaddr; +unsigned long pagesize; +unsigned long ramaddr; +bool noloadflag = false; +extern int writeloop; +uint8_t sp=1; +uint8_t flash_op103[ ] ={ + 0x01, 0x11, 0x02, 0xCE, 0x93, 0x77, 0x15, 0x00, 0x99, 0xCF, 0xB7, 0x06, 0x67, 0x45, 0xB7, 0x27, + 0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, + 0xD8, 0xC3, 0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x9D, 0xC7, 0xB7, 0x27, 0x02, 0x40, + 0x98, 0x4B, 0xAD, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, + + 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x63, 0x1F, + 0x07, 0x10, 0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, 0xA9, 0xCB, 0x93, 0x07, + 0xF6, 0x07, 0x9D, 0x83, 0x2E, 0xC6, 0x2D, 0x68, 0x81, 0x76, 0x3E, 0xCA, 0xB7, 0x08, 0x02, 0x00, + 0xB7, 0x27, 0x02, 0x40, 0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0xFD, 0x16, 0x98, 0x4B, + + 0x33, 0x67, 0x17, 0x01, 0x98, 0xCB, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 0x07, 0x04, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x71, 0xEF, 0x98, 0x4B, 0x75, 0x8F, 0x98, 0xCB, 0x32, 0x47, + 0x13, 0x07, 0x07, 0x08, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, 0x69, 0xFB, 0x93, 0x77, + 0x85, 0x00, 0xED, 0xC3, 0x93, 0x07, 0xF6, 0x07, 0x2E, 0xC6, 0x9D, 0x83, 0x37, 0x27, 0x02, 0x40, + + 0x3E, 0xCA, 0x1C, 0x4B, 0xC1, 0x66, 0x37, 0x08, 0x08, 0x00, 0xD5, 0x8F, 0x1C, 0xCB, 0xA1, 0x48, + 0x37, 0x17, 0x00, 0x20, 0xB7, 0x27, 0x02, 0x40, 0x37, 0x03, 0x04, 0x00, 0x94, 0x4B, 0xB3, 0xE6, + 0x06, 0x01, 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0xB2, 0x46, 0x3A, 0x8E, 0x36, 0xC8, + 0x46, 0xCC, 0xC2, 0x46, 0x83, 0x2E, 0x07, 0x00, 0x41, 0x07, 0x23, 0xA0, 0xD6, 0x01, 0xC2, 0x46, + + 0x83, 0x2E, 0x47, 0xFF, 0x23, 0xA2, 0xD6, 0x01, 0xC2, 0x46, 0x83, 0x2E, 0x87, 0xFF, 0x23, 0xA4, + 0xD6, 0x01, 0xC2, 0x46, 0x03, 0x2E, 0xCE, 0x00, 0x23, 0xA6, 0xC6, 0x01, 0x94, 0x4B, 0xB3, 0xE6, + 0x66, 0x00, 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0xC2, 0x46, 0x3A, 0x8E, 0xC1, 0x06, + 0x36, 0xC8, 0xE2, 0x46, 0xFD, 0x16, 0x36, 0xCC, 0xCD, 0xFE, 0xB2, 0x46, 0xD4, 0xCB, 0x94, 0x4B, + + 0x93, 0xE6, 0x06, 0x04, 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0xD4, 0x47, 0xD1, 0x8A, + 0x85, 0xC6, 0xD8, 0x47, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x13, 0x67, 0x47, 0x01, 0xD8, 0xC7, + 0x98, 0x4B, 0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x05, 0x61, 0x02, 0x90, 0x23, 0x20, 0xD8, 0x00, + 0xE9, 0xBD, 0x23, 0x20, 0x03, 0x01, 0x31, 0xBF, 0xB2, 0x46, 0x93, 0x86, 0x06, 0x08, 0x36, 0xC6, + + 0xD2, 0x46, 0xFD, 0x16, 0x36, 0xCA, 0xB9, 0xFA, 0x98, 0x4B, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, + 0x75, 0x8F, 0x98, 0xCB, 0x41, 0x89, 0x19, 0xE1, 0x01, 0x45, 0xF9, 0xB7, 0x2E, 0xC6, 0x0D, 0x06, + 0x02, 0xCA, 0x09, 0x82, 0x32, 0xCC, 0xB7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, + 0xD2, 0x47, 0xB2, 0x46, 0x8A, 0x07, 0xB6, 0x97, 0x9C, 0x43, 0x63, 0x18, 0xF7, 0x02, 0xD2, 0x47, + + 0x32, 0x47, 0x8A, 0x07, 0xBA, 0x97, 0x98, 0x43, 0xF2, 0x47, 0xBA, 0x97, 0x3E, 0xCE, 0xD2, 0x47, + 0x85, 0x07, 0x3E, 0xCA, 0xD2, 0x46, 0x62, 0x47, 0xB2, 0x87, 0xE3, 0xE8, 0xE6, 0xFC, 0xB7, 0x27, + 0x00, 0x20, 0x98, 0x4B, 0xF2, 0x47, 0xE3, 0x09, 0xF7, 0xFA, 0x41, 0x45, 0xB5, 0xBF, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +uint8_t flash_op569[ ] ={ + 0x79, 0x71, 0x22, 0xD4, 0x4A, 0xD0, 0x56, 0xCA, 0x06, 0xD6, 0x26, 0xD2, 0x4E, 0xCE, 0x52, 0xCC, + 0x5A, 0xC8, 0x5E, 0xC6, 0x62, 0xC4, 0x93, 0x77, 0x15, 0x00, 0x2A, 0x84, 0xAE, 0x8A, 0x32, 0x89, + 0xBD, 0xE7, 0x93, 0x77, 0x24, 0x00, 0x99, 0xC7, 0xB7, 0x85, 0x07, 0x00, 0x01, 0x45, 0xA9, 0x2C, + 0x89, 0x47, 0x35, 0xE1, 0x93, 0x77, 0x44, 0x00, 0x91, 0xC7, 0x85, 0x65, 0x56, 0x85, 0xA9, 0x24, + + 0x91, 0x47, 0x31, 0xE9, 0x93, 0x77, 0x84, 0x01, 0x01, 0x4A, 0xD9, 0xC7, 0xB7, 0x14, 0x00, 0x20, + 0x13, 0x09, 0xF9, 0x0F, 0x93, 0x84, 0x04, 0x10, 0x13, 0x59, 0x89, 0x00, 0x01, 0x4A, 0xB3, 0x8A, + 0x9A, 0x40, 0x93, 0x7B, 0x84, 0x00, 0x13, 0x7C, 0x04, 0x01, 0x33, 0x8B, 0x9A, 0x00, 0x63, 0x91, + 0x0B, 0x04, 0x63, 0x0E, 0x0C, 0x04, 0x93, 0x89, 0x04, 0xF0, 0x13, 0x06, 0x00, 0x10, 0xCE, 0x85, + + 0x5A, 0x85, 0x2D, 0x26, 0x13, 0x75, 0xF5, 0x0F, 0x0D, 0xCD, 0xC1, 0x47, 0x29, 0xA0, 0x01, 0x45, + 0x69, 0x2E, 0x85, 0x47, 0x59, 0xD5, 0xB2, 0x50, 0x22, 0x54, 0x92, 0x54, 0x02, 0x59, 0xF2, 0x49, + 0x62, 0x4A, 0xD2, 0x4A, 0x42, 0x4B, 0xB2, 0x4B, 0x22, 0x4C, 0x3E, 0x85, 0x45, 0x61, 0x02, 0x90, + 0x13, 0x06, 0x00, 0x10, 0x93, 0x85, 0x04, 0xF0, 0x5A, 0x85, 0xCD, 0x22, 0x5D, 0xD9, 0xA1, 0x47, + + 0xD9, 0xBF, 0x83, 0xA7, 0x09, 0x00, 0x91, 0x09, 0x3E, 0x9A, 0xE3, 0x9C, 0x34, 0xFF, 0x7D, 0x19, + 0x93, 0x84, 0x04, 0x10, 0xE3, 0x1B, 0x09, 0xF8, 0x41, 0x88, 0x81, 0x47, 0x4D, 0xDC, 0x37, 0x67, + 0x00, 0x20, 0x18, 0x4B, 0xE3, 0x09, 0x47, 0xFB, 0x4D, 0xB7, 0xB7, 0x17, 0x00, 0x40, 0x23, 0x8D, + 0x07, 0x00, 0x1D, 0x47, 0x23, 0x8D, 0xE7, 0x00, 0x23, 0x8C, 0xA7, 0x00, 0x82, 0x80, 0x37, 0x17, + + 0x00, 0x40, 0x83, 0x47, 0xA7, 0x01, 0xE2, 0x07, 0xE1, 0x87, 0xE3, 0xCC, 0x07, 0xFE, 0x23, 0x0D, + 0x07, 0x00, 0x82, 0x80, 0x37, 0x17, 0x00, 0x40, 0x83, 0x47, 0xA7, 0x01, 0xE2, 0x07, 0xE1, 0x87, + 0xE3, 0xCC, 0x07, 0xFE, 0x23, 0x0C, 0xA7, 0x00, 0x82, 0x80, 0x37, 0x17, 0x00, 0x40, 0x83, 0x47, + 0xA7, 0x01, 0xE2, 0x07, 0xE1, 0x87, 0xE3, 0xCC, 0x07, 0xFE, 0x03, 0x45, 0x87, 0x01, 0x82, 0x80, + + 0x41, 0x11, 0x22, 0xC4, 0x2A, 0x84, 0x41, 0x81, 0x13, 0x75, 0xF5, 0x0F, 0x06, 0xC6, 0xD9, 0x37, + 0x13, 0x55, 0x84, 0x00, 0x13, 0x75, 0xF5, 0x0F, 0x75, 0x3F, 0x13, 0x75, 0xF4, 0x0F, 0x22, 0x44, + 0xB2, 0x40, 0x41, 0x01, 0x45, 0xBF, 0x41, 0x11, 0x22, 0xC4, 0x2A, 0x84, 0x19, 0x45, 0x06, 0xC6, + 0xAD, 0x3F, 0x71, 0x37, 0x22, 0x85, 0x22, 0x44, 0xB2, 0x40, 0x41, 0x01, 0xBD, 0xB7, 0x01, 0x11, + + 0x22, 0xCC, 0x06, 0xCE, 0x37, 0x04, 0x28, 0x00, 0x9D, 0x3F, 0x15, 0x45, 0xB9, 0x3F, 0x71, 0x3F, + 0x69, 0x3F, 0x2A, 0xC6, 0xAD, 0x37, 0x32, 0x45, 0x05, 0x89, 0x09, 0xC9, 0x7D, 0x14, 0x75, 0xF4, + 0x13, 0x05, 0xF0, 0x0F, 0xF2, 0x40, 0x62, 0x44, 0x05, 0x61, 0x82, 0x80, 0x01, 0x45, 0xDD, 0xBF, + 0x85, 0x67, 0xFD, 0x17, 0x01, 0x11, 0xBE, 0x95, 0xE9, 0x8F, 0x26, 0xCA, 0xAE, 0x97, 0xFD, 0x74, + + 0x22, 0xCC, 0x06, 0xCE, 0x33, 0xF4, 0x97, 0x00, 0x4A, 0xC8, 0x4E, 0xC6, 0xE9, 0x8C, 0xB7, 0x06, + 0x08, 0x00, 0x63, 0xF8, 0xD4, 0x0A, 0xB3, 0x07, 0x94, 0x00, 0x2A, 0x87, 0x13, 0x05, 0xA0, 0x0F, + 0x63, 0xE3, 0xF6, 0x06, 0xB7, 0x17, 0x00, 0x40, 0x93, 0x06, 0x70, 0x05, 0x23, 0x80, 0xD7, 0x00, + 0x93, 0x06, 0x80, 0xFA, 0x23, 0x80, 0xD7, 0x00, 0x83, 0xC6, 0x47, 0x00, 0x3D, 0x65, 0x69, 0x8F, + + 0x93, 0xE6, 0xC6, 0x08, 0x23, 0x82, 0xD7, 0x00, 0x11, 0xE7, 0xB7, 0x09, 0x07, 0x00, 0x41, 0x69, + 0x63, 0xE2, 0x34, 0x05, 0xA2, 0x94, 0x05, 0x69, 0xB3, 0x89, 0x84, 0x40, 0x63, 0x79, 0x24, 0x05, + 0x01, 0x45, 0x37, 0x17, 0x00, 0x40, 0x93, 0x07, 0x70, 0x05, 0x23, 0x00, 0xF7, 0x00, 0x93, 0x07, + 0x80, 0xFA, 0x23, 0x00, 0xF7, 0x00, 0x83, 0x47, 0x47, 0x00, 0x93, 0xF7, 0x37, 0x07, 0x93, 0xE7, + + 0x07, 0x08, 0x23, 0x02, 0xF7, 0x00, 0xF2, 0x40, 0x62, 0x44, 0xD2, 0x44, 0x42, 0x49, 0xB2, 0x49, + 0x05, 0x61, 0x82, 0x80, 0xE3, 0x60, 0x24, 0xFD, 0x13, 0x05, 0x80, 0x0D, 0x29, 0x37, 0x26, 0x85, + 0xC5, 0x35, 0x31, 0x3F, 0x5D, 0xFD, 0xCA, 0x94, 0x33, 0x04, 0x24, 0x41, 0x55, 0xB7, 0x13, 0x05, + 0x00, 0x02, 0xD5, 0x3D, 0x4E, 0x85, 0xE9, 0x35, 0x19, 0x37, 0x45, 0xF5, 0x33, 0x04, 0x24, 0x41, + + 0x61, 0xBF, 0x13, 0x05, 0xE0, 0x0F, 0xC1, 0xB7, 0xB7, 0x17, 0x00, 0x40, 0x83, 0xC7, 0x47, 0x00, + 0xC1, 0x8B, 0x91, 0xE3, 0x31, 0xBF, 0x13, 0x05, 0xB0, 0x0F, 0x82, 0x80, 0x01, 0x11, 0x22, 0xCC, + 0x37, 0x04, 0x00, 0x10, 0x71, 0x14, 0x69, 0x8C, 0x21, 0x65, 0x2A, 0x94, 0x06, 0xCE, 0x26, 0xCA, + 0x4A, 0xC8, 0x4E, 0xC6, 0x37, 0x07, 0x08, 0x00, 0x13, 0x05, 0xE0, 0x0F, 0x63, 0x71, 0xE4, 0x0E, + + 0xB3, 0x07, 0xC4, 0x00, 0x13, 0x05, 0xA0, 0x0F, 0x63, 0x6B, 0xF7, 0x0C, 0xB7, 0x17, 0x00, 0x40, + 0x03, 0xC7, 0x47, 0x00, 0x13, 0x05, 0xB0, 0x0F, 0x41, 0x8B, 0x71, 0xE3, 0x13, 0x07, 0x70, 0x05, + 0x23, 0x80, 0xE7, 0x00, 0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x00, 0x03, 0xC7, 0x47, 0x00, + 0x2E, 0x89, 0x93, 0x59, 0x26, 0x00, 0x13, 0x67, 0xC7, 0x08, 0x23, 0x82, 0xE7, 0x00, 0xB7, 0x14, + + 0x00, 0x40, 0x63, 0x94, 0x09, 0x00, 0x01, 0x45, 0x8D, 0xA8, 0x09, 0x45, 0xA9, 0x3D, 0x22, 0x85, + 0x05, 0x3D, 0x33, 0x05, 0x24, 0x41, 0x11, 0x09, 0x83, 0x27, 0xC9, 0xFF, 0xDC, 0xC8, 0x83, 0xC7, + 0xA4, 0x01, 0x93, 0xE7, 0x07, 0x01, 0x03, 0xC7, 0xA4, 0x01, 0x62, 0x07, 0x61, 0x87, 0xE3, 0x4C, + 0x07, 0xFE, 0x23, 0x8D, 0xF4, 0x00, 0x03, 0xC7, 0xA4, 0x01, 0x62, 0x07, 0x61, 0x87, 0xE3, 0x4C, + + 0x07, 0xFE, 0x23, 0x8D, 0xF4, 0x00, 0x03, 0xC7, 0xA4, 0x01, 0x62, 0x07, 0x61, 0x87, 0xE3, 0x4C, + 0x07, 0xFE, 0x23, 0x8D, 0xF4, 0x00, 0x03, 0xC7, 0xA4, 0x01, 0x62, 0x07, 0x61, 0x87, 0xE3, 0x4C, + 0x07, 0xFE, 0x23, 0x8D, 0xF4, 0x00, 0xFD, 0x19, 0x33, 0x04, 0xA9, 0x00, 0x63, 0x85, 0x09, 0x00, + 0x93, 0x77, 0xF4, 0x0F, 0xCD, 0xF3, 0x21, 0x35, 0x49, 0xD5, 0x37, 0x17, 0x00, 0x40, 0x93, 0x07, + + 0x70, 0x05, 0x23, 0x00, 0xF7, 0x00, 0x93, 0x07, 0x80, 0xFA, 0x23, 0x00, 0xF7, 0x00, 0x83, 0x47, + 0x47, 0x00, 0x93, 0xF7, 0x37, 0x07, 0x93, 0xE7, 0x07, 0x08, 0x23, 0x02, 0xF7, 0x00, 0xF2, 0x40, + 0x62, 0x44, 0xD2, 0x44, 0x42, 0x49, 0xB2, 0x49, 0x05, 0x61, 0x82, 0x80, 0x01, 0x11, 0x4A, 0xC8, + 0x21, 0x69, 0x26, 0xCA, 0x06, 0xCE, 0x22, 0xCC, 0x4E, 0xC6, 0x52, 0xC4, 0x2A, 0x99, 0xB7, 0x07, + + 0x08, 0x00, 0x93, 0x04, 0xE0, 0x0F, 0x63, 0x7C, 0xF9, 0x02, 0xB7, 0x17, 0x00, 0x40, 0x83, 0xC7, + 0x47, 0x00, 0x93, 0x04, 0xB0, 0x0F, 0xC1, 0x8B, 0x9D, 0xE3, 0x2D, 0x45, 0x2E, 0x84, 0x93, 0x54, + 0x26, 0x00, 0x21, 0x33, 0x4A, 0x85, 0xA9, 0x3B, 0x89, 0x33, 0x81, 0x33, 0xFD, 0x59, 0x37, 0x1A, + 0x00, 0x40, 0x13, 0x89, 0xF4, 0xFF, 0x63, 0x1D, 0x39, 0x01, 0x81, 0x44, 0x09, 0x33, 0xF2, 0x40, + + 0x62, 0x44, 0x26, 0x85, 0x42, 0x49, 0xD2, 0x44, 0xB2, 0x49, 0x22, 0x4A, 0x05, 0x61, 0x82, 0x80, + 0x29, 0x3B, 0x21, 0x3B, 0x19, 0x3B, 0x11, 0x3B, 0x11, 0x04, 0x03, 0x27, 0x4A, 0x01, 0x83, 0x27, + 0xC4, 0xFF, 0xE3, 0x1D, 0xF7, 0xFC, 0xCA, 0x84, 0xE9, 0xB7, 0x01, 0x11, 0x22, 0xCC, 0x06, 0xCE, + 0x37, 0x04, 0x28, 0x00, 0xE9, 0x31, 0x15, 0x45, 0x4D, 0x39, 0xC5, 0x39, 0xFD, 0x31, 0x2A, 0xC6, + + 0x7D, 0x39, 0x32, 0x45, 0x93, 0x77, 0x15, 0x00, 0x8D, 0xCB, 0x7D, 0x14, 0x6D, 0xF4, 0x13, 0x05, + 0xF0, 0x0F, 0xF2, 0x40, 0x62, 0x44, 0x05, 0x61, 0x82, 0x80, 0x13, 0x07, 0x40, 0x04, 0x01, 0x45, + 0xE3, 0x89, 0xE7, 0xFE, 0x05, 0x45, 0x01, 0x33, 0x13, 0x05, 0x40, 0x04, 0x65, 0x31, 0x09, 0x45, + 0x55, 0x31, 0x62, 0x44, 0xF2, 0x40, 0x05, 0x61, 0x19, 0xB3, 0x93, 0x77, 0xC5, 0x07, 0xF1, 0xFF, + + 0x01, 0x45, 0xC1, 0xBF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +uint8_t flash_op573[ ] ={ + 0x79, 0x71, 0x22, 0xD4, 0x4A, 0xD0, 0x52, 0xCC, 0x06, 0xD6, 0x26, 0xD2, 0x4E, 0xCE, 0x56, 0xCA, + 0x5A, 0xC8, 0x5E, 0xC6, 0x93, 0x77, 0x15, 0x00, 0x2A, 0x84, 0x2E, 0x8A, 0x32, 0x89, 0x9D, 0xEF, + 0x93, 0x77, 0x24, 0x00, 0x99, 0xCB, 0xB7, 0x86, 0x07, 0x00, 0x01, 0x46, 0x81, 0x45, 0x05, 0x45, + 0x69, 0x22, 0x93, 0x77, 0xF5, 0x0F, 0x09, 0x45, 0x9D, 0xEB, 0x93, 0x77, 0x44, 0x00, 0x91, 0xCB, + + 0x85, 0x66, 0x01, 0x46, 0xD2, 0x85, 0x05, 0x45, 0x8D, 0x2A, 0x93, 0x77, 0xF5, 0x0F, 0x11, 0x45, + 0x99, 0xEF, 0x93, 0x77, 0x84, 0x01, 0x9D, 0xE7, 0x01, 0x45, 0x11, 0xA8, 0x81, 0x46, 0x01, 0x46, + 0x81, 0x45, 0x21, 0x45, 0x99, 0x2A, 0x93, 0x77, 0xF5, 0x0F, 0x05, 0x45, 0xD5, 0xDB, 0xB2, 0x50, + 0x22, 0x54, 0x92, 0x54, 0x02, 0x59, 0xF2, 0x49, 0x62, 0x4A, 0xD2, 0x4A, 0x42, 0x4B, 0xB2, 0x4B, + + 0x45, 0x61, 0x02, 0x90, 0xB7, 0x54, 0x00, 0x20, 0x13, 0x09, 0xF9, 0x0F, 0x93, 0x84, 0x04, 0x10, + 0x93, 0x7B, 0x84, 0x00, 0x13, 0x59, 0x89, 0x00, 0x81, 0x4A, 0x33, 0x0A, 0x9A, 0x40, 0x41, 0x88, + 0x33, 0x0B, 0x9A, 0x00, 0x63, 0x90, 0x0B, 0x02, 0x21, 0xC0, 0x93, 0x89, 0x04, 0xF0, 0x93, 0x06, + 0x00, 0x10, 0x4E, 0x86, 0xDA, 0x85, 0x0D, 0x45, 0x09, 0x22, 0x13, 0x75, 0xF5, 0x0F, 0x19, 0xCD, + + 0x41, 0x45, 0x75, 0xB7, 0x93, 0x06, 0x00, 0x10, 0x13, 0x86, 0x04, 0xF0, 0xDA, 0x85, 0x09, 0x45, + 0xED, 0x20, 0x13, 0x75, 0xF5, 0x0F, 0x69, 0xD9, 0x21, 0x45, 0x51, 0xBF, 0x83, 0xA7, 0x09, 0x00, + 0x91, 0x09, 0xBE, 0x9A, 0xE3, 0x9C, 0x99, 0xFE, 0x7D, 0x19, 0x93, 0x84, 0x04, 0x10, 0xE3, 0x19, + 0x09, 0xFA, 0x3D, 0xD0, 0xB7, 0x67, 0x00, 0x20, 0x9C, 0x4B, 0xE3, 0x8F, 0x57, 0xF5, 0xC9, 0xB7, + + 0x23, 0x03, 0x04, 0x80, 0x95, 0x47, 0x23, 0x03, 0xF4, 0x80, 0x23, 0x02, 0xA4, 0x80, 0x82, 0x80, + 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, 0x07, 0xFE, 0x23, 0x03, 0x04, 0x80, 0x82, 0x80, 0x83, 0x07, + 0x64, 0x80, 0xE3, 0xCE, 0x07, 0xFE, 0x03, 0x45, 0x44, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, + 0xE3, 0xCE, 0x07, 0xFE, 0x23, 0x02, 0xA4, 0x80, 0x82, 0x80, 0x41, 0x11, 0x26, 0xC4, 0x4A, 0xC2, + + 0x4E, 0xC0, 0x06, 0xC6, 0x13, 0x77, 0xF5, 0x0B, 0xAD, 0x47, 0xAA, 0x89, 0x2E, 0x89, 0x95, 0x44, + 0x63, 0x06, 0xF7, 0x00, 0x19, 0x45, 0x6D, 0x37, 0x65, 0x3F, 0x8D, 0x44, 0x4E, 0x85, 0x4D, 0x37, + 0xFD, 0x59, 0xFD, 0x14, 0x63, 0x98, 0x34, 0x01, 0xB2, 0x40, 0xA2, 0x44, 0x12, 0x49, 0x82, 0x49, + 0x41, 0x01, 0x82, 0x80, 0x13, 0x55, 0x09, 0x01, 0x13, 0x75, 0xF5, 0x0F, 0x45, 0x3F, 0x22, 0x09, + + 0xCD, 0xB7, 0x01, 0x11, 0x26, 0xCC, 0x06, 0xCE, 0xB7, 0x04, 0x08, 0x00, 0x51, 0x37, 0x15, 0x45, + 0x85, 0x3F, 0x71, 0x37, 0x69, 0x37, 0x2A, 0xC6, 0xA5, 0x3F, 0x32, 0x45, 0x93, 0x77, 0x15, 0x00, + 0x89, 0xEB, 0x13, 0x65, 0x15, 0x00, 0x13, 0x75, 0xF5, 0x0F, 0xF2, 0x40, 0xE2, 0x44, 0x05, 0x61, + 0x82, 0x80, 0xFD, 0x14, 0xE9, 0xFC, 0x01, 0x45, 0xCD, 0xBF, 0x39, 0x71, 0x26, 0xDC, 0x4A, 0xDA, + + 0x4E, 0xD8, 0x52, 0xD6, 0x56, 0xD4, 0x5A, 0xD2, 0x5E, 0xD0, 0x06, 0xDE, 0x62, 0xCE, 0x66, 0xCC, + 0xB7, 0xE7, 0x00, 0xE0, 0x7D, 0x57, 0x83, 0xAA, 0x07, 0x00, 0x22, 0xC6, 0x03, 0xAA, 0x47, 0x00, + 0x23, 0xA0, 0xE7, 0x18, 0x23, 0xA2, 0xE7, 0x18, 0xB7, 0x17, 0x00, 0x40, 0x13, 0x07, 0x70, 0x05, + 0x23, 0x80, 0xE7, 0x04, 0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, 0x83, 0xC7, 0x47, 0x04, + + 0x13, 0x09, 0x75, 0xFF, 0xB6, 0x84, 0xE2, 0x07, 0x13, 0x79, 0xF9, 0x0F, 0x85, 0x46, 0xAA, 0x89, + 0xAE, 0x8B, 0x32, 0x8B, 0x37, 0x24, 0x00, 0x40, 0xE1, 0x87, 0x01, 0x57, 0x63, 0xFA, 0x26, 0x01, + 0x63, 0x08, 0xD5, 0x00, 0x89, 0x46, 0x13, 0x07, 0x00, 0x02, 0x63, 0x13, 0xD5, 0x00, 0x01, 0x57, + 0xD9, 0x8F, 0x93, 0xF7, 0xF7, 0x0F, 0xB7, 0x1C, 0x00, 0x40, 0x23, 0x82, 0xFC, 0x04, 0x11, 0x47, + + 0x23, 0x03, 0xE4, 0x80, 0x13, 0x05, 0xF0, 0x0F, 0x65, 0x3D, 0x09, 0x4C, 0xD1, 0x35, 0x63, 0x69, + 0x2C, 0x11, 0xB7, 0x07, 0x07, 0x00, 0xBE, 0x9B, 0x37, 0x87, 0x07, 0x00, 0x79, 0x55, 0x63, 0xFE, + 0xEB, 0x02, 0xB3, 0x87, 0x9B, 0x00, 0x63, 0x6A, 0xF7, 0x02, 0xA9, 0x47, 0x63, 0x99, 0xF9, 0x06, + 0x89, 0xE4, 0x81, 0x44, 0x71, 0x3D, 0x26, 0x85, 0x0D, 0xA0, 0xDE, 0x85, 0x09, 0x45, 0x75, 0x3D, + + 0x05, 0x0B, 0x03, 0x45, 0xFB, 0xFF, 0xFD, 0x14, 0x85, 0x0B, 0x4D, 0x35, 0x81, 0xC4, 0x93, 0xF7, + 0xFB, 0x0F, 0xFD, 0xF7, 0xFD, 0x35, 0x69, 0xFD, 0x7D, 0x55, 0xB7, 0x17, 0x00, 0x40, 0x13, 0x07, + 0x70, 0x05, 0x23, 0x80, 0xE7, 0x04, 0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, 0x03, 0xC7, + 0x47, 0x04, 0x41, 0x8B, 0x23, 0x82, 0xE7, 0x04, 0xF2, 0x50, 0xB7, 0xE7, 0x00, 0xE0, 0x23, 0xA0, + + 0x57, 0x11, 0x23, 0xA2, 0x47, 0x11, 0xE2, 0x54, 0x32, 0x44, 0x52, 0x59, 0xC2, 0x59, 0x32, 0x5A, + 0xA2, 0x5A, 0x12, 0x5B, 0x82, 0x5B, 0x72, 0x4C, 0xE2, 0x4C, 0x21, 0x61, 0x82, 0x80, 0xA5, 0x47, + 0x63, 0x95, 0xF9, 0x06, 0x85, 0x69, 0x13, 0x09, 0xF0, 0x0F, 0xB3, 0x06, 0x99, 0x00, 0xB3, 0xF4, + 0x2B, 0x01, 0xB6, 0x94, 0x13, 0x49, 0xF9, 0xFF, 0xB3, 0x74, 0x99, 0x00, 0x41, 0x6B, 0x33, 0x79, + + 0x79, 0x01, 0x85, 0x6B, 0x93, 0x87, 0xF9, 0xFF, 0xB3, 0xF7, 0x27, 0x01, 0x99, 0xE3, 0x63, 0xFC, + 0x34, 0x01, 0x93, 0xD9, 0x49, 0x00, 0xC1, 0x47, 0xE3, 0xE6, 0x37, 0xFF, 0x99, 0xBF, 0x05, 0x69, + 0xC1, 0x69, 0x7D, 0x19, 0xD9, 0xB7, 0x13, 0x05, 0x80, 0x0D, 0x63, 0x88, 0x69, 0x01, 0x13, 0x05, + 0x00, 0x02, 0x63, 0x84, 0x79, 0x01, 0x13, 0x05, 0x10, 0x08, 0xCA, 0x85, 0xFD, 0x3B, 0x91, 0x35, + + 0x21, 0xDD, 0x4E, 0x99, 0xB3, 0x84, 0x34, 0x41, 0xD9, 0xB7, 0xDE, 0x85, 0x2D, 0x45, 0xF5, 0x33, + 0xDA, 0x94, 0xE3, 0x00, 0x9B, 0xF2, 0x05, 0x0B, 0xD9, 0x33, 0xA3, 0x0F, 0xAB, 0xFE, 0xD5, 0xBF, + 0x93, 0x87, 0xF9, 0xFF, 0x93, 0xF7, 0xF7, 0x0F, 0x63, 0x6C, 0xFC, 0x08, 0x03, 0xC7, 0x5C, 0x04, + 0xB7, 0x07, 0x08, 0x00, 0x13, 0x77, 0x07, 0x02, 0x19, 0xE3, 0xB7, 0x87, 0x07, 0x00, 0x79, 0x55, + + 0xE3, 0xFD, 0xFB, 0xF0, 0x33, 0x87, 0x9B, 0x00, 0xE3, 0xE9, 0xE7, 0xF0, 0x89, 0x47, 0x63, 0x90, + 0xF9, 0x04, 0x89, 0x80, 0x55, 0x49, 0xE3, 0x8E, 0x04, 0xEC, 0xDE, 0x85, 0x09, 0x45, 0x71, 0x3B, + 0x11, 0x0B, 0x03, 0x27, 0xCB, 0xFF, 0x91, 0x47, 0x23, 0x20, 0xE4, 0x80, 0x03, 0x07, 0x64, 0x80, + 0xE3, 0x4E, 0x07, 0xFE, 0x23, 0x03, 0x24, 0x81, 0xFD, 0x17, 0xED, 0xFB, 0xFD, 0x14, 0x91, 0x0B, + + 0x81, 0xC4, 0x93, 0xF7, 0xFB, 0x0F, 0xE9, 0xFF, 0x6D, 0x3B, 0x71, 0xF5, 0xF1, 0xB5, 0x85, 0x47, + 0xE3, 0x87, 0xF9, 0xF4, 0xDE, 0x85, 0x2D, 0x45, 0x8D, 0x33, 0x13, 0x89, 0xF4, 0xFF, 0xE3, 0x8A, + 0x04, 0xE8, 0x35, 0x3B, 0x93, 0x77, 0x39, 0x00, 0x91, 0xEB, 0x83, 0x26, 0x04, 0x80, 0x03, 0x27, + 0x0B, 0x00, 0x93, 0x07, 0x4B, 0x00, 0xE3, 0x9F, 0xE6, 0xE6, 0x3E, 0x8B, 0xCA, 0x84, 0xF1, 0xBF, + + 0xA1, 0x47, 0x63, 0x92, 0xF9, 0x04, 0xB5, 0x3B, 0x81, 0x44, 0x63, 0x8D, 0x0B, 0x00, 0x8D, 0x47, + 0x93, 0x04, 0xC0, 0x03, 0x63, 0x88, 0xFB, 0x00, 0x93, 0x04, 0x00, 0x05, 0x63, 0x84, 0x8B, 0x01, + 0x93, 0x04, 0x40, 0x04, 0x13, 0x75, 0xC5, 0x07, 0xE3, 0x05, 0x95, 0xE4, 0x19, 0x45, 0xC9, 0x39, + 0xC5, 0x31, 0x05, 0x45, 0xF1, 0x31, 0x26, 0x85, 0xD5, 0x39, 0x09, 0x45, 0xC5, 0x39, 0x91, 0x33, + + 0xE3, 0x19, 0x05, 0xE2, 0x91, 0xBD, 0xE3, 0x86, 0x09, 0xE2, 0xF1, 0x54, 0x25, 0xB5, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +uint8_t flash_op307[ ] ={ + 0x01, 0x11, 0x02, 0xCE, 0x93, 0x77, 0x15, 0x00, 0x99, 0xCF, 0xB7, 0x06, 0x67, 0x45, 0xB7, 0x27, + 0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, + 0xD8, 0xC3, 0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x95, 0xC7, 0xB7, 0x27, 0x02, 0x40, + 0x98, 0x4B, 0xAD, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, + + 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x61, 0xEB, + 0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, 0xA9, 0xCB, 0x93, 0x07, 0xF6, 0x0F, + 0xA1, 0x83, 0x2E, 0xC6, 0x2D, 0x68, 0x81, 0x76, 0x3E, 0xCA, 0xB7, 0x08, 0x02, 0x00, 0xB7, 0x27, + 0x02, 0x40, 0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0xFD, 0x16, 0x98, 0x4B, 0x33, 0x67, + + 0x17, 0x01, 0x98, 0xCB, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, + 0xD8, 0x47, 0x05, 0x8B, 0x41, 0xEB, 0x98, 0x4B, 0x75, 0x8F, 0x98, 0xCB, 0x32, 0x47, 0x13, 0x07, + 0x07, 0x10, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, 0x69, 0xFB, 0x93, 0x77, 0x85, 0x00, + 0xD5, 0xCB, 0x93, 0x07, 0xF6, 0x0F, 0x2E, 0xC6, 0xA1, 0x83, 0x3E, 0xCA, 0x37, 0x27, 0x02, 0x40, + + 0x1C, 0x4B, 0xC1, 0x66, 0x41, 0x68, 0xD5, 0x8F, 0x1C, 0xCB, 0xB7, 0x16, 0x00, 0x20, 0xB7, 0x27, + 0x02, 0x40, 0x93, 0x08, 0x00, 0x04, 0x37, 0x03, 0x20, 0x00, 0x98, 0x4B, 0x33, 0x67, 0x07, 0x01, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x75, 0xFF, 0x32, 0x47, 0x3A, 0xC8, 0x46, 0xCC, 0x62, 0x47, + 0x0D, 0xEF, 0x98, 0x4B, 0x33, 0x67, 0x67, 0x00, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x75, 0xFF, + + 0xD8, 0x47, 0x41, 0x8B, 0x39, 0xC3, 0xD8, 0x47, 0xC1, 0x76, 0xFD, 0x16, 0x13, 0x67, 0x07, 0x01, + 0xD8, 0xC7, 0x98, 0x4B, 0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x05, 0x61, 0x02, 0x90, 0x23, 0x20, + 0xD8, 0x00, 0x25, 0xB7, 0x23, 0x20, 0x03, 0x01, 0xA5, 0xB7, 0x42, 0x47, 0x13, 0x8E, 0x46, 0x00, + 0x94, 0x42, 0x14, 0xC3, 0x42, 0x47, 0x11, 0x07, 0x3A, 0xC8, 0x62, 0x47, 0x7D, 0x17, 0x3A, 0xCC, + + 0xD8, 0x47, 0x09, 0x8B, 0x75, 0xFF, 0xF2, 0x86, 0x5D, 0xB7, 0x32, 0x47, 0x13, 0x07, 0x07, 0x10, + 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, 0x49, 0xF3, 0x98, 0x4B, 0xC1, 0x76, 0xFD, 0x16, + 0x75, 0x8F, 0x98, 0xCB, 0x41, 0x89, 0x19, 0xE1, 0x01, 0x45, 0x45, 0xBF, 0x2E, 0xC6, 0x0D, 0x06, + 0x02, 0xCA, 0x09, 0x82, 0x32, 0xCC, 0xB7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, + + 0xD2, 0x47, 0xB2, 0x46, 0x8A, 0x07, 0xB6, 0x97, 0x9C, 0x43, 0x63, 0x18, 0xF7, 0x02, 0xD2, 0x47, + 0x32, 0x47, 0x8A, 0x07, 0xBA, 0x97, 0x98, 0x43, 0xF2, 0x47, 0xBA, 0x97, 0x3E, 0xCE, 0xD2, 0x47, + 0x85, 0x07, 0x3E, 0xCA, 0xD2, 0x46, 0x62, 0x47, 0xB2, 0x87, 0xE3, 0xE8, 0xE6, 0xFC, 0xB7, 0x27, + 0x00, 0x20, 0x98, 0x4B, 0xF2, 0x47, 0xE3, 0x09, 0xF7, 0xFA, 0x41, 0x45, 0xB9, 0xBF, 0xff, 0xff, + + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +uint8_t flash_op003[ ] ={//v003 + 0x11, 0x11, 0x22, 0xCC, 0x26, 0xCA, 0x02, 0xC8, 0x93, 0x77, 0x15, 0x00, 0x99, 0xCF, 0xB7, 0x06, + 0x67, 0x45, 0xB7, 0x27, 0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, + 0x13, 0x07, 0xB7, 0x9A, 0xD8, 0xC3, 0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x9D, 0xC7, + 0xB7, 0x27, 0x02, 0x40, 0x98, 0x4B, 0xAD, 0x66, 0x37, 0x33, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, + + 0x98, 0xCB, 0x98, 0x4B, 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, + 0x05, 0x8B, 0x63, 0x16, 0x07, 0x10, 0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, + 0xA9, 0xCB, 0x93, 0x07, 0xF6, 0x03, 0x99, 0x83, 0x2E, 0xC0, 0x2D, 0x63, 0x81, 0x76, 0x3E, 0xC4, + 0xB7, 0x32, 0x00, 0x40, 0xB7, 0x27, 0x02, 0x40, 0x13, 0x03, 0xA3, 0xAA, 0xFD, 0x16, 0x98, 0x4B, + + 0xB7, 0x03, 0x02, 0x00, 0x33, 0x67, 0x77, 0x00, 0x98, 0xCB, 0x02, 0x47, 0xD8, 0xCB, 0x98, 0x4B, + 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x69, 0xE7, 0x98, 0x4B, 0x75, 0x8F, + 0x98, 0xCB, 0x02, 0x47, 0x13, 0x07, 0x07, 0x04, 0x3A, 0xC0, 0x22, 0x47, 0x7D, 0x17, 0x3A, 0xC4, + 0x79, 0xF7, 0x93, 0x77, 0x85, 0x00, 0xF1, 0xCF, 0x93, 0x07, 0xF6, 0x03, 0x2E, 0xC0, 0x99, 0x83, + + 0x37, 0x27, 0x02, 0x40, 0x3E, 0xC4, 0x1C, 0x4B, 0xC1, 0x66, 0x2D, 0x63, 0xD5, 0x8F, 0x1C, 0xCB, + 0x37, 0x07, 0x00, 0x20, 0x13, 0x07, 0x07, 0x20, 0xB7, 0x27, 0x02, 0x40, 0xB7, 0x03, 0x08, 0x00, + 0xB7, 0x32, 0x00, 0x40, 0x13, 0x03, 0xA3, 0xAA, 0x94, 0x4B, 0xB3, 0xE6, 0x76, 0x00, 0x94, 0xCB, + 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0x82, 0x46, 0xBA, 0x84, 0x37, 0x04, 0x04, 0x00, 0x36, 0xC2, + + 0xC1, 0x46, 0x36, 0xC6, 0x92, 0x46, 0x84, 0x40, 0x11, 0x07, 0x84, 0xC2, 0x94, 0x4B, 0xC1, 0x8E, + 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xB1, 0xEA, 0x92, 0x46, 0xBA, 0x84, 0x91, 0x06, 0x36, 0xC2, + 0xB2, 0x46, 0xFD, 0x16, 0x36, 0xC6, 0xF9, 0xFE, 0x82, 0x46, 0xD4, 0xCB, 0x94, 0x4B, 0x93, 0xE6, + 0x06, 0x04, 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0x85, 0xEE, 0xD4, 0x47, 0xC1, 0x8A, 0x85, 0xCE, + + 0xD8, 0x47, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x13, 0x67, 0x07, 0x01, 0xD8, 0xC7, 0x98, 0x4B, + 0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x62, 0x44, 0xD2, 0x44, 0x71, 0x01, 0x02, 0x90, 0x23, 0x20, + 0xD3, 0x00, 0xF5, 0xB5, 0x23, 0xA0, 0x62, 0x00, 0x3D, 0xB7, 0x23, 0xA0, 0x62, 0x00, 0x55, 0xB7, + 0x23, 0xA0, 0x62, 0x00, 0xC1, 0xB7, 0x82, 0x46, 0x93, 0x86, 0x06, 0x04, 0x36, 0xC0, 0xA2, 0x46, + + 0xFD, 0x16, 0x36, 0xC4, 0xB5, 0xF2, 0x98, 0x4B, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x75, 0x8F, + 0x98, 0xCB, 0x41, 0x89, 0x19, 0xE1, 0x01, 0x45, 0x7D, 0xBF, 0x2E, 0xC0, 0x0D, 0x06, 0x02, 0xC4, + 0x09, 0x82, 0xB7, 0x07, 0x00, 0x20, 0x32, 0xC6, 0x93, 0x87, 0x07, 0x20, 0x94, 0x43, 0x13, 0x87, + 0x47, 0x00, 0xA2, 0x47, 0x02, 0x46, 0x8A, 0x07, 0xB2, 0x97, 0x9C, 0x43, 0x63, 0x99, 0xF6, 0x02, + + 0xA2, 0x47, 0x82, 0x46, 0x8A, 0x07, 0xB6, 0x97, 0x94, 0x43, 0xC2, 0x47, 0xB6, 0x97, 0x3E, 0xC8, + 0xA2, 0x47, 0x85, 0x07, 0x3E, 0xC4, 0x22, 0x46, 0xB2, 0x46, 0xBA, 0x87, 0xE3, 0x68, 0xD6, 0xFC, + 0xB7, 0x07, 0x00, 0x20, 0x03, 0xA7, 0x07, 0x61, 0xC2, 0x47, 0xE3, 0x06, 0xF7, 0xFA, 0x41, 0x45, + 0x9D, 0xB7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +uint8_t flash_op8571[ ]={//CH8571 + 0x01, 0x11, 0x22, 0xCE, 0x26, 0xCC, 0x2E, 0xC0, 0x32, 0xC2, 0x93, 0x77, 0x25, 0x00, 0x63, 0x8D, + 0x07, 0x22, 0xB7, 0x17, 0x00, 0x40, 0x83, 0xC7, 0x07, 0x08, 0x9D, 0x8B, 0x3E, 0xCA, 0xD2, 0x47, + 0x63, 0x9C, 0x07, 0x4A, 0x85, 0x47, 0x3E, 0xC8, 0xB7, 0x17, 0x00, 0x40, 0x02, 0xC4, 0x93, 0x04, + 0xF0, 0x04, 0x93, 0x82, 0xD7, 0x03, 0xFD, 0x53, 0x7D, 0x53, 0x79, 0x56, 0xF5, 0x55, 0x15, 0x44, + + 0x23, 0x8F, 0x97, 0x02, 0x23, 0x80, 0x62, 0x00, 0xA3, 0x8D, 0x07, 0x02, 0x23, 0x8E, 0xC7, 0x02, + 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x19, 0x47, 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, + 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, 0x83, 0xC6, + 0xF7, 0x03, 0x85, 0x8A, 0xED, 0xFE, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, + + 0xB7, 0x02, 0x93, 0x06, 0x80, 0xFD, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xC1, 0x82, 0x93, 0xF6, + 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xA1, 0x82, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, + 0xD7, 0x02, 0xA2, 0x46, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0x23, 0x8E, 0xC7, 0x02, + 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, 0x03, 0xC7, 0xF7, 0x03, + + 0x05, 0x8B, 0x6D, 0xFF, 0x23, 0x8F, 0x07, 0x02, 0x23, 0x80, 0x02, 0x00, 0x22, 0x47, 0xC1, 0x66, + 0x36, 0x97, 0x3A, 0xC4, 0x42, 0x47, 0x7D, 0x17, 0x3A, 0xC8, 0x3D, 0xF3, 0x85, 0x47, 0x3E, 0xC8, + 0xB7, 0x17, 0x00, 0x40, 0x93, 0x04, 0xF0, 0x04, 0x93, 0x82, 0xD7, 0x03, 0xFD, 0x53, 0x7D, 0x53, + 0x79, 0x56, 0xF5, 0x55, 0x15, 0x44, 0x23, 0x8F, 0x97, 0x02, 0x23, 0x80, 0x62, 0x00, 0xA3, 0x8D, + + 0x07, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x19, 0x47, + 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, + 0xA3, 0x8F, 0x87, 0x02, 0x83, 0xC6, 0xF7, 0x03, 0x85, 0x8A, 0xED, 0xFE, 0x23, 0x8E, 0xC7, 0x02, + 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x93, 0x06, 0x20, 0x05, 0xA3, 0x8F, 0xD7, 0x02, + + 0xA2, 0x46, 0xC1, 0x82, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xA1, 0x82, + 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, + 0xD7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, + 0x87, 0x02, 0x03, 0xC7, 0xF7, 0x03, 0x05, 0x8B, 0x6D, 0xFF, 0x23, 0x8F, 0x07, 0x02, 0x23, 0x80, + + 0x02, 0x00, 0x22, 0x47, 0xA1, 0x66, 0x36, 0x97, 0x3A, 0xC4, 0x42, 0x47, 0x7D, 0x17, 0x3A, 0xC8, + 0x3D, 0xF3, 0x99, 0x47, 0x3E, 0xC8, 0xB7, 0x17, 0x00, 0x40, 0x93, 0x04, 0xF0, 0x04, 0x93, 0x82, + 0xD7, 0x03, 0xFD, 0x53, 0x7D, 0x53, 0x79, 0x56, 0xF5, 0x55, 0x15, 0x44, 0x23, 0x8F, 0x97, 0x02, + 0x23, 0x80, 0x62, 0x00, 0xA3, 0x8D, 0x07, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, + + 0x23, 0x8E, 0xB7, 0x02, 0x19, 0x47, 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, + 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, 0x83, 0xC6, 0xF7, 0x03, 0x85, 0x8A, + 0xED, 0xFE, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x93, 0x06, + 0x00, 0x02, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xC1, 0x82, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, + + 0xD7, 0x02, 0xA2, 0x46, 0xA1, 0x82, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, + 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, + 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, 0x03, 0xC7, 0xF7, 0x03, 0x05, 0x8B, 0x6D, 0xFF, + 0x23, 0x8F, 0x07, 0x02, 0x23, 0x80, 0x02, 0x00, 0x22, 0x47, 0x85, 0x66, 0x36, 0x97, 0x3A, 0xC4, + + 0x42, 0x47, 0x7D, 0x17, 0x3A, 0xC8, 0x3D, 0xF3, 0x93, 0x77, 0x45, 0x00, 0xE9, 0xC3, 0x82, 0x47, + 0x93, 0x04, 0xF0, 0x04, 0xFD, 0x53, 0x3E, 0xC4, 0x92, 0x47, 0x7D, 0x53, 0x79, 0x56, 0x93, 0x87, + 0xF7, 0x0F, 0xA1, 0x83, 0x3E, 0xC6, 0xB7, 0x17, 0x00, 0x40, 0x93, 0x82, 0xD7, 0x03, 0xF5, 0x55, + 0x15, 0x44, 0x23, 0x8F, 0x97, 0x02, 0x23, 0x80, 0x62, 0x00, 0xA3, 0x8D, 0x07, 0x02, 0x23, 0x8E, + + 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x19, 0x47, 0xA3, 0x8F, 0xE7, 0x02, + 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x67, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, + 0x83, 0xC6, 0xF7, 0x03, 0x85, 0x8A, 0xED, 0xFE, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, + 0x23, 0x8E, 0xB7, 0x02, 0x93, 0x06, 0x10, 0xF8, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xC1, 0x82, + + 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0xA1, 0x82, 0x93, 0xF6, 0xF6, 0x0F, + 0xA3, 0x8F, 0xD7, 0x02, 0xA2, 0x46, 0x93, 0xF6, 0xF6, 0x0F, 0xA3, 0x8F, 0xD7, 0x02, 0x23, 0x8E, + 0xC7, 0x02, 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0xA3, 0x8F, 0x87, 0x02, 0x03, 0xC7, + 0xF7, 0x03, 0x05, 0x8B, 0x6D, 0xFF, 0x23, 0x8F, 0x07, 0x02, 0x23, 0x80, 0x02, 0x00, 0x22, 0x47, + + 0x13, 0x07, 0x07, 0x10, 0x3A, 0xC4, 0x32, 0x47, 0x7D, 0x17, 0x3A, 0xC6, 0x3D, 0xF3, 0x93, 0x77, + 0x85, 0x00, 0xF5, 0xCF, 0x02, 0xCA, 0xB7, 0x27, 0x00, 0x40, 0x83, 0xC7, 0x27, 0x00, 0xBD, 0x8B, + 0x99, 0xEF, 0x37, 0x57, 0x00, 0x40, 0x83, 0x47, 0x77, 0x00, 0xE2, 0x07, 0xE1, 0x87, 0x63, 0xD8, + 0x07, 0x00, 0x93, 0x07, 0xA0, 0xFA, 0xA3, 0x02, 0xF7, 0x00, 0x85, 0x47, 0x3E, 0xCA, 0x82, 0x47, + + 0x37, 0x17, 0x00, 0x20, 0xFD, 0x53, 0x3E, 0xC4, 0x92, 0x47, 0xFD, 0x55, 0xF9, 0x56, 0x93, 0x87, + 0xF7, 0x0F, 0xA1, 0x83, 0x3E, 0xC6, 0xB7, 0x17, 0x00, 0x40, 0x93, 0x82, 0xD7, 0x03, 0x75, 0x56, + 0x19, 0x44, 0x93, 0x04, 0xF0, 0x04, 0x23, 0x8F, 0x97, 0x02, 0x23, 0x80, 0xB2, 0x00, 0xA3, 0x8D, + 0x07, 0x02, 0x23, 0x8E, 0xD7, 0x02, 0xA3, 0x8F, 0xB7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, + + 0x87, 0x02, 0x23, 0x8E, 0xD7, 0x02, 0xA3, 0x8F, 0xB7, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0x09, 0x43, + 0xA3, 0x8F, 0x67, 0x02, 0x22, 0x43, 0x93, 0x04, 0xF0, 0x0F, 0x13, 0x53, 0x03, 0x01, 0x13, 0x73, + 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, 0x22, 0x43, 0x13, 0x53, 0x83, 0x00, 0x13, 0x73, 0xF3, 0x0F, + 0xA3, 0x8F, 0x67, 0x02, 0x22, 0x43, 0x13, 0x73, 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, 0x02, 0xC8, + + 0x42, 0x43, 0x63, 0xFD, 0x64, 0x12, 0x23, 0x8E, 0xD7, 0x02, 0xA3, 0x8F, 0x77, 0x02, 0x23, 0x8E, + 0xC7, 0x02, 0x15, 0x43, 0xA3, 0x8F, 0x67, 0x02, 0x03, 0xC3, 0xF7, 0x03, 0x13, 0x73, 0x13, 0x00, + 0xE3, 0x1C, 0x03, 0xFE, 0x23, 0x8F, 0x07, 0x02, 0x23, 0x80, 0x02, 0x00, 0x22, 0x43, 0x13, 0x03, + 0x03, 0x10, 0x1A, 0xC4, 0x32, 0x43, 0x7D, 0x13, 0x1A, 0xC6, 0xE3, 0x14, 0x03, 0xF6, 0xD2, 0x47, + + 0x99, 0xC7, 0xB7, 0x57, 0x00, 0x40, 0x13, 0x07, 0x50, 0x05, 0x23, 0x83, 0xE7, 0x00, 0x41, 0x89, + 0x71, 0xC1, 0x82, 0x47, 0xB7, 0x16, 0x00, 0x20, 0x93, 0x02, 0xF0, 0x04, 0x3E, 0xC4, 0x92, 0x47, + 0x7D, 0x57, 0xF5, 0x55, 0x13, 0x86, 0xF7, 0x0F, 0x21, 0x82, 0xB7, 0x17, 0x00, 0x40, 0x32, 0xC6, + 0x13, 0x85, 0xE7, 0x03, 0x79, 0x56, 0x23, 0x00, 0x55, 0x00, 0xA3, 0x8E, 0xE7, 0x02, 0xA3, 0x8D, + + 0x07, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x19, 0x44, + 0xA3, 0x8F, 0x87, 0x02, 0x23, 0x8E, 0xC7, 0x02, 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, 0xB7, 0x02, + 0x2D, 0x44, 0xA3, 0x8F, 0x87, 0x02, 0x22, 0x43, 0x93, 0x03, 0xF0, 0x0F, 0x13, 0x53, 0x03, 0x01, + 0x13, 0x73, 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, 0x22, 0x43, 0x13, 0x53, 0x83, 0x00, 0x13, 0x73, + + 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, 0x22, 0x43, 0x13, 0x73, 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, + 0xA3, 0x8F, 0x07, 0x02, 0x02, 0xC8, 0x42, 0x43, 0x63, 0xFD, 0x63, 0x06, 0x23, 0x8E, 0xC7, 0x02, + 0xA3, 0x8F, 0xE7, 0x02, 0x23, 0x8E, 0xB7, 0x02, 0x15, 0x43, 0xA3, 0x8F, 0x67, 0x02, 0x03, 0xC3, + 0xF7, 0x03, 0x13, 0x73, 0x13, 0x00, 0xE3, 0x1C, 0x03, 0xFE, 0x23, 0x00, 0x05, 0x00, 0xA3, 0x8E, + + 0x07, 0x02, 0x22, 0x43, 0x13, 0x03, 0x03, 0x10, 0x1A, 0xC4, 0x32, 0x43, 0x7D, 0x13, 0x1A, 0xC6, + 0xE3, 0x13, 0x03, 0xF6, 0x01, 0x45, 0x49, 0xA0, 0x52, 0x47, 0x85, 0x47, 0x63, 0x14, 0xF7, 0x00, + 0x8D, 0x47, 0x91, 0xB6, 0x52, 0x47, 0x89, 0x47, 0x63, 0x14, 0xF7, 0x00, 0x9D, 0x47, 0x25, 0xBE, + 0x52, 0x47, 0x8D, 0x47, 0xE3, 0x1A, 0xF7, 0xB2, 0xBD, 0x47, 0x35, 0xB6, 0x03, 0x43, 0x07, 0x00, + + 0x05, 0x07, 0x13, 0x73, 0xF3, 0x0F, 0xA3, 0x8F, 0x67, 0x02, 0x42, 0x43, 0x05, 0x03, 0x1A, 0xC8, + 0x45, 0xBD, 0x83, 0xC4, 0xF7, 0x03, 0x13, 0x84, 0x16, 0x00, 0x83, 0xC6, 0x06, 0x00, 0x13, 0x83, + 0xF7, 0x03, 0x93, 0xF6, 0xF6, 0x0F, 0x63, 0x8D, 0x96, 0x02, 0x79, 0x57, 0x23, 0x8E, 0xE7, 0x02, + 0x7D, 0x57, 0xA3, 0x8F, 0xE7, 0x02, 0x75, 0x57, 0x23, 0x8E, 0xE7, 0x02, 0x95, 0x47, 0x23, 0x00, + + 0xF3, 0x00, 0xB7, 0x17, 0x00, 0x40, 0x03, 0xC7, 0xF7, 0x03, 0x05, 0x8B, 0x6D, 0xFF, 0x23, 0x8F, + 0x07, 0x02, 0xA3, 0x8E, 0x07, 0x02, 0x41, 0x45, 0x72, 0x44, 0xE2, 0x44, 0x05, 0x61, 0x02, 0x90, + 0xC2, 0x46, 0x85, 0x06, 0x36, 0xC8, 0xA2, 0x86, 0x3D, 0xB7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + +}; +uint8_t flash_op643[ ] = /* CH64x */ +{ + 0x01, 0x11, 0x02, 0xCE, 0x93, 0x77, 0x15, 0x00, 0x99, 0xCF, 0xB7, 0x06, 0x67, 0x45, 0xB7, 0x27, + 0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, + 0xD8, 0xC3, 0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x9D, 0xC7, 0xB7, 0x27, 0x02, 0x40, + 0x98, 0x4B, 0xAD, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, + + 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x63, 0x16, + 0x07, 0x10, 0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, 0xA9, 0xCB, 0x93, 0x07, + 0xF6, 0x0F, 0xA1, 0x83, 0x2E, 0xC6, 0x2D, 0x68, 0x81, 0x76, 0x3E, 0xCA, 0xB7, 0x08, 0x02, 0x00, + 0xB7, 0x27, 0x02, 0x40, 0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0xFD, 0x16, 0x98, 0x4B, + + 0x33, 0x67, 0x17, 0x01, 0x98, 0xCB, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 0x07, 0x04, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x69, 0xE7, 0x98, 0x4B, 0x75, 0x8F, 0x98, 0xCB, 0x32, 0x47, + 0x13, 0x07, 0x07, 0x10, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, 0x69, 0xFB, 0x93, 0x77, + 0x85, 0x00, 0xF1, 0xCF, 0x93, 0x07, 0xF6, 0x0F, 0x2E, 0xC6, 0xA1, 0x83, 0x3E, 0xCA, 0x37, 0x27, + + 0x02, 0x40, 0x1C, 0x4B, 0xC1, 0x66, 0x2D, 0x68, 0xD5, 0x8F, 0x1C, 0xCB, 0xB7, 0x16, 0x00, 0x20, + 0xB7, 0x27, 0x02, 0x40, 0x37, 0x03, 0x08, 0x00, 0x13, 0x0E, 0x00, 0x04, 0xB7, 0x0E, 0x04, 0x00, + 0xB7, 0x38, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0x98, 0x4B, 0x33, 0x67, 0x67, 0x00, 0x98, 0xCB, + 0xD8, 0x47, 0x05, 0x8B, 0x75, 0xFF, 0x32, 0x47, 0x36, 0x8F, 0x3A, 0xC8, 0x72, 0xCC, 0x42, 0x47, + + 0x03, 0x2F, 0x0F, 0x00, 0x91, 0x06, 0x23, 0x20, 0xE7, 0x01, 0x98, 0x4B, 0x33, 0x67, 0xD7, 0x01, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x21, 0xEB, 0x42, 0x47, 0x36, 0x8F, 0x11, 0x07, 0x3A, 0xC8, + 0x62, 0x47, 0x7D, 0x17, 0x3A, 0xCC, 0x61, 0xFF, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, + 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x15, 0xEB, 0xD8, 0x47, 0x41, 0x8B, 0x15, 0xCB, + + 0xD8, 0x47, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x13, 0x67, 0x07, 0x01, 0xD8, 0xC7, 0x98, 0x4B, + 0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x05, 0x61, 0x02, 0x90, 0x23, 0x20, 0xD8, 0x00, 0xF5, 0xB5, + 0x23, 0x20, 0x03, 0x01, 0x3D, 0xB7, 0x23, 0xA0, 0x08, 0x01, 0x65, 0xB7, 0x23, 0xA0, 0x08, 0x01, + 0xD1, 0xB7, 0x32, 0x47, 0x13, 0x07, 0x07, 0x10, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, + + 0x25, 0xF7, 0x98, 0x4B, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x75, 0x8F, 0x98, 0xCB, 0x41, 0x89, + 0x19, 0xE1, 0x01, 0x45, 0xC9, 0xB7, 0x2E, 0xC6, 0x0D, 0x06, 0x02, 0xCA, 0x09, 0x82, 0x32, 0xCC, + 0xB7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, 0xD2, 0x47, 0xB2, 0x46, 0x8A, 0x07, + 0xB6, 0x97, 0x9C, 0x43, 0x63, 0x18, 0xF7, 0x02, 0xD2, 0x47, 0x32, 0x47, 0x8A, 0x07, 0xBA, 0x97, + + 0x98, 0x43, 0xF2, 0x47, 0xBA, 0x97, 0x3E, 0xCE, 0xD2, 0x47, 0x85, 0x07, 0x3E, 0xCA, 0xD2, 0x46, + 0x62, 0x47, 0xB2, 0x87, 0xE3, 0xE8, 0xE6, 0xFC, 0xB7, 0x27, 0x00, 0x20, 0x98, 0x4B, 0xF2, 0x47, + 0xE3, 0x09, 0xF7, 0xFA, 0x41, 0x45, 0x85, 0xBF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +uint8_t flash_op583[ ]={ + 0x79, 0x71, 0x22, 0xD4, 0x4A, 0xD0, 0x56, 0xCA, 0x06, 0xD6, 0x26, 0xD2, 0x4E, 0xCE, 0x52, 0xCC, + 0x5A, 0xC8, 0x5E, 0xC6, 0x62, 0xC4, 0x93, 0x77, 0x15, 0x00, 0x2A, 0x84, 0xAE, 0x8A, 0x32, 0x89, + 0xC1, 0xE3, 0x93, 0x77, 0x24, 0x00, 0x99, 0xCB, 0xB7, 0x86, 0x07, 0x00, 0x01, 0x46, 0x81, 0x45, + 0x05, 0x45, 0x49, 0x2A, 0x93, 0x77, 0xF5, 0x0F, 0x09, 0x45, 0xA5, 0xEF, 0x93, 0x77, 0x44, 0x00, + + 0x91, 0xCB, 0x85, 0x66, 0x01, 0x46, 0xD6, 0x85, 0x05, 0x45, 0xAD, 0x2A, 0x93, 0x77, 0xF5, 0x0F, + 0x11, 0x45, 0xA5, 0xE3, 0x93, 0x77, 0x84, 0x01, 0x01, 0x4A, 0xD9, 0xCF, 0xB7, 0x54, 0x00, 0x20, + 0x13, 0x09, 0xF9, 0x0F, 0x93, 0x84, 0x04, 0x10, 0x13, 0x59, 0x89, 0x00, 0x01, 0x4A, 0xB3, 0x8A, + 0x9A, 0x40, 0x93, 0x7B, 0x84, 0x00, 0x13, 0x7C, 0x04, 0x01, 0x33, 0x8B, 0x9A, 0x00, 0x63, 0x96, + + 0x0B, 0x04, 0x63, 0x06, 0x0C, 0x06, 0x93, 0x89, 0x04, 0xF0, 0x93, 0x06, 0x00, 0x10, 0x4E, 0x86, + 0xDA, 0x85, 0x0D, 0x45, 0x05, 0x2A, 0x13, 0x75, 0xF5, 0x0F, 0x21, 0xC5, 0x41, 0x45, 0x11, 0xA8, + 0x81, 0x46, 0x01, 0x46, 0x81, 0x45, 0x21, 0x45, 0x31, 0x2A, 0x93, 0x77, 0xF5, 0x0F, 0x05, 0x45, + 0xAD, 0xDB, 0xB2, 0x50, 0x22, 0x54, 0x92, 0x54, 0x02, 0x59, 0xF2, 0x49, 0x62, 0x4A, 0xD2, 0x4A, + + 0x42, 0x4B, 0xB2, 0x4B, 0x22, 0x4C, 0x45, 0x61, 0x02, 0x90, 0x93, 0x06, 0x00, 0x10, 0x13, 0x86, + 0x04, 0xF0, 0xDA, 0x85, 0x09, 0x45, 0xFD, 0x20, 0x13, 0x75, 0xF5, 0x0F, 0x5D, 0xD1, 0x21, 0x45, + 0xC9, 0xBF, 0x83, 0xA7, 0x09, 0x00, 0x91, 0x09, 0x3E, 0x9A, 0xE3, 0x9C, 0x34, 0xFF, 0x7D, 0x19, + 0x93, 0x84, 0x04, 0x10, 0xE3, 0x13, 0x09, 0xF8, 0x41, 0x88, 0x01, 0x45, 0x5D, 0xD8, 0xB7, 0x67, + + 0x00, 0x20, 0x9C, 0x4B, 0xE3, 0x87, 0x47, 0xFB, 0x51, 0xBF, 0x23, 0x03, 0x04, 0x80, 0x95, 0x47, + 0x23, 0x03, 0xF4, 0x80, 0x23, 0x02, 0xA4, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, + 0x07, 0xFE, 0x23, 0x03, 0x04, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, 0x07, 0xFE, + 0x03, 0x45, 0x44, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, 0x07, 0xFE, 0x23, 0x02, + + 0xA4, 0x80, 0x82, 0x80, 0x41, 0x11, 0x26, 0xC4, 0x4A, 0xC2, 0x4E, 0xC0, 0x06, 0xC6, 0x13, 0x77, + 0xF5, 0x0B, 0xAD, 0x47, 0xAA, 0x89, 0x2E, 0x89, 0x95, 0x44, 0x63, 0x06, 0xF7, 0x00, 0x19, 0x45, + 0x6D, 0x37, 0x65, 0x3F, 0x8D, 0x44, 0x4E, 0x85, 0x4D, 0x37, 0xFD, 0x59, 0xFD, 0x14, 0x63, 0x98, + 0x34, 0x01, 0xB2, 0x40, 0xA2, 0x44, 0x12, 0x49, 0x82, 0x49, 0x41, 0x01, 0x82, 0x80, 0x13, 0x55, + + 0x09, 0x01, 0x13, 0x75, 0xF5, 0x0F, 0x45, 0x3F, 0x22, 0x09, 0xCD, 0xB7, 0x01, 0x11, 0x26, 0xCC, + 0x06, 0xCE, 0xB7, 0x04, 0x08, 0x00, 0x51, 0x37, 0x15, 0x45, 0x85, 0x3F, 0x71, 0x37, 0x69, 0x37, + 0x2A, 0xC6, 0xA5, 0x3F, 0x32, 0x45, 0x93, 0x77, 0x15, 0x00, 0x89, 0xEB, 0x13, 0x65, 0x15, 0x00, + 0x13, 0x75, 0xF5, 0x0F, 0xF2, 0x40, 0xE2, 0x44, 0x05, 0x61, 0x82, 0x80, 0xFD, 0x14, 0xE9, 0xFC, + + 0x01, 0x45, 0xCD, 0xBF, 0x39, 0x71, 0x26, 0xDC, 0x4A, 0xDA, 0x4E, 0xD8, 0x52, 0xD6, 0x56, 0xD4, + 0x5A, 0xD2, 0x5E, 0xD0, 0x06, 0xDE, 0x62, 0xCE, 0x66, 0xCC, 0xB7, 0xE7, 0x00, 0xE0, 0x7D, 0x57, + 0x83, 0xAA, 0x07, 0x00, 0x22, 0xC6, 0x03, 0xAA, 0x47, 0x00, 0x23, 0xA0, 0xE7, 0x18, 0x23, 0xA2, + 0xE7, 0x18, 0xB7, 0x17, 0x00, 0x40, 0x13, 0x07, 0x70, 0x05, 0x23, 0x80, 0xE7, 0x04, 0x13, 0x07, + + 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, 0x83, 0xC7, 0x47, 0x04, 0x93, 0x0B, 0x75, 0xFF, 0xB6, 0x84, + 0xE2, 0x07, 0x93, 0xFB, 0xFB, 0x0F, 0x85, 0x46, 0xAA, 0x89, 0x2E, 0x8B, 0x32, 0x89, 0x37, 0x24, + 0x00, 0x40, 0xE1, 0x87, 0x01, 0x57, 0x63, 0xFA, 0x76, 0x01, 0x63, 0x08, 0xD5, 0x00, 0x89, 0x46, + 0x13, 0x07, 0x00, 0x02, 0x63, 0x13, 0xD5, 0x00, 0x01, 0x57, 0xD9, 0x8F, 0x93, 0xF7, 0xF7, 0x0F, + + 0xB7, 0x1C, 0x00, 0x40, 0x23, 0x82, 0xFC, 0x04, 0x11, 0x47, 0x23, 0x03, 0xE4, 0x80, 0x13, 0x05, + 0xF0, 0x0F, 0x65, 0x3D, 0x09, 0x4C, 0xD1, 0x35, 0x63, 0x6D, 0x7C, 0x11, 0xB7, 0x05, 0x07, 0x00, + 0xDA, 0x95, 0x37, 0x87, 0x07, 0x00, 0x79, 0x55, 0x63, 0xF2, 0xE5, 0x04, 0xB3, 0x87, 0x95, 0x00, + 0x63, 0x6E, 0xF7, 0x02, 0x37, 0x0B, 0x08, 0x00, 0xA9, 0x47, 0x33, 0xEB, 0x65, 0x01, 0x63, 0x99, + + 0xF9, 0x06, 0x89, 0xE4, 0x81, 0x44, 0x51, 0x3D, 0x26, 0x85, 0x0D, 0xA0, 0xDA, 0x85, 0x09, 0x45, + 0x55, 0x3D, 0x05, 0x09, 0x03, 0x45, 0xF9, 0xFF, 0xFD, 0x14, 0x05, 0x0B, 0x69, 0x3D, 0x81, 0xC4, + 0x93, 0x77, 0xFB, 0x0F, 0xFD, 0xF7, 0xDD, 0x35, 0x69, 0xFD, 0x7D, 0x55, 0xB7, 0x17, 0x00, 0x40, + 0x13, 0x07, 0x70, 0x05, 0x23, 0x80, 0xE7, 0x04, 0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, + + 0x03, 0xC7, 0x47, 0x04, 0x41, 0x8B, 0x23, 0x82, 0xE7, 0x04, 0xF2, 0x50, 0xB7, 0xE7, 0x00, 0xE0, + 0x23, 0xA0, 0x57, 0x11, 0x23, 0xA2, 0x47, 0x11, 0xE2, 0x54, 0x32, 0x44, 0x52, 0x59, 0xC2, 0x59, + 0x32, 0x5A, 0xA2, 0x5A, 0x12, 0x5B, 0x82, 0x5B, 0x72, 0x4C, 0xE2, 0x4C, 0x21, 0x61, 0x82, 0x80, + 0xA5, 0x47, 0x63, 0x95, 0xF9, 0x06, 0x85, 0x69, 0x13, 0x09, 0xF0, 0x0F, 0xB3, 0x06, 0x99, 0x00, + + 0xB3, 0x74, 0x2B, 0x01, 0xB6, 0x94, 0x13, 0x49, 0xF9, 0xFF, 0xB3, 0x74, 0x99, 0x00, 0x85, 0x6B, + 0x33, 0x79, 0x69, 0x01, 0x41, 0x6B, 0x93, 0x87, 0xF9, 0xFF, 0xB3, 0xF7, 0x27, 0x01, 0x99, 0xE3, + 0x63, 0xFC, 0x34, 0x01, 0x93, 0xD9, 0x49, 0x00, 0xC1, 0x47, 0xE3, 0xE6, 0x37, 0xFF, 0x99, 0xBF, + 0x05, 0x69, 0xC1, 0x69, 0x7D, 0x19, 0xD9, 0xB7, 0x13, 0x05, 0x80, 0x0D, 0x63, 0x88, 0x69, 0x01, + + 0x13, 0x05, 0x00, 0x02, 0x63, 0x84, 0x79, 0x01, 0x13, 0x05, 0x10, 0x08, 0xCA, 0x85, 0xDD, 0x3B, + 0x35, 0x3D, 0x21, 0xDD, 0x4E, 0x99, 0xB3, 0x84, 0x34, 0x41, 0xD9, 0xB7, 0xDA, 0x85, 0x2D, 0x45, + 0xD5, 0x33, 0xCA, 0x94, 0xE3, 0x00, 0x99, 0xF2, 0x05, 0x09, 0x7D, 0x3B, 0xA3, 0x0F, 0xA9, 0xFE, + 0xD5, 0xBF, 0x93, 0x87, 0xF9, 0xFF, 0x93, 0xF7, 0xF7, 0x0F, 0x63, 0x61, 0xFC, 0x0C, 0x83, 0xC7, + + 0x1C, 0x04, 0x13, 0x07, 0x30, 0x08, 0x63, 0x1F, 0xF7, 0x04, 0x37, 0x07, 0x08, 0x00, 0x63, 0x6B, + 0xEB, 0x04, 0xB3, 0x07, 0x9B, 0x00, 0xB7, 0x06, 0x10, 0x00, 0x63, 0xF5, 0xD7, 0x04, 0x33, 0x4B, + 0xEB, 0x00, 0x89, 0x47, 0x63, 0x93, 0xF9, 0x06, 0x89, 0x80, 0xD5, 0x49, 0xE3, 0x8C, 0x04, 0xEC, + 0xDA, 0x85, 0x09, 0x45, 0x41, 0x3B, 0x11, 0x09, 0x03, 0x27, 0xC9, 0xFF, 0x91, 0x47, 0x23, 0x20, + + 0xE4, 0x80, 0x03, 0x07, 0x64, 0x80, 0xE3, 0x4E, 0x07, 0xFE, 0x23, 0x03, 0x34, 0x81, 0xFD, 0x17, + 0xED, 0xFB, 0xFD, 0x14, 0x11, 0x0B, 0x81, 0xC4, 0x93, 0x77, 0xFB, 0x0F, 0xE9, 0xFF, 0x7D, 0x33, + 0x71, 0xF5, 0xE1, 0xB5, 0xB7, 0x17, 0x00, 0x40, 0x03, 0xC7, 0x57, 0x04, 0xB7, 0x07, 0x08, 0x00, + 0x13, 0x77, 0x07, 0x02, 0x19, 0xE3, 0xB7, 0x87, 0x07, 0x00, 0x79, 0x55, 0xE3, 0x78, 0xFB, 0xEA, + + 0x33, 0x07, 0x9B, 0x00, 0xE3, 0xFF, 0xE7, 0xF8, 0x55, 0xB5, 0x85, 0x47, 0xE3, 0x82, 0xF9, 0xF2, + 0xDA, 0x85, 0x2D, 0x45, 0x05, 0x3B, 0x93, 0x89, 0xF4, 0xFF, 0xE3, 0x85, 0x04, 0xE6, 0x29, 0x33, + 0x93, 0xF7, 0x39, 0x00, 0x91, 0xEB, 0x83, 0x26, 0x04, 0x80, 0x03, 0x27, 0x09, 0x00, 0x93, 0x07, + 0x49, 0x00, 0xE3, 0x9A, 0xE6, 0xE4, 0x3E, 0x89, 0xCE, 0x84, 0xF1, 0xBF, 0xB5, 0x47, 0x63, 0x96, + + 0xF9, 0x00, 0x13, 0x05, 0x90, 0x0B, 0xD1, 0x31, 0x35, 0xBD, 0xB1, 0x47, 0x13, 0x05, 0xB0, 0x0A, + 0xE3, 0x8B, 0xF9, 0xFE, 0x99, 0x47, 0x63, 0x91, 0xF9, 0x04, 0xB7, 0x05, 0x08, 0x00, 0xB3, 0x65, + 0xBB, 0x00, 0x2D, 0x45, 0xC5, 0x31, 0x81, 0x44, 0x8D, 0x4B, 0xA1, 0x49, 0x75, 0x39, 0x63, 0x96, + 0x74, 0x01, 0x83, 0x27, 0x04, 0x80, 0x23, 0x20, 0xF9, 0x00, 0x85, 0x04, 0xE3, 0x98, 0x34, 0xFF, + + 0x83, 0x27, 0x04, 0x80, 0x13, 0x17, 0x2B, 0x01, 0x63, 0x55, 0x07, 0x00, 0x23, 0x12, 0xF9, 0x00, + 0xD5, 0xBB, 0x23, 0x22, 0xF9, 0x00, 0xFD, 0xB3, 0x9D, 0x47, 0x63, 0x99, 0xF9, 0x02, 0x81, 0x45, + 0x13, 0x05, 0xB0, 0x04, 0x45, 0x31, 0xBD, 0x44, 0x23, 0x20, 0x09, 0x00, 0x23, 0x22, 0x09, 0x00, + 0xFD, 0x59, 0x9D, 0x39, 0x93, 0xF7, 0x74, 0x00, 0xCA, 0x97, 0x03, 0xC7, 0x07, 0x00, 0xFD, 0x14, + + 0x39, 0x8D, 0x23, 0x80, 0xA7, 0x00, 0xE3, 0x96, 0x34, 0xFF, 0x6D, 0xBB, 0xA1, 0x47, 0x63, 0x92, + 0xF9, 0x04, 0x6D, 0x39, 0x81, 0x44, 0x63, 0x0D, 0x0B, 0x00, 0x8D, 0x47, 0x93, 0x04, 0xC0, 0x03, + 0x63, 0x08, 0xFB, 0x00, 0x93, 0x04, 0x00, 0x05, 0x63, 0x04, 0x8B, 0x01, 0x93, 0x04, 0x40, 0x04, + 0x13, 0x75, 0xC5, 0x07, 0xE3, 0x08, 0x95, 0xD8, 0x19, 0x45, 0x01, 0x39, 0x39, 0x39, 0x05, 0x45, + + 0x29, 0x31, 0x26, 0x85, 0x0D, 0x39, 0x09, 0x45, 0x3D, 0x31, 0x49, 0x31, 0xE3, 0x1C, 0x05, 0xD6, + 0x69, 0xBB, 0x91, 0x47, 0x63, 0x99, 0xF9, 0x00, 0x13, 0x05, 0x60, 0x06, 0xFD, 0x36, 0xF5, 0x3E, + 0x13, 0x05, 0x90, 0x09, 0x0D, 0xB7, 0xE3, 0x8F, 0x09, 0xD4, 0xF1, 0x54, 0xA9, 0xBB, 0xff ,0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +uint8_t flash_opl103[ ]={ + 0x01, 0x11, 0x02, 0xCE, 0x93, 0x77, 0x15, 0x00, 0x99, 0xCF, 0xB7, 0x06, 0x67, 0x45, 0xB7, 0x27, + 0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, + 0xD8, 0xC3, 0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x9D, 0xC7, 0xB7, 0x27, 0x02, 0x40, + 0x98, 0x4B, 0xAD, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, + + 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x63, 0x16, + 0x07, 0x10, 0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, 0xA9, 0xCB, 0x93, 0x07, + 0xF6, 0x0F, 0xA1, 0x83, 0x2E, 0xC6, 0x2D, 0x68, 0x81, 0x76, 0x3E, 0xCA, 0xB7, 0x08, 0x02, 0x00, + 0xB7, 0x27, 0x02, 0x40, 0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0xFD, 0x16, 0x98, 0x4B, + + 0x33, 0x67, 0x17, 0x01, 0x98, 0xCB, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 0x07, 0x04, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x69, 0xE7, 0x98, 0x4B, 0x75, 0x8F, 0x98, 0xCB, 0x32, 0x47, + 0x13, 0x07, 0x07, 0x10, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, 0x69, 0xFB, 0x93, 0x77, + 0x85, 0x00, 0xF1, 0xCF, 0x93, 0x07, 0xF6, 0x0F, 0x2E, 0xC6, 0xA1, 0x83, 0x3E, 0xCA, 0x37, 0x27, + + 0x02, 0x40, 0x1C, 0x4B, 0xC1, 0x66, 0x2D, 0x68, 0xD5, 0x8F, 0x1C, 0xCB, 0xB7, 0x16, 0x00, 0x20, + 0xB7, 0x27, 0x02, 0x40, 0x37, 0x03, 0x08, 0x00, 0x13, 0x0E, 0x00, 0x04, 0xB7, 0x0E, 0x04, 0x00, + 0xB7, 0x38, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0x98, 0x4B, 0x33, 0x67, 0x67, 0x00, 0x98, 0xCB, + 0xD8, 0x47, 0x05, 0x8B, 0x75, 0xFF, 0x32, 0x47, 0x36, 0x8F, 0x3A, 0xC8, 0x72, 0xCC, 0x42, 0x47, + + 0x03, 0x2F, 0x0F, 0x00, 0x91, 0x06, 0x23, 0x20, 0xE7, 0x01, 0x98, 0x4B, 0x33, 0x67, 0xD7, 0x01, + 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x21, 0xEB, 0x42, 0x47, 0x36, 0x8F, 0x11, 0x07, 0x3A, 0xC8, + 0x62, 0x47, 0x7D, 0x17, 0x3A, 0xCC, 0x61, 0xFF, 0x32, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, + 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x15, 0xEB, 0xD8, 0x47, 0x41, 0x8B, 0x15, 0xCB, + + 0xD8, 0x47, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x13, 0x67, 0x07, 0x01, 0xD8, 0xC7, 0x98, 0x4B, + 0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x05, 0x61, 0x02, 0x90, 0x23, 0x20, 0xD8, 0x00, 0xF5, 0xB5, + 0x23, 0x20, 0x03, 0x01, 0x3D, 0xB7, 0x23, 0xA0, 0x08, 0x01, 0x65, 0xB7, 0x23, 0xA0, 0x08, 0x01, + 0xD1, 0xB7, 0x32, 0x47, 0x13, 0x07, 0x07, 0x10, 0x3A, 0xC6, 0x52, 0x47, 0x7D, 0x17, 0x3A, 0xCA, + + 0x25, 0xF7, 0x98, 0x4B, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x75, 0x8F, 0x98, 0xCB, 0x41, 0x89, + 0x19, 0xE1, 0x01, 0x45, 0xC9, 0xB7, 0x2E, 0xC6, 0x0D, 0x06, 0x02, 0xCA, 0x09, 0x82, 0x32, 0xCC, + 0xB7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, 0xD2, 0x47, 0xB2, 0x46, 0x8A, 0x07, + 0xB6, 0x97, 0x9C, 0x43, 0x63, 0x18, 0xF7, 0x02, 0xD2, 0x47, 0x32, 0x47, 0x8A, 0x07, 0xBA, 0x97, + + 0x98, 0x43, 0xF2, 0x47, 0xBA, 0x97, 0x3E, 0xCE, 0xD2, 0x47, 0x85, 0x07, 0x3E, 0xCA, 0xD2, 0x46, + 0x62, 0x47, 0xB2, 0x87, 0xE3, 0xE8, 0xE6, 0xFC, 0xB7, 0x27, 0x00, 0x20, 0x98, 0x4B, 0xF2, 0x47, + 0xE3, 0x09, 0xF7, 0xFA, 0x41, 0x45, 0x85, 0xBF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + + + +void wlink_ramcodewrite(uint8_t *buffer, int size) +{ + unsigned long len = 64; + int i = 0; + while (size >= 64) + { + pWriteData(0, 2, buffer + 64 * i, &len); + size -= 64; + i++; + } + if (size) + { + len = size; + pWriteData(0, 2, buffer + 64 * i, &len); + } +} + +void wlink_getromram(uint32_t *rom, uint32_t *ram) +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + bool type_A = false; + bool type_B = false; + bool type_C = false; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x04; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if (chip_type == 0x30700508 || chip_type == 0x30710508 || chip_type == 0x30730508 || chip_type == 0x30300504 || chip_type == 0x30310504) + type_A = true; + if (chip_type == 0x30720508 || chip_type == 0x30740508) + type_C = true; + if (chip_type == 0x2034050c || chip_type == 0x2080050c || chip_type == 0x2081050c || chip_type == 0x2082050c || chip_type == 0x2083050c) + type_B = true; + switch (rxbuf[3]) + { + case 0: + if (type_B) + { + *rom = 128; + *ram = 64; + } + else if (type_A) + { + *rom = 192; + *ram = 128; + } + else if (type_C) + { + *rom = 192; + *ram = 128; + } + else if (riscvchip == 3) + { + *rom = 96; + *ram = 32; + } + else + { + *rom = 0; + *ram = 0; + } + break; + case 1: + if (type_B) + { + *rom = 144; + *ram = 48; + } + else if (type_A) + { + *rom = 224; + *ram = 96; + } + else if (type_C) + { + *rom = 224; + *ram = 96; + } + else if (riscvchip == 3) + { + *rom = 64; + *ram = 64; + } + else + { + *rom = 0; + *ram = 0; + } + break; + case 2: + if (type_B) + { + *rom = 160; + *ram = 32; + } + else if (type_A) + { + *rom = 256; + *ram = 64; + } + else if (type_C) + { + *rom = 0; + *ram = 0; + } + else if (riscvchip == 3) + { + *rom = 32; + *ram = 96; + } + else + { + *rom = 0; + *ram = 0; + } + break; + case 3: + if (type_B) + { + *rom = 160; + *ram = 32; + } + else if (type_A) + { + *rom = 288; + *ram = 32; + } + else if (type_C) + { + *rom = 0; + *ram = 0; + } + else if (riscvchip == 3) + { + *rom = 32; + *ram = 96; + } + else + { + *rom = 0; + *ram = 0; + } + break; + default: + *rom = 0; + *ram = 0; + break; + } +} +void readmcause(); +unsigned char DMI_OP( + unsigned long iIndex, + unsigned char iAddr, + unsigned long iData, + unsigned char iOP, + unsigned char *oAddr, + unsigned long *oData, + unsigned char *oOP) +{ + unsigned char Txbuf[9]; + unsigned char Rxbuf[9]; + unsigned long len; + unsigned char *pData; + unsigned char retrytime; + Txbuf[0] = 0x81; + Txbuf[1] = 0x08; + Txbuf[2] = 0x06; + Txbuf[3] = iAddr; + Txbuf[4] = (unsigned char)(iData >> 24); + Txbuf[5] = (unsigned char)(iData >> 16); + Txbuf[6] = (unsigned char)(iData >> 8); + Txbuf[7] = (unsigned char)(iData); + Txbuf[8] = iOP; + retrytime = 0; +RETRY: + len = 9; + if (pWriteData(gIndex, 1, Txbuf, &len)) + { + memset(Rxbuf, 0, sizeof(Rxbuf)); + len = 9; + + if (pReadData(gIndex, 1, Rxbuf, &len)) + { + + *oAddr = Rxbuf[3]; + if (oData) + { + pData = (unsigned char *)oData; + *pData = Rxbuf[7]; + *(pData + 1) = Rxbuf[6]; + *(pData + 2) = Rxbuf[5]; + *(pData + 3) = Rxbuf[4]; + } + *oOP = Rxbuf[8]; + + retrytime++; + + if (Rxbuf[8] == 2 && Rxbuf[6] == 3) + { + readmcause(); + } + + return true; + } + } + return false; +} + +void wlink_reset() +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0b; + txbuf[2] = 0x01; + txbuf[3] = 0x03; + unsigned char oAddr; + unsigned long oData; + unsigned char oOP; + unsigned char iAddr; + DMI_OP(0, 0x10, 0x80000001, 2, &oAddr, &oData, &oOP); + usleep(1000); + oAddr = 0; + oData = 0; + oOP = 0; + iAddr = 0; + DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP); + usleep(1000); + len = 4; + pWriteData(0, 1, txbuf, &len); + usleep(1000); + usleep(1000); + len = 4; + pReadData(0, 1, rxbuf, &len); + DMI_OP(0, 0x10, 0x80000001, 2, &oAddr, &oData, &oOP); + usleep(1000); + DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP); +} +void wlink_quitreset(void) +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + unsigned char oAddr; + unsigned long oData; + unsigned char oOP; + unsigned char iAddr; + txbuf[0] = 0x81; + txbuf[1] = 0x0b; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + usleep(300000); + DMI_OP(0, 0x10, 0x40000001, 2, &oAddr, &oData, &oOP); + usleep(1000); + oAddr = 0; + oData = 0; + oOP = 0; + iAddr = 0; + DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP); +} +void wlink_softreset(void){ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0b; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + usleep(300000); +} + + +void wlink_clean(void){ + unsigned char txbuf[10]; + unsigned char rxbuf[10]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + pWriteData(0, 1, txbuf, &len); + len = 7; + pReadData(0, 1, rxbuf, &len); + txbuf[1] = 0x0c; + txbuf[2] = 0x02; + txbuf[4] = 0x01; + len=5; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x02; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 8; + pReadData(0, 1, rxbuf, &len); + txbuf[1]=0x0c; + txbuf[2]=0x02; + txbuf[3]=riscvchip; + txbuf[4]=0x01; + len=5; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); +} + +void wlink_chip_reset() +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0b; + txbuf[2] = 0x01; + txbuf[3] = 0x02; + unsigned char oAddr; + unsigned long oData; + unsigned char oOP; + unsigned char iAddr; + DMI_OP(0, 0x10, 0x80000001, 2, &oAddr, &oData, &oOP); + usleep(1000); + oAddr = 0; + oData = 0; + oOP = 0; + iAddr = 0; + DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP); + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); +} +int wlnik_protect_check(void) +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x06; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if (((rxbuf[0] == 0x82) && (rxbuf[1] == 0x06) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x01))) + return 4; + if (((rxbuf[0] == 0x82) && (rxbuf[1] == 0x06) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x02))) + return 5; + return ERROR_FAIL; +} +int wlink_flash_protect(bool stat) +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x06; + txbuf[2] = 0x01; + if (stat) + txbuf[3] = 0x03; + else + txbuf[3] = 0x02; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if (((rxbuf[0] == 0x82) && (rxbuf[1] == 0x06) && (rxbuf[2] == 0x01) && (rxbuf[3] == txbuf[3]))) + { + wlink_reset(); + usleep(300000); + int ret = wlnik_protect_check(); + if ((stat) && (ret == 4)) + return ERROR_OK; + if ((!stat) && (ret == 5)) + return ERROR_OK; + } + return ERROR_FAIL; +} + +int wlink_ready_write(uint32_t address, uint32_t count) +{ + unsigned char txbuf[24]; + unsigned char rxbuf[24]; + unsigned long len = 4; + unsigned long chipiaddr1 = chipiaddr + address; + if (chipiaddr1 >= 0x10000000) + chipiaddr1 -= 0x08000000; + txbuf[0] = 0x81; + txbuf[1] = 0x02; + txbuf[2] = 0x01; + txbuf[3] = 0x06; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + txbuf[0] = 0x81; + txbuf[1] = 0x01; + txbuf[2] = 0x08; + txbuf[3] = (uint8_t)(chipiaddr1 >> 24); + txbuf[4] = (uint8_t)(chipiaddr1 >> 16); + txbuf[5] = (uint8_t)(chipiaddr1 >> 8); + txbuf[6] = (uint8_t)chipiaddr1; + txbuf[7] = (uint8_t)(count >> 24); + txbuf[8] = (uint8_t)(count >> 16); + txbuf[9] = (uint8_t)(count >> 8); + txbuf[10] = (uint8_t)count; + len = 11; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + txbuf[0] = 0x81; + txbuf[1] = 0x02; + txbuf[2] = 0x01; + txbuf[3] = 0x05; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + switch (riscvchip) + { + case 3: + wlink_ramcodewrite(flash_op569, sizeof(flash_op569)); + break; + case 1: + wlink_ramcodewrite(flash_op103, sizeof(flash_op103)); + break; + case 2: + wlink_ramcodewrite(flash_op573, sizeof(flash_op573)); + break; + case 7: + case 0x0b: + wlink_ramcodewrite(flash_op583, sizeof(flash_op583)); + break; + case 5: + case 6: + wlink_ramcodewrite(flash_op307, sizeof(flash_op307)); + break; + case 9: + wlink_ramcodewrite(flash_op003, sizeof(flash_op003)); + break; + case 0x0a: + wlink_ramcodewrite(flash_op8571, sizeof(flash_op8571)); + break; + case 0x0c: + wlink_ramcodewrite(flash_op643, sizeof(flash_op8571)); + break; + case 0x0e: + wlink_ramcodewrite(flash_opl103, sizeof(flash_opl103)); + break; + default:; + } + txbuf[0] = 0x81; + txbuf[1] = 0x02; + txbuf[2] = 0x01; + txbuf[3] = 0x07; + if ((riscvchip == 0x1) || (pageerase)|| (writeloop>0)) + { + txbuf[3] = 0x0b; + } + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + return rxbuf[3]; +} + +void wlink_endprogram(void) +{ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x02; + txbuf[2] = 0x01; + txbuf[3] = 0x08; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); +} + +int wlink_fastprogram(uint8_t *buffer, int packsize) +{ + unsigned long len = 64; + unsigned char rxbuf[4]; + for (int i = 0; i < packsize / 64; i++) + { + pWriteData(0, 2, (buffer + i * 64), &len); + len = 64; + } + len = 4; + if (pReadData(0, 2, rxbuf, &len)) + { + if ((rxbuf[3] == 0x02) || (rxbuf[3] == 0x04)) + return ERROR_OK; + } + return ERROR_FAIL; +} + +int WriteNonFullPage(unsigned long iaddr, + unsigned char *ibuff, + unsigned long ilen) +{ + unsigned char txbuf[8]; + unsigned char rxbuf[8]; + unsigned long len; + txbuf[0] = 0x81; + txbuf[1] = 0x0A; + txbuf[2] = 0x05; + iaddr += chipiaddr; + txbuf[3] = (unsigned char)(iaddr >> 24); + txbuf[4] = (unsigned char)(iaddr >> 16); + txbuf[5] = (unsigned char)(iaddr >> 8); + txbuf[6] = (unsigned char)(iaddr); + txbuf[7] = (unsigned char)ilen; + len = 8; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + len = ilen; + pWriteData(0, 2, ibuff, &len); + len = 4; + if (pReadData(0, 2, rxbuf, &len)) + { + if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x02))) + return ERROR_OK; + } + return ERROR_FAIL; +} + +int wlink_erase(void) +{ + int ret; + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x02; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + ret = pWriteData(0, 1, txbuf, &len); + len = 4; + ret = pReadData(0, 1, rxbuf, &len); + return ret; +} +void readmcause() +{ + unsigned char oAddr; + unsigned long oData; + unsigned char oOP; + DMI_OP(0, 0x16, 0x00000700, 2, &oAddr, &oData, &oOP); + DMI_OP(0, 0x17, 0x220342, 2, &oAddr, &oData, &oOP); + DMI_OP(0, 0x16, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x4, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x17, 0x220343, 2, &oAddr, &oData, &oOP); + DMI_OP(0, 0x16, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x4, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x20, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x21, 0, 1, &oAddr, &oData, &oOP); + DMI_OP(0, 0x22, 0, 1, &oAddr, &oData, &oOP); +} + +void wlink_endprocess(void) +{ + + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0xff; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); +} + +void wlink_pow3v3( bool set){ + +if(wlinkw || wlinke){ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + if(set) + txbuf[3] = 0x09; + else + txbuf[3] =0x0a; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if(rxbuf[3]==0x09) + LOG_INFO(" POWER 3V3 ENABLE"); + else if(rxbuf[3]==0x0a){ + LOG_INFO(" POWER 3V3 DISABLE"); + // exit(0); + } + else + LOG_ERROR("POWER SET FAILED "); + + }else{ + + LOG_ERROR("This LINK dont support this function"); + + } + + +} + +void wlink_pow5v( bool set){ + + if(wlinkw || wlinke){ + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + if(set) + txbuf[3] = 0x0b; + else + txbuf[3] =0x0c; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if(rxbuf[3]==0x0b) + LOG_INFO(" POWER 5V ENABLE"); + else if(rxbuf[3]==0x0c) + LOG_INFO(" POWER 5V DISABLE"); + else + LOG_ERROR("POWER SET FAILED "); + + + }else{ + + LOG_ERROR("This LINK dont support this function"); + + } + + +} + +void wlink_rstout(int state){ + + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + if(state==0) + txbuf[3] = 0x13; + else if(state==1) + txbuf[3] = 0x14; + else if(state==2) + txbuf[3] = 0x15; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + if((rxbuf[2]==0x01) &&(rxbuf[3]==0x00)){ + if(state==0) + LOG_INFO(" RST PUSH_PULL OUTPUT 0"); + else if(state==1) + LOG_INFO(" RST PUSH_PULL OUTPUT 1"); + else if(state==2) + LOG_INFO(" RST FLOATING INPUT"); + + }else + LOG_ERROR(" RST SET FAILED"); +} + + +int wlink_init(void) +{ + unsigned char txbuf[6]; + unsigned char rxbuf[20]; + char *wlink_name = NULL; + unsigned long len = 5; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + +#ifdef _WIN32 + OSVERSIONINFO version; + + version.dwOSVersionInfoSize = sizeof version; + if (!GetVersionEx(&version)) + { + LOG_ERROR("GetVersionEx error"); + return ERROR_FAIL; + } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) + { + LOG_ERROR("Not Win32 Platform"); + return ERROR_FAIL; + } + if (hModule == 0) + { + hModule = LoadLibrary("WCHLinkDll.dll"); + if (hModule) + { + pOpenDev = (pCH375OpenDevice)GetProcAddress(hModule, "CH375OpenDevice"); + pCloseDev = (pCH375CloseDevice)GetProcAddress(hModule, "CH375CloseDevice"); + pSetTimeout = (pCH375SetTimeout)GetProcAddress(hModule, "CH375SetTimeout"); + pReadData = (pCH375ReadEndP)GetProcAddress(hModule, "CH375ReadEndP"); + pWriteData = (pCH375WriteEndP)GetProcAddress(hModule, "CH375WriteEndP"); + if (pOpenDev == NULL || pCloseDev == NULL || pSetTimeout == NULL || pReadData == NULL || pWriteData == NULL) + { + LOG_ERROR("GetProcAddress error"); + return ERROR_FAIL; + } + if (pOpenDev(gIndex) == -1) + { + gOpen = FALSE; + LOG_ERROR("WLink Open Error"); + return ERROR_FAIL; + } + pSetTimeout(gIndex, 5000, 5000); + } + } +#else if + + if (jtag_libusb_open(wlink_vids, wlink_pids, &wfd, NULL) != ERROR_OK) + { + LOG_ERROR("open failed"); + goto error_wlink; + } + jtag_libusb_set_configuration(wfd, 0); + if (libusb_claim_interface(wfd, 0) != ERROR_OK) + { + LOG_ERROR("claim interface failed"); + goto error_wlink; + } + +#endif + + + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 7; + if (pReadData(0, 1, rxbuf, &len)) + { + + switch (rxbuf[5]) + { + case 1: + wlink_name = "WCH-Link-CH549 mode:RV"; + wlink549 = true; + break; + case 2: + case 0x12: + wlink_name = "WCH-LinkE mode:RV"; + wlinke = true; + break; + case 3: + wlink_name = "WCH-LinkS mode:RV"; + break; + case 5: + case 0x85: + wlink_name = "WCH-LinkW mode:RV"; + wlinkw = true; + break; + default: + LOG_ERROR("unknow WCH-LINK "); + goto error_wlink; + break; + } + LOG_INFO("%s version %d.%d ", wlink_name, rxbuf[3], rxbuf[4]); + + + + txbuf[0] = 0x81; + txbuf[1] = 0x0c; + txbuf[2] = 0x02; + txbuf[3] = 0x01; + txbuf[4] = sp; + len=5; + pWriteData(0, 1, txbuf, &len); + len=4; + pReadData(0, 1, rxbuf, &len); + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x02; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 8; + pReadData(0, 1, rxbuf, &len); + if (((rxbuf[0] == 0x81) && (rxbuf[1] == 0x55) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x01))) + { + LOG_ERROR(" WCH-Link failed to connect with riscvchip"); + LOG_ERROR(" 1.Make sure the two-line debug interface has been opened. If not, set board to boot mode then use ISP tool to open it"); + LOG_ERROR(" 2.Please check your physical link connection"); + if (wlink549) + LOG_ERROR(" if your chip is CH32V00X,WCH-Link-CH549 does not support this chip, please use WCH-LinkE"); + if(wlinkw) + LOG_ERROR(" if your chip is CH56X/CH57X/CH58X/CH59X,WCH-LinkW does not support this chip, please use WCH-LinkE"); + goto error_wlink; + } + chip_type = (((unsigned int)rxbuf[4]) << 24) + (((unsigned int)rxbuf[5]) << 16) + (((unsigned int)rxbuf[6]) << 8) + (((unsigned int)rxbuf[7])); + chip_type = chip_type & 0xffffff0f; + if((chip_type==0x30520508) || (chip_type == 0x305b0508)) + pageerase=true; + switch (rxbuf[3]) + { + case 1: + { + riscvchip = 0x01; + chipiaddr = 0x08000000; + pagesize = 128; + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x03; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + txbuf[3] = 0x10; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + + break; + } + case 2: + { + riscvchip = 0x02; + chipiaddr = 0x00000000; + pagesize = 256; + LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !"); + break; + } + case 3: + { + riscvchip = 0x03; + chipiaddr = 0x0000; + pagesize = 256; + LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !"); + txbuf[0] = 0x81; + txbuf[1] = 0x0d; + txbuf[2] = 0x01; + txbuf[3] = 0x04; + + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + + switch (rxbuf[3]) + { + case 0: + { + ramaddr = 0x8000; + break; + } + case 1: + { + ramaddr = 0x10000; + break; + } + case 3: + { + ramaddr = 0x18000; + break; + } + default: + LOG_ERROR(" unknow CH56X riscvchip"); + goto error_wlink; + } + + break; + } + case 5: + { + riscvchip = 0x05; + chipiaddr = 0x08000000; + pagesize = 256; + break; + } + case 6: + { + riscvchip = 0x06; + chipiaddr = 0x08000000; + pagesize = 256; + txbuf[3] = 0x03; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + break; + } + case 7: // + { + riscvchip = 0x07; + chipiaddr = 0x00000000; + pagesize = 256; + LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !"); + break; + } + case 9: // + { + riscvchip = 0x09; + chipiaddr = 0x08000000; + pagesize = 64; + txbuf[3] = 0x03; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + break; + } + case 0x0a: + { + riscvchip = 0x0a; + chipiaddr = 0x00000000; + pagesize = 256; + txbuf[3] = 0x03; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + + break; + } + case 0x0b: // + { + riscvchip = 0x0b; + chipiaddr = 0x00000000; + pagesize = 256; + break; + } + case 0x0c: + case 0x0d: // + { + riscvchip = 0x0c; + chipiaddr = 0x08000000; + pagesize = 256; + break; + } + case 0x0e: // + { + riscvchip = 0x0e; + chipiaddr = 0x08000000; + pagesize = 256; + break; + } + default: + LOG_ERROR(" communication fail,please contact [support@mounriver.com]"); + goto error_wlink; + } +#ifdef _WIN32 + gOpen = TRUE; +#endif + } + else + { + return ERROR_FAIL; + } + LOG_INFO("wlink_init ok"); + if(iocontrol){ + switch (iocontrol) + { + case 1: + wlink_pow3v3(powstat); + break; + case 2: + wlink_pow5v(powstat); + break; + case 3: + wlink_rstout(poutput); + break; + default: + + goto error_wlink; + break; + } + usleep(10000); + return ERROR_OK; + } + + return ERROR_OK; +#ifdef _WIN32 +error_wlink: + + wlink_endprocess(); + pCloseDev(gIndex); + if (hModule) + { + FreeLibrary(hModule); + hModule = 0; + } + return ERROR_FAIL; +#else +error_wlink: + if (wfd) + { + + wlink_endprocess(); + jtag_libusb_close(wfd); + } + return ERROR_FAIL; +#endif +} + +int wlink_quit(void) +{ +#ifdef _WIN32 + if (gOpen) + { + wlink_endprocess(); + pCloseDev(gIndex); + gOpen = FALSE; + } + if (hModule) + { + FreeLibrary(hModule); + hModule = 0; + } +#else if + wlink_endprocess(); + jtag_libusb_close(wfd); +#endif + return ERROR_OK; +} + +void wlink_disabledebug(void) +{ + if ((riscvchip == 0x02) || (riscvchip == 0x03) || (riscvchip == 0x07)|| (riscvchip == 0x0b)) + { + unsigned char txbuf[4]; + unsigned char rxbuf[4]; + unsigned long len = 4; + txbuf[0] = 0x81; + txbuf[1] = 0x0e; + txbuf[2] = 0x01; + txbuf[3] = 0x01; + len = 4; + pWriteData(0, 1, txbuf, &len); + len = 4; + pReadData(0, 1, rxbuf, &len); + } +} + + + +int wlink_write(const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + int packsize = 4096; + + if (riscvchip == 0x09) + packsize = 1024; + uint8_t *buf_bin; + buf_bin = malloc(packsize); + memset(buf_bin, 0xff, packsize); + + int binlength = count; + wlink_ready_write(offset, count); + + if (binlength <= packsize) + { + for (int i = 0; i < count; i++) + { + buf_bin[i] = *(buffer + i); + } + int ret = wlink_fastprogram(buf_bin, packsize); + if (ret != ERROR_OK) + { + return ERROR_FAIL; + } + } + else + { + while (binlength >= packsize) + { + for (int i = 0; i < packsize; i++) + { + buf_bin[i] = *(buffer + i); + } + int ret = wlink_fastprogram(buf_bin, packsize); + if (ret != ERROR_OK) + { + return ERROR_FAIL; + } + binlength -= packsize; + buffer += packsize; + } + if (binlength > 0) + { + memset(buf_bin, 0xff, packsize); + for (int i = 0; i < binlength; i++) + { + buf_bin[i] = *(buffer + i); + } + int ret = wlink_fastprogram(buf_bin, packsize); + if (ret != ERROR_OK) + { + return ERROR_FAIL; + } + } + } + wlink_endprogram(); + return ERROR_OK; +} +int wlink_speed(int speed ){ + unsigned char txbuf[5]; + unsigned char rxbuf[4]; + unsigned long len = 5; + txbuf[0]=0x81; + txbuf[1]=0x0c; + txbuf[2]=0x02; + txbuf[3]=riscvchip; + + switch (speed) + { + case 6000: + txbuf[4]=1; + break; + case 4000: + txbuf[4]=2; + break; + case 400: + txbuf[4]=3; + break; + default: + LOG_WARNING("unknow speed config"); + txbuf[4]=1; + break; + } + sp=txbuf[4]; + pWriteData(0, 1, txbuf, &len); + len=4; + pReadData(0, 1, rxbuf, &len); + if (((rxbuf[0] == 0x82) && (rxbuf[1] == 0x0c) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x01))) + return ERROR_OK; + return ERROR_FAIL; +} + +int wlink_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} +static int wlink_khz(int khz, int *speed) +{ + *speed = khz; + + return ERROR_OK; +} + + +COMMAND_HANDLER(wlink_set_address) +{ + + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[0], wlink_address); + return ERROR_OK; +} + +COMMAND_HANDLER(rst_set) +{ + iocontrol=3; + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[0], poutput); + + + + + if((poutput !=1)&&(poutput !=0)&&(poutput !=2)){ + + LOG_ERROR("invalid parameter"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(wlink_set_index) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], gIndex); + return ERROR_OK; +} + +COMMAND_HANDLER(noload) +{ + noloadflag = true; + return ERROR_OK; +} +COMMAND_HANDLER(pow3v3) +{ + iocontrol=1; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], powstat); + + return ERROR_OK; +} +COMMAND_HANDLER(pow5v) +{ + iocontrol=2; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], powstat); + + return ERROR_OK; +} +COMMAND_HANDLER(disabledebug) +{ + wlink_disabledebug(); + return ERROR_OK; +} +COMMAND_HANDLER(page_erase) +{ + pageerase = true; + return ERROR_OK; +} +// COMMAND_HANDLER(protect_check) +// { +// protectcheck=true; +// return ERROR_OK; +// } +static const struct command_registration wlink_command_handlers[] = { + { + .name = "wlink_set_index", + .handler = &wlink_set_index, + .mode = COMMAND_CONFIG, + .help = "wlink_set_index num", + .usage = "set Wlink index", + }, + { + .name = "wlink_set_address", + .handler = &wlink_set_address, + .mode = COMMAND_CONFIG, + .help = "wlink_set_address num", + .usage = "[count]", + }, + { + .name = "noload", + .handler = &noload, + .mode = COMMAND_CONFIG, + .help = "noload", + .usage = "dont download", + }, + { + .name = "disabledebug", + .handler = &disabledebug, + .mode = COMMAND_CONFIG, + .help = "disabledebug", + .usage = "disable debug", + }, + { + .name = "page_erase", + .handler = &page_erase, + .mode = COMMAND_CONFIG, + .help = "page_erase", + .usage = "page erase", + }, + { + .name = "pow3v3", + .handler = &pow3v3, + .mode = COMMAND_CONFIG, + .help = "3.3v", + .usage = "('on'|'off')", + }, + { + .name = "pow5v", + .handler = &pow5v, + .mode = COMMAND_CONFIG, + .help = "5v", + .usage = "('on'|'off')", + }, + { + .name = "rst_set", + .handler = &rst_set, + .mode = COMMAND_CONFIG, + .help = "", + .usage = "[count]", + }, + COMMAND_REGISTRATION_DONE}; +static struct sdi_driver wlink_interface = { + + .transfer = &DMI_OP, +}; + +struct adapter_driver wlinke_adapter_driver = { + .name = "wlinke", + + .commands = wlink_command_handlers, + .transports = sdi_transports, + .speed=wlink_speed, + .khz = wlink_khz, + .speed_div = wlink_speed_div, + .init = wlink_init, + .quit = wlink_quit, + .sdi_ops = &wlink_interface, +}; diff --git a/src/jtag/interface.h b/src/jtag/interface.h old mode 100644 new mode 100755 index 58bfd02b0..a2477e3b7 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -27,6 +27,7 @@ #include #include +#include #include /* @file @@ -363,10 +364,12 @@ struct adapter_driver { /* SWIM APIs */ const struct swim_driver *swim_ops; + /* SDI APIs */ + const struct sdi_driver *sdi_ops; }; extern const char * const jtag_only[]; - +extern const char *sdi_transports[]; int adapter_resets(int assert_trst, int assert_srst); int adapter_assert_reset(void); int adapter_deassert_reset(void); diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c old mode 100644 new mode 100755 index ddf70cc24..54669eeff --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -150,6 +150,12 @@ extern struct adapter_driver stlink_dap_adapter_driver; #if BUILD_RSHIM == 1 extern struct adapter_driver rshim_dap_adapter_driver; #endif +#if BUILD_WLINKE == 1 +extern struct adapter_driver wlinke_adapter_driver; +#endif +#if BUILD_CH347 == 1 +extern struct adapter_driver ch347_adapter_driver; +#endif /** * The list of built-in JTAG interfaces, containing entries for those @@ -264,5 +270,12 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_RSHIM == 1 &rshim_dap_adapter_driver, #endif +#if BUILD_WLINKE == 1 + &wlinke_adapter_driver, +#endif +#if BUILD_CH347 == 1 + &ch347_adapter_driver, +#endif + NULL, }; diff --git a/src/jtag/sdi.c b/src/jtag/sdi.c new file mode 100755 index 000000000..dce2dcfdf --- /dev/null +++ b/src/jtag/sdi.c @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "interface.h" + +#include +#include + +extern struct adapter_driver *adapter_driver; + +int transfer(unsigned long iIndex, unsigned char iAddr,unsigned long iData,unsigned char iOP,unsigned char *oAddr,unsigned long *oData,unsigned char *oOP) +{ + assert(adapter_driver->sdi_ops); + + return adapter_driver->sdi_ops->transfer(iIndex,iAddr,iData,iOP,oAddr,oData,oOP); +} + + + + + + +COMMAND_HANDLER(handle_sdi_newtap_command) +{ + struct jtag_tap *tap; + + /* + * only need "basename" and "tap_type", but for backward compatibility + * ignore extra parameters + */ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = calloc(1, sizeof(*tap)); + if (!tap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + tap->chip = strdup(CMD_ARGV[0]); + tap->tapname = strdup(CMD_ARGV[1]); + tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); + if (!tap->chip || !tap->tapname || !tap->dotted_name) { + LOG_ERROR("Out of memory"); + free(tap->dotted_name); + free(tap->tapname); + free(tap->chip); + free(tap); + return ERROR_FAIL; + } + + LOG_DEBUG("Creating new sdi \"tap\", Chip: %s, Tap: %s, Dotted: %s", + tap->chip, tap->tapname, tap->dotted_name); + + /* default is enabled-after-reset */ + tap->enabled = true; + + jtag_tap_init(tap); + return ERROR_OK; +} + +static const struct command_registration sdi_transport_subcommand_handlers[] = { + { + .name = "newtap", + .handler = handle_sdi_newtap_command, + .mode = COMMAND_CONFIG, + .help = "Create a new TAP instance named basename.tap_type, " + "and appends it to the scan chain.", + .usage = "basename tap_type", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration sdi_transport_command_handlers[] = { + { + .name = "sdi", + .mode = COMMAND_ANY, + .help = "perform sdi adapter actions", + .usage = "", + .chain = sdi_transport_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static int sdi_transport_select(struct command_context *cmd_ctx) +{ + LOG_DEBUG(__func__); + + return register_commands(cmd_ctx, NULL, sdi_transport_command_handlers); +} + +static int sdi_transport_init(struct command_context *cmd_ctx) +{ + // enum reset_types jtag_reset_config = jtag_get_reset_config(); + + // LOG_DEBUG(__func__); + + // if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + // if (jtag_reset_config & RESET_SRST_NO_GATING) + // adapter_assert_reset(); + // else + // LOG_WARNING("\'srst_nogate\' reset_config option is required"); + // } else + // adapter_deassert_reset(); + + return ERROR_OK; +} + +static struct transport sdi_transport = { + .name = "sdi", + .select = sdi_transport_select, + .init = sdi_transport_init, +}; +const char *sdi_transports[] = { "sdi", NULL }; +static void sdi_constructor(void) __attribute__ ((constructor)); +static void sdi_constructor(void) +{ + transport_register(&sdi_transport); +} + +bool transport_is_sdi(void) +{ + return get_current_transport() == &sdi_transport; +} diff --git a/src/jtag/sdi.h b/src/jtag/sdi.h new file mode 100755 index 000000000..a9d2806a9 --- /dev/null +++ b/src/jtag/sdi.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_JTAG_SDI_H +#define OPENOCD_JTAG_SDI_H + + + +struct sdi_driver { + unsigned char (* transfer)( unsigned long iIndex, unsigned char iAddr,unsigned long iData,unsigned char iOP,unsigned char *oAddr,unsigned long *oData,unsigned char *oOP); +}; + +extern int transfer(unsigned long iIndex, unsigned char iAddr,unsigned long iData,unsigned char iOP,unsigned char *oAddr,unsigned long *oData,unsigned char *oOP); + +#endif \ No newline at end of file diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c old mode 100644 new mode 100755 index 086fd1121..21d68e20c --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3260,7 +3260,9 @@ static bool gdb_handle_vrun_packet(struct connection *connection, const char *pa gdb_put_packet(connection, "S00", 3); return true; } - +extern void wlink_quitreset(void); +extern int register_write_direct(struct target *target, unsigned number, + uint64_t value); static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -3416,7 +3418,13 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } - + if (strncmp(packet, "vKill", 5) == 0) { + if (strncmp(target->type->name, "wch_riscv", 9) == 0) { + // uint64_t value=0; + // register_write_direct(target, 0x7f2,0); + wlink_quitreset(); + } + } gdb_put_packet(connection, "", 0); return ERROR_OK; } @@ -3538,7 +3546,25 @@ static int gdb_input_inner(struct connection *connection) /* terminate with zero */ gdb_packet_buffer[packet_size] = '\0'; - + // if(1){ + // char buf[64]; + // unsigned offset = 0; + // int i = 0; + // while (i < packet_size && offset < 56) { + // if (packet[i] == '\\') { + // buf[offset++] = '\\'; + // buf[offset++] = '\\'; + // } else if (isprint(packet[i])) { + // buf[offset++] = packet[i]; + // } else { + // sprintf(buf + offset, "\\x%02x", (unsigned char) packet[i]); + // offset += 4; + // } + // i++; + // } + // buf[offset] = 0; + // LOG_INFO("received packet: '%s'%s", buf, i < packet_size ? "..." : ""); + // } if (packet_size > 0) { gdb_log_incoming_packet(connection, gdb_packet_buffer); diff --git a/src/target/Makefile.am b/src/target/Makefile.am old mode 100644 new mode 100755 index 49e882fe6..9aeb360db --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -14,6 +14,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(ARMV7_SRC) \ $(ARM_MISC_SRC) \ $(AVR32_SRC) \ + $(WCH_RISCV_SRC) \ $(MIPS32_SRC) \ $(NDS32_SRC) \ $(STM8_SRC) \ @@ -115,6 +116,9 @@ AVR32_SRC = \ %D%/avr32_mem.c \ %D%/avr32_regs.c +WCH_RISCV_SRC = \ + %D%/wch_riscv.c\ + %D%/wch_riscv-013.c MIPS32_SRC = \ %D%/mips32.c \ %D%/mips_m4k.c \ @@ -256,6 +260,7 @@ ARC_SRC = \ %D%/arc_cmd.h \ %D%/arc_jtag.h \ %D%/arc_mem.h \ + %D%/wch_riscv.h \ %D%/rtt.h include %D%/openrisc/Makefile.am diff --git a/src/target/armv7m.c b/src/target/armv7m.c old mode 100644 new mode 100755 index 0a51ad4d6..6e704bfe9 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -494,6 +494,7 @@ int armv7m_run_algorithm(struct target *target, target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info) { + int retval; retval = armv7m_start_algorithm(target, @@ -577,6 +578,7 @@ int armv7m_start_algorithm(struct target *target, /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */ armv7m_set_core_reg(reg, reg_params[i].value); + } { @@ -614,9 +616,8 @@ int armv7m_start_algorithm(struct target *target, /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; - retval = target_resume(target, 0, entry_point, 1, 1); - + return retval; } @@ -626,7 +627,8 @@ int armv7m_wait_algorithm(struct target *target, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, int timeout_ms, void *arch_info) -{ +{ + struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; @@ -650,7 +652,7 @@ int armv7m_wait_algorithm(struct target *target, return retval; return ERROR_TARGET_TIMEOUT; } - + if (exit_point) { /* PC value has been cached in cortex_m_debug_entry() */ uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32); diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h old mode 100644 new mode 100755 index 32bc1d577..1de91ba2c --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -2,7 +2,7 @@ #ifndef TARGET__RISCV__GDB_REGS_H #define TARGET__RISCV__GDB_REGS_H - +#include "encoding.h" /* gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in * its source tree. We must interpret the numbers the same here. */ enum gdb_regno { diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c old mode 100644 new mode 100755 index 9a1e55ccb..e5df47718 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -640,7 +640,6 @@ static int add_trigger(struct target *target, struct trigger *trigger) if (result != ERROR_OK) return result; int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); - result = ERROR_OK; switch (type) { case 1: @@ -3916,7 +3915,7 @@ int riscv_enumerate_triggers(struct target *target) result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; - + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); if (type == 0) break; @@ -4222,7 +4221,7 @@ static int cmp_csr_info(const void *p1, const void *p2) int riscv_init_registers(struct target *target) { RISCV_INFO(info); - + riscv_free_registers(target); target->reg_cache = calloc(1, sizeof(*target->reg_cache)); diff --git a/src/target/target.c b/src/target/target.c old mode 100644 new mode 100755 index 927329a64..9c07e593b --- a/src/target/target.c +++ b/src/target/target.c @@ -112,7 +112,7 @@ extern struct target_type riscv_target; extern struct target_type mem_ap_target; extern struct target_type esirisc_target; extern struct target_type arcv2_target; - +extern struct target_type wch_riscv_target; static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, @@ -150,6 +150,7 @@ static struct target_type *target_types[] = { &arcv2_target, &aarch64_target, &mips_mips64_target, + &wch_riscv_target, NULL, }; @@ -824,7 +825,7 @@ const char *target_type_name(struct target *target) return target->type->name; } -static int target_soft_reset_halt(struct target *target) + int target_soft_reset_halt(struct target *target) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -863,7 +864,7 @@ int target_run_algorithm(struct target *target, int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; - + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; @@ -873,7 +874,7 @@ int target_run_algorithm(struct target *target, target_type_name(target), __func__); goto done; } - + target->running_alg = true; retval = target->type->run_algorithm(target, num_mem_params, mem_params, @@ -3096,13 +3097,12 @@ COMMAND_HANDLER(handle_reg_command) /* list all available registers for the current target */ if (CMD_ARGC == 0) { struct reg_cache *cache = target->reg_cache; - unsigned int count = 0; while (cache) { unsigned i; command_print(CMD, "===== %s", cache->name); - + for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { @@ -3355,7 +3355,12 @@ COMMAND_HANDLER(handle_reset_command) /* reset *all* targets */ return target_process_reset(CMD, reset_mode); } - +extern void wlink_softreset(void); +COMMAND_HANDLER(handle_wlink_reset_resume_command) +{ + + wlink_softreset(); +} COMMAND_HANDLER(handle_resume_command) { @@ -4404,6 +4409,7 @@ COMMAND_HANDLER(handle_profile_command) return retval; } + static int new_u64_array_element(Jim_Interp *interp, const char *varname, int idx, uint64_t val) { char *namebuf; @@ -7014,6 +7020,14 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "Reset all targets into the specified mode. " "Default reset mode is run, if not given.", }, + { + .name = "wlink_reset_resume", + .handler = handle_wlink_reset_resume_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Reset && resume. ", + }, + { .name = "soft_reset_halt", .handler = handle_soft_reset_halt_command, diff --git a/src/target/wch_riscv-013.c b/src/target/wch_riscv-013.c new file mode 100755 index 000000000..e1e395f45 --- /dev/null +++ b/src/target/wch_riscv-013.c @@ -0,0 +1,4300 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the + * latest draft. + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/algorithm.h" +#include "target/target_type.h" +#include +#include "jtag/jtag.h" +#include "target/register.h" +#include "target/breakpoints.h" +#include "helper/time_support.h" +#include "helper/list.h" +#include "target/riscv/riscv.h" +#include "target/riscv/debug_defines.h" +#include "rtos/rtos.h" +#include "target/riscv/program.h" +#include "target/riscv/asm.h" +#include "target/riscv/batch.h" +#include "jtag/sdi.h" +static int riscv013_on_step_or_resume(struct target *target, bool step); +static int riscv013_step_or_resume_current_hart(struct target *target, + bool step); +static void riscv013_clear_abstract_error(struct target *target); + +/* Implementations of the functions in riscv_info_t. */ +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int rid); +static int riscv013_set_register(struct target *target, int regid, uint64_t value); +static int dm013_select_hart(struct target *target, int hart_index); +static int riscv013_halt_prep(struct target *target); +static int riscv013_halt_go(struct target *target); +static int riscv013_resume_go(struct target *target); +static int riscv013_step_current_hart(struct target *target); +static int riscv013_on_halt(struct target *target); +static int riscv013_on_step(struct target *target); +static int riscv013_resume_prep(struct target *target); +static bool riscv013_is_halted(struct target *target); +static enum riscv_halt_reason riscv013_halt_reason(struct target *target); +static int riscv013_write_debug_buffer(struct target *target, unsigned index, + riscv_insn_t d); +static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned + index); +static int riscv013_invalidate_cached_debug_buffer(struct target *target); +static int riscv013_execute_debug_buffer(struct target *target); +static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); +static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); +static int riscv013_dmi_write_u64_bits(struct target *target); +static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); +int register_write_direct(struct target *target, unsigned number, + uint64_t value); +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); +static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address, + uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); +static void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *write_data, + uint32_t write_size, uint32_t sbcs); +static void read_memory_sba_simple(struct target *target, target_addr_t addr, + uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs); + +/** + * Since almost everything can be accomplish by scanning the dbus register, all + * functions here assume dbus is already selected. The exception are functions + * called directly by OpenOCD, which can't assume anything about what's + * currently in IR. They should set IR to dbus explicitly. + */ + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +#define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) +#define WCH_DMOD 0x80 +/*** JTAG registers. ***/ + +typedef enum { + DMI_OP_NOP = 0, + DMI_OP_READ = 1, + DMI_OP_WRITE = 2 +} dmi_op_t; +typedef enum { + DMI_STATUS_SUCCESS = 0, + DMI_STATUS_FAILED = 2, + DMI_STATUS_BUSY = 3 +} dmi_status_t; + +// typedef enum slot { +// SLOT0, +// SLOT1, +// SLOT_LAST, +// } slot_t; + +/*** Debug Bus registers. ***/ + +#define CMDERR_NONE 0 +#define CMDERR_BUSY 1 +#define CMDERR_NOT_SUPPORTED 2 +#define CMDERR_EXCEPTION 3 +#define CMDERR_HALT_RESUME 4 +#define CMDERR_OTHER 7 + +/*** Info about the core being debugged. ***/ + +struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; + +typedef enum { + YNM_MAYBE, + YNM_YES, + YNM_NO +} yes_no_maybe_t; + +#define HART_INDEX_MULTIPLE -1 + +typedef struct { + struct list_head list; + int abs_chain_position; + + /* The number of harts connected to this DM. */ + int hart_count; + /* Indicates we already reset this DM, so don't need to do it again. */ + bool was_reset; + /* Targets that are connected to this DM. */ + struct list_head target_list; + /* Contains the ID of the hart that is currently selected by this DM. + * If multiple harts are selected this is HART_INDEX_MULTIPLE. */ + int current_hartid; + + bool hasel_supported; + + /* The program buffer stores executable code. 0 is an illegal instruction, + * so we use 0 to mean the cached value is invalid. */ + uint32_t progbuf_cache[16]; +} dm013_info_t; + +extern int WriteNonFullPage(unsigned long iaddr, unsigned char *ibuff,unsigned long ilen); +static int execute_fence(struct target *target); +typedef struct { + struct list_head list; + struct target *target; +} target_list_t; + +typedef struct { + /* The indexed used to address this hart in its DM. */ + unsigned index; + /* Number of address bits in the dbus register. */ + unsigned abits; + /* Number of abstract command data registers. */ + unsigned datacount; + /* Number of words in the Program Buffer. */ + unsigned progbufsize; + + /* We cache the read-only bits of sbcs here. */ + uint32_t sbcs; + + yes_no_maybe_t progbuf_writable; + /* We only need the address so that we know the alignment of the buffer. */ + riscv_addr_t progbuf_address; + + /* Number of run-test/idle cycles the target requests we do after each dbus + * access. */ + unsigned int dtmcs_idle; + + /* This value is incremented every time a dbus access comes back as "busy". + * It's used to determine how many run-test/idle cycles to feed the target + * in between accesses. */ + unsigned int dmi_busy_delay; + + /* Number of run-test/idle cycles to add between consecutive bus master + * reads/writes respectively. */ + unsigned int bus_master_write_delay, bus_master_read_delay; + + /* This value is increased every time we tried to execute two commands + * consecutively, and the second one failed because the previous hadn't + * completed yet. It's used to add extra run-test/idle cycles after + * starting a command, so we don't have to waste time checking for busy to + * go low. */ + unsigned int ac_busy_delay; + + bool abstract_read_csr_supported; + bool abstract_write_csr_supported; + bool abstract_read_fpr_supported; + bool abstract_write_fpr_supported; + + yes_no_maybe_t has_aampostincrement; + + /* When a function returns some error due to a failure indicated by the + * target in cmderr, the caller can look here to see what that error was. + * (Compare with errno.) */ + uint8_t cmderr; + + /* Some fields from hartinfo. */ + uint8_t datasize; + uint8_t dataaccess; + int16_t dataaddr; + + /* The width of the hartsel field. */ + unsigned hartsellen; + + /* DM that provides access to this target. */ + dm013_info_t *dm; + + /* This target was selected using hasel. */ + bool selected; +} riscv013_info_t; + +static LIST_HEAD(dm_list); + +static riscv013_info_t *get_info(const struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + assert(info); + assert(info->version_specific); + return (riscv013_info_t *) info->version_specific; +} + +/** + * Return the DM structure for this target. If there isn't one, find it in the + * global list of DMs. If it's not in there, then create one and initialize it + * to 0. + */ +static dm013_info_t *get_dm(struct target *target) +{ + RISCV013_INFO(info); + if (info->dm) + return info->dm; + + int abs_chain_position = target->tap->abs_chain_position; + + dm013_info_t *entry; + dm013_info_t *dm = NULL; + list_for_each_entry(entry, &dm_list, list) { + if (entry->abs_chain_position == abs_chain_position) { + dm = entry; + break; + } + } + if (!dm) { + LOG_DEBUG("[%d] Allocating new DM", target->coreid); + dm = calloc(1, sizeof(dm013_info_t)); + if (!dm) + return NULL; + dm->abs_chain_position = abs_chain_position; + dm->current_hartid = 0; + dm->hart_count = -1; + INIT_LIST_HEAD(&dm->target_list); + list_add(&dm->list, &dm_list); + } + + info->dm = dm; + target_list_t *target_entry; + list_for_each_entry(target_entry, &dm->target_list, list) { + if (target_entry->target == target) + return dm; + } + target_entry = calloc(1, sizeof(*target_entry)); + if (!target_entry) { + info->dm = NULL; + return NULL; + } + target_entry->target = target; + list_add(&target_entry->list, &dm->target_list); + + return dm; +} + +static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) +{ + if (hart_index >= 0) { + initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_SINGLE); + uint32_t index_lo = hart_index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); + initial = set_field(initial, DM_DMCONTROL_HARTSELLO, index_lo); + uint32_t index_hi = hart_index >> DM_DMCONTROL_HARTSELLO_LENGTH; + assert(index_hi < (1 << DM_DMCONTROL_HARTSELHI_LENGTH)); + initial = set_field(initial, DM_DMCONTROL_HARTSELHI, index_hi); + } else if (hart_index == HART_INDEX_MULTIPLE) { + initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_MULTIPLE); + /* TODO: https://github.com/riscv/riscv-openocd/issues/748 */ + initial = set_field(initial, DM_DMCONTROL_HARTSELLO, 0); + initial = set_field(initial, DM_DMCONTROL_HARTSELHI, 0); + } + + return initial; +} +int write_flash_data(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + + execute_fence(target); + int ret =WriteNonFullPage(address,buffer,size); + return ret; +} + + + +/** + * @param target + * @param data_in The data we received from the target. + * @param dmi_busy_encountered + * If non-NULL, will be updated to reflect whether DMI busy was + * encountered while executing this operation or not. + * @param dmi_op The operation to perform (read/write/nop). + * @param address The address argument to that operation. + * @param data_out The data to send to the target. + * @param timeout_sec + * @param exec When true, this scan will execute something, so extra RTI + * cycles may be added. + * @param ensure_success + * Scan a nop after the requested operation, ensuring the + * DMI operation succeeded. + */ +static int dmi_op_timeout(struct target *target, uint32_t *data_in, + bool *dmi_busy_encountered, int dmi_op, uint32_t address, + uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) +{ + dmi_status_t status; + uint32_t address_in; + uint8_t recvOP; + uint32_t recvData; + if (dmi_busy_encountered) + *dmi_busy_encountered = false; + + const char *op_name; + switch (dmi_op) { + case DMI_OP_NOP: + op_name = "nop"; + break; + case DMI_OP_READ: + op_name = "read"; + break; + case DMI_OP_WRITE: + op_name = "write"; + break; + default: + LOG_ERROR("Invalid DMI operation: %d", dmi_op); + return ERROR_FAIL; + } + + time_t start = time(NULL); + int result=0; + /* This first loop performs the request. Note that if for some reason this + * stays busy, it is actually due to the previous access. */ + while (1) { + if(dmi_op == DMI_OP_READ) + { + result=transfer(0, (unsigned char )address, 0, (unsigned char )dmi_op, &address_in, data_in,&recvOP); + if(!result){ + LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status); + LOG_ERROR("Maybe the device has been removed"); + server_quit(); + return ERROR_FAIL; + } + }else{ + transfer(0, (unsigned char )address, data_out, (unsigned char )dmi_op, &address_in, &recvData,&recvOP); + } + status = recvOP; + if (status == DMI_STATUS_BUSY) { + if (dmi_busy_encountered) + *dmi_busy_encountered = true; + transfer(0, (unsigned char )DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR, (unsigned char )DMI_OP_WRITE, &address_in, &recvData,&recvOP); + } else if (status == DMI_STATUS_SUCCESS) { + break; + } else { + return ERROR_FAIL; + } + if (time(NULL) - start > timeout_sec) + return ERROR_TIMEOUT_REACHED; + } + + if (status != DMI_STATUS_SUCCESS) { + LOG_ERROR("Failed %s at 0x%x; status=%d", op_name, address, status); + return ERROR_FAIL; + } + return ERROR_OK; + +} + +static int dmi_op(struct target *target, uint32_t *data_in, + bool *dmi_busy_encountered, int dmi_op, uint32_t address, + uint32_t data_out, bool exec, bool ensure_success) +{ + int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, dmi_op, + address, data_out, riscv_command_timeout_sec, exec, ensure_success); + if (result == ERROR_TIMEOUT_REACHED) { + LOG_ERROR("[%s] DMI operation didn't complete in %d seconds. The target is " + "either really slow or broken. You could increase the " + "timeout with riscv set_command_timeout_sec.", + target_name(target), riscv_command_timeout_sec); + return ERROR_FAIL; + } + return result; + +} + +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) +{ + return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); +} + +static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) +{ + return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); +} + +static int dmi_write_exec(struct target *target, uint32_t address, + uint32_t value, bool ensure_success) +{ + return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, true, ensure_success); +} + +static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, + bool authenticated, unsigned timeout_sec) +{ + int result = dmi_op_timeout(target, dmstatus, NULL, DMI_OP_READ, + DM_DMSTATUS, 0, timeout_sec, false, true); + if (result != ERROR_OK) + return result; + int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION); + if (dmstatus_version != 2 && dmstatus_version != 3) { + LOG_ERROR("OpenOCD only supports Debug Module version 2 (0.13) and 3 (1.0), not " + "%d (dmstatus=0x%x). This error might be caused by a JTAG " + "signal issue. Try reducing the JTAG clock speed.", + get_field(*dmstatus, DM_DMSTATUS_VERSION), *dmstatus); + } else if (authenticated && !get_field(*dmstatus, DM_DMSTATUS_AUTHENTICATED)) { + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", *dmstatus); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int dmstatus_read(struct target *target, uint32_t *dmstatus, + bool authenticated) +{ + int result = dmstatus_read_timeout(target, dmstatus, authenticated, + riscv_command_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) + LOG_TARGET_ERROR(target, "DMSTATUS read didn't complete in %d seconds. The target is " + "either really slow or broken. You could increase the " + "timeout with `riscv set_command_timeout_sec`.", + riscv_command_timeout_sec); + return result; +} + +static void increase_ac_busy_delay(struct target *target) +{ + riscv013_info_t *info = get_info(target); + info->ac_busy_delay += info->ac_busy_delay / 10 + 1; + LOG_DEBUG("dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + info->dtmcs_idle, info->dmi_busy_delay, + info->ac_busy_delay); +} + +static uint32_t abstract_register_size(unsigned width) +{ + switch (width) { + case 32: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); + case 64: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); + case 128: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); + default: + LOG_ERROR("Unsupported register width: %d", width); + return 0; + } +} + +static int wait_for_idle(struct target *target, uint32_t *abstractcs) +{ + RISCV013_INFO(info); + time_t start = time(NULL); + while (1) { + if (dmi_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) + return ERROR_OK; + + if (time(NULL) - start > riscv_command_timeout_sec) { + info->cmderr = get_field(*abstractcs, DM_ABSTRACTCS_CMDERR); + + LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + *abstractcs); + return ERROR_FAIL; + } + } +} + +static int dm013_select_target(struct target *target) +{ + riscv013_info_t *info = get_info(target); + return dm013_select_hart(target, info->index); +} + +static int execute_abstract_command(struct target *target, uint32_t command) +{ + RISCV013_INFO(info); + if (debug_level >= LOG_LVL_DEBUG) { + switch (get_field(command, DM_COMMAND_CMDTYPE)) { + case 0: + LOG_DEBUG("command=0x%x; access register, size=%d, postexec=%d, " + "transfer=%d, write=%d, regno=0x%x", + command, + 8 << get_field(command, AC_ACCESS_REGISTER_AARSIZE), + get_field(command, AC_ACCESS_REGISTER_POSTEXEC), + get_field(command, AC_ACCESS_REGISTER_TRANSFER), + get_field(command, AC_ACCESS_REGISTER_WRITE), + get_field(command, AC_ACCESS_REGISTER_REGNO)); + break; + default: + LOG_DEBUG("command=0x%x", command); + break; + } + } + + if (dmi_write_exec(target, DM_COMMAND, command, false) != ERROR_OK) + return ERROR_FAIL; + + uint32_t abstractcs = 0; + int result = wait_for_idle(target, &abstractcs); + + info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); + if (info->cmderr != 0 || result != ERROR_OK) { + LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, abstractcs); + /* Clear the error. */ + dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, + unsigned size_bits) +{ + riscv_reg_t value = 0; + uint32_t v; + unsigned offset = index * size_bits / 32; + switch (size_bits) { + default: + LOG_ERROR("Unsupported size: %d bits", size_bits); + return ~0; + case 64: + dmi_read(target, &v, DM_DATA0 + offset + 1); + value |= ((uint64_t) v) << 32; + /* falls through */ + case 32: + dmi_read(target, &v, DM_DATA0 + offset); + value |= v; + } + return value; +} + +static int write_abstract_arg(struct target *target, unsigned index, + riscv_reg_t value, unsigned size_bits) +{ + unsigned offset = index * size_bits / 32; + switch (size_bits) { + default: + LOG_ERROR("Unsupported size: %d bits", size_bits); + return ERROR_FAIL; + case 64: + dmi_write(target, DM_DATA0 + offset + 1, value >> 32); + /* falls through */ + case 32: + dmi_write(target, DM_DATA0 + offset, value); + } + return ERROR_OK; +} + +/** + * @par size in bits + */ +static uint32_t access_register_command(struct target *target, uint32_t number, + unsigned size, uint32_t flags) +{ + uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); + switch (size) { + case 32: + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); + break; + default: + LOG_ERROR("[%s] %d-bit register %s not supported.", + target_name(target), size, gdb_regno_name(number)); + assert(0); + } + + if (number <= GDB_REGNO_XPR31) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1000 + number - GDB_REGNO_ZERO); + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1020 + number - GDB_REGNO_FPR0); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + number - GDB_REGNO_CSR0); + } else if (number >= GDB_REGNO_COUNT) { + /* Custom register. */ + assert(target->reg_cache->reg_list[number].arch_info); + riscv_reg_info_t *reg_info = target->reg_cache->reg_list[number].arch_info; + assert(reg_info); + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0xc000 + reg_info->custom_number); + } else { + assert(0); + } + + command |= flags; + + return command; +} + +static int register_read_abstract(struct target *target, uint64_t *value, + uint32_t number, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_read_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_read_csr_supported) + return ERROR_FAIL; + /* The spec doesn't define abstract register numbers for vector registers. */ + if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) + return ERROR_FAIL; + + uint32_t command = access_register_command(target, number, size, + AC_ACCESS_REGISTER_TRANSFER); + + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + info->abstract_read_fpr_supported = false; + LOG_INFO("Disabling abstract command reads from FPRs."); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + info->abstract_read_csr_supported = false; + LOG_INFO("Disabling abstract command reads from CSRs."); + } + } + return result; + } + + if (value) + *value = read_abstract_arg(target, 0, size); + + return ERROR_OK; +} + +static int register_write_abstract(struct target *target, uint32_t number, + uint64_t value, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_write_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_write_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(target, number, size, + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); + + if (write_abstract_arg(target, 0, value, size) != ERROR_OK) + return ERROR_FAIL; + + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + info->abstract_write_fpr_supported = false; + LOG_INFO("Disabling abstract command writes to FPRs."); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + info->abstract_write_csr_supported = false; + LOG_INFO("Disabling abstract command writes to CSRs."); + } + } + return result; + } + + return ERROR_OK; +} + +/* + * Sets the AAMSIZE field of a memory access abstract command based on + * the width (bits). + */ +static uint32_t abstract_memory_size(unsigned width) +{ + switch (width) { + case 8: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 0); + case 16: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 1); + case 32: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 2); + case 64: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 3); + case 128: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 4); + default: + LOG_ERROR("Unsupported memory width: %d", width); + return 0; + } +} + +/* + * Creates a memory access abstract command. + */ +static uint32_t access_memory_command(struct target *target, bool virtual, + unsigned width, bool postincrement, bool write) +{ + uint32_t command = set_field(0, AC_ACCESS_MEMORY_CMDTYPE, 2); + command = set_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL, virtual); + command |= abstract_memory_size(width); + command = set_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT, + postincrement); + command = set_field(command, AC_ACCESS_MEMORY_WRITE, write); + + return command; +} + +static int examine_progbuf(struct target *target) +{ + riscv013_info_t *info = get_info(target); + + if (info->progbuf_writable != YNM_MAYBE) + return ERROR_OK; + + /* Figure out if progbuf is writable. */ + + if (info->progbufsize < 1) { + info->progbuf_writable = YNM_NO; + LOG_INFO("No program buffer present."); + return ERROR_OK; + } + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, auipc(S0)); + if (riscv_program_exec(&program, target) != ERROR_OK) + return ERROR_FAIL; + + if (register_read_direct(target, &info->progbuf_address, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + riscv_program_init(&program, target); + riscv_program_insert(&program, sw(S0, S0, 0)); + int result = riscv_program_exec(&program, target); + + if (result != ERROR_OK) { + /* This program might have failed if the program buffer is not + * writable. */ + info->progbuf_writable = YNM_NO; + return ERROR_OK; + } + + uint32_t written; + if (dmi_read(target, &written, DM_PROGBUF0) != ERROR_OK) + return ERROR_FAIL; + if (written == (uint32_t) info->progbuf_address) { + LOG_INFO("progbuf is writable at 0x%" PRIx64, + info->progbuf_address); + info->progbuf_writable = YNM_YES; + + } else { + LOG_INFO("progbuf is not writeable at 0x%" PRIx64, + info->progbuf_address); + info->progbuf_writable = YNM_NO; + } + + return ERROR_OK; +} + +static int is_fpu_reg(uint32_t gdb_regno) +{ + return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FRM) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR); +} + +static int is_vector_reg(uint32_t gdb_regno) +{ + return (gdb_regno >= GDB_REGNO_V0 && gdb_regno <= GDB_REGNO_V31) || + gdb_regno == GDB_REGNO_VSTART || + gdb_regno == GDB_REGNO_VXSAT || + gdb_regno == GDB_REGNO_VXRM || + gdb_regno == GDB_REGNO_VL || + gdb_regno == GDB_REGNO_VTYPE || + gdb_regno == GDB_REGNO_VLENB; +} + +static int prep_for_register_access(struct target *target, uint64_t *mstatus, + int regno) +{ + if (is_fpu_reg(regno) || is_vector_reg(regno)) { + if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) { + if (register_write_direct(target, GDB_REGNO_MSTATUS, + set_field(*mstatus, MSTATUS_FS, 1)) != ERROR_OK) + return ERROR_FAIL; + } else if (is_vector_reg(regno) && (*mstatus & MSTATUS_VS) == 0) { + if (register_write_direct(target, GDB_REGNO_MSTATUS, + set_field(*mstatus, MSTATUS_VS, 1)) != ERROR_OK) + return ERROR_FAIL; + } + } else { + *mstatus = 0; + } + return ERROR_OK; +} + +static int cleanup_after_register_access(struct target *target, + uint64_t mstatus, int regno) +{ + if ((is_fpu_reg(regno) && (mstatus & MSTATUS_FS) == 0) || + (is_vector_reg(regno) && (mstatus & MSTATUS_VS) == 0)) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; +} + +typedef enum { + SPACE_DM_DATA, + SPACE_DMI_PROGBUF, + SPACE_DMI_RAM +} memory_space_t; + +typedef struct { + /* How can the debugger access this memory? */ + memory_space_t memory_space; + /* Memory address to access the scratch memory from the hart. */ + riscv_addr_t hart_address; + /* Memory address to access the scratch memory from the debugger. */ + riscv_addr_t debug_address; + struct working_area *area; +} scratch_mem_t; + +/** + * Find some scratch memory to be used with the given program. + */ +static int scratch_reserve(struct target *target, + scratch_mem_t *scratch, + struct riscv_program *program, + unsigned size_bytes) +{ + riscv_addr_t alignment = 1; + while (alignment < size_bytes) + alignment *= 2; + + scratch->area = NULL; + + riscv013_info_t *info = get_info(target); + + /* Option 1: See if data# registers can be used as the scratch memory */ + if (info->dataaccess == 1) { + /* Sign extend dataaddr. */ + scratch->hart_address = info->dataaddr; + if (info->dataaddr & (1<<11)) + scratch->hart_address |= 0xfffffffffffff000ULL; + /* Align. */ + scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); + + if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= + info->datasize) { + scratch->memory_space = SPACE_DM_DATA; + scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; + return ERROR_OK; + } + } + + /* Option 2: See if progbuf can be used as the scratch memory */ + if (examine_progbuf(target) != ERROR_OK) + return ERROR_FAIL; + + /* Allow for ebreak at the end of the program. */ + unsigned program_size = (program->instruction_count + 1) * 4; + scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & + ~(alignment - 1); + if ((info->progbuf_writable == YNM_YES) && + ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= + info->progbufsize)) { + scratch->memory_space = SPACE_DMI_PROGBUF; + scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; + return ERROR_OK; + } + + /* Option 3: User-configured memory area as scratch RAM */ + if (target_alloc_working_area(target, size_bytes + alignment - 1, + &scratch->area) == ERROR_OK) { + scratch->hart_address = (scratch->area->address + alignment - 1) & + ~(alignment - 1); + scratch->memory_space = SPACE_DMI_RAM; + scratch->debug_address = scratch->hart_address; + return ERROR_OK; + } + + LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " + "a work area with 'configure -work-area-phys'.", size_bytes); + return ERROR_FAIL; +} + +static int scratch_release(struct target *target, + scratch_mem_t *scratch) +{ + return target_free_working_area(target, scratch->area); +} + +static int scratch_read64(struct target *target, scratch_mem_t *scratch, + uint64_t *value) +{ + uint32_t v; + switch (scratch->memory_space) { + case SPACE_DM_DATA: + if (dmi_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; + break; + case SPACE_DMI_PROGBUF: + if (dmi_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = {0}; + if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK) + return ERROR_FAIL; + *value = buffer[0] | + (((uint64_t) buffer[1]) << 8) | + (((uint64_t) buffer[2]) << 16) | + (((uint64_t) buffer[3]) << 24) | + (((uint64_t) buffer[4]) << 32) | + (((uint64_t) buffer[5]) << 40) | + (((uint64_t) buffer[6]) << 48) | + (((uint64_t) buffer[7]) << 56); + } + break; + } + return ERROR_OK; +} + +static int scratch_write64(struct target *target, scratch_mem_t *scratch, + uint64_t value) +{ + switch (scratch->memory_space) { + case SPACE_DM_DATA: + dmi_write(target, DM_DATA0 + scratch->debug_address, value); + dmi_write(target, DM_DATA1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_PROGBUF: + dmi_write(target, DM_PROGBUF0 + scratch->debug_address, value); + dmi_write(target, DM_PROGBUF1 + scratch->debug_address, value >> 32); + riscv013_invalidate_cached_debug_buffer(target); + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = { + value, + value >> 8, + value >> 16, + value >> 24, + value >> 32, + value >> 40, + value >> 48, + value >> 56 + }; + if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + } + break; + } + return ERROR_OK; +} + +/** Return register size in bits. */ +static unsigned register_size(struct target *target, unsigned number) +{ + /* If reg_cache hasn't been initialized yet, make a guess. We need this for + * when this function is called during examine(). */ + if (target->reg_cache) + return target->reg_cache->reg_list[number].size; + else + return riscv_xlen(target); +} + +static bool has_sufficient_progbuf(struct target *target, unsigned size) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + + return info->progbufsize + r->impebreak >= size; +} + +/** + * Immediately write the new value to the requested register. This mechanism + * bypasses any caches. + */ + int register_write_direct(struct target *target, unsigned number, + uint64_t value) +{ + LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(number), value); + + int result = register_write_abstract(target, number, value, + register_size(target, number)); + if (result == ERROR_OK || !has_sufficient_progbuf(target, 2) || + !riscv_is_halted(target)) + return result; + + struct riscv_program program; + riscv_program_init(&program, target); + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + scratch_mem_t scratch; + bool use_scratch = false; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + riscv_supports_extension(target, 'D') && + riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a register, so + * we need to use some scratch RAM. */ + use_scratch = true; + if (riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)) + != ERROR_OK) + return ERROR_FAIL; + + if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + + if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + + if (scratch_write64(target, &scratch, value) != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + + } else { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (riscv_supports_extension(target, 'D')) { + if (riscv_program_insert(&program, + fmv_d_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) + return ERROR_FAIL; + } else { + if (riscv_program_insert(&program, + fmv_w_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) + return ERROR_FAIL; + } + } else if (number == GDB_REGNO_VTYPE) { + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, csrr(S1, CSR_VL)) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, vsetvl(ZERO, S1, S0)) != ERROR_OK) + return ERROR_FAIL; + } else if (number == GDB_REGNO_VL) { + /* "The XLEN-bit-wide read-only vl CSR can only be updated by the + * vsetvli and vsetvl instructions, and the fault-only-rst vector + * load instruction variants." */ + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, csrr(S1, CSR_VTYPE)) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, vsetvl(ZERO, S0, S1)) != ERROR_OK) + return ERROR_FAIL; + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + if (riscv_program_csrw(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + return ERROR_FAIL; + } + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + } + + int exec_out = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ + if (exec_out == ERROR_OK && target->reg_cache) { + struct reg *reg = &target->reg_cache->reg_list[number]; + buf_set_u64(reg->value, 0, reg->size, value); + } + + if (use_scratch) + scratch_release(target, &scratch); + + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + return exec_out; +} + +/** Actually read registers from the target right now. */ +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) +{ + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + int result = register_read_abstract(target, value, number, + register_size(target, number)); + + if (result != ERROR_OK && + has_sufficient_progbuf(target, 2) && + number > GDB_REGNO_XPR31) { + struct riscv_program program; + riscv_program_init(&program, target); + + scratch_mem_t scratch; + bool use_scratch = false; + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + /* Write program to move data into s0. */ + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (riscv_supports_extension(target, 'D') + && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a + * register, so we need to use some scratch RAM. */ + if (riscv_program_insert(&program, + fsd(number - GDB_REGNO_FPR0, S0, 0)) != ERROR_OK) + return ERROR_FAIL; + if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + use_scratch = true; + + if (register_write_direct(target, GDB_REGNO_S0, + scratch.hart_address) != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + } else if (riscv_supports_extension(target, 'D')) { + if (riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)) != + ERROR_OK) + return ERROR_FAIL; + } else { + if (riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)) != + ERROR_OK) + return ERROR_FAIL; + } + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + if (riscv_program_csrr(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_ERROR("Unsupported register: %s", gdb_regno_name(number)); + return ERROR_FAIL; + } + + /* Execute program. */ + result = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ + + if (use_scratch) { + result = scratch_read64(target, &scratch, value); + scratch_release(target, &scratch); + if (result != ERROR_OK) + return result; + } else { + /* Read S0 */ + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + } + + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; + } + + if (result == ERROR_OK) + LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(number), *value); + + return result; +} + +static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) +{ + time_t start = time(NULL); + while (1) { + uint32_t value; + if (dmstatus_read(target, &value, false) != ERROR_OK) + return ERROR_FAIL; + if (dmstatus) + *dmstatus = value; + if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + value); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +/*** OpenOCD target functions. ***/ + +static void deinit_target(struct target *target) +{ + LOG_DEBUG("riscv_deinit_target()"); + riscv_info_t *info = (riscv_info_t *) target->arch_info; + free(info->version_specific); + /* TODO: free register arch_info */ + info->version_specific = NULL; +} + +typedef enum { + HALTGROUP, + RESUMEGROUP +} grouptype_t; +static int set_group(struct target *target, bool *supported, unsigned group, grouptype_t grouptype) +{ + uint32_t write_val = DM_DMCS2_HGWRITE; + assert(group <= 31); + write_val = set_field(write_val, DM_DMCS2_GROUP, group); + write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 0 : 1); + if (dmi_write(target, DM_DMCS2, write_val) != ERROR_OK) + return ERROR_FAIL; + uint32_t read_val; + if (dmi_read(target, &read_val, DM_DMCS2) != ERROR_OK) + return ERROR_FAIL; + *supported = get_field(read_val, DM_DMCS2_GROUP) == group; + return ERROR_OK; +} + +static int discover_vlenb(struct target *target) +{ + RISCV_INFO(r); + riscv_reg_t vlenb; + + if (register_read_direct(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) { + LOG_WARNING("Couldn't read vlenb for %s; vector register access won't work.", + target_name(target)); + r->vlenb = 0; + return ERROR_OK; + } + r->vlenb = vlenb; + + LOG_INFO("Vector support with vlenb=%d", r->vlenb); + + return ERROR_OK; +} + +static int examine(struct target *target) +{ + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + + riscv013_info_t *info = get_info(target); + /* TODO: This won't be true if there are multiple DMs. */ + info->index = target->coreid; + // info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); + // info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); + + /* Reset the Debug Module. */ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (!dm->was_reset) { + dmi_write(target, DM_DMCONTROL, 0); + dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); + dm->was_reset = true; + + /* The DM gets reset, so forget any cached progbuf entries. */ + riscv013_invalidate_cached_debug_buffer(target); + } + + // dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | + // DM_DMCONTROL_HARTSELHI | DM_DMCONTROL_DMACTIVE | + // DM_DMCONTROL_HASEL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + + if (!get_field(dmcontrol, DM_DMCONTROL_DMACTIVE)) { + LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", + dmcontrol); + return ERROR_FAIL; + } + + dm->hasel_supported = get_field(dmcontrol, DM_DMCONTROL_HASEL); + + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("dmstatus: 0x%08x", dmstatus); + int dmstatus_version = get_field(dmstatus, DM_DMSTATUS_VERSION); + if (dmstatus_version != 2 && dmstatus_version != 3) { + /* Error was already printed out in dmstatus_read(). */ + return ERROR_FAIL; + } + + uint32_t hartsel = + (get_field(dmcontrol, DM_DMCONTROL_HARTSELHI) << + DM_DMCONTROL_HARTSELLO_LENGTH) | + get_field(dmcontrol, DM_DMCONTROL_HARTSELLO); + info->hartsellen = 0; + while (hartsel & 1) { + info->hartsellen++; + hartsel >>= 1; + } + LOG_DEBUG("hartsellen=%d", info->hartsellen); + + uint32_t hartinfo; + if (dmi_read(target, &hartinfo, DM_HARTINFO) != ERROR_OK) + return ERROR_FAIL; + + info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR); + + if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) { + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", dmstatus); + return ERROR_FAIL; + } + + if (dmi_read(target, &info->sbcs, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + + /* Check that abstract data registers are accessible. */ + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); + info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); + + LOG_INFO("[%s] datacount=%d progbufsize=%d", target_name(target), + info->datacount, info->progbufsize); + + RISCV_INFO(r); + r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); + + if (!has_sufficient_progbuf(target, 2)) { + LOG_WARNING("We won't be able to execute fence instructions on this " + "target. Memory may not always appear consistent. " + "(progbufsize=%d, impebreak=%d)", info->progbufsize, + r->impebreak); + } + + if (info->progbufsize < 4 && riscv_enable_virtual) { + LOG_ERROR("set_enable_virtual is not available on this target. It " + "requires a program buffer size of at least 4. (progbufsize=%d) " + "Use `riscv set_enable_virtual off` to continue." + , info->progbufsize); + } + + /* Before doing anything else we must first enumerate the harts. */ + if (dm->hart_count < 0) { + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { + if (dm013_select_hart(target, i) != ERROR_OK) + return ERROR_FAIL; + + uint32_t s; + if (dmstatus_read(target, &s, true) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(s, DM_DMSTATUS_ANYNONEXISTENT)) + break; + dm->hart_count = i + 1; + + if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) + dmi_write(target, DM_DMCONTROL, + set_dmcontrol_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); + } + + LOG_DEBUG("Detected %d harts.", dm->hart_count); + } + + if (dm->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } + + /* Don't call any riscv_* functions until after we've counted the number of + * cores and initialized registers. */ + + if (dm013_select_hart(target, info->index) != ERROR_OK) + return ERROR_FAIL; + + bool halted = riscv_is_halted(target); + if (!halted) { + r->prepped = true; + if (riscv013_halt_go(target) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()", + info->index); + return ERROR_FAIL; + } + } + + /* Without knowing anything else we can at least mess with the + * program buffer. */ + r->debug_buffer_size = info->progbufsize; + + int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); + + if (result == ERROR_OK) + r->xlen = 64; + else + r->xlen = 32; + + /* Save s0 and s1. The register cache hasn't be initialized yet so we + * need to take care of this manually. */ + uint64_t s0, s1; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); + return ERROR_FAIL; + } + if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); + return ERROR_FAIL; + } + + if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { + LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA."); + return ERROR_FAIL; + } + + if (riscv_supports_extension(target, 'V')) { + if (discover_vlenb(target) != ERROR_OK) + return ERROR_FAIL; + } + + /* Now init registers based on what we discovered. */ + if (riscv_init_registers(target) != ERROR_OK) + return ERROR_FAIL; + + /* Display this as early as possible to help people who are using + * really slow simulators. */ + LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); + + /* Restore s0 and s1. */ + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0."); + return ERROR_FAIL; + } + if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1."); + return ERROR_FAIL; + } + + if (!halted) + riscv013_step_or_resume_current_hart(target, false); + + if (target->smp) { + bool haltgroup_supported; + if (set_group(target, &haltgroup_supported, target->smp, HALTGROUP) != ERROR_OK) + return ERROR_FAIL; + if (haltgroup_supported) + LOG_INFO("Core %d made part of halt group %d.", target->coreid, + target->smp); + else + LOG_INFO("Core %d could not be made part of halt group %d.", + target->coreid, target->smp); + } + + /* Some regression suites rely on seeing 'Examined RISC-V core' to know + * when they can connect with gdb/telnet. + * We will need to update those suites if we want to change that text. */ + LOG_TARGET_INFO(target, "Examined RISC-V core; found %d harts", + riscv_count_harts(target)); + LOG_TARGET_INFO(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); + return ERROR_OK; +} + +static int riscv013_authdata_read(struct target *target, uint32_t *value, unsigned int index) +{ + if (index > 0) { + LOG_ERROR("Spec 0.13 only has a single authdata register."); + return ERROR_FAIL; + } + + if (wait_for_authbusy(target, NULL) != ERROR_OK) + return ERROR_FAIL; + + return dmi_read(target, value, DM_AUTHDATA); +} + +static int riscv013_authdata_write(struct target *target, uint32_t value, unsigned int index) +{ + if (index > 0) { + LOG_ERROR("Spec 0.13 only has a single authdata register."); + return ERROR_FAIL; + } + + uint32_t before, after; + if (wait_for_authbusy(target, &before) != ERROR_OK) + return ERROR_FAIL; + + dmi_write(target, DM_AUTHDATA, value); + + if (wait_for_authbusy(target, &after) != ERROR_OK) + return ERROR_FAIL; + + if (!get_field(before, DM_DMSTATUS_AUTHENTICATED) && + get_field(after, DM_DMSTATUS_AUTHENTICATED)) { + LOG_INFO("authdata_write resulted in successful authentication"); + int result = ERROR_OK; + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + target_list_t *entry; + list_for_each_entry(entry, &dm->target_list, list) { + if (target_examine_one(entry->target) != ERROR_OK) + result = ERROR_FAIL; + } + return result; + } + + return ERROR_OK; +} + +static int riscv013_hart_count(struct target *target) +{ + dm013_info_t *dm = get_dm(target); + assert(dm); + return dm->hart_count; + +} + +/* Try to find out the widest memory access size depending on the selected memory access methods. */ +static unsigned riscv013_data_bits(struct target *target) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (has_sufficient_progbuf(target, 3)) + return riscv_xlen(target); + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (get_field(info->sbcs, DM_SBCS_SBACCESS128)) + return 128; + if (get_field(info->sbcs, DM_SBCS_SBACCESS64)) + return 64; + if (get_field(info->sbcs, DM_SBCS_SBACCESS32)) + return 32; + if (get_field(info->sbcs, DM_SBCS_SBACCESS16)) + return 16; + if (get_field(info->sbcs, DM_SBCS_SBACCESS8)) + return 8; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + /* TODO: Once there is a spec for discovering abstract commands, we can + * take those into account as well. For now we assume abstract commands + * support XLEN-wide accesses. */ + return riscv_xlen(target); + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + } + LOG_ERROR("Unable to determine supported data bits on this target. Assuming 32 bits."); + return 32; +} + +COMMAND_HELPER(wch_riscv013_print_info, struct target *target) +{ + RISCV013_INFO(info); + + /* Abstract description. */ + riscv_print_info_line(CMD, "target", "memory.read_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); + riscv_print_info_line(CMD, "target", "memory.write_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); + riscv_print_info_line(CMD, "target", "memory.read_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); + riscv_print_info_line(CMD, "target", "memory.write_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); + riscv_print_info_line(CMD, "target", "memory.read_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); + riscv_print_info_line(CMD, "target", "memory.write_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); + riscv_print_info_line(CMD, "target", "memory.read_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); + riscv_print_info_line(CMD, "target", "memory.write_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); + riscv_print_info_line(CMD, "target", "memory.read_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); + riscv_print_info_line(CMD, "target", "memory.write_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); + + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) == ERROR_OK) + riscv_print_info_line(CMD, "dm", "authenticated", get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)); + + return 0; +} + +static int prep_for_vector_access(struct target *target, uint64_t *vtype, + uint64_t *vl, unsigned *debug_vl) +{ + RISCV_INFO(r); + /* TODO: this continuous save/restore is terrible for performance. */ + /* Write vtype and vl. */ + unsigned encoded_vsew; + switch (riscv_xlen(target)) { + case 32: + encoded_vsew = 2; + break; + case 64: + encoded_vsew = 3; + break; + default: + LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target)); + return ERROR_FAIL; + } + + /* Save vtype and vl. */ + if (register_read_direct(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK) + return ERROR_FAIL; + if (register_read_direct(target, vl, GDB_REGNO_VL) != ERROR_OK) + return ERROR_FAIL; + + if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) + return ERROR_FAIL; + *debug_vl = DIV_ROUND_UP(r->vlenb * 8, riscv_xlen(target)); + if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int cleanup_after_vector_access(struct target *target, uint64_t vtype, + uint64_t vl) +{ + /* Restore vtype and vl. */ + if (register_write_direct(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_VL, vl) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; +} + +static int riscv013_get_register_buf(struct target *target, + uint8_t *value, int regno) +{ + assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + uint64_t vtype, vl; + unsigned debug_vl; + if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) + return ERROR_FAIL; + + unsigned vnum = regno - GDB_REGNO_V0; + unsigned xlen = riscv_xlen(target); + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, vmv_x_s(S0, vnum)); + riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); + + int result = ERROR_OK; + for (unsigned i = 0; i < debug_vl; i++) { + /* Executing the program might result in an exception if there is some + * issue with the vector implementation/instructions we're using. If that + * happens, attempt to restore as usual. We may have clobbered the + * vector register we tried to read already. + * For other failures, we just return error because things are probably + * so messed up that attempting to restore isn't going to help. */ + result = riscv_program_exec(&program, target); + if (result == ERROR_OK) { + uint64_t v; + if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + buf_set_u64(value, xlen * i, xlen, v); + } else { + break; + } + } + + if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) + return ERROR_FAIL; + + if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static int riscv013_set_register_buf(struct target *target, + int regno, const uint8_t *value) +{ + assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + uint64_t vtype, vl; + unsigned debug_vl; + if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) + return ERROR_FAIL; + + unsigned vnum = regno - GDB_REGNO_V0; + unsigned xlen = riscv_xlen(target); + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); + int result = ERROR_OK; + for (unsigned i = 0; i < debug_vl; i++) { + if (register_write_direct(target, GDB_REGNO_S0, + buf_get_u64(value, xlen * i, xlen)) != ERROR_OK) + return ERROR_FAIL; + result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + break; + } + + if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) + return ERROR_FAIL; + + if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static uint32_t sb_sbaccess(unsigned int size_bytes) +{ + switch (size_bytes) { + case 1: + return set_field(0, DM_SBCS_SBACCESS, 0); + case 2: + return set_field(0, DM_SBCS_SBACCESS, 1); + case 4: + return set_field(0, DM_SBCS_SBACCESS, 2); + case 8: + return set_field(0, DM_SBCS_SBACCESS, 3); + case 16: + return set_field(0, DM_SBCS_SBACCESS, 4); + } + assert(0); + return 0; +} + +static int sb_write_address(struct target *target, target_addr_t address, + bool ensure_success) +{ + RISCV013_INFO(info); + unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + /* There currently is no support for >64-bit addresses in OpenOCD. */ + if (sbasize > 96) + dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); + if (sbasize > 64) + dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); + if (sbasize > 32) + dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, address >> 32, false, false); + return dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, address, + false, ensure_success); +} + +static int batch_run(const struct target *target, struct riscv_batch *batch) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + if (r->reset_delays_wait >= 0) { + r->reset_delays_wait -= batch->used_scans; + if (r->reset_delays_wait <= 0) { + batch->idle_count = 0; + info->dmi_busy_delay = 0; + info->ac_busy_delay = 0; + } + } + return riscv_batch_run(batch); +} + +static int sba_supports_access(struct target *target, unsigned int size_bytes) +{ + RISCV013_INFO(info); + switch (size_bytes) { + case 1: + return get_field(info->sbcs, DM_SBCS_SBACCESS8); + case 2: + return get_field(info->sbcs, DM_SBCS_SBACCESS16); + case 4: + return get_field(info->sbcs, DM_SBCS_SBACCESS32); + case 8: + return get_field(info->sbcs, DM_SBCS_SBACCESS64); + case 16: + return get_field(info->sbcs, DM_SBCS_SBACCESS128); + default: + return 0; + } +} + +static int sample_memory_bus_v1(struct target *target, + struct riscv_sample_buf *buf, + const riscv_sample_config_t *config, + int64_t until_ms) +{ + RISCV013_INFO(info); + unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + if (sbasize > 64) { + LOG_ERROR("Memory sampling is only implemented for sbasize <= 64."); + return ERROR_NOT_IMPLEMENTED; + } + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) != 1) { + LOG_ERROR("Memory sampling is only implemented for SBA version 1."); + return ERROR_NOT_IMPLEMENTED; + } + + uint32_t sbcs = 0; + uint32_t sbcs_valid = false; + + uint32_t sbaddress0 = 0; + bool sbaddress0_valid = false; + uint32_t sbaddress1 = 0; + bool sbaddress1_valid = false; + + /* How often to read each value in a batch. */ + const unsigned int repeat = 5; + + unsigned int enabled_count = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { + if (config->bucket[i].enabled) + enabled_count++; + } + + while (timeval_ms() < until_ms) { + /* + * batch_run() adds to the batch, so we can't simply reuse the same + * batch over and over. So we create a new one every time through the + * loop. + */ + struct riscv_batch *batch = riscv_batch_alloc( + target, 1 + enabled_count * 5 * repeat, + info->dmi_busy_delay + info->bus_master_read_delay); + if (!batch) + return ERROR_FAIL; + + unsigned int result_bytes = 0; + for (unsigned int n = 0; n < repeat; n++) { + for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { + if (config->bucket[i].enabled) { + if (!sba_supports_access(target, config->bucket[i].size_bytes)) { + LOG_ERROR("Hardware does not support SBA access for %d-byte memory sampling.", + config->bucket[i].size_bytes); + return ERROR_NOT_IMPLEMENTED; + } + + uint32_t sbcs_write = DM_SBCS_SBREADONADDR; + if (enabled_count == 1) + sbcs_write |= DM_SBCS_SBREADONDATA; + sbcs_write |= sb_sbaccess(config->bucket[i].size_bytes); + if (!sbcs_valid || sbcs_write != sbcs) { + riscv_batch_add_dmi_write(batch, DM_SBCS, sbcs_write); + sbcs = sbcs_write; + sbcs_valid = true; + } + + if (sbasize > 32 && + (!sbaddress1_valid || + sbaddress1 != config->bucket[i].address >> 32)) { + sbaddress1 = config->bucket[i].address >> 32; + riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1); + sbaddress1_valid = true; + } + if (!sbaddress0_valid || + sbaddress0 != (config->bucket[i].address & 0xffffffff)) { + sbaddress0 = config->bucket[i].address; + riscv_batch_add_dmi_write(batch, DM_SBADDRESS0, sbaddress0); + sbaddress0_valid = true; + } + if (config->bucket[i].size_bytes > 4) + riscv_batch_add_dmi_read(batch, DM_SBDATA1); + riscv_batch_add_dmi_read(batch, DM_SBDATA0); + result_bytes += 1 + config->bucket[i].size_bytes; + } + } + } + + if (buf->used + result_bytes >= buf->size) { + riscv_batch_free(batch); + break; + } + + size_t sbcs_key = riscv_batch_add_dmi_read(batch, DM_SBCS); + + int result = batch_run(target, batch); + if (result != ERROR_OK) + return result; + + uint32_t sbcs_read = riscv_batch_get_dmi_read_data(batch, sbcs_key); + if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { + /* Discard this batch (too much hassle to try to recover partial + * data) and try again with a larger delay. */ + info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; + dmi_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); + riscv_batch_free(batch); + continue; + } + if (get_field(sbcs_read, DM_SBCS_SBERROR)) { + /* The memory we're sampling was unreadable, somehow. Give up. */ + dmi_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); + riscv_batch_free(batch); + return ERROR_FAIL; + } + + unsigned int read = 0; + for (unsigned int n = 0; n < repeat; n++) { + for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { + if (config->bucket[i].enabled) { + assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); + uint64_t value = 0; + if (config->bucket[i].size_bytes > 4) + value = ((uint64_t)riscv_batch_get_dmi_read_data(batch, read++)) << 32; + value |= riscv_batch_get_dmi_read_data(batch, read++); + + buf->buf[buf->used] = i; + buf_set_u64(buf->buf + buf->used + 1, 0, config->bucket[i].size_bytes * 8, value); + buf->used += 1 + config->bucket[i].size_bytes; + } + } + } + + riscv_batch_free(batch); + } + + return ERROR_OK; +} + +static int sample_memory(struct target *target, + struct riscv_sample_buf *buf, + riscv_sample_config_t *config, + int64_t until_ms) +{ + if (!config->enabled) + return ERROR_OK; + + return sample_memory_bus_v1(target, buf, config, until_ms); +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + RISCV_INFO(generic_info); + + generic_info->get_register = &riscv013_get_register; + generic_info->set_register = &riscv013_set_register; + generic_info->get_register_buf = &riscv013_get_register_buf; + generic_info->set_register_buf = &riscv013_set_register_buf; + generic_info->select_target = &dm013_select_target; + generic_info->is_halted = &riscv013_is_halted; + generic_info->resume_go = &riscv013_resume_go; + generic_info->step_current_hart = &riscv013_step_current_hart; + generic_info->on_halt = &riscv013_on_halt; + generic_info->resume_prep = &riscv013_resume_prep; + generic_info->halt_prep = &riscv013_halt_prep; + generic_info->halt_go = &riscv013_halt_go; + generic_info->on_step = &riscv013_on_step; + generic_info->halt_reason = &riscv013_halt_reason; + generic_info->read_debug_buffer = &riscv013_read_debug_buffer; + generic_info->write_debug_buffer = &riscv013_write_debug_buffer; + generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; + generic_info->invalidate_cached_debug_buffer = &riscv013_invalidate_cached_debug_buffer; + generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; + generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; + generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; + generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; + generic_info->authdata_read = &riscv013_authdata_read; + generic_info->authdata_write = &riscv013_authdata_write; + generic_info->dmi_read = &dmi_read; + generic_info->dmi_write = &dmi_write; + generic_info->read_memory = read_memory; + generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg; + generic_info->hart_count = &riscv013_hart_count; + generic_info->data_bits = &riscv013_data_bits; + generic_info->print_info = &wch_riscv013_print_info; + if (!generic_info->version_specific) { + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + } + + riscv013_info_t *info = get_info(target); + + info->progbufsize = -1; + + info->dmi_busy_delay = 0; + info->bus_master_read_delay = 0; + info->bus_master_write_delay = 0; + info->ac_busy_delay = 0; + + /* Assume all these abstract commands are supported until we learn + * otherwise. + * TODO: The spec allows eg. one CSR to be able to be accessed abstractly + * while another one isn't. We don't track that this closely here, but in + * the future we probably should. */ + info->abstract_read_csr_supported = true; + info->abstract_write_csr_supported = true; + info->abstract_read_fpr_supported = true; + info->abstract_write_fpr_supported = true; + + info->has_aampostincrement = YNM_MAYBE; + + return ERROR_OK; +} + +static int assert_reset(struct target *target) +{ + RISCV013_INFO(info); + + target->reset_halt=1; + + uint32_t control_base = set_field(0, DM_DMCONTROL_DMACTIVE, 1); + + if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { + /* Run the user-supplied script if there is one. */ + target_handle_event(target, TARGET_EVENT_RESET_ASSERT); + } else if (target->rtos) { + /* There's only one target, and OpenOCD thinks each hart is a thread. + * We must reset them all. */ + + /* TODO: Try to use hasel in dmcontrol */ + + /* Set haltreq for each hart. */ + uint32_t control = control_base; + + control = set_dmcontrol_hartsel(control_base, info->index); + control = set_field(control, DM_DMCONTROL_HALTREQ, + target->reset_halt ? 1 : 0); + dmi_write(target, DM_DMCONTROL, control); + + /* Assert ndmreset */ + control = set_field(control, DM_DMCONTROL_NDMRESET, 1); + dmi_write(target, DM_DMCONTROL, control); + + } else { + /* Reset just this hart. */ + uint32_t control = set_dmcontrol_hartsel(control_base, info->index); + control = set_field(control, DM_DMCONTROL_HALTREQ, + target->reset_halt ? 1 : 0); + control = set_field(control, DM_DMCONTROL_NDMRESET, 1); + dmi_write(target, DM_DMCONTROL, control); + } + + target->state = TARGET_RESET; + + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + /* The DM might have gotten reset if OpenOCD called us in some reset that + * involves SRST being toggled. So clear our cache which may be out of + * date. */ + riscv013_invalidate_cached_debug_buffer(target); + + return ERROR_OK; +} + +static int deassert_reset(struct target *target) +{ + RISCV013_INFO(info); + target->reset_halt=1; + + /* Clear the reset, but make sure haltreq is still set */ + uint32_t control = 0; + control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); + control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); + dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index)); + + uint32_t dmstatus; + int dmi_busy_delay = info->dmi_busy_delay; + time_t start = time(NULL); + + for (unsigned int i = 0; i < riscv_count_harts(target); ++i) { + unsigned int index = i; + if (target->rtos) { + if (index != info->index) + continue; + dmi_write(target, DM_DMCONTROL, + set_dmcontrol_hartsel(control, index)); + } else { + index = info->index; + } + + LOG_DEBUG("Waiting for hart %d to come out of reset.", index); + while (1) { + int result = dmstatus_read_timeout(target, &dmstatus, true, + riscv_reset_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) + LOG_ERROR("Hart %d didn't complete a DMI read coming out of " + "reset in %ds; Increase the timeout with riscv " + "set_reset_timeout_sec.", + index, riscv_reset_timeout_sec); + break; + } + if (target->reset_halt) { + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + } else { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + + if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { + /* Ack reset. */ + dmi_write(target, DM_DMCONTROL, + set_dmcontrol_hartsel(control, index) | + DM_DMCONTROL_ACKHAVERESET); + } + + if (!target->rtos) + break; + } + info->dmi_busy_delay = dmi_busy_delay; + uint64_t tmpDcsr; + int res = register_read_direct(target, &tmpDcsr, GDB_REGNO_DCSR); + if(res != ERROR_OK){ + LOG_DEBUG("[wch] dcsr read fail!"); + } + else{ + LOG_DEBUG("[wch] read dcsr value is 0x%x", tmpDcsr); + //enable ebreak in m&u mode + tmpDcsr = set_field(tmpDcsr, CSR_DCSR_EBREAKM, 1); + tmpDcsr = set_field(tmpDcsr, CSR_DCSR_EBREAKU, 1); + res = register_write_direct(target, GDB_REGNO_DCSR, tmpDcsr); + register_read_direct(target, &tmpDcsr, GDB_REGNO_DCSR); + if(res == ERROR_OK){ + } + else{ + LOG_DEBUG("[wch] dcsr write fail"); + assert(false); + } + } + + return ERROR_OK; +} + +static int execute_fence(struct target *target) +{ + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + /* FIXME: For non-coherent systems we need to flush the caches right + * here, but there's no ISA-defined way of doing that. */ + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_fence_i(&program); + riscv_program_fence(&program); + int result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + LOG_TARGET_DEBUG(target, "Unable to execute pre-fence"); + + return ERROR_OK; +} + +static void log_memory_access(target_addr_t address, uint64_t value, + unsigned size_bytes, bool read) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + char fmt[80]; + sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, + address, read ? "read" : "write", size_bytes * 2); + switch (size_bytes) { + case 1: + value &= 0xff; + break; + case 2: + value &= 0xffff; + break; + case 4: + value &= 0xffffffffUL; + break; + case 8: + break; + default: + assert(false); + } + LOG_DEBUG(fmt, value); +} + +/* Read the relevant sbdata regs depending on size, and put the results into + * buffer. */ +static int read_memory_bus_word(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + uint32_t value; + int result; + static int sbdata[4] = { DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3 }; + assert(size <= 16); + for (int i = (size - 1) / 4; i >= 0; i--) { + result = dmi_op(target, &value, NULL, DMI_OP_READ, sbdata[i], 0, false, true); + if (result != ERROR_OK) + return result; + buf_set_u32(buffer + i * 4, 0, 8 * MIN(size, 4), value); + log_memory_access(address + i * 4, value, MIN(size, 4), true); + } + return ERROR_OK; +} + +static target_addr_t sb_read_address(struct target *target) +{ + RISCV013_INFO(info); + unsigned sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + target_addr_t address = 0; + uint32_t v; + if (sbasize > 32) { + dmi_read(target, &v, DM_SBADDRESS1); + address |= v; + address <<= 32; + } + dmi_read(target, &v, DM_SBADDRESS0); + address |= v; + return address; +} + +static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) +{ + time_t start = time(NULL); + while (1) { + if (dmi_read(target, sbcs, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + if (!get_field(*sbcs, DM_SBCS_SBBUSY)) + return ERROR_OK; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, *sbcs); + return ERROR_FAIL; + } + } +} + +static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old) +{ + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) { + /* Read DCSR */ + uint64_t dcsr; + if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + + /* Read and save MSTATUS */ + if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + *mstatus_old = *mstatus; + + /* If we come from m-mode with mprv set, we want to keep mpp */ + if (get_field(dcsr, CSR_DCSR_PRV) < 3) { + /* MPP = PRIV */ + *mstatus = set_field(*mstatus, MSTATUS_MPP, get_field(dcsr, CSR_DCSR_PRV)); + + /* MPRV = 1 */ + *mstatus = set_field(*mstatus, MSTATUS_MPRV, 1); + + /* Write MSTATUS */ + if (*mstatus != *mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int read_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + if (size != increment) { + LOG_ERROR("sba v0 reads only support size==increment"); + return ERROR_NOT_IMPLEMENTED; + } + + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + uint8_t *t_buffer = buffer; + riscv_addr_t cur_addr = address; + riscv_addr_t fin_addr = address + (count * size); + uint32_t access = 0; + + const int DM_SBCS_SBSINGLEREAD_OFFSET = 20; + const uint32_t DM_SBCS_SBSINGLEREAD = (0x1U << DM_SBCS_SBSINGLEREAD_OFFSET); + + const int DM_SBCS_SBAUTOREAD_OFFSET = 15; + const uint32_t DM_SBCS_SBAUTOREAD = (0x1U << DM_SBCS_SBAUTOREAD_OFFSET); + + /* ww favorise one off reading if there is an issue */ + if (count == 1) { + for (uint32_t i = 0; i < count; i++) { + if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + dmi_write(target, DM_SBADDRESS0, cur_addr); + /* size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); + LOG_DEBUG("\r\nread_memory: sab: access: 0x%08x", access); + dmi_write(target, DM_SBCS, access); + /* 3) read */ + uint32_t value; + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); + buf_set_u32(t_buffer, 0, 8 * size, value); + t_buffer += size; + cur_addr += size; + } + return ERROR_OK; + } + + /* has to be the same size if we want to read a block */ + LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); + if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + /* set current address */ + dmi_write(target, DM_SBADDRESS0, cur_addr); + /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement + * size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBAUTOREAD, 1); + access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); + access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08x", access); + dmi_write(target, DM_SBCS, access); + + while (cur_addr < fin_addr) { + LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" + PRIx64, size, count, cur_addr); + /* read */ + uint32_t value; + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + buf_set_u32(t_buffer, 0, 8 * size, value); + cur_addr += size; + t_buffer += size; + + /* if we are reaching last address, we must clear autoread */ + if (cur_addr == fin_addr && count != 1) { + dmi_write(target, DM_SBCS, 0); + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + buf_set_u32(t_buffer, 0, 8 * size, value); + } + } + + uint32_t sbcs; + if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + + +static void log_mem_access_result(struct target *target, bool success, int method, bool read) +{ + RISCV_INFO(r); + bool warn = false; + char msg[60]; + + /* Compose the message */ + snprintf(msg, 60, "%s to %s memory via %s.", + success ? "Succeeded" : "Failed", + read ? "read" : "write", + (method == RISCV_MEM_ACCESS_PROGBUF) ? "program buffer" : + (method == RISCV_MEM_ACCESS_SYSBUS) ? "system bus" : "abstract access"); + + /* Determine the log message severity. Show warnings only once. */ + if (!success) { + if (method == RISCV_MEM_ACCESS_PROGBUF) { + warn = r->mem_access_progbuf_warn; + r->mem_access_progbuf_warn = false; + } + if (method == RISCV_MEM_ACCESS_SYSBUS) { + warn = r->mem_access_sysbus_warn; + r->mem_access_sysbus_warn = false; + } + if (method == RISCV_MEM_ACCESS_ABSTRACT) { + warn = r->mem_access_abstract_warn; + r->mem_access_abstract_warn = false; + } + } + + if (warn) + LOG_WARNING("%s", msg); + else + LOG_DEBUG("%s", msg); +} + +static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, + uint32_t size, bool read, char **skip_reason) +{ + assert(skip_reason); + + if (!has_sufficient_progbuf(target, 3)) { + LOG_DEBUG("Skipping mem %s via progbuf - insufficient progbuf size.", + read ? "read" : "write"); + *skip_reason = "skipped (insufficient progbuf)"; + return true; + } + if (target->state != TARGET_HALTED) { + LOG_DEBUG("Skipping mem %s via progbuf - target not halted.", + read ? "read" : "write"); + *skip_reason = "skipped (target not halted)"; + return true; + } + if (riscv_xlen(target) < size * 8) { + LOG_DEBUG("Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", + read ? "read" : "write", riscv_xlen(target), size * 8); + *skip_reason = "skipped (XLEN too short)"; + return true; + } + if (size > 8) { + LOG_DEBUG("Skipping mem %s via progbuf - unsupported size.", + read ? "read" : "write"); + *skip_reason = "skipped (unsupported size)"; + return true; + } + if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { + LOG_DEBUG("Skipping mem %s via progbuf - progbuf only supports %u-bit address.", + read ? "read" : "write", riscv_xlen(target)); + *skip_reason = "skipped (too large address)"; + return true; + } + + return false; +} + +static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool read, char **skip_reason) +{ + assert(skip_reason); + + RISCV013_INFO(info); + if (!sba_supports_access(target, size)) { + LOG_DEBUG("Skipping mem %s via system bus - unsupported size.", + read ? "read" : "write"); + *skip_reason = "skipped (unsupported size)"; + return true; + } + unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + if ((sizeof(address) * 8 > sbasize) && (address >> sbasize)) { + LOG_DEBUG("Skipping mem %s via system bus - sba only supports %u-bit address.", + read ? "read" : "write", sbasize); + *skip_reason = "skipped (too large address)"; + return true; + } + if (read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { + LOG_DEBUG("Skipping mem read via system bus - " + "sba reads only support size==increment or also size==0 for sba v1."); + *skip_reason = "skipped (unsupported increment)"; + return true; + } + + return false; +} + +static bool mem_should_skip_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool read, char **skip_reason) +{ + assert(skip_reason); + + if (size > 8) { + /* TODO: Add 128b support if it's ever used. Involves modifying + read/write_abstract_arg() to work on two 64b values. */ + LOG_DEBUG("Skipping mem %s via abstract access - unsupported size: %d bits", + read ? "read" : "write", size * 8); + *skip_reason = "skipped (unsupported size)"; + return true; + } + if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { + LOG_DEBUG("Skipping mem %s via abstract access - abstract access only supports %u-bit address.", + read ? "read" : "write", riscv_xlen(target)); + *skip_reason = "skipped (too large address)"; + return true; + } + if (read && size != increment) { + LOG_ERROR("Skipping mem read via abstract access - " + "abstract command reads only support size==increment."); + *skip_reason = "skipped (unsupported increment)"; + return true; + } + + return false; +} + +/* + * Performs a memory read using memory access abstract commands. The read sizes + * supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 byte + * aamsize fields in the memory access abstract command. + */ +static int read_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + RISCV013_INFO(info); + + int result = ERROR_OK; + bool use_aampostincrement = info->has_aampostincrement != YNM_NO; + + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); + + memset(buffer, 0, count * size); + + /* Convert the size (bytes) to width (bits) */ + unsigned width = size << 3; + + /* Create the command (physical address, postincrement, read) */ + uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false); + + /* Execute the reads */ + uint8_t *p = buffer; + bool updateaddr = true; + unsigned int width32 = (width < 32) ? 32 : width; + for (uint32_t c = 0; c < count; c++) { + /* Update the address if it is the first time or aampostincrement is not supported by the target. */ + if (updateaddr) { + /* Set arg1 to the address: address + c * size */ + result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); + if (result != ERROR_OK) { + LOG_ERROR("Failed to write arg1 during read_memory_abstract()."); + return result; + } + } + + /* Execute the command */ + result = execute_abstract_command(target, command); + + if (info->has_aampostincrement == YNM_MAYBE) { + if (result == ERROR_OK) { + /* Safety: double-check that the address was really auto-incremented */ + riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); + if (new_address == address + size) { + LOG_DEBUG("aampostincrement is supported on this target."); + info->has_aampostincrement = YNM_YES; + } else { + LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); + info->has_aampostincrement = YNM_NO; + } + } else { + /* Try the same access but with postincrement disabled. */ + command = access_memory_command(target, false, width, false, false); + result = execute_abstract_command(target, command); + if (result == ERROR_OK) { + LOG_DEBUG("aampostincrement is not supported on this target."); + info->has_aampostincrement = YNM_NO; + } + } + } + + if (result != ERROR_OK) + return result; + + /* Copy arg0 to buffer (rounded width up to nearest 32) */ + riscv_reg_t value = read_abstract_arg(target, 0, width32); + buf_set_u64(p, 0, 8 * size, value); + + if (info->has_aampostincrement == YNM_YES) + updateaddr = false; + p += size; + } + + return result; +} + +/* + * Performs a memory write using memory access abstract commands. The write + * sizes supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 + * byte aamsize fields in the memory access abstract command. + */ +static int write_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + int result = ERROR_OK; + bool use_aampostincrement = info->has_aampostincrement != YNM_NO; + + LOG_DEBUG("writing %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); + + /* Convert the size (bytes) to width (bits) */ + unsigned width = size << 3; + + /* Create the command (physical address, postincrement, write) */ + uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true); + + /* Execute the writes */ + const uint8_t *p = buffer; + bool updateaddr = true; + for (uint32_t c = 0; c < count; c++) { + /* Move data to arg0 */ + riscv_reg_t value = buf_get_u64(p, 0, 8 * size); + result = write_abstract_arg(target, 0, value, riscv_xlen(target)); + if (result != ERROR_OK) { + LOG_ERROR("Failed to write arg0 during write_memory_abstract()."); + return result; + } + + /* Update the address if it is the first time or aampostincrement is not supported by the target. */ + if (updateaddr) { + /* Set arg1 to the address: address + c * size */ + result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); + if (result != ERROR_OK) { + LOG_ERROR("Failed to write arg1 during write_memory_abstract()."); + return result; + } + } + + /* Execute the command */ + result = execute_abstract_command(target, command); + + if (info->has_aampostincrement == YNM_MAYBE) { + if (result == ERROR_OK) { + /* Safety: double-check that the address was really auto-incremented */ + riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); + if (new_address == address + size) { + LOG_DEBUG("aampostincrement is supported on this target."); + info->has_aampostincrement = YNM_YES; + } else { + LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); + info->has_aampostincrement = YNM_NO; + } + } else { + /* Try the same access but with postincrement disabled. */ + command = access_memory_command(target, false, width, false, true); + result = execute_abstract_command(target, command); + if (result == ERROR_OK) { + LOG_DEBUG("aampostincrement is not supported on this target."); + info->has_aampostincrement = YNM_NO; + } + } + } + + if (result != ERROR_OK) + return result; + + if (info->has_aampostincrement == YNM_YES) + updateaddr = false; + p += size; + } + + return result; +} + +/** + * Read the requested memory, taking care to execute every read exactly once, + * even if cmderr=busy is encountered. + */ +static int read_memory_progbuf_inner(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + RISCV013_INFO(info); + + int result = ERROR_OK; + + /* Write address to S0. */ + result = register_write_direct(target, GDB_REGNO_S0, address); + if (result != ERROR_OK) + return result; + + if (increment == 0 && + register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK) + return ERROR_FAIL; + + uint32_t command = access_register_command(target, GDB_REGNO_S1, + riscv_xlen(target), + AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); + if (execute_abstract_command(target, command) != ERROR_OK) + return ERROR_FAIL; + + /* First read has just triggered. Result is in s1. */ + if (count == 1) { + uint64_t value; + if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + buf_set_u64(buffer, 0, 8 * size, value); + log_memory_access(address, value, size, true); + return ERROR_OK; + } + + if (dmi_write(target, DM_ABSTRACTAUTO, + 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET) != ERROR_OK) + goto error; + result=ERROR_FAIL; + goto error; + /* Read garbage from dmi_data0, which triggers another execution of the + * program. Now dmi_data0 contains the first good result, and s1 the next + * memory value. */ + if (dmi_read_exec(target, NULL, DM_DATA0) != ERROR_OK) + goto error; + + /* read_addr is the next address that the hart will read from, which is the + * value in s0. */ + unsigned index = 2; + while (index < count) { + riscv_addr_t read_addr = address + index * increment; + LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr); + /* The pipeline looks like this: + * memory -> s1 -> dm_data0 -> debugger + * Right now: + * s0 contains read_addr + * s1 contains mem[read_addr-size] + * dm_data0 contains[read_addr-size*2] + */ + + struct riscv_batch *batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE, + info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) + return ERROR_FAIL; + + unsigned reads = 0; + for (unsigned j = index; j < count; j++) { + if (size > 4) + riscv_batch_add_dmi_read(batch, DM_DATA1); + riscv_batch_add_dmi_read(batch, DM_DATA0); + + reads++; + if (riscv_batch_full(batch)) + break; + } + + batch_run(target, batch); + + /* Wait for the target to finish performing the last abstract command, + * and update our copy of cmderr. If we see that DMI is busy here, + * dmi_busy_delay will be incremented. */ + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); + + unsigned next_index; + unsigned ignore_last = 0; + switch (info->cmderr) { + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory read"); + next_index = index + reads; + break; + case CMDERR_BUSY: + LOG_DEBUG("memory read resulted in busy response"); + + increase_ac_busy_delay(target); + riscv013_clear_abstract_error(target); + + dmi_write(target, DM_ABSTRACTAUTO, 0); + + uint32_t dmi_data0, dmi_data1 = 0; + /* This is definitely a good version of the value that we + * attempted to read when we discovered that the target was + * busy. */ + if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + /* See how far we got, clobbering dmi_data0. */ + if (increment == 0) { + uint64_t counter; + result = register_read_direct(target, &counter, GDB_REGNO_S2); + next_index = counter; + } else { + uint64_t next_read_addr; + result = register_read_direct(target, &next_read_addr, + GDB_REGNO_S0); + next_index = (next_read_addr - address) / increment; + } + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; + buf_set_u64(buffer + (next_index - 2) * size, 0, 8 * size, value64); + log_memory_access(address + (next_index - 2) * size, value64, size, true); + + /* Restore the command, and execute it. + * Now DM_DATA0 contains the next value just as it would if no + * error had occurred. */ + dmi_write_exec(target, DM_COMMAND, command, true); + next_index++; + + dmi_write(target, DM_ABSTRACTAUTO, + 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + ignore_last = 1; + + break; + default: + LOG_DEBUG("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; + } + + /* Now read whatever we got out of the batch. */ + dmi_status_t status = DMI_STATUS_SUCCESS; + unsigned read = 0; + assert(index >= 2); + for (unsigned j = index - 2; j < index + reads; j++) { + assert(j < count); + LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d", + index, reads, next_index, ignore_last, j); + if (j + 3 + ignore_last > next_index) + break; + + status = riscv_batch_get_dmi_read_op(batch, read); + uint64_t value = riscv_batch_get_dmi_read_data(batch, read); + read++; + if (status != DMI_STATUS_SUCCESS) { + /* If we're here because of busy count, dmi_busy_delay will + * already have been increased and busy state will have been + * cleared in dmi_read(). */ + /* In at least some implementations, we issue a read, and then + * can get busy back when we try to scan out the read result, + * and the actual read value is lost forever. Since this is + * rare in any case, we return error here and rely on our + * caller to reread the entire block. */ + LOG_WARNING("Batch memory read encountered DMI error %d. " + "Falling back on slower reads.", status); + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; + } + if (size > 4) { + status = riscv_batch_get_dmi_read_op(batch, read); + if (status != DMI_STATUS_SUCCESS) { + LOG_WARNING("Batch memory read encountered DMI error %d. " + "Falling back on slower reads.", status); + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; + } + value <<= 32; + value |= riscv_batch_get_dmi_read_data(batch, read); + read++; + } + riscv_addr_t offset = j * size; + buf_set_u64(buffer + offset, 0, 8 * size, value); + log_memory_access(address + j * increment, value, size, true); + } + + index = next_index; + + riscv_batch_free(batch); + } + + dmi_write(target, DM_ABSTRACTAUTO, 0); + + if (count > 1) { + /* Read the penultimate word. */ + uint32_t dmi_data0, dmi_data1 = 0; + if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) + return ERROR_FAIL; + if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) + return ERROR_FAIL; + uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; + buf_set_u64(buffer + size * (count - 2), 0, 8 * size, value64); + log_memory_access(address + size * (count - 2), value64, size, true); + } + + /* Read the last word. */ + uint64_t value; + result = register_read_direct(target, &value, GDB_REGNO_S1); + if (result != ERROR_OK) + goto error; + buf_set_u64(buffer + size * (count-1), 0, 8 * size, value); + log_memory_access(address + size * (count-1), value, size, true); + + return ERROR_OK; + +error: + dmi_write(target, DM_ABSTRACTAUTO, 0); + + return result; +} + +/* Only need to save/restore one GPR to read a single word, and the progbuf + * program doesn't need to increment. */ +static int read_memory_progbuf_one(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + int result = ERROR_FAIL; + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + goto restore_mstatus; + + /* Write the program (load, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + switch (size) { + case 1: + riscv_program_lbr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_lhr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_lwr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); + break; + case 8: + riscv_program_ldr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + goto restore_mstatus; + } + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + + if (riscv_program_ebreak(&program) != ERROR_OK) + goto restore_mstatus; + if (riscv_program_write(&program) != ERROR_OK) + goto restore_mstatus; + + /* Write address to S0, and execute buffer. */ + if (write_abstract_arg(target, 0, address, riscv_xlen(target)) != ERROR_OK) + goto restore_mstatus; + uint32_t command = access_register_command(target, GDB_REGNO_S0, + riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | + AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); + if (execute_abstract_command(target, command) != ERROR_OK) + goto restore_mstatus; + + uint64_t value; + if (register_read_direct(target, &value, GDB_REGNO_S0) != ERROR_OK) + goto restore_mstatus; + buf_set_u64(buffer, 0, 8 * size, value); + log_memory_access(address, value, size, true); + result = ERROR_OK; + +restore_mstatus: + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + result = ERROR_FAIL; + + return result; +} + +/** + * Read the requested memory, silently handling memory access errors. + */ +static int read_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + if (riscv_xlen(target) < size * 8) { + LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", + riscv_xlen(target), size * 8); + return ERROR_FAIL; + } + + int result = ERROR_OK; + + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + // select_dmi(target); + + memset(buffer, 0, count*size); + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + if (count == 1) + return read_memory_progbuf_one(target, address, size, buffer); + + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + /* s0 holds the next address to read from + * s1 holds the next data value read + * s2 is a counter in case increment is 0 + */ + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + if (increment == 0 && riscv_save_register(target, GDB_REGNO_S2) != ERROR_OK) + return ERROR_FAIL; + + /* Write the program (load, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + + switch (size) { + case 1: + riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 8: + riscv_program_ldr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + if (increment == 0) + riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1); + else + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment); + + if (riscv_program_ebreak(&program) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_write(&program) != ERROR_OK) + return ERROR_FAIL; + + result = read_memory_progbuf_inner(target, address, size, count, buffer, increment); + + if (result != ERROR_OK) { + /* The full read did not succeed, so we will try to read each word individually. */ + /* This will not be fast, but reading outside actual memory is a special case anyway. */ + /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */ + target_addr_t address_i = address; + uint32_t count_i = 1; + uint8_t *buffer_i = buffer; + + for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) { + /* TODO: This is much slower than it needs to be because we end up + * writing the address to read for every word we read. */ + result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment); + + /* The read of a single word failed, so we will just return 0 for that instead */ + if (result != ERROR_OK) { + LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, + size, address_i); + + buf_set_u64(buffer_i, 0, 8 * size, 0); + } + } + result = ERROR_OK; + } + + /* Restore MSTATUS */ + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + return ERROR_FAIL; + + return result; +} + +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + + if (count == 0) + return ERROR_OK; + + if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { + LOG_ERROR("BUG: Unsupported size for memory read: %d", size); + return ERROR_FAIL; + } + + int ret = ERROR_FAIL; + RISCV_INFO(r); + RISCV013_INFO(info); + + char *progbuf_result = "disabled"; + char *sysbus_result = "disabled"; + char *abstract_result = "disabled"; + + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (mem_should_skip_progbuf(target, address, size, true, &progbuf_result)) + continue; + + ret = read_memory_progbuf(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + progbuf_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (mem_should_skip_sysbus(target, address, size, increment, true, &sysbus_result)) + continue; + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) + ret = read_memory_bus_v0(target, address, size, count, buffer, increment); + // else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) + // ret = read_memory_bus_v1(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + sysbus_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + if (mem_should_skip_abstract(target, address, size, increment, true, &abstract_result)) + continue; + + ret = read_memory_abstract(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + abstract_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + + log_mem_access_result(target, ret == ERROR_OK, method, true); + + if (ret == ERROR_OK) + return ret; + } + + LOG_ERROR("Target %s: Failed to read memory (addr=0x%" PRIx64 ")", target_name(target), address); + LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); + return ret; +} + +static int write_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + dmi_write(target, DM_SBADDRESS0, address); + int64_t value = 0; + int64_t access = 0; + riscv_addr_t offset = 0; + riscv_addr_t t_addr = 0; + const uint8_t *t_buffer = buffer + offset; + + /* B.8 Writing Memory, single write check if we write in one go */ + if (count == 1) { /* count is in bytes here */ + value = buf_get_u64(t_buffer, 0, 8 * size); + + access = 0; + access = set_field(access, DM_SBCS_SBACCESS, size/2); + dmi_write(target, DM_SBCS, access); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); + dmi_write(target, DM_SBDATA0, value); + return ERROR_OK; + } + + /*B.8 Writing Memory, using autoincrement*/ + + access = 0; + access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + dmi_write(target, DM_SBCS, access); + + /*2)set the value according to the size required and write*/ + for (riscv_addr_t i = 0; i < count; ++i) { + offset = size*i; + /* for monitoring only */ + t_addr = address + offset; + t_buffer = buffer + offset; + + value = buf_get_u64(t_buffer, 0, 8 * size); + LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" + PRIx64, (uint32_t)t_addr, (uint32_t)value); + dmi_write(target, DM_SBDATA0, value); + } + /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ + access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DM_SBCS, access); + + return ERROR_OK; +} + + +static int write_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + + if (riscv_xlen(target) < size * 8) { + LOG_ERROR("XLEN (%d) is too short for %d-bit memory write.", + riscv_xlen(target), size * 8); + return ERROR_FAIL; + } + + LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); + + // select_dmi(target); + + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + + int result = ERROR_OK; + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + /* Write the program (store, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + + switch (size) { + case 1: + riscv_program_sbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_shr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_swr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 8: + riscv_program_sdr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("write_memory_progbuf(): Unsupported size: %d", size); + result = ERROR_FAIL; + goto error; + } + + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) + riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + + result = riscv_program_ebreak(&program); + if (result != ERROR_OK) + goto error; + riscv_program_write(&program); + + riscv_addr_t cur_addr = address; + riscv_addr_t distance = (riscv_addr_t)count * size; + bool setup_needed = true; + LOG_DEBUG("writing until final address 0x%016" PRIx64, cur_addr + distance); + while (cur_addr - address < distance) { + LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, + cur_addr); + + struct riscv_batch *batch = riscv_batch_alloc( + target, + RISCV_BATCH_ALLOC_SIZE, + info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) + goto error; + + /* To write another word, we put it in S1 and execute the program. */ + for (riscv_addr_t offset = cur_addr - address; offset < distance; offset += size) { + const uint8_t *t_buffer = buffer + offset; + + uint64_t value = buf_get_u64(t_buffer, 0, 8 * size); + + log_memory_access(cur_addr, value, size, false); + cur_addr += size; + + if (setup_needed) { + result = register_write_direct(target, GDB_REGNO_S0, + address + offset); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + /* Write value. */ + if (size > 4) + dmi_write(target, DM_DATA1, value >> 32); + dmi_write(target, DM_DATA0, value); + + /* Write and execute command that moves value into S1 and + * executes program buffer. */ + uint32_t command = access_register_command(target, + GDB_REGNO_S1, riscv_xlen(target), + AC_ACCESS_REGISTER_POSTEXEC | + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); + result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + } else { + } + } + + /* Note that if the scan resulted in a Busy DMI response, it + * is this read to abstractcs that will cause the dmi_busy_delay + * to be incremented if necessary. */ + + uint32_t abstractcs; + bool dmi_busy_encountered; + result = dmi_op(target, &abstractcs, &dmi_busy_encountered, + DMI_OP_READ, DM_ABSTRACTCS, 0, false, true); + if (result != ERROR_OK) + goto error; + while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); + if (info->cmderr == CMDERR_NONE && !dmi_busy_encountered) { + LOG_DEBUG("successful (partial?) memory write"); + } else if (info->cmderr == CMDERR_BUSY || dmi_busy_encountered) { + if (info->cmderr == CMDERR_BUSY) + LOG_DEBUG("Memory write resulted in abstract command busy response."); + else if (dmi_busy_encountered) + LOG_DEBUG("Memory write resulted in DMI busy response."); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + + dmi_write(target, DM_ABSTRACTAUTO, 0); + result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); + if (result != ERROR_OK) + goto error; + setup_needed = true; + } else { + LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_clear_abstract_error(target); + result = ERROR_FAIL; + goto error; + } + } + +error: + dmi_write(target, DM_ABSTRACTAUTO, 0); + + /* Restore MSTATUS */ + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + return ERROR_FAIL; + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { + LOG_ERROR("BUG: Unsupported size for memory write: %d", size); + return ERROR_FAIL; + } + + int ret = ERROR_FAIL; + RISCV_INFO(r); + RISCV013_INFO(info); + + char *progbuf_result = "disabled"; + char *sysbus_result = "disabled"; + char *abstract_result = "disabled"; + + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (mem_should_skip_progbuf(target, address, size, false, &progbuf_result)) + continue; + + ret = write_memory_progbuf(target, address, size, count, buffer); + + if (ret != ERROR_OK) + progbuf_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (mem_should_skip_sysbus(target, address, size, 0, false, &sysbus_result)) + continue; + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) + ret = write_memory_bus_v0(target, address, size, count, buffer); + + + if (ret != ERROR_OK) + sysbus_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + if (mem_should_skip_abstract(target, address, size, 0, false, &abstract_result)) + continue; + + ret = write_memory_abstract(target, address, size, count, buffer); + + if (ret != ERROR_OK) + abstract_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + + log_mem_access_result(target, ret == ERROR_OK, method, false); + + if (ret == ERROR_OK) + return ret; + } + + LOG_ERROR("Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); + LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); + return ret; +} + +static int arch_state(struct target *target) +{ + return ERROR_OK; +} + +struct target_type wch_riscv013_target = { + .name = "riscv", + + .init_target = init_target, + .deinit_target = deinit_target, + .examine = examine, + + .poll = &riscv_openocd_poll, + .halt = &riscv_halt, + .step = &riscv_openocd_step, + + .assert_reset = assert_reset, + .deassert_reset = deassert_reset, + + .write_memory = write_memory, + + .arch_state = arch_state +}; + +/*** 0.13-specific implementations of various RISC-V helper functions. ***/ +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int rid) +{ + LOG_DEBUG("[%s] reading register %s", target_name(target), + gdb_regno_name(rid)); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + int result = ERROR_OK; + if (rid == GDB_REGNO_PC) { + /* TODO: move this into riscv.c. */ + result = register_read_direct(target, value, GDB_REGNO_DPC); + LOG_TARGET_DEBUG(target, "read PC from DPC: 0x%" PRIx64, *value); + } else if (rid == GDB_REGNO_PRIV) { + uint64_t dcsr; + /* TODO: move this into riscv.c. */ + result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); + *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); + } else { + result = register_read_direct(target, value, rid); + if (result != ERROR_OK) + *value = -1; + } + + return result; +} + +static int riscv013_set_register(struct target *target, int rid, uint64_t value) +{ + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", + value, gdb_regno_name(rid)); + + if (rid <= GDB_REGNO_XPR31) { + return register_write_direct(target, rid, value); + } else if (rid == GDB_REGNO_PC) { + LOG_TARGET_DEBUG(target, "writing PC to DPC: 0x%" PRIx64, value); + register_write_direct(target, GDB_REGNO_DPC, value); + uint64_t actual_value; + register_read_direct(target, &actual_value, GDB_REGNO_DPC); + LOG_TARGET_DEBUG(target, " actual DPC written: 0x%016" PRIx64, actual_value); + if (value != actual_value) { + LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " + "value (0x%" PRIx64 ")", value, actual_value); + return ERROR_FAIL; + } + } else if (rid == GDB_REGNO_PRIV) { + uint64_t dcsr; + register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); + dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); + return register_write_direct(target, GDB_REGNO_DCSR, dcsr); + } else { + return register_write_direct(target, rid, value); + } + + return ERROR_OK; +} + +static int dm013_select_hart(struct target *target, int hart_index) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (hart_index == dm->current_hartid) + return ERROR_OK; + + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; + dmcontrol = set_dmcontrol_hartsel(dmcontrol, hart_index); + if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { + /* Who knows what the state is? */ + dm->current_hartid = -2; + return ERROR_FAIL; + } + dm->current_hartid = hart_index; + return ERROR_OK; +} + +/* Select all harts that were prepped and that are selectable, clearing the + * prepped flag on the harts that actually were selected. */ +static int select_prepped_harts(struct target *target) +{ + RISCV_INFO(r); + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (!dm->hasel_supported) { + r->prepped = false; + dm013_select_target(target); + return ERROR_OK; + } + + assert(dm->hart_count); + unsigned hawindow_count = (dm->hart_count + 31) / 32; + uint32_t hawindow[hawindow_count]; + + memset(hawindow, 0, sizeof(uint32_t) * hawindow_count); + + target_list_t *entry; + unsigned total_selected = 0; + unsigned int selected_index = 0; + list_for_each_entry(entry, &dm->target_list, list) { + struct target *t = entry->target; + riscv_info_t *info = riscv_info(t); + riscv013_info_t *info_013 = get_info(t); + unsigned index = info_013->index; + LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, info->prepped); + if (info->prepped) { + info_013->selected = true; + hawindow[index / 32] |= 1 << (index % 32); + info->prepped = false; + total_selected++; + selected_index = index; + } + } + + if (total_selected == 0) { + LOG_TARGET_ERROR(target, "No harts were prepped!"); + return ERROR_FAIL; + } else if (total_selected == 1) { + /* Don't use hasel if we only need to talk to one hart. */ + return dm013_select_hart(target, selected_index); + } + + if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) + return ERROR_FAIL; + + for (unsigned i = 0; i < hawindow_count; i++) { + if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) + return ERROR_FAIL; + if (dmi_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int riscv013_halt_prep(struct target *target) +{ + return ERROR_OK; +} + +static int riscv013_halt_go(struct target *target) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + if (select_prepped_harts(target) != ERROR_OK) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "halting hart"); + + /* Issue the halt command, and then wait for the current hart to halt. */ + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; + dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); + dmi_write(target, DM_DMCONTROL, dmcontrol); + uint32_t dmstatus; + for (size_t i = 0; i < 256; ++i) { + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + /* When no harts are running, there's no point in continuing this loop. */ + if (!get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) + break; + } + + /* We declare success if no harts are running. One or more of them may be + * unavailable, though. */ + + if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) { + if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + + LOG_TARGET_ERROR(target, "Unable to halt. dmcontrol=0x%08x, dmstatus=0x%08x", + dmcontrol, dmstatus); + return ERROR_FAIL; + } + + dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); + dmi_write(target, DM_DMCONTROL, dmcontrol); + + if (dm->current_hartid == HART_INDEX_MULTIPLE) { + target_list_t *entry; + list_for_each_entry(entry, &dm->target_list, list) { + struct target *t = entry->target; + t->state = TARGET_HALTED; + if (t->debug_reason == DBG_REASON_NOTHALTED) + t->debug_reason = DBG_REASON_DBGRQ; + } + } + /* The "else" case is handled in halt_go(). */ + + return ERROR_OK; +} + +static int riscv013_resume_go(struct target *target) +{ + if (select_prepped_harts(target) != ERROR_OK) + return ERROR_FAIL; + + return riscv013_step_or_resume_current_hart(target, false); +} + +static int riscv013_step_current_hart(struct target *target) +{ + return riscv013_step_or_resume_current_hart(target, true); +} + +static int riscv013_resume_prep(struct target *target) +{ + return riscv013_on_step_or_resume(target, false); +} + +static int riscv013_on_step(struct target *target) +{ + return riscv013_on_step_or_resume(target, true); +} + +static int riscv013_on_halt(struct target *target) +{ + return ERROR_OK; +} + +static bool riscv013_is_halted(struct target *target) +{ + RISCV013_INFO(info); + + uint32_t dmstatus; + if (dm013_select_target(target) != ERROR_OK) + return false; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return false; + if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL)) + LOG_TARGET_ERROR(target, "Hart is unavailable."); + if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT)) + LOG_TARGET_ERROR(target, "Hart doesn't exist."); + if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { + LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); + /* TODO: Can we make this more obvious to eg. a gdb user? */ + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | + DM_DMCONTROL_ACKHAVERESET; + dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index); + /* If we had been halted when we reset, request another halt. If we + * ended up running out of reset, then the user will (hopefully) get a + * message that a reset happened, that the target is running, and then + * that it is halted again once the request goes through. + */ + if (target->state == TARGET_HALTED) + dmcontrol |= DM_DMCONTROL_HALTREQ; + dmi_write(target, DM_DMCONTROL, dmcontrol); + } + return get_field(dmstatus, DM_DMSTATUS_ALLHALTED); +} + +static enum riscv_halt_reason riscv013_halt_reason(struct target *target) +{ + riscv_reg_t dcsr; + int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return RISCV_HALT_UNKNOWN; + + LOG_TARGET_DEBUG(target, "dcsr.cause: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); + + switch (get_field(dcsr, CSR_DCSR_CAUSE)) { + case CSR_DCSR_CAUSE_EBREAK: + return RISCV_HALT_BREAKPOINT; + case CSR_DCSR_CAUSE_TRIGGER: + /* We could get here before triggers are enumerated if a trigger was + * already set when we connected. Force enumeration now, which has the + * side effect of clearing any triggers we did not set. */ + riscv_enumerate_triggers(target); + LOG_DEBUG("{%d} halted because of trigger", target->coreid); + return RISCV_HALT_TRIGGER; + case CSR_DCSR_CAUSE_STEP: + return RISCV_HALT_SINGLESTEP; + case CSR_DCSR_CAUSE_HALTREQ: + case CSR_DCSR_CAUSE_RESETHALTREQ: + return RISCV_HALT_INTERRUPT; + case CSR_DCSR_CAUSE_GROUP: + return RISCV_HALT_GROUP; + } + + LOG_ERROR("Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); + LOG_ERROR(" dcsr=0x%" PRIx32, (uint32_t) dcsr); + return RISCV_HALT_UNKNOWN; +} + +static int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) +{ + if (dmi_write(target, DM_PROGBUF0 + index, data) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) +{ + uint32_t value; + dmi_read(target, &value, DM_PROGBUF0 + index); + return value; +} + +static int riscv013_invalidate_cached_debug_buffer(struct target *target) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "Invalidating progbuf cache"); + for (unsigned int i = 0; i < 15; i++) + dm->progbuf_cache[i] = 0; + return ERROR_OK; +} + +static int riscv013_execute_debug_buffer(struct target *target) +{ + uint32_t run_program = 0; + run_program = set_field(run_program, AC_ACCESS_REGISTER_AARSIZE, 2); + run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1); + run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); + run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); + + return execute_abstract_command(target, run_program); +} + + static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) +{ + +} + +static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) +{ + +} + +static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) +{ + +} + +/* Helper function for riscv013_test_sba_config_reg */ +static int get_max_sbaccess(struct target *target) +{ + RISCV013_INFO(info); + + uint32_t sbaccess128 = get_field(info->sbcs, DM_SBCS_SBACCESS128); + uint32_t sbaccess64 = get_field(info->sbcs, DM_SBCS_SBACCESS64); + uint32_t sbaccess32 = get_field(info->sbcs, DM_SBCS_SBACCESS32); + uint32_t sbaccess16 = get_field(info->sbcs, DM_SBCS_SBACCESS16); + uint32_t sbaccess8 = get_field(info->sbcs, DM_SBCS_SBACCESS8); + + if (sbaccess128) + return 4; + else if (sbaccess64) + return 3; + else if (sbaccess32) + return 2; + else if (sbaccess16) + return 1; + else if (sbaccess8) + return 0; + else + return -1; +} + +static uint32_t get_num_sbdata_regs(struct target *target) +{ + RISCV013_INFO(info); + + uint32_t sbaccess128 = get_field(info->sbcs, DM_SBCS_SBACCESS128); + uint32_t sbaccess64 = get_field(info->sbcs, DM_SBCS_SBACCESS64); + uint32_t sbaccess32 = get_field(info->sbcs, DM_SBCS_SBACCESS32); + + if (sbaccess128) + return 4; + else if (sbaccess64) + return 2; + else if (sbaccess32) + return 1; + else + return 0; +} + +static int riscv013_test_sba_config_reg(struct target *target, + target_addr_t legal_address, uint32_t num_words, + target_addr_t illegal_address, bool run_sbbusyerror_test) +{ + LOG_INFO("Testing System Bus Access as defined by RISC-V Debug Spec v0.13"); + + uint32_t tests_failed = 0; + + uint32_t rd_val; + uint32_t sbcs_orig; + dmi_read(target, &sbcs_orig, DM_SBCS); + + uint32_t sbcs = sbcs_orig; + bool test_passed; + + int max_sbaccess = get_max_sbaccess(target); + + if (max_sbaccess == -1) { + LOG_ERROR("System Bus Access not supported in this config."); + return ERROR_FAIL; + } + + if (get_field(sbcs, DM_SBCS_SBVERSION) != 1) { + LOG_ERROR("System Bus Access unsupported SBVERSION (%d). Only version 1 is supported.", + get_field(sbcs, DM_SBCS_SBVERSION)); + return ERROR_FAIL; + } + + uint32_t num_sbdata_regs = get_num_sbdata_regs(target); + assert(num_sbdata_regs); + + uint32_t rd_buf[num_sbdata_regs]; + + /* Test 1: Simple write/read test */ + test_passed = true; + sbcs = set_field(sbcs_orig, DM_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DM_SBCS, sbcs); + + uint32_t test_patterns[4] = {0xdeadbeef, 0xfeedbabe, 0x12345678, 0x08675309}; + for (uint32_t sbaccess = 0; sbaccess <= (uint32_t)max_sbaccess; sbaccess++) { + sbcs = set_field(sbcs, DM_SBCS_SBACCESS, sbaccess); + dmi_write(target, DM_SBCS, sbcs); + + uint32_t compare_mask = (sbaccess == 0) ? 0xff : (sbaccess == 1) ? 0xffff : 0xffffffff; + + for (uint32_t i = 0; i < num_words; i++) { + uint32_t addr = legal_address + (i << sbaccess); + uint32_t wr_data[num_sbdata_regs]; + for (uint32_t j = 0; j < num_sbdata_regs; j++) + wr_data[j] = test_patterns[j] + i; + write_memory_sba_simple(target, addr, wr_data, num_sbdata_regs, sbcs); + } + + for (uint32_t i = 0; i < num_words; i++) { + uint32_t addr = legal_address + (i << sbaccess); + read_memory_sba_simple(target, addr, rd_buf, num_sbdata_regs, sbcs); + for (uint32_t j = 0; j < num_sbdata_regs; j++) { + if (((test_patterns[j]+i)&compare_mask) != (rd_buf[j]&compare_mask)) { + LOG_ERROR("System Bus Access Test 1: Error reading non-autoincremented address %x," + "expected val = %x, read val = %x", addr, test_patterns[j]+i, rd_buf[j]); + test_passed = false; + tests_failed++; + } + } + } + } + if (test_passed) + LOG_INFO("System Bus Access Test 1: Simple write/read test PASSED."); + + /* Test 2: Address autoincrement test */ + target_addr_t curr_addr; + target_addr_t prev_addr; + test_passed = true; + sbcs = set_field(sbcs_orig, DM_SBCS_SBAUTOINCREMENT, 1); + dmi_write(target, DM_SBCS, sbcs); + + for (uint32_t sbaccess = 0; sbaccess <= (uint32_t)max_sbaccess; sbaccess++) { + sbcs = set_field(sbcs, DM_SBCS_SBACCESS, sbaccess); + dmi_write(target, DM_SBCS, sbcs); + + dmi_write(target, DM_SBADDRESS0, legal_address); + read_sbcs_nonbusy(target, &sbcs); + curr_addr = legal_address; + for (uint32_t i = 0; i < num_words; i++) { + prev_addr = curr_addr; + read_sbcs_nonbusy(target, &sbcs); + curr_addr = sb_read_address(target); + if ((curr_addr - prev_addr != (uint32_t)(1 << sbaccess)) && (i != 0)) { + LOG_ERROR("System Bus Access Test 2: Error with address auto-increment, sbaccess = %x.", sbaccess); + test_passed = false; + tests_failed++; + } + dmi_write(target, DM_SBDATA0, i); + } + + read_sbcs_nonbusy(target, &sbcs); + + dmi_write(target, DM_SBADDRESS0, legal_address); + + uint32_t val; + sbcs = set_field(sbcs, DM_SBCS_SBREADONDATA, 1); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &val, DM_SBDATA0); /* Dummy read to trigger first system bus read */ + curr_addr = legal_address; + for (uint32_t i = 0; i < num_words; i++) { + prev_addr = curr_addr; + read_sbcs_nonbusy(target, &sbcs); + curr_addr = sb_read_address(target); + if ((curr_addr - prev_addr != (uint32_t)(1 << sbaccess)) && (i != 0)) { + LOG_ERROR("System Bus Access Test 2: Error with address auto-increment, sbaccess = %x", sbaccess); + test_passed = false; + tests_failed++; + } + dmi_read(target, &val, DM_SBDATA0); + read_sbcs_nonbusy(target, &sbcs); + if (i != val) { + LOG_ERROR("System Bus Access Test 2: Error reading auto-incremented address," + "expected val = %x, read val = %x.", i, val); + test_passed = false; + tests_failed++; + } + } + } + if (test_passed) + LOG_INFO("System Bus Access Test 2: Address auto-increment test PASSED."); + + /* Test 3: Read from illegal address */ + read_memory_sba_simple(target, illegal_address, rd_buf, 1, sbcs_orig); + + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 2) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 2); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 0) + LOG_INFO("System Bus Access Test 3: Illegal address read test PASSED."); + else + LOG_ERROR("System Bus Access Test 3: Illegal address read test FAILED, unable to clear to 0."); + } else { + LOG_ERROR("System Bus Access Test 3: Illegal address read test FAILED, unable to set error code."); + } + + /* Test 4: Write to illegal address */ + write_memory_sba_simple(target, illegal_address, test_patterns, 1, sbcs_orig); + + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 2) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 2); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 0) + LOG_INFO("System Bus Access Test 4: Illegal address write test PASSED."); + else { + LOG_ERROR("System Bus Access Test 4: Illegal address write test FAILED, unable to clear to 0."); + tests_failed++; + } + } else { + LOG_ERROR("System Bus Access Test 4: Illegal address write test FAILED, unable to set error code."); + tests_failed++; + } + + /* Test 5: Write with unsupported sbaccess size */ + uint32_t sbaccess128 = get_field(sbcs_orig, DM_SBCS_SBACCESS128); + + if (sbaccess128) { + LOG_INFO("System Bus Access Test 5: SBCS sbaccess error test PASSED, all sbaccess sizes supported."); + } else { + sbcs = set_field(sbcs_orig, DM_SBCS_SBACCESS, 4); + + write_memory_sba_simple(target, legal_address, test_patterns, 1, sbcs); + + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 4) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 4); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 0) + LOG_INFO("System Bus Access Test 5: SBCS sbaccess error test PASSED."); + else { + LOG_ERROR("System Bus Access Test 5: SBCS sbaccess error test FAILED, unable to clear to 0."); + tests_failed++; + } + } else { + LOG_ERROR("System Bus Access Test 5: SBCS sbaccess error test FAILED, unable to set error code."); + tests_failed++; + } + } + + /* Test 6: Write to misaligned address */ + sbcs = set_field(sbcs_orig, DM_SBCS_SBACCESS, 1); + + write_memory_sba_simple(target, legal_address+1, test_patterns, 1, sbcs); + + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 3) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 3); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBERROR) == 0) + LOG_INFO("System Bus Access Test 6: SBCS address alignment error test PASSED"); + else { + LOG_ERROR("System Bus Access Test 6: SBCS address alignment error test FAILED, unable to clear to 0."); + tests_failed++; + } + } else { + LOG_ERROR("System Bus Access Test 6: SBCS address alignment error test FAILED, unable to set error code."); + tests_failed++; + } + + /* Test 7: Set sbbusyerror, only run this case in simulation as it is likely + * impossible to hit otherwise */ + if (run_sbbusyerror_test) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBREADONADDR, 1); + dmi_write(target, DM_SBCS, sbcs); + + for (int i = 0; i < 16; i++) + dmi_write(target, DM_SBDATA0, 0xdeadbeef); + + for (int i = 0; i < 16; i++) + dmi_write(target, DM_SBADDRESS0, legal_address); + + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBBUSYERROR)) { + sbcs = set_field(sbcs_orig, DM_SBCS_SBBUSYERROR, 1); + dmi_write(target, DM_SBCS, sbcs); + dmi_read(target, &rd_val, DM_SBCS); + if (get_field(rd_val, DM_SBCS_SBBUSYERROR) == 0) + LOG_INFO("System Bus Access Test 7: SBCS sbbusyerror test PASSED."); + else { + LOG_ERROR("System Bus Access Test 7: SBCS sbbusyerror test FAILED, unable to clear to 0."); + tests_failed++; + } + } else { + LOG_ERROR("System Bus Access Test 7: SBCS sbbusyerror test FAILED, unable to set error code."); + tests_failed++; + } + } + + if (tests_failed == 0) { + LOG_INFO("ALL TESTS PASSED"); + return ERROR_OK; + } else { + LOG_ERROR("%d TESTS FAILED", tests_failed); + return ERROR_FAIL; + } + +} + +static void write_memory_sba_simple(struct target *target, target_addr_t addr, + uint32_t *write_data, uint32_t write_size, uint32_t sbcs) +{ + RISCV013_INFO(info); + + uint32_t rd_sbcs; + uint32_t masked_addr; + + uint32_t sba_size = get_field(info->sbcs, DM_SBCS_SBASIZE); + + read_sbcs_nonbusy(target, &rd_sbcs); + + uint32_t sbcs_no_readonaddr = set_field(sbcs, DM_SBCS_SBREADONADDR, 0); + dmi_write(target, DM_SBCS, sbcs_no_readonaddr); + + for (uint32_t i = 0; i < sba_size/32; i++) { + masked_addr = (addr >> 32*i) & 0xffffffff; + + if (i != 3) + dmi_write(target, DM_SBADDRESS0+i, masked_addr); + else + dmi_write(target, DM_SBADDRESS3, masked_addr); + } + + /* Write SBDATA registers starting with highest address, since write to + * SBDATA0 triggers write */ + for (int i = write_size-1; i >= 0; i--) + dmi_write(target, DM_SBDATA0+i, write_data[i]); +} + +static void read_memory_sba_simple(struct target *target, target_addr_t addr, + uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs) +{ + RISCV013_INFO(info); + + uint32_t rd_sbcs; + uint32_t masked_addr; + + uint32_t sba_size = get_field(info->sbcs, DM_SBCS_SBASIZE); + + read_sbcs_nonbusy(target, &rd_sbcs); + + uint32_t sbcs_readonaddr = set_field(sbcs, DM_SBCS_SBREADONADDR, 1); + dmi_write(target, DM_SBCS, sbcs_readonaddr); + + /* Write addresses starting with highest address register */ + for (int i = sba_size/32-1; i >= 0; i--) { + masked_addr = (addr >> 32*i) & 0xffffffff; + + if (i != 3) + dmi_write(target, DM_SBADDRESS0+i, masked_addr); + else + dmi_write(target, DM_SBADDRESS3, masked_addr); + } + + read_sbcs_nonbusy(target, &rd_sbcs); + + for (uint32_t i = 0; i < read_size; i++) + dmi_read(target, &(rd_buf[i]), DM_SBDATA0+i); +} + +static int riscv013_dmi_write_u64_bits(struct target *target) +{ + RISCV013_INFO(info); + return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; +} + +static int maybe_execute_fence_i(struct target *target) +{ + if (has_sufficient_progbuf(target, 3)) + return execute_fence(target); + return ERROR_OK; +} +/* Helper Functions. */ +static int riscv013_on_step_or_resume(struct target *target, bool step) +{ + if (maybe_execute_fence_i(target) != ERROR_OK) + return ERROR_FAIL; + dmi_write(target,WCH_DMOD,0); + /* We want to twiddle some bits in the debug CSR so debugging works. */ + riscv_reg_t dcsr; + int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return result; + dcsr = set_field(dcsr, CSR_DCSR_STEP, step); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); + if (riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) + return ERROR_FAIL; + if (riscv_flush_registers(target) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; +} + +static int riscv013_step_or_resume_current_hart(struct target *target, + bool step) +{ + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Hart is not halted!"); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step); + + if (riscv_flush_registers(target) != ERROR_OK) + return ERROR_FAIL; + + dm013_info_t *dm = get_dm(target); + /* Issue the resume command, and then wait for the current hart to resume. */ + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; + dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); + dmi_write(target, DM_DMCONTROL, dmcontrol); + + dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); + + uint32_t dmstatus; + for (size_t i = 0; i < 256; ++i) { + usleep(10); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0) + continue; + if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0) + continue; + + dmi_write(target, DM_DMCONTROL, dmcontrol); + return ERROR_OK; + } + + dmi_write(target, DM_DMCONTROL, dmcontrol); + + LOG_TARGET_ERROR(target, "unable to resume"); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + LOG_TARGET_ERROR(target, " dmstatus=0x%08x", dmstatus); + + if (step) { + LOG_ERROR(" was stepping, halting"); + riscv_halt(target); + return ERROR_OK; + } + + return ERROR_FAIL; +} + +static void riscv013_clear_abstract_error(struct target *target) +{ + /* Wait for busy to go away. */ + time_t start = time(NULL); + uint32_t abstractcs; + dmi_read(target, &abstractcs, DM_ABSTRACTCS); + while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) { + dmi_read(target, &abstractcs, DM_ABSTRACTCS); + + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("abstractcs.busy is not going low after %d seconds " + "(abstractcs=0x%x). The target is either really slow or " + "broken. You could increase the timeout with riscv " + "set_command_timeout_sec.", + riscv_command_timeout_sec, abstractcs); + break; + } + } + /* Clear the error status. */ + dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); +} diff --git a/src/target/wch_riscv.c b/src/target/wch_riscv.c new file mode 100755 index 000000000..e5d94e7bd --- /dev/null +++ b/src/target/wch_riscv.c @@ -0,0 +1,3028 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wch_riscv.h" + + +static int wch_riscv_flush_registers(struct target *target); + struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; +extern int write_flash_data(struct target *target, target_addr_t address,uint32_t size, uint32_t count, uint8_t *buffer); + + +static enum { + RO_NORMAL, + RO_REVERSED +} resume_order; + +static int riscv_resume_go_all_harts(struct target *target); +extern unsigned char riscvchip; +extern unsigned int chip_type; + +static struct target_type *get_target_type(struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + if (!info) { + LOG_ERROR("Target has not been initialized"); + return NULL; + } + + switch (info->dtm_version) { + case 0: + case 1: + return &wch_riscv013_target; + default: + LOG_ERROR("[%s] Unsupported DTM version: %d", + target_name(target), info->dtm_version); + return NULL; + } +} + +static int wch_riscv_create_target(struct target *target, Jim_Interp *interp) +{ + LOG_DEBUG("wch_riscv_create_target()"); + target->arch_info = calloc(1, sizeof(riscv_info_t)); + if (!target->arch_info) { + LOG_ERROR("Failed to allocate RISC-V target structure."); + return ERROR_FAIL; + } + riscv_info_init(target, target->arch_info); + return ERROR_OK; +} + +static int wch_riscv_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("wch_riscv_init_target()"); + RISCV_INFO(info); + info->cmd_ctx = cmd_ctx; + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static void riscv_free_registers(struct target *target) +{ + /* Free the shared structure use for most registers. */ + if (target->reg_cache) { + if (target->reg_cache->reg_list) { + free(target->reg_cache->reg_list[0].arch_info); + /* Free the ones we allocated separately. */ + for (unsigned i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++) + free(target->reg_cache->reg_list[i].arch_info); + for (unsigned int i = 0; i < target->reg_cache->num_regs; i++) + free(target->reg_cache->reg_list[i].value); + free(target->reg_cache->reg_list); + } + free(target->reg_cache); + } +} + +static void wch_riscv_deinit_target(struct target *target) +{ + LOG_DEBUG("wch_riscv_deinit_target()"); + + riscv_info_t *info = target->arch_info; + struct target_type *tt = get_target_type(target); + + if (wch_riscv_flush_registers(target) != ERROR_OK) + LOG_ERROR("[%s] Failed to flush registers. Ignoring this error.", target_name(target)); + + if (tt && info->version_specific) + tt->deinit_target(target); + + riscv_free_registers(target); + + range_list_t *entry, *tmp; + list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) { + free(entry->name); + free(entry); + } + + list_for_each_entry_safe(entry, tmp, &info->expose_custom, list) { + free(entry->name); + free(entry); + } + + free(info->reg_names); + free(target->arch_info); + + target->arch_info = NULL; +} + +static void trigger_from_breakpoint(struct trigger *trigger, + const struct breakpoint *breakpoint) +{ + trigger->address = breakpoint->address; + trigger->length = breakpoint->length; + trigger->mask = ~0LL; + trigger->read = false; + trigger->write = false; + trigger->execute = true; + /* unique_id is unique across both breakpoints and watchpoints. */ + trigger->unique_id = breakpoint->unique_id; +} + +static int maybe_add_trigger_t1(struct target *target, + struct trigger *trigger, uint64_t tdata1) +{ + RISCV_INFO(r); + + const uint32_t bpcontrol_x = 1<<0; + const uint32_t bpcontrol_w = 1<<1; + const uint32_t bpcontrol_r = 1<<2; + const uint32_t bpcontrol_u = 1<<3; + const uint32_t bpcontrol_s = 1<<4; + const uint32_t bpcontrol_h = 1<<5; + const uint32_t bpcontrol_m = 1<<6; + const uint32_t bpcontrol_bpmatch = 0xf << 7; + const uint32_t bpcontrol_bpaction = 0xff << 11; + + if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { + /* Trigger is already in use, presumably by user code. */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); + tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); + tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); + tdata1 = set_field(tdata1, bpcontrol_u, + !!(r->misa & BIT('U' - 'A'))); + tdata1 = set_field(tdata1, bpcontrol_s, + !!(r->misa & BIT('S' - 'A'))); + tdata1 = set_field(tdata1, bpcontrol_h, + !!(r->misa & BIT('H' - 'A'))); + tdata1 |= bpcontrol_m; + tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ + tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ + + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); + + riscv_reg_t tdata1_rb; + if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int maybe_add_trigger_t2(struct target *target, + struct trigger *trigger, uint64_t tdata1) +{ + RISCV_INFO(r); + + /* tselect is already set */ + if (tdata1 & (CSR_MCONTROL_EXECUTE | CSR_MCONTROL_STORE | CSR_MCONTROL_LOAD)) { + /* Trigger is already in use, presumably by user code. */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* address/data match trigger */ + + tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION, + CSR_MCONTROL_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL); + tdata1 |= CSR_MCONTROL_M; + if (r->misa & (1 << ('S' - 'A'))) + tdata1 |= CSR_MCONTROL_S; + if (r->misa & (1 << ('U' - 'A'))) + tdata1 |= CSR_MCONTROL_U; + + if (trigger->execute) + tdata1 |= CSR_MCONTROL_EXECUTE; + if (trigger->read) + tdata1 |= CSR_MCONTROL_LOAD; + if (trigger->write) + tdata1 |= CSR_MCONTROL_STORE; + + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); + + uint64_t tdata1_rb; + int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int maybe_add_trigger_t6(struct target *target, + struct trigger *trigger, uint64_t tdata1) +{ + RISCV_INFO(r); + + /* tselect is already set */ + if (tdata1 & (CSR_MCONTROL6_EXECUTE | CSR_MCONTROL6_STORE | CSR_MCONTROL6_LOAD)) { + /* Trigger is already in use, presumably by user code. */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* address/data match trigger */ + tdata1 |= CSR_MCONTROL6_DMODE(riscv_xlen(target)); + tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, + CSR_MCONTROL6_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL); + tdata1 |= CSR_MCONTROL6_M; + if (r->misa & (1 << ('H' - 'A'))) + tdata1 |= CSR_MCONTROL6_VS | CSR_MCONTROL6_VU; + if (r->misa & (1 << ('S' - 'A'))) + tdata1 |= CSR_MCONTROL6_S; + if (r->misa & (1 << ('U' - 'A'))) + tdata1 |= CSR_MCONTROL6_U; + + if (trigger->execute) + tdata1 |= CSR_MCONTROL6_EXECUTE; + if (trigger->read) + tdata1 |= CSR_MCONTROL6_LOAD; + if (trigger->write) + tdata1 |= CSR_MCONTROL6_STORE; + + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); + + uint64_t tdata1_rb; + int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int add_trigger(struct target *target, struct trigger *trigger) +{ + RISCV_INFO(r); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + + unsigned int i; + for (i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] != -1) + continue; + + riscv_set_register(target, GDB_REGNO_TSELECT, i); + + uint64_t tdata1; + int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + + result = ERROR_OK; + switch (type) { + case 1: + result = maybe_add_trigger_t1(target, trigger, tdata1); + break; + case 2: + result = maybe_add_trigger_t2(target, trigger, tdata1); + break; + case 6: + result = maybe_add_trigger_t6(target, trigger, tdata1); + break; + default: + LOG_DEBUG("trigger %d has unknown type %d", i, type); + continue; + } + + if (result != ERROR_OK) + continue; + + LOG_DEBUG("[%d] Using trigger %d (type %d) for bp %d", target->coreid, + i, type, trigger->unique_id); + r->trigger_unique_id[i] = trigger->unique_id; + break; + } + + riscv_set_register(target, GDB_REGNO_TSELECT, tselect); + + if (i >= r->trigger_count) { + LOG_ERROR("Couldn't find an available hardware trigger."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +/** + * Write one memory item of given "size". Use memory access of given "access_size". + * Utilize read-modify-write, if needed. + * */ +static int write_by_given_size(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer, uint32_t access_size) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); + + if (access_size <= size && address % access_size == 0) + /* Can do the memory access directly without a helper buffer. */ + return target_write_memory(target, address, access_size, size / access_size, buffer); + + unsigned int offset_head = address % access_size; + unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; + uint8_t helper_buf[n_blocks * access_size]; + + /* Read from memory */ + if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) + return ERROR_FAIL; + + /* Modify and write back */ + memcpy(helper_buf + offset_head, buffer, size); + return target_write_memory(target, address - offset_head, access_size, n_blocks, helper_buf); +} + +/** + * Read one memory item of given "size". Use memory access of given "access_size". + * Read larger section of memory and pick out the required portion, if needed. + * */ +static int read_by_given_size(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer, uint32_t access_size) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); + + if (access_size <= size && address % access_size == 0) + /* Can do the memory access directly without a helper buffer. */ + return target_read_memory(target, address, access_size, size / access_size, buffer); + + unsigned int offset_head = address % access_size; + unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; + uint8_t helper_buf[n_blocks * access_size]; + + /* Read from memory */ + if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) + return ERROR_FAIL; + + /* Pick the requested portion from the buffer */ + memcpy(buffer, helper_buf + offset_head, size); + return ERROR_OK; +} + +int wch_riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +{ + + assert(size == 1 || size == 2 || size == 4 || size == 8); + /* Find access size that correspond to data size and the alignment. */ + unsigned int preferred_size = size; + while (address % preferred_size != 0) + preferred_size /= 2; + + /* First try the preferred (most natural) access size. */ + if (read_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) + return ERROR_OK; + + /* On failure, try other access sizes. + Minimize the number of accesses by trying first the largest size. */ + for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { + if (access_size == preferred_size) + /* Already tried this size. */ + continue; + + if (read_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) + return ERROR_OK; + } + + /* No access attempt succeeded. */ + return ERROR_FAIL; +} +/** + * Write one memory item using any memory access size that will work. + * Utilize read-modify-write, if needed. + * */ +int wch_riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + if(address<0x20000000){ + if((address>=0x08000000)&&(riscvchip!=0x09) ) + address -= 0x08000000; + + int ret=write_flash_data(target,address,size,1,buffer); + return ret; + } + /* Find access size that correspond to data size and the alignment. */ + unsigned int preferred_size = size; + while (address % preferred_size != 0) + preferred_size /= 2; + + /* First try the preferred (most natural) access size. */ + if (write_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) + return ERROR_OK; + + /* On failure, try other access sizes. + Minimize the number of accesses by trying first the largest size. */ + for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { + if (access_size == preferred_size) + /* Already tried this size. */ + continue; + + if (write_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) + return ERROR_OK; + } + + /* No access attempt succeeded. */ + return ERROR_FAIL; +} + + +int wch_riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + LOG_TARGET_DEBUG(target, "@0x%" TARGET_PRIxADDR, breakpoint->address); + + assert(breakpoint); + if((riscvchip==6 ||(((uint16_t)chip_type) ==0x050c)||(riscvchip==0x0b)||(riscvchip==0x0c)||(riscvchip==0x0e)) && breakpoint->type == BKPT_HARD && target->breakpoints ){ + struct breakpoint *p= target->breakpoints->next; + int len=0; + while(p){ + len++; + p=p->next; + } + if(len>3) + breakpoint->type = BKPT_SOFT; + } + if(riscvchip==1||riscvchip==2||riscvchip==3 ||riscvchip==7 ||riscvchip==9 ||riscvchip==0x0a ||((uint16_t)chip_type) ==0x0500){ + breakpoint->type = BKPT_SOFT; + } + if (breakpoint->type == BKPT_SOFT) { + /** @todo check RVC for size/alignment */ + if (!(breakpoint->length == 4 || breakpoint->length == 2)) { + LOG_ERROR("Invalid breakpoint length %d", breakpoint->length); + return ERROR_FAIL; + } + + if (0 != (breakpoint->address % 2)) { + LOG_ERROR("Invalid breakpoint alignment for address 0x%" TARGET_PRIxADDR, breakpoint->address); + return ERROR_FAIL; + } + + /* Read the original instruction. */ + if (wch_riscv_read_by_any_size( + target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, + breakpoint->address); + return ERROR_FAIL; + } + uint8_t buff[4] = { 0 }; + buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); + /* Write the ebreak instruction. */ + if (wch_riscv_write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) { + LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" + TARGET_PRIxADDR, breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int const result = add_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->is_set = true; + return ERROR_OK; +} + +static int remove_trigger(struct target *target, struct trigger *trigger) +{ + RISCV_INFO(r); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + unsigned int i; + for (i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == trigger->unique_id) + break; + } + if (i >= r->trigger_count) { + LOG_ERROR("Couldn't find the hardware resources used by hardware " + "trigger."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i, + trigger->unique_id); + + riscv_reg_t tselect; + int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; + riscv_set_register(target, GDB_REGNO_TSELECT, i); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + riscv_set_register(target, GDB_REGNO_TSELECT, tselect); + r->trigger_unique_id[i] = -1; + + return ERROR_OK; +} + +int wch_riscv_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + if (breakpoint->type == BKPT_SOFT) { + uint8_t buf[32]; + + + /* Write the original instruction. */ + if (wch_riscv_write_by_any_size( + target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " + "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + // wch_riscv_read_by_any_size(target, 0x08000000, 4, buf); + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->is_set = false; + + return ERROR_OK; +} + +static void trigger_from_watchpoint(struct trigger *trigger, + const struct watchpoint *watchpoint) +{ + trigger->address = watchpoint->address; + trigger->length = watchpoint->length; + trigger->mask = watchpoint->mask; + trigger->value = watchpoint->value; + trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); + trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); + trigger->execute = false; + /* unique_id is unique across both breakpoints and watchpoints. */ + trigger->unique_id = watchpoint->unique_id; +} + +int wch_riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = add_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + watchpoint->is_set = true; + + return ERROR_OK; +} + +int wch_riscv_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, watchpoint->address); + + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + watchpoint->is_set = false; + + return ERROR_OK; +} + +/** + * Look at the trigger hit bits to find out which trigger is the reason we're + * halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is + * ~0, no match was found. + */ +static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) +{ + RISCV_INFO(r); + + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + + *unique_id = ~0; + for (unsigned int i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == -1) + continue; + + if (riscv_set_register(target, GDB_REGNO_TSELECT, i) != ERROR_OK) + return ERROR_FAIL; + + uint64_t tdata1; + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + + uint64_t hit_mask = 0; + switch (type) { + case 1: + /* Doesn't support hit bit. */ + break; + case 2: + hit_mask = CSR_MCONTROL_HIT; + break; + case 6: + hit_mask = CSR_MCONTROL6_HIT; + break; + default: + LOG_DEBUG("trigger %d has unknown type %d", i, type); + continue; + } + + /* Note: If we ever use chained triggers, then this logic needs + * to be changed to ignore triggers that are not the last one in + * the chain. */ + if (tdata1 & hit_mask) { + LOG_DEBUG("Trigger %d (unique_id=%d) has hit bit set.", i, r->trigger_unique_id[i]); + if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) + return ERROR_FAIL; + + *unique_id = r->trigger_unique_id[i]; + break; + } + } + + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + + + +static int oldriscv_step(struct target *target, int current, uint32_t address, + int handle_breakpoints) +{ + struct target_type *tt = get_target_type(target); + return tt->step(target, current, address, handle_breakpoints); +} + +static int old_or_new_riscv_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ + RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + if (!r->is_halted) + return oldriscv_step(target, current, address, handle_breakpoints); + else + return wch_riscv_openocd_step(target, current, address, handle_breakpoints); +} + +static int wch_riscv_examine(struct target *target) +{ + LOG_DEBUG("[%s]", target_name(target)); + if (target_was_examined(target)) { + LOG_DEBUG("Target was already examined."); + return ERROR_OK; + } + + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + + RISCV_INFO(info); + info->dtm_version = 1; + LOG_DEBUG(" version=0x%x", info->dtm_version); + + struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; + + int result = tt->init_target(info->cmd_ctx, target); + if (result != ERROR_OK) + return result; + + return tt->examine(target); +} + +static int oldriscv_poll(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->poll(target); +} + +static int old_or_new_riscv_poll(struct target *target) +{ + RISCV_INFO(r); + if (!r->is_halted) + return oldriscv_poll(target); + else + return wch_riscv_openocd_poll(target); +} + +static int wch_riscv_flush_registers(struct target *target) +{ + RISCV_INFO(r); + + if (!target->reg_cache) + return ERROR_OK; + + LOG_DEBUG("[%s]", target_name(target)); + + for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) { + struct reg *reg = &target->reg_cache->reg_list[number]; + if (reg->valid && reg->dirty) { + uint64_t value = buf_get_u64(reg->value, 0, reg->size); + LOG_DEBUG("[%s] %s is dirty; write back 0x%" PRIx64, + target_name(target), reg->name, value); + int result = r->set_register(target, number, value); + if (result != ERROR_OK) + return ERROR_FAIL; + reg->dirty = false; + } + } + + return ERROR_OK; +} + + +int wch_halt_prep(struct target *target) +{ + RISCV_INFO(r); + + LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target), + target->debug_reason); + if (riscv_is_halted(target)) { + LOG_DEBUG("[%s] Hart is already halted (debug_reason=%d).", + target_name(target), target->debug_reason); + if (target->debug_reason == DBG_REASON_NOTHALTED) { + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + } + } else { + if (r->halt_prep(target) != ERROR_OK) + return ERROR_FAIL; + r->prepped = true; + } + + return ERROR_OK; +} + +int wch_riscv_halt_go_all_harts(struct target *target) +{ + RISCV_INFO(r); + + if (riscv_is_halted(target)) { + LOG_DEBUG("[%s] Hart is already halted.", target_name(target)); + } else { + if (r->halt_go(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_invalidate_register_cache(target); + } + + return ERROR_OK; +} + +int wch_halt_go(struct target *target) +{ + riscv_info_t *r = riscv_info(target); + int result; + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + result = tt->halt(target); + } else { + result = wch_riscv_halt_go_all_harts(target); + } + target->state = TARGET_HALTED; + if (target->debug_reason == DBG_REASON_NOTHALTED) + target->debug_reason = DBG_REASON_DBGRQ; + + return result; +} + +static int halt_finish(struct target *target) +{ + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); +} + +int wch_riscv_halt(struct target *target) +{ + RISCV_INFO(r); + + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + return tt->halt(target); + } + + LOG_TARGET_DEBUG(target, "halting all harts"); + + int result = ERROR_OK; + if (target->smp) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (wch_halt_prep(t) != ERROR_OK) + result = ERROR_FAIL; + } + + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + riscv_info_t *i = riscv_info(t); + if (i->prepped) { + if (wch_halt_go(t) != ERROR_OK) + result = ERROR_FAIL; + } + } + + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (halt_finish(t) != ERROR_OK) + return ERROR_FAIL; + } + + } else { + if (wch_halt_prep(target) != ERROR_OK) + result = ERROR_FAIL; + if (wch_halt_go(target) != ERROR_OK) + result = ERROR_FAIL; + if (halt_finish(target) != ERROR_OK) + return ERROR_FAIL; + } + + return result; +} + +static int riscv_assert_reset(struct target *target) +{ + LOG_DEBUG("[%d]", target->coreid); + struct target_type *tt = get_target_type(target); + riscv_invalidate_register_cache(target); + return tt->assert_reset(target); +} + +static int riscv_deassert_reset(struct target *target) +{ + LOG_DEBUG("[%d]", target->coreid); + struct target_type *tt = get_target_type(target); + return tt->deassert_reset(target); +} + +/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ +static int disable_triggers(struct target *target, riscv_reg_t *state) +{ + RISCV_INFO(r); + + LOG_DEBUG("deal with triggers"); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (r->manual_hwbp_set) { + /* Look at every trigger that may have been set. */ + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + for (unsigned int t = 0; t < r->trigger_count; t++) { + if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + return ERROR_FAIL; + riscv_reg_t tdata1; + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) { + state[t] = tdata1; + if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + return ERROR_FAIL; + } + } + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + } else { + /* Just go through the triggers we manage. */ + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set); + state[i] = watchpoint->is_set; + if (watchpoint->is_set) { + if (wch_riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) + return ERROR_FAIL; + } + watchpoint = watchpoint->next; + i++; + } + } + + return ERROR_OK; +} + +static int enable_triggers(struct target *target, riscv_reg_t *state) +{ + RISCV_INFO(r); + + if (r->manual_hwbp_set) { + /* Look at every trigger that may have been set. */ + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + for (unsigned int t = 0; t < r->trigger_count; t++) { + if (state[t] != 0) { + if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + return ERROR_FAIL; + if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) + return ERROR_FAIL; + } + } + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + } else { + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]); + if (state[i]) { + if (wch_riscv_add_watchpoint(target, watchpoint) != ERROR_OK) + return ERROR_FAIL; + } + watchpoint = watchpoint->next; + i++; + } + } + + return ERROR_OK; +} + +/** + * Get everything ready to resume. + */ +static int resume_prep(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + RISCV_INFO(r); + LOG_TARGET_DEBUG(target, "target->state=%d", target->state); + + if (!current) + riscv_set_register(target, GDB_REGNO_PC, address); + + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; + + if (disable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + + if (old_or_new_riscv_step(target, true, 0, false) != ERROR_OK) + return ERROR_FAIL; + + if (enable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + } + + if (r->is_halted) { + if (r->resume_prep(target) != ERROR_OK) + return ERROR_FAIL; + } + + LOG_DEBUG("[%d] mark as prepped", target->coreid); + r->prepped = true; + + return ERROR_OK; +} + +/** + * Resume all the harts that have been prepped, as close to instantaneous as + * possible. + */ +static int resume_go(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + riscv_info_t *r = riscv_info(target); + int result; + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + result = tt->resume(target, current, address, handle_breakpoints, + debug_execution); + } else { + result = riscv_resume_go_all_harts(target); + } + + return result; +} + +static int resume_finish(struct target *target, int debug_execution) +{ + register_cache_invalidate(target->reg_cache); + + target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return target_call_event_callbacks(target, + debug_execution ? TARGET_EVENT_DEBUG_RESUMED : TARGET_EVENT_RESUMED); +} + +/** + * @par single_hart When true, only resume a single hart even if SMP is + * configured. This is used to run algorithms on just one hart. + */ +int wch_riscv_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution, + bool single_hart) +{ + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + int result = ERROR_OK; + if (target->smp && !single_hart) { + struct target_list *tlist; + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { + struct target *t = tlist->target; + if (resume_prep(t, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { + struct target *t = tlist->target; + riscv_info_t *i = riscv_info(t); + if (i->prepped) { + if (resume_go(t, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + } + + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { + struct target *t = tlist->target; + if (resume_finish(t, debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + + } else { + if (resume_prep(target, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + if (resume_go(target, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + if (resume_finish(target, debug_execution) != ERROR_OK) + return ERROR_FAIL; + } + + return result; +} + +static int riscv_target_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) +{ + return wch_riscv_resume(target, current, address, handle_breakpoints, + debug_execution, false); +} + +static int riscv_mmu(struct target *target, int *enabled) +{ + if (!riscv_enable_virt2phys) { + *enabled = 0; + return ERROR_OK; + } + + /* Don't use MMU in explicit or effective M (machine) mode */ + riscv_reg_t priv; + if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + LOG_ERROR("Failed to read priv register."); + return ERROR_FAIL; + } + + riscv_reg_t mstatus; + if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { + LOG_ERROR("Failed to read mstatus register."); + return ERROR_FAIL; + } + + if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) { + LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus); + *enabled = 0; + return ERROR_OK; + } + + riscv_reg_t satp; + if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { + LOG_DEBUG("Couldn't read SATP."); + /* If we can't read SATP, then there must not be an MMU. */ + *enabled = 0; + return ERROR_OK; + } + + if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) { + LOG_DEBUG("MMU is disabled."); + *enabled = 0; + } else { + LOG_DEBUG("MMU is enabled."); + *enabled = 1; + } + + return ERROR_OK; +} + +static int riscv_address_translate(struct target *target, + target_addr_t virtual, target_addr_t *physical) +{ + RISCV_INFO(r); + riscv_reg_t satp_value; + int mode; + uint64_t ppn_value; + target_addr_t table_address; + const virt2phys_info_t *info; + uint64_t pte = 0; + int i; + + int result = riscv_get_register(target, &satp_value, GDB_REGNO_SATP); + if (result != ERROR_OK) + return result; + + unsigned xlen = riscv_xlen(target); + mode = get_field(satp_value, RISCV_SATP_MODE(xlen)); + switch (mode) { + case SATP_MODE_SV32: + info = &sv32; + break; + case SATP_MODE_SV39: + info = &sv39; + break; + case SATP_MODE_SV48: + info = &sv48; + break; + case SATP_MODE_OFF: + LOG_ERROR("No translation or protection." \ + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; + default: + LOG_ERROR("The translation mode is not supported." \ + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; + } + LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name); + + /* verify bits xlen-1:va_bits-1 are all equal */ + target_addr_t mask = ((target_addr_t)1 << (xlen - (info->va_bits - 1))) - 1; + target_addr_t masked_msbs = (virtual >> (info->va_bits - 1)) & mask; + if (masked_msbs != 0 && masked_msbs != mask) { + LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended " + "for %s mode.", virtual, info->name); + return ERROR_FAIL; + } + + ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen)); + table_address = ppn_value << RISCV_PGSHIFT; + i = info->level - 1; + while (i >= 0) { + uint64_t vpn = virtual >> info->vpn_shift[i]; + vpn &= info->vpn_mask[i]; + target_addr_t pte_address = table_address + + (vpn << info->pte_shift); + uint8_t buffer[8]; + assert(info->pte_shift <= 3); + int retval = r->read_memory(target, pte_address, + 4, (1 << info->pte_shift) / 4, buffer, 4); + if (retval != ERROR_OK) + return ERROR_FAIL; + + if (info->pte_shift == 2) + pte = buf_get_u32(buffer, 0, 32); + else + pte = buf_get_u64(buffer, 0, 64); + + LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i, + pte_address, pte); + + if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) + return ERROR_FAIL; + + if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */ + break; + + i--; + if (i < 0) + break; + ppn_value = pte >> PTE_PPN_SHIFT; + table_address = ppn_value << RISCV_PGSHIFT; + } + + if (i < 0) { + LOG_ERROR("Couldn't find the PTE."); + return ERROR_FAIL; + } + + /* Make sure to clear out the high bits that may be set. */ + *physical = virtual & (((target_addr_t)1 << info->va_bits) - 1); + + while (i < info->level) { + ppn_value = pte >> info->pte_ppn_shift[i]; + ppn_value &= info->pte_ppn_mask[i]; + *physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) << + info->pa_ppn_shift[i]); + *physical |= (ppn_value << info->pa_ppn_shift[i]); + i++; + } + LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual, + *physical); + + return ERROR_OK; +} + +static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) +{ + int enabled; + if (riscv_mmu(target, &enabled) == ERROR_OK) { + if (!enabled) + return ERROR_FAIL; + + if (riscv_address_translate(target, virtual, physical) == ERROR_OK) + return ERROR_OK; + } + + return ERROR_FAIL; +} + +static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV_INFO(r); + return r->read_memory(target, phys_address, size, count, buffer, size); +} + +static int riscv_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + if (count == 0) { + LOG_WARNING("0-length read from 0x%" TARGET_PRIxADDR, address); + return ERROR_OK; + } + + target_addr_t physical_addr; + if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) + address = physical_addr; + + RISCV_INFO(r); + return r->read_memory(target, address, size, count, buffer, size); +} + +static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + struct target_type *tt = get_target_type(target); + return tt->write_memory(target, phys_address, size, count, buffer); +} + +static int riscv_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + if (count == 0) { + LOG_WARNING("0-length write to 0x%" TARGET_PRIxADDR, address); + return ERROR_OK; + } + + target_addr_t physical_addr; + if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) + address = physical_addr; + + struct target_type *tt = get_target_type(target); + return tt->write_memory(target, address, size, count, buffer); +} + + + +static int riscv_get_gdb_reg_list_internal(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class, bool read) +{ + LOG_TARGET_DEBUG(target, "reg_class=%d, read=%d", reg_class, read); + + if (!target->reg_cache) { + LOG_ERROR("Target not initialized. Return ERROR_FAIL."); + return ERROR_FAIL; + } + + switch (reg_class) { + case REG_CLASS_GENERAL: + *reg_list_size = 33; + break; + case REG_CLASS_ALL: + *reg_list_size = target->reg_cache->num_regs; + break; + default: + LOG_ERROR("Unsupported reg_class: %d", reg_class); + return ERROR_FAIL; + } + + *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); + if (!*reg_list) + return ERROR_FAIL; + + for (int i = 0; i < *reg_list_size; i++) { + assert(!target->reg_cache->reg_list[i].valid || + target->reg_cache->reg_list[i].size > 0); + (*reg_list)[i] = &target->reg_cache->reg_list[i]; + if (read && + target->reg_cache->reg_list[i].exist && + !target->reg_cache->reg_list[i].valid) { + if (target->reg_cache->reg_list[i].type->get( + &target->reg_cache->reg_list[i]) != ERROR_OK) + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int riscv_get_gdb_reg_list_noread(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) +{ + return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size, + reg_class, false); +} + +static int riscv_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) +{ + return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size, + reg_class, true); +} + +static int riscv_arch_state(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->arch_state(target); +} + +/* Algorithm must end with a software breakpoint instruction. */ +static int riscv_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + RISCV_INFO(info); + + if (num_mem_params > 0) { + LOG_ERROR("Memory parameters are not supported for RISC-V algorithms."); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Save registers */ + struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", true); + if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) + return ERROR_FAIL; + uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); + LOG_DEBUG("saved_pc=0x%" PRIx64, saved_pc); + + uint64_t saved_regs[32]; + for (int i = 0; i < num_reg_params; i++) { + LOG_DEBUG("save %s", reg_params[i].reg_name); + struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); + if (!r) { + LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name); + return ERROR_FAIL; + } + + if (r->size != reg_params[i].size) { + LOG_ERROR("Register %s is %d bits instead of %d bits.", + reg_params[i].reg_name, r->size, reg_params[i].size); + return ERROR_FAIL; + } + + if (r->number > GDB_REGNO_XPR31) { + LOG_ERROR("Only GPRs can be use as argument registers."); + return ERROR_FAIL; + } + + if (r->type->get(r) != ERROR_OK) + return ERROR_FAIL; + saved_regs[r->number] = buf_get_u64(r->value, 0, r->size); + + if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) { + if (r->type->set(r, reg_params[i].value) != ERROR_OK) + return ERROR_FAIL; + } + } + + /* Disable Interrupts before attempting to run the algorithm. */ + uint64_t current_mstatus; + uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; + if (riscv_interrupts_disable(target, irq_disabled_mask, ¤t_mstatus) != ERROR_OK) + return ERROR_FAIL; + + /* Run algorithm */ + LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); + if (wch_riscv_resume(target, 0, entry_point, 0, 1, true) != ERROR_OK) + return ERROR_FAIL; + + int64_t start = timeval_ms(); + while (target->state != TARGET_HALTED) { + LOG_DEBUG("poll()"); + int64_t now = timeval_ms(); + if (now - start > timeout_ms) { + LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start); + wch_riscv_halt(target); + old_or_new_riscv_poll(target); + enum gdb_regno regnums[] = { + GDB_REGNO_RA, GDB_REGNO_SP, GDB_REGNO_GP, GDB_REGNO_TP, + GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_FP, + GDB_REGNO_S1, GDB_REGNO_A0, GDB_REGNO_A1, GDB_REGNO_A2, + GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_A6, + GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4, + GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8, + GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3, + GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6, + GDB_REGNO_PC, + GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE, + }; + for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { + enum gdb_regno regno = regnums[i]; + riscv_reg_t reg_value; + if (riscv_get_register(target, ®_value, regno) != ERROR_OK) + break; + LOG_ERROR("%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value); + } + return ERROR_TARGET_TIMEOUT; + } + + int result = old_or_new_riscv_poll(target); + if (result != ERROR_OK) + return result; + } + + /* TODO: The current hart id might have been changed in poll(). */ + /* if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; */ + + if (reg_pc->type->get(reg_pc) != ERROR_OK) + return ERROR_FAIL; + uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); + if (exit_point && final_pc != exit_point) { + LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" + TARGET_PRIxADDR, final_pc, exit_point); + return ERROR_FAIL; + } + + /* Restore Interrupts */ + if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) + return ERROR_FAIL; + + /* Restore registers */ + uint8_t buf[8] = { 0 }; + buf_set_u64(buf, 0, info->xlen, saved_pc); + if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) + return ERROR_FAIL; + + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction == PARAM_IN || + reg_params[i].direction == PARAM_IN_OUT) { + struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); + if (r->type->get(r) != ERROR_OK) { + LOG_ERROR("get(%s) failed", r->name); + return ERROR_FAIL; + } + buf_cpy(r->value, reg_params[i].value, reg_params[i].size); + } + LOG_DEBUG("restore %s", reg_params[i].reg_name); + struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); + buf_set_u64(buf, 0, info->xlen, saved_regs[r->number]); + if (r->type->set(r, buf) != ERROR_OK) { + LOG_ERROR("set(%s) failed", r->name); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int riscv_checksum_memory(struct target *target, + target_addr_t address, uint32_t count, + uint32_t *checksum) +{ + struct working_area *crc_algorithm; + struct reg_param reg_params[2]; + int retval; + + LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); + + static const uint8_t riscv32_crc_code[] = { +#include "../../contrib/loaders/checksum/riscv32_crc.inc" + }; + static const uint8_t riscv64_crc_code[] = { +#include "../../contrib/loaders/checksum/riscv64_crc.inc" + }; + + static const uint8_t *crc_code; + + unsigned xlen = riscv_xlen(target); + unsigned crc_code_size; + if (xlen == 32) { + crc_code = riscv32_crc_code; + crc_code_size = sizeof(riscv32_crc_code); + } else { + crc_code = riscv64_crc_code; + crc_code_size = sizeof(riscv64_crc_code); + } + + if (count < crc_code_size * 4) { + /* Don't use the algorithm for relatively small buffers. It's faster + * just to read the memory. target_checksum_memory() will take care of + * that if we fail. */ + return ERROR_FAIL; + } + + retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm); + if (retval != ERROR_OK) + return retval; + + if (crc_algorithm->address + crc_algorithm->size > address && + crc_algorithm->address < address + count) { + /* Region to checksum overlaps with the work area we've been assigned. + * Bail. (Would be better to manually checksum what we read there, and + * use the algorithm for the rest.) */ + target_free_working_area(target, crc_algorithm); + return ERROR_FAIL; + } + + retval = target_write_buffer(target, crc_algorithm->address, crc_code_size, + crc_code); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", + crc_algorithm->address, retval); + target_free_working_area(target, crc_algorithm); + return retval; + } + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, address); + buf_set_u64(reg_params[1].value, 0, xlen, count); + + /* 20 second timeout/megabyte */ + int timeout = 20000 * (1 + (count / (1024 * 1024))); + + retval = target_run_algorithm(target, 0, NULL, 2, reg_params, + crc_algorithm->address, + 0, /* Leave exit point unspecified because we don't know. */ + timeout, NULL); + + if (retval == ERROR_OK) + *checksum = buf_get_u32(reg_params[0].value, 0, 32); + else + LOG_ERROR("error executing RISC-V CRC algorithm"); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + + target_free_working_area(target, crc_algorithm); + + LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval); + + return retval; +} + +/*** OpenOCD Helper Functions ***/ + + static enum riscv_poll_hart { + RPH_NO_CHANGE, + RPH_DISCOVERED_HALTED, + RPH_DISCOVERED_RUNNING, + RPH_ERROR +}; +static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) +{ + RISCV_INFO(r); + + LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state); + + /* If OpenOCD thinks we're running but this hart is halted then it's time + * to raise an event. */ + bool halted = riscv_is_halted(target); + + if (halted && timeval_ms() - r->last_activity > 100) { + /* If we've been idle for a while, flush the register cache. Just in case + * OpenOCD is going to be disconnected without shutting down cleanly. */ + if (wch_riscv_flush_registers(target) != ERROR_OK) + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED && halted) { + LOG_DEBUG(" triggered a halt"); + r->on_halt(target); + return RPH_DISCOVERED_HALTED; + } else if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING && !halted) { + LOG_DEBUG(" triggered running"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return RPH_DISCOVERED_RUNNING; + } + + return RPH_NO_CHANGE; +} + +int wch_sample_memory(struct target *target) +{ + RISCV_INFO(r); + + if (!r->sample_buf.buf || !r->sample_config.enabled) + return ERROR_OK; + + LOG_DEBUG("buf used/size: %d/%d", r->sample_buf.used, r->sample_buf.size); + + uint64_t start = timeval_ms(); + riscv_sample_buf_maybe_add_timestamp(target, true); + int result = ERROR_OK; + if (r->sample_memory) { + result = r->sample_memory(target, &r->sample_buf, &r->sample_config, + start + TARGET_DEFAULT_POLLING_INTERVAL); + if (result != ERROR_NOT_IMPLEMENTED) + goto exit; + } + + /* Default slow path. */ + while (timeval_ms() - start < TARGET_DEFAULT_POLLING_INTERVAL) { + for (unsigned int i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { + if (r->sample_config.bucket[i].enabled && + r->sample_buf.used + 1 + r->sample_config.bucket[i].size_bytes < r->sample_buf.size) { + assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); + r->sample_buf.buf[r->sample_buf.used] = i; + result = riscv_read_phys_memory( + target, r->sample_config.bucket[i].address, + r->sample_config.bucket[i].size_bytes, 1, + r->sample_buf.buf + r->sample_buf.used + 1); + if (result == ERROR_OK) + r->sample_buf.used += 1 + r->sample_config.bucket[i].size_bytes; + else + goto exit; + } + } + } + +exit: + riscv_sample_buf_maybe_add_timestamp(target, false); + if (result != ERROR_OK) { + LOG_INFO("Turning off memory sampling because it failed."); + r->sample_config.enabled = false; + } + return result; +} + +/*** OpenOCD Interface ***/ +int wch_riscv_openocd_poll(struct target *target) +{ + LOG_DEBUG("polling all harts"); + enum target_state old_state = target->state; + + if (target->smp) { + unsigned should_remain_halted = 0; + unsigned should_resume = 0; + struct target_list *list; + foreach_smp_target(list, target->smp_targets) { + struct target *t = list->target; + if (!target_was_examined(t)) + continue; + enum riscv_poll_hart out = riscv_poll_hart(t, t->coreid); + switch (out) { + case RPH_NO_CHANGE: + break; + case RPH_DISCOVERED_RUNNING: + t->state = TARGET_RUNNING; + t->debug_reason = DBG_REASON_NOTHALTED; + break; + case RPH_DISCOVERED_HALTED: + t->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = + riscv_halt_reason(t); + if (set_debug_reason(t, halt_reason) != ERROR_OK) + return ERROR_FAIL; + + if (halt_reason == RISCV_HALT_BREAKPOINT) { + int retval; + switch (riscv_semihosting(t, &retval)) { + case SEMI_NONE: + case SEMI_WAITING: + /* This hart should remain halted. */ + should_remain_halted++; + break; + case SEMI_HANDLED: + /* This hart should be resumed, along with any other + * harts that halted due to haltgroups. */ + should_resume++; + break; + case SEMI_ERROR: + return retval; + } + } else if (halt_reason != RISCV_HALT_GROUP) { + should_remain_halted++; + } + break; + + case RPH_ERROR: + return ERROR_FAIL; + } + } + + LOG_DEBUG("should_remain_halted=%d, should_resume=%d", + should_remain_halted, should_resume); + if (should_remain_halted && should_resume) { + LOG_WARNING("%d harts should remain halted, and %d should resume.", + should_remain_halted, should_resume); + } + if (should_remain_halted) { + LOG_DEBUG("halt all"); + wch_riscv_halt(target); + } else if (should_resume) { + LOG_DEBUG("resume all"); + wch_riscv_resume(target, true, 0, 0, 0, false); + } + + /* Sample memory if any target is running. */ + foreach_smp_target(list, target->smp_targets) { + struct target *t = list->target; + if (t->state == TARGET_RUNNING) { + wch_sample_memory(target); + break; + } + } + + return ERROR_OK; + + } else { + enum riscv_poll_hart out = riscv_poll_hart(target, target->coreid); + if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) { + if (target->state == TARGET_RUNNING) + wch_sample_memory(target); + return ERROR_OK; + } else if (out == RPH_ERROR) { + return ERROR_FAIL; + } + + LOG_TARGET_DEBUG(target, "hart halted"); + + target->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + target->state = TARGET_HALTED; + } + + if (target->debug_reason == DBG_REASON_BREAKPOINT) { + int retval; + switch (riscv_semihosting(target, &retval)) { + case SEMI_NONE: + case SEMI_WAITING: + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + break; + case SEMI_HANDLED: + if (wch_riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK) + return ERROR_FAIL; + break; + case SEMI_ERROR: + return retval; + } + } else { + if (old_state == TARGET_DEBUG_RUNNING) + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + else + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + + return ERROR_OK; +} + +int wch_riscv_openocd_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ + LOG_TARGET_DEBUG(target, "stepping hart"); + + if (!current) { + if (riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK) + return ERROR_FAIL; + } + + struct breakpoint *breakpoint = NULL; + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + if (current) { + if (riscv_get_register(target, &address, GDB_REGNO_PC) != ERROR_OK) + return ERROR_FAIL; + } + breakpoint = breakpoint_find(target, address); + if (breakpoint && (wch_riscv_remove_breakpoint(target, breakpoint) != ERROR_OK)) + return ERROR_FAIL; + } + + riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; + if (disable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + + bool success = true; + uint64_t current_mstatus; + RISCV_INFO(info); + + if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) { + /* Disable Interrupts before stepping. */ + uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; + if (riscv_interrupts_disable(target, irq_disabled_mask, + ¤t_mstatus) != ERROR_OK) { + success = false; + LOG_ERROR("unable to disable interrupts"); + goto _exit; + } + } + + if (riscv_step_rtos_hart(target) != ERROR_OK) { + success = false; + LOG_ERROR("unable to step rtos hart"); + } + + register_cache_invalidate(target->reg_cache); + + if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) + if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) { + success = false; + LOG_ERROR("unable to restore interrupts"); + } + +_exit: + if (enable_triggers(target, trigger_state) != ERROR_OK) { + success = false; + LOG_ERROR("unable to enable triggers"); + } + + if (breakpoint && (wch_riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { + success = false; + LOG_TARGET_ERROR(target, "unable to restore the disabled breakpoint"); + } + + if (success) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + return success ? ERROR_OK : ERROR_FAIL; +} + +/* Command Handlers */ +COMMAND_HANDLER(wch_riscv_set_command_timeout_sec) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0) { + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_command_timeout_sec = timeout; + + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_reset_timeout_sec) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0) { + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_reset_timeout_sec = timeout; + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_prefer_sba) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + bool prefer_sba; + LOG_WARNING("`riscv set_prefer_sba` is deprecated. Please use `riscv set_mem_access` instead."); + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], prefer_sba); + if (prefer_sba) { + /* Use system bus with highest priority */ + r->mem_access_methods[0] = RISCV_MEM_ACCESS_SYSBUS; + r->mem_access_methods[1] = RISCV_MEM_ACCESS_PROGBUF; + r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; + } else { + /* Use progbuf with highest priority */ + r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF; + r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; + r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; + } + + /* Reset warning flags */ + r->mem_access_progbuf_warn = true; + r->mem_access_sysbus_warn = true; + r->mem_access_abstract_warn = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_mem_access) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + int progbuf_cnt = 0; + int sysbus_cnt = 0; + int abstract_cnt = 0; + + if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) { + LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* Check argument validity */ + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (strcmp("progbuf", CMD_ARGV[i]) == 0) { + progbuf_cnt++; + } else if (strcmp("sysbus", CMD_ARGV[i]) == 0) { + sysbus_cnt++; + } else if (strcmp("abstract", CMD_ARGV[i]) == 0) { + abstract_cnt++; + } else { + LOG_ERROR("Unknown argument '%s'. " + "Must be one of: 'progbuf', 'sysbus' or 'abstract'.", CMD_ARGV[i]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + if (progbuf_cnt > 1 || sysbus_cnt > 1 || abstract_cnt > 1) { + LOG_ERROR("Syntax error - duplicate arguments to `riscv set_mem_access`."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* Args are valid, store them */ + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED; + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (strcmp("progbuf", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF; + else if (strcmp("sysbus", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_SYSBUS; + else if (strcmp("abstract", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_ABSTRACT; + } + + /* Reset warning flags */ + r->mem_access_progbuf_warn = true; + r->mem_access_sysbus_warn = true; + r->mem_access_abstract_warn = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_enable_virtual) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual); + return ERROR_OK; +} + + +COMMAND_HANDLER(wch_riscv_set_expose_csrs) +{ + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + int ret = ERROR_OK; + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + ret = parse_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff); + if (ret != ERROR_OK) + break; + } + + return ret; +} + +COMMAND_HANDLER(wch_riscv_set_expose_custom) +{ + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + int ret = ERROR_OK; + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + ret = parse_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff); + if (ret != ERROR_OK) + break; + } + + return ret; +} + +COMMAND_HANDLER(wch_riscv_authdata_read) +{ + unsigned int index = 0; + if (CMD_ARGC == 0) { + /* nop */ + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + } else { + LOG_ERROR("Command takes at most one parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->authdata_read) { + uint32_t value; + if (r->authdata_read(target, &value, index) != ERROR_OK) + return ERROR_FAIL; + command_print_sameline(CMD, "0x%08" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("authdata_read is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(wch_riscv_authdata_write) +{ + uint32_t value; + unsigned int index = 0; + + if (CMD_ARGC == 0) { + /* nop */ + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); + } else if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + } else { + LOG_ERROR("Command takes at most 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (r->authdata_write) { + return r->authdata_write(target, value, index); + } else { + LOG_ERROR("authdata_write is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(wch_riscv_dmi_read) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->dmi_read) { + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("dmi_read is not implemented for this target."); + return ERROR_FAIL; + } +} + + +COMMAND_HANDLER(wch_riscv_dmi_write) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (r->dmi_write) { + /* Perform the DMI write */ + int retval = r->dmi_write(target, address, value); + + /* Invalidate our cached progbuf copy: + - if the user tinkered directly with a progbuf register + - if debug module was reset, in which case progbuf registers + may not retain their value. + */ + bool progbufTouched = (address >= DM_PROGBUF0 && address <= DM_PROGBUF15); + bool dmDeactivated = (address == DM_DMCONTROL && (value & DM_DMCONTROL_DMACTIVE) == 0); + if (progbufTouched || dmDeactivated) { + if (r->invalidate_cached_debug_buffer) + r->invalidate_cached_debug_buffer(target); + } + + return retval; + } + + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; +} + +COMMAND_HANDLER(wch_riscv_test_sba_config_reg) +{ + if (CMD_ARGC != 4) { + LOG_ERROR("Command takes exactly 4 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + target_addr_t legal_address; + uint32_t num_words; + target_addr_t illegal_address; + bool run_sbbusyerror_test; + + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], legal_address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], num_words); + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[2], illegal_address); + COMMAND_PARSE_ON_OFF(CMD_ARGV[3], run_sbbusyerror_test); + + if (r->test_sba_config_reg) { + return r->test_sba_config_reg(target, legal_address, num_words, + illegal_address, run_sbbusyerror_test); + } else { + LOG_ERROR("test_sba_config_reg is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(wch_riscv_reset_delays) +{ + int wait = 0; + + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait); + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + r->reset_delays_wait = wait; + return ERROR_OK; +} + + + +COMMAND_HANDLER(wch_riscv_resume_order) +{ + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!strcmp(CMD_ARGV[0], "normal")) { + resume_order = RO_NORMAL; + } else if (!strcmp(CMD_ARGV[0], "reversed")) { + resume_order = RO_REVERSED; + } else { + LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return ERROR_OK; +} + + + + +COMMAND_HANDLER(wch_riscv_set_maskisr) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + + static const struct jim_nvp nvp_maskisr_modes[] = { + { .name = "off", .value = RISCV_ISRMASK_OFF }, + { .name = "steponly", .value = RISCV_ISRMASK_STEPONLY }, + { .name = NULL, .value = -1 }, + }; + const struct jim_nvp *n; + + if (CMD_ARGC > 0) { + n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + if (!n->name) + return ERROR_COMMAND_SYNTAX_ERROR; + info->isrmask_mode = n->value; + } else { + n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode); + command_print(CMD, "riscv interrupt mask %s", n->name); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_enable_virt2phys) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys); + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_ebreakm) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_ebreaks) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); + return ERROR_OK; +} + +COMMAND_HANDLER(wch_riscv_set_ebreaku) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); + return ERROR_OK; +} + +COMMAND_HANDLER(wch_handle_repeat_read) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC < 2) { + LOG_ERROR("Command requires at least count and address arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (CMD_ARGC > 3) { + LOG_ERROR("Command takes at most 3 arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t count; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address); + uint32_t size = 4; + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); + + if (count == 0) + return ERROR_OK; + + uint8_t *buffer = malloc(size * count); + if (!buffer) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + int result = r->read_memory(target, address, size, count, buffer, 0); + if (result == ERROR_OK) { + target_handle_md_output(cmd, target, address, size, count, buffer, + false); + } + free(buffer); + return result; +} + +COMMAND_HANDLER(wch_handle_memory_sample_command) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "Memory sample configuration for %s:", target_name(target)); + for (unsigned i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { + if (r->sample_config.bucket[i].enabled) { + command_print(CMD, "bucket %d; address=0x%" TARGET_PRIxADDR "; size=%d", i, + r->sample_config.bucket[i].address, + r->sample_config.bucket[i].size_bytes); + } else { + command_print(CMD, "bucket %d; disabled", i); + } + } + return ERROR_OK; + } + + if (CMD_ARGC < 2) { + LOG_ERROR("Command requires at least bucket and address arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t bucket; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bucket); + if (bucket > ARRAY_SIZE(r->sample_config.bucket)) { + LOG_ERROR("Max bucket number is %d.", (unsigned) ARRAY_SIZE(r->sample_config.bucket)); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (!strcmp(CMD_ARGV[1], "clear")) { + r->sample_config.bucket[bucket].enabled = false; + } else { + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], r->sample_config.bucket[bucket].address); + + if (CMD_ARGC > 2) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], r->sample_config.bucket[bucket].size_bytes); + if (r->sample_config.bucket[bucket].size_bytes != 4 && + r->sample_config.bucket[bucket].size_bytes != 8) { + LOG_ERROR("Only 4-byte and 8-byte sizes are supported."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } else { + r->sample_config.bucket[bucket].size_bytes = 4; + } + + r->sample_config.bucket[bucket].enabled = true; + } + + if (!r->sample_buf.buf) { + r->sample_buf.size = 1024 * 1024; + r->sample_buf.buf = malloc(r->sample_buf.size); + } + + /* Clear the buffer when the configuration is changed. */ + r->sample_buf.used = 0; + + r->sample_config.enabled = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(wch_handle_dump_sample_buf_command) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most 1 arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + bool base64 = false; + if (CMD_ARGC > 0) { + if (!strcmp(CMD_ARGV[0], "base64")) { + base64 = true; + } else { + LOG_ERROR("Unknown argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + + int result = ERROR_OK; + if (base64) { + unsigned char *encoded = base64_encode(r->sample_buf.buf, + r->sample_buf.used, NULL); + if (!encoded) { + LOG_ERROR("Failed base64 encode!"); + result = ERROR_FAIL; + goto error; + } + command_print(CMD, "%s", encoded); + free(encoded); + } else { + unsigned i = 0; + while (i < r->sample_buf.used) { + uint8_t command = r->sample_buf.buf[i++]; + if (command == RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE) { + uint32_t timestamp = buf_get_u32(r->sample_buf.buf + i, 0, 32); + i += 4; + command_print(CMD, "timestamp before: %u", timestamp); + } else if (command == RISCV_SAMPLE_BUF_TIMESTAMP_AFTER) { + uint32_t timestamp = buf_get_u32(r->sample_buf.buf + i, 0, 32); + i += 4; + command_print(CMD, "timestamp after: %u", timestamp); + } else if (command < ARRAY_SIZE(r->sample_config.bucket)) { + command_print_sameline(CMD, "0x%" TARGET_PRIxADDR ": ", + r->sample_config.bucket[command].address); + if (r->sample_config.bucket[command].size_bytes == 4) { + uint32_t value = buf_get_u32(r->sample_buf.buf + i, 0, 32); + i += 4; + command_print(CMD, "0x%08" PRIx32, value); + } else if (r->sample_config.bucket[command].size_bytes == 8) { + uint64_t value = buf_get_u64(r->sample_buf.buf + i, 0, 64); + i += 8; + command_print(CMD, "0x%016" PRIx64, value); + } else { + LOG_ERROR("Found invalid size in bucket %d: %d", command, + r->sample_config.bucket[command].size_bytes); + result = ERROR_FAIL; + goto error; + } + } else { + LOG_ERROR("Found invalid command byte in sample buf: 0x%2x at offset 0x%x", + command, i - 1); + result = ERROR_FAIL; + goto error; + } + } + } + +error: + /* Clear the sample buffer even when there was an error. */ + r->sample_buf.used = 0; + return result; +} + + + +COMMAND_HANDLER(wch_handle_info) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + /* This output format can be fed directly into TCL's "array set". */ + + riscv_print_info_line(CMD, "hart", "xlen", riscv_xlen(target)); + riscv_enumerate_triggers(target); + riscv_print_info_line(CMD, "hart", "trigger_count", + r->trigger_count); + + if (r->print_info) + return CALL_COMMAND_HANDLER(r->print_info, target); + + return 0; +} + +static const struct command_registration riscv_exec_command_handlers[] = { + { + .name = "dump_sample_buf", + .handler = wch_handle_dump_sample_buf_command, + .mode = COMMAND_ANY, + .usage = "[base64]", + .help = "Print the contents of the sample buffer, and clear the buffer." + }, + { + .name = "info", + .handler = wch_handle_info, + .mode = COMMAND_ANY, + .usage = "", + .help = "Displays some information OpenOCD detected about the target." + }, + { + .name = "memory_sample", + .handler = wch_handle_memory_sample_command, + .mode = COMMAND_ANY, + .usage = "bucket address|clear [size=4]", + .help = "Causes OpenOCD to frequently read size bytes at the given address." + }, + { + .name = "repeat_read", + .handler = wch_handle_repeat_read, + .mode = COMMAND_ANY, + .usage = "count address [size=4]", + .help = "Repeatedly read the value at address." + }, + { + .name = "set_command_timeout_sec", + .handler = wch_riscv_set_command_timeout_sec, + .mode = COMMAND_ANY, + .usage = "[sec]", + .help = "Set the wall-clock timeout (in seconds) for individual commands" + }, + { + .name = "set_reset_timeout_sec", + .handler = wch_riscv_set_reset_timeout_sec, + .mode = COMMAND_ANY, + .usage = "[sec]", + .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" + }, + { + .name = "set_prefer_sba", + .handler = wch_riscv_set_prefer_sba, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "When on, prefer to use System Bus Access to access memory. " + "When off (default), prefer to use the Program Buffer to access memory." + }, + { + .name = "set_mem_access", + .handler = wch_riscv_set_mem_access, + .mode = COMMAND_ANY, + .usage = "method1 [method2] [method3]", + .help = "Set which memory access methods shall be used and in which order " + "of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'." + }, + { + .name = "set_enable_virtual", + .handler = wch_riscv_set_enable_virtual, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "When on, memory accesses are performed on physical or virtual " + "memory depending on the current system configuration. " + "When off (default), all memory accessses are performed on physical memory." + }, + { + .name = "expose_csrs", + .handler = wch_riscv_set_expose_csrs, + .mode = COMMAND_CONFIG, + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", + .help = "Configure a list of inclusive ranges for CSRs to expose in " + "addition to the standard ones. This must be executed before " + "`init`." + }, + { + .name = "expose_custom", + .handler = wch_riscv_set_expose_custom, + .mode = COMMAND_CONFIG, + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", + .help = "Configure a list of inclusive ranges for custom registers to " + "expose. custom0 is accessed as abstract register number 0xc000, " + "etc. This must be executed before `init`." + }, + { + .name = "authdata_read", + .handler = wch_riscv_authdata_read, + .usage = "[index]", + .mode = COMMAND_ANY, + .help = "Return the 32-bit value read from authdata or authdata0 " + "(index=0), or authdata1 (index=1)." + }, + { + .name = "authdata_write", + .handler = wch_riscv_authdata_write, + .mode = COMMAND_ANY, + .usage = "[index] value", + .help = "Write the 32-bit value to authdata or authdata0 (index=0), " + "or authdata1 (index=1)." + }, + { + .name = "dmi_read", + .handler = wch_riscv_dmi_read, + .mode = COMMAND_ANY, + .usage = "address", + .help = "Perform a 32-bit DMI read at address, returning the value." + }, + { + .name = "dmi_write", + .handler = wch_riscv_dmi_write, + .mode = COMMAND_ANY, + .usage = "address value", + .help = "Perform a 32-bit DMI write of value at address." + }, + { + .name = "test_sba_config_reg", + .handler = wch_riscv_test_sba_config_reg, + .mode = COMMAND_ANY, + .usage = "legal_address num_words " + "illegal_address run_sbbusyerror_test[on/off]", + .help = "Perform a series of tests on the SBCS register. " + "Inputs are a legal, 128-byte aligned address and a number of words to " + "read/write starting at that address (i.e., address range [legal address, " + "legal_address+word_size*num_words) must be legally readable/writable), " + "an illegal, 128-byte aligned address for error flag/handling cases, " + "and whether sbbusyerror test should be run." + }, + { + .name = "reset_delays", + .handler = wch_riscv_reset_delays, + .mode = COMMAND_ANY, + .usage = "[wait]", + .help = "OpenOCD learns how many Run-Test/Idle cycles are required " + "between scans to avoid encountering the target being busy. This " + "command resets those learned values after `wait` scans. It's only " + "useful for testing OpenOCD itself." + }, + { + .name = "resume_order", + .handler = wch_riscv_resume_order, + .mode = COMMAND_ANY, + .usage = "normal|reversed", + .help = "Choose the order that harts are resumed in when `hasel` is not " + "supported. Normal order is from lowest hart index to highest. " + "Reversed order is from highest hart index to lowest." + }, + + { + .name = "set_maskisr", + .handler = wch_riscv_set_maskisr, + .mode = COMMAND_EXEC, + .help = "mask riscv interrupts", + .usage = "['off'|'steponly']", + }, + { + .name = "set_enable_virt2phys", + .handler = wch_riscv_set_enable_virt2phys, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "When on (default), enable translation from virtual address to " + "physical address." + }, + { + .name = "set_ebreakm", + .handler = wch_riscv_set_ebreakm, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaks", + .handler = wch_riscv_set_ebreaks, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaku", + .handler = wch_riscv_set_ebreaku, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + COMMAND_REGISTRATION_DONE +}; + +/* + * To be noted that RISC-V targets use the same semihosting commands as + * ARM targets. + * + * The main reason is compatibility with existing tools. For example the + * Eclipse OpenOCD/SEGGER J-Link/QEMU plug-ins have several widgets to + * configure semihosting, which generate commands like `arm semihosting + * enable`. + * A secondary reason is the fact that the protocol used is exactly the + * one specified by ARM. If RISC-V will ever define its own semihosting + * protocol, then a command like `riscv semihosting enable` will make + * sense, but for now all semihosting commands are prefixed with `arm`. + */ +extern const struct command_registration semihosting_common_handlers[]; + +const struct command_registration wch_riscv_command_handlers[] = { + { + .name = "riscv", + .mode = COMMAND_ANY, + .help = "RISC-V Command Group", + .usage = "", + .chain = riscv_exec_command_handlers + }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +static unsigned riscv_xlen_nonconst(struct target *target) +{ + return riscv_xlen(target); +} + +static unsigned int riscv_data_bits(struct target *target) +{ + RISCV_INFO(r); + if (r->data_bits) + return r->data_bits(target); + return riscv_xlen(target); +} + +struct target_type wch_riscv_target = { + .name = "wch_riscv", + + .target_create = wch_riscv_create_target, + .init_target = wch_riscv_init_target, + .deinit_target = wch_riscv_deinit_target, + .examine = wch_riscv_examine, + + /* poll current target status */ + .poll = old_or_new_riscv_poll, + + .halt = wch_riscv_halt, + .resume = riscv_target_resume, + .step = old_or_new_riscv_step, + + .assert_reset = riscv_assert_reset, + .deassert_reset = riscv_deassert_reset, + + .read_memory = riscv_read_memory, + .write_memory = riscv_write_memory, + .read_phys_memory = riscv_read_phys_memory, + .write_phys_memory = riscv_write_phys_memory, + + .checksum_memory = riscv_checksum_memory, + + .mmu = riscv_mmu, + .virt2phys = riscv_virt2phys, + + .get_gdb_arch = riscv_get_gdb_arch, + .get_gdb_reg_list = riscv_get_gdb_reg_list, + .get_gdb_reg_list_noread = riscv_get_gdb_reg_list_noread, + + .add_breakpoint = wch_riscv_add_breakpoint, + .remove_breakpoint = wch_riscv_remove_breakpoint, + + .add_watchpoint = wch_riscv_add_watchpoint, + .remove_watchpoint = wch_riscv_remove_watchpoint, + .hit_watchpoint = riscv_hit_watchpoint, + + .arch_state = riscv_arch_state, + + .run_algorithm = riscv_run_algorithm, + + .commands = wch_riscv_command_handlers, + + .address_bits = riscv_xlen_nonconst, + .data_bits = riscv_data_bits +}; + + + +static int riscv_resume_go_all_harts(struct target *target) +{ + RISCV_INFO(r); + + LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state); + if (riscv_is_halted(target)) { + if (r->resume_go(target) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_DEBUG("[%s] hart requested resume, but was already resumed", + target_name(target)); + } + + riscv_invalidate_register_cache(target); + return ERROR_OK; +} + + + + + +/** + * If write is true: + * return true iff we are guaranteed that the register will contain exactly + * the value we just wrote when it's read. + * If write is false: + * return true iff we are guaranteed that the register will read the same + * value in the future as the value we just read. + */ +static bool gdb_regno_cacheable(enum gdb_regno regno, bool write) +{ + /* GPRs, FPRs, vector registers are just normal data stores. */ + if (regno <= GDB_REGNO_XPR31 || + (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || + (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)) + return true; + + /* Most CSRs won't change value on us, but we can't assume it about arbitrary + * CSRs. */ + switch (regno) { + case GDB_REGNO_DPC: + return true; + + case GDB_REGNO_VSTART: + case GDB_REGNO_VXSAT: + case GDB_REGNO_VXRM: + case GDB_REGNO_VLENB: + case GDB_REGNO_VL: + case GDB_REGNO_VTYPE: + case GDB_REGNO_MISA: + case GDB_REGNO_DCSR: + case GDB_REGNO_DSCRATCH0: + case GDB_REGNO_MSTATUS: + case GDB_REGNO_MEPC: + case GDB_REGNO_MCAUSE: + case GDB_REGNO_SATP: + /* + * WARL registers might not contain the value we just wrote, but + * these ones won't spontaneously change their value either. * + */ + return !write; + + case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ + case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ + case GDB_REGNO_TDATA2: /* Changse value when tselect is changed. */ + default: + return false; + } +} + + + +static int register_get(struct reg *reg) +{ + riscv_reg_info_t *reg_info = reg->arch_info; + struct target *target = reg_info->target; + RISCV_INFO(r); + + if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { + if (!r->get_register_buf) { + LOG_ERROR("Reading register %s not supported on this RISC-V target.", + gdb_regno_name(reg->number)); + return ERROR_FAIL; + } + + if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK) + return ERROR_FAIL; + } else { + uint64_t value; + int result = riscv_get_register(target, &value, reg->number); + if (result != ERROR_OK) + return result; + buf_set_u64(reg->value, 0, reg->size, value); + } + reg->valid = gdb_regno_cacheable(reg->number, false); + char *str = buf_to_hex_str(reg->value, reg->size); + LOG_DEBUG("[%s] read 0x%s from %s (valid=%d)", target_name(target), + str, reg->name, reg->valid); + free(str); + return ERROR_OK; +} + +static int register_set(struct reg *reg, uint8_t *buf) +{ + riscv_reg_info_t *reg_info = reg->arch_info; + struct target *target = reg_info->target; + RISCV_INFO(r); + + char *str = buf_to_hex_str(buf, reg->size); + LOG_DEBUG("[%s] write 0x%s to %s (valid=%d)", target_name(target), + str, reg->name, reg->valid); + free(str); + + /* Exit early for writing x0, which on the hardware would be ignored, and we + * don't want to update our cache. */ + if (reg->number == GDB_REGNO_ZERO) + return ERROR_OK; + + memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); + reg->valid = gdb_regno_cacheable(reg->number, true); + + if (reg->number == GDB_REGNO_TDATA1 || + reg->number == GDB_REGNO_TDATA2) { + r->manual_hwbp_set = true; + /* When enumerating triggers, we clear any triggers with DMODE set, + * assuming they were left over from a previous debug session. So make + * sure that is done before a user might be setting their own triggers. + */ + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + } + + if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { + if (!r->set_register_buf) { + LOG_ERROR("Writing register %s not supported on this RISC-V target.", + gdb_regno_name(reg->number)); + return ERROR_FAIL; + } + + if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK) + return ERROR_FAIL; + } else { + uint64_t value = buf_get_u64(buf, 0, reg->size); + if (riscv_set_register(target, reg->number, value) != ERROR_OK) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static struct reg_arch_type riscv_reg_arch_type = { + .get = register_get, + .set = register_set +}; + +static struct csr_info { + unsigned number; + const char *name; +}; + +static int cmp_csr_info(const void *p1, const void *p2) +{ + return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); +} + + + + + diff --git a/src/target/wch_riscv.h b/src/target/wch_riscv.h new file mode 100755 index 000000000..24c06c00a --- /dev/null +++ b/src/target/wch_riscv.h @@ -0,0 +1,26 @@ +#include + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +extern const virt2phys_info_t sv32; +extern const virt2phys_info_t sv39; +extern const virt2phys_info_t sv48; + + +extern void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before); +extern const char *riscv_get_gdb_arch(struct target *target); +extern int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val); + +extern const char *gdb_regno_name(enum gdb_regno regno); +extern struct target_type wch_riscv013_target; + + + +extern bool riscv_enable_virt2phys ; +extern bool riscv_ebreakm ; +extern bool riscv_ebreaks ; +extern bool riscv_ebreaku ; + +extern bool riscv_enable_virtual; +extern int wch_riscv_openocd_poll(struct target *target); \ No newline at end of file diff --git a/src/transport/transport.h b/src/transport/transport.h old mode 100644 new mode 100755 index e04f78063..b51e51339 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -97,7 +97,7 @@ bool transport_is_swd(void); bool transport_is_dapdirect_jtag(void); bool transport_is_dapdirect_swd(void); bool transport_is_swim(void); - +bool transport_is_sdi(void); #if BUILD_HLADAPTER bool transport_is_hla(void); #else From 208f87056a38e2717424fb34031979e69bd3f7b4 Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Thu, 24 Aug 2023 11:10:41 -0400 Subject: [PATCH 182/186] Add a more standard interface config and target config for wch parts and wlink driver. Mirroring: https://github.com/karlp/openocd-hacks/commit/dab1ec4235209360778196584f4d62d553eff227 --- tcl/interface/wlink.cfg | 5 +++++ tcl/target/wch-riscv.cfg | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 tcl/interface/wlink.cfg create mode 100644 tcl/target/wch-riscv.cfg diff --git a/tcl/interface/wlink.cfg b/tcl/interface/wlink.cfg new file mode 100644 index 000000000..9dd89cfe8 --- /dev/null +++ b/tcl/interface/wlink.cfg @@ -0,0 +1,5 @@ +adapter driver wlinke +adapter speed 6000 +transport select sdi + +wlink_set_address 0x00000000 \ No newline at end of file diff --git a/tcl/target/wch-riscv.cfg b/tcl/target/wch-riscv.cfg new file mode 100644 index 000000000..e49d9c418 --- /dev/null +++ b/tcl/target/wch-riscv.cfg @@ -0,0 +1,7 @@ +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash + +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 \ No newline at end of file From c60ddd58fd16592cf3a821eef598be44c1d59a0b Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Thu, 24 Aug 2023 12:11:38 -0400 Subject: [PATCH 183/186] Delete .travis.yml --- .travis.yml | 76 ----------------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d0bc8f261..000000000 --- a/.travis.yml +++ /dev/null @@ -1,76 +0,0 @@ -language: c -dist: trusty - -matrix: - include: - - os: linux - env: - - BUILD=x86_64-linux-gnu - - EXECUTABLE=openocd - addons: - apt: - packages: - - patchutils - compiler: gcc - - - os: linux - env: - - BUILD=i686-linux-gnu - - CFLAGS=-m32 - - EXECUTABLE=openocd - addons: - apt: - packages: - - gcc-multilib patchutils - compiler: gcc - - - os: linux - env: - - BUILD=x86_64-linux-gnu - - EXECUTABLE=openocd - addons: - apt: - packages: - - patchutils - compiler: clang - - - os: linux - env: - - BUILD=i686-linux-gnu - - CFLAGS=-m32 - - CONFIGURE_ARGS="--disable-target64" - - EXECUTABLE=openocd - compiler: clang - addons: - apt: - packages: - - gcc-multilib patchutils - - - os: linux - env: - - BUILD=i686-w64-mingw - - CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32" - - EXECUTABLE=openocd.exe - compiler: i686-w64-mingw32-gcc - addons: - apt: - packages: - - binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 patchutils - -script: - # This is here for the signoff check. - # Disabled because when travis does the integration build the last change - # is an automated change, which won't have the Signed-off-by line. - #- ./tools/checkpatch.sh - - # Ideally we'd diff back to where we either branched off OpenOCD or master, - # or riscv. But that's tricky, and the default git clone only gets the last - # 50 changes any case. Most merges won't consist of more than 40 changes, - # so this should work fine most of the time, and be a lot better than not - # checking at all. - - git diff -U20 HEAD~40 | - filterdiff -x "a/src/jtag/drivers/libjaylink/*" -x "a/tools/git2cl/*" - -x "b/src/gnulib/*" | - ./tools/scripts/checkpatch.pl --no-signoff - - - ./bootstrap && ./configure --enable-remote-bitbang --enable-jtag_vpi $CONFIGURE_ARGS && make - - file src/$EXECUTABLE From 820f357bc7d729b2bf35b65b5077f5fe6526dc83 Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Thu, 24 Aug 2023 12:14:32 -0400 Subject: [PATCH 184/186] Wlink config fixes --- tcl/interface/wlink.cfg | 2 -- tcl/target/wch-riscv.cfg | 8 +++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tcl/interface/wlink.cfg b/tcl/interface/wlink.cfg index 9dd89cfe8..73707ac27 100644 --- a/tcl/interface/wlink.cfg +++ b/tcl/interface/wlink.cfg @@ -1,5 +1,3 @@ adapter driver wlinke adapter speed 6000 transport select sdi - -wlink_set_address 0x00000000 \ No newline at end of file diff --git a/tcl/target/wch-riscv.cfg b/tcl/target/wch-riscv.cfg index e49d9c418..35131c306 100644 --- a/tcl/target/wch-riscv.cfg +++ b/tcl/target/wch-riscv.cfg @@ -1,7 +1,13 @@ +transport select sdi + +wlink_set_address 0x00000000 +set _CHIPNAME wch_riscv +sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 + set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1 set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 \ No newline at end of file +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 From 84576c8c4afc3c155269a8e6bde77d82c4ca363f Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Fri, 25 Aug 2023 01:03:19 -0400 Subject: [PATCH 185/186] Restore semihosting support for RISCV on WCH chips Change-Id: Id9c974ce48cf90f6235fbb0663a8e5c7b4a29896 --- src/target/wch_riscv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target/wch_riscv.c b/src/target/wch_riscv.c index e5d94e7bd..9919d5ccd 100755 --- a/src/target/wch_riscv.c +++ b/src/target/wch_riscv.c @@ -85,6 +85,8 @@ static int wch_riscv_init_target(struct command_context *cmd_ctx, RISCV_INFO(info); info->cmd_ctx = cmd_ctx; + riscv_semihosting_init(target); + target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; From 569a2316fc5f7c22dc29ecf8c04fcaaa73bfe64a Mon Sep 17 00:00:00 2001 From: Thomas Reidemeister Date: Fri, 25 Aug 2023 01:09:11 -0400 Subject: [PATCH 186/186] Temporarily disabling signoff --- git-hooks/pre-push | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-hooks/pre-push b/git-hooks/pre-push index a7e126655..d7e0aa552 100755 --- a/git-hooks/pre-push +++ b/git-hooks/pre-push @@ -1,3 +1,3 @@ #!/bin/sh -./tools/checkpatch.sh +#./tools/checkpatch.sh