This is an automated email from Gerrit.

"Erhan Kurubas <erhan.kuru...@espressif.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6942

-- gerrit

commit 6c4a4d21e3954119bcff5d0f944700c29c256bd9
Author: Erhan Kurubas <erhan.kuru...@espressif.com>
Date:   Thu Apr 21 21:17:04 2022 +0200

    target: add Espressif ESP32-C3 basic support
    
    Signed-off-by: Erhan Kurubas <erhan.kuru...@espressif.com>
    Change-Id: Ifb83e698ec5d5c6ec6ba488ee70dbe4b7efe4bc0

diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 49e882fe6c..783652f097 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -17,6 +17,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
        $(MIPS32_SRC) \
        $(NDS32_SRC) \
        $(STM8_SRC) \
+       $(ESP32_SRC) \
        $(INTEL_IA32_SRC) \
        $(ESIRISC_SRC) \
         $(ARC_SRC) \
@@ -145,6 +146,11 @@ NDS32_SRC = \
 STM8_SRC = \
        %D%/stm8.c
 
+ESP32_SRC= \
+       %D%/esp32c3.c \
+       %D%/esp.c \
+       %D%/esp_riscv.c \
+       %D%/esp_semihosting.c
 INTEL_IA32_SRC = \
        %D%/quark_x10xx.c \
        %D%/quark_d20xx.c \
