https://github.com/virtualagc/virtualagc
Tip revision: 52901838ab640b21ad17cecf2eff21bd2a65565b authored by Mike Stewart on 22 September 2019, 06:57:09 UTC
Luminary 173: final cleanup and removal of incompletion warnings
Luminary 173: final cleanup and removal of incompletion warnings
Tip revision: 5290183
ParseBBCON.c
/*
* Copyright 2004,2016-2017 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: ParseBBCON.c
* Purpose: Assembles the BBCON and BBCON* pseudo-ops.
* History: 07/21/04 RSB. Adapted from ParseECADR.c.
* 11/02/16 RSB. Changed handling of BBCON*, which was previously
* hard-coded, but for which the value is no
* longer correct in Sunburst 120. Hopefully
* works correctly in all cases now.
* 11/03/16 RSB. Permanently removed some code I had temporarily
* commented out yesterday.
* 2017-01-05 RSB Added BBCON* as distinct from BBCON.
* 2017-06-17 MAS Refactored superbank bit logic.
*/
#include "yaYUL.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
//-------------------------------------------------------------------------
// Returns non-zero on unrecoverable error.
static int
ParseBBCONraw(int star, ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
Address_t Address, ebank;
int Value, i;
//extern Line_t CurrentFilename;
//extern int CurrentLineInFile;
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;
OutRecord->NumWords = 1;
OutRecord->Words[0] = 0;
if (InRecord->Extend && !InRecord->IndexValid) {
strcpy(OutRecord->ErrorMessage, "Illegally preceded by EXTEND.");
OutRecord->Fatal = 1;
OutRecord->Extend = 0;
}
if (InRecord->IndexValid) {
strcpy(OutRecord->ErrorMessage, "Illegally preceded by INDEX.");
OutRecord->Fatal = 1;
OutRecord->IndexValid = 0;
}
i = GetOctOrDec(InRecord->Operand, &Value);
if ((!i && *InRecord->Mod1 == 0) || star) {
IncPc(&InRecord->ProgramCounter, Value, &Address);
DoIt:
if (star)
{
/*
* Since this is BBCON*, we need to generate an address, instead find the
* last address used in the last non-empty fixed bank.
*/
int GetPriorBankCount(int bank); // From ParseBANK.c.
int bank, highestOffset = 0;
for (bank = 043; bank >= 0; bank--)
{
highestOffset = GetPriorBankCount(bank);
if (highestOffset > 0)
break;
}
//printf("Debug %02o %04o\n", bank, highestOffset);
Address.Address = 1;
Address.Banked = 1;
Address.Constant = 0;
Address.EB = 0;
Address.Erasable = 0;
Address.FB = (bank >= 040) ? (bank - 010) : bank;
Address.Fixed = 1;
Address.Invalid = 0;
Address.Overflow = 0;
Address.SReg = 04000 + highestOffset;
Address.Super = (bank >= 040) ? 1 : 0;
Address.Syllable = 0;
Address.Unbanked = 0;
Address.Value = 010000 + (Address.SReg - 02000) + 02000 * Address.FB;
if (Address.Super && Address.FB >= 030)
Address.Value += 010 * 02000;
}
if (Address.Invalid) {
strcpy(OutRecord->ErrorMessage, "Destination address not resolved.");
OutRecord->Fatal = 1;
return (0);
}
if (!Address.Address) {
strcpy(OutRecord->ErrorMessage, "Destination is not a memory address.");
OutRecord->Fatal = 1;
return (0);
}
if (!Address.Fixed) {
strcpy(OutRecord->ErrorMessage, "Destination is not in fixed memory.");
OutRecord->Fatal = 1;
return (0);
}
if (Address.SReg < 02000 || Address.SReg > 07777) {
strcpy(OutRecord->ErrorMessage, "Destination address out of range.");
OutRecord->Fatal = 1;
return (0);
}
if (!Address.Banked)
Address.Value = Address.SReg / 02000;
else
Address.Value = Address.FB;
ebank = InRecord->EBank.current;
if (ebank.SReg >= 0 && ebank.SReg < 01400)
ebank.EB = ebank.SReg / 0400;
Address.Value = (Address.Value << 10) | ebank.EB;
if (Address.FB >= 030 && Address.FB <= 037) {
// Determine the superbank needed for the target address
unsigned AddressSBank;
if (Address.Super)
AddressSBank = 4;
else
AddressSBank = 3;
Address.Value |= AddressSBank << 4;
// Generate a warning if we're implicitly referencing a different superbank
// ... someday? It really looks like there are things that YUL would have cussed
// in, e.g., Luminary 210, but GAP does not appear to have done so. For now
// we will just let it slide...
//if (InRecord->ProgramCounter.FB >= 030 && InRecord->ProgramCounter.FB <= 037
// && AddressSBank != InRecord->SBank.current) {
// sprintf(OutRecord->ErrorMessage,
// "BBCON referencing unestablished superbank %u when in superbank %u",
// AddressSBank,
// InRecord->SBank.current);
// OutRecord->Warning = 1;
//}
} else if (!EarlySBank) {
// If the target address is not in a superbank, then simply fill in the
// superbank bits with whatever the established superbank is...
// *unless* we're building with pre-1967 superbank behavior.
Address.Value |= InRecord->SBank.current << 4;
}
OutRecord->Words[0] = Address.Value;
} else {
// The operand is NOT a number. Presumably, it's a symbol.
i = FetchSymbolPlusOffset(&InRecord->ProgramCounter, InRecord->Operand, InRecord->Mod1, &Address);
if (!i)
goto DoIt;
sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
OutRecord->Fatal = 1;
}
#ifdef YAYUL_TRACE
PrintTrace(InRecord, OutRecord);
#endif
return (0);
}
int ParseBBCON(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
return (ParseBBCONraw(0, InRecord, OutRecord));
}
int ParseBBCONstar(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
return (ParseBBCONraw(1, InRecord, OutRecord));
}