debugger.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. MSP430 Emulator
  3. Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
  4. "MSP430 Emulator" is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. "MSP430 Emulator" is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "debugger.h"
  16. extern uint8_t* MEMSPACE;
  17. Emulator *local_emu = NULL;
  18. bool exec_cmd (Emulator *emu, char *line, int len)
  19. {
  20. Cpu *cpu = emu->cpu;
  21. Debugger *deb = emu->debugger;
  22. char cmd[100] = {0};
  23. unsigned int op1 = 0, op2 = 0, op3 = 0;
  24. int ops;
  25. char bogus1[100] = {0};
  26. uint32_t bogus2 = 0, bogus3 = 0;
  27. ops = sscanf(line, "%s %u %u", cmd, &op1, &op2);
  28. //printf("Got %s, %u, %u - ops %d\n", cmd, op1, op2, ops);
  29. /* RESET / RESTART
  30. Resets the entire virtual machine to it's starting state.
  31. Puts the starting address back into Program Counter
  32. */
  33. if ( !strncasecmp("reset", cmd, sizeof "reset") ||
  34. !strncasecmp("restart", cmd, sizeof "restart"))
  35. {
  36. cpu->pc = 0xC000;
  37. display_registers(emu);
  38. disassemble(emu, cpu->pc, 1);
  39. }
  40. // s [NUM], step NUM instructions forward, defaults to 1 //
  41. else if ( !strncasecmp("s", cmd, sizeof "s") ||
  42. !strncasecmp("step", cmd, sizeof "step"))
  43. {
  44. int steps = 1; // 1 step by default
  45. uint32_t i;
  46. if (ops == 2) {
  47. steps = (int) op1;
  48. }
  49. for (i = 0;i < steps;i++) {
  50. decode(emu, fetch(emu), EXECUTE);
  51. // Handle Peripherals
  52. handle_bcm(emu);
  53. handle_timer_a(emu);
  54. handle_port_1(emu);
  55. handle_usci(emu);
  56. }
  57. display_registers(emu);
  58. disassemble(emu, cpu->pc, 1);
  59. }
  60. // Quit program //
  61. else if ( !strncasecmp("quit", cmd, sizeof "quit") ||
  62. !strncasecmp("q", cmd, sizeof "q"))
  63. {
  64. // This flag stops the main loop in main.c
  65. deb->quit = true;
  66. }
  67. // run the program until a breakpoint is hit //
  68. else if ( !strncasecmp("run", cmd, sizeof "run") ||
  69. !strncasecmp("r", cmd, sizeof "r"))
  70. {
  71. cpu->running = true;
  72. deb->debug_mode = false;
  73. update_register_display(emu);
  74. }
  75. // Display disassembly of N at HEX_ADDR: dis [N] [HEX_ADDR] //
  76. else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
  77. !strncasecmp("dis", cmd, sizeof "dis") ||
  78. !strncasecmp("disassemble", cmd, sizeof "disassemble"))
  79. {
  80. uint16_t start_addr = cpu->pc;
  81. uint32_t num = 10;
  82. ops = sscanf(line, "%s %u %X", bogus1, &bogus2, &bogus3);
  83. if (ops == 2) {
  84. sscanf(line, "%s %u", bogus1, &num);
  85. }
  86. else if (ops == 3) {
  87. sscanf(line, "%s %u %X", bogus1, &num,
  88. (unsigned int *)&start_addr);
  89. }
  90. disassemble(emu, start_addr, num);
  91. }
  92. else if ( !strncasecmp("dump", cmd, sizeof "dump" ))
  93. {
  94. char str[100] = {0};
  95. uint16_t start_addr = cpu->pc;
  96. uint32_t stride;
  97. sscanf(line, "%s %s", bogus1, str);
  98. // Is it a direct address or an adress in a register being spec'd
  99. if (str[0] >= '0' && str[0] <= '9') {
  100. sscanf(str, "%X", (unsigned int *) &start_addr);
  101. }
  102. else if (str[0] == '%' || str[0] == 'r' || str[0] == 'R')
  103. {
  104. uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(str));
  105. start_addr = *p;
  106. }
  107. stride = BYTE_STRIDE;
  108. dump_memory(emu, MEMSPACE, 0x0, start_addr, stride);
  109. }
  110. // Set REG/LOC VALUE
  111. else if ( !strncasecmp("set", cmd, sizeof "set") )
  112. {
  113. uint16_t value = 0;
  114. char reg_name_or_addr[50] = {0};
  115. char *reg_name = NULL;
  116. char *addr_str = NULL;
  117. //print_console(emu, "Not yet implemented.\n");
  118. sscanf(line, "%s %s %X", bogus1, reg_name_or_addr,
  119. (unsigned int*)&value);
  120. //printf("Got %s and %X\n", reg_name_or_addr, value);
  121. // Figure out if the value given is a reg name or addr
  122. int res = reg_name_to_num(reg_name_or_addr);
  123. if (res != -1) { // If its a reg name
  124. reg_name = reg_name_or_addr;
  125. printf("In reg part...\n");
  126. if (res == 2) { // SR (R2)
  127. set_sr_value(emu, value);
  128. }
  129. else { // All others
  130. uint16_t *p = (uint16_t*)get_reg_ptr(emu, res);
  131. *p = value;
  132. }
  133. display_registers(emu);
  134. disassemble(emu, cpu->pc, 1);
  135. }
  136. else {
  137. addr_str = reg_name_or_addr;
  138. printf("In addr part...\n");
  139. uint16_t virtual_addr = (uint16_t) strtol(addr_str, NULL, 0);
  140. uint16_t *p = get_addr_ptr(virtual_addr);
  141. *p = value;
  142. }
  143. }
  144. // break BREAKPOINT_ADDRESS - set breakpoint //
  145. else if ( !strncasecmp("break", cmd, sizeof "break") )
  146. {
  147. if (deb->num_bps >= MAX_BREAKPOINTS) {
  148. //printf("Breakpoints are full.\n");
  149. print_console(emu, "Breakpoints are full.\n");
  150. return true;
  151. }
  152. ops = sscanf(line, "%s %X", bogus1, &bogus2);
  153. char entry[100] = {0};
  154. if (ops == 2) {
  155. sscanf(line, "%s %X", bogus1, (unsigned int *)
  156. &deb->bp_addresses[deb->num_bps]);
  157. sprintf(entry, "\n\t[Breakpoint [%d] Set]\n", deb->num_bps + 1);
  158. //printf("%s", entry);
  159. print_console(emu, entry);
  160. ++deb->num_bps;
  161. }
  162. else {
  163. //printf("error\n");
  164. print_console(emu, "error\n");
  165. }
  166. }
  167. // Display all breakpoints //
  168. else if ( !strncasecmp("bps", cmd, sizeof "bps" ))
  169. {
  170. char entry[100] = {0};
  171. if (deb->num_bps > 0) {
  172. deb->current_bp = 0;
  173. while (deb->current_bp < deb->num_bps) {
  174. sprintf(entry, "\t[%d] 0x%04X\n",
  175. deb->current_bp+1, deb->bp_addresses[deb->current_bp]);
  176. //printf("%s", entry);
  177. print_console(emu, entry);
  178. ++deb->current_bp;
  179. }
  180. }
  181. else {
  182. //printf("You have not set any breakpoints!\n");
  183. print_console(emu, "You have not set any breakpoints!\n");
  184. }
  185. }
  186. // Display registers //
  187. else if ( !strncasecmp("regs", cmd, sizeof "regs"))
  188. {
  189. display_registers(emu);
  190. disassemble(emu, cpu->pc, 1);
  191. }
  192. // help, display a list of debugger cmds //
  193. else if ( !strncasecmp("help", cmd, sizeof "help") ||
  194. !strncasecmp("h", cmd, sizeof "h") )
  195. {
  196. display_help(emu);
  197. }
  198. // End the line loop, next instruction
  199. else
  200. {
  201. print_console(emu, "\t[Invalid command, type \"help\".]\n");
  202. }
  203. return true;
  204. }
  205. /* Main command loop */
  206. bool command_loop (Emulator *emu, char *buf, int len)
  207. {
  208. /*
  209. Cpu *cpu = emu->cpu;
  210. Debugger *debugger = emu->debugger;
  211. static uint16_t breakpoint_addresses[MAX_BREAKPOINTS];
  212. static uint8_t cur_bp_number = 0;
  213. char cmd[512];
  214. char *line;
  215. // Check for breakpoints //
  216. int i;
  217. for (i = 0;i < cur_bp_number;i++) {
  218. if (cpu->pc == breakpoint_addresses[i]) {
  219. debugger->run = 0; // Stop fast execution //
  220. debugger->debug_mode = true;
  221. printf("\n\t[Breakpoint %d hit]\n\n", i + 1);
  222. break;
  223. }
  224. }
  225. if (!debugger->disassemble_mode && debugger->debug_mode) {
  226. display_registers(emu);
  227. disassemble(emu, cpu->pc, 1);
  228. }
  229. while (!debugger->run) {
  230. bzero(cmd, sizeof cmd);
  231. line = readline("\n>> ");
  232. if ( strlen(line) >= 1 ) {
  233. add_history(line);
  234. sscanf(line, "%s", cmd);
  235. line += strlen(cmd) + 1;
  236. }
  237. else {
  238. continue;
  239. }
  240. // reset the virtual machine
  241. if ( !strncasecmp("reset", cmd, sizeof "reset") ||
  242. !strncasecmp("restart", cmd, sizeof "restart")) {
  243. cpu->pc = 0xC000;
  244. break;
  245. }
  246. // s NUM_STEPS, step X instructions forward, defaults to 1
  247. else if ( !strncasecmp("s", cmd, sizeof "s") ||
  248. !strncasecmp("step", cmd, sizeof "step")) {
  249. unsigned int num_of_steps = 0;
  250. if (line[1] == ' ') {
  251. sscanf(line, "%u", &num_of_steps);
  252. printf("TODO:Stepping %u\n", num_of_steps);
  253. }
  254. break;
  255. }
  256. // run, run the program until a breakpoint is hit
  257. else if ( !strncasecmp("quit", cmd, sizeof "quit") ||
  258. !strncasecmp("q", cmd, sizeof "q")) {
  259. return false;
  260. }
  261. // run, run the program until a breakpoint is hit
  262. else if ( !strncasecmp("run", cmd, sizeof "run") ||
  263. !strncasecmp("r", cmd, sizeof "r")) {
  264. debugger->run = true;
  265. debugger->debug_mode = false;
  266. break;
  267. }
  268. // Display disassembly
  269. else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
  270. !strncasecmp("dis", cmd, sizeof "dis") ||
  271. !strncasecmp("disassemble", cmd, sizeof "disassemble")) {
  272. uint16_t start_addr;
  273. uint32_t num;
  274. int res;
  275. res = sscanf(line, "%X%u", (unsigned int *) &start_addr, &num);
  276. if (res <= 0) {
  277. start_addr = cpu->pc;
  278. num = 10;
  279. }
  280. else if (res == 1) {
  281. num = 10;
  282. }
  283. if (num > 0)
  284. disassemble(emu, start_addr, num);
  285. continue;
  286. }
  287. // Display all 16 registers
  288. else if ( !strncasecmp("regs", cmd, sizeof "regs")) {
  289. display_registers(emu);
  290. continue;
  291. }
  292. // Display all breakpoints
  293. else if ( !strncasecmp("bps", cmd, sizeof "bps" )) {
  294. if (cur_bp_number > 0) {
  295. int i;
  296. for (i = 0;i < cur_bp_number;i++) {
  297. printf("\t[%d] 0x%04X\n", i + 1, breakpoint_addresses[i]);
  298. }
  299. }
  300. else {
  301. puts("You have not set any breakpoints!\n");
  302. }
  303. continue;
  304. }
  305. else if ( !strncasecmp("dump", cmd, sizeof "dump" )) {
  306. char param1[33] = {0};
  307. uint16_t start_addr;
  308. uint32_t stride;
  309. sscanf(line, "%s", param1);
  310. // Is it a direct address or a an address in a register being spec'd
  311. if (param1[0] >= '0' && param1[0] <= '9') {
  312. sscanf(param1, "%X", (unsigned int *) &start_addr);
  313. }
  314. else if (param1[0] == '%' || param1[0] == 'r' || param1[0] == 'R') {
  315. uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(param1));
  316. start_addr = *p;
  317. }
  318. stride = BYTE_STRIDE;
  319. dump_memory(MEMSPACE, 0x0, start_addr, stride);
  320. }
  321. // Set REG/LOC VALUE
  322. else if ( !strncasecmp("set", cmd, sizeof "set") ) {
  323. int value = 0;
  324. char reg_name_or_addr[33];
  325. sscanf(line, "%s %X", reg_name_or_addr, &value);
  326. if ( reg_name_to_num(reg_name_or_addr) != -1 ) {
  327. uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(reg_name_or_addr) );
  328. *p = value;
  329. display_registers(emu);
  330. disassemble(emu, cpu->pc, 1);
  331. }
  332. else {
  333. uint16_t virtual_addr = (uint16_t) strtol(reg_name_or_addr, NULL, 0);
  334. uint16_t *p = get_addr_ptr(virtual_addr);
  335. *p = value;
  336. }
  337. continue;
  338. }
  339. // break BREAKPOINT_ADDRESS
  340. else if ( !strncasecmp("break", cmd, sizeof "break") ) {
  341. if (cur_bp_number >= MAX_BREAKPOINTS) {
  342. printf("Too many breakpoints.\n");
  343. }
  344. else {
  345. sscanf(line, "%X", (unsigned int *)
  346. &breakpoint_addresses[cur_bp_number]);
  347. printf("\n\t[Breakpoint [%d] Set]\n", cur_bp_number + 1);
  348. ++cur_bp_number;
  349. }
  350. continue;
  351. }
  352. // help, display a list of debugger cmds
  353. else if ( !strncasecmp("help", cmd, sizeof "help") ||
  354. !strncasecmp("h", cmd, sizeof "h") ) {
  355. display_help(emu);
  356. }
  357. // End the line loop, next instruction
  358. else {
  359. puts("\t[Invalid command, type \"help\".]");
  360. continue;
  361. }
  362. }
  363. */
  364. return true;
  365. }
  366. //##########+++ Dump Memory Function +++##########
  367. void dump_memory ( Emulator *emu, uint8_t *MEM, uint32_t size, uint32_t start_addr, uint8_t stride)
  368. {
  369. uint32_t i, msp_addr = start_addr;
  370. MEM += start_addr;
  371. char str[100] = {0};
  372. puts("");
  373. print_console(emu, "\n");
  374. for (i = 0; i < 32; i += 8) {
  375. sprintf(str, "0x%04X:\t", msp_addr);
  376. printf("%s", str);
  377. print_console(emu, str);
  378. if ( stride == BYTE_STRIDE ) {
  379. sprintf(str, "0x%02X 0x%02X 0x%02X 0x%02X "\
  380. "0x%02X 0x%02X 0x%02X 0x%02X\n",
  381. *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),
  382. *(MEM+4),*(MEM+5),*(MEM+6),*(MEM+7));
  383. printf("%s", str);
  384. print_console(emu, str);
  385. }
  386. else if ( stride == WORD_STRIDE ) {
  387. printf("0x%02X%02X 0x%02X%02X 0x%02X%02X 0x%02X%02X\n",
  388. *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),*(MEM+4),
  389. *(MEM+5),*(MEM+6),*(MEM+7));
  390. }
  391. else if ( stride == DWORD_STRIDE ) {
  392. printf("0x%02X%02X%02X%02X 0x%02X%02X%02X%02X\n",
  393. *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),*(MEM+4),
  394. *(MEM+5),*(MEM+6),*(MEM+7));
  395. }
  396. MEM += 8; // Increase character by 4
  397. msp_addr += 8; // Increase msp_addr by 4
  398. }
  399. puts("");
  400. }
  401. void setup_debugger(Emulator *emu)
  402. {
  403. local_emu = emu;
  404. Debugger *deb = emu->debugger;
  405. deb->debug_mode = true;
  406. deb->disassemble_mode = false;
  407. deb->quit = false;
  408. deb->web_interface = true;
  409. deb->web_server_ready = false;
  410. deb->web_firmware_uploaded = false;
  411. deb->console_interface = false;
  412. memset(deb->bp_addresses, 0, sizeof(deb->bp_addresses));
  413. deb->num_bps = 0;
  414. deb->current_bp = 0;
  415. }
  416. void handle_sigint(int sig)
  417. {
  418. if (local_emu == NULL) return;
  419. local_emu->cpu->running = false;
  420. local_emu->debugger->debug_mode = true;
  421. }
  422. void register_signal(int sig)
  423. {
  424. signal(sig, handle_sigint);
  425. }
  426. void handle_breakpoints (Emulator *emu)
  427. {
  428. int i;
  429. Cpu *cpu = emu->cpu;
  430. Debugger *deb = emu->debugger;
  431. char str[100] = {0};
  432. for (i = 0;i < deb->num_bps;i++) {
  433. if (cpu->pc == deb->bp_addresses[i]) {
  434. cpu->running = false;
  435. deb->debug_mode = true;
  436. sprintf(str, "\n\t[Breakpoint %d hit]\n\n", i + 1);
  437. printf("%s", str);
  438. print_console(emu, str);
  439. display_registers(emu);
  440. disassemble(emu, cpu->pc, 1);
  441. return;
  442. }
  443. }
  444. }