| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /*
- MSP430 Emulator
- Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
- "MSP430 Emulator" is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- "MSP430 Emulator" is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "debugger.h"
- extern uint8_t* MEMSPACE;
- Emulator *local_emu = NULL;
- bool exec_cmd (Emulator *emu, char *line, int len)
- {
- Cpu *cpu = emu->cpu;
- Debugger *deb = emu->debugger;
- char cmd[100] = {0};
- unsigned int op1 = 0, op2 = 0, op3 = 0;
- int ops;
- char bogus1[100] = {0};
- uint32_t bogus2 = 0, bogus3 = 0;
- ops = sscanf(line, "%s %u %u", cmd, &op1, &op2);
- //printf("Got %s, %u, %u - ops %d\n", cmd, op1, op2, ops);
- /* RESET / RESTART
-
- Resets the entire virtual machine to it's starting state.
- Puts the starting address back into Program Counter
- */
- if ( !strncasecmp("reset", cmd, sizeof "reset") ||
- !strncasecmp("restart", cmd, sizeof "restart"))
- {
- cpu->pc = 0xC000;
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
-
- // s [NUM], step NUM instructions forward, defaults to 1 //
- else if ( !strncasecmp("s", cmd, sizeof "s") ||
- !strncasecmp("step", cmd, sizeof "step"))
- {
- int steps = 1; // 1 step by default
- uint32_t i;
- if (ops == 2) {
- steps = (int) op1;
- }
- for (i = 0;i < steps;i++) {
- decode(emu, fetch(emu), EXECUTE);
- // Handle Peripherals
- handle_bcm(emu);
- handle_timer_a(emu);
- handle_port_1(emu);
- handle_usci(emu);
- }
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
-
- // Quit program //
- else if ( !strncasecmp("quit", cmd, sizeof "quit") ||
- !strncasecmp("q", cmd, sizeof "q"))
- {
- // This flag stops the main loop in main.c
- deb->quit = true;
- }
-
- // run the program until a breakpoint is hit //
- else if ( !strncasecmp("run", cmd, sizeof "run") ||
- !strncasecmp("r", cmd, sizeof "r"))
- {
- cpu->running = true;
- deb->debug_mode = false;
- update_register_display(emu);
- }
- // Display disassembly of N at HEX_ADDR: dis [N] [HEX_ADDR] //
- else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
- !strncasecmp("dis", cmd, sizeof "dis") ||
- !strncasecmp("disassemble", cmd, sizeof "disassemble")) {
- uint16_t start_addr = cpu->pc;
- uint32_t num = 10;
-
- ops = sscanf(line, "%s %u %X", bogus1, &bogus2, &bogus3);
-
- if (ops == 2) {
- sscanf(line, "%s %u", bogus1, &num);
- }
- else if (ops == 3) {
- sscanf(line, "%s %u %X", bogus1, &num, (unsigned int *)&start_addr);
- }
- disassemble(emu, start_addr, num);
- }
- else if ( !strncasecmp("dump", cmd, sizeof "dump" ))
- {
- char str[100] = {0};
- uint16_t start_addr = cpu->pc;
- uint32_t stride;
-
- sscanf(line, "%s %s", bogus1, str);
-
- // Is it a direct address or an adress in a register being spec'd
- if (str[0] >= '0' && str[0] <= '9') {
- sscanf(str, "%X", (unsigned int *) &start_addr);
- }
- else if (str[0] == '%' || str[0] == 'r' || str[0] == 'R')
- {
- uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(str));
- start_addr = *p;
- }
-
- stride = BYTE_STRIDE;
- dump_memory(emu, MEMSPACE, 0x0, start_addr, stride);
- }
- // Set REG/LOC VALUE
- else if ( !strncasecmp("set", cmd, sizeof "set") )
- {
- uint16_t value = 0;
- char reg_name_or_addr[50] = {0};
- char *reg_name = NULL;
- char *addr_str = NULL;
- //print_console(emu, "Not yet implemented.\n");
-
- sscanf(line, "%s %s %X", bogus1, reg_name_or_addr,
- (unsigned int*)&value);
-
- //printf("Got %s and %X\n", reg_name_or_addr, value);
- // Figure out if the value given is a reg name or addr
- int res = reg_name_to_num(reg_name_or_addr);
- if (res != -1) { // If its a reg name
- reg_name = reg_name_or_addr;
- printf("In reg part...\n");
-
- if (res == 2) { // SR (R2)
- set_sr_value(emu, value);
- }
- else { // All others
- uint16_t *p = (uint16_t*)get_reg_ptr(emu, res);
- *p = value;
- }
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
- else {
- addr_str = reg_name_or_addr;
- printf("In addr part...\n");
- uint16_t virtual_addr = (uint16_t) strtol(addr_str, NULL, 0);
- uint16_t *p = get_addr_ptr(virtual_addr);
- *p = value;
- }
- }
- // break BREAKPOINT_ADDRESS - set breakpoint //
- else if ( !strncasecmp("break", cmd, sizeof "break") )
- {
- if (deb->num_bps >= MAX_BREAKPOINTS) {
- //printf("Breakpoints are full.\n");
- print_console(emu, "Breakpoints are full.\n");
- return true;
- }
-
- ops = sscanf(line, "%s %X", bogus1, &bogus2);
- char entry[100] = {0};
- if (ops == 2) {
- sscanf(line, "%s %X", bogus1, (unsigned int *)
- &deb->bp_addresses[deb->num_bps]);
-
- sprintf(entry, "\n\t[Breakpoint [%d] Set]\n", deb->num_bps + 1);
- //printf("%s", entry);
- print_console(emu, entry);
- ++deb->num_bps;
- }
- else {
- //printf("error\n");
- print_console(emu, "error\n");
- }
- }
- // Display all breakpoints //
- else if ( !strncasecmp("bps", cmd, sizeof "bps" ))
- {
- char entry[100] = {0};
- if (deb->num_bps > 0) {
- deb->current_bp = 0;
- while (deb->current_bp < deb->num_bps) {
- sprintf(entry, "\t[%d] 0x%04X\n",
- deb->current_bp+1, deb->bp_addresses[deb->current_bp]);
- //printf("%s", entry);
- print_console(emu, entry);
- ++deb->current_bp;
- }
- }
- else {
- //printf("You have not set any breakpoints!\n");
- print_console(emu, "You have not set any breakpoints!\n");
- }
- }
- // Display registers //
- else if ( !strncasecmp("regs", cmd, sizeof "regs"))
- {
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
- // help, display a list of debugger cmds //
- else if ( !strncasecmp("help", cmd, sizeof "help") ||
- !strncasecmp("h", cmd, sizeof "h") )
- {
- display_help(emu);
- }
- // End the line loop, next instruction
- else
- {
- print_console(emu, "\t[Invalid command, type \"help\".]\n");
- }
- return true;
- }
- /* Main command loop */
- bool command_loop (Emulator *emu, char *buf, int len)
- {
- /*
- Cpu *cpu = emu->cpu;
- Debugger *debugger = emu->debugger;
- static uint16_t breakpoint_addresses[MAX_BREAKPOINTS];
- static uint8_t cur_bp_number = 0;
- char cmd[512];
- char *line;
- // Check for breakpoints //
- int i;
- for (i = 0;i < cur_bp_number;i++) {
- if (cpu->pc == breakpoint_addresses[i]) {
- debugger->run = 0; // Stop fast execution //
- debugger->debug_mode = true;
- printf("\n\t[Breakpoint %d hit]\n\n", i + 1);
- break;
- }
- }
- if (!debugger->disassemble_mode && debugger->debug_mode) {
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
-
- while (!debugger->run) {
- bzero(cmd, sizeof cmd);
- line = readline("\n>> ");
- if ( strlen(line) >= 1 ) {
- add_history(line);
- sscanf(line, "%s", cmd);
- line += strlen(cmd) + 1;
- }
- else {
- continue;
- }
-
- // reset the virtual machine
- if ( !strncasecmp("reset", cmd, sizeof "reset") ||
- !strncasecmp("restart", cmd, sizeof "restart")) {
-
- cpu->pc = 0xC000;
- break;
- }
- // s NUM_STEPS, step X instructions forward, defaults to 1
- else if ( !strncasecmp("s", cmd, sizeof "s") ||
- !strncasecmp("step", cmd, sizeof "step")) {
-
- unsigned int num_of_steps = 0;
- if (line[1] == ' ') {
- sscanf(line, "%u", &num_of_steps);
- printf("TODO:Stepping %u\n", num_of_steps);
- }
- break;
- }
- // run, run the program until a breakpoint is hit
- else if ( !strncasecmp("quit", cmd, sizeof "quit") ||
- !strncasecmp("q", cmd, sizeof "q")) {
- return false;
- }
- // run, run the program until a breakpoint is hit
- else if ( !strncasecmp("run", cmd, sizeof "run") ||
- !strncasecmp("r", cmd, sizeof "r")) {
- debugger->run = true;
- debugger->debug_mode = false;
-
- break;
- }
- // Display disassembly
- else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
- !strncasecmp("dis", cmd, sizeof "dis") ||
- !strncasecmp("disassemble", cmd, sizeof "disassemble")) {
- uint16_t start_addr;
- uint32_t num;
- int res;
- res = sscanf(line, "%X%u", (unsigned int *) &start_addr, &num);
- if (res <= 0) {
- start_addr = cpu->pc;
- num = 10;
- }
- else if (res == 1) {
- num = 10;
- }
- if (num > 0)
- disassemble(emu, start_addr, num);
- continue;
- }
- // Display all 16 registers
- else if ( !strncasecmp("regs", cmd, sizeof "regs")) {
- display_registers(emu);
- continue;
- }
-
- // Display all breakpoints
- else if ( !strncasecmp("bps", cmd, sizeof "bps" )) {
- if (cur_bp_number > 0) {
- int i;
- for (i = 0;i < cur_bp_number;i++) {
- printf("\t[%d] 0x%04X\n", i + 1, breakpoint_addresses[i]);
- }
- }
- else {
- puts("You have not set any breakpoints!\n");
- }
-
- continue;
- }
- else if ( !strncasecmp("dump", cmd, sizeof "dump" )) {
- char param1[33] = {0};
- uint16_t start_addr;
- uint32_t stride;
- sscanf(line, "%s", param1);
-
- // Is it a direct address or a an address in a register being spec'd
- if (param1[0] >= '0' && param1[0] <= '9') {
- sscanf(param1, "%X", (unsigned int *) &start_addr);
- }
- else if (param1[0] == '%' || param1[0] == 'r' || param1[0] == 'R') {
- uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(param1));
- start_addr = *p;
- }
-
- stride = BYTE_STRIDE;
- dump_memory(MEMSPACE, 0x0, start_addr, stride);
- }
- // Set REG/LOC VALUE
- else if ( !strncasecmp("set", cmd, sizeof "set") ) {
- int value = 0;
- char reg_name_or_addr[33];
-
- sscanf(line, "%s %X", reg_name_or_addr, &value);
- if ( reg_name_to_num(reg_name_or_addr) != -1 ) {
- uint16_t *p = (uint16_t *)get_reg_ptr(emu, reg_name_to_num(reg_name_or_addr) );
- *p = value;
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- }
- else {
- uint16_t virtual_addr = (uint16_t) strtol(reg_name_or_addr, NULL, 0);
- uint16_t *p = get_addr_ptr(virtual_addr);
- *p = value;
- }
- continue;
- }
- // break BREAKPOINT_ADDRESS
- else if ( !strncasecmp("break", cmd, sizeof "break") ) {
- if (cur_bp_number >= MAX_BREAKPOINTS) {
- printf("Too many breakpoints.\n");
- }
- else {
- sscanf(line, "%X", (unsigned int *)
- &breakpoint_addresses[cur_bp_number]);
- printf("\n\t[Breakpoint [%d] Set]\n", cur_bp_number + 1);
-
- ++cur_bp_number;
- }
-
- continue;
- }
- // help, display a list of debugger cmds
- else if ( !strncasecmp("help", cmd, sizeof "help") ||
- !strncasecmp("h", cmd, sizeof "h") ) {
- display_help(emu);
- }
- // End the line loop, next instruction
- else {
- puts("\t[Invalid command, type \"help\".]");
- continue;
- }
- }
- */
- return true;
- }
- //##########+++ Dump Memory Function +++##########
- void dump_memory ( Emulator *emu, uint8_t *MEM, uint32_t size, uint32_t start_addr, uint8_t stride)
- {
- uint32_t i, msp_addr = start_addr;
- MEM += start_addr;
- char str[100] = {0};
- puts("");
- print_console(emu, "\n");
- for (i = 0; i < 32; i += 8) {
- sprintf(str, "0x%04X:\t", msp_addr);
- printf("%s", str);
- print_console(emu, str);
- if ( stride == BYTE_STRIDE ) {
- sprintf(str, "0x%02X 0x%02X 0x%02X 0x%02X "\
- "0x%02X 0x%02X 0x%02X 0x%02X\n",
- *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),
- *(MEM+4),*(MEM+5),*(MEM+6),*(MEM+7));
- printf("%s", str);
- print_console(emu, str);
- }
- else if ( stride == WORD_STRIDE ) {
- printf("0x%02X%02X 0x%02X%02X 0x%02X%02X 0x%02X%02X\n",
- *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),*(MEM+4),
- *(MEM+5),*(MEM+6),*(MEM+7));
- }
- else if ( stride == DWORD_STRIDE ) {
- printf("0x%02X%02X%02X%02X 0x%02X%02X%02X%02X\n",
- *(MEM+0),*(MEM+1),*(MEM+2),*(MEM+3),*(MEM+4),
- *(MEM+5),*(MEM+6),*(MEM+7));
- }
-
- MEM += 8; // Increase character by 4
- msp_addr += 8; // Increase msp_addr by 4
- }
-
- puts("");
- }
- void setup_debugger(Emulator *emu)
- {
- local_emu = emu;
- Debugger *deb = emu->debugger;
- deb->debug_mode = true;
- deb->disassemble_mode = false;
- deb->quit = false;
- deb->web_interface = true;
- deb->web_server_ready = false;
- deb->web_firmware_uploaded = false;
- deb->console_interface = false;
- memset(deb->bp_addresses, 0, sizeof(deb->bp_addresses));
- deb->num_bps = 0;
- deb->current_bp = 0;
- }
- void handle_sigint(int sig)
- {
- if (local_emu == NULL) return;
- local_emu->cpu->running = false;
- local_emu->debugger->debug_mode = true;
- }
- void register_signal(int sig)
- {
- signal(sig, handle_sigint);
- }
- void handle_breakpoints (Emulator *emu)
- {
- int i;
- Cpu *cpu = emu->cpu;
- Debugger *deb = emu->debugger;
- char str[100] = {0};
- for (i = 0;i < deb->num_bps;i++) {
- if (cpu->pc == deb->bp_addresses[i]) {
- cpu->running = false;
- deb->debug_mode = true;
-
- sprintf(str, "\n\t[Breakpoint %d hit]\n\n", i + 1);
- printf("%s", str);
- print_console(emu, str);
-
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
-
- return;
- }
- }
- }
|