Revision b848d1bc915eb239b7ede8de755fca6f7edb63cb authored by Jim Lawton on 24 August 2016, 17:23:36 UTC, committed by Jim Lawton on 24 August 2016, 17:23:44 UTC
1 parent 7481b16
ParseST.c
/*
Copyright 2003-2004,2016 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: ParseST.c
Purpose: Assembles STCALL, STODL, STORE, and STOVAL interpretive
opcodes.
Mode: 07/27/04 RSB Forked from ParseGeneral.c.
08/24/16 RSB Updated for --block1.
*/
#include "yaYUL.h"
#include <stdlib.h>
#include <string.h>
//------------------------------------------------------------------------
static int
ParseST(ParseInput_t *InRecord, ParseOutput_t *OutRecord, int Opcode, int Flags)
{
int Value, i;
Address_t K;
// A debugging statement.
//if (!strcmp(InRecord->Operand, "XNB"))
// {
// i = 12;
// }
if (!Block1)
{
Opcode += 04000 * ArgType;
}
IncPc(&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow)
{
strcpy(OutRecord->ErrorMessage, "Next code may overflow storage.");
OutRecord->Warning = 1;
}
OutRecord->EBank = InRecord->EBank;
OutRecord->SBank = InRecord->SBank;
// Set the default binary word.
OutRecord->NumWords = 1;
if (Flags & PC1)
Opcode |= 01000;
else if (Flags & PC2)
Opcode |= 02000;
else if (Flags & PC3)
Opcode |= 03000;
else if (Flags & PC4)
Opcode |= 04000;
else if (Flags & PC5)
Opcode |= 05000;
else if (Flags & PC6)
Opcode |= 06000;
else if (Flags & PC7)
Opcode |= 07000;
else if (Flags & QC1)
Opcode |= 02000;
else if (Flags & QC2)
Opcode |= 04000;
else if (Flags & QC3)
Opcode |= 06000;
OutRecord->Words[0] = Opcode;
if (Flags & QCNOT0)
OutRecord->Words[0] |= 06000;
// Do some sanity checking.
if (InRecord->Extend && !(Flags & EXTENDED) && !InRecord->IndexValid)
{
strcpy(OutRecord->ErrorMessage, "Illegally preceded by EXTEND.");
OutRecord->Fatal = 1;
OutRecord->Extend = 0;
}
else if (!InRecord->Extend && (Flags & EXTENDED))
{
strcpy(OutRecord->ErrorMessage, "Required EXTEND is missing.");
OutRecord->Fatal = 1;
OutRecord->Extend = 0;
}
if (InRecord->IndexValid)
{
OutRecord->IndexValid = 0;
}
i = GetOctOrDec(InRecord->Operand, &Value);
if (!i && (Flags & ENUMBER) && *InRecord->Operand != '+'
&& *InRecord->Operand != '-')
{
int Offset;
PseudoToStruct(Value, &K);
if (!GetOctOrDec(InRecord->Mod1, &Offset))
OpcodeOffset = Offset;
goto DoIt;
}
if (!i && *InRecord->Mod1 == 0)
{
IncPc(&InRecord->ProgramCounter, Value, &K);
DoIt: if (K.Invalid)
{
strcpy(OutRecord->ErrorMessage, "Destination address not resolved.");
OutRecord->Fatal = 1;
}
else if (K.Overflow)
{
strcpy(OutRecord->ErrorMessage, "Destination address out of range.");
OutRecord->Fatal = 1;
}
else if (!K.Address)
{
strcpy(OutRecord->ErrorMessage, "Destination not an address.");
OutRecord->Fatal = 1;
}
else
{
//AddressFound:
// Here I had originally intended to add a check that the bank
// numbers were compatible. This turns out not to be generally
// possible at assembly time, unless a bunch of analysis is
// added to understand program flow. However, certain checks,
// particularly having to do with quarter-codes, can be done.
// ... Later: Not true for erasable banks, since the EBANK=
// pseudo-op tells the assembler what bank is expected. Also,
// some constants need to be translated to erasable.
if (K.Constant)
PseudoToStruct(K.Value, &K);
if (Flags & KPLUS1)
IncPc(&K, 1, &K);
i = K.SReg;
if (!K.Erasable)
{
i = 0;
strcpy(OutRecord->ErrorMessage,
"The Address is not in erasable memory.");
OutRecord->Fatal = 1;
}
else
{
if (!K.Banked)
i = K.SReg;
else
i = 0400 * K.EB + (K.SReg - 01400);
}
if (Block1 && ArgType != 0) {
OpcodeOffset *= 2;
OutRecord->Words[0] = 034000 + 2 * i + ArgType;
} else
OutRecord->Words[0] = Opcode | i;
}
}
else
{
// The operand is NOT a number. Presumably, it's a symbol.
i = FetchSymbolPlusOffset(&InRecord->ProgramCounter, InRecord->Operand,
InRecord->Mod1, &K);
if (!i)
{
if (K.Constant)
PseudoToStruct(K.Value, &K);
goto DoIt;
}
sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad",
InRecord->Operand);
OutRecord->Fatal = 1;
}
OutRecord->Extend = 0;
//if (Opcode == 000000 && !(Flags & EXTENDED) && !K.Invalid &&
// (K.Constant || (K.Erasable && K.Unbanked)) && K.SReg == 06)
// OutRecord->Extend = 1;
//else
OutRecord->Extend = 0;
OutRecord->IndexValid = 0;
return (0);
}
//------------------------------------------------------------------------
// Various little parsers based on ParseST.
int
ParseSTCALL(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
ArgType = ParseComma(InRecord);
SwitchIncrement[0] = 0;
SwitchInvert[0] = 0;
nnnnFields[0] = 0;
RawNumInterpretiveOperands = NumInterpretiveOperands = 1;
return (ParseST(InRecord, OutRecord, 034000,
ERASABLE | ENUMBER | KPLUS1));
}
int
ParseSTODL(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
ArgType = ParseComma(InRecord);
SwitchIncrement[0] = 1;
SwitchInvert[0] = 0;
nnnnFields[0] = 0;
RawNumInterpretiveOperands = NumInterpretiveOperands = 1;
return (ParseST(InRecord, OutRecord, 014000,
ERASABLE | ENUMBER | KPLUS1));
}
int
ParseSTORE(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
ArgType = ParseComma(InRecord);
NumInterpretiveOperands = 0;
return (ParseST(InRecord, OutRecord, (Block1 ? 032000 : 000000),
ERASABLE | ENUMBER | ((Block1 && ArgType) ? 0 : KPLUS1)));
}
int
ParseSTOVL(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
ArgType = ParseComma(InRecord);
SwitchIncrement[0] = 1;
SwitchInvert[0] = 0;
nnnnFields[0] = 0;
RawNumInterpretiveOperands = NumInterpretiveOperands = 1;
return (ParseST(InRecord, OutRecord, 024000,
ERASABLE | ENUMBER | KPLUS1));
}
//-------------------------------------------------------------------------
// What we have here is a function that parses the Operand and Mod1 fields
// of an instruction line, in order to find the suffices ",1" or ",2", and
// to remove them. The return value is 0 if no suffix, or is 1 or 2 if there
// is a suffix. This concept applies only to the operands of interpretive
// instructions.
// Do it for just a single string.
static int
ParseCommaString(char *s)
{
int Len;
Len = strlen(s);
if (Len < 3)
return (0);
s += Len - 2;
if (!strcmp(",1", s))
{
*s = 0;
return (1);
}
if (!strcmp(",2", s))
{
*s = 0;
return (2);
}
return (0);
}
int
ParseComma(ParseInput_t *Record)
{
// If there is a Mod1 field, then the comma-suffix (if any) will appear
// on the Mod1 field.
if (*Record->Mod1)
return (ParseCommaString(Record->Mod1));
// If there is NOT a Mod1 field, then the comma-suffix may appear on the
// Operand field.
if (*Record->Operand)
return (ParseCommaString(Record->Operand));
// Guess there was neither one!
return (0);
}
Computing file changes ...