/* 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 "public.h" #include "niosii.h" #include "io_device.h" #include "instruction.h" static struct NIOS_CPU cpu; static struct image_info * img_info = NULL; void reset_cpu(void) { img_info = get_image_info(); memset(&cpu, 0x00, sizeof(struct NIOS_CPU)); /* set the default to control register */ cpu.ctrl_regs[status] = 0x00800000; cpu.gp_regs[4] = 0x00; cpu.gp_regs[7] = 0x00; cpu.trace_index = 0; } static uint32_t get_opcode(uint32_t intr) { struct i_type_code * code = (struct i_type_code*)&intr; return code->op; } static uint32_t get_opxcode(uint32_t intr) { struct r_type_code * code = (struct r_type_code *)&intr; return code->opx; } struct NIOS_CPU * get_nios_cpu(void) { return &cpu; } static uint32_t handle_r_type_code(uint32_t opxcode, uint32_t code) { return (r_type_handlers[opxcode]).handler(&cpu, code); } static uint32_t handle_i_type_code(uint32_t opcode, uint32_t code) { return i_type_handlers[opcode].handler(&cpu, code); } static uint32_t handle_j_type_code(uint32_t opcode, uint32_t code) { return j_type_handlers[opcode].handler(&cpu, code); } uint32_t get_offset_pc(uint32_t pc, uint32_t base_addr) { return (pc - base_addr) / 4; } uint32_t get_instruct(struct NIOS_CPU * cpu, uint32_t * mem_base, uint32_t base_addr) { uint32_t code = 0; uint32_t offset = get_offset_pc(cpu->pc, base_addr); code = mem_base[offset]; return code; } static int is_j_type(uint32_t opcode) { if (opcode == CALL || opcode == JMPI){ return SIM_TRUE; } else { return SIM_FALSE; } } uint32_t execute(uint32_t code) { uint32_t opcode = 0; uint32_t opxcode = 0; uint32_t pc_mod_type = 0; opcode = get_opcode(code); if (is_j_type(opcode) == SIM_TRUE){ pc_mod_type = handle_j_type_code(opcode, code); } else if (opcode != OP_R_TYPE){ pc_mod_type = handle_i_type_code(opcode, code); } else{ opxcode = get_opxcode(code); pc_mod_type = handle_r_type_code(opxcode, code); } return pc_mod_type; } int32_t get_addr_type(uint32_t addr) { if ((addr >= img_info->base_addr) && ((addr - img_info->base_addr) <= img_info->mem_size)){ return MEM_ADDR; } else{ return IO_ADDR; } } uint8_t get_byte(uint32_t addr) { if (get_addr_type(addr) == MEM_ADDR){ uint8_t * buf = (uint8_t *)img_info->mem_base; return buf[addr - img_info->base_addr]; } else{ struct io_device * dev = get_device(addr); if (dev != NULL){ return dev->read_data(dev, addr, 1); } else { printf("%s->error at %x\n",__func__,addr); return 0; } } } void store_byte(uint32_t addr, unsigned char data) { if(get_addr_type(addr) == MEM_ADDR){ uint8_t * buf = (uint8_t *)img_info->mem_base; buf[addr - img_info->base_addr] = data; } else { struct io_device * dev = get_device(addr); if (dev != NULL){ dev->write_data(dev, addr, data, 1); } else { printf("%s->unhandled data:%x at %x\n",__func__,data,addr); } } } uint16_t get_half_word(uint32_t addr) { if (get_addr_type(addr) == MEM_ADDR){ uint16_t * buf = (uint16_t *)img_info->mem_base; return buf[(addr - img_info->base_addr)/2]; } else { struct io_device * dev = get_device(addr); if (dev != NULL){ return dev->read_data(dev, addr, 2); } else { printf("%s->error at %x\n",__func__,addr); return 0; } } } void store_half_word(uint32_t addr, unsigned short data) { if (get_addr_type(addr) == MEM_ADDR){ uint16_t * buf = (uint16_t *)img_info->mem_base; buf[(addr - img_info->base_addr) / 2] = data; } else { struct io_device * dev = get_device(addr); if (dev != NULL){ dev->write_data(dev, addr, data, 2); } else { printf("%s->unhandled data:%x at %x\n",__func__,data,addr); } } } uint32_t get_word(uint32_t addr) { if (get_addr_type(addr) == MEM_ADDR){ uint32_t * buf = (uint32_t * )img_info->mem_base; return buf[(addr - img_info->base_addr) / 4]; } else { struct io_device * dev = get_device(addr); if (dev != NULL){ return dev->read_data(dev, addr, 4); } else { printf("%s->error at %x\n",__func__,addr); return 0; } } } void store_word(uint32_t addr, uint32_t data) { if (get_addr_type(addr) == MEM_ADDR){ uint32_t * buf = (uint32_t *)img_info->mem_base; buf[(addr - img_info->base_addr) / 4] = data; } else { struct io_device * dev = get_device(addr); if (dev != NULL){ dev->write_data(dev, addr, data, 4); } else { printf("%s->unhandled data:%x at %x\n",__func__,data,addr); } } } static uint32_t has_irq(struct NIOS_CPU * cpu) { uint32_t ret_val = CPU_HAS_NO_EVENT; uint32_t irq_mask = 0; uint32_t temp = 0; /* 1. judge the device has irq */ irq_mask = get_io_irq_status(); if (irq_mask != 0){ if ((cpu->ctrl_regs[status] & REG_STATUS_PIE) == REG_STATUS_PIE){ temp = cpu->ctrl_regs[ienable] & irq_mask; #if 1 if (temp != 0 && (temp != cpu->ctrl_regs[ipending])){ #else if (temp != 0){ #endif /* 2. modify the control register */ cpu->ctrl_regs[ipending] |= temp; ret_val = CPU_HAS_IRQ; } } } return ret_val; } static uint32_t has_exception(struct NIOS_CPU * cpu) { uint32_t ret_val = CPU_HAS_NO_EVENT; return ret_val; } static uint32_t get_cpu_status(struct NIOS_CPU * cpu) { uint32_t ret_val = CPU_HAS_NO_EVENT; ret_val |= has_irq(cpu); ret_val |= has_exception(cpu); return ret_val; } static void handle_irq(struct NIOS_CPU * cpu) { uint32_t reg_status_val = 0; uint32_t temp_pc = 0; /* according to the kind of interrupt or exception, * set PC to the address of IRQ or exception vector. */ temp_pc = cpu->pc; cpu->pc = EXCEPTION_HANDLER_ADDR; reg_status_val = cpu->ctrl_regs[status]; cpu->ctrl_regs[status] &= 0xFFFFFFFE; /* clear PIE */ if((reg_status_val & REG_STATUS_EH) == 0){ cpu->ctrl_regs[estatus] = reg_status_val; cpu->gp_regs[ea] = temp_pc + 4; } } static void handle_exception(struct NIOS_CPU * cpu) { } void handle_irq_exception(struct NIOS_CPU * cpu) { uint32_t cpu_status = CPU_HAS_NO_EVENT; cpu_status = get_cpu_status(cpu); if(cpu_status & CPU_HAS_IRQ){ handle_irq(cpu); } else if (cpu_status & CPU_HAS_EXCEPTION){ handle_exception(cpu); } } static void dump_j_code(uint32_t code) { def_j_type_code; printf("TYPE: J Code [%08X]\n", code); printf("OP: 0x%02X\n",instr->op); printf("IMM26: 0x%X\n",instr->imm26); } static void dump_r_code(uint32_t code) { def_r_type_code; printf("TYPE: R Code [%08X]\n", code); printf("OP: 0x%02X\n", instr->op); printf("A=0x%X B=0x%X C=0x%X OPX=0x%X N=0x%X\n", instr->a, instr->b, instr->c, instr->opx, instr->n); } static void dump_i_code(uint32_t code) { def_i_type_code; printf("TYPE: I Code [%08X]\n", code); printf("OP: 0x%02X\n", instr->op); printf("A=0x%X B=0x%X IMM16=0x%04X\n", instr->a, instr->b, instr->imm16); } static void dump_code(uint32_t code) { uint32_t code_type = get_opcode(code); printf("\n"); printf("--------------Code Dump--------------\n"); switch(code_type){ case OP_J_TYPE: dump_j_code(code); break; case OP_R_TYPE: dump_r_code(code); break; default: dump_i_code(code); break; } printf("-------------------------------------\n"); } void dump_curr_code(uint32_t code) { dump_code(code); } void dump_next_code(struct NIOS_CPU * cpu) { uint32_t code = get_instruct(cpu,img_info->mem_base, img_info->base_addr); dump_code(code); } void dump_pc(struct NIOS_CPU * cpu) { int32_t i = 0; printf("============================================================\n"); printf("ERROR PC=%08X\n",cpu->pc); printf("PC Trace Index :%d\n", cpu->trace_index); printf("============================================================\n"); for (i=0;itrace_index - 1)){ printf("(%08X) ",cpu->pc_trace[i]); } else { printf("%08X ",cpu->pc_trace[i]); } if (((i+1)% 8) == 0){ printf("\n"); } } printf("\n============================================================\n"); } static const char * g_regs_name[] = { " ZERO", " AT", "REG02", "REG03", "REG04", "REG05", "REG06", "REG07", "REG08", "REG09", "REG10", "REG11", "REG12", "REG13", "REG14", "REG15", "REG16", "REG17", "REG18", "REG19", "REG20", "REG21", "REG22", "REG23", " ET", " BT", " GP", " SP", " FP", " EA", " BA", " RA" }; static const char * c_regs_name[] = { "SSTAT", "ESTAT", "BSTAT", "IENAB", "IPEND", "CPUID", "RESER", "EXCEP", "PTEAD", "TLBAD", "TLBMI", "RESER", "BADAD", "CONFI", "MPUBA", "MPUAD" }; void dump_register(struct NIOS_CPU * cpu) { int32_t i = 0; printf("\n"); printf("============================================================\n"); printf("[Genernal Register]\n"); printf("============================================================\n"); for (i=0;igp_regs[i]); if (((i+1) % 4) == 0) printf("\n"); } printf("============================================================\n"); printf("[Control Register]\n"); printf("============================================================\n"); for (i=0;i<16;i++){ printf("%s=%08X ",c_regs_name[i],cpu->ctrl_regs[i]); if (((i+1) % 4) == 0) printf("\n"); } printf("============================================================\n"); } /** * Parse the options of break command */ #define SPACE_CHAR (' ') #define BREAK_CMD_LEN (16) extern char break_func_name[256]; static uint32_t get_break_pc(char * input) { uint32_t ret_pc = 0x0; uint32_t input_len = 0; input_len = strlen(input); /* * TODO: the judgement of option's format is not full implemented. */ if (input_len == BREAK_CMD_LEN){ sscanf(input, "break 0x%08x\n", &ret_pc); } if (strstr(input, "func") != NULL){ memset(break_func_name, 0x00, 256); sscanf(input, "break func=%s", break_func_name); return 0xFFFFFFFF; } return ret_pc; } void set_break(struct NIOS_CPU * cpu, char * input) { uint32_t break_pc = 0x0; break_pc = get_break_pc(input); if (break_pc != 0x0){ if (break_pc == 0xFFFFFFFF){ cpu->mode = BREAK_MODE; } else { cpu->mode = BREAK_MODE; cpu->break_pc = break_pc; } } else{ printf("Error Address\n"); cpu->mode = SINGLE_STEP; } } static void output_char(char c) { if (c == '\r' || c == '\n'){ printf("."); } else { printf("%c",c); } } static void output_ascii(uint32_t * buf) { uint32_t val = 0; char temp = 0; uint32_t i = 0; printf("\t"); for (i = 0; i < 4; i++){ val = buf[i]; temp = val & 0xFF; output_char(temp); temp = (val >> 8) & 0xFF; output_char(temp); temp = (val >> 16) & 0xFF; output_char(temp); temp = (val >> 24) & 0xFF; output_char(temp); } } /* * dump the content of memory */ void dump_mem(struct NIOS_CPU * cpu, char * input) { uint32_t addr, size; struct image_info * info = get_image_info(); int32_t i = 0; uint32_t * buf = NULL; uint32_t temp_buf[4] = {0}; uint32_t index = 0; sscanf(input, "dump 0x%X %d", &addr, &size); addr = addr & (~0x3); size = size / 4 * 4; if (addr >= info->base_addr && size < info->mem_size){ buf = info->mem_base + (addr - info->base_addr) / 4 ; printf("================================================\n"); printf("[Memory Dump start:0x%08X size:%d]\n", addr, size); printf("================================================\n"); for (i=0;ipc_trace[cpu->trace_index] = cpu->pc; cpu->trace_index ++; if (cpu->trace_index >= PC_TRACE_CNT){ cpu->trace_index = 0; } } /*----------------------------------------------------------------------------*/