Volume 1 -- Issue 2 | November 1980

Our second issue is 33% larger than the first! And not only so, but also there is useful information on the back page! I found a source for 6x9 white envelopes, so your address can be external to the newsletter, and so your copy will arrive in better condition. In less than a month since the newsletter was first announced, we already have over 45 paid subscribers. They are sprinkled all over the map, including one in Japan!

In This Issue...

- A Bug in S-C Assembler II Version 4.0
- Variable Cross Reference for Applesoft Programs
- Bags, Boxes, et cetera
- Assembly Source on Text Files
- A Use for the USR Command
- A Simulated Numeric Key-Pad

A Bug in S-C Assembler II Disk Version 4.0

One real bug has turned up, and a few of you have had the bad luck to discover it the hard way. The assembler is free-format, in that opcodes and directives may start in any column after the blank which terminates the label field. However, the ".IN" directive will malfunction unless there are at least six spaces. If you tab over before typing ".IN" there will be no problem. However, if you type your line like "1230 .IN FILE1", with only two spaces between the line number and the period, you are in for a long wait. The processor goes into a loop printing D's. If you have the MONC mode on, you will see "LOADDDDDDDDD....." with D's forever appearing on your screen. Remember to TAB OVER, and it will not malfunction.

One fancied bug has been reported, and I would like to explain it. A user pointed out that you cannont shorten the SAVE command to three letters if you wish to save the source program on a disk file. Why? Because "SAVE" or "SAV" with no file name is not a DOS command. It is an assembler command to save the source program on cassette tape! On the other hand, SAVE with a filename is not an assembler command. It is a DOS command, and the assembler never sees it. The same goes for "LOAD", "LOA", and LOAD with a filename.

Variable Cross Reference for Applesoft Programs | Bob Sander-Cederlof

Besides illustrating a lot of programming techniques, the VCR program is a very useful tool when you are writing large Applesoft programs. As listed here, it requires a 48K Apple, and assumes that HIMEM is set to at least $8AA7. You BRUN it, and it sets up the &-vector. When you are ready to print a cross reference, you merely type "&" and a carriage return, and out it comes. It is VERY fast: about 15 times faster than the VCR program included in Apple's DOS Tool Kit. It also takes less memory than Apple's version, both for the program itself and for the tables it constructs during execution.

The main body of the program is in lines 1400 thru 1460. After calling INITIALIZATION, the subroutine PROCESS.LINE is called until there are no more lines. Then PRINT.REPORT is called, and finally INITIALIZATION is called again to restore Applesoft's tables to their original form.

INITIALIZATION sets up PNTR to point to the beginning of the program, and EOT to point to the end of the table area. It also clears out a set of 26 two-byte pointers in HSHTBL (hash table). PROCESS.ONE scans a single line looking for variables by calling SCAN.FOR.VARIABLES, until the end of the program is reached. PRINT.REPORT merely prints a nice orderly report from the data which has been stored in the table by SCAN.FOR.VARIABLES.

The symbol table routines used in VCR are very similar to the ones used inside S-C Assembler II Version 4.0. There are 26 pointers starting at HSHTBL ($280), each one representing one letter of the alphabet. The first letter of a variable name selects one of these pointers. The pointer points at the first entry in a chain of variable names. When a new variable name is found, it is inserted in the appropriate chain at the place where it will be in alphabetical order. A sub-chain is kept for each variable name of all the line numbers from which it is referenced. The line number chain is maintained in numerical order. Thus there is no sorting necessary when it comes time to print the report.

Since no routines from the Applesoft ROMs are used, VCR will work with no changes with the RAM version of Aplesoft. Since it loads below $9000, it will not conflict with Neil Konzen's PLE (Program Line Editor). Since it is just straight-forward code, with no address tables or embedded data, you can easily relocate it to a different running address; only the 3-byte instructions with the third byte equal to $88, $89, or $8A need to be changed. Or, you can type it in, and use a different origin (line 1040).

