+bool debug_module_t::perform_abstract_command()
+{
+ if (abstractcs.cmderr != CMDERR_NONE)
+ return true;
+ if (abstractcs.busy) {
+ abstractcs.cmderr = CMDERR_BUSY;
+ return true;
+ }
+
+ if ((command >> 24) == 0) {
+ // register access
+ unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
+ bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
+ unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
+
+ if (!halted[dmcontrol.hartsel]) {
+ abstractcs.cmderr = CMDERR_HALTRESUME;
+ return true;
+ }
+
+ if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
+
+ if (regno < 0x1000 || regno >= 0x1020) {
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
+
+ unsigned regnum = regno - 0x1000;
+
+ switch (size) {
+ case 2:
+ if (write)
+ write32(debug_abstract, 0, lw(regnum, ZERO, debug_data_start));
+ else
+ write32(debug_abstract, 0, sw(regnum, ZERO, debug_data_start));
+ break;
+ case 3:
+ if (write)
+ write32(debug_abstract, 0, ld(regnum, ZERO, debug_data_start));
+ else
+ write32(debug_abstract, 0, sd(regnum, ZERO, debug_data_start));
+ break;
+ /*
+ case 4:
+ if (write)
+ write32(debug_rom_code, 0, lq(regnum, ZERO, debug_data_start));
+ else
+ write32(debug_rom_code, 0, sq(regnum, ZERO, debug_data_start));
+ break;
+ */
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
+ } else {
+ //NOP
+ write32(debug_abstract, 0, addi(ZERO, ZERO, 0));
+ }
+
+ if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
+ // Since the next instruction is what we will use, just use nother NOP
+ // to get there.
+ write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
+ } else {
+ write32(debug_abstract, 1, ebreak());
+ }
+
+ debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
+
+ abstractcs.busy = true;
+ } else {
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ }
+ return true;
+}
+
+bool debug_module_t::dmi_write(unsigned address, uint32_t value)
+{
+ D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+
+ if (!dmstatus.authenticated && address != DMI_AUTHDATA &&
+ address != DMI_DMCONTROL)
+ return false;
+
+ if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
+ unsigned i = address - DMI_DATA0;
+ if (!abstractcs.busy)
+ write32(dmdata, address - DMI_DATA0, value);
+
+ if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
+ abstractcs.cmderr = CMDERR_BUSY;
+ }
+
+ if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) {
+ perform_abstract_command();
+ }
+ return true;
+
+ } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progbufsize) {
+ unsigned i = address - DMI_PROGBUF0;
+
+ if (!abstractcs.busy)
+ write32(program_buffer, i, value);
+
+ if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) {
+ perform_abstract_command();
+ }
+ return true;
+
+ } else {
+ switch (address) {
+ case DMI_DMCONTROL:
+ {
+ if (!dmcontrol.dmactive && get_field(value, DMI_DMCONTROL_DMACTIVE))
+ reset();
+ dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+ if (!dmstatus.authenticated)
+ return true;
+ if (dmcontrol.dmactive) {
+ dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
+ dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
+ dmcontrol.hartreset = get_field(value, DMI_DMCONTROL_HARTRESET);
+ dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
+ dmcontrol.hartsel = get_field(value, ((1L<<hartsellen)-1) <<
+ DMI_DMCONTROL_HARTSEL_OFFSET);
+ }
+ processor_t *proc = current_proc();
+ if (proc) {
+ proc->halt_request = dmcontrol.haltreq;
+ if (dmcontrol.resumereq) {
+ debug_rom_flags[dmcontrol.hartsel] |= (1 << DEBUG_ROM_FLAG_RESUME);
+ resumeack[dmcontrol.hartsel] = false;
+ }
+ if (dmcontrol.hartreset) {
+ proc->reset();
+ }
+ }
+ if (dmcontrol.ndmreset) {
+ for (size_t i = 0; i < sim->nprocs(); i++) {
+ proc = sim->get_core(i);
+ proc->reset();
+ }
+ }
+ }
+ return true;
+
+ case DMI_COMMAND:
+ command = value;
+ return perform_abstract_command();
+
+ case DMI_ABSTRACTCS:
+ abstractcs.cmderr = (cmderr_t) (((uint32_t) (abstractcs.cmderr)) & (~(uint32_t)(get_field(value, DMI_ABSTRACTCS_CMDERR))));
+ return true;
+
+ case DMI_ABSTRACTAUTO:
+ abstractauto.autoexecprogbuf = get_field(value,
+ DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
+ abstractauto.autoexecdata = get_field(value,
+ DMI_ABSTRACTAUTO_AUTOEXECDATA);
+ return true;
+ case DMI_SBCS:
+ sbcs.readonaddr = get_field(value, DMI_SBCS_SBREADONADDR);
+ sbcs.sbaccess = get_field(value, DMI_SBCS_SBACCESS);
+ sbcs.autoincrement = get_field(value, DMI_SBCS_SBAUTOINCREMENT);
+ sbcs.readondata = get_field(value, DMI_SBCS_SBREADONDATA);
+ sbcs.error &= ~get_field(value, DMI_SBCS_SBERROR);
+ return true;
+ case DMI_SBADDRESS0:
+ sbaddress[0] = value;
+ if (sbcs.error == 0 && sbcs.readonaddr) {
+ sb_read();
+ }
+ return true;
+ case DMI_SBADDRESS1:
+ sbaddress[1] = value;
+ return true;
+ case DMI_SBADDRESS2:
+ sbaddress[2] = value;
+ return true;
+ case DMI_SBADDRESS3:
+ sbaddress[3] = value;
+ return true;
+ case DMI_SBDATA0:
+ sbdata[0] = value;
+ if (sbcs.error == 0) {
+ sb_write();
+ if (sbcs.autoincrement && sbcs.error == 0) {
+ sb_autoincrement();
+ }
+ }
+ return true;
+ case DMI_SBDATA1:
+ sbdata[1] = value;
+ return true;
+ case DMI_SBDATA2:
+ sbdata[2] = value;
+ return true;
+ case DMI_SBDATA3:
+ sbdata[3] = value;
+ return true;
+ case DMI_AUTHDATA:
+ D(fprintf(stderr, "debug authentication: got 0x%x; 0x%x unlocks\n", value,
+ challenge + secret));
+ if (require_authentication) {
+ if (value == challenge + secret) {
+ dmstatus.authenticated = true;
+ } else {
+ dmstatus.authenticated = false;
+ challenge = random();
+ }
+ }
+ return true;
+ }
+ }
+ return false;