/* * Copyright (C) 2010 Tobias Klauser * * 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 #include #include #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, off_t offset, uint8_t *mem_base, size_t mem_size) { size_t i; uint32_t *base = (uint32_t *) mem_base; 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) { err("Image file too large for allocated memory of %zu bytes\n", mem_size); return -1; } /* Store in memory */ base[offset / 4 + 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': /* Ignore */ 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 __unused, 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; }