If you like to modify programs, this one needs one improvement. (Only one?) I forgot to take note of the FN token, so any FN definitions or uses will look like references to an array variable. Another kind of modification, called "major" perhaps, will turn the VCR into LNCR (Line Number Cross Reference).

         1000  *---------------------------------
         1010  *      VARIABLE CROSS REFERENCE
         1020  *       FOR APPLESOFT PROGRAMS
         1030  *---------------------------------
         1040  ZZ.BEG .EQ $8800
         1050         .OR ZZ.BEG
         1060         .TF B.VCR
         1070  *---------------------------------
         1080         LDA #$4C     AMPERSAND VECTOR
         1090         STA $3F5
         1100         LDA #VCR
         1110         STA $3F6
         1120         LDA /VCR
         1130         STA $3F7
         1140         RTS
         1150  *---------------------------------
         1160  PNTR   .EQ $18,19   POINTER INTO PROGRAM
         1170  DATA   .EQ $1A THRU $1D
         1180  LZFLAG .EQ $1A      LEADING ZERO FLAG
         1190  NEXTLN .EQ $1A,1B   ADDRESS OF NEXT LINE
         1200  LINNUM .EQ $1C,1D   CURRENT LINE NUMBER
         1210  STPNTR .EQ $1E,1F   POINTER INTO VARIABLE TABLE
         1220  TPTR   .EQ $9B,9C   TEMP POINTER
         1230  SYMBOL .EQ $9D THRU $A4  8 BYTES
         1240  VARNAM .EQ SYMBOL+1
         1250  HSHTBL .EQ $280
         1260  ENTRY.SIZE .EQ $A5,A6
         1270  *---------------------------------
         1280  PRGBOT .EQ $67,68   BEGINNING OF PROGRAM
         1290  LOMEM  .EQ $69,6A   BEGINNING OF VARIABLE SPACE
         1300  EOT    .EQ $6B,6C   END OF VARIABLE TABLE
         1310  *---------------------------------
         1320  TKN.REM    .EQ 178
         1330  TKN.DATA   .EQ 131
         1340  *---------------------------------
         1350  MON.CH     .EQ $24
         1360  MON.PRBL2  .EQ $F94A
         1370  MON.COUT   .EQ $FDED
         1380  MON.CROUT  .EQ $FD8E
         1390  *---------------------------------
         1400  VCR
         1410         JSR INITIALIZATION
         1420  .1     JSR PROCESS.LINE
         1430         BNE .1       UNTIL END OF PROGRAM
         1440         JSR PRINT.REPORT
         1450         JSR INITIALIZATION  ERASE VARIABLE TABLE
         1452         LDA #0       CLEAR $A4 SO APPLESOFT WILL
         1454         STA $A4      WORK CORRECTLY
         1460         RTS
         1470  *---------------------------------
         1480  INITIALIZATION
         1490         LDA LOMEM
         1500         STA EOT
         1510         LDA LOMEM+1
         1520         STA EOT+1
         1530         LDX #52      # OF BYTES FOR HASH POINTERS
         1540         LDA #0
         1550  .1     STA HSHTBL-1,X
         1560         DEX
         1570         BNE .1
         1580         LDA PRGBOT
         1590         STA PNTR
         1600         LDA PRGBOT+1
         1610         STA PNTR+1
         1620         RTS
         1630  *---------------------------------
         1640  PROCESS.LINE
         1650         LDY #3       CAPTURE POINTER AND LINE #
         1660  .1     LDA (PNTR),Y
         1670         STA DATA,Y
         1680         DEY
         1690         BPL .1
         1692         LDA DATA+1   CHECK IF END
         1694         BEQ .3       YES
         1700         CLC          SKIP OVER DATA
         1710         LDA PNTR
         1720         ADC #4
         1730         STA PNTR
         1740         BCC .2
         1750         INC PNTR+1
         1760  .2     JSR SCAN.FOR.VARIABLES
         1770         LDA DATA
         1780         STA PNTR
         1790         LDA DATA+1
         1800         STA PNTR+1
         1810  *      BNE .3
         1820  .3     RTS
         1830  *---------------------------------
         1840  SCAN.FOR.VARIABLES
         1850  .1     JSR GET.NEXT.VARIABLE
         1860         BEQ .3       END OF LINE
         1870         JSR PACK.VARIABLE.NAME
         1880         JSR SEARCH.VARIABLE.TABLE
         1890         BCC .2       FOUND SAME VARIABLE
         1900         LDA #0
         1910         STA SYMBOL+4 START OF LINE NUMBER CHAIN
         1920         STA SYMBOL+5
         1930         LDA LINNUM+1 MSB FIRST
         1940         STA SYMBOL+6
         1950         LDA LINNUM
         1960         STA SYMBOL+7
         1970         LDA #8       ADD 8 BYTE ENTRY
         1980         JSR ADD.NEW.ENTRY
         1990         JMP .1
         2000  .2     JSR SEARCH.LINE.CHAIN
         2010         BCC .1       FOUND SAME LINE NUMBER
         2020         LDA #4       ADD 4 BYTE ENTRY
         2030         JSR ADD.NEW.ENTRY
         2040         JMP .1
         2050  .3     RTS
         2060  *---------------------------------
         2070  GET.NEXT.VARIABLE
         2080  .1     JSR NEXT.CHAR.NOT.QUOTE
         2090         BEQ .2       END OF LINE
         2100         CMP #TKN.DATA
         2110         BEQ .3
         2120         CMP #TKN.REM
         2130         BEQ .2       SKIP TO NEXT LINE
         2140         JSR LETTER   LETTER?
         2150         BCC .1       NO, KEEP LOOKING
         2160  .2     RTS
         2170  *   DATA, SO SKIP TO NEXT STATEMENT
         2180  .3     JSR NEXT.CHAR.NOT.QUOTE
         2190         BEQ .2       EOL, RETURN
         2200         CMP #':      COLON?
         2210         BNE .3       NOT END YET
         2220         BEQ .1       ...ALWAYS
         2230  *---------------------------------
         2240  NEXT.CHAR.NOT.QUOTE
         2250  .1     JSR NEXT.CHAR
         2260         BEQ .2       EOL, RETURN
         2270         CMP #'      QUOTE?
         2280         BEQ .3       YES, SCAN OVER QUOTATION
         2290  .2     RTS          RETURN
         2300  .3     JSR NEXT.CHAR
         2310         BEQ .2       EOL, RETURN
         2320         CMP #'      TERMINAL QUOTE?
         2330         BNE .3       NOT YET
         2340         BEQ .1       ...ALWAYS
         2350  *---------------------------------
         2360  *      NEXT CHARACTER FROM LINE
         2370  *        CALL:  JSR NEXT.CHAR
         2380  *      RETURN:  (A)=CHAR FROM LINE
         2390  *               IF CHAR .NE. EOL,
         2400  *                   INCREMENT PNTR AND
         2410  *                   STATUS Z=0
         2420  *               IF CHAR .EQ. EOL,
         2430  *                   STATUS Z=1
         2440  *---------------------------------
         2450  NEXT.CHAR
         2460         LDY #0
         2470         LDA (PNTR),Y
         2480         BEQ .1       EOL
         2490         INC PNTR     BUMP POINTER
         2500         BNE .1
         2510         INC PNTR+1
         2520  .1     RTS
         2530  *---------------------------------
         2540  PACK.VARIABLE.NAME
         2550         STA VARNAM   FIRST CHAR OF NAME
         2560         LDA #'       BLANKS FOR OTHER TWO CHARS
         2570         STA VARNAM+1
         2580         STA VARNAM+2
         2590         JSR NEXT.CHAR
         2600         BEQ .5       END OF LINE
         2610         JSR LTRDIG
         2620         BCC .2       NOT LETTER OR DIGIT
         2630         STA VARNAM+1
         2640  .1     JSR NEXT.CHAR IGNORE EXCESS NAME
         2650         BEQ .5       END OF LINE
         2660         JSR LTRDIG
         2670         BCS .1       LETTER OR DIGIT
         2680  .2     CMP #'$      DOLLAR SIGN?
         2690         BEQ .3       YES
         2700         CMP #'%      PER CENT?
         2710         BNE .4       NO
         2720  .3     STA VARNAM+2
         2730         JSR NEXT.CHAR
         2740         BEQ .5       END OF LINE
         2750  .4     CMP #'(      LEFT PAREN?
         2752         BEQ .6       YES
         2754         CMP #'      QUOTE?
         2760         BNE .5       NO
         2762         LDA PNTR     YES, BACK UP POINTER
         2763         BNE .7
         2764         DEC PNTR+1
         2765  .7     DEC PNTR
         2766         RTS
         2770  .6     LDA VARNAM+2 SET HIGH BIT
         2780         ORA #$80     TO FLAG ARRAY
         2790         STA VARNAM+2 REFERENCE
         2800  .5     RTS
         2810  *---------------------------------
         2820  SEARCH.VARIABLE.TABLE
         2830         SEC          CONVERT 1ST CHAR TO
         2840         LDA VARNAM   HASH TABLE INDEX
         2850         SBC #'A
         2860         ASL
         2870         ADC #HSHTBL
         2880         STA STPNTR
         2890         LDA /HSHTBL
         2900         ADC #0
         2910         STA STPNTR+1
         2920  *---   FALL INTO CHAIN SEARCH ROUTINE
         2930  *---------------------------------
         2940  CHAIN.SEARCH
         2950  .1     LDY #0       POINT AT POINTER IN ENTRY
         2960         LDA (STPNTR),Y
         2970         STA TPTR
         2980         INY
         2990         LDA (STPNTR),Y
         3000         BEQ .4       END OF CHAIN, NOT IN TABLE
         3010         STA TPTR+1
         3020         LDX #2       2 MORE CHARS IN SYMBOL
         3030         LDY #2       POINT AT NAME IN ENTRY
         3040  .2     LDA (TPTR),Y COMPARE NAMES
         3050         CMP SYMBOL,Y
         3060         BCC .3       NOT THIS ONE, BUT KEEP LOOKING
         3070         BNE .4       NOT IN THIS CHAIN
         3080         DEX
         3090         BEQ .5       NAME IS THE SAME
         3100         INY          NEXT BYTE PAIR
         3110         BNE .2       ...ALWAYS
         3120  *---------------------------------
         3130  .3     JSR .5       UPDATE POINTER, CLEAR CARRY
         3140         BCC .1       ...ALWAYS
         3150  *---------------------------------
         3160  .4     SEC          DID NOT FIND
         3170         RTS
         3180  *---------------------------------
         3190  .5     LDA TPTR
         3200         STA STPNTR
         3210         LDA TPTR+1
         3220         STA STPNTR+1
         3230         CLC
         3240         RTS
         3250  *---------------------------------
         3260  ADD.NEW.ENTRY
         3270         STA ENTRY.SIZE
         3280         CLC          SEE IF ROOM
         3290         LDX #1
         3300         LDY #0
         3310         STY ENTRY.SIZE+1
         3320  .1     LDA (STPNTR),Y  GET CURRENT POINTER
         3330         STA SYMBOL,Y
         3340         LDA EOT,Y
         3350         STA (STPNTR),Y
         3360         STA TPTR,Y
         3370         ADC ENTRY.SIZE,Y
         3380         STA EOT,Y
         3390         INY
         3400         DEX
         3410         BPL .1
         3420  *---   SEE IF GOING TO BE ENOUGH ROOM
         3430         LDA EOT
         3440         CMP #ZZ.BEG
         3450         LDA EOT+1
         3460         SBC /ZZ.BEG
         3470         BCS .3       MEM FULL ERR
         3480  *---   MOVE ENTRY INTO VARIABLE TABLE
         3490         LDY ENTRY.SIZE
         3500         DEY
         3510  .2     LDA SYMBOL,Y
         3520         STA (TPTR),Y
         3530         DEY
         3540         BPL .2
         3550         LDA TPTR
         3560         STA STPNTR
         3570         LDA TPTR+1
         3580         STA STPNTR+1
         3590         RTS
         3600  .3     JMP MEM.FULL.ERR
         3610  MEM.FULL.ERR
         3620         BRK
         3630  *---------------------------------
         3640  SEARCH.LINE.CHAIN
         3650         CLC          ADJUST POINTER TO START
         3660         LDA STPNTR   OF LINE # CHAIN
         3670         ADC #4
         3680         STA SYMBOL
         3690         LDA STPNTR+1
         3700         ADC #0
         3710         STA SYMBOL+1
         3720         LDA #SYMBOL
         3730         STA STPNTR
         3740         LDA /SYMBOL
         3750         STA STPNTR+1
         3760         LDA LINNUM   PUT LINE NUMBER INTO SYMBOL
         3770         STA SYMBOL+3
         3780         LDA LINNUM+1
         3790         STA SYMBOL+2
         3800         JMP CHAIN.SEARCH
         3810  *---------------------------------
         3820  PRINT.REPORT
         3830         LDA #'A      START WITH A'S
         3840  .1     STA VARNAM
         3850         SEC
         3860         SBC #'A      CONVERT TO HSHTBL INDEX
         3870         ASL
         3880         TAY
         3890         LDA HSHTBL+1,Y
         3900         BEQ .2       NO ENTRY FOR THIS LETTER
         3910         STA PNTR+1
         3920         LDA HSHTBL,Y
         3930         STA PNTR
         3940         JSR PRINT.LETTER.CHAIN
         3950  .2     INC VARNAM   NEXT LETTER
         3960         LDA VARNAM
         3970         CMP #'Z+1
         3980         BCC .1       STILL MORE LETTERS
         3990         RTS          FINISHED
         4000  *---------------------------------
         4010  LTRDIG
         4020         CMP #'0      DIGIT?
         4030         BCC LD1      NO
         4040         CMP #'9+1
         4050         BCC LD2      YES
         4060  LETTER
         4070         CMP #'A      LETTER?
         4080         BCC LD1      NO
         4090         CMP #'Z+1
         4100         BCC LD2      YES
         4110         CLC          NO
         4120  LD1    RTS
         4130  LD2    SEC
         4140         RTS
         4150  *---------------------------------
         4160  PRINT.LETTER.CHAIN
         4170  .1     LDA VARNAM   FIRST LETTER
         4180         JSR PRINT.CHAR
         4190         LDY #1
         4200  .2     INY
         4210         LDA (PNTR),Y REST OF NAME
         4220         AND #$7F
         4230         CMP #'       BLANK?
         4240         BEQ .3
         4250         JSR PRINT.CHAR
         4260  .3     CPY #3
         4270         BCC .2
         4280         LDA (PNTR),Y CHECK IF ARRAY
         4290         BPL .4
         4300         LDA #'(
         4310         JSR PRINT.CHAR
         4320  .4     CLC          POINT AT LINE # CHAIN
         4330         LDA PNTR
         4340         ADC #4
         4350         STA TPTR
         4360         LDA PNTR+1
         4370         ADC #0
         4380         STA TPTR+1
         4390         JSR PRINT.LINNUM.CHAIN
         4400         JSR MON.CROUT
         4410         LDY #1
         4420         LDA (PNTR),Y POINTER TO NEXT VARIABLE
         4430         BEQ .5       NO MORE
         4440         PHA
         4450         DEY
         4460         LDA (PNTR),Y
         4470         STA PNTR
         4480         PLA
         4490         STA PNTR+1
         4500         BNE .1       ...ALWAYS
         4510  .5     RTS
         4520  *---------------------------------
         4530  PRINT.LINNUM.CHAIN
         4540  .1     JSR TAB.NEXT.COLUMN
         4550         LDY #2       POINT AT LINE #
         4560         LDA (TPTR),Y
         4570         STA LINNUM+1
         4580         INY
         4590         LDA (TPTR),Y
         4600         STA LINNUM
         4610         JSR PRINT.LINE.NUMBER
         4620         LDY #1       SET UP NEXT POINTER
         4630         LDA (TPTR),Y
         4640         BEQ .2
         4650         PHA
         4660         DEY
         4670         LDA (TPTR),Y
         4680         STA TPTR
         4690         PLA
         4700         STA TPTR+1
         4710         BNE .1       ...ALWAYS
         4720  .2     RTS
         4730  *---------------------------------
         4740  TAB.NEW.LINE
         4750         JSR MON.CROUT
         4760  TAB.NEXT.COLUMN
         4770  .1     LDA #7       FIRST TAB STOP
         4780  .2     CMP MON.CH   CURSOR POSITION
         4790         BCS .3       PERFORM TAB
         4800         ADC #6       NEXT TAB STOP
         4810         CMP #33      END OF LINE?
         4820         BCC .2
         4830         BCS TAB.NEW.LINE  ...ALWAYS
         4840  .3     BEQ .4       ALREADY THERE
         4850         SBC MON.CH   CALCULATE # OF BLANKS
         4860         TAX
         4870         JSR MON.PRBL2
         4880  .4     RTS
         4890  *---------------------------------
         4900  PRINT.LINE.NUMBER
         4910         LDX #4       PRINT 5 DIGITS
         4920         STX LZFLAG   TURN ON LEADING ZERO FLAG
         4930  .1     LDA #'0      DIGIT=0
         4940  .2     PHA
         4950         SEC
         4960         LDA LINNUM
         4970         SBC PLNTBL,X
         4980         PHA
         4990         LDA LINNUM+1
         5000         SBC PLNTBH,X
         5010         BCC .3       LESS THAN DIVISOR
         5020         STA LINNUM+1
         5030         PLA
         5040         STA LINNUM
         5050         PLA
         5060         ADC #0       INCREMENT DIGIT
         5070         BNE .2       ...ALWAYS
         5080  .3     PLA
         5090         PLA
         5100         CMP #'0
         5110         BEQ .5       ZERO, MIGHT BE LEADING
         5120         SEC          TURN OFF LZFLAG
         5130         ROR LZFLAG
         5140  .4     JSR PRINT.CHAR
         5150         DEX
         5160         BPL .1
         5170         RTS
         5180  .5     BIT LZFLAG   LEADING ZERO FLAG
         5190         BMI .4       NO
         5200         LDA #'       BLANK
         5210         BNE .4       ...ALWAYS
         5220  PLNTBL .DA #1
         5230         .DA #10
         5240         .DA #100
         5250         .DA #1000
         5260         .DA #10000
         5270  PLNTBH .DA /1
         5280         .DA /10
         5290         .DA /100
         5300         .DA /1000
         5310         .DA /10000
         5320  *---------------------------------
         5330  PRINT.CHAR
         5340         ORA #$80
         5350         JSR MON.COUT
         5360         RTS
         5370  *---------------------------------
         5380  ZZ.END .EQ *
         5390  ZZ.SIZ .EQ ZZ.END-ZZ.BEG

