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 /*****************************************************************************/
40 #include "../common/segdefs.h"
54 /*****************************************************************************/
56 /*****************************************************************************/
60 /* Are we in absolute mode or in relocatable mode? */
62 unsigned long AbsPC = 0; /* PC if in absolute mode */
66 typedef struct Segment_ 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 */
74 unsigned Num; /* Segment number */
75 char* Name; /* Segment name */
80 /* Predefined segments */
81 static Segment NullSeg = {
82 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
84 static Segment ZeropageSeg = {
85 &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
87 static Segment DataSeg = {
88 &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
90 static Segment BssSeg = {
91 &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
93 static Segment RODataSeg = {
94 &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
96 static Segment CodeSeg = {
97 &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
100 /* Number of segments */
101 static unsigned SegmentCount = 6;
103 /* List of all segments */
104 static Segment* SegmentList = &CodeSeg;
105 static Segment* SegmentLast = &NullSeg;
107 /* Currently active segment */
108 static Segment* ActiveSeg = &CodeSeg;
112 /*****************************************************************************/
113 /* Segment management */
114 /*****************************************************************************/
118 static Segment* NewSegment (const char* Name, unsigned SegType)
119 /* Create a new segment, insert it into the global list and return it */
124 /* Check for too many segments */
125 if (SegmentCount >= 256) {
126 Fatal (FAT_TOO_MANY_SEGMENTS);
129 /* Check the segment name for invalid names */
131 if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
132 Error (ERR_ILLEGAL_SEGMENT, Name);
135 if (*N != '_' && !isalnum (*N)) {
136 Error (ERR_ILLEGAL_SEGMENT, Name);
142 /* Create a new segment */
143 S = Xmalloc (sizeof (*S));
150 S->SegType = SegType;
152 S->Num = SegmentCount++;
153 S->Name = StrDup (Name);
155 /* Insert it into the segment list */
156 SegmentLast->List = S;
159 /* And return it... */
165 void UseCodeSeg (void)
166 /* Use the code segment */
168 ActiveSeg = &CodeSeg;
173 void UseRODataSeg (void)
174 /* Use the r/o data segment */
176 ActiveSeg = &RODataSeg;
181 void UseDataSeg (void)
182 /* Use the data segment */
184 ActiveSeg = &DataSeg;
189 void UseBssSeg (void)
190 /* Use the BSS segment */
197 void UseZeropageSeg (void)
198 /* Use the zero page segment */
200 ActiveSeg = &ZeropageSeg;
205 void UseNullSeg (void)
206 /* Use the null segment */
208 ActiveSeg = &NullSeg;
213 void UseSeg (const char* Name, unsigned SegType)
214 /* Use the segment with the given name */
216 Segment* Seg = SegmentList;
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;
228 /* Check next segment */
232 /* Segment is not in list, create a new one */
233 if (SegType == SEGTYPE_DEFAULT) {
234 SegType = SEGTYPE_ABS;
236 Seg = NewSegment (Name, SegType);
242 unsigned long GetPC (void)
243 /* Get the program counter of the current segment */
245 return RelocMode? ActiveSeg->PC : AbsPC;
250 void SetAbsPC (unsigned long PC)
251 /* Set the program counter in absolute mode */
259 unsigned GetSegNum (void)
260 /* Get the number of the current segment */
262 return ActiveSeg->Num;
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
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;
279 /* User defined fill value */
280 memset (Data, Val, sizeof (Data));
282 if (Count > sizeof (Data)) {
283 EmitData (Data, sizeof (Data));
284 Count -= sizeof (Data);
286 EmitData (Data, Count);
291 /* Linker defined fill value */
295 /* Remember the alignment in the header */
296 if (ActiveSeg->Align < Power) {
297 ActiveSeg->Align = Power;
304 /* Return true if the current segment is a zeropage segment */
306 return (ActiveSeg->SegType == SEGTYPE_ZP);
312 /* Return true if the current segment is a far segment */
314 return (ActiveSeg->SegType == SEGTYPE_FAR);
319 unsigned GetSegType (unsigned SegNum)
320 /* Return the type of the segment with the given number */
322 /* Search for the segment */
323 Segment* S = SegmentList;
324 while (S && SegNum) {
329 /* Did we find it? */
331 FAIL ("Invalid segment number");
334 /* Return the segment type */
341 /* Check the segments for range and other errors */
343 Segment* S = SegmentList;
345 Fragment* F = S->Root;
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.
354 long Val = GetExprVal (F->V.Expr);
355 int Abs = (F->Type != FRAG_SEXPR);
361 PError (&F->Pos, ERR_RANGE);
364 /* PC relative value */
365 if (Val < -128 || Val > 127) {
366 PError (&F->Pos, ERR_RANGE);
369 } else if (F->Len == 2) {
373 PError (&F->Pos, ERR_RANGE);
376 /* PC relative value */
377 if (Val < -32768 || Val > 32767) {
378 PError (&F->Pos, ERR_RANGE);
383 /* Convert the fragment into a literal fragment */
384 for (I = 0; I < F->Len; ++I) {
385 F->V.Data [I] = Val & 0xFF;
388 F->Type = FRAG_LITERAL;
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.
394 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
395 PError (&F->Pos, ERR_RANGE);
408 /* Dump the contents of all segments */
411 Segment* S = SegmentList;
417 printf ("New segment: %s", S->Name);
420 if (F->Type == FRAG_LITERAL) {
422 printf ("\n Literal:");
426 for (I = 0; I < F->Len; ++I) {
427 printf (" %02X", F->V.Data [I]);
430 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
432 printf ("\n Expression (%u): ", F->Len);
433 DumpExpr (F->V.Expr);
434 } else if (F->Type == FRAG_FILL) {
436 printf ("\n Fill bytes (%u)", F->Len);
438 Internal ("Unknown fragment type: %u", F->Type);
445 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
453 static void WriteOneSeg (Segment* Seg)
454 /* Write one segment to the object file */
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);
466 /* Now walk through the fragment list for this segment and write the
472 /* Write data depending on the type */
473 switch (Frag->Type) {
476 /* To make the object file somewhat smaller, write all literal
477 * data of this and the following fragments preceeded by the
482 while (F && F->Type == FRAG_LITERAL) {
487 ObjWrite8 (FRAG_LITERAL8);
489 } else if (Size < 0x10000) {
490 ObjWrite8 (FRAG_LITERAL16);
492 } else if (Size < 0x1000000) {
493 ObjWrite8 (FRAG_LITERAL24);
496 ObjWrite8 (FRAG_LITERAL32);
500 /* Now write the literal data */
502 while (F && F->Type == FRAG_LITERAL) {
503 ObjWriteData (F->V.Data, F->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);
517 WriteExpr (Frag->V.Expr);
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);
528 WriteExpr (Frag->V.Expr);
532 ObjWrite8 (FRAG_FILL);
533 ObjWrite16 (Frag->Len);
537 Internal ("Invalid fragment type: %u", Frag->Type);
541 /* Write the file position of this fragment */
542 ObjWritePos (&Frag->Pos);
551 void WriteSegments (void)
552 /* Write the segment data to the object file */
556 /* Tell the object file module that we're about to start the seg list */
559 /* First thing is segment count */
560 ObjWrite8 (SegmentCount);
562 /* Now walk through all segments and write them to the object file */
565 /* Write one segment */
571 /* Done writing segments */
577 /*****************************************************************************/
579 /*****************************************************************************/
583 static void IncPC (unsigned Value)
584 /* Increment the PC counter */
586 ActiveSeg->PC += Value;
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.
601 /* Create a new fragment */
602 F = Xmalloc (sizeof (*F));
612 /* Insert it into the list of all segments */
620 /* Insert it into the current segment */
621 if (ActiveSeg->Root) {
622 ActiveSeg->Last->Next = F;
625 ActiveSeg->Root = ActiveSeg->Last = F;
628 /* Add this fragment to the current listing line */
630 if (LineCur->FragList == 0) {
631 LineCur->FragList = F;
632 /* First fragment - set the PC
633 LineCur->PC = GetPC ();
634 LineCur->Reloc = RelocMode;
637 LineCur->FragLast->LineList = F;
639 LineCur->FragLast = F;
642 /* Increment the program counter */
651 void Emit0 (unsigned char OPC)
652 /* Emit an instruction with a zero sized operand */
654 /* First fragment, wrong type or out of space, create new one */
655 Fragment* F = NewFragment (FRAG_LITERAL, 1);
661 void Emit1 (unsigned char OPC, ExprNode* Value)
662 /* Emit an instruction with an one byte argument */
670 void Emit2 (unsigned char OPC, ExprNode* Value)
671 /* Emit an instruction with a two byte argument */
679 void Emit3 (unsigned char OPC, ExprNode* Expr)
680 /* Emit an instruction with a three byte argument */
688 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
689 /* Emit an instruction with a three byte argument and separate bank */
698 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
699 /* Emit an opcode with a PC relative argument of one or two bytes */
703 F = NewFragment (FRAG_SEXPR, Size);
709 void EmitData (const unsigned char* Data, unsigned Size)
710 /* Emit data into the current segment */
712 /* Create lots of fragments for the data */
716 /* Determine the length of the next fragment */
718 if (Len > sizeof (F->V.Data)) {
719 Len = sizeof (F->V.Data);
722 /* Create a new fragment */
723 F = NewFragment (FRAG_LITERAL, Len);
726 memcpy (F->V.Data, Data, Len);
737 void EmitByte (ExprNode* Expr)
740 if (IsConstExpr (Expr)) {
741 /* Constant expression, emit literal byte */
742 long Val = GetExprVal (Expr);
744 if ((Val & ~0xFF) != 0) {
749 /* Create a new fragment */
750 Fragment* F = NewFragment (FRAG_EXPR, 1);
759 void EmitWord (ExprNode* Expr)
762 if (IsConstExpr (Expr)) {
763 /* Constant expression, emit literal byte */
764 long Val = GetExprVal (Expr);
766 if ((Val & ~0xFFFF) != 0) {
770 Emit0 ((Val >> 8) & 0xFF);
772 /* Create a new fragment */
773 Fragment* F = NewFragment (FRAG_EXPR, 2);
782 void EmitFarAddr (ExprNode* Expr)
783 /* Emit a 24 bit expression */
785 if (IsConstExpr (Expr)) {
786 /* Constant expression, emit literal byte */
787 long Val = GetExprVal (Expr);
789 if ((Val & ~0xFFFFFF) != 0) {
793 Emit0 ((Val >> 8) & 0xFF);
794 Emit0 ((Val >> 16) & 0xFF);
796 /* Create a new fragment */
797 Fragment* F = NewFragment (FRAG_EXPR, 3);
806 void EmitDWord (ExprNode* Expr)
809 if (IsConstExpr (Expr)) {
810 /* Constant expression, emit literal byte */
811 long Val = GetExprVal (Expr);
814 Emit0 ((Val >> 8) & 0xFF);
815 Emit0 ((Val >> 16) & 0xFF);
816 Emit0 ((Val >> 24) & 0xFF);
818 /* Create a new fragment */
819 Fragment* F = NewFragment (FRAG_EXPR, 4);
828 void EmitFill (unsigned long Count)
829 /* Emit Count fill bytes */
832 /* Calculate the size of the next chunk */
833 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
837 NewFragment (FRAG_FILL, Chunk);