        TITLE   *** COLOR COMPUTER GRAPHICS TERMINAL SOFTWARE ***
        NAME    COLORGRAPH
        WITH    WI=105,DE=51
*       EDITED 07/12/83 2000 HOURS
*       COPYRIGHT (C) 1983 BY SOFTWARE DYNAMICS
*       ALL RIGHTS RESERVED
*
VERSION EQU     $03     LEFT DIGIT = MAJOR REV, RIGHT DIGIT = MINOR REV
*
CHARHEIGHT      EQU     8       # ROWS IN A CHARACTER
CHARWIDTH       EQU     6       # COLUMNS IN A CHARACTER POSITION
SCREENHEIGHT    EQU     192     NUMBER OF ROWS ON THE SCREEN
SCREENWIDTH     EQU     256     NUMBER OF DOTS ACROSS THE SCREEN
CHARLEFTSIDE    EQU     1       CURSOR X AFTER NEWPAGE
CHARTOPSIDE     EQU     (SCREENHEIGHT/CHARHEIGHT)*CHARHEIGHT-1 CURSOR Y AFTER NEWPAGE
NBROW           EQU     SCREENWIDTH/8   NUMBER OF BYTES PER ROW
NROWS           EQU     SCREENHEIGHT    NUMBER OF ROWS DOWN SCREEN
SCREENBOTTOM    EQU     $200            16*1024-6144-512  Lowest displayable byte
                ; note: this byte is screen's upper left corner