diff --git a/src/target/esp.c b/src/target/esp.c
new file mode 100644
index 0000000000..c29c3fbdee
--- /dev/null
+++ b/src/target/esp.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *   Espressif chips common target API for OpenOCD                         *
+ *   Copyright (C) 2021 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include <helper/log.h>
+#include <helper/binarybuffer.h>
+#include "target.h"
+#include "esp.h"
+
+#define ESP_FLASH_BREAKPOINTS_MAX_NUM  32
+
+
+int esp_common_init(struct esp_common *esp)
+{
+       return ERROR_OK;
+}
+
+int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs 
*dbg_stubs)
+{
+       int table_size, table_start_id, desc_entry_id, gcov_entry_id;
+       uint32_t entries[ESP_DBG_STUB_ENTRY_MAX];
+
+       LOG_DEBUG("%s: Read debug stubs info %" PRIu32 " / %d", 
target_name(target),
+               dbg_stubs->base, dbg_stubs->entries_count);
+
+       /* first read 2 entries to get magic num and table size */
+       int res = target_read_memory(target, dbg_stubs->base, sizeof(uint32_t),
+               2,
+               (uint8_t *)&entries[0]);
+       if (res != ERROR_OK) {
+               LOG_ERROR("%s: Failed to read first debug stub entry!", 
target_name(target));
+               return res;
+       }
+       if (entries[0] != ESP_DBG_STUB_MAGIC_NUM_VAL) {
+               /* idf with the old table entry structure */
+               table_size = 2;
+               table_start_id = desc_entry_id = 0;
+               gcov_entry_id = 1;
+       } else {
+               table_size = entries[1];
+               table_start_id = desc_entry_id = ESP_DBG_STUB_TABLE_START;
+               gcov_entry_id = ESP_DBG_STUB_ENTRY_FIRST;
+
+               if (table_size < 2) {
+                       LOG_ERROR("Invalid stub table entry size (%x)", 
table_size);
+                       return ERROR_FAIL;
+               }
+               /* discard unsupported entries */
+               if (table_size > ESP_DBG_STUB_ENTRY_MAX)
+                       table_size = ESP_DBG_STUB_ENTRY_MAX;
+
+               /* now read the remaining entries */
+               res = target_read_memory(target,
+                       dbg_stubs->base + 2 * sizeof(uint32_t),
+                       sizeof(uint32_t),
+                       table_size - 2,
+                       (uint8_t *)&entries[2]);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("%s: Failed to read debug stubs info!", 
target_name(target));
+                       return res;
+               }
+               dbg_stubs->entries[ESP_DBG_STUB_CAPABILITIES] =
+                       entries[ESP_DBG_STUB_CAPABILITIES];
+       }
+
+       dbg_stubs->entries[ESP_DBG_STUB_DESC] = entries[desc_entry_id];
+       dbg_stubs->entries[ESP_DBG_STUB_ENTRY_GCOV] = entries[gcov_entry_id];
+
+       for (enum esp_dbg_stub_id i = ESP_DBG_STUB_DESC; i < 
ESP_DBG_STUB_ENTRY_MAX; i++) {
+               LOG_DEBUG("Check dbg stub %d - %x", i, dbg_stubs->entries[i]);
+               if (dbg_stubs->entries[i]) {
+                       dbg_stubs->entries[i] = buf_get_u32(
+                               (uint8_t *)&dbg_stubs->entries[i],
+                               0,
+                               32);
+                       LOG_DEBUG("New dbg stub %d at %x",
+                               dbg_stubs->entries_count,
+                               dbg_stubs->entries[i]);
+                       dbg_stubs->entries_count++;
+               }
+       }
+       if (dbg_stubs->entries_count <
+               (uint32_t)(table_size - table_start_id)) {
+               LOG_WARNING("Not full dbg stub table %d of %d", 
dbg_stubs->entries_count,
+                       (table_size - table_start_id));
+       }
+
+       return ERROR_OK;
+}
+
+int esp_common_handle_gdb_detach(struct target *target, struct esp_common 
*esp_common)
+{
+       int ret;
+
+       enum target_state old_state = target->state;
+       if (target->state != TARGET_HALTED) {
+               ret = target_halt(target);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR(
+                               "%s: Failed to halt target to remove flash BPs 
(%d)!",
+                               target_name(target),
+                               ret);
+                       return ret;
+               }
+               ret = target_wait_state(target, TARGET_HALTED, 3000);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR(
+                               "%s: Failed to wait halted target to remove 
flash BPs (%d)!",
+                               target_name(target),
+                               ret);
+                       return ret;
+               }
+       }
+
+       if (old_state == TARGET_RUNNING) {
+               ret = target_resume(target, 1, 0, 1, 0);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR(
+                               "%s: Failed to resume target after flash BPs 
removal (%d)!",
+                               target_name(target),
+                               ret);
+                       return ret;
+               }
+       }
+       return ERROR_OK;
+}
diff --git a/src/target/esp.h b/src/target/esp.h
new file mode 100644
index 0000000000..9652691519
--- /dev/null
+++ b/src/target/esp.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ *   ESP common definitions for OpenOCD                                    *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef _ESP_H
+#define _ESP_H
+
+#include <stdint.h>
+
+/* must be in sync with ESP-IDF version */
+/** Size of the pre-compiled target buffer for stub trampoline.
+ * @note Must be in sync with ESP-IDF version */
+#define ESP_DBG_STUBS_CODE_BUF_SIZE         32 /* TODO: move this info to 
esp_dbg_stubs_desc */
+/** Size of the pre-compiled target buffer for stack.
+ * @note Must be in sync with ESP-IDF version */
+#define ESP_DBG_STUBS_STACK_MIN_SIZE        2048/* TODO: move this info to 
esp_dbg_stubs_desc */
+
+/**
+ * Debug stubs table entries IDs
+ *
+ * @note Must be in sync with ESP-IDF version
+ */
+enum esp_dbg_stub_id {
+       ESP_DBG_STUB_ENTRY_MAGIC_NUM,
+       ESP_DBG_STUB_TABLE_SIZE,
+       ESP_DBG_STUB_TABLE_START,
+       ESP_DBG_STUB_DESC = ESP_DBG_STUB_TABLE_START,   /*< Stubs descriptor ID 
*/
+       ESP_DBG_STUB_ENTRY_FIRST,
+       ESP_DBG_STUB_ENTRY_GCOV = ESP_DBG_STUB_ENTRY_FIRST,     /*< GCOV stub 
ID */
+       ESP_DBG_STUB_CAPABILITIES,
+       /* add new stub entries here */
+       ESP_DBG_STUB_ENTRY_MAX,
+};
+
+#define ESP_DBG_STUB_MAGIC_NUM_VAL      0xFEEDBEEF
+#define ESP_DBG_STUB_CAP_GCOV_THREAD    (1 << 0)
+
+/**
+ * Debug stubs descriptor. ID: ESP_DBG_STUB_DESC
+ *
+ * @note Must be in sync with ESP-IDF version
+ */
+struct esp_dbg_stubs_desc {
+       /** Address of pre-compiled target buffer for stub trampoline. Size of 
the buffer is
+        * ESP_DBG_STUBS_CODE_BUF_SIZE. */
+       uint32_t tramp_addr;
+       /** Pre-compiled target buffer's addr for stack. The size of the buffer 
is ESP_DBG_STUBS_STACK_MIN_SIZE.
+           Target has the buffer which is used for the stack of onboard 
algorithms.
+       If stack size required by algorithm exceeds 
ESP_DBG_STUBS_STACK_MIN_SIZE,
+       it should be allocated using onboard function pointed by 'data_alloc' 
and
+       freed by 'data_free'. They fit to the minimal stack. See below. */
+       uint32_t min_stack_addr;
+       /** Address of malloc-like function to allocate buffer on target. */
+       uint32_t data_alloc;
+       /** Address of free-like function to free buffer allocated with 
data_alloc. */
+       uint32_t data_free;
+};
+
+/**
+ * Debug stubs info.
+ */
+struct esp_dbg_stubs {
+       /** Address. */
+       uint32_t base;
+       /** Table contents. */
+       uint32_t entries[ESP_DBG_STUB_ENTRY_MAX];
+       /** Number of table entries. */
+       uint32_t entries_count;
+       /** Debug stubs decsriptor. */
+       struct esp_dbg_stubs_desc desc;
+};
+
+/**
+ * Semihost calls handling operations.
+ */
+struct esp_semihost_ops {
+       /** Callback called before handling semihost call */
+       int (*prepare)(struct target *target);
+};
+
+struct esp_semihost_data {
+       uint32_t version;               /* sending with drvinfo syscall */
+       bool need_resume;
+       struct esp_semihost_ops *ops;
+};
+
+struct esp_common {
+       struct esp_dbg_stubs dbg_stubs;
+};
+
+int esp_common_init(struct esp_common *esp);
+int esp_common_flash_breakpoint_add(struct target *target,
+       struct esp_common *esp,
+       struct breakpoint *breakpoint);
+int esp_common_flash_breakpoint_remove(struct target *target,
+       struct esp_common *esp,
+       struct breakpoint *breakpoint);
+bool esp_common_flash_breakpoint_exists(struct esp_common *esp,
+       struct breakpoint *breakpoint);
+int esp_common_handle_gdb_detach(struct target *target, struct esp_common 
*esp_common);
+
+int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs 
*dbg_stubs);
+
+#endif /* _ESP_H */
diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c
new file mode 100644
index 0000000000..c837c9efaf
--- /dev/null
+++ b/src/target/esp32c3.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+ *   ESP32-C3 target for OpenOCD                                           *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "esp32c3.h"
+#include <helper/command.h>
+#include <helper/bits.h>
+#include "target_type.h"
+#include "register.h"
+#include "semihosting_common.h"
+#include "esp_semihosting.h"
+#include "riscv/debug_defines.h"
+#include "rtos/rtos.h"
+
+/* ESP32-C3 WDT */
+#define ESP32C3_WDT_WKEY_VALUE       0x50d83aa1
+#define ESP32C3_TIMG0_BASE           0x6001F000
+#define ESP32C3_TIMG1_BASE           0x60020000
+#define ESP32C3_TIMGWDT_CFG0_OFF     0x48
+#define ESP32C3_TIMGWDT_PROTECT_OFF  0x64
+#define ESP32C3_TIMG0WDT_CFG0        (ESP32C3_TIMG0_BASE + 
ESP32C3_TIMGWDT_CFG0_OFF)
+#define ESP32C3_TIMG1WDT_CFG0        (ESP32C3_TIMG1_BASE + 
ESP32C3_TIMGWDT_CFG0_OFF)
+#define ESP32C3_TIMG0WDT_PROTECT     (ESP32C3_TIMG0_BASE + 
ESP32C3_TIMGWDT_PROTECT_OFF)
+#define ESP32C3_TIMG1WDT_PROTECT     (ESP32C3_TIMG1_BASE + 
ESP32C3_TIMGWDT_PROTECT_OFF)
+#define ESP32C3_RTCCNTL_BASE         0x60008000
+#define ESP32C3_RTCWDT_CFG_OFF       0x90
+#define ESP32C3_RTCWDT_PROTECT_OFF   0xa8
+#define ESP32C3_RTCWDT_CFG           (ESP32C3_RTCCNTL_BASE + 
ESP32C3_RTCWDT_CFG_OFF)
+#define ESP32C3_RTCWDT_PROTECT       (ESP32C3_RTCCNTL_BASE + 
ESP32C3_RTCWDT_PROTECT_OFF)
+
+#define ESP32C3_GPIO_STRAP_REG      0x60004038UL
+#define IS_1XXX(v)                  (((v)&0x08) == 0x08)
+#define ESP32C3_IS_FLASH_BOOT(_r_)  IS_1XXX(_r_)
+#define ESP32C3_FLASH_BOOT_MODE     0x08
+
+extern struct target_type riscv_target;
+extern const struct command_registration riscv_command_handlers[];
+
+static int esp32c3_on_reset(struct target *target);
+
+
+static int esp32c3_wdt_disable(struct target *target)
+{
+       /* TIMG1 WDT */
+       int res = target_write_u32(target, ESP32C3_TIMG0WDT_PROTECT, 
ESP32C3_WDT_WKEY_VALUE);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_TIMG0WDT_PROTECT (%d)!", 
res);
+               return res;
+       }
+       res = target_write_u32(target, ESP32C3_TIMG0WDT_CFG0, 0);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_TIMG0WDT_CFG0 (%d)!", res);
+               return res;
+       }
+       /* TIMG2 WDT */
+       res = target_write_u32(target, ESP32C3_TIMG1WDT_PROTECT, 
ESP32C3_WDT_WKEY_VALUE);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_TIMG1WDT_PROTECT (%d)!", 
res);
+               return res;
+       }
+       res = target_write_u32(target, ESP32C3_TIMG1WDT_CFG0, 0);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_TIMG1WDT_CFG0 (%d)!", res);
+               return res;
+       }
+       /* RTC WDT */
+       res = target_write_u32(target, ESP32C3_RTCWDT_PROTECT, 
ESP32C3_WDT_WKEY_VALUE);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_RTCWDT_PROTECT (%d)!", res);
+               return res;
+       }
+       res = target_write_u32(target, ESP32C3_RTCWDT_CFG, 0);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to write ESP32C3_RTCWDT_CFG (%d)!", res);
+               return res;
+       }
+       return ERROR_OK;
+}
+
+static const struct esp_semihost_ops esp32c3_semihost_ops = {
+       .prepare = esp32c3_wdt_disable
+};
+
+static int esp32c3_handle_target_event(struct target *target, enum 
target_event event, void *priv)
+{
+       if (target != priv)
+               return ERROR_OK;
+
+       LOG_DEBUG("%d", event);
+
+       int ret = esp_riscv_handle_target_event(target, event, priv);
+       if (ret != ERROR_OK)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static int esp32c3_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct esp32c3_common *esp32c3 = calloc(1, sizeof(struct 
esp32c3_common));
+       if (!esp32c3)
+               return ERROR_FAIL;
+
+       target->arch_info = esp32c3;
+
+       riscv_info_init(target, &esp32c3->esp_riscv.riscv);
+
+       return ERROR_OK;
+}
+
+static int esp32c3_init_target(struct command_context *cmd_ctx,
+       struct target *target)
+{
+       int ret = riscv_target.init_target(cmd_ctx, target);
+       if (ret != ERROR_OK)
+               return ret;
+
+       struct esp32c3_common *esp32c3 = esp32c3_common(target);
+
+       ret = esp_riscv_init_arch_info(cmd_ctx,
+               target,
+               &esp32c3->esp_riscv,
+               esp32c3_on_reset,
+               &esp32c3_semihost_ops);
+       if (ret != ERROR_OK)
+               return ret;
+
+       ret = target_register_event_callback(esp32c3_handle_target_event, 
target);
+       if (ret != ERROR_OK)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static void esp32c3_deinit_target(struct target *target)
+{
+       riscv_target.deinit_target(target);
+}
+
+static const char *const s_nonexistent_regs[] = {
+       "mie", "mip", "tdata3", "uie", "utvt", "utvec", "vcsr", "uscratch", 
"utval",
+       "uip", "unxti", "uintstatus", "uscratchcsw", "uscratchcswl", "sedeleg",
+       "sideleg", "stvt", "snxti", "sintstatus", "sscratchcsw", "sscratchcswl",
+       "vsstatus", "vsie", "vstvec", "vsscratch", "vsepc", "vscause", "vstval",
+       "vsip", "vsatp", "mtvt", "mstatush", "mcountinhibit", "mnxti", 
"mintstatus",
+       "mscratchcsw", "mscratchcswl", "mtinst", "mtval2", "hstatus", "hedeleg",
+       "hideleg", "hie", "htimedelta", "hcounteren", "hgeie", "htimedeltah",
+       "htval", "hip", "hvip", "htinst", "hgatp", "hgeip", "mvendorid", 
"marchid",
+       "mimpid", "mhartid", "seed", "mcounteren", "mhpmevent3", "mhpmevent4", 
"mhpmevent5",
+       "mhpmevent6", "mhpmevent7", "mhpmevent8", "mhpmevent9", "mhpmevent10", 
"mhpmevent11",
+       "mhpmevent12", "mhpmevent13", "mhpmevent14", "mhpmevent15", 
"mhpmevent16", "mhpmevent17",
+       "mhpmevent18", "mhpmevent19", "mhpmevent20", "mhpmevent21", 
"mhpmevent22", "mhpmevent23",
+       "mhpmevent24", "mhpmevent25", "mhpmevent26", "mhpmevent27", 
"mhpmevent28", "mhpmevent29",
+       "mhpmevent30", "mhpmevent31",
+       "scontext", "hcontext", "tinfo", "mcontext", "mscontext", "mcycle", 
"minstret",
+       "mhpmcounter3", "mhpmcounter4", "mhpmcounter5", "mhpmcounter6", 
"mhpmcounter7",
+       "mhpmcounter8", "mhpmcounter9", "mhpmcounter10", "mhpmcounter11", 
"mhpmcounter12",
+       "mhpmcounter13", "mhpmcounter14", "mhpmcounter15", "mhpmcounter16", 
"mhpmcounter17",
+       "mhpmcounter18", "mhpmcounter19", "mhpmcounter20", "mhpmcounter21", 
"mhpmcounter22",
+       "mhpmcounter23", "mhpmcounter24", "mhpmcounter25", "mhpmcounter26", 
"mhpmcounter27",
+       "mhpmcounter28", "mhpmcounter29", "mhpmcounter30", "mhpmcounter31", 
"mcycleh",
+       "minstreth", "mhpmcounter3h", "mhpmcounter4h", "mhpmcounter5h", 
"mhpmcounter6h",
+       "mhpmcounter7h", "mhpmcounter8h", "mhpmcounter9h", "mhpmcounter10h", 
"mhpmcounter11h",
+       "mhpmcounter12h", "mhpmcounter13h", "mhpmcounter14h", "mhpmcounter15h", 
"mhpmcounter16h",
+       "mhpmcounter17h", "mhpmcounter18h", "mhpmcounter19h", "mhpmcounter20h", 
"mhpmcounter21h",
+       "mhpmcounter22h", "mhpmcounter23h", "mhpmcounter24h", "mhpmcounter25h", 
"mhpmcounter26h",
+       "mhpmcounter27h", "mhpmcounter28h", "mhpmcounter29h", "mhpmcounter30h", 
"mhpmcounter31h",
+       "cycle", "time", "instret", "hpmcounter3", "hpmcounter4", 
"hpmcounter5", "hpmcounter6",
+       "hpmcounter7", "hpmcounter8", "hpmcounter9", "hpmcounter10", 
"hpmcounter11", "hpmcounter12",
+       "hpmcounter13", "hpmcounter14", "hpmcounter15", "hpmcounter17", 
"hpmcounter18",
+       "hpmcounter19",
+       "hpmcounter20", "hpmcounter21", "hpmcounter22", "hpmcounter23", 
"hpmcounter24",
+       "hpmcounter25",
+       "hpmcounter26", "hpmcounter27", "hpmcounter28", "hpmcounter29", 
"hpmcounter30",
+       "hpmcounter31",
+       "cycleh", "timeh", "instreth", "hpmcounter3h", "hpmcounter4h", 
"hpmcounter5h",
+       "hpmcounter6h",
+       "hpmcounter7h", "hpmcounter8h", "hpmcounter9h", "hpmcounter10h", 
"hpmcounter11h",
+       "hpmcounter12h",
+       "hpmcounter13h", "hpmcounter14h", "hpmcounter15h", "hpmcounter17h", 
"hpmcounter18h",
+       "hpmcounter19h",
+       "hpmcounter20h", "hpmcounter21h", "hpmcounter22h", "hpmcounter23h", 
"hpmcounter24h",
+       "hpmcounter25h",
+       "hpmcounter26h", "hpmcounter27h", "hpmcounter28h", "hpmcounter29h", 
"hpmcounter30h",
+       "hpmcounter31h",
+       "hpmcounter16h", "mhpmevent4"
+};
+
+static int esp32c3_examine(struct target *target)
+{
+       int ret = riscv_target.examine(target);
+       if (ret != ERROR_OK)
+               return ret;
+       /* RISCV code initializes registers upon target examination.
+          disable some registers because their reading or writing causes 
exception. Not supported in ESP32-C3??? */
+       for (size_t i = 0; i < 
sizeof(s_nonexistent_regs)/sizeof(s_nonexistent_regs[0]); i++) {
+               struct reg *r = register_get_by_name(target->reg_cache, 
s_nonexistent_regs[i], 1);
+               if (r)
+                       r->exist = false;
+       }
+       return ERROR_OK;
+}
+
+static int esp32c3_on_reset(struct target *target)
+{
+       LOG_DEBUG("esp32c3_on_reset!");
+       struct esp32c3_common *esp32c3 = esp32c3_common(target);
+       esp32c3->was_reset = true;
+       return ERROR_OK;
+}
+
+static int esp32c3_poll(struct target *target)
+{
+       struct esp32c3_common *esp32c3 = esp32c3_common(target);
+       int res = ERROR_OK;
+
+       RISCV_INFO(r);
+       if (esp32c3->was_reset && r->dmi_read && r->dmi_write) {
+               uint32_t dmstatus;
+               res = r->dmi_read(target, &dmstatus, DM_DMSTATUS);
+               if (res != ERROR_OK)
+                       LOG_ERROR("Failed to read DMSTATUS (%d)!", res);
+               else {
+                       uint32_t strap_reg;
+                       LOG_DEBUG("Core is out of reset: dmstatus 0x%x", 
dmstatus);
+                       esp32c3->was_reset = false;
+                       res = target_read_u32(target, ESP32C3_GPIO_STRAP_REG, 
&strap_reg);
+                       if (res != ERROR_OK) {
+                               LOG_WARNING("Failed to read 
ESP32C3_GPIO_STRAP_REG (%d)!", res);
+                               strap_reg = ESP32C3_FLASH_BOOT_MODE;
+                       }
+                       if (ESP32C3_IS_FLASH_BOOT(strap_reg) &&
+                               get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 
0) {
+                               LOG_DEBUG("Halt core");
+                               res = esp_riscv_core_halt(target);
+                               if (res == ERROR_OK) {
+                                       res = esp32c3_wdt_disable(target);
+                                       if (res != ERROR_OK)
+                                               LOG_ERROR("Failed to disable 
WDTs (%d)!", res);
+                               } else
+                                       LOG_ERROR("Failed to halt core (%d)!", 
res);
+                       }
+                       if (ESP32C3_IS_FLASH_BOOT(strap_reg)) {
+                               /* enable ebreaks */
+                               res = esp_riscv_core_ebreaks_enable(target);
+                               if (res != ERROR_OK)
+                                       LOG_ERROR("Failed to enable EBREAKS 
handling (%d)!", res);
+                               if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) 
== 0) {
+                                       LOG_DEBUG("Resume core");
+                                       res = esp_riscv_core_resume(target);
+                                       if (res != ERROR_OK)
+                                               LOG_ERROR("Failed to resume 
core (%d)!", res);
+                                       LOG_DEBUG("resumed core");
+                               }
+                       }
+               }
+       }
+       return esp_riscv_poll(target);
+}
+
+static const struct command_registration esp32c3_command_handlers[] = {
+       {
+               .usage = "",
+               .chain = riscv_command_handlers,
+       },
+       {
+               .name = "esp",
+               .usage = "",
+               .chain = esp_riscv_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct target_type esp32c3_target = {
+       .name = "esp32c3",
+
+       .target_create = esp32c3_target_create,
+       .init_target = esp32c3_init_target,
+       .deinit_target = esp32c3_deinit_target,
+       .examine = esp32c3_examine,
+
+       /* poll current target status */
+       .poll = esp32c3_poll,
+
+       .halt = esp_riscv_halt,
+       .resume = esp_riscv_resume,
+       .step = esp_riscv_step,
+
+       .assert_reset = esp_riscv_assert_reset,
+       .deassert_reset = esp_riscv_deassert_reset,
+
+       .read_memory = esp_riscv_read_memory,
+       .write_memory = esp_riscv_write_memory,
+
+       .checksum_memory = esp_riscv_checksum_memory,
+
+       .get_gdb_arch = esp_riscv_get_gdb_arch,
+       .get_gdb_reg_list = esp_riscv_get_gdb_reg_list,
+       .get_gdb_reg_list_noread = esp_riscv_get_gdb_reg_list_noread,
+
+       .add_breakpoint = esp_riscv_breakpoint_add,
+       .remove_breakpoint = esp_riscv_breakpoint_remove,
+
+       .add_watchpoint = esp_riscv_add_watchpoint,
+       .remove_watchpoint = esp_riscv_remove_watchpoint,
+       .hit_watchpoint = esp_riscv_hit_watchpoint,
+
+       .arch_state = esp_riscv_arch_state,
+
+       .commands = esp32c3_command_handlers,
+
+       .address_bits = esp_riscv_address_bits,
+};
diff --git a/src/target/esp32c3.h b/src/target/esp32c3.h
new file mode 100644
index 0000000000..ec9b7c7c5f
--- /dev/null
+++ b/src/target/esp32c3.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *   ESP32-C3 target for OpenOCD                                           *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef _ESP32C3_H
+#define _ESP32C3_H
+
+#include "esp_riscv.h"
+
+#define ESP32C3_DROM_LOW    0x3C000000
+#define ESP32C3_DROM_HIGH   0x3C800000
+#define ESP32C3_IROM_LOW    0x42000000
+#define ESP32C3_IROM_HIGH   0x42800000
+
+struct esp32c3_common {
+       struct esp_riscv_common esp_riscv;
+       bool was_reset;
+};
+
+static inline struct  esp32c3_common *esp32c3_common(const struct target 
*target)
+{
+       return target->arch_info;
+}
+
+#endif /* _ESP32C3_H */
diff --git a/src/target/esp_riscv.c b/src/target/esp_riscv.c
new file mode 100644
index 0000000000..395f01f57d
--- /dev/null
+++ b/src/target/esp_riscv.c
@@ -0,0 +1,439 @@
+/***************************************************************************
+ *   Espressif RISCV target API for OpenOCD                                *
+ *   Copyright (C) 2021 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "breakpoints.h"
+#include "smp.h"
+#include "semihosting_common.h"
+#include "esp_riscv.h"
+#include "target_type.h"
+#include "esp_semihosting.h"
+
+/* Argument indexes for ESP_SEMIHOSTING_SYS_BREAKPOINT_SET */
+enum {
+       ESP_RISCV_SET_BREAKPOINT_ARG_SET,
+       ESP_RISCV_SET_BREAKPOINT_ARG_ID,
+       ESP_RISCV_SET_BREAKPOINT_ARG_ADDR,      /* missed if `set` is false */
+       ESP_RISCV_SET_BREAKPOINT_ARG_MAX
+};
+
+/* Argument indexes for ESP_SEMIHOSTING_SYS_WATCHPOINT_SET */
+enum {
+       ESP_RISCV_SET_WATCHPOINT_ARG_SET,
+       ESP_RISCV_SET_WATCHPOINT_ARG_ID,
+       ESP_RISCV_SET_WATCHPOINT_ARG_ADDR,      /* missed if `set` is false */
+       ESP_RISCV_SET_WATCHPOINT_ARG_SIZE,      /* missed if `set` is false */
+       ESP_RISCV_SET_WATCHPOINT_ARG_FLAGS,     /* missed if `set` is false */
+       ESP_RISCV_SET_WATCHPOINT_ARG_MAX
+};
+
+#define ESP_SEMIHOSTING_WP_FLG_RD   (1UL << 0)
+#define ESP_SEMIHOSTING_WP_FLG_WR   (1UL << 1)
+
+#define ESP_RISCV_DBGSTUBS_UPDATE_DATA_ENTRY(_e_) \
+       do { \
+               (_e_) = buf_get_u32((uint8_t *)&(_e_), 0, 32); \
+               if ((_e_) == 0) { \
+                       LOG_WARNING("No valid stub data entry found (0x%x)!", 
(uint32_t)(_e_)); \
+               } \
+       } while (0)
+
+#define ESP_RISCV_DBGSTUBS_UPDATE_CODE_ENTRY(_e_) \
+       do { \
+               (_e_) = buf_get_u32((uint8_t *)&(_e_), 0, 32); \
+               if ((_e_) == 0) { \
+                       LOG_WARNING("No valid stub code entry found (0x%x)!", 
(uint32_t)(_e_)); \
+               } \
+       } while (0)
+
+extern struct target_type riscv_target;
+static int esp_riscv_debug_stubs_info_init(struct target *target,
+       target_addr_t ctrl_addr);
+
+
+int esp_riscv_semihosting(struct target *target)
+{
+       int res = ERROR_OK;
+       struct esp_riscv_common *esp_riscv = target_to_esp_riscv(target);
+       struct semihosting *semihosting = target->semihosting;
+
+       LOG_DEBUG("op:(%x) param: (%" PRIx64 ")", semihosting->op, 
semihosting->param);
+
+       if (esp_riscv->semi_ops && esp_riscv->semi_ops->prepare)
+               esp_riscv->semi_ops->prepare(target);
+
+       switch (semihosting->op) {
+               case ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT:
+                       res = esp_riscv_debug_stubs_info_init(target, 
semihosting->param);
+                       if (res != ERROR_OK)
+                               return res;
+                       break;
+               default:
+                       return ERROR_FAIL;
+       }
+
+       semihosting->result = res == ERROR_OK ? 0 : -1;
+       semihosting->is_resumable = true;
+
+       return res;
+}
+
+static int esp_riscv_debug_stubs_info_init(struct target *target,
+       target_addr_t vec_addr)
+{
+       struct esp_riscv_common *esp_riscv = target_to_esp_riscv(target);
+
+       LOG_INFO("%s: Detected debug stubs @ " TARGET_ADDR_FMT, 
target_name(target), vec_addr);
+
+       memset(&esp_riscv->esp.dbg_stubs, 0, sizeof(esp_riscv->esp.dbg_stubs));
+
+       esp_riscv->esp.dbg_stubs.base = vec_addr;
+       int res = esp_dbgstubs_table_read(target, &esp_riscv->esp.dbg_stubs);
+       if (res != ERROR_OK)
+               return res;
+       if (esp_riscv->esp.dbg_stubs.entries_count == 0)
+               return ERROR_OK;
+
+       /* read debug stubs descriptor */
+       
ESP_RISCV_DBGSTUBS_UPDATE_DATA_ENTRY(esp_riscv->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC]);
+       res =
+               target_read_buffer(target, 
esp_riscv->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC],
+               sizeof(struct esp_dbg_stubs_desc),
+               (uint8_t *)&esp_riscv->esp.dbg_stubs.desc);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to read debug stubs descriptor (%d)!", res);
+               return res;
+       }
+       
ESP_RISCV_DBGSTUBS_UPDATE_CODE_ENTRY(esp_riscv->esp.dbg_stubs.desc.tramp_addr);
+       
ESP_RISCV_DBGSTUBS_UPDATE_DATA_ENTRY(esp_riscv->esp.dbg_stubs.desc.min_stack_addr);
+       
ESP_RISCV_DBGSTUBS_UPDATE_CODE_ENTRY(esp_riscv->esp.dbg_stubs.desc.data_alloc);
+       
ESP_RISCV_DBGSTUBS_UPDATE_CODE_ENTRY(esp_riscv->esp.dbg_stubs.desc.data_free);
+
+       return ERROR_OK;
+}
+
+int esp_riscv_breakpoint_add(struct target *target, struct breakpoint 
*breakpoint)
+{
+       struct esp_riscv_common *esp_riscv;
+
+       int res = riscv_add_breakpoint(target, breakpoint);
+       if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE && breakpoint->type == 
BKPT_HARD) {
+               /* For SMP target return OK if SW flash breakpoint is already 
set using another
+                *core; GDB causes call to esp_flash_breakpoint_add() for every 
core, since it
+                *treats flash breakpoints as HW ones */
+               if (target->smp) {
+                       struct target_list *curr;
+                       foreach_smp_target(curr, target->smp_targets) {
+                               esp_riscv = target_to_esp_riscv(curr->target);
+                               if 
(esp_common_flash_breakpoint_exists(&esp_riscv->esp, breakpoint))
+                                       return ERROR_OK;
+                       }
+               }
+               esp_riscv = target_to_esp_riscv(target);
+               return esp_common_flash_breakpoint_add(target, &esp_riscv->esp, 
breakpoint);
+       }
+       return res;
+}
+
+int esp_riscv_breakpoint_remove(struct target *target, struct breakpoint 
*breakpoint)
+{
+       struct esp_riscv_common *esp_riscv = target_to_esp_riscv(target);
+
+       int res = riscv_remove_breakpoint(target, breakpoint);
+       if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE && breakpoint->type == 
BKPT_HARD) {
+               res = esp_common_flash_breakpoint_remove(target, 
&esp_riscv->esp, breakpoint);
+               if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE && target->smp) {
+                       /* For SMP target return OK always, because SW flash 
breakpoint are set only
+                        *using one core, but GDB causes call to 
esp_flash_breakpoint_remove() for
+                        *every core, since it treats flash breakpoints as HW 
ones */
+                       return ERROR_OK;
+               }
+       }
+
+       return res;
+}
+
+int esp_riscv_handle_target_event(struct target *target, enum target_event 
event,
+       void *priv)
+{
+       int ret;
+
+       if (target != priv)
+               return ERROR_OK;
+
+       LOG_DEBUG("%d", event);
+
+       switch (event) {
+               case TARGET_EVENT_GDB_DETACH:
+               {
+                       struct esp_riscv_common *esp_riscv = 
target_to_esp_riscv(target);
+                       ret = esp_common_handle_gdb_detach(target, 
&esp_riscv->esp);
+                       if (ret != ERROR_OK)
+                               return ret;
+                       break;
+               }
+               default:
+                       break;
+       }
+       return ERROR_OK;
+}
+
+int esp_riscv_read_memory(struct target *target, target_addr_t address,
+       uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       /* TODO: find out the widest system bus access size. For now we are 
assuming it is equal to
+        *xlen */
+       uint32_t sba_access_size = target_data_bits(target) / 8;
+
+       if (size < sba_access_size) {
+               LOG_DEBUG("Use %d-bit access: size: %d\tcount:%d\tstart 
address: 0x%08"
+                       TARGET_PRIxADDR, sba_access_size * 8, size, count, 
address);
+               target_addr_t al_addr = address & ~(sba_access_size - 1);
+               uint32_t al_len = (size * count) + address - al_addr;
+               uint32_t al_cnt = (al_len + sba_access_size - 1) & 
~(sba_access_size - 1);
+               uint8_t al_buf[al_cnt];
+               int ret = riscv_target.read_memory(target,
+                       al_addr,
+                       sba_access_size,
+                       al_cnt / sba_access_size,
+                       al_buf);
+               if (ret == ERROR_OK)
+                       memcpy(buffer, &al_buf[address & (sba_access_size - 
1)], size * count);
+               return ret;
+       }
+
+       return riscv_target.read_memory(target, address, size, count, buffer);
+}
+
+int esp_riscv_write_memory(struct target *target, target_addr_t address,
+       uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       /* TODO: find out the widest system bus access size. For now we are 
assuming it is equal to
+        *xlen */
+       uint32_t sba_access_size = target_data_bits(target) / 8;
+
+       if (target->state == TARGET_RUNNING || target->state == 
TARGET_DEBUG_RUNNING) {
+               /* Emulate using 32-bit SBA access if target is running.
+                  Access via prog_buf or abstartct commands does not work in 
running state and
+                  fails with abstractcs.cmderr == 4 (halt/resume) */
+               if (size < sba_access_size) {
+                       LOG_DEBUG("Use %d-bit access: size: %d\tcount:%d\tstart 
address: 0x%08"
+                               TARGET_PRIxADDR, sba_access_size * 8, size, 
count, address);
+                       target_addr_t al_addr = address & ~(sba_access_size - 
1);
+                       uint32_t al_len = (size * count) + address - al_addr;
+                       uint32_t al_cnt = (al_len + sba_access_size - 1) & 
~(sba_access_size - 1);
+                       uint8_t al_buf[al_cnt];
+                       int ret = riscv_target.read_memory(target,
+                               al_addr,
+                               sba_access_size,
+                               al_cnt / sba_access_size,
+                               al_buf);
+                       if (ret == ERROR_OK) {
+                               memcpy(&al_buf[address & (sba_access_size - 1)],
+                                       buffer,
+                                       size * count);
+                               ret = riscv_target.write_memory(target,
+                                       address,
+                                       sba_access_size,
+                                       al_cnt / sba_access_size,
+                                       al_buf);
+                       }
+                       return ret;
+               }
+       }
+       return riscv_target.write_memory(target, address, size, count, buffer);
+}
+
+int esp_riscv_poll(struct target *target)
+{
+       return riscv_target.poll(target);
+}
+
+int esp_riscv_halt(struct target *target)
+{
+       return riscv_target.halt(target);
+}
+
+int esp_riscv_resume(struct target *target, int current, target_addr_t address,
+       int handle_breakpoints, int debug_execution)
+{
+       return riscv_target.resume(target, current, address, 
handle_breakpoints, debug_execution);
+}
+
+int esp_riscv_step(
+       struct target *target,
+       int current,
+       target_addr_t address,
+       int handle_breakpoints)
+{
+       return riscv_target.step(target, current, address, handle_breakpoints);
+}
+
+int esp_riscv_assert_reset(struct target *target)
+{
+       return riscv_target.assert_reset(target);
+}
+
+int esp_riscv_deassert_reset(struct target *target)
+{
+       return riscv_target.deassert_reset(target);
+}
+
+int esp_riscv_checksum_memory(struct target *target,
+       target_addr_t address, uint32_t count,
+       uint32_t *checksum)
+{
+       return riscv_target.checksum_memory(target, address, count, checksum);
+}
+
+int esp_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_target.get_gdb_reg_list_noread(target, reg_list, 
reg_list_size, reg_class);
+}
+
+int esp_riscv_get_gdb_reg_list(struct target *target,
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class)
+{
+       return riscv_target.get_gdb_reg_list(target, reg_list, reg_list_size, 
reg_class);
+}
+
+const char *esp_riscv_get_gdb_arch(struct target *target)
+{
+       return riscv_target.get_gdb_arch(target);
+}
+
+int esp_riscv_arch_state(struct target *target)
+{
+       return riscv_target.arch_state(target);
+}
+
+int esp_riscv_add_watchpoint(struct target *target, struct watchpoint 
*watchpoint)
+{
+       return riscv_target.add_watchpoint(target, watchpoint);
+}
+
+int esp_riscv_remove_watchpoint(struct target *target,
+       struct watchpoint *watchpoint)
+{
+       return riscv_target.remove_watchpoint(target, watchpoint);
+}
+
+int esp_riscv_hit_watchpoint(struct target *target, struct watchpoint 
**hit_watchpoint)
+{
+       return riscv_target.hit_watchpoint(target, hit_watchpoint);
+}
+
+unsigned esp_riscv_address_bits(struct target *target)
+{
+       return riscv_target.address_bits(target);
+}
+
+bool esp_riscv_core_is_halted(struct target *target)
+{
+       uint32_t dmstatus;
+       RISCV_INFO(r);
+       if (r->dmi_read(target, &dmstatus, DM_DMSTATUS) != ERROR_OK)
+               return false;
+       return get_field(dmstatus, DM_DMSTATUS_ALLHALTED);
+}
+
+int esp_riscv_core_halt(struct target *target)
+{
+       RISCV_INFO(r);
+
+       /* Issue the halt command, and then wait for the current hart to halt. 
*/
+       uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
+       r->dmi_write(target, DM_DMCONTROL, dmcontrol);
+       for (size_t i = 0; i < 256; ++i)
+               if (esp_riscv_core_is_halted(target))
+                       break;
+
+       if (!esp_riscv_core_is_halted(target)) {
+               uint32_t dmstatus;
+               if (r->dmi_read(target, &dmstatus, DM_DMSTATUS) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (r->dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               LOG_ERROR("unable to halt core");
+               LOG_ERROR("  dmcontrol=0x%08x", dmcontrol);
+               LOG_ERROR("  dmstatus =0x%08x", dmstatus);
+               return ERROR_FAIL;
+       }
+
+       dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
+       r->dmi_write(target, DM_DMCONTROL, dmcontrol);
+       return ERROR_OK;
+}
+
+int esp_riscv_core_resume(struct target *target)
+{
+       RISCV_INFO(r);
+
+       /* Issue the resume command, and then wait for the current hart to 
resume. */
+       uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
+       r->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;
+       for (size_t i = 0; i < 256; ++i) {
+               usleep(10);
+               int res = r->dmi_read(target, &dmstatus, DM_DMSTATUS);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("Failed to read dmstatus!");
+                       return res;
+               }
+               if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0)
+                       continue;
+               res = r->dmi_write(target, DM_DMCONTROL, dmcontrol);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("Failed to write dmcontrol!");
+                       return res;
+               }
+               return ERROR_OK;
+       }
+
+       r->dmi_write(target, DM_DMCONTROL, dmcontrol);
+
+       LOG_ERROR("unable to resume core");
+       if (r->dmi_read(target, &dmstatus, DM_DMSTATUS) != ERROR_OK)
+               return ERROR_FAIL;
+       LOG_ERROR("  dmstatus =0x%08x", dmstatus);
+
+       return ERROR_FAIL;
+}
+
+int esp_riscv_core_ebreaks_enable(struct target *target)
+{
+       riscv_reg_t dcsr;
+       RISCV_INFO(r);
+       int result = r->get_register(target, &dcsr, GDB_REGNO_DCSR);
+       if (result != ERROR_OK)
+               return result;
+       LOG_DEBUG("DCSR: %" PRIx64, dcsr);
+       dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1);
+       dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1);
+       dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1);
+       return r->set_register(target, GDB_REGNO_DCSR, dcsr);
+}
diff --git a/src/target/esp_riscv.h b/src/target/esp_riscv.h
new file mode 100644
index 0000000000..15d7cf9756
--- /dev/null
+++ b/src/target/esp_riscv.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ *   ESP RISCV common definitions for OpenOCD                              *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef _ESP_RISCV_H
+#define _ESP_RISCV_H
+
+#include "target.h"
+#include "riscv/riscv.h"
+#include "riscv/debug_defines.h"
+#include "esp.h"
+
+#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & 
~((mask) << 1))) & (mask)))
+#define ESP_RISCV_TARGET_BP_NUM         8
+#define ESP_RISCV_TARGET_WP_NUM         8
+
+struct esp_riscv_common {
+       /* should be first, will be accessed by riscv generic code */
+       riscv_info_t riscv;
+       struct esp_common esp;
+       struct esp_semihost_data semihost;
+       struct esp_semihost_ops *semi_ops;
+       target_addr_t target_bp_addr[ESP_RISCV_TARGET_BP_NUM];
+       target_addr_t target_wp_addr[ESP_RISCV_TARGET_WP_NUM];
+};
+
+static inline struct esp_riscv_common *target_to_esp_riscv(const struct target 
*target)
+{
+       return target->arch_info;
+}
+
+static inline int esp_riscv_init_arch_info(struct command_context *cmd_ctx, 
struct target *target,
+       struct esp_riscv_common *esp_riscv, int (*on_reset)(struct target *),
+       const struct esp_semihost_ops *semi_ops)
+{
+       int ret = esp_common_init(&esp_riscv->esp);
+       if (ret != ERROR_OK)
+               return ret;
+
+       esp_riscv->semi_ops = (struct esp_semihost_ops *)semi_ops;
+
+       return ERROR_OK;
+}
+
+int esp_riscv_semihosting(struct target *target);
+int esp_riscv_breakpoint_add(struct target *target, struct breakpoint 
*breakpoint);
+int esp_riscv_breakpoint_remove(struct target *target, struct breakpoint 
*breakpoint);
+int esp_riscv_handle_target_event(struct target *target, enum target_event 
event,
+       void *priv);
+int esp_riscv_read_memory(struct target *target, target_addr_t address,
+       uint32_t size, uint32_t count, uint8_t *buffer);
+int esp_riscv_write_memory(struct target *target, target_addr_t address,
+       uint32_t size, uint32_t count, const uint8_t *buffer);
+int esp_riscv_poll(struct target *target);
+int esp_riscv_halt(struct target *target);
+int esp_riscv_resume(struct target *target, int current, target_addr_t address,
+       int handle_breakpoints, int debug_execution);
+int esp_riscv_step(
+       struct target *target,
+       int current,
+       target_addr_t address,
+       int handle_breakpoints);
+int esp_riscv_assert_reset(struct target *target);
+int esp_riscv_deassert_reset(struct target *target);
+int esp_riscv_checksum_memory(struct target *target,
+       target_addr_t address, uint32_t count,
+       uint32_t *checksum);
+int esp_riscv_get_gdb_reg_list_noread(struct target *target,
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class);
+int esp_riscv_get_gdb_reg_list(struct target *target,
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class);
+const char *esp_riscv_get_gdb_arch(struct target *target);
+int esp_riscv_arch_state(struct target *target);
+int esp_riscv_add_watchpoint(struct target *target, struct watchpoint 
*watchpoint);
+int esp_riscv_remove_watchpoint(struct target *target,
+       struct watchpoint *watchpoint);
+int esp_riscv_hit_watchpoint(struct target *target, struct watchpoint 
**hit_watchpoint);
+unsigned esp_riscv_address_bits(struct target *target);
+bool esp_riscv_core_is_halted(struct target *target);
+int esp_riscv_core_halt(struct target *target);
+int esp_riscv_core_resume(struct target *target);
+int esp_riscv_core_ebreaks_enable(struct target *target);
+
+extern const struct command_registration esp_riscv_command_handlers[];
+
+#endif /* _ESP_RISCV_H */
diff --git a/src/target/esp_semihosting.c b/src/target/esp_semihosting.c
new file mode 100644
index 0000000000..862c8d970e
--- /dev/null
+++ b/src/target/esp_semihosting.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *   Semihosting API for Espressif chips                                   *
+ *   Copyright (C) 2022 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include <helper/log.h>
+#include "target.h"
+#include "semihosting_common.h"
+#include "esp_semihosting.h"
+#include "esp_riscv.h"
+
+struct esp_semihost_data *target_to_esp_semihost_data(struct target *target)
+{
+       const char *arch = target_get_gdb_arch(target);
+       if (arch) {
+               if (strncmp(arch, "riscv", 5) == 0)
+                       return &target_to_esp_riscv(target)->semihost;
+       }
+       LOG_ERROR("Unknown target arch!");
+       return NULL;
+}
+
+int esp_semihosting_common(struct target *target)
+{
+       struct semihosting *semihosting = target->semihosting;
+       if (!semihosting) {
+               /* Silently ignore if the semihosting field was not set. */
+               return ERROR_OK;
+       }
+
+       int retval = ERROR_FAIL;
+
+       LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
+               semihosting->param);
+
+       switch (semihosting->op) {
+               case ESP_SEMIHOSTING_SYS_DRV_INFO:
+                       /* not implemented yet */
+                       break;
+               case ESP_SEMIHOSTING_SYS_SEEK:
+                       /* not implemented yet */
+                       break;
+               case ESP_SEMIHOSTING_SYS_APPTRACE_INIT:
+               case ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT:
+               case ESP_SEMIHOSTING_SYS_BREAKPOINT_SET:
+               case ESP_SEMIHOSTING_SYS_WATCHPOINT_SET:
+                       /* For the time being only riscv chips support these 
commands */
+                       return esp_riscv_semihosting(target);
+       }
+
+       return retval;
+}
diff --git a/src/target/esp_semihosting.h b/src/target/esp_semihosting.h
new file mode 100644
index 0000000000..1ad20db6b6
--- /dev/null
+++ b/src/target/esp_semihosting.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *   Semihosting API for Espressif chips                                   *
+ *   Copyright (C) 2022 Espressif Systems Ltd.                             *
+ *                                                                         *
+ *   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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef _ESP_SEMIHOSTING_H_
+#define _ESP_SEMIHOSTING_H_
+
+/* syscalls compatible to ARM standard */
+#define ESP_SEMIHOSTING_SYS_DRV_INFO                0x100
+#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT           0x101
+#define ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT        0x102
+#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET          0x103
+#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET          0x104
+#define ESP_SEMIHOSTING_SYS_SEEK                    0x105      /* custom lseek 
with whence */
+/* not implemented yet */
+#define ESP_SEMIHOSTING_SYS_MKDIR                   0x106
+#define ESP_SEMIHOSTING_SYS_OPENDIR                 0x107
+#define ESP_SEMIHOSTING_SYS_READDIR                 0x108
+#define ESP_SEMIHOSTING_SYS_READDIR_R               0x109
+#define ESP_SEMIHOSTING_SYS_SEEKDIR                 0x10A
+#define ESP_SEMIHOSTING_SYS_TELLDIR                 0x10B
+#define ESP_SEMIHOSTING_SYS_CLOSEDIR                0x10C
+#define ESP_SEMIHOSTING_SYS_RMDIR                   0x10D
+#define ESP_SEMIHOSTING_SYS_ACCESS                  0x10E
+#define ESP_SEMIHOSTING_SYS_TRUNCATE                0x10F
+#define ESP_SEMIHOSTING_SYS_UTIME                   0x110
+#define ESP_SEMIHOSTING_SYS_FSTAT                   0x111
+#define ESP_SEMIHOSTING_SYS_STAT                    0x112
+#define ESP_SEMIHOSTING_SYS_FSYNC                   0x113
+#define ESP_SEMIHOSTING_SYS_LINK                    0x114
+#define ESP_SEMIHOSTING_SYS_UNLINK                  0x115
+
+int esp_semihosting_common(struct target *target);
+
+#endif

-- 

Reply via email to