Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit 235fcaf

Browse files
author
mean
committed
add native rvswd implementation
1 parent ec31cd5 commit 235fcaf

10 files changed

Lines changed: 312 additions & 18 deletions

File tree

cross-file/native-riscv.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ probe = 'native'
2323
targets = 'riscv32,riscv64,gd32,rp'
2424
rtt_support = false
2525
bmd_bootloader = true
26+
rvswd_support = true

cross-file/swlink-riscv.ini

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This a cross-file for the native probe. It defines a default configuration profile that
2+
# provides only support for both RISC-V architectures and support for RISC-V targets.
3+
4+
[binaries]
5+
c = 'arm-none-eabi-gcc'
6+
cpp = 'arm-none-eabi-g++'
7+
ld = 'arm-none-eabi-gcc'
8+
ar = 'arm-none-eabi-ar'
9+
nm = 'arm-none-eabi-nm'
10+
strip = 'arm-none-eabi-strip'
11+
objcopy = 'arm-none-eabi-objcopy'
12+
objdump = 'arm-none-eabi-objdump'
13+
size = 'arm-none-eabi-size'
14+
15+
[host_machine]
16+
system = 'bare-metal'
17+
cpu_family = 'arm'
18+
cpu = 'arm'
19+
endian = 'little'
20+
21+
[project options]
22+
probe = 'swlink'
23+
targets = 'riscv32,riscv64,gd32,ch32v'
24+
rtt_support = false
25+
bmd_bootloader = false
26+
rvswd_support = true

