summaryrefslogtreecommitdiff
path: root/niosii.c
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2010-11-10 09:20:50 +0100
committerTobias Klauser <tklauser@distanz.ch>2010-11-10 09:20:50 +0100
commit32f507ce5f66dd9c89a45854688f46bde33c5e3d (patch)
tree9626fc49bcf9c3f8e7fbf228395efe72688989bf /niosii.c
Initial import of nios2sim (http://nios2sim.googlecode.com/svn/trunk/ r16)
Diffstat (limited to 'niosii.c')
-rw-r--r--niosii.c603
1 files changed, 603 insertions, 0 deletions
diff --git a/niosii.c b/niosii.c
new file mode 100644
index 0000000..4db4ce2
--- /dev/null
+++ b/niosii.c
@@ -0,0 +1,603 @@
+/*
+ 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 <ctype.h>
+
+#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;i<PC_TRACE_CNT;i++){
+ if (i == (cpu->trace_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;i<NIOS_REG_CNT;i++){
+ printf("%s=%08X ",g_regs_name[i],cpu->gp_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;i<size/4;i++){
+ temp_buf[index] = buf[i];
+ index = index + 1;
+ if (i % 4 == 0){
+ printf("[%08X]",addr + i * 4);
+ }
+ printf("%08X ", (uint32_t)buf[i]);
+
+ if (((i+1) % 4) == 0){
+ output_ascii(temp_buf);
+ index = 0;
+ printf("\n");
+ }
+ else if (i == (size/4 - 1)){
+ printf("\n");
+ }
+ }
+ printf("================================================\n");
+ }
+}
+
+void clean_ipending(uint32_t mask)
+{
+ cpu.ctrl_regs[ipending] &= (~mask);
+}
+
+/* Record the pc trace. It is used when segment fault happening. */
+void trace_pc(struct NIOS_CPU * cpu)
+{
+ cpu->pc_trace[cpu->trace_index] = cpu->pc;
+ cpu->trace_index ++;
+ if (cpu->trace_index >= PC_TRACE_CNT){
+ cpu->trace_index = 0;
+ }
+}
+/*----------------------------------------------------------------------------*/
+