diff --git a/.gitattributes b/.gitattributes index bfb843f0..d3c36027 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,6 @@ *.vcproj binary *.exe binary *.bin binary +*.rim binary sim_rev.h export-subst diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index a58174ec..a6a76a14 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -25,13 +25,14 @@ cpu PDP-1 central processor - 210Mar-12 RMS Fixed & vs && in Ea_ch (Michael Bloom) + 21-Mar-12 RMS Fixed & vs && in Ea_ch (Michael Bloom) 30-May-07 RMS Fixed typo in SBS clear (Norm Lastovica) 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support 28-Jun-06 RMS Fixed bugs in MUS and DIV 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 09-Nov-04 RMS Added instruction history + 08-Feb-04 PLB Added display device spacewar/test switches 07-Sep-03 RMS Added additional explanation on I/O simulation 01-Sep-03 RMS Added address switches for hardware readin 23-Jul-03 RMS Revised to detect I/O wait hang @@ -360,6 +361,10 @@ extern int32 dt (int32 inst, int32 dev, int32 dat); extern int32 drm (int32 inst, int32 dev, int32 dat); extern int32 clk (int32 inst, int32 dev, int32 dat); extern int32 dcs (int32 inst, int32 dev, int32 dat); +#ifdef USE_DISPLAY +extern int32 dpy (int32 inst, int32 dev, int32 dat, int32 dat2); +extern int32 spacewar (int32 inst, int32 dev, int32 dat); +#endif const int32 sc_map[512] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ @@ -1203,6 +1208,11 @@ while (reason == 0) { /* loop until halted */ io_data = ptp (IR, dev, IO); break; +#ifdef USE_DISPLAY + case 007: /* display */ + io_data = dpy (IR, dev, IO, AC); + break; +#endif case 010: /* leave ring mode */ if (cpu_unit.flags & UNIT_1D) PF = PF & ~PF_RNG; @@ -1212,7 +1222,12 @@ while (reason == 0) { /* loop until halted */ case 011: /* enter ring mode */ if (cpu_unit.flags & UNIT_1D) PF = PF | PF_RNG; - else reason = stop_inst; + else +#ifdef USE_DISPLAY + io_data = spacewar (IR, dev, IO); +#else + reason = stop_inst; +#endif break; case 022: /* data comm sys */ @@ -1685,3 +1700,19 @@ for (k = 0; k < lnt; k++) { /* print specified */ } /* end for */ return SCPE_OK; } + +#ifdef USE_DISPLAY +/* set "test switches"; from display code */ +void +cpu_set_switches(unsigned long bits) +{ +/* just what we want; smaller CPUs might want to shift down? */ +TW = bits; +} + +unsigned long +cpu_get_switches(void) +{ +return TW; +} +#endif diff --git a/PDP1/pdp1_dpy.c b/PDP1/pdp1_dpy.c new file mode 100644 index 00000000..805de2f5 --- /dev/null +++ b/PDP1/pdp1_dpy.c @@ -0,0 +1,153 @@ +/* pdp1_dpy.c: PDP-1 display simulator + + Copyright (c) 2004, Philip L. Budne + Copyright (c) 1993-2003, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + dpy Type 30 Display for the PDP-1 + 02-Feb-04 PLB Revamp intensity levels + 02-Jan-04 DAG Provide dummy global when display not supported + 16-Sep-03 PLB Update for SIMH 3.0-2 + 12-Sep-03 PLB Add spacewar switch support + 04-Sep-03 PLB Start from pdp1_lp.c +*/ + +#ifdef USE_DISPLAY +#include "pdp1_defs.h" +#include "display/display.h" + +extern int32 ios, cpls, iosta, PF; +extern int32 stop_inst; + +t_stat dpy_svc (UNIT *uptr); +t_stat dpy_reset (DEVICE *dptr); + +/* DPY data structures + + dpy_dev DPY device descriptor + dpy_unit DPY unit + dpy_reg DPY register list +*/ + +#define CYCLE_TIME 5 /* 5us memory cycle */ +#define DPY_WAIT (50/CYCLE_TIME) /* 50us */ + +UNIT dpy_unit = { + UDATA (&dpy_svc, UNIT_ATTABLE, 0), DPY_WAIT }; + +DEVICE dpy_dev = { + "DPY", &dpy_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &dpy_reset, + NULL, NULL, NULL, + NULL, DEV_DIS | DEV_DISABLE }; + +/* Display IOT routine */ + +int32 dpy (int32 inst, int32 dev, int32 io, int32 ac) +{ +int32 x, y; +int level; + +if (dpy_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | io; /* stop if requested */ +if (GEN_CPLS (inst)) { /* comp pulse? */ + ios = 0; /* clear flop */ + cpls = cpls | CPLS_DPY; } /* request completion */ +else cpls = cpls & ~CPLS_DPY; + +x = (ac >> 8) & 01777; /* high ten bits of ac */ +y = (io >> 8) & 01777; /* high ten bits of io */ +/* + * convert one's complement -511..+511 center origin + * to 0..1022 (lower left origin) + */ +if (x & 01000) + x ^= 01000; +else + x += 511; +if (y & 01000) + y ^= 01000; +else + y += 511; + +/* intensity, from values seen in spacewar (40,00,01,02,03) */ +switch ((inst >> 6) & 077) { +case 01: level = DISPLAY_INT_MAX-5; break; +case 02: level = DISPLAY_INT_MAX-4; break; +case 03: level = DISPLAY_INT_MAX-2; break; +case 040: /* super bright? */ +default: level = DISPLAY_INT_MAX; break; +} + +if (display_point(x,y,level,0)) { + /* here with light pen hit */ + PF = PF | 010; /* set prog flag 3 */ + iosta |= IOS_TTI; /* set io status flag */ +} +else + iosta &= ~IOS_TTI; /* clear io status flag */ +sim_activate (&dpy_unit, dpy_unit.wait); /* activate */ + +return io; +} + +/* + * Unit service routine + * + * Under X11 this includes polling for events, so it can't be + * call TOO infrequently... + */ +t_stat dpy_svc (UNIT *uptr) +{ + if (cpls & CPLS_DPY) { /* completion pulse? */ + ios = 1; /* restart */ + cpls = cpls & ~CPLS_DPY; } /* clr pulse pending */ + + display_age(dpy_unit.wait*CYCLE_TIME, 1); + sim_activate (&dpy_unit, dpy_unit.wait); /* requeue! */ + return SCPE_OK; +} + +/* Reset routine */ + +t_stat dpy_reset (DEVICE *dptr) +{ + if (!(dptr->flags & DEV_DIS)) { + display_reset(); + cpls = cpls & ~CPLS_DPY; + iosta = iosta & ~(IOS_PNT | IOS_SPC); /* clear flags */ + } + sim_cancel (&dpy_unit); /* deactivate unit */ + return SCPE_OK; +} + +int32 spacewar (int32 inst, int32 dev, int32 io) +{ +if (dpy_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | io; /* stop if requested */ +return spacewar_switches; +} +#else /* USE_DISPLAY not defined */ +char pdp1_dpy_unused; /* sometimes empty object modules cause problems */ +#endif /* USE_DISPLAY not defined */ diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index 210d01c0..502aa0e2 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -58,7 +58,9 @@ extern DEVICE dt_dev; extern DEVICE drm_dev; extern DEVICE drp_dev; extern DEVICE dcs_dev, dcsl_dev; +#if defined(USE_DISPLAY) extern DEVICE dpy_dev; +#endif extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 M[]; @@ -95,7 +97,9 @@ DEVICE *sim_devices[] = { &drp_dev, &dcs_dev, &dcsl_dev, -/* &dpy_dev, */ +#if defined(USE_DISPLAY) + &dpy_dev, +#endif NULL }; diff --git a/PDP1/spacewar1/README b/PDP1/spacewar1/README new file mode 100644 index 00000000..116e726a --- /dev/null +++ b/PDP1/spacewar1/README @@ -0,0 +1,64 @@ +Preliminary PDP-1 Spacewar README +Phil Budne +February 9, 2004 + +Both spacewar.mac and macro1.c are available from Phil's CVS server. +see http://www.ultimate.com/phil/xy + +cvs -d :pserver:anonymous@cvs.ultimate.com:/home/cvs login +Password: anonymous +cvs -d :pserver:anonymous@cvs.ultimate.com:/home/cvs co history/pdp1 + + +README.MIT + readme from MIT + contains history, and instructions + +spacewar.mac + spacewar 3.1 (24 sep 62) retyped at MIT from a listing, + originally assembled using a Perl macro-expander and assembler, + and run under a Java PDP-1 emulator. + + This version modified by Phil Budne to assemble under his + version of "macro1" (see below) + + Note that low memory (locations 6 thru 31) contains various + manifest constants which can be tweaked to alter the game's + behavior! + +spacewar.rim + above assembled by Phil Budne's macro1 + + PDP-1 RIM of "loader" followed by loader blocks: + + PDP-1 simulator V4.0 + sim> set dpy enable + sim> attach ptr spacewar.rim + sim> boot ptr + + controls compatible with MIT Java simulation, see README.LCS + or display/README from your SIMH distribution + +munch.mac + "munching squares" display hack, reconstructed + from world.std.com/~dpbsmith/munch.html + +munch.rim + binary of munching squares. + + reads console switches: + Upto 18 simulated console switches, toggled by hitting keys: + + 123 456 789 qwe rty uio + + space bar clears all switches. + + assembled with '-r' option, so it can be "loaded" directly: + + PDP-1 simulator V4.0 + sim> set dpy enable + sim> load munch.rim + sim> run + +macro1.c + Phil Budne's version of the MACRO cross-assembler diff --git a/PDP1/spacewar1/README.MIT b/PDP1/spacewar1/README.MIT new file mode 100644 index 00000000..9be283a6 --- /dev/null +++ b/PDP1/spacewar1/README.MIT @@ -0,0 +1,25 @@ + + Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell, and + Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by Stephen + Russell, Peter Samson, Dan Edwards, and Martin Graetz, together with + Alan Kotok, Steve Piner, and Robert A Saunders. Spacewar! is in the + public domain, but this credit paragraph must accompany all + distributed versions of the program. + + This is the original version! Martin Graetz provided us with a printed + version of the source. We typed in in again - it was about 40 pages + long - and re-assembled it with a PDP-1 assembler written in PERL. The + resulting binary runs on a PDP-1 emulator written as a Java applet. + The code is extremely faithful to the original. There are only two + changes. 1)The spaceships have been made bigger and 2) The overall + timing has been special cased to deal with varying machine speeds. + + The sources are available in a subdirectory called "sources". + + The "a", "s", "d", "f" keys control one of the spaceships. The "k", + "l", ";", "'" keys control the other. The controls are spin one way, + spin the other, thrust, and fire. + + Barry Silverman + Brian Silverman + Vadim Gerasimov diff --git a/PDP1/spacewar1/macro1.c b/PDP1/spacewar1/macro1.c new file mode 100644 index 00000000..47b78ef6 --- /dev/null +++ b/PDP1/spacewar1/macro1.c @@ -0,0 +1,3068 @@ +/* + * $Id: macro1.c,v 1.73 2003/10/23 22:49:45 phil Exp $ + * + * TODO: + * have flex() use nextfiodec()?? (what if legal in repeat???) + * "flexx" should give right justified result??? + * squawk if nextfiodec called in a repeat w/ a delim? + * + * forbid variables/constants in macros + * forbid text in repeat?? + * forbid start in repeat or macro + * use same error TLA's as MACRO??? + * IPA error for overbar on LHS of = + * variables returns value?? + * + * macro addressing: labels defined during macro are local use only???? + * spacewar expects this??? (is it wrong?) + * + * self-feeding lines: \n legal anywhere \t is + * read next token into "token" buffer -- avoid saving "line"? + * remove crocks from "define" + * list title (first line of file) should not be parsed as source? + * incorrect listing for bare "start" + * list only 4 digits for address column + * + * other; + * note variables in symbol dump, xref? + * no "permenant" symbols; flush -p? rename .ini? + * keep seperate macro/pseudo table? + * verify bad input(?) detected + * implement dimension pseudo? + * remove crocks for '/' and ','? + */ + +/* + * Program: MACRO1 + * File: macro1.c + * Author: Gary A. Messenbrink (macro8) + * MACRO7 modifications: Bob Supnik + * MACRO1 modifications: Bob Supnik + * slashed to be more like real MACRO like by Phil Budne + * + * Purpose: A 2 pass PDP-1 assembler + * + * NAME + * macro1 - a PDP-1 assembler. + * + * SYNOPSIS: + * macro1 [ -d -p -m -r -s -x ] inputfile inputfile... + * + * DESCRIPTION + * This is a cross-assembler to for PDP-1 assembly language programs. + * It will produce an output file in rim format only. + * A listing file is always produced and with an optional symbol table + * and/or a symbol cross-reference (concordance). The permanent symbol + * table can be output in a form that may be read back in so a customized + * permanent symbol table can be produced. Any detected errors are output + * to a separate file giving the filename in which they were detected + * along with the line number, column number and error message as well as + * marking the error in the listing file. + * The following file name extensions are used: + * .mac source code (input) + * .lst assembly listing (output) + * .rim assembly output in DEC's rim format (output) + * .prm permanent symbol table in form suitable for reading after + * the EXPUNGE pseudo-op. + * .sym "symbol punch" tape (for DDT, or reloading into macro) + * + * OPTIONS + * -d Dump the symbol table at end of assembly + * -p Generate a file with the permanent symbols in it. + * (To get the current symbol table, assemble a file than has only + * START in it.) + * -x Generate a cross-reference (concordance) of user symbols. + * -r Output a tape using only RIM format (else output block loader) + * -s Output a symbol dump tape (loader + loader blocks) + * -S file + * Read a symbol tape back in + * + * DIAGNOSTICS + * Assembler error diagnostics are output to an error file and inserted + * in the listing file. Each line in the error file has the form + * + * :: : error: at Loc = + * + * An example error message is: + * + * bintst.7:17:9 : error: undefined symbol "UNDEF" at Loc = 07616 + * + * The error diagnostics put in the listing start with a two character + * error code (if appropriate) and a short message. A carat '^' is + * placed under the item in error if appropriate. + * An example error message is: + * + * 17 07616 3000 DAC UNDEF + * UD undefined ^ + * 18 07617 1777 TAD I DUMMY + * + * Undefined symbols are marked in the symbol table listing by prepending + * a '?' to the symbol. Redefined symbols are marked in the symbol table + * listing by prepending a '#' to the symbol. Examples are: + * + * #REDEF 04567 + * SWITCH 07612 + * ?UNDEF 00000 + * + * Refer to the code for the diagnostic messages generated. + * + * REFERENCES: + * This assembler is based on the pal assember by: + * Douglas Jones and + * Rich Coon + * + * COPYRIGHT NOTICE: + * This is free software. There is no fee for using it. You may make + * any changes that you wish and also give it away. If you can make + * a commercial product out of it, fine, but do not put any limits on + * the purchaser's right to do the same. If you improve it or fix any + * bugs, it would be nice if you told me and offered me a copy of the + * new version. + * + * + * Amendments Record: + * Version Date by Comments + * ------- ------- --- --------------------------------------------------- + * v1.0 12Apr96 GAM Original + * v1.1 18Nov96 GAM Permanent symbol table initialization error. + * v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators. + * v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants). + * v1.4 29Nov96 GAM Fixed bug in checksum generation. + * v2.1 08Dec96 GAM Added concordance processing (cross reference). + * v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants). + * v2.3 2Feb97 GAM Fixed paging problem in cross reference output. + * v3.0 14Feb97 RMS MACRO8X features. + * ? RMS MACRO7 + * ? RMS MACRO1 released w/ lispswre + * ? RMS MACRO1 released w/ tools + * ? RMS MACRO1 released w/ ddt1 + * 2003 PLB major reworking + */ + + +#include +#include +#include +#include + +#define LINELEN 96 +#define LIST_LINES_PER_PAGE 60 /* Includes 3 line page header. */ +#define NAMELEN 128 +#define SYMBOL_COLUMNS 5 +#define SYMLEN 7 +/*#define SYMSIG 4 /* EXP: significant chars in a symbol */ +#define SYMBOL_TABLE_SIZE 8192 +#define MAC_MAX_ARGS 20 +#define MAC_MAX_LENGTH 8192 +#define MAC_TABLE_LENGTH 1024 /* Must be <= 4096. */ + +#define MAX_LITERALS 1000 +#define MAX_CONSTANTS 10 /* max number of "constants" blocks */ + +#define XREF_COLUMNS 8 + +#define ADDRESS_FIELD 0007777 +#define INDIRECT_BIT 0010000 +#define OP_CODE 0760000 + +#define CONCISE_LC 072 +#define CONCISE_UC 074 + +/* Macro to get the number of elements in an array. */ +#define DIM(a) (sizeof(a)/sizeof(a[0])) + +#define ISBLANK(c) ((c==' ') || (c=='\f')) +#define ISEND(c) ((c=='\0')|| (c=='\n') || (c == '\t')) +#define ISDONE(c) ((c=='/') || ISEND(c)) + +#define ISOVERBAR(c) (c == '\\' || c == '~') + +/* Macros for testing symbol attributes. Each macro evaluates to non-zero */ +/* (true) if the stated condtion is met. */ +/* Use these to test attributes. The proper bits are extracted and then */ +/* tested. */ +#define M_DEFINED(s) (((s) & DEFINED) == DEFINED) +#define M_DUPLICATE(s) (((s) & DUPLICATE) == DUPLICATE) +#define M_FIXED(s) (((s) & FIXED) == FIXED) +#define M_LABEL(s) (((s) & LABEL) == LABEL) +#define M_PSEUDO(s) (((s) & PSEUDO) == PSEUDO) +#define M_EPSEUDO(s) (((s) & EPSEUDO) == EPSEUDO) +#define M_MACRO(s) (((s) & MACRO) == MACRO) +#define M_NOTRDEF(s) (((s) & NOTRDEF) != 0) + +typedef unsigned char BOOL; +typedef unsigned char BYTE; +typedef int WORD32; + +#ifndef FALSE + #define FALSE 0 + #define TRUE (!FALSE) +#endif + +/* Line listing styles. Used to control listing of lines. */ +enum linestyle_t +{ + LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL, LINE_LOC +}; +typedef enum linestyle_t LINESTYLE_T; + +/* Symbol Types. */ +/* Note that the names that have FIX as the suffix contain the FIXED bit */ +/* included in the value. */ +enum symtyp +{ + UNDEFINED = 0000, + DEFINED = 0001, + FIXED = 0002, + LABEL = 0010 | DEFINED, + REDEFINED = 0020 | DEFINED, + DUPLICATE = 0040 | DEFINED, + PSEUDO = 0100 | FIXED | DEFINED, + EPSEUDO = 0200 | FIXED | DEFINED, + MACRO = 0400 | DEFINED, + DEFFIX = DEFINED | FIXED, + NOTRDEF = (MACRO | PSEUDO | LABEL | FIXED) & ~DEFINED +}; +typedef enum symtyp SYMTYP; + +enum pseudo_t { + DECIMAL, + DEFINE, + FLEX, + CONSTANTS, + OCTAL, + REPEAT, + START, + CHAR, + VARIABLES, + TEXT, + NOINPUT, + EXPUNGE +}; +typedef enum pseudo_t PSEUDO_T; + +struct sym_t +{ + SYMTYP type; + char name[SYMLEN]; + WORD32 val; + WORD32 xref_index; + WORD32 xref_count; +}; +typedef struct sym_t SYM_T; + +struct emsg_t +{ + char *list; + char *file; +}; +typedef struct emsg_t EMSG_T; + +struct errsave_t +{ + char *mesg; + WORD32 col; +}; +typedef struct errsave_t ERRSAVE_T; + +/*----------------------------------------------------------------------------*/ + +/* Function Prototypes */ + +int binarySearch( char *name, int start, int symbol_count ); +int compareSymbols( const void *a, const void *b ); +SYM_T *defineLexeme( WORD32 start, WORD32 term, WORD32 val, SYMTYP type ); +SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start); +void errorLexeme( EMSG_T *mesg, WORD32 col ); +void errorMessage( EMSG_T *mesg, WORD32 col ); +void errorSymbol( EMSG_T *mesg, char *name, WORD32 col ); +SYM_T eval( void ); +SYM_T *evalSymbol( void ); +void getArgs( int argc, char *argv[] ); +SYM_T getExpr( void ); +WORD32 getExprs( void ); +WORD32 incrementClc( void ); +WORD32 literal( WORD32 value ); +BOOL isLexSymbol(); +char *lexemeToName( char *name, WORD32 from, WORD32 term ); +void listLine( void ); +SYM_T *lookup( char *name, int type ); +void moveToEndOfLine( void ); +void next(int); +void onePass( void ); +void printCrossReference( void ); +void printErrorMessages( void ); +void printLine(char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle); +void printPageBreak( void ); +void printPermanentSymbolTable( void ); +void printSymbolTable( void ); +BOOL pseudo( PSEUDO_T val ); +void punchLocObject( WORD32 loc, WORD32 val ); +void punchOutObject( WORD32 loc, WORD32 val ); +void punchLeader( WORD32 count ); +void punchLoader( void ); +void flushLoader( void ); +void readLine( void ); +void saveError( char *mesg, WORD32 cc ); +void topOfForm( char *title, char *sub_title ); +void constants(void); +void variables(void); +void eob(void); +void dump_symbols(void); + +/*----------------------------------------------------------------------------*/ + +/* Table of pseudo-ops (directives) which are used to setup the symbol */ +/* table on startup */ +SYM_T pseudos[] = +{ + { PSEUDO, "consta", CONSTANTS }, + { PSEUDO, "define", DEFINE }, /* Define macro. */ + { PSEUDO, "repeat", REPEAT }, + { PSEUDO, "start", START }, /* Set starting address. */ + { PSEUDO, "variab", VARIABLES }, + { PSEUDO, "text", TEXT }, + { PSEUDO, "noinpu", NOINPUT }, + { PSEUDO, "expung", EXPUNGE }, +/* the following can appear in expressions: */ + { EPSEUDO, "charac", CHAR }, + { EPSEUDO, "decima", DECIMAL }, /* base 10. */ + { EPSEUDO, "flexo", FLEX }, + { EPSEUDO, "octal", OCTAL }, /* Read literal constants in base 8. */ +}; + +/* Symbol Table */ +/* The table is put in lexical order on startup, so symbols can be */ +/* inserted as desired into the initial table. */ +#define DIO 0320000 +#define JMP 0600000 +SYM_T permanent_symbols[] = +{ + /* Memory Reference Instructions */ + { DEFFIX, "and", 0020000 }, + { DEFFIX, "ior", 0040000 }, + { DEFFIX, "xor", 0060000 }, + { DEFFIX, "xct", 0100000 }, + { DEFFIX, "lac", 0200000 }, + { DEFFIX, "lio", 0220000 }, + { DEFFIX, "dac", 0240000 }, + { DEFFIX, "dap", 0260000 }, + { DEFFIX, "dip", 0300000 }, + { DEFFIX, "dio", 0320000 }, + { DEFFIX, "dzm", 0340000 }, + { DEFFIX, "add", 0400000 }, + { DEFFIX, "sub", 0420000 }, + { DEFFIX, "idx", 0440000 }, + { DEFFIX, "isp", 0460000 }, + { DEFFIX, "sad", 0500000 }, + { DEFFIX, "sas", 0520000 }, + { DEFFIX, "mul", 0540000 }, + { DEFFIX, "mus", 0540000 }, /* for spacewar */ + { DEFFIX, "div", 0560000 }, + { DEFFIX, "dis", 0560000 }, /* for spacewar */ + { DEFFIX, "jmp", 0600000 }, + { DEFFIX, "jsp", 0620000 }, + { DEFFIX, "skip", 0640000 }, /* for spacewar */ + { DEFFIX, "cal", 0160000 }, + { DEFFIX, "jda", 0170000 }, + { DEFFIX, "i", 0010000 }, + { DEFFIX, "skp", 0640000 }, + { DEFFIX, "law", 0700000 }, + { DEFFIX, "iot", 0720000 }, + { DEFFIX, "opr", 0760000 }, + { DEFFIX, "nop", 0760000 }, + /* Shift Instructions */ + { DEFFIX, "ral", 0661000 }, + { DEFFIX, "ril", 0662000 }, + { DEFFIX, "rcl", 0663000 }, + { DEFFIX, "sal", 0665000 }, + { DEFFIX, "sil", 0666000 }, + { DEFFIX, "scl", 0667000 }, + { DEFFIX, "rar", 0671000 }, + { DEFFIX, "rir", 0672000 }, + { DEFFIX, "rcr", 0673000 }, + { DEFFIX, "sar", 0675000 }, + { DEFFIX, "sir", 0676000 }, + { DEFFIX, "scr", 0677000 }, + { DEFFIX, "1s", 0000001 }, + { DEFFIX, "2s", 0000003 }, + { DEFFIX, "3s", 0000007 }, + { DEFFIX, "4s", 0000017 }, + { DEFFIX, "5s", 0000037 }, + { DEFFIX, "6s", 0000077 }, + { DEFFIX, "7s", 0000177 }, + { DEFFIX, "8s", 0000377 }, + { DEFFIX, "9s", 0000777 }, + /* Skip Microinstructions */ + { DEFFIX, "sza", 0640100 }, + { DEFFIX, "spa", 0640200 }, + { DEFFIX, "sma", 0640400 }, + { DEFFIX, "szo", 0641000 }, + { DEFFIX, "spi", 0642000 }, + { DEFFIX, "szs", 0640000 }, + { DEFFIX, "szf", 0640000 }, + /*{ DEFFIX, "clo", 0651600 },*/ + + /* Operate Microinstructions */ + { DEFFIX, "clf", 0760000 }, + { DEFFIX, "stf", 0760010 }, + { DEFFIX, "cla", 0760200 }, + /*{ DEFFIX, "lap", 0760300 },*/ + { DEFFIX, "hlt", 0760400 }, + { DEFFIX, "xx", 0760400 }, + { DEFFIX, "cma", 0761000 }, + { DEFFIX, "clc", 0761200 }, + { DEFFIX, "lat", 0762200 }, + { DEFFIX, "cli", 0764000 }, + /* IOT's */ + /*{ DEFFIX, "ioh", 0730000 },*/ + { DEFFIX, "rpa", 0730001 }, + { DEFFIX, "rpb", 0730002 }, + { DEFFIX, "rrb", 0720030 }, + { DEFFIX, "ppa", 0730005 }, + { DEFFIX, "ppb", 0730006 }, + { DEFFIX, "tyo", 0730003 }, + { DEFFIX, "tyi", 0720004 }, + { DEFFIX, "dpy", 0730007 }, /* for spacewar, munching squares! */ + { DEFFIX, "lsm", 0720054 }, + { DEFFIX, "esm", 0720055 }, + { DEFFIX, "cbs", 0720056 }, + { DEFFIX, "lem", 0720074 }, + { DEFFIX, "eem", 0724074 }, + { DEFFIX, "cks", 0720033 }, +}; /* End-of-Symbols for Permanent Symbol Table */ + +/* Global variables */ +SYM_T *symtab; /* Symbol Table */ +int symbol_top; /* Number of entries in symbol table. */ + +#define LOADERBASE 07751 + +/* make it relocatable (DDT expects it at 7751) */ +#define LOADER_IN LOADERBASE +#define LOADER_B (LOADERBASE+06) +#define LOADER_A (LOADERBASE+07) +#define LOADER_CK (LOADERBASE+025) +#define LOADER_EN1 (LOADERBASE+026) + +WORD32 loader[] = { + 0730002, /* in, rpb */ + 0320000+LOADER_A, /* dio a */ + 0100000+LOADER_A, /* xct a */ + 0320000+LOADER_CK, /* dio ck */ + 0730002, /* rpb */ + 0320000+LOADER_EN1, /* dio en1 */ + 0730002, /* b, rpb */ + 0000000, /* a, xx */ + 0210000+LOADER_A, /* lac i a */ + 0400000+LOADER_CK, /* add ck */ + 0240000+LOADER_CK, /* dac ck */ + 0440000+LOADER_A, /* idx a */ + 0520000+LOADER_EN1, /* sas en1 */ + 0600000+LOADER_B, /* jmp b */ + 0200000+LOADER_CK, /* lac ck */ + 0400000+LOADER_EN1, /* add en1 */ + 0730002, /* rpb */ + 0320000+LOADER_CK, /* dio ck */ + 0520000+LOADER_CK, /* sas ck */ + 0760400, /* hlt */ + 0600000+LOADER_IN /* jmp in */ + /* ck, 0 */ + /* en1, 0 */ +}; + +#define LOADERBUFSIZE 0100 /* <=0100, power of 2*/ +#define LOADERBUFMASK (LOADERBUFSIZE-1) /* for block alignment */ + +WORD32 loaderbuf[LOADERBUFSIZE]; +WORD32 loaderbufcount; +WORD32 loaderbufstart; + +/*----------------------------------------------------------------------------*/ + +WORD32 *xreftab; /* Start of the concordance table. */ + +ERRSAVE_T error_list[20]; +int save_error_count; + +char s_detected[] = "detected"; +char s_error[] = "error"; +char s_errors[] = "errors"; +char s_no[] = "No"; +char s_page[] = "Page"; +char s_symtable[] = "Symbol Table"; +char s_xref[] = "Cross Reference"; + +/* Assembler diagnostic messages. */ +/* Some attempt has been made to keep continuity with the PAL-III and */ +/* MACRO-8 diagnostic messages. If a diagnostic indicator, (e.g., IC) */ +/* exists, then the indicator is put in the listing as the first two */ +/* characters of the diagnostic message. The PAL-III indicators where used */ +/* when there was a choice between using MACRO-8 and PAL-III indicators. */ +/* The character pairs and their meanings are: */ +/* DT Duplicate Tag (symbol) */ +/* IC Illegal Character */ +/* ID Illegal Redefinition of a symbol. An attempt was made to give */ +/* a symbol a new value not via =. */ +/* IE Illegal Equals An equal sign was used in the wrong context, */ +/* (e.g., A+B=C, or TAD A+=B) */ +/* II Illegal Indirect An off page reference was made, but a literal */ +/* could not be generated because the indirect bit was already set. */ +/* IR Illegal Reference (address is not on current page or page zero) */ +/* PE Current, Non-Zero Page Exceeded (literal table flowed into code) */ +/* RD ReDefintion of a symbol */ +/* ST Symbol Table full */ +/* UA Undefined Address (undefined symbol) */ +/* VR Value Required */ +/* ZE Zero Page Exceeded (see above, or out of space) */ +EMSG_T duplicate_label = { "DT duplicate", "duplicate label" }; +EMSG_T illegal_blank = { "IC illegal blank", "illegal blank" }; +EMSG_T illegal_character = { "IC illegal char", "illegal character" }; +EMSG_T illegal_expression = { "IC in expression", "illegal expression" }; +EMSG_T label_syntax = { "IC label syntax", "label syntax" }; +EMSG_T not_a_number = { "IC numeric syntax", "numeric syntax of" }; +EMSG_T number_not_radix = { "IC radix", "number not in current radix"}; +EMSG_T symbol_syntax = { "IC symbol syntax", "symbol syntax" }; +EMSG_T illegal_equals = { "IE illegal =", "illegal equals" }; +EMSG_T illegal_indirect = { "II off page", "illegal indirect" }; +EMSG_T illegal_reference = { "IR off page", "illegal reference" }; +EMSG_T undefined_symbol = { "UD undefined", "undefined symbol" }; +EMSG_T misplaced_symbol = { "misplaced symbol", "misplaced symbol" }; +EMSG_T redefined_symbol = { "RD redefined", "redefined symbol" }; +EMSG_T value_required = { "VR value required", "value required" }; +EMSG_T literal_gen_off = { "lit generation off", + "literal generation disabled" }; +EMSG_T literal_overflow = { "PE page exceeded", + "current page literal capacity exceeded" }; +EMSG_T zblock_too_small = { "expr too small", "ZBLOCK value too small" }; +EMSG_T zblock_too_large = { "expr too large", "ZBLOCK value too large" }; +EMSG_T no_pseudo_op = { "not implemented", "Unimplemented pseudo-op" }; +EMSG_T illegal_vfd_value = { "width out of range", + "VFD field width not in range" }; +EMSG_T no_literal_value = { "no value", "No literal value" }; +EMSG_T text_string = { "no delimiter", + "Text string delimiters not matched" }; +EMSG_T lt_expected = { "'<' expected", "'<' expected" }; +EMSG_T symbol_table_full = { "ST Symbol Tbl full", "Symbol table full" }; +EMSG_T no_macro_name = { "no macro name", "No name following DEFINE" }; +EMSG_T bad_dummy_arg = { "bad dummy arg", + "Bad dummy argument following DEFINE" }; +EMSG_T macro_too_long = { "macro too long", "Macro too long" }; +EMSG_T no_virtual_memory = { "out of memory", + "Insufficient memory for macro" }; +EMSG_T macro_table_full = { "Macro Table full", "Macro table full" }; +EMSG_T define_in_repeat = { "define in a repeat", "Define in a repeat" }; + +/*----------------------------------------------------------------------------*/ + +FILE *errorfile; +FILE *infile; +FILE *listfile; +FILE *listsave; +FILE *objectfile; +FILE *objectsave; + +char filename[NAMELEN]; +char listpathname[NAMELEN]; +char sympathname[NAMELEN]; +char objectpathname[NAMELEN]; +char *pathname; +char permpathname[NAMELEN]; + +WORD32 mac_count; /* Total macros defined. */ + +/* + * malloced macro bodies, indexed by sym->val dummies are evaluated at + * invocation time, and value saved in "args"; if recursive macros are + * desired (without conditionals, how would you escape?), keep a name + * list here and move symbols to "macinv" + */ +struct macdef { + int nargs; /* number of args */ + SYM_T args[MAC_MAX_ARGS+1]; /* symbol for each and one for "r" */ + char body[1]; /* malloc'ed accordingly */ +} *mac_defs[MAC_TABLE_LENGTH]; + +struct macinv { /* current macro invocation */ + char mac_line[LINELEN]; /* Saved macro invocation line. */ + WORD32 mac_cc; /* Saved cc after macro invocation. */ + char *mac_ptr; /* Pointer to macro body, NULL if no macro. */ + struct macdef *defn; /* pointer to definition for dummies */ + struct macinv *prev; /* previous invocation in stack */ +} *curmacro; /* macro stack */ + +int nrepeats; /* count of nested repeats */ + +int list_lineno; +int list_pageno; +char list_title[LINELEN]; +BOOL list_title_set; /* Set if TITLE pseudo-op used. */ +char line[LINELEN]; /* Input line. */ +int lineno; /* Current line number. */ +int page_lineno; /* print line number on current page. */ +WORD32 listed; /* Listed flag. */ +WORD32 listedsave; + +WORD32 cc; /* Column Counter (char position in line). */ +WORD32 clc; /* Location counter */ +BOOL end_of_input; /* End of all input files. */ +int errors; /* Number of errors found so far. */ +BOOL error_in_line; /* TRUE if error on current line. */ +int errors_pass_1; /* Number of errors on pass 1. */ +int filix_curr; /* Index in argv to current input file. */ +int filix_start; /* Start of input files in argv. */ +int lexstartprev; /* Where previous lexeme started. */ +int lextermprev; /* Where previous lexeme ended. */ +int lexstart; /* Index of current lexeme on line. */ +int lexterm; /* Index of character after current lexeme. */ +int overbar; /* next saw an overbar in last token */ + +int nconst; /* number of "constants" blocks */ +int lit_count[MAX_CONSTANTS]; /* # of lits in each block in pass 1 */ +WORD32 lit_loc[MAX_CONSTANTS]; /* Base of literal blocks */ + +int noinput; /* don't punch loader */ + +int nvars; /* number of variables */ +WORD32 vars_addr; /* address of "variables" */ +WORD32 vars_end; /* end of "variables" */ + +/* pass 2 only; */ +int nlit; /* number of literals in litter[] */ +WORD32 litter[MAX_LITERALS]; /* literals */ + +WORD32 maxcc; /* Current line length. */ +BOOL nomac_exp; /* No macro expansion */ +WORD32 pass; /* Number of current pass. */ +BOOL print_permanent_symbols; +WORD32 radix; /* Default number radix. */ +BOOL rim_mode; /* RIM mode output. */ +BOOL sym_dump; /* punch symbol tape */ +int save_argc; /* Saved argc. */ +char **save_argv; /* Saved *argv[]. */ +WORD32 start_addr; /* Saved start address. */ +BOOL symtab_print; /* Print symbol table flag */ +BOOL xref; + +SYM_T sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */ + +/* initial data from SIMH v3.0 pdp1_stddev.c (different encoding of UC/LC) */ +#define UC 0100 /* Upper case */ +#define LC 0200 +#define CHARBITS 077 +#define BC LC|UC /* both case bits */ +#define BAD 014 /* unused concise code */ + +unsigned char ascii_to_fiodec[128] = { + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BC|075, BC|036, BAD, BAD, BAD, BC|077, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BC|000, UC|005, UC|001, UC|004, BAD, BAD, UC|006, UC|002, + LC|057, LC|055, UC|073, UC|054, LC|033, LC|054, LC|073, LC|021, + LC|020, LC|001, LC|002, LC|003, LC|004, LC|005, LC|006, LC|007, + LC|010, LC|011, BAD, BAD, UC|007, UC|033, UC|010, UC|021, + LC|040, UC|061, UC|062, UC|063, UC|064, UC|065, UC|066, UC|067, + UC|070, UC|071, UC|041, UC|042, UC|043, UC|044, UC|045, UC|046, + UC|047, UC|050, UC|051, UC|022, UC|023, UC|024, UC|025, UC|026, + UC|027, UC|030, UC|031, UC|057, LC|056, UC|055, UC|011, UC|040, + UC|020, LC|061, LC|062, LC|063, LC|064, LC|065, LC|066, LC|067, + LC|070, LC|071, LC|041, LC|042, LC|043, LC|044, LC|045, LC|046, + LC|047, LC|050, LC|051, LC|022, LC|023, LC|024, LC|025, LC|026, + LC|027, LC|030, LC|031, BAD, UC|056, BAD, UC|003, BC|075 +}; + +/* for symbol punch tape conversion only!! */ +char fiodec_to_ascii[64] = { + 0, '1', '2', '3', '4', '5', '6', '7', + '8', '9', 0, 0, 0, 0, 0, 0, + '0', 0, 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', 0, 0, 0, 0, 0, 0, + 0, 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 0, 0, 0, 0, 0, 0, + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 0, 0, 0, 0, 0, 0 }; + +/* used at startup & for expunge */ +void +init_symtab(void) { + /* Place end marker in symbol table. */ + symtab[0] = sym_undefined; + symbol_top = 0; +} + +/* Function: main */ +/* Synopsis: Starting point. Controls order of assembly. */ +int +main( int argc, char *argv[] ) +{ + int ix; + int space; + + save_argc = argc; + save_argv = argv; + + /* Set the default values for global symbols. */ + print_permanent_symbols = FALSE; + nomac_exp = TRUE; + rim_mode = FALSE; /* default to loader tapes */ + sym_dump = FALSE; + noinput = FALSE; + + symtab_print = FALSE; + xref = FALSE; + pathname = NULL; + + /* init symbol table before processing arguments, so we can + * load symbol punch tapes on the fly + */ + + /* + * Setup the error file in case symbol table overflows while + * installing the permanent symbols. + */ + errorfile = stderr; + pass = 0; /* required for symbol table init */ + symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE ); + + if( symtab == NULL ) { + fprintf( stderr, "Could not allocate memory for symbol table.\n"); + exit( -1 ); + } + + init_symtab(); + + /* Enter the pseudo-ops into the symbol table */ + for( ix = 0; ix < DIM( pseudos ); ix++ ) + defineSymbol( pseudos[ix].name, pseudos[ix].val, pseudos[ix].type, 0 ); + + /* Enter the predefined symbols into the table. */ + /* Also make them part of the permanent symbol table. */ + for( ix = 0; ix < DIM( permanent_symbols ); ix++ ) + defineSymbol( permanent_symbols[ix].name, + permanent_symbols[ix].val, + permanent_symbols[ix].type, 0 ); + + /* Get the options and pathnames */ + getArgs( argc, argv ); + + /* Do pass one of the assembly */ + pass = 1; + onePass(); + errors_pass_1 = errors; + + /* Set up for pass two */ + objectfile = fopen( objectpathname, "wb" ); + objectsave = objectfile; + + listfile = fopen( listpathname, "w" ); + listsave = listfile; + + /* XXX punch title into tape! */ + punchLeader( 0 ); + if (!rim_mode) { + punchLoader(); + punchLeader(5); + } + + if (nlit > 0) + constants(); /* implied "constants"? */ + + /* Do pass two of the assembly */ + errors = 0; + save_error_count = 0; + + if( xref ) { + /* Get the amount of space that will be required for the concordance */ + for( space = 0, ix = 0; ix < symbol_top; ix++ ) { + symtab[ix].xref_index = space; /* Index into concordance table. */ + space += symtab[ix].xref_count + 1; + symtab[ix].xref_count = 0; /* Clear the count for pass 2. */ + } + /* Allocate & clear the necessary space. */ + xreftab = (WORD32 *) calloc( space, sizeof( WORD32 )); + } + pass = 2; + onePass(); + + objectfile = objectsave; + + /* Works great for trailer. */ + punchLeader( 1 ); + + /* undo effects of NOLIST for any following output to listing file. */ + listfile = listsave; + + /* Display value of error counter. */ + if( errors == 0 ) { + fprintf( listfile, "\n %s %s %s\n", s_no, s_errors, s_detected ); + } + else { + fprintf( errorfile, "\n %d %s %s\n", errors, s_detected, + ( errors == 1 ? s_error : s_errors )); + fprintf( listfile, "\n %d %s %s\n", errors, s_detected, + ( errors == 1 ? s_error : s_errors )); + } + + if( symtab_print ) + printSymbolTable(); + + if( print_permanent_symbols ) + printPermanentSymbolTable(); + + if( xref ) + printCrossReference(); + + fclose( objectfile ); + fclose( listfile ); + if( errors == 0 && errors_pass_1 == 0 ) { + /* after closing objectfile -- we reuse the FILE *!! */ + if (sym_dump) + dump_symbols(); + } + else + remove( objectpathname ); + + return( errors != 0 ); +} /* main() */ + +/* read a word from a binary punch file */ +WORD32 +getw(FILE *f) +{ + int i, c; + WORD32 w; + + w = 0; + for (i = 0; i < 3;) { + c = getc(f); + if (c == -1) + return -1; + if (c & 0200) { /* ignore if ch8 not punched */ + w <<= 6; + w |= c & 077; + i++; + } + } + return w; +} + +/* + * "permute zone bits" like MACRO does for proper sorting + * (see routine "per" in MACRO) -- it's what DDT expects + * + * it's it's own inverse! + */ + +WORD32 +permute(WORD32 name) +{ + WORD32 temp; + + temp = name & 0202020; /* get zone bits */ + temp = ((temp << 1) & 0777777) | ((temp >> 17) & 1); /* rotate left */ + name ^= temp; /* flip zone bits */ + name ^= 0400000; /* toggle sign */ + return name; +} + +/* add a symbol from a "symbol punch" tape */ +void +addsym(WORD32 sym, WORD32 val) +{ + char name[4]; + + sym = permute(sym); + name[0] = fiodec_to_ascii[(sym >>12) & 077]; + name[1] = fiodec_to_ascii[(sym >> 6) & 077]; + name[2] = fiodec_to_ascii[sym & 077]; + name[3] = '\0'; + defineSymbol( name, val, LABEL, 0); +} + +void +read_symbols(char *fname) +{ + FILE *f; + + f = fopen(fname, "rb"); + if (!f) { + perror(fname); + exit(1); + } + + /* skip loader */ + for (;;) { + WORD32 w; + + w = getw(f); + if (w == -1) + goto err; /* XXX complain? */ + if ((w & OP_CODE) == JMP) + break; + if ((w & OP_CODE) != DIO) + goto err; /* XXX complain? */ + w = getw(f); + if (w == -1) + goto err; /* XXX complain? */ + } + + + /* XXX should push block reader down into a co-routine */ + for (;;) { + WORD32 start, end, sum; + + start = getw(f); + if ((start & OP_CODE) == JMP) { + fclose(f); + return; + } + + if (start == -1 || (start & OP_CODE) != DIO) + goto err; + + end = getw(f); + if (end == -1 || (end & OP_CODE) != DIO) + goto err; /* XXX complain? */ + + sum = start + end; + while (start < end) { + WORD32 sym, val; + sym = getw(f); + if (sym == -1) + goto err; + sum += sym; + start++; + /* XXX handle block boundaries? */ + if (start >= end) + goto err; + val = getw(f); + if (val == -1) + goto err; + /*printf("%06o %06o\n", sym, val);*/ + addsym(sym, val); + sum += val; + start++; + } + start = getw(f); /* eat checksum XXX verify? */ + if (start == -1) + goto err; + /* roll over all the overflows at once */ + if (sum & ~0777777) { + sum = (sum & 0777777) + (sum >> 18); + if (sum & 01000000) /* one more time */ + sum++; + } + if (start != sum) + goto err; + } +err: + fprintf(stderr, "error reading symbol file %s\n", fname); + exit(1); +} + +/* Function: getArgs */ +/* Synopsis: Parse command line, set flags accordingly and setup input and */ +/* output files. */ +void getArgs( int argc, char *argv[] ) +{ + WORD32 len; + WORD32 ix, jx; + + /* Set the defaults */ + infile = NULL; + listfile = NULL; + listsave = NULL; + objectfile = NULL; + objectsave = NULL; + + for( ix = 1; ix < argc; ) + { + if( argv[ix][0] == '-' ) + { + char *switches = argv[ix++]; + for( jx = 1; switches[jx] != 0; jx++ ) + { + switch( switches[jx] ) + { + case 'd': + symtab_print = TRUE; + break; + + case 'r': + rim_mode = TRUE; /* punch pure rim-mode tapes */ + break; + + case 's': + sym_dump = TRUE; + break; + + case 'm': + nomac_exp = FALSE; + break; + + case 'p': + print_permanent_symbols = TRUE; + break; + + case 'x': + xref = TRUE; + break; + + case 'S': + if (ix <= argc) + read_symbols(argv[ix++]); + break; + + default: + fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] ); + fprintf( stderr, " -d -- dump symbol table\n" ); + fprintf( stderr, " -m -- output macro expansions\n" ); + fprintf( stderr, " -p -- output permanent symbols to file\n" ); + fprintf( stderr, " -r -- output RIM format file\n" ); + fprintf( stderr, " -s -- output symbol punch tape to file\n" ); + fprintf( stderr, " -S file -- read symbol punch tape\n" ); + fprintf( stderr, " -x -- output cross reference to file\n" ); + fflush( stderr ); + exit( -1 ); + } /* end switch */ + } /* end for */ + } + else + { + filix_start = ix; + pathname = argv[ix]; + break; + } + } /* end for */ + + if( pathname == NULL ) + { + fprintf( stderr, "%s: no input file specified\n", argv[0] ); + exit( -1 ); + } + + len = strlen( pathname ); + if( len > NAMELEN - 5 ) + { + fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname ); + exit( -1 ); + } + + /* Now make the pathnames */ + /* Find last '.', if it exists. */ + jx = len - 1; + while( pathname[jx] != '.' && pathname[jx] != '/' + && pathname[jx] != '\\' && jx >= 0 ) + { + jx--; + } + + switch( pathname[jx] ) + { + case '.': + break; + + case '/': + case '\\': + jx = len; + break; + + default: + break; + } + + /* Add the pathname extensions. */ + strncpy( objectpathname, pathname, jx ); + objectpathname[jx] = '\0'; + strcat( objectpathname, ".rim"); + + strncpy( listpathname, pathname, jx ); + listpathname[jx] = '\0'; + strcat( listpathname, ".lst" ); + + strncpy( permpathname, pathname, jx ); + permpathname[jx] = '\0'; + strcat( permpathname, ".prm" ); + + strncpy( sympathname, pathname, jx ); + sympathname[jx] = '\0'; + strcat( sympathname, ".sym" ); + + /* Extract the filename from the path. */ + if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' ) + pathname[1] = '\\'; /* MS-DOS style pathname */ + + jx = len - 1; + while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 ) + jx--; + strcpy( filename, &pathname[jx + 1] ); +} /* getArgs() */ + + +int +invokeMacro(int index) +{ + struct macinv *mip; + struct macdef *mdp; + int jx; + + mdp = mac_defs[index]; + if (mdp == NULL || mdp->body[0] == '\0') + return 0; + + /* Find arguments. */ + while (ISBLANK(line[lexstart])) + next(0); + + mip = calloc(1, sizeof(struct macinv)); + if (!mip) { + fprintf(stderr, "could not allocate memory for macro invocation\n"); + exit(1); + } + mip->defn = mdp; + + /* evaluate args, saving values in SYM_T entries in defn. + * (cannot have recursive macros) + */ + mdp->args[0].val = clc; /* r is location at start */ + for( jx = 1; !ISDONE(line[lexstart]) && jx <= MAC_MAX_ARGS; ) { + WORD32 val; + + next(0); + if (ISDONE(line[lexstart])) + break; + + if (line[lexstart] == ',') + next(0); + + while( ISBLANK( line[lexstart] )) + next(0); + + if (ISDONE(line[lexstart])) + break; + + val = getExprs(); + + /* ignore excess values silently? */ + if (jx <= mdp->nargs) + mdp->args[jx].val = val; + jx++; + } /* end for */ + + /* XXX complain if too few actuals? -- nah */ + while (jx <= mdp->nargs) + mdp->args[jx++].val = 0; + + strcpy(mip->mac_line, line); /* save line */ + mip->mac_cc = cc; /* save position in line */ + mip->mac_ptr = mdp->body; + mip->prev = curmacro; /* push the old entry */ + curmacro = mip; /* step up to the plate! */ + return 1; +} + +/* process input; used by onePass and repeat */ +void +processLine() { + if (!list_title_set) { + char *cp; + + /* assert(sizeof(title) >= sizeof(line)); */ + strcpy(list_title, line); + + if ((cp = strchr(list_title, '\n'))) + *cp = '\0'; + + if (list_title[0]) { + list_title_set = TRUE; + fprintf(stderr, "%s - pass %d\n", list_title, pass ); + /* XXX punch title into tape banner (until an '@' seen) */ + } + return; + } + + for (;;) { + int jx; + SYM_T evalue; + + next(0); + if( end_of_input ) + return; + + if( ISEND( line[lexstart] )) { + if (line[lexstart] != '\t') + return; + continue; + } + if (line[lexstart] == '/') /* comment? */ + return; /* done */ + + /* look ahead for 'exp/' */ + /* skip until whitespace or terminator */ + for( jx = lexstart; jx < maxcc; jx++ ) + if( ISBLANK(line[jx]) || ISDONE(line[jx])) + break; + if( line[jx] == '/') { /* EXP/ set location */ + WORD32 newclc; + + newclc = getExprs(); + + /* Do not change Current Location Counter if an error occurred. */ + if( !error_in_line ) + clc = newclc; + + printLine( line, newclc, 0, LINE_LOC ); + cc = jx + 1; + next(0); /* discard slash */ + continue; + } + + switch( line[lexterm] ) { + case ',': + if( isLexSymbol()) { + WORD32 val; + SYM_T *sym; + char name[SYMLEN]; + + /* Use lookup so symbol will not be counted as reference. */ + sym = lookup(lexemeToName(name, lexstart, lexterm), UNDEFINED); + + if (curmacro) { + /* relative during macro expansion!! */ + val = clc - curmacro->defn->args[0].val; + } + else + val = clc; + + if( M_DEFINED( sym->type )) { + if( sym->val != val && pass == 2 ) + errorSymbol( &duplicate_label, sym->name, lexstart ); + sym->type |= DUPLICATE; /* XXX never used! */ + } + /* Must call define on pass 2 to generate concordance. */ + defineLexeme( lexstart, lexterm, val, LABEL ); + } + else if (isdigit(line[lexstart])) { /* constant, */ + int i; + WORD32 val = 0; + + for( i = lexstart; i < lexterm; i++ ) { + if( isdigit( line[i] )) { + int digit; + digit = line[i] - '0'; + if( digit >= radix ) { + errorLexeme( &number_not_radix, i ); + val = 0; + break; + } + val = val * radix + digit; + } + else { + errorLexeme( ¬_a_number, lexstart ); + val = 0; + break; + } + } + if (i == lexterm) { + if( clc != val && pass == 2 ) + errorLexeme( &duplicate_label, lexstart); /* XXX */ + } + } + else + errorLexeme( &label_syntax, lexstart ); + next(0); /* skip comma */ + continue; + + case '=': + if( isLexSymbol()) { + WORD32 start, term, val; + + start = lexstart; + term = lexterm; + next(0); /* skip symbol */ + next(0); /* skip trailing = */ + val = getExprs(); + defineLexeme( start, term, val, DEFINED ); + printLine( line, 0, val, LINE_VAL ); + } + else { + errorLexeme( &symbol_syntax, lexstartprev ); + next(0); /* skip symbol */ + next(0); /* skip trailing = */ + getExprs(); /* skip expression */ + } + continue; + } /* switch on terminator */ + + if( isLexSymbol()) { + SYM_T *sym; + WORD32 val; + + sym = evalSymbol(); + val = sym->val; + if( M_MACRO(sym->type)) { + if (!invokeMacro(val)) + next(0); /* bad defn? or body is empty! */ + continue; + } /* macro invocation */ + else if( M_PSEUDO(sym->type)) { /* NO EPSEUDOs */ + pseudo( (PSEUDO_T)val & 0777777 ); + continue; + } /* pseudo */ + } /* macro, or non-char pseudo */ + + evalue = getExpr(); + if (evalue.type != PSEUDO) { /* not a bare pseudo-op? */ + if (line[lexstart] == ',') { /* EXP, */ + if(evalue.val != clc && pass == 2 ) + errorLexeme( &duplicate_label, lexstart); /* XXX */ + } + else if (line[lexstart] == '/') { /* EXP/ */ + clc = evalue.val; + printLine( line, clc, 0, LINE_LOC ); + next(0); + } + else { + punchOutObject( clc, evalue.val & 0777777); /* punch it! */ + incrementClc(); + } + } + } /* forever */ +} + +/* Function: onePass */ +/* Synopsis: Do one assembly pass. */ +void onePass() { + int ix; + + clc = 4; /* Default location is 4 */ + start_addr = 0; /* No starting address. */ + nconst = 0; /* No constant blocks seen */ + nvars = 0; /* No variables seen */ + + while (curmacro) { /* pop macro stack */ + struct macinv *mp; + + mp = curmacro->prev; + free(curmacro); + curmacro = mp; + } + + for( ix = 0; ix < mac_count; ix++) { + if (mac_defs[ix]) + free( mac_defs[ix] ); + mac_defs[ix] = NULL; + } + mac_count = 0; /* No macros defined. */ + + listed = TRUE; + lineno = 0; + list_pageno = 0; + list_lineno = 0; + list_title_set = FALSE; + page_lineno = LIST_LINES_PER_PAGE; /* Force top of page for new titles. */ + radix = 8; /* Initial radix is octal (base 8). */ + + /* Now open the first input file. */ + end_of_input = FALSE; + filix_curr = filix_start; /* Initialize pointer to input files. */ + if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) { + fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0], + save_argv[filix_curr] ); + exit( -1 ); + } + + for (;;) { + readLine(); + if (end_of_input) { + eob(); + fclose( infile ); + return; + } + processLine(); + } /* forever */ +} /* onePass */ + + +/* Function: getExprs */ +/* Synopsys: gutted like a fish */ +WORD32 getExprs() +{ + SYM_T sym; + + sym = getExpr(); + if (sym.type == PSEUDO) + errorMessage( &value_required, lexstart ); /* XXX wrong pointer? */ + + return sym.val & 0777777; +} /* getExprs */ + + +SYM_T getExpr() +{ + SYM_T sym; + + sym = eval(); + + /* Here we assume the current lexeme is the operator separating the */ + /* previous operator from the next, if any. */ + + for (;;) { + int space; + /* + * falling out of switch breaks loop and returns from routine + * so if you want to keep going, you must "continue"!! + */ + space = FALSE; + switch( line[lexstart] ) { + case ' ': + space = TRUE; + /* fall */ + case '+': /* add */ + next(1); /* skip operator */ + if (space && ISEND(line[lexstart])) /* tollerate a trailing space */ + return sym; + sym.val += eval().val; /* XXX look at type? */ + sym.type = DEFINED; + if( sym.val >= 01000000 ) + sym.val = ( sym.val + 1 ) & 0777777; + continue; + + case '-': /* subtract */ + next(1); /* skip over the operator */ + sym.val += eval().val ^ 0777777; /* XXX look at type? */ + sym.type = DEFINED; + if( sym.val >= 01000000 ) + sym.val = ( sym.val + 1 ) & 0777777; + continue; + + case '*': /* multiply */ + next(1); /* skip over the operator */ + sym.val *= eval().val; + sym.type = DEFINED; + if( sym.val >= 01000000 ) + sym.val = ( sym.val + 1 ) & 0777777; + continue; + +#if 0 + case '%': /* divide !??? */ + /* + * neither '%' nor the divide symbol appear in FIO-DEC, + * does any known program use such an operator? + * Easily confused for "MOD", which is how C uses '%'! + */ + next(1); + sym.val /= eval().val; + sym.type = DEFINED; + continue; +#endif + + case '&': /* and */ + next(1); /* skip over the operator */ + sym.val &= eval().val; + sym.type = DEFINED; + continue; + + case '!': /* or */ + next(1); /* skip over the operator */ + sym.val |= eval().val; + sym.type = DEFINED; + continue; + + case '/': + case ')': + case ']': + case ':': + case ',': + break; + + case '=': + errorMessage( &illegal_equals, lexstart ); + moveToEndOfLine(); + sym.val = 0; + break; + + default: + if (!ISEND(line[lexstart])) { + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + sym.val = 0; + break; + } + } /* switch */ + break; /* break loop!! */ + } /* "forever" */ + return( sym ); +} /* getExpr */ + +/* + * return fio-dec code for next char + * embeds shifts as needed + */ +int +nextfiodec(int *ccase, int delim) +{ + unsigned char c; + + for (;;) { + if (cc >= maxcc) { + if (delim == -1) + return -1; + + /* XXX MUST NOT BE IN A REPEAT!! */ + readLine(); /* danger will robinson! */ + if (end_of_input) + return -1; + } + c = line[cc]; + switch (c) { + case '\n': + c = '\r'; + break; + case '\r': + continue; + } + break; + } + + if (delim != -1 && c == delim) { + if (*ccase == LC) { + cc++; /* eat delim */ + return -1; + } + *ccase = LC; + return CONCISE_LC; /* shift down first */ + } + + if (c > 0177) { /* non-ascii */ + errorMessage( &illegal_character, cc ); + c = 0; /* space?! */ + } + + c = ascii_to_fiodec[c&0177]; + if (c == BAD) { + errorMessage( &illegal_character, cc ); + c = 0; /* space?! */ + } + + if (!(c & *ccase)) { /* char not in current case? */ + *ccase ^= BC; /* switch case */ + if (*ccase == LC) + return CONCISE_LC; /* shift down */ + else + return CONCISE_UC; /* shift up */ + } + cc++; + return c & CHARBITS; +} + +/* + * Function: flex + * Synopsis: Handle data for "flexo" pseudo + * handle upper case by doing shifts + */ + +WORD32 flex() +{ + WORD32 w; + int shift; + int ccase; + + if (line[lexstart] == ' ') /* always? */ + next(0); + + /* original version appears to take next 3 characters, + * REGARDLESS of what they are (tab, newline, space?)! + */ + w = 0; + ccase = LC; /* current case */ + for (shift = 12; shift >= 0; shift -= 6) { + unsigned char c; + if( lexstart >= maxcc ) + break; + + c = line[lexstart]; + if (c == '\t' || c == '\n') { + if (ccase == LC) + break; + c = CONCISE_LC; /* shift down first */ + } + else { + if (c > 0177) { /* non-ascii */ + errorMessage( &illegal_character, lexstart ); + c = 0; + } + + c = ascii_to_fiodec[c&0177]; + if (c == BAD) { + errorMessage( &illegal_character, lexstart ); + c = 0; + } + + if (!(c & ccase)) { /* char not in current case? */ + ccase ^= BC; /* switch case */ + if (ccase == LC) + c = CONCISE_LC; /* shift down */ + else + c = CONCISE_UC; /* shift up */ + } + else + lexstart++; + } + w |= (c & CHARBITS) << shift; + } + /* error to get here w/ case == UC? nah. shift down could be next */ + return w; +} /* flex */ + +/* + * Function: getChar + * Synopsis: Handle data for "char" pseudo + */ + +WORD32 getChar() +{ + unsigned char c, pos; + + if( cc >= maxcc ) + return 0; /* XXX error? */ + pos = line[cc++]; + if (pos != 'l' && pos != 'm' && pos != 'r') { + errorMessage( &illegal_character, lexstart ); + return 0; + } + + if( cc >= maxcc ) + return 0; /* XXX error? */ + + c = line[cc++]; + if (c > 0177) { + errorMessage( &illegal_character, lexstart ); + c = 0; + } + + c = ascii_to_fiodec[c]; + if (c == BAD) { + errorMessage( &illegal_character, lexstart ); + c = 0; + } + + if (!(c & LC)) { /* upper case only char? */ + c = CONCISE_UC; /* take a shift up */ + cc--; /* and leave char for next luser */ + } + + c &= CHARBITS; + switch (pos) { + case 'l': return c << 12; + case 'm': return c << 6; + case 'r': return c; + } + /* should not happen */ + return 0; +} /* flex */ + +/* Function: eval */ +/* Synopsis: Get the value of the current lexeme, and advance.*/ +SYM_T eval2() +{ + WORD32 digit; + WORD32 from; + SYM_T *sym; + WORD32 val; + SYM_T sym_eval; + + sym_eval.type = DEFINED; + sym_eval.name[0] = '\0'; + sym_eval.val = sym_eval.xref_index = sym_eval.xref_count = 0; + + val = 0; + + if( isLexSymbol()) { + sym = evalSymbol(); + if(!M_DEFINED( sym->type )) { + if( pass == 2 ) + errorSymbol( &undefined_symbol, sym->name, lexstart ); + next(1); + return( *sym ); + } + else if( M_PSEUDO(sym->type) || M_EPSEUDO(sym->type)) { + switch (sym->val) { + case DECIMAL: + radix = 10; + sym_eval.type = PSEUDO; + sym_eval.val = 0; /* has zero as a value! */ + break; + case OCTAL: + radix = 8; + sym_eval.type = PSEUDO; + sym_eval.val = 0; /* has zero as a value */ + break; + case FLEX: + next(1); /* skip keyword */ + sym_eval.val = flex(); + break; + case CHAR: + next(1); /* skip keyword */ + sym_eval.val = getChar(); + break; + default: + errorSymbol( &value_required, sym->name, lexstart ); + sym_eval.type = sym->type; + sym_eval.val = 0; + break; + } + next(1); + return( sym_eval ); + } + else if( M_MACRO( sym->type )) + { + if( pass == 2 ) + { + errorSymbol( &misplaced_symbol, sym->name, lexstart ); + } + sym_eval.type = sym->type; + sym_eval.val = 0; + next(1); + return( sym_eval ); + } + else + { + next(1); + return( *sym ); + } + } /* symbol */ + else if( isdigit( line[lexstart] )) { + from = lexstart; + val = 0; + while( from < lexterm ) { + if( isdigit( line[from] )) { + digit = line[from++] - '0'; + if( digit >= radix ) { + errorLexeme( &number_not_radix, from - 1 ); + val = 0; + break; + } + val = val * radix + digit; + } + else { + errorLexeme( ¬_a_number, lexstart ); + val = 0; + break; + } + } + next(1); + sym_eval.val = val; + return( sym_eval ); + } /* digit */ + else { + switch( line[lexstart] ) { + case '.': /* Value of Current Location Counter */ + val = clc; + next(1); + break; + case '(': /* Generate literal */ + next(1); /* Skip paren */ + val = getExprs(); /* recurse */ + if( line[lexstart] == ')' ) + next(1); /* Skip end paren */ + sym_eval.val = literal(val); + return sym_eval; + case '[': /* parens!! */ + next(1); + sym_eval.val = getExprs(); /* mutual recursion */ + if( line[lexstart] == ']' ) + next(1); /* Skip close bracket */ + else + errorMessage( &illegal_character, lexstart ); + return sym_eval; + default: + switch( line[lexstart] ) { + case '=': + errorMessage( &illegal_equals, lexstart ); + moveToEndOfLine(); + break; + default: + errorMessage( &illegal_character, lexstart ); + break; + } /* error switch */ + val = 0; /* On error, set value to zero. */ + next(1); /* Go past illegal character. */ + } /* switch on first char */ + } /* not symbol or number */ + sym_eval.val = val; + return( sym_eval ); +} /* eval2 */ + + +SYM_T eval() { + SYM_T sym; + + switch (line[lexstart]) { + case '-': /* unary - */ + next(1); + sym = eval2(); /* skip op */ + sym.val ^= 0777777; + break; + case '+': /* unary + */ + next(1); /* skip op */ + /* fall */ + default: + sym = eval2(); + } + return sym; +} + +/* Function: incrementClc */ +/* Synopsis: Set the next assembly location. Test for collision with */ +/* the literal tables. */ +WORD32 incrementClc() +{ + clc = (( clc + 1 ) & ADDRESS_FIELD ); + return( clc ); +} /* incrementClc */ + + +/* Function: readLine */ +/* Synopsis: Get next line of input. Print previous line if needed. */ +void readLine() +{ + BOOL ffseen; + WORD32 ix; + WORD32 iy; + char inpline[LINELEN]; + + /* XXX panic if nrepeats > 0 (if self-feeding, do the backup here?) */ + + listLine(); /* List previous line if needed. */ + error_in_line = FALSE; /* No error in line. */ + + if(curmacro && *curmacro->mac_ptr == '\0') { /* end of macro? */ + struct macinv *mp; + + listed = TRUE; /* Already listed. */ + + /* Restore invoking line. */ + strcpy(line, curmacro->mac_line); + cc = lexstartprev = curmacro->mac_cc; /* Restore cc. */ + maxcc = strlen( line ); /* Restore maxcc. */ + + mp = curmacro->prev; /* pop stack */ + free(curmacro); + curmacro = mp; + + return; + } /* end of macro */ + + cc = 0; /* Initialize column counter. */ + lexstartprev = 0; + if( curmacro ) { /* Inside macro? */ + char mc; + + maxcc = 0; + do { + + mc = *curmacro->mac_ptr++; /* Next character. */ + /* watch for overflow? how could it?? */ + line[maxcc++] = mc; + } while( !ISEND( mc )); /* note: terminates on tab?! */ + line[maxcc] = '\0'; + listed = nomac_exp; + return; + } /* inside macro */ + + lineno++; /* Count lines read. */ + listed = FALSE; /* Mark as not listed. */ + READ_LINE: + if(( fgets( inpline, LINELEN - 1, infile )) == NULL ) { + filix_curr++; /* Advance to next file. */ + if( filix_curr < save_argc ) { /* More files? */ + fclose( infile ); + if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) { + fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0], + save_argv[filix_curr] ); + exit( -1 ); + } + list_title_set = FALSE; + goto READ_LINE; + } + else + end_of_input = TRUE; + } /* fgets failed */ + + ffseen = FALSE; + for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ ) { + if( inpline[ix] == '\f' ) { + if( !ffseen && list_title_set ) topOfForm( list_title, NULL ); + ffseen = TRUE; + } + else + line[iy++] = inpline[ix]; + } + line[iy] = '\0'; + + /* If the line is terminated by CR-LF, remove, the CR. */ + if( line[iy - 2] == '\r' ) { + iy--; + line[iy - 1] = line[iy - 0]; + line[iy] = '\0'; + } + maxcc = iy; /* Save the current line length. */ +} /* readLine */ + + +/* Function: listLine */ +/* Synopsis: Output a line to the listing file. */ +void listLine() +/* generate a line of listing if not already done! */ +{ + if( listfile != NULL && listed == FALSE ) + { + printLine( line, 0, 0, LINE ); + } +} /* listLine */ + + +/* Function: printPageBreak */ +/* Synopsis: Output a Top of Form and listing header if new page necessary. */ +void printPageBreak() +{ + if( page_lineno >= LIST_LINES_PER_PAGE ) + /* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */ + { + topOfForm( list_title, NULL ); + } +} /* printPageBreak */ + + +/* Function: printLine */ +/* Synopsis: Output a line to the listing file with new page if necessary. */ +void printLine( char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle ) +{ + if( listfile == NULL ) + { + save_error_count = 0; + return; + } + + printPageBreak(); + + list_lineno++; + page_lineno++; + switch( linestyle ) + { + default: + case LINE: + fprintf( listfile, "%5d ", lineno ); + fputs( line, listfile ); + listed = TRUE; + break; + + case LINE_VAL: + if( !listed ) + { + fprintf( listfile, "%5d %6.6o ", lineno, val ); + fputs( line, listfile ); + listed = TRUE; + } + else + { + fprintf( listfile, " %6.6o\n", val ); + } + break; + + case LINE_LOC: + if( !listed ) + { + fprintf( listfile, "%5d %5.5o ", lineno, loc ); + fputs( line, listfile ); + listed = TRUE; + } + else + { + fprintf( listfile, " %5.5o\n", loc ); + } + break; + + case LINE_LOC_VAL: + if( !listed ) + { + fprintf( listfile, "%5d %5.5o %6.6o ", lineno, loc, val ); + fputs( line, listfile ); + listed = TRUE; + } + else + { + fprintf( listfile, " %5.5o %6.6o\n", loc, val ); + } + break; + + case LOC_VAL: + fprintf( listfile, " %5.5o %6.6o\n", loc, val ); + break; + } + printErrorMessages(); +} /* printLine */ + + +/* Function: printErrorMessages */ +/* Synopsis: Output any error messages from the current list of errors. */ +void printErrorMessages() +{ + WORD32 ix; + WORD32 iy; + + if( listfile != NULL ) + { + /* If any errors, display them now. */ + for( iy = 0; iy < save_error_count; iy++ ) + { + printPageBreak(); + fprintf( listfile, "%-18.18s ", error_list[iy].mesg ); + if( error_list[iy].col >= 0 ) + { + for( ix = 0; ix < error_list[iy].col; ix++ ) + { + if( line[ix] == '\t' ) + { + putc( '\t', listfile ); + } + else + { + putc( ' ', listfile ); + } + } + fputs( "^", listfile ); + list_lineno++; + page_lineno++; + } + fputs( "\n", listfile ); + } + } + save_error_count = 0; +} /* printErrorMessages */ + + +/* Function: punchObject */ +/* Synopsis: Put one character to object file */ +void punchObject( WORD32 val ) +{ + val &= 0377; + if( objectfile != NULL ) + fputc( val, objectfile ); +} /* punchObject */ + +/* Function: punchTriplet */ +/* Synopsis: Output 18b word as three 6b characters with ho bit set. */ +void punchTriplet( WORD32 val ) +{ + punchObject((( val >> 12) & 077) | 0200 ); + punchObject((( val >> 6 ) & 077) | 0200 ); + punchObject(( val & 077) | 0200 ); +} /* punchTriplet */ + +void +eob() { + /* in case no "start" in file (an error?) */ +} + +/* Function: punchLeader */ +/* Synopsis: Generate 2 feet of leader on object file, as per DEC */ +/* documentation. Paper tape has 10 punches per inch. */ +void punchLeader( WORD32 count ) +{ + WORD32 ix; + + /* If value is zero, set to the default of 2 feet of leader. */ + count = ( count == 0 ) ? 240 : count; + + if( objectfile != NULL ) + { + for( ix = 0; ix < count; ix++ ) + { + fputc( 0, objectfile ); + } + } +} /* punchLeader */ + +/* Function: punchOutObject */ +/* Synopsis: Output the current line and then then punch value to the */ +/* object file. */ +void punchOutObject( WORD32 loc, WORD32 val ) +{ + printLine( line, loc, val, LINE_LOC_VAL ); + punchLocObject( loc, val ); +} /* punchOutObject */ + + +/* Function: punchLocObjectRIM */ +/* Synopsis: Output the word in RIM mode */ +void punchLocObjectRIM( WORD32 loc, WORD32 val ) +{ + punchTriplet( DIO | loc ); + punchTriplet( val ); +} /* punchLocObject */ + +/* punch loader in RIM mode */ +void +punchLoader() { + int i; + + if (noinput) + return; + + for (i = 0; i < DIM(loader); i++) + punchLocObjectRIM(LOADERBASE+i, loader[i]); + punchTriplet( JMP | LOADERBASE ); +} + +/* + * flush out loader buffer; output a block: + * DIO start + * DIO end+1 + * .... data .... + * sum + */ +#define PW(X) { WORD32 x = X; sum += x; punchTriplet(x); } +void +flushLoader() { + WORD32 sum; + int i; + + if (loaderbufcount == 0) + return; + + sum = 0; + PW( DIO | loaderbufstart ); + PW( DIO | loaderbufstart + loaderbufcount ); + for (i = 0; i < loaderbufcount; i++) + PW( loaderbuf[i] ); + + /* roll over all the overflows at once */ + if (sum & ~0777777) + sum = (sum & 0777777) + (sum >> 18); + if (sum & 01000000) /* one more time */ + sum++; + PW( sum ); + + punchLeader(5); + loaderbufcount = 0; +} + +void punchLocObject( WORD32 loc, WORD32 val ) +{ + if (!rim_mode) { + if ((loc & LOADERBUFMASK) == 0 || /* full/force alignment */ + loaderbufcount > 0 && + loc != loaderbufstart + loaderbufcount) /* disjoint */ + flushLoader(); + if (loaderbufcount == 0) + loaderbufstart = loc; + loaderbuf[loaderbufcount++] = val; + } + else + punchLocObjectRIM( loc, val ); +} + +/* Function: literal */ +/* Synopsis: Add a value to the literal pool */ +WORD32 +literal( WORD32 value ) +{ + int i; + + if (nconst >= MAX_CONSTANTS) { + fprintf(stderr, "too many 'constants'; increase MAX_CONSTANTS\n"); + exit(1); + } + + if (pass == 1) { + if (++lit_count[nconst] == MAX_LITERALS) { + fprintf(stderr, "too many literals; increase MAX_LITERALS\n"); + exit(1); + } + return lit_count[nconst]; + } + +#if 1 + /* + * pool constants; makes for a shorter tape + * (but "middle" constants blocks can't shrink) + */ + for (i = 0; i < nlit; i++) + if (litter[i] == value) + return lit_loc[nconst] + i; +#endif + + /* paranoia */ + if (nlit == MAX_LITERALS) { + fprintf(stderr, "too many literals; increase MAX_LITERALS\n"); + exit(1); + } + + /* not found, save it */ + litter[nlit] = value; + + /* use base for this block, determined on pass1 */ + return lit_loc[nconst] + nlit++; +} /* literal */ + + +/* Function: printSymbolTable */ +/* Synopsis: Output the symbol table. */ +/* XXX now prints FIXED symbols too */ +void printSymbolTable() +{ + int ix; + int symbol_lines; + SYM_T *sym; + char mark; + + symbol_lines = 0; + for (ix = 0, sym = symtab; ix < symbol_top; ix++, sym++) { + if (M_FIXED(sym->type) || M_PSEUDO(sym->type) || + M_MACRO(sym->type) || M_EPSEUDO(sym->type)) + continue; + + if (symbol_lines == 0) { + topOfForm( list_title, s_symtable ); + symbol_lines = LIST_LINES_PER_PAGE; + } + + switch( sym->type & ( DEFINED | REDEFINED )) { + case UNDEFINED: + mark = '?'; + break; + + case REDEFINED: + mark = '#'; + break; + + default: + mark = ' '; + break; + } + fprintf( listfile, "%c%-6.6s %6.6o\n", mark, sym->name, sym->val ); + symbol_lines--; + } +} /* printSymbolTable */ + + +/* Function: printPermanentSymbolTable */ +/* Synopsis: Output the permanent symbol table to a file suitable for */ +/* being input after the EXPUNGE pseudo-op. */ +void printPermanentSymbolTable() +{ + int ix; + FILE *permfile; + + if(( permfile = fopen( permpathname, "w" )) == NULL ) + { + exit( 2 ); + } + + fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" ); + fprintf( permfile, " expunge\n/\n" ); + + for( ix = 0; ix < symbol_top; ix++ ) + { + int type = symtab[ix].type; + if( M_FIXED(type) && !M_PSEUDO(type) && !M_EPSEUDO(type) ) + fprintf( permfile, "\t%s=%o\n", + symtab[ix].name, symtab[ix].val ); + } + fclose( permfile ); +} /* printPermanentSymbolTable */ + + +/* Function: printCrossReference */ +/* Synopsis: Output a cross reference (concordance) for the file being */ +/* assembled. */ +void printCrossReference() +{ + int ix; + int xc; + int xc_index; + int xc_refcount; + int xc_cols; + SYM_T *sym; + + /* Force top of form for first page. */ + page_lineno = LIST_LINES_PER_PAGE; + + list_lineno = 0; + + for( ix = 0, sym = symtab; ix < symbol_top; ix++, sym++ ) { + if (M_FIXED(sym->type) && xreftab[sym->xref_index] == 0) + continue; + list_lineno++; + page_lineno++; + if( page_lineno >= LIST_LINES_PER_PAGE ) + topOfForm( list_title, s_xref ); + + fprintf( listfile, "%5d", list_lineno ); + + /* Get reference count & index into concordance table for this symbol */ + xc_refcount = sym->xref_count; + xc_index = sym->xref_index; + /* Determine how to label symbol on concordance. */ + /* XXX flag variables? */ + switch( sym->type & ( DEFINED | REDEFINED )) { + case UNDEFINED: + fprintf( listfile, " U "); + break; + + case REDEFINED: + fprintf( listfile, " M %5d ", xreftab[xc_index] ); + break; + + default: + fprintf( listfile, " A %5d ", xreftab[xc_index] ); + break; + } + fprintf( listfile, "%-6.6s ", sym->name ); + + /* Output the references, 8 numbers per line after symbol name. */ + for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ ) { + if( xc_cols >= XREF_COLUMNS ) { + xc_cols = 0; + page_lineno++; + if( page_lineno >= LIST_LINES_PER_PAGE ) + topOfForm( list_title, s_xref); + list_lineno++; + fprintf( listfile, "\n%5d%-19s", list_lineno, " " ); + } + fprintf( listfile, " %5d", xreftab[xc_index + xc] ); + } + fprintf( listfile, "\n" ); + } /* for */ +} /* printCrossReference */ + + +/* Function: topOfForm */ +/* Synopsis: Prints title and sub-title on top of next page of listing. */ +void topOfForm( char *title, char *sub_title ) +{ + char temp[10]; + + list_pageno++; + strcpy( temp, s_page ); + sprintf( temp, "%s %d", s_page, list_pageno ); + + if (!listfile) + return; + + /* Output a top of form if not the first page of the listing. */ + if( list_pageno > 1 ) + fprintf( listfile, "\f" ); + + fprintf( listfile, "\n %-63s %10s\n", title, temp ); + + /* Reset the current page line counter. */ + page_lineno = 1; + if( sub_title != NULL ) + { + fprintf( listfile, "%80s\n", sub_title ); + page_lineno++; + } + else + { + fprintf( listfile, "\n" ); + page_lineno++; + } + fprintf( listfile, "\n" ); + page_lineno++; +} /* topOfForm */ + + +/* Function: lexemeToName */ +/* Synopsis: Convert the current lexeme into a string. */ +char *lexemeToName( char *name, WORD32 from, WORD32 term ) +{ + int to; + + to = 0; + while( from < term && to < SYMLEN-1) { + char c = line[from++]; + if (ISOVERBAR(c)) + continue; + name[to++] = c; + } + name[to] = '\0'; + + return( name ); +} /* lexemeToName */ + +/* Function: defineLexeme */ +/* Synopsis: Put lexeme into symbol table with a value. */ +SYM_T *defineLexeme( WORD32 start, /* start of lexeme being defined. */ + WORD32 term, /* end+1 of lexeme being defined. */ + WORD32 val, /* value of lexeme being defined. */ + SYMTYP type ) /* how symbol is being defined. */ +{ + char name[SYMLEN]; + + lexemeToName( name, start, term); + return( defineSymbol( name, val, type, start )); +} /* defineLexeme */ + + +/* Function: defineSymbol */ +/* Synopsis: Define a symbol in the symbol table, enter symbol name if not */ +/* not already in table. */ +SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start ) +{ + SYM_T *sym; + WORD32 xref_count; + + if( strlen( name ) < 1 ) + { + return( &sym_undefined ); /* Protect against non-existent names. */ + } + sym = lookup( name, type ); + xref_count = 0; /* Set concordance for normal defintion. */ + + if( M_DEFINED( sym->type ) && sym->val != val && M_NOTRDEF( sym -> type )) + { + if( pass == 2 ) + { + errorSymbol( &redefined_symbol, sym->name, start ); + type = type | REDEFINED; + sym->xref_count++; /* Referenced symbol, count it. */ + xref_count = sym->xref_count; + /* moved inside "if pass2" -plb 10/2/03 allow redefinition + * of predefined symbols during pass1 + */ + return ( sym ); + } + } + + if( pass == 2 && xref ) + { + /* Put the definition line number in the concordance table. */ + /* Defined symbols are not counted as references. */ + if (sym->xref_index >= 0) { /* beware macro dummies */ + xreftab[sym->xref_index] = lineno; + /* Put the line number in the concordance table. */ + xreftab[sym->xref_index + xref_count] = lineno; + } + } + + /* Now set the value and the type. */ + sym->val = val & 0777777; + sym->type = type; + return( sym ); +} /* defineSymbol */ + + +/* Function: lookup */ +/* Synopsis: Find a symbol in table. If not in table, enter symbol in */ +/* table as undefined. Return address of symbol in table. */ +SYM_T *lookup( char *name, int type ) +{ + int ix; /* Insertion index */ + int lx; /* Left index */ + int rx; /* Right index */ + SYM_T *best; /* best match */ + SYM_T *sym; + + /* YIKES! Search dummies (and "R") before anything else!! */ + if (curmacro && curmacro->defn) { + struct macdef *mdp = curmacro->defn; + int i; + + for (i = 0, sym = mdp->args; i <= mdp->nargs; i++, sym++) + if (strcmp(name, sym->name) == 0) + return sym; + } + + lx = 0; + rx = symbol_top - 1; + best = NULL; + while (lx <= rx) { + int mx = (lx + rx) / 2; /* Find center of search area. */ + int compare; + + sym = symtab + mx; + + compare = strcmp(name, sym->name); + if (compare < 0) + rx = mx - 1; + else if (compare > 0) + lx = mx + 1; + else { /* match */ + if (overbar && !M_DEFINED(sym->type) && pass == 2) { + sym->type = DEFINED; + sym->val = vars_addr++; + nvars++; + } + return sym; /* return exact match */ + } /* match */ + + /* save best non-exact match; MACRO returns last defined n-x match! */ + if ((M_PSEUDO(sym->type)||M_EPSEUDO(sym->type)||M_MACRO(sym->type)) && + strncmp(name, sym->name, 3) == 0) + best = sym; + } /* while */ + + /* return best match (pseudo or macro) if any for lookups (not defns) */ + if (best && type == UNDEFINED) + return best; + + /* Must put symbol in table if index is negative. */ + ix = lx; /* insertion point */ + if( symbol_top + 1 >= SYMBOL_TABLE_SIZE ) { + errorSymbol( &symbol_table_full, name, lexstart ); + exit( 1 ); + } + + for( rx = symbol_top; rx >= ix; rx-- ) + symtab[rx + 1] = symtab[rx]; + + symbol_top++; + + /* Enter the symbol as UNDEFINED with a value of zero. */ + sym = symtab + ix; + strcpy( sym->name, name ); + sym->type = UNDEFINED; + sym->val = 0; + sym->xref_count = 0; + if( xref && pass == 2 && sym->xref_index >= 0) + xreftab[sym->xref_index] = 0; + + if (overbar) + nvars++; + + return sym; +} /* lookup */ + +/* Function: compareSymbols */ +/* Synopsis: Used to presort the symbol table when starting assembler. */ +int compareSymbols( const void *a, const void *b ) +{ + return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name )); +} /* compareSymbols */ + +/* Function: evalSymbol */ +/* Synopsis: Get the pointer for the symbol table entry if exists. */ +/* If symbol doesn't exist, return a pointer to the undefined sym */ +SYM_T *evalSymbol() +{ + char name[SYMLEN]; + SYM_T *sym; + + sym = lookup( lexemeToName( name, lexstart, lexterm ), UNDEFINED); + + sym->xref_count++; /* Count the number of references to symbol. */ + + if( xref && pass == 2 && sym->xref_index >= 0) + { + /* Put the line number in the concordance table. */ + xreftab[sym->xref_index + sym->xref_count] = lineno; + } + + return( sym ); +} /* evalSymbol */ + + +/* Function: moveToEndOfLine */ +/* Synopsis: Move the parser input to the end of the current input line. */ +void moveToEndOfLine() +{ + while( !ISEND( line[cc] )) cc++; /* XXX wrong! will stop on a tab! */ + lexstart = cc; + lexterm = cc; + lexstartprev = lexstart; +} /* moveToEndOfLine */ + +/* frame the next token in "line" with lexstart and lexterm indicies */ +void +next(int op) { + char c; + + /* Save start column of previous lexeme for diagnostic messages. */ + lexstartprev = lexstart; + lextermprev = lexterm; + + c = line[cc]; + if (c == ' ') { + /* eat spaces */ + do { + c = line[++cc]; + } while (c == ' '); + if (op) /* looking for operators? */ + cc--; /* return one */ + } + + overbar = 0; + lexstart = cc; + c = line[cc]; + if( isalnum(c) || ISOVERBAR(c)) { + if (ISOVERBAR(c)) + overbar = 1; + do { + c = line[++cc]; + if (ISOVERBAR(c)) + overbar = 1; + } while (isalnum(c) || ISOVERBAR(c)); + } + else if(!ISDONE(c) || c == '\t') /* not end of line, or comment */ + cc++; /* advance past all punctuation */ + lexterm = cc; +} /* next */ + +BOOL isLexSymbol() +{ + int ix; + + /* XXX alpha within first 4? 3?? */ + for( ix = lexstart; ix < lexterm; ix++ ) + if(isalpha(line[ix])) + return TRUE; /* any position will do! */ + return FALSE; +} /* isLexSymbol */ + +/* + * from macro manual (F-36BP), p.18; + * + * "A macro-instruction definition consists of four parts; + * the pseudo-instruction _define_, the _macro instruction name_ + * amd _dummy symbol list,_ the _body_, and the pseudo-instruction + * _terminate_. Each part is followed by at least one tabulation or + * carriage return." + * + * and in the next paragraph; + * + * "The name is terminated by a _space_ or by a _tab_ or _cr_ + * if there is no dummy symbol list." + * + * This accepts tabs and/or a newline after define + * (but will accept a space), and only accepts spaces + * between macro and dummy names. + */ + +void +defineMacro() { + int lexstartsave; /* point to macro name */ + int index; /* point to error char */ + int error; /* error boolean */ + int i; + int count; + WORD32 length; + WORD32 value; + char termin[SYMLEN]; + char args[MAC_MAX_ARGS][SYMLEN]; /* macro & arg names */ + char body[MAC_MAX_LENGTH + 1]; + struct macdef *mdp; + SYM_T *sym; + + if (nrepeats) { + /* we can call readLine, so throw up hands now */ + errorLexeme( &define_in_repeat, lexstartprev ); + return; + } + + while (line[lexstart] == ' ' || line[lexstart] == '\t') + next(0); + + /* not a tab or space */ + if (ISEND(line[lexstart])) { /* newline or EOS? */ + /* crock; next token should invisibly skip over line boundaries? */ + readLine(); + next(0); + while (line[lexstart] == ' ' || line[lexstart] == '\t') + next(0); + } + + /* XXX pick up macro name out here */ + + count = 0; + index = 0; + error = FALSE; + lexstartsave = lexstart; + while (!ISDONE(line[lexstart]) && count < MAC_MAX_ARGS) { + if (!isalnum(line[lexstart]) && index == 0) + index = lexstart; /* error pointer */ + lexemeToName( args[count++], lexstart, lexterm ); + /* XXX error if NOT a comma (& not first dummy) ? */ + if (line[lexterm] == ',') + next(0); /* eat the comma */ + next(0); + if (line[lexstart] == ' ') + next(0); + } + if( count == 0 ) { /* No macro name. */ + errorMessage( &no_macro_name, lexstartsave ); + error = TRUE; + } + else if( index ) { /* Bad argument name. */ + errorMessage( &bad_dummy_arg, index ); + error = TRUE; + } + else if( mac_count >= MAC_TABLE_LENGTH ) { + errorMessage( ¯o_table_full, lexstartsave ); + error = TRUE; + } + else { + value = mac_count++; /* sym value is index into mac */ + defineSymbol( args[0], value, MACRO, lexstartsave ); + } + + for( length = 0;; ) { + readLine(); + if (end_of_input) + break; + next(0); + while (line[lexstart] == ' ' || line[lexstart] == '\t') + next(0); + + lexemeToName( termin, lexstart, lexterm ); /* just look at line? */ + if (strncmp( termin, "term", 4 ) == 0) + break; + + if (!error) { + int ll = strlen(line); + int allblank = FALSE; + + /* don't save blank lines! */ + for( i = 0; i < ll && allblank; i++ ) + if(!ISBLANK(line[i])) + allblank = FALSE; + + if (allblank) /* nothing but air? */ + continue; /* skip it! */ + + if ((length + ll + 1) >= MAC_MAX_LENGTH ) { + errorMessage (¯o_too_long, lexstart ); + error = TRUE; + continue; + } + + strcpy(body+length, line); + length += ll; + } + } /* for */ + if( error ) + return; + + mdp = calloc(1, sizeof(struct macdef) + length); + if (mdp == NULL) { + fprintf(stderr, "error allocating memory for macro definition\n"); + exit(1); + } + mac_defs[value] = mdp; + + strncpy(mdp->body, body, length); + mdp->body[length] = '\0'; + mdp->nargs = count - 1; + + /* + * save dummy names + * symbol slot 0 reserved for "r" symbol + * move SYM_T entries to macinv to allow recursion + */ + sym = mdp->args; + sym->type = DEFINED; + strcpy(sym->name, "R"); + sym->val = 0; + sym->xref_index = -1; /* ??? allow xref? */ + sym++; + + for (i = 1; i <= mdp->nargs; i++, sym++) { + sym->type = DEFINED; + strcpy(sym->name, args[i]); + sym->val = 0; + sym->xref_index = -1; /* don't xref!! */ + } +} /* defineMacro */ + +/* VARIABLES pseudo-op */ +void +variables() { + /* XXX error if "variables" already seen (in this pass) */ + /* XXX error if different address on pass 2 */ + if (pass == 2) + printLine( line, clc, 0, LINE_LOC ); + vars_addr = clc; + vars_end = clc = (clc + nvars) & ADDRESS_FIELD; + if (pass == 2) + printLine( line, clc, 0, LINE_LOC); +} + +/* TEXT pseudo-op */ +void +text(void) +{ + char delim; + WORD32 w; + int count; + int ccase; + /* XXX error in repeat!! */ + do { + if (cc == maxcc) { + /* XXX EOL before delim found!!! */ + fprintf(stderr, "FIX ME!\n"); + return; + } + delim = line[cc++]; + } while (delim == ' '); /* others? NL */ + + w = count = 0; + ccase = LC; + for (;;) { + int c = nextfiodec(&ccase, delim); + if (c == -1) + break; + w |= c << ((2-count)*6); + if (++count == 3) { + punchOutObject(clc, w); /* punch it! */ + incrementClc(); + count = w = 0; + } + } + if (count > 0) { + punchOutObject(clc, w); /* punch remainder */ + incrementClc(); + } +} + +/* CONSTANTS pseudo-op */ +void +constants(void) { + int i; + + /* XXX illegal inside macro (curmacro != NULL) */ + + if (pass == 1) { + lit_loc[nconst] = clc; + + /* just use addition?! */ + for (i = 0; i < lit_count[nconst]; i++) + incrementClc(); + + nconst++; + return; + } + + /* pass 2: */ + /* XXX complain if clc != lit_base[nconst]? */ + + for (i = 0; i < lit_count[nconst]; i++) { + if (i < nlit) + punchOutObject( clc, litter[i] & 0777777); /* punch it! */ + incrementClc(); + } + + nconst++; + nlit = 0; /* litter[] now empty */ +} /* constants */ + + +/* process pseudo-ops + * return FALSE if line scan should end (no longer used) + */ +BOOL pseudo( PSEUDO_T val ) +{ + int count; + int repeatstart; + + switch( (PSEUDO_T) val ) { + case CONSTANTS: + next(0); /* Skip symbol */ + constants(); + break; + + case VARIABLES: + next(0); /* Skip symbol */ + variables(); + break; + + case DEFINE: + next(0); /* Skip symbol */ + defineMacro(); + return FALSE; + break; + + case REPEAT: + next(0); /* Skip symbol */ + + /* NOTE!! constant followed by SPACE picked up as expression!! */ + count = getExprs() & ADDRESS_FIELD; + /* XXX error if sign bit set? */ + + /* allow comma, but do not require */ + if( line[lexstart] == ',') + next(0); + + nrepeats++; + repeatstart = lexstart; /* save line start */ + while (count-- > 0) { + cc = repeatstart; /* reset input pointer */ + processLine(); /* recurse! */ + } + cc = maxcc; + nrepeats--; + + return FALSE; + break; + + case START: + next(0); /* Skip symbol */ + /* XXX illegal in macro or repeat */ + flushLoader(); + if (!ISDONE(line[lexstart])) { + if (line[lexstart] == ' ') + next(0); + start_addr = getExprs() & ADDRESS_FIELD; + next(0); + printLine( line, 0, start_addr, LINE_VAL ); + /* MACRO punches 4" of leader */ + punchTriplet(JMP | start_addr); + /* MACRO punches 24" of leader? */ + } + /* + * handle multiple tapes concatenated into one file!! + * have command line option?? treat "start" as EOF?? + */ + list_title_set = FALSE; + return FALSE; + + case TEXT: + /* NOTE!! no next()! */ + text(); + break; + + case NOINPUT: + next(0); /* Skip symbol */ + noinput = TRUE; + break; + + case EXPUNGE: + next(0); /* Skip symbol */ + if (pass == 1) + init_symtab(); + break; + + default: + break; + } /* end switch for pseudo-ops */ + return TRUE; /* keep scanning */ +} /* pseudo */ + + +/* Function: errorLexeme */ +/* Synopsis: Display an error message using the current lexical element. */ +void errorLexeme( EMSG_T *mesg, WORD32 col ) +{ + char name[SYMLEN]; + + errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col ); +} /* errorLexeme */ + + +/* Function: errorSymbol */ +/* Synopsis: Display an error message with a given string. */ +void errorSymbol( EMSG_T *mesg, char *name, WORD32 col ) +{ + char linecol[12]; + char *s; + + if( pass == 2 ) + { + s = ( name == NULL ) ? "" : name ; + errors++; + sprintf( linecol, ":%d:%d", lineno, col + 1 ); + fprintf( errorfile, "%s%-9s : error: %s \"%s\" at Loc = %5.5o\n", + filename, linecol, mesg->file, s, clc ); + saveError( mesg->list, col ); + } + error_in_line = TRUE; +} /* errorSymbol */ + + +/* Function: errorMessage */ +/* Synopsis: Display an error message without a name argument. */ +void errorMessage( EMSG_T *mesg, WORD32 col ) +{ + char linecol[12]; + + if( pass == 2 ) + { + errors++; + sprintf( linecol, ":%d:%d", lineno, col + 1 ); + fprintf( errorfile, "%s%-9s : error: %s at Loc = %5.5o\n", + filename, linecol, mesg->file, clc ); + saveError( mesg->list, col ); + } + error_in_line = TRUE; +} /* errorMessage */ + +/* Function: saveError */ +/* Synopsis: Save the current error in a list so it may displayed after the */ +/* the current line is printed. */ +void saveError( char *mesg, WORD32 col ) +{ + if( save_error_count < DIM( error_list )) + { + error_list[save_error_count].mesg = mesg; + error_list[save_error_count].col = col; + save_error_count++; + } + error_in_line = TRUE; + + if( listed ) + printErrorMessages(); +} /* saveError */ + +/* create a "symbol punch" for DDT */ +/* MUST be called after object file closed; we reuse the FILE*! */ + +void +dump_symbols(void) { + int ix; + WORD32 addr; + + objectfile = fopen( sympathname, "wb" ); + if (!objectfile) { + perror(sympathname); + return; + } + + punchLeader(0); + punchLoader(); + punchLeader(5); + + /* XXX fudge addr -- get count, and subtract 2N from 07750? */ + addr = 05000; + + for( ix = 0; ix < symbol_top; ix++ ) { + int i, type; + WORD32 name; + + type = symtab[ix].type; + if (M_FIXED(type) || M_PSEUDO(type) || M_MACRO(type)) + continue; + + name = 0; + for (i = 0; i < 3; i++) { + char c; + + c = symtab[ix].name[i]; + /* XXX leave on NUL? */ + + c = ascii_to_fiodec[tolower(c) & 0177]; + /* XXX check for BAD entries? */ + + /* XXX OR in val<<(3-i)*6?? */ + name <<= 6; + name |= c & CHARBITS; + } + punchLocObject(addr++, permute(name)); + punchLocObject(addr++, symtab[ix].val); + } + flushLoader(); + punchTriplet( JMP ); /* ??? */ + punchLeader(0); + fclose(objectfile); +} diff --git a/PDP1/spacewar1/munch.mac b/PDP1/spacewar1/munch.mac new file mode 100644 index 00000000..3ea95b34 --- /dev/null +++ b/PDP1/spacewar1/munch.mac @@ -0,0 +1,21 @@ +munching squares + +1000/ + +// from dpbsmith's web page: +// http://world.std.com/~dpbsmith/munch.html + +// classic: 04000 +// fun: 1, 4014, 4016, 100000 + +foo, lat + add \v + dac v + rcl 9s + xor v + dpy-4000 + jmp foo + +variables + +start foo diff --git a/PDP1/spacewar1/munch.rim b/PDP1/spacewar1/munch.rim new file mode 100644 index 00000000..696e54a4 Binary files /dev/null and b/PDP1/spacewar1/munch.rim differ diff --git a/PDP1/spacewar1/spacewar.mac b/PDP1/spacewar1/spacewar.mac new file mode 100644 index 00000000..408fd70d --- /dev/null +++ b/PDP1/spacewar1/spacewar.mac @@ -0,0 +1,1857 @@ +macro fio-dec system@ june 1963 + + szm=sza sma-szf + spq=szm i + clc=cma+cla-opr + ioh=iot i + + define senseswitch A + repeat 3, A=A+A + szs A + term + + define initialize A,B + law B + dap A + term + + define index A,B,C + idx A + sas B + jmp C + term + + define listen + cla+cli+clf 1-opr-opr + szf i 1 + jmp .-1 + tyi + term + + define swap + rcl 9s + rcl 9s + term + + define load A,B + lio (B + dio A + term + + define setup A,B + law i B + dac A + term + + define count A,B + isp A + jmp B + term + + define move A,B + lio A + dio B + term + + define clear A,B + init .+2, A + dzm + index .-1, (dzm B+1, .-1 + term +start + +spacewar 3.1 24 sep 62 p1. 1 + + 3/ + jmp sbf / ignore seq. break + jmp a40 + jmp a1 / use test word for control, note iot 11 00 + +/ interesting and often changed constants + +/symb loc usual value (all instructions are executed, +/ and may be replaced by jda or jsp) + +tno,6, law i 41 / number of torps + 1 +tvl,7, sar 4s / torpedo velocity +rlt,10, law i 20 / torpedo reload time +tlf,11, law i 140 / torpedo life +foo,12, -20000 / fuel supply +maa,13, 10 / spaceship angular acceleration +sac,14, sar 4s / spaceship acceleration +str,15, 1 / star capture radius +me1,16, 6000 / collision "radius" +me2,17, 3000 / above/2 +ddd,20, 777777 / 0 to save space for ddt +the,21, sar 9s / amount of torpedo space warpage +mhs,22, law i 10 / number of hyperspace shots +hd1,23, law i 40 / time in hyperspace before breakout +hd2,24, law i 100 / time in hyperspace breakout +hd3,25, law i 200 / time to recharge hyperfield generator +hr1,26, scl 9s / scale on hyperspatial displacement +hr2,27, scl 4s / scale on hyperspatially induced velocity +hur,30, 40000 / hyperspatial uncertancy +ran,31, 0 / random number + +/ place to build a private control word routine. +/ it should leave the control word in the io as follows. +/ high order 4 bits, rotate ccw, rotate cw, (both mean hyperspace) +/ fire rocket, and fire torpedo. low order 4 bits, same for +/ other ship. routine is entered by jsp cwg. + + 40/ + +cwr, jmp mg1 / normally iot 11 control + . 20/ / space + +//// + +/ routine to flush sequence breaks, if they occur. + +sbf, tyi + lio 2 + lac 0 + lsm + jmp i 1 + + define xincr X,Y,INS + lac Y + INS \ssn + dac Y + lac X + INS \scn + dac X + term + + define yincr X,Y,INS + lac Y + INS \scn + dac Y + lac X + -INS+add+sub \ssn + dac X + term + +//// + +// PLB: "aa" was "a" + define dispatch + add (aa+R + dap . 1 + jmp . +aa, + term + + define dispt A,Y,B + repeat 6, B=B+B + lio Y + dpy-A+B + term + + define scale A,B,C + lac A + sar B + dac C + term + + define diff V,S,QF + add i V + dac i V + xct QF + add i S + dac i S + term + + define random + lac ran + rar 1s + xor (355760 + add (355670 + dac ran + term + + define ranct S,X,C + random + S + X + sma + cma + dac C + term + +//// + +/sine-cosine subroutine. adams associates +/calling sequence= number in ac, jda jda sin or jdacos. +/argument is between q+2 pi, with binary point to right of bit 3. +/anser has binary point to right of bit 0. time = 2.35 ms. + + define mult Z + jda mpy + lac Z + term + +cos, 0 + dap csx + lac (62210 + add cos + dac sin + jmp .+4 + +sin, 0 + dap csx + lac sin + spa +si1, add (311040 + sub (62210 + sma + jmp si2 + add (62210 + +si3, ral 2s + mult (242763 + dac sin + mult sin + dac cos + + mult (756103 + add (121312 + mult cos + add (532511 + mult cos + add (144417 + mult sin + scl 3s + dac cos + xor sin + sma + jmp csx-1 + lac (377777 + lio sin + spi + cma + jmp csx + + lac cos +csx, jmp . + +si2, cma + add (62210 + sma + jmp si3 + add (62210 + spa + jmp .+3 + sub (62210 + jmp si3 + sub (62210 + jmp si1 + +//// + +/bbn multiply subroutine +/call.. lac one factor, jdy mpy or imp, lac other factor. + +imp, 0 /returns low 17 bits and sign in ac + dap im1 +im1, xct + jda mpy + lac imp + idx im1 + rir 1s + rcr 9s + rcr 9s + jmp i im1 + +mp2, 0 + +mpy, 0 /return 34 bits and 2 signs + dap mp1 + lac mpy + spa + cma + rcr 9s + rcr 9s +mp1, xct + spa + cma + dac mp2 + cla + repeat 21, mus mp2 + dac mp2 + xct mp1 + xor mpy + sma + jmp mp3 + lac mp2 + cma + rcr 9s + rcr 9s + cma + rcr 9s + rcr 9s + dac mp2 +mp3, idx mp1 + lac mp2 + jmp i mp1 + +//// + +/integer square root +/input in ac, binary point to right of bit 17, jda sqt +/answer in ac with binary point between 8 and 9 +/largest input number = 177777 + +sqt, 0 + dap sqx + law i 23 + dac sq1 + dzm sq2 + lio sqt + dzm sqt + +sq3, isp sq1 + jmp .+3 + lac sq2 +sqx, jmp . + + lac sq2 + sal 1s + dac sq2 + lac sqt + rcl 2s + sza i + jmp sq3 + dac sqt + lac sq2 + sal 1s + add (1 + sub sqt + sma+sza-skip + jmp sq3 + spa + cma + dac sqt + idx sq2 + jmp sq3 + +sq1, 0 +sq2, 0 + +//// + +/bbn divide subroutine + +/calling sequence.. lac hi-dividend, lio lo-dividend, jda dvd, lac divisor. +/returns quot in ac, rem in io. + +idv, 0 /integer divide, dividend in ac. + dap dv1 + lac idv + scr 9s + scr 8s + dac dvd + jmp dv1 + +dvd, 0 + dap dv1 +dv1, xct + spa + cma + dac idv + lac dvd + sma + jmp dv2 + cma + rcr 9s + rcr 9s + cma + rcr 9s + rcr 9s +dv2, sub idv + + sma + jmp dve + repeat 22, dis idv + add idv + dio idv + cli + rcr 1s + lio dvd + spi + cma + dac dvd + xct dv1 + xor dvd + rcr 9s + rcr 9s + idx dv1 +dve, idx dv1 + lac idv + spi + cma + lio dvd + jmp i dv1 + +//// + +/outline compiler +/ac=where to compile to, call oc +/ot=address of outline table + + define plinst A + lac A + dac i oc + idx oc + terminate + + define comtab A, B + plinst A + jsp ocs + lac B + jmp oce + terminate + +ocs, dap ocz /puts in swap + dio i oc + idx oc + dio i oc + idx oc +ocz, jmp . +oc, 0 + dap ocx + lac i ocx + dap ocg + plinst (stf 5 + dap ocm + idx ocx +ock, plinst (lac \sx1 + plinst (lio \sy1 + clf 6 +ocj, setup \occ,6 +ocg, lio . +och, cla + rcl 3s + dio \oci + lio (rcl 9s + dispatch + opr + jmp oc1 +oco, jmp oc2 +ocq, jmp oc3 +ocp, jmp oc4 +ocr, jmp oc5 + jmp oc6 + +//// + + plinst (szf 5 //code + add (4 + dap ocn + plinst ocn + plinst (dac \sx1 + plinst (dio \sy1 + plinst (jmp sq6 + plinst (clf 5 + plinst (lac \scm + plinst (cma + plinst (dac \scm + plinst (lac \ssm + plinst (cma + plinst (dac \ssm + plinst (lac \csm + plinst (lio \ssd + plinst (dac \ssd + plinst (dio \csm + + plinst (lac \ssc + plinst (lio \csn + plinst (dac \csn + plinst (dio \ssc + plinst ocm +ocx, jmp . + +ocm, jmp . +ocn, jmp . + +oc1, plinst (add \ssn + jsp ocs + lac (sub \scn +oce, dac i oc + idx oc + jsp ocs + plinst (ioh + lac (dpy-4000 +ocd, dac i oc + idx oc + lio \oci + count \occ, och + idx ocg + jmp ocj + +oc2, comtab (add \scm, (add \ssm +oc3, comtab (add \ssc, (sub \csm +oc4, comtab (sub \scm, (sub \ssm +oc5, comtab (add \csn, (sub \ssd +oc6, szf 6 + jmp oc9 + stf 6 + plinst (dac \ssa + lac (dio \ssi + jmp ocd +oc9, clf 6 + plinst (lac \ssa + lac (lio \ssi + jmp ocd + +//// + +/ display a star + + define starp + add \bx + swap + add \by + swap + ioh + dpy-4000 + terminate + /star +blp, dap blx + szs 60 + jmp blx + random + rar 9s + and (add 340 + spa + xor (377777 + dac \bx + lac ran + ral 4s + and (add 340 + spa + xor (377777 + dac \by + jsp bpt + ioh +blx, jmp . + +bpt, dap bpx + random + sar 9s + sar 5s + spa + cma + sal 3s + add (bds + dap bjm + cla cli clf 6-opr-opr + dpy-4000 +bjm, jmp . +bds, repeat 20, starp + szf 6 +bpx, jmp . + stf 6 + cma + swap + cma + swap + jmp bjm + +//// + +/background display . 3/13/62, prs. + + define dislis J, Q, B + repeat 6, B=B+B + clf 5 + lac flo+R + dap fpo+R +fs, dap fin+R + dap fyn+R + idx fyn+R +fin, lac /lac x + sub fpr /right margin + sma + jmp fgr+R + add (2000 +frr, spq +fou, jmp fuu+R +fie, sub (1000 + sal 8s +fyn, lio /lio y + dpy-i+B + stf 5 +fid, idx fyn+R + sad (lio Q+2 + jmp flp+R + sad fpo+R + jmp fx+R + dap fin+R + idx fyn+R + jmp fin+R +fgr, add (2000 -20000 + jmp frr+R +fuu, szf 5 +fx, jmp flo+R+1 /return + idx flo+R + idx flo+R + sas (Q+2 + jmp fid+R + law J + dac flo+R + jmp fid+R +flp, lac (lio J + sad fpo+R + jmp fx+R + dap fin+R + law J+1 + dap fyn+R + jmp fin+R +fpo, lio +flo, J + terminate + +//// + + define background + jsp bck + termin + +bck, dap bcx + szs 40 + jmp bcx + isp bcc +bcx, jmp . + law i 2 + dac bcc + dislis 1j,1q,3 + dislis 2j,2q,2 + dislis 3j,3q,1 + dislis 4j,4q,0 + isp bkc + jmp bcx + law i 20 + dac bkc + law i 1 + add fpr + spa + add (20000 + dac fpr + jmp bcx + +bcc, 0 +bkc, 0 +fpr, 10000 + +//// + +/spacewar 3.1 24 sep 62 pt. 2 + +/main control for spaceships + + nob=30 /total number of colliding objects + +ml0, load \mtc, -4000 /delay for loop + init ml1, mtb /loc of calc routines + add (nob + dap mx1 /x + nx1=mtb nob + add (nob + dap my1 /y + ny1=nx1 nob + add (nob + dap ma1 / count for length of explosion or torp + na1=ny1 nob + add (nob + dap mb1 / count of instructions taken by calc routine + nb1=na1 nob + add (nob + dac \mdx / dx + ndx=nb1 nob + add (nob + dac \mdy / dy + ndy=ndx nob + add (nob + dap mom /angular velocity + nom=ndy nob + add (2 + dap mth / angle + nth=nom 2 + add (2 + dac \mfu /fuel + nfu=nth 2 + add (2 + dac \mtr / no torps remaining + ntr=nfu 2 + add (2 + dap mot / outline of spaceship + not=ntr 2 + add (2 + dap mco / old control word + nco=not 2 + add (2 + dac \mh1 + nh1=nco 2 + add (2 + dac \mh2 + nh2=nh1 2 + add (2 + dac \mh3 + nh3=nh2 2 + add (2 + dac \mh4 + nh4=nh3 2 + nnn=nh4 2 + +//// + + law ss1 + xor mtb + sza + jmp mdn + law ss2 + xor mtb 1 + sza + jmp mdn + law 1 / test if both ships out of torps + add ntr + spa + jmp md1 + law 1 + add ntr 1 + spa i + jmp mdn +md1, xct tlf / restart delay is 2x torpedo life + sal 1s + dac \ntd + jmp ml1 + +mdn, count \ntd,ml1 + stf 1 + stf 2 + law ss1 + xor mtb + sza + clf 1 + sza i + idx \1sc + + law ss2 + xor mtb 1 + sza + clf 2 + sza i + idx \2sc + clf 2 + jmp a + +//// + +a1, law mg2 / test word control + dac \cwg + jmp a + +a40, law cwr / here from start at 4 + dac \cwg + jmp a6 + +a, lac \gct + sma + jmp a5 + count \gct, a5 + lac \1sc + sas \2sc + jmp a4 + law i 1 + dac \gct +a5, lat + and (40 + sza i + jmp a2 +a4, lac \1sc + lio \2sc + hlt + lat + and (40 + sza + jmp a2 + dzm \1sc + dzm \2sc +a6, lat + rar 6s + and (37 + sza + cma + dac \gct +a2, clear mtb, nnn-1 / clear out all tables + law ss1 + dac mtb + law ss2 + dac mtb 1 + lac (200000 + dac nx1 + dac ny1 + cma + dac nx1 1 + dac ny1 1 + lac (144420 + dac nth + +//// + + law nnn / start of outline problem + dac not + lio ddd + spi i + jmp a3 + jda oc + ot1 +a3, dac not 1 + jda oc + ot2 + xct tno + dac ntr + dac ntr 1 + lac foo + dac nfu + dac nfu 1 + law 2000 + dac nb1 + dac nb1 1 + xct mhs + dac nh2 + dac nh2 1 + jmp ml0 + + +/ control word get routines + +mg1, dap mg3 + cli + iot 11 +mg3, jmp . + +mg2, dap mg4 + lat + swap +mg4, jmp . + +//// + +ml1, lac . / 1st control word + sza i / zero if not active + jmp mq1 / not active + swap + idx \moc + spi + jmp mq4 + law 1 + add ml1 + dap ml2 + law 1 + add mx1 + dap mx2 + law 1 + add my1 + dap my2 + law 1 + add ma1 + dap ma2 + law 1 + add mb1 + dap mb2 +mot, lac . + dap sp5 +ml2, lac . / 2nd control word + spq / can it collide? + jmp mq2 / no +mx1, lac . / calc if collision +mx2, sub . / delta x + + spa / take abs value + cma + dac \mt1 + sub me1 / < epsilon ? + sma + jmp mq2 / no +my1, lac . +my2, sub . + spa + cma + sub me1 / < epsilon ? + sma + jmp mq2 / no + add \mt1 + sub me2 + sma + jmp mq2 + lac (mex 400000 / yes, explode + dac i ml1 / replace calc routine with explosion + dac i ml2 + lac i mb1 / duration of explosion +mb2, add . + cma + sar 8s + add (1 +ma1, dac . +ma2, dac . +mq2, idx mx2 / end of comparion loop + idx my2 + idx ma2 + idx mb2 + index ml2, (lac mtb nob, ml2 + +//// + +mq4, lac i ml1 / routine for calculating spaceship + dap . 1 / or other object and displaying it + jsp . +mb1, lac . / alter count of number of instructions + add \mtc + dac \mtc +mq1, idx mx1 / end of comparison and display loop + idx my1 + idx ma1 + idx mb1 + idx \mdx + idx \mdy + idx mom + idx mth + idx \mas + idx \mfu + idx \mtr + idx mot + idx mco + idx \mh1 + idx \mh2 + idx \mh3 + idx \mh4 + index ml1, (lac mtb nob-1, ml1 + lac i ml1 / display and compute last point + sza i / if active + jmp mq3 + dap . 1 + jsp . + lac i mb1 + add \mtc + dac \mtc +mq3, background / display stars of the heavens + jsp blp / display massive star + count \mtc, . / use the rest of time of main loop + jmp ml0 / repeat whole works + +//// + +/ misc calculation routines + + / explosion + +mex, dap mxr + cla + diff \mdx, mx1, (sar 3s + cla + diff \mdy, my1, (sar 3s + law ms2 + dap msh + lac i mb1 / time involved + cma cli-opr + sar 3s + dac \mxc +ms1, sub (140 + sma + idx msh +mz1, random + and (777 + ior (scl + dac mi1 + random + scr 9s + sir 9s +msh, xct . +mi1, hlt + add i my1 + swap + add i mx1 + dpy-i 300 + count \mxc, mz1 + count i ma1, mxr + dzm i ml1 +mxr, jmp . + +ms2, scr 1s + scr 3s + +/ torpedo calc routine + +tcr, dap trc + count i ma1, tc1 + lac (mex 400000 + dac i ml1 + law i 2 + dac i ma1 + jmp trc + +tc1, lac i mx1 + sar 9s + xct the + diff \mdy, my1, (sar 3s + sar 9s + xct the + diff \mdx, mx1, (sar 3s + dispt i, i my1, 1 +trc, jmp . + +//// + +/ hyperspace routines + +/ this routine handles a non-colliding ship invisibly +/ in hyperspace + +hp1, dap hp2 + count i ma1, hp2 + law hp3 / next step + dac i ml1 + law 7 + dac i mb1 + random + scr 9s + sir 9s + xct hr1 + add i mx1 + dac i mx1 + swap + add i my1 + dac i my1 + random + scr 9s + sir 9s + xct hr2 + dac i \mdy + dio i \mdx + setup \hpt,3 + lac ran + dac i mth +hp4, lac i mth + sma + sub (311040 + spa + add (311040 + dac i mth + count \hpt,hp4 + xct hd2 + dac i ma1 +hp2, jmp . + +/ this routine handles a ship breaking out of +/ hyperspace + +hp3, dap hp5 + count i ma1,hp6 + lac i \mh1 + dac i ml1 + law 2000 + dac i mb1 + count i \mh2,hp7 + dzm i \mh2 + +//// + +hp7, xct hd3 + dac i \mh3 + lac i \mh4 + add hur + dac i \mh4 + random + ior (400000 + add i \mh4 + spa + jmp hp5 + lac (mex 400000 + dac i ml1 + law i 10 + dac i ma1 + law 2000 + dac i mb1 +hp6, lac i mx1 + dispt i, i my1, 2 +hp5, jmp . + +//// + +/ spaceship calc + +ss1, dap srt / first spaceship + jsp i \cwg + dio \scw + jmp sr0 + +ss2, dap srt + jsp i \cwg + rir 4s + dio \scw + +sr0,sc1, + lio \scw /control word + clf 6 cla-opr /update angle + spi + add maa + ril 1s + spi + sub maa +mom, add . + dac i mom + szs 10 + jmp sr8 + dzm i mom + ral 7s +sr8, ril 1s + spi + stf 6 + lio i \mfu + spi i + clf 6 + +mth, add . + sma + sub (311040 + spa + add (311040 + dac i mth + jda sin + dac \sn + dzm \bx + dzm \by + szs 60 + jmp bsg + lac i mx1 + sar 9s + sar 2s + dac \t1 + jda imp + lac \t1 + dac \t2 + lac i my1 + +//// + + sar 9s + sar 2s + dac \t1 + jda imp + lac \t1 + add \t2 + sub str + sma i sza-skp + jmp poh + add str + dac \t1 + jda sqt + sar 9s + jda mpy + lac \t1 + scr 2s + szs i 20 / switch 2 for light star + scr 2s + sza + jmp bsg + dio \t1 + lac i mx1 + cma + jda idv + lac \t1 + opr + dac \bx + lac i my1 + cma + + jda idv + lac \t1 + opr + dac \by +bsg, cla + sad i \mfu + clf 6 + lac i mth + jda cos + dac \cs + sar 9s + xct sac + szf i 6 + cla + add \by + diff \mdy, my1, (sar 3s + lac \sn + sar 9s + xct sac + cma + szf i 6 + cla + add \bx + diff \mdx, mx1, (sar 3s +sp1, scale \sn, 5s, \ssn +sp2, scale \cs, 5s, \scn + lac i mx1 + +//// + + sub \ssn + dac \sx1 + sub \ssn + dac \stx + lac i my1 + add \scn + dac \sy1 + add \scn + dac \sty +/ Modified for Smaller Laptop screens - BDS + scale \sn, 9s, \ssn + scale \cs, 9s, \scn +// scale \sn, 8s, \ssn +// scale \cs, 8s, \scn + lac \ssn + dac \ssm + add \scn + dac \ssc + dac \ssd + lac \ssn + sub \scn + dac \csn + cma + dac \csm + lac \scn + dac \scm + cla cli-opr + dpy-4000 +sp5, jmp . +sq6, ioh + ranct sar 9s, sar 4s, \src + lio \scw + ril 2s + spi i / not blasting + jmp sq9 / no tail +sq7, scale \sn, 8s, \ssn + scale \cs, 8s, \scn + count i \mfu, st2 + dzm i \mfu + jmp sq9 + +st2, yincr \sx1, \sy1, sub + dispt i, \sy1 + count \src,sq7 +sq9, count i ma1, sr5 / check if torp tube reloaded + dzm i ma1 / prevent count around +mco, lac . / previous control word + cma + szs i 30 + clc + and \scw / present control word + ral 3s / torpedo bit to bit 0 + sma + jmp sr5 / no launch + count i \mtr, st1 / check if torpedos exhausted + dzm i \mtr / prevent count around + jmp sr5 +st1, init sr1, mtb / search for unused object +sr1, lac . + sza i / 0 if unused + jmp sr2 + index sr1, (lac mtb+nob, sr1 + hlt / no space for new objects + jmp .-1 + +//// + +sr2, lac (tcr + dac i sr1 + law nob + add sr1 + dap ss3 + lio \stx +ss3, dio . + add (nob + dap ss4 + lio \sty +ss4, dio . + add (nob + dap sr6 + add (nob + dap sr7 + add (nob + dap sr3 + add (nob + dap sr4 + lac \sn + xct tvl + cma + add i \mdx +sr3, dac . + lac \cs + xct tvl + add i \mdy +sr4, dac . + xct rlt + dac i ma1 / permit torp tubes to cool +trp, xct tlf / life of torpedo +sr6, dac . + law 20 +sr7, dap . / length of torp calc +sr5, count i \mh3, st3 / hyperbutton active? + dzm i \mh3 + lac i \mh2 + sza i + jmp st3 + lac \scw + cma + ior i mco + and (600000 + sza + jmp st3 + lac i ml1 + dac i \mh1 + lac (hp1 400000 + dac i ml1 + xct hd1 + dac i ma1 + law 3 + dac i mb1 +st3, +srt, jmp . + +//// + +/ here to handle spaceships into star + +/ spaceship in star + +poh, dzm i \mdx + dzm i \mdy + szs 50 + jmp po1 + lac (377777 + dac i mx1 + dac i my1 + lac i mb1 + dac \ssn + count \ssn, . + jmp srt + +po1, lac (mex 400000 / now go bang + dac i ml1 + law i 10 + dac i ma1 + jmp srt + +//// + +/ outlines of spaceships + +ot1, 111131 + 111111 + 111111 + 111163 + 311111 + 146111 + 111114 + 700000 +. 5/ +ot2, 013113 + 113111 + 116313 + 131111 + 161151 + 111633 + 365114 + 700000 +. 5/ + constants + 0 + variables +p, . 200/ / space for patches + +mtb, / table of objects and their properties + 6000/ +/stars 1 3/13/62 prs. + decimal + define mark X, Y + repeat 10, Y=Y+Y + 0 8192 -X + 0 Y + terminate + + +1j, mark 1537, 371 /87 taur, aldebaran + mark 1762, -189 /19 orio, rigel + mark 1990, 168 /58 orio, betelgeuze + mark 2280, -377 /9 cmaj, sirius + mark 2583, 125 /25 cmin, procyon + mark 3431, 283 /32 leon, regulus + mark 4551, -242 /67 virg, spica + mark 4842, 448 /16 boot, arcturus +1q, mark 6747, 196 /53 aqil, altair + +2j, mark 1819, 143 /24 orio, bellatrix + mark 1884, -29 /46 orio + mark 1910, -46 /50 orio + mark 1951, -221 /53 orio + mark 2152, -407 / 2 cmaj + mark 2230, 375 /24 gemi + mark 3201, -187 /30 hyda, alphard + mark 4005, 344 /94 leon, denebola +2q, mark 5975, 288 /55 ophi + +3j, mark 46, 333 /88 pegs, algenib + mark 362, -244 /31 ceti + mark 490, 338 /99 pisc + mark 566, -375 /52 ceti + mark 621, 462 / 6 arie + mark 764, -78 /68 ceti, mira + mark 900, 64 /86 ceti + mark 1007, 84 /92 ceti + mark 1243, -230 /23 erid + mark 1328, -314 /34 erid + mark 1495, 432 /74 taur + mark 1496, 356 /78 taur + mark 1618, 154 / 1 orio + mark 1644, 52 / 8 orio + mark 1723, -119 /67 erid + mark 1755, -371 / 5 leps + mark 1779, -158 /20 orio + mark 1817, -57 /28 orio + mark 1843, -474 / 9 leps + mark 1860, -8 /34 orio + mark 1868, -407 /11 leps + mark 1875, 225 /39 orio + mark 1880, -136 /44 orio + mark 1887, 480 /123 taur + mark 1948, -338 /14 leps + mark 2274, 296 /31 gemi + mark 2460, 380 /54 gemi + mark 2470, 504 /55 gemi + mark 2513, 193 / 3 cmin + mark 2967, 154 /11 hyda + mark 3016, 144 /16 hyda + mark 3424, 393 /30 leon + mark 3496, 463 /41 leon, algieba + mark 3668, -357 /nu hyda + mark 3805, 479 /68 leon + mark 3806, 364 /10 leon + mark 4124, -502 / 2 corv + mark 4157, -387 / 4 corv + mark 4236, -363 / 7 corv + mark 4304, -21 /29 virg + mark 4384, 90 /43 virg + mark 4421, 262 /47 virg + mark 4606, -2 /79 virg + mark 4721, 430 / 8 boot + mark 5037, -356 / 9 libr + mark 5186, -205 /27 libr + mark 5344, 153 /24 serp + mark 5357, 358 /28 serp + mark 5373, -71 /32 serp + mark 5430, -508 / 7 scor + mark 5459, -445 / 8 scor + mark 5513, -78 / 1 ophi + mark 5536, -101 / 2 ophi + mark 5609, 494 /27 herc + mark 5641, -236 /13 ophi + mark 5828, -355 /35 ophi + mark 5860, 330 /64 herc + mark 5984, -349 /55 serp + mark 6047, 63 /62 ophi + mark 6107, -222 /64 ophi + mark 6159, 217 /72 ophi + mark 6236, -66 /58 serp + mark 6439, -483 /37 sgtr + mark 6490, 312 /17 aqil + mark 6491, -115 /16 aqil + mark 6507, -482 /41 sgtr + mark 6602, 66 /30 aqil + mark 6721, 236 /50 aqil + mark 6794, 437 /12 sgte + mark 6862, -25 /65 aqil + mark 6914, -344 / 9 capr + mark 7014, 324 / 6 dlph + mark 7318, -137 /22 aqar + mark 7391, 214 / 8 pegs + mark 7404, -377 /49 capr + mark 7513, -18 /34 aqar + mark 7539, 130 /26 pegs + mark 7644, -12 /55 aqar + mark 7717, 235 /42 pegs + mark 7790, -372 /76 aqar +3q, mark 7849, 334 /54 pegs, markab +4j, mark 1, -143 /33 pisc + mark 54, 447 /89 pegs + mark 54, -443 /7 ceti + mark 82, -214 /8 ceti + mark 223, -254 /17 ceti + mark 248, 160 /63 pisc + mark 273, -38 /20 ceti + mark 329, 167 /71 pisc + mark 376, 467 /84 pisc + mark 450, -198 /45 ceti + mark 548, 113 /106 pisc + mark 570, 197 /110 pisc + mark 595, -255 /53 ceti + mark 606, -247 /55 ceti + mark 615, 428 / 5 arie + mark 617, 61 /14 pisc + mark 656, -491 /59 ceti + mark 665, 52 /113 pisc + mark 727, 191 /65 ceti + mark 803, -290 /72 ceti + mark 813, 182 /73 ceti + mark 838, -357 /76 ceti + mark 878, -2 /82 ceti + mark 907, -340 /89 ceti + mark 908, 221 /87 ceti + mark 913, -432 / 1 erid + mark 947, -487 / 2 erid + mark 976, -212 / 3 erid + mark 992, 194 /91 ceti + mark 1058, 440 /57 arie + mark 1076, 470 /58 arie + mark 1087, -209 /13 erid + mark 1104, 68 /96 ceti + mark 1110, -503 /16 erid + mark 1135, 198 / 1 taur + mark 1148, 214 / 2 taur + mark 1168, 287 / 5 taur + mark 1170, -123 /17 erid + mark 1185, -223 /18 erid + mark 1191, -500 /19 erid + mark 1205, 2 /10 taur + mark 1260, -283 /26 erid + mark 1304, -74 /32 erid + mark 1338, 278 /35 taur + mark 1353, 130 /38 taur + mark 1358, 497 /37 taur + mark 1405, -162 /38 erid + mark 1414, 205 /47 taur + mark 1423, 197 /49 taur + mark 1426, -178 /40 erid + mark 1430, 463 /50 taur + mark 1446, 350 /54 taur + mark 1463, 394 /61 taur + mark 1470, 392 /64 taur + mark 1476, 502 /65 taur + mark 1477, 403 /68 taur + mark 1483, 350 /71 taur + mark 1485, 330 /73 taur + mark 1495, 358 /77 taur + mark 1507, 364 / + mark 1518, -6 /45 erid + mark 1526, 333 /86 taur + mark 1537, 226 /88 taur + mark 1544, -81 /48 erid + mark 1551, 280 /90 taur + mark 1556, 358 /92 taur + mark 1557, -330 /53 erid + mark 1571, -452 /54 erid + mark 1596, -78 /57 erid + mark 1622, 199 / 2 orio + mark 1626, 124 / 3 orio + mark 1638, -128 /61 erid + mark 1646, 228 / 7 orio + mark 1654, 304 / 9 orio + mark 1669, 36 /10 orio + mark 1680, -289 /64 erid + mark 1687, -167 /65 erid + mark 1690, -460 / + mark 1690, 488 /102 taur + mark 1700, 347 /11 orio + mark 1729, 352 /15 orio + mark 1732, -202 /69 erid + mark 1750, -273 / 3 leps + mark 1753, 63 /17 orio + mark 1756, -297 / 4 leps + mark 1792, -302 / 6 leps + mark 1799, -486 / + mark 1801, -11 /22 orio + mark 1807, 79 /23 orio + mark 1816, -180 /29 orio + mark 1818, 40 /25 orio + mark 1830, 497 /114 taur + mark 1830, 69 /30 orio + mark 1851, 134 /32 orio + mark 1857, 421 /119 taur + mark 1861, -168 /36 orio + mark 1874, 214 /37 orio + mark 1878, -132 / + mark 1880, -112 /42 orio + mark 1885, 210 /40 orio + mark 1899,-60 /48 orio + mark 1900, 93 /47 orio + mark 1900, -165 /49 orio + mark 1909, 375 /126 taur + mark 1936, -511 /13 leps + mark 1957, 287 /134 taur + mark 1974, -475 /15 leps + mark 1982, 461 /54 orio + mark 2002, -323 /16 leps + mark 2020, -70 / + mark 2030, 220 /61 orio + mark 2032, -241 / 3 mono + mark 2037, 458 /62 orio + mark 2057, -340 /18 leps + mark 2059, 336 /67 orio + mark 2084, 368 /69 orio + mark 2084, 324 /70 orio + mark 2105, -142 / 5 mono + mark 2112, -311 / + mark 2153, 106 / 8 mono + mark 2179, 462 /18 gemi + mark 2179, -107 /10 mono + mark 2184, -159 /11 mono + mark 2204, 168 /13 mono + mark 2232, -436 / 7 cmaj + mark 2239, -413 / 8 cmaj + mark 2245, -320 / + mark 2250, 227 /15 mono + mark 2266, 303 /30 gemi + mark 2291, 57 /18 mono + mark 2327, 303 /38 gemi + mark 2328, -457 /15 cmaj + mark 2330, -271 /14 cmaj + mark 2340, -456 /19 cmaj + mark 2342, -385 /20 cmaj + mark 2378, -93 /19 mono + mark 2379, 471 /43 gemi + mark 2385, -352 /23 cmaj + mark 2428, -8 /22 mono + mark 2491, -429 / + mark 2519, 208 / 4 cmin + + mark 2527, 278 / 6 cmin + mark 2559, -503 / + mark 2597, -212 /26 mono + mark 2704, -412 / + mark 2709, -25 /28 mono + mark 2714, 60 / + mark 2751, -61 /29 mono + mark 2757, -431 /16 pupp + mark 2768, -288 /19 pupp + mark 2794, 216 /17 canc + mark 2848, -82 / + mark 2915, 138 / 4 hyda + mark 2921, 84 / 5 hyda + mark 2942, -355 / 9 hyda + mark 2944, 497 /43 canc + mark 2947, 85 / 7 hyda + mark 2951, -156 / + mark 2953, 421 /47 canc + mark 2968, -300 /12 hyda + mark 2976, 141 /13 hyda + mark 3032, 279 /65 canc + mark 3124, 62 /22 hyda + mark 3157, -263 /26 hyda + mark 3161, -208 /27 hyda + mark 3209, -53 /31 hyda + mark 3225, -17 /32 hyda + mark 3261, 116 / + mark 3270, -16 /35 hyda + mark 3274, -316 /38 hyda + mark 3276, 236 /14 leon + mark 3338, -327 /39 hyda + mark 3385, 194 /29 leon + mark 3415, -286 /40 hyda + mark 3428, 239 /31 leon + mark 3429, 3 /15 sext + mark 3446, -270 /41 hyda + mark 3495, 455 /40 leon + mark 3534, -372 /42 hyda + mark 3557, -3 /30 sext + mark 3570, 223 /47 leon + mark 3726, -404 /al crat + mark 3736, -44 /61 leon + mark 3738, 471 /60 leon + mark 3754, 179 /63 leon + mark 3793, -507 /11 crat + mark 3821, -71 /74 leon + mark 3836, -324 /12 crat + mark 3846, 150 /77 leon + mark 3861, 252 /78 leon + mark 3868, -390 /15 crat + mark 3935, -211 /21 crat + mark 3936, -6 /91 leon + mark 3981, -405 /27 crat + mark 3986, 161 / 3 virg + mark 3998, 473 /93 leon + mark 4013, 53 / 5 virg + mark 4072, 163 / 8 virg + mark 4097, 211 / 9 virg + mark 4180, -3 /15 virg + mark 4185, 418 /11 coma + mark 4249, -356 / 8 corv + mark 4290, -170 /26 virg + mark 4305, 245 /30 virg + mark 4376, -205 /40 virg + mark 4403, 409 /36 coma + mark 4465, -114 /51 virg + mark 4466, 411 /42 coma + mark 4512, -404 /61 virg + mark 4563, -352 /69 virg + mark 4590, -131 /74 virg + mark 4603, 95 /78 virg + mark 4679, 409 / 4 boot + mark 4691, 371 / 5 boot + mark 4759, 46 /93 virg + mark 4820, 66 / + mark 4822, -223 /98 virg + mark 4840, -126 /99 virg + mark 4857, -294 /100 virg + mark 4864, 382 /20 boot + mark 4910, -41 /105 virg + mark 4984, 383 /29 boot + mark 4986, 322 /30 boot + mark 4994, -119 /107 virg + mark 5009, 396 /35 boot + mark 5013, 53 /109 virg + mark 5045, 444 /37 boot + mark 5074, -90 /16 libr + mark 5108, 57 /110 virg + mark 5157, -442 /24 libr + mark 5283, -221 /37 libr + mark 5290, -329 /38 libr + mark 5291, 247 /13 serp + mark 5326, -440 /43 libr + mark 5331, 455 /21 serp + mark 5357, 175 /27 serp + mark 5372, 420 /35 serp + mark 5381, 109 /37 serp + mark 5387, 484 /38 serp + mark 5394, -374 /46 libr + mark 5415, 364 /41 serp + mark 5419, -318 /48 libr + mark 5455, -253 /xi scor + mark 5467, -464 / 9 scor + mark 5470, -469 /10 scor + mark 5497, -437 /14 scor + mark 5499, -223 /15 scor + mark 5558, 29 /50 serp + mark 5561, 441 /20 herc + mark 5565, -451 / 4 ophi + mark 5580, 325 /24 herc + mark 5582, -415 / 7 ophi + mark 5589, -186 / 3 ophi + mark 5606, -373 / 8 ophi + mark 5609, 50 /10 ophi + mark 5610, -484 / 9 ophi + mark 5620, 266 /29 herc + mark 5713, -241 /20 ophi + mark 5742, 235 /25 ophi + mark 5763, 217 /27 ophi + mark 5807, 293 /60 herc + mark 5868, -8 /41 ophi + mark 5888, -478 /40 ophi + mark 5889, -290 /53 serp + mark 5924, -114 / + mark 5925, 96 /49 ophi + mark 5987, -183 /57 ophi + mark 6006, -292 /56 serp + mark 6016, -492 /58 ophi + mark 6117, -84 /57 serp + mark 6117, 99 /66 ophi + mark 6119, 381 /93 herc + mark 6119, 67 /67 ophi + mark 6125, 30 /68 ophi + mark 6146, 57 /70 ophi + mark 6158, 198 /71 ophi + mark 6170, 473 /102 herc + mark 6188, -480 /13 sgtr + mark 6234, 76 /74 ophi + mark 6235, 499 /106 herc + mark 6247, -204 /xi scut + mark 6254, -469 /21 sgtr + mark 6255, 494 /109 herc + mark 6278, -333 /ga scut + mark 6313, -189 /al scut + mark 6379, 465 /110 herc + mark 6382, -110 /be scut + mark 6386, 411 /111 herc + mark 6436, 93 /63 serp + mark 6457, 340 /13 aqil + mark 6465, -134 /12 aqil + mark 6478, -498 /39 sgtr + mark 6553, 483 / 1 vulp + mark 6576, -410 /44 sgtr + mark 6576, -368 /46 sgtr + mark 6607, 3 /32 aqil + mark 6651, 163 /38 aqil + mark 6657, 445 / 9 vulp + mark 6665, -35 /41 aqil + mark 6688, 405 / 5 sgte + mark 6693, 393 / 6 sgte + mark 6730, 416 / 7 sgte + mark 6739, 430 / 8 sgte + mark 6755, 17 /55 aqil + mark 6766, 187 /59 aqil + mark 6772, 140 /60 aqil + mark 6882, 339 /67 aqil + mark 6896, -292 / 5 capr + mark 6898, -292 / 6 capr + mark 6913, -297 / 8 capr + mark 6958, -413 /11 capr + mark 6988, 250 / 2 dlph + mark 7001, 326 / 4 dlph + mark 7015, -33 /71 aqil + mark 7020, 475 /29 vulp + mark 7026, 354 / 9 dlph + mark 7047, 335 /11 dlph + mark 7066, 359 /12 dlph + mark 7067, -225 / 2 aqar + mark 7068, -123 / 3 aqar + mark 7096, -213 / 6 aqar + mark 7161, -461 /22 capr + mark 7170, -401 /23 capr + mark 7192, -268 /13 capr + mark 7199, 222 / 5 equl + mark 7223, 219 / 7 equl + mark 7230, 110 / 8 equl + mark 7263, -393 /32 capr + mark 7267, 441 / 1 pegs + mark 7299, -506 /36 capr + mark 7347, -453 /39 capr + mark 7353, -189 /23 aqar + mark 7365, -390 /40 capr + mark 7379, -440 /43 capr + mark 7394, 384 / 9 pegs + mark 7499, -60 /31 aquar + mark 7513, 104 /22 pegs + mark 7515, -327 /33 aqar + mark 7575, -189 /43 aqar + mark 7603, -43 /48 aqar + mark 7604, 266 /31 pegs + mark 7624, 20 /52 aquar + mark 7639, 96 /35 pegs + mark 7654, -255 /57 aqar + mark 7681, -14 /62 aqar + mark 7727, -440 /66 aqar + mark 7747, 266 /46 pegs + mark 7761, -321 /71 aqar + mark 7779, -185 /73 aqar + mark 7795, 189 /50 pegs + mark 7844, 75 / 4 pisc + mark 7862, 202 /55 pegs + mark 7874, -494 /88 aqar + mark 7903, -150 /90 aqar + mark 7911, -219 /91 aqar + mark 7919, 62 / 6 pisc + mark 7923, -222 /93 aqar + mark 7952, -470 /98 aqar + mark 7969, -482 /99 aqar + mark 7975, 16 / 8 pisc + mark 7981, 133 /10 pisc + mark 7988, 278 /70 pegs + mark 8010, -489 /101 aqar + mark 8049, 116 /17 pisc + mark 8059, -418 /104 aqar + mark 8061, 28 /18 pisc + mark 8064, -344 /105 aqar + mark 8159, 144 /28 pisc + mark 8174, -149 /30 pisc +4q, mark 8188, -407 / 2 ceti + start 4 + diff --git a/PDP1/spacewar1/spacewar.rim b/PDP1/spacewar1/spacewar.rim new file mode 100644 index 00000000..a44b673e Binary files /dev/null and b/PDP1/spacewar1/spacewar.rim differ diff --git a/PDP11/lunar11/README.txt b/PDP11/lunar11/README.txt new file mode 100644 index 00000000..33267f80 --- /dev/null +++ b/PDP11/lunar11/README.txt @@ -0,0 +1,52 @@ +VT11/GT40 Lunar Lander files +preliminary README phil + +Phil Budne +February 9, 2004 + +Lunar lander startup can take forever (lander uses spin loop to count +down time for display of starting screen. This may be due to the fact +that SIMH only tracks cycles in terms of instructions, not execution +time). To speed up display of the startup screen, deposit a 1 in +location 32530 after loading the lander program, and before starting +it; + + sim> ! Set CPU to a Unibus system type + sim> set cpu 11/70 + sim> ! Enable DLI device so VT device autoconfigures + sim> ! with a starting vector of 320 + sim> set dli enable + sim> set dli line=2 + sim> ! Enable VT device + sim> set vt enable + sim> load lunar.lda + sim> dep 32530 1 + sim> run + +Lunar lander only needs a small screen area, and can run using a +simulated "VR14" display, which can fit on many computer screens +without scaling: + + sim> set vt crt=vr14 + sim> set vt scale=1 + +For more information on the VT11/GT40 see + http://www.brouhaha.com/~eric/retrocomputing/dec/gt40/ + +lunar.txt + Lunar lander instructions + (from ???) + +lunar.lda + PDP-11 Paper Tape (LDA) format + http://www.brouhaha.com/~eric/retrocomputing/dec/gt40/software/moonlander/lunar.lda + +lunar.dag + PDP-11 Paper Tape (LDA) format + above(?) as patched by Doug Gwyn to fix a spelling error? + load fails with bad checksum under 3.2-preview2? + +gtlem.mac + Does not match above binaries?? + http://www.brouhaha.com/~eric/retrocomputing/dec/gt40/software/moonlander/gtlem.mac + diff --git a/PDP11/lunar11/gtlem.mac b/PDP11/lunar11/gtlem.mac new file mode 100644 index 00000000..5f9c901f --- /dev/null +++ b/PDP11/lunar11/gtlem.mac @@ -0,0 +1,5102 @@ +;********************************************************************* +; +; MOONLANDER FOR THE GT40 TERMINAL, FIRST VERSION. +; LEM.090, FEBRUARY 25, 1973 5:55 PM +; WRITTEN BY JACK BURNESS. +; FOR FANTASTIC PROGRAMS AT REASONABLE PRICES, +; OR EXPERT CONSULTING DONE IN EVERY PHASE OF SYSTEM +; DESIGN AND IMPLEMENTATION, WRITE +; JACK BURNESS +; P.O. BOX 411 +; MAYNARD, MASS. +; 01754 +;********************************************************************* + IN1=R0 ;INPUT REGISTER FOR SUBROUTINE CALLING. + IN2=R1 ;SECOND VALUE. + RET1=R2 ;HIGH ORDER PORTION OF SUBROUTINE RETURN. + RET2=R3 ;LOW ORDER PORTION. + TEMP=R4 ;SCRATCH REGISTER. + TEMP2=R5 ;SECOND SCRATCH. +; +; MAJOR DEFINITIONS FOR THE SYSTEM. +; + CLKFRQ=50. ;FREQUENCY OF THE RUN TIME CLOCK. + FIVESECONDS=300. ;DEFINE FIVE SECONDS WORTH OF TIME. + CLKFDG=1500. ;CLKFRQ*25. + CLKFG2=3000. ;CLKFRQ*50. + CLKFG3=600. ;CLKFRQ*10. + LKS=177546 ;CLOCK ADDRESS. + G=32. ;ACTUALLY 32.174 IN FUTURE CALCULATIONS. + G1=16087. ;G*500 + G2=2670. ;MOON GRAVITY*500. (.166 EARTH'S). + STATUS=177776 ;WHERE STATUS IS LOCATED. + DISTOP=173400 ;THE DISPLAY STOP INSTRUCTION. + SETSVM=106120 ;INSTRUCTION TO SET SMALL VECTOR MODE. + SETPNT=114000 ;BASIC SET POINT INSTRUCTION. + DISJMP=160000 ;BASIC DISPLAY JUMP INSTRUCTION. + DPC=172000 ;DISPLAY PROGRAM COUNTER. + DSR=172002 ;DISPLAY STATUS REGISTER. + XSR=172004 ;X STATUS REGISTER. + YSR=172006 ;Y STATUS REGISTER. + INT=40000 ;INTENSITY BIT. + LEFT=20000 ;BIT TO SET FOR LEFT X IN LONG V + DOWN=20000 ;BIT TO SET FOR DOWN Y IN LONG VECTOR. + OTHER=100 ;BIT TO SET LEFT OR DOWN FOR SHORT MODE. + INTTWO=200 ;INTENSIFY BIT SHIFTED OVER. + MINTRS=10. ;10% IS MIN. ROCKET WILL RUN AT. + MAXTRS=10500. ;MAXIMUM THRUST OF ENGINE. + EMPTY=14300. ;EMPTY WEIGHT OF SHIP (18200 DESCENT FUEL). + FUELS=30000. ;INITIAL START QUANTITY OF FUEL. + DX1=0. ;X POSITION FOR DATA MESSAGE. + DX2=250. + DX3=500. + DX4=750. + DY1=730. ;Y POSITION FOR DATA MESSAGE. + DY2=730. + DY3=730. + DY4=730. + ITEMX1=900. ;X POSITIONS FOR CHOICE OF DISPLAY. + ITEMX2=ITEMX1 + ITEMX3=ITEMX1 + ITEMX4=ITEMX1 + ITEMX5=ITEMX1 + ITEMX6=ITEMX1 + ITEMX7=ITEMX1 + ITEMX8=ITEMX1 + ITEMX9=ITEMX1 + ITEMXT=ITEMX1 + ITEMXE=ITEMX1 + ITEMXS=ITEMX1 + ITEMDY=22. ;SET UP DELTA Y VALUES NOW. + ITEMYS=5. ;DEFINE BOTTOM Y NOW. + ITEMYE=ITEMYS+ITEMDY ;DEFINE ALL THE OTHER Y'S AS DELTA'S. + ITEMYT=ITEMYE+ITEMDY + ITEMY9=ITEMYT+ITEMDY + ITEMY8=ITEMY9+ITEMDY + ITEMY7=ITEMY8+ITEMDY + ITEMY6=ITEMY7+ITEMDY + ITEMY5=ITEMY6+ITEMDY + ITEMY4=ITEMY5+ITEMDY + ITEMY3=ITEMY4+ITEMDY + ITEMY2=ITEMY3+ITEMDY + ITEMY1=ITEMY2+ITEMDY + SLFTAX=945. ;COORDINATES FOR THE TURNING ARROWS. + SLFTAY=375. + BLFTAX=945. + BLFTAY=330. + SRGTAX=955. + SRGTAY=375. + BRGTAX=955. + BRGTAY=330. + BARLX=947. ;LEFT EDGE OF THROTTLE BAR. + BARBY=450. ;BOTTOM OF THE THROTTLE BAR. + BARTY=700. ;TOP OF THE BAR. + BARSIZ=250. ;LENGTH OF THE BAR. + BARFDG=BARBY+25. ;ARITHEMENTIC FUDGE FACTOR. + BARMXR=940. ;WHERE UNDERLINING IS TO START. + BARMXL=43.+LEFT ;LENGTH OF UNDERLINE. + BAREST=55.+LEFT ;WHERE TO POSITION FOR THE LEADING BLANKS. + BARADD=13. ;AMOUNT TO ADD TO Y FOR UNDERLINE. + .PAGE +; +; +; MISC INFORMATION. +; ---- ------------ +; ALL VELOCITIES ARE SIGNED AND STORED IN TENTHS OF FEET PER SECOND. +; ALL ACCELERATIONS ARE 500 TIMES ACTUAL. +; THE HORIZONTAL AND VERTICAL DISTANCE IS IN FEET (SIGNED). +; THE FUEL IS IN TENTHS OF POUNDS. +; WEIGHT OF THE CRAFT IS IN POUNDS, AS IS THRUST. +; ORIENTATION OF THE SHIP IS STRICTLY COMPASS (I.E. +; ZERO DEGREES IS AT THE TOP, 90 TO THE RIGHT, ETC. +; M A I N D A T A A R E A . +; +TURN: .WORD 0 ;PRESENT RATE OF TURN AS SELECTED BY USER. +ANGLE: .WORD 0 ;ANGLE CURRENTLY BEING USED FOR TRIG CALCULATIONS. +ANGLER: .WORD 0 ;REMAINDER OF ANGLE FOR TURNING. +SINANG: .WORD 0 ;SINE OF THAT ANGLE +COSANG: .WORD 0 ;COSINE OF THAT ANGLE. +ACCEL: .WORD 0 ;CURRENT ACCEL OF SHIP CAUSED BY ROCKET. +HORACC: .WORD 0 ;CURRENT HORIZONTAL ACCELERATION. +VERACC: .WORD 0 ;CURRENT VERTICAL ACCELERATION (INCLUDING G). +HORVEL: .WORD 0 ;CURRENT HORIZONTAL VELOCITY> +HORREM: .WORD 0 ;REMAINDER OF HORIZONTAL VELOCITY AFTER DIVIDING. +VERVEL: .WORD 0 ;CURRENT VERTICAL VELOCTIY. +VERREM: .WORD 0 ;REMAINDER OF VERTICAL VELOCITY AFTER DIVIDING. +HORDIS: .WORD 0 ;CURRENT HORIZONTAL DISTANCE. +VERDIS: .WORD 0 ;CURRENT VERTICAL DISTANCE. +PERCNT: .WORD 0 ;% OF THRUST FROM LIGHT BAR. +OLDPER: .WORD 0 ;PREVIOUS % TO SAVE USELESS DISPLAY CALCULATION. +PERTRS: .WORD 0 ;% THRUST THE USER IS REQUESTING. +THRUST: .WORD 0 ;ACTUAL THRUST DELIVERED. +FUEL: .WORD 0 ;TENTHS OF # OF LBS (EARTH) OF FUEL REMIANING. +WEIGHT: .WORD 0 ;CURRENT EARTH WEIGHT OF SHIP. +TICKS: .WORD 0 ;# OF TICKS. MOVED OVER TO CLOCK. +CLOCK: .WORD 0 ;# OF CLOCK TICKS SINCE LAST CALCULATION. +TIME: .WORD 0 ;ACCUMULATION OF "CLOCK". I.E. TOD. +BIGXCT: .WORD 0 ;PRESENT POSITION OF SHIP (X RASTOR). +LEFTED: .WORD 0 ;LEFT EDGE OF SCREEN FOR CLOSEUP WORK (DELTA X). +LEFEET: .WORD 0 ;DISTANCE FROM LANDING THAT LEFTEDGE IS DURING CLOSEUP. +INDEXL: .WORD 0 ;INDEX FOR FEATURE JUST TO LEFT OF SHIP. +AVERT: .WORD 0 ;AVERAGE RASTOR HEIGHT OF TERAIN. +AVERY: .WORD 0 ;AVERAGE Y HEIGHT OF THE TERRAIN. +RADARY: .WORD 0 ;AVERAGE RADAR HEIGHT ABOVE THE TERRAIN. +LASTX: .WORD 0 ;USED TO KEEP TRACK OF WHERE DRAW WAS WORKING. +LASTY: .WORD 0 ;SAME FOR Y. +LOWY: .WORD 0 ;LOWER LIMIT TO SHOW INVISIBLE VECTOR. +LOWEST: .WORD 0 ;LOWEST Y COORDINATE OF PRESENT SCREEN FIGURE. +SAVEY: .WORD 0 ;LOWEST Y OF LAST DRAWN SHIP. +FRAND: .WORD 0 ;RANDOMIZER WORD FOR ROCKET FLICKER. +FSHIFT: .WORD 0 ;X SHIFTER FOR FLAME. +FINT: .WORD 0 ;INTENSITY OF FLAME. +FLINE: .WORD 0 ;LINE TYPE FOR FLAME. +SHIPTP: .WORD 0 ;FLIP-FLOP TO DETERMINE WHICH BUFFER + ;THE USER IS DISPLAYING SHIP FROM. +DNUM: .WORD 0 ;CURRENT PICTURE WE ARE DISPALYING. +DSTACK: .WORD STACKD ;CURRENT DISPLAY STACK POINTER. +LPFLG1: .WORD 0 ;CURRENT ADDRESS OF VALUE TO BE DISPLAYED. +OLDHIT: .WORD 0 ;PREVIOUS LIGHT PEN ADDRESS COUNTER TO +HITCNT: .WORD 0 ;AVOID SPURIOUS HITS. +MOON: .WORD . ;CURRENT STATUS OF PICTURE OF MOON. +DRAWCT: .WORD 0 ;COUNTER FOR DRAWING THE MOON. +DRAWTY: .WORD 0 ;LOCAL COUNTER FOR CHANGING THE INTENSITY OF +DRAWTZ: .WORD 0 ;THE SURFACE OF THE MOON. +DINT: .WORD 0 +DTYPE: .WORD 0 +DFUDGE: .WORD 0 ;ADDITIONAL MOON FUDGING FOR CLOSEUP. +XTYPE: .WORD 0 ;THIS IS THE RANDOMIZING WORD FOR +RADIUS: .WORD 0 ;THE EXPLOSION, AND THE BLAST RADIUS. +DUSTX: .WORD . ;A RANDOM WORD FOR GENERATING DUST. + .=.+40 ; -- RESERVE 40 OCTAL WORDS FOR STACK +STACKD: ;MAKE SURE THAT THERE IS ENOUGH SPACE FOR IT. + .PAGE +; C O D E +; - - - - +; START OF THE SYSTEM. +START: RESET ; DO A FEW HEAVY RESETS + RESET +; +; INSTALL THE NEW VECTORS +; + MOV #POWERF,24 ; PWR FAIL VECTOR + MOV #340,26 + MOV #KBDINT,60 ; KEYBOARD + MOV #340,62 + MOV #TIMER,100 ; LINE CLOCK + MOV #300,102 + MOV #DISPLY,320 ; VT-11 + MOV #200,322 + MOV #LIGHT,324 + MOV #200,326 + MOV #DBUSE,330 + MOV #340,332 +; +; DISPLAY THE STARTING MESSAGE (ONCE) +; + MOV #STACK,SP + MOV #STARTM,DPC + MOV #100,177560 ; ENABLE KBD INTERRUPTS + MOV #100,LKS ; ENABLE LINE CLOCK + JSR PC,DELAY ; WAIT 10 SECS AND GET STARTED + .WORD 10. +; +; ONCE STARTED, ALL RESTARTS OCCUR HERE +; +RESTAR: MOV #MOONST,IN1 ;NOW SET THE MOON AREA TO ALL DISTOP'S + MOV #MOONEN,IN2 ;FOLLOWED BY A ZERO. GET LOC TO GET COUNT. + SUB IN1,IN2 ;AND GET # OF BYTES. + ASR IN2 ;GET NUMBER OF WORDS TO CLEAR. + ASR IN2 ;GET NUMBER OF DOUBLE WORDS TO CLEAR. +RESTL1: MOV #DISTOP,(IN1)+ ;PUT IN THE DISPLAY STOP INSTRUCTIONS NOW. + CLR (IN1)+ + DEC IN2 + BGT RESTL1 ;AND LOOP TILL DONE. + CLR STATUS ;CLEAR CPU STUFF. + MOV #STACK,SP ;SET UP THE STACK POINTER NOW. + MOV #INIT,IN1 ;INITIALIZE THE SYSTEM NOW. +STARTL: MOV (IN1)+,IN2 ;PICK UP NEXT COMMAND. + BEQ IDLE ;ZERO. ALL DONE. + MOV (IN1)+,(IN2) ;DO COMMAND NOW. + BR STARTL ;AND LOOP FOREVER. +; +; THIS IS THE MAIN WAIT POINT. IT IS +; ACTIVATED IN THE NORMAL RUNNING MODE. +; SUBROUTINE "EIDLE" CAN BE CALLED WHEN +; IT IS TIME TO BLAST OFF FROM THE MOON +; AFTER GETTING A HAMBURGER. +; +IDLE: JSR PC,EIDLE ;WAIT FOR AN EVENT. + BR IDLE ;AND LOOP FOREVER. +EIDLE: WAIT ;WAIT FOR AN INTERUPT TO OCCUR. +1$: CMP TICKS,#5 ;WAIT FOR CLOCK ON THE 40AND 45 + BLT 1$ + MOV TICKS,IN1 ;PICK UP THE NUMBER OF CLOCK TICKS NOW. + BEQ EXIDLE ;IF NONE, JUST EXIT. + CLR TICKS ;ELSE RESET THE LITTLE TICK COUNTER. + MOV IN1,CLOCK ;AND THEN PUT THE # OF TICKS AWAY FOR CALCULATIONS. + JSR PC,SHOWSP ;DO CALCULATIONS. +EXIDLE: RTS PC ;AND THEN RETURN TO CALLER. + .PAGE +; +; THE INITIALIZATION CRAP. +; +INIT: .WORD TURN,-1. + .WORD ANGLE,-70. + .WORD ANGLER,0 + .WORD HORREM,0 + .WORD VERREM,0 + .WORD HORVEL,10000. + .WORD VERVEL,-5000. + .WORD HORDIS,-22000. + .WORD VERDIS,23000. + .WORD PERCNT,75. + .WORD LPBARY,BARFDG+150. + .WORD OLDPER,-1. + .WORD FUEL,FUELS + .WORD TIME,0 + .WORD CLOCK,0 + .WORD TICKS,0 + .WORD LOWY,0 + .WORD DNUM,0 + .WORD DSTACK,STACKD + .WORD STACKD,DTOP + .WORD LPFLG1,0 + .WORD MOON,. + .WORD DPC,ITEME1 + .WORD LKS,100 + .WORD FSUBC,0 + .WORD SHIPDP,0 + .WORD MOONGO,0 + .WORD SYSMES,0 + .WORD DUSTON,0 + .WORD DIALTB,ITEME1 + .WORD DIALTB+2,ITEME3 + .WORD DIALTB+4,ITEME8 + .WORD DIALTB+6,ITEME9 + .WORD ITEME1+2,117560 + .WORD ITEME2+2,117560 + .WORD ITEME3+2,117560 + .WORD ITEME4+2,117560 + .WORD ITEME5+2,117560 + .WORD ITEME6+2,117560 + .WORD ITEME7+2,117560 + .WORD ITEME8+2,117560 + .WORD ITEME9+2,117560 + .WORD ITEMET+2,117560 + .WORD ITEMEE+2,117560 + .WORD ITEMES+2,117560 + .WORD OLDHIT,. + .WORD HITCNT,10. + .WORD LPSW,DISTOP + .WORD 0 + .PAGE +; +; GO HERE IF THERE IS ANY ACTION FROM THE KEYBOARD +; +KBDINT: RESET + RTI + .PAGE +; +; POWER FAIL ROUTINES HERE. +; +POWERF: MOV #STACKD,DSTACK ;SET UP ALL THE STACKS NOW. + MOV #DTOP,STACKD + CLR DNUM + MOV #ITEME1,DPC ;THE DISPLAY IS GOING NOW. + MOV #100,LKS ;SO IS THE CLOCK. + MOV #STACK,SP ;NOW SO IS THE PROGRAM. + CLR STATUS + JMP IDLE ;AND REENTER. +; +; DISPLAY BUS ERROR ROUTINES. +; +DBUSE: CLR DNUM ;RECYCLE DISPLAY TO THE TOP OF THE LIST. + MOV IN1,-(SP) ;MAKE IT LOOK LIKE A NORMAL INTERUPT. + MOV IN2,-(SP) + MOV #DITEM1,IN2 + JMP DTOPOK ;AND REENTER IT NOW. + .PAGE +; +; THIS ROUTINE WILL DRAW THE SHIP RELATIVE TO IT'S CENTER. +; THE ANGLES HAVE ALREADY BEEN GOTTEN FROM SOMEWHERE +; ELSE AND HAVE BEEN LEFT IN COSANG AND SINANG. IN ADDITION, +; IN1 POINTS TO THE COMMANDS ON HOW TO DRAW THE SHIP, AND IN2 +; POINTS TO WHERE TO LEAVE THEM. +; COMMAND LIST OF THE THE FORM: +; "ADDRESS OF ROUTINE" +; "EXTRA DATA, IF NEEDED". +; IF IT'S A DATA POINT TO BE ROTATED, THEN THE NEXT WORD +; HAS THE X AND Y VALUES AS SEPARATE BYTES. THE X VALUE +; IS THE BYTE ON THE RIGHT....... REMEMBER THAT. +; +DRAW: MOV IN1,TEMP ;MOVE OVER THE INPUT LIST POINTER. + MOV IN2,TEMP2 ;AND THE OUTPUT LIST POINTER. + CLR LASTX ;SET TO CENTER OF OBJECT. + CLR LASTY + MOV #77777,LOWEST ;SET UP LOWEST POINT WE HAVE DRAWN SO FAR. +DRAWLP: MOV (TEMP)+,PC ;GO TO FIRST INSTRUCTION. +DRAWIS: CLR -(SP) ;DRAW INVISIBLE SHORT. + JSR PC,DRAWRT ;ROTATE NEXT SET OF POINTS. + BR DRAWSC ;AND THEN INSERT THEM INTO LIST. +DRAWVS: MOV #40000,-(SP) ;DRAW VISIBLE SHORT. + JSR PC,DRAWRT ;ROTATE RETURNS X IN RET1, Y IN RET2. + CMP LASTY,LOWY ;SEE IF THIS LINE SHOULD BE DRAWN. + BGE DRAWV1 ;YEP. + CLR (SP) ;NOPE. CLEAR OUT DISPLAY BIT. + BR DRAWSC +DRAWV1: CMP RET2,LOWY ;CHECK OTHER END NOW. + BGE DRAWSC ;IT'S ALSO OK. + CLR (SP) ;ELSE CLEAR THE DISPLAY BIT. +DRAWSC: MOV RET1,IN1 ;MOVE OVER X. + SUB LASTX,RET1 ;FIGURE OUT DELTA X. + BPL DRAWS1 ;IF POSITIVE, OK. ELSE + NEG RET1 ;REVERSE SIGN AND SET MINUS BITS. + BIS #20000,(SP) ;IN THE NEW SHORT VECTOR COMMAND. +DRAWS1: BIC #-100,RET1 ;REMOVE STRAY BITS (IF ANY). + SWAB RET1 ;GET INTO CORRECT POSITION. + ROR RET1 + MOV IN1,LASTX ;AND FINALLY UPDATE THE NEW X POSITION. + MOV RET2,IN2 ;AND NOW DO SAME THING WITH THE Y. + SUB LASTY,RET2 + BPL DRAWS2 + NEG RET2 + BIS #100,(SP) +DRAWS2: BIC #-100,RET2 + MOV IN2,LASTY ;UPDATE THE NEW Y NOW. + CMP IN2,LOWEST ;SEE IF PRESENT Y IS LOWEST POINT ON SCREEN. + BGE DRAWNL ;NOT LOWEST. + MOV IN2,LOWEST ;IF LOWEST, REMEMBER IT. +DRAWNL: BIS RET1,RET2 ;NOW CREATE THE NEW INSTRUCTION. + BIS (SP)+,RET2 + MOV RET2,(TEMP2)+ ;AND STORE IT AWAY. + BR DRAWLP ;AND FINALLY LOOP AROUND AGAIN. +DRAWIN: MOV (TEMP)+,(TEMP2)+ ;THIS MOVES OVER ONE WORD. + BR DRAWLP +DRAWDN: MOV #DISTOP,(TEMP2)+ ;THIS TERMINATES THE PICTURE + CLR (TEMP2)+ ;AND WILL CAUSE THE SUBROUTINE TO EXIT. + RTS PC + .PAGE +; +; THIS ROTATES THE X AND Y BYTE. (TEMP) POINTS TO THE X. +; +DRAWRT: MOVB (TEMP)+,IN1 ;PICK UP THE X. + MOV SINANG,IN2 + JSR PC,TRGMUL ;MULTIPLY THEM. + MOV RET1,-(SP) ;AND SAVE X*SINANG. + MOVB (TEMP),IN1 ;PICK UP THE Y. + MOV COSANG,IN2 + JSR PC,TRGMUL ;MULTIPLY THEM OUT. + SUB RET1,(SP) ;X*SINANG-Y*COSANG (WE'LL REVERSE SIGNS LATER. + MOVB -1(TEMP),IN1 ;PICK UP THE X AGAIN. + MOV COSANG,IN2 + JSR PC,TRGMUL ;X*COSANG + MOV RET1,-(SP) + MOVB (TEMP)+,IN1 ;Y ONCE AGAIN. + MOV SINANG,IN2 + JSR PC,TRGMUL ;Y*SINE + ADD (SP)+,RET1 ;X*COS+Y*SIN + MOV (SP)+,RET2 ;X*SIN-Y*COS + NEG RET2 ;Y*COS-X*SIN + RTS PC ;AND EXIT NOW. + .PAGE +; +; THIS ROUTINE FIGURES OUT THE ACCELERATION OF THE SHIP AND +; THE AMOUNT OF FUEL REMAINING. +; +ROCKET: TST FUEL ;SEE HOW MUCH FUEL WE HAVE ON BOARD NOW. + BEQ ROCKOFF ;NONE. TURN OFF THE ENGINE. + MOV PERTRS,IN1 ;PICK UP THE PERCENT THROTTLE NOW. + MOV #MAXTRS,IN2 ;GET THE MAXIMUM THRUST NOW. + JSR PC,MULTWO ;GET PER CENT * MAXTHRUST. + MOV #100.,IN1 ;GET %*MAXIMUM THRUST /100. + JSR PC,DIVTWO + MOV RET2,THRUST ;SAVE IT AWAY NOW. + MOV RET2,IN2 + MOV CLOCK,IN1 ;PICK UP NUMBER OF CLOCK TICKS. + JSR PC,MULTWO + MOV #CLKFDG,IN1 ;PICK UP FREQUENCY*25. + JSR PC,DIVTWO ;APPROX. 250LBS FUEL PER LB THRUST. + SUB FUEL,RET2 ;NOW SUBTRACT OFF REMAINING FUEL. + BMI FUELOK ;IF NEGATIVE, THEN THE FUEL IS OK. + CLR RET2 ;ELSE MAKE SURE TOTAL IS ZERO. + MOV #DISTOP,LPSW ;STOP THE LOW FUEL MESSAGE NOW. + BR FUELKO ;HE'S GOT NONE LEFT. +FUELOK: NEG RET2 ;GET FUEL LEFT + TST LPSW ;SEE IF FUEL IS ALREADY LOW. + BEQ FUELKO ;IT IS. + CMP RET2,#2000. ;SEE IF UNDER 200 POUNDS. + BGE FUELKO ;NO. STILL OK. + CLR LPSW ;ELSE CLEAR THE SWITCH NOW. + BIS #0,DSR ;AND RING THE BELL +FUELKO: MOV RET2,FUEL ;AND SAVE IT AWAY. + CLR RET1 ;NOW DIVIDE BY 10 TO CONVERT + MOV #10.,IN1 ;TENTHS OF POUNDS TO POUNDS. + JSR PC,DIVTWO ;DO DIVISION NOW. + ADD #EMPTY,RET2 ;ADD IN EMPTY WEIGHT OF SHIP. + MOV RET2,WEIGHT ;AND SAVE AWAY NOW. + MOV THRUST,IN1 ;FIGURE OUT ACCELERATION NOW. + MOV #G1,IN2 + JSR PC,MULTWO + MOV TEMP,IN1 ;NOW DIVIDE BY WEIGHT. + JSR PC,DIVTWO + MOV RET2,ACCEL ;AND SAVE THIS AWAY. A=TRS*G/W + MOV RET2,IN1 + MOV SINANG,IN2 ;GET HORIZONTAL ACCELERATION. + JSR PC,TRGMUL + MOV RET1,HORACC + MOV ACCEL,IN1 ;AND GET THE VERTICAL ACCELERATION. + MOV COSANG,IN2 + JSR PC,TRGMUL + SUB #G2,RET1 ;DON'T FORGET ABOUT THE LUNAR GRAVITY. + MOV RET1,VERACC + RTS PC ;AND RETURN NOW. +ROCKOF: MOV #DISTOP,LPSW ;TURN OFF LOW FUEL MESSAGE WHEN OUT. + CLR THRUST ;IF ROCKET IS OFF, TURN OFF THRUST. + MOV #EMPTY,WEIGHT ;UPDATE WEIGHT OF THE ROCKET NOW. + ADD FUEL,WEIGHT + CLR ACCEL ;CLEAR THE ROCKET'S ACCELERATION'S NOW. + CLR HORACC + MOV #-G2,VERACC ;SET ROCKET TO FREE FALL. + RTS PC ;AND RETURN NOW. + .PAGE +; +; THIS ROUTINE WILL DRAW THE THRUST OF THE ROCKET, BASED ON +; THE AMOUNT OF FUEL THAT IS BEING CONSUMED. +; +FLAME: MOV IN1,IN2 ;MOVE OVER WHERE TO LEAVE FLAME. + MOV PERTRS,TEMP ;PICK UP THE PERCENTAGE THRUST NOW. + ASR TEMP ;DIVDE BY EIGHT FOR THE TABLE LOOKUP. + ASR TEMP + ASR TEMP + MOVB YTHRST(TEMP),RET1 ;PICK UP THE Y LENGTH. + INC FRAND ;INCREMENT TO NEXT FLAME DIS@PLACEMENT. + MOV FRAND,RET2 + BIC #-40,RET2 ;JUST THIRTY TWO VALUES POSSIBLE. + MOVB YUPDWN(RET2),RET2 ;PICK UP FLAME DISPLACEMENT. + ADD RET2,RET1 ;ADD THEM TOGETHER. + ADD RET1,FSHIFT ;FIX UP HORIZONTAL FLICKER NOW. + MOV FSHIFT,RET2 + BIC #-4,RET2 ;JUST 0 TO 3. + MOV #FLEN,TEMP ;PICK UP #OF POINTS TO DO. + MOV #FLAMXS,TEMP2 ;PICK UP POINTER TO WHERE TO INSERT. + ADD #FLAMBT,RET2 ;LET RET2 POINT TO THE BYTE X TABLE. +FLAMLP: MOVB (RET2)+,(TEMP2)+ ;INSERT X VALUE NOW. + MOVB RET1,(TEMP2)+ ;INSERT THE Y VALUE. + ADD #6,TEMP2 ;UPDATE PAST COMMANDS. + DEC TEMP ;AND LOOP TILL DONE. + BGT FLAMLP + INC FLINE ;INCREMENT THE LINE TYPE NOW. + BIC #-4,FLINE + ADD #600,FINT ;AND THE INTENSITY NOW. + BIC #176177,FINT ;AND MAKE JUST SEVEN BITS. + MOV #106124,FLAMEX ;SET UP PROTOTYPE COMMAND. + BIS FLINE,FLAMEX ;AND MOVE OVER THE DATA. + BIS FINT,FLAMEX + MOV #FLAMDO,IN1 ;FINALLY SET UP THE POINTER. + JMP DRAW ;AND DRAW THE FIGURE, AND RETURN + .PAGE +; +; THIS ROUTINE GETS THE SINE AND COSINE FROM THE TABLES. +; +TRIG: MOV ANGLE,IN1 ;PICK UP THE ANGLE NOW. + BPL TRIG2 ;POSITIVE. SEE IF >180. +TRIG1: CMP IN1,#-180. ;NEGATIVE. SEE IF BELOW -180. + BGT TRIG3 ;>-180. IT'S OK. + ADD #360.,IN1 ;TOO SMALL. FUDGE IT AND LOOP. + BPL TRIG3 ;IF STILL NEGATIVE. ELSE IT'S OK. + BR TRIG1 +TRIG2: CMP IN1,#180. ;POSITIVE. SEE IF IT'S >180. + BLE TRIG3 ;NOPE. IT'S OK. + SUB #360.,IN1 ;DECREMENT BY ONE REVOLUTION + BMI TRIG2 ;AND LOOP IF IT'S STILL TO BIG. +TRIG3: MOV IN1,ANGLE ;AND NOW SAVE IT AWAY AGAIN. + BPL TRIG4 ;CONVERT TO A GOOD COMPASS NOTATION. + ADD #360.,IN1 ;ELSE WRAP AROUND ONCE. +TRIG4: ASL IN1 ;SHIFT IT LEFT BECAUSE IT'S NECESSARY. + MOV SINTAB(IN1),SINANG ;NOW GET THE NECESSARY CONSTANTS. + CMP IN1,#540. ;SEE IF GREATER THEN 269 DEGREES. + BLT TRIG5 ;NO. IT'S ALRIGHT. + SUB #720.,IN1 ;TOO BIG. WRAP IT AROUND. +TRIG5: MOV COSTAB(IN1),COSANG ;NOW MOVE OVER THE COSINE. + RTS PC ;AND RETURN WHEN DONE. + .PAGE +; +; THIS ROUTINE FIGURES OUT WHERE THE SHIP IS IN RELATIONSHIP TO THE MOON. +; +WHERE: MOV HORACC,IN2 ;PICK UP THE X ACCEL. + BPL WH1 ;IF POSITIVE, FINE. + NEG IN2 ;ELSE NEGATE IT FOR A SECOND. +WH1: MOV CLOCK,IN1 ;PICK UP ELAPSED TIME NOW. + JSR PC,MULTWO ;MULTIPLY THEM TOGETHER. + MOV #CLKFG2,IN1 ;PICK UP TIMER FUDGE. + JSR PC,DIVTWO ;AND DIVIDE IT OUT NOW. + TST HORACC ;GET ORIGINAL SIGN OF X. + BPL WH2 + NEG RET2 +WH2: MOV RET2,RET1 ;MOVE OVER A*T + ASR RET2 ;GET .5*A*T + ADD HORVEL,RET2 ;GET V0+.5*A*T + ADD RET1,HORVEL ;UPDATE THE HORIZONTAL VELOCITY NOW. + MOV RET2,-(SP) ;SAVE SIGN OF VELOCITY FOR TEST LATER. + MOV RET2,IN2 ;VEL IN FPS*10 + BPL WH3 + NEG IN2 +WH3: MOV CLOCK,IN1 ;NOW GET THE DISTANCE COVERED. + JSR PC,MULTWO + MOV #CLKFG3,IN1 + ADD HORREM,RET2 ;BRING BACK THE REMAINDER FROM PREVIOUS OPERATIONS. + ADC RET1 ;AND DON'T FORGET THE CARRY. + JSR PC,DIVTWO ;ACTUAL DISTANCE COVERED. + TST (SP)+ ;RECALL OLD SIGN OF VELOCITY. + BPL WH4 + NEG RET2 +WH4: ADD RET2,HORDIS ;UPDATE THE DISTANCE NOW. + MOV RET1,HORREM ;AND SAVE THE REMAINDER NOW. + MOV VERACC,IN2 ;NOW DO THE UP AND DOWN PART. + BPL WH5 ;SAME SORT OF CRAP FOR THE Y. + NEG IN2 +WH5: MOV CLOCK,IN1 + JSR PC,MULTWO + MOV #CLKFG2,IN1 + JSR PC,DIVTWO + TST VERACC + BPL WH6 + NEG RET2 +WH6: MOV RET2,RET1 + ASR RET2 + ADD VERVEL,RET2 + ADD RET1,VERVEL + MOV RET2,-(SP) ;SAVE SIGN FOR LATER USE. + MOV RET2,IN2 + BPL WH7 + NEG IN2 +WH7: MOV CLOCK,IN1 + JSR PC,MULTWO + MOV #CLKFG3,IN1 + ADD VERREM,RET2 ;ADD IN PREVIOUS REMAINDER NOW. + ADC RET1 ;AND FIDDLE IT ACCROSS. + JSR PC,DIVTWO + TST (SP)+ + BPL WH8 + NEG RET2 +WH8: ADD RET2,VERDIS + MOV RET1,VERREM ;AND SAVE THE REMAINDER NOW. + RTS PC + .PAGE +; +; THIS SECTION WILL FIGURE OUT THE POSITION OF THE +; LUNAR MODULE AND WHICH VEIW TO USE. +; +SHOWSP: MOV #-64.,LOWY ;SET UP ABORT LIMIT OUT OF RANGE. + MOV TURN,TEMP2 ;PICK UP THE RATE OF TURN. + CLR TURN ;AND TURN IT OFF NOW. + MOV CLOCK,IN1 ;PICK UP THE NUMBER OF CLOCK TICKS. + MOV TEMP2,IN2 ;AND MOVE OVER THE RATE OF TURN. + BPL SHOWP1 ;IF POSITIVE, THEN OK, + NEG IN2 ;ELSE NEGATE IT. +SHOWP1: JSR PC,MULTWO ;MULTIPLY THEM TOGETHER. + MOV #CLKFRQ,IN1 ;AND THEN GET ACTUAL # OF DEGREES OF TURN. + ADD ANGLER,RET2 ;DON'T FORGET TO ADD IN THE REMAINDER NOW. + ADC RET1 ;AND THE CARRY, ALSO. + JSR PC,DIVTWO + TST TEMP2 ;AND FINALLY SET TO THE CORRECT SIGN. + BPL SHOWP2 + NEG RET2 +SHOWP2: ADD RET2,ANGLE ;UPDATE THE ANGLE NOW. + MOV RET1,ANGLER ;SAVE THE REMAINDER NOW. + JSR PC,TRIG ;AND GET NEW SINES AND COSINES. + ADD #2,SHIPTP ;GET WHICH SHIP'S + MOV SHIPTP,IN2 ;BUFFER TO USE. + BIC #-3,IN2 ;SO WE HAVE NO PROBLEMS. + MOV SHIPLC(IN2),IN2 ;AND SET UP CALL. + MOV #DESIGN,IN1 ;SET UP SHIP'S DESIGN. + MOV IN2,-(SP) ;REMEMBER THE BUFFER FOR LATER USE. + JSR PC,DRAW ;AND DRAW IT NOW. + MOV (SP)+,SHIPDP ;AND FINALLY MOVE OVER BUFFER POINTER TO CALL. + MOV LOWEST,SAVEY ;AND FINALLY SAVE THE LOWEST Y DRAWN. +SHOWNT: MOV PERCNT,PERTRS ;PICK UP THE PRESENT FUEL SETTING. + JSR PC,ROCKET ;FIGURE OUT ROCKET COMPONENTS. + JSR PC,WHERE ;AND NOW FIGURE OUT WHERE WE ARE ON MOON. + MOV HORDIS,TEMP ;PICK UP X IN FEET. + ADD #22400.,TEMP ;FUDGE UP DOWNRANGE CALCULATION. + ASR TEMP ;32 FEET PER RASTOR ON BIG SCALE. + ASR TEMP + ASR TEMP + ASR TEMP + ASR TEMP + MOV TEMP,BIGXCT ;AND SAVE AWAY FOR LATER USE. + MOV TEMP,TEMP2 + ASL TEMP ;NOW GET THE CURRENT RADAR HEIGHT. + ADD #TERAIN,TEMP + MOV (TEMP)+,IN1 ;LEFT TERAIN. + ADD (TEMP),IN1 ;RIGHT TERAIN. + ASR IN1 ;AVERAGE IT OUT. + MOV IN1,AVERY ;AND SAVE IT AWAY. + SUB VERDIS,IN1 ;AND NOW GET THE RADAR HEIGHT. + NEG IN1 + MOV IN1,RADARY ;RADAR HEIGHT IS NOW CALCULATED. + TST THRUST ;NOW SEE ABOUT THE ROCKET FLAME. + BLE NOFLAM ;NO THRUST=NO FLAME. + MOV #FLAMIN,IN1 ;THIS IS WHERE TO LEAVE THE FLAME. + JSR PC,FLAME ;GO DRAW THE FLAME NOW. + MOV #FLAMIN,FSUBC ;AND TURN ON THE FLAME AGAIN. + BR YSFLAM ;AND LEAVE FLAME ON. +NOFLAM: CLR FSUBC ;IF NO THRUST, TURN OF ROCKET. +YSFLAM: MOV BIGXCT,TEMP ;PICK UP X POSITION NOW. + BMI OFFLFT ;WE'RE OFF TO THE LEFT. + CMP TEMP,#10. + BLE OFFLFT ;WE ARE STILL OFF TO THE LEFT. + CMP TEMP,#890. + BGE OFFRGT ;SEE IF WE ARE TOO FAR TO THE RIGHT. + MOV VERDIS,TEMP ;WE SEEM TO BE OK. HOW ABOUT HEIGHT. + BMI CLSEUP ;IF MINUS, GO INTO CLOSEUP MODE. + CMP TEMP,#25000. ;IF OFF TOP, GIVE MESSAGE. + BGE OFFTOP + CMP TEMP,#450. ;SEE IF WE SHOULD MAGNIFY. + BLE CLSEUP ;YES. MAGNIFY. + MOV BIGXCT,SHOWX ;ELSE ESTABLISH THE Y COORDINATE. + ASR TEMP ;NOW SCALE DOWN THE VERTICAL DISTANCE. + ASR TEMP + ASR TEMP + ASR TEMP + ASR TEMP ;32 FEET PER RASTOR AT THIS RANGE. + ADD #43.,TEMP ;UPDATE + MOV TEMP,SHOWY + TST MOON ;IS MOON DRAWN. + BEQ SHWMN1 ;YES. + JSR PC,DRAWM1 ;NO. + CLR MOON ;RESET FLAG. +SHWMN1: JSR PC,DIAL ;DISPLAY THE DIALS NOW. + MOV RADARY,TEMP + SUB #16.,TEMP ;FIX FOR CENTER OF THE SHIP. + BPL SHWOUT ;IT'S OK. + MOV #640.,IN1 ;NOT OK. WE'VE CRASHED. BIG DISTORTION. + JSR PC,ALTER ;ALTER MOON NOW. + MOV SP,MOON ;INDICATE THAT WE'VE ALTERED THE MOON. + JSR PC,DRAWM1 ;NOW REDRAW IT. + CLR MOON ;AND REMEMBER THAT WE'VE REDRAWN IT. + JSR PC,EXPLOD ;GIVE AN EXPLOSION. +SHWOUT: RTS PC ;AND RETURN NOW. + .PAGE +; +; OFF SCREEN ROUTINES GO HERE...... +; +OFFLFT: MOV #13.,IN1 ;PICK UP A NEW X NOW. + MOV #LFTMSG,IN2 ;AND PICK UP A MESSAGE NOW. + BR OFFCOM ;AND DO THE COMMON ROUTINES NOW. +OFFRGT: MOV #887.,IN1 ;A RIGHT X VALUE. + MOV #RGTMSG,IN2 + BR OFFCOM ;SAME CRAP. +OFFTOP: MOV TEMP,IN1 ;PRESENT X VALUE. + MOV #TOPMSG,IN2 ;TOP MESSAGE. +OFFCOM: ASL IN1 ;GET A NEW HORDISTANCE. + ASL IN1 + ASL IN1 + ASL IN1 + ASL IN1 + SUB #22400.,IN1 + MOV IN1,HORDIS ;SET DISTANCE. + MOV IN2,SYSMES ;SET MESSAGE NOW. + CLR FUEL ;TURN OFF FUEL NOW. + CLR HORVEL ;CLEAR SIDEWAYS MOTION. + MOV VERDIS,RET2 ;PICK UP VERTICAL DISTANCE NOW. + ASR RET2 ;DIVIDE BY 4 TO GET A REASONALBE SPEED. + ASR RET2 + BMI OFFCMD ;IF GOING DOWN, WE ARE OK. + NEG RET2 ;ELSE MAKE US GO DOWN. +OFFCMD: MOV RET2,VERVEL ;AND SAVE IT AWAY NOW. + JMP SHOWSP ;AND RELOOP AND REDISPLAY SHIP NOW. + .PAGE +; +; THIS ROUTINE WILL DRAW THE CLOSEUP PICTURES OF +; THE MOON, WHEN THEY BECOME NECESSARY. RETURN GOES +; BACK TO IDLE VIA THE OLD PC ON THE STACK +; . +; +CLSEUP: CMP MOON,(SP) ;SEE IF WE HAVE THE MOON IN SIGHT. + BEQ CLSEC1 ;YES. + MOV BIGXCT,IN1 ;NO. GET CURRENT RASTOR POSITION. + SUB #9.,IN1 ;NOW SET A GOOD LEFT EDGE. +CLSEFG: MOV IN1,LEFTEDGE ;LEFT EDGE ESTABLISHED NOW. + ASL IN1 ;NOW CONVERT EDGE TO FEET. + ASL IN1 + ASL IN1 + ASL IN1 + ASL IN1 + SUB #22400.,IN1 + MOV IN1,LEFEET ;AND SAVE THAT AWAY. + JSR PC,DRAWM2 ;DRAW A CLOSE-UP OF THE MOON NOW. + MOV (SP),MOON ;SET FLAG TO INDICATE WE HAVE DONE SO. + MOV HORDIS,IN1 ;PICK UP THE HORIZONTAL POSITION NOW. + SUB LEFEET,IN1 ;GET FEET FROM LEFT EDGE OF SCREEN. +CLSEOK: MOV IN1,RET2 ;NOW GET RASTOR POSITION (3/2) + ASL IN1 + ADD IN1,RET2 + ASR RET2 ;(3/2) OF FEET=RASTOR + MOV RET2,SHOWX ;AND SAVE IT AWAY NOW. + CLR RET1 ;NOW CONVERT THIS POSITION TO A GOOD. + MOV #48.,IN1 ;NOW CONVERT BACK TO A TERAIN INDEX. + JSR PC,DIVTWO ;DO THE DIVISION NOW. + ADD LEFTEDGE,RET2 ;MAKE INTO A TERAIN AND FEATURE INDEX. + MOV RET2,INDEXL ;SAVE AWAY INDEX TO LEFT POSTION OF SHIP. + ASL RET2 ;MULTIPLY BY TWO FOR THE TERAIN. + MOV RET2,TEMP ;SAVE IT FOR A SECOND. + MOV #48.,IN1 ;NOW FIGURE OUT HOW MUCH SHIP IS TO LEFT + SUB RET1,IN1 ;OR RIGHT OF CENTER OF TERAIN. USE DIVISION REMAINDER. + MOV RET1,TEMP2 ;SAVE THAT AWAY. + MOV TERAIN(TEMP),IN2 ;PICK UP TERAIN NOW. + JSR PC,SGNMUL ;MULTIPLY IT OUT NOW. + MOV RET2,-(SP) ;SAVE FOR A SECOND NOW. + MOV TEMP2,IN1 ;RECALL REMAINDER NOW. DO RIGHT EDGE OF "TERRAIN". + MOV TERAIN+2(TEMP),IN2 ;OTHER HEIGHT. + JSR PC,SGNMUL ;MULTIPLY THEM OUT. + CLR RET1 ;NOW SET UP DIVIDE. THIS WILL CONVERT + MOV #48.,IN1 ;TERAIN HEIGHT*48 TO DISPLAY FUDGED HEIGHT. + ADD (SP)+,RET2 ;OLD FUDGED WEIGHTED HEIGHT. + BPL CLSEF1 ;AVERAGE IS POSITIVE. + NEG RET2 ;AVERAGE IS NEGATIVE. + JSR PC,DIVTWO ;DO THE DIVIDE NOW. + NEG RET2 ;AND NEGATE THE ANSWER. + BR CLSEF2 +CLSEF1: JSR PC,DIVTWO +CLSEF2: MOV RET2,TEMP ;MOVE OVER HEIGHT FOR DFAKE TO USE. + ASR RET2 ;NOW CONTINUING FUDING TERRAIN BY KNOWN STANDARDS. + ASR RET2 + MOV RET2,AVERY ;SAVE AWAY AVERAGE TERAIN HEIGHT. + JSR PC,DFAKE ;GET ACTUAL RASTER HEIGHT ABOVE THE MOON. + MOV TEMP,AVERT ;SAVE IT AWAY NOW. + MOV VERDIS,IN1 ;PICK UP THE DISTANCE NOW. + MOV IN1,RET2 ;PREPARE TO CONVERT TO RASTORS. + ASL RET2 ; THE OLD 3/2 GAMBIT. + ADD IN1,RET2 + ASR RET2 + ADD #23.,RET2 ;TO CONVERT TO VIEWING RASTORS. + MOV RET2,SHOWY ;SAVE IT AWAY NOW. + ADD #24.,SHOWY ;EXCEPT FOR THE FUDGE. + SUB TEMP,RET2 ;GET # OF RASTORS TO GO. + MOV RET2,TEMP ;MOVE BACK OVER. + BPL CLSEF3 ;IF POSITIVE, ALL IS WELL. + NEG RET2 ;ELSE NEGATE IT NOW. +CLSEF3: CLR RET1 ;PREPARE TO DO THE DIVIDE. + MOV #3.,IN1 ;MAKE IT THREE HALFS. + ASL RET2 + JSR PC,DIVTWO + TST TEMP ;GET BACK THE ORIGINAL SIGN NOW. + BPL CLSEF4 + NEG RET2 +CLSEF4: MOV RET2,RADARY ;AND THIS IS THE RADAR HEIGHT. + JSR PC,INTEL ;FIGURE OUT IF ANYTHING GREAT IS TO HAPPEN. + JSR PC,DUST ;AND ALSO IF WE SHOULD SHOW DUST. +AHNONE: RTS PC ;AND WHEN DONE, RETURN NOW. +CLSEC1: MOV HORDIS,IN1 ;MOON ALREADY BEING DISPLAYED. + SUB LEFEET,IN1 ;SEE IF IT'S STILL ON THE SCREEN. + CMP IN1,#30. ;TO CLOSE TO LEFT? + BLE CLOL ;YES. SHIFT TO RIGHT. + CMP IN1,#580. ;TOO CLOSE TO LEFT + BLT CLSEOK ;NOPE. DISPLAY AS IS. + MOV BIGXCT,IN1 ;SHIFT EVERYTHING LEFT NOW. + DEC IN1 + BR CLSEFG ;SHOULD BE POIFECT. +CLOL: MOV BIGXCT,IN1 ;SHIFT EVERYTHING RIGHT IF TOO CLOSE TO THE LEFT. + SUB #17.,IN1 + BR CLSEFG ;FUDGE IT NOW. + .PAGE +; +; GENERAL INTELIGENCE SECTION... +; THIS CODE GOES HERE SO THAT IT MAY BE +; REFERENCED BY SIMPLE BRANCH INSTRUCTIONS +; FROM THE MAIN SECTION "INTEL". +; +AHMAC: TST #MACON ;OVER MACDONALD'S. SEE IF DRAWN. + .=.-2 ;DEFINE MACON AS BEING HERE. +MACON: .WORD 0 ;AND INITIALIZE IT TO ZERO. + BEQ AHNONE ;NO, NOT DRAWN. EXIT NOW. + CMP TEMP2,#30. ;YES. SEE HOW CLOSE WE ARE. + BGT AHNONE ;NOT TOO CLOSE. ALL IS WELL. + CLR #MACTHR ;TOO CLOSE. WE'VE CRASHED INTO IT. + .=.-2 ;AND LIKEWISE DEFINE THE MAC DESTROYED +MACTHR: .WORD MACTHR ;FLAG AS STILL HAVING MACDONALDS. + MOV #MACDED,SYSMES ;TELL HIM WE'VE CRASHED INTO IT. + JMP QUICK ;AND KILL HIM OFF. +AHROCK: CMP TEMP2,#15. ;ARE WE TOO LOW OVER THE ROCK? + BGT AHNONE ;NOPE. + CMP VERVEL,#-600. ;GREATER THAN CRASH SPEED? + BLE GODEAD ;YES. HE'S DEAD. + MOV #ROCKMS,SYSMES ;START DISPLAYING THE ROCK MESSAGE NOW. + CLR SHIPDP ;STOP DISPLAYING THE SHIP NOW. + JSR PC,EXPLOD ;EXPLOD NOW +AHSP1: CMP TEMP2,#26. ;TOO HIGH? + BGT AHNONE ;IT'S ALRIGHT. + CMP TEMP,#-600. ;TOO FAST. + BLE GODEAD + MOV #OLDMS,SYSMES ;DISPLAY THE OLD SHIP MESSAGE. + MOV #3,-(SP) ;SET UP A LEFT SHIP + TST HORVEL ;GET HORIZONTAL VELOCITY. + BMI AHSP1M ;DIRECTION OK. + INC (SP) ;MAKE IT RIGHT TILTING. +AHSP1M: MOV IN1,-(SP) ;PUSH THE INDEX ONTO THE STACK. + JSR PC,PUTFET ;PLACE IN FEATURE TABLE NOW. + SUB #16.,SHOWY ;BRING DOWN THE OLD SHIP. + JSR PC,DRAWM2 ;REDRAW THE MOON NOW. + JSR PC,EXPLOD ;EXPLOD THE SHIP NOW. +AHFLG: CMP TEMP2,#26. ;ARE WE TOO HIGH + BGT AHNONE ;YEP. + TST THRUST ;ENGINE ON? + BEQ AHNONE ;NOPE. EXIT. + CLR -(SP) ;CLEAR THE FLAG NOW. + MOV IN1,-(SP) + JSR PC,PUTFET ;CLEAR INDICATOR FLAG NOW. + MOV #FLAGMS,SYSMES ;GIVE THE FLAG MESSAGE NOW. + JSR PC,DRAWM2 ;REDRAW THE MOON NOW. + BR AHNONE ;AND CONTINUE CHECKING CRAP. +AHOLDS: CMP TEMP2,#17. ;SEE IF ON CRASHED SHIP. + BGT AHNONE ;NOPE. + CMP TEMP,#-600. ;SEE IF TOO FAST. +GODEAD: BLE DEAD ;ELSE DEAD. + MOV #OLDTLT,SYSMES ;GIVE MESSAGE. + JSR PC,EXPLOD ;AND EXPLOD NOW. + .PAGE +; +; ROUTINE WHICH FIGURES OUT WHAT TO DO NOW. +; +INTEL: JSR PC,DIAL ;DISPLAY USER'S DATA NOW. + MOV RADARY,TEMP2 ;PICK UP ALTITUDE NOW. + BMI INTELM ;IT'S NEGATIVE. FIGURE OUT SOMETHING SPECIAL. + CMP TEMP2,#3. ;ARE WE CLOSE. + BLE VERYLOW ;WE CERTAINLY ARE. + MOV VERVEL,TEMP ;NOT TOO LOW. GET VELOCITY NOW. + CMP TEMP,#-600. ;SEE IF <=60 FPS + BLT AHAH ;YES. IS HE SCREWED UP. + CMP TEMP,#-300. ;HOW ABOUT 30 FPS + BLT AHAH2 ;HE'S NOT TOO SCREWED UP + CMP TEMP,#-150. ;HOW ABOUT FIFTEEN FPS. + BLT AHAH3 ;GIVE ANOTHER MESSAGE. + CMP SYSMES,#N2FAST ;WAS A NOT TOO FAST MESSAGE THE + BNE AHAHC ;ONE ISSUED. NO. + CLR SYSMES ;YES. DELETE IT NOW. +AHAHC: MOV INDEXL,IN1 ;PICK UP FEATURE INDEX NOW. + MOV IN1,-(SP) ;PUSH DESIRED ITEM ONTO STACK. + JSR PC,GETFET ;GET THE FEATURE NOW. + MOV (SP)+,IN2 ;AND POP THE ITEM OFF THE STACK. + ASL IN2 ;MULTIPLY IT BY TWO. + JMP @AHTAB(IN2) ;WE'VE GOT IT NOW. +AHAH: MOV #VFAST,SYSMES ;GIVE A VERY FAST MESSAGE NOW. + BR AHAHC ;AND DO SOMETHING ELSE. +AHAH2: MOV #FAST,SYSMES ;GIVE A FAST MESSAGE. + BR AHAHC +AHAH3: MOV #N2FAST,SYSMES ;GIVE A "TAKE IT EASY MESSAGE". + BR AHAHC +INTELM: CMP TEMP2,#-10. + BLE DEAD ;TOO FAR DOWN. HE'S DEAD. +VERYLO: CLR PERCNT ;TURN OFF FUEL NOW. + MOV #BARBY,LPBARY ;AND INIDCATE IT TO HIM. + CLR FSUBC ;TERMINATE FLAMES. + CLR DUSTON ;AND THE DUST. + TST TEMP2 ;GET ALTITUDE NOW. + BEQ VD ;WE'RE DOWN. + BPL AHAHC ;IF POSITIVE, LOOK FOR FEATURES. +VD: MOV VERVEL,TEMP ;PICK UP THE VERTICAL VELOCITY NOW. + CMP TEMP,#-600. ;SEE IF GREATER THAN 60 FPS. + BLE DEAD ;YES. SPLAT + CMP TEMP,#-300. ;HOW ABOUT 30FPS + BLE CRIPPLED ;YES. HE'S CRIPLLED. + CMP TEMP,#-150. ;HOW ABOUT 15FPS + BLE ROUGH ;IT'S A ROUGH ONE. + CMP TEMP,#-80. ;HOW ABOUT 8FPS. + BLE GOOD ;IT'S A GOOD ONE. + MOV #GREATM,IN1 ;ISSUE GREAT MESSAGE + BR MAYBE ;AND NOW CHECK HORIZONTAL VELOCITY. +GOOD: MOV #GOODM,IN1 ;A GOOD LANDING. + BR MAYBE +ROUGH: MOV #ROUGHM,IN1 ;A ROUGH LANDING. + BR MAYBE +CRIPPL: MOV #CRIPM,IN1 ;CRIPPLED. GIVE THAT MESSAGE. + BR MAYBE +DEAD: MOV #DEADM,SYSMES ;ISSUE THE DEAD MESSAGE NOW. +QUICK: MOV #32.,IN1 ;ALTER THE SURFACE NOW. + JSR PC,ALTER + JSR PC,DRAWM2 ;REDRAW THE MOON NOW. + CLR SHIPDP ;STOP DISPLAYING THE SHIP. + JSR PC,EXPLOD ;EXPLOD NOW. +MAYBE: CLR FSUBC ;TURN OFF FLAME IMAGE NOW. + MOV IN1,SYSMES ;DISPLAY THE CALLER'S MESSAGE NOW. + CMP HORVEL,#100. ;SEE IF TOO FAST SIDEWAYS. + BGT MAYBEB ;TOO FAST. + CMP HORVEL,#-100. ;HOW ABOUT LEFT. + BLT MAYBEB ;TOO FAST. + CMP ANGLE,#-15. ;SEE IF THE ANGLE IS OK. + BLT MAYBEC ;TOO FAR LEFT. + CMP ANGLE,#15. ;RIGHT OK? + BGT MAYBEC ;YES. TIP HIM OVER. + MOV INDEXL,IN2 ;NOW FIGURE OUT IF TERAIN IS TOO ROUGH. + ASL IN2 + MOV TERAIN+2(IN2),IN1 ;RIGHT TERAIN. + SUB TERAIN(IN2),IN1 ;LEFT TERAIN. + MOV IN1,RET1 ;MOVE OVER FOR ABSOLUTE VALUE. + BPL MAYBEP ;TAKE ABSOLUTE VALUE NOW. + NEG RET1 +MAYBEP: CMP RET1,#48. ;SEE IF GREATER THAN A 48 FOOT DROP. + BGE MAYBED ;YES. A BADDY. + ;PLANT THE FLAG NOW!!!!!!! + ; . + JSR PC,PALSY ;WITH THE SPASTIC MAN. +MAYBEB: MOV HORVEL,IN1 ;PICK UP DIRECTION TO TIP SHIP. + MOV #SIDEM,IN2 ;PICK UP POINTER TO THE MESSAGE. + BR TILT ;AND TILT THE SHIP NOW. +MAYBEC: MOV ANGLE,IN1 ;GET THE DIRECTION TO TILT THE SHIP. + MOV #ANGLEM,IN2 ;AND PICK UP THE MESSAGE NOW. + BR TILT ;AND TILT IT NOW. +MAYBED: MOV #BUMPYM,IN2 ;PICK UP MESSAGE NOW. IN1=CORRECT SIGN. +TILT: MOV IN2,FSUBC ;DISPLAY MESSAGE FROM FLAME POINT. + MOV INDEXL,IN2 ;PICK UP TERAIN INDEX AGAIN. + MOV #3,-(SP) ;INDICATE IT'S TIPPED TO THE LEFT. + TST IN1 ;PICK UP DIRECTION AGAIN. + BMI TILT1 ;NO, MAKE IT TO THE RIGHT. + INC (SP) +TILT1: MOV IN2,-(SP) ;AND NOW UPDATE THE FEATURE TABLE. + JSR PC,PUTFET + ASL IN2 ;NOW GET TERAIN CHARACTERISTICS. + MOV TERAIN+2(IN2),RET1 ;RIGHT TERAIN. + SUB TERAIN(IN2),RET1 ;LEFT TERAIN. + MOV RET1,RET2 ;NOW WE'LL CONVERT FEET DIFFERENCE TO AN ANGLE. + ASL RET2 ;MULTIPLY IT BY 3 + ADD RET1,RET2 ;OK + ASR RET2 ;NOW DIVIDE BY FOUR. + ASR RET2 + SUB RET2,RET1 ;SUBTRACT FROM THE ORIGINAL. + MOV RET1,RET2 ;NOW HALF ANSWER AGAIN. + ASR RET2 + ADD RET2,RET1 ;AND ADD IN NEW ANSWER. RESULT + ;IS NUMBER OF DEGREES TO TILT. + BPL TILT2 ;NOW SEE IF RESULT IS GREATER THAN + CMP RET1,#-45. ;THE ABS(45). + BGE TILT3 ;IF OK, THEN LEAVE ALONE. + MOV #-45.,RET1 ;ELSE SET IT TO -45. + BR TILT3 +TILT2: CMP RET1,#45. ;SEE IF IT'S GREATER THAN 45 DEGREES. + BLE TILT3 ;NO, IT'S OK. + MOV #45.,RET1 ;ELSE FIX IT UP NOW. +TILT3: MOV #90.,RET2 ;PICK UP FALLEN SHIP ANGLE. + TST IN1 ;GET WHICH WAY TO FALL. + BPL TILT4 ;IT'S OK. + NEG RET2 ;NEGATE IT NOW. +TILT4: ADD RET2,RET1 ;GET THE NEW SHIP ANGLE NOW. + MOV RET1,ANGLE ;UPDATE SHIP ANGLE. + MOV SHIPTP,IN2 ;NOW TOGGLE SHIP SWITCH. + ADD #2,IN2 + BIC #-3,IN2 + MOV IN2,SHIPTP + MOV SHIPLC(IN2),IN2 ;PICK UP BUFER POINTER NOW. + MOV IN2,-(SP) ;AND SAVE IT AWAY FOR LATER USE. + JSR PC,TRIG ;GET THE SINE AND COSINE NOW. + MOV #DESIGN,IN1 ;HOW TO DRAW SHIP. + JSR PC,DRAW ;DRAW IT NOW. + MOV (SP)+,SHIPDP ;SHOW NEW SHIP NOW. + SUB #7.,SHOWY ;BUT BRING IT DOWN A LITTLE BIT. + JSR PC,DELAY ;DELAY FOR A WHILE + .WORD 10. + .PAGE +; +; THIS ROUTINE WILL KICK UP DUST ON THE MOON. +; +DUST: CMP RADARY,#150. ;SEE IF WE ARE CLOSE TO THE MOON NOW. + BGE NODUST ;DON'T GENERATE ANY DUST NOW. + MOV #EXLIST,TEMP2 ;PICK UP ADDRESS OF WHERE TO LEAVE DUST. + MOV PERTRS,TEMP ;GET THE TRUST NOW. + CMP TEMP,#63. ;SEE IF MORE THAN 63% + BLE DUSTB1 ;NO. OK. + MOV #63.,TEMP ;IF MORE, SET TO 63% FOR SCALING. +DUSTB1: ROL TEMP ;BECAUSE WE WILL USE MAGNITUDE TO + ROL TEMP ;CONTROL INTENSITY. + ROL TEMP ;MOVE OVER TO INTENSITY SPOT. + ROL TEMP + BIC #176177,TEMP ;CLEAR OUT ANY STRAY BITS NOW. + BIS #116120,TEMP ;NOW SET THE POSITIONING MASK. + MOV TEMP,(TEMP2)+ ;PLACE IN THE LIST NOW. + CMP ANGLE,#45. ;SEE IF THE ANGLE IS TOO GREAT NOW. + BGT NODUST ;YEP. + CMP ANGLE,#-45. + BLT NODUST ;SAME HERE. + MOV SINANG,IN2 ;NOW GET THE PLACE TO PUT THE DUST + BPL DUSTP1 ;BY FIGURING OUT THE TANGENT OF + NEG IN2 ;OF THE ANGLE. MAKE POSITIVE +DUSTP1: MOV SHOWY,IN1 ;SO DIVIDE WON'T BLOW. GET RASTOR Y NOW. + SUB AVERT,IN1 ;SUBTRACT OFF THE TERAIN HEIGHT NOW. + MOV IN1,TEMP ;SAVE FOR A SECOND. + JSR PC,MULTWO ;GET PRODUCT. + MOV COSANG,IN1 ;GET COSINE NOW. + JSR PC,DIVTWO ;RET2=TAN(ANGLE)*DELTAY + ADD RET2,TEMP ;TEMP=DELTAX+DELTAY=TOTAL FLAME DISTANCE. + TST SINANG ;FIGURE OUT WHICH WAY DUST IS TO GO. + BMI DUSTP2 ;CORRECT DIRECTION NOW. + NEG RET2 ;ELSE NEGATE IT NOW. +DUSTP2: ADD SHOWX,RET2 ;CENTER OF DUST NOW. + MOV RET2,(TEMP2)+ ;INSERT INTO THE BUFFER. + MOV AVERT,(TEMP2)+ ;INSERT THE Y VALUE NOW. + MOV #130000,(TEMP2)+ ;INSERT RELATIVE POINT COMMAND INTO THE BUFFER. + SUB #150.,TEMP ;GET APPROXIMATE DISTANCE TO GROUND. + BPL NODUST ;MORE THAN 50 FEET AWAY. PRODUCE NO DUST. + NEG TEMP ;MAKE THE DISTANCE POSITIVE AGAIN. + MOV TEMP,IN1 ;NOW MULTIPLY IT BY THE % THROTTLE. + MOV PERTRS,IN2 + JSR PC,MULTWO ;NOW HAVE ANUMBER BETWEEN 0 AND 5000 + ASR RET2 ;NOW BRING IT DOWN TO A CIVILIZED NUMBER. + ASR RET2 ;BY DIVIDING BY 16. + ASR RET2 + ASR RET2 + BEQ NODUST ;IF ZERO, GENERATE NO DUST. + MOV RET2,-(SP) ;SAVE THE COUNTER ON THE STACK. + MOV #STACK-200.-EXLIST-12.,RET1 ;PICK UP SIZE OF DUST AREA. + ASR RET1 ;GET NUMBER OF DOUBLE WORD ENTRIES. + ASR RET1 + CMP RET1,(SP) ;SEE IF CALCULATED NUMBER IS OK. + BHIS DUSTWF ;IF GREATER OR EQUAL, ALL IS WELL. + MOV RET1,(SP) ;ELSE SET A FINITE LIMIT NOW. +DUSTWF: MOV DUSTX,RET1 ;PICK UP A RANDOM DUST GENERATING WORD. + MOV #-100,RET2 ;AND LEAVE A GOOD MASK IN RET2. +DUSTL: ADD TIME,RET1 ;GENERATE THE RANDOM WORD NOW. + INC RET1 + BIC RET2,RET1 ;NOW LEAVE JUST LOW SIX BITS. + MOVB YTHRST(RET1),IN1 ;PICK UP AN X NOW. + ADD VERACC,RET1 ;NOW A LITTLE MORE RANDOMIZING. + BIC RET2,RET1 ;INDEX SET TO PICK UP Y. + BIC RET2,IN1 ;MAKE X JUST SIX BITS. + SWAB IN1 ;X OVER TO LEFT. + ROR IN1 ;AND INTO POSITION NOW. + COM TEMP ;COMPLEMENT X DIRECTION NOW. + BIC #-20001,TEMP ;LEAVE JUST THE SIGN BIT. + BIS #40000,TEMP ;SET THE INTENSITY BIT NOW. + BIS TEMP,IN1 ;AND SET THEM IN THE X NOW. + MOVB YTHRST(RET1),IN2 ;PICK UP THE Y NOW. + BIC RET2,IN2 ;Y IS ALWAYS POSITIVE. + BIS IN2,IN1 ;MAKE THE COMMAND NOW. + MOV IN1,(TEMP2)+ ;AND STICK IT AWAY. + ADD #20100,IN1 ;FLIP X AND Y SIGNS. + BIC #140000,IN1 ;TURN OFF DISPLAY BIT. + MOV IN1,(TEMP2)+ ;AND SAVE AWAY NOW. + DEC (SP) ;DECREMENT THE COUNTER NOW. + BGT DUSTL ;LOOP AROUND UNTIL DONE. + MOV #DISTOP,(TEMP2)+ ;TERMINATE THE LIST NOW. + CLR (TEMP2) ;WITH A DISPLAY STOP INSTRUCTION + MOV RET1,DUSTX ;SAVE DUSTX NOW. + TST (SP)+ ;INCREMENT THE COUNTER NOW. + MOV #EXLIST,DUSTON ;TURN ON THE DUST NOW. + RTS PC ;AND RETURN TO THE CALLER. +NODUST: CLR DUSTON ;TURN OFF THE DUST DISPLAY NOW. + RTS PC ;AND RETURN. + + .PAGE +; +; THIS ROUTINE WILL PLANT AN AMERICAN FLAG ON THE MOON. +; +; OR EVEN MORE SUPER, IT WILL BUY +; SOME HAMBURGERS. +; +PALSY: JSR PC,DELAY ;WAIT FOUR SECONDS BEFORE + .WORD -4. ;DOING ANYTHING GREAT. + MOV SHOWX,MANX ;POSITION MAN CORRECTLY. + MOV SHOWY,MANY + MOV #MAN,DUSTON ;SHOW THE MAN NOW. +PALSY1: BIT #177,TIME ;WAIT FOR CLOCK TO LINE UP NOW. + BNE PALSY1 ;WHICH SHOULD TAKE A RANDOM AMOUNT OF TIME. + TST MACON ;SEE IF THERE'S A MACDONALD'S PRESENT. + BEQ PALNOR ;NONE. NORMAL PLANT. +; MOVE THE MAN TO THE MACDONALD'S NOW! + MOV MACX,RET2 ;PICK UP THE MACDONALD'S X + SUB SHOWX,RET2 ;FIGURE OUT WHICH WAY TO GO. + MOV MACY,RET1 ;PICK UP THE HEIGHT OF THE MACDONALD'S. + SUB MANY,RET1 ;GET THE HEIGHT OF THE MAN NOW. + ADD #3,RET1 ;LIFT HIM UP OFF THE FLOOR. + MOV RET1,-(SP) ;AND PUSH DIFFERENCE ONTO STACK. + BEQ PALMX1 ;IF NO X, THEN ONLY MOVE Y. + JSR PC,MOVMAN ;MOVE THE MAN NOW. +PALMX1: MOV MACX,RET2 ;NOW FIGURE OUT HOW FAR TO MOVE THE MAN. + SUB MANX,RET2 + ADD #25.,RET2 ;BRING HIM INTO THE PLACE. + MOV RET2,-(SP) ;REMEMBER WHERE WE WERE. + CLR RET1 ;NO Y MOVE. + JSR PC,MOVMAN ;MOVE THE MAN NOW. + MOV #ORDER,SYSMES ;ORDER THE FOOD NOW. + JSR PC,DELAY ;WAIT FOR AWHILE. + .WORD -8. + CLR SYSMES ;REMOVE THE MESSAGE. + JSR PC,DELAY ;WAIT SOME MORE NOW. + .WORD -2. ;AND THEN FINALLY START HIM BACK. + NEG (SP) ;GET THE NEGATIVE DISTANCE. + MOV (SP),RET2 + CLR RET1 ;NO Y. + JSR PC,MOVMAN + MOV (SP)+,RET2 ;AND THEN GO UP INTO THE SHIP. + MOV (SP)+,RET1 ;BY RECALLING THE VALUES. + NEG RET1 ;INVERT SIGN, AND DON'T + BEQ PALMX2 ;FORGET POSSIBILITY OF SHIP LEVEL. + JSR PC,MOVMAN ;UP HE GOES NOW. +PALMX2: JSR PC,DELAY ;HOLD HIM IN SHIP A FEW SECONDS. + .WORD -2. + ADD #4.,VERDIS ;THEN LIFT HIM UP, AND TAKE HIM OFF. + ADD #2000.,FUEL ;GIVE HIM A LITTLE BIT MORE FUEL. + CLR VERVEL ;AND NO UPWARD VELOCITY. + CLR TICKS ;RESET NUMBER OF TICKS THAT HAVE ELAPSED. + MOV #STACK,SP ;AND SET SP TO TOP OF CORE . +PALOFF: CLR SYSMES ;LOOP WITHOUT GIVING ANY MESSAGES. + CLR ANGLE ;STRAIGHT UP. + CLR HORVEL ;WITH NO SIDEWAYS MOTION. + MOV #30.,PERCNT ;WITH ENOUGH THRUST TO RISE UP. + JSR PC,EIDLE ;AND DO EVERYTHING RIGHT. + TST MOON ;AND WAIT TILL MOON GETS BIG. + BNE PALOFF ;AND THEN MAYBE WE'LL FALL THROUGH. + CLR SHIPDP ;WHEN MOON IS BIG, REMOVE + CLR FSUBC ;SHIP AND FLAME. + JSR PC,DELAY ;AND THEN JUST WAIT FOR A FEW SECONDS. + .WORD 3. + .PAGE +; +; THIS ROUTINE PLANTS AN AMERICAN FLAG ON THE MOON. +; +PALNOR: MOV #1,-(SP) ;INDICATE TO MEMORY THAT SHIP HAS LANDED. + MOV INDEXL,-(SP) + JSR PC,PUTFET ;AWAY GO THE FEATURES NOW. + MOV #-24.,RET1 ;PREPARE TO MOVE THE MAN OUT NOW. + MOV #48.,RET2 + MOV TIME,TEMP2 ;FUDGE WHICH WAY TO MOV THE MAN. + ROR TEMP2 ;BY DIDDLING LOW BIT OF TIME. + BCC PALN1 ;IF LOW BIT OFF, GO RIGHT. + NEG RET2 ;IF ON, GO LEFT. +PALN1: MOV RET2,-(SP) ;REMEMBER IT ANYWAY. + JSR PC,MOVMAN ;MOVE THE MAN NOW. + MOV (SP)+,RET2 ;AND THEN THE FINAL DISTANCE. + CLR RET1 ;WITH NO Y. + JSR PC,MOVMAN + MOV MANX,FLAGX ;DISPLAY THE FLAG NOW. + MOV MANY,FLAGY + ADD #20.,FLAGX ;OFFSET IT A LITTLE BIT. + MOV #FLAGL,FSUBC ;PLACE FLAG IN THE FLAME LIST. + MOV INDEXL,IN1 ;PICK UP THE INDEX NOW. + JSR PC,PALSYI ;UPDATE IT ALSO. + JSR PC,PALSYI ;SO WE KNOW WHERE TO REMEMBER FLAG. + MOV #2,-(SP) ;SAVE IT AWAY NOW. + MOV IN1,-(SP) ;IN THE FEATURE TABLE + JSR PC,PUTFET + MOV #MANMSG,SYSMES ;DISPLAY THE MESSAGE NOW. + JSR PC,DELAY ;WAIT TEN MORE SECONDS. + .WORD 10. + .PAGE +; +; THIS ROUTINE MOVES THE MAN ALONG THE SURFACE +; OF THE MOON. RET1=DELTA Y; RET2=DELTA X. +; IF Y=0, THEN ONLY X IS USED. IF Y<>0, THEN ONLY +; THE SIGN OF THE X IS USED. +; +MOVMAN: MOV #INC,TEMP2 ;GET "INC IN1" TO INDICATE X TO RIGHT. + TST RET2 ;GET X DIRECTION NOW. + BPL MOVM1 ;TO THE RIGHT. + MOV #DEC,TEMP2 ;ELSE MAKE THE X GO THE OTHER WAY. + NEG RET2 ;AND SET THE COUNTER TO GO DOWN. +MOVM1: MOV TEMP2,PALSYI ;SAVE AWAY THE GENERATED INSTRUCTION NOW. + CLR TEMP2 ;CLEAR THE DELTA Y ADD NOW. + TST RET1 ;NOW GET THE AMOUNT OF THE DELTA "Y". + BEQ MOVJX ;NO Y. JUST X MOVE. + INC TEMP2 ;SOME Y. SET TO UP. + MOV RET1,RET2 ;AND USE THE Y AS THE COUNTER NOW. + BPL MOVJX ;IF UP, ALL IS WELL, + NEG RET2 ;ELSE NEGATE COUNT AND THE + NEG TEMP2 ;AND THE DELTA Y ADD. + ;RET2=+COUNT TO DO, TEMP2=DELTA Y. +MOVJX: MOV MANX,IN1 ;PICK UP THE PRESENT POSITION NOW. +MOVLUP: JSR PC,PALSYI ;MOVE OVER THE X. + MOV IN1,MANX ;AND PLACE IN MEMORY. + ADD TEMP2,MANY ;UPDATE THE Y ALSO. + JSR PC,PALSYW ;WAIT FOR 8 CLOCK TICKS TO GO BY. + DEC RET2 ;ELSE DECREMENT THE COUNTER. + BGT MOVLUP ;AND LOOP TILL DONE. + RTS PC ;AND THEN RETURN. +PALSYI: .WORD 0 ;EITHER AN INC OR DEC 'IN1' + RTS PC ;AND THEN RETURN WITH IN1 UPDATED. +PALSYW: BIT #7,TIME ;WAIT FOR NONE MULTIPLE OF 8. + BEQ PALSYW + JSR PC,DIAL ;AND DISPLAY THE USER'S INFORMATION NOW. +PALSYV: BIT #7,TIME ;AND THEN WAIT FOR 8 MORE + BNE PALSYV + JSR PC,DIAL ;WHILE DOING THIS, DISPLAY THE USER'S INFO. + RTS PC ;AND THEN RETURN. + .PAGE +; +; THESE ROUTINE WILL INSERT OR CHANGE A LUNAR +; FEATURE OR WILL RETRIEVE IT'S VALUE. +; +PUTFET: MOV TEMP,-(SP) ;SAVE TEMPORARY NOW. + MOV 4(SP),TEMP ;PICK UP AN INDEX NOW. + ASR TEMP ;MAKE IT A BYTE INDEX. + BCC FETRGT ;IF EVEN, IT'S THE RIGHT BYTE. + ASL 6(SP) ;LEFT BYTE. SHIFT OVER THE VALUE. + ASL 6(SP) + ASL 6(SP) + ASL 6(SP) + BICB #360,FEATUR(TEMP) ;CLEAR OUT THE BYTE NOW. + BR PUTCOM ;INSERT IT NOW. +FETRGT: BICB #17,FEATUR(TEMP) ;CLEAR OUT THE RIGHT BYTE NOW. +PUTCOM: BISB 6(SP),FEATUR(TEMP) ;INSERT THE BYTE NOW. + MOV (SP)+,TEMP ;RESTORE THE REGISTER NOW. + MOV (SP),4(SP) + ADD #4,SP ;UPDATE THE STACK AFTER MOVING OVER THE PC. + RTS PC ;RETURN NOW. +GETFET: MOV TEMP,-(SP) ;SAVE A SCRATCH REGISTER NOW. + MOV 4(SP),TEMP ;PICK UP THE INDEX NOW. + ASR TEMP ;BYTE ADDRESS IT. + MOVB FEATUR(TEMP),TEMP ;PICK UP THE FEATUR NOW. + BCC GETDUN ;IF RIGHT BYTE, NO SHIFTING IS NECESSARY. + ASR TEMP ;ELSE SHIFT IT OVER. + ASR TEMP + ASR TEMP + ASR TEMP +GETDUN: BIC #177360,TEMP ;JUST RETURN 4 BITS NOW. + MOV TEMP,4(SP) + MOV (SP)+,TEMP ;MOVE OVER ANSWER AND RESTORE SCRATCH + RTS PC ;REGISTER AND EXIT. + .PAGE +; +; THIS ROUTINE WILL "DRAW" THE MOON FROM THE TABLE OF Y VALUES. +; +DRAWM1: JSR PC,DRAWMC ;SET UP COMMON CRAP. + MOV TERAIN,TEMP ;PICK UP FIRST Y POS. + ASR TEMP ;DIVIDE BY 32 + ASR TEMP + ASR TEMP + ASR TEMP + ASR TEMP + ADD #23.,TEMP + MOV TEMP,(TEMP2)+ + MOV TEMP,LASTY ;SAVE Y FOR TOP OF SCREEN CHECK. + MOV #SETSVM,(TEMP2)+ ;AFTER STORING Y POS, SET GRAPH PLOT MODE. + MOV #TERAIN,IN1 ;POINTER TO THE TERAIN. +DRAW1L: ADD #8.,IN1 ;POSITION TO THE NEXT Y. + MOV (IN1),TEMP + ASR TEMP + ASR TEMP + ASR TEMP + ASR TEMP + ASR TEMP + ADD #23.,TEMP ;SCALE IT AROUND NOW. + JSR PC,DRAWIC ;INSERT ONE Y CO-ORD + BR DRAW1L ;AND LOOP TILL DONE. + MOV #DISTOP,(TEMP2)+ ;AND FINALLY TERMINATE THE LIST + CLR (TEMP2) + MOV #MOONST,MOONGO ;START DISPLAYING THE MOON NOW. + JSR PC,DRAWRS ;RESTORE REGISTERS + RTS PC ;AND EXIT NOW. + .PAGE +; +; THIS ROUTINE WILL ITIALIZE CERTAIN +; REGISTERS, SAVE REGISTERS AND DO OTHER CRAP NECESSARY +; FOR THE MOON DRAWING ROUTINES TO WORK. +; +DRAWMC: MOV RET1,-(SP) + MOV RET2,-(SP) + MOV IN1,-(SP) + MOV IN2,-(SP) + MOV TEMP,-(SP) + MOV #225.,DRAWCT ;NUMBER OF VECTORS TO DRAW. + CLR MOONGO ;TURN OFF DRAWING OF MOON. + CLR MACON ;SET FLAG TO "NO MACDONALD'S ON SCREEN". + MOV #MOONST,TEMP2 ;SET UP THE POINTER NOW. + MOV #114124,(TEMP2)+ ;PLOT POINT MODE. + MOV #170240,(TEMP2)+ ;SET STATUS MODE. + CLR (TEMP2)+ ;SET X POSITION TO ZERO NOW. + JMP @10.(SP) ;AND RETURN NOW. +DRAWRS: MOV (SP),12.(SP) ;MOVE OVER RETURN ADDRESS. + MOV (SP)+,TEMP ;THROW AWAY TOP ITEM. + MOV (SP)+,TEMP ;AND RESTORE THE REGISTERS. + MOV (SP)+,IN2 + MOV (SP)+,IN1 + MOV (SP)+,RET2 + MOV (SP)+,RET1 + RTS PC ;AND RETURN NOW. + .PAGE +; +; THIS ROUTINE WILL INSERT ONE "Y" POINT INTO THE +; MOON LIST. IT WILL RANDOMIZE THE LINE TYPE AND INTENSITY +; +DRAWIC: MOV #1000,-(SP) ;MAKE THE VECTOR INVISIBLE FOR NOW. + CMP TEMP,#1024. ;SEE IF IT'S TOO BIG. + BLO DRAWI1 ;NOT TOO BIG. + MOV #1023.,TEMP ;TOO BIG, SET TO TOP, AND TURN OFF + CMP TEMP,LASTY ;IS IT STILL ON TOP? + BEQ DRAWI3 ;YES. DON'T DRAW THE MOUNTAIN. +DRAWI1: TST TEMP ;SEE IF VALUE IS LESS THAN ZERO. + BPL DRAWI2 ;YES. + CLR TEMP ;NO IT ISN'T. + TST LASTY ;WAS LAST RESULT 0? + BEQ DRAWI3 ;YES. DO NOT PUT ON VISIBLE BIT. +DRAWI2: BIS #40000,(SP) ;TURN ON VISIBLE BIT. +DRAWI3: DEC DRAWTY ;SEE WHAT TYPE OF INTENSITY + BPL DRWIN ;AND LINE TYPE IS REQUIRED, IF ANY. + INC DRAWTZ ;COUNTER OVERFLOWED. CHANGE TYPE. + BIC #-4,DRAWTZ + INC DRAWTZ + MOV DRAWTZ,DRAWTY ;RESET BIGGY AND LITTLY. + ADD #1200,DINT ;RANDOMIZE INTENSITY AND TYPE. + BIC #176177,DINT + INC DTYPE + BIC #-4,DTYPE + MOV DINT,(TEMP2) ;CREATE NEW PLOT POINT INSTRUCTION. + BIS DTYPE,(TEMP2) + BIS #106004,(TEMP2)+ ;GRAPH Y WITH BLANK INTENSITY'S AND TYPES. +DRWIN: SUB LASTY,TEMP ;GET THE DELTA Y. + BPL DRWINP ;FIX UP DIRECTION OF VECTOR. + NEG TEMP + BIC #-100,TEMP ;REMOVE CRAP NOW. + SUB TEMP,LASTY ;UPDATE PREVIOUS Y NOW. + BIS #100,TEMP + BR DRWINQ +DRWINP: BIC #-100,TEMP ;CLEAN IT UP. + ADD TEMP,LASTY ;AND UPGRADE PREVIOUS Y NOW. +DRWINQ: BIS (SP)+,TEMP ;MAKE IT A GOOD INSTRUCTION NOW. + MOV TEMP,(TEMP2)+ ;AND SAVE IT AWAY NOW. + DEC DRAWCT ;DECREMENT MASTER COUNTER. + BGT DRAWRR ;NORMAL RETURN. + ADD #2,(SP) ;END RETURN. +DRAWRR: RTS PC ;AND EXIT NOW. + .PAGE +; +; ALTER WILL ALTER THE FACE OF THE MOON. IN1 +; CONTAINS A NUMBER TO BE USED IN ALTERING IT. +; +ALTER: MOV BIGXCT,IN2 ;PICK UP PRESENT INDEX. + MOV IN2,TEMP ;WORK BOTH FORWARD AND BACKWARD. + ASL IN2 + ADD #TERAIN,IN2 + MOV #3,-(SP) ;INDICATE A CRASHED SHIP. + MOV (IN2)+,TEMP2 ;PICK UP Y. + MOV IN2,RET2 + SUB (IN2),TEMP2 ;FIGURE OUT WHICH WAY TO TILT SHIP. + BMI ALERTP ;LEAVE TILTED TO LEFT. + INC (SP) +ALERTP: MOV TEMP,-(SP) ;PUSH THE INDEX ONTO THE STACK. + JSR PC,PUTFET ;AND PUT AWAY THE FEATURE. +ALERTL: SUB IN1,(IN2)+ ;NOW ALTER BOTH WAYS. + SUB IN1,-(RET2) + ASR IN1 ;DIVIDE BY TWO. + NEG IN1 ;AND NEGATE IT. + BNE ALERTL ;AND LOOP TILL DONE. + RTS PC ;ELSE RETURN NOW. + .PAGE +; +; THIS SECTION WILL CAUSE THE SKIP TO +; EXPLODE ON THE SCREEN BY SHOOTING OUT A SERIES OF +; "DOTS" FOR A GIVEN PERIOD OF TIME. +; +EXPLOD: CLR RADIUS ;SET THE RADIUS TO ZERO. + CLR FSUBC ;TURN OFF THE ROCKET NOW. + CLR DUSTON ;TURN OFF THE DUST, IF ANY. + BIS #0,DSR ;"RING THE BELL". +EXPLD1: MOV #EXLIST,TEMP2 ;GET POINTER TO WHERE TO SHOW EXPLOSION. + MOV XTYPE,TEMP ;PICK UP RANDOMIZING WORD NOW. + INC TEMP ;AND JUST PLAY WITH YOURSELF FOR A WHILE. + SWAB TEMP + ROR TEMP + ADD (TEMP2),TEMP ;ADD IN OLD COMMAND. + BIC #176177,TEMP ;CLEAR OUT CRAP NOW. + BIS #116120,TEMP ;MAKE IT A GOOD COMMAND NOW. + MOV TEMP,(TEMP2)+ ;AND INSERT IT INTO THE BUFFER. + JSR PC,EXGEN ;GENERATE SOME SMOKE NOW. + BIS #0,DSR ;GIVE A GOOD BEEP NOW. + SUB #10.,RADIUS ;NOW PRODUCE SOME MORE DOTS. + JSR PC,EXGEN + MOV #DISTOP,(TEMP2)+ ;TERMINATE THE PICTURE NOW. + CLR (TEMP2) + MOV #EXLIST,FSUBC ;MAKE SURE WE'RE SHOWING IT. + BIS #0,DSR ;GIVE A RANDOM BEEP, AT TIMES. + ADD #33.,RADIUS ;FINALLY INCREMENT RADIUS AND CHECK + CMP RADIUS,#300 ;DONE? + BLE EXPLD1 ;NOPE. + JSR PC,DELAY ;DELAY NOW BEFORE RESTARTING. + .WORD 5. ;FIVE SECONDS. +EXGEN: MOV #-30.,ANGLE ;INITIALIZE THE ANGLE NOW. + MOV #241.,-(SP) ;AND SET COUNTER TO DO -30 TO 210 DEGREES. +EXGENL: JSR PC,TRIG ;FIGURE OUT VARIOUS ANGLES NOW. + MOV -6(SP),IN1 ;PICK UP RANDOM INTERUPT NUMBER NOW. + ASR IN1 ;JUST IN CASE IT WAS EVEN. + INC IN1 ;INCREMENT IT NOW. + ADD TIME,IN1 ;ADD IN THE TIME ALSO. + ADD XTYPE,IN1 ;AND ALSO THE PREVIOUS NUMBER. + MOV IN1,XTYPE ;AND SAVE IT AWAY NOW. + BIC #-40,IN1 ;MAKE IT BETWEEN 0 AND 31 + MOVB YUPDWN(IN1),TEMP ;SO THAT WE CAN USE THE FLAME TABLE. + ADD RADIUS,TEMP ;GET A NEW RADIUS NOW. + BMI EXGENP ;IF MINUS, FORGET ABOUT IT. + MOV TEMP,IN1 ;ELSE GET THE SINES AND COSINES. + MOV COSANG,IN2 ;SO WE CAN GET THE X AND THE + JSR PC,TRGMUL ;Y POINTS FOR THE EXPLOSION. + ADD SHOWX,RET1 ;WE'VE GOT OUR X NOW. + BMI EXGENP ;MINUS IS A BADDY. + BIS #INT,RET1 ;DON'T FORGET TO TURN ON INTENSIFY BIT. + MOV RET1,(TEMP2)+ ;AND PLACE IT AWAY NOW. + MOV TEMP,IN1 ;NOW GET THE Y. + MOV SINANG,IN2 + JSR PC,TRGMUL + ADD SHOWY,RET1 + BMI EXGENO ;IF THIS IS BAD, WE MUST BACK UP. + MOV RET1,(TEMP2)+ +EXGEND: INC ANGLE ;NOW GET THE NEXT ANGLE. + DEC (SP) ;AND WAIT TILL DONE. + BGT EXGENL ;AND LOOP TILL DONE. + TST (SP)+ ;AND THEN EXIT. + RTS PC ;THIS INSTRUCTION HELPS IF ONE LEAVES IT IN. +EXGENO: CLR -(TEMP2) ;IF X IS ALREADY THERE, TAKE IT BACK. +EXGENP: CLR (TEMP2)+ ;INSERT DUMMY'S SO DISPLAY WON'T SCREW UP. + CLR (TEMP2)+ + BR EXGEND ;AND SEE IF ALL DONE. + .PAGE +; +; NOTE, ANY ADDITIONAL CRAP YOU WISH TO PUT +; IN MAY GO HERE. +; +DRAWM2: JSR PC,DRAWMC ;THIS ROUTINE WILL THE CLOSE-UP + CLR DFUDGE ;VIEW OF THE MOON. + MOV LEFTEDGE,IN1 ;PICK UP LEFT SIDE OF THE SCREEN. + ASL IN1 + ADD #TERAIN,IN1 ;GET POINTER TO LEFT Y. + MOV (IN1),TEMP ;GET LEFT Y. + JSR PC,DFAKE ;MAKE INTO GOOD RASTOR. + TST TEMP ;SEE IF ON THE SCREEN NOW. + BPL DRW2L5 ;IF POSITIVE OK, + CLR TEMP ;ELSE ZERO IT OUT. + BR DRW2M +DRW2L5: CMP TEMP,#1024. ;SEE IF TOO BIG. + BLO DRW2M ;NOPE. OK + MOV #1023.,TEMP ;ELSE FIX IT UP. +DRW2M: MOV TEMP,(TEMP2)+ ;INSERT STARTING Y INTO BUFFER. + MOV TEMP,LASTY ;ESTABLISH LAST Y POSITION NOW. + MOV #SETSVM,(TEMP2)+ ;INSERT THE GRAPH PLOT MODE COMMAND . +DRW2L: MOV TEMP,-(SP) ;NOW GET Y(NEW) AND DELTA Y. + MOV (IN1)+,TEMP + JSR PC,DFAKE + MOV TEMP,IN2 + MOV (SP)+,TEMP + CLR RET1 ;CLEAR AWAY LEFT MOST PART FOR THE DIVIDE. + MOV IN1,-(SP) ;SAVE IN1 NOW. + MOV #12.,IN1 ;PICK UP A TWELVE FOR THE DIVIDE. + SUB TEMP,IN2 ;GET DELTA Y NOW. + BPL DRAW2G + SUB #6.,IN2 + NEG IN2 ;MAKE IN2 POSITIVE NOW. + MOV IN2,RET2 ;MOVE OVER TO DIVISOR PART. + JSR PC,DIVTWO ;DIVIDE BY TWO NOW. + NEG RET2 ;NEGATE THE ANSWER NOW. + BR DRAW2H +DRAW2G: ADD #6.,IN2 + MOV IN2,RET2 ;MOVE IT OVER NOW. + JSR PC,DIVTWO ;DO THE DIVISION NOW. +DRAW2H: MOV RET2,IN2 ;MOVE OVER THE DELTA NOW. + MOV IN1,RET1 ;ESTABLISH THE COUNT NOW. + MOV (SP)+,IN1 ;RESTORE THE REGISTER NOW. +DRAW22: INC @#DFUDGE ;---<>--- + CMP DFUDGE,#3. + BLT DRAW2V + MOV (PC)+,@(PC)+ + DEC @(PC)+ + .WORD DRAW22 + BR DRAW2W +DRAW2V: CMP DFUDGE,#-3. + BGT DRAW2W + MOV (PC)+,@(PC)+ + INC @(PC)+ + .WORD DRAW22 +DRAW2W: ADD DFUDGE,TEMP ;PERTIBATE SURFACE NOW. + ADD IN2,TEMP ;UPDATE TEMP NOW. + MOV TEMP,-(SP) ;SAVE Y FOR A SECOND. + JSR PC,DRAWIC ;INSERT + BR DRAW2C ;STILL GOING. + BR DRAW2X ;GONE. +DRAW2C: MOV (SP)+,TEMP ;RECALL THE Y NOW. + DEC RET1 ;SEE IF DONE WITH THE EIGHT. + BGT DRAW22 ;NO. + BR DRW2L ;YES. +DRAW2X: MOV LEFTEDGE,RET1 ;PICK UP LEFTEDGE AGAIN. + MOV #19.,(SP) ;PREPARE TO EXAMINE THE TERAIN NOW. + MOV #24.,IN1 + MOV RET1,RET2 ;SET UP TWO POINTERS NOW. + ASL RET2 + ADD #TERAIN,RET2 +DRAW2Y: MOV RET1,-(SP) ;PUSH FEATURE INDEX ONTO THE STACK. + INC RET1 ;INCREMENT INDEX POINTER TO NEXT FEATURE. + JSR PC,GETFET ;GET THE FEATURE NOW. + MOV (SP)+,TEMP ;AND PUT IT IN A USEFUL REGISTER. + ASL TEMP ;MAKE IT INTO A GOOD INDEX. + JSR PC,@DRAWTB(TEMP) + TST (RET2)+ ;BYPASS + ADD #48.,IN1 + DEC (SP) + BGT DRAW2Y ;KEEP LOOKING NOW. + TST (SP)+ ;ELSE UPDATE. + MOV #DISTOP,(TEMP2)+ ;TERMINATE THE DISPLAY NOW. + CLR (TEMP2) + JSR PC,DRAWRS ;RESTORE THE REGISTERS. + MOV #MOONST,MOONGO ;START DISPLAYING THE MOON NOW. + RTS PC ;AND RETURN NOW. + .PAGE +; +; JUMP TABLE FOR THE VARIOUS KINDS OF +; CRAP ONE IS LIKELY TO FIND ON THE MOON. +; +AHTAB: .WORD AHNONE ;HOW TO PROCESS THIS CRAP. + .WORD AHSP1 + .WORD AHFLG + .WORD AHOLDS + .WORD AHOLDS + .WORD AHROCK + .WORD AHMAC + .WORD AHMAC +DRAWTB: .WORD DRAWRR ;0=NOTHING=RETURN. + .WORD OLDSHP ;1=OLD SPACE SHIP + .WORD FLAG ;2=PLANTED FLAG. + .WORD LEFTSP ;3=CRASHED SHIP ON LEFT SIDE. + .WORD RIGHTS ;4=CRASHED SHIP ON RIGHT SIDE. + .WORD ROCK ;5=A ROCK. + .WORD AHNONE ;6=LEFT OR RIGHT OF MAC'S. RETURN. + .WORD MACDON ;7=CENTER OF MAC'S. THIS COVERS 6. +DFAKE: MOV TEMP,-(SP) ;THIS ROUTINE FIGURES OUT + ASL TEMP ;Y*3/2/4 OR ((3*Y)/2)/4 + ADD (SP)+,TEMP + ASR TEMP + ASR TEMP ;ALMOST THERE. + ASR TEMP + ADD #23.,TEMP ;AND THEN IT CORRECTS THE BASE + RTS PC ;SCREEN Y. + .PAGE +; +; THESE ROUTINES WILL DRAW OLD AND CRASHED SHIPS +; ONE THE SURFACE OF THE MOON. +; +OLDSHP: JSR PC,DEADSP + .WORD 0 ;UPRIGHT + .WORD 23. ;DISTANCE ABOVE SURFACE. + .WORD -24. ;LOWEST POINT TO DRAW. +LEFTSP: JSR PC,DEADSP ;LEFT TILTED SHIP. + .WORD -90. + .WORD 16. + .WORD -18. +RIGHTS: JSR PC,DEADSP + .WORD 90. + .WORD 16. + .WORD -18. +DEADSP: CMP TEMP2,#MOONEN-102. ;SEE IF ENOUGH ROOM FOR THE SHIP. + BHI DEADBY ;NOPE. EXIT. + MOV IN2,-(SP) + MOV RET1,-(SP) + MOV RET2,-(SP) + MOV TEMP,-(SP) + MOV IN1,-(SP) + MOV 10.(SP),IN1 ;PICK UP OLD PC. + MOV #SETPNT,(TEMP2)+ ;SET POINT MODE. + MOV (SP),(TEMP2)+ ;MOV OVER THE X NOW. + MOV ANGLE,-(SP) ;PUSH DOWN THE OLD ANGLE. + MOV (RET2),TEMP ;PICK UP A Y. + JSR PC,DFAKE + MOV TEMP,-(SP) + MOV 2(RET2),TEMP ;NEXT Y. + JSR PC,DFAKE + ADD (SP)+,TEMP + ASR TEMP ;AVERAGE OF THE Y'S, WHICH IS CENTER. + MOV (IN1)+,ANGLE ;MOVE OVER THE CALLER'S ANGLE NOW. + ADD (IN1)+,TEMP ;AND CENTER THE SHIP. + MOV (IN1),LOWY ;AND SET THE LOW Y ALL AT THE SAME TIME. + MOV TEMP,(TEMP2)+ ;INSERT THE Y NOW. + CMP (RET2),2(RET2) ;SEE WHICH Y IS BIGGER. + BEQ DEADOK + BHI DEADPL + ADD #-22.,ANGLE + BR DEADOK +DEADPL: ADD #22.,ANGLE +DEADOK: JSR PC,TRIG ;FIGURE OUT SINES AND COSINES. + MOV TEMP2,IN2 + MOV #DESIGN,IN1 ;SET UP DRAW CALL. + JSR PC,DRAW ;DRAW THE SHIP NOW. + CLR -(TEMP2) ;REMOVE THE DISPLAY STOP INSTRUCTION. + CLR -(TEMP2) + MOV (SP)+,ANGLE ;RESTORE THE ANGLE. + JSR PC,TRIG ;AND THE VALUES. + MOV (SP)+,IN1 ;POP THE VALUES NOW. + MOV (SP)+,TEMP + MOV (SP)+,RET2 + MOV (SP)+,RET1 + MOV (SP)+,IN2 + TST (SP)+ ;IGNORE ORIGINAL CALL. +DEADBY: RTS PC ;AND RETURN NOW. + .PAGE +; +; THIS ROUTINE WILL PLANT AN AMERICAN FLAG ON THE MOON. +; +FLAG: CMP TEMP2,#MOONEN-FLAGEN+FLAGL-6 ;SEE IF FLAG CAN FIT. + BHI ROCKRT ;NOPE. NO ROOM. DO NOT INSERT IT + MOV IN1,FLAGX + MOV (RET2),TEMP + JSR PC,DFAKE ;GET THE Y'S + MOV TEMP,IN2 + MOV 2(RET2),TEMP + JSR PC,DFAKE + ADD IN2,TEMP + ASR TEMP + MOV TEMP,FLAGY + MOV #FLAGL,IN2 ;NOW FAKE OUT A ROUTINE. + BR ROCKLP ;AND NOW ENTER ROCK PUTTER. + .PAGE +; +; THIS ROUTINE WILL DRAW A ROCK ON THE MOON. +; +ROCK: CMP TEMP2,#MOONEN-ROCKEN+ROCKL-6 ;SEE IF THE ROCK CAN FIT. + BHI ROCKRT ;CAN'T FIT NOW. + MOV IN1,ROCKX ;SAVE THE ROCK'S X AND Y POINT. + MOV (RET2),TEMP ;AFTER FUDGING Y. + JSR PC,DFAKE + MOV TEMP,IN2 + MOV 2(RET2),TEMP + JSR PC,DFAKE + ADD IN2,TEMP + ASR TEMP + MOV TEMP,ROCKY ;SAVE IT AWAY NOW. + MOV #ROCKL,IN2 ;PICK UP POINTER TO PROTOTYPE ROCK. +ROCKLP: MOV (IN2)+,TEMP + CMP TEMP,#DISTOP ;DONE? + BEQ ROCKRT ;YES. + MOV TEMP,(TEMP2)+ ;NO. PUT AWAY NOW. + BR ROCKLP +ROCKRT: RTS PC ;RETURN NOW. +MACDON: TST MACTHR ;IS MACDONALD'S STILL IN EXISTANCE. + BEQ MACEX ;NO. EXIT. + CMP IN1,#25. ;IT IS. ARE WE CENTERED ENOUGH + BLE MACEX ;TO DRAW IT. NO. TO FAR LEFT. + CMP IN1,#880. + BGE MACEX ;NO. TO FAR TO THE RIGHT. + MOV 2(RET2),TEMP ;PICK UP RIGHT Y NOW. + CMP (RET2),TEMP ;AND SEE IF IT'S SMALLER THAN LEFT Y. + BGE MACB1 ;IT IS. + MOV (RET2),TEMP ;IT ISN'T. PICK SMALLEST Y NOW. +MACB1: JSR PC,DFAKE ;GET SCREEN COORDINATES NOW. + MOV TEMP,MACY ;SAVE AWAY THE Y + MOV IN1,MACX ;AND THE X ALSO. + MOV SP,MACON ;AND SET THE MAC IS DRAWN FLAG. + MOV #DISTOP,(TEMP2)+ ;AND PLACE CALL TO IT IN THE BUFFER. + MOV #MACS,(TEMP2)+ +MACEX: RTS PC ;AND RETURN NOW. SIMPLE, ISN'T IT. + .PAGE +; +; THESE ARE SOME MISC MULTIPLY ROUTINES (AND DIVIDE) WHICH +; ARE NECESSARY FOR THE SMOOTH OPERATION OF THE SYSTEM. +; +MULTWO: CLR RET2 ;CLEAR LOW ORDER RETURN VALUE. + CMP IN2,IN1 ;SEE WHICH ONE IS SMALLER. + BHIS MULT1L ;IN1 IS SMALLER (AS EXPECTED). + MOV IN2,RET1 ;PLACE IN2 IN RET1, AND + BEQ MULTDN ;IF ZERO, EXIT. ELSE THEN PLACE + MOV IN1,IN2 ;IN1 IN IN2. . + CLC ;CLEAR THE CARRY BEFORE WE BLOW IT! + BR MULTCM ;AND START MULTIPLY GOING. +MULT1L: MOV IN1,RET1 ;MOVE OVER IN1, BECAUSE IT IS SMALLEST. + BEQ MULTDN ;IF IT'S ZERO, THEN WE ARE DONE. +MULTCM: ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD16 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD15 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD14 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD13 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD12 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD11 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD10 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD9 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD8 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD7 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD6 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD5 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD4 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD3 ;AND START MULTIPLY WHEN SET. + ROL RET1 ;ROTATE MULTIPLIER ONE PLACE. + BCS ADD2 ;AND START MULTIPLY WHEN SET. + CLR RET1 ;RET1 MUST BE 100000, BECAUSE + MOV IN2,RET2 ;IF WE GOT HERE, THEN IT MUST +MULTDN: RTS PC ;BE A MULTIPLY BY 1. +ADD16: MOV IN2,RET2 ;IF A BIGGY, JUST MOVE OVER CRAP. + ASL RET2 ;OK, NOW LET'S SHIFT AND START GOING. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD15 ;NO. BYPASS THE ADD NOW. +ADD15: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD15: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD14 ;NO. BYPASS THE ADD NOW. +ADD14: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD14: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD13 ;NO. BYPASS THE ADD NOW. +ADD13: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD13: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD12 ;NO. BYPASS THE ADD NOW. +ADD12: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD12: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD11 ;NO. BYPASS THE ADD NOW. +ADD11: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD11: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD10 ;NO. BYPASS THE ADD NOW. +ADD10: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD10: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD9 ;NO. BYPASS THE ADD NOW. +ADD9: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD9: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD8 ;NO. BYPASS THE ADD NOW. +ADD8: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD8: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD7 ;NO. BYPASS THE ADD NOW. +ADD7: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD7: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD6 ;NO. BYPASS THE ADD NOW. +ADD6: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD6: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD5 ;NO. BYPASS THE ADD NOW. +ADD5: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD5: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD4 ;NO. BYPASS THE ADD NOW. +ADD4: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD4: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD3 ;NO. BYPASS THE ADD NOW. +ADD3: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD3: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD2 ;NO. BYPASS THE ADD NOW. +ADD2: ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD2: ASL RET2 ;ALL DONE WITH PREV. OPER. + ROL RET1 ;DO NEXT BIT NOW. OK TO MULT? + BCC NADD1 ;NO. BYPASS THE ADD NOW. + ADD IN2,RET2 ;BIT ON. ADD IN MULTIPLICAND. + ADC RET1 ;DON'T FORGET ABOUT ADDING IN CARRY. +NADD1: RTS PC ;AND RETURN WHEN DONE. + .PAGE +; +; THIS ROUTINE WILL MULTIPLY TWO SIGNED NUMBERS. +; +SGNMUL: TST IN1 ;GET SIGN OF THE FIRST ARGUMENT. + BPL SGNMP1 ;IT'S OK. + NEG IN1 ;NOT OK. + TST IN2 ;HOW ABOUT SECOND. + BPL SGNMP2 ;IT'S POSITIVE. + NEG IN2 ;BOTH NEGATIVE=POSITIVE. +SGNMP3: JSR PC,MULTWO ;MULTIPLY THEM OUT. + RTS PC ;AND RETURN NOW. +SGNMP1: TST IN2 ;TEST SIGN OF THE SECOND ONE. + BPL SGNMP3 ;IT'S ALSO POSITIVE. DO MULTIPLY. + NEG IN2 ;ELSE NEGATE IT, ANDINVERT ANSWER. +SGNMP2: JSR PC,MULTWO ;MULTIPLY THEM OUT. + NEG RET2 ;AND DO A DOUBLE PRECISION NEGATE. + ADC RET1 + NEG RET1 + RTS PC ;AND THEN RETURN. ALL IS WELL. +TRGMUL: JSR PC,SGNMUL + ASL RET2 ;FUDGE THE RETURN ANSWER NOW. + ROL RET1 + ASL RET2 + ROL RET1 + RTS PC + .PAGE +; +; THIS ROUTINE WILL DIVIDE RET1-RET2 BY IN1 AND LEAVE THE +; ANSWER IN RET2. DOES IT BY 16 SUBTRACTIONS. CRUDE BUT FAST. +; +DIVTWO: ASL RET2 ;WE FORBID LEFT-MOST BIT TO BE ON. + ROL RET1 + SUB IN1,RET1 ;SEE IF IT FITS. + BPL DVOKA ;IT FITS. GENERATE A "1". +DVBADA: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKB ;IT FITS. GENERATE A "1". +DVBADB: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKC ;IT FITS. GENERATE A "1". +DVBADC: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKD ;IT FITS. GENERATE A "1". +DVBADD: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKE ;IT FITS. GENERATE A "1". +DVBADE: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKF ;IT FITS. GENERATE A "1". +DVBADF: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKG ;IT FITS. GENERATE A "1". +DVBADG: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKH ;IT FITS. GENERATE A "1". +DVBADH: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKI ;IT FITS. GENERATE A "1". +DVBADI: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKJ ;IT FITS. GENERATE A "1". +DVBADJ: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKK ;IT FITS. GENERATE A "1". +DVBADK: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKL ;IT FITS. GENERATE A "1". +DVBADL: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKM ;IT FITS. GENERATE A "1". +DVBADM: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKN ;IT FITS. GENERATE A "1". +DVBADN: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKO ;IT FITS. GENERATE A "1". +DVBADO: ASL RET2 ;NOT YET. PUT IN A ZERO. + ROL RET1 ;AND PICK UP THE NEXT BIT. + ADD IN1,RET1 ;2*(Y-X)+X=2*Y-X. + BPL DVOKP ;IT FITS. GENERATE A "1". +DVBADP: ADD IN1,RET1 ;ON LAST FAIL, ADD BACK IN TO GET A + RTS PC ;CORRECT REMAINDER, AND THEN EXIT. +DVOKA: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADB ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKB: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADC ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKC: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADD ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKD: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADE ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKE: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADF ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKF: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADG ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKG: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADH ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKH: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADI ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKI: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADJ ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKJ: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADK ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKK: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADL ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKL: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADM ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKM: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADN ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKN: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADO ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKO: INC RET2 ;SUBTRACTION IS GOOD. INSERT A "1". + ASL RET2 ;NOW CHECK THE NEXT ONE. + ROL RET1 ;TO SEE IF IT GOES. + SUB IN1,RET1 + BMI DVBADP ;GOES NOT GO. INSERT A ZERO AND START ADDING. +DVOKP: INC RET2 ;LAST SUBTRACTION SUCCESSFULL. +DVOKX: RTS PC ;INSERT A "1" AND RETURN. ALL IS WELL. + .PAGE +; +; THIS IS THE CLOCK INTERUPT ROUTINE. +; +TIMER: BIS #100,LKS ;JUST MAKE SURE CLOCK IS STILL GOING. + INC TICKS ;UPDATE CLOCKS. + INC TIME ;INCREMENT BOTH CLOCKS. + BIT #17,TIME ;SEE IF IT'S TIME TO CLEAR ARROWS. + BNE TIMERT ;NOPE. EXIT. + CLR DLIST1 ;YES. CLEAR THEM. + CLR DLIST2 +TIMERT: RTI ;AND RETURN NOW. + .PAGE +; +; THIS IS THE DELAY ROUTINE. +; IT WILL WAIT "N" SECONDS BEFORE RESTARTING THE SYSTEM. +; +DELAY: MOV #DISTOP,LPSW ;IF DELAYED CALLED, TURN OFF LOW FUEL MESSAGE. + MOV @0(SP),IN1 ;PICK UP THE TIME. + MOV TIME,IN2 ;GET CURRENT TIME. + MOV IN1,RET1 ;MOVE OVER TIME REQUESTED. + BPL DELAY1 ;IF POSITIVE, IT'S ALRIGHT. + NEG IN1 ;ELSE NEGATE IT NOW. +DELAY1: ADD #CLKFRQ,IN2 ;CALCULATE FUTURE TIME + DEC IN1 ;WAIT TILL MULTIPLICATION IS DONE. + BGT DELAY1 +DELAY2: WAIT ;WAIT FOR AN INTERUPT TO OCCUR. + JSR PC,DIAL ;WHILE WAITING, DISPLAY THE USER'S DATA. + CMP IN2,TIME ;CHECK THE TIMES NOW. + BHI DELAY2 + ADD #2,(SP) ;UPDATE THE RETURN PC NOW. + TST RET1 ;TEST SIGN OF THE WAIT. + BMI DVOKX ;IF NEGATIVE, THEN RETURN. + JMP RESTART ;ELSE RESTART THE SYSTEM. + .PAGE +; +; THIS IS THE START OF THE DISPLAY SECTION. PLEASE BE MERICFUL. +; +DISPLY: MOV IN1,-(SP) ;COMES HERE ON AN INTERUPT. + MOV IN2,-(SP) + MOV DSTACK,IN1 ;PICK UP OLD STACK. + MOV @DPC,IN2 ;FIND OUT WHY WE STOPPED. + BEQ DSUBRT ;DISPLAY SUBROUTINE RETURN. + MOV DPC,-(IN1) ;SUBROUTINE CALL. PUSH RETURN DPC ON STACK. + ADD #2,(IN1) ;AND FUDGE PAST POINTER. + MOV #GOTSUB,-(IN1) ;AND PUSH RETURN ADDRESS ONTO STACK. +DISRT: CMP (IN2),#DISTOP ;SEE IF WHERE HE WANTS TO START IS + BNE DISRST ;ANOTHER SUBROUTINE CALL. + TST 2(IN2) ;IF IT IS, THEN FIGURE OUT WHETHER + BEQ DSUBRT ;TO RETURN OR GO DOWN ONE LEVEL. + MOV IN2,-(IN1) ;PUSH NEXT DPC ONTO STACK. + ADD #4,(IN1) ;AND FUDGE IT UP A BIT. + MOV #GOTSUB,-(IN1) ;PUT ADDRESS ONTO STACK. + MOV 2(IN2),IN2 ;UPDATE NEW PC NOW. + BR DISRT ;AND LOOP AGAIN. +DISRST: MOV IN1,DSTACK ;SAVE THE STACK NOW. + MOV IN2,DPC ;START THE DISPLAY GOING NOW. + MOV (SP)+,IN2 ;RESTORE SAVED REGISTERS. + MOV (SP)+,IN1 + RTI ;AND RETURN NOW. +DSUBRT: MOV (IN1)+,PC ;GO TO SUBROUTINE NOW. +GOTSUB: MOV (IN1)+,IN2 ;PICK UP OLD DPC + BR DISRT ;AND RESTART AND CONTINUE. +DTOP: INC DNUM ;THIS ROUTINE GOES DOWN THE MASTER LIST. +DTOP2: MOV DNUM,IN2 + ASL IN2 ;MAKE INTO A GOOD INDEX. + MOV DLIST(IN2),IN2 + BNE DTOPOK ;IT'S OK TO START NOW. + CLR DNUM ;AT BOTTOM. LOOP. + BR DTOP2 +DTOPOK: MOV #DTOP,STACKD + MOV #STACKD,IN1 + BR DISRT + .PAGE +; +; LIGHT PEN HIT ROUTINE. +; +LIGHT: MOV IN1,-(SP) + MOV IN2,-(SP) ;SAVE REGISTERS NOW. + MOV DNUM,IN2 ;PICK UP THE INDEXED NUMBER NOW. + CMP IN2,OLDHIT ;SEE IF INDEX IS SAME AS PREVIOUS. + BEQ LIGHTG ;YES. MAYBE WE CAN PROCESS IT. + MOV #15.,HITCNT ;NOT SAME. SET UP HIT COUNTER + MOV IN2,OLDHIT ;AND THE OLD REGISTER NOW. + BR LPRESM ;AND EXIT NOW. +LIGHTG: DEC HITCNT ;HAVE WE BEEN HIT ENOUGH? + BPL LPRESM ;NO. GET OUT NOW. + ASL IN2 ;ELSE SHIFT THE INDEX OVER + JMP @LPTAB(IN2) ;AND GO PROCESS INTERUPT. + .PAGE +; +; THIS ROUTINE IS CALLED WHENEVER THE LIGHT PEN HITS +; THE THROTTLE BAR. +; +LPBARH: MOV YSR,IN2 ;GET THE Y COORDINATE. + BIC #-2000,IN2 ;MAKE IT JUST 10 BITS. + ADD #BARADD,IN2 ;ADD FUDGE FACTOR NOW. + MOV LPBARY,IN1 ;PICK UP OLD Y NOW. + ASL IN1 ;AND MULTIPLY IT BY 8. + ASL IN1 + ASL IN1 + SUB LPBARY,IN1 ;WE REALLY ONLY WANTED 7. + ADD IN1,IN2 ;NOW MAKE IT 7*OLD+NEW Y. + ASR IN2 + ASR IN2 + ASR IN2 ;NOW AVERAGE IT OUT. + MOV IN2,LPBARY ;SAVE THE Y VALUE NOW. + SUB #BARFDG,IN2 ;SUBTRACT BASE Y NOW. + ASR IN2 ;DIVIDE BY TWO. + CMP IN2,#MINTRS ;COMPARE AGAINST MINIMUM THRUST. + BPL LPBARP ;GREATER OR EQUAL. IT'S OK. + MOV #MINTRS,IN2 ;ELSE SET TO THE MINIMUM THRUST. +LPBARP: CMP #100.,IN2 ;LIKEWISE IF GREATER THEN 100, MAKE + BGE LPBARQ ;IT ONLY 100. + MOV #100.,IN2 +LPBARQ: MOV IN2,PERCNT ;SAVE AWAY THE VALUE NOW. +LPRESM: BIS #1,DPC ;RESUME THE DISPLAY NOW. + MOV (SP)+,IN2 ;RESTORE THE REGISTERS NOW. + MOV (SP)+,IN1 ;AND THEN EXIT. + RTI +LPIT1: MOV DLIST(IN2),IN2 ;GET POINTER TO USER'S DISPAY ITEM. + MOV LPFLG1,IN1 ;AND PICK UP PREVIOUS ITEM NOW. + BEQ LPIT1P ;IF ZERO, NO PREVIOUS BLINKING. + BIC #10,2(IN1) ;ELSE CLEAR OUT THE BLINK BITS. +LPIT1P: MOV IN2,LPFLG1 ;SAVE IT AWAY FOR DISPLAY TRANSFER. + BIS #30,2(IN2) ;SET IT BLINKING NOW. + BR LPRESM ;AND RESUME THE DISPLAY NOW. +LPIT2: MOV LPFLG1,IN1 ;GET HIS POINTER. + BEQ LPRESM ;NONE SPECIFIED. + CLR LPFLG1 ;CLEAR POINTER NOW. + MOV IN1,DIALTB-LPBASE+DLIST(IN2) ;CHANGE OUR POINTER NOW. + BIC #10,2(IN1) ;AND CLEAR THE BLINK FLAG NOW. + BR LPRESM ;AND RESUME THE DISPLAY NOW. +ARROW: MOV DLIST(IN2),IN2 ;ON ARROW HIT, COME HERE. PICK UP ADDRESS. + MOV -2(IN2),TURN ;AND MOVE OVER RATE OF TURN. + MOV IN2,DLIST1 ;AND ALSO MAKE IT BRIGHTER. + MOV IN2,DLIST2 + BR LPRESM ;AND RESUME NOW. + .PAGE +; +; DISPLAY POINTERS. +; +LPBASE: +DLIST: .WORD DITEM1 + .WORD DITEM2 + .WORD DITEM3 + .WORD DITEM4 + .WORD ITEME1 + .WORD ITEME2 + .WORD ITEME3 + .WORD ITEME4 + .WORD ITEME5 + .WORD ITEME6 + .WORD ITEME7 + .WORD ITEME8 + .WORD ITEME9 + .WORD ITEMET + .WORD ITEMEE + .WORD ITEMES + .WORD DRWSHP + .WORD ONFIRE + .WORD INFO + .WORD DRWDST + .WORD DRWLUN + .WORD SLEFTA + .WORD SRGTA + .WORD BLEFTA + .WORD BRGTA + .WORD LPBAR +DLIST1: .WORD 0 ;EXTRA BRIGHTNESS WORD +DLIST2: .WORD 0 ;IF DISPLAYING THE ARROWS. + .WORD 0 + .PAGE +; +; ;LIGHT PEN VECTORS. +; +LPTAB: .WORD LPIT2,LPIT2,LPIT2,LPIT2 + .WORD LPIT1,LPIT1,LPIT1,LPIT1 + .WORD LPIT1,LPIT1,LPIT1,LPIT1 + .WORD LPIT1,LPIT1,LPIT1,LPIT1 + .WORD DSUBRT,DSUBRT,DSUBRT,DSUBRT,DSUBRT + .WORD ARROW,ARROW,ARROW,ARROW + .WORD LPBARH + .WORD ARROW,ARROW ;TERMINATING LIGHT PEN HITS. + .PAGE +; +; THIS ROUTINE WILL CALCULATE THE VALUES THAT THE +; USER WISHES TO HAVE DISPLAYED. +; +DIAL: MOV IN1,-(SP) ;SAVE ALL THE IMPORTANT REGISTERS NOW. + MOV IN2,-(SP) + MOV RET1,-(SP) + MOV RET2,-(SP) + MOV TEMP,-(SP) + MOV TEMP2,-(SP) + CLR TEMP ;NOW SET POINTER TO FIRST ITEM. +DIALL: MOV DIALTB(TEMP),TEMP2 ;PICK UP POINTER TO AN ITEM ENTRY. + BEQ DIALD1 ;IF ZERO, THEN END OF LIST. + MOV DIALTC(TEMP),IN2 ;PICK UP POINTER TO WHERE TO + MOV TEMP2,RET2 ;DISPLAY CALCULATED VALUES. + ADD #10.,RET2 ;CALCULATE "ITEMFX" ENTRY ADDRESS. + MOV RET2,18.(IN2) ;AND INSERT IT IN THE DISJMP OF + MOV @-4(TEMP2),RET2 ;THE DITEMX TABLE. PICK UP USERS NUMBER NOW. + MOV -2(TEMP2),IN1 ;PICK UP THE DIVISOR . + BEQ DIALND ;NONE. DO NOT DIVIDE. DISPLAY AS IS. + TST RET2 ;NOW MAKE ANSWER POSITIVE. + BPL DIALLP + NEG RET2 +DIALLP: CLR RET1 ;GET RID OF THE HIGH PART. + JSR PC,DIVTWO ;DO THE DIVISION NOW. + TST @-4(TEMP2) ;NOW RESTORE THE SIGN. + BPL DIALND + NEG RET2 +DIALND: MOV DIALTC(TEMP),TEMP2 ;PICK UP DITEMX POINTER AGAIN. + MOV RET2,IN1 ;MOVE OVER NUMBER NOW. + MOV #10.,IN2 ;NOW CREATE ADDRESS OF WHERE TO LEAVE ANSWER + ADD TEMP2,IN2 ;AFTER CONVERTING TO ASCII STRING. + JSR PC,SASCII ;DO THE CONVERSION NOW. + TST (TEMP)+ ;FINALLY INCREMENT POINTER TO NEXT ITEM. + BR DIALL ;AND GO BACK UP TO TOP AND GET NEXT VALUE. +DIALD1: CMP PERCNT,OLDPER ;CONVERT PERCENTAGE NOW. ANY CHANGE? + BEQ DIALRT ;NO. JUST EXIT. + MOV #LPBARC,IN2 ;YES. GET ADDRESS OF WHERE TO PLACE STRING. + MOV PERCNT,IN1 ;GET THE NUMBER NOW. + MOV IN1,OLDPER ;UPDATE OLD PERCENTAGE NOW. + JSR PC,SASCII ;AND CONVERT IT NOW. +DIALRT: MOV (SP)+,TEMP2 ;RESTORE ALL THE ACTIVE REGISTERS NOW. + MOV (SP)+,TEMP + MOV (SP)+,RET2 + MOV (SP)+,RET1 + MOV (SP)+,IN2 + MOV (SP)+,IN1 + RTS PC ;AND RETURN NOW. + .PAGE +; +; THIS ROUTINE CONVERT THE BINARY NUMBER (UNSIGNED) +; IN THE REGISTER "IN1" INTO AN ASCII STRING SIX +; CHARACTERS LONG AND LEAVES THE ANSWER TO WHERE "IN2" +; POINTS TO. THE ANSWER IS PUT RIGHT JUSTIFIED WITH +; LEADING BLANKS. +; +ASCII: MOVB #' ,(IN2)+ ;FIRST CHARACTER WILL BE BLANK ALWAYS. + CMP IN1,#10000. ;IS IT GREATER THEN 9999.? + BHIS ASCIIG ;YES. DO SOMETHING SPECIAL. + MOVB #' ,(IN2)+ ;NO. JUST INSERTA BLANK. + CLR -(SP) ;AND REMEMBER TO DELETE LEADING ZEROS. +ASCIIL: CMP IN1,#100. ;IS IT GREATER THAN 99? + BLT ASCIID ;NO! NO DIVIDE IS NECESSARY. + MOV IN1,RET2 ;GREATER THAN 99. DIVIDE. + CLR RET1 ;CLEAR HIGH ORDER WORD OF AC-MQ. + MOV #100.,IN1 ;DIVIDE BY 100. + JSR PC,DIVTWO ;DIVIDE NOW. + ASL RET2 ;NOW LOOK UP ANSWER IN TABLE. + ADD #TENTAB,RET2 ;TWO BYTES WHICH COMPOSE NEXT TWO DIGITS. +ASCIIB: JSR PC,ASCDO ;INSERT FIRST. + JSR PC,ASCDO ;INSERT SECOND. + MOV RET1,RET2 ;GET THE REMAINDER NOW. + ASL RET2 + ADD #TENTAB,RET2 ;AND MAKE IT A GOOD ADDRESS. + JSR PC,ASCDO ;AND DO THE NEXT TWO DIGITS. + MOV PC,(SP) ;BUT MAKE SURE WE GET A GOOD ZERO. + JSR PC,ASCDO + ADD #2,SP ;BUMP THE STACK NOW. + RTS PC ;AND RETURN. +ASCIIG: MOV PC,-(SP) ;UPDATE LEADING ZERO FLAG TO NO DELETE. + MOVB #'0,(IN2)+ ;INSERT IT INTO THE BUFFER NOW. +ASCIIM: CMP IN1,#10000. ;SEE IF IT'S STILL ABOVE 9999. + BLO ASCIIL ;NO. EXIT + INCB -1(IN2) ;YES CHANGE DIGIT AND UPDATE. + SUB #10000.,IN1 + BR ASCIIM ;AND LOOP TILL DONE. +ASCIID: MOV IN1,RET1 ;SMALL NUMBER. SET UP REMAINDER. + MOV #TENTAB,RET2 ;AND ADDRESS FOR THE FIRST 0. + BR ASCIIB ;AND INSERT THEM NOW. +ASCDO: TST 2(SP) ;INSERT ANYTHING? + BNE ASCDBP ;YES. + CMPB (RET2),#'0 ;NO. IS THIS CHARACTER A ZERO? + BNE ASCDO1 ;NO. FIRST GOOD CHARACTER. + MOVB #' ,(IN2)+ ;STILL ZERO. INSERT A BLANK. + INC RET2 ;AND BOP INPUT POINTER. + RTS PC ;AND RETURN NOW. +ASCDO1: MOV SP,2(SP) ;GOOD CHARACTER. CLEAR ZERO FLAG. +ASCDBP: MOVB (RET2)+,(IN2)+ ;AND MOVE OVER THE CHARACTER NOW. + RTS PC ;AND THEN RETURN. + .PAGE +; +; THIS ROUTINE WILL CONVERT A SIGNED NUMBER TO AN ASCII +; STRING ACCORDING TO THE RULES USED IN "ASCII". +; +SASCII: TST IN1 ;GET THE SIGN OF THE INPUT. + BPL ASCII ;IF POSITIVE, NOTHING SPECIAL. + NEG IN1 ;ELSE NEGATE IT. + JSR PC,ASCII ;AND CONVERT IT. + MOV IN2,IN1 ;MOV BACK LAST POINTER. +SASCIL: CMPB #' ,-(IN1) ;AND LOOK FOR THE FIRST BACKWARD BLANK. + BNE SASCIL + MOVB #'-,(IN1) ;WHEN FOUND, CHANGE IT. + RTS PC ;AND RETURN NOW. + .PAGE +; +; THESE LISTS ARE USED IN PRINTING OUT THE USER +; REQUESTED VALUES. +; +DIALTB: .WORD ITEME1 + .WORD ITEME2 + .WORD ITEME3 + .WORD ITEME4 + .WORD 0 ;0=END OF LIST. +DIALTC: .WORD DITEM1 ;WHERE OUR TABLES ARE. + .WORD DITEM2 + .WORD DITEM3 + .WORD DITEM4 +; +; VALUE DISPLAY ITEMS. +; +DITEM1: .WORD 170240 ;ENABLE LIGHT PEN STUFF. + .WORD 117560 ;AND MOVE THE POINTER AROUND. + .WORD DX1 + .WORD DY1 + .WORD 100000 ;ENTER CHARACTER MODE NOW. + .ASCII ' ' ;SIX CHARACTERS OF ZERO, + .WORD DISJMP ;AND NOW CALL THE NEXT SUBROUTINE. + .WORD ITEMF1 +DITEM2: .WORD 170240 + .WORD 117560 + .WORD DX2 + .WORD DY2 + .WORD 100000 + .ASCII ' ' + .WORD DISJMP + .WORD ITEMF2 +DITEM3: .WORD 170240 + .WORD 117560 + .WORD DX3 + .WORD DY3 + .WORD 100000 + .ASCII ' ' + .WORD DISJMP + .WORD ITEMF3 +DITEM4: .WORD 170240 + .WORD 117560 + .WORD DX4 + .WORD DY4 + .WORD 100000 + .ASCII ' ' + .WORD DISJMP + .WORD ITEMF4 +; +; THESE TABLES CONTAIN THE ACTUAL MESSAGES THAT THE +; USER HAS A CHOICE OF SEEING. +; +ITEM1: .WORD RADARY + .WORD 0 ;WHERE ITEM IS AND WHAT TO DIVIDE IT BY. +ITEME1: .WORD 170260 ;ACTUALLY DISPLAY PORTION HERE. + .WORD 117560 + .WORD ITEMX1 + .WORD ITEMY1 + .WORD 100000 +ITEMF1: .ASCII ' HEIGHT ' + .WORD DISTOP + .WORD 0 +ITEM2: .WORD VERDIS + .WORD 0 +ITEME2: .WORD 170260 + .WORD 117560 + .WORD ITEMX2 + .WORD ITEMY2 + .WORD 100000 +ITEMF2: .ASCII ' ALTITUDE ' + .WORD DISTOP + .WORD 0 +ITEM3: .WORD HORDIS + .WORD 0 +ITEME3: .WORD 170260 + .WORD 117560 + .WORD ITEMX3 + .WORD ITEMY3 + .WORD 100000 +ITEMF3: .ASCII ' DISTANCE ' + .WORD DISTOP + .WORD 0 +ITEM4: .WORD FUEL + .WORD 10. +ITEME4: .WORD 170260 + .WORD 117560 + .WORD ITEMX4 + .WORD ITEMY4 + .WORD 100000 +ITEMF4: .ASCII ' FUEL LEFT' + .WORD DISTOP + .WORD 0 +ITEM5: .WORD WEIGHT + .WORD 0 +ITEME5: .WORD 170260 + .WORD 117560 + .WORD ITEMX5 + .WORD ITEMY5 + .WORD 100000 +ITEMF5: .ASCII ' WEIGHT ' + .WORD DISTOP + .WORD 0 +ITEM6: .WORD THRUST + .WORD 0 +ITEME6: .WORD 170260 + .WORD 117560 + .WORD ITEMX6 + .WORD ITEMY6 + .WORD 100000 +ITEMF6: .ASCII ' THRUST ' + .WORD DISTOP + .WORD 0 +ITEM7: .WORD ANGLE + .WORD 0 +ITEME7: .WORD 170260 + .WORD 117560 + .WORD ITEMX7 + .WORD ITEMY7 + .WORD 100000 +ITEMF7: .ASCII ' ANGLE' + .WORD DISTOP + .WORD 0 +ITEM8: .WORD VERVEL + .WORD 10. +ITEME8: .WORD 170260 + .WORD 117560 + .WORD ITEMX8 + .WORD ITEMY8 + .WORD 100000 +ITEMF8: .ASCII ' VER VEL' + .WORD DISTOP + .WORD 0 +ITEM9: .WORD HORVEL + .WORD 10. +ITEME9: .WORD 170260 + .WORD 117560 + .WORD ITEMX9 + .WORD ITEMY9 + .WORD 100000 +ITEMF9: .ASCII ' HOR VEL' + .WORD DISTOP + .WORD 0 +ITEM10: .WORD VERACC + .WORD 500. +ITEMET: .WORD 170260 + .WORD 117560 + .WORD ITEMXT + .WORD ITEMYT + .WORD 100000 +ITEMFT: .ASCII ' VER ACC' + .WORD DISTOP + .WORD 0 +ITEM11: .WORD HORACC + .WORD 500. +ITEMEE: .WORD 170260 + .WORD 117560 + .WORD ITEMXE + .WORD ITEMYE + .WORD 100000 +ITEMFE: .ASCII ' HOR ACC' + .WORD DISTOP + .WORD 0 +ITEM12: .WORD TIME + .WORD 60. +ITEMES: .WORD 170260 + .WORD 117560 + .WORD ITEMXS + .WORD ITEMYS + .WORD 100000 +ITEMFS: .ASCII ' SECONDS' + .WORD DISTOP + .WORD 0 + .PAGE +; +; THIS IS WHERE THE MOON GOES, WHEN IT IS CORRECTLY +; DRAWN. IT IS PLACED HERE SO NO CODE GOES OVER 15000-20000 +; AND SO THAT NO CODE GOES OVER 35000-37776 EITHER. THIS AREA +; IS INITIALIZED TO ALL "DISTOP,0" BY THE RESTART ROUTINE. +; +MOONST: ;DEFINE IT AS STARTING HERE. + .=.+2002. ;AND BEING 1000 DECIMAL WORDS LONG. +MOONEN: ;NEXT WORD AFTER MOON TO DETERMINE + ;HOW FAR TO INITIALIZE THIS SECTION. +; +; MESSAGES FOR GOING OFF SCREEN . +; +LFTMSG: .WORD 117520 + .WORD 30. + .WORD 600. + .WORD 100000 + .ASCII 'BOY, ARE YOU' + .BYTE 0 + .=.-1 + .EVEN + .WORD 103730 + .ASCII ' INEPT' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +RGTMSG: .WORD 117520 + .WORD 525. + .WORD 600. + .WORD 100000 + .ASCII ' YOU HAVE JUST CRASHED' + .BYTE 0 + .=.-1 + .EVEN + .WORD 117520 + .WORD 525. + .WORD 570. + .WORD 100000 + .ASCII 'INTO THE EDGE OF THE MOON' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +TOPMSG: .WORD 117520 + .WORD 50. + .WORD 650. + .WORD 100000 + .ASCII 'SORRY, BUT WHEN YOU LOSE TV COVERAGE, YOU ALSO LOSE YOUR FUEL' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 + .PAGE +; +; SPEED WARNING MASSAGES... +; +VFAST: .WORD 117530 + .WORD 100. + .WORD 2. + .WORD 100000 + .ASCII "TOO FAST. YOU'RE GOING TO CRASH" + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +FAST: .WORD 117520 + .WORD 100. + .WORD 700. + .WORD 100000 + .ASCII 'BETTER START SLOWING IT UP PRETTY SOON' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +N2FAST: .WORD 117520 + .WORD 100. + .WORD 2. + .WORD 100000 + .ASCII 'TAKE IT NICE AND EASY. A PERFECT LANDING IS UNDER 8 FPS' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +GREATM: .WORD 117520 + .WORD 100. + .WORD 600. + .WORD 100000 + .ASCII 'FANTASTIC, A PERFECT LANDING' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +GOODM: .WORD 117520 + .WORD 100. + .WORD 600. + .WORD 100000 + .ASCII 'CONGRATULATIONS ON A GOOD LANDING' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +ROUGHM: .WORD 117520 + .WORD 100. + .WORD 600. + .WORD 100000 + .ASCII 'THE LANDING WAS A LITTLE FAST' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +CRIPM: .WORD 117520 + .WORD 100. + .WORD 600. + .WORD 100000 + .ASCII 'THE LANDING WAS TOO FAST AND DAMAGE WAS DONE TO THE SHIP' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +DEADM: .WORD 117530 + .WORD 100. + .WORD 550. + .WORD 100000 + .ASCII 'WELL, YOU CERTAINLY BLEW THAT ONE. THERE WERE NO SURVIRORS' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +ANGLEM: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'BUT THE ANGLE WAS TOO GREAT AND THE SHIP TIPPED OVER' + .BYTE 0 + .=.-1 + .EVEN +ANGLEJ: .WORD 117520 + .WORD 100. + .WORD 540. + .WORD 100000 + .ASCII 'SORRY, BUT THERE WERE ' + .BYTE 0 + .=.-1 + .EVEN + .WORD 103630 + .ASCII 'NO' + .WORD 103520 + .ASCII ' SURVIVORS' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +SIDEM: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'BUT THE HORIZONTAL VELOCITY WAS TOO GREAT, AND YOU CRASHED ANYWAY' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD ANGLEJ ;DO A DISPLAY JUMP INTO ANGLEM. +BUMPYM: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'BUT THE TERRAIN IS TOO ROUGH, AND YOU TIPPED OVER' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD ANGLEJ +ROCKMS: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'YOU JUST CRASHED INTO THAT ROCK' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD ANGLEJ +OLDMS: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'YOU JUST CRASHED ON TOP OF AN OLD LUNAR MODULE' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD ANGLEJ +FLAGMS: .WORD 117520 + .WORD 50. + .WORD 3. + .WORD 100000 + .ASCII 'YOU HAVE JUST VAPORIZED A PREVIOUSLY PLANTED AMERICAN FLAG' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +OLDTLT: .WORD 117520 + .WORD 100. + .WORD 570. + .WORD 100000 + .ASCII 'NICE WORK. YOU JUST CRASHED INTO A PREVIOUSLY CRASHED SHIP' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD ANGLEJ +MACDED: .WORD 117520 + .WORD 10. + .WORD 570. + .WORD 100000 + .ASCII 'W' + .BYTE 145,154,154 + .ASCII ', ' + .BYTE 171,157,165 + .ASCII "'" + .BYTE 166,145,40,152,165,163,164,40,144,145,163 + .BYTE 164,162,157,171,145,144,40,164,150,145,40 + .BYTE 157,156,154,171 + .ASCII ' M' + .BYTE 141,143 + .ASCII 'D' + .BYTE 157,156,141,154,144 + .ASCII "'" + .BYTE 163 + .BYTE 0 + .=.-1 + .EVEN + .WORD 117520 + .WORD 10. + .WORD 540. + .WORD 100000 + .BYTE 157,156,40,164,150,145,40,155,157,157,156 + .ASCII '. W' + .BYTE 150,141,164,40,141 + .ASCII ' CLOD.' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +ORDER: .WORD 117520 + .WORD 150. + .WORD 2. + .WORD 100000 + .WORD 170260 + .ASCII 'TWO CHEESEBURGERS AND A BIG MAC TO GO.' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 +MANMSG: .WORD 117520 + .WORD 50. + .WORD 2. + .WORD 100000 + .WORD 170260 + .ASCII "THAT'S ONE SMALL STEP FOR A MAN, ONE GIANT LEAP FOR MANKIND." + .BYTE 0 + .=.-1 + .EVEN + .WORD DISTOP + .WORD 0 + .PAGE +; +; THIS LITTLE SECTION CONTAINS THE CODE +; FOR DRAWING THE CONTROLLING ARROWS +; FOR HANDLING THE DEGREES OF ROTATION. +; SMALL LEFT ARROW. +; + .WORD -15. +SLEFTA: .WORD 114020 + .WORD 170240 + .WORD SLFTAX + .WORD SLFTAY + .WORD 113144 + .WORD 20.+LEFT+INT + .WORD 0. +LEFTC: .WORD 12.+INT + .WORD 8. + .WORD 12.+LEFT + .WORD 8.+DOWN + .WORD 12.+INT + .WORD 8.+DOWN + .WORD DISTOP + .WORD 0 + .WORD -100. +BLEFTA: .WORD 114020 + .WORD 170240 + .WORD BLFTAX + .WORD BLFTAY + .WORD 113144 + .WORD 40.+LEFT+INT + .WORD 0 + .WORD DISJMP + .WORD LEFTC + .WORD 15. +SRGTA: .WORD 114020 ;SMALL RIGHT ARROW. + .WORD 170240 + .WORD SRGTAX + .WORD SRGTAY + .WORD 113144 + .WORD 20.+INT + .WORD 0 +RGTC: .WORD 12.+INT+LEFT + .WORD 8. + .WORD 12. + .WORD 8.+DOWN + .WORD 12.+LEFT+INT + .WORD 8.+DOWN + .WORD DISTOP + .WORD 0 + .WORD 100. +BRGTA: .WORD 114020 + .WORD 170240 + .WORD BRGTAX + .WORD BRGTAY + .WORD 113144 + .WORD 40.+INT + .WORD 0 + .WORD DISJMP + .WORD RGTC + .PAGE +; +; THIS IS THE LIGHT PEN BAR WHICH CONTROLS THE +; THRUST OF THE ROCKET ENGINE. +; +LPBAR: .WORD 116764 + .WORD 170200 + .WORD BARLX+0 + .WORD BARTY + .WORD 110140 + .WORD INT + .WORD BARSIZ+DOWN + .WORD 3 + .WORD BARSIZ + .WORD INT + .WORD BARSIZ+DOWN + .WORD 3 + .WORD BARSIZ + .WORD INT + .WORD BARSIZ+DOWN + .WORD 114100 + .WORD BARMXR ;NOW MOVE OVER TO THE BAR POSITION. +LPBARY: .WORD 0 ;VERTICAL HEIGHT GOES HERE. + .WORD 110000 + .WORD BARMXL+INT ;BE CAREFULL OF SIGN OF THIS ONE. + .WORD 0 + .WORD BAREST + .WORD 0 + .WORD 100000 ;ENTER CHARACTER MODE NOW. +LPBARC: .ASCII ' % ' ;OVERLAYED WITH A NUMBER. +LPSW: .WORD DISTOP ;0 ON FUEL LOW--FALL TO NEXT MSG + .WORD 0 + .WORD 117130 + .WORD 350. + .WORD 700. + .WORD 100000 + .ASCII 'FUEL LOW' + .WORD DISTOP + .WORD 0 + .PAGE +; +; ;THIS IS THE BASIC ROCK COMMANDS. +; +ROCKL: .WORD 116727 + .WORD 170240 +ROCKX: .WORD 0 +ROCKY: .WORD 0 + .WORD 104000 + .WORD 14.+OTHER*200+8.+OTHER + .WORD OTHER+6+INTTWO*200+8. + .WORD 4+INTTWO*200+6 + .WORD 0+INTTWO*200+6 + .WORD 2+INTTWO*200+2 + .WORD 2+INTTWO*200+4 + .WORD 6+INTTWO*200+6 + .WORD INTTWO*200+4 + .WORD 4+INTTWO*200+2 + .WORD 2+INTTWO*200+0 + .WORD 2+INTTWO*200+2+OTHER + .WORD 6+INTTWO*200+2+OTHER + .WORD 4+INTTWO*200+2+OTHER + .WORD 2+INTTWO*200+6+OTHER + .WORD 6+INTTWO*200+6+OTHER + .WORD INTTWO*200+4+OTHER + .WORD 2+INTTWO*200+4+OTHER + .WORD 2+OTHER+INTTWO*200+4+OTHER + .WORD 2+OTHER+INTTWO*200+8.+OTHER + .WORD DISTOP + .WORD 0 +ROCKEN: ;NEXT LOCATION AFTER ROCKS. + .PAGE +; +; THIS LIST EXPLAINS HOW TO DRAW THE MACDONALD'S. +; +MACS: 117724 + 170240 +MACX: .WORD 0 +MACY: .WORD 0 + .WORD 104000 + .WORD 18.*200 + .WORD 107000 + .WORD 30.+INT + .WORD 54.*200+INT + .WORD 30.+OTHER+INT + .WORD 54.+OTHER*200+INT + .WORD 105324 + .WORD 12.*200 + .WORD 8.+INT + .WORD 6.*200+INT + .WORD 8.+OTHER+INT + .WORD 19.+OTHER*200 + .WORD 110000 + .WORD 73.+LEFT + .WORD 0. + .WORD DISTOP + .WORD ARCH + .WORD 104000 + .WORD 22.*200 +; +; NOTICE HOW I FALL THROUGH TO DRAW THE +; SECOND ARCH. CLEVER, CLEVER. +; +ARCH: .WORD 107724 + .WORD 17.+OTHER*200+OTHER+3. + .WORD 1*200+10.+INT + .WORD 1*200+9.+INT + .WORD 1*200+6+INT + .WORD 1*200+5+INT + .WORD 1*200+4+INT + .WORD 1*200+2+INT + .WORD 1*200+4+INT + .WORD 2*200+5+INT + .WORD 1*200+1+INT + .WORD 2*200+4+INT + .WORD 3*200+2+INT + .WORD 1*200+1+INT + .WORD 2*200+0+INT + .WORD 1*200+1+INT+OTHER + .WORD 3*200+2+INT+OTHER + .WORD 2*200+4+INT+OTHER + .WORD 1*200+1+INT+OTHER + .WORD 2*200+5+INT+OTHER + .WORD 1*200+4+INT+OTHER + .WORD 1*200+2+INT+OTHER + .WORD 1*200+4+INT+OTHER + .WORD 1*200+5+INT+OTHER + .WORD 1*200+6+INT+OTHER + .WORD 1*200+9.+INT+OTHER + .WORD 1*200+10.+INT+OTHER + .WORD 17.+OTHER*200+3. + .WORD DISTOP + .WORD 0 + .PAGE +; +; THIS LIST EXPLAINS HOW TO DRAW A MAN. +; +MAN: .WORD 116720 ;DON'T MAKE HIM TOO BRIGHT. +MANX: .WORD 0 +MANY: .WORD 0 + .WORD 104000 ;ALL SHORT VECTORS. + .WORD 400 ;INVISIBLE 2 RIGHT. + .WORD INT+20000+404 ;LEFT TWO, UP FOUR. + .WORD INT+20000+1104 ;LEFT FOUR, DOWN 4. + .WORD 1004 ;INVISIBLE, UP 4, RIGHT 4 + .WORD INT+5 ;UP FIVE. + .WORD INT+200 ;RIGHT ONE + .WORD INT+201 ;RIGHT ONE, UP ONE. + .WORD INT+1 ;UP ONE + .WORD INT+20000+201 ;LEFT ONE, UP ONE. + .WORD INT+20000+400 ;LEFT TWO. + .WORD INT+20000+301 ;LEFT ONE, DOWN ONE. + .WORD INT+101 ;DOWN ONE. + .WORD INT+301 ;DOWN ONE, RIGHT ONE. + .WORD INT+200 ;RIGHT ONE. + .WORD 101 ;DOWN ONE. + .WORD INT+1203 ;RIGHT FIVE, UP THREE. + .WORD 20000+1305 ;LEFT FIVE, DOWN FIVE. + .WORD INT+20000+1403 ;LEFT SIX, UP THREE. + .WORD DISTOP + .WORD 0 + .PAGE +; +; THIS LIST EXPLAINS HOW TO DRAW A FLAG. +; +FLAGL: .WORD 115324 + .WORD 170240 +FLAGX: .WORD 0 +FLAGY: .WORD 0 + .WORD 104000 + .WORD 18.+INT + .WORD 112727 + .WORD 16.+INT + .WORD 0 + .WORD INT + .WORD 8.+DOWN + .WORD 16.+INT+LEFT + .WORD 0 + .WORD 112326 + .WORD 0 + .WORD 3 + .WORD 16.+INT + .WORD 0 + .WORD 0 + .WORD 2 + .WORD 16.+INT+LEFT + .WORD 0 + .WORD DISTOP + .WORD 0 +FLAGEN: ;NEXT LOCATION AFTER FLAG. + .PAGE +; +; COMMANDS FOR DISPLAYING THE LUNAR MODULE. +; +DESIGN: .WORD DRAWIN,170200 ;LOAD STATUS. + .WORD DRAWIN,107124 ;AND SHORT VECTORS, INTENSITY 4. + .WORD DRAWIS ;DRAW BODY OF SHIP NOW. + .BYTE -6.,0. + .WORD DRAWVS + .BYTE -14.,8. + .WORD DRAWVS + .BYTE -14.,20. + .WORD DRAWVS + .BYTE -6.,29. + .WORD DRAWVS + .BYTE 6.,29. + .WORD DRAWVS + .BYTE 14.,20. + .WORD DRAWVS + .BYTE 14.,8. + .WORD DRAWVS + .BYTE 6.,0. + .WORD DRAWVS + .BYTE -6.,0. ;TOP OF SHIP DONE . + .WORD DRAWIS + .BYTE -17.,0. + .WORD DRAWVS + .BYTE -17.,-16. + .WORD DRAWVS + .BYTE 17.,-16. + .WORD DRAWVS + .BYTE 17.,0. + .WORD DRAWVS + .BYTE -17.,0. ;LOWER BODY OF SHIP DONE. + .WORD DRAWIN,107524 ;CHANGE TO LEVEL 3 INTENSITY. + .WORD DRAWVS ;DRAW LANDING LEGS NOW. + .BYTE -32.,-24. + .WORD DRAWIS ;POSITION OVER TO OTHER SIDE. + .BYTE 17.,0. + .WORD DRAWVS + .BYTE 32.,-24. + .WORD DRAWIN,106324 ;LEVEL ONE INTENSITY. + .WORD DRAWIS + .BYTE -17.,-14. + .WORD DRAWVS + .BYTE -28.,-18. + .WORD DRAWIS + .BYTE 17.,-14. + .WORD DRAWVS + .BYTE 28.,-18. ;LOWER LANDING BRACE DONE. + .WORD DRAWIN,107124 ;INTENSITY 4 FOR LANDING PODS. + .WORD DRAWIS + .BYTE 36.,-24. + .WORD DRAWVS + .BYTE 28.,-24. + .WORD DRAWIS + .BYTE -28.,-24. + .WORD DRAWVS + .BYTE -36.,-24. ;END OF LANDING PODS. + .WORD DRAWIS ;DRAW THE ENGINE NOW. + .BYTE -3.,-16. + .WORD DRAWVS + .BYTE -7.,-21. + .WORD DRAWVS + .BYTE 7.,-21. + .WORD DRAWVS + .BYTE 3.,-16. ;END OF THE ENGINE. + .WORD DRAWIS ;NOW BRING VECTOR BACK UP TO CENTER + .BYTE 0,0 ;OF THE LUNAR MODULE. + .WORD DRAWDN ;AND TERMINATE THE PICTURE. + .PAGE +; +; THESE TABLES CONTROL THE DRAWING OF THE ROCKET +; ENGINE FLAME, AND ALL IT'S PURTIBATIONS. +; Y THRUST TABLE ACCORDING TO PERCENTAGE THROTTLE. +; 13 SEGMENTS, EACH ONE APPROX 8% THROTTLE. +; +YTHRST: .BYTE 0.,-30.,-31.,-32.,-34.,-36.,-38.,-41.,-44.,-47.,-50.,-53.,-56. + +; +; Y UP DOWN IS A TABLE WHICH WILL SORT OF +; RANDOMIZE THE HEIGHT OF THE FLAME AND SHOULD ENHANCE THE +; FLICKERING APPEARANCE. +; +YUPDWN: .BYTE 0,1,3,6,4,3,1,-2,-6,-7,-5,-2,2,3,5,6,2,1 + .BYTE -1,-4,-6,-5,-3,0,4,5,7,4,0,-1,-3,-1 +; +; "FLAME BOTTOM" CONTAINS THE TABLE OF THE X VALUES +; FOR THE BOTTOM OF THE ROCKET FLAME. THEY ARE INDEXED SLIGHTLY +; RANDOMLY AT TIMES. +; +FLAMBT: .BYTE -20.,-16.,-13.,-10.,-7.,-4.,-2. + .BYTE 0.,2.,4.,7.,10.,13.,16.,20. +; +; THIS SECTION CONTAINS THE ACTUAL LIST OF COMMANDS TO +; BE FOLLOWED WHEN DRAWING THE ROCKET FLAME. +; + .EVEN ;REALIGN NOW IF NECESSARY. +FLAMDO: .WORD DRAWIN,170200 ;LOAD STATUS PROPERLY. + .WORD DRAWIN ;INSERT COMMAND NOW. +FLAMEX: .WORD 0 ;FLAME COMMAND GOES HERE. + .WORD DRAWIS ;MOVE POINTER OVER TO BOTTOM + .BYTE -6.,-21. ;OFF THE ROCKET ENGINE. + .WORD DRAWVS ;NOW DRAW THE VECTORS +FLAMXS: .BYTE 0.,0. ;WHICH WE SHOULD SET UP HERE. + .WORD DRAWVS ;AND MOVE BACK UP AGAIN. + .BYTE -5.,-21. ;BOTTOM OF THE ENGINE. + .WORD DRAWVS + .BYTE 0.,0. ;OVERLAYED HERE ALSO. + .WORD DRAWVS + .BYTE -4.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE -3.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE -2.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE -1.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 0.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 1.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 2.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 3.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 4.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 5.,-21. + .WORD DRAWVS + .BYTE 0.,0. + .WORD DRAWVS + .BYTE 6.,-21. + .WORD DRAWIS ;RETURN TO CENTER NOW. + .BYTE 0.,0. + .WORD DRAWDN ;AND END THE COMMAND LIST. + FLEN=12. ;NUMBER OF ITEMS TO INSERT IN THE TABLE. + .PAGE +; +; THESE ARE THE HIDEOUS TABLES THAT THE +; SYSTEM NEEDS TO FUNCTION PROPERLY. THEY INCLUDE +; TERRAIN TABLES (ALTITUDE), FEATURE TABLES (ROCKS, +; OLD SHIPS, ETC.), CONVERSION TABLES, AND THE +; SINE AND COSINE TABLES. THEY SHOULD BE BETWEEN +; 20000 AND 35000 OCTAL (LOCATION), OR YOU CAN BE SCREWED. +; THIS IS THE CONVERSION TABLE FROM A BINARY +; NUMBER LESS THAN 100 TO AN ASCII STRING. SEE THE +; SUBROUTINE "ASCII". +; +TENTAB: .BYTE '0,'0 + .BYTE '0,'1 + .BYTE '0,'2 + .BYTE '0,'3 + .BYTE '0,'4 + .BYTE '0,'5 + .BYTE '0,'6 + .BYTE '0,'7 + .BYTE '0,'8 + .BYTE '0,'9 + .BYTE '1,'0 + .BYTE '1,'1 + .BYTE '1,'2 + .BYTE '1,'3 + .BYTE '1,'4 + .BYTE '1,'5 + .BYTE '1,'6 + .BYTE '1,'7 + .BYTE '1,'8 + .BYTE '1,'9 + .BYTE '2,'0 + .BYTE '2,'1 + .BYTE '2,'2 + .BYTE '2,'3 + .BYTE '2,'4 + .BYTE '2,'5 + .BYTE '2,'6 + .BYTE '2,'7 + .BYTE '2,'8 + .BYTE '2,'9 + .BYTE '3,'0 + .BYTE '3,'1 + .BYTE '3,'2 + .BYTE '3,'3 + .BYTE '3,'4 + .BYTE '3,'5 + .BYTE '3,'6 + .BYTE '3,'7 + .BYTE '3,'8 + .BYTE '3,'9 + .BYTE '4,'0 + .BYTE '4,'1 + .BYTE '4,'2 + .BYTE '4,'3 + .BYTE '4,'4 + .BYTE '4,'5 + .BYTE '4,'6 + .BYTE '4,'7 + .BYTE '4,'8 + .BYTE '4,'9 + .BYTE '5,'0 + .BYTE '5,'1 + .BYTE '5,'2 + .BYTE '5,'3 + .BYTE '5,'4 + .BYTE '5,'5 + .BYTE '5,'6 + .BYTE '5,'7 + .BYTE '5,'8 + .BYTE '5,'9 + .BYTE '6,'0 + .BYTE '6,'1 + .BYTE '6,'2 + .BYTE '6,'3 + .BYTE '6,'4 + .BYTE '6,'5 + .BYTE '6,'6 + .BYTE '6,'7 + .BYTE '6,'8 + .BYTE '6,'9 + .BYTE '7,'0 + .BYTE '7,'1 + .BYTE '7,'2 + .BYTE '7,'3 + .BYTE '7,'4 + .BYTE '7,'5 + .BYTE '7,'6 + .BYTE '7,'7 + .BYTE '7,'8 + .BYTE '7,'9 + .BYTE '8,'0 + .BYTE '8,'1 + .BYTE '8,'2 + .BYTE '8,'3 + .BYTE '8,'4 + .BYTE '8,'5 + .BYTE '8,'6 + .BYTE '8,'7 + .BYTE '8,'8 + .BYTE '8,'9 + .BYTE '9,'0 + .BYTE '9,'1 + .BYTE '9,'2 + .BYTE '9,'3 + .BYTE '9,'4 + .BYTE '9,'5 + .BYTE '9,'6 + .BYTE '9,'7 + .BYTE '9,'8 + .BYTE '9,'9 + .PAGE +; +; THIS TABLE HOLDS THE TERAIN OF THE MOON IN +; FEET ABOVE THE MEAN HEIGHT. IT GOES SOMEEWHAT FORWARD AND +; BACKWARD BECAUSE THE PROGRAM MAY "SCAN" A LITTLE BIT. +; + .WORD 718. ;X=-10 + .WORD 718. ;X= -9 + .WORD 718. ;X= -8 + .WORD 750. ;X= -7 + .WORD 750. ;X= -6 + .WORD 750. ;X= -5 + .WORD 782. ;X= -4 + .WORD 782. ;X= -3 + .WORD 782. ;X= -2 + .WORD 814. ;X= -1 +TERAIN: .WORD 780. ;X= 0 + .WORD 750. ;X= 1 + .WORD 703. ;X= 2 + .WORD 650. ;X= 3 + .WORD 620. ;X= 4 + .WORD 575. ;X= 5 + .WORD 500. ;X= 6 + .WORD 420. ;X= 7 + .WORD 400. ;X= 8 + .WORD 350. ;X= 9 + .WORD 270. ;X= 10 + .WORD 246. ;X= 11 + .WORD 200. ;X= 12 + .WORD 180. ;X= 13 + .WORD 107. ;X= 14 + .WORD 24. ;X= 15 + .WORD 54. ;X= 16 + .WORD 53. ;X= 17 + .WORD 51. ;X= 18 + .WORD 82. ;X= 19 + .WORD 80. ;X= 20 + .WORD 78. ;X= 21 + .WORD 109. ;X= 22 + .WORD 107. ;X= 23 + .WORD 74. ;X= 24 + .WORD 72. ;X= 25 + .WORD 70. ;X= 26 + .WORD 69. ;X= 27 + .WORD 99. ;X= 28 + .WORD 98. ;X= 29 + .WORD 128. ;X= 30 + .WORD 126. ;X= 31 + .WORD 125. ;X= 32 + .WORD 123. ;X= 33 + .WORD 122. ;X= 34 + .WORD 152. ;X= 35 + .WORD 182. ;X= 36 + .WORD 174. ;X= 37 + .WORD 166. ;X= 38 + .WORD 158. ;X= 39 + .WORD 181. ;X= 40 + .WORD 173. ;X= 41 + .WORD 165. ;X= 42 + .WORD 156. ;X= 43 + .WORD 148. ;X= 44 + .WORD 140. ;X= 45 + .WORD 131. ;X= 46 + .WORD 91. ;X= 47 + .WORD 83. ;X= 48 + .WORD 75. ;X= 49 + .WORD 182. ;X= 50 + .WORD 161. ;X= 51 + .WORD 236. ;X= 52 + .WORD 120. ;X= 53 + .WORD 67. ;X= 54 + .WORD 174. ;X= 55 + .WORD 153. ;X= 56 + .WORD 197. ;X= 57 + .WORD 80. ;X= 58 + .WORD 59. ;X= 59 + .WORD 866. ;X= 60 + .WORD 123. ;X= 61 + .WORD 201. ;X= 62 + .WORD 250. ;X= 63 + .WORD 275. ;X= 64 + .WORD 300. ;X= 65 + .WORD 375. ;X= 66 + .WORD 410. ;X= 67 + .WORD 579. ;X= 68 + .WORD 926. ;X= 69 + .WORD 1832. ;X= 70 + .WORD 1907. ;X= 71 + .WORD 2013. ;X= 72 + .WORD 2119. ;X= 73 + .WORD 2257. ;X= 74 + .WORD 2395. ;X= 75 + .WORD 2533. ;X= 76 + .WORD 2639. ;X= 77 + .WORD 2745. ;X= 78 + .WORD 2883. ;X= 79 + .WORD 3021. ;X= 80 + .WORD 3128. ;X= 81 + .WORD 3226. ;X= 82 + .WORD 3197. ;X= 83 + .WORD 3231. ;X= 84 + .WORD 3170. ;X= 85 + .WORD 3140. ;X= 86 + .WORD 3143. ;X= 87 + .WORD 3145. ;X= 88 + .WORD 3180. ;X= 89 + .WORD 3246. ;X= 90 + .WORD 3153. ;X= 91 + .WORD 3252. ;X= 92 + .WORD 3286. ;X= 93 + .WORD 3353. ;X= 94 + .WORD 3387. ;X= 95 + .WORD 3390. ;X= 96 + .WORD 3424. ;X= 97 + .WORD 3523. ;X= 98 + .WORD 3429. ;X= 99 + .WORD 3440. ;X=100 + .WORD 3450. ;X=101 + .WORD 3429. ;X=102 + .WORD 3407. ;X=103 + .WORD 3386. ;X=104 + .WORD 3396. ;X=105 + .WORD 3375. ;X=106 + .WORD 3321. ;X=107 + .WORD 3300. ;X=108 + .WORD 3246. ;X=109 + .WORD 3257. ;X=110 + .WORD 3203. ;X=111 + .WORD 3182. ;X=112 + .WORD 3128. ;X=113 + .WORD 3107. ;X=114 + .WORD 3085. ;X=115 + .WORD 3064. ;X=116 + .WORD 3074. ;X=117 + .WORD 3085. ;X=118 + .WORD 3095. ;X=119 + .WORD 3195. ;X=120 + .WORD 3167. ;X=121 + .WORD 3139. ;X=122 + .WORD 3239. ;X=123 + .WORD 2954. ;X=124 + .WORD 2926. ;X=125 + .WORD 2834. ;X=126 + .WORD 2710. ;X=127 + .WORD 2746. ;X=128 + .WORD 2718. ;X=129 + .WORD 2753. ;X=130 + .WORD 2469. ;X=131 + .WORD 2569. ;X=132 + .WORD 2509. ;X=133 + .WORD 2513. ;X=134 + .WORD 2580. ;X=135 + .WORD 2584. ;X=136 + .WORD 2620. ;X=137 + .WORD 2720. ;X=138 + .WORD 2820. ;X=139 + .WORD 2919. ;X=140 + .WORD 2859. ;X=141 + .WORD 2703. ;X=142 + .WORD 2739. ;X=143 + .WORD 2967. ;X=144 + .WORD 2906. ;X=145 + .WORD 3134. ;X=146 + .WORD 3042. ;X=147 + .WORD 2918. ;X=148 + .WORD 2858. ;X=149 + .WORD 2759. ;X=150 + .WORD 2468. ;X=151 + .WORD 2498. ;X=152 + .WORD 2399. ;X=153 + .WORD 2396. ;X=154 + .WORD 2362. ;X=155 + .WORD 2071. ;X=156 + .WORD 1940. ;X=157 + .WORD 1970. ;X=158 + .WORD 2063. ;X=159 + .WORD 2028. ;X=160 + .WORD 1930. ;X=161 + .WORD 1799. ;X=162 + .WORD 1668. ;X=163 + .WORD 1762. ;X=164 + .WORD 1823. ;X=165 + .WORD 1660. ;X=166 + .WORD 1626. ;X=167 + .WORD 1527. ;X=168 + .WORD 1428. ;X=169 + .WORD 1650. ;X=170 + .WORD 1615. ;X=171 + .WORD 1676. ;X=172 + .WORD 1770. ;X=173 + .WORD 1703. ;X=174 + .WORD 1636. ;X=175 + .WORD 1666. ;X=176 + .WORD 1599. ;X=177 + .WORD 1436. ;X=178 + .WORD 1402. ;X=179 + .WORD 1431. ;X=180 + .WORD 1332. ;X=181 + .WORD 1426. ;X=182 + .WORD 1647. ;X=183 + .WORD 1516. ;X=184 + .WORD 1354. ;X=185 + .WORD 1319. ;X=186 + .WORD 1380. ;X=187 + .WORD 1090. ;X=188 + .WORD 1055. ;X=189 + .WORD 1148. ;X=190 + .WORD 1146. ;X=191 + .WORD 1207. ;X=192 + .WORD 1172. ;X=193 + .WORD 1202. ;X=194 + .WORD 1071. ;X=195 + .WORD 780. ;X=196 + .WORD 746. ;X=197 + .WORD 711. ;X=198 + .WORD 933. ;X=199 + .WORD 1092. ;X=200 + .WORD 1348. ;X=201 + .WORD 1539. ;X=202 + .WORD 1827. ;X=203 + .WORD 1858. ;X=204 + .WORD 2114. ;X=205 + .WORD 2337. ;X=206 + .WORD 2497. ;X=207 + .WORD 2624. ;X=208 + .WORD 2752. ;X=209 + .WORD 2847. ;X=210 + .WORD 3007. ;X=211 + .WORD 3166. ;X=212 + .WORD 3422. ;X=213 + .WORD 3581. ;X=214 + .WORD 3709. ;X=215 + .WORD 3964. ;X=216 + .WORD 4124. ;X=217 + .WORD 4315. ;X=218 + .WORD 4443. ;X=219 + .WORD 4449. ;X=220 + .WORD 4711. ;X=221 + .WORD 4845. ;X=222 + .WORD 4883. ;X=223 + .WORD 4985. ;X=224 + .WORD 5055. ;X=225 + .WORD 5061. ;X=226 + .WORD 5260. ;X=227 + .WORD 5362. ;X=228 + .WORD 5592. ;X=229 + .WORD 5726. ;X=230 + .WORD 5860. ;X=231 + .WORD 5994. ;X=232 + .WORD 6160. ;X=233 + .WORD 6259. ;X=234 + .WORD 6422. ;X=235 + .WORD 6584. ;X=236 + .WORD 6715. ;X=237 + .WORD 6877. ;X=238 + .WORD 7008. ;X=239 + .WORD 7138. ;X=240 + .WORD 7301. ;X=241 + .WORD 7432. ;X=242 + .WORD 7562. ;X=243 + .WORD 7693. ;X=244 + .WORD 7791. ;X=245 + .WORD 7954. ;X=246 + .WORD 8084. ;X=247 + .WORD 8215. ;X=248 + .WORD 8345. ;X=249 + .WORD 8400. ;X=250 + .WORD 8678. ;X=251 + .WORD 8765. ;X=252 + .WORD 8851. ;X=253 + .WORD 9033. ;X=254 + .WORD 9152. ;X=255 + .WORD 9366. ;X=256 + .WORD 9388. ;X=257 + .WORD 9539. ;X=258 + .WORD 9945. ;X=259 + .WORD 10191. ;X=260 + .WORD 10377. ;X=261 + .WORD 10659. ;X=262 + .WORD 10781. ;X=263 + .WORD 11063. ;X=264 + .WORD 11312. ;X=265 + .WORD 11370. ;X=266 + .WORD 11396. ;X=267 + .WORD 11646. ;X=268 + .WORD 11768. ;X=269 + .WORD 11985. ;X=270 + .WORD 12203. ;X=271 + .WORD 12357. ;X=272 + .WORD 12607. ;X=273 + .WORD 12857. ;X=274 + .WORD 12965. ;X=275 + .WORD 13073. ;X=276 + .WORD 13117. ;X=277 + .WORD 13193. ;X=278 + .WORD 13238. ;X=279 + .WORD 13282. ;X=280 + .WORD 13358. ;X=281 + .WORD 13434. ;X=282 + .WORD 13478. ;X=283 + .WORD 13555. ;X=284 + .WORD 13631. ;X=285 + .WORD 13707. ;X=286 + .WORD 13815. ;X=287 + .WORD 13923. ;X=288 + .WORD 13967. ;X=289 + .WORD 14029. ;X=290 + .WORD 13996. ;X=291 + .WORD 14121. ;X=292 + .WORD 14215. ;X=293 + .WORD 14308. ;X=294 + .WORD 14466. ;X=295 + .WORD 14591. ;X=296 + .WORD 14749. ;X=297 + .WORD 14874. ;X=298 + .WORD 15000. ;X=299 + .WORD 14754. ;X=300 + .WORD 14604. ;X=301 + .WORD 14326. ;X=302 + .WORD 14176. ;X=303 + .WORD 14090. ;X=304 + .WORD 13940. ;X=305 + .WORD 13662. ;X=306 + .WORD 13480. ;X=307 + .WORD 13394. ;X=308 + .WORD 13116. ;X=309 + .WORD 12548. ;X=310 + .WORD 11469. ;X=311 + .WORD 10582. ;X=312 + .WORD 10015. ;X=313 + .WORD 9160. ;X=314 + .WORD 8960. ;X=315 + .WORD 8696. ;X=316 + .WORD 8432. ;X=317 + .WORD 8200. ;X=318 + .WORD 7936. ;X=319 + .WORD 7770. ;X=320 + .WORD 7509. ;X=321 + .WORD 7375. ;X=322 + .WORD 7210. ;X=323 + .WORD 7076. ;X=324 + .WORD 6911. ;X=325 + .WORD 6745. ;X=326 + .WORD 6644. ;X=327 + .WORD 6478. ;X=328 + .WORD 6185. ;X=329 + .WORD 6019. ;X=330 + .WORD 5758. ;X=331 + .WORD 5656. ;X=332 + .WORD 5491. ;X=333 + .WORD 5261. ;X=334 + .WORD 5096. ;X=335 + .WORD 4867. ;X=336 + .WORD 4712. ;X=337 + .WORD 4398. ;X=338 + .WORD 4020. ;X=339 + .WORD 3834. ;X=340 + .WORD 3296. ;X=341 + .WORD 3014. ;X=342 + .WORD 2668. ;X=343 + .WORD 2642. ;X=344 + .WORD 2424. ;X=345 + .WORD 2398. ;X=346 + .WORD 2212. ;X=347 + .WORD 2186. ;X=348 + .WORD 1840. ;X=349 + .WORD 1828. ;X=350 + .WORD 2008. ;X=351 + .WORD 2156. ;X=352 + .WORD 2272. ;X=353 + .WORD 2356. ;X=354 + .WORD 2312. ;X=355 + .WORD 2268. ;X=356 + .WORD 2224. ;X=357 + .WORD 2276. ;X=358 + .WORD 2328. ;X=359 + .WORD 2413. ;X=360 + .WORD 2511. ;X=361 + .WORD 2673. ;X=362 + .WORD 2836. ;X=363 + .WORD 2998. ;X=364 + .WORD 3129. ;X=365 + .WORD 3227. ;X=366 + .WORD 3390. ;X=367 + .WORD 3488. ;X=368 + .WORD 3586. ;X=369 + .WORD 3717. ;X=370 + .WORD 3879. ;X=371 + .WORD 4010. ;X=372 + .WORD 4108. ;X=373 + .WORD 4239. ;X=374 + .WORD 4369. ;X=375 + .WORD 4531. ;X=376 + .WORD 4694. ;X=377 + .WORD 4824. ;X=378 + .WORD 4987. ;X=379 + .WORD 5117. ;X=380 + .WORD 5216. ;X=381 + .WORD 5314. ;X=382 + .WORD 5445. ;X=383 + .WORD 5543. ;X=384 + .WORD 5705. ;X=385 + .WORD 5804. ;X=386 + .WORD 5966. ;X=387 + .WORD 6097. ;X=388 + .WORD 6195. ;X=389 + .WORD 6294. ;X=390 + .WORD 6392. ;X=391 + .WORD 6522. ;X=392 + .WORD 6685. ;X=393 + .WORD 6815. ;X=394 + .WORD 6914. ;X=395 + .WORD 7076. ;X=396 + .WORD 7239. ;X=397 + .WORD 7337. ;X=398 + .WORD 7436. ;X=399 + .WORD 7074. ;X=400 + .WORD 6809. ;X=401 + .WORD 6448. ;X=402 + .WORD 6118. ;X=403 + .WORD 5629. ;X=404 + .WORD 5268. ;X=405 + .WORD 5002. ;X=406 + .WORD 4769. ;X=407 + .WORD 4535. ;X=408 + .WORD 4270. ;X=409 + .WORD 3909. ;X=410 + .WORD 3515. ;X=411 + .WORD 3108. ;X=412 + .WORD 2796. ;X=413 + .WORD 2389. ;X=414 + .WORD 2077. ;X=415 + .WORD 1509. ;X=416 + .WORD 1326. ;X=417 + .WORD 1078. ;X=418 + .WORD 895. ;X=419 + .WORD 583. ;X=420 + .WORD 144. ;X=421 + .WORD 64. ;X=422 + .WORD -15. ;X=423 + .WORD -127. ;X=424 + .WORD -114. ;X=425 + .WORD -101. ;X=426 + .WORD -56. ;X=427 + .WORD -10. ;X=428 + .WORD 2. ;X=429 + .WORD -15. ;X=430 + .WORD 29. ;X=431 + .WORD 74. ;X=432 + .WORD 56. ;X=433 + .WORD 69. ;X=434 + .WORD 82. ;X=435 + .WORD 95. ;X=436 + .WORD 88. ;X=437 + .WORD 49. ;X=438 + .WORD 73. ;X=439 + .WORD 34. ;X=440 + .WORD 59. ;X=441 + .WORD 51. ;X=442 + .WORD 44. ;X=443 + .WORD 68. ;X=444 + .WORD 29. ;X=445 + .WORD 22. ;X=446 + .WORD 14. ;X=447 + .WORD 7. ;X=448 + .WORD 32. ;X=449 + .WORD 85. ;X=450 + .WORD 171. ;X=451 + .WORD 256. ;X=452 + .WORD 310. ;X=453 + .WORD 460. ;X=454 + .WORD 555. ;X=455 + .WORD 618. ;X=456 + .WORD 681. ;X=457 + .WORD 776. ;X=458 + .WORD 839. ;X=459 + .WORD 870. ;X=460 + .WORD 933. ;X=461 + .WORD 996. ;X=462 + .WORD 1092. ;X=463 + .WORD 1187. ;X=464 + .WORD 1250. ;X=465 + .WORD 1345. ;X=466 + .WORD 1408. ;X=467 + .WORD 1471. ;X=468 + .WORD 1566. ;X=469 + .WORD 1597. ;X=470 + .WORD 1628. ;X=471 + .WORD 1692. ;X=472 + .WORD 1755. ;X=473 + .WORD 1818. ;X=474 + .WORD 1881. ;X=475 + .WORD 1944. ;X=476 + .WORD 2007. ;X=477 + .WORD 2070. ;X=478 + .WORD 2133. ;X=479 + .WORD 2196. ;X=480 + .WORD 2260. ;X=481 + .WORD 2323. ;X=482 + .WORD 2386. ;X=483 + .WORD 2481. ;X=484 + .WORD 2544. ;X=485 + .WORD 2607. ;X=486 + .WORD 2670. ;X=487 + .WORD 2733. ;X=488 + .WORD 2764. ;X=489 + .WORD 2828. ;X=490 + .WORD 2859. ;X=491 + .WORD 2922. ;X=492 + .WORD 2985. ;X=493 + .WORD 3080. ;X=494 + .WORD 3111. ;X=495 + .WORD 3174. ;X=496 + .WORD 3237. ;X=497 + .WORD 3300. ;X=498 + .WORD 3396. ;X=499 + .WORD 3356. ;X=500 + .WORD 3252. ;X=501 + .WORD 2957. ;X=502 + .WORD 3173. ;X=503 + .WORD 3390. ;X=504 + .WORD 3446. ;X=505 + .WORD 3406. ;X=506 + .WORD 3303. ;X=507 + .WORD 3231. ;X=508 + .WORD 3448. ;X=509 + .WORD 3142. ;X=510 + .WORD 3156. ;X=511 + .WORD 3107. ;X=512 + .WORD 3089. ;X=513 + .WORD 2944. ;X=514 + .WORD 2835. ;X=515 + .WORD 2726. ;X=516 + .WORD 2617. ;X=517 + .WORD 2476. ;X=518 + .WORD 2367. ;X=519 + .WORD 2373. ;X=520 + .WORD 2410. ;X=521 + .WORD 2511. ;X=522 + .WORD 2580. ;X=523 + .WORD 2618. ;X=524 + .WORD 2719. ;X=525 + .WORD 2724. ;X=526 + .WORD 2793. ;X=527 + .WORD 2798. ;X=528 + .WORD 2772. ;X=529 + .WORD 2740. ;X=530 + .WORD 2709. ;X=531 + .WORD 2645. ;X=532 + .WORD 2614. ;X=533 + .WORD 2582. ;X=534 + .WORD 2551. ;X=535 + .WORD 2519. ;X=536 + .WORD 2488. ;X=537 + .WORD 2456. ;X=538 + .WORD 2425. ;X=539 + .WORD 2393. ;X=540 + .WORD 2362. ;X=541 + .WORD 2362. ;X=542 + .WORD 2363. ;X=543 + .WORD 2363. ;X=544 + .WORD 2296. ;X=545 + .WORD 2228. ;X=546 + .WORD 2224. ;X=547 + .WORD 2092. ;X=548 + .WORD 2153. ;X=549 + .WORD 2032. ;X=550 + .WORD 2072. ;X=551 + .WORD 2144. ;X=552 + .WORD 2248. ;X=553 + .WORD 2128. ;X=554 + .WORD 1976. ;X=555 + .WORD 2016. ;X=556 + .WORD 1864. ;X=557 + .WORD 1936. ;X=558 + .WORD 1912. ;X=559 + .WORD 1856. ;X=560 + .WORD 1704. ;X=561 + .WORD 1616. ;X=562 + .WORD 1496. ;X=563 + .WORD 1344. ;X=564 + .WORD 1320. ;X=565 + .WORD 1232. ;X=566 + .WORD 952. ;X=567 + .WORD 992. ;X=568 + .WORD 1032. ;X=569 + .WORD 1136. ;X=570 + .WORD 1048. ;X=571 + .WORD 1056. ;X=572 + .WORD 968. ;X=573 + .WORD 688. ;X=574 + .WORD 792. ;X=575 + .WORD 768. ;X=576 + .WORD 744. ;X=577 + .WORD 624. ;X=578 + .WORD 343. ;X=579 + .WORD 298. ;X=580 + .WORD 444. ;X=581 + .WORD 494. ;X=582 + .WORD 289. ;X=583 + .WORD 211. ;X=584 + .WORD 165. ;X=585 + .WORD 152. ;X=586 + .WORD 74. ;X=587 + .WORD 156. ;X=588 + .WORD 174. ;X=589 + .WORD 225. ;X=590 + .WORD 147. ;X=591 + .WORD -58. ;X=592 + .WORD -39. ;X=593 + .WORD -85. ;X=594 + .WORD -163. ;X=595 + .WORD 143. ;X=596 + .WORD 449. ;X=597 + .WORD 755. ;X=598 + .WORD 934. ;X=599 + .WORD 787. ;X=600 + .WORD 673. ;X=601 + .WORD 654. ;X=602 + .WORD 636. ;X=603 + .WORD 618. ;X=604 + .WORD 471. ;X=605 + .WORD 325. ;X=606 + .WORD 403. ;X=607 + .WORD 416. ;X=608 + .WORD 270. ;X=609 + .WORD 220. ;X=610 + .WORD 105. ;X=611 + .WORD 87. ;X=612 + .WORD 101. ;X=613 + .WORD -13. ;X=614 + .WORD -63. ;X=615 + .WORD 46. ;X=616 + .WORD 155. ;X=617 + .WORD 137. ;X=618 + .WORD 183. ;X=619 + .WORD 164. ;X=620 + .WORD 50. ;X=621 + .WORD 31. ;X=622 + .WORD 13. ;X=623 + .WORD 123. ;X=624 + .WORD 104. ;X=625 + .WORD 214. ;X=626 + .WORD 228. ;X=627 + .WORD 273. ;X=628 + .WORD 287. ;X=629 + .WORD 141. ;X=630 + .WORD 250. ;X=631 + .WORD 328. ;X=632 + .WORD 278. ;X=633 + .WORD 323. ;X=634 + .WORD 401. ;X=635 + .WORD 511. ;X=636 + .WORD 364. ;X=637 + .WORD 218. ;X=638 + .WORD 200. ;X=639 + .WORD 212. ;X=640 + .WORD 160. ;X=641 + .WORD 172. ;X=642 + .WORD 152. ;X=643 + .WORD 132. ;X=644 + .WORD 112. ;X=645 + .WORD 92. ;X=646 + .WORD 72. ;X=647 + .WORD 52. ;X=648 + .WORD 63. ;X=649 + .WORD 94. ;X=650 + .WORD 93. ;X=651 + .WORD 92. ;X=652 + .WORD 90. ;X=653 + .WORD 89. ;X=654 + .WORD 120. ;X=655 + .WORD 119. ;X=656 + .WORD 117. ;X=657 + .WORD 116. ;X=658 + .WORD 83. ;X=659 + .WORD 81. ;X=660 + .WORD 80. ;X=661 + .WORD 79. ;X=662 + .WORD 110. ;X=663 + .WORD 108. ;X=664 + .WORD 139. ;X=665 + .WORD 138. ;X=666 + .WORD 136. ;X=667 + .WORD 103. ;X=668 + .WORD 134. ;X=669 + .WORD 165. ;X=670 + .WORD 131. ;X=671 + .WORD 162. ;X=672 + .WORD 193. ;X=673 + .WORD 159. ;X=674 + .WORD 185. ;X=675 + .WORD 179. ;X=676 + .WORD 140. ;X=677 + .WORD 102. ;X=678 + .WORD 128. ;X=679 + .WORD 153. ;X=680 + .WORD 147. ;X=681 + .WORD 172. ;X=682 + .WORD 134. ;X=683 + .WORD 160. ;X=684 + .WORD 153. ;X=685 + .WORD 179. ;X=686 + .WORD 204. ;X=687 + .WORD 166. ;X=688 + .WORD 160. ;X=689 + .WORD 153. ;X=690 + .WORD 179. ;X=691 + .WORD 172. ;X=692 + .WORD 166. ;X=693 + .WORD 160. ;X=694 + .WORD 153. ;X=695 + .WORD 125. ;X=696 + .WORD 110. ;X=697 + .WORD 95. ;X=698 + .WORD 80. ;X=699 + .WORD 85. ;X=700 + .WORD 82. ;X=701 + .WORD 87. ;X=702 + .WORD 84. ;X=703 + .WORD 81. ;X=704 + .WORD 86. ;X=705 + .WORD 103. ;X=706 + .WORD 125. ;X=707 + .WORD 140. ;X=708 + .WORD 152. ;X=709 + .WORD 135. ;X=710 + .WORD 130. ;X=711 + .WORD 125. ;X=712 + .WORD 88. ;X=713 + .WORD 83. ;X=714 + .WORD 46. ;X=715 + .WORD 40. ;X=716 + .WORD 35. ;X=717 + .WORD 30. ;X=718 + .WORD 25. ;X=719 + .WORD 52. ;X=720 + .WORD 47. ;X=721 + .WORD 42. ;X=722 + .WORD 37. ;X=723 + .WORD 63. ;X=724 + .WORD 61. ;X=725 + .WORD 90. ;X=726 + .WORD 120. ;X=727 + .WORD 117. ;X=728 + .WORD 115. ;X=729 + .WORD 112. ;X=730 + .WORD 78. ;X=731 + .WORD 75. ;X=732 + .WORD 104. ;X=733 + .WORD 70. ;X=734 + .WORD 67. ;X=735 + .WORD 33. ;X=736 + .WORD 62. ;X=737 + .WORD 60. ;X=738 + .WORD 57. ;X=739 + .WORD 55. ;X=740 + .WORD 52. ;X=741 + .WORD 81. ;X=742 + .WORD 111. ;X=743 + .WORD 140. ;X=744 + .WORD 138. ;X=745 + .WORD 167. ;X=746 + .WORD 165. ;X=747 + .WORD 162. ;X=748 + .WORD 192. ;X=749 + .WORD 137. ;X=750 + .WORD 179. ;X=751 + .WORD 124. ;X=752 + .WORD 230. ;X=753 + .WORD 336. ;X=754 + .WORD 377. ;X=755 + .WORD 387. ;X=756 + .WORD 301. ;X=757 + .WORD 406. ;X=758 + .WORD 288. ;X=759 + .WORD 426. ;X=760 + .WORD 467. ;X=761 + .WORD 541. ;X=762 + .WORD 423. ;X=763 + .WORD 528. ;X=764 + .WORD 506. ;X=765 + .WORD 452. ;X=766 + .WORD 365. ;X=767 + .WORD 311. ;X=768 + .WORD 193. ;X=769 + .WORD 298. ;X=770 + .WORD 436. ;X=771 + .WORD 510. ;X=772 + .WORD 487. ;X=773 + .WORD 465. ;X=774 + .WORD 347. ;X=775 + .WORD 260. ;X=776 + .WORD 334. ;X=777 + .WORD 440. ;X=778 + .WORD 417. ;X=779 + .WORD 427. ;X=780 + .WORD 341. ;X=781 + .WORD 318. ;X=782 + .WORD 232. ;X=783 + .WORD 146. ;X=784 + .WORD 27. ;X=785 + .WORD 69. ;X=786 + .WORD 175. ;X=787 + .WORD 280. ;X=788 + .WORD 258. ;X=789 + .WORD 204. ;X=790 + .WORD 277. ;X=791 + .WORD 415. ;X=792 + .WORD 425. ;X=793 + .WORD 466. ;X=794 + .WORD 412. ;X=795 + .WORD 326. ;X=796 + .WORD 463. ;X=797 + .WORD 537. ;X=798 + .WORD 547. ;X=799 + .WORD 798. ;X=800 + .WORD 665. ;X=801 + .WORD 660. ;X=802 + .WORD 592. ;X=803 + .WORD 555. ;X=804 + .WORD 646. ;X=805 + .WORD 514. ;X=806 + .WORD 765. ;X=807 + .WORD 760. ;X=808 + .WORD 755. ;X=809 + .WORD 875. ;X=810 + .WORD 994. ;X=811 + .WORD 1081. ;X=812 + .WORD 1136. ;X=813 + .WORD 1223. ;X=814 + .WORD 1311. ;X=815 + .WORD 1398. ;X=816 + .WORD 1485. ;X=817 + .WORD 1604. ;X=818 + .WORD 1691. ;X=819 + .WORD 1747. ;X=820 + .WORD 1834. ;X=821 + .WORD 1921. ;X=822 + .WORD 1976. ;X=823 + .WORD 2095. ;X=824 + .WORD 2183. ;X=825 + .WORD 2238. ;X=826 + .WORD 2357. ;X=827 + .WORD 2412. ;X=828 + .WORD 2468. ;X=829 + .WORD 2422. ;X=830 + .WORD 2440. ;X=831 + .WORD 2523. ;X=832 + .WORD 2381. ;X=833 + .WORD 2336. ;X=834 + .WORD 2380. ;X=835 + .WORD 2392. ;X=836 + .WORD 2404. ;X=837 + .WORD 2449. ;X=838 + .WORD 2493. ;X=839 + .WORD 2505. ;X=840 + .WORD 2517. ;X=841 + .WORD 2562. ;X=842 + .WORD 2574. ;X=843 + .WORD 2586. ;X=844 + .WORD 2598. ;X=845 + .WORD 2643. ;X=846 + .WORD 2687. ;X=847 + .WORD 2731. ;X=848 + .WORD 2775. ;X=849 + .WORD 2849. ;X=850 + .WORD 2890. ;X=851 + .WORD 2932. ;X=852 + .WORD 2781. ;X=853 + .WORD 2759. ;X=854 + .WORD 2832. ;X=855 + .WORD 2810. ;X=856 + .WORD 2787. ;X=857 + .WORD 2509. ;X=858 + .WORD 2742. ;X=859 + .WORD 2752. ;X=860 + .WORD 2825. ;X=861 + .WORD 2899. ;X=862 + .WORD 2844. ;X=863 + .WORD 2822. ;X=864 + .WORD 2543. ;X=865 + .WORD 2777. ;X=866 + .WORD 2882. ;X=867 + .WORD 2892. ;X=868 + .WORD 2773. ;X=869 + .WORD 2879. ;X=870 + .WORD 2792. ;X=871 + .WORD 2770. ;X=872 + .WORD 2747. ;X=873 + .WORD 2629. ;X=874 + .WORD 2670. ;X=875 + .WORD 2391. ;X=876 + .WORD 2497. ;X=877 + .WORD 2570. ;X=878 + .WORD 2804. ;X=879 + .WORD 2781. ;X=880 + .WORD 2823. ;X=881 + .WORD 2544. ;X=882 + .WORD 2490. ;X=883 + .WORD 2435. ;X=884 + .WORD 2477. ;X=885 + .WORD 2518. ;X=886 + .WORD 2368. ;X=887 + .WORD 2313. ;X=888 + .WORD 2419. ;X=889 + .WORD 2524. ;X=890 + .WORD 2502. ;X=891 + .WORD 2479. ;X=892 + .WORD 2553. ;X=893 + .WORD 2562. ;X=894 + .WORD 2540. ;X=895 + .WORD 2549. ;X=896 + .WORD 2591. ;X=897 + .WORD 2664. ;X=898 + .WORD 2386. ;X=899 + .WORD 2455. ;X=900 + .WORD 2428. ;X=901 + .WORD 2145. ;X=902 + .WORD 2119. ;X=903 + .WORD 2156. ;X=904 + .WORD 2001. ;X=905 + .WORD 1974. ;X=906 + .WORD 2204. ;X=907 + .WORD 2145. ;X=908 + .WORD 2374. ;X=909 + .WORD 2476. ;X=910 + .PAGE +; +; THIS TABLE HOLDS THE FEATURES OF THE MOON +; THAT MAY CHANGE FROM TIME TO TIME. +; 0=NOTHING SPECIAL. +; 1=LANDED SHIP. +; 2=PLANTED AMERICAN FLAG. +; 3=DEAD SHIP TILTED LEFT. +; 4=DEAD SHIP TILTED RIGHT. +; 5=BOULDER. +; 6=MACDONALD'S +; 7=CENTER OF MACDONALD'S +; + .BYTE 0*20+0 ;X= -9 X=-10 + .BYTE 5*20+0 ;X= -7 X= -8 + .BYTE 0*20+0 ;X= -5 X= -6 + .BYTE 0*20+0 ;X= -3 X= -4 + .BYTE 0*20+0 ;X= -1 X= -2 +FEATUR: .BYTE 0*20+5 ;X= 1 X= 0 + .BYTE 0*20+0 ;X= 3 X= 2 + .BYTE 0*20+0 ;X= 5 X= 4 + .BYTE 0*20+0 ;X= 7 X= 6 + .BYTE 0*20+0 ;X= 9 X= 8 + .BYTE 0*20+0 ;X= 11 X= 10 + .BYTE 0*20+0 ;X= 13 X= 12 + .BYTE 0*20+0 ;X= 15 X= 14 + .BYTE 0*20+0 ;X= 17 X= 16 + .BYTE 0*20+0 ;X= 19 X= 18 + .BYTE 0*20+0 ;X= 21 X= 20 + .BYTE 0*20+0 ;X= 23 X= 22 + .BYTE 0*20+0 ;X= 25 X= 24 + .BYTE 0*20+5 ;X= 27 X= 26 + .BYTE 5*20+5 ;X= 29 X= 28 + .BYTE 0*20+0 ;X= 31 X= 30 + .BYTE 0*20+0 ;X= 33 X= 32 + .BYTE 0*20+0 ;X= 35 X= 34 + .BYTE 0*20+0 ;X= 37 X= 36 + .BYTE 0*20+0 ;X= 39 X= 38 + .BYTE 0*20+0 ;X= 41 X= 40 + .BYTE 0*20+0 ;X= 43 X= 42 + .BYTE 0*20+5 ;X= 45 X= 44 + .BYTE 0*20+0 ;X= 47 X= 46 + .BYTE 0*20+0 ;X= 49 X= 48 + .BYTE 5*20+5 ;X= 51 X= 50 + .BYTE 0*20+5 ;X= 53 X= 52 + .BYTE 5*20+5 ;X= 55 X= 54 + .BYTE 0*20+0 ;X= 57 X= 56 + .BYTE 0*20+0 ;X= 59 X= 58 + .BYTE 0*20+5 ;X= 61 X= 60 + .BYTE 0*20+5 ;X= 63 X= 62 + .BYTE 5*20+5 ;X= 65 X= 64 + .BYTE 5*20+0 ;X= 67 X= 66 + .BYTE 0*20+5 ;X= 69 X= 68 + .BYTE 5*20+5 ;X= 71 X= 70 + .BYTE 5*20+5 ;X= 73 X= 72 + .BYTE 5*20+0 ;X= 75 X= 74 + .BYTE 0*20+5 ;X= 77 X= 76 + .BYTE 0*20+5 ;X= 79 X= 78 + .BYTE 0*20+0 ;X= 81 X= 80 + .BYTE 0*20+5 ;X= 83 X= 82 + .BYTE 5*20+0 ;X= 85 X= 84 + .BYTE 0*20+5 ;X= 87 X= 86 + .BYTE 0*20+0 ;X= 89 X= 88 + .BYTE 0*20+5 ;X= 91 X= 90 + .BYTE 0*20+0 ;X= 93 X= 92 + .BYTE 0*20+0 ;X= 95 X= 94 + .BYTE 5*20+5 ;X= 97 X= 96 + .BYTE 0*20+0 ;X= 99 X= 98 + .BYTE 0*20+5 ;X=101 X=100 + .BYTE 5*20+5 ;X=103 X=102 + .BYTE 0*20+5 ;X=105 X=104 + .BYTE 5*20+5 ;X=107 X=106 + .BYTE 0*20+5 ;X=109 X=108 + .BYTE 0*20+5 ;X=111 X=110 + .BYTE 5*20+0 ;X=113 X=112 + .BYTE 5*20+5 ;X=115 X=114 + .BYTE 5*20+5 ;X=117 X=116 + .BYTE 5*20+5 ;X=119 X=118 + .BYTE 0*20+5 ;X=121 X=120 + .BYTE 5*20+5 ;X=123 X=122 + .BYTE 5*20+5 ;X=125 X=124 + .BYTE 5*20+5 ;X=127 X=126 + .BYTE 0*20+5 ;X=129 X=128 + .BYTE 5*20+5 ;X=131 X=130 + .BYTE 0*20+5 ;X=133 X=132 + .BYTE 5*20+5 ;X=135 X=134 + .BYTE 5*20+5 ;X=137 X=136 + .BYTE 5*20+5 ;X=139 X=138 + .BYTE 0*20+5 ;X=141 X=140 + .BYTE 0*20+5 ;X=143 X=142 + .BYTE 5*20+5 ;X=145 X=144 + .BYTE 5*20+5 ;X=147 X=146 + .BYTE 5*20+0 ;X=149 X=148 + .BYTE 5*20+5 ;X=151 X=150 + .BYTE 5*20+5 ;X=153 X=152 + .BYTE 5*20+5 ;X=155 X=154 + .BYTE 5*20+0 ;X=157 X=156 + .BYTE 0*20+0 ;X=159 X=158 + .BYTE 5*20+5 ;X=161 X=160 + .BYTE 0*20+5 ;X=163 X=162 + .BYTE 0*20+5 ;X=165 X=164 + .BYTE 5*20+5 ;X=167 X=166 + .BYTE 5*20+5 ;X=169 X=168 + .BYTE 5*20+5 ;X=171 X=170 + .BYTE 5*20+5 ;X=173 X=172 + .BYTE 0*20+5 ;X=175 X=174 + .BYTE 5*20+5 ;X=177 X=176 + .BYTE 0*20+5 ;X=179 X=178 + .BYTE 5*20+0 ;X=181 X=180 + .BYTE 0*20+5 ;X=183 X=182 + .BYTE 5*20+5 ;X=185 X=184 + .BYTE 5*20+5 ;X=187 X=186 + .BYTE 5*20+5 ;X=189 X=188 + .BYTE 5*20+5 ;X=191 X=190 + .BYTE 5*20+5 ;X=193 X=192 + .BYTE 5*20+5 ;X=195 X=194 + .BYTE 5*20+5 ;X=197 X=196 + .BYTE 0*20+5 ;X=199 X=198 + .BYTE 0*20+0 ;X=201 X=200 + .BYTE 5*20+0 ;X=203 X=202 + .BYTE 0*20+0 ;X=205 X=204 + .BYTE 0*20+0 ;X=207 X=206 + .BYTE 0*20+0 ;X=209 X=208 + .BYTE 0*20+5 ;X=211 X=210 + .BYTE 0*20+0 ;X=213 X=212 + .BYTE 0*20+0 ;X=215 X=214 + .BYTE 0*20+0 ;X=217 X=216 + .BYTE 0*20+0 ;X=219 X=218 + .BYTE 5*20+0 ;X=221 X=220 + .BYTE 5*20+5 ;X=223 X=222 + .BYTE 0*20+0 ;X=225 X=224 + .BYTE 0*20+0 ;X=227 X=226 + .BYTE 0*20+0 ;X=229 X=228 + .BYTE 0*20+0 ;X=231 X=230 + .BYTE 0*20+0 ;X=233 X=232 + .BYTE 0*20+5 ;X=235 X=234 + .BYTE 0*20+0 ;X=237 X=236 + .BYTE 0*20+0 ;X=239 X=238 + .BYTE 0*20+5 ;X=241 X=240 + .BYTE 0*20+0 ;X=243 X=242 + .BYTE 0*20+5 ;X=245 X=244 + .BYTE 0*20+0 ;X=247 X=246 + .BYTE 0*20+0 ;X=249 X=248 + .BYTE 0*20+5 ;X=251 X=250 + .BYTE 0*20+5 ;X=253 X=252 + .BYTE 0*20+0 ;X=255 X=254 + .BYTE 0*20+0 ;X=257 X=256 + .BYTE 0*20+0 ;X=259 X=258 + .BYTE 0*20+0 ;X=261 X=260 + .BYTE 0*20+0 ;X=263 X=262 + .BYTE 0*20+0 ;X=265 X=264 + .BYTE 0*20+5 ;X=267 X=266 + .BYTE 0*20+0 ;X=269 X=268 + .BYTE 0*20+0 ;X=271 X=270 + .BYTE 0*20+0 ;X=273 X=272 + .BYTE 0*20+0 ;X=275 X=274 + .BYTE 0*20+0 ;X=277 X=276 + .BYTE 0*20+0 ;X=279 X=278 + .BYTE 5*20+0 ;X=281 X=280 + .BYTE 0*20+0 ;X=283 X=282 + .BYTE 0*20+0 ;X=285 X=284 + .BYTE 0*20+0 ;X=287 X=286 + .BYTE 0*20+0 ;X=289 X=288 + .BYTE 0*20+0 ;X=291 X=290 + .BYTE 0*20+0 ;X=293 X=292 + .BYTE 0*20+0 ;X=295 X=294 + .BYTE 0*20+0 ;X=297 X=296 + .BYTE 0*20+0 ;X=299 X=298 + .BYTE 5*20+5 ;X=301 X=300 + .BYTE 5*20+5 ;X=303 X=302 + .BYTE 5*20+0 ;X=305 X=304 + .BYTE 5*20+5 ;X=307 X=306 + .BYTE 0*20+5 ;X=309 X=308 + .BYTE 5*20+5 ;X=311 X=310 + .BYTE 0*20+5 ;X=313 X=312 + .BYTE 5*20+5 ;X=315 X=314 + .BYTE 5*20+5 ;X=317 X=316 + .BYTE 5*20+5 ;X=319 X=318 + .BYTE 5*20+5 ;X=321 X=320 + .BYTE 5*20+5 ;X=323 X=322 + .BYTE 5*20+5 ;X=325 X=324 + .BYTE 5*20+5 ;X=327 X=326 + .BYTE 5*20+5 ;X=329 X=328 + .BYTE 5*20+5 ;X=331 X=330 + .BYTE 5*20+5 ;X=333 X=332 + .BYTE 5*20+5 ;X=335 X=334 + .BYTE 5*20+5 ;X=337 X=336 + .BYTE 5*20+5 ;X=339 X=338 + .BYTE 5*20+5 ;X=341 X=340 + .BYTE 5*20+5 ;X=343 X=342 + .BYTE 5*20+5 ;X=345 X=344 + .BYTE 5*20+5 ;X=347 X=346 + .BYTE 5*20+5 ;X=349 X=348 + .BYTE 0*20+0 ;X=351 X=350 + .BYTE 0*20+0 ;X=353 X=352 + .BYTE 0*20+0 ;X=355 X=354 + .BYTE 5*20+0 ;X=357 X=356 + .BYTE 5*20+5 ;X=359 X=358 + .BYTE 5*20+5 ;X=361 X=360 + .BYTE 0*20+0 ;X=363 X=362 + .BYTE 0*20+0 ;X=365 X=364 + .BYTE 0*20+0 ;X=367 X=366 + .BYTE 0*20+0 ;X=369 X=368 + .BYTE 0*20+0 ;X=371 X=370 + .BYTE 0*20+0 ;X=373 X=372 + .BYTE 0*20+0 ;X=375 X=374 + .BYTE 0*20+0 ;X=377 X=376 + .BYTE 0*20+5 ;X=379 X=378 + .BYTE 0*20+0 ;X=381 X=380 + .BYTE 0*20+5 ;X=383 X=382 + .BYTE 0*20+0 ;X=385 X=384 + .BYTE 0*20+5 ;X=387 X=386 + .BYTE 0*20+0 ;X=389 X=388 + .BYTE 0*20+0 ;X=391 X=390 + .BYTE 0*20+0 ;X=393 X=392 + .BYTE 0*20+0 ;X=395 X=394 + .BYTE 0*20+0 ;X=397 X=396 + .BYTE 0*20+0 ;X=399 X=398 + .BYTE 5*20+5 ;X=401 X=400 + .BYTE 5*20+5 ;X=403 X=402 + .BYTE 5*20+5 ;X=405 X=404 + .BYTE 5*20+5 ;X=407 X=406 + .BYTE 5*20+5 ;X=409 X=408 + .BYTE 5*20+5 ;X=411 X=410 + .BYTE 5*20+5 ;X=413 X=412 + .BYTE 5*20+5 ;X=415 X=414 + .BYTE 5*20+0 ;X=417 X=416 + .BYTE 5*20+5 ;X=419 X=418 + .BYTE 5*20+5 ;X=421 X=420 + .BYTE 0*20+5 ;X=423 X=422 + .BYTE 0*20+5 ;X=425 X=424 + .BYTE 0*20+0 ;X=427 X=426 + .BYTE 0*20+0 ;X=429 X=428 + .BYTE 0*20+5 ;X=431 X=430 + .BYTE 0*20+0 ;X=433 X=432 + .BYTE 5*20+0 ;X=435 X=434 + .BYTE 5*20+0 ;X=437 X=436 + .BYTE 0*20+0 ;X=439 X=438 + .BYTE 0*20+0 ;X=441 X=440 + .BYTE 0*20+0 ;X=443 X=442 + .BYTE 0*20+0 ;X=445 X=444 + .BYTE 0*20+0 ;X=447 X=446 + .BYTE 0*20+0 ;X=449 X=448 + .BYTE 5*20+0 ;X=451 X=450 + .BYTE 5*20+0 ;X=453 X=452 + .BYTE 0*20+5 ;X=455 X=454 + .BYTE 0*20+0 ;X=457 X=456 + .BYTE 5*20+0 ;X=459 X=458 + .BYTE 0*20+5 ;X=461 X=460 + .BYTE 0*20+5 ;X=463 X=462 + .BYTE 5*20+5 ;X=465 X=464 + .BYTE 0*20+5 ;X=467 X=466 + .BYTE 0*20+0 ;X=469 X=468 + .BYTE 0*20+5 ;X=471 X=470 + .BYTE 0*20+5 ;X=473 X=472 + .BYTE 0*20+5 ;X=475 X=474 + .BYTE 0*20+0 ;X=477 X=476 + .BYTE 0*20+5 ;X=479 X=478 + .BYTE 0*20+0 ;X=481 X=480 + .BYTE 0*20+0 ;X=483 X=482 + .BYTE 0*20+0 ;X=485 X=484 + .BYTE 0*20+0 ;X=487 X=486 + .BYTE 0*20+0 ;X=489 X=488 + .BYTE 0*20+0 ;X=491 X=490 + .BYTE 5*20+0 ;X=493 X=492 + .BYTE 0*20+0 ;X=495 X=494 + .BYTE 0*20+0 ;X=497 X=496 + .BYTE 0*20+0 ;X=499 X=498 + .BYTE 5*20+5 ;X=501 X=500 + .BYTE 5*20+5 ;X=503 X=502 + .BYTE 5*20+5 ;X=505 X=504 + .BYTE 5*20+5 ;X=507 X=506 + .BYTE 5*20+5 ;X=509 X=508 + .BYTE 5*20+5 ;X=511 X=510 + .BYTE 5*20+5 ;X=513 X=512 + .BYTE 5*20+0 ;X=515 X=514 + .BYTE 5*20+0 ;X=517 X=516 + .BYTE 5*20+5 ;X=519 X=518 + .BYTE 5*20+5 ;X=521 X=520 + .BYTE 5*20+5 ;X=523 X=522 + .BYTE 5*20+5 ;X=525 X=524 + .BYTE 5*20+0 ;X=527 X=526 + .BYTE 5*20+5 ;X=529 X=528 + .BYTE 5*20+5 ;X=531 X=530 + .BYTE 5*20+5 ;X=533 X=532 + .BYTE 0*20+5 ;X=535 X=534 + .BYTE 5*20+5 ;X=537 X=536 + .BYTE 5*20+0 ;X=539 X=538 + .BYTE 5*20+0 ;X=541 X=540 + .BYTE 5*20+5 ;X=543 X=542 + .BYTE 5*20+5 ;X=545 X=544 + .BYTE 5*20+5 ;X=547 X=546 + .BYTE 5*20+5 ;X=549 X=548 + .BYTE 5*20+5 ;X=551 X=550 + .BYTE 5*20+5 ;X=553 X=552 + .BYTE 5*20+0 ;X=555 X=554 + .BYTE 5*20+5 ;X=557 X=556 + .BYTE 5*20+5 ;X=559 X=558 + .BYTE 5*20+5 ;X=561 X=560 + .BYTE 5*20+5 ;X=563 X=562 + .BYTE 5*20+5 ;X=565 X=564 + .BYTE 5*20+5 ;X=567 X=566 + .BYTE 5*20+5 ;X=569 X=568 + .BYTE 5*20+5 ;X=571 X=570 + .BYTE 5*20+0 ;X=573 X=572 + .BYTE 5*20+5 ;X=575 X=574 + .BYTE 0*20+5 ;X=577 X=576 + .BYTE 0*20+5 ;X=579 X=578 + .BYTE 0*20+5 ;X=581 X=580 + .BYTE 5*20+0 ;X=583 X=582 + .BYTE 5*20+0 ;X=585 X=584 + .BYTE 5*20+5 ;X=587 X=586 + .BYTE 5*20+5 ;X=589 X=588 + .BYTE 5*20+5 ;X=591 X=590 + .BYTE 5*20+5 ;X=593 X=592 + .BYTE 5*20+5 ;X=595 X=594 + .BYTE 5*20+5 ;X=597 X=596 + .BYTE 5*20+5 ;X=599 X=598 + .BYTE 0*20+0 ;X=601 X=600 + .BYTE 0*20+0 ;X=603 X=602 + .BYTE 0*20+0 ;X=605 X=604 + .BYTE 0*20+0 ;X=607 X=606 + .BYTE 0*20+0 ;X=609 X=608 + .BYTE 0*20+0 ;X=611 X=610 + .BYTE 0*20+0 ;X=613 X=612 + .BYTE 0*20+0 ;X=615 X=614 + .BYTE 5*20+0 ;X=617 X=616 + .BYTE 5*20+0 ;X=619 X=618 + .BYTE 0*20+0 ;X=621 X=620 + .BYTE 0*20+0 ;X=623 X=622 + .BYTE 0*20+0 ;X=625 X=624 + .BYTE 0*20+0 ;X=627 X=626 + .BYTE 0*20+0 ;X=629 X=628 + .BYTE 0*20+0 ;X=631 X=630 + .BYTE 5*20+0 ;X=633 X=632 + .BYTE 0*20+0 ;X=635 X=634 + .BYTE 0*20+0 ;X=637 X=636 + .BYTE 0*20+0 ;X=639 X=638 + .BYTE 0*20+0 ;X=641 X=640 + .BYTE 0*20+0 ;X=643 X=642 + .BYTE 0*20+5 ;X=645 X=644 + .BYTE 0*20+0 ;X=647 X=646 + .BYTE 0*20+0 ;X=649 X=648 + .BYTE 0*20+5 ;X=651 X=650 + .BYTE 0*20+0 ;X=653 X=652 + .BYTE 0*20+0 ;X=655 X=654 + .BYTE 0*20+0 ;X=657 X=656 + .BYTE 0*20+0 ;X=659 X=658 + .BYTE 0*20+0 ;X=661 X=660 + .BYTE 0*20+0 ;X=663 X=662 + .BYTE 0*20+0 ;X=665 X=664 + .BYTE 0*20+0 ;X=667 X=666 + .BYTE 5*20+0 ;X=669 X=668 + .BYTE 5*20+5 ;X=671 X=670 + .BYTE 0*20+0 ;X=673 X=672 + .BYTE 0*20+0 ;X=675 X=674 + .BYTE 0*20+0 ;X=677 X=676 + .BYTE 0*20+0 ;X=679 X=678 + .BYTE 0*20+0 ;X=681 X=680 + .BYTE 0*20+0 ;X=683 X=682 + .BYTE 0*20+0 ;X=685 X=684 + .BYTE 0*20+0 ;X=687 X=686 + .BYTE 5*20+5 ;X=689 X=688 + .BYTE 0*20+5 ;X=691 X=690 + .BYTE 0*20+0 ;X=693 X=692 + .BYTE 0*20+0 ;X=695 X=694 + .BYTE 0*20+0 ;X=697 X=696 + .BYTE 0*20+0 ;X=699 X=698 + .BYTE 0*20+0 ;X=701 X=700 + .BYTE 7*20+6 ;X=703 X=702 + .BYTE 0*20+6 ;X=705 X=704 + .BYTE 5*20+0 ;X=707 X=706 + .BYTE 5*20+5 ;X=709 X=708 + .BYTE 5*20+0 ;X=711 X=710 + .BYTE 0*20+0 ;X=713 X=712 + .BYTE 5*20+0 ;X=715 X=714 + .BYTE 5*20+0 ;X=717 X=716 + .BYTE 0*20+0 ;X=719 X=718 + .BYTE 5*20+5 ;X=721 X=720 + .BYTE 5*20+5 ;X=723 X=722 + .BYTE 0*20+0 ;X=725 X=724 + .BYTE 0*20+5 ;X=727 X=726 + .BYTE 0*20+0 ;X=729 X=728 + .BYTE 5*20+0 ;X=731 X=730 + .BYTE 0*20+5 ;X=733 X=732 + .BYTE 5*20+5 ;X=735 X=734 + .BYTE 5*20+0 ;X=737 X=736 + .BYTE 0*20+0 ;X=739 X=738 + .BYTE 5*20+0 ;X=741 X=740 + .BYTE 5*20+0 ;X=743 X=742 + .BYTE 0*20+5 ;X=745 X=744 + .BYTE 0*20+0 ;X=747 X=746 + .BYTE 0*20+0 ;X=749 X=748 + .BYTE 5*20+0 ;X=751 X=750 + .BYTE 0*20+5 ;X=753 X=752 + .BYTE 0*20+0 ;X=755 X=754 + .BYTE 5*20+0 ;X=757 X=756 + .BYTE 5*20+0 ;X=759 X=758 + .BYTE 0*20+0 ;X=761 X=760 + .BYTE 0*20+0 ;X=763 X=762 + .BYTE 5*20+0 ;X=765 X=764 + .BYTE 0*20+0 ;X=767 X=766 + .BYTE 5*20+5 ;X=769 X=768 + .BYTE 5*20+0 ;X=771 X=770 + .BYTE 0*20+0 ;X=773 X=772 + .BYTE 5*20+0 ;X=775 X=774 + .BYTE 0*20+0 ;X=777 X=776 + .BYTE 5*20+0 ;X=779 X=778 + .BYTE 0*20+0 ;X=781 X=780 + .BYTE 0*20+0 ;X=783 X=782 + .BYTE 0*20+5 ;X=785 X=784 + .BYTE 0*20+0 ;X=787 X=786 + .BYTE 0*20+0 ;X=789 X=788 + .BYTE 0*20+0 ;X=791 X=790 + .BYTE 0*20+0 ;X=793 X=792 + .BYTE 0*20+0 ;X=795 X=794 + .BYTE 0*20+0 ;X=797 X=796 + .BYTE 0*20+0 ;X=799 X=798 + .BYTE 0*20+0 ;X=801 X=800 + .BYTE 0*20+0 ;X=803 X=802 + .BYTE 0*20+0 ;X=805 X=804 + .BYTE 0*20+5 ;X=807 X=806 + .BYTE 0*20+0 ;X=809 X=808 + .BYTE 0*20+0 ;X=811 X=810 + .BYTE 0*20+0 ;X=813 X=812 + .BYTE 0*20+0 ;X=815 X=814 + .BYTE 0*20+0 ;X=817 X=816 + .BYTE 0*20+0 ;X=819 X=818 + .BYTE 0*20+0 ;X=821 X=820 + .BYTE 0*20+0 ;X=823 X=822 + .BYTE 0*20+0 ;X=825 X=824 + .BYTE 5*20+0 ;X=827 X=826 + .BYTE 0*20+5 ;X=829 X=828 + .BYTE 0*20+0 ;X=831 X=830 + .BYTE 0*20+0 ;X=833 X=832 + .BYTE 0*20+0 ;X=835 X=834 + .BYTE 5*20+5 ;X=837 X=836 + .BYTE 0*20+0 ;X=839 X=838 + .BYTE 5*20+0 ;X=841 X=840 + .BYTE 0*20+5 ;X=843 X=842 + .BYTE 0*20+0 ;X=845 X=844 + .BYTE 0*20+0 ;X=847 X=846 + .BYTE 5*20+0 ;X=849 X=848 + .BYTE 5*20+5 ;X=851 X=850 + .BYTE 5*20+5 ;X=853 X=852 + .BYTE 5*20+0 ;X=855 X=854 + .BYTE 5*20+5 ;X=857 X=856 + .BYTE 5*20+5 ;X=859 X=858 + .BYTE 5*20+5 ;X=861 X=860 + .BYTE 5*20+5 ;X=863 X=862 + .BYTE 5*20+5 ;X=865 X=864 + .BYTE 5*20+5 ;X=867 X=866 + .BYTE 5*20+0 ;X=869 X=868 + .BYTE 5*20+0 ;X=871 X=870 + .BYTE 5*20+5 ;X=873 X=872 + .BYTE 0*20+5 ;X=875 X=874 + .BYTE 5*20+5 ;X=877 X=876 + .BYTE 5*20+5 ;X=879 X=878 + .BYTE 5*20+5 ;X=881 X=880 + .BYTE 5*20+5 ;X=883 X=882 + .BYTE 0*20+0 ;X=885 X=884 + .BYTE 5*20+5 ;X=887 X=886 + .BYTE 5*20+5 ;X=889 X=888 + .BYTE 5*20+5 ;X=891 X=890 + .BYTE 5*20+5 ;X=893 X=892 + .BYTE 5*20+5 ;X=895 X=894 + .BYTE 5*20+5 ;X=897 X=896 + .BYTE 5*20+5 ;X=899 X=898 + .BYTE 5*20+5 ;X=901 X=900 + .BYTE 5*20+5 ;X=903 X=902 + .BYTE 5*20+5 ;X=905 X=904 + .BYTE 5*20+5 ;X=907 X=906 + .BYTE 5*20+5 ;X=909 X=908 + .BYTE 0*20+5 ;X=911 X=910 + .EVEN ;MAKE SURE TO BRING TO BRING BYTES BACK. + .PAGE +; +; SINE AND COSINE TABLES FROM 0 TO 359 DEGREES. +; +SINTAB: 000000 ; 0 DEGREES. + 000436 ; 1 DEGREES. + 001074 ; 2 DEGREES. + 001531 ; 3 DEGREES. + 002167 ; 4 DEGREES. + 002624 ; 5 DEGREES. + 003261 ; 6 DEGREES. + 003715 ; 7 DEGREES. + 004350 ; 8 DEGREES. + 005003 ; 9 DEGREES. + 005435 ; 10 DEGREES. + 006066 ; 11 DEGREES. + 006516 ; 12 DEGREES. + 007146 ; 13 DEGREES. + 007574 ; 14 DEGREES. + 010220 ; 15 DEGREES. + 010644 ; 16 DEGREES. + 011266 ; 17 DEGREES. + 011707 ; 18 DEGREES. + 012326 ; 19 DEGREES. + 012744 ; 20 DEGREES. + 013360 ; 21 DEGREES. + 013772 ; 22 DEGREES. + 014402 ; 23 DEGREES. + 015010 ; 24 DEGREES. + 015414 ; 25 DEGREES. + 016016 ; 26 DEGREES. + 016416 ; 27 DEGREES. + 017014 ; 28 DEGREES. + 017407 ; 29 DEGREES. + 020000 ; 30 DEGREES. + 020366 ; 31 DEGREES. + 020752 ; 32 DEGREES. + 021333 ; 33 DEGREES. + 021712 ; 34 DEGREES. + 022265 ; 35 DEGREES. + 022636 ; 36 DEGREES. + 023204 ; 37 DEGREES. + 023547 ; 38 DEGREES. + 024107 ; 39 DEGREES. + 024443 ; 40 DEGREES. + 024775 ; 41 DEGREES. + 025323 ; 42 DEGREES. + 025646 ; 43 DEGREES. + 026165 ; 44 DEGREES. + 026501 ; 45 DEGREES. + 027012 ; 46 DEGREES. + 027316 ; 47 DEGREES. + 027620 ; 48 DEGREES. + 030115 ; 49 DEGREES. + 030407 ; 50 DEGREES. + 030675 ; 51 DEGREES. + 031157 ; 52 DEGREES. + 031435 ; 53 DEGREES. + 031707 ; 54 DEGREES. + 032155 ; 55 DEGREES. + 032417 ; 56 DEGREES. + 032655 ; 57 DEGREES. + 033106 ; 58 DEGREES. + 033334 ; 59 DEGREES. + 033555 ; 60 DEGREES. + 033772 ; 61 DEGREES. + 034202 ; 62 DEGREES. + 034406 ; 63 DEGREES. + 034606 ; 64 DEGREES. + 035001 ; 65 DEGREES. + 035170 ; 66 DEGREES. + 035352 ; 67 DEGREES. + 035527 ; 68 DEGREES. + 035700 ; 69 DEGREES. + 036044 ; 70 DEGREES. + 036203 ; 71 DEGREES. + 036336 ; 72 DEGREES. + 036464 ; 73 DEGREES. + 036605 ; 74 DEGREES. + 036722 ; 75 DEGREES. + 037031 ; 76 DEGREES. + 037134 ; 77 DEGREES. + 037232 ; 78 DEGREES. + 037323 ; 79 DEGREES. + 037407 ; 80 DEGREES. + 037466 ; 81 DEGREES. + 037541 ; 82 DEGREES. + 037606 ; 83 DEGREES. + 037646 ; 84 DEGREES. + 037702 ; 85 DEGREES. + 037730 ; 86 DEGREES. + 037752 ; 87 DEGREES. + 037766 ; 88 DEGREES. + 037776 ; 89 DEGREES. +COSTAB: 040000 ; 90 DEGREES. + 037776 ; 91 DEGREES. + 037766 ; 92 DEGREES. + 037752 ; 93 DEGREES. + 037730 ; 94 DEGREES. + 037702 ; 95 DEGREES. + 037646 ; 96 DEGREES. + 037606 ; 97 DEGREES. + 037541 ; 98 DEGREES. + 037466 ; 99 DEGREES. + 037407 ; 100 DEGREES. + 037323 ; 101 DEGREES. + 037232 ; 102 DEGREES. + 037134 ; 103 DEGREES. + 037031 ; 104 DEGREES. + 036722 ; 105 DEGREES. + 036605 ; 106 DEGREES. + 036464 ; 107 DEGREES. + 036336 ; 108 DEGREES. + 036203 ; 109 DEGREES. + 036044 ; 110 DEGREES. + 035700 ; 111 DEGREES. + 035527 ; 112 DEGREES. + 035352 ; 113 DEGREES. + 035170 ; 114 DEGREES. + 035001 ; 115 DEGREES. + 034606 ; 116 DEGREES. + 034406 ; 117 DEGREES. + 034202 ; 118 DEGREES. + 033772 ; 119 DEGREES. + 033555 ; 120 DEGREES. + 033334 ; 121 DEGREES. + 033106 ; 122 DEGREES. + 032655 ; 123 DEGREES. + 032417 ; 124 DEGREES. + 032155 ; 125 DEGREES. + 031707 ; 126 DEGREES. + 031435 ; 127 DEGREES. + 031157 ; 128 DEGREES. + 030675 ; 129 DEGREES. + 030407 ; 130 DEGREES. + 030115 ; 131 DEGREES. + 027620 ; 132 DEGREES. + 027316 ; 133 DEGREES. + 027012 ; 134 DEGREES. + 026501 ; 135 DEGREES. + 026165 ; 136 DEGREES. + 025646 ; 137 DEGREES. + 025323 ; 138 DEGREES. + 024775 ; 139 DEGREES. + 024443 ; 140 DEGREES. + 024107 ; 141 DEGREES. + 023547 ; 142 DEGREES. + 023204 ; 143 DEGREES. + 022636 ; 144 DEGREES. + 022265 ; 145 DEGREES. + 021712 ; 146 DEGREES. + 021333 ; 147 DEGREES. + 020752 ; 148 DEGREES. + 020366 ; 149 DEGREES. + 020000 ; 150 DEGREES. + 017407 ; 151 DEGREES. + 017014 ; 152 DEGREES. + 016416 ; 153 DEGREES. + 016016 ; 154 DEGREES. + 015414 ; 155 DEGREES. + 015010 ; 156 DEGREES. + 014402 ; 157 DEGREES. + 013772 ; 158 DEGREES. + 013360 ; 159 DEGREES. + 012744 ; 160 DEGREES. + 012326 ; 161 DEGREES. + 011707 ; 162 DEGREES. + 011266 ; 163 DEGREES. + 010644 ; 164 DEGREES. + 010220 ; 165 DEGREES. + 007574 ; 166 DEGREES. + 007146 ; 167 DEGREES. + 006516 ; 168 DEGREES. + 006066 ; 169 DEGREES. + 005435 ; 170 DEGREES. + 005003 ; 171 DEGREES. + 004350 ; 172 DEGREES. + 003715 ; 173 DEGREES. + 003261 ; 174 DEGREES. + 002624 ; 175 DEGREES. + 002167 ; 176 DEGREES. + 001531 ; 177 DEGREES. + 001074 ; 178 DEGREES. + 000436 ; 179 DEGREES. + 000000 ; 180 DEGREES. + 177344 ; 181 DEGREES. + 176706 ; 182 DEGREES. + 176247 ; 183 DEGREES. + 175613 ; 184 DEGREES. + 175156 ; 185 DEGREES. + 174521 ; 186 DEGREES. + 174065 ; 187 DEGREES. + 173430 ; 188 DEGREES. + 172775 ; 189 DEGREES. + 172343 ; 190 DEGREES. + 171712 ; 191 DEGREES. + 171262 ; 192 DEGREES. + 170634 ; 193 DEGREES. + 170206 ; 194 DEGREES. + 167560 ; 195 DEGREES. + 167134 ; 196 DEGREES. + 166512 ; 197 DEGREES. + 166073 ; 198 DEGREES. + 165452 ; 199 DEGREES. + 165036 ; 200 DEGREES. + 164421 ; 201 DEGREES. + 164010 ; 202 DEGREES. + 163400 ; 203 DEGREES. + 162772 ; 204 DEGREES. + 162364 ; 205 DEGREES. + 161762 ; 206 DEGREES. + 161362 ; 207 DEGREES. + 160766 ; 208 DEGREES. + 160371 ; 209 DEGREES. + 160002 ; 210 DEGREES. + 157412 ; 211 DEGREES. + 157026 ; 212 DEGREES. + 156445 ; 213 DEGREES. + 156070 ; 214 DEGREES. + 155513 ; 215 DEGREES. + 155142 ; 216 DEGREES. + 154574 ; 217 DEGREES. + 154233 ; 218 DEGREES. + 153673 ; 219 DEGREES. + 153335 ; 220 DEGREES. + 153005 ; 221 DEGREES. + 152455 ; 222 DEGREES. + 152134 ; 223 DEGREES. + 151613 ; 224 DEGREES. + 151277 ; 225 DEGREES. + 150770 ; 226 DEGREES. + 150462 ; 227 DEGREES. + 150162 ; 228 DEGREES. + 147663 ; 229 DEGREES. + 147373 ; 230 DEGREES. + 147105 ; 231 DEGREES. + 146623 ; 232 DEGREES. + 146345 ; 233 DEGREES. + 146073 ; 234 DEGREES. + 145625 ; 235 DEGREES. + 145363 ; 236 DEGREES. + 145125 ; 237 DEGREES. + 144672 ; 238 DEGREES. + 144446 ; 239 DEGREES. + 144225 ; 240 DEGREES. + 144010 ; 241 DEGREES. + 143576 ; 242 DEGREES. + 143372 ; 243 DEGREES. + 143174 ; 244 DEGREES. + 143001 ; 245 DEGREES. + 142612 ; 246 DEGREES. + 142430 ; 247 DEGREES. + 142253 ; 248 DEGREES. + 142102 ; 249 DEGREES. + 141736 ; 250 DEGREES. + 141575 ; 251 DEGREES. + 141442 ; 252 DEGREES. + 141314 ; 253 DEGREES. + 141173 ; 254 DEGREES. + 141060 ; 255 DEGREES. + 140747 ; 256 DEGREES. + 140644 ; 257 DEGREES. + 140550 ; 258 DEGREES. + 140457 ; 259 DEGREES. + 140371 ; 260 DEGREES. + 140312 ; 261 DEGREES. + 140241 ; 262 DEGREES. + 140174 ; 263 DEGREES. + 140132 ; 264 DEGREES. + 140100 ; 265 DEGREES. + 140050 ; 266 DEGREES. + 140030 ; 267 DEGREES. + 140012 ; 268 DEGREES. + 140004 ; 269 DEGREES. + 140000 ; 270 DEGREES. + 140004 ; 271 DEGREES. + 140012 ; 272 DEGREES. + 140030 ; 273 DEGREES. + 140050 ; 274 DEGREES. + 140100 ; 275 DEGREES. + 140132 ; 276 DEGREES. + 140174 ; 277 DEGREES. + 140241 ; 278 DEGREES. + 140312 ; 279 DEGREES. + 140371 ; 280 DEGREES. + 140457 ; 281 DEGREES. + 140550 ; 282 DEGREES. + 140644 ; 283 DEGREES. + 140747 ; 284 DEGREES. + 141060 ; 285 DEGREES. + 141173 ; 286 DEGREES. + 141314 ; 287 DEGREES. + 141442 ; 288 DEGREES. + 141575 ; 289 DEGREES. + 141736 ; 290 DEGREES. + 142102 ; 291 DEGREES. + 142253 ; 292 DEGREES. + 142430 ; 293 DEGREES. + 142612 ; 294 DEGREES. + 143001 ; 295 DEGREES. + 143174 ; 296 DEGREES. + 143372 ; 297 DEGREES. + 143576 ; 298 DEGREES. + 144010 ; 299 DEGREES. + 144225 ; 300 DEGREES. + 144446 ; 301 DEGREES. + 144672 ; 302 DEGREES. + 145125 ; 303 DEGREES. + 145363 ; 304 DEGREES. + 145625 ; 305 DEGREES. + 146073 ; 306 DEGREES. + 146345 ; 307 DEGREES. + 146623 ; 308 DEGREES. + 147105 ; 309 DEGREES. + 147373 ; 310 DEGREES. + 147663 ; 311 DEGREES. + 150162 ; 312 DEGREES. + 150463 ; 313 DEGREES. + 150770 ; 314 DEGREES. + 151277 ; 315 DEGREES. + 151613 ; 316 DEGREES. + 152134 ; 317 DEGREES. + 152455 ; 318 DEGREES. + 153005 ; 319 DEGREES. + 153335 ; 320 DEGREES. + 153673 ; 321 DEGREES. + 154233 ; 322 DEGREES. + 154574 ; 323 DEGREES. + 155142 ; 324 DEGREES. + 155513 ; 325 DEGREES. + 156070 ; 326 DEGREES. + 156445 ; 327 DEGREES. + 157026 ; 328 DEGREES. + 157412 ; 329 DEGREES. + 160000 ; 330 DEGREES. + 160371 ; 331 DEGREES. + 160766 ; 332 DEGREES. + 161362 ; 333 DEGREES. + 161762 ; 334 DEGREES. + 162364 ; 335 DEGREES. + 162772 ; 336 DEGREES. + 163400 ; 337 DEGREES. + 164010 ; 338 DEGREES. + 164422 ; 339 DEGREES. + 165036 ; 340 DEGREES. + 165452 ; 341 DEGREES. + 166073 ; 342 DEGREES. + 166512 ; 343 DEGREES. + 167134 ; 344 DEGREES. + 167560 ; 345 DEGREES. + 170206 ; 346 DEGREES. + 170634 ; 347 DEGREES. + 171262 ; 348 DEGREES. + 171712 ; 349 DEGREES. + 172343 ; 350 DEGREES. + 172775 ; 351 DEGREES. + 173430 ; 352 DEGREES. + 174065 ; 353 DEGREES. + 174521 ; 354 DEGREES. + 175156 ; 355 DEGREES. + 175613 ; 356 DEGREES. + 176247 ; 357 DEGREES. + 176706 ; 358 DEGREES. + 177344 ; 359 DEGREES. + .PAGE +; +; THIS IS THE SHIP BUFFER FOR STORING THE SPACE SHIP. +; THERE ARE TWO OF THEM TO AVOID PROBLEMS. +; +SHIPLC: .WORD SHIPB1 ;BUFFER POINTERS. + .WORD SHIPB2 +DRWSHP: .WORD 114120 ;BASIC SHIP START. + .WORD 170200 +SHOWX: .WORD 0 +SHOWY: .WORD 0 + .WORD DISTOP ;THE SUBROUTINE CALL NOW. +SHIPDP: .WORD 0 + .WORD DISTOP + .WORD 0 +; +; ROCKET FLAME CONTROL, AND BUFFER. +; +ONFIRE: .WORD DISTOP +FSUBC: .WORD 0 + .WORD DISTOP + .WORD 0 +; +; MESSAGE DISPLAY CONTROL. +; +INFO: .WORD DISTOP +SYSMES: .WORD 0 + .WORD DISTOP + .WORD 0 +; +; THIS SECTION CONTROLS THE DUST WHEN THE +; ROCKET FLAME HITS THE SURFACE OF THE MOON. +; +DRWDST: .WORD DISTOP +DUSTON: .WORD 0 + .WORD DISTOP + .WORD 0 +; +; THIS SECTION DRAWS AND STORES THE MOON, WHEN NECESSARY. +; +DRWLUN: .WORD DISTOP +MOONGO: .WORD 0 ;OVERLAYED BY POINTER + .WORD DISTOP + .WORD 0 +SHIPB1: + .=.+84. +SHIPB2: + .=.+84. +FLAMIN: + .=.+66. +; +; THIS SECTION IS WHERE THE EXPLOSION GOES (ALSO THE +; DUST FROM THE ROCKET ENGINE). +; +EXLIST: + .=.+2602. ;IT'S BIG (241*2*2+1) BUT NOT USED + ;JUST TO GIVE US A SIZE FEELING. + .=.+100. ;ALLOCATE 100 WORDS FOR THE STACK +STACK: .WORD ;DO NOT PUT ANYTHING IN IT + ;JUST DEFINE IT. + .PAGE +; +; THIS IS THE MESSAGE THAT IS DISPLAYED WHEN +; STARTING UP THE FIRST TIME +; +STARTM: .WORD 116720 + .WORD 0. + .WORD 650. + .WORD 170240 + .WORD 100000 + .ASCII ' R T - 1 1 L U N A R L A N D E R' + .BYTE 15,12 + .ASCII ' -----------------------------' + .BYTE 15,12,12,12 + .ASCII ' ALL INTERNAL NAVIGATIONAL SYSTEMS HAVE DIED ON YOU' + .BYTE 15,12 + .ASCII / IT LOOKS AS THOUGH YOU'RE GOING TO HAVE TO/ + .BYTE 15,12 + .ASCII ' LAND THIS THING ON YOUR OWN' + .BYTE 15,12,12 + .ASCII ' ***** GOOD BYE, GOOD LUCK, AND SORRY *****' + .BYTE 0 + .=.-1 + .EVEN + .WORD DISJMP + .WORD STARTM + .END START ;RESTART ADDRESS. + diff --git a/PDP11/lunar11/lunar.dag b/PDP11/lunar11/lunar.dag new file mode 100644 index 00000000..565dfeb7 Binary files /dev/null and b/PDP11/lunar11/lunar.dag differ diff --git a/PDP11/lunar11/lunar.lda b/PDP11/lunar11/lunar.lda new file mode 100644 index 00000000..565dfeb7 Binary files /dev/null and b/PDP11/lunar11/lunar.lda differ diff --git a/PDP11/lunar11/lunar.txt b/PDP11/lunar11/lunar.txt new file mode 100644 index 00000000..4bd16a41 --- /dev/null +++ b/PDP11/lunar11/lunar.txt @@ -0,0 +1,114 @@ + PLAYING MOONLANDER (LEM) + + +The object of moonlander is to land a lunar module on the +surface of the moon. The program will run on any 8K GT40 +with a light pen and a clock. If you are attached to a PDP-10 +you may use the ROM bootstrap to bring over the assembled +binary. If you are not "talking" to a PDP-10, you may load +in the binary loader (absolute loader) and load in the paper +tape version of the program. Note: the program will destroy +the binary loader when it starts running. + +When the program is loaded, it will automatically start and +display an "introductory message" on the screen. Future +restart of the program will not cause this message to be +displayed. Should any problems occur, the program may be +restarted at any time at location zero (000000). Power fail +protection is also provided. After starting (or restarting), +you then start playing the actual game. All numbers, speeds, +weights, etc., are actual numbers. They are for real. To +make the game more possible for an average person to play, I +have given him about 25 to 50% more fuel in the final stages +of landing than he would actually have. + +What the user sees on the screen is a broad and extremely +mountainous view of the moon. On the right is a list of data +parameters which the user may examine. They are height, +altitude, angle, fuel left, thrust, weight, horizontal velocity, +vertical velocity, horizontal acceleration, vertical accelera- +tion, distance and seconds. At the top of the screen, any +four of the values may be displayed. To display an item, the +user points the light pen at the item he wishes to display. +The item will then start blinking, to indicate that this is the +item to be displayed. The user then points the light pen at +one of the previously displayed items at the top of the screen. +The old item disappears and is replaced by the new item. +Note that it is possible to display any item anywhere, and even +possible to display one item four times at the top. Anyway, +the parameters mean the following. Height is the height in +feet above the surface (terrain) of the moon. It is the "radar" +height. Altitude is the height above the "mean" height of the +moon ( I guess you would call it "mare" level). Thus altitude +is not affected by terrain. Angle is the angle of the ship in +relationship to the vertical. 10 degrees, -70 degrees, etc. +Fuel left is the amount of fuel left in pounds. Thrust is the +amount of thrust (pounds) currently being produced by the engine. +Weight is the current earth weight of the ship. As fuel is +burned off, the acceleration will increase due to a lessening of +weight. The horizontal velocity is the current horizontal speed +of the ship, in feet per second. It is necessary to land at +under 10 fps horizontal, or else the ship will tip over. +Vertical velocity is the downward speed of the ship. Try to +keep it under 30 for the first few landings, until you get +better. A perfect landing is under 8 fps. The horizontal +and vertical accelerations are just those, in f/sec/sec. +With no power, the vertical acceleration is about 5 fp/s/s +down (-5). Distance is the horizontal distance (X direction) +you are from the projected landing site. Try to stay within +500 feet of this distance, because there are not too many +spots suitable for landing on the moon. Seconds is just the +time since you started trying to land. Thus you now know how +to display information and what they mean. + +To control the ship, two controls are provided. The first +controls the rolling or turning of the ship. This is accom- +plished by four arrows just above the display menu. Two point +left and two point right. The two pointing left mean rotate +left and the two pointing right mean rotate right. There is +a big and a little one in each direction. The big one means +to rotate "fast" and the small one means to rotate "slow". +Thus to rotate fast left, you point the light pen at +left arrow. To rotate slow right, you point the light pen at +the small arrow pointing to the right. The arrow will get +slightly brighter to indicate you have chosen it. Above the +arrow there is a bright, solid bar. This bar is your throttle +bar. To its left there is a number in percent (say 50%). This +number indicates the percentage of full thrust your rocket +engine is developing. The engine can develop anywhere from +10% to 100% thrust - full thrust is 10,500 pounds. The +engine thrust cannot fall below 10%. That is the way Grumman +built it (actually the subcontractor). To increase or decrease +your thrust, you merely slide the light pen up and down the bar. +The indicated percentage thrust will change accordingly. + +Now we come to actually flying the beast. The module appears +in the upper left hand corner of the screen and is traveling +down and to the right. Your job is to land at the correct +spot (for the time being, we will say this is when the +distance and height both reach zero). The first picture you +see, with the module in the upper left hand corner, is not +drawn to scale (the module appears too big in relationship +to the mountains). Should you successfully get below around +400 feet altitude, the view will now change to a closeup +view of the landing site, and everything will be in scale. +Remember, it is not easy to land the first few times, but +don't be disappointed, you'll do it. Be careful, the game +is extremely addictive. It is also quite dynamic. + +Incorporated in the game are just about everything the GT40 +can do. Letters, italics, light pen letters, a light bar, +dynamic motion, various line types and intensities (the moon +is not all the same brightness you know). It also shows that +the GT40 can do a lot of calculations while maintaining a +reasonable display. + +There are three possible landing sites on the Moon: + + 1. On the extreme left of the landscape + + 2. A small flat area to the right of the mountains + + 3. In the large "flat" area on the right + +Good Luck! diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index cd22da38..54eab84d 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -620,6 +620,14 @@ typedef struct pdp_dib DIB; #define INT_V_DLO 10 #define INT_V_DCI 11 #define INT_V_DCO 12 + /* VT simulation is sequential, so only + one interrupt is posted at a time. */ +#define INT_V_VTLP 13 /* XXX - Manual says VTLP, VTST have opposite */ +#define INT_V_VTST 14 /* XXX precedence, but that breaks LUNAR! */ + /* XXX How this happens is an utter mystery. */ +#define INT_V_VTCH 15 +#define INT_V_VTNM 16 +#define INT_V_LK 17 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -667,6 +675,11 @@ typedef struct pdp_dib DIB; #define INT_DLO (1u << INT_V_DLO) #define INT_DCI (1u << INT_V_DCI) #define INT_DCO (1u << INT_V_DCO) +#define INT_VTLP (1u << INT_V_VTLP) +#define INT_VTST (1u << INT_V_VTST) +#define INT_VTCH (1u << INT_V_VTCH) +#define INT_VTNM (1u << INT_V_VTNM) +#define INT_LK (1u << INT_V_LK) #define INT_PIR3 (1u << INT_V_PIR3) #define INT_PIR2 (1u << INT_V_PIR2) #define INT_PIR1 (1u << INT_V_PIR1) @@ -717,6 +730,11 @@ typedef struct pdp_dib DIB; #define IPL_DLO 4 #define IPL_DCI 4 #define IPL_DCO 4 +#define IPL_VTLP 4 +#define IPL_VTST 4 +#define IPL_VTCH 4 +#define IPL_VTNM 4 +#define IPL_LK 4 /* XXX just a guess */ #define IPL_PIR7 7 #define IPL_PIR6 6 diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 67849dfd..4c85af69 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -528,8 +528,8 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ { { NULL }, 1, 2, 0, 8, { 0 } }, /* DLV11J - fx CSRs */ { { NULL }, 1, 2, 8, 8 }, /* DJ11 */ { { NULL }, 1, 2, 16, 8 }, /* DH11 */ - { { NULL }, 1, 4, 0, 8, - {012000, 012010, 012020, 012030} }, /* GT40 */ + { { "VT" }, 1, 4, 0, 8, + {012000, 012010, 012020, 012030} }, /* VT11/GT40 - fx CSRs */ { { NULL }, 1, 2, 0, 8, {010400} }, /* LPS11 */ { { NULL }, 1, 2, 8, 8 }, /* DQ11 */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index ffa3aa93..75be6ea1 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -41,6 +41,7 @@ 22-Jul-05 RMS Fixed missing , in initializer (Doug Gwyn) 22-Dec-03 RMS Added second DEUNA/DELUA support 18-Oct-03 RMS Added DECtape off reel message + 14-Sep-03 PLB Added VT11 support 06-May-03 RMS Added support for second DEQNA/DELQA 09-Jan-03 RMS Added DELUA/DEUNA support 17-Oct-02 RMS Fixed bugs in branch, SOB address parsing @@ -100,6 +101,9 @@ extern DEVICE tq_dev; extern DEVICE ts_dev; extern DEVICE tu_dev; extern DEVICE ta_dev; +#ifdef USE_DISPLAY +extern DEVICE vt_dev; +#endif extern DEVICE xq_dev, xqb_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE ke_dev; @@ -167,6 +171,9 @@ DEVICE *sim_devices[] = { &tq_dev, &tu_dev, &ta_dev, +#ifdef USE_DISPLAY + &vt_dev, +#endif &xq_dev, &xqb_dev, &xu_dev, diff --git a/PDP11/pdp11_vt.c b/PDP11/pdp11_vt.c new file mode 100644 index 00000000..a7228272 --- /dev/null +++ b/PDP11/pdp11_vt.c @@ -0,0 +1,433 @@ +#ifdef USE_DISPLAY +/* pdp11_vt.c: PDP-11 VT11/VS60 Display Processor Simulation + + Copyright (c) 2003-2004, Philip L. Budne, Douglas A. Gwyn + Copyright (c) 1993-2003, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + vt VT11/VS60 Display Processor + + 05-Feb-04 DAG Improved VT11 emulation + Added VS60 support + 14-Sep-03 PLB Start from pdp11_lp.c +*/ + +/* + * this file is just a thin layer of glue to the simulator- + * independent XY Display simulation + */ + +#if defined (VM_VAX) /* VAX version */ +#include "vax_defs.h" +#elif defined(VM_PDP11) /* PDP-11 version */ +#include "pdp11_defs.h" +#else +#error "VT11/VS60 is supported only on the PDP-11 and VAX" +#endif + +#include "display/display.h" +#include "display/vt11.h" + +/* + * Timing parameters. Should allow some runtime adjustment, + * since several different configurations were shipped, including: + * + * GT40: PDP-11/05 with VT11 display processor + * GT44: PDP-11/40 with VT11 display processor + * GT46: PDP-11/34 with VT11 display processor + * GT62: PDP-11/34a with VS60 display system + */ + +/* + * run a VT11/VS60 cycle every this many PDP-11 "cycle" times; + * + * Under the X Window System (X11), this includes polling + * for events (mouse movement)! + */ +#define VT11_DELAY 1 + +/* + * memory cycle time + */ +#define MEMORY_CYCLE 1 /* either .98 or 1.2 us? */ + +/* + * delay in microseconds between VT11/VS60 cycles: + * VT11/VS60 and PDP-11 CPU's share the same memory bus, + * and each VT11/VS60 instruction requires a memory reference; + * figure each PDP11 instruction requires two memory references + */ +#define CYCLE_US (MEMORY_CYCLE*(VT11_DELAY*2+1)) + +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + +DEVICE vt_dev; +t_stat vt_rd(int32 *data, int32 PA, int32 access); +t_stat vt_wr(int32 data, int32 PA, int32 access); +t_stat vt_svc(UNIT *uptr); +t_stat vt_reset(DEVICE *dptr); +t_stat vt_boot(int32 unit, DEVICE *dptr); +t_stat vt_set_crt(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vt_show_crt(FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat vt_set_scale(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vt_show_scale(FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat vt_set_hspace(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vt_show_hspace(FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat vt_set_vspace(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vt_show_vspace(FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat vt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +char *vt_description (DEVICE *dptr); + +/* VT11/VS60 data structures + + vt_dev VT11 device descriptor + vt_unit VT11 unit descriptor + vt_reg VT11 register list + vt_mod VT11 modifier list +*/ +#define IOLN_VT11 010 /* VT11 */ +#define IOLN_VS60 040 /* VS60 */ +DIB vt_dib = { IOBA_AUTO, IOLN_VT11, &vt_rd, &vt_wr, + 4, IVCL(VTST), VEC_AUTO, {NULL} }; + /* (VT11 uses only the first 3 interrupt vectors) */ + +UNIT vt_unit = { + UDATA (&vt_svc, UNIT_SEQ, 0), VT11_DELAY}; + +REG vt_reg[] = { + { GRDATA (DEVADDR, vt_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, vt_dib.vec, DEV_RDX, 16, 0), REG_HRO }, + { NULL } }; + +MTAB vt_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "CRT", "CRT={VR14|VR17|VR48}", + &vt_set_crt, &vt_show_crt, NULL, "CRT Type" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SCALE", "SCALE={1|2|4|8}", + &vt_set_scale, &vt_show_scale, NULL, "Pixel Scale Factor" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "HSPACE", "HSPACE={NARROW|NORMAL}", + &vt_set_hspace, &vt_show_hspace, NULL, "Horizontal Spacing" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VSPACE", "VSPACE={TALL|NORMAL}", + &vt_set_vspace, &vt_show_vspace, NULL, "Vertical Spacing" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 020, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL, "Bus address" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL, "Interrupt vector" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL, "Enable autoconfiguration of address & vector" }, + { 0 } }; + +DEVICE vt_dev = { + "VT", &vt_unit, vt_reg, vt_mod, + 1, 8, 31, 1, DEV_RDX, 16, + NULL, NULL, &vt_reset, + &vt_boot, NULL, NULL, + &vt_dib, DEV_DIS | DEV_DISABLE | DEV_UBUS | DEV_Q18, + 0, 0, NULL, NULL, NULL, NULL, NULL, + &vt_description +}; + +/* VT11/VS60 routines + + vt_rd I/O page read + vt_wr I/O page write + vt_svc process event + vt_reset process reset + vt_boot bootstrap device +*/ + +t_stat +vt_rd(int32 *data, int32 PA, int32 access) +{ + switch (PA & 036) { + case 000: *data = vt11_get_dpc(); return SCPE_OK; + case 002: *data = vt11_get_mpr(); return SCPE_OK; + case 004: *data = vt11_get_xpr(); return SCPE_OK; + case 006: *data = vt11_get_ypr(); return SCPE_OK; + case 010: if (!VS60) break; *data = vt11_get_rr(); return SCPE_OK; + case 012: if (!VS60) break; *data = vt11_get_spr(); return SCPE_OK; + case 014: if (!VS60) break; *data = vt11_get_xor(); return SCPE_OK; + case 016: if (!VS60) break; *data = vt11_get_yor(); return SCPE_OK; + case 020: if (!VS60) break; *data = vt11_get_anr(); return SCPE_OK; + case 022: if (!VS60) break; *data = vt11_get_scr(); return SCPE_OK; + case 024: if (!VS60) break; *data = vt11_get_nr(); return SCPE_OK; + case 026: if (!VS60) break; *data = vt11_get_sdr(); return SCPE_OK; + case 030: if (!VS60) break; *data = vt11_get_str(); return SCPE_OK; + case 032: if (!VS60) break; *data = vt11_get_sar(); return SCPE_OK; + case 034: if (!VS60) break; *data = vt11_get_zpr(); return SCPE_OK; + case 036: if (!VS60) break; *data = vt11_get_zor(); return SCPE_OK; + } + return SCPE_NXM; +} + +t_stat +vt_wr(int32 data, int32 PA, int32 access) +{ + uint16 d = data & 0177777; /* mask just in case */ + + switch (PA & 037) { + case 000: /* DPC */ + /* set the simulator PC */ + vt11_set_dpc(d); + + /* clear interrupt request (only one will be simulated at a time) */ + CLR_INT (VTST); + CLR_INT (VTLP); + CLR_INT (VTCH); + CLR_INT (VTNM); + + /* start the display processor by running a cycle */ + return vt_svc(&vt_unit); + + case 002: vt11_set_mpr(d); return SCPE_OK; + case 004: vt11_set_xpr(d); return SCPE_OK; + case 006: vt11_set_ypr(d); return SCPE_OK; + case 010: if (!VS60) break; vt11_set_rr(d); return SCPE_OK; + case 012: if (!VS60) break; vt11_set_spr(d); return SCPE_OK; + case 014: if (!VS60) break; vt11_set_xor(d); return SCPE_OK; + case 016: if (!VS60) break; vt11_set_yor(d); return SCPE_OK; + case 020: if (!VS60) break; vt11_set_anr(d); return SCPE_OK; + case 022: if (!VS60) break; vt11_set_scr(d); return SCPE_OK; + case 024: if (!VS60) break; vt11_set_nr(d); return SCPE_OK; + case 026: if (!VS60) break; vt11_set_sdr(d); return SCPE_OK; + case 030: if (!VS60) break; vt11_set_str(d); return SCPE_OK; + case 032: if (!VS60) break; vt11_set_sar(d); return SCPE_OK; + case 034: if (!VS60) break; vt11_set_zpr(d); return SCPE_OK; + case 036: if (!VS60) break; vt11_set_zor(d); return SCPE_OK; + } + return SCPE_NXM; +} + +/* + * here to run a display processor cycle, called as a SIMH + * "device service routine". + * + * Under X11 this includes polling for events, so it can't be + * call TOO infrequently... + */ +t_stat +vt_svc(UNIT *uptr) +{ + if (vt11_cycle(CYCLE_US, 1)) + sim_activate (&vt_unit, vt_unit.wait); /* running; reschedule */ + return SCPE_OK; +} + +t_stat +vt_reset(DEVICE *dptr) +{ + if (!(dptr->flags & DEV_DIS)) + vt11_reset(); + CLR_INT (VTST); + CLR_INT (VTLP); + CLR_INT (VTCH); + CLR_INT (VTNM); + sim_cancel (&vt_unit); /* deactivate unit */ + return auto_config ("VT", (dptr->flags & DEV_DIS) ? 0 : 1); +} + +/* + * GT4x/GT62 bootstrap (acts as remote terminal) + */ +t_stat +vt_boot(int32 unit, DEVICE *dptr) +{ + /* XXX should do something like vt11_set_dpc(&appropriate_ROM_image) */ + return SCPE_NOFNC; /* not yet implemented */ +} + +/* SET/SHOW VT options: */ + +t_stat +vt_set_crt(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + char gbuf[CBUFSIZE]; + if (vt11_init) + return SCPE_ALATT; /* should be "changes locked out" */ + if (cptr == NULL) + return SCPE_ARG; + get_glyph(cptr, gbuf, 0); + if (strcmp(gbuf, "VR14") == 0) + vt11_display = DIS_VR14; + else if (strcmp(gbuf, "VR17") == 0) + vt11_display = DIS_VR17; + else if (strcmp(gbuf, "VR48") == 0) + vt11_display = DIS_VR48; + else + return SCPE_ARG; + vt_dib.lnt = (VS60) ? IOLN_VS60 : IOLN_VT11; + return SCPE_OK; +} + +t_stat +vt_show_crt(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st, "crt=VR%d", (int)vt11_display); + return SCPE_OK; +} + +t_stat +vt_set_scale(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + t_stat r; + t_value v; + if (vt11_init) + return SCPE_ALATT; /* should be "changes locked out" */ + if (cptr == NULL) + return SCPE_ARG; + v = get_uint(cptr, 10, 8, &r); + if (r != SCPE_OK) + return r; + if (v != 1 && v != 2 && v != 4 && v != 8) + return SCPE_ARG; + vt11_scale = v; + return SCPE_OK; +} + +t_stat +vt_show_scale(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st, "scale=%d", (int)vt11_scale); + return SCPE_OK; +} + +t_stat +vt_set_hspace(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + char gbuf[CBUFSIZE]; + if (vt11_init) + return SCPE_ALATT; /* should be "changes locked out" */ + if (cptr == NULL) + return SCPE_ARG; + get_glyph(cptr, gbuf, 0); + if (strcmp(gbuf, "NARROW") == 0) + vt11_csp_w = 12; + else if (strcmp(gbuf, "NORMAL") == 0) + vt11_csp_w = 14; + else + return SCPE_ARG; + return SCPE_OK; +} + +t_stat +vt_show_hspace(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st, "hspace=%s", vt11_csp_w==12 ? "narrow" : "normal"); + return SCPE_OK; +} + +t_stat +vt_set_vspace(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + char gbuf[CBUFSIZE]; + if (vt11_init) + return SCPE_ALATT; /* should be "changes locked out" */ + if (cptr == NULL) + return SCPE_ARG; + get_glyph(cptr, gbuf, 0); + if (strcmp(gbuf, "TALL") == 0) + vt11_csp_h = 26; + else if (strcmp(gbuf, "NORMAL") == 0) + vt11_csp_h = 24; + else + return SCPE_ARG; + return SCPE_OK; +} + +t_stat +vt_show_vspace(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st, "vspace=%s", vt11_csp_h==26 ? "tall" : "normal"); + return SCPE_OK; +} + +/* interface routines (called from display simulator) */ + +void +vt_stop_intr(void) +{ + SET_INT (VTST); +} + +void +vt_lpen_intr(void) +{ + SET_INT (VTLP); +} + +void +vt_char_intr(void) +{ + SET_INT (VTCH); +} + +void +vt_name_intr(void) +{ + SET_INT (VTNM); +} + +/* fetch memory */ +int +vt_fetch(uint32 addr, vt11word *wp) +{ + /* On PDP-11 Unibus 22-bit systems, the VT11/VS60 behaves as + an 18-bit Unibus peripheral and must go through the I/O map. */ + + /* apply Unibus map, when appropriate */ + if (Map_ReadW(addr, 2, wp) == 0) + return 0; /* no problem */ + /* else mapped address lies outside configured memory range */ + + *wp = 0164000; /* DNOP; just updates DPC if used */ + /* which shouldn't happen */ + return 1; /* used to set "time_out" flag */ +} + +char *vt_description (DEVICE *dptr) +{ +return (VS60) ? "VS60 Display processor" + : "VT11 Display processor"; +} + +#ifdef VM_PDP11 +/* PDP-11 simulation provides this */ +extern int32 SR; /* switch register */ +#else +int32 SR; /* switch register */ +#endif + +void +cpu_set_switches(unsigned long val) +{ + SR = val; +} + +unsigned long +cpu_get_switches(void) +{ + return SR; +} +#else /* USE_DISPLAY not defined */ +char pdp11_vt_unused; /* sometimes empty object modules cause problems */ +#endif /* USE_DISPLAY not defined */ diff --git a/Visual Studio Projects/PDP1.vcproj b/Visual Studio Projects/PDP1.vcproj index a9af5c51..4937e3a0 100644 --- a/Visual Studio Projects/PDP1.vcproj +++ b/Visual Studio Projects/PDP1.vcproj @@ -45,7 +45,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="./;../;../PDP1/" - PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID" + PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;USE_DISPLAY" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -128,7 +128,7 @@ InlineFunctionExpansion="1" OmitFramePointers="true" AdditionalIncludeDirectories="./;../;../PDP1/" - PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID" + PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;USE_DISPLAY" StringPooling="true" RuntimeLibrary="0" EnableFunctionLevelLinking="true" @@ -189,6 +189,10 @@ Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > + + @@ -201,6 +205,10 @@ RelativePath="..\PDP1\pdp1_dcs.c" > + + @@ -261,11 +269,19 @@ RelativePath="..\sim_tmxr.c" > + + + + @@ -318,6 +334,10 @@ RelativePath="..\sim_tmxr.h" > + + + + @@ -339,6 +343,10 @@ RelativePath="..\PDP11\pdp11_vh.c" > + + @@ -407,11 +415,23 @@ RelativePath="..\sim_tmxr.c" > + + + + + + @@ -504,6 +524,14 @@ RelativePath="..\sim_tmxr.h" > + + + + -Douglas A Gwyn -February 5, 2004 - -Designed for use with Bob Supnik's SIMH, but the code should be easily -portable, and usable standalone (see vttest.c for an example). - -Display code is provided for X11 (Unix/VMS) and Win32. -We're not GUI programmers, so the code is PRIMITIVE!! - -Started from VC8E simulator by Douglas W. Jones -(distribution 5, of Feb 4, 1997); - - This PDP8 Emulator was written by Douglas W. Jones at the - University of Iowa. It is distributed as freeware, of - uncertain function and uncertain utility. - -Original phosphor decay constants for Type 30 display from XMame 0.72.1 - -VT11 support GREATLY enhanced (and VT48 support added) and -other general improvements from Douglas A Gwyn. - -In the interest of fair play we have supplied two makefiles (neither -of which is named Makefile nor makefile), one which works under all -flavors of "make" (after necessary editing, in the traditional manner), -and one which functions only under the GNU version of make (sometimes -installed as "gmake", but the default "make" on many systems). We have -not added a third flavor which uses BSD make enhancements, because our -deeply held roots (over 40 combined years of Unix experience by the -authors) demand that things should work on all platforms. Both the -Linux and Windows worlds violate this simple credo (everything works so -long as you use OUR preferred software), and many current users may not -even realize that editing Makefiles used to be de rigeur. Since the -GNU environment is widely available and "gmake" has features that -support automatic configuration for multiple platforms, we have -supplied thr GNU-specific variant with the expectation that many users -will find it more convenient. You can copy or link whichever flavor of -makefile suits your taste to whichever spelling of "makefile" suits -your fancy, or invoke "make" with the -f flag specifying the desired -makefile. - -To compile test programs: -======================== -On Unix: - # edit smakefile to match your environment - make -f smakefile -or - gmake -f gmakefile - -On Win32 (using Cygwin); - make -f gmakefile WIN32=1 - -On Win32 (using MINGW): - # edit smakefile to match your environment - make -f smakefile -or - mingw32-make -f gmakefile WIN32=1 -or - execute build-mingw.bat in a DOS command window - -creates: - - munch: standalone simulation of PDP-1 munching squares; - examines console "test switches" (see next section) - - vt11: sequences through VT11/VS60 simulator test displays; - shows how the diplay-processor simulator can be used - from applications other than PDP-11 simulators - -Console switches: -================ - -Upto 18 simulated console switches, toggled by hitting keys: - -123 456 789 qwe rty uio - -space bar clears all switches. - -Spacewar Switches: -================= - -Key presses for simulated Spacewar control box switches; - -action player - 1 2 -rotate clockwise a k -rotate counter clockwise s l -fire engines d ; -launch torpedo f ' -hyperspace (both at once) as kl - -Light pen: -========= - -The light pen is active when any mouse button is held down. - -Mouse button 1 acts as a "tip switch" for models so equipped (VS60). -The light pen may be dragged while active. - -Too many compile time parameters: -================================ - -Read the comments in display.c for more explanations!! - -DISPLAY_TYPE default display type, one of: - DIS_VR14, DIS_VR17, DIS_VR20, DIS_VR48, DIS_TYPE30, DIS_TYPE340 - selects screen characteristics (phosphor, dimensions). - - Only affects programs which do not make an expicit - display_init() call. - -PIX_SCALE one of RES_FULL, RES_HALF, RES_QUARTER, RES_EIGHTH - selects default display scaling factor. - -PEN_RADIUS default radius of light pen in (scaled) pixels - -MAXELAPSED Upper limit in real microseconds between polls/delays -MINELAPSED Lower limit in real microseconds between polls/delays -MINDELAY Lower limit in real microseconds for attempted delay -MAXDELAY Upper limit in real microseconds for attempted delay -GAINSHIFT delay_check increment/decrement gain factor - -In display system support (x11.c, win32.c); - -PIX_SIZE selects displayed pixel size (default 1) - makes screen larger, useful when display scaled to small size - -Programming interface: -===================== - -see display.h - -Source repository: -================= - -Up-to-date Sources are available by anonymous CVS. -See http://www.ultimate.com/phil/xy/ +$Id: README,v 1.15 2004/02/09 07:20:18 phil Exp $ + +XY Display Simulation +Simulates XY plotting displays used on DEC PDP systems. + + Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors shall + not be used in advertising or otherwise to promote the sale, use or + other dealings in this Software without prior written authorization + from the authors. + +Phil Budne +Douglas A Gwyn +February 5, 2004 + +Designed for use with Bob Supnik's SIMH, but the code should be easily +portable, and usable standalone (see vttest.c for an example). + +Display code is provided for X11 (Unix/VMS) and Win32. +We're not GUI programmers, so the code is PRIMITIVE!! + +Started from VC8E simulator by Douglas W. Jones +(distribution 5, of Feb 4, 1997); + + This PDP8 Emulator was written by Douglas W. Jones at the + University of Iowa. It is distributed as freeware, of + uncertain function and uncertain utility. + +Original phosphor decay constants for Type 30 display from XMame 0.72.1 + +VT11 support GREATLY enhanced (and VT48 support added) and +other general improvements from Douglas A Gwyn. + +In the interest of fair play we have supplied two makefiles (neither +of which is named Makefile nor makefile), one which works under all +flavors of "make" (after necessary editing, in the traditional manner), +and one which functions only under the GNU version of make (sometimes +installed as "gmake", but the default "make" on many systems). We have +not added a third flavor which uses BSD make enhancements, because our +deeply held roots (over 40 combined years of Unix experience by the +authors) demand that things should work on all platforms. Both the +Linux and Windows worlds violate this simple credo (everything works so +long as you use OUR preferred software), and many current users may not +even realize that editing Makefiles used to be de rigeur. Since the +GNU environment is widely available and "gmake" has features that +support automatic configuration for multiple platforms, we have +supplied thr GNU-specific variant with the expectation that many users +will find it more convenient. You can copy or link whichever flavor of +makefile suits your taste to whichever spelling of "makefile" suits +your fancy, or invoke "make" with the -f flag specifying the desired +makefile. + +To compile test programs: +======================== +On Unix: + # edit smakefile to match your environment + make -f smakefile +or + gmake -f gmakefile + +On Win32 (using Cygwin); + make -f gmakefile WIN32=1 + +On Win32 (using MINGW): + # edit smakefile to match your environment + make -f smakefile +or + mingw32-make -f gmakefile WIN32=1 +or + execute build-mingw.bat in a DOS command window + +creates: + + munch: standalone simulation of PDP-1 munching squares; + examines console "test switches" (see next section) + + vt11: sequences through VT11/VS60 simulator test displays; + shows how the diplay-processor simulator can be used + from applications other than PDP-11 simulators + +Console switches: +================ + +Upto 18 simulated console switches, toggled by hitting keys: + +123 456 789 qwe rty uio + +space bar clears all switches. + +Spacewar Switches: +================= + +Key presses for simulated Spacewar control box switches; + +action player + 1 2 +rotate clockwise a k +rotate counter clockwise s l +fire engines d ; +launch torpedo f ' +hyperspace (both at once) as kl + +Light pen: +========= + +The light pen is active when any mouse button is held down. + +Mouse button 1 acts as a "tip switch" for models so equipped (VS60). +The light pen may be dragged while active. + +Too many compile time parameters: +================================ + +Read the comments in display.c for more explanations!! + +DISPLAY_TYPE default display type, one of: + DIS_VR14, DIS_VR17, DIS_VR20, DIS_VR48, DIS_TYPE30, DIS_TYPE340 + selects screen characteristics (phosphor, dimensions). + + Only affects programs which do not make an expicit + display_init() call. + +PIX_SCALE one of RES_FULL, RES_HALF, RES_QUARTER, RES_EIGHTH + selects default display scaling factor. + +PEN_RADIUS default radius of light pen in (scaled) pixels + +MAXELAPSED Upper limit in real microseconds between polls/delays +MINELAPSED Lower limit in real microseconds between polls/delays +MINDELAY Lower limit in real microseconds for attempted delay +MAXDELAY Upper limit in real microseconds for attempted delay +GAINSHIFT delay_check increment/decrement gain factor + +In display system support (x11.c, win32.c); + +PIX_SIZE selects displayed pixel size (default 1) + makes screen larger, useful when display scaled to small size + +Programming interface: +===================== + +see display.h + +Source repository: +================= + +Up-to-date Sources are available by anonymous CVS. +See http://www.ultimate.com/phil/xy/ diff --git a/display/build_mingw.bat b/display/build_mingw.bat index 49222c11..38f5b489 100644 --- a/display/build_mingw.bat +++ b/display/build_mingw.bat @@ -1,12 +1,12 @@ -@echo off -rem $Id: build_mingw.bat,v 1.1 2004/01/25 17:48:03 phil Exp $ -rem Compile all test programs using MINGW make and gcc environment -rem -rem If needed, define the path for the MINGW bin directory. -rem (this should already be set if MINGW was installed correctly) -rem -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 path C:\MinGW\bin;D:\MinGW\bin;E:\MinGW\bin;%path% -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make WIN32=1 -f gmakefile %1 %2 %3 %4 +@echo off +rem $Id: build_mingw.bat,v 1.1 2004/01/25 17:48:03 phil Exp $ +rem Compile all test programs using MINGW make and gcc environment +rem +rem If needed, define the path for the MINGW bin directory. +rem (this should already be set if MINGW was installed correctly) +rem +gcc -v 1>NUL 2>NUL +if ERRORLEVEL 1 path C:\MinGW\bin;D:\MinGW\bin;E:\MinGW\bin;%path% +gcc -v 1>NUL 2>NUL +if ERRORLEVEL 1 echo "MinGW Environment Unavailable" +mingw32-make WIN32=1 -f gmakefile %1 %2 %3 %4 diff --git a/display/carbon.c b/display/carbon.c new file mode 100644 index 00000000..fb0c2f23 --- /dev/null +++ b/display/carbon.c @@ -0,0 +1,328 @@ +/* + * $Id: carbon.c,v 1.2 2005/08/06 21:09:03 phil Exp $ + * Mac OS X Carbon support for XY display simulator + * John Dundas + * December 2004 + * + * This is a simplistic driver under Mac OS Carbon for the XY display + * simulator. + * + * A more interesting driver would use OpenGL directly. + */ + +#include +#include +#include +#include +#include "ws.h" +#include "xy.h" + +#include +#include + +#define ARRAYLEN(a) (sizeof (a) / sizeof (a[0])) + +#ifndef PIX_SIZE +#define PIX_SIZE 1 +#endif + +/* + * light pen location + * see ws.h for full description + */ +int ws_lp_x = -1; +int ws_lp_y = -1; + +static RGBColor blckColor = { 0x0000, 0x0000, 0x0000 }; +static RGBColor whteColor = { 0xFFFF, 0xFFFF, 0xFFFF }; +static WindowRef mainWind; +static RgnHandle rgn; +static MouseTrackingRef mouseRef; +static int xpixels, ypixels; +static int buttons = 0; /* tracks state of all buttons */ +static EventTargetRef EventDispatchTarget; + +void MyEventWait ( EventTimeout timeout ) /* double */ +{ + EventRef theEvent; + + if (ReceiveNextEvent (0, NULL, timeout, true, &theEvent) == noErr) { + SendEventToEventTarget (theEvent, EventDispatchTarget); + ReleaseEvent (theEvent); + } +} + +static pascal OSStatus doMouseEvent ( EventHandlerCallRef handlerRef, + EventRef event, + void *userData ) +{ + OSStatus err = eventNotHandledErr; + Point start; + GrafPtr prevPort; + + /* make sure the display is the current grafport */ + if (!QDSwapPort (GetWindowPort (mainWind), &prevPort)) + prevPort = NULL; + switch (GetEventKind (event)) { + case kEventMouseEntered: + if (ActiveNonFloatingWindow () != mainWind) + break; + SetThemeCursor (kThemeCrossCursor); + break; + case kEventMouseExited: + if (ActiveNonFloatingWindow () != mainWind) + break; + SetThemeCursor (kThemeArrowCursor); + break; + case kEventMouseDown: + GetEventParameter (event, kEventParamMouseLocation, + typeQDPoint, NULL, sizeof (typeQDPoint), NULL, &start); + GlobalToLocal (&start); + ws_lp_x = start.h; + ws_lp_y = ypixels - start.v; + display_lp_sw = 1; + break; + case kEventMouseUp: + display_lp_sw = 0; + ws_lp_x = ws_lp_y = -1; + break; + default: + break; + } + if (prevPort) + SetPort (prevPort); + return (err); +} + +static pascal OSStatus updateWindow ( EventHandlerCallRef handlerRef, + EventRef event, + void *userData ) +{ + OSStatus err = eventNotHandledErr; + + switch (GetEventKind (event)) { + case kEventWindowActivated: + /* update menus */ + break; + case kEventWindowClose: /* Override window close */ + err = noErr; + break; + case kEventWindowDrawContent: + display_repaint (); + err = noErr; + default: + break; + } + return (err); +} + +static pascal OSStatus doKbdEvent ( EventHandlerCallRef handlerRef, + EventRef event, + void *userData ) +{ + UInt32 c, m; + char key; + + GetEventParameter (event, kEventParamKeyCode, + typeUInt32, NULL, sizeof (typeUInt32), NULL, &c); + GetEventParameter (event, kEventParamKeyMacCharCodes, + typeChar, NULL, sizeof (typeChar), NULL, &key); + GetEventParameter (event, kEventParamKeyModifiers, + typeUInt32, NULL, sizeof (typeUInt32), NULL, &m); + + /* Keys with meta-modifiers are not allowed at this time. */ +#define KEY_MODIFIERS (cmdKey | optionKey | kEventKeyModifierFnMask) + if (m & KEY_MODIFIERS) + return (eventNotHandledErr); + switch (GetEventKind (event)) { + case kEventRawKeyRepeat: + case kEventRawKeyDown: + display_keydown (key); + break; + case kEventRawKeyUp: + display_keyup (key); + break; + default: + break; + } + return (noErr); +} + +int ws_init ( char *crtname, /* crt type name */ + int xp, /* screen size in pixels */ + int yp, + int colors ) /* colors to support (not used) */ +{ + WindowAttributes windowAttrs; + Rect r; + CFStringRef str; + static MouseTrackingRegionID mouseID = { 'AAPL', 0 }; + static const EventTypeSpec moEvent[] = { + { kEventClassMouse, kEventMouseEntered }, + { kEventClassMouse, kEventMouseExited }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + }; + static const EventTypeSpec wuEvent[] = { + { kEventClassWindow, kEventWindowDrawContent }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowActivated}, + }; + static const EventTypeSpec kdEvent[] = { + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp}, + }; + + + xpixels = xp; /* save screen size */ + ypixels = yp; + r.top = 100; r.left = 100; r.bottom = r.top + yp; r.right = r.left + xp; + + /* should check this r against GetQDGlobalsScreenBits (&screen); */ + windowAttrs = kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute; + if (CreateNewWindow (kDocumentWindowClass, windowAttrs, &r, &mainWind) != noErr) + return (0); + if (str = CFStringCreateWithCString (kCFAllocatorDefault, crtname, + kCFStringEncodingASCII)) { + SetWindowTitleWithCFString (mainWind, str); + CFRelease (str); + } + SetPortWindowPort (mainWind); +/* + * Setup to handle events + */ + EventDispatchTarget = GetEventDispatcherTarget (); + InstallEventHandler (GetWindowEventTarget (mainWind), + NewEventHandlerUPP (doMouseEvent), ARRAYLEN(moEvent), + (EventTypeSpec *) &moEvent, NULL, NULL); + InstallEventHandler (GetWindowEventTarget (mainWind), + NewEventHandlerUPP (updateWindow), ARRAYLEN(wuEvent), + (EventTypeSpec *) &wuEvent, NULL, NULL); + InstallEventHandler (GetWindowEventTarget (mainWind), + NewEventHandlerUPP (doKbdEvent), ARRAYLEN(kdEvent), + (EventTypeSpec *) &kdEvent, NULL, NULL); + /* create region to track cursor shape */ + r.top = 0; r.left = 0; r.bottom = yp; r.right = xp; + rgn = NewRgn (); + RectRgn (rgn, &r); + CloseRgn (rgn); + CreateMouseTrackingRegion (mainWind, rgn, NULL, + kMouseTrackingOptionsLocalClip, mouseID, NULL, NULL, &mouseRef); + + ShowWindow (mainWind); + RGBForeColor (&blckColor); + PaintRect (&r); + RGBBackColor (&blckColor); + return (1); +} + +void *ws_color_black (void) +{ + return (&blckColor); +} + +void *ws_color_white (void) +{ + return (&whteColor); +} + +void *ws_color_rgb ( int r, + int g, + int b ) +{ + RGBColor *color; + + if ((color = malloc (sizeof (RGBColor))) != NULL) { + color->red = r; + color->green = g; + color->blue = b; + } + return (color); +} + +/* put a point on the screen */ +void ws_display_point ( int x, + int y, + void *color ) +{ +#if PIX_SIZE != 1 + Rect r; +#endif + + if (x > xpixels || y > ypixels) + return; + + y = ypixels - y /* - 1 */; + +#if PIX_SIZE == 1 + SetCPixel (x, y, (color == NULL) ? &blckColor : color); +#else + r.top = y * PIX_SIZE; + r.left = x * PIX_SIZE; + r.bottom = (y + 1) * PIX_SIZE; + r.right = (x + 1) * PIX_SIZE; + + RGBForeColor ((color == NULL) ? &blckColor : color); + PaintRect (&r); +#endif +} + +void ws_sync (void) +{ + ; +} + +/* + * elapsed wall clock time since last call + * +INF on first call + */ + +struct elapsed_state { + struct timeval tvs[2]; + int new; +}; + +static unsigned long +elapsed(struct elapsed_state *ep) +{ + unsigned long val; + + gettimeofday(&ep->tvs[ep->new], NULL); + if (ep->tvs[!ep->new].tv_sec == 0) + val = ~0L; + else + val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 + + (ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec)); + ep->new = !ep->new; + return val; +} + +/* called periodically */ +int ws_poll ( int *valp, + int maxusec ) +{ + static struct elapsed_state es; /* static to avoid clearing! */ + + elapsed(&es); /* start clock */ + do { + unsigned long e; + + MyEventWait (maxusec * kEventDurationMicrosecond); + e = elapsed(&es); + maxusec -= e; + } while (maxusec > 10000); /* 10ms */ + return (1); +} + +void ws_beep (void) +{ + SysBeep (3); +} + +/* public version, used by delay code */ +unsigned long os_elapsed (void) +{ + static struct elapsed_state es; + return (elapsed (&es)); +} diff --git a/display/display.c b/display/display.c index aa276435..ef3f9840 100644 --- a/display/display.c +++ b/display/display.c @@ -1,1053 +1,1059 @@ -/* - * $Id: display.c,v 1.57 2004/02/04 16:59:01 phil Exp $ - * Simulator and host O/S independent XY display simulator - * Phil Budne - * September 2003 - * - * with changes by Douglas A. Gwyn, 21 Jan. 2004 - * - * started from PDP-8/E simulator vc8e.c; - * This PDP8 Emulator was written by Douglas W. Jones at the - * University of Iowa. It is distributed as freeware, of - * uncertain function and uncertain utility. - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#include -#include -#include -#include /* for USHRT_MAX */ -#include "ws.h" -#include "display.h" - -/* - * The user may select (at compile time) how big a window is used to - * emulate the display. Using smaller windows saves memory and screen space. - * - * Type 30 has 1024x1024 addressing, but only 512x512 visible points. - * VR14 has only 1024x768 visible points; VR17 has 1024x1024 visible points. - * VT11 supports 4096x4096 addressing, clipping to the lowest 1024x1024 region. - * VR48 has 1024x1024 visible points in the main display area and 128x1024 - * visible points in a menu area on the right-hand side (1152x1024 total). - * VT48 supports 8192x8192 (signed) main-area addressing, clipping to a - * 1024x1024 window which can be located anywhere within that region. - * (XXX -- That is what the VT11/VT48 manuals say; however, evidence suggests - * that the VT11 may actually support 8192x8192 (signed) addressing too.) - */ - -/* Define the default display type (if display_init() not called) */ -#ifndef DISPLAY_TYPE -#define DISPLAY_TYPE DIS_TYPE30 -#endif /* DISPLAY_TYPE not defined */ - -/* select a default resolution if display_init() not called */ -/* XXX keep in struct display? */ -#ifndef PIX_SCALE -#define PIX_SCALE RES_HALF -#endif /* PIX_SCALE not defined */ - -/* select a default light-pen hit radius if display_init() not called */ -#ifndef PEN_RADIUS -#define PEN_RADIUS 4 -#endif /* PEN_RADIUS not defined */ - -/* - * note: displays can have up to two different colors (eg VR20) - * each color can be made up of any number of phosphors - * with different colors and decay characteristics (eg Type 30) - */ - -#define ELEMENTS(X) (sizeof(X)/sizeof(X[0])) - -struct phosphor { - double red, green, blue; - double level; /* decay level (0.5 for half life) */ - double t_level; /* seconds to decay to level */ -}; - -struct color { - struct phosphor *phosphors; - int nphosphors; - int half_life; /* for refresh calc */ -}; - -struct display { - enum display_type type; - char *name; - struct color *color0, *color1; - short xpoints, ypoints; -}; - -/* - * original phosphor constants from Raphael Nabet's XMame 0.72.1 PDP-1 sim. - * not even sure Type30 really used P17 (guess by Daniel P. B. Smith) - */ -static struct phosphor p17[] = { - {0.11, 0.11, 1.0, 0.5, 0.05}, /* fast blue */ - {1.0, 1.0, 0.11, 0.5, 0.20} /* slow yellow/green */ -}; -static struct color color_p17 = { p17, ELEMENTS(p17), 125000 }; - -/* green phosphor for VR14, VR17, VR20 */ -static struct phosphor p29[] = {{0.0260, 1.0, 0.00121, 0.5, 0.025}}; -struct color color_p29 = { p29, ELEMENTS(p29), 25000 }; - -static struct phosphor p40[] = { - /* P40 blue-white spot with yellow-green decay (.045s to 10%?) */ - {0.4, 0.2, 0.924, 0.5, 0.0135}, - {0.5, 0.7, 0.076, 0.5, 0.065} -}; -static struct color color_p40 = { p40, ELEMENTS(p40), 20000 }; - -/* "red" -- until real VR20 phosphor type/number/constants known */ -static struct phosphor pred[] = { {1.0, 0.37, 0.37, 0.5, 0.10} }; -static struct color color_red = { pred, ELEMENTS(pred), 100000 }; - -static struct display displays[] = { - /* - * TX-0 - * - * - * Unknown manufacturer - * - * 12" tube, - * maximum dot size ??? - * 50us point plot time (20,000 points/sec) - * P17 Phosphor??? Two phosphor layers: - * fast blue (.05s half life), and slow green (.2s half life) - * - * - */ - { DIS_TX0, "MIT TX-0", &color_p17, NULL, 512, 512 }, - - - /* - * Type 30 - * PDP-1/4/5/8/9/10 "Precision CRT" display system - * - * Raytheon 16ADP7A CRT? - * web searches for 16ADP7 finds useful information!! - * 16" tube, 14 3/8" square raster - * maximum dot size .015" - * 50us point plot time (20,000 points/sec) - * P17 Phosphor??? Two phosphor layers: - * fast blue (.05s half life), and slow green (.2s half life) - * 360 lb - * 7A at 115+-10V 60Hz - */ - { DIS_TYPE30, "Type 30", &color_p17, NULL, 1024, 1024 }, - - /* - * VR14 - * used w/ GT40/44, AX08, VC8E - * - * Viewable area 6.75" x 9" - * 12" diagonal - * brightness >= 30 fL - * dot size .02" (20 mils) - * settle time: - * full screen 18us to +/-1 spot diameter - * .1" change 1us to +/-.5 spot diameter - * weight 75lb - */ - { DIS_VR14, "VR14", &color_p29, NULL, 1024, 768 }, - - /* - * VR17 - * used w/ GT40/44, AX08, VC8E - * - * Viewable area 9.25" x 9.25" - * 17" diagonal - * dot size .02" (20 mils) - * brightness >= 25 fL - * phosphor: P39 doped for IR light pen use - * light pen: Type 375 - * weight 85lb - */ - { DIS_VR17, "VR17", &color_p29, NULL, 1024, 1024 }, - - /* - * VR20 - * on VC8E - * Two colors!! - */ - { DIS_VR20, "VR20", &color_p29, &color_red, 1024, 1024 }, - - /* - * VR48 - * (on VT48 in VS60) - * from Douglas A. Gwyn 23 Nov. 2003 - * - * Viewable area 12" x 12", plus 1.5" x 12" menu area on right-hand side - * 21" diagonal - * dot size <= .01" (10 mils) - * brightness >= 31 fL - * phosphor: P40 (blue-white fluorescence with yellow-green phosphorescence) - * light pen: Type 377A (with tip switch) - * driving circuitry separate - * (normally under table on which CRT is mounted) - */ - { DIS_VR48, "VR48", &color_p40, NULL, 1024+VR48_GUTTER+128, 1024 }, - - /* - * Type 340 Display system - * on PDP-4/6/7/9/10 - * - * 1024x1024 - * 9 3/8" raster (.01" dot pitch) - * 0,0 at lower left - * 8 intensity levels - */ - { DIS_TYPE340, "Type 340", &color_p17, NULL, 1024, 1024 } -}; - -/* - * Unit time (in microseconds) used to store display point time to - * live at current aging level. If this is too small, delay values - * cannot fit in an unsigned short. If it is too large all pixels - * will age at once. Perhaps a suitable value should be calculated at - * run time? When display_init() calculates refresh_interval it - * sanity checks for both cases. - */ -#define DELAY_UNIT 250 - -/* levels to display in first half-life; determines refresh rate */ -#ifndef LEVELS_PER_HALFLIFE -#define LEVELS_PER_HALFLIFE 4 -#endif - -/* after 5 half lives (.5**5) remaining intensity is 3% of original */ -#ifndef HALF_LIVES_TO_DISPLAY -#define HALF_LIVES_TO_DISPLAY 5 -#endif - -/* - * refresh_rate is number of times per (simulated) second a pixel is - * aged to next lowest intensity level. - * - * refresh_rate = ((1e6*LEVELS_PER_HALFLIFE)/PHOSPHOR_HALF_LIFE) - * refresh_interval = 1e6/DELAY_UNIT/refresh_rate - * = PHOSPHOR_HALF_LIFE/LEVELS_PER_HALF_LIFE - * intensities = (HALF_LIVES_TO_DISPLAY*PHOSPHOR_HALF_LIFE)/refresh_interval - * = HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE - * - * See also comments on display_age() - * - * Try to keep LEVELS_PER_HALFLIFE*HALF_LIVES_TO_DISPLAY*NLEVELS <= 192 - * to run on 8-bit (256 color) displays! - */ - -/* - * number of aging periods to display a point for - */ -#define NTTL (HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE) - -/* - * maximum (initial) TTL for a point. - * TTL's are stored 1-based - * (a stored TTL of zero means the point is off) - */ -#define MAXTTL NTTL - -/* - * number of drawing intensity levels - */ -#define NLEVELS (DISPLAY_INT_MAX-DISPLAY_INT_MIN+1) - -#define MAXLEVEL (NLEVELS-1) - -/* - * Display Device Implementation - */ - -/* - * Each point on the display is represented by a "struct point". When - * a point isn't dark (intensity > 0), it is linked into a circular, - * doubly linked delta queue (a priority queue where "delay" - * represents the time difference from the previous entry (if any) in - * the queue. - * - * All points are aged refresh_rate times/second, each time moved to the - * next (logarithmically) lower intensity level. When display_age() is - * called, only the entries which have expired are processed. Calling - * display_age() often allows spreading out the workload. - * - * An alternative would be to have intensity levels represent linear - * decreases in intensity, and have the decay time at each level change. - * Inverting the decay function for a multi-component phosphor may be - * tricky, and the two different colors would need different time tables. - * Furthermore, it would require finding the correct location in the - * queue when adding a point (currently only need to add points at end) - */ - -/* - * 12 bytes/entry on 32-bit system when REFRESH_RATE > 15 - * (requires 3MB for 512x512 display). - */ - -typedef unsigned short delay_t; -#define DELAY_T_MAX USHRT_MAX - -struct point { - struct point *next; /* next entry in queue */ - struct point *prev; /* prev entry in queue */ - delay_t delay; /* delta T in DELAY_UNITs */ - unsigned char ttl; /* zero means off, not linked in */ - unsigned char level : 7; /* intensity level */ - unsigned char color : 1; /* for VR20 (two colors) */ -}; - -static struct point *points; /* allocated array of points */ -static struct point _head; -#define head (&_head) - -/* - * time span of all entries in queue - * should never exceed refresh_interval - * (should be possible to make this a delay_t) - */ -static long queue_interval; - -/* convert X,Y to a "struct point *" */ -#define P(X,Y) (points + (X) + ((Y)*(size_t)xpixels)) - -/* convert "struct point *" to X and Y */ -#define X(P) (((P) - points) % xpixels) -#define Y(P) (((P) - points) / xpixels) - -static int initialized = 0; - -/* - * global set by O/S display level to indicate "light pen tip switch activated" - * (This is used only by the VS60 emulation, also by vttest to change patterns) - */ -unsigned char display_lp_sw = 0; - -/* - * global set by DR11-C simulation when DR device enabled; deactivates - * light pen and instead reports mouse coordinates as Talos digitizer - * data via DR11-C - */ -unsigned char display_tablet = 0; - -/* - * can be changed with display_lp_radius() - */ -static long scaled_pen_radius_squared; - -/* run-time -- set by display_init() */ -static int xpoints, ypoints; -static int xpixels, ypixels; -static int refresh_rate; -static int refresh_interval; -static int ncolors; -static enum display_type display_type; -static int scale; - -/* - * relative brightness for each display level - * (all but last must be less than 1.0) - */ -static float level_scale[NLEVELS]; - -/* - * table of pointer to window system "colors" - * for painting each age level, intensity level and beam color - */ -void *colors[2][NLEVELS][NTTL]; - -void -display_lp_radius(int r) -{ - r /= scale; - scaled_pen_radius_squared = r * r; -} - -/* - * from display_age and display_point - * since all points age at the same rate, - * only adds points at end of list. - */ -static void -queue_point(struct point *p) -{ - int d; - - d = refresh_interval - queue_interval; - queue_interval += d; - /* queue_interval should now be == refresh_interval */ - -#ifdef PARANOIA - if (p->ttl == 0 || p->ttl > MAXTTL) - printf("queuing %d,%d level %d!\n", X(p), Y(p), p->level); - if (d > DELAY_T_MAX) - printf("queuing %d,%d delay %d!\n", X(p), Y(p), d); - if (queue_interval > DELAY_T_MAX) - printf("queue_interval (%d) > DELAY_T_MAX (%d)\n", - (int)queue_interval, DELAY_T_MAX); -#endif /* PARANOIA defined */ - - p->next = head; - p->prev = head->prev; - - head->prev->next = p; - head->prev = p; - - p->delay = d; -} - -/* - * here to to dynamically adjust interval for examination - * of elapsed vs. simulated time, and fritter away - * any extra wall-clock time without eating CPU - */ - -/* - * more parameters! - */ - -/* - * upper bound for elapsed time between elapsed time checks. - * if more than MAXELAPSED microseconds elapsed while simulating - * delay_check simulated microseconds, decrease delay_check. - */ -#define MAXELAPSED 100000 /* 10Hz */ - -/* - * lower bound for elapsed time between elapsed time checks. - * if fewer than MINELAPSED microseconds elapsed while simulating - * delay_check simulated microseconds, increase delay_check. - */ -#define MINELAPSED 50000 /* 20Hz */ - -/* - * upper bound for delay (sleep/poll). - * If difference between elapsed time and simulated time is - * larger than MAXDELAY microseconds, decrease delay_check. - * - * since delay is elapsed time - simulated time, MAXDELAY - * should be <= MAXELAPSED - */ -#ifndef MAXDELAY -#define MAXDELAY 100000 /* 100ms */ -#endif /* MAXDELAY not defined */ - -/* - * lower bound for delay (sleep/poll). - * If difference between elapsed time and simulated time is - * smaller than MINDELAY microseconds, increase delay_check. - * - * since delay is elapsed time - simulated time, MINDELAY - * should be <= MINELAPSED - */ -#ifndef MINDELAY -#define MINDELAY 50000 /* 50ms */ -#endif /* MINDELAY not defined */ - -/* - * Initial amount of simulated time to elapse before polling. - * Value is very low to ensure polling occurs on slow systems. - * Fast systems should ramp up quickly. - */ -#ifndef INITIAL_DELAY_CHECK -#define INITIAL_DELAY_CHECK 1000 /* 1ms */ -#endif /* INITIAL_DELAY_CHECK */ - -/* - * gain factor (2**-GAINSHIFT) for adjustment of adjustment - * of delay_check - */ -#ifndef GAINSHIFT -#define GAINSHIFT 3 /* gain=0.125 (12.5%) */ -#endif /* GAINSHIFT not defined */ - -static void -display_delay(int t, int slowdown) -{ - /* how often (in simulated us) to poll/check for delay */ - static unsigned long delay_check = INITIAL_DELAY_CHECK; - - /* accumulated simulated time */ - static unsigned long sim_time = 0; - unsigned long elapsed; - long delay; - - sim_time += t; - if (sim_time < delay_check) - return; - - elapsed = os_elapsed(); /* read and reset elapsed timer */ - if (elapsed == ~0L) { /* first time thru? */ - slowdown = 0; /* no adjustments */ - elapsed = sim_time; - } - - /* - * get delta between elapsed (real) time, and simulated time. - * if simulated time running faster, we need to slow things down (delay) - */ - if (slowdown) - delay = sim_time - elapsed; - else - delay = 0; /* just poll */ - -#ifdef DEBUG_DELAY2 - printf("sim %d elapsed %d delay %d\r\n", sim_time, elapsed, delay); -#endif - - /* - * Try to keep the elapsed (real world) time between checks for - * delay (and poll for window system events) bounded between - * MAXELAPSED and MINELAPSED. Also tries to keep - * delay/poll time bounded between MAXDELAY and MINDELAY -- large - * delays make the simulation spastic, while very small ones are - * inefficient (too many system calls) and tend to be inaccurate - * (operating systems have a certain granularity for time - * measurement, and when you try to sleep/poll for very short - * amounts of time, the noise will dominate). - * - * delay_check period may be adjusted often, and oscillate. There - * is no single "right value", the important things are to keep - * the delay time and max poll intervals bounded, and responsive - * to system load. - */ - if (elapsed > MAXELAPSED || delay > MAXDELAY) { - /* too much elapsed time passed, or delay too large; shrink interval */ - if (delay_check > 1) { - delay_check -= delay_check>>GAINSHIFT; -#ifdef DEBUG_DELAY - printf("reduced period to %d\r\n", delay_check); -#endif /* DEBUG_DELAY defined */ - } - } - else if ((elapsed < MINELAPSED) || (slowdown && (delay < MINDELAY))) { - /* too little elapsed time passed, or delta very small */ - int gain = delay_check>>GAINSHIFT; - if (gain == 0) - gain = 1; /* make sure some change made! */ - delay_check += gain; -#ifdef DEBUG_DELAY - printf("increased period to %d\r\n", delay_check); -#endif /* DEBUG_DELAY defined */ - } - if (delay < 0) - delay = 0; - /* else if delay < MINDELAY, clamp at MINDELAY??? */ - - /* poll for window system events and/or delay */ - ws_poll(NULL, delay); - - sim_time = 0; /* reset simulated time clock */ - - /* - * delay (poll/sleep) time included in next "elapsed" period - * (clock not reset after a delay) - */ -} /* display_delay */ - -/* - * here periodically from simulator to age pixels. - * - * calling often with small values will age a few pixels at a time, - * and assist with graceful aging of display, and pixel aging. - * - * values should be smaller than refresh_interval! - * - * returns true if anything on screen changed. - */ - -int -display_age(int t, /* simulated us since last call */ - int slowdown) /* slowdown to simulated speed */ -{ - struct point *p; - static int elapsed = 0; - int changed; - - if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) - return 0; - - display_delay(t, slowdown); - - changed = 0; - - elapsed += t; - if (elapsed < DELAY_UNIT) - return 0; - - t = elapsed / DELAY_UNIT; - elapsed %= DELAY_UNIT; - - while ((p = head->next) != head) { - int x, y; - - /* look at oldest entry */ - if (p->delay > t) { /* further than our reach? */ - p->delay -= t; /* update head */ - queue_interval -= t; /* update span */ - break; /* quit */ - } - - x = X(p); - y = Y(p); -#ifdef PARANOIA - if (p->ttl == 0) - printf("BUG: age %d,%d ttl zero\n", x, y); -#endif /* PARANOIA defined */ - - /* dequeue point */ - p->prev->next = p->next; - p->next->prev = p->prev; - - t -= p->delay; /* lessen our reach */ - queue_interval -= p->delay; /* update queue span */ - - ws_display_point(x, y, colors[p->color][p->level][--p->ttl]); - changed = 1; - - /* queue it back up, unless we just turned it off! */ - if (p->ttl > 0) - queue_point(p); - } - return changed; -} /* display_age */ - -/* here from window system */ -void -display_repaint(void) { - struct point *p; - int x, y; - /* - * bottom to top, left to right. - */ - for (p = points, y = 0; y < ypixels; y++) - for (x = 0; x < xpixels; p++, x++) - if (p->ttl) - ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); - ws_sync(); -} - -/* (0,0) is lower left */ -static int -intensify(int x, /* 0..xpixels */ - int y, /* 0..ypixels */ - int level, /* 0..MAXLEVEL */ - int color) /* for VR20! 0 or 1 */ -{ - struct point *p; - int bleed; - - if (x < 0 || x >= xpixels || y < 0 || y >= ypixels) - return 0; /* limit to display */ - - p = P(x,y); - if (p->ttl) { /* currently lit? */ -#ifdef LOUD - printf("%d,%d old level %d ttl %d new %d\r\n", - x, y, p->level, p->ttl, level); -#endif /* LOUD defined */ - - /* unlink from delta queue */ - p->prev->next = p->next; - - if (p->next == head) - queue_interval -= p->delay; - else - p->next->delay += p->delay; - p->next->prev = p->prev; - } - - bleed = 0; /* no bleeding for now */ - - /* EXP: doesn't work... yet */ - /* if "recently" drawn, same or brighter, same color, make even brighter */ - if (p->ttl >= MAXTTL*2/3 && level >= p->level && p->color == color && - level < MAXLEVEL) - level++; - - /* - * this allows a dim beam to suck light out of - * a recently drawn bright spot!! - */ - if (p->ttl != MAXTTL || p->level != level || p->color != color) { - p->ttl = MAXTTL; - p->level = level; - p->color = color; /* save color even if monochrome */ - ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); - } - - queue_point(p); /* put at end of list */ - return bleed; -} - -int -display_point(int x, /* 0..xpixels (unscaled) */ - int y, /* 0..ypixels (unscaled) */ - int level, /* DISPLAY_INT_xxx */ - int color) /* for VR20! 0 or 1 */ -{ - long lx, ly; - - if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) - return 0; - - /* scale x and y to the displayed number of pixels */ - /* handle common cases quickly */ - if (scale > 1) { - if (scale == 2) { - x >>= 1; - y >>= 1; - } - else { - x /= scale; - y /= scale; - } - } - -#if DISPLAY_INT_MIN > 0 - level -= DISPLAY_INT_MIN; /* make zero based */ -#endif - intensify(x, y, level, color); - /* no bleeding for now (used to recurse for neighbor points) */ - - if (ws_lp_x == -1 || ws_lp_y == -1) - return 0; - - lx = x - ws_lp_x; - ly = y - ws_lp_y; - return lx*lx + ly*ly <= scaled_pen_radius_squared; -} /* display_point */ - -/* - * calculate decay color table for a phosphor mixture - * must be called AFTER refresh_rate initialized! - */ -static void -phosphor_init(struct phosphor *phosphors, int nphosphors, int color) -{ - int ttl; - - /* for each display ttl level; newest to oldest */ - for (ttl = NTTL-1; ttl > 0; ttl--) { - struct phosphor *pp; - double rr, rg, rb; /* real values */ - - /* fractional seconds */ - double t = ((double)(NTTL-1-ttl))/refresh_rate; - - int ilevel; /* intensity levels */ - int p; - - /* sum over all phosphors in mixture */ - rr = rg = rb = 0.0; - for (pp = phosphors, p = 0; p < nphosphors; pp++, p++) { - double decay = pow(pp->level, t/pp->t_level); - rr += decay * pp->red; - rg += decay * pp->green; - rb += decay * pp->blue; - } - - /* scale for brightness for each intensity level */ - for (ilevel = MAXLEVEL; ilevel >= 0; ilevel--) { - int r, g, b; - void *cp; - - /* - * convert to 16-bit integer; clamp at 16 bits. - * this allows the sum of brightness factors across phosphors - * for each of R G and B to be greater than 1.0 - */ - - r = (int)(rr * level_scale[ilevel] * 0xffff); - if (r > 0xffff) r = 0xffff; - - g = (int)(rg * level_scale[ilevel] * 0xffff); - if (g > 0xffff) g = 0xffff; - - b = (int)(rb * level_scale[ilevel] * 0xffff); - if (b > 0xffff) b = 0xffff; - - cp = ws_color_rgb(r, g, b); - if (!cp) { /* allocation failed? */ - if (ttl == MAXTTL-1) { /* brand new */ - if (ilevel == MAXLEVEL) /* highest intensity? */ - cp = ws_color_white(); /* use white */ - else - cp = colors[color][ilevel+1][ttl]; /* use next lvl */ - } /* brand new */ - else if (r + g + b >= 0xffff*3/3) /* light-ish? */ - cp = colors[color][ilevel][ttl+1]; /* use previous TTL */ - else - cp = ws_color_black(); - } - colors[color][ilevel][ttl] = cp; - } /* for each intensity level */ - } /* for each TTL */ -} /* phosphor_init */ - -static struct display * -find_type(enum display_type type) -{ - int i; - struct display *dp; - for (i = 0, dp = displays; i < ELEMENTS(displays); i++, dp++) - if (dp->type == type) - return dp; - return NULL; -} - -int -display_init(enum display_type type, int sf) -{ - static int init_failed = 0; - struct display *dp; - int half_life; - int i; - - if (initialized) { - /* cannot change type once started */ - /* XXX say something???? */ - return type == display_type; - } - - if (init_failed) - return 0; /* avoid thrashing */ - - init_failed = 1; /* assume the worst */ - dp = find_type(type); - if (!dp) { - fprintf(stderr, "Unknown display type %d\r\n", (int)type); - goto failed; - } - - /* Initialize display list */ - head->next = head->prev = head; - - display_type = type; - scale = sf; - - xpoints = dp->xpoints; - ypoints = dp->ypoints; - - /* increase scale factor if won't fit on desktop? */ - xpixels = xpoints / scale; - ypixels = ypoints / scale; - - /* set default pen radius now that scale is set */ - display_lp_radius(PEN_RADIUS); - - ncolors = 1; - /* - * use function to calculate from looking at avg (max?) - * of phosphor half lives??? - */ -#define COLOR_HALF_LIFE(C) ((C)->half_life) - - half_life = COLOR_HALF_LIFE(dp->color0); - if (dp->color1) { - if (dp->color1->half_life > half_life) - half_life = COLOR_HALF_LIFE(dp->color1); - ncolors++; - } - - /* before phosphor_init; */ - refresh_rate = (1000000*LEVELS_PER_HALFLIFE)/half_life; - refresh_interval = 1000000/DELAY_UNIT/refresh_rate; - - /* - * sanity check refresh_interval - * calculating/selecting DELAY_UNIT at runtime might avoid this! - */ - - /* must be non-zero; interval of 1 means all pixels will age at once! */ - if (refresh_interval < 1) { - /* decrease DELAY_UNIT? */ - fprintf(stderr, "NOTE! refresh_interval too small: %d\r\n", - refresh_interval); - - /* dunno if this is a good idea, but might be better than dying */ - refresh_interval = 1; - } - - /* point lifetime in DELAY_UNITs will not fit in p->delay field! */ - if (refresh_interval > DELAY_T_MAX) { - /* increase DELAY_UNIT? */ - fprintf(stderr, "bad refresh_interval %d > DELAY_T_MAX %d\r\n", - refresh_interval, DELAY_T_MAX); - goto failed; - } - - /* - * before phosphor_init; - * set up relative brightness of display intensity levels - * (could differ for different hardware) - * - * linear for now. boost factor insures low intensities are visible - */ -#define BOOST 5 - for (i = 0; i < NLEVELS; i++) - level_scale[i] = ((float)i+1+BOOST)/(NLEVELS+BOOST); - - points = (struct point *)calloc((size_t)xpixels, - ypixels * sizeof(struct point)); - if (!points) - goto failed; - - if (!ws_init(dp->name, xpixels, ypixels, ncolors)) - goto failed; - - phosphor_init(dp->color0->phosphors, dp->color0->nphosphors, 0); - - if (dp->color1) - phosphor_init(dp->color1->phosphors, dp->color1->nphosphors, 1); - - initialized = 1; - init_failed = 0; /* hey, we made it! */ - return 1; - - failed: - fprintf(stderr, "Display initialization failed\r\n"); - return 0; -} - -void -display_reset(void) -{ - /* XXX tear down window? just clear it? */ -} - -void -display_sync(void) -{ - ws_sync(); -} - -void -display_beep(void) -{ - ws_beep(); -} - -int -display_xpoints(void) -{ - return xpoints; -} - -int -display_ypoints(void) -{ - return ypoints; -} - -int -display_scale(void) -{ - return scale; -} - -/* - * handle keyboard events - * - * data switches; 18 -- enough for PDP-1/4/7/9/15 (for munching squares!) - * 123 456 789 qwe rty uio - * bit toggled on key up - * all cleared on space - * - * spacewar switches; bit high as long as key down - * asdf kl;' - * just where PDP-1 spacewar expects them! - * key mappings same as MIT Media Lab Java PDP-1 simulator - * - */ -unsigned long spacewar_switches = 0; - -/* here from window system */ -void -display_keydown(int k) -{ - switch (k) { - case 'f': case 'F': spacewar_switches |= 01; break; /* torpedos */ - case 'd': case 'D': spacewar_switches |= 02; break; /* engines */ - case 'a': case 'A': spacewar_switches |= 04; break; /* rotate R */ - case 's': case 'S': spacewar_switches |= 010; break; /* rotate L */ - case '\'': case '"': spacewar_switches |= 040000; break; /* torpedos */ - case ';': case ':': spacewar_switches |= 0100000; break; /* engines */ - case 'k': case 'K': spacewar_switches |= 0200000; break; /* rotate R */ - case 'l': case 'L': spacewar_switches |= 0400000; break; /* rotate L */ - default: return; - } -} - -/* here from window system */ -void -display_keyup(int k) -{ - unsigned long test_switches = cpu_get_switches(); - - /* fetch console switches from simulator? */ - switch (k) { - case 'f': case 'F': spacewar_switches &= ~01; return; - case 'd': case 'D': spacewar_switches &= ~02; return; - case 'a': case 'A': spacewar_switches &= ~04; return; - case 's': case 'S': spacewar_switches &= ~010; return; - - case '\'': case '"': spacewar_switches &= ~040000; return; - case ';': case ':': spacewar_switches &= ~0100000; return; - case 'k': case 'K': spacewar_switches &= ~0200000; return; - case 'l': case 'L': spacewar_switches &= ~0400000; return; - - case '1': test_switches ^= 1<<17; break; - case '2': test_switches ^= 1<<16; break; - case '3': test_switches ^= 1<<15; break; - - case '4': test_switches ^= 1<<14; break; - case '5': test_switches ^= 1<<13; break; - case '6': test_switches ^= 1<<12; break; - - case '7': test_switches ^= 1<<11; break; - case '8': test_switches ^= 1<<10; break; - case '9': test_switches ^= 1<<9; break; - - case 'q': case 'Q': test_switches ^= 1<<8; break; - case 'w': case 'W': test_switches ^= 1<<7; break; - case 'e': case 'E': test_switches ^= 1<<6; break; - - case 'r': case 'R': test_switches ^= 1<<5; break; - case 't': case 'T': test_switches ^= 1<<4; break; - case 'y': case 'Y': test_switches ^= 1<<3; break; - - case 'u': case 'U': test_switches ^= 1<<2; break; - case 'i': case 'I': test_switches ^= 1<<1; break; - case 'o': case 'O': test_switches ^= 1; break; - - case ' ': test_switches = 0; break; - default: return; - } - cpu_set_switches(test_switches); -} +/* + * $Id: display.c,v 1.57 2004/02/04 16:59:01 phil Exp $ + * Simulator and host O/S independent XY display simulator + * Phil Budne + * September 2003 + * + * with changes by Douglas A. Gwyn, 21 Jan. 2004 + * + * started from PDP-8/E simulator vc8e.c; + * This PDP8 Emulator was written by Douglas W. Jones at the + * University of Iowa. It is distributed as freeware, of + * uncertain function and uncertain utility. + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#include +#include +#include +#include /* for USHRT_MAX */ +#include "ws.h" +#include "display.h" + +/* + * The user may select (at compile time) how big a window is used to + * emulate the display. Using smaller windows saves memory and screen space. + * + * Type 30 has 1024x1024 addressing, but only 512x512 visible points. + * VR14 has only 1024x768 visible points; VR17 has 1024x1024 visible points. + * VT11 supports 4096x4096 addressing, clipping to the lowest 1024x1024 region. + * VR48 has 1024x1024 visible points in the main display area and 128x1024 + * visible points in a menu area on the right-hand side (1152x1024 total). + * VT48 supports 8192x8192 (signed) main-area addressing, clipping to a + * 1024x1024 window which can be located anywhere within that region. + * (XXX -- That is what the VT11/VT48 manuals say; however, evidence suggests + * that the VT11 may actually support 8192x8192 (signed) addressing too.) + */ + +/* Define the default display type (if display_init() not called) */ +#ifndef DISPLAY_TYPE +#define DISPLAY_TYPE DIS_TYPE30 +#endif /* DISPLAY_TYPE not defined */ + +/* select a default resolution if display_init() not called */ +/* XXX keep in struct display? */ +#ifndef PIX_SCALE +#define PIX_SCALE RES_HALF +#endif /* PIX_SCALE not defined */ + +/* select a default light-pen hit radius if display_init() not called */ +#ifndef PEN_RADIUS +#define PEN_RADIUS 4 +#endif /* PEN_RADIUS not defined */ + +/* + * note: displays can have up to two different colors (eg VR20) + * each color can be made up of any number of phosphors + * with different colors and decay characteristics (eg Type 30) + */ + +#define ELEMENTS(X) (sizeof(X)/sizeof(X[0])) + +struct phosphor { + double red, green, blue; + double level; /* decay level (0.5 for half life) */ + double t_level; /* seconds to decay to level */ +}; + +struct color { + struct phosphor *phosphors; + int nphosphors; + int half_life; /* for refresh calc */ +}; + +struct display { + enum display_type type; + char *name; + struct color *color0, *color1; + short xpoints, ypoints; +}; + +/* + * original phosphor constants from Raphael Nabet's XMame 0.72.1 PDP-1 sim. + * not even sure Type30 really used P17 (guess by Daniel P. B. Smith) + */ +static struct phosphor p17[] = { + {0.11, 0.11, 1.0, 0.5, 0.05}, /* fast blue */ + {1.0, 1.0, 0.11, 0.5, 0.20} /* slow yellow/green */ +}; +static struct color color_p17 = { p17, ELEMENTS(p17), 125000 }; + +/* green phosphor for VR14, VR17, VR20 */ +static struct phosphor p29[] = {{0.0260, 1.0, 0.00121, 0.5, 0.025}}; +struct color color_p29 = { p29, ELEMENTS(p29), 25000 }; + +static struct phosphor p40[] = { + /* P40 blue-white spot with yellow-green decay (.045s to 10%?) */ + {0.4, 0.2, 0.924, 0.5, 0.0135}, + {0.5, 0.7, 0.076, 0.5, 0.065} +}; +static struct color color_p40 = { p40, ELEMENTS(p40), 20000 }; + +/* "red" -- until real VR20 phosphor type/number/constants known */ +static struct phosphor pred[] = { {1.0, 0.37, 0.37, 0.5, 0.10} }; +static struct color color_red = { pred, ELEMENTS(pred), 100000 }; + +static struct display displays[] = { + /* + * TX-0 + * + * + * Unknown manufacturer + * + * 12" tube, + * maximum dot size ??? + * 50us point plot time (20,000 points/sec) + * P17 Phosphor??? Two phosphor layers: + * fast blue (.05s half life), and slow green (.2s half life) + * + * + */ + { DIS_TX0, "MIT TX-0", &color_p17, NULL, 512, 512 }, + + + /* + * Type 30 + * PDP-1/4/5/8/9/10 "Precision CRT" display system + * + * Raytheon 16ADP7A CRT? + * web searches for 16ADP7 finds useful information!! + * 16" tube, 14 3/8" square raster + * maximum dot size .015" + * 50us point plot time (20,000 points/sec) + * P17 Phosphor??? Two phosphor layers: + * fast blue (.05s half life), and slow green (.2s half life) + * 360 lb + * 7A at 115+-10V 60Hz + */ + { DIS_TYPE30, "Type 30", &color_p17, NULL, 1024, 1024 }, + + /* + * VR14 + * used w/ GT40/44, AX08, VC8E + * + * Viewable area 6.75" x 9" + * 12" diagonal + * brightness >= 30 fL + * dot size .02" (20 mils) + * settle time: + * full screen 18us to +/-1 spot diameter + * .1" change 1us to +/-.5 spot diameter + * weight 75lb + */ + { DIS_VR14, "VR14", &color_p29, NULL, 1024, 768 }, + + /* + * VR17 + * used w/ GT40/44, AX08, VC8E + * + * Viewable area 9.25" x 9.25" + * 17" diagonal + * dot size .02" (20 mils) + * brightness >= 25 fL + * phosphor: P39 doped for IR light pen use + * light pen: Type 375 + * weight 85lb + */ + { DIS_VR17, "VR17", &color_p29, NULL, 1024, 1024 }, + + /* + * VR20 + * on VC8E + * Two colors!! + */ + { DIS_VR20, "VR20", &color_p29, &color_red, 1024, 1024 }, + + /* + * VR48 + * (on VT48 in VS60) + * from Douglas A. Gwyn 23 Nov. 2003 + * + * Viewable area 12" x 12", plus 1.5" x 12" menu area on right-hand side + * 21" diagonal + * dot size <= .01" (10 mils) + * brightness >= 31 fL + * phosphor: P40 (blue-white fluorescence with yellow-green phosphorescence) + * light pen: Type 377A (with tip switch) + * driving circuitry separate + * (normally under table on which CRT is mounted) + */ + { DIS_VR48, "VR48", &color_p40, NULL, 1024+VR48_GUTTER+128, 1024 }, + + /* + * Type 340 Display system + * on PDP-4/6/7/9/10 + * + * 1024x1024 + * 9 3/8" raster (.01" dot pitch) + * 0,0 at lower left + * 8 intensity levels + */ + { DIS_TYPE340, "Type 340", &color_p17, NULL, 1024, 1024 } +}; + +/* + * Unit time (in microseconds) used to store display point time to + * live at current aging level. If this is too small, delay values + * cannot fit in an unsigned short. If it is too large all pixels + * will age at once. Perhaps a suitable value should be calculated at + * run time? When display_init() calculates refresh_interval it + * sanity checks for both cases. + */ +#define DELAY_UNIT 250 + +/* levels to display in first half-life; determines refresh rate */ +#ifndef LEVELS_PER_HALFLIFE +#define LEVELS_PER_HALFLIFE 4 +#endif + +/* after 5 half lives (.5**5) remaining intensity is 3% of original */ +#ifndef HALF_LIVES_TO_DISPLAY +#define HALF_LIVES_TO_DISPLAY 5 +#endif + +/* + * refresh_rate is number of times per (simulated) second a pixel is + * aged to next lowest intensity level. + * + * refresh_rate = ((1e6*LEVELS_PER_HALFLIFE)/PHOSPHOR_HALF_LIFE) + * refresh_interval = 1e6/DELAY_UNIT/refresh_rate + * = PHOSPHOR_HALF_LIFE/LEVELS_PER_HALF_LIFE + * intensities = (HALF_LIVES_TO_DISPLAY*PHOSPHOR_HALF_LIFE)/refresh_interval + * = HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE + * + * See also comments on display_age() + * + * Try to keep LEVELS_PER_HALFLIFE*HALF_LIVES_TO_DISPLAY*NLEVELS <= 192 + * to run on 8-bit (256 color) displays! + */ + +/* + * number of aging periods to display a point for + */ +#define NTTL (HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE) + +/* + * maximum (initial) TTL for a point. + * TTL's are stored 1-based + * (a stored TTL of zero means the point is off) + */ +#define MAXTTL NTTL + +/* + * number of drawing intensity levels + */ +#define NLEVELS (DISPLAY_INT_MAX-DISPLAY_INT_MIN+1) + +#define MAXLEVEL (NLEVELS-1) + +/* + * Display Device Implementation + */ + +/* + * Each point on the display is represented by a "struct point". When + * a point isn't dark (intensity > 0), it is linked into a circular, + * doubly linked delta queue (a priority queue where "delay" + * represents the time difference from the previous entry (if any) in + * the queue. + * + * All points are aged refresh_rate times/second, each time moved to the + * next (logarithmically) lower intensity level. When display_age() is + * called, only the entries which have expired are processed. Calling + * display_age() often allows spreading out the workload. + * + * An alternative would be to have intensity levels represent linear + * decreases in intensity, and have the decay time at each level change. + * Inverting the decay function for a multi-component phosphor may be + * tricky, and the two different colors would need different time tables. + * Furthermore, it would require finding the correct location in the + * queue when adding a point (currently only need to add points at end) + */ + +/* + * 12 bytes/entry on 32-bit system when REFRESH_RATE > 15 + * (requires 3MB for 512x512 display). + */ + +typedef unsigned short delay_t; +#define DELAY_T_MAX USHRT_MAX + +struct point { + struct point *next; /* next entry in queue */ + struct point *prev; /* prev entry in queue */ + delay_t delay; /* delta T in DELAY_UNITs */ + unsigned char ttl; /* zero means off, not linked in */ + unsigned char level : 7; /* intensity level */ + unsigned char color : 1; /* for VR20 (two colors) */ +}; + +static struct point *points; /* allocated array of points */ +static struct point _head; +#define head (&_head) + +/* + * time span of all entries in queue + * should never exceed refresh_interval + * (should be possible to make this a delay_t) + */ +static long queue_interval; + +/* convert X,Y to a "struct point *" */ +#define P(X,Y) (points + (X) + ((Y)*(size_t)xpixels)) + +/* convert "struct point *" to X and Y */ +#define X(P) (((P) - points) % xpixels) +#define Y(P) (((P) - points) / xpixels) + +static int initialized = 0; + +/* + * global set by O/S display level to indicate "light pen tip switch activated" + * (This is used only by the VS60 emulation, also by vttest to change patterns) + */ +unsigned char display_lp_sw = 0; + +/* + * global set by DR11-C simulation when DR device enabled; deactivates + * light pen and instead reports mouse coordinates as Talos digitizer + * data via DR11-C + */ +unsigned char display_tablet = 0; + +/* + * can be changed with display_lp_radius() + */ +static long scaled_pen_radius_squared; + +/* run-time -- set by display_init() */ +static int xpoints, ypoints; +static int xpixels, ypixels; +static int refresh_rate; +static int refresh_interval; +static int ncolors; +static enum display_type display_type; +static int scale; + +/* + * relative brightness for each display level + * (all but last must be less than 1.0) + */ +static float level_scale[NLEVELS]; + +/* + * table of pointer to window system "colors" + * for painting each age level, intensity level and beam color + */ +void *colors[2][NLEVELS][NTTL]; + +void +display_lp_radius(int r) +{ + r /= scale; + scaled_pen_radius_squared = r * r; +} + +/* + * from display_age and display_point + * since all points age at the same rate, + * only adds points at end of list. + */ +static void +queue_point(struct point *p) +{ + int d; + + d = refresh_interval - queue_interval; + queue_interval += d; + /* queue_interval should now be == refresh_interval */ + +#ifdef PARANOIA + if (p->ttl == 0 || p->ttl > MAXTTL) + printf("queuing %d,%d level %d!\n", X(p), Y(p), p->level); + if (d > DELAY_T_MAX) + printf("queuing %d,%d delay %d!\n", X(p), Y(p), d); + if (queue_interval > DELAY_T_MAX) + printf("queue_interval (%d) > DELAY_T_MAX (%d)\n", + (int)queue_interval, DELAY_T_MAX); +#endif /* PARANOIA defined */ + + p->next = head; + p->prev = head->prev; + + head->prev->next = p; + head->prev = p; + + p->delay = d; +} + +/* + * here to to dynamically adjust interval for examination + * of elapsed vs. simulated time, and fritter away + * any extra wall-clock time without eating CPU + */ + +/* + * more parameters! + */ + +/* + * upper bound for elapsed time between elapsed time checks. + * if more than MAXELAPSED microseconds elapsed while simulating + * delay_check simulated microseconds, decrease delay_check. + */ +#define MAXELAPSED 100000 /* 10Hz */ + +/* + * lower bound for elapsed time between elapsed time checks. + * if fewer than MINELAPSED microseconds elapsed while simulating + * delay_check simulated microseconds, increase delay_check. + */ +#define MINELAPSED 50000 /* 20Hz */ + +/* + * upper bound for delay (sleep/poll). + * If difference between elapsed time and simulated time is + * larger than MAXDELAY microseconds, decrease delay_check. + * + * since delay is elapsed time - simulated time, MAXDELAY + * should be <= MAXELAPSED + */ +#ifndef MAXDELAY +#define MAXDELAY 100000 /* 100ms */ +#endif /* MAXDELAY not defined */ + +/* + * lower bound for delay (sleep/poll). + * If difference between elapsed time and simulated time is + * smaller than MINDELAY microseconds, increase delay_check. + * + * since delay is elapsed time - simulated time, MINDELAY + * should be <= MINELAPSED + */ +#ifndef MINDELAY +#define MINDELAY 50000 /* 50ms */ +#endif /* MINDELAY not defined */ + +/* + * Initial amount of simulated time to elapse before polling. + * Value is very low to ensure polling occurs on slow systems. + * Fast systems should ramp up quickly. + */ +#ifndef INITIAL_DELAY_CHECK +#define INITIAL_DELAY_CHECK 1000 /* 1ms */ +#endif /* INITIAL_DELAY_CHECK */ + +/* + * gain factor (2**-GAINSHIFT) for adjustment of adjustment + * of delay_check + */ +#ifndef GAINSHIFT +#define GAINSHIFT 3 /* gain=0.125 (12.5%) */ +#endif /* GAINSHIFT not defined */ + +static void +display_delay(int t, int slowdown) +{ + /* how often (in simulated us) to poll/check for delay */ + static unsigned long delay_check = INITIAL_DELAY_CHECK; + + /* accumulated simulated time */ + static unsigned long sim_time = 0; + unsigned long elapsed; + long delay; + + sim_time += t; + if (sim_time < delay_check) + return; + + elapsed = os_elapsed(); /* read and reset elapsed timer */ + if (elapsed == ~0L) { /* first time thru? */ + slowdown = 0; /* no adjustments */ + elapsed = sim_time; + } + + /* + * get delta between elapsed (real) time, and simulated time. + * if simulated time running faster, we need to slow things down (delay) + */ + if (slowdown) + delay = sim_time - elapsed; + else + delay = 0; /* just poll */ + +#ifdef DEBUG_DELAY2 + printf("sim %d elapsed %d delay %d\r\n", sim_time, elapsed, delay); +#endif + + /* + * Try to keep the elapsed (real world) time between checks for + * delay (and poll for window system events) bounded between + * MAXELAPSED and MINELAPSED. Also tries to keep + * delay/poll time bounded between MAXDELAY and MINDELAY -- large + * delays make the simulation spastic, while very small ones are + * inefficient (too many system calls) and tend to be inaccurate + * (operating systems have a certain granularity for time + * measurement, and when you try to sleep/poll for very short + * amounts of time, the noise will dominate). + * + * delay_check period may be adjusted often, and oscillate. There + * is no single "right value", the important things are to keep + * the delay time and max poll intervals bounded, and responsive + * to system load. + */ + if (elapsed > MAXELAPSED || delay > MAXDELAY) { + /* too much elapsed time passed, or delay too large; shrink interval */ + if (delay_check > 1) { + delay_check -= delay_check>>GAINSHIFT; +#ifdef DEBUG_DELAY + printf("reduced period to %d\r\n", delay_check); +#endif /* DEBUG_DELAY defined */ + } + } + else + if ((elapsed < MINELAPSED) || (slowdown && (delay < MINDELAY))) { + /* too little elapsed time passed, or delta very small */ + int gain = delay_check>>GAINSHIFT; + + if (gain == 0) + gain = 1; /* make sure some change made! */ + delay_check += gain; +#ifdef DEBUG_DELAY + printf("increased period to %d\r\n", delay_check); +#endif /* DEBUG_DELAY defined */ + } + if (delay < 0) + delay = 0; + /* else if delay < MINDELAY, clamp at MINDELAY??? */ + + /* poll for window system events and/or delay */ + ws_poll(NULL, delay); + + sim_time = 0; /* reset simulated time clock */ + + /* + * delay (poll/sleep) time included in next "elapsed" period + * (clock not reset after a delay) + */ +} /* display_delay */ + +/* + * here periodically from simulator to age pixels. + * + * calling often with small values will age a few pixels at a time, + * and assist with graceful aging of display, and pixel aging. + * + * values should be smaller than refresh_interval! + * + * returns true if anything on screen changed. + */ + +int +display_age(int t, /* simulated us since last call */ + int slowdown) /* slowdown to simulated speed */ +{ + struct point *p; + static int elapsed = 0; + int changed; + + if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) + return 0; + + display_delay(t, slowdown); + + changed = 0; + + elapsed += t; + if (elapsed < DELAY_UNIT) + return 0; + + t = elapsed / DELAY_UNIT; + elapsed %= DELAY_UNIT; + + while ((p = head->next) != head) { + int x, y; + + /* look at oldest entry */ + if (p->delay > t) { /* further than our reach? */ + p->delay -= t; /* update head */ + queue_interval -= t; /* update span */ + break; /* quit */ + } + + x = X(p); + y = Y(p); +#ifdef PARANOIA + if (p->ttl == 0) + printf("BUG: age %d,%d ttl zero\n", x, y); +#endif /* PARANOIA defined */ + + /* dequeue point */ + p->prev->next = p->next; + p->next->prev = p->prev; + + t -= p->delay; /* lessen our reach */ + queue_interval -= p->delay; /* update queue span */ + + ws_display_point(x, y, colors[p->color][p->level][--p->ttl]); + changed = 1; + + /* queue it back up, unless we just turned it off! */ + if (p->ttl > 0) + queue_point(p); + } + return changed; +} /* display_age */ + +/* here from window system */ +void +display_repaint(void) { + struct point *p; + int x, y; + /* + * bottom to top, left to right. + */ + for (p = points, y = 0; y < ypixels; y++) + for (x = 0; x < xpixels; p++, x++) + if (p->ttl) + ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); + ws_sync(); +} + +/* (0,0) is lower left */ +static int +intensify(int x, /* 0..xpixels */ + int y, /* 0..ypixels */ + int level, /* 0..MAXLEVEL */ + int color) /* for VR20! 0 or 1 */ +{ + struct point *p; + int bleed; + + if (x < 0 || x >= xpixels || y < 0 || y >= ypixels) + return 0; /* limit to display */ + + p = P(x,y); + if (p->ttl) { /* currently lit? */ +#ifdef LOUD + printf("%d,%d old level %d ttl %d new %d\r\n", + x, y, p->level, p->ttl, level); +#endif /* LOUD defined */ + + /* unlink from delta queue */ + p->prev->next = p->next; + + if (p->next == head) + queue_interval -= p->delay; + else + p->next->delay += p->delay; + p->next->prev = p->prev; + } + + bleed = 0; /* no bleeding for now */ + + /* EXP: doesn't work... yet */ + /* if "recently" drawn, same or brighter, same color, make even brighter */ + if (p->ttl >= MAXTTL*2/3 && + level >= p->level && + p->color == color && + level < MAXLEVEL) + level++; + + /* + * this allows a dim beam to suck light out of + * a recently drawn bright spot!! + */ + if (p->ttl != MAXTTL || p->level != level || p->color != color) { + p->ttl = MAXTTL; + p->level = level; + p->color = color; /* save color even if monochrome */ + ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); + } + + queue_point(p); /* put at end of list */ + return bleed; +} + +int +display_point(int x, /* 0..xpixels (unscaled) */ + int y, /* 0..ypixels (unscaled) */ + int level, /* DISPLAY_INT_xxx */ + int color) /* for VR20! 0 or 1 */ +{ + long lx, ly; + + if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) + return 0; + + /* scale x and y to the displayed number of pixels */ + /* handle common cases quickly */ + if (scale > 1) { + if (scale == 2) { + x >>= 1; + y >>= 1; + } + else { + x /= scale; + y /= scale; + } + } + +#if DISPLAY_INT_MIN > 0 + level -= DISPLAY_INT_MIN; /* make zero based */ +#endif + intensify(x, y, level, color); + /* no bleeding for now (used to recurse for neighbor points) */ + + if (ws_lp_x == -1 || ws_lp_y == -1) + return 0; + + lx = x - ws_lp_x; + ly = y - ws_lp_y; + return lx*lx + ly*ly <= scaled_pen_radius_squared; +} /* display_point */ + +/* + * calculate decay color table for a phosphor mixture + * must be called AFTER refresh_rate initialized! + */ +static void +phosphor_init(struct phosphor *phosphors, int nphosphors, int color) +{ + int ttl; + + /* for each display ttl level; newest to oldest */ + for (ttl = NTTL-1; ttl > 0; ttl--) { + struct phosphor *pp; + double rr, rg, rb; /* real values */ + + /* fractional seconds */ + double t = ((double)(NTTL-1-ttl))/refresh_rate; + + int ilevel; /* intensity levels */ + int p; + + /* sum over all phosphors in mixture */ + rr = rg = rb = 0.0; + for (pp = phosphors, p = 0; p < nphosphors; pp++, p++) { + double decay = pow(pp->level, t/pp->t_level); + + rr += decay * pp->red; + rg += decay * pp->green; + rb += decay * pp->blue; + } + + /* scale for brightness for each intensity level */ + for (ilevel = MAXLEVEL; ilevel >= 0; ilevel--) { + int r, g, b; + void *cp; + + /* + * convert to 16-bit integer; clamp at 16 bits. + * this allows the sum of brightness factors across phosphors + * for each of R G and B to be greater than 1.0 + */ + + r = (int)(rr * level_scale[ilevel] * 0xffff); + if (r > 0xffff) r = 0xffff; + + g = (int)(rg * level_scale[ilevel] * 0xffff); + if (g > 0xffff) g = 0xffff; + + b = (int)(rb * level_scale[ilevel] * 0xffff); + if (b > 0xffff) b = 0xffff; + + cp = ws_color_rgb(r, g, b); + if (!cp) { /* allocation failed? */ + if (ttl == MAXTTL-1) { /* brand new */ + if (ilevel == MAXLEVEL) /* highest intensity? */ + cp = ws_color_white(); /* use white */ + else + cp = colors[color][ilevel+1][ttl]; /* use next lvl */ + } /* brand new */ + else if (r + g + b >= 0xffff*3/3) /* light-ish? */ + cp = colors[color][ilevel][ttl+1]; /* use previous TTL */ + else + cp = ws_color_black(); + } + colors[color][ilevel][ttl] = cp; + } /* for each intensity level */ + } /* for each TTL */ +} /* phosphor_init */ + +static struct display * +find_type(enum display_type type) +{ + int i; + struct display *dp; + + for (i = 0, dp = displays; i < ELEMENTS(displays); i++, dp++) + if (dp->type == type) + return dp; + return NULL; +} + +int +display_init(enum display_type type, int sf) +{ + static int init_failed = 0; + struct display *dp; + int half_life; + int i; + + if (initialized) { + /* cannot change type once started */ + /* XXX say something???? */ + return type == display_type; + } + + if (init_failed) + return 0; /* avoid thrashing */ + + init_failed = 1; /* assume the worst */ + dp = find_type(type); + if (!dp) { + fprintf(stderr, "Unknown display type %d\r\n", (int)type); + goto failed; + } + + /* Initialize display list */ + head->next = head->prev = head; + + display_type = type; + scale = sf; + + xpoints = dp->xpoints; + ypoints = dp->ypoints; + + /* increase scale factor if won't fit on desktop? */ + xpixels = xpoints / scale; + ypixels = ypoints / scale; + + /* set default pen radius now that scale is set */ + display_lp_radius(PEN_RADIUS); + + ncolors = 1; + /* + * use function to calculate from looking at avg (max?) + * of phosphor half lives??? + */ +#define COLOR_HALF_LIFE(C) ((C)->half_life) + + half_life = COLOR_HALF_LIFE(dp->color0); + if (dp->color1) { + if (dp->color1->half_life > half_life) + half_life = COLOR_HALF_LIFE(dp->color1); + ncolors++; + } + + /* before phosphor_init; */ + refresh_rate = (1000000*LEVELS_PER_HALFLIFE)/half_life; + refresh_interval = 1000000/DELAY_UNIT/refresh_rate; + + /* + * sanity check refresh_interval + * calculating/selecting DELAY_UNIT at runtime might avoid this! + */ + + /* must be non-zero; interval of 1 means all pixels will age at once! */ + if (refresh_interval < 1) { + /* decrease DELAY_UNIT? */ + fprintf(stderr, "NOTE! refresh_interval too small: %d\r\n", + refresh_interval); + + /* dunno if this is a good idea, but might be better than dying */ + refresh_interval = 1; + } + + /* point lifetime in DELAY_UNITs will not fit in p->delay field! */ + if (refresh_interval > DELAY_T_MAX) { + /* increase DELAY_UNIT? */ + fprintf(stderr, "bad refresh_interval %d > DELAY_T_MAX %d\r\n", + refresh_interval, DELAY_T_MAX); + goto failed; + } + + /* + * before phosphor_init; + * set up relative brightness of display intensity levels + * (could differ for different hardware) + * + * linear for now. boost factor insures low intensities are visible + */ +#define BOOST 5 + for (i = 0; i < NLEVELS; i++) + level_scale[i] = ((float)i+1+BOOST)/(NLEVELS+BOOST); + + points = (struct point *)calloc((size_t)xpixels, + ypixels * sizeof(struct point)); + if (!points) + goto failed; + + if (!ws_init(dp->name, xpixels, ypixels, ncolors)) + goto failed; + + phosphor_init(dp->color0->phosphors, dp->color0->nphosphors, 0); + + if (dp->color1) + phosphor_init(dp->color1->phosphors, dp->color1->nphosphors, 1); + + initialized = 1; + init_failed = 0; /* hey, we made it! */ + return 1; + + failed: + fprintf(stderr, "Display initialization failed\r\n"); + return 0; +} + +void +display_reset(void) +{ + /* XXX tear down window? just clear it? */ +} + +void +display_sync(void) +{ + ws_sync(); +} + +void +display_beep(void) +{ + ws_beep(); +} + +int +display_xpoints(void) +{ + return xpoints; +} + +int +display_ypoints(void) +{ + return ypoints; +} + +int +display_scale(void) +{ + return scale; +} + +/* + * handle keyboard events + * + * data switches; 18 -- enough for PDP-1/4/7/9/15 (for munching squares!) + * 123 456 789 qwe rty uio + * bit toggled on key up + * all cleared on space + * + * spacewar switches; bit high as long as key down + * asdf kl;' + * just where PDP-1 spacewar expects them! + * key mappings same as MIT Media Lab Java PDP-1 simulator + * + */ +unsigned long spacewar_switches = 0; + +/* here from window system */ +void +display_keydown(int k) +{ + switch (k) { + case 'f': case 'F': spacewar_switches |= 01; break; /* torpedos */ + case 'd': case 'D': spacewar_switches |= 02; break; /* engines */ + case 'a': case 'A': spacewar_switches |= 04; break; /* rotate R */ + case 's': case 'S': spacewar_switches |= 010; break; /* rotate L */ + case '\'': case '"': spacewar_switches |= 040000; break; /* torpedos */ + case ';': case ':': spacewar_switches |= 0100000; break; /* engines */ + case 'k': case 'K': spacewar_switches |= 0200000; break; /* rotate R */ + case 'l': case 'L': spacewar_switches |= 0400000; break; /* rotate L */ + default: return; + } +} + +/* here from window system */ +void +display_keyup(int k) +{ + unsigned long test_switches = cpu_get_switches(); + + /* fetch console switches from simulator? */ + switch (k) { + case 'f': case 'F': spacewar_switches &= ~01; return; + case 'd': case 'D': spacewar_switches &= ~02; return; + case 'a': case 'A': spacewar_switches &= ~04; return; + case 's': case 'S': spacewar_switches &= ~010; return; + + case '\'': case '"': spacewar_switches &= ~040000; return; + case ';': case ':': spacewar_switches &= ~0100000; return; + case 'k': case 'K': spacewar_switches &= ~0200000; return; + case 'l': case 'L': spacewar_switches &= ~0400000; return; + + case '1': test_switches ^= 1<<17; break; + case '2': test_switches ^= 1<<16; break; + case '3': test_switches ^= 1<<15; break; + + case '4': test_switches ^= 1<<14; break; + case '5': test_switches ^= 1<<13; break; + case '6': test_switches ^= 1<<12; break; + + case '7': test_switches ^= 1<<11; break; + case '8': test_switches ^= 1<<10; break; + case '9': test_switches ^= 1<<9; break; + + case 'q': case 'Q': test_switches ^= 1<<8; break; + case 'w': case 'W': test_switches ^= 1<<7; break; + case 'e': case 'E': test_switches ^= 1<<6; break; + + case 'r': case 'R': test_switches ^= 1<<5; break; + case 't': case 'T': test_switches ^= 1<<4; break; + case 'y': case 'Y': test_switches ^= 1<<3; break; + + case 'u': case 'U': test_switches ^= 1<<2; break; + case 'i': case 'I': test_switches ^= 1<<1; break; + case 'o': case 'O': test_switches ^= 1; break; + + case ' ': test_switches = 0; break; + default: return; + } + cpu_set_switches(test_switches); +} diff --git a/display/display.h b/display/display.h index 94616b8f..98226eaf 100644 --- a/display/display.h +++ b/display/display.h @@ -1,143 +1,143 @@ -/* - * $Id: display.h,v 1.13 2004/01/24 08:34:33 phil Exp $ - * interface to O/S independent layer of XY display simulator - * Phil Budne - * September 2003 - * - * Changes from Douglas A. Gwyn, Jan 12, 2004 - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -/* - * known display types - */ -enum display_type { - DIS_VR14 = 14, - DIS_VR17 = 17, - DIS_VR20 = 20, - DIS_TYPE30 = 30, - DIS_TX0 = 33, - DIS_VR48 = 48, - DIS_TYPE340 = 340 -}; - -/* - * display scale factors - */ -#define RES_FULL 1 -#define RES_HALF 2 -#define RES_QUARTER 4 -#define RES_EIGHTH 8 - -/* - * must be called before first call to display_age() - * (but called implicitly by display_point()) - */ -extern int display_init(enum display_type, int scale); - -/* return size of virtual display */ -extern int display_xpoints(void); -extern int display_ypoints(void); - -/* virtual points between display and menu sections */ -#define VR48_GUTTER 8 /* just a guess */ - -/* conversion factor from virtual points and displayed pixels */ -extern int display_scale(void); - -/* - * simulate passage of time; first argument is simulated microseconds elapsed, - * second argument is flag to slow down simulated speed - * see comments in display.c for why you should call it often!! - * Under X11 polls for window events!! - */ -extern int display_age(int,int); - -/* - * display intensity levels. - * always at least 8 (for VT11/VS60) -- may be mapped internally - */ -#define DISPLAY_INT_MAX 7 -#define DISPLAY_INT_MIN 0 /* lowest "on" level */ - -/* - * plot a point; argumen ts are x, y, intensity, color (0/1) - * returns true if light pen active (mouse button down) - * at (or very near) this location. - * - * Display initialized on first call. - */ -extern int display_point(int,int,int,int); - -/* - * force window system to output bits to screen; - * call after adding points, or aging the screen - */ -extern void display_sync(void); - -/* - * currently a noop - */ -extern void display_reset(void); - -/* - * ring the bell - */ -extern void display_beep(void); - -/* - * Set light-pen radius; maximum radius in display coordinates - * from a "lit" location that the light pen will see. - */ -extern void display_lp_radius(int); - -/* - * set by simulated spacewar switch box switches - * 18 bits (only high 4 and low 4 used) - */ -extern unsigned long spacewar_switches; - -/* - * light pen "tip switch" activated (for VS60 emulation etc.) - * should only be set from "driver" (window system layer) - */ -extern unsigned char display_lp_sw; - -/* - * deactivates light pen - * (SIMH DR11-C simulation when initialized sets this and - * then reports mouse coordinates as Talos digitizer data) - */ -extern unsigned char display_tablet; - -/* - * users of this library are expected to provide these calls. - * simulator will set 18 simulated switches. - */ -extern unsigned long cpu_get_switches(void); /* get current switch state */ -extern void cpu_set_switches(unsigned long); /* set switches */ +/* + * $Id: display.h,v 1.13 2004/01/24 08:34:33 phil Exp $ + * interface to O/S independent layer of XY display simulator + * Phil Budne + * September 2003 + * + * Changes from Douglas A. Gwyn, Jan 12, 2004 + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +/* + * known display types + */ +enum display_type { + DIS_VR14 = 14, + DIS_VR17 = 17, + DIS_VR20 = 20, + DIS_TYPE30 = 30, + DIS_TX0 = 33, + DIS_VR48 = 48, + DIS_TYPE340 = 340 +}; + +/* + * display scale factors + */ +#define RES_FULL 1 +#define RES_HALF 2 +#define RES_QUARTER 4 +#define RES_EIGHTH 8 + +/* + * must be called before first call to display_age() + * (but called implicitly by display_point()) + */ +extern int display_init(enum display_type, int scale); + +/* return size of virtual display */ +extern int display_xpoints(void); +extern int display_ypoints(void); + +/* virtual points between display and menu sections */ +#define VR48_GUTTER 8 /* just a guess */ + +/* conversion factor from virtual points and displayed pixels */ +extern int display_scale(void); + +/* + * simulate passage of time; first argument is simulated microseconds elapsed, + * second argument is flag to slow down simulated speed + * see comments in display.c for why you should call it often!! + * Under X11 polls for window events!! + */ +extern int display_age(int,int); + +/* + * display intensity levels. + * always at least 8 (for VT11/VS60) -- may be mapped internally + */ +#define DISPLAY_INT_MAX 7 +#define DISPLAY_INT_MIN 0 /* lowest "on" level */ + +/* + * plot a point; argumen ts are x, y, intensity, color (0/1) + * returns true if light pen active (mouse button down) + * at (or very near) this location. + * + * Display initialized on first call. + */ +extern int display_point(int,int,int,int); + +/* + * force window system to output bits to screen; + * call after adding points, or aging the screen + */ +extern void display_sync(void); + +/* + * currently a noop + */ +extern void display_reset(void); + +/* + * ring the bell + */ +extern void display_beep(void); + +/* + * Set light-pen radius; maximum radius in display coordinates + * from a "lit" location that the light pen will see. + */ +extern void display_lp_radius(int); + +/* + * set by simulated spacewar switch box switches + * 18 bits (only high 4 and low 4 used) + */ +extern unsigned long spacewar_switches; + +/* + * light pen "tip switch" activated (for VS60 emulation etc.) + * should only be set from "driver" (window system layer) + */ +extern unsigned char display_lp_sw; + +/* + * deactivates light pen + * (SIMH DR11-C simulation when initialized sets this and + * then reports mouse coordinates as Talos digitizer data) + */ +extern unsigned char display_tablet; + +/* + * users of this library are expected to provide these calls. + * simulator will set 18 simulated switches. + */ +extern unsigned long cpu_get_switches(void); /* get current switch state */ +extern void cpu_set_switches(unsigned long); /* set switches */ diff --git a/display/gmakefile b/display/gmakefile index 4ef7b28e..4b5b9813 100644 --- a/display/gmakefile +++ b/display/gmakefile @@ -1,77 +1,86 @@ -# $Id: gmakefile,v 1.17 2004/01/24 08:31:56 phil Exp - revised by DAG - -# (GNU) Makefile for test programs under Unix/X11 and Win32 -# -# Unix: -# edit Unix defs to fit your compiler/library environment, then -# gmake -f gmakefile -# or if GNU make is the default: -# make -f gmakefile -# -# Win32 (Cygwin) -# make WIN32=1 -# -# Win32 (MINGW): -# mingw32-make -f gmakefile WIN32=1 - -DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11 - -ifeq ($(WIN32),) -#Unix environments -X11BASE=/usr/X11R6 -X11LIBDIR=$(X11BASE)/lib -X11INCDIR=$(X11BASE)/include -LIBS=-L$(X11LIBDIR) -lXt -lX11 -lm -OSFLAGS=-I$(X11INCDIR) -DRIVER=x11.o -EXT= -else -#Win32 environments -LIBS=-lgdi32 -OSFLAGS= -DRIVER=win32.o -EXT=.exe -endif - -#PROF=-g # -pg -OPT=-O2 -CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) -CC=gcc -Wunused -LDFLAGS=$(PROF) - -ALL= munch$(EXT) vt11$(EXT) -ALL: $(ALL) - -# munching squares; see README file for -# how to use console switches - -MUNCH=$(DRIVER) display.o test.o -munch$(EXT): $(MUNCH) - $(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS) - -VT11=$(DRIVER) vt11.o vttest.o display.o -vt11$(EXT): $(VT11) - $(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS) - -display.o: display.h ws.h -vt11.o: display.h vt11.h -x11.o: ws.h display.h -win32.o: ws.h -test.o: display.h vt11.h -vttest.o: display.h vt11.h vtmacs.h - -clean: -ifeq ($(WIN32),) - rm -f *.o *~ .#* -else - if exist *.o del /q *.o - if exist *~ del /q *~ - if exist .#* del /q .#* -endif - -clobber: clean -ifeq ($(WIN32),) - rm -f $(ALL) -else - if exist *.exe del /q *.exe -endif +# $Id: gmakefile,v 1.24 2005/11/05 02:06:14 phil Exp $ + +# (GNU) Makefile for test programs under Unix/X11 and Win32 +# +# Unix: +# edit Unix defs to fit your compiler/library environment, then +# gmake -f gmakefile +# or if GNU make is the default: +# make -f gmakefile +# +# OS X (Carbon) +# make -f gmakefile OSX=1 +# +# Win32 (Cygwin) +# make -f gmakefile WIN32=1 +# +# Win32 (MINGW): +# mingw32-make -f gmakefile WIN32=1 + +DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11 + +ifeq ($(WIN32),) +ifeq ($(OSX),) +#Unix environments +X11BASE=/usr/X11R6 +X11LIBDIR=$(X11BASE)/lib +X11INCDIR=$(X11BASE)/include +LIBS=-L$(X11LIBDIR) -lXt -lX11 -lm +OSFLAGS=-I$(X11INCDIR) +DRIVER=x11.o +EXT= +else +DRIVER=carbon.o +LIBS=-framework Carbon +endif +else +#Win32 environments +LIBS=-lgdi32 +OSFLAGS= +DRIVER=win32.o +EXT=.exe +endif + +#PROF=-g # -pg +OPT=-O2 +CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) +CC=gcc -Wunused +LDFLAGS=$(PROF) + +ALL= munch$(EXT) vt11$(EXT) +ALL: $(ALL) + +# munching squares; see README file for +# how to use console switches + +MUNCH=$(DRIVER) xy.o test.o +munch$(EXT): $(MUNCH) + $(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS) + +VT11=$(DRIVER) vt11.o vttest.o xy.o +vt11$(EXT): $(VT11) + $(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS) + +xy.o: xy.h ws.h +vt11.o: xy.h vt11.h +x11.o: ws.h xy.h +carbon.o: ws.h +win32.o: ws.h +test.o: xy.h vt11.h +vttest.o: xy.h vt11.h vtmacs.h + +clean: +ifeq ($(WIN32),) + rm -f *.o *~ .#* +else + if exist *.o del /q *.o + if exist *~ del /q *~ + if exist .#* del /q .#* +endif + +clobber: clean +ifeq ($(WIN32),) + rm -f $(ALL) +else + if exist *.exe del /q *.exe +endif diff --git a/display/smakefile b/display/smakefile index 0956a917..10d6f2cc 100644 --- a/display/smakefile +++ b/display/smakefile @@ -1,75 +1,91 @@ -# $Id: smakefile,v 1.17 2004/01/24 08:31:56 phil Exp - revised by DAG - -# Makefile for test programs (standard Unix "make" version) - -# Unix: -# comment out Windows defs, uncomment Unix defs, -# edit Unix defs to fit your compiler/library environment, then -# (g)make -# -# Win32 (Cygwin) -# comment out Unix defs, uncomment Windows defs, then -# make -# -# Win32 (MINGW) -# comment out Unix defs, uncomment Windows defs, then -# mingw32-make - -DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11 - -#Unix environments -CC=cc # gcc -Wunused -#X11BASE=/usr/X11R6 -#X11LIBDIR=$(X11BASE)/lib -#X11INCDIR=$(X11BASE)/include -LIBS=-lXt -lX11 -lm # -L$(X11LIBDIR) -OSFLAGS=-I$(X11INCDIR) -DRIVER=x11.o -EXT= -PROF=-g # -pg -OPT=-O # -O2 -CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) -CC=cc # gcc -Wunused -LDFLAGS=$(PROF) - -##Win32 environments -#LIBS=-lgdi32 -#OSFLAGS= -#DRIVER=win32.o -#EXT=.exe -#PROF=-g # -pg -#OPT=-O2 -#CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) -#CC=gcc -Wunused -LDFLAGS=$(PROF) - -ALL= munch$(EXT) vt11$(EXT) -ALL: $(ALL) - -# munching squares; see README file for -# how to use console switches - -MUNCH=$(DRIVER) display.o test.o -munch$(EXT): $(MUNCH) - $(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS) - -VT11=$(DRIVER) vt11.o vttest.o display.o -vt11$(EXT): $(VT11) - $(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS) - -display.o: display.h ws.h -vt11.o: display.h vt11.h -x11.o: ws.h display.h -win32.o: ws.h -test.o: display.h vt11.h -vttest.o: display.h vt11.h vtmacs.h - -clean: - rm -f *.o *~ .#* # Unix -# if exist *.o del /q *.o # Win32 -# if exist *~ del /q *~ # Win32 -# if exist .#* del /q .#* # Win32 - -clobber: clean - rm -f $(ALL) # Unix -# if exist *.exe del /q *.exe # Win32 +# $Id: smakefile,v 1.6 2005/11/05 02:06:14 phil Exp $ + +# Makefile for test programs (standard Unix "make" version) + +# Unix: +# comment out OS X, Windows defs, uncomment Unix defs, +# edit Unix defs to fit your compiler/library environment, then +# make -f smakefile +# +# OS X (Carbon) +# comment out Unix, Windows defs, uncomment OS X defs +# make -f smakefile +# +# Win32 (Cygwin) +# comment out Unix defs, uncomment Windows defs, then +# make -f smakefile +# +# Win32 (MINGW) +# comment out Unix defs, uncomment Windows defs, then +# mingw32-make + +DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11 + +#Unix environments +CC=cc +#CC=gcc -Wunused +#X11BASE=/usr/X11R6 +#X11LIBDIR=$(X11BASE)/lib +#X11INCDIR=$(X11BASE)/include +LIBS=-lXt -lX11 -lm # -L$(X11LIBDIR) +OSFLAGS=-I$(X11INCDIR) +DRIVER=x11.o +EXT= +PROF=-g # -pg +OPT=-O # -O2 +CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) +LDFLAGS=$(PROF) + +##OS X +#CC=cc -Wunused +#LIBS=-framework Carbon +#OSFLAGS= +#DRIVER=carbon.o +#EXT= +#PROF=-g # -pg +#OPT=-O # -O2 +#CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) +#LDFLAGS=$(PROF) + +##Win32 environments +#LIBS=-lgdi32 +#OSFLAGS= +#DRIVER=win32.o +#EXT=.exe +#PROF=-g # -pg +#OPT=-O2 +#CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS) +#CC=gcc -Wunused +LDFLAGS=$(PROF) + +ALL= munch$(EXT) vt11$(EXT) +ALL: $(ALL) + +# munching squares; see README file for +# how to use console switches + +MUNCH=$(DRIVER) xy.o test.o +munch$(EXT): $(MUNCH) + $(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS) + +VT11=$(DRIVER) vt11.o vttest.o xy.o +vt11$(EXT): $(VT11) + $(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS) + +xy.o: xy.h ws.h +vt11.o: xy.h vt11.h +x11.o: ws.h xy.h +carbon.o: ws.h +win32.o: ws.h +test.o: xy.h vt11.h +vttest.o: xy.h vt11.h vtmacs.h + +clean: + rm -f *.o *~ .#* # Unix +# if exist *.o del /q *.o # Win32 +# if exist *~ del /q *~ # Win32 +# if exist .#* del /q .#* # Win32 + +clobber: clean + rm -f $(ALL) # Unix +# if exist *.exe del /q *.exe # Win32 diff --git a/display/test.c b/display/test.c index 5b5b6438..99f576d9 100644 --- a/display/test.c +++ b/display/test.c @@ -1,192 +1,192 @@ -/* - * $Id: test.c,v 1.23 2004/02/07 06:31:20 phil Exp $ - * XY Display simulator test program (PDP-1 Munching Squares) - * Phil Budne - * September 2003 - * - * Updates from Douglas A. Gwyn, 12 Jan. 2004 - * - * With thanks to Daniel Smith for his web page: - * http://world.std.com/~dpbsmith/munch.html - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#ifndef TEST_DIS -#define TEST_DIS DIS_TYPE30 -#endif - -#ifndef TEST_RES -#define TEST_RES RES_HALF -#endif - -#include -#include - -#ifndef EXIT_FAILURE -/* SunOS4 doesn't define this */ -#define EXIT_FAILURE 1 -#endif - -#include "display.h" - -static unsigned long test_switches = 0; - -/* called from display code: */ -unsigned long -cpu_get_switches(void) { - return test_switches; -} - -/* called from display code: */ -void -cpu_set_switches(bits) - unsigned long bits; -{ - printf("switches: %06lo\n", bits); - test_switches = bits; -} - -void -munch(void) { - static long us = 0; - static long io = 0, v = 0; - long ac; - int x, y; - - ac = test_switches; - ac += v; /* add v */ - if (ac & ~0777777) { - ac++; - ac &= 0777777; - } - v = ac; /* dac v */ - - ac <<= 9; /* rcl 9s */ - io <<= 9; - io |= ac>>18; - ac &= 0777777; - ac |= io>>18; - io &= 0777777; - - ac ^= v; /* xor v */ - - /* convert +/-512 one's complement to 0..1022, origin in lower left */ - y = (io >> 8) & 01777; /* hi 10 */ - if (y & 01000) - y ^= 01000; - else - y += 511; - - x = (ac >> 8) & 01777; /* hi 10 */ - if (x & 01000) /* negative */ - x ^= 01000; - else - x += 511; - - if (display_point(x, y, DISPLAY_INT_MAX, 0)) - printf("light pen hit at (%d,%d)\n", x, y); - -/*#define US 100000 /* 100ms (10/sec) */ -/*#define US 50000 /* 50ms (20/sec) */ -/*#define US 20000 /* 20ms (50/sec) */ -/*#define US 10000 /* 10ms (100/sec) */ -#define US 0 - us += 50; /* 10 5us PDP-1 memory cycles */ - if (us >= US) { - display_age(us, 1); - us = 0; - } - display_sync(); /* XXX push down */ -} - -#ifdef T2 -/* display all window system level intensities; - * must be compiled with -DINTENSITIES= -DT2 - */ -void -t2(void) { - int x, y; - - display_init(TEST_DIS, TEST_RES); - for (x = INTENSITIES-1; x >= 0; x--) { - for (y = 0; y < 20; y++) { - ws_display_point(x*4, y, x, 0); - ws_display_point(x*4+1, y, x, 0); - ws_display_point(x*4+2, y, x, 0); - ws_display_point(x*4+3, y, x, 0); - } - display_sync(); - } - fflush(stdout); - for (;;) - /* wait */ ; -} -#endif - -#ifdef T3 -/* display all "user" level intensities; - * must be compiled with -DINTENSITIES= -DT3 - * - * skip every other virtual point on both axes - * default scaling maps adjacent pixels and - * causes re-intensification! - */ -void -t3(void) { - int x, y; - - display_init(TEST_DIS, TEST_RES); - for (x = DISPLAY_INT_MAX; x >= 0; x--) { - for (y = 0; y < 20; y++) { - display_point(x*2, y*2, x, 0); - } - display_sync(); - } - fflush(stdout); - for (;;) - /* wait */ ; -} -#endif - -int -main(void) { - if (!display_init(TEST_DIS, TEST_RES)) - exit(EXIT_FAILURE); - - cpu_set_switches(04000UL); /* classic starting value */ - for (;;) { -#ifdef T2 - t2(); -#endif -#ifdef T3 - t3(); -#endif - munch(); - } - /*NOTREACHED*/ -} +/* + * $Id: test.c,v 1.24 2005/01/14 18:58:00 phil Exp $ + * XY Display simulator test program (PDP-1 Munching Squares) + * Phil Budne + * September 2003 + * + * Updates from Douglas A. Gwyn, 12 Jan. 2004 + * + * With thanks to Daniel Smith for his web page: + * http://world.std.com/~dpbsmith/munch.html + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#ifndef TEST_DIS +#define TEST_DIS DIS_TYPE30 +#endif + +#ifndef TEST_RES +#define TEST_RES RES_HALF +#endif + +#include +#include + +#ifndef EXIT_FAILURE +/* SunOS4 doesn't define this */ +#define EXIT_FAILURE 1 +#endif + +#include "xy.h" + +static unsigned long test_switches = 0; + +/* called from display code: */ +unsigned long +cpu_get_switches(void) { + return test_switches; +} + +/* called from display code: */ +void +cpu_set_switches(bits) + unsigned long bits; +{ + printf("switches: %06lo\n", bits); + test_switches = bits; +} + +void +munch(void) { + static long us = 0; + static long io = 0, v = 0; + long ac; + int x, y; + + ac = test_switches; + ac += v; /* add v */ + if (ac & ~0777777) { + ac++; + ac &= 0777777; + } + v = ac; /* dac v */ + + ac <<= 9; /* rcl 9s */ + io <<= 9; + io |= ac>>18; + ac &= 0777777; + ac |= io>>18; + io &= 0777777; + + ac ^= v; /* xor v */ + + /* convert +/-512 one's complement to 0..1022, origin in lower left */ + y = (io >> 8) & 01777; /* hi 10 */ + if (y & 01000) + y ^= 01000; + else + y += 511; + + x = (ac >> 8) & 01777; /* hi 10 */ + if (x & 01000) /* negative */ + x ^= 01000; + else + x += 511; + + if (display_point(x, y, DISPLAY_INT_MAX, 0)) + printf("light pen hit at (%d,%d)\n", x, y); + +/*#define US 100000 /* 100ms (10/sec) */ +/*#define US 50000 /* 50ms (20/sec) */ +/*#define US 20000 /* 20ms (50/sec) */ +/*#define US 10000 /* 10ms (100/sec) */ +#define US 0 + us += 50; /* 10 5us PDP-1 memory cycles */ + if (us >= US) { + display_age(us, 1); + us = 0; + } + display_sync(); /* XXX push down */ +} + +#ifdef T2 +/* display all window system level intensities; + * must be compiled with -DINTENSITIES= -DT2 + */ +void +t2(void) { + int x, y; + + display_init(TEST_DIS, TEST_RES); + for (x = INTENSITIES-1; x >= 0; x--) { + for (y = 0; y < 20; y++) { + ws_display_point(x*4, y, x, 0); + ws_display_point(x*4+1, y, x, 0); + ws_display_point(x*4+2, y, x, 0); + ws_display_point(x*4+3, y, x, 0); + } + display_sync(); + } + fflush(stdout); + for (;;) + /* wait */ ; +} +#endif + +#ifdef T3 +/* display all "user" level intensities; + * must be compiled with -DINTENSITIES= -DT3 + * + * skip every other virtual point on both axes + * default scaling maps adjacent pixels and + * causes re-intensification! + */ +void +t3(void) { + int x, y; + + display_init(TEST_DIS, TEST_RES); + for (x = DISPLAY_INT_MAX; x >= 0; x--) { + for (y = 0; y < 20; y++) { + display_point(x*2, y*2, x, 0); + } + display_sync(); + } + fflush(stdout); + for (;;) + /* wait */ ; +} +#endif + +int +main(void) { + if (!display_init(TEST_DIS, TEST_RES)) + exit(EXIT_FAILURE); + + cpu_set_switches(04000UL); /* classic starting value */ + for (;;) { +#ifdef T2 + t2(); +#endif +#ifdef T3 + t3(); +#endif + munch(); + } + /*NOTREACHED*/ +} diff --git a/display/type340.c b/display/type340.c index 7ac9eb9a..58ccc989 100644 --- a/display/type340.c +++ b/display/type340.c @@ -1,706 +1,706 @@ -/* - * $Id: type340.c,v 1.5 2004/01/24 20:52:16 phil Exp $ - * Simulator Independent DEC Type 340 Graphic Display Processor Simulation - * Phil Budne - * September 20, 2003 - * from vt11.c - * - * Information from DECUS 7-13 - * http://www.spies.com/~aek/pdf/dec/pdp7/7-13_340displayProgMan.pdf - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the author shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#include "display.h" /* XY plot interface */ - -/* - * The Type 340 was used on the PDP-{4,6,7,9,10} - * and used 18-bit words, with bits numbered 0 thru 17 - * (most significant to least) - */ - -#define BITMASK(N) (1<<(17-(N))) - -/* mask for a field */ -#define FIELDMASK(START,END) ((1<<((END)-(START)+1))-1) - -/* extract a field */ -#define GETFIELD(W,START,END) (((W)>>(17-(END)))&FIELDMASK(START,END)) - -/* extract a 1-bit field */ -#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0) - -#ifdef DEBUG_TY340 -#define DEBUGF(X) printf X -#else -#define DEBUGF(X) -#endif - -typedef long ty340word; - -static ty340word DAC; /* Display Address Counter */ -static unsigned char shift; /* 1 bit */ -static enum mode mode; /* 3 bits */ -static int scale; /* 2 bits */ - -enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR }; - -enum jump_type { DJP=2, DJS=3, DDS=1 }; -static ty340word ASR; /* Address Save Register */ -static unsigned char save_ff; /* "save" flip-flop */ - -static unsigned char intensity; /* 3 bits */ -static unsigned char lp_ena; /* 1 bit */ - -/* kept signed for raster violation checking */ -static short xpos, ypos; /* 10 bits, signed */ -static unsigned char sequence; /* 2 bits */ - -/* XXX make defines public for 340_cycle return */ -#define STOPPED 01 -#define LPHIT 02 -#define VEDGE 04 -#define HEDGE 010 -static unsigned char status = STOPPED; - -/* - * callbacks into PDP-6/10 simulator - */ -extern ty340word ty340_fetch(ty340word); -extern void ty340_store(ty340word, ty340word); -extern void ty340_stop_int(void); -extern void ty340_lp_int(void); - -void -ty340_set_dac(ty340word addr) -{ - DAC = addr; - mode = 0; - DEBUGF(("set DAC %06\r\n", DAC)); - status = 0; /* XXX just clear stopped? */ - /* XXX clear other stuff? save_ff? */ -} - -void -ty340_reset(void) -{ - /* XXX call display layer? destroy window? */ - xpos = ypos = 0; - status = STOPPED; -} - -static int -point(int x, int y, int seq) -{ - int i; - - /* XXX apply scale? */ - - i = DISPLAY_INT_MAX-7+intensity; - if (i <= 0) - i = 1; - - if (x < 0 || x > 1023) { - status |= VEDGE; - return 0; - } - if (y < 0 || y > 1023) { - status |= HEDGE; - return 0; - } - - if (display_point(x, y, i, 0)) { - if (lp_ena) { - /* XXX save location? */ - status |= LPHIT; - sequence = seq; - } - } -} - -/* - * two-step algorithm, developed by Xiaolin Wu - * from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html - */ - -/* - * The two-step algorithm takes the interesting approach of treating - * line drawing as a automaton, or finite state machine. If one looks - * at the possible configurations for the next two pixels of a line, - * it is easy to see that only a finite set of possibilities exist. - * The two-step algorithm shown here also exploits the symmetry of - * line-drawing by simultaneously drawn from both ends towards the - * midpoint. - */ - -static void -lineTwoStep(int x0, int y0, int x1, int y1) -{ - int dy = y1 - y0; - int dx = x1 - x0; - int stepx, stepy; - - if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } - if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } - - lpoint(x0,y0); - if (dx == 0 && dy == 0) /* following algorithm won't work */ - return; /* just the one dot */ - lpoint(x1, y1); - if (dx > dy) { - int length = (dx - 1) >> 2; - int extras = (dx - 1) & 3; - int incr2 = (dy << 2) - (dx << 1); - if (incr2 < 0) { - int c = dy << 1; - int incr1 = c << 1; - int d = incr1 - dx; - int i; - - for (i = 0; i < length; i++) { - x0 += stepx; - x1 -= stepx; - if (d < 0) { /* Pattern: */ - lpoint(x0, y0); - lpoint(x0 += stepx, y0); /* x o o */ - lpoint(x1, y1); - lpoint(x1 -= stepx, y1); - d += incr1; - } - else { - if (d < c) { /* Pattern: */ - lpoint(x0, y0); /* o */ - lpoint(x0 += stepx, y0 += stepy); /* x o */ - lpoint(x1, y1); - lpoint(x1 -= stepx, y1 -= stepy); - } else { - lpoint(x0, y0 += stepy); /* Pattern: */ - lpoint(x0 += stepx, y0); /* o o */ - lpoint(x1, y1 -= stepy); /* x */ - lpoint(x1 -= stepx, y1); - } - d += incr2; - } - } - if (extras > 0) { - if (d < 0) { - lpoint(x0 += stepx, y0); - if (extras > 1) lpoint(x0 += stepx, y0); - if (extras > 2) lpoint(x1 -= stepx, y1); - } else - if (d < c) { - lpoint(x0 += stepx, y0); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1 -= stepx, y1); - } else { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0); - if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); - } - } - } else { - int c = (dy - dx) << 1; - int incr1 = c << 1; - int d = incr1 + dx; - int i; - for (i = 0; i < length; i++) { - x0 += stepx; - x1 -= stepx; - if (d > 0) { - lpoint(x0, y0 += stepy); /* Pattern: */ - lpoint(x0 += stepx, y0 += stepy); /* o */ - lpoint(x1, y1 -= stepy); /* o */ - lpoint(x1 -= stepx, y1 -= stepy); /* x */ - d += incr1; - } else { - if (d < c) { - lpoint(x0, y0); /* Pattern: */ - lpoint(x0 += stepx, y0 += stepy); /* o */ - lpoint(x1, y1); /* x o */ - lpoint(x1 -= stepx, y1 -= stepy); - } else { - lpoint(x0, y0 += stepy); /* Pattern: */ - lpoint(x0 += stepx, y0); /* o o */ - lpoint(x1, y1 -= stepy); /* x */ - lpoint(x1 -= stepx, y1); - } - d += incr2; - } - } - if (extras > 0) { - if (d > 0) { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); - } else if (d < c) { - lpoint(x0 += stepx, y0); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1 -= stepx, y1); - } else { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0); - if (extras > 2) { - if (d > c) - lpoint(x1 -= stepx, y1 -= stepy); - else - lpoint(x1 -= stepx, y1); - } - } - } - } - } else { - int length = (dy - 1) >> 2; - int extras = (dy - 1) & 3; - int incr2 = (dx << 2) - (dy << 1); - if (incr2 < 0) { - int c = dx << 1; - int incr1 = c << 1; - int d = incr1 - dy; - int i; - for (i = 0; i < length; i++) { - y0 += stepy; - y1 -= stepy; - if (d < 0) { - lpoint(x0, y0); - lpoint(x0, y0 += stepy); - lpoint(x1, y1); - lpoint(x1, y1 -= stepy); - d += incr1; - } else { - if (d < c) { - lpoint(x0, y0); - lpoint(x0 += stepx, y0 += stepy); - lpoint(x1, y1); - lpoint(x1 -= stepx, y1 -= stepy); - } else { - lpoint(x0 += stepx, y0); - lpoint(x0, y0 += stepy); - lpoint(x1 -= stepx, y1); - lpoint(x1, y1 -= stepy); - } - d += incr2; - } - } - if (extras > 0) { - if (d < 0) { - lpoint(x0, y0 += stepy); - if (extras > 1) lpoint(x0, y0 += stepy); - if (extras > 2) lpoint(x1, y1 -= stepy); - } else - if (d < c) { - lpoint(x0, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1, y1 -= stepy); - } else { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0, y0 += stepy); - if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); - } - } - } else { - int c = (dx - dy) << 1; - int incr1 = c << 1; - int d = incr1 + dy; - int i; - for (i = 0; i < length; i++) { - y0 += stepy; - y1 -= stepy; - if (d > 0) { - lpoint(x0 += stepx, y0); - lpoint(x0 += stepx, y0 += stepy); - lpoint(x1 -= stepy, y1); - lpoint(x1 -= stepx, y1 -= stepy); - d += incr1; - } else { - if (d < c) { - lpoint(x0, y0); - lpoint(x0 += stepx, y0 += stepy); - lpoint(x1, y1); - lpoint(x1 -= stepx, y1 -= stepy); - } else { - lpoint(x0 += stepx, y0); - lpoint(x0, y0 += stepy); - lpoint(x1 -= stepx, y1); - lpoint(x1, y1 -= stepy); - } - d += incr2; - } - } - if (extras > 0) { - if (d > 0) { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); - } else if (d < c) { - lpoint(x0, y0 += stepy); - if (extras > 1) lpoint(x0 += stepx, y0 += stepy); - if (extras > 2) lpoint(x1, y1 -= stepy); - } else { - lpoint(x0 += stepx, y0 += stepy); - if (extras > 1) lpoint(x0, y0 += stepy); - if (extras > 2) { - if (d > c) - lpoint(x1 -= stepx, y1 -= stepy); - else - lpoint(x1, y1 -= stepy); - } - } - } - } - } -} /* lineTwoStep */ - -static int -vector(int i, int sx, int dx, int sy, int dy) -{ - int x0, y0, x1, y1; - - x0 = xpos; - y0 = ypos; - - if (sx) { - x1 = x0 - dx; - if (x1 < 0) /* XXX TEMP? */ - x1 = 0; - } - else { - x1 = x0 + dx; - if (x1 > 1023) /* XXX TEMP? */ - x1 = 1023; - } - - if (sy) { - y1 = y0 - dy; - if (y1 < 0) /* XXX TEMP? */ - y1 = 0; - } - else { - y1 = y0 + dy; /* XXX TEMP? */ - if (y1 > 1023) - y1 = 1023; - } - - DEBUGF(("vector i%d (%d,%d) to (%d,%d)\r\n", i, x0, y0, x1, y1)); - if (i) - lineTwoStep(x0, y0, x1, y1); - - xpos = x1; - ypos = y1; - return 0; -} - -/* return true on raster violation */ -int -ipoint(int i, int n, unsigned char byte) -{ - if (byte & 010) { /* left/right */ - if (byte & 04) { - if (xpos == 0) { - status |= VEDGE; - return 1; - } - xpos--; - } - else { - if (xpos == 1023) { - status |= VEDGE; - return 1; - } - xpos++; - } - } - if (byte & 02) { /* up/down */ - if (byte & 04) { - if (ypos == 0) { - status |= HEDGE; - return 1; - } - ypos--; - } - else { - if (ypos == 1023) { - status |= HEDGE; - return 1; - } - ypos++; - } - } - if (i) - point(xpos, ypos, n); - - return 0; -} - -/* - * 342 character generator - first 64 characters (from manual) - */ -static const unsigned char chars[64][5] = { - { 0070, 0124, 0154, 0124, 0070 }, /* 00 */ - { 0174, 0240, 0240, 0240, 0174 }, /* 01 A */ - { 0376, 0222, 0222, 0222, 0154 }, /* 02 B */ - { 0174, 0202, 0202, 0202, 0104 }, /* 03 C */ - { 0376, 0202, 0202, 0202, 0174 }, /* 04 D */ - { 0376, 0222, 0222, 0222, 0222 }, /* 05 E */ - { 0376, 0220, 0220, 0220, 0220 }, /* 06 F */ - { 0174, 0202, 0222, 0222, 0134 }, /* 07 G */ - { 0376, 0020, 0020, 0020, 0376 }, /* 10 H */ - { 0000, 0202, 0376, 0202, 0000 }, /* 11 I */ - { 0004, 0002, 0002, 0002, 0374 }, /* 12 J */ - { 0376, 0020, 0050, 0104, 0202 }, /* 13 K */ - { 0376, 0002, 0002, 0002, 0002 }, /* 14 K */ - { 0374, 0100, 0040, 0100, 0374 }, /* 15 M */ - { 0376, 0100, 0040, 0020, 0376 }, /* 16 N */ - { 0174, 0202, 0202, 0202, 0174 }, /* 17 O */ - { 0376, 0220, 0220, 0220, 0140 }, /* 20 P */ - { 0174, 0202, 0212, 0206, 0176 }, /* 21 Q */ - { 0376, 0220, 0230, 0224, 0142 }, /* 22 R */ - { 0144, 0222, 0222, 0222, 0114 }, /* 23 S */ - { 0200, 0200, 0376, 0200, 0200 }, /* 24 T */ - { 0374, 0002, 0002, 0002, 0374 }, /* 25 U */ - { 0370, 0004, 0002, 0004, 0370 }, /* 26 V */ - { 0376, 0004, 0010, 0004, 0376 }, /* 27 W */ - { 0202, 0104, 0070, 0104, 0202 }, /* 30 X */ - { 0200, 0100, 0076, 0100, 0200 }, /* 31 Y */ - { 0226, 0232, 0222, 0262, 0322 }, /* 32 Z */ - { 0000, 0000, 0000, 0000, 0000 }, /* 33 LF */ - { 0000, 0000, 0000, 0000, 0000 }, /* 34 CR */ - { 0000, 0000, 0000, 0000, 0000 }, /* 35 HORIZ */ - { 0000, 0000, 0000, 0000, 0000 }, /* 36 VERT */ - { 0000, 0000, 0000, 0000, 0000 }, /* 37 ESC */ - { 0000, 0000, 0000, 0000, 0000 }, /* 40 space */ - { 0000, 0000, 0372, 0000, 0000 }, /* 41 ! */ - { 0000, 0340, 0000, 0340, 0000 }, /* 42 " */ - { 0050, 0376, 0050, 0376, 0050 }, /* 43 # */ - { 0144, 0222, 0376, 0222, 0114 }, /* 44 $ */ - { 0306, 0310, 0220, 0246, 0306 }, /* 45 % */ - { 0154, 0222, 0156, 0004, 0012 }, /* 46 & */ - { 0000, 0000, 0300, 0340, 0000 }, /* 47 ' */ - { 0070, 0104, 0202, 0000, 0000 }, /* 50 ( */ - { 0000, 0000, 0202, 0104, 0070 }, /* 51 ) */ - { 0124, 0070, 0174, 0070, 0124 }, /* 52 * */ - { 0020, 0020, 0174, 0020, 0020 }, /* 53 + */ - { 0000, 0014, 0016, 0000, 0000 }, /* 54 , */ - { 0020, 0020, 0020, 0020, 0020 }, /* 55 - */ - { 0000, 0006, 0006, 0000, 0000 }, /* 56 . */ - { 0004, 0010, 0020, 0040, 0100 }, /* 57 / */ - { 0174, 0212, 0222, 0242, 0174 }, /* 60 0 */ - { 0000, 0102, 0376, 0002, 0000 }, /* 61 1 */ - { 0116, 0222, 0222, 0222, 0142 }, /* 62 2 */ - { 0104, 0202, 0222, 0222, 0154 }, /* 63 3 */ - { 0020, 0060, 0120, 0376, 0020 }, /* 64 4 */ - { 0344, 0222, 0222, 0222, 0214 }, /* 65 5 */ - { 0174, 0222, 0222, 0222, 0114 }, /* 66 6 */ - { 0306, 0210, 0220, 0240, 0300 }, /* 67 7 */ - { 0154, 0222, 0222, 0222, 0154 }, /* 70 8 */ - { 0144, 0222, 0222, 0222, 0174 }, /* 71 9 */ - { 0000, 0066, 0066, 0000, 0000 }, /* 72 : */ - { 0000, 0154, 0156, 0000, 0000 }, /* 73 ; */ - { 0020, 0050, 0104, 0202, 0000 }, /* 74 < */ - { 0050, 0050, 0050, 0050, 0050 }, /* 75 = */ - { 0000, 0202, 0104, 0050, 0020 }, /* 76 > */ - { 0100, 0200, 0236, 0220, 0140 } /* 77 ? */ -}; - -/* - * type 342 Character/Symbol generator for type 340 display - * return true if ESCaped - */ -static int -character(int n, char c) -{ - int x, y; - - switch (c) { - case 033: /* LF */ - if (ypos < 12) { - status |= HEDGE; - ypos = 0; - } - else - ypos -= 12; /* XXX scale? */ - - return 0; - case 034: /* CR */ - xpos = 0; - return 0; - case 035: /* shift in */ - shift = 1; - return 0; - case 036: /* shift out */ - shift = 0; - return 0; - case 037: /* escape */ - sequence = n; - return 1; - } - /* XXX plot character from character set selected by "shift" - * (offset index by 64?) - */ - for (x = 0; x < 5; x++) { - for (y = 0; y < 7; y++) { - if (chars[c][x] & (1< 1023) { - xpos = 1023; - status |= VEDGE; - } - return 0; -} - -int -ty340_cycle(int us, int slowdown) -{ - ty340word inst, addr; - int i, escape, stopped; - - if (status & STOPPED) - return 0; /* XXX age display? */ - - inst = ty340_fetch(DAC); - DEBUGF(("%06o: %06o\r\n", DAC, inst)); - DAC++; - - escape = 0; - switch (mode) { - case PARAM: - mode = GETFIELD(inst, 2, 4); - - if (TESTBIT(inst, 5)) { /* load l.p. enable */ - lp_ena = TESTBIT(inst,6); - DEBUGF(("lp_ena %d\r\n", lp_ena)); - } - - if (TESTBIT(inst, 7)) { - status |= STOPPED; - if (TESTBIT(inst, 8)) - ty340_stop_int(); /* set stop_int_end? */ - } - - if (TESTBIT(inst, 11)) - scale = GETFIELD(inst, 12, 13); - - if (TESTBIT(inst, 14)) - intensity = GETFIELD(inst, 15, 17); - - break; - - case POINT: - mode = GETFIELD(inst, 2, 4); - - if (TESTBIT(inst, 5)) /* load l.p. enable */ - lp_ena = TESTBIT(inst,6); - - if (TESTBIT(inst, 1)) - ypos = GETFIELD(inst, 8, 17); - else - xpos = GETFIELD(inst, 8, 17); - - if (TESTBIT(inst, 7)) - point(xpos, ypos, 0); - break; - - case SLAVE: - mode = GETFIELD(inst, 2, 4); - break; - - case CHAR: - escape = (character(0, GETFIELD(inst, 0, 5)) || - character(1, GETFIELD(inst, 6, 11)) || - character(2, GETFIELD(inst, 12, 17))); - break; - - case VECTOR: - escape = TESTBIT(inst, 0); - if (vector(TESTBIT(inst, 1), - TESTBIT(inst, 2), GETFIELD(inst, 3, 9), - TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { - /* XXX interrupt? */ - } - break; - case VCONT: - escape = TESTBIT(inst, 0); - if (vector(TESTBIT(inst, 1), - TESTBIT(inst, 2), GETFIELD(inst, 3, 9), - TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { - /* XXX set escape? */ - mode = PARAM; /* raster violation */ - } - break; - - case INCR: - escape = TESTBIT(inst, 0); /* escape bit */ - i = TESTBIT(inst, 1); - - if (ipoint(i, 0, GETFIELD(inst, 2, 5)) || - ipoint(i, 1, GETFIELD(inst, 6, 9)) || - ipoint(i, 2, GETFIELD(inst, 10, 13)) || - ipoint(i, 3, GETFIELD(inst, 14, 17))) - /* XXX set escape? */ - mode = PARAM; /* raster violation */ - break; - - case SUBR: - /* type 347 Display Subroutine Option? */ - - mode = GETFIELD(inst, 2, 4); - /* XXX take high bits of current DAC? */ - addr = GETFIELD(inst, 5, 17); - - switch (GETFIELD(inst, 0, 1)) { - case DJS: /* display jump and save */ - ASR = DAC; - save_ff = 1; /* set "save" flip-flop */ - /* FALL */ - case DJP: /* display jump */ - DAC = addr; - break; - case DDS: /* display deposit save register */ - ty340_deposit(addr, (DJP<<16) | ASR); - save_ff = 0; /* ?? */ - break; - default: - /* XXX ??? */ - break; - } - break; - } - - if (escape) { - mode = PARAM; - if (save_ff) { - /* return from subroutine */ - DAC = ASR; - save_ff = 0; - } - } - return status; -} /* ty340_cycle */ +/* + * $Id: type340.c,v 1.6 2005/01/14 18:58:00 phil Exp $ + * Simulator Independent DEC Type 340 Graphic Display Processor Simulation + * Phil Budne + * September 20, 2003 + * from vt11.c + * + * Information from DECUS 7-13 + * http://www.spies.com/~aek/pdf/dec/pdp7/7-13_340displayProgMan.pdf + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the author shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#include "xy.h" /* XY plot interface */ + +/* + * The Type 340 was used on the PDP-{4,6,7,9,10} + * and used 18-bit words, with bits numbered 0 thru 17 + * (most significant to least) + */ + +#define BITMASK(N) (1<<(17-(N))) + +/* mask for a field */ +#define FIELDMASK(START,END) ((1<<((END)-(START)+1))-1) + +/* extract a field */ +#define GETFIELD(W,START,END) (((W)>>(17-(END)))&FIELDMASK(START,END)) + +/* extract a 1-bit field */ +#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0) + +#ifdef DEBUG_TY340 +#define DEBUGF(X) printf X +#else +#define DEBUGF(X) +#endif + +typedef long ty340word; + +static ty340word DAC; /* Display Address Counter */ +static unsigned char shift; /* 1 bit */ +static enum mode mode; /* 3 bits */ +static int scale; /* 2 bits */ + +enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR }; + +enum jump_type { DJP=2, DJS=3, DDS=1 }; +static ty340word ASR; /* Address Save Register */ +static unsigned char save_ff; /* "save" flip-flop */ + +static unsigned char intensity; /* 3 bits */ +static unsigned char lp_ena; /* 1 bit */ + +/* kept signed for raster violation checking */ +static short xpos, ypos; /* 10 bits, signed */ +static unsigned char sequence; /* 2 bits */ + +/* XXX make defines public for 340_cycle return */ +#define STOPPED 01 +#define LPHIT 02 +#define VEDGE 04 +#define HEDGE 010 +static unsigned char status = STOPPED; + +/* + * callbacks into PDP-6/10 simulator + */ +extern ty340word ty340_fetch(ty340word); +extern void ty340_store(ty340word, ty340word); +extern void ty340_stop_int(void); +extern void ty340_lp_int(void); + +void +ty340_set_dac(ty340word addr) +{ + DAC = addr; + mode = 0; + DEBUGF(("set DAC %06\r\n", DAC)); + status = 0; /* XXX just clear stopped? */ + /* XXX clear other stuff? save_ff? */ +} + +void +ty340_reset(void) +{ + /* XXX call display layer? destroy window? */ + xpos = ypos = 0; + status = STOPPED; +} + +static int +point(int x, int y, int seq) +{ + int i; + + /* XXX apply scale? */ + + i = DISPLAY_INT_MAX-7+intensity; + if (i <= 0) + i = 1; + + if (x < 0 || x > 1023) { + status |= VEDGE; + return 0; + } + if (y < 0 || y > 1023) { + status |= HEDGE; + return 0; + } + + if (display_point(x, y, i, 0)) { + if (lp_ena) { + /* XXX save location? */ + status |= LPHIT; + sequence = seq; + } + } +} + +/* + * two-step algorithm, developed by Xiaolin Wu + * from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html + */ + +/* + * The two-step algorithm takes the interesting approach of treating + * line drawing as a automaton, or finite state machine. If one looks + * at the possible configurations for the next two pixels of a line, + * it is easy to see that only a finite set of possibilities exist. + * The two-step algorithm shown here also exploits the symmetry of + * line-drawing by simultaneously drawn from both ends towards the + * midpoint. + */ + +static void +lineTwoStep(int x0, int y0, int x1, int y1) +{ + int dy = y1 - y0; + int dx = x1 - x0; + int stepx, stepy; + + if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } + if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } + + lpoint(x0,y0); + if (dx == 0 && dy == 0) /* following algorithm won't work */ + return; /* just the one dot */ + lpoint(x1, y1); + if (dx > dy) { + int length = (dx - 1) >> 2; + int extras = (dx - 1) & 3; + int incr2 = (dy << 2) - (dx << 1); + if (incr2 < 0) { + int c = dy << 1; + int incr1 = c << 1; + int d = incr1 - dx; + int i; + + for (i = 0; i < length; i++) { + x0 += stepx; + x1 -= stepx; + if (d < 0) { /* Pattern: */ + lpoint(x0, y0); + lpoint(x0 += stepx, y0); /* x o o */ + lpoint(x1, y1); + lpoint(x1 -= stepx, y1); + d += incr1; + } + else { + if (d < c) { /* Pattern: */ + lpoint(x0, y0); /* o */ + lpoint(x0 += stepx, y0 += stepy); /* x o */ + lpoint(x1, y1); + lpoint(x1 -= stepx, y1 -= stepy); + } else { + lpoint(x0, y0 += stepy); /* Pattern: */ + lpoint(x0 += stepx, y0); /* o o */ + lpoint(x1, y1 -= stepy); /* x */ + lpoint(x1 -= stepx, y1); + } + d += incr2; + } + } + if (extras > 0) { + if (d < 0) { + lpoint(x0 += stepx, y0); + if (extras > 1) lpoint(x0 += stepx, y0); + if (extras > 2) lpoint(x1 -= stepx, y1); + } else + if (d < c) { + lpoint(x0 += stepx, y0); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1 -= stepx, y1); + } else { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0); + if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); + } + } + } else { + int c = (dy - dx) << 1; + int incr1 = c << 1; + int d = incr1 + dx; + int i; + for (i = 0; i < length; i++) { + x0 += stepx; + x1 -= stepx; + if (d > 0) { + lpoint(x0, y0 += stepy); /* Pattern: */ + lpoint(x0 += stepx, y0 += stepy); /* o */ + lpoint(x1, y1 -= stepy); /* o */ + lpoint(x1 -= stepx, y1 -= stepy); /* x */ + d += incr1; + } else { + if (d < c) { + lpoint(x0, y0); /* Pattern: */ + lpoint(x0 += stepx, y0 += stepy); /* o */ + lpoint(x1, y1); /* x o */ + lpoint(x1 -= stepx, y1 -= stepy); + } else { + lpoint(x0, y0 += stepy); /* Pattern: */ + lpoint(x0 += stepx, y0); /* o o */ + lpoint(x1, y1 -= stepy); /* x */ + lpoint(x1 -= stepx, y1); + } + d += incr2; + } + } + if (extras > 0) { + if (d > 0) { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); + } else if (d < c) { + lpoint(x0 += stepx, y0); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1 -= stepx, y1); + } else { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0); + if (extras > 2) { + if (d > c) + lpoint(x1 -= stepx, y1 -= stepy); + else + lpoint(x1 -= stepx, y1); + } + } + } + } + } else { + int length = (dy - 1) >> 2; + int extras = (dy - 1) & 3; + int incr2 = (dx << 2) - (dy << 1); + if (incr2 < 0) { + int c = dx << 1; + int incr1 = c << 1; + int d = incr1 - dy; + int i; + for (i = 0; i < length; i++) { + y0 += stepy; + y1 -= stepy; + if (d < 0) { + lpoint(x0, y0); + lpoint(x0, y0 += stepy); + lpoint(x1, y1); + lpoint(x1, y1 -= stepy); + d += incr1; + } else { + if (d < c) { + lpoint(x0, y0); + lpoint(x0 += stepx, y0 += stepy); + lpoint(x1, y1); + lpoint(x1 -= stepx, y1 -= stepy); + } else { + lpoint(x0 += stepx, y0); + lpoint(x0, y0 += stepy); + lpoint(x1 -= stepx, y1); + lpoint(x1, y1 -= stepy); + } + d += incr2; + } + } + if (extras > 0) { + if (d < 0) { + lpoint(x0, y0 += stepy); + if (extras > 1) lpoint(x0, y0 += stepy); + if (extras > 2) lpoint(x1, y1 -= stepy); + } else + if (d < c) { + lpoint(x0, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1, y1 -= stepy); + } else { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0, y0 += stepy); + if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); + } + } + } else { + int c = (dx - dy) << 1; + int incr1 = c << 1; + int d = incr1 + dy; + int i; + for (i = 0; i < length; i++) { + y0 += stepy; + y1 -= stepy; + if (d > 0) { + lpoint(x0 += stepx, y0); + lpoint(x0 += stepx, y0 += stepy); + lpoint(x1 -= stepy, y1); + lpoint(x1 -= stepx, y1 -= stepy); + d += incr1; + } else { + if (d < c) { + lpoint(x0, y0); + lpoint(x0 += stepx, y0 += stepy); + lpoint(x1, y1); + lpoint(x1 -= stepx, y1 -= stepy); + } else { + lpoint(x0 += stepx, y0); + lpoint(x0, y0 += stepy); + lpoint(x1 -= stepx, y1); + lpoint(x1, y1 -= stepy); + } + d += incr2; + } + } + if (extras > 0) { + if (d > 0) { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy); + } else if (d < c) { + lpoint(x0, y0 += stepy); + if (extras > 1) lpoint(x0 += stepx, y0 += stepy); + if (extras > 2) lpoint(x1, y1 -= stepy); + } else { + lpoint(x0 += stepx, y0 += stepy); + if (extras > 1) lpoint(x0, y0 += stepy); + if (extras > 2) { + if (d > c) + lpoint(x1 -= stepx, y1 -= stepy); + else + lpoint(x1, y1 -= stepy); + } + } + } + } + } +} /* lineTwoStep */ + +static int +vector(int i, int sx, int dx, int sy, int dy) +{ + int x0, y0, x1, y1; + + x0 = xpos; + y0 = ypos; + + if (sx) { + x1 = x0 - dx; + if (x1 < 0) /* XXX TEMP? */ + x1 = 0; + } + else { + x1 = x0 + dx; + if (x1 > 1023) /* XXX TEMP? */ + x1 = 1023; + } + + if (sy) { + y1 = y0 - dy; + if (y1 < 0) /* XXX TEMP? */ + y1 = 0; + } + else { + y1 = y0 + dy; /* XXX TEMP? */ + if (y1 > 1023) + y1 = 1023; + } + + DEBUGF(("vector i%d (%d,%d) to (%d,%d)\r\n", i, x0, y0, x1, y1)); + if (i) + lineTwoStep(x0, y0, x1, y1); + + xpos = x1; + ypos = y1; + return 0; +} + +/* return true on raster violation */ +int +ipoint(int i, int n, unsigned char byte) +{ + if (byte & 010) { /* left/right */ + if (byte & 04) { + if (xpos == 0) { + status |= VEDGE; + return 1; + } + xpos--; + } + else { + if (xpos == 1023) { + status |= VEDGE; + return 1; + } + xpos++; + } + } + if (byte & 02) { /* up/down */ + if (byte & 04) { + if (ypos == 0) { + status |= HEDGE; + return 1; + } + ypos--; + } + else { + if (ypos == 1023) { + status |= HEDGE; + return 1; + } + ypos++; + } + } + if (i) + point(xpos, ypos, n); + + return 0; +} + +/* + * 342 character generator - first 64 characters (from manual) + */ +static const unsigned char chars[64][5] = { + { 0070, 0124, 0154, 0124, 0070 }, /* 00 */ + { 0174, 0240, 0240, 0240, 0174 }, /* 01 A */ + { 0376, 0222, 0222, 0222, 0154 }, /* 02 B */ + { 0174, 0202, 0202, 0202, 0104 }, /* 03 C */ + { 0376, 0202, 0202, 0202, 0174 }, /* 04 D */ + { 0376, 0222, 0222, 0222, 0222 }, /* 05 E */ + { 0376, 0220, 0220, 0220, 0220 }, /* 06 F */ + { 0174, 0202, 0222, 0222, 0134 }, /* 07 G */ + { 0376, 0020, 0020, 0020, 0376 }, /* 10 H */ + { 0000, 0202, 0376, 0202, 0000 }, /* 11 I */ + { 0004, 0002, 0002, 0002, 0374 }, /* 12 J */ + { 0376, 0020, 0050, 0104, 0202 }, /* 13 K */ + { 0376, 0002, 0002, 0002, 0002 }, /* 14 K */ + { 0374, 0100, 0040, 0100, 0374 }, /* 15 M */ + { 0376, 0100, 0040, 0020, 0376 }, /* 16 N */ + { 0174, 0202, 0202, 0202, 0174 }, /* 17 O */ + { 0376, 0220, 0220, 0220, 0140 }, /* 20 P */ + { 0174, 0202, 0212, 0206, 0176 }, /* 21 Q */ + { 0376, 0220, 0230, 0224, 0142 }, /* 22 R */ + { 0144, 0222, 0222, 0222, 0114 }, /* 23 S */ + { 0200, 0200, 0376, 0200, 0200 }, /* 24 T */ + { 0374, 0002, 0002, 0002, 0374 }, /* 25 U */ + { 0370, 0004, 0002, 0004, 0370 }, /* 26 V */ + { 0376, 0004, 0010, 0004, 0376 }, /* 27 W */ + { 0202, 0104, 0070, 0104, 0202 }, /* 30 X */ + { 0200, 0100, 0076, 0100, 0200 }, /* 31 Y */ + { 0226, 0232, 0222, 0262, 0322 }, /* 32 Z */ + { 0000, 0000, 0000, 0000, 0000 }, /* 33 LF */ + { 0000, 0000, 0000, 0000, 0000 }, /* 34 CR */ + { 0000, 0000, 0000, 0000, 0000 }, /* 35 HORIZ */ + { 0000, 0000, 0000, 0000, 0000 }, /* 36 VERT */ + { 0000, 0000, 0000, 0000, 0000 }, /* 37 ESC */ + { 0000, 0000, 0000, 0000, 0000 }, /* 40 space */ + { 0000, 0000, 0372, 0000, 0000 }, /* 41 ! */ + { 0000, 0340, 0000, 0340, 0000 }, /* 42 " */ + { 0050, 0376, 0050, 0376, 0050 }, /* 43 # */ + { 0144, 0222, 0376, 0222, 0114 }, /* 44 $ */ + { 0306, 0310, 0220, 0246, 0306 }, /* 45 % */ + { 0154, 0222, 0156, 0004, 0012 }, /* 46 & */ + { 0000, 0000, 0300, 0340, 0000 }, /* 47 ' */ + { 0070, 0104, 0202, 0000, 0000 }, /* 50 ( */ + { 0000, 0000, 0202, 0104, 0070 }, /* 51 ) */ + { 0124, 0070, 0174, 0070, 0124 }, /* 52 * */ + { 0020, 0020, 0174, 0020, 0020 }, /* 53 + */ + { 0000, 0014, 0016, 0000, 0000 }, /* 54 , */ + { 0020, 0020, 0020, 0020, 0020 }, /* 55 - */ + { 0000, 0006, 0006, 0000, 0000 }, /* 56 . */ + { 0004, 0010, 0020, 0040, 0100 }, /* 57 / */ + { 0174, 0212, 0222, 0242, 0174 }, /* 60 0 */ + { 0000, 0102, 0376, 0002, 0000 }, /* 61 1 */ + { 0116, 0222, 0222, 0222, 0142 }, /* 62 2 */ + { 0104, 0202, 0222, 0222, 0154 }, /* 63 3 */ + { 0020, 0060, 0120, 0376, 0020 }, /* 64 4 */ + { 0344, 0222, 0222, 0222, 0214 }, /* 65 5 */ + { 0174, 0222, 0222, 0222, 0114 }, /* 66 6 */ + { 0306, 0210, 0220, 0240, 0300 }, /* 67 7 */ + { 0154, 0222, 0222, 0222, 0154 }, /* 70 8 */ + { 0144, 0222, 0222, 0222, 0174 }, /* 71 9 */ + { 0000, 0066, 0066, 0000, 0000 }, /* 72 : */ + { 0000, 0154, 0156, 0000, 0000 }, /* 73 ; */ + { 0020, 0050, 0104, 0202, 0000 }, /* 74 < */ + { 0050, 0050, 0050, 0050, 0050 }, /* 75 = */ + { 0000, 0202, 0104, 0050, 0020 }, /* 76 > */ + { 0100, 0200, 0236, 0220, 0140 } /* 77 ? */ +}; + +/* + * type 342 Character/Symbol generator for type 340 display + * return true if ESCaped + */ +static int +character(int n, char c) +{ + int x, y; + + switch (c) { + case 033: /* LF */ + if (ypos < 12) { + status |= HEDGE; + ypos = 0; + } + else + ypos -= 12; /* XXX scale? */ + + return 0; + case 034: /* CR */ + xpos = 0; + return 0; + case 035: /* shift in */ + shift = 1; + return 0; + case 036: /* shift out */ + shift = 0; + return 0; + case 037: /* escape */ + sequence = n; + return 1; + } + /* XXX plot character from character set selected by "shift" + * (offset index by 64?) + */ + for (x = 0; x < 5; x++) { + for (y = 0; y < 7; y++) { + if (chars[c][x] & (1< 1023) { + xpos = 1023; + status |= VEDGE; + } + return 0; +} + +int +ty340_cycle(int us, int slowdown) +{ + ty340word inst, addr; + int i, escape, stopped; + + if (status & STOPPED) + return 0; /* XXX age display? */ + + inst = ty340_fetch(DAC); + DEBUGF(("%06o: %06o\r\n", DAC, inst)); + DAC++; + + escape = 0; + switch (mode) { + case PARAM: + mode = GETFIELD(inst, 2, 4); + + if (TESTBIT(inst, 5)) { /* load l.p. enable */ + lp_ena = TESTBIT(inst,6); + DEBUGF(("lp_ena %d\r\n", lp_ena)); + } + + if (TESTBIT(inst, 7)) { + status |= STOPPED; + if (TESTBIT(inst, 8)) + ty340_stop_int(); /* set stop_int_end? */ + } + + if (TESTBIT(inst, 11)) + scale = GETFIELD(inst, 12, 13); + + if (TESTBIT(inst, 14)) + intensity = GETFIELD(inst, 15, 17); + + break; + + case POINT: + mode = GETFIELD(inst, 2, 4); + + if (TESTBIT(inst, 5)) /* load l.p. enable */ + lp_ena = TESTBIT(inst,6); + + if (TESTBIT(inst, 1)) + ypos = GETFIELD(inst, 8, 17); + else + xpos = GETFIELD(inst, 8, 17); + + if (TESTBIT(inst, 7)) + point(xpos, ypos, 0); + break; + + case SLAVE: + mode = GETFIELD(inst, 2, 4); + break; + + case CHAR: + escape = (character(0, GETFIELD(inst, 0, 5)) || + character(1, GETFIELD(inst, 6, 11)) || + character(2, GETFIELD(inst, 12, 17))); + break; + + case VECTOR: + escape = TESTBIT(inst, 0); + if (vector(TESTBIT(inst, 1), + TESTBIT(inst, 2), GETFIELD(inst, 3, 9), + TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { + /* XXX interrupt? */ + } + break; + case VCONT: + escape = TESTBIT(inst, 0); + if (vector(TESTBIT(inst, 1), + TESTBIT(inst, 2), GETFIELD(inst, 3, 9), + TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { + /* XXX set escape? */ + mode = PARAM; /* raster violation */ + } + break; + + case INCR: + escape = TESTBIT(inst, 0); /* escape bit */ + i = TESTBIT(inst, 1); + + if (ipoint(i, 0, GETFIELD(inst, 2, 5)) || + ipoint(i, 1, GETFIELD(inst, 6, 9)) || + ipoint(i, 2, GETFIELD(inst, 10, 13)) || + ipoint(i, 3, GETFIELD(inst, 14, 17))) + /* XXX set escape? */ + mode = PARAM; /* raster violation */ + break; + + case SUBR: + /* type 347 Display Subroutine Option? */ + + mode = GETFIELD(inst, 2, 4); + /* XXX take high bits of current DAC? */ + addr = GETFIELD(inst, 5, 17); + + switch (GETFIELD(inst, 0, 1)) { + case DJS: /* display jump and save */ + ASR = DAC; + save_ff = 1; /* set "save" flip-flop */ + /* FALL */ + case DJP: /* display jump */ + DAC = addr; + break; + case DDS: /* display deposit save register */ + ty340_deposit(addr, (DJP<<16) | ASR); + save_ff = 0; /* ?? */ + break; + default: + /* XXX ??? */ + break; + } + break; + } + + if (escape) { + mode = PARAM; + if (save_ff) { + /* return from subroutine */ + DAC = ASR; + save_ff = 0; + } + } + return status; +} /* ty340_cycle */ diff --git a/display/vt11.c b/display/vt11.c index 7dddadb0..dd52e549 100644 --- a/display/vt11.c +++ b/display/vt11.c @@ -1,3148 +1,3772 @@ -/* - * $Id: vt11.c,v 1.19 2004/02/07 06:38:12 phil Exp $ - * Simulator Independent VT11/VS60 Graphic Display Processor Simulation - * Started by Phil Budne September 13, 2003 - * Substantially revised by Douglas A. Gwyn, 05 Feb. 2004 - * - * from EK-VT11-TM-001, September 1974 - * and EK-VT48-TM-001, November 1976 - * with help from Al Kossow's "VT11 instruction set" posting of 21 Feb 93 - * and VT48 Engineering Specification Rev B - * and VS60 diagnostic test listings, provided by Alan Frisbie - * - * The VT11 is a calligraphic display-file device used in the GT4x series - * of workstations (PDP-11/04,34,40 based). - * - * The VS60 is an improved, extended, upward-compatible version of the - * VT11, used in the GT62 workstation (PDP-11/34 based). It supported - * dual consoles (CRTs with lightpens), multiple phosphor colors, 3D - * depth cueing, and circle/arc generator as options. We do not know - * whether any of these options were ever implemented or delivered. - * XXX VS60 depth-cueing option not yet fully implemented - * - * The VSV11/VS11 is a color raster display-file device (with joystick - * instead of light pen) with instructions similar to the VT11's but - * different enough that a separate emulation should be created by - * editing a copy of this source file rather than trying to hack it into - * this one. Very likely, the display (phosphor decay) simulation will - * also require revision to handle multiple colors. - * - * A PDP-11 system has at most one display controller attached. - * In principle, a VT11 or VS60 can also be used on a VAX Unibus. - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#ifdef DEBUG_VT11 -#include -#endif -#include /* memset */ -#ifndef NO_CONIC_OPT -#include /* atan2, cos, sin, sqrt */ -#endif - -#include "display.h" /* XY plot interface */ -#include "vt11.h" - -#define BITMASK(n) (1<<(n)) /* PDP-11 bit numbering */ - -/* mask for a field */ -#define FIELDMASK(START,END) ((1<<((START)-(END)+1))-1) - -/* extract a field */ -#define GETFIELD(W,START,END) (((W)>>(END)) & FIELDMASK(START,END)) - -/* extract a 1-bit field */ -#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0) - -#ifdef DEBUG_VT11 -#define DEBUGF(X) do { printf X; fflush(stdout); } while (0) -#else -#define DEBUGF(X) -#endif - -/* - * Note about coordinate signedness and wrapping: - * - * There is a discrepancy between the documentation and the known or suspected - * behavior of these devices. The VT11 manual says it wraps 12-bit position - * coordinates independently of sign (4097 -> 1), but then it doesn't mention - * any sign for X,Y position registers, yet we think that graphics is properly - * tracked in the negative domain. The VS60 manual says it wraps from 4097 to - * -4095, but there is no evidence of this in the manual's diagrams, and the - * absolute-point graphic data format doesn't show signs for X,Y coordinates. - * Most likely, both devices have signed position coordinates (either sign- - * magnitude or twos-complement) and merely drop bits that overflow. - * - * At one point this simulation attempted to implement position wrapping, but - * because it adds overhead, has uncertain characteristics, and should never - * be exploited by any application anyway, now no wrapping is done, and the - * position is tracked using at least 32 bits including sign. - * - * Note about scaling and offsets: - * - * The VS60 supports character and vector scaling and position offsets. The - * X, Y, and Z position register values always include scaling and offsets. - * It is not clear from the manual whether or not there are two "guard bits", - * which would better track the virtual position when using a scale factor of - * 3/4, 1/2, or 1/4. Most likely, there are no guard bits. This simulation - * maintains position values and offsets both multiplied by PSCALEF, which - * should be 4 to obtain maximum drawing precision, or 1 to mimic non-guard-bit - * display hardware. These internal coordinates are "normalized" (converted to - * correct virtual CRT coordinates) before being reported via the position/ - * offset registers. The normalized Z position register value's 2 lowest bits - * are always 0. - * Example of why this matters: Set vector scale 1/2; draw successive vectors - * with delta X = 1, 1, and -2. With guard bits, the final and original X - * positions are the same; without guard bits, the final X position is one - * unit to the left of the original position. This effect accumulates over a - * long sequence of vectors, leading to quite visible distortion of the image. - * - * Light-pen and edge-interrupt positions always have "on-screen" values. - */ - -#ifndef PSCALEF -#if 1 /* XXX temporary during development, to catch any oversights */ -#define PSCALEF 4 /* position scale factor 4 for maximum precision */ -#else -#define PSCALEF 1 /* position scale factor 1 for accurate simulation */ -#endif -#endif - -#define PSCALE(x) ((x) * PSCALEF) -#define PNORM(x) ((x) / PSCALEF) -/* virtual_CRT_coordinate = PNORM(scaled_value) */ - -/* VS60 scales points/vectors and characters separately */ -#define VSCALE(x) (PSCALE(vector_scale * (int32)(x)) / 4) -#define CSCALE(x) (PSCALE(char_scale * (int32)(x)) / 4) - -#define ABS(x) ((x) >= 0 ? (x) : -(x)) - -enum display_type vt11_display = DISPLAY_TYPE; /* DIS_VR{14,17,48} */ -int vt11_scale = PIX_SCALE; /* RES_{FULL,HALF,QUARTER,EIGHTH} */ -unsigned char vt11_init = 0; /* set after display_init() called */ -#define INIT { if (!vt11_init) { display_init(vt11_display, vt11_scale); \ - vt11_init = 1; vt11_reset(); } } - -/* state visible to host */ - -/* The register and field names are those used in the VS60 manual (minus the - trailing "flag", "code", "status", or "select"); the VT11 manual uses - somewhat different names. */ - -/* - * Display Program Counter - * Read/Write (reading returns the *relocated* DPC bits [15:0]) - * DPC address 15:1 - * resume 0 - */ -#define DPC sp->_dpc /* Display PC (always even) */ -static uint16 bdb = 0; /* Buffered Data Bits register; - see comment in vt11_get_dpc() */ - -/* - * Mode Parameter Register - * Read Only, except that writing to it beeps the LK40 keyboard's bell - * internal stop flag 15 - * graphic mode code 14:11 - * intensity level 10:8 - * LP con. 0 hit flag 7 - * shift out status 6 - * edge indicator 5 - * italics status 4 - * blink status 3 - * edge flag status 2 (VS60 only) - * line type register status 1:0 - */ -static unsigned char internal_stop = 0; /* 1 bit: stop display */ - -#define graphic_mode sp->_mode /* 4 bits: sets type for graphic data */ -enum mode { CHAR=0, SVECTOR, LVECTOR, POINT, GRAPHX, GRAPHY, RELPOINT, /* all */ - BSVECT, CIRCLE, ABSVECTOR /* VS60 only */ -}; - -#define intensity sp->_intens /* 3 bits: 0 => dim .. 7 => bright */ -static unsigned char lp0_flag = 0; /* 1 bit: light pen #0 detected hit */ -#define shift_out sp->_so /* 1 bit: chars using shift-out codes */ -static unsigned char edge_indic = 0; /* 1 bit: end pt outside visible area; - on-to-off transition only! */ -#define italics sp->_italics /* 1 bit: use italic font */ -#define blink_ena sp->_blink /* 1 bit: blink graphic item */ -static unsigned char edge_flag = 0; /* 1 bit: any edge transition (VS60) */ -#define line_type sp->_ltype /* 2 bits: style for drawing vectors */ -enum linetype { SOLID=0, LONG_DASH, SHORT_DASH, DOT_DASH }; - -/* - * Graphplot Increment and X Position Register - * Read Only - * graphplot increment register value 15:10 - * X position register value 9:0 - */ -static unsigned char graphplot_step = 0;/* (scaled) graphplot step increment */ -static int32 xpos = 0; /* X position register * PSCALEF */ - /* note: offset has been applied! */ -static int lp_xpos; /* (normalized) */ -static int edge_xpos; /* (normalized) */ - -/* - * Character Code and Y Position Register - * Read Only - * character register contents 15:10 - * Y position register value 9:0 - */ -static unsigned char char_buf = 0; /* (only lowest 6 bits reported) */ -static int32 ypos = 0; /* Y position register * PSCALEF */ - /* note: offset has been applied! */ -static int lp_ypos; /* (normalized) */ -static int edge_ypos; /* (normalized) */ - -/* - * Relocate Register (VS60 only) - * Read/Write - * spare 15:12 - * relocate register value[17:6] 11:0 - */ -static uint32 reloc = 0; /* relocation, aligned with DPC */ - -/* - * Status Parameter Register (VS60 only) - * Read Only, except for bit 7 (1 => external stop request) - * display busy status 15 - * stack overflow status 13 - * stack underflow status 12 - * time out status 11 - * char. rotate status 10 - * char. scale index 9:8 - * external stop flag 7 - * menu status 6 - * relocated DPC bits [17:16] 5:4 - * vector scale 3:0 - */ -#define busy (!(internal_stop || ext_stop || lphit_irq || lpsw_irq || edge_irq \ - || char_irq || stack_over || stack_under || time_out || name_irq)) - /* 1 bit: display initiated | resumed */ -static unsigned char stack_over = 0; /* 1 bit: "push" with full stack */ -static unsigned char stack_under = 0; /* 1 bit: "pop" with empty stack */ -static unsigned char time_out = 0; /* 1 bit: timeout has occurred */ -#define char_rotate sp->_crotate /* 1 bit: rotate chars 90 degrees CCW */ -#define cs_index sp->_csi /* character scale index 0..3 */ -static unsigned char ext_stop = 0; /* 1 bit: stop display */ -#define menu sp->_menu /* 1 bit: VS60 graphics in menu area */ -#define vector_scale sp->_vscale /* non-character scale factor * 4 */ - -/* - * X Offset Register (VS60 only) - * Read/Write - * upper X position bits 15:12 (read) - * sign of X dynamic offset 13 (write) - * X dynamic offset 11:0 - */ -static unsigned char s_xoff = 0; /* sign bit for xoff (needed for -0) */ -static int32 xoff = 0; /* X offset register * PSCALEF */ - -/* - * Y Offset Register (VS60 only) - * Read/Write - * upper Y position bits 15:12 (read) - * sign of Y dynamic offset 13 (write) - * Y dynamic offset 11:0 - */ -static unsigned char s_yoff = 0; /* sign bit for yoff (needed for -0) */ -static int32 yoff = 0; /* Y offset register * PSCALEF */ - -/* - * Associative Name Register (VS60 only) - * Write Only - * search code change enable 14 - * search code 13:12 - * name change enable 11 - * associative name 10:0 - */ -static unsigned char search = 0; /* 00=> no search, no interrupt - 01 => intr. on 11-bit compare - 10 => intr. on high-8-bit compare - 11 => intr. on high-4-bit compare */ -static unsigned assoc_name = 0; /* compare value */ - -/* - * Slave Console/Color Register (VS60 only) - * Read/Write * - * inten enable con. 0 15 - * light pen hit flag con. 0 14 * - * LP switch on flag con. 0 13 * - * LP switch off flag con. 0 12 * - * LP flag intr. enable con. 0 11 - * LP switch flag intr. enable con. 0 10 - * inten enable con. 1 9 - * light pen hit flag con. 1 8 * - * LP switch on flag con. 1 7 * - * LP switch off flag con. 1 6 * - * LP flag intr. enable con. 1 5 - * LP switch flag intr. enable con. 1 4 - * color 3:2 - * - * * indicates that maintenance switch 3 must be set to write these bits; - * the other bits are not writable at all - */ -#define int0_scope sp->_inten0 /* enable con. 0 for all graphic data */ -/* lp0_flag has already been defined, under Mode Parameter Register */ -#define lp0_sw display_lp_sw /* (defined in display.c) */ -#define lp0_intr_ena sp->_lp0intr /* generate interrupt on LP #0 hit */ -#define lp0_sw_intr_ena sp->_lp0swintr /* generate intr. on LP #0 switch chg */ -#define int1_scope sp->_inten1 /* enable con. 1 for all graphic data */ -/* following 2 flags only mutable via writing this register w/ MS3 set: */ -static unsigned char lp1_flag = 0; /* 1 bit: light pen #1 detected hit */ -static unsigned char lp1_sw = 0; /* 1 bit: LP #1 switch changed state */ -#define lp1_intr_ena sp->_lp1intr /* generate interrupt on LP #1 hit */ -#define lp1_sw_intr_ena sp->_lp1swintr /* generate intr. on LP #1 switch chg */ - -enum scolor { GREEN=0, YELLOW, ORANGE, RED }; -#define color sp->_color /* 2 bits: VS60 color option */ - -/* - * Name Register (VS60 only) - * Read Only - * name/assoc name match flag 15 - * search code 13:12 - * name 10:0 - */ -static unsigned char name_flag = 0; /* 1 bit: name matches associative nm */ -/* search previously defined, under Associative Name Register */ -#define name sp->_name /* current name from display file */ - -/* - * Stack Data Register (VS60 only) - * Read Only - * stack data 15:0 (as selected by Stk. Addr./Maint. Reg.) - * - * On the actual hardware there are 2 32-bit words per each of 8 stack levels. - * At the PDP-11 these appear to be 4 16-bit words ("stack bytes") per level. - */ -/* Two alternatives: keep active data in globals or use directly from stack. - The former is presumably more efficient when the stack isn't being used, - as in VT11 mode, but on most host processors the difference is small. - POPR is faster if we do not have to restore data to all those globals. - There are thus 9 levels of data, the initial state and 8 stacked sets. - Mimicking the actual hardware, the stack level *decreases* upon JSR. - */ - -static struct frame - { - vt11word _dpc; /* Display Program Counter (even) */ - unsigned _name; /* (11-bit) name from display file */ - enum mode _mode; /* 4 bits: sets type for graphic data */ - unsigned char _vscale; /* non-character scale factor * 4 */ - unsigned char _csi; /* character scale index 0..3 */ - unsigned char _cscale; /* character scale factor * 4 */ - unsigned char _crotate; /* rotate chars 90 degrees CCW */ - unsigned char _intens; /* intensity: 0 => dim .. 7 => bright */ - enum linetype _ltype; /* line type (long dash, etc.) */ - unsigned char _blink; /* blink enable */ - unsigned char _italics; /* italicize characters */ - unsigned char _so; /* chars are using shift-out codes */ - unsigned char _menu; /* VS60 graphics in menu area */ - unsigned char _cesc; /* perform POPR on char. term. match */ - unsigned char _edgeintr; /* generate intr. on edge transition */ - unsigned char _lp1swintr; /* generate intr. on LP #1 switch chg */ - unsigned char _lp0swintr; /* generate intr. on LP #0 switch chg */ - unsigned char _lp1intr; /* generate interrupt on LP #1 hit */ - unsigned char _inten1; /* blank cons. 1 for all graphic data */ - unsigned char _lp0intr; /* generate interrupt on LP #0 hit */ - unsigned char _inten0; /* blank cons. 0 for all graphic data */ - unsigned char _bright; /* visually indicate hit on entity */ - unsigned char _stopintr; /* generate interrupt on stop */ - enum scolor _color; /* scope display color (option) */ - unsigned char _zdata; /* flag: display file has Z coords */ - unsigned char _depth; /* flag: display Z using depth cue */ - } stack[9] = { { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, CHAR, 4, 1, 0, 4, SOLID, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, - }; -/* (stack pointer "sp" defined under Stack Address/Maintenance Register) */ - -#define char_scale sp->_cscale /* character scale factor * 4 */ -static const unsigned char csi2csf[4] = { 2, 4, 6, 8 }; /* maps cs_index to " */ -#define char_escape sp->_cesc /* perform POPR on char. term. match */ -#define edge_intr_ena sp->_edgeintr /* generate intr. on edge transition */ -#define lp_intensify sp->_bright /* if VT11, 20us bright spot; - if VS60, "bright down" the entity */ -#define stop_intr_ena sp->_stopintr /* generate intr. on internal stop */ -#define file_z_data sp->_zdata /* flag: display file has Z coords */ -#define depth_cue_proc sp->_depth /* flag: display Z using depth cue */ - -/* - * Character String Terminate Register (VS60 only) - * Read/Write - * char. term. reg. enable 7 - * character terminate code 6:0 - */ -static int char_term = 0; /* char. processing POPRs after this */ - -/* - * Stack Address/Maintenance Register (VS60 only) - * Read/Write - * maint. sw. 4 15 - * maint. sw. 3 14 - * maint. sw. 2 13 - * maint. sw. 1 12 - * offset mode status 10 - * jump to subr. ?rel. status 9 (diagnostic requires this be JSR abs.!) - * word 2 status 8 - * word 1 status 7 - * word 0 status 6 - * stack reset status 5 - * stack level select 4:2 (manual has this messed up) - * stack halfword select 1:0 (manual has this messed up) - */ -static unsigned char maint4 = 0; /* 1 bit: maintenance switch #4 */ -static unsigned char maint3 = 0; /* 1 bit: maintenance switch #3 */ -static unsigned char maint2 = 0; /* 1 bit: maintenance switch #2 */ -static unsigned char maint1 = 0; /* 1 bit: maintenance switch #1 */ -static unsigned char offset = 0; /* 1 bit: last data loaded offsets */ -static unsigned char jsr = 0; /* 1 bit: last control was JSR ?rel. */ -static unsigned char word_number = 0; /* tracks multiple data words etc. */ -static struct frame *sp = &stack[8]; -#define STACK_EMPTY (sp == &stack[8]) -#define STACK_FULL (sp == stack) -static unsigned char stack_sel = 8<<2; /* 8 levels, 4 PDP-11 words per level */ - /* stack_sel must track sp! */ - -/* - * Z Position Register, Depth Cue Option (VS60 only) - * Read/Write - * Z position register value[13:2] 11:0 - */ -static int32 zpos = 0; /* (Z "position" reg. * 4) * PSCALEF */ - /* note: offset has been applied! */ -static int32 lp_zpos; /* (scaled) */ -static int32 edge_zpos; /* (scaled) */ - -/* - * Z Offset Register, Depth Cue Option (VS60 only) - * Read/Write - * sign of X dynamic offset 15 (read) (VT48 manual has this confused) - * sign of Y dynamic offset 14 (read) (VT48 manual has this confused) - * sign of Z dynamic offset 13 - * Z dynamic offset 11:0 - */ -static unsigned char s_zoff = 0; /* sign bit for zoff (needed for -0) */ -static int32 zoff = 0; /* Z offset register * PSCALEF */ - -/* - * Invisible state: - */ -static unsigned char char_irq = 0; /* intr. on illegal char in SO mode */ -static unsigned char lphit_irq = 0; /* intr. on light-pen hit */ -static unsigned char lpsw_irq = 0; /* intr. on tip-switch state change */ -static unsigned char edge_irq = 0; /* intr. on edge transition */ -static unsigned char name_irq = 0; /* intr. on name match */ - -static unsigned char lp0_sw_state = 0; /* track light-pen tip-switch state */ -static unsigned char blink_off = 0; /* set when blinking graphics is dark */ -static unsigned char finish_jmpa = 0; /* reminder to fetch JMPA address */ -static unsigned char finish_jsra = 0; /* reminder to fetch JSRA address */ - -static unsigned char more_vect = 0; /* remembers LP hit in middle of vec. */ -static unsigned char more_arc = 0; /* remembers LP hit in middle of arc */ -static int32 save_x0, save_y0, save_x1, save_y1;/* CRT coords for rest of vec */ - -static unsigned char lp_suppress = 0; /* edge columns of char. (VT11 only) */ -static unsigned char stroking = 0; /* set when drawing VS60 char strokes */ -static unsigned char skip_start = 0; /* set between vis. char./arc strokes */ - -static unsigned char sync_period = 0; /* frame sync period (msec) */ -static unsigned char refresh_rate = 0; /* 2 bits: - 00 => continuous display refresh - 01 => 30 fps (60 fps if VT11) - 10 => 40 fps (VS60) - 11 => external sync (VS60) */ - -#if 0 /* this is accurate in simulated "real" time */ -#define BLINK_COUNT 266 /* 266 milliseconds */ -#else /* this looks better in actual real time (adjust for your host speed) */ -#define BLINK_COUNT 67 /* 67 milliseconds */ -#endif - -unsigned char vt11_csp_w = VT11_CSP_W; /* horizontal character spacing */ -unsigned char vt11_csp_h = VT11_CSP_H; /* vertical character spacing */ - -/* VS60 has a menu area to the right of the "main working surface" */ -#define MENU_OFFSET (1024 + VR48_GUTTER) /* left edge of menu on CRT */ -#define VR48_WIDTH (MENU_OFFSET + 128) /* X beyond this is not illuminated */ - -static int reduce; /* CRT units per actual pixel */ -static int x_edge; /* 1023 or VR48_WIDTH-1, depending */ -static int y_edge; /* 767 or 1023, depending on display */ -#define ONCRT(x,y) ((x) >= 0 && (x) <= x_edge && (y) >= 0 && (y) <= y_edge) - -/* - * Uncertain whether VS60 edge transitions in menu area are flagged and whether - * clipping takes menu width into account. Three possibilities: - */ -#if 0 /* menu area never clipped (seems wrong) */ -#define ONSCREEN(x,y) (menu || ((x)>=0 && (x)<=1023 && (y)>=0 && (y)<=y_edge)) -#elif 0 /* menu area correctly clipped */ -#define ONSCREEN(x,y) ((x) >= 0 && (x) <= (menu ? 127 : 1023) \ - && (y) >= 0 && (y) <= y_edge) -#else /* menu area clipped same as main area */ -#define ONSCREEN(x,y) ((x) >= 0 && (x) <= 1023 && (y) >= 0 && (y) <= y_edge) - -#endif - -static void lineTwoStep(int32, int32, int32, int32); /* forward reference */ - -/* - * calls to read/write VT11/VS60 CSRs - * - * presumably the host looks at our state less often than we do(!) - * so we keep it in a form convenient to us! - */ - -int32 -vt11_get_dpc(void) -{ INIT - /* - * The VT48 manual says that Maintenance Switch 1 causes the Buffered - * Data Bits register to be "entered into the DPC" so it can be - * examined by reading the DPC address, but details of when and how - * often that happens are not provided. Examination of the diagnostic - * test listings show that relocation is applied and that only the DPC - * is involved when this switch is set. - */ - return ((maint1 ? bdb : DPC) + reloc) & 0177777; -} - -void -vt11_set_dpc(uint16 d) -{ INIT - bdb = d; /* save all bits in case maint1 used */ - DEBUGF(("set DPC 0%06o\r\n", (unsigned)d)); - if (!TESTBIT(d,0)) { - sp = &stack[8]; /* important! do this first */ - stack_sel = 8<<2; - DPC = d; /* load DPC */ - sync_period = 0; - ext_stop = 0; - /* the following seem reasonable, but might be wrong */ - finish_jmpa = finish_jsra = jsr = 0; - word_number = 0; -#if 0 /* probably accurate mimicry, but ugly behavior */ - if (edge_irq) { - xpos = PSCALE(edge_x); - ypos = PSCALE(edge_y); - } -#endif - } else { /* RESUME (after intr); DPC unchanged */ - /* if resuming from LP hit interrupt, finish drawing rest of vector */ - /* (if resuming from edge interrupt, vector is *not* drawn) */ - if (more_vect) { - unsigned char save_ena = lp0_intr_ena; - lp0_intr_ena = 0; /* one hit per vector is plenty */ - lphit_irq = 0; /* or else lineTwoStep aborts again! */ - /* line_counter is intact; draw rest of visible vector */ - lineTwoStep(save_x0, save_y0, save_x1, save_y1); - lp0_intr_ena = save_ena; - } - if (more_arc) { /* remainder of chord was just drawn */ - unsigned char save_ena = lp0_intr_ena; - lp0_intr_ena = 0; /* one hit per arc is plenty */ - lphit_irq = 0; /* or else lineTwoStep aborts again! */ - /* line_counter is intact; draw rest of visible arc */ - /*XXX not yet implemented [conic{23}() needed]*/ - lp0_intr_ena = save_ena; - } - if (!maint2) /* kludge to satify diagnostic test */ - ext_stop = 0; - } - internal_stop = time_out = stack_over = stack_under = 0; - more_vect = more_arc = stroking = skip_start = 0; - edge_indic = edge_flag = lp0_flag = lp1_flag = lp_suppress = 0; - char_irq = lphit_irq = lpsw_irq = edge_irq = name_irq = 0; - /* next vt11_cycle() will perform a fetch */ -} - -int32 -vt11_get_mpr(void) -{ - int32 ret; - INIT - ret = (internal_stop<<15) | (graphic_mode<<11) | (intensity<<8) | - (lp0_flag<<7) | (shift_out<<6) | (edge_indic<<5) | (italics<<4) | - (blink_ena<<3) | line_type; - - if (VS60) - ret |= edge_flag<<2; - - return ret; -} - -void -vt11_set_mpr(uint16 d) -{ INIT - /* beeps the "bell" on the LK40 keyboard */ -#if 0 /* probably doesn't hurt to do it for the VS60 also */ - if (VT11) /* according to the VS60 specs */ -#endif - display_beep(); -} - -int32 -vt11_get_xpr(void) -{ - int32 pos; - INIT - pos = lphit_irq ? lp_xpos : edge_irq ? edge_xpos : PNORM(xpos); - return (graphplot_step << 10) | GETFIELD(ABS(pos),9,0); -} - -void -vt11_set_xpr(uint16 d) -{ INIT - DEBUGF(("set XPR: no effect\r\n")); -} - -int32 -vt11_get_ypr(void) -{ - int32 pos; - INIT - pos = lphit_irq ? lp_ypos : edge_irq ? edge_ypos : PNORM(ypos); - return (GETFIELD(char_buf,5,0) << 10) | GETFIELD(ABS(pos),9,0); -} - -void -vt11_set_ypr(uint16 d) -{ INIT - DEBUGF(("set YPR: no effect\r\n")); -} - -/* All the remaining registers pertain to the VS60 only. */ - -int32 -vt11_get_rr(void) -{ INIT - return reloc >> 6; -} - -void -vt11_set_rr(uint16 d) -{ INIT - reloc = (uint32)GETFIELD(d,11,0) << 6; -} - -int32 -vt11_get_spr(void) -{ INIT - return (busy<<15) | (stack_over<<13) | (stack_under<<12) | (time_out<<11) | - (char_rotate<<10) | (cs_index<<8) | (ext_stop<<7) | - (menu<<6) | (((DPC + reloc) & 0600000L) >> 12) | vector_scale; -} - -void -vt11_set_spr(uint16 d) -{ INIT - ext_stop = TESTBIT(d,7); - - if (ext_stop /* && stop_intr_ena */)/* not maskable? */ - vt_stop_intr(); /* post stop interrupt to host */ - /* (asynchronous with display cycle) */ -} - -int32 -vt11_get_xor(void) -{ - int32 off, pos; - INIT - off = PNORM(xoff); - pos = lphit_irq ? lp_xpos : edge_irq ? edge_xpos : PNORM(xpos); - return (GETFIELD(ABS(pos),13,10)<<12) | GETFIELD(ABS(off),11,0); -} - -void -vt11_set_xor(uint16 d) -{ INIT - xoff = PSCALE(GETFIELD(d,11,0)); - if (s_xoff = TESTBIT(d,13)) - xoff = -xoff; -} - -int32 -vt11_get_yor(void) -{ - int32 off, pos; - INIT - off = PNORM(yoff); - pos = lphit_irq ? lp_ypos : edge_irq ? edge_ypos : PNORM(ypos); - return (GETFIELD(ABS(pos),13,10)<<12) | GETFIELD(ABS(off),11,0); -} - -void -vt11_set_yor(uint16 d) -{ INIT - yoff = PSCALE(GETFIELD(d,11,0)); - if (s_yoff = TESTBIT(d,13)) - yoff = -yoff; -} - -int32 -vt11_get_anr(void) -{ INIT - DEBUGF(("get ANR: no effect\r\n")); - return (search << 12) | assoc_name; /* [garbage] */ -} - -void -vt11_set_anr(uint16 d) -{ INIT - if (TESTBIT(d,14)) - search = GETFIELD(d,13,12); - if (TESTBIT(d,11)) - assoc_name = GETFIELD(d,10,0); -} - -int32 -vt11_get_scr(void) -{ INIT - return (int0_scope<<15) | (lp0_flag<<14) | (lp0_sw<<13) | ((!lp0_sw)<<12) | - (lp0_intr_ena<<11) | (lp0_sw_intr_ena<<10) | (int1_scope<<9) | - (lp1_flag<<8) | (lp1_sw<<7) | ((!lp1_sw)<<6) | (lp1_intr_ena<<5) | - (lp1_sw_intr_ena<<4) | (color << 2); -} - -void -vt11_set_scr(uint16 d) -{ INIT - if (maint3) { - unsigned char old_sw0 = lp0_sw; - unsigned char old_sw1 = lp1_sw; - - if (TESTBIT(d,14)) { - if (!lphit_irq) { /* ensure correct position registers reported */ - lp_xpos = PNORM(xpos); - lp_ypos = PNORM(ypos); - lp_zpos = PNORM(zpos); - } - lp0_flag = 1; - if (lp0_intr_ena) - lphit_irq = 1; - } - if (TESTBIT(d,13)) { - lp0_sw = 1; /* the manual seems to have it backward */ - if (lp0_sw_intr_ena && lp0_sw != old_sw0) - lpsw_irq = 1; - } - if (TESTBIT(d,12)) { - lp0_sw = 0; /* the manual seems to have it backward */ - if (lp0_sw_intr_ena && lp0_sw != old_sw0) - lpsw_irq = 1; - } - if (TESTBIT(d,8)) { - if (!lphit_irq) { /* ensure correct position registers reported */ - lp_xpos = PNORM(xpos); - lp_ypos = PNORM(ypos); - lp_zpos = PNORM(zpos); - } - lp1_flag = 1; - if (lp1_intr_ena) - lphit_irq = 1; - } - if (TESTBIT(d,7)) { - lp1_sw = 1; - if (lp1_sw_intr_ena && lp1_sw != old_sw1) - lpsw_irq = 1; - } - if (TESTBIT(d,6)) { - lp1_sw = 0; - if (lp1_sw_intr_ena && lp1_sw != old_sw1) - lpsw_irq = 1; - } - if (lphit_irq || lpsw_irq) - vt_lpen_intr(); - } -} - -int32 -vt11_get_nr(void) -{ INIT - return (name_flag<<15) | (search<<12) | name; -} - -void -vt11_set_nr(uint16 d) -{ INIT - DEBUGF(("set NR: no effect\r\n")); -} - -int32 -vt11_get_sdr(void) -{ - struct frame *p; - INIT - p = &stack[GETFIELD(stack_sel,4,2)]; - switch (GETFIELD(stack_sel,1,0)) { /* 16-bit "byte" within frame */ - case 0: - return p->_dpc; /* DPC bit#0 is always 0 */ - - case 1: - return (p->_name << 4) | p->_mode; - - case 2: - return (p->_italics << 15) | (p->_vscale << 11) | (p->_cscale << 9) | - (p->_crotate << 7) | (p->_intens << 4) | ((int)p->_color << 2) | - p->_ltype; - - case 3: - return (p->_blink << 15) | (p->_so << 14) | (p->_menu << 13) | - (p->_cesc << 12) | (p->_edgeintr << 11) | (p->_zdata << 10) | - (p->_depth << 8) | (p->_lp1swintr << 7) | - (p->_lp0swintr << 6) | (p->_lp1intr << 5) | (p->_inten1 << 4) | - (p->_lp0intr << 3) | (p->_inten0 << 2) | (p->_bright << 1) | - p->_stopintr; /* XXX should that be !p->_so ? */ - } - /*NOTREACHED*/ -} - -void -vt11_set_sdr(uint16 d) -{ INIT - DEBUGF(("set SDR: no effect\r\n")); -} - -int32 -vt11_get_str(void) -{ INIT - return char_term; -} - -void -vt11_set_str(uint16 d) -{ INIT - if (TESTBIT(d,7)) - char_term = GETFIELD(d,6,0); -} - -int32 -vt11_get_sar(void) -{ - int32 ret; - INIT - ret = (maint4<<15) | (maint3<<14) | (maint2<<13) | (maint1<<12) | - (offset<<10) | (jsr<<9) | stack_sel /*includes bit 5, TOS [level 8]*/; - switch (word_number) { - case 0: - ret |= 1<<6; - break; - case 1: - ret |= 1<<7; - break; - case 2: - ret |= 1<<8; - break; - /* others not reportable */ - } - return ret; -} - -void -vt11_set_sar(uint16 d) -{ INIT - maint4 = TESTBIT(d,15); /* 1 => synch. processing pipeline */ - maint3 = TESTBIT(d,14); /* 1 => copy delta,tangent to x,y pos */ - maint2 = TESTBIT(d,13); /* 1 => set single-step mode */ - maint1 = TESTBIT(d,12); /* 1 => vt11_get_dpc will return bdb */ - if (TESTBIT(d,5)) { - sp = &stack[8]; /* reset stack pointer */ - stack_sel = 8<<2; /* TOS amounts to level 8 */ -#if 1 /* the following seems wrong, but is needed to pass diagnostic test! */ - stack_sel |= 1; -#endif - } else { - stack_sel = GETFIELD(d,4,0); - sp = &stack[GETFIELD(stack_sel,4,2)]; - } -} - -/* registers used with the VS60 depth cueing option */ - -/* - * Since there is no support for hardware 3D rotation or viewing transform, the - * only effect of the Z coordinate is to modulate beam intensity along a vector - * to give the illusion that greater Z coordinates are closer (brighter). - * This is known as "depth cueing" and is implemented in illum3(). - */ - -int32 -vt11_get_zpr(void) -{ - int32 pos; - INIT - pos = lphit_irq ? lp_zpos : edge_irq ? edge_zpos : PNORM(zpos); - return GETFIELD(ABS(pos)/4,11,0); /* sign not reported? */ -} - -void -vt11_set_zpr(uint16 d) -{ INIT - DEBUGF(("set ZPR: no effect\r\n")); -} - -int32 -vt11_get_zor(void) -{ - int32 off, ret; - INIT - off = PNORM(zoff); - ret = GETFIELD(ABS(off),11,0); - if (s_xoff) /* (VT48 manual has this confused) */ - ret |= 1<<15; - if (s_yoff) /* (VT48 manual has this confused) */ - ret |= 1<<14; - if (s_zoff) - ret |= 1<<13; - return ret; -} - -void -vt11_set_zor(uint16 d) -{ INIT - zoff = PSCALE(GETFIELD(d,11,0)); - if (s_zoff = TESTBIT(d,13)) - zoff = -zoff; -} - -void -vt11_reset(void) -{ - /* XXX call display layer? destroy window? */ - - /* make sure display code has been initialized */ - if (!vt11_init) /* (SIMH invokes before display type is set) */ - return; /* wait until last moment */ - - if (VS60) { - /* XXX verify that this is correct VS60 character spacing */ - vt11_csp_w = 14; /* override VT11 options */ - vt11_csp_h = 24; - } /* else assume already set up for desired VT11 behavior */ - - x_edge = display_xpoints() - 1; - y_edge = display_ypoints() - 1; - reduce = display_scale(); - - /* reset VT11/VT48 to initial default internal state: */ - - /* clear interrupts, BDB, etc. */ - vt11_set_dpc(0); /* important! do this first */ - /* some of the following should probably be moved to vt11_set_dpc([even]) */ - internal_stop = int0_scope = 1; /* idle, console 0 enabled */ - lp0_sw_state = lp0_sw; /* sync with mouse button #1 */ - lp1_sw = 0; - shift_out = int1_scope = stop_intr_ena = blink_off = 0; - italics = blink_ena = char_rotate = menu = search = offset = 0; - lp0_sw_intr_ena = lp1_sw_intr_ena = lp0_intr_ena = lp1_intr_ena = 0; - file_z_data = edge_intr_ena = depth_cue_proc = char_escape = 0; - maint1 = maint2 = maint3 = maint4 = 0; - refresh_rate = 0; - char_buf = char_term = 0; - assoc_name = name = 0; - reloc = 0; - xpos = ypos = zpos = xoff = yoff = zoff = 0; - s_xoff = s_yoff = s_zoff = 0; - graphplot_step = 0; - graphic_mode = CHAR; - line_type = SOLID; - color = GREEN; - lp_intensify = 1; - cs_index = 1; - char_scale = vector_scale = 4; - intensity = 4; - - /* following just in case the stack is inspected via stack data reg. */ - { int i; - for (i = 0; i < 8; ++i) - memset(&stack[i], 0, sizeof(struct frame)); - } -} - -/* VS60 display subroutine support (see stack layout for SDR, above) */ - -static void -push() -{ - stack_over = STACK_FULL; - if (!stack_over) { - --sp; - sp[0] = sp[1]; /* initially have same parameters */ - /* (including *old* DPC) */ - stack_sel -= 1<<2; - /* XXX should stack_sel stack-byte bits be cleared? */ - } - /* else will generate interrupt soon after return */ -} - -static void -pop(int restore) -{ - stack_under = STACK_EMPTY; - if (!stack_under) { - ++sp; /* that's all! */ - stack_sel += 1<<2; - /* XXX should stack_sel stack-byte bits be cleared? */ - } - /* else will generate interrupt soon after return */ -} - -/* illuminate pixel in raster image */ - -static void -illum3(int32 x, int32 y, int32 z) /* XXX should supply intensity also */ - /* virtual CRT units (offset and normalized) */ -{ - int i; - - /* don't update position registers! */ - - /* coords might be outside viewable area, e.g. clipped italic character */ - if (!ONCRT(x, y) || !int0_scope) - return; - - if (blink_ena && blink_off) /* blinking & in dark phase */ - return; - - i = intensity; - if (depth_cue_proc) { /* apply depth cue */ - i += i * z / 1024; /* XXX is z scaled properly? */ - if (i > 7) - i = 7; - else if (i < 0) - i = 0; - } - i += DISPLAY_INT_MAX - 7; - if (i < DISPLAY_INT_MIN) - i = DISPLAY_INT_MIN; - - if (display_point((int)x, (int)y, i, 0) /* XXX VS60 might switch color */ - /* VT11, per maintenance spec, has threshold 6 for CHAR, 4 for others */ - /* but the classic Lunar Lander uses 3 for its menu and thrust bar! */ - /* I seem to recall that both thresholds were 4 for the VS60 (VR48). */ -#if 0 - && (i >= (DISPLAY_INT_MAX-1) /* (using i applies depth cueing) */ - || (graphic_mode != CHAR && i >= (DISPLAY_INT_MAX-3))) -#else - /* The following imposes thresholds of 3 for all graphic objects. */ - && (i >= (DISPLAY_INT_MAX-4)) /* (using i applies depth cueing) */ -#endif - && !lp_suppress) { - lp0_flag = 1; - if (lp0_intr_ena) - lphit_irq = 1; /* will lead to an interrupt */ - /* - * Save LP hit coordinates so CPU can look at them; the virtual position - * registers cannot be reported on LP interrupt, since they track the - * (pre-clipping) end of the vector that was being drawn. - */ - lp_xpos = x; - if (menu) - lp_xpos -= MENU_OFFSET; - lp_ypos = y; - lp_zpos = z; - if (lp_intensify) /* [technically shouldn't exceed max] */ - display_point((int)x, (int)y, DISPLAY_INT_MAX, 0); - /* XXX appropriate for VT11; what about VS60? chars? */ - } -} - -#define illum2(x,y) illum3(x, y, PNORM(zpos)) /* may be depth cued */ - /* the extra overhead if not depth cueing is not much */ - -static void -point3(int i, int32 x1, int32 y1, int32 z1, int detect_edge) - /* unscaled, unoffset display-file units */ -{ - int32 x0 = PNORM(xpos), y0 = PNORM(ypos); - - if (detect_edge) { - edge_indic = ONSCREEN(x0, y0); /* first test */ - edge_flag = !ONSCREEN(x0, y0); /* first test */ - } else { - edge_indic = 0; - edge_flag = 0; - } - xpos = VSCALE(x1) + xoff; - ypos = VSCALE(y1) + yoff; - zpos = VSCALE(z1 * 4) + zoff; - x1 = PNORM(xpos); - y1 = PNORM(ypos); - z1 = PNORM(zpos); - if (detect_edge) { - edge_indic &= !ONSCREEN(x1, y1); /* second test */ - edge_flag &= ONSCREEN(x1, y1); /* second test */ - edge_flag |= edge_indic; - if (edge_flag && edge_intr_ena) { - edge_xpos = x1; - edge_ypos = y1; - edge_zpos = z1; - edge_irq = 1; -#if 1 /* XXX uncertain whether point is displayed during edge intr. */ - return; /* point not displayed */ -#endif - } - } - if (i && ONSCREEN(x1, y1)) - if (menu) - illum3(x1 + MENU_OFFSET, y1, z1); - else - illum3(x1, y1, z1); -} - -#define point2(i,x,y,e) point3(i, x, y, PNORM(zpos - zoff) / 4, e) - /* the extra overhead if not depth cueing is not much */ - -/* 4 bit counter, fed from div 2 clock (to compensate for raster algorithm) */ -/* XXX check display against example photos to see if div 2 is right */ -static unsigned char line_counter; -#define LC1 02 -#define LC2 04 -#define LC3 010 -#define LC4 020 - -/* point on a line (apply line style) */ -static void -lpoint(int32 x, int32 y) /* window-system screen pixel units */ -{ - int i, on; - - /* convert back from actual screen pixels to emulated CRT coordinates */ - x *= reduce; - y *= reduce; - - if (!(on = (line_type == SOLID) || stroking)) - for (i = 0; i < reduce; ++i) { - switch (line_type) { - case LONG_DASH: - if (line_counter & LC4) - on = 1; - break; - case SHORT_DASH: - if (line_counter & LC3) - on = 1; - break; - case DOT_DASH: - /* LC(2:1)H * LC3L + LC4L */ - if (((line_counter & (LC1|LC2)) == (LC1|LC2) - && !(line_counter & LC3)) || !(line_counter & LC4)) - on = 1; - break; - } - - --line_counter; - } - - if (on) - illum2(x, y); -} - -/* - * 2-step algorithm, developed by Xiaolin Wu - * from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html - * - * The two-step algorithm takes the interesting approach of treating - * line drawing as a automaton, or finite state machine. If one looks - * at the possible configurations that the next two pixels of a line, - * it is easy to see that only a finite set of possiblities exist. - * If line styles weren't involved, the line could be drawn symmetrically - * from both ends toward the midpoint. - * Rasterization is done using actual screen pixel units, not emulated device - * coordinates! - */ - -static void -lineTwoStep(int32 x0, int32 y0, int32 x1, int32 y1) - /* virtual CRT units (offset and normalized) */ -{ - int32 dx, dy; - int stepx, stepy; - - /* after clipping is implemented, coords should always be on-screen */ - - /* convert from emulated CRT units to actual screen pixels */ - x0 /= reduce; - y0 /= reduce; - x1 /= reduce; - y1 /= reduce; - - dx = x1 - x0; - dy = y1 - y0; - - /* XXX there could be fast special cases for "basic vectors" */ - - if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } - if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } - -#define TPOINT do { if (lphit_irq && !stroking) goto hit; \ - /* XXX would longjmp be more efficient? */ \ - lpoint(x0, y0); \ - } while (0) - - if (!skip_start) /* not for continuing stroke when VS60 char. or arc */ - lpoint(x0, y0); /* (could have used TPOINT) */ - - if (dx == 0 && dy == 0) /* following algorithm won't work */ - return; /* just the one dot */ - - if (dx > dy) { - int32 length = (dx - 1) / 2; - int extras = (dx - 1) & 1; - int32 incr2 = (dy * 4) - (dx * 2); - if (incr2 < 0) { - int32 c = dy * 2; - int32 incr1 = c * 2; - int32 d = incr1 - dx; - int32 i; - for (i = 0; i < length; i++) { - x0 += stepx; - if (d < 0) { /* Pattern: */ - TPOINT; /* x o o */ - x0 += stepx; - TPOINT; - d += incr1; - } - else { - if (d < c) { /* Pattern: */ - TPOINT; /* o */ - y0 += stepy; /* x o */ - } else { /* Pattern: */ - y0 += stepy; /* o o */ - TPOINT; /* x */ - } - x0 += stepx; - TPOINT; - d += incr2; - } - } - if (extras > 0) { - x0 += stepx; - if (d >= c) - y0 += stepy; - TPOINT; - } - - } else { - int32 c = (dy - dx) * 2; /* negative */ - int32 incr1 = c * 2; /* negative */ - int32 d = incr1 + dx; - int32 i; - for (i = 0; i < length; i++) { - x0 += stepx; - if (d > 0) { /* Pattern: */ - y0 += stepy; /* o */ - TPOINT; /* o */ - x0 += stepx; /* x */ - y0 += stepy; - TPOINT; - d += incr1; - } else { - if (d < c) { /* Pattern: */ - TPOINT; /* o */ - y0 += stepy; /* x o */ - } else { /* Pattern: */ - y0 += stepy; /* o o */ - TPOINT; /* x */ - } - x0 += stepx; - TPOINT; - d += incr2; - } - } - if (extras > 0) { - x0 += stepx; - if (d >= c) - y0 += stepy; - TPOINT; - } - } - - } else { - int32 length = (dy - 1) / 2; - int extras = (dy - 1) & 1; - int32 incr2 = (dx * 4) - (dy * 2); - if (incr2 < 0) { - int32 c = dx * 2; - int32 incr1 = c * 2; - int32 d = incr1 - dy; - int32 i; - for (i = 0; i < length; i++) { - y0 += stepy; - if (d < 0) { /* Pattern: */ - TPOINT; /* o */ - y0 += stepy; /* o */ - TPOINT; /* x */ - d += incr1; - } else { - if (d < c) { /* Pattern: */ - TPOINT; /* o */ - x0 += stepx; /* o */ - /* x */ - } else { /* Pattern: */ - x0 += stepx; /* o */ - TPOINT; /* o */ - /* x */ - } - y0 += stepy; - TPOINT; - d += incr2; - } - } - if (extras > 0) { - y0 += stepy; - if (d >= c) - x0 += stepx; - TPOINT; - } - - } else { - int32 c = (dx - dy) * 2; /* nonpositive */ - int32 incr1 = c * 2; /* nonpositive */ - int32 d = incr1 + dy; - int32 i; - for (i = 0; i < length; i++) { - y0 += stepy; - if (d > 0) { /* Pattern: */ - x0 += stepx; - TPOINT; /* o */ - y0 += stepy; /* o */ - x0 += stepx; /* x */ - TPOINT; - d += incr1; - } else { - if (d < c) { /* Pattern: */ - TPOINT; /* o */ - x0 += stepx; /* o */ - /* x */ - } else { /* Pattern: */ - x0 += stepx; /* o */ - TPOINT; /* o */ - /* x */ - } - y0 += stepy; - TPOINT; - d += incr2; - } - } - if (extras > 0) { - y0 += stepy; - if (d >= c) - x0 += stepx; - TPOINT; - } - } - } - lpoint(x1, y1); /* not TPOINT (0-length vector on resume) */ - return; - - /* here if LP hit interrupt during rendering */ - hit: - more_vect = 1; - save_x0 = x0 * reduce; - save_y0 = y0 * reduce; - save_x1 = x1 * reduce; - save_y1 = y1 * reduce; - /* XXX should also save Z coord. for use when completing the line */ - /* line_counter is static and thus will be intact upon resume */ -} /* lineTwoStep */ - -/* draw a 3D relative vector, depth-cued when appropriate */ - -static void -vector3(int i, int32 dx, int32 dy, int32 dz) /* unscaled display-file units */ -{ - int32 x0, y0, z0, x1, y1, z1; - int on0, on1; /* ONSCREEN(x0,y0), ONSCREEN(x1,y1) */ - - line_counter = 037; /* reset line-style counter */ - - dx = VSCALE(dx); /* apply vector scale (VS60) */ - dy = VSCALE(dy); - dz = VSCALE(dz * 4); - x0 = PNORM(xpos); /* (includes offset) */ - y0 = PNORM(ypos); - z0 = PNORM(zpos); - xpos += dx; - ypos += dy; - zpos += dz; - x1 = PNORM(xpos); - y1 = PNORM(ypos); - z1 = PNORM(zpos); - dx = PNORM(dx); - dy = PNORM(dy); - dz = PNORM(dz); - DEBUGF(("offset, normalized vector i%d (%ld,%ld,%ld) to (%ld,%ld,%ld)\r\n", - i, (long)x0, (long)y0, (long)z0, (long)x1, (long)y1, (long)z1)); - - /* Maintenance Switch 3 => store delta length and tangent in xpos,ypos */ - if (maint3) { - int32 adx = ABS(dx), ady = ABS(dy); - if (adx == ady) { - xpos = adx; /* or ady */ - ypos = 07777; /* (12 bits?) ~ 1.0 */ - } else if (adx > ady) { - xpos = dx; - ypos = 010000L * ady / adx; /* truncates */ /* XXX 07777L? */ - } else /* (adx < ady) */ { - xpos = dy; - ypos = 010000L * adx / ady; /* truncates */ /* XXX 07777L? */ - } - DEBUGF(("delta=0%o, tangent=0%o\r\n", xpos, ypos)); - xpos = PSCALE(xpos); /* compensates for eventual PNORM */ - ypos = PSCALE(ypos); /* compensates for eventual PNORM */ - } - - /* clip to viewport ("working surface") if necessary */ - - /* XXX not implemented yet */ - - /* check for edge conditions (XXX will change when clipping implemented) */ - on0 = ONSCREEN(x0, y0); - on1 = ONSCREEN(x1, y1); - edge_indic = on0 && !on1; - edge_flag = edge_indic || (!on0 && on1); - if (edge_flag && edge_intr_ena) { /* need to clip to viewport */ - /* XXX edge positions aren't right; need proper clipping, - then recompute using tangent register */ - edge_xpos = x1; - edge_ypos = y1; - edge_zpos = z1; - return; - } - - if (dx == 0 && dy == 0) - return; /* hardware skips null vector */ - - /* XXX for now, resort to scissoring: - illuminates only pixels that lie in the visible display area */ - - /* draw OK even when Maintenance Switch 3 is set */ - /* (but updated position registers must not be used to draw vector) */ - if (i && int0_scope) - if (menu) - lineTwoStep(x0 + MENU_OFFSET, y0, x1 + MENU_OFFSET, y1); - else - lineTwoStep(x0, y0, x1, y1); - /* XXX Depth cueing not yet right. Probably the way to do this is to - adapt a copy of lineTwoStep() to step intensity values along the - vector as it rasterizes it, calling illum3() instead of illum2(). - The unmodified lineTwoStep() should continue to be used for 2D - vectors, to avoid the overhead of recomputing constant i values. */ - - /* - * In case of LP hit, recompute coords using "tangent register", because: - * (1) pixelization can lead to off-by-1 or -2 - * (2) rasterization might not be same as VT48 computation - */ - - if (lp0_flag) { - long tangent; - int32 adx = ABS(dx), ady = ABS(dy); - if (adx >= ady) { - tangent = 010000L * dy / dx; /* signed */ - lp_ypos = y0 + tangent * (lp_xpos - x0) / 010000L; - tangent = 010000L * dz / dx; - lp_zpos = z0 + tangent * (lp_xpos - x0) / 010000L; - } else { - tangent = 010000L * dx / dy; /* signed */ - lp_xpos = x0 + tangent * (lp_ypos - y0) / 010000L; - tangent = 010000L * dz / dy; - lp_zpos = z0 + tangent * (lp_ypos - y0) / 010000L; - } - DEBUGF(("adjusted LP coords (0%o,0%o)\r\n", lp_xpos, lp_ypos)); - /* xpos,ypos,zpos still pertain to the original endpoint - (assuming that Maintenance Switch 3 isn't set) */ - } -} - -/* draw a 2D relative vector, depth-cued (constant Z) when appropriate */ - -/* for the sake of efficiency, vector2() does not invoke vector3() */ - -static void -vector2(int i, int32 dx, int32 dy) /* unscaled display-file units */ -{ - int32 x0, y0, x1, y1; - int on0, on1; /* ONSCREEN(x0,y0), ONSCREEN(x1,y1) */ - - dx = stroking ? CSCALE(dx) : VSCALE(dx); /* apply scale factor (VS60) */ - dy = stroking ? CSCALE(dy) : VSCALE(dy); - x0 = PNORM(xpos); /* (includes offset) */ - y0 = PNORM(ypos); - xpos += dx; - ypos += dy; - x1 = PNORM(xpos); - y1 = PNORM(ypos); - dx = PNORM(dx); - dy = PNORM(dy); - - if (stroking) { /* drawing a VS60 character */ - DEBUGF(("offset, normalized stroke i%d (%ld,%ld) to (%ld,%ld)\r\n", - i, (long)x0,(long)y0, (long)x1,(long)y1)); - - if (dx == 0 && dy == 0) { /* just display a point */ - if (menu) - illum2(x0 + MENU_OFFSET, y0); /* [checks ONCRT, int0_scope] */ - else - illum2(x0, y0); /* [checks ONCRT, int0_scope] */ - return; - } - } else { - DEBUGF(("[offset, normalized] vector i%d (%ld,%ld) to (%ld,%ld)\r\n", - i, (long)x0,(long)y0, (long)x1,(long)y1)); - - line_counter = 037; /* reset line-style counter */ - - /* Maintenance Switch 3 => store delta length,tangent in xpos,ypos */ - if (maint3) { - int32 adx = ABS(dx), ady = ABS(dy); - if (adx == ady) { - xpos = adx; /* or ady */ - ypos = 07777; /* (12 bits?) ~ 1.0 */ - } else if (adx > ady) { - xpos = dx; - ypos = 010000L * ady / adx; /* truncates *//* XXX 07777L? */ - } else /* (adx < ady) */ { - xpos = dy; - ypos = 010000L * adx / ady; /* truncates *//* XXX 07777L? */ - } - DEBUGF(("delta=0%o, tangent=0%o\r\n", xpos, ypos)); - xpos = PSCALE(xpos); /* compensates for eventual PNORM */ - ypos = PSCALE(ypos); /* compensates for eventual PNORM */ - } - - /* clip to viewport ("working surface") if necessary */ - - /* XXX not implemented yet */ - - /* check for edge conditions (XXX changes when clipping implemented) */ - on0 = ONSCREEN(x0, y0); - on1 = ONSCREEN(x1, y1); - edge_indic = on0 && !on1; - edge_flag = edge_indic || (!on0 && on1); - if (edge_flag && edge_intr_ena) { /* need to clip to viewport */ - /* XXX edge positions aren't right; need proper clipping, - then recompute using tangent register */ - edge_xpos = x1; - edge_ypos = y1; - edge_zpos = PNORM(zpos); - return; - } - - if (dx == 0 && dy == 0) - return; /* hardware skips null vectors */ - } - - /* XXX for now, resort to scissoring: - illuminates only pixels that lie in the visible display area */ - - /* draw OK even when Maintenance Switch 3 is set */ - /* (but updated position registers must not be used to draw vector) */ - if (i && int0_scope) - if (menu) - lineTwoStep(x0 + MENU_OFFSET, y0, x1 + MENU_OFFSET, y1); - else - lineTwoStep(x0, y0, x1, y1); - - /* - * In case of LP hit, recompute coords using "tangent register", because: - * (1) distinct virtual CRT points can be mapped into the same pixel - * (2) raster computation might not match that of the actual VT48 - */ - - if (lp0_flag) { - long tangent; - int32 adx = ABS(dx), ady = ABS(dy); - if (adx >= ady) { - tangent = 010000L * dy / dx; /* signed */ - lp_ypos = y0 + tangent * (lp_xpos - x0) / 010000L; - } else { - tangent = 010000L * dx / dy; /* signed */ - lp_xpos = x0 + tangent * (lp_ypos - y0) / 010000L; - } - DEBUGF(("adjusted LP coords (0%o,0%o)\r\n", lp_xpos, lp_ypos)); - /* xpos,ypos,zpos still pertain to the original endpoint - (assuming that Maintenance Switch 3 isn't set) */ - } -} - -/* basic vector (multiple of 45 degrees; directions numbered CCW, #0 => +X) */ -static void -basic_vector(int i, int dir, int len) /* unscaled display-file units */ -{ - int32 dx, dy; - - /* Alternatively, could be rasterized specially for each case; then - the general vector2() function could detect these special cases and - invoke this function to handle them, instead of the other way around. */ - - switch (dir) { - case 0: - dx = len; - dy = 0; - break; - case 1: - dx = len; - dy = len; - break; - case 2: - dx = 0; - dy = len; - break; - case 3: - dx = -len; - dy = len; - break; - case 4: - dx = -len; - dy = 0; - break; - case 5: - dx = -len; - dy = -len; - break; - case 6: - dx = 0; - dy = -len; - break; - case 7: - dx = len; - dy = -len; - break; - default: /* "can't happen" */ - DEBUGF(("BUG: basic vector: illegal direction %d\r\n", dir)); - return; - } - DEBUGF(("basic ")); - vector2(i, dx, dy); -} - -/* - * support for VS60 circle/arc option - * - * Since the literature that I have access to does not handle the case where - * starting and ending radii differ, I invented a solution that should be - * "good enough" for now: an approximation of an Archimedean spiral is drawn - * as connected individual chords, with the line-type counter applied (without - * being reset) over the entire curve. - * - * It is not known whether the direction is supposed to be clockwise or - * counterclockwise (the latter is assumed in the following code); it is - * assumed that if the starting and ending directions from the center point - * are identical, that a full circle is being specified. - * - * Although throughout the display simulation substantial effort has been - * invested to avoid using floating point, this preliminary implementation - * of the circle/arc generator does use floating point. Presumably this - * is avoidable, but the algorithmic details would need to be worked out. - * If use of floating point is a problem, #define NO_CONIC_OPT when compiling. - */ - -static void -conic2(int i, int32 dcx, int32 dcy, int32 dex, int32 dey) - /* unscaled display-file units */ -{ -#ifdef NO_CONIC_OPT - /* just draw vector to endpoint (like real VS60 with option missing) */ - vector2(i, dex, dey); -#else - int32 xs, ys, xc, yc, xe, ye, x, y, n; - double rs, re, dr, as, da; - int ons, one; /* ONSCREEN(xs,ys), ONSCREEN(xe,ye) */ - static double two_pi = -1.0; /* will be set (once only) to 2*Pi */ - static double k; /* will be set to 2-sqrt(4-(Pi/4)^2) */ - - if (two_pi < 0.0) { /* (initial entry only) */ - k = atan2(1.0, 1.0); - two_pi = 8.0 * k; - k = 2.0 - sqrt(4.0 - k*k); - } - dcx = VSCALE(dcx); /* apply vector scale factor */ - dcy = VSCALE(dcy); - dex = VSCALE(dex); - dey = VSCALE(dey); - xs = PNORM(xpos); /* starting pos. (includes offset) */ - ys = PNORM(ypos); - xc = PNORM(xpos + dcx); /* center pos. (includes offset) */ - yc = PNORM(ypos + dcy); - xe = PNORM(xpos + dex); /* ending pos. (includes offset) */ - ye = PNORM(ypos + dey); - /* determine vector from center to finish */ - dex -= dcx; /* PSCALEd */ - dey -= dcy; - - DEBUGF(("offset, normalized arc i%d s(%ld,%ld) c(%ld,%ld) e(%ld,%ld)\r\n", - i, (long)xs,(long)ys, (long)xc,(long)yc, (long)xe,(long)ye)); - - /* XXX not known whether Maintenance Switch 3 has any effect for arcs */ - - /* clip to viewport ("working surface") if necessary */ - - /* XXX not implemented yet [could check each chord individually] */ - - /* check for edge conditions (XXX changes when clipping implemented) */ - /* XXX this test is very crude; should be much more complex */ - ons = ONSCREEN(xs, ys); - one = ONSCREEN(xe, ye); - edge_indic = ons && !one; - edge_flag = edge_indic || (!ons && one); - if (edge_flag && edge_intr_ena) { /* need to clip to viewport */ - /* XXX edge positions aren't right; need proper clipping */ - edge_xpos = xe; - edge_ypos = ye; - edge_zpos = PNORM(zpos); - goto done; - } - - /* XXX for now, resort to scissoring: - illuminates only pixels that lie in the visible display area */ - - if (dcx == 0 && dcy == 0 && dex == 0 && dey == 0) - goto done; /* skip null curve */ - - /* determine starting, ending radii and their maximum */ - rs = PNORM(sqrt((double)dcx*dcx + (double)dcy*dcy)); /* (f.p.) */ - re = PNORM(sqrt((double)dex*dex + (double)dey*dey)); - dr = rs >= re ? rs : re; - - /* determine starting direction from center, and included angle */ - as = dcx == 0 && dcy == 0 ? 0.0 : atan2((double)-dcy, (double)-dcx); - da = (dex == 0 && dey == 0 ? 0.0 : atan2((double)dey, (double)dex)) - as; - while (da <= 0.0) /* exactly 0.0 implies full cycle */ - da += two_pi; - - /* determine number of chords to use; - make deviation from true curve no more than approximately one pixel */ - dr = reduce / dr; - if (dr > k) - dr = k; - n = (int32)(da / sqrt(4.0*dr - dr*dr) + 1.0); - if (n < 1) /* "can't happen" */ - n = 1; - else if (n > 360) - n = 360; /* arbitrarily chosen upper limit */ - - /* determine angular and radial step sizes */ - dr = (re - rs) / n; - da /= n; - - if (menu) { - xs += MENU_OFFSET; - xc += MENU_OFFSET; - xe += MENU_OFFSET; - } - - line_counter = 037; /* reset line-style counter */ - - /* draw successive chords */ - while (--n > 0) { - rs += dr; - as += da; - re = rs * cos(as); - x = xc + (re >= 0 ? (int32)(re + 0.5) : -(int32)(-re + 0.5)); - re = rs * sin(as); - y = yc + (re >= 0 ? (int32)(re + 0.5) : -(int32)(-re + 0.5)); - lineTwoStep(xs, ys, x, y); /* (applies continuing line style) */ - skip_start = 1; /* don't double-illuminate junctions */ - xs = x; - ys = y; - if (lphit_irq) - goto done; /* light-pen hit interrupted drawing */ - } - lineTwoStep(xs, ys, xe, ye); /* draw final chord to exact endpoint */ - skip_start = 0; /* important! */ - - done: - xpos += dcx + dex; /* update virtual beam position */ - ypos += dcy + dey; - if (lp0_flag) { - DEBUGF(("LP hit on arc at (0%o,0%o)\r\n", lp_xpos, lp_ypos)); - if (lphit_irq) { - /* XXX save parameters for drawing remaining chords */ - } - } -#endif -} - -static void -conic3(int i, int32 dcx, int32 dcy, int32 dcz, int32 dex, int32 dey, int32 dez) - /* unscaled display-file units */ -{ -#ifdef NO_CONIC_OPT - /* just draw vector to endpoint (like real VS60 with option missing) */ - vector3(i, dex, dey, dez); -#else - conic2(i, dcx, dcy, dex, dey); /* XXX not properly depth cued */ - zpos += PSCALE(dez); -#endif -} - -/* - * VT11 character font; - * 6x8 matrix, not serpentine encoded, decenders supported as in real VT11 - */ - -static const unsigned char dots[0200][6] = { - { 0x8f, 0x50, 0x20, 0x10, 0x08, 0x07 }, /* 000 lambda */ - { 0x1e, 0x21, 0x22, 0x14, 0x0c, 0x13 }, /* 001 alpha */ - { 0x00, 0x18, 0x24, 0xff, 0x24, 0x18 }, /* 002 phi */ - { 0x83, 0xc5, 0xa9, 0x91, 0x81, 0xc3 }, /* 003 SIGMA */ - { 0x00, 0x46, 0xa9, 0x91, 0x89, 0x06 }, /* 004 delta */ - { 0x03, 0x05, 0x09, 0x11, 0x21, 0x7f }, /* 005 DELTA */ - { 0x00, 0x20, 0x20, 0x3f, 0x01, 0x01 }, /* 006 iota */ - { 0x46, 0x29, 0x11, 0x2e, 0x40, 0x80 }, /* 007 gamma */ - { 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f }, /* 010 intersect */ - { 0x40, 0x3c, 0x04, 0xff, 0x04, 0x78 }, /* 011 psi */ - { 0x00, 0x10, 0x10, 0x54, 0x10, 0x10 }, /* 012 divide by */ - { 0x00, 0x60, 0x90, 0x90, 0x60, 0x00 }, /* 013 degree */ - { 0x00, 0x01, 0x00, 0x10, 0x00, 0x01 }, /* 014 therefore */ - { 0x01, 0x02, 0x3c, 0x02, 0x02, 0x3c }, /* 015 mu */ - { 0x11, 0x7f, 0x91, 0x81, 0x41, 0x03 }, /* 016 pound sterling */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 017 SHIFT IN */ - { 0x20, 0x40, 0x7f, 0x40, 0x7f, 0x40 }, /* 020 pi */ - { 0x00, 0xff, 0x00, 0x00, 0xff, 0x00 }, /* 021 parallel */ - { 0x1d, 0x23, 0x40, 0x42, 0x25, 0x19 }, /* 022 OMEGA */ - { 0x1c, 0x22, 0x61, 0x51, 0x4e, 0x40 }, /* 023 sigma */ - { 0x20, 0x40, 0x40, 0x7f, 0x40, 0x40 }, /* 024 UPSILON */ - { 0x00, 0x1c, 0x2a, 0x49, 0x49, 0x00 }, /* 025 epsilon */ - { 0x10, 0x38, 0x54, 0x10, 0x10, 0x10 }, /* 026 left arrow */ - { 0x10, 0x10, 0x10, 0x54, 0x38, 0x10 }, /* 027 right arrow */ - { 0x00, 0x20, 0x40, 0xfe, 0x40, 0x20 }, /* 030 up arrow */ - { 0x00, 0x04, 0x02, 0x7f, 0x02, 0x04 }, /* 031 down arrow */ - { 0x00, 0xff, 0x80, 0x80, 0x80, 0x80 }, /* 032 GAMMA */ - { 0x00, 0x01, 0x01, 0xff, 0x01, 0x01 }, /* 033 perpendicular */ - { 0x2a, 0x2c, 0x28, 0x38, 0x68, 0xa8 }, /* 034 unequal */ - { 0x24, 0x48, 0x48, 0x24, 0x24, 0x48 }, /* 035 approx equal */ - { 0x00, 0x20, 0x10, 0x08, 0x10, 0x20 }, /* 036 vel */ - { 0xff, 0x81, 0x81, 0x81, 0x81, 0xff }, /* 037 box */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 040 space */ - { 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00 }, /* 041 ! */ - { 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00 }, /* 042 " */ - { 0x00, 0x24, 0xff, 0x24, 0xff, 0x24 }, /* 043 # */ - { 0x22, 0x52, 0xff, 0x52, 0x4c, 0x00 }, /* 044 $ */ - { 0x42, 0xa4, 0x48, 0x12, 0x25, 0x42 }, /* 045 % */ - { 0x66, 0x99, 0x99, 0x66, 0x0a, 0x11 }, /* 046 & */ - { 0x00, 0x00, 0x20, 0x40, 0x80, 0x00 }, /* 047 ' */ - { 0x00, 0x00, 0x3c, 0x42, 0x81, 0x00 }, /* 050 ( */ - { 0x00, 0x00, 0x81, 0x42, 0x3c, 0x00 }, /* 051 ) */ - { 0x00, 0x44, 0x28, 0xf0, 0x28, 0x44 }, /* 052 * */ - { 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10 }, /* 053 + */ - { 0x00, 0x01, 0x06, 0x00, 0x00, 0x00 }, /* 054 , */ - { 0x00, 0x10, 0x10, 0x10, 0x10, 0x10 }, /* 055 - */ - { 0x00, 0x00, 0x06, 0x06, 0x00, 0x00 }, /* 056 . */ - { 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 }, /* 057 / */ - { 0x7e, 0x85, 0x89, 0x91, 0xa1, 0x7e }, /* 060 0 */ - { 0x00, 0x41, 0xff, 0x01, 0x00, 0x00 }, /* 061 1 */ - { 0x47, 0x89, 0x91, 0x91, 0x91, 0x61 }, /* 062 2 */ - { 0x42, 0x81, 0x91, 0xb1, 0xd1, 0x8e }, /* 063 3 */ - { 0x0c, 0x14, 0x24, 0x44, 0xff, 0x04 }, /* 064 4 */ - { 0xf2, 0x91, 0x91, 0x91, 0x91, 0x8e }, /* 065 5 */ - { 0x3c, 0x46, 0x89, 0x89, 0x89, 0x46 }, /* 066 6 */ - { 0x40, 0x87, 0x88, 0x90, 0xa0, 0xc0 }, /* 067 7 */ - { 0x6e, 0x91, 0x91, 0x91, 0x91, 0x6e }, /* 070 8 */ - { 0x62, 0x91, 0x91, 0x91, 0x62, 0x3c }, /* 071 9 */ - { 0x00, 0x66, 0x66, 0x00, 0x00, 0x00 }, /* 072 : */ - { 0x00, 0x00, 0x61, 0x66, 0x00, 0x00 }, /* 073 ; */ - { 0x00, 0x18, 0x24, 0x42, 0x81, 0x00 }, /* 074 < */ - { 0x00, 0x28, 0x28, 0x28, 0x28, 0x28 }, /* 075 = */ - { 0x00, 0x81, 0x42, 0x24, 0x18, 0x00 }, /* 076 > */ - { 0x00, 0x40, 0x80, 0x9d, 0x90, 0x60 }, /* 077 ? */ - { 0x3c, 0x42, 0x91, 0xa9, 0xa9, 0x72 }, /* 100 @ */ - { 0x3f, 0x48, 0x88, 0x88, 0x48, 0x3f }, /* 101 A */ - { 0x81, 0xff, 0x91, 0x91, 0x91, 0x6e }, /* 102 B */ - { 0x3c, 0x42, 0x81, 0x81, 0x81, 0x42 }, /* 103 C */ - { 0x81, 0xff, 0x81, 0x81, 0x42, 0x3c }, /* 104 D */ - { 0x81, 0xff, 0x91, 0x91, 0x91, 0xc3 }, /* 105 E */ - { 0x81, 0xff, 0x91, 0x90, 0x80, 0xc0 }, /* 106 F */ - { 0x3c, 0x42, 0x81, 0x89, 0x89, 0x4f }, /* 107 G */ - { 0xff, 0x10, 0x10, 0x10, 0x10, 0xff }, /* 110 H */ - { 0x00, 0x81, 0xff, 0x81, 0x00, 0x00 }, /* 111 I */ - { 0x0e, 0x01, 0x01, 0x81, 0xfe, 0x80 }, /* 112 J */ - { 0xff, 0x08, 0x10, 0x28, 0x44, 0x83 }, /* 113 K */ - { 0x81, 0xff, 0x81, 0x01, 0x01, 0x03 }, /* 114 L */ - { 0xff, 0x40, 0x30, 0x30, 0x40, 0xff }, /* 115 M */ - { 0xff, 0x20, 0x10, 0x08, 0x04, 0xff }, /* 116 N */ - { 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c }, /* 117 O */ - { 0x81, 0xff, 0x90, 0x90, 0x90, 0x60 }, /* 120 P */ - { 0x3c, 0x42, 0x81, 0x8f, 0x42, 0x3d }, /* 121 Q */ - { 0x81, 0xff, 0x90, 0x98, 0x94, 0x63 }, /* 122 R */ - { 0x22, 0x51, 0x91, 0x91, 0x89, 0x46 }, /* 123 S */ - { 0xc0, 0x80, 0x81, 0xff, 0x81, 0xc0 }, /* 124 T */ - { 0xfe, 0x01, 0x01, 0x01, 0x01, 0xfe }, /* 125 U */ - { 0xff, 0x02, 0x04, 0x08, 0x10, 0xe0 }, /* 126 V */ - { 0xff, 0x02, 0x0c, 0x0c, 0x02, 0xff }, /* 127 W */ - { 0xc3, 0x24, 0x18, 0x18, 0x24, 0xc3 }, /* 130 X */ - { 0x00, 0xe0, 0x10, 0x0f, 0x10, 0xe0 }, /* 131 Y */ - { 0x83, 0x85, 0x89, 0x91, 0xa1, 0xc1 }, /* 132 Z */ - { 0x00, 0x00, 0xff, 0x81, 0x81, 0x00 }, /* 133 [ */ - { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04 }, /* 134 \ */ - { 0x00, 0x00, 0x81, 0x81, 0xff, 0x00 }, /* 135 ] */ - { 0x00, 0x10, 0x20, 0x40, 0x20, 0x10 }, /* 136 ^ */ - { 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 }, /* 137 _ */ - /* for all lowercase characters, first column is just a "descender" flag: */ - { 0x00, 0x00, 0x80, 0x40, 0x20, 0x00 }, /* 140 ` */ - { 0x00, 0x26, 0x29, 0x29, 0x2a, 0x1f }, /* 141 a */ - { 0x00, 0xff, 0x12, 0x21, 0x21, 0x1e }, /* 142 b */ - { 0x00, 0x1e, 0x21, 0x21, 0x21, 0x12 }, /* 143 c */ - { 0x00, 0x1e, 0x21, 0x21, 0x12, 0xff }, /* 144 d */ - { 0x00, 0x1e, 0x29, 0x29, 0x29, 0x19 }, /* 145 e */ - { 0x00, 0x20, 0x7f, 0xa0, 0xa0, 0x80 }, /* 146 f */ - { 0x01, 0x78, 0x85, 0x85, 0x49, 0xfe }, /* 147 g */ - { 0x00, 0xff, 0x10, 0x20, 0x20, 0x1f }, /* 150 h */ - { 0x00, 0x00, 0x21, 0xbf, 0x01, 0x00 }, /* 151 i */ - { 0x01, 0x02, 0x01, 0x81, 0xfe, 0x00 }, /* 152 j */ - { 0x00, 0xff, 0x08, 0x14, 0x22, 0x21 }, /* 153 k */ - { 0x00, 0x00, 0xfe, 0x01, 0x01, 0x00 }, /* 154 l */ - { 0x00, 0x3f, 0x20, 0x3f, 0x20, 0x3f }, /* 155 m */ - { 0x00, 0x3f, 0x10, 0x20, 0x20, 0x1f }, /* 156 n */ - { 0x00, 0x1e, 0x21, 0x21, 0x21, 0x1e }, /* 157 o */ - { 0x01, 0xff, 0x48, 0x84, 0x84, 0x78 }, /* 160 p */ - { 0x01, 0x78, 0x84, 0x84, 0x48, 0xff }, /* 161 q */ - { 0x00, 0x3f, 0x08, 0x10, 0x20, 0x20 }, /* 162 r */ - { 0x00, 0x12, 0x29, 0x29, 0x29, 0x26 }, /* 163 s */ - { 0x00, 0x20, 0xfe, 0x21, 0x21, 0x00 }, /* 164 t */ - { 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3f }, /* 165 u */ - { 0x00, 0x3c, 0x02, 0x01, 0x02, 0x3c }, /* 166 v */ - { 0x00, 0x3e, 0x01, 0x1e, 0x01, 0x3e }, /* 167 w */ - { 0x00, 0x23, 0x14, 0x08, 0x14, 0x23 }, /* 170 x */ - { 0x01, 0xf8, 0x05, 0x05, 0x09, 0xfe }, /* 171 y */ - { 0x00, 0x23, 0x25, 0x29, 0x31, 0x21 }, /* 172 z */ - { 0x00, 0x18, 0x66, 0x81, 0x81, 0x00 }, /* 173 { */ - { 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00 }, /* 174 | */ - { 0x00, 0x00, 0x81, 0x81, 0x66, 0x18 }, /* 175 } */ - { 0x00, 0x0c, 0x10, 0x08, 0x04, 0x18 }, /* 176 ~ */ - { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff } /* 177 rubout */ -}; - -/* - * VS60 character stroke table - * - * stroke[] contains "prototype" encodings for all vector strokes (visible and - * invisible) needed to draw each character at a standard size. The actual - * display is of course properly italicized, positioned, scaled, and rotated. - * - * Variable-length entries are used; each character stroke sequence is - * terminated by a 0-valued byte. Pointers to the appropriate data for all - * characters are stored into sstroke[] during a one-time initialization. - * - * The prototype strokes are for the most part constrained to a 4x6 unit area, - * except for a few cases that are handled by kludging the coordinates. - * Coordinates are relative to the left end of the character baseline. - * - * A prototype stroke is encoded as 8 bits SVXXXYYY: - * S = 0 if YYY is correct as is - * 1 if YYY needs to have 2 subtracted - * V = 0 if stroke is invisible (move) - * 1 if stroke is visible (draw) - * XXX = final X coord of stroke (0..4; 7 => -1) - * YYY = final Y coord of stroke (0..6) - */ - -static const unsigned char stroke[] = { - /* - * While based on the actual VT48 strokes, these have been tweaked - * (especially the lower-case letters, which had erratic sizes) to - * improve their appearance and/or reduce the number of strokes. - * Several of the special symbols (e.g. alpha, delta, iota) could - * be further improved, but I didn't want to make them look too - * different from the original. Note that VS60 screen photos - * disagree, for several characters, with the (incomplete) chart of - * strokes given in the VT48 manual. (There could have been ROM changes.) - * - * The simulated character sizes are not exact at all scales, but there - * is no really good way to fix this without spoiling the appearance. - * char. scale VS60 units simulation units (pixel has size!) - * 1/2 5 x 7 5 x 7 - * 1 10 x 14 9 x 13 - * 3/2 15 x 21 13 x 19 - * 2 20 x 28 17 x 25 - */ - 0111, 0123, 0006, 0115, 0131, 0140, 0, /* 000 lambda */ - 0042, 0132, 0114, 0103, 0112, 0134, 0144, 0, /* 001 alpha */ - 0011, 0103, 0115, 0135, 0143, 0131, 0111, 0010, - 0146, 0, /* 002 phi */ - 0040, 0100, 0133, 0106, 0146, 0, /* 003 SIGMA */ - 0022, 0111, 0120, 0131, 0113, 0115, 0124, 0, /* 004 delta */ - 0140, 0124, 0100, 0, /* 005 DELTA */ - 0006, 0126, 0120, 0140, 0, /* 006 iota */ - 0006, 0115, 0131, 0120, 0111, 0135, 0146, 0, /* 007 gamma */ - 0104, 0116, 0136, 0144, 0140, 0, /* 010 intersect */ - 0010, 0136, 0044, 0142, 0131, 0111, 0102, 0104, 0, /* 011 psi */ - 0022, 0122, 0003, 0143, 0024, 0124, 0, /* 012 divide by */ - 0024, 0115, 0126, 0135, 0124, 0, /* 013 degree */ - 0001, 0101, 0025, 0125, 0041, 0141, 0, /* 014 therefore */ - 0111, 0115, 0012, 0121, 0131, 0142, 0045, 0142, - 0151, 0, /* 015 mu */ - 0105, 0116, 0126, 0135, 0013, 0173, 0001, 0120, - 0130, 0141, 0, /* 016 pound sterling */ - 0, /* 017 SHIFT IN */ - 0003, 0114, 0144, 0034, 0130, 0010, 0114, 0, /* 020 pi */ - 0010, 0116, 0036, 0130, 0, /* 021 parallel */ - 0110, 0111, 0102, 0104, 0115, 0135, 0144, 0142, - 0131, 0130, 0140, 0, /* 022 OMEGA */ - 0025, 0134, 0132, 0120, 0110, 0102, 0104, 0146, 0, /* 023 sigma */ - 0010, 0136, 0046, 0116, 0105, 0, /* 024 UPSILON */ - 0003, 0133, 0045, 0136, 0116, 0105, 0101, 0110, - 0130, 0141, 0, /* 025 epsilon */ - 0042, 0102, 0113, 0011, 0102, 0, /* 026 left arrow */ - 0002, 0142, 0133, 0031, 0142, 0, /* 027 right arrow */ - 0020, 0124, 0133, 0013, 0124, 0, /* 030 up arrow */ - 0024, 0120, 0131, 0011, 0120, 0, /* 031 down arrow */ - 0106, 0146, 0144, 0, /* 032 GAMMA */ - 0140, 0026, 0120, 0, /* 033 perpendicular */ - 0001, 0145, 0044, 0104, 0002, 0142, 0, /* 034 unequal */ - 0001, 0112, 0131, 0142, 0044, 0133, 0114, 0103, 0, /* 035 approx equal */ - 0016, 0125, 0135, 0146, 0, /* 036 vel */ - 0106, 0146, 0140, 0100, 0, /* 037 box */ - 0, /* 040 space */ - 0020, 0120, 0021, 0125, 0, /* 041 ! */ - 0004, 0126, 0046, 0124, 0, /* 042 " */ - 0012, 0116, 0036, 0132, 0043, 0103, 0005, 0145, 0, /* 043 # */ - 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, - 0105, 0116, 0136, 0145, 0026, 0120, 0, /* 044 $ */ - 0146, 0116, 0105, 0114, 0125, 0116, 0032, 0141, - 0130, 0121, 0132, 0, /* 045 % */ - 0040, 0104, 0105, 0116, 0126, 0135, 0134, 0101, - 0110, 0120, 0142, 0, /* 046 & */ - 0014, 0136, 0, /* 047 ' */ - 0030, 0112, 0114, 0136, 0, /* 050 ( */ - 0010, 0132, 0134, 0116, 0, /* 051 ) */ - 0002, 0146, 0026, 0122, 0042, 0106, 0, /* 052 * */ - 0021, 0125, 0003, 0143, 0, /* 053 + */ - 0211, 0120, 0121, 0, /* 054 , */ - 0003, 0143, 0, /* 055 - */ - 0020, 0120, 0, /* 056 . */ - 0146, 0, /* 057 / */ - 0001, 0145, 0136, 0116, 0105, 0101, 0110, 0130, - 0141, 0145, 0, /* 060 0 */ - 0010, 0130, 0020, 0126, 0115, 0, /* 061 1 */ - 0005, 0116, 0136, 0145, 0144, 0100, 0140, 0, /* 062 2 */ - 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0005, - 0116, 0136, 0145, 0144, 0133, 0, /* 063 3 */ - 0030, 0136, 0025, 0102, 0142, 0, /* 064 4 */ - 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, - 0106, 0146, 0, /* 065 5 */ - 0002, 0113, 0133, 0142, 0141, 0130, 0110, 0101, - 0105, 0116, 0136, 0145, 0, /* 066 6 */ - 0006, 0146, 0120, 0, /* 067 7 */ - 0013, 0133, 0142, 0141, 0130, 0110, 0101, 0102, - 0113, 0104, 0105, 0116, 0136, 0145, 0144, 0133, 0, /* 070 8 */ - 0001, 0110, 0130, 0141, 0145, 0136, 0116, 0105, - 0104, 0113, 0133, 0144, 0, /* 071 9 */ - 0022, 0122, 0024, 0124, 0, /* 072 : */ - 0010, 0121, 0122, 0024, 0124, 0, /* 073 ; */ - 0030, 0103, 0136, 0, /* 074 < */ - 0002, 0142, 0004, 0144, 0, /* 075 = */ - 0010, 0143, 0116, 0, /* 076 > */ - 0020, 0120, 0021, 0122, 0144, 0145, 0136, 0116, - 0105, 0104, 0, /* 077 ? */ - 0030, 0110, 0101, 0104, 0115, 0145, 0141, 0121, - 0112, 0113, 0124, 0134, 0131, 0, /* 100 @ */ - 0104, 0116, 0136, 0144, 0140, 0042, 0102, 0, /* 101 A */ - 0106, 0136, 0145, 0144, 0133, 0103, 0033, 0142, - 0141, 0130, 0100, 0, /* 102 B */ - 0041, 0130, 0110, 0101, 0105, 0116, 0136, 0145, 0, /* 103 C */ - 0106, 0136, 0145, 0141, 0130, 0100, 0, /* 104 D */ - 0003, 0133, 0046, 0106, 0100, 0140, 0, /* 105 E */ - 0106, 0146, 0033, 0103, 0, /* 106 F */ - 0023, 0143, 0141, 0130, 0110, 0101, 0105, 0116, - 0136, 0145, 0, /* 107 G */ - 0106, 0003, 0143, 0046, 0140, 0, /* 110 H */ - 0010, 0130, 0020, 0126, 0016, 0136, 0, /* 111 I */ - 0001, 0110, 0120, 0131, 0136, 0, /* 112 J */ - 0106, 0046, 0102, 0024, 0140, 0, /* 113 K */ - 0006, 0100, 0140, 0, /* 114 L */ - 0106, 0123, 0146, 0140, 0, /* 115 M */ - 0106, 0140, 0146, 0, /* 116 N */ - 0001, 0105, 0116, 0136, 0145, 0141, 0130, 0110, - 0101, 0, /* 117 O */ - 0106, 0136, 0145, 0144, 0133, 0103, 0, /* 120 P */ - 0030, 0110, 0101, 0105, 0116, 0136, 0145, 0141, - 0130, 0031, 0140, 0, /* 121 Q */ - 0106, 0136, 0145, 0144, 0133, 0103, 0033, 0140, 0, /* 122 R */ - 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, - 0105, 0116, 0136, 0145, 0, /* 123 S */ - 0020, 0126, 0006, 0146, 0, /* 124 T */ - 0006, 0101, 0110, 0130, 0141, 0146, 0, /* 125 U */ - 0006, 0120, 0146, 0, /* 126 V */ - 0006, 0100, 0123, 0140, 0146, 0, /* 127 W */ - 0146, 0006, 0140, 0, /* 130 X */ - 0020, 0123, 0106, 0046, 0123, 0, /* 131 Y */ - 0006, 0146, 0100, 0140, 0033, 0113, 0, /* 132 Z */ - 0030, 0110, 0116, 0136, 0, /* 133 [ */ - 0006, 0140, 0, /* 134 \ */ - 0010, 0130, 0136, 0116, 0, /* 135 ] */ - 0003, 0126, 0143, 0, /* 136 ^ */ - 0140, 0, /* 137 _ */ - 0016, 0134, 0, /* original was backward */ /* 140 ` */ - 0032, 0112, 0101, 0110, 0130, 0133, 0124, 0114, 0, /* 141 a */ - 0006, 0100, 0120, 0131, 0133, 0124, 0104, 0, /* 142 b */ - 0033, 0124, 0114, 0103, 0101, 0110, 0120, 0131, 0, /* 143 c */ - 0036, 0130, 0110, 0101, 0103, 0114, 0134, 0, /* 144 d */ - 0002, 0132, 0133, 0124, 0114, 0103, 0101, 0110, - 0120, 0, /* 145 e */ - 0010, 0115, 0126, 0136, 0145, 0023, 0103, 0, /* 146 f */ - 0200, 0320, 0331, 0134, 0114, 0103, 0101, 0110, - 0130, 0, /* 147 g */ - 0106, 0004, 0124, 0133, 0130, 0, /* 150 h */ - 0020, 0124, 0025, 0125, 0, /* 151 i */ - 0201, 0310, 0320, 0331, 0134, 0035, 0135, 0, /* 152 j */ - 0105, 0034, 0101, 0023, 0130, 0, /* 153 k */ - 0010, 0130, 0020, 0126, 0116, 0, /* 154 l */ - 0104, 0114, 0122, 0134, 0144, 0140, 0, /* 155 m */ - 0104, 0124, 0133, 0130, 0, /* 156 n */ - 0010, 0120, 0131, 0133, 0124, 0114, 0103, 0101, - 0110, 0, /* 157 o */ - 0200, 0104, 0124, 0133, 0131, 0120, 0100, 0, /* 160 p */ - 0030, 0110, 0101, 0103, 0114, 0134, 0330, 0341, 0, /* 161 q */ - 0104, 0124, 0133, 0, /* 162 r */ - 0001, 0110, 0120, 0131, 0122, 0112, 0103, 0114, - 0124, 0133, 0, /* 163 s */ - 0030, 0121, 0125, 0034, 0114, 0, /* 164 t */ - 0014, 0111, 0120, 0130, 0141, 0144, 0, /* 165 u */ - 0004, 0120, 0144, 0, /* 166 v */ - 0004, 0102, 0110, 0122, 0130, 0142, 0144, 0, /* 167 w */ - 0134, 0004, 0130, 0, /* 170 x */ - 0210, 0120, 0134, 0004, 0120, 0, /* 171 y */ - 0004, 0134, 0100, 0130, 0, /* 172 z */ - 0030, 0121, 0122, 0113, 0124, 0125, 0136, 0, /* 173 { */ - 0020, 0122, 0024, 0126, 0, /* 174 | */ - 0010, 0121, 0122, 0133, 0124, 0125, 0116, 0, /* 175 } */ - 0003, 0114, 0132, 0143, 0, /* 176 ~ */ - 0140, 0146, 0106, 0100, 0010, 0116, 0026, 0120, - 0030, 0136, 0 /* 177 rubout */ - }; - -/* pointers to start of stroke data for each character */ -static const unsigned char *sstroke[128] = { NULL }; /* init. at run time */ - -/* character generator; - * supports control characters, POPR on terminating character (VS60) - */ - -static int /* returns nonzero iff VS60 char terminate feature triggered */ -character(int c) -{ - /* following 3 tables map cs_index to adjustments for sub/superscript */ - static const unsigned char sus_left[4] = - {PSCALE(0), PSCALE(1), PSCALE(2), PSCALE(3)}; - static const unsigned char sub_down[4] = - {PSCALE(2), PSCALE(4), PSCALE(6), PSCALE(8)}; - static const unsigned char sup_up[4] = - {PSCALE(5), PSCALE(10), PSCALE(15), PSCALE(20)}; - int x, y; - int32 xbase, ybase, xnext, ynext; - - char_buf = c; - - if (shift_out) { - if (c >= 040) { - char_irq = 1; /* will generate a char intr. */ - return 0; /* presumably, no POPR on term? */ - } - if (c == 017) { /* SHIFT IN */ - shift_out = 0; - goto cesc; - } - - } else { /* !shift_out */ - - if (c <= 040) { - switch (c) { - - case 010: /* BACKSPACE */ - if (char_rotate) - ypos -= CSCALE(vt11_csp_w); - else - xpos -= CSCALE(vt11_csp_w); - break; - case 012: /* LINE FEED */ - if (char_rotate) - xpos += CSCALE(vt11_csp_h); - else - ypos -= CSCALE(vt11_csp_h); - break; - case 015: /* CARRIAGE RETURN */ - if (char_rotate) - ypos = yoff; - else - xpos = xoff; - break; - case 016: /* SHIFT OUT */ - shift_out = 1; - break; - - case 021: /* SUPERSCRIPT */ - if (VT11) - break; - if (char_rotate) { - xpos -= sup_up[cs_index]; - ypos -= sus_left[cs_index]; - } else { - xpos -= sus_left[cs_index]; - ypos += sup_up[cs_index]; - } - if (cs_index > 0) - char_scale = csi2csf[--cs_index]; - break; - case 022: /* SUBSCRIPT */ - if (VT11) - break; - if (char_rotate) { - xpos += sub_down[cs_index]; - ypos -= sus_left[cs_index]; - } else { - xpos -= sus_left[cs_index]; - ypos -= sub_down[cs_index]; - } - if (cs_index > 0) - char_scale = csi2csf[--cs_index]; - break; - case 023: /* END SUPERSCRIPT */ - if (VT11) - break; - if (cs_index < 3) - char_scale = csi2csf[++cs_index]; - if (char_rotate) { - xpos += sup_up[cs_index]; - ypos += sus_left[cs_index]; - } else { - xpos += sus_left[cs_index]; - ypos -= sup_up[cs_index]; - } - break; - case 024: /* END SUBSCRIPT */ - if (VT11) - break; - if (cs_index < 3) - char_scale = csi2csf[++cs_index]; - if (char_rotate) { - xpos -= sub_down[cs_index]; - ypos += sus_left[cs_index]; - } else { - xpos += sus_left[cs_index]; - ypos += sub_down[cs_index]; - } - break; - case 040: /* SPACE */ - goto space; - default: /* other control codes ignored */ - break; - } - goto cesc; - } - } - - /* VT11/VS60 doesn't draw any part of a character if its *baseline* is - (partly) offscreen; thus the top of a character might be clipped */ - /* (no allowance for descender, italic, or interchar. spacing) */ - - /* virtual CRT coordinates of this and the next character's "origin": */ - xbase = xnext = PNORM(xpos); - ybase = ynext = PNORM(ypos); - if (char_rotate) - ynext += (vt11_csp_w <= 12 ? 10 : 11); - else - xnext += (vt11_csp_w <= 12 ? 10 : 11); - - edge_indic = ONSCREEN(xbase, ybase) && !ONSCREEN(xnext, ynext); - edge_flag = edge_indic || - !ONSCREEN(xbase, ybase) && ONSCREEN(xnext, ynext); - /* (scaling cannot make spacing so large that it crosses the - "working surface" while going from offscreen to offscreen) */ - if (edge_flag && edge_intr_ena) { - edge_irq = 1; - goto space; - } - - if (!ONSCREEN(xbase, ybase) || !ONSCREEN(xnext, ynext)) - goto space; - - /* plot a (nominally on-screen) graphic symbol */ - - if (VT11) { - unsigned char col, prvcol; - - /* plot a graphic symbol (unscaled, unrotated) using a dot matrix */ - - /* not drawn in a serpentine manner; supports control characters */ - - /* draw pattern using 2x2 dot size, with fudges for spacing & italics */ - /* (looks very nice under all conditions at full resolution) */ - - if (c >= 0140) { /* lower-case */ - if (dots[c][0]) /* flag: with descender */ - ybase -= 4; - x = 1; /* skip first column (descender flag) */ - } else /* no descender */ - x = 0; - - prvcol = 0; - col = dots[c][x]; /* starting column bit pattern */ - for (; x < 6; ++x) { - int xllc = 2*x, yllc = 0; - unsigned char nxtcol = (x == 5) ? 0 : dots[c][x+1]; - - /* no LP hit on first or last column */ - lp_suppress = x == 0 || x == 5; - - for (y = 0; y < 8; ++y) { - int delay_skew; - int compress = vt11_csp_w <= 12 && x == 2; - int dot = col & (1<>y) == 2)) - ++xllc; /* shift within selected dots */ - } - ++yllc; - if (dot) { - illum2(xbase + xllc, ybase + yllc); - if (!compress || nxtdot == 0) - illum2(xbase + xllc + 1, ybase + yllc); - } - if (italics && delay_skew) - ++xllc; /* shift between selected dots */ - ++yllc; - } - if (vt11_csp_w <= 12 && x == 2) /* narrow spacing: */ - --xbase; /* slight compression */ - - prvcol = col; - col = nxtcol; - } - lp_suppress = 0; - - } else { /* VS60 */ - const unsigned char *p; /* -> stroke data */ - unsigned char s; /* encoded stroke */ - int32 xlast, ylast; /* "beam follower" within character */ - int32 xp = xpos, yp = ypos; /* save these (altered by vector2()) */ - - /* plot a graphic symbol using vector strokes */ - - /* initialize starting stroke pointers upon first use only */ - if (sstroke[0] == NULL) { - p = stroke; /* -> stroke data */ - - for (s = 0; s < 128; ++s) { /* for each ASCII code value s */ - sstroke[s] = p; /* code's stroke list starts here */ - while (*p++) /* 0 terminates the data */ - ; - } - } - - stroking = 1; /* prevents stroke clipping etc. and - tells vector2() to apply global - character scale factor */ - xlast = ylast = 0; - for (p = sstroke[c]; (s = *p) != 0; ++p) { - xnext = (s & 0070) >> 3; - if (xnext == 7) - xnext = -1; /* (kludge needed for pound sterling) */ - ynext = s & 0007; /* delay stretching for just a moment */ - if (s & 0200) - ynext -= 2; /* kludge for stroke below baseline */ - xnext *= 2; - if (italics) - xnext += ynext; - ynext *= 2; /* safe to stretch now */ - - if (s & 0100) { /* visible stroke */ - int32 dx = xnext - xlast, /* (okay if both 0) */ - dy = ynext - ylast; - - if (char_rotate) - vector2(1, -dy, dx); - else - vector2(1, dx, dy); - } else /* invisible stroke, can do faster */ - if (char_rotate) { - xpos = xp - CSCALE(ynext); - ypos = yp + CSCALE(xnext); - } else { - xpos = xp + CSCALE(xnext); - ypos = yp + CSCALE(ynext); - } - xlast = xnext; - ylast = ynext; - skip_start = (s & 0100) && (p[1] & 0100); /* avoid bright dot */ - } - /* skip_start was reset to 0 by the last iteration! */ - stroking = 0; - xpos = xp; /* restore for use in spacing (below) */ - ypos = yp; - } /* end of graphic character drawing */ - - space: - if (char_rotate) - ypos += CSCALE(vt11_csp_w); - else - xpos += CSCALE(vt11_csp_w); - - /* There may have been multiple LP hits during drawing; - the last one is the only one that can be reported. */ - - cesc: - if (char_escape && c == char_term) { /* (VS60) */ - pop(1); - return 1; - } else - return 0; -} - -/* - * Perform one display processor "cycle": - * If display processor is halted or awaiting sync, just performs "background" - * maintenance tasks and returns 0. - * Otherwise, completes any pending second CHAR or BSVECT (must be a RESUME - * after interrupt on first CHAR or BSVECT), or fetches one word from the - * display file and processes it. May post an interrupt; returns 1 if display - * processor is still running, or 0 if halted or an interrupt was posted. - * - * word_number keeps track of the state of multi-word graphic data parsing; - * word_number also serves to keep track of half-word for graphic data having - * two independent entities encoded within one word (CHAR or BSVECT). - * Note that, for the VT11, there might be control words (e.g. JMPA) embedded - * within the data! (We don't know of any application that exploits this.) - */ -int -vt11_cycle(int us, int slowdown) -{ - static vt11word inst; - static int i; - static int32 x, y, z, ex, ey, sxo, syo, szo; - int c; - int32 ez; - static uint32 usec = 0; /* cumulative */ - static uint32 msec = 0; /* ditto */ - uint32 new_msec; - INIT - /* keep running time counter; track state even when processor is idle */ - - new_msec = (usec += us) / 1000; - - if (msec / BLINK_COUNT != new_msec / BLINK_COUNT) - blink_off = !blink_off; - - /* if awaiting sync, look for next frame start */ - if (sync_period && (msec / sync_period != new_msec / sync_period)) - sync_period = 0; /* start next frame */ - - msec = new_msec; - - if ((sync_period || maint1 || !busy) && !maint2) - goto age_ret; /* just age the display */ - - /* fetch next word from display file (if needed) and process it */ - - if (word_number != 1 || (graphic_mode != CHAR && graphic_mode != BSVECT)) { - time_out = vt_fetch((uint32)((DPC+reloc)&0777777), &inst); - DPC += 2; - if (time_out) - goto bus_timeout; - DEBUGF(("0%06o: 0%06o\r\n", - (unsigned)(DPC - 2 + reloc) & 0777777, (unsigned)inst)); - if (finish_jmpa) - goto jmpa; - if (finish_jsra) - goto jsra; - } - /* else have processed only half the CHAR or BSVECT data word so far */ - - fetched: - - if (TESTBIT(inst,15)) { /* control */ - unsigned op = GETFIELD(inst,14,11); /* bits 14-11 */ -#if 1 /* XXX not sure about VT11 behavior */ - if (VS60) -#endif - word_number = 0; /* according to VT48 ES */ - switch (op) { - - case 7: /* Set Graphic Mode 0111 */ - case 011: /* Set Graphic Mode 1001 */ - if (VT11) - goto bad_ins; - /*FALLTHRU*/ - case 010: /* Set Graphic Mode 1000 */ - if (VT11) { - DEBUGF(("SGM 1000 IGNORED\r\n")); - break; - } - /*FALLTHRU*/ - case 0: /* Set Graphic Mode 0000 */ - case 1: /* Set Graphic Mode 0001 */ - case 2: /* Set Graphic Mode 0010 */ - case 3: /* Set Graphic Mode 0011 */ - case 4: /* Set Graphic Mode 0100 */ - case 5: /* Set Graphic Mode 0101 */ - case 6: /* Set Graphic Mode 0110 */ - DEBUGF(("Set Graphic Mode %u", op)); - graphic_mode = op; - word_number = 0; /* XXX redundant? (see above) */ - shift_out = 0; /* XXX is this right? */ - if (TESTBIT(inst,10)) { - intensity = GETFIELD(inst,9,7); - DEBUGF((" intensity=%d", (int)intensity)); - } - if (TESTBIT(inst,6)) { - lp0_intr_ena = TESTBIT(inst,5); - DEBUGF((" lp0_intr_ena=%d", (int)lp0_intr_ena)); - } - if (TESTBIT(inst,4)) { - blink_ena = TESTBIT(inst,3); - DEBUGF((" blink=%d", (int)blink_ena)); - } - if (TESTBIT(inst,2)) { - line_type = GETFIELD(inst,1,0); - DEBUGF((" line_type=%d", (int)line_type)); - } - DEBUGF(("\r\n")); - break; - - case 012: /* 1010: Load Name Register */ - if (VT11) - goto bad_ins; - name = GETFIELD(inst,10,0); - DEBUGF(("Load Name Register name=0%o\r\n", name)); - { static unsigned nmask[4] = { 0, 03777, 03770, 03600 }; - - if (search != 0 && ((name^assoc_name) & nmask[search]) == 0) - name_irq = 1; /* will cause name-match interrupt */ - } - break; - - case 013: /* 1011: Load Status C */ - if (VT11) - goto bad_ins; - DEBUGF(("Load Status C")); - if (TESTBIT(inst,9)) { - char_rotate = TESTBIT(inst,8); - DEBUGF((" char_rotate=d", (int)char_rotate)); - } - if (TESTBIT(inst,7)) { - cs_index = GETFIELD(inst,6,5); /* 0, 1, 2, 3 */ - char_scale = csi2csf[cs_index]; /* for faster CSCALE macro */ - DEBUGF((" cs_index=%d(x%d/4)", (int)cs_index, (int)char_scale)); - } - if (TESTBIT(inst,4)) { - vector_scale = GETFIELD(inst,3,0); - DEBUGF((" vector_scale=%d/4", (int)vector_scale)); - } - DEBUGF(("\r\n")); - break; - - case 014: /* 1100__ */ - if (VT11) /* other bits are "spare" */ - op = 0; /* always Display Jump Absolute */ - else - op = GETFIELD(inst,10,9); - switch (op) { - - case 00: /* 110000: Display Jump Absolute */ - finish_jmpa = 1; - break; - jmpa: - finish_jmpa = 0; - DPC = inst & ~1; - DEBUGF(("Display Jump Absolute 0%06o\r\n", (unsigned)inst)); - break; - - case 01: /* 110001: Display Jump Relative */ - ez = GETFIELD(inst,7,0);/* relative address (words) */ - ez *= 2; /* convert to bytes */ - /* have to be careful; DPC is unsigned */ - if (TESTBIT(inst,8)) - DPC -= ez; - else - DPC += ez; - /* DPC was already incremented by 2 */ - DEBUGF(("Display Jump Relative %c0%o\r\n", - "+-"[TESTBIT(inst,8)], (unsigned)ez)); - break; - - case 02: /* 110010: Display Jump to Subroutine Absolute */ - finish_jsra = 1; - break; - jsra: - finish_jsra = 0; - push(); /* save return address and parameters */ - DPC = inst & ~1; - DEBUGF(("Display Jump to Subroutine Absolute 0%06o\r\n", - (unsigned)inst)); -#if 1 /* VT48 manual and ES disagree with the diagnostic test! */ - jsr = 1; /* the diagnostic test needs this */ - goto check; /* (break would set jsr = 0) */ -#else - break; -#endif - case 03: /* 110011: Display Jump to Subroutine Relative */ - ez = GETFIELD(inst,7,0);/* relative address (words) */ - ez *= 2; /* convert to bytes */ - push(); /* save return address and parameters */ - /* have to be careful; DPC is unsigned */ - if (TESTBIT(inst,8)) - DPC -= ez; - else - DPC += ez; - /* DPC was already incremented by 2 */ - DEBUGF(("Display Jump to Subroutine Relative %c0%o\r\n", - "+-"[TESTBIT(inst,8)], (unsigned)ez)); -#if 0 /* VT48 manual and ES disagree with the diagnostic test! */ - jsr = 1; /* the hardware actually needs this? */ - goto check; /* (break would set jsr = 0) */ -#else - break; -#endif - } - break; - - case 015: /* 1101__ */ - if (VT11) - DEBUGF(("Display NOP\r\n")); - else { - op = GETFIELD(inst,10,9); - switch (op) { - - case 00: /* 110100: Load Scope Selection */ - /* also used as Display NOP */ - DEBUGF(("Load Scope Selection")); - c = TESTBIT(inst,8); - DEBUGF((" console=%d", c)); - if (TESTBIT(inst,7)) { - ez = TESTBIT(inst,6); - DEBUGF((" blank=%d", (int)!ez)); - if (c) - int1_scope = ez; - else - int0_scope = ez; - } - if (TESTBIT(inst,5)) { - ez = TESTBIT(inst,4); - DEBUGF((" lp_intr_ena=%d", (int)ez)); - if (c) - lp1_intr_ena = ez; - else - lp0_intr_ena = ez; - } - if (TESTBIT(inst,3)) { - ez = TESTBIT(inst,2); - DEBUGF((" lp_sw_intr_ena=%d", (int)ez)); - if (c) - lp1_sw_intr_ena = ez; - else - lp0_sw_intr_ena = ez; - } - DEBUGF(("\r\n")); - break; - - case 01: /* 110101: Display POP Not Restore */ - DEBUGF(("Display POP Not Restore\r\n")); - pop(0); /* sets new DPC as side effect */ - break; - - case 10: /* 110110: Display POP Restore */ - DEBUGF(("Display POP Restore\r\n")); - pop(1); /* sets new DPC as side effect */ - break; - - default: /* 110111: undocumented -- ignored? */ - DEBUGF(("Display NOP?\r\n")); - } - } - break; - - case 016: /* 1110: Load Status A */ - DEBUGF(("Load Status A")); - if ((internal_stop = TESTBIT(inst,10)) != 0)/* 11101 Display Stop */ - DEBUGF((" stop")); - if (TESTBIT(inst,9)) { - stop_intr_ena = TESTBIT(inst,8); - DEBUGF((" stop_intr_ena=%d", (int)stop_intr_ena)); - } - if (TESTBIT(inst,7)) { - lp_intensify = !TESTBIT(inst,6); - DEBUGF((" lp_intensify=%d", (int)lp_intensify)); - } - if (TESTBIT(inst,5)) { - italics = TESTBIT(inst,4); - DEBUGF((" italics=%d", (int)italics)); - } - refresh_rate = GETFIELD(inst,VS60?3:2,2); - DEBUGF((" refresh=%d", refresh_rate)); - switch (refresh_rate) { - case 0: /* continuous */ - sync_period = 0; - break; - case 1: /* VT11: 60 Hz; VS60: 30 Hz */ - sync_period = VT11 ? 17 : 33; - break; - case 2: /* VS60: 40 Hz */ - sync_period = 25; - break; - default: /* (case 3) VS60: external sync */ - sync_period = 17; /* fake a 60 Hz source */ - break; - } - if (internal_stop) - sync_period = 0; /* overridden */ - if (VS60 && TESTBIT(inst,1)) { - menu = TESTBIT(inst,0); - DEBUGF((" menu=%d", (int)menu)); - } - DEBUGF(("\r\n")); - break; - - case 017: /* 1111_ */ - if (VS60 && TESTBIT(inst,10)) { /* 11111: Load Status BB */ - DEBUGF(("Load Status BB")); - if (TESTBIT(inst,7)) { - depth_cue_proc = TESTBIT(inst,6); - DEBUGF((" depth_cue_proc=%d", (int)depth_cue_proc)); - } - if (TESTBIT(inst,5)) { - edge_intr_ena = TESTBIT(inst,4); - DEBUGF((" edge_intr_ena=%d", (int)edge_intr_ena)); - } - if (TESTBIT(inst,3)) { - file_z_data = TESTBIT(inst,2); - DEBUGF((" file_z_data=%d", (int)file_z_data)); - } - if (TESTBIT(inst,1)) { - char_escape = TESTBIT(inst,0); - DEBUGF((" char_escape=%d", (int)char_escape)); - } - } else { /* 11110: Load Status B */ - DEBUGF(("Load Status B")); - if (VS60 && TESTBIT(inst,9)) { - color = GETFIELD(inst,8,7); - DEBUGF((" color=%d", (int)color)); - } - if (TESTBIT(inst,6)) { - graphplot_step = GETFIELD(inst,5,0); - DEBUGF((" graphplot_step=%d", (int)graphplot_step)); - } - } - DEBUGF(("\r\n")); - break; - - default: - bad_ins: DEBUGF(("SPARE COMMAND 0%o\r\n", op)); - /* "display processor hangs" */ - DPC -= 2; /* hang around scene of crime */ - break; - - } /* end of control instruction opcode switch */ - jsr = 0; - - } else { /* graphic data */ - - lp0_flag = 0; /* XXX maybe not for OFFSET? */ - if (word_number == 0) - offset = 0; - -#define MORE_DATA { ++word_number; goto check; } - - switch (graphic_mode) { - - case CHAR: - if (word_number == 0) { - c = GETFIELD(inst,6,0); - DEBUGF(("char1 %d (", c)); - DEBUGF((040 <= c && c < 0177 ? "'%c'" : "0%o", c)); - DEBUGF((")\r\n")); - if (character(c)) /* POPR was done; end chars */ - break; - MORE_DATA /* post any intrs now */ - } - c = GETFIELD(inst,15,8); - DEBUGF(("char2 %d (", c)); - DEBUGF((040 <= c && c < 0177 ? "'%c'" : "0%o", c)); - DEBUGF((")\r\n")); - (void)character(c); - break; - - case SVECTOR: - if (word_number == 0) { - i = TESTBIT(inst,14); /* inten_ena: beam on */ - x = GETFIELD(inst,12,7);/* delta_x */ - if (TESTBIT(inst,13)) - x = -x; - y = GETFIELD(inst,5,0); /* delta_y */ - if (TESTBIT(inst,6)) - y = -y; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { /* (VS60) */ - z = GETFIELD(inst,9,2); /* delta_z */ - if (TESTBIT(inst,13)) - z = -z; - DEBUGF(("short vector i%d (%d,%d,%d)\r\n", - i, (int)x, (int)y, (int)z)); - vector3(i, x, y, z); - } else { - DEBUGF(("short vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); - vector2(i, x, y); - } - break; - - case LVECTOR: - if (word_number == 0) { - ex = VS60 && TESTBIT(inst,12); - i = TESTBIT(inst,14); - x = GETFIELD(inst,9,0); /* delta_x */ - if (TESTBIT(inst,13)) - x = -x; - MORE_DATA - } - if (word_number == 1) { - y = GETFIELD(inst,9,0); /* delta_y */ - if (TESTBIT(inst,13)) - y = -y; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { /* (VS60) */ - if (ex) - goto norot; - z = GETFIELD(inst,9,2); /* delta_z */ - if (TESTBIT(inst,13)) - z = -z; - DEBUGF(("long vector i%d (%d,%d,%d)\r\n", - i, (int)x, (int)y, (int)z)); - vector3(i, x, y, z); - } else { - if (ex) - norot: /* undocumented and probably nonfunctional */ - DEBUGF(("ROTATE NOT SUPPORTED\r\n")); - else { - DEBUGF(("long vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); - vector2(i, x, y); - } - } - break; - - case POINT: /* (or OFFSET, if VS60) */ - /* [VT48 manual incorrectly says point data doesn't use sign bit] */ - if (word_number == 0) { - ex = GETFIELD(inst,(VS60?11:9),0); - offset = VS60 && TESTBIT(inst,12); /* offset flag */ - if (!offset) - i = TESTBIT(inst,14); /* for point only */ - if (VS60) - if (sxo = TESTBIT(inst,13)) /* sign bit */ - ex = -ex; - /* XXX if VT11, set xpos/xoff now?? */ - MORE_DATA - } - if (word_number == 1) { - ey = GETFIELD(inst,(VS60?11:9),0); - if (VS60) - if (syo = TESTBIT(inst,13)) /* sign bit */ - ey = -ey; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { /* (VS60) */ - ez = GETFIELD(inst,11,2); - if (szo = TESTBIT(inst,13)) /* sign bit */ - ez = -ez; - if (offset) { /* OFFSET rather than POINT */ - DEBUGF(("offset (%d,%d,%d)\r\n", (int)ex,(int)ey,(int)ez)); - xoff = PSCALE(ex); - yoff = PSCALE(ey); - zoff = PSCALE(ez * 4); /* XXX include bits 1:0 ? */ - s_xoff = sxo; - s_yoff = syo; - s_zoff = szo; - } else { - DEBUGF(("point i%d (%d,%d,%d)\r\n", i, - (int)ex, (int)ey, (int)ez)); - point3(i, ex, ey, ez, VS60); - } - } else { - if (offset) { /* (VS60) OFFSET rather than POINT */ - DEBUGF(("offset (%d,%d)\r\n", (int)ex, (int)ey)); - xoff = PSCALE(ex); - yoff = PSCALE(ey); - s_xoff = sxo; - s_yoff = syo; - } else { - DEBUGF(("point i%d (%d,%d)\r\n", i, (int)ex, (int)ey)); - point2(i, ex, ey, VS60); - } - } - break; - - case GRAPHX: /* (or BLVECT if VS60) */ - i = TESTBIT(inst,14); - if (VS60 && TESTBIT(inst,10)) - goto blv; /* (VS60) BLVECT rather than GRAPHX */ - else { - ex = GETFIELD(inst,9,0); - DEBUGF(("graphplot x i%d (%d)\r\n", i, (int)ex)); - ey = ypos - yoff + VSCALE(graphplot_step); - /* XXX VT48 ES says first datum doesn't increment Y?? */ - point2(i, ex, PNORM(ey), VS60); /* approx. */ - ypos = ey; /* more precise, if PSCALEF > 1 */ - } - break; - - case GRAPHY: /* (or BLVECT if VS60) */ - i = TESTBIT(inst,14); - if (VS60 && TESTBIT(inst,10)) { - blv: /* (VS60) BLVECT rather than GRAPHY */ - x = GETFIELD(inst,13,11); /* direction */ - y = GETFIELD(inst,9,0); /* length */ - DEBUGF(("basic long vector i%d d%d l%d\r\n", - i, (int)x, (int)y)); - basic_vector(i, (int)x, (int)y); - } else { - ey = GETFIELD(inst,9,0); - DEBUGF(("graphplot y i%d (%d)\r\n", i, (int)ey)); - ex = xpos - xoff + VSCALE(graphplot_step); - /* XXX VT48 ES says first datum doesn't increment X?? */ - point2(i, PNORM(ex), ey, VS60); /* approx. */ - xpos = ex; /* more precise, if PSCALEF > 1 */ - } - break; - - case RELPOINT: - if (word_number == 0) { - i = TESTBIT(inst,14); - ex = GETFIELD(inst,12,7); - if (TESTBIT(inst,13)) - ex = -ex; - ey = GETFIELD(inst,5,0); - if (TESTBIT(inst,6)) - ey = -ey; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { /* (VS60) */ - ez = GETFIELD(inst,9,2); - if (TESTBIT(inst,13)) - ez = -ez; - DEBUGF(("relative point i%d (%d,%d,%d)\r\n", - i, (int)ex, (int)ey, (int)ez)); - ex = xpos - xoff + VSCALE(ex); - ey = ypos - yoff + VSCALE(ey); - ez = zpos - zoff + VSCALE(ez * 4); - point3(i, PNORM(ex), PNORM(ey), PNORM(ez) / 4, 1); /* approx */ - zpos = ez; /* more precise, if PSCALEF > 1 */ - } else { - DEBUGF(("relative point i%d (%d,%d)\r\n", i, (int)ex, (int)ey)); - ex = xpos - xoff + VSCALE(ex); - ey = ypos - yoff + VSCALE(ey); - point2(i, PNORM(ex), PNORM(ey), 1); /* approx. */ - } - xpos = ex; /* more precise, if PSCALEF > 1 */ - ypos = ey; - break; - - /* the remaining graphic data types are supported by the VS60 only */ - - case BSVECT: /* (VS60) */ - if (word_number == 0) { - i = TESTBIT(inst,14); - x = GETFIELD(inst,6,4); /* direction 0 */ - y = GETFIELD(inst,3,0); /* length 0 */ - ex = GETFIELD(inst,13,11); /* direction 1 */ - ey = GETFIELD(inst,10,7); /* length 1 */ - DEBUGF(("basic short vector1 i%d d%d l%d\r\n", - i, (int)x, (int)y)); - basic_vector(i, (int)x, (int)y); - MORE_DATA - } - DEBUGF(("basic short vector2 i%d d%d l%d\r\n", i, (int)ex,(int)ey)); - basic_vector(i, (int)ex, (int)ey); - break; - - case ABSVECTOR: /* (VS60) */ - /* Note: real VS60 can't handle a delta of more than +-4095 */ - if (word_number == 0) { - i = TESTBIT(inst,14); - x = GETFIELD(inst,11,0); - if (TESTBIT(inst,13)) - x = -x; - MORE_DATA - } - if (word_number == 1) { - y = GETFIELD(inst,11,0); - if (TESTBIT(inst,13)) - y = -y; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { - z = GETFIELD(inst,11,2); - if (TESTBIT(inst,13)) - z = -z; - DEBUGF(("absolute vector i%d (%d,%d,%d)\r\n", - i, (int)x, (int)y, (int)z)); - ex = VSCALE(x) + xoff; - ey = VSCALE(y) + yoff; - ez = VSCALE(z * 4) + zoff; - vector3(i, PNORM(ex - xpos), PNORM(ey - ypos), - PNORM(ez - zpos) / 4); /* approx. */ - zpos = ez; /* more precise, if PSCALEF > 1 */ - } else { - DEBUGF(("absolute vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); - ex = VSCALE(x) + xoff; - ey = VSCALE(y) + yoff; - vector2(i, PNORM(ex - xpos), PNORM(ey - ypos)); /* approx. */ - } - xpos = ex; /* more precise, if PSCALEF > 1 */ - ypos = ey; - break; - - case CIRCLE: /* (VS60) */ - if (word_number == 0) { - i = TESTBIT(inst,14); - x = GETFIELD(inst,9,0); /* delta cx */ - if (TESTBIT(inst,13)) - x = -x; - MORE_DATA - } - if (word_number == 1) { - y = GETFIELD(inst,9,0); /* delta cy */ - if (TESTBIT(inst,13)) - y = -y; - MORE_DATA - } - if (word_number == 2) { - if (file_z_data) { - z = GETFIELD(inst,11,2); /* delta cz */ - if (TESTBIT(inst,13)) - z = -z; - MORE_DATA - } - } - if (word_number == 2 + file_z_data) { - ex = GETFIELD(inst,9,0); /* delta ex */ - if (TESTBIT(inst,13)) - ex = -ex; - MORE_DATA - } - if (word_number == 3 + file_z_data) { - ey = GETFIELD(inst,9,0); /* delta ey */ - if (TESTBIT(inst,13)) - ey = -ey; - if (file_z_data) - MORE_DATA - } - if (file_z_data) { - ez = GETFIELD(inst,11,2); /* delta ez */ - if (TESTBIT(inst,13)) - ez = -ez; - DEBUGF(("circle/arc i%d C(%d,%d,%d) E(%d,%d,%d)\r\n", - i, (int)x, (int)y, (int)z, (int)ex, (int)ey, (int)ez)); - conic3(i, x, y, z, ex, ey, ez); /* approx. */ - } else { - DEBUGF(("circle/arc i%d C(%d,%d) E(%d,%d)\r\n", - i, (int)x, (int)y, (int)ex, (int)ey)); - conic2(i, x, y, ex, ey); - } - break; - - default: /* "can't happen" */ - DPC -= 2; /* hang around scene of crime */ - break; - - } /* end of graphic_mode switch */ - word_number = 0; - - } /* end of instruction decoding and execution */ - goto check; - - bus_timeout: - DEBUGF(("TIMEOUT\r\n")); - /* fall through to check (time_out has already been set) */ - - check: - - /* post an interrupt if conditions are right; - because this simulation has no pipeline, only one is active at a time */ - - if (lp0_sw_state != lp0_sw) { - lp0_sw_state = lp0_sw; /* track switch state */ - if (lp0_sw_intr_ena) - lpsw_irq = 1; - } - - /* lphit_irq triggering should await data mode, - but this is simpler and (probably) good enough */ - if (lphit_irq || lpsw_irq || edge_irq) - vt_lpen_intr(); /* post graphic interrupt to host */ - else if ((internal_stop && stop_intr_ena) || (ext_stop/*&& stop_intr_ena*/)) - vt_stop_intr(); /* post stop interrupt to host */ - else if (char_irq || stack_over || stack_under || time_out) - vt_char_intr(); /* post character interrupt to host */ - else if (name_irq) - vt_name_intr(); /* post name-match interrupt to host */ -#if 1 /* XXX this might be a mistake */ - else /* handle any pending 2nd CHAR/BSVECT */ - if (word_number == 1 && (graphic_mode==CHAR || graphic_mode==BSVECT)) - goto fetched; -#endif - - /* fall through to age_ret */ - - age_ret: - display_age(us, slowdown); - return !maint1 && !maint2 && busy; -} /* vt11_cycle */ +/* + * $Id: vt11.c,v 1.28 2005/08/06 21:09:04 phil Exp $ + * Simulator Independent VT11/VS60 Graphic Display Processor Simulation + * Phil Budne + * September 13, 2003 + * Substantially revised by Douglas A. Gwyn; last edited 05 Aug 2005 + * + * from EK-VT11-TM-001, September 1974 + * and EK-VT48-TM-001, November 1976 + * with help from Al Kossow's "VT11 instruction set" posting of 21 Feb 93 + * and VT48 Engineering Specification Rev B + * and VS60 diagnostic test listings, provided by Alan Frisbie + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +/* + * The VT11 is a calligraphic display-file device used in the GT4x series + * of workstations (PDP-11/04,34,40 based). + * + * The VS60 is an improved, extended, upward-compatible version of the + * VT11, used in the GT62 workstation (PDP-11/34 based). It supports + * dual consoles (CRTs with light pens), multiple phosphor colors, 3D + * depth cueing, and circle/arc generator as options. We do not know + * whether any of these options were ever implemented or delivered. + * Apparently a later option substituted a digitizing-tablet correlator + * for the light pen. The VS60 has a 4-level silo (graphic data pipeline) + * which for reasons of simplicity is not implemented in this simulation; + * the only visible effect is that DZVSC diagnostic tests 110 & 111 will + * report failure. + * + * The VSV11/VS11 is a color raster display-file device (with joystick + * instead of light pen) with instructions similar to the VT11's but + * different enough that a separate emulation should be created by + * editing a copy of this source file rather than trying to hack it into + * this one. Very likely, the display (phosphor decay) simulation will + * also require revision to handle multiple colors. + * + * There were further models in this series, but they appear to have + * little if any compatibility with the VT11. + * + * Much later, DEC produced a display system it called the VS60S, but + * that doesn't seem to bear any relationship to the original VS60. + * + * A PDP-11 system has at most one display controller attached. + * In principle, a VT11 or VS60 can also be used on a VAX Unibus. + * + * STATUS: + * + * Clipping is not implemented properly for arcs. + * + * This simulation passes all four MAINDEC VS60 diagnostics and the + * DEC/X11 VS60 system exerciser, with the following exceptions: + * + * MD-11-DZVSA-A, VS60 instruction test part I, test 161: + * Failure to time-out an access to a "nonexistent" bus address, when the + * system is configured with so much memory that the probed address + * actually responds; this is a deficiency in the diagnostic itself. + * + * MD-11-DZVSB-A, VS60 instruction test part II: + * No exceptions. + * + * MD-11-DZVSC-B, VS60 instruction test part III, tests 107,110,111: + * Memory address test fails under SIMH, due to SIMH not implementing + * KT11 "maintenance mode", in which the final destination address (only) + * is relocated. When SIMH is patched to fix this, the test still fails + * due to a bug in the diagnostic itself, namely a call to DPCONV1 which + * tests a condition code that is supposed to pertain to R0 but which + * hasn't been set up. Swapping the two instructions before the call to + * DPCONV1 corrects this, and then this test passes. + * Graphic silo content tests fail, since the silo pipeline is not + * simulated; there are no plans to fix this, since it serves no other + * purpose in this simulation and would adversely affect performance. + * + * MD-11-DZVSD-B, VS60 visual display test, frame 13: + * "O" character sizes are slightly off, due to optimization for raster + * display rather than true stroking; there are no plans to change this. + * + * MD-11-DZVSE-A0, XXDP VS60 visual display exerciser: + * No visible exceptions. Light-pen interrupts might not be handled + * right, since they're reported as errors and cause display restart. + * (XXX Need to obtain source listing to check this.) + */ + +#ifdef DEBUG_VT11 +#include +#endif +#include /* memset */ +#ifndef NO_CONIC_OPT +#include /* atan2, cos, sin, sqrt */ +#endif + +#include "xy.h" /* XY plot interface */ +#include "vt11.h" + +#define BITMASK(n) (1<<(n)) /* PDP-11 bit numbering */ + +/* mask for a field */ +#define FIELDMASK(START,END) ((1<<((START)-(END)+1))-1) + +/* extract a field */ +#define GETFIELD(W,START,END) (((W)>>(END)) & FIELDMASK(START,END)) + +/* extract a 1-bit field */ +#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0) + +#ifdef DEBUG_VT11 +#define DEBUGF(X) do { printf X; fflush(stdout); } while (0) +#else +#define DEBUGF(X) +#endif + +/* + * Note about coordinate signedness and wrapping: + * + * The documentation for these devices says confusing things about coordinate + * wrapping and signedness. The VT11 maintains 12-bit coordinate registers + * (wrapping 4096 -> 0), while the VS60 maintains 14-bit coordinate registers. + * Coordinate arithmetic (such as adding a vector "delta" to the current + * position) that overflows merely drops the extra bits; this can be treated + * as use of twos-complement representation for the position registers, whereas + * the VS60 offset registers and the display file itself use a signed-magnitude + * representation. (Except that JMP/JSR-relative delta uses twos-complement!) + * This simulation tracks position using at least 32 bits including sign; this + * can overflow only for a pathological display file. + * + * Note about scaling and offsets: + * + * The VS60 supports character and vector scaling and position offsets. The + * X, Y, and Z position register values always include scaling and offsets. + * It is not clear from the manual whether or not there are two "guard bits", + * which would better track the virtual position when using a scale factor of + * 3/4, 1/2, or 1/4. Most likely, there are no guard bits (this has been + * confirmed by diagnostic DZVSB test 31). This simulation maintains position + * values and offsets both multiplied by PSCALEF, which should be 4 to obtain + * maximum drawing precision, or 1 to mimic the actual non-guard-bit display + * hardware. These internal coordinates are "normalized" (converted to correct + * virtual CRT coordinates) before being reported via the position/offset + * registers. The normalized Z position register value's 2 lowest bits are + * always 0. + * Example of why this matters: Set vector scale 1/2; draw successive vectors + * with delta X = 1, 1, and -2. With guard bits, the final and original X + * positions are the same; without guard bits, the final X position is one + * unit to the left of the original position. This effect accumulates over a + * long sequence of vectors, leading to quite visible distortion of the image. + * + * Light-pen and edge-interrupt positions always have "on-screen" values. + */ + +#ifndef PSCALEF +#if 0 /* XXX enable only during development, to catch any oversights */ +#define PSCALEF 4 /* position scale factor 4 for maximum precision */ +#else +#define PSCALEF 1 /* position scale factor 1 for accurate simulation */ +#endif +#endif + +#define PSCALE(x) ((x) * PSCALEF) +#define PNORM(x) ((x) / PSCALEF) +/* virtual_CRT_coordinate = PNORM(scaled_value) */ + +/* VS60 scales points/vectors and characters separately */ +#define VSCALE(x) ((PSCALE(vector_scale * (int32)(x)) + ((x)>=0 ? 1 : -1)) / 4) +#define CSCALE(x) ((PSCALE(char_scale * (int32)(x)) + ((x)>=0 ? 1 : -1)) / 4) +/* (The "+ ((x)>=0 ? 1 : -1)" above is needed to pass the diagnostics.) */ + +#define ABS(x) ((x) >= 0 ? (x) : -(x)) +#define TWOSCOMP(x) ((x) >= 0 ? (x) : ~(-(x)-1)) + +enum display_type vt11_display = DISPLAY_TYPE; /* DIS_VR{14,17,48} */ +int vt11_scale = PIX_SCALE; /* RES_{FULL,HALF,QUARTER,EIGHTH} */ +unsigned char vt11_init = 0; /* set after display_init() called */ +#define INIT { if (!vt11_init) { display_init(vt11_display, vt11_scale); \ + vt11_init = 1; vt11_reset(); } } + +/* state visible to host */ + +/* The register and field names are those used in the VS60 manual (minus the + trailing "flag", "code", "status", or "select"); the VT11 manual uses + somewhat different names. */ + +/* + * Display Program Counter + * Read/Write (reading returns the *relocated* DPC bits [15:0]) + * DPC address 15:1 + * resume 0 + */ +#define DPC stack[8]._dpc /* Display PC (always even) */ +static uint16 bdb = 0; /* Buffered Data Bits register; + see comment in vt11_get_dpc() */ + +/* + * Mode Parameter Register + * Read Only, except that writing to it beeps the LK40 keyboard's bell + * internal stop flag 15 + * graphic mode code 14:11 + * intensity level 10:8 + * LP con. 0 hit flag 7 + * shift out status 6 + * edge indicator 5 + * italics status 4 + * blink status 3 + * edge flag status 2 (VS60 only) + * line type register status 1:0 + */ +static unsigned char internal_stop = 0; /* 1 bit: stop display */ +static unsigned char mode_field = 0; /* copy of control instr. bits 14-11 */ +#define graphic_mode stack[8]._mode /* 4 bits: sets type for graphic data */ +enum mode { CHAR=0, SVECTOR, LVECTOR, POINT, GRAPHX, GRAPHY, RELPOINT, /* all */ + BSVECT, CIRCLE, ABSVECTOR /* VS60 only */ +}; + +#define intensity stack[8]._intens /* 3 bits: 0 => dim .. 7 => bright */ +static unsigned char lp0_hit = 0; /* 1 bit: light pen #0 detected hit */ +static unsigned char so_flag = 0; /* 1 bit: illegal char. in SO mode */ +static unsigned char edge_indic = 0; /* 1 bit: crossing visible area edge */ +#define italics stack[8]._italics /* 1 bit: use italic font */ +#define blink_ena stack[8]._blink /* 1 bit: blink graphic item */ +static unsigned char edge_flag = 0; /* 1 bit: edge intr if enabled (VS60) */ +#define line_type stack[8]._ltype /* 2 bits: style for drawing vectors */ +enum linetype { SOLID=0, LONG_DASH, SHORT_DASH, DOT_DASH }; + +/* + * Graphplot Increment and X Position Register + * Read Only + * graphplot increment register value 15:10 + * X position register value 9:0 + */ +static unsigned char graphplot_step = 0;/* (scaled) graphplot step increment */ +static int32 xpos = 0; /* X position register * PSCALEF */ + /* note: offset has been applied! */ +static int lp_xpos; /* (normalized) */ +static int edge_xpos; /* (normalized) */ + +/* + * Character Code and Y Position Register + * Read Only + * character register contents 15:10 + * Y position register value 9:0 + */ +static unsigned char char_buf = 0; /* (only lowest 6 bits reported) */ +static int32 ypos = 0; /* Y position register * PSCALEF */ + /* note: offset has been applied! */ +static int lp_ypos; /* (normalized) */ +static int edge_ypos; /* (normalized) */ + +/* + * Relocate Register (VS60 only) + * Read/Write + * spare 15:12 + * relocate register value[17:6] 11:0 + */ +static uint32 reloc = 0; /* relocation, aligned with DPC */ + +/* + * Status Parameter Register (VS60 only) + * Read Only, except for bit 7 (1 => external stop request) + * display busy status 15 + * stack overflow status 13 + * stack underflow status 12 + * time out status 11 + * char. rotate status 10 + * char. scale index 9:8 + * external stop flag 7 + * menu status 6 + * relocated DPC bits [17:16] 5:4 + * vector scale 3:0 + */ +#define busy (!(stopped || lphit_irq || lpsw_irq || edge_irq || char_irq \ + || stack_over || stack_under || time_out || name_irq)) + /* 1 bit: display initiated | resumed */ +static unsigned char stack_over = 0; /* 1 bit: "push" with full stack */ +static unsigned char stack_under = 0; /* 1 bit: "pop" with empty stack */ +static unsigned char time_out = 0; /* 1 bit: timeout has occurred */ +#define char_rotate stack[8]._crotate /* 1 bit: rotate chars 90 degrees CCW */ +#define cs_index stack[8]._csi /* character scale index 0..3 */ +static unsigned char ext_stop = 0; /* 1 bit: stop display */ +#define menu stack[8]._menu /* 1 bit: VS60 graphics in menu area */ +#define vector_scale stack[8]._vscale /* non-character scale factor * 4 */ + +/* + * X Offset Register (VS60 only) + * Read/Write + * upper X position bits 15:12 (read) + * sign of X dynamic offset 13 (write) + * X dynamic offset 11:0 + */ +static unsigned char s_xoff = 0; /* sign bit for xoff (needed for -0) */ +static int32 xoff = 0; /* X offset register * PSCALEF */ + +/* + * Y Offset Register (VS60 only) + * Read/Write + * upper Y position bits 15:12 (read) + * sign of Y dynamic offset 13 (write) + * Y dynamic offset 11:0 + */ +static unsigned char s_yoff = 0; /* sign bit for yoff (needed for -0) */ +static int32 yoff = 0; /* Y offset register * PSCALEF */ + +/* + * Associative Name Register (VS60 only) + * Write Only + * search code change enable 14 + * search code 13:12 + * name change enable 11 + * associative name 10:0 + */ +static unsigned char search = 0; /* 00=> no search, no interrupt + 01 => intr. on 11-bit compare + 10 => intr. on high-8-bit compare + 11 => intr. on high-4-bit compare */ +static unsigned assoc_name = 0; /* compare value */ + +/* + * Slave Console/Color Register (VS60 only) + * Read/Write * + * inten enable con. 0 15 + * light pen hit flag con. 0 14 * + * LP switch on flag con. 0 13 * + * LP switch off flag con. 0 12 * + * LP flag intr. enable con. 0 11 + * LP switch flag intr. enable con. 0 10 + * inten enable con. 1 9 + * light pen hit flag con. 1 8 * + * LP switch on flag con. 1 7 * + * LP switch off flag con. 1 6 * + * LP flag intr. enable con. 1 5 + * LP switch flag intr. enable con. 1 4 + * color 3:2 + * + * * indicates that maintenance switch 3 must be set to write these bits; + * the other bits are not writable at all + */ +#define int0_scope stack[8]._inten0 /* enable con 0 for all graphic data */ +/* lp0_hit has already been defined, under Mode Parameter Register */ +static unsigned char lp0_down = 0; /* 1 bit: LP #0 switch was depressed */ +static unsigned char lp0_up = 0; /* 1 bit: LP #0 switch was released */ +#define lp0_intr_ena stack[8]._lp0intr /* generate interrupt on LP #0 hit */ +#define lp0_sw_intr_ena stack[8]._lp0swintr /* generate intr. on LP #0 sw chg */ +#define int1_scope stack[8]._inten1 /* enable con 1 for all graphic data */ +/* following 2 flags only mutable via writing this register w/ MS3 set: */ +static unsigned char lp1_hit = 0; /* 1 bit: light pen #1 detected hit */ +static unsigned char lp1_down = 0; /* 1 bit: LP #1 switch was depressed */ +static unsigned char lp1_up = 0; /* 1 bit: LP #1 switch was released */ +#define lp1_intr_ena stack[8]._lp1intr /* generate interrupt on LP #1 hit */ +#define lp1_sw_intr_ena stack[8]._lp1swintr /* generate intr. on LP #1 sw chg */ + +enum scolor { GREEN=0, YELLOW, ORANGE, RED }; +#define color stack[8]._color /* 2 bits: VS60 color option */ + +/* + * Name Register (VS60 only) + * Read Only + * name/assoc name match flag 15 + * search code 13:12 + * name 10:0 + */ +static unsigned char name_irq = 0; /* 1 bit: name matches associative nm */ + /* (always interrupts on name match!) */ +/* search previously defined, under Associative Name Register */ +#define name stack[8]._name /* current name from display file */ + +/* + * Stack Data Register (VS60 only) + * Read Only + * stack data 15:0 (as selected by Stk. Addr./Maint. Reg.) + * + * On the actual hardware there are 2 32-bit words per each of 8 stack levels. + * At the PDP-11 these appear to be 4 16-bit words ("stack bytes") per level. + */ +/* It is important to note that setting the stack level via SAR doesn't change + the parameters currently in effect; only JSR/POPR does that. To speed up + JSR/POPR, the current state is implemented as an extra stack frame, so that + push/pop is done by copying a block rather than lots of individual variables. + There are thus 9 stack elements, 8 stack entries [0..7] and the current state + [8]. Mimicking the actual hardware, the stack level *decreases* upon JSR. + */ + +static struct frame + { + vt11word _dpc; /* Display Program Counter (even) */ + unsigned _name; /* (11-bit) name from display file */ + enum mode _mode; /* 4 bits: sets type for graphic data */ + unsigned char _vscale; /* non-character scale factor * 4 */ + unsigned char _csi; /* character scale index 0..3 */ + unsigned char _cscale; /* character scale factor * 4 */ + unsigned char _crotate; /* rotate chars 90 degrees CCW */ + unsigned char _intens; /* intensity: 0 => dim .. 7 => bright */ + enum linetype _ltype; /* line type (long dash, etc.) */ + unsigned char _blink; /* blink enable */ + unsigned char _italics; /* italicize characters */ + unsigned char _so; /* currently in shift-out mode */ + unsigned char _menu; /* VS60 graphics in menu area */ + unsigned char _cesc; /* perform POPR on char. term. match */ + unsigned char _edgeintr; /* generate intr. on edge transition */ + unsigned char _lp1swintr; /* generate intr. on LP #1 switch chg */ + unsigned char _lp0swintr; /* generate intr. on LP #0 switch chg */ + unsigned char _lp1intr; /* generate interrupt on LP #1 hit */ + unsigned char _inten1; /* blank cons. 1 for all graphic data */ + unsigned char _lp0intr; /* generate interrupt on LP #0 hit */ + unsigned char _inten0; /* blank cons. 0 for all graphic data */ + unsigned char _bright; /* visually indicate hit on entity */ + unsigned char _stopintr; /* generate interrupt on intern. stop */ + enum scolor _color; /* scope display color (option) */ + unsigned char _zdata; /* flag: display file has Z coords */ + unsigned char _depth; /* flag: display Z using depth cue */ + } stack[9] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, CHAR, 4, 1, 4, 0, 4, SOLID, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + }; + +#define char_scale stack[8]._cscale /* character scale factor * 4 */ + /* _cscale must track _csi! */ +static const unsigned char csi2csf[4] = { 2, 4, 6, 8 }; /* maps cs_index to " */ +#define shift_out stack[8]._so /* flag: using shift-out char. set */ +#define char_escape stack[8]._cesc /* perform POPR on char. term. match */ +#define edge_intr_ena stack[8]._edgeintr /* generate intr. on edge transit */ +#define lp_intensify stack[8]._bright /* if VT11, 20us bright spot; + if VS60, brighten the entity */ +#define stop_intr_ena stack[8]._stopintr /* generate intr. on internal stop */ +#define file_z_data stack[8]._zdata /* flag: display file has Z coords */ +#define depth_cue_proc stack[8]._depth /* flag: display Z using depth cue */ + +/* + * Character String Terminate Register (VS60 only) + * Read/Write + * char. term. reg. enable 7 + * character terminate code 6:0 + */ +static int char_term = 0; /* char. processing POPRs after this */ + +/* + * Stack Address/Maintenance Register (VS60 only) + * Read/Write + * maint. sw. 4 15 + * maint. sw. 3 14 + * maint. sw. 2 13 + * maint. sw. 1 12 + * offset mode status 10 + * jump to subr. ?rel. status 9 (diagnostic requires this be JSR abs.!) + * word 2 status 8 + * word 1 status 7 + * word 0 status 6 + * stack reset status 5 + * stack level select 4:2 (manual has this messed up) + * stack halfword select 1:0 (manual has this messed up) + */ +static unsigned char maint4 = 0; /* 1 bit: maintenance switch #4 */ +static unsigned char maint3 = 0; /* 1 bit: maintenance switch #3 */ +static unsigned char maint2 = 0; /* 1 bit: maintenance switch #2 */ +static unsigned char maint1 = 0; /* 1 bit: maintenance switch #1 */ +static unsigned char offset = 0; /* 1 bit: last data loaded offsets */ +static unsigned char jsr = 0; /* 1 bit: last control was JSR ?rel. */ +static int word_number = -2; /* tracks multiple data words */ +#define CONTROL_MODE() (word_number == -1) /* true when in control mode */ +#define DATA_MODE() (word_number >= 0) /* true when in data mode */ +static struct frame *sp = &stack[8]; /* -> selected stack frame, or TOS */ +#define STACK_EMPTY (sp == &stack[8]) /* "TOS" */ +#define STACK_FULL (sp == &stack[0]) /* "BOS" */ +static unsigned char stack_sel = 8<<2; /* 8 levels, 4 PDP-11 words per level */ + /* stack_sel must track sp and TOS! */ + +/* + * Z Position Register, Depth Cue Option (VS60 only) + * Read/Write + * Z position register value[13:2] 11:0 + */ +static int32 zpos = 0; /* (Z "position" reg. * 4) * PSCALEF */ + /* note: offset has been applied! */ +static int32 lp_zpos; /* (scaled) */ +static int32 edge_zpos; /* (scaled) */ + +/* + * Z Offset Register, Depth Cue Option (VS60 only) + * Read/Write + * sign of X dynamic offset 15 (read) (VT48 manual has this confused) + * sign of Y dynamic offset 14 (read) (VT48 manual has this confused) + * sign of Z dynamic offset 13 + * Z dynamic offset 11:0 + */ +static unsigned char s_zoff = 0; /* sign bit for zoff (needed for -0) */ +static int32 zoff = 0; /* Z offset register * PSCALEF */ + +/* + * Invisible state: + */ +static unsigned char char_irq = 0; /* intr. on illegal char in SO mode */ +static unsigned char lphit_irq = 0; /* intr. on light-pen hit */ +static unsigned char lpsw_irq = 0; /* intr. on tip-switch state change */ +static unsigned char edge_irq = 0; /* intr. on edge transition */ + +static unsigned char lp0_sw_state = 0; /* last known LP tip-switch state */ +static unsigned char blink_off = 0; /* set when blinking graphics is dark */ +static unsigned char finish_jmpa = 0; /* reminder to fetch JMPA address */ +static unsigned char finish_jsra = 0; /* reminder to fetch JSRA address */ + +static unsigned char more_vect = 0; /* remembers LP hit in middle of vec. */ +static unsigned char more_arc = 0; /* remembers LP hit in middle of arc */ +static int32 save_x0, save_y0, save_z0, save_x1, save_y1, save_z1; + /* CRT coords for rest of vector */ + +static unsigned char lp_suppress = 0; /* edge columns of char. (VT11 only) */ +static unsigned char stroking = 0; /* set when drawing VS60 char strokes */ +static unsigned char skip_start = 0; /* set between vis. char./arc strokes */ + +static unsigned char stopped = 1; /* display processor frozen */ +static unsigned char sync_period = 0; /* frame sync period (msec) */ +static unsigned char refresh_rate = 0; /* 2 bits: + 00 => continuous display refresh + 01 => 30 fps (60 fps if VT11) + 10 => 40 fps (VS60) + 11 => external sync (VS60) */ + +#if 0 /* this is accurate in simulated "real" time */ +#define BLINK_COUNT 266 /* 266 milliseconds */ +#else /* this looks better in actual real time (adjust for your host speed) */ +#define BLINK_COUNT 67 /* 67 milliseconds */ +#endif + +unsigned char vt11_csp_w = VT11_CSP_W; /* horizontal character spacing */ +unsigned char vt11_csp_h = VT11_CSP_H; /* vertical character spacing */ +/* VS60 spacing depends on char scale; above are right for char scale x1 */ + +/* VS60 has a menu area to the right of the "main working surface" */ +#define MENU_OFFSET (1024 + VR48_GUTTER) /* left edge of menu on CRT */ +#define VR48_WIDTH (MENU_OFFSET + 128) /* X beyond this is not illuminated */ + +static int reduce; /* CRT units per actual pixel */ +static int x_edge; /* 1023 or VR48_WIDTH-1, depending */ +static int y_edge; /* 767 or 1023, depending on display */ +#define ONCRT(x,y) ((x) >= 0 && (x) <= x_edge && (y) >= 0 && (y) <= y_edge) + +/* + * Clipping-specific stuff. + * When a vector crosses the edge of the viewing window, the "edge flag" is set + * and the "edge indicator" indicates whether the first point on the visible + * segment is clipped. Apparently the VT11 does not draw the visible segment, + * but the VS60 will draw the segment (after a resume from an edge interrupt, + * if the interrupt was enabled). The VS60 will also post a second interrupt + * corresponding to the end of the visible segment, after setting the edge flag + * (again) and setting the edge indicator according to whether the last point + * on the visible segment was clipped. + * Note: a light-pen hit is possible on a drawn clipped segment. + */ +static int clip_vect = 0; /* set when clipped coords saved; bit-coded: + 1 => entry clipped + 2 => exit clipped */ +static int clip_i; /* saved "intensify" bit */ +static int32 clip_x0, clip_y0, clip_z0; /* CRT coords for entry point */ +static int32 clip_x1, clip_y1, clip_z1; /* CRT coords for exit point */ + +/* + * Uncertain whether VS60 edge transitions in menu area are flagged and whether + * clipping takes menu width into account. Three possibilities: + */ +#define CLIPYMAX y_edge +#if 0 /* menu area never clipped (seems wrong) */ +#define CLIPXMAX 1023 +#define ONSCREEN(x,y) (menu || ((x) >= 0 && (x) <= CLIPXMAX \ + && (y) >= 0 && (y) <= CLIPYMAX)) +#elif 0 /* menu area correctly clipped (unlikely) */ +#define CLIPXMAX (menu ? 127 : 1023) +#define ONSCREEN(x,y) ((x) >= 0 && (x) <= CLIPXMAX \ + && (y) >= 0 && (y) <= CLIPYMAX) +#else /* menu area clipped same as main area */ +#define CLIPXMAX 1023 +#define ONSCREEN(x,y) ((x) >= 0 && (x) <= CLIPXMAX \ + && (y) >= 0 && (y) <= CLIPYMAX) +#endif + +static void lineTwoStep(int32, int32, int32, int32, int32, int32); + /* forward reference */ + +/* + * calls to read/write VT11/VS60 CSRs + * + * Presumably the host looks at our state less often than we do(!) + * so we keep it in a form convenient to us, rather than as bit fields + * packed into "registers". The simulated VT48 register contents are + * converted to/from our internal variables by the following functions. + */ + +int32 +vt11_get_dpc(void) +{ INIT + /* + * The VT48 manual says that Maintenance Switch 1 causes the Buffered + * Data Bits register to be "entered into the DPC" so it can be + * examined by reading the DPC address, but details of when and how + * often that happens are not provided. Examination of the diagnostic + * test listings shows that relocation is applied and that only the DPC + * is involved when this switch is set. + */ + return ((maint1 ? bdb : DPC) + reloc) & 0177777; +} + +void +vt11_set_dpc(uint16 d) +{ INIT + bdb = d; /* save all bits in case maint1 used */ + DEBUGF(("set DPC 0%06o\r\n", (unsigned)d)); + /* Stack level is unaffected, except that stack_sel==037 goes to 040; this + fudge is necessary to pass DZVSC test 3, which misleadingly calls it + setting top-of-stack upon START (vt11_set_dpc(even)). If one instead + were to set TOS upon START, then several DZVSC diagnostics would fail! */ + if (VS60 && !STACK_EMPTY && GETFIELD(stack_sel,1,0) == 3) { + stack_sel = GETFIELD(stack_sel,4,2) + 1; /* 1..8 */ + sp = &stack[stack_sel]; /* [1..8] */ + stack_sel <<= 2; + } + if (!TESTBIT(d,0)) { /* START */ + DPC = d; /* load DPC */ + sync_period = 0; + ext_stop = 0; + /* the following seem reasonable, but might be wrong */ + finish_jmpa = finish_jsra = jsr = 0; + word_number = -2; + clip_vect = 0; /* discard clipped vector data */ +#if 0 /* probably accurate mimicry, but ugly behavior */ + if (edge_irq) { + xpos = PSCALE(edge_x); + ypos = PSCALE(edge_y); + } +#endif + } else { /* RESUME (after intr); DPC unchanged */ + /* if resuming from LP hit interrupt, finish drawing rest of vector */ + if (more_vect) { + unsigned char save_ena = lp0_intr_ena; + lp0_intr_ena = 0; /* one hit per vector is plenty */ + lphit_irq = 0; /* or else lineTwoStep aborts again! */ + /* line_counter is intact; draw rest of visible vector */ + lineTwoStep(save_x0, save_y0, save_z0, save_x1, save_y1, save_z1); + lp0_intr_ena = save_ena; + } + if (more_arc) { /* remainder of chord was just drawn */ + unsigned char save_ena = lp0_intr_ena; + lp0_intr_ena = 0; /* one hit per arc is plenty */ + lphit_irq = 0; /* or else lineTwoStep aborts again! */ + /* line_counter is intact; draw rest of visible arc */ + /*XXX not yet implemented [conic{23}() needed]*/ + lp0_intr_ena = save_ena; + } + if (!maint2) /* kludge to satify diagnostic test */ + ext_stop = 0; + } + stopped = internal_stop = time_out = stack_over = stack_under = 0; + more_vect = more_arc = stroking = skip_start = 0; + so_flag = edge_indic = edge_flag = lp0_hit = lp1_hit = lp_suppress = 0; + lp0_down = lp0_up = lp1_down = lp1_up = 0; + char_irq = lphit_irq = lpsw_irq = edge_irq = name_irq = 0; + /* next vt11_cycle() will perform a fetch */ +} + +int32 +vt11_get_mpr(void) +{ + int32 ret; + INIT + ret = (internal_stop<<15) | (mode_field<<11) | (intensity<<8) | + (lp0_hit<<7) | (so_flag<<6) | (edge_indic<<5) | (italics<<4) | + (blink_ena<<3) | line_type; + + if (VS60) + ret |= edge_flag<<2; + + return ret; +} + +void +vt11_set_mpr(uint16 d) +{ INIT + /* beeps the "bell" on the LK40 keyboard */ +#if 0 /* probably doesn't hurt to do it for the VS60 also */ + if (VT11) /* according to the VS60 specs */ +#endif + display_beep(); +} + +int32 +vt11_get_xpr(void) +{ + int32 pos; + INIT + pos = lphit_irq ? lp_xpos : edge_irq ? edge_xpos : PNORM(xpos); + return (graphplot_step << 10) | GETFIELD(TWOSCOMP(pos),9,0); +} + +void +vt11_set_xpr(uint16 d) +{ INIT + DEBUGF(("set XPR: no effect\r\n")); +} + +int32 +vt11_get_ypr(void) +{ + int32 pos; + INIT + pos = lphit_irq ? lp_ypos : edge_irq ? edge_ypos : PNORM(ypos); + return (GETFIELD(char_buf,5,0) << 10) | GETFIELD(TWOSCOMP(pos),9,0); +} + +void +vt11_set_ypr(uint16 d) +{ INIT + DEBUGF(("set YPR: no effect\r\n")); +} + +/* All the remaining registers pertain to the VS60 only. */ + +int32 +vt11_get_rr(void) +{ INIT + return reloc >> 6; +} + +void +vt11_set_rr(uint16 d) +{ INIT + reloc = (uint32)GETFIELD(d,11,0) << 6; +} + +int32 +vt11_get_spr(void) +{ INIT + return (busy<<15) | (stack_over<<13) | (stack_under<<12) | (time_out<<11) | + (char_rotate<<10) | (cs_index<<8) | (ext_stop<<7) | + (menu<<6) | (((DPC + reloc) & 0600000L) >> 12) | vector_scale; +} + +void +vt11_set_spr(uint16 d) +{ INIT + ext_stop = TESTBIT(d,7); /* stop occurs at end of next display cycle */ + + if (ext_stop /* not maskable */) { + stopped = 1; /* (asynchronous with display cycle) */ + vt_stop_intr(); /* post stop interrupt to host */ + } +} + +int32 +vt11_get_xor(void) +{ + int32 off, pos; + INIT + off = PNORM(xoff); + pos = lphit_irq ? lp_xpos : edge_irq ? edge_xpos : PNORM(xpos); + return (GETFIELD(TWOSCOMP(pos),13,10)<<12) | GETFIELD(ABS(off),11,0); +} + +void +vt11_set_xor(uint16 d) +{ INIT + xoff = PSCALE(GETFIELD(d,11,0)); + s_xoff = TESTBIT(d,13); + if (s_xoff) + xoff = -xoff; +} + +int32 +vt11_get_yor(void) +{ + int32 off, pos; + INIT + off = PNORM(yoff); + pos = lphit_irq ? lp_ypos : edge_irq ? edge_ypos : PNORM(ypos); + return (GETFIELD(TWOSCOMP(pos),13,10)<<12) | GETFIELD(ABS(off),11,0); +} + +void +vt11_set_yor(uint16 d) +{ INIT + yoff = PSCALE(GETFIELD(d,11,0)); + s_yoff = TESTBIT(d,13); + if (s_yoff) + yoff = -yoff; +} + +int32 +vt11_get_anr(void) +{ INIT + DEBUGF(("get ANR: no effect\r\n")); + return (search << 12) | assoc_name; /* [garbage] */ +} + +void +vt11_set_anr(uint16 d) +{ INIT + if (TESTBIT(d,14)) + search = GETFIELD(d,13,12); + if (TESTBIT(d,11)) + assoc_name = GETFIELD(d,10,0); +} + +int32 +vt11_get_scr(void) +{ INIT + return (int0_scope<<15) | (lp0_hit<<14) | (lp0_down<<13) | (lp0_up<<12) | + (lp0_intr_ena<<11) | (lp0_sw_intr_ena<<10) | (int1_scope<<9) | + (lp1_hit<<8) | (lp1_down<<7) | (lp1_up<<6) | (lp1_intr_ena<<5) | + (lp1_sw_intr_ena<<4) | (color << 2); +} + +void +vt11_set_scr(uint16 d) +{ INIT + if (maint3) { + if (TESTBIT(d,14) && lp0_intr_ena) { + if (!lphit_irq) { /* ensure correct position registers reported */ + lp_xpos = PNORM(xpos); + lp_ypos = PNORM(ypos); + lp_zpos = PNORM(zpos); + } + lp0_hit = lphit_irq = 1; + } + if (TESTBIT(d,13)) { + lp0_down = 1; /* the manual seems to have this backward */ + if (lp0_sw_intr_ena) + lpsw_irq = 1; + } + if (TESTBIT(d,12)) { + lp0_up = 1; /* the manual seems to have this backward */ + if (lp0_sw_intr_ena) + lpsw_irq = 1; + } + if (TESTBIT(d,8) && lp1_intr_ena) { + if (!lphit_irq) { /* ensure correct position registers reported */ + lp_xpos = PNORM(xpos); + lp_ypos = PNORM(ypos); + lp_zpos = PNORM(zpos); + } + lp1_hit = lphit_irq = 1; + } + if (TESTBIT(d,7)) { + lp1_down = 1; + if (lp1_sw_intr_ena) + lpsw_irq = 1; + } + if (TESTBIT(d,6)) { + lp1_up = 1; + if (lp1_sw_intr_ena) + lpsw_irq = 1; + } + if (lpsw_irq || lphit_irq /* && DATA_MODE() */) + vt_lpen_intr(); + } +} + +int32 +vt11_get_nr(void) +{ INIT + return (name_irq<<15) | (search<<12) | name; +} + +void +vt11_set_nr(uint16 d) +{ INIT + DEBUGF(("set NR: no effect\r\n")); +} + +int32 +vt11_get_sdr(void) +{ + struct frame *p; + INIT + p = &stack[GETFIELD(stack_sel,4,2)]; /* [0..7], 8 (TOS) => 0 */ + switch (GETFIELD(stack_sel,1,0)) { /* 16-bit "byte" within frame */ + case 0: + return p->_dpc; /* DPC bit#0 is always 0 */ + + case 1: + return (p->_name << 4) | p->_mode; + + case 2: + return (p->_italics << 15) | (p->_vscale << 11) | (p->_csi << 9) | + (p->_crotate << 7) | (p->_intens << 4) | ((int)p->_color << 2) | + p->_ltype; + + case 3: + return (p->_blink << 15) | (p->_so << 14) | (p->_menu << 13) | + (p->_cesc << 12) | (p->_edgeintr << 11) | (p->_zdata << 10) | + (p->_depth << 8) | (p->_lp1swintr << 7) | + (p->_lp0swintr << 6) | (p->_lp1intr << 5) | (p->_inten1 << 4) | + (p->_lp0intr << 3) | (p->_inten0 << 2) | ((!p->_bright) << 1) | + p->_stopintr; + } + /*NOTREACHED*/ + return 0; +} + +void +vt11_set_sdr(uint16 d) +{ INIT + DEBUGF(("set SDR: no effect\r\n")); +} + +int32 +vt11_get_str(void) +{ INIT + return char_term; +} + +void +vt11_set_str(uint16 d) +{ INIT + if (TESTBIT(d,7)) + char_term = GETFIELD(d,6,0); +} + +int32 +vt11_get_sar(void) +{ + int32 ret; + INIT + ret = (maint4<<15) | (maint3<<14) | (maint2<<13) | (maint1<<12) | + (offset<<10) | (jsr<<9) | stack_sel /*includes bit 5=TOS [level 8]*/; + switch (word_number) { + case -1: /* control mode reported as word 0, + according to VT48 ES */ + case 0: + ret |= 1<<6; + break; + case 1: + ret |= 1<<7; + break; + case 2: + ret |= 1<<8; + break; + /* others (including -1) not reportable */ + } + return ret; +} + +void +vt11_set_sar(uint16 d) +{ INIT + maint4 = TESTBIT(d,15); /* 1 => synch. processing pipeline */ + maint3 = TESTBIT(d,14); /* 1 => copy delta,tangent to x,y pos */ + maint2 = TESTBIT(d,13); /* 1 => set single-step mode */ + maint1 = TESTBIT(d,12); /* 1 => vt11_get_dpc will return bdb */ + if (TESTBIT(d,5)) { + sp = &stack[8]; /* reset stack pointer to TOS */ + stack_sel = (8<<2) /* TOS amounts to level 8 */ + | TESTBIT(stack_sel,0); /* preserve PDP-11 word sel. */ + } else { + stack_sel = GETFIELD(d,4,0); + sp = &stack[GETFIELD(stack_sel,4,2)]; /* [0..7] */ + } +} + +/* registers used with the VS60 depth cueing option */ + +/* + * Since there is no support for hardware 3D rotation or viewing transform, the + * only effect of the Z coordinate is to modulate beam intensity along a vector + * to give the illusion that greater Z coordinates are closer (brighter). + * This is known as "depth cueing" and is implemented in dintens(). + */ + +int32 +vt11_get_zpr(void) +{ + int32 pos; + INIT + pos = lphit_irq ? lp_zpos : edge_irq ? edge_zpos : PNORM(zpos); + return GETFIELD(TWOSCOMP(pos),13,2); +} + +void +vt11_set_zpr(uint16 d) +{ INIT + DEBUGF(("set ZPR: no effect\r\n")); +} + +int32 +vt11_get_zor(void) +{ + int32 off, ret; + INIT + off = PNORM(zoff); + ret = GETFIELD(ABS(off),11,0); + if (s_xoff) /* (VT48 manual has this confused) */ + ret |= 1<<15; + if (s_yoff) /* (VT48 manual has this confused) */ + ret |= 1<<14; + if (s_zoff) + ret |= 1<<13; + return ret; +} + +void +vt11_set_zor(uint16 d) +{ INIT + zoff = PSCALE(GETFIELD(d,11,0)); + s_zoff = TESTBIT(d,13); + if (s_zoff) + zoff = -zoff; +} + +void +vt11_reset(void) +{ + /* make sure display code has been initialized */ + if (!vt11_init) /* (SIMH invokes before display type is set) */ + return; /* wait until last moment */ + + if (VS60) { + /* VS60 character spacing depends on char scale; these are for x1 */ + vt11_csp_w = 14; /* override VT11 options */ + vt11_csp_h = 24; + } /* else assume already set up for desired VT11 behavior */ + + x_edge = display_xpoints() - 1; + y_edge = display_ypoints() - 1; + reduce = display_scale(); + + /* reset VT11/VT48 to initial default internal state: */ + + /* clear interrupts, BDB, etc. */ + vt11_set_dpc(0); + /* some of the following should probably be moved to vt11_set_dpc([even]) */ + stopped = int0_scope = 1; /* idle, console 0 enabled */ + lp0_sw_state = display_lp_sw; /* sync with mouse button #1 */ + shift_out = int1_scope = stop_intr_ena = blink_off = 0; + italics = blink_ena = char_rotate = menu = search = offset = 0; + lp0_sw_intr_ena = lp1_sw_intr_ena = lp0_intr_ena = lp1_intr_ena = 0; + file_z_data = edge_intr_ena = depth_cue_proc = char_escape = 0; + maint1 = maint2 = maint3 = maint4 = 0; + refresh_rate = 0; + char_buf = char_term = 0; + assoc_name = name = 0; + reloc = 0; + xpos = ypos = zpos = xoff = yoff = zoff = 0; + s_xoff = s_yoff = s_zoff = 0; + graphplot_step = 0; + mode_field = 0; + graphic_mode = CHAR; + line_type = SOLID; + color = GREEN; + lp_intensify = 1; + cs_index = 1; + char_scale = vector_scale = 4; + intensity = 4; + sp = &stack[8]; + stack_sel = 8<<2; /* PDP-11 word selector also cleared */ + + /* following necessary in case the stack is inspected via stack data reg. */ + { int i; + for (i = 0; i < 8; ++i) + memset(&stack[i], 0, sizeof(struct frame)); + } +} + +/* VS60 display subroutine support (see stack layout for SDR, above) */ + +static void +push() +{ + stack_over = STACK_FULL; /* BOS? */ + if (!stack_over) { + --sp; + *sp = stack[8]; /* copy current parameters */ + /* (including *old* DPC) */ + stack_sel -= 1<<2; + /* XXX should stack_sel stack-byte bits be cleared? */ + } + /* else will generate interrupt soon after return */ +} + +static void +pop(int restore) +{ + stack_under = STACK_EMPTY; /* TOS? */ + if (!stack_under) { + stack[8] = *sp; /* restore parameters (including DPC) */ + ++sp; + stack_sel += 1<<2; + /* XXX should stack_sel stack-byte bits be cleared? maybe for TOS? */ + } + /* else will generate interrupt soon after return */ +} + +/* compute depth-cued display intensity from current display-file intensity */ + +int +dintens(int32 z) +{ + int i = intensity; + + if (depth_cue_proc) { /* apply depth cue */ + i += i * z / 1024; /* XXX is z scaled properly? */ + if (i > 7) + i = 7; + else if (i < 0) + i = 0; + } + i += DISPLAY_INT_MAX - 7; + return i >= DISPLAY_INT_MIN ? i : DISPLAY_INT_MIN; +} + +/* + * Note: It would be more efficient to work directly with display intensity + * levels than with Z coordinates, since the vast majority of dintens() + * computations result in the same display intensity level as the previous + * such computation. However, compared to the rest of the processing per + * pixel, this computation doesn't seem too expensive, so optimization isn't + * necessary. + */ + +/* illuminate pixel in raster image */ + +static void +illum3(int32 x, int32 y, int32 z) + /* virtual CRT units (offset and normalized) */ +{ + int i; /* display intensity level */ + + /* don't update position registers! */ + + /* coords might be outside viewable area, e.g. clipped italic character */ + if (!ONCRT(x, y) || !int0_scope) + return; + + if (blink_ena && blink_off) /* blinking & in dark phase */ + return; + + i = dintens(z); + + if (display_point((int)x, (int)y, i, 0) /* XXX VS60 might switch color */ + /* VT11, per maintenance spec, has threshold 6 for CHAR, 4 for others */ + /* but the classic Lunar Lander uses 3 for its menu and thrust bar! */ + /* I seem to recall that both thresholds were 4 for the VS60 (VR48). */ +#if 0 + && (i >= (DISPLAY_INT_MAX-1) /* (using i applies depth cueing) */ + || (graphic_mode != CHAR && i >= (DISPLAY_INT_MAX-3))) +#else + /* The following imposes thresholds of 3 for all graphic objects. */ + && (i >= (DISPLAY_INT_MAX-4)) /* (using i applies depth cueing) */ +#endif + && !lp_suppress) { + lp0_hit = 1; + if (lp0_intr_ena) + lphit_irq = 1; /* will lead to an interrupt */ + /* + * Save LP hit coordinates so CPU can look at them; the virtual position + * registers cannot be reported on LP interrupt, since they track the + * (pre-clipping) end of the vector that was being drawn. + */ + lp_xpos = x; + if (menu) + lp_xpos -= MENU_OFFSET; + lp_ypos = y; + lp_zpos = z; + if (lp_intensify) /* [technically shouldn't exceed max] */ + display_point((int)x, (int)y, DISPLAY_INT_MAX, 0); + /* XXX appropriate for VT11; what about VS60? chars? */ + } +} + +#define illum2(x,y) illum3(x, y, PNORM(zpos)) /* may be depth cued */ + /* the extra overhead if not depth cueing is not much */ + +static void +point3(int i, int32 x1, int32 y1, int32 z1, int detect_edge) + /* VSCALEd, offset coordinates (z1 * 4) */ +{ + int32 x0 = PNORM(xpos), y0 = PNORM(ypos); + + if (detect_edge) { + edge_indic = ONSCREEN(x0, y0); /* first test */ + edge_flag = !ONSCREEN(x0, y0); /* first test */ + } else { + edge_indic = 0; + edge_flag = 0; + } + xpos = x1; + ypos = y1; + zpos = z1; + x1 = PNORM(xpos); + y1 = PNORM(ypos); + z1 = PNORM(zpos); + if (detect_edge) { + edge_indic &= !ONSCREEN(x1, y1); /* second test */ + edge_flag &= ONSCREEN(x1, y1); /* second test */ + edge_flag |= edge_indic; + if (edge_flag) + if (edge_intr_ena) { + edge_xpos = x1; + edge_ypos = y1; + edge_zpos = z1; + edge_irq = 1; +#if 0 /* XXX uncertain whether point is displayed during edge intr. */ + return; /* point not displayed */ +#endif + } else + edge_flag = 0; + } + if (i && ONSCREEN(x1, y1)) + if (menu) + illum3(x1 + MENU_OFFSET, y1, z1); + else + illum3(x1, y1, z1); +} + +#define point2(i,x,y,e) point3(i, x, y, zpos, e) + /* the extra overhead if not depth cueing is not much */ + +/* 4 bit counter, fed from div 2 clock (to compensate for raster algorithm) */ +/* XXX check display against example photos to see if div 2 is right */ +static unsigned char line_counter; +#define LC1 02 +#define LC2 04 +#define LC3 010 +#define LC4 020 + +/* point on a line (apply line style) */ +static void +lpoint(int32 x, int32 y, int32 z) + /* X, Y are in window-system screen pixel units */ + /* Z is in virtual CRT units (offset and normalized) */ +{ + int i, on = (line_type == SOLID) || stroking; /* on for sure */ + + if (!on) /* see if in visible portion of cycle */ + for (i = 0; i < reduce; ++i) { + switch (line_type) { + case LONG_DASH: + if (line_counter & LC4) + on = 1; + break; + case SHORT_DASH: + if (line_counter & LC3) + on = 1; + break; + case DOT_DASH: + /* LC(2:1)H * LC3L + LC4L */ + if (((line_counter & (LC1|LC2)) == (LC1|LC2) + && !(line_counter & LC3)) || !(line_counter & LC4)) + on = 1; + break; + } + + --line_counter; + } + + if (on) + /* convert back from actual screen pixels to emulated CRT coordinates */ + /* note: Z coordinate is already in virtual CRT units */ + illum3(x * reduce, y * reduce, z); +} + +/* + * 2-step algorithm, developed by Xiaolin Wu + * from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html + * + * The two-step algorithm takes the interesting approach of treating + * line drawing as a automaton, or finite state machine. If one looks + * at the possible configurations that the next two pixels of a line, + * it is easy to see that only a finite set of possiblities exist. + * If line styles weren't involved, the line could be drawn symmetrically + * from both ends toward the midpoint. + * Rasterization is done using actual screen pixel units, not emulated device + * coordinates! + * + * The Z coordinate just goes along for the ride. It is computed thusly: + * Let N = # steps in major direction (X or Y) + * i = step number + * dZ = Z1 - Z0 + * Then Zi = floor(Z0 + dZ*(i+0.5)/N) 0.5 centers steps + * Zi = floor((2*N*Z0 + dZ + 2*i*dZ) / (2*N)) + * The numerator at step i is + * Znum(i) = Znum(i-1) + 2*dZ + * with Znum(0) = 2*N*Z0 + dZ + */ + +static void +lineTwoStep(int32 x0, int32 y0, int32 z0, int32 x1, int32 y1, int32 z1) + /* virtual CRT units (offset and normalized) */ +{ + int32 dx, dy, dz; + int stepx, stepy; + + /* when clipping is implemented, coords should always be on-screen */ + + /* convert from emulated CRT units to actual screen pixels */ + x0 /= reduce; + y0 /= reduce; + x1 /= reduce; + y1 /= reduce; + /* note: Z coords remain in virtual CRT units */ + + dx = x1 - x0; + dy = y1 - y0; + dz = z1 - z0; + + /* XXX there could be fast special cases for "basic vectors" */ + + if (dx >= 0) + stepx = 1; + else { + dx = -dx; + stepx = -1; + } + if (dy >= 0) + stepy = 1; + else { + dy = -dy; + stepy = -1; + } + +#define TPOINT do { znum += dz; /* 2 * original_dz */ \ + z0 = znum / twoN; /* truncates */ \ + if (lphit_irq && !stroking) goto hit; \ + /* XXX longjmp from hit detector may be more efficient */ \ + lpoint(x0, y0, z0); \ + } while (0) + + if (!skip_start) /* not for continuing stroke when VS60 char. or arc */ + lpoint(x0, y0, z0); /* (could have used TPOINT) */ + + if (dx == 0 && dy == 0) /* following algorithm won't work */ + return; /* just the one dot */ + /* XXX not accurate for vector in Z direction */ + + if (dx > dy) { + int32 length = (dx - 1) / 2; + int extras = (dx - 1) & 1; + int32 incr2 = (dy * 4) - (dx * 2); + long twoN = 2 * dx, znum = twoN * z0 + dz; + dz *= 2; + if (incr2 < 0) { + int32 c = dy * 2; + int32 incr1 = c * 2; + int32 d = incr1 - dx; + int32 i; + for (i = 0; i < length; i++) { + x0 += stepx; + if (d < 0) { /* Pattern: */ + TPOINT; /* x o o */ + x0 += stepx; + TPOINT; + d += incr1; + } + else { + if (d < c) { /* Pattern: */ + TPOINT; /* o */ + y0 += stepy; /* x o */ + } else { /* Pattern: */ + y0 += stepy; /* o o */ + TPOINT; /* x */ + } + x0 += stepx; + TPOINT; + d += incr2; + } + } + if (extras > 0) { + x0 += stepx; + if (d >= c) + y0 += stepy; + TPOINT; + } + + } else { + int32 c = (dy - dx) * 2; /* negative */ + int32 incr1 = c * 2; /* negative */ + int32 d = incr1 + dx; + int32 i; + for (i = 0; i < length; i++) { + x0 += stepx; + if (d > 0) { /* Pattern: */ + y0 += stepy; /* o */ + TPOINT; /* o */ + x0 += stepx; /* x */ + y0 += stepy; + TPOINT; + d += incr1; + } else { + if (d < c) { /* Pattern: */ + TPOINT; /* o */ + y0 += stepy; /* x o */ + } else { /* Pattern: */ + y0 += stepy; /* o o */ + TPOINT; /* x */ + } + x0 += stepx; + TPOINT; + d += incr2; + } + } + if (extras > 0) { + x0 += stepx; + if (d >= c) + y0 += stepy; + TPOINT; + } + } + + } else { /* dy >= dx */ + int32 length = (dy - 1) / 2; + int extras = (dy - 1) & 1; + int32 incr2 = (dx * 4) - (dy * 2); + long twoN = 2 * dy, znum = twoN * z0 + dz; + dz *= 2; + if (incr2 < 0) { + int32 c = dx * 2; + int32 incr1 = c * 2; + int32 d = incr1 - dy; + int32 i; + for (i = 0; i < length; i++) { + y0 += stepy; + if (d < 0) { /* Pattern: */ + TPOINT; /* o */ + y0 += stepy; /* o */ + TPOINT; /* x */ + d += incr1; + } else { + if (d < c) { /* Pattern: */ + TPOINT; /* o */ + x0 += stepx; /* o */ + /* x */ + } else { /* Pattern: */ + x0 += stepx; /* o */ + TPOINT; /* o */ + /* x */ + } + y0 += stepy; + TPOINT; + d += incr2; + } + } + if (extras > 0) { + y0 += stepy; + if (d >= c) + x0 += stepx; + TPOINT; + } + + } else { + int32 c = (dx - dy) * 2; /* nonpositive */ + int32 incr1 = c * 2; /* nonpositive */ + int32 d = incr1 + dy; + int32 i; + for (i = 0; i < length; i++) { + y0 += stepy; + if (d > 0) { /* Pattern: */ + x0 += stepx; + TPOINT; /* o */ + y0 += stepy; /* o */ + x0 += stepx; /* x */ + TPOINT; + d += incr1; + } else { + if (d < c) { /* Pattern: */ + TPOINT; /* o */ + x0 += stepx; /* o */ + /* x */ + } else { /* Pattern: */ + x0 += stepx; /* o */ + TPOINT; /* o */ + /* x */ + } + y0 += stepy; + TPOINT; + d += incr2; + } + } + if (extras > 0) { + y0 += stepy; + if (d >= c) + x0 += stepx; + TPOINT; + } + } + } + lpoint(x1, y1, z1); /* not TPOINT (0-length vector on resume) */ + return; + + /* here if LP hit interrupt during rendering */ + hit: + more_vect = 1; + save_x0 = x0 * reduce; + save_y0 = y0 * reduce; + save_z0 = z0; + save_x1 = x1 * reduce; + save_y1 = y1 * reduce; + save_z1 = z1; + /* line_counter is static and thus will be intact upon resume */ +} /* lineTwoStep */ + +/* + * Clip segment to only that portion, if any, visible within the window. + * Returns: -1 visible and not clipped + * 0 invisible + * 1,2,3 visible and clipped (clipped coords stashed); + * bit-coded: 1 => entry clipped, 2=> exit clipped + * + * The Z coordinate just goes along for the ride. + */ +int +clip3(int32 x0, int32 y0, int32 z0, int32 x1, int32 y1, int32 z1) +{ + int code0, code1; /* Cohen-Sutherland endpoint codes */ + /* remaining variables are used in modified Liang-Barsky algorithm: */ + int32 rdx, rdy, rdz; /* x0-x1, y0-y1, z0-z1 */ + int32 tn; /* Edge parameter: numerator */ + int32 tPEn, tPEd, tPLn, tPLd; /* Enter/Leave params: numer, denom */ + int clipped; /* potential clip_vect value */ + + /* + * Use the first parts of the Cohen-Sutherland algorithm to detect + * all IN-to-IN cases and OUT-to-OUT along the same side, each of + * which is trivially handled without needing any clipping actions. + + * The idea is that the extended window edges divide the plane into + * 9 regions; the segment endpoints are assigned bit-codes that + * indicate which of the 3 X sections and which of the 3 Y sections + * each point lies in; then simple tests on the codes can detect + * the desired "trivial" cases, which are the most common. + */ + + /* assign X/Y region codes to the endpoints */ + + if (y0 > CLIPYMAX) + code0 = 1; + else if (y0 < 0) + code0 = 2; + else + code0 = 0; + + if (x0 > CLIPXMAX) + code0 |= 4; + else if (x0 < 0) + code0 |= 8; + + if (y1 > CLIPYMAX) + code1 = 1; + else if ( y1 < 0 ) + code1 = 2; + else + code1 = 0; + + if (x1 > CLIPXMAX) + code1 |= 4; + else if ( x1 < 0 ) + code1 |= 8; + + if (code0 == code1) /* endpoints lie in same region */ + if (code0 == 0) /* ON to ON; trivially visible */ + return -1; + else /* OFF to OFF and trivially invisible */ + return 0; + + /* Endpoints are now known to lie in different regions. */ + + if ((code0 & code1) != 0) /* OFF to OFF and trivially invisible */ + return 0; + + /* Handle horizontal and vertical cases separately, + both for speed and to simplify later computations. */ + + rdx = x0 - x1; + rdy = y0 - y1; + rdz = z0 - z1; + + if (rdx == 0) { /* vertical; has a visible portion! */ + clipped = 0; + /* Using the direction allows us to save one test. */ + if (rdy < 0) { /* directed upward */ + if (y1 > CLIPYMAX) { + clipped = 2; + y1 = CLIPYMAX; /* clip */ + z1 = z0 + rdz * (y1 - y0) / rdy; + } + if (y0 < 0) { + clipped |= 1; + z0 -= rdz * y0 / rdy; + y0 = 0; /* clip */ + } + } else { /* directed downward */ + if (y0 > CLIPYMAX) { + clipped = 1; + y0 = CLIPYMAX; /* clip */ + z0 = z1 + rdz * (y0 - y1) / rdy; + } + if (y1 < 0) { + clipped |= 2; + z1 -= rdz * y1 / rdy; + y1 = 0; /* clip */ + } + } + goto stash; + } + + if (rdy == 0) { /* horizontal; has a visible portion! */ + clipped = 0; + /* Using the direction allows us to save one test. */ + if (rdx < 0) { /* directed rightward */ + if (x1 > CLIPXMAX) { + clipped |= 2; + x1 = CLIPXMAX; /* clip */ + z1 = z0 + rdz * (x1 - x0) / rdx; + } + if (x0 < 0) { + clipped = 1; + z0 -= rdz * x0 / rdx; + x0 = 0; /* clip */ + } + } else { /* directed leftward */ + if (x0 > CLIPXMAX) { + clipped = 1; + x0 = CLIPXMAX; /* clip */ + z0 = z1 + rdz * (x0 - x1) / rdx; + } + if (x1 < 0) { + clipped |= 2; + z1 -= rdz * x1 / rdx; + x1 = 0; /* clip */ + } + } + goto stash; + } + + /* + * Hardest cases: use modified Liang-Barsky algorithm. + * + * Not only is this computation supposedly faster than Cohen- + * Sutherland clipping, but also the original direction is + * preserved, which is necessary to accurately emulate the + * VT48 behavior (association of coordinates with interrupts). + */ + + /* + * t is a line parameter: P(t) = P0 + t * (P1 - P0). + * N is an outward normal vector. + * L, R, B, T denote edges (left, right, bottom, top). + * PE denotes "potentially entering", PL "potentially leaving". + * n, d denote numerator, denominator (avoids floating point). + */ + + /* + * We know at this point that the endpoints lie in different + * regions and that there must be at least one PE or PL crossing + * at some value of t in [0,1]. Indeed, there will be *both* PE + * and PL crossings *unless* one endpoint is IN the window. + * + * As a result of the previous filtering, denominators are never 0. + */ + + tPEn = -1; /* tPE = -1, lower than any candidate */ + tPEd = 1; + tPLn = 2; /* tPL = 2, higher than any candidate */ + tPLd = 1; + + /* + * Left: tL = NL . (PL - P0) / NL . (P1 - P0) + * NL = (-1,0) + * PL = (0,y) + * => + * tL = x0 / rdx + * + * if ( tL >= 0 & tL <= 1 ) + * if ( NL . (P1 - P0) < 0 & tL > tPE ) + * tPE := tL + * if ( NL . (P1 - P0) > 0 & tL < tPL ) + * tPL := tL + * => + * if ( rdx < 0 ) + * if ( rdx <= x0 & x0 <= 0 ) + * if ( tPEd > 0 ) + * if ( x0 * tPEd < tPEn * rdx ) + * tPE := tL + * else + * if ( x0 * tPEd > tPEn * rdx ) + * tPE := tL + * else + * if ( 0 <= x0 & x0 <= rdx ) + * if ( tPLd > 0 ) + * if ( x0 * tPLd < tPLn * rdx ) + * tPL := tL + * else + * if ( x0 * tPLd > tPLn * rdx ) + * tPL := tL + */ + + if (rdx < 0) { + if (x0 <= 0 && x0 >= rdx) + if (tPEd > 0) { + if (x0 * (long)tPEd < (long)tPEn * rdx) + tPEn = x0, tPEd = rdx; + } else /* tPEd < 0 */ + if (x0 * (long)tPEd > (long)tPEn * rdx) + tPEn = x0, tPEd = rdx; + } else /* rdx > 0 */ + if (x0 >= 0 && x0 <= rdx) + if (tPLd > 0) { + if (x0 * (long)tPLd < (long)tPLn * rdx) + tPLn = x0, tPLd = rdx; + } else /* tPLd < 0 */ + if (x0 * (long)tPLd > (long)tPLn * rdx) + tPLn = x0, tPLd = rdx; + + /* + * Right: tR = NR . (PR - P0) / NR . (P1 - P0) + * NR = (1,0) + * PR = (XMAX,y) + * => + * tR = (x0 - XMAX) / rdx + * + * if ( tR >= 0 & tR <= 1 ) + * if ( NR . (P1 - P0) < 0 & tR > tPE ) + * tPE := tR + * if ( NR . (P1 - P0) > 0 & tR < tPL ) + * tPL := tR + * => + * if ( rdx < 0 ) + * if ( rdx <= TRn & TRn <= 0 ) + * if ( tPLd > 0 ) + * if ( TRn * tPLd > tPLn * rdx ) + * tPL := tR + * else + * if ( TRn * tPLd < tPLn * rdx ) + * tPL := tR + * else + * if ( 0 <= TRn & TRn <= rdx ) + * if ( tPEd > 0 ) + * if ( TRn * tPEd > tPEn * rdx ) + * tPE := tR + * else + * if ( TRn * tPEd < tPEn * rdx ) + * tPE := tR + */ + + tn = x0 - CLIPXMAX; + + if (rdx < 0) { + if (tn <= 0 && tn >= rdx) + if (tPLd > 0) { + if (tn * (long)tPLd > (long)tPLn * rdx) + tPLn = tn, tPLd = rdx; + } else /* tPLd < 0 */ + if (tn * (long)tPLd < (long)tPLn * rdx) + tPLn = tn, tPLd = rdx; + } else /* rdx > 0 */ + if (tn >= 0 && tn <= rdx) + if (tPEd > 0) { + if (tn * (long)tPEd > (long)tPEn * rdx) + tPEn = tn, tPEd = rdx; + } else /* tPEd < 0 */ + if (tn * (long)tPEd < (long)tPEn * rdx) + tPEn = tn, tPEd = rdx; + + /* + * Bottom: tB = NB . (PB - P0) / NB . (P1 - P0) + * NB = (0,-1) + * PB = (x,0) + * => + * tB = y0 / rdy + * + * if ( tB >= 0 & tB <= 1 ) + * if ( NB . (P1 - P0) < 0 & tB > tPE ) + * tPE := tB + * if ( NB . (P1 - P0) > 0 & tB < tPL ) + * tPL := tB + * => + * if ( rdy < 0 ) + * if ( rdy <= y0 & y0 <= 0 ) + * if ( tPEd > 0 ) + * if ( y0 * tPEd < tPEn * rdy ) + * tPE := tB + * else + * if ( y0 * tPEd > tPEn * rdy ) + * tPE := tB + * else + * if ( 0 <= y0 & y0 <= rdy ) + * if ( tPLd > 0 ) + * if ( y0 * tPLd < tPLn * rdy ) + * tPL := tB + * else + * if ( y0 * tPLd > tPLn * rdy ) + * tPL := tB + */ + + if (rdy < 0) { + if (y0 <= 0 && y0 >= rdy) + if (tPEd > 0) { + if (y0 * (long)tPEd < (long)tPEn * rdy) + tPEn = y0, tPEd = rdy; + } else /* tPEd < 0 */ + if (y0 * (long)tPEd > (long)tPEn * rdy) + tPEn = y0, tPEd = rdy; + } else /* rdy > 0 */ + if (y0 >= 0 && y0 <= rdy) + if (tPLd > 0) { + if (y0 * (long)tPLd < (long)tPLn * rdy) + tPLn = y0, tPLd = rdy; + } else /* tPLd < 0 */ + if (y0 * (long)tPLd > (long)tPLn * rdy) + tPLn = y0, tPLd = rdy; + + /* + * Top: tT = NT . (PT - P0) / NT . (P1 - P0) + * NT = (0,1) + * PT = (x,YMAX) + * => + * tT = (y0 - YMAX) / rdy + * + * if ( tT >= 0 & tT <= 1 ) + * if ( NT . (P1 - P0) < 0 & tT > tPE ) + * tPE := tT + * if ( NT . (P1 - P0) > 0 & tT < tPL ) + * tPL := tT + * => + * if ( rdy < 0 ) + * if ( rdy <= TRn & TRn <= 0 ) + * if ( tPLd > 0 ) + * if ( TRn * tPLd > tPLn * rdy ) + * tPL := tT + * else + * if ( TRn * tPLd < tPLn * rdy ) + * tPL := tT + * else + * if ( 0 <= TRn & TRn <= rdy ) + * if ( tPEd > 0 ) + * if ( TRn * tPEd > tPEn * rdy ) + * tPE := tT + * else + * if ( TRn * tPEd < tPEn * rdy ) + * tPE := tT + */ + + tn = y0 - CLIPYMAX; + + if (rdy < 0) { + if (tn <= 0 && tn >= rdy) + if (tPLd > 0) { + if (tn * (long)tPLd > (long)tPLn * rdy) + tPLn = tn, tPLd = rdy; + } else /* tPLd < 0 */ + if (tn * (long)tPLd < (long)tPLn * rdy) + tPLn = tn, tPLd = rdy; + } else /* rdy > 0 */ + if (tn >= 0 && tn <= rdy) + if (tPEd > 0) { + if (tn * (long)tPEd > (long)tPEn * rdy) + tPEn = tn, tPEd = rdy; + } else /* tPEd < 0 */ + if (tn * (long)tPEd < (long)tPEn * rdy) + tPEn = tn, tPEd = rdy; + + /* + * if ( tPL < tPE ) + * invisible + * => + * if ( tPLd > 0 && tPEd < 0 || tPLd < 0 && tPEd > 0 ) + * if ( tPLn * tPEd > tPEn * tPLd ) + * invis + * else + * if ( tPLn * tPEd < tPEn * tPLd ) + * invis + */ + + if (tPLd > 0 && tPEd < 0 || tPLd < 0 && tPEd > 0) { + if (tPLn * (long)tPEd > (long)tPEn * tPLd) + return 0; /* invisible */ + } else + if (tPLn * (long)tPEd < (long)tPEn * tPLd) + return 0; /* invisible */ + + /* + * if ( tPE < 0 ) tPE := 0 [code0 is 0] + * if ( tPL > 1 ) tPL := 1 [code1 is 0] + * draw from P(tPE) to P(tPL) + * + * P(t) = P0 + t * (P1 - P0) + * => + * xE = x0 - tE * rdx, yE = y0 - tE * rdy + * xL = x0 - tL * rdx, yL = y0 - tL * rdy + */ + + /* note: update P1 first since it uses original P0 coords */ + + if (code1 == 0) + clipped = 0; + else { + clipped = 2; + /* XXX might not be rounded the same as on the VT48: */ + x1 = x0 - rdx * tPLn / tPLd; + y1 = y0 - rdy * tPLn / tPLd; + z1 = z0 - rdz * tPLn / tPLd; + } + + if (code0 != 0) { + clipped |= 1; + /* XXX might not be rounded the same as on the VT48: */ + x0 -= rdx * tPEn / tPEd; + y0 -= rdy * tPEn / tPEd; + z0 -= rdz * tPEn / tPEd; + } + + /* Stash clipped coords and set global "vector was clipped" flag. */ + + stash: + clip_x0 = x0; + clip_y0 = y0; + clip_x1 = x1; + clip_y1 = y1; + clip_z0 = z0; + clip_z1 = z1; + return clipped; +} + +/* draw a relative vector, depth-cued when appropriate */ + +static void +vector3(int i, int32 dx, int32 dy, int32 dz) /* unscaled display-file units */ +{ + int32 x0, y0, z0, x1, y1, z1; + + dx = stroking ? CSCALE(dx) : VSCALE(dx); /* apply scale factor (VS60) */ + dy = stroking ? CSCALE(dy) : VSCALE(dy); + dz = VSCALE(dz * 4); + x0 = PNORM(xpos); /* (includes offset) */ + y0 = PNORM(ypos); + z0 = PNORM(zpos); + xpos += dx; + ypos += dy; + zpos += dz; + x1 = PNORM(xpos); + y1 = PNORM(ypos); + z1 = PNORM(zpos); + dx = x1 - x0; + dy = y1 - y0; + dz = z1 - z0; + + if (stroking) { /* drawing a VS60 character */ + DEBUGF(("offset, normalized stroke i%d (%ld,%ld) to (%ld,%ld)\r\n", + i, (long)x0,(long)y0, (long)x1,(long)y1)); + + if (dx == 0 && dy == 0) { /* just display a point */ + if (i) + if (menu) + illum3(x0 + MENU_OFFSET, y0, z0); + else + illum3(x0, y0, z0); /* illum3() checks ONCRT, int0_scope */ + return; + } + } else { + DEBUGF(( + "offset, normalized vector i%d (%ld,%ld,%ld) to (%ld,%ld,%ld)\r\n", + i, (long)x0, (long)y0, (long)z0, (long)x1, (long)y1, (long)z1)); + + line_counter = 037; /* reset line-style counter */ + + /* Maintenance Switch 3 => store delta length,tangent in xpos,ypos */ + if (maint3) { + int32 adx = ABS(dx), ady = ABS(dy); + if (adx == ady) { + xpos = 07777; /* ~ 1.0 */ + ypos = adx; /* or ady */ + } else if (adx > ady) { + xpos = adx; + ypos = 010000L * ady / adx + 1; /* truncates */ + } else /* (adx < ady) */ { + xpos = 010000L * adx / ady + 1; /* truncates */ + ypos = ady; /* according to DZVSC test 100 */ + } + DEBUGF(("delta=0%o, tangent=0%o\r\n", xpos, ypos)); + xpos = PSCALE(xpos); /* compensates for eventual PNORM */ + ypos = PSCALE(ypos); /* compensates for eventual PNORM */ + } + + /* clip to viewport ("working surface") if necessary */ + + /* + * Note about edge conditions and interrupts: + * + * The VT48 documentation isn't very clear about this, but the expected + * behavior has been determined from one of the VS60 diagnostics. The + * "edge flag" flip-flop (bit) corresponds directly to an edge interrupt + * (controlled by the "edge interrupt enable" bit in a Load Status BB + * instruction) and is set precisely twice for *each* vector that is + * clipped in *any* way (on->off, off->off, off->on), assuming that + * after each interrupt is caught a RESUME (set DPC with odd value) is + * issued. The X,Y position registers at the time of the first edge + * interrupt for a clipped vector give the starting position of the + * *visible* segment; the position registers at the time of the second + * edge interrupt for a clipped vector give the ending position of the + * *visible* segment. The "edge indicator" flip-flop (bit) at the time + * of an edge interrupt is set if and only if the vector has been + * clipped at that position. Thus for on-to-off, the edge indicator is + * set for just the second edge interrupt; for off-to-off, the edge + * indicator is set for both edge interrupts; for off-to-on, the edge + * indicator is set for just the first interrupt. Resuming after a + * vector has gone off-screen updates the position registers to the + * location (off-screen) specified in the display file. Edge interrupts + * share an interrupt vector with other "surface" interrupts such as + * light-pen hits. + * + * It appears from diagnostic DZVSD that the menu area might not be + * clipped. + * + * Note that the VT11 cannot generate edge interrupts, and its edge + * indicator provides less information than on the VS60. + */ + + switch (clip_vect = clip3(x0, y0, z0, x1, y1, z1)) { + case 1: /* clipped only on entry */ + case 3: /* clipped on entry and exit */ + edge_indic = 1; /* indicate clipped going in */ + /* XXX might not be correct for VT11 */ + case 2: /* clipped only on exit */ + edge_flag = edge_intr_ena; /* indicate vector-clip interrupt */ + if (edge_flag) { + edge_xpos = clip_x0; + edge_ypos = clip_y0; + edge_zpos = clip_z0; + edge_irq = 1; + } + clip_i = i; + return; /* may be drawn later by vt_cycle() */ + case 0: /* invisible */ + return; + default: + DEBUGF(("clip() bad return: %d\n", clip_vect)); + case -1: /* visible, not clipped */ + clip_vect = 0; + break; /* draw immediately */ + } + } + + if (dx == 0 && dy == 0 && dz == 0) + return; /* hardware skips null vector */ + + /* for character strokes, resort to scissoring: + illum3() illuminates only pixels that lie in the visible display area */ + + /* draw OK even when Maintenance Switch 3 is set */ + /* (but updated position registers must not be used to draw vector) */ + if (i && int0_scope && !clip_vect) /* clipped vector drawn by vt_cycle() */ + if (menu) + lineTwoStep(x0 + MENU_OFFSET, y0, z0, x1 + MENU_OFFSET, y1, z1); + else + lineTwoStep(x0, y0, z0, x1, y1, z1); + + /* + * In case of LP hit, recompute coords using "tangent register", because: + * (1) distinct virtual CRT points can be mapped into the same pixel + * (2) raster computation might not match that of the actual VT48 + */ + + if (lp0_hit) { + long tangent; + int32 adx = ABS(dx), ady = ABS(dy); + if (adx >= ady) { + tangent = 010000L * dy / dx; /* signed */ + lp_ypos = y0 + tangent * (lp_xpos - x0) / 010000L; + tangent = 010000L * dz / dx; + lp_zpos = z0 + tangent * (lp_xpos - x0) / 010000L; + } else { + tangent = 010000L * dx / dy; /* signed */ + lp_xpos = x0 + tangent * (lp_ypos - y0) / 010000L; + tangent = 010000L * dz / dy; + lp_zpos = z0 + tangent * (lp_ypos - y0) / 010000L; + } + DEBUGF(("adjusted LP coords (0%o,0%o,0%o)\r\n", + lp_xpos, lp_ypos, lp_zpos)); + /* xpos,ypos,zpos still pertain to the original endpoint + (assuming that Maintenance Switch 3 isn't set) */ + } +} + +#define vector2(i,dx,dy) vector3(i,dx,dy,0) + /* the extra overhead for Z computation is not much */ + +/* basic vector (multiple of 45 degrees; directions numbered CCW, #0 => +X) */ +static void +basic_vector(int i, int dir, int len) /* unscaled display-file units */ +{ + int32 dx, dy; + + /* Alternatively, could be rasterized specially for each case; then + the general vector2() function could detect these special cases and + invoke this function to handle them, instead of the other way around. */ + + switch (dir) { + case 0: + dx = len; + dy = 0; + break; + case 1: + dx = len; + dy = len; + break; + case 2: + dx = 0; + dy = len; + break; + case 3: + dx = -len; + dy = len; + break; + case 4: + dx = -len; + dy = 0; + break; + case 5: + dx = -len; + dy = -len; + break; + case 6: + dx = 0; + dy = -len; + break; + case 7: + dx = len; + dy = -len; + break; + default: /* "can't happen" */ + DEBUGF(("BUG: basic vector: illegal direction %d\r\n", dir)); + return; + } + DEBUGF(("basic ")); + vector2(i, dx, dy); +} + +/* + * support for VS60 circle/arc option + * + * Since the literature that I have access to does not handle the case where + * starting and ending radii differ, I invented a solution that should be + * "good enough" for now: an approximation of an Archimedean spiral is drawn + * as connected individual chords, with the line-type counter applied (without + * being reset) over the entire curve. + * + * It is not known whether the direction is supposed to be clockwise or + * counterclockwise (the latter is assumed in the following code); it is + * assumed that if the starting and ending directions from the center point + * are identical, that a full circle is being specified. + * + * Although throughout the display simulation substantial effort has been + * invested to avoid using floating point, this preliminary implementation + * of the circle/arc generator does use floating point. Presumably this + * is avoidable, but the algorithmic details would need to be worked out. + * If use of floating point is a problem, #define NO_CONIC_OPT when compiling. + * + * The Z coordinate is linearly interpolated. + */ + +static void +conic3(int i, int32 dcx, int32 dcy, int32 dcz, int32 dex, int32 dey, int32 dez) + /* unscaled display-file units */ +{ +#ifdef NO_CONIC_OPT + /* just draw vector to endpoint (like real VS60 with option missing) */ + vector3(i, dex, dey, dez); +#else + int32 xs, ys, zs, xc, yc, zc, xe, ye, ze, x, y, z, nseg, seg; + double rs, re, dr, as, da, zo, dz; + int ons, one; /* ONSCREEN(xs,ys), ONSCREEN(xe,ye) */ + static double two_pi = -1.0; /* will be set (once only) to 2*Pi */ + static double k; /* will be set to 2-sqrt(4-(Pi/4)^2) */ + + if (two_pi < 0.0) { /* (initial entry only) */ + k = atan2(1.0, 1.0); + two_pi = 8.0 * k; + k = 2.0 - sqrt(4.0 - k*k); + } + dcx = VSCALE(dcx); /* apply vector scale factor */ + dcy = VSCALE(dcy); + dcz = VSCALE(dcz * 4); + dex = VSCALE(dex); + dey = VSCALE(dey); + dez = VSCALE(dez * 4); + xs = PNORM(xpos); /* starting pos. (includes offset) */ + ys = PNORM(ypos); + zs = PNORM(zpos); + xc = PNORM(xpos + dcx); /* center pos. (includes offset) */ + yc = PNORM(ypos + dcy); + zc = PNORM(zpos + dcz); + xe = PNORM(xpos + dex); /* ending pos. (includes offset) */ + ye = PNORM(ypos + dey); + ze = PNORM(zpos + dez); + /* determine vector from center to finish */ + dex -= dcx; /* PSCALEd */ + dey -= dcy; + dez -= dcz; + + DEBUGF(( + "offset, normalized arc i%d s(%ld,%ld,%ld) c(%ld,%ld,%ld) e(%ld,%ld,%ld)\r\n", + i, (long)xs,(long)ys,(long)zs, (long)xc,(long)yc,(long)zc, + (long)xe,(long)ye,(long)ze)); + + /* XXX not known whether Maintenance Switch 3 has any effect for arcs */ + + /* clip to viewport ("working surface") if necessary */ + + /* XXX not implemented yet [could check each chord individually] */ + + /* check for edge conditions (XXX change when conic clipping implemented) */ + /* XXX this test is very crude; should be much more complex */ + ons = ONSCREEN(xs, ys); + one = ONSCREEN(xe, ye); + edge_indic = ons && !one; + edge_flag = edge_indic || (!ons && one); + if (edge_flag) + if (edge_intr_ena) { /* need to clip to viewport */ + /* XXX edge positions aren't right; need proper clipping */ + edge_xpos = xe; + edge_ypos = ye; + edge_zpos = ze; + edge_irq = 1; + goto done; + } else + edge_flag = 0; + + /* XXX for now, resort to scissoring: + illuminates only pixels that lie in the visible display area */ + + if (dcx == 0 && dcy == 0 && dcz == 0 && dex == 0 && dey == 0 && dez == 0) + goto done; /* skip null curve */ + + /* determine starting, ending radii and their maximum */ + rs = PNORM(sqrt((double)dcx*dcx + (double)dcy*dcy)); /* (f.p.) */ + re = PNORM(sqrt((double)dex*dex + (double)dey*dey)); + dr = rs >= re ? rs : re; + + /* determine starting direction from center, and included angle */ + as = dcx == 0 && dcy == 0 ? 0.0 : atan2((double)-dcy, (double)-dcx); + da = (dex == 0 && dey == 0 ? 0.0 : atan2((double)dey, (double)dex)) - as; + while (da <= 0.0) /* exactly 0.0 implies full cycle */ + da += two_pi; + + /* determine number of chords to use; + make deviation from true curve no more than approximately one pixel */ + dr = reduce / dr; + if (dr > k) + dr = k; + nseg = (int32)(da / sqrt(4.0*dr - dr*dr) + 1.0); + if (nseg < 1) /* "can't happen" */ + nseg = 1; + else if (nseg > 360) + nseg = 360; /* arbitrarily chosen upper limit */ + + /* determine angular, radial, and Z step sizes */ + dr = (re - rs) / nseg; + da /= nseg; + dz = (double)(ze - zs) / nseg; + + if (menu) { + xs += MENU_OFFSET; + xc += MENU_OFFSET; + xe += MENU_OFFSET; + } + + line_counter = 037; /* reset line-style counter */ + + /* draw successive chords */ + zo = zs; + for (seg = 0; ++seg < nseg; ) { + rs += dr; + as += da; + re = rs * cos(as); + x = xc + (re >= 0 ? (int32)(re + 0.5) : -(int32)(-re + 0.5)); + re = rs * sin(as); + y = yc + (re >= 0 ? (int32)(re + 0.5) : -(int32)(-re + 0.5)); + z = (int32)(zo + seg * dz); /* truncates */ + lineTwoStep(xs, ys, zs, x, y, z); /* (continuing line style) */ + skip_start = 1; /* don't double-illuminate junctions */ + xs = x; + ys = y; + zs = z; + if (lphit_irq) + goto done; /* light-pen hit interrupted drawing */ + } + lineTwoStep(xs, ys, zs, xe, ye, ze);/* draw final chord to exact endpoint */ + + done: + skip_start = 0; /* important! */ + xpos += dcx + dex; /* update virtual beam position */ + ypos += dcy + dey; + zpos += dcz + dez; + if (lp0_hit) { + DEBUGF(("LP hit on arc at (0%o,0%o,0%o)\r\n", + lp_xpos, lp_ypos, lp_zpos)); + if (lphit_irq) { + /* XXX save parameters for drawing remaining chords */ + } + } +#endif +} + +#define conic2(i,dcx,dcy,dex,dey) conic3(i,dcx,dcy,0,dex,dey,0) + /* the extra overhead for Z computation is not much */ + +/* + * VT11 character font; + * 6x8 matrix, not serpentine encoded, decenders supported as in real VT11 + */ + +static const unsigned char dots[0200][6] = { + { 0x8f, 0x50, 0x20, 0x10, 0x08, 0x07 }, /* 000 lambda */ + { 0x1e, 0x21, 0x22, 0x14, 0x0c, 0x13 }, /* 001 alpha */ + { 0x00, 0x18, 0x24, 0xff, 0x24, 0x18 }, /* 002 phi */ + { 0x83, 0xc5, 0xa9, 0x91, 0x81, 0xc3 }, /* 003 SIGMA */ + { 0x00, 0x46, 0xa9, 0x91, 0x89, 0x06 }, /* 004 delta */ + { 0x03, 0x05, 0x09, 0x11, 0x21, 0x7f }, /* 005 DELTA */ + { 0x00, 0x20, 0x20, 0x3f, 0x01, 0x01 }, /* 006 iota */ + { 0x46, 0x29, 0x11, 0x2e, 0x40, 0x80 }, /* 007 gamma */ + { 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f }, /* 010 intersect */ + { 0x40, 0x3c, 0x04, 0xff, 0x04, 0x78 }, /* 011 psi */ + { 0x00, 0x10, 0x10, 0x54, 0x10, 0x10 }, /* 012 divide by */ + { 0x00, 0x60, 0x90, 0x90, 0x60, 0x00 }, /* 013 degree */ + { 0x00, 0x01, 0x00, 0x10, 0x00, 0x01 }, /* 014 therefore */ + { 0x01, 0x02, 0x3c, 0x02, 0x02, 0x3c }, /* 015 mu */ + { 0x11, 0x7f, 0x91, 0x81, 0x41, 0x03 }, /* 016 pound sterling */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 017 SHIFT IN */ + { 0x20, 0x40, 0x7f, 0x40, 0x7f, 0x40 }, /* 020 pi */ + { 0x00, 0xff, 0x00, 0x00, 0xff, 0x00 }, /* 021 parallel */ + { 0x1d, 0x23, 0x40, 0x42, 0x25, 0x19 }, /* 022 OMEGA */ + { 0x1c, 0x22, 0x61, 0x51, 0x4e, 0x40 }, /* 023 sigma */ + { 0x20, 0x40, 0x40, 0x7f, 0x40, 0x40 }, /* 024 UPSILON */ + { 0x00, 0x1c, 0x2a, 0x49, 0x49, 0x00 }, /* 025 epsilon */ + { 0x10, 0x38, 0x54, 0x10, 0x10, 0x10 }, /* 026 left arrow */ + { 0x10, 0x10, 0x10, 0x54, 0x38, 0x10 }, /* 027 right arrow */ + { 0x00, 0x20, 0x40, 0xfe, 0x40, 0x20 }, /* 030 up arrow */ + { 0x00, 0x04, 0x02, 0x7f, 0x02, 0x04 }, /* 031 down arrow */ + { 0x00, 0xff, 0x80, 0x80, 0x80, 0x80 }, /* 032 GAMMA */ + { 0x00, 0x01, 0x01, 0xff, 0x01, 0x01 }, /* 033 perpendicular */ + { 0x2a, 0x2c, 0x28, 0x38, 0x68, 0xa8 }, /* 034 unequal */ + { 0x24, 0x48, 0x48, 0x24, 0x24, 0x48 }, /* 035 approx equal */ + { 0x00, 0x20, 0x10, 0x08, 0x10, 0x20 }, /* 036 vel */ + { 0xff, 0x81, 0x81, 0x81, 0x81, 0xff }, /* 037 box */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 040 space */ + { 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00 }, /* 041 ! */ + { 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00 }, /* 042 " */ + { 0x00, 0x24, 0xff, 0x24, 0xff, 0x24 }, /* 043 # */ + { 0x22, 0x52, 0xff, 0x52, 0x4c, 0x00 }, /* 044 $ */ + { 0x42, 0xa4, 0x48, 0x12, 0x25, 0x42 }, /* 045 % */ + { 0x66, 0x99, 0x99, 0x66, 0x0a, 0x11 }, /* 046 & */ + { 0x00, 0x00, 0x20, 0x40, 0x80, 0x00 }, /* 047 ' */ + { 0x00, 0x00, 0x3c, 0x42, 0x81, 0x00 }, /* 050 ( */ + { 0x00, 0x00, 0x81, 0x42, 0x3c, 0x00 }, /* 051 ) */ + { 0x00, 0x44, 0x28, 0xf0, 0x28, 0x44 }, /* 052 * */ + { 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10 }, /* 053 + */ + { 0x00, 0x01, 0x06, 0x00, 0x00, 0x00 }, /* 054 , */ + { 0x00, 0x10, 0x10, 0x10, 0x10, 0x10 }, /* 055 - */ + { 0x00, 0x00, 0x06, 0x06, 0x00, 0x00 }, /* 056 . */ + { 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 }, /* 057 / */ + { 0x7e, 0x85, 0x89, 0x91, 0xa1, 0x7e }, /* 060 0 */ + { 0x00, 0x41, 0xff, 0x01, 0x00, 0x00 }, /* 061 1 */ + { 0x47, 0x89, 0x91, 0x91, 0x91, 0x61 }, /* 062 2 */ + { 0x42, 0x81, 0x91, 0xb1, 0xd1, 0x8e }, /* 063 3 */ + { 0x0c, 0x14, 0x24, 0x44, 0xff, 0x04 }, /* 064 4 */ + { 0xf2, 0x91, 0x91, 0x91, 0x91, 0x8e }, /* 065 5 */ + { 0x3c, 0x46, 0x89, 0x89, 0x89, 0x46 }, /* 066 6 */ + { 0x40, 0x87, 0x88, 0x90, 0xa0, 0xc0 }, /* 067 7 */ + { 0x6e, 0x91, 0x91, 0x91, 0x91, 0x6e }, /* 070 8 */ + { 0x62, 0x91, 0x91, 0x91, 0x62, 0x3c }, /* 071 9 */ + { 0x00, 0x66, 0x66, 0x00, 0x00, 0x00 }, /* 072 : */ + { 0x00, 0x00, 0x61, 0x66, 0x00, 0x00 }, /* 073 ; */ + { 0x00, 0x18, 0x24, 0x42, 0x81, 0x00 }, /* 074 < */ + { 0x00, 0x28, 0x28, 0x28, 0x28, 0x28 }, /* 075 = */ + { 0x00, 0x81, 0x42, 0x24, 0x18, 0x00 }, /* 076 > */ + { 0x00, 0x40, 0x80, 0x9d, 0x90, 0x60 }, /* 077 ? */ + { 0x3c, 0x42, 0x91, 0xa9, 0xa9, 0x72 }, /* 100 @ */ + { 0x3f, 0x48, 0x88, 0x88, 0x48, 0x3f }, /* 101 A */ + { 0x81, 0xff, 0x91, 0x91, 0x91, 0x6e }, /* 102 B */ + { 0x3c, 0x42, 0x81, 0x81, 0x81, 0x42 }, /* 103 C */ + { 0x81, 0xff, 0x81, 0x81, 0x42, 0x3c }, /* 104 D */ + { 0x81, 0xff, 0x91, 0x91, 0x91, 0xc3 }, /* 105 E */ + { 0x81, 0xff, 0x91, 0x90, 0x80, 0xc0 }, /* 106 F */ + { 0x3c, 0x42, 0x81, 0x89, 0x89, 0x4f }, /* 107 G */ + { 0xff, 0x10, 0x10, 0x10, 0x10, 0xff }, /* 110 H */ + { 0x00, 0x81, 0xff, 0x81, 0x00, 0x00 }, /* 111 I */ + { 0x0e, 0x01, 0x01, 0x81, 0xfe, 0x80 }, /* 112 J */ + { 0xff, 0x08, 0x10, 0x28, 0x44, 0x83 }, /* 113 K */ + { 0x81, 0xff, 0x81, 0x01, 0x01, 0x03 }, /* 114 L */ + { 0xff, 0x40, 0x30, 0x30, 0x40, 0xff }, /* 115 M */ + { 0xff, 0x20, 0x10, 0x08, 0x04, 0xff }, /* 116 N */ + { 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c }, /* 117 O */ + { 0x81, 0xff, 0x90, 0x90, 0x90, 0x60 }, /* 120 P */ + { 0x3c, 0x42, 0x81, 0x8f, 0x42, 0x3d }, /* 121 Q */ + { 0x81, 0xff, 0x90, 0x98, 0x94, 0x63 }, /* 122 R */ + { 0x22, 0x51, 0x91, 0x91, 0x89, 0x46 }, /* 123 S */ + { 0xc0, 0x80, 0x81, 0xff, 0x81, 0xc0 }, /* 124 T */ + { 0xfe, 0x01, 0x01, 0x01, 0x01, 0xfe }, /* 125 U */ + { 0xff, 0x02, 0x04, 0x08, 0x10, 0xe0 }, /* 126 V */ + { 0xff, 0x02, 0x0c, 0x0c, 0x02, 0xff }, /* 127 W */ + { 0xc3, 0x24, 0x18, 0x18, 0x24, 0xc3 }, /* 130 X */ + { 0x00, 0xe0, 0x10, 0x0f, 0x10, 0xe0 }, /* 131 Y */ + { 0x83, 0x85, 0x89, 0x91, 0xa1, 0xc1 }, /* 132 Z */ + { 0x00, 0x00, 0xff, 0x81, 0x81, 0x00 }, /* 133 [ */ + { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04 }, /* 134 \ */ + { 0x00, 0x00, 0x81, 0x81, 0xff, 0x00 }, /* 135 ] */ + { 0x00, 0x10, 0x20, 0x40, 0x20, 0x10 }, /* 136 ^ */ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 }, /* 137 _ */ + /* for all lowercase characters, first column is just a "descender" flag: */ + { 0x00, 0x00, 0x80, 0x40, 0x20, 0x00 }, /* 140 ` */ + { 0x00, 0x26, 0x29, 0x29, 0x2a, 0x1f }, /* 141 a */ + { 0x00, 0xff, 0x12, 0x21, 0x21, 0x1e }, /* 142 b */ + { 0x00, 0x1e, 0x21, 0x21, 0x21, 0x12 }, /* 143 c */ + { 0x00, 0x1e, 0x21, 0x21, 0x12, 0xff }, /* 144 d */ + { 0x00, 0x1e, 0x29, 0x29, 0x29, 0x19 }, /* 145 e */ + { 0x00, 0x20, 0x7f, 0xa0, 0xa0, 0x80 }, /* 146 f */ + { 0x01, 0x78, 0x85, 0x85, 0x49, 0xfe }, /* 147 g */ + { 0x00, 0xff, 0x10, 0x20, 0x20, 0x1f }, /* 150 h */ + { 0x00, 0x00, 0x21, 0xbf, 0x01, 0x00 }, /* 151 i */ + { 0x01, 0x02, 0x01, 0x81, 0xfe, 0x00 }, /* 152 j */ + { 0x00, 0xff, 0x08, 0x14, 0x22, 0x21 }, /* 153 k */ + { 0x00, 0x00, 0xfe, 0x01, 0x01, 0x00 }, /* 154 l */ + { 0x00, 0x3f, 0x20, 0x3f, 0x20, 0x3f }, /* 155 m */ + { 0x00, 0x3f, 0x10, 0x20, 0x20, 0x1f }, /* 156 n */ + { 0x00, 0x1e, 0x21, 0x21, 0x21, 0x1e }, /* 157 o */ + { 0x01, 0xff, 0x48, 0x84, 0x84, 0x78 }, /* 160 p */ + { 0x01, 0x78, 0x84, 0x84, 0x48, 0xff }, /* 161 q */ + { 0x00, 0x3f, 0x08, 0x10, 0x20, 0x20 }, /* 162 r */ + { 0x00, 0x12, 0x29, 0x29, 0x29, 0x26 }, /* 163 s */ + { 0x00, 0x20, 0xfe, 0x21, 0x21, 0x00 }, /* 164 t */ + { 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3f }, /* 165 u */ + { 0x00, 0x3c, 0x02, 0x01, 0x02, 0x3c }, /* 166 v */ + { 0x00, 0x3e, 0x01, 0x1e, 0x01, 0x3e }, /* 167 w */ + { 0x00, 0x23, 0x14, 0x08, 0x14, 0x23 }, /* 170 x */ + { 0x01, 0xf8, 0x05, 0x05, 0x09, 0xfe }, /* 171 y */ + { 0x00, 0x23, 0x25, 0x29, 0x31, 0x21 }, /* 172 z */ + { 0x00, 0x18, 0x66, 0x81, 0x81, 0x00 }, /* 173 { */ + { 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00 }, /* 174 | */ + { 0x00, 0x00, 0x81, 0x81, 0x66, 0x18 }, /* 175 } */ + { 0x00, 0x0c, 0x10, 0x08, 0x04, 0x18 }, /* 176 ~ */ + { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff } /* 177 rubout */ +}; + +/* + * VS60 character stroke table + * + * stroke[] contains "prototype" encodings for all vector strokes (visible and + * invisible) needed to draw each character at a standard size. The actual + * display is of course properly italicized, positioned, scaled, and rotated. + * + * Variable-length entries are used; each character stroke sequence is + * terminated by a 0-valued byte. Pointers to the appropriate data for all + * characters are stored into sstroke[] during a one-time initialization. + * + * The prototype strokes are for the most part constrained to a 4x6 unit area, + * except for a few cases that are handled by kludging the coordinates. + * Coordinates are relative to the left end of the character baseline. + * + * A prototype stroke is encoded as 8 bits SVXXXYYY: + * S = 0 if YYY is correct as is + * 1 if YYY needs to have 2 subtracted + * V = 0 if stroke is invisible (move) + * 1 if stroke is visible (draw) + * XXX = final X coord of stroke (0..4; 7 => -1) + * YYY = final Y coord of stroke (0..6) + */ + +static const unsigned char stroke[] = { + /* + * While based on the actual VT48 strokes, these have been tweaked + * (especially the lower-case letters, which had erratic sizes) to + * improve their appearance and/or reduce the number of strokes. + * Several of the special symbols (e.g. alpha, delta, iota) could + * be further improved, but I didn't want to make them look too + * different from the original. Note that VS60 screen photos + * disagree, for several characters, with the (incomplete) chart of + * strokes given in the VT48 manual. (There could have been ROM changes.) + * + * The simulated character sizes are not exact at all scales, but there + * is no really good way to fix this without spoiling the appearance. + * char. scale VS60 units simulation units (pixel has size!) + * 1/2 5 x 7 5 x 7 + * 1 10 x 14 9 x 13 + * 3/2 15 x 21 13 x 19 + * 2 20 x 28 17 x 25 + */ + 0111, 0123, 0006, 0115, 0131, 0140, 0, /* 000 lambda */ + 0042, 0132, 0114, 0103, 0112, 0134, 0144, 0, /* 001 alpha */ + 0011, 0103, 0115, 0135, 0143, 0131, 0111, 0010, + 0146, 0, /* 002 phi */ + 0040, 0100, 0133, 0106, 0146, 0, /* 003 SIGMA */ + 0022, 0111, 0120, 0131, 0113, 0115, 0124, 0, /* 004 delta */ + 0140, 0124, 0100, 0, /* 005 DELTA */ + 0006, 0126, 0120, 0140, 0, /* 006 iota */ + 0006, 0115, 0131, 0120, 0111, 0135, 0146, 0, /* 007 gamma */ + 0104, 0116, 0136, 0144, 0140, 0, /* 010 intersect */ + 0010, 0136, 0044, 0142, 0131, 0111, 0102, 0104, 0, /* 011 psi */ + 0022, 0122, 0003, 0143, 0024, 0124, 0, /* 012 divide by */ + 0024, 0115, 0126, 0135, 0124, 0, /* 013 degree */ + 0001, 0101, 0025, 0125, 0041, 0141, 0, /* 014 therefore */ + 0111, 0115, 0012, 0121, 0131, 0142, 0045, 0142, + 0151, 0, /* 015 mu */ + 0105, 0116, 0126, 0135, 0013, 0173, 0001, 0120, + 0130, 0141, 0, /* 016 pound sterling */ + 0, /* 017 SHIFT IN */ + 0003, 0114, 0144, 0034, 0130, 0010, 0114, 0, /* 020 pi */ + 0010, 0116, 0036, 0130, 0, /* 021 parallel */ + 0110, 0111, 0102, 0104, 0115, 0135, 0144, 0142, + 0131, 0130, 0140, 0, /* 022 OMEGA */ + 0025, 0134, 0132, 0120, 0110, 0102, 0104, 0146, 0, /* 023 sigma */ + 0010, 0136, 0046, 0116, 0105, 0, /* 024 UPSILON */ + 0003, 0133, 0045, 0136, 0116, 0105, 0101, 0110, + 0130, 0141, 0, /* 025 epsilon */ + 0042, 0102, 0113, 0011, 0102, 0, /* 026 left arrow */ + 0002, 0142, 0133, 0031, 0142, 0, /* 027 right arrow */ + 0020, 0124, 0133, 0013, 0124, 0, /* 030 up arrow */ + 0024, 0120, 0131, 0011, 0120, 0, /* 031 down arrow */ + 0106, 0146, 0144, 0, /* 032 GAMMA */ + 0140, 0026, 0120, 0, /* 033 perpendicular */ + 0001, 0145, 0044, 0104, 0002, 0142, 0, /* 034 unequal */ + 0001, 0112, 0131, 0142, 0044, 0133, 0114, 0103, 0, /* 035 approx equal */ + 0016, 0125, 0135, 0146, 0, /* 036 vel */ + 0106, 0146, 0140, 0100, 0, /* 037 box */ + 0, /* 040 space */ + 0020, 0120, 0021, 0125, 0, /* 041 ! */ + 0004, 0126, 0046, 0124, 0, /* 042 " */ + 0012, 0116, 0036, 0132, 0043, 0103, 0005, 0145, 0, /* 043 # */ + 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, + 0105, 0116, 0136, 0145, 0026, 0120, 0, /* 044 $ */ + 0146, 0116, 0105, 0114, 0125, 0116, 0032, 0141, + 0130, 0121, 0132, 0, /* 045 % */ + 0040, 0104, 0105, 0116, 0126, 0135, 0134, 0101, + 0110, 0120, 0142, 0, /* 046 & */ + 0014, 0136, 0, /* 047 ' */ + 0030, 0112, 0114, 0136, 0, /* 050 ( */ + 0010, 0132, 0134, 0116, 0, /* 051 ) */ + 0002, 0146, 0026, 0122, 0042, 0106, 0, /* 052 * */ + 0021, 0125, 0003, 0143, 0, /* 053 + */ + 0211, 0120, 0121, 0, /* 054 , */ + 0003, 0143, 0, /* 055 - */ + 0020, 0120, 0, /* 056 . */ + 0146, 0, /* 057 / */ + 0001, 0145, 0136, 0116, 0105, 0101, 0110, 0130, + 0141, 0145, 0, /* 060 0 */ + 0010, 0130, 0020, 0126, 0115, 0, /* 061 1 */ + 0005, 0116, 0136, 0145, 0144, 0100, 0140, 0, /* 062 2 */ + 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0005, + 0116, 0136, 0145, 0144, 0133, 0, /* 063 3 */ + 0030, 0136, 0025, 0102, 0142, 0, /* 064 4 */ + 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, + 0106, 0146, 0, /* 065 5 */ + 0002, 0113, 0133, 0142, 0141, 0130, 0110, 0101, + 0105, 0116, 0136, 0145, 0, /* 066 6 */ + 0006, 0146, 0120, 0, /* 067 7 */ + 0013, 0133, 0142, 0141, 0130, 0110, 0101, 0102, + 0113, 0104, 0105, 0116, 0136, 0145, 0144, 0133, 0, /* 070 8 */ + 0001, 0110, 0130, 0141, 0145, 0136, 0116, 0105, + 0104, 0113, 0133, 0144, 0, /* 071 9 */ + 0022, 0122, 0024, 0124, 0, /* 072 : */ + 0010, 0121, 0122, 0024, 0124, 0, /* 073 ; */ + 0030, 0103, 0136, 0, /* 074 < */ + 0002, 0142, 0004, 0144, 0, /* 075 = */ + 0010, 0143, 0116, 0, /* 076 > */ + 0020, 0120, 0021, 0122, 0144, 0145, 0136, 0116, + 0105, 0104, 0, /* 077 ? */ + 0030, 0110, 0101, 0104, 0115, 0145, 0141, 0121, + 0112, 0113, 0124, 0134, 0131, 0, /* 100 @ */ + 0104, 0116, 0136, 0144, 0140, 0042, 0102, 0, /* 101 A */ + 0106, 0136, 0145, 0144, 0133, 0103, 0033, 0142, + 0141, 0130, 0100, 0, /* 102 B */ + 0041, 0130, 0110, 0101, 0105, 0116, 0136, 0145, 0, /* 103 C */ + 0106, 0136, 0145, 0141, 0130, 0100, 0, /* 104 D */ + 0003, 0133, 0046, 0106, 0100, 0140, 0, /* 105 E */ + 0106, 0146, 0033, 0103, 0, /* 106 F */ + 0023, 0143, 0141, 0130, 0110, 0101, 0105, 0116, + 0136, 0145, 0, /* 107 G */ + 0106, 0003, 0143, 0046, 0140, 0, /* 110 H */ + 0010, 0130, 0020, 0126, 0016, 0136, 0, /* 111 I */ + 0001, 0110, 0120, 0131, 0136, 0, /* 112 J */ + 0106, 0046, 0102, 0024, 0140, 0, /* 113 K */ + 0006, 0100, 0140, 0, /* 114 L */ + 0106, 0123, 0146, 0140, 0, /* 115 M */ + 0106, 0140, 0146, 0, /* 116 N */ + 0001, 0105, 0116, 0136, 0145, 0141, 0130, 0110, + 0101, 0, /* 117 O */ + 0106, 0136, 0145, 0144, 0133, 0103, 0, /* 120 P */ + 0030, 0110, 0101, 0105, 0116, 0136, 0145, 0141, + 0130, 0031, 0140, 0, /* 121 Q */ + 0106, 0136, 0145, 0144, 0133, 0103, 0033, 0140, 0, /* 122 R */ + 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, + 0105, 0116, 0136, 0145, 0, /* 123 S */ + 0020, 0126, 0006, 0146, 0, /* 124 T */ + 0006, 0101, 0110, 0130, 0141, 0146, 0, /* 125 U */ + 0006, 0120, 0146, 0, /* 126 V */ + 0006, 0100, 0123, 0140, 0146, 0, /* 127 W */ + 0146, 0006, 0140, 0, /* 130 X */ + 0020, 0123, 0106, 0046, 0123, 0, /* 131 Y */ + 0006, 0146, 0100, 0140, 0033, 0113, 0, /* 132 Z */ + 0030, 0110, 0116, 0136, 0, /* 133 [ */ + 0006, 0140, 0, /* 134 \ */ + 0010, 0130, 0136, 0116, 0, /* 135 ] */ + 0003, 0126, 0143, 0, /* 136 ^ */ + 0140, 0, /* 137 _ */ + 0016, 0134, 0, /* original was backward */ /* 140 ` */ + 0032, 0112, 0101, 0110, 0130, 0133, 0124, 0114, 0, /* 141 a */ + 0006, 0100, 0120, 0131, 0133, 0124, 0104, 0, /* 142 b */ + 0033, 0124, 0114, 0103, 0101, 0110, 0120, 0131, 0, /* 143 c */ + 0036, 0130, 0110, 0101, 0103, 0114, 0134, 0, /* 144 d */ + 0002, 0132, 0133, 0124, 0114, 0103, 0101, 0110, + 0120, 0, /* 145 e */ + 0010, 0115, 0126, 0136, 0145, 0023, 0103, 0, /* 146 f */ + 0200, 0320, 0331, 0134, 0114, 0103, 0101, 0110, + 0130, 0, /* 147 g */ + 0106, 0004, 0124, 0133, 0130, 0, /* 150 h */ + 0020, 0124, 0025, 0125, 0, /* 151 i */ + 0201, 0310, 0320, 0331, 0134, 0035, 0135, 0, /* 152 j */ + 0105, 0034, 0101, 0023, 0130, 0, /* 153 k */ + 0010, 0130, 0020, 0126, 0116, 0, /* 154 l */ + 0104, 0114, 0122, 0134, 0144, 0140, 0, /* 155 m */ + 0104, 0124, 0133, 0130, 0, /* 156 n */ + 0010, 0120, 0131, 0133, 0124, 0114, 0103, 0101, + 0110, 0, /* 157 o */ + 0200, 0104, 0124, 0133, 0131, 0120, 0100, 0, /* 160 p */ + 0030, 0110, 0101, 0103, 0114, 0134, 0330, 0341, 0, /* 161 q */ + 0104, 0124, 0133, 0, /* 162 r */ + 0001, 0110, 0120, 0131, 0122, 0112, 0103, 0114, + 0124, 0133, 0, /* 163 s */ + 0030, 0121, 0125, 0034, 0114, 0, /* 164 t */ + 0014, 0111, 0120, 0130, 0141, 0144, 0, /* 165 u */ + 0004, 0120, 0144, 0, /* 166 v */ + 0004, 0102, 0110, 0122, 0130, 0142, 0144, 0, /* 167 w */ + 0134, 0004, 0130, 0, /* 170 x */ + 0210, 0120, 0134, 0004, 0120, 0, /* 171 y */ + 0004, 0134, 0100, 0130, 0, /* 172 z */ + 0030, 0121, 0122, 0113, 0124, 0125, 0136, 0, /* 173 { */ + 0020, 0122, 0024, 0126, 0, /* 174 | */ + 0010, 0121, 0122, 0133, 0124, 0125, 0116, 0, /* 175 } */ + 0003, 0114, 0132, 0143, 0, /* 176 ~ */ + 0140, 0146, 0106, 0100, 0010, 0116, 0026, 0120, + 0030, 0136, 0 /* 177 rubout */ + }; + +/* pointers to start of stroke data for each character */ +static const unsigned char *sstroke[128] = { NULL }; /* init. at run time */ + +/* character generator; supports control chars, POPR on term character (VS60) */ + +static int /* returns nonzero iff VS60 char terminate feature triggered */ +character(int c) +{ + /* following table maps cs_index to line-feed spacing for VS60 */ + static const unsigned char vs60_csp_h[4] = + {PSCALE(12), PSCALE(24), PSCALE(46), PSCALE(62)}; + /* following tables map cs_index to adjustments for sub/superscript */ + /* (cs_index 0 just a guess; others from VS60 Instruction Test Part II) */ + static const unsigned char sus_left[4] = + {PSCALE(0), PSCALE(2), PSCALE(4), PSCALE(3)}; + static const unsigned char susr_left[4] = + {PSCALE(0), PSCALE(2), PSCALE(4), PSCALE(0)}; + static const unsigned char sub_down[4] = + {PSCALE(2), PSCALE(3), PSCALE(6), PSCALE(7)}; + static const unsigned char sup_up[4] = + {PSCALE(5), PSCALE(9), PSCALE(18), PSCALE(24)}; + static const unsigned char esus_right[4] = + {PSCALE(0), PSCALE(2), PSCALE(0), PSCALE(0)}; + static const unsigned char esub_up[4] = + {PSCALE(2), PSCALE(3), PSCALE(6), PSCALE(8)}; + int x, y; + int32 xbase, ybase, xnext, ynext; + + if (shift_out) { + if (c >= 040) { + so_flag = char_irq = 1; /* will generate a char intr. */ + char_buf = c; + return 0; /* presumably, no POPR on term? */ + } + if (c == 017) { /* SHIFT IN */ + shift_out = 0; + goto copy; + } + } else { /* !shift_out */ + + if (c <= 040) { + switch (c) { + + case 000: /* NULL */ + goto cesc; /* apparently not copied to char_buf */ + case 010: /* BACKSPACE */ + if (char_rotate) + ypos -= CSCALE(vt11_csp_w); + else + xpos -= CSCALE(vt11_csp_w); + break; + case 012: /* LINE FEED */ + if (char_rotate) + xpos += (VT11 ? CSCALE(vt11_csp_h) : vs60_csp_h[cs_index]); + else + ypos -= (VT11 ? CSCALE(vt11_csp_h) : vs60_csp_h[cs_index]); + break; + case 015: /* CARRIAGE RETURN */ + if (char_rotate) + ypos = yoff; + else + xpos = xoff; + break; + case 016: /* SHIFT OUT */ + shift_out = 1; + break; + + case 021: /* SUPERSCRIPT */ + if (VT11) + break; + if (char_rotate) { + xpos -= sup_up[cs_index]; + ypos -= susr_left[cs_index]; + } else { + xpos -= sus_left[cs_index]; + ypos += sup_up[cs_index]; + } + if (cs_index > 0) + char_scale = csi2csf[--cs_index]; + break; + case 022: /* SUBSCRIPT */ + if (VT11) + break; + if (char_rotate) { + xpos += sub_down[cs_index]; + ypos -= susr_left[cs_index]; + } else { + xpos -= sus_left[cs_index]; + ypos -= sub_down[cs_index]; + } + if (cs_index > 0) + char_scale = csi2csf[--cs_index]; + break; + case 023: /* END SUPERSCRIPT */ + if (VT11) + break; + if (cs_index < 3) + char_scale = csi2csf[++cs_index]; + if (char_rotate) { + xpos += sup_up[cs_index]; + ypos += esus_right[cs_index]; + } else { + xpos += esus_right[cs_index]; + ypos -= sup_up[cs_index]; + } + break; + case 024: /* END SUBSCRIPT */ + if (VT11) + break; + if (cs_index < 3) + char_scale = csi2csf[++cs_index]; + if (char_rotate) { + xpos -= esub_up[cs_index]; + ypos += esus_right[cs_index]; + } else { + xpos += esus_right[cs_index]; + ypos += esub_up[cs_index]; + } + break; + case 040: /* SPACE */ + goto space; + default: /* other control codes ignored */ + break; + } + goto copy; + } + } + + /* VT11/VS60 doesn't draw any part of a character if its *baseline* is + (partly) offscreen; thus the top of a character might be clipped */ + /* (no allowance for descender, italic, or interchar. spacing) */ + + /* virtual CRT coordinates of this and the next character's "origin": */ + xbase = xnext = PNORM(xpos); + ybase = ynext = PNORM(ypos); + if (char_rotate) + ynext += (vt11_csp_w <= 12 ? 10 : 11); + else + xnext += (vt11_csp_w <= 12 ? 10 : 11); + + edge_indic = ONSCREEN(xbase, ybase) && !ONSCREEN(xnext, ynext); + edge_flag = edge_indic || + !ONSCREEN(xbase, ybase) && ONSCREEN(xnext, ynext); + /* (scaling cannot make spacing so large that it crosses the + "working surface" while going from offscreen to offscreen) */ + if (edge_flag) + if (edge_intr_ena) { + edge_irq = 1; + goto space; + } else + edge_flag = 0; + + if (!ONSCREEN(xbase, ybase) || !ONSCREEN(xnext, ynext)) + goto space; + + /* plot a (nominally on-screen) graphic symbol */ + + if (VT11) { + unsigned char col, prvcol; + + /* plot a graphic symbol (unscaled, unrotated) using a dot matrix */ + + /* not drawn in a serpentine manner; supports control characters */ + + /* draw pattern using 2x2 dot size, with fudges for spacing & italics */ + /* (looks very nice under all conditions at full resolution) */ + + if (c >= 0140) { /* lower-case */ + if (dots[c][0]) /* flag: with descender */ + ybase -= 4; + x = 1; /* skip first column (descender flag) */ + } else /* no descender */ + x = 0; + + prvcol = 0; + col = dots[c][x]; /* starting column bit pattern */ + for (; x < 6; ++x) { + int xllc = 2*x, yllc = 0; + unsigned char nxtcol = (x == 5) ? 0 : dots[c][x+1]; + + /* no LP hit on first or last column */ + lp_suppress = x == 0 || x == 5; + + for (y = 0; y < 8; ++y) { + int delay_skew; + int compress = vt11_csp_w <= 12 && x == 2; + int dot = col & (1<>y) == 2)) + ++xllc; /* shift within selected dots */ + } + ++yllc; + if (dot) { + illum2(xbase + xllc, ybase + yllc); + if (!compress || nxtdot == 0) + illum2(xbase + xllc + 1, ybase + yllc); + } + if (italics && delay_skew) + ++xllc; /* shift between selected dots */ + ++yllc; + } + if (vt11_csp_w <= 12 && x == 2) /* narrow spacing: */ + --xbase; /* slight compression */ + + prvcol = col; + col = nxtcol; + } + lp_suppress = 0; + + } else { /* VS60 */ + const unsigned char *p; /* -> stroke data */ + unsigned char s; /* encoded stroke */ + int32 xlast, ylast; /* "beam follower" within character */ + int32 xp = xpos, yp = ypos; /* save these (altered by vector2()) */ + + /* plot a graphic symbol using vector strokes */ + + /* initialize starting stroke pointers upon first use only */ + if (sstroke[0] == NULL) { + p = stroke; /* -> stroke data */ + + for (s = 0; s < 128; ++s) { /* for each ASCII code value s */ + sstroke[s] = p; /* code's stroke list starts here */ + while (*p++) /* 0 terminates the data */ + ; + } + } + + stroking = 1; /* prevents stroke clipping etc. and + tells vector2() to apply global + character scale factor */ + xlast = ylast = 0; + for (p = sstroke[c]; (s = *p) != 0; ++p) { + xnext = (s & 0070) >> 3; + if (xnext == 7) + xnext = -1; /* (kludge needed for pound sterling) */ + ynext = s & 0007; /* delay stretching for just a moment */ + if (s & 0200) + ynext -= 2; /* kludge for stroke below baseline */ + xnext *= 2; + if (italics) + xnext += ynext; + ynext *= 2; /* safe to stretch now */ + + if (s & 0100) { /* visible stroke */ + int32 dx = xnext - xlast, /* (okay if both 0) */ + dy = ynext - ylast; + + if (char_rotate) + vector2(1, -dy, dx); + else + vector2(1, dx, dy); + } else /* invisible stroke, can do faster */ + if (char_rotate) { + xpos = xp - CSCALE(ynext); + ypos = yp + CSCALE(xnext); + } else { + xpos = xp + CSCALE(xnext); + ypos = yp + CSCALE(ynext); + } + xlast = xnext; + ylast = ynext; + skip_start = (s & 0100) && (p[1] & 0100); /* avoid bright dot */ + } + /* skip_start was reset to 0 by the last iteration! */ + stroking = 0; + xpos = xp; /* restore for use in spacing (below) */ + ypos = yp; + } /* end of graphic character drawing */ + + space: + if (char_rotate) + ypos += CSCALE(vt11_csp_w); + else + xpos += CSCALE(vt11_csp_w); + + /* There may have been multiple LP hits during drawing; + the last one is the only one that can be reported. */ + + copy: + char_buf = c; + + cesc: + if (char_escape && c == char_term) { /* (VS60) */ + pop(1); + return 1; + } else + return 0; +} + +/* + * Perform one display processor "cycle": + * If display processor is halted or awaiting sync, just performs "background" + * maintenance tasks and returns 0. + * Otherwise, draws any pending clipped vector (VS60 only). + * Otherwise, completes any pending second CHAR or BSVECT (must be a RESUME + * after interrupt on first CHAR or BSVECT), or fetches one word from the + * display file and processes it. May post an interrupt; returns 1 if display + * processor is still running, or 0 if halted or an interrupt was posted. + * + * word_number keeps track of the state of multi-word graphic data parsing; + * word_number also serves to keep track of half-word for graphic data having + * two independent entities encoded within one word (CHAR or BSVECT). + * Note that, for the VT11, there might be control words (e.g. JMPA) embedded + * within the data! (We don't know of any application that exploits this.) + */ +int +vt11_cycle(int us, int slowdown) +{ + static vt11word inst; + static int i; + static int32 x, y, z, ex, ey, sxo, syo, szo; + int c; + int32 ez; + static uint32 usec = 0; /* cumulative */ + static uint32 msec = 0; /* ditto */ + uint32 new_msec; + INIT + /* keep running time counter; track state even when processor is idle */ + + new_msec = (usec += us) / 1000; + + if (msec / BLINK_COUNT != new_msec / BLINK_COUNT) + blink_off = !blink_off; + + /* if awaiting sync, look for next frame start */ + if (sync_period && (msec / sync_period != new_msec / sync_period)) + sync_period = 0; /* start next frame */ + + msec = new_msec; + + if ((sync_period || maint1 || !busy) && !maint2) + goto age_ret; /* just age the display */ + + /* draw a clipped vector [perhaps after resume from edge interrupt] */ + + if (clip_vect) { + int32 dx = clip_x1 - clip_x0, + dy = clip_y1 - clip_y0, + dz = clip_z1 - clip_z0; + DEBUGF(("clipped vector i%d (%ld,%ld,%ld) to (%ld,%ld,%ld)\r\n", clip_i, + (long)clip_x0, (long)clip_y0, (long)clip_z0, + (long)clip_x1, (long)clip_y1, (long)clip_z1)); + if (VS60 /* XXX assuming VT11 doesn't display */ + && (dx != 0 || dy != 0 || dz != 0) /* hardware skips null vects */ + && clip_i && int0_scope) /* show it */ + if (menu) + lineTwoStep(clip_x0 + MENU_OFFSET, clip_y0, clip_z0, + clip_x1 + MENU_OFFSET, clip_y1, clip_z1); + else + lineTwoStep(clip_x0, clip_y0, clip_z0, + clip_x1, clip_y1, clip_z1); + /* + * In case of LP hit, recompute coords using "tangent register", + * because: + * (1) distinct virtual CRT points can be mapped into the same pixel + * (2) raster computation might not match that of the actual VT48 + */ + if (lp0_hit) { + long tangent; + int32 adx = ABS(dx), ady = ABS(dy); + if (adx >= ady) { + tangent = 010000L * dy / dx; /* signed */ + lp_ypos = clip_y0 + tangent * (lp_xpos - clip_x0) / 010000L; + tangent = 010000L * dz / dx; + lp_zpos = clip_z0 + tangent * (lp_xpos - clip_x0) / 010000L; + } else { + tangent = 010000L * dx / dy; /* signed */ + lp_xpos = clip_x0 + tangent * (lp_ypos - clip_y0) / 010000L; + tangent = 010000L * dz / dy; + lp_zpos = clip_z0 + tangent * (lp_ypos - clip_y0) / 010000L; + } + DEBUGF(("adjusted LP coords (0%o,0%o,0%o)\r\n", + lp_xpos, lp_ypos, lp_zpos)); + /* xpos,ypos,zpos still pertain to the original endpoint + (assuming that Maintenance Switch 3 isn't set) */ + } + if (VS60) { /* XXX assuming just 1 intr for VT11 */ + edge_xpos = clip_x1; + edge_ypos = clip_y1; + edge_zpos = clip_z1; + edge_indic = (clip_vect & 2) != 0; /* indicate clipped going out */ + edge_flag = edge_intr_ena; + if (edge_flag) { + edge_irq = 1; + vt_lpen_intr(); /* post graphic interrupt to host */ + } + } + clip_vect = 0; /* this finishes the condition */ + goto check; /* possibly post more interrupts; age */ + } + + /* fetch next word from display file (if needed) and process it */ + + if (word_number != 1 || (graphic_mode != CHAR && graphic_mode != BSVECT)) { + time_out = vt_fetch((uint32)((DPC+reloc)&0777777), &inst); + DPC += 2; + if (time_out) + goto bus_timeout; + DEBUGF(("0%06o: 0%06o\r\n", + (unsigned)(DPC - 2 + reloc) & 0777777, (unsigned)inst)); + if (finish_jmpa) + goto jmpa; + if (finish_jsra) + goto jsra; + } + /* else have processed only half the CHAR or BSVECT data word so far */ + + fetched: + + if (TESTBIT(inst,15)) { /* control */ + unsigned op; + mode_field = GETFIELD(inst,14,11); /* save bits 14-11 for diags. */ + word_number = -1; /* flags "control mode"; ersatz 0 */ + switch (mode_field) { + + case 7: /* Set Graphic Mode 0111 */ + case 011: /* Set Graphic Mode 1001 */ + if (VT11) + goto bad_ins; + /*FALLTHRU*/ + case 010: /* Set Graphic Mode 1000 */ + if (VT11) { + DEBUGF(("SGM 1000 IGNORED\r\n")); + break; + } + /*FALLTHRU*/ + case 0: /* Set Graphic Mode 0000 */ + case 1: /* Set Graphic Mode 0001 */ + case 2: /* Set Graphic Mode 0010 */ + case 3: /* Set Graphic Mode 0011 */ + case 4: /* Set Graphic Mode 0100 */ + case 5: /* Set Graphic Mode 0101 */ + case 6: /* Set Graphic Mode 0110 */ + DEBUGF(("Set Graphic Mode %u", (unsigned)mode_field)); + graphic_mode = mode_field; + offset = 0; + shift_out = 0; /* seems to be right */ + if (TESTBIT(inst,10)) { + intensity = GETFIELD(inst,9,7); + DEBUGF((" intensity=%d", (int)intensity)); + } + if (TESTBIT(inst,6)) { + lp0_intr_ena = TESTBIT(inst,5); + DEBUGF((" lp0_intr_ena=%d", (int)lp0_intr_ena)); + } + if (TESTBIT(inst,4)) { + blink_ena = TESTBIT(inst,3); + DEBUGF((" blink=%d", (int)blink_ena)); + } + if (TESTBIT(inst,2)) { + line_type = GETFIELD(inst,1,0); + DEBUGF((" line_type=%d", (int)line_type)); + } + DEBUGF(("\r\n")); + break; + + case 012: /* 1010: Load Name Register */ + if (VT11) + goto bad_ins; + name = GETFIELD(inst,10,0); + DEBUGF(("Load Name Register name=0%o\r\n", name)); + { static unsigned nmask[4] = { 0, 03777, 03770, 03600 }; + + if (search != 0 && ((name^assoc_name) & nmask[search]) == 0) + name_irq = 1; /* will cause name-match interrupt */ + } + break; + + case 013: /* 1011: Load Status C */ + if (VT11) + goto bad_ins; + DEBUGF(("Load Status C")); + if (TESTBIT(inst,9)) { + char_rotate = TESTBIT(inst,8); + DEBUGF((" char_rotate=d", (int)char_rotate)); + } + if (TESTBIT(inst,7)) { + cs_index = GETFIELD(inst,6,5); /* 0, 1, 2, 3 */ + char_scale = csi2csf[cs_index]; /* for faster CSCALE macro */ + DEBUGF((" cs_index=%d(x%d/4)", (int)cs_index, (int)char_scale)); + } + if (TESTBIT(inst,4)) { + vector_scale = GETFIELD(inst,3,0); + DEBUGF((" vector_scale=%d/4", (int)vector_scale)); + } + DEBUGF(("\r\n")); + break; + + case 014: /* 1100__ */ + if (VT11) /* other bits are "spare" */ + op = 0; /* always Display Jump Absolute */ + else + op = GETFIELD(inst,10,9); + switch (op) { + + case 0: /* 110000: Display Jump Absolute */ + finish_jmpa = 1; + break; + jmpa: + finish_jmpa = 0; + DPC = inst & ~1; + DEBUGF(("Display Jump Absolute 0%06o\r\n", (unsigned)inst)); + break; + + case 1: /* 110001: Display Jump Relative */ + ez = GETFIELD(inst,7,0);/* relative address (words) */ + ez *= 2; /* convert to bytes */ + /* have to be careful; DPC is unsigned */ + if (TESTBIT(inst,8)) { +#if 0 /* manual seems to say this, but it's wrong: */ + DPC -= ez; + DEBUGF(("Display Jump Relative -0%o\r\n", + (unsigned)ez)); +#else /* sign extend, twos complement add, 16-bit wrapping */ + DPC = (DPC + (~0777 | ez)) & 0177777; + DEBUGF(("Display Jump Relative -0%o\r\n", + ~((~0777 | ez) - 1))); +#endif + } else { + DPC += (vt11word)ez; + DEBUGF(("Display Jump Relative +0%o\r\n", + (unsigned)ez)); + } + /* DPC was already incremented by 2 */ + break; + + case 2: /* 110010: Display Jump to Subroutine Absolute */ + finish_jsra = 1; + jsr = 1; /* diagnostic test needs this here */ + /* but the documentation says JSR bit set only for JSR REL! */ + goto check; /* (break would set jsr = 0) */ + jsra: + finish_jsra = 0; + push(); /* save return address and parameters */ + DPC = inst & ~1; + DEBUGF(("Display Jump to Subroutine Absolute 0%06o\r\n", + (unsigned)inst)); + goto check; /* (break would set jsr = 0) */ + + case 3: /* 110011: Display Jump to Subroutine Relative */ + ez = GETFIELD(inst,7,0);/* relative address (words) */ + ez *= 2; /* convert to bytes */ + push(); /* save return address and parameters */ + /* have to be careful; DPC is unsigned */ + if (TESTBIT(inst,8)) { +#if 0 /* manual seems to say this, but it's wrong: */ + DPC -= ez; + DEBUGF(("Display Jump to Subroutine Relative -0%o\r\n", + (unsigned)ez)); +#else /* sign extend, twos complement add, 16-bit wrapping */ + DPC = (DPC + (~0777 | ez)) & 0177777; + DEBUGF(("Display Jump to Subroutine Relative -0%o\r\n", + ~((~0777 | ez) - 1))); +#endif + } else { + DPC += (vt11word)ez; + DEBUGF(("Display Jump to Subroutine Relative +0%o\r\n", + (unsigned)ez)); + } + /* DPC was already incremented by 2 */ + break; /* jsr = 0 ?? */ + } + break; + + case 015: /* 1101__ */ + if (VT11) + DEBUGF(("Display NOP\r\n")); + else { + op = GETFIELD(inst,10,9); + switch (op) { + + case 0: /* 110100: Load Scope Selection */ + /* also used as Display NOP */ + DEBUGF(("Load Scope Selection")); + c = TESTBIT(inst,8); + DEBUGF((" console=%d", c)); + if (TESTBIT(inst,7)) { + ez = TESTBIT(inst,6); + DEBUGF((" blank=%d", (int)!ez)); + if (c) + int1_scope = (unsigned char)(ez & 0xFF); + else + int0_scope = (unsigned char)(ez & 0xFF); + } + if (TESTBIT(inst,5)) { + ez = TESTBIT(inst,4); + DEBUGF((" lp_intr_ena=%d", (int)ez)); + if (c) + lp1_intr_ena = (unsigned char)(ez & 0xFF); + else + lp0_intr_ena = (unsigned char)(ez & 0xFF); + } + if (TESTBIT(inst,3)) { + ez = TESTBIT(inst,2); + DEBUGF((" lp_sw_intr_ena=%d", (int)ez)); + if (c) + lp1_sw_intr_ena = (unsigned char)(ez & 0xFF); + else + lp0_sw_intr_ena = (unsigned char)(ez & 0xFF); + } + DEBUGF(("\r\n")); + break; + + case 1: /* 110101: Display POP Not Restore */ + DEBUGF(("Display POP Not Restore\r\n")); + pop(0); /* sets new DPC as side effect */ + break; + + case 2: /* 110110: Display POP Restore */ + DEBUGF(("Display POP Restore\r\n")); + pop(1); /* sets new DPC as side effect */ + break; + + default: /* 110111: undocumented -- ignored? */ + DEBUGF(("Display NOP?\r\n")); + } + } + break; + + case 016: /* 1110: Load Status A */ + DEBUGF(("Load Status A")); + internal_stop = TESTBIT(inst,10); /* 11101 Display Stop */ + if (internal_stop) { + stopped = 1; /* (synchronous with display cycle) */ + DEBUGF((" stop")); + } + if (TESTBIT(inst,9)) { + stop_intr_ena = TESTBIT(inst,8); + DEBUGF((" stop_intr_ena=%d", (int)stop_intr_ena)); + } + if (TESTBIT(inst,7)) { + lp_intensify = !TESTBIT(inst,6); + DEBUGF((" lp_intensify=%d", (int)lp_intensify)); + } + if (TESTBIT(inst,5)) { + italics = TESTBIT(inst,4); + DEBUGF((" italics=%d", (int)italics)); + } + refresh_rate = GETFIELD(inst,VS60?3:2,2); + DEBUGF((" refresh=%d", refresh_rate)); + switch (refresh_rate) { + case 0: /* continuous */ + sync_period = 0; + break; + case 1: /* VT11: 60 Hz; VS60: 30 Hz */ + sync_period = VT11 ? 17 : 33; + break; + case 2: /* VS60: 40 Hz */ + sync_period = 25; + break; + default: /* (case 3) VS60: external sync */ + sync_period = 17; /* fake a 60 Hz source */ + break; + } + if (internal_stop) { + sync_period = 0; /* overridden */ + } + if (VS60 && TESTBIT(inst,1)) { + menu = TESTBIT(inst,0); + DEBUGF((" menu=%d", (int)menu)); + } + DEBUGF(("\r\n")); + break; + + case 017: /* 1111_ */ + if (VS60 && TESTBIT(inst,10)) { /* 11111: Load Status BB */ + DEBUGF(("Load Status BB")); + if (TESTBIT(inst,7)) { + depth_cue_proc = TESTBIT(inst,6); + DEBUGF((" depth_cue_proc=%d", (int)depth_cue_proc)); + } + if (TESTBIT(inst,5)) { + edge_intr_ena = TESTBIT(inst,4); + DEBUGF((" edge_intr_ena=%d", (int)edge_intr_ena)); + } + if (TESTBIT(inst,3)) { + file_z_data = TESTBIT(inst,2); + DEBUGF((" file_z_data=%d", (int)file_z_data)); + } + if (TESTBIT(inst,1)) { + char_escape = TESTBIT(inst,0); + DEBUGF((" char_escape=%d", (int)char_escape)); + } + } else { /* 11110: Load Status B */ + DEBUGF(("Load Status B")); + if (VS60 && TESTBIT(inst,9)) { + color = GETFIELD(inst,8,7); + DEBUGF((" color=%d", (int)color)); + } + if (TESTBIT(inst,6)) { + graphplot_step = GETFIELD(inst,5,0); + DEBUGF((" graphplot_step=%d", (int)graphplot_step)); + } + } + DEBUGF(("\r\n")); + break; + + default: + bad_ins: DEBUGF(("SPARE COMMAND 0%o\r\n", mode_field)); + /* "display processor hangs" */ + DPC -= 2; /* hang around scene of crime */ + break; + + } /* end of control instruction opcode switch */ + jsr = 0; + + } else { /* graphic data */ + +#if 0 /* XXX ? */ + lp0_hit = 0; /* XXX maybe not for OFFSET? */ +#endif + if (word_number < 0) /* (after reset or control instr.) */ + word_number = 0; + if (word_number == 0) + offset = 0; + +#define MORE_DATA { ++word_number; goto check; } + + switch (mode_field = graphic_mode) { /* save for MPR read */ + + case CHAR: + if (word_number > 1) + word_number = 0; + if (word_number == 0) { + c = GETFIELD(inst,6,0); + DEBUGF(("char1 %d (", c)); + DEBUGF((040 <= c && c < 0177 ? "'%c'" : "0%o", c)); + DEBUGF((")\r\n")); + if (character(c)) /* POPR was done; end chars */ + break; + MORE_DATA /* post any intrs now */ + } + c = GETFIELD(inst,15,8); + DEBUGF(("char2 %d (", c)); + DEBUGF((040 <= c && c < 0177 ? "'%c'" : "0%o", c)); + DEBUGF((")\r\n")); + (void)character(c); + break; + + case SVECTOR: + if (word_number > 1 || (!file_z_data && word_number > 0)) + word_number = 0; + if (word_number == 0) { + i = TESTBIT(inst,14); /* inten_ena: beam on */ + x = GETFIELD(inst,12,7);/* delta_x */ + if (TESTBIT(inst,13)) + x = -x; + y = GETFIELD(inst,5,0); /* delta_y */ + if (TESTBIT(inst,6)) + y = -y; + if (file_z_data) + MORE_DATA + } + if (file_z_data) { /* (VS60) */ + z = GETFIELD(inst,9,2); /* delta_z */ + if (TESTBIT(inst,13)) + z = -z; + DEBUGF(("short vector i%d (%d,%d,%d)\r\n", + i, (int)x, (int)y, (int)z)); + vector3(i, x, y, z); + } else { + DEBUGF(("short vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); + vector2(i, x, y); + } + break; + + case LVECTOR: + if (word_number > 2 || (!file_z_data && word_number > 1)) + word_number = 0; + if (word_number == 0) { + ex = VS60 && TESTBIT(inst,12); + i = TESTBIT(inst,14); + x = GETFIELD(inst,9,0); /* delta_x */ + if (TESTBIT(inst,13)) + x = -x; + MORE_DATA + } + if (word_number == 1) { + y = GETFIELD(inst,9,0); /* delta_y */ + if (TESTBIT(inst,13)) + y = -y; + if (file_z_data) + MORE_DATA + } + if (file_z_data) { /* (VS60) */ + if (ex) + goto norot; + z = GETFIELD(inst,9,2); /* delta_z */ + if (TESTBIT(inst,13)) + z = -z; + DEBUGF(("long vector i%d (%d,%d,%d)\r\n", + i, (int)x, (int)y, (int)z)); + vector3(i, x, y, z); + } else { + if (ex) + norot: /* undocumented and probably nonfunctional */ + DEBUGF(("ROTATE NOT SUPPORTED\r\n")); + else { + DEBUGF(("long vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); + vector2(i, x, y); + } + } + break; + + case POINT: /* (or OFFSET, if VS60) */ + /* [VT48 manual incorrectly says point data doesn't use sign bit] */ + if (word_number > 2 || (!file_z_data && word_number > 1)) + word_number = 0; + if (word_number == 0) { + ex = GETFIELD(inst,(VS60?11:9),0); + offset = VS60 && TESTBIT(inst,12); /* offset flag */ + if (!offset) + i = TESTBIT(inst,14); /* for point only */ + if (VS60) { + sxo = TESTBIT(inst,13); /* sign bit */ + if (sxo) + ex = -ex; + } + /* XXX if VT11, set xpos/xoff now?? */ + MORE_DATA + } + if (word_number == 1) { + ey = GETFIELD(inst,(VS60?11:9),0); + if (VS60) { + syo = TESTBIT(inst,13); /* sign bit */ + if (syo) + ey = -ey; + } + if (file_z_data) + MORE_DATA + } + if (file_z_data) { /* (VS60) */ + ez = GETFIELD(inst,11,2); + szo = TESTBIT(inst,13); /* sign bit */ + if (szo) + ez = -ez; + if (offset) { /* OFFSET rather than POINT */ + DEBUGF(("offset (%d,%d,%d)\r\n", (int)ex,(int)ey,(int)ez)); + xoff = PSCALE(ex); + yoff = PSCALE(ey); + zoff = PSCALE(ez * 4); /* XXX include bits 1:0 ? */ + s_xoff = (unsigned char)(sxo & 0xFF); + s_yoff = (unsigned char)(syo & 0xFF); + s_zoff = (unsigned char)(szo & 0xFF); + } else { + DEBUGF(("point i%d (%d,%d,%d)\r\n", i, + (int)ex, (int)ey, (int)ez)); + point3(i, VSCALE(ex) + xoff, VSCALE(ey) + yoff, + VSCALE(ez * 4) + zoff, VS60); + } + } else { + if (offset) { /* (VS60) OFFSET rather than POINT */ + DEBUGF(("offset (%d,%d)\r\n", (int)ex, (int)ey)); + xoff = PSCALE(ex); + yoff = PSCALE(ey); + s_xoff = (unsigned char)(sxo & 0xFF); + s_yoff = (unsigned char)(syo & 0xFF); + } else { + DEBUGF(("point i%d (%d,%d)\r\n", i, (int)ex, (int)ey)); + point2(i, VSCALE(ex) + xoff, VSCALE(ey) + yoff, VS60); + } + } + break; + + case GRAPHX: /* (or BLVECT if VS60) */ + word_number = 0; + i = TESTBIT(inst,14); + if (VS60 && TESTBIT(inst,10)) + goto blv; /* (VS60) BLVECT rather than GRAPHX */ + else { + ex = GETFIELD(inst,9,0); + DEBUGF(("graphplot x (%d) i%d\r\n", (int)ex, i)); + ey = ypos + VSCALE(graphplot_step); + /* VT48 ES says first datum doesn't increment Y; that's wrong */ + /* diagnostic DZVSD shows that "i" bit is ignored! */ + point2(1, VSCALE(ex) + xoff, ey, VS60); + } + break; + + case GRAPHY: /* (or BLVECT if VS60) */ + word_number = 0; + i = TESTBIT(inst,14); + if (VS60 && TESTBIT(inst,10)) { + blv: /* (VS60) BLVECT rather than GRAPHY */ + x = GETFIELD(inst,13,11); /* direction */ + y = GETFIELD(inst,9,0); /* length */ + DEBUGF(("basic long vector i%d d%d l%d\r\n", + i, (int)x, (int)y)); + basic_vector(i, (int)x, (int)y); + } else { + ey = GETFIELD(inst,9,0); + DEBUGF(("graphplot y (%d) i%d\r\n", (int)ey, i)); + ex = xpos + VSCALE(graphplot_step); + /* VT48 ES says first datum doesn't increment X; that's wrong */ + /* diagnostic DZVSD shows that "i" bit is ignored! */ + point2(1, ex, VSCALE(ey) + yoff, VS60); + } + break; + + case RELPOINT: + if (word_number > 1 || (!file_z_data && word_number > 0)) + word_number = 0; + if (word_number == 0) { + i = TESTBIT(inst,14); + ex = GETFIELD(inst,12,7); + if (TESTBIT(inst,13)) + ex = -ex; + ey = GETFIELD(inst,5,0); + if (TESTBIT(inst,6)) + ey = -ey; + if (file_z_data) + MORE_DATA + } + if (file_z_data) { /* (VS60) */ + ez = GETFIELD(inst,9,2); + if (TESTBIT(inst,13)) + ez = -ez; + DEBUGF(("relative point i%d (%d,%d,%d)\r\n", + i, (int)ex, (int)ey, (int)ez)); + point3(i, xpos + VSCALE(ex), ypos + VSCALE(ey), + zpos + VSCALE(ez * 4), 1); + } else { + DEBUGF(("relative point i%d (%d,%d)\r\n", i, (int)ex, (int)ey)); + point2(i, xpos + VSCALE(ex), ypos + VSCALE(ey), 1); + } + break; + + /* the remaining graphic data types are supported by the VS60 only */ + + case BSVECT: /* (VS60) */ + if (word_number > 1) + word_number = 0; + if (word_number == 0) { + i = TESTBIT(inst,14); + x = GETFIELD(inst,6,4); /* direction 0 */ + y = GETFIELD(inst,3,0); /* length 0 */ + ex = GETFIELD(inst,13,11); /* direction 1 */ + ey = GETFIELD(inst,10,7); /* length 1 */ + DEBUGF(("basic short vector1 i%d d%d l%d\r\n", + i, (int)x, (int)y)); + basic_vector(i, (int)x, (int)y); + if (lphit_irq || edge_irq) /* MORE_DATA skips this */ + vt_lpen_intr(); /* post graphic interrupt to host */ + MORE_DATA + } + DEBUGF(("basic short vector2 i%d d%d l%d\r\n", i, (int)ex,(int)ey)); + basic_vector(i, (int)ex, (int)ey); + break; + + case ABSVECTOR: /* (VS60) */ + /* Note: real VS60 can't handle a delta of more than +-4095 */ + if (word_number > 2 || (!file_z_data && word_number > 1)) + word_number = 0; + if (word_number == 0) { + i = TESTBIT(inst,14); + x = GETFIELD(inst,11,0); + if (TESTBIT(inst,13)) + x = -x; + MORE_DATA + } + if (word_number == 1) { + y = GETFIELD(inst,11,0); + if (TESTBIT(inst,13)) + y = -y; + if (file_z_data) + MORE_DATA + } + if (file_z_data) { + z = GETFIELD(inst,11,2); + if (TESTBIT(inst,13)) + z = -z; + DEBUGF(("absolute vector i%d (%d,%d,%d)\r\n", + i, (int)x, (int)y, (int)z)); + ex = VSCALE(x) + xoff; + ey = VSCALE(y) + yoff; + ez = VSCALE(z * 4) + zoff; + vector3(i, PNORM(ex - xpos), PNORM(ey - ypos), + PNORM(ez - zpos) / 4); /* approx. */ + zpos = ez; /* more precise, if PSCALEF > 1 */ + } else { + DEBUGF(("absolute vector i%d (%d,%d)\r\n", i, (int)x, (int)y)); + ex = VSCALE(x) + xoff; + ey = VSCALE(y) + yoff; + vector2(i, PNORM(ex - xpos), PNORM(ey - ypos)); /* approx. */ + } + xpos = ex; /* more precise, if PSCALEF > 1 */ + ypos = ey; + break; + + case CIRCLE: /* (VS60) */ + if (word_number > 5 || (!file_z_data && word_number > 3)) + word_number = 0; + if (word_number == 0) { + i = TESTBIT(inst,14); + x = GETFIELD(inst,9,0); /* delta cx */ + if (TESTBIT(inst,13)) + x = -x; + MORE_DATA + } + if (word_number == 1) { + y = GETFIELD(inst,9,0); /* delta cy */ + if (TESTBIT(inst,13)) + y = -y; + MORE_DATA + } + if (word_number == 2) { + if (file_z_data) { + z = GETFIELD(inst,11,2); /* delta cz */ + if (TESTBIT(inst,13)) + z = -z; + MORE_DATA + } + } + if (word_number == 2 + file_z_data) { + ex = GETFIELD(inst,9,0); /* delta ex */ + if (TESTBIT(inst,13)) + ex = -ex; + MORE_DATA + } + if (word_number == 3 + file_z_data) { + ey = GETFIELD(inst,9,0); /* delta ey */ + if (TESTBIT(inst,13)) + ey = -ey; + if (file_z_data) + MORE_DATA + } + if (file_z_data) { + ez = GETFIELD(inst,11,2); /* delta ez */ + if (TESTBIT(inst,13)) + ez = -ez; + DEBUGF(("circle/arc i%d C(%d,%d,%d) E(%d,%d,%d)\r\n", + i, (int)x, (int)y, (int)z, (int)ex, (int)ey, (int)ez)); + conic3(i, x, y, z, ex, ey, ez); /* approx. */ + } else { + DEBUGF(("circle/arc i%d C(%d,%d) E(%d,%d)\r\n", + i, (int)x, (int)y, (int)ex, (int)ey)); + conic2(i, x, y, ex, ey); + } + break; + + default: /* "can't happen" */ + DPC -= 2; /* hang around scene of crime */ + break; + + } /* end of graphic_mode switch */ + ++word_number; + + /* LP hit & edge interrupts triggered only while in data mode */ + if (lphit_irq || edge_irq) + vt_lpen_intr(); /* post graphic interrupt to host */ + + } /* end of instruction decoding and execution */ + goto check; + + bus_timeout: + DEBUGF(("TIMEOUT\r\n")); + /* fall through to check (time_out has already been set) */ + + check: + + /* post an interrupt if conditions are right; + because this simulation has no pipeline, only one is active at a time */ + + if (lp0_sw_state != display_lp_sw) { /* tip-switch state change */ + lp0_sw_state = display_lp_sw; /* track switch state */ + lp0_up = !(lp0_down = lp0_sw_state); /* set transition flags */ + if (lp0_sw_intr_ena) + lpsw_irq = 1; + } + + if (lpsw_irq) /* (LP hit or edge interrupt already triggered above) */ + vt_lpen_intr(); /* post graphic interrupt to host */ + else if (internal_stop && stop_intr_ena) /* ext_stop does immediately */ + vt_stop_intr(); /* post stop interrupt to host */ + else if (char_irq || stack_over || stack_under || time_out) + vt_char_intr(); /* post character interrupt to host */ + else if (name_irq) + vt_name_intr(); /* post name-match interrupt to host */ +#if 1 /* risky? */ + else /* handle any pending 2nd CHAR/BSVECT */ + if (word_number == 1 && (graphic_mode==CHAR || graphic_mode==BSVECT)) + goto fetched; +#endif + + /* fall through to age_ret */ + + age_ret: + display_age(us, slowdown); + return !maint1 && !maint2 && busy; +} /* vt11_cycle */ + diff --git a/display/vt11.h b/display/vt11.h index c647b121..d5833ebc 100644 --- a/display/vt11.h +++ b/display/vt11.h @@ -1,137 +1,137 @@ -/* - * $Id: vt11.h,v 1.7 2004/01/25 17:20:51 phil Exp $ - * interface to VT11 simulator - * Phil Budne - * September 16, 2003 - * Substantially revised by Douglas A. Gwyn, 14 Jan. 2004 - * - * prerequisite: display.h - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#ifndef SIM_DEFS_H_ -typedef unsigned short uint16; -typedef long int32; -typedef unsigned long uint32; -#endif /* SIM_DEFS_H_ */ - -/* - * VT11 jumpers control character spacing; VS60 always uses VT11 normal. - * The VT11_CSP_{W,H} #defines establish the initial default character - * spacing; to change the VT11 simulation from these default values, - * set vt11_csp_{w,h} before calling any function named vt11_*. - */ -extern unsigned char vt11_csp_w; /* horizontal character spacing */ -#ifdef VT11_NARROW_OPT /* W3 or W6 installed */ -#define VT11_CSP_W 12 -#else /* VT11 normal; W4 or W5 installed */ -#define VT11_CSP_W 14 -#endif -extern unsigned char vt11_csp_h; /* vertical character spacing */ -#ifdef VT11_TALL_OPT /* W3 or W4 installed */ -#define VT11_CSP_H 26 -#else /* VT11 normal; W5 or W6 installed */ -#define VT11_CSP_H 24 -#endif - -/* - * The DISPLAY_TYPE #define establishes the initial default display - * type; to change from the default display type, set vt11_display - * before calling any function named vt11_* (other than vt11_reset()). - */ -#ifndef DISPLAY_TYPE -#define DISPLAY_TYPE DIS_VR17 /* default display type */ -#endif -extern enum display_type vt11_display; /* DIS_VR{14,17,48} */ -/* - * The PIX_SCALE #define establishes the initial default display scale - * factor; to change from the default scale factor, set vt11_scale - * before calling any function named vt11_* (other than vt11_reset()). - */ -#ifndef PIX_SCALE -#define PIX_SCALE RES_HALF /* default display scale factor */ -#endif -extern int vt11_scale; /* RES_{FULL,HALF,QUARTER,EIGHTH} */ -/* - * When vt11_init (READONLY) is nonzero, it indicates that it is too late - * to change display parameters (type, scale, character spacing, etc.). - */ -extern unsigned char vt11_init; /* set after display_init() called */ - -/* vt11.c simulates either a VT11 or a VT48(VS60), according to display type: */ -#define VS60 (vt11_display == DIS_VR48) -#define VT11 (!VS60) - -/* The display file is an array of 16-bit words. */ -typedef uint16 vt11word; - -extern int32 vt11_get_dpc(void); /* read Display PC */ -extern int32 vt11_get_mpr(void); /* read mode parameter register */ -extern int32 vt11_get_xpr(void); /* read graphplot incr/X pos register */ -extern int32 vt11_get_ypr(void); /* read char code/Y pos register */ -extern int32 vt11_get_rr(void); /* read relocate register */ -extern int32 vt11_get_spr(void); /* read status parameter register */ -extern int32 vt11_get_xor(void); /* read X offset register */ -extern int32 vt11_get_yor(void); /* read Y offset register */ -extern int32 vt11_get_anr(void); /* read associative name register */ -extern int32 vt11_get_scr(void); /* read slave console/color register */ -extern int32 vt11_get_nr(void); /* read name register */ -extern int32 vt11_get_sdr(void); /* read stack data register */ -extern int32 vt11_get_str(void); /* read char string term register */ -extern int32 vt11_get_sar(void); /* read stack address/maint register */ -extern int32 vt11_get_zpr(void); /* read Z position register */ -extern int32 vt11_get_zor(void); /* read Z offset register */ - -extern void vt11_set_dpc(uint16); /* write Display PC */ -extern void vt11_set_mpr(uint16); /* write mode parameter register */ -extern void vt11_set_xpr(uint16); /* write graphplot inc/X pos register */ -extern void vt11_set_ypr(uint16); /* write char code/Y pos register */ -extern void vt11_set_rr(uint16); /* write relocate register */ -extern void vt11_set_spr(uint16); /* write status parameter register */ -extern void vt11_set_xor(uint16); /* write X offset register */ -extern void vt11_set_yor(uint16); /* write Y offset register */ -extern void vt11_set_anr(uint16); /* write associative name register */ -extern void vt11_set_scr(uint16); /* write slave console/color register */ -extern void vt11_set_nr(uint16); /* write name register */ -extern void vt11_set_sdr(uint16); /* write stack data register */ -extern void vt11_set_str(uint16); /* write char string term register */ -extern void vt11_set_sar(uint16); /* write stack address/maint register */ -extern void vt11_set_zpr(uint16); /* write Z position register */ -extern void vt11_set_zor(uint16); /* write Z offset register */ - -extern void vt11_reset(void); /* reset the display processor */ -extern int vt11_cycle(int,int); /* perform a display processor cycle */ - -/* - * callbacks from VT11/VS60 simulator (to SIMH PDP-11 VT driver, for example) - */ -extern int vt_fetch(uint32, vt11word *); /* get a display-file word */ -extern void vt_stop_intr(void); /* post a display-stop interrupt */ -extern void vt_lpen_intr(void); /* post a surface-related interrupt */ -extern void vt_char_intr(void); /* post a bad-char./timeout interrupt */ -extern void vt_name_intr(void); /* post a name-match interrupt */ +/* + * $Id: vt11.h,v 1.8 2005/01/14 18:58:02 phil Exp $ + * interface to VT11 simulator + * Phil Budne + * September 16, 2003 + * Substantially revised by Douglas A. Gwyn, 14 Jan. 2004 + * + * prerequisite: xy.h + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#ifndef SIM_DEFS_H_ +typedef unsigned short uint16; +typedef long int32; +typedef unsigned long uint32; +#endif /* SIM_DEFS_H_ */ + +/* + * VT11 jumpers control character spacing; VS60 always uses VT11 normal. + * The VT11_CSP_{W,H} #defines establish the initial default character + * spacing; to change the VT11 simulation from these default values, + * set vt11_csp_{w,h} before calling any function named vt11_*. + */ +extern unsigned char vt11_csp_w; /* horizontal character spacing */ +#ifdef VT11_NARROW_OPT /* W3 or W6 installed */ +#define VT11_CSP_W 12 +#else /* VT11 normal; W4 or W5 installed */ +#define VT11_CSP_W 14 +#endif +extern unsigned char vt11_csp_h; /* vertical character spacing */ +#ifdef VT11_TALL_OPT /* W3 or W4 installed */ +#define VT11_CSP_H 26 +#else /* VT11 normal; W5 or W6 installed */ +#define VT11_CSP_H 24 +#endif + +/* + * The DISPLAY_TYPE #define establishes the initial default display + * type; to change from the default display type, set vt11_display + * before calling any function named vt11_* (other than vt11_reset()). + */ +#ifndef DISPLAY_TYPE +#define DISPLAY_TYPE DIS_VR17 /* default display type */ +#endif +extern enum display_type vt11_display; /* DIS_VR{14,17,48} */ +/* + * The PIX_SCALE #define establishes the initial default display scale + * factor; to change from the default scale factor, set vt11_scale + * before calling any function named vt11_* (other than vt11_reset()). + */ +#ifndef PIX_SCALE +#define PIX_SCALE RES_HALF /* default display scale factor */ +#endif +extern int vt11_scale; /* RES_{FULL,HALF,QUARTER,EIGHTH} */ +/* + * When vt11_init (READONLY) is nonzero, it indicates that it is too late + * to change display parameters (type, scale, character spacing, etc.). + */ +extern unsigned char vt11_init; /* set after display_init() called */ + +/* vt11.c simulates either a VT11 or a VT48(VS60), according to display type: */ +#define VS60 (vt11_display == DIS_VR48) +#define VT11 (!VS60) + +/* The display file is an array of 16-bit words. */ +typedef uint16 vt11word; + +extern int32 vt11_get_dpc(void); /* read Display PC */ +extern int32 vt11_get_mpr(void); /* read mode parameter register */ +extern int32 vt11_get_xpr(void); /* read graphplot incr/X pos register */ +extern int32 vt11_get_ypr(void); /* read char code/Y pos register */ +extern int32 vt11_get_rr(void); /* read relocate register */ +extern int32 vt11_get_spr(void); /* read status parameter register */ +extern int32 vt11_get_xor(void); /* read X offset register */ +extern int32 vt11_get_yor(void); /* read Y offset register */ +extern int32 vt11_get_anr(void); /* read associative name register */ +extern int32 vt11_get_scr(void); /* read slave console/color register */ +extern int32 vt11_get_nr(void); /* read name register */ +extern int32 vt11_get_sdr(void); /* read stack data register */ +extern int32 vt11_get_str(void); /* read char string term register */ +extern int32 vt11_get_sar(void); /* read stack address/maint register */ +extern int32 vt11_get_zpr(void); /* read Z position register */ +extern int32 vt11_get_zor(void); /* read Z offset register */ + +extern void vt11_set_dpc(uint16); /* write Display PC */ +extern void vt11_set_mpr(uint16); /* write mode parameter register */ +extern void vt11_set_xpr(uint16); /* write graphplot inc/X pos register */ +extern void vt11_set_ypr(uint16); /* write char code/Y pos register */ +extern void vt11_set_rr(uint16); /* write relocate register */ +extern void vt11_set_spr(uint16); /* write status parameter register */ +extern void vt11_set_xor(uint16); /* write X offset register */ +extern void vt11_set_yor(uint16); /* write Y offset register */ +extern void vt11_set_anr(uint16); /* write associative name register */ +extern void vt11_set_scr(uint16); /* write slave console/color register */ +extern void vt11_set_nr(uint16); /* write name register */ +extern void vt11_set_sdr(uint16); /* write stack data register */ +extern void vt11_set_str(uint16); /* write char string term register */ +extern void vt11_set_sar(uint16); /* write stack address/maint register */ +extern void vt11_set_zpr(uint16); /* write Z position register */ +extern void vt11_set_zor(uint16); /* write Z offset register */ + +extern void vt11_reset(void); /* reset the display processor */ +extern int vt11_cycle(int,int); /* perform a display processor cycle */ + +/* + * callbacks from VT11/VS60 simulator (to SIMH PDP-11 VT driver, for example) + */ +extern int vt_fetch(uint32, vt11word *); /* get a display-file word */ +extern void vt_stop_intr(void); /* post a display-stop interrupt */ +extern void vt_lpen_intr(void); /* post a surface-related interrupt */ +extern void vt_char_intr(void); /* post a bad-char./timeout interrupt */ +extern void vt_name_intr(void); /* post a name-match interrupt */ diff --git a/display/vtmacs.h b/display/vtmacs.h index 6e0c04de..417aee6f 100644 --- a/display/vtmacs.h +++ b/display/vtmacs.h @@ -1,291 +1,297 @@ -/* - * $Id: vtmacs.h,v 1.4 2004/02/07 06:26:47 phil Exp $ - * macros for coding a VT11/VS60 display file (instructions and data) - * Douglas A. Gwyn - * January 31, 2004 - * - * XXX -- assumes ASCII host character set - */ - -/* helper macros (not for use outside this header): */ -#define SGN_(x) ((x) < 0) -#define MAG_(x) ((x) >= 0 ? (x) : -(x)) /* -0 not expressible directly in C */ - -/* control instructions: */ - -/* load status register A: */ -#define LSRA(stop,stop_intr,lp_hit_chg,ital,refresh,menu) \ - 0170000 | stop | stop_intr | lp_hit_chg | ital | refresh | menu - /* display stop: */ -#define ST_SAME 00000 /* don't stop display */ -#define ST_STOP 02000 /* stop display */ - /* stop interrupt: */ -#define SI_SAME 00000 /* no change */ -#define SI_INHIBIT 01000 /* inhibit interrupt on stop */ -#define SI_GENERATE 01400 /* generate interrupt on stop */ - /* light pen hit intensify (bright-down on VS60): */ -#define LI_SAME 0000 /* no change */ -#define LI_INTENSIFY 0200 /* enable intensify on hit (VT11) */ -#define LI_BRIGHTDOWN 0200 /* enable bright down on hit (VS60) */ -#define LI_NOINTENSIFY 0300 /* inhibit intensify on hit (VT11) */ -#define LI_NOBRIGHTDOWN 0300 /* inhibit bright down on hit (VS60) */ - /* italic font: */ -#define IT_SAME 000 /* no change */ -#define IT_NORMAL 040 /* normal font */ -#define IT_ITALIC 060 /* italic font */ - /* refresh rate: */ -#define RF_UNSYNC 000 /* unsynchronized */ -#define RF_SAME 000 /* (happens to work like that) */ -#define RF_LINE 004 /* sync with line (VT11) */ -#define RF_30 004 /* 30 frames/sec (VS60) */ -#define RF_40 010 /* 40 frames/sec (VS60) */ -#define RF_EXT 014 /* external sync (VS60) */ - /* menu/main area (VS60): */ -#define MN_SAME 0 /* no change */ -#define MN_MAIN 2 /* major screen area */ -#define MN_MENU 3 /* menu area */ - -/* load status register B: */ -#define LSRB(color,set_step,step) \ - 0174000 | color | set_step | (step) - /* color select (VS60): */ -#define CL_SAME 00000 /* no change */ -#define CL_GREEN 01000 /* green */ -#define CL_YELLOW 01200 /* yellow */ -#define CL_ORANGE 01400 /* orange */ -#define CL_RED 01600 /* red */ - /* graphplot increment register change enable: */ -#define SS_SAME 0000 /* no change (step value ignored) */ -#define SS_CHANGE 0100 /* write step value into register */ - -/* load status register BB (VS60): */ -#define LSRBB(z_data,edge_intr,depth_cue,char_esc) \ - 0176000 | z_data | edge_intr | depth_cue | char_esc - /* file Z data: */ -#define ZD_SAME 000 /* no change */ -#define ZD_NO 010 /* d.file does not contain Z coords. */ -#define ZD_YES 014 /* d.file contains Z coordinates */ - /* edge interrupts enable: */ -#define ED_SAME 000 /* no change */ -#define ED_DIS 040 /* disable intr. on edge transition */ -#define ED_ENA 060 /* enable intr. on edge transition */ - /* depth cue processing: */ -#define DQ_SAME 0000 /* no change */ -#define DQ_OFF 0200 /* disable depth cueing (Z intensity) */ -#define DQ_ON 0300 /* enable depth cueing (Z intensity) */ - /* escape on terminating character: */ -#define ES_SAME 0 /* no change */ -#define ES_NO 2 /* disable POPR on terminating char. */ -#define ES_YES 3 /* enable POPR on terminating char. */ - -/* load status register C (VS60): */ -#define LSRC(rotate,cs_change,cscale,vs_change,vscale) \ - 0154000 | rotate | cs_change | ((cscale)<<5) | \ - vs_change | (vscale) - /* character rotation: */ -#define RO_SAME 00000 /* no change */ -#define RO_HORIZONTAL 01000 /* no text rotation */ -#define RO_VERTICAL 01400 /* rotate text 90 degrees CCW */ - /* character scale change enable: */ -#define CS_SAME 0000 /* no change (cscale value ignored) */ -#define CS_CHANGE 0200 /* set character scale */ - /* vector scale change enable: */ -#define VS_SAME 000 /* no change (vscale value ignored) */ -#define VS_CHANGE 020 /* set vector scale */ - -/* load scope selection register (VS60): */ -#define LSSR(console,disp,lp_intr,sw_intr) \ - 0164000 | console | disp | lp_intr | sw_intr - /* console to which this instruction applies: */ -#define CN_0 0000 /* console # 0 */ -#define CN_1 0400 /* console # 1 */ - /* display enable: */ -#define DS_SAME 0000 /* no change */ -#define DS_DIS 0200 /* disable display (blank CRT) */ -#define DS_ENA 0300 /* enable display (use CRT) */ - /* light-pen hit interrupt enable: */ -#define LH_SAME 0000 /* no change */ -#define LH_DIS 0040 /* light-pen hit interrupt disabled */ -#define LH_ENA 0060 /* light-pen hit interrupt enabled */ - /* tip-switch transition interrupt enable: */ -#define SW_SAME 0000 /* no change */ -#define SW_DIS 0010 /* tip-switch interrupt disabled */ -#define SW_ENA 0014 /* tip-switch hit interrupt enabled */ - -/* load name register (VS60): */ -#define LNR(name) \ - 0150000 | (name) - -/* set graphic mode: */ -#define SGM(mode,intens,lp_intr,blink,line_type) \ - 0100000 | mode | intens | lp_intr | blink | line_type - /* graphic mode: */ -#define GM_CHAR 000000 /* character */ -#define GM_SVECT 004000 /* short vector */ -#define GM_LVECT 010000 /* long vector */ -#define GM_APOINT 014000 /* absolute point, or offset */ -#define GM_GRAPHX 020000 /* graphplot X, or basic long vector */ -#define GM_GRAPHY 024000 /* graphplot Y, or basic long vector */ -#define GM_RPOINT 030000 /* relative point */ -#define GM_BSVECT 034000 /* basic short vector */ -#define GM_ARC 040000 /* circle/arc */ -#define GM_AVECT 044000 /* absolute vector */ - /* intensity: */ -#define IN_SAME 00000 /* no change */ -#define IN_0 02000 /* intensity level 0 (dimmest) */ -#define IN_1 02200 /* intensity level 1 */ -#define IN_2 02400 /* intensity level 2 */ -#define IN_3 02600 /* intensity level 3 */ -#define IN_4 03000 /* intensity level 4 */ -#define IN_5 03200 /* intensity level 5 */ -#define IN_6 03400 /* intensity level 6 */ -#define IN_7 03600 /* intensity level 7 (brightest) */ - /* light pen interrupt: */ -#define LP_SAME 0000 /* no change */ -#define LP_DIS 0100 /* light-pen hit interrupt disabled */ -#define LP_ENA 0140 /* light-pen hit interrupt enabled */ - /* blink: */ -#define BL_SAME 000 /* no change */ -#define BL_OFF 020 /* blink off */ -#define BL_ON 030 /* blink on */ - /* line type: */ -#define LT_SAME 00 /* no change */ -#define LT_SOLID 04 /* solid */ -#define LT_LDASH 05 /* long dash */ -#define LT_SDASH 06 /* short dash */ -#define LT_DDASH 07 /* dot dash */ - -/* display jump absolute: */ -#define DJMP_ABS(addr) \ - 0160000, \ - (addr) & ~1 - -/* display jump relative (VS60): */ -#define DJMP_REL(raddr) \ - 0161000 | (SGN_(raddr) << 8) | MAG_(raddr) - -/* display jump to subroutine absolute (VS60): */ -#define DJSR_ABS(addr) \ - 0162000, \ - (addr) & ~1 - -/* display jump to subroutine relative (VS60): */ -#define DJSR_REL(raddr) \ - 0163000 | (SGN_(raddr) << 8) | MAG_(raddr) - -/* display no-op: */ -#define DNOP \ - 0164000 - -/* display pop, no restore (VS60): */ -#define DPOP_NR \ - 0165000 - -/* display pop, restore (VS60): */ -#define DPOP_R \ - 0165000 - -/* display stop: */ -#define DSTOP LSRA(ST_STOP,SI_SAME,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME) - -/* graphic data: */ - - /* intensify enable (common to all modes exept CHAR and OFFSET): */ -#define I_OFF 000000 /* beam off */ -#define I_ON 040000 /* beam on */ - -/* Note: when VS60 "file Z data" is enabled, - use the *3() macros instead of the corresponding normal ones. */ - -/* character data: */ -#define CHAR(c1,c2) \ - ((c2) << 8) | (c1) /* 7-bit ASCII assumed */ - -/* short vector data: */ -#define SVECT(i,dx,dy) \ - i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy) -#define SVECT3(i,dx,dy,dz) \ - i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \ - (SGN_(dz) << 13) | (MAG_(dz) << 2) - -/* long vector data: */ -#define LVECT(i,dx,dy) \ - i | (SGN_(dx) << 13) | MAG_(dx), \ - (SGN_(dy) << 13) | MAG_(dy) -#define LVECT3(i,dx,dy,dz) \ - i | (SGN_(dx) << 13) | MAG_(dx), \ - (SGN_(dy) << 13) | MAG_(dy), \ - (SGN_(dz) << 13) | (MAG_(dz) << 2) - -/* rotation data (VS60, probably unimplemented): */ -#define ROTATE(i,a,b) \ - i | (SGN_(a) << 13) | 010000 | MAG_(a), \ - (SGN_(b) << 13) | MAG_(b) -#define ROTATE3(i,a,b,c) \ - i | (SGN_(a) << 13) | 010000 | MAG_(a), \ - (SGN_(b) << 13) | MAG_(b), \ - (SGN_(c) << 13) | (MAG_(c) << 2) - -/* absolute point data: */ -#define APOINT(i,x,y) \ - i | (SGN_(x) << 13) | MAG_(x), \ - (SGN_(y) << 13) | MAG_(y) -#define APOINT3(i,x,y,z) \ - i | (SGN_(x) << 13) | MAG_(x), \ - (SGN_(y) << 13) | MAG_(y), \ - (SGN_(z) << 13) | (MAG_(z) << 2) - -/* offset data (VS60): */ -#define OFFSET(x,y) \ - (SGN_(x) << 13) | 010000 | MAG_(x), \ - (SGN_(y) << 13) | 010000 | MAG_(y) -#define OFFSET3(x,y,z) \ - (SGN_(x) << 13) | 010000 | MAG_(x), \ - (SGN_(y) << 13) | 010000 | MAG_(y), \ - (SGN_(z) << 13) | 010000 | (MAG_(z) << 2) - -/* graphplot X data: */ -#define GRAPHX(i,x) \ - i | (x) - -/* graphplot Y data: */ -#define GRAPHY(i,y) \ - i | (y) - -/* basic long vector data (VS60): */ -#define BLVECT(i,dir,len) \ - i | ((dir) << 11) | 02000 | (len) - -/* relative point data: */ -#define RPOINT(i,dx,dy) \ - i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy) -#define RPOINT3(i,dx,dy,dz) \ - i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \ - (SGN_(dz) << 13) | (MAG_(dz) << 2) - -/* basic short vector data (VS60): */ -#define BSVECT(i,dir1,len1,dir2,len2) \ - i | ((dir2) << 11) | ((len2) << 7) | ((dir1) << 4) | (len1) - -/* circle/arc data (VS60, option): */ -#define ARC(i,dcx,dcy,dex,dey) \ - i | (SGN_(dcx) << 13) | MAG_(dcx), \ - (SGN_(dcy) << 13) | MAG_(dcy), \ - (SGN_(dex) << 13) | MAG_(dex), \ - (SGN_(dey) << 13) | MAG_(dey) -#define ARC3(i,dcx,dcy,cz,dex,dey,ez) \ - i | (SGN_(dcx) << 13) | MAG_(dcx), \ - (SGN_(dcy) << 13) | MAG_(dcy), \ - (SGN_(cz) << 13) | (MAG_(cz) << 2), \ - (SGN_(dex) << 13) | MAG_(dex), \ - (SGN_(dey) << 13) | MAG_(dey), \ - (SGN_(ez) << 13) | (MAG_(ez) << 2) - -/* absolute vector data (VS60): */ -#define AVECT(i,x,y) \ - i | (SGN_(x) << 13) | MAG_(x), \ - (SGN_(y) << 13) | MAG_(y) -#define AVECT3(i,x,y,z) \ - i | (SGN_(x) << 13) | MAG_(x), \ - (SGN_(y) << 13) | MAG_(y), \ - (SGN_(z) << 13) | (MAG_(z) << 2) +/* + * $Id: vtmacs.h,v 1.5 2005/01/12 18:10:13 phil Exp $ + * macros for coding a VT11/VS60 display file (instructions and data) + * for standalone use of vt11.c (not embedded in PDP-11 simulator) + * Douglas A. Gwyn + * September 03, 2004 + * + * XXX -- assumes ASCII host character set + */ + +/* helper macros (not for use outside this header): */ +#define SGN_(x) ((x) < 0) +#define MAG_(x) ((x) >= 0 ? (x) : -(x)) /* -0 not expressible directly in C */ +#if 0 /* manual seems to say this; wrong! */ +#define JDL_(x) ((SGN_(raddr) << 8) | MAG_(raddr)) +#else /* sign extend, 9-bit twos complement */ +#define JDL_(x) ((x) >= 0 ? (x) : ((~(unsigned)-(x))+1) & 0777) +#endif + +/* control instructions: */ + +/* load status register A: */ +#define LSRA(stop,stop_intr,lp_hit_chg,ital,refresh,menu) \ + 0170000 | stop | stop_intr | lp_hit_chg | ital | refresh | menu + /* display stop: */ +#define ST_SAME 00000 /* don't stop display */ +#define ST_STOP 02000 /* stop display */ + /* stop interrupt: */ +#define SI_SAME 00000 /* no change */ +#define SI_INHIBIT 01000 /* inhibit interrupt on stop */ +#define SI_GENERATE 01400 /* generate interrupt on stop */ + /* light pen hit intensify (bright-down on VS60): */ +#define LI_SAME 0000 /* no change */ +#define LI_INTENSIFY 0200 /* enable intensify on hit (VT11) */ +#define LI_BRIGHTDOWN 0200 /* enable bright down on hit (VS60) */ +#define LI_NOINTENSIFY 0300 /* inhibit intensify on hit (VT11) */ +#define LI_NOBRIGHTDOWN 0300 /* inhibit bright down on hit (VS60) */ + /* italic font: */ +#define IT_SAME 000 /* no change */ +#define IT_NORMAL 040 /* normal font */ +#define IT_ITALIC 060 /* italic font */ + /* refresh rate: */ +#define RF_UNSYNC 000 /* unsynchronized */ +#define RF_SAME 000 /* (happens to work like that) */ +#define RF_LINE 004 /* sync with line (VT11) */ +#define RF_30 004 /* 30 frames/sec (VS60) */ +#define RF_40 010 /* 40 frames/sec (VS60) */ +#define RF_EXT 014 /* external sync (VS60) */ + /* menu/main area (VS60): */ +#define MN_SAME 0 /* no change */ +#define MN_MAIN 2 /* major screen area */ +#define MN_MENU 3 /* menu area */ + +/* load status register B: */ +#define LSRB(color,set_step,step) \ + 0174000 | color | set_step | (step) + /* color select (VS60): */ +#define CL_SAME 00000 /* no change */ +#define CL_GREEN 01000 /* green */ +#define CL_YELLOW 01200 /* yellow */ +#define CL_ORANGE 01400 /* orange */ +#define CL_RED 01600 /* red */ + /* graphplot increment register change enable: */ +#define SS_SAME 0000 /* no change (step value ignored) */ +#define SS_CHANGE 0100 /* write step value into register */ + +/* load status register BB (VS60): */ +#define LSRBB(z_data,edge_intr,depth_cue,char_esc) \ + 0176000 | z_data | edge_intr | depth_cue | char_esc + /* file Z data: */ +#define ZD_SAME 000 /* no change */ +#define ZD_NO 010 /* d.file does not contain Z coords. */ +#define ZD_YES 014 /* d.file contains Z coordinates */ + /* edge interrupts enable: */ +#define ED_SAME 000 /* no change */ +#define ED_DIS 040 /* disable intr. on edge transition */ +#define ED_ENA 060 /* enable intr. on edge transition */ + /* depth cue processing: */ +#define DQ_SAME 0000 /* no change */ +#define DQ_OFF 0200 /* disable depth cueing (Z intensity) */ +#define DQ_ON 0300 /* enable depth cueing (Z intensity) */ + /* escape on terminating character: */ +#define ES_SAME 0 /* no change */ +#define ES_NO 2 /* disable POPR on terminating char. */ +#define ES_YES 3 /* enable POPR on terminating char. */ + +/* load status register C (VS60): */ +#define LSRC(rotate,cs_change,cscale,vs_change,vscale) \ + 0154000 | rotate | cs_change | ((cscale)<<5) | \ + vs_change | (vscale) + /* character rotation: */ +#define RO_SAME 00000 /* no change */ +#define RO_HORIZONTAL 01000 /* no text rotation */ +#define RO_VERTICAL 01400 /* rotate text 90 degrees CCW */ + /* character scale change enable: */ +#define CS_SAME 0000 /* no change (cscale value ignored) */ +#define CS_CHANGE 0200 /* set character scale */ + /* vector scale change enable: */ +#define VS_SAME 000 /* no change (vscale value ignored) */ +#define VS_CHANGE 020 /* set vector scale */ + +/* load scope selection register (VS60): */ +#define LSSR(console,disp,lp_intr,sw_intr) \ + 0164000 | console | disp | lp_intr | sw_intr + /* console to which this instruction applies: */ +#define CN_0 0000 /* console # 0 */ +#define CN_1 0400 /* console # 1 */ + /* display enable: */ +#define DS_SAME 0000 /* no change */ +#define DS_DIS 0200 /* disable display (blank CRT) */ +#define DS_ENA 0300 /* enable display (use CRT) */ + /* light-pen hit interrupt enable: */ +#define LH_SAME 0000 /* no change */ +#define LH_DIS 0040 /* light-pen hit interrupt disabled */ +#define LH_ENA 0060 /* light-pen hit interrupt enabled */ + /* tip-switch transition interrupt enable: */ +#define SW_SAME 0000 /* no change */ +#define SW_DIS 0010 /* tip-switch interrupt disabled */ +#define SW_ENA 0014 /* tip-switch hit interrupt enabled */ + +/* load name register (VS60): */ +#define LNR(name) \ + 0150000 | (name) + +/* set graphic mode: */ +#define SGM(mode,intens,lp_intr,blink,line_type) \ + 0100000 | mode | intens | lp_intr | blink | line_type + /* graphic mode: */ +#define GM_CHAR 000000 /* character */ +#define GM_SVECT 004000 /* short vector */ +#define GM_LVECT 010000 /* long vector */ +#define GM_APOINT 014000 /* absolute point, or offset */ +#define GM_GRAPHX 020000 /* graphplot X, or basic long vector */ +#define GM_GRAPHY 024000 /* graphplot Y, or basic long vector */ +#define GM_RPOINT 030000 /* relative point */ +#define GM_BSVECT 034000 /* basic short vector */ +#define GM_ARC 040000 /* circle/arc */ +#define GM_AVECT 044000 /* absolute vector */ + /* intensity: */ +#define IN_SAME 00000 /* no change */ +#define IN_0 02000 /* intensity level 0 (dimmest) */ +#define IN_1 02200 /* intensity level 1 */ +#define IN_2 02400 /* intensity level 2 */ +#define IN_3 02600 /* intensity level 3 */ +#define IN_4 03000 /* intensity level 4 */ +#define IN_5 03200 /* intensity level 5 */ +#define IN_6 03400 /* intensity level 6 */ +#define IN_7 03600 /* intensity level 7 (brightest) */ + /* light pen interrupt: */ +#define LP_SAME 0000 /* no change */ +#define LP_DIS 0100 /* light-pen hit interrupt disabled */ +#define LP_ENA 0140 /* light-pen hit interrupt enabled */ + /* blink: */ +#define BL_SAME 000 /* no change */ +#define BL_OFF 020 /* blink off */ +#define BL_ON 030 /* blink on */ + /* line type: */ +#define LT_SAME 00 /* no change */ +#define LT_SOLID 04 /* solid */ +#define LT_LDASH 05 /* long dash */ +#define LT_SDASH 06 /* short dash */ +#define LT_DDASH 07 /* dot dash */ + +/* display jump absolute: */ +#define DJMP_ABS(addr) \ + 0160000, \ + (addr) & ~1 + +/* display jump relative (VS60) [raddr in words]: */ +#define DJMP_REL(raddr) \ + 0161000 | JDL_(raddr) + +/* display jump to subroutine absolute (VS60): */ +#define DJSR_ABS(addr) \ + 0162000, \ + (addr) & ~1 + +/* display jump to subroutine relative (VS60) [raddr in words]: */ +#define DJSR_REL(raddr) \ + 0163000 | JDL_(raddr) + +/* display no-op: */ +#define DNOP \ + 0164000 + +/* display pop, no restore (VS60): */ +#define DPOP_NR \ + 0165000 + +/* display pop, restore (VS60): */ +#define DPOP_R \ + 0165000 + +/* display stop: */ +#define DSTOP LSRA(ST_STOP,SI_SAME,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME) + +/* graphic data: */ + + /* intensify enable (common to all modes exept CHAR and OFFSET): */ +#define I_OFF 000000 /* beam off */ +#define I_ON 040000 /* beam on */ + +/* Note: when VS60 "file Z data" is enabled, + use the *3() macros instead of the corresponding normal ones. */ + +/* character data: */ +#define CHAR(c1,c2) \ + ((c2) << 8) | (c1) /* 7-bit ASCII assumed */ + +/* short vector data: */ +#define SVECT(i,dx,dy) \ + i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy) +#define SVECT3(i,dx,dy,dz) \ + i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \ + (SGN_(dz) << 13) | (MAG_(dz) << 2) + +/* long vector data: */ +#define LVECT(i,dx,dy) \ + i | (SGN_(dx) << 13) | MAG_(dx), \ + (SGN_(dy) << 13) | MAG_(dy) +#define LVECT3(i,dx,dy,dz) \ + i | (SGN_(dx) << 13) | MAG_(dx), \ + (SGN_(dy) << 13) | MAG_(dy), \ + (SGN_(dz) << 13) | (MAG_(dz) << 2) + +/* rotation data (VS60, probably unimplemented): */ +#define ROTATE(i,a,b) \ + i | (SGN_(a) << 13) | 010000 | MAG_(a), \ + (SGN_(b) << 13) | MAG_(b) +#define ROTATE3(i,a,b,c) \ + i | (SGN_(a) << 13) | 010000 | MAG_(a), \ + (SGN_(b) << 13) | MAG_(b), \ + (SGN_(c) << 13) | (MAG_(c) << 2) + +/* absolute point data: */ +#define APOINT(i,x,y) \ + i | (SGN_(x) << 13) | MAG_(x), \ + (SGN_(y) << 13) | MAG_(y) +#define APOINT3(i,x,y,z) \ + i | (SGN_(x) << 13) | MAG_(x), \ + (SGN_(y) << 13) | MAG_(y), \ + (SGN_(z) << 13) | (MAG_(z) << 2) + +/* offset data (VS60): */ +#define OFFSET(x,y) \ + (SGN_(x) << 13) | 010000 | MAG_(x), \ + (SGN_(y) << 13) | 010000 | MAG_(y) +#define OFFSET3(x,y,z) \ + (SGN_(x) << 13) | 010000 | MAG_(x), \ + (SGN_(y) << 13) | 010000 | MAG_(y), \ + (SGN_(z) << 13) | 010000 | (MAG_(z) << 2) + +/* graphplot X data: */ +#define GRAPHX(i,x) \ + i | (x) + +/* graphplot Y data: */ +#define GRAPHY(i,y) \ + i | (y) + +/* basic long vector data (VS60): */ +#define BLVECT(i,dir,len) \ + i | ((dir) << 11) | 02000 | (len) + +/* relative point data: */ +#define RPOINT(i,dx,dy) \ + i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy) +#define RPOINT3(i,dx,dy,dz) \ + i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \ + (SGN_(dz) << 13) | (MAG_(dz) << 2) + +/* basic short vector data (VS60): */ +#define BSVECT(i,dir1,len1,dir2,len2) \ + i | ((dir2) << 11) | ((len2) << 7) | ((dir1) << 4) | (len1) + +/* circle/arc data (VS60, option): */ +#define ARC(i,dcx,dcy,dex,dey) \ + i | (SGN_(dcx) << 13) | MAG_(dcx), \ + (SGN_(dcy) << 13) | MAG_(dcy), \ + (SGN_(dex) << 13) | MAG_(dex), \ + (SGN_(dey) << 13) | MAG_(dey) +#define ARC3(i,dcx,dcy,cz,dex,dey,ez) \ + i | (SGN_(dcx) << 13) | MAG_(dcx), \ + (SGN_(dcy) << 13) | MAG_(dcy), \ + (SGN_(cz) << 13) | (MAG_(cz) << 2), \ + (SGN_(dex) << 13) | MAG_(dex), \ + (SGN_(dey) << 13) | MAG_(dey), \ + (SGN_(ez) << 13) | (MAG_(ez) << 2) + +/* absolute vector data (VS60): */ +#define AVECT(i,x,y) \ + i | (SGN_(x) << 13) | MAG_(x), \ + (SGN_(y) << 13) | MAG_(y) +#define AVECT3(i,x,y,z) \ + i | (SGN_(x) << 13) | MAG_(x), \ + (SGN_(y) << 13) | MAG_(y), \ + (SGN_(z) << 13) | (MAG_(z) << 2) diff --git a/display/vttest.c b/display/vttest.c index eb2efc3f..e2e16c98 100644 --- a/display/vttest.c +++ b/display/vttest.c @@ -1,1301 +1,1465 @@ -/* - * $Id: vttest.c,v 1.10 2004/02/07 06:31:21 phil Exp $ - * VT11 test - * Phil Budne - * September 13, 2003 - * Substantially revised by Douglas A. Gwyn, 27 Jan. 2004 - * - * XXX -- assumes ASCII host character set - * - * In addition to providing some display tests, this program serves as an - * example of how the VT11/VS60 display processor simulator can be used - * without a PDP-11 simulator. The vt11_cycle() function performs a single - * "instruction cycle" of the display processor, and display_sync() forces - * the graphics changes to appear in the window system; thus these must be - * iterated at a fairly rapid rate to provide reasonable interaction. This - * implies that "host" computation must be kept minimal per iteration, or - * else done in a separate thread. When using multiple threads, the display - * file should be declared with "volatile" qualification to ensure that - * modifications are picked up by the display-processor thread. - * - * Part of the fun of display-file programming is figuring out ways to - * safely modify the display without stopping the display processor, which - * is asynchronously interpreting the display file. - */ -#undef FRAME1STOP /* define to pause after first frame of a section */ - -#ifndef TEST_DIS -#define TEST_DIS DIS_VR48 -#endif - -#ifndef TEST_RES -#define TEST_RES RES_HALF -#endif - -#include -#include - -#include "ws.h" /* for ws_beep() */ -#include "display.h" -#include "vt11.h" -#include "vtmacs.h" - -#define USEC 3 /* simulated microseconds per cycle; - making this large causes flicker! */ - -#define JMPA 0160000 /* first word of DJMP_ABS */ - -#define SUPSCR 021 /* SUPERSCRIPT char */ -#define SUBSCR 022 /* SUBSCRIPT char */ -#define ENDSUP 023 /* END SUPERSCRIPT char */ -#define ENDSUB 024 /* END SUBSCRIPT char */ - -/* The following display file (whose words might be larger than 16 bits) is - divided into sections, each ended by a display-stop-with-interrupt - instruction followed by an extra word. The display-stop interrupt handler - replaces these two words with a jump to the start of the section, causing - an endless refresh loop. To advance to the next section, activate the - "tip switch" (mouse button 1); this works even if simulating a VT11. */ - -#define ENDSECT LSRA(ST_STOP,SI_GENERATE,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME), 0, -#define ENDFILE LSRA(ST_STOP,SI_GENERATE,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME), 1, - -/* FILE VT. Static displays that work for both VT11 and VS60. */ - -unsigned short VT[] = { - /* SECTION 1. Box just inside VR14 area using all four line types. - Suitable for VT11 and VS60. */ - - LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_5, LP_ENA, BL_OFF, LT_SAME), - APOINT(I_OFF, 0, 0), - - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_LDASH), - LVECT(I_ON, 01777, 0), - - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), - LVECT(I_ON, 0, 01377), - - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_DDASH), - LVECT(I_ON, -01777, 0), - - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - LVECT(I_ON, 0, -01377), - - ENDSECT - - /* SECTION 2. All text characters (both normal and italic). - Suitable for VT11 and VS60. */ - - LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), - - /* normal text */ - SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), - APOINT(I_OFF, 0, 736), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), - CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), - CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), - CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), - CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), - CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), - CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), - CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), - CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), - CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), - CHAR(15,0), CHAR('\r','\n'), - - /* italic text */ - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), - - /* note no SGMhere */ - CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), - CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), - CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), - CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), - CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), - CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), - CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), - CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), - CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), - CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), - CHAR(15,0), CHAR('\r','\n'), - - ENDSECT - - /* SECTION 3. Fancy display involving all VT11 graphic modes. - Suitable for VT11 and VS60. */ - - LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), - - /* normal text */ - SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_SAME), - APOINT(I_OFF, 0, 01340), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), - CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), - CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), - CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), - CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), - CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), - CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), - CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), - CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), - CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), - CHAR(15,0), CHAR('\r','\n'), - - /* italic text */ - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), - - /* note no SGMhere */ - CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), - CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), - CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), - CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), - CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), - CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), - CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), - CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), - CHAR('\r','\n'), - CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), - CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), - CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), - CHAR(15,0), CHAR('\r','\n'), - - /* labeled lines of all types, blinks, and intensities (LP intr disabled) */ - LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_SAME, LP_DIS, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0740), - - SGM(GM_CHAR, IN_0, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('0',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0740), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0740), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0740), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0700), - - SGM(GM_CHAR, IN_1, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('1',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0700), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0700), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0700), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0640), - - SGM(GM_CHAR, IN_2, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('2',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0640), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0640), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0640), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0600), - - SGM(GM_CHAR, IN_3, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('3',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0600), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0600), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0600), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0540), - - SGM(GM_CHAR, IN_4, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('4',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0540), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0540), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0540), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0500), - - SGM(GM_CHAR, IN_5, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('5',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0500), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0500), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0500), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0440), - - SGM(GM_CHAR, IN_6, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('6',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0440), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0440), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0440), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0400), - - SGM(GM_CHAR, IN_7, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), CHAR('7',0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 0140, 0400), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0400), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0400), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - /* similar, but LP intr enabled, official threshold intensities */ - SGM(GM_APOINT, IN_SAME, LP_ENA, BL_SAME, LT_SAME), - APOINT(I_OFF, 020, 0340), - - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), - - SGM(GM_CHAR, IN_6, LP_SAME, BL_ON, LT_SAME), - CHAR('I','N'), CHAR('T','R'), - - SGM(GM_APOINT, IN_4, LP_SAME, BL_OFF, LT_SAME), - APOINT(I_ON, 0140, 0340), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - APOINT(I_ON, 0150, 0340), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0160, 0340), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), - SVECT(I_ON, 060, 0), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), - SVECT(I_ON, 060, 0), - - /* graphplots */ - SGM(GM_APOINT, IN_5, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_ON, 040, 0200), - - LSRB(CL_SAME, SS_CHANGE, 040), - - SGM(GM_GRAPHY, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - GRAPHY(I_ON, 0160), - GRAPHY(I_ON, 0140), - GRAPHY(I_ON, 0120), - GRAPHY(I_ON, 0100), - GRAPHY(I_ON, 0060), - GRAPHY(I_ON, 0040), - - SGM(GM_RPOINT, IN_SAME, LP_SAME, BL_OFF, LT_SAME), - RPOINT(I_OFF, 0040, 0), - RPOINT(I_ON, 0040, 0), - - LSRB(CL_SAME, SS_CHANGE, 020), - - SGM(GM_GRAPHX, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - GRAPHX(I_ON, 0500), - GRAPHX(I_ON, 0540), - GRAPHX(I_ON, 0600), - GRAPHX(I_ON, 0640), - GRAPHX(I_ON, 0700), - GRAPHX(I_ON, 0740), - - /* long vectors in all directions from a common origin */ - SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SOLID), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, 0100), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, 0200), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0300, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0200, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0100, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0100, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0200, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0300, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, 0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, 0200), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, 0100), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, -0100), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, -0200), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0400, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0300, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0200, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, -0100, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0100, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0200, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0300, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, -0300), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, -0200), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01400, 01100), - SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LVECT(I_ON, 0400, -0100), - - /* nearby lines with varied spacing */ - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01200, 0500), - - SGM(GM_SVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -1), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -2), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -3), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -4), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -5), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -6), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -7), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, -010), - SVECT(I_ON, 077, 0), - SVECT(I_OFF, -077, 044), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 1, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 2, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 3, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 4, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 5, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 6, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 7, 077), - SVECT(I_ON, 0, -077), - SVECT(I_OFF, 010, 077), - SVECT(I_ON, 0, -077), - - /* all four flavors of characters (lp intr enabled, but intensity 4) */ - - SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01040, 0240), - - LSRA(ST_SAME, SI_SAME, LP_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), - CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), - CHAR(' ','B'), CHAR('l','i'), CHAR('n','k'), - - SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01040, 0200), - - LSRA(ST_SAME, SI_SAME, LP_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','t'), CHAR('a','l'), CHAR('i','c'), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), - CHAR(' ','B'), CHAR('l','i'), CHAR('n','k'), - - /* all eight intensities of characters (lp intr enabled) */ - - LSRA(ST_SAME, SI_SAME, LP_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_5, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01040, 0100), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), - CHAR('I','N'), CHAR('T',' '), - - SGM(GM_CHAR, IN_0, LP_SAME, BL_SAME, LT_SAME), - CHAR('0',0), - SGM(GM_CHAR, IN_1, LP_SAME, BL_SAME, LT_SAME), - CHAR('1',0), - SGM(GM_CHAR, IN_2, LP_SAME, BL_SAME, LT_SAME), - CHAR('2',0), - SGM(GM_CHAR, IN_3, LP_SAME, BL_SAME, LT_SAME), - CHAR('3',0), - SGM(GM_CHAR, IN_4, LP_SAME, BL_SAME, LT_SAME), - CHAR('4',0), - SGM(GM_CHAR, IN_5, LP_SAME, BL_SAME, LT_SAME), - CHAR('5',0), - SGM(GM_CHAR, IN_6, LP_SAME, BL_SAME, LT_SAME), - CHAR('6',0), - SGM(GM_CHAR, IN_7, LP_SAME, BL_SAME, LT_SAME), - CHAR('7',0), - - /* XXX -- more can be included in this pattern */ - - ENDSECT - - /* SECTION 4. Clipping tests. - Suitable for VT11 and VS60. */ - - LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01000, 01000), - - SGM(GM_LVECT, IN_4, LP_ENA, BL_OFF, LT_SOLID), - LVECT(I_ON, 01100, 0), - LVECT(I_ON, -01100, 01100), - LVECT(I_ON, 0, -01100), - LVECT(I_OFF, 0, 01100), - LVECT(I_ON, -01100, -01100), - LVECT(I_ON, 01100, 0), - LVECT(I_ON, 0, -01100), - LVECT(I_ON, -01100, 01100), - LVECT(I_OFF, 01100, 0), - LVECT(I_OFF, 01100, 0), - LVECT(I_ON, -01100, -01100), - - ENDSECT - - /* END OF TEST SECTIONS. */ - - ENDFILE -}; - -/* FILE LP. Dynamic light pen tracking; works for both VT11 and VS60. */ - -unsigned short LP[] = { - /* SECTION 1. "rubber-band" dot-dash vector to tracking object. */ - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01000, 01000), /* screen center */ - - SGM(GM_LVECT, IN_4, LP_DIS, BL_SAME, LT_DDASH), - /* following coordinates are updated by LP hit intr. handler: */ - LVECT(I_ON, 0, 0), /* tracking object center */ - - SGM(GM_SVECT, IN_7, LP_ENA, BL_SAME, LT_SOLID), - SVECT(I_OFF, 1, -31), - SVECT(I_ON, -2, 0), - SVECT(I_OFF, 2, 0), - SVECT(I_ON, 0, 62), - SVECT(I_ON, -2, 0), - SVECT(I_OFF, 2, 0), - SVECT(I_ON, 30, -30), - SVECT(I_OFF, 0, -2), - SVECT(I_ON, 0, 2), - SVECT(I_ON, -62, 0), - SVECT(I_OFF, 0, -2), - SVECT(I_ON, 0, 2), - SVECT(I_ON, 30, 30), - SVECT(I_ON, 0, -62), - SVECT(I_ON, -30, 30), - SVECT(I_ON, 62, 0), - SVECT(I_ON, -30, -30), -#if 0 /* not needed for this app */ - SVECT(I_OFF, -1, 31), /* "flyback" vector */ -#endif - - ENDSECT - - /* END OF TEST SECTIONS. */ - - ENDFILE -}; - -/* FILE VS. Static displays that work only for VS60. */ - -unsigned short VS[] = { - /* SECTION 0. Warning that VS60 is required. */ - - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0300, 01000), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), - CHAR('F','o'), CHAR('l','l'), CHAR('o','w'), CHAR('i','n'), CHAR('g',' '), - CHAR('t','e'), CHAR('s','t'), CHAR('s',' '), CHAR('d','o'), - CHAR(' ','n'), CHAR('o','t'), CHAR(' ','w'), CHAR('o','r'), - CHAR('k',' '), CHAR('f','o'), CHAR('r',' '), CHAR('V','T'), - CHAR('1','1'), CHAR(';',0), - - /* italic text */ - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), - - SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0340, 00720), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), - CHAR('S','T'), CHAR('O','P'), CHAR(' ','P'), CHAR('R','O'), CHAR('G','R'), - CHAR('A','M'), CHAR(' ','i'), CHAR('f',' '), CHAR('n','o'), CHAR('t',' '), - CHAR('u','s'), CHAR('i','n'), CHAR('g',' '), CHAR('V','R'), CHAR('4','8'), - CHAR('!',0), - - ENDSECT - - /* SECTION 1. Variety of text characters. */ - - LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_UNSYNC, MN_MAIN), - - /* horizontal text, 4 sizes */ - SGM(GM_APOINT, IN_4, LP_ENA, BL_SAME, LT_SAME), - APOINT(I_OFF, 0, 01600), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LSRC(RO_SAME, CS_CHANGE, 0, VS_SAME, 0), - CHAR(' ',' '), CHAR('S','m'), CHAR('a','l'), CHAR('l',':'), CHAR(' ','1'), - CHAR('/','2'), - LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), - CHAR(' ',' '), CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), CHAR(':',' '), - CHAR('1',0), - LSRC(RO_SAME, CS_CHANGE, 2, VS_SAME, 0), - CHAR(' ',' '), CHAR('B','i'), CHAR('g',':'), CHAR(' ','1'), CHAR('-','1'), - CHAR('/','2'), - LSRC(RO_SAME, CS_CHANGE, 3, VS_SAME, 0), - CHAR(' ',' '), CHAR('L','a'), CHAR('r','g'), CHAR('e',':'), CHAR(' ','2'), - CHAR('\r','\n'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('A',SUBSCR), CHAR('B',SUBSCR), CHAR('C',SUBSCR), - CHAR('D',ENDSUB), CHAR(ENDSUB,ENDSUB), CHAR('W',SUPSCR), - CHAR('X',SUPSCR), CHAR('Y',SUPSCR), CHAR('Z',ENDSUP), - CHAR(ENDSUP,ENDSUP), CHAR('!','!'), - - /* vertical text, 4 sizes */ - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0200, 0), - - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - LSRC(RO_VERTICAL, CS_CHANGE, 0, VS_SAME, 0), - CHAR(' ',' '), CHAR('S','m'), CHAR('a','l'), CHAR('l',':'), CHAR(' ','1'), - CHAR('/','2'), - LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), - CHAR(' ',' '), CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), CHAR(':',' '), - CHAR('1',0), - LSRC(RO_SAME, CS_CHANGE, 2, VS_SAME, 0), - CHAR(' ',' '), CHAR('B','i'), CHAR('g',':'), CHAR(' ','1'), CHAR('-','1'), - CHAR('/','2'), - LSRC(RO_SAME, CS_CHANGE, 3, VS_SAME, 0), - CHAR(' ',' '), CHAR('L','a'), CHAR('r','g'), CHAR('e',':'), CHAR(' ','2'), - CHAR('\r','\n'), CHAR('\r','\n'), - CHAR(' ',' '), CHAR('A',SUBSCR), CHAR('B',SUBSCR), CHAR('C',SUBSCR), - CHAR('D',ENDSUB), CHAR(ENDSUB,ENDSUB), CHAR('W',SUPSCR), - CHAR('X',SUPSCR), CHAR('Y',SUPSCR), CHAR('Z',ENDSUP), - CHAR(ENDSUP,ENDSUP), CHAR('!','!'), - - /* horizontal text, sub/superscript examples from DECgraphic-11 manual */ - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 0400, 01200), - - LSRC(RO_HORIZONTAL, CS_CHANGE, 2, VS_SAME, 0), - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - CHAR('C',SUBSCR), CHAR('2',ENDSUB), CHAR('H',SUBSCR), CHAR('5',ENDSUB), - CHAR('O','H'), CHAR(' ',' '), - CHAR(016,000), CHAR(017,'='), CHAR(016,003), CHAR(017,'('), - CHAR('x',SUBSCR), CHAR('i',ENDSUB), CHAR('-','q'), CHAR(SUBSCR,'i'), - CHAR(ENDSUB,')'), CHAR(SUPSCR,'2'), CHAR(ENDSUP,'e'), CHAR(SUPSCR,'-'), - CHAR('i',SUPSCR), CHAR('2',ENDSUP), CHAR(ENDSUP,0), - - LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), - SGM(GM_APOINT, IN_7, LP_ENA, BL_SAME, LT_SAME), - APOINT(I_OFF, 0, 1000), - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - CHAR('U','n'), CHAR('s','y'), CHAR('n','c'), - - ENDSECT - - /* SECTION 2. Basic vectors (long and short). */ - - LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_40, MN_MAIN), - - SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_SDASH), - APOINT(I_OFF, 01000, 01000), - - SGM(GM_GRAPHX, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - BLVECT(I_OFF, 2, 0600), - BLVECT(I_ON, 0, 0200), - BLVECT(I_ON, 7, 0400), - BLVECT(I_ON, 6, 0400), - BLVECT(I_ON, 5, 0400), - BLVECT(I_ON, 4, 0400), - SGM(GM_GRAPHY, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - BLVECT(I_ON, 3, 0400), - BLVECT(I_ON, 2, 0400), - BLVECT(I_ON, 1, 0400), - BLVECT(I_ON, 0, 0200), - BLVECT(I_OFF, 6, 0600), - - SGM(GM_BSVECT, IN_SAME, LP_SAME, BL_ON, LT_SOLID), - BSVECT(I_OFF, 2, 007, 2, 016), - BSVECT(I_ON, 0, 007, 7, 016), - BSVECT(I_ON, 6, 016, 5, 016), - BSVECT(I_ON, 4, 016, 3, 016), - BSVECT(I_ON, 2, 016, 1, 016), - BSVECT(I_ON, 0, 007, 0, 000), - - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), - SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), - APOINT(I_OFF, 0, 1000), - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - CHAR('4','0'), CHAR('H','z'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), - - ENDSECT - - /* SECTION 3. 3D data, but depth cueing disabled. */ - - LSRBB(ZD_YES, ED_ENA, DQ_OFF, ES_YES), /* but term char not used */ - LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_30, MN_MAIN), - - SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_LDASH), - APOINT3(I_OFF, 0200, 0200, 0400), - - SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - AVECT3(I_ON, 01200, 00200, 0400), - AVECT3(I_ON, 01200, 01200, 0400), - AVECT3(I_ON, 00200, 01200, 0400), - AVECT3(I_ON, 00200, 00200, 0400), - AVECT3(I_OFF, 00600, 00600, -0400), - AVECT3(I_ON, 01600, 00600, -0400), - AVECT3(I_ON, 01600, 01600, -0400), - AVECT3(I_ON, 00600, 01600, -0400), - AVECT3(I_ON, 00600, 00600, -0400), - SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - AVECT3(I_ON, 00200, 00200, 0400), - AVECT3(I_OFF, 01200, 00200, 0400), - AVECT3(I_ON, 01600, 00600, -0400), - AVECT3(I_OFF, 01600, 01600, -0400), - AVECT3(I_ON, 01200, 01200, 0400), - AVECT3(I_OFF, 00200, 01200, 0400), - AVECT3(I_ON, 00600, 01600, -0400), - - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), - SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), - APOINT3(I_OFF, 0, 1000, 0200), - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - CHAR('3','0'), CHAR('H','z'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), - - ENDSECT - - /* SECTION 4. 3D data, with depth cueing enabled. */ - - LSRBB(ZD_YES, ED_ENA, DQ_ON, ES_YES), /* but term char not used */ - LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_EXT, MN_MAIN), - - SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_DDASH), - APOINT3(I_OFF, 0200, 0200, 0400), - - SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - AVECT3(I_ON, 01200, 00200, 0400), - AVECT3(I_ON, 01200, 01200, 0400), - AVECT3(I_ON, 00200, 01200, 0400), - AVECT3(I_ON, 00200, 00200, 0400), - AVECT3(I_OFF, 00600, 00600, -0400), - AVECT3(I_ON, 01600, 00600, -0400), - AVECT3(I_ON, 01600, 01600, -0400), - AVECT3(I_ON, 00600, 01600, -0400), - AVECT3(I_ON, 00600, 00600, -0400), - SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - AVECT3(I_ON, 00200, 00200, 0400), - AVECT3(I_OFF, 01200, 00200, 0400), - AVECT3(I_ON, 01600, 00600, -0400), - AVECT3(I_OFF, 01600, 01600, -0400), - AVECT3(I_ON, 01200, 01200, 0400), - AVECT3(I_OFF, 00200, 01200, 0400), - AVECT3(I_ON, 00600, 01600, -0400), - - LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), - SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), - APOINT3(I_OFF, 0, 1000, 0200), - SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - CHAR('E','x'), CHAR('t','.'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), - - ENDSECT - - /* SECTION 5. Circles and arcs. */ - - SGM(GM_APOINT, IN_4, LP_ENA, BL_ON, LT_SOLID), - APOINT(I_OFF, 0500, 01400), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, -0100, 0, 0, 0), - - SGM(GM_APOINT, IN_5, LP_SAME, BL_OFF, LT_SDASH), - APOINT(I_OFF, 0532, 01532), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, -0132, -0132, 0, -0264), - - SGM(GM_APOINT, IN_6, LP_SAME, BL_SAME, LT_LDASH), - APOINT(I_OFF, 0400, 01700), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, 0, -0300, 0, -0600), - - SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_DDASH), - APOINT(I_OFF, 0114, 01664), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, 0264, -0264, 0, -0550), - - SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SOLID), - APOINT(I_OFF, 01400, 01400), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, 0, 0, 0400, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), - APOINT(I_OFF, 0500, 0400), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - ARC(I_ON, -0100, 0, 0200, 0), - - SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), - APOINT(I_OFF, 01600, 0400), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), - ARC(I_ON, -0200, 0, -0200, 0300), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), - ARC(I_ON, 0, -0300, -0200, -0300), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_LDASH), - ARC(I_ON, 0200, 0, 0200, -0300), - SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_DDASH), - ARC(I_ON, 0, 0300, 0200, 0300), - - ENDSECT - - /* SECTION 6. Display subroutines, with and without parameter restore. */ - - /* XXX need test for subroutines */ - - /* SECTION 7. Offset, vector scale, and clipping. */ - - /* XXX need test for offset, vector scale, and clipping */ - - /* END OF TEST SECTIONS. */ - - ENDFILE -}; - -static unsigned short *df; /* -> start of current display file */ -static uint16 start; /* initial DPC for section of d.file */ -static int more; /* set until end of d.file seen */ - -int -main(void) { - int c; - - vt11_display = TEST_DIS; - vt11_scale = TEST_RES; - - /* VT11/VS60 tests */ - - puts("initial tests work for both VT11 and VS60"); - for (df = VT, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ - vt11_set_dpc(start); /* start section */ - c = 0; - while (vt11_cycle(USEC, 1)) { - display_sync(); /* XXX push down? */ - if (display_lp_sw) /* tip switch activated */ - c = 1; /* flag: break requested */ - if (c && !display_lp_sw) /* wait for switch release */ - break; - } - /* end of section */ - } - /* end of display file */ - - /* light pen tracking */ - - ws_beep(); - puts("move the light pen through the tracking object"); - fflush(stdout); - for (df = LP, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ - vt11_set_dpc(start); /* start section */ - c = 0; - while (vt11_cycle(USEC, 1)) { - display_sync(); /* XXX push down? */ - if (display_lp_sw) /* tip switch activated */ - c = 1; /* flag: break requested */ - if (c && !display_lp_sw) /* wait for switch release */ - break; - /* [dynamic modifications to the display file can be done here] */ - } - /* end of section */ - } - /* end of display file */ - - /* VS60 tests */ - - ws_beep(); - puts("following tests require VS60"); - for (df = VS, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ - vt11_set_str((uint16)(0200 | '~')); /* set terminating char. */ - vt11_set_anr((uint16)(040000 | (2<<12) | 04000 | 01234)); - /* set associative name 0123x */ - vt11_set_dpc(start); /* start section */ - c = 0; - while (vt11_cycle(USEC, 1)) { - display_sync(); /* XXX push down? */ - if (display_lp_sw) /* tip switch activated */ - c = 1; /* flag: break requested */ - if (c && !display_lp_sw) /* wait for switch release */ - break; - } - /* end of section */ - } - /* end of display file */ - - /* XXX would be nice to have an example of animation */ - - return 0; -} - -/* - * callbacks from display.c - */ -unsigned long -cpu_get_switches(void) { - return 0; -} - -void -cpu_set_switches(unsigned long bits) { -} - -/* - * callbacks from vt11.c - */ - -int -vt_fetch(uint32 addr, vt11word *w) { - *w = df[addr/2]; - return 0; -} - -void -vt_stop_intr(void) { - uint16 dpc = vt11_get_dpc(); /* -> just after DSTOP instruction */ - if (df[dpc/2] == 0) { /* ENDSECT */ -#ifdef FRAME1STOP - int c; - puts("end of first pass through this test pattern; display frozen"); - puts("enter newline to refresh this section or EOF to quit"); - fflush(stdout); - while ((c = getchar()) != '\n') - if (c == EOF) - exit(0); /* user aborted test */ -#endif - df[dpc/2 - 1] = JMPA; - df[dpc/2] = start; - start = dpc + 2; /* save start of next section */ - vt11_set_dpc(dpc - 2); /* reset; then JMPA to old start */ - puts("press and release tip switch (mouse button 1) for next display"); - fflush(stdout); - } else /* ENDFILE */ - more = 0; -} - -void -vt_lpen_intr(void) { - if (df == LP) { - int dx = (int)(vt11_get_xpr() & 01777) - 01000; - int dy = (int)(vt11_get_ypr() & 01777) - 01000; - if (dx < 0) - dx = (-dx) | 020000; /* negative */ - if (dy < 0) - dy = (-dy) | 020000; /* negative */ - - df[4] = dx | I_ON; /* visible */ - df[5] = dy; - } else { - printf("VT11 lightpen interrupt (%d,%d)\n", - (int)vt11_get_xpr() & 01777, (int)vt11_get_ypr() & 01777); - fflush(stdout); - } - vt11_set_dpc((uint16)1); /* resume */ -} - -void -vt_char_intr(void) { - puts("VT11 illegal character/timeout interrupt"); - fflush(stdout); - vt11_set_dpc((uint16)1); /* resume */ -} - -void -vt_name_intr(void) { - puts("VS60 name-match interrupt"); - fflush(stdout); - vt11_set_dpc((uint16)1); /* resume */ -} +/* + * $Id: vttest.c,v 1.15 2005/08/06 21:09:05 phil Exp $ + * VT11 test + * Phil Budne + * September 13, 2003 + * Substantially revised by Douglas A. Gwyn, 05 Aug 2005 + * + * XXX -- assumes ASCII host character set + * + * In addition to providing some display tests, this program serves as an + * example of how the VT11/VS60 display processor simulator can be used + * without a PDP-11 simulator. The vt11_cycle() function performs a single + * "instruction cycle" of the display processor, and display_sync() forces + * the graphics changes to appear in the window system; thus these must be + * iterated at a fairly rapid rate to provide reasonable interaction. This + * implies that "host" computation must be kept minimal per iteration, or + * else done in a separate thread. When using multiple threads, the display + * file should be declared with "volatile" qualification to ensure that + * modifications are picked up by the display-processor thread. + * + * Part of the fun of display-file programming is figuring out ways to + * safely modify the display without stopping the display processor, which + * is asynchronously interpreting the display file. + */ +#undef FRAME1STOP /* define to pause after first frame of a section */ + +#ifndef TEST_DIS +#define TEST_DIS DIS_VR48 +#endif + +#ifndef TEST_RES +#define TEST_RES RES_HALF +#endif + +#include +#include +#include + +#include "ws.h" /* for ws_beep() */ +#include "xy.h" +#include "vt11.h" +#include "vtmacs.h" + +#define USEC 3 /* simulated microseconds per cycle; + making this large causes flicker! */ + +#define JMPA 0160000 /* first word of DJMP_ABS */ + +#define SUPSCR 021 /* SUPERSCRIPT char */ +#define SUBSCR 022 /* SUBSCRIPT char */ +#define ENDSUP 023 /* END SUPERSCRIPT char */ +#define ENDSUB 024 /* END SUBSCRIPT char */ + +/* The following display file (whose words might be larger than 16 bits) is + divided into sections, each ended by a display-stop-with-interrupt + instruction followed by an extra word. The display-stop interrupt handler + replaces these two words with a jump to the start of the section, causing + an endless refresh loop. To advance to the next section, activate the + "tip switch" (mouse button 1); this works even if simulating a VT11. */ + +#define ENDSECT LSRA(ST_STOP,SI_GENERATE,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME), 0, +#define ENDFILE LSRA(ST_STOP,SI_GENERATE,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME), 1, + +/* FILE VT. Static displays that work for both VT11 and VS60. */ + +unsigned short VT[] = { + /* SECTION 1. Box just inside VR14 area using all four line types. + Suitable for VT11 and VS60. */ + + LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_5, LP_ENA, BL_OFF, LT_SAME), + APOINT(I_OFF, 0, 0), + + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_LDASH), + LVECT(I_ON, 01777, 0), + + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), + LVECT(I_ON, 0, 01377), + + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_DDASH), + LVECT(I_ON, -01777, 0), + + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + LVECT(I_ON, 0, -01377), + + ENDSECT + + /* SECTION 2. All text characters (both normal and italic). + Suitable for VT11 and VS60. */ + + LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), + + /* normal text */ + SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), + APOINT(I_OFF, 0, 736), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), + CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), + CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), + CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), + CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), + CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), + CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), + CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), + CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), + CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), + CHAR(15,0), CHAR('\r','\n'), + + /* italic text */ + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), + + /* note no SGMhere */ + CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), + CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), + CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), + CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), + CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), + CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), + CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), + CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), + CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), + CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), + CHAR(15,0), CHAR('\r','\n'), + + ENDSECT + + /* SECTION 3. Fancy display involving all VT11 graphic modes. + Suitable for VT11 and VS60. */ + + LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), + + /* normal text */ + SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_SAME), + APOINT(I_OFF, 0, 01340), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), + CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), + CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), + CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), + CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), + CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), + CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), + CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), + CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), + CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), + CHAR(15,0), CHAR('\r','\n'), + + /* italic text */ + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), + + /* note no SGMhere */ + CHAR(' ',' '), CHAR('A','B'), CHAR('C','D'), CHAR('E','F'), CHAR('G','H'), + CHAR('I','J'), CHAR('K','L'), CHAR('M','N'), CHAR('O','P'), CHAR('Q','R'), + CHAR('S','T'), CHAR('U','V'), CHAR('W','X'), CHAR('Y','Z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('a','b'), CHAR('c','d'), CHAR('e','f'), CHAR('g','h'), + CHAR('i','j'), CHAR('k','l'), CHAR('m','n'), CHAR('o','p'), CHAR('q','r'), + CHAR('s','t'), CHAR('u','v'), CHAR('w','x'), CHAR('y','z'), CHAR('\r','\n'), + CHAR(' ',' '), CHAR('0','1'), CHAR('2','3'), CHAR('4','5'), CHAR('6','7'), + CHAR('8','9'), CHAR(' ','!'), CHAR('"','#'), CHAR('$','%'), CHAR('&','\''), + CHAR('(',')'), CHAR('*','+'), CHAR(',','-'), CHAR('.','/'), CHAR('@',0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(':',';'), CHAR('<','='), CHAR('>','?'), CHAR('[','\\'), + CHAR(']','^'), CHAR('_','`'), CHAR('{','|'), CHAR('}','~'), CHAR(127,0), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR(14,0), CHAR(1,2), CHAR(3,4), CHAR(5,6), CHAR(7,8), + CHAR(9,10), CHAR(11,12), CHAR(13,14), CHAR(16,17), CHAR(18,19), CHAR(20,21), + CHAR(22,23), CHAR(24,25), CHAR(26,27), CHAR(28,29), CHAR(30,31), + CHAR(15,0), CHAR('\r','\n'), + + /* labeled lines of all types, blinks, and intensities (LP intr disabled) */ + LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_SAME, LP_DIS, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0740), + + SGM(GM_CHAR, IN_0, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('0',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0740), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0740), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0740), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0700), + + SGM(GM_CHAR, IN_1, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('1',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0700), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0700), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0700), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0640), + + SGM(GM_CHAR, IN_2, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('2',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0640), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0640), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0640), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0600), + + SGM(GM_CHAR, IN_3, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('3',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0600), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0600), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0600), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0540), + + SGM(GM_CHAR, IN_4, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('4',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0540), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0540), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0540), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0500), + + SGM(GM_CHAR, IN_5, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('5',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0500), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0500), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0500), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0440), + + SGM(GM_CHAR, IN_6, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('6',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0440), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0440), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0440), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0400), + + SGM(GM_CHAR, IN_7, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), CHAR('7',0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 0140, 0400), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0400), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0400), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + /* similar, but LP intr enabled, official threshold intensities */ + SGM(GM_APOINT, IN_SAME, LP_ENA, BL_SAME, LT_SAME), + APOINT(I_OFF, 020, 0340), + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), + + SGM(GM_CHAR, IN_6, LP_SAME, BL_ON, LT_SAME), + CHAR('I','N'), CHAR('T','R'), + + SGM(GM_APOINT, IN_4, LP_SAME, BL_OFF, LT_SAME), + APOINT(I_ON, 0140, 0340), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + APOINT(I_ON, 0150, 0340), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0160, 0340), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SOLID), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_LDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_SDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_OFF, LT_DDASH), + SVECT(I_ON, 060, 0), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_ON, LT_SAME), + SVECT(I_ON, 060, 0), + + /* graphplots */ + SGM(GM_APOINT, IN_5, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_ON, 040, 0200), + + LSRB(CL_SAME, SS_CHANGE, 040), + + SGM(GM_GRAPHY, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + GRAPHY(I_ON, 0160), + GRAPHY(I_ON, 0140), + GRAPHY(I_ON, 0120), + GRAPHY(I_ON, 0100), + GRAPHY(I_ON, 0060), + GRAPHY(I_ON, 0040), + + SGM(GM_RPOINT, IN_SAME, LP_SAME, BL_OFF, LT_SAME), + RPOINT(I_OFF, 0040, 0), + RPOINT(I_ON, 0040, 0), + + LSRB(CL_SAME, SS_CHANGE, 020), + + SGM(GM_GRAPHX, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + GRAPHX(I_ON, 0500), + GRAPHX(I_ON, 0540), + GRAPHX(I_ON, 0600), + GRAPHX(I_ON, 0640), + GRAPHX(I_ON, 0700), + GRAPHX(I_ON, 0740), + + /* long vectors in all directions from a common origin */ + SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SOLID), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, 0100), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, 0200), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0300, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0200, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0100, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0100, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0200, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0300, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, 0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, 0200), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, 0100), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, -0100), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, -0200), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0400, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0300, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0200, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, -0100, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0100, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0200, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0300, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, -0300), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, -0200), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01400, 01100), + SGM(GM_LVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LVECT(I_ON, 0400, -0100), + + /* nearby lines with varied spacing */ + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01200, 0500), + + SGM(GM_SVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -1), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -2), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -3), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -4), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -5), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -6), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -7), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, -010), + SVECT(I_ON, 077, 0), + SVECT(I_OFF, -077, 044), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 1, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 2, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 3, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 4, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 5, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 6, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 7, 077), + SVECT(I_ON, 0, -077), + SVECT(I_OFF, 010, 077), + SVECT(I_ON, 0, -077), + + /* all four flavors of characters (lp intr enabled, but intensity 4) */ + + SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01040, 0240), + + LSRA(ST_SAME, SI_SAME, LP_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), + CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), + CHAR(' ','B'), CHAR('l','i'), CHAR('n','k'), + + SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01040, 0200), + + LSRA(ST_SAME, SI_SAME, LP_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','t'), CHAR('a','l'), CHAR('i','c'), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), + CHAR(' ','B'), CHAR('l','i'), CHAR('n','k'), + + /* all eight intensities of characters (lp intr enabled) */ + + LSRA(ST_SAME, SI_SAME, LP_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_5, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01040, 0100), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), + CHAR('I','N'), CHAR('T',' '), + + SGM(GM_CHAR, IN_0, LP_SAME, BL_SAME, LT_SAME), + CHAR('0',0), + SGM(GM_CHAR, IN_1, LP_SAME, BL_SAME, LT_SAME), + CHAR('1',0), + SGM(GM_CHAR, IN_2, LP_SAME, BL_SAME, LT_SAME), + CHAR('2',0), + SGM(GM_CHAR, IN_3, LP_SAME, BL_SAME, LT_SAME), + CHAR('3',0), + SGM(GM_CHAR, IN_4, LP_SAME, BL_SAME, LT_SAME), + CHAR('4',0), + SGM(GM_CHAR, IN_5, LP_SAME, BL_SAME, LT_SAME), + CHAR('5',0), + SGM(GM_CHAR, IN_6, LP_SAME, BL_SAME, LT_SAME), + CHAR('6',0), + SGM(GM_CHAR, IN_7, LP_SAME, BL_SAME, LT_SAME), + CHAR('7',0), + + /* XXX -- more can be included in this pattern */ + + ENDSECT + + /* SECTION 4. Clipping tests. + Suitable for VT11 and VS60. */ + + LSRA(ST_SAME, SI_SAME, LI_INTENSIFY, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01000, 01000), + + SGM(GM_LVECT, IN_4, LP_ENA, BL_OFF, LT_SOLID), + LVECT(I_ON, 01100, 0), + LVECT(I_ON, -01100, 01100), + LVECT(I_ON, 0, -01100), + LVECT(I_OFF, 0, 01100), + LVECT(I_ON, -01100, -01100), + LVECT(I_ON, 01100, 0), + LVECT(I_ON, 0, -01100), + LVECT(I_ON, -01100, 01100), + LVECT(I_OFF, 01100, 0), + LVECT(I_OFF, 01100, 0), + LVECT(I_ON, -01100, -01100), + + ENDSECT + + /* END OF TEST SECTIONS. */ + + ENDFILE +}; + +/* FILE LP. Dynamic light pen tracking; works for both VT11 and VS60. */ + +unsigned short LP[] = { + /* SECTION 1. "rubber-band" dot-dash vector to tracking object. */ + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01000, 01000), /* screen center */ + + SGM(GM_LVECT, IN_4, LP_DIS, BL_SAME, LT_DDASH), + /* following coordinates are updated by LP hit intr. handler: */ + LVECT(I_ON, 0, 0), /* tracking object center */ + + SGM(GM_SVECT, IN_7, LP_ENA, BL_SAME, LT_SOLID), + SVECT(I_OFF, 0, 30), + SVECT(I_ON, 0, -60), + SVECT(I_OFF, 30, 30), + SVECT(I_ON, -60, 0), + SVECT(I_ON, 30, 30), + SVECT(I_ON, 30, -30), + SVECT(I_ON, -30, -30), + SVECT(I_ON, -30, 30), + SVECT(I_OFF, 10, 0), + SVECT(I_ON, 20, 20), + SVECT(I_ON, 20, -20), + SVECT(I_ON, -20, -20), + SVECT(I_ON, -20, 20), + SVECT(I_OFF, 10, 0), + SVECT(I_ON, 10, 10), + SVECT(I_ON, 10, -10), + SVECT(I_ON, -10, -10), + SVECT(I_ON, -10, 10), +#if 0 /* not needed for this app */ + SVECT(I_OFF, 0, -10), /* "flyback" vector */ +#endif + + ENDSECT + + /* END OF TEST SECTIONS. */ + + ENDFILE +}; + +/* FILE VS. Static displays that work only for VS60. */ + +unsigned short VS[] = { + /* SECTION 0. Warning that VS60 is required. */ + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_NORMAL, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0300, 01000), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_OFF, LT_SAME), + CHAR('F','o'), CHAR('l','l'), CHAR('o','w'), CHAR('i','n'), CHAR('g',' '), + CHAR('t','e'), CHAR('s','t'), CHAR('s',' '), CHAR('d','o'), + CHAR(' ','n'), CHAR('o','t'), CHAR(' ','w'), CHAR('o','r'), + CHAR('k',' '), CHAR('f','o'), CHAR('r',' '), CHAR('V','T'), + CHAR('1','1'), CHAR(';',0), + + /* italic text */ + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_ITALIC, RF_UNSYNC, MN_SAME), + + SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0340, 00720), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_ON, LT_SAME), + CHAR('S','T'), CHAR('O','P'), CHAR(' ','P'), CHAR('R','O'), CHAR('G','R'), + CHAR('A','M'), CHAR(' ','i'), CHAR('f',' '), CHAR('n','o'), CHAR('t',' '), + CHAR('u','s'), CHAR('i','n'), CHAR('g',' '), CHAR('V','R'), CHAR('4','8'), + CHAR('!',0), + + ENDSECT + + /* SECTION 1. Variety of text characters. */ + + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_UNSYNC, MN_MAIN), + + /* horizontal text, 4 sizes */ + SGM(GM_APOINT, IN_4, LP_ENA, BL_SAME, LT_SAME), + APOINT(I_OFF, 0, 01600), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LSRC(RO_SAME, CS_CHANGE, 0, VS_SAME, 0), + CHAR(' ',' '), CHAR('S','m'), CHAR('a','l'), CHAR('l',':'), CHAR(' ','1'), + CHAR('/','2'), + LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), + CHAR(' ',' '), CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), CHAR(':',' '), + CHAR('1',0), + LSRC(RO_SAME, CS_CHANGE, 2, VS_SAME, 0), + CHAR(' ',' '), CHAR('B','i'), CHAR('g',':'), CHAR(' ','1'), CHAR('-','1'), + CHAR('/','2'), + LSRC(RO_SAME, CS_CHANGE, 3, VS_SAME, 0), + CHAR(' ',' '), CHAR('L','a'), CHAR('r','g'), CHAR('e',':'), CHAR(' ','2'), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR('A',SUBSCR), CHAR('B',SUBSCR), CHAR('C',SUBSCR), + CHAR('D',ENDSUB), CHAR(ENDSUB,ENDSUB), CHAR('W',SUPSCR), + CHAR('X',SUPSCR), CHAR('Y',SUPSCR), CHAR('Z',ENDSUP), + CHAR(ENDSUP,ENDSUP), CHAR('!','!'), + + /* vertical text, 4 sizes */ + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0200, 0), + + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + LSRC(RO_VERTICAL, CS_CHANGE, 0, VS_SAME, 0), + CHAR(' ',' '), CHAR('S','m'), CHAR('a','l'), CHAR('l',':'), CHAR(' ','1'), + CHAR('/','2'), + LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), + CHAR(' ',' '), CHAR('N','o'), CHAR('r','m'), CHAR('a','l'), CHAR(':',' '), + CHAR('1',0), + LSRC(RO_SAME, CS_CHANGE, 2, VS_SAME, 0), + CHAR(' ',' '), CHAR('B','i'), CHAR('g',':'), CHAR(' ','1'), CHAR('-','1'), + CHAR('/','2'), + LSRC(RO_SAME, CS_CHANGE, 3, VS_SAME, 0), + CHAR(' ',' '), CHAR('L','a'), CHAR('r','g'), CHAR('e',':'), CHAR(' ','2'), + CHAR('\r','\n'), + CHAR(' ',' '), CHAR('A',SUBSCR), CHAR('B',SUBSCR), CHAR('C',SUBSCR), + CHAR('D',ENDSUB), CHAR(ENDSUB,ENDSUB), CHAR('W',SUPSCR), + CHAR('X',SUPSCR), CHAR('Y',SUPSCR), CHAR('Z',ENDSUP), + CHAR(ENDSUP,ENDSUP), CHAR('!','!'), + + /* horizontal text, sub/superscript examples from DECgraphic-11 manual */ + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 0400, 01200), + + LSRC(RO_HORIZONTAL, CS_CHANGE, 2, VS_SAME, 0), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('C',SUBSCR), CHAR('2',ENDSUB), CHAR('H',SUBSCR), CHAR('5',ENDSUB), + CHAR('O','H'), CHAR(' ',' '), + CHAR(016,000), CHAR(017,'='), CHAR(016,003), CHAR(017,'('), + CHAR('x',SUBSCR), CHAR('i',ENDSUB), CHAR('-','q'), CHAR(SUBSCR,'i'), + CHAR(ENDSUB,')'), CHAR(SUPSCR,'2'), CHAR(ENDSUP,'e'), CHAR(SUPSCR,'-'), + CHAR('i',SUPSCR), CHAR('2',ENDSUP), CHAR(ENDSUP,0), + + LSRC(RO_SAME, CS_CHANGE, 1, VS_SAME, 0), + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), + SGM(GM_APOINT, IN_7, LP_ENA, BL_SAME, LT_SAME), + APOINT(I_OFF, 0, 1000), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('U','n'), CHAR('s','y'), CHAR('n','c'), + + ENDSECT + + /* SECTION 2. Basic vectors (long and short). */ + + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_40, MN_MAIN), + + SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_SDASH), + APOINT(I_OFF, 01000, 01000), + + SGM(GM_GRAPHX, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + BLVECT(I_OFF, 2, 0600), + BLVECT(I_ON, 0, 0200), + BLVECT(I_ON, 7, 0400), + BLVECT(I_ON, 6, 0400), + BLVECT(I_ON, 5, 0400), + BLVECT(I_ON, 4, 0400), + SGM(GM_GRAPHY, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + BLVECT(I_ON, 3, 0400), + BLVECT(I_ON, 2, 0400), + BLVECT(I_ON, 1, 0400), + BLVECT(I_ON, 0, 0200), + BLVECT(I_OFF, 6, 0600), + + SGM(GM_BSVECT, IN_SAME, LP_SAME, BL_ON, LT_SOLID), + BSVECT(I_OFF, 2, 007, 2, 016), + BSVECT(I_ON, 0, 007, 7, 016), + BSVECT(I_ON, 6, 016, 5, 016), + BSVECT(I_ON, 4, 016, 3, 016), + BSVECT(I_ON, 2, 016, 1, 016), + BSVECT(I_ON, 0, 007, 0, 000), + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), + SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), + APOINT(I_OFF, 0, 1000), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('4','0'), CHAR('H','z'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), + + ENDSECT + + /* SECTION 3. 3D data, but depth cueing disabled. */ + + LSRBB(ZD_YES, ED_ENA, DQ_OFF, ES_YES), /* but term char not used */ + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_30, MN_MAIN), + + SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_LDASH), + APOINT3(I_OFF, 0200, 0200, 0400), + + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + AVECT3(I_ON, 01200, 00200, 0400), + AVECT3(I_ON, 01200, 01200, 0400), + AVECT3(I_ON, 00200, 01200, 0400), + AVECT3(I_ON, 00200, 00200, 0400), + AVECT3(I_OFF, 00600, 00600, -0400), + AVECT3(I_ON, 01600, 00600, -0400), + AVECT3(I_ON, 01600, 01600, -0400), + AVECT3(I_ON, 00600, 01600, -0400), + AVECT3(I_ON, 00600, 00600, -0400), + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + AVECT3(I_ON, 00200, 00200, 0400), + AVECT3(I_OFF, 01200, 00200, 0400), + AVECT3(I_ON, 01600, 00600, -0400), + AVECT3(I_OFF, 01600, 01600, -0400), + AVECT3(I_ON, 01200, 01200, 0400), + AVECT3(I_OFF, 00200, 01200, 0400), + AVECT3(I_ON, 00600, 01600, -0400), + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), + SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), + APOINT3(I_OFF, 0, 1000, 0200), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('3','0'), CHAR('H','z'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), + + ENDSECT + + /* SECTION 4. 3D data, with depth cueing enabled. */ + + LSRBB(ZD_YES, ED_ENA, DQ_ON, ES_YES), /* but term char not used */ + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_EXT, MN_MAIN), + + SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_DDASH), + APOINT3(I_OFF, 0200, 0200, 0400), + + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + AVECT3(I_ON, 01200, 00200, 0400), + AVECT3(I_ON, 01200, 01200, 0400), + AVECT3(I_ON, 00200, 01200, 0400), + AVECT3(I_ON, 00200, 00200, 0400), + AVECT3(I_OFF, 00600, 00600, -0400), + AVECT3(I_ON, 01600, 00600, -0400), + AVECT3(I_ON, 01600, 01600, -0400), + AVECT3(I_ON, 00600, 01600, -0400), + AVECT3(I_ON, 00600, 00600, -0400), + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + AVECT3(I_ON, 00200, 00200, 0400), + AVECT3(I_OFF, 01200, 00200, 0400), + AVECT3(I_ON, 01600, 00600, -0400), + AVECT3(I_OFF, 01600, 01600, -0400), + AVECT3(I_ON, 01200, 01200, 0400), + AVECT3(I_OFF, 00200, 01200, 0400), + AVECT3(I_ON, 00600, 01600, -0400), + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), + SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), + APOINT3(I_OFF, 0, 1000, 0200), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('E','x'), CHAR('t','.'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), + + ENDSECT + + /* SECTION 5. Circles and arcs. */ + + SGM(GM_APOINT, IN_4, LP_ENA, BL_ON, LT_SOLID), + APOINT(I_OFF, 0500, 01400), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, -0100, 0, 0, 0), + + SGM(GM_APOINT, IN_5, LP_SAME, BL_OFF, LT_SDASH), + APOINT(I_OFF, 0532, 01532), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, -0132, -0132, 0, -0264), + + SGM(GM_APOINT, IN_6, LP_SAME, BL_SAME, LT_LDASH), + APOINT(I_OFF, 0400, 01700), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, 0, -0300, 0, -0600), + + SGM(GM_APOINT, IN_7, LP_SAME, BL_SAME, LT_DDASH), + APOINT(I_OFF, 0114, 01664), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, 0264, -0264, 0, -0550), + + SGM(GM_APOINT, IN_4, LP_SAME, BL_SAME, LT_SOLID), + APOINT(I_OFF, 01400, 01400), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, 0, 0, 0400, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), + APOINT(I_OFF, 0500, 0400), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + ARC(I_ON, -0100, 0, 0200, 0), + + SGM(GM_APOINT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + APOINT(I_OFF, 01600, 0400), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + ARC(I_ON, -0200, 0, -0200, 0300), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_SDASH), + ARC(I_ON, 0, -0300, -0200, -0300), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_LDASH), + ARC(I_ON, 0200, 0, 0200, -0300), + SGM(GM_ARC, IN_SAME, LP_SAME, BL_SAME, LT_DDASH), + ARC(I_ON, 0, 0300, 0200, 0300), + + ENDSECT + + /* SECTION 6. Display subroutines, with and without parameter restore. */ + + /* XXX need test for subroutines */ + + /* SECTION 7. Offset, vector scale, and clipping. */ + + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_NORMAL, RF_UNSYNC, MN_MAIN), + LSRC(RO_HORIZONTAL, CS_CHANGE, 1, VS_CHANGE, 4), + + SGM(GM_APOINT, IN_3, LP_ENA, BL_OFF, LT_SOLID), + OFFSET(0, 0), + APOINT(I_ON, 01040, 01040), + APOINT(I_ON, 01040, 0740), + APOINT(I_ON, 0740, 01040), + APOINT(I_ON, 0740, 0740), + + SGM(GM_APOINT, IN_5, LP_SAME, BL_ON, LT_SAME), + OFFSET(06, 010), + APOINT(I_ON, 01040, 01040), + APOINT(I_ON, 01040, 0740), + APOINT(I_ON, 0740, 01040), + APOINT(I_ON, 0740, 0740), + + OFFSET(014, 020), + LSRC(RO_HORIZONTAL, CS_SAME, 0, VS_CHANGE, 8), + SGM(GM_APOINT, IN_7, LP_ENA, BL_SAME, LT_SAME), + APOINT(I_ON, 0420, 0420), + SGM(GM_RPOINT, IN_7, LP_SAME, BL_SAME, LT_SAME), + RPOINT(I_ON, 0, -040), + RPOINT(I_ON, -040, 040), + RPOINT(I_ON, 0, -040), + + /* XXX need test for clipping */ + + ENDSECT + + /* END OF TEST SECTIONS. */ + + ENDFILE +}; + +/* FILE WF. Rotating wire-frame display that works only for VS60. */ + +unsigned short WF[] = { + + /* SECTION 1. 3D data, with depth cueing enabled. */ + + LSRBB(ZD_YES, ED_ENA, DQ_ON, ES_NO), + LSRA(ST_SAME, SI_SAME, LI_BRIGHTDOWN, IT_SAME, RF_40, MN_MAIN), + + SGM(GM_APOINT, IN_4, LP_ENA, BL_OFF, LT_DDASH), + APOINT3(I_OFF, 0, 0, 0), /* cube coords filled in by wf_update() */ + + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_OFF, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + SGM(GM_AVECT, IN_SAME, LP_SAME, BL_SAME, LT_SOLID), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_OFF, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_OFF, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + AVECT3(I_OFF, 0, 0, 0), + AVECT3(I_ON, 0, 0, 0), + + LSRA(ST_SAME, SI_SAME, LI_SAME, IT_SAME, RF_SAME, MN_MENU), + SGM(GM_APOINT, IN_7, LP_ENA, BL_OFF, LT_SAME), + APOINT3(I_OFF, 0, 1000, 0200), + SGM(GM_CHAR, IN_SAME, LP_SAME, BL_SAME, LT_SAME), + CHAR('4','0'), CHAR('H','z'), CHAR(' ','S'), CHAR('y','n'), CHAR('c',0), + + ENDSECT + + /* END OF TEST SECTIONS. */ + + ENDFILE +}; + +static unsigned short *df; /* -> start of current display file */ +static uint16 start; /* initial DPC for section of d.file */ +static int more; /* set until end of d.file seen */ + +static void +wf_update(int first_time) { + double c, s; /* cosine, sine of rotation angle */ + int x, y, z; /* rotated coordinates */ + static int xc = 01000, yc = 01000, zc = 0; /* cube center coords */ + static int vp = 010000; /* distance to vanishing point */ + static struct { + int offset; /* WF[] offset (words) of vector data */ + int i; /* I_ON or I_OFF */ + int x, y, z; /* coords of cube corner point */ + } *dp, data[] = { + 3, I_OFF, 00400, 00400, 0400, + 7, I_ON, 01400, 00400, 0400, + 10, I_ON, 01400, 01400, 0400, + 13, I_ON, 00400, 01400, 0400, + 16, I_ON, 00400, 00400, 0400, + 19, I_OFF, 00400, 00400, -0400, + 22, I_ON, 01400, 00400, -0400, + 25, I_ON, 01400, 01400, -0400, + 28, I_ON, 00400, 01400, -0400, + 31, I_ON, 00400, 00400, -0400, + 35, I_ON, 00400, 00400, 0400, + 38, I_OFF, 01400, 00400, 0400, + 41, I_ON, 01400, 00400, -0400, + 44, I_OFF, 01400, 01400, -0400, + 47, I_ON, 01400, 01400, 0400, + 50, I_OFF, 00400, 01400, 0400, + 53, I_ON, 00400, 01400, -0400, + -1 /* end-of-data marker */ + }; + static double rot = 0.0; /* total amount of rotation, degrees */ + if (first_time) { + /* tilt cube toward viewer */ + c = cos(30.0 * 3.14159/180.0); + s = sin(30.0 * 3.14159/180.0); + for (dp = data; dp->offset >= 0; ++dp) { + z = zc + ((dp->z - zc) * c + (dp->y - yc) * s); + y = yc + ((dp->y - yc) * c - (dp->z - zc) * s); + WF[dp->offset ] = dp->i | (SGN_(dp->x) << 13) | MAG_(dp->x); + WF[dp->offset + 1] = (SGN_(y) << 13) | MAG_(y); + WF[dp->offset + 2] = (SGN_(z) << 13) | (MAG_(z) << 2); + /* X coord. unchanged because rotation is parallel to X axis */ + dp->y = y; + dp->z = z; + } + } else + if ((rot += 1.0) >= 360.0) /* rotation increment */ + rot -= 360.0; + c = cos(rot * 3.14159/180.0); + s = sin(rot * 3.14159/180.0); + for (dp = data; dp->offset >= 0; ++dp) { + x = xc + ((dp->x - xc) * c + (dp->z - zc) * s); + z = zc + ((dp->z - zc) * c - (dp->x - xc) * s); + /* apply (approximate) perspective */ + x = x * (1.0 + (double)z / vp ); + y = dp->y * (1.0 + (double)z / vp ); + WF[dp->offset ] = dp->i | (SGN_(x) << 13) | MAG_(x); + WF[dp->offset + 1] = (SGN_(y) << 13) | MAG_(y); + WF[dp->offset + 2] = (SGN_(z) << 13) | (MAG_(z) << 2); + } +} + +int +main(void) { + int c; + + vt11_display = TEST_DIS; + vt11_scale = TEST_RES; + + /* VT11/VS60 tests */ + + puts("initial tests work for both VT11 and VS60"); + for (df = VT, start = 0, more = 1; more; ) { + vt11_reset(); /* reset everything */ + vt11_set_dpc(start); /* start section */ + c = 0; + while (vt11_cycle(USEC, 1)) { + display_sync(); /* XXX push down? */ + if (display_lp_sw) /* tip switch activated */ + c = 1; /* flag: break requested */ + if (c && !display_lp_sw) /* wait for switch release */ + break; + } + /* end of section */ + } + /* end of display file */ + + /* light pen tracking */ + + ws_beep(); + puts("move the light pen through the tracking object"); + fflush(stdout); + for (df = LP, start = 0, more = 1; more; ) { + vt11_reset(); /* reset everything */ + vt11_set_dpc(start); /* start section */ + c = 0; + while (vt11_cycle(USEC, 1)) { + display_sync(); /* XXX push down? */ + if (display_lp_sw) /* tip switch activated */ + c = 1; /* flag: break requested */ + if (c && !display_lp_sw) /* wait for switch release */ + break; + /* [dynamic modifications to the display file can be done here] */ + } + /* end of section */ + } + /* end of display file */ + + /* VS60 tests */ + + ws_beep(); + puts("following tests require VS60"); + for (df = VS, start = 0, more = 1; more; ) { + vt11_reset(); /* reset everything */ + vt11_set_str((uint16)(0200 | '~')); /* set terminating char. */ + vt11_set_anr((uint16)(040000 | (2<<12) | 04000 | 01234)); + /* set associative name 0123x */ + vt11_set_dpc(start); /* start section */ + c = 0; + while (vt11_cycle(USEC, 1)) { + display_sync(); /* XXX push down? */ + if (display_lp_sw) /* tip switch activated */ + c = 1; /* flag: break requested */ + if (c && !display_lp_sw) /* wait for switch release */ + break; + } + /* end of section */ + } + /* end of display file */ + + /* VS60 rotating wire-frame display */ + + puts("press and release tip switch (button 1) for next display"); + fflush(stdout); + wf_update(1); /* do first-time init */ + for (df = WF, start = 0, more = 1; more; ) { + vt11_reset(); /* reset everything */ + vt11_set_dpc(start); /* start section */ + c = 0; + while (vt11_cycle(USEC, 1)) { + display_sync(); /* XXX push down? */ + if (display_lp_sw) /* tip switch activated */ + c = 1; /* flag: break requested */ + if (c && !display_lp_sw) /* wait for switch release */ + break; + } + /* end of section */ + } + /* end of display file */ + + /* XXX would be nice to have an example of animation */ + + return 0; +} + +/* + * callbacks from display.c + */ +unsigned long +cpu_get_switches(void) { + return 0; +} + +void +cpu_set_switches(unsigned long bits) { +} + +/* + * callbacks from vt11.c + */ + +int +vt_fetch(uint32 addr, vt11word *w) { + *w = df[addr/2]; + return 0; +} + +void +vt_stop_intr(void) { + uint16 dpc = vt11_get_dpc(); /* -> just after DSTOP instruction */ + if (df[dpc/2] == 0) { /* ENDSECT */ +#ifdef FRAME1STOP + int c; + puts("end of pass through this test pattern; display frozen"); + puts("enter newline to refresh this section or EOF to quit"); + fflush(stdout); + while ((c = getchar()) != '\n') + if (c == EOF) + exit(0); /* user aborted test */ +#endif + if (df == WF) { + wf_update(0); + vt11_set_dpc(0); /* restart modified display */ + start = dpc + 2; /* save start of next section */ + } else { + df[dpc/2 - 1] = JMPA; + df[dpc/2] = start; + start = dpc + 2; /* save start of next section */ + vt11_set_dpc(dpc - 2); /* reset; then JMPA to old start */ + puts("press and release tip switch (button 1) for next display"); + fflush(stdout); + } + } else /* ENDFILE */ + more = 0; +} + +void +vt_lpen_intr(void) { + if (df == LP) { + int dx = (int)(vt11_get_xpr() & 01777) - 01000; + int dy = (int)(vt11_get_ypr() & 01777) - 01000; + if (dx < 0) + dx = (-dx) | 020000; /* negative */ + if (dy < 0) + dy = (-dy) | 020000; /* negative */ + + df[4] = dx | I_ON; /* visible */ + df[5] = dy; + } else { + printf("VT11 lightpen interrupt (0%o,0%o)\n", + (unsigned)vt11_get_xpr() & 01777, + (unsigned)vt11_get_ypr() & 01777); + fflush(stdout); + } + vt11_set_dpc((uint16)1); /* resume */ +} + +void +vt_char_intr(void) { + puts("VT11 illegal character/timeout interrupt"); + fflush(stdout); + vt11_set_dpc((uint16)1); /* resume */ +} + +void +vt_name_intr(void) { + puts("VS60 name-match interrupt"); + fflush(stdout); + vt11_set_dpc((uint16)1); /* resume */ +} + diff --git a/display/win32.c b/display/win32.c index 3eb26802..670d6ecb 100644 --- a/display/win32.c +++ b/display/win32.c @@ -1,418 +1,418 @@ -/* - * $Id: win32.c,v 1.38 2004/02/07 06:32:01 phil Exp $ - * Win32 support for XY display simulator - * Phil Budne - * September 2003 - * Revised by Douglas A. Gwyn, 05 Feb. 2004 - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -/* use a thread to handle windows messages; */ -#define THREADS - -/* - * BUGS: - * Does not allow you to close display window; - * would need to tear down both system, and system independent data. - * - * now tries to handle PAINT message, as yet untested!! - */ - -#include -#include -#include -#include "ws.h" -#include "display.h" - -#ifndef PIX_SIZE -#define PIX_SIZE 1 -#endif - -#define APP_CLASS "XYAppClass" -#define APP_MENU "XYAppMenu" /* ?? */ - -/* - * light pen location - * see ws.h for full description - */ -int ws_lp_x = -1; -int ws_lp_y = -1; - -static HWND static_wh; -static HINSTANCE static_inst; -static int xpixels, ypixels; -static char *window_name; -static HBRUSH white_brush; -static HBRUSH black_brush; -#ifdef SWITCH_CURSORS -static HCURSOR cross, arrow; -#endif - -static __inline int -map_key(int k) -{ - switch (k) { - case 186: return ';'; /* VK_OEM_1? */ - case 222: return '\''; /* VK_OEM_7? */ - } - return k; -} - -static void -keydown(int k) -{ - display_keydown(map_key(k)); -} - -static void -keyup(int k) -{ - display_keyup(map_key(k)); -} - -/* - * here on any button click, or if mouse dragged while a button down - */ -static void -mousepos(DWORD lp) -{ - int x, y; - - x = LOWORD(lp); - y = HIWORD(lp); - - /* convert to display coordinates */ -#if PIX_SIZE > 1 - x /= PIX_SIZE; - y /= PIX_SIZE; -#endif - y = ypixels - 1 - y; - - /* if window has been stretched, can get out of range bits!! */ - if (x >= 0 && x < xpixels && y >= 0 && y < ypixels) { - /* checked by display_add_point() */ - ws_lp_x = x; - ws_lp_y = y; - } -} - -/* thoingggg!! "message for you sir!!!" */ -static LRESULT CALLBACK -patsy(HWND wh, UINT msg, WPARAM wp, LPARAM lp) /* "WndProc" */ -{ - /* printf("msg %d\n", msg); */ - switch (msg) { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_MOUSEMOVE: - if (wp & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) { -#ifdef SWITCH_CURSORS - if (ws_lp_x == -1 && !display_tablet) - SetCursor(cross); -#endif - mousepos(lp); - } -#ifdef SWITCH_CURSORS - else if (ws_lp_x != -1 && !display_tablet) - SetCursor(arrow); -#endif - break; /* return?? */ - - case WM_LBUTTONDOWN: - display_lp_sw = 1; - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: -#ifdef SWITCH_CURSORS - if (!display_tablet) - SetCursor(cross); -#endif - mousepos(lp); - break; /* return?? */ - - case WM_LBUTTONUP: - display_lp_sw = 0; - case WM_MBUTTONUP: - case WM_RBUTTONUP: -#ifdef SWITCH_CURSORS - if (!display_tablet) - SetCursor(arrow); -#endif - ws_lp_x = ws_lp_y = -1; - break; /* return?? */ - - case WM_KEYDOWN: - keydown(wp); - break; - - case WM_KEYUP: - keyup(wp); - break; - - case WM_PAINT: - display_repaint(); - break; /* return?? */ - } - return DefWindowProc(wh, msg, wp, lp); -} - -int -ws_poll(int *valp, int maxus) -{ -#ifdef THREADS - /* msgthread handles window events; just delay simulator */ - if (maxus > 0) - Sleep((maxus+999)/1000); -#else - MSG msg; - DWORD start; - int maxms = (maxus + 999) / 1000; - - for (start = GetTickCount(); GetTickCount() - start < maxms; Sleep(1)) { - /* empty message queue without blocking */ - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -#endif - return 1; -} - -/* called from non-threaded main program */ -int -ws_loop(void (*func)(void *), void *arg) -{ - int val; - while (ws_poll(&val, 0)) - (*func)(arg); - return val; -} - -/* worker for display init */ -static void -ws_init2(void) { - WNDCLASS wc; - int h, w; - -#ifdef SWITCH_CURSORS - if (!display_tablet) { - arrow = LoadCursor(NULL, IDC_ARROW); - cross = LoadCursor(NULL, IDC_CROSS); - } -#endif - - black_brush = GetStockObject(BLACK_BRUSH); - white_brush = GetStockObject(WHITE_BRUSH); - - wc.lpszClassName = APP_CLASS; - wc.lpfnWndProc = patsy; - wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; - /* also CS_NOCLOSE? CS_SAVEBITS? */ - - wc.hInstance = static_inst = GetModuleHandleA(0); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); -#ifdef SWITCH_CURSORS - wc.hCursor = NULL; -#else - wc.hCursor = display_tablet ? NULL : LoadCursor(NULL, IDC_CROSS); -#endif - wc.hbrBackground = black_brush; - wc.lpszMenuName = APP_MENU; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - /* WNDCLASSEX/RegisterClassEx include hIconSm (small icon) */ - RegisterClass(&wc); - - /* - * WS_OVERLAPPEDWINDOW=> - * WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, - * WS_MINIMIZEBOX, WS_MAXIMIZEBOX - * - * WS_CHILD (no menu bar), WS_POPUP (mutually exclusive) - */ - - /* empirical crocks to get entire screen; */ - w = (xpixels*PIX_SIZE)+6; - h = (ypixels*PIX_SIZE)+32; - /* XXX -- above values work with XP; Phil had +10,+30 */ - - static_wh = CreateWindow(APP_CLASS, /* registered class name */ - window_name, /* window name */ - WS_OVERLAPPED, /* style */ - CW_USEDEFAULT, CW_USEDEFAULT, /* X,Y */ - w, h, - NULL, /* HWND hWndParent */ - NULL, /* HMENU hMenu */ - static_inst, /* application instance */ - NULL); /* lpParam */ - - ShowWindow(static_wh, SW_SHOW); - UpdateWindow(static_wh); -} - -#ifdef THREADS -static volatile int init_done; -static DWORD msgthread_id; - -static DWORD WINAPI -msgthread(LPVOID arg) -{ - MSG msg; - - ws_init2(); - - /* XXX use a mutex? */ - init_done = 1; - - while (GetMessage(&msg, NULL, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return msg.wParam; -} - -static void -ws_thread_init(void) -{ - HANDLE th = CreateThread(NULL, /* sec. attr. */ - 0, /* stack size */ - msgthread, - NULL, /* param */ - 0, /* flags */ - &msgthread_id); - CloseHandle(th); - - /* XXX use a mutex; don't wait forever!! */ - while (!init_done) - ; -} -#endif /* THREADS */ - -/* called from display layer on first display op */ -int -ws_init(char *name, int xp, int yp, int colors) -{ - xpixels = xp; - ypixels = yp; - window_name = name; - -#ifdef THREADS - ws_thread_init(); -#else - ws_init2(); -#endif - return 1; /* XXX return errors!! */ -} - -void * -ws_color_rgb(int r, int g, int b) -{ - /* XXX check for failure??? try GetNearestColor??? */ - return CreateSolidBrush(RGB(r/256, g/256, b/256)); -} - -void * -ws_color_black(void) -{ - return black_brush; -} - -void * -ws_color_white(void) -{ - return white_brush; -} - -void -ws_display_point(int x, int y, void *color) -{ - HDC dc; - RECT r; - HBRUSH brush = color; - - if (x > xpixels || y > ypixels) - return; - - y = ypixels - 1 - y; /* invert y, top left origin */ - - /* top left corner */ - r.left = x*PIX_SIZE; - r.top = y*PIX_SIZE; - - /* bottom right corner, non-inclusive */ - r.right = (x+1)*PIX_SIZE; - r.bottom = (y+1)*PIX_SIZE; - - if (brush == NULL) - brush = black_brush; - - dc = GetDC(static_wh); - FillRect(dc, &r, brush); - ReleaseDC(static_wh, dc); -} - -void -ws_sync(void) { - /* noop */ -} - -void -ws_beep(void) { -#if 0 - /* play SystemDefault sound; does not work over terminal service */ - MessageBeep(MB_OK); -#else - /* works over terminal service? Plays default sound/beep on Win9x/ME */ - Beep(440, 500); /* Hz, ms. */ -#endif -} - -unsigned long -os_elapsed(void) -{ - static int new; - unsigned long ret; - static DWORD t[2]; - - /* - * only returns milliseconds, but Sleep() - * only takes milliseconds. - * - * wraps after 49.7 days of uptime. - * DWORD is an unsigned long, so this should be OK - */ - t[new] = GetTickCount(); - if (t[!new] == 0) - ret = ~0L; /* +INF */ - else - ret = (t[new] - t[!new]) * 1000; - new = !new; /* Ecclesiastes III */ - return ret; -} +/* + * $Id: win32.c,v 1.39 2005/01/14 18:58:03 phil Exp $ + * Win32 support for XY display simulator + * Phil Budne + * September 2003 + * Revised by Douglas A. Gwyn, 05 Feb. 2004 + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +/* use a thread to handle windows messages; */ +#define THREADS + +/* + * BUGS: + * Does not allow you to close display window; + * would need to tear down both system, and system independent data. + * + * now tries to handle PAINT message, as yet untested!! + */ + +#include +#include +#include +#include "ws.h" +#include "xy.h" + +#ifndef PIX_SIZE +#define PIX_SIZE 1 +#endif + +#define APP_CLASS "XYAppClass" +#define APP_MENU "XYAppMenu" /* ?? */ + +/* + * light pen location + * see ws.h for full description + */ +int ws_lp_x = -1; +int ws_lp_y = -1; + +static HWND static_wh; +static HINSTANCE static_inst; +static int xpixels, ypixels; +static char *window_name; +static HBRUSH white_brush; +static HBRUSH black_brush; +#ifdef SWITCH_CURSORS +static HCURSOR cross, arrow; +#endif + +static __inline int +map_key(int k) +{ + switch (k) { + case 186: return ';'; /* VK_OEM_1? */ + case 222: return '\''; /* VK_OEM_7? */ + } + return k; +} + +static void +keydown(int k) +{ + display_keydown(map_key(k)); +} + +static void +keyup(int k) +{ + display_keyup(map_key(k)); +} + +/* + * here on any button click, or if mouse dragged while a button down + */ +static void +mousepos(DWORD lp) +{ + int x, y; + + x = LOWORD(lp); + y = HIWORD(lp); + + /* convert to display coordinates */ +#if PIX_SIZE > 1 + x /= PIX_SIZE; + y /= PIX_SIZE; +#endif + y = ypixels - 1 - y; + + /* if window has been stretched, can get out of range bits!! */ + if (x >= 0 && x < xpixels && y >= 0 && y < ypixels) { + /* checked by display_add_point() */ + ws_lp_x = x; + ws_lp_y = y; + } +} + +/* thoingggg!! "message for you sir!!!" */ +static LRESULT CALLBACK +patsy(HWND wh, UINT msg, WPARAM wp, LPARAM lp) /* "WndProc" */ +{ + /* printf("msg %d\n", msg); */ + switch (msg) { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_MOUSEMOVE: + if (wp & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) { +#ifdef SWITCH_CURSORS + if (ws_lp_x == -1 && !display_tablet) + SetCursor(cross); +#endif + mousepos(lp); + } +#ifdef SWITCH_CURSORS + else if (ws_lp_x != -1 && !display_tablet) + SetCursor(arrow); +#endif + break; /* return?? */ + + case WM_LBUTTONDOWN: + display_lp_sw = 1; + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: +#ifdef SWITCH_CURSORS + if (!display_tablet) + SetCursor(cross); +#endif + mousepos(lp); + break; /* return?? */ + + case WM_LBUTTONUP: + display_lp_sw = 0; + case WM_MBUTTONUP: + case WM_RBUTTONUP: +#ifdef SWITCH_CURSORS + if (!display_tablet) + SetCursor(arrow); +#endif + ws_lp_x = ws_lp_y = -1; + break; /* return?? */ + + case WM_KEYDOWN: + keydown(wp); + break; + + case WM_KEYUP: + keyup(wp); + break; + + case WM_PAINT: + display_repaint(); + break; /* return?? */ + } + return DefWindowProc(wh, msg, wp, lp); +} + +int +ws_poll(int *valp, int maxus) +{ +#ifdef THREADS + /* msgthread handles window events; just delay simulator */ + if (maxus > 0) + Sleep((maxus+999)/1000); +#else + MSG msg; + DWORD start; + int maxms = (maxus + 999) / 1000; + + for (start = GetTickCount(); GetTickCount() - start < maxms; Sleep(1)) { + /* empty message queue without blocking */ + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +#endif + return 1; +} + +/* called from non-threaded main program */ +int +ws_loop(void (*func)(void *), void *arg) +{ + int val; + while (ws_poll(&val, 0)) + (*func)(arg); + return val; +} + +/* worker for display init */ +static void +ws_init2(void) { + WNDCLASS wc; + int h, w; + +#ifdef SWITCH_CURSORS + if (!display_tablet) { + arrow = LoadCursor(NULL, IDC_ARROW); + cross = LoadCursor(NULL, IDC_CROSS); + } +#endif + + black_brush = GetStockObject(BLACK_BRUSH); + white_brush = GetStockObject(WHITE_BRUSH); + + wc.lpszClassName = APP_CLASS; + wc.lpfnWndProc = patsy; + wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + /* also CS_NOCLOSE? CS_SAVEBITS? */ + + wc.hInstance = static_inst = GetModuleHandleA(0); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); +#ifdef SWITCH_CURSORS + wc.hCursor = NULL; +#else + wc.hCursor = display_tablet ? NULL : LoadCursor(NULL, IDC_CROSS); +#endif + wc.hbrBackground = black_brush; + wc.lpszMenuName = APP_MENU; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + /* WNDCLASSEX/RegisterClassEx include hIconSm (small icon) */ + RegisterClass(&wc); + + /* + * WS_OVERLAPPEDWINDOW=> + * WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, + * WS_MINIMIZEBOX, WS_MAXIMIZEBOX + * + * WS_CHILD (no menu bar), WS_POPUP (mutually exclusive) + */ + + /* empirical crocks to get entire screen; */ + w = (xpixels*PIX_SIZE)+6; + h = (ypixels*PIX_SIZE)+32; + /* XXX -- above values work with XP; Phil had +10,+30 */ + + static_wh = CreateWindow(APP_CLASS, /* registered class name */ + window_name, /* window name */ + WS_OVERLAPPED, /* style */ + CW_USEDEFAULT, CW_USEDEFAULT, /* X,Y */ + w, h, + NULL, /* HWND hWndParent */ + NULL, /* HMENU hMenu */ + static_inst, /* application instance */ + NULL); /* lpParam */ + + ShowWindow(static_wh, SW_SHOW); + UpdateWindow(static_wh); +} + +#ifdef THREADS +static volatile int init_done; +static DWORD msgthread_id; + +static DWORD WINAPI +msgthread(LPVOID arg) +{ + MSG msg; + + ws_init2(); + + /* XXX use a mutex? */ + init_done = 1; + + while (GetMessage(&msg, NULL, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +static void +ws_thread_init(void) +{ + HANDLE th = CreateThread(NULL, /* sec. attr. */ + 0, /* stack size */ + msgthread, + NULL, /* param */ + 0, /* flags */ + &msgthread_id); + CloseHandle(th); + + /* XXX use a mutex; don't wait forever!! */ + while (!init_done) + Sleep(200); +} +#endif /* THREADS */ + +/* called from display layer on first display op */ +int +ws_init(char *name, int xp, int yp, int colors) +{ + xpixels = xp; + ypixels = yp; + window_name = name; + +#ifdef THREADS + ws_thread_init(); +#else + ws_init2(); +#endif + return 1; /* XXX return errors!! */ +} + +void * +ws_color_rgb(int r, int g, int b) +{ + /* XXX check for failure??? try GetNearestColor??? */ + return CreateSolidBrush(RGB(r/256, g/256, b/256)); +} + +void * +ws_color_black(void) +{ + return black_brush; +} + +void * +ws_color_white(void) +{ + return white_brush; +} + +void +ws_display_point(int x, int y, void *color) +{ + HDC dc; + RECT r; + HBRUSH brush = color; + + if (x > xpixels || y > ypixels) + return; + + y = ypixels - 1 - y; /* invert y, top left origin */ + + /* top left corner */ + r.left = x*PIX_SIZE; + r.top = y*PIX_SIZE; + + /* bottom right corner, non-inclusive */ + r.right = (x+1)*PIX_SIZE; + r.bottom = (y+1)*PIX_SIZE; + + if (brush == NULL) + brush = black_brush; + + dc = GetDC(static_wh); + FillRect(dc, &r, brush); + ReleaseDC(static_wh, dc); +} + +void +ws_sync(void) { + /* noop */ +} + +void +ws_beep(void) { +#if 0 + /* play SystemDefault sound; does not work over terminal service */ + MessageBeep(MB_OK); +#else + /* works over terminal service? Plays default sound/beep on Win9x/ME */ + Beep(440, 500); /* Hz, ms. */ +#endif +} + +unsigned long +os_elapsed(void) +{ + static int new; + unsigned long ret; + static DWORD t[2]; + + /* + * only returns milliseconds, but Sleep() + * only takes milliseconds. + * + * wraps after 49.7 days of uptime. + * DWORD is an unsigned long, so this should be OK + */ + t[new] = GetTickCount(); + if (t[!new] == 0) + ret = ~0L; /* +INF */ + else + ret = (t[new] - t[!new]) * 1000; + new = !new; /* Ecclesiastes III */ + return ret; +} diff --git a/display/ws.h b/display/ws.h index f27cdfa6..87d67869 100644 --- a/display/ws.h +++ b/display/ws.h @@ -1,66 +1,65 @@ -/* - * $Id: ws.h,v 1.17 2004/02/03 21:23:51 phil Exp $ - * Interfaces to window-system specific code for XY display simulation - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -/* unless you're writing a new driver, you shouldn't be looking here! */ - -extern int ws_init(char *, int, int, int); -extern void ws_close(void); // 2006-07-19 SAI -extern void *ws_color_rgb(int, int, int); -extern void *ws_color_black(void); -extern void *ws_color_white(void); -extern void ws_display_point(int, int, void *); -extern void ws_sync(void); -extern int ws_loop(void (*)(void *), void *); -extern int ws_poll(int *, int); -extern void ws_beep(void); - -/* entries into display.c from below: */ -extern void display_keyup(int); -extern void display_keydown(int); -extern void display_repaint(void); - -/* - * Globals set by O/S display level to SCALED location in display - * coordinate system in order to save an upcall on every mouse - * movement. - * - * *NOT* for consumption by clients of display.c; although display - * clients can now get the scaling factor, real displays only give you - * a light pen "hit" when the beam passes under the light pen. - */ - -extern int ws_lp_x, ws_lp_y; - -/* - * O/S services in theory independent of window system, - * but in (current) practice not! - */ -extern unsigned long os_elapsed(void); +/* + * $Id: ws.h,v 1.17 2004/02/03 21:23:51 phil Exp $ + * Interfaces to window-system specific code for XY display simulation + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +/* unless you're writing a new driver, you shouldn't be looking here! */ + +extern int ws_init(char *, int, int, int); +extern void *ws_color_rgb(int, int, int); +extern void *ws_color_black(void); +extern void *ws_color_white(void); +extern void ws_display_point(int, int, void *); +extern void ws_sync(void); +extern int ws_loop(void (*)(void *), void *); +extern int ws_poll(int *, int); +extern void ws_beep(void); + +/* entries into display.c from below: */ +extern void display_keyup(int); +extern void display_keydown(int); +extern void display_repaint(void); + +/* + * Globals set by O/S display level to SCALED location in display + * coordinate system in order to save an upcall on every mouse + * movement. + * + * *NOT* for consumption by clients of display.c; although display + * clients can now get the scaling factor, real displays only give you + * a light pen "hit" when the beam passes under the light pen. + */ + +extern int ws_lp_x, ws_lp_y; + +/* + * O/S services in theory independent of window system, + * but in (current) practice not! + */ +extern unsigned long os_elapsed(void); diff --git a/display/x11.c b/display/x11.c index e04709df..d68ad65f 100644 --- a/display/x11.c +++ b/display/x11.c @@ -1,512 +1,489 @@ -/* - * $Id: x11.c,v 1.29 2004/02/03 21:23:51 phil Exp $ - * X11 support for XY display simulator - * Phil Budne - * September 2003 - * - * Changes from Douglas A. Gwyn, Jan 8, 2004 - * - * started from PDP-8/E simulator (vc8e.c & kc8e.c); - * This PDP8 Emulator was written by Douglas W. Jones at the - * University of Iowa. It is distributed as freeware, of - * uncertain function and uncertain utility. - */ - -/* - * Copyright (c) 2003-2004, Philip L. Budne - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the names of the authors shall - * not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization - * from the authors. - */ - -#include -#include -#include -#include "ws.h" -#include "display.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef PIX_SIZE -#define PIX_SIZE 1 -#endif - -//#define FULL_SCREEN 1 -#define NO_CURSOR 1 -#define NO_BORDER 1 - -/* - * light pen location - * see ws.h for full description - */ -int ws_lp_x = -1; -int ws_lp_y = -1; - -static XtAppContext app_context; /* the topmost context for everything */ -static Display* dpy; /* its display */ -static int scr; /* its screen */ -static Colormap cmap; /* its colormap */ -static Widget crtshell; /* the X window shell */ -static Widget crt; /* the X window in which output will plot */ -static int xpixels, ypixels; -#ifdef FULL_SCREEN -/* occupy entire screen for vintage computer fan Sellam Ismail */ -static int xoffset, yoffset; -#endif - -static GC whiteGC; /* gc with white foreground */ -static GC blackGC; /* gc with black foreground */ -static int buttons = 0; /* tracks state of all buttons */ - -static int os_pollfd(int, int); /* forward */ - -/* here on any mouse button down, AND movement when any button down */ -static void -handle_button_press(w, d, e, b) - Widget w; - XtPointer d; - XEvent *e; - Boolean *b; -{ - int x, y; - - x = e->xbutton.x; - y = e->xbutton.y; -#ifdef FULL_SCREEN - x -= xoffset; - y -= yoffset; -#endif -#if PIX_SIZE > 1 - x *= PIX_SIZE; - y *= PIX_SIZE; -#endif - -#ifndef NO_CURSUR - if (!display_tablet) - /* crosshair cursor to indicate tip of active pen */ - XDefineCursor(dpy, XtWindow(crt), - (Cursor) XCreateFontCursor(dpy, XC_crosshair)); -#endif - - y = ypixels - y - 1; - /*printf("lightpen at %d,%d\n", x, y); fflush(stdout);*/ - ws_lp_x = x; - ws_lp_y = y; - - if (e->type == ButtonPress) { - buttons |= e->xbutton.button; - - if (e->xbutton.button == 1) { - display_lp_sw = 1; - /*printf("tip switch activated\n"); fflush(stdout);*/ - } - } - - if (b) - *b = TRUE; -} - -static void -handle_button_release(w, d, e, b) - Widget w; - XtPointer d; - XEvent *e; - Boolean *b; -{ - if ((buttons &= ~e->xbutton.button) == 0) { /* all buttons released */ -#ifndef NO_CURSOR - if (!display_tablet) - /* pencil cursor (close to a pen!) to indicate inactive pen posn */ - XDefineCursor(dpy, XtWindow(crt), - (Cursor) XCreateFontCursor(dpy, XC_pencil)); -#endif - - /* XXX change cursor back?? */ - ws_lp_x = ws_lp_y = -1; - } - - if (e->xbutton.button == 1) { - display_lp_sw = 0; - /*printf("tip switch deactivated\n"); fflush(stdout);*/ - } - - if (b) - *b = TRUE; -} - -static void -handle_key_press(w, d, e, b) - Widget w; - XtPointer d; - XEvent *e; - Boolean *b; -{ - int shift = (ShiftMask & e->xkey.state) != 0; - KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); - - /*printf("key %d down\n", key); fflush(stdout);*/ - if ((key & 0xff00) == 0) - display_keydown(key); - - if (b) - *b = TRUE; -} - -static void -handle_key_release(w, d, e, b) - Widget w; - XtPointer d; - XEvent *e; - Boolean *b; -{ - int shift = (ShiftMask & e->xkey.state) != 0; - KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); - - /*printf("key %d up\n", key); fflush(stdout);*/ - if ((key & 0xff00) == 0) - display_keyup(key); - - if (b) - *b = TRUE; -} - -static void -handle_exposure(w, d, e, b) - Widget w; - XtPointer d; - XEvent *e; - Boolean *b; -{ - display_repaint(); - - if (b) - *b = TRUE; -} - -int -ws_init(char *crtname, /* crt type name */ - int xp, int yp, /* screen size in pixels */ - int colors) /* colors to support (not used) */ -{ - Arg arg[25]; - XGCValues gcvalues; - unsigned int n; - int argc; - char *argv[1]; - int height, width; - - xpixels = xp; /* save screen size */ - ypixels = yp; - - XtToolkitInitialize(); - app_context = XtCreateApplicationContext(); - argc = 0; - argv[0] = NULL; - dpy = XtOpenDisplay( app_context, NULL, NULL, crtname, NULL, 0, - &argc, argv); - - scr = DefaultScreen(dpy); - - crtshell = XtAppCreateShell( crtname, /* app name */ - crtname, /* app class */ - #ifdef NO_BORDER - overrideShellWidgetClass, - #else - applicationShellWidgetClass, /* wclass */ - #endif - dpy, /* display */ - NULL, /* arglist */ - 0); /* nargs */ - - cmap = DefaultColormap(dpy, scr); - - /* - * Create a drawing area - */ - - n = 0; -#ifdef FULL_SCREEN - /* center raster in full-screen black window */ - width = DisplayWidth(dpy,scr); - height = DisplayHeight(dpy,scr); - - xoffset = (width - xpixels*PIX_SIZE)/2; - yoffset = (height - ypixels*PIX_SIZE)/2; -#else - width = xpixels*PIX_SIZE; - height = ypixels*PIX_SIZE; -#endif - XtSetArg(arg[n], XtNwidth, width); n++; - XtSetArg(arg[n], XtNheight, height); n++; - XtSetArg(arg[n], XtNbackground, BlackPixel( dpy, scr )); n++; - - crt = XtCreateWidget( crtname, widgetClass, crtshell, arg, n); - XtManageChild(crt); - XtPopup(crtshell, XtGrabNonexclusive); - - /* - * Create black and white Graphics Contexts - */ - - gcvalues.foreground = BlackPixel( dpy, scr ); - gcvalues.background = BlackPixel( dpy, scr ); - blackGC = XCreateGC(dpy, XtWindow(crt), - GCForeground | GCBackground, &gcvalues); - - gcvalues.foreground = WhitePixel( dpy, scr ); - whiteGC = XCreateGC(dpy, XtWindow(crt), - GCForeground | GCBackground, &gcvalues); - -#ifndef NO_CURSOR - if (!display_tablet) { - /* pencil cursor */ - XDefineCursor(dpy, XtWindow(crt), - (Cursor) XCreateFontCursor(dpy, XC_pencil)); - } -#endif - - /* - * Setup to handle events - */ - - XtAddEventHandler(crt, ButtonPressMask|ButtonMotionMask, FALSE, - handle_button_press, NULL); - XtAddEventHandler(crt, ButtonReleaseMask, FALSE, - handle_button_release, NULL); - XtAddEventHandler(crt, KeyPressMask, FALSE, - handle_key_press, NULL); - XtAddEventHandler(crt, KeyReleaseMask, FALSE, - handle_key_release, NULL); - XtAddEventHandler(crt, ExposureMask, FALSE, - handle_exposure, NULL); - return 1; -} /* ws_init */ - - -/* Added 2006-07-19 SAI */ - -void ws_close(void) -{ - - XtCloseDisplay(dpy); - -} - - -void * -ws_color_black(void) -{ - return blackGC; -} - -void * -ws_color_white(void) -{ - return whiteGC; -} - -void * -ws_color_rgb(int r, int g, int b) -{ - XColor color; - - color.red = r; - color.green = g; - color.blue = b; - /* ignores flags */ - - if (XAllocColor(dpy, cmap, &color)) { - XGCValues gcvalues; - memset(&gcvalues, 0, sizeof(gcvalues)); - gcvalues.foreground = gcvalues.background = color.pixel; - return XCreateGC(dpy, XtWindow(crt), - GCForeground | GCBackground, - &gcvalues); - } - /* allocation failed */ - return NULL; -} - -/* put a point on the screen */ -void -ws_display_point(int x, int y, void *color) -{ - GC gc = (GC) color; - - if (x > xpixels || y > ypixels) - return; - - y = ypixels - y - 1; /* X11 coordinate system */ - -#ifdef FULL_SCREEN - x += xoffset; - y += yoffset; -#endif - if (gc == NULL) - gc = blackGC; /* default to off */ -#if PIX_SIZE == 1 - XDrawPoint(dpy, XtWindow(crt), gc, x, y); -#else - XFillRectangle(dpy, XtWindow(crt), gc, - x*PIX_SIZE, y*PIX_SIZE, PIX_SIZE, PIX_SIZE); -#endif -} - -void -ws_sync(void) -{ - XFlush(dpy); -} - -/* - * elapsed wall clock time since last call - * +INF on first call - */ - -struct elapsed_state { - struct timeval tvs[2]; - int new; -}; - -static unsigned long -elapsed(struct elapsed_state *ep) -{ - unsigned long val; - - gettimeofday(&ep->tvs[ep->new], NULL); - if (ep->tvs[!ep->new].tv_sec == 0) - val = ~0L; - else - val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 + - (ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec)); - ep->new = !ep->new; - return val; -} - -/* called periodically */ -int -ws_poll(int *valp, int maxusec) -{ - static struct elapsed_state es; /* static to avoid clearing! */ - -#ifdef WS_POLL_DEBUG - printf("ws_poll %d\n", maxusec); - fflush(stdout); -#endif - elapsed(&es); /* start clock */ - do { - unsigned long e; - - /* tried checking return, but lost on TCP connections? */ - os_pollfd(ConnectionNumber(dpy), maxusec); - - while (XtAppPending(app_context)) { - XEvent event; - - /* XXX check for connection loss; set *valp? return 0 */ - XtAppNextEvent(app_context, &event ); - XtDispatchEvent( &event ); - } - e = elapsed(&es); -#ifdef WS_POLL_DEBUG - printf(" maxusec %d e %d\r\n", maxusec, e); - fflush(stdout); -#endif - maxusec -= e; - } while (maxusec > 10000); /* 10ms */ - return 1; -} - -/* utility: can be called from main program - * which is willing to cede control - */ -int -ws_loop(void (*func)(void *), void *arg) -{ - int val; - - /* XXX use XtAppAddWorkProc & XtAppMainLoop? */ - while (ws_poll(&val,0)) - (*func)(arg); - return val; -} - -void -ws_beep(void) -{ - XBell(dpy, 0); /* ring at base volume */ - XFlush(dpy); -} - -/**************** - * could move these to unix.c, if VMS versions needed - * (or just (GASP!) ifdef) - */ - -/* public version, used by delay code */ -unsigned long -os_elapsed(void) -{ - static struct elapsed_state es; - return elapsed(&es); -} - -/* - * select/DisplayNumber works on VMS 7.0+? - * could move to "unix.c" - * (I have some nasty VMS code that's supposed to to the job - * for older systems) - */ - -/* - * sleep for maxus microseconds, returning TRUE sooner if fd is readable - * used by X11 driver - */ -static int -os_pollfd(int fd, int maxus) -{ - - /* use trusty old select (most portable) */ - fd_set rfds; - struct timeval tv; - - if (maxus >= 1000000) { /* not bloody likely, avoid divide */ - tv.tv_sec = maxus / 1000000; - tv.tv_usec = maxus % 1000000; - } - else { - tv.tv_sec = 0; - tv.tv_usec = maxus; - } - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - return select(fd+1, &rfds, NULL, NULL, &tv) > 0; -} +/* + * $Id: x11.c,v 1.32 2005/01/14 18:58:03 phil Exp $ + * X11 support for XY display simulator + * Phil Budne + * September 2003 + * + * Changes from Douglas A. Gwyn, Jan 8, 2004 + * + * started from PDP-8/E simulator (vc8e.c & kc8e.c); + * This PDP8 Emulator was written by Douglas W. Jones at the + * University of Iowa. It is distributed as freeware, of + * uncertain function and uncertain utility. + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#include +#include +#include +#include "ws.h" +#include "xy.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef PIX_SIZE +#define PIX_SIZE 1 +#endif + +/* + * light pen location + * see ws.h for full description + */ +int ws_lp_x = -1; +int ws_lp_y = -1; + +static XtAppContext app_context; /* the topmost context for everything */ +static Display* dpy; /* its display */ +static int scr; /* its screen */ +static Colormap cmap; /* its colormap */ +static Widget crtshell; /* the X window shell */ +static Widget crt; /* the X window in which output will plot */ +static int xpixels, ypixels; +#ifdef FULL_SCREEN +/* occupy entire screen for vintage computer fan Sellam Ismail */ +static int xoffset, yoffset; +#endif + +static GC whiteGC; /* gc with white foreground */ +static GC blackGC; /* gc with black foreground */ +static int buttons = 0; /* tracks state of all buttons */ + +static int os_pollfd(int, int); /* forward */ + +/* here on any mouse button down, AND movement when any button down */ +static void +handle_button_press(w, d, e, b) + Widget w; + XtPointer d; + XEvent *e; + Boolean *b; +{ + int x, y; + + x = e->xbutton.x; + y = e->xbutton.y; +#ifdef FULL_SCREEN + /* untested! */ + x -= xoffset; + y -= yoffset; +#endif +#if PIX_SIZE > 1 + x *= PIX_SIZE; + y *= PIX_SIZE; +#endif + + if (!display_tablet) + /* crosshair cursor to indicate tip of active pen */ + XDefineCursor(dpy, XtWindow(crt), + (Cursor) XCreateFontCursor(dpy, XC_crosshair)); + + y = ypixels - y - 1; + /*printf("lightpen at %d,%d\n", x, y); fflush(stdout);*/ + ws_lp_x = x; + ws_lp_y = y; + + if (e->type == ButtonPress) { + buttons |= e->xbutton.button; + + if (e->xbutton.button == 1) { + display_lp_sw = 1; + /*printf("tip switch activated\n"); fflush(stdout);*/ + } + } + + if (b) + *b = TRUE; +} + +static void +handle_button_release(w, d, e, b) + Widget w; + XtPointer d; + XEvent *e; + Boolean *b; +{ + if ((buttons &= ~e->xbutton.button) == 0) { /* all buttons released */ + if (!display_tablet) + /* pencil cursor (close to a pen!) to indicate inactive pen posn */ + XDefineCursor(dpy, XtWindow(crt), + (Cursor) XCreateFontCursor(dpy, XC_pencil)); + + /* XXX change cursor back?? */ + ws_lp_x = ws_lp_y = -1; + } + + if (e->xbutton.button == 1) { + display_lp_sw = 0; + /*printf("tip switch deactivated\n"); fflush(stdout);*/ + } + + if (b) + *b = TRUE; +} + +static void +handle_key_press(w, d, e, b) + Widget w; + XtPointer d; + XEvent *e; + Boolean *b; +{ + int shift = (ShiftMask & e->xkey.state) != 0; + KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); + + /*printf("key %d down\n", key); fflush(stdout);*/ + if ((key & 0xff00) == 0) + display_keydown(key); + + if (b) + *b = TRUE; +} + +static void +handle_key_release(w, d, e, b) + Widget w; + XtPointer d; + XEvent *e; + Boolean *b; +{ + int shift = (ShiftMask & e->xkey.state) != 0; + KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); + + /*printf("key %d up\n", key); fflush(stdout);*/ + if ((key & 0xff00) == 0) + display_keyup(key); + + if (b) + *b = TRUE; +} + +static void +handle_exposure(w, d, e, b) + Widget w; + XtPointer d; + XEvent *e; + Boolean *b; +{ + display_repaint(); + + if (b) + *b = TRUE; +} + +int +ws_init(char *crtname, /* crt type name */ + int xp, int yp, /* screen size in pixels */ + int colors) /* colors to support (not used) */ +{ + Arg arg[25]; + XGCValues gcvalues; + unsigned int n; + int argc; + char *argv[1]; + int height, width; + + xpixels = xp; /* save screen size */ + ypixels = yp; + + XtToolkitInitialize(); + app_context = XtCreateApplicationContext(); + argc = 0; + argv[0] = NULL; + dpy = XtOpenDisplay( app_context, NULL, NULL, crtname, NULL, 0, + &argc, argv); + + scr = DefaultScreen(dpy); + + crtshell = XtAppCreateShell( crtname, /* app name */ + crtname, /* app class */ + applicationShellWidgetClass, /* wclass */ + dpy, /* display */ + NULL, /* arglist */ + 0); /* nargs */ + + cmap = DefaultColormap(dpy, scr); + + /* + * Create a drawing area + */ + + n = 0; +#ifdef FULL_SCREEN + /* center raster in full-screen black window */ + width = DisplayWidth(dpy,scr); + height = DisplayHeight(dpy,scr); + + xoffset = (width - xpixels*PIX_SIZE)/2; + yoffset = (height - ypixels*PIX_SIZE)/2; +#else + width = xpixels*PIX_SIZE; + height = ypixels*PIX_SIZE; +#endif + XtSetArg(arg[n], XtNwidth, width); n++; + XtSetArg(arg[n], XtNheight, height); n++; + XtSetArg(arg[n], XtNbackground, BlackPixel( dpy, scr )); n++; + + crt = XtCreateWidget( crtname, widgetClass, crtshell, arg, n); + XtManageChild(crt); + XtPopup(crtshell, XtGrabNonexclusive); + XtSetKeyboardFocus(crtshell, crt); /* experimental? */ + + /* + * Create black and white Graphics Contexts + */ + + gcvalues.foreground = BlackPixel( dpy, scr ); + gcvalues.background = BlackPixel( dpy, scr ); + blackGC = XCreateGC(dpy, XtWindow(crt), + GCForeground | GCBackground, &gcvalues); + + gcvalues.foreground = WhitePixel( dpy, scr ); + whiteGC = XCreateGC(dpy, XtWindow(crt), + GCForeground | GCBackground, &gcvalues); + + if (!display_tablet) { + /* pencil cursor */ + XDefineCursor(dpy, XtWindow(crt), + (Cursor) XCreateFontCursor(dpy, XC_pencil)); + } + + /* + * Setup to handle events + */ + + XtAddEventHandler(crt, ButtonPressMask|ButtonMotionMask, FALSE, + handle_button_press, NULL); + XtAddEventHandler(crt, ButtonReleaseMask, FALSE, + handle_button_release, NULL); + XtAddEventHandler(crt, KeyPressMask, FALSE, + handle_key_press, NULL); + XtAddEventHandler(crt, KeyReleaseMask, FALSE, + handle_key_release, NULL); + XtAddEventHandler(crt, ExposureMask, FALSE, + handle_exposure, NULL); + return 1; +} /* ws_init */ + +void * +ws_color_black(void) +{ + return blackGC; +} + +void * +ws_color_white(void) +{ + return whiteGC; +} + +void * +ws_color_rgb(int r, int g, int b) +{ + XColor color; + + color.red = r; + color.green = g; + color.blue = b; + /* ignores flags */ + + if (XAllocColor(dpy, cmap, &color)) { + XGCValues gcvalues; + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.foreground = gcvalues.background = color.pixel; + return XCreateGC(dpy, XtWindow(crt), + GCForeground | GCBackground, + &gcvalues); + } + /* allocation failed */ + return NULL; +} + +/* put a point on the screen */ +void +ws_display_point(int x, int y, void *color) +{ + GC gc = (GC) color; + + if (x > xpixels || y > ypixels) + return; + + y = ypixels - y - 1; /* X11 coordinate system */ + +#ifdef FULL_SCREEN + x += xoffset; + y += yoffset; +#endif + if (gc == NULL) + gc = blackGC; /* default to off */ +#if PIX_SIZE == 1 + XDrawPoint(dpy, XtWindow(crt), gc, x, y); +#else + XFillRectangle(dpy, XtWindow(crt), gc, + x*PIX_SIZE, y*PIX_SIZE, PIX_SIZE, PIX_SIZE); +#endif +} + +void +ws_sync(void) +{ + XFlush(dpy); +} + +/* + * elapsed wall clock time since last call + * +INF on first call + */ + +struct elapsed_state { + struct timeval tvs[2]; + int new; +}; + +static unsigned long +elapsed(struct elapsed_state *ep) +{ + unsigned long val; + + gettimeofday(&ep->tvs[ep->new], NULL); + if (ep->tvs[!ep->new].tv_sec == 0) + val = ~0L; + else + val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 + + (ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec)); + ep->new = !ep->new; + return val; +} + +/* called periodically */ +int +ws_poll(int *valp, int maxusec) +{ + static struct elapsed_state es; /* static to avoid clearing! */ + +#ifdef WS_POLL_DEBUG + printf("ws_poll %d\n", maxusec); + fflush(stdout); +#endif + elapsed(&es); /* start clock */ + do { + unsigned long e; + + /* tried checking return, but lost on TCP connections? */ + os_pollfd(ConnectionNumber(dpy), maxusec); + + while (XtAppPending(app_context)) { + XEvent event; + + /* XXX check for connection loss; set *valp? return 0 */ + XtAppNextEvent(app_context, &event ); + XtDispatchEvent( &event ); + } + e = elapsed(&es); +#ifdef WS_POLL_DEBUG + printf(" maxusec %d e %d\r\n", maxusec, e); + fflush(stdout); +#endif + maxusec -= e; + } while (maxusec > 10000); /* 10ms */ + return 1; +} + +/* utility: can be called from main program + * which is willing to cede control + */ +int +ws_loop(void (*func)(void *), void *arg) +{ + int val; + + /* XXX use XtAppAddWorkProc & XtAppMainLoop? */ + while (ws_poll(&val,0)) + (*func)(arg); + return val; +} + +void +ws_beep(void) +{ + XBell(dpy, 0); /* ring at base volume */ + XFlush(dpy); +} + +/**************** + * could move these to unix.c, if VMS versions needed + * (or just (GASP!) ifdef) + */ + +/* public version, used by delay code */ +unsigned long +os_elapsed(void) +{ + static struct elapsed_state es; + return elapsed(&es); +} + +/* + * select/DisplayNumber works on VMS 7.0+? + * could move to "unix.c" + * (I have some nasty VMS code that's supposed to to the job + * for older systems) + */ + +/* + * sleep for maxus microseconds, returning TRUE sooner if fd is readable + * used by X11 driver + */ +static int +os_pollfd(int fd, int maxus) +{ + + /* use trusty old select (most portable) */ + fd_set rfds; + struct timeval tv; + + if (maxus >= 1000000) { /* not bloody likely, avoid divide */ + tv.tv_sec = maxus / 1000000; + tv.tv_usec = maxus % 1000000; + } + else { + tv.tv_sec = 0; + tv.tv_usec = maxus; + } + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + return select(fd+1, &rfds, NULL, NULL, &tv) > 0; +} diff --git a/display/xy.c b/display/xy.c new file mode 100644 index 00000000..79ccf271 --- /dev/null +++ b/display/xy.c @@ -0,0 +1,1036 @@ +/* + * $Id: xy.c,v 1.59 2005/01/14 18:58:04 phil Exp $ + * Simulator and host O/S independent XY display simulator + * Phil Budne + * September 2003 + * + * with changes by Douglas A. Gwyn, 21 Jan. 2004 + * + * started from PDP-8/E simulator vc8e.c; + * This PDP8 Emulator was written by Douglas W. Jones at the + * University of Iowa. It is distributed as freeware, of + * uncertain function and uncertain utility. + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +#include +#include +#include +#include /* for USHRT_MAX */ +#include "ws.h" +#include "xy.h" + +/* + * The user may select (at compile time) how big a window is used to + * emulate the display. Using smaller windows saves memory and screen space. + * + * Type 30 has 1024x1024 addressing, but only 512x512 visible points. + * VR14 has only 1024x768 visible points; VR17 has 1024x1024 visible points. + * VT11 supports 4096x4096 addressing, clipping to the lowest 1024x1024 region. + * VR48 has 1024x1024 visible points in the main display area and 128x1024 + * visible points in a menu area on the right-hand side (1152x1024 total). + * VT48 supports 8192x8192 (signed) main-area addressing, clipping to a + * 1024x1024 window which can be located anywhere within that region. + * (XXX -- That is what the VT11/VT48 manuals say; however, evidence suggests + * that the VT11 may actually support 8192x8192 (signed) addressing too.) + */ + +/* Define the default display type (if display_init() not called) */ +#ifndef DISPLAY_TYPE +#define DISPLAY_TYPE DIS_TYPE30 +#endif /* DISPLAY_TYPE not defined */ + +/* select a default resolution if display_init() not called */ +/* XXX keep in struct display? */ +#ifndef PIX_SCALE +#define PIX_SCALE RES_HALF +#endif /* PIX_SCALE not defined */ + +/* select a default light-pen hit radius if display_init() not called */ +#ifndef PEN_RADIUS +#define PEN_RADIUS 4 +#endif /* PEN_RADIUS not defined */ + +/* + * note: displays can have up to two different colors (eg VR20) + * each color can be made up of any number of phosphors + * with different colors and decay characteristics (eg Type 30) + */ + +#define ELEMENTS(X) (sizeof(X)/sizeof(X[0])) + +struct phosphor { + float red, green, blue; + float level; /* decay level (0.5 for half life) */ + float t_level; /* seconds to decay to level */ +}; + +struct color { + struct phosphor *phosphors; + int nphosphors; + int half_life; /* for refresh calc */ +}; + +struct display { + enum display_type type; + char *name; + struct color *color0, *color1; + short xpoints, ypoints; +}; + +/* + * P7 phosphor for type 30 (16ADP7(A?) CRT) + * original phosphor constants from Raphael Nabet's XMame 0.72.1 PDP-1 sim. + * fast blue (.05s half life), and slow green (.2s half life) + */ +static struct phosphor p7[] = { + {0.11, 0.11, 1.0, 0.5, 0.05}, /* fast blue */ + {1.0, 1.0, 0.11, 0.5, 0.20} /* slow yellow/green */ +}; +static struct color color_p7 = { p7, ELEMENTS(p7), 125000 }; + +/* green phosphor for VR14, VR17, VR20 */ +static struct phosphor p29[] = {{0.0260, 1.0, 0.00121, 0.5, 0.025}}; +struct color color_p29 = { p29, ELEMENTS(p29), 25000 }; + +static struct phosphor p40[] = { + /* P40 blue-white spot with yellow-green decay (.045s to 10%?) */ + {0.4, 0.2, 0.924, 0.5, 0.0135}, + {0.5, 0.7, 0.076, 0.5, 0.065} +}; +static struct color color_p40 = { p40, ELEMENTS(p40), 20000 }; + +/* "red" -- until real VR20 phosphor type/number/constants known */ +static struct phosphor pred[] = { {1.0, 0.37, 0.37, 0.5, 0.10} }; +static struct color color_red = { pred, ELEMENTS(pred), 100000 }; + +static struct display displays[] = { + /* + * Type 30 + * PDP-1/4/5/8/9/10 "Precision CRT" display system + * + * Raytheon 16ADP7A CRT? + * web searches for 16ADP7 finds useful information!! + * 16" tube, 14 3/8" square raster + * maximum dot size .015" + * 50us point plot time (20,000 points/sec) + * P7 Phosphor? Two phosphor layers: fast blue, slow yellow/green + * 360 lb + * 7A at 115+-10V 60Hz + */ + { DIS_TYPE30, "Type 30", &color_p7, NULL, 1024, 1024 }, + + /* + * VR14 + * used w/ GT40/44, AX08, VC8E + * + * Viewable area 6.75" x 9" + * 12" diagonal + * brightness >= 30 fL + * dot size .02" (20 mils) + * settle time: + * full screen 18us to +/-1 spot diameter + * .1" change 1us to +/-.5 spot diameter + * weight 75lb + */ + { DIS_VR14, "VR14", &color_p29, NULL, 1024, 768 }, + + /* + * VR17 + * used w/ GT40/44, AX08, VC8E + * + * Viewable area 9.25" x 9.25" + * 17" diagonal + * dot size .02" (20 mils) + * brightness >= 25 fL + * phosphor: P39 doped for IR light pen use + * light pen: Type 375 + * weight 85lb + */ + { DIS_VR17, "VR17", &color_p29, NULL, 1024, 1024 }, + + /* + * VR20 + * on VC8E + * Two colors!! + */ + { DIS_VR20, "VR20", &color_p29, &color_red, 1024, 1024 }, + + /* + * VR48 + * (on VT48 in VS60) + * from Douglas A. Gwyn 23 Nov. 2003 + * + * Viewable area 12" x 12", plus 1.5" x 12" menu area on right-hand side + * 21" diagonal + * dot size <= .01" (10 mils) + * brightness >= 31 fL + * phosphor: P40 (blue-white fluorescence with yellow-green phosphorescence) + * light pen: Type 377A (with tip switch) + * driving circuitry separate + * (normally under table on which CRT is mounted) + */ + { DIS_VR48, "VR48", &color_p40, NULL, 1024+VR48_GUTTER+128, 1024 }, + + /* + * Type 340 Display system + * on PDP-4/6/7/9/10 + * + * 1024x1024 + * 9 3/8" raster (.01" dot pitch) + * 0,0 at lower left + * 8 intensity levels + */ + { DIS_TYPE340, "Type 340", &color_p7, NULL, 1024, 1024 } +}; + +/* + * Unit time (in microseconds) used to store display point time to + * live at current aging level. If this is too small, delay values + * cannot fit in an unsigned short. If it is too large all pixels + * will age at once. Perhaps a suitable value should be calculated at + * run time? When display_init() calculates refresh_interval it + * sanity checks for both cases. + */ +#define DELAY_UNIT 250 + +/* levels to display in first half-life; determines refresh rate */ +#ifndef LEVELS_PER_HALFLIFE +#define LEVELS_PER_HALFLIFE 4 +#endif + +/* after 5 half lives (.5**5) remaining intensity is 3% of original */ +#ifndef HALF_LIVES_TO_DISPLAY +#define HALF_LIVES_TO_DISPLAY 5 +#endif + +/* + * refresh_rate is number of times per (simulated) second a pixel is + * aged to next lowest intensity level. + * + * refresh_rate = ((1e6*LEVELS_PER_HALFLIFE)/PHOSPHOR_HALF_LIFE) + * refresh_interval = 1e6/DELAY_UNIT/refresh_rate + * = PHOSPHOR_HALF_LIFE/LEVELS_PER_HALF_LIFE + * intensities = (HALF_LIVES_TO_DISPLAY*PHOSPHOR_HALF_LIFE)/refresh_interval + * = HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE + * + * See also comments on display_age() + * + * Try to keep LEVELS_PER_HALFLIFE*HALF_LIVES_TO_DISPLAY*NLEVELS <= 192 + * to run on 8-bit (256 color) displays! + */ + +/* + * number of aging periods to display a point for + */ +#define NTTL (HALF_LIVES_TO_DISPLAY*LEVELS_PER_HALFLIFE) + +/* + * maximum (initial) TTL for a point. + * TTL's are stored 1-based + * (a stored TTL of zero means the point is off) + */ +#define MAXTTL NTTL + +/* + * number of drawing intensity levels + */ +#define NLEVELS (DISPLAY_INT_MAX-DISPLAY_INT_MIN+1) + +#define MAXLEVEL (NLEVELS-1) + +/* + * Display Device Implementation + */ + +/* + * Each point on the display is represented by a "struct point". When + * a point isn't dark (intensity > 0), it is linked into a circular, + * doubly linked delta queue (a priority queue where "delay" + * represents the time difference from the previous entry (if any) in + * the queue. + * + * All points are aged refresh_rate times/second, each time moved to the + * next (logarithmically) lower intensity level. When display_age() is + * called, only the entries which have expired are processed. Calling + * display_age() often allows spreading out the workload. + * + * An alternative would be to have intensity levels represent linear + * decreases in intensity, and have the decay time at each level change. + * Inverting the decay function for a multi-component phosphor may be + * tricky, and the two different colors would need different time tables. + * Furthermore, it would require finding the correct location in the + * queue when adding a point (currently only need to add points at end) + */ + +/* + * 12 bytes/entry on 32-bit system when REFRESH_RATE > 15 + * (requires 3MB for 512x512 display). + */ + +typedef unsigned short delay_t; +#define DELAY_T_MAX USHRT_MAX + +struct point { + struct point *next; /* next entry in queue */ + struct point *prev; /* prev entry in queue */ + delay_t delay; /* delta T in DELAY_UNITs */ + unsigned char ttl; /* zero means off, not linked in */ + unsigned char level : 7; /* intensity level */ + unsigned char color : 1; /* for VR20 (two colors) */ +}; + +static struct point *points; /* allocated array of points */ +static struct point _head; +#define head (&_head) + +/* + * time span of all entries in queue + * should never exceed refresh_interval + * (should be possible to make this a delay_t) + */ +static long queue_interval; + +/* convert X,Y to a "struct point *" */ +#define P(X,Y) (points + (X) + ((Y)*(size_t)xpixels)) + +/* convert "struct point *" to X and Y */ +#define X(P) (((P) - points) % xpixels) +#define Y(P) (((P) - points) / xpixels) + +static int initialized = 0; + +/* + * global set by O/S display level to indicate "light pen tip switch activated" + * (This is used only by the VS60 emulation, also by vttest to change patterns) + */ +unsigned char display_lp_sw = 0; + +/* + * global set by DR11-C simulation when DR device enabled; deactivates + * light pen and instead reports mouse coordinates as Talos digitizer + * data via DR11-C + */ +unsigned char display_tablet = 0; + +/* + * can be changed with display_lp_radius() + */ +static long scaled_pen_radius_squared; + +/* run-time -- set by display_init() */ +static int xpoints, ypoints; +static int xpixels, ypixels; +static int refresh_rate; +static int refresh_interval; +static int ncolors; +static enum display_type display_type; +static int scale; + +/* + * relative brightness for each display level + * (all but last must be less than 1.0) + */ +static float level_scale[NLEVELS]; + +/* + * table of pointer to window system "colors" + * for painting each age level, intensity level and beam color + */ +void *colors[2][NLEVELS][NTTL]; + +void +display_lp_radius(int r) +{ + r /= scale; + scaled_pen_radius_squared = r * r; +} + +/* + * from display_age and display_point + * since all points age at the same rate, + * only adds points at end of list. + */ +static void +queue_point(struct point *p) +{ + int d; + + d = refresh_interval - queue_interval; + queue_interval += d; + /* queue_interval should now be == refresh_interval */ + +#ifdef PARANOIA + if (p->ttl == 0 || p->ttl > MAXTTL) + printf("queuing %d,%d level %d!\n", X(p), Y(p), p->level); + if (d > DELAY_T_MAX) + printf("queuing %d,%d delay %d!\n", X(p), Y(p), d); + if (queue_interval > DELAY_T_MAX) + printf("queue_interval (%d) > DELAY_T_MAX (%d)\n", + (int)queue_interval, DELAY_T_MAX); +#endif /* PARANOIA defined */ + + p->next = head; + p->prev = head->prev; + + head->prev->next = p; + head->prev = p; + + p->delay = d; +} + +/* + * here to to dynamically adjust interval for examination + * of elapsed vs. simulated time, and fritter away + * any extra wall-clock time without eating CPU + */ + +/* + * more parameters! + */ + +/* + * upper bound for elapsed time between elapsed time checks. + * if more than MAXELAPSED microseconds elapsed while simulating + * delay_check simulated microseconds, decrease delay_check. + */ +#define MAXELAPSED 100000 /* 10Hz */ + +/* + * lower bound for elapsed time between elapsed time checks. + * if fewer than MINELAPSED microseconds elapsed while simulating + * delay_check simulated microseconds, increase delay_check. + */ +#define MINELAPSED 50000 /* 20Hz */ + +/* + * upper bound for delay (sleep/poll). + * If difference between elapsed time and simulated time is + * larger than MAXDELAY microseconds, decrease delay_check. + * + * since delay is elapsed time - simulated time, MAXDELAY + * should be <= MAXELAPSED + */ +#ifndef MAXDELAY +#define MAXDELAY 100000 /* 100ms */ +#endif /* MAXDELAY not defined */ + +/* + * lower bound for delay (sleep/poll). + * If difference between elapsed time and simulated time is + * smaller than MINDELAY microseconds, increase delay_check. + * + * since delay is elapsed time - simulated time, MINDELAY + * should be <= MINELAPSED + */ +#ifndef MINDELAY +#define MINDELAY 50000 /* 50ms */ +#endif /* MINDELAY not defined */ + +/* + * Initial amount of simulated time to elapse before polling. + * Value is very low to ensure polling occurs on slow systems. + * Fast systems should ramp up quickly. + */ +#ifndef INITIAL_DELAY_CHECK +#define INITIAL_DELAY_CHECK 1000 /* 1ms */ +#endif /* INITIAL_DELAY_CHECK */ + +/* + * gain factor (2**-GAINSHIFT) for adjustment of adjustment + * of delay_check + */ +#ifndef GAINSHIFT +#define GAINSHIFT 3 /* gain=0.125 (12.5%) */ +#endif /* GAINSHIFT not defined */ + +static void +display_delay(int t, int slowdown) +{ + /* how often (in simulated us) to poll/check for delay */ + static unsigned long delay_check = INITIAL_DELAY_CHECK; + + /* accumulated simulated time */ + static unsigned long sim_time = 0; + unsigned long elapsed; + long delay; + + sim_time += t; + if (sim_time < delay_check) + return; + + elapsed = os_elapsed(); /* read and reset elapsed timer */ + if (elapsed == ~0L) { /* first time thru? */ + slowdown = 0; /* no adjustments */ + elapsed = sim_time; + } + + /* + * get delta between elapsed (real) time, and simulated time. + * if simulated time running faster, we need to slow things down (delay) + */ + if (slowdown) + delay = sim_time - elapsed; + else + delay = 0; /* just poll */ + +#ifdef DEBUG_DELAY2 + printf("sim %d elapsed %d delay %d\r\n", sim_time, elapsed, delay); +#endif + + /* + * Try to keep the elapsed (real world) time between checks for + * delay (and poll for window system events) bounded between + * MAXELAPSED and MINELAPSED. Also tries to keep + * delay/poll time bounded between MAXDELAY and MINDELAY -- large + * delays make the simulation spastic, while very small ones are + * inefficient (too many system calls) and tend to be inaccurate + * (operating systems have a certain granularity for time + * measurement, and when you try to sleep/poll for very short + * amounts of time, the noise will dominate). + * + * delay_check period may be adjusted often, and oscillate. There + * is no single "right value", the important things are to keep + * the delay time and max poll intervals bounded, and responsive + * to system load. + */ + if (elapsed > MAXELAPSED || delay > MAXDELAY) { + /* too much elapsed time passed, or delay too large; shrink interval */ + if (delay_check > 1) { + delay_check -= delay_check>>GAINSHIFT; +#ifdef DEBUG_DELAY + printf("reduced period to %d\r\n", delay_check); +#endif /* DEBUG_DELAY defined */ + } + } + else if (elapsed < MINELAPSED || slowdown && delay < MINDELAY) { + /* too little elapsed time passed, or delta very small */ + int gain = delay_check>>GAINSHIFT; + if (gain == 0) + gain = 1; /* make sure some change made! */ + delay_check += gain; +#ifdef DEBUG_DELAY + printf("increased period to %d\r\n", delay_check); +#endif /* DEBUG_DELAY defined */ + } + if (delay < 0) + delay = 0; + /* else if delay < MINDELAY, clamp at MINDELAY??? */ + + /* poll for window system events and/or delay */ + ws_poll(NULL, delay); + + sim_time = 0; /* reset simulated time clock */ + + /* + * delay (poll/sleep) time included in next "elapsed" period + * (clock not reset after a delay) + */ +} /* display_delay */ + +/* + * here periodically from simulator to age pixels. + * + * calling often with small values will age a few pixels at a time, + * and assist with graceful aging of display, and pixel aging. + * + * values should be smaller than refresh_interval! + * + * returns true if anything on screen changed. + */ + +int +display_age(int t, /* simulated us since last call */ + int slowdown) /* slowdown to simulated speed */ +{ + struct point *p; + static int elapsed = 0; + int changed; + + if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) + return 0; + + display_delay(t, slowdown); + + changed = 0; + + elapsed += t; + if (elapsed < DELAY_UNIT) + return 0; + + t = elapsed / DELAY_UNIT; + elapsed %= DELAY_UNIT; + + while ((p = head->next) != head) { + int x, y; + + /* look at oldest entry */ + if (p->delay > t) { /* further than our reach? */ + p->delay -= t; /* update head */ + queue_interval -= t; /* update span */ + break; /* quit */ + } + + x = X(p); + y = Y(p); +#ifdef PARANOIA + if (p->ttl == 0) + printf("BUG: age %d,%d ttl zero\n", x, y); +#endif /* PARANOIA defined */ + + /* dequeue point */ + p->prev->next = p->next; + p->next->prev = p->prev; + + t -= p->delay; /* lessen our reach */ + queue_interval -= p->delay; /* update queue span */ + + ws_display_point(x, y, colors[p->color][p->level][--p->ttl]); + changed = 1; + + /* queue it back up, unless we just turned it off! */ + if (p->ttl > 0) + queue_point(p); + } + return changed; +} /* display_age */ + +/* here from window system */ +void +display_repaint(void) { + struct point *p; + int x, y; + /* + * bottom to top, left to right. + */ + for (p = points, y = 0; y < ypixels; y++) + for (x = 0; x < xpixels; p++, x++) + if (p->ttl) + ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); + ws_sync(); +} + +/* (0,0) is lower left */ +static int +intensify(int x, /* 0..xpixels */ + int y, /* 0..ypixels */ + int level, /* 0..MAXLEVEL */ + int color) /* for VR20! 0 or 1 */ +{ + struct point *p; + int bleed; + + if (x < 0 || x >= xpixels || y < 0 || y >= ypixels) + return 0; /* limit to display */ + + p = P(x,y); + if (p->ttl) { /* currently lit? */ +#ifdef LOUD + printf("%d,%d old level %d ttl %d new %d\r\n", + x, y, p->level, p->ttl, level); +#endif /* LOUD defined */ + + /* unlink from delta queue */ + p->prev->next = p->next; + + if (p->next == head) + queue_interval -= p->delay; + else + p->next->delay += p->delay; + p->next->prev = p->prev; + } + + bleed = 0; /* no bleeding for now */ + + /* EXP: doesn't work... yet */ + /* if "recently" drawn, same or brighter, same color, make even brighter */ + if (p->ttl >= MAXTTL*2/3 && level >= p->level && p->color == color && + level < MAXLEVEL) + level++; + + /* + * this allows a dim beam to suck light out of + * a recently drawn bright spot!! + */ + if (p->ttl != MAXTTL || p->level != level || p->color != color) { + p->ttl = MAXTTL; + p->level = level; + p->color = color; /* save color even if monochrome */ + ws_display_point(x, y, colors[p->color][p->level][p->ttl-1]); + } + + queue_point(p); /* put at end of list */ + return bleed; +} + +int +display_point(int x, /* 0..xpixels (unscaled) */ + int y, /* 0..ypixels (unscaled) */ + int level, /* DISPLAY_INT_xxx */ + int color) /* for VR20! 0 or 1 */ +{ + long lx, ly; + + if (!initialized && !display_init(DISPLAY_TYPE, PIX_SCALE)) + return 0; + + /* scale x and y to the displayed number of pixels */ + /* handle common cases quickly */ + if (scale > 1) { + if (scale == 2) { + x >>= 1; + y >>= 1; + } + else { + x /= scale; + y /= scale; + } + } + +#if DISPLAY_INT_MIN > 0 + level -= DISPLAY_INT_MIN; /* make zero based */ +#endif + intensify(x, y, level, color); + /* no bleeding for now (used to recurse for neighbor points) */ + + if (ws_lp_x == -1 || ws_lp_y == -1) + return 0; + + lx = x - ws_lp_x; + ly = y - ws_lp_y; + return lx*lx + ly*ly <= scaled_pen_radius_squared; +} /* display_point */ + +/* + * calculate decay color table for a phosphor mixture + * must be called AFTER refresh_rate initialized! + */ +static void +phosphor_init(struct phosphor *phosphors, int nphosphors, int color) +{ + int ttl; + + /* for each display ttl level; newest to oldest */ + for (ttl = NTTL-1; ttl > 0; ttl--) { + struct phosphor *pp; + double rr, rg, rb; /* real values */ + + /* fractional seconds */ + double t = ((double)(NTTL-1-ttl))/refresh_rate; + + int ilevel; /* intensity levels */ + int p; + + /* sum over all phosphors in mixture */ + rr = rg = rb = 0.0; + for (pp = phosphors, p = 0; p < nphosphors; pp++, p++) { + double decay = pow(pp->level, t/pp->t_level); + rr += decay * pp->red; + rg += decay * pp->green; + rb += decay * pp->blue; + } + + /* scale for brightness for each intensity level */ + for (ilevel = MAXLEVEL; ilevel >= 0; ilevel--) { + int r, g, b; + void *cp; + + /* + * convert to 16-bit integer; clamp at 16 bits. + * this allows the sum of brightness factors across phosphors + * for each of R G and B to be greater than 1.0 + */ + + r = rr * level_scale[ilevel] * 0xffff; + if (r > 0xffff) r = 0xffff; + + g = rg * level_scale[ilevel] * 0xffff; + if (g > 0xffff) g = 0xffff; + + b = rb * level_scale[ilevel] * 0xffff; + if (b > 0xffff) b = 0xffff; + + cp = ws_color_rgb(r, g, b); + if (!cp) { /* allocation failed? */ + if (ttl == MAXTTL-1) { /* brand new */ + if (ilevel == MAXLEVEL) /* highest intensity? */ + cp = ws_color_white(); /* use white */ + else + cp = colors[color][ilevel+1][ttl]; /* use next lvl */ + } /* brand new */ + else if (r + g + b >= 0xffff*3/3) /* light-ish? */ + cp = colors[color][ilevel][ttl+1]; /* use previous TTL */ + else + cp = ws_color_black(); + } + colors[color][ilevel][ttl] = cp; + } /* for each intensity level */ + } /* for each TTL */ +} /* phosphor_init */ + +static struct display * +find_type(enum display_type type) +{ + int i; + struct display *dp; + for (i = 0, dp = displays; i < ELEMENTS(displays); i++, dp++) + if (dp->type == type) + return dp; + return NULL; +} + +int +display_init(enum display_type type, int sf) +{ + static int init_failed = 0; + struct display *dp; + int half_life; + int i; + + if (initialized) { + /* cannot change type once started */ + /* XXX say something???? */ + return type == display_type; + } + + if (init_failed) + return 0; /* avoid thrashing */ + + init_failed = 1; /* assume the worst */ + dp = find_type(type); + if (!dp) { + fprintf(stderr, "Unknown display type %d\r\n", (int)type); + goto failed; + } + + /* Initialize display list */ + head->next = head->prev = head; + + display_type = type; + scale = sf; + + xpoints = dp->xpoints; + ypoints = dp->ypoints; + + /* increase scale factor if won't fit on desktop? */ + xpixels = xpoints / scale; + ypixels = ypoints / scale; + + /* set default pen radius now that scale is set */ + display_lp_radius(PEN_RADIUS); + + ncolors = 1; + /* + * use function to calculate from looking at avg (max?) + * of phosphor half lives??? + */ +#define COLOR_HALF_LIFE(C) ((C)->half_life) + + half_life = COLOR_HALF_LIFE(dp->color0); + if (dp->color1) { + if (dp->color1->half_life > half_life) + half_life = COLOR_HALF_LIFE(dp->color1); + ncolors++; + } + + /* before phosphor_init; */ + refresh_rate = (1000000*LEVELS_PER_HALFLIFE)/half_life; + refresh_interval = 1000000/DELAY_UNIT/refresh_rate; + + /* + * sanity check refresh_interval + * calculating/selecting DELAY_UNIT at runtime might avoid this! + */ + + /* must be non-zero; interval of 1 means all pixels will age at once! */ + if (refresh_interval < 1) { + /* decrease DELAY_UNIT? */ + fprintf(stderr, "NOTE! refresh_interval too small: %d\r\n", + refresh_interval); + + /* dunno if this is a good idea, but might be better than dying */ + refresh_interval = 1; + } + + /* point lifetime in DELAY_UNITs will not fit in p->delay field! */ + if (refresh_interval > DELAY_T_MAX) { + /* increase DELAY_UNIT? */ + fprintf(stderr, "bad refresh_interval %d > DELAY_T_MAX %d\r\n", + refresh_interval, DELAY_T_MAX); + goto failed; + } + + /* + * before phosphor_init; + * set up relative brightness of display intensity levels + * (could differ for different hardware) + * + * linear for now. boost factor insures low intensities are visible + */ +#define BOOST 5 + for (i = 0; i < NLEVELS; i++) + level_scale[i] = ((float)i+1+BOOST)/(NLEVELS+BOOST); + + points = (struct point *)calloc((size_t)xpixels, + ypixels * sizeof(struct point)); + if (!points) + goto failed; + + if (!ws_init(dp->name, xpixels, ypixels, ncolors)) + goto failed; + + phosphor_init(dp->color0->phosphors, dp->color0->nphosphors, 0); + + if (dp->color1) + phosphor_init(dp->color1->phosphors, dp->color1->nphosphors, 1); + + initialized = 1; + init_failed = 0; /* hey, we made it! */ + return 1; + + failed: + fprintf(stderr, "Display initialization failed\r\n"); + return 0; +} + +void +display_reset(void) +{ + /* XXX tear down window? just clear it? */ +} + +void +display_sync(void) +{ + ws_sync(); +} + +void +display_beep(void) +{ + ws_beep(); +} + +int +display_xpoints(void) +{ + return xpoints; +} + +int +display_ypoints(void) +{ + return ypoints; +} + +int +display_scale(void) +{ + return scale; +} + +/* + * handle keyboard events + * + * data switches; 18 -- enough for PDP-1/4/7/9/15 (for munching squares!) + * 123 456 789 qwe rty uio + * bit toggled on key up + * all cleared on space + * + * spacewar switches; bit high as long as key down + * asdf kl;' + * just where PDP-1 spacewar expects them! + * key mappings same as MIT Media Lab Java PDP-1 simulator + * + */ +unsigned long spacewar_switches = 0; + +/* here from window system */ +void +display_keydown(int k) +{ + switch (k) { + case 'f': case 'F': spacewar_switches |= 01; break; /* torpedos */ + case 'd': case 'D': spacewar_switches |= 02; break; /* engines */ + case 'a': case 'A': spacewar_switches |= 04; break; /* rotate R */ + case 's': case 'S': spacewar_switches |= 010; break; /* rotate L */ + case '\'': case '"': spacewar_switches |= 040000; break; /* torpedos */ + case ';': case ':': spacewar_switches |= 0100000; break; /* engines */ + case 'k': case 'K': spacewar_switches |= 0200000; break; /* rotate R */ + case 'l': case 'L': spacewar_switches |= 0400000; break; /* rotate L */ + default: return; + } +} + +/* here from window system */ +void +display_keyup(int k) +{ + unsigned long test_switches = cpu_get_switches(); + + /* fetch console switches from simulator? */ + switch (k) { + case 'f': case 'F': spacewar_switches &= ~01; return; + case 'd': case 'D': spacewar_switches &= ~02; return; + case 'a': case 'A': spacewar_switches &= ~04; return; + case 's': case 'S': spacewar_switches &= ~010; return; + + case '\'': case '"': spacewar_switches &= ~040000; return; + case ';': case ':': spacewar_switches &= ~0100000; return; + case 'k': case 'K': spacewar_switches &= ~0200000; return; + case 'l': case 'L': spacewar_switches &= ~0400000; return; + + case '1': test_switches ^= 1<<17; break; + case '2': test_switches ^= 1<<16; break; + case '3': test_switches ^= 1<<15; break; + + case '4': test_switches ^= 1<<14; break; + case '5': test_switches ^= 1<<13; break; + case '6': test_switches ^= 1<<12; break; + + case '7': test_switches ^= 1<<11; break; + case '8': test_switches ^= 1<<10; break; + case '9': test_switches ^= 1<<9; break; + + case 'q': case 'Q': test_switches ^= 1<<8; break; + case 'w': case 'W': test_switches ^= 1<<7; break; + case 'e': case 'E': test_switches ^= 1<<6; break; + + case 'r': case 'R': test_switches ^= 1<<5; break; + case 't': case 'T': test_switches ^= 1<<4; break; + case 'y': case 'Y': test_switches ^= 1<<3; break; + + case 'u': case 'U': test_switches ^= 1<<2; break; + case 'i': case 'I': test_switches ^= 1<<1; break; + case 'o': case 'O': test_switches ^= 1; break; + + case ' ': test_switches = 0; break; + default: return; + } + cpu_set_switches(test_switches); +} diff --git a/display/xy.h b/display/xy.h new file mode 100644 index 00000000..7fc87328 --- /dev/null +++ b/display/xy.h @@ -0,0 +1,142 @@ +/* + * $Id: xy.h,v 1.13 2004/01/24 08:34:33 phil Exp $ + * interface to O/S independent layer of XY display simulator + * Phil Budne + * September 2003 + * + * Changes from Douglas A. Gwyn, Jan 12, 2004 + */ + +/* + * Copyright (c) 2003-2004, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +/* + * known display types + */ +enum display_type { + DIS_VR14 = 14, + DIS_VR17 = 17, + DIS_VR20 = 20, + DIS_TYPE30 = 30, + DIS_VR48 = 48, + DIS_TYPE340 = 340 +}; + +/* + * display scale factors + */ +#define RES_FULL 1 +#define RES_HALF 2 +#define RES_QUARTER 4 +#define RES_EIGHTH 8 + +/* + * must be called before first call to display_age() + * (but called implicitly by display_point()) + */ +extern int display_init(enum display_type, int scale); + +/* return size of virtual display */ +extern int display_xpoints(void); +extern int display_ypoints(void); + +/* virtual points between display and menu sections */ +#define VR48_GUTTER 8 /* just a guess */ + +/* conversion factor from virtual points and displayed pixels */ +extern int display_scale(void); + +/* + * simulate passage of time; first argument is simulated microseconds elapsed, + * second argument is flag to slow down simulated speed + * see comments in display.c for why you should call it often!! + * Under X11 polls for window events!! + */ +extern int display_age(int,int); + +/* + * display intensity levels. + * always at least 8 (for VT11/VS60) -- may be mapped internally + */ +#define DISPLAY_INT_MAX 7 +#define DISPLAY_INT_MIN 0 /* lowest "on" level */ + +/* + * plot a point; arguments are x, y, intensity, color (0/1) + * returns true if light pen active (mouse button down) + * at (or very near) this location. + * + * Display initialized on first call. + */ +extern int display_point(int,int,int,int); + +/* + * force window system to output bits to screen; + * call after adding points, or aging the screen + */ +extern void display_sync(void); + +/* + * currently a noop + */ +extern void display_reset(void); + +/* + * ring the bell + */ +extern void display_beep(void); + +/* + * Set light-pen radius; maximum radius in display coordinates + * from a "lit" location that the light pen will see. + */ +extern void display_lp_radius(int); + +/* + * set by simulated spacewar switch box switches + * 18 bits (only high 4 and low 4 used) + */ +extern unsigned long spacewar_switches; + +/* + * light pen "tip switch" activated (for VS60 emulation etc.) + * should only be set from "driver" (window system layer) + */ +extern unsigned char display_lp_sw; + +/* + * deactivates light pen + * (SIMH DR11-C simulation when initialized sets this and + * then reports mouse coordinates as Talos digitizer data) + */ +extern unsigned char display_tablet; + +/* + * users of this library are expected to provide these calls. + * simulator will set 18 simulated switches. + */ +extern unsigned long cpu_get_switches(void); /* get current switch state */ +extern void cpu_set_switches(unsigned long); /* set switches */ diff --git a/makefile b/makefile index 9622af64..3dc92f9f 100644 --- a/makefile +++ b/makefile @@ -677,15 +677,31 @@ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c \ sim_video.c - +DISPLAYD = display +ifeq ($(WIN32),) + ifeq (x11,$(shell if $(TEST) -e /usr/include/X11/Intrinsic.h ; then echo x11; fi)) + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/x11.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY_OPT = -DUSE_DISPLAY -I/usr/X11/include -lXt -lX11 -lm + else + DISPLAYL = + DISPLAYVT = + DISPLAY_OPT = + endif +else + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/win32.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY_OPT = -DUSE_DISPLAY -lgdi32 +endif + # # Emulator source files and compile time options # PDP1D = PDP1 PDP1 = ${PDP1D}/pdp1_lp.c ${PDP1D}/pdp1_cpu.c ${PDP1D}/pdp1_stddev.c \ ${PDP1D}/pdp1_sys.c ${PDP1D}/pdp1_dt.c ${PDP1D}/pdp1_drm.c \ - ${PDP1D}/pdp1_clk.c ${PDP1D}/pdp1_dcs.c -PDP1_OPT = -I ${PDP1D} + ${PDP1D}/pdp1_clk.c ${PDP1D}/pdp1_dcs.c ${PDP1D}/pdp1_dpy.c ${DISPLAYL} +PDP1_OPT = -I ${PDP1D} $(DISPLAY_OPT) NOVAD = NOVA @@ -727,8 +743,9 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ - ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c ${PDP11D}/pdp11_io_lib.c -PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c ${PDP11D}/pdp11_vt.c \ + ${PDP11D}/pdp11_io_lib.c $(DISPLAYL) $(DISPLAYVT) +PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} $(DISPLAY_OPT) VAXD = VAX @@ -978,20 +995,6 @@ SWTP6800MP-A2 = ${SWTP6800C}/mp-a2.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ ${SWTP6800C}/mp-b2.c ${SWTP6800C}/mp-8m.c ${SWTP6800C}/i2716.c SWTP6800_OPT = -I ${SWTP6800D} -DISPLAYD = display -ifeq ($(WIN32),) - ifeq (x11,$(shell if $(TEST) -e /usr/include/X11/Intrinsic.h ; then echo x11; fi)) - DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/x11.c - DISPLAY_OPT = -DUSE_DISPLAY -I/usr/X11/include -lXt -lX11 -lm - else - DISPLAYL = - DISPLAY_OPT = - endif -else - DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/win32.c - DISPLAY_OPT = -DUSE_DISPLAY -endif - TX0D = TX-0 TX0 = ${TX0D}/tx0_cpu.c ${TX0D}/tx0_dpy.c ${TX0D}/tx0_stddev.c \ ${TX0D}/tx0_sys.c ${TX0D}/tx0_sys_orig.c ${DISPLAYL}