Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cross-file/native-riscv.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ probe = 'native'
targets = 'riscv32,riscv64,gd32,rp'
rtt_support = false
bmd_bootloader = true
rvswd_support = true
26 changes: 26 additions & 0 deletions cross-file/swlink-riscv.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# This a cross-file for the native probe. It defines a default configuration profile that
# provides only support for both RISC-V architectures and support for RISC-V targets.

[binaries]
c = 'arm-none-eabi-gcc'
cpp = 'arm-none-eabi-g++'
ld = 'arm-none-eabi-gcc'
ar = 'arm-none-eabi-ar'
nm = 'arm-none-eabi-nm'
strip = 'arm-none-eabi-strip'
objcopy = 'arm-none-eabi-objcopy'
objdump = 'arm-none-eabi-objdump'
size = 'arm-none-eabi-size'

[host_machine]
system = 'bare-metal'
cpu_family = 'arm'
cpu = 'arm'
endian = 'little'

[project options]
probe = 'swlink'
targets = 'riscv32,riscv64,gd32,ch32v'
rtt_support = false
bmd_bootloader = false
rvswd_support = true
8 changes: 7 additions & 1 deletion src/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ static bool cmd_jtag_scan(target_s *target, int argc, const char **argv);
static bool cmd_swd_scan(target_s *target, int argc, const char **argv);
#if defined(CONFIG_RVSWD) && defined(PLATFORM_HAS_RVSWD)
static bool cmd_rvswd_scan(target_s *target, int argc, const char **argv);
#if CONFIG_BMDA == 0
bool bmp_rvswd_scan(void);
#endif
#endif
static bool cmd_onboard_flash_scan(target_s *target, int argc, const char **argv);
static bool cmd_auto_scan(target_s *target, int argc, const char **argv);
Expand Down Expand Up @@ -370,7 +373,7 @@ bool cmd_rvswd_scan(target_s *target, int argc, const char **argv)
#if CONFIG_BMDA == 1
scan_result = bmda_rvswd_scan();
#else
scan_result = false;
scan_result = bmp_rvswd_scan();
#endif
}
CATCH () {
Expand Down Expand Up @@ -423,6 +426,9 @@ bool cmd_auto_scan(target_s *target, int argc, const char **argv)
{
{jtag_scan, "JTAG"},
{adiv5_swd_scan, "SWD"},
#if defined(CONFIG_RVSWD) && defined(PLATFORM_HAS_RVSWD)
{bmp_rvswd_scan, "RVSWD"},
#endif
};
/* clang-format on */
#endif
Expand Down
1 change: 1 addition & 0 deletions src/platforms/common/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ platform_common_sources = files(
'aux_serial.c',
'jtagtap.c',
'swdptap.c',
'rvswdptap.c',
'usb.c',
'usb_dfu_stub.c',
'usb_serial.c',
Expand Down
255 changes: 255 additions & 0 deletions src/platforms/common/rvswdptap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by mean00
*
* 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 <http://www.gnu.org/licenses/>.
*/

/* This file implements the RVSW interface used by WCH chips */

#include "general.h"
#include "platform.h"
#include "timing.h"
#include "swd.h"
#include "maths_utils.h"
#include "swdptap_common.h"
#include "jep106.h"
#include "riscv_debug.h"

bool bmp_rvswd_scan(void);
// -- protocol part --
static bool rv_dm_reset(void);
static bool rv_start_frame(uint32_t adr, bool wr);
static bool rv_end_frame(uint32_t *status);

#define CLK_OFF() \
{ \
gpio_clear(SWCLK_PORT, SWCLK_PIN); \
for (volatile uint32_t counter = target_clk_divider + 1; counter > 0; --counter) \
__asm__("nop"); \
}
#define CLK_ON() \
{ \
gpio_set(SWCLK_PORT, SWCLK_PIN); \
for (volatile uint32_t counter = target_clk_divider + 1; counter > 0; --counter) \
__asm__("nop"); \
}

#define IO_OFF() \
{ \
gpio_clear(SWDIO_PORT, SWDIO_PIN); \
}
#define IO_ON() \
{ \
gpio_set(SWDIO_PORT, SWDIO_PIN); \
}

static void rv_write_nbits(int n, uint32_t value)
{
value <<= (uint32_t)(32 - n);
const uint32_t mask = 0x80000000UL;
for (int i = 0; i < n; i++) {
CLK_OFF();
if (value & mask)
IO_ON()
else
IO_OFF();
CLK_ON();
value <<= 1;
}
}

static void rv_start_bit(void)
{
SWDIO_MODE_DRIVE();
IO_OFF();
}

static void rv_stop_bit(void)
{
CLK_OFF();
SWDIO_MODE_DRIVE();
IO_OFF();
CLK_ON();
IO_ON();
}

static uint32_t rv_read_nbits(int n)
{
SWDIO_MODE_FLOAT();
uint32_t out = 0;
for (int i = 0; i < n; i++) {
CLK_OFF();
CLK_ON();
out = (out << 1) + (!!gpio_get(SWDIO_IN_PORT, SWDIO_IN_PIN)); // read bit on rising edge
}
return out;
}

static bool rv_dm_reset(void)
{
// toggle the clock 100 times
SWDIO_MODE_DRIVE();
IO_ON();
for (int i = 0; i < 5; i++) // 100 bits to 1
{
rv_write_nbits(20, 0xfffff);
}
IO_OFF();
IO_ON();
platform_delay(10);
return true;
}

static bool rv_start_frame(uint32_t adr, bool wr)
{
rv_start_bit();
adr = (adr << 1) + wr;
uint8_t parity = calculate_odd_parity(adr);
adr = adr << 2 | (parity + parity + parity);
rv_write_nbits(10, adr);
return true;
}

static bool rv_end_frame(uint32_t *status)
{
uint32_t out = 0;

// now get the reply - 4 bits
out = rv_read_nbits(4);
rv_stop_bit();

*status = out;
if (out != 3 && out != 7) {
DEBUG_ERROR("Status error : 0x%x\n", out);
return false;
}
return out;
}

bool rv_dm_write(uint32_t adr, uint32_t val)
{
rv_start_frame(adr, true);

rv_write_nbits(4, 0);
// Now data
uint8_t parity2 = calculate_odd_parity(val);
rv_write_nbits(32, val);

// data parity (twice)
rv_write_nbits(2, parity2 + parity2 + parity2);

uint32_t st = 0;
if (!rv_end_frame(&st)) {
DEBUG_ERROR("Write failed Adr=0x%x Value=0x%x status=0x%x\n", adr, val, st);
return false;
}
return true;
}

bool rv_dm_read(uint32_t adr, uint32_t *output)
{
rv_start_frame(adr, false);
rv_write_nbits(4, 1); // 000 1
*output = rv_read_nbits(32);
rv_read_nbits(2); // parity

uint32_t st = 0;
if (!rv_end_frame(&st)) {
DEBUG_ERROR("Read failed Adr=0x%x Value=0x%x status=0x%x\n", adr, *output, st);
return false;
}
return true;
}

static bool rv_dm_probe(uint32_t *chip_id)
{
*chip_id = 0;
uint32_t out = 0; // scratch
// This follows exactly what the wchlink does
rv_dm_write(0x10, 0x80000001UL); // write DM CTRL = 0x800000001
platform_delay(1);
rv_dm_write(0x10, 0x80000001UL); // write DM CTRL = 0x800000001
platform_delay(1);
rv_dm_read(0x11, &out); // read DM_STATUS
platform_delay(1);
rv_dm_read(0x7f, chip_id); // read 0x7f
return ((*chip_id) & 0x7fff) != 0x7fff;
}

//---------------------- RVSWD DMI -----------------------
static bool rvswdp_riscv_dmi_read(riscv_dmi_s *dmi, uint32_t address, uint32_t *value);
static bool rvswdp_riscv_dmi_write(riscv_dmi_s *dmi, uint32_t address, uint32_t value);

static bool rvswdp_riscv_dmi_read(riscv_dmi_s *const dmi, const uint32_t address, uint32_t *const value)
{
int retries = 1;
while (1) {
if (!retries) {
dmi->fault = RV_DMI_FAILURE;
return false;
}
const bool result = rv_dm_read(address, value);
if (result) {
dmi->fault = RV_DMI_SUCCESS;
return true;
}
retries--;
}
}

static bool rvswdp_riscv_dmi_write(riscv_dmi_s *const dmi, const uint32_t address, const uint32_t value)
{
const bool result = rv_dm_write(address, value);
if (result) {
dmi->fault = RV_DMI_SUCCESS;
return true;
}
dmi->fault = RV_DMI_FAILURE;
return false;
}

bool bmp_rvswd_scan(void)
{
uint32_t id = 0;
rv_dm_reset();
target_list_free();
if (!rv_dm_probe(&id)) {
return false;
}
DEBUG_INFO("WCH : found 0x%x device\n", id);
riscv_dmi_s *dmi = (riscv_dmi_s *)calloc(1, sizeof(riscv_dmi_s));
if (!dmi) { /* calloc failed: heap exhaustion */
DEBUG_ERROR("calloc: failed in %s\n", __func__);
return false;
}
dmi->designer_code = JEP106_MANUFACTURER_WCH;
dmi->version = RISCV_DEBUG_0_13; /* Assumption, unverified */
/*dmi->version = RISCV_DEBUG_NONSTANDARD;*/
dmi->address_width = 8U;
dmi->read = rvswdp_riscv_dmi_read;
dmi->write = rvswdp_riscv_dmi_write;

riscv_dmi_init(dmi);
/* If we failed to find any DMs or Harts, free the structure */
if (!dmi->ref_count) {
free(dmi);
return false;
}
return true;
}

// EOF
12 changes: 1 addition & 11 deletions src/platforms/common/swdptap.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,7 @@
#include "swd.h"
#include "maths_utils.h"

#if !defined(SWDIO_IN_PORT)
#define SWDIO_IN_PORT SWDIO_PORT
#endif
#if !defined(SWDIO_IN_PIN)
#define SWDIO_IN_PIN SWDIO_PIN
#endif

typedef enum swdio_status_e {
SWDIO_STATUS_FLOAT = 0,
SWDIO_STATUS_DRIVE
} swdio_status_t;
#include "swdptap_common.h"

swd_proc_s swd_proc;

Expand Down
13 changes: 13 additions & 0 deletions src/platforms/common/swdptap_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#if !defined(SWDIO_IN_PORT)
#define SWDIO_IN_PORT SWDIO_PORT
#endif
#if !defined(SWDIO_IN_PIN)
#define SWDIO_IN_PIN SWDIO_PIN
#endif

typedef enum swdio_status_e {
SWDIO_STATUS_FLOAT = 0,
SWDIO_STATUS_DRIVE
} swdio_status_t;
1 change: 1 addition & 0 deletions src/platforms/native/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#define PLATFORM_HAS_TRACESWO
#define PLATFORM_HAS_POWER_SWITCH
#define PLATFORM_HAS_RVSWD

#if ENABLE_DEBUG == 1
#define PLATFORM_HAS_DEBUG
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/swlink/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void platform_init(void)
/* Unmap JTAG Pins so we can reuse as GPIO */
data = AFIO_MAPR;
data &= ~AFIO_MAPR_SWJ_MASK;
data |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF;
data |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON;
AFIO_MAPR = data;
/* Setup JTAG GPIO ports */
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_INPUT_FLOAT, TMS_PIN);
Expand Down
Loading
Loading