comparison lwasm/output.c @ 543:e10618b48e68

Implement support for dragon format binaries Implement support for dragon format binaries. As an added bonus, also implement a variation on raw binaries which guarantees the whole binary fits in the file. These are the "dragon" and "abs" output formats. Based on code submitted by Mike Miller.
author William Astle <lost@l-w.ca>
date Thu, 29 Sep 2022 13:59:42 -0600
parents 33a59e232a5b
children e49d24f4a9a5
comparison
equal deleted inserted replaced
542:f3018ed5e30e 543:e10618b48e68
42 void write_code_os9(asmstate_t *as, FILE *of); 42 void write_code_os9(asmstate_t *as, FILE *of);
43 void write_code_hex(asmstate_t *as, FILE *of); 43 void write_code_hex(asmstate_t *as, FILE *of);
44 void write_code_srec(asmstate_t *as, FILE *of); 44 void write_code_srec(asmstate_t *as, FILE *of);
45 void write_code_ihex(asmstate_t *as, FILE *of); 45 void write_code_ihex(asmstate_t *as, FILE *of);
46 void write_code_lwmod(asmstate_t *as, FILE *of); 46 void write_code_lwmod(asmstate_t *as, FILE *of);
47 void write_code_dragon(asmstate_t *as, FILE *of);
48 void write_code_abs(asmstate_t *as, FILE *of);
47 49
48 // this prevents warnings about not using the return value of fwrite() 50 // this prevents warnings about not using the return value of fwrite()
49 // r++ prevents the "set but not used" warnings; should be optimized out 51 // r++ prevents the "set but not used" warnings; should be optimized out
50 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0) 52 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); r++; } while (0)
51 53
105 write_code_ihex(as, of); 107 write_code_ihex(as, of);
106 break; 108 break;
107 109
108 case OUTPUT_LWMOD: 110 case OUTPUT_LWMOD:
109 write_code_lwmod(as, of); 111 write_code_lwmod(as, of);
112 break;
113
114 case OUTPUT_DRAGON:
115 write_code_dragon(as, of);
116 break;
117
118 case OUTPUT_ABS:
119 write_code_abs(as, of);
110 break; 120 break;
111 121
112 default: 122 default:
113 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); 123 fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
114 fclose(of); 124 fclose(of);
1257 writebytes(reloccode, relocsize, 1, of); 1267 writebytes(reloccode, relocsize, 1, of);
1258 // init stuff 1268 // init stuff
1259 if (initsize) 1269 if (initsize)
1260 writebytes(initcode, initsize, 1, of); 1270 writebytes(initcode, initsize, 1, of);
1261 } 1271 }
1272
1273 void write_code_abs_calc(asmstate_t *as, unsigned int *start, unsigned int *length)
1274 {
1275 line_t *cl;
1276 unsigned int lowaddr = 65535;
1277 unsigned int highaddr = 0;
1278 char outbyte;
1279 int outaddr, rc;
1280
1281 // if not specified, calculate
1282 for (cl = as -> line_head; cl; cl = cl -> next)
1283 {
1284 do
1285 {
1286 rc = fetch_output_byte(cl, &outbyte, &outaddr);
1287 if (rc)
1288 {
1289 if (outaddr < lowaddr)
1290 lowaddr = outaddr;
1291 if (outaddr > highaddr)
1292 highaddr = outaddr;
1293 }
1294 }
1295 while (rc);
1296
1297 *length = (lowaddr > highaddr) ? 0 : 1 + highaddr - lowaddr;
1298 *start = (lowaddr > highaddr ) ? 0 : lowaddr;
1299 }
1300 }
1301
1302 void write_code_abs_aux(asmstate_t *as, FILE *of, unsigned int start, unsigned int header_size)
1303 {
1304 line_t *cl;
1305
1306 char outbyte;
1307 int outaddr, rc;
1308
1309 for (cl = as -> line_head; cl; cl = cl -> next)
1310 {
1311 do
1312 {
1313 rc = fetch_output_byte(cl, &outbyte, &outaddr);
1314
1315 // if first byte to write or output stream jumps address, seek
1316 if (rc == -1)
1317 {
1318 fseek(of,(long int) header_size + outaddr - start, SEEK_SET);
1319 }
1320 if (rc) fputc(outbyte,of);
1321 }
1322 while (rc);
1323 }
1324
1325 }
1326
1327 /* Write a DragonDOS binary file */
1328
1329 void write_code_dragon(asmstate_t *as, FILE *of)
1330 {
1331 unsigned char headerbuf[9];
1332 unsigned int start, length;
1333
1334 write_code_abs_calc(as, &start, &length);
1335
1336 headerbuf[0] = 0x55; // magic $55
1337 headerbuf[1] = 0x02; // binary file
1338 headerbuf[2] = (start >> 8) & 0xFF;
1339 headerbuf[3] = (start) & 0xFF;
1340 headerbuf[4] = (length >> 8) & 0xFF;
1341 headerbuf[5] = (length) & 0xFF;
1342 headerbuf[6] = (as -> execaddr >> 8) & 0xFF;
1343 headerbuf[7] = (as -> execaddr) & 0xFF;
1344 headerbuf[8] = 0xAA; // magic $AA
1345
1346 writebytes(headerbuf, 9, 1, of);
1347
1348 write_code_abs_aux(as, of, start, 9);
1349
1350 }
1351
1352 /* Write a monolithic binary block, respecting absolute address segments from ORG directives */
1353 /* Uses fseek, requires lowest code address and header offset size */
1354 /* Out of order ORG addresses are handled */
1355
1356 void write_code_abs(asmstate_t *as, FILE *of)
1357 {
1358 unsigned int start, length;
1359
1360 write_code_abs_calc(as, &start, &length);
1361 write_code_abs_aux(as, of, start, 0);
1362 }