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