summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nios2.c121
-rw-r--r--nios2.h30
-rw-r--r--simulator.c108
3 files changed, 221 insertions, 38 deletions
diff --git a/nios2.c b/nios2.c
index 87eb3f3..86dee5e 100644
--- a/nios2.c
+++ b/nios2.c
@@ -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");
+ }
+
+}
diff --git a/nios2.h b/nios2.h
index eb13b95..aacf1b9 100644
--- a/nios2.h
+++ b/nios2.h
@@ -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