https://github.com/virtualagc/virtualagc
Revision 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC, committed by Ron Burkey on 07 August 2022, 15:04:04 UTC
assembly listings from yaASM and yaLEMAP. Added some debugging messages
to 'make install'.  Tweaked debugging messages that VirtualAGC embeds in
'simulate'.  Verified buildability in Mint 21, 20, 19, 17, and verified
buildability using clang in Mint 17.
1 parent 6bb1acc
Raw File
Tip revision: 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC
Fixed a potential string-overflow bug in yaASM. Removed timestamps from
Tip revision: 078c79d
IncPc.c
/*
  Copyright 2003,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:     IncPc.c
  Purpose:      Increments (or decrements) an Address_t structure, with 
                detection of out-of range.  This is a more complicated
                thing than it seems, because of the variety of different
                types of memory bank.  (Also, since the Address_t 
                structure can represent a constant rather than an address.)
  History:      04/15/03 RSB    Began.
                08/18/16 RSB    Some cross-my-finger-and-hope tweaks for
                                --block1.
 */

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

//-------------------------------------------------------------------------
// Increment program counter by a certain amount. 
// Sets the Overflow flag in the Address_t structure.
void IncPc(Address_t *OldPc, int Increment, Address_t *NewPc)
{
    int i, j, Max, Min, BankIncrement;

    // I have no theoretical basis for how to treat the case of Increment
    // being very large (larger than a bank size), but there is a place
    // in the Luminary source code where decrements of about 12000 (octal)
    // are used.  The lower 12 bits seem to be applied to SREG, whereas
    // the upper 3 bits seem to be applied to the bank number.
    if (Increment >= 0) {
        BankIncrement = 7 & (Increment >> 12);
        Increment &= 07777;
    } else {
        Increment = -Increment;
        BankIncrement = -(7 & (Increment >> 12));
        Increment = -(07777 & Increment);
    }

    // Get a good starting point for the calculation.
    *NewPc = *OldPc;

    // If the value is invalid---not yet assigned---then adding to it makes
    // no sense.
    if (NewPc->Invalid)
        return;

    // Okay, add to the existing Value.  This is something that ALWAYS works.
    // (Only overflowing 32-bit arithmetic could make it fail, but since
    // all possible starting values and increments are 15-bit or less,
    // overflowing 32-bit arithmetic would be a real feat!
    //NewPc->Value += Increment;

    // Convert constants (which are presumably pseudo-addresses) to real
    // addresses.
    if (NewPc->Constant) {
        // ... except we do want to check that the constant is in range.
        //if (NewPc->Value < -16383 || NewPc->Value > 32767)
        //  NewPc->Overflow = 1;
        if (NewPc->Value < 0)
            return;
        else if (NewPc->Value < 01400) {
            NewPc->Constant = 0;
            NewPc->Address = 1;
            NewPc->Erasable = 1;
            NewPc->Fixed = 0;
            NewPc->Banked = 0;
            NewPc->Unbanked = 1;
            NewPc->EB = 0;
            NewPc->FB = 0;
#ifdef YAYUL_TRACE
            printf("*** IncPc (%d): clearing superbank...\n", __LINE__);
#endif
            NewPc->Super = 0;
            NewPc->SReg = NewPc->Value;
        } else
            return;
    }

    // Okey-smokey, the "address" is really an address. If it has previously
    // overflowed, there's no particular reason to continue.
    if (NewPc->Overflow)
        return;

    // Compute the new S-register value (in the absence of overflow).
    i = (j = NewPc->SReg) + Increment;
    NewPc->SReg = i;
    if (NewPc->Erasable && NewPc->Banked)
        NewPc->EB += BankIncrement;
    else if (NewPc->Fixed && NewPc->Banked)
        NewPc->FB += BankIncrement;

    // Okay, here's some workaround code for the weird construct
    // TC FixedMemoryLabel -LargeOffset
    // taking a location in fixed memory down to a location in erasable.
    // Don't blame me!
    if (NewPc->Fixed && BankIncrement != 0 && NewPc->FB == 0) {
        NewPc->Constant = 0;
        NewPc->Address = 1;
        NewPc->Erasable = 1;
        NewPc->Fixed = 0;
        NewPc->Banked = 0;
        NewPc->Unbanked = 1;
        NewPc->EB = 0;
        NewPc->FB = 0;
#ifdef YAYUL_TRACE
        //printf("--- IncPc (%d): clearing superbank...\n", __LINE__);
#endif
        NewPc->Super = 0;
    }  

    // Determine the appropriate SReg ranges for this memory region.
    // The address will be either banked or unbanked, and either in fixed
    // memory or erasable memory.  So, there are four possible combos.
    if (NewPc->Erasable) {
        if (NewPc->Unbanked) {
            Min = 0;
            Max = Block1 ? 01777 : 01377;
        } else if (!Block1 && NewPc->Banked) {
            Min = 01400;
            Max = 01777;
            NewPc->EB += BankIncrement;
        } else
            goto ImplementationError;
    } else if (NewPc->Fixed) {
        if (NewPc->Banked) {
            Min = Block1 ? 06000 : 02000;
            Max = Block1 ? 07777 : 03777;
            NewPc->FB += BankIncrement;
        } else if (NewPc->Unbanked) {
            Min = Block1 ? 02000 : 04000;
            Max = 07777;
        } else
            goto ImplementationError;
    } else
        goto ImplementationError;

    // Did the new S-register value go out of range for the memory region?
    if (i < Min) {
        NewPc->Overflow = 1;
        NewPc->SReg = Min;
    } else if (i > Max) {
        NewPc->Overflow = 1;
        NewPc->SReg = Max;
    }  

    // Back-convert to get a pseudo-address.
    if (NewPc->Unbanked)
        NewPc->Value = NewPc->SReg;
    else if (NewPc->Erasable) {
        NewPc->Value = (NewPc->SReg - 01400) + 0400 * NewPc->EB;
    }
    else if (NewPc->Fixed) {
        NewPc->Value = 010000 + (NewPc->SReg - 02000) + 02000 * NewPc->FB;
        if (NewPc->Super && NewPc->FB >= 030)
            NewPc->Value += 010 * 02000;
    } else
        goto ImplementationError;
    return;

    ImplementationError:
    // Can't occur, but I give it a good pinch if it does!
    NewPc->Invalid = 1;
}
back to top