]> git.sur5r.net Git - cc65/blob - src/cc65/codeseg.c
c27f44b3d9b9898cd35e2460fd7344563c08238f
[cc65] / src / cc65 / codeseg.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeseg.c                                 */
4 /*                                                                           */
5 /*                          Code segment structure                           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2004 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
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 <ctype.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "debugflag.h"
43 #include "global.h"
44 #include "hashstr.h"
45 #include "strutil.h"
46 #include "xmalloc.h"
47 #include "xsprintf.h"
48
49 /* cc65 */
50 #include "asmlabel.h"
51 #include "codeent.h"
52 #include "codeinfo.h"
53 #include "codeseg.h"
54 #include "datatype.h"
55 #include "error.h"
56 #include "global.h"
57 #include "ident.h"
58 #include "symentry.h"
59
60
61
62 /*****************************************************************************/
63 /*                             Helper functions                              */
64 /*****************************************************************************/
65
66
67
68 static void CS_PrintFunctionHeader (const CodeSeg* S, FILE* F)
69 /* Print a comment with the function signature to the given file */
70 {
71     /* Get the associated function */
72     const SymEntry* Func = S->Func;
73
74     /* If this is a global code segment, do nothing */
75     if (Func) {
76         fprintf (F,
77                  "; ---------------------------------------------------------------\n"
78                  "; ");
79         PrintFuncSig (F, Func->Name, Func->Type);
80         fprintf (F,
81                  "\n"
82                  "; ---------------------------------------------------------------\n"
83                  "\n");
84     }
85 }
86
87
88
89 static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E)
90 /* Move all labels from the label pool to the given entry and remove them
91  * from the pool.
92  */
93 {
94     /* Transfer the labels if we have any */
95     unsigned I;
96     unsigned LabelCount = CollCount (&S->Labels);
97     for (I = 0; I < LabelCount; ++I) {
98
99         /* Get the label */
100         CodeLabel* L = CollAt (&S->Labels, I);
101
102         /* Attach it to the entry */
103         CE_AttachLabel (E, L);
104     }
105
106     /* Delete the transfered labels */
107     CollDeleteAll (&S->Labels);
108 }
109
110
111
112 static void CS_MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
113 /* Move the labels of the code entry E to the label pool of the code segment */
114 {
115     unsigned LabelCount = CE_GetLabelCount (E);
116     while (LabelCount--) {
117         CodeLabel* L = CE_GetLabel (E, LabelCount);
118         L->Owner = 0;
119         CollAppend (&S->Labels, L);
120     }
121     CollDeleteAll (&E->Labels);
122 }
123
124
125
126 static CodeLabel* CS_FindLabel (CodeSeg* S, const char* Name, unsigned Hash)
127 /* Find the label with the given name. Return the label or NULL if not found */
128 {
129     /* Get the first hash chain entry */
130     CodeLabel* L = S->LabelHash[Hash];
131
132     /* Search the list */
133     while (L) {
134         if (strcmp (Name, L->Name) == 0) {
135             /* Found */
136             break;
137         }
138         L = L->Next;
139     }
140     return L;
141 }
142
143
144
145 static CodeLabel* CS_NewCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
146 /* Create a new label and insert it into the label hash table */
147 {
148     /* Create a new label */
149     CodeLabel* L = NewCodeLabel (Name, Hash);
150
151     /* Enter the label into the hash table */
152     L->Next = S->LabelHash[L->Hash];
153     S->LabelHash[L->Hash] = L;
154
155     /* Return the new label */
156     return L;
157 }
158
159
160
161 static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
162 /* Remove the given code label from the hash list */
163 {
164     /* Get the first entry in the hash chain */
165     CodeLabel* List = S->LabelHash[L->Hash];
166     CHECK (List != 0);
167
168     /* First, remove the label from the hash chain */
169     if (List == L) {
170         /* First entry in hash chain */
171         S->LabelHash[L->Hash] = L->Next;
172     } else {
173         /* Must search through the chain */
174         while (List->Next != L) {
175             /* If we've reached the end of the chain, something is *really* wrong */
176             CHECK (List->Next != 0);
177             /* Next entry */
178             List = List->Next;
179         }
180         /* The next entry is the one, we have been searching for */
181         List->Next = L->Next;
182     }
183 }
184
185
186
187 /*****************************************************************************/
188 /*                    Functions for parsing instructions                     */
189 /*****************************************************************************/
190
191
192
193 static const char* SkipSpace (const char* S)
194 /* Skip white space and return an updated pointer */
195 {
196     while (IsSpace (*S)) {
197         ++S;
198     }
199     return S;
200 }
201
202
203
204 static const char* ReadToken (const char* L, const char* Term,
205                               char* Buf, unsigned BufSize)
206 /* Read the next token into Buf, return the updated line pointer. The
207  * token is terminated by one of the characters given in term.
208  */
209 {
210     /* Read/copy the token */
211     unsigned I = 0;
212     unsigned ParenCount = 0;
213     while (*L && (ParenCount > 0 || strchr (Term, *L) == 0)) {
214         if (I < BufSize-1) {
215             Buf[I] = *L;
216         } else if (I == BufSize-1) {
217             /* Cannot store this character, this is an input error (maybe
218              * identifier too long or similar).
219              */
220             Error ("ASM code error: syntax error");
221         }
222         ++I;
223         if (*L == ')') {
224             --ParenCount;
225         } else if (*L == '(') {
226             ++ParenCount;
227         }
228         ++L;
229     }
230
231     /* Terminate the buffer contents */
232     Buf[I] = '\0';
233
234     /* Return the updated line pointer */
235     return L;
236 }
237
238
239
240 static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
241 /* Parse an instruction nnd generate a code entry from it. If the line contains
242  * errors, output an error message and return NULL.
243  * For simplicity, we don't accept the broad range of input a "real" assembler
244  * does. The instruction and the argument are expected to be separated by
245  * white space, for example.
246  */
247 {
248     char                Mnemo[IDENTSIZE+10];
249     const OPCDesc*      OPC;
250     am_t                AM = 0;         /* Initialize to keep gcc silent */
251     char                Arg[IDENTSIZE+10];
252     char                Reg;
253     CodeEntry*          E;
254     CodeLabel*          Label;
255
256     /* Read the first token and skip white space after it */
257     L = SkipSpace (ReadToken (L, " \t:", Mnemo, sizeof (Mnemo)));
258
259     /* Check if we have a label */
260     if (*L == ':') {
261
262         /* Skip the colon and following white space */
263         L = SkipSpace (L+1);
264
265         /* Add the label */
266         CS_AddLabel (S, Mnemo);
267
268         /* If we have reached end of line, bail out, otherwise a mnemonic
269          * may follow.
270          */
271         if (*L == '\0') {
272             return 0;
273         }
274
275         L = SkipSpace (ReadToken (L, " \t", Mnemo, sizeof (Mnemo)));
276     }
277
278     /* Try to find the opcode description for the mnemonic */
279     OPC = FindOP65 (Mnemo);
280
281     /* If we didn't find the opcode, print an error and bail out */
282     if (OPC == 0) {
283         Error ("ASM code error: %s is not a valid mnemonic", Mnemo);
284         return 0;
285     }
286
287     /* Get the addressing mode */
288     Arg[0] = '\0';
289     switch (*L) {
290
291         case '\0':
292             /* Implicit */
293             AM = AM65_IMP;
294             break;
295
296         case '#':
297             /* Immidiate */
298             StrCopy (Arg, sizeof (Arg), L+1);
299             AM = AM65_IMM;
300             break;
301
302         case '(':
303             /* Indirect */
304             L = ReadToken (L+1, ",)", Arg, sizeof (Arg));
305
306             /* Check for errors */
307             if (*L == '\0') {
308                 Error ("ASM code error: syntax error");
309                 return 0;
310             }
311
312             /* Check the different indirect modes */
313             if (*L == ',') {
314                 /* Expect zp x indirect */
315                 L = SkipSpace (L+1);
316                 if (toupper (*L) != 'X') {
317                     Error ("ASM code error: `X' expected");
318                     return 0;
319                 }
320                 L = SkipSpace (L+1);
321                 if (*L != ')') {
322                     Error ("ASM code error: `)' expected");
323                     return 0;
324                 }
325                 L = SkipSpace (L+1);
326                 if (*L != '\0') {
327                     Error ("ASM code error: syntax error");
328                     return 0;
329                 }
330                 AM = AM65_ZPX_IND;
331             } else if (*L == ')') {
332                 /* zp indirect or zp indirect, y */
333                 L = SkipSpace (L+1);
334                 if (*L == ',') {
335                     L = SkipSpace (L+1);
336                     if (toupper (*L) != 'Y') {
337                         Error ("ASM code error: `Y' expected");
338                         return 0;
339                     }
340                     L = SkipSpace (L+1);
341                     if (*L != '\0') {
342                         Error ("ASM code error: syntax error");
343                         return 0;
344                     }
345                     AM = AM65_ZP_INDY;
346                 } else if (*L == '\0') {
347                     AM = AM65_ZP_IND;
348                 } else {
349                     Error ("ASM code error: syntax error");
350                     return 0;
351                 }
352             }
353             break;
354
355         case 'a':
356         case 'A':
357             /* Accumulator? */
358             if (L[1] == '\0') {
359                 AM = AM65_ACC;
360                 break;
361             }
362             /* FALLTHROUGH */
363
364         default:
365             /* Absolute, maybe indexed */
366             L = ReadToken (L, ",", Arg, sizeof (Arg));
367             if (*L == '\0') {
368                 /* Absolute, zeropage or branch */
369                 if ((OPC->Info & OF_BRA) != 0) {
370                     /* Branch */
371                     AM = AM65_BRA;
372                 } else if (GetZPInfo(Arg) != 0) {
373                     AM = AM65_ZP;
374                 } else {
375                     AM = AM65_ABS;
376                 }
377             } else if (*L == ',') {
378                 /* Indexed */
379                 L = SkipSpace (L+1);
380                 if (*L == '\0') {
381                     Error ("ASM code error: syntax error");
382                     return 0;
383                 } else {
384                     Reg = toupper (*L);
385                     L = SkipSpace (L+1);
386                     if (Reg == 'X') {
387                         if (GetZPInfo(Arg) != 0) {
388                             AM = AM65_ZPX;
389                         } else {
390                             AM = AM65_ABSX;
391                         }
392                     } else if (Reg == 'Y') {
393                         AM = AM65_ABSY;
394                     } else {
395                         Error ("ASM code error: syntax error");
396                         return 0;
397                     }
398                     if (*L != '\0') {
399                         Error ("ASM code error: syntax error");
400                         return 0;
401                     }
402                 }
403             }
404             break;
405
406     }
407
408     /* If the instruction is a branch, check for the label and generate it
409      * if it does not exist. This may lead to unused labels (if the label
410      * is actually an external one) which are removed by the CS_MergeLabels
411      * function later.
412      */
413     Label = 0;
414     if (AM == AM65_BRA) {
415
416         /* Generate the hash over the label, then search for the label */
417         unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
418         Label = CS_FindLabel (S, Arg, Hash);
419
420         /* If we don't have the label, it's a forward ref - create it */
421         if (Label == 0) {
422             /* Generate a new label */
423             Label = CS_NewCodeLabel (S, Arg, Hash);
424         }
425     }
426
427     /* We do now have the addressing mode in AM. Allocate a new CodeEntry
428      * structure and initialize it.
429      */
430     E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);
431
432     /* Return the new code entry */
433     return E;
434 }
435
436
437
438 /*****************************************************************************/
439 /*                                   Code                                    */
440 /*****************************************************************************/
441
442
443
444 CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
445 /* Create a new code segment, initialize and return it */
446 {
447     unsigned I;
448     const type* RetType;
449
450     /* Allocate memory */
451     CodeSeg* S = xmalloc (sizeof (CodeSeg));
452
453     /* Initialize the fields */
454     S->SegName  = xstrdup (SegName);
455     S->Func     = Func;
456     InitCollection (&S->Entries);
457     InitCollection (&S->Labels);
458     for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) {
459         S->LabelHash[I] = 0;
460     }
461
462     /* If we have a function given, get the return type of the function.
463      * Assume ANY return type besides void will use the A and X registers.
464      */
465     if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) {
466         if (SizeOf (RetType) == SizeOf (type_long)) {
467             S->ExitRegs = REG_EAX;
468         } else {
469             S->ExitRegs = REG_AX;
470         }
471     } else {
472         S->ExitRegs = REG_NONE;
473     }
474
475     /* Copy the global optimization settings */
476     S->Optimize       = (unsigned char) IS_Get (&Optimize);
477     S->CodeSizeFactor = (unsigned) IS_Get (&CodeSizeFactor);
478
479     /* Return the new struct */
480     return S;
481 }
482
483
484
485 void CS_AddEntry (CodeSeg* S, struct CodeEntry* E)
486 /* Add an entry to the given code segment */
487 {
488     /* Transfer the labels if we have any */
489     CS_MoveLabelsToEntry (S, E);
490
491     /* Add the entry to the list of code entries in this segment */
492     CollAppend (&S->Entries, E);
493 }
494
495
496
497 void CS_AddVLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap)
498 /* Add a line to the given code segment */
499 {
500     const char* L;
501     CodeEntry*  E;
502     char        Token[IDENTSIZE+10];
503
504     /* Format the line */
505     char Buf [256];
506     xvsprintf (Buf, sizeof (Buf), Format, ap);
507
508     /* Skip whitespace */
509     L = SkipSpace (Buf);
510
511     /* Check which type of instruction we have */
512     E = 0;      /* Assume no insn created */
513     switch (*L) {
514
515         case '\0':
516             /* Empty line, just ignore it */
517             break;
518
519         case ';':
520             /* Comment or hint, ignore it for now */
521             break;
522
523         case '.':
524             /* Control instruction */
525             ReadToken (L, " \t", Token, sizeof (Token));
526             Error ("ASM code error: Pseudo instruction `%s' not supported", Token);
527             break;
528
529         default:
530             E = ParseInsn (S, LI, L);
531             break;
532     }
533
534     /* If we have a code entry, transfer the labels and insert it */
535     if (E) {
536         CS_AddEntry (S, E);
537     }
538 }
539
540
541
542 void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...)
543 /* Add a line to the given code segment */
544 {
545     va_list ap;
546     va_start (ap, Format);
547     CS_AddVLine (S, LI, Format, ap);
548     va_end (ap);
549 }
550
551
552
553 void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
554 /* Insert the code entry at the index given. Following code entries will be
555  * moved to slots with higher indices.
556  */
557 {
558     /* Insert the entry into the collection */
559     CollInsert (&S->Entries, E, Index);
560 }
561
562
563
564 void CS_DelEntry (CodeSeg* S, unsigned Index)
565 /* Delete an entry from the code segment. This includes moving any associated
566  * labels, removing references to labels and even removing the referenced labels
567  * if the reference count drops to zero.
568  * Note: Labels are moved forward if possible, that is, they are moved to the
569  * next insn (not the preceeding one).
570  */
571 {
572     /* Get the code entry for the given index */
573     CodeEntry* E = CS_GetEntry (S, Index);
574
575     /* If the entry has a labels, we have to move this label to the next insn.
576      * If there is no next insn, move the label into the code segement label
577      * pool. The operation is further complicated by the fact that the next
578      * insn may already have a label. In that case change all reference to
579      * this label and delete the label instead of moving it.
580      */
581     unsigned Count = CE_GetLabelCount (E);
582     if (Count > 0) {
583
584         /* The instruction has labels attached. Check if there is a next
585          * instruction.
586          */
587         if (Index == CS_GetEntryCount (S)-1) {
588
589             /* No next instruction, move to the codeseg label pool */
590             CS_MoveLabelsToPool (S, E);
591
592         } else {
593
594             /* There is a next insn, get it */
595             CodeEntry* N = CS_GetEntry (S, Index+1);
596
597             /* Move labels to the next entry */
598             CS_MoveLabels (S, E, N);
599
600         }
601     }
602
603     /* If this insn references a label, remove the reference. And, if the
604      * the reference count for this label drops to zero, remove this label.
605      */
606     if (E->JumpTo) {
607         /* Remove the reference */
608         CS_RemoveLabelRef (S, E);
609     }
610
611     /* Delete the pointer to the insn */
612     CollDelete (&S->Entries, Index);
613
614     /* Delete the instruction itself */
615     FreeCodeEntry (E);
616 }
617
618
619
620 void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count)
621 /* Delete a range of code entries. This includes removing references to labels,
622  * labels attached to the entries and so on.
623  */
624 {
625     /* Start deleting the entries from the rear, because this involves less
626      * memory moving.
627      */
628     while (Count--) {
629         CS_DelEntry (S, Start + Count);
630     }
631 }
632
633
634
635 void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos)
636 /* Move a range of entries from one position to another. Start is the index
637  * of the first entry to move, Count is the number of entries and NewPos is
638  * the index of the target entry. The entry with the index Start will later
639  * have the index NewPos. All entries with indices NewPos and above are
640  * moved to higher indices. If the code block is moved to the end of the
641  * current code, and if pending labels exist, these labels will get attached
642  * to the first instruction of the moved block (the first one after the
643  * current code end)
644  */
645 {
646     /* If NewPos is at the end of the code segment, move any labels from the
647      * label pool to the first instruction of the moved range.
648      */
649     if (NewPos == CS_GetEntryCount (S)) {
650         CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start));
651     }
652
653     /* Move the code block to the destination */
654     CollMoveMultiple (&S->Entries, Start, Count, NewPos);
655 }
656
657
658
659 struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index)
660 /* Get the code entry preceeding the one with the index Index. If there is no
661  * preceeding code entry, return NULL.
662  */
663 {
664     if (Index == 0) {
665         /* This is the first entry */
666         return 0;
667     } else {
668         /* Previous entry available */
669         return CollAtUnchecked (&S->Entries, Index-1);
670     }
671 }
672
673
674
675 struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index)
676 /* Get the code entry following the one with the index Index. If there is no
677  * following code entry, return NULL.
678  */
679 {
680     if (Index >= CollCount (&S->Entries)-1) {
681         /* This is the last entry */
682         return 0;
683     } else {
684         /* Code entries left */
685         return CollAtUnchecked (&S->Entries, Index+1);
686     }
687 }
688
689
690
691 int CS_GetEntries (CodeSeg* S, struct CodeEntry** List,
692                    unsigned Start, unsigned Count)
693 /* Get Count code entries into List starting at index start. Return true if
694  * we got the lines, return false if not enough lines were available.
695  */
696 {
697     /* Check if enough entries are available */
698     if (Start + Count > CollCount (&S->Entries)) {
699         return 0;
700     }
701
702     /* Copy the entries */
703     while (Count--) {
704         *List++ = CollAtUnchecked (&S->Entries, Start++);
705     }
706
707     /* We have the entries */
708     return 1;
709 }
710
711
712
713 unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E)
714 /* Return the index of a code entry */
715 {
716     int Index = CollIndex (&S->Entries, E);
717     CHECK (Index >= 0);
718     return Index;
719 }
720
721
722
723 int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
724 /* Return true if any of the code entries in the given range has a label
725  * attached. If the code segment does not span the given range, check the
726  * possible span instead.
727  */
728 {
729     unsigned EntryCount = CS_GetEntryCount(S);
730
731     /* Adjust count. We expect at least Start to be valid. */
732     CHECK (Start < EntryCount);
733     if (Start + Count > EntryCount) {
734         Count = EntryCount - Start;
735     }
736
737     /* Check each entry. Since we have validated the index above, we may
738      * use the unchecked access function in the loop which is faster.
739      */
740     while (Count--) {
741         const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++);
742         if (CE_HasLabel (E)) {
743             return 1;
744         }
745     }
746
747     /* No label in the complete range */
748     return 0;
749 }
750
751
752
753 CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name)
754 /* Add a code label for the next instruction to follow */
755 {
756     /* Calculate the hash from the name */
757     unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
758
759     /* Try to find the code label if it does already exist */
760     CodeLabel* L = CS_FindLabel (S, Name, Hash);
761
762     /* Did we find it? */
763     if (L) {
764         /* We found it - be sure it does not already have an owner */
765         if (L->Owner) {
766             Error ("ASM label `%s' is already defined", Name);
767             return L;
768         }
769     } else {
770         /* Not found - create a new one */
771         L = CS_NewCodeLabel (S, Name, Hash);
772     }
773
774     /* Safety. This call is quite costly, but safety is better */
775     if (CollIndex (&S->Labels, L) >= 0) {
776         Error ("ASM label `%s' is already defined", Name);
777         return L;
778     }
779
780     /* We do now have a valid label. Remember it for later */
781     CollAppend (&S->Labels, L);
782
783     /* Return the label */
784     return L;
785 }
786
787
788
789 CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E)
790 /* If the code entry E does already have a label, return it. Otherwise
791  * create a new label, attach it to E and return it.
792  */
793 {
794     CodeLabel* L;
795
796     if (CE_HasLabel (E)) {
797
798         /* Get the label from this entry */
799         L = CE_GetLabel (E, 0);
800
801     } else {
802
803         /* Get a new name */
804         const char* Name = LocalLabelName (GetLocalLabel ());
805
806         /* Generate the hash over the name */
807         unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
808
809         /* Create a new label */
810         L = CS_NewCodeLabel (S, Name, Hash);
811
812         /* Attach this label to the code entry */
813         CE_AttachLabel (E, L);
814
815     }
816
817     /* Return the label */
818     return L;
819 }
820
821
822
823 void CS_DelLabel (CodeSeg* S, CodeLabel* L)
824 /* Remove references from this label and delete it. */
825 {
826     unsigned Count, I;
827
828     /* First, remove the label from the hash chain */
829     CS_RemoveLabelFromHash (S, L);
830
831     /* Remove references from insns jumping to this label */
832     Count = CollCount (&L->JumpFrom);
833     for (I = 0; I < Count; ++I) {
834         /* Get the insn referencing this label */
835         CodeEntry* E = CollAt (&L->JumpFrom, I);
836         /* Remove the reference */
837         CE_ClearJumpTo (E);
838     }
839     CollDeleteAll (&L->JumpFrom);
840
841     /* Remove the reference to the owning instruction if it has one. The
842      * function may be called for a label without an owner when deleting
843      * unfinished parts of the code. This is unfortunate since it allows
844      * errors to slip through.
845      */
846     if (L->Owner) {
847         CollDeleteItem (&L->Owner->Labels, L);
848     }
849
850     /* All references removed, delete the label itself */
851     FreeCodeLabel (L);
852 }
853
854
855
856 void CS_MergeLabels (CodeSeg* S)
857 /* Merge code labels. That means: For each instruction, remove all labels but
858  * one and adjust references accordingly.
859  */
860 {
861     unsigned I;
862     unsigned J;
863
864     /* First, remove all labels from the label symbol table that don't have an
865      * owner (this means that they are actually external labels but we didn't
866      * know that previously since they may have also been forward references).
867      */
868     for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) {
869
870         /* Get the first label in this hash chain */
871         CodeLabel** L = &S->LabelHash[I];
872         while (*L) {
873             if ((*L)->Owner == 0) {
874
875                 /* The label does not have an owner, remove it from the chain */
876                 CodeLabel* X = *L;
877                 *L = X->Next;
878
879                 /* Cleanup any entries jumping to this label */
880                 for (J = 0; J < CL_GetRefCount (X); ++J) {
881                     /* Get the entry referencing this label */
882                     CodeEntry* E = CL_GetRef (X, J);
883                     /* And remove the reference. Do NOT call CE_ClearJumpTo
884                      * here, because this will also clear the label name,
885                      * which is not what we want.
886                      */
887                     E->JumpTo = 0;
888                 }
889
890                 /* Print some debugging output */
891                 if (Debug) {
892                     printf ("Removing unused global label `%s'", X->Name);
893                 }
894
895                 /* And free the label */
896                 FreeCodeLabel (X);
897             } else {
898                 /* Label is owned, point to next code label pointer */
899                 L = &((*L)->Next);
900             }
901         }
902     }
903
904     /* Walk over all code entries */
905     for (I = 0; I < CS_GetEntryCount (S); ++I) {
906
907         CodeLabel* RefLab;
908         unsigned   J;
909
910         /* Get a pointer to the next entry */
911         CodeEntry* E = CS_GetEntry (S, I);
912
913         /* If this entry has zero labels, continue with the next one */
914         unsigned LabelCount = CE_GetLabelCount (E);
915         if (LabelCount == 0) {
916             continue;
917         }
918
919         /* We have at least one label. Use the first one as reference label. */
920         RefLab = CE_GetLabel (E, 0);
921
922         /* Walk through the remaining labels and change references to these
923          * labels to a reference to the one and only label. Delete the labels
924          * that are no longer used. To increase performance, walk backwards
925          * through the list.
926          */
927         for (J = LabelCount-1; J >= 1; --J) {
928
929             /* Get the next label */
930             CodeLabel* L = CE_GetLabel (E, J);
931
932             /* Move all references from this label to the reference label */
933             CL_MoveRefs (L, RefLab);
934
935             /* Remove the label completely. */
936             CS_DelLabel (S, L);
937         }
938
939         /* The reference label is the only remaining label. Check if there
940          * are any references to this label, and delete it if this is not
941          * the case.
942          */
943         if (CollCount (&RefLab->JumpFrom) == 0) {
944             /* Delete the label */
945             CS_DelLabel (S, RefLab);
946         }
947     }
948 }
949
950
951
952 void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
953 /* Move all labels from Old to New. The routine will move the labels itself
954  * if New does not have any labels, and move references if there is at least
955  * a label for new. If references are moved, the old label is deleted
956  * afterwards.
957  */
958 {
959     /* Get the number of labels to move */
960     unsigned OldLabelCount = CE_GetLabelCount (Old);
961
962     /* Does the new entry have itself a label? */
963     if (CE_HasLabel (New)) {
964
965         /* The new entry does already have a label - move references */
966         CodeLabel* NewLabel = CE_GetLabel (New, 0);
967         while (OldLabelCount--) {
968
969             /* Get the next label */
970             CodeLabel* OldLabel = CE_GetLabel (Old, OldLabelCount);
971
972             /* Move references */
973             CL_MoveRefs (OldLabel, NewLabel);
974
975             /* Delete the label */
976             CS_DelLabel (S, OldLabel);
977
978         }
979
980     } else {
981
982         /* The new entry does not have a label, just move them */
983         while (OldLabelCount--) {
984
985             /* Move the label to the new entry */
986             CE_MoveLabel (CE_GetLabel (Old, OldLabelCount), New);
987
988         }
989
990     }
991 }
992
993
994
995 void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E)
996 /* Remove the reference between E and the label it jumps to. The reference
997  * will be removed on both sides and E->JumpTo will be 0 after that. If
998  * the reference was the only one for the label, the label will get
999  * deleted.
1000  */
1001 {
1002     /* Get a pointer to the label and make sure it exists */
1003     CodeLabel* L = E->JumpTo;
1004     CHECK (L != 0);
1005
1006     /* Delete the entry from the label */
1007     CollDeleteItem (&L->JumpFrom, E);
1008
1009     /* The entry jumps no longer to L */
1010     CE_ClearJumpTo (E);
1011
1012     /* If there are no more references, delete the label */
1013     if (CollCount (&L->JumpFrom) == 0) {
1014         CS_DelLabel (S, L);
1015     }
1016 }
1017
1018
1019
1020 void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
1021 /* Change the reference of E to L instead of the current one. If this
1022  * was the only reference to the old label, the old label will get
1023  * deleted.
1024  */
1025 {
1026     /* Get the old label */
1027     CodeLabel* OldLabel = E->JumpTo;
1028
1029     /* Be sure that code entry references a label */
1030     PRECONDITION (OldLabel != 0);
1031
1032     /* Remove the reference to our label */
1033     CS_RemoveLabelRef (S, E);
1034
1035     /* Use the new label */
1036     CL_AddRef (L, E);
1037 }
1038
1039
1040
1041 void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
1042 /* Delete all entries including the given one */
1043 {
1044     /* Get the number of entries in this segment */
1045     unsigned Count = CS_GetEntryCount (S);
1046
1047     /* First pass: Delete all references to labels. If the reference count
1048      * for a label drops to zero, delete it.
1049      */
1050     unsigned C = Count;
1051     while (Last < C--) {
1052
1053         /* Get the next entry */
1054         CodeEntry* E = CS_GetEntry (S, C);
1055
1056         /* Check if this entry has a label reference */
1057         if (E->JumpTo) {
1058             /* If the label is a label in the label pool and this is the last
1059              * reference to the label, remove the label from the pool.
1060              */
1061             CodeLabel* L = E->JumpTo;
1062             int Index = CollIndex (&S->Labels, L);
1063             if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
1064                 /* Delete it from the pool */
1065                 CollDelete (&S->Labels, Index);
1066             }
1067
1068             /* Remove the reference to the label */
1069             CS_RemoveLabelRef (S, E);
1070         }
1071
1072     }
1073
1074     /* Second pass: Delete the instructions. If a label attached to an
1075      * instruction still has references, it must be references from outside
1076      * the deleted area. Don't delete the label in this case, just make it
1077      * ownerless and move it to the label pool.
1078      */
1079     C = Count;
1080     while (Last < C--) {
1081
1082         /* Get the next entry */
1083         CodeEntry* E = CS_GetEntry (S, C);
1084
1085         /* Check if this entry has a label attached */
1086         if (CE_HasLabel (E)) {
1087             /* Move the labels to the pool and clear the owner pointer */
1088             CS_MoveLabelsToPool (S, E);
1089         }
1090
1091         /* Delete the pointer to the entry */
1092         CollDelete (&S->Entries, C);
1093
1094         /* Delete the entry itself */
1095         FreeCodeEntry (E);
1096     }
1097 }
1098
1099
1100
1101 void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last)
1102 /* Remove all user marks from the entries in the given range */
1103 {
1104     while (First <= Last) {
1105         CE_ResetMark (CS_GetEntry (S, First++));
1106     }
1107 }
1108
1109
1110
1111 int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
1112 /* Check if the given code segment range is a basic block. That is, check if
1113  * First is the only entrance and Last is the only exit. This means that no
1114  * jump/branch inside the block may jump to an insn below First or after(!)
1115  * Last, and that no insn may jump into this block from the outside.
1116  */
1117 {
1118     unsigned I;
1119
1120     /* Don't accept invalid ranges */
1121     CHECK (First <= Last);
1122
1123     /* First pass: Walk over the range and remove all marks from the entries */
1124     CS_ResetMarks (S, First, Last);
1125
1126     /* Second pass: Walk over the range checking all labels. Note: There may be
1127      * label on the first insn which is ok.
1128      */
1129     I = First + 1;
1130     while (I <= Last) {
1131
1132         /* Get the next entry */
1133         CodeEntry* E = CS_GetEntry (S, I);
1134
1135         /* Check if this entry has one or more labels, if so, check which
1136          * entries jump to this label.
1137          */
1138         unsigned LabelCount = CE_GetLabelCount (E);
1139         unsigned LabelIndex;
1140         for (LabelIndex = 0; LabelIndex < LabelCount; ++LabelIndex) {
1141
1142             /* Get this label */
1143             CodeLabel* L = CE_GetLabel (E, LabelIndex);
1144
1145             /* Walk over all entries that jump to this label. Check for each
1146              * of the entries if it is out of the range.
1147              */
1148             unsigned RefCount = CL_GetRefCount (L);
1149             unsigned RefIndex;
1150             for (RefIndex = 0; RefIndex < RefCount; ++RefIndex) {
1151
1152                 /* Get the code entry that jumps here */
1153                 CodeEntry* Ref = CL_GetRef (L, RefIndex);
1154
1155                 /* Walk over out complete range and check if we find the
1156                  * refering entry. This is cheaper than using CS_GetEntryIndex,
1157                  * because CS_GetEntryIndex will search the complete code
1158                  * segment and not just our range.
1159                  */
1160                 unsigned J;
1161                 for (J = First; J <= Last; ++J) {
1162                     if (Ref == CS_GetEntry (S, J)) {
1163                         break;
1164                     }
1165                 }
1166                 if (J > Last) {
1167                     /* We did not find the entry. This means that the jump to
1168                      * out code segment entry E came from outside the range,
1169                      * which in turn means that the given range is not a basic
1170                      * block.
1171                      */
1172                     CS_ResetMarks (S, First, Last);
1173                     return 0;
1174                 }
1175
1176                 /* If we come here, we found the entry. Mark it, so we know
1177                  * that the branch to the label is in range.
1178                  */
1179                 CE_SetMark (Ref);
1180             }
1181         }
1182
1183         /* Next entry */
1184         ++I;
1185     }
1186
1187     /* Third pass: Walk again over the range and check all branches. If we
1188      * find a branch that is not marked, its target is not inside the range
1189      * (since we checked all the labels in the range before).
1190      */
1191     I = First;
1192     while (I <= Last) {
1193
1194         /* Get the next entry */
1195         CodeEntry* E = CS_GetEntry (S, I);
1196
1197         /* Check if this is a branch and if so, if it has a mark */
1198         if (E->Info & (OF_UBRA | OF_CBRA)) {
1199             if (!CE_HasMark (E)) {
1200                 /* No mark means not a basic block. Before bailing out, be sure
1201                  * to remove the marks from the remaining entries.
1202                  */
1203                 CS_ResetMarks (S, I+1, Last);
1204                 return 0;
1205             }
1206
1207             /* Remove the mark */
1208             CE_ResetMark (E);
1209         }
1210
1211         /* Next entry */
1212         ++I;
1213     }
1214
1215     /* Done - this is a basic block */
1216     return 1;
1217 }
1218
1219
1220
1221 void CS_OutputPrologue (const CodeSeg* S, FILE* F)
1222 /* If the given code segment is a code segment for a function, output the
1223  * assembler prologue into the file. That is: Output a comment header, switch
1224  * to the correct segment and enter the local function scope. If the code
1225  * segment is global, do nothing.
1226  */
1227 {
1228     /* Get the function associated with the code segment */
1229     SymEntry* Func = S->Func;
1230
1231     /* If the code segment is associated with a function, print a function
1232      * header and enter a local scope. Be sure to switch to the correct
1233      * segment before outputing the function label.
1234      */
1235     if (Func) {
1236         /* Get the function descriptor */
1237         const FuncDesc* D = GetFuncDesc (Func->Type);
1238         CS_PrintFunctionHeader (S, F);
1239         fprintf (F, ".segment\t\"%s\"\n\n.proc\t_%s", S->SegName, Func->Name);
1240         if (D->Flags & FD_NEAR) {
1241             fputs (": near", F);
1242         } else if (D->Flags & FD_FAR) {
1243             fputs (": far", F);
1244         }
1245         fputs ("\n\n", F);
1246     }
1247
1248 }
1249
1250
1251
1252 void CS_OutputEpilogue (const CodeSeg* S, FILE* F)
1253 /* If the given code segment is a code segment for a function, output the
1254  * assembler epilogue into the file. That is: Close the local function scope.
1255  */
1256 {
1257     if (S->Func) {
1258         fputs ("\n.endproc\n\n", F);
1259     }
1260 }
1261
1262
1263
1264 void CS_Output (CodeSeg* S, FILE* F)
1265 /* Output the code segment data to a file */
1266 {
1267     unsigned I;
1268     const LineInfo* LI;
1269
1270     /* Get the number of entries in this segment */
1271     unsigned Count = CS_GetEntryCount (S);
1272
1273     /* If the code segment is empty, bail out here */
1274     if (Count == 0) {
1275         return;
1276     }
1277
1278     /* Generate register info */
1279     CS_GenRegInfo (S);
1280
1281     /* Output the segment directive */
1282     fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
1283
1284     /* Output all entries, prepended by the line information if it has changed */
1285     LI = 0;
1286     for (I = 0; I < Count; ++I) {
1287         /* Get the next entry */
1288         const CodeEntry* E = CollConstAt (&S->Entries, I);
1289         /* Check if the line info has changed. If so, output the source line
1290          * if the option is enabled and output debug line info if the debug
1291          * option is enabled.
1292          */
1293         if (E->LI != LI) {
1294             /* Line info has changed, remember the new line info */
1295             LI = E->LI;
1296
1297             /* Add the source line as a comment. Beware: When line continuation
1298              * was used, the line may contain newlines.
1299              */
1300             if (AddSource) {
1301                 const char* L = LI->Line;
1302                 fputs (";\n; ", F);
1303                 while (*L) {
1304                     if (*L == '\n') {
1305                         fputs ("\n; ", F);
1306                     } else {
1307                         fputc (*L, F);
1308                     }
1309                     ++L;
1310                 }
1311                 fputs ("\n;\n", F);
1312             }
1313
1314             /* Add line debug info */
1315             if (DebugInfo) {
1316                 fprintf (F, "\t.dbg\tline, \"%s\", %u\n",
1317                          GetInputName (LI), GetInputLine (LI));
1318             }
1319         }
1320         /* Output the code */
1321         CE_Output (E, F);
1322     }
1323
1324     /* If debug info is enabled, terminate the last line number information */
1325     if (DebugInfo) {
1326         fputs ("\t.dbg\tline\n", F);
1327     }
1328
1329     /* Free register info */
1330     CS_FreeRegInfo (S);
1331 }
1332
1333
1334
1335 void CS_FreeRegInfo (CodeSeg* S)
1336 /* Free register infos for all instructions */
1337 {
1338     unsigned I;
1339     for (I = 0; I < CS_GetEntryCount (S); ++I) {
1340         CE_FreeRegInfo (CS_GetEntry(S, I));
1341     }
1342 }
1343
1344
1345
1346 void CS_GenRegInfo (CodeSeg* S)
1347 /* Generate register infos for all instructions */
1348 {
1349     unsigned I;
1350     RegContents Regs;           /* Initial register contents */
1351     RegContents* CurrentRegs;   /* Current register contents */
1352     int WasJump;                /* True if last insn was a jump */
1353     int Done;                   /* All runs done flag */
1354
1355     /* Be sure to delete all register infos */
1356     CS_FreeRegInfo (S);
1357
1358     /* We may need two runs to get back references right */
1359     do {
1360
1361         /* Assume we're done after this run */
1362         Done = 1;
1363
1364         /* On entry, the register contents are unknown */
1365         RC_Invalidate (&Regs);
1366         CurrentRegs = &Regs;
1367
1368         /* Walk over all insns and note just the changes from one insn to the
1369          * next one.
1370          */
1371         WasJump = 0;
1372         for (I = 0; I < CS_GetEntryCount (S); ++I) {
1373
1374             CodeEntry* P;
1375
1376             /* Get the next instruction */
1377             CodeEntry* E = CollAtUnchecked (&S->Entries, I);
1378
1379             /* If the instruction has a label, we need some special handling */
1380             unsigned LabelCount = CE_GetLabelCount (E);
1381             if (LabelCount > 0) {
1382
1383                 /* Loop over all entry points that jump here. If these entry
1384                  * points already have register info, check if all values are
1385                  * known and identical. If all values are identical, and the
1386                  * preceeding instruction was not an unconditional branch, check
1387                  * if the register value on exit of the preceeding instruction
1388                  * is also identical. If all these values are identical, the
1389                  * value of a register is known, otherwise it is unknown.
1390                  */
1391                 CodeLabel* Label = CE_GetLabel (E, 0);
1392                 unsigned Entry;
1393                 if (WasJump) {
1394                     /* Preceeding insn was an unconditional branch */
1395                     CodeEntry* J = CL_GetRef(Label, 0);
1396                     if (J->RI) {
1397                         Regs = J->RI->Out2;
1398                     } else {
1399                         RC_Invalidate (&Regs);
1400                     }
1401                     Entry = 1;
1402                 } else {
1403                     Regs = *CurrentRegs;
1404                     Entry = 0;
1405                 }
1406
1407                 while (Entry < CL_GetRefCount (Label)) {
1408                     /* Get this entry */
1409                     CodeEntry* J = CL_GetRef (Label, Entry);
1410                     if (J->RI == 0) {
1411                         /* No register info for this entry. This means that the
1412                          * instruction that jumps here is at higher addresses and
1413                          * the jump is a backward jump. We need a second run to
1414                          * get the register info right in this case. Until then,
1415                          * assume unknown register contents.
1416                          */
1417                         Done = 0;
1418                         RC_Invalidate (&Regs);
1419                         break;
1420                     }
1421                     if (J->RI->Out2.RegA != Regs.RegA) {
1422                         Regs.RegA = UNKNOWN_REGVAL;
1423                     }
1424                     if (J->RI->Out2.RegX != Regs.RegX) {
1425                         Regs.RegX = UNKNOWN_REGVAL;
1426                     }
1427                     if (J->RI->Out2.RegY != Regs.RegY) {
1428                         Regs.RegY = UNKNOWN_REGVAL;
1429                     }
1430                     if (J->RI->Out2.SRegLo != Regs.SRegLo) {
1431                         Regs.SRegLo = UNKNOWN_REGVAL;
1432                     }
1433                     if (J->RI->Out2.SRegHi != Regs.SRegHi) {
1434                         Regs.SRegHi = UNKNOWN_REGVAL;
1435                     }
1436                     if (J->RI->Out2.Tmp1 != Regs.Tmp1) {
1437                         Regs.Tmp1 = UNKNOWN_REGVAL;
1438                     }
1439                     ++Entry;
1440                 }
1441
1442                 /* Use this register info */
1443                 CurrentRegs = &Regs;
1444
1445             }
1446
1447             /* Generate register info for this instruction */
1448             CE_GenRegInfo (E, CurrentRegs);
1449
1450             /* Remember for the next insn if this insn was an uncondition branch */
1451             WasJump = (E->Info & OF_UBRA) != 0;
1452
1453             /* Output registers for this insn are input for the next */
1454             CurrentRegs = &E->RI->Out;
1455
1456             /* If this insn is a branch on zero flag, we may have more info on
1457              * register contents for one of both flow directions, but only if
1458              * there is a previous instruction.
1459              */
1460             if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
1461
1462                 /* Get the branch condition */
1463                 bc_t BC = GetBranchCond (E->OPC);
1464
1465                 /* Check the previous instruction */
1466                 switch (P->OPC) {
1467
1468                     case OP65_ADC:
1469                     case OP65_AND:
1470                     case OP65_DEA:
1471                     case OP65_EOR:
1472                     case OP65_INA:
1473                     case OP65_LDA:
1474                     case OP65_ORA:
1475                     case OP65_PLA:
1476                     case OP65_SBC:
1477                         /* A is zero in one execution flow direction */
1478                         if (BC == BC_EQ) {
1479                             E->RI->Out2.RegA = 0;
1480                         } else {
1481                             E->RI->Out.RegA = 0;
1482                         }
1483                         break;
1484
1485                     case OP65_CMP:
1486                         /* If this is an immidiate compare, the A register has
1487                          * the value of the compare later.
1488                          */
1489                         if (CE_KnownImm (P)) {
1490                             if (BC == BC_EQ) {
1491                                 E->RI->Out2.RegA = (unsigned char)P->Num;
1492                             } else {
1493                                 E->RI->Out.RegA = (unsigned char)P->Num;
1494                             }
1495                         }
1496                         break;
1497
1498                     case OP65_CPX:
1499                         /* If this is an immidiate compare, the X register has
1500                          * the value of the compare later.
1501                          */
1502                         if (CE_KnownImm (P)) {
1503                             if (BC == BC_EQ) {
1504                                 E->RI->Out2.RegX = (unsigned char)P->Num;
1505                             } else {
1506                                 E->RI->Out.RegX = (unsigned char)P->Num;
1507                             }
1508                         }
1509                         break;
1510
1511                     case OP65_CPY:
1512                         /* If this is an immidiate compare, the Y register has
1513                          * the value of the compare later.
1514                          */
1515                         if (CE_KnownImm (P)) {
1516                             if (BC == BC_EQ) {
1517                                 E->RI->Out2.RegY = (unsigned char)P->Num;
1518                             } else {
1519                                 E->RI->Out.RegY = (unsigned char)P->Num;
1520                             }
1521                         }
1522                         break;
1523
1524                     case OP65_DEX:
1525                     case OP65_INX:
1526                     case OP65_LDX:
1527                     case OP65_PLX:
1528                         /* X is zero in one execution flow direction */
1529                         if (BC == BC_EQ) {
1530                             E->RI->Out2.RegX = 0;
1531                         } else {
1532                             E->RI->Out.RegX = 0;
1533                         }
1534                         break;
1535
1536                     case OP65_DEY:
1537                     case OP65_INY:
1538                     case OP65_LDY:
1539                     case OP65_PLY:
1540                         /* X is zero in one execution flow direction */
1541                         if (BC == BC_EQ) {
1542                             E->RI->Out2.RegY = 0;
1543                         } else {
1544                             E->RI->Out.RegY = 0;
1545                         }
1546                         break;
1547
1548                     case OP65_TAX:
1549                     case OP65_TXA:
1550                         /* If the branch is a beq, both A and X are zero at the
1551                          * branch target, otherwise they are zero at the next
1552                          * insn.
1553                          */
1554                         if (BC == BC_EQ) {
1555                             E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
1556                         } else {
1557                             E->RI->Out.RegA = E->RI->Out.RegX = 0;
1558                         }
1559                         break;
1560
1561                     case OP65_TAY:
1562                     case OP65_TYA:
1563                         /* If the branch is a beq, both A and Y are zero at the
1564                          * branch target, otherwise they are zero at the next
1565                          * insn.
1566                          */
1567                         if (BC == BC_EQ) {
1568                             E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
1569                         } else {
1570                             E->RI->Out.RegA = E->RI->Out.RegY = 0;
1571                         }
1572                         break;
1573
1574                     default:
1575                         break;
1576
1577                 }
1578             }
1579         }
1580     } while (!Done);
1581
1582 }
1583
1584
1585