diff options
-rw-r--r-- | nios2.c | 121 | ||||
-rw-r--r-- | nios2.h | 30 | ||||
-rw-r--r-- | simulator.c | 108 |
3 files changed, 221 insertions, 38 deletions
@@ -16,10 +16,34 @@ void nios2_cpu_reset(struct nios2 *cpu) { - memset(cpu, 0x00, sizeof(struct nios2)); + /* Reset registers */ + memset(cpu->gp_regs, 0x00, NIOS2_GP_REG_COUNT * sizeof(uint32_t)); + memset(cpu->ctrl_regs, 0x00, NIOS2_CTRL_REG_COUNT * sizeof(uint32_t)); + + cpu->pc = 0; cpu->mode = NIOS2_SUPERVISOR_MODE; } +void nios2_cpu_init(struct nios2 *cpu) +{ + /* Set PC to entry address of program */ + cpu->pc = cpu->mem->image_base; +} + +void nios2_cpu_inc_pc(struct nios2 *cpu) +{ + cpu->pc += 4; +} + +void nios2_simulate(struct nios2 *cpu) +{ + /* Did anyone write to r0? */ + if (cpu->gp_regs[zero]) { + warn("Written to r0\n"); + cpu->gp_regs[zero] = 0; + } +} + bool nios2_in_user_mode(struct nios2 *cpu) { if (!cpu->has_mmu) @@ -35,21 +59,100 @@ bool nios2_in_supervisor_mode(struct nios2 *cpu) return !nios2_in_user_mode(cpu); } -uint32_t nios2_cpu_fetch_instr(struct nios2 *cpu, uint32_t *mem_base) +void nios2_exception(struct nios2 *cpu, uint8_t cause) { - uint32_t instr = 0; + cpu->ctrl_regs[exception] = (cause << 2) & 0x7C; +} - return instr; +uint32_t nios2_fetch_instr(struct nios2 *cpu) +{ + struct memory *mem = cpu->mem; + + return mem->base[cpu->pc / 4]; } -int nios2_cpu_execute_instr(struct nios2 *cpu, uint32_t instr) +int nios2_execute_instr(struct nios2 *cpu, uint32_t instr) { instruction_handler handle_instr = instruction_get_handler(instr); - if (unlikely(handle_instr == NULL)) { - err("Invalid instruction %08x\n", instr); - return -1; - } + if (unlikely(handle_instr == NULL)) + return INSTR_ERR; return handle_instr(cpu, instr); } + +static const char *nios2_gp_registers[] = { + "zero", + "at", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "et", + "bt", + "gp", + "sp", + "fp", + "ea", + "ba", + "ra", +}; + +static const char *nios2_ctrl_registers[] = { + "status", + "estatus", + "bstatus", + "ienable", + "ipending", + "cpuid", + "reserved", + "exception", + "pteaddr", + "tlbacc", + "tlbmisc", + "reserved", + "badaddr", + "config", + "mpubase", + "mpuacc" +}; + +void nios2_dump_registers(struct nios2 *cpu) +{ + unsigned int i; + uint32_t *gp_regs = cpu->gp_regs; + uint32_t *ctrl_regs = cpu->ctrl_regs; + + info("General-purpose registers:\n"); + for (i = 0; i < NIOS2_GP_REG_COUNT; i++) { + info(" %8s 0x%08x", nios2_gp_registers[i], gp_regs[i]); + if ((i + 1) % 4 == 0) + info("\n"); + } + + info("Control registers:\n"); + for (i = 0; i < NIOS2_CTRL_REG_COUNT; i++) { + info(" %10s 0x%08x", nios2_ctrl_registers[i], ctrl_regs[i]); + if ((i + 1) % 4 == 0) + info("\n"); + } + +} @@ -13,6 +13,7 @@ #define _NIOS2_H_ #include "instruction.h" +#include "memory.h" #define NIOS2_GP_REG_COUNT 32 /* there are really 32, but 16-31 are reserved for future use */ @@ -34,6 +35,10 @@ struct nios2 { bool has_div; /* div, divu */ bool has_mmu; /* Memory Management Unit */ + + struct memory *mem; + /* Exception handler address */ + uint32_t exception_handler_addr; }; /* Aliases for general-purpose registers */ @@ -70,15 +75,36 @@ enum { mpuacc, }; +/* status register fields */ +#define NIOS2_STATUS_PIE 0 +#define NIOS2_STATUS_U 1 +#define NIOS2_STATUS_EH 2 + +/* exception causes */ +#define NIOS2_EX_RESET 0 +#define NIOS2_EX_PROC_ONLY_RESET 1 +#define NIOS2_EX_IRQ 2 +#define NIOS2_EX_UNIMPLEMENTED 4 +#define NIOS2_EX_DIV_ERR 8 +#define NIOS2_EX_SUPERVISOR_ONLY_I 9 +#define NIOS2_EX_SUPERVISOR_ONLY_D 11 +#define NIOS2_EX_FAST_TLB_MISS 12 + enum { NIOS2_SUPERVISOR_MODE, NIOS2_USER_MODE, }; extern void nios2_cpu_reset(struct nios2 *cpu); +extern void nios2_cpu_init(struct nios2 *cpu); +extern void nios2_simulate(struct nios2 *cpu); +extern void nios2_cpu_inc_pc(struct nios2 *cpu); extern bool nios2_in_user_mode(struct nios2 *cpu); extern bool nios2_in_supervisor_mode(struct nios2 *cpu); -extern uint32_t nios2_cpu_fetch_instr(struct nios2 *cpu, uint32_t *mem_base); -extern int nios2_cpu_execute_instr(struct nios2 *cpu, uint32_t instr); +extern void nios2_exception(struct nios2 *cpu, uint8_t cause); +extern uint32_t nios2_fetch_instr(struct nios2 *cpu); +extern int nios2_execute_instr(struct nios2 *cpu, uint32_t instr); + +extern void nios2_dump_registers(struct nios2 *cpu); #endif /* _NIOS2_H_ */ diff --git a/simulator.c b/simulator.c index fb41893..1507f22 100644 --- a/simulator.c +++ b/simulator.c @@ -1,39 +1,95 @@ /* - 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. -*/ + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2010 chysun2000@gmail.com + * + * This file is part of nios2sim-ng. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ #include <stdio.h> -#include <string.h> +#include <stdlib.h> #include <signal.h> #include <unistd.h> -#include "public.h" -#include "niosii.h" -#include "io_device.h" +#include "nios2sim-ng.h" +#include "nios2.h" +#include "memory.h" +#include "device.h" #include "simulator.h" -static int32_t simulator_mode = SIM_MODE; +static bool simulator_running; +static struct nios2 *this_cpu = NULL; -static void modify_pc(struct NIOS_CPU * cpu) +static void sigint_handler(int sig __unused) { - cpu->pc += 4; + info("SIGINT caught\n"); + simulator_running = false; +} + +static void sigsegv_handler(int sig __unused) +{ + info("SIGSEGV caught\n"); + /* TODO: Dump registers, memory etc */ + if (this_cpu != NULL) + nios2_dump_registers(this_cpu); + _exit(EXIT_FAILURE); +} + +void simulator_run(struct nios2 *cpu) +{ + uint32_t instr = 0; + int ret; + + this_cpu = cpu; + + /* Register signal handlers */ + signal(SIGINT, sigint_handler); + signal(SIGSEGV, sigsegv_handler); + + nios2_cpu_reset(cpu); + nios2_cpu_init(cpu); + + vinfo("Starting nios2sim-ng simulator...\n"); + + dbg("Dumping first 32 words of memory:\n"); + memory_dump(cpu->mem, cpu->pc, 32); + + simulator_running = true; + while (simulator_running) { + instr = nios2_fetch_instr(cpu); + + ret = nios2_execute_instr(cpu, instr); + + if (ret == PC_INC_NORMAL) + nios2_cpu_inc_pc(cpu); + else if (ret == PC_INC_BY_INSTR) + ; + else if (IS_EXCEPTION(ret)) { + dbg("Exception\n"); + nios2_exception(cpu, EXCEPTION_CAUSE(ret)); + } else if (ret == INSTR_UNIMPL) { + simulator_running = false; + break; + } else { + err("Invalid instruction 0x%08x at PC 0x%08x\n", instr, cpu->pc); + nios2_dump_registers(cpu); + simulator_running = false; + break; + } + + nios2_simulate(cpu); + device_simulate_all(); + } + + vinfo("Exiting nios2sim-ng simulator...\n"); } +#if 0 +static int32_t simulator_mode = SIM_MODE; + static void set_init_pc(struct NIOS_CPU * cpu, uint32_t pc) { cpu->pc = pc; @@ -415,6 +471,4 @@ void simulator_run(void) } } -/*----------------------------------------------------------------------------*/ - - +#endif |