summaryrefslogtreecommitdiff
path: root/simulator.c
diff options
context:
space:
mode:
Diffstat (limited to 'simulator.c')
-rw-r--r--simulator.c420
1 files changed, 420 insertions, 0 deletions
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 <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#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;i<CMD_COUNT;i++){
+ printf("[%d] \"%s\" or \"%s\"\n %s\n",
+ debug_cmds[i].code,
+ debug_cmds[i].short_cmd,
+ debug_cmds[i].long_cmd,
+ debug_cmds[i].desc);
+ }
+ printf("==============================================\n");
+}
+
+static int32_t get_cmd_code(char * input_char)
+{
+ int32_t ret_val = 0;
+ int32_t i = 0;
+
+ if (strlen(input_char) == 0){
+ return GO;
+ }
+
+ for(i=0;i<CMD_COUNT;i++){
+ if (debug_cmds[i].short_cmd != NULL
+ && strcmp(input_char, debug_cmds[i].short_cmd) == 0){
+ ret_val = debug_cmds[i].code;
+ break;
+ }
+
+ if (debug_cmds[i].long_cmd != NULL
+ && strcmp(input_char, debug_cmds[i].long_cmd) == 0){
+ ret_val = debug_cmds[i].code;
+ break;
+ }
+
+ if (debug_cmds[i].short_cmd == NULL && debug_cmds[i].long_cmd != NULL
+ && strstr(input_char, debug_cmds[i].long_cmd) != NULL){
+ ret_val = debug_cmds[i].code;
+ break;
+ }
+ }
+ return ret_val;
+}
+
+static void quit_simulator(void)
+{
+ simulator_mode = EXIT_MODE;
+}
+
+static void dump_call_stack(void);
+static const char *DEBUG_PMT = "(dbg)";
+char break_func_name[256] = {0};
+static int32_t exec_this_func(char * func_name);
+static void debug_mode(struct NIOS_CPU * cpu, uint32_t code, uint32_t exec_ret)
+{
+ int32_t input_key = 0;
+ int32_t index = 0;
+
+ if (cpu->mode == 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;i<CS_LEN;i++){
+ if(cs.stack[i] != NULL){
+ obj = cs.stack[i];
+ if (cs.pos == (i + 1)){
+ printf("[%03d] %s (0x%08x)**\n", i, obj->sym_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);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+