+static void CS_PrintFunctionHeader (const CodeSeg* S, FILE* F)
+/* Print a comment with the function signature to the given file */
+{
+ /* Get the associated function */
+ const SymEntry* Func = S->Func;
+
+ /* If this is a global code segment, do nothing */
+ if (Func) {
+ fprintf (F,
+ "; ---------------------------------------------------------------\n"
+ "; ");
+ PrintFuncSig (F, Func->Name, Func->Type);
+ fprintf (F,
+ "\n"
+ "; ---------------------------------------------------------------\n"
+ "\n");
+ }
+}
+
+
+
static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E)
/* Move all labels from the label pool to the given entry and remove them
* from the pool.
static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name,
- void (*ErrorFunc) (const char*, ...))
+ void (*ErrorFunc) (const char*, ...))
/* Add a code label for the next instruction to follow */
{
/* Calculate the hash from the name */
+int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
+/* Return true if any of the code entries in the given range has a label
+ * attached. If the code segment does not span the given range, check the
+ * possible span instead.
+ */
+{
+ unsigned EntryCount = CS_GetEntryCount(S);
+
+ /* Adjust count. We expect at least Start to be valid. */
+ CHECK (Start < EntryCount);
+ if (Start + Count > EntryCount) {
+ Count = EntryCount - Start;
+ }
+
+ /* Check each entry. Since we have validated the index above, we may
+ * use the unchecked access function in the loop which is faster.
+ */
+ while (Count--) {
+ const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++);
+ if (CE_HasLabel (E)) {
+ return 1;
+ }
+ }
+
+ /* No label in the complete range */
+ return 0;
+}
+
+
+
CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name)
/* Add a code label for the next instruction to follow */
{
*/
{
unsigned I;
+ unsigned J;
/* First, remove all labels from the label symbol table that don't have an
* owner (this means that they are actually external labels but we didn't
CodeLabel** L = &S->LabelHash[I];
while (*L) {
if ((*L)->Owner == 0) {
- /* The label does not have an owner, remove it from the chain */
+
+ /* The label does not have an owner, remove it from the chain */
CodeLabel* X = *L;
*L = X->Next;
+
+ /* Cleanup any entries jumping to this label */
+ for (J = 0; J < CL_GetRefCount (X); ++J) {
+ /* Get the entry referencing this label */
+ CodeEntry* E = CL_GetRef (X, J);
+ /* And remove the reference */
+ E->JumpTo = 0;
+ }
+
+ /* Print some debugging output */
if (Debug) {
printf ("Removing unused global label `%s'", X->Name);
}
+
+ /* And free the label */
FreeCodeLabel (X);
} else {
/* Label is owned, point to next code label pointer */
+void CS_OutputPrologue (const CodeSeg* S, FILE* F)
+/* If the given code segment is a code segment for a function, output the
+ * assembler prologue into the file. That is: Output a comment header, switch
+ * to the correct segment and enter the local function scope. If the code
+ * segment is global, do nothing.
+ */
+{
+ /* Get the function associated with the code segment */
+ SymEntry* Func = S->Func;
+
+ /* If the code segment is associated with a function, print a function
+ * header and enter a local scope. Be sure to switch to the correct
+ * segment before outputing the function label.
+ */
+ if (Func) {
+ CS_PrintFunctionHeader (S, F);
+ fprintf (F, ".segment\t\"%s\"\n\n.proc\t_%s\n\n", S->SegName, Func->Name);
+ }
+
+}
+
+
+
+void CS_OutputEpilogue (const CodeSeg* S, FILE* F)
+/* If the given code segment is a code segment for a function, output the
+ * assembler epilogue into the file. That is: Close the local function scope.
+ */
+{
+ if (S->Func) {
+ fprintf (F, "\n.endproc\n\n");
+ }
+}
+
+
+
void CS_Output (const CodeSeg* S, FILE* F)
/* Output the code segment data to a file */
{
/* Output the segment directive */
fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
- /* If this is a segment for a function, enter a function */
- if (S->Func) {
- fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
- }
-
/* Output all entries, prepended by the line information if it has changed */
LI = 0;
for (I = 0; I < Count; ++I) {
if (DebugInfo) {
fprintf (F, "\t.dbg\tline\n");
}
-
- /* If this is a segment for a function, leave the function */
- if (S->Func) {
- fprintf (F, "\n.endproc\n\n");
- }
}
/* Assume we're done after this run */
Done = 1;
-
+
/* On entry, the register contents are unknown */
RC_Invalidate (&Regs);
CurrentRegs = &Regs;
}
++Entry;
}
-
+
/* Use this register info */
CurrentRegs = &Regs;
-
+
}
-
+
/* Generate register info for this instruction */
CE_GenRegInfo (E, CurrentRegs);
-
+
/* Remember for the next insn if this insn was an uncondition branch */
WasJump = (E->Info & OF_UBRA) != 0;
/* Output registers for this insn are input for the next */
CurrentRegs = &E->RI->Out;
-
+
/* If this insn is a branch on zero flag, we may have more info on
* register contents for one of both flow directions, but only if
* there is a previous instruction.
*/
if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
-
+
/* Get the branch condition */
bc_t BC = GetBranchCond (E->OPC);
-
+
/* Check the previous instruction */
switch (P->OPC) {
-
+
case OP65_ADC:
case OP65_AND:
case OP65_DEA:
E->RI->Out.RegA = 0;
}
break;
-
+
case OP65_CMP:
/* If this is an immidiate compare, the A register has
* the value of the compare later.
}
}
break;
-
+
case OP65_CPX:
/* If this is an immidiate compare, the X register has
* the value of the compare later.
}
}
break;
-
+
case OP65_CPY:
/* If this is an immidiate compare, the Y register has
* the value of the compare later.
}
}
break;
-
+
case OP65_DEX:
case OP65_INX:
case OP65_LDX:
E->RI->Out.RegX = 0;
}
break;
-
+
case OP65_DEY:
case OP65_INY:
case OP65_LDY:
E->RI->Out.RegY = 0;
}
break;
-
+
case OP65_TAX:
case OP65_TXA:
/* If the branch is a beq, both A and X are zero at the
E->RI->Out.RegA = E->RI->Out.RegX = 0;
}
break;
-
+
case OP65_TAY:
case OP65_TYA:
/* If the branch is a beq, both A and Y are zero at the
E->RI->Out.RegA = E->RI->Out.RegY = 0;
}
break;
-
+
default:
break;
-
+
}
}
}