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