1 /* lkout.c */
2
3 /*
4 * Copyright (C) 1989-2009 Alan R. Baldwin
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
23 *
24 * With enhancements by
25 *
26 * G. Osborn
27 * gary@s-4.com.
28 */
29
30 #include "aslink.h"
31
32 /*)Module lkout.c
33 *
34 * The module lkout.c contains the dispatch
35 * function to create the relocated object
36 * code output in the required format.
37 *
38 * lkout.c contains the following functions:
39 * VOID lkout()
40 * VOID lkflush()
41 * VOID ixx()
42 * VOID iflush()
43 * VOID dbx()
44 * VOID dflush()
45 *
46 * lkout.c contains no local variables.
47 */
48
49 /*)Function lkout(i)
50 *
51 * int i 1 - process data
52 * 0 - end of data
53 *
54 * The function lkout() dispatches to the
55 * required output format routine.
56 *
57 * local variables:
58 * none
59 *
60 * global variables:
61 * int oflag output type flag
62 * int obj_flag Output enabled flag
63 * FILE * ofp output file handle
64 * a_uint pc Current relocation address
65 * int pcb Current pc bytes per address
66 *
67 * functions called:
68 * VOID ixx() lkout.c
69 * VOID s19() lks19.c
70 * VOID dbx() lkout.c
71 * VOID elf() lkelf.c
72 *
73 * side effects:
74 * The REL data is output in the required format.
75 */
76
77 VOID
lkout(int i)78 lkout(int i)
79 {
80 int j;
81
82 if (i && obj_flag) { return; }
83 if (ofp == NULL) { return; }
84
85 /*
86 * Create the Byte Output Address
87 */
88 for (j=1; j<pcb; j++) {
89 adb_xb(pc, 0);
90 }
91
92 /*
93 * Intel Formats
94 */
95 if (oflag == 1) {
96 ixx(i);
97 } else
98 /*
99 * Motorola Formats
100 */
101 if (oflag == 2) {
102 s19(i);
103 } else
104 /*
105 * Disk Basic Formats
106 */
107 if (oflag == 3) {
108 dbx(i);
109 } else
110 /*
111 * Elf Formats
112 */
113 if (oflag == 4) {
114 elf(i);
115 }
116 }
117
118
119 /*)Function lkflush()
120 *
121 * The function lkflush() dispatches
122 * to the required data flushing routine.
123 *
124 * local variables:
125 * none
126 *
127 * global variables:
128 * int oflag output type flag
129 * FILE * ofp output file handle
130 *
131 * functions called:
132 * VOID iflush() lkout.c
133 * VOID sflush() lks19.c
134 * VOID dflush() lkout.c
135 *
136 * side effects:
137 * Any remaining REL data is flushed
138 * to the output file.
139 */
140
141 VOID
lkflush()142 lkflush()
143 {
144 if (ofp == NULL) { return; }
145
146 /*
147 * Intel Formats
148 */
149 if (oflag == 1) {
150 iflush();
151 } else
152 /*
153 * Motorola Formats
154 */
155 if (oflag == 2) {
156 sflush();
157 } else
158 /*
159 * Disk Basic Formats
160 */
161 if (oflag == 3) {
162 dflush();
163 }
164 }
165
166
167 /*Intel Format
168 * Record Mark Field - This field signifies the start of a
169 * record, and consists of an ascii colon
170 * (:).
171 *
172 * Record Length Field - This field consists of two ascii
173 * characters which indicate the number of
174 * data bytes in this record. The
175 * characters are the result of converting
176 * the number of bytes in binary to two
177 * ascii characters, high digit first. An
178 * End of File record contains two ascii
179 * zeros in this field.
180 *
181 * Load Address Field - This field consists of the four ascii
182 * characters which result from converting
183 * the the binary value of the address in
184 * which to begin loading this record. The
185 * order is as follows:
186 *
187 * High digit of high byte of address.
188 * Low digit of high byte of address.
189 * High digit of low byte of address.
190 * Low digit of low byte of address.
191 *
192 * In an End of File record this field con-
193 * sists of four ascii zeros, in a start
194 * address record this is the program entry
195 * address (low), or in a segment record
196 * this is the high order address.
197 *
198 * Record Type Field - This field identifies the record type,
199 * which is either 0 for data records, 1
200 * for an End of File record, 3 for a
201 * start address, or 4 for a
202 * segment record. It consists
203 * of two ascii characters, with the high
204 * digit of the record type first, followed
205 * by the low digit of the record type.
206 *
207 * Data Field - This field consists of the actual data,
208 * converted to two ascii characters, high
209 * digit first. There are no data bytes in
210 * the End of File record.
211 *
212 * Checksum Field - The checksum field is the 8 bit binary
213 * sum of the record length field, the load
214 * address field, the record type field,
215 * and the data field. This sum is then
216 * negated (2's complement) and converted
217 * to two ascii characters, high digit
218 * first.
219 */
220
221 /*)Function ixx(i)
222 *
223 * int i 1 - process data
224 * 0 - end of data
225 *
226 * The function ixx() loads the output buffer with
227 * the relocated data.
228 *
229 * local variables:
230 * a_uint chksum byte checksum
231 * a_uint lo_addr address within segment
232 * a_uint hi_addr segment number
233 * int i loop counter
234 * a_uint j temporary
235 * int k loop counter
236 * struct sym *sp symbol pointer
237 * a_uint symadr symbol address
238 *
239 * global variables:
240 * int a_bytes T Line Address Bytes
241 * int hilo byte order
242 * FILE * ofp output file handle
243 * int rtaflg first output flag
244 * int rtcnt count of data words
245 * int rtflg[] output the data flag
246 * a_uint rtval[] relocated data
247 * char rtbuf[] output buffer
248 * a_uint rtadr0 address temporary
249 * a_uint rtadr1 address temporary
250 * a_uint rtadr2 address temporary
251 *
252 * functions called:
253 * int fprintf() c_library
254 * VOID iflush() lkout.c
255 *
256 * side effects:
257 * The data is placed into the output buffer.
258 */
259
260 /*
261 * The number of Data Field bytes is:
262 *
263 * 1 Record Mark Field
264 * 2 Record Length Field
265 * 4 Load Address Field
266 * 2 Record Type Field
267 * 2 Checksum Field
268 *
269 * Plus 32 data bytes (64 characters)
270 */
271
272 VOID
ixx(int i)273 ixx(int i)
274 {
275 int k;
276 struct sym *sp;
277 a_uint j, symadr, chksum;
278
279 if (i) {
280 if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
281 return;
282
283 if (hilo == 0) {
284 switch(a_bytes){
285 default:
286 case 2:
287 j = rtval[0];
288 rtval[0] = rtval[1];
289 rtval[1] = j;
290 break;
291 case 3:
292 j = rtval[0];
293 rtval[0] = rtval[2];
294 rtval[2] = j;
295 break;
296 case 4:
297 j = rtval[0];
298 rtval[0] = rtval[3];
299 rtval[3] = j;
300 j = rtval[2];
301 rtval[2] = rtval[1];
302 rtval[1] = j;
303 break;
304 }
305 }
306 for (i=0,rtadr2=0; i<a_bytes; i++) {
307 rtadr2 = (rtadr2 << 8) | rtval[i];
308 }
309 if ((rtadr2 != rtadr1) || rtaflg) {
310 /*
311 * data bytes not contiguous between records
312 */
313 iflush();
314 rtadr0 = rtadr1 = rtadr2;
315 rtaflg = 0;
316 }
317 for (k=a_bytes; k<rtcnt; k++) {
318 if (rtflg[k]) {
319 rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
320 if ((rtadr1 & 0xffff) == 0) {
321 iflush();
322 }
323 if (rtadr1 - rtadr0 == IXXMAXBYTES) {
324 iflush();
325 }
326 }
327 }
328 } else {
329 sp = lkpsym(".__.END.", 0);
330 if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
331 symadr = symval(sp);
332 chksum = 0x04;
333 chksum += 0x05;
334 chksum += symadr;
335 chksum += symadr >> 8;
336 chksum += symadr >> 16;
337 chksum += symadr >> 24;
338 #ifdef LONGINT
339 fprintf(ofp, ":04000005%08lX%02lX\n", symadr, (~chksum + 1) & 0x00ff);
340 #else
341 fprintf(ofp, ":04000005%08X%02X\n", symadr, (~chksum + 1) & 0x00ff);
342 #endif
343 }
344
345 fprintf(ofp, ":00000001FF\n");
346 }
347 }
348
349
350 /*)Function iflush()
351 *
352 * The function iflush() outputs the relocated data
353 * in the standard Intel format.
354 *
355 * local variables:
356 * a_uint chksum byte checksum
357 * a_uint lo_addr address within segment
358 * a_uint hi_addr segment number
359 * int i loop counter
360 * int max number of data bytes
361 * int reclen record length
362 *
363 * global variables:
364 * int a_bytes T Line Address Bytes
365 * FILE * ofp output file handle
366 * int rtaflg first output flag
367 * char rtbuf[] output buffer
368 * a_uint rtadr0 address temporary
369 * a_uint rtadr1 address temporary
370 *
371 * functions called:
372 * int fprintf() c_library
373 *
374 * side effects:
375 * The data is output to the file defined by ofp.
376 */
377
378 /*
379 * This function derived from the work
380 * of G. Osborn, gary@s-4.com.
381 * The new version concatenates the assembler
382 * output records when they represent contiguous
383 * memory segments to produce IXXMAXBYTES data byte
384 * Intel Hex output lines whenever possible, resulting
385 * in a substantial reduction in file size.
386 * More importantly, the download time
387 * to the target system is much improved.
388 */
389
390 VOID
iflush()391 iflush()
392 {
393 int i, max, reclen;
394 a_uint chksum, lo_addr, hi_addr;
395
396 max = (int) (rtadr1 - rtadr0);
397 if (max) {
398 if (a_bytes > 2) {
399 static a_uint prev_hi_addr = 0;
400
401 hi_addr = (rtadr0 >> 16) & 0xffff;
402 if ((hi_addr != prev_hi_addr) || rtaflg) {
403 chksum = 0x02;
404 chksum += 0x04;
405 chksum += hi_addr;
406 chksum += hi_addr >> 8;
407 #ifdef LONGINT
408 fprintf(ofp, ":02000004%04lX%02lX\n", hi_addr, (~chksum + 1) & 0x00ff);
409 #else
410 fprintf(ofp, ":02000004%04X%02X\n", hi_addr, (~chksum + 1) & 0x00ff);
411 #endif
412 prev_hi_addr = hi_addr;
413 }
414 }
415
416 /*
417 * Only the ":" and the checksum itself are excluded
418 * from the checksum. The record length includes
419 * only the data bytes.
420 */
421 lo_addr = rtadr0 & 0xffff;
422 reclen = max;
423 chksum = reclen;
424 chksum += lo_addr;
425 chksum += lo_addr >> 8;
426 #ifdef LONGINT
427 fprintf(ofp, ":%02X%04lX00", reclen, lo_addr);
428 #else
429 fprintf(ofp, ":%02X%04X00", reclen, lo_addr);
430 #endif
431 for (i=0; i<max; i++) {
432 chksum += rtbuf[i];
433 fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
434 }
435 /*
436 * 2's complement
437 */
438 #ifdef LONGINT
439 fprintf(ofp, "%02lX\n", (~chksum + 1) & 0x00ff);
440 #else
441 fprintf(ofp, "%02X\n", (~chksum + 1) & 0x00ff);
442 #endif
443 rtadr0 = rtadr1;
444 }
445
446 }
447
448 #if 0
449 /*)S19/S28/S37 Formats
450 * Record Type Field - This field signifies the start of a
451 * record and identifies the the record
452 * type as follows:
453 *
454 * 2-Byte Address: Ascii S1 - Data Record
455 * Ascii S9 - End of File Record
456 * 3-Byte Address: Ascii S2 - Data Record
457 * Ascii S8 - End of File Record
458 * 4-Byte Address: Ascii S3 - Data Record
459 * Ascii S7 - End of File Record
460 *
461 * Record Length Field - This field specifies the record length
462 * which includes the address, data, and
463 * checksum fields. The 8 bit record
464 * length value is converted to two ascii
465 * characters, high digit first.
466 *
467 * Load Address Field - This field consists of the 4/6/8 ascii
468 * characters which result from converting
469 * the the binary value of the address in
470 * which to begin loading this record. The
471 * order is as follows:
472 *
473 * S37: High digit of fourth byte of address.
474 * Low digit of fourth byte of address.
475 * S28/S37: High digit of third byte of address.
476 * Low digit of third byte of address.
477 * S19/S28/S37: High digit of high byte of address.
478 * Low digit of high byte of address.
479 * High digit of low byte of address.
480 * Low digit of low byte of address.
481 *
482 * In an End of File record this field con-
483 * sists of either 4/6/8 ascii zeros or the
484 * program entry address.
485 *
486 * Data Field - This field consists of the actual data,
487 * converted to two ascii characters, high
488 * digit first. There are no data bytes in
489 * the End of File record.
490 *
491 * Checksum Field - The checksum field is the 8 bit binary
492 * sum of the record length field, the load
493 * address field, and the data field. This
494 * sum is then complemented (1's comple-
495 * ment) and converted to two ascii
496 * characters, high digit first.
497 */
498
499 /*)Function sxx(i)
500 *
501 * int i 1 - process data
502 * 0 - end of data
503 *
504 * The function s19() loads the output buffer with
505 * the relocated data.
506 *
507 * local variables:
508 * a_uint addr address temporary
509 * a_uint chksum byte checksum
510 * char * frmt format string pointer
511 * int i loop counter
512 * a_uint j temporary
513 * int k loop counter
514 * int max number of data bytes
515 * int reclen record length
516 * struct sym *sp symbol pointer
517 * a_uint symadr symbol address
518 *
519 * global variables:
520 * int a_bytes T Line Address Bytes
521 * int hilo byte order
522 * FILE * ofp output file handle
523 * int rtcnt count of data words
524 * int rtflg[] output the data flag
525 * a_uint rtval[] relocated data
526 * char rtbuf[] output buffer
527 * a_uint rtadr0 address temporary
528 * a_uint rtadr1 address temporary
529 * a_uint rtadr2 address temporary
530 *
531 * functions called:
532 * int fprintf() c_library
533 * VOID sflush() lkout.c
534 *
535 * side effects:
536 * The data is placed into the output buffer.
537 */
538
539 /*
540 * Number of Data Field bytes is:
541 *
542 * 2 Record Type Field
543 * 2 Record Length Field
544 * 4/6/8 Load Address Field
545 * 2 Checksum Field
546 *
547 * Plus 32 data bytes (64 characters)
548 */
549
550 VOID
551 sxx(i)
552 int i;
553 {
554 struct sym *sp;
555 char *frmt;
556 int k, reclen;
557 a_uint j, addr, symadr, chksum;
558
559 if (i) {
560 if (hilo == 0) {
561 switch(a_bytes){
562 default:
563 case 2:
564 j = rtval[0];
565 rtval[0] = rtval[1];
566 rtval[1] = j;
567 break;
568 case 3:
569 j = rtval[0];
570 rtval[0] = rtval[2];
571 rtval[2] = j;
572 break;
573 case 4:
574 j = rtval[0];
575 rtval[0] = rtval[3];
576 rtval[3] = j;
577 j = rtval[2];
578 rtval[2] = rtval[1];
579 rtval[1] = j;
580 break;
581 }
582 }
583 for (i=0,rtadr2=0; i<a_bytes; i++) {
584 rtadr2 = (rtadr2 << 8) | rtval[i];
585 }
586
587 if (rtadr2 != rtadr1) {
588 /*
589 * data bytes not contiguous between records
590 */
591 sflush();
592 rtadr0 = rtadr1 = rtadr2;
593 }
594 for (k=a_bytes; k<rtcnt; k++) {
595 if (rtflg[k]) {
596 rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
597 if (rtadr1 - rtadr0 == SXXMAXBYTES) {
598 sflush();
599 }
600 }
601 }
602 } else {
603 /*
604 * Only the "S_" and the checksum itself are excluded
605 * from the checksum. The record length does not
606 * include "S_" and the pair count. It does
607 * include the address bytes, the data bytes,
608 * and the checksum.
609 */
610 reclen = 1 + a_bytes;
611 chksum = reclen;
612 sp = lkpsym(".__.END.", 0);
613 if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
614 symadr = symval(sp);
615 for (i=0,addr=symadr; i<a_bytes; i++,addr>>=8) {
616 chksum += addr;
617 }
618 } else {
619 symadr = 0;
620 }
621 #ifdef LONGINT
622 switch(a_bytes) {
623 default:
624 case 2: frmt = "S9%02X%04lX"; addr = symadr & 0x0000ffffl; break;
625 case 3: frmt = "S8%02X%06lX"; addr = symadr & 0x00ffffffl; break;
626 case 4: frmt = "S7%02X%08lX"; addr = symadr & 0xffffffffl; break;
627 }
628 #else
629 switch(a_bytes) {
630 default:
631 case 2: frmt = "S9%02X%04X"; addr = symadr & 0x0000ffff; break;
632 case 3: frmt = "S8%02X%06X"; addr = symadr & 0x00ffffff; break;
633 case 4: frmt = "S7%02X%08X"; addr = symadr & 0xffffffff; break;
634 }
635 #endif
636 fprintf(ofp, frmt, reclen, addr);
637 /*
638 * 1's complement
639 */
640 #ifdef LONGINT
641 fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
642 #else
643 fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
644 #endif
645 }
646 }
647
648
649 /*)Function sflush()
650 *
651 * The function sflush() outputs the relocated data
652 * in the standard Motorola format.
653 *
654 * local variables:
655 * a_uint addr address temporary
656 * a_uint chksum byte checksum
657 * char * frmt format string pointer
658 * int i loop counter
659 * int max number of data bytes
660 * int reclen record length
661 *
662 * global variables:
663 * int a_bytes T Line Address Bytes
664 * FILE * ofp output file handle
665 * char rtbuf[] output buffer
666 * a_uint rtadr0 address temporary
667 * a_uint rtadr1 address temporary
668 *
669 * functions called:
670 * int fprintf() c_library
671 *
672 * side effects:
673 * The data is output to the file defined by ofp.
674 */
675
676 /*
677 * Written by G. Osborn, gary@s-4.com, 6-17-98.
678 * The new version concatenates the assembler
679 * output records when they represent contiguous
680 * memory segments to produce SXXMAXBYTES data byte
681 * S_ output lines whenever possible, resulting
682 * in a substantial reduction in file size.
683 * More importantly, the download time
684 * to the target system is much improved.
685 */
686
687 VOID
688 sflush()
689 {
690 char *frmt;
691 int i, max, reclen;
692 a_uint addr, chksum;
693
694 max = (int) (rtadr1 - rtadr0);
695 if (max == 0) {
696 return;
697 }
698
699 /*
700 * Only the "S_" and the checksum itself are excluded
701 * from the checksum. The record length does not
702 * include "S_" and the pair count. It does
703 * include the address bytes, the data bytes,
704 * and the checksum.
705 */
706 reclen = max + 1 + a_bytes;
707 chksum = reclen;
708 for (i=0,addr=rtadr0; i<a_bytes; i++,addr>>=8) {
709 chksum += addr;
710 }
711 #ifdef LONGINT
712 switch(a_bytes) {
713 default:
714 case 2: frmt = "S1%02X%04lX"; addr = rtadr0 & 0x0000ffffl; break;
715 case 3: frmt = "S2%02X%06lX"; addr = rtadr0 & 0x00ffffffl; break;
716 case 4: frmt = "S3%02X%08lX"; addr = rtadr0 & 0xffffffffl; break;
717 }
718 #else
719 switch(a_bytes) {
720 default:
721 case 2: frmt = "S1%02X%04X"; addr = rtadr0 & 0x0000ffff; break;
722 case 3: frmt = "S2%02X%06X"; addr = rtadr0 & 0x00ffffff; break;
723 case 4: frmt = "S3%02X%08X"; addr = rtadr0 & 0xffffffff; break;
724 }
725 #endif
726 fprintf(ofp, frmt, reclen, addr);
727 for (i=0; i<max; i++) {
728 chksum += rtbuf[i];
729 fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
730 }
731 /*
732 * 1's complement
733 */
734 #ifdef LONGINT
735 fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
736 #else
737 fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
738 #endif
739 rtadr0 = rtadr1;
740 }
741 #endif
742
743 /*)Disk BASIC Format
744 *
745 * Each code segment starts with the following record:
746 *
747 * Record Preamble - This field is either $00 (for start of new
748 * record) or $FF (for last record in file).
749 *
750 * Record Length Field - This field specifies the record length
751 * that follows the Load Address Field.
752 *
753 * 16-Bit Length - 2-bytes
754 * 24-Bit Length - 3-bytes
755 * 32-Bit Length - 4-bytes
756 *
757 * Load Address Field - This field consists of the address where
758 * the record will be loaded into memory.
759 *
760 * 16-Bit Address - 2-bytes
761 * 24-Bit Address - 3-bytes
762 * 32-Bit Address - 4-bytes
763 *
764 * Binary Data Bytes - Record Length data bytes.
765 *
766 * After the last code segment, a final record like the one above is
767 * placed. In this final segment, the Record Preamble is $FF, the
768 * Record Length Field is $0000 and the Load Adress Field is the
769 * execution address.
770 */
771
772 /*)Function dbx(i)
773 *
774 * int i 1 - process data
775 * 0 - end of data
776 *
777 * The function decb() loads the output buffer with
778 * the relocated data.
779 *
780 * local variables:
781 * int k loop counter
782 * struct sym *sp symbol pointer
783 * a_uint symadr start address
784 *
785 * global variables:
786 * int a_bytes T Line Address Bytes
787 * FILE * ofp output file handle
788 * int rtcnt count of data words
789 * int rtflg[] output the data flag
790 * a_uint rtval[] relocated data
791 * char rtbuf[] output buffer
792 * a_uint rtadr0 address temporary
793 * a_uint rtadr1 address temporary
794 * a_uint rtadr2 address temporary
795 *
796 * functions called:
797 * int putc() c_library
798 * VOID dflush() lkout.c
799 *
800 * side effects:
801 * The data is placed into the output buffer.
802 */
803
804 VOID
dbx(i)805 dbx(i)
806 int i;
807 {
808 struct sym *sp;
809 int k;
810 a_uint j, symadr;
811
812 if (i) {
813 if (hilo == 0) {
814 switch(a_bytes){
815 default:
816 case 2:
817 j = rtval[0];
818 rtval[0] = rtval[1];
819 rtval[1] = j;
820 break;
821 case 3:
822 j = rtval[0];
823 rtval[0] = rtval[2];
824 rtval[2] = j;
825 break;
826 case 4:
827 j = rtval[0];
828 rtval[0] = rtval[3];
829 rtval[3] = j;
830 j = rtval[2];
831 rtval[2] = rtval[1];
832 rtval[1] = j;
833 break;
834 }
835 }
836 for (i=0,rtadr2=0; i<a_bytes; i++) {
837 rtadr2 = (rtadr2 << 8) | rtval[i];
838 }
839
840 if (rtadr2 != rtadr1) {
841 /*
842 * data bytes not contiguous between records
843 */
844 dflush();
845 rtadr0 = rtadr1 = rtadr2;
846 }
847 for (k=a_bytes; k<rtcnt; k++) {
848 if (rtflg[k]) {
849 rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
850 if (rtadr1 - rtadr0 == (unsigned) (DBXMAXBYTES - (2 * a_bytes) - 1)) {
851 dflush();
852 }
853 }
854 }
855 } else {
856 /* Disk BASIC BIN Trailer */
857 sp = lkpsym(".__.END.", 0);
858 if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
859 symadr = symval(sp);
860 } else {
861 symadr = 0;
862 }
863 /* Terminator */
864 putc(0xFF, ofp);
865
866 /* Size (0) */
867 switch(a_bytes) {
868 case 4: putc((int) (0 >> 24) & 0xFF, ofp);
869 case 3: putc((int) (0 >> 16) & 0xFF, ofp);
870 default:
871 case 2: putc((int) (0 >> 8) & 0xFF, ofp);
872 putc((int) (0 >> 0) & 0xFF, ofp);
873 break;
874 }
875
876 /* Starting Address */
877 switch(a_bytes) {
878 case 4: putc((int) (symadr >> 24) & 0xFF, ofp);
879 case 3: putc((int) (symadr >> 16) & 0xFF, ofp);
880 default:
881 case 2: putc((int) (symadr >> 8) & 0xFF, ofp);
882 putc((int) (symadr >> 0) & 0xFF, ofp);
883 break;
884 }
885 }
886 }
887
888
889 /*)Function dflush()
890 *
891 * The function dflush() outputs the relocated data
892 * in the Disk BASIC loadable format
893 *
894 * local variables:
895 * int i loop counter
896 * int max number of data bytes
897 *
898 * global variables:
899 * FILE * ofp output file handle
900 * char rtbuf[] output buffer
901 * a_uint rtadr0 address temporary
902 * a_uint rtadr1 address temporary
903 *
904 * functions called:
905 * int putc() c_library
906 *
907 * side effects:
908 * The data is output to the file defined by ofp.
909 */
910
911 /*
912 * Written by Boisy G. Pitre, boisy@boisypitre.com, 6-7-04
913 */
914
915 VOID
dflush()916 dflush()
917 {
918 int i, max;
919
920 max = (int) (rtadr1 - rtadr0);
921 if (max == 0) {
922 return;
923 }
924
925 /* Preamble Byte */
926 putc(0, ofp);
927
928 /* Record Size */
929 switch(a_bytes){
930 case 4: putc((int) (max >> 24) & 0xFF, ofp);
931 case 3: putc((int) (max >> 16) & 0xFF, ofp);
932 default:
933 case 2: putc((int) (max >> 8) & 0xFF, ofp);
934 putc((int) (max >> 0) & 0xFF, ofp);
935 break;
936 }
937
938 /* Load Address */
939 switch(a_bytes){
940 case 4: putc((int) (rtadr0 >> 24) & 0xFF, ofp);
941 case 3: putc((int) (rtadr0 >> 16) & 0xFF, ofp);
942 default:
943 case 2: putc((int) (rtadr0 >> 8) & 0xFF, ofp);
944 putc((int) (rtadr0 >> 0) & 0xFF, ofp);
945 break;
946 }
947
948 for (i = 0; i < max; i++) {
949 putc(rtbuf[i], ofp);
950 }
951
952 rtadr0 = rtadr1;
953 }
954