Mercurial > hg > index.cgi
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 } |