13 #define MIN(a,b) ((a)<(b)?(a):(b))
15 /* return 0 for end of file. -1 for error */
16 int parse_ihex16(const char *line, uint8_t *bytes, int *addr, int *code)
18 unsigned int sum, len, cksum;
19 unsigned int laddr, lcode;
23 if (line[0] != ':') return -1;
24 if (strlen(line) < 11) return -1;
26 if (!sscanf(p, "%02x", &len)) return -1;
28 if (strlen(line) < (11 + (len * 2))) return -1;
29 if (!sscanf(p, "%04x", &laddr)) return -1;
31 *addr = laddr; // little endian address record
32 if (!sscanf(p, "%02x", &lcode)) return -1;
36 /* end of file record */
37 if (*code == 1) return 0;
39 sum = (len & 0xFF) + ((*addr >> 8) & 0xFF) + (*addr & 0xFF) + (*code & 0xFF);
44 /* files are little-endian */
45 if (!sscanf(p, "%02x", &byte)) return -1;
46 bytes[i+1] = byte & 0xFF;
50 if (!sscanf(p, "%02x", &byte)) return -1;
51 bytes[i] = byte & 0xFF;
56 if (!sscanf(p, "%02x", &cksum)) return -1;
57 if ( ((sum & 0xFF) + (cksum & 0xFF)) & 0xFF ) return -1;
61 static void mem_add(mem_t **head, uint32_t start, uint8_t * bytes, int len)
63 /* look for an existing block this overlaps/adjoins */
64 mem_t * block = *head;
65 uint32_t end = start + len;
67 for(block = *head; block!=NULL; block=block->next) {
68 int bend = block->start + block->len;
69 /* before and not touching */
70 if (start < block->start && end+1 < block->start) continue;
71 /* after and not touching */
72 if (start > bend+1) continue;
74 /* therefore it at least touches */
76 /* starts before or on old block */
77 if (start <= block->start) {
78 int pre=0, lap=0, post=0;
79 pre = block->start - start; // bytes before the old block
80 lap = len - pre; // bytes overlapping, from start
81 if (lap > block->len) {
82 post = lap - block->len;
85 int newsize = block->len + pre + post;
86 uint8_t * newbytes = malloc(newsize);
87 memcpy(&newbytes[pre], block->bytes, block->len);
88 memcpy(newbytes, bytes, len);
90 block->bytes = newbytes;
94 /* starts part way down / at end */
95 int pre=0, /*lap=0, */ post=0;
96 pre = start - block->start; // gap from start
97 //lap = MIN(block->len - pre, len);
98 if (end > bend) post = end - bend;
99 int newsize = block->len + post;
100 uint8_t * newbytes = malloc(newsize);
101 memcpy(newbytes, block->bytes, block->len);
102 memcpy(&newbytes[pre], bytes, len);
103 block->bytes = newbytes;
104 block->len = newsize;
109 block = calloc(1, sizeof(mem_t));
110 block->start = start;
112 block->bytes = malloc(len);
113 memcpy(block->bytes, bytes, len);
118 mem_t * load_ihex(FILE *in)
126 while (!feof(in) && fgets(buff, sizeof(buff), in)!=NULL) {
127 if (buff[0] == '#') continue;
129 unsigned char bytes[80];
132 if ((len=parse_ihex16(buff, bytes, &addr, &code)) <= 0) {
133 if (len < 0) loge("LoadIHEX: Bad line: %s\n", buff);
138 addrh = ((bytes[0] << 8) | bytes[1]) << 16;
139 logd("LoadIHEX: Setting high addr 0x%02X%02X", bytes[0], bytes[1]);
142 /* end of file marker */
146 /* normal code block */
147 uint32_t fulladdr = addrh | addr;
148 mem_add(&ram, fulladdr, bytes, len);
154 /* summary of the memory blocks in this list */
155 void list_mem(const mem_t * head)
157 const mem_t *p = head;
159 logd("%6X : %d bytes", p->start, p->len);
164 /* check that the program will fit */
165 int validate_mem(mem_t * head, uint16_t maxmem)
168 loge("MemValidate: No program!");
175 /* test that all the memory blocks will fit */
176 for (p=head; p!=NULL; p=p->next) {
177 /* just ignore config bytes, we cant write them anyway */
178 if (p->start / 2 >= 0x8000) continue;
182 if (p->start / 2 >= maxmem || (p->start+p->len)/2 >= maxmem) {
183 loge("MemValidate: Program too large, overlaps bootloader.");
188 logd("MemValidate: Used %d of %d leaving %d free.", used, maxmem, maxmem-used);
193 /* reorganise bytes to work with the boot loader */
194 int makesafe_mem(mem_t **head, uint16_t maxmem)
196 /* it must fit safely first */
197 if (validate_mem(*head, maxmem)) return 1;
199 mem_t * new = malloc(sizeof(mem_t));
200 new->start = maxmem * 2;
202 new->bytes = malloc(8);
203 memset(new->bytes, 255, 8);
206 /* find the code that goes in words 0-3 and move it */
208 for (p = *head; p!=NULL; p=p->next) {
209 if (p->start >= 0 && p->start <= 7) {
211 int lap = MIN(8-pre, p->len);
212 memcpy(&new->bytes[pre], p->bytes, lap);
215 memmove(p->bytes, &p->bytes[lap], p->len);
221 loge("MakeSafeMem: Could not find start vector");
226 /* check that there is something sane in here
227 * Warning: this is very enhanced-midrange dependant */
229 uint8_t * m = new->bytes;
231 for (int i=0; i<4; i++) {
232 uint16_t in = (m[0] << 8) | m[1];
233 if ((in & 0x3F80) == 0x3180) { // MOVLP
235 logd("MakeSafeMem: 0x%04X MOVLP 0x%02X", i, lath);
237 if ((in & 0x3800) == 0x2800) { // GOTO
238 uint16_t addr = in & 0x07FF;
240 logd("MakeSafeMem: 0x%04X GOTO 0x%02X", i, addr);
243 // an absolute goto within the reset vector
244 // this is silly and wrong, replace with NOP
245 logd("MakeSafeMem: Rewriting bad 'GOTO 0x%02X' to NOP", addr);
249 // there is a sane GOTO, hurrah
257 loge("Start Vector did not contain a GOTO");