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