debug: consider COMMAND.transfer bit, and implment HARTINFO
[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 // TODO : Autoexec progbuf.
239 result = read32(program_buffer, address - DMI_PROGBUF0);
240 } else {
241 switch (address) {
242 case DMI_DMCONTROL:
243 {
244 processor_t *proc = current_proc();
245 if (proc)
246 dmcontrol.haltreq = proc->halt_request;
247
248 result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
249 result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq);
250 result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
251 result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset);
252 result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset);
253 result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
254 }
255 break;
256 case DMI_DMSTATUS:
257 {
258 processor_t *proc = current_proc();
259
260 dmstatus.allnonexistant = false;
261 dmstatus.allunavail = false;
262 dmstatus.allrunning = false;
263 dmstatus.allhalted = false;
264 if (proc) {
265 if (halted[dmcontrol.hartsel]) {
266 dmstatus.allhalted = true;
267 } else {
268 dmstatus.allrunning = true;
269 }
270 } else {
271 dmstatus.allnonexistant = true;
272 }
273 dmstatus.anynonexistant = dmstatus.allnonexistant;
274 dmstatus.anyunavail = dmstatus.allunavail;
275 dmstatus.anyrunning = dmstatus.allrunning;
276 dmstatus.anyhalted = dmstatus.allhalted;
277
278 result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
279 result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
280 result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
281 result = set_field(result, DMI_DMSTATUS_ALLHALTED, dmstatus.allhalted);
282 result = set_field(result, DMI_DMSTATUS_ANYNONEXISTENT, dmstatus.anynonexistant);
283 result = set_field(result, DMI_DMSTATUS_ANYUNAVAIL, dmstatus.anyunavail);
284 result = set_field(result, DMI_DMSTATUS_ANYRUNNING, dmstatus.anyrunning);
285 result = set_field(result, DMI_DMSTATUS_ANYHALTED, dmstatus.anyhalted);
286 result = set_field(result, DMI_DMSTATUS_AUTHENTICATED, dmstatus.authenticated);
287 result = set_field(result, DMI_DMSTATUS_AUTHBUSY, dmstatus.authbusy);
288 result = set_field(result, DMI_DMSTATUS_VERSIONHI, dmstatus.versionhi);
289 result = set_field(result, DMI_DMSTATUS_VERSIONLO, dmstatus.versionlo);
290 }
291 break;
292 case DMI_ABSTRACTCS:
293 result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
294 result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
295 result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
296 result = set_field(result, DMI_ABSTRACTCS_PROGSIZE, abstractcs.progsize);
297 break;
298 case DMI_ABSTRACTAUTO:
299 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, abstractauto.autoexecprogbuf);
300 result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECDATA, abstractauto.autoexecdata);
301 break;
302 case DMI_COMMAND:
303 result = 0;
304 break;
305 case DMI_HARTINFO:
306 result = set_field(result, DMI_HARTINFO_NSCRATCH, 1);
307 result = set_field(result, DMI_HARTINFO_DATAACCESS, 1);
308 result = set_field(result, DMI_HARTINFO_DATASIZE, abstractcs.datacount);
309 result = set_field(result, DMI_HARTINFO_DATAADDR, DEBUG_EXCHANGE);
310 break;
311 default:
312 result = 0;
313 }
314 }
315 D(fprintf(stderr, "0x%x\n", result));
316 *value = result;
317 return true;
318 }
319
320 bool debug_module_t::perform_abstract_command()
321 {
322 if (abstractcs.cmderr != abstractcs.CMDERR_NONE)
323 return true;
324 if (abstractcs.busy) {
325 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
326 return true;
327 }
328
329 if ((command >> 24) == 0) {
330 // register access
331 unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
332 bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
333 unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
334
335 if (regno < 0x1000 || regno >= 0x1020) {
336 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
337 return true;
338 }
339
340 unsigned regnum = regno - 0x1000;
341
342 if (!halted[dmcontrol.hartsel]) {
343 abstractcs.cmderr = abstractcs.CMDERR_HALTRESUME;
344 return true;
345 }
346
347 if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
348 switch (size) {
349 case 2:
350 if (write)
351 write32(debug_rom_code, 0, lw(regnum, ZERO, DEBUG_EXCHANGE));
352 else
353 write32(debug_rom_code, 0, sw(regnum, ZERO, DEBUG_EXCHANGE));
354 break;
355 case 3:
356 if (write)
357 write32(debug_rom_code, 0, ld(regnum, ZERO, DEBUG_EXCHANGE));
358 else
359 write32(debug_rom_code, 0, sd(regnum, ZERO, DEBUG_EXCHANGE));
360 break;
361 /*
362 case 4:
363 if (write)
364 write32(debug_rom_code, 0, lq(regnum, ZERO, DEBUG_EXCHANGE));
365 else
366 write32(debug_rom_code, 0, sq(regnum, ZERO, DEBUG_EXCHANGE));
367 break;
368 */
369 default:
370 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
371 return true;
372 }
373 } else {
374 // Should be a NOP. Store DEBUG_EXCHANGE to x0.
375 write32(debug_rom_code, 0, sw(ZERO, ZERO, DEBUG_EXCHANGE));
376 }
377
378 if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
379 write32(debug_rom_code, 1, jal(ZERO, DEBUG_RAM_START - DEBUG_ROM_CODE - 4));
380 } else {
381 write32(debug_rom_code, 1, ebreak());
382 }
383
384 write32(debug_rom_entry, dmcontrol.hartsel,
385 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
386
387 write32(debug_rom_exception, dmcontrol.hartsel,
388 jal(ZERO, (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel) - DEBUG_ROM_EXCEPTION));
389 abstractcs.busy = true;
390 } else {
391 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
392 }
393 return true;
394 }
395
396 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
397 {
398 D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
399 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
400 unsigned i = address - DMI_DATA0;
401 dmdata.write32(4 * i, value);
402
403 if (abstractcs.busy && abstractcs.cmderr == abstractcs.CMDERR_NONE) {
404 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
405 }
406
407 if ((abstractauto.autoexecdata >> i) & 1)
408 perform_abstract_command();
409 return true;
410
411 } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
412 write32(program_buffer, address - DMI_PROGBUF0, value);
413 return true;
414 } else {
415 switch (address) {
416 case DMI_DMCONTROL:
417 {
418 dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
419 if (dmcontrol.dmactive) {
420 dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
421 dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
422 dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
423 dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
424 } else {
425 reset();
426 }
427 processor_t *proc = current_proc();
428 if (proc) {
429 proc->halt_request = dmcontrol.haltreq;
430 if (dmcontrol.resumereq) {
431 write32(debug_rom_code, 0, dret());
432 write32(debug_rom_entry, dmcontrol.hartsel,
433 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
434 abstractcs.busy = true;
435 }
436 }
437 }
438 return true;
439
440 case DMI_COMMAND:
441 command = value;
442 return perform_abstract_command();
443
444 case DMI_ABSTRACTCS:
445 if (get_field(value, DMI_ABSTRACTCS_CMDERR) == abstractcs.CMDERR_NONE) {
446 abstractcs.cmderr = abstractcs.CMDERR_NONE;
447 }
448 return true;
449
450 case DMI_ABSTRACTAUTO:
451 abstractauto.autoexecprogbuf = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
452 abstractauto.autoexecdata = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECDATA);
453 break;
454 }
455 }
456 return false;
457 }