Skip to content

Commit 5397899

Browse files
committed
Add configurable datacount for debug module
This commit adds support for configuring the number of data registers available in the debug module. Previously, the debug module had a fixed datasize of 2, but now users can specify the number of data registers using the --dm-datacount option when running spike. The changes include: - Adding a datacount parameter to debug_module_config_t - Making dmdata a std::vector instead of a fixed array - Validating that datacount is between 1 and 12 - Updating the debug module to use the configured datacount - Adding command-line option to set datacount - Updating documentation in help output Signed-off-by: Farid Khaydari <[email protected]>
1 parent 8df626b commit 5397899

File tree

3 files changed

+115
-44
lines changed

3 files changed

+115
-44
lines changed

riscv/debug_module.cc

Lines changed: 97 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
#include <algorithm>
2+
#include <array>
13
#include <cassert>
4+
#include <iterator>
5+
#include <limits>
26

37
#include "simif.h"
48
#include "devices.h"
@@ -32,6 +36,25 @@ static unsigned field_width(unsigned n)
3236

3337
///////////////////////// debug_module_t
3438

39+
static bool region_descriptor_comparator(const region_descriptor &lhs,
40+
const region_descriptor &rhs) {
41+
return lhs.addr < rhs.addr;
42+
}
43+
44+
template <typename It>
45+
static bool has_intersection(It begin, It end) {
46+
assert(std::is_sorted(begin, end, region_descriptor_comparator));
47+
48+
// If current interval's end > next interval's start, they intersect
49+
auto intersecion =
50+
std::adjacent_find(begin, end, [](const auto &lhs, const auto &rhs) {
51+
assert(std::numeric_limits<reg_t>::max() - lhs.addr >= lhs.len);
52+
return lhs.addr + lhs.len > rhs.addr;
53+
});
54+
55+
return intersecion != end;
56+
}
57+
3558
debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config) :
3659
config(config),
3760
program_buffer_bytes((config.support_impebreak ? 4 : 0) + 4*config.progbufsize),
@@ -57,11 +80,18 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config
5780
exit(1);
5881
}
5982

83+
constexpr unsigned max_data_reg = 12;
84+
constexpr unsigned min_data_reg = 1;
85+
if (config.datacount < min_data_reg || config.datacount > max_data_reg) {
86+
fprintf(stderr, "dm-datacount must be between 1 and 12 (got %u)\n", config.datacount);
87+
exit(1);
88+
}
89+
90+
dmdata.resize(config.datacount * dmdata_reg_size);
6091
program_buffer = new uint8_t[program_buffer_bytes];
6192

6293
memset(debug_rom_flags, 0, sizeof(debug_rom_flags));
6394
memset(program_buffer, 0, program_buffer_bytes);
64-
memset(dmdata, 0, sizeof(dmdata));
6595

6696
if (config.support_impebreak) {
6797
program_buffer[4*config.progbufsize] = ebreak();
@@ -78,6 +108,20 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config
78108
hart_available_state[i] = true;
79109
}
80110

111+
debug_memory_regions = {
112+
region_descriptor{DEBUG_ROM_ENTRY, debug_rom_raw_len, debug_rom_raw},
113+
region_descriptor{DEBUG_ROM_WHERETO, sizeof(debug_rom_whereto), debug_rom_whereto},
114+
region_descriptor{DEBUG_ROM_FLAGS, sizeof(debug_rom_flags), debug_rom_flags},
115+
region_descriptor{debug_data_start, dmdata.size(), dmdata.data()},
116+
region_descriptor{debug_abstract_start, sizeof(debug_abstract), debug_abstract},
117+
region_descriptor{debug_progbuf_start, program_buffer_bytes, program_buffer},
118+
};
119+
120+
std::sort(debug_memory_regions.begin(), debug_memory_regions.end(),
121+
region_descriptor_comparator);
122+
assert(!has_intersection(debug_memory_regions.begin(),
123+
debug_memory_regions.end()));
124+
81125
reset();
82126
}
83127

@@ -100,7 +144,7 @@ void debug_module_t::reset()
100144
dmstatus.version = 2;
101145

102146
memset(&abstractcs, 0, sizeof(abstractcs));
103-
abstractcs.datacount = sizeof(dmdata) / 4;
147+
abstractcs.datacount = config.datacount;
104148
abstractcs.progbufsize = config.progbufsize;
105149

106150
memset(&abstractauto, 0, sizeof(abstractauto));
@@ -122,38 +166,27 @@ void debug_module_t::reset()
122166
challenge = random();
123167
}
124168

