Chapter 3
SpeedScript Source Code
Atari Source Code
The source code for SpeedScript was originally developed using the MAC/65 assembler (from Optimized Systems Software, Inc.). The MAC/65 assembler uses the standard MOS source code format, so this source code can be assembled on a variety of Atari assemblers, including EASMD from OSS and the Atari Assembler/Editor cartridge. The source code was originally broken up into a number of modules, each SAVE#'d to disk. The .INCLUDE pseudo-op was used to link all the modules together. All files must be merged together to be assembled with the Atari Assembler/Editor cartridge. Line numbers are omitted.
Most pseudo-ops are in standard MOS 6502 notation: *= updates the program counter (some assemblers use .ORG instead); .BYTE assembles a list of numbers or an ATASCII character string; .WOR, or .WORD, assembles a list of addresses into low byte/high byte format; < extracts the low byte of a 16-bit expression; > extracts the high byte of a 16-bit expression (some assemblers reverse the use of < and > others, such as EASMD and the Assembler/Editor cartridge, use a suffix of &255 and /256 to achieve the same effect); and = is used to assign an expression to a label (some assemblers use .EQU).
Beginners should make sure they understand Indirect-Y addressing, as in LDA ($FB),Y or LDA (CURR),Y. This mode is used extensively in SpeedScript.
The Atari version of SpeedScript was developed by sending the Commodore 64 source code to the Atari via modem. References to Commodore 64 Kernal ROM routines were replaced with Atari CIO routines. Some routines built into the Commodore 64's ROM had to be programmed into Atari SpeedScript, with resulting code expansion. References to location 1 (which maps banks of ROM in and out in the 64) were omitted. The REFRESH routine, TOPCLR, and a few other routines were changed to compensate for Atari's floating screen memory. The raster interrupt used to highlight the command line in the 64 version became a display-list interrupt. A custom character set was added to take advantage of the Atari's special nine-line character mode. The DOS package was written to support disk functions. But much of the source code did not need to be changed at all, since SpeedScript's machine-specific code is segregated into distinct modules. These modules were rewritten. Approximately one week was required to get a primitive version running, followed by two months of testing, debugging, and refining to complete Atari SpeedScript. Because of the new character set, the DOS package, smoother input/output programming (such as Atari's device-independent I/O), and more logical keyboard layout, the Atari version may be the best version of SpeedScript yet.
SpeedScript is written in small modules. Some people think that subroutines are useful only when a routine is called more than once. I strongly believe in breaking up a problem into a number of discrete tasks. These tasks can be written as subroutines, then tested individually. Once all the modules are working, just link them together with JSRs and you have a working program.
I've also tried to use meaningful labels, but sometimes one just runs out of imagination. Comments are added below as signposts to guide you through the source code (you needn't type them in--if you do, precede each comment with a semicolon for the sake of your assembler). Modules are also set apart with blank lines. Notice that some modules are used in rather creative ways. For example, word left/word right is used both for moving the cursor and in delimiting a word to be erased in the erase mode. Also, note that memory locations are sometimes used instead of meaningful labels. In order to fit the complete source code into memory at once, I sometimes had to compromise readability for the sake of brevity.
Crucial to the understanding of SpeedScript is the REFRESH routine. Study it carefully. REFRESH is the only routine in SpeedScript that writes directly to the screen (CIO is used to print on the command line). It automatically takes care of word-wrap and carriage returns, and provides useful pointers so that the CHECK routine can easily scroll the screen. This frees the rest of SpeedScript to just move and modify contiguous memory. Carriage returns are not padded out in memory with spaces to fill the rest of a line; the REFRESH routine takes care of this transparently.
Speedscript 3.0 Source Code for Atari
Filename: SPEED.0Location $1F00 is safely above DOS 2.0S, DOS 3, and OS/A+ DOS. Some DOS's may use more memory, so you may need to reassemble SpeedScript at a higher address, usually the address of LOMEM plus 256 bytes to be safe. *= $1F00 Locations used by high-speed memory move routines. FROML = $80 FROMH = $81 DESTL = $82 DESTH = $83 LLEN = $84 HLEN = $85 CURR: Position of cursor within text memory. SCR: used by the REFRESH routine. CURR = $86 SCR = $88 TEX: An alternate location used in tandem with CURR. COLR is used by REFRESH. TEMP is used throughout as a scratehpad pointer. INDIR is also a reusable indirect pointer. UNDERCURS stores the value of the character highlighted by the cursor. TEX = $8A TEMP = $8C INDIR = $8E UNDERCURS = $90 WTNDCOLOR: Color of command line window supported by HIGHLIGHT. RETCHAR is the screen-code value of the return-mark (a left-pointing arrow). SPACE is the screen-code value of the space character, RED and BLUE are used as command-line colors WINDCOLR = $91 RETCHAR = 94 SPACE = 0 RED = $32 BLUE = $74 Input/Output Control System definitions for input/output control blocks (IOCBs). CIO is the entry point for all file-oriented input/output. SHFLOK is the SHiFtLOcK flag. ICCOM = $0342 ICBADR = $0344 ICBLEN = $0348 ICAUX1 = $034A ICAUX2 = $034B ICSTAT = $0343 SHFLOK = $02BE CIO = $E456 Called only when run from DOS. It is assumed that the author's initials (that conveniently work out in hex) are not normally present in memory. If they are, we know that SpeedScript has been run before, so we avoid the ERASE routine to preserve the text in memory. BEGIN LDA 710 STA 709 JSR INIT LDA #$CB CMP FIRSTRUN STA FIRSTRUN BEQ SKIPERAS JSR ERASE JSR KILLBUFF We save the DOS reset vector and change this vector to point to SpeedScript's SYSTEM RESET routine. Since this routine is called at power-up, right after DOS.SYS runs, we need to disable the cold-start flag (location 580) and set location $09 to signify a successful disk boot. LDA $0C STA JDOS+1 LDA $0D STA JDOS+2 LDA # <JDOS STA $0C LDA # >JDOS STA $0D LDA #0 STA 580 LDA #1 STA $09 SKIPERAS JSR INIT2 JMP MAIN The character set for the ANTIC 3 nine-line character mode must be on an even 512-Syte boundary, so we force the assembler's program counter to address $2000 and merge in the character set. We then link in each successive module of SpeedScript. Again, if your assembler cannot handle .INCLUDE, you'll have to merge all these files together in the order indicated. *= $2000 .INCLUDE #D:CHSET.SRC .INCLUDE #D:SPEED.1 .INCLUDE #D:SUPPORT .INCLUDE #D:DOSPAK .INCLUDE #D:SPEED.2 .INCLUDE #D:DATA .ENDFilename: CHSET.SRC
The character set here is stored as eight bytes per line, so each line defines one character. Sheldon Leemon's INSTEDIT character editor was used to create the character set, and I wrote a special program to convert the character set into .BYTE statements. In ANTIC mode 3, each character takes up ten scan lines of vertical screen space. The characters in the lowercase portion of the character set are displayed with a blank line at the top line, then the character data from bytes 1-7 of the character set. Byte 0 of the character's definition is displayed at the ninth line of the character. The tenth line is always blank. This lets you define characters with true descenders. The forced blank line lets you use more of the character matrix for defining a character, so these characters are larger than normal Atari characters. .BYTE 0,0,0,0,0,0,0,0 .BYTE 0,24,24,24,24,24,0,24 .BYTE 0,102,102,102,0,0,0,0 .BYTE 0,102,255,102,102,255,102,0 .BYTE 24,62,96,60,6,124,24,0 .BYTE 0,204,216,48,96,204,140,0 .BYTE 0,56,108,56,112,222,204,118 .BYTE 0,24,24,48,0,0,0,0 .BYTE 0,24,48,96,96,96,48,24 .BYTE 0,48,24,12,12,12,24,48 .BYTE 0,0,102,60,255,60,102,0 .BYTE 0,0,24,24,126,24,24,0 .BYTE 0,0,0,0,0,48,48,96 .BYTE 0,0,0,0,126,0,0,0 .BYTE 0,0,0,0,0,0,48,48 .BYTE 0,0,6,12,24,48,96,192 .BYTE 0,124,206,222,246,230,198,124 .BYTE 0,24,56,24,24,24,24,126 .BYTE 0,124,198,12,24,48,96,254 .BYTE 0,254,12,24,56,12,198,124 .BYTE 0,28,60,108,204,254,12,12 .BYTE 0,254,192,252,6,6,198,124 .BYTE 0,124,192,252,198,198,198,124 .BYTE 0,126,6,12,24,48,96,96 .BYTE 0,124,198,198,124,198,198,124 .BYTE 0,124,198,198,126,12,24,48 .BYTE 0,0,48,48,0,48,48,0 .BYTE 0,0,48,48,0,48,48,96 .BYTE 0,12,24,48,96,48,24,12 .BYTE 0,0,0,126,0,0,126,0 .BYTE 0,48,24,12,6,12,24,48 .BYTE 0,60,102,6,12,24,0,24 .BYTE 0,124,198,222,214,220,224,60 .BYTE 0,124,198,198,198,254,198,198 .BYTE 0,252,198,198,252,198,198,252 .BYTE 0,124,198,192,192,192,198,124 .BYTE 0,248,204,198,198,198,204,248 .BYTE 0,254,192,192,252,192,192,254 .BYTE 0,254,192,192,252,192,192,192 .BYTE 0,124,198,192,222,198,198,124 .BYTE 0,198,198,198,254,198,198,198 .BYTE 0,126,24,24,24,24,24,126 .BYTE 0,62,12,12,12,12,204,120 .BYTE 0,198,204,216,240,216,204,198 .BYTE 0,192,192,192,192,192,192,254 .BYTE 0,198,238,254,214,198,198,198 .BYTE 0,198,230,246,254,222,206,198 .BYTE 0,124,198,198,198,198,198,124 .BYTE 0,252,198,198,198,252,192,192 .BYTE 0,124,198,198,198,222,124,14 .BYTE 0,252,198,198,252,216,204,198 .BYTE 0,124,198,192,124,6,198,124 .BYTE 0,126,24,24,24,24,24,24 .BYTE 0,198,198,198,198,198,198,124 .BYTE 0,198,198,198,198,198,108,56 .BYTE 0,198,198,198,214,254,238,198 .BYTE 0,198,198,108,56,108,198,198 .BYTE 0,102,102,102,60,24,24,24 .BYTE 0,254,12,24,48,96,192,254 .BYTE 0,30,24,24,24,24,24,30 .BYTE 0,64,96,48,24,12,6,0 .BYTE 0,240,48,48,48,48,48,240 .BYTE 0,8,28,54,99,0,0,0 .BYTE 0,0,0,0,0,0,0,255 .BYTE 0,0,0,0,0,0,0,0 .BYTE 124,194,153,153,129,153,153,230 .BYTE 252,130,153,130,153,153,131,252 .BYTE 124,194,153,158,158,153,194,124 .BYTE 252,130,153,153,153,153,130,252 .BYTE 254,130,158,132,156,158,130,254 .BYTE 126,193,206,194,206,204,204,120 .BYTE 124,194,153,158,145,153,194,124 .BYTE 246,153,153,129,153,153,153,246 .BYTE 127,97,115,50,50,115,97,127 .BYTE 62,50,50,50,50,114,198,124 .BYTE 230,153,146,132,146,153,153,230 .BYTE 120,76,76,76,76,78,66,124 .BYTE 230,153,129,129,137,153,153,230 .BYTE 230,153,137,129,145,153,153,230 .BYTE 124,194,153,153,153,153,194,124 .BYTE 254,195,201,201,195,206,200,240 .BYTE 124,194,153,153,153,146,201,118 .BYTE 124,194,201,201,194,201,201,247 .BYTE 126,195,158,194,249,153,195,126 .BYTE 254,194,102,100,100,100,100,124 .BYTE 246,153,153,153,153,153,194,124 .BYTE 230,153,153,153,153,194,100,56 .BYTE 246,153,153,153,137,129,153,246 .BYTE 230,153,153,194,153,153,153,230 .BYTE 230,153,153,195,230,100,100,124 .BYTE 254,193,249,50,228,206,193,254 .BYTE 120,96,120,96,126,24,30,0 .BYTE 0,24,60,126,24,24,24,0 .BYTE 0,24,24,24,126,60,24,0 .BYTE 0,0,0,12,12,88,112,120 .BYTE 0,24,12,126,12,24,0,0 .BYTE 0,0,24,60,126,126,60,24 .BYTE 0,0,0,124,6,126,198,126 .BYTE 0,0,192,252,198,198,198,252 .BYTE 0,0,0,124,198,192,198,124 .BYTE 0,0,6,126,198,198,198,126 .BYTE 0,0,0,124,198,254,192,124 .BYTE 0,0,62,96,252,96,96,96 .BYTE 6,252,0,126,198,198,198,126 .BYTE 0,0,192,192,252,198,198,198 .BYTE 0,0,24,0,56,24,24,60 .BYTE 24,240,24,0,24,24,24,24 .BYTE 0,0,192,204,216,248,204,198 .BYTE 0,0,56,24,24,24,24,60 .BYTE 0,0,0,204,254,254,214,198 .BYTE 0,0,0,252,198,198,198,198 .BYTE 0,0,0,124,198,198,198,124 .BYTE 192,192,0,252,198,198,198,252 .BYTE 6,6,0,126,198,198,198,126 .BYTE 0,0,0,252,198,192,192,192 .BYTE 0,0,0,126,192,124,6,252 .BYTE 0,0,48,254,48,48,48,30 .BYTE 0,0,0,198,198,198,198,126 .BYTE 0,0,0,198,198,198,108,56 .BYTE 0,0,0,198,214,254,124,108 .BYTE 0,0,0,198,108,56,108,198 .BYTE 6,252,0,198,198,198,198,126 .BYTE 0,0,0,254,12,56,96,254 .BYTE 14,0,14,24,24,56,24,24 .BYTE 24,24,24,24,24,24,24,24 .BYTE 112,0,112,24,24,28,24,24 .BYTE 0,0,0,8,24,56,24,8 .BYTE 0,0,0,16,16,24,28,24 *= *+16 .ENDFilename: SPEED.1
This module is chiefly concerned with the word processor editing functions. It contains many common subroutines, such as TOPCLR and PRMSG to clear the command line and print messages. It contains the initialization routines and takes care of memory moves (inserts and deletes). A second module, SPEED.2, is responsible for most input/output, including the printer routines. SPEED.1 is the largest file in the linked chain. UMOVE is a high-speed memory move routine. It gets its speed from selfmodifying code (the $FFFFs at MOVLOOP are replaced by actual addresses when UMOVE is called). UMOVE is used to move an overlapping range of memory upward (toward location 0), so it is used to delete. Set FROML/FROMH to point to the source area of memory, DESTL/DESTH to point to the destination, and LLEN/HLEN to hold the length of the area being moved. UMOVE LDA FROML STA MOVLOOP+1 LDA FROMH STA MOVLOOP+2 LDA DESTL STA MOVLOOP+4 LDA DESTH STA MOVLOOP+5 LDX HLEN BEQ SKIPMOV MOV1 LDA #0 MOV2 STA ENDPOS LDY #0 MOVLOOP LDA $FFFF,Y STA $FFFF,Y INY CPY ENDPOS BNE MOVLOOP INC MOVLOOP+2 INC MOVLOOP+5 CPX #0 BEQ OUT DEX BNE MOV1 SKIPMOV LDA LLEN BNE MOV2 OUT RTS DMOVE uses the same variables as UMOVE, but it is used to move an overlapping block of memory downward (toward location $FFFF), so it is used to insert. If the block of memory to be moved does not overlap the destination area, then either routine can be used. DMOVE LDA HLEN TAX ORA LLEN BNE NOTNULL RTS NOTNULL CLC TXA ADC FROMH STA DMOVLOOP+2 LDA FROML STA DMOVLOOP+1 CLC TXA ADC DESTH STA DMOVLOOP+5 LDA DESTL STA DMOVLOOP+4 INX LDY LLEN BNE DMOVLOOP BEQ SKIPDMOV DMOV1 LDY #255 DMOVLOOP LDA $FFFF,Y STA $FFFF,Y DEY CPY #255 BNE DMOVLOOP SKIPDMOV DEC DMOVLOOP+2 DEC DMOVLOOP+5 DEX BNE DMOV1 RTS REFRESH copies a screenful of text from the area of memory pointed to by TOPLIN. It works like a printer routine, fitting a line of text between the screen margins, wrapping words, and restarts at the left margin after printing a carriage return. SpeedScript constantly calls this routine while the cursor is blinking, so it has to be very fast. To eliminate flicker, it clears out the end of each line instead of first clearing the screen. It stores the length of the first screen line for the sake of the CHECK routine (which scrolls up by adding that length to TOPLIN) and the last text location referenced (so CHECK can see if the cursor has moved off the visible screen). REFRESH can automatically handle different screen widths. REFRESH LDA #40 INY CLC RLM: Left margin. Location $58/$59 points to the address of screen memory. ADC RLM CLC ADC $58 STA SCR LDA $59 ADC #0 STA SCR+1 TOPLIN points to the first character within text to be printed at the top-left comer of the screen. CLC LDA TOPLIN STA TEX LDA TOPLIN+1 STA TEX+1 LDX #1 LDA INSMODE STA WINDCOLR PPAGE LDY #0 PLINE LDA (TEX),Y STA LBUFF,Y INY AND #127 CMP #RETCHAR BEQ BREAK CPY LINELEN BNE PLINE DEY SLOOP LDA (TEX),Y AND #127 NXCUR CMP #SPACE BEQ SBRK DEY BNE SLOOP LDY LINELEN DEY SBRK INY BREAK STY TEMP LDY #0 COPY LDA LBUFF,Y STA (SCR),Y INY CPY TEMP BNE COPY CLC TYA ADC TEX STA TEX LDA TEX+1 ADC #0 STA TEX+1 CPX #1 BNE CLRLN STY LENTABLE CLRLN CPY LINELEN BEQ CLEARED Character #64 (ATASCII value of O) fills the gap when a line is broken. It can be redefined to show or not show these false spaces. LDA #64 STA (SCR),Y INY JMP CLRLN CLEARED CLC LDA SCR ADC #40 STA SCR BCC INCNOT INC SCR+1 INCNOT INX CPX #19 BEQ PDONE JMP PPAGE PDONE LDA TEX STA BOTSCR LDA TEX+1 STA BOTSCR+1 RTS The following routine fills the entire text area with space characters (screen code 0), effectively erasing all text. It is called when the program is first run and when an Erase All is performed. It also initializes the cursor position (CURR) and the end-of-text pointer (LASTLINE). ERASE LDA TEXSTART STA TEX STA TOPLIN STA LASTLINE STA CURR LDA TEXSTART+1 STA TEX+1 STA TOPLIN+1 STA LASTLINE+1 STA CURR+1 SEC LDA TEXEND+1 SBC TEXSTART+1 TAX LDA #SPACE CLRLOOP LDY #255 DEC TEX+1 STA (TEX),Y INY INC TEX+1 CLR2 STA (TEX),Y INY BNE CLR2 INC TEX+1 DEX BNE CLR2 STA (TEX),Y RTS PRMSG is used anytime we need to print something at the top of the screen (the command line). Pass it the address of the message to be printed by storing the low byte of the address in the accumulator and the high byte in the Y register. The message in memory must end with a zero byte. The routine does not add a carriage return. CHROUT (character out) prints the character in the accumulator to the screen. CHROUT is a subroutine in the SUPPORT package. PRMSG STA TEMP STY TEMP+1 LDA #1 STA 752 LDY #0 PRLOOP LDA (TEMP),Y BEQ PREXIT JSR CHROUT INY BNE PRLOOP PREXIT RTS GETAKEY JSR GETIN BEQ GETAKEY RTS JDOS JSR PREXIT LDA BLINK BEQ NOBLINK LDY #0 LDA UNDERCURS STA (CURR),Y NOBLINK JSR INIT2 JMP MAIN The initialization routine sets up the memory map, clears out certain flags, and enables the display-list interrupt. INIT LDA #125 JSR CHROUT LDA #0 STA INSMODE STA TEXSTART STA TEXEND STA TEXBUF STA BUFEND STA HUNTLEN STA REPLEN STA ESCFLAG STA SHFLOK STA RLM LDA #40 STA LINELEN Label END is at the end of the source code, so it points to the last address used by the object code. We use it to calculate the start-of-text memory. LDA # >END CLC ADC #1 STA TEXSTART+1 Location 561 points to the display list, which holds screen information at the top of memory. We use it as the last address available for storing text or buffer text. LDA 561 SEC SBC #1 STA BUFEND+1 SEC SBC #8 STA TEXBUF+1 SEC SBC #1 STA TEXEND+1 LDA #$FF STA FPOS+1 If location $4B is 0, then SpeedScript is booted from disk. if we booted from cassette, we free up the DOS area ($0700-$1E00) for use as the text buffer, and free up the text memory used by disk-based SpeedScript as the text buffer. LDA $4B BEQ DISKBOOT LDA BUFEND+1 STA TEXEND+1 LDA #$07 STA TEXBUF+1 LDA #$1E STA BUFEND+1 DISKBOOT RTS The second initialization routine turns on the display-list interrupt (HIGH- LIGHT), homes the cursor, and prints the credit line. INIT2 JSR HIGHLIGHT LDA TEXSTART STA CURR LDA TEXSTART+1 STA CURR+1 JSR REFRESH JSR SYSMSG LDA # <MSG2 LDY # >MSG2 JSR PRMSG INC MSGFLG JMP CHECK SYSMSG displays "SpeedScript 3.0." The message flag (MSGFLG) is set when a message is to be left on the screen only until the next keystroke. After that keystroke, SYSMSG is called. The INIT2 routine prints the credit line with the MSGFLG set so that you won't have to stare at the author's name while you're writing--a modesty feature. SYSMSG JSR TOPCLR LDA # <MSG1 LDY # >MSG1 JSR PRMSG LDA #0 STA MSGFLG RTS TOPCLR keeps the command line clean. It is called before most messages. It's like a one-line clear-screen. It also forces the left margin (82) to 0, and homes the cursor to the beginning of the command line by zeroing out the X and Y cursor positions (84 and 85). TOPCLR LDY #39 LDA #SPACE TOPLOOP STA ($58),Y DEY BPL TOPLOOP LDA #0 STA 82 STA 85 STA 84 RTS Convert ATASCII to screen codes ASTOIN PHA AND #128 STA TEMP PLA AND #127 CMP #96 BCS LOWR CMP #32 BCS NOTCTRL CLC ADC #64 JMP LOWR NOTCTRL SEC SBC #32 LOWR ORA TEMP RTS The MAIN loop blinks the cursor, checks for keystrokes, converts them from ATASCII to screen codes, puts them in text at the CURRent position, and increments the CURRent position and LASTLINE. It also checks for special cases like the RETURN key and passes control characters to the CONTROL routine. The INSMODE flag is checked to see if we should insert a space before a character. MAIN LDY #0 STY BLINK LDA (CURR),Y STA UNDERCURS MAIN2 LDY #0 STY SELFLAG LDA (CURR),Y EOR #$80 STA (CURR),Y LDA BLINK EOR #1 STA BLINK JSR REFRESH WAIT JSR GETIN BNE KEYPRESS We check for the START key, and if pressed, go to the HOME cursor routine. LDA #8 STA 53279 LDA 53279 CMP #6 BNE FLIPIT LDY #0 STY BLINK LDA UNDERCURS STA (CURR),Y JSR HOME JMP MAIN The realtime clock (location 20), which counts in 1/60 seconds, is checked for 16/60 seconds (about 1/5 second) to see if it's time to blink the cursor. FLIPIT LDA 20 AND #16 BEQ WAIT LDA #0 STA 20 JMP MAIN2 A key has been pressed. We check the SELECT key to see if the keystroke should be inverted. KEYPRESS TAX LDA #8 STA 53279 LDA 53279 CMP #5 BNE NOTSEL LDA #128 STA SELFLAG NOTSEL LDY #0 LDA UNDERCURS STA (CURR),Y NOTBKS LDA MSGFLG BEQ NOMSG TXA PHA JSR SYSMSG PLA TAX NOMSG TXA CMP #155 BNE NOTCR Change a carriage return into a back arrow. LDX #30 JMP OVERCTRL NOTCR TXA BIT ESCFLAG BMI OVERCTRL CMP #156 BCS CONTROL AND #127 CMP #32 BCC CONTROL CMP #123 BCS CONTROL CMP #92 BEQ CONTROL CMP #94 BEQ CONTROL CMP #95 BEQ CONTROL OVERCTRL TXA PHA LDY #0 STY ESCFLAG LDA (CURR),Y CMP #RETCHAR BEQ DOINS LDA INSMODE BEQ NOINST DOINS JSR INSCHAR NOINST PLA JSR ASTOIN AND #127 ORA SELFLAG LDY #0 Put the character into memory. STA (CURR),Y JSR REFRESH SEC LDA CURR SBC LASTLINE STA TEMP LDA CURR+1 SBC LASTLINE+1 ORA TEMP BCC INKURR LDA CURR ADC #0 STA LASTLINE LDA CURR+1 ADC #0 STA LASTLINE+1 Move the cursor forward. INKURR INC CURR BNE NOINC2 INC CURR+1 NOINC2 JSR CHECK JMP MAIN CONTROL looks up a keyboard command in the list of control codes at CTBL. The first byte of CTBL is the actual number of commands. Once the position is found, this position is doubled as an index to the two-byte address table at VECT. The address of MAIN-1 is put on the stack, simulating the return address; then the address of the command routine taken from VECT is pushed. We then perform an RTS. RTS pulls the bytes off the stack as if they were put there by a JSR. This powerful technique is used to simulate ON-GOTO in machine language. CONTROL LDX CTBL SRCH CMP CTBL,X BEQ FOUND DEX BNE SRCH JMP MAIN FOUND DEX TXA ASL A TAX LDA # >MAIN-1 PHA LDA # <MAIN-1 PHA LDA VECT+1,X PHA LDA VECT,X PHA RTS CTBL .BYTE 35 .BYTE 31,30,92,94,2,20,28,29 .BYTE 126,255,4 .BYTE 9,125,124,95,5,12,19 .BYTE 13,18,24,26,16 .BYTE 254,1,11,6,21,127,157 .BYTE 3,7,156,27,15 VECT .WORD RIGHT-1,LEFT-1,WLEFT-1,WRIGHT-1,BORDER-1,LETTERS-1 .WORD SLEFT-1,SRIGHT-1,DELCHAR-1,INSCHAR-1,DELETE-1 .WORD INSTGL-1,CLEAR-1,PARIGHT-1,PARLEFT-1 .WORD ERAS-1,TLOAD-1,TSAVE-1 .WORD DOS-1,INSBUFFER-1,SWITCH-1 .WORD ENDTEX-1,PRINT-1 .WORD DELIN-1,ALPHA-1,KILLBUFF-1,HUNT-1,FREEMEM-1,TAB-1 .WORD LOTTASPACE-1,REPSTART-1,SANDR-1,EATSPACE-1,ESC-1,ONOFF-1 Toggle ESCape mode. ESC LDA ESCFLAG EOR #128 STA ESCFLAG RTS Change the character definition of the character used to fill in the end of a line. It alternates between being a blank space, and being a blank space with a tiny dot visible. This lets you see which spaces are actually part of your text and which are just used to parse the screen. Beware of the address $2204 if you reassemble at a different address (sorry, I didn't use a label). ONOFF LDA $2204 EOR #16 STA $2204 RTS The CHECK routine first prevents the cursor from disappearing past the beginning or end-of-text memory and prevents us from cursoring past the end-of-text pointer. It also checks to see if the cursor has left the visible screen, scrolling with REFRESH to make the cursor visible. The double-byte SBCs are used as a 16-bit CMP macro, setting the Z and C flags just like CMP does. CHECK JSR CHECK2 SEC LDA CURR SBC TOPLIN LDA CURR+1 SBC TOPLIN+1 BCS OK1 SEC LDA TOPLIN SBC TEXSTART STA TEMP LDA TOPLIN+1 SBC TEXSTART+1 ORA TEMP BEQ OK1 LDA CURR STA TOPLIN LDA CURR+1 STA TOPLIN+1 JSR REFRESH OK1 SEC LDA BOTSCR SBC CURR STA TEX LDA BOTSCR+1 SBC CURR+1 STA TEX+1 ORA TEX BEQ EQA BCS OK2 EQA CLC LDA TOPLIN ADC LENTABLE STA TOPLIN LDA TOPLIN+1 ADC #0 STA TOPLIN+1 REF JSR REFRESH JMP OK1 OK2 RTS CHECK2 SEC LDA LASTLINE SBC TEXEND STA TEMP LDA LASTLINE+1 SBC TEXEND+1 ORA TEMP BCC CK3 LDA TEXEND STA LASTLINE LDA TEXEND+1 STA LASTLINE+1 CK3 SEC LDA CURR SBC TEXSTART STA TEMP LDA CURR+1 SBC TEXSTART+1 ORA TEMP BCS INRANGE LDA TEXSTART STA CURR LDA TEXSTART+1 STA CURR+1 RTS INRANGE SEC LDA CURR SBC LASTLINE STA TEMP LDA CURR+1 SBC LASTLINE+1 ORA TEMP BCS OUTRANGE RTS OUTRANGE LDA LASTLINE STA CURR LDA LASTLINE+1 STA CURR+1 RTS Move cursor right. If the OPTION key is held down, we instead increase the line length. RIGHT LDA #8 STA 53279 LDA 53279 CMP #3 BNE CRIGHT LDA LINELEN CMP #40 BEQ NOBIGGER INC LINELEN INC LINELEN DEC RLM JSR REFRESH JSR CHECK LDA #125 JSR CHROUT NOBIGGER JMP SYSMSG CRIGHT INC CURR BNE NOINCR INC CURR+1 NOINCR JMP CHECK Move cursor left. If the OPTION key is held down, we instead decrease the line length. LEFT LDA #8 STA 53279 LDA 53279 CMP #3 BNE CLEFT LDA LINELEN CMP #2 BEQ TOOSMALL DEC LINELEN DEC LINELEN INC RLM JSR REFRESH JSR CHECK LDA #125 JSR CHROUT TOOSMALL JMP SYSMSG CLEFT LDA CURR BNE NODEC DEC CURR+1 NODEC DEC CURR JMP CHECK Word left. We look backward for a space. WLEFT LDA CURR STA TEX LDA CURR+1 STA TEX+1 DEC TEX+1 LDY #$FF STRIP LDA (TEX),Y CMP #SPACE BEQ STRLOOP CMP #RETCHAR BNE WLOOP STRLOOP DEY BNE STRIP WLOOP LDA (TEX),Y CMP #SPACE BEQ WROUT CMP #RETCHAR BEQ WROUT DEY BNE WLOOP RTS WROUT SEC TYA ADC TEX STA CURR LDA TEX+1 ADC #0 STA CURR+1 JMP CHECK Word right. We scan forward for a space. OIDS is not a meaningful label. WRIGHT LDY #0 RLOOP LDA (CURR),Y CMP #SPACE BEQ ROUT CMP #RETCHAR BEQ ROUT INY BNE RLOOP RTS ROUT INY BNE OIDS INC CURR+1 LDA CURR+1 CMP LASTLINE+1 BCC OIDS BNE LASTWORD OIDS LDA (CURR),Y CMP #SPACE BEQ ROUT CMP #RETCHAR BEQ ROUT Add the Y register to the CURRent cursor position to move the cursor. CHECK prevents illegal cursor movement. LASTWORD is called if the end of the word cannot be found before we reach the end-of-text. ADYCURR CLC TYA ADC CURR STA CURR LDA CURR+1 ADC #0 STA CURR+1 WRTN JMP CHECK LASTWORD LDA LASTLINE STA CURR LDA LASTLINE+1 STA CURR+1 JMP CHECK ENDTEX is tricky. If the end-of-text pointer would point to an area already visible on the screen, we just move the cursor there and call REFRESH. Otherwise, we step back 1K from the end-of-text and then scroll to the end. This is necessary since in the worst case only 18 characters of return-marks would fill the screen. ENDTEX LDA #0 STA TOPLIN LDA LASTLINE+1 SEC SBC #4 CMP TEXSTART+1 BCS SAFE LDA TEXSTART+1 SAFE STA TOPLIN+1 JSR REFRESH JMP LASTWORD Change the border color. The display list interrupt automatically places SCRCOL into the hardware background color register #2. BORDER INC SCRCOL INC SCRCOL RTS SCRCOL .BYTE 8 Change text luminance. TEXCOLR is stored into hardware color register #1 during the display-list interrupt. LETTERS INC TEXCOLR INC TEXCOLR LDA TEXCOLR AND #15 STA TEXCOLR RTS TEXCOLR .BYTE 2 Sentence left. We look backward for ending punctuation or a return-mark, then go forward until we run out of spaces. SLEFT LDA CURR STA TEX LDA CURR+1 STA TEX+1 DEC TEX+1 LDY #$FF PMANY LDA (TEX),Y CMP #'.-32 BEQ PSRCH CMP #'!-32 BEQ PSRCH CMP #'?-32 BEQ PSRCH CMP #RETCHAR BNE PSLOOP PSRCH DEY BNE PMANY RTS PSLOOP LDA (TEX),Y CMP #'.-32 BEQ PUNCT CMP #'!-32 BEQ PUNCT CMP #'?-32 BEQ PUNCT CMP #RETCHAR BEQ PUNCT DEY BNE PSLOOP DEC TEX+1 LDA TEX+1 CMP TEXSTART BCS PSLOOP JMP FIRSTWORD PUNCT STY TEMP DEC TEMP SKIPSPC INY BEQ REPEAT LDA (TEX),Y CMP #SPACE BEQ SKIPSPC DEY JMP WROUT REPEAT LDY TEMP JMP PSLOOP FIRSTWORD LDA TEXSTART STA CURR LDA TEXSTART+1 STA CURR+1 JMP CHECK Sentence right. We look forward for ending punctuation, then skip forward until we run out of spaces. SRIGHT LDY #0 SRLP LDA (CURR),Y CMP #'.-32 BEQ PUNCT2 CMP #'!-32 BEQ PUNCT2 CMP #'?-32 BEQ PUNCT2 CMP #RETCHAR BEQ PUNCT2 INY BNE SRLP INC CURR+1 LDA CURR+1 CMP LASTLINE+1 BEQ SRLP BCC SRLP SREXIT JMP LASTWORD PUNCT2 INY BNE NOFIXCURR INC CURR+1 LDA CURR+1 CMP LASTLINE+1 BCC NOFIXCURR BEQ NOFIXCURR JMP LASTWORD NOFIXCURR LDA (CURR),Y CMP #SPACE BEQ PUNCT2 CMP #'.-32 BEQ PUNCT2 CMP #'!-32 BEQ PUNCT2 CMP #'?-32 BEQ PUNCT2 CMP #RETCHAR BEQ PUNCT2 JMP ADYCURR The text buffer starts at a fixed location, but the end of the buffer is changed as text is added to it. To clear the buffer, we just set the end of the buffer to the value of the start of the buffer. No text is actually erased. KILLBUFF LDA TEXBUF STA TPTR LDA TEXBUF+1 STA TPTR+1 JSR TOPCLR LDA # <KILLMSG LDY # >KILLMSG JSR PRMSG LDA #1 STA MSGFLG RTS This is the second level of the general-purpose delete routines. UMOVE is the primitive core of deleting. For CTRL-D, the CURRent cursor position is the source; then a cursor command is called to update the cursor pointer. This becomes the destination. For CTRL-E, the CURRent cursor position is the destination; a cursor movement routine is called, and this becomes the source. UMOVE is then called. We actually move more than the length from the source to the end-of-text. Some extra text is moved from past the end-of-text. Since everything past the end-of-text is spaces, this neatly erases everything past the new end-of-text position. Naturally, the end-of-text pointer is updated. Before the actual delete is performed, the text to be deleted is stored in the buffer so that it can be recalled in case of error. The buffer doubles as a fail-safe device, and for moving and copying text. Checks are made to make sure that the buffer does not overflow. DEL1 SEC LDA CURR SBC TEXSTART STA TEMP LDA CURR+1 SBC TEXSTART+1 ORA TEMP BNE DEL1A DELABORT PLA PLA RTS DEL1A LDA CURR STA FROML LDA CURR+1 STA FROMH RTS DEL2 SEC LDA CURR STA DESTL EOR #$FF ADC FROML STA GOBLEN LDA CURR+1 STA DESTH EOR #$FF ADC FROMH STA GOBLEN+1 DELC LDA FROML STA FROMSAV LDA FROMH STA FROMSAV+1 LDA DESTL STA DESTSAV STA FROML LDA DESTH STA DESTSAV+1 STA FROMH SEC LDA GOBLEN+1 ADC TPTR+1 CMP BUFEND+1 BCC GOSAV JSR TOPCLR LDA # <BUFERR LDY # >BUFERR JSR PRMSG LDA #1 STA MSGFLG RTS GOSAV LDA TPTR STA DESTL LDA TPTR+1 STA DESTH LDA GOBLEN STA LLEN CLC ADC TPTR STA TPTR LDA GOBLEN+1 STA HLEN ADC TPTR+1 STA TPTR+1 JSR UMOVE LDA FROMSAV STA FROML LDA FROMSAV+1 STA FROMH LDA DESTSAV STA DESTL LDA DESTSAV+1 STA DESTH SEC LDA LASTLINE SBC DESTL STA LLEN LDA LASTLINE+1 SBC DESTH STA HLEN JSR UMOVE SEC LDA LASTLINE SBC GOBLEN STA LASTLINE LDA LASTLINE+1 SBC GOBLEN+1 STA LASTLINE+1 RTS Most delete commands end up calling the above routines. The single-character deletes must subtract 1 from the buffer pointer so that single characters are not added to the buffer. But note how short these routines are. Delete character (BACK S) DELCHAR JSR DEL1 JSR LEFT JSR DEL2 FIXTP SEC LDA TPTR SBC #1 STA TPTR LDA TPTR+1 SBC #0 STA TPTR+1 RTS CTRL-BACK S DELIN JSR RIGHT JSR DEL1 JSR LEFT JSR DEL2 JMP FIXTP Called by CTRL-D. As mentioned, it stores CURR into FROML/FROMH, moves the cursor either by sentence, word, or paragraph, then stores the new position of CURR into DESTL and DESTH. The above routines perform the actual delete. CTRL-D always discards the previous contents of the buffer, for deleting text backward creates a buffer of out-of-order text. Notice how we change the color of the command window to red to warn the user of the impending deletion. DELETE JSR KILLBUFF LDA #RED STA WINDCOLR JSR TOPCLR LDA # <DELMSG LDY # >DELMSG JSR PRMSG JSR GETAKEY PHA JSR SYSMSG PLA AND #95 ORA #64 CMP #'W BNE NOTWORD DELWORD JSR DEL1 JSR WLEFT JMP DEL2 NOTWORD CMP #'S BNE NOTSENT DELSENT JSR DEL1 JSR SLEFT JMP DEL2 NOTSENT CMP #'P BNE NOTPAR JSR DEL1 JSR PARLEFT JMP DEL2 NOTPAR RTS Home the cursor. This is called by the START key. We check to see if START is held down for at least 1/2 second. If it is, we move the cursor to the top of text. HOME SEC LDA CURR SBC TOPLIN STA TEMP LDA CURR+1 SBC TOPLIN+1 ORA TEMP BEQ TOPHOME LDA TOPLIN STA CURR LDA TOPLIN+1 STA CURR+1 WAITST LDA #0 STA 20 STA 53279 HOMEPAUSE LDA 20 CMP #30 BNE HOMEPAUSE OUTHOME JMP CHECK TOPHOME LDA TEXSTART STA CURR LDA TEXSTART+1 STA CURR+1 JMP WAITST This deletes all spaces between the cursor and following nonspace text. Sometimes inventing labels can be fun. EATSPACE LDA CURR STA TEX STA DESTL LDA CURR+1 STA TEX+1 STA DESTH LDY #0 SPCSRCH LDA (TEX),Y CMP #SPACE BNE OUTSPACE INY BNE SPCSRCH LDA TEX+1 CMP LASTLINE+1 BCC GOINC LDA LASTLINE STA TEX LDA LASTLINE+1 STA TEX+1 LDY #0 JMP OUTSPACE GOINC INC TEX+1 JMP SPCSRCH OUTSPACE CLC TYA ADC TEX STA FROML LDA #0 ADC TEX+1 STA FROMH SEC LDA LASTLINE SBC DESTL STA LLEN LDA LASTLINE+1 SBC DESTH STA HLEN SEC LDA FROML SBC DESTL STA GOBLEN LDA FROMH SBC DESTH STA GOBLEN+1 JSR UMOVE SEC LDA LASTLINE SBC GOBLEN STA LASTLINE LDA LASTLINE+1 SBC GOBLEN+1 STA LASTLINE+1 RTS Insert 255 spaces. Notice how it and other insert routines use TAB2. LOTTASPACE LDA #255 STA INSLEN JMP TAB2 TAB LDA #5 STA INSLEN JSR TAB2 LDA (CURR),Y CMP #SPACE BNE NOINCY INY NOINCY JMP ADYCURR TAB2 LDA #0 STA INSLEN+1 JSR INSBLOCK LDA #SPACE LDX INSLEN LDY #0 FILLSP STA (CURR),Y INY DEX BNE FILLSP RTS Insert a single space. INSCHAR LDA #1 STA INSLEN LDA #0 STA INSLEN+1 JSR INSBLOCK LDA #SPACE LDY #0 STA (CURR),Y JMP CHECK A general routine to insert as many spaces as are specified by INSLEN. INSBLOCK CLC LDA LASTLINE ADC INSLEN LDA LASTLINE+1 ADC INSLEN+1 CMP TEXEND+1 BCC OKINS PLA PLA JMP INOUT OKINS CLC LDA CURR STA FROML ADC INSLEN STA DESTL LDA CURR+1 STA FROMH ADC INSLEN+1 STA DESTH SEC LDA LASTLINE SBC FROML STA LLEN LDA LASTLINE+1 SBC FROMH STA HLEN JSR DMOVE CLC LDA LASTLINE ADC INSLEN STA LASTLINE LDA LASTLINE+1 ADC INSLEN+1 STA LASTLINE+1 INOUT RTS Toggle insert mode. The INSMODE nag doubles as the color of the command line. INSTGL LDA INSMODE EOR #BLUE STA INSMODE RTS Another example of modular code. This is called anytime a yes/no response is called for. It prints "Are you sure? (Y/N)," then returns with the zero flag set to true if Y was pressed, ready for the calling routine to use BEQ or BNE as a branch for yes or no. We trap out the clear-screen key in case this routine is called by Erase All, since otherwise repeating keys may instantly cancel the command. The AND #223 zaps out the distinction between uppercase and lowercase Y. YORN LDA # <YMSG LDY # >YMSG JSR PRMSG YORNKEY JSR GETIN AND #127 BEQ YORNKEY CMP #125 BEQ YORNKEY AND #223 CMP #'Y RTS Erase all text. Allowed only if the OPTION key is held down with SHIFT-CLEAR. It calls YORN to affirm the deadly deed, then calls ERASE to erase all text, INIT2 to reset some flags, then jumps back to the MAIN loop. LDX #$FA / TXS is used to clean up the stack. CLEAR LDA #8 STA 53279 LDA 53279 CMP #3 BEQ OKCLEAR RTS OKCLEAR LDA #RED STA WINDCOLR JSR TOPCLR LDA # <CLRMSG LDY # >CLRMSG JSR PRMSG JSR YORN BEQ DOIT JMP SYSMSG DOIT LDX #$FA TXS JSR ERASE JSR INIT2 JMP MAIN Paragraph right. PARIGHT LDY #0 PARLP LDA (CURR),Y CMP #RETCHAR BEQ RETFOUND INY BNE PARLP INC CURR+1 LDA CURR+1 CMP LASTLINE+1 BCC PARLP BEQ PARLP JMP LASTWORD RETFOUND INY BNE GOADY INC CURR+1 GOADY JMP ADYCURR Paragraph left. Notice the trick of decrementing the high byte of the pointer, then starting the index at 255 in order to search backward. PARLEFT LDA CURR STA TEX LDA CURR+1 STA TEX+1 DEC TEX+1 LDY #$FF PARLOOP LDA (TEX),Y CMP #RETCHAR BEQ RETF2 PARCONT DEY CPY #255 BNE PARLOOP DEC TEX+1 LDA TEX+1 CMP TEXSTART+1 BCS PARLOOP JMP FIRSTWORD RETF2 SEC TYA ADC TEX STA TEX LDA #0 ADC TEX+1 STA TEX+1 SEC LDA TEX SBC CURR STA TEMP LDA TEX+1 SBC CURR+1 ORA TEMP BNE TEXTOCURR STY TEMP CLC LDA TEX SBC TEMP STA TEX LDA TEX+1 SBC #0 STA TEX+1 JMP PARCONT TEXTOCURR LDA TEX STA CURR LDA TEX+1 STA CURR+1 JMP CHECK This enables the display-list interrupt (DLI). The DLI allows separate background colors for the command line and the rest of the screen. It lets us change the color of the top line to flag insert mode or to warn the user with a red color that he/she should be careful. Since it is an interrupt, it is always running in the background. Interrupt routines must always be careful not to corrupt the main program. HIGHLIGHT turns off any DLIs (by storing #64 into $D40E), sets the NMI pointer ($200/$201), creates a custom display list of IRG mode 3 (lowercase descenders, GRAPHICS 0 1/2) With DLI set in one line, then enables DLIs ($C0 into $D40E) and returns. The routine DLI is now running constantly in the background, changing the screen color of all text below the DLI. HIGHLIGHT LDA #64 STA $D40E LDA # <DLI STA $0200 LDA # >DLI STA $0201 LDA 560 STA TEMP LDA 561 STA TEMP+1 LDY #0 DLOOP LDA DLIST,Y STA (TEMP),Y INY CPY #28 BNE DLOOP LDY #4 LDA $58 STA (TEMP),Y LDA $59 INY STA (TEMP),Y LDY #26 LDA TEMP STA (TEMP),Y LDA TEMP+1 INY STA (TEMP),Y LDA #$C0 STA $D40E RTS The custom display list. DLIST .BYTE 112,112,112,3+64+128,0,0 .BYTE 3,3,3,3,3,3,3,3,3,3,3,3,3 .BYTE 3,3,3,3,3,16,65,0,0 The display-list interrupt routine stores the SCReen COLor and TEXt COLoR into the appropriate hardware registers, then stores the WINDow COLoR into 710, and #10 into 709 to set the color of the top line of the screen. This line is automatically set by the normal vertical- blank interrupt. We also force the character-set pointer to keep our character set in place whenever we're on the editing screen. DLI PHA LDA SCRCOL STA $D40A STA $D018 STA 712 LDA TEXCOLR STA $D017 LDA WINDCOLR STA 710 LDA #10 STA 709 LDA #$20 STA 756 LDA #0 STA $02B6 PLA RTI ERAS is called by CTRL-E. It works much like CTRL-D. Notice that the ORA #64 allows users to press either S, W, P, or CTRL-S, CTRL-W, CTRL-P, in case they have a habit of leaving the control key held down. It must call RE- FRESH after each move and adjust the new position of the cursor. If OPTION is held down with CTRL-E, we don't erase the previous contents of the buffer, letting the user chain non-contiguous sections into the buffer for later recall. ERAS LDA #8 STA 53279 LDA 53279 CMP #3 BEQ ERAS1 JSR KILLBUFF ERAS1 JSR TOPCLR LDA # <ERASMSG LDY # >ERASMSG JSR PRMSG ERASAGAIN LDY #0 LDA (CURR),Y EOR #$80 STA (CURR),Y JSR REFRESH LDY #0 LDA (CURR),Y EOR #$80 STA (CURR),Y LDA #RED STA WINDCOLR JSR GETAKEY AND #95 ORA #64 CMP #'W BNE NOWORD ERASWORD JSR ERA1 JSR WRIGHT JMP ERA2 NOWORD CMP #'S BNE UNSENT ERASENT JSR ERA1 JSR SRIGHT JMP ERA2 UNSENT CMP #'P BNE NOPAR JSR ERA1 JSR PARIGHT JMP ERA2 NOPAR JSR CHECK JMP SYSMSG ERA1 LDA CURR STA DESTL STA SAVCURR LDA CURR+1 STA DESTH STA SAVCURR+1 RTS ERA2 SEC LDA CURR STA FROML SBC SAVCURR STA GOBLEN LDA CURR+1 STA FROMH SBC SAVCURR+1 STA GOBLEN+1 JSR DELC LDA SAVCURR STA CURR LDA SAVCURR+1 STA CURR+1 JSR REFRESH JMP ERASAGAIN The INPUT routine is used to get responses from the command line. It returns the complete line in INBUFF. INLEN is the length of the input. A zero byte is stored at INBUFF+INLEN after the user presses RETURN. This routine is foolproof (I know...), since no control keys other than BACK S are allowed, unless preceded by ESCape. The SELECT key can be held down to enter inverse-video characters. The system cursor is turned on for this routine (by putting #0 into 752), then turned off when we exit (by putting #1 into 752). This routine also prevents the user from typing past the end of the command line. If the limit of typing length must be set arbitrarily, LIMIT is preset and INPUT is called at INP1. CURSIN is the MAIN loop. INPUT LDA #39 SBC 85 STA LIMIT INP1 LDY #0 STY INLEN STY 752 LDA #32 JSR CHROUT LDA #126 JSR CHROUT CURSIN STY INLEN JSR GETAKEY LDY INLEN BIT ESCFLAG BMI ESCKEY CMP #27 BNE NOESC LDA #128 STA ESCFLAG STA $02A2 JMP CURSIN NOESC CMP #155 BEQ INEXIT CMP #126 BNE NOBACK DEY BPL NOTZERO INY JMP CURSIN NOTZERO LDA #126 JSR CHROUT JMP CURSIN NOBACK STA TEMP AND #127 CMP #32 BCC CURSIN CMP #125 BCS CURSIN CPY LIMIT BEQ CURSIN LDA TEMP ESCKEY AND #127 LDX #8 STX 53279 LDX 53279 CPX #5 BNE SKIPSEL ORA #128 SKIPSEL STA INBUFF,Y JSR CHROUT LDA #0 STA ESCFLAG INY JMP CURSIN INEXIT LDX #1 STX 752 LDA #0 STA INBUFF,Y TYA RTS .ENDFilename: SUPPORT
This module supports most primitive input/output functions, including a routine to clear the screen and reset the screen editor (OPENEDITOR), print a character (CHROUT), and get a key from the keyboard (GETAKEY). OPENEDITOR LDX #0 LDA #12 STA ICCOM JSR CIO LDX #0 LDA # <ENAME STA ICBADR LDA # >ENAME STA ICBADR+1 LDA #2 STA ICBLEN STX ICBLEN+1 LDA #3 STA ICCOM,X JMP CIO Put the ATASCII value of the character into the accumulator and call CHROUT to print a character. The Y register is preserved. We call CIO with a buffer length of zero. CHROUT STY CHRYSAVE LDX #0 STX ICBLEN STX ICBLEN+1 STX $02FF LDY #11 STY ICCOM JSR CIO LDY CHRYSAVE RTS The filename of the Editor device. ENAME .BYTE "E:" OUTNUM and PROUTNUM print decimal numbers to the display or printer. The integer to be printed is passed with the low byte in the X register and the high byte in the accumulator. The integer to floating-point routine ($D9AA) is called first, followed by floating-point to ATASCII routine, which creates a string of ATASCII digits. The last digit of the number has bit 7 set, which we use to terminate printing. PROUTNUM LDY #128 JMP OVERZAP OUTNUM LDY #0 OVERZAP STY WHICHFLAG STX $D4 STA $D5 JSR $D9AA JSR $D8E6 LDY #0 ONUMLOOP LDA ($F3),Y PHA AND #$7F BIT WHICHFLAG BMI GOPCHR JSR CHROUT JMP OVERPCHR GOPCHR JSR PCHROUT OVERPCHR PLA BMI ONUMEXIT INY BNE ONUMLOOP ONUMEXIT RTS CHRYSAVE .BYTE 0 The system keyboard fetch routine interferes with the display-list interrupt, since the blip of each key is timed with WSYNC, which freezes the ANTIC chip for one line. This causes annoying flicker. This routine uses POKEY sound decaying from volume 15 to 0 for the keyboard feedback tone. It's not hard to create any sound effect you want for the keyboard blip. This routine mimics the system routine fairly closely. It's easy to expand it to allow many more keyboard functions and full processing of new keystrokes just by changing some of this code and the keyboard table. GETIN LDA 764 CMP #$FF BNE GETCHAR LDA #0 RTS GETCHAR LDA 764 CMP #$FF BEQ GETCHAR STA KEYVAL LDA #$FF STA 764 Clear break flag. STA $11 JSR BLIP LDA KEYVAL Check for SHIFT+CTRL. CMP #$C0 BCS GXIT AND #63 CMP #60 BNE NOTCAPS LDA KEYVAL AND #64 BEQ NOTSET STA SHFLOK GXIT LDA #0 RTS The CAPS/LOWR key toggles the SHiFtLOcK flag to allow either only uppercase, or both uppercase and lowercase. NOTSET LDA SHFLOK EOR #64 STA SHFLOK LDA #0 RTS NOTCAPS LDX KEYVAL LDA KEYBOARD,X BIT SHFLOK BVC NOTLOCKED CMP #'a BCC NOTLOCKED CMP #'z+1 BCS NOTLOCKED AND #223 NOTLOCKED CMP #$80 BEQ GXIT RTS The sound effect for the keyboard "blip." BLIP PHA LDA #50 STA $D200 LDX #$AF SNDLOOP STX $D201 LDY #128 SLOW DEY BNE SLOW DEX CPX #$9F BNE SNDLOOP PLA RTS KEYBOARD .BYTE 108,106,59,128,128,107 .BYTE 43,42,111,128,112,117 .BYTE 155,105,45,61,118,128 .BYTE 99,128,128,98,120,122 .BYTE 52,128,51,54,27,53 .BYTE 50,49,44,32,46,110 .BYTE 128,109,47,$80,114,128 .BYTE 101,121,127,116,119,113 .BYTE 57,128,48,55,126,56 .BYTE 60,62,102,104,100,128 .BYTE 130,103,115,97,76,74 .BYTE 58,128,128,75,92,94 .BYTE 79,128,80,85,155,73 .BYTE 95,124,86,128,67,128 .BYTE 128,66,88,90,36,128 .BYTE 35,38,27,37,34,33 .BYTE 91,32,93,78,128,77 .BYTE 63,$80,82,128,69,89 .BYTE 159,84,87,81,40,128 .BYTE 41,39,156,64,125,157 .BYTE 70,72,68,128,131,71 .BYTE 83,65,12,10,123,128 .BYTE 128,11,30,31,15,128 .BYTE 16,21,155,9,28,29 .BYTE 22,128,3,128,128,2 .BYTE 24,26,128,128,133,128 .BYTE 27,128,253,128,0,32 .BYTE 96,14,128,13,128,$80 .BYTE 18,128,5,25,158,20 .BYTE 23,17,128,128,128,128 .BYTE 254,128,125,255,6,8 .BYTE 4,128,132,7,19,1 .ENDFilename: DOSPAK
DOSPAK is a self-contained substitute for the DOS menu, although it uses several routines built into SpeedScript. The concept of DOSPAK is that all directory entries should fit on one screen. A large cursor is used to move from filename to filename. At any time, you can delete, rename, lock, unlock, or load the selected filename, just by pressing one key, or a CTRL key combination. Except for Rename, you don't have to type the filename. You can also format the entire disk or redisplay the directory. CATALOG fits the entire disk directory onto the screen by skipping over the sector counts, trimming up spacing, and placing three items per line. The cursor position of each filename is saved into a slot in memory so that the cursor routine can quickly and easily skip about. CATALOG JSR CLOSE7 LDX #$70 LDA # <DIRNAME STA ICBADR,X LDA # >DIRNAME STA ICBADR+1,X LDA #5 STA ICBLEN,X LDA #0 STA ICBLEN+1,X LDA #6 STA ICAUX1,X LDA #3 STA ICCOM,X JSR CIO BMI CLOSE7 LDA #0 STA XPTR REDIR LDX XPTR LDA $64 STA SLOT,X LDA $65 STA SLOT+1,X INC XPTR INC XPTR JSR GET7 BMI CLOSE7 CMP #'*+1 BCS ENDIR JSR CHROUT JSR GET7 BMI CLOSE7 LDA #0 STA DIRCOUNT DIRLOOP JSR GET7 BMI CLOSE7 DNOTCR JSR CHROUT INC DIRCOUNT LDA DIRCOUNT CMP #8 BNE DNOT8 LDA #'. JSR CHROUT JMP DIRLOOP DNOT8 CMP #11 BNE DIRLOOP LDA #5 STA TEMP THROW5 JSR GET7 DEC TEMP LDA TEMP BNE THROW5 JMP REDIR CLOSE7 LDX #$70 LDA #12 STA ICCOM,X JSR CIO LDX #$70 LDY ICSTAT,X RTS ENDIR PHA LDA #155 JSR CHROUT PLA JSR CHROUT ENDLP JSR GET7 BMI CLOSE7 JSR CHROUT JMP ENDLP GET7 LDX #$70 LDA #0 STA ICBLEN,X STA ICBLEN+1,X LDA #7 STA ICCOM,X JMP CIO The main DOS routine calls the CATALOG routine to fill the screen with filenames, then puts the cursor on the current filename, waiting for a keypress. DOS JSR DELITE JSR OPENEDITOR JSR DELITE LDA #1 STA 752 STA 82 LDA #125 JSR CHROUT JSR CATALOG JSR DOSMSG GETNAME LDA SLOT STA SCR LDA SLOT+1 STA SCR+1 LDA #0 STA XSLOT DEC XPTR DEC XPTR NAMELP JSR INVNAME JSR GETAKEY LDX #1 STX 752 Now that we've got a keypress, we look it up in the keypress table, then vector to the appropriate routine. This is the same ML ON-GOTO routine that we've used in several places in SpeedScript, including the CONTROL routine. LDX DOSTABLE CMP #97 BCC NOPROB AND #95 NOPROB STA TEMP FINDIT CMP DOSTABLE,X BEQ FOUNDIT DEX BNE FINDIT JMP JNAME FOUNDIT DEX TXA ASL A TAX LDA DOSADR+1,X PHA LDA DOSADR,X PHA RTS The braces surround control characters, some entered with the ESCape key: cursor-left, cursor-right, cursor-up, cursor-down, CTRL-D, ESCape, and CTRL-L. DOSTABLE .BYTE 15 .BYTE "{LEFT}{RIGHT}{UP}{DOWN}{D}RLUF1234{ESC}{L}" DOSADR .WORD DLEFT-1,DRIGHT-1,DUP-1,DDOWN-1,DELFILE-1,RENAME-1 .WORD LOCK-1,UNLOCK-1,FORMAT-1,DRIVE-1,DRIVE-1,DRIVE-1 .WORD DRIVE-1,ESCDOS-1,LOADIT-1 Move bar cursor left by decrementing slot pointer. DLEFT JSR INVNAME LDX XSLOT BEQ NRANGE DEX DEX JMP RESLOT Move bar cursor right by incrementing slot pointer. DRIGHT JSR INVNAME LDX XSLOT INX INX CPX XPTR BCS NRANGE Store new slot index. RESLOT STX XSLOT LDA SLOT,X STA SCR LDA SLOT+1,X STA SCR+1 NRANGE JMP NAMELP Move bar cursor up by subtracting 6 from the slot pointer (each slot is two bytes). DUP JSR INVNAME LDA XSLOT CMP #6 BCC NRANGE SEC SBC #6 TAX JMP RESLOT Move bar cursor down by adding 6 to the slot pointer. DDOWN JSR INVNAME LDA XSLOT CLC ADC #6 CMP XPTR BCS NRANGE TAX JMP RESLOT This routine turns a filename pointed to by the bar cursor into a legal CIO filename, complete with Dx: and legal extension. NAMER LDX #0 COPYD LDA DIRNAME,X STA FNBUFF,X INX CPX #3 BNE COPYD LDY #1 COPYNAME LDA (SCR),Y AND #127 JSR INTOAS CMP #32 BEQ NOSTOR STA FNBUFF,X INX NOSTOR INY CPY #13 BNE COPYNAME LDA FNBUFF-1,X CMP #'. BNE NOTDOT DEX NOTDOT STX FNLEN LDA #0 STA FNBUFF,X RTS This routine passes any CIO command along with a formed filename. XIO LDX #$70 STA ICCOM,X LDA FNLEN STA ICBLEN,X LDA #0 STA ICBLEN+1,X LDA # <FNBUFF STA ICBADR,X LDA # >FNBUFF STA ICBADR+1,X JMP CIO The DOS functions are quite short. NAMER builds the name; then we simply pass the number of the DOS CIO function unto XIO. If there's no error, we return to waiting for the next keystroke; otherwise, print the DOS error message and wait for a keystroke. DELFILE JSR NAMER LDA #33 Jump to the XIO routine. GOXIO JSR XIO BPL JNAME JMP DOSERR JNAME JSR INVNAME JMP NAMELP Lock a file. LOCK JSR NAMER LDA #35 JMP GOXIO Unlock a file. UNLOCK JSR NAMER LDA #36 JMP GOXIO We ask for the new name of the file, build the rename string, then jump to the XIO routine. RENAME JSR BOTCLR LDA # <RENMSG LDY # >RENMSG JSR PRMSG LDA #64 STA $02BE JSR INPUT LDA #0 STA $02BE LDA INLEN BEQ NONAME JSR NAMER LDX #0 LDY FNLEN LDA #', STA FNBUFF,Y INY COPYR LDA INBUFF,X STA FNBUFF,Y INY INX CPX INLEN BNE COPYR STY FNLEN LDA #0 STA FNBUFF,Y JSR DOSMSG LDA #32 JMP GOXIO NONAME JSR DOSMSG JMP JNAME Format routine. We use YORN to af firm this operation, which erases an entire disk. BOTCLR clears the bottom line of the screen. FORMAT JSR BOTCLR LDA # <FORMSG LDY # >FORMSG JSR PRMSG JSR YORN BNE NONAME JSR DOSMSG JSR NAMER LDA #254 JMP GOXIO Select new drive number and redisplay directory. DRIVE LDA TEMP STA DIRNAME+1 JMP DOS The Load-from-directory routine opens the file, then jumps into the SpeedScript Load routine. LOADIT LDX #$70 STX IOCB LDA #4 STA ICAUX1,X LDA #0 STA INDIR STA INDIR+1 JSR NAMER Command 3 is for OPEN file. LDA #3 JSR XIO BMI DOSERR JSR ERASE JSR LOADLINK If the load ended with an error, we display the error; otherwise, we exit the DOSPAK at ESCDOS. BMI DOSERR The ESCape DOS routine clears the stack, clears the screen, reenables the display-list interrupt, prints the "SpeedScript" message, then jumps back to the editing loop. ESCDOS LDX #$FA TXS LDA #125 JSR CHROUT JSR HIGHLIGHT JSR SYSMSG JMP MAIN BOTCLR erases the bottom two lines of the screen by positioning the cursor on the next-to-the-last line, then printing two INSERT LINE characters that push any text on these lines off the bottom of the screen. Nifty, eh? BOTCLR LDA #22 STA 84 LDA #157 JSR CHROUT JMP CHROUT This is the error routine for the DOSPAK. We print "ERROR #", then print the error number with OUTNUM, a bell character (actually sounds like an annoying buzzer, appropriate Pavlovian treatment), then "Press RETURN." We wait for a keystroke, then return to getting keys for the DOSPAK commands. DOSERR STY YSAVE JSR CLOSE7 JSR BOTCLR LDA # <ERRMSG LDY # >ERRMSG JSR PRMSG LDX YSAVE LDA #0 JSR OUTNUM LDA #253 JSR CHROUT LDA # <DIRMSG LDY # >DIRMSG JSR PRMSG JSR GETAKEY JSR DOSMSG JMP JNAME Inverse the filename field of the currently selected filename. Used to create the bar cursor. INVNAME LDY #12 INVLP LDA (SCR),Y EOR #128 STA (SCR),Y DEY BPL INVLP RTS DOSMSG erases the bottom line of the screen and prints the DOSPAK command line, an abbreviated menu. DOSMSG JSR BOTCLR LDA # <DIRINS LDY # >DIRINS JSR PRMSG LDA DIRNAME+1 JMP CHROUT .ENDFilename: SPEED.2
This is the main input/output portion of SpeedScript, responsible for loading, saving, and all printing functions. CAST and CINSTOAS (standing for Convert to ASCII and Convert INTernal code to ASCII) translate the way SpeedScript stores text in memory (internal screen codes) into ASCII so that disk files will be compatible with most other software. In addition, the return- mark is changed to character 155, and vice versa. This is why you can't load a machine language file into SpeedScript, edit it, then save it back as a runnable modification. All back-arrows are turned into carriage returns on output, and all carriage returns (155's) are turned into back-arrows (30's) on input. CAST LDA #0 STA CONVFLAG JMP CAST1 CINTOAS LDA #128 STA CONVFLAG CAST1 LDA TEXSTART STA TEX LDA TEXSTART+1 STA TEX+1 JMP CIN CASTOIN LDA #0 STA CONVFLAG LDA CURR STA TEX LDA CURR+1 STA TEX+1 CIN SEC LDA LASTLINE+1 SBC TEX+1 TAX INX LDY #0 CVLOOP LDA (TEX),Y BIT CONVFLAG BMI COTHER CMP #155 BNE NOTRTN LDA #RETCHAR JMP OVEROTHER NOTRTN JSR ASTOIN JMP OVEROTHER COTHER CMP #RETCHAR BNE NOTRC LDA #155 JMP OVEROTHER NOTRC JSR INTOAS OVEROTHER STA (TEX),Y INY BNE CVLOOP INC TEX+1 DEX BNE CVLOOP RTS Here is where most of the input/output routines start. TSAVE saves the entire document area using the CIO block output routine (PUT TEXT). TOPEN is called by both TSAVE and TLOAD to get the filename and open the file. The device specification (D: or C:) must be typed in by the user. TSAVE prints the Save: prompt, goes to TOPEN with an 8 (for output, the same number in OPEN 1,8,0,"D:file"), and uses IOCB #7 (LDX #$70) to send a PUT TEXT command (11). Text is written from the start-of-text with a length of LASTLINE - TEXSTART. TSAVE JSR TOPCLR LDA # <SAVMSG LDY # >SAVMSG JSR PRMSG LDA #8 JSR TOPEN BMI ERROR JSR CINTOAS LDX #$70 LDA TEXSTART STA ICBADR,X LDA TEXSTART+1 STA ICBADR+1,X SEC LDA LASTLINE SBC TEXSTART STA ICBLEN,X LDA LASTLINE+1 SBC TEXSTART+1 STA ICBLEN+1,X LDA #11 STA ICCOM,X JSR CIO The N (negative) bit is set when an error occurs after a call to CIO or a routine that ends up calling CIO. Therefore, we can use BMI to branch on an error condition. BMI ERR1 JSR CAST JSR CLOSE7 BMI ERROR JMP FINE ERR1 TYA PHA JSR CAST PLA TAY The error routine uses the error number found in the Y register, prints the error message with PRMSG, and the error number with OUTNUM. The open file is closed. If the BREAK key was used to stop the operation, we distinguish this from an ordinary error, and print "BREAK Abort" instead. ERROR CPY #128 BEQ STOPPED TYA PHA LDA #125 JSR CHROUT LDA # <ERRMSG LDY # >ERRMSG JSR PRMSG PLA TAX LDA #0 JSR OUTNUM ERXIT JSR IOCLOSE JSR HIGHLIGHT LDA #1 STA MSGFLG RTS STOPPED JSR TOPCLR LDA # <BRMSG LDY # >BRMSG JSR PRMSG JMP ERXIT General file closing routine. IOCB contains the channel number times 16. IOCLOSE LDX IOCB LDA #12 STA ICCOM,X JMP CIO TOPEN is used to get a filename, including the device specification. It's used by Save, Load, and Print. It forces the CAPS key to uppercase for the filename, which is not quite as satisfactory as converting the filename if lowercase was used. It does return the CAPS key to its former value, though. TOPEN opens the file and returns with the error code in the Y register. TOPEN LDX #$70 STX IOCB STA ACCESS Save current CAPS value. LDA SHFLOK PHA CAPS On. LDA #64 STA SHFLOK JSR INPUT Restore CAPS value. PLA STA SHFLOK LDA INLEN BNE OPCONT OPABORT JSR SYSMSG PLA PLA JMP HIGHLIGHT OPCONT JSR IOCLOSE LDX IOCB LDA # <INBUFF STA ICBADR,X LDA # >INBUFF STA ICBADR+1,X LDA INLEN STA ICBLEN,X LDA #0 STA ICBLEN+1,X LDA ACCESS STA ICAUX1,X LDA #3 STA ICCOM,X JMP CIO The Load routine checks the cursor position. If the cursor is at the top-of-text (CURR=TEXSTART), we call the ERASE routine to wipe out memory before the load. Otherwise, the load starts at the cursor position, performing an append, and we change the command line to green ($C4, sorry about not using a label) to warn the user. We open the file for reading by passing a 4 to TOPEN, then at LOADLINK use GET TEXT (command 7) to get no more than the length of the text area. The actual length loaded is found in ICBLEN, so we add this to TEXSTART and the offset between the cursor position and TEXSTART to get the position of the end-of-text (LASTLINE). A funny thing happens, though. Up to 255 garbage characters appear following an otherwise normal load, after the end-of-text. I was never able to figure out why (and I puzzled over it for a week), so I wrote a stopgap routine to just clear out one page past the end-of-text. The bug is not fixed per se, but it has no effect anymore! I still think it must be the fault of the operating system (I know...). TLOAD SEC LDA CURR SBC TEXSTART STA TEX STA INDIR LDA CURR+1 SBC TEXSTART+1 STA TEX+1 STA INDIR+1 ORA TEX BEQ LOAD2 LDA #$C4 STA WINDCOLR LOAD2 JSR TOPCLR LDA # <LOADMSG LDY # >LOADMSG JSR PRMSG LDA #4 JSR TOPEN BPL OKLOD GOERROR JMP ERROR OKLOD LDA WINDCOLR CMP #$C4 BEQ NOER JSR ERASE NOER JSR LOADLINK CPY #128 BCC JFINE JMP ERROR JFINE JMP FINE Entry point for linked files loading. LOADLINK LDX IOCB LDA CURR STA ICBADR,X LDA CURR+1 STA ICBADR+1,X SEC LDA TEXEND SBC CURR STA ICBLEN,X LDA TEXEND+1 SBC CURR+1 STA ICBLEN+1,X LDA #7 STA ICCOM,X JSR CIO BPL TEXOK CPY #136 BEQ TEXOK RTS TEXOK LDX IOCB CLC LDA ICBLEN,X ADC TEXSTART STA LASTLINE LDA ICBLEN+1,X ADC TEXSTART+1 STA LASTLINE+1 CLC LDA LASTLINE ADC INDIR STA LASTLINE LDA LASTLINE+1 ADC INDIR+1 STA LASTLINE+1 JSR CASTOIN LDA LASTLINE STA TEX LDA LASTLINE+1 STA TEX+1 LDA #0 TAY NOGARBAGE STA (TEX),Y INY BNE NOGARBAGE RTS FINE JSR IOCLOSE BPL PROKMSG JMP ERROR PROKMSG LDA #125 JSR CHROUT LDA # <OKMSG LDY # >OKMSG JSR PRMSG JMP ERXIT Disable display-list interrupt and restore screen colors. DELITE LDA #$40 STA $D40E LDA SCRCOL STA 710 STA 712 LDA TEXCOLR STA 709 RTS A rather short routine that converts a string of ASCII digits into a number in hex and the accumulator. It takes advantage of decimal mode. In decimal mode, the accumulator is adjusted after additions and subtractions so that it acts like a two-digit decimal counter. We shift BCD over a nybble and add in the left nybble of the ASCII number until we reach the end of the ASCII number. We then subtract 1 from BCD and increment X (which doesn't conform to decimal mode) until BCD is down to 0. The X register magically holds the converted number. Naturally, decimal mode is cleared before this routine exits, or it would wreak major havoc. ASCHEX is used to convert the parameters of printer commands like left margin. ASCHEX LDX #0 STX BCD STX BCD+1 STX HEX STX HEX+1 DIGIT SEC LDA (TEX),Y SBC #16 BCC NONUM CMP #10 BCS NONUM ASL BCD ROL BCD+1 ASL BCD ROL BCD+1 ASL BCD ROL BCD+1 ASL BCD ROL BCD+1 ORA BCD STA BCD INY BNE DIGIT INC TEX+1 JMP DIGIT NONUM SED DECHEX LDA BCD ORA BCD+1 BEQ DONENUM SEC LDA BCD SBC #1 STA BCD LDA BCD+1 SBC #0 STA BCD+1 INC HEX BNE NOHEXINC INC HEX+1 NOHEXINC JMP DECHEX DONENUM LDA HEX CLD RTS Insert the buffer. This is the recall routine called by CTRL-R. It must not allow an insertion that would overfill memory. It calls DMOVE to open a space in memory, then UMOVE (which is a little faster than DMOVE) to copy the buffer to the empty space. INSBUFFER SEC LDA TPTR SBC TEXBUF STA BUFLEN LDA TPTR+1 SBC TEXBUF+1 STA BUFLEN+1 ORA BUFLEN BNE OKBUFF JSR TOPCLR LDA # <INSMSG LDY # >INSMSG JSR PRMSG LDA #1 STA MSGFLG RTS OKBUFF CLC LDA CURR STA FROML ADC BUFLEN STA DESTL LDA CURR+1 STA FROMH ADC BUFLEN+1 STA DESTH SEC LDA LASTLINE SBC FROML STA LLEN LDA LASTLINE+1 SBC FROMH STA HLEN CLC ADC DESTH CMP TEXEND+1 BCC OKMOV JSR TOPCLR LDA # <INSERR LDY # >INSERR JSR PRMSG LDA #1 STA MSGFLG RTS OKMOV JSR DMOVE CLC LDA BUFLEN STA LLEN ADC LASTLINE STA LASTLINE LDA BUFLEN+1 STA HLEN ADC LASTLINE+1 STA LASTLINE+1 LDA CURR STA DESTL LDA CURR+1 STA DESTH LDA TEXBUF STA FROML LDA TEXBUF+1 STA FROMH JSR UMOVE JMP CHECK Exchange the character highlighted by the cursor with the character to the right of it. Not a vital command, but it was included due to the brevity of the code. SWITCH LDY #0 LDA (CURR),Y TAX INY LDA (CURR),Y DEY STA (CURR),Y INY TXA STA (CURR),Y RTS Change the case of the character highlighted by the cursor. ALPHA LDY #0 LDA (CURR),Y AND #63 CMP #33 BCC NOTALPHA CMP #59 BCS NOTALPHA LDA (CURR),Y EOR #64 STA (CURR),Y NOTALPHA JMP RIGHT Convert internal (screen code) format to Atari ASCII (ATASCII). Used to convert the screen-code format of SpeedScript documents to ASCII for the sake of printing. INTOAS PHA AND #128 STA TEMP PLA AND #127 CMP #96 BCS XINT INCONT CMP #64 BCC INT1 SBC #64 JMP XINT INT1 ADC #32 XINT ORA TEMP RTS The start of the printer routines. This part could logically be called a separate program, but many variables are common to the above code. DEFTAB: Table of default settings for left margin, right margin, page length, top margin, bottom margin, etc. See the table starting at LMARGIN at the end of this source code. DEFTAB .BYTE 5,75,66,5,58,1,1,1,0,1,0,80 Table of default printer codes. PRCODES .BYTE 27,14,15,18 Another advantage of modular coding is that you can change the behavior of a lot of code by just changing one small common routine. This is a substitute for the normal CHROUT routine. It checks to see if the current page number equals the page number specified by the user to start printing. It also checks for the BREAK to abort the printing and permits printing to be paused with CTRL-1. PCHROUT STA PCR TXA PHA TYA PHA SEC LDA PAGENUM SBC STARTNUM LDA PAGENUM+1 SBC STARTNUM+1 BCC SKIPOUT LDA #1 STA 766 LDX #$70 LDA #0 STA ICBLEN,X STA ICBLEN+1,X LDA #11 STA ICCOM,X LDA PCR JSR CIO PHP LDA #0 STA 766 PLP BPL SHIFTFREEZE ERRLINK JSR ERROR LDX #$FA TXS JMP MAIN SHIFTFREEZE LDA $02FF ;CTRL-1 BNE SHIFTFREEZE SKIPOUT PLA TAY PLA TAX LDA PCR RTS Displays "Printing..." PRIN JSR TOPCLR LDA # <PRINMSG LDY # >PRINMSG JMP PRMSG PBORT JMP PEXIT Called by CTRL-P. We get the filename to print to (usually P:, although you can use E: to print to the screen) with ICAUX1 set to 8 for output. We exit on any error. The DELITE routine turns off the display-list interrupt, which might otherwise interfere with output timing. PRINT JSR TOPCLR LDA # <FNMSG LDY # >FNMSG JSR PRMSG JSR DELITE LDA #8 JSR TOPEN BPL PROK JMP PEXIT Reset several flags (footer length, header length, true ASCII, underline mode, and linefeed mode). Notice how DELITE is called again. This isn't a mistake. The first time we called DELITE, we then may have opened a file to the Editor device. This reset the screen to the default colors, so the second DELITE retains the user's true color choice. PROK JSR DELITE JSR PRIN LDX #0 STX FTLEN STX HDLEN STX NEEDASC STX UNDERLINE STX LINEFEED Copy definition tables and default printercodes. COPYDEF LDA DEFTAB,X STA LMARGIN,X INX CPX #12 BNE COPYDEF LDA #$FF STA LINE STA NOMARG LDX #4 COPYDEFS LDA PRCODES-1,X STA CODEBUFFER+16,X DEX BNE COPYDEFS Reentry point for printing after linked files. RETEX LDA TEXSTART STA TEX LDA TEXSTART+1 STA TEX+1 Main printing loop. We print the left margin, grab a line of text, scan backward until we find a space or a carriage return, then break the line there. If printer codes are encountered, they're passed on to the SPECIAL routine. Otherwise, we end up calling BUFPRT to print the line and process some other control codes. PLOOP LDY #0 STY POS CPY NOMARG BEQ PLOOP1 LDA LMARGIN STA POS PLOOP1 LDA (TEX),Y BPL NOTSP JMP SPECIAL NOTSP CMP #RETCHAR BEQ FOUNDSPACE NOTRET STA PRBUFF,Y INY INC POS LDA POS CMP RMARGIN BCC PLOOP1 STY FINPOS FINDSPACE LDA (TEX),Y CMP #SPACE BEQ FOUNDSPACE DEC POS DEY BNE FINDSPACE LDY FINPOS FSPACE INY LDA (TEX),Y CMP #SPACE BEQ FOUNDSPACE DEY FOUNDSPACE STY FINPOS OVERSTOR TYA SEC ADC TEX STA TEX LDA TEX+1 ADC #0 STA TEX+1 LDY #0 If this is the first page, we need to print the header, if any, with JSR TOP. DOBUFF LDA LINE CMP #$FF BNE DOBUF2 JSR TOP DOBUF2 LDA NOMARG BEQ OVERMARG JSR LMARG OVERMARG SEC ROL NOMARG LDA FINPOS STA ENDPOS LDA # <PRBUFF STA INDIR LDA # >PRBUFF STA INDIR+1 JSR BUFPRT A line has been printed. We check to see if we've hit the bottom margin and, if so, go to PAGE, which goes to the end of the page, prints the footer (if any), and feeds to the next page. ZBUFF JSR CRLF LDA LINE CMP BOTMARG BCC NOTPAGE JSR PAGE Have we reached the end-of-text? NOTPAGE SEC LDA TEX SBC LASTLINE STA TEMP LDA TEX+1 SBC LASTLINE+1 ORA TEMP BEQ DORPT BCC DORPT If so, we check for a footer. If there is one, we set HDLEN and TOPMARG to 0 (so that the printhead will end up at the right place on the last page) and call PAGE, which prints the footer. If there is no footer, we leave the printhead on the same page so that paper isn't wasted. LDA FTLEN BEQ PXIT LDA #0 STA HDLEN STA TOPMARG JSR PAGE Exit routines. If screen output was selected, we wait for a keystroke before going back to editing mode. PXIT LDA INBUFF CMP #'E BNE PEXIT LDA #155 JSR CHROUT LDA # <DIRMSG LDY # >DIRMSG JSR PRMSG JSR GETAKEY PEXIT JSR CLOSE7 LDX #$FA TXS JSR HIGHLIGHT LDA #125 JSR CHROUT JSR SYSMSG JMP MAIN DORPT JMP PLOOP Paging routines. We skip (PAGELENGTH - LINE) -- two blank lines to get to the bottom of the page, print a footer (if there is one) or a blank line (if not), then page to the beginning of the next page, skipping over the paper perforation. If the wait mode is enabled, we wait for the user to insert a new sheet of paper. PAGE SEC LDA PAGELENGTH SBC LINE TAY DEY DEY BEQ NOSK BMI NOSK NEXPAGE JSR CR DEY BNE NEXPAGE NOSK LDA FTLEN BEQ SKIPFT STA ENDPOS LDA # <FTBUFF STA INDIR LDA # >FTBUFF STA INDIR+1 JSR LMARG JSR BUFPRT SKIPFT JSR CR JSR CR JSR CR Increment the page number. INC PAGENUM BNE NOIPN INC PAGENUM+1 The page wait mode is inappropriate when printing to the screen or to disk, or when skipping over pages with the ? format command. NOIPN LDA CONTINUOUS BNE TOP SEC LDA PAGENUM SBC STARTNUM LDA PAGENUM+1 SBC STARTNUM+1 BCC TOP JSR TOPCLR LDA # <WAITMSG LDY # >WAITMSG JSR PRMSG JSR GETAKEY JSR PRIN Print the header; skip to the top margin. TOP LDA HDLEN BEQ NOHEADER STA ENDPOS LDA # <HDBUFF STA INDIR LDA # >HDBUFF STA INDIR+1 JSR LMARG JSR BUFPRT NOHEADER LDY TOPMARG STY LINE DEY BEQ SKIPTOP BMI SKIPTOP TOPLP JSR CR DEY BNE TOPLP SKIPTOP RTS Left margin routine. This routine is not called if NOMARG is selected (margin release). LMARG LDA #32 LDY LMARGIN STY POS BEQ LMEXIT LMLOOP JSR PCHROUT DEY BNE LMLOOP LMEXIT RTS CRLF is called at the end of most printed lines. It increments the LINE count and takes into account the current line spacing mode set by the a format command. CRLF LDY SPACING CLC TYA ADC LINE STA LINE CRLOOP JSR CR DEY BNE CRLOOP RTS CR just prints a single carriage return and linefeed (if specified). CR LDA #155 JSR PCHROUT LDA LINEFEED BEQ NOLF JSR PCHROUT NOLF RTS Handle special printer codes like left margin. This looks up the printer code using a routine similar to CONTROL. SPECIAL STA SAVCHAR AND #127 JSR INTOAS LDX SPTAB SRCHSP CMP SPTAB,X BEQ FSP DEX BNE SRCHSP DEC POS JMP DEFINE FSP DEX TXA ASL A TAX STY YSAVE LDA # >SPCONT-1 PHA LDA # <SPCONT-1 PHA LDA SPVECT+1,X PHA LDA SPVECT,X PHA RTS After the format code is processed, we must skip over the format command and its parameter so that it's not printed. SPCONT SEC LDA YSAVE ADC TEX STA TEX LDA TEX+1 ADC #0 STA TEX+1 JMP PLOOP If the format command ends with a return-mark, we must skip over the return-mark as well. SPCEXIT LDA (TEX),Y CMP #RETCHAR BEQ NOAD DEY NOAD STY YSAVE RTS Special format code table. It starts with the number of format commands, then the characters for each format command. SPTAB .BYTE 17 .BYTE "wlrtbsnhf@p?xmigj" The address-1 of each format routine. SPVECT .WORD PW-1,LM-1,RM-1,TP-1 .WORD BT-1,SP-1,NX-1,HD-1,FT-1 .WORD PN-1,PL-1,SPAGE-1,ACROSS-1 .WORD MRELEASE-1,COMMENT-1,LINK-1 .WORD LFSET-1 m Margin release. INY is used to skip over the format character. MRELEASE INY LDA #0 STA NOMARG JMP SPCEXIT x Columns across, used by centering. ACROSS INY JSR ASCHEX STA PAGEWIDTH JMP SPCEXIT ? Start printing at specified page. SPAGE INY JSR ASCHEX STA STARTNUM LDA HEX+1 STA STARTNUM+1 JMP SPCEXIT @ Set starting default page number. PN INY JSR ASCHEX STA PAGENUM LDA HEX+1 STA PAGENUM+1 JMP SPCEXIT p Page length. PL INY JSR ASCHEX STA PAGELENGTH JMP SPCEXIT w Set page wait mode. PW LDA #0 STA CONTINUOUS INY JMP SPCEXIT j Set linefeed mode. LFSET LDA #10 STA LINEFEED INY JMP SPCEXIT l Left margin. LM INY JSR ASCHEX STA LMARGIN JMP SPCEXIT r Right margin. RM INY JSR ASCHEX STA RMARGIN JMP SPCEXIT t Top margin. TP INY JSR ASCHEX STA TOPMARG JMP SPCEXIT b Bottom margin. BT INY JSR ASCHEX STA BOTMARG JMP SPCEXIT s Set line spacing. SP INY JSR ASCHEX STA SPACING JMP SPCEXIT n Jump to next page. NX LDY YSAVE INY TYA PHA JSR PAGE PLA TAY STY YSAVE RTS h Define header. Copy header into header buffer. HD JSR PASTRET DEY STY HDLEN LDY #1 HDCOPY LDA (TEX),Y STA HDBUFF-1,Y INY CPY HDLEN BCC HDCOPY BEQ HDCOPY INY JMP SPCEXIT Skip just past the return-mark. PASTRET INY LDA (TEX),Y CMP #RETCHAR BNE PASTRET RTS f Define footer. FT JSR PASTRET DEY STY FTLEN LDY #1 FTCOPY LDA (TEX),Y STA FTBUFF-1,Y INY CPY FTLEN BCC FTCOPY BEQ FTCOPY JMP SPCEXIT i Ignore a line of information. COMMENT JSR PASTRET JMP SPCEXIT Define programmable printkeys. We check for =. If not found, this is not an assignment, so we just skip past the code. Otherwise, we use the screen code value as the index into the CODEBUFFER and put the value there, ready to be called during printing by BUFPRT. DEFINE INY LDA (TEX),Y CMP #'=-32 BEQ DODEFINE DEY LDA SAVCHAR JMP NOTRET DODEFINE INY JSR ASCHEX PHA LDA SAVCHAR AND #127 TAX PLA STA CODEBUFFER,X JSR SPCEXIT JMP SPCONT g Link to next file. We get the filename from text and put it into the input buffer, just as if the filename were typed in with INPUT. We then jump into the TOPEN routine to open the file, and into the Load routine to load the file. After the load, we check for a load error, then jump to RETEX to continue printing. LINK LDY #1 LDX #0 FNCOPY LDA (TEX),Y CMP #RETCHAR BEQ FNEND JSR INTOAS STA INBUFF,X INY INX CPX #14 BNE FNCOPY FNEND STX INLEN LDA #0 STA INBUFF,X LDX #$60 STX IOCB LDA #4 STA ACCESS JSR OPCONT BPL LNOERR JMP ERRLINK LNOERR LDA #0 STA INDIR STA INDIR+1 JSR ERASE JSR LOADLINK BPL LCONT JMP ERRLINK LCONT PLA PLA LDX #$70 STA IOCB JMP RETEX Global search and replace. This just links together the search-specify routine, the replace-specify routine, then repeatedly calls Hunt and Replace, until Hunt returns "Not Found." (FPOS+1 is $FF after a search failure.) SANDR JSR RESET LDA HUNTLEN BEQ NOSR JSR ASKREP SNR JSR CONTSRCH LDA FPOS+1 CMP #$FF BEQ NOSR JSR REPL JSR REFRESH JMP SNR NOSR JMP SYSMSG If OPTION is held down with CTRL-F, we ask for and store the search phrase. If OPTION is not down, we perform the actual search. The line in the INBUFF is compared with characters in text. If at any point the search fails, we continue the comparison with the first character of INBUFF. The search is a failure if we reach the end-of-text. If the entire length of INBUFF matches, the search succeeds, so we change the CURRent cursor position to the found position, save the found position for the sake of the replace routine, then call CHECK to scroll to the found position. HUNT LDA #8 STA 53279 LDA 53279 CMP #3 BNE CONTSRCH RESET JSR TOPCLR LDA # <SRCHMSG LDY # >SRCHMSG JSR PRMSG JSR INPUT STA HUNTLEN BNE OKSRCH JMP SYSMSG OKSRCH LDY #0 TOBUFF LDA INBUFF,Y STA HUNTBUFF,Y INY CPY INLEN BNE TOBUFF JMP SYSMSG CONTSRCH LDA CURR STA TEX LDA CURR+1 STA TEX+1 LDA #$FF STA FPOS+1 LDY #1 SRCH0 LDX #0 LDA HUNTLEN BEQ NOTFOUND SRCH1 LDA HUNTBUFF,X JSR ASTOIN CMP (TEX),Y BEQ CY CPX #0 BNE SRCH0 DEX CY INY BNE NOVFL INC TEX+1 LDA TEX+1 CMP LASTLINE+1 BEQ NOVFL BCS NOTFOUND NOVFL INX CPX HUNTLEN BNE SRCH1 CLC TYA ADC TEX STA TEMP LDA TEX+1 ADC #0 STA TEMP+1 LDA LASTLINE CMP TEMP LDA LASTLINE+1 SBC TEMP+1 BCC NOTFOUND SEC LDA TEMP SBC HUNTLEN STA CURR STA FPOS LDA TEMP+1 SBC #0 STA CURR+1 STA FPOS+1 JSR CHECK RTS NOTFOUND JSR TOPCLR LDA # <NFMSG LDY # >NFMSG JSR PRMSG LDA #1 STA MSGFLG RTS The change (replace) routine checks to see if OPTION is held down with CTRL-C. If it is, we ask for a replace phrase, and exit. If not, we check to see if the cursor is at the position previously located by the search routine. If it is, we delete the found phrase, then insert the replace phrase. The cursor is moved past the replace phrase for the sake of the next search. This also prevents endless recursion, as in replacing in with winner. REPSTART LDA #8 STA 53279 LDA 53279 CMP #3 BNE REPL ASKREP JSR TOPCLR LDA # <REPMSG LDY # >REPMSG JSR PRMSG JSR INPUT STA REPLEN BEQ NOREP LDY #0 REPMOV LDA INBUFF,Y STA REPBUFF,Y INY CPY INLEN BNE REPMOV NOREP JMP SYSMSG REPL SEC LDA CURR STA DESTL SBC FPOS STA TEMP LDA CURR+1 STA DESTH SBC FPOS+1 ORA TEMP BNE NOREPL LDA #$FF STA FPOS+1 CLC LDA HUNTLEN ADC CURR STA FROML LDA #0 ADC CURR+1 STA FROMH SEC LDA LASTLINE SBC DESTL STA LLEN LDA LASTLINE+1 SBC DESTH STA HLEN JSR UMOVE SEC LDA LASTLINE SBC HUNTLEN STA LASTLINE LDA LASTLINE+1 SBC #0 STA LASTLINE+1 LDA REPLEN BEQ NOREPL STA INSLEN LDA #0 STA INSLEN+1 JSR INSBLOCK LDY #0 REPLOOP LDA REPBUFF,Y JSR ASTOIN STA (CURR),Y INY CPY REPLEN BNE REPLOOP CLC LDA CURR ADC REPLEN STA CURR LDA CURR+1 ADC #0 STA CURR+1 NOREPL JMP CHECK Suddenly, we're back to a PRINT subroutine. This examines the buffer as it's being printed, checking for printkeys and Stage 2 commands like centering. BUFPRT LDY #0 BUFLP CPY ENDPOS BEQ ENDBUFF LDA (INDIR),Y BMI SPEC2 JSR INTOAS JSR PCHROUT In underline mode, after we print the character, we backspace the printhead and print an underline character. LDA UNDERLINE BEQ NOBRK LDA #8 JSR PCHROUT LDA #95 JSR PCHROUT NOBRK INY JMP BUFLP ENDBUFF RTS Stage 2 format commands. SPEC2 STY YSAVE AND #127 STA SAVCHAR JSR INTOAS OTHER CMP #'c BNE NOTCENTER c Centering looks at the length of the line, then sends out extra spaces (the left margin has already been printed) to move the printhead to the right place. SEC LDA PAGEWIDTH SBC ENDPOS LSR A SEC SBC LMARGIN TAY LDA #32 CLOOP JSR PCHROUT DEY BNE CLOOP LDY YSAVE JMP NOBRK NOTCENTER CMP #'e BNE NOTEDGE e Edge right. This subtracts the length of the line from the right margin position and moves the printhead to this position. EDGE SEC LDA RMARGIN SBC ENDPOS SEC SBC LMARGIN TAY LDA #32 JMP CLOOP NOTEDGE CMP #'u BNE NOTOG u Toggle underline mode. L LDA UNDERLINE EOR #1 STA UNDERLINE NOTOG CMP #'# BNE DOCODES # Substitute the current page number for the # symbol. DOPGN STY YSAVE LDX PAGENUM LDA PAGENUM+1 JSR PROUTNUM LDY YSAVE JMP NOBRK Do special format codes. This just uses the screen-code value of the character as an index into the CODEBUFFER, then sends out the code. SpeedScript makes no judgment on the code being sent out. DOCODES LDX SAVCHAR LDA CODEBUFFER,X JSR PCHROUT JMP NOBRK Display free memory using OUTNUM. FREEMEM JSR TOPCLR SEC LDA TEXEND SBC LASTLINE TAX LDA TEXEND+1 SBC LASTLINE+1 JSR OUTNUM LDA #1 STA MSGFLG RTS .ENDFilename: DATA
Data tables Messages are stored in ATASCII, with a zero byte for a delimiter. MSG1 .BYTE "SpeedScript 3.0" .BYTE 0 MSG2 .BYTE " by Charles Brannon" .BYTE 0 KILLMSG .BYTE "Buffer Cleared" .BYTE 0 BUFERR .BYTE "Buffer Full" .BYTE 0 DELMSG .BYTE "Delete (S,W,P)" .BYTE 0 YMSG .BYTE ": Are you sure? (Y/N):" .BYTE 0 CLRMSG .BYTE "ERASE ALL TEXT" .BYTE 0 ERASMSG .BYTE "Erase (S,W,P): {inv}RETURN{inv} to exit" .BYTE 0 SAVMSG .BYTE "Save (Device:Filename)>" .BYTE 0 ERRMSG .BYTE "Error #" .BYTE 0 BRMSG .BYTE "BREAK Key Abort" .BYTE 0 OKMSG .BYTE "No Errors" .BYTE 0 LOADMSG .BYTE "Load (Device:Filename)>" .BYTE 0 DIRMSG .BYTE " Press {inv}RETURN{inv}" .BYTE 0 DIRNAME .BYTE "D1:*.*" INSERR .BYTE "Memory Full" .BYTE 0 INSMSG .BYTE "No text in buffer" .BYTE 0 FNMSG .BYTE "Print (Device:Filename)>" .BYTE 0 PRINMSG .BYTE "Printing..." .BYTE 155,155,0 WAITMSG .BYTE "Insert next sheet, press {inv}RETURN{inv}" .BYTE 0 SRCHMSG .BYTE "Find:" .BYTE 0 NFMSG .BYTE "Not found" .BYTE 0 REPMSG .BYTE "Change to:" .BYTE 0 The {ESC}'s represent the ESCape key. The arrows are the cursor keys, which must be preceded by ESC to be entered into text. There is actually only one space between the e of Rename and the E of ESC. DIRINS .BYTE "{ESC}{up}{ESC}{down}{ESC}{left} {ESC}{right} {inv}CTRL-D{inv}elete {inv}L{inv}ock {inv}U{inv}nlock {inv}R{inv}ename {inv}ESC{inv} {inv}CTRL-L{inv}oad Drive [ {inv}1{inv} {inv}2{inv} {inv}3{inv} {inv}4{inv} ]: ",0 RENMSG .BYTE "Rename to:",0 FORMSG .BYTE "Format disk",0 The .OPT NO OBJ and .OPT OBJ pseudo-ops turn on and off object code generation. This insures that no object code is generated for the variable table. .OPT NO OBJ TEXSTART *= *+2 ; Start-of-text area TEXEND *= *+2 ; End-of-text area TEXBUF *= *+2 ; Start of buffer BUFEND *= *+2 ; End-of-buffer area LENTABLE *= *+1 ; Length of first screen line TOPLIN *= *+2 ; Home position in text MSGFLG *= *+1 ; Messageflag INSMODE *= *+1 ; Insertmode ENDPOS *= *+1 ; Used by delete routines FINPOS *= *+1 ; " LASTLINE *= *+2 ; End-of-text position LIMIT *= *+1 ; Used by INPUT INLEN *= *+1 ; " BOTSCR *= *+2 ; Bottom of screen in text LBUFF *= *+40 ; Linebuffer (REFRESH) INBUFF *= *+40 ; INPUT buffer SAVCURR *= *+2 ; Used by delete routines BCD *= *+2 ; Usedby ASCHEX HEX *= *+2 ; " TPTR *= *+2 ; Last character in buffer BUFLEN *= *+2 ; Buffer length GOBLEN *= *+2 ; Size of deleted text FROMSAV *= *+2 ; Used by delete routines DESTSAV *= *+2 ; " HDLEN *= *+1 ; Header length FTLEN *= *+1 ; Footer length LMARGIN *= *+1 ; Holds left margin RMARGIN *= *+1 ; Right margin PAGELENGTH *= *+1 ; Pagelength TOPMARG *= *+1 ; Topmargin BOTMARG *= *+1 ; Bottom margin SPACING *= *+1 ; Linespacing CONTINUOUS *= *+1 ; Pagewait mode PAGENUM *= *+2 ; Page number STARTNUM *= *+2 ; Start printing at # PAGEWIDTH *= *+1 ; Columns across NOMARG *= *+1 ; Margin release flag POS *= *+1 ; POSition within line LINE *= *+1 ; Linecount YSAVE *= *+1 ; Preserves Y register SAVCHAR *= *+1 ; Preserves accumulator INSLEN *= *+1 ; Length of an insertion DEVNO *= *+1 ; Device number NEEDASC *= *+1 ; True ASCII flag UNDERLINE *= *+1 ; Underline mode flag FPOS *= *+2 ; Found position PCR *= *+1 ; Usedby PCHROUT HUNTLEN *= *+1 ; Length of hunt phrase HUNTBUFF *= *+30 ; Holds hunt phrase REPLEN *= *+1 ; Length of replacephrase REPBUFF *= *+30 ; Holds replace phrase CODEBUFFER *= *+128 ; Holds definable printkeys PRBUFF *= *+256 ; Printer line buffer HDBUFF *= *+256 ; Holds header FIRSTRUN *= *+1 ; Has program been run before? FTBUFF *= *+256 ; Holds footer SAVCOL *= *+1 ; Save SCRCOL LINEFEED *= *+1 ; Linefeed mode flag ESCFLAG *= *+1 ; Was ESC pressed? CONVFLAG *= *+1 ; Used by CAST and CINTOAS SELFLAG *= *+1 ; The SELECT key flag IOCB *= *+1 ; Which IOCB is OPEN ACCESS *= *+1 ; Direction of ACCESS (read/write) FNBUFF *= *+40 ; Filename buffer FNLEN *= *+1 ; Filename Length XSLOT *= *+1 ; Number of filename slots (DOSPAK) SLOT *= *+130 ; Slot positions (DOSPAK) XPTR *= *+1 ; Current filename slot (DOSPAK) WHICHFLAG *= *+1 ; Which key is pressed DIRCOUNT *= *+1 ; Directory count BLINK *= *+1 ; Cursor blink flag LINELEN *= *+1 ; Length of screen lines RLM *= *+1 ; REFRESH Left margin value KEYVAL *= *+1 ; Which key is pressed END = * ; High byte of this +$100 is TEXSTART .OPT OBJ Autorun vector *= $02E2 .WORD BEGIN .END
Label Cross Reference. This chart makes it easier to find your place in the object code while looking at the source code. The number to the left of each label is its value or position within the object code. Labels preceded by an = mark are equates. Others are internal labels for object code positions.
43BA ACCESS 3A2E ACROSS 294B ADYCURR 3721 ALPHA 3614 ASCHEX 3C3C ASKREP 262C ASTOIN 3FCD BCD 1FOO BEGIN 446A BLINK 3029 BLIP = 0074 BLUE 2983 BORDER 33AA BOTCLR 3FEI BOTMARG 3F79 BOTSCR 24D3 BREAK 3E3A BRMSG 3A92 BT 3F6C BUFEND 3DBB BUFERR 3FD3 BUFLEN 3CDE BUFLP 3CDC BUFPRT 33FF CAST 340C CAST1 3419 CASTOIN 3100 CATALOG 27CF CHECK 282D CHECK2 2F7F CHROUT 2FCB CHRYSAVE 3426 CIN 3407 CINTOAS = E456 CIO 284C CK3 2D02 CLEAR 2501 CLEARED 28E2 CLEFT 3DIF CLOOP 3184 CLOSE7 254C CLR2 24F4 CLRLN 2543 CLRLOOP 3DED CLRMSG 4033 CODEBUFFER 3AFO COMMENT 3FE3 CONTINUOUS 2732 CONTROL 3BB7 CONTSRCH 43B7 CONVELAG 24D7 COPY 3296 COPYD 37EC COPYDEF 3801 COPYDEFS 32A3 COPYNAME 3332 COPYR 3446 COTHER 3998 CR 2SAF CRIGHT 3986 CRLF 3991 CRLOOP 2753 CTBL = 0086 CURR 2EE7 CURSIN 3430 CVLOOP 3BDC CY 3282 DDOWN 3654 DECHEX 3AF6 DEFINE 3752 DEFTAB 2A6C DELI 2A80 DELlA 2A89 DEL2 2A7D DELABORT 2AAO DELC 2B32 DELCHAR 2B5C DELETE 32E5 DELFILE 2B4D DELIN 35FF DELITE 3DC7 DELMSG 288A DELSENT 2B7D DELWORD = 0083 DESTH = 0082 DESTL 3FD9 DESTSAV 3FEF DFVNO 3622 DIGIT 4469 DIRCOUNT 3F00 DIRINS 3156 DIRLOOP 3E6C DIRMSG 3E7A DIRNAME 25E9 DISKBOOT 3247 DLEFT 2EOA DLI 2DEE DUST 2DC8 DLOOP 2474 DMOVI 244D DMOVE 2476 DMOVLOOP 3170 DNOT8 315B DNOTCR 3873 DOBUF2 3869 DOBUFF 3D62 DOCODIIS 3B04 DODEFINE 26F4 DOINS 2D25 DOLT 3678 DONENUM 3D50 DOPGN 38EB DORPT 3IBB DOS 3229 DOSADR 33B6 DOSERR 33FF DOSMSG 3219 DOSTABLE 3254 DRIGHT 336F DRIVE 3271 DUP 2BD9 EATSPACE 3D2F EDGE 2F99 ENAME = 446E END 31300 ENDBUFF 3194 ENDIR 319E ENDLP 3F73 ENDPOS 2967 ENDTEX 2814 EQA 2E97 ERAI 2EA6 ERA2 2E33 ERAS 2E42 ERAS1 2E4C ERASAGAIN 251F ERASE 2E7B ERASENT 3DFC ERASMSG 2E6E ERASWORD 34A7 ERR1 379B ERRLINK 3E32 ERRMSG 34AE ERROR 34C7 ERXIT 27BD ESC 3399 ESCDOS 43B6 ESCFLAG 2F2E ESCKEY 2C75 FILLSP 3201 FINDIT 3841 FINDSPACE 35E8 FINE 3F74 FINPOS 4283 FLRSTRUN 29F4 FIRSTWORD 2B3B FIXTP 2687 FLIPIT 43BB FNBUFF 3B1D FNCOPY 3B2F FNEND 43E3 FNLEN 3E9E FNMSG 3355 FORMAT 3F5A FORMSG 2740 FOUND 320C FOUNDIT 3858 FOUNDSPACE 3FF2 FPOS 3D6E FREEMEM = 0081 FROMH 0080 FROML 3FD7 FROMSAV 39BF FSP 3850 FSPACE 3AD7 FT 42B4 FTBUFF 3AEO FTCOPY 3FDC FTLEN 31A9 GET7 256F GETAKEY 2FD6 GETCHAR 2FCC GETIN 31D6 GETNAME 2D4F GOADY 3FD5 GOBLEN 3565 GOERROR 2C06 GOINC 2FC1 GOPCHR 2AD4 GOSAV 32EA GOXIO 3001 GXIT 3AB5 HD 4183 HDBUFF 3ABE HDCOPY 3FDB HDLEN 3FCF HEX 2DAD HIGHLIGHT = 0085 HLEN 2BAI HOME 2BC3 HOMEPAUSE 3B85 HUNT 3FF6 HUNTBUFF 3FF5 HUNTLEN = 034A ICAUX1 = 034B ICAUX2 = 0344 ICBADR = 0348 ICBLEN = 0342 ICCOM = 0343 ICSTAT 3FA3 INBUFF 250C INCNOT 3744 INCONT = 008E INDIR 2F4D INEXIT 2589 INIT 25EA INIT2 2726 INKURR 3F78 INLEN 2CEI INOUT 2ED5 INP1 2ECE INPUT 2868 INRANGE 2C92 INSBLOCK 367D INSBUFFER 2C7C INSCHAR 3E80 INSERR 3FEE INSLEN 3F72 INSMODE 3E8C INSMSG 2CE2 INSTGL 374D INTl 3738 INTOAS 33E5 INVLP 33E3 INVNAME 3B9 IOCB 34E0 IOCLOSE 2575 JDOS 357B JFINE 32F2 JNAME 3040 KEYBOARD 2694 KEYPRESS 446D KEYVAL 2A50 KILLBUFF 3DAC KILLMSG 3F75 LASTLINE 295A LAST WORD 3F7B LBUFF 3B5A LCONT 28B8 LEFT 3F6E LENTABLE 298B LETTERS 3A68 LFSET 3F77 LIMIT 3FEB LINE 43B5 LINEFEED 446B LINELEN 3B19 LINK = 0084 LLEN 3A74 LM 3975 LMARG 3FDD LMARGIN 3985 LMEXIT 397F LMLOOP 3B49 LNOERR 3554 LOAD2 3377 LOADIT 357E LOADLINK 3E54 LOADMSG 32F8 LOCK 2C4C LOTTASPACE 2645 LOWR 2648 MAIN 2651 MAIN2 2428 MOV1 242A MOV2 242F MOVLOOP 3A25 MRELEASE 3D88 MSG1 3D98 MSG2 3F71 MSGFLG 31E5 NAMELP 3294 NAMER 3FFO NEEDASC 38FC NEXPAGE 3EEB NFMSG 39ED NOAD 2F1B NOBACK 28AC NOBIGGER 2583 NOBLINK 3CFC NOBRK 28E8 NODEC 3571 NOER 2F04 NOESC 2A37 NOFIXCURR 35E2 NOGARBAGE 3963 NOHEADER 3675 NOHEXINC 272C NOINC2 28B5 NOINCR 2C63 NOINCY 3929 NOIPN 39A5 NOLF 3FE9 NOMARG 26B8 NOMSG 334F NONAME 3653 NONUM 2E91 NOPAR 31FF NOPROB 3C5C NOREP 3CD9 NOREPL 3902 NOSK 3B82 NOSR 32B2 NOSTOR 3735 NOTALPHA 26AC NOTBKS 300F NOTCAPS 3D2B NOTCENTER 26C2 NOTCR 2642 NOTCTRL 32BF NOTDOT 3D40 NOTEDGE 3C20 NOTFOUND 26F7 NOTINST 3024 NOTLOCKED 2455 NOTNULL 3D4C NOTOG 389E NOTPAGE 2BAO NOTPAR 344F NOTRC 382F NOTRET 3440 NOTRTN 26A6 NOTSEL 2B93 NOTSENT 3004 NOTSET 382B NOTSP 2B86 NOTWORD 2F13 NOTZERO 3BEA NOVFL 2E77 NOWORD 326E NRANGE 3AA6 NX 24C7 NXCUR 2941 OIDS 27FF OK1 282C OK2 36A5 OKBUFF 2DOF OKCLEAR 2CA9 OKINS 3568 OKLOD 36DF OKMOV 3E4A OKMSG 3BA6 OKSRCH 27C6 ONOFF 2FCA ONUMEXIT 2FBI ONUMLOOP 3508 OPABORT 3510 OPCONT 2F59 OPENEDITOR 3DOC OTHER 244C OUT 2BC9 OUTHOME 2FAO OUTNUM 287A OUTRANGE 2COB OUTSPACE 26E2 OVERCTRL 387B OVERMARG 3452 OVEROTHER 2FC4 OVERPCHR 385B OVERSTOR 2FA2 OVERZAP 38EE PAGE 3FDF PAGELENGTH 3FE4 PAGENUM 3FE8 PAGEWIDTH 2D64 PARCONT 2D31 PARIGHT 2D52 PARLEFT 2D5E PARLOOP 2D33 PARLP 3ACF PASTRET 37BB PBORT 3762 PCHROUT 3FF4 PCR 2514 PDONE 38D7 PEXIT 3A58 PL 24B1 PLINE 3814 PLOOP 3824 PLOOPI 29A7 PMANY 3A48 PN 3FEA POS 24AF PPAGE 40B3 PRBUFF 375E ERCODES 256E PREXIT 37B1 PRIN 3EB7 PRINMSG 37BE PRINT 2564 PRLOOP 2559 PRMSG 37D5 PROK 35F0 PROKMSG 2F9B PROUTNUM 29BD PSLOOP 29B9 PSRCH 29DE PUNCT 2A26 PUNCT2 3A62 PW 38C1 PXIT = 0032 RED 312D REDIR 2826 REF 248B REFRESH 3308 RENAME 3F4F RENMSG 4015 REPBUFF 29EF REPEAT 3C5F REPL 4014 REPLEN 3USD REPLOOP 3C50 REPMOV 3EF5 REPMSG 3C30 REPSTART 3B91 RESET 3261 RESLOT = 005E RETCHAR 380A RETEX 2D75 RETF2 2D4A RETFOUND 2885 RIGHT 446C RLM 2925 RLOOP 3A7E RM 3FDE RMARGIN 2933 ROUT 297A SAFE 3B64 SANDR 3FED SAVCHAR 43B4 SAVCOL 3FCB SAVCURR 3E1A SAVMSG 24D2 SBRK = 0088 SCR 298A SCRCOL 43B8 SELFLAG = O2BE SHFLOK 37A4 SHIFTFREEZE 2481 SKIPDMOV 1F34 SKIPERAS 3918 SKIPFT 2448 SKIPMOV 37A9 SKIPOUT 2F3E SKIPSEL 29E2 SKIPSPC 3974 SKIPTOP 299B SLEFT 24C3 SLOOP 43E5 SLOT 3036 SLOW 3031 SNDLOOP 3B6F SNR 3A9C SP = 0000 SPACE 3FE2 SPACING 3A38 SPACE 39E6 SPCEXIT 39D5 SPCONT 2BE7 SPCSRCH 3D01 SPEC2 39A6 SPECIAL 39F1 SPTAB 3A03 SPVECT 2735 SRCH 3BC6 SRCHO 3BCD SRCH1 3EE5 SRCHMSG 39B1 SRCHSP 2A23 SREXIT 2A01 SRIGHT 2A03 SRLP 3FE6 STARTNUM 34D3 STOPPED 28F9 STRIP 2903 STRLOOP 37B1 SWITCH 260A SYSMSG 2C54 TAB 2C66 TAB2 = 008C TEMP = 008A TEX 3F6A TEXBUF 299A TEXCOLR 3F68 TEXEND 35AB TEXOK 3F66 TEXSTART 2DA2 TEXTOCURR 3178 THROWS 3539 TLOAD 3BA8 TOBUFF 28DF TOOSMALL 394D TOP 261A TOPCLR 34EB TOPEN 2BCC TOPHOME 3F6F TOPLIN 261E TOPLOOP 396E TOPLP 3FEO TOPMARG 3A88 TP 3FD1 TPTR 345D TSAVE 2410 UMOVE = 0090 UNDERCURS 3FF1 UNDERLINE 3300 UNLOCK 2E84 UNSENT 2777 VECT 2667 WAIT 3EC5 WAITMSG 2BBC WAITST 4468 WHICHFLAG = 0091 WINDCOLR 28ED WLEFT 2906 WLOOP 2923 WRIGHT 2914 WROUT 2957 WRTN 374F XINT 32C8 XIO 4467 XPTR 43E4 XSLOT 3DD6 YMSG 2CEB YORN 2CF2 YORNKEY 3FEC YSAVE 3890 ZBUFF
Return to Table of Contents | Previous Chapter