]>
Commit | Line | Data |
---|---|---|
179bc609 L |
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 | ||
5480dc65 L |
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 | static uint32_t min(uint32_t a, uint32_t b) | |
47 | { | |
48 | if (a < b) | |
49 | return a; | |
50 | return b; | |
51 | } | |
52 | ||
53 | ||
179bc609 L |
54 | typedef enum { |
55 | IHX_OK, | |
56 | IHX_BROKEN, | |
57 | IHX_CHKSUMERR | |
58 | } ihx_rstat_t; | |
59 | ||
60 | typedef struct { | |
61 | ihx_rstat_t status; | |
62 | int8_t type; | |
63 | uint8_t len; | |
64 | uint16_t address; | |
5480dc65 | 65 | uint8_t data[256]; |
179bc609 L |
66 | } ihex_t; |
67 | ||
68 | ||
69 | static | |
70 | int get_hexdigit(void) { | |
71 | ||
72 | int c; | |
73 | c = toupper(my_getchar(1)); | |
74 | if (isxdigit(c)) { | |
75 | c -= '0'; | |
76 | if (c > 9) | |
77 | c -= ('A' - '0' - 10); | |
78 | return c; | |
79 | } else | |
80 | return -1; | |
81 | } | |
82 | ||
83 | static | |
84 | int get_hexbyte(void) { | |
85 | ||
86 | uint8_t i,j; | |
87 | ||
88 | if ((i = (uint8_t) get_hexdigit()) < 0x10) | |
89 | if ((j = (uint8_t) get_hexdigit()) < 0x10) { | |
90 | return (i<<4) + j; | |
91 | } | |
92 | ||
93 | return -1; | |
94 | } | |
95 | ||
5480dc65 L |
96 | #if 0 |
97 | ||
179bc609 L |
98 | static |
99 | ihex_t ihex_get_record() { | |
100 | ||
101 | int i; | |
102 | uint8_t sum, c; | |
103 | ihex_t rec = { IHX_BROKEN, 0, 0, 0, 0 }; | |
104 | ||
105 | ||
106 | while ((c = my_getchar(0)) != ':') | |
107 | if (c == 0x03) | |
108 | return rec; | |
109 | ||
110 | if ((i = get_hexbyte()) < 0) /* Start code */ | |
111 | return rec; | |
112 | sum = i; | |
113 | rec.len = i; | |
114 | if ((i = get_hexbyte()) < 0) /* Byte Count */ | |
115 | return rec; | |
116 | sum += i; | |
117 | rec.address = i * 256; | |
118 | if ((i = get_hexbyte()) < 0) /* Address */ | |
119 | return rec; | |
120 | sum += i; | |
121 | rec.address += i; | |
122 | if ((i = get_hexbyte()) < 0) /* Record type */ | |
123 | return rec; | |
124 | sum += i; | |
125 | rec.type = i; | |
126 | ||
127 | if (rec.len) { /* Record Data */ | |
128 | uint8_t *p; int k; | |
129 | if ((rec.data = malloc(rec.len)) == 0) | |
130 | return rec; | |
ae017d4c | 131 | |
179bc609 L |
132 | for (p=rec.data, k=rec.len; k; k--) { |
133 | if ((i = get_hexbyte()) < 0) | |
134 | break; | |
135 | sum += i; | |
136 | *p++ = i; | |
137 | } | |
ae017d4c | 138 | |
179bc609 L |
139 | if (k) { |
140 | free(rec.data); rec.data = 0; | |
141 | return rec; | |
142 | } | |
143 | } | |
ae017d4c L |
144 | |
145 | i = get_hexbyte(); /* Check sum */ | |
146 | ||
147 | if (i >= 0) { | |
148 | sum += i; | |
149 | if (sum == 0) | |
150 | rec.status = IHX_OK; | |
151 | else | |
152 | rec.status = IHX_CHKSUMERR; | |
153 | } | |
154 | ||
155 | if (rec.status != IHX_OK) { | |
156 | free(rec.data); | |
157 | rec.data = 0; | |
158 | } | |
179bc609 L |
159 | |
160 | return rec; | |
161 | } | |
162 | ||
5480dc65 L |
163 | #else |
164 | ||
165 | static | |
166 | int ihex_get_record(ihex_t *rec) { | |
167 | ||
168 | int c; | |
169 | uint8_t sum; | |
170 | ||
171 | rec->status = IHX_BROKEN; | |
172 | ||
173 | ||
174 | while ((c = my_getchar(0)) != ':') | |
175 | if (c == 0x03) | |
176 | return -1; | |
177 | ||
178 | if ((c = get_hexbyte()) < 0) /* Start code */ | |
179 | return -1; | |
180 | sum = c; | |
181 | rec->len = c; | |
182 | if ((c = get_hexbyte()) < 0) /* Byte Count */ | |
183 | return -1; | |
184 | sum += c; | |
185 | rec->address = c * 256; | |
186 | if ((c = get_hexbyte()) < 0) /* Address */ | |
187 | return -1; | |
188 | sum += c; | |
189 | rec->address += c; | |
190 | if ((c = get_hexbyte()) < 0) /* Record type */ | |
191 | return -1; | |
192 | sum += c; | |
193 | rec->type = c; | |
194 | ||
195 | if (rec->len) { /* Record Data */ | |
196 | uint8_t n; | |
197 | ||
198 | for (n = 0; n < rec->len; n++) { | |
199 | if ((c = get_hexbyte()) < 0) | |
200 | break; | |
201 | sum += c; | |
202 | rec->data[n] = c; | |
203 | } | |
204 | ||
205 | if (n < rec->len) { | |
206 | return -1; | |
207 | } | |
208 | } | |
209 | ||
210 | c = get_hexbyte(); /* Check sum */ | |
211 | ||
212 | if (c >= 0) { | |
213 | sum += c; | |
214 | if (sum == 0) | |
215 | rec->status = IHX_OK; | |
216 | else | |
217 | rec->status = IHX_CHKSUMERR; | |
218 | } | |
219 | ||
220 | return rec->len; | |
221 | } | |
222 | ||
223 | #endif | |
179bc609 L |
224 | |
225 | command_ret_t do_loadihex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
226 | { | |
227 | long offset = 0; | |
228 | uint32_t base_address = 0; | |
5480dc65 | 229 | uint32_t address_max = detect_ramsize(); |
179bc609 | 230 | uint32_t address_high = 0; |
5480dc65 | 231 | uint32_t address_low = address_max; |
179bc609 L |
232 | command_ret_t rcode = CMD_RET_FAILURE; |
233 | ihex_t rec; | |
234 | ||
5480dc65 L |
235 | (void) cmdtp; (void) flag; |
236 | ||
237 | ||
238 | printf_P(PSTR("RAM Size: 0x%.5lX\n"), address_max); | |
239 | ||
179bc609 L |
240 | |
241 | if (argc > 1) | |
242 | offset = strtol(argv[1], NULL, 16); | |
243 | ||
5480dc65 L |
244 | while (ihex_get_record(&rec) > 0 && |
245 | rec.status == IHX_OK && | |
246 | rec.type != 1 ) { | |
247 | ||
248 | switch (rec.type) { | |
249 | case 0: /* Data record */ | |
250 | if (rec.len) { | |
251 | uint32_t addr = base_address + rec.address + offset; | |
252 | if (addr < address_low) | |
253 | address_low = addr; | |
254 | if (addr+rec.len > address_high) | |
255 | address_high = addr + rec.len; | |
179bc609 | 256 | |
179bc609 | 257 | |
5480dc65 L |
258 | printf_P(PSTR("low: 0x%.5lX, high: 0x%.5lX, max: 0x%.5lX, addr: 0x%.5lX, len: %d\n"), |
259 | address_low, address_high, address_max, addr, rec.len); | |
260 | ||
261 | if (addr < address_max) { | |
262 | uint32_t tmplen = address_max - addr; | |
263 | if (rec.len > tmplen) | |
264 | rec.len = tmplen; | |
265 | ||
266 | if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { | |
267 | my_puts_P(PSTR("Bus timeout\n")); | |
268 | return CMD_RET_FAILURE; | |
269 | } | |
179bc609 L |
270 | z80_write_block(rec.data, /* src */ |
271 | addr, /* dest */ | |
272 | rec.len); /* len */ | |
273 | z80_bus_cmd(Release); | |
274 | } | |
179bc609 | 275 | } |
5480dc65 | 276 | break; |
179bc609 | 277 | |
5480dc65 L |
278 | #if 0 |
279 | case 1: /* EOF record */ | |
280 | break; | |
281 | #endif | |
282 | case 2: /* Extended Segment Address Record */ | |
283 | base_address = ((rec.data[0] << 8) + rec.data[1]) << 4; | |
284 | break; | |
ae017d4c | 285 | |
5480dc65 L |
286 | case 4: /* Extended Linear Address Record */ |
287 | base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16; | |
288 | break; | |
ae017d4c | 289 | |
5480dc65 L |
290 | case 3: /* Start Segment Address Record (ignored)*/ |
291 | case 5: /* Start Linear Address Record (ignored)*/ | |
292 | break; | |
293 | ||
294 | } | |
179bc609 L |
295 | } |
296 | ||
297 | switch (rec.status) { | |
298 | case IHX_OK: | |
299 | rcode = CMD_RET_SUCCESS; | |
300 | break; | |
301 | ||
302 | case IHX_BROKEN: | |
303 | case IHX_CHKSUMERR: | |
304 | printf_P(PSTR("Broken Hex Record or loading interrupted!\n")); | |
305 | break; | |
306 | } | |
307 | ||
5480dc65 L |
308 | printf_P(PSTR("Data loaded: ")); |
309 | if (address_low >= min(address_high, address_max)) | |
179bc609 L |
310 | printf_P(PSTR("None.\n")); |
311 | else | |
5480dc65 L |
312 | printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low, |
313 | min(address_high, address_max) - 1); | |
314 | ||
315 | if (address_high > address_max) | |
316 | printf_P(PSTR("Data above highest RAM address " | |
317 | "(Range 0x%.5lX...0x%.5lX) ignored!\n"), address_max, address_high - 1); | |
179bc609 L |
318 | |
319 | return rcode; | |
320 | } |