]> git.sur5r.net Git - cc65/blob - ca65/objcode.c
Fixed _textcolor definition.
[cc65] / ca65 / objcode.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 objcode.c                                 */
4 /*                                                                           */
5 /*             Objectcode management for the ca65 macroassembler             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <errno.h>
38 #include <ctype.h>
39
40 #include "../common/segdefs.h"
41
42 #include "error.h"
43 #include "fragment.h"
44 #include "global.h"
45 #include "listing.h"
46 #include "mem.h"
47 #include "objfile.h"
48 #include "scanner.h"
49 #include "symtab.h"
50 #include "objcode.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* Are we in absolute mode or in relocatable mode? */
61 int             RelocMode = 1;
62 unsigned long   AbsPC     = 0;          /* PC if in absolute mode */
63
64
65
66 typedef struct Segment_ Segment;
67 struct Segment_ {
68     Segment*        List;               /* List of all segments */
69     Fragment*       Root;               /* Root of fragment list */
70     Fragment*       Last;               /* Pointer to last fragment */
71     unsigned char   Align;              /* Segment alignment */
72     unsigned char   SegType;            /* True if zero page segment */
73     unsigned long   PC;
74     unsigned        Num;                /* Segment number */
75     char*           Name;               /* Segment name */
76 };
77
78
79
80 /* Predefined segments */
81 static Segment NullSeg = {
82     0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
83 };
84 static Segment ZeropageSeg = {
85     &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
86 };
87 static Segment DataSeg = {
88     &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
89 };
90 static Segment BssSeg = {
91     &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
92 };
93 static Segment RODataSeg = {
94     &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
95 };
96 static Segment CodeSeg = {
97     &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
98 };
99
100 /* Number of segments */
101 static unsigned SegmentCount = 6;
102
103 /* List of all segments */
104 static Segment* SegmentList = &CodeSeg;
105 static Segment* SegmentLast = &NullSeg;
106
107 /* Currently active segment */
108 static Segment* ActiveSeg = &CodeSeg;
109
110
111
112 /*****************************************************************************/
113 /*                            Segment management                             */
114 /*****************************************************************************/
115
116
117
118 static Segment* NewSegment (const char* Name, unsigned SegType)
119 /* Create a new segment, insert it into the global list and return it */
120 {
121     Segment* S;
122     const char* N;
123
124     /* Check for too many segments */
125     if (SegmentCount >= 256) {
126         Fatal (FAT_TOO_MANY_SEGMENTS);
127     }
128
129     /* Check the segment name for invalid names */
130     N = Name;
131     if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
132         Error (ERR_ILLEGAL_SEGMENT, Name);
133     }
134     do {
135         if (*N != '_' && !isalnum (*N)) {
136             Error (ERR_ILLEGAL_SEGMENT, Name);
137             break;
138         }
139         ++N;
140     } while (*N);
141
142     /* Create a new segment */
143     S = Xmalloc (sizeof (*S));
144
145     /* Initialize it */
146     S->List    = 0;
147     S->Root    = 0;
148     S->Last    = 0;
149     S->Align   = 0;
150     S->SegType = SegType;
151     S->PC      = 0;
152     S->Num     = SegmentCount++;
153     S->Name    = StrDup (Name);
154
155     /* Insert it into the segment list */
156     SegmentLast->List = S;
157     SegmentLast = S;
158
159     /* And return it... */
160     return S;
161 }
162
163
164
165 void UseCodeSeg (void)
166 /* Use the code segment */
167 {
168     ActiveSeg = &CodeSeg;
169 }
170
171
172
173 void UseRODataSeg (void)
174 /* Use the r/o data segment */
175 {
176     ActiveSeg = &RODataSeg;
177 }
178
179
180
181 void UseDataSeg (void)
182 /* Use the data segment */
183 {
184     ActiveSeg = &DataSeg;
185 }
186
187
188
189 void UseBssSeg (void)
190 /* Use the BSS segment */
191 {
192     ActiveSeg = &BssSeg;
193 }
194
195
196
197 void UseZeropageSeg (void)
198 /* Use the zero page segment */
199 {
200     ActiveSeg = &ZeropageSeg;
201 }
202
203
204
205 void UseNullSeg (void)
206 /* Use the null segment */
207 {
208     ActiveSeg = &NullSeg;
209 }
210
211
212
213 void UseSeg (const char* Name, unsigned SegType)
214 /* Use the segment with the given name */
215 {
216     Segment* Seg = SegmentList;
217     while (Seg) {
218         if (strcmp (Seg->Name, Name) == 0) {
219             /* We found this segment. Check if the type is identical */
220             if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
221                 Error (ERR_SEG_ATTR_MISMATCH);
222                 /* Use the new attribute to avoid errors */
223                 Seg->SegType = SegType;
224             }
225             ActiveSeg = Seg;
226             return;
227         }
228         /* Check next segment */
229         Seg = Seg->List;
230     }
231
232     /* Segment is not in list, create a new one */
233     if (SegType == SEGTYPE_DEFAULT) {
234         SegType = SEGTYPE_ABS;
235     }
236     Seg = NewSegment (Name, SegType);
237     ActiveSeg = Seg;
238 }
239
240
241
242 unsigned long GetPC (void)
243 /* Get the program counter of the current segment */
244 {
245     return RelocMode? ActiveSeg->PC : AbsPC;
246 }
247
248
249
250 void SetAbsPC (unsigned long PC)
251 /* Set the program counter in absolute mode */
252 {
253     RelocMode = 0;
254     AbsPC = PC;
255 }
256
257
258
259 unsigned GetSegNum (void)
260 /* Get the number of the current segment */
261 {
262     return ActiveSeg->Num;
263 }
264
265
266
267 void SegAlign (unsigned Power, int Val)
268 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
269  * actual fill value will be determined by the linker), otherwise use the
270  * given value.
271  */
272 {
273     unsigned char Data [4];
274     unsigned long Align = (1UL << Power) - 1;
275     unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
276     unsigned long Count = NewPC - ActiveSeg->PC;
277
278     if (Val != -1) {
279         /* User defined fill value */
280         memset (Data, Val, sizeof (Data));
281         while (Count) {
282             if (Count > sizeof (Data)) {
283                 EmitData (Data, sizeof (Data));
284                 Count -= sizeof (Data);
285             } else {
286                 EmitData (Data, Count);
287                 Count = 0;
288             }
289         }
290     } else {
291         /* Linker defined fill value */
292         EmitFill (Count);
293     }
294
295     /* Remember the alignment in the header */
296     if (ActiveSeg->Align < Power) {
297         ActiveSeg->Align = Power;
298     }
299 }
300
301
302
303 int IsZPSeg (void)
304 /* Return true if the current segment is a zeropage segment */
305 {
306     return (ActiveSeg->SegType == SEGTYPE_ZP);
307 }
308
309
310
311 int IsFarSeg (void)
312 /* Return true if the current segment is a far segment */
313 {
314     return (ActiveSeg->SegType == SEGTYPE_FAR);
315 }
316
317
318
319 unsigned GetSegType (unsigned SegNum)
320 /* Return the type of the segment with the given number */
321 {
322     /* Search for the segment */
323     Segment* S = SegmentList;
324     while (S && SegNum) {
325         --SegNum;
326         S = S->List;
327     }
328
329     /* Did we find it? */
330     if (S == 0) {
331         FAIL ("Invalid segment number");
332     }
333
334     /* Return the segment type */
335     return S->SegType;
336 }
337
338
339
340 void SegCheck (void)
341 /* Check the segments for range and other errors */
342 {
343     Segment* S = SegmentList;
344     while (S) {
345         Fragment* F = S->Root;
346         while (F) {
347             if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
348                 F->V.Expr = FinalizeExpr (F->V.Expr);
349                 if (IsConstExpr (F->V.Expr)) {
350                     /* We are able to evaluate the expression. Get the value
351                      * and check for range errors.
352                      */
353                     unsigned I;
354                     long Val = GetExprVal (F->V.Expr);
355                     int Abs = (F->Type != FRAG_SEXPR);
356
357                     if (F->Len == 1) {
358                         if (Abs) {
359                             /* Absolute value */
360                             if (Val > 255) {
361                                 PError (&F->Pos, ERR_RANGE);
362                             }
363                         } else {
364                             /* PC relative value */
365                             if (Val < -128 || Val > 127) {
366                                 PError (&F->Pos, ERR_RANGE);
367                             }
368                         }
369                     } else if (F->Len == 2) {
370                         if (Abs) {
371                             /* Absolute value */
372                             if (Val > 65535) {
373                                 PError (&F->Pos, ERR_RANGE);
374                             }
375                         } else {
376                             /* PC relative value */
377                             if (Val < -32768 || Val > 32767) {
378                                 PError (&F->Pos, ERR_RANGE);
379                             }
380                         }
381                     }
382
383                     /* Convert the fragment into a literal fragment */
384                     for (I = 0; I < F->Len; ++I) {
385                         F->V.Data [I] = Val & 0xFF;
386                         Val >>= 8;
387                     }
388                     F->Type = FRAG_LITERAL;
389                 } else {
390                     /* We cannot evaluate the expression now, leave the job for
391                      * the linker. However, we are able to check for explicit
392                      * byte expressions and we will do so.
393                      */
394                     if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
395                         PError (&F->Pos, ERR_RANGE);
396                     }
397                 }
398             }
399             F = F->Next;
400         }
401         S = S->List;
402     }
403 }
404
405
406
407 void SegDump (void)
408 /* Dump the contents of all segments */
409 {
410     unsigned X = 0;
411     Segment* S = SegmentList;
412     printf ("\n");
413     while (S) {
414         unsigned I;
415         Fragment* F;
416         int State = -1;
417         printf ("New segment: %s", S->Name);
418         F = S->Root;
419         while (F) {
420             if (F->Type == FRAG_LITERAL) {
421                 if (State != 0) {
422                     printf ("\n  Literal:");
423                     X = 15;
424                     State = 0;
425                 }
426                 for (I = 0; I < F->Len; ++I) {
427                     printf (" %02X", F->V.Data [I]);
428                     X += 3;
429                 }
430             } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
431                 State = 1;
432                 printf ("\n  Expression (%u): ", F->Len);
433                 DumpExpr (F->V.Expr);
434             } else if (F->Type == FRAG_FILL) {
435                 State = 1;
436                 printf ("\n  Fill bytes (%u)", F->Len);
437             } else {
438                 Internal ("Unknown fragment type: %u", F->Type);
439             }
440             if (X > 65) {
441                 State = -1;
442             }
443             F = F->Next;
444         }
445         printf ("\n  End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
446         S = S->List;
447     }
448     printf ("\n");
449 }
450
451
452
453 static void WriteOneSeg (Segment* Seg)
454 /* Write one segment to the object file */
455 {
456     Fragment* Frag;
457     Fragment* F;
458     unsigned long Size;
459
460     /* Write the segment name followed by the byte count in this segment */
461     ObjWriteStr (Seg->Name);
462     ObjWrite32 (Seg->PC);
463     ObjWrite8 (Seg->Align);
464     ObjWrite8 (Seg->SegType);
465
466     /* Now walk through the fragment list for this segment and write the
467      * fragments.
468      */
469     Frag = Seg->Root;
470     while (Frag) {
471
472         /* Write data depending on the type */
473         switch (Frag->Type) {
474
475             case FRAG_LITERAL:
476                 /* To make the object file somewhat smaller, write all literal
477                  * data of this and the following fragments preceeded by the
478                  * length.
479                  */
480                 F = Frag;
481                 Size = 0;
482                 while (F && F->Type == FRAG_LITERAL) {
483                     Size += F->Len;
484                     F = F->Next;
485                 }
486                 if (Size < 0x100) {
487                     ObjWrite8 (FRAG_LITERAL8);
488                     ObjWrite8 (Size);
489                 } else if (Size < 0x10000) {
490                     ObjWrite8 (FRAG_LITERAL16);
491                     ObjWrite16 (Size);
492                 } else if (Size < 0x1000000) {
493                     ObjWrite8 (FRAG_LITERAL24);
494                     ObjWrite24 (Size);
495                 } else {
496                     ObjWrite8 (FRAG_LITERAL32);
497                     ObjWrite32 (Size);
498                 }
499
500                 /* Now write the literal data */
501                 F = Frag;
502                 while (F && F->Type == FRAG_LITERAL) {
503                     ObjWriteData (F->V.Data, F->Len);
504                     Frag = F;
505                     F = F->Next;
506                 }
507                 break;
508
509             case FRAG_EXPR:
510                 switch (Frag->Len) {
511                     case 1:   ObjWrite8 (FRAG_EXPR8);   break;
512                     case 2:   ObjWrite8 (FRAG_EXPR16);  break;
513                     case 3:   ObjWrite8 (FRAG_EXPR24);  break;
514                     case 4:   ObjWrite8 (FRAG_EXPR32);  break;
515                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
516                 }
517                 WriteExpr (Frag->V.Expr);
518                 break;
519
520             case FRAG_SEXPR:
521                 switch (Frag->Len) {
522                     case 1:   ObjWrite8 (FRAG_SEXPR8);  break;
523                     case 2:   ObjWrite8 (FRAG_SEXPR16); break;
524                     case 3:   ObjWrite8 (FRAG_SEXPR24); break;
525                     case 4:   ObjWrite8 (FRAG_SEXPR32); break;
526                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
527                 }
528                 WriteExpr (Frag->V.Expr);
529                 break;
530
531             case FRAG_FILL:
532                 ObjWrite8 (FRAG_FILL);
533                 ObjWrite16 (Frag->Len);
534                 break;
535
536             default:
537                 Internal ("Invalid fragment type: %u", Frag->Type);
538
539         }
540
541         /* Write the file position of this fragment */
542         ObjWritePos (&Frag->Pos);
543
544         /* Next fragment */
545         Frag = Frag->Next;
546     }
547 }
548
549
550
551 void WriteSegments (void)
552 /* Write the segment data to the object file */
553 {
554     Segment* Seg;
555
556     /* Tell the object file module that we're about to start the seg list */
557     ObjStartSegments ();
558
559     /* First thing is segment count */
560     ObjWrite8 (SegmentCount);
561
562     /* Now walk through all segments and write them to the object file */
563     Seg = SegmentList;
564     while (Seg) {
565         /* Write one segment */
566         WriteOneSeg (Seg);
567         /* Next segment */
568         Seg = Seg->List;
569     }
570
571     /* Done writing segments */
572     ObjEndSegments ();
573 }
574
575
576
577 /*****************************************************************************/
578 /*                                   Code                                    */
579 /*****************************************************************************/
580
581
582
583 static void IncPC (unsigned Value)
584 /* Increment the PC counter */
585 {
586     ActiveSeg->PC += Value;
587     if (!RelocMode) {
588         AbsPC += Value;
589     }
590 }
591
592
593
594 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
595 /* Create, initialize and return a new fragment. The fragment will be inserted
596  * into the current segment.
597  */
598 {
599     Fragment* F;
600
601     /* Create a new fragment */
602     F = Xmalloc (sizeof (*F));
603
604     /* Initialize it */
605     F->List     = 0;
606     F->Next     = 0;
607     F->LineList = 0;
608     F->Pos      = CurPos;
609     F->Len      = Len;
610     F->Type     = Type;
611
612     /* Insert it into the list of all segments */
613     if (FragList == 0) {
614         FragList = F;
615     } else {
616         FragLast->List = F;
617     }
618     FragLast = F;
619
620     /* Insert it into the current segment */
621     if (ActiveSeg->Root) {
622         ActiveSeg->Last->Next = F;
623         ActiveSeg->Last = F;
624     } else {
625         ActiveSeg->Root = ActiveSeg->Last = F;
626     }
627
628     /* Add this fragment to the current listing line */
629     if (LineCur) {
630         if (LineCur->FragList == 0) {
631             LineCur->FragList = F;
632             /* First fragment - set the PC
633             LineCur->PC    = GetPC ();
634             LineCur->Reloc = RelocMode;    
635 */
636         } else {
637             LineCur->FragLast->LineList = F;
638         }
639         LineCur->FragLast = F;
640     }
641
642     /* Increment the program counter */
643     IncPC (Len);
644
645     /* And return it */
646     return F;
647 }
648
649
650
651 void Emit0 (unsigned char OPC)
652 /* Emit an instruction with a zero sized operand */
653 {
654     /* First fragment, wrong type or out of space, create new one */
655     Fragment* F = NewFragment (FRAG_LITERAL, 1);
656     F->V.Data [0] = OPC;
657 }
658
659
660
661 void Emit1 (unsigned char OPC, ExprNode* Value)
662 /* Emit an instruction with an one byte argument */
663 {
664     Emit0 (OPC);
665     EmitByte (Value);
666 }
667
668
669
670 void Emit2 (unsigned char OPC, ExprNode* Value)
671 /* Emit an instruction with a two byte argument */
672 {
673     Emit0 (OPC);
674     EmitWord (Value);
675 }
676
677
678
679 void Emit3 (unsigned char OPC, ExprNode* Expr)
680 /* Emit an instruction with a three byte argument */
681 {
682     Emit0 (OPC);
683     EmitFarAddr (Expr);
684 }
685
686
687
688 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
689 /* Emit an instruction with a three byte argument and separate bank */
690 {
691     Emit0 (OPC);
692     EmitWord (Expr);
693     EmitByte (Bank);
694 }
695
696
697
698 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
699 /* Emit an opcode with a PC relative argument of one or two bytes */
700 {
701     Fragment* F;
702     Emit0 (OPC);
703     F = NewFragment (FRAG_SEXPR, Size);
704     F->V.Expr = Expr;
705 }
706
707
708
709 void EmitData (const unsigned char* Data, unsigned Size)
710 /* Emit data into the current segment */
711 {
712     /* Create lots of fragments for the data */
713     while (Size) {
714         Fragment* F;
715
716         /* Determine the length of the next fragment */
717         unsigned Len = Size;
718         if (Len > sizeof (F->V.Data)) {
719             Len = sizeof (F->V.Data);
720         }
721
722         /* Create a new fragment */
723         F = NewFragment (FRAG_LITERAL, Len);
724
725         /* Copy the data */
726         memcpy (F->V.Data, Data, Len);
727
728         /* Next chunk */
729         Data += Len;
730         Size -= Len;
731
732     }
733 }
734
735
736
737 void EmitByte (ExprNode* Expr)
738 /* Emit one byte */
739 {
740     if (IsConstExpr (Expr)) {
741         /* Constant expression, emit literal byte */
742         long Val = GetExprVal (Expr);
743         FreeExpr (Expr);
744         if ((Val & ~0xFF) != 0) {
745             Error (ERR_RANGE);
746         }
747         Emit0 (Val & 0xFF);
748     } else {
749         /* Create a new fragment */
750         Fragment* F = NewFragment (FRAG_EXPR, 1);
751
752         /* Set the data */
753         F->V.Expr = Expr;
754     }
755 }
756
757
758
759 void EmitWord (ExprNode* Expr)
760 /* Emit one word */
761 {
762     if (IsConstExpr (Expr)) {
763         /* Constant expression, emit literal byte */
764         long Val = GetExprVal (Expr);
765         FreeExpr (Expr);
766         if ((Val & ~0xFFFF) != 0) {
767             Error (ERR_RANGE);
768         }
769         Emit0 (Val & 0xFF);
770         Emit0 ((Val >> 8) & 0xFF);
771     } else {
772         /* Create a new fragment */
773         Fragment* F = NewFragment (FRAG_EXPR, 2);
774
775         /* Set the data */
776         F->V.Expr = Expr;
777     }
778 }
779
780
781
782 void EmitFarAddr (ExprNode* Expr)
783 /* Emit a 24 bit expression */
784 {
785     if (IsConstExpr (Expr)) {
786         /* Constant expression, emit literal byte */
787         long Val = GetExprVal (Expr);
788         FreeExpr (Expr);
789         if ((Val & ~0xFFFFFF) != 0) {
790             Error (ERR_RANGE);
791         }
792         Emit0 (Val & 0xFF);
793         Emit0 ((Val >> 8) & 0xFF);
794         Emit0 ((Val >> 16) & 0xFF);
795     } else {
796         /* Create a new fragment */
797         Fragment* F = NewFragment (FRAG_EXPR, 3);
798
799         /* Set the data */
800         F->V.Expr = Expr;
801     }
802 }
803
804
805
806 void EmitDWord (ExprNode* Expr)
807 /* Emit one dword */
808 {
809     if (IsConstExpr (Expr)) {
810         /* Constant expression, emit literal byte */
811         long Val = GetExprVal (Expr);
812         FreeExpr (Expr);
813         Emit0 (Val & 0xFF);
814         Emit0 ((Val >> 8) & 0xFF);
815         Emit0 ((Val >> 16) & 0xFF);
816         Emit0 ((Val >> 24) & 0xFF);
817     } else {
818         /* Create a new fragment */
819         Fragment* F = NewFragment (FRAG_EXPR, 4);
820
821         /* Set the data */
822         F->V.Expr = Expr;
823     }
824 }
825
826
827
828 void EmitFill (unsigned long Count)
829 /* Emit Count fill bytes */
830 {
831     while (Count) {
832         /* Calculate the size of the next chunk */
833         unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
834         Count -= Chunk;
835
836         /* Emit one chunk */
837         NewFragment (FRAG_FILL, Chunk);
838     }
839 }
840
841
842