From 3171650a68e25b3ddf944c1e15ceae84625d8808 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Mon, 25 Sep 2017 14:38:14 +1300 Subject: [PATCH 01/19] riscv: Identify SiFive IDCODE and call stub to probe. FIXME: Use -O2 in Makefile again. --- src/Makefile | 1 + src/target/jtag_devs.c | 4 ++++ src/target/riscv.c | 33 +++++++++++++++++++++++++++++++++ src/target/riscv.h | 29 +++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/target/riscv.c create mode 100644 src/target/riscv.h diff --git a/src/Makefile b/src/Makefile index 188ecfa4a75..964626a84a3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,6 +48,7 @@ SRC = \ platform.c \ remote.c \ rp.c \ + riscv.c \ sam3x.c \ sam4l.c \ samd.c \ diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index af55a636ee5..ea5d30a3766 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -22,11 +22,15 @@ #include "jtag_scan.h" #include "adiv5.h" #include "jtag_devs.h" +#include "riscv.h" jtag_dev_descr_t dev_descr[] = { {.idcode = 0x0BA00477, .idmask = 0x0FFF0FFF, .descr = "ARM Limited: ADIv5 JTAG-DP port.", .handler = adiv5_jtag_dp_handler}, + {.idcode = 0x10e31913, .idmask = 0xFFFFFFFF, + .descr = "SiFive: E310-G000.", + .handler = riscv_jtag_handler}, {.idcode = 0x06410041, .idmask = 0x0FFFFFFF, .descr = "ST Microelectronics: STM32, Medium density."}, {.idcode = 0x06412041, .idmask = 0x0FFFFFFF, diff --git a/src/target/riscv.c b/src/target/riscv.c new file mode 100644 index 00000000000..fbb18ef44f2 --- /dev/null +++ b/src/target/riscv.c @@ -0,0 +1,33 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2017 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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 . + */ + +/* This file implements debugging functionality specific to RISC-V targets. + */ + +#include "general.h" +#include "jtagtap.h" +#include "jtag_scan.h" +#include "target.h" + +void riscv_jtag_handler(jtag_dev_t *dev) +{ + (void) dev; + DEBUG_WARN("Scanning RISC-V target! %p\n", dev); +} diff --git a/src/target/riscv.h b/src/target/riscv.h new file mode 100644 index 00000000000..94cabcb4135 --- /dev/null +++ b/src/target/riscv.h @@ -0,0 +1,29 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2017 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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 . + */ + +#ifndef __RISCV_H +#define __RISCV_H + +#include "jtag_scan.h" +#include "target.h" + +void riscv_jtag_handler(jtag_dev_t *dev); + +#endif From 907eec58defa8e5cb6030142dc936bab47c5ea73 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 10 May 2020 13:03:46 +0200 Subject: [PATCH 02/19] Add GD32V103 target. --- src/target/jtag_devs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index ea5d30a3766..17c42e2dfdf 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -31,6 +31,9 @@ jtag_dev_descr_t dev_descr[] = { {.idcode = 0x10e31913, .idmask = 0xFFFFFFFF, .descr = "SiFive: E310-G000.", .handler = riscv_jtag_handler}, + {.idcode = 0x1000563d, .idmask = 0xFFFFFFFF, + .descr = "Sipeed RV32.", + .handler = riscv_jtag_handler}, {.idcode = 0x06410041, .idmask = 0x0FFFFFFF, .descr = "ST Microelectronics: STM32, Medium density."}, {.idcode = 0x06412041, .idmask = 0x0FFFFFFF, From 6ed3e9af0a902576f13d739906186885a1d2a2d9 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Tue, 26 Sep 2017 10:43:25 +1300 Subject: [PATCH 03/19] riscv: low-level DTM/DM access implemented --- src/target/riscv.c | 146 ++++++++++++++++++++++++++++++++++++++++++++- src/target/riscv.h | 2 +- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index fbb18ef44f2..72fd1464da1 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -19,15 +19,155 @@ */ /* This file implements debugging functionality specific to RISC-V targets. + * According to risv-debug-spec 0.11nov12 November 12, 2016 */ +#define DEBUG DEBUG_WARN #include "general.h" #include "jtagtap.h" #include "jtag_scan.h" #include "target.h" -void riscv_jtag_handler(jtag_dev_t *dev) +#define RISCV_IR_IDCODE 0x01 +#define RISCV_IR_DTMCONTROL 0x10 +#define RISCV_IR_DBUS 0x11 +#define RISCV_IR_BYPASS 0x1f + +#define RISCV_DTMCONTROL_DBUSRESET (1 << 16) + +#define RISCV_DBUS_NOP 0 +#define RISCV_DBUS_READ 1 +#define RISCV_DBUS_WRITE 2 + +#define RISCV_DMCONTROL 0x10 +#define RISCV_DMINFO 0x11 + +#define RISCV_DMCONTROL_INTERRUPT (1ull << 33) + +struct riscv_dtm { + uint8_t dtm_index; + uint8_t version; /* As read from dmtcontrol */ + uint8_t abits; /* Debug bus address bits (6 bits wide) */ + uint8_t idle; /* Number of cycles required in run-test/idle */ + bool error; + uint64_t lastdbus; +}; + +static void riscv_dtm_reset(struct riscv_dtm *dtm) { - (void) dev; - DEBUG_WARN("Scanning RISC-V target! %p\n", dev); + jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, RISCV_IR_DTMCONTROL); + uint32_t dtmcontrol = RISCV_DTMCONTROL_DBUSRESET; + jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, (void*)&dtmcontrol, (void*)&dtmcontrol, 32); + DEBUG("after dbusreset: dtmcontrol = 0x%08x\n", dtmcontrol); +} + +static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) +{ + uint64_t ret = 0; + /* Do not smash the stack is abits has gone astray!*/ + if (dtm->abits > (64 - 36)) { + DEBUG("Abits overflow in riscv_dtm_low_access: %d\n", dtm->abits); + return 0; + } +retry: + DEBUG("out %"PRIx64"\n", dbus); + jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, (void*)&ret, (const void*)&dbus, + 36 + dtm->abits); + DEBUG("in %"PRIx64"\n", ret); + switch (ret & 3) { + case 3: + riscv_dtm_reset(dtm); + jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, RISCV_IR_DBUS); + DEBUG("retry out %"PRIx64"\n", dbus); + jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, + (void*)&ret, (const void*)&dtm->lastdbus, + dtm->abits + 36); + DEBUG("in %"PRIx64"\n", ret); + jtag_proc.jtagtap_tms_seq(0, dtm->idle); + goto retry; + case 0: + dtm->lastdbus = dbus; + break; + case 2: + default: + dtm->error = true; + return 0; + } + jtag_proc.jtagtap_tms_seq(0, dtm->idle); + return (ret >> 2) & 0x3ffffffffull; +} + +static void riscv_dtm_write(struct riscv_dtm *dtm, uint32_t addr, uint64_t data) +{ + uint64_t dbus = ((uint64_t)addr << 36) | + ((data & 0x3ffffffffull) << 2) | RISCV_DBUS_WRITE; + riscv_dtm_low_access(dtm, dbus); +} + +static uint64_t riscv_dtm_read(struct riscv_dtm *dtm, uint32_t addr) +{ + riscv_dtm_low_access(dtm, ((uint64_t)addr << 36) | RISCV_DBUS_READ); + return riscv_dtm_low_access(dtm, RISCV_DBUS_NOP); +} + +void riscv_jtag_handler(jtag_dev_t *jd) +{ + uint32_t dtmcontrol = 0; + DEBUG("Scanning RISC-V jtag dev at pos %d, idcode %08" PRIx32 "\n", + jd->jd_dev, jd->jd_idcode); + jtag_dev_write_ir(&jtag_proc, jd->jd_dev, RISCV_IR_DTMCONTROL); + jtag_dev_shift_dr(&jtag_proc, jd->jd_dev, (void*)&dtmcontrol, (void*)&dtmcontrol, 32); + DEBUG("dtmcontrol = 0x%08x\n", dtmcontrol); + uint8_t version = dtmcontrol & 0xf; + + if (version > 0) { + DEBUG("Only DTM version 0 handle. Version is %d\n", version); +// FIXME return; /* We'll come back to this someday */ + } + + struct riscv_dtm *dtm = alloca(sizeof(*dtm)); + memset(dtm, 0, sizeof(*dtm)); + dtm->dtm_index = jd->jd_dev; + dtm->abits = ((dtmcontrol >> 13) & 3) << 4 | + ((dtmcontrol >> 4) & 0xf); + dtm->idle = (dtmcontrol >> 10) & 7; + DEBUG("abits = %d\n", dtm->abits); + DEBUG("idle = %d\n", dtm->idle); + DEBUG("dbusstat = %d\n", (dtmcontrol >> 8) & 3); + riscv_dtm_reset(dtm); + + jtag_dev_write_ir(&jtag_proc, jd->jd_dev, RISCV_IR_DBUS); + + uint32_t dminfo = riscv_dtm_read(dtm, RISCV_DMINFO); + uint8_t dmversion = ((dminfo >> 4) & 0xc) | (dminfo & 3); +#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) + uint64_t dmcontrol = riscv_dtm_read(dtm, RISCV_DMCONTROL); + DEBUG("dmcontrol = %"PRIx64"\n", dmcontrol); + DEBUG("dminfo = %"PRIx32"\n", dminfo); + DEBUG("\tloversion = %d\n", dmversion); +#endif + if (dmversion != 1) + return; + + uint8_t authenticated = (dminfo >> 5) & 1; +#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) + uint8_t authtype = (dminfo >> 2) & 3; + uint8_t authbusy = (dminfo >> 4) & 1; + DEBUG("\tauthtype = %d, authbusy = %d, authenticated = %d\n", + authtype, authbusy, authenticated); +#endif + if (authenticated != 1) + return; + +#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) + uint8_t dramsize = (dminfo >> 10) & 0x3f; + DEBUG("\tdramsize = %d (%d bytes)\n", dramsize, (dramsize + 1) * 4); + + riscv_dtm_write(dtm, 0, 0xbeefcafe); + riscv_dtm_write(dtm, 1, 0xdeadbeef); + DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 0)); + DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 1)); +#else + (void)riscv_dtm_write; +#endif } diff --git a/src/target/riscv.h b/src/target/riscv.h index 94cabcb4135..478bec89ad5 100644 --- a/src/target/riscv.h +++ b/src/target/riscv.h @@ -24,6 +24,6 @@ #include "jtag_scan.h" #include "target.h" -void riscv_jtag_handler(jtag_dev_t *dev); +void riscv_jtag_handler(jtag_dev_t *jd); #endif From 0a95daa34dab570de4e32df1be27030ad72e52c5 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Tue, 26 Sep 2017 14:26:50 +1300 Subject: [PATCH 04/19] riscv: Read words from system ram. --- src/target/riscv.c | 199 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 72fd1464da1..d688d1c7cbb 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -27,6 +27,9 @@ #include "jtagtap.h" #include "jtag_scan.h" #include "target.h" +#include "target_internal.h" + +#include #define RISCV_IR_IDCODE 0x01 #define RISCV_IR_DTMCONTROL 0x10 @@ -43,6 +46,7 @@ #define RISCV_DMINFO 0x11 #define RISCV_DMCONTROL_INTERRUPT (1ull << 33) +#define RISCV_DMCONTROL_HALTNOT (1ull << 32) struct riscv_dtm { uint8_t dtm_index; @@ -63,6 +67,9 @@ static void riscv_dtm_reset(struct riscv_dtm *dtm) static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) { + if (dtm->error) + return 0; + uint64_t ret = 0; /* Do not smash the stack is abits has gone astray!*/ if (dtm->abits > (64 - 36)) { @@ -73,7 +80,6 @@ static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) DEBUG("out %"PRIx64"\n", dbus); jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, (void*)&ret, (const void*)&dbus, 36 + dtm->abits); - DEBUG("in %"PRIx64"\n", ret); switch (ret & 3) { case 3: riscv_dtm_reset(dtm); @@ -90,6 +96,7 @@ static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) break; case 2: default: + DEBUG("Set sticky error!"); dtm->error = true; return 0; } @@ -109,6 +116,172 @@ static uint64_t riscv_dtm_read(struct riscv_dtm *dtm, uint32_t addr) riscv_dtm_low_access(dtm, ((uint64_t)addr << 36) | RISCV_DBUS_READ); return riscv_dtm_low_access(dtm, RISCV_DBUS_NOP); } +static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, + const uint32_t code[], int count) +{ + int i; + for (i = 0; i < count - 1; i++) { + riscv_dtm_write(dtm, i, code[i]); + } + riscv_dtm_write(dtm, i, code[i] | RISCV_DMCONTROL_INTERRUPT); + uint64_t ret; + do { + ret = riscv_dtm_read(dtm, count); + } while (ret & RISCV_DMCONTROL_INTERRUPT); + return ret; +} + +static uint32_t riscv_mem_read32(struct riscv_dtm *dtm, uint32_t addr) +{ + /* Debug RAM stub + * 400: 41002403 lw s0, 0x410(zero) + * 404: 00042483 lw s1, 0(s0) + * 408: 40902a23 sw s1, 0x414(zero) + * 40c: 3f80006f j 0 + * 410: dw addr + * 414: dw data + */ + uint32_t ram[] = {0x41002403, 0x42483, 0x40902a23, 0x3f80006f, addr}; + return riscv_debug_ram_exec(dtm, ram, 5); +} + +static void riscv_mem_write32(struct riscv_dtm *dtm, + uint32_t addr, uint32_t val) +{ + /* Debug RAM stub + * 400: 41002403 lw s0, 0x410(zero) + * 408: 41402483 lw s1, 0x414(zero) + * 404: 00942023 sw s1, 0(s0) + * 40c: 3f80006f j 0 + * 410: dw addr + * 414: dw data + */ + uint32_t ram[] = {0x41002403, 0x41402483, 0x942023, 0x3f80006f, addr, val}; + riscv_debug_ram_exec(dtm, ram, 5); +} + +static uint32_t riscv_gpreg_read(struct riscv_dtm *dtm, uint8_t reg) +{ + /* Debug RAM stub + * 400: 40x02423 sw , 0x408(zero) + * 40c: 4000006f j 0 + */ + uint32_t ram[] = {0x40002423, 0x4000006f}; + ram[0] |= reg << 20; + uint32_t val = riscv_debug_ram_exec(dtm, ram, 2); + DEBUG("x%d = 0x%x\n", reg, val); + return val; +} + +static void riscv_gpreg_write(struct riscv_dtm *dtm, uint8_t reg, uint32_t val) +{ + /* Debug RAM stub + * 400: 40802403 lw , 0x408(zero) + * 40c: 4000006f j 0 + */ + uint32_t ram[] = {0x40002423, 0x4000006f, val}; + ram[0] |= reg << 7; + riscv_debug_ram_exec(dtm, ram, 3); +} + +static void riscv_halt_request(target *t) +{ + struct riscv_dtm *dtm = t->priv; + /* Debug RAM stub + * 400: 7b026073 csrsi dcsr,4 + * 40c: 4000006f j 0 + */ + uint32_t ram[] = {0x7b026073, 0x4000006f}; + riscv_debug_ram_exec(dtm, ram, 2); +} + +static void riscv_halt_resume(target *t, bool step) +{ + assert(!step); + struct riscv_dtm *dtm = t->priv; + /* Debug RAM stub + * 400: 7b027073 csrci dcsr,4 + * 40c: 4000006f j 0 + */ + uint32_t ram[] = {0x7b027073, 0x4000006f}; + riscv_debug_ram_exec(dtm, ram, 2); +} + +static void riscv_mem_read(target *t, void *dest, target_addr src, size_t len) +{ + uint32_t *d = dest; + assert((src & 3) == 0); + assert((len & 3) == 0); + while (len) { + *d++ = riscv_mem_read32(t->priv, src); + src += 4; + len -= 4; + } +} + +static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t len) +{ + const uint32_t *s = src; + assert((dest & 3) == 0); + assert((len & 3) == 0); + while (len) { + riscv_mem_write32(t->priv, dest, *s++); + dest += 4; + len -= 4; + } +} + +static void riscv_reset(target *t) +{ + (void)t; + DEBUG("RISC-V reset not implemented!\n"); +} + +bool riscv_check_error(target *t) +{ + struct riscv_dtm *dtm = t->priv; + if (dtm->error) { + riscv_dtm_reset(dtm); + dtm->error = false; + return true; + } + return false; +} + +static bool riscv_attach(target *t) +{ + target_halt_request(t); + return true; +} + +static void riscv_detach(target *t) +{ + target_halt_resume(t, false); +} + +static void riscv_regs_read(target *t, void *data) +{ + uint32_t *reg = data; + for (int i = 0; i < 32; i++) + *reg++ = riscv_gpreg_read(t->priv, i); +} + +static void riscv_regs_write(target *t, const void *data) +{ + const uint32_t *reg = data; + for (int i = 0; i < 32; i++) + riscv_gpreg_write(t->priv, i, *reg++); +} + +static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) +{ + (void)watch; + struct riscv_dtm *dtm = t->priv; + uint64_t dmcontrol = riscv_dtm_read(dtm, RISCV_DMCONTROL); + if (dmcontrol & RISCV_DMCONTROL_HALTNOT) + return TARGET_HALT_REQUEST; + return TARGET_HALT_RUNNING; +} void riscv_jtag_handler(jtag_dev_t *jd) { @@ -167,7 +340,31 @@ void riscv_jtag_handler(jtag_dev_t *jd) riscv_dtm_write(dtm, 1, 0xdeadbeef); DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 0)); DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 1)); + for (int i = 0; i < dramsize + 1; i++) { + DEBUG("DebugRAM[%d] = %08"PRIx32"\n", i, + riscv_mem_read32(dtm, 0x400 + i*4)); + } #else (void)riscv_dtm_write; + (void)riscv_mem_read32; #endif + /* Allocate and set up new target */ + target *t = target_new(); + t->priv = malloc(sizeof(*dtm)); + memcpy(t->priv, dtm, sizeof(*dtm)); + dtm = t->priv; + t->priv_free = free; + t->driver = "RISC-V"; + t->mem_read = riscv_mem_read; + t->mem_write = riscv_mem_write; + t->attach = riscv_attach; + t->detach = riscv_detach; + t->check_error = riscv_check_error; + t->regs_read = riscv_regs_read; + t->regs_write = riscv_regs_write; + t->reset = riscv_reset; + t->halt_request = riscv_halt_request; + t->halt_poll = riscv_halt_poll; + t->halt_resume = riscv_halt_resume; + t->regs_size = 33 * 4; } From fe42f98551aacb7979b7345e6d9eb573027497e2 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 27 Sep 2017 12:30:55 +1300 Subject: [PATCH 05/19] riscv: Fix reading registers --- src/target/riscv.c | 47 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index d688d1c7cbb..7712fdf6cac 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -48,11 +48,16 @@ #define RISCV_DMCONTROL_INTERRUPT (1ull << 33) #define RISCV_DMCONTROL_HALTNOT (1ull << 32) +#define RISCV_DCSR 0x7b0 +#define RISCV_DPC 0x7b1 +#define RISCV_DSCRATCH 0x7b2 + struct riscv_dtm { uint8_t dtm_index; uint8_t version; /* As read from dmtcontrol */ uint8_t abits; /* Debug bus address bits (6 bits wide) */ uint8_t idle; /* Number of cycles required in run-test/idle */ + uint8_t dramsize; /* Size of debug ram in words - 1 */ bool error; uint64_t lastdbus; }; @@ -173,6 +178,21 @@ static uint32_t riscv_gpreg_read(struct riscv_dtm *dtm, uint8_t reg) return val; } +static uint32_t riscv_csreg_read(struct riscv_dtm *dtm, uint16_t csr) +{ + /* Debug RAM stub + * 400: xxx02473 csrr s0, + * 404: 40802623 sw s0, 0x40c(zero) + * 408: 3fc0006f j 0 + * 40c: dw data + */ + uint32_t ram[] = {0x00002473, 0x40802623, 0x3fc0006f}; + ram[0] |= (uint32_t)csr << 20; + uint32_t val = riscv_debug_ram_exec(dtm, ram, 3); + DEBUG("CSR(%03x) = 0x%x\n", csr, val); + return val; +} + static void riscv_gpreg_write(struct riscv_dtm *dtm, uint8_t reg, uint32_t val) { /* Debug RAM stub @@ -261,9 +281,26 @@ static void riscv_detach(target *t) static void riscv_regs_read(target *t, void *data) { + struct riscv_dtm *dtm = t->priv; uint32_t *reg = data; - for (int i = 0; i < 32; i++) - *reg++ = riscv_gpreg_read(t->priv, i); + for (int i = 0; i < 33; i++) { + switch (i) { + case 0: + reg[i] = 0; + break; + case 8: + reg[i] = riscv_csreg_read(dtm, RISCV_DSCRATCH); + break; + case 9: + reg[i] = riscv_dtm_read(dtm, dtm->dramsize); + break; + case 32: + reg[i] = riscv_csreg_read(dtm, RISCV_DPC); + break; + default: + reg[i] = riscv_gpreg_read(dtm, i); + } + } } static void riscv_regs_write(target *t, const void *data) @@ -333,14 +370,14 @@ void riscv_jtag_handler(jtag_dev_t *jd) return; #if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) - uint8_t dramsize = (dminfo >> 10) & 0x3f; - DEBUG("\tdramsize = %d (%d bytes)\n", dramsize, (dramsize + 1) * 4); + dtm->dramsize = (dminfo >> 10) & 0x3f; + DEBUG("\tdramsize = %d (%d bytes)\n", dtm->dramsize, (dtm->dramsize + 1) * 4); riscv_dtm_write(dtm, 0, 0xbeefcafe); riscv_dtm_write(dtm, 1, 0xdeadbeef); DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 0)); DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 1)); - for (int i = 0; i < dramsize + 1; i++) { + for (int i = 0; i < dtm->dramsize + 1; i++) { DEBUG("DebugRAM[%d] = %08"PRIx32"\n", i, riscv_mem_read32(dtm, 0x400 + i*4)); } From c717443149b7d4a5f9f4b86c630d1ada80409d9e Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 27 Sep 2017 14:01:20 +1300 Subject: [PATCH 06/19] riscv: Fixes around halt/resume, implement stepping --- src/target/riscv.c | 47 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 7712fdf6cac..7a9c80c1f9a 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -60,6 +60,7 @@ struct riscv_dtm { uint8_t dramsize; /* Size of debug ram in words - 1 */ bool error; uint64_t lastdbus; + bool halt_requested; }; static void riscv_dtm_reset(struct riscv_dtm *dtm) @@ -206,25 +207,33 @@ static void riscv_gpreg_write(struct riscv_dtm *dtm, uint8_t reg, uint32_t val) static void riscv_halt_request(target *t) { + DEBUG("Halt requested!\n"); struct riscv_dtm *dtm = t->priv; /* Debug RAM stub - * 400: 7b026073 csrsi dcsr,4 - * 40c: 4000006f j 0 + * 400: 7b046073 csrsi dcsr, halt + * 404: 4000006f j 0 */ - uint32_t ram[] = {0x7b026073, 0x4000006f}; + uint32_t ram[] = {0x7b046073, 0x4000006f}; riscv_debug_ram_exec(dtm, ram, 2); + dtm->halt_requested = true; } static void riscv_halt_resume(target *t, bool step) { - assert(!step); + DEBUG("Resume requested! step=%d\n", step); struct riscv_dtm *dtm = t->priv; - /* Debug RAM stub - * 400: 7b027073 csrci dcsr,4 - * 40c: 4000006f j 0 + /* Debug RAM stub - we patch in step bit as needed + * 400: 7b006073 csrsi dcsr, 0 + * 404: 7b047073 csrci dcsr, halt + * 408: 4000006f j 0 */ - uint32_t ram[] = {0x7b027073, 0x4000006f}; - riscv_debug_ram_exec(dtm, ram, 2); + uint32_t ram[] = {0x7b006073, 0x7b047073, 0x3fc0006f}; + if (step) + ram[0] |= 4 << 15; + else + ram[1] |= 4 << 15; + riscv_debug_ram_exec(dtm, ram, 3); + dtm->halt_requested = false; } static void riscv_mem_read(target *t, void *dest, target_addr src, size_t len) @@ -315,9 +324,23 @@ static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) (void)watch; struct riscv_dtm *dtm = t->priv; uint64_t dmcontrol = riscv_dtm_read(dtm, RISCV_DMCONTROL); - if (dmcontrol & RISCV_DMCONTROL_HALTNOT) - return TARGET_HALT_REQUEST; - return TARGET_HALT_RUNNING; + DEBUG("dmcontrol = 0x%"PRIx64"\n", dmcontrol); + if (!dtm->halt_requested && (dmcontrol & RISCV_DMCONTROL_HALTNOT) == 0) + return TARGET_HALT_RUNNING; + + uint32_t dcsr = riscv_csreg_read(dtm, RISCV_DCSR); + DEBUG_WARN("cause = %d\n", (dcsr >> 6) & 7); + switch ((dcsr >> 6) & 7) { + case 0: return TARGET_HALT_RUNNING; + case 1: /* Software breakpoint */ + case 2: /* Hardware trigger breakpoint */ + return TARGET_HALT_BREAKPOINT; + case 3: return TARGET_HALT_REQUEST; + case 4: return TARGET_HALT_STEPPING; + case 5: return TARGET_HALT_REQUEST; + default: + return TARGET_HALT_ERROR; + } } void riscv_jtag_handler(jtag_dev_t *jd) From 2ae764753d5548f4f77a674605fcab3b7f99b79a Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 27 Sep 2017 14:16:24 +1300 Subject: [PATCH 07/19] riscv: Fix register writes --- src/target/riscv.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 7a9c80c1f9a..1e3f90da487 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -194,6 +194,19 @@ static uint32_t riscv_csreg_read(struct riscv_dtm *dtm, uint16_t csr) return val; } +static void riscv_csreg_write(struct riscv_dtm *dtm, uint16_t csr, uint32_t val) +{ + /* Debug RAM stub + * 404: 40c02403 lw s0, 0x40c(zero) + * 400: xxx41073 csrw s0, + * 408: 3fc0006f j 0 + * 40c: dw data + */ + uint32_t ram[] = {0x40c02403, 0x00041073, 0x3fc0006f, val}; + ram[1] |= (uint32_t)csr << 20; + riscv_debug_ram_exec(dtm, ram, 4); +} + static void riscv_gpreg_write(struct riscv_dtm *dtm, uint8_t reg, uint32_t val) { /* Debug RAM stub @@ -314,9 +327,25 @@ static void riscv_regs_read(target *t, void *data) static void riscv_regs_write(target *t, const void *data) { + struct riscv_dtm *dtm = t->priv; const uint32_t *reg = data; - for (int i = 0; i < 32; i++) - riscv_gpreg_write(t->priv, i, *reg++); + for (int i = 0; i < 33; i++) { + switch (i) { + case 0: + break; + case 8: + riscv_csreg_write(dtm, RISCV_DSCRATCH, reg[i]); + break; + case 9: + riscv_dtm_write(dtm, dtm->dramsize, reg[i]); + break; + case 32: + riscv_csreg_write(dtm, RISCV_DPC, reg[i]); + break; + default: + riscv_gpreg_write(dtm, i, reg[i]); + } + } } static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) From f10641978f85aa4104958b506d01ae775fceb6b1 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 27 Sep 2017 14:23:23 +1300 Subject: [PATCH 08/19] riscv: Report architecture as rv32 --- src/target/riscv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/target/riscv.c b/src/target/riscv.c index 1e3f90da487..03dab78bd18 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -52,6 +52,13 @@ #define RISCV_DPC 0x7b1 #define RISCV_DSCRATCH 0x7b2 +/* GDB register map / target description */ +static const char tdesc_rv32[] = +"" +"" +" riscv:rv32" +""; + struct riscv_dtm { uint8_t dtm_index; uint8_t version; /* As read from dmtcontrol */ @@ -456,4 +463,5 @@ void riscv_jtag_handler(jtag_dev_t *jd) t->halt_poll = riscv_halt_poll; t->halt_resume = riscv_halt_resume; t->regs_size = 33 * 4; + t->tdesc = tdesc_rv32; } From f2328f3e0d92a96a284441842b77a64f91412ad2 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 27 Sep 2017 14:23:44 +1300 Subject: [PATCH 09/19] riscv: Implement reset --- src/target/riscv.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 03dab78bd18..f2b400afc9c 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -282,8 +282,8 @@ static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t static void riscv_reset(target *t) { - (void)t; - DEBUG("RISC-V reset not implemented!\n"); + DEBUG("Resetting!\n"); + riscv_csreg_write(t->priv, RISCV_DCSR, 1 << 29); } bool riscv_check_error(target *t) @@ -365,8 +365,9 @@ static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) return TARGET_HALT_RUNNING; uint32_t dcsr = riscv_csreg_read(dtm, RISCV_DCSR); - DEBUG_WARN("cause = %d\n", (dcsr >> 6) & 7); - switch ((dcsr >> 6) & 7) { + uint8_t cause = (dcsr >> 6) & 7; + DEBUG_WARN("cause = %d\n", cause); + switch (cause) { case 0: return TARGET_HALT_RUNNING; case 1: /* Software breakpoint */ case 2: /* Hardware trigger breakpoint */ @@ -409,22 +410,13 @@ void riscv_jtag_handler(jtag_dev_t *jd) uint32_t dminfo = riscv_dtm_read(dtm, RISCV_DMINFO); uint8_t dmversion = ((dminfo >> 4) & 0xc) | (dminfo & 3); -#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) - uint64_t dmcontrol = riscv_dtm_read(dtm, RISCV_DMCONTROL); - DEBUG("dmcontrol = %"PRIx64"\n", dmcontrol); DEBUG("dminfo = %"PRIx32"\n", dminfo); DEBUG("\tloversion = %d\n", dmversion); -#endif if (dmversion != 1) return; uint8_t authenticated = (dminfo >> 5) & 1; -#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) - uint8_t authtype = (dminfo >> 2) & 3; - uint8_t authbusy = (dminfo >> 4) & 1; - DEBUG("\tauthtype = %d, authbusy = %d, authenticated = %d\n", - authtype, authbusy, authenticated); -#endif + DEBUG("\tauthenticated = %d\n", authenticated); if (authenticated != 1) return; From da93f105d693306f7bd4bbf2dc0ad2b8c2bfa158 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 28 Sep 2017 12:31:26 +1300 Subject: [PATCH 10/19] riscv: Implement break- and watchpoints --- src/target/riscv.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/target/riscv.c b/src/target/riscv.c index f2b400afc9c..eb7e03a6d68 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -48,10 +48,21 @@ #define RISCV_DMCONTROL_INTERRUPT (1ull << 33) #define RISCV_DMCONTROL_HALTNOT (1ull << 32) +#define RISCV_TSELECT 0x7a0 +#define RISCV_MCONTROL 0x7a1 +#define RISCV_TDATA2 0x7a2 + #define RISCV_DCSR 0x7b0 #define RISCV_DPC 0x7b1 #define RISCV_DSCRATCH 0x7b2 +#define RISCV_MCONTROL_DMODE (1<<(32-5)) +#define RISCV_MCONTROL_ENABLE_MASK (0xf << 3) +#define RISCV_MCONTROL_LOAD (1 << 0) +#define RISCV_MCONTROL_STORE (1 << 1) +#define RISCV_MCONTROL_EXECUTE (1 << 2) +#define RISCV_MCONTROL_ACTION_DEBUG (1 << 12) + /* GDB register map / target description */ static const char tdesc_rv32[] = "" @@ -70,6 +81,9 @@ struct riscv_dtm { bool halt_requested; }; +static int riscv_breakwatch_set(target *t, struct breakwatch *); +static int riscv_breakwatch_clear(target *t, struct breakwatch *); + static void riscv_dtm_reset(struct riscv_dtm *dtm) { jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, RISCV_IR_DTMCONTROL); @@ -456,4 +470,70 @@ void riscv_jtag_handler(jtag_dev_t *jd) t->halt_resume = riscv_halt_resume; t->regs_size = 33 * 4; t->tdesc = tdesc_rv32; + + t->breakwatch_set = riscv_breakwatch_set; + t->breakwatch_clear = riscv_breakwatch_clear; +} + +static int riscv_breakwatch_set(target *t, struct breakwatch *bw) +{ + struct riscv_dtm *dtm = t->priv; + unsigned i; + uint32_t mcontrol = RISCV_MCONTROL_DMODE | RISCV_MCONTROL_ACTION_DEBUG | + RISCV_MCONTROL_ENABLE_MASK; + + switch (bw->type) { + case TARGET_BREAK_HARD: + mcontrol |= RISCV_MCONTROL_EXECUTE; + break; + case TARGET_WATCH_WRITE: + mcontrol |= RISCV_MCONTROL_STORE; + break; + case TARGET_WATCH_READ: + mcontrol |= RISCV_MCONTROL_LOAD; + break; + case TARGET_WATCH_ACCESS: + mcontrol |= RISCV_MCONTROL_LOAD | RISCV_MCONTROL_STORE; + break; + default: + return 1; + } + + uint32_t tselect_saved = riscv_csreg_read(dtm, RISCV_TSELECT); + + for (i = 0; ; i++) { + riscv_csreg_write(dtm, RISCV_TSELECT, i); + if (riscv_csreg_read(dtm, RISCV_TSELECT) != i) + return -1; + uint32_t tdata1 = riscv_csreg_read(dtm, RISCV_MCONTROL); + uint8_t type = (tdata1 >> (32-4)) & 0xf; + if ((type == 0)) + return -1; + if ((type == 2) && + ((tdata1 & RISCV_MCONTROL_ENABLE_MASK) == 0)) + break; + } + /* if we get here tselect = i is the index of our trigger */ + bw->reserved[0] = i; + + riscv_csreg_write(dtm, RISCV_MCONTROL, mcontrol); + riscv_csreg_write(dtm, RISCV_TDATA2, bw->addr); + + /* Restore saved tselect */ + riscv_csreg_write(dtm, RISCV_TSELECT, tselect_saved); + return 0; +} + +static int riscv_breakwatch_clear(target *t, struct breakwatch *bw) +{ + struct riscv_dtm *dtm = t->priv; + unsigned i = bw->reserved[0]; + uint32_t tselect_saved = riscv_csreg_read(dtm, RISCV_TSELECT); + + riscv_csreg_write(dtm, RISCV_TSELECT, i); + riscv_csreg_write(dtm, RISCV_MCONTROL, 0); + + /* Restore saved tselect */ + riscv_csreg_write(dtm, RISCV_TSELECT, tselect_saved); + return 0; } From 7e6dbf3ccd774a786024d03c1447c9e3fb29886e Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 29 Sep 2017 13:18:24 +1300 Subject: [PATCH 11/19] riscv: Implement single register reads --- src/target/riscv.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index eb7e03a6d68..59b954e684e 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -322,28 +322,33 @@ static void riscv_detach(target *t) target_halt_resume(t, false); } -static void riscv_regs_read(target *t, void *data) +static ssize_t riscv_reg_read(target *t, int reg, void *data, size_t s) { + (void)s; struct riscv_dtm *dtm = t->priv; - uint32_t *reg = data; - for (int i = 0; i < 33; i++) { - switch (i) { - case 0: - reg[i] = 0; - break; - case 8: - reg[i] = riscv_csreg_read(dtm, RISCV_DSCRATCH); - break; - case 9: - reg[i] = riscv_dtm_read(dtm, dtm->dramsize); - break; - case 32: - reg[i] = riscv_csreg_read(dtm, RISCV_DPC); - break; - default: - reg[i] = riscv_gpreg_read(dtm, i); - } + uint32_t *val = data; + switch (reg) { + case 0: + *val = 0; + break; + case 8: + *val = riscv_csreg_read(dtm, RISCV_DSCRATCH); + break; + case 9: + *val = riscv_dtm_read(dtm, dtm->dramsize); + break; + case 32: + *val = riscv_csreg_read(dtm, RISCV_DPC); + break; + case 65 ... 65 + 4095: + *val = riscv_csreg_read(dtm, reg - 65); + break; + case 1 ... 7: + case 10 ... 31: + *val = riscv_gpreg_read(dtm, reg); + break; } + return sizeof(*val); } static void riscv_regs_write(target *t, const void *data) @@ -462,7 +467,7 @@ void riscv_jtag_handler(jtag_dev_t *jd) t->attach = riscv_attach; t->detach = riscv_detach; t->check_error = riscv_check_error; - t->regs_read = riscv_regs_read; + t->reg_read = riscv_reg_read; t->regs_write = riscv_regs_write; t->reset = riscv_reset; t->halt_request = riscv_halt_request; From 616f72a7f71c79f52676f9aaec8d48ffba53e9e1 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 29 Sep 2017 14:43:14 +1300 Subject: [PATCH 12/19] riscv: Improve macro naming --- src/target/riscv.c | 124 +++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 59b954e684e..a08992ce65b 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -31,37 +31,37 @@ #include -#define RISCV_IR_IDCODE 0x01 -#define RISCV_IR_DTMCONTROL 0x10 -#define RISCV_IR_DBUS 0x11 -#define RISCV_IR_BYPASS 0x1f +#define IR_IDCODE 0x01 +#define IR_DTMCONTROL 0x10 +#define IR_DBUS 0x11 +#define IR_BYPASS 0x1f -#define RISCV_DTMCONTROL_DBUSRESET (1 << 16) +#define DTMCONTROL_DBUSRESET (1 << 16) -#define RISCV_DBUS_NOP 0 -#define RISCV_DBUS_READ 1 -#define RISCV_DBUS_WRITE 2 +#define DBUS_NOP 0 +#define DBUS_READ 1 +#define DBUS_WRITE 2 -#define RISCV_DMCONTROL 0x10 -#define RISCV_DMINFO 0x11 +#define DBUS_DMCONTROL 0x10 +#define DBUS_DMINFO 0x11 -#define RISCV_DMCONTROL_INTERRUPT (1ull << 33) -#define RISCV_DMCONTROL_HALTNOT (1ull << 32) +#define DMCONTROL_INTERRUPT (1ull << 33) +#define DMCONTROL_HALTNOT (1ull << 32) -#define RISCV_TSELECT 0x7a0 -#define RISCV_MCONTROL 0x7a1 -#define RISCV_TDATA2 0x7a2 +#define CSR_TSELECT 0x7a0 +#define CSR_MCONTROL 0x7a1 +#define CSR_TDATA2 0x7a2 -#define RISCV_DCSR 0x7b0 -#define RISCV_DPC 0x7b1 -#define RISCV_DSCRATCH 0x7b2 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 -#define RISCV_MCONTROL_DMODE (1<<(32-5)) -#define RISCV_MCONTROL_ENABLE_MASK (0xf << 3) -#define RISCV_MCONTROL_LOAD (1 << 0) -#define RISCV_MCONTROL_STORE (1 << 1) -#define RISCV_MCONTROL_EXECUTE (1 << 2) -#define RISCV_MCONTROL_ACTION_DEBUG (1 << 12) +#define CSR_MCONTROL_DMODE (1<<(32-5)) +#define CSR_MCONTROL_ENABLE_MASK (0xf << 3) +#define CSR_MCONTROL_LOAD (1 << 0) +#define CSR_MCONTROL_STORE (1 << 1) +#define CSR_MCONTROL_EXECUTE (1 << 2) +#define CSR_MCONTROL_ACTION_DEBUG (1 << 12) /* GDB register map / target description */ static const char tdesc_rv32[] = @@ -86,8 +86,8 @@ static int riscv_breakwatch_clear(target *t, struct breakwatch *); static void riscv_dtm_reset(struct riscv_dtm *dtm) { - jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, RISCV_IR_DTMCONTROL); - uint32_t dtmcontrol = RISCV_DTMCONTROL_DBUSRESET; + jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, IR_DTMCONTROL); + uint32_t dtmcontrol = DTMCONTROL_DBUSRESET; jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, (void*)&dtmcontrol, (void*)&dtmcontrol, 32); DEBUG("after dbusreset: dtmcontrol = 0x%08x\n", dtmcontrol); } @@ -110,7 +110,7 @@ static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) switch (ret & 3) { case 3: riscv_dtm_reset(dtm); - jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, RISCV_IR_DBUS); + jtag_dev_write_ir(&jtag_proc, dtm->dtm_index, IR_DBUS); DEBUG("retry out %"PRIx64"\n", dbus); jtag_dev_shift_dr(&jtag_proc, dtm->dtm_index, (void*)&ret, (const void*)&dtm->lastdbus, @@ -134,15 +134,16 @@ static uint64_t riscv_dtm_low_access(struct riscv_dtm *dtm, uint64_t dbus) static void riscv_dtm_write(struct riscv_dtm *dtm, uint32_t addr, uint64_t data) { uint64_t dbus = ((uint64_t)addr << 36) | - ((data & 0x3ffffffffull) << 2) | RISCV_DBUS_WRITE; + ((data & 0x3ffffffffull) << 2) | DBUS_WRITE; riscv_dtm_low_access(dtm, dbus); } static uint64_t riscv_dtm_read(struct riscv_dtm *dtm, uint32_t addr) { - riscv_dtm_low_access(dtm, ((uint64_t)addr << 36) | RISCV_DBUS_READ); - return riscv_dtm_low_access(dtm, RISCV_DBUS_NOP); + riscv_dtm_low_access(dtm, ((uint64_t)addr << 36) | DBUS_READ); + return riscv_dtm_low_access(dtm, DBUS_NOP); } + static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, const uint32_t code[], int count) { @@ -150,11 +151,11 @@ static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, for (i = 0; i < count - 1; i++) { riscv_dtm_write(dtm, i, code[i]); } - riscv_dtm_write(dtm, i, code[i] | RISCV_DMCONTROL_INTERRUPT); + riscv_dtm_write(dtm, i, code[i] | DMCONTROL_INTERRUPT); uint64_t ret; do { ret = riscv_dtm_read(dtm, count); - } while (ret & RISCV_DMCONTROL_INTERRUPT); + } while (ret & DMCONTROL_INTERRUPT); return ret; } @@ -297,7 +298,7 @@ static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t static void riscv_reset(target *t) { DEBUG("Resetting!\n"); - riscv_csreg_write(t->priv, RISCV_DCSR, 1 << 29); + riscv_csreg_write(t->priv, CSR_DCSR, 1 << 29); } bool riscv_check_error(target *t) @@ -332,13 +333,13 @@ static ssize_t riscv_reg_read(target *t, int reg, void *data, size_t s) *val = 0; break; case 8: - *val = riscv_csreg_read(dtm, RISCV_DSCRATCH); + *val = riscv_csreg_read(dtm, CSR_DSCRATCH); break; case 9: *val = riscv_dtm_read(dtm, dtm->dramsize); break; case 32: - *val = riscv_csreg_read(dtm, RISCV_DPC); + *val = riscv_csreg_read(dtm, CSR_DPC); break; case 65 ... 65 + 4095: *val = riscv_csreg_read(dtm, reg - 65); @@ -360,13 +361,13 @@ static void riscv_regs_write(target *t, const void *data) case 0: break; case 8: - riscv_csreg_write(dtm, RISCV_DSCRATCH, reg[i]); + riscv_csreg_write(dtm, CSR_DSCRATCH, reg[i]); break; case 9: riscv_dtm_write(dtm, dtm->dramsize, reg[i]); break; case 32: - riscv_csreg_write(dtm, RISCV_DPC, reg[i]); + riscv_csreg_write(dtm, CSR_DPC, reg[i]); break; default: riscv_gpreg_write(dtm, i, reg[i]); @@ -378,12 +379,12 @@ static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) { (void)watch; struct riscv_dtm *dtm = t->priv; - uint64_t dmcontrol = riscv_dtm_read(dtm, RISCV_DMCONTROL); + uint64_t dmcontrol = riscv_dtm_read(dtm, DBUS_DMCONTROL); DEBUG("dmcontrol = 0x%"PRIx64"\n", dmcontrol); - if (!dtm->halt_requested && (dmcontrol & RISCV_DMCONTROL_HALTNOT) == 0) + if (!dtm->halt_requested && (dmcontrol & DMCONTROL_HALTNOT) == 0) return TARGET_HALT_RUNNING; - uint32_t dcsr = riscv_csreg_read(dtm, RISCV_DCSR); + uint32_t dcsr = riscv_csreg_read(dtm, CSR_DCSR); uint8_t cause = (dcsr >> 6) & 7; DEBUG_WARN("cause = %d\n", cause); switch (cause) { @@ -404,7 +405,7 @@ void riscv_jtag_handler(jtag_dev_t *jd) uint32_t dtmcontrol = 0; DEBUG("Scanning RISC-V jtag dev at pos %d, idcode %08" PRIx32 "\n", jd->jd_dev, jd->jd_idcode); - jtag_dev_write_ir(&jtag_proc, jd->jd_dev, RISCV_IR_DTMCONTROL); + jtag_dev_write_ir(&jtag_proc, jd->jd_dev, IR_DTMCONTROL); jtag_dev_shift_dr(&jtag_proc, jd->jd_dev, (void*)&dtmcontrol, (void*)&dtmcontrol, 32); DEBUG("dtmcontrol = 0x%08x\n", dtmcontrol); uint8_t version = dtmcontrol & 0xf; @@ -425,9 +426,10 @@ void riscv_jtag_handler(jtag_dev_t *jd) DEBUG("dbusstat = %d\n", (dtmcontrol >> 8) & 3); riscv_dtm_reset(dtm); - jtag_dev_write_ir(&jtag_proc, jd->jd_dev, RISCV_IR_DBUS); + jtag_dev_write_ir(&jtag_proc, jd->jd_dev, IR_DBUS); - uint32_t dminfo = riscv_dtm_read(dtm, RISCV_DMINFO); + uint32_t dminfo = riscv_dtm_read(dtm, DBUS_DMINFO); + DEBUG("dminfo = %"PRIx32"\n", dminfo); uint8_t dmversion = ((dminfo >> 4) & 0xc) | (dminfo & 3); DEBUG("dminfo = %"PRIx32"\n", dminfo); DEBUG("\tloversion = %d\n", dmversion); @@ -484,48 +486,48 @@ static int riscv_breakwatch_set(target *t, struct breakwatch *bw) { struct riscv_dtm *dtm = t->priv; unsigned i; - uint32_t mcontrol = RISCV_MCONTROL_DMODE | RISCV_MCONTROL_ACTION_DEBUG | - RISCV_MCONTROL_ENABLE_MASK; + uint32_t mcontrol = CSR_MCONTROL_DMODE | CSR_MCONTROL_ACTION_DEBUG | + CSR_MCONTROL_ENABLE_MASK; switch (bw->type) { case TARGET_BREAK_HARD: - mcontrol |= RISCV_MCONTROL_EXECUTE; + mcontrol |= CSR_MCONTROL_EXECUTE; break; case TARGET_WATCH_WRITE: - mcontrol |= RISCV_MCONTROL_STORE; + mcontrol |= CSR_MCONTROL_STORE; break; case TARGET_WATCH_READ: - mcontrol |= RISCV_MCONTROL_LOAD; + mcontrol |= CSR_MCONTROL_LOAD; break; case TARGET_WATCH_ACCESS: - mcontrol |= RISCV_MCONTROL_LOAD | RISCV_MCONTROL_STORE; + mcontrol |= CSR_MCONTROL_LOAD | CSR_MCONTROL_STORE; break; default: return 1; } - uint32_t tselect_saved = riscv_csreg_read(dtm, RISCV_TSELECT); + uint32_t tselect_saved = riscv_csreg_read(dtm, CSR_TSELECT); for (i = 0; ; i++) { - riscv_csreg_write(dtm, RISCV_TSELECT, i); - if (riscv_csreg_read(dtm, RISCV_TSELECT) != i) + riscv_csreg_write(dtm, CSR_TSELECT, i); + if (riscv_csreg_read(dtm, CSR_TSELECT) != i) return -1; - uint32_t tdata1 = riscv_csreg_read(dtm, RISCV_MCONTROL); + uint32_t tdata1 = riscv_csreg_read(dtm, CSR_MCONTROL); uint8_t type = (tdata1 >> (32-4)) & 0xf; if ((type == 0)) return -1; if ((type == 2) && - ((tdata1 & RISCV_MCONTROL_ENABLE_MASK) == 0)) + ((tdata1 & CSR_MCONTROL_ENABLE_MASK) == 0)) break; } /* if we get here tselect = i is the index of our trigger */ bw->reserved[0] = i; - riscv_csreg_write(dtm, RISCV_MCONTROL, mcontrol); - riscv_csreg_write(dtm, RISCV_TDATA2, bw->addr); + riscv_csreg_write(dtm, CSR_MCONTROL, mcontrol); + riscv_csreg_write(dtm, CSR_TDATA2, bw->addr); /* Restore saved tselect */ - riscv_csreg_write(dtm, RISCV_TSELECT, tselect_saved); + riscv_csreg_write(dtm, CSR_TSELECT, tselect_saved); return 0; } @@ -533,12 +535,12 @@ static int riscv_breakwatch_clear(target *t, struct breakwatch *bw) { struct riscv_dtm *dtm = t->priv; unsigned i = bw->reserved[0]; - uint32_t tselect_saved = riscv_csreg_read(dtm, RISCV_TSELECT); + uint32_t tselect_saved = riscv_csreg_read(dtm, CSR_TSELECT); - riscv_csreg_write(dtm, RISCV_TSELECT, i); - riscv_csreg_write(dtm, RISCV_MCONTROL, 0); + riscv_csreg_write(dtm, CSR_TSELECT, i); + riscv_csreg_write(dtm, CSR_MCONTROL, 0); /* Restore saved tselect */ - riscv_csreg_write(dtm, RISCV_TSELECT, tselect_saved); + riscv_csreg_write(dtm, CSR_TSELECT, tselect_saved); return 0; } From 5b1a022ba2aa6e7f06728367809b597a8f9c4f12 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 29 Sep 2017 16:38:25 +1300 Subject: [PATCH 13/19] riscv: Catch exceptions in ram stubs --- src/target/riscv.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index a08992ce65b..5a9dd9e750f 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -77,6 +77,7 @@ struct riscv_dtm { uint8_t idle; /* Number of cycles required in run-test/idle */ uint8_t dramsize; /* Size of debug ram in words - 1 */ bool error; + bool exception; uint64_t lastdbus; bool halt_requested; }; @@ -152,11 +153,16 @@ static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, riscv_dtm_write(dtm, i, code[i]); } riscv_dtm_write(dtm, i, code[i] | DMCONTROL_INTERRUPT); - uint64_t ret; + uint64_t ex; do { - ret = riscv_dtm_read(dtm, count); - } while (ret & DMCONTROL_INTERRUPT); - return ret; + ex = riscv_dtm_read(dtm, dtm->dramsize); + } while (ex & DMCONTROL_INTERRUPT); + if ((uint32_t)ex != 0) { + DEBUG("%s exception 0x%"PRIx32"\n", __func__, (uint32_t)ex); + dtm->exception = true; + return 0; + } + return riscv_dtm_read(dtm, count); } static uint32_t riscv_mem_read32(struct riscv_dtm *dtm, uint32_t addr) @@ -307,6 +313,11 @@ bool riscv_check_error(target *t) if (dtm->error) { riscv_dtm_reset(dtm); dtm->error = false; + dtm->exception = false; + return true; + } + if (dtm->exception) { + dtm->exception = false; return true; } return false; From 240fd566467e80c243b274c94a376e49aeea2697 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 30 Sep 2017 20:56:08 +1300 Subject: [PATCH 14/19] riscv: Implement byte and halfword memory access Use macros as pseudo-assembler for instruction encodings --- src/target/riscv.c | 110 ++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 5a9dd9e750f..271a47762c6 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -48,6 +48,29 @@ #define DMCONTROL_INTERRUPT (1ull << 33) #define DMCONTROL_HALTNOT (1ull << 32) +#define OP_ITYPE(opcode, funct, rd, imm, rs1) \ + ((opcode) | ((funct) << 12) | ((rd) << 7) | ((rs1) << 15) | ((imm) << 20)) +#define OP_STYPE(opcode, funct, rs1, imm, rs2) \ + ((opcode) | ((funct) << 12) | ((rs1) << 15) | ((rs2) << 20) | \ + (((imm) & 0x1f) << 7) | (((imm) & 0xfe0) << 20)) +#define OPCODE_LOAD 0x03 +#define OPCODE_STORE 0x23 +#define OPCODE_OP_IMM 0x13 +#define OPCODE_JUMP 0x6f +#define OP_ADDI 0 +#define LB(rd, imm, base) OP_ITYPE(OPCODE_LOAD, 0, rd, imm, base) +#define LH(rd, imm, base) OP_ITYPE(OPCODE_LOAD, 1, rd, imm, base) +#define LW(rd, imm, base) OP_ITYPE(OPCODE_LOAD, 2, rd, imm, base) +#define SB(rs, imm, base) OP_STYPE(OPCODE_STORE, 0, base, imm, rs) +#define SH(rs, imm, base) OP_STYPE(OPCODE_STORE, 1, base, imm, rs) +#define SW(rs, imm, base) OP_STYPE(OPCODE_STORE, 2, base, imm, rs) +#define J(imm) (OPCODE_JUMP | ((imm) << 20)) +#define ADDI(rd, rs, imm) OP_ITYPE(OPCODE_OP_IMM, OP_ADDI, rd, imm, rs) +#define S0 8 +#define S1 9 +#define T0 5 +#define JRESUME(n) (J(0x804 - (0x400 + ((n) * 4)))) + #define CSR_TSELECT 0x7a0 #define CSR_MCONTROL 0x7a1 #define CSR_TDATA2 0x7a2 @@ -145,14 +168,13 @@ static uint64_t riscv_dtm_read(struct riscv_dtm *dtm, uint32_t addr) return riscv_dtm_low_access(dtm, DBUS_NOP); } -static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, - const uint32_t code[], int count) +static void ram_stub_write(struct riscv_dtm *dtm, int i, uint32_t inst, bool run) +{ + riscv_dtm_write(dtm, i, run ? DMCONTROL_INTERRUPT | inst : inst); +} + +static uint32_t ram_stub_result(struct riscv_dtm *dtm, int i) { - int i; - for (i = 0; i < count - 1; i++) { - riscv_dtm_write(dtm, i, code[i]); - } - riscv_dtm_write(dtm, i, code[i] | DMCONTROL_INTERRUPT); uint64_t ex; do { ex = riscv_dtm_read(dtm, dtm->dramsize); @@ -162,21 +184,18 @@ static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, dtm->exception = true; return 0; } - return riscv_dtm_read(dtm, count); + return riscv_dtm_read(dtm, i); } -static uint32_t riscv_mem_read32(struct riscv_dtm *dtm, uint32_t addr) +static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, + const uint32_t code[], int count) { - /* Debug RAM stub - * 400: 41002403 lw s0, 0x410(zero) - * 404: 00042483 lw s1, 0(s0) - * 408: 40902a23 sw s1, 0x414(zero) - * 40c: 3f80006f j 0 - * 410: dw addr - * 414: dw data - */ - uint32_t ram[] = {0x41002403, 0x42483, 0x40902a23, 0x3f80006f, addr}; - return riscv_debug_ram_exec(dtm, ram, 5); + int i; + for (i = 0; i < count - 1; i++) { + ram_stub_write(dtm, i, code[i], false); + } + ram_stub_write(dtm, i, code[i], true); + return ram_stub_result(dtm, count); } static void riscv_mem_write32(struct riscv_dtm *dtm, @@ -241,8 +260,11 @@ static void riscv_gpreg_write(struct riscv_dtm *dtm, uint8_t reg, uint32_t val) * 400: 40802403 lw , 0x408(zero) * 40c: 4000006f j 0 */ - uint32_t ram[] = {0x40002423, 0x4000006f, val}; - ram[0] |= reg << 7; + uint32_t ram[] = { + LW(reg, 0x408, 0), + JRESUME(1), + val + }; riscv_debug_ram_exec(dtm, ram, 3); } @@ -279,14 +301,43 @@ static void riscv_halt_resume(target *t, bool step) static void riscv_mem_read(target *t, void *dest, target_addr src, size_t len) { - uint32_t *d = dest; - assert((src & 3) == 0); - assert((len & 3) == 0); + struct riscv_dtm *dtm = t->priv; + int size = 0; + uint32_t load = 0; + switch ((src | len) & 3) { + case 0: + load = LW(S1, 0, T0); + size = 4; + break; + case 2: + load = LH(S1, 0, T0); + size = 2; + break; + case 1: + case 3: + load = LB(S1, 0, T0); + size = 1; + break; + } + uint32_t t0 = riscv_gpreg_read(dtm, T0); + ram_stub_write(dtm, 0, LW(T0, 0x410, 0), false); + ram_stub_write(dtm, 1, load, false); + ram_stub_write(dtm, 2, SW(S1, 0x410, 0), false); + ram_stub_write(dtm, 3, JRESUME(3), false); + ram_stub_write(dtm, 4, src, true); while (len) { - *d++ = riscv_mem_read32(t->priv, src); - src += 4; - len -= 4; + uint32_t r = ram_stub_result(dtm, 4); + switch (size) { + case 1: *(uint8_t*)dest = r; break; + case 2: *(uint16_t*)dest = r; break; + case 4: *(uint32_t*)dest = r; break; + } + len -= size; + dest += size; + if (len) + ram_stub_write(dtm, 0, ADDI(T0, T0, size), true); } + riscv_gpreg_write(dtm, T0, t0); } static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t len) @@ -461,12 +512,11 @@ void riscv_jtag_handler(jtag_dev_t *jd) DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 0)); DEBUG("%"PRIx32"\n", (uint32_t)riscv_dtm_read(dtm, 1)); for (int i = 0; i < dtm->dramsize + 1; i++) { - DEBUG("DebugRAM[%d] = %08"PRIx32"\n", i, - riscv_mem_read32(dtm, 0x400 + i*4)); + DEBUG("DebugRAM[%d] = %08"PRIx64"\n", i, + riscv_dtm_read(dtm, 0x400 + i*4)); } #else (void)riscv_dtm_write; - (void)riscv_mem_read32; #endif /* Allocate and set up new target */ target *t = target_new(); From 5ebb2edea83a6c17ae551a36587f1f18aa7c074c Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 30 Sep 2017 21:32:49 +1300 Subject: [PATCH 15/19] riscv: Fix breakpoints --- src/target/riscv.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 271a47762c6..ec3faf8ccf8 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -81,9 +81,11 @@ #define CSR_MCONTROL_DMODE (1<<(32-5)) #define CSR_MCONTROL_ENABLE_MASK (0xf << 3) -#define CSR_MCONTROL_LOAD (1 << 0) -#define CSR_MCONTROL_STORE (1 << 1) -#define CSR_MCONTROL_EXECUTE (1 << 2) +#define CSR_MCONTROL_R (1 << 0) +#define CSR_MCONTROL_W (1 << 1) +#define CSR_MCONTROL_X (1 << 2) +#define CSR_MCONTROL_RW (CSR_MCONTROL_R | CSR_MCONTROL_W) +#define CSR_MCONTROL_RWX (CSR_MCONTROL_RW | CSR_MCONTROL_X) #define CSR_MCONTROL_ACTION_DEBUG (1 << 12) /* GDB register map / target description */ @@ -552,16 +554,16 @@ static int riscv_breakwatch_set(target *t, struct breakwatch *bw) switch (bw->type) { case TARGET_BREAK_HARD: - mcontrol |= CSR_MCONTROL_EXECUTE; + mcontrol |= CSR_MCONTROL_X; break; case TARGET_WATCH_WRITE: - mcontrol |= CSR_MCONTROL_STORE; + mcontrol |= CSR_MCONTROL_W; break; case TARGET_WATCH_READ: - mcontrol |= CSR_MCONTROL_LOAD; + mcontrol |= CSR_MCONTROL_R; break; case TARGET_WATCH_ACCESS: - mcontrol |= CSR_MCONTROL_LOAD | CSR_MCONTROL_STORE; + mcontrol |= CSR_MCONTROL_RW; break; default: return 1; @@ -578,7 +580,8 @@ static int riscv_breakwatch_set(target *t, struct breakwatch *bw) if ((type == 0)) return -1; if ((type == 2) && - ((tdata1 & CSR_MCONTROL_ENABLE_MASK) == 0)) + (((tdata1 & CSR_MCONTROL_RWX) == 0) || + ((tdata1 & CSR_MCONTROL_ENABLE_MASK) == 0))) break; } /* if we get here tselect = i is the index of our trigger */ From 25c8839e313411f931f3d5b29b9488105bec6750 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 30 Sep 2017 20:56:08 +1300 Subject: [PATCH 16/19] riscv: Implement byte and halfword memory access Use macros as pseudo-assembler for instruction encodings --- src/target/riscv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index ec3faf8ccf8..847b061a344 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -315,8 +315,7 @@ static void riscv_mem_read(target *t, void *dest, target_addr src, size_t len) load = LH(S1, 0, T0); size = 2; break; - case 1: - case 3: + default: load = LB(S1, 0, T0); size = 1; break; From af2d3740b3979ee3dfca2f4198f27b692e7a04bd Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Mon, 2 Oct 2017 10:16:10 +1300 Subject: [PATCH 17/19] riscv: Implement byte and halfword memory writes --- src/target/riscv.c | 111 ++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 42 deletions(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 847b061a344..74ada5cccf6 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -105,6 +105,7 @@ struct riscv_dtm { bool exception; uint64_t lastdbus; bool halt_requested; + uint32_t saved_s1; }; static int riscv_breakwatch_set(target *t, struct breakwatch *); @@ -200,21 +201,6 @@ static uint32_t riscv_debug_ram_exec(struct riscv_dtm *dtm, return ram_stub_result(dtm, count); } -static void riscv_mem_write32(struct riscv_dtm *dtm, - uint32_t addr, uint32_t val) -{ - /* Debug RAM stub - * 400: 41002403 lw s0, 0x410(zero) - * 408: 41402483 lw s1, 0x414(zero) - * 404: 00942023 sw s1, 0(s0) - * 40c: 3f80006f j 0 - * 410: dw addr - * 414: dw data - */ - uint32_t ram[] = {0x41002403, 0x41402483, 0x942023, 0x3f80006f, addr, val}; - riscv_debug_ram_exec(dtm, ram, 5); -} - static uint32_t riscv_gpreg_read(struct riscv_dtm *dtm, uint8_t reg) { /* Debug RAM stub @@ -287,6 +273,7 @@ static void riscv_halt_resume(target *t, bool step) { DEBUG("Resume requested! step=%d\n", step); struct riscv_dtm *dtm = t->priv; + riscv_dtm_write(dtm, dtm->dramsize, dtm->saved_s1); /* Debug RAM stub - we patch in step bit as needed * 400: 7b006073 csrsi dcsr, 0 * 404: 7b047073 csrci dcsr, halt @@ -343,14 +330,47 @@ static void riscv_mem_read(target *t, void *dest, target_addr src, size_t len) static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t len) { - const uint32_t *s = src; - assert((dest & 3) == 0); - assert((len & 3) == 0); + struct riscv_dtm *dtm = t->priv; + int size; + uint32_t store; + bool first = false; + switch ((dest | len) & 3) { + case 0: + store = SW(S1, 0, T0); + size = 4; + break; + case 2: + store = SH(S1, 0, T0); + size = 2; + break; + default: + store = SB(S1, 0, T0); + size = 1; + break; + } + uint32_t t0 = riscv_gpreg_read(dtm, T0); + ram_stub_write(dtm, 0, LW(T0, 0x410, 0), false); + ram_stub_write(dtm, 1, LW(S1, 0x414, 0), false); + ram_stub_write(dtm, 2, store, false); + ram_stub_write(dtm, 3, JRESUME(3), false); + ram_stub_write(dtm, 4, dest, false); while (len) { - riscv_mem_write32(t->priv, dest, *s++); - dest += 4; - len -= 4; + uint32_t r = 0; + switch (size) { + case 1: r = *(uint8_t*)src; break; + case 2: r = *(uint16_t*)src; break; + case 4: r = *(uint32_t*)src; break; + } + ram_stub_write(dtm, 5, r, true); + ram_stub_result(dtm, 5); + len -= size; + src += size; + if (first) { + ram_stub_write(dtm, 0, ADDI(T0, T0, size), false); + first = false; + } } + riscv_gpreg_write(dtm, T0, t0); } static void riscv_reset(target *t) @@ -399,7 +419,7 @@ static ssize_t riscv_reg_read(target *t, int reg, void *data, size_t s) *val = riscv_csreg_read(dtm, CSR_DSCRATCH); break; case 9: - *val = riscv_dtm_read(dtm, dtm->dramsize); + *val = dtm->saved_s1; break; case 32: *val = riscv_csreg_read(dtm, CSR_DPC); @@ -415,27 +435,32 @@ static ssize_t riscv_reg_read(target *t, int reg, void *data, size_t s) return sizeof(*val); } -static void riscv_regs_write(target *t, const void *data) +static ssize_t riscv_reg_write(target *t, int reg, const void *data, size_t s) { + (void)s; struct riscv_dtm *dtm = t->priv; - const uint32_t *reg = data; - for (int i = 0; i < 33; i++) { - switch (i) { - case 0: - break; - case 8: - riscv_csreg_write(dtm, CSR_DSCRATCH, reg[i]); - break; - case 9: - riscv_dtm_write(dtm, dtm->dramsize, reg[i]); - break; - case 32: - riscv_csreg_write(dtm, CSR_DPC, reg[i]); - break; - default: - riscv_gpreg_write(dtm, i, reg[i]); - } + uint32_t val = *(uint32_t*)data; + switch (reg) { + case 0: + break; + case 1 ... 7: + case 10 ... 31: + riscv_gpreg_write(dtm, reg, val); + break; + case 8: + riscv_csreg_write(dtm, CSR_DSCRATCH, val); + break; + case 9: + dtm->saved_s1 = val; + break; + case 32: + riscv_csreg_write(dtm, CSR_DPC, val); + break; + case 65 ... 65 + 4095: + riscv_csreg_write(dtm, reg - 65, val); + break; } + return sizeof(val); } static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) @@ -450,8 +475,10 @@ static enum target_halt_reason riscv_halt_poll(target *t, target_addr *watch) uint32_t dcsr = riscv_csreg_read(dtm, CSR_DCSR); uint8_t cause = (dcsr >> 6) & 7; DEBUG_WARN("cause = %d\n", cause); + if (cause == 0) + return TARGET_HALT_RUNNING; + dtm->saved_s1 = riscv_dtm_read(dtm, dtm->dramsize); switch (cause) { - case 0: return TARGET_HALT_RUNNING; case 1: /* Software breakpoint */ case 2: /* Hardware trigger breakpoint */ return TARGET_HALT_BREAKPOINT; @@ -532,7 +559,7 @@ void riscv_jtag_handler(jtag_dev_t *jd) t->detach = riscv_detach; t->check_error = riscv_check_error; t->reg_read = riscv_reg_read; - t->regs_write = riscv_regs_write; + t->reg_write = riscv_reg_write; t->reset = riscv_reset; t->halt_request = riscv_halt_request; t->halt_poll = riscv_halt_poll; From 2f4cebaed76a0c2dd7e69ea6fb9b104b42031678 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Mon, 2 Oct 2017 11:29:01 +1300 Subject: [PATCH 18/19] riscv: Clean up reset --- src/target/riscv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/target/riscv.c b/src/target/riscv.c index 74ada5cccf6..fcf02ecc6f7 100644 --- a/src/target/riscv.c +++ b/src/target/riscv.c @@ -88,6 +88,10 @@ #define CSR_MCONTROL_RWX (CSR_MCONTROL_RW | CSR_MCONTROL_X) #define CSR_MCONTROL_ACTION_DEBUG (1 << 12) +#define CSR_DCSR_STEP (1 << 2) +#define CSR_DCSR_HALT (1 << 3) +#define CSR_DCSR_NDRESET (1 << 29) + /* GDB register map / target description */ static const char tdesc_rv32[] = "" @@ -376,7 +380,7 @@ static void riscv_mem_write(target *t, target_addr dest, const void *src, size_t static void riscv_reset(target *t) { DEBUG("Resetting!\n"); - riscv_csreg_write(t->priv, CSR_DCSR, 1 << 29); + riscv_csreg_write(t->priv, CSR_DCSR, CSR_DCSR_NDRESET | CSR_DCSR_HALT); } bool riscv_check_error(target *t) From d3447e1c76ebd799f4d76c7661782873cae83b85 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 5 Oct 2017 08:33:09 +1300 Subject: [PATCH 19/19] libftdi: Add HiFive 1 FTDI cable definition --- src/platforms/hosted/ftdi_bmp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/platforms/hosted/ftdi_bmp.c b/src/platforms/hosted/ftdi_bmp.c index 7d515f1cb9e..5d61c20dc78 100644 --- a/src/platforms/hosted/ftdi_bmp.c +++ b/src/platforms/hosted/ftdi_bmp.c @@ -164,6 +164,14 @@ cable_desc_t cable_desc[] = { .name = "ftdiswd", .description = "FTDISWD" }, + { + .vendor = 0x0403, + .product = 0x6010, + .interface = INTERFACE_A, + .init.data_low = PIN3, + .init.ddr_low = PIN4 | PIN3 | PIN1 | PIN0, + .name = "hifive1" + }, { .vendor = 0x15b1, .product = 0x0003,