1 /*****************************************************************************/
5 /* Objectcode management for the ca65 macroassembler */
9 /* (C) 1998-2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
57 /*****************************************************************************/
59 /*****************************************************************************/
63 /* Are we in absolute mode or in relocatable mode? */
65 unsigned long AbsPC = 0; /* PC if in absolute mode */
69 typedef struct Segment_ Segment;
71 Segment* List; /* List of all segments */
72 Fragment* Root; /* Root of fragment list */
73 Fragment* Last; /* Pointer to last fragment */
74 unsigned char Align; /* Segment alignment */
75 unsigned char SegType; /* True if zero page segment */
77 unsigned Num; /* Segment number */
78 char* Name; /* Segment name */
83 /* Predefined segments */
84 static Segment NullSeg = {
85 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
87 static Segment ZeropageSeg = {
88 &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
90 static Segment DataSeg = {
91 &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
93 static Segment BssSeg = {
94 &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
96 static Segment RODataSeg = {
97 &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
99 static Segment CodeSeg = {
100 &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
103 /* Number of segments */
104 static unsigned SegmentCount = 6;
106 /* List of all segments */
107 static Segment* SegmentList = &CodeSeg;
108 static Segment* SegmentLast = &NullSeg;
110 /* Currently active segment */
111 static Segment* ActiveSeg = &CodeSeg;
115 /*****************************************************************************/
116 /* Segment management */
117 /*****************************************************************************/
121 static Segment* NewSegment (const char* Name, unsigned SegType)
122 /* Create a new segment, insert it into the global list and return it */
127 /* Check for too many segments */
128 if (SegmentCount >= 256) {
129 Fatal (FAT_TOO_MANY_SEGMENTS);
132 /* Check the segment name for invalid names */
134 if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
135 Error (ERR_ILLEGAL_SEGMENT, Name);
138 if (*N != '_' && !isalnum (*N)) {
139 Error (ERR_ILLEGAL_SEGMENT, Name);
145 /* Create a new segment */
146 S = xmalloc (sizeof (*S));
153 S->SegType = SegType;
155 S->Num = SegmentCount++;
156 S->Name = xstrdup (Name);
158 /* Insert it into the segment list */
159 SegmentLast->List = S;
162 /* And return it... */
168 void UseCodeSeg (void)
169 /* Use the code segment */
171 ActiveSeg = &CodeSeg;
176 void UseRODataSeg (void)
177 /* Use the r/o data segment */
179 ActiveSeg = &RODataSeg;
184 void UseDataSeg (void)
185 /* Use the data segment */
187 ActiveSeg = &DataSeg;
192 void UseBssSeg (void)
193 /* Use the BSS segment */
200 void UseZeropageSeg (void)
201 /* Use the zero page segment */
203 ActiveSeg = &ZeropageSeg;
208 void UseNullSeg (void)
209 /* Use the null segment */
211 ActiveSeg = &NullSeg;
216 void UseSeg (const char* Name, unsigned SegType)
217 /* Use the segment with the given name */
219 Segment* Seg = SegmentList;
221 if (strcmp (Seg->Name, Name) == 0) {
222 /* We found this segment. Check if the type is identical */
223 if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
224 Error (ERR_SEG_ATTR_MISMATCH);
225 /* Use the new attribute to avoid errors */
226 Seg->SegType = SegType;
231 /* Check next segment */
235 /* Segment is not in list, create a new one */
236 if (SegType == SEGTYPE_DEFAULT) {
237 SegType = SEGTYPE_ABS;
239 Seg = NewSegment (Name, SegType);
245 unsigned long GetPC (void)
246 /* Get the program counter of the current segment */
248 return RelocMode? ActiveSeg->PC : AbsPC;
253 void SetAbsPC (unsigned long PC)
254 /* Set the program counter in absolute mode */
262 unsigned GetSegNum (void)
263 /* Get the number of the current segment */
265 return ActiveSeg->Num;
270 void SegAlign (unsigned Power, int Val)
271 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
272 * actual fill value will be determined by the linker), otherwise use the
276 unsigned char Data [4];
277 unsigned long Align = (1UL << Power) - 1;
278 unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
279 unsigned long Count = NewPC - ActiveSeg->PC;
282 /* User defined fill value */
283 memset (Data, Val, sizeof (Data));
285 if (Count > sizeof (Data)) {
286 EmitData (Data, sizeof (Data));
287 Count -= sizeof (Data);
289 EmitData (Data, Count);
294 /* Linker defined fill value */
298 /* Remember the alignment in the header */
299 if (ActiveSeg->Align < Power) {
300 ActiveSeg->Align = Power;
307 /* Return true if the current segment is a zeropage segment */
309 return (ActiveSeg->SegType == SEGTYPE_ZP);
315 /* Return true if the current segment is a far segment */
317 return (ActiveSeg->SegType == SEGTYPE_FAR);
322 unsigned GetSegType (unsigned SegNum)
323 /* Return the type of the segment with the given number */
325 /* Search for the segment */
326 Segment* S = SegmentList;
327 while (S && SegNum) {
332 /* Did we find it? */
334 FAIL ("Invalid segment number");
337 /* Return the segment type */
344 /* Check the segments for range and other errors */
346 Segment* S = SegmentList;
348 Fragment* F = S->Root;
350 if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
351 F->V.Expr = FinalizeExpr (F->V.Expr);
352 if (IsConstExpr (F->V.Expr)) {
353 /* We are able to evaluate the expression. Get the value
354 * and check for range errors.
357 long Val = GetExprVal (F->V.Expr);
358 int Abs = (F->Type != FRAG_SEXPR);
364 PError (&F->Pos, ERR_RANGE);
367 /* PC relative value */
368 if (Val < -128 || Val > 127) {
369 PError (&F->Pos, ERR_RANGE);
372 } else if (F->Len == 2) {
376 PError (&F->Pos, ERR_RANGE);
379 /* PC relative value */
380 if (Val < -32768 || Val > 32767) {
381 PError (&F->Pos, ERR_RANGE);
386 /* Convert the fragment into a literal fragment */
387 for (I = 0; I < F->Len; ++I) {
388 F->V.Data [I] = Val & 0xFF;
391 F->Type = FRAG_LITERAL;
393 /* We cannot evaluate the expression now, leave the job for
394 * the linker. However, we are able to check for explicit
395 * byte expressions and we will do so.
397 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
398 PError (&F->Pos, ERR_RANGE);
411 /* Dump the contents of all segments */
414 Segment* S = SegmentList;
420 printf ("New segment: %s", S->Name);
423 if (F->Type == FRAG_LITERAL) {
425 printf ("\n Literal:");
429 for (I = 0; I < F->Len; ++I) {
430 printf (" %02X", F->V.Data [I]);
433 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
435 printf ("\n Expression (%u): ", F->Len);
436 DumpExpr (F->V.Expr);
437 } else if (F->Type == FRAG_FILL) {
439 printf ("\n Fill bytes (%u)", F->Len);
441 Internal ("Unknown fragment type: %u", F->Type);
448 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
456 static void WriteOneSeg (Segment* Seg)
457 /* Write one segment to the object file */
463 /* Write the segment name followed by the byte count in this segment */
464 ObjWriteStr (Seg->Name);
465 ObjWrite32 (Seg->PC);
466 ObjWrite8 (Seg->Align);
467 ObjWrite8 (Seg->SegType);
469 /* Now walk through the fragment list for this segment and write the
475 /* Write data depending on the type */
476 switch (Frag->Type) {
479 /* To make the object file somewhat smaller, write all literal
480 * data of this and the following fragments preceeded by the
485 while (F && F->Type == FRAG_LITERAL) {
489 ObjWrite8 (FRAG_LITERAL);
492 /* Now write the literal data */
494 while (F && F->Type == FRAG_LITERAL) {
495 ObjWriteData (F->V.Data, F->Len);
503 case 1: ObjWrite8 (FRAG_EXPR8); break;
504 case 2: ObjWrite8 (FRAG_EXPR16); break;
505 case 3: ObjWrite8 (FRAG_EXPR24); break;
506 case 4: ObjWrite8 (FRAG_EXPR32); break;
507 default: Internal ("Invalid fragment size: %u", Frag->Len);
509 WriteExpr (Frag->V.Expr);
514 case 1: ObjWrite8 (FRAG_SEXPR8); break;
515 case 2: ObjWrite8 (FRAG_SEXPR16); break;
516 case 3: ObjWrite8 (FRAG_SEXPR24); break;
517 case 4: ObjWrite8 (FRAG_SEXPR32); break;
518 default: Internal ("Invalid fragment size: %u", Frag->Len);
520 WriteExpr (Frag->V.Expr);
524 ObjWrite8 (FRAG_FILL);
525 ObjWriteVar (Frag->Len);
529 Internal ("Invalid fragment type: %u", Frag->Type);
533 /* Write the file position of this fragment */
534 ObjWritePos (&Frag->Pos);
543 void WriteSegments (void)
544 /* Write the segment data to the object file */
548 /* Tell the object file module that we're about to start the seg list */
551 /* First thing is segment count */
552 ObjWriteVar (SegmentCount);
554 /* Now walk through all segments and write them to the object file */
557 /* Write one segment */
563 /* Done writing segments */
569 /*****************************************************************************/
571 /*****************************************************************************/
575 static void IncPC (unsigned Value)
576 /* Increment the PC counter */
578 ActiveSeg->PC += Value;
586 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
587 /* Create, initialize and return a new fragment. The fragment will be inserted
588 * into the current segment.
593 /* Create a new fragment */
594 F = xmalloc (sizeof (*F));
604 /* Insert it into the list of all segments */
612 /* Insert it into the current segment */
613 if (ActiveSeg->Root) {
614 ActiveSeg->Last->Next = F;
617 ActiveSeg->Root = ActiveSeg->Last = F;
620 /* Add this fragment to the current listing line */
622 if (LineCur->FragList == 0) {
623 LineCur->FragList = F;
625 LineCur->FragLast->LineList = F;
627 LineCur->FragLast = F;
630 /* Increment the program counter */
639 void Emit0 (unsigned char OPC)
640 /* Emit an instruction with a zero sized operand */
642 /* First fragment, wrong type or out of space, create new one */
643 Fragment* F = NewFragment (FRAG_LITERAL, 1);
649 void Emit1 (unsigned char OPC, ExprNode* Value)
650 /* Emit an instruction with an one byte argument */
658 void Emit2 (unsigned char OPC, ExprNode* Value)
659 /* Emit an instruction with a two byte argument */
667 void Emit3 (unsigned char OPC, ExprNode* Expr)
668 /* Emit an instruction with a three byte argument */
676 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
677 /* Emit an instruction with a three byte argument and separate bank */
686 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
687 /* Emit an opcode with a PC relative argument of one or two bytes */
691 F = NewFragment (FRAG_SEXPR, Size);
697 void EmitData (const unsigned char* Data, unsigned Size)
698 /* Emit data into the current segment */
700 /* Create lots of fragments for the data */
704 /* Determine the length of the next fragment */
706 if (Len > sizeof (F->V.Data)) {
707 Len = sizeof (F->V.Data);
710 /* Create a new fragment */
711 F = NewFragment (FRAG_LITERAL, Len);
714 memcpy (F->V.Data, Data, Len);
725 void EmitByte (ExprNode* Expr)
728 if (IsConstExpr (Expr)) {
729 /* Constant expression, emit literal byte */
730 long Val = GetExprVal (Expr);
732 if ((Val & ~0xFF) != 0) {
737 /* Create a new fragment */
738 Fragment* F = NewFragment (FRAG_EXPR, 1);
747 void EmitWord (ExprNode* Expr)
750 if (IsConstExpr (Expr)) {
751 /* Constant expression, emit literal byte */
752 long Val = GetExprVal (Expr);
754 if ((Val & ~0xFFFF) != 0) {
758 Emit0 ((Val >> 8) & 0xFF);
760 /* Create a new fragment */
761 Fragment* F = NewFragment (FRAG_EXPR, 2);
770 void EmitFarAddr (ExprNode* Expr)
771 /* Emit a 24 bit expression */
773 if (IsConstExpr (Expr)) {
774 /* Constant expression, emit literal byte */
775 long Val = GetExprVal (Expr);
777 if ((Val & ~0xFFFFFF) != 0) {
781 Emit0 ((Val >> 8) & 0xFF);
782 Emit0 ((Val >> 16) & 0xFF);
784 /* Create a new fragment */
785 Fragment* F = NewFragment (FRAG_EXPR, 3);
794 void EmitDWord (ExprNode* Expr)
797 if (IsConstExpr (Expr)) {
798 /* Constant expression, emit literal byte */
799 long Val = GetExprVal (Expr);
802 Emit0 ((Val >> 8) & 0xFF);
803 Emit0 ((Val >> 16) & 0xFF);
804 Emit0 ((Val >> 24) & 0xFF);
806 /* Create a new fragment */
807 Fragment* F = NewFragment (FRAG_EXPR, 4);
816 void EmitFill (unsigned long Count)
817 /* Emit Count fill bytes */
820 /* Calculate the size of the next chunk */
821 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
825 NewFragment (FRAG_FILL, Chunk);