Bags, Boxes, et cetera

Since I sell software in stores, I buy a lot of zip-lock bags, cardboard mailing boxes, diskettes, and so on. I thought that maybe you need some of these, and haven't been able to find a source at good prices in small quantities. I will sell you some of mine, at the follwoing prices:

6"x9" zip-lock bags $8.50/100
9"x12" zip-lock bags $12/100
Verbatim diskettes
without hubrings $30 for box of ten, $265 for 100
with hubrings $32 for box of ten, $285 for 100

Anything else you need? Let me know, maybe I have it or can get it for you or tell you where you can get it at a good price.

Assembly Source on Text Files | Bob Sander-Cederlof

Version 4.0 of the S-C Assembler II allows you to EXEC a source program, if it is on a DOS text file. This is handy if you have created it with a different editor, or perhaps with a compiler. But what if you want to go the other way? What if you want to SAVE a source program on a text file, so that it can be used in another editor, or by another assembler?

There is no built-in command to allow it, so I have now written a separate program to do it. The program loads at $0800 thru $093C, and does not borrow any code from the assembler. It does use some routines in the Monitor ROMs, and the DOS I/O rehook routine. If you BRUN the program, it will assume the pointers at $CA,CB and $4C,4D are bracketing a valid assembly source program, and try to list it on a text file.

