]>
Commit | Line | Data |
---|---|---|
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, int 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 | } |