        TITLE   *** GRAPHBOX *** TERMINAL SOFTWARE
        NAME    GRAPHBOX
        WITH    WI=105,DE=51
*       EDITED 07/12/83 2000 HOURS
*       GRAPHBOX TERMINAL SOFTWARE
*       COPYRIGHT (C) 1977 BY IRA D. BAXTER
*       8192 REGENCY STREET
*       LA PALMA, CALIF. 90623
*       ALL RIGHTS RESERVED
*
*       NEXT PASS: MAKE SCREEN WINDOW ON 65536 X 65536 SPACE
*               INSTALL DRAWCIRCLE, 2 STOP BITS ON 150 BAUD AND LOWER
*               MAKE (X,A) ENTRYPOINTS INTO (X, (0,B)) ENTRY POINTS
*               CURSOR BLINK STEPS ON TOP LINE OF SCREEN!
*               CROSSHAIRS STILL MOVE JERKY
*               USE EXTRA FN KEYS TO IMPLEMENT ODDBALL FNS
*               BREAK XMIT ?
*               AFTER SCROLL, CHAR TOP LINE = LINE 0 ?
*               'OR' MODE WORKS TERRIBLE!
*               ADD AUTOBOOT FEATURE
*               WHY TO CROSSHAIRS DISAPPEAR AT 0,0 ?
*               SMOOTH SCROLL
*               ONCE XOF SENT, DON'T SEND ANOTHER UNTIL XON SENT
*               UPDATE CIRCUITRY TO ALLOW CTS FROM GRAPHBOX
        PAGE
        IFUND   MSI
MSI     EQU     0
        FIN
        IF      MSI
*       ADDRESS SPACE LAYOUT FOR MIDWEST SCIENTIFIC VERSION OF GRAPHBOX
*
*       :0000-:3FFF     16K USER RAM (OPTIONAL)
*       :4000-:7FFF     16K USER RAM (OPTIONAL)
*       :8000-:BFFF     16K USER RAM (OPTIONAL)
*                               SELECTED AFTER REFERENCE TO :F800-:FFFF
*                               THIS RAM MAY NOT CONTAIN PICTURES OR OPERANDS
*                               FOR USE WITH GRAPHICS PRIMITIVES, AS IT IS NOT
*                               ACCESSIBLE WHEN GRAPHICS SUBROUTINES HAVE CONTROL.
*                               TYPICALLY USED TO HOLD OPERATING SYSTEM.
*       :8000-:BFFF     16K DISPLAY BUFFER RAM (REQUIRED)
*                               SELECTED AFTER REFERENCE TO :D800-:F7FF
*       :C000-:C3FF     1K RAM FOR EXTENDED USER SPACE OR EXTENDED ROM PROGRAM
*       :C400-:C7FF     1K RAM FOR EXTENDED USER SPACE OR EXTENDED ROM PROGRAM
*       :C800-:CBFF     1K RAM FOR EXTENDED USER SPACE OR EXTENDED ROM PROGRAM
*                       TOTAL USER SPACE: 51K IN MAX CONFIGURATION
*       :CC00-CFFF      1K RAM RESERVED FOR GRAPHICS ROM PROGRAM
*                               ALSO DOUBLES AS :0000-:00FF WHEN DISPLAY BUFFER RAM SELECTED
*
*       :D000-:D7FF     I/O DEVICE SPACE
*
*       :D7E0-:D7E3     KEYBOARD/GRAPHICS (DOT MATRIX) PRINTER PIA
*       :D7E4-:D7E7     JOYSTICK/BAUD RATE CONTROL PIA
*       :D7E8-:D7EB     MAIN ACIA (TO HOST COMPUTER)
*       :D7EC-:D7EF     AUXILIARY ACIA (TO LOCAL PRINTER...)
*       :D7F0-:D7F3     CRT CONTROLLER CHIP
*       :D7F4-:D7F7     ADVANCED DATA LINK CONTROLLER CHIP
*       :D7F8-:D7FF     IEEE BUS INTERFACE CONTROLLER CHIP
*
*       :D800-:E3FF     EDIT (OR CUSTOM PROGRAM) ROM PROGRAM (OPTIONAL)
*       :E400-:FFFF     GRAPHICS PROGRAM IN ROM (REQUIRED)
GRAPHROM        EQU     $E400
GRAPHRAM        EQU     0       FUNNY DECODER SWITCHES $CC00 INTO LOCATION "0"...
*                               WHEN GRAPHICS ROM IS ACTIVE
IOBASE  EQU     $D000   FOR THE MSI
ACIACTRL        EQU     $D7E8
        FIN
        PAGE
        IFUND   CONRAC
CONRAC  EQU     0
        FIN
        IF      CONRAC
*
*       ADDRESS SPACE LAYOUT FOR CONRAC VERSION OF GRAPHBOX
*
*       :0000-7FFF      32K OF USER RAM (OPTIONAL)
*       :8000-E000      24K OF USER RAM (OPTIONAL)
*       :8000-:BFFF     16K DISPLAY BUFFER RAM (REQUIRED)
*                               ENABLED BY "DISPLAY RAM ENABLE" TERM ON PIA
*                               USER RAM MUST BE DISABLED BEFORE DISPLAY RAM IS ENABLED...
*                               AND VICE-VERSA.
*       :E000-:F7FF     GRAPHICS PROGRAM IN ROM (REQUIRED)
*       :FA80-:FA83     GRAPHICS CONTROL PIA
*                       A SIDE: NOT USED
*                       B SIDE: JOYSTICK, 50/60 HZ SENSE,...
*                               ROW ADDRESS ADJUST, DISPLAY RAM ENABLE
*       :FA84-:FA85     MOTOROLA 6845 CRT CONTROLLER CHIP FOR GRAPHICS DISPLAY
*       :FAF4-:FAF7     KEYBOARD INPUT PIA
*       :FAF0-:FAF1     ACIA FOR DUMB GRAPHICS TERMINAL EMULATION
*       :FE00-:FFFD     RAM RESERVED FOR GRAPHICS

GRAPHROM        EQU     $1000   FOR NOW
GRAPHRAM        EQU     $3000   SINCE WE OWN THE MACHINE
IOBASE  EQU     $FA00   SIGH! WHAT A FUNNY PLACE TO START...
GBPIA   EQU     $FA81   GRAPHBOX PIA
GBPIADATAA      EQU     GBPIA-1 "A" SIDE OF GBPIA
ACIACTRL        EQU     $FAF0   THIS IS PRETTY STANDARD
KEYPIA  EQU     $FAF5   KEYBOARD PIA
        FIN
        IFUND   COLORCOMPUTER
COLORCOMPUTER EQU 0
        FIN
        if      COLORCOMPUTER
*
*       ADDRESS SPACE LAYOUT FOR COLOR COMPUTER VERSION OF GRAPHBOX
*
*       :0000-:3FFF     16K OF REQUIRED USER RAM
*       :4000-:7FFF     16K OF USER RAM (OPTIONAL)
*
*       :0100-:1900     6K DISPLAY BUFFER WINDOW RAM HANDLED BY SAM + VDG CHIP
*
*       :1A00-:3000     GRAPHBOX PROGRAM
*
*        Radio Shack device definitions need to go here!
*       :FA80-:FA83     GRAPHICS CONTROL PIA
*                       A SIDE: NOT USED
*                       B SIDE: JOYSTICK, 50/60 HZ SENSE,...
*                               ROW ADDRESS ADJUST, DISPLAY RAM ENABLE
*       :FA84-:FA85     MOTOROLA 6845 CRT CONTROLLER CHIP FOR GRAPHICS DISPLAY
*       :FAF4-:FAF7     KEYBOARD INPUT PIA
*       :FAF0-:FAF1     ACIA FOR DUMB GRAPHICS TERMINAL EMULATION
*       :FE00-:FFFD     RAM RESERVED FOR GRAPHICS

GRAPHROM        EQU     $1A00   FOR NOW
GRAPHRAM        EQU     $3000   SINCE WE OWN THE MACHINE
IOBASE  EQU     $FA00   SIGH! WHAT A FUNNY PLACE TO START...
GBPIA   EQU     $FA81   GRAPHBOX PIA
GBPIADATAA      EQU     GBPIA-1 "A" SIDE OF GBPIA
ACIACTRL        EQU     $FAF0   THIS IS PRETTY STANDARD
KEYPIA  EQU     $FAF5   KEYBOARD PIA
        FIN
        PAGE
*       DEFINITIONS
*
VERSION EQU     $03     LEFT DIGIT = MAJOR REV, RIGHT DIGIT = MINOR REV
*
CHARHEIGHT      EQU     9       # ROWS IN A CHARACTER
CHARWIDTH       EQU     6       # COLUMNS IN A CHARACTER POSITION
SCREENHEIGHT    EQU     256     NUMBER OF ROWS ON THE SCREEN
SCREENWIDTH     EQU     512     NUMBER OF DOTS ACROSS THE SCREEN
CHARLEFTSIDE    EQU     1       CURSOR X AFTER NEWPAGE
CHARTOPSIDE     EQU     SCREENHEIGHT-2  CURSOR Y AFTER NEWPAGE
NBROW           EQU     SCREENWIDTH/8   NUMBER OF BYTES PER ROW
NROWS           EQU     SCREENHEIGHT    NUMBER OF ROWS DOWN SCREEN
SCREENBOTTOM    EQU     $8000   LOWEST ADDRESS DISPLAY BYTE
SCREENTOP       EQU     $8000+16383     HIGHEST ADDRESS DISPLAY BYTE


        PAGE
*       PIA AND ACIA INTERFACE DEFINITIONS

DDRACCESS       EQU     %00000000       TURN OFF THIS BIT TO ACCESS DATA DIRECTION REGISTER
DATAACCESS      EQU     %00000100       TURN DDRACCESS BIT ON TO GET TO DATA REGISTER


VERTSYNCSENSE   EQU     %10000000       SENSE BIT FOR VERTICAL BLANKING ON CRT
VERTSYNCACK     EQU     GBPIADATAA      READING THIS CLEARS VERTSYNC INTERRUPT
VERTSYNCCA1     EQU     %00000011       THIS FORCES CA1 TO BE INTERRUPT INPUT ON VERTICAL SYNC
BGDCA2  EQU     %00110000       THIS CAUSES CA2 TO BE BACKGROUND OUTPUT
BLACKBGD        EQU     %00001000       THIS PATTERN IN UPSHIFTPIA MAKES BLACK BACKGROUND
WHITEBGD        EQU     %00000000       THIS PATTERN IN UPSHIFTPIA MAKES WHITE BACKGROUND
VIDEOINVERT     EQU     %00001000       TOGGLE THIS BIT TO INVERT VIDEO IN UPSHIFTPIA
GBPIACTLACW     EQU     BGDCA2+DATAACCESS+VERTSYNCCA1   CONTROL WORD FOR LEFTSHIFTPIA
CLEARTOSEND     EQU     %01000000       "GRAPHBOX READY" FEEDBACK TO HOST
GRAPHBOXBUSY    EQU     %00000000       "GRAPHBOX NOT READY" FEEDBACK TO HOST

        PAGE
JOYSTICKPIA     EQU     GBPIA+2 PIA CONTROL WORD FOR JOYSTICK SENSE
JOYSTICK        EQU     JOYSTICKPIA-1   JOYSTICK DATA WORD (BITS 0-3 ARE SENSE BITS)
JOYDDR  EQU     DISPLAYRAMENABLE!ROWADJUST              DATA DIRECTION: BITS 7-4 ARE INPUT
SPEAKER EQU     JOYSTICKPIA     CB2 IS SPEAKER OUTPUT BIT
SPEAKERCB2      EQU     %00110000       MAKES CB2 BE SPEAKER OUTPUT BIT
SPEAKERON       EQU     %00110000       TURN SPEAKER ON
SPEAKEROFF      EQU     %00111000       TURN SPEAKER OFF
JOYSTICKCW      EQU     SPEAKERCB2+DATAACCESS   NORMAL CONTROL WORD FOR JOYBAUDPIA
CROSSUP EQU     %00001000       BIT IN JOYSTICK MEANS "MOVE CROSSHAIRS UP"
CROSSDN EQU     %00000100       BIT IN JOYSTICK MEANS "MOVE CROSSHAIRS DOWN"
CROSSRT EQU     %00000010       BIT IN JOYSTICK MEANS "MOVE CROSSHAIRS RIGHT"
CROSSLF EQU     %00000001       BIT IN JOYSTICK MEANS "MOVE CROSSHAIRS LEFT"
SIXTYHZSENSE    EQU     %00010000       "JOYSTICK" BIT MEANING "60HZ POWER"
ROWADJUST       EQU     %01100000       ROW ADJUST BITS TO OFFSET RA0,RA1 OF MC6845
DISPLAYRAMENABLE        EQU     %10000000       BIT IN JOYSTICK TO ALLOW MPU ACCESS TO DISPLAY RAM
DISPLAYRAMDISABLE       EQU     %00000000       BIT IN JOYSTICK TO DISABLE MPU ACCESS TO DISPLAY RAM
*
*
KEYDATA EQU     KEYPIA-1        KEYBOARD DATA WORD
KEYDDR  EQU     %00000000       DATA DIRECTION: ALL INPUT
*                               LEAST SIGNIFICANT 7 BITS ARE KEYBOARD CHARACTER
*                               MSB IS FUNNY BIT WHICH GRAPHBOX CHOPS OFF
KEYCA1  EQU     %00000011       THIS FORCES CA1 TO BE INTERRUPT INPUT ON KEY STROKE
KEYSENSE        EQU     %10000000       BIT IN KEYPIA INDICATING KEY WAS STRUCK
KEYCW   EQU     DATAACCESS+KEYCA1       CONTROL WORD FOR KEYPIA
        PAGE
*
HORIZONTALBITCOUNT      EQU     680     TIME PER RASTER LINE
VERTICALSCANLINES       EQU     273     SCREEN TIME MEASURED IN RASTER LINES
*
*       FOR 60HZ:
*               HORIZONTALBITCOUNT*VERTICALSCANLINES=1/60
*               HORIZONTALBITCOUNT=512+8*K
*       CRT CONTROLLER CHIP DEFINITIONS
*
CRTCREGISTERSELECT      EQU     $FA84   CRT CONTROLLER CHIP ADDRESS REGISTER
CRTCREGISTER    EQU     CRTCREGISTERSELECT+1    CRT REGISTER FILE SELECTED BY ADDR REGISTER
CRTCHORZTOTAL   EQU     0       HORIZONTAL TOTAL REGISTER
CRTCHORZDISP    EQU     1       HORIZONTAL DISPLAYED REGISTER
CRTCHORZSYNC    EQU     2       HORIZONTAL SYNC POSITION REGISTER
CRCTHORZSYNCW   EQU     3       HORIZONTAL SYNC WIDTH REGISTER
CRTCVERTTOTAL   EQU     4       VERTICAL TOTAL REGISTER
CRTCVTOTALADJ   EQU     5       VERTICAL TOTAL ADJUST REGISTER
CRTCVERTDISP    EQU     6       VERTICAL DISPLAYED REGISTER
CRTCVSYNCPOS    EQU     7       VERTICAL SYNC POSITION
CRTCINTERLACE   EQU     8       INTERLACE MODE REGISTER
CRTCMAXSCANLINE EQU     9       MAXIMUM SCAN LINE ADDRESS REGISTER
CRTCCURSORSTART EQU     10      CURSOR START REGISTER
CRTCCURSOREND   EQU     11      CURSOR END REGISTER
CRTCSTARTADDRH  EQU     12      START ADDRESS REGISTER (UPPER 8 BITS)
CRTCSTARTADDRL  EQU     13      START ADDRESS REGISTER (LOWER 8 BITS)
CRTCCURSORH     EQU     14      CURSOR REGISTER (UPPER 8 BITS)
CRTCCURSORL     EQU     15      CURSOR REGISTER (LOWER 8 BITS)
CRTCLIGHTPENH   EQU     16      LIGHT PEN REGISTER (UPPER 8 BITS)
CRTCLIGHTPENL   EQU     17      LIGHT PEN REGISTER (LOWER 8 BITS)
        PAGE
ACIASTATUS      EQU     ACIACTRL        ACIA STATUS BITS
ACIAXMITD       EQU     ACIACTRL+1      ACIA TRANSMIT DATA REGISTER
ACIARCVD        EQU     ACIAXMITD       ACIA RECEIVE DATA REGISTER

ACIARESET       EQU     %00000011       TELLS ACIA TO RESET INTERNAL GUTS
ACIADIV16       EQU     %00000001       TELLS ACIA THAT CLOCK FREQ = 16 * BAUD RATE
ACIA8BITS       EQU     %00010100       TELLS ACIA "8 DATA BITS + 1 STOP BIT (NO PARITY)"
ACIARTSD        EQU     %00000000       "REQUEST TO SEND" + XMIT INTERRUPT DISABLED
ACIARTSI        EQU     %00100000       "REQUEST TO SEND" + XMIT INTERRUPT ENABLE
ACIARCVI        EQU     %10000000       RECEIVER INTERRUPT ENABLE
ACIACW  EQU     ACIARCVI+ACIA8BITS+ACIADIV16    CONTROL WORD FOR NORMAL USE OF ACIA
ACIARDRF        EQU     %00000001       ACIA STATUS: RECEIVER DATA REGISTER FULL
ACIATDRE        EQU     %00000010       ACIA STATUS: TRANSMITTER DATA REGISTER EMPTY
ACIAERR EQU     %01110000       ACIA STATUS: RECEIVED CHARACTER HAS ERROR
ACIAIRQ EQU     %10000000       ACIA STATUS: INTERRUPT PENDING

*       TIME DELAYS

ONESEC60HZ      EQU     60      # 60THS SECOND IN ONE SECOND

CLICK   EQU     ONESEC60HZ/60           KEYSTROKE CLICK TIME (NMI TICKS)
DINGTIME        EQU     ONESEC60HZ/5    "BELL" TIME FOR CONTROL G (NMI TICKS)
CURSORBLINK     EQU     ONESEC60HZ/2    TIME BETWEEN CURSOR BLINKS (60THS SEC)

        PAGE
*       CROSS HAIR PHYSICS

CROSSACCEL      EQU     $11     =17/256=.066 DOTS/60TH SEC/60TH SEC = 239 DOTS/SEC/SEC
CROSSVMAX       EQU     5       = 300 DOTS/SEC
CROSSPTIME      EQU     ONESEC60HZ/60   # CLOCK TICKS BETWEEN CROSS HAIR PROCESSING EVENTS (NMI TICKS)

*       JOY STICK DEAD TIMES

JOYDEADSS       EQU     $100//(CROSSACCEL*4)    = TIME IN 60THS SEC TO MOVE ONE UNIT OF DISTANCE
JOYDEADSTOP     EQU     ONESEC60HZ/3    JOYSTICK DEAD TIME AFTER INSTANT STOP (60THS SEC)
*
*       FUNNY FRACTIONS
*
POINT5  EQU     $8000   = .5 IF FOUND IN FRACTIONX, FRACTIONY
*
*       SPECIAL KEYSTROKES
*
CTRLD   EQU     $04     CONTROL D (ACTIVATE DEBUG)
LF      EQU     $0A     LINE FEED
CR      EQU     $0D     CARRIAGE RETURN
ESCAPE  EQU     $1B     "STOP PROGRAM GRACEFULLY", START GRAPHICS SEQUENCE
XON     EQU     $11     REQUEST HOST TO SEND MORE COMMANDS
XOFF    EQU     $13     NOTIFY HOST THAT BUFFER IS FULL, STOP SENDING

        PAGE
*       PICTURE BLOCK DISPLACEMENTS
*
PICTXSIZ        EQU     0       X SIZE OF PICTURE IN BITS
PICTYSIZ        EQU     PICTXSIZ+2      Y SIZE OF PICTURE IN ROWS
PICTBYT EQU     PICTYSIZ+1              1ST BYTE OF PICTURE DATA

*       CROSSHAIR VELOCITY CONTROL BLOCKS

CROSSDIR        EQU     0       DIRECTION BIT MASK (UP, DOWN, LEFT, RIGHT)
CROSSVPTR       EQU     CROSSDIR+1      POINTER TO VELOCITY WORD
CROSSVINC       EQU     CROSSVPTR+2     POINTER TO VELOCITY INCREMENT WORD

*       CROSSHAIR AXIS VELOCITY BLOCK

CROSSV  EQU     0       VELOCITY WORD ALONG AN AXIS (X OR Y)

