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