diff options
-rw-r--r-- | device.h | 4 | ||||
-rw-r--r-- | instruction.c | 59 | ||||
-rw-r--r-- | memory.c | 20 | ||||
-rw-r--r-- | memory.h | 5 | ||||
-rw-r--r-- | nios2.c | 94 | ||||
-rw-r--r-- | nios2.h | 4 |
6 files changed, 173 insertions, 13 deletions
@@ -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), @@ -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) @@ -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); @@ -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"); } @@ -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_ */ |