Fixed multiple warnings for -Wall
[simavr] / simavr / sim / sim_hex.c
1 /*
2         sim_hex.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "sim_hex.h"
26
27 // friendly hex dump
28 void hdump(const char *w, uint8_t *b, size_t l)
29 {
30         uint32_t i;
31         if (l < 16) {
32                 printf("%s: ",w);
33                 for (i = 0; i < l; i++) printf("%02x",b[i]);
34         } else {
35                 printf("%s:\n",w);
36                 for (i = 0; i < l; i++) {
37                         if (!(i & 0x1f)) printf("    ");
38                         printf("%02x",b[i]);
39                         if ((i & 0x1f) == 0x1f) {
40                                 printf(" ");
41                                 printf("\n");
42                         }
43                 }
44         }
45         printf("\n");
46 }
47
48     // decode line text hex to binary
49 int read_hex_string(const char * src, uint8_t * buffer, int maxlen)
50 {
51     uint8_t * dst = buffer;
52     int ls = 0;
53     uint8_t b = 0;
54     while (*src && maxlen--) {
55         char c = *src++;
56         switch (c) {
57             case 'a' ... 'f':   b = (b << 4) | (c - 'a' + 0xa); break;
58             case 'A' ... 'F':   b = (b << 4) | (c - 'A' + 0xa); break;
59             case '0' ... '9':   b = (b << 4) | (c - '0'); break;
60             default:
61                 if (c > ' ') {
62                     fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src);
63                     return -1;
64                 }
65                 continue;
66         }
67         if (ls & 1) {
68             *dst++ = b; b = 0;
69         }
70         ls++;
71     }
72
73     return dst - buffer;
74 }
75
76 uint8_t * read_ihex_file(const char * fname, uint32_t * dsize, uint32_t * start)
77 {
78         if (!fname || !dsize)
79                 return NULL;
80         FILE * f = fopen(fname, "r");
81         if (!f) {
82                 perror(fname);
83                 return NULL;
84         }
85         uint8_t * res = NULL;
86         uint32_t size = 0;
87         uint32_t base = ~0;
88
89         while (!feof(f)) {
90                 char line[128];
91                 if (!fgets(line, sizeof(line)-1, f))
92                         continue;
93                 if (line[0] != ':') {
94                         fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line);
95                         break;
96                 }
97                 uint8_t bline[64];
98
99                 int len = read_hex_string(line + 1, bline, sizeof(bline));
100                 if (len <= 0)
101                         continue;
102
103                 uint8_t chk = 0;
104                 {       // calculate checksum
105                         uint8_t * src = bline;
106                         int tlen = len-1;
107                         while (tlen--)
108                                 chk += *src++;
109                         chk = 0x100 - chk;
110                 }
111                 if (chk != bline[len-1]) {
112                         fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]);
113                         break;
114                 }
115                 if (bline[3] != 0) {
116                         if (bline[3] != 1) {
117                                 fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]);
118                                 break;
119                         }
120                         continue;
121                 }
122                 uint16_t addr = (bline[1] << 8) | bline[2];
123                 if (base == ~0) {
124                         base = addr;    // stadt address
125                 }
126                 if (addr != base + size) {
127                         fprintf(stderr, "%s: %s, offset out of bounds %04x expected %04x\n", __FUNCTION__, fname, addr, base+size);
128                         break;
129                 }
130                 res = realloc(res, size + bline[0]);
131                 memcpy(res + size, bline + 4, bline[0]);
132                 size += bline[0];
133         }
134         *dsize = size;
135         if (start)
136                 *start = base;
137         fclose(f);
138         return res;
139 }
140
141
142 int read_ihex_chunks(const char * fname, struct ihex_chunk_t * chunks, int max_chunks)
143 {
144         if (!fname || !chunks || !max_chunks)
145                 return -1;
146         memset((void*)chunks, 0, sizeof(chunks[0]) * max_chunks);
147         FILE * f = fopen(fname, "r");
148         if (!f) {
149                 perror(fname);
150                 return -1;
151         }
152         uint32_t segment = 0;   // segment address
153         int chunk = 0;
154         chunks[0].baseaddr = ~0;
155
156         while (!feof(f)) {
157                 char line[128];
158                 if (!fgets(line, sizeof(line)-1, f))
159                         continue;
160                 if (line[0] != ':') {
161                         fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line);
162                         break;
163                 }
164                 uint8_t bline[64];
165
166                 int len = read_hex_string(line + 1, bline, sizeof(bline));
167                 if (len <= 0)
168                         continue;
169
170                 uint8_t chk = 0;
171                 {       // calculate checksum
172                         uint8_t * src = bline;
173                         int tlen = len-1;
174                         while (tlen--)
175                                 chk += *src++;
176                         chk = 0x100 - chk;
177                 }
178                 if (chk != bline[len-1]) {
179                         fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]);
180                         break;
181                 }
182                 uint32_t addr = 0;
183                 switch (bline[3]) {
184                         case 0: // normal data
185                                 addr = segment | (bline[1] << 8) | bline[2];
186                                 break;
187                         case 1: // end of file
188                                 continue;
189                         case 2: // extended address 2 bytes
190                                 segment = ((bline[4] << 8) | bline[5]) << 4;
191                                 continue;
192                         case 4:
193                                 segment = ((bline[4] << 8) | bline[5]) << 16;
194                                 continue;
195                         default:
196                                 fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]);
197                                 continue;
198                 }
199                 if (addr != chunks[chunk].baseaddr + chunks[chunk].size) {
200                         if (chunks[chunk].size)
201                                 chunk++;
202                         chunks[chunk].baseaddr = addr;
203                 }
204                 chunks[chunk].data = realloc(chunks[chunk].data, chunks[chunk].size + bline[0]);
205                 memcpy(chunks[chunk].data + chunks[chunk].size, bline + 4, bline[0]);
206                 chunks[chunk].size += bline[0];
207         }
208         if (chunks[chunk].size)
209                 chunk++;
210         fclose(f);
211         return chunk;
212 }
213
214
215 #ifdef IHEX_TEST
216 // gcc -std=gnu99 -Isimavr/sim simavr/sim/sim_hex.c -o sim_hex -DIHEX_TEST
217 int main(int argc, char * argv[])
218 {
219         struct ihex_chunk_t chunk[4];
220         
221         for (int fi = 1; fi < argc; fi++) {
222                 int c = read_ihex_chunks(argv[fi], chunk, 4);
223                 if (c == -1) {
224                         perror(argv[fi]);
225                         continue;
226                 }
227                 for (int ci = 0; ci < c; ci++) {
228                         char n[96];
229                         sprintf(n, "%s[%d] = %08x", argv[fi], ci, chunk[ci].baseaddr);
230                         hdump(n, chunk[ci].data, chunk[ci].size);
231                 }
232         }
233 }
234 #endif