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);