1 /*****************************************************************************/
5 /* Objectcode management for the ca65 macroassembler */
9 /* (C) 1998-2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
59 /*****************************************************************************/
61 /*****************************************************************************/
65 /* Are we in absolute mode or in relocatable mode? */
67 unsigned long AbsPC = 0; /* PC if in absolute mode */
71 typedef struct Segment Segment;
73 Segment* List; /* List of all segments */
74 Fragment* Root; /* Root of fragment list */
75 Fragment* Last; /* Pointer to last fragment */
76 unsigned Num; /* Segment number */
77 unsigned Align; /* Segment alignment */
79 SegDef* Def; /* Segment definition (name and type) */
83 #define SEG(segdef, num, prev) \
84 { prev, 0, 0, num, 0, 0, segdef }
86 /* Definitions for predefined segments */
87 SegDef NullSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL, SEGTYPE_ABS);
88 SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_ZEROPAGE, SEGTYPE_ZP);
89 SegDef DataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_DATA, SEGTYPE_ABS);
90 SegDef BssSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_BSS, SEGTYPE_ABS);
91 SegDef RODataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_RODATA, SEGTYPE_ABS);
92 SegDef CodeSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_CODE, SEGTYPE_ABS);
94 /* Predefined segments */
95 static Segment NullSeg = SEG (&NullSegDef, 5, NULL);
96 static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg);
97 static Segment DataSeg = SEG (&DataSegDef, 3, &ZeropageSeg);
98 static Segment BssSeg = SEG (&BssSegDef, 2, &DataSeg);
99 static Segment RODataSeg = SEG (&RODataSegDef, 1, &BssSeg);
100 static Segment CodeSeg = SEG (&CodeSegDef, 0, &RODataSeg);
102 /* Number of segments */
103 static unsigned SegmentCount = 6;
105 /* List of all segments */
106 static Segment* SegmentList = &CodeSeg;
107 static Segment* SegmentLast = &NullSeg;
109 /* Currently active segment */
110 static Segment* ActiveSeg = &CodeSeg;
114 /*****************************************************************************/
115 /* Segment management */
116 /*****************************************************************************/
120 static Segment* NewSegment (const char* Name, unsigned SegType)
121 /* Create a new segment, insert it into the global list and return it */
125 /* Check for too many segments */
126 if (SegmentCount >= 256) {
127 Fatal (FAT_TOO_MANY_SEGMENTS);
130 /* Check the segment name for invalid names */
131 if (!ValidSegName (Name)) {
132 Error (ERR_ILLEGAL_SEGMENT, Name);
135 /* Create a new segment */
136 S = xmalloc (sizeof (*S));
142 S->Num = SegmentCount++;
145 S->Def = NewSegDef (Name, SegType);
147 /* Insert it into the segment list */
148 SegmentLast->List = S;
151 /* And return it... */
157 void UseSeg (const SegDef* D)
158 /* Use the segment with the given name */
160 Segment* Seg = SegmentList;
162 if (strcmp (Seg->Def->Name, D->Name) == 0) {
163 /* We found this segment. Check if the type is identical */
164 if (D->Type != SEGTYPE_DEFAULT && Seg->Def->Type != D->Type) {
165 Error (ERR_SEG_ATTR_MISMATCH);
166 /* Use the new attribute to avoid errors */
167 Seg->Def->Type = D->Type;
172 /* Check next segment */
176 /* Segment is not in list, create a new one */
177 if (D->Type == SEGTYPE_DEFAULT) {
178 Seg = NewSegment (D->Name, SEGTYPE_ABS);
180 Seg = NewSegment (D->Name, D->Type);
187 unsigned long GetPC (void)
188 /* Get the program counter of the current segment */
190 return RelocMode? ActiveSeg->PC : AbsPC;
195 void SetAbsPC (unsigned long PC)
196 /* Set the program counter in absolute mode */
204 const SegDef* GetCurrentSeg (void)
205 /* Get a pointer to the segment defininition of the current segment */
207 return ActiveSeg->Def;
212 unsigned GetSegNum (void)
213 /* Get the number of the current segment */
215 return ActiveSeg->Num;
220 void SegAlign (unsigned Power, int Val)
221 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
222 * actual fill value will be determined by the linker), otherwise use the
226 unsigned char Data [4];
227 unsigned long Align = (1UL << Power) - 1;
228 unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
229 unsigned long Count = NewPC - ActiveSeg->PC;
232 /* User defined fill value */
233 memset (Data, Val, sizeof (Data));
235 if (Count > sizeof (Data)) {
236 EmitData (Data, sizeof (Data));
237 Count -= sizeof (Data);
239 EmitData (Data, Count);
244 /* Linker defined fill value */
248 /* Remember the alignment in the header */
249 if (ActiveSeg->Align < Power) {
250 ActiveSeg->Align = Power;
257 /* Return true if the current segment is a zeropage segment */
259 return (ActiveSeg->Def->Type == SEGTYPE_ZP);
265 /* Return true if the current segment is a far segment */
267 return (ActiveSeg->Def->Type == SEGTYPE_FAR);
272 unsigned GetSegType (unsigned SegNum)
273 /* Return the type of the segment with the given number */
275 /* Search for the segment */
276 Segment* S = SegmentList;
277 while (S && SegNum) {
282 /* Did we find it? */
284 FAIL ("Invalid segment number");
287 /* Return the segment type */
294 /* Check the segments for range and other errors */
296 Segment* S = SegmentList;
298 Fragment* F = S->Root;
300 if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
301 F->V.Expr = FinalizeExpr (F->V.Expr);
302 if (IsConstExpr (F->V.Expr)) {
303 /* We are able to evaluate the expression. Get the value
304 * and check for range errors.
307 long Val = GetExprVal (F->V.Expr);
308 int Abs = (F->Type != FRAG_SEXPR);
314 PError (&F->Pos, ERR_RANGE);
317 /* PC relative value */
318 if (Val < -128 || Val > 127) {
319 PError (&F->Pos, ERR_RANGE);
322 } else if (F->Len == 2) {
326 PError (&F->Pos, ERR_RANGE);
329 /* PC relative value */
330 if (Val < -32768 || Val > 32767) {
331 PError (&F->Pos, ERR_RANGE);
336 /* Convert the fragment into a literal fragment */
337 for (I = 0; I < F->Len; ++I) {
338 F->V.Data [I] = Val & 0xFF;
341 F->Type = FRAG_LITERAL;
343 /* We cannot evaluate the expression now, leave the job for
344 * the linker. However, we are able to check for explicit
345 * byte expressions and we will do so.
347 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
348 PError (&F->Pos, ERR_RANGE);
361 /* Dump the contents of all segments */
364 Segment* S = SegmentList;
370 printf ("New segment: %s", S->Def->Name);
373 if (F->Type == FRAG_LITERAL) {
375 printf ("\n Literal:");
379 for (I = 0; I < F->Len; ++I) {
380 printf (" %02X", F->V.Data [I]);
383 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
385 printf ("\n Expression (%u): ", F->Len);
386 DumpExpr (F->V.Expr);
387 } else if (F->Type == FRAG_FILL) {
389 printf ("\n Fill bytes (%u)", F->Len);
391 Internal ("Unknown fragment type: %u", F->Type);
398 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
406 static void WriteOneSeg (Segment* Seg)
407 /* Write one segment to the object file */
410 unsigned LineInfoIndex;
412 /* Write the segment name followed by the byte count in this segment */
413 ObjWriteStr (Seg->Def->Name);
414 ObjWrite32 (Seg->PC);
415 ObjWrite8 (Seg->Align);
416 ObjWrite8 (Seg->Def->Type);
418 /* Now walk through the fragment list for this segment and write the
424 /* Write data depending on the type */
425 switch (Frag->Type) {
428 ObjWrite8 (FRAG_LITERAL);
429 ObjWriteVar (Frag->Len);
430 ObjWriteData (Frag->V.Data, Frag->Len);
435 case 1: ObjWrite8 (FRAG_EXPR8); break;
436 case 2: ObjWrite8 (FRAG_EXPR16); break;
437 case 3: ObjWrite8 (FRAG_EXPR24); break;
438 case 4: ObjWrite8 (FRAG_EXPR32); break;
439 default: Internal ("Invalid fragment size: %u", Frag->Len);
441 WriteExpr (Frag->V.Expr);
446 case 1: ObjWrite8 (FRAG_SEXPR8); break;
447 case 2: ObjWrite8 (FRAG_SEXPR16); break;
448 case 3: ObjWrite8 (FRAG_SEXPR24); break;
449 case 4: ObjWrite8 (FRAG_SEXPR32); break;
450 default: Internal ("Invalid fragment size: %u", Frag->Len);
452 WriteExpr (Frag->V.Expr);
456 ObjWrite8 (FRAG_FILL);
457 ObjWriteVar (Frag->Len);
461 Internal ("Invalid fragment type: %u", Frag->Type);
465 /* Write the file position of this fragment */
466 ObjWritePos (&Frag->Pos);
468 /* Write extra line info for this fragment. Zero is considered
469 * "no line info", so add one to the value.
471 LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
472 ObjWriteVar (LineInfoIndex);
481 void WriteSegments (void)
482 /* Write the segment data to the object file */
486 /* Tell the object file module that we're about to start the seg list */
489 /* First thing is segment count */
490 ObjWriteVar (SegmentCount);
492 /* Now walk through all segments and write them to the object file */
495 /* Write one segment */
501 /* Done writing segments */
507 /*****************************************************************************/
509 /*****************************************************************************/
513 static void IncPC (unsigned Value)
514 /* Increment the PC counter */
516 ActiveSeg->PC += Value;
524 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
525 /* Create, initialize and return a new fragment. The fragment will be inserted
526 * into the current segment.
531 /* Create a new fragment */
532 F = xmalloc (sizeof (*F));
539 F->LI = UseLineInfo (CurLineInfo);
543 /* Insert it into the list of all segments */
551 /* Insert it into the current segment */
552 if (ActiveSeg->Root) {
553 ActiveSeg->Last->Next = F;
556 ActiveSeg->Root = ActiveSeg->Last = F;
559 /* Add this fragment to the current listing line */
561 if (LineCur->FragList == 0) {
562 LineCur->FragList = F;
564 LineCur->FragLast->LineList = F;
566 LineCur->FragLast = F;
569 /* Increment the program counter */
578 void Emit0 (unsigned char OPC)
579 /* Emit an instruction with a zero sized operand */
581 /* First fragment, wrong type or out of space, create new one */
582 Fragment* F = NewFragment (FRAG_LITERAL, 1);
588 void Emit1 (unsigned char OPC, ExprNode* Value)
589 /* Emit an instruction with an one byte argument */
597 void Emit2 (unsigned char OPC, ExprNode* Value)
598 /* Emit an instruction with a two byte argument */
606 void Emit3 (unsigned char OPC, ExprNode* Expr)
607 /* Emit an instruction with a three byte argument */
615 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
616 /* Emit an instruction with a three byte argument and separate bank */
625 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
626 /* Emit an opcode with a PC relative argument of one or two bytes */
630 F = NewFragment (FRAG_SEXPR, Size);
636 void EmitData (const unsigned char* Data, unsigned Size)
637 /* Emit data into the current segment */
639 /* Create lots of fragments for the data */
643 /* Determine the length of the next fragment */
645 if (Len > sizeof (F->V.Data)) {
646 Len = sizeof (F->V.Data);
649 /* Create a new fragment */
650 F = NewFragment (FRAG_LITERAL, Len);
653 memcpy (F->V.Data, Data, Len);
664 void EmitByte (ExprNode* Expr)
667 if (IsConstExpr (Expr)) {
668 /* Constant expression, emit literal byte */
669 long Val = GetExprVal (Expr);
671 if ((Val & ~0xFF) != 0) {
676 /* Create a new fragment */
677 Fragment* F = NewFragment (FRAG_EXPR, 1);
686 void EmitWord (ExprNode* Expr)
689 if (IsConstExpr (Expr)) {
690 /* Constant expression, emit literal byte */
691 long Val = GetExprVal (Expr);
693 if ((Val & ~0xFFFF) != 0) {
697 Emit0 ((Val >> 8) & 0xFF);
699 /* Create a new fragment */
700 Fragment* F = NewFragment (FRAG_EXPR, 2);
709 void EmitFarAddr (ExprNode* Expr)
710 /* Emit a 24 bit expression */
712 if (IsConstExpr (Expr)) {
713 /* Constant expression, emit literal byte */
714 long Val = GetExprVal (Expr);
716 if ((Val & ~0xFFFFFF) != 0) {
720 Emit0 ((Val >> 8) & 0xFF);
721 Emit0 ((Val >> 16) & 0xFF);
723 /* Create a new fragment */
724 Fragment* F = NewFragment (FRAG_EXPR, 3);
733 void EmitDWord (ExprNode* Expr)
736 if (IsConstExpr (Expr)) {
737 /* Constant expression, emit literal byte */
738 long Val = GetExprVal (Expr);
741 Emit0 ((Val >> 8) & 0xFF);
742 Emit0 ((Val >> 16) & 0xFF);
743 Emit0 ((Val >> 24) & 0xFF);
745 /* Create a new fragment */
746 Fragment* F = NewFragment (FRAG_EXPR, 4);
755 void EmitFill (unsigned long Count)
756 /* Emit Count fill bytes */
759 /* Calculate the size of the next chunk */
760 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
764 NewFragment (FRAG_FILL, Chunk);