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 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 /* Are we in absolute mode or in relocatable mode? */
66 unsigned long AbsPC = 0; /* PC if in absolute mode */
70 typedef struct Segment Segment;
72 Segment* List; /* List of all segments */
73 Fragment* Root; /* Root of fragment list */
74 Fragment* Last; /* Pointer to last fragment */
75 unsigned Num; /* Segment number */
76 unsigned Align; /* Segment alignment */
78 SegDef* Def; /* Segment definition (name and type) */
82 #define SEG(segdef, num, prev) \
83 { prev, 0, 0, num, 0, 0, segdef }
85 /* Definitions for predefined segments */
86 SegDef NullSegDef = STATIC_SEGDEF_INITIALIZER ("NULL", SEGTYPE_ABS);
87 SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER ("ZEROPAGE", SEGTYPE_ZP);
88 SegDef DataSegDef = STATIC_SEGDEF_INITIALIZER ("DATA", SEGTYPE_ABS);
89 SegDef BssSegDef = STATIC_SEGDEF_INITIALIZER ("BSS", SEGTYPE_ABS);
90 SegDef RODataSegDef = STATIC_SEGDEF_INITIALIZER ("RODATA", SEGTYPE_ABS);
91 SegDef CodeSegDef = STATIC_SEGDEF_INITIALIZER ("CODE", SEGTYPE_ABS);
93 /* Predefined segments */
94 static Segment NullSeg = SEG (&NullSegDef, 5, NULL);
95 static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg);
96 static Segment DataSeg = SEG (&DataSegDef, 3, &ZeropageSeg);
97 static Segment BssSeg = SEG (&BssSegDef, 2, &DataSeg);
98 static Segment RODataSeg = SEG (&RODataSegDef, 1, &BssSeg);
99 static Segment CodeSeg = SEG (&CodeSegDef, 0, &RODataSeg);
101 /* Number of segments */
102 static unsigned SegmentCount = 6;
104 /* List of all segments */
105 static Segment* SegmentList = &CodeSeg;
106 static Segment* SegmentLast = &NullSeg;
108 /* Currently active segment */
109 static Segment* ActiveSeg = &CodeSeg;
113 /*****************************************************************************/
114 /* Segment management */
115 /*****************************************************************************/
119 static Segment* NewSegment (const char* Name, unsigned SegType)
120 /* 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 */
130 if (!ValidSegName (Name)) {
131 Error (ERR_ILLEGAL_SEGMENT, Name);
134 /* Create a new segment */
135 S = xmalloc (sizeof (*S));
141 S->Num = SegmentCount++;
144 S->Def = NewSegDef (Name, SegType);
146 /* Insert it into the segment list */
147 SegmentLast->List = S;
150 /* And return it... */
156 void UseSeg (const SegDef* D)
157 /* Use the segment with the given name */
159 Segment* Seg = SegmentList;
161 if (strcmp (Seg->Def->Name, D->Name) == 0) {
162 /* We found this segment. Check if the type is identical */
163 if (D->Type != SEGTYPE_DEFAULT && Seg->Def->Type != D->Type) {
164 Error (ERR_SEG_ATTR_MISMATCH);
165 /* Use the new attribute to avoid errors */
166 Seg->Def->Type = D->Type;
171 /* Check next segment */
175 /* Segment is not in list, create a new one */
176 if (D->Type == SEGTYPE_DEFAULT) {
177 Seg = NewSegment (D->Name, SEGTYPE_ABS);
179 Seg = NewSegment (D->Name, D->Type);
186 unsigned long GetPC (void)
187 /* Get the program counter of the current segment */
189 return RelocMode? ActiveSeg->PC : AbsPC;
194 void SetAbsPC (unsigned long PC)
195 /* Set the program counter in absolute mode */
203 const SegDef* GetCurrentSeg (void)
204 /* Get a pointer to the segment defininition of the current segment */
206 return ActiveSeg->Def;
211 unsigned GetSegNum (void)
212 /* Get the number of the current segment */
214 return ActiveSeg->Num;
219 void SegAlign (unsigned Power, int Val)
220 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
221 * actual fill value will be determined by the linker), otherwise use the
225 unsigned char Data [4];
226 unsigned long Align = (1UL << Power) - 1;
227 unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
228 unsigned long Count = NewPC - ActiveSeg->PC;
231 /* User defined fill value */
232 memset (Data, Val, sizeof (Data));
234 if (Count > sizeof (Data)) {
235 EmitData (Data, sizeof (Data));
236 Count -= sizeof (Data);
238 EmitData (Data, Count);
243 /* Linker defined fill value */
247 /* Remember the alignment in the header */
248 if (ActiveSeg->Align < Power) {
249 ActiveSeg->Align = Power;
256 /* Return true if the current segment is a zeropage segment */
258 return (ActiveSeg->Def->Type == SEGTYPE_ZP);
264 /* Return true if the current segment is a far segment */
266 return (ActiveSeg->Def->Type == SEGTYPE_FAR);
271 unsigned GetSegType (unsigned SegNum)
272 /* Return the type of the segment with the given number */
274 /* Search for the segment */
275 Segment* S = SegmentList;
276 while (S && SegNum) {
281 /* Did we find it? */
283 FAIL ("Invalid segment number");
286 /* Return the segment type */
293 /* Check the segments for range and other errors */
295 Segment* S = SegmentList;
297 Fragment* F = S->Root;
299 if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
300 F->V.Expr = FinalizeExpr (F->V.Expr);
301 if (IsConstExpr (F->V.Expr)) {
302 /* We are able to evaluate the expression. Get the value
303 * and check for range errors.
306 long Val = GetExprVal (F->V.Expr);
307 int Abs = (F->Type != FRAG_SEXPR);
313 PError (&F->Pos, ERR_RANGE);
316 /* PC relative value */
317 if (Val < -128 || Val > 127) {
318 PError (&F->Pos, ERR_RANGE);
321 } else if (F->Len == 2) {
325 PError (&F->Pos, ERR_RANGE);
328 /* PC relative value */
329 if (Val < -32768 || Val > 32767) {
330 PError (&F->Pos, ERR_RANGE);
335 /* Convert the fragment into a literal fragment */
336 for (I = 0; I < F->Len; ++I) {
337 F->V.Data [I] = Val & 0xFF;
340 F->Type = FRAG_LITERAL;
342 /* We cannot evaluate the expression now, leave the job for
343 * the linker. However, we are able to check for explicit
344 * byte expressions and we will do so.
346 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
347 PError (&F->Pos, ERR_RANGE);
360 /* Dump the contents of all segments */
363 Segment* S = SegmentList;
369 printf ("New segment: %s", S->Def->Name);
372 if (F->Type == FRAG_LITERAL) {
374 printf ("\n Literal:");
378 for (I = 0; I < F->Len; ++I) {
379 printf (" %02X", F->V.Data [I]);
382 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
384 printf ("\n Expression (%u): ", F->Len);
385 DumpExpr (F->V.Expr);
386 } else if (F->Type == FRAG_FILL) {
388 printf ("\n Fill bytes (%u)", F->Len);
390 Internal ("Unknown fragment type: %u", F->Type);
397 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
405 static void WriteOneSeg (Segment* Seg)
406 /* Write one segment to the object file */
409 unsigned LineInfoIndex;
411 /* Write the segment name followed by the byte count in this segment */
412 ObjWriteStr (Seg->Def->Name);
413 ObjWrite32 (Seg->PC);
414 ObjWrite8 (Seg->Align);
415 ObjWrite8 (Seg->Def->Type);
417 /* Now walk through the fragment list for this segment and write the
423 /* Write data depending on the type */
424 switch (Frag->Type) {
427 ObjWrite8 (FRAG_LITERAL);
428 ObjWriteVar (Frag->Len);
429 ObjWriteData (Frag->V.Data, Frag->Len);
434 case 1: ObjWrite8 (FRAG_EXPR8); break;
435 case 2: ObjWrite8 (FRAG_EXPR16); break;
436 case 3: ObjWrite8 (FRAG_EXPR24); break;
437 case 4: ObjWrite8 (FRAG_EXPR32); break;
438 default: Internal ("Invalid fragment size: %u", Frag->Len);
440 WriteExpr (Frag->V.Expr);
445 case 1: ObjWrite8 (FRAG_SEXPR8); break;
446 case 2: ObjWrite8 (FRAG_SEXPR16); break;
447 case 3: ObjWrite8 (FRAG_SEXPR24); break;
448 case 4: ObjWrite8 (FRAG_SEXPR32); break;
449 default: Internal ("Invalid fragment size: %u", Frag->Len);
451 WriteExpr (Frag->V.Expr);
455 ObjWrite8 (FRAG_FILL);
456 ObjWriteVar (Frag->Len);
460 Internal ("Invalid fragment type: %u", Frag->Type);
464 /* Write the file position of this fragment */
465 ObjWritePos (&Frag->Pos);
467 /* Write extra line info for this fragment. Zero is considered
468 * "no line info", so add one to the value.
470 LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
471 ObjWriteVar (LineInfoIndex);
480 void WriteSegments (void)
481 /* Write the segment data to the object file */
485 /* Tell the object file module that we're about to start the seg list */
488 /* First thing is segment count */
489 ObjWriteVar (SegmentCount);
491 /* Now walk through all segments and write them to the object file */
494 /* Write one segment */
500 /* Done writing segments */
506 /*****************************************************************************/
508 /*****************************************************************************/
512 static void IncPC (unsigned Value)
513 /* Increment the PC counter */
515 ActiveSeg->PC += Value;
523 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
524 /* Create, initialize and return a new fragment. The fragment will be inserted
525 * into the current segment.
530 /* Create a new fragment */
531 F = xmalloc (sizeof (*F));
538 F->LI = UseLineInfo (CurLineInfo);
542 /* Insert it into the list of all segments */
550 /* Insert it into the current segment */
551 if (ActiveSeg->Root) {
552 ActiveSeg->Last->Next = F;
555 ActiveSeg->Root = ActiveSeg->Last = F;
558 /* Add this fragment to the current listing line */
560 if (LineCur->FragList == 0) {
561 LineCur->FragList = F;
563 LineCur->FragLast->LineList = F;
565 LineCur->FragLast = F;
568 /* Increment the program counter */
577 void Emit0 (unsigned char OPC)
578 /* Emit an instruction with a zero sized operand */
580 /* First fragment, wrong type or out of space, create new one */
581 Fragment* F = NewFragment (FRAG_LITERAL, 1);
587 void Emit1 (unsigned char OPC, ExprNode* Value)
588 /* Emit an instruction with an one byte argument */
596 void Emit2 (unsigned char OPC, ExprNode* Value)
597 /* Emit an instruction with a two byte argument */
605 void Emit3 (unsigned char OPC, ExprNode* Expr)
606 /* Emit an instruction with a three byte argument */
614 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
615 /* Emit an instruction with a three byte argument and separate bank */
624 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
625 /* Emit an opcode with a PC relative argument of one or two bytes */
629 F = NewFragment (FRAG_SEXPR, Size);
635 void EmitData (const unsigned char* Data, unsigned Size)
636 /* Emit data into the current segment */
638 /* Create lots of fragments for the data */
642 /* Determine the length of the next fragment */
644 if (Len > sizeof (F->V.Data)) {
645 Len = sizeof (F->V.Data);
648 /* Create a new fragment */
649 F = NewFragment (FRAG_LITERAL, Len);
652 memcpy (F->V.Data, Data, Len);
663 void EmitByte (ExprNode* Expr)
666 if (IsConstExpr (Expr)) {
667 /* Constant expression, emit literal byte */
668 long Val = GetExprVal (Expr);
670 if ((Val & ~0xFF) != 0) {
675 /* Create a new fragment */
676 Fragment* F = NewFragment (FRAG_EXPR, 1);
685 void EmitWord (ExprNode* Expr)
688 if (IsConstExpr (Expr)) {
689 /* Constant expression, emit literal byte */
690 long Val = GetExprVal (Expr);
692 if ((Val & ~0xFFFF) != 0) {
696 Emit0 ((Val >> 8) & 0xFF);
698 /* Create a new fragment */
699 Fragment* F = NewFragment (FRAG_EXPR, 2);
708 void EmitFarAddr (ExprNode* Expr)
709 /* Emit a 24 bit expression */
711 if (IsConstExpr (Expr)) {
712 /* Constant expression, emit literal byte */
713 long Val = GetExprVal (Expr);
715 if ((Val & ~0xFFFFFF) != 0) {
719 Emit0 ((Val >> 8) & 0xFF);
720 Emit0 ((Val >> 16) & 0xFF);
722 /* Create a new fragment */
723 Fragment* F = NewFragment (FRAG_EXPR, 3);
732 void EmitDWord (ExprNode* Expr)
735 if (IsConstExpr (Expr)) {
736 /* Constant expression, emit literal byte */
737 long Val = GetExprVal (Expr);
740 Emit0 ((Val >> 8) & 0xFF);
741 Emit0 ((Val >> 16) & 0xFF);
742 Emit0 ((Val >> 24) & 0xFF);
744 /* Create a new fragment */
745 Fragment* F = NewFragment (FRAG_EXPR, 4);
754 void EmitFill (unsigned long Count)
755 /* Emit Count fill bytes */
758 /* Calculate the size of the next chunk */
759 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
763 NewFragment (FRAG_FILL, Chunk);