The main body of the program is in lines 1190 thru 1630. Lines 1200 and 1210 serve to un-hook the S-C Assembler II from the output. They will also turn off your printer, if you had it on. Lines 1220 and 1230 tell DOS that it should recognize commands printed after a control-D. Lines 1240 and 1250 change the prompt symblol to a blank, so that the monitor input subroutine will not print a colon or some other character as the prompt when reading the file name.

Lines 1290-1360 request you to enter a file name, read it into the monitor buffer starting at $0200, and move it to a safe place at $0280. It has to be moved, because when we print DOS commands later the area starting at $0200 will be written on by DOS.

Once the file name you have typed is safely stored at $0280 and following, lines 1410 thru 1490 will set up the file for writing. This is done in five steps. First, close all files. Second, issue an OPEN-DELETE-OPEN sequence, with the file name (of course); this will make sure that we are writing on a fresh empty file. Then the WRITE command is sent, and we are ready to roll.

Line 1530 calls a subroutine which lists your source program. Since the file is OPEN and in WRITE mode, the listing goes into your text file. If you have MON O mode set, you will also see the listing on your screen. Note that it is not really necessary for me to use a subroutine at this point. ASM.LIST is only called once, and it is not very long. But I did it anyway, to keep the main body short enough to fit on a page (of paper), easy to understand, modular, structured, etc.

