diff options
-rw-r--r-- | Makefile | 46 | ||||
-rw-r--r-- | compiler.h | 61 | ||||
-rw-r--r-- | elf.c | 106 | ||||
-rw-r--r-- | image.c | 49 | ||||
-rw-r--r-- | image.h | 37 | ||||
-rw-r--r-- | main.c | 236 | ||||
-rw-r--r-- | nios2sim-ng.h | 47 | ||||
-rw-r--r-- | srec.c | 169 |
8 files changed, 652 insertions, 99 deletions
@@ -1,25 +1,43 @@ -# -# Make file for compiling simulator for NIOSII -# +P = nios2sim-ng +VERSION = 0.1 -TARGET=nios-sim +OBJS = main.o image.o elf.o srec.o +#OBJS += load_image.o nor_flash.o simulator.o simulator.o niosii.o i_type_handler.o j_type_handler.o \ +# r_type_handler.o custom_instr.o io_device.o jtag_uart.o timer.o uart_core.o -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 +DEFS = -DVERSION="\"$(VERSION)\"" -DDEBUG -CFLAGS= -g -Wall +CFLAGS += -g -W -Wall $(DEFS) +LDFLAGS += -lelf -all: - gcc -o ${TARGET} ${CFLAGS} ${SRC} +all: prepare $(P) -.phony: - clean distclean +prepare: + @mkdir -p .deps + +$(P): $(OBJS) + @echo LD $@ + @$(CC) $(LDFLAGS) -o $@ $^ + +-include $(addprefix .deps/,$(OBJS:.o=.o.dep)) + +%.o: %.c %.h + @echo CC $@ + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $(CFLAGS) $< > $(addprefix .deps/,$@.dep) + +%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $(CFLAGS) $< > $(addprefix .deps/,$@.dep) clean: - @rm -rf ${TARGET} *.o + @echo CLEAN + @rm -rf .deps + @rm -rf $(P) *.o distclean: clean + @echo DISTCLEAN @rm -rf *~ @rm -rf #* - @rm -rf tags
\ No newline at end of file + @rm -rf tags diff --git a/compiler.h b/compiler.h new file mode 100644 index 0000000..1005017 --- /dev/null +++ b/compiler.h @@ -0,0 +1,61 @@ +#ifndef _COMPILER_H_ +#define _COMPILER_H_ + +#include <stdint.h> + +#ifdef __GNUC__ +# define __packed __attribute__ ((packed)) +# define __unused __attribute__ ((unused)) +# define __noreturn __attribute__ ((noreturn)) +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) + +static inline void prefetch(const void *ptr) +{ + /* We could use some arch specific instructions here, but a GCC builtin + is fine for now */ + __builtin_prefetch(ptr, 0, 3); +} + +static inline int32_t bswap_32(int32_t x) +{ + return __builtin_bswap32(x); +} + +#else +# define __packed +# define __unused +# define __noreturn +# define likely(x) (x) +# define unlikely(x) (x) + +static inline prefetch(const void *ptr) +{ + /* empty */ +} + +static inline int32_t bswap_32(int32_t x) +{ + int32_t ret = 0; + + ret |= ((x & 0xFF000000) >> 24); + ret |= ((x & 0x00FF0000) >> 8); + ret |= ((x & 0x0000FF00) << 8); + ret |= ((x & 0x000000FF) << 24); + return ret; + +} + +#endif /* __GNUC__ */ + +#ifndef offsetof +# define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif /* offsetof */ + +#ifndef container_of +# define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type, member) );}) +#endif /* container_of */ + +#endif /* _COMPILER_H_ */ @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * This file is part of nios2sim-ng. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <stdio.h> +#include <stdint.h> +#include <libelf.h> +#include <gelf.h> + +#include "nios2sim-ng.h" +#include "image.h" + +/* not defined with libelf */ +#define EM_ALTERA_NIOS2 113 + +/* + * http://elftoolchain.sourceforge.net/for-review/libelf-by-example-20100112.pdf + */ + +static int elf_read_sections(Elf *e) +{ + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + size_t shstrndx; + char *name; + + if (elf_getshdrstrndx(e, &shstrndx) != 0) { + err("elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1)); + return -1; + } + + while ((scn = elf_nextscn(e, scn)) != NULL) { + GElf_Phdr phdr; + + if (gelf_getshdr(scn, &shdr) != &shdr) { + err("Couldn't get section header: %s\n", elf_errmsg(-1)); + return -1; + } + + if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { + err("Couldn't get section name: %s\n", elf_errmsg(-1)); + return -1; + } + + dbg("Section %zu: %s\n", elf_ndxscn(scn), name); + } + + return 0; +} + +int elf_load(FILE *fp, const char *name, uint8_t *mem_base, size_t mem_size) +{ + int fd = fileno(fp); + int ret; + Elf *e; + GElf_Ehdr ehdr; + size_t n; + + if (unlikely(fd < 0)) { + err("Couldn't get file descriptor for '%s'\n", name); + return -1; + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + err("ELF library initialization failed\n"); + return -1; + } + + ret = -1; + e = elf_begin(fd, ELF_C_READ, NULL); + if (unlikely(e == NULL)) { + err("Couldn't get ELF file handle for '%s': %s\n", name, elf_errmsg(-1)); + goto out; + } + + if (elf_kind(e) != ELF_K_ELF) { + err("'%s' is not an ELF object\n", name); + goto out; + } + + if (gelf_getclass(e) != ELFCLASS32) { + err("'%s' has invalid ELF class\n", name); + goto out; + } + + if (gelf_getehdr(e, &ehdr) == NULL) { + err("gelf_getehdr() failed: %s\n", elf_errmsg(-1)); + goto out; + } + + if (ehdr.e_type != ET_EXEC || ehdr.e_machine != EM_ALTERA_NIOS2) { + err("'%s' is not a Nios2 ELF executable (%x, %x)\n", name, ehdr.e_type, ehdr.e_machine); + goto out; + } + + ret = elf_read_sections(e); +out: + elf_end(e); + return ret; +} @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * This file is part of nios2sim-ng. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "nios2sim-ng.h" +#include "image.h" + +int image_load(const char *image_path, int image_format, uint8_t *mem_base, + size_t mem_size) +{ + FILE *fp; + loader_func_t loader; + int ret; + + switch(image_format) { + case FORMAT_ELF: + loader = elf_load; + break; + case FORMAT_SREC: + loader = srec_load; + break; + default: + err("Invalid image format\n"); + return -1; + } + + fp = fopen(image_path, "r"); + if (unlikely(fp == NULL)) { + err("Could not open image file '%s': %s\n", image_path, strerror(errno)); + return -1; + } + + ret = loader(fp, image_path, mem_base, mem_size); + + fclose(fp); + + return ret; +} @@ -0,0 +1,37 @@ +/* + */ + +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +extern int image_load(const char *image_path, int image_format, uint8_t *mem_base, size_t mem_size); + +/* Image file loader functions */ +typedef int (*loader_func_t)(FILE *, const char *, uint8_t *, size_t); +extern int srec_load(FILE *fp, const char *name, uint8_t *mem_base, size_t mem_size); +extern int elf_load(FILE *fp, const char *name, uint8_t *mem_base, size_t mem_size); + +enum { + FORMAT_SREC, + FORMAT_ELF, +}; + +static inline char *image_format_str(int format) +{ + char *ret; + + switch (format) { + case FORMAT_SREC: + ret = "SREC"; + break; + case FORMAT_ELF: + ret = "ELF"; + break; + default: + ret = "<invalid format>"; + } + + return ret; +} + +#endif /* _IMAGE_H_ */ @@ -1,123 +1,189 @@ /* - 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. -*/ + * nios2sim-ng -- Nios II Simulator (Next Generation) + * + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * Based on Nios-sim, which is: + * 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" +#include <errno.h> + +#include "nios2sim-ng.h" +#include "image.h" -static void print_help(void) +#define PROGRAM_NAME "nios2sim-ng" +#define PROGRAM_VERSION VERSION /* Set in Makefile */ + +#define DEFAULT_MEM_SIZE (16 * 1024 * 1024) + +static void usage(const int status) { - 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"); + fprintf(stdout, "Usage: %s [OPTION...] IMAGE\n" + " -c CMDLINE, --cmdline=CMDLINE\n" + " specify kernel command line\n" + " -m MEMSIZE, --memsize=MEMSIZE\n" + " set memory size for simulator (default %zu%s)\n" + " -d, --debug enable debug mode\n" + " -e, --elf image is in ELF format (default)\n" + " -s, --srec image is in SREC format\n" + " -h, --help print this help and exit\n" + " -V, --version print version information and exit\n" + "\n" + "Example:\n" + " %s -s -m 32M -d -c console=ttyJ0 init=/bin/sh\n" + "", + PROGRAM_NAME, size_scale(DEFAULT_MEM_SIZE), + size_postfix(DEFAULT_MEM_SIZE), PROGRAM_NAME); + + exit(status); } +static const struct option long_opts[] = { + { "elf", no_argument, NULL, 'e' }, + { "srec", no_argument, NULL, 's' }, + { "mem_size", required_argument, NULL, 'm' }, + { "debug", 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' }, + { NULL, 0, NULL, 0 } +}; -static const char * version = "Simulator for NIOSII(None-MMU) Version 0.1\n Copyright@chysun2000@gmail.com\n"; -static void print_version(void) +static const char *short_opts = "sm:db:p:c:r:f:Vh"; + +static size_t parse_mem_size(char *opt) { - printf("\n---------------------------------------------\n"); - printf("%s", version); - printf("---------------------------------------------\n"); + size_t len = strlen(opt); + size_t mem_size; + size_t mul = 1; + + switch (opt[len - 1]) { + case 'k': + case 'K': + mul = 1024; + opt[len - 1] = '\0'; + break; + case 'm': + case 'M': + mul = 1024 * 1024; + opt[len - 1] = '\0'; + break; + } + + errno = 0; + mem_size = strtoul(optarg, NULL, 0); + if (errno != 0) { + err("Invalid memory size: %s\n", opt); + exit(EXIT_FAILURE); + } + + mem_size *= mul; + + return round_up(mem_size, 4); } -int main(int argc, char * argv[]) +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); + char *image_path; + char *cmdline = ""; + int image_format = FORMAT_ELF; + uint8_t *mem_base; + size_t mem_size = DEFAULT_MEM_SIZE; + int c; + + while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + switch(c) { + case 'e': + image_format = FORMAT_ELF; break; case 's': - set_image_format(SREC_FMT); + image_format = FORMAT_SREC; break; case 'm': - set_image_memsize(optarg); + mem_size = parse_mem_size(optarg); break; case 'd': - set_debug_mode(get_nios_cpu()); +// set_debug_mode(get_nios_cpu()); break; case 'b': - set_image_base_addr(optarg); +// sscanf(addr, "0x%X\n", &image_info.base_addr); break; case 'p': - load_symbol_file(optarg); +// load_symbol_file(optarg); break; case 'c': - set_cmdline(optarg); + cmdline = optarg; break; case 'r': - set_initrd(optarg); +// set_initrd(optarg); break; case 'f': - set_fs_image(optarg); +// set_fs_image(optarg); break; - case 'v': - print_version(); - return 0; + case 'V': + info("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION); + exit(EXIT_SUCCESS); case 'h': - print_help(); - return 0; - default: + usage(EXIT_SUCCESS); break; + default: + usage(EXIT_FAILURE); } } - - alloc_image_mem(); - load_image(); - print_image_info(); + + if (optind >= argc) { + err("No image file specified\n"); + exit(EXIT_FAILURE); + } + + image_path = argv[optind]; + + mem_base = malloc(mem_size); + if (unlikely(mem_base == NULL)) { + err("Failed to allocate memory\n"); + exit(EXIT_FAILURE); + } + + if (image_load(image_path, image_format, mem_base, mem_size)) + exit(EXIT_FAILURE); + + info(" Image file: %s\n", image_path); + info(" Image format: %s\n", image_format_str(image_format)); + info(" Memory size: %zu %sbytes\n", size_scale(mem_size), size_postfix(mem_size)); + info(" Memory base: %p\n", mem_base); + +#if 0 + 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); + simulating(); - return 0; +#endif + + exit(EXIT_SUCCESS); } diff --git a/nios2sim-ng.h b/nios2sim-ng.h new file mode 100644 index 0000000..7a3d711 --- /dev/null +++ b/nios2sim-ng.h @@ -0,0 +1,47 @@ +/* + * + */ + +#ifndef _NIOS2SIM_NG_H_ +#define _NIOS2SIM_NG_H_ + +#include <stdlib.h> +#include <stdint.h> + +#include "compiler.h" + +#define __round_mask(x, y) ((__typeof__(x))((y) - 1)) +#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) + +#define err(fmt, args...) fprintf(stderr, "Error: " fmt, ##args) +#define warn(fmt, args...) fprintf(stderr, "Warning: " fmt, ##args) +#define info(fmt, args...) fprintf(stdout, fmt, ##args) +#ifdef DEBUG +# define dbg(fmt, args...) fprintf(stdout, fmt, ##args) +#else +# define dbg(fmt, args...) +#endif + +static inline size_t size_scale(size_t size) +{ + if (size > 1024 * 1024) + size /= 1024 * 1024; + else if (size > 1024) + size /= 1024; + + return size; +} + +static inline char *size_postfix(size_t size) +{ + char *ret = ""; + + if (size > 1024 * 1024) + ret = "M"; + else if (size > 1024) + ret = "K"; + + return ret; +} + +#endif /* _NIOS2SIM_NG_H_ */ @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * This file is part of nios2sim-ng. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include "nios2sim-ng.h" +#include "image.h" + +#define SREC_CRC_COUNT 1 + +#define SREC_LINE_LENGTH 515 +static char data_buf[SREC_LINE_LENGTH]; + +/** + * @return length of the line + */ +static ssize_t srec_read_line(FILE *fp, char *buf, size_t count) +{ + char c; + ssize_t len = 0; + + while (count > 0 && !feof(fp)) { + if (ferror(fp)) { + err("ferror\n"); + goto err_out; + } + + /* Read byte by byte */ + if (fread(&c, 1, 1, fp) == 1) { + if (c == '\n' || c == '\r') + break; /* end of line */ + + buf[len++] = c; + count--; + } else { + if (feof(fp) && !ferror(fp)) + break; + else + goto err_out; + } + } + + return len; +err_out: + return -1; +} + +static int srec_load_S3(char *buf, size_t data_count, + uint32_t start_addr, uint8_t *mem_base, size_t mem_size) +{ + size_t i; + uint32_t *base = (uint32_t *) mem_base; + off_t offset = 0; + + for (i = 0; i < data_count; i += 4) { + uint32_t tmp; + + if (sscanf(buf + i * 2, "%8x", &tmp) != 1) { + err("sscanf() failed on S3 record\n"); + return -1; + } + /* SREC is Big Endian, NiosII is Little Endian */ + tmp = bswap_32(tmp); + + if (offset + i > mem_size - 1) { + err("Image file too large for allocated memory of %zu bytes\n", mem_size); + return -1; + } + /* Store in memory */ + base[offset + i] = tmp; + } + + return 0; +} + +static int srec_handle_line(char *buf, size_t len, uint8_t *mem_base, size_t mem_size) +{ + unsigned int data_count = 0; + unsigned int start_addr; + + /* Minimum valid record size */ + if (len < 2) { + err("Invalid line in SREC file\n"); + return -1; + } + + if (buf[0] != 'S') { + err("Invalid line in SREC file\n"); + return -1; + } + + switch (buf[1]) { + case '0': + dbg("handling S0\n"); + break; + case '1': + dbg("handling S1\n"); + break; + case '2': + dbg("handling S2\n"); + break; + case '3': + if (sscanf(buf, "S3%2x%8x", &data_count, &start_addr) != 2) { + err("Invalid S3 record\n"); + return -1; + } + + if (srec_load_S3(buf + 12, data_count - 4, start_addr, mem_base, mem_size) != 0) + return -1; + break; + case '4': + dbg("handling S4\n"); + break; + case '5': + dbg("handling S5\n"); + break; + case '6': + dbg("handling S6\n"); + break; + case '7': + dbg("handling S7\n"); + break; + case '8': + dbg("handling S8\n"); + break; + case '9': + dbg("handling S9\n"); + break; + default: + err("Invalid SREC type: %c\n", buf[1]); + return -1; + } + + return 0; +} + +int srec_load(FILE *fp, const char *name, uint8_t *mem_base, size_t mem_size) +{ + ssize_t len; + int ret = 0; + + while (1) { + memset(data_buf, 0x00, SREC_LINE_LENGTH); + len = srec_read_line(fp, data_buf, SREC_LINE_LENGTH); + if (len < 0) { + ret = -1; + break; + } else if (len == 0) { + ret = 0; + break; + } else { + ret = srec_handle_line(data_buf, len, mem_base, mem_size); + if (ret < 0) + break; + } + } + + return ret; +} |