summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile46
-rw-r--r--compiler.h61
-rw-r--r--elf.c106
-rw-r--r--image.c49
-rw-r--r--image.h37
-rw-r--r--main.c236
-rw-r--r--nios2sim-ng.h47
-rw-r--r--srec.c169
8 files changed, 652 insertions, 99 deletions
diff --git a/Makefile b/Makefile
index a2f4ad9..5233213 100644
--- a/Makefile
+++ b/Makefile
@@ -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_ */
diff --git a/elf.c b/elf.c
new file mode 100644
index 0000000..cc90b18
--- /dev/null
+++ b/elf.c
@@ -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;
+}
diff --git a/image.c b/image.c
new file mode 100644
index 0000000..1f12238
--- /dev/null
+++ b/image.c
@@ -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;
+}
diff --git a/image.h b/image.h
new file mode 100644
index 0000000..01f94c9
--- /dev/null
+++ b/image.h
@@ -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_ */
diff --git a/main.c b/main.c
index 40fc250..9646725 100644
--- a/main.c
+++ b/main.c
@@ -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_ */
diff --git a/srec.c b/srec.c
new file mode 100644
index 0000000..dde118c
--- /dev/null
+++ b/srec.c
@@ -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;
+}