After the listing is completed, line 1570 will close the text file. Lines 1610 and 1620 turn off the DOS run flag, so that DOS will not look for control-D commands. And finally, line 1630 re-enters the S-C Assembler II through its soft entry point.

Lines 1670 thru 1780 are text strings, printed by the subroutine named PRINT.QUOTE. Each string is written with the sign bit of every byte zero except for the last byte. The sign bit of the last byte is 1, telling PRINT.QUOTE that it is finished. For example, the first message is the word "CLOSE" and a carriage return. The carriage return is entered in hex with the sign bit 1 as in $8D. The second message is the word "OPEN", and the letter "N" is preceded by a minus sign in the .AS directive to indicate that the sign bit should be 1.

The PRINT.QUOTE subroutine is at lines 2140 thru 2200. It expects the Y-register to contain the offset of the desired message from the beginning of all the messages at QTS. It calls on PRINT.CHAR to actually send each character.

PRINT.CHAR, at lines 2020 thru 2100, calls on the monitor print character routine at $FDED. This branches through DOS, and DOS writes the character on the text file. PRINT.CHAR saves and restores the Y-register and A-register contents. It also sets the sign bit on each character before printing it. Upon exit, the status will reflect the value of the character printed.

Lines 1820-1980 issue a DOS command. The Y-register points at one of the message strings in QTS. Control-D is printed, followed by the command key word, a space, and file name you previously typed. Since DOS does not allow slot and drive specifications on the WRITE command, and since it is sufficient to specify them only once, the subroutine chops them off after printing them once. The logic for this is in lines 1910-1940: after printing a comma, it is replaced with a carriage return. The next time the name is printed, the carriage return will be the end.

