Make progbuf a run-time option.
[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 #include "debug_rom/debug_rom_defines.h"
10
11 #if 0
12 # define D(x) x
13 #else
14 # define D(x)
15 #endif
16
17 ///////////////////////// debug_module_t
18
19 debug_module_t::debug_module_t(sim_t *sim, unsigned progsize) :
20 progsize(progsize),
21 program_buffer_bytes(4 + 4*progsize),
22 debug_progbuf_start(debug_data_start - program_buffer_bytes),
23 debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
24 sim(sim)
25 {
26 dmcontrol = {0};
27
28 dmstatus = {0};
29 dmstatus.authenticated = 1;
30 dmstatus.versionlo = 2;
31
32 abstractcs = {0};
33 abstractcs.progsize = progsize;
34
35 abstractauto = {0};
36
37 program_buffer = new uint8_t[program_buffer_bytes];
38
39 memset(halted, 0, sizeof(halted));
40 memset(debug_rom_flags, 0, sizeof(debug_rom_flags));
41 memset(resumeack, 0, sizeof(resumeack));
42 memset(program_buffer, 0, program_buffer_bytes);
43 program_buffer[progsize] = ebreak();
44 memset(dmdata, 0, sizeof(dmdata));
45
46 write32(debug_rom_whereto, 0,
47 jal(ZERO, debug_abstract_start - DEBUG_ROM_WHERETO));
48
49 memset(debug_abstract, 0, sizeof(debug_abstract));
50 }
51
52 debug_module_t::~debug_module_t()
53 {
54 delete[] program_buffer;
55 }
56
57 void debug_module_t::reset()
58 {
59 for (unsigned i = 0; i < sim->nprocs(); i++) {
60 processor_t *proc = sim->get_core(i);
61 if (proc)
62 proc->halt_request = false;
63 }
64
65 dmcontrol = {0};
66
67 dmstatus = {0};
68 dmstatus.authenticated = 1;
69 dmstatus.versionlo = 2;
70
71 abstractcs = {0};
72 abstractcs.datacount = sizeof(dmdata) / 4;
73 abstractcs.progsize = progsize;
74
75 abstractauto = {0};
76 }
77
78 void debug_module_t::add_device(bus_t *bus) {
79 bus->add_device(DEBUG_START, this);
80 }
81
82 bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
83 {
84 addr = DEBUG_START + addr;
85
86 if (addr >= DEBUG_ROM_ENTRY &&
87 (addr + len) <= (DEBUG_ROM_ENTRY + debug_rom_raw_len)) {
88 memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_ENTRY, len);
89 return true;
90 }
91
92 if (addr >= DEBUG_ROM_WHERETO && (addr + len) <= (DEBUG_ROM_WHERETO + 4)) {
93 memcpy(bytes, debug_rom_whereto + addr - DEBUG_ROM_WHERETO, len);
94 return true;
95 }
96
97 if (addr >= DEBUG_ROM_FLAGS && ((addr + len) <= DEBUG_ROM_FLAGS + 1024)) {
98 memcpy(bytes, debug_rom_flags + addr - DEBUG_ROM_FLAGS, len);
99 return true;
100 }
101
102 if (addr >= debug_abstract_start && ((addr + len) <= (debug_abstract_start + sizeof(debug_abstract)))) {
103 memcpy(bytes, debug_abstract + addr - debug_abstract_start, len);
104 return true;
105 }
106
107 if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
108 memcpy(bytes, dmdata + addr - debug_data_start, len);
109 return true;
110 }
111
112 if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) {
113 memcpy(bytes, program_buffer + addr - debug_progbuf_start, len);
114 return true;
115 }
116
117 fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
118 PRIx64 "\n", len, addr);
119
120 return false;
121 }
122
123 bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
124 {
125 D(
126 switch (len) {
127 case 4:
128 fprintf(stderr, "store(addr=0x%lx, len=%d, bytes=0x%08x); "
129 "hartsel=0x%x\n", addr, (unsigned) len, *(uint32_t *) bytes,
130 dmcontrol.hartsel);
131 break;
132 default:
133 fprintf(stderr, "store(addr=0x%lx, len=%d, bytes=...); "
134 "hartsel=0x%x\n", addr, (unsigned) len, dmcontrol.hartsel);
135 break;
136 }
137 );
138
139 uint8_t id_bytes[4];
140 uint32_t id = 0;
141 if (len == 4) {
142 memcpy(id_bytes, bytes, 4);
143 id = read32(id_bytes, 0);
144 }
145
146 addr = DEBUG_START + addr;
147
148 if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
149 memcpy(dmdata + addr - debug_data_start, bytes, len);
150 return true;
151 }
152
153 if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) {
154 memcpy(program_buffer + addr - debug_progbuf_start, bytes, len);
155
156 return true;
157 }
158
159 if (addr == DEBUG_ROM_HALTED) {
160 assert (len == 4);
161 halted[id] = true;
162 if (dmcontrol.hartsel == id) {
163 if (0 == (debug_rom_flags[id] & (1 << DEBUG_ROM_FLAG_GO))){
164 if (dmcontrol.hartsel == id) {
165 abstractcs.busy = false;
166 }
167 }
168 }
169 return true;
170 }
171
172 if (addr == DEBUG_ROM_GOING) {
173 debug_rom_flags[dmcontrol.hartsel] &= ~(1 << DEBUG_ROM_FLAG_GO);
174 return true;
175 }
176
177 if (addr == DEBUG_ROM_RESUMING) {
178 assert (len == 4);
179 halted[id] = false;
180 resumeack[id] = true;
181 debug_rom_flags[id] &= ~(1 << DEBUG_ROM_FLAG_RESUME);
182 return true;
183 }
184
185 if (addr == DEBUG_ROM_EXCEPTION) {
186 if (abstractcs.cmderr == CMDERR_NONE) {
187 abstractcs.cmderr = CMDERR_EXCEPTION;
188 }
189 return true;
190 }
191
192 fprintf(stderr, "ERROR: invalid store to debug module: %zd bytes at 0x%016"
193 PRIx64 "\n", len, addr);
194 return false;
195 }
196
197 void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
198 {
199 uint8_t* base = memory + index * 4;
200 base[0] = value & 0xff;
201 base[1] = (value >> 8) & 0xff;
202 base[2] = (value >> 16) & 0xff;
203 base[3] = (value >> 24) & 0xff;
204 }
205
206 uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
207 {
208 uint8_t* base = memory + index * 4;
209 uint32_t value = ((uint32_t) base[0]) |
210 (((uint32_t) base[1]) << 8) |
211 (((uint32_t) base[2]) << 16) |
212 (((uint32_t) base[3]) << 24);
213 return value;
214 }
215
216 processor_t *debug_module_t::current_proc() const
217 {
218 processor_t *proc = NULL;
219 try {
220 proc = sim->get_core(dmcontrol.hartsel);
221 } catch (const std::out_of_range&) {
222 }
223 return proc;
224 }
225
226 bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
227 {
228 uint32_t result = 0;
229 D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
230 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
231 unsigned i = address - DMI_DATA0;
232 result = read32(dmdata, i);
233 if (abstractcs.busy) {
234 result = -1;
235 fprintf(stderr, "\ndmi_read(0x%02x (data[%d]) -> -1 because abstractcs.busy==true\n", address, i);
236 }
237
238 if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
239 abstractcs.cmderr = CMDERR_BUSY;
240 }
241
242 if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) {
243 perform_abstract_command();
244 }
245 } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
246 unsigned i = address - DMI_PROGBUF0;
247 result = read32(program_buffer, i);
248 if (abstractcs.busy) {
249 result = -1;
250 fprintf(stderr, "\ndmi_read(0x%02x (progbuf[%d]) -> -1 because abstractcs.busy==true\n", address, i);
251 }
252 if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) {
253 perform_abstract_command();
254 }
255
256 } else {
257 switch (address) {
258 case DMI_DMCONTROL:
259 {
260 processor_t *proc = current_proc();
261 if (proc)
262 dmcontrol.haltreq = proc->halt_request;
263
264 result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
265 result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq);
266 result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
267 result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset);
268 result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset);
269 result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
270 }
271 break;
272 case DMI_DMSTATUS:
273 {
274 processor_t *proc = current_proc();
275
276 dmstatus.allnonexistant = false;
277 dmstatus.allunavail = false;
278 dmstatus.allrunning = false;
279 dmstatus.allhalted = false;
280 dmstatus.allresumeack = false;
281 if (proc) {
282 if (halted[dmcontrol.hartsel]) {
283 dmstatus.allhalted = true;
284 } else {
285 dmstatus.allrunning = true;
286 }
287 } else {
288 dmstatus.allnonexistant = true;
289 }
290 dmstatus.anynonexistant = dmstatus.allnonexistant;
291 dmstatus.anyunavail = dmstatus.allunavail;
292 dmstatus.anyrunning = dmstatus.allrunning;
293 dmstatus.anyhalted = dmstatus.allhalted;
294 if (proc) {
295 if (resumeack[dmcontrol.hartsel]) {
296 dmstatus.allresumeack = true;
297 } else {
298 dmstatus.allresumeack = false;
299 }
300 } else {
301 dmstatus.allresumeack = false;
302 }
303
304 result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
305 result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
306 result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
307 result = set_field(result, DMI_DMSTATUS_ALLHALTED, dmstatus.allhalted);
308 result = set_field(result, DMI_DMSTATUS_ALLRESUMEACK, dmstatus.allresumeack);
309 result = set_field(result, DMI_DMSTATUS_ANYNONEXISTENT, dmstatus.anynonexistant);
310 result = set_field(result, DMI_DMSTATUS_ANYUNAVAIL, dmstatus.anyunavail);
311 result = set_field(result, DMI_DMSTATUS_ANYRUNNING, dmstatus.anyrunning);
312 result = set_field(result, DMI_DMSTATUS_ANYHALTED, dmstatus.anyhalted);
313 result = set_field(result, DMI_DMSTATUS_ANYRESUMEACK, dmstatus.anyresumeack);
314 result = set_field(result, DMI_DMSTATUS_AUTHENTICATED, dmstatus.authenticated);
315 result = set_field(result, DMI_DMSTATUS_AUTHBUSY, dmstatus.authbusy);
316 result = set_field(result, DMI_DMSTATUS_VERSIONHI, dmstatus.versionhi);
317 result = set_field(result, DMI_DMSTATUS_VERSIONLO, dmstatus.versionlo);
318 }
319 break;
320 case DMI_ABSTRACTCS:
321 result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
322 result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
323 result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
324 result = set_field(result, DMI_ABSTRACTCS_PROGSIZE, abstractcs.progsize);
325 break;
326 case DMI_ABSTRACTAUTO:
327 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, abstractauto.autoexecprogbuf);
328 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECDATA, abstractauto.autoexecdata);
329 break;
330 case DMI_COMMAND:
331 result = 0;
332 break;
333 case DMI_HARTINFO:
334 result = set_field(result, DMI_HARTINFO_NSCRATCH, 1);
335 result = set_field(result, DMI_HARTINFO_DATAACCESS, 1);
336 result = set_field(result, DMI_HARTINFO_DATASIZE, abstractcs.datacount);
337 result = set_field(result, DMI_HARTINFO_DATAADDR, debug_data_start);
338 break;
339 default:
340 result = 0;
341 D(fprintf(stderr, "Unexpected. Returning Error."));
342 return false;
343 }
344 }
345 D(fprintf(stderr, "0x%x\n", result));
346 *value = result;
347 return true;
348 }
349
350 bool debug_module_t::perform_abstract_command()
351 {
352 if (abstractcs.cmderr != CMDERR_NONE)
353 return true;
354 if (abstractcs.busy) {
355 abstractcs.cmderr = CMDERR_BUSY;
356 return true;
357 }
358
359 if ((command >> 24) == 0) {
360 // register access
361 unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
362 bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
363 unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
364
365 if (!halted[dmcontrol.hartsel]) {
366 abstractcs.cmderr = CMDERR_HALTRESUME;
367 return true;
368 }
369
370 if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
371
372 if (regno < 0x1000 || regno >= 0x1020) {
373 abstractcs.cmderr = CMDERR_NOTSUP;
374 return true;
375 }
376
377 unsigned regnum = regno - 0x1000;
378
379 switch (size) {
380 case 2:
381 if (write)
382 write32(debug_abstract, 0, lw(regnum, ZERO, debug_data_start));
383 else
384 write32(debug_abstract, 0, sw(regnum, ZERO, debug_data_start));
385 break;
386 case 3:
387 if (write)
388 write32(debug_abstract, 0, ld(regnum, ZERO, debug_data_start));
389 else
390 write32(debug_abstract, 0, sd(regnum, ZERO, debug_data_start));
391 break;
392 /*
393 case 4:
394 if (write)
395 write32(debug_rom_code, 0, lq(regnum, ZERO, debug_data_start));
396 else
397 write32(debug_rom_code, 0, sq(regnum, ZERO, debug_data_start));
398 break;
399 */
400 default:
401 abstractcs.cmderr = CMDERR_NOTSUP;
402 return true;
403 }
404 } else {
405 //NOP
406 write32(debug_abstract, 0, addi(ZERO, ZERO, 0));
407 }
408
409 if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
410 // Since the next instruction is what we will use, just use nother NOP
411 // to get there.
412 write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
413 } else {
414 write32(debug_abstract, 1, ebreak());
415 }
416
417 debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
418
419 abstractcs.busy = true;
420 } else {
421 abstractcs.cmderr = CMDERR_NOTSUP;
422 }
423 return true;
424 }
425
426 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
427 {
428 D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
429 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
430 unsigned i = address - DMI_DATA0;
431 if (!abstractcs.busy)
432 write32(dmdata, address - DMI_DATA0, value);
433
434 if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
435 abstractcs.cmderr = CMDERR_BUSY;
436 }
437
438 if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) {
439 perform_abstract_command();
440 }
441 return true;
442
443 } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
444 unsigned i = address - DMI_PROGBUF0;
445
446 if (!abstractcs.busy)
447 write32(program_buffer, i, value);
448
449 if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) {
450 perform_abstract_command();
451 }
452 return true;
453
454 } else {
455 switch (address) {
456 case DMI_DMCONTROL:
457 {
458 dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
459 if (dmcontrol.dmactive) {
460 dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
461 dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
462 dmcontrol.hartreset = get_field(value, DMI_DMCONTROL_HARTRESET);
463 dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
464 dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
465 } else {
466 reset();
467 }
468 processor_t *proc = current_proc();
469 if (proc) {
470 proc->halt_request = dmcontrol.haltreq;
471 if (dmcontrol.resumereq) {
472 debug_rom_flags[dmcontrol.hartsel] |= (1 << DEBUG_ROM_FLAG_RESUME);
473 resumeack[dmcontrol.hartsel] = false;
474 }
475 if (dmcontrol.hartreset) {
476 proc->reset();
477 }
478 }
479 if (dmcontrol.ndmreset) {
480 for (size_t i = 0; i < sim->nprocs(); i++) {
481 proc = sim->get_core(i);
482 proc->reset();
483 }
484 }
485 }
486 return true;
487
488 case DMI_COMMAND:
489 command = value;
490 return perform_abstract_command();
491
492 case DMI_ABSTRACTCS:
493 abstractcs.cmderr = (cmderr_t) (((uint32_t) (abstractcs.cmderr)) & (~(uint32_t)(get_field(value, DMI_ABSTRACTCS_CMDERR))));
494 return true;
495
496 case DMI_ABSTRACTAUTO:
497 abstractauto.autoexecprogbuf = get_field(value,
498 DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
499 abstractauto.autoexecdata = get_field(value,
500 DMI_ABSTRACTAUTO_AUTOEXECDATA);
501 return true;
502 }
503 }
504 return false;
505 }