Revision d5003cfb1a074bccf62e386669486d31b0bd303c authored by Mike Stewart on 18 July 2020, 01:17:35 UTC, committed by Mike Stewart on 18 July 2020, 01:17:35 UTC
1 parent fe5a260
yaLVDC.h
/*
* Copyright 2019-20 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
*
* In addition, as a special exception, Ronald S. Burkey gives permission to
* link the code of this program with the Orbiter SDK library (or with
* modified versions of the Orbiter SDK library that use the same license as
* the Orbiter SDK library), and distribute linked combinations including
* the two. You must obey the GNU General Public License in all respects for
* all of the code used other than the Orbiter SDK library. If you modify
* this file, you may extend this exception to your version of the file,
* but you are not obligated to do so. If you do not wish to do so, delete
* this exception statement from your version.
*
* Filename: yaLVDC.h
* Purpose: Common header for yaLVDC.c and friends.
* Compiler: GNU gcc.
* Reference: http://www.ibibio.org/apollo
* Mods: 2019-09-18 RSB Began.
* 2020-04-29 RSB Added the --ptc switch.
*/
#ifndef yaLVDC_h
#define yaLVDC_h
#include <stdint.h>
#include <limits.h>
///////////////////////////////////////////////////////////////////////
// Function prototypes and any global variables that go with them.
// Length of an LVDC CPU's "computer cycle".
#define SECONDS_PER_CYCLE (168.0/2048000) // About 82us.
// A delay, expressed in number of CPU machine cycles, for which to hold the
// plotter, printer, and typewriter ready lines at a BUSY level after writing
// data or commands to those peripherals. Yes, it could be fine-tuned a lot
// more than this! All I really know is that 0 is too short and 45 is too long.
#define REALLY_SHORT_BUSY_CYCLES 5
#define SHORT_BUSY_CYCLES 15
#define MEDIUM_BUSY_CYCLES 20
#define PERIPHERAL_BUSY_CYCLES 30
#define CASE_CHANGE_BUSY_CYCLES 1060
#define CARRIAGE_RETURN_BUSY_CYCLES 40
// See debug.c
// (Note that debug.c relates to debugging yaLVDC and not to the
// features yaLVDC itself contains for debugging LVDC code.)
// The idea here is that there's a set of flags which determine which
// features of debug.c are active, and which are not. If DEBUG_FLAGS
// is set to DEBUG_NONE, then all debugging code is inactive. If it
// is set to a bitwise-OR of the various flags, then just that
// combination of features is active. Using DEBUG_NONE will be the
// normal case after yaLVDC is fully developed.
#define DEBUG_NONE 0
#define DEBUG_SYMBOLS 1
#define DEBUG_SOURCE_LINES 2
#define DEBUG_CORE 4
#define DEBUG_TYPEWRITER 8
#define DEBUG_FLAGS DEBUG_NONE
#if DEBUG_FLAGS != DEBUG_NONE
#define DEBUG
#endif
// See yaLVDC.c
extern int clockDivisor;
extern int inhibitFetchMessages;
extern unsigned long cycleCount;
#define MAX_SYMBOL_LENGTH 10
typedef struct
{
int temporary; // 0=permanent, 1=temporary.
int module;
int sector;
int syllable;
int location;
char name[MAX_SYMBOL_LENGTH];
int number;
int whichType; // 0=name, 1=number, 2=address.
} breakpoint_t;
#define MAX_BREAKPOINTS 50
extern breakpoint_t breakpoints[MAX_BREAKPOINTS];
extern int numBreakpoints;
typedef struct
{
int32_t fromWhere;
int32_t toWhere;
unsigned long cycleCount;
unsigned long instructionCount;
int16_t fromInstruction;
} backtrace_t;
// A circular buffer for backtraces. If firstEmptyBacktrace == firstUsedBacktrace,
// then the buffer is empty, so it can hold up to MAX_BACKTRACES-1 entries.
// When adding a new one, if the buffer is already full then the oldest one
// is silently deleted. Yes, it would be preferable instead of a circular buffer
// to unroll as subroutines were returned from, but that's beyond my ability to
// analyze, given the nature of the code.
#define MAX_BACKTRACES 101
extern backtrace_t backtraces[MAX_BACKTRACES];
extern int firstUsedBacktrace, firstEmptyBacktrace;
extern int runStepN; // # of emulation steps left to run until pausing. INT_MAX is unlimited.
extern int runNextN;
extern int inNextNotStep, inNextHop, inNextHopIM, inNextHopIS, inNextHopS,
inNextHopLOC;
#define NEXT_BACKTRACE(n) (((n) + 1) % MAX_BACKTRACES)
void
addBacktrace(int16_t fromInstruction, int32_t fromWhere, int32_t toWhere,
unsigned long cycleCount, unsigned long instructionCount);
// CPU/Panel status/commands.
extern int panelPause;
extern int panelPatternDataAddress;
extern int panelPatternDM, panelPatternDS, panelPatternDLOC;
extern int panelPatternInstructionAddress;
extern int panelPatternDataValue;
extern int panelDisplayModePlus;
extern int panelDisplaySelect;
extern int panelAddressCompare;
extern int panelModeControl;
extern int cpuIsRunning;
extern int cpuCurrentAddressData;
extern int cpuCurrentAddressInstruction;
extern int cpuCurrentValueData;
extern int cpuCurrentAccumulator;
// See parseCommandLineArguments.c
extern char *coreFilename;
extern int ptc;
extern int coldStart;
int
parseCommandLineArguments(int argc, char *argv[]);
// See readAssemblies.c
// Note that state_t contains just persistent values ... i.e., stuff in the CPU
// that I expect to be stored in ferrite cores, and thus to survive a power
// cycle, because the emulator will periodically write it out to a persistence
// file that will be reread at startup. So if there's non-persistent state
// stuff, it needs to be handled using some other mechanism than state_t.
typedef struct
{
int restart;
int32_t hop;
int32_t acc;
int32_t pq;
int32_t hopSaver; // otherwise known as the "HOP saver" register.
int32_t core[8][16][3][256];
int32_t pio[01000];
int32_t cio[01000]; // PTC only.
int32_t prs[01000]; // PTC only.
struct
{
int pending; // True or False, if last instruction was EXM or not.
int32_t nextHop; // HOP constant for next instruction (as if no pending EXM-modified instruction).
int32_t pendingHop; // HOP constant for the pending EXM-modified instruction.
int16_t pendingInstruction; // the EXM-modified instruction.
} pendingEXM; // LVDC only.
// The following three are reset at the start of a runOneInstruction()
// invocation, but changed if the associated pio[], cio[], or prs
// change during the runOneInstruction(). That's because
// runOneInstruction() itself does not do anything other than to change
// those values, without performed any of the explicit actions they're
// associated with in peripheral space, so it has to convey that some
// action is necessary by external code.
int pioChange;
int cioChange;
int prsChange;
// The following is normally -1, but is set by runOneInstruction()
// to the address of a HOP, TRA, TMI, or TNZ if it causes a jump
// to an instruction that's out of sequence.
int32_t lastHop;
int16_t lastInstruction;
// Counters used for faking up busy signals for printer, plotter, typewriter.
int busyCountPlotter;
int busyCountPrinter;
int busyCountTypewriter;
int bbPlotter;
int bbPrinter;
int bbTypewriter;
int caseChange;
int currentTypewriterInterrupt;
int currentCaseInterrupt;
int lastTypewriterCharCase;
int interruptInhibitLatches;
int masterInterruptLatch;
int progRegA17_22;
int riLastHOP; // Just used for debugging.
int riLastInstruction; // Just used for debugging.
int ai3Shifter;
int cio210CarrBusy;
// The following are used only for generating the check-parity bit in the interrupt
// latch in the aftermath of a PRS instruction. prsDelayedParity[0] and [4] are
// permanently 0, and represent the condition in which a readback of CIO 154 are
// not altered by this check-parity bit. The [1], [2], and [3] entries are used
// for CIO 154 immediately following the PRS, one cycle after PRS, or two cycles
// after.
int prsDelayedParity[5];
int prsParityDelayCount;
int inhibit250;
// It's possible that I missed seeing it, but the PTC documentation doesn't cover
// something which I think is necessary, and that's that you can't have an interrupt
// immediately following an instruction like HOP, TRA, TNZ, or TMI (in some cases),
// since the HOPSAVE register would be immediately overwritten prior to the called
// subroutine saving it, and hence would destroy the return address of the called
// subroutine. The inhibitInterruptsOneCycle field can be set within runOneInstruction(),
// and inhibit interrupts for a single instruction cycle (being immediately reset
// upon the next entry to runOneInstruction()).
int inhibitInterruptsOneCycle;
} state_t;
extern state_t state;
typedef struct
{
char name[MAX_SYMBOL_LENGTH];
uint8_t module;
uint8_t sector;
uint8_t syllable; // 0,1 instructions, 2 data.
uint8_t loc;
} symbol_t;
typedef struct
{
char *line;
uint8_t module;
uint8_t sector;
uint8_t syllable; // 0,1 instructions, 2 data.
uint8_t loc;
int lineNumber;
uint16_t assembled;
uint8_t dm;
uint8_t ds;
} sourceLine_t;
#define MAX_ASSEMBLIES 16
typedef struct
{
char *name;
symbol_t *symbols;
int numSymbols;
sourceLine_t *sourceLines;
int numSourceLines;
int codeWords;
int dataWords;
} assembly_t;
extern assembly_t assemblies[MAX_ASSEMBLIES];
extern int numAssemblies;
extern int freezeAssemblies;
int
readAssemblies(void);
int
cmpSourceByAddress(const void *r1, const void *r2);
int
cmpSymbolsByAddress(const void *r1, const void *r2);
// See readWriteCore.c
int
readCore(void);
int
writeCore(void);
// See runOneInstruction.c
typedef struct
{
uint8_t im;
uint8_t is;
uint8_t s;
uint8_t loc;
uint8_t dm;
uint8_t ds;
uint8_t dupin;
uint8_t dupdn;
} hopStructure_t;
extern int instructionFromDataMemory;
extern int dataFromInstructionMemory;
extern int dataOverwritesInstructionMemory;
int
runOneInstruction(int *cyclesUsed);
int
parseHopConstant(int hopConstant, hopStructure_t *hopStructure);
int
formHopConstant(hopStructure_t *hopStructure, int *hopConstant);
int
fetchData(int module, int residual, int sector, int loc, int32_t *data,
int *dataFromInstructionMemory);
int
storeData(int module, int residual, int sector, int loc, int32_t data,
int *dataOverwritesInstructionMemory);
int
fetchInstruction(int module, int sector, int syllable, int loc,
uint16_t *instruction, int *instructionFromDataMemory);
void
checkForInterrupts(void);
// See gdbInterface.c
int
gdbInterface(unsigned long instructionCount, unsigned long cycleCount,
breakpoint_t *breakpoint);
// See processInterruptsAndIO.c
int
processInterruptsAndIO(void);
// See virtualWire.c
// Socket stuff.
#define MAX_LISTENERS 7
extern int ServerBaseSocket;
extern int PortNum;
extern int virtualWireErrorCodes;
extern int typewriterMargin;
extern int typewriterTabStop;
extern int typewriterCharsInLine;
// Functions.
int
InitializeSocketSystem(void);
void
UnblockSocket(int SocketNum);
int
EstablishSocket(unsigned short portnum, int MaxClients);
int
CallSocket(char *hostname, unsigned short portnum);
void
connectCheck(void);
int
pendingVirtualWireActivity(void);
// Used only during development, for printing certain kinds of debugging messages.
#if defined(DEBUG) && (DEBUG & DEBUG_TYPEWRITER) != 0
#ifndef yaLVDC_C
void dPrintoutsTypewriter(char *);
#else
void
dPrintoutsTypewriter(char *msg)
{
hopStructure_t hs;
parseHopConstant(state.riLastHOP, &hs);
printf(
"Cycles=%lu, ACC=%09o, INT=%09o, TINT=%09o, TCNT=%d, TBB=%d, TCHARS=%d, PCNT=%d, PBB=%d, HOP=%o-%02o-%o-%03o %o-%02o, INS=%05o: %s\n",
cycleCount, state.acc, state.cio[0154], state.currentTypewriterInterrupt,
state.busyCountTypewriter, state.bbTypewriter, typewriterCharsInLine, state.busyCountPrinter, state.bbPrinter, hs.im, hs.is, hs.s, hs.loc, hs.dm, hs.ds, state.riLastInstruction, msg);
}
#endif // yaLVDC_C
#else
#define dPrintoutsTypewriter(msg)
#endif // DEBUG_TYPEWRITER
#ifdef DEBUG
void
dPrintouts(void);
#else
#define dPrintouts()
#endif
#endif // yaLVDC_h
Computing file changes ...