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

Commit be7f5e6

Browse files
author
mean
committed
native: add rvswd implementation
1 parent 7e35068 commit be7f5e6

11 files changed

Lines changed: 295 additions & 12 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

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/blackpill-f401cc/platform.h

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

2626
#define PLATFORM_IDENT "(BlackPill-F401CC) "
2727
#define PLATFORM_CLOCK_FREQ RCC_CLOCK_3V3_84MHZ
28+
#define PLATFORM_HAS_RVSWD
2829

2930
#include "blackpill-f4.h"
3031

src/platforms/blackpill-f401ce/platform.h

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

2626
#define PLATFORM_IDENT "(BlackPill-F401CE) "
2727
#define PLATFORM_CLOCK_FREQ RCC_CLOCK_3V3_84MHZ
28+
#define PLATFORM_HAS_RVSWD
2829

2930
#include "blackpill-f4.h"
3031

src/platforms/blackpill-f411ce/platform.h

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

2626
#define PLATFORM_IDENT "(BlackPill-F411CE) "
2727
#define PLATFORM_CLOCK_FREQ RCC_CLOCK_3V3_96MHZ
28+
#define PLATFORM_HAS_RVSWD
2829

2930
#include "blackpill-f4.h"
3031

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

0 commit comments

Comments
 (0)