diff options
author | Tobias Klauser <tklauser@distanz.ch> | 2010-11-10 09:20:50 +0100 |
---|---|---|
committer | Tobias Klauser <tklauser@distanz.ch> | 2010-11-10 09:20:50 +0100 |
commit | 32f507ce5f66dd9c89a45854688f46bde33c5e3d (patch) | |
tree | 9626fc49bcf9c3f8e7fbf228395efe72688989bf |
Initial import of nios2sim (http://nios2sim.googlecode.com/svn/trunk/ r16)
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | custom_instr.c | 34 | ||||
-rw-r--r-- | i_type_handler.c | 496 | ||||
-rw-r--r-- | instruction.h | 120 | ||||
-rw-r--r-- | io_device.c | 155 | ||||
-rw-r--r-- | io_device.h | 65 | ||||
-rw-r--r-- | j_type_handler.c | 46 | ||||
-rw-r--r-- | jtag_uart.c | 169 | ||||
-rw-r--r-- | jtag_uart.h | 56 | ||||
-rw-r--r-- | load_image.c | 620 | ||||
-rw-r--r-- | main.c | 123 | ||||
-rwxr-xr-x | nios-sim | bin | 0 -> 124940 bytes | |||
-rw-r--r-- | niosii.c | 603 | ||||
-rw-r--r-- | niosii.h | 182 | ||||
-rw-r--r-- | nor_flash.c | 108 | ||||
-rw-r--r-- | nor_flash.h | 57 | ||||
-rw-r--r-- | public.h | 85 | ||||
-rw-r--r-- | r_type_handler.c | 458 | ||||
-rw-r--r-- | simulator.c | 420 | ||||
-rw-r--r-- | simulator.h | 32 | ||||
-rw-r--r-- | timer.c | 215 | ||||
-rw-r--r-- | timer.h | 55 | ||||
-rw-r--r-- | uart_core.c | 157 | ||||
-rw-r--r-- | uart_core.h | 79 |
24 files changed, 4360 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a2f4ad9 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +# +# Make file for compiling simulator for NIOSII +# + +TARGET=nios-sim + +SRC=main.c load_image.c simulator.c niosii.c i_type_handler.c j_type_handler.c \ + r_type_handler.c custom_instr.c io_device.c jtag_uart.c timer.c uart_core.c \ + nor_flash.c + +CFLAGS= -g -Wall + +all: + gcc -o ${TARGET} ${CFLAGS} ${SRC} + +.phony: + clean distclean + +clean: + @rm -rf ${TARGET} *.o + +distclean: clean + @rm -rf *~ + @rm -rf #* + @rm -rf tags
\ No newline at end of file diff --git a/custom_instr.c b/custom_instr.c new file mode 100644 index 0000000..c9e5abf --- /dev/null +++ b/custom_instr.c @@ -0,0 +1,34 @@ +/* + 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 <stdlib.h> +#include <string.h> +#include "public.h" +#include "niosii.h" +#include "instruction.h" + +uint32_t custom_instr(struct NIOS_CPU * cpu, uint32_t code) +{ + printf("%s\n",__func__); + return PC_INC_NORMAL; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/i_type_handler.c b/i_type_handler.c new file mode 100644 index 0000000..be1ff76 --- /dev/null +++ b/i_type_handler.c @@ -0,0 +1,496 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "instruction.h" + + +static uint32_t ldbu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int32_t addr = 0; + + addr = cpu->gp_regs[instr->a] + (int16_t)(instr->imm16); + cpu->gp_regs[instr->b] = get_byte(addr) & 0x000000FF; + + return PC_INC_NORMAL; +} + +static uint32_t addi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] + (int16_t)(instr->imm16); + return PC_INC_NORMAL; +} + +static uint32_t stb(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t addr = 0; + + addr = cpu->gp_regs[instr->a] + (int16_t)(instr->imm16); + store_byte(addr, (cpu->gp_regs[instr->b] & 0xFF)); + return PC_INC_NORMAL; +} + +static uint32_t br(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t imm16 = (int16_t)instr->imm16; + + cpu->pc = cpu->pc + 4 + (int16_t)(imm16 & 0xFFFC); + return PC_INC_BY_INSTR; +} + +static uint32_t ldb(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t addr = cpu->gp_regs[instr->a] + (int16_t)(instr->imm16); + + cpu->gp_regs[instr->b] = (int)((char)(get_byte(addr))); + return PC_INC_NORMAL; +} + +static uint32_t cmpgei(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if ((int32_t)(cpu->gp_regs[instr->a]) >= (int32_t)((int16_t)(instr->imm16))){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t cmplti(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if ((int32_t)(cpu->gp_regs[instr->a]) < (int32_t)((int16_t)(instr->imm16))){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + + return PC_INC_NORMAL; +} + +static uint32_t ldhu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t offset = (int16_t) instr->imm16; + int16_t value = 0; + + value = get_half_word((int16_t)offset + cpu->gp_regs[instr->a]); + cpu->gp_regs[instr->b] = ((uint32_t)value) & 0xFFFF; + return PC_INC_NORMAL; +} + +static uint32_t andi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t temp = instr->imm16; + + temp = temp & 0xFFFF; + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] & temp; + return PC_INC_NORMAL; +} + +static uint32_t sth(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t offset = (int16_t)instr->imm16; + uint32_t addr = 0; + + addr = cpu->gp_regs[instr->a] + (int16_t)offset; + store_half_word(addr, (uint16_t)(cpu->gp_regs[instr->b] & 0xFFFF)); + return PC_INC_NORMAL; +} + +static uint32_t bge(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + int32_t a = (int32_t)(cpu->gp_regs[instr->a]); + int32_t b = (int32_t)(cpu->gp_regs[instr->b]); + + if (a >= b){ + cpu->pc = cpu->pc + 4 + (int16_t)((int16_t)instr->imm16 & 0xFFFC); + } + else{ + cpu->pc = cpu->pc + 4; + } + + return PC_INC_BY_INSTR; +} + +static uint32_t ldh(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t value = 0; + + value = (int16_t)get_half_word(cpu->gp_regs[instr->a] + (int16_t)(instr->imm16)); + cpu->gp_regs[instr->b] = (int32_t)value; + return PC_INC_NORMAL; +} + +static uint32_t initda(struct NIOS_CPU * cpu, uint32_t code) +{ +#if 0 + def_i_type_code; +#endif + return PC_INC_NORMAL; +} + +static uint32_t ori(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int32_t temp = (int16_t)instr->imm16; + + temp = temp & 0xFFFF; + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] | temp; + return PC_INC_NORMAL; +} + +static uint32_t stw(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + int16_t offset = (int16_t)(instr->imm16); + + store_word(cpu->gp_regs[instr->a] + (int16_t)offset, cpu->gp_regs[instr->b]); + return PC_INC_NORMAL; +} + +static uint32_t blt(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int32_t a = (int32_t)(cpu->gp_regs[instr->a]); + int32_t b = (int32_t)(cpu->gp_regs[instr->b]); + int16_t imm16 = (int16_t)(instr->imm16); + + if (a < b){ + cpu->pc = cpu->pc + 4 + (int16_t)(imm16 & 0xFFFC); + } + else{ + cpu->pc = cpu->pc + 4; + } + return PC_INC_BY_INSTR; +} + +static uint32_t ldw(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t offset = (int16_t)(instr->imm16); + cpu->gp_regs[instr->b] = get_word(cpu->gp_regs[instr->a] + (int16_t)offset); + return PC_INC_NORMAL; +} + +static uint32_t cmpnei(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int16_t value = (int16_t)(instr->imm16); + + if (cpu->gp_regs[instr->a] != (int16_t)value){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t flushda(struct NIOS_CPU * cpu, uint32_t code) +{ +#if 0 + def_i_type_code; +#endif + return PC_INC_NORMAL; +} + +static uint32_t xori(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t value = 0; + + value = (uint16_t)instr->imm16; + value &= 0xFFFF; + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] ^ value; + return PC_INC_NORMAL; +} + +static uint32_t bne(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if (cpu->gp_regs[instr->a] != cpu->gp_regs[instr->b]){ + cpu->pc = cpu->pc + 4 + (int16_t)((int16_t)instr->imm16 & 0xFFFC); + } + else { + cpu->pc = cpu->pc + 4; + } + + return PC_INC_BY_INSTR; +} + +static uint32_t cmpeqi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if(cpu->gp_regs[instr->a] == (int32_t)(instr->imm16)){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t ldbuio(struct NIOS_CPU * cpu, uint32_t code) +{ + return ldbu(cpu, code); +} + +static uint32_t muli(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + unsigned long long data = 0; + uint32_t a = cpu->gp_regs[instr->a]; + int32_t b = (int32_t)((int16_t)instr->imm16); + + data = (a * b); + cpu->gp_regs[instr->b] = (uint32_t)(data & 0xFFFFFFFF); + return PC_INC_NORMAL; +} + +static uint32_t stbio(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t addr = cpu->gp_regs[instr->a] + (int16_t)(instr->imm16); + + store_byte(addr, (uint8_t)(cpu->gp_regs[instr->b] & 0xFF)); + return PC_INC_NORMAL; +} + +static uint32_t beq(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + int16_t temp = (int16_t)instr->imm16; + + if (cpu->gp_regs[instr->a] == cpu->gp_regs[instr->b]){ + cpu->pc = cpu->pc + 4 + (int16_t)(temp & 0xFFFC); + } + else{ + cpu->pc = cpu->pc + 4; + } + return PC_INC_BY_INSTR; +} + +static uint32_t ldbio(struct NIOS_CPU * cpu, uint32_t code) +{ + return ldb(cpu, code); +} + +static uint32_t cmpgeui(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t value = 0; + + value = (uint32_t)(((uint16_t)(instr->imm16)) & 0xFFFF); + if ((uint32_t)(cpu->gp_regs[instr->a]) >= value){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t ldhuio(struct NIOS_CPU * cpu, uint32_t code) +{ + return ldhu(cpu, code); +} + +static uint32_t andhi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + int32_t value = 0; + int32_t temp = (int32_t)(instr->imm16); + + value = temp << 16; + value = value & 0xFFFF0000; + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] & value; + return PC_INC_NORMAL; +} + +static uint32_t sthio(struct NIOS_CPU * cpu, uint32_t code) +{ + return sth(cpu, code); +} + +static uint32_t bgeu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if (cpu->gp_regs[instr->a] >= cpu->gp_regs[instr->b]){ + cpu->pc = cpu->pc + 4 + (int16_t)((int16_t)(instr->imm16) & 0xFFFC); + } + else{ + cpu->pc = cpu->pc + 4; + } + return PC_INC_BY_INSTR; +} + +static uint32_t ldhio(struct NIOS_CPU * cpu, uint32_t code) +{ + return ldh(cpu, code); +} + +static uint32_t cmpltui(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if (cpu->gp_regs[instr->a] < ((uint32_t)((uint16_t)instr->imm16) & 0xFFFF)){ + cpu->gp_regs[instr->b] = 1; + } + else{ + cpu->gp_regs[instr->b] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t custom(struct NIOS_CPU * cpu, uint32_t code) +{ + return custom_instr(cpu, code); +} + +static uint32_t initd(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t orhi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] | (((uint32_t)((uint16_t)instr->imm16) << 16) & 0xFFFF0000); + return PC_INC_NORMAL; +} + +static uint32_t stwio(struct NIOS_CPU * cpu, uint32_t code) +{ + return stw(cpu, code); +} + +static uint32_t bltu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + + if (cpu->gp_regs[instr->a] < cpu->gp_regs[instr->b]){ + cpu->pc = cpu->pc + 4 + (int16_t)((int16_t)instr->imm16 & 0xFFFC); + } + else{ + cpu->pc = cpu->pc + 4; + } + return PC_INC_BY_INSTR; +} + +static uint32_t ldwio(struct NIOS_CPU * cpu, uint32_t code) +{ + return ldw(cpu, code); +} + +static uint32_t rdprs(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t flushd(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t xorhi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_i_type_code; + uint32_t value = (uint16_t)(instr->imm16); + + value = value << 16; + value = value & 0xFFFF0000; + cpu->gp_regs[instr->b] = cpu->gp_regs[instr->a] ^ value; + return PC_INC_NORMAL; +} + +/*----------------------------------------------------------------------------*/ +#define I_TYPE_HANDLER_COUNT (0x40) +struct i_type_handler i_type_handlers[I_TYPE_HANDLER_COUNT] = { + [LDBU] = handler_item(ldbu), + [ADDI] = handler_item(addi), + [STB] = handler_item(stb), + [BR] = handler_item(br), + [LDB] = handler_item(ldb), + [CMPGEI] = handler_item(cmpgei), + [LDHU] = handler_item(ldhu), + [ANDI] = handler_item(andi), + [STH] = handler_item(sth), + [BGE] = handler_item(bge), + [LDH] = handler_item(ldh), + [CMPLTI] = handler_item(cmplti), + [INITDA] = handler_item(initda), + [ORI] = handler_item(ori), + [STW] = handler_item(stw), + [BLT] = handler_item(blt), + [LDW] = handler_item(ldw), + [CMPNEI] = handler_item(cmpnei), + [FLUSHDA] = handler_item(flushda), + [XORI] = handler_item(xori), + [BNE] = handler_item(bne), + [CMPEQI] = handler_item(cmpeqi), + [LDBUIO] = handler_item(ldbuio), + [MULI] = handler_item(muli), + [STBIO] = handler_item(stbio), + [BEQ] = handler_item(beq), + [LDBIO] = handler_item(ldbio), + [CMPGEUI] = handler_item(cmpgeui), + [LDHUIO] = handler_item(ldhuio), + [ANDHI] = handler_item(andhi), + [STHIO] = handler_item(sthio), + [BGEU] = handler_item(bgeu), + [LDHIO] = handler_item(ldhio), + [CMPLTUI] = handler_item(cmpltui), + [CUSTOM] = handler_item(custom), + [INITD] = handler_item(initd), + [ORHI] = handler_item(orhi), + [STWIO] = handler_item(stwio), + [BLTU] = handler_item(bltu), + [LDWIO] = handler_item(ldwio), + [RDPRS] = handler_item(rdprs), + [FLUSHD] = handler_item(flushd), + [XORHI] = handler_item(xorhi) +}; + +/*----------------------------------------------------------------------------*/ + diff --git a/instruction.h b/instruction.h new file mode 100644 index 0000000..2253c86 --- /dev/null +++ b/instruction.h @@ -0,0 +1,120 @@ +/* + 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. +*/ + +#ifndef __INSTRUCTION_H__ +#define __INSTRUCTION_H__ + +/*--J_TYPE-------------------------------------------------------------*/ +/*--R_TYPE-------------------------------------------------------------*/ +enum OPX_TYPE_INSTR{ + ERET = 0x01, + ROLI = 0x02, + ROL = 0x03, + FLUSHP = 0x04, + RET = 0x05, + NOR = 0x06, + MULXUU = 0x07, + CMPGE = 0x08, + BRET = 0x09, + ROR=0x0B, + FLUSHI=0x0c, + JMP=0x0d, + AND=0x0e, + CMPLT = 0x10, + SLLI = 0x12, + SLL=0x13, + WRPRS = 0x14, + OR = 0x16, + MULXSU=0x17, + CMPNE=0x18, + SRLI = 0x1A, + SRL=0x1b, + NEXTPC=0x1c, + CALLR = 0x1D, + XOR=0x1e, + MULXSS=0x1f, + CMPEQ=0x20, + DIVU = 0x24, + DIV=0x25, + RDCTL, + MUL, + CMPGEU, + INITI, + TRAP = 0x2D, + WRCTL, + CMPLTU = 0x30, + ADD, + BREAK = 0x34, + SYNC = 0x36, + SUB = 0x39, + SRAI = 0x3A, + SRA=0x3b +}; +/*--I_TYPE-------------------------------------------------------------*/ +enum OP_TYPE_INSTR{ + CALL = 0x00, + JMPI = 0x01, + LDBU = 0x03, + ADDI = 0x04, + STB = 0x05, + BR = 0x06, + LDB = 0x07, + CMPGEI = 0x08, + LDHU = 0x0B, + ANDI = 0x0C, + STH = 0x0D, + BGE = 0x0E, + LDH = 0x0F, + CMPLTI = 0x10, + INITDA = 0x13, + ORI, + STW, + BLT, + LDW, + CMPNEI=0x18, + FLUSHDA = 0x1B, + XORI = 0x1C, + BNE = 0x1E, + CMPEQI = 0x20, + LDBUIO = 0x23, + MULI, + STBIO, + BEQ, + LDBIO, + CMPGEUI=0x28, + LDHUIO = 0x2B, + ANDHI = 0x2C, + STHIO = 0x2D, + BGEU = 0x2E, + LDHIO = 0x2F, + CMPLTUI = 0x30, + CUSTOM = 0x32, + INITD, + ORHI, + STWIO, + BLTU, + LDWIO, + RDPRS, + R_TYPE = 0x3A, + FLUSHD = 0x3B, + XORHI = 0x3C +}; +#endif + + diff --git a/io_device.c b/io_device.c new file mode 100644 index 0000000..e650608 --- /dev/null +++ b/io_device.c @@ -0,0 +1,155 @@ +/* + 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 "public.h" +#include "io_device.h" +#include "jtag_uart.h" +#include "timer.h" +#include "uart_core.h" +#include "nor_flash.h" + +static struct io_device * devices[] = { + &jtag_uart_io_device, + &timer_core, + &uart_core, + &nor_flash_core +}; + +#define DEVICES_COUNT (sizeof(devices)/sizeof(devices[0])) + +static struct io_device * last_used_device = NULL; + +struct io_device * get_device(uint32_t address) +{ + struct io_device * ret_val = NULL; + uint32_t i = 0; + + if (last_used_device != NULL){ + if(last_used_device->is_belong(address) == ADDR_IS_DEV){ + return last_used_device; + } + } + + for (i=0;i<DEVICES_COUNT; i++){ + if (devices[i]->is_belong != NULL){ + if (devices[i]->is_belong(address) == ADDR_IS_DEV){ + ret_val = devices[i]; + last_used_device = ret_val; + break; + } + } + } + + return ret_val; +} + +void init_devices(void) +{ + uint32_t i = 0; + + printf("--------------------------------------------------\n"); + printf(" Init H/W Device Module!\n"); + printf("--------------------------------------------------\n"); + for (i=0;i<DEVICES_COUNT; i++){ + if (devices[i]->init != NULL){ + devices[i]->init(devices[i]); + } + } + printf("--------------------------------------------------\n"); +} + +static const uint32_t data_mask[5] = { + [1] = 0xFF, + [2] = 0xFFFF, + [4] = 0xFFFFFFFF, +}; + +uint32_t io_write_data(uint32_t old_data, uint32_t new_data, + uint32_t data_len) +{ + uint32_t mask = data_mask[data_len]; + + old_data = old_data & (~mask); + new_data = new_data & mask; + return (old_data | new_data); +} + +uint32_t io_write_data_mask(uint32_t old_data, uint32_t new_data, + uint32_t data_len, uint32_t valid_mask, + uint32_t only_read_mask) +{ + uint32_t mask = data_mask[data_len]; + + new_data = new_data & mask; /* remove as the access bus width */ + new_data = new_data & valid_mask; /* remove as the valid bits */ + new_data = new_data & (~only_read_mask); /* remove the read-only bits */ + + old_data = old_data &(~mask | only_read_mask); + + return (old_data | new_data); +} + +uint32_t io_read_data(unsigned old_data, uint32_t data_len) +{ + uint32_t mask = data_mask[data_len]; + return (old_data & mask); +} + +void hw_simulating(void) +{ + int i = 0; + struct io_device * device = NULL; + + for (i=0;i<DEVICES_COUNT; i++){ + device = devices[i]; + if(device->simulate != NULL){ + device->simulate(device); + } + } +} + +uint32_t get_io_irq_status(void) +{ + int i = 0; + uint32_t irq_mask = 0; + struct io_device * device = NULL; + + for (i=0;i<DEVICES_COUNT; i++){ + device = devices[i]; + if(device->has_irq != NULL){ + if (device->has_irq(device) == DEV_HAS_IRQ){ + irq_mask |= device->irq_enable_mask; + } + } + } + + return irq_mask; +} + +uint32_t check_reg_bit(uint32_t value, uint32_t mask) +{ + if ((value & mask) == mask){ + return SIM_TRUE; + } + else { + return SIM_FALSE; + } +} +/*--------------------------------------------------------------------------*/ diff --git a/io_device.h b/io_device.h new file mode 100644 index 0000000..e520ff0 --- /dev/null +++ b/io_device.h @@ -0,0 +1,65 @@ +/* + 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. +*/ + + +#ifndef __IO_DEVICE_H__ +#define __IO_DEVICE_H__ +#include <stdio.h> + +#define ADDR_IS_NOT_DEV (0) +#define ADDR_IS_DEV (1) + +#define DEV_HAS_IRQ (1) +#define DEV_NO_IRQ (0) + +struct io_device; +struct io_device { + void * priv_data; + char * name; + uint32_t irq_enable_mask; + void (*init)(struct io_device * self); + int32_t (*is_belong)(uint32_t address); + uint32_t (*read_data)(struct io_device * self, uint32_t addr, uint32_t data_len); + void (*write_data)(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len); + int32_t (*has_irq)(struct io_device * self); + void (*simulate)(struct io_device * self); + +}; + +struct io_reg { + uint32_t addr; + uint32_t value; + uint32_t valid_mask; + uint32_t only_read_mask; +}; + +extern void init_devices(void); +extern struct io_device * get_device(uint32_t address); + +extern uint32_t io_write_data(uint32_t old_data, uint32_t new_data, uint32_t data_len); +extern uint32_t io_read_data(uint32_t old_data, uint32_t data_len); +extern uint32_t io_write_data_mask(uint32_t old_data, uint32_t new_data, uint32_t data_len, + uint32_t valid_mask, uint32_t only_read_mask); +extern void hw_simulating(void); +extern uint32_t get_io_irq_status(void); + +extern uint32_t check_reg_bit(uint32_t value, uint32_t mask); +#endif + + diff --git a/j_type_handler.c b/j_type_handler.c new file mode 100644 index 0000000..648e882 --- /dev/null +++ b/j_type_handler.c @@ -0,0 +1,46 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "instruction.h" + +static uint32_t call(struct NIOS_CPU * cpu, uint32_t code) +{ + def_j_type_code; + uint32_t imm26 = (uint32_t)instr->imm26; + + cpu->gp_regs[ra] = cpu->pc + 4; + cpu->pc = (imm26 * 4) | (cpu->pc & 0xF0000000); + return PC_INC_BY_INSTR; +} + +static uint32_t jmpi(struct NIOS_CPU * cpu, uint32_t code) +{ + def_j_type_code; + cpu->pc = (((uint32_t)(instr->imm26) * 4) & 0xFFFFFFF)| (cpu->pc & 0xF0000000); + return PC_INC_BY_INSTR; +} + +#define J_TYPE_HANDLER_COUNT (0x40) +struct j_type_handler j_type_handlers[J_TYPE_HANDLER_COUNT] = { + [CALL] = handler_item(call), + [JMPI] = handler_item(jmpi) +}; diff --git a/jtag_uart.c b/jtag_uart.c new file mode 100644 index 0000000..052c42c --- /dev/null +++ b/jtag_uart.c @@ -0,0 +1,169 @@ +/* + 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 "public.h" +#include "jtag_uart.h" + +static struct jtag_uart_priv priv; +static void uart_init(struct io_device * self) +{ + memset(&priv, 0x00, sizeof(struct jtag_uart_priv)); + + if (self != NULL){ + self->priv_data = &priv; + priv.regs[JTAG_UART_DATA_REG].addr = JTAG_UART_BASE_ADDR; + priv.regs[JTAG_UART_CTRL_REG].addr = JTAG_UART_BASE_ADDR + 4; + /* init control register */ + priv.regs[JTAG_UART_CTRL_REG].value = (JTAG_UART_FIFO_SIZE) << ALTERA_JTAGUART_CONTROL_WSPACE_OFST; /* FIFO is empty */ + } + + printf("Jtag UART at 0x%08x\n",JTAG_UART_BASE_ADDR); +} + +static int32_t uart_is_belong(uint32_t address) +{ + int32_t i = 0; + + for (i=0;i<JTAG_UART_REG_COUNT;i++){ + if (priv.regs[i].addr == address){ + return ADDR_IS_DEV; + } + } + return ADDR_IS_NOT_DEV; +} + +static uint32_t uart_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + if (addr == priv.regs[JTAG_UART_CTRL_REG].addr){ + return priv.regs[JTAG_UART_CTRL_REG].value; + } + else if (addr == priv.regs[JTAG_UART_DATA_REG].addr){ + return priv.regs[JTAG_UART_DATA_REG].value; + } + + return 0; +} + +static void write_tx_fifo(uint32_t data) +{ + priv.tx_fifo.data = data & 0xFF; + priv.tx_fifo.is_write = 1; + /* clean WI bit */ + priv.regs[JTAG_UART_CTRL_REG].value &= (~ALTERA_JTAGUART_CONTROL_WI_MSK); + /* clean write space bits */ + priv.regs[JTAG_UART_CTRL_REG].value &= 0xFFFF; +} + +static void uart_write(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len) +{ + int32_t i = 0; + + for (i=0;i<JTAG_UART_REG_COUNT;i++){ + if (priv.regs[i].addr == addr){ + if (i == JTAG_UART_DATA_REG){ + priv.regs[i].value = io_write_data(priv.regs[i].value, data, data_len); + write_tx_fifo(data); + } + else if(i == JTAG_UART_CTRL_REG){ + priv.regs[i].value |= (io_write_data(priv.regs[i].value, data, data_len) & 0x3); + /* if change the interrupt enable bits */ + if (data & 0x03){ + priv.regs[i].value = priv.regs[i].value & (~ALTERA_JTAGUART_CONTROL_WI_MSK); + } + } + } + } +} + +static uint32_t jtag_trans_clk = 500; +static int32_t jtag_uart_has_irq(struct io_device * self) +{ + int32_t ret_val = DEV_NO_IRQ; + uint32_t reg_ctrl_val = priv.regs[JTAG_UART_CTRL_REG].value; + + if (jtag_trans_clk > 0){ + jtag_trans_clk --; + return ret_val; + } + else { + jtag_trans_clk = 500; + } + + /* handle TX write fifo empty interrupt */ + if (reg_ctrl_val & ALTERA_JTAGUART_CONTROL_WE_MSK){ + if ((reg_ctrl_val & ALTERA_JTAGUART_CONTROL_WSPACE_MSK) != 0){ + ret_val = DEV_HAS_IRQ; + } + } + +#if 0 + /* handle RX data available interrupt */ + if (reg_ctrl_val & ALTERA_JTAGUART_CONTROL_RE_MSK){ + if (reg_ctrl_val & ALTERA_JTAGUART_DATA_RVALID_MSK){ + ret_val = DEV_HAS_IRQ; + priv.regs[JTAG_UART_CTRL_REG].value |= ALTERA_JTAGUART_CONTROL_RI_MSK; + } + else{ + priv.regs[JTAG_UART_CTRL_REG].value &= (~ALTERA_JTAGUART_CONTROL_RI_MSK); + } + } +#endif + return ret_val; +} + +static void jtag_uart_simulate(struct io_device * self) +{ + /* if has data to send */ + if (priv.tx_fifo.is_write){ + printf("%c", priv.tx_fifo.data); + priv.tx_fifo.is_write = 0; + /* set available fifo size */ + priv.regs[JTAG_UART_CTRL_REG].value |= (JTAG_UART_FIFO_SIZE << ALTERA_JTAGUART_CONTROL_WSPACE_OFST); + /* if set write interrupt enable */ + if (priv.regs[JTAG_UART_CTRL_REG].value & ALTERA_JTAGUART_CONTROL_WE_MSK){ + /* set write interrupt bit */ + priv.regs[JTAG_UART_CTRL_REG].value |= ALTERA_JTAGUART_CONTROL_WI_MSK; + } + } + else { + if (priv.regs[JTAG_UART_CTRL_REG].value & (JTAG_UART_FIFO_SIZE << ALTERA_JTAGUART_CONTROL_WSPACE_OFST)){ + /* if set write interrupt enable */ + if (priv.regs[JTAG_UART_CTRL_REG].value & ALTERA_JTAGUART_CONTROL_WE_MSK){ + /* set write interrupt bit */ + priv.regs[JTAG_UART_CTRL_REG].value |= ALTERA_JTAGUART_CONTROL_WI_MSK; + } + } + } +} + +struct io_device jtag_uart_io_device = { + .name = "Jtag UART Core", + .init = uart_init, + .is_belong = uart_is_belong, + .read_data = uart_read, + .write_data = uart_write, + .has_irq = jtag_uart_has_irq, + .simulate = jtag_uart_simulate, + .irq_enable_mask = JTAG_IRQ_MASK +}; + + diff --git a/jtag_uart.h b/jtag_uart.h new file mode 100644 index 0000000..d855e39 --- /dev/null +++ b/jtag_uart.h @@ -0,0 +1,56 @@ +/* + 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. +*/ + +#ifndef __JTAG_UART_H__ +#define __JTAG_UART_H__ + +#include "io_device.h" +#define JTAG_UART_REG_COUNT (2) +#define JTAG_UART_CTRL_REG (0) +#define JTAG_UART_DATA_REG (1) +#define JTAG_UART_BASE_ADDR (0x806810F0) +#define JTAG_IRQ_MASK (1 << 1) +#define JTAG_UART_FIFO_SIZE (1) + +struct fifo { + uint8_t data; + uint8_t is_write; +}; + +struct jtag_uart_priv{ + struct io_reg regs[JTAG_UART_REG_COUNT]; + struct fifo tx_fifo; +}; + +#define ALTERA_JTAGUART_DATA_DATA_MSK (0x000000FF) +#define ALTERA_JTAGUART_DATA_RVALID_MSK (0x00008000) +#define ALTERA_JTAGUART_DATA_RAVAIL_MSK (0xFFFF0000) +#define ALTERA_JTAGUART_DATA_RAVAIL_OFST (16) + +#define ALTERA_JTAGUART_CONTROL_RE_MSK (0x00000001) +#define ALTERA_JTAGUART_CONTROL_WE_MSK (0x00000002) +#define ALTERA_JTAGUART_CONTROL_RI_MSK (0x00000100) +#define ALTERA_JTAGUART_CONTROL_RI_OFST (8) +#define ALTERA_JTAGUART_CONTROL_WI_MSK (0x00000200) +#define ALTERA_JTAGUART_CONTROL_AC_MSK (0x00000400) +#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK (0xFFFF0000) +#define ALTERA_JTAGUART_CONTROL_WSPACE_OFST (16) + +extern struct io_device jtag_uart_io_device; +#endif /* __JTAG_UART_H__*/ diff --git a/load_image.c b/load_image.c new file mode 100644 index 0000000..6a10e47 --- /dev/null +++ b/load_image.c @@ -0,0 +1,620 @@ +/* + 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 <stdlib.h> +#include <string.h> +#include "public.h" +#include "nor_flash.h" + +typedef enum { + S_INVALID = 0x00, + S0 = 0x01, + S1 = 0x02, + S2 = 0x03, + S3 = 0x04, + S4 = 0x05, + S5 = 0x06, + S6 = 0x07, + S7 = 0x08, + S8 = 0x09, + S9 = 0x0A +} SREC_TYPE; + +static struct image_info image_info; + +static int32_t is_line_end(char data) +{ + if (data == '\n'){ + return 0; + } + else{ + return -1; + } +} + +static void get_line(FILE * fp, char * buf, int32_t buf_len, int32_t * line_len) +{ + char data = '\0'; + int32_t index = 0; + + memset(buf, 0x00, buf_len); + while(1){ + if(feof(fp) != 0 || ferror(fp) != 0){ + return ; + } + + data = '\0'; + if (fread(&data, 1, 1, fp) == 1){ + if (is_line_end(data) != 0){ + buf[index++] = data; + *line_len = index; + } + else { + return ; + } + } + else { + return ; + } + } +} + +static SREC_TYPE get_srec_type(char * buf) +{ + if (buf[1] >= 0x30 && buf[1] <= 0x39){ + return S0 + buf[1] - 0x30; + } + else{ + return S_INVALID; + } +} + +static uint32_t __factors [] = { + 1, + 16, + 256, + 16 * 16 * 16, + 16 * 16 * 16 * 16, + 16 * 16 * 16 * 16 * 16, + 16 * 16 * 16 * 16 * 16 * 16, + 16 * 16 * 16 * 16 * 16 * 16 * 16 +}; + +static uint32_t single_ascii_to_hex(char data) +{ + if (data >= 0x30 && data <= 0x39) + return data - 0x30; + if (data >= 0x41 && data <= 0x46) + return data - 0x41 + 10; + if (data >= 0x61 && data <= 0x66) + return data - 0x61 + 10; + return 0; +} + +uint32_t ascii_to_hex(char * buf, uint32_t buf_len) +{ + uint32_t ret = 0x0000; + int32_t i = 0; + for (i=0;i<buf_len;i++){ + ret = ret + (single_ascii_to_hex(buf[i]) * __factors[buf_len - i - 1]); + } + return ret; +} + +static uint32_t get_srec_data_count(char * buf) +{ + uint32_t count = 0; + count = ascii_to_hex(buf + 2, 2); + return count; +} + +static uint32_t to_le(uint32_t data) +{ + uint32_t ret = 0; + ret = ret | ((data & 0xFF000000) >> 24); + ret = ret | ((data & 0x00FF0000) >> 8); + ret = ret | ((data & 0x0000FF00) << 8); + ret = ret | ((data & 0x000000FF) << 24); + return ret; +} + +#define S0_DATA_OFFSET (8) +#define S0_ADDR_CRC_CNT (3) +static uint32_t handle_S0(char * buf, uint32_t data_count, uint32_t * mem_base) +{ + int32_t i = 0; + char * data_buf = buf; + + data_buf = data_buf + S0_DATA_OFFSET; + for (i=0;i<data_count - S0_ADDR_CRC_CNT; i++){ + data_buf += 2; + } + return 0; +} + +#define S3_ADDR_OFFSET (4) +#define S3_DATA_OFFSET (S3_ADDR_OFFSET + 8) +#define S3_ADDR_CRC_CNT (5) + +static uint32_t get_S3_address(char * buf) +{ + uint32_t ret = 0; + buf = buf + S3_ADDR_OFFSET; + ret = ascii_to_hex(buf, 8); + return ret; +} + +static uint32_t handle_S3(char * buf, uint32_t data_count, uint32_t * mem_base, + uint32_t base_addr) +{ + uint32_t start_addr = 0; + uint32_t offset = 0; + uint32_t data = 0; + char * data_buf = buf; + int32_t i; + + start_addr = get_S3_address(buf); + + if (base_addr == 0){ + offset = 0; + } + else{ + offset = (start_addr - base_addr)/4; + } + data_buf = data_buf + S3_DATA_OFFSET; + for (i=0;i<(data_count-S3_ADDR_CRC_CNT)/4;i++){ + data = to_le(ascii_to_hex(data_buf, 8)); + data_buf += 8; + mem_base[offset + i] = data; + } + + return start_addr; +} + +#define S2_ADDR_OFFSET (4) +#define S2_DATA_OFFSET (S2_ADDR_OFFSET + 6) +#define S2_ADDR_CRC_CNT (4) + +static uint32_t get_S2_address(char * buf) +{ + uint32_t ret = 0; + buf = buf + S2_ADDR_OFFSET; + ret = ascii_to_hex(buf, 6); + return ret; +} + +static uint32_t handle_S2(char * buf, uint32_t data_count, uint32_t * mem_base, + uint32_t base_addr) +{ + uint32_t start_addr = 0; + uint32_t offset = 0; + uint32_t data = 0; + char * data_buf = buf; + int32_t i; + + start_addr = get_S2_address(buf); + + if (base_addr == 0){ + offset = 0; + } + else{ + offset = (start_addr - base_addr)/4; + } + + data_buf = data_buf + S2_DATA_OFFSET; + for (i=0;i<(data_count-S2_ADDR_CRC_CNT)/4;i++){ + data = to_le(ascii_to_hex(data_buf, 8)); + data_buf += 8; + mem_base[offset + i] = data; + } + + return start_addr; +} + + +#define S7_DATA_OFFSET (4) +#define S7_CRC_CNT (2) +static uint32_t handle_S7(char * buf, uint32_t data_count, uint32_t * mem_base) +{ + char * data_buf = buf; + + data_buf = data_buf + S7_DATA_OFFSET; + return ascii_to_hex(data_buf, 8); +} + +#define S8_DATA_OFFSET (4) +#define S8_CRC_CNT (2) +static uint32_t handle_S8(char * buf, uint32_t data_count, uint32_t * mem_base) +{ + char * data_buf = buf; + + data_buf = data_buf + S8_DATA_OFFSET; + return ascii_to_hex(data_buf, 6); +} + +static void dummy_srec_handler(char * name) +{ + printf("%s: for %s\n",__func__, name); +} + +static void handle_srec_line(char * buf, int line_len, uint32_t * mem_base) +{ + SREC_TYPE srec_type = S_INVALID; + uint32_t data_count = 0; + uint32_t start_addr = 0; + + srec_type = get_srec_type(buf); + data_count = get_srec_data_count(buf); + + switch(srec_type){ + case S0: + handle_S0(buf, data_count, mem_base); + break; + case S1: + dummy_srec_handler("S1"); + break; + case S2: + if (image_info.base_addr == 0){ + image_info.base_addr = handle_S2(buf, data_count, mem_base, image_info.base_addr); + } + else { + handle_S2(buf, data_count, mem_base, image_info.base_addr); + } + break; + case S3: + if (image_info.base_addr == 0){ + image_info.base_addr = handle_S3(buf, data_count, mem_base, image_info.base_addr); + } + else { + handle_S3(buf, data_count, mem_base, image_info.base_addr); + } + break; + case S4: + dummy_srec_handler("S4"); + break; + case S5: + dummy_srec_handler("S5"); + break; + case S6: + dummy_srec_handler("S6"); + break; + case S7: + start_addr = handle_S7(buf, data_count, mem_base); + set_image_entry_addr(start_addr); + break; + case S8: + start_addr = handle_S8(buf, data_count, mem_base); + set_image_entry_addr(start_addr); + break; + case S9: + dummy_srec_handler("S9"); + break; + default: + return; + } + return; +} + +#define SREC_LINE_LENGTH (515) +static char data_buf[SREC_LINE_LENGTH] = {0}; + +static void load_srec(const char * image_path_name, uint32_t * image_addr) +{ + FILE * fp = NULL; + int32_t line_len = 0; + + fp = fopen(image_path_name, "r"); + if (fp != NULL){ + while(1){ + memset(data_buf, 0x00, SREC_LINE_LENGTH); + line_len = 0; + get_line(fp, data_buf, SREC_LINE_LENGTH, &line_len); + if (line_len == 0){ + break; + } + else + { + handle_srec_line(data_buf, line_len, image_addr); + } + } + fclose(fp); + } + else{ + printf("ERROR--> can not open image at %s\n", image_path_name); + } +} + +void load_image(void) +{ + switch(image_info.image_format){ + case SREC_FMT: + load_srec(image_info.path_name, image_info.mem_base); + break; + default: + break; + } +} + +void alloc_image_mem(void) +{ + char * address = NULL; + struct image_info * info = &image_info; + uint32_t temp = 0; + + address = (char *)malloc(info->mem_size); + temp = info->mem_size % 4; + if (temp != 0){ + address = address + temp; + } + info->mem_base = (uint32_t *)address; +} + +void set_image_pathname(char * pathname) +{ + image_info.path_name = pathname; +} + +void set_image_format(IMG_FORMAT format) +{ + image_info.image_format = format; +} + +void set_image_memsize(char * size) +{ + int32_t str_len = strlen(size); + char * temp = NULL; + + if (size[str_len - 1] == 'M' || size[str_len - 1] == 'm'){ + temp = malloc(str_len); + memset(temp, 0x00, str_len); + memcpy(temp, size, str_len); + temp[str_len - 1] = '\0'; + image_info.mem_size = atoi(temp) * 1024 * 1024; + free(temp); + } +} + +void set_image_entry_addr(uint32_t addr) +{ + image_info.entry_addr = addr; +} + +void set_image_base_addr(char * addr) +{ + sscanf(addr, "0x%X\n", &image_info.base_addr); +} +static char cmd_line[256] = {0}; +static uint32_t initrd_start = 0; +static uint32_t initrd_size = 0; +static char fs_image[256] = {0}; + +void print_image_info(void) +{ + printf("--------------------------------------------------\n"); + printf(" NIOS Simulator (Built at %s-%s)\n",__DATE__,__TIME__); + printf("--------------------------------------------------\n"); + printf("Image File:%s\n",image_info.path_name); + + if (image_info.image_format == SREC_FMT){ + printf("Format:SREC\n"); + } + + printf("Mem size:0x%08X, loading at %p\n", image_info.mem_size, + image_info.mem_base); + printf("Base address:0x%08X, Entry address:0x%08X\n",image_info.base_addr, + image_info.entry_addr); + printf("Set command line:%s\n", cmd_line); + printf("Initrd: 0x%08x size:0x%08x\n",initrd_start, initrd_size); + printf("rootfs: %s \n",fs_image); + printf("--------------------------------------------------\n"); +} + +struct image_info * get_image_info(void) +{ + return &image_info; +} + +static struct symbol_obj * sym_hash[256] = {NULL}; + +static struct symbol_obj * get_head_list(uint32_t addr) +{ + return sym_hash[addr % 256]; +} + +static void insert_symbol_obj(struct symbol_obj * list, struct symbol_obj * obj) +{ + if (list == NULL){ + sym_hash[obj->addr % 256] = obj; + } + else{ + while(list != NULL){ + if (list->next != NULL){ + list = list->next; + } + else{ + break; + } + + } + list->next = obj; + } +} + +static struct symbol_obj * alloc_symbol_obj(char * addr, char * name) +{ + struct symbol_obj * obj = NULL; + uint32_t size = 0; + + obj = (struct symbol_obj *)malloc(sizeof(struct symbol_obj)); + memset(obj, 0x00, sizeof(struct symbol_obj)); + + if (obj != NULL){ + obj->addr = ascii_to_hex(addr, 8); + obj->next = NULL; + size = strlen(name) + 1; + obj->sym_name = (char *)malloc(size); + if (obj->sym_name != NULL){ + memset(obj->sym_name, 0x00, size); + strncpy(obj->sym_name, name, size - 1); + } + else{ + printf("[ERROR] %s --> can not allocate symname %s \n",__func__, name); + } + } + + return obj; +} + +static void handle_symbol_line(char * line) +{ + char addr[10] = {0}; + char sym_name[64] = {0}; + char type[2] = {0}; + struct symbol_obj * obj = NULL; + struct symbol_obj * list = NULL; + + memset(sym_name, 0x00, 64); + sscanf(line, "%s %s %s\n", addr, type, sym_name); + obj = alloc_symbol_obj(addr, sym_name); + + if (obj != NULL){ + list = get_head_list(obj->addr); + insert_symbol_obj(list, obj); + } +} + +void load_symbol_file(char * symbol_file) +{ + char line[256] = {0}; + int32_t line_len = 0; + FILE * fp = NULL; + + memset(sym_hash, 0x00, sizeof(sym_hash)); + fp = fopen(symbol_file, "r"); + if (fp != NULL){ + while(1){ + memset(line, 0x00, 256); + line_len = 0; + get_line(fp, line, 256, &line_len); + if (line_len == 0){ + break; + } + else{ + line[line_len] = '\0'; + handle_symbol_line(line); + } + } + fclose(fp); + } +} + +static struct symbol_obj * find_symbol_obj(struct symbol_obj * list, uint32_t addr) +{ + struct symbol_obj * ret = NULL; + + ret = list; + while(ret != NULL){ + if (ret->addr == addr){ + break; + } + else{ + ret = ret->next; + } + } + return ret; +} + +struct symbol_obj * get_symbol(uint32_t addr) +{ + struct symbol_obj * ret = NULL; + struct symbol_obj * lst = NULL; + + lst = get_head_list(addr); + if (lst != NULL){ + ret = find_symbol_obj(lst, addr); + } + + return ret; +} + +void set_cmdline(char * optarg) +{ + strcpy(cmd_line,optarg); +} + +void init_cmdline(struct NIOS_CPU * cpu) +{ + + char * addr = (char *)image_info.mem_base; + + /* R7 is stored the start address of command line */ + memcpy((char *)(addr + 0x700000), cmd_line, 255); + /* Set magic number. + * this is copied from arch/nios2/kernel/setup.c <setup_arch> + */ + if (cmd_line[0] != '\0'){ + cpu->gp_regs[4] = 0x534f494e; + cpu->gp_regs[7] = 0xF00000; + } + +} + +void set_initrd(char * optarg) +{ + sscanf(optarg,"0x%08x,0x%08x",&initrd_start,&initrd_size); +} + +void init_initrd(struct NIOS_CPU * cpu) +{ + cpu->gp_regs[5] = initrd_start & 0xFFFFFFFC; + cpu->gp_regs[6] = (initrd_start + initrd_size) & 0xFFFFFFFC; +} + +void set_fs_image(char * optarg) +{ + sscanf(optarg,"%s",fs_image); +} + +void init_fs_image(struct NIOS_CPU * cpu) +{ + int32_t fd = open(fs_image,O_RDWR); + int32_t size = 0; + uint8_t buf [256] = {0}; + uint8_t * mem_load_addr = NULL; + + /* set the load memory address */ + mem_load_addr = nor_flash_mem_addr(); + + if (fd){ + printf("loading rootfs at %p\n", mem_load_addr); + while((size = read(fd,buf, 256)) > 0){ + memcpy(mem_load_addr, buf, size); + mem_load_addr += size; + } + + close(fd); + } + else { + printf("Can not load rootfs image at %s\n",fs_image); + } +} + +/*----------------------------------------------------------------------------*/ + @@ -0,0 +1,123 @@ +/* + 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 <unistd.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#include "public.h" + +static void print_help(void) +{ + printf("\n----------------------------------------------\n"); + printf(" HELP INFORMATION of NIOS2 Simulator\n"); + printf("----------------------------------------------\n"); + printf(" --image|-i image path name\n"); + printf(" --srec|-s image format is SREC\n"); + printf(" --mem_size|-m memory size of board\n"); + printf(" --debug_mode|-d enter debug mode\n"); + printf(" --base_addr|-b base address of memory\n"); + printf(" --sys_map|-p load symbol table\n"); + printf(" --cmdline|-c set kernel command line\n"); + printf(" --initrd|-r set the address of initrd\n"); + printf(" --fs_image|-f set the file system image\n"); + printf(" --version|-v print the version information\n"); + printf("----------------------------------------------\n"); + printf(" For Example:\n"); + printf(" nios-sim -s -i [srec file] -m [memsize] -d [set to debug mode] \n"); + printf(" -b [base addr of mem] -p [symbol file]\n"); + printf(" -c [kernel command line]\n"); + printf("----------------------------------------------\n"); +} + +static const char * version = "Simulator for NIOSII(None-MMU) Version 0.1\n Copyright@chysun2000@gmail.com\n"; +static void print_version(void) +{ + printf("\n---------------------------------------------\n"); + printf("%s", version); + printf("---------------------------------------------\n"); +} + +int main(int argc, char * argv[]) +{ + struct option long_opt [] = { + {"image",required_argument,NULL,'i'}, + {"srec",no_argument, NULL, 's'}, + {"mem_size",required_argument, NULL, 'm'}, + {"debug_mode",no_argument, NULL, 'd'}, + {"base_addr", required_argument, NULL, 'b'}, + {"sys_map", required_argument, NULL, 'p'}, + {"cmdline", required_argument, NULL, 'c'}, + {"initrd", required_argument, NULL, 'r'}, + {"fs_image",required_argument, NULL, 'f'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {0,0,0,0} + }; + + char * short_opt = "i:sm:db:p:c:vhr:f:"; + int32_t c = 0; + + while((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1){ + switch(c){ + case 'i': + set_image_pathname(optarg); + break; + case 's': + set_image_format(SREC_FMT); + break; + case 'm': + set_image_memsize(optarg); + break; + case 'd': + set_debug_mode(get_nios_cpu()); + break; + case 'b': + set_image_base_addr(optarg); + break; + case 'p': + load_symbol_file(optarg); + break; + case 'c': + set_cmdline(optarg); + break; + case 'r': + set_initrd(optarg); + break; + case 'f': + set_fs_image(optarg); + break; + case 'v': + print_version(); + return 0; + case 'h': + print_help(); + return 0; + default: + break; + } + } + + alloc_image_mem(); + load_image(); + print_image_info(); + simulating(); + return 0; +} diff --git a/nios-sim b/nios-sim Binary files differnew file mode 100755 index 0000000..2ff346d --- /dev/null +++ b/nios-sim 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; + } +} +/*----------------------------------------------------------------------------*/ + diff --git a/niosii.h b/niosii.h new file mode 100644 index 0000000..cd4ba80 --- /dev/null +++ b/niosii.h @@ -0,0 +1,182 @@ +/* + 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. +*/ + +#ifndef __NIOS_II_H__ +#define __NIOS_II_H__ + +#include <stdio.h> +#include "public.h" + +#define NIOS_REG_CNT (32) +#define D_CACHE_SIZE (16 * 1024) +#define I_CACHE_SIZE (16 * 1024) +#define PC_TRACE_CNT (128) + +enum { + NORMAL_MODE = 0x00, + SINGLE_STEP = 0x01, + BREAK_MODE = 0x02, +}; + +struct NIOS_CPU { + uint32_t gp_regs[NIOS_REG_CNT]; /* default value is 0 */ + uint32_t ctrl_regs[NIOS_REG_CNT]; /* is defined in Processor Reference Handbook */ + uint32_t pc; + uint32_t break_pc; + uint32_t mode; + uint32_t pc_trace[PC_TRACE_CNT]; + uint32_t trace_index; +}; + +#define EXCEPTION_HANDLER_ADDR (0x00800020) /* exc_hook, exception handler address */ +#define BREAK_HANDLER_ADDRESS (0x00000000) /* break handler address */ + +#define OP_R_TYPE 0x3A +#define OP_J_TYPE 0x00 + +struct i_type_handler { + uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code); +}; + +struct r_type_handler{ + uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code); +}; + +struct j_type_handler{ + uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code); +}; + +struct custom_type_handler{ + uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code); +}; + +extern struct i_type_handler i_type_handlers[]; +extern struct r_type_handler r_type_handlers[]; +extern struct j_type_handler j_type_handlers[]; + +struct i_type_code{ + uint32_t op:6; + uint32_t imm16:16; + uint32_t b:5; + uint32_t a:5; +}__attribute__ ((__packed__)); + +struct j_type_code{ + uint32_t op:6; + uint32_t imm26:26; +}__attribute__ ((__packed__)); + +struct r_type_code{ + uint32_t op:6; + uint32_t n:5; + uint32_t opx:6; + uint32_t c:5; + uint32_t b:5; + uint32_t a:5; +}__attribute__ ((__packed__)); + +#define handler_item(func) {.handler = func} + +struct custom_type_code { + uint32_t op:6; + uint32_t n:8; + uint32_t rc:1; + uint32_t rb:1; + uint32_t ra:1; + uint32_t c:5; + uint32_t b:5; + uint32_t a:5; +}; + +enum GP_REG_ALIAS{ + zero = 0, + at = 1, + et = 24, + bt = 25, + gp = 26, + sp = 27, + fp = 28, + ea = 29, + ba = 30, + ra = 31, +}; +enum CTRL_REG_ALIAS{ + status = 0, + estatus, + bstatus, + ienable, + ipending, + cpuid, + exception = 7, + pteaddr, + tlbacc, + tlbmisc, + badaddr = 12, + config, + mpubase, + mpuacc +}; + + + +#define MEM_ADDR (0) +#define IO_ADDR (1) + +#define PC_INC_NORMAL (0) +#define PC_INC_BY_INSTR (1) + +extern uint32_t custom_instr(struct NIOS_CPU * cpu, uint32_t code); +extern void reset_cpu(void); +extern struct NIOS_CPU * get_nios_cpu(void); +extern uint32_t execute(uint32_t code); +extern int32_t get_addr_type(uint32_t addr); +extern uint8_t get_byte(uint32_t addr); +extern void store_byte(uint32_t addr, uint8_t data); +extern uint16_t get_half_word(uint32_t addr); +extern void store_half_word(uint32_t addr, uint16_t data); +extern uint32_t get_word(uint32_t addr); +extern void store_word(uint32_t addr, uint32_t data); +extern uint32_t get_instruct(struct NIOS_CPU * cpu, uint32_t * mem_base, + uint32_t base_addr); +extern void dump_register(struct NIOS_CPU * cpu); +extern void dump_curr_code(uint32_t code); +extern void dump_next_code(struct NIOS_CPU * cpu); +extern void dump_pc(struct NIOS_CPU * cpu); +extern void set_break(struct NIOS_CPU * cpu, char * input); +extern void dump_mem(struct NIOS_CPU * cpu, char * input); +extern uint32_t ascii_to_hex(char * buf, uint32_t buf_len); + +#define def_i_type_code struct i_type_code * instr = (struct i_type_code *)&code +#define def_j_type_code struct j_type_code * instr = (struct j_type_code *)&code +#define def_r_type_code struct r_type_code * instr = (struct r_type_code *)&code + + +/* BIT Definition for Control register */ +#define REG_STATUS_PIE (0x01) +#define REG_STATUS_EH (1<<2) + +#define CPU_HAS_IRQ (0x01) +#define CPU_HAS_EXCEPTION (0x02) +#define CPU_HAS_NO_EVENT (0) + +extern void handle_irq_exception(struct NIOS_CPU * cpu); +extern void clean_ipending(uint32_t mask); +extern void trace_pc(struct NIOS_CPU * cpu); +#endif + diff --git a/nor_flash.c b/nor_flash.c new file mode 100644 index 0000000..3083735 --- /dev/null +++ b/nor_flash.c @@ -0,0 +1,108 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "io_device.h" +#include "nor_flash.h" + +static struct nor_flash_core_hw hw; + +static void flash_init(struct io_device * self) +{ + memset(&hw, 0x00, sizeof(struct nor_flash_core_hw)); + self->priv_data = &hw; + + hw.phys_base_addr = NOR_FLASH_BASE_ADDR; + hw.size = NOR_FLASH_SIZE; + hw.status = STATUS_READ; + hw.mem_base_addr = (unsigned char *)malloc(hw.size); + + printf("NOR Flash Module: PHYS:0x%08X at %p size:0x%08X\n", + hw.phys_base_addr, hw.mem_base_addr, hw.size); +} + +static int32_t flash_is_belong(uint32_t address) +{ + int32_t ret_val = ADDR_IS_NOT_DEV; + + if (address >= hw.phys_base_addr && address <(hw.phys_base_addr + hw.size)){ + ret_val = ADDR_IS_DEV; + } + return ret_val; +} + +/* only support 8bit access */ +static uint32_t flash_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + uint32_t ret_val = 0; + uint8_t * data = (uint8_t *)hw.mem_base_addr; + + if(data_len == (hw.bus_width / 8)){ + ret_val = (uint32_t)(data[addr - hw.phys_base_addr]); + printf("%s->%x:%x\n",__func__,addr,ret_val); + } + return ret_val; +} + +static int32_t judge_special_addr(uint32_t addr) +{ + int32_t ret_val = SIM_TRUE; + return ret_val; +} + +static void handle_special_operation(uint32_t addr, uint32_t data) +{ + +} + +static void flash_write(struct io_device * self, uint32_t addr, uint32_t data, + uint32_t data_len) +{ + uint8_t * data_buf = (uint8_t *)hw.mem_base_addr; + + /* judge whether the address is the special address */ + if (judge_special_addr(addr) == SIM_TRUE){ + handle_special_operation(addr, data); + } else { + if (hw.status == STATUS_CHIP_ERASE || hw.status == STATUS_SECTION_ERASE){ + if (data_len == (hw.bus_width/8)){ + data_buf[(addr - hw.phys_base_addr)] = (uint8_t)(data & 0xFF); + } + } + } +} + +struct io_device nor_flash_core = { + .name = "NOR Flash Core", + .init = flash_init, + .is_belong = flash_is_belong, + .read_data = flash_read, + .write_data = flash_write, + .has_irq = NULL, + .simulate = NULL, + .irq_enable_mask = 0, +}; + +uint8_t * nor_flash_mem_addr(void) +{ + return hw.mem_base_addr; +} + + diff --git a/nor_flash.h b/nor_flash.h new file mode 100644 index 0000000..a5e5e9e --- /dev/null +++ b/nor_flash.h @@ -0,0 +1,57 @@ +/* + 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. +*/ + +#ifndef __NOR_FLASH_H__ +#define __NOR_FLASH_H__ + +#include <stdio.h> +#include <stdlib.h> + +#include "io_device.h" + +#define NOR_FLASH_OPS_CNT (10) +struct nor_flash_operations{ + uint32_t addr; + uint32_t value; +}; + +#define STATUS_READ (0) +#define STATUS_WRITE (1) +#define STATUS_CHIP_ERASE (2) +#define STATUS_SECTION_ERASE (3) + +#define NOR_FLASH_BASE_ADDR (0x0000) +#define NOR_FLASH_SIZE (0x400000) +#define NOR_FLASH_BUS_WIDTH (8) + +struct nor_flash_core_hw { + struct nor_flash_operations ops[10]; + uint32_t phys_base_addr; + uint32_t size; + uint32_t status; + uint8_t * mem_base_addr; + uint32_t bus_width; +}; + +extern struct io_device nor_flash_core; +extern uint8_t * nor_flash_mem_addr(void); +#endif /* end of nor_flash.h */ + + + diff --git a/public.h b/public.h new file mode 100644 index 0000000..a84b6f6 --- /dev/null +++ b/public.h @@ -0,0 +1,85 @@ +/* + 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. +*/ + +#ifndef __PUBLIC_H__ +#define __PUBLIC_H__ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "niosii.h" + +#define SIM_FALSE (0) +#define SIM_TRUE (1) + +typedef enum { + INVALID_FMT=0x00, + SREC_FMT=0x01 +}IMG_FORMAT; + +struct image_info{ + char * path_name; + IMG_FORMAT image_format; + uint32_t mem_size; + uint32_t * mem_base; + uint32_t entry_addr; + uint32_t base_addr; +}; + +struct symbol_obj; + +struct symbol_obj{ + char * sym_name; + uint32_t addr; + struct symbol_obj * next; +}; + +extern void load_image(void); +extern void alloc_image_mem(void); +extern void set_image_pathname(char * pathname); +extern void set_image_format(IMG_FORMAT format); +extern void set_image_memsize(char * size); +extern void set_image_entry_addr(uint32_t addr); +extern void set_image_base_addr(char * addr); +extern void set_cmdline(char * optarg); +extern void set_initrd(char * optarg); +extern void set_fs_image(char * optarg); +extern void init_cmdline(struct NIOS_CPU * cpu); +extern void init_initrd(struct NIOS_CPU * cpu); +extern void init_fs_image(struct NIOS_CPU * cpu); +extern void print_image_info(void); +extern void simulating(void); +extern struct image_info * get_image_info(void); +extern void set_debug_mode(struct NIOS_CPU * cpu); +extern void load_symbol_file(char * symbol_file); +extern struct symbol_obj * get_symbol(uint32_t addr); + +#define SIM_MODE (0) +#define DEBUG_MODE (1) +#define EXIT_MODE (2) +extern int32_t get_run_mode(void); + +#endif /*__PUBLIC_H__*/ + + diff --git a/r_type_handler.c b/r_type_handler.c new file mode 100644 index 0000000..a5d5d1d --- /dev/null +++ b/r_type_handler.c @@ -0,0 +1,458 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "instruction.h" + +static uint32_t wrctl(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->ctrl_regs[instr->n] = cpu->gp_regs[instr->a]; + + return PC_INC_NORMAL; +} + + +static uint32_t eret(struct NIOS_CPU * cpu, uint32_t code) +{ + cpu->ctrl_regs[status] = cpu->ctrl_regs[estatus]; + cpu->pc = cpu->gp_regs[ea]; + + return PC_INC_BY_INSTR; +} + +static uint32_t roli(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + uint32_t shift_bit = (instr->n) ; + uint32_t value = cpu->gp_regs[instr->a]; + uint32_t temp = 0; + + temp = value >> (32 - shift_bit); + cpu->gp_regs[instr->c] = value << shift_bit; + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->c] | temp; + return PC_INC_NORMAL; +} + +static uint32_t rol(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + uint32_t shift_bit = cpu->gp_regs[instr->b] & 0x1F; + uint32_t temp = (cpu->gp_regs[instr->a]) >> (32 - shift_bit); + + cpu->gp_regs[instr->c] = (cpu->gp_regs[instr->a] << shift_bit) | temp; + return PC_INC_NORMAL; +} + +static uint32_t flushp(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t ret(struct NIOS_CPU * cpu, uint32_t code) +{ + cpu->pc = cpu->gp_regs[ra]; + + return PC_INC_BY_INSTR; +} + +static uint32_t nor(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = ~(cpu->gp_regs[instr->a] | cpu->gp_regs[instr->b]); + return PC_INC_NORMAL; +} + +static uint32_t mulxuu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + uint64_t temp = 0; + + temp = (uint32_t)cpu->gp_regs[instr->a]; + temp = temp * (uint32_t)cpu->gp_regs[instr->b]; + cpu->gp_regs[instr->c] = ((uint32_t)(temp >> 32)) & (0xFFFFFFFF); + return PC_INC_NORMAL; +} + +static uint32_t cmpge(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if ((int32_t)(cpu->gp_regs[instr->a]) >= (int32_t)(cpu->gp_regs[instr->b])){ + cpu->gp_regs[instr->c] = 1; + } + else { + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t bret(struct NIOS_CPU * cpu, uint32_t code) +{ + + cpu->ctrl_regs[status] = cpu->ctrl_regs[bstatus]; + cpu->pc = cpu->gp_regs[ba]; + return PC_INC_BY_INSTR; +} + +static uint32_t ror(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + uint32_t shift_bit = cpu->gp_regs[instr->b] & 0x1F; + uint32_t temp = cpu->gp_regs[instr->a] << (32 - shift_bit); + + cpu->gp_regs[instr->c] = (cpu->gp_regs[instr->a] >> shift_bit) | temp; + return PC_INC_NORMAL; +} + +static uint32_t flushi(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t jmp(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->pc = cpu->gp_regs[instr->a]; + return PC_INC_BY_INSTR; +} + +static uint32_t and(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] & cpu->gp_regs[instr->b]; + return PC_INC_NORMAL; +} + +static uint32_t cmplt(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if ((int32_t)(cpu->gp_regs[instr->a]) < (int32_t)(cpu->gp_regs[instr->b])){ + cpu->gp_regs[instr->c] = 1; + } + else{ + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t slli(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] << instr->n; + return PC_INC_NORMAL; +} + +static uint32_t sll(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] << (cpu->gp_regs[instr->b] & 0x1F); + return PC_INC_NORMAL; +} + +static uint32_t wrprs(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t or(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] | cpu->gp_regs[instr->b]; + return PC_INC_NORMAL; +} + +static uint32_t mulxsu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + int64_t a = (int32_t)(cpu->gp_regs[instr->a]); + int64_t temp = 0; + + temp = a * cpu->gp_regs[instr->b]; + cpu->gp_regs[instr->c] = (uint32_t)((temp >> 32)); + return PC_INC_NORMAL; +} + +static uint32_t cmpne(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if (cpu->gp_regs[instr->a] != cpu->gp_regs[instr->b]){ + cpu->gp_regs[instr->c] = 1; + } + else{ + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} +static uint32_t srli(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] >> (uint32_t)(instr->n); + return PC_INC_NORMAL; +} +static uint32_t srl(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] >> (cpu->gp_regs[instr->b] & 0x1F); + return PC_INC_NORMAL; +} + +static uint32_t nextpc(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->pc + 4; + return PC_INC_NORMAL; +} + +static uint32_t callr(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + cpu->gp_regs[ra] = cpu->pc + 4; + cpu->pc = cpu->gp_regs[instr->a]; + return PC_INC_BY_INSTR; +} + +static uint32_t xor(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + uint32_t a = cpu->gp_regs[instr->a]; + uint32_t b = cpu->gp_regs[instr->b]; + + cpu->gp_regs[instr->c] = a ^ b; + return PC_INC_NORMAL; +} + +static uint32_t mulxss(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + int32_t a = (int32_t)cpu->gp_regs[instr->a]; + int32_t b = (int32_t)cpu->gp_regs[instr->b]; + uint64_t temp = 0; + + temp = a * b; + cpu->gp_regs[instr->c] = (uint32_t) (temp >> 32); + return PC_INC_NORMAL; +} + +static uint32_t cmpeq(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if(cpu->gp_regs[instr->a] == cpu->gp_regs[instr->b]){ + cpu->gp_regs[instr->c] = 1; + } + else{ + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t divu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if (cpu->gp_regs[instr->b] != 0){ + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] / cpu->gp_regs[instr->b]; + } + return PC_INC_NORMAL; +} + +static uint32_t div(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + int32_t a = (int32_t)cpu->gp_regs[instr->a]; + int32_t b = (int32_t)cpu->gp_regs[instr->b]; + + if (b != 0){ + cpu->gp_regs[instr->c] = a / b; + } + return PC_INC_NORMAL; +} + +static uint32_t rdctl(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->ctrl_regs[instr->n]; + return PC_INC_NORMAL; +} + +static uint32_t mul(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = (cpu->gp_regs[instr->a] * cpu->gp_regs[instr->b]) & 0xFFFFFFFF; + return PC_INC_NORMAL; +} + +static uint32_t cmpgeu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if (cpu->gp_regs[instr->a] >= cpu->gp_regs[instr->b]){ + cpu->gp_regs[instr->c] = 1; + } + else{ + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t initi(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t trap(struct NIOS_CPU * cpu, uint32_t code) +{ + cpu->ctrl_regs[estatus] = cpu->ctrl_regs[status]; + cpu->ctrl_regs[status] = cpu->ctrl_regs[status] & 0xFFFFFFFC; + cpu->gp_regs[ea] = cpu->pc + 4; + cpu->pc = EXCEPTION_HANDLER_ADDR; + return PC_INC_BY_INSTR; +} + +static uint32_t cmpltu(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + if (cpu->gp_regs[instr->a] < cpu->gp_regs[instr->b]){ + cpu->gp_regs[instr->c] = 1; + } + else { + cpu->gp_regs[instr->c] = 0; + } + return PC_INC_NORMAL; +} + +static uint32_t add(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] + cpu->gp_regs[instr->b]; + return PC_INC_NORMAL; +} + +static uint32_t instr_break(struct NIOS_CPU * cpu, uint32_t code) +{ +#ifdef NIOS_SIM_SUPPORT_BREAK + cpu->ctrl_regs[bstatus] = cpu->ctrl_regs[status]; + cpu->ctrl_regs[status] = cpu->ctrl_regs[status] & 0xFFFFFFFC; + cpu->gp_regs[ba] = cpu->pc + 4; + cpu->pc = BREAK_HANDLER_ADDRESS; + return PC_INC_BY_INSTR; +#else + return PC_INC_NORMAL; +#endif +} + +static uint32_t instr_sync(struct NIOS_CPU * cpu, uint32_t code) +{ + return PC_INC_NORMAL; +} + +static uint32_t sub(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + cpu->gp_regs[instr->c] = cpu->gp_regs[instr->a] - cpu->gp_regs[instr->b]; + return PC_INC_NORMAL; +} + +static uint32_t srai(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + + int32_t a = (int32_t)cpu->gp_regs[instr->a]; + cpu->gp_regs[instr->c] = a >> (uint32_t)(instr->n); + return PC_INC_NORMAL; +} + +static uint32_t sra(struct NIOS_CPU * cpu, uint32_t code) +{ + def_r_type_code; + int32_t a = (int32_t) cpu->gp_regs[instr->a]; + + cpu->gp_regs[instr->c] = a >> (uint32_t)(cpu->gp_regs[instr->b] & 0x1F); + return PC_INC_NORMAL; +} + +#define R_TYPE_HANDLER_COUNT (0x40) + +struct r_type_handler r_type_handlers[R_TYPE_HANDLER_COUNT] = { + [ERET] = handler_item(eret), + [ROLI] = handler_item(roli), + [ROL] = handler_item(rol), + [FLUSHP] = handler_item(flushp), + [RET] = handler_item(ret), + [NOR] = handler_item(nor), + [MULXUU] = handler_item(mulxuu), + [CMPGE] = handler_item(cmpge), + [BRET] = handler_item(bret), + [ROR] = handler_item(ror), + [FLUSHI] = handler_item(flushi), + [JMP] = handler_item(jmp), + [AND] = handler_item(and), + [CMPLT] = handler_item(cmplt), + [SLLI] = handler_item(slli), + [SLL] = handler_item(sll), + [WRPRS] = handler_item(wrprs), + [OR] = handler_item(or), + [MULXSU] = handler_item(mulxsu), + [CMPNE] = handler_item(cmpne), + [SRLI] = handler_item(srli), + [SRL] = handler_item(srl), + [NEXTPC] = handler_item(nextpc), + [CALLR] = handler_item(callr), + [XOR] = handler_item(xor), + [MULXSS] = handler_item(mulxss), + [CMPEQ] = handler_item(cmpeq), + [DIVU] = handler_item(divu), + [DIV] = handler_item(div), + [RDCTL] = handler_item(rdctl), + [MUL] = handler_item(mul), + [CMPGEU] = handler_item(cmpgeu), + [INITI] = handler_item(initi), + [TRAP] = handler_item(trap), + [WRCTL] = handler_item(wrctl), + [CMPLTU] = handler_item(cmpltu), + [ADD] = handler_item(add), + [BREAK] = handler_item(instr_break), + [SYNC] = handler_item(instr_sync), + [SUB] = handler_item(sub), + [SRAI] = handler_item(srai), + [SRA] = handler_item(sra) +}; + + + diff --git a/simulator.c b/simulator.c new file mode 100644 index 0000000..e4880e9 --- /dev/null +++ b/simulator.c @@ -0,0 +1,420 @@ +/* + 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 <signal.h> +#include <unistd.h> + +#include "public.h" +#include "niosii.h" +#include "io_device.h" +#include "simulator.h" + +static int32_t simulator_mode = SIM_MODE; + +static void modify_pc(struct NIOS_CPU * cpu) +{ + cpu->pc += 4; +} + +static void set_init_pc(struct NIOS_CPU * cpu, uint32_t pc) +{ + cpu->pc = pc; +} + +static void quit_debug_mode(struct NIOS_CPU * cpu) +{ + simulator_mode = SIM_MODE; + cpu->mode = NORMAL_MODE; + cpu->break_pc = 0; +} + +int32_t get_run_mode(void) +{ + return simulator_mode; +} + +void set_debug_mode(struct NIOS_CPU * cpu) +{ + simulator_mode = DEBUG_MODE; + cpu->break_pc = 0; + cpu->mode = NORMAL_MODE; +} + +#define CMD_CHAR_SIZE (256) + +static char input_char[CMD_CHAR_SIZE] = {0}; +enum { + DISP_CURR = 0x01, + DISP_NEXT, + DUMP_REG, + HELP, + GO, + DISP_PC, + SET_BREAK, + QUIT, + DUMP_MEM, + CALL_STACK, + QUIT_SIM +}; + +static const struct debug_command debug_cmds[] = { + {"c", "disp_curr", "display the contents of current code", DISP_CURR}, + {"n", "disp_next", "display the contents of next code", DISP_NEXT}, + {"r", "dump_reg", "display the contents of register", DUMP_REG}, + {"h", "help", "display the help information", HELP}, + {"g", "go", "continue executing", GO}, + {"p", "disp_pc", "display current PC Value", DISP_PC}, + {NULL, "break", "set break address.For example:\n\t(1)break 08000010\n\t(2)break func=function name", SET_BREAK}, + {"qd", "quit_debug","quit debug mode", QUIT}, + {NULL, "dump", "dump memory",DUMP_MEM}, + {"cs", "call_stack", "dump call stack", CALL_STACK}, + {"qs", "quit_sim", "quit simulator", QUIT_SIM} +}; + +#define CMD_COUNT (sizeof(debug_cmds) / sizeof(debug_cmds[0])) + +static void disp_help(void) +{ + int32_t i; + printf("\n[HELP INFORMATION]\n"); + printf("==============================================\n"); + for (i=0;i<CMD_COUNT;i++){ + printf("[%d] \"%s\" or \"%s\"\n %s\n", + debug_cmds[i].code, + debug_cmds[i].short_cmd, + debug_cmds[i].long_cmd, + debug_cmds[i].desc); + } + printf("==============================================\n"); +} + +static int32_t get_cmd_code(char * input_char) +{ + int32_t ret_val = 0; + int32_t i = 0; + + if (strlen(input_char) == 0){ + return GO; + } + + for(i=0;i<CMD_COUNT;i++){ + if (debug_cmds[i].short_cmd != NULL + && strcmp(input_char, debug_cmds[i].short_cmd) == 0){ + ret_val = debug_cmds[i].code; + break; + } + + if (debug_cmds[i].long_cmd != NULL + && strcmp(input_char, debug_cmds[i].long_cmd) == 0){ + ret_val = debug_cmds[i].code; + break; + } + + if (debug_cmds[i].short_cmd == NULL && debug_cmds[i].long_cmd != NULL + && strstr(input_char, debug_cmds[i].long_cmd) != NULL){ + ret_val = debug_cmds[i].code; + break; + } + } + return ret_val; +} + +static void quit_simulator(void) +{ + simulator_mode = EXIT_MODE; +} + +static void dump_call_stack(void); +static const char *DEBUG_PMT = "(dbg)"; +char break_func_name[256] = {0}; +static int32_t exec_this_func(char * func_name); +static void debug_mode(struct NIOS_CPU * cpu, uint32_t code, uint32_t exec_ret) +{ + int32_t input_key = 0; + int32_t index = 0; + + if (cpu->mode == BREAK_MODE){ + if (cpu->break_pc == cpu->pc){ + cpu->break_pc = 0; + cpu->mode = SINGLE_STEP; + } + else if (exec_this_func(break_func_name) == SIM_TRUE){ + cpu->break_pc = 0; + cpu->mode = SINGLE_STEP; + } + else { + return; + } + } + + for (;;){ + memset(input_char, 0x00, CMD_CHAR_SIZE); + index = 0; + printf("%s-(PC:%08X)#",DEBUG_PMT,cpu->pc); + + while(1){ + input_key = getchar(); + if (input_key != '\n' && index < CMD_CHAR_SIZE){ + input_char[index++] = (char)input_key; + } + else { + break; + } + } + + input_key = get_cmd_code(input_char); + switch(input_key){ + case DISP_CURR: + dump_curr_code(code); + break; + case DISP_NEXT: + dump_next_code(cpu); + break; + case DUMP_REG: + dump_register(cpu); + break; + case HELP: + disp_help(); + break; + case GO: + return; + case DISP_PC: + dump_pc(cpu); + break; + case SET_BREAK: + set_break(cpu, input_char); + break; + case DUMP_MEM: + dump_mem(cpu, input_char); + break; + case QUIT: + quit_debug_mode(cpu); + return; + case QUIT_SIM: + quit_debug_mode(cpu); + quit_simulator(); + return; + case CALL_STACK: + dump_call_stack(); + break; + default: + printf("INVALID COMMAND\n"); + continue; + } + } +} + +static void sigint_handler(int sig) +{ + int32_t input = '\0'; + struct NIOS_CPU * cpu = get_nios_cpu(); + + signal(sig, SIG_IGN); + + while(1){ + printf("\nPlease select what you want?\n"); + printf("Q for Quit Simulator\n"); + printf("D for enter Debug Mode\n"); + printf("R for Resume the simulating\n"); + printf("N for do Nothing\n#"); + + input = getchar(); + if ((char)input == '\n'){ + goto handler_out; + } + + switch((char)input){ + case 'Q': + quit_debug_mode(cpu); + simulator_mode = EXIT_MODE; + return; + case 'D': + set_debug_mode(cpu); + goto handler_out; + case 'R': + quit_debug_mode(cpu); + goto handler_out; + case 'N': + goto handler_out; + default: + continue; + } + } + +handler_out: + signal(SIGINT, sigint_handler); +} + +static void sigsegv_handler(int sig) +{ + struct NIOS_CPU * cpu = get_nios_cpu(); + + signal(sig, SIG_IGN); + printf("\n--------------Segmentation fault------------------\n"); + dump_pc(cpu); + dump_register(cpu); + printf("----------------------------------------------------\n"); + dump_call_stack(); + _exit(0); +} + +static void register_signal_handler(void) +{ + signal(SIGINT, sigint_handler); + signal(SIGSEGV, sigsegv_handler); +} + +#define CS_LEN (32) +struct call_stack { + struct symbol_obj * stack[CS_LEN]; + uint32_t pos; +}; + +static struct call_stack cs = { + .stack = {NULL}, + .pos = 0, +}; + +static int32_t exec_this_func(char * func_name) +{ + struct symbol_obj * obj = NULL; + + if (cs.pos == 0){ + obj = cs.stack[0]; + } + else{ + obj = cs.stack[cs.pos-1]; + } + + if (obj != NULL){ + if (strcmp(obj->sym_name, func_name) == 0){ + return SIM_TRUE; + } + } + + return SIM_FALSE; +} +static void dump_call_stack(void); +static void record_call_stack(uint32_t addr) +{ + struct symbol_obj * obj = NULL; + + obj = get_symbol(addr); + if (obj != NULL){ + if (cs.pos == 0){ + cs.stack[cs.pos] = obj; + cs.pos ++; + } + else { + if (cs.stack[cs.pos-1] != obj){ + cs.stack[cs.pos] = obj; + cs.pos ++; + if (cs.pos == CS_LEN){ + cs.pos = 0; + } + } + } + } +} + +static void dump_call_stack(void) +{ + int32_t i = 0; + struct symbol_obj * obj = NULL; + + printf("\n============================================================\n"); + printf("[Function Call Trace]\n"); + printf("============================================================\n"); + for(i=0;i<CS_LEN;i++){ + if(cs.stack[i] != NULL){ + obj = cs.stack[i]; + if (cs.pos == (i + 1)){ + printf("[%03d] %s (0x%08x)**\n", i, obj->sym_name, obj->addr); + } + else { + printf("[%03d] %s (0x%08x)\n", i, obj->sym_name, obj->addr); + } + } + } + printf("============================================================\n"); +} + +void simulating(void) +{ + struct image_info * info = get_image_info(); + struct NIOS_CPU * cpu = NULL; + uint32_t code = 0; + uint32_t exec_result = 0; + + /* register the segment fault and Ctrl-C handler */ + register_signal_handler(); + + /* init cpu*/ + reset_cpu(); + cpu = get_nios_cpu(); + set_init_pc(cpu, info->entry_addr); /* Set the init value of PC */ + cpu = get_nios_cpu(); + + /* init device modules */ + init_devices(); + /* init the boot parameter setting for u-boot */ + init_cmdline(cpu); + init_initrd(cpu); + + /* main loop to simulating the execute of NIOSII */ + printf("Enter simulating ..................\n"); + while(1){ + /* Get the instruction */ + code = get_instruct(cpu, info->mem_base, info->base_addr); + + /* Judge whether into debug mode */ + if (get_run_mode() == DEBUG_MODE){ + if (cpu->mode == NORMAL_MODE){ + cpu->mode = SINGLE_STEP; + } + trace_pc(cpu); + debug_mode(cpu, code, exec_result); + } + else if(get_run_mode() == EXIT_MODE) { + printf("NIOS SIMULATOR EXIT!\n"); + return; + } + /* Execute the code */ + exec_result = execute(code); + if (exec_result == PC_INC_NORMAL){ + modify_pc(cpu); + } + else { + if(get_run_mode() == DEBUG_MODE){ + record_call_stack(cpu->pc); + } + } + + /* Simulate the hardware running. */ + hw_simulating(); + /* judge whether IRQ or exception happen, if yes, then handle it.*/ + handle_irq_exception(cpu); + } +} + +/*----------------------------------------------------------------------------*/ + + diff --git a/simulator.h b/simulator.h new file mode 100644 index 0000000..4773fb6 --- /dev/null +++ b/simulator.h @@ -0,0 +1,32 @@ +/* + 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. +*/ + +#ifndef __SIMULATOR_H__ +#define __SIMULATOR_H__ + +#include <stdio.h> +#include "public.h" + +struct debug_command { + char * short_cmd; + char * long_cmd; + char * desc; + int32_t code; +}; +#endif /* __SIMULATOR_H__*/ @@ -0,0 +1,215 @@ +/* + 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 "public.h" +#include "timer.h" +#include "niosii.h" + + +static struct timer_hw hw; +static uint32_t valid_mask[TIMER_REG_CNT] = { + 0x3,0xF,0xFFFF,0xFFFF,0xFFFF,0xFFFF +}; + +static uint32_t only_read_mask[TIMER_REG_CNT] = { + 0x2,0,0,0,0,0 +}; + +static void update_period_reg(void); +static void timer_init(struct io_device * self) +{ + int32_t i = 0; + + self->priv_data = &hw; + + for (i=0;i<TIMER_REG_CNT;i++){ + hw.io_regs[i].addr = TIMER_BASE_ADDR + 4 * i; + hw.io_regs[i].value = 0; + hw.io_regs[i].valid_mask = valid_mask[i]; + hw.io_regs[i].only_read_mask = only_read_mask[i]; + } + + hw.set_period = 0; + hw.curr_count = 0; + + printf("Timer Core at 0x%08X-0x%08X\n", hw.io_regs[0].addr, + hw.io_regs[TIMER_REG_CNT-1].addr); +} + +static int timer_is_belong(uint32_t address) +{ + int32_t ret_val = ADDR_IS_NOT_DEV; + if ((address >= TIMER_BASE_ADDR) && (address < (TIMER_BASE_ADDR + TIMER_REG_CNT * 4))){ + ret_val = ADDR_IS_DEV; + } + + return ret_val; +} +static void copy_snapshot(void); +static uint32_t timer_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + uint32_t ret_val = 0; + uint32_t index = 0; + + index = (addr - TIMER_BASE_ADDR) / 4; + if (index >= 0 && index < TIMER_REG_CNT){ + if (index == TIM_REG_SNAPL || index == TIM_REG_SNAPH){ + copy_snapshot(); + } + ret_val = hw.io_regs[index].value & hw.io_regs[index].valid_mask; + ret_val = io_read_data(ret_val, data_len); + } + return ret_val; +} + +static void timer_write(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len) +{ + uint32_t index = 0; + uint32_t temp = 0; + uint32_t only_read_mask = 0; + uint32_t valid_mask = 0; + + index = (addr - TIMER_BASE_ADDR) / 4; + + if (index >= 0 && index < TIMER_REG_CNT){ + temp = hw.io_regs[index].value; + valid_mask = hw.io_regs[index].valid_mask; + only_read_mask = hw.io_regs[index].only_read_mask; + hw.io_regs[index].value = io_write_data_mask(temp, data, data_len, valid_mask, only_read_mask); + + + if (index == TIM_REG_PERIODL){ + hw.set_period = hw.set_period &0xFFFF0000; + hw.set_period = hw.set_period | (data & 0xFFFF); + hw.curr_count = hw.set_period; + update_period_reg(); + } + else if (index == TIM_REG_PERIODH){ + hw.set_period = hw.set_period & 0xFFFF; + hw.set_period = hw.set_period | ((data & 0xFFFF) <<16); + hw.curr_count = hw.set_period; + update_period_reg(); + } + else if (index == TIM_REG_STATUS){ + if ((hw.io_regs[index].value & STATUS_TO_MASK) == 0){ + clean_ipending(self->irq_enable_mask); + } + } + } +} + +static int32_t timer_has_irq(struct io_device * self) +{ + int32_t ret_val = DEV_NO_IRQ; + uint32_t ctrl_reg_val = 0; + uint32_t status_reg_val = 0; + + ctrl_reg_val = hw.io_regs[TIM_REG_CTRL].value & hw.io_regs[TIM_REG_CTRL].valid_mask; + status_reg_val = hw.io_regs[TIM_REG_STATUS].value & hw.io_regs[TIM_REG_STATUS].valid_mask; + + if ((ctrl_reg_val & CTRL_ITO_MASK) == CTRL_ITO_MASK){ + if ((status_reg_val & STATUS_TO_MASK) == STATUS_TO_MASK){ + ret_val = DEV_HAS_IRQ; + } + } + return ret_val; +} + +static void copy_snapshot(void) +{ + hw.io_regs[TIM_REG_SNAPL].value = hw.io_regs[TIM_REG_PERIODL].value; + hw.io_regs[TIM_REG_SNAPH].value = hw.io_regs[TIM_REG_PERIODH].value; +} + +static void update_period_reg(void) +{ + hw.io_regs[TIM_REG_PERIODL].value = hw.curr_count & 0xFFFF; + hw.io_regs[TIM_REG_PERIODH].value = (hw.curr_count & 0xFFFF0000) >> 16; + //copy_snapshot(); +} + +static void decrease_counter(void) +{ + if (hw.curr_count > 2){ + hw.curr_count -= 2; + } + else { + hw.curr_count = 0; + } + update_period_reg(); +} + +static int32_t timer_can_decrease(void) +{ + int32_t ret = SIM_TRUE; + uint32_t reg_ctrl_val = hw.io_regs[TIM_REG_CTRL].value; + + if ((reg_ctrl_val & CTRL_START_MASK) == 0){ + ret = SIM_FALSE; + goto out; + } + + if ((reg_ctrl_val & CTRL_STOP_MASK) != 0){ + ret = SIM_FALSE; + goto out; + } + + if (hw.set_period == hw.curr_count){ + if ((reg_ctrl_val & CTRL_CONT_MASK) == 0){ + ret = SIM_FALSE; + goto out; + } + } +out: + return ret; +} + +static void update_status(void) +{ + if(hw.curr_count <= 0){ + hw.io_regs[TIM_REG_CTRL].value |= CTRL_ITO_MASK; + hw.curr_count = hw.set_period; + update_period_reg(); + hw.io_regs[TIM_REG_STATUS].value |= STATUS_TO_MASK; + } +} + +static void timer_simulate(struct io_device * self) +{ + if (timer_can_decrease() == SIM_TRUE) { + decrease_counter(); + update_status(); + } +} + +struct io_device timer_core = { + .name = "timer_core", + .init = timer_init, + .is_belong = timer_is_belong, + .read_data = timer_read, + .write_data = timer_write, + .has_irq = timer_has_irq, + .simulate = timer_simulate, + .irq_enable_mask = TIM_IRQ_MASK, +}; + + @@ -0,0 +1,55 @@ +/* + 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. +*/ + +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include <stdio.h> +#include "public.h" +#include "niosii.h" +#include "io_device.h" + +#define TIMER_REG_CNT (6) +#define TIMER_BASE_ADDR (0x80681020) + +#define CTRL_ITO_MASK (0x01) +#define CTRL_CONT_MASK (0x02) +#define CTRL_START_MASK (0x04) +#define CTRL_STOP_MASK (0x08) + +#define STATUS_TO_MASK (0x01) +#define TIM_IRQ_MASK (1 << 3) +struct timer_hw{ + struct io_reg io_regs[TIMER_REG_CNT]; + uint32_t set_period; + uint32_t curr_count; + +}; + +/* the index */ +#define TIM_REG_STATUS (0) +#define TIM_REG_CTRL (1) +#define TIM_REG_PERIODL (2) +#define TIM_REG_PERIODH (3) +#define TIM_REG_SNAPL (4) +#define TIM_REG_SNAPH (5) + +extern struct io_device timer_core; +#endif + diff --git a/uart_core.c b/uart_core.c new file mode 100644 index 0000000..ae58154 --- /dev/null +++ b/uart_core.c @@ -0,0 +1,157 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "io_device.h" +#include "uart_core.h" + +#define REG_RXDATA (0) +#define REG_TXDATA (1) +#define REG_STATUS (2) +#define REG_CONTROL (3) +#define REG_DIVISOR (4) +#define REG_ENDOFPACKET (5) + +static struct uart_core_hw hw; +static uint32_t valid_mask[UART_CORE_REG_CNT] = { + 0x1FF,0x1FF,0x1FFF,0x1FFF,0xFFFF,0x1FF +}; + +static uint32_t only_read_mask[UART_CORE_REG_CNT] = { + 0x1FF,0x00,0x00,0x00,0x00,0x00 +}; + +static void uart_init(struct io_device * self) +{ + int32_t i = 0; + + self->priv_data = &hw; + for (i=0;i<UART_CORE_REG_CNT; i++){ + hw.io_regs[i].addr = UART_CORE_BASE_ADDR + i * 4; + hw.io_regs[i].value = 0; + hw.io_regs[i].valid_mask = valid_mask[i]; + hw.io_regs[i].only_read_mask = only_read_mask[i]; + } + + hw.rx_status = 0; + hw.tx_status = 0; + printf("%s at 0x%08X-0x%08X\n",self->name, UART_CORE_BASE_ADDR, UART_CORE_BASE_ADDR + i * 4 - 4); +} + +static int32_t uart_is_belong(uint32_t address) +{ + int32_t ret_val = ADDR_IS_NOT_DEV; + + if ((address >= UART_CORE_BASE_ADDR) && (address < (UART_CORE_BASE_ADDR + UART_CORE_REG_CNT * 4))){ + ret_val = ADDR_IS_DEV; + } + return ret_val; +} + +static uint32_t uart_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + uint32_t ret_val = 0; + uint32_t index = 0; + + index = (addr - UART_CORE_BASE_ADDR) / 4; + if (index >= 0 && index < UART_CORE_REG_CNT){ + ret_val = hw.io_regs[index].value & hw.io_regs[index].valid_mask; + ret_val = io_read_data(ret_val, data_len); + + if (index == REG_RXDATA){ + hw.rx_status = UART_HAS_NO_DATA_TO_RX; + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_RRDY_MSK); + } + } + return ret_val; +} + +static void uart_write(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len) +{ + uint32_t index = 0; + uint32_t temp = 0; + uint32_t only_read_mask = 0; + uint32_t valid_mask = 0; + + index = (addr - UART_CORE_BASE_ADDR) / 4; + + if (index >= 0 && index < UART_CORE_REG_CNT){ + temp = hw.io_regs[index].value; + valid_mask = hw.io_regs[index].valid_mask; + only_read_mask = hw.io_regs[index].only_read_mask; + hw.io_regs[index].value = io_write_data_mask(temp, data, data_len, valid_mask, only_read_mask); + if(index == REG_TXDATA){ + hw.tx_status = UART_HAS_DATA_TO_TX; + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_TRDY_MSK); + } + } +} + +static int32_t uart_has_irq(struct io_device * self) +{ + int32_t ret_val = DEV_NO_IRQ; + uint32_t reg_ctrl_val = hw.io_regs[REG_CONTROL].value; + uint32_t reg_status_val = hw.io_regs[REG_STATUS].value; + + /* Check TX ready Interrupt */ + if (check_reg_bit(reg_ctrl_val, ALTERA_UART_CONTROL_TRDY_MSK) == SIM_TRUE){ + if (check_reg_bit(reg_status_val, ALTERA_UART_STATUS_TRDY_MSK) == SIM_TRUE){ + ret_val = DEV_HAS_IRQ; + } + } + + /* Check RX ready Interrupt */ + if (check_reg_bit(reg_ctrl_val, ALTERA_UART_CONTROL_RRDY_MSK) == SIM_TRUE){ + if (check_reg_bit(reg_status_val, ALTERA_UART_STATUS_RRDY_MSK) == SIM_TRUE){ + ret_val = DEV_HAS_IRQ; + } + } + + return ret_val; +} + +static void uart_simulate(struct io_device * self) +{ + /* handler TX */ + if (hw.tx_status == UART_HAS_DATA_TO_TX){ + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_TRDY_MSK); + hw.tx_status = UART_HAS_NO_DATA_TO_TX; + /* Set status TRDY bit */ + hw.io_regs[REG_STATUS].value |= ALTERA_UART_STATUS_TRDY_MSK; + } + /* handler RX */ + if(hw.rx_status == UART_HAS_NO_DATA_TO_RX){ + /* ToDo: Get the input data */ + hw.rx_status = UART_HAS_DATA_TO_RX; + /* Set status RRDY bit */ + hw.io_regs[REG_STATUS].value |= ALTERA_UART_STATUS_RRDY_MSK; + } +} + +struct io_device uart_core = { + .name = "UART Core", + .init = uart_init, + .is_belong = uart_is_belong, + .read_data = uart_read, + .write_data = uart_write, + .has_irq = uart_has_irq, + .simulate = uart_simulate, + .irq_enable_mask = UART_IRQ_MASK, +}; diff --git a/uart_core.h b/uart_core.h new file mode 100644 index 0000000..4cab207 --- /dev/null +++ b/uart_core.h @@ -0,0 +1,79 @@ +/* + 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. +*/ + +#ifndef __UART_CORE_H__ +#define __UART_CORE_H__ + +#include <stdio.h> +#include "public.h" +#include "niosii.h" +#include "io_device.h" + +#define UART_IRQ_MASK (1 << 2) +#define UART_CORE_BASE_ADDR (0x80681000) +#define UART_CORE_REG_CNT (8) + +/* Mask for registers */ +/* copy from /drivers/serial/altuart.c */ +#define ALTERA_UART_STATUS_PE_MSK (0x1) +#define ALTERA_UART_STATUS_FE_MSK (0x2) +#define ALTERA_UART_STATUS_BRK_MSK (0x4) +#define ALTERA_UART_STATUS_ROE_MSK (0x8) +#define ALTERA_UART_STATUS_TOE_MSK (0x10) +#define ALTERA_UART_STATUS_TMT_MSK (0x20) +#define ALTERA_UART_STATUS_TRDY_MSK (0x40) +#define ALTERA_UART_STATUS_RRDY_MSK (0x80) +#define ALTERA_UART_STATUS_E_MSK (0x100) +#define ALTERA_UART_STATUS_DCTS_MSK (0x400) +#define ALTERA_UART_STATUS_CTS_MSK (0x800) +#define ALTERA_UART_STATUS_EOP_MSK (0x1000) + +#define ALTERA_UART_CONTROL_PE_MSK (0x1) +#define ALTERA_UART_CONTROL_FE_MSK (0x2) +#define ALTERA_UART_CONTROL_BRK_MSK (0x4) +#define ALTERA_UART_CONTROL_ROE_MSK (0x8) +#define ALTERA_UART_CONTROL_TOE_MSK (0x10) +#define ALTERA_UART_CONTROL_TMT_MSK (0x20) +#define ALTERA_UART_CONTROL_TRDY_MSK (0x40) +#define ALTERA_UART_CONTROL_RRDY_MSK (0x80) +#define ALTERA_UART_CONTROL_E_MSK (0x100) +#define ALTERA_UART_CONTROL_TRBK_MSK (0x200) +#define ALTERA_UART_CONTROL_DCTS_MSK (0x400) +#define ALTERA_UART_CONTROL_RTS_MSK (0x800) +#define ALTERA_UART_CONTROL_EOP_MSK (0x1000) + +#define ALTERA_UART_EOP_MSK (0xFF) +#define ALTERA_UART_EOP_OFST (0) + +#define UART_HAS_NO_DATA_TO_RX (0x00) +#define UART_HAS_DATA_TO_RX (0x01) +#define UART_HAS_DATA_TO_TX (0x01) +#define UART_HAS_NO_DATA_TO_TX (0x00) + +struct uart_core_hw { + struct io_reg io_regs[UART_CORE_REG_CNT]; + uint32_t rx_status; + uint32_t tx_status; +}; + +extern struct io_device uart_core; +#endif + + + |