]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/ihex.c
Add command loadi (load intel hex file)
[z180-stamp.git] / avr / ihex.c
1 /*
2 * (C) Copyright 2015 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7 #include "common.h"
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <stdbool.h>
11
12 #include "command.h"
13 #include "con-utils.h"
14 #include "z80-if.h"
15 //#include "debug.h"
16
17
18 typedef enum {
19 IHX_OK,
20 IHX_BROKEN,
21 IHX_CHKSUMERR
22 } ihx_rstat_t;
23
24 typedef struct {
25 ihx_rstat_t status;
26 int8_t type;
27 uint8_t len;
28 uint16_t address;
29 uint8_t *data;
30 } ihex_t;
31
32
33 static
34 int get_hexdigit(void) {
35
36 int c;
37 c = toupper(my_getchar(1));
38 if (isxdigit(c)) {
39 c -= '0';
40 if (c > 9)
41 c -= ('A' - '0' - 10);
42 return c;
43 } else
44 return -1;
45 }
46
47 static
48 int get_hexbyte(void) {
49
50 uint8_t i,j;
51
52 if ((i = (uint8_t) get_hexdigit()) < 0x10)
53 if ((j = (uint8_t) get_hexdigit()) < 0x10) {
54 return (i<<4) + j;
55 }
56
57 return -1;
58 }
59
60 static
61 ihex_t ihex_get_record() {
62
63 int i;
64 uint8_t sum, c;
65 ihex_t rec = { IHX_BROKEN, 0, 0, 0, 0 };
66
67
68 while ((c = my_getchar(0)) != ':')
69 if (c == 0x03)
70 return rec;
71
72 if ((i = get_hexbyte()) < 0) /* Start code */
73 return rec;
74 sum = i;
75 rec.len = i;
76 if ((i = get_hexbyte()) < 0) /* Byte Count */
77 return rec;
78 sum += i;
79 rec.address = i * 256;
80 if ((i = get_hexbyte()) < 0) /* Address */
81 return rec;
82 sum += i;
83 rec.address += i;
84 if ((i = get_hexbyte()) < 0) /* Record type */
85 return rec;
86 sum += i;
87 rec.type = i;
88
89 if (rec.len) { /* Record Data */
90 uint8_t *p; int k;
91 if ((rec.data = malloc(rec.len)) == 0)
92 return rec;
93 for (p=rec.data, k=rec.len; k; k--) {
94 if ((i = get_hexbyte()) < 0)
95 break;
96 sum += i;
97 *p++ = i;
98 }
99 if (k) {
100 free(rec.data); rec.data = 0;
101 return rec;
102 }
103 }
104 if ((i = get_hexbyte()) < 0) /* Check sum */
105 return rec;
106 sum += i;
107 if (sum) {
108 free(rec.data); rec.data = 0;
109 rec.status = IHX_CHKSUMERR;
110 } else
111 rec.status = IHX_OK;
112
113 return rec;
114 }
115
116
117 command_ret_t do_loadihex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
118 {
119 long offset = 0;
120 uint32_t base_address = 0;
121 uint32_t address_low = 0xffffffff;
122 uint32_t address_high = 0;
123 bool done = false;
124 command_ret_t rcode = CMD_RET_FAILURE;
125 ihex_t rec;
126
127 (void) cmdtp;
128 (void) flag;
129
130 if (argc > 1)
131 offset = strtol(argv[1], NULL, 16);
132
133 while (!done) {
134 rec = ihex_get_record();
135
136 if (rec.status == IHX_OK) {
137 switch (rec.type) {
138 case 0: /* Data record */
139 if (rec.len) {
140 uint32_t addr = base_address + rec.address + offset;
141 if (addr < address_low)
142 address_low = addr;
143 if (addr+rec.len > address_high)
144 address_high = addr + rec.len;
145
146 z80_bus_cmd(Request);
147 z80_write_block(rec.data, /* src */
148 addr, /* dest */
149 rec.len); /* len */
150 z80_bus_cmd(Release);
151 }
152 continue;
153 break;
154
155 case 1: /* EOF record */
156
157 done = true;
158 break;
159
160 case 2: /* Extended Segment Address Record */
161 base_address = ((rec.data[0] << 8) + rec.data[1]) << 4;
162 continue;
163 break;
164
165 case 4: /* Extended Linear Address Record */
166 base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16;
167 continue;
168 break;
169
170 case 3: /* Start Segment Address Record (ignored)*/
171 case 5: /* Start Linear Address Record (ignored)*/
172 continue;
173 break;
174
175 }
176
177 } else
178 done = true;
179 }
180
181 switch (rec.status) {
182 case IHX_OK:
183 rcode = CMD_RET_SUCCESS;
184 break;
185
186 case IHX_BROKEN:
187 case IHX_CHKSUMERR:
188 printf_P(PSTR("Broken Hex Record or loading interrupted!\n"));
189 break;
190 }
191
192 printf_P(PSTR("Data loaded - "));
193 if (address_low >= address_high)
194 printf_P(PSTR("None.\n"));
195 else
196 printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low, address_high);
197
198 return rcode;
199 }