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