summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--device.h4
-rw-r--r--instruction.c59
-rw-r--r--memory.c20
-rw-r--r--memory.h5
-rw-r--r--nios2.c94
-rw-r--r--nios2.h4
6 files changed, 173 insertions, 13 deletions
diff --git a/device.h b/device.h
index cf84e05..da65a37 100644
--- a/device.h
+++ b/device.h
@@ -29,8 +29,8 @@ struct device {
int (*init)(struct device *dev);
bool (*is_dev_addr)(struct device *dev, uint32_t addr);
- size_t (*read)(struct device *dev, uint32_t addr, uint32_t *data, size_t count);
- size_t (*write)(struct device *dev, uint32_t addr, uint32_t *data, size_t count);
+ size_t (*read)(struct device *dev, uint32_t addr, uint8_t *data, size_t count);
+ size_t (*write)(struct device *dev, uint32_t addr, uint8_t *data, size_t count);
bool (*has_irq)(struct device *dev);
void (*simulate)(struct device *dev);
diff --git a/instruction.c b/instruction.c
index 133470d..0ab99c8 100644
--- a/instruction.c
+++ b/instruction.c
@@ -84,11 +84,16 @@ static int ldbu(struct nios2 *cpu, uint32_t code)
{
I_TYPE(instr, code);
uint32_t *gp_regs = cpu->gp_regs;
- int32_t addr = gp_regs[instr->a] + (int16_t) instr->imm16;
+ uint32_t addr = gp_regs[instr->a] + (int16_t) instr->imm16;
+ uint8_t byte;
- gp_regs[instr->b] = memory_get_byte(cpu->mem, addr);
+ if (nios2_load_byte(cpu, addr, &byte))
+ return INSTR_ERR;
+
+ gp_regs[instr->b] = (uint32_t) byte;
return PC_INC_NORMAL;
+
}
/* rB <- rA + IMM16 */
@@ -102,12 +107,41 @@ static int addi(struct nios2 *cpu, uint32_t code)
return PC_INC_NORMAL;
}
+/* Mem8[rA + @(IMM16)] <- rB(7..0) */
+static int stb(struct nios2 *cpu, uint32_t code)
+{
+ I_TYPE(instr, code);
+ uint32_t *gp_regs = cpu->gp_regs;
+ uint32_t addr = gp_regs[instr->a] + (int16_t) instr->imm16;
+
+ if (nios2_store_byte(cpu, addr, gp_regs[instr->b] & 0xFF))
+ return INSTR_ERR;
+
+ return PC_INC_NORMAL;
+}
+
/* PC <- PC + 4 + IMM16 */
static int br(struct nios2 *cpu, uint32_t code)
{
I_TYPE(instr, code);
- cpu->pc += 4 + (instr->imm16 & 0xFFFC);
+ cpu->pc += 4 + (int16_t)(instr->imm16 & 0xFFFC);
+
+ return PC_INC_NORMAL;
+}
+
+/* rB <- @(Mem8[rA + @(IMM16)]) */
+static int ldb(struct nios2 *cpu, uint32_t code)
+{
+ I_TYPE(instr, code);
+ uint32_t *gp_regs = cpu->gp_regs;
+ uint32_t addr = gp_regs[instr->a] + (int16_t) instr->imm16;
+ uint8_t byte;
+
+ if (nios2_load_byte(cpu, addr, &byte))
+ return INSTR_ERR;
+
+ gp_regs[instr->b] = (int32_t) byte;
return PC_INC_NORMAL;
}
@@ -227,6 +261,19 @@ static int blt(struct nios2 *cpu, uint32_t code)
return PC_INC_BY_INSTR;
}
+/* rB <- @(Mem32[rA + @(IMM16)]) */
+static int ldw(struct nios2 *cpu, uint32_t code)
+{
+ I_TYPE(instr, code);
+ uint32_t *gp_regs = cpu->gp_regs;
+ uint32_t addr = gp_regs[instr->a] + (int16_t) instr->imm16;
+
+ if (nios2_load_word(cpu, addr, &gp_regs[instr->b]))
+ return INSTR_ERR;
+
+ return PC_INC_NORMAL;
+}
+
/* rB <- rA ^ IMM16 */
static int xori(struct nios2 *cpu, uint32_t code)
{
@@ -359,9 +406,9 @@ static struct instruction i_type_instructions[I_TYPE_COUNT] = {
[JMPI] = INSTRUCTION(jmpi),
[LDBU] = INSTRUCTION(ldbu),
[ADDI] = INSTRUCTION(addi),
- [STB] = INSTRUCTION_UNIMPLEMENTED(stb),
+ [STB] = INSTRUCTION(stb),
[BR] = INSTRUCTION(br),
- [LDB] = INSTRUCTION_UNIMPLEMENTED(ldb),
+ [LDB] = INSTRUCTION(ldb),
[CMPGEI] = INSTRUCTION_UNIMPLEMENTED(cmpgei),
[LDHU] = INSTRUCTION(ldhu),
[ANDI] = INSTRUCTION(andi),
@@ -373,7 +420,7 @@ static struct instruction i_type_instructions[I_TYPE_COUNT] = {
[ORI] = INSTRUCTION(ori),
[STW] = INSTRUCTION(stw),
[BLT] = INSTRUCTION(blt),
- [LDW] = INSTRUCTION_UNIMPLEMENTED(ldw),
+ [LDW] = INSTRUCTION(ldw),
[CMPNEI] = INSTRUCTION_UNIMPLEMENTED(cmpnei),
[FLUSHDA] = INSTRUCTION_NOP(flushda),
[XORI] = INSTRUCTION(xori),
diff --git a/memory.c b/memory.c
index 75b041f..553766a 100644
--- a/memory.c
+++ b/memory.c
@@ -15,10 +15,26 @@
#include "nios2.h"
#include "memory.h"
-uint8_t memory_get_byte(struct memory *mem, int32_t offset)
+uint8_t memory_get_byte(struct memory *mem, int32_t addr)
{
uint8_t *base = (uint8_t *) mem->base;
- return base[offset];
+ return base[addr - mem->image_base];
+}
+
+void memory_set_byte(struct memory *mem, int32_t addr, uint8_t data)
+{
+ uint8_t *base = (uint8_t *) mem->base;
+ base[addr - mem->image_base] = data;
+}
+
+uint32_t memory_get_word(struct memory *mem, int32_t addr)
+{
+ return mem->base[(addr - mem->image_base) / 4];
+}
+
+void memory_set_word(struct memory *mem, int32_t addr, uint32_t data)
+{
+ mem->base[(addr - mem->image_base) / 4] = data;
}
void memory_dump(struct memory *mem, uint32_t offset, size_t count)
diff --git a/memory.h b/memory.h
index e5bd073..80de90b 100644
--- a/memory.h
+++ b/memory.h
@@ -20,7 +20,10 @@ struct memory {
#define IMAGE_BASE_UNINITIALIZED UINT32_MAX
-extern uint8_t memory_get_byte(struct memory *mem, int32_t offset);
+extern uint8_t memory_get_byte(struct memory *mem, int32_t addr);
+extern void memory_set_byte(struct memory *mem, int32_t addr, uint8_t data);
+extern uint32_t memory_get_word(struct memory *mem, int32_t addr);
+extern void memory_set_word(struct memory *mem, int32_t addr, uint32_t data);
extern void memory_dump(struct memory *mem, uint32_t offset, size_t count);
diff --git a/nios2.c b/nios2.c
index 86dee5e..a8ff9c4 100644
--- a/nios2.c
+++ b/nios2.c
@@ -13,6 +13,8 @@
#include "nios2sim-ng.h"
#include "nios2.h"
+#include "memory.h"
+#include "device.h"
void nios2_cpu_reset(struct nios2 *cpu)
{
@@ -81,6 +83,94 @@ int nios2_execute_instr(struct nios2 *cpu, uint32_t instr)
return handle_instr(cpu, instr);
}
+static bool is_mem_addr(struct memory *mem, uint32_t addr)
+{
+ if (addr >= mem->image_base && addr < (mem->image_base + mem->size))
+ return true;
+ else
+ return false;
+}
+
+int nios2_load_byte(struct nios2 *cpu, uint32_t addr, uint8_t *data)
+{
+ struct memory *mem = cpu->mem;
+
+ dbg("ldb %08x\n", addr);
+
+ if (is_mem_addr(mem, addr)) {
+ dbg("load byte MEM\n");
+ *data = memory_get_byte(mem, addr);
+ } else { /* must be I/O */
+ struct device *dev = device_get_by_addr(addr);
+ dbg("load byte I/O\n");
+
+ if (unlikely(dev == NULL)) {
+ err("Reading data outside of device range (0x%08x)\n", addr);
+ return -1;
+ }
+
+ if (dev->read(dev, addr, data, 1) != 1) {
+ err("Read from device '%s' failed\n", dev->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int nios2_store_byte(struct nios2 *cpu, uint32_t addr, uint8_t data)
+{
+ struct memory *mem = cpu->mem;
+
+ dbg("stb %02x @ %08x\n", data, addr);
+
+ if (is_mem_addr(mem, addr)) {
+ dbg("store byte MEM\n");
+ memory_set_byte(mem, addr, data);
+ } else { /* must be I/O */
+ struct device *dev = device_get_by_addr(addr);
+ dbg("store byte I/O\n");
+ if (unlikely(dev == NULL)) {
+ err("Writing data outside of device range (0x%08x)\n", addr);
+ return -1;
+ }
+
+ if (dev->write(dev, addr, &data, 1) != 1) {
+ err("Write to device '%s' failed\n", dev->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int nios2_load_word(struct nios2 *cpu, uint32_t addr, uint32_t *data)
+{
+ struct memory *mem = cpu->mem;
+
+ dbg("ldw %08x\n", addr);
+
+ if (is_mem_addr(mem, addr)) {
+ dbg("load word MEM\n");
+ *data = memory_get_word(mem, addr);
+ } else { /* must be I/O */
+ struct device *dev = device_get_by_addr(addr);
+ dbg("load byte I/O\n");
+
+ if (unlikely(dev == NULL)) {
+ err("Reading data outside of device range (0x%08x)\n", addr);
+ return -1;
+ }
+
+ if (dev->read(dev, addr, (uint8_t *) data, 4) != 1) {
+ err("Read from device '%s' failed\n", dev->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static const char *nios2_gp_registers[] = {
"zero",
"at",
@@ -143,14 +233,14 @@ void nios2_dump_registers(struct nios2 *cpu)
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]);
+ info(" %10s 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]);
+ 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 aacf1b9..b4ab4ff 100644
--- a/nios2.h
+++ b/nios2.h
@@ -105,6 +105,10 @@ 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 int nios2_load_byte(struct nios2 *cpu, uint32_t addr, uint8_t *data);
+extern int nios2_store_byte(struct nios2 *cpu, uint32_t addr, uint8_t data);
+extern int nios2_load_word(struct nios2 *cpu, uint32_t addr, uint32_t *data);
+
extern void nios2_dump_registers(struct nios2 *cpu);
#endif /* _NIOS2_H_ */