*       CROSS HAIR POSITION FUDGE FACTOR (YOU'LL LOVE THIS!)

CROSSXFUDGE     EQU     3       SO THAT CROSSX+CROSSXFUDGE = X POSITION OF CENTER OF CROSSHAIRS
CROSSYFUDGE     EQU     -2      SO THAT CROSSY+CROSSYFUDGE = Y POSITION OF CENTER OF CROSSHAIRS

*       STACK DISPLACEMENTS FOR MACHINE REGISTERS

AREG    EQU     3               DISPLACEMENT INTO STACK FOR A REGISTER
PC      EQU     6               DISPLACEMENT INTO STACK FOR P-COUNTER

*       WAKE UP CODES

WAKBUFCH        EQU     1       DISPLAY TASK WOKE BECAUSE NEW DATA ARRIVED IN BUFFER
WAK60HZ EQU     2       DISPLAY TASK WOKE BECAUSE ITS TIME TO MOVE CROSSHAIRS

*       DATA INITIALIZATION LIST ENTRIES

IADDR   EQU     0       POINTER TO BYTE(S) TO INITIALIZE
IDATA   EQU     IADDR+2 DATA BYTE(S) TO STORE AT SPECIFIED ADDRESS

        PAGE
*       BUFFER SIZES

KEYBUFSIZ       EQU     10      SIZE OF KEYSTROKE INPUT BUFFER (<=255!)
XMITBUFSIZ      EQU     10      SIZE OF XMITTER BUFFER (<=255!)
DISPLAYBUFSIZ   EQU     255     SIZE OF DISPLAY TASK INPUT BUFFER (<=255!)

*       OPERATING SYSTEM KERNAL DEFINITIONS

MINSTACK        EQU     (7+2)+7+7       9 BYTES FOR INTERRUPT, 7 FOR NMI, AND 7 FOR CAUSEINT$

*       TCB (TASK CONTROL BLOCK) DEFIINITIONS

TCBLNK  EQU     0               POINTER TO NEXT TCB IN QUEUE
TCBSTK  EQU     TCBLNK+2        STACK POINTER FOR TASK
*       ON TOP OF A STACK IS ALWAYS A CONTEXT BLOCK CONTAINING...
*       REGISTERS, TEMPB AND TEMPA
TCBCND  EQU     TCBSTK+2        TASK'S WAKE UP ROUTINE
TCBSIZ  EQU     TCBCND+2        SIZE OF TASK CONTROL BLOCK
       PAGE    GRAPHBOX CONTROL VARIABLES
        ORG     0       GRAPHRAM APPEARS HERE WHEN GRAPHROM REFERENCED

TEMPX   RMB 2   LOCATIONS 0 AND 1 ARE TASK DEPENDENT
TEMP    EQU     TEMPX   FOR CONVENIENCE
TEMPA   EQU     TEMPX   TEMP STORAGE FOR A REGISTER
TEMPB   EQU     TEMPX+1 TEMP STORAGE FOR B REGISTER

XORIGIN RMB     2       X POSITION OF LOWER LEFT CORNER IN VIRTUAL DISPLAY
YORIGIN RMB     2       Y POSITION OF LOWER LEFT CORNER IN VIRTUAL DISPLAY
XWINDOWTOP      RMB     2       X TOP OF WINDOW IN VIRTUAL DISPLAY
YWINDOWTOP      RMB     2       Y TOP OF WINDOW IN VIRTUAL DISPLAY
******** THE ABOVE 4 AREN'T USEFUL YET..********
CURSORX RMB 2   LOGICAL X POSITION IN DOTS FROM LOWER SCREEN LEFT
CURSORY RMB 1   LOGICAL Y POSITION IN DOTS FROM LOWER SCREEN LEFT
CURSORBYTE      RMB 2   POINTER TO SCREEN BYTE CONTAINING CURSORBIT
CURSORBIT       RMB 2   BIT NUMBER OF SCREEN BYTE SELECTED BY (CURSORX, CURSORY)
WRITEATOSCREEN  RMB     6       SUBROUTINE TO WRITE (A) TO (X)
*                               (EORMODE, IORMODE OR ANDMODE)
NEWX            RMB 2   NEW VALUE OF CURSORX
SHIFT           RMB 2   POINTER TO ROUTINE TO SHIFT DATA PATTERN
ROWCOUNT        RMB 1   NUMBER OF ROWS OF CHARACTER LEFT TO COPY TO SCREEN
TARGETLEFT      RMB 2   PLACE ON SCREEN TO PUT LEFT BYTE OF NEXT ROW OF CHARACTER
DELTAXSIGN      RMB 1   SIGN OF DELTA X (0 OR :FF)
DELTAYSIGN      RMB 1   SIGN OF DELTA Y (0 OR :FF)
*       NOTE! DELTAX, DELTAY MUST BE IN THIS EXACT ORDER FOR "RASSOCIATE"
DELTAX          RMB 2   DIFFERENCE BETWEEN CURSOR AND TARGETX
DELTAY          RMB 2   DIFFERENCE BETWEEN CURSORY AND TARGETY
TARGETX RMB 2   LOGICAL X POSITION TARGET
TARGETY RMB 1   LOGICAL Y POSITION TARGET
FRACTIONX       RMB 2   FRACTIONAL PART OF CURSORX (USED IN DDA ROUTINES)
FRACTIONY       RMB 2   FRACTIONAL PART OF CURSORY (USED IN DDA ROUTINES)

*       UP-SHIFTDIST IS LOGICAL SCREEN ROTATION
*       ASSUMING THAT SCREENBOTTOM BYTE IS HIGHEST, LEFTMOST BYTE ON DISPLAY...
*       WHEN UPSHIFTDIST=0
UPSHIFTDIST     RMB     1       UP SHIFT DISTANCE

*       CROSS HAIR STUFF (ORDER DETERMINED BY CROSSHAIR CONTROL BLOCKS)

CROSSXVEL       RMB     1       CROSSHAIRS X VELOCITY (SIGNED)
CROSSXVFRA      RMB     1       CROSSHAIRS X FRACTIONAL VELOCITY (.005... .995)
CROSSYVEL       RMB     1       CROSSHAIRS Y VELOCITY (SIGNED)
CROSSYVFRA      RMB     1       CROSSHAIRS Y FRACTIONAL VELOCITY (.005... .995)
CROSSX          RMB     2       CROSSHAIRSX POSITION (INTEGER PART) 0..511
CROSSY          RMB     1       CROSSHAIRS Y POSITION (INTEGER PART) 0..255
CROSSXFRA       RMB     1       CROSSHAIRS X FRACTION PART (.005.. .995)
CROSSYFRA       RMB     1       CROSSHAIRS Y FRACTION PART (.005 .. .995)
CROSSON RMB     1       0 --> CROSSHAIRS NOT DISPLAYED; <>0 --> DISPLAYED
CURSORON        RMB     1       0 --> CURSOR NOT DISPLAYED; <>0 --> DISPLAYED

LCTIME  RMB     1       LAST TIME CROSS HAIRS WERE PROCESSED (IN TICKS)
BLINKFUSE       RMB 1   ONE SECOND TIMER FOR CURSOR BLINKER

PICTUREP        RMB 2   POINTER TO ASSOCIATION TABLE ENTRY
PICTURE RMB     2       POINTER TO PICTURE BLOCK
PICTOP  RMB     2       POINTER TO TOP OF PICTURE BLOCK REGION

MULTIPLIER      RMB 1   USED TO COMPUTE # BYTES IN A PICTURE
PWIDTH          RMB 1   WIDTH OF PICTURE (ROUNDED UP) IN BYTES
WIDTHCNT        RMB 1   DOWN COUNTER USED TO SCAN PICTURE ROW
RESIDUE         RMB 1   PARTIAL PICTURE BYTE NOT YET PLACED ON SCREEN

LEFTEND RMB     1       LEFT END OF TOP (BOTTOM) LINE OF A BOX
LEFTCOLUMN      RMB 1   LEFT EDGE OF (SIDE OF) EMPTY BOX
RIGHTEND        RMB 1   RIGHT END OF TOP (BOTTOM) LINE OF A BOX
RIGHTCOLUMN     RMB 1   RIGHT EDGE OF (SIDE OF) BOX

JOYDEADTIME     RMB 1   <>0 --> JOYSTICK IS IGNORED FOR N 60THS OF A SECOND
DURATION        RMB 1   <>0 --> BEEPER TONE TIME IN CLOCK INTERRUPTS
TIME            RMB 3   TIME SINCE RESTART IN VERTICAL RETRACE TICKS
        ORG     *+GRAPHRAM      SPECIAL RAM FOR GRAPHBOX VARIABLES
*       SWI INTERRUPT TRANSFERS CONTROL HERE
SWINT   JMP     *       USER PROGRAM MUST FILL IN JMP ADDRESS

*       I/O INTERRUPT TRANSFERS CONTROL HERE
IOINT   JMP     GRAPHBOXINTERRUPT       USER PROGRAM CAN CHANGE THIS

*       NON-MASKABLE INTERRUPT TRANSFERS CONTROL HERE
*
NMINT   JMP     *       USER PROGRAM MUST INITIALIZE THIS
*
*       DEBUGGER ENTRY POINT
*
DEBUG   JMP     *               DEBUGGER SHOULD INITZ THIS PLACE

SCHEDSTK        FDB     SSTK    DEFAULT VALUE FOR SCHEDULER'S STACK
        PAGE
KEYBUFILL       RMB 2   POINTER TO NEXT FREE BYTE IN KEYBUFFER
KEYBUFMPT       RMB 2   POINTER USED TO EMPTY THE KEYBUFFER
KEYBUFREE       RMB 1   # BYTES FREE IN KEY BUFFER

DISPLAYBUFILL   RMB 2   POINTER TO NEXT FREE BYTE IN DISPLAY BUFFER
DISPLAYBUFMPT   RMB 2   POINTER USED TO EMPTY THE DISPLAY BUFFER
DISPLAYBUFFREE  RMB 1   NUMBER OF UNUSED BYTES REMAINING IN DISPLAY BUFFER
CHARREJECT      RMB 1   <>0 --> LASTCHAR WAS REJECTED
LASTCHAR        RMB 1   LAST CHARACTER RETURNED BY GETDB

XMITBUFILL      RMB 2   POINTER USED TO FILL TRANSMIT BUFFER
XMITBUFMPT      RMB 2   POINTER USED TO EMPTY TRANSMIT BUFFER
XMITBUFREE      RMB 1   # BYTES FREE IN TRANSMIT BUFFER
PRIORITYXMIT    RMB 1   DATA BYTE TO BE SENT INSTEAD OF BYTE FROM TRANSMIT BUFFER

CURRENTASK      RMB 2   POINTER TO CURRENTLY EXECUTING TASK
TASKQUEUE       RMB 2   POINTER TO LIST OF TASKS TO RUN
DONTSTOPME      RMB     1       -1 --> OK TO SCHEDULE OR INTERRUPT;
*                               0 --> IN SCHEDULER
*                               >= 0 --> ONLY OK TO INTERRUPT
SURPRISE        RMB 1   0--> SCHEDULING DECISION IS OK

PARAMETERERROR  RMB 2   POINTER TO PARAMETER ERROR RECOVERY ROUTINE

ADDRESS RMB     2       STORAGE FOR DOWNLOAD
CKSUM   RMB     1       CHECKSUM BYTE FOR LOAD RECORDS
COUNT   RMB     1       GENERAL PURPOSE COUNTER

ESCCOUNT        RMB     1       NUMBER OF ESCAPE CHARACTERS RECEIVED

VALUE   RMB     2       16 BIT NUMBER TO BE SENT TO REMOTE HOST
ACC     RMB     3       5 BCD DIGIT BUFFER IN WHICH TO CONVERT BINARY TO DECIMAL

ALTERNATESET    RMB     1       $FF --> USE ROM CHARACTER SET;
*                               $3F --> USE ALTERNATE CHARACTER SET
*      DISPLAY TASK CONTROL BLOCK

DISPLAYTCB      RMB     TCBSIZ

        RMB     MINSTACK+30     STACK SPACE FOR INTERRUPT, NMI, + SLOP
DISPSTACK       EQU     *-1     DISPLAY TASK'S STACK

*       KEYBOARD TASK CONTROL BLOCK

KEYTCB  RMB     TCBSIZ

        RMB     MINSTACK+20     STACK SPACE FOR INTERRUPT, NMI + WORKING SPACE
KEYSTACK        EQU     *-1     KEYBOARD TASK'S STACK

*       KEYBUFFER

KEYBUFBAS       EQU     *       KEYSTROKE BUFFER (CIRCULAR)
        RMB     KEYBUFSIZ       MUST NOT EXCEED 255 BYTES!
KEYBUFTOP       EQU     *

*       TRANSMIT BUFFER

XMITBUFBAS      EQU     *       TRANSMITTER BUFFER (CIRCULAR)
        RMB     XMITBUFSIZ      MUST NOT EXCEED 255 BYTES!
XMITBUFTOP      EQU     *

*       SCHEDULER'S STACK SPACE
*       ALL INTERRUPTS USE THIS STACK FOR SCRATCH SPACE, TOO

        RMB     MINSTACK+10     16 BYTES MINIMUM TO ALLOW INTERRUPT AND NMI
SSTK    EQU     *-1     (EXTRA BYTES IF INTERRUPT ROUTINES DO PUSHES)

*       DISPLAYBUFFER

DISPLAYBUFBAS   EQU     *       DISPLAY (COMMAND) BUFFER (CIRCULAR)
        RMB     DISPLAYBUFSIZ   NEEDS TO BE BIG ENOUGH TO ALLOW FOR SOFTWARE DELAYS
DISPLAYBUFTOP   EQU     *

        IF *>/IOBASE
        ?GRAPHRAM OVERALLOCATED?
        FIN
        PAGE
        ORG     $100            ARBITRARY STARTING POINT FOR ASSOC TABLE
*                               MUST BE ABOVE SWITCHED-IN PAGE ZERO

*       ASSOCIATION TABLE

ASSOCIATIONTBL  EQU     *       SET OF POINTERS TO ASSOCIATED PICTURES
        RMB     64*2    2 BYTES/POINTER * 64 ASSOCIATION CODES
ASSOCTBLEND     EQU     *       END OF ASSOCIATION TABLE

*       FROM HERE ON IS USER/ASSOCIATED PICTURE MEMORY

FREESPACE       EQU     *
       PAGE    APPLICATION PROGRAM ENTRY POINTS

        ORG     GRAPHROM        SET PROGRAM BASE FOR THE ROM

*       *** A LINKING LOADER WOULD SAVE A LOT OF ROM! ***

*       OS ENTRY POINTS

        JMP     WAIT$           ENTRY POINT FOR TASK WAIT
        JMP     CAUSEINT$       ENTRY POINT FOR TASK TO CAUSE FAKE INTERRUPT
        JMP     FORCESCHEDULE   ENTRY POINT FOR INTERRUPT ROUTINE TO FORCE SCHEDULING
        JMP     IORTI           I/O INTERRUPT RETURN IF NOTHING SIGNIFICANT HAPPENED

*       CONTROL FUNCTION ENTRY POINTS

        JMP     DEBUG           $00 NULL (ILLEGAL)
        JMP     SETCHCURSOR     $01 CONTROL A; (A) = ROW, (B)= COL
        JMP     RETURN          $02 CONTROL B
        JMP     RETURN          $03 CONTROL C
        JMP     RETURN          $04 CONTROL D
        JMP     RETURN          $05 CONTROL E
        JMP     RETURN          $06 CONTROL F
        JMP     DING            $07 CONTROL G
        JMP     BACKSPACE       $08 CONTROL H
        JMP     RETURN          $09 CONTROL I
        JMP     CHCURSORDOWN    $0A CONTROL J
        JMP     RETURN          $0B CONTROL K
        JMP     NEWPAGE         $0C CONTROL L
        JMP     ENDLINE         $0D CONTROL M
        JMP     RETURN          $0E CONTROL N
        JMP     RETURN          $0F CONTROL O
        JMP     RETURN          $10 CONTROL P
        JMP     RETURN          $11 CONTROL Q
        JMP     CHCURSORRIGHT   $12 CONTROL R
        JMP     CHCURSORLEFT    $13 CONTROL S
        JMP     RETURN          $14 CONTROL T
        JMP     RETURN          $15 CONTROL U
        JMP     RETURN          $16 CONTROL V
        JMP     RETURN          $17 CONTROL W
        JMP     RETURN          $18 CONTROL X
        JMP     RETURN          $19 CONTROL Y
        JMP     RETURN          $1A CONTROL Z
        JMP     RETURN          $1B CONTROL [ (ESCAPE)
        JMP     RETURN          $1C CONTROL \
        JMP     RETURN          $1D CONTROL ]
        JMP     CHCURSORUP      $1E CONTROL ^
        JMP     RETURN          $1F CONTROL _
       PAGE    GRAPHICS ENTRY POINTS

        JMP     DISPLAYCHAR     PRINTING CHARACTER OUTPUT TO CRT; (A) CONTAINS CHARACTER
????    JMP     PROCESSCHAR     BYTE STREAM OUTPUT TO CRT; (A) CONTAINS CHARACTER
        JMP     SENDCHAR        BYTE STREAM OUTPUT TO REMOTE CPU
        JMP     DRAWASSOCIATED  ESC $40-$7F: (A) CONTAINS PICTURE NUMBER

        JMP     READCROSSHAIRS  ESC ENQ ($05):  RETURNS (X)=CROSSX, (Y)=CROSSY
        JMP     READCURSORXY    ESC ACK ($06):  RETURNS (X)=CURSORX, (Y)=CURSORY
        JMP     ROLLSCREENUP    ESC DC3 ($13)
        JMP     ROLLSCREENDOWN  ESC DC4 ($14)
        JMP     IMAGEROWTOP     ESC FS ($1C):  (X) POINTS TO IMAGE ROW (64 BYTES)
        JMP     IMAGEROWBOTTOM  ESC GS ($1D):  (X) POINTS TO IMAGE ROW (64 BYTES)
        JMP     SETCURSORXY     ESC SP ($20):  (X) CONTAINS NEW CURSORX, (A) CONTAINS NEW CURSOR Y
        JMP     DOTCURSORXY     ESC !  ($21):  (X) CONTAINS NEW CURSORX, (A) CONTAINS NEW CURSOR Y
        JMP     SETCURSORX      ESC "  ($22):  (X) CONTAINS NEW CURSORX
        JMP     SETCURSORY      ESC #  ($23):  (A) CONTAINS NEW CURSORY
        JMP     DRAWDOT         ESC $  ($24):  DRAWS DOT AT CURSOR
        JMP     BACKBLACK       ESC %  ($25):  SET SCREEN BACKGROUND TO BLACK
        JMP     DRAWLINE        ESC &  ($26):  (X) CONTAINS TARGET X, (A) CONTAINS TARGET Y
        JMP     DOTLINE         ESC '  ($27):  (X) CONTAINS TARGET X, (A) CONTAINS TARGET Y
        JMP     DRAWPICTURE     ESC (  ($28):  (X) POINTS TO PICTURE BLOCK
        JMP     EMPTYBOX        ESC *  ($2A):  (X) CONTAINS X BOX SIZE, (A) CONTAINS Y BOX SIZE
        JMP     SOLIDBOX        ESC +  ($2B):  (X) CONTAINS X BOX SIZE, (A) CONTAINS Y BOX SIZE
        JMP     BACKTOGGLE      ESC ,  ($2C):  TOGGLE SCREEN BACKGROUND COLOR
        JMP     BLANKREGION     ESC -  ($2D):  (X) CONTAINS X REGION SIZE, (A) CONTAINS Y REGION SIZE
        JMP     BACKWHITE       ESC .  ($2E):  SET SCREEN BACKGROUND TO WHITE
        JMP     MOVECU          ESC 0  ($30):  MOVE CURSOR UP (ONE DOT)
        JMP     MOVECUR         ESC 1  ($31):  MOVE CURSOR UP AND RIGHT
        JMP     MOVECR          ESC 2  ($32):  MOVE CURSOR RIGHT
        JMP     MOVECRD         ESC 3  ($33):  MOVE CURSOR RIGHT AND DOWN
        JMP     MOVECD          ESC 4  ($34):  MOVE CURSOR DOWN
        JMP     MOVECDL         ESC 5  ($35):  MOVE CURSOR DOWN AND LEFT
        JMP     MOVECL          ESC 6  ($36):  MOVE CURSOR LEFT
        JMP     MOVECLU         ESC 7  ($37):  MOVE CURSOR LEFT AND UP
        JMP     DOTAMCU         ESC 8  ($38):  DRAW DOT AND MOVE CURSOR UP
        JMP     DOTAMCUR        ESC 9  ($39):  DRAW DOT AND MOVE CURSOR UP AND RIGHT
        JMP     DOTAMCR         ESC :  ($3A):  DRAW DOT AND MOVE CURSOR RIGHT
        JMP     DOTAMCRD        ESC ;  ($3B):  DRAW DOT AND MOVE CURSOR RIGHT AND DOWN
        JMP     DOTAMCD         ESC <  ($3C):  DRAW DOT AND MOVE CURSOR DOWN
        JMP     DOTAMCDL        ESC =  ($3D):  DRAW DOT AND MOVE CURSOR DOWN AND LEFT
        JMP     DOTAMCL         ESC >  ($3E):  DRAW DOT AND MOVE CURSOR LEFT
        JMP     DOTAMCLU        ESC ?  ($3F):  DRAW DOT AND MOVE CURSOR LEFT AND UP
       PAGE    CONTROL CHARACTER BRANCH TABLE
CONTROLBRANCH   EQU     *       CONTROL CHARACTER BRANCH TABLE
        FDB     RETURN          $00 NULL
        FDB     RSETCHCURSOR    $01 CONTROL A
        FDB     RETURN          $02 CONTROL B
        FDB     RETURN          $03 CONTROL C
        FDB     RETURN          $04 CONTROL D
        FDB     RETURN          $05 CONTROL E
        FDB     RETURN          $06 CONTROL F
        FDB     DING            $07 CONTROL G
        FDB     BACKSPACE       $08 CONTROL H
        FDB     RETURN          $09 CONTROL I
        FDB     CHCURSORDOWN    $0A CONTROL J
        FDB     RETURN          $0B CONTROL K
        FDB     NEWPAGE         $0C CONTROL L
        FDB     ENDLINE         $0D CONTROL M
        FDB     RETURN          $0E CONTROL N
        FDB     RETURN          $0F CONTROL O
        FDB     RETURN          $10 CONTROL P
        FDB     RETURN          $11 CONTROL Q
        FDB     CHCURSORRIGHT   $12 CONTROL R
        FDB     CHCURSORLEFT    $13 CONTROL S
        FDB     RETURN          $14 CONTROL T
        FDB     RETURN          $15 CONTROL U
        FDB     RETURN          $16 CONTROL V
        FDB     RETURN          $17 CONTROL W
        FDB     RETURN          $18 CONTROL X
        FDB     RETURN          $19 CONTROL Y
        FDB     RETURN          $1A CONTROL Z
        FDB     REMOTEESCAPE    $1B CONTROL [ (GRAPHICS COMMAND PREAMBLE)
        FDB     RETURN          $1C CONTROL BACKSLASH
        FDB     RETURN          $1D CONTROL ]
        FDB     CHCURSORUP      $1E CONTROL UP ARROW
        FDB     RETURN          $1F CONTROL LEFT ARROW
       PAGE    GRAPHICS COMMAND BRANCH TABLE
GRAPHICSBRANCH  EQU     *       BRANCH TABLE FOR REMOTE GRAPHICS COMMANDS
        FDB     BADCOMMAND      ESC NUL ($00)
        FDB     RSELECTWINDOW   ESC SOH ($01): XORIGIN, YORIGIN <CR><LF>
        FDB     BADCOMMAND      ESC STX ($02)
        FDB     BADCOMMAND      ESC ETX ($03)
        FDB     BADCOMMAND      ESC EOT ($04)
        FDB     RREADCROSSHAIRS ESC ENQ ($05):  RETURNS CROSSX, CROSSY
        FDB     RREADCURSORXY   ESC ACK ($06):  RETURNS CURSORX, CURSORY
        FDB     BADCOMMAND      ESC BEL ($07)
        FDB     BADCOMMAND      ESC BS  ($08)
        FDB     BADCOMMAND      ESC HT  ($09)
        FDB     BADCOMMAND      ESC LF  ($0A)
        FDB     BADCOMMAND      ESC VT  ($0B)
        FDB     BADCOMMAND      ESC FF  ($0C)
        FDB     BADCOMMAND      ESC CR  ($0D)
        FDB     BADCOMMAND      ESC SO  ($0E)
        FDB     ZAPASSOCIATIONS ESC SI  ($0F)
        FDB     DUMPMODE        ESC DLE ($10)   SWITCH TO CHARACTER DUMP MODE
        FDB     BADCOMMAND      ESC DC1 ($11)
        FDB     BADCOMMAND      ESC DC2 ($12)
        FDB     ROLLSCREENUP    ESC DC3 ($13)
        FDB     ROLLSCREENDOWN  ESC DC4 ($14)
        FDB     RDRAWCIRCLE     ESC NAK ($15):  RADIUS? ENDPOINT? <CR><LF>
        FDB     SELECTIORMODE   ESC SYN ($16)
        FDB     RGOTO           ESC ETB ($17):  HEXADDRESS <CR><LF>
        FDB     SELECTANDMODE   ESC CAN ($18)
        FDB     SELECTEORMODE   ESC EM  ($19)
        FDB     RDOWNLOAD       ESC SUB ($1A):  SEQUENCE OF MIKBUG RECORDS, S9 <CR><LF>
        FDB     RALTERNATESET   ESC ESC ($1B)
        FDB     RIMAGEROWTOP    ESC FS  ($1C):  IMAGE ROW OF 64 BYTES <CR><LF>
        FDB     RIMAGEROWBOTTOM ESC GS  ($1D):  IMAGE ROW OF 64 BYTES <CR><LF>
        FDB     RIMAGEROWLEFT   ESC RS  ($1E):  IMAGE COLUMN OF 32 BYTES
        FDB     RIMAGEROWRIGHT  ESC US  ($1F):  IMAGE COLUMN OF 32 BYTES
        FDB     RSETCURSORXY    ESC SP  ($20):  NEW CURSORX, NEW CURSOR Y <CR><LF>
        FDB     RDOTCURSORXY    ESC !   ($21):  NEW CURSORX, NEW CURSOR Y <CR><LF>
        FDB     RSETCURSORX     ESC "   ($22):  NEW CURSORX <CR><LF>
        FDB     RSETCURSORY     ESC #   ($23):  NEW CURSORY <CR><LF>
        FDB     DRAWDOT         ESC $   ($24)   DRAWS DOT AT CURSOR
        FDB     BACKBLACK       ESC %   ($25)   SET SCREEN BACKGROUND TO BLACK
        FDB     RDRAWLINE       ESC &   ($26):  TARGET X, TARGET Y <CR><LF>
        FDB     RDOTLINE        ESC '   ($27):  TARGET X, TARGET Y <CR><LF>
        FDB     RDRAWPICTURE    ESC (   ($28):  X SIZE, Y SIZE <CR><LF> HEX BYTES OF PICTURE <CR><LF>
        FDB     RASSOCIATE      ESC )   ($29):  X SIZE, Y SIZE <CR><LF> HEX BYTES OF PICTURE <CR><LF>
        FDB     REMPTYBOX       ESC *   ($2A):  X BOX SIZE, Y BOX SIZE <CR><LF>
        FDB     RSOLIDBOX       ESC +   ($2B):  X BOX SIZE, Y BOX SIZE <CR><LF>
        FDB     BACKTOGGLE      ESC ,   ($2C)   TOGGLE SCREEN BACKGROUND COLOR
        FDB     RBLANKREGION    ESC -   ($2D):  X REGION SIZE, Y REGION SIZE <CR><LF>
        FDB     BACKWHITE       ESC .   ($2E)   SET SCREEN BACKGROUND TO WHITE
        FDB     BADCOMMAND      ESC /   ($2F)
        FDB     MOVECU          ESC 0   ($30):  MOVE CURSOR UP (ONE DOT)
        FDB     MOVECUR         ESC 1   ($31):  MOVE CURSOR UP AND RIGHT
        FDB     MOVECR          ESC 2   ($32):  MOVE CURSOR RIGHT
        FDB     MOVECRD         ESC 3   ($33):  MOVE CURSOR RIGHT AND DOWN
        FDB     MOVECD          ESC 4   ($34):  MOVE CURSOR DOWN
        FDB     MOVECDL         ESC 5   ($35):  MOVE CURSOR DOWN AND LEFT
        FDB     MOVECL          ESC 6   ($36):  MOVE CURSOR LEFT
        FDB     MOVECLU         ESC 7   ($37):  MOVE CURSOR LEFT AND UP
        FDB     DOTAMCU         ESC 8   ($38):  DRAW DOT AND MOVE CURSOR UP
        FDB     DOTAMCUR        ESC 9   ($39):  DRAW DOT AND MOVE CURSOR UP AND RIGHT
        FDB     DOTAMCR         ESC :   ($3A):  DRAW DOT AND MOVE CURSOR RIGHT
        FDB     DOTAMCRD        ESC ;   ($3B):  DRAW DOT AND MOVE CURSOR RIGHT AND DOWN
        FDB     DOTAMCD         ESC <   ($3C):  DRAW DOT AND MOVE CURSOR DOWN
        FDB     DOTAMCDL        ESC =   ($3D):  DRAW DOT AND MOVE CURSOR DOWN AND LEFT
        FDB     DOTAMCL         ESC >   ($3E):  DRAW DOT AND MOVE CURSOR LEFT
        FDB     DOTAMCLU        ESC ?   ($3F):  DRAW DOT AND MOVE CURSOR LEFT AND UP

*       CODES $40 TO $7F ARE 64 PICTURE ASSOCIATION CODES
       PAGE    CHARACTER SET BIT PATTERNS
CHARACTERSET    EQU     *       ASCII TO BIT PATTERN CONVERSION TABLE
**** COULD THIS BE MADE FASTER BY ALIGNING ON SOME BOUNDARY ?
**** COULD BE MADE SMALLER BY GOING 7 BY 5 ???
*       EACH CHARACTER BIT PATTERN OCCUPIES A 5 BY 7 MATRIX
*       THIS BIT PATTERN OCCUPIES 7 CONTIGUOUS BYTES...
*       WITH THE FIRST BYTE BEING THE FIRST DOT ROW OF THE CHARACTER, ETC.
*       THE 5 X 7 BIT MATRIX IS RIGHT JUSTIFIED IN THE BLOCK OF BYTES
*       THE TABLE IS ORDERED IN ASCII SEQUENCE...
*       SO THE PROCESS OF FINDING THE BIT MATRIX FOR A CHARACTER...
*       IS SIMPLY: LOC(BIT MATRIX):=CHARACTERSET+(CHAR-$21)*7
*       1ST BYTE OF CHARACTER HAS SIGN BIT SET IF CHARACTER HAS TAIL (SMALL G,J,P,Q,Y)

CHBANG  FCB     %00100  ! BANG
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00000
        FCB     %00100

CHDBLQ  FCB     %01010  " DOUBLE QUOTE
        FCB     %01010
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000

CHHASH  FCB     %01010  # HASH
        FCB     %01010
        FCB     %11111
        FCB     %01010
        FCB     %11111
        FCB     %01010
        FCB     %01010

CHDOLR  FCB     %00100  $ DOLLAR
        FCB     %01111
        FCB     %10100
        FCB     %01110
        FCB     %00101
        FCB     %11110
        FCB     %00100

CHPCNT  FCB     %11001  % PERCENT
        FCB     %11001
        FCB     %00010
        FCB     %00100
        FCB     %01000
        FCB     %10011
        FCB     %10011

CHAMP   FCB     %01100  & AMPERSAND
        FCB     %10010
        FCB     %01100
        FCB     %11000
        FCB     %10101
        FCB     %10010
        FCB     %01101

CHSGQ   FCB     %00100  ' SINGLE QUOTE
        FCB     %00100
        FCB     %00100
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000

CHLP    FCB     %00010  ( LEFT PARENTHESES
        FCB     %00100
        FCB     %01000
        FCB     %01000
        FCB     %01000
        FCB     %00100
        FCB     %00010

CHRP    FCB     %01000  ) RIGHT PARENTHESES
        FCB     %00100
        FCB     %00010
        FCB     %00010
        FCB     %00010
        FCB     %00100
        FCB     %01000

CHSTAR  FCB     %00100  * ASTERISK
        FCB     %10101
        FCB     %01110
        FCB     %11111
        FCB     %01110
        FCB     %10101
        FCB     %00100

CHPLUS  FCB     %00000  + PLUS
        FCB     %00100
        FCB     %00100
        FCB     %11111
        FCB     %00100
        FCB     %00100
        FCB     %00000

CHCOMA  FCB     %00000  , COMMA
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00010
        FCB     %00010
        FCB     %00100

CHDASH  FCB     %00000  - DASH
        FCB     %00000
        FCB     %00000
        FCB     %11111
        FCB     %00000
        FCB     %00000
        FCB     %00000

CHDOT   FCB     %00000  . DOT
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00110
        FCB     %00110

CHSLS   FCB     %00001  / SLASH
        FCB     %00001
        FCB     %00010
        FCB     %00100
        FCB     %01000
        FCB     %10000
        FCB     %10000

CH0     FCB     %01110  0 ZERO
        FCB     %10001
        FCB     %10011
        FCB     %10101
        FCB     %11001
        FCB     %10001
        FCB     %01110

CH1     FCB     %00100  1 ONE
        FCB     %01100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %11111

CH2     FCB     %01110  2 TWO
        FCB     %10001
        FCB     %00001
        FCB     %01110
        FCB     %10000
        FCB     %10000
        FCB     %11111

CH3     FCB     %01110  3 THREE
        FCB     %10001
        FCB     %00001
        FCB     %01110
        FCB     %00001
        FCB     %10001
        FCB     %01110

CH4     FCB     %10010  4 FOUR
        FCB     %10010
        FCB     %10010
        FCB     %11111
        FCB     %00010
        FCB     %00010
        FCB     %00010

CH5     FCB     %11111  5 FIVE
        FCB     %10000
        FCB     %10000
        FCB     %11110
        FCB     %00001
        FCB     %00001
        FCB     %11110

CH6     FCB     %01110  6 SIX
        FCB     %10001
        FCB     %10000
        FCB     %11110
        FCB     %10001
        FCB     %10001
        FCB     %01110

CH7     FCB     %11111  7 SEVEN
        FCB     %10001
        FCB     %00010
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100

CH8     FCB     %01110  8 EIGHT
        FCB     %10001
        FCB     %10001
        FCB     %01110
        FCB     %10001
        FCB     %10001
        FCB     %01110

CH9     FCB     %01110  9 NINE
        FCB     %10001
        FCB     %10001
        FCB     %01111
        FCB     %00001
        FCB     %00010
        FCB     %11100

CHCLN   FCB     %00000  : COLON
        FCB     %00110
        FCB     %00110
        FCB     %00000
        FCB     %00110
        FCB     %00110
        FCB     %00000

CHSMI   FCB     %00000  ; SEMICOLON
        FCB     %00100
        FCB     %00100
        FCB     %00000
        FCB     %00100
        FCB     %00100
        FCB     %01000

CHLAB   FCB     %00011  < LEFT ANGLE BRACKET
        FCB     %00100
        FCB     %01000
        FCB     %10000
        FCB     %01000
        FCB     %00100
        FCB     %00011

CHEQ    FCB     %00000  = EQUAL
        FCB     %00000
        FCB     %11111
        FCB     %00000
        FCB     %11111
        FCB     %00000
        FCB     %00000

CHRAB   FCB     %11000  > RIGHT ANGLE BRACKET
        FCB     %00100
        FCB     %00010
        FCB     %00001
        FCB     %00010
        FCB     %00100
        FCB     %11000

CHQMK   FCB     %01110  ? QUESTION MARK
        FCB     %10001
        FCB     %00010
        FCB     %00100
        FCB     %00000
        FCB     %00110
        FCB     %00110

CHAT    FCB     %01110  @ AT SIGN
        FCB     %10001
        FCB     %10101
        FCB     %10111
        FCB     %10110
        FCB     %10000
        FCB     %01111

CHA     FCB     %01110  LETTER A
        FCB     %10001
        FCB     %10001
        FCB     %11111
        FCB     %10001
        FCB     %10001
        FCB     %10001

CHB     FCB     %11110  LETTER B
        FCB     %10001
        FCB     %10001
        FCB     %11110
        FCB     %10001
        FCB     %10001
        FCB     %11110

CHC     FCB     %01110  LETTER C
        FCB     %10001
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %10001
        FCB     %01110

CHD     FCB     %11110  LETTER D
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %11110

CHE     FCB     %11111  LETTER E
        FCB     %10000
        FCB     %10000
        FCB     %11100
        FCB     %10000
        FCB     %10000
        FCB     %11111

CHF     FCB     %11111  LETTER F
        FCB     %10000
        FCB     %10000
        FCB     %11100
        FCB     %10000
        FCB     %10000
        FCB     %10000

CHG     FCB     %01110  LETTER G
        FCB     %10001
        FCB     %10000
        FCB     %10000
        FCB     %10011
        FCB     %10001
        FCB     %01110

CHH     FCB     %10001  LETTER H
        FCB     %10001
        FCB     %10001
        FCB     %11111
        FCB     %10001
        FCB     %10001
        FCB     %10001

CHI     FCB     %11111  LETTER I
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %11111

CHJ     FCB     %01111  LETTER J
        FCB     %00010
        FCB     %00010
        FCB     %00010
        FCB     %00010
        FCB     %10010
        FCB     %01100

CHK     FCB     %10001  LETTER K
        FCB     %10010
        FCB     %10100
        FCB     %11000
        FCB     %10100
        FCB     %10010
        FCB     %10001

CHL     FCB     %10000  LETTER L
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %11111

CHM     FCB     %10001  LETTER M
        FCB     %11011
        FCB     %10101
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001

CHN     FCB     %10001  LETTER N
        FCB     %10001
        FCB     %11001
        FCB     %10101
        FCB     %10011
        FCB     %10001
        FCB     %10001

CHO     FCB     %01110  LETTER OH
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %01110

CHP     FCB     %11110  LETTER P
        FCB     %10001
        FCB     %10001
        FCB     %11110
        FCB     %10000
        FCB     %10000
        FCB     %10000

CHQ     FCB     %01110  LETTER Q
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10101
        FCB     %10010
        FCB     %01101

CHR     FCB     %11110  LETTER R
        FCB     %10001
        FCB     %10001
        FCB     %11110
        FCB     %10100
        FCB     %10010
        FCB     %10001

CHS     FCB     %01110  LETTER S
        FCB     %10001
        FCB     %10000
        FCB     %01110
        FCB     %00001
        FCB     %10001
        FCB     %01110

CHT     FCB     %11111  LETTER T
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100

CHU     FCB     %10001  LETTER U
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %01110

CHV     FCB     %10001  LETTER V
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %01010
        FCB     %00100

CHW     FCB     %10001  LETTER W
        FCB     %10001
        FCB     %10001
        FCB     %10101
        FCB     %10101
        FCB     %11011
        FCB     %10001

CHX     FCB     %10001  LETTER X
        FCB     %10001
        FCB     %01010
        FCB     %00100
        FCB     %01010
        FCB     %10001
        FCB     %10001

CHY     FCB     %10001  LETTER Y
        FCB     %10001
        FCB     %01010
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100

CHZ     FCB     %11111  LETTER Z
        FCB     %00001
        FCB     %00010
        FCB     %00100
        FCB     %01000
        FCB     %10000
        FCB     %11111

CHLSB   FCB     %11111  [ LEFT SQUARE BRACKET
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %11111

CHBSL   FCB     %10000  BACK SLASH
        FCB     %10000
        FCB     %01000
        FCB     %00100
        FCB     %00010
        FCB     %00001
        FCB     %00001

CHRSB   FCB     %11111  ] RIGHT SQUARE BRACKET
        FCB     %00001
        FCB     %00001
        FCB     %00001
        FCB     %00001
        FCB     %00001
        FCB     %11111

CHUPA   FCB     %00100  ^ UP ARROW OR CARET
        FCB     %01110
        FCB     %10101
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100

CHLFA   FCB     %00000  _ LEFT ARROW OR UNDERSCORE
        FCB     %00100
        FCB     %01000
        FCB     %11111
        FCB     %01000
        FCB     %00100
        FCB     %00000

CHAGR   FCB     %01000  ` ACCENT GRAVE
        FCB     %00100
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000
        FCB     %00000

CHSA    FCB     %00000  SMALL A
        FCB     %00000
        FCB     %01110
        FCB     %10010
        FCB     %10010
        FCB     %10010
        FCB     %01111

CHSB    FCB     %10000  SMALL B
        FCB     %10000
        FCB     %10000
        FCB     %11110
        FCB     %10001
        FCB     %10001
        FCB     %11110

CHSC    FCB     %00000  SMALL C
        FCB     %00000
        FCB     %01110
        FCB     %10000
        FCB     %10000
        FCB     %10000
        FCB     %01110

CHSD    FCB     %00001  SMALL D
        FCB     %00001
        FCB     %00001
        FCB     %01111
        FCB     %10001
        FCB     %10001
        FCB     %01111

CHSE    FCB     %00000  SMALL E
        FCB     %00000
        FCB     %01110
        FCB     %10001
        FCB     %11110
        FCB     %10000
        FCB     %01110

CHSF    FCB     %00110  SMALL F
        FCB     %01001
        FCB     %01000
        FCB     %11100
        FCB     %01000
        FCB     %01000
        FCB     %01000

CHSG    FCB     %00111+$80      SMALL G
        FCB     %01001
        FCB     %01001
        FCB     %00111
        FCB     %00001
        FCB     %00001
        FCB     %00110

CHSH    FCB     %10000  SMALL H
        FCB     %10000
        FCB     %10000
        FCB     %11110
        FCB     %10001
        FCB     %10001
        FCB     %10001

CHSI    FCB     %00100  SMALL I
        FCB     %00000
        FCB     %01100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00110

CHSJ    FCB     $82     SMALL J
        FCB     %00000
        FCB     %00110
        FCB     %00010
        FCB     %00010
        FCB     %00010
        FCB     %01100

CHSK    FCB     %10000  SMALL K
        FCB     %10000
        FCB     %10010
        FCB     %10100
        FCB     %11000
        FCB     %10100
        FCB     %10010

CHSL    FCB     %01100  SMALL L
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %00100
        FCB     %01110

CHSM    FCB     %00000  SMALL M
        FCB     %10000
        FCB     %11010
        FCB     %10101
        FCB     %10101
        FCB     %10101
        FCB     %10101

CHSN    FCB     %00000  SMALL N
        FCB     %10000
        FCB     %11100
        FCB     %10010
        FCB     %10010
        FCB     %10010
        FCB     %10010

CHSO    FCB     %00000  SMALL O
        FCB     %00000
        FCB     %01110
        FCB     %10001
        FCB     %10001
        FCB     %10001
        FCB     %01110

CHSP    FCB     %11100+$80      SMALL P
        FCB     %10010
        FCB     %10010
        FCB     %11100
        FCB     %10000
        FCB     %10000
        FCB     %10000

CHSQ    FCB     %00111+$80      SMALL Q
        FCB     %01001
        FCB     %01001
        FCB     %00111
        FCB     %00001
        FCB     %00001
        FCB     %00001

CHSR    FCB     %00000  SMALL R
        FCB     %00000
        FCB     %10110
        FCB     %11001
        FCB     %10000
        FCB     %10000
        FCB     %10000

CHSS    FCB     %00000  SMALL S
        FCB     %00000
        FCB     %01110
        FCB     %10000
        FCB     %01110
        FCB     %00001
        FCB     %01110

CHST    FCB     %00000  SMALL T
        FCB     %01000
        FCB     %11100
        FCB     %01000
        FCB     %01000
        FCB     %01000
        FCB     %00100

CHSU    FCB     %00000  SMALL U
        FCB     %00000
        FCB     %10010
        FCB     %10010
        FCB     %10010
        FCB     %10010
        FCB     %01101

CHSV    FCB     %00000  SMALL V
        FCB     %00000
        FCB     %10001
        FCB     %10001
        FCB     %01010
        FCB     %01010
        FCB     %00100

CHSW    FCB     %00000  SMALL W
        FCB     %00000
        FCB     %10001
        FCB     %10001
        FCB     %10101
        FCB     %10101
        FCB     %01010

CHSX    FCB     %00000  SMALL X
        FCB     %00000
        FCB     %10001
        FCB     %01010
        FCB     %00100
        FCB     %01010
        FCB     %10001

CHSY    FCB     %01001+$80      SMALL Y
        FCB     %01001
        FCB     %01001
        FCB     %00111
        FCB     %00001
        FCB     %00001
        FCB     %00110

CHSZ    FCB     %00000  SMALL Z
        FCB     %00000
        FCB     %01111
        FCB     %00001
        FCB     %00010
        FCB     %00100
        FCB     %01111

CHLCB   FCB     %00110  LEFT CURLY BRACKET
        FCB     %01000
        FCB     %01000
        FCB     %10000
        FCB     %01000
        FCB     %01000
        FCB     %00110

CHVB    FCB     %00100  VERTICAL BAR
        FCB     %00100
        FCB     %00100
        FCB     %00000
        FCB     %00100
        FCB     %00100
        FCB     %00100

CHRCB   FCB     %01100  RIGHT CURLY BRACKET
        FCB     %00010
        FCB     %00010
        FCB     %00001
        FCB     %00010
        FCB     %00010
        FCB     %01100

CHTIL   FCB     %00000  TILDE
        FCB     %00000
        FCB     %01001
        FCB     %10101
        FCB     %10010
        FCB     %00000
        FCB     %00000

CHRUB   FCB     %11111  RUBOUT
        FCB     %11111
        FCB     %11111
        FCB     %11111
        FCB     %11111
        FCB     %11111
        FCB     %11111
       PAGE    REMOTE GRAPHICS TERMINAL EMULATION
*       PROCESSES RECEIVED CHARACTERS

REMOTECHAR      EQU     *       PROCESSES PRINTING CHARACTERS
        CMPA    ALTERNATESET    = $FF IF NORMAL MODE
        BHI     DRAWASSOCIATED  B/ $3F, USE ASSOCIATED SET FOR CHARACTERS
        JSR     DISPLAYCHAR
REMOTELOOP      EQU     *
        JSR     GETDBLINK       WAIT FOR NEXT COMMAND BYTE TO ARRIVE
*                               THIS IS ONLY PLACE CURSOR BLINKS OR CROSS MOVES
        CMPA    #$1F            A CONTROL CHARACTER ?
        BHI     REMOTECHAR      B/ PRINTING CHARACTER, GO PRINT
REMOTECONTROL   EQU     *
        ASLA                    IT'S A CONTROL CHARACTER !
        ldx     #ControlBranch
        jsr     [a,x]           call processing subroutine
        BRA     REMOTELOOP      GO PROCESS NEXT CHARACTER


REMOTEESCAPE    EQU     *       PROCESS SEQUENCE THAT STARTS WITH "ESC ..."
        JSR     GETDB           GET GRAPHICS COMMAND CODE
        CMPA    #$3F            A DRAW ASSOCIATED PICTURE COMMAND ?
        BHI     DRAWASSOCIATED  YES, GO PROCESS
        LEAS    2,S             POP RETURN ADDRESS PUSHED BY "JSR 0,X" (ABOVE)
        ASLA                    DOUBLE TO MAKE BRANCH INDEX, SUBTRACT $80
        ldx     #GraphicsBranch
        jsr     [a,x]
        bra     remoteloop

DING    LDAA    #DINGTIME       GET LENGTH OF DING TIME
        STAA    DURATION        SET SPEAKER TONE DURATION
RETURN  RTS                     YOU GUESS...
        PAGE    DRAW ASSOCIATED, DRAW PICTURE
DRAWASSOCIATED  EQU     *
        JSR     CHECKFORUSERRAM AND DON'T RETURN IS THERE ISN'T ANY!
        ASLA                    DOUBLE TO GET BYTE INDEX...
        LDX     #(ASSOCIATIONTBL-2*$40)
        ldx     a,x
        BEQ     PICTXIT         B/ NO PICTURE TO DRAW
DRAWPICTURE ; (X) points to picture block, put picture on screen
        LDAA    PICTYSIZ,X      FETCH PICTURE SIZE
        LDX     PICTXSIZ,X
        BEQ     PICTXIT         EXIT IF PICTURE IS 0 BYTES WIDE
        leau    pictbyt,x       form pointer to 1st byte of picture bit image
        STU     PICTURE         SAVE POINTER TO PICTURE BLOCK
        JSR     MAKESPACE       MAKE SURE ENOUGH SPACE EXISTS
                                ; and roll screen up enough if it doesn't
        JSR     GENCURSORBYTE   FIGURE OUT WHERE FIRST BYTE GOES
        STX     TARGETLEFT
        LDX     NEWX            UPDATE CURSORX PAST THE PICTURE
        STX     CURSORX
SPLAT1 ; entry point for drawing characters, crosshairs and cursor
; (B) = lower 3 bits of X coordinate
; PICTURE points to raw bit image to display
        ASLB                    DOUBLE BIT INDEX FOR WORD TABLE BRANCH
        ldx     #DRAWSHF        find draw shift routine, which shifts each
        ldy     [b,x]           picture byte before placing it on screen
        LDD     DELTAX          COMPUTE PICTURE WIDTH IN BYTES
        ADDD    #7              ROUND WIDTH IN DOTS TO BYTES
        LSRD                    # DOTS + 7 <= 512 + 7 = 519 MAX
        LSRD
        LSRB
        BEQ     PICTXIT         QUIT IF PICTURE IS ZERO BYTES WIDE
        STAB    PWIDTH          SAVE PICTURE WIDTH
        LDX     PICTURE         FETCH PICTURE BYTE TO PLACE ON SCREEN
        LDU     CURSORBYTE      PLACE ON SCREEN TO PUT THE BYTE
PICTLINE        EQU     *       DRAW REMOTE PICTURE LINE ON SCREEN
        LDAB    PWIDTH          GET NUMBER OF BYTES PER PICTURE ROW
        STAB    WIDTHCNT        USE AS LOOP LIMIT COUNT
        CLR     RESIDUE         ZERO THE RESIDUE BYTE
PICTBYTE ; DRAW REMOTE PICTURE BYTE ON SCREEN
; (X) points to next picture byte to draw
;     (note: rightmost picture bit is bit 0 of some byte)
; (U) points to next screen byte to update (CURSORBYTE)
; (Y) points to picture shift routine
        LDAA    ,X+             BUMP POINTER TO PICTURE BLOCK
        CLRB                    NEED 8 ZERO BITS TO SHIFT INTO
        JMP     ,y              GO SHIFT BYTE; THEN COPY TO SCREEN

PICTXIT EQU     *
        RTS

PRSHIFT3 LSRD                   SHIFT RIGHT 3
PRSHIFT2 LSRD                   SHIFT RIGHT 2
PRSHIFT1 LSRD                   SHIFT RIGHT 1
PRSHIFT0 ;                      SHIFT RIGHT 0
        ORAA    RESIDUE         COMBINE SHIFTED STUFF WITH RESIDUE FROM LAST TIME
        STAB    RESIDUE         WHAT'S LEFT OVER IS RESIDUE FOR NEXT TIME
        JSR     WRITEATOSCREEN  COPY PICTURE BYTE TO SCREEN
        DEC     WIDTHCNT        MORE BYTES IN THIS PICTURE ROW ?
        BNE     PICTBYTE        YES, GO COPY TO SCREEN
        BRA     PICTNEXTROW     FIGURE OUT WHERE NEXT BYTE SHOULD GO

PLSHIFT4 ASLA                   LEFT SHIFT 4 PLACES
         ROLB                   NOTE: ASLA\ROLB is NOT same as ASLD!!!
PLSHIFT3 ASLA                   LEFT SHIFT 3 PLACES
         ROLB
PLSHIFT2 ASLA                   LEFT SHIFT 2 PLACES
         ROLB
PLSHIFT1 ASLA                   LEFT SHIFT 1 PLACE
         ROLB
        ORAB    RESIDUE         COMBINE WITH RESIDUE FROM BYTE TO LEFT
        STAA    RESIDUE         WHAT'S LEFT OVER IS RESIDUE FOR NEXT TIME
        TFR     B,A             COPY BYTE TO (A)
        JSR     WRITEATOSCREEN  KICK PICTURE BYTE TO SCREEN
        DEC     WIDTHCNT        MORE BYTES IN THIS PICTURE ROW ?
        BNE     PICTBYTE        YES, GO COPY TO SCREEN
PICTNEXTROW ; COMPUTE SCREEN ADDRESS OF NEXT PICTURE BYTE ROW
        LDAA    RESIDUE         BY COPYING RESIDUE TO SCREEN
        JSR     WRITEATOSCREEN
        DEC     DELTAY          MORE PICTURE ROWS TO SHOW ?
        BEQ     PICTXIT         NO, I GIVE UP
        LDB     #NBROW-1        MOVE DOWN THE SCREEN ONE ROW (-1 for RESIDUE)
        SUBB    PICTWIDTH       delta = bytes per row minus bytes displayed
        LEAU    B,U             U now points to next row leftmost picture byte
        ; assert: we cannot run off "top" of screen!
        BRA     PICTLINE        GO DRAW NEXT PICTURE LINE

DRAWSHF EQU     *       REMOTE PICTURE BYTE SHIFT TABLE
        PRSHIFT0                BIT 0
        PRSHIFT1                BIT 1
        PRSHIFT2                BIT 2
        PRSHIFT3                BIT 3
        PLSHIFT4                BIT 4
        PLSHIFT3                BIT 5
        PLSHIFT2                BIT 6
        PLSHIFT1                BIT 7

WRITEATOSCREEN ; write bit pattern in (A) to screen at (X)
;       (A) placed on screen according to current display mode (XOR, IOR, AND)
;       Current display mode selected by changing 1st opcode byte(s)
;       of this routine, which is in page zero for speed-of-access.
        NOP                     this is changed to COMA for AND mode
        EORA    ,U              combine bytes (changed to ORA for IOR mode)
        STA     ,U+             store byte onto screen, advance pointer
        RTS

       PAGE    REMOTE DRAWPICTURE
RDRAWPICTURE ; remote draw picture
        JSR     GETXY           GET X AND Y DIMENSIONS OF PICTURE
        STX     DELTAX          SAVE X SIZE OF PICTURE IN DOTS
        STAA    DELTAY          REMEMBER DEPTH OF PICTURE
        JSR     MAKESPACE       MAKE SURE ENOUGH SPACE ON SCREEN
        JSR     GENCURSORBYTE   FIGURE OUT WHERE FIRST BYTE GOES
        STX     TARGETLEFT
        LDX     #RDRAWSHF       COMPUTE POINTER TO SHIFT ROUTINE
        ASLB                    DOUBLE BIT INDEX FOR WORD BRANCH TABLE
        LDX     B,X             which shifts each picture before screen deposit
        STX     SHIFT           where to go to shift each byte
        LDD     DELTAX          COMPUTE PICTURE WIDTH IN BYTES
        ADDD    #7              ROUND WIDTH IN DOTS TO BYTES
        LSRD                    # DOTS + 7 <= 512 + 7 = 519 MAX
        LSRD
        LSRB
        BEQ     RPICTXIT        QUIT IF PICTURE IS ZERO BYTES WIDE
        STAB    PWIDTH          SAVE PICTURE WIDTH
RPICTLINE       EQU     *       DRAW REMOTE PICTURE LINE ON SCREEN
        LDAB    PWIDTH          GET NUMBER OF BYTES PER PICTURE ROW
        STAB    WIDTHCNT        USE AS LOOP LIMIT COUNT
        CLR     RESIDUE         ZERO THE RESIDUE BYTE
RPICTBYTE       EQU     *       DRAW REMOTE PICTURE BYTE ON SCREEN
        LDX     #RPICTXIT       GIVE UP IF BAD PICTURE BYTE SENT
        JSR     GETHEXBYTE      GET PICTURE BYTE TO PLACE ON SCREEN
        CLRB                    NEED 8 ZERO BITS TO SHIFT INTO
        JMP     [SHIFT]         GO SHIFT BYTE; THEN COPY TO SCREEN

RPRSHIFT3 LSRA                  SHIFT RIGHT 3
          RORB
RPRSHIFT2 LSRA                  SHIFT RIGHT 2
          RORB
RPRSHIFT1 LSRA                  SHIFT RIGHT 1
          RORB
RPRSHIFT0 ;                     SHIFT RIGHT 0
        ORAA    RESIDUE         COMBINE SHIFTED STUFF WITH RESIDUE FROM LAST TIME
        STAB    RESIDUE         WHAT'S LEFT OVER IS RESIDUE FOR NEXT TIME
        BRA     RPICTNEXT       FIGURE OUT WHERE NEXT BYTE SHOULD GO

RPLSHIFT4 ASLA                  LEFT SHIFT 4 PLACES
          ROLB
RPLSHIFT3 ASLA                  LEFT SHIFT 3 PLACES
          ROLB
RPLSHIFT2 ASLA                  LEFT SHIFT 2 PLACES
          ROLB
RPLSHIFT1 ASLA                  LEFT SHIFT 1 PLACE
          ROLB
        ORAB    RESIDUE         COMBINE WITH RESIDUE FROM BYTE TO LEFT
        STAA    RESIDUE         WHAT'S LEFT OVER IS RESIDUE FOR NEXT TIME
        TBA                     SET UP TO COPY BYTE TO SCREEN
RPICTNEXT ; STORE PICTURE BYTE
        LDU     CURSORBYTE      PLACE ON SCREEN TO PUT THE BYTE
        JSR     WRITEATOSCREEN  KICK PICTURE BYTE TO SCREEN
        STU     CURSORBYTE      STORE UPDATED SCREEN POINTER
        DEC     WIDTHCNT        MORE BYTES IN THIS PICTURE ROW ?
        BNE     RPICTBYTE       YES, GO COPY TO SCREEN
        LDU     CURSORBYTE      NO, FINISH OFF THIS ROW...
        LDAA    RESIDUE         BY COPYING RESIDUE TO SCREEN
        JSR     WRITEATOSCREEN
        DEC     DELTAY          MORE PICTURE ROWS TO SHOW ?
        BEQ     RPICTXIT        NO, I GIVE UP
        LDB     #NBROW-1        MOVE DOWN THE SCREEN ONE ROW (-1 for RESIDUE)
        SUBB    PICTWIDTH       delta = bytes per row minus bytes displayed
        LEAU    B,U             U now points to next row leftmost picture byte
        ; assert: we cannot run off "top" of screen!
        STU     CURSORBYTE      STORE NEW ROW POINTER
        BRA     RPICTLINE       GO DRAW NEXT PICTURE LINE

RPICTXIT        EQU     *
        JSR     EATCRLF         EAT TRAILING <CR><LF> IF SENT
        LDX     NEWX            UPDATE CURSORX PAST PICTURE
        STX     CURSORX
        RTS

^^^^^^ all picture draw routines need to check no overrun off top of physical
^^^^ screen memory
RDRAWSHF ; REMOTE PICTURE BYTE SHIFT TABLE
        RPRSHIFT0       BIT 0
        RPRSHIFT1       BIT 1
        RPRSHIFT2       BIT 2
        RPRSHIFT3       BIT 3
        RPLSHIFT4       BIT 4
        RPLSHIFT3       BIT 5
        RPLSHIFT2       BIT 6
        RPLSHIFT1       BIT 7
       PAGE    DISPLAY PRINTING CHARACTER
DISPLAYCHAR ; DISPLAY PRINTING CHARACTER (A)
        LDX     CURSORX         IS THIS LINE FULL ?
        CMPX    #(SCREENWIDTH-CHARWIDTH-1) ... ?
        BLS     CHAR1           NO, GO CHECK FOR OVERRUN BOTTOM OF SCREEN
        LDX     #CHARLEFTSIDE   CHARACTER WOULD RUN OFF RIGHT SIDE OF SCREEN
        STX     CURSORX         SO PUT CURSOR BACK TO LEFT SIDE OF SCREEN
        LDAB    CURSORY         NOW MOVE DOWN THE SCREEN A ROW
        SUBB    #CHARHEIGHT     RUN OFF BOTTOM OF SCREEN ?
;        **** WHAT IF CHARTOPSIDE <> 0 ??? what does this question mean???
        BLO     CHAR2           YES, MUST ROLL SCREEN
        STAB    CURSORY         (ADVANCE CURSORY DOWN A CHARACTER ROW)
CHAR1   EQU     *       CHECK FOR OVERRUN BOTTOM OF SCREEN
        LDAB    CURSORY         GET VERTICAL CURSOR POSITION
        CMPB    #CHARHEIGHT-1   DOES NEXT LINE RUN OFF BOTTOM OF SCREEN ?
        BHS     CHARPUTC        NO, JUST GO DISPLAY THE CHARACTER
CHAR2   EQU     *               MUST ROLL SCREEN MORE THAN 1 CHARACTER LINE
        SUBB    #CHARHEIGHT-1+(SCREENHEIGHT-(SCREENHEIGHT/CHARHEIGHT)*CHARHEIGHT)
*                               ADD ANOTHER LINE TO OVERRUN DISTANCE
CHARR   EQU     *               ROLL THE SCREEN; (B) = - # LINES
        PSHA                    SAVE THE CHARACTER, WE NEED IT LATER
        JSR     ROLLUPCHARLINE  ROLL THE SCREEN UP ONE CHARACTER LINE
        PULA                    GIMME MY CHARACTER BACK !
*       NEXT, WE OUTPUT THE CHARACTER TO THE SCREEN
CHARPUTC ; NOW PUT CHARACTER ON THE SCREEN
        SUBB    #$20            subtract of bias for control characters
        BEQ     CHARPUTX        b/ blank, clean up and exit
        LDB     #7              MULTIPLY CHARACTER BY 7
        MUL
        LDX     #CHARACTERSET-7 COMPUTE POINTER TO DOT MATRIX PATTERN
        LEAX    D,X
        STX     PICTURE         AND SAVE IT
        LDAA    CURSORY         IF WE ARE DISPLAYING A LETTER WITH A TAIL,
        LDX     PICTURE         (SMALL G,J,P,Q,Y)
        LDAB    0,X             THEN PLACE ON SCREEN 2 LINES BELOW NORMAL
        BPL     CPUT1           B/ NO TAIL
        SUBA    #2              TAIL, SKIP DOWN SCREEN TWO LINES
CPUT1   JSR     GENCURSORCHAR   GET POINTER TO BYTE WHICH CURSOR SELECTS
        STX     TARGETLEFT      SAVE POINTER TO LEFT TARGET BYTE
        ASLB                    DOUBLE BIT INDEX FOR WORD JUMP TABLE
        LDX     #CSHIFTBL       compute pointer to shift routine
        LDY     [B,X]
        LDAA    #7              GET NUMBER OF ROWS TO INSERT
        STAA    ROWCOUNT        SET UP LOOP LIMIT COUNTER
*
*       THE PUMP IS PRIMED, NOW LET'S INSERT THE CHARACTER DOT MATRIX
*
        LDX     PICTURE         GET POINTER TO CHARACTER ROW
        LDU     TARGETLEFT      GET POINTER TO LEFT HALF OF TARGET
        LDA     ,X+             FETCH 1ST ROW OF DOT MATRIX TO INSERT
        ANDA    #$1F            MASK OFF "TAIL" FLAG
        CLRB                    IN CASE WE MUST SHIFT RIGHT
        JMP     0,Y             GO SHIFT AND INSERT ROW

CHARPUTX ; DONE INSERTING CHARACTER ON SCREEN
        LDD     CURSORX         GRAB CURSOR POINTER
        ADDD    #CHARWIDTH      ADVANCE IT TO NEXT CHARACTER POSITION
        ; (THIS CANNOT OVERRUN THE RIGHT EDGE OF THE SCREEN)
        STD     CURSORX
        RTS                     RETURN TO CALLER

CSHIFTL3 ASLA                   SHIFT DOT MATRIX LEFT 3 BITS
CSHIFTL2 ASLA                   SHIFT DOT MATRIX LEFT 2 BITS
CSHIFTL1 ASLA                   SHIFT DOT MATRIX LEFT 1 BIT
CSHIFT0  JSR     WRITEATOSCREEN  STORE BIT PATTERN FOR CHARACTER TO SCREEN
        DEC     ROWCOUNT        ANY MORE ROWS LEFT TO INSERT ?
        BEQ     CHARPUTX        NO, JUST ADVANCE THE CURSOR
        LEAU    #NBROW-1        ADVANCE POINTER TO NEXT ROW
        LDA     ,X+             FETCH NEXT ROW OF DOT MATRIX
        CLRB                    IN CASE WE MUST SHIFT RIGHT
        JMP     ,Y              GO SHIFT AND INSERT CHARACTER ROW

CSHIFTR4 LSRA                   SHIFT RIGHT 4 PLACES
         RORB
CSHIFTR3 LSRA                   SHIFT RIGHT 3 PLACES
         RORB
CSHIFTR2 LSRA                   SHIFT RIGHT 2 PLACES
         RORB
CSHIFTR1 LSRA                   SHIFT RIGHT 1 PLACE
         RORB
        JSR     WRITEATOSCREEN
        TFR     B,A             COPY RIGHT HALF OF CHARACTER TO (A)
        JSR     WRITEATOSCREEN  INSERT RIGHT HALF OF CHARACTER
        DEC     ROWCOUNT        ANY MORE ROWS LEFT TO INSERT ?
        BEQ     CHARPUTX        NO, JUST ADVANCE THE CURSOR
        LEAU    #NBROW-2        ADVANCE POINTER TO NEXT ROW
        LDA     ,X+             FETCH NEXT ROW OF DOT MATRIX
        CLRB                    IN CASE WE MUST SHIFT RIGHT
        JMP     ,Y              GO SHIFT AND INSERT CHARACTER ROW

CSHIFTBL ; POINTERS TO CHARACTER SHIFT ROUTINES
        CSHIFTL3                BIT # =0 --> SHIFT LEFT 3
        CSHIFTL2                =1 --> LEFT 2
        CSHIFTL1                ETC.
        CSHIFT0
        CSHIFTR1
        CSHIFTR2
        CSHIFTR3
        CSHIFTR4
       PAGE    "GOTO ROUTINE" (THAT WAS DOWNLOADED BY HOST)
*       PROCESS REMOTE "GOTO" COMMAND

RGOTO   JSR     GETHEXBYTE      GET LEFT HALF OF TARGET ADDRESS
        STA     SHIFT           A SAFE PLACE TO USE
        JSR     GETHEXBYTE      GET RIGHT HALF OF TARGET ADDRESS
        STA     SHIFT+1
        LDD     SHIFT
        PSHD
*       RTS                     BYE!!!
*
*       EATCRLF -- EAT <CR><LF> OPTIONAL SEQUENCE
*       (<CR><LF> TERMINATES PARAMETERIZED GRAPHICS COMMAND)
*       (MAKES IT VERY CONVENIENT FOR "BASIC" PROGRAMS AND THE LIKE TO DRIVE GRAPHBOX)
*
EATCRLF JSR     GETDB           GET TERMINATOR CHARACTER
        CMPA    #CR             A CARRIAGE RETURN ?
        BNE     EATREJECT       B/ NO, OPTIONAL SEQUENCE NOT SUPPLIED
        JSR     GETDB           GET OPTIONAL <LF>
        CMPA    #LF             IS IT ?
        BEQ     EATRTS          B/ YES, IT'S GONE !
EATREJECT       EQU     *
        INC     CHARREJECT      NO, LET SOMEBODY PROCESS IT!
EATRTS  RTS
       PAGE    CURSOR CONTROL
RSETCURSORX     EQU     *       REMOTE SET CURSORX
        BSR     GETX            GET THE X VALUE
        BSR     EATCRLF         EAT COMMAND TERMINATOR
        LDX     TARGETX         GET X VALUE BACK
SETCURSORX      EQU     *       SETS X VALUE OF CURSOR TO (X)
        STX     CURSORX
        RTS

RSETCURSORY     EQU     *       REMOTE SET Y VALUE OF CURSOR TO 0..255
        BSR     GETY            WAIT FOR PARAMETER TO ARRIVE
        BSR     EATCRLF         EAT COMMAND TERMINATOR
        LDAA    TARGETY         GET Y VALUE BACK
SETCURSORY      EQU     *       SETS Y VALUE OF CURSOR TO (A)
        STAA    CURSORY         STORE AS CURSORY Y VALUE
        RTS                     AND EXIT

RSETCURSORXY    EQU     *       REMOTE SET CURSORX, CURSORY
        BSR     GETXY           GET BOTH X AND Y PARAMETERS
SETCURSORXY     EQU     *       SET CURSOR X TO (X), CURSORY TO (A)
        STX     CURSORX
        STAA    CURSORY
        RTS
       PAGE
*       GETX-- GET X DIMENSION
*       MASKS TO 9 BITS, RETURNED IN (A,B) AND (X)
*
GETX    LDX     #RETURN         NO RECOVERY IF ERROR IN PARAMETER
GETXX   JSR     GETINTEGERX     GO CONVERT INPUT STREAM VALUE
        ANDA    #(SCREENWIDTH-1)/256    MASK TO 9 BITS
        STD     TARGETX         save as TARGETX
        TFR     D,X             meet contract
        RTS
*
*       GETY-- GET Y DIMENSION
*       MASKED TO 8 BITS, RETURNED IN (A) ONLY
*
GETY    LDX     #RETURN         NO RECOVERY IF ERROR IN PARAMETER
GETYX   JSR     GETINTEGERX     GO CONVERT INPUT STREAM VALUE
        TFR     B,A             COPY VALUE TO (A) AS PROMISED
        STAA    TARGETY         SAVE IT, JUST IN CASE...
        RTS
*
*       GETXY-- GET X AND Y DIMENSIONS
*       SELECTS "NO ERROR RECOVERY"
*       RETURNS X DIMENSION IN (X) AND Y IN (A)
*       CALLS "EATCRLF"
*
GETXY   BSR     GETX            GO GET THE X VALUE
        BSR     GETY
        BSR     EATCRLF
        LDX     TARGETX         GET STORED X AND Y PARAMETERS
        LDAA    TARGETY
        RTS
       PAGE    DRAW DOT
RDOTCURSORXY    EQU     *       SET CURSOR, THEN DRAW DOT
        BSR     GETXY
DOTCURSORXY     EQU     *       SET CURSOR X,Y AND DRAW DOT
        BSR     SETCURSORXY
*       DRAWDOT  --  SUBROUTINE TO DRAW DOT AT (CURSORX, CURSORY)
*
DRAWDOT EQU     *
        JSR     GENCURSORBYTE   GET BIT NUMBER
        LDX     #BITMSK         CONVERT BIT NUMBER TO BIT MASK
        LDA     B,X
        LDU     CURSORBYTE      GO UPDATE THE SELECTED BYTE
        JMP     WRITEATOSCREEN  MODIFY THE DISPLAY MEMORY
*       RTS

BITMSK  FCB     %10000000       BIT # 0
        FCB     %01000000       BIT # 1
        FCB     %00100000       BIT # 2
        FCB     %00010000       BIT # 3
        FCB     %00001000       BIT # 4
        FCB     %00000100       BIT # 5
        FCB     %00000010       BIT # 6
        FCB     %00000001       BIT # 7
       PAGE    DRAW DOT AND MOVE CURSOR ROUTINES
DOTAMCU ; DRAW DOT AND MOVE CURSOR UP
        BSR     DRAWDOT
MOVECU ; MOVE CURSOR UP
        BRA     BUMPCURSORY     MOVE CURSOR UP

DOTAMCUR ; DRAW DOT AND MOVE CURSOR UP AND RIGHT
        BSR     DRAWDOT
MOVECUR ; MOVE CURSOR UP AND RIGHT
        BSR     BUMPCURSORY
        BRA     BUMPCURSORX

DOTAMCR ; DRAW DOT AND MOVE CURSOR RIGHT
        BSR     DRAWDOT
MOVECR ; MOVE CURSOR RIGHT
        BRA     BUMPCURSORX

DOTAMCRD ; DRAW DOT AND MOVE CURSOR RIGHT AND DOWN
        BSR     DRAWDOT
MOVECRD ; MOVE CURSOR RIGHT AND DOWN
        BSR     BUMPCURSORX
        BRA     DECCURSORY

DOTAMCD ; DRAW DOT AND MOVE CURSOR DOWN
        BSR     DRAWDOT
MOVECD ; MOVE CURSOR DOWN
        BRA     DECCURSORY

DOTAMCDL ; DRAW DOT AND MOVE CURSOR DOWN AND LEFT
        BSR     DRAWDOT
MOVECDL ; MOVE CURSOR DOWN AND LEFT
        BSR     DECCURSORY
        BRA     DECCURSORX

DOTAMCL ; DRAW DOT AND MOVE CURSOR LEFT
        BSR     DRAWDOT
MOVECL ; MOVE CURSOR LEFT
        BRA     DECCURSORX

DOTAMCLU ; DRAW DOT AND MOVE CURSOR LEFT AND UP
        BSR     DRAWDOT
MOVECLU ; MOVE CURSOR LEFT AND UP
        BSR     DECCURSORX
        BRA     BUMPCURSORY
*      BUMPCURSORX -- BUMPS CURSORX OR LEFT ROTATES THE SCREEN
*
BUMPCURSORX     EQU     *
        LDX     CURSORX         DO WHAT WE SAID !
        CPX     #SCREENWIDTH-1  AT RIGHT EDGE OF SCREEN ?
        BEQ     ROLLSCREENLEFT  (B/ YES)
        INX                     NO, SO BUMP THE CURSORX
        STX     CURSORX         SAVE UPDATED VALUE
        RTS                     AND EXIT

*       DECCURSORX -- DECREMENT CURSORX OR RIGHT ROTATE THE SCREEN
*
DECCURSORX      EQU     *
        LDX     CURSORX         DO WHAT HE SAID
        BEQ     ROLLSCREENRIGHT AT LEFT EDGE OF SCREEN ?
        DEX                     NO, SO DECREMENT THE CURSORX
        STX     CURSORX         STORE THE UPDATED VALUE
        RTS                     AND EXIT
*      BUMPCURSORY -- BUMPS CURSORY OR ROLLS SCREEN DOWN
*
BUMPCURSORY     EQU     *
        INC     CURSORY         DO IT
        BNE     BUMPRTS         EXIT IF ITS OK
        DEC     CURSORY         RAN OFF TOP OF SCREEN
ROLLSCREENDOWN  EQU     *
        LDAA    UPSHIFTDIST     MODIFY UPSHIFT INSTEAD
        DECA            BY SUBTRACTING ONE
*
*       MODIFYSCREENSHIFT -- SETS LOGICAL UP SHIFT DISTANCE TO (A)
*       ALSO SETS HARDWARE DOWN SHIFT CONTROL REGISTER
*       DESTROYS (A),(B)
*
MODIFYSCREENSHIFT       EQU     *
        STAA    UPSHIFTDIST     STORE NEW VALUE FOR UPSHIFT OF SCREEN
        LSRA                    (A):=INT(UPSHIFT/64)
        RORB                    PUT RESULT IN (A,B)
        LSRA
        RORB
        RORB                    POSITION ROW ADJUST BITS FOR PIA
        ORAA    #DISPLAYRAMENABLE       REASONABLE ASSUMPTION: IF YOU'RE IN HERE,...
        STAA    JOYSTICKDATA    THE SCREEN IS ACCESSIBLE! (OUTPUT ROW ADJUST BITS)
        CLRB            (UPSHIFT/64)*64 IS MA14-0 FOR CRTC
        LSRA
        RORB
        LSRA                    SHIFT NEW MA14-0 TO BOTTOM OF (A,B)
        RORB
        PSHB                    WHAT'S LEFT IS THE MA14-0 BIAS NEEDED
        LDAB    #CRTCSTARTADDRH SO TELL THE CRT CONTROLLER CHIP!
        STAB    CRTCREGISTERSELECT
        STAA    CRTCREGISTER
        INCB                    (=LDAB #CRTCSTARTADDRL)
        STAB    CRTCREGISTERSELECT
        PULB
        STAB    CRTCREGISTER
        RTS
        if      colorcomputer
        ; for color computer, must actually shuffle screen store!
MODIFYSCREENSHIFT       EQU     *
        ldx     #ScreenBottom
        ldb     #nbperrow       figure out distance to top of screen
        mul
        leax    d,x
        ...
MODIFYSCREENSHIFTSHUFFLE
        ldd     -16,x
        std     -16,y
        ldd     -14,x
        std     -14,y
        ldd     -12,x
        std     -12,y
        ldd     -10,x
        std     -10,y
        ldd     -8,x
        std     -8,y
        ldd     -6,x
        std     -6,y
        ldd     -4,x
        std     -4,y
        ldd     -2,x
        std     -2,y
        ldd     ,x
        std     ,y
        ldd     2,x
        std     2,y
        ldd     4,x
        std     4,y
        ldd     6,x
        std     6,y
        ldd     8,x
        std     8,y
        ldd     10,x
        std     10,y
        ldd     12,x
        std     12,y
        ldd     14,x
        std     14,y
        leax    32,x
        leax    32,y
; assert: number of bytes per row is divisible by 8
        dec     tempx
        bne     modifyscreenshiftshuffle
        rts
; this routine neeeds a lot of work!
        fin
*
*       DECCURSORY -- DECREMENTS CURSORY OR ROLLS SCREEN UP
*
DECCURSORY      EQU     *
        LDAA    CURSORY         ARE WE AT BOTTOM OF SCREEN ?
        BNE     DECCURSORY1     NO, WE CAN DO IT!
ROLLSCREENUP    EQU     *
        LDAA    UPSHIFTDIST     RATS, MUST ROLL SCREEN UP
        INCA                    INCREMENT THE LOGICAL UPSHIFT
        BRA     MODIFYSCREENSHIFT

DECCURSORY1     EQU     *
        DECA                    DO WHAT WE PROMISED
        STAA    CURSORY
BUMPRTS RTS                     AND GET OUT...
        if      colorcomputer
*       GENCURSORBYTE -- RETURNS POINTER TO BYTE ON SCREEN IN (X)
*       WHICH CONTAINS THE BIT SPECIFIED BY CURSORX, CURSORY
*       ALSO SETS CURSORBYTE TO (X)
*       (B) = BIT NUMBER  (0 = MSB, 7 = LSB)
*       BYTE = CURSORY*ROWSIZE+INT(CURSORX/8)
*       BIT = CURSORX MOD 8
*
*       GENCURSOR1 IS ENTRY POINT WITH (A,B) = X POSITION
*               AND TOP OF STACK = Y POSITION
*
; on color computer, x and y are limited to 255!!!
GENCURSORBYTE   EQU     *
        LDAA    CURSORY         GET Y POSITION
GENCURSORCHAR ; ENTRY TO GENERATE CURSORBYTE FOR CHARACTER DISPLAY
        LDX     #SCREENBOTTOM   = (0,0)
        LDB     #NBPROW
        MUL
        PSHD                    (D) = offset to desired screen row
        LDD     CURSORX
        LSRD                    compute cursorx divided by 8
        lsrb                    ...=/4; assert: (A)=0
        lsrb                    ...=/8
        addd    ,s++            combine with row offset
        leax    d,x             pointer to desired location
        STX     CURSORBYTE      SAVE POINTER WHERE WE PROMISED
        LDB     CURSORX         GET BIT NUMBER BACK
        ANDB    #7              = CURSORX MOD 8
        RTS                     AND EXIT

GENCURSOR1 ; ENTRY POINT FOR "SPLAT2"
; this routine is wrong!
;       (A) = Y position
;       (B) = X position
        LDX     #SCREENBOTTOM   = (0,0)
        LDB     #NBPROW
        MUL
        PSHD                    (D) = offset to desired screen row
        LDD     CURSORX
        LSRD                    compute cursorx divided by 8
        lsrb                    ...=/4; assert: (A)=0
        lsrb                    ...=/8
        addd    ,s++            combine with row offset
        leax    d,x             pointer to desired location
        STX     CURSORBYTE      SAVE POINTER WHERE WE PROMISED
        LDB     CURSORX         GET BIT NUMBER BACK
        ANDB    #7              = CURSORX MOD 8
        RTS                     AND EXIT
        else
*       GENCURSORBYTE -- RETURNS POINTER TO BYTE ON SCREEN IN (X)
*       WHICH CONTAINS THE BIT SPECIFIED BY CURSORX, CURSORY
*       ALSO SETS CURSORBYTE TO (X)
*       (B) = BIT NUMBER  (0 = MSB, 7 = LSB)
*       BYTE = [(255-CURSORY+UPSHIFT) MOD 256]*64...
*               +INT(CURSORX/8)
*       BIT = CURSORX MOD 8
*
*       GENCURSOR1 IS ENTRY POINT WITH (A,B) = X POSITION
*               AND TOP OF STACK = Y POSITION
*
GENCURSORBYTE   EQU     *
        LDAA    CURSORY         GET Y POSITION
GENCURSORCHAR   EQU     *       ENTRY TO GENERATE CURSORBYTE FOR CHARACTER DISPLAY
        PSHA            AND PUSH ONTO STACK
        LDD     CURSORX         GET X POSITION
GENCURSOR1      EQU     *       ENTRY POINT FOR "SPLAT2"
        STAB    TEMPB           SAVE THIS, WE'LL NEED IT LATER
        LSRD                    TAKE MODULUS 512 AND DIVIDE BY 2
        PULA                    GET Y VALUE
        COMA                    = 255-Y
        ADDA    UPSHIFTDIST     MULTIPLIED BY 256
        LSRD                    DIVIDE BY 4 LEAVING ROW NUMBER * 256/4 (=64)
        LSRD                    AND COLUMN NUMBER DIVIDED BY 8
        ORAA    #SCREENBOTTOM/256       ADD DISPLACEMENT TO SCREEN BASE
        STD     CURSORBYTE      SAVE POINTER WHERE WE PROMISED
        LDX     CURSORBYTE      ALSO LOAD IN X
        LDAB    TEMPB   GET BIT NUMBER BACK
        ANDB    #7              = (CURSORX + LEFTSHIFT) MOD 8
        RTS                     AND EXIT
        fin
*       CLEARLINES -- SUBROUTINE TO CLEAR HORIZONTAL SCREEN LINES
*       (X) POINTS TO 1ST BYTE OF LINE
*       (B) CONTAINS LINE COUNT
*       CLEARS LINES ABOVE AND INCLUDING (X) ON SCREEN
*
CLEARLINES      EQU     *
        LEAX    16,X            to compensate for STD -16,X below
        STB     COUNT
        LDD     #0              GET ZEROS TO STORE
CLEARLOOP       EQU     *
        RPT     16
        STD     *-CLEARLOOP-16,X clear 64 bytes (1 screen row)
        LEAX    32,X            advance (X) to "start" of next row
        DEC     COUNT           ALL ROWS ZEROED ?
        BNE     CLEARLOOP       B/ no, go clear another!
CLEARRTS
        RTS
        PAGE    DRAWLINE -- ROUTINE TO DRAW LINE FROM CURSOR TO TARGET
*
*       T. MOORE SHOWS ALGORITHM THAT PRODUCES 1 NEW LINE DOT PER ITERATION
*       USE IT???
*
RDRAWLINE       EQU     *       REMOTE ENTRY POINT TO DRAW A LINE
        JSR     GETXY           WAIT FOR TARGET POINT TO ARRIVE
DRAWLINE        EQU     *       ENTERED WITH (X)=TARGETX, (D)=TARGETY
        STX     TARGETX         SAVE THIS, WE NEED IT LATER
        STD     TARGETY         SAVE TARGETY, TOO.
        SUBD    CURSORY         COMPUTE DELTAY
        STD     DELTAY
        LDA     #0              DELTAYSIGN = BORROW FROM DELTAY COMPUTATION
        SBCA    #0
        STA     DELTAYSIGN
        LDD     TARGETX         COMPUTE DELTAX
        SUBD    CURSORX+1
        STD     DELTAX
        LDA     #0              COMPUTE DELTAXSIGN
        SBC     #0              = BORROW OF DELTA X COMPUTATION
        STA     DELTAXSIGN
        ORAB    DELTAX          NON-ZERO LENGTH LINE ?
        ORAB    DELTAY
        ORAB    DELTAY+1        ...
        BEQ     CLEARRTS        NO, LINE SEGMENT IS NULL
        LDX     #POINT5         SET UP THE FRACTIONAL PARTS OF CURSORX,CURSORY
        STX     FRACTIONX       FOR AUTOMATIC ROUNDING
        STX     FRACTIONY
DRAWNORMLOOP    EQU     *       LOOP TO NORMALIZE SLOPE OF LINE
        LDAA    DELTAXSIGN      "NORMALIZED" MEANS MAXIMIZE DELTAX, DELTAY...
        EORA    DELTAX          WITHOUT CHANGING LINE SLOPE
        BMI     DRAWLINEBIT     NORMALIZATION COMPLETE
        LDAA    DELTAYSIGN      NORMALIZATION OCCURS...
        EORA    DELTAY          WHEN SIGN OF THE DELTA...
        BMI     DRAWLINEBIT     IS DIFFERENT THAN MSB OF DELTA
        ASL     DELTAX+1        SLOPE NOT YET NORMALIZED...
        ROL     DELTAX          SO DOUBLE BOTH DELTAX AND DELTAY
        ASL     DELTAY+1        WHICH LEAVES SLOPE THE SAME
        ROL     DELTAY          REASON FOR NORMALIZING IS TO SPEED...
        BRA     DRAWNORMLOOP    DDA GENERATION OF DOTS

DRAWLINEBIT ; NEW DOT REACHED, TURN ON THE BIT
        JSR     DRAWDOT         at current cursor location
; ?? substitute code inline here ??
DRAWLINEDDA     EQU     *       NOW GENERATE NEXT DOT POSTION BY DDA TECHNIQUE
        LDD     FRACTIONX       ADD DELTAX TO (CURSORX,FRACTIONX)
        ADDD    DELTAX          IF CURSOR CHANGES, A NEW DOT IS REACHED
        STD     FRACTIONX       OTHERWISE, REPEAT THE DDA LOOP
        LDD     CURSORX         THIS LOOP CANNOT OCCUR MORE THAN TWICE...
        ADCB    DELTAXSIGN      WITHOUT A NEW POINT BEING GENERATED,
        ADCA    DELTAXSIGN      SINCE THE DELTAS ARE NORMALIZED...
        LDX     CURSORX         WITH RESPECT TO UNITY IN CURSORX, CURSORY
        STD     CURSORX         (I.E., .5 <= DELTA < 1) SAVE NEW CURSORX
        LDD     FRACTIONY       NOW ADD DELTAY TO (CURSORY,FRACTIONY)
        ADDD    DELTAY          SAME TRICK AS FOR CURSORX COMPUTATION
        STD     FRACTIONY
        LDD     CURSORY
        ADCB    DELTAYSIGN
        ADCA    DELTAYSIGN      COMPUTE NEW CURSORY
        CMPD    CURSORY         DID CURSORY CHANGE ?
        BNE     DRAWLINECOMPARE B/ YES, GO SEE IF ENDPOINT FOUND
        CMPX    CURSORX         DID CURSORX CHANGE ?
        BEQ     DRAWLINEDDA     NO, NEXT PASS WILL CHANGE CURSOR FOR SURE
DRAWLINECOMPARE EQU     *       CHECK TO SEE IF AT ENDPOINT OF LINE
        STD     CURSORY         UPDATE CURSORY
        CMPD    TARGETY         ... ?
        BNE     DRAWLINEBIT     NOPE
        LDX     CURSORX         AT TARGET POINT YET ?
        CMPX    TARGETX         WELL ?
        BNE     DRAWLINEBIT     NO, GO TURN ON THE BIT
        RTS                     HIT END OF LINE, QUIT HERE !
       PAGE    CHARACTER CURSOR CONTROL
NEWPAGE EQU     *
        LDX     #SCREENBOTTOM   ZERO THE ENTIRE SCREEN
        LDAB    #SCREENHEIGHT&$FF
        JSR     CLEARLINES
        LDX     #CHARLEFTSIDE   POSITION CURSOR...
        STX     CURSORX         AT TOP LEFT CORNER OF SCREEN
        LDX     #CHARTOPSIDE
        STX     CURSORY
        CLR     CURSORON        FORCE RE-DRAWING OF CURSOR...
        CLR     CROSSON         AND CROSSHAIRS
        LDX     #(0-CROSSXFUDGE-1)&(SCREENWIDTH-1)
        STX     CROSSX          MAKE CROSSHAIRS DISAPPEAR
        LDX     #(0-CROSSYFUDGE-1)&(SCREENHEIGHT-1)
        STX     CROSSY
        RTS                     ALL DONE !

RSETCHCURSOR    EQU     *
        JSR     GETDB           WAIT FOR ROW NUMBER TO ARRIVE
        PSHA                    SAVE ROW NUMBER
        JSR     GETDB           WAIT FOR COLUMN NUMBER TO ARRIVE
        TFR     A,B             COPY TO (B)
        PULA                    RESTORE ROW NUMBER
SETCHCURSOR     EQU     *       (A)= ROW, (B)= COLUMN
        PSHB                    save column number
        LDAB    #CHARHEIGHT     Scan lines/character row
        MUL                     = Scan lines to skip (assert: < 256!)
        NEGB                    ROW #0 = MAX Y POSITION
        ADDB    #CHARTOPSIDE-1
        CLRA
        STD     CURSORY+1
        PULB                    get character column number
        LDAA    #CHARWIDTH      convert to X dot number
        MUL
        ADDD    #CHARLEFTSIDE   add position of leftmost character column
        STD     CURSORX         RESULT <= 511 GAURANTEED!!
        RTS
        PAGE
BACKSPACE       EQU     *       BACKSPACE THE CHARACTER CURSOR AND ERASE
        LDD     CURSORX         GET CURRENT CURSOR POSITION
        SUBD    #CHARWIDTH      BACK UP ONE CHARACTER WIDTH
        BCC     BACKSPACE1      B/ DIDN'T RUN OFF LEFT SIDE OF SCREEN
        LDD     #CHARLEFTSIDE   DID RUN OFF LEFT SIDE, STOP IT AT LEFT SIDE
BACKSPACE1      EQU     *
        STD     CURSORX         UPDATE CURSOR POSITION
        LDX     #CHARWIDTH      NOW STOMP ON THE CHARACTER
        LDD     #CHARHEIGHT
        JSR     BLANKREGION
CHCURSORLEFT    EQU     *       MOVE CHARACTER CURSOR LEFT
        LDD     CURSORX         GET CURRENT CURSOR POSITION
        SUBD    #CHARWIDTH      MOVE IT LEFT 6 DOT POSITIONS
        BCS     ENDLINE         GO IF RUNS OFF LEFT SIDE OF SCREEN
CHCURSORXSTAB   EQU     *       STORE (A,B) INTO CURSORX
        STD     CURSORX
        RTS

CHCURSORRIGHT   EQU     *       MOVE CURSOR ON CHARACTER POSITION TO THE RIGHT
        LDD     CURSORX         GET THE CURRENT CURSOR
        ADDD    #CHARWIDTH      ADVANCE TO RIGHT 6 COLUMNS
        CMPD    #(SCREENWIDTH/CHARWIDTH*CHARWIDTH-CHARWIDTH)/256
        BLS     CHCURSORXSTAB   GO IF UPDATED VALUE IS OK
CHCURSORXMAX    EQU     *       NEW VALUE FOR CURSOR IS PAST RIGHT SIDE OF SCRREN
        LDX     #(SCREENWIDTH/CHARWIDTH)*CHARWIDTH-CHARWIDTH
        STX     CURSORX         FORCE TO RIGHTMOST SCREEN CHARACTER POSITION
        RTS                     AND QUIT

ENDLINE EQU     *       END OF LINE SEEN ($0D)
        LDX     #CHARLEFTSIDE   MOVE CURSOR TO LEFT SIDE OF SCREEN
        STX     CURSORX         WITHOUT MOVING DOWN A ROW
        RTS                     GO PROCESS THE NEXT COMMAND
        PAGE
CHCURSORUP      EQU     *       MOVE CURSOR UP ONE CHARACTER ROW
        LDD     CURSORY         GET CURRENT ROW POSITION
        ADDD    #CHARHEIGHT     BUMP IT BY ONE CHARACTER ROW
        CMPD    #SCREENHEIGHT-1 OFF TOP OF SCREEN ?
        BLS     CHCURSORYSTAB   GO STORE THE VALUE IF NOT OFF TOP OF SCREEN
        LDD     #SCREENHEIGHT-1 OFF TOP OF SCREEN, MOVE BACK
CHCURSORYSTAB   EQU     *       STORE (A) INTO CURSORY
        STD     CURSORY         DO IT !
        RTS

CHCURSORDOWN    EQU     *       MOVE CURSOR DOWN ONE CHARACTER ROW
        LDD     CURSORY         GET CURRENT ROW POSITION
        SUBD    #CHARHEIGHT     MOVE DOWN SCREEN ONE CHARACTER ROW
        BCS     CHCURSORYMIN    OOPS, RAN OFF BOTTOM OF SCREEN
        CMPD    #CHARHEIGHT-1   NOT QUITE, STILL A CHARACTER ROW LEFT ?
        BCC     CHCURSORYSTAB   YES, GO STORE VALUE
CHCURSORYMIN    EQU     *       RAN OFF BOTTOM OF SCREEN, ROLL SCREEN
        SUBD    #CHARHEIGHT-1+(SCREENHEIGHT-(SCREENHEIGHT/CHARHEIGHT)*CHARHEIGHT)
*                               COMPUTE MINUS NUMBER OF LINES TO CLEAR
*
*       ROLLUPCHARLINE -- ROLL SCREEN UP -(B) SCREEN LINES AND CLEAR
*       ADJUSTS UPSHIFT
*       SETS CURSORY TO CHARHEIGHT-1
*       (= LOWEST ROW ON SCREEN WHICH DOESN'T CHOP OFF PART OF A ROW AT THE TOP)
*
ROLLUPCHARLINE  EQU     *
        LDAA    UPSHIFTDIST     DO WE HAVE TO CLEAR TWO BLOCKS OF LINES ?
        SBA                     (COMPUTE NEW UPSHIFT VALUE)
        BCC     ROLLUPCHARLINE2 B/ NO, CLEARING A SINGLE BLOCK OF LINES WILL DO
*********** NEEDS WORK ****************
*!!! no kidding....
        LDAA    UPSHIFTDIST     UP SHIFT = 0 OR > 127 ?
        BLE     ROLLUPCHARLINE1 YES, CLEAR A SINGLE BLOCK OF LINES
        SBA                     NO, COMPUTE NEW DOWN SHIFT
        BPL     ROLLUPCHARLINE2 IF >= 0, GO CLEAR A BLOCK OF SCREEN LINES
        PSHA                    SAVE NEW UPSHIFT
        SBA                     OLD UPSHIFT IS # LINES...
        TAB                     AT SCREENBOTTOM TO CLEAR
        LDX     #SCREENBOTTOM   GO CLEAR THEM
        JSR     CLEARLINES
        PULB                    GET NEW UPSHIFT, WHICH IS ALSO...
        CLRA                    THE NEGATIVE OF # LINES TO CLEAR AT SCREENTOP
ROLLUPCHARLINE1 EQU     *
        SBA                     COMPUTE NEW UP SHIFT
ROLLUPCHARLINE2 EQU     *
        PSHB            SAVE NUMBER OF LINES TO CLEAR
        JSR     MODIFYSCREENSHIFT       TELL THE HARDWARE ABOUT IT
        PULB            RESTORE # LINES TO CLEAR
        LDAA    UPSHIFTDIST     WE NEED THIS IN A MOMENT...
        ABA             = LINE # OF FIRST LINE TO CLEAR
        NEGB                    CONVERT - LINE COUNT TO + LINE COUNT
        PSHB                    NUMBER OF SCREEN LINES TO ZERO
        LDAB    #1              COMPUTE ADDRESS OF 1ST LINE TO ZERO
        LSRD                    = SCREENBOTTOM + (UPSHIFT-ROLLCOUNT) * 64
        RORD
        TFR     D,X             GET ADDRESS OF 1ST LINE TO ZERO
        PULB                    FETCH # LINES TO CLEAR
*       CLRA
        JSR     CLEARLINES      GO ZERO THEM
        LDD     #CHARHEIGHT-1+(SCREENHEIGHT-(SCREENHEIGHT/CHARHEIGHT)*CHARHEIGHT)
*                               SET NEW CURSOR POSITION...
        STD     CURSORY         TO TOP OF BOTTOM CHARACTER LINE
        RTS                     WHEW! ALL DONE
       PAGE    ASSOCIATE PICTURE
RASSOCIATE      EQU     *
; should allow 96 remotely associated pictures, so user can define own char set
        JSR     CHECKFORUSERRAM AND DON'T RETURN IF THERE ISN'T ANY!
        JSR     GETDB           NOW GET ASSOCIATION CODE
        ANDA    #$3F            ONLY 64 CODES; IGNORE GARBAGE
        ASLA                    TWO BYTES PER ASSOCIATION TABLE ENTRY
        LDX     #ASSOCIATIONTBL FIND SLOT IN ASSOCIATION TABLE
        LEAX    A,X
        STX     PICTUREP        SAVE POINTER TO PICTUTE POINTER IN TABLE
        JSR     GETXY           GET PICTURE X AND Y DIMENSIONS
        STX     DELTAX          SAVE PICTURE X SIZE IN DOTS
        STD     DELTAY          SAVE PICTURE Y DIMENSION
        LDX     PICTUREP        ARE WE GETTING A NEW ASSOCIATION ?
        LDX     0,X             (IS TABLE ENTRY NULL ?)
        BEQ     ASSOCIATEINSERT YES, JUST GO DO IT
        STX     PICTURE         NO, MUST DUMP OLD PICTURE ASSOCIATION
        JSR     PICTURESIZE     DECIDE HOW BIG OLD PICTURE IS (IN BYTES)
        LDX     #ASSOCIATIONTBL RELOCATE REST OF ASSOCIATED PICTURE POINTERS
RASSOCL ; RELOCATE A POINTER FROM ASSOCIATION TSBLE
        LDD     ,X++            GET POINTER TO RELOCATE
        CMPD    PICTURE         DOES IT POINT INTO REGION WE WILL SHUFFLE DOWN ?
        BLS     RASSOC2         (NO)
        SUBD    TEMPX           SUBTRACT SIZE OF OLD PICTURE FROM POINTER
        STD     -2,X            UPDATE ASSOCIATION TABLE ENTRY
RASSOC2 EQU     *       NOW ADVANCE TO NEXT ASSOCIATION TABLE ENTRY
        CPX     #ASSOCTBLEND    DONE WITH ENTIRE TABLE ?
        BNE     RASSOCL         NW, GO RELOCATE ANOTHER POINTER
*       ALL ASSOCATION TABLE POINTERS READJUSTED
*       NOW SHUFFLE DOWN OTHER PICTURES TO RECAPTURE THE SPACE
        LDD     PICTOP          COMPUTE NEW "TOP OF ASSOCIATED PICTURE REGION"
        SUBD    TEMPX           = OLD TOP MINUS SIZE OF PICTURE TE ARE DELETING
        STD     PICTOP          (PICTOP POINTS TO 1ST UNUSED BYTE)
        LDD     PICTURE         FORM "COPY FROM..." POINTER
        ADDD    TEMPX           = OLD PICTURE ADDRESS + OLD PICTURE SIZE
        STD     TEMPX
        LDX     PICTURE         DO WE HAVE TO SHUFFLE ?
        CPX     PICTOP          (DELETING LAST PICTURE ?)
        BEQ     ASSOCIATEINSERT NO, JUST SKIP SHUFFLE STEP
        LDU     TEMPX           POINTS TO 1ST BYTE TO SHUFFLE DOWN
SHUFFLEPICTURES EQU     *
        LDA     ,U+             GET THE BYTE TO SHUFFLE DOWN
        STA     ,X+             DO THE OBVIOUS
        CPX     PICTOP          SHUFFLE COMPLETED ?
        BNE     SHUFFLEPICTURES LOOP UNTIL DONE
ASSOCIATEINSERT EQU     *
        LDX     #DELTAX         COMPUTE SIZE OF NEW PICTURE
        JSR     PICTURESIZE
        LDX     PICTUREP        SET ASSOCIATION TABLE ENTRY...
        LDD     PICTOP          POINTING TO WHERE WE WILL PUT PICTURE BODY
        STD     0,X
        ADDD    TEMPX           COMPUTE NEW TOP OF ASSOCIATED PICTURE REGION
        STD     PICTOP
        LDX     0,X             FIND OUT WHERE WE PUT THE PICTURE
        LDD     DELTAX          COPY PICTURE X AND Y BOUNDS...
        STD     PICTXSIZ,X      INTO THE HEADER FOR THE PICTURE
        LDD     DELTAY          ...
        STD     PICTYSIZ,X
        LEAX    PICTUREBODY,X   BUMP (X) PAST PICTURE HEADER
ASSOCIATELOOP   EQU     *       COLLECT PICTURE BYTES
        CPX     PICTOP          ALL PICTURE BYTES STORED ?
        BEQ     ASSOCIATERTS    YES, SO EXIT
        STX     PICTURE         NO, SAVE POINTER TO NEXT PICTURE BYTE
        JSR     GETHEXBYTE      GET THE PICTURE BYTE
        LDX     PICTURE         WHERE TO PUT BYTE, I WONDER ?
        STA     ,X+             HOW 'BOUT HERE ?
        BRA     ASSOCIATELOOP   GO STORE ANOTHER

ASSOCIATERTS    EQU     *       THIS IS OUR ACE UP OUR SLEEVE !
        JSR     EATCRLF         EAT CRMMAND TERMINATOR
        RTS                     DONE ! (WHEW...)
*      PICTURESIZE -- (X) POINTS TO (XSIZE, YSIZE)
*       RETURNS IN (A,B) THE SIZE OF THE PICTURE BLOCK IN BYTES
*
PICTURESIZE     EQU     *
        LDD     PICTXSIZ,X      GET X SIZE IN DOTS
        ADDD    #7              ROUND UP TO BYTES (PER BOW OF PICTURE)
        LSRD                    = (SIZE IN DOTS + 7) / 8
        LSRD                    COULD NOT EXCEED 512+7 = 519 DOTS
        LSRD                    ASSERT: PICTURE WIDTH < 256*8 BITS
        STAB    MULTIPLIER      SAVE MULTIPLIER
        LDD     PICTYSIZ,X      MULTIPLY ROW SIZE IN BYTES BY Y SIZE
        STD     TEMPX           SAVE MULTIPLICAND
        LDD     #0              ZERO THE PRODUCT
        ASR     MULTIPLIER      LOOK AT NEXT MULTIPLIER BIT
        BCC     PICTURESHIFT
PICTUREADD      EQU     *
        ADDD    TEMPX           MULTIPLIER BIT = 1, ADD MULTIPLICAND TO PRODUCT
PICTURESHIFT    EQU     *
        ASL     TEMPB           DOUBLE MULTIPLICAND TO COMPENSATE...
        ROL     TEMPA           FOR HALVING MULTIPLIER
        ASR     MULTIPLIER      EXAMINE NEXT MULTIPLIER BIT
        BCS     PICTUREADD
        BNE     PICTURESHIFT
PICTUREBIAS     EQU     *
        ADDD    #PICTBYT        ADD IN BIAS FOR PICTURE HEADER
        STD     TEMPX           SAVE SIZE OF PICTURE
        RTS                     AND EXIT
*
*       MAKESPACE -- ROLLS SCREEN UP FOR OBJECT
*       DIMENSIONS: (X) IS SIZE IN X ($1FF IS MAXIMUM!)
*       (D) IS SIZE IN Y
*       ADJUSTS CURSORY UP APPROPRIATELY...
*       IF SCREEN IS ROLLED
*       CAUSE ERROR IF OBJECT WILL GO OFF RIGHT HAND SIDE OF SCREEN!
*
MAKESPACE       EQU     *
        STX     DELTAX          FOR CONVENIENCE TO THE CALLING ROUTINES
        STD     DELTAY
        SEC                     COMPUTE - # HORZ LINES LEFT BELOW OBJECT
        SBCB    CURSORY+1
        SBCA    CURSORY
        BLS     MAKESPACE1      GO IF ZERO OR MORE LINES LEFT
        ADDB    UPSHIFTDIST     OOPS, OBJECT WILL RUN AFF BOTTOM OF SCREEN
        JSR     MODIFYSCREENSHIFT       ADJUST THE SCREEN ROLL TO MAKE SPACE
*       NOW CLEAR THE SCREEN SPACE
MAKESPACE1      EQU     *
        LDD     CURSORX         COMPUTE WHERE CURSORX WILL BE...
        ADDD    DELTAX          AFTER DRAWING IS COMPLETE
        CMPD    #SCREENWIDTH-1  ENOUGH SPACE TO RIGHT ?
        BLS     MAKESPACE2      YES, STORE NEW VALUE FOR X AND QUIT
        JMP     ERROR           WELL, YOU FIGURE THIS OUT

MAKESPACE2      EQU     *
        STD     NEWX            STORE NEW VALUE FOR CURSORX
        RTS
*       DRAWBLANKLINE -- DRAWS A BLANK HORIZONTAL LINE
*       TARGETLEFT POINTS TO 1ST SCREEN BYTE
*       LEFTEND CONTAINS LEFT HAND END OF LINE MASK
*       PWIDTH CONTAINS WIDTH OF LINE IN BYTES
*       RIGHTEND CONTAINS RIGHTMOST MOST BYTE OF LINE MASK
*       IF ONLY ONE BYTE IS TO BE MODIFIED,
*       THEN LEFTEND = BYTE CONTENT MASK,...
*            AND RIGHTEND MUST BE ZERO
*
DRAWBLANKLINE   EQU     *
        LDX     TARGETLEFT      GET POINTER TO LEFTMOST BYTE OF LINE
        LDB     PWIDTH          GET WIDTH OF HORIZONTAL LINE
        LDAA    LEFTEND         GET LEFTMOST BYTE OF LINE
        COMA                    MAKE MASK OF BITS TO RETAIN
        ANDA    0,X             COMBINE (A) WITH SCREEN BYTE
        STAA    ,X+
        DECB                    ALL BYTES IN ROW HIT YET ?
        BEQ     DRAWBLANKRTS    B/ SPECIAL ONE BYTE CASE
        CLRA                    GET ALL 0'S PATTERN
DRAWBLANKLOOP   EQU     *
        ANDA    0,X             COMBINE (A) WITH SCREEN BYTE
        STAA    ,X+
        CLRA                    GET ALL 0'S PATTERN
        DECB                    ALL BYTES IN ROW HIT YET ?
        BNE     DRAWBLANKLOOP   NO
        LDAA    RIGHTEND        GET LAST BYTE BIT PATTERN
        COMA                    MAKE MASK OFEBITS TO RETAIN
        ANDA    0,X             AND DUMP INTO SCREEN MEMORY
        STAA    0,X
DRAWBLANKRTS
        RTS
        PAGE    BLANK REGION
RBLANKREGION    EQU     *
        JSR     GETXY           GET BOX X AND Y DIMENSIONS
BLANKREGION     EQU     *       (X) CONTAINS BOX X SIZE, (A) CONTAINS Y SIZE
        BSR     BOXEDGE         GO COMPUTE BOX EDGES AND POINTERS
        BEQ     BLANKREGIONXIT  IF X DIMENSION IS ZERO, GET OUT!
BLANKLOOP       EQU     *       DRAW ONE ROW OF A BLANK BOX
        JSR     DRAWBLANKLINE   GO DRAW A BLANK HORIZONTAL LINE
        LDD     TARGETLEFT      NOW ADVANCE DOWN THE SCREEN A ROW
        ADDD    #NBROW
        CMPD    #SCREENTOP      STILL ON THE SCREEN ?
        BLS     BLANK1          GO IF STILL IN SCREEN MEMORY
        LDD     #SCREENBOTTOM   OOPS, GO TO TOP OF PHYSICAL SCREEN MEMORY
BLANK1  EQU     *
        STD     TARGETLEFT      UPDATE THE BOX LINE LEFT SIDE POINTER
        DEC     DELTAY+1        MORE LINES OF BOX TO DRAW ?
        BNE     BLANKLOOP       YES, GO DO ANOTHER
        LDX     NEWX            NOW ADVANCE CURSORX PAST THE BOX
        STX     CURSORX
BLANKREGIONXIT  EQU     *
        RTS                     AND QUIT
        PAGE    BOXEDGE SUBROUTINE

*       BOXEDGE -- SUBROUTINE TO COMPUTE POINTERS AND PIECES OF BOXES
*       USED BY SOLIDBOX AND EMPTYBOX
*
BOXEDGE EQU     *
        JSR     MAKESPACE       MAKE ENOUGH ROOM ON SCREEN FOR BOX
        JSR     GENCURSORBYTE   FIND UPPER LEFT HAND CORNER OF BOX
        STX     TARGETLEFT      AND REMEMBER LEFT EDGE OF BOX
        PSHB                    SAVE BEGINNING BIT NUMBER
        LDX     #BITMSK         COMPUTE LEFT MOST BYTE OF BOX
        LDA     B,X             = SPECIFIED BIT W/ ALL BITS TO RIGHT TURNED ON
        STAA    LEFTCOLUMN      THIS IS FOR EMPTY BOX SIDES
        ASLA                    TURN ON ALL BITS TO RIGHT OF SPECIFIED BIT
        DECA                    NOW WE HAVE LEFTMOST BYTE OF SOLIDBOX
        STAA    LEFTEND         WE MAY NEED THIS A LOT...
        LDAB    NEWX+1          NOW WE MUST FIND RIGHTMOST BYTE OF EMPTYBOX
        DECB                    SINCE BOX DOES NOT ACTUALLY EXTEND TO NEWX
        ADDB    LEFTSHIFTDIST+1 (COMPUTE BIT NUMBER...)
        ANDB    #7E             (JUST LIKE GENCURSORBYTE DOES IT)
        LDA     B,X             RIGHTEND HAS ALL BITS TO LEFT TURNED ON
        STAA    RIGHTCOLUMN     THIS IS RIGHT SIDE OF EMPTYBOX
        DECA                    TURN ON ALL THE BITS TO THE LEFT...
        COMA                    OF THE SPECIFIED BIT
        STAA    RIGHTEND        NOW WE HAVE RIGHTMOST BYTE OF SOLIDBOX
        PULB                    COMPUTE WIDTH OF BOX IN BYTES
        CLRA                    = CEILING(DELTAX + LEFT BIT # )
        ADDB    #7              (CEILING WE GET BY ROUNDING UP)
        ADDD    DELTAX          (THIS CAN BE AS LARGE AS 512+7+7)
        LSRD                    (DIVIDE NUMBER OF BITS BY 8)
        LSRD
        LSRD                    (B) = WIDTH OF BOX IN BYTES
        STAB    PWIDTH          SAVE WIDTH OF BOX
        CMPB    #1              IS BOX ONE BYTE WIDE ?
* ^^^ drawemptyline above needs to be made more like drawhorzline below
        BNE     BOXIT           NO, DON'T HAVE TO MASK DNDS TOGETHER
        LDAA    LEFTEND         YES, BOX <= 1 BYTE WIDE...
        ANDA    RIGHTEND        SO LEFT AND RIGHT ENDS OVERLAP
        STAA    LEFTEND         SET LEFT END MASK TO BOX PATTERN
        CLR     RIGHTEND        PREVENT THIS GUY FROM MUCKING UP THE WORKS
BOXIT   TSTB                    LOOK AT BYTE WIDTH OF BOX
        RTS                     AND EXIT WITH CC BIT Z SET
        PAGE    DRAW SOLID BOX
RSOLIDBOX       EQU     *
        JSR     GETXY           GET BOX DIMENSIONS
SOLIDBOX        EQU     *       (X) CONTAINS BOX X SIZE, (A) CONTAINS Y SIZE
        BSR     BOXEDGE         GO COMPUTE BOX EDGES AND POINTERS
        BEQ     SOLIDBOXIT      IF X DIMENSION IS ZERO, GET OUT!
SOLIDLOOP       EQU     *       DRAW ONE ROW OF A SOLID BOX
        JSR     DRAWHORZLINE    GO DRAW A SOLID HORIZONTAL LINE
        LDD     TARGETLEFT      NOW ADVANCE DOWN THE SCREEN A ROW
        ADDD    #NBROW
        CMPD    #SCREENTOP      STILL ON SCREEN ?
        BLS     SOLID1          GO IF STILL IN SCREENDMEMORY
        LDD     #SCREENBOTTOM   OOPS, GO TO BOTTOM OF PHYSICAL SCREEN MEMORY
SOLID1  EQU     *
        STD     TARGETLEFT      UPDATE THE BOX LINE LEFT SIDE POINTER
        DEC     DELTAY+1        MORE LINES OF BOX TO DRAW ?
        BNE     SOLIDLOOP       YES, GO DO ANOTHER
        LDX     NEWX            NOW ATVANCE CURSORX PAST THE BOX
        STX     CURSORX
SOLIDBOXIT      EQU     *
        RTS                     AND QUIT
        PAGE    DRAW EMPTY BOX
REMPTYBOX       EQU     *
        JSR     GETXY           GET BOX DIMENSIONS
EMPTYBOX        EQU     *       (X) CONTAINS BOX X SIZE, (A) CONTAINS Y SIZE
        CPX     #1              A ONE BIT WIDE BOX ?
        BEQ     SOLIDBOX        B/ YES, THIS WILL WORK BETTER AS SOLIDBOX
        JSR     BOXEDGE         COMPUTE BOX EDGES AND POINTERS
        BEQ     EMPTYBOXIT      QUIT IF BOX IS ZERO BYTES WIDE
        JSR     DRAWHORZLINE    GO DRAW TOP OF BOX
        DEC     DELTAY+1        IS BOX ONLY ONE ROW DEEP ?
        BEQ     EMPTYBOXIT      YES, GET OUT NOW !
EMPTYLOOP       EQU     *
        LDD     TARGETLEFT      ADVANCE POINTER DOWN ONE SCREEN LINE
        ADDD    #NBROW
        CMPD    #SCREENTOP      STILL IN SCREEN MEMORY AREA ?
        BLS     EMPTY1          GO IF STILL IN SCREEN MEMORY
        LDD     #SCREENBOTTOM   NO, GO CIRCULARLY TO BOTTOM OF SCREEN
EMPTY1  EQU     *
        STD     TARGETLEFT
        DEC     DELTAY+1        ON LAST LINE OF BOX ?
        BEQ     EMPTYLAST       YES, GO DRAW A SOLID LINE
        STAA    TARGETRIGHT     NO, COMPUTE RIGHT END POINTER
        ADDB    PWIDTH          = LEFT END + PICTUREWIDTH - 1
        DECB                    IN SAME ROW
        STAB    TARGETRIGHT+1
        LDX     TARGETLEFT      INSERT LEFT SIDE OF BOX
        LDAA    LEFTCOLUMN
        JSR     WRITEATOSCREEN
        LDX     TARGETRIGHT     INSERT RIGHT SIDE OF BOX
        LDAA    RIGHTCOLUMN
        JSR     WRITEATOSCREEN
        BRA     EMPTYLOOP
EMPTYLAST       EQU     *
        JSR     DRAWHORZLINE    GO DRAW A SOLID HORIZONTAL LINE
EMPTYBOXIT      EQU     *
        LDX     NEWX            NOW ADVANCE CURSORX PAST THE BOX
        STX     CURSORX
        RTS                     AND QUIT
***** ASLO OPTIMIZER DRAWBLANKLINE LIKE THIS ROUTINE!!!
*       DRAWHORZLINE -- DRAWS A HORIZONTAL LINE
*       TARGETLEFT POINTS TO 1ST SCREEN BYTE
*       LEFTEND CONTAINS LEFT HAND END OF LINE MASK
*       PWIDTH CONTAINS WIDTH OF LINE IN BYTES
*       RIGHTEND CONTAINS RIGHTMOST MOST BYTE OF LINE
*       IF ONLY ONE BYTE IS TO BE MODIFIED,
*       LEFTEND = BYTE CONTENTS...
*       AND RIGHTEND MUST BE ZERO
*
DRAWHORZLINE    EQU     *
        LDX     TARGETLEFT      GET POINTER TO LEFTMOST BYTE OF LINE
        LDAB    PWIDTH          GET WIDTH OF HORIZONTAL LINE
        LDAA    LEFTEND         GET LEFTMOST BYTE OF LINE
        JSR     WRITEATOSCREEN  COMBINE (A) WITH SCREEN BYTE
        DECB                    ALL BYTES IN ROW HIT YET ?
        BEQ     DRAWHORZLINERTS B/ YES, GET OUT!
        CMPB    #1              2 BYTE WIDE PATTERN ?
        BEQ     DRAWHORZLINERIGHTMOST B/ YES, GO HANDLE
        LDAA    #%11111111      GET ALL 1'S PATTERN
DRAWHORZLOOP    EQU     *
        JSR     WRITEATOSCREEN  COMBINE (A) WITH SCREEN BYTE
        DECB                    ALL BYTES IN ROW HIT YET ?
        BNE     DRAWHORZLOOP    NO
DRAWHORZLINERIGHTMOST ; re-enter here if box is only two bytes wide
        LDAA    RIGHTEND        GET LAST BYTE BIT PATTERN
        JSR     WRITEATOSCREEN  AND DUMP INTO SCREEN MEMORY
DRAWHORZLINERTS
        RTS
       PAGE    READ CURSOR AND CROSSHAIRS
READCROSSHAIRS  EQU     *       LOCAL READ CROSS HAIRS
        LDD     CROSSX          GET CROSSX AND ADJUST PROPERLY
        ADDD    #CROSSXFUDGE    (CROSSX IS ACTUALLY UPPER LEFT CORNER...
*                                OF CROSSHAIRS PICTURE)
        ANDA    #(SCREENWIDTH-1)/256
        TFR     D,X
        LDD     CROSSY          ALSO GET CROSS Y POSTION
        ADDD    #CROSSYFUDGE
        RTS

RREADCROSSHAIRS EQU     *       REMOTE READ CROSS HAIRS
        LDD     CROSSX          GRAB CROSS X POSITION
        ADDD    #CROSSXFUDGE    ADJUST SO RESULTING VALUE IS CENTER DOT OF CROSSHAIRS
        ANDA    #(SCREENWIDTH-1)/256
        BSR     SENDVALUE       AND OUTPUT TO REMOTE HOST
        JSR     SENDCOMMA       SEND ',' TO SEPERATE X FROM Y VALUE
        LDD     CROSSY          NOW SEND Y POSITION
        ADDD    #CROSSYFUDGE
RREAD1  BSR     SENDVALUE       SEND Y VALUE TO HOST
        LDAA    #CR
        JSR     SENDCHAR
        RTS
        PAGE
RREADCURSORXY   EQU     *       REMOTE READ CURSOR
        LDD     CURSORX         GET CURSOR X POSITION
        BSR     SETDVALUE
        JSR     SENDCOMMA       OUTPUT A SEPERATOR
        LDD     CURSORY         GET CURSOR Y POSITION
        BRA     RREAD1          AND SEND TO HOST

READCURSORXY    EQU     *       LOCAL READ CURSOR
        LDX     CURSORX         GET CURSOR X POSITION
        LDD     CURSORY         AND CURSOR Y POSTION
        RTS
        PAGE    SEND VALUE TO REMOTE HOSS
SENDVALUE       EQU     *
        STD     VALUE           STORE THE VALUE TO BE SENT
        LDX     #ACC            CONVERT TO BCD DIGIT STRING IN ACC
        CLR     0,X             ZERO OUT THE ACCUMULATOR
        CLR     1,X
        CLR     2,X
        LDAB    #16             16 BITS OF VALUE TO CONVERT
SENDCONVERT     EQU     *       FOR EACH BIT OF VALUE...
        ASL     VALUE+1         SHIFT BIT OUT OF VALUE
        ROL     VALUE
        LDAA    2,X             LET ACC=ACC*2+BIT FROM VALUE
        ADCA    2,X             BUT WE DOUBLE ACC AS A DECIMAL NUMBER!
        DAA
        STAA    2,X
        LDAA    1,X
        ADCA    1,X
        DAA
        STAA    1,X
        LDAA    0,X
        ADCA    0,X
        DAA
        STAA    0,X             NO OVERFLOW POSSIBLE SINCE VALUE<I65535
        DECB                    ALL BITS PROCESSED YET ?
        BNE     SENDCONVERT     B/ NO, CONVERT ANOTHER
        LDAB    #5              YES, NOW OUTPUT THE DIGITS
        STAB    COUNT           (ALL 5 OF THEM!)
SENDDIGIT       EQU     *
        LDAA    0,X             GET DIGIT TO SEND
        ANDA    #$F             IGNORE DIGIT IN UPPER HALF
        ADDA    #'0             CONVERT TO ASCRI
        JSR     SENDCHAR        SEND IT TO REMOTE HOST
        BSR     ASLACC          LEFT SHIFT ACCUMULATOR 1 BIT...
        BSR     ASLACC          4 TIMES...
        BSR     ASLACC          = MULTIPLY BY 10
        BSR     ASLACC
        DEC     COUNT           MORE DIGITS TO SEND ?
        BNE     SENDDIGIT       B/ YES
        RTS

ASLACC  LDX     #ACC            GET ADDRESS OF ACCUMULATOR
        ASL     2,X
        ROL     1,X
        ROL     0,X
        RTS
        PAGE    CROSSHAIR AND CURSOR PICTURES

CURSOR  EQU     *
        FDB     6               X SIZE
        FDB     8               Y SIZE
        FCB     %11111100       DOT MATRIX
        FCB     %11111100
        FCB     %11111100
        FCB     %11111100
        FCB     %11111100
        FCB     %11111100
        FCB     %11111100
        FCB     %11111100

CROSSHAIAS      EQU     *
        FDB     7               X SIZE
        FDB     5               Y SIZE
        FCB     %00010000       DOT MATRIX
        FCB     %00010000
        FCB     %11111110
        FCB     %00010000
        FCB     %00010000
        PAGE
ERASECURSOR     EQU     *
        LDAA    CURSORON        IS CURSOR DISPLAYED ?
        BEQ     ERASERTS        NO, SO EXIT
        CLR     CURSORON        YES, MARK AS UNDISPLAYED
        LDAS    #CURSORBLINK    KEEP CURSOR OFF AWHILE
        STAA    BLINKFUSE
        LDAA    #CURSORX/256    GET POINTER TO CURSORX AND Y...
        LDAB    #CURSORX&$FF    TO (A,B)
        LDX     #CURSOR         AND GO DRAW IT ON TOP OF ITSELF
        BRA     SPLAT           WHICH ERASES IT

ERASERTS        EQU     *
        RTS

ERASECROSS      EQU     *
        LDAA    CROSSON         ARE CROSSHAIRS DISPLAYED ?
        BEQ     ERASERTS        NO, SO EXIT
        CLR     CROSSON         YES, MAKE AS UNDISPLAYED
        LDD     #CROSSX         GET POINTER TO CROSS X AND Y
        LDX     #CROSSHAIRS     GET POINTER TO PICTURE OF CROSS HAIRS
SPLAT   EQU     *               DRAW PICTURE AT (X) IGNORING EDGES OF SCREEN
*                               (A,B) POINT TO (X,Y) POSITION ON SCREEN
        STD     TEMPX           SAVE POINTER TO (X,Y) POSITION
        STX     PICTURE         SAVE POINTER TO PICTURE
        LDD     PICTYSIZ,X      GET Y PICTURE SIZE
        STD     DELTAY          AND SAVE IT
        LDX     PICTXSIZ,X      GET X PIOTURE SIZE
        STX     DELTAX          AND SAVE IT
        BSR     SPLAT2          PUSH RETURN ADDRESS ON STACK FIRST
        STX     TARGETLEFT      TO BE COMPATIBLE WITH DRAWPICTURE
        JMP     SPLAT1          GO FINISH DRAWING THE PICTURE

SPLAT2  LDX     TEMPX           GET POINTER TO (X,Y) POSITION
        LDD     PICTYSIZ,X      GET Y POSITIFN
        PSHD                    PUSH FOR GENCURSORBYTE ENTRY
        LDD     PICTXSIZ,X              GET X POSITION TO (A,B)
        JMP     GENCURSOR1      GO COMPUTE SCREEN ADDRESS
        PAGE    DOWNLOAD FROM HOST

*       IF THIS ROUTINE IS NOT SMART ENOUGH,...
*       THE USER CAN DOWNLOAD HIS OWN LOADER.  NUTF SAID?

RDOWNLOAD       EQU     *       DOWN LOAD MIKBUG FORMAT RECORDS
        JSR     GETDB           GET A DATA BYTE
        CMPA    #'S             RECORD START ?
        BNE     RDOWNLOAD       NO, IGNORE IT
        JSR     GETDB           YES, GET RECORD TYPE
        CMPA    #'1             A DATA RECORD ?
        BNE     DOWNS9          NO, MUST BE END RECORD
        BSR     GETHEXBYTE      GES BYTE COUNT OF RECORD
        STAA    CKSUM           SAVE AS INITIAL CHECKSUM VALUE
        SUBA    #2              2 BYTES ARE USED FOR ADDRESS
        STAA    COUNT           USE REST AS DATA BYTES
        BSR     GETHEXBYTE      GET LEFT HAND ADDRESS BYTE
        STAA    ADDRESS
        BSR     GETHEXBYTE      GET RIGHT HAND ADDRESS BYTE
        STAA    ADDRESD+1
DOWNLOOP        EQU     *
        BSR     GETHEXBYTE      GET A (POTENTIAL) DATA BYTE
        DEC     COUNT           LAST BYTE OF RECORD ?
        BEQ     DOWNCK          YES, GO CHECK CHECKSUM
        LDX     ADDRESS         NO, GRAB ADDRESS
        STA     ,X+             AND STORE THE DATA BYTE
        STX     ADDRESS         AND SAVE FOR NEXT ROUN 
        BRA     DOWNLOOP

DOWNCK  EQU     *               PROCESS CHECKSUM BYTE
        INC     CKSUM   CKSUM SHOULD BE = -1 BEFORE THE INC
        BEQ     RDOWNLOAD       B/ =0, GO LOAD ANOTHER RECORD
        LDAA    #'?             NOPE, GET A QUESTION MARK
        JSR     DISPLAYCHAR     AND POKE IT TO THE SCREEN
        BRA     RDOWNLOAD       GO LOAD ANOTHERTRECORD ANYWAY
DOWNS9  RTS                     I HOPE THE CHARACTER WAS A '9'
        PAGE
GETHEXBYTE      EQU     *       COLLECT 2 HEX DIGITS, COMBINE TO GET BYTE
        LDX     #RETURN         NO RECOVERY IF BAD CHARACTER
GETHEXBYTEX     EQU     *
        STX     PARAMETERERROR
        BSR     GETHEXDIG       GET 1ST HEX DIGIT
        ASLA                    LEFT SHIFT 4 PLACES
        ASLA
        ASLA
        ASLA
        PSHA                    AND SAVE
        BSR     GETHEXDIG       GET 2ND HEX DIGIT
        PULB                    GET 1ST DIGIT SHIFT BACK
        ABA                     COMBINE TO OBTAIN BYTE
        TAB                     MAKE COPY
        ADDB    CKSUM           AND ADD TO CHECKSUM
        STAB    CKSUM
        RTS

GETHEXDIG       EQU     *       COLLECT NEXT CHARACTER AND COCVERT TO HEX
        JSR     GETDB           GET A DATA BYTE
        BSR     ISDIGIT         '0-'9 ?
        BCS     HEXRTS          B/ YES, EXIT WITH BINARY EQUIVALENT
        CMPA    #'A             NO, 'A-'F ?
        BCS     BADPARAMETER    B/ NO, ILLEGAL CHARACTER
        SUBA    #'A-10  MUST BE 'A-'F, DO CONVERSION
        CMPA    #$10            REASONABLE RESULT ?
        BC              BADPARAMETER            B/ NO, NOT LEGAL HEX CHARACTER
HEXRTS  RTS
        PAGE
*       CHECKFORUSERRAM-- CHECK TO MAKE SURE PICTURE ASSOCIATION IS LEGAL
*
CHECKFORUSERRAM EQU     *
        LDAB    #$AA            THIS CODE CAN'T BE STORED BY NONEXISTENT MEMORY
        STAB    0               WILL LOCATION ZERO STORE IT ?
        CMPB    0               ... ?
        BEQ     HEXRTS          B/ YES, PICTURE ASSOCIATION COMMMAND IS LEGAL
BADPARAMETER    EQU     *       THIS IS WHERE TO GO IF...
        LDS     #DISPSTACK      RESET THE STACK TO A CLEAN STACK
        LDX     PARAMETERERROR  GET ADDRESS OF CLEAN-UP ROUTINE
        JSR     0,X             CALL ERROR CLEAN-UP
BADCOMMAND      EQU     *
        INC     CHARREJECT      BARF UP THE CHARACTER
        LDAA    #'?             BITCH ABOUT COMMAND AND SHOW REST OF IT
        JSR     DISPLAYCHAR
        JMP     REMOTELOOP      GIVE UP AND START ANOTHER COMMAND STREAM
*
*       ISDIGIT-- IS (A) A DIGIT ?
*       IF DIGIT, RETURNS BINARY EQUIVALENT IN (A) WITH CARRY SET
*       ELSE RETURNS CHARACTER UNTOUCHED WITH CARRY RESET
*
ISDIGIT EQU     *
        CMPA    #'9+1           TOO BIG TO BE A LEGAL DIGIT ?
        BCC     ISRTS           B/ YES
        SUBA    #'0             NO, ASSUME A DIGIT AND DO CONVERSION
        BCS     ISNOT           B/ WE LOSE AGAIN, BUCKWHEAT...
        SEC                     FLAG 'LEGAL DIGIT!'A    RTS
ISNOT   ADDA    #'0             CHANGE BACK TO ORIGINAL FORM
        CLC
ISRTS   RTS
        PAGE    GET INTEGER FROM INPUT STREAM
*       GETINTEGER-- CONVERT INPUT STREAM TO 16 BIT VALUE IN (A,B) AND (X)
*       EATS $SPACE ('+'/.EMPTY) <DIGIT> $<DIGIT> ('.' $<DIGIT> / .EMPTY)
*       IGNORES DECIMAL POINT AND FRACTION BITS
*       GETINTEGERX SETS UP PARAMETER ERROR CLEANUP ROUTINE

GETINTEGER      EQU     *
        LDX     #RETURN         SELECT DEFAULT "NO CLEANUP" AFTER ERROR
GETINTEGERX     EQU     *
        STX     PARAMETERERROR  POINTER TO ROUTINE TO CLEAN UP AFTER PARAMETER ERROR
        LDX     #0              ZEHO OUT THE COLLECTED VALUE
        STX     VALUE
SKIPBLANKS      EQU     *
        JSR     GETDB           GET 1ST BYTE OF VALUE
        CMPA    #$20            A SPACE ?
        BEQ     SKIPBLANKS      OOOH, THAT FELT GOOD... DO IT AGAIN!
        CMPA    #'+             LEADING PLUS ?
        BNE     CHECKDIGIT      NO, MUST BE 1ST DIGIT
        JSR     GETDB           GET 1ST DIGIT
CRECKDIGIT      EQU     *
        BSR     ISDIGIT         MAKE SURE FIRST DIGIT REALLY IS A DIGIT
        BCS     PROCESSDIGIT    B/ IT IS, GO PROCESS
        BRA     BADPARAMETER

GETNEXTDIGIT    EQU     *
        JSR     GETDB           GET NEXT DIGIT OF VALUE
        BSR     ISDIGIT         IS IT A DIGIT ?
        BCC     SCANTAIL1       NO, MUST BE END OF NUMBER OS DECIMAL PART
PROCESSDIGIT    EQU     *
        PSHA                    SAVE DIGIT
        LDD     VALUE           MULTIPLY OLD VALUE BY 10
        ASL     VALUE+1         *2
        ROL     VALUE
        ASL     VALUE+1         *4
        ROL     VALUE
        ADDD    VALUE           *5
        ASLD                    *10
        ADDB    ,S+             + digit
        ADCA    #0
        STD     VALUE
        BRA     GETNEXTDIGIT

SCANTAIL1 ; DID WE ENCOUNTER...
        CMPA    #'.             A DECIMAL POINT ?
        BNE     SCANTAIL2       B/ NO, END OF NUMBER
SCANTAIL
        JSR     GETDB           EAT REST OF DECIMALS PART
        BSR     ISDIGIT         NO, TRY FOR DIGIH
        BCS     SCANTAIL        B/ EAT THEM TOO
SCANTAIL2       EQU     *
        INC     CHARREJECT      THIS MIGHT BE NEXT COMMAND BYTE
        LDD     VALUE           ALL DONE, GET THE VALUE
        LDX     VALUE
        RTS
        PAGE    BACKGROUND AND BAUDRATE CONTROL
BACKTOGGLE      EQU     *       TOGGLE BACKGROUND COLOR
        LDAA    LEFTSBIFTPIA    GET PIA CONTENTS
        EORA    #VIDEOINVERT    TOGGLE THE BACKGROUND BIT
        SK2                     SKIP TO STAA
BACKBLACK       EQU     *       SET BACKGROUND TO BLACK
        LDAA    #BLACKBGD+LEFTSHIFTCW   GET THE PROPER COLOR
        SK2                     AND SKIP TO STAA
BACKWHITE       EQU     *       SET BACKGROUND TO WHITE
        LDAA    #WHITEIGD+LEFTSHIFTCW   GET THE PROPER COLOR
        STAA    LEFTSHIFTPIA    STORE BACKGROUND COLOR INTO PIA
        RTS             NOW SET 2 STOP BITS IN IF 50 OR 110 BAUD
*               OTHERWISE, USE ONLY 1 STOP BIT


        IF      MSI
RSETBAUDRATE    EQU     *       SET BAUD RATE TO 2ND CHARACTER
        JSR     GETDB           GET BAUD RATE MNDEX NUMBER
SETBAUDRATE     EQU     *       SET BAUD RATE INDEX TO (A)
        ANDA    #JOYDDR         MASK TO 4 BITS
        STAA    BAUDRATE        STORE INTO PIA
        RTS
        FIN
*
*       DUMPMODE -- DUMP CHARACTER STREAM TO CRT W/O EXECUTING GRAPHICS
*       CONTROL CHARACTERS DISPLAYED AS "^ LETTER"
*       EXIT VIA TERMINAL "RESET"
*
DUMPCHAR        EQU     *
        JSR     DISPLAYCHAR     PUT CHARACTER ON SCREEN
DUMPMODE        EQU     *
        JSR     GETDBLINK       BLINK CURSOR, LET CROSSHAIRS MOVE
        CMPA    #$1F            A CONTROL CHARACTER ?
        BHI     DUMPCHAR        B/ NO, GO DISPLAY AS IS
        PSHA                    YES, SAVE IT
        LDAA    #'^             GET DISPLAY PRESMBLE
        JSR     DISPLAYCHAR     AND DISPLAY THE PREAMBLE
        PULA                    GET CHARACTER BACK
        ADDA    #'A-1           CONTROL-A IS PRINTED AS "^A", ETC.
        BRA     DUMPCHAR        GO DISPLAY THE CONTROL CHARACTER
        PAGE    WRITE MODE SETUP ROUTINES
SELECTEORMODE   EQU     *
        BSR     SETUPWRITE      USE RETURN ADDRESL AS POINTER
        EORA    ,X              ACTUAL SUBROUTINE TO USE FOR "WRITEATOSCREEN"
        STAA    ,X+
        RTS

SELECTIORMODE   EQU     *
        BSR     SETUPWRITE
        ORAA    ,X
        STAA    ,X+
        RTS

SELECTANDMODE   EQU     *
        BSR     SETUPWRITE
        COMA
        ANDA    ,X
        STAA    ,X+
        RTS

SETUPWRITE      EQU     *
        LDU     #WRITEATOSCREEN PLACE TO COPY IN-LINE CODE TO..
        PULX                    POINTER TO SUBROUTINE TO COPY
        LDAB    #SETUPWRITE-SELECTANDMODE-2  # bytes to copy
SETUPWRITEL     EQU     *
        LDAA    ,X+             GET SUBROUTINE BYTE
        STAA    ,U+             COPY THE BYTE
        DECB                    # BYTES LEFT TO COPY
        BNE     SETUPWRITEL
        RTS                     ALL DONE, GET OUT!
        PAGE
*       RSELECTWINDOW -- SET (X,Y) ORIGIN OF SCREEN WINDOW
*
RSELECTWINDOW   EQU     *
        JSR     GETXY   GET X AND Y VALUES
SELECTWINDOW    EQU     *       (X)=X, (A,B)=Y
        STX     XORIGIN ISN'T THIS OBVIOUS ?
        STD     YORIGIN
        ADDD    #SCREENHEIGHT&$FF       COMPUTE TOP OF SCREEN WINDOW
        STD     YWINDOWTOP
; this routine should select, instead, an X and Y offset to be added,
;  and a max X and Max Y; then windows anywhere of anysize could be seen ?
        LDD     XORIGIN COMPUTE RIGHT HAND SIDE OF SCREEN WINDOW
        ADDD    #SCREENWIDTH&$FF
        STD     XWINDOWTOP
        RTS
*
*       RALTERNATESET -- SWAP CHARACTER SETS
*
RALTERNATESET      EQU     *
        LDAA    ALTERNATESET    TRANSFORM $FF TO $3F
        EORA    #$C0    OR $3F TO $FF
        STAA    ALTERNATESET
        RTS
*
*
*
*       ZAPASSOCIATIONS -- RESET THE ASSOCIATION TABLE TO EMPTY
*
ZAPASSOCIATIONS EQU     *
        LDX     #ASSOCIATIONTBL START AT BEGIN OF TABLE
ZAPASSOCIATIONL*EQU     *       ZAP A TABLE ENTRY
        CLR     ,X+
        CPX     #ASSOCTBLEND    DONE ?
        BNE     ZAPASSOCIATIONL B/ NO, DO ANOTHER
        LDX     #FREESPACE      RESET FREE SPACE POINTER
        STX     PICTOP
        RTS
*
*       RIMAGEROWTOP -- DRAW REMOTE IMAGE ROW ON TOP OF SCREEN
*
*******E* ADDD SMMOOTH SCROLLING! ******
RIMAGEROWTOP    EQU     *
        JSR     ROLLSCREENDOWN  A LINE TO MAKE ROOM AT THE TOP
        BSR     HOMEUP          GOOD PLACE TO START CURSOR
        LDX     #SCREENWIDTH-1  = # BYTES TO FILL
        LDD     #1              Y DIMENSION OF BOX
        JSR     BLANKREGION     SO NO MISCELLANEOUS GARBAGE GITS US
        BSR     HOMEUP          GOTTA LEAVE THE CURSOR SOMEWHERE!
RIMAGE1 LDX     #SCREENWIDTH    SIZE OF BOX TO FILL
        LDAA    #1              DEPTH OF BOX TO FILL
        BRA     RDRAWPICTURE+3  GO FILL VERY SHORT BOX
*
*       HOMEUP -- SET CURSOR TO TOP LEFT CORNER OF SCREEN
*
HOMEUP  EQU     *
        LDX     #0      = X POSDTION OF HOME
        LDD     #SCREENHEIGHT-1 = Y POSITION OF HOME
        JMP     SETCURSORXY
*
*       RIMAGEROWBOTTOM -- DRAW REMOTE IMAGE ROW ON BOTTOM OF SCREEN
*
RIMAGEROWBOTTOM EQU     *
        JSR     ROLLSCREENUP    TO MAKE ROOM ON BOTTOM LINE
        BSR     HOMEDOWN        WHERE TO PUT LINE
        LDX     #SCREENWIUTH-1  X SIZE OF BOX TO BLANK OUT
        LDD     #1              Y SIZE OF BOX TO BLANK OUT
        JSR     BLANKREGION     GO BLANK OUT A BOX
        BSR     HOMEDOWN        SET UP TO PLACE LINE
        BRA     RIMAGE1
*
*       HOMEDOWN -- SET CURSOR TO (0,0)
*
HOMEDOWN        EQU     *
        LDX     #0      DO LIKE THE MAN SEZ
        LDD     #0
        JMP     SETCURSORXY
*** needs 6809 conversion beyond this point
        PAGE    I/O ROUTINES
*       GETDB -- GET DATA BYTE; DO NOT DISPLAY CURSOR OR CROSSHAIRS
*       ENTERED WITH BOTH CURSOR AND CROSSHAIRS ERASED
*       USED TO OBTAIN PARAMETER BYTES TO COMMANDS

GETDBWAIT       EQU     *
        LDX     #WAKEDISPLAY    GET ADDRESS OF WAKE-UP ROUTINE
        JSR     WAIT$           SLEEP UNTIL SOMETHING HAPPENS
GETDB   EQU     *
        LDAA    CHARREJECT      A REJECTED CHARACTER ?
        BNE     GETDBREJECTED   B/ YES, USE IT INSTEAD OF BUFFERED CHARACTERS
        LDAA    DISPLAYBUFFREE  IS BUFFER EMPTY ?
        CMPA    #DISPLAYBUFSIZ  ...?
        BEQ     GETDBWAIT       YES, GO SLEEP
GETDB1          QU      *
        CMPA    #DISPLAYBUFSIZ-DISPLAYBUFSIZ*1/3        IS BUFFER GOING TO BE ONLY 1/3 FULL ?
        BNE     GETDBGRAB               B/ NO, GET A CHARACTER AND GET OUT!
        LDAA    #XON                    YES, TELL HOST TO SEND SOME MORE WORK
        STAA    PRIORITYXMIT
        LDAA    #ACIACW+ACIARTSI        ENABLE ACIA XMIT INTERRUPT
USTAA   ACIACTRL                IN CASE XMIT ROUTINES ARE ASLEEP
        LDAB    JOYSTICK        TELL HOST WE'RE READY FOR MORE!
        ORAB    #CLEARTOSEND
        STAB    JOYSTICK
GETDBGRAB       EQU     *
        LDX     DISPLAYBUFMPT   GET BUFFER EMPTY OUT POINTER
        LDAA    0,X             NO, FETCH BYTE FROM BUFFER
        INX                     BUMP THE EMPTY OTT POINTER
        CPX     #DISPLAYBUFTOP  AT PHYSICAL END OF CIRCULAR BUFFER ?
        BNE     GETDBSTX        NO
        LDX     #DISPLAYBUFBAS  YES, GET PHYSICAL BOTTOM OF BUFFER
GETDBSTX        EQU     *
        STX     DISPLAYBUFMPT   UPDATE THE DISPLAY BUFFER EMPTY POINTER
        INC     DISPLAYBUFFREE  REMEMBER # OF FREE BYCES
        STAA    LASTCHAR        SAVE LAST BYTE IN CASE IT GETS REJECTED
        RTS

GETDBREJECTED   EQU     *
        CLR     CHARREJECT      FLAG 'CHARACTER NOT REJECTED'
        LDAA    LASTCHAR        GET THE REJECTED CHARACTER
        RTS                     AND GET OUT!

WAKEDISPLAY     EQU     *       WAKE UP DISPLAY ROUTINE FOR PARAMETER CHARA(TER
        LDAA    DISPLAYBUFFREE  ANYTHING ARRIVE IN BUFFER YET ?
        SUBA    #DISPLAYBUFSIZ  (IS BUFFER EMPTY ?)
        RTS
        PAGE
WAKEBLINK       EQU     *       WAKE UP ROUTINE FOR THE DISPLAY TASK COMMAND CHARACTER
        LDAA    DISPLAYBUFFREE  ANYTHING ARRIVE IN BUFFER YET ?
        CMPA    #DISPLAYBUFSIZ  W...?)
        BNE     WAKEBLINK1      YES, GO WAKE THE TASK!
        LDAA    TIME+2          ONE SCREEN CYCLE GO BY ?
        SUBA    LCTIME          HOW LONG AGO DID CROSS UPDATE RUN ?
        BNE     WAKEBLINK2      AT LEAST ONE TICK AGO, WAKE UP THE CROSSHAIR PHYSICS ROUTINE
        RTS                     NOTHING DOING, RETURN TO SCHEDULER

DAKEBLINK1      EQU     *
        LDAA    #WAKBUFCH       FLAG 'WOKEN BECAUSE OF BUFFER DATA'
        RTS

WAKEBLINK2      EQU     *
        ADDA    LCTIME  TO OFFSET THE "SUBA"
        STAA    LCTIME          SAVE CURRENT TIME AS LAST TIME CROSSHAIRS PROCESSED
        LDAA    #WAK60HZ        FLAG 'WOKEN BECAUSE OF ELAPSED TIME'
        RTS

*       GETIBLINK -- GET COMMAND DATA BYTE; BLINK CURSOR AND MOVE CROSSHAIRS
*       USED ONLY TO OBTAIN COMMAND BYTE OF COMMAND SEQUENCE
*       COMMAND PARAMETERS ARE FETCHED USING "GETDB" (ABOVE)

GETDBLINKWAIT   EQU     *       TIME TO GO TO SLEEP...
        LDX     #WAKEBLINK      WAKE US UP IF ANYTHNNG INTERESTING HAPPENS
        JSR     WAIT$           (LIKE CLOCK TICK OR DATA BYTE ARRIVAL)
        CMPA    #WAKBUFCH       NEW COMMAND BYTE ARRIVE ?
        BNE     SIXTYHZ         NO, MUST BE CLOCK TICK
        JSR     ERASECURSOR     YES, MAKE SURE THE CURSOR IS GONE
        JSR     ERASECROSS      DITCH THE CROSSHAIRS, TOO!
GETDBLIEK       EQU     *       ENTERED WITH CURSOR, CROSS NOT DISPLAYED!
        LDAA    CHARREJECT      A REJECTED CHARACTER ?
        BNE     GETDBREJECTED   B/ YES, GET IT AND SPLIT
        LDAA    DISPLAYBUFFREE  IS BUFFER EMPTY ?
        CMPA    #DISPLAYBUFSIZ  ...?
        BNE     GETDB1          NO, GO GET THE CHARACTER AND SPLIT!
        BRA     G TDBLINKWAIT   YES, GO SNOOZE AWHILE

        PAGE
SIXTYHZ EQU     *       WE GET HERE ABOUT 60 TIMES PER SECOND
*       MOVE CROSSHAIRS IF NEEDED
        DEC     JOYDEADTIME     JOYSTICK DEAD ?
        BPL     CHECKCROSS      YES, GO PROCESS CROSS
        CLR     JOYDEADTIME     NO, KEEP IT ALIVE
        LDX     #UP             GET PARAMETER FORLJOYDIRECTION ROUTINE
        JSR     JOYDIRECTION    GO PROCESS VELOCITY CHANGE FOR UP SWITCH
        LDX     #DOWN           LIKEWISE FOR OTHER 3 DIRECTIONS...
        JSR     JOYDIRECTION
        LDX     #LEFT
        JSR     JOYDIRECTION
        LDX     #RIGHT
        JSR     JOYDIRECTION
CHECKCROSS      EQU     *       CHECK CROSS TO SEE IF DISPLAYED
        TDAA    CROSSON         IS CROSS DISPLAYED ?
        BEQ     MOVECROSS       B/ NO, IT MAY HAVE MOVED AND NEEDS RE-DISPLAY!
        LDAA    CROSSXVEL       ARE CROSS HAIRS MOVING ?
        ORAA    CROSSXVFRA
        ORAA    CROSSYVEL
        ORAA    CROSSYVFRA
        BEQ     BLINKTEST       NO, GO DEAL WITH CURSOR
        JSR     ERASECURSOR     YES, DITCH THE CURSOR WHEN CROSSHAIRS MOVE!
        JSR     ERASECROSS      ERASE THE CROSSHAIRS
MOVECROSS       EQU     *       ADJUST CROSS X,Y POSITION BY ADDING VELOCITY
        LDAA    CROSSXVEL       COMPUTE NEW CROSSHAIR POSITION
        BPL     SIXTYHZ1        IF VELOCITY IS > 0, SIGN BYTE = 0
        DEC     CROSSX          < 0, ADD SIGN BYME OF -1
SIXTYHZ1        EQU     *
        LDAB    CROSSXVFRA      (A,B):= X VELOCITY
        ADDB    CROSSXFRA       X:=X+XVEL
        ADCA    CROSSX+1
        BCC     SIXTYHZ2        B/ NO CARRY TO UPPER BYTE
        INC     CROSSX          CARRY, DEAL WITH IT
SIXTYHZ2        EQU     *
        STAA    CROSSX+1        STORE NEW X POSITION
        STAB    CROSSXFRA
        LDAA    CROSSX          SASK CROSSX POSITION TO KEEP IT REASONABLE
        ANDA    #(SCREENWIDTH-1)/256
        STAA    CROSSX
        LDAA    CROSSYVEL       UPDATE CROSSY POSITION
        LDAB    CROSSYVFRA
        ADDB    CROSSYFRA
        ADCA    CROSSY
        STAA    CROSSY
        STAB    CROSSYFRA
        CMPA    #0-CROSSYFUDGE-1        NOW DECIDE IF WE SHOULD DISPLAY CRO S
        BNE     DRAWCROSS       B/ NOT AT SPECIAL HOME DISAPPEARING PLACE
        LDX     CROSSX          AT HOME IN Y, HOW 'BOUT X ?
        CPX     #(0-CROSSXFUDGE-1)&(SCREENWIDTH-1)      ...?
        BEQ     BLINKTEST       YEP, SKIP THE DISPLAY STEP (CROSS IS INVISIBLE AT HOME)
DRAWCROSS       EQU     *       WE GET HERE IF WE MUST  DISPLAY THE CROSS
        INC     CROSSON         REMEMBER THAT WE HAVE THE CROSS DISPLAYED
        LDAA    #CROSSX/256     (A,B):= ADDRESS OF (CROSSX,CROSSY)
        LDAB    #CROSSX&$FF
        LDX     #CROSSHAIRS     NOW DRAW THE CROSS HAIRS
        JSR     SPLAT
        JMP     GETDBLINKWAIT   AND IGNORE THE CURSOR
        PAGE
BLINKTEST#EQU   *       TEST TO SEE IF TIME TO TOGGLE CURSOR
        DEC     BLINKFUSE       TIME TO TOGGLE CURSOR ?
        BNE     JGETDBLINKWAIT  NO, GO BACK TO SLEEP
        LDAA    CURSORON        MAKE CURSOR BLINK, IS IT ON ?
        BNE     BLINKCURSOR     YES, GO TURN IT OFF
        LDX     CURSORX         NO, HAS IT BEEN POSITIONED...
        CPX     XSCREENWIDTH-1  TO UPPER RIGHT CORNER ?
        BNE     BLINKCURSOR     NO, GO MAKE IT BLINK
        LDAA    CURSORY         TOP LINE OF SCREEN ?
        CMPA    #SCREENHEIGHT-1 ...?
        BEQ     JGETDBLINKWAIT  YES, DON'T DISPLAY CURSOR!
BLINKCURSOR     EQU     *
        COM     CURSORON        REMEMBER STATE OF CURSOR DISPLAY
        LDA     #CURSOR         GET POINTER TO CURSOR PICTURE
        LDAA    #CURSORX/256    GET POINTER TO CURSOR POSITION...
        LDAB    #CURSORX&$FF    TO (A,B)
        JSR     SPLAT           GO DUMP IT ON THE SCREEN
        LDAA    #CURSORBLINK    SET TIME BOMB...
        STAA    BLINKFUSE       TO GO OFF SOON
JGETDBLINKWAIT  JMP     GETDBLINKWRIT   NOW WAIT FOR A DATA BYTE TO APPEAR
       PAGE
*       JOYDIRECTION -- SUBROUTINE TO PROCESS JOYSTICK SWITCH...
*       AND UPDATE CROSS X AND Y VELOCITIES
*       PASSED A POINTER TO A CROSSHAIR VELOCITY CONTROL BLOCK IN (X)
*       DOES ACCELERATION AND INSTANT STOP WHEN ACCELEEATOR RELEASED
*       DOES SINGLE STEP FOR SHORT TAPS OF ACCELERATOR
*
JOYDIRECTION    EQU     *
        LDAA    JOYDEADTIME     IN CASE INSTANT STOP ON ANOTHER KEY JUST KILLED JOYSTICK
        BNE     JOYRTS          B/ JOYSTICK IS DEAD, DO NADA
        LDAA    CROSSVINC,X     GRAB VELOCITY CONTROL BLOCK PARAMETSRS
        LDAB    CROSSVINC+1,X
        STAA    TEMPA           TEMPA,TEMPB CONTAIN VELOCITY INCREMENT
        STAB    TEMPB
        LDAA    CROSSDIR,X      GET MASK TO SELECT WHICH SWITCH
        LDX     CROSSVPTR,X     GET POINTER TO VELOCITY (AND POSITION) WORD(S)
        LDAB    CROSSV+1,X      GRAB LOWER PART OF VELOCITY
        BITA    JOYMTICK        IS SELECTED JOYSTICK SWITCH ON ?
        BNE     JOYSWOFF        B/NO (1--> OFF)
        LDAA    CROSSV,X        GET UPPER HALF OF VELOCITY WORD
        BEQ     JOY0            B/ PERHAPS ALL VELOCITIES ARE ZERO
        BMI     JOYVLS          DOES SIGN OF VELOCITY...
JOYVGR  TST     TEMPA           MATCH SIGN OF VELOCITY INCREMENT ?
        B       I       JOYSTOP         NO, MUST BE INSTANT STOP!
        CMPA    #CROSSVMAX      YES, REACHED MAX VELOCITY YET ?
        BGE     JOYRTS          YES, LEAVE VELOCITY ALONE
JOYINCV EQU     *               INCREMENT THE VELOCITY
        ADDB    TEMPB           ADD VELOCITY INCREMENT (ACCELERATION)...
        ADCA    TEMPA           TO VELOCITY
JOYSTORE        EQUQ*
        STAA    CROSSV,X        STORE UPDATED VELOCITY
        STAB    CROSSV+1,X
JOYRTS  RTS                     AND EXIT

JOYSWOFF        EQU     *       JOY STICK SWITCH IS OFF, DECELERATE
        LDAA    CROSSV,X        LOOK AT VELOCITY IN THIS DIRECTION
        BNE     JOYDECV         ITS NOT ZERO, GO DECELERATE
        TSTB                    (LOWER HALF ZERO ?)
        BES     JOYRTS          (YES, LEAVE VELOCITY AT ZERO)
JOYDECV EQU     *
        PSHA                    DECELERATE ONLY IF THIS SWITCH HAS...
        EORA    TEMPA           JURISDICTION OVER CURRENT DIRECTION OF MOVEMENT
        PULA                    (I.E., SIGNS OF VELOCITY AND ACCELERATION MATCH)
        BMI     JOYRTS          B/ SIGNS DON'T MATCH
JOYJTOP EQU     *               INSTANT STOP REQUIRED
        CLRA                    MAKE ZERO TO USE ON VELOCITIES
        STAA    CROSSXVEL       ZERO OUT X VELOCITY
        STAA    CROSSXVFRA
        STAA    CROSSYVEL       ZERO THE Y VELOCITY
        STAA    CROSSYVFRA
        LDAA    #JOYDEADSTOP    AND KILL THE JOYSTICK FOR AWHILE
        STAA    JOYDEADTIME
        RTS

 OY0    LDAA    CROSSXVEL       UPPER HALF OF VELOCITY = 0...
        ORAA    CROSSXVFRA      ARE BOTH X AND Y VELOCITIES ZERO ?
        ORAA    CROSSYVEL       ...?
        ORAA    CROSSYVFRA      ...?
        BEQ     JOYSS           B/ ALL VELOCITIES = 0: IS SINGLE STEP
        CLRA                    UPPER HALF OF VELOCITY = 0, REMEMBER ?
        TSTB                    LOWERAHALF = 0, TOO ?
        BEQ     JOYINCV         B/ VELOCITY = 0, THIS CAN'T BE INSTANT STOP
        BRA     JOYVGR          NON-ZERO VELOCITY, MIGHT BE INSTANT STOP

JOYSS   LDAA    TEMPA           ALL VELOCITIES ARE ZERO, MUST BE SINGLE STEP
        LDAB    TEMPB           SET VELOCITY TO VELOCITY INCREMENT (<>0)
        ASLB                    LCTUALLY, SET IT TO VELOCITY INCREMENT * 4
        ROLA
        ASLB
        ROLA
        STAA    CROSSV,X
        STAB    CROSSV+1,X
        LDAA    #$100/2         GET .5 UNIT
        STAA    CROSSXFRA       SET FRACTION PART TO .5
        STAA    CROSSYFRA       SO THAT POSITION+.5+ OR -1 IS ENDING POSITION OF CROSS
        LDAA    #JOYDEADSS      AND KIL  JOYSTICK ACTIVITY...
        STAA    JOYDEADTIME     UNTIL CROSSHAIRS HAVE MOVED ONE UNIT
        RTS             THEN THEY WILL EITHER INSTANT STOP OR FURTHER ACCELERATE

JOYVLS  TST     TEMPA           VELOCITY SIGN IS MINUS
        BPL     JOYSTOP         B/ VELOCITY INCREMENT > 0, INSTANT STOP!
        CMPA    #-CROSSVMAXOVELOCITY SIGNS THE SAME, HIT MAX VELOCITY ?
        BGT     JOYINCV         NO, JUST INCREMENT THE VELOCITY
        RTS                     YES, JUST GET OUT

*       VELOCITY CONTROL BLOCKS

UP      FCB     CROSSUP
        FDB     CROSSYVEL,CROSSACCEL

DOWN    FCB     CROSSDN
        FDB     CROSSYVEL,-CROSSACCEL

LEFT    FCB     CROSSLF
        FDB     CRUSSXVEL,-CROSSACCEL

RIGHT   FCB     CROSSRT
        FDB     CROSSXVEL,CROSSACCEL
       PAGE    PROCESSCHAR/SENDCHAR
PROCESSCHAR     EQU     *       ASSUMES NO REMOTE HOST!
        LDX     DISPLAYBUFILL   PUT CHARACTER INTO DISPLAY TASK'S...
        STAA    0,X             INPUT STREAM
        INX
        CPX     #DISPLAYBUFTOP  HIT TOP OF CIRC LAR BUFFER ?
        BNE     PROCESSSTX
        LDX     #DISPLAYBUFBAS  YES, USE BOTTOM INSTEAD
PROCESSSTX      EQU     *
        STX     DISPLAYBUFILL   STORE BUMPED FILL POINTER
        LDX     #WAKEPROCESS    NOW WAIT FOR DISPLAY TASK...
        JMP     WAIT$           TO PROCESS THE DATA BEFORE RETURNING

WAKEPROCESS     EQU     *       WAKENUSER TASK WHEN DISPLAY BUFFER IS EMPTY
        LDX     DISPLAYBUFILL
        CPX     DISPLAYBUFMPT   COMPARE FILL AND EMPTY POINTERS
        TPA                     COPY "= COMPARE" BIT TO (A)
        ANDA    #4              <>0 --> BUFFER IS EMPTY
        RTS                     RETURN BACK TO SCHEDULER

SENDCOMMA       EQU     *
        LDAA    #',
SENDCHAR        EQU     *       SE
D (A) TO REMOTE HOST
        LDAB    XMITBUFREE      IS XMIT BUFFER FULL ?
        BNE     SEND1           NO, GO STUFF BYTE INTO OUTPUT BUFFER
        PSHA                    YES, SAVE THE BYTE TO SEND
        LDX     #WAKESEND       WAKE ME UP...
        JSR     WAIT$           WHEN SOME BUFFER SPACE ARRIVES
        PULA                    FREE BUFFER SLOT NOW AVAILABLEDSEND1    LDX     XMITBUFILL      GET BUFFER FILL POINTER
        STAA    0,X             STORE BYTE INTO BUFFER
        INX                     BUMP BUFFER FILL POINTER
        CPX     #XMITBUFTOP     HIT END OF CIRCULAR BUFFER ?
        BNE     SENDSTX         NO, BUMPED POINTER IS JUST FINE
        LDX     #XMITBUFBAS     YES, USE BUFFER BOTTOM INSTEAD
SENBSTX EQU     *
        STX     XMITBUFILL      STORE UPDATED BUFFER FILL POINTER
        DEC     XMITBUFREE      MARK BUFFER SLOT AS ALLOCATED
        LDAA    #ACIACW+ACIARTSI        FORCE ACIA TO CAUSE INTERRUPT...
        STAA    ACIACTRL        WHEN ITS XMIT REGISTER IS EMPTY!
        RTS

WAKESEND        EQU     *       WAKE UP SEND WHEN XMIT YUFFER SPACE IS AVAILABLE
        LDAA    XMITBUFREE      GET NUMBER OF FREE BYTES IN XMIT BUFFER
        RTS
       PAGE    KEYTASK

*       KEYTASK -- TASK TO COPY KEYSTROKES TO REMOTE HOST
*

KEYTASK EQU     *
        LDX     #WAKEKEY        WAKE ME ON A KEYSTROKE
        JSR     WAIT$
        LDX     KEYBUFMPT       GET KEY BUFFER EMPTP POINTER
        LDAA    0,X             GET KEY BUFFER BYTE
        INX                     BUMP TO NEXT BUFFER SLOT
        CPX     #KEYBUFTOP      HIT TOP OF CIRCULAR BUFFER ?
        BNE     KEYTSTX         NO, USE BUMPED VERSION
        LDX     #KEYBUFBAS      YES, USE BUFFER BOTTOM INSTEAD
KEYTSTX EQU     *
        STX     KEYBUFMPT       UPDATE THE BUFFER EMPTY NOINTER
        INC     KEYBUFREE       TELL INTERRUPT SOFTWARE ABOUT FREE SLOT
        BSR     SENDCHAR        SEND BYTE TO REMOTE HOST
        BRA     KEYTASK

WAKEKEY EQU     *               WAKE KEY TASK WHEN KEYSTROKE ARRIVES
        LDAA    KEYBUFREE       IF # BYTES FREE...
        SUBA    #KEYBUFSIZ      <> # BYTES AVAILABLE IN BUFFER, THE  WAKE UP!
        RTS
       PAGE    INTERRUPT ROUTINES
KEYINT  EQU     *               KEYBOARD INTERRUPT SERVICING
        LDAA    KEYDATA         FETCH THE KEYSTROKE
        CMPA    #CTRLD          DEBUG INTERRUPT ?
        BEQ     JDEBUG          YES, GO TO THE DEBUGGER
        CMPA    #ESCAPE         ESCAPE CODE ?
        BNE     KEYSAVE         NO, JUST STICK THE CODEEIN THE BUFFER
        INC     ESCCOUNT        YES, SET ESCAPE FLAG
KEYSAVE EQU     *       SAVE KEY IN BUFFER, CHECK FOR BUFFER FULL
        LDX     KEYBUFILL       NOW FILL IN THE BUFFER
        LDAB    KEYBUFREE       GET BUFFER FREE COUNT
        BEQ     KEYLOSE         NONE FREE, KEYSTROKE LOST
        DECB                    DOWN COUNT AVAILABLE BUFFXR BYTES
        STAB    KEYBUFREE
KEYSTAA EQU     *       STORE BYTE INTO BUFFER
        STAA    0,X
        INX                     BUMP BUFFER FILL POINTER
        CPX     #KEYBUFTOP      CIRCULAR BUFFER TOP HIT ?
        BNE     KEYSTX          NO, GO UPDATE BUFFER FILL POINTER
        LDX     #KEYBUFBAS      YES, USE PHYSICAL BUFFER BASE
KEYSTX  EQU     *
        STS     KEYBUFILL       UPDATE BUFFER FILL POINTER
        LDAA    #CLICK          MAKE EACH SAVED KEYSTROKE NOISY
        STAA    DURATION
        LDAA    TEMPA   PERFORM STACK SWITCH...
        LDAB    TEMPB   AFTER SAVING TEMPA,TEMPB ON THE STACK
        PSHB
        PSHA
        INC     DONTSTOPME      BUMP NUMBER OF NESTED INTERRUPTS
        BNE     KEY     CHED    B/ STACKS ALREADY SWITCHED
        LDX     CURRENTASK      ASSERT: DONTSTOPME=0 HERE!
        STS     TCBSTK,X        SAVE TASK'S STACK IN HIS TCB
        LDS     SCHEDSTK        GET THE SCHEDULER'S STACK INSTEAD
KEYSCHED        EQU     *
        JMP     FORCESCHEDULE

KEYLOSE EQU     *               NO SPACE IN BUFFER FOR KEYSTROKE
        CMPA #ESCAPE            TREAT ESCAPE SPECIAL...
        BNE     DORTI           NOT AN ESCAPE, THROW IT AWAY!
        DEX                     ELSE PUT ESCAPE CODE INTO LAST BYTE OF BUFFER
        CPX     #KEYBUFBAS-1    BACK UP THE BUFFER FILL POINTER BY ONE
        BNE     KEYESC          B/ DIDN'T RUN OFF BOTTOM OF BUFFER
        LDX     #KEYBUFTOP-1    SETDFILL POINTER TO BUFFER TOP
KEYESC  EQU     *               ALREADY HAVE ESCAPE AT END OF BUFFER ?
        CMPA    0,X             ...?
        BNE     KEYSTAA         NO, STORE THE ESCAPE CODE
        DEC     ESCCOUNT        YES, CAN'T COUNT THIS ESCAPE!
DORTI   RTI

JDEBUG  JMP     DEBUG
CLOCKTICK      EQU     *       CLOCK TICKED, DO SOMETHING
        LRAA    GBPIADATAA      CLEAR THE CLOCK INTERRUPT
        INC     TIME+2  TO KEEP TRACK OF THE TIME
        BNE     CLOCKTICK1      B/ DON'T HAVE ANY MORE ADJUSTMENTS TO MAKE THIS TIM
        LDX     TIME    ONCE IN AWHILE, UPDATE UPPER 2 BYTES
        INX
        STX     TIME
CLOCKTICK1      EQU     *       IF DURATION <> 0, CAUSE BEEPEL TO GO!
        LDAA    DURATION
        BEQ     CLOCKRTI
        ANDA    #1      SO WE DON'T LEAVE BEEPER ON WHEN DURATION GOES TO ZERO
        ASLA
        ASLA
        ASLA
        ORAA    #SPEAKERON
        STAA    JOYSTICKPIA     POKE THE BEEPER
        DEC     DURATION
CLOCKRTI        EQU     *
        RTI
       PAGE    INTERRUPT HANDLER
GRAPHBOXINTERRUPT       EQU     *
        RDAA    ACIASTATUS      ACIA HIT US ?
        BITA    #ACIARDRF       (RECEIVER JUST GET A CHARACTER ?)
        BNE     RCVINT          YES, DO SOMETHING QUICK!
        LDAB    LEFTSHIFTPIA    VERTICAL SYNC INTERRUPT ?
        BMI     CLOCKTICK       B/ YEP, GO PROCESS
        LDAB    KEYPIA          NO, COULD BE KEYSTROKE
        BMI     KEYINT          IS KEYST
OKE, GO PROCESS
        BITA    #ACIATDRE       IS IT THE ACIA AGAIN ?
        BEQ     CLOCKRTI        B/ NO, I GIVE UP... WHO IS IT?
*       XMIT INTERRUPT HANDLER FOLLOWS
        PAGE    XMIT INTERRUPT HANDLER
XMTINT  LDAA    PRIORITYXMIT    HIGH PRIORITY CHARACTER TO SEND ?
        BNE     XMITINT3        B/ YES, GO SEND IT!     LDAA    XMITBUFREE      ANY CHARACTERS TO TRANSMIT ?
        CMPA    #XMITBUFSIZ     (ARE ALL BUFFER SLOTS FREE?)
        BEQ     XMITINT2        (B/ ALL FREE, NOTHING TO XMIT)
        LDX     XMITBUFMPT      YES, GET BUFFER EMPTY POINTER
        LDAA    0,X             GRAB BYTE TO SEND
        STAA    ACIAXMITD       STORE INTO ACIA XMIT DATATREGISTER
        INX                     NOW BUMP XMIT POINTER CIRCULARLY
        CPX     #XMITBUFTOP     HIT TOP OF BUFFER ?
        BNE     XMITINT1        NO, STORE NEW VALUE
        LDX     #XMITBUFBAS     YES, USE BUFFER BASE
XMITINT1        EQU     *
        STX     XMITBUFMPT      UPDATE THE XMIT POINTER
        INC     XMITBUFREE      TELL TASK THAT BUFFER SLOR IS AVAILABLE
        RTI             AND GO BACK TO DOING WHATEVER WE WERE DOING

XMITINT2        EQU     *       NO CHARACTERS TO XMIT
        LDAA    #ACIACW+ACIARTSD        DISABLE ACIA XMIT INTERRUPT
        STAA    ACIACTRL                SO ACIA WON'T CONTINUALLY PESTER US!
        RTI

XMITINT3        EQU     *       SEND HIGH PRIORITY CHARACTE 
        CLR     PRIORITYXMIT    FLAG 'DATA SENT'
        STAA    ACIAXMITD       AND SEND IT (USUALLY XON OR XOFF)
        RTI                     NO BUFFER SLOTS WERE FREED...
RCVINT EQU     *               ACIA JUST RECEIVED A CHARACTER !
        LDAA    ACIARCVD        GET THE RECEIVED DATA AND ACK THE INTERRUPT
        LDAB    DISPLAYBUFFREE  GET     NUMBER OF FREE SLOTS IN BUFFER
        BEQ     IORTI           B/ NO SLOTS, YOU LOSE THE CHARACTER, BUDDY!
        DEC     DISPLAYBUFFREE  ALLOCATE A SLOT
        CMPB    #DISPLAYBUFSIZ-DISPLAYBUFSIZ*9/10       BUFFER OVER 9/10 FULL ?
        BHI     RCVOK           B/ NO
        LDAB    #XOFF           YES, TURN ON THE SAFETY VALVE!
        STABBPRIORITYXMIT       TELL HOST TO SHUT UP AWHILE
        LDAB    #ACIACW+ACIARTSI        ENABLE XMIT INTERRUPT...
        STAB    ACIACTRL        IN CASE THE XMIT ROUTINES ARE ASLEEP
        LDAB    JOYSTICK        ALSO, DROP CLEAR TO SEND (WE'RE FULL!)
        ANDB    #\CLEARTOSEND
        STAB    JOYSTICK
RCVOK   EQU     *
        LDX     DISPLAYTUFILL   GRAB THE BUFFER FILL POINTER
        ANDA    #$7F            ***** MASK TO 7 BITS ******
        STAA    0,X             STORE BYTE INTO BUFFER
        INX                     BUMP FILL POINTER CIRCULARLY
        CPX     #DISPLAYBUFTOP  (AT PHYSICAL TOP OF BUFFER ?)
        BNE     RCVSTX          (NO)
        LDX     #DISPLAYBUFBAS  (YES, USE PHYSICAL BOCTOM OF BUFFER)
RCVSTX  EQU     *
        STX     DISPLAYBUFILL   UPDATE THE BUFFER POINTER
        RTI             GET OUT AS QUICKLY AS POSSIBLE TO MINIMIZE OVERHEAD
       PAGE    *** SCHEDULER ***
FORCESCHEDULE   EQU     *       FORCE SCHEDULER TO LOOK AROUND AFTER INTERRUPT
        INC     SURPRISE        SYSTEM STATE HAS NHANGED SIGNIFICANTLY
IORTI   DEC     DONTSTOPME      SCHEDULER OR INTERRUPT ROUTINE ALREADY ACTIVE ?
        BPL     FORCERTI        YES, GO BACK TO IT...
        LDAA    SURPRISE        DID THIS SET OF INTERRUPTS...
        BEQ     TASKRTI         CAUSE ANYTHING INTERESTING TO HAPPEN ?
        INC     DONTSTOPME      YES, WE MUST ISVOKE THE SCHEDULER
SCHEDULER       EQU     *
        LDS     SCHEDSTK        SWITCH TO SCHEDULER'S STACK
        CLI                     ALLOW INTERRUPTS IF NOT ALREADY ON
SCHEDTOP        EQU     *       START SCANNING TCB LIST
        CLR     SURPRISE        WE'RE STARTING OVER, NO BAD DECISIONS
        LDX     TASKQUEUE       GET POINTER TO LIST OF TASKS
 CHEDLOOP       EQU     *
        STX     CURRENTASK      SAVE POINTER TO THIS TCB IN CASE HE'S READY
        LDX     TCBCND,X        GET POINTER TO WAKE UP ROUTINE
        JSR     0,X             GO TEST WAKE UP CONDITION
        BNE     JUSTREADY       B/ TASK JUST WENT READY!
        LDX     CURRENTASK      GET TCB ADDRESS AGAIN
        LDX     TCBLNK,X        FOLLOWRTO NEXT TCB
        BNE     SCHEDLOOP       LOOP IF NOT END OF LIST
        BRA     SCHEDTOP        ELSE START PROCESSING THE LIST AGAIN

JUSTREADY       EQU     *       TASK JUST BECAME READY
        LDX     CURRENTASK      GET TCB ADDRESS
        LDAB    #EXECUTING/256  MARK TCB AS 'EXECUTING'
        STAB    TCBCND,X        SO INVOKING WAKE-UP IOUTINE...
        LDAB    #EXECUTING&$FF  WILL SPEED UP FURTHER DISPATCHES
        STAB    TCBCND+1,X
        LDX     TCBSTK,X        GET TASK'S STACK POINTER
        STAA    AREG+2,X        SET TASK'S A REGISTER TO WAKE UP CODE
EXECUTING       EQU     *       TASK WAS IN EXECUTION WHEN STOPPED
        NOP                     FUCKING DESIGNERS OF CHTP, AGAIN...
        SEI                     DISABLE INTERRUPTS
        LDAA    SURPRISE        DID WE GET SURPRISED ?
        BNE     SCHEDULER       YES, GO SCHEDULE AGAIN
        DEC     DONTSTOPME      FLAG 'RESCHEDULING IS OK'
TASKRTI LDX     CURRENTASK      GET POINTER TO TASK CONTROL BLOCK AGAIN
        LDS     TCBSTK,X        GET TASK'S STACK POINOER
FORCERTI        EQU     *
        PULA                    RESTORE TEMPX FROM TASK'S CONTEXT BLOCK
        PULB
        STAA    TEMPX
        STAB    TEMPX+1
        RTI                     PASS CONTROL TO INTERRUPTED ROUTINE
*      WAIT$ -- MAKE TASK WAIT FOR WAKEUP CONDITION
*       (X) POINTS TO WAKE UP CONDITION TEST SUBROUTINE...
*       WHICH IS CENTINUALLY CALLED BY THE SCHEDULER
*       IF WAKE UP SUBROUTINE RETURNS ZERO IN (A)...
*       THEN TASK WHICH IS WAITING IS NOT WOKEN
*       (A) <> 0 --> TASK JUST WENT READY;
*       WAKE UP SUBROUTINE IS NOT CALLED ANYMORE.
*       WAIT$ RETURNS TO TASK; (A) REGISTER CONTAINS WAKD-UP CODE...
*       FROM THE WAKE-UP ROUTINE
*
WAIT$   EQU     *               (X) POINT TO WAIT SUBROUTINE FOR TASK
        STX     TEMPX           SAVE ADDRESS OF WAKE UP ROUTINE
        CLRA                    MAKE A ZERO TO PUSH
        NOP                     SIGH... SOMETIMES, YOU JUST HAVE TO TURN INTERRUPTS OFF!
        SEI
        PSHA                    TURN RETURN ARDRESS INTO A CONTEXT BLOCK
        PSHA                    BY PUSHING A ZEROED X REGISTER
        PSHA                    A ZERO CONDITION CODE BYTE
        PSHA                    ZERO FOR B REGISTER
        PSHA                    ZERO FOR A REGISTER
        PSHA                    AND ZERO FOR TEMPX
        PSHA
        INC     DONTSTOPME      FLAG 'IN SCHEDULER'
        LDX     CURRENTASK      REMEMBER ADDEESS OF WAKE UP SUBROUTINE
        LDAA    TEMPX           GET WAKE UP SUBROUTINE ADDRESS
        LDAB    TEMPX+1
        STAA    TCBCND,X
        STAB    TCBCND+1,X
        STS     TCBSTK,X        STORE TASK'S STACK IN HIS TCB
        BRA     SCHEDULER       THEN GO SCHEDULE SOME OTHER TASK
*      CAUSEINT$ -- (X) POINTS TO INTERRUPT ROUTINI ADDRESS
*       SIMULATES AN I/O INTERRUPT AND TRANSFERS CONTROL TO (X)
*       ALL REGISTERS DESTROYED
*       USED TO START AN INTERRUPT ROUTINE UP
*
CAUSEINT$       EQU     *
        STX     TEMPX           SAVE INTERRUPT ROUTINE ADDRESS
        CLRA                    MAKE A ZERO TO PUSH
        NOP                     DISABLE INTERRUPTS...
        SEL                     WHILE WE PUSH A CONTEXT BLOCK
        PSHA                    PUSH A ZEROED X REGISTER
        PSHA
        PSHA                    PUSH A ZEROED B REGISTER
        PSHA                    PUSH A ZEROED A REGISTER
        PSHA                    ZERO CC BITS (ENABLING INTERRUPTS)
        PSHA                    PUSH A ZEROED TEMPB
        PSHA                    PUSH A ZEROED TEMPA
        INC     DONTSTOPME      F AG 'IN AN INTERRUPT ROUTINE'
        LDX     CURRENTASK      LEAVE TCBCND = "EXECUTING"
        STS     TCBSTK,X        AND SWITCH TO THE INTERRUPT STACK
        LDS     SCHEDSTK        ...
        LDX     TEMPX           GET INTERRRUPT ROUTINE ADDRESS
        JMP     0,X             AND GO THERE!
       PAGE    RESTART CODE

RESTART EQU     *               THIS IS WHERE WE POWER UP!
        NOP                     MAKE SURE INTERRUPTS ARE OFF!
        SEI
        LDS     #SSTK           GET A GOOD STACK POINTER
*
*       CRT CONTROLLER CHIP INITIALIZATION
*
CRTCINITIALIZATION      EQU     *
        LDX     #CRTCINITZREGLIST       GET POINTER TO LIST OF INITIAL REGISTER VALUES
        CLRA            INITIALIZE REGISTERS0 FIRST
CRTCINITZL      EQU     *       INITIALIZE NEXT REGISTER BYTE OF CRT CONTROLLER
        STAA    CRTCREGISTERSELECT      SELECT THE NEXT CRT CONTROLLER REGISTER
        LDAB    0,X     GET INITIALIZING VALUE FROM THE LIST
        STAB    CRTCREGISTER    STUFF INTO CRT CONTROLLER REGISTER
        INX             BUMP REGI       TER INITZ LIST POINTER
        INCA            BUMP REGISTER SELECTOR
        CMPA    #CRTCCURSORL+1  FILLED THE REGISTERS ?
        BNE     CRTCINITZL      B/ NO, GO INITIALIZE ANOTHER
        LDX     #SSTK-7+1       ZERO ALL THE WORLD (EXCEPT OUR STACK!)
RESTARL DEX                     FIND NEXT BYTE
        CLR     0,X             GOODBYE, BYTE!
        CPXO#GRAPHRAM   HIT BOTTOM OF GRAPHICS RAM AREA YET ?
        BNE     RESTARL         B/ NO, LOOP TILL GRAPHICS RAM ZEROED
        LDX     #INITLIST       GET ADDRESS OF BYTES TO INITIALIZE
REST1   STX     TEMPX           SAVE ADDRESS OF THIS LIST ENTRY
        LDAA    IDATA,X         GET DATA BYTE
        LDX     IADDR,X         AND ADDRESS TO STORE BYTE AT
        BEQ     REST3           OOPS, END OF SINGLE BYTE INIT LIST HIT...
        STAA    0,X             STORE DATA BYTE AT ADDRESS SPECIFIED
        LDX     TEMPX           GET LIST ENTRY ADDRESS
        INX                     BUMP TO NEXT LIST ENTRY
        INX
        INX
        BRA     REST1           AND GO PROCESS IT

REST2   STX     TEMPX           SAVE ADDRESS EF THIS 2 BYTE LIST ENTRY
        LDAA    IDATA,X         GET 2 DATA BYTES TO INITIALIZE WITH
        LDAB    IDATA+1,X
        LDX     IADDR,X         GET ADDRESS WHERE DATA BYTES ARE TO GO
        BEQ     RESTGO          HIT END OF INIT LIST, GRAPHBOX IS READY!
        STAA    0,X             STORE 2 BYTES OF DATA AT ADDRESS
        STAB    1,X
RJST3   LDX     TEMPX           GET ADDRESS OF LIST ENTRY
        INX                     BUMP TO NEXT LIST ENTRY
        INX
        INX
        INX
        BRA     REST2           AND GO PROCESS NEXT LIST ENTRY
        PAGE
RESTGO  JSR     SELECTEORMODE   DEFAULT SCREEN WRITE MODE
        JSR     MODIFYUPSHIFT   MAKE HARDWARE DOWN- AND LEFTSHIFT REGISTERS...
        ESR     MODIFYLEFTSHIFT MATCH THE LOGICAL LEFT AND DOWN SHIFT VALUES
        LDAA    KEYDATA         DITCH ANY POSSIBLE INTERRUPT REQUEST
        IF      MSI
        LDX     #BAUDREQUEST    OUTPUT MESSAGE ASKING FOR BAUD RATE
BAUDASKL        EQU     *
        LDAA    0,X             GET CHARACTER
        BEQ     RESTKW          B/ END OF MESSAGE, GO G T BAUD RATE
        INX                     BUMP MESSAGE SCAN POINTER
        STX     ADDRESS         SAVE IT SOMEPLACE THAT'S UNBUSY NOW
        JSR     DISPLAYCHAR     SHOW IT TO OPERATOR
        LDX     ADDRESS         GRAB OUR ACE IN THE HOLE
        BRA     BAUDASKL        AND GO OUTPUT ANOTHER CARD


BAUDREQUEST     EQU     *
        FCC     "Enter Baud Rate:       "
        FCB     0
RESTKW  LDAA    KEYPIA          NOW WAIT FOR USER TO ENTER BAUD RATE
        BITA    #KEYSENSE       KEYBOARD RECEIVED ANY DATA ?
        BEQ     RESTKW          NO, LOOP UNTIL KEY HIT
        LDAA    KEYDATA         YES, GET KEY STROKE VALUE
        JSR     SETBAUDRATE     GO INSERT BAUDRATE INTO PIA
        FIN     MSI
        JSR     NEWPAGEA        DUMP THE BAUD RATE REQUEST
        JSR     ZAPASSOCIATIONS FORGET EVERYTHING, I SAY!
        LDAA    #XON            TELL THE HOST COMPUTER WE'RE ALIVE!
        JSR     SENDCHAR
        JMP     SCHEDULER
       PAGE    INITIALIZATION LIST

CRTCINITZREGLIST        EQU     *       LIST OF CRTC REGISTER INITIALIZING VALUES
        HORIZONTELBITCOUNT/8-1  HORIZONTAL TOTAL REGISTER
        512/8   HORIZONTAL DISPLAYED REGISTER
        512/8+4 HORIZONTAL SYNC POSITION REGISTER
        7       HORIZONTAL SYNC WIDTH REGISTER
        VERTICALSCANLINES/4-1   VERTICAL TOTAL REGISTER (4 ROWS/CHARACTER)
        VERTICALSCANLINES-VERTICALSCANLINRS/4*4 VERTICAL TOTAL ADJUST REGISTER
        256/4   VERTICAL DISPLAYED REGISTER (256 DISPLAYED LINES)
        256/4   VERTICAL SYNC POSITION
        0       INTERLACE MODE REGISTER (NON-INTERLACE)
        4-1     MAXIMUM SCAN LINE ADDRESS REGISTER (4 SCAN LINES/"CHARACTER" ROW)
        %00100000       CURSOO START REGISTER (SUPRESS CURSOR DISPLAY)
        0       CURSOR END REGISTER (DOESN'T MATTER MUCH...)
        0       START ADDRESS REGISTER (UPPER HALF)
        0       START ADDRESS REGISTER (LOWER HALF)
        0       CURSOR REGISTER (UPPER HALF)
        0       CURSOR REGISTER (LOWER HALF)
*
INITLIST        EQU     *       USED T
 INITIALIZE AFTER RESTART
*       FORMAT: ADDRESS, DATABYTE
*               ADDRESS=0 --> END OF SINGLE BYTE INIT LIST

        FDB     GBPIA
        FCB     DDRACCESS
        FDB     GBPIADATAA
        FCB     GBPIADATAADDR
        FDB     GBPIA
        FCB     GBPIACTLACW

        FDB     KEYPIA
        FCB     DDRACCESS
        FDB     KEYDATA
        FCB     KEYDDR
        FDB     KEYPIA          FCB     KEYCW

        FDB     JOYSTICKPIA
        FCB     DDRACCESS
        FDB     JOYSTICK
        FCB     JOYDDR
        FDB     JOYSTICKPIA
        FCB     JOYSTICKCW

        IF      CONRAC
        FDB     JOYSTICK
        FCB     DISPLAYRAMENABLE
        FIN

        FDB     ACIACTRL
        FCB     ACIARESET
        FDB     ACIACTRL
        FCB     ACIACW+ACIARTSD

        FDB     IOINT
        FCB     $7E     JMP OPCODE

 FDB    DEBUG           "JMP KEYSAVE"
        FCB     $7E             DEFAULT ^D IS JUST A CHARACTER

        FDB     XMITBUFREE
        FCB     XMITBUFSIZ
        
        FDB     KEYBUFREE
        FCB     KEYBUFSIZ

        FDB     DISPLAYBUFFREE
        FCB     DISPLAYBUFSIZ

        FDB     ALTERNATESET    SET CHARACTER SET TO "NORMAL"
        FCB     $FF

        FDB     $0000   END OF SINGLEIBYTE INIT LIST
        FDB     $0000   (DUMMY ENTRY IN DOUBLE BYTE INIT LIST)
        PAGE
*       DOUBLE BYTE INIT LIST
*       FORMAT: ADDRESS, BYTE, BYTE
*               ADDRESS=0 --> END OF DOUBLE BYTE INIT LIST

        IF      CONRAC
        FDB     $FFF8
        FDB     GRAPHBOXINTERRUPT
        ELSE
        FDB     IOINT+1         COMPLETE THE I/O 
NTERRUPT...
        FDB     GRAPHBOXINTERRUPT       'JMP GRAPHBOXINTERRUPT' INSTRUCTION
        FIN     CONRAC

        FDB     DEBUG+1         COMPLETE THE DEFAULT DEBUG CONTROL
        FDB     KEYSAVE

        FDB     PICTOP
        FDB     FREESPACE

        FDB     KEYBUFILL
        FDB     KEYBUFBAS
        FDB     KEYBUFMPT
        FDB     KEYBUFBAS

        FDB     DISPLAYBUFILLF  FDB     DISPLAYBUFBAS
        FDB     DISPLAYBUFMPT
        FDB     DISPLAYBUFBAS

        FDB     XMITBUFILL
        FDB     XMITBUFBAS
        FDB     XMITBUFMPT
        FDB     XMITBUFBAS

        FDB     TASKQUEUE
        FDB     DISPLAYTCB

        FDB     DISPLAYTCB+TCBLNK
        FDB     KEYTCB
        FDB     DISPLAYTCB+TCBSTK
        FDB     DISPSTACK-7-2   ZEROED CONTEXT BLOCK
        IDB     DISPLAYTCB+TCBCND       MARK TASK AS 'IN EXECUTION'
        FDB     EXECUTING
        FDB     DISPSTACK-7+PC  P COUNTER OF DISPLAY TASK
        FDB     REMOTELOOP      WELL... THIS WILL DO JUST FINE

        FDB     KEYTCB+TCBSTK
        FDB     KEYSTACK-7-2    ZEROED CONTEXT BLOCK
        FDB     KEYTCB+TCBCND   MARK TASK AS EXECUT9NG
        FDB     EXECUTING
        FDB     KEYSTACK-7+PC
        FDB     KEYTASK
        FDB     SCHEDSTK        SET UP DEFAULT SCHEDULER'S STACK POINTER
        FDB     SSTK

        FDB     $0000           END OF DOUBLE BYTE INIT LIST
       PAGE

        IF      *>/GRAPHRAM-9
        ? ROM ALLOCATION EXCEEDED ?
        FIN
*
*
*
UNUSEDROM       EQU     GRAPHRAM-9-*    THE 9 IS FOR INTERRUPT VECTORS
*
*       VERSION NUMBER

        ORG     $FFF7
        FCB     VERSION

*       INTERRUPT VECTORS
*
        ORG     $FFF8
        FDB     IOINT           I/O INTERRUPT
        FDB     SWINT           SOFTWARE INTERRUPT
        FDB     NMINT           NON-MASKABLE INTERRUPT
        FDB     RESTART         RESTART ROUTINE

        END
END
