7b113abc0fe570e20d8fc1d483f4e53aeb6d9854
[riscv-isa-sim.git] / riscv / debug_module.cc
1 #include <cassert>
2
3 #include "debug_module.h"
4 #include "debug_defines.h"
5 #include "opcodes.h"
6 #include "mmu.h"
7
8 #include "debug_rom/debug_rom.h"
9
10 #if 1
11 # define D(x) x
12 #else
13 # define D(x)
14 #endif
15
16 ///////////////////////// debug_module_data_t
17
18 debug_module_data_t::debug_module_data_t()
19 {
20 memset(data, 0, sizeof(data));
21 }
22
23 bool debug_module_data_t::load(reg_t addr, size_t len, uint8_t* bytes)
24 {
25 if (addr + len < sizeof(data)) {
26 memcpy(bytes, data + addr, len);
27 return true;
28 }
29
30 fprintf(stderr, "ERROR: invalid load from debug_module_data_t: %zd bytes at 0x%016"
31 PRIx64 "\n", len, addr);
32
33 return false;
34 }
35
36 bool debug_module_data_t::store(reg_t addr, size_t len, const uint8_t* bytes)
37 {
38 D(fprintf(stderr, "debug_module_data_t store 0x%lx bytes at 0x%lx\n", len,
39 addr));
40
41 if (addr + len < sizeof(data)) {
42 memcpy(data + addr, bytes, len);
43 return true;
44 }
45
46 fprintf(stderr, "ERROR: invalid store to debug_module_data_t: %zd bytes at 0x%016"
47 PRIx64 "\n", len, addr);
48 return false;
49 }
50
51 uint32_t debug_module_data_t::read32(reg_t addr) const
52 {
53 assert(addr + 4 <= sizeof(data));
54 return data[addr] |
55 (data[addr + 1] << 8) |
56 (data[addr + 2] << 16) |
57 (data[addr + 3] << 24);
58 }
59
60 void debug_module_data_t::write32(reg_t addr, uint32_t value)
61 {
62 fprintf(stderr, "debug_module_data_t::write32(0x%lx, 0x%x)\n", addr, value);
63 assert(addr + 4 <= sizeof(data));
64 data[addr] = value & 0xff;
65 data[addr + 1] = (value >> 8) & 0xff;
66 data[addr + 2] = (value >> 16) & 0xff;
67 data[addr + 3] = (value >> 24) & 0xff;
68 }
69
70 ///////////////////////// debug_module_t
71
72 debug_module_t::debug_module_t(sim_t *sim) : sim(sim),
73 next_action(jal(ZERO, 0)),
74 action_executed(false)
75 {
76 dmcontrol = {0};
77
78 dmstatus = {0};
79 dmstatus.authenticated = 1;
80 dmstatus.versionlo = 2;
81
82 abstractcs = {0};
83 abstractcs.progsize = progsize;
84
85 abstractauto = {0};
86
87 for (unsigned i = 0; i < DEBUG_ROM_ENTRY_SIZE / 4; i++) {
88 write32(debug_rom_entry, i, jal(ZERO, 0));
89 halted[i] = false;
90 }
91
92 memset(program_buffer, 0, sizeof(program_buffer));
93 }
94
95 void debug_module_t::reset()
96 {
97 for (unsigned i = 0; i < sim->nprocs(); i++) {
98 processor_t *proc = sim->get_core(i);
99 if (proc)
100 proc->halt_request = false;
101 }
102
103 dmcontrol = {0};
104
105 dmstatus = {0};
106 dmstatus.authenticated = 1;
107 dmstatus.versionlo = 2;
108
109 abstractcs = {0};
110 abstractcs.datacount = sizeof(dmdata.data) / 4;
111 abstractcs.progsize = progsize;
112
113 abstractauto = {0};
114 }
115
116 void debug_module_t::add_device(bus_t *bus) {
117 bus->add_device(DEBUG_START, this);
118 bus->add_device(DEBUG_EXCHANGE, &dmdata);
119 }
120
121 bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
122 {
123 addr = DEBUG_START + addr;
124
125 if (addr >= DEBUG_ROM_ENTRY &&
126 addr < DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE) {
127
128 if (read32(debug_rom_entry, dmcontrol.hartsel) == jal(ZERO, 0)) {
129 // We're here in an infinite loop. That means that whatever abstract
130 // command has complete.
131 abstractcs.busy = false;
132 }
133
134 action_executed = true;
135
136 halted[(addr - DEBUG_ROM_ENTRY) / 4] = true;
137 memcpy(bytes, debug_rom_entry + addr - DEBUG_ROM_ENTRY, len);
138 return true;
139 }
140
141 if (action_executed) {
142 // Restore the jump-to-self loop.
143 write32(debug_rom_entry, dmcontrol.hartsel, next_action);
144 next_action = jal(ZERO, 0);
145 action_executed = false;
146 }
147
148 if (addr >= DEBUG_ROM_CODE &&
149 addr < DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE) {
150
151 if (read32(debug_rom_code, 0) == dret()) {
152 abstractcs.busy = false;
153 halted[dmcontrol.hartsel] = false;
154 }
155
156 memcpy(bytes, debug_rom_code + addr - DEBUG_ROM_CODE, len);
157 return true;
158 }
159
160 if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
161 memcpy(bytes, program_buffer + addr - DEBUG_RAM_START, len);
162 return true;
163 }
164
165 if (addr >= DEBUG_ROM_EXCEPTION &&
166 addr < DEBUG_ROM_EXCEPTION + DEBUG_ROM_EXCEPTION_SIZE) {
167 memcpy(bytes, debug_rom_exception + addr - DEBUG_ROM_EXCEPTION, len);
168 if (abstractcs.cmderr == abstractcs.CMDERR_NONE) {
169 abstractcs.cmderr = abstractcs.CMDERR_EXCEPTION;
170 }
171 return true;
172 }
173
174 fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
175 PRIx64 "\n", len, addr);
176
177 return false;
178 }
179
180 bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
181 {
182 addr = DEBUG_START + addr;
183
184 if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
185 memcpy(program_buffer + addr - DEBUG_RAM_START, bytes, len);
186 return true;
187 }
188
189 fprintf(stderr, "ERROR: invalid store to debug module: %zd bytes at 0x%016"
190 PRIx64 "\n", len, addr);
191 return false;
192 }
193
194 void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
195 {
196 uint8_t* base = memory + index * 4;
197 base[0] = value & 0xff;
198 base[1] = (value >> 8) & 0xff;
199 base[2] = (value >> 16) & 0xff;
200 base[3] = (value >> 24) & 0xff;
201 }
202
203 uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
204 {
205 uint8_t* base = memory + index * 4;
206 uint32_t value = ((uint32_t) base[0]) |
207 (((uint32_t) base[1]) << 8) |
208 (((uint32_t) base[2]) << 16) |
209 (((uint32_t) base[3]) << 24);
210 return value;
211 }
212
213 processor_t *debug_module_t::current_proc() const
214 {
215 processor_t *proc = NULL;
216 try {
217 proc = sim->get_core(dmcontrol.hartsel);
218 } catch (const std::out_of_range&) {
219 }
220 return proc;
221 }
222
223 bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
224 {
225 uint32_t result = 0;
226 D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
227 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
228 unsigned i = address - DMI_DATA0;
229 result = dmdata.read32(4 * i);
230
231 if (abstractcs.busy && abstractcs.cmderr == abstractcs.CMDERR_NONE) {
232 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
233 }
234
235 if ((abstractauto.autoexecdata >> i) & 1)
236 perform_abstract_command();
237 } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
238 result = read32(program_buffer, address - DMI_PROGBUF0);
239 } else {
240 switch (address) {
241 case DMI_DMCONTROL:
242 {
243 processor_t *proc = current_proc();
244 if (proc)
245 dmcontrol.haltreq = proc->halt_request;
246
247 result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
248 result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq);
249 result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
250 result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset);
251 result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset);
252 result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
253 }
254 break;
255 case DMI_DMSTATUS:
256 {
257 processor_t *proc = current_proc();
258
259 dmstatus.allnonexistant = false;
260 dmstatus.allunavail = false;
261 dmstatus.allrunning = false;
262 dmstatus.allhalted = false;
263 if (proc) {
264 if (halted[dmcontrol.hartsel]) {
265 dmstatus.allhalted = true;
266 } else {
267 dmstatus.allrunning = true;
268 }
269 } else {
270 dmstatus.allnonexistant = true;
271 }
272 dmstatus.anynonexistant = dmstatus.allnonexistant;
273 dmstatus.anyunavail = dmstatus.allunavail;
274 dmstatus.anyrunning = dmstatus.allrunning;
275 dmstatus.anyhalted = dmstatus.allhalted;
276
277 result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
278 result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
279 result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
280 result = set_field(result, DMI_DMSTATUS_ALLHALTED, dmstatus.allhalted);
281 result = set_field(result, DMI_DMSTATUS_ANYNONEXISTENT, dmstatus.anynonexistant);
282 result = set_field(result, DMI_DMSTATUS_ANYUNAVAIL, dmstatus.anyunavail);
283 result = set_field(result, DMI_DMSTATUS_ANYRUNNING, dmstatus.anyrunning);
284 result = set_field(result, DMI_DMSTATUS_ANYHALTED, dmstatus.anyhalted);
285 result = set_field(result, DMI_DMSTATUS_AUTHENTICATED, dmstatus.authenticated);
286 result = set_field(result, DMI_DMSTATUS_AUTHBUSY, dmstatus.authbusy);
287 result = set_field(result, DMI_DMSTATUS_VERSIONHI, dmstatus.versionhi);
288 result = set_field(result, DMI_DMSTATUS_VERSIONLO, dmstatus.versionlo);
289 }
290 break;
291 case DMI_ABSTRACTCS:
292 result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
293 result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
294 result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
295 result = set_field(result, DMI_ABSTRACTCS_PROGSIZE, abstractcs.progsize);
296 break;
297 case DMI_ABSTRACTAUTO:
298 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, abstractauto.autoexecprogbuf);
299 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECDATA, abstractauto.autoexecdata);
300 break;
301 case DMI_COMMAND:
302 result = 0;
303 break;
304 default:
305 D(fprintf(stderr, "error\n"));
306 return false;
307 }
308 }
309 D(fprintf(stderr, "0x%x\n", result));
310 *value = result;
311 return true;
312 }
313
314 bool debug_module_t::perform_abstract_command()
315 {
316 if (abstractcs.cmderr != abstractcs.CMDERR_NONE)
317 return true;
318 if (abstractcs.busy) {
319 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
320 return true;
321 }
322
323 if ((command >> 24) == 0) {
324 // register access
325 unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
326 bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
327 unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
328
329 if (regno < 0x1000 || regno >= 0x1020) {
330 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
331 return true;
332 }
333
334 unsigned regnum = regno - 0x1000;
335
336 if (!halted[dmcontrol.hartsel]) {
337 abstractcs.cmderr = abstractcs.CMDERR_HALTRESUME;
338 return true;
339 }
340
341 switch (size) {
342 case 2:
343 if (write)
344 write32(debug_rom_code, 0, lw(regnum, ZERO, DEBUG_EXCHANGE));
345 else
346 write32(debug_rom_code, 0, sw(regnum, ZERO, DEBUG_EXCHANGE));
347 break;
348 case 3:
349 if (write)
350 write32(debug_rom_code, 0, ld(regnum, ZERO, DEBUG_EXCHANGE));
351 else
352 write32(debug_rom_code, 0, sd(regnum, ZERO, DEBUG_EXCHANGE));
353 break;
354 /*
355 case 4:
356 if (write)
357 write32(debug_rom_code, 0, lq(regnum, ZERO, DEBUG_EXCHANGE));
358 else
359 write32(debug_rom_code, 0, sq(regnum, ZERO, DEBUG_EXCHANGE));
360 break;
361 */
362 default:
363 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
364 return true;
365 }
366 if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
367 write32(debug_rom_code, 1, jal(ZERO, DEBUG_RAM_START - DEBUG_ROM_CODE - 4));
368 } else {
369 write32(debug_rom_code, 1, ebreak());
370 }
371
372 //TODO: Consider 'transfer' bit.
373 write32(debug_rom_entry, dmcontrol.hartsel,
374 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
375
376 write32(debug_rom_exception, dmcontrol.hartsel,
377 jal(ZERO, (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel) - DEBUG_ROM_EXCEPTION));
378 abstractcs.busy = true;
379 } else {
380 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
381 }
382 return true;
383 }
384
385 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
386 {
387 D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
388 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
389 unsigned i = address - DMI_DATA0;
390 dmdata.write32(4 * i, value);
391
392 if (abstractcs.busy && abstractcs.cmderr == abstractcs.CMDERR_NONE) {
393 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
394 }
395
396 if ((abstractauto.autoexecdata >> i) & 1)
397 perform_abstract_command();
398 return true;
399
400 } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
401 write32(program_buffer, address - DMI_PROGBUF0, value);
402 return true;
403 } else {
404 switch (address) {
405 case DMI_DMCONTROL:
406 {
407 dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
408 if (dmcontrol.dmactive) {
409 dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
410 dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
411 dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
412 dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
413 } else {
414 reset();
415 }
416 processor_t *proc = current_proc();
417 if (proc) {
418 proc->halt_request = dmcontrol.haltreq;
419 if (dmcontrol.resumereq) {
420 write32(debug_rom_code, 0, dret());
421 write32(debug_rom_entry, dmcontrol.hartsel,
422 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
423 abstractcs.busy = true;
424 }
425 }
426 }
427 return true;
428
429 case DMI_COMMAND:
430 command = value;
431 return perform_abstract_command();
432
433 case DMI_ABSTRACTCS:
434 if (get_field(value, DMI_ABSTRACTCS_CMDERR) == abstractcs.CMDERR_NONE) {
435 abstractcs.cmderr = abstractcs.CMDERR_NONE;
436 }
437 return true;
438
439 case DMI_ABSTRACTAUTO:
440 abstractauto.autoexecprogbuf = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
441 abstractauto.autoexecdata = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECDATA);
442 break;
443 }
444 }
445 return false;
446 }