src/command.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ static bool cmd_jtag_scan(target_s *target, int argc, const char **argv);
6363
static bool cmd_swd_scan(target_s *target, int argc, const char **argv);
6464
#if defined(CONFIG_RVSWD) && defined(PLATFORM_HAS_RVSWD)
6565
static bool cmd_rvswd_scan(target_s *target, int argc, const char **argv);
66+
#if CONFIG_BMDA == 0
67+
bool bmp_rvswd_scan(void);
68+
#endif
6669
#endif
6770
static bool cmd_onboard_flash_scan(target_s *target, int argc, const char **argv);
6871
static bool cmd_auto_scan(target_s *target, int argc, const char **argv);
@@ -370,7 +373,7 @@ bool cmd_rvswd_scan(target_s *target, int argc, const char **argv)
370373
#if CONFIG_BMDA == 1
371374
scan_result = bmda_rvswd_scan();
372375
#else
373-
scan_result = false;
376+
scan_result = bmp_rvswd_scan();
374377
#endif
375378
}
376379
CATCH () {
@@ -423,6 +426,9 @@ bool cmd_auto_scan(target_s *target, int argc, const char **argv)
423426
{
424427
{jtag_scan, "JTAG"},
425428
{adiv5_swd_scan, "SWD"},
429+
#if defined(CONFIG_RVSWD) && defined(PLATFORM_HAS_RVSWD)
430+
{bmp_rvswd_scan, "RVSWD"},
431+
#endif
426432
};
427433
/* clang-format on */
428434
#endif

src/platforms/common/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ platform_common_sources = files(
3434
'aux_serial.c',
3535
'jtagtap.c',
3636
'swdptap.c',
37+
'rvswdptap.c',
3738
'usb.c',
3839
'usb_dfu_stub.c',
3940
'usb_serial.c',

src/platforms/common/rvswdptap.c

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* This file is part of the Black Magic Debug project.
3+
*
4+
* Copyright (C) 2011 Black Sphere Technologies Ltd.
5+
* Written by mean00
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
/* This file implements the RVSW interface used by WCH chips */
22+
23+
#include "general.h"
24+
#include "platform.h"
25+
#include "timing.h"
26+
#include "swd.h"
27+
#include "maths_utils.h"
28+
#include "swdptap_common.h"
29+
#include "jep106.h"
30+
#include "riscv_debug.h"
31+
32+
bool bmp_rvswd_scan(void);
33+
// -- protocol part --
34+
static bool rv_dm_reset(void);
35+
static bool rv_start_frame(uint32_t adr, bool wr);
36+
static bool rv_end_frame(uint32_t *status);
37+
38+
#define CLK_OFF() \
39+
{ \
40+
gpio_clear(SWCLK_PORT, SWCLK_PIN); \
41+
for (volatile uint32_t counter = target_clk_divider + 1; counter > 0; --counter) \
42+
__asm__("nop"); \
43+
}
44+
#define CLK_ON() \
45+
{ \
46+
gpio_set(SWCLK_PORT, SWCLK_PIN); \
47+
for (volatile uint32_t counter = target_clk_divider + 1; counter > 0; --counter) \
48+
__asm__("nop"); \
49+
}
50+
51+
#define IO_OFF() \
52+
{ \
53+
gpio_clear(SWDIO_PORT, SWDIO_PIN); \
54+
}
55+
#define IO_ON() \
56+
{ \
57+
gpio_set(SWDIO_PORT, SWDIO_PIN); \
58+
}
59+
60+
static void rv_write_nbits(int n, uint32_t value)
61+
{
62+
value <<= (uint32_t)(32 - n);
63+
const uint32_t mask = 0x80000000UL;
64+
for (int i = 0; i < n; i++) {
65+
CLK_OFF();
66+
if (value & mask)
67+
IO_ON()
68+
else
69+
IO_OFF();
70+
CLK_ON();
71+
value <<= 1;
72+
}
73+
}
74+
75+
static void rv_start_bit(void)
76+
{
77+
SWDIO_MODE_DRIVE();
78+
IO_OFF();
79+
}
80+
81+
static void rv_stop_bit(void)
82+
{
83+
CLK_OFF();
84+
SWDIO_MODE_DRIVE();
85+
IO_OFF();
86+
CLK_ON();
87+
IO_ON();
88+
}
89+
90+
static uint32_t rv_read_nbits(int n)
91+
{
92+
SWDIO_MODE_FLOAT();
93+
uint32_t out = 0;
94+
for (int i = 0; i < n; i++) {
95+
CLK_OFF();
96+
CLK_ON();
97+
out = (out << 1) + (!!gpio_get(SWDIO_IN_PORT, SWDIO_IN_PIN)); // read bit on rising edge
98+
}
99+
return out;
100+
}
101+
102+
static bool rv_dm_reset(void)
103+
{
104+
// toggle the clock 100 times
105+
SWDIO_MODE_DRIVE();
106+
IO_ON();
107+
for (int i = 0; i < 5; i++) // 100 bits to 1
108+
{
109+
rv_write_nbits(20, 0xfffff);
110+
}
111+
IO_OFF();
112+
IO_ON();
113+
platform_delay(10);
114+
return true;
115+
}
116+
117+
static bool rv_start_frame(uint32_t adr, bool wr)
118+
{
119+
rv_start_bit();
120+
adr = (adr << 1) + wr;
121+
uint8_t parity = calculate_odd_parity(adr);
122+
adr = adr << 2 | (parity + parity + parity);
123+
rv_write_nbits(10, adr);
124+
return true;
125+
}
126+
127+
static bool rv_end_frame(uint32_t *status)
128+
{
129+
uint32_t out = 0;
130+
131+
// now get the reply - 4 bits
132+
out = rv_read_nbits(4);
133+
rv_stop_bit();
134+
135+
*status = out;
136+
if (out != 3 && out != 7) {
137+
DEBUG_ERROR("Status error : 0x%x\n", out);
138+
return false;
139+
}
140+
return out;
141+
}
142+
143+
bool rv_dm_write(uint32_t adr, uint32_t val)
144+
{
145+
rv_start_frame(adr, true);
146+
147+
rv_write_nbits(4, 0);
148+
// Now data
149+
uint8_t parity2 = calculate_odd_parity(val);
150+
rv_write_nbits(32, val);
151+
152+
// data parity (twice)
153+
rv_write_nbits(2, parity2 + parity2 + parity2);
154+
155+
uint32_t st = 0;
156+
if (!rv_end_frame(&st)) {
157+
DEBUG_ERROR("Write failed Adr=0x%x Value=0x%x status=0x%x\n", adr, val, st);
158+
return false;
159+
}
160+
return true;
161+
}
162+
163+
bool rv_dm_read(uint32_t adr, uint32_t *output)
164+
{
165+
rv_start_frame(adr, false);
166+
rv_write_nbits(4, 1); // 000 1
167+
*output = rv_read_nbits(32);
168+
rv_read_nbits(2); // parity
169+
170+
uint32_t st = 0;
171+
if (!rv_end_frame(&st)) {
172+
DEBUG_ERROR("Read failed Adr=0x%x Value=0x%x status=0x%x\n", adr, *output, st);
173+
return false;
174+
}
175+
return true;
176+
}
177+
178+
static bool rv_dm_probe(uint32_t *chip_id)
179+
{
180+
*chip_id = 0;
181+
uint32_t out = 0; // scratch
182+
// This follows exactly what the wchlink does
183+
rv_dm_write(0x10, 0x80000001UL); // write DM CTRL = 0x800000001
184+
platform_delay(1);
185+
rv_dm_write(0x10, 0x80000001UL); // write DM CTRL = 0x800000001
186+
platform_delay(1);
187+
rv_dm_read(0x11, &out); // read DM_STATUS
188+
platform_delay(1);
189+
rv_dm_read(0x7f, chip_id); // read 0x7f
190+
return ((*chip_id) & 0x7fff) != 0x7fff;
191+
}
192+
193+
//---------------------- RVSWD DMI -----------------------
194+
static bool rvswdp_riscv_dmi_read(riscv_dmi_s *dmi, uint32_t address, uint32_t *value);
195+
static bool rvswdp_riscv_dmi_write(riscv_dmi_s *dmi, uint32_t address, uint32_t value);
196+
197+
static bool rvswdp_riscv_dmi_read(riscv_dmi_s *const dmi, const uint32_t address, uint32_t *const value)
198+
{
199+
int retries = 1;
200+
while (1) {
201+
if (!retries) {
202+
dmi->fault = RV_DMI_FAILURE;
203+
return false;
204+
}
205+
const bool result = rv_dm_read(address, value);
206+
if (result) {
207+
dmi->fault = RV_DMI_SUCCESS;
208+
return true;
209+
}
210+
retries--;
211+
}
212+
}
213+
214+
static bool rvswdp_riscv_dmi_write(riscv_dmi_s *const dmi, const uint32_t address, const uint32_t value)
215+
{
216+
const bool result = rv_dm_write(address, value);
217+
if (result) {
218+
dmi->fault = RV_DMI_SUCCESS;
219+
return true;
220+
}
221+
dmi->fault = RV_DMI_FAILURE;
222+
return false;
223+
}
224+
225+
bool bmp_rvswd_scan(void)
226+
{
227+
uint32_t id = 0;
228+
rv_dm_reset();
229+
target_list_free();
230+
if (!rv_dm_probe(&id)) {
231+
return false;
232+
}
233+
DEBUG_INFO("WCH : found 0x%x device\n", id);
234+
riscv_dmi_s *dmi = (riscv_dmi_s *)calloc(1, sizeof(riscv_dmi_s));
235+
if (!dmi) { /* calloc failed: heap exhaustion */
236+
DEBUG_ERROR("calloc: failed in %s\n", __func__);
237+
return false;
238+
}
239+
dmi->designer_code = JEP106_MANUFACTURER_WCH;
240+
dmi->version = RISCV_DEBUG_0_13; /* Assumption, unverified */
241+
/*dmi->version = RISCV_DEBUG_NONSTANDARD;*/
242+
dmi->address_width = 8U;
243+
dmi->read = rvswdp_riscv_dmi_read;
244+
dmi->write = rvswdp_riscv_dmi_write;
245+
246+
riscv_dmi_init(dmi);
247+
/* If we failed to find any DMs or Harts, free the structure */
248+
if (!dmi->ref_count) {
249+
free(dmi);
250+
return false;
251+
}
252+
return true;
253+
}
254+
255+
// EOF

src/platforms/common/swdptap.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,7 @@
2626
#include "swd.h"
2727
#include "maths_utils.h"
2828

29-
#if !defined(SWDIO_IN_PORT)
30-
#define SWDIO_IN_PORT SWDIO_PORT
31-
#endif
32-
#if !defined(SWDIO_IN_PIN)
33-
#define SWDIO_IN_PIN SWDIO_PIN
34-
#endif
35-
36-
typedef enum swdio_status_e {
37-
SWDIO_STATUS_FLOAT = 0,
38-
SWDIO_STATUS_DRIVE
39-
} swdio_status_t;
29+
#include "swdptap_common.h"
4030

4131
swd_proc_s swd_proc;
4232

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#if !defined(SWDIO_IN_PORT)
4+
#define SWDIO_IN_PORT SWDIO_PORT
5+
#endif
6+
#if !defined(SWDIO_IN_PIN)
7+
#define SWDIO_IN_PIN SWDIO_PIN
8+
#endif
9+
10+
typedef enum swdio_status_e {
11+
SWDIO_STATUS_FLOAT = 0,
12+
SWDIO_STATUS_DRIVE
13+
} swdio_status_t;

src/platforms/native/platform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#define PLATFORM_HAS_TRACESWO
3131
#define PLATFORM_HAS_POWER_SWITCH
32+
#define PLATFORM_HAS_RVSWD
3233

3334
#if ENABLE_DEBUG == 1
3435
#define PLATFORM_HAS_DEBUG

src/platforms/swlink/platform.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void platform_init(void)
6363
/* Unmap JTAG Pins so we can reuse as GPIO */
6464
data = AFIO_MAPR;
6565
data &= ~AFIO_MAPR_SWJ_MASK;
66-
data |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF;
66+
data |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON;
6767
AFIO_MAPR = data;
6868
/* Setup JTAG GPIO ports */
6969
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_INPUT_FLOAT, TMS_PIN);

0 commit comments

Comments
 (0)