Mercurial > hg > index.cgi
comparison lwasm/output.c @ 321:d4ac484d0ec6
Add support for Motorola SREC and Intel Hex output formats to lwasm.
Add support for creating SREC (--format=srec), Intel Hex (--format=ihex),
and a generic hexadecimal (--format=hex) output formats.
author | Tom LeMense <tlemense@yahoo.com> |
---|---|
date | Mon, 03 Mar 2014 21:30:38 -0700 |
parents | 2b784a28428e |
children | ade217fd76a5 |
comparison
equal
deleted
inserted
replaced
320:a640ff4ed95f | 321:d4ac484d0ec6 |
---|---|
33 void write_code_raw(asmstate_t *as, FILE *of); | 33 void write_code_raw(asmstate_t *as, FILE *of); |
34 void write_code_decb(asmstate_t *as, FILE *of); | 34 void write_code_decb(asmstate_t *as, FILE *of); |
35 void write_code_rawrel(asmstate_t *as, FILE *of); | 35 void write_code_rawrel(asmstate_t *as, FILE *of); |
36 void write_code_obj(asmstate_t *as, FILE *of); | 36 void write_code_obj(asmstate_t *as, FILE *of); |
37 void write_code_os9(asmstate_t *as, FILE *of); | 37 void write_code_os9(asmstate_t *as, FILE *of); |
38 void write_code_hex(asmstate_t *as, FILE *of); | |
39 void write_code_srec(asmstate_t *as, FILE *of); | |
40 void write_code_ihex(asmstate_t *as, FILE *of); | |
38 | 41 |
39 // this prevents warnings about not using the return value of fwrite() | 42 // this prevents warnings about not using the return value of fwrite() |
40 // r++ prevents the "set but not used" warnings; should be optimized out | 43 // r++ prevents the "set but not used" warnings; should be optimized out |
41 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0) | 44 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0) |
42 | 45 |
76 write_code_obj(as, of); | 79 write_code_obj(as, of); |
77 break; | 80 break; |
78 | 81 |
79 case OUTPUT_OS9: | 82 case OUTPUT_OS9: |
80 write_code_os9(as, of); | 83 write_code_os9(as, of); |
84 break; | |
85 | |
86 case OUTPUT_HEX: | |
87 write_code_hex(as, of); | |
88 break; | |
89 | |
90 case OUTPUT_SREC: | |
91 write_code_srec(as, of); | |
92 break; | |
93 | |
94 case OUTPUT_IHEX: | |
95 write_code_ihex(as, of); | |
81 break; | 96 break; |
82 | 97 |
83 default: | 98 default: |
84 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); | 99 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); |
85 fclose(of); | 100 fclose(of); |
217 outbuf[3] = (as -> execaddr >> 8) & 0xFF; | 232 outbuf[3] = (as -> execaddr >> 8) & 0xFF; |
218 outbuf[4] = (as -> execaddr) & 0xFF; | 233 outbuf[4] = (as -> execaddr) & 0xFF; |
219 writebytes(outbuf, 5, 1, of); | 234 writebytes(outbuf, 5, 1, of); |
220 } | 235 } |
221 | 236 |
237 int fetch_output_byte(line_t *cl, char *value, int *addr) | |
238 { | |
239 static int outidx = 0; | |
240 static int lastaddr = -2; | |
241 | |
242 // try to read next byte in current line's output field | |
243 if ((cl -> outputl > 0) && (outidx < cl -> outputl)) | |
244 { | |
245 *addr = lw_expr_intval(cl -> addr) + outidx; | |
246 *value = *(cl -> output + outidx++); | |
247 | |
248 // this byte follows the previous byte (contiguous, rc = 1) | |
249 if (*addr == lastaddr + 1) | |
250 { | |
251 lastaddr = *addr; | |
252 return 1; | |
253 } | |
254 | |
255 // this byte does not follow prev byte (disjoint, rc = -1) | |
256 else | |
257 { | |
258 lastaddr = *addr; | |
259 return -1; | |
260 } | |
261 } | |
262 | |
263 // no (more) output from this line (rc = 0) | |
264 else | |
265 { | |
266 outidx = 0; | |
267 return 0; | |
268 } | |
269 } | |
270 | |
271 | |
272 /* a simple ASCII hex file format */ | |
273 | |
274 void write_code_hex(asmstate_t *as, FILE *of) | |
275 { | |
276 const int RECLEN = 16; | |
277 | |
278 line_t *cl; | |
279 char outbyte; | |
280 int outaddr; | |
281 int rc; | |
282 | |
283 for (cl = as -> line_head; cl; cl = cl -> next) | |
284 do | |
285 { | |
286 rc = fetch_output_byte(cl, &outbyte, &outaddr); | |
287 | |
288 // if address jump or xxx0 address, start new line | |
289 if ((rc == -1) || ((rc == 1) && (outaddr % RECLEN == 0))) | |
290 { | |
291 fprintf(of, "\r\n%04X:", (unsigned int)outaddr); | |
292 fprintf(of, "%02X", (unsigned char)outbyte); | |
293 rc = -1; | |
294 } | |
295 if (rc == 1) | |
296 fprintf(of, ",%02X", (unsigned char)outbyte); | |
297 } | |
298 while (rc); | |
299 } | |
300 | |
301 | |
302 /* Motorola S19 hex file format */ | |
303 | |
304 void write_code_srec(asmstate_t *as, FILE *of) | |
305 { | |
306 const int SRECLEN = 16; | |
307 const int HDRLEN = 51; | |
308 | |
309 line_t *cl; | |
310 char outbyte; | |
311 int outaddr; | |
312 int rc; | |
313 int i; | |
314 int recaddr = 0; | |
315 int recdlen = 0; | |
316 unsigned char recdata[SRECLEN]; | |
317 int recsum; | |
318 int reccnt = -1; | |
319 char rechdr[HDRLEN]; | |
320 | |
321 for (cl = as -> line_head; cl; cl = cl -> next) | |
322 do | |
323 { | |
324 rc = fetch_output_byte(cl, &outbyte, &outaddr); | |
325 | |
326 // if address jump or xxx0 address, start new S1 record | |
327 if ((rc == -1) || ((rc == 1) && (outaddr % SRECLEN == 0))) | |
328 { | |
329 // if not already done so, emit an S0 header record | |
330 if (reccnt < 0) | |
331 { | |
332 // build header from version and filespec | |
333 // e.g. "[lwtools X.Y] filename.asm" | |
334 strcpy(rechdr, "["); | |
335 strcat(rechdr, PACKAGE_STRING); | |
336 strcat(rechdr, "] "); | |
337 i = strlen(rechdr); | |
338 strncat(rechdr, cl -> linespec, HDRLEN - 1 - i); | |
339 recsum = strlen(rechdr) + 3; | |
340 fprintf(of, "S0%02X0000", recsum); | |
341 for (i = 0; i < strlen(rechdr); i++) | |
342 { | |
343 fprintf(of, "%02X", (unsigned char)rechdr[i]); | |
344 recsum += (unsigned char)rechdr[i]; | |
345 } | |
346 fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); | |
347 reccnt = 0; | |
348 } | |
349 | |
350 // flush any current S1 record before starting new one | |
351 if (recdlen > 0) | |
352 { | |
353 recsum = recdlen + 3; | |
354 fprintf(of, "S1%02X%04X", recdlen + 3, recaddr); | |
355 for (i = 0; i < recdlen; i++) | |
356 { | |
357 fprintf(of, "%02X", (unsigned char)recdata[i]); | |
358 recsum += (unsigned char)recdata[i]; | |
359 } | |
360 recsum += (recaddr >> 8) & 0xFF; | |
361 recsum += recaddr & 0xFF; | |
362 fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); | |
363 reccnt += 1; | |
364 } | |
365 | |
366 // now start the new S1 record | |
367 recdlen = 0; | |
368 recaddr = outaddr; | |
369 rc = 1; | |
370 } | |
371 | |
372 // for each new byte read, add to recdata[] | |
373 if (rc == 1) | |
374 recdata[recdlen++] = outbyte; | |
375 } | |
376 while (rc); | |
377 | |
378 // done with all output lines, flush the final S1 record (if any) | |
379 if (recdlen > 0) | |
380 { | |
381 recsum = recdlen + 3; | |
382 fprintf(of, "S1%02X%04X", recdlen + 3, recaddr); | |
383 for (i = 0; i < recdlen; i++) | |
384 { | |
385 fprintf(of, "%02X", (unsigned char)recdata[i]); | |
386 recsum += (unsigned char)recdata[i]; | |
387 } | |
388 recsum += (recaddr >> 8) & 0xFF; | |
389 recsum += recaddr & 0xFF; | |
390 fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); | |
391 reccnt += 1; | |
392 } | |
393 | |
394 // if any S1 records were output, close with S5 and S9 records | |
395 if (reccnt > 0) | |
396 { | |
397 // emit S5 count record | |
398 recsum = 3; | |
399 recsum += (reccnt >> 8) & 0xFF; | |
400 recsum += reccnt & 0xFF; | |
401 fprintf(of, "S503%04X", (unsigned int)reccnt); | |
402 fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); | |
403 | |
404 // emit S9 end-of-file record | |
405 recsum = 3; | |
406 recsum += (as -> execaddr >> 8) & 0xFF; | |
407 recsum += (as -> execaddr) & 0xFF; | |
408 fprintf(of, "S903%04X", as -> execaddr); | |
409 fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); | |
410 } | |
411 } | |
412 | |
413 | |
414 /* Intel hex file format */ | |
415 | |
416 void write_code_ihex(asmstate_t *as, FILE *of) | |
417 { | |
418 const int IRECLEN = 16; | |
419 | |
420 line_t *cl; | |
421 char outbyte; | |
422 int outaddr; | |
423 int rc; | |
424 int i; | |
425 int recaddr = 0; | |
426 int recdlen = 0; | |
427 unsigned char recdata[IRECLEN]; | |
428 int recsum; | |
429 int reccnt = 0; | |
430 | |
431 for (cl = as -> line_head; cl; cl = cl -> next) | |
432 do | |
433 { | |
434 rc = fetch_output_byte(cl, &outbyte, &outaddr); | |
435 | |
436 // if address jump or xxx0 address, start new ihx record | |
437 if ((rc == -1) || ((rc == 1) && (outaddr % IRECLEN == 0))) | |
438 { | |
439 // flush any current ihex record before starting new one | |
440 if (recdlen > 0) | |
441 { | |
442 recsum = recdlen; | |
443 fprintf(of, ":%02X%04X00", recdlen, recaddr); | |
444 for (i = 0; i < recdlen; i++) | |
445 { | |
446 fprintf(of, "%02X", (unsigned char)recdata[i]); | |
447 recsum += (unsigned char)recdata[i]; | |
448 } | |
449 recsum += (recaddr >> 8) & 0xFF; | |
450 recsum += recaddr & 0xFF; | |
451 fprintf(of, "%02X\r\n", (unsigned char)(256 - recsum)); | |
452 reccnt += 1; | |
453 } | |
454 | |
455 // now start the new ihex record | |
456 recdlen = 0; | |
457 recaddr = outaddr; | |
458 rc = 1; | |
459 } | |
460 | |
461 // for each new byte read, add to recdata[] | |
462 if (rc == 1) | |
463 recdata[recdlen++] = outbyte; | |
464 } | |
465 while (rc); | |
466 | |
467 // done with all output lines, flush the final ihex record (if any) | |
468 if (recdlen > 0) | |
469 { | |
470 recsum = recdlen; | |
471 fprintf(of, ":%02X%04X00", recdlen, recaddr); | |
472 for (i = 0; i < recdlen; i++) | |
473 { | |
474 fprintf(of, "%02X", (unsigned char)recdata[i]); | |
475 recsum += (unsigned char)recdata[i]; | |
476 } | |
477 recsum += (recaddr >> 8) & 0xFF; | |
478 recsum += recaddr & 0xFF; | |
479 fprintf(of, "%02X\r\n", (unsigned char)(256 - recsum)); | |
480 reccnt += 1; | |
481 } | |
482 | |
483 // if any ihex records were output, close with a "01" record | |
484 if (reccnt > 0) | |
485 { | |
486 fprintf(of, ":00000001FF"); | |
487 } | |
488 } | |
489 | |
490 | |
222 void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) | 491 void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) |
223 { | 492 { |
224 if (s -> oblen >= s -> obsize) | 493 if (s -> oblen >= s -> obsize) |
225 { | 494 { |
226 s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128); | 495 s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128); |