Skip to content

Commit

Permalink
riscv_debug: move jtag dtm related functions to sepperate file
Browse files Browse the repository at this point in the history
  • Loading branch information
perigoso committed Feb 23, 2023
1 parent c151f19 commit e5a320a
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 180 deletions.
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ SRC = \
riscv32.c \
riscv64.c \
riscv_debug.c \
riscv_dtm_jtag.c \
rp.c \
sam3x.c \
sam4l.c \
Expand Down
6 changes: 3 additions & 3 deletions src/target/jtag_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "general.h"
#include "jtag_scan.h"
#include "adiv5.h"
#include "riscv_debug.h"
#include "riscv_dtm_jtag.h"
#include "jtag_devs.h"

const jtag_dev_descr_s dev_descr[] = {
Expand Down Expand Up @@ -111,13 +111,13 @@ const jtag_dev_descr_s dev_descr[] = {
.idcode = 0x0000563dU,
.idmask = 0x0fffffffU,
.descr = "RISC-V debug v0.13.",
.handler = riscv_debug_dtm_handler,
.handler = riscv_dtm_jtag_handler,
},
{
.idcode = 0x00005c25U,
.idmask = 0x0fffffffU,
.descr = "RISC-V debug v0.13.",
.handler = riscv_debug_dtm_handler,
.handler = riscv_dtm_jtag_handler,
.ir_quirks =
{
.ir_length = 5,
Expand Down
178 changes: 3 additions & 175 deletions src/target/riscv_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
#include "general.h"
#include "target_probe.h"
#include "target_internal.h"
#include "jtag_scan.h"
#include "jtagtap.h"
#include "gdb_reg.h"
#include "riscv_debug.h"

Expand All @@ -51,29 +49,8 @@
* https://github.com/riscv/riscv-debug-spec/blob/master/riscv-debug-stable.pdf
*/

#define IR_DTMCS 0x10U
#define IR_DMI 0x11U
#define IR_BYPASS 0x1fU

#define RV_DTMCS_NOOP 0x00000000U
#define RV_DTMCS_DMI_RESET 0x00010000U
#define RV_DTMCS_DMI_HARD_RESET 0x00020000U
#define RV_DTMCS_IDLE_CYCLES_MASK 0x00007000U
#define RV_DTMCS_IDLE_CYCLES_SHIFT 12U
#define RV_DTMCS_DMI_STATUS_MASK 0x00000c00U
#define RV_DTMCS_DMI_STATUS_SHIFT 10U
#define RV_DTMCS_ADDRESS_MASK 0x000003f0U
#define RV_DTMCS_ADDRESS_SHIFT 4U

#define RV_STATUS_VERSION_MASK 0x0000000fU

#define RV_DMI_NOOP 0U
#define RV_DMI_READ 1U
#define RV_DMI_WRITE 2U
#define RV_DMI_SUCCESS 0U
#define RV_DMI_FAILURE 2U
#define RV_DMI_TOO_SOON 3U

#define RV_DM_CONTROL 0x10U
#define RV_DM_STATUS 0x11U
#define RV_DM_NEXT_DM 0x1dU
Expand Down Expand Up @@ -203,18 +180,11 @@ static_assert(ARRAY_LENGTH(riscv_gpr_names) == ARRAY_LENGTH(riscv_gpr_types),
);
// clang-format on

static void riscv_dtm_init(riscv_dtm_s *dtm);
static void riscv_dm_init(riscv_dm_s *dbg_module);
static bool riscv_hart_init(riscv_hart_s *hart);
static void riscv_hart_free(void *priv);
static uint32_t riscv_shift_dtmcs(const riscv_dtm_s *dtm, uint32_t control);
static bool riscv_jtag_dmi_read(riscv_dtm_s *dtm, uint32_t address, uint32_t *value);
static bool riscv_jtag_dmi_write(riscv_dtm_s *dtm, uint32_t address, uint32_t value);
static void riscv_jtag_attach(target_s *target);
static void riscv_jtag_detach(target_s *target);
static void riscv_dm_ref(riscv_dm_s *dbg_module);
static void riscv_dm_unref(riscv_dm_s *dbg_module);
static riscv_debug_version_e riscv_dtmcs_version(uint32_t dtmcs);
static riscv_debug_version_e riscv_dm_version(uint32_t status);

static uint32_t riscv_hart_discover_isa(riscv_hart_s *hart);
Expand Down Expand Up @@ -243,59 +213,12 @@ static bool riscv_dmi_write(riscv_dtm_s *dtm, uint32_t address, uint32_t value)
return dtm->dmi_write(dtm, address, value);
}

void riscv_debug_dtm_handler(const uint8_t dev_index)
{
riscv_dtm_s *dtm = calloc(1, sizeof(*dtm));
if (!dtm) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
return;
}

dtm->dmi_read = riscv_jtag_dmi_read;
dtm->dmi_write = riscv_jtag_dmi_write;
dtm->dtm_attach = riscv_jtag_attach;
dtm->dtm_detach = riscv_jtag_detach;

/* Setup and try to discover the DMI bus */
dtm->dev_index = dev_index;
/*
* the code in JTAG_IDCODE_DESIGNER is in the form
* Bits 10:7 - JEP-106 Continuation code
* Bits 6:0 - JEP-106 Identity code
* here we convert it to our internal representation, See JEP-106 code list
*/
const uint16_t designer =
(jtag_devs[dev_index].jd_idcode & JTAG_IDCODE_DESIGNER_MASK) >> JTAG_IDCODE_DESIGNER_OFFSET;
dtm->designer_code =
(designer & JTAG_IDCODE_DESIGNER_JEP106_CONT_MASK) << 1U | (designer & JTAG_IDCODE_DESIGNER_JEP106_CODE_MASK);

riscv_dtm_init(dtm);

/* If we failed to find any DMs or Harts, free the structure */
if (!dtm->ref_count)
free(dtm);

/* Reset the JTAG machinary back to bypass to scan the next device in the chain */
jtag_dev_write_ir(dev_index, IR_BYPASS);
}

static void riscv_dtm_init(riscv_dtm_s *const dtm)
void riscv_dtm_init(riscv_dtm_s *const dtm)
{
const uint32_t dtmcs = riscv_shift_dtmcs(dtm, RV_DTMCS_NOOP);
dtm->version = riscv_dtmcs_version(dtmcs);
/* If we don't currently know how to talk to this DTM, warn and fail */
if (dtm->version == RISCV_DEBUG_UNKNOWN)
return;
if (dtm->version == RISCV_DEBUG_0_11) {
DEBUG_INFO("RISC-V debug v0.11 not presently supported\n");
if (!dtm || !dtm->dmi_read || !dtm->dmi_write) {
DEBUG_WARN("Invalid DTM structure in %s\n", __func__);
return;
}
/* Configure the TAP idle cylces based on what we've read */
dtm->idle_cycles = (dtmcs & RV_DTMCS_IDLE_CYCLES_MASK) >> RV_DTMCS_IDLE_CYCLES_SHIFT;
/* And figure out how many address bits the DMI address space has */
dtm->dmi_address_bits = (dtmcs & RV_DTMCS_ADDRESS_MASK) >> RV_DTMCS_ADDRESS_SHIFT;
/* Switch into DMI access mode for speed */
jtag_dev_write_ir(dtm->dev_index, IR_DMI);

/* Iterate through the possible DMs and probe implemented ones */
/* The first DM is always at base address 0 */
Expand Down Expand Up @@ -481,70 +404,6 @@ static void riscv_hart_free(void *const priv)
free(priv);
}

/* Shift (read + write) the Debug Transport Module Control/Status (DTMCS) register */
static uint32_t riscv_shift_dtmcs(const riscv_dtm_s *const dtm, const uint32_t control)
{
jtag_dev_write_ir(dtm->dev_index, IR_DTMCS);
uint32_t status = 0;
jtag_dev_shift_dr(dtm->dev_index, (uint8_t *)&status, (const uint8_t *)&control, 32);
return status;
}

static void riscv_dmi_reset(const riscv_dtm_s *const dtm)
{
riscv_shift_dtmcs(dtm, RV_DTMCS_DMI_RESET);
jtag_dev_write_ir(dtm->dev_index, IR_DMI);
}

static bool riscv_shift_dmi(riscv_dtm_s *const dtm, const uint8_t operation, const uint32_t address,
const uint32_t data_in, uint32_t *const data_out)
{
jtag_dev_s *device = &jtag_devs[dtm->dev_index];
jtagtap_shift_dr();
jtag_proc.jtagtap_tdi_seq(false, ones, device->dr_prescan);
/* Shift out the 2 bits for the operation, and get the status bits for the previous back */
uint8_t status = 0;
jtag_proc.jtagtap_tdi_tdo_seq(&status, false, &operation, 2);
/* Then the data component */
if (data_out)
jtag_proc.jtagtap_tdi_tdo_seq((uint8_t *)data_out, false, (const uint8_t *)&data_in, 32);
else
jtag_proc.jtagtap_tdi_seq(false, (const uint8_t *)&data_in, 32);
/* And finally the address component */
jtag_proc.jtagtap_tdi_seq(!device->dr_postscan, (const uint8_t *)&address, dtm->dmi_address_bits);
jtag_proc.jtagtap_tdi_seq(true, ones, device->dr_postscan);
jtagtap_return_idle(dtm->idle_cycles);
/* XXX: Need to deal with when status is 3. */
dtm->fault = status;
if (status == RV_DMI_FAILURE)
riscv_dmi_reset(dtm);
return status == RV_DMI_SUCCESS;
}

static bool riscv_jtag_dmi_read(riscv_dtm_s *const dtm, const uint32_t address, uint32_t *const value)
{
/* Setup the location to read from */
bool result = riscv_shift_dmi(dtm, RV_DMI_READ, address, 0, NULL);
if (result)
/* If that worked, read back the value and check the operation status */
result = riscv_shift_dmi(dtm, RV_DMI_NOOP, 0, 0, value);
if (!result)
DEBUG_WARN("JTAG DMI read at 0x%08" PRIx32 " failed with status %u\n", address, dtm->fault);
return result;
}

static bool riscv_jtag_dmi_write(riscv_dtm_s *const dtm, const uint32_t address, const uint32_t value)
{
/* Write a value to the requested register */
bool result = riscv_shift_dmi(dtm, RV_DMI_WRITE, address, value, NULL);
if (result)
/* If that worked, read back the operation status to ensure the write actually worked */
result = riscv_shift_dmi(dtm, RV_DMI_NOOP, 0, 0, NULL);
if (!result)
DEBUG_WARN("JTAG DMI write at 0x%08" PRIx32 " failed with status %u\n", address, dtm->fault);
return result;
}

bool riscv_dm_read(riscv_dm_s *dbg_module, const uint8_t address, uint32_t *const value)
{
return riscv_dmi_read(dbg_module->dtm, dbg_module->base + address, value);
Expand All @@ -555,23 +414,6 @@ bool riscv_dm_write(riscv_dm_s *dbg_module, const uint8_t address, const uint32_
return riscv_dmi_write(dbg_module->dtm, dbg_module->base + address, value);
}

static riscv_debug_version_e riscv_dtmcs_version(const uint32_t dtmcs)
{
uint8_t version = dtmcs & RV_STATUS_VERSION_MASK;
switch (version) {
case 0:
DEBUG_INFO("RISC-V debug v0.11 DMI\n");
return RISCV_DEBUG_0_11;
case 1:
/* The stable version of the spec (v1.0) does not currently provide a way to distinguish between */
/* a device built against v0.13 of the spec or v1.0 of the spec. They use the same value here. */
DEBUG_INFO("RISC-V debug v0.13/v1.0 DMI\n");
return RISCV_DEBUG_0_13;
}
DEBUG_INFO("Please report part with unknown RISC-V debug DMI version %x\n", version);
return RISCV_DEBUG_UNKNOWN;
}

static riscv_debug_version_e riscv_dm_version(const uint32_t status)
{
uint8_t version = status & RV_STATUS_VERSION_MASK;
Expand Down Expand Up @@ -866,20 +708,6 @@ bool riscv_config_trigger(riscv_hart_s *const hart, const uint32_t trigger, cons
return result;
}

static void riscv_jtag_attach(target_s *const target)
{
riscv_hart_s *const hart = riscv_hart_struct(target);
/* We put the TAP into bypass at the end of the JTAG handler and on detach, so put it back into DMI */
jtag_dev_write_ir(hart->dbg_module->dtm->dev_index, IR_DMI);
}

static void riscv_jtag_detach(target_s *const target)
{
riscv_hart_s *const hart = riscv_hart_struct(target);
/* On detaching, stick the TAP back into bypass */
jtag_dev_write_ir(hart->dbg_module->dtm->dev_index, IR_BYPASS);
}

static bool riscv_attach(target_s *const target)
{
riscv_hart_s *const hart = riscv_hart_struct(target);
Expand Down
4 changes: 2 additions & 2 deletions src/target/riscv_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ typedef struct riscv_hart {

#define RV_TOPT_INHIBIT_NRST 0x00000001U

void riscv_debug_dtm_handler(uint8_t dev_index);
void riscv_dtm_init(riscv_dtm_s *dtm);
riscv_hart_s *riscv_hart_struct(target_s *target);

bool riscv_dm_read(riscv_dm_s *dbg_module, uint8_t address, uint32_t *value);
Expand All @@ -194,4 +194,4 @@ uint8_t riscv_mem_access_width(const riscv_hart_s *hart, target_addr_t address,
void riscv32_unpack_data(void *dest, uint32_t data, uint8_t access_width);
uint32_t riscv32_pack_data(const void *src, uint8_t access_width);

#endif /*TARGET_RISCV_DEBUG_H*/
#endif /* TARGET_RISCV_DEBUG_H */
Loading

0 comments on commit e5a320a

Please sign in to comment.