169+
static bool belongs_to_range(reg_t access_addr, size_t access_len,
170+
reg_t range_addr, size_t range_len)
171+
{
172+
assert(std::numeric_limits<reg_t>::max() - access_addr >= access_len);
173+
assert(std::numeric_limits<reg_t>::max() - range_addr >= range_len);
174+
return access_addr >= range_addr && (access_addr < range_addr + range_len) &&
175+
((access_addr + access_len) <= (range_addr + range_len));
176+
}
177+
125178
bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
126179
{
127180
addr = DEBUG_START + addr;
128181

129-
if (addr >= DEBUG_ROM_ENTRY &&
130-
(addr + len) <= (DEBUG_ROM_ENTRY + debug_rom_raw_len)) {
131-
memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_ENTRY, len);
132-
return true;
133-
}
134-
135-
if (addr >= DEBUG_ROM_WHERETO && (addr + len) <= (DEBUG_ROM_WHERETO + 4)) {
136-
memcpy(bytes, debug_rom_whereto + addr - DEBUG_ROM_WHERETO, len);
137-
return true;
138-
}
139-
140-
if (addr >= DEBUG_ROM_FLAGS && ((addr + len) <= DEBUG_ROM_FLAGS + 1024)) {
141-
memcpy(bytes, debug_rom_flags + addr - DEBUG_ROM_FLAGS, len);
142-
return true;
143-
}
144-
145-
if (addr >= debug_abstract_start && ((addr + len) <= (debug_abstract_start + sizeof(debug_abstract)))) {
146-
memcpy(bytes, debug_abstract + addr - debug_abstract_start, len);
147-
return true;
148-
}
149-
150-
if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
151-
memcpy(bytes, dmdata + addr - debug_data_start, len);
152-
return true;
153-
}
182+
const auto interval_ptr =
183+
std::find_if(debug_memory_regions.begin(), debug_memory_regions.end(),
184+
[addr, len](const auto &range) {
185+
return belongs_to_range(addr, len, range.addr, range.len);
186+
});
154187

155-
if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) {
156-
memcpy(bytes, program_buffer + addr - debug_progbuf_start, len);
188+
if (interval_ptr != debug_memory_regions.end()) {
189+
std::copy_n(std::next(interval_ptr->bytes, addr - interval_ptr->addr), len, bytes);
157190
return true;
158191
}
159192

@@ -163,6 +196,15 @@ bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
163196
return false;
164197
}
165198

199+
static bool handle_range_store(reg_t input_addr, size_t input_len, const uint8_t *bytes,
200+
reg_t range_addr, size_t range_len, uint8_t *data)
201+
{
202+
if (!belongs_to_range(input_addr, input_len, range_addr, range_len))
203+
return false;
204+
std::copy_n(bytes, input_len, std::next(data, input_addr - range_addr));
205+
return true;
206+
}
207+
166208
bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
167209
{
168210
D(
@@ -188,16 +230,11 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
188230

189231
addr = DEBUG_START + addr;
190232

191-
if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
192-
memcpy(dmdata + addr - debug_data_start, bytes, len);
233+
if (handle_range_store(addr, len, bytes, debug_data_start, dmdata.size(), dmdata.data()))
193234
return true;
194-
}
195-
196-
if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) {
197-
memcpy(program_buffer + addr - debug_progbuf_start, bytes, len);
198235

236+
if (handle_range_store(addr, len, bytes, debug_progbuf_start, program_buffer_bytes, program_buffer))
199237
return true;
200-
}
201238

202239
if (addr == DEBUG_ROM_HALTED) {
203240
assert (len == 4);
@@ -283,6 +320,16 @@ unsigned debug_module_t::sb_access_bits()
283320
return 8 << sbcs.sbaccess;
284321
}
285322

