6ffbae45e6f8188b40f348cb47c6bae2d64f170e
[fw/sdcc] / as / hc08 / asout.c
1 /* asout.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * 28-Oct-97 JLH: 
12  *           - outsym: show s_id as string rather than array [NCPS]
13  *           - Added outr11 to support 8051's 11 bit destination address
14  */
15
16 #include <stdio.h>
17 #include <setjmp.h>
18 #include <string.h>
19 #include "asm.h"
20
21
22 /*)Module       asout.c
23  *
24  *      The module asout.c contains all the functions used to
25  *      generate the .REL assembler output file.
26  *
27  *
28  *      The  assemblers' output object file is an ascii file containing
29  *      the information needed by the linker  to  bind  multiple  object
30  *      modules into a complete loadable memory image.  
31  *
32  *      The object module contains the following designators:  
33  *
34  *              [XDQ][HL]
35  *                      X        Hexadecimal radix
36  *                      D        Decimal radix
37  *                      Q        Octal radix
38  *      
39  *                      H        Most significant byte first
40  *                      L        Least significant byte first
41  *      
42  *              H        Header 
43  *              M        Module
44  *              A        Area
45  *              S        Symbol
46  *              T        Object code
47  *              R        Relocation information
48  *              P        Paging information
49  *
50  *
51  *      (1)     Radix Line
52  *
53  *      The  first  line  of  an object module contains the [XDQ][HL]
54  *      format specifier (i.e.  XH indicates  a  hexadecimal  file  with
55  *      most significant byte first) for the following designators.  
56  *
57  *
58  *      (2)     Header Line
59  *
60  *              H aa areas gg global symbols 
61  *
62  *      The  header  line  specifies  the number of areas(aa) and the
63  *      number of global symbols(gg) defined or referenced in  this  ob-
64  *      ject module segment.  
65  *
66  *
67  *      (3)     Module Line 
68  *
69  *              M name 
70  *
71  *      The  module  line  specifies  the module name from which this
72  *      header segment was assembled.  The module line will  not  appear
73  *      if the .module directive was not used in the source program.  
74  *
75  *
76  *      (4)     Symbol Line 
77  *
78  *              S string Defnnnn 
79  *
80  *                      or 
81  *
82  *              S string Refnnnn 
83  *
84  *      The  symbol line defines (Def) or references (Ref) the symbol
85  *      'string' with the value nnnn.  The defined value is relative  to
86  *      the  current area base address.  References to constants and ex-
87  *      ternal global symbols will always appear before the  first  area
88  *      definition.  References to external symbols will have a value of
89  *      zero.  
90  *
91  *
92  *      (5)     Area Line 
93  *
94  *              A label size ss flags ff 
95  *
96  *      The  area  line  defines the area label, the size (ss) of the
97  *      area in bytes, and the area flags (ff).  The area flags  specify
98  *      the ABS, REL, CON, OVR, and PAG parameters:  
99  *
100  *              OVR/CON (0x04/0x00 i.e.  bit position 2) 
101  *
102  *              ABS/REL (0x08/0x00 i.e.  bit position 3) 
103  *
104  *              PAG (0x10 i.e.  bit position 4) 
105  *
106  *
107  *      (6)     T Line 
108  *
109  *              T xx xx nn nn nn nn nn ...  
110  *
111  *      The  T  line contains the assembled code output by the assem-
112  *      bler with xx xx being the offset address from the  current  area
113  *      base address and nn being the assembled instructions and data in
114  *      byte format.  
115  *
116  *
117  *      (7)     R Line 
118  *
119  *              R 0 0 nn nn n1 n2 xx xx ...  
120  *
121  *      The R line provides the relocation information to the linker.
122  *      The nn nn value is the current area index, i.e.  which area  the
123  *      current  values  were  assembled.  Relocation information is en-
124  *      coded in groups of 4 bytes:  
125  *
126  *      1.  n1 is the relocation mode and object format 
127  *              1.  bit 0 word(0x00)/byte(0x01) 
128  *              2.  bit 1 relocatable area(0x00)/symbol(0x02) 
129  *              3.  bit 2 normal(0x00)/PC relative(0x04) relocation 
130  *              4.  bit  3  1-byte(0x00)/2-byte(0x08) object format for
131  *                  byte data 
132  *              5.  bit 4 signed(0x00)/unsigned(0x10) byte data 
133  *              6.  bit 5 normal(0x00)/page '0'(0x20) reference 
134  *              7.  bit 6 normal(0x00)/page 'nnn'(0x40) reference 
135  *              8.  bit 7 normal(0x00)/MSB of value
136  *
137  *      2.  n2  is  a byte index into the corresponding (i.e.  pre-
138  *              ceeding) T line data (i.e.  a pointer to the data to be
139  *              updated  by  the  relocation).   The T line data may be
140  *              1-byte or  2-byte  byte  data  format  or  2-byte  word
141  *              format.  
142  *
143  *      3.  xx xx  is the area/symbol index for the area/symbol be-
144  *              ing referenced.  the corresponding area/symbol is found
145  *              in the header area/symbol lists.  
146  *
147  *
148  *      The groups of 4 bytes are repeated for each item requiring relo-
149  *      cation in the preceeding T line.  
150  *
151  *
152  *      (8)     P Line 
153  *
154  *              P 0 0 nn nn n1 n2 xx xx 
155  *
156  *      The  P  line provides the paging information to the linker as
157  *      specified by a .setdp directive.  The format of  the  relocation
158  *      information is identical to that of the R line.  The correspond-
159  *      ing T line has the following information:  
160  *              T xx xx aa aa bb bb 
161  *
162  *      Where  aa aa is the area reference number which specifies the
163  *      selected page area and bb bb is the base address  of  the  page.
164  *      bb bb will require relocation processing if the 'n1 n2 xx xx' is
165  *      specified in the P line.  The linker will verify that  the  base
166  *      address is on a 256 byte boundary and that the page length of an
167  *      area defined with the PAG type is not larger than 256 bytes.  
168  *
169  *      The  linker  defaults any direct page references to the first
170  *      area defined in the input REL file.  All ASxxxx assemblers  will
171  *      specify the _CODE area first, making this the default page area. 
172  *
173  *
174  *      asout.c contains the following functions:
175  *              int     lobyte()
176  *              int     hibyte()
177  *              VOID    out()
178  *              VOID    outab()
179  *              VOID    outall()
180  *              VOID    outarea()
181  *              VOID    outaw()
182  *              VOID    outbuf()
183  *              VOID    outchk()
184  *              VOID    outdot()
185  *              VOID    outdp()
186  *              VOID    outgsd()
187  *              VOID    outrb()
188  *              VOID    outrw()
189  *              VOID    outsym()
190  *              VOID    out_lb()
191  *              VOID    out_lw()
192  *              VOID    out_rw()
193  *              VOID    out_tw()
194  *
195  *      The module asout.c contains the following local variables:
196  *              int     rel[]           relocation data for code/data array
197  *              int *   relp            pointer to rel array
198  *              int     txt[]           assembled code/data array
199  *              int *   txtp            pointer to txt array
200  */
201
202 #define  NTXT   16
203 #define  NREL   16
204
205 char     txt[NTXT];
206 char     rel[NREL];
207
208 char    *txtp = { &txt[0] };
209 char    *relp = { &rel[0] };
210
211 /*)Function     VOID    outab(b)
212  *
213  *              int     b               assembler data word
214  *
215  *      The function outab() processes a single word of
216  *      assembled data in absolute format.
217  *
218  *      local variables:
219  *              int *   txtp            pointer to data word
220  *
221  *      global variables:
222  *              int     oflag           -o, generate relocatable output flag
223  *              int     pass            assembler pass number
224  *
225  *      functions called:
226  *              VOID    outchk()        asout.c
227  *              VOID    out_lb()        asout.c
228  *
229  *      side effects:
230  *              The current assembly address is incremented by 1.
231  */
232
233 VOID
234 outab(int b)
235 {
236         if (pass == 2) {
237                 out_lb(b,0);
238                 if (oflag) {
239                         outchk(1, 0);
240                         *txtp++ = lobyte(b);
241                 }
242         }
243         ++dot.s_addr;
244 }
245
246 /*)Function     VOID    outaw(w)
247  *
248  *              int     w               assembler data word
249  *
250  *      The function outaw() processes a single word of
251  *      assembled data in absolute format.
252  *
253  *      local variables:
254  *              int *   txtp            pointer to data word
255  *
256  *      global variables:
257  *              int     oflag           -o, generate relocatable output flag
258  *              int     pass            assembler pass number
259  *
260  *      functions called:
261  *              VOID    outchk()        asout.c
262  *              VOID    out_lw()        asout.c
263  *
264  *      side effects:
265  *              The current assembly address is incremented by 2.
266  */
267
268 VOID
269 outaw(int w)
270 {
271         if (pass == 2) {
272                 out_lw(w,0);
273                 if (oflag) {
274                         outchk(2, 0);
275                         out_tw(w);
276                 }
277         }
278         dot.s_addr += 2;
279 }
280
281 /*)Function     VOID    write_rmode(r)
282  *
283  *              int     r               relocation mode
284  *
285  *      write_rmode puts the passed relocation mode into the 
286  *      output relp buffer, escaping it if necessary.
287  *
288  *      global variables:
289  *              int *   relp            pointer to rel array
290  *
291  *      functions called:
292  *              VOID    rerr()          assubr.c
293  *
294  *      side effects:
295  *              relp is incremented appropriately.
296  */
297 VOID
298 write_rmode(int r)
299 {
300     /* We need to escape the relocation mode if it is greater
301      * than a byte, or if it happens to look like an escape.
302      * (I don't think that the latter case is legal, but
303      * better safe than sorry).
304      */
305     if ((r > 0xff) || ((r & R_ESCAPE_MASK) == R_ESCAPE_MASK))
306     {
307         /* Hack in up to an extra 4 bits of flags with escape. */
308         if (r > 0xfff)
309         {
310              /* uh-oh.. we have more than 4 extra bits. */
311              fprintf(stderr, 
312                      "Internal error: relocation mode 0x%X too big.\n", 
313                      r);
314              rerr();
315         }
316         /* printf("escaping relocation mode\n"); */
317         *relp++ = R_ESCAPE_MASK | (r >> 8);
318         *relp++ = r & 0xff;
319     }
320     else
321     {
322         *relp++ = r;
323     }
324 }
325
326 /*)Function     VOID    outrb(esp, r)
327  *
328  *              expr *  esp             pointer to expr structure
329  *              int     r               relocation mode
330  *
331  *      The function outrb() processes a byte of generated code
332  *      in either absolute or relocatable format dependent upon
333  *      the data contained in the expr structure esp.  If the
334  *      .REL output is enabled then the appropriate information
335  *      is loaded into the txt and rel buffers.
336  *
337  *      local variables:
338  *              int     n               symbol/area reference number
339  *              int *   relp            pointer to rel array
340  *              int *   txtp            pointer to txt array
341  *
342  *      global variables:
343  *              sym     dot             defined as sym[0]
344  *              int     oflag           -o, generate relocatable output flag
345  *              int     pass            assembler pass number
346  *              
347  *      functions called:
348  *              VOID    aerr()          assubr.c
349  *              VOID    outchk()        asout.c
350  *              VOID    out_lb()        asout.c
351  *              VOID    out_rb()        asout.c
352  *              VOID    out_tb()        asout.c
353  *
354  *      side effects:
355  *              The current assembly address is incremented by 1.
356  */
357
358 VOID
359 outrb(struct expr *esp, int r)
360 {
361         register int n;
362
363         if (pass == 2) {
364                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
365                         /* This is a constant; simply write the
366                          * const byte to the T line and don't
367                          * generate any relocation info.
368                          */
369                         out_lb(lobyte(esp->e_addr),0);
370                         if (oflag) {
371                                 outchk(1, 0);
372                                 *txtp++ = lobyte(esp->e_addr);
373                         }
374                 } else {
375                         /* We are generating a single byte of relocatable
376                          * info.
377                          *
378                          * In 8051 mode, we generate a 16 bit address. The 
379                          * linker will later select a single byte based on
380                          * whether R_MSB is set.
381                          *
382                          * In flat24 mode, we generate a 24 bit address. The
383                          * linker will select a single byte based on 
384                          * whether R_MSB or R_HIB is set.
385                          */
386                         if (!flat24Mode)
387                         { 
388                             r |= R_BYTE | R_BYT2 | esp->e_rlcf;
389                             if (r & R_MSB) {
390                                 out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
391                             } else {
392                                 out_lb(lobyte(esp->e_addr),r|R_RELOC);
393                             }
394                             if (oflag) {
395                                 outchk(2, 5);
396                                 out_tw(esp->e_addr);
397                                 if (esp->e_flag) {
398                                         n = esp->e_base.e_sp->s_ref;
399                                         r |= R_SYM;
400                                 } else {
401                                         n = esp->e_base.e_ap->a_ref;
402                                 }
403                                 write_rmode(r);
404                                 *relp++ = txtp - txt - 2;
405                                 out_rw(n);
406                             }
407                         }
408                         else
409                         {
410                             /* 24 bit mode. */
411                             r |= R_BYTE | R_BYT3 | esp->e_rlcf;
412                             if (r & R_HIB)
413                             {
414                                 /* Probably should mark this differently in the
415                                  * listing file.
416                                  */
417                                 out_lb(byte3(esp->e_addr),r|R_RELOC|R_HIGH);
418                             }
419                             else if (r & R_MSB) {
420                                 out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
421                             } else {
422                                 out_lb(lobyte(esp->e_addr),r|R_RELOC);
423                             }
424                             if (oflag) {
425                                 outchk(3, 5);
426                                 out_t24(esp->e_addr);
427                                 if (esp->e_flag) {
428                                         n = esp->e_base.e_sp->s_ref;
429                                         r |= R_SYM;
430                                 } else {
431                                         n = esp->e_base.e_ap->a_ref;
432                                 }
433                                 write_rmode(r);
434                                 *relp++ = txtp - txt - 3;
435                                 out_rw(n);                          
436                             }
437                         }
438                 }
439         }
440         ++dot.s_addr;
441 }
442
443 /*)Function     VOID    outrw(esp, r)
444  *
445  *              expr *  esp             pointer to expr structure
446  *              int     r               relocation mode
447  *
448  *      The function outrw() processes a word of generated code
449  *      in either absolute or relocatable format dependent upon
450  *      the data contained in the expr structure esp.  If the
451  *      .REL output is enabled then the appropriate information
452  *      is loaded into the txt and rel buffers.
453  *
454  *      local variables:
455  *              int     n               symbol/area reference number
456  *              int *   relp            pointer to rel array
457  *              int *   txtp            pointer to txt array
458  *
459  *      global variables:
460  *              sym     dot             defined as sym[0]
461  *              int     oflag           -o, generate relocatable output flag
462  *              int     pass            assembler pass number
463  *              
464  *      functions called:
465  *              VOID    aerr()          assubr.c
466  *              VOID    outchk()        asout.c
467  *              VOID    out_lw()        asout.c
468  *              VOID    out_rw()        asout.c
469  *              VOID    out_tw()        asout.c
470  *
471  *      side effects:
472  *              The current assembly address is incremented by 2.
473  */
474
475 VOID
476 outrw(struct expr *esp, int r)
477 {
478         register int n;
479
480         if (pass == 2) {
481         
482                 if (esp->e_addr > 0xffff)
483                 {
484                     warnBanner();
485                     fprintf(stderr,
486                             "large constant 0x%x truncated to 16 bits\n",
487                             esp->e_addr);
488                 }
489                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
490                         out_lw(esp->e_addr,0);
491                         if (oflag) {
492                                 outchk(2, 0);
493                                 out_tw(esp->e_addr);
494                         }
495                 } else {
496                         r |= R_WORD | esp->e_rlcf;
497                         if (r & R_BYT2) {
498                                 rerr();
499                                 if (r & R_MSB) {
500                                         out_lw(hibyte(esp->e_addr),r|R_RELOC);
501                                 } else {
502                                         out_lw(lobyte(esp->e_addr),r|R_RELOC);
503                                 }
504                         } else {
505                                 out_lw(esp->e_addr,r|R_RELOC);
506                         }
507                         if (oflag) {
508                                 outchk(2, 5);
509                                 out_tw(esp->e_addr);
510                                 if (esp->e_flag) {
511                                         n = esp->e_base.e_sp->s_ref;
512                                         r |= R_SYM;
513                                 } else {
514                                         n = esp->e_base.e_ap->a_ref;
515                                 }
516                                 
517                                 if (IS_C24(r))
518                                 {
519                                     /* If this happens, the linker will
520                                      * attempt to process this 16 bit field
521                                      * as 24 bits. That would be bad.
522                                      */
523                                     fprintf(stderr,
524                                             "***Internal error: C24 out in "
525                                             "outrw()\n");
526                                     rerr();
527                                 }
528                                 write_rmode(r);
529                                 *relp++ = txtp - txt - 2;
530                                 out_rw(n);
531                         }
532                 }
533         }
534         dot.s_addr += 2;
535 }
536
537 /*)Function     VOID    outr24(esp, r)
538  *
539  *              expr *  esp             pointer to expr structure
540  *              int     r               relocation mode
541  *
542  *      The function outr24() processes 24 bits of generated code
543  *      in either absolute or relocatable format dependent upon
544  *      the data contained in the expr structure esp.  If the
545  *      .REL output is enabled then the appropriate information
546  *      is loaded into the txt and rel buffers.
547  *
548  *      local variables:
549  *              int     n               symbol/area reference number
550  *              int *   relp            pointer to rel array
551  *              int *   txtp            pointer to txt array
552  *
553  *      global variables:
554  *              sym     dot             defined as sym[0]
555  *              int     oflag           -o, generate relocatable output flag
556  *              int     pass            assembler pass number
557  *              
558  *      functions called:
559  *              VOID    aerr()          assubr.c
560  *              VOID    outchk()        asout.c
561  *              VOID    out_l24()       asout.c
562  *              VOID    out_rw()        asout.c
563  *              VOID    out_t24()       asout.c
564  *
565  *      side effects:
566  *              The current assembly address is incremented by 3.
567  */
568
569 VOID
570 outr24(struct expr *esp, int r)
571 {
572         register int n;
573
574         if (pass == 2) {
575                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
576                         /* This is a constant expression. */
577                         out_l24(esp->e_addr,0);
578                         if (oflag) {
579                                 outchk(3, 0);
580                                 out_t24(esp->e_addr);
581                         }
582                 } else {
583                         /* This is a symbol. */
584                         r |= R_WORD | esp->e_rlcf;
585                         if (r & R_BYT2) {
586                                 /* I have no idea what this case is. */
587                                 rerr();
588                                 if (r & R_MSB) {
589                                         out_lw(hibyte(esp->e_addr),r|R_RELOC);
590                                 } else {
591                                         out_lw(lobyte(esp->e_addr),r|R_RELOC);
592                                 }
593                         } else {
594                                 out_l24(esp->e_addr,r|R_RELOC);
595                         }
596                         if (oflag) {
597                                 outchk(3, 5);
598                                 out_t24(esp->e_addr);
599                                 if (esp->e_flag) {
600                                         n = esp->e_base.e_sp->s_ref;
601                                         r |= R_SYM;
602                                 } else {
603                                         n = esp->e_base.e_ap->a_ref;
604                                 }
605                                 
606                                 if (r & R_BYTE)
607                                 {
608                                     /* If this occurs, we cannot properly
609                                      * code the relocation data with the
610                                      * R_C24 flag. This means the linker
611                                      * will fail to do the 24 bit relocation.
612                                      * Which will suck.
613                                      */
614                                     fprintf(stderr,
615                                             "***Internal error: BYTE out in 24 "
616                                             "bit flat mode unexpected.\n");
617                                     rerr();
618                                 }
619                                 
620                                 write_rmode(r | R_C24);
621                                 *relp++ = txtp - txt - 3;
622                                 out_rw(n);
623                         }
624                 }
625         }
626         dot.s_addr += 3;
627 }
628
629 /*)Function     VOID    outdp(carea, esp)
630  *
631  *              area *  carea           pointer to current area strcuture
632  *              expr *  esp             pointer to expr structure
633  *
634  *      The function outdp() flushes the output buffer and
635  *      outputs paging information to the .REL file.
636  *
637  *      local variables:
638  *              int     n               symbol/area reference number
639  *              int     r               relocation mode
640  *              int *   relp            pointer to rel array
641  *              int *   txtp            pointer to txt array
642  *
643  *      global variables:
644  *              int     oflag           -o, generate relocatable output flag
645  *              int     pass            assembler pass number
646  *              
647  *      functions called:
648  *              VOID    outbuf()        asout.c
649  *              VOID    outchk()        asout.c
650  *              VOID    out_rw()        asout.c
651  *              VOID    out_tw()        asout.c
652  *
653  *      side effects:
654  *              Output buffer flushed to .REL fiel.
655  *              Paging information dumped to .REL file.
656  */
657
658 VOID
659 outdp(register struct area *carea, register struct expr *esp)
660 {
661         register int n, r;
662
663         if (oflag && pass==2) {
664                 outchk(HUGE,HUGE);
665                 out_tw(carea->a_ref);
666                 out_tw(esp->e_addr);
667                 if (esp->e_flag || esp->e_base.e_ap!=NULL) {
668                         r = R_WORD;
669                         if (esp->e_flag) {
670                                 n = esp->e_base.e_sp->s_ref;
671                                 r |= R_SYM;
672                         } else {
673                                 n = esp->e_base.e_ap->a_ref;
674                         }
675                         write_rmode(r);
676                         *relp++ = txtp - txt - 2;
677                         out_rw(n);
678                 }
679                 outbuf("P");
680         }
681 }
682
683 /*)Function     VOID    outall()
684  *
685  *      The function outall() will output any bufferred assembled
686  *      data and relocation information (during pass 2 if the .REL
687  *      output has been enabled).
688  *
689  *      local variables:
690  *              none
691  *
692  *      global variables:
693  *              int     oflag           -o, generate relocatable output flag
694  *              int     pass            assembler pass number
695  *
696  *      functions called:
697  *              VOID    outbuf()        asout.c
698  *
699  *      side effects:
700  *              assembled data and relocation buffers will be cleared.
701  */
702
703 VOID
704 outall(void)
705 {
706         if (oflag && pass==2)
707                 outbuf("R");
708 }
709
710 /*)Function     VOID    outdot()
711  *
712  *      The function outdot() outputs information about the
713  *      current program counter value (during pass 2 if the .REL
714  *      output has been enabled).
715  *
716  *      local variables:
717  *              none
718  *
719  *      global variables:
720  *              int     oflag           -o, generate relocatable output flag
721  *              int     pass            assembler pass number
722  *
723  *      functions called:
724  *              int     fprintf()       c_library
725  *              VOID    out()           asout.c
726  *
727  *      side effects:
728  *              assembled data and relocation buffers will be cleared.
729  */
730
731 VOID
732 outdot(void)
733 {
734         if (oflag && pass==2) {
735                 fprintf(ofp, "T");
736                 out(txt,(int) (txtp-txt));
737                 fprintf(ofp, "\n");
738                 fprintf(ofp, "R");
739                 out(rel,(int) (relp-rel));
740                 fprintf(ofp, "\n");
741                 txtp = txt;
742                 relp = rel;
743         }
744 }
745
746 /*)Function     outchk(nt, nr)
747  *
748  *              int     nr              number of additional relocation words
749  *              int     nt              number of additional data words
750  *
751  *      The function outchk() checks the data and relocation buffers
752  *      for space to insert the nt data words and nr relocation words.
753  *      If space is not available then output the current data and
754  *      initialize the data buffers to receive the new data.
755  *
756  *      local variables:
757  *              area *  ap              pointer to an area structure
758  *              int *   relp            pointer to rel array
759  *              int *   txtp            pointer to txt array
760  *
761  *      global variables:
762  *              sym     dot             defined as sym[0]
763  *
764  *      functions called:
765  *              VOID    outbuf()        asout.c
766  *
767  *      side effects:
768  *              Data and relocation buffers may be emptied and initialized.
769  */
770
771 VOID
772 outchk(int nt, int nr)
773 {
774         register struct area *ap;
775
776         if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) {
777                 outbuf("R");
778         }
779         if (txtp == txt) {
780                 out_tw(dot.s_addr);
781                 if ((ap = dot.s_area) != NULL) {
782                         write_rmode(R_WORD|R_AREA);
783                         *relp++ = 0;
784                         out_rw(ap->a_ref);
785                 }
786         }
787 }
788
789 /*)Function     VOID    outbuf()
790  *
791  *      The function outbuf() will output any bufferred data
792  *      and relocation information to the .REL file.  The output
793  *      buffer pointers and counters are initialized.
794  *
795  *      local variables:
796  *              int     rel[]           relocation data for code/data array
797  *              int *   relp            pointer to rel array
798  *              int     txt[]           assembled code/data array
799  *              int *   txtp            pointer to txt array
800  *
801  *      global variables:
802  *              FILE *  ofp             relocation output file handle
803  *
804  *      functions called:
805  *              VOID    out()           asout.c
806  *
807  *      side effects:
808  *              All bufferred data written to .REL file and
809  *              buffer pointers and counters initialized.
810  */
811
812 VOID
813 outbuf(char *s)
814 {
815         if (txtp > &txt[2]) {
816                 fprintf(ofp, "T");
817                 out(txt,(int) (txtp-txt));
818                 fprintf(ofp, "\n");
819                 fprintf(ofp, "%s", s);
820                 out(rel,(int) (relp-rel));
821                 fprintf(ofp, "\n");
822         }
823         txtp = txt;
824         relp = rel;
825 }
826
827 /*)Function     VOID    outgsd()
828  *
829  *      The function outgsd() performs the following:
830  *      (1)     outputs the .REL file radix
831  *      (2)     outputs the header specifying the number
832  *              of areas and global symbols
833  *      (3)     outputs the module name
834  *      (4)     set the reference number and output a symbol line
835  *              for all external global variables and absolutes
836  *      (5)     output an area name, set reference number and output
837  *              a symbol line for all global relocatables in the area.
838  *              Repeat this proceedure for all areas.
839  *
840  *      local variables:
841  *              area *  ap              pointer to an area structure
842  *              sym *   sp              pointer to a sym structure
843  *              int     i               loop counter
844  *              int     j               loop counter
845  *              int     c               string character value
846  *              int     narea           number of code areas
847  *              char *  ptr             string pointer
848  *              int     nglob           number of global symbols
849  *              int     rn              symbol reference number
850  *
851  *      global variables:
852  *              area *  areap           pointer to an area structure
853  *              char    module[]        module name string
854  *              sym * symhash[]         array of pointers to NHASH
855  *                                      linked symbol lists
856  *              int     xflag           -x, listing radix flag
857  *
858  *      functions called:
859  *              int     fprintf()       c_library
860  *              VOID    outarea()       asout.c
861  *              VOID    outsym()        asout.c
862  *              int     putc()          c_library
863  *
864  *      side effects:
865  *              All symbols are given reference numbers, all symbol
866  *              and area information is output to the .REL file.
867  */
868
869 VOID
870 outgsd(void)
871 {
872         register struct area *ap;
873         register struct sym  *sp;
874         register int i, j;
875         char *ptr;
876         int c, narea, nglob, rn;
877
878         /*
879          * Number of areas
880          */
881         narea = areap->a_ref + 1;
882
883         /*
884          * Number of global references/absolutes
885          */
886         nglob = 0;
887         for (i = 0; i < NHASH; ++i) {
888                 sp = symhash[i];
889                 while (sp) {
890                         if (sp->s_flag&S_GBL)
891                                 ++nglob;
892                         sp = sp->s_sp;
893                 }
894         }
895
896         /*
897          * Output Radix and number of areas and symbols
898          */
899         if (xflag == 0) {
900                 fprintf(ofp, "X%c\n", hilo ? 'H' : 'L');
901                 fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob);
902         } else
903         if (xflag == 1) {
904                 fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L');
905                 fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob);
906         } else
907         if (xflag == 2) {
908                 fprintf(ofp, "D%c\n", hilo ? 'H' : 'L');
909                 fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob);
910         }               
911
912         /*
913          * Module name
914          */
915         if (module[0]) {
916                 fprintf(ofp, "M ");
917                 ptr = &module[0];
918                 while (ptr < &module[NCPS]) {
919                         if ((c = *ptr++) != 0)
920                                 putc(c, ofp);
921                 }
922                 putc('\n', ofp);
923         }
924
925     /*
926      * Sdcc compile options
927      */
928         if (strlen(optsdcc)) fprintf(ofp, "O %s\n", optsdcc);
929
930         /*
931          * Global references and absolutes.
932          */
933         rn = 0;
934         for (i=0; i<NHASH; ++i) {
935                 sp = symhash[i];
936                 while (sp) {
937                         if (sp->s_area==NULL && sp->s_flag&S_GBL) {
938                                 sp->s_ref = rn++;
939                                 outsym(sp);
940                         }
941                         sp = sp->s_sp;
942                 }
943         }
944
945         /*
946          * Global relocatables.
947          */
948         for (i=0; i<narea; ++i) {
949                 ap = areap;
950                 while (ap->a_ref != i)
951                         ap = ap->a_ap;
952                 outarea(ap);
953                 for (j=0; j<NHASH; ++j) {
954                         sp = symhash[j];
955                         while (sp) {
956                                 if (sp->s_area==ap && sp->s_flag&S_GBL) {
957                                         sp->s_ref = rn++;
958                                         outsym(sp);
959                                 }
960                                 sp = sp->s_sp;
961                         }
962                 }
963         }
964 }
965
966 /*)Function     VOID    outarea(ap)
967  *
968  *              area *  ap              pointer to an area structure
969  *
970  *      The function outarea()  outputs the A line to the .REL
971  *      file.  The A line contains the area's name, size, and
972  *      attributes.
973  *
974  *      local variables:
975  *              char *  ptr             pointer to area id string
976  *              int     c               character value
977  *
978  *      global variables:
979  *              FILE *  ofp             relocation output file handle
980  *              int     xflag           -x, listing radix flag
981  *
982  *      functions called:
983  *              int     fprintf()       c_library
984  *              int     putc()          c_library
985  *
986  *      side effects:
987  *              The A line is sent to the .REL file.
988  */
989
990 VOID
991 outarea(register struct area *ap)
992 {
993         register char *ptr;
994         register int c;
995
996         fprintf(ofp, "A ");
997         ptr = &ap->a_id[0];
998         while (ptr < &ap->a_id[NCPS]) {
999                 if ((c = *ptr++) != 0)
1000                         putc(c, ofp);
1001         }
1002         if (xflag == 0) {
1003                 fprintf(ofp, " size %X flags %X addr %X\n", ap->a_size, ap->a_flag, ap->a_addr);
1004         } else
1005         if (xflag == 1) {
1006                 fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag);
1007         } else
1008         if (xflag == 2) {
1009                 fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag);
1010         }
1011 }
1012
1013 /*)Function     VOID    outsym(sp)
1014  *
1015  *              sym *   sp              pointer to a sym structure
1016  *
1017  *      The function outsym() outputs the S line to the .REL
1018  *      file.  The S line contains the symbols name and whether the
1019  *      the symbol is defined or referenced.
1020  *
1021  *      local variables:
1022  *              char *  ptr             pointer to symbol id string
1023  *              int     c               character value
1024  *
1025  *      global variables:
1026  *              FILE *  ofp             relocation output file handle
1027  *              int     xflag           -x, listing radix flag
1028  *
1029  *      functions called:
1030  *              int     fprintf()       c_library
1031  *              int     putc()          c_library
1032  *
1033  *      side effects:
1034  *              The S line is sent to the .REL file.
1035  */
1036
1037 VOID
1038 outsym(register struct sym *sp)
1039 {
1040         register char *ptr;       
1041
1042         fprintf(ofp, "S ");
1043         ptr = &sp->s_id[0];
1044         fprintf(ofp, "%s", ptr );
1045         fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def");
1046         if (xflag == 0) {
1047                 fprintf(ofp, "%04X\n", sp->s_addr);
1048         } else
1049         if (xflag == 1) {
1050                 fprintf(ofp, "%06o\n", sp->s_addr);
1051         } else
1052         if (xflag == 2) {
1053                 fprintf(ofp, "%05u\n", sp->s_addr);
1054         }
1055 }
1056
1057 /*)Function     VOID    out(p, n)
1058  *
1059  *              int     n               number of words to output
1060  *              int *   p               pointer to data words
1061  *
1062  *      The function out() outputs the data words to the .REL file
1063  *      int the specified radix.
1064  *
1065  *      local variables:
1066  *              none
1067  *
1068  *      global variables:
1069  *              FILE *  ofp             relocation output file handle
1070  *              int     xflag           -x, listing radix flag
1071  *
1072  *      functions called:
1073  *              int     fprintf()       c_library
1074  *
1075  *      side effects:
1076  *              Data is sent to the .REL file.
1077  */
1078
1079 VOID
1080 out(char *p, int n)
1081 {
1082         while (n--) {
1083                 if (xflag == 0) {
1084                         fprintf(ofp, " %02X", (*p++)&0xff);
1085                 } else
1086                 if (xflag == 1) {
1087                         fprintf(ofp, " %03o", (*p++)&0xff);
1088                 } else
1089                 if (xflag == 2) {
1090                         fprintf(ofp, " %03u", (*p++)&0xff);
1091                 }
1092         }
1093 }
1094
1095 /*)Function     VOID    out_lb(b, t)
1096  *
1097  *              int     b               assembled data
1098  *              int     t               relocation type
1099  *
1100  *      The function out_lb() copies the assembled data and
1101  *      its relocation type to the list data buffers.
1102  *
1103  *      local variables:
1104  *              none
1105  *
1106  *      global variables:
1107  *              int *   cp              pointer to assembler output array cb[]
1108  *              int *   cpt             pointer to assembler relocation type
1109  *                                      output array cbt[]
1110  *
1111  *      functions called:
1112  *              none
1113  *
1114  *      side effects:
1115  *              Pointers to data and relocation buffers incremented by 1.
1116  */
1117
1118 VOID
1119 out_lb(register int b, register int t)
1120 {
1121         if (cp < &cb[NCODE]) {
1122                 *cp++ = b;
1123                 *cpt++ = t;
1124         }
1125 }
1126
1127 /*)Function     VOID    out_lw(n, t)
1128  *
1129  *              int     n               assembled data
1130  *              int     t               relocation type
1131  *
1132  *      The function out_lw() copies the assembled data and
1133  *      its relocation type to the list data buffers.
1134  *
1135  *      local variables:
1136  *              none
1137  *
1138  *      global variables:
1139  *              int *   cp              pointer to assembler output array cb[]
1140  *              int *   cpt             pointer to assembler relocation type
1141  *                                      output array cbt[]
1142  *
1143  *      functions called:
1144  *              none
1145  *
1146  *      side effects:
1147  *              Pointers to data and relocation buffers incremented by 2.
1148  */
1149
1150 VOID
1151 out_lw(register int n, register int t)
1152 {
1153         if (hilo) {
1154                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1155                 out_lb(lobyte(n),t);
1156         } else {
1157                 out_lb(lobyte(n),t);
1158                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1159         }
1160 }
1161
1162 /*)Function     VOID    out_l24(n, t)
1163  *
1164  *              int     n               assembled data
1165  *              int     t               relocation type
1166  *
1167  *      The function out_l24() copies the assembled data and
1168  *      its relocation type to the list data buffers.
1169  *
1170  *      local variables:
1171  *              none
1172  *
1173  *      global variables:
1174  *              int *   cp              pointer to assembler output array cb[]
1175  *              int *   cpt             pointer to assembler relocation type
1176  *                                      output array cbt[]
1177  *
1178  *      functions called:
1179  *              none
1180  *
1181  *      side effects:
1182  *              Pointers to data and relocation buffers incremented by 3.
1183  */
1184
1185 VOID
1186 out_l24(int n, int t)
1187 {
1188         if (hilo) {
1189                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1190                 out_lb(hibyte(n),t);
1191                 out_lb(lobyte(n),t);
1192         } else {
1193                 out_lb(lobyte(n),t);
1194                 out_lb(hibyte(n),t);
1195                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1196         }
1197 }
1198
1199 /*)Function     VOID    out_rw(n)
1200  *
1201  *              int     n               data word
1202  *
1203  *      The function out_rw() outputs the relocation (R)
1204  *      data word as two bytes ordered according to hilo.
1205  *
1206  *      local variables:
1207  *              int *   relp            pointer to rel array
1208  *
1209  *      global variables:
1210  *              none
1211  *
1212  *      functions called:
1213  *              int     lobyte()        asout.c
1214  *              int     hibyte()        asout.c
1215  *
1216  *      side effects:
1217  *              Pointer to relocation buffer incremented by 2.
1218  */
1219
1220 VOID
1221 out_rw(register int n)
1222 {
1223         if (hilo) {
1224                 *relp++ = hibyte(n);
1225                 *relp++ = lobyte(n);
1226         } else {
1227                 *relp++ = lobyte(n);
1228                 *relp++ = hibyte(n);
1229         }
1230 }
1231
1232 /*)Function     VOID    out_tw(n)
1233  *
1234  *              int     n               data word
1235  *
1236  *      The function out_tw() outputs the text (T)
1237  *      data word as two bytes ordered according to hilo.
1238  *
1239  *      local variables:
1240  *              int *   txtp            pointer to txt array
1241  *
1242  *      global variables:
1243  *              none
1244  *
1245  *      functions called:
1246  *              int     lobyte()        asout.c
1247  *              int     hibyte()        asout.c
1248  *
1249  *      side effects:
1250  *              Pointer to relocation buffer incremented by 2.
1251  */
1252
1253 VOID
1254 out_tw(register int n)
1255 {
1256         if (hilo) {
1257                 *txtp++ = hibyte(n);
1258                 *txtp++ = lobyte(n);
1259         } else {
1260                 *txtp++ = lobyte(n);
1261                 *txtp++ = hibyte(n);
1262         }
1263 }
1264
1265 /*)Function     VOID    out_t24(n)
1266  *
1267  *              int     n               data word
1268  *
1269  *      The function out_t24() outputs the text (T)
1270  *      data word as three bytes ordered according to hilo.
1271  *
1272  *      local variables:
1273  *              int *   txtp            pointer to txt array
1274  *
1275  *      global variables:
1276  *              none
1277  *
1278  *      functions called:
1279  *              int     lobyte()        asout.c
1280  *              int     hibyte()        asout.c
1281  *
1282  *      side effects:
1283  *              Pointer to relocation buffer incremented by 3.
1284  */
1285
1286 VOID
1287 out_t24(int n)
1288 {
1289         if (hilo) {
1290                 *txtp++ = byte3(n);
1291                 *txtp++ = hibyte(n);
1292                 *txtp++ = lobyte(n);
1293         } else {
1294                 *txtp++ = lobyte(n);
1295                 *txtp++ = hibyte(n);
1296                 *txtp++ = byte3(n);
1297         }
1298 }
1299
1300 /*)Function     int     lobyte(n)
1301  *
1302  *              int     n               data word
1303  *
1304  *      The function lobyte() returns the lower byte of
1305  *      integer n.
1306  *
1307  *      local variables:
1308  *              none
1309  *
1310  *      global variables:
1311  *              none
1312  *
1313  *      functions called:
1314  *              none
1315  *
1316  *      side effects:
1317  *              none
1318  */
1319
1320 int
1321 lobyte(int n)
1322 {
1323         return (n&0377);
1324 }
1325
1326 /*)Function     int     hibyte(n)
1327  *
1328  *              int     n               data word
1329  *
1330  *      The function hibyte() returns the higher byte of
1331  *      integer n.
1332  *
1333  *      local variables:
1334  *              none
1335  *
1336  *      global variables:
1337  *              none
1338  *
1339  *      functions called:
1340  *              none
1341  *
1342  *      side effects:
1343  *              none
1344  */
1345
1346 int
1347 hibyte(int n)
1348 {
1349         return ((n>>8)&0377);
1350 }
1351
1352 /*)Function     int     byte3(n)
1353  *
1354  *              int     n               24 bit data
1355  *
1356  *      The function byte3() returns the MSB of the
1357  *      24 bit integer n.
1358  *
1359  *      local variables:
1360  *              none
1361  *
1362  *      global variables:
1363  *              none
1364  *
1365  *      functions called:
1366  *              none
1367  *
1368  *      side effects:
1369  *              none
1370  */
1371 int
1372 byte3(int n)
1373 {
1374         return ((n >> 16) & 0xff);
1375 }
1376
1377 /*
1378  * JLH: Output relocatable 11 bit jump/call
1379  *
1380  * This function is derived from outrw(), adding the parameter for the
1381  * 11 bit address.  This form of address is used only on the 8051 and 8048.
1382  */
1383 VOID
1384 outr11(register struct expr *esp, int op, int r)
1385 {
1386         register int n;
1387
1388         if (pass == 2) {
1389                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1390                         /* Absolute destination.
1391                          * Listing shows only the address.
1392                          */
1393                         out_lw(esp->e_addr,0);
1394                         if (oflag) {
1395                                 outchk(3, 0);
1396                                 out_tw(esp->e_addr);
1397                                 *txtp++ = op;
1398
1399                                 write_rmode(r);
1400                                 *relp++ = txtp - txt - 3;
1401                                 out_rw(0xFFFF);
1402                         }
1403                 } else {
1404                         /* Relocatable destination.  Build THREE
1405                          * byte output: relocatable word, followed
1406                          * by op-code.  Linker will combine them.
1407                          * Listing shows only the address.
1408                          */
1409                         r |= R_WORD | esp->e_rlcf;
1410                         out_lw(esp->e_addr,r|R_RELOC);
1411                         if (oflag) {
1412                                 outchk(3, 5);
1413                                 out_tw(esp->e_addr);
1414                                 *txtp++ = op;
1415
1416                                 if (esp->e_flag) {
1417                                         n = esp->e_base.e_sp->s_ref;
1418                                         r |= R_SYM;
1419                                 } else {
1420                                         n = esp->e_base.e_ap->a_ref;
1421                                 }
1422                                 write_rmode(r);
1423                                 *relp++ = txtp - txt - 3;
1424                                 out_rw(n);
1425                         }
1426                 }
1427         }
1428         dot.s_addr += 2;
1429 }
1430
1431 /*
1432  * Output relocatable 19 bit jump/call
1433  *
1434  * This function is derived from outrw(), adding the parameter for the
1435  * 19 bit address.  This form of address is used only in the DS80C390
1436  * Flat24 mode.
1437  */
1438 VOID
1439 outr19(struct expr * esp, int op, int r)
1440 {
1441         register int n;
1442
1443         if (pass == 2) {
1444                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1445                         /* Absolute destination.
1446                          * Listing shows only the address.
1447                          */
1448                         out_lw(esp->e_addr,0);
1449                         if (oflag) {
1450                                 outchk(4, 0);
1451                                 out_t24(esp->e_addr);
1452                                 *txtp++ = op;
1453
1454                                 write_rmode(r);
1455                                 *relp++ = txtp - txt - 4;
1456                                 out_rw(0xFFFF);
1457                         }
1458                 } else {
1459                         /* Relocatable destination.  Build FOUR
1460                          * byte output: relocatable 24-bit entity, followed
1461                          * by op-code.  Linker will combine them.
1462                          * Listing shows only the address.
1463                          */
1464                         r |= R_WORD | esp->e_rlcf;
1465                         out_l24(esp->e_addr,r|R_RELOC);
1466                         if (oflag) {
1467                                 outchk(4, 5);
1468                                 out_t24(esp->e_addr);
1469                                 *txtp++ = op;
1470                         
1471                                 if (esp->e_flag) {
1472                                         n = esp->e_base.e_sp->s_ref;
1473                                         r |= R_SYM;
1474                                 } else {
1475                                         n = esp->e_base.e_ap->a_ref;
1476                                 }
1477                                 write_rmode(r);
1478                                 *relp++ = txtp - txt - 4;
1479                                 out_rw(n);
1480                         }
1481                 }
1482         }
1483         dot.s_addr += 3;
1484 }