Implement program buffer preexec/postexec.
[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 D(fprintf(stderr, "debug_module_data_t load 0x%lx bytes at 0x%lx\n", len,
26 addr));
27
28 if (addr + len < sizeof(data)) {
29 memcpy(bytes, data + addr, len);
30 return true;
31 }
32
33 fprintf(stderr, "ERROR: invalid load from debug_module_data_t: %zd bytes at 0x%016"
34 PRIx64 "\n", len, addr);
35
36 return false;
37 }
38
39 bool debug_module_data_t::store(reg_t addr, size_t len, const uint8_t* bytes)
40 {
41 D(fprintf(stderr, "debug_module_data_t store 0x%lx bytes at 0x%lx\n", len,
42 addr));
43
44 if (addr + len < sizeof(data)) {
45 memcpy(data + addr, bytes, len);
46 return true;
47 }
48
49 fprintf(stderr, "ERROR: invalid store to debug_module_data_t: %zd bytes at 0x%016"
50 PRIx64 "\n", len, addr);
51 return false;
52 }
53
54 uint32_t debug_module_data_t::read32(reg_t addr) const
55 {
56 assert(addr + 4 <= sizeof(data));
57 return data[addr] |
58 (data[addr + 1] << 8) |
59 (data[addr + 2] << 16) |
60 (data[addr + 3] << 24);
61 }
62
63 void debug_module_data_t::write32(reg_t addr, uint32_t value)
64 {
65 fprintf(stderr, "debug_module_data_t::write32(0x%lx, 0x%x)\n", addr, value);
66 assert(addr + 4 <= sizeof(data));
67 data[addr] = value & 0xff;
68 data[addr + 1] = (value >> 8) & 0xff;
69 data[addr + 2] = (value >> 16) & 0xff;
70 data[addr + 3] = (value >> 24) & 0xff;
71 }
72
73 ///////////////////////// debug_module_t
74
75 debug_module_t::debug_module_t(sim_t *sim) : sim(sim),
76 next_action(jal(ZERO, 0)),
77 action_executed(false)
78 {
79 dmcontrol = {0};
80 dmcontrol.version = 1;
81
82 for (unsigned i = 0; i < DEBUG_ROM_ENTRY_SIZE / 4; i++) {
83 write32(debug_rom_entry, i, jal(ZERO, 0));
84 halted[i] = false;
85 }
86
87 memset(program_buffer, 0, sizeof(program_buffer));
88 }
89
90 void debug_module_t::reset()
91 {
92 for (unsigned i = 0; i < sim->nprocs(); i++) {
93 processor_t *proc = sim->get_core(i);
94 if (proc)
95 proc->halt_request = false;
96 }
97
98 dmcontrol = {0};
99 dmcontrol.authenticated = 1;
100 dmcontrol.version = 1;
101 dmcontrol.authtype = dmcontrol.AUTHTYPE_NOAUTH;
102
103 abstractcs = {0};
104 abstractcs.datacount = sizeof(dmdata.data) / 4;
105 }
106
107 void debug_module_t::add_device(bus_t *bus) {
108 bus->add_device(DEBUG_START, this);
109 bus->add_device(DEBUG_EXCHANGE, &dmdata);
110 }
111
112 bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
113 {
114 D(fprintf(stderr, "load 0x%lx bytes at 0x%lx\n",
115 len, addr));
116 addr = DEBUG_START + addr;
117
118 if (addr >= DEBUG_ROM_ENTRY &&
119 addr < DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE) {
120
121 if (read32(debug_rom_entry, dmcontrol.hartsel) == jal(ZERO, 0)) {
122 // We're here in an infinite loop. That means that whatever abstract
123 // command has complete.
124 abstractcs.busy = false;
125 }
126
127 action_executed = true;
128
129 halted[(addr - DEBUG_ROM_ENTRY) / 4] = true;
130 memcpy(bytes, debug_rom_entry + addr - DEBUG_ROM_ENTRY, len);
131 return true;
132 }
133
134 if (action_executed) {
135 // Restore the jump-to-self loop.
136 write32(debug_rom_entry, dmcontrol.hartsel, next_action);
137 next_action = jal(ZERO, 0);
138 action_executed = false;
139 }
140
141 if (addr >= DEBUG_ROM_CODE &&
142 addr < DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE) {
143 memcpy(bytes, debug_rom_code + addr - DEBUG_ROM_CODE, len);
144 return true;
145 }
146
147 if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
148 memcpy(bytes, program_buffer + addr - DEBUG_RAM_START, len);
149 return true;
150 }
151
152 if (addr >= DEBUG_ROM_EXCEPTION &&
153 addr < DEBUG_ROM_EXCEPTION + DEBUG_ROM_EXCEPTION_SIZE) {
154 memcpy(bytes, debug_rom_exception + addr - DEBUG_ROM_EXCEPTION, len);
155 if (abstractcs.cmderr == abstractcs.CMDERR_NONE) {
156 abstractcs.cmderr = abstractcs.CMDERR_EXCEPTION;
157 }
158 return true;
159 }
160
161 fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
162 PRIx64 "\n", len, addr);
163
164 return false;
165 }
166
167 bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
168 {
169 addr = DEBUG_START + addr;
170
171 if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
172 memcpy(program_buffer + addr - DEBUG_RAM_START, bytes, len);
173 return true;
174 }
175
176 fprintf(stderr, "ERROR: invalid store to debug module: %zd bytes at 0x%016"
177 PRIx64 "\n", len, addr);
178 return false;
179 }
180
181 void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
182 {
183 uint8_t* base = memory + index * 4;
184 base[0] = value & 0xff;
185 base[1] = (value >> 8) & 0xff;
186 base[2] = (value >> 16) & 0xff;
187 base[3] = (value >> 24) & 0xff;
188 }
189
190 uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
191 {
192 uint8_t* base = memory + index * 4;
193 uint32_t value = ((uint32_t) base[0]) |
194 (((uint32_t) base[1]) << 8) |
195 (((uint32_t) base[2]) << 16) |
196 (((uint32_t) base[3]) << 24);
197 return value;
198 }
199
200 processor_t *debug_module_t::current_proc() const
201 {
202 processor_t *proc = NULL;
203 try {
204 proc = sim->get_core(dmcontrol.hartsel);
205 } catch (const std::out_of_range&) {
206 }
207 return proc;
208 }
209
210 bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
211 {
212 uint32_t result = 0;
213 D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
214 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
215 result = dmdata.read32(4 * (address - DMI_DATA0));
216 } else if (address >= DMI_IBUF0 && address < DMI_IBUF0 + progsize) {
217 result = read32(program_buffer, address - DMI_IBUF0);
218 } else {
219 switch (address) {
220 case DMI_DMCONTROL:
221 {
222 processor_t *proc = current_proc();
223 if (proc) {
224 if (halted[dmcontrol.hartsel]) {
225 dmcontrol.hartstatus = dmcontrol.HARTSTATUS_HALTED;
226 } else {
227 dmcontrol.hartstatus = dmcontrol.HARTSTATUS_RUNNING;
228 }
229 dmcontrol.haltreq = proc->halt_request;
230 } else {
231 dmcontrol.hartstatus = dmcontrol.HARTSTATUS_NOTEXIST;
232 }
233 result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
234 result = set_field(result, DMI_DMCONTROL_RESET, dmcontrol.reset);
235 result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
236 result = set_field(result, DMI_DMCONTROL_HARTSTATUS, dmcontrol.hartstatus);
237 result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
238 result = set_field(result, DMI_DMCONTROL_AUTHENTICATED, dmcontrol.authenticated);
239 result = set_field(result, DMI_DMCONTROL_AUTHBUSY, dmcontrol.authbusy);
240 result = set_field(result, DMI_DMCONTROL_AUTHTYPE, dmcontrol.authtype);
241 result = set_field(result, DMI_DMCONTROL_VERSION, dmcontrol.version);
242 }
243 break;
244 case DMI_ABSTRACTCS:
245 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC7, abstractcs.autoexec7);
246 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC6, abstractcs.autoexec6);
247 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC5, abstractcs.autoexec5);
248 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC4, abstractcs.autoexec4);
249 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC3, abstractcs.autoexec3);
250 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC2, abstractcs.autoexec2);
251 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC1, abstractcs.autoexec1);
252 result = set_field(result, DMI_ABSTRACTCS_AUTOEXEC0, abstractcs.autoexec0);
253 result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
254 result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
255 result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
256 break;
257 case DMI_ACCESSCS:
258 result = progsize << DMI_ACCESSCS_PROGSIZE_OFFSET;
259 break;
260 case DMI_COMMAND:
261 result = 0;
262 break;
263 default:
264 D(fprintf(stderr, "error\n"));
265 return false;
266 }
267 }
268 D(fprintf(stderr, "0x%x\n", result));
269 *value = result;
270 return true;
271 }
272
273 bool debug_module_t::perform_abstract_command(uint32_t command)
274 {
275 if (abstractcs.cmderr != abstractcs.CMDERR_NONE)
276 return true;
277 if (abstractcs.busy) {
278 abstractcs.cmderr = abstractcs.CMDERR_BUSY;
279 return true;
280 }
281
282 if ((command >> 24) == 0) {
283 // register access
284 unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
285 bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
286 unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
287
288 if (regno < 0x1000 || regno >= 0x1020) {
289 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
290 return true;
291 }
292
293 unsigned regnum = regno - 0x1000;
294
295 if (!halted[dmcontrol.hartsel]) {
296 abstractcs.cmderr = abstractcs.CMDERR_HALTRESUME;
297 return true;
298 }
299
300 switch (size) {
301 case 2:
302 if (write)
303 write32(debug_rom_code, 0, lw(regnum, ZERO, DEBUG_EXCHANGE));
304 else
305 write32(debug_rom_code, 0, sw(regnum, ZERO, DEBUG_EXCHANGE));
306 break;
307 case 3:
308 if (write)
309 write32(debug_rom_code, 0, ld(regnum, ZERO, DEBUG_EXCHANGE));
310 else
311 write32(debug_rom_code, 0, sd(regnum, ZERO, DEBUG_EXCHANGE));
312 break;
313 /*
314 case 4:
315 if (write)
316 write32(debug_rom_code, 0, lq(regnum, ZERO, DEBUG_EXCHANGE));
317 else
318 write32(debug_rom_code, 0, sq(regnum, ZERO, DEBUG_EXCHANGE));
319 break;
320 */
321 default:
322 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
323 return true;
324 }
325 if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
326 write32(debug_rom_code, 1, jal(ZERO, DEBUG_RAM_START - DEBUG_ROM_CODE - 4));
327 } else {
328 write32(debug_rom_code, 1, ebreak());
329 }
330
331 if (get_field(command, AC_ACCESS_REGISTER_PREEXEC)) {
332 write32(debug_rom_entry, dmcontrol.hartsel,
333 jal(ZERO, DEBUG_RAM_START - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
334 next_action =
335 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel));
336 } else {
337 write32(debug_rom_entry, dmcontrol.hartsel,
338 jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
339 }
340
341 write32(debug_rom_exception, dmcontrol.hartsel,
342 jal(ZERO, (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel) - DEBUG_ROM_EXCEPTION));
343 abstractcs.busy = true;
344 } else {
345 abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
346 }
347 return true;
348 }
349
350 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
351 {
352 D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
353 if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
354 dmdata.write32(4 * (address - DMI_DATA0), value);
355 return true;
356 } else if (address >= DMI_IBUF0 && address < DMI_IBUF0 + progsize) {
357 write32(program_buffer, address - DMI_IBUF0, value);
358 return true;
359 } else {
360 switch (address) {
361 case DMI_DMCONTROL:
362 {
363 dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
364 if (dmcontrol.dmactive) {
365 dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
366 dmcontrol.reset = get_field(value, DMI_DMCONTROL_RESET);
367 dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
368 } else {
369 reset();
370 }
371 processor_t *proc = current_proc();
372 if (proc) {
373 proc->halt_request = dmcontrol.haltreq;
374 }
375 }
376 return true;
377
378 case DMI_COMMAND:
379 return perform_abstract_command(value);
380
381 case DMI_ABSTRACTCS:
382 abstractcs.autoexec7 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC7);
383 abstractcs.autoexec6 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC6);
384 abstractcs.autoexec5 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC5);
385 abstractcs.autoexec4 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC4);
386 abstractcs.autoexec3 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC3);
387 abstractcs.autoexec2 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC2);
388 abstractcs.autoexec1 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC1);
389 abstractcs.autoexec0 = get_field(value, DMI_ABSTRACTCS_AUTOEXEC0);
390 if (get_field(value, DMI_ABSTRACTCS_CMDERR) == abstractcs.CMDERR_NONE) {
391 abstractcs.cmderr = abstractcs.CMDERR_NONE;
392 }
393 return true;
394 }
395 }
396 return false;
397 }