From 32f507ce5f66dd9c89a45854688f46bde33c5e3d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 10 Nov 2010 09:20:50 +0100 Subject: Initial import of nios2sim (http://nios2sim.googlecode.com/svn/trunk/ r16) --- simulator.c | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 simulator.c (limited to 'simulator.c') diff --git a/simulator.c b/simulator.c new file mode 100644 index 0000000..e4880e9 --- /dev/null +++ b/simulator.c @@ -0,0 +1,420 @@ +/* + 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); + } +} + +/*----------------------------------------------------------------------------*/ + + -- cgit v1.2.3-54-g00ecf