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