+static void AddStoreA (StackOpData* D)
+/* Add a store to zero page after the push insn */
+{
+ CodeEntry* X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPLo, 0, D->PushEntry->LI);
+ InsertEntry (D, X, D->PushIndex+1);
+}
+
+
+
+static void AddStoreX (StackOpData* D)
+/* Add a store to zero page after the push insn */
+{
+ CodeEntry* X = NewCodeEntry (OP65_STX, AM65_ZP, D->ZPHi, 0, D->PushEntry->LI);
+ InsertEntry (D, X, D->PushIndex+1);
+}
+
+
+
+static void ReplacePushByStore (StackOpData* D)
+/* Replace the call to the push subroutine by a store into the zero page
+ * location (actually, the push is not replaced, because we need it for
+ * later, but the name is still ok since the push will get removed at the
+ * end of each routine).
+ */
+{
+ /* Store the value into the zeropage instead of pushing it. Check high
+ * byte first so that the store is later in A/X order.
+ */
+ if ((D->Lhs.X.Flags & LI_DIRECT) == 0) {
+ AddStoreX (D);
+ }
+ if ((D->Lhs.A.Flags & LI_DIRECT) == 0) {
+ AddStoreA (D);
+ }
+}
+
+
+
+static void AddOpLow (StackOpData* D, opc_t OPC, LoadInfo* LI)
+/* Add an op for the low byte of an operator. This function honours the
+ * OP_DIRECT and OP_RELOAD_Y flags and generates the necessary instructions.
+ * All code is inserted at the current insertion point.
+ */
+{
+ CodeEntry* X;
+
+ if ((LI->A.Flags & LI_DIRECT) != 0) {
+ /* Op with a variable location. If the location is on the stack, we
+ * need to reload the Y register.
+ */
+ if ((LI->A.Flags & LI_RELOAD_Y) == 0) {
+
+ /* opc ... */
+ CodeEntry* LoadA = LI->A.LoadEntry;
+ X = NewCodeEntry (OPC, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (LI->A.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* opc (sp),y */
+ X = NewCodeEntry (OPC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ }
+
+ /* In both cases, we can remove the load */
+ LI->A.Flags |= LI_REMOVE;
+
+ } else {
+
+ /* Op with temp storage */
+ X = NewCodeEntry (OPC, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ }
+}
+
+
+
+static void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
+/* Add an op for the high byte of an operator. Special cases (constant values
+ * or similar) have to be checked separately, the function covers only the
+ * generic case. Code is inserted at the insertion point.
+ */
+{
+ CodeEntry* X;
+
+ if (KeepResult) {
+ /* pha */
+ X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* txa */
+ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ if ((LI->X.Flags & LI_DIRECT) != 0) {
+
+ if ((LI->X.Flags & LI_RELOAD_Y) == 0) {
+
+ /* opc xxx */
+ CodeEntry* LoadX = LI->X.LoadEntry;
+ X = NewCodeEntry (OPC, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #const */
+ const char* Arg = MakeHexArg (LI->X.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* opc (sp),y */
+ X = NewCodeEntry (OPC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ LI->X.Flags |= LI_REMOVE;
+
+ } else {
+ /* opc zphi */
+ X = NewCodeEntry (OPC, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ if (KeepResult) {
+ /* tax */
+ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* pla */
+ X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+}
+
+
+
+static void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
+/* Remove register load insns */
+{
+ /* Both registers may be loaded with one insn, but DelEntry will in this
+ * case clear the other one.
+ */
+ if (LI->A.Flags & LI_REMOVE) {
+ if (LI->A.LoadIndex >= 0) {
+ DelEntry (D, LI->A.LoadIndex);
+ }
+ if (LI->A.XferIndex >= 0) {
+ DelEntry (D, LI->A.XferIndex);
+ }
+ }
+ if (LI->X.Flags & LI_REMOVE) {
+ if (LI->X.LoadIndex >= 0) {
+ DelEntry (D, LI->X.LoadIndex);
+ }
+ if (LI->X.XferIndex >= 0) {
+ DelEntry (D, LI->X.XferIndex);
+ }
+ }
+}
+
+
+
+static void RemoveRemainders (StackOpData* D)
+/* Remove the code that is unnecessary after translation of the sequence */
+{
+ /* Remove the register loads for lhs and rhs */
+ RemoveRegLoads (D, &D->Lhs);
+ RemoveRegLoads (D, &D->Rhs);
+
+ /* Remove the push and the operator routine */
+ DelEntry (D, D->OpIndex);
+ DelEntry (D, D->PushIndex);
+}