]>
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 | ||
18 | typedef enum { | |
19 | IHX_OK, | |
20 | IHX_BROKEN, | |
21 | IHX_CHKSUMERR | |
22 | } ihx_rstat_t; | |
23 | ||
24 | typedef struct { | |
25 | ihx_rstat_t status; | |
26 | int8_t type; | |
27 | uint8_t len; | |
28 | uint16_t address; | |
29 | uint8_t *data; | |
30 | } ihex_t; | |
31 | ||
32 | ||
33 | static | |
34 | int get_hexdigit(void) { | |
35 | ||
36 | int c; | |
37 | c = toupper(my_getchar(1)); | |
38 | if (isxdigit(c)) { | |
39 | c -= '0'; | |
40 | if (c > 9) | |
41 | c -= ('A' - '0' - 10); | |
42 | return c; | |
43 | } else | |
44 | return -1; | |
45 | } | |
46 | ||
47 | static | |
48 | int get_hexbyte(void) { | |
49 | ||
50 | uint8_t i,j; | |
51 | ||
52 | if ((i = (uint8_t) get_hexdigit()) < 0x10) | |
53 | if ((j = (uint8_t) get_hexdigit()) < 0x10) { | |
54 | return (i<<4) + j; | |
55 | } | |
56 | ||
57 | return -1; | |
58 | } | |
59 | ||
60 | static | |
61 | ihex_t ihex_get_record() { | |
62 | ||
63 | int i; | |
64 | uint8_t sum, c; | |
65 | ihex_t rec = { IHX_BROKEN, 0, 0, 0, 0 }; | |
66 | ||
67 | ||
68 | while ((c = my_getchar(0)) != ':') | |
69 | if (c == 0x03) | |
70 | return rec; | |
71 | ||
72 | if ((i = get_hexbyte()) < 0) /* Start code */ | |
73 | return rec; | |
74 | sum = i; | |
75 | rec.len = i; | |
76 | if ((i = get_hexbyte()) < 0) /* Byte Count */ | |
77 | return rec; | |
78 | sum += i; | |
79 | rec.address = i * 256; | |
80 | if ((i = get_hexbyte()) < 0) /* Address */ | |
81 | return rec; | |
82 | sum += i; | |
83 | rec.address += i; | |
84 | if ((i = get_hexbyte()) < 0) /* Record type */ | |
85 | return rec; | |
86 | sum += i; | |
87 | rec.type = i; | |
88 | ||
89 | if (rec.len) { /* Record Data */ | |
90 | uint8_t *p; int k; | |
91 | if ((rec.data = malloc(rec.len)) == 0) | |
92 | return rec; | |
ae017d4c | 93 | |
179bc609 L |
94 | for (p=rec.data, k=rec.len; k; k--) { |
95 | if ((i = get_hexbyte()) < 0) | |
96 | break; | |
97 | sum += i; | |
98 | *p++ = i; | |
99 | } | |
ae017d4c | 100 | |
179bc609 L |
101 | if (k) { |
102 | free(rec.data); rec.data = 0; | |
103 | return rec; | |
104 | } | |
105 | } | |
ae017d4c L |
106 | |
107 | i = get_hexbyte(); /* Check sum */ | |
108 | ||
109 | if (i >= 0) { | |
110 | sum += i; | |
111 | if (sum == 0) | |
112 | rec.status = IHX_OK; | |
113 | else | |
114 | rec.status = IHX_CHKSUMERR; | |
115 | } | |
116 | ||
117 | if (rec.status != IHX_OK) { | |
118 | free(rec.data); | |
119 | rec.data = 0; | |
120 | } | |
179bc609 L |
121 | |
122 | return rec; | |
123 | } | |
124 | ||
125 | ||
126 | command_ret_t do_loadihex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
127 | { | |
128 | long offset = 0; | |
129 | uint32_t base_address = 0; | |
130 | uint32_t address_low = 0xffffffff; | |
131 | uint32_t address_high = 0; | |
132 | bool done = false; | |
133 | command_ret_t rcode = CMD_RET_FAILURE; | |
134 | ihex_t rec; | |
135 | ||
136 | (void) cmdtp; | |
137 | (void) flag; | |
138 | ||
139 | if (argc > 1) | |
140 | offset = strtol(argv[1], NULL, 16); | |
141 | ||
142 | while (!done) { | |
143 | rec = ihex_get_record(); | |
144 | ||
145 | if (rec.status == IHX_OK) { | |
146 | switch (rec.type) { | |
147 | case 0: /* Data record */ | |
148 | if (rec.len) { | |
149 | uint32_t addr = base_address + rec.address + offset; | |
150 | if (addr < address_low) | |
151 | address_low = addr; | |
152 | if (addr+rec.len > address_high) | |
153 | address_high = addr + rec.len; | |
154 | ||
155 | z80_bus_cmd(Request); | |
156 | z80_write_block(rec.data, /* src */ | |
157 | addr, /* dest */ | |
158 | rec.len); /* len */ | |
159 | z80_bus_cmd(Release); | |
160 | } | |
161 | continue; | |
162 | break; | |
163 | ||
164 | case 1: /* EOF record */ | |
165 | ||
166 | done = true; | |
167 | break; | |
168 | ||
169 | case 2: /* Extended Segment Address Record */ | |
170 | base_address = ((rec.data[0] << 8) + rec.data[1]) << 4; | |
171 | continue; | |
172 | break; | |
173 | ||
174 | case 4: /* Extended Linear Address Record */ | |
175 | base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16; | |
176 | continue; | |
177 | break; | |
178 | ||
179 | case 3: /* Start Segment Address Record (ignored)*/ | |
180 | case 5: /* Start Linear Address Record (ignored)*/ | |
181 | continue; | |
182 | break; | |
183 | ||
184 | } | |
185 | ||
186 | } else | |
187 | done = true; | |
ae017d4c L |
188 | |
189 | free(rec.data); | |
190 | rec.data = 0; | |
191 | ||
179bc609 L |
192 | } |
193 | ||
194 | switch (rec.status) { | |
195 | case IHX_OK: | |
196 | rcode = CMD_RET_SUCCESS; | |
197 | break; | |
198 | ||
199 | case IHX_BROKEN: | |
200 | case IHX_CHKSUMERR: | |
201 | printf_P(PSTR("Broken Hex Record or loading interrupted!\n")); | |
202 | break; | |
203 | } | |
204 | ||
205 | printf_P(PSTR("Data loaded - ")); | |
206 | if (address_low >= address_high) | |
207 | printf_P(PSTR("None.\n")); | |
208 | else | |
209 | printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low, address_high); | |
210 | ||
211 | return rcode; | |
212 | } |