1
2
3
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
107
112
113
114
115
116
121
122
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
178
179
180
181
182
183
184
185
186
187
188
191
192
193
194
195
197
198
199
202
203
204
208
209
210
211
212
213
217
218
219
220
221
222
223
224
225
226
227
228
235
236
237
238
239
254
255
256
257
258
259
260
261
266
267
268
273
274
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
476
477
478
487
488
489
490
491
492
493
494
495
496
497
498
499
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
570
571
576
577
578
579
580
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
605
606
612
613
615
616
621
622
624
625
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
657
658
659
663
664
665
669
670
671
672
678
679
680
687
688
689
690
691
692
693
694
695
696
700
701
723
724
728
729
730
731
752
753
754
765
766
767
768
769
775
776
777
778
779
780
781
788
789
794
795
796
801
802
803
808
809
816
817
818
826
827
829
838
839
840
841
842
843
844
850
851
855
856
857
858
859
861
862
863
864
865
866
867
868
869
870
871
875
876
889
890
899
900
901
906
907
908
927
928
929
930
931
933
940
941
942
943
949
950
951
957
958
959
960
961
971
972
973
974
978
979
980
981
982
983
984
985
986
987
988
989
990
991
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1012
1013
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1092
1093
1094
1095
1096
1097
1098
1099
1100
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1191
1192
1193
1194
1195
1204
1205
1206
1207
1208
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1233
1234
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1253
1254
1255
1256
1257
1258
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1296
1297
1298
1299
1300
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1326
1327
1328
1329
1330
1331
1332
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1352
1353
1354
1355
1356
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1378
1379
1380
1381
1382
1383
1384
1385
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1428
1429
1430
1431
1432
1433
1434
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1456
1457
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1481
1486
1487
1488
1489
1490
1491
1492
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1519
1520
1521
1522
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1563
1564
1565
1566
1567
1568
1569
1570
1571
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1642
1643
1644
1645
1646
1647
1651
1652
1653
1654
1655
1656
1657
1659
1660
1661
1662
1663
1664
1665
1678
1682
1683
1684
1685
1688
1691
1694
1697
1700
1703
1708
1711
1714
1717
1720
1723
1726
1729
1732
1735
1738
1741
1744
1747
1750
1753
1756
1759
1762
1765
1768
1771
1774
1777
1780
1783
1786
1790
1791
1803
1804
1805
1806
1807
1808
1812
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1839
1843
1844
1845
1846
1849
1852
1855
1858
1859
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1905
1906
1907
1908
1909
1910
1911
1923
1924
1925
1926
1927
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1954
1955
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1994
1995
1996
1997
1998
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2043
2044
2045
2049
2050
2051
2052
2053
2054
2055
2068
2069
2070
2071
2072
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2107
2108
2109
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2193
2194
2195
2196
2213
2214
2215
2216
2217
2218
2219
2223
2224
2225
2226
2227
2228
2229
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2271
2272
2273
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
/* ... */
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "target/target.h"
#include "target/algorithm.h"
#include "target/target_type.h"
#include <helper/log.h>
#include "jtag/jtag.h"
#include "target/register.h"
#include "target/breakpoints.h"
#include "helper/time_support.h"
#include "riscv.h"
#include "asm.h"
#include "gdb_regs.h"
11 includes
/* ... */
/* ... */
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
#define CSR_BPCONTROL_X (1<<0)
#define CSR_BPCONTROL_W (1<<1)
#define CSR_BPCONTROL_R (1<<2)
#define CSR_BPCONTROL_U (1<<3)
#define CSR_BPCONTROL_S (1<<4)
#define CSR_BPCONTROL_H (1<<5)
#define CSR_BPCONTROL_M (1<<6)
#define CSR_BPCONTROL_BPMATCH (0xf<<7)
#define CSR_BPCONTROL_BPACTION (0xff<<11)
#define DEBUG_ROM_START 0x800
#define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4)
#define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8)
#define DEBUG_RAM_START 0x400
#define SETHALTNOT 0x10c
#define DTMCONTROL 0x10
#define DTMCONTROL_DBUS_RESET (1<<16)
#define DTMCONTROL_IDLE (7<<10)
#define DTMCONTROL_ADDRBITS (0xf<<4)
#define DTMCONTROL_VERSION (0xf)
#define DBUS 0x11
#define DBUS_OP_START 0
#define DBUS_OP_SIZE 2
24 definestypedef enum {
DBUS_OP_NOP = 0,
DBUS_OP_READ = 1,
DBUS_OP_WRITE = 2
...} dbus_op_t;
typedef enum {
DBUS_STATUS_SUCCESS = 0,
DBUS_STATUS_FAILED = 2,
DBUS_STATUS_BUSY = 3
...} dbus_status_t;
#define DBUS_DATA_START 2
#define DBUS_DATA_SIZE 34
#define DBUS_ADDRESS_START 36
typedef enum {
RE_OK,
RE_FAIL,
RE_AGAIN
...} riscv_error_t;
typedef enum slot {
SLOT0,
SLOT1,
SLOT_LAST,
...} slot_t;
#define DMCONTROL 0x10
#define DMCONTROL_INTERRUPT (((uint64_t)1)<<33)
#define DMCONTROL_HALTNOT (((uint64_t)1)<<32)
#define DMCONTROL_BUSERROR (7<<19)
#define DMCONTROL_SERIAL (3<<16)
#define DMCONTROL_AUTOINCREMENT (1<<15)
#define DMCONTROL_ACCESS (7<<12)
#define DMCONTROL_HARTID (0x3ff<<2)
#define DMCONTROL_NDRESET (1<<1)
#define DMCONTROL_FULLRESET 1
#define DMINFO 0x11
#define DMINFO_ABUSSIZE (0x7fU<<25)
#define DMINFO_SERIALCOUNT (0xf<<21)
#define DMINFO_ACCESS128 (1<<20)
#define DMINFO_ACCESS64 (1<<19)
#define DMINFO_ACCESS32 (1<<18)
#define DMINFO_ACCESS16 (1<<17)
#define DMINFO_ACCESS8 (1<<16)
#define DMINFO_DRAMSIZE (0x3f<<10)
#define DMINFO_AUTHENTICATED (1<<5)
#define DMINFO_AUTHBUSY (1<<4)
#define DMINFO_AUTHTYPE (3<<2)
#define DMINFO_VERSION 3
#define DMAUTHDATA0 0x12
#define DMAUTHDATA1 0x13
#define DBUS_ADDRESS_UNKNOWN 0xffff
#define DRAM_CACHE_SIZE 16
27 defines
struct trigger {
uint64_t address;
uint32_t length;
uint64_t mask;
uint64_t value;
bool read, write, execute;
int unique_id;
...};
struct memory_cache_line {
uint32_t data;
bool valid;
bool dirty;
...};
typedef struct {
uint8_t addrbits;
unsigned int dramsize;
uint64_t dcsr;
uint64_t dpc;
uint64_t tselect;
bool tselect_dirty;
/* ... */
uint64_t mstatus_actual;
struct memory_cache_line dram_cache[DRAM_CACHE_SIZE];
/* ... */
unsigned int dtmcontrol_idle;
/* ... */
unsigned int dbus_busy_delay;
/* ... */
unsigned int interrupt_high_delay;
bool never_halted;
...} riscv011_info_t;
typedef struct {
bool haltnot;
bool interrupt;
...} bits_t;
static int poll_target(struct target *target, bool announce);
static int riscv011_poll(struct target *target);
static int get_register(struct target *target, riscv_reg_t *value, int regid);
#define DEBUG_LENGTH 264
static riscv011_info_t *get_info(const struct target *target)
{
struct riscv_info *info = target->arch_info;
assert(info);
assert(info->version_specific);
return info->version_specific;
}{ ... }
static unsigned int slot_offset(const struct target *target, slot_t slot)
{
riscv011_info_t *info = get_info(target);
switch (riscv_xlen(target)) {
case 32:
switch (slot) {
case SLOT0: return 4;
case SLOT1: return 5;
case SLOT_LAST: return info->dramsize-1;
}switch (slot) { ... }
break;case 32:
case 64:
switch (slot) {
case SLOT0: return 4;
case SLOT1: return 6;
case SLOT_LAST: return info->dramsize-2;
}switch (slot) { ... }
case 64: }switch (riscv_xlen(target)) { ... }
LOG_ERROR("slot_offset called with xlen=%d, slot=%d",
riscv_xlen(target), slot);
assert(0);
return 0;
}{ ... }
static uint32_t load_slot(const struct target *target, unsigned int dest,
slot_t slot)
{
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
return load(target, dest, ZERO, offset);
}{ ... }
static uint32_t store_slot(const struct target *target, unsigned int src,
slot_t slot)
{
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
return store(target, src, ZERO, offset);
}{ ... }
static uint16_t dram_address(unsigned int index)
{
if (index < 0x10)
return index;
else
return 0x40 + index - 0x10;
}{ ... }
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
{
struct scan_field field;
uint8_t in_value[4];
uint8_t out_value[4] = { 0 };
buf_set_u32(out_value, 0, 32, out);
jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
field.num_bits = 32;
field.out_value = out_value;
field.in_value = in_value;
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("failed jtag scan: %d", retval);
return retval;
}if (retval != ERROR_OK) { ... }
uint32_t in = buf_get_u32(field.in_value, 0, 32);
LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in);
return in;
}{ ... }
static uint32_t idcode_scan(struct target *target)
{
struct scan_field field;
uint8_t in_value[4];
jtag_add_ir_scan(target->tap, &select_idcode, TAP_IDLE);
field.num_bits = 32;
field.out_value = NULL;
field.in_value = in_value;
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("failed jtag scan: %d", retval);
return retval;
}if (retval != ERROR_OK) { ... }
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
uint32_t in = buf_get_u32(field.in_value, 0, 32);
LOG_DEBUG("IDCODE: 0x0 -> 0x%x", in);
return in;
}{ ... }
static void increase_dbus_busy_delay(struct target *target)
{
riscv011_info_t *info = get_info(target);
info->dbus_busy_delay += info->dbus_busy_delay / 10 + 1;
LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d",
info->dtmcontrol_idle, info->dbus_busy_delay,
info->interrupt_high_delay);
dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET);
}{ ... }
static void increase_interrupt_high_delay(struct target *target)
{
riscv011_info_t *info = get_info(target);
info->interrupt_high_delay += info->interrupt_high_delay / 10 + 1;
LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d",
info->dtmcontrol_idle, info->dbus_busy_delay,
info->interrupt_high_delay);
}{ ... }
static void add_dbus_scan(const struct target *target, struct scan_field *field,
uint8_t *out_value, uint8_t *in_value, dbus_op_t op,
uint16_t address, uint64_t data)
{
riscv011_info_t *info = get_info(target);
RISCV_INFO(r);
if (r->reset_delays_wait >= 0) {
r->reset_delays_wait--;
if (r->reset_delays_wait < 0) {
info->dbus_busy_delay = 0;
info->interrupt_high_delay = 0;
}if (r->reset_delays_wait < 0) { ... }
}if (r->reset_delays_wait >= 0) { ... }
field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
field->in_value = in_value;
field->out_value = out_value;
buf_set_u64(out_value, DBUS_OP_START, DBUS_OP_SIZE, op);
buf_set_u64(out_value, DBUS_DATA_START, DBUS_DATA_SIZE, data);
buf_set_u64(out_value, DBUS_ADDRESS_START, info->addrbits, address);
jtag_add_dr_scan(target->tap, 1, field, TAP_IDLE);
int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay;
if (data & DMCONTROL_INTERRUPT)
idle_count += info->interrupt_high_delay;
if (idle_count)
jtag_add_runtest(idle_count, TAP_IDLE);
}{ ... }
static void dump_field(const struct scan_field *field)
{
static const char * const op_string[] = {"nop", "r", "w", "?"};
static const char * const status_string[] = {"+", "?", "F", "b"};
if (debug_level < LOG_LVL_DEBUG)
return;
uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
unsigned int out_op = (out >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1);
char out_interrupt = ((out >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.';
char out_haltnot = ((out >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.';
unsigned int out_data = out >> 2;
unsigned int out_address = out >> DBUS_ADDRESS_START;
uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
unsigned int in_op = (in >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1);
char in_interrupt = ((in >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.';
char in_haltnot = ((in >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.';
unsigned int in_data = in >> 2;
unsigned int in_address = in >> DBUS_ADDRESS_START;
log_printf_lf(LOG_LVL_DEBUG,
__FILE__, __LINE__, "scan",
"%ub %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x",
field->num_bits,
op_string[out_op], out_interrupt, out_haltnot, out_data,
out_address,
status_string[in_op], in_interrupt, in_haltnot, in_data,
in_address);
}{ ... }
static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in,
uint64_t *data_in, dbus_op_t op, uint16_t address_out, uint64_t data_out)
{
riscv011_info_t *info = get_info(target);
uint8_t in[8] = {0};
uint8_t out[8] = {0};
struct scan_field field = {
.num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE,
.out_value = out,
.in_value = in
...};
assert(info->addrbits != 0);
buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op);
buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out);
buf_set_u64(out, DBUS_ADDRESS_START, info->addrbits, address_out);
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay;
if (idle_count)
jtag_add_runtest(idle_count, TAP_IDLE);
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("dbus_scan failed jtag scan");
return DBUS_STATUS_FAILED;
}if (retval != ERROR_OK) { ... }
if (data_in)
*data_in = buf_get_u64(in, DBUS_DATA_START, DBUS_DATA_SIZE);
if (address_in)
*address_in = buf_get_u32(in, DBUS_ADDRESS_START, info->addrbits);
dump_field(&field);
return buf_get_u32(in, DBUS_OP_START, DBUS_OP_SIZE);
}{ ... }
static uint64_t dbus_read(struct target *target, uint16_t address)
{
uint64_t value;
dbus_status_t status;
uint16_t address_in;
/* ... */
unsigned i = 0;
do {
status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0);
if (status == DBUS_STATUS_BUSY)
increase_dbus_busy_delay(target);
if (status == DBUS_STATUS_FAILED) {
LOG_ERROR("dbus_read(0x%x) failed!", address);
return 0;
}if (status == DBUS_STATUS_FAILED) { ... }
...} while (((status == DBUS_STATUS_BUSY) || (address_in != address)) &&
i++ < 256);
if (status != DBUS_STATUS_SUCCESS)
LOG_ERROR("failed read from 0x%x; value=0x%" PRIx64 ", status=%d\n", address, value, status);
return value;
}{ ... }
static void dbus_write(struct target *target, uint16_t address, uint64_t value)
{
dbus_status_t status = DBUS_STATUS_BUSY;
unsigned i = 0;
while (status == DBUS_STATUS_BUSY && i++ < 256) {
status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value);
if (status == DBUS_STATUS_BUSY)
increase_dbus_busy_delay(target);
}while (status == DBUS_STATUS_BUSY && i++ < 256) { ... }
if (status != DBUS_STATUS_SUCCESS)
LOG_ERROR("failed to write 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status);
}{ ... }
typedef struct {
unsigned int scan_count;
unsigned int scan_size;
unsigned int next_scan;
uint8_t *in;
uint8_t *out;
struct scan_field *field;
const struct target *target;
...} scans_t;
static scans_t *scans_new(struct target *target, unsigned int scan_count)
{
scans_t *scans = malloc(sizeof(scans_t));
if (!scans)
goto error0;
scans->scan_count = scan_count;
if (riscv_xlen(target))
scans->scan_size = 2 + riscv_xlen(target) / 8;
else
scans->scan_size = 2 + 128 / 8;
scans->next_scan = 0;
scans->in = calloc(scans->scan_size, scans->scan_count);
if (!scans->in)
goto error1;
scans->out = calloc(scans->scan_size, scans->scan_count);
if (!scans->out)
goto error2;
scans->field = calloc(scans->scan_count, sizeof(struct scan_field));
if (!scans->field)
goto error3;
scans->target = target;
return scans;
error3:
free(scans->out);
error2:
free(scans->in);
error1:
free(scans);
error0:
return NULL;
}{ ... }
static scans_t *scans_delete(scans_t *scans)
{
assert(scans);
free(scans->field);
free(scans->out);
free(scans->in);
free(scans);
return NULL;
}{ ... }
static void scans_reset(scans_t *scans)
{
scans->next_scan = 0;
}{ ... }
static void scans_dump(scans_t *scans)
{
for (unsigned int i = 0; i < scans->next_scan; i++)
dump_field(&scans->field[i]);
}{ ... }
static int scans_execute(scans_t *scans)
{
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("failed jtag scan: %d", retval);
return retval;
}if (retval != ERROR_OK) { ... }
scans_dump(scans);
return ERROR_OK;
}{ ... }
static void scans_add_write32(scans_t *scans, uint16_t address, uint32_t data,
bool set_interrupt)
{
const unsigned int i = scans->next_scan;
int data_offset = scans->scan_size * i;
add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset,
scans->in + data_offset, DBUS_OP_WRITE, address,
(set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT | data);
scans->next_scan++;
assert(scans->next_scan <= scans->scan_count);
}{ ... }
/* ... */
static void scans_add_write_jump(scans_t *scans, uint16_t address,
bool set_interrupt)
{
scans_add_write32(scans, address,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*address))),
set_interrupt);
}{ ... }
/* ... */
static void scans_add_write_load(scans_t *scans, uint16_t address,
unsigned int reg, slot_t slot, bool set_interrupt)
{
scans_add_write32(scans, address, load_slot(scans->target, reg, slot),
set_interrupt);
}{ ... }
/* ... */
static void scans_add_write_store(scans_t *scans, uint16_t address,
unsigned int reg, slot_t slot, bool set_interrupt)
{
scans_add_write32(scans, address, store_slot(scans->target, reg, slot),
set_interrupt);
}{ ... }
static void scans_add_read32(scans_t *scans, uint16_t address, bool set_interrupt)
{
assert(scans->next_scan < scans->scan_count);
const unsigned int i = scans->next_scan;
int data_offset = scans->scan_size * i;
add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset,
scans->in + data_offset, DBUS_OP_READ, address,
(set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT);
scans->next_scan++;
}{ ... }
static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt)
{
const struct target *target = scans->target;
switch (riscv_xlen(target)) {
case 32:
scans_add_read32(scans, slot_offset(target, slot), set_interrupt);
break;case 32:
case 64:
scans_add_read32(scans, slot_offset(target, slot), false);
scans_add_read32(scans, slot_offset(target, slot) + 1, set_interrupt);
break;case 64:
}switch (riscv_xlen(target)) { ... }
}{ ... }
static uint32_t scans_get_u32(scans_t *scans, unsigned int index,
unsigned first, unsigned num)
{
return buf_get_u32(scans->in + scans->scan_size * index, first, num);
}{ ... }
static uint64_t scans_get_u64(scans_t *scans, unsigned int index,
unsigned first, unsigned num)
{
return buf_get_u64(scans->in + scans->scan_size * index, first, num);
}{ ... }
static uint32_t dram_read32(struct target *target, unsigned int index)
{
uint16_t address = dram_address(index);
uint32_t value = dbus_read(target, address);
return value;
}{ ... }
static void dram_write32(struct target *target, unsigned int index, uint32_t value,
bool set_interrupt)
{
uint64_t dbus_value = DMCONTROL_HALTNOT | value;
if (set_interrupt)
dbus_value |= DMCONTROL_INTERRUPT;
dbus_write(target, dram_address(index), dbus_value);
}{ ... }
static bits_t read_bits(struct target *target)
{
uint64_t value;
dbus_status_t status;
uint16_t address_in;
riscv011_info_t *info = get_info(target);
bits_t err_result = {
.haltnot = 0,
.interrupt = 0
...};
do {
unsigned i = 0;
do {
status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, 0, 0);
if (status == DBUS_STATUS_BUSY) {
if (address_in == (1<<info->addrbits) - 1 &&
value == (1ULL<<DBUS_DATA_SIZE) - 1) {
LOG_ERROR("TDO seems to be stuck high.");
return err_result;
}if (address_in == (1<addrbits) - 1 && value == (1ULL<
increase_dbus_busy_delay(target);
}if (status == DBUS_STATUS_BUSY) { ... } else if (status == DBUS_STATUS_FAILED) {
return err_result;
}else if (status == DBUS_STATUS_FAILED) { ... }
...} while (status == DBUS_STATUS_BUSY && i++ < 256);
if (i >= 256) {
LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status);
return err_result;
}if (i >= 256) { ... }
...} while (address_in > 0x10 && address_in != DMCONTROL);
bits_t result = {
.haltnot = get_field(value, DMCONTROL_HALTNOT),
.interrupt = get_field(value, DMCONTROL_INTERRUPT)
...};
return result;
}{ ... }
static int wait_for_debugint_clear(struct target *target, bool ignore_first)
{
time_t start = time(NULL);
if (ignore_first) {
/* ... */
read_bits(target);
}if (ignore_first) { ... }
while (1) {
bits_t bits = read_bits(target);
if (!bits.interrupt)
return ERROR_OK;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out waiting for debug int to clear."
"Increase timeout with riscv set_command_timeout_sec.");
return ERROR_FAIL;
}if (time(NULL) - start > riscv_command_timeout_sec) { ... }
}while (1) { ... }
}{ ... }
static int dram_check32(struct target *target, unsigned int index,
uint32_t expected)
{
uint16_t address = dram_address(index);
uint32_t actual = dbus_read(target, address);
if (expected != actual) {
LOG_ERROR("Wrote 0x%x to Debug RAM at %d, but read back 0x%x",
expected, index, actual);
return ERROR_FAIL;
}if (expected != actual) { ... }
return ERROR_OK;
}{ ... }
static void cache_set32(struct target *target, unsigned int index, uint32_t data)
{
riscv011_info_t *info = get_info(target);
if (info->dram_cache[index].valid &&
info->dram_cache[index].data == data) {
LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data);
return;
}if (info->dram_cache[index].valid && info->dram_cache[index].data == data) { ... }
LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x)", index, data, data);
info->dram_cache[index].data = data;
info->dram_cache[index].valid = true;
info->dram_cache[index].dirty = true;
}{ ... }
static void cache_set(struct target *target, slot_t slot, uint64_t data)
{
unsigned int offset = slot_offset(target, slot);
cache_set32(target, offset, data);
if (riscv_xlen(target) > 32)
cache_set32(target, offset + 1, data >> 32);
}{ ... }
static void cache_set_jump(struct target *target, unsigned int index)
{
cache_set32(target, index,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))));
}{ ... }
static void cache_set_load(struct target *target, unsigned int index,
unsigned int reg, slot_t slot)
{
uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
cache_set32(target, index, load(target, reg, ZERO, offset));
}{ ... }
static void cache_set_store(struct target *target, unsigned int index,
unsigned int reg, slot_t slot)
{
uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
cache_set32(target, index, store(target, reg, ZERO, offset));
}{ ... }
static void dump_debug_ram(struct target *target)
{
for (unsigned int i = 0; i < DRAM_CACHE_SIZE; i++) {
uint32_t value = dram_read32(target, i);
LOG_ERROR("Debug RAM 0x%x: 0x%08x", i, value);
}for (unsigned int i = 0; i < DRAM_CACHE_SIZE; i++) { ... }
}{ ... }
static void cache_invalidate(struct target *target)
{
riscv011_info_t *info = get_info(target);
for (unsigned int i = 0; i < info->dramsize; i++) {
info->dram_cache[i].valid = false;
info->dram_cache[i].dirty = false;
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
}{ ... }
/* ... */
static void cache_clean(struct target *target)
{
riscv011_info_t *info = get_info(target);
for (unsigned int i = 0; i < info->dramsize; i++) {
if (i >= 4)
info->dram_cache[i].valid = false;
info->dram_cache[i].dirty = false;
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
}{ ... }
static int cache_check(struct target *target)
{
riscv011_info_t *info = get_info(target);
int error = 0;
for (unsigned int i = 0; i < info->dramsize; i++) {
if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) {
if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK)
error++;
}if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) { ... }
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
if (error) {
dump_debug_ram(target);
return ERROR_FAIL;
}if (error) { ... }
return ERROR_OK;
}{ ... }
/* ... */
#define CACHE_NO_READ 128
static int cache_write(struct target *target, unsigned int address, bool run)
{
LOG_DEBUG("enter");
riscv011_info_t *info = get_info(target);
scans_t *scans = scans_new(target, info->dramsize + 2);
if (!scans)
return ERROR_FAIL;
unsigned int last = info->dramsize;
for (unsigned int i = 0; i < info->dramsize; i++) {
if (info->dram_cache[i].dirty)
last = i;
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
if (last == info->dramsize) {
dbus_write(target, DMCONTROL, DMCONTROL_HALTNOT | (run ? DMCONTROL_INTERRUPT : 0));
}if (last == info->dramsize) { ... } else {
for (unsigned int i = 0; i < info->dramsize; i++) {
if (info->dram_cache[i].dirty) {
bool set_interrupt = (i == last && run);
scans_add_write32(scans, i, info->dram_cache[i].data,
set_interrupt);
}if (info->dram_cache[i].dirty) { ... }
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
}else { ... }
if (run || address < CACHE_NO_READ) {
/* ... */
scans_add_read32(scans, address, false);
/* ... */
scans_add_read32(scans, address, false);
}if (run || address < CACHE_NO_READ) { ... }
int retval = scans_execute(scans);
if (retval != ERROR_OK) {
scans_delete(scans);
LOG_ERROR("JTAG execute failed.");
return retval;
}if (retval != ERROR_OK) { ... }
int errors = 0;
for (unsigned int i = 0; i < scans->next_scan; i++) {
dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START,
DBUS_OP_SIZE);
switch (status) {
case DBUS_STATUS_SUCCESS:
break;case DBUS_STATUS_SUCCESS:
case DBUS_STATUS_FAILED:
LOG_ERROR("Debug RAM write failed. Hardware error?");
scans_delete(scans);
return ERROR_FAIL;case DBUS_STATUS_FAILED:
case DBUS_STATUS_BUSY:
errors++;
break;case DBUS_STATUS_BUSY:
default:
LOG_ERROR("Got invalid bus access status: %d", status);
scans_delete(scans);
return ERROR_FAIL;default
}switch (status) { ... }
}for (unsigned int i = 0; i < scans->next_scan; i++) { ... }
if (errors) {
increase_dbus_busy_delay(target);
/* ... */
for (unsigned int i = 0; i < info->dramsize; i++) {
if (i == last && run)
dram_write32(target, last, info->dram_cache[last].data, true);
else
dram_write32(target, i, info->dram_cache[i].data, false);
info->dram_cache[i].dirty = false;
}for (unsigned int i = 0; i < info->dramsize; i++) { ... }
if (run)
cache_clean(target);
if (wait_for_debugint_clear(target, true) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
dump_debug_ram(target);
scans_delete(scans);
return ERROR_FAIL;
}if (wait_for_debugint_clear(target, true) != ERROR_OK) { ... }
}if (errors) { ... } else {
if (run) {
cache_clean(target);
}if (run) { ... } else {
for (unsigned int i = 0; i < info->dramsize; i++)
info->dram_cache[i].dirty = false;
}else { ... }
if (run || address < CACHE_NO_READ) {
int interrupt = scans_get_u32(scans, scans->next_scan-1,
DBUS_DATA_START + 33, 1);
if (interrupt) {
increase_interrupt_high_delay(target);
if (wait_for_debugint_clear(target, false) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
dump_debug_ram(target);
scans_delete(scans);
return ERROR_FAIL;
}if (wait_for_debugint_clear(target, false) != ERROR_OK) { ... }
}if (interrupt) { ... } else {
unsigned int read_addr = scans_get_u32(scans, scans->next_scan-1,
DBUS_ADDRESS_START, info->addrbits);
if (read_addr != address) {
LOG_INFO("Got data from 0x%x but expected it from 0x%x",
read_addr, address);
}if (read_addr != address) { ... }
info->dram_cache[read_addr].data =
scans_get_u32(scans, scans->next_scan-1, DBUS_DATA_START, 32);
info->dram_cache[read_addr].valid = true;
}else { ... }
}if (run || address < CACHE_NO_READ) { ... }
}else { ... }
scans_delete(scans);
LOG_DEBUG("exit");
return ERROR_OK;
}{ ... }
static uint32_t cache_get32(struct target *target, unsigned int address)
{
riscv011_info_t *info = get_info(target);
if (!info->dram_cache[address].valid) {
info->dram_cache[address].data = dram_read32(target, address);
info->dram_cache[address].valid = true;
}if (!info->dram_cache[address].valid) { ... }
return info->dram_cache[address].data;
}{ ... }
static uint64_t cache_get(struct target *target, slot_t slot)
{
unsigned int offset = slot_offset(target, slot);
uint64_t value = cache_get32(target, offset);
if (riscv_xlen(target) > 32)
value |= ((uint64_t) cache_get32(target, offset + 1)) << 32;
return value;
}{ ... }
/* ... */
static void dram_write_jump(struct target *target, unsigned int index,
bool set_interrupt)
{
dram_write32(target, index,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))),
set_interrupt);
}{ ... }
static int wait_for_state(struct target *target, enum target_state state)
{
time_t start = time(NULL);
while (1) {
int result = riscv011_poll(target);
if (result != ERROR_OK)
return result;
if (target->state == state)
return ERROR_OK;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out waiting for state %d. "
"Increase timeout with riscv set_command_timeout_sec.", state);
return ERROR_FAIL;
}if (time(NULL) - start > riscv_command_timeout_sec) { ... }
}while (1) { ... }
}{ ... }
static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
{
riscv011_info_t *info = get_info(target);
cache_set32(target, 0, csrr(S0, csr));
cache_set_store(target, 1, S0, SLOT0);
cache_set_jump(target, 2);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
*value = cache_get(target, SLOT0);
LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value);
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception,
gdb_regno_name(GDB_REGNO_CSR0 + csr));
*value = ~0;
return ERROR_FAIL;
}if (exception) { ... }
return ERROR_OK;
}{ ... }
static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value)
{
LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, csr));
cache_set_jump(target, 2);
cache_set(target, SLOT0, value);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}{ ... }
static int write_gpr(struct target *target, unsigned int gpr, uint64_t value)
{
cache_set_load(target, 0, gpr, SLOT0);
cache_set_jump(target, 1);
cache_set(target, SLOT0, value);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}{ ... }
static int maybe_read_tselect(struct target *target)
{
riscv011_info_t *info = get_info(target);
if (info->tselect_dirty) {
int result = read_remote_csr(target, &info->tselect, CSR_TSELECT);
if (result != ERROR_OK)
return result;
info->tselect_dirty = false;
}if (info->tselect_dirty) { ... }
return ERROR_OK;
}{ ... }
static int maybe_write_tselect(struct target *target)
{
riscv011_info_t *info = get_info(target);
if (!info->tselect_dirty) {
int result = write_remote_csr(target, CSR_TSELECT, info->tselect);
if (result != ERROR_OK)
return result;
info->tselect_dirty = true;
}if (!info->tselect_dirty) { ... }
return ERROR_OK;
}{ ... }
static int execute_resume(struct target *target, bool step)
{
riscv011_info_t *info = get_info(target);
LOG_DEBUG("step=%d", step);
maybe_write_tselect(target);
/* ... */
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, CSR_DPC));
cache_set_jump(target, 2);
cache_set(target, SLOT0, info->dpc);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS];
if (mstatus_reg->valid) {
uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target));
if (mstatus_user != info->mstatus_actual) {
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, CSR_MSTATUS));
cache_set_jump(target, 2);
cache_set(target, SLOT0, mstatus_user);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
}if (mstatus_user != info->mstatus_actual) { ... }
}if (mstatus_reg->valid) { ... }
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr &= ~DCSR_HALT;
if (step)
info->dcsr |= DCSR_STEP;
else
info->dcsr &= ~DCSR_STEP;
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, csrw(S0, CSR_DCSR), false);
dram_write32(target, 2, fence_i(), false);
dram_write_jump(target, 3, false);
uint64_t dbus_value = DMCONTROL_INTERRUPT | info->dcsr;
dbus_write(target, dram_address(4), dbus_value);
cache_invalidate(target);
if (wait_for_debugint_clear(target, true) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}if (wait_for_debugint_clear(target, true) != ERROR_OK) { ... }
target->state = TARGET_RUNNING;
register_cache_invalidate(target->reg_cache);
return ERROR_OK;
}{ ... }
static int full_step(struct target *target, bool announce)
{
int result = execute_resume(target, true);
if (result != ERROR_OK)
return result;
time_t start = time(NULL);
while (1) {
result = poll_target(target, announce);
if (result != ERROR_OK)
return result;
if (target->state != TARGET_DEBUG_RUNNING)
break;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out waiting for step to complete."
"Increase timeout with riscv set_command_timeout_sec");
return ERROR_FAIL;
}if (time(NULL) - start > riscv_command_timeout_sec) { ... }
}while (1) { ... }
return ERROR_OK;
}{ ... }
static int resume(struct target *target, int debug_execution, bool step)
{
if (debug_execution) {
LOG_ERROR("TODO: debug_execution is true");
return ERROR_FAIL;
}if (debug_execution) { ... }
return execute_resume(target, step);
}{ ... }
static uint64_t reg_cache_get(struct target *target, unsigned int number)
{
struct reg *r = &target->reg_cache->reg_list[number];
if (!r->valid) {
LOG_ERROR("Register cache entry for %d is invalid!", number);
assert(r->valid);
}if (!r->valid) { ... }
uint64_t value = buf_get_u64(r->value, 0, r->size);
LOG_DEBUG("%s = 0x%" PRIx64, r->name, value);
return value;
}{ ... }
static void reg_cache_set(struct target *target, unsigned int number,
uint64_t value)
{
struct reg *r = &target->reg_cache->reg_list[number];
LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value);
r->valid = true;
buf_set_u64(r->value, 0, r->size, value);
}{ ... }
static int update_mstatus_actual(struct target *target)
{
struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS];
if (mstatus_reg->valid) {
return ERROR_OK;
}if (mstatus_reg->valid) { ... }
/* ... */
riscv_reg_t mstatus;
return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
}{ ... }
static int register_read(struct target *target, riscv_reg_t *value, int regnum)
{
riscv011_info_t *info = get_info(target);
if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) {
cache_set32(target, 0, csrr(S0, regnum - GDB_REGNO_CSR0));
cache_set_store(target, 1, S0, SLOT0);
cache_set_jump(target, 2);
}if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) { ... } else {
LOG_ERROR("Don't know how to read register %d", regnum);
return ERROR_FAIL;
}else { ... }
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum));
*value = ~0;
return ERROR_FAIL;
}if (exception) { ... }
*value = cache_get(target, SLOT0);
LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value);
if (regnum == GDB_REGNO_MSTATUS)
info->mstatus_actual = *value;
return ERROR_OK;
}{ ... }
static int register_write(struct target *target, unsigned int number,
uint64_t value)
{
riscv011_info_t *info = get_info(target);
maybe_write_tselect(target);
if (number == S0) {
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0));
cache_set_jump(target, 2);
}if (number == S0) { ... } else if (number == S1) {
cache_set_load(target, 0, S0, SLOT0);
cache_set_store(target, 1, S0, SLOT_LAST);
cache_set_jump(target, 2);
}else if (number == S1) { ... } else if (number <= GDB_REGNO_XPR31) {
cache_set_load(target, 0, number - GDB_REGNO_ZERO, SLOT0);
cache_set_jump(target, 1);
}else if (number <= GDB_REGNO_XPR31) { ... } else if (number == GDB_REGNO_PC) {
info->dpc = value;
return ERROR_OK;
}else if (number == GDB_REGNO_PC) { ... } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
int result = update_mstatus_actual(target);
if (result != ERROR_OK)
return result;
unsigned i = 0;
if ((info->mstatus_actual & MSTATUS_FS) == 0) {
info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1);
cache_set_load(target, i++, S0, SLOT1);
cache_set32(target, i++, csrw(S0, CSR_MSTATUS));
cache_set(target, SLOT1, info->mstatus_actual);
}if ((info->mstatus_actual & MSTATUS_FS) == 0) { ... }
if (riscv_xlen(target) == 32)
cache_set32(target, i++, flw(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
else
cache_set32(target, i++, fld(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
cache_set_jump(target, i++);
}else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { ... } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, number - GDB_REGNO_CSR0));
cache_set_jump(target, 2);
if (number == GDB_REGNO_MSTATUS)
info->mstatus_actual = value;
}else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { ... } else if (number == GDB_REGNO_PRIV) {
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
return ERROR_OK;
}else if (number == GDB_REGNO_PRIV) { ... } else {
LOG_ERROR("Don't know how to write register %d", number);
return ERROR_FAIL;
}else { ... }
cache_set(target, SLOT0, value);
if (cache_write(target, info->dramsize - 1, true) != ERROR_OK)
return ERROR_FAIL;
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when writing %s", exception,
gdb_regno_name(number));
return ERROR_FAIL;
}if (exception) { ... }
return ERROR_OK;
}{ ... }
static int get_register(struct target *target, riscv_reg_t *value, int regid)
{
riscv011_info_t *info = get_info(target);
maybe_write_tselect(target);
if (regid <= GDB_REGNO_XPR31) {
*value = reg_cache_get(target, regid);
}if (regid <= GDB_REGNO_XPR31) { ... } else if (regid == GDB_REGNO_PC) {
*value = info->dpc;
}else if (regid == GDB_REGNO_PC) { ... } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) {
int result = update_mstatus_actual(target);
if (result != ERROR_OK)
return result;
unsigned i = 0;
if ((info->mstatus_actual & MSTATUS_FS) == 0) {
info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1);
cache_set_load(target, i++, S0, SLOT1);
cache_set32(target, i++, csrw(S0, CSR_MSTATUS));
cache_set(target, SLOT1, info->mstatus_actual);
}if ((info->mstatus_actual & MSTATUS_FS) == 0) { ... }
if (riscv_xlen(target) == 32)
cache_set32(target, i++, fsw(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
else
cache_set32(target, i++, fsd(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
cache_set_jump(target, i++);
if (cache_write(target, 4, true) != ERROR_OK)
return ERROR_FAIL;
}else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { ... } else if (regid == GDB_REGNO_PRIV) {
*value = get_field(info->dcsr, DCSR_PRV);
}else if (regid == GDB_REGNO_PRIV) { ... } else {
int result = register_read(target, value, regid);
if (result != ERROR_OK)
return result;
}else { ... }
if (regid == GDB_REGNO_MSTATUS)
target->reg_cache->reg_list[regid].valid = true;
return ERROR_OK;
}{ ... }
static int set_register(struct target *target, int regid, uint64_t value)
{
return register_write(target, regid, value);
}{ ... }
static int halt(struct target *target)
{
LOG_DEBUG("riscv_halt()");
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
cache_set32(target, 0, csrsi(CSR_DCSR, DCSR_HALT));
cache_set32(target, 1, csrr(S0, CSR_MHARTID));
cache_set32(target, 2, sw(S0, ZERO, SETHALTNOT));
cache_set_jump(target, 3);
if (cache_write(target, 4, true) != ERROR_OK) {
LOG_ERROR("cache_write() failed.");
return ERROR_FAIL;
}if (cache_write(target, 4, true) != ERROR_OK) { ... }
return ERROR_OK;
}{ ... }
static void deinit_target(struct target *target)
{
LOG_DEBUG("riscv_deinit_target()");
struct riscv_info *info = target->arch_info;
if (!info)
return;
free(info->version_specific);
info->version_specific = NULL;
}{ ... }
static int strict_step(struct target *target, bool announce)
{
LOG_DEBUG("enter");
struct watchpoint *watchpoint = target->watchpoints;
while (watchpoint) {
riscv_remove_watchpoint(target, watchpoint);
watchpoint = watchpoint->next;
}while (watchpoint) { ... }
int result = full_step(target, announce);
if (result != ERROR_OK)
return result;
watchpoint = target->watchpoints;
while (watchpoint) {
riscv_add_watchpoint(target, watchpoint);
watchpoint = watchpoint->next;
}while (watchpoint) { ... }
return ERROR_OK;
}{ ... }
static int step(struct target *target, int current, target_addr_t address,
int handle_breakpoints)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
if (!current) {
if (riscv_xlen(target) > 32) {
LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
riscv_xlen(target));
}if (riscv_xlen(target) > 32) { ... }
int result = register_write(target, GDB_REGNO_PC, address);
if (result != ERROR_OK)
return result;
}if (!current) { ... }
if (handle_breakpoints) {
int result = strict_step(target, true);
if (result != ERROR_OK)
return result;
}if (handle_breakpoints) { ... } else {
return full_step(target, false);
}else { ... }
return ERROR_OK;
}{ ... }
static int examine(struct target *target)
{
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS));
LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION));
LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE));
if (dtmcontrol == 0) {
LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power.");
return ERROR_FAIL;
}if (dtmcontrol == 0) { ... }
if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) {
LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)",
get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol);
return ERROR_FAIL;
}if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) { ... }
RISCV_INFO(r);
riscv011_info_t *info = get_info(target);
info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
info->dtmcontrol_idle = get_field(dtmcontrol, DTMCONTROL_IDLE);
if (info->dtmcontrol_idle == 0) {
uint32_t idcode = idcode_scan(target);
if (idcode == 0x10e31913)
info->dtmcontrol_idle = 1;
}if (info->dtmcontrol_idle == 0) { ... }
uint32_t dminfo = dbus_read(target, DMINFO);
LOG_DEBUG("dminfo: 0x%08x", dminfo);
LOG_DEBUG(" abussize=0x%x", get_field(dminfo, DMINFO_ABUSSIZE));
LOG_DEBUG(" serialcount=0x%x", get_field(dminfo, DMINFO_SERIALCOUNT));
LOG_DEBUG(" access128=%d", get_field(dminfo, DMINFO_ACCESS128));
LOG_DEBUG(" access64=%d", get_field(dminfo, DMINFO_ACCESS64));
LOG_DEBUG(" access32=%d", get_field(dminfo, DMINFO_ACCESS32));
LOG_DEBUG(" access16=%d", get_field(dminfo, DMINFO_ACCESS16));
LOG_DEBUG(" access8=%d", get_field(dminfo, DMINFO_ACCESS8));
LOG_DEBUG(" dramsize=0x%x", get_field(dminfo, DMINFO_DRAMSIZE));
LOG_DEBUG(" authenticated=0x%x", get_field(dminfo, DMINFO_AUTHENTICATED));
LOG_DEBUG(" authbusy=0x%x", get_field(dminfo, DMINFO_AUTHBUSY));
LOG_DEBUG(" authtype=0x%x", get_field(dminfo, DMINFO_AUTHTYPE));
LOG_DEBUG(" version=0x%x", get_field(dminfo, DMINFO_VERSION));
if (get_field(dminfo, DMINFO_VERSION) != 1) {
LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d "
"(dminfo=0x%x)", get_field(dminfo, DMINFO_VERSION), dminfo);
return ERROR_FAIL;
}if (get_field(dminfo, DMINFO_VERSION) != 1) { ... }
info->dramsize = get_field(dminfo, DMINFO_DRAMSIZE) + 1;
if (get_field(dminfo, DMINFO_AUTHTYPE) != 0) {
LOG_ERROR("Authentication required by RISC-V core but not "
"supported by OpenOCD. dminfo=0x%x", dminfo);
return ERROR_FAIL;
}if (get_field(dminfo, DMINFO_AUTHTYPE) != 0) { ... }
r->xlen = 32;
cache_set32(target, 0, xori(S1, ZERO, -1));
cache_set32(target, 1, srli(S1, S1, 31));
cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START));
cache_set32(target, 3, srli(S1, S1, 31));
cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4));
cache_set_jump(target, 5);
for (unsigned i = 6; i < info->dramsize; i++)
cache_set32(target, i, i * 0x01020304);
cache_write(target, 0, false);
if (cache_check(target) != ERROR_OK)
return ERROR_FAIL;
cache_write(target, 0, true);
cache_invalidate(target);
uint32_t word0 = cache_get32(target, 0);
uint32_t word1 = cache_get32(target, 1);
struct riscv_info *generic_info = riscv_info(target);
if (word0 == 1 && word1 == 0) {
generic_info->xlen = 32;
}if (word0 == 1 && word1 == 0) { ... } else if (word0 == 0xffffffff && word1 == 3) {
generic_info->xlen = 64;
}else if (word0 == 0xffffffff && word1 == 3) { ... } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
generic_info->xlen = 128;
}else if (word0 == 0xffffffff && word1 == 0xffffffff) { ... } else {
uint32_t exception = cache_get32(target, info->dramsize-1);
LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
word0, word1, exception);
dump_debug_ram(target);
return ERROR_FAIL;
}else { ... }
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
const unsigned old_csr_misa = 0xf10;
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
old_csr_misa);
if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
/* ... */
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
return ERROR_FAIL;
}if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { ... }
}if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { ... }
riscv_init_registers(target);
info->never_halted = true;
int result = riscv011_poll(target);
if (result != ERROR_OK)
return result;
target_set_examined(target);
riscv_set_current_hartid(target, 0);
for (size_t i = 0; i < 32; ++i)
reg_cache_set(target, i, -1);
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
riscv_xlen(target), r->misa);
return ERROR_OK;
}{ ... }
static riscv_error_t handle_halt_routine(struct target *target)
{
riscv011_info_t *info = get_info(target);
scans_t *scans = scans_new(target, 256);
if (!scans)
return RE_FAIL;
/* ... */
scans_add_write_jump(scans, 1, false);
for (int reg = 1; reg < 32; reg++) {
if (reg == S0 || reg == S1)
continue;
scans_add_write_store(scans, 0, reg, SLOT0, true);
scans_add_read(scans, SLOT0, false);
}for (int reg = 1; reg < 32; reg++) { ... }
scans_add_write_store(scans, 1, S0, SLOT0, false);
scans_add_write_jump(scans, 2, false);
scans_add_write_load(scans, 0, S0, SLOT_LAST, true);
scans_add_read(scans, SLOT0, false);
unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR};
for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) {
scans_add_write32(scans, 0, csrr(S0, csr[i]), true);
scans_add_read(scans, SLOT0, false);
}for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) { ... }
scans_add_read32(scans, 4, false);
int retval = scans_execute(scans);
if (retval != ERROR_OK) {
LOG_ERROR("JTAG execute failed: %d", retval);
goto error;
}if (retval != ERROR_OK) { ... }
unsigned int dbus_busy = 0;
unsigned int interrupt_set = 0;
unsigned result = 0;
uint64_t value = 0;
reg_cache_set(target, 0, 0);
/* ... */
for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) {
dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START,
DBUS_OP_SIZE);
uint64_t data = scans_get_u64(scans, i, DBUS_DATA_START, DBUS_DATA_SIZE);
uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START,
info->addrbits);
switch (status) {
case DBUS_STATUS_SUCCESS:
break;case DBUS_STATUS_SUCCESS:
case DBUS_STATUS_FAILED:
LOG_ERROR("Debug access failed. Hardware error?");
goto error;case DBUS_STATUS_FAILED:
case DBUS_STATUS_BUSY:
dbus_busy++;
break;case DBUS_STATUS_BUSY:
default:
LOG_ERROR("Got invalid bus access status: %d", status);
goto error;default
}switch (status) { ... }
if (data & DMCONTROL_INTERRUPT) {
interrupt_set++;
break;
}if (data & DMCONTROL_INTERRUPT) { ... }
if (address == 4 || address == 5) {
unsigned int reg;
switch (result) {
case 0:
reg = 1;
break;case 0:
case 1:
reg = 2;
break;case 1:
case 2:
reg = 3;
break;case 2:
case 3:
reg = 4;
break;case 3:
case 4:
reg = 5;
break;case 4:
case 5:
reg = 6;
break;case 5:
case 6:
reg = 7;
break;
case 6:
case 7:
reg = 10;
break;case 7:
case 8:
reg = 11;
break;case 8:
case 9:
reg = 12;
break;case 9:
case 10:
reg = 13;
break;case 10:
case 11:
reg = 14;
break;case 11:
case 12:
reg = 15;
break;case 12:
case 13:
reg = 16;
break;case 13:
case 14:
reg = 17;
break;case 14:
case 15:
reg = 18;
break;case 15:
case 16:
reg = 19;
break;case 16:
case 17:
reg = 20;
break;case 17:
case 18:
reg = 21;
break;case 18:
case 19:
reg = 22;
break;case 19:
case 20:
reg = 23;
break;case 20:
case 21:
reg = 24;
break;case 21:
case 22:
reg = 25;
break;case 22:
case 23:
reg = 26;
break;case 23:
case 24:
reg = 27;
break;case 24:
case 25:
reg = 28;
break;case 25:
case 26:
reg = 29;
break;case 26:
case 27:
reg = 30;
break;case 27:
case 28:
reg = 31;
break;case 28:
case 29:
reg = S1;
break;case 29:
case 30:
reg = S0;
break;case 30:
case 31:
reg = CSR_DPC;
break;case 31:
case 32:
reg = CSR_DCSR;
break;case 32:
default:
assert(0);
LOG_ERROR("Got invalid register result %d", result);
goto error;default
}switch (result) { ... }
if (riscv_xlen(target) == 32) {
reg_cache_set(target, reg, data & 0xffffffff);
result++;
}if (riscv_xlen(target) == 32) { ... } else if (riscv_xlen(target) == 64) {
if (address == 4) {
value = data & 0xffffffff;
}if (address == 4) { ... } else if (address == 5) {
reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value);
value = 0;
result++;
}else if (address == 5) { ... }
}else if (riscv_xlen(target) == 64) { ... }
}if (address == 4 || address == 5) { ... }
}for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { ... }
scans_delete(scans);
if (dbus_busy) {
increase_dbus_busy_delay(target);
return RE_AGAIN;
}if (dbus_busy) { ... }
if (interrupt_set) {
increase_interrupt_high_delay(target);
return RE_AGAIN;
}if (interrupt_set) { ... }
info->dpc = reg_cache_get(target, CSR_DPC);
info->dcsr = reg_cache_get(target, CSR_DCSR);
cache_invalidate(target);
return RE_OK;
error:
scans_delete(scans);
return RE_FAIL;
}{ ... }
static int handle_halt(struct target *target, bool announce)
{
riscv011_info_t *info = get_info(target);
target->state = TARGET_HALTED;
riscv_error_t re;
do {
re = handle_halt_routine(target);
...} while (re == RE_AGAIN);
if (re != RE_OK) {
LOG_ERROR("handle_halt_routine failed");
return ERROR_FAIL;
}if (re != RE_OK) { ... }
int cause = get_field(info->dcsr, DCSR_CAUSE);
switch (cause) {
case DCSR_CAUSE_SWBP:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;case DCSR_CAUSE_SWBP:
case DCSR_CAUSE_HWBP:
target->debug_reason = DBG_REASON_WATCHPOINT;
break;case DCSR_CAUSE_HWBP:
case DCSR_CAUSE_DEBUGINT:
target->debug_reason = DBG_REASON_DBGRQ;
break;case DCSR_CAUSE_DEBUGINT:
case DCSR_CAUSE_STEP:
target->debug_reason = DBG_REASON_SINGLESTEP;
break;case DCSR_CAUSE_STEP:
case DCSR_CAUSE_HALT:
default:
LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")",
cause, info->dcsr);default
}switch (cause) { ... }
if (info->never_halted) {
info->never_halted = false;
int result = maybe_read_tselect(target);
if (result != ERROR_OK)
return result;
riscv_enumerate_triggers(target);
}if (info->never_halted) { ... }
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
int retval;
if (riscv_semihosting(target, &retval) != 0)
return retval;
}if (target->debug_reason == DBG_REASON_BREAKPOINT) { ... }
if (announce)
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
const char *cause_string[] = {
"none",
"software breakpoint",
"hardware trigger",
"debug interrupt",
"step",
"halt"
...};
/* ... */
LOG_USER("halted at 0x%" PRIx64 " due to %s", info->dpc, cause_string[cause]);
return ERROR_OK;
}{ ... }
static int poll_target(struct target *target, bool announce)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
/* ... */
int old_debug_level = debug_level;
if (debug_level >= LOG_LVL_DEBUG)
debug_level = LOG_LVL_INFO;
bits_t bits = read_bits(target);
debug_level = old_debug_level;
if (bits.haltnot && bits.interrupt) {
target->state = TARGET_DEBUG_RUNNING;
LOG_DEBUG("debug running");
}if (bits.haltnot && bits.interrupt) { ... } else if (bits.haltnot && !bits.interrupt) {
if (target->state != TARGET_HALTED)
return handle_halt(target, announce);
}else if (bits.haltnot && !bits.interrupt) { ... } else if (!bits.haltnot && bits.interrupt) {
LOG_DEBUG("halting");
}else if (!bits.haltnot && bits.interrupt) { ... } else if (!bits.haltnot && !bits.interrupt) {
target->state = TARGET_RUNNING;
}else if (!bits.haltnot && !bits.interrupt) { ... }
return ERROR_OK;
}{ ... }
static int riscv011_poll(struct target *target)
{
return poll_target(target, true);
}{ ... }
static int riscv011_resume(struct target *target, int current,
target_addr_t address, int handle_breakpoints, int debug_execution)
{
RISCV_INFO(r);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
r->prepped = false;
return resume(target, debug_execution, false);
}{ ... }
static int assert_reset(struct target *target)
{
riscv011_info_t *info = get_info(target);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
if (wait_for_debugint_clear(target, true) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}if (wait_for_debugint_clear(target, true) != ERROR_OK) { ... }
/* ... */
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr |= DCSR_HALT;
if (target->reset_halt)
info->dcsr |= DCSR_NDRESET;
else
info->dcsr |= DCSR_FULLRESET;
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, csrw(S0, CSR_DCSR), false);
dram_write_jump(target, 2, false);
dram_write32(target, 4, info->dcsr, true);
cache_invalidate(target);
target->state = TARGET_RESET;
return ERROR_OK;
}{ ... }
static int deassert_reset(struct target *target)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
if (target->reset_halt)
return wait_for_state(target, TARGET_HALTED);
else
return wait_for_state(target, TARGET_RUNNING);
}{ ... }
static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
if (increment != size) {
LOG_ERROR("read_memory with custom increment not implemented");
return ERROR_NOT_IMPLEMENTED;
}if (increment != size) { ... }
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
switch (size) {
case 1:
cache_set32(target, 1, lb(S1, S0, 0));
cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16));
break;case 1:
case 2:
cache_set32(target, 1, lh(S1, S0, 0));
cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16));
break;case 2:
case 4:
cache_set32(target, 1, lw(S1, S0, 0));
cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16));
break;case 4:
default:
LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL;default
}switch (size) { ... }
cache_set_jump(target, 3);
cache_write(target, CACHE_NO_READ, false);
riscv011_info_t *info = get_info(target);
const unsigned max_batch_size = 256;
scans_t *scans = scans_new(target, max_batch_size);
if (!scans)
return ERROR_FAIL;
uint32_t result_value = 0x777;
uint32_t i = 0;
while (i < count + 3) {
unsigned int batch_size = MIN(count + 3 - i, max_batch_size);
scans_reset(scans);
for (unsigned int j = 0; j < batch_size; j++) {
if (i + j == count) {
scans_add_read32(scans, 4, false);
}if (i + j == count) { ... } else if (i + j >= count + 1) {
scans_add_read32(scans, info->dramsize-1, false);
}else if (i + j >= count + 1) { ... } else {
uint32_t offset = size * (i + j);
scans_add_write32(scans, 4, address + offset, true);
}else { ... }
}for (unsigned int j = 0; j < batch_size; j++) { ... }
int retval = scans_execute(scans);
if (retval != ERROR_OK) {
LOG_ERROR("JTAG execute failed: %d", retval);
goto error;
}if (retval != ERROR_OK) { ... }
int dbus_busy = 0;
int execute_busy = 0;
for (unsigned int j = 0; j < batch_size; j++) {
dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START,
DBUS_OP_SIZE);
switch (status) {
case DBUS_STATUS_SUCCESS:
break;case DBUS_STATUS_SUCCESS:
case DBUS_STATUS_FAILED:
LOG_ERROR("Debug RAM write failed. Hardware error?");
goto error;case DBUS_STATUS_FAILED:
case DBUS_STATUS_BUSY:
dbus_busy++;
break;case DBUS_STATUS_BUSY:
default:
LOG_ERROR("Got invalid bus access status: %d", status);
return ERROR_FAIL;default
}switch (status) { ... }
uint64_t data = scans_get_u64(scans, j, DBUS_DATA_START,
DBUS_DATA_SIZE);
if (data & DMCONTROL_INTERRUPT)
execute_busy++;
if (i + j == count + 2) {
result_value = data;
}if (i + j == count + 2) { ... } else if (i + j > 1) {
uint32_t offset = size * (i + j - 2);
switch (size) {
case 1:
buffer[offset] = data;
break;case 1:
case 2:
buffer[offset] = data;
buffer[offset+1] = data >> 8;
break;case 2:
case 4:
buffer[offset] = data;
buffer[offset+1] = data >> 8;
buffer[offset+2] = data >> 16;
buffer[offset+3] = data >> 24;
break;case 4:
}switch (size) { ... }
}else if (i + j > 1) { ... }
LOG_DEBUG("j=%d status=%d data=%09" PRIx64, j, status, data);
}for (unsigned int j = 0; j < batch_size; j++) { ... }
if (dbus_busy)
increase_dbus_busy_delay(target);
if (execute_busy)
increase_interrupt_high_delay(target);
if (dbus_busy || execute_busy) {
wait_for_debugint_clear(target, false);
LOG_INFO("Retrying memory read starting from 0x%" TARGET_PRIxADDR
" with more delays", address + size * i);
}if (dbus_busy || execute_busy) { ... } else {
i += batch_size;
}else { ... }
}while (i < count + 3) { ... }
if (result_value != 0) {
LOG_USER("Core got an exception (0x%x) while reading from 0x%"
TARGET_PRIxADDR, result_value, address + size * (count-1));
if (count > 1) {
LOG_USER("(It may have failed between 0x%" TARGET_PRIxADDR
" and 0x%" TARGET_PRIxADDR " as well, but we "
"didn't check then.)",
address, address + size * (count-2) + size - 1);
}if (count > 1) { ... }
goto error;
}if (result_value != 0) { ... }
scans_delete(scans);
cache_clean(target);
return ERROR_OK;
error:
scans_delete(scans);
cache_clean(target);
return ERROR_FAIL;
}{ ... }
static int setup_write_memory(struct target *target, uint32_t size)
{
switch (size) {
case 1:
cache_set32(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16));
cache_set32(target, 1, sb(S0, T0, 0));
break;case 1:
case 2:
cache_set32(target, 0, lh(S0, ZERO, DEBUG_RAM_START + 16));
cache_set32(target, 1, sh(S0, T0, 0));
break;case 2:
case 4:
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
cache_set32(target, 1, sw(S0, T0, 0));
break;case 4:
default:
LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL;default
}switch (size) { ... }
cache_set32(target, 2, addi(T0, T0, size));
cache_set_jump(target, 3);
cache_write(target, 4, false);
return ERROR_OK;
}{ ... }
static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
riscv011_info_t *info = get_info(target);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
cache_set_store(target, 0, T0, SLOT1);
cache_set_load(target, 1, T0, SLOT0);
cache_set_jump(target, 2);
cache_set(target, SLOT0, address);
if (cache_write(target, 5, true) != ERROR_OK)
return ERROR_FAIL;
uint64_t t0 = cache_get(target, SLOT1);
LOG_DEBUG("t0 is 0x%" PRIx64, t0);
if (setup_write_memory(target, size) != ERROR_OK)
return ERROR_FAIL;
const unsigned max_batch_size = 256;
scans_t *scans = scans_new(target, max_batch_size);
if (!scans)
return ERROR_FAIL;
uint32_t result_value = 0x777;
uint32_t i = 0;
while (i < count + 2) {
unsigned int batch_size = MIN(count + 2 - i, max_batch_size);
scans_reset(scans);
for (unsigned int j = 0; j < batch_size; j++) {
if (i + j >= count) {
scans_add_read32(scans, info->dramsize-1, false);
}if (i + j >= count) { ... } else {
uint32_t value;
uint32_t offset = size * (i + j);
switch (size) {
case 1:
value = buffer[offset];
break;case 1:
case 2:
value = buffer[offset] |
(buffer[offset+1] << 8);
break;case 2:
case 4:
value = buffer[offset] |
((uint32_t) buffer[offset+1] << 8) |
((uint32_t) buffer[offset+2] << 16) |
((uint32_t) buffer[offset+3] << 24);
break;case 4:
default:
goto error;default
}switch (size) { ... }
scans_add_write32(scans, 4, value, true);
}else { ... }
}for (unsigned int j = 0; j < batch_size; j++) { ... }
int retval = scans_execute(scans);
if (retval != ERROR_OK) {
LOG_ERROR("JTAG execute failed: %d", retval);
goto error;
}if (retval != ERROR_OK) { ... }
int dbus_busy = 0;
int execute_busy = 0;
for (unsigned int j = 0; j < batch_size; j++) {
dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START,
DBUS_OP_SIZE);
switch (status) {
case DBUS_STATUS_SUCCESS:
break;case DBUS_STATUS_SUCCESS:
case DBUS_STATUS_FAILED:
LOG_ERROR("Debug RAM write failed. Hardware error?");
goto error;case DBUS_STATUS_FAILED:
case DBUS_STATUS_BUSY:
dbus_busy++;
break;case DBUS_STATUS_BUSY:
default:
LOG_ERROR("Got invalid bus access status: %d", status);
return ERROR_FAIL;default
}switch (status) { ... }
int interrupt = scans_get_u32(scans, j, DBUS_DATA_START + 33, 1);
if (interrupt)
execute_busy++;
if (i + j == count + 1)
result_value = scans_get_u32(scans, j, DBUS_DATA_START, 32);
}for (unsigned int j = 0; j < batch_size; j++) { ... }
if (dbus_busy)
increase_dbus_busy_delay(target);
if (execute_busy)
increase_interrupt_high_delay(target);
if (dbus_busy || execute_busy) {
wait_for_debugint_clear(target, false);
/* ... */
LOG_INFO("Retrying memory write starting from 0x%" TARGET_PRIxADDR
" with more delays", address + size * i);
cache_clean(target);
if (write_gpr(target, T0, address + size * i) != ERROR_OK)
goto error;
if (setup_write_memory(target, size) != ERROR_OK)
goto error;
}if (dbus_busy || execute_busy) { ... } else {
i += batch_size;
}else { ... }
}while (i < count + 2) { ... }
if (result_value != 0) {
LOG_ERROR("Core got an exception (0x%x) while writing to 0x%"
TARGET_PRIxADDR, result_value, address + size * (count-1));
if (count > 1) {
LOG_ERROR("(It may have failed between 0x%" TARGET_PRIxADDR
" and 0x%" TARGET_PRIxADDR " as well, but we "
"didn't check then.)",
address, address + size * (count-2) + size - 1);
}if (count > 1) { ... }
goto error;
}if (result_value != 0) { ... }
scans_delete(scans);
cache_clean(target);
return register_write(target, T0, t0);
error:
scans_delete(scans);
cache_clean(target);
return ERROR_FAIL;
}{ ... }
static int arch_state(struct target *target)
{
return ERROR_OK;
}{ ... }
static COMMAND_HELPER(riscv011_print_info, struct target *target)
{
riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0);
uint32_t dminfo = dbus_read(target, DMINFO);
riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED));
return 0;
}{ ... }
static int wait_for_authbusy(struct target *target)
{
time_t start = time(NULL);
while (1) {
uint32_t dminfo = dbus_read(target, DMINFO);
if (!get_field(dminfo, DMINFO_AUTHBUSY))
break;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec,
dminfo);
return ERROR_FAIL;
}if (time(NULL) - start > riscv_command_timeout_sec) { ... }
}while (1) { ... }
return ERROR_OK;
}{ ... }
static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index)
{
if (index > 1) {
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
return ERROR_FAIL;
}if (index > 1) { ... }
if (wait_for_authbusy(target) != ERROR_OK)
return ERROR_FAIL;
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
*value = dbus_read(target, authdata_address);
return ERROR_OK;
}{ ... }
static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index)
{
if (index > 1) {
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
return ERROR_FAIL;
}if (index > 1) { ... }
if (wait_for_authbusy(target) != ERROR_OK)
return ERROR_FAIL;
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
dbus_write(target, authdata_address, value);
return ERROR_OK;
}{ ... }
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
LOG_DEBUG("init");
RISCV_INFO(generic_info);
generic_info->get_register = get_register;
generic_info->set_register = set_register;
generic_info->read_memory = read_memory;
generic_info->authdata_read = &riscv011_authdata_read;
generic_info->authdata_write = &riscv011_authdata_write;
generic_info->print_info = &riscv011_print_info;
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
if (!generic_info->version_specific)
return ERROR_FAIL;
generic_info->xlen = 32;
riscv_init_registers(target);
return ERROR_OK;
}{ ... }
struct target_type riscv011_target = {
.name = "riscv",
.init_target = init_target,
.deinit_target = deinit_target,
.examine = examine,
.poll = riscv011_poll,
.halt = halt,
.resume = riscv011_resume,
.step = step,
.assert_reset = assert_reset,
.deassert_reset = deassert_reset,
.write_memory = write_memory,
.arch_state = arch_state,
...};