3 #include "debug_module.h"
4 #include "debug_defines.h"
8 #include "debug_rom/debug_rom.h"
16 ///////////////////////// debug_module_t
18 debug_module_t::debug_module_t(sim_t
*sim
) : sim(sim
),
19 next_action(jal(ZERO
, 0)),
20 action_executed(false)
25 dmstatus
.authenticated
= 1;
26 dmstatus
.versionlo
= 2;
29 abstractcs
.progsize
= progsize
;
33 for (unsigned i
= 0; i
< DEBUG_ROM_ENTRY_SIZE
/ 4; i
++) {
34 write32(debug_rom_entry
, i
, jal(ZERO
, 0));
38 memset(program_buffer
, 0, sizeof(program_buffer
));
41 void debug_module_t::reset()
43 for (unsigned i
= 0; i
< sim
->nprocs(); i
++) {
44 processor_t
*proc
= sim
->get_core(i
);
46 proc
->halt_request
= false;
52 dmstatus
.authenticated
= 1;
53 dmstatus
.versionlo
= 2;
56 abstractcs
.datacount
= sizeof(dmdata
) / 4;
57 abstractcs
.progsize
= progsize
;
62 void debug_module_t::add_device(bus_t
*bus
) {
63 bus
->add_device(DEBUG_START
, this);
66 bool debug_module_t::load(reg_t addr
, size_t len
, uint8_t* bytes
)
68 addr
= DEBUG_START
+ addr
;
70 if (addr
>= DEBUG_ROM_ENTRY
&&
71 addr
< DEBUG_ROM_ENTRY
+ DEBUG_ROM_ENTRY_SIZE
) {
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;
79 action_executed
= true;
81 halted
[(addr
- DEBUG_ROM_ENTRY
) / 4] = true;
82 memcpy(bytes
, debug_rom_entry
+ addr
- DEBUG_ROM_ENTRY
, len
);
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;
93 if (addr
>= DEBUG_ROM_CODE
&&
94 addr
< DEBUG_ROM_CODE
+ DEBUG_ROM_CODE_SIZE
) {
96 if (read32(debug_rom_code
, 0) == dret()) {
97 abstractcs
.busy
= false;
98 halted
[dmcontrol
.hartsel
] = false;
99 resumeack
[dmcontrol
.hartsel
] = true;
102 fprintf(stderr
, "returning the debug rom code.\n");
103 memcpy(bytes
, debug_rom_code
+ addr
- DEBUG_ROM_CODE
, len
);
107 if (addr
>= DEBUG_DATA_START
&& addr
< DEBUG_DATA_END
) {
108 memcpy(bytes
, dmdata
+ addr
- DEBUG_DATA_START
, len
);
112 if (addr
>= DEBUG_PROGBUF_START
&& addr
< DEBUG_PROGBUF_END
) {
113 memcpy(bytes
, program_buffer
+ addr
- DEBUG_PROGBUF_START
, len
);
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
;
126 fprintf(stderr
, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
127 PRIx64
"\n", len
, addr
);
132 bool debug_module_t::store(reg_t addr
, size_t len
, const uint8_t* bytes
)
135 addr
= DEBUG_START
+ addr
;
137 if (addr
>= DEBUG_DATA_START
&& addr
< DEBUG_DATA_END
) {
138 memcpy(dmdata
+ addr
- DEBUG_DATA_START
, bytes
, len
);
142 if (addr
>= DEBUG_PROGBUF_START
&& addr
< DEBUG_PROGBUF_END
) {
143 memcpy(program_buffer
+ addr
- DEBUG_PROGBUF_START
, bytes
, len
);
147 fprintf(stderr
, "ERROR: invalid store to debug module: %zd bytes at 0x%016"
148 PRIx64
"\n", len
, addr
);
152 void debug_module_t::write32(uint8_t *memory
, unsigned int index
, uint32_t value
)
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;
161 uint32_t debug_module_t::read32(uint8_t *memory
, unsigned int index
)
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);
171 processor_t
*debug_module_t::current_proc() const
173 processor_t
*proc
= NULL
;
175 proc
= sim
->get_core(dmcontrol
.hartsel
);
176 } catch (const std::out_of_range
&) {
181 bool debug_module_t::dmi_read(unsigned address
, uint32_t *value
)
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
);
189 if (abstractcs
.busy
&& abstractcs
.cmderr
== CMDERR_NONE
) {
190 abstractcs
.cmderr
= CMDERR_BUSY
;
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
);
202 processor_t
*proc
= current_proc();
204 dmcontrol
.haltreq
= proc
->halt_request
;
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
);
216 processor_t
*proc
= current_proc();
218 dmstatus
.allnonexistant
= false;
219 dmstatus
.allunavail
= false;
220 dmstatus
.allrunning
= false;
221 dmstatus
.allhalted
= false;
222 dmstatus
.allresumeack
= false;
224 if (halted
[dmcontrol
.hartsel
]) {
225 dmstatus
.allhalted
= true;
227 dmstatus
.allrunning
= true;
230 dmstatus
.allnonexistant
= true;
232 dmstatus
.anynonexistant
= dmstatus
.allnonexistant
;
233 dmstatus
.anyunavail
= dmstatus
.allunavail
;
234 dmstatus
.anyrunning
= dmstatus
.allrunning
;
235 dmstatus
.anyhalted
= dmstatus
.allhalted
;
237 if (resumeack
[dmcontrol
.hartsel
]) {
238 dmstatus
.allresumeack
= true;
240 dmstatus
.allresumeack
= false;
243 dmstatus
.allresumeack
= false;
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
);
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
);
268 case DMI_ABSTRACTAUTO
:
269 result
= set_field(result
, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF
, abstractauto
.autoexecprogbuf
);
270 result
= set_field(result
, DMI_ABSTRACTAUTO_AUTOEXECDATA
, abstractauto
.autoexecdata
);
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
);
283 D(fprintf(stderr
, "Unexpected. Returning Error."));
287 D(fprintf(stderr
, "0x%x\n", result
));
292 bool debug_module_t::perform_abstract_command()
294 if (abstractcs
.cmderr
!= CMDERR_NONE
)
296 if (abstractcs
.busy
) {
297 abstractcs
.cmderr
= CMDERR_BUSY
;
301 if ((command
>> 24) == 0) {
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
);
307 if (regno
< 0x1000 || regno
>= 0x1020) {
308 abstractcs
.cmderr
= CMDERR_NOTSUP
;
312 unsigned regnum
= regno
- 0x1000;
314 if (!halted
[dmcontrol
.hartsel
]) {
315 abstractcs
.cmderr
= CMDERR_HALTRESUME
;
319 if (get_field(command
, AC_ACCESS_REGISTER_TRANSFER
)) {
323 write32(debug_rom_code
, 0, lw(regnum
, ZERO
, DEBUG_DATA_START
));
325 write32(debug_rom_code
, 0, sw(regnum
, ZERO
, DEBUG_DATA_START
));
329 write32(debug_rom_code
, 0, ld(regnum
, ZERO
, DEBUG_DATA_START
));
331 write32(debug_rom_code
, 0, sd(regnum
, ZERO
, DEBUG_DATA_START
));
336 write32(debug_rom_code, 0, lq(regnum, ZERO, DEBUG_DATA_START));
338 write32(debug_rom_code, 0, sq(regnum, ZERO, DEBUG_DATA_START));
342 abstractcs
.cmderr
= CMDERR_NOTSUP
;
346 // Should be a NOP. Store DEBUG_DATA to x0.
347 write32(debug_rom_code
, 0, sw(ZERO
, ZERO
, DEBUG_DATA_START
));
350 if (get_field(command
, AC_ACCESS_REGISTER_POSTEXEC
)) {
351 write32(debug_rom_code
, 1, jal(ZERO
, DEBUG_PROGBUF_START
- DEBUG_ROM_CODE
- 4));
353 write32(debug_rom_code
, 1, ebreak());
357 write32(debug_rom_entry
, dmcontrol
.hartsel
,
358 jal(ZERO
, DEBUG_ROM_CODE
- (DEBUG_ROM_ENTRY
+ 4 * dmcontrol
.hartsel
)));
360 write32(debug_rom_exception
, dmcontrol
.hartsel
,
361 jal(ZERO
, (DEBUG_ROM_ENTRY
+ 4 * dmcontrol
.hartsel
) - DEBUG_ROM_EXCEPTION
));
362 abstractcs
.busy
= true;
364 abstractcs
.cmderr
= CMDERR_NOTSUP
;
369 bool debug_module_t::dmi_write(unsigned address
, uint32_t value
)
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
);
376 if (abstractcs
.busy
&& abstractcs
.cmderr
== CMDERR_NONE
) {
377 abstractcs
.cmderr
= CMDERR_BUSY
;
380 if ((abstractauto
.autoexecdata
>> i
) & 1)
381 perform_abstract_command();
384 } else if (address
>= DMI_PROGBUF0
&& address
< DMI_PROGBUF0
+ progsize
) {
385 write32(program_buffer
, address
- DMI_PROGBUF0
, value
);
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
);
400 processor_t
*proc
= current_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;
416 return perform_abstract_command();
419 abstractcs
.cmderr
= (cmderr_t
) (((uint32_t) (abstractcs
.cmderr
)) & (~(uint32_t)(get_field(value
, DMI_ABSTRACTCS_CMDERR
))));
422 case DMI_ABSTRACTAUTO
:
423 abstractauto
.autoexecprogbuf
= get_field(value
, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF
);
424 abstractauto
.autoexecdata
= get_field(value
, DMI_ABSTRACTAUTO_AUTOEXECDATA
);