misc: Point to correct simavr include dirs
[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;    // start 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
143 read_ihex_chunks(
144                 const char * fname,
145                 ihex_chunk_p * chunks )
146 {
147         if (!fname || !chunks)
148                 return -1;
149         FILE * f = fopen(fname, "r");
150         if (!f) {
151                 perror(fname);
152                 return -1;
153         }
154         uint32_t segment = 0;   // segment address
155         int chunk = 0, max_chunks = 0;
156         *chunks = NULL;
157
158         while (!feof(f)) {
159                 char line[128];
160                 if (!fgets(line, sizeof(line)-1, f))
161                         continue;
162                 if (line[0] != ':') {
163                         fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line);
164                         break;
165                 }
166                 uint8_t bline[64];
167
168                 int len = read_hex_string(line + 1, bline, sizeof(bline));
169                 if (len <= 0)
170                         continue;
171
172                 uint8_t chk = 0;
173                 {       // calculate checksum
174                         uint8_t * src = bline;
175                         int tlen = len-1;
176                         while (tlen--)
177                                 chk += *src++;
178                         chk = 0x100 - chk;
179                 }
180                 if (chk != bline[len-1]) {
181                         fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]);
182                         break;
183                 }
184                 uint32_t addr = 0;
185                 switch (bline[3]) {
186                         case 0: // normal data
187                                 addr = segment | (bline[1] << 8) | bline[2];
188                                 break;
189                         case 1: // end of file
190                                 continue;
191                         case 2: // extended address 2 bytes
192                                 segment = ((bline[4] << 8) | bline[5]) << 4;
193                                 continue;
194                         case 4:
195                                 segment = ((bline[4] << 8) | bline[5]) << 16;
196                                 continue;
197                         default:
198                                 fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]);
199                                 continue;
200                 }
201                 if (chunk < max_chunks && addr != ((*chunks)[chunk].baseaddr + (*chunks)[chunk].size)) {
202                         if ((*chunks)[chunk].size)
203                                 chunk++;
204                 }
205                 if (chunk >= max_chunks) {
206                         max_chunks++;
207                         *chunks = realloc(*chunks, max_chunks * sizeof(ihex_chunk_t));
208                         memset(*chunks + chunk, 0, (max_chunks - chunk) * sizeof(ihex_chunk_t));
209                         (*chunks)[chunk].baseaddr = addr;
210                 }
211                 (*chunks)[chunk].data = realloc((*chunks)[chunk].data, (*chunks)[chunk].size + bline[0]);
212                 memcpy((*chunks)[chunk].data + (*chunks)[chunk].size, bline + 4, bline[0]);
213                 (*chunks)[chunk].size += bline[0];
214         }
215         fclose(f);
216         return max_chunks;
217 }
218
219
220 #ifdef IHEX_TEST
221 // gcc -std=gnu99 -Isimavr/sim simavr/sim/sim_hex.c -o sim_hex -DIHEX_TEST -Dtest_main=main
222 int test_main(int argc, char * argv[])
223 {
224         struct ihex_chunk_t chunk[4];
225         
226         for (int fi = 1; fi < argc; fi++) {
227                 int c = read_ihex_chunks(argv[fi], chunk, 4);
228                 if (c == -1) {
229                         perror(argv[fi]);
230                         continue;
231                 }
232                 for (int ci = 0; ci < c; ci++) {
233                         char n[96];
234                         sprintf(n, "%s[%d] = %08x", argv[fi], ci, chunk[ci].baseaddr);
235                         hdump(n, chunk[ci].data, chunk[ci].size);
236                 }
237         }
238 }
239 #endif