Raw File
ParseSETLOC.c
/*
  Copyright 2003-2004 Ronald S. Burkey <info@sandroid.org>

  This file is part of yaAGC. 

  yaAGC is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  yaAGC is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with yaAGC; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Filename:     ParseSETLOC.c
  Purpose:      Assembles the SETLOC pseudo-op.
  Mode:         04/17/03 RSB.   Began.
                07/24/04 RSB.   Now allow offsets.
                12/18/16 MAS.   Added support for relative arguments
                                (eg. SETLOC +2)
                01/27/17 MAS.   Added support for Raytheon-style
                                absolute addresses (eg. FF024000)
                06/17/17 MAS.   SETLOC has no effect on the SBank.
 */

#include "yaYUL.h"
#include <stdlib.h>
#include <string.h>

//------------------------------------------------------------------------
// Return non-zero on unrecoverable error.
int ParseSETLOC(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
    int Value, i;
    Symbol_t *Symbol;

    OutRecord->ProgramCounter = InRecord->ProgramCounter;
    OutRecord->SBank= InRecord->SBank;

    // Pass EXTEND through.
    OutRecord->Extend = InRecord->Extend;

    if (InRecord->IndexValid) {
        strcpy(OutRecord->ErrorMessage, "Illegally preceded by INDEX.");
        OutRecord->Fatal = 1;
        OutRecord->IndexValid = 0;
    }

    i = GetOctOrDec(InRecord->Operand, &Value);
    if (!i) {
        if (InRecord->Operand[0] == '+' || InRecord->Operand[0] == '-') {
            // This is a relative SETLOC or LOC. Change the PC by the requested
            // value.
            IncPc(&OutRecord->ProgramCounter, Value, &OutRecord->ProgramCounter);
        } else {
            // What we've found here is that a constant, like 04000, is the
            // operand of the SETLOC pseudo-op.  I don't really know what is
            // supposed to be done with this in general.  (I've seen
            // `SETLOC 04000' in the source code, but I don't know if there
            // are others.)  I'm going to ASSUME that the operand is a
            // full 16-bit pseudo-address, and I'm going to choose the best
            // memory type based on that assumption.
            PseudoToSegmented(Value, OutRecord);
        }
    } else {
        Symbol = GetSymbol(InRecord->Operand);
        if (!Symbol) {
            char MemType;
            int Bank, SReg;
            int RaytheonAddr = 0;
            if (3 == sscanf(InRecord->Operand, "%cF%2o%4o", &MemType, &Bank, &SReg)) {
                if (MemType == 'C' || MemType == 'F') {
                    OutRecord->ProgramCounter = VALID_ADDRESS;
                    OutRecord->ProgramCounter.Address = 1;
                    OutRecord->ProgramCounter.Fixed = 1;
                    OutRecord->ProgramCounter.SReg = SReg;
                    if (MemType == 'C') {
                        OutRecord->ProgramCounter.Banked = 1;
                        OutRecord->ProgramCounter.FB = Bank;
                    } else {
                        OutRecord->ProgramCounter.Unbanked = 1;
                    }
                    RaytheonAddr = 1;
                }
            }

            if (!RaytheonAddr) {
                sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
                OutRecord->Fatal = 1;
                OutRecord->ProgramCounter.Invalid = 1;
            }
        } else {
            OutRecord->ProgramCounter = Symbol->Value;
        }
    }

    i = GetOctOrDec(InRecord->Mod1, &Value);
    if (!i)
        IncPc(&OutRecord->ProgramCounter, Value, &OutRecord->ProgramCounter);

    // Make sure this prints properly in the output listing (?).
    InRecord->ProgramCounter = OutRecord->ProgramCounter;

    if (!OutRecord->ProgramCounter.Invalid) {
        if (OutRecord->ProgramCounter.Erasable) {
            OutRecord->EBank.current = OutRecord->ProgramCounter;
            OutRecord->EBank.last = OutRecord->ProgramCounter;
            OutRecord->EBank.oneshotPending = 0;
        }
    }

#ifdef YAYUL_TRACE
    PrintTrace(InRecord, OutRecord);
#endif

    return (0);
}
back to top