SCREENTOP       EQU     SCREENBOTTOM+NBROW*NROWS HIGHEST ADDRESS DISPLAY BYTE
DEFAULTBACKGROUND      EQU     $FF     FOR BLACK-ON-WHITE
*       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
*       SPECIAL KEYSTROKES
*
CTRLD   EQU     $04     CONTROL D (ACTIVATE DEBUG)
LF      EQU     $0A     LINE FEED
CR      EQU     $0D     CARRIAGE RETURN
        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+2      1ST BYTE OF PICTURE DATA

        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
         with  wi=132,de=66
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 2   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 2   Pointer to SUBROUTINE TO WRITE (A) TO (U)
*                               (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
TARGETRIGHT     RMB 2   PLACE ON SCREEN TO PLACE RIGHTMOST 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 2   LOGICAL Y POSITION TARGET

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
CURSORON        RMB 1   REMEMBERS THAT CURSOR IS DISPLAYED
CURSORBLINKDELAY RMB 2  counts down to toggle cursor blink
currentbackground rmb 1 0 --> black background, $FF --> white background
stack    equ $ff                       put it somewhere
        page
        org     $2100
SetUpColorComputer ; resets Color Computer Hardware properly
*???? Need RefreshScreen, which clears screen, displays chess board
* Need FlashPiece, to indicate computer move
* Need Display Piece (synonom fo r Erase Piece)
*                                      (last page holds "dummy" dead row)
*
         sei
         lds   #Stack
         clra
         tfr   a,dp
        setdpr  0               let assembler know where "page zero" is

         clr   cursoron                remember, no cursor showing!
         jsr   SelectEORMode           set display mode
         lda   #defaultbackground      select black chars on white background
         sta   currentbackground
         jsr   newpage                 erase the screen display
         ldx   #$100                   delay until cursor changes state next
         stx   cursorblinkdelay
*
*        select G6R mode, move display buffer to top of 16k space
*
         lda   #%110                   "G6R" mode
         ldb   #3                      = # SAM chip bits to set
         ldx   #$FFC0                  SAM chip address
         jsr   SetSAM                  set up SAM chip properly
         lda   $ff22                   (don't disturb 3 lsbs)
         anda  #%111
         ora   #%11110000              finish G6R mode selection
         sta   $ff22                   (see color computer tech ref manual)
         lda   #ScreenBottom/512       = page register select
         ldb   #7                      = # bits to set
         jsr   SetSAM

         jsr   PrintText
         fcc   "Welcome to ColorMate!"
         fcb   $0d,$0a
         fcc   "This is the best thing since sliced bread!"
         fcb   $0d,$0a
         fcc   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
         fcb   $0d,$0a
         fcc   "abcdefghijklmnopqrstuvwxyz"
         fcb   $0d,$0a,$00

waitkey
         ldx   cursorblinkdelay
         dex
         stx   cursorblinkdelay
         bne   waitkey1
         ldx   #$100                   delay until cursor changes state next
         stx   cursorblinkdelay
         jsr   cursortoggle
*** Note: cursor ONLY blinks when there are Poll requests to Keyboard!
*** this keeps "make cursor go away" overhead zero unless waiting for user!!

waitkey1
         jsr   [$a000]                 see if keyboard char present
         beq   waitkey
         tst   cursoron                is cursor on?
         beq   waitkey2
         psha                          save the character
         jsr   cursortoggle            yes, make cursor go away
         pula
waitkey2
         cmpa  #$03                    escape ?
         beq   waitspecial
         jsr   putchar                 output keystroke
         bra   waitkey                 and wait for another

waitspecial
         jsr   [$a000]                 wait for next keystroke
         beq   waitspecial
         cmpa  #$03
         beq   drawchess1
         anda  #$1f                    make it into a control character
         jsr   putchar
         bra   waitkey

drawchess1
         ldx   #0
         lda   #$0c                    erase the screen
         jsr   putchar                 poof!

         jsr   drawchessboard

drawchesswait
         jsr   [$a000]
         beq   drawchesswait
         bsr   DrawChessMen
         bra   *

         page
DrawChessMen ; draw all chess men on chess board
         ldx   #ChessBoardEnd
DrawChessMan ; draw next chess man on chess board
         lda   ,-x                     fetch piece in square
         pshx                          save pointer
         bsr   DrawChessPieceAatX      draw chess piece in (A) at Square (X)
         pulx
         cmpx  #ChessBoard             all chess pieces drawn ?
         bne   DrawChessMan            b/ no
         rts

DrawChessPieceAatX ; draw chess piece in (A) at square designated by (X)
         tsta                          empty square ?
         beq   DrawChessPieceAatXRTS   b/ yes, nothing to draw!
         psha                          save name of piece to display
         tfr   x,d                     determine screen coordinate
         tfr   b,a                     (A)=row # * 8, (B)= column number
         psha                          save row number * 8
         pshb                          save column number
         andb  #7                      actual column number
         lsra                          shift row number to LSBs
         lsra
         lsra
         anda  #7                      actual row number
         psha                          save y coordinate generator
         lda   #ChessBoardSquareXSize  in dots
         mul                           = offset to left corner of square
    addd #ChessBoardLeftX+(ChessBoardSquareXSize-ChessPiecePictureXSize)/2
         ; add actual X value of left corner of square
         tfr   d,x
         pula                          = row number
         ldb   #ChessBoardSquareYSize  in dots
         mul
    addd  #ChessBoardUpperLeftY-7*ChessBoardSquareYSize-(ChessBoardSquareYSize-ChessPiecePictureYSize)/2
         jsr   setcursorxy             set the graphics cursor location
         pula                          get column number again
         asla                          compute column number * 8
         asla                          (aligns LSBs of row and column)
         asla
         eora  ,s+                     bit 2 is 1 --> square is white
         asla                          bit 3 is 1 --> square is white
PersonPiece equ $10 this should be removed!
         anda  #PersonPiece            extract color bit of square from noise
         eora  ColorOfWhite            flip colors if person is white
         eora  ,s+                     flip piece color bit if white square
PieceNameMask equ $1e this should be removed!
         anda  #PieceNameMask          extract name of piece
         ldu   #PieceToPictureTable    translate piece name to picture
         ldu   a,u                     fetch pointer to bit picture for piece
         ldx   #ChessPiecePictureXSize
         ldd   #ChessPiecePictureYSize
         jsr   DrawPictureSizeXDatU
DrawChessPieceAatXRTS
         rts

ColorOfWhite fcb 0 this should be removed!

         org   (*//64)*64
ChessBoard ; KLUGE! delete this when merge with CHESSD
         fcb   $5A,$5E,$5C,$58,$54,$5C,$5E,$56
         fcb   $50,$50,$50,$50,$50,$50,$50,$50
         fcb   $00,$00,$00,$00,$00,$00,$00,$00
         fcb   $00,$00,$00,$00,$00,$00,$00,$00
         fcb   $00,$00,$00,$00,$00,$00,$00,$00
         fcb   $00,$00,$00,$00,$00,$00,$00,$00
         fcb   $60,$60,$60,$60,$60,$60,$60,$60
         fcb   $6A,$6E,$6C,$68,$64,$6C,$6E,$66
ChessBoardEnd ; end of KLUGE chessboard


PrintText ; (X) points at text string to print
         pulx
         lda   ,x+
         beq   PrintTextRts
         pshx
         jsr   Putchar
         bra   PrintText

PrintTextRts
         jmp   ,x

         page
SetSAM   rora                          check mode bit state
         bcs   SetSAM1                 b/ bit is set
         sta   ,x                      bit is reset, hit SAM register
         bra   SetSAM2
SetSAM1  sta   1,x                     hit appropriate sam register
SetSAM2  leax  2,x                     advance to next SAM chip pair
         decb                          down count number of bits to set
         bne   SetSAM                  b/ more SAM bits to set
         rts
         page
ChessBoardLeftBorderX equ 2*CharWidth   so we have room for row numbers
ChessBoardLeftX      equ ChessBoardLeftBorderX+1 leave 1 dot for border
ChessBoardUpperBorderY equ ScreenHeight-1 pushed against top of screen
ChessBoardUpperLeftY equ ChessBoardUpperBorderY-1 leave 1 dot for border
ChessBoardSquareXSize equ 20           8 rows leaves space for column letters
ChessBoardSquareYSize equ 20           screen has 1:1 aspect ratio
ChessPiecePictureXSize equ 16          in dots
ChessPiecePictureYSize equ 16          in dots

DrawChessBoard ; draw outline and square for chessboard
         ldx   #ChessBoardLeftBorderX  set upper left corner
         ldd   #ChessBoardUpperBorderY
         jsr   setcursorxy
         ldx   #8*ChessBoardSquareXSize+2 room for 8 square + outline
         ldd   #8*ChessBoardSquareYSize+2 room for 8 rows + outline
         jsr   EmptyBox
         ldx   #ChessBoardLeftX        upper left corner of 1st square on board
         ldd   #ChessBoardUpperLeftY
         jsr   setcursorxy
         bsr   Draw2RowsOfSquares      with upper row offset from lower row
         bsr   Draw2RowsOfSquares      with upper row offset from lower row
         bsr   Draw2RowsOfSquares      with upper row offset from lower row
*        bsr   Draw2RowsOfSquares      with upper row offset from lower row
*        rts
Draw2RowsOfSquares ; starting from current X,Y
         bsr   DrawRowOf4Squares       doing light, dark, light, dark,...
         jsr   getcursorxy
         subd  #ChessBoardSquareYSize  move down screen one row
         leax  -7*ChessBoardSquareXSize,x move to left edge, offset by 1 square
         jsr   setcursorxy
         bsr   DrawRowOf4Squares       doing light, dark, light, dark,...
         jsr   getcursorxy
         subd  #ChessBoardSquareYSize  move down screen one row
         leax  -9*ChessBoardSquareXSize,x move back to left edge of screen
         jsr   setcursorxy
         rts

DrawRowOf4Squares ; starting with current X,Y
         bsr   DrawChessBoardSquare    draw the first pair of light, dark
         bsr   DrawChessBoardSquare    draw the second pair
         bsr   DrawChessBoardSquare    draw the third pair
*        bsr   DrawChessBoardSquare    draw the fourth pair
*        rts
DrawChessBoardSquare ; starting at current X,Y
         ldx   #ChessBoardSquareXSize  get size of square to drawn
         ldd   #ChessBoardSquareYSize
         jsr   solidbox                go draw a box to represent square
         jsr   getcursorxy
         leax  ChessBoardSquareXSize,x skip over a square
         jsr   setcursorxy
         rts

getcursorxy ; fetch values of current cursor position
         ldx   cursorx
         ldd   cursory
         rts

PieceToPictureTable equ * ; indexed by PieceName (masked to 4 bits) to get picture for piece
         #SolidPawn                    Pawn
         #SolidKing                    King
         #SolidUnmovedKing             Unmoved King
         #SolidUnmovedRook             Unmoved Rook
         #SolidQueen                   Queen
         #SolidRook                    Moved Rook
         #SolidBishop                  Bishop
         #SolidKnight                  Knight
         #HollowPawn                   Pawn
         #HollowKing                   King
         #HollowUnmovedKing            Unmoved King
         #HollowUnmovedRook            Unmoved Rook
         #HollowQueen                  Queen
         #HollowRook                   Moved Rook
         #HollowBishop                 Bishop
         #HollowKnight                 Knight
         page
*        Graphics Chess Pieces for Color Computer Chess Program
*
*        All pieces are 16 pixels by 16 pixels.
*        Chess board Squares are 20 by 20 pixels.
*
*        Design rules: no horizontal hole shall be only 1 dot.
*        All visible protrusions should be 2 or more dots in any direction.
*
         list 0
SolidRook
 fdb %0111001111001110
 fdb %0111111111111110
 fdb %0111111111111110
 fdb %0010000000000100
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0010000000000100
 fdb %0111111111111110
 fdb %0111111111111110
 fdb %1111111111111111
 fdb %1111111111111111

HollowRook
 fdb %0111001111001110
 fdb %0101111001111010
 fdb %0100000000000010
 fdb %0011111111111100
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0011111111111100
 fdb %0100000000000010
 fdb %0100000000000010
 fdb %1000000000000001
 fdb %1111111111111111
         page
SolidUnmovedRook
 fdb %0111001111001110
 fdb %0111111111111110
 fdb %0111111111111110
 fdb %0010000000000100
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111001111000
 fdb %0001111001111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0010000000000100
 fdb %0111111111111110
 fdb %0111111111111110
 fdb %1111111111111111
 fdb %1111111111111111

HollowUnmovedRook
 fdb %0111001111001110
 fdb %0101111001111010
 fdb %0100000000000010
 fdb %0011111111111100
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000110001000
 fdb %0001000110001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0011111111111100
 fdb %0100000000000010
 fdb %0100000000000010
 fdb %1000000000000001
 fdb %1111111111111111
         page
SolidKnight
 fdb %0000101000000000
 fdb %0001101100000000
 fdb %0011111111000000
 fdb %0011001111110000
 fdb %0111111111101000
 fdb %1101111111110100
 fdb %1111111111111010
 fdb %1101110111111110
 fdb %0011000111111111
 fdb %0000000011111110
 fdb %0000000011111111
 fdb %0000000111111111
 fdb %0000001111111111
 fdb %0000011111111111
 fdb %0000111111111110
 fdb %0001111111111110

HollowKnight
 fdb %0000101000000000
 fdb %0001010100000000
 fdb %0010000011000000
 fdb %0100110000110000
 fdb %1000000000101000
 fdb %1010000000010100
 fdb %1000001000001010
 fdb %1101110100000010
 fdb %0011000100000001
 fdb %0000000010000010
 fdb %0000000100000001
 fdb %0000001000000001
 fdb %0000010000000001
 fdb %0000100000000001
 fdb %0001000000000010
 fdb %0011111111111110
         page
SolidBishop
 fdb %0000001001000000
 fdb %0000011011100000
 fdb %0000111101110000
 fdb %0001111100111000
 fdb %0001111110111000
 fdb %0011111110111100
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0000100000010000
 fdb %0000111111110000
 fdb %0000111111110000
 fdb %0000111111110000
 fdb %0000100000010000
 fdb %0001111111111000
 fdb %0111111111111110
 fdb %1111111001111111

HollowBishop
 fdb %0000001001000000
 fdb %0000011011100000
 fdb %0000100101010000
 fdb %0001000100101000
 fdb %0001000010101000
 fdb %0010000010100100
 fdb %0001000001001000
 fdb %0001000000001000
 fdb %0000111111110000
 fdb %0000100000010000
 fdb %0000100000010000
 fdb %0000100000010000
 fdb %0000111111110000
 fdb %0001000000001000
 fdb %0110000110000110
 fdb %1111111001111111
         page
SolidKing
 fdb %0000000110000000
 fdb %0000011111100000
 fdb %0000000110000000
 fdb %0001100110011000
 fdb %0011111111111100
 fdb %0111011111101110
 fdb %0110111111110110
 fdb %1110111111110111
 fdb %0111111111111110
 fdb %0111111001111110
 fdb %0011111111111100
 fdb %0001000000001000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0011111111111100

HollowKing
 fdb %0000000110000000
 fdb %0000011111100000
 fdb %0000000110000000
 fdb %0001100110011000
 fdb %0010011001100100
 fdb %0100100000010010
 fdb %0101000000001010
 fdb %1001000000001001
 fdb %0100000000000010
 fdb %0100000110000010
 fdb %0010000000000100
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0011111111111100
         page
SolidUnmovedKing
 fdb %0000000110000000
 fdb %0000011111100000
 fdb %0000000110000000
 fdb %0001100110011000
 fdb %0011111111111100
 fdb %0111011111101110
 fdb %0110111001110110
 fdb %1110111001110111
 fdb %0111111111111110
 fdb %0111111001111110
 fdb %0011111111111100
 fdb %0001000000001000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0011111111111100

HollowUnmovedKing
 fdb %0000000110000000
 fdb %0000011111100000
 fdb %0000000110000000
 fdb %0001100110011000
 fdb %0010011001100100
 fdb %0100100000010010
 fdb %0101000110001010
 fdb %1001000110001001
 fdb %0100000000000010
 fdb %0100000110000010
 fdb %0010000000000100
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0011111111111100
         page
SolidQueen
 fdb %0000110000110000
 fdb %0000110000110000
 fdb %1100010000100011
 fdb %1100011001100011
 fdb %0011011111101100
 fdb %0011111111111100
 fdb %0111111111111110
 fdb %0011111111111100
 fdb %0001000000001000
 fdb %0001111111111000
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0011111111111100
 fdb %0011111111111100
 fdb %0111111111111110
 fdb %1111111111111111

HollowQueen
 fdb %0000110000110000
 fdb %0000110000110000
 fdb %1100010000100011
 fdb %1100011001100011
 fdb %0011100110011100
 fdb %0010000000000100
 fdb %0100000000000010
 fdb %0010000000000100
 fdb %0001111111111000
 fdb %0001000000001000
 fdb %0001000000001000
 fdb %0001111111111000
 fdb %0010000000000100
 fdb %0010000000000100
 fdb %0100000000000010
 fdb %1111111111111111
         page
SolidPawn
 fdb %0000000000000000
 fdb %0000000110000000
 fdb %0000011111100000
 fdb %0000001111000000
 fdb %0011111111111100
 fdb %0111111111111110
 fdb %0000001111000000
 fdb %0000011111100000
 fdb %0000011111100000
 fdb %0000111111110000
 fdb %0000111111110000
 fdb %0000011111100000
 fdb %0000111111110000
 fdb %0001111111111000
 fdb %0111111111111110
 fdb %1111111111111111

HollowPawn
 fdb %0000000000000000
 fdb %0000000110000000
 fdb %0000011001100000
 fdb %0000001111000000
 fdb %0011110000111100
 fdb %0111111111111110
 fdb %0000001001000000
 fdb %0000010000100000
 fdb %0000010000100000
 fdb %0000100000010000
 fdb %0000100000010000
 fdb %0000010000100000
 fdb %0000100000010000
 fdb %0001111111111000
 fdb %0110000000000110
 fdb %1111111111111111
         list 1
         page
        *       CONTROL FUNCTION ENTRY POINTS

CONTROLCHARBRANCH
        FDB     RETURN          $00 NULL (ILLEGAL)
        FDB     SETCHCURSOR     $01 CONTROL A; (A) = ROW, (B)= COL
        FDB     RETURN          $02 CONTROL B
        FDB     RETURN          $03 CONTROL C
        FDB     RETURN          $04 CONTROL D
        FDB     ERASETOEOL      $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     RETURN          $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
CHARACTERSET    EQU     *       ASCII TO BIT PATTERN CONVERSION TABLE
         list  0                       just uses up paper
*       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
         list 1
         page
putprint ; send (A) to Radio Shack printer (task level entry point!)
rs232in equ $ff22                      lsb
rs232out equ $ff20                     bit 1
bittime fdb   25
; assert: we can't get here unless stop bit from previous printer char ...
; has been completely sent!
         ldx   #0                      set timeout
putprintwaitready
         dex
         beq   putprinttimedout
         ldb    rs232in                is printer ready ?
         bitb  #%00000001              (CTS high ?)
         bne   putprintwaitready       b/ no, wait for printer ready
         sec                           create single stop bit
         rola                          now (A) contains 7 data bits, 1 stop bit
*        clc                           manufacture start bit
         sei                           CHEAT! shut off ints to get fixed times
         bsr   putprintsendbit         go send start bit
         clc                           1st data bit
         bsr   putprintsendbit         go send next bit
putprintbits ; loop to send bits
         asla                          shift next bit into carry
         beq   putprintstopbit         b/ time to send stop bit
         bsr   putprintsendbit
         bra   putprintbits

putprintstopbit ; carry=1, send stop bit
         ldb   rs232out                send stop bit
         orb   #%00000010              force RS232 line high
         stb   rs232out
         cli                           allow interrupts during stop bit
         bsr   putprintwaitbittime
         okrts

putprintsendbit ; send bit in carry, preserves (A)
         ldab  #%00111111              move carry to bit 1
         rolb
         rolb
         andb  rs232out                send bit, preserve D/A value
         orb   rs232out                combine bits
         stb   rs232out
putprintwaitbittime
         ldx   bittime                 pick up bit time delay
putprintwaitbittimeloop
         dex
         bne   putprintwaitbittimeloop
         rts

putprinttimedout ; printer timed out
         ldx   #err:timedout
         jmp   errored
         org   (*//$100)*$100          org to next convenient page (debug only)

        PAGE    DRAW ASSOCIATED, DRAW PICTURE

DRAWPICTURE ; (X) points to picture block, put picture on screen
        LDD     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
DrawPictureSizeXDatU ; draw picture whose bits are at (U), size is in (X,D)
        stu     picture         save pointer to picture
        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+1        MORE PICTURE ROWS TO SHOW ?
        BEQ     PICTXIT         NO, I GIVE UP
        LDB     #NBROW-1        MOVE DOWN THE SCREEN ONE ROW (-1 for RESIDUE)
        SUBB    PWIDTH          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

        PAGE    DISPLAY PRINTING CHARACTER
         org   (*//$100)*$100          org to next convenient page (debug only)
        PAGE    GRAPHICS TERMINAL EMULATION

PUTCHAR ; (A) contains 7 bit ASCII code
        CMPA    #$1F            A CONTROL CHARACTER ?
        BHI     DISPLAYCHAR     B/ PRINTING CHARACTER, GO PRINT
        ASLA                    IT'S A CONTROL CHARACTER !
        ldx     #ControlCharBranch
        jmp     [a,x]           call processing subroutine

DING ; output <BEL> sound
        LDAA    #DINGTIME       GET LENGTH OF DING TIME
        STAA    DURATION        SET SPEAKER TONE DURATION
RETURN  RTS                     YOU GUESS...

DISPLAYCHAR ; DISPLAY PRINTING CHARACTER (A)
        PSHA                    SAVE THE CHARACTER, WE NEED IT LATER
        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
        LDD     CURSORY         NOW MOVE DOWN THE SCREEN A ROW
        SUBD    #CHARHEIGHT     RUN OFF BOTTOM OF SCREEN ?
        BLO     CHAR2           YES, MUST ROLL SCREEN
        STD     CURSORY         (ADVANCE CURSORY DOWN A CHARACTER ROW)
CHAR1   EQU     *       CHECK FOR OVERRUN BOTTOM OF SCREEN
        LDD     CURSORY         GET VERTICAL CURSOR POSITION
        CMPD    #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
        SUBD    #CHARHEIGHT-1+(SCREENHEIGHT-(SCREENHEIGHT/CHARHEIGHT)*CHARHEIGHT)
*                               ADD ANOTHER LINE TO OVERRUN DISTANCE
CHARR   EQU     *               ROLL THE SCREEN; (D) = - # LINES
        JSR     ROLLUPCHARLINE  ROLL THE SCREEN UP ONE CHARACTER LINE
*       NEXT, WE OUTPUT THE CHARACTER TO THE SCREEN
CHARPUTC ; NOW PUT CHARACTER ON THE SCREEN
        PULA                    GIMME MY CHARACTER BACK !
        SUBA    #$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
        LDD     CURSORY         IF WE ARE DISPLAYING A LETTER WITH A TAIL,
        TST     0,X             THEN PLACE ON SCREEN 2 LINES BELOW NORMAL
        BPL     CPUT1           B/ NO TAIL (not small G,J,P,Q,Y)
        SUBD    #1              TAIL, SKIP DOWN SCREEN ONE LINE
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,U       ADVANCE POINTER TO NEXT ROW
        LDA     ,X+             FETCH NEXT ROW OF DOT MATRIX
*       CLRB                    IF WE GET HERE, WE'LL NEVER 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,U       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
         org   (*//$100)*$100          org to next convenient page (debug only)
         page
SETCURSORX      EQU     *       SETS X VALUE OF CURSOR TO (X)
        STX     CURSORX
        RTS

SETCURSORY      EQU     *       SETS Y VALUE OF CURSOR TO (D)
        STD     CURSORY         STORE AS CURSORY Y VALUE
        RTS                     AND EXIT

SETCURSORXY     EQU     *       SET CURSOR X TO (X), CURSORY TO (A)
        STX     CURSORX
        STD     CURSORY
        RTS
        PAGE
*
DRAWDOTATXY ; 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
         page
*      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
        JMP     ROLLSCREENDOWN
         org   (*//$100)*$100          org to next convenient page (debug only)
*
*       DECCURSORY -- DECREMENTS CURSORY OR ROLLS SCREEN UP
*
DECCURSORY      EQU     *
        LDD     CURSORY         ARE WE AT BOTTOM OF SCREEN ?
        BNE     DECCURSORY1     NO, WE CAN DO IT!
ROLLSCREENUP    EQU     *
        LDD     #1              DISTANCE TO ROLL SCREEN UP
        JMP     MODIFYSCREENSHIFT

DECCURSORY1     EQU     *
        SUBD    #1              DO WHAT WE PROMISED
        STAA    CURSORY
BUMPRTS RTS                     AND GET OUT...
         page
ROLLSCREENDOWN  EQU     *
         LDD   #-1              DISTANCE TO ROLL SCREEN UP, IN LINES
MODIFYSCREENSHIFT ; (D) contains # scan lines to roll screen up
;  shuffles from high part of display area to lower addresses
        if      0
        tsta
        bmi     modifyscreenshift1 b/ must roll screen down
        fin
        ldu     #ScreenBottom-NBRow+16 = shuffle to target
        lda     #nbrow          figure out distance to move screen lines
        mul
        leax    d,u             = shuffle from source
MODIFYSCREENSHIFTSHUFFLEUP
        ldd     -16,x
        std     -16,u
        ldd     -14,x
        std     -14,u
        ldd     -12,x
        std     -12,u
        ldd     -10,x
        std     -10,u
        ldd     -8,x
        std     -8,u
        ldd     -6,x
        std     -6,u
        ldd     -4,x
        std     -4,u
        ldd     -2,x
        std     -2,u
        ldd     ,x
        std     ,u
        ldd     2,x
        std     2,u
        ldd     4,x
        std     4,u
        ldd     6,x
        std     6,u
        ldd     8,x
        std     8,u
        ldd     10,x
        std     10,u
        ldd     12,x
        std     12,u
        ldd     14,x
        std     14,u
        leax    32,x
        leau    32,u
; assert: number of bytes per row is divisible by 8
        cmpx    #ScreenTop+16 shuffle complete ?
        bne     modifyscreenshiftshuffleup
        rts

        if      0
modifyscreenshift1
        ldu     #ScreenTop-NBRow+16 = shuffle to target
        lda     #nbrow          figure out distance to move screen lines
        mul
        negd
        leax    d,u             = shuffle from source
MODIFYSCREENSHIFTSHUFFLEDOWN
        ldd     -16,x
        std     -16,u
        ldd     -14,x
        std     -14,u
        ldd     -12,x
        std     -12,u
        ldd     -10,x
        std     -10,u
        ldd     -8,x
        std     -8,u
        ldd     -6,x
        std     -6,u
        ldd     -4,x
        std     -4,u
        ldd     -2,x
        std     -2,u
        ldd     ,x
        std     ,u
        ldd     2,x
        std     2,u
        ldd     4,x
        std     4,u
        ldd     6,x
        std     6,u
        ldd     8,x
        std     8,u
        ldd     10,x
        std     10,u
        ldd     12,x
        std     12,u
        ldd     14,x
        std     14,u
        leax    -32,x
        leau    -32,u
; assert: number of bytes per row is divisible by 8
        cmpx    #ScreenBottom-16 shuffle complete ?
        bne     modifyscreenshiftshuffledown
        rts
        fin
         page
*       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     *
        LDD     CURSORY         GET Y POSITION
GENCURSORCHAR ; ENTRY TO GENERATE CURSORBYTE FOR CHARACTER DISPLAY
        NEGD                    OFFSET INTO BUFFER
        ADDD    #SCREENHEIGHT-1 produces 0 for max Y position
        LDX     #SCREENBOTTOM   = (X,Y) = (0,255)
        LDA     #NBROW
        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+1       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     #NBROW
        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
        page
         org   (*//$100)*$100          org to next convenient page (debug only)
*       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     TEMPB
        LDA     CURRENTBACKGROUND GET BACKGROUND TO STORE
        TFR     A,B
CLEARLOOP       EQU     *
        RPT     16
        STD     *-CLEARLOOP-16,X clear 32 bytes (1 screen row)
        LEAX    32,X            advance (X) to "start" of next row
        DEC     TEMPB           ALL ROWS ZEROED ?
        BNE     CLEARLOOP       B/ no, go clear another!
CLEARRTS
        RTS

NEWPAGE EQU     *
        LDX     #SCREENBOTTOM   ZERO THE ENTIRE SCREEN
        LDD     #SCREENHEIGHT
        JSR     CLEARLINES
        LDX     #CHARLEFTSIDE   POSITION CURSOR...
        STX     CURSORX         AT TOP LEFT CORNER OF SCREEN
        LDX     #CHARTOPSIDE
        STX     CURSORY
        RTS                     ALL DONE !

SETCHCURSOR ; (A)= ROW, (B)= COLUMN; (0,0) is upper left corner
        PSHB                    save column number
        LDAB    #CHARHEIGHT     Scan lines/character row
        MUL                     = Scan lines to skip (assert: < 256!)
        NEGD                    ROW #0 = MAX Y POSITION
        ADDD    #CHARTOPSIDE
        STD     CURSORY
        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-1
        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 -(D) SCAN LINES AND CLEAR
*       SETS CURSORY TO CHARHEIGHT-1
*       (= LOWEST ROW ON SCREEN WHICH DOESN'T CHOP OFF PART OF A ROW AT THE TOP)
*
ROLLUPCHARLINE  EQU     *
        NEGD
        PSHD                    SAVE # SCAN LINES TO CLEAR
        JSR     MODIFYSCREENSHIFT GO SHUFFLE THE DISPLAY BUFFER
        LDD     ,S              RESTORE # LINES TO CLEAR
        LDA     #NBROW
        MUL
        NEGD
        LDX     #SCREENTOP
        LEAX    D,X             = address of 1st screen line to clear
        PULD                    = # lines to clear
        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
         org   (*//$100)*$100          org to next convenient page (debug only)
*       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
        JSR     MODIFYSCREENSHIFT OBJECT WILL GO OFF 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
        if      0
        CMPD    #SCREENWIDTH-1  ENOUGH SPACE TO RIGHT ?
        BLS     MAKESPACE2      YES, STORE NEW VALUE FOR X AND QUIT
        JMP     ERROR           WELL, YOU FIGURE THIS OUT
        fin
MAKESPACE2      EQU     *
        STD     NEWX            STORE NEW VALUE FOR CURSORX
        RTS
         page
         org   (*//$100)*$100          org to next convenient page (debug only)
*       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     *
        LDA     CURRENTBACKGROUND IS BACKGROUND 1's or 0's?
        BNE     DRAWSOLIDLINE   B/ BACKGROUND is 1's
        LDU     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,U             COMBINE (A) WITH SCREEN BYTE
        STAA    ,U+
        DECB                    ALL BYTES IN ROW HIT YET ?
        BEQ     DRAWBLANKRTS    B/ SPECIAL ONE BYTE CASE
        DECB                    TWO BYTE WIDE BLANK REGION ?
        BEQ     DRAWBLANKLAST   B/ yes, go handle last byte
        CLRA                    GET ALL 0'S PATTERN
DRAWBLANKLOOP   EQU     *
        STA     ,U+             COMBINE (A) WITH SCREEN BYTE
        DECB                    ALL BYTES IN ROW HIT YET ?
        BNE     DRAWBLANKLOOP   NO
DRAWBLANKLAST ; re-enter here to handle two byte wide blank region
        LDAA    RIGHTEND        GET LAST BYTE BIT PATTERN
        COMA                    MAKE MASK OFEBITS TO RETAIN
        ANDA    0,U             AND DUMP INTO SCREEN MEMORY
        STAA    0,U
DRAWBLANKRTS
        RTS

DRAWSOLIDLINE   EQU     *
        LDU     TARGETLEFT      GET POINTER TO LEFTMOST BYTE OF LINE
        LDB     PWIDTH          GET WIDTH OF HORIZONTAL LINE
        LDAA    LEFTEND         GET LEFTMOST BYTE OF LINE
        ORAA    0,U             COMBINE (A) WITH SCREEN BYTE
        STAA    ,U+
        DECB                    ALL BYTES IN ROW HIT YET ?
        BEQ     DRAWSOLIDRTS    B/ SPECIAL ONE BYTE CASE
        DECB                    TWO BYTE WIDE BLANK REGION ?
        BEQ     DRAWSOLIDLAST   B/ yes, go handle last byte
        LDAA    #%11111111      GET ALL 1'S PATTERN
DRAWSOLIDLOOP   EQU     *
        STAA    ,U+             COMBINE (A) WITH SCREEN BYTE
        DECB                    ALL BYTES IN ROW HIT YET ?
        BNE     DRAWSOLIDLOOP   NO
DRAWSOLIDLAST ; re-enter here to handle two byte wide blank region
        LDAA    RIGHTEND        GET LAST BYTE BIT PATTERN
        ORAA    0,U             AND DUMP INTO SCREEN MEMORY
        STAA    0,U
DRAWSOLIDRTS
        RTS
        PAGE    BLANK REGION
BLANKREGION ; (X) CONTAINS BOX X SIZE, (D) 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
        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 ; (X) = SIZE IN X, (D) = SIZE IN Y
        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
        ANDB    #$7             (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 ?
        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
         org   (*//$100)*$100          org to next convenient page (debug only)
         rmb   1                       skip over $3000 to leave loader alone
        PAGE    DRAW SOLID BOX
         org   (*//$100)*$100          org to next convenient page (debug only)
SOLIDBOX ; (X) CONTAINS BOX X SIZE, (D) 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
        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
         org   (*//$100)*$100          org to next convenient page (debug only)
EMPTYBOX ; (X) CONTAINS BOX X SIZE, (D) 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     *
        LDU     TARGETLEFT      ADVANCE POINTER...
        LEAU    NBROW,U          DOWN SCREEN...
        STU     TARGETLEFT        ONE LINE
        DEC     DELTAY+1        ON LAST LINE OF BOX ?
        BEQ     EMPTYLAST       YES, GO DRAW A SOLID LINE
        LDAA    LEFTCOLUMN      INSERT LEFT SIDE OF BOX
        JSR     [WRITEATOSCREEN]
        LDB     PWIDTH          COMPUTE RIGHT END POINTER
        LEAU    B,U             = LEFT END + PICTUREWIDTH - 1
        LEAU    -1-1,U          IN SAME ROW (EXTRA -1 OFFSETS AUTOINC...
        LDAA    RIGHTCOLUMN         IN WRITEATOSCREEN)
        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
        page
*       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     *
        LDU     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!
        DECB                    2 BYTE WIDE PATTERN ?
        BEQ     DRAWHORZLINERIGHTMOST B/ YES, GO HANDLE
DRAWHORZLOOP    EQU     *
        LDAA    #%11111111      GET ALL 1'S PATTERN
        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    CURSOR HANDLING
         org   (*//$100)*$100          org to next convenient page (debug only)
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

ERASECURSOR ; make cursor go away if displayed
        LDAA    CURSORON        IS CURSOR DISPLAYED ?
        BEQ     ERASERTS        NO, SO EXIT
        CLR     CURSORON        YES, MARK AS UNDISPLAYED
        LDAB    #CURSORBLINK    KEEP CURSOR OFF AWHILE
        STAA    BLINKFUSE
        LDD     #CURSORX        GET POINTER TO CURSORX AND Y...
        LDX     #CURSOR         AND GO DRAW IT ON TOP OF ITSELF
        BRA     SPLAT           WHICH ERASES IT

ERASERTS        EQU     *
        RTS

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
SELECTEORMODE EQU *
        BSR     SETUPWRITE
        EORA    ,U
        STAA    ,U+
        RTS

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

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

SETUPWRITE      EQU     *
        PULX                    POINTER TO SUBROUTINE TO COPY
        LDD     WRITEATOSCREEN GET OLD DISPLAY MODE
        STX     WRITEATOSCREEN REMEMBER NEW DISPLAY MODE
        RTS                     ALL DONE, GET OUT!

; Logically, this is what WRITEATOSCREEN is:
; 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
*
*       HOMEUP -- SET CURSOR TO TOP LEFT CORNER OF SCREEN [(0,0) Char cursor]
*
HOMEUP  EQU     *
        LDX     #CHARLEFTSIDE   = X POSITION OF HOME
        LDD     #CHARTOPSIDE    = Y POSITION OF HOME
        JMP     SETCURSORXY
*

ERASETOEOL ; erase to end of line
        LDD     CURSORX         save current cursor position
        PSHD
        NEGD                    compute distance from cursor to side of screen
        ADDD    #SCREENWIDTH
        TFR     D,X             = width of box to blank
        LDD     #CHARHEIGHT     = height of box to blank
        JSR     BLANKREGION     make region empty
        PULD                    set cursorx back to original value
        STD     CURSORX
        RTS                     all done!

CURSORTOGGLE ; EOR CURSOR DISPLAY INTO SCREEN AT CURSOR LOCATION
        COM     CURSORON        remember whether cursor present on screen
        JSR     SelectEORMode   so successive passes install/erase cursor
        ; also, we want EOR mode in case Cursor sits on top of some char
        PSHD                    remember old display mode
        LDA     #$7F            rubout is cursor blotch
        JSR     DISPLAYCHAR
        LDD     CURSORX         backup cursor to point before display blotch
        SUBD    #CHARWIDTH
        STD     CURSORX
        PULX                    restore current display mode
        STX     WRITEATOSCREEN
        RTS

        END     SETUPCOLORCOMPUTER
