]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_loadihex.c
Merge branch 'fatfs-integration' into fatcommands
[z180-stamp.git] / avr / cmd_loadihex.c
1 /*
2 * (C) Copyright 2015 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 #include "cmd_loadihex.h"
8 #include <ctype.h>
9
10 #include "con-utils.h"
11 #include "z80-if.h"
12 #include "debug.h"
13
14
15 uint32_t detect_ramsize(void)
16 {
17 uint32_t addr;
18 uint8_t save_addr, save_0;
19 const uint8_t PATTERN_1 = 0x55;
20 const uint8_t PATTERN_2 = ~PATTERN_1;
21
22 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
23 my_puts_P(PSTR("Bus timeout\n"));
24 return 0;
25 }
26
27 save_0 = z80_read(0);
28 z80_write(0, PATTERN_1);
29
30 for (addr=1; addr < CONFIG_SYS_RAMSIZE_MAX; addr <<= 1) {
31 save_addr = z80_read(addr);
32 z80_write(addr, PATTERN_2);
33 if (z80_read(0) != PATTERN_1 || z80_read(addr) != PATTERN_2)
34 break;
35 z80_write(addr, save_addr);
36 }
37 z80_write(0, save_0);
38 z80_bus_cmd(Release);
39
40 return addr;
41 }
42
43 typedef enum {
44 IHX_OK,
45 IHX_BROKEN,
46 IHX_CHKSUMERR
47 } ihx_rstat_t;
48
49 typedef struct {
50 ihx_rstat_t status;
51 int8_t type;
52 uint8_t len;
53 uint16_t address;
54 uint8_t data[256];
55 } ihex_t;
56
57
58 static
59 int get_hexdigit(void) {
60
61 int c;
62 c = toupper(my_getchar(1));
63 if (isxdigit(c)) {
64 c -= '0';
65 if (c > 9)
66 c -= ('A' - '0' - 10);
67 return c;
68 } else
69 return -1;
70 }
71
72 static
73 int get_hexbyte(void) {
74
75 uint8_t i,j;
76
77 if ((i = (uint8_t) get_hexdigit()) < 0x10)
78 if ((j = (uint8_t) get_hexdigit()) < 0x10) {
79 return (i<<4) + j;
80 }
81
82 return -1;
83 }
84
85
86 static
87 int ihex_get_record(ihex_t *rec) {
88
89 int c;
90 uint8_t sum;
91
92 rec->status = IHX_BROKEN;
93 rec->len = 0;
94 rec->type = 0xff;
95
96 while ((c = my_getchar(0)) != ':') {
97 if (c == 0x03)
98 return -1; /* Control-C */
99 if (c == 0x04) {
100 rec->status = IHX_OK;
101 return 0; /*Control-D, EOF */
102 }
103 }
104
105 if ((c = get_hexbyte()) < 0) /* Start code */
106 return -1;
107 sum = c;
108 rec->len = c;
109 if ((c = get_hexbyte()) < 0) /* Byte Count */
110 return -1;
111 sum += c;
112 rec->address = c * 256;
113 if ((c = get_hexbyte()) < 0) /* Address */
114 return -1;
115 sum += c;
116 rec->address += c;
117 if ((c = get_hexbyte()) < 0) /* Record type */
118 return -1;
119 sum += c;
120 rec->type = c;
121
122 if (rec->len) { /* Record Data */
123 uint8_t n;
124
125 for (n = 0; n < rec->len; n++) {
126 if ((c = get_hexbyte()) < 0)
127 break;
128 sum += c;
129 rec->data[n] = c;
130 }
131
132 if (n < rec->len) {
133 return -1;
134 }
135 }
136
137 c = get_hexbyte(); /* Check sum */
138
139 if (c >= 0) {
140 sum += c;
141 if (sum == 0)
142 rec->status = IHX_OK;
143 else
144 rec->status = IHX_CHKSUMERR;
145 }
146
147 return rec->len;
148 }
149
150
151 command_ret_t do_loadihex(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
152 {
153 long offset = 0;
154 uint32_t base_address = 0;
155 uint32_t address_max = detect_ramsize();
156 uint32_t address_high = 0;
157 uint32_t address_low = address_max;
158 command_ret_t rcode = CMD_RET_FAILURE;
159 ihex_t rec;
160 bool firstrec = true;
161
162 (void) cmdtp; (void) flag;
163
164
165 if (argc > 1)
166 offset = strtol(argv[1], NULL, 16);
167
168 printf_P(PSTR("Waiting for Intel Hex Records...\n"));
169
170 while (ihex_get_record(&rec) > 0 &&
171 rec.status == IHX_OK &&
172 rec.type != 1 ) {
173
174 switch (rec.type) {
175 case 0: /* Data record */
176 if (firstrec) {
177 printf_P(PSTR("Loading: 0x....."));
178 firstrec = false;
179 }
180 if (rec.len) {
181 uint32_t addr = base_address + rec.address + offset;
182 if (addr < address_low)
183 address_low = addr;
184 if (addr+rec.len > address_high)
185 address_high = addr + rec.len;
186
187 // debug("low: 0x%.5lX, high: 0x%.5lX, max: 0x%.5lX, addr: 0x%.5lX, len: %d\n",
188 // address_low, address_high, address_max, addr, rec.len);
189 printf_P(PSTR("\b\b\b\b\b%.5lX"), addr);
190 if (addr < address_max) {
191 uint32_t tmplen = address_max - addr;
192 if (rec.len > tmplen)
193 rec.len = tmplen;
194
195 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
196 my_puts_P(PSTR("Bus timeout\n"));
197 return CMD_RET_FAILURE;
198 }
199 z80_write_block(rec.data, /* src */
200 addr, /* dest */
201 rec.len); /* len */
202 z80_bus_cmd(Release);
203 }
204 }
205 break;
206
207 #if 0
208 case 1: /* EOF record */
209 break;
210 #endif
211 case 2: /* Extended Segment Address Record */
212 base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 4;
213 break;
214
215 case 4: /* Extended Linear Address Record */
216 base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16;
217 break;
218
219 case 3: /* Start Segment Address Record (ignored)*/
220 case 5: /* Start Linear Address Record (ignored)*/
221 break;
222
223 }
224 }
225
226 switch (rec.status) {
227 case IHX_OK:
228 rcode = CMD_RET_SUCCESS;
229 break;
230
231 case IHX_BROKEN:
232 case IHX_CHKSUMERR:
233 printf_P(PSTR("Broken Hex Record or loading interrupted!\n"));
234 break;
235 }
236
237
238 for (uint_fast8_t i=0; i<100; ++i) {
239 /* flush input buffer */
240 while (my_getchar(0) > 0)
241 ;
242 udelay(1000);
243 }
244
245
246 printf_P(PSTR("\nData loaded: "));
247 if (address_low >= MIN(address_high, address_max))
248 printf_P(PSTR("None.\n"));
249 else
250 printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low,
251 MIN(address_high, address_max) - 1);
252
253 if (address_high > address_max)
254 printf_P(PSTR("Data above highest RAM address "
255 "(in range 0x%.5lX - 0x%.5lX) ignored!\n"), address_max, address_high - 1);
256
257 return rcode;
258 }