323+
uint8_t *debug_module_t::get_dmdata_checked(size_t required_size)
324+
{
325+
if(dmdata.size() < required_size) {
326+
fprintf(stderr, "dmdata size (%ld) less then required (%ld)\n",
327+
dmdata.size(), required_size);
328+
exit(1);
329+
}
330+
return dmdata.data();
331+
}
332+
286333
void debug_module_t::sb_autoincrement()
287334
{
288335
if (!sbcs.autoincrement || !config.max_sba_data_width)
@@ -392,7 +439,8 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
392439
D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
393440
if (address >= DM_DATA0 && address < DM_DATA0 + abstractcs.datacount) {
394441
unsigned i = address - DM_DATA0;
395-
result = read32(dmdata, i);
442+
assert(dmdata.size() >= 4);
443+
result = read32(get_dmdata_checked(i + 1), i);
396444
if (abstractcs.busy) {
397445
result = -1;
398446
D(fprintf(stderr, "\ndmi_read(0x%02x (data[%d]) -> -1 because abstractcs.busy==true\n", address, i));
@@ -660,6 +708,13 @@ bool debug_module_t::perform_abstract_command()
660708
return true;
661709
}
662710

711+
assert(size < 8);
712+
// Check if register fit in dmdata
713+
if ((1U << size) > dmdata.size()) {
714+
abstractcs.cmderr = CMDERR_NOTSUP;
715+
return true;
716+
}
717+
663718
unsigned i = 0;
664719
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
665720

@@ -781,10 +836,11 @@ bool debug_module_t::perform_abstract_command()
781836
if (write) {
782837
// Writing V to custom register N will cause future reads of N to
783838
// return V, reads of N-1 will return V-1, etc.
784-
custom_base = read32(dmdata, 0) - custom_number;
839+
assert(dmdata.size() >= 4);
840+
custom_base = read32(get_dmdata_checked(1), 0) - custom_number;
785841
} else {
786-
write32(dmdata, 0, custom_number + custom_base);
787-
write32(dmdata, 1, 0);
842+
write32(get_dmdata_checked(1), 0, custom_number + custom_base);
843+
write32(get_dmdata_checked(2), 1, 0);
788844
}
789845
return true;
790846

@@ -832,7 +888,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
832888
if (address >= DM_DATA0 && address < DM_DATA0 + abstractcs.datacount) {
833889
unsigned i = address - DM_DATA0;
834890
if (!abstractcs.busy)
835-
write32(dmdata, address - DM_DATA0, value);
891+
write32(get_dmdata_checked(address - DM_DATA0), address - DM_DATA0, value);
836892

837893
if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
838894
abstractcs.cmderr = CMDERR_BUSY;

riscv/debug_module.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#ifndef _RISCV_DEBUG_MODULE_H
33
#define _RISCV_DEBUG_MODULE_H
44

5-
#include <set>
5+
#include <array>
66
#include <vector>
77

88
#include "abstract_device.h"
@@ -15,6 +15,7 @@ struct debug_module_config_t {
1515
// Size of program_buffer in 32-bit words, as exposed to the rest of the
1616
// world.
1717
unsigned progbufsize = 2;
18+
unsigned datacount = 2;
1819
unsigned max_sba_data_width = 0;
1920
bool require_authentication = false;
2021
unsigned abstract_rti = 0;
@@ -99,6 +100,13 @@ struct hart_debug_state_t {
99100
uint8_t haltgroup;
100101
};
101102

103+
// structure to describe mmio region
104+
struct region_descriptor {
105+
reg_t addr; // 1st addr in a range
106+
size_t len; // range size
107+
const uint8_t *bytes; // data
108+
};
109+
102110
class debug_module_t : public abstract_device_t
103111
{
104112
public:
@@ -131,7 +139,6 @@ class debug_module_t : public abstract_device_t
131139
void proc_reset(unsigned id);
132140

133141
private:
134-
static const unsigned datasize = 2;
135142
debug_module_config_t config;
136143
// Actual size of the program buffer, which is 1 word bigger than we let on
137144
// to implement the implicit ebreak at the end.
@@ -150,7 +157,8 @@ class debug_module_t : public abstract_device_t
150157
uint8_t debug_rom_whereto[4];
151158
uint8_t debug_abstract[debug_abstract_size * 4];
152159
uint8_t *program_buffer;
153-
uint8_t dmdata[datasize * 4];
160+
static constexpr unsigned dmdata_reg_size = 4;
161+
std::vector<uint8_t> dmdata;
154162

155163
std::vector<hart_debug_state_t> hart_state;
156164
uint8_t debug_rom_flags[1024];
@@ -174,6 +182,8 @@ class debug_module_t : public abstract_device_t
174182

175183
unsigned sb_access_bits();
176184

185+
uint8_t *get_dmdata_checked(size_t required_size);
186+
177187
dmcontrol_t dmcontrol;
178188
dmstatus_t dmstatus;
179189
abstractcs_t abstractcs;
@@ -206,6 +216,8 @@ class debug_module_t : public abstract_device_t
206216
bool hart_available(unsigned hart_id) const;
207217

208218
unsigned sb_read_wait, sb_write_wait;
219+
220+
std::array<region_descriptor, 6> debug_memory_regions;
209221
};
210222

211223
#endif

spike_main/spike.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static void help(int exit_code = 1)
7171
fprintf(stderr, " --real-time-clint Increment clint time at real-time rate\n");
7272
fprintf(stderr, " --triggers=<n> Number of supported triggers [default 4]\n");
7373
fprintf(stderr, " --dm-progsize=<words> Progsize for the debug module [default 2]\n");
74+
fprintf(stderr, " --dm-datacount=<n> Number of data registers available for the debug module [default 2]\n");
7475
fprintf(stderr, " --dm-sba=<bits> Debug system bus access supports up to "
7576
"<bits> wide accesses [default 0]\n");
7677
fprintf(stderr, " --dm-auth Debug module requires debugger to authenticate\n");
@@ -413,6 +414,8 @@ int main(int argc, char** argv)
413414
});
414415
parser.option(0, "dm-progsize", 1,
415416
[&](const char* s){dm_config.progbufsize = atoul_safe(s);});
417+
parser.option(0, "dm-datacount", 1,
418+
[&](const char* s){dm_config.datacount = atoul_safe(s);});
416419
parser.option(0, "dm-no-impebreak", 0,
417420
[&](const char UNUSED *s){dm_config.support_impebreak = false;});
418421
parser.option(0, "dm-sba", 1,

0 commit comments

Comments
 (0)