The subroutine which really controls the listing is in lines 2330-2450. The first four instructions set up a zero-page pointer SRCP to point at the beginning of your source program. Lines 2380-2420 compare the pointer with HIMEM to see if the listing is completed. If you really had no source program, we would already be finished at this point. If there is another line (or more), the subroutine named ASM.LIST.LINE is called to list the next lne. The process is repeated until the last line has been printed onto your text file.

At this point it might be helpful to explain how source lines are stored in memory. Each line begins with a single byte which contains the byte-count of the line. Next are a byte-pair containing the line number of the line, in the usual backwards 6502 format. The text of the line follows, and a final byte containing $00 ends the line. No carriage return is stored. Blanks are treated specially. A single blank is stored as $81. Two blanks in a row are replaced by one byte of value $82. Any string of blanks up to 63 blanks is thus replaced by a single token of value $80 plus the blank count. Longer strings of blanks will take more than one token.

For example, the source line

         1000 ABC    LDA SAM

is stored as:

         0F (total of 15 bytes in line image)
         E8 03 (line number 1000)
         41 42 43 84 ("ABC" and 4 blanks)
         4C 44 41 81 ("LDA" and 1 blank)
         53 41 4D ("SAM")
         00 (end of line indicator)

The subroutine ASM.LIST.LINE at lines 2490-2610 prints one source line. A subroutine named GNB ("get next byte") is called to skip over the length byte, and to pick up the line number. PRINT.LINNUM is called to convert the line number to decimal and print it, with leading zeroes if necessary, as a four digit number. The loop at lines 2570-2600 is seeded with a blank (because the blank between the line number and the label field is not actually stored in the source program), and the text of the line is printed. The loop prints a character, and then calls NEXT.TOKEN to get the next one. When the token returned equals $00, the line is finished.

GNB, lines 2630-2690, clears the queued blank count, picks up the character pointed at by SRCP, and increments SRCP.

NEXT.TOKEN, lines 2710-2820, tests the blank count. If it is non-zero, the count is decremented and a blank ($20) character is returned. If the count was zero, the next character is picked up from the line. If this character is not a blank count token, it is returned and the pointer in SRCP is incremented. If the character is a blank count token, it is saved, the SRCP pointer is incremented past the token, and then the count is decremented and a blank returned.

The PRINT.LINNUM routine, lines 2860-3170, is a revision of a routine used in the Integer BASIC ROMs. I think it is commented well enough for you to follow. The general idea is to divide by 1000 and print the quotient; divide the remainder by 100 and print the quotient; then by 10; and finally print the remainder.

Since several of you have asked me to provide the capability to list programs onto text files, you should be pleased with this program. If you do not need it, then maybe it has shed some light on the internal structure of part of the assembler, or served as a tutorial in programming.

         1000         .LIST OFF
         1010  *---------------------------------
         1020  *      WRITE ASSEMBLY SOURCE ON A TEXT FILE
         1030  *---------------------------------
         1040         .OR $800
         1050  MON.PROMPT .EQ $33
         1060  PP     .EQ $CA,CB
         1070  HIMEM  .EQ $4C,4D
         1080  DOS.RUNFLAG .EQ $D9
         1090  MON.BUFFER .EQ $200
         1100  DOS.BUFFER .EQ $280
         1110  MON.GETLN  .EQ $FD6A
         1120  MON.CROUT  .EQ $FD8E
         1130  MON.COUT   .EQ $FDED
         1140  MON.SETVID .EQ $FE93
         1150  DOS.REHOOK .EQ $3EA
         1160  BLANK.COUNT .EQ $00
         1170  SRCP   .EQ $01,02
         1180  LINNUM .EQ $03,04
         1190  *---------------------------------
         1200  TEXT.LIST
         1210         JSR MON.SETVID
         1220         JSR DOS.REHOOK
         1230         LDA #$FF
         1240         STA DOS.RUNFLAG
         1250         LDA #' +$80  SET PROMPT CHAR = BLANK
         1260         STA MON.PROMPT
         1270  *---------------------------------
         1280  *      GET FILE NAME
         1290  *---------------------------------
         1300         LDY #QFILNAM-QTS
         1310         JSR PRINT.QUOTE
         1320         JSR MON.GETLN
         1330         LDY #$7F     MOVE FILE NAME TO SEPARATE BUFFER
         1340  .1     LDA MON.BUFFER,Y
         1350         STA DOS.BUFFER,Y
         1360         DEY
         1370         BPL .1
         1380  *---------------------------------
         1390  *      SET UP THE TEXT FILE
         1400  *      (CLOSE, OPEN, DELETE, OPEN, WRITE)
         1410  *---------------------------------
         1420         JSR CLOSE.FILE
         1430         LDY #QOPEN-QTS
         1440         JSR ISSUE.DOS.COMMAND
         1450         LDY #QDELETE-QTS
         1460         JSR ISSUE.DOS.COMMAND
         1470         LDY #QOPEN-QTS
         1480         JSR ISSUE.DOS.COMMAND
         1490         LDY #QWRITE-QTS
         1500         JSR ISSUE.DOS.COMMAND
         1510  *---------------------------------
         1520  *      LIST THE SOURCE PROGRAM
         1530  *---------------------------------
         1540         JSR ASM.LIST
         1550  *---------------------------------
         1560  *      CLOSE THE FILE
         1570  *---------------------------------
         1580         JSR CLOSE.FILE
         1590  *---------------------------------
         1600  *      RETURN TO CALLER
         1610  *---------------------------------
         1620         LDA #0
         1630         STA DOS.RUNFLAG
         1640         JMP $1003
         1650  *---------------------------------
         1660  *      MESSAGE TEXT
         1670  *---------------------------------
         1680  QTS    .EQ *
         1690  QCLOSE .AS /CLOSE/
         1700         .HS 8D
         1710  QOPEN  .AS /OPE/
         1720         .AS -/N/
         1730  QDELETE .AS /DELET/
         1740         .AS -/E/
         1750  QWRITE .AS /WRIT/
         1760         .AS -/E/
         1770  QFILNAM .HS 0D
         1780         .AS /TEXT FILE NAME:/
         1790         .AS -/ /
         1800  *---------------------------------
         1810  *      ISSUE DOS COMMAND
         1820  *---------------------------------
         1830  ISSUE.DOS.COMMAND
         1840         LDA #$84     CONTROL-D
         1850         JSR PRINT.CHAR
         1860         JSR PRINT.QUOTE
         1870         LDY #0
         1880         LDA #'       PRINT A SPACE
         1890  .5     JSR PRINT.CHAR
         1900         CMP #$8D
         1910         BEQ .7
         1920         CMP #$AC     COMMA?
         1930         BNE .6
         1940         LDA #$8D
         1950         STA DOS.BUFFER-1,Y
         1960  .6     LDA DOS.BUFFER,Y
         1970         INY
         1980         BNE .5       ...ALWAYS
         1990  .7     RTS
         2000  *---------------------------------
         2010  *      PRINT CHARACTER
         2020  *---------------------------------
         2030  PRINT.CHAR
         2040         PHA
         2050         STY PC.SAVEY
         2060         ORA #$80
         2070         JSR MON.COUT
         2080         LDY PC.SAVEY
         2090         PLA
         2100         RTS
         2110  PC.SAVEY .BS 1
         2120  *---------------------------------
         2130  *      PRINT A QUOTATION
         2140  *---------------------------------
         2150  PRINT.QUOTE.NEXT
         2160         INY
         2170  PRINT.QUOTE
         2180         LDA QTS,Y
         2190         JSR PRINT.CHAR
         2200         BPL PRINT.QUOTE.NEXT
         2210         RTS
         2220  *---------------------------------
         2230  *      CLOSE ALL FILES
         2240  *---------------------------------
         2250  CLOSE.FILE
         2260         JSR MON.CROUT
         2270         LDA #$84
         2280         JSR PRINT.CHAR CONTROL-D
         2290         LDY #QCLOSE-QTS
         2300         JMP PRINT.QUOTE
         2310  *---------------------------------
         2320  *      LIST SOURCE PROGRAM
         2330  *---------------------------------
         2340  ASM.LIST
         2350         LDA PP
         2360         STA SRCP
         2370         LDA PP+1
         2380         STA SRCP+1
         2390  .1     LDA SRCP
         2400         CMP HIMEM
         2410         LDA SRCP+1
         2420         SBC HIMEM+1
         2430         BCS .2       FINISHED
         2440         JSR ASM.LIST.LINE
         2450         JMP .1
         2460  .2     RTS
         2470  *---------------------------------
         2480  *      LIST ONE SOURCE LINE
         2490  *---------------------------------
         2500  ASM.LIST.LINE
         2510         JSR GNB      SKIP OVER BYTE COUNT
         2520         JSR GNB      GET LINE NUMBER
         2530         STA LINNUM
         2540         JSR GNB
         2550         STA LINNUM+1
         2560         JSR PRINT.LINNUM
         2570         LDA #'       BLANK
         2580  .1     JSR PRINT.CHAR
         2590         JSR NEXT.TOKEN
         2600         CMP #0
         2610         BNE .1
         2620         JMP MON.CROUT
         2630  *---------------------------------
         2640  GNB    LDY #0
         2650         STY BLANK.COUNT
         2660         LDA (SRCP),Y
         2670  GNBI   INC SRCP
         2680         BNE .1
         2690         INC SRCP+1
         2700  .1     RTS
         2710  *---------------------------------
         2720  NEXT.TOKEN
         2730         LDY #0
         2740         LDA BLANK.COUNT
         2750         BNE .1
         2760         LDA (SRCP),Y
         2770         BPL GNBI
         2780         AND #$7F
         2790         STA BLANK.COUNT
         2800         JSR GNBI
         2810  .1     DEC BLANK.COUNT
         2820         LDA #'       BLANK
         2830         RTS
         2840  *---------------------------------
         2850  *      PRINT LINE NUMBER
         2860  *---------------------------------
         2870  PRINT.LINNUM
         2880         LDX #3       PRINT 4 DIGITS
         2890  .3     LDA #'0      SET DIGIT TO ASCII ZERO
         2900  .1     PHA          PUSH DIGIT ON STACK
         2910         SEC          SUBTRACT CURRENT DIVISOR
         2920         LDA LINNUM
         2930         SBC PLNTBL,X
         2940         PHA          SAVE BYTE ON STACK
         2950         LDA LINNUM+1
         2960         SBC PLNTBH,X
         2970         BCC .2       LESS THAN DIVISOR
         2980         STA LINNUM+1
         2990         PLA          GET LOW BYTE OFF STACK
         3000         STA LINNUM
         3010         PLA          GET DIGIT FROM STACK
         3020         ADC #0       INCREMENT DIGIT
         3030         BNE .1       ...ALWAYS
         3040  .2     PLA          DISCARD BYTE FROM STACK
         3050         PLA          GET DIGIT FROM STACK
         3060         JSR PRINT.CHAR
         3070         DEX          NEXT DIGIT
         3080         BPL .3
         3090         RTS          RETURN
         3100  *---------------------------------
         3110  PLNTBL .DA #1
         3120         .DA #10
         3130         .DA #100
         3140         .DA #1000
         3150  PLNTBH .DA /1
         3160         .DA /10
         3170         .DA /100
         3180         .DA /1000

A Use for the USR Command | Bob Sander-Cederlof

The S-C Assembler II Version 4.0 has one user-programmable command, called "USR". (The Quick Reference Card spells it erroneously "USEr".) One good use for it is to re-print the current symbol table.

After an assembly, if the listing was not printed, it is often desirable to be able to see what the spelling or value of a symbol or group of symbols is. If the VAL command is not enough for you, then the following steps will set up the USR command to re-list the symbol table on the screen. And, if your printer is selected, it will also print there.

Get into the assembler, by using BRUN ASMDISK 4.0 from either Applesoft or Integer BASIC. Type "$1E4EL" after the prompt. The first two lines listed should be "LDY #$02" and "STY $E1". If they are not, you have a different version. (It may still be version 4.0, but slightly different.) The "LDY#$02" line is the first instruction of the symbol table printing subroutine.

Patch the USR vector by typing "$1007:4E 1E", and then BSAVE the result like this:

         :BSAVE ASMDISK 4.0 (WITH USR),A$1000,L$14FB

This new version, whenever you type "USR", will print out the current symbol table. It will look exactly the same as the symbol table pritned out at the end of an assembly.

A Simulated Numeric Key-Pad | Bob Sander-Cederlof

This little program will turn part of your Apple's keyboard into a simulated numeric key-pad. A lot cheaper than buying a real one! It is set up to run in page 3, and assumes you are using DOS. If not, just change line 1120 to an RTS.

If you BRUN it or CALL it at 768, the input vector is patched to input all characters through the NKP program. Typing a control-S will toggle the numeric key-pad translator on and off. When the translator is off, all keyboard action is normal, except that another control-S will turn it back on again. When the translator is on, all keys which are not part of the simulated key-pad will input normally.

The keys translated by the simulator are listed in line 1390. The slash key duplicates RETURN, because it is easier to hit when yu are entering a lot of numbers. For the same reason, the L-key duplicates "-", in case you are in a hurry to enter negative numbers too. The space bar is used for "0". I set it up to use "NM," for "123", "HJK" for "456", and "YUI" for "789". You shuld be able to easily change these translations to any other combination, by changing lines 1390-1420.

The heart of the translator is the search loop in lines 1240-1280. If the input character is not found in CHRTBL, the search loop drops out and the character is not changed. If the character is found, line 1310 picks up the alias for the key, and returns. That's all there is to it!

         1000  *---------------------------------
         1010  *     NUMERIC KEY PAD FOR APPLE
         1020  *---------------------------------
         1030         .OR $300
         1040         .TF B.NKP
         1050  *---------------------------------
         1060         LDA #1
         1070         STA TOGGLE
         1080         LDA #NKP
         1090         STA $38
         1100         LDA /NKP
         1110         STA $39
         1120         JMP $3EA
         1130  *---------------------------------
         1140  TOGGLE .BS 1
         1150  SAVEY  .BS 1
         1160  *---------------------------------
         1170  NKP
         1180         JSR $FD1B
         1190         CMP #$93     CONTROL-S
         1200         BEQ .4
         1210         BIT TOGGLE
         1220         BMI .2       NOT IN NUMERIC MODE
         1230         STY SAVEY
         1240         LDY #TBLSIZ-1
         1250  .1     CMP CHRTBL,Y
         1260         BEQ .3       FOUND IN TABLE
         1270         DEY
         1280         BPL .1
         1290         LDY SAVEY
         1300  .2     RTS
         1310  .3     LDA ALIAS,Y
         1320         LDY SAVEY
         1330         RTS
         1340  .4     LDA TOGGLE
         1350         EOR #$80
         1360         STA TOGGLE
         1370         JMP $FD0C
         1380  *---------------------------------
         1390  CHRTBL .AS -/L NM,HJKYUI
         1400  TBLSIZ .EQ *-CHRTBL
         1410  ALIAS  .HS 8D
         1420         .AS --0123456789
         1430  *---------------------------------

Apple Assembly Line is published monthly by S-C SOFTWARE, P. O. Box 5537, Richardson, TX 75080. Subscription rate is $12/year, in the U.S.A., Canada, and Mexico. Other countries add $6/year for extra postage. All material herein is copyrighted by S-C SOFTWARE, all rights reserved. Unless otherwise indicated, all material herein is authored by Bob Sander-Cederlof. (Apple is a registered trademark of Apple Computer, Inc.)