1 //
2 // srecord - Manipulate EPROM load files
3 // Copyright (C) 2011, 2013 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <cassert>
20
21 #include <srecord/arglex/tool.h>
22 #include <srecord/input/file/ppx.h>
23 #include <srecord/record.h>
24
25
~input_file_ppx()26 srecord::input_file_ppx::~input_file_ppx()
27 {
28 }
29
30
input_file_ppx(const std::string & filename)31 srecord::input_file_ppx::input_file_ppx(const std::string &filename) :
32 input_file(filename),
33 state(0),
34 token(token_eof),
35 token_value(0),
36 address(0),
37 data_seen(false),
38 dsum(0),
39 buffer_length(0)
40 {
41 }
42
43
44 srecord::input_file_ppx::pointer
create(const std::string & filename)45 srecord::input_file_ppx::create(const std::string &filename)
46 {
47 return pointer(new input_file_ppx(filename));
48 }
49
50
51 void
get_next_token(void)52 srecord::input_file_ppx::get_next_token(void)
53 {
54 for (;;)
55 {
56 int sc = get_char();
57 if (sc < 0)
58 {
59 token = token_eof;
60 return;
61 }
62 unsigned char c = sc;
63 switch (c)
64 {
65 case '*':
66 token = token_star;
67 return;
68
69 case '$':
70 token = token_end;
71 return;
72
73 case 'S':
74 token = token_sum;
75 return;
76
77 case ' ':
78 case '\t':
79 case '\f':
80 case '\r':
81 case '\v':
82 case '\n':
83 break;
84
85 case '0': case '1': case '2': case '3': case '4':
86 case '5': case '6': case '7': case '8': case '9':
87 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
88 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
89 {
90 token_value = get_nibble_value(c);
91 int ndigits = 1;
92 for (;;)
93 {
94 int sc = get_char();
95 if (sc < 0)
96 break;
97 c = sc;
98 switch (c)
99 {
100 case '0': case '1': case '2': case '3': case '4':
101 case '5': case '6': case '7': case '8': case '9':
102 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
103 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
104 token_value = (token_value << 4) | get_nibble_value(c);
105 ++ndigits;
106 continue;
107
108 default:
109 get_char_undo(c);
110 break;
111 }
112 break;
113 }
114 if (ndigits > 2)
115 {
116 token = token_address;
117 return;
118 }
119 token = token_byte;
120 return;
121 }
122
123 default:
124 syntax_error();
125 break;
126 }
127 }
128 }
129
130
131 void
syntax_error(void)132 srecord::input_file_ppx::syntax_error(void)
133 {
134 fatal_error("syntax error");
135 }
136
137
138 bool
read(record & result)139 srecord::input_file_ppx::read(record &result)
140 {
141 //
142 // file
143 // : STAR lines end
144 // ;
145 // lines
146 // : line
147 // | lines line
148 // ;
149 // line
150 // : ADDRESS bytes
151 // ;
152 // bytes
153 // : BYTE
154 // | bytes BYTE
155 // ;
156 // end
157 // : END
158 // | END SUM ADDRESS
159 // ;
160 //
161 for (;;)
162 {
163 switch (state)
164 {
165 case 0:
166 get_next_token();
167 // file: . ASTERISK lines end;
168 switch (token)
169 {
170 case token_star:
171 get_next_token();
172 state = 1;
173 break;
174
175 default:
176 syntax_error();
177 }
178 break;
179
180 case 1:
181 // file: ASTERISK . lines end;
182 // file: ASTERISK lines . end;
183 // lines: . line
184 // lines: lines . line
185 // lines: lines line .
186 // line: . ADDRESS bytes
187 // end: . END
188 // end: . END SUM ADDRESS
189 switch (token)
190 {
191 case token_address:
192 if (address != token_value)
193 assert(buffer_length == 0);
194 address = token_value;
195 get_next_token();
196 state = 3;
197 break;
198
199 case token_end:
200 get_next_token();
201 state = 2;
202 break;
203
204 default:
205 syntax_error();
206 }
207 break;
208
209 case 2:
210 // end: END .
211 // end: END . SUM ADDRESS
212 switch (token)
213 {
214 case token_eof:
215 state = 5;
216 break;
217
218 case token_sum:
219 get_next_token();
220 state = 4;
221 break;
222
223 default:
224 syntax_error();
225 }
226 break;
227
228 case 3:
229 // line: ADDRESS . bytes
230 // line: ADDRESS bytes .
231 // bytes: . BYTE
232 // bytes: bytes . BYTE
233 // bytes: bytes BYTE .
234 switch (token)
235 {
236 case token_address:
237 case token_end:
238 state = 1;
239
240 if (buffer_length)
241 {
242 return_data_record:
243 result =
244 record
245 (
246 record::type_data,
247 address - buffer_length,
248 buffer,
249 buffer_length
250 );
251 buffer_length = 0;
252 return true;
253 }
254 break;
255
256 case token_byte:
257 dsum += token_value;
258 buffer[buffer_length++] = token_value;
259 ++address;
260 get_next_token();
261 data_seen = true;
262
263 if (buffer_length >= sizeof(buffer))
264 goto return_data_record;
265 break;
266
267 default:
268 syntax_error();
269 }
270 break;
271
272 case 4:
273 // end: END SUM . ADDRESS
274 switch (token)
275 {
276 case token_address:
277 if (use_checksums() && dsum != token_value)
278 {
279 fatal_error
280 (
281 "checksum mismatch (calculated 0x%04X, given 0x%04X)",
282 dsum,
283 token_value
284 );
285 }
286 get_next_token();
287 state = 5;
288 break;
289
290 default:
291 syntax_error();
292 }
293 break;
294
295 case 5:
296 // file: ASTERISK lines end .
297 switch (token)
298 {
299 case token_eof:
300 if (!data_seen)
301 fatal_error("no data seen");
302 return false;
303
304 default:
305 syntax_error();
306 }
307 break;
308 }
309 }
310 }
311
312
313 const char *
get_file_format_name(void) const314 srecord::input_file_ppx::get_file_format_name(void)
315 const
316 {
317 return "Stag Prom Programmer hexadecimal (PPX)";
318 }
319
320
321 int
format_option_number(void) const322 srecord::input_file_ppx::format_option_number(void)
323 const
324 {
325 return arglex_tool::token_ppx;
326 }
327
328
329 // vim: set ts=8 sw=4 et :
330