/* Nios-sim - one simple NIOSII simulator only for personal interest and fun. Copyright (C) 2010 chysun2000@gmail.com This program 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 2 of the License, or (at your option) any later version. This program 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "public.h" #include "niosii.h" #include "io_device.h" #include "simulator.h" static int32_t simulator_mode = SIM_MODE; static void modify_pc(struct NIOS_CPU * cpu) { cpu->pc += 4; } static void set_init_pc(struct NIOS_CPU * cpu, uint32_t pc) { cpu->pc = pc; } static void quit_debug_mode(struct NIOS_CPU * cpu) { simulator_mode = SIM_MODE; cpu->mode = NORMAL_MODE; cpu->break_pc = 0; } int32_t get_run_mode(void) { return simulator_mode; } void set_debug_mode(struct NIOS_CPU * cpu) { simulator_mode = DEBUG_MODE; cpu->break_pc = 0; cpu->mode = NORMAL_MODE; } #define CMD_CHAR_SIZE (256) static char input_char[CMD_CHAR_SIZE] = {0}; enum { DISP_CURR = 0x01, DISP_NEXT, DUMP_REG, HELP, GO, DISP_PC, SET_BREAK, QUIT, DUMP_MEM, CALL_STACK, QUIT_SIM }; static const struct debug_command debug_cmds[] = { {"c", "disp_curr", "display the contents of current code", DISP_CURR}, {"n", "disp_next", "display the contents of next code", DISP_NEXT}, {"r", "dump_reg", "display the contents of register", DUMP_REG}, {"h", "help", "display the help information", HELP}, {"g", "go", "continue executing", GO}, {"p", "disp_pc", "display current PC Value", DISP_PC}, {NULL, "break", "set break address.For example:\n\t(1)break 08000010\n\t(2)break func=function name", SET_BREAK}, {"qd", "quit_debug","quit debug mode", QUIT}, {NULL, "dump", "dump memory",DUMP_MEM}, {"cs", "call_stack", "dump call stack", CALL_STACK}, {"qs", "quit_sim", "quit simulator", QUIT_SIM} }; #define CMD_COUNT (sizeof(debug_cmds) / sizeof(debug_cmds[0])) static void disp_help(void) { int32_t i; printf("\n[HELP INFORMATION]\n"); printf("==============================================\n"); for (i=0;imode == BREAK_MODE){ if (cpu->break_pc == cpu->pc){ cpu->break_pc = 0; cpu->mode = SINGLE_STEP; } else if (exec_this_func(break_func_name) == SIM_TRUE){ cpu->break_pc = 0; cpu->mode = SINGLE_STEP; } else { return; } } for (;;){ memset(input_char, 0x00, CMD_CHAR_SIZE); index = 0; printf("%s-(PC:%08X)#",DEBUG_PMT,cpu->pc); while(1){ input_key = getchar(); if (input_key != '\n' && index < CMD_CHAR_SIZE){ input_char[index++] = (char)input_key; } else { break; } } input_key = get_cmd_code(input_char); switch(input_key){ case DISP_CURR: dump_curr_code(code); break; case DISP_NEXT: dump_next_code(cpu); break; case DUMP_REG: dump_register(cpu); break; case HELP: disp_help(); break; case GO: return; case DISP_PC: dump_pc(cpu); break; case SET_BREAK: set_break(cpu, input_char); break; case DUMP_MEM: dump_mem(cpu, input_char); break; case QUIT: quit_debug_mode(cpu); return; case QUIT_SIM: quit_debug_mode(cpu); quit_simulator(); return; case CALL_STACK: dump_call_stack(); break; default: printf("INVALID COMMAND\n"); continue; } } } static void sigint_handler(int sig) { int32_t input = '\0'; struct NIOS_CPU * cpu = get_nios_cpu(); signal(sig, SIG_IGN); while(1){ printf("\nPlease select what you want?\n"); printf("Q for Quit Simulator\n"); printf("D for enter Debug Mode\n"); printf("R for Resume the simulating\n"); printf("N for do Nothing\n#"); input = getchar(); if ((char)input == '\n'){ goto handler_out; } switch((char)input){ case 'Q': quit_debug_mode(cpu); simulator_mode = EXIT_MODE; return; case 'D': set_debug_mode(cpu); goto handler_out; case 'R': quit_debug_mode(cpu); goto handler_out; case 'N': goto handler_out; default: continue; } } handler_out: signal(SIGINT, sigint_handler); } static void sigsegv_handler(int sig) { struct NIOS_CPU * cpu = get_nios_cpu(); signal(sig, SIG_IGN); printf("\n--------------Segmentation fault------------------\n"); dump_pc(cpu); dump_register(cpu); printf("----------------------------------------------------\n"); dump_call_stack(); _exit(0); } static void register_signal_handler(void) { signal(SIGINT, sigint_handler); signal(SIGSEGV, sigsegv_handler); } #define CS_LEN (32) struct call_stack { struct symbol_obj * stack[CS_LEN]; uint32_t pos; }; static struct call_stack cs = { .stack = {NULL}, .pos = 0, }; static int32_t exec_this_func(char * func_name) { struct symbol_obj * obj = NULL; if (cs.pos == 0){ obj = cs.stack[0]; } else{ obj = cs.stack[cs.pos-1]; } if (obj != NULL){ if (strcmp(obj->sym_name, func_name) == 0){ return SIM_TRUE; } } return SIM_FALSE; } static void dump_call_stack(void); static void record_call_stack(uint32_t addr) { struct symbol_obj * obj = NULL; obj = get_symbol(addr); if (obj != NULL){ if (cs.pos == 0){ cs.stack[cs.pos] = obj; cs.pos ++; } else { if (cs.stack[cs.pos-1] != obj){ cs.stack[cs.pos] = obj; cs.pos ++; if (cs.pos == CS_LEN){ cs.pos = 0; } } } } } static void dump_call_stack(void) { int32_t i = 0; struct symbol_obj * obj = NULL; printf("\n============================================================\n"); printf("[Function Call Trace]\n"); printf("============================================================\n"); for(i=0;isym_name, obj->addr); } else { printf("[%03d] %s (0x%08x)\n", i, obj->sym_name, obj->addr); } } } printf("============================================================\n"); } void simulating(void) { struct image_info * info = get_image_info(); struct NIOS_CPU * cpu = NULL; uint32_t code = 0; uint32_t exec_result = 0; /* register the segment fault and Ctrl-C handler */ register_signal_handler(); /* init cpu*/ reset_cpu(); cpu = get_nios_cpu(); set_init_pc(cpu, info->entry_addr); /* Set the init value of PC */ cpu = get_nios_cpu(); /* init device modules */ init_devices(); /* init the boot parameter setting for u-boot */ init_cmdline(cpu); init_initrd(cpu); /* main loop to simulating the execute of NIOSII */ printf("Enter simulating ..................\n"); while(1){ /* Get the instruction */ code = get_instruct(cpu, info->mem_base, info->base_addr); /* Judge whether into debug mode */ if (get_run_mode() == DEBUG_MODE){ if (cpu->mode == NORMAL_MODE){ cpu->mode = SINGLE_STEP; } trace_pc(cpu); debug_mode(cpu, code, exec_result); } else if(get_run_mode() == EXIT_MODE) { printf("NIOS SIMULATOR EXIT!\n"); return; } /* Execute the code */ exec_result = execute(code); if (exec_result == PC_INC_NORMAL){ modify_pc(cpu); } else { if(get_run_mode() == DEBUG_MODE){ record_call_stack(cpu->pc); } } /* Simulate the hardware running. */ hw_simulating(); /* judge whether IRQ or exception happen, if yes, then handle it.*/ handle_irq_exception(cpu); } } /*----------------------------------------------------------------------------*/