Apple Assembly   Line
Volume 2 -- Issue 3 December 1981

In This Issue...


EXCEL-9: A 6809 Card with FLEX Bob Sander-Cederlof

For the last month and a half I have been working with a fantastic new device: the EXCEL-9 from Seikou Electronics in Japan. The EXCEL-9 contains a 6809E CPU, 8K bytes of ROM, and an interval timer. The 8K ROM contains a monitor with 35 commands (including mini-assembler anddis-assembler commands). The introductory price of $399.95 includes the FLEX Operating System from Technical Systems Consultants (TSC), with utilities, text editor, and macro assembler.

The board will soon be appearing in your local computer stores, courtesy of ESD Laboratories. I worked with them to translate the excellent reference manual into English. (That explains how I obtained one of the boards so early.)

EXCEL-9 has a lot of unique features that should make it a very popular board:

I intend to handle these boards. You can order them from me now, but please allow a while for delivery. The documentation is ready for the printer, but not yet printed.


Applesoft Hi-Res Subroutines Bob Sander-Cederlof

One of the questions I hear the most is "How can I call the Hi-Res subroutines in the Applesoft ROMs?" The basic information about those subroutines has been published (in Apple Orchard, Vol. 1 No. 1), but with an error in the subroutine addresses.

First, some important locations in page zero:


     $1A,1B  Shape pointer used by DRAW and XDRAW

     $1C     Last used color byte

     $26,27  Address of byte containing X,Y point

     $30     Bit mask for bit in that byte

     $E0,E1  X-coordinate (0-279)

     $E2     Y-coordinate (0-191)

     $E4     Color

     $E6     Page ($20 if HGR, $40 if HGR2)

     $E7     SCALE= value

     $E8,E9  Address of beginning of shape table

     $EA     Collision counter

     $F9     ROT= value

The software uses some other page zero variables, but I am not too clear yet on their purpose.

Now here are the major entry points:


     HGR2     $F3D8   Initialize and clear hi-res page 2.



     HGR      $F3E2   Initialize and clear hi-res page 1.



     HCLR     $F3F2   Clear the current hi-res screen to black.



     BKGND    $F3F6   Clear the current hi-res screen to the

                      last plotted color (from ($1C).



     HPOSN    $F411   Positions the hi-res cursor without

                      plotting a point.

                      Enter with (A) = Y-coordinate, and

                      (Y,X) = X-coordinate.



     HPLOT    $F457   Calls HPOSN and tries to plot a dot at

                      the cursor's position.  If you are

                      trying to plot a non-white color at

                      a complementary color position, no

                      dot will be plotted.



     HLIN     $F53A   Draws a line from the last plotted

                      point or line destination to:

                      (X,A) = X-coordinate, and

                      (Y) = Y-coordinate.



     HFIND    $F5CB   Converts the hi-res coursor's position

                      back to X- and Y-coordinates; stores

                      X-coordinate at $E0,E1 and Y-coordinate

                      at $E2.



     DRAW     $F601   Draws a shape.  Enter with (Y,X) = the

                      address of the shape table, and (A) =

                      the rotation factor.  Uses the current

                      color.



     XDRAW    $F65D   Draws a shape by inverting the existing

                      color of the dots the shape draws over.

                      Same entry parameters as DRAW.



     SETHCOL  $F6EC   Set the hi-res color to (X), where (X)

                      must be between 0 and 7.

I wrote a sample demonstration program of the hi-res subroutines. First, here is an Applesoft version. Note that it first sets the whole screen to a particular color, and then draws a series of nested squares in a complementary color. Since it is nice and short, why don't you type it in and try it?


  100  HGR2 

  110  FOR C = 0 TO 7: HCOLOR= C

  120  HPLOT 0,0: CALL 62454: REM CLEAR TO CURRENT COLOR

  130  HCOLOR= 7 - C

  140  FOR S = 10 TO 190 STEP 10

  150  X1 = 140 - S / 2: X2 = X1 + S

  160  Y1 = 95 - S / 2: Y2 = Y1 + S

  170  HPLOT X1,Y1 TO X2,Y1 TO X2,Y2 TO X1,Y2 TO X1,Y1

  180  NEXT S

  190  PRINT  CHR$ (7): FOR I = 1 TO 500: NEXT 

  200  NEXT C

  210  TEXT 

Now here is the assembly language program for the same task. It seemed to run about twice as fast as the Applesoft version, but I didn't use the stopwatch on it.

 1000  *---------------------------------

 1010  *      SAMPLE PLOTTING PROGRAM

 1020  *---------------------------------

 1030  AS.LASTCLR .EQ $1C

 1040  *---------------------------------

 1050  AS.HGR2    .EQ $F3D8 SET UP HI-RES PAGE 2

 1060  AS.HCLR    .EQ $F3F2 CLEAR HI-RES SCREEN

 1070  AS.BKGND   .EQ $F3F6 CLEAR HI-RES SCREEN TO LAST COLOR

 1080  AS.HPOSN   .EQ $F411 MOVE CURSOR TO (Y,X),(A)

 1090  AS.HPLOT   .EQ $F457 PLOT A DOT AT (Y,X),(A)

 1100  AS.HLIN    .EQ $F53A DRAW A LINE FROM LAST POINT TO (X,A),(Y)

 1110  AS.SETHCOL .EQ $F6EC SET HI-RES COLOR

 1120  MON.TEXT   .EQ $FB2F

 1130  *---------------------------------

 1140  HI.RES.DEMO

 1150         JSR AS.HGR2

 1160         LDX #0       FOR COLOR = 0 TO 7

 1170  .1     STX COLOR

 1180         JSR AS.SETHCOL

 1190         STA AS.LASTCLR

 1200         JSR AS.BKGND   CLEAR SCREEN TO SOLID COLOR

 1210         LDA COLOR

 1220         EOR #7       COMPLEMENTARY COLOR

 1230         TAX

 1240         JSR AS.SETHCOL

 1250         JSR DRAW.SQUARE

 1260         LDX COLOR      NEXT COLOR

 1270         INX

 1280         CPX #8

 1290         BCC .1

 1300         JSR MON.TEXT

 1310         RTS

 1320  *---------------------------------

 1330  DRAW.SQUARE

 1340         LDA #10      FOR SIZE=10 TO 190 STEP 10

 1350  .1     STA SIZE

 1360         LSR          SIZE/2

 1370         STA SIZE2

 1380         LDA #0

 1390         STA XSTART+1

 1400         STA XSTOP+1

 1410         SEC          XSTART=140-SIZE/2

 1420         LDA #140

 1430         SBC SIZE2

 1440         STA XSTART

 1450         CLC          XSTOP=XSTART+SIZE

 1460         ADC SIZE

 1470         STA XSTOP

 1480         SEC

 1490         LDA #95      YSTART=95-SIZE/2

 1500         SBC SIZE2

 1510         STA YSTART

 1520         CLC          YSTOP=YSTART+SIZE

 1530         ADC SIZE

 1540         STA YSTOP

 1550         LDY XSTART+1 HPLOT XSTART,YSTART

 1560         LDX XSTART

 1570         LDA YSTART

 1580         JSR AS.HPLOT

 1590         LDX XSTOP+1    TO XSTOP,YSTART

 1600         LDA XSTOP

 1610         LDY YSTART

 1620         JSR AS.HLIN

 1630         LDX XSTOP+1    TO XSTOP,YSTOP

 1640         LDA XSTOP

 1650         LDY YSTOP

 1660         JSR AS.HLIN

 1670         LDX XSTART+1   TO XSTART,YSTOP

 1680         LDA XSTART

 1690         LDY YSTOP

 1700         JSR AS.HLIN

 1710         LDX XSTART+1   TO XSTART,YSTART

 1720         LDA XSTART

 1730         LDY YSTART

 1740         JSR AS.HLIN

 1750         CLC

 1760         LDA SIZE     NEXT SIZE

 1770         ADC #10

 1780         CMP #191

 1790         BCC .1

 1800  DELAY.LOOP

 1810         LDY #0       DELAY LOOP SO WE CAN SEE IT

 1820  .1     LDX #0

 1830  .2     DEX

 1840         BNE .2

 1850         LDA $C030    AND HEAR IT

 1860         DEY

 1870         BNE .1

 1880         RTS

 1890  *---------------------------------

 1900  COLOR  .BS 1

 1910  SIZE   .BS 1

 1920  SIZE2  .BS 1

 1930  XSTART .BS 2

 1940  YSTART .BS 1

 1950  XSTOP  .BS 2

 1960  YSTOP  .BS 1

[ The following advertisement is for historical interest only!!! The company closed its doors in 1988.]

A D V E R T I S E M E N T


S-C ASSEMBLER II Version 4.0...................................$55.00

    Includes Manual, Diskette with Assembler and sample

    source programs, and Quick Reference Card.



Source code of Version 4.0 on disk.............................$95.00

    Fully commented, easy to understand and modify to

    your own tastes.



Cross Assembler Patches for 6809...............................$20.00

    Requires possession of Version 4.0.  Enables you to

    develop programs for the Motorola 6809 CPU.  (The

    MILL from Stellation, EXCEL-9 from ESD Laboratories,

    or the Radio Shack Color Computer.)



Cross Assembler for 6800.......................................$22.50

    Requires possession of Version 4.0.  Enables you to

    develop programs for the Motorola 6800, 6801, and

    6802 CPUs.



AAL Quarterly Disks.......................................each $15.00

    Each disk contains all the source code from three

    issues of "Apple Assembly Line", to save you lots

    of typing and testing time.

    QD#1:  Oct - Dec 1980    QD#4:  Jul - Sep 1981

    QD#2:  Jan - Mar 1981    QD#5:  Oct - Dec 1981

    QD#3:  Apr - Jun 1981



Double Precision Floating Point for Applesoft..................$50.00

    Provides 21-digit precision for Applesoft programs.

    Includes subroutines for standard math functions.



Some Simple Integer BASIC Games................................$10.00

    Includes 4x4x4 tic-tac-toe, lo-res space war, lo-res

    jig-saw puzzle, and mastermind.



Blank Diskettes..............................package of 20 for $50.00

    Verbatim Datalife, with hub rings, no labels, in plain

    white jackets, in cellophane wrapper.



Lower-Case Display Encoder ROM.................................$25.00

    Works only Revision level 7 Apples.  Replaces the

    encoder ROM.  Comes with instructions.



Diskette Mailing Protectors.....................10-99:  40 cents each

                                          100 or more:  25 cents each

    Corrugated folder specially designed for mailing

    mini-floppy diskettes.  Fits in standard 6x9-inch

    envelope.  (Envelopes 5-cents each, if you need them.)



Zip-Lock Bags (2-mil, 6"x9")............................100 for $8.50

              (2-mil, 9"x12")..........................100 for $13.00



Books, Books, Books......................compare our discount prices!

    "Beneath Apple DOS", Worth & Lechner.............($19.95)  $18.00

    "What's Where in the Apple", William Leubert.....($14.95)  $14.00

    "6502 Assembly Language Programming", Leventhal..($16.99)  $16.00

    "Apple Assembly Language", Don & Kurt Inman......($12.95)  $12.00







      *** S-C SOFTWARE, P. O. BOX 280300, Dallas, TX 75228 ***

      *** (214) 324-2050    We take Master Charge and VISA ***

A D V E R T I S E M E N T


Hex Constants in Applesoft David Bartley

Coding in BASIC has several frustrations for the assembly language programmer. One small but constant irritant for me has been the inability to directly specify hexadecimal values in Applesoft statements or in response to an INPUT command. I finally decided to do something about it when I read Bob Sander-Cederlof's article on the CHRGET routine in the September Apple Assembly Line. The result is the short program shown here.

My goal was to be able to enter a hex constant, defined as a "$" followed by one or more hex digits, anywhere Applesoft would allow an integer constant to appear. I nearly succeeded -- I'll discuss the exceptions a little later. I now can write statements like:


       100 FOR I = $0 TO $FF

       110 INPUT X,Y

       120 Z(I) = $100*X + Y - $3DEF

The responses to the INPUT statement may also be hex constants. Values may range from -$FFFF (-65535) to $FFFF (65535); the left-most bit is not considered a sign bit.

My program is set up by BRUN-ning the object file XB.A/S HEX CONSTANTS (see line 1010). Initialization consists of modifying the Applesoft CHRGET subroutine to branch into new code starting at line 1400. As you may recall, CHRGET is used by the BASIC interpreter to fetch characters and tokens from the program text of keyboard when a program is executing. The new CHRGET code watches for a "$" character; when one is found, it scans forward until it hits a character which is not a hex digit, converting to a binary value (in VAL) on the fly.

Variable IDX serves two purposes. It is normally negative, signifying that characters are to be fetched without special action until a "$" is encountered. After a hex constant is found and converted to a binary value, IDX becomes a positive index into a power-of-ten table to facilitate converting VAL to a decimal value. Each subsequent call to CHRGET then returns a successive character of the decimal integer representation of VAL until IDX becomes -1, the entire value has been transformed from hex to decimal, and the normal mode is restored.

There are, of course, several complications. One is the BASIC "DEF" command, which happens to consist of a string of hex digits. Applesoft therefore parses a constant like "$3DEF" as the ASCII characters "$" and "3" followed by the DEF token (hex 88). Lines 1760 to 1840 take care of that.

A more serious complication is the existence of a frequently used alternate entry point to CHRGET callled CHRGOT. CHRGOT is called to fetch the previous item from the text rather than the next one. It seems that numeric constants are parsed from several places within the Applesoft interpreter, with some using CHRGOT and others not. When I fixed things up so CHRGOT would work for inline constants and the INPUT command, it no longer worked for values in DATA statements (or for hex line numbers, for that matter!)

The trick that makes CHRGOT work (most of the time) is to back up TXTPTR and then return a leading zero to start off the converted decimal value. The zero causes no consternation for the parts of the interpreter that see it and is not missed by those that don't. If CHRGOT is not called, however, TXTPTR should not be backed up. You can't win!

I hope others will be able to make use of this routine -- better, that someone will overcome the problem with DATA statement values. It has been quite valuable to me as it is, as well as quite an education in understanding the inner workings of the Applesoft interpreter.


 1000         .OR $300

 1010         .TF XB.A/S HEX CONSTANTS

 1020  *---------------------------------

 1030  *

 1040  *      APPLESOFT HEX CONSTANTS

 1050  *

 1060  *      WRITTEN BY DAVID H. BARTLEY

 1070  *      AUSTIN, TEXAS -- AUGUST 1981

 1080  *

 1090  *      TO INITIALIZE:

 1100  *          BRUN THIS PROGRAM (XB.A/S HEX CONSTANTS)

 1110  *

 1120  *      TO USE:

 1130  *          PRECEDE HEX CONSTANTS

 1140  *          WITH A "$" CHARACTER

 1150  *

 1160  *---------------------------------

 1170  BASIC  .EQ $E003    SOFT RE-ENTRY

 1180  CHRGET .EQ $00B1    A/S CHRGET RTN

 1190  CHRGOT .EQ $00B7    A/S CHRGOT RTN

 1200  CHRCHK .EQ CHRGOT+3

 1210  TXTPTR .EQ $B8      A/S TEXT PTR

 1220  OVERR  .EQ $E8D5    OVERFLOW ERROR

 1230  TEMP   .EQ $FC      16-BIT TEMPORARY

 1240  VAL    .EQ $FE      16-BIT VALUE

 1250  *---------------------------------

 1260  INIT

 1270         LDA #$4C     MODIFY CHRGET

 1280         STA CHRGET   TO CALL HERE

 1290         LDA #NEW.CHRGET

 1300         STA CHRGET+1

 1310         LDA /NEW.CHRGET

 1320         STA CHRGET+2

 1330         JMP BASIC    RETURN TO A/S

 1340  NEXTCH

 1350         INC TXTPTR   DUPLICATE THE

 1360         BNE .10      OLD CHRGET

 1370         INC TXTPTR+1

 1380  .10    JMP CHRGOT

 1390  *---------------------------------

 1400  NEW.CHRGET

 1410         BIT IDX      NORMAL MODE?

 1420         BPL .60      -NO

 1430  *

 1440  * CHECK FOR "$" AS NEXT CHARACTER

 1450  *

 1460         JSR NEXTCH   GET CHAR

 1470         CMP #$24    "$"?

 1480         BNE .50      -NO, RETURN IT

 1490  .10

 1500  * PARSE A HEX NUMBER AND CONVERT

 1510  * IT TO A BINARY VALUE

 1520  *

 1530         LDA #0

 1540         STA VAL      VAL = 0

 1550         STA VAL+1

 1560         LDA #4       INDEX TO POWER

 1570         STA IDX

 1580  .20

 1590         JSR NEXTCH   GET HEX DIGIT

 1600         BEQ .40      -EOL OR ":"

 1610         SEC

 1620         SBC #$30     CHECK FOR DIGIT

 1630         BMI .35      -NOT A DIGIT

 1640         CMP #10

 1650         BCC .30      -OK (0-9)

 1660         SBC #17

 1670         BMI .40      -NOT A DIGIT

 1680         CMP #6

 1690         BCS .40      -NOT A DIGIT

 1700         ADC #10

 1710  .30    JSR ASL4     MULT VAL BY 16

 1720         ORA VAL      ADD NEW DIGIT

 1730         STA VAL

 1740         JMP .20

 1750  .35

 1760         CMP #$88     "DEF" TOKEN?

 1770         BNE .40      -NO

 1780         JSR ASL4     -YES

 1790         LDA VAL

 1800         ORA #$0D     ASL BY 12 AND

 1810         STA VAL+1    ADD $0DEF

 1820         LDA #$EF

 1830         STA VAL

 1840         BNE .20      (ALWAYS)

 1850  .40

 1860         LDA TXTPTR   BACK UP THE

 1870         BNE .41

 1880         DEC TXTPTR+1

 1890  .41    DEC TXTPTR

 1900         LDA TXTPTR   SAVE TXTPTR

 1910         STA TEMP     IN CASE IS IS

 1920         LDA TXTPTR+1 DECREMENTED

 1930         STA TEMP+1   BY THE CALLER

 1940  *

 1950         LDA #$30     ASCII "0"

 1960  .50    JMP CHRCHK   -EXIT

 1970  .60

 1980  * CONVERT BINARY VALUE TO DECIMAL

 1990  * AND RETURN THE NEXT ASCII DIGIT

 2000  *

 2010         LDA TEMP     FIX ANY ATTEMPT

 2020         STA TXTPTR   TO DECREMENT

 2030         LDA TEMP+1   TXTPTR

 2040         STA TXTPTR+1

 2050         STX SAVE.X

 2060         LDX IDX      POWER OF TEN

 2070         DEC IDX

 2080         LDA #$30     ASCII "0"

 2090  .70

 2100         PHA          ASCII DIGIT

 2110         LDA VAL

 2120         CMP LO.TENS,X  SET CARRY

 2130         LDA VAL+1

 2140         SBC HI.TENS,X

 2150         BCC .80      -EXIT LOOP

 2160         STA VAL+1

 2170         LDA VAL

 2180         SBC LO.TENS,X

 2190         STA VAL

 2200         PLA          ASCII DIGIT

 2210         CLC

 2220         ADC #1       INCREMENT IT

 2230         BNE .70      -LOOP

 2240  .80

 2250         PLA          ASCII DIGIT

 2260         LDX SAVE.X

 2270  .90

 2280         JMP CHRCHK   PROCESS IT

 2290  *---------------------------------

 2300  ASL4   JSR ASL2     ASL VAL BY 4

 2310  ASL2   JSR ASL1     ASL VAL BY 2

 2320  ASL1   ASL VAL      ASL VAL BY 1

 2330         ROL VAL+1

 2340         BCS OVFLOW   -OVERFLOW ERROR

 2350         RTS          -EXIT

 2360  OVFLOW

 2370         JMP OVERR    REPORT OVERFLOW

 2380  *---------------------------------

 2390  LO.TENS .DA #1

 2400         .DA #10

 2410         .DA #100

 2420         .DA #1000

 2430         .DA #10000

 2440  HI.TENS .DA /1

 2450         .DA /10

 2460         .DA /100

 2470         .DA /1000

 2480         .DA /10000

 2490  IDX    .DA #$FF     TABLE INDEX

 2500  SAVE.X .DA #0       SAVE X-REG

 2510  *---------------------------------

 2520  ZZZZZZ .EN


Applesoft Line Editing Aid Sandy Mossberg

[ Sandy is an M.D. in Port Chester, New York. You have probably seen his excellent articles and programs in NIBBLE. ]

The following program is a developmental tool for line-editing Applesoft programs. It places the line you specify at the top of the screen, ready to be cursor edited. The line is displayed without added blanks at the end of each screen line, which can mess up editing of PRINT statements. Obviously, adding Konzen-like PLE features would make it much nicer, but that's a story for another day.

The program loads at the ever-popular $300. If you BRUN it, or BLOAD and CALL768, it installs itself. To use it, type a slash and a line number. For example, to edit line 150, type "/150" and a carriage return. The screen will be cleared and line 150 displayed on the top. The cursor will be placed over the first character, and you will be ready to edit it with standard cursor-editing techniques. (If there is no line 150 in memory, the bell will ring instead.)

Several aspects of the code should be of interest to assembly language programmers:

  1. As noted in AAL of 9/81, the CHRGET/CHRGOT routine screens for the command character (a slash). This technique permits concurrent use of an amper-utility. The KSW hook could be employed as yet another filter, making a trio of vectors operative.
  2. To allow "illegal" line numbers (64000-65535) to be accessed, the LINGET routine is replaced by calls to FRMEVL and GETADR (see Lines 1800-1810).
  3. The de-parsing secton (see Lines 2030-2500) is an offspring of Applesoft's LIST routine, modified to pring a single program line rather than an entire listing. I also eliminated the code which adds those extra blanks in the middle of quoted strings which take more than one screen line to LIST. To me it seems pretty neat!

Since I did not make any test to determine whether or not the program is RUNning at the time the slash is trapped in my filter, you have to be careful about using the slash character in REM statements. For example, "REM /150" will clear the screen and list line 150 at the top before proceeding. Other combinations of "/" in REM's may blow up. Also, typing "/" when Applesoft is executing an INPUT statement is now dangerous. Anyone know how to fix this?


 1000  *---------------------------------

 1010  *           LINE.EDIT

 1020  *

 1030  *       BY SANDY MOSSBERG

 1040  *

 1050  *   COMMERCIAL RIGHTS RESERVED

 1060  *

 1070  *---------------------------------

 1080  * 1.PACKS PROGRAM LINE FOR EASY EDITING.

 1090  *

 1100  * 2.USES CHRGET/CHRGOT FILTER ROUTINE NOTED IN AAL 9/81.

 1110  *

 1120  * 3.CHARACTER OUTPUT ROUTINE MODIFIED FROM APSOFT ROM

 1130  *   CODE (LIST, $D6A5-$D765).

 1140  *

 1150  * 4.INSTALLATION AND USE:

 1160  *    (A) BRUN LINE.EDIT.

 1170  *    (B) COMMAND "/LINENUMBER" PRODUCES PACKED LINE AT

 1180  *        TOP OF SCREEN.

 1190  *    (C) IF CHRGET/CHRGOT VECTOR DESTROYED BY APSOFT

 1200  *        COLDSTART (]FP, *E000G, *CTL-B), RESET LINE.EDIT

 1210  *        VECTOR BY CALL 768.

 1220  *---------------------------------

 1230             .OR $300

 1240  *---------------------------------

 1250  *          APPLESOFT POINTERS

 1260  *---------------------------------

 1270  AS.FORPNT  .EQ  $85     ;HOLD Y-REGISTER

 1280  AS.LOWTR   .EQ  $9B,$9C ;LOCATION OF CHARACTER OR TOKEN IN PGM

 1290  AS.DSCTMP  .EQ  $9D,$9E ;LOCATION IN KEYWORD TABLE

 1300  *---------------------------------

 1310  *          APPLESOFT CHRGET/CHRGOT

 1320  *---------------------------------

 1330  AS.CHRGET  .EQ  $B1     ;GETS CHARACTER AT TEXT POINTER

 1340  AS.TXTPTR  .EQ  $B8,$B9 ;TEXT POINTER

 1350  AS.CHREXT  .EQ  $BA     ;CHRGET/CHRGOT VECTOR TO LINE.EDIT

 1360  AS.CHRENT  .EQ  $BE     ;RE-ENTRY TO CHRGET/CHRGOT

 1370  *---------------------------------

 1380  *          APPLESOFT ROM

 1390  *---------------------------------

 1400  AS.FNDLIN  .EQ  $D61A   ;ADDR NMBR IN LINNUM ($50,$51) TO LOWTR

 1410  AS.CRDO    .EQ  $DAFB   ;LINEFEED

 1420  AS.OUTSP   .EQ  $DB57   ;OUTPUT SPACE

 1430  AS.OUTDO   .EQ  $DB5C   ;OUTPUT CHARACTER

 1440  AS.FRMEVL  .EQ  $DD7B   ;FORMULA AT TEXT POINTER TO FAC ($9D-$A2)

 1450  AS.GETADR  .EQ  $E752   ;FAC TO INTEGER IN LINNUM ($50,$51)

 1460  AS.LINPRT  .EQ  $ED24   ;PRINT DECIMAL OF (A,X)

 1470  *---------------------------------

 1480  *          MONITOR ROM

 1490  *---------------------------------

 1500  MON.TABV   .EQ  $FB5B   ;VTAB TO VALUE IN (A)

 1510  MON.HOME   .EQ  $FC58   ;HOME CURSOR, CLEAR SCREEN

 1520  MON.BELL   .EQ  $FF3A   ;BEEP!

 1530         .PG

 1540  *---------------------------------

 1550  *  PUT LINE.EDIT VECTOR INTO CHRGET/CHRGOT

 1560  *---------------------------------

 1570  START  LDA #$4C         ;JMP 'LINE.EDIT'

 1580         STA AS.CHREXT

 1590         LDA #EDIT

 1600         STA AS.CHREXT+1

 1610         LDA /EDIT

 1620         STA AS.CHREXT+2

 1630  RTS1   RTS

 1640  *---------------------------------

 1650  *  CHECK FOR VALID COMMAND

 1660  *---------------------------------

 1670  EDIT   CMP #$2F         ;IS IT A SLASH (/)?

 1680         BNE .1           ;NO. RETURN

 1690         INC AS.TXTPTR    ;YES. BUMP TEXT POINTER

 1700         BNE .2           ;BRANCH ALWAYS

 1710  *---------------------------------

 1720  *  RETURN TO CHRGET/CHRGOT OR CALLER

 1730  *---------------------------------

 1740  .1     CMP #$3A         ;IF COLON (EOS), SET Z AND C

 1750         BCS RTS1         ; FLAGS AND RETURN TO CALLER

 1760         JMP AS.CHRENT    ;IF NOT EOS, RE-ENTER CHRGET/CHRGOT

 1770  *---------------------------------

 1780  *  FIND LOCATION OF LINE NUMBER

 1790  *---------------------------------

 1800  .2     JSR AS.FRMEVL    ;PUT LINE NUMBER INTO FAC ($9D-$A2)

 1810         JSR AS.GETADR    ;PUT FAC INTO LINNUM ($50,$51)

 1820         JSR AS.FNDLIN    ;PUT ADDR OF LINE INTO LOWTR

 1830         BCC .5           ;CARRY CLEAR IF LINE NMBR NOT FOUND

 1840  *---------------------------------

 1850  *  CLEAR SCREEN AND SET TO ROW 2, COLUMN 2

 1860  *---------------------------------

 1870         JSR MON.HOME

 1880         JSR AS.CRDO

 1890         JSR AS.OUTSP

 1900  *---------------------------------

 1910  *  PRINT LINE NUMBER

 1920  *---------------------------------

 1930         LDY #02          ;SET INDEX TO LINE NUMBER BYTES

 1940         LDA (AS.LOWTR),Y ;PUT LINE NUMBER LO

 1950         TAX              ; INTO (X)

 1960         INY

 1970         LDA (AS.LOWTR),Y ;PUT LINE NUMBER HI INTO (A)

 1980         STY AS.FORPNT    ;HOLD (Y)

 1990         JSR AS.LINPRT    ;PRINT DECIMAL OF (A,X)

 2000  *---------------------------------

 2010  *  GET CHARACTER OR TOKEN

 2020  *---------------------------------

 2030         LDA #$20         ;SPACE

 2040  .3     LDY AS.FORPNT    ;RESTORE (Y)

 2050  .4     JSR AS.OUTDO     ;PRINT CHARACTER IN (A)

 2060         INY

 2070         LDA (AS.LOWTR),Y ;GET CHARACTER OR TOKEN

 2080         BNE .8           ;IF NOT EOS (0), GET MORE

 2090         .PG

 2100  *---------------------------------

 2110  *  TWO ENDINGS -- ONE HAPPY, ONE SAD

 2120  *---------------------------------

 2130         LDA #00          ;LINE WAS FOUND. END WITH

 2140         JMP MON.TABV     ; CURSOR AT ROW 2, COLUMN 2

 2150  .5     JSR MON.BELL     ;LINE WAS NOT FOUND. END WITH

 2160         JMP AS.CRDO      ; CURSOR BELOW COMMAND INPUT

 2170  *---------------------------------

 2180  *  GET CHARACTER IN KEYWORD TABLE

 2190  *---------------------------------

 2200  .6     INY  

 2210         BNE .7

 2220         INC AS.DSCTMP+1

 2230  .7     LDA (AS.DSCTMP),Y

 2240         RTS

 2250  *---------------------------------

 2260  *  PRINT CHARACTER OR KEYWORD

 2270  *---------------------------------

 2280  .8     BPL .4           ;NON-TOKEN IS POS ASCII

 2290         SEC              ;TOKEN MINUS $7F EQUALS INDEX TO

 2300         SBC #$7F         ; LOCATION OF KEYWORD IN TABLE

 2310         TAX              ;PUT INDEX IN (X)

 2320         STY AS.FORPNT    ;HOLD (Y)

 2330         LDY #$D0         ;KEYWORD TABLE STARTS AT $D0D0

 2340         STY AS.DSCTMP

 2350         LDY #$CF

 2360         STY AS.DSCTMP+1

 2370         LDY #$FF         ;WHEN BUMPED, (Y) WILL BE ZERO

 2380  .9     DEX              ;DEC INDEX TO KEYWORD LOCATION

 2390         BEQ .11          ;WHEN (X) IS ZERO, KEYWORD LOCATED

 2400  .10    JSR .6           ;GET CHARACTER IN KEYWORD TABLE

 2410         BPL .10          ;IF POS ASCII, GET ANOTHER

 2420         BMI .9           ;IF NEG ASCII, DEC LOCATION INDEX

 2430  .11    JSR AS.OUTSP     ;PRINT SPACE

 2440  .12    JSR .6           ;GET CHARACTER IN KEYWORD TABLE

 2450         BMI .13          ;IT'S THE FINAL CHAR IN KEYWORD

 2460         JSR AS.OUTDO     ;PRINT NON-FINAL CHAR (POS ASCII)

 2470         BNE .12          ;BRANCH ALWAYS

 2480  .13    JSR AS.OUTDO     ;PRINT FINAL CHAR (NEG ASCII)

 2490         LDA #$20         ;SPACE

 2500         BNE .3           ;BRANCH ALWAYS

 2510  *---------------------------------

 2520  SIZE   .EQ *-START

 2530         .PG


Improved Applesoft Fast String Input Bob Sander-Cederlof

In the April 1981 issue of AAL I printed a subroutine to read a line from the keyboard or a text file into an Applesoft string. The original version had a minor flaw (or major, if you happened to run into it): it left the high-order bit on in each byte, so that Applesoft could not compare them properly with strings from other sources. I printed a correction in a later issue, which stripped off the leading bit from each byte before putting it in the string.

Now Sherm Ostrowsky (from Goleta, California) has pointed out a more elegant solution. He uses a subroutine inside Applesoft that reads a line, terminates it with hex 00, and strips off the leading bit from each byte. The subroutine starts at $D52C. The only thing it doesn't do that we need is give us the length of the input line. Here is a commented listing of it.


 1000  *---------------------------------

 1010  *      APPLESOFT LINE INPUT SUBROUTINE

 1020  *---------------------------------

 1030         .OR $D52C

 1040         .TA $82C

 1050  *---------------------------------

 1060  MON.PROMPT .EQ $33

 1070  MON.RDLINE .EQ $FD6A

 1080  BUFFER     .EQ $200

 1090  *---------------------------------

 1100  AS.INLINE

 1110         LDX #$80     NULL CHARACTER

 1120  INLIN2 STX MON.PROMPT  FOR THE PROMPT CHARACTER

 1130         JSR MON.RDLINE  READ A LINE INTO BUFFER

 1140         CPX #239     TRUNCATE TO 239 CHARACTERS

 1150         BCC .1

 1160         LDX #239

 1170  .1     LDA #0       MARK END OF LINE WITH $00

 1180         STA BUFFER,X

 1190         TXA          # REAL CHARS IN LINE

 1200         BEQ .3       EMPTY LINE

 1210  .2     LDA BUFFER-1,X  STRIP OFF ALL SIGN BITS

 1220         AND #$7F

 1230         STA BUFFER-1,X

 1240         DEX

 1250         BNE .2

 1260  .3     LDA #0

 1270         LDX #BUFFER-1

 1280         LDY /BUFFER-1

 1290         RTS

Since $D52C stores $80 (null) in the prompt character, you might want to load the X-register with $87 (bell) and enter at $D52E instead.

Since the subroutine returns with $FF in the X-register, and we need the length of the input line instead, we can use the following code to get the line length in X:


            JSR $D52C

     .1     INX

            LDA $200,X

            BNE .1

Here is a new version, then, of my fast string input subroutine:


 1000  *---------------------------------

 1010  *      FAST STRING INPUT ROUTINE

 1020  *      &GET <STRING VARIABLE>

 1030  *      ACCEPTS ANY CHARACTER, UNLIKE NORMAL INPUT

 1040  *---------------------------------

 1050         .OR $300

 1060         .TF B.FAST READ

 1070  *---------------------------------

 1080  AS.CHRGET  .EQ $00B1

 1090  AS.SYNERR  .EQ $DEC9

 1100  AS.INLINE  .EQ $D52C

 1110  AS.PTRGET  .EQ $DFE3

 1120  AS.GETSPA  .EQ $E452

 1130  AS.MOVSTR  .EQ $E5E2

 1140  *---------------------------------

 1150  ADDR       .EQ $71 AND 72

 1160  PNTR       .EQ $83 AND 84

 1170  LENGTH     .EQ $9D

 1180  BUFFER     .EQ $200

 1190  *---------------------------------

 1200  GET    CMP #$BE     "GET" TOKEN

 1210         BEQ .1       YES

 1220         JMP AS.SYNERR  SORRY...

 1230  .1     JSR AS.CHRGET SET UP THE FOLLOWING CHARACTER

 1240         JSR AS.PTRGET FIND THE STRING VARIABLE POINTER

 1250         JSR AS.INLINE READ A LINE INTO BUFFER

 1260  .2     INX          COMPUTE THE LENGTH OF THE LINE

 1270         LDA BUFFER,X

 1280         BNE .2       NOT AT END OF LINE YET

 1290         STX LENGTH   SAVE LINE LENGTH

 1300         TXA

 1310         JSR AS.GETSPA  GET SPACE IN STRING AREA

 1320         LDY #0       SET UP STRING VARIABLE POINTER

 1330         STA (PNTR),Y   LENGTH

 1340         INY

 1350         LDA ADDR

 1360         STA (PNTR),Y   ADDRESS (LO-BYTE)

 1370         INY

 1380         LDA ADDR+1

 1390         STA (PNTR),Y   ADDRESS (HI-BYTE)

 1400         LDY /BUFFER    SET UP TO COPY STRING DATA

 1410         LDX #BUFFER    INTO STRING AREA

 1420         LDA LENGTH

 1430         JMP AS.MOVSTR  COPY IT NOW, AND RETURN

Here is how you might use it from an Applesoft program, to read a series of lines from a file:


     100 D$ = CHR$ (4)

     110 PRINT D$"BLOAD B.FAST READ"

     120 POKE 1013,76 : POKE 1014,0 : POKE 1015,3

     210 PRINT D$"OPEN MY.FILE"

     220 PRINT D$"READ MY.FILE"

     230 FOR I = 1 TO 10

     240 & GET A$(I)

     250 NEXT I

Note that the subroutine is fully relocatable. Since there are no internal JMP's or JSR's, and no internal variables, you can load the program anywhere it will fit and run it without any modifications. Just be sure to change line 120 above to POKE the correct address in 1014 and 1015.


Adding ASCII to Apple Monitor Dump Bob Sander-Cederlof

Peter Bartlett (subscriber in Chicago, IL) sent me some source code for patches to the Apple Monitor ROM. Of course, patching a ROM may be a little too much hardware work, but if you have a 16K RAM card you can put the revised monitor up there. The space needed for the patch is stolen from the cassette I/O command, so if you install this patch you will lose cassette I/O.

Peter's patches add the ASCII dump to the Apple Monitor's hex dump. That is, when I type a command like "800.87F" in the monitor, it will not only print out the hex values, but also the ASCII values of each byte. I modified his patches a little, to shorten the code to the following:


 1000 *---------------------------------

 1010 *    PATCHES TO ADD ASCII DUMP

 1020 *    TO THE APPLE MONITOR

 1030 *---------------------------------

 1040 A1L    .EQ $3C

 1050 COUT   .EQ $FDED

 1060 *---------------------------------

 1070        .OR $FDB8

 1080        .TA $0DB8

 1090        JSR PATCH     CALL MY PATCH CODE

 1100 *---------------------------------

 1110        .OR $FCC9

 1120        .DA $0CC9

 1130 PATCH

 1140        JSR COUT      PRINT A SPACE

 1150        LDA (A1L),Y   GET BYTE TO BE DISPLAYED

 1160        PHA           SAVE IT ON STACK

 1170        LDA A1L       LOW BYKTE OF DUMP ADDRESS

 1180        AND #7        MASK LINE POSITION

 1190        CLC           

 1200        ADC #41       COMMPUTE HORIZONTAL OFFSET

 1210        TAY           

 1220        PLA           GET BYTE FROM STACK

 1230        STA ($28),Y   STORE IT ON THE SCREEN

 1240        LDY #0        RESTORE Y

 1250        RTS           REJOIN ORIGINAL CODE

These patches will work with either the old monitor ROM, or the Autostart ROM. The JSR PATCH line goes right into the hex dump program, over the top of a JSR COUT that printed a space. That space is normally printed right before the next byte value is printed in hex. The address of the next byte is kept in A1L,A1H ($3C,3D). The Y-register has 0 in it.

The main patch subroutine is stored on top of part of the cassette tape I/O, at $FC99; it begins with the JSR COUT that was covered up at $FDB8. Lines 1150,1160 pick up the byte to be displayed and save it on the stack. Lines 1170-1210 compute the horizontal postition for poking the byte on the screen. The low-order three bits of the memory address determine which column will be used, from column 31 through 38. Lines 1220,1230 retrieve the byte from the stack and store it into the screen buffer. Lines 1240,1250 restore Y=0 and return to the hex dump subroutine.

Note that this patch does not "print" the ASCII codes on the screen; it "pokes" them. Therefore if your printer is on, the printed copy will only contain the hex dump. The ASCII codes will only appear on the screen.

How do you patch the RAM card version of the monitor? Here's how I did it:

  1. Load the language card using your DOS 3.3 Master Disk, or whatever technique you like to use.
  2. Turn on the language that is in the card (using FP or INT).
  3. BSAVE MONITOR,A$F800,L$800.
  4. BRUN ASMDISK 4.0
  5. BLOAD MONITOR,A$800
  6. Enter the source code for the patches and assemble them with the ASM command. This will patch the monitor copy which you loaded at A$800 in step 5.
  7. Type "$C081 C081" to write enable the language card.
  8. Type "$F800<800.FFFM" to move the patched monitor into the real monitor space.
  9. Type "BSAVE <your file name>,A$D000,L$3000" to save the combined language and monitor for later loading into the language card.

If you really do want to burn a new monitor ROM, follow the instructions with your ROM Burner.


Applesoft GOTO from Assembly Language Bob Sander-Cederlof

Bob Potts called the other day with an interesting question. Suppose you want to jump to a particular line (by line number) of an Applesoft program, rather than simply returning from an assembly language program.

For example, I might call an assembly language subroutine at $300 with "CALL 768". After it does its job, the subroutine may decide either to return to the following Applesoft statement by an "RTS" instruction, or to GOTO a particular line number in the program. (Perhaps an error processing subroutine in the Applesoft code.) Can it be done?

Yes, and it is fairly simple. First we need to put the binary value of the line number into locations $50 and $51. Then we must jump to $D944 in the Applesoft ROMs to finish the GOTO operation. Here is the code to jump to line number 1350, for example:


     GOTO1350 LDA #1350   LOW BYTE OF "1350"

              STA $50

              LDA /1350   HIGH BYTE OF "1350"

              STA $51

              JMP $D955   APPLESOFT GOTO PROCESSOR

That's all there is to it!

I wrote a tiny little subroutine to demonstrate that this works. It expects to find the line number in $2FE and $2FF. You can POKE it there before CALLing 768. Here is my subroutine:


 1000  *---------------------------------

 1010  *      GO TO <LINE #>

 1020  *      POKE THE LINE # INTO 766,767

 1030  *      AND CALL768 TO GO TO IT

 1040  *---------------------------------

 1050         .OR $300

 1060  GOTO   LDA $2FE

 1070         STA $50

 1080         LDA $2FF

 1090         STA $51

 1100         JMP $D944

Now here is a test program in Applesoft. Can you tell what it will do before you try it? The first two lines poke in the GOTO subroutine. The next five lines call the subroutine for successive values 1000, 2000, 3000 etc. up to 9000. The code in line 10000 jumps back to line 140 to continue the loop. Try it!


   10  FOR I = 0 TO 12: READ A: POKE 768 + I,A: NEXT 

   20  DATA 173,254,2,133,80,173,255,2,133,81,76,68,217

  100  FOR I = 1000 TO 9000 STEP 1000

  110  IH =  INT (I / 256): IL = I - IH * 256

  120  POKE 766,IL: POKE 767,IH

  130  CALL 768

  140  NEXT I

  150  END 

 1000  PRINT 1000: GOTO 10000

 2000  PRINT 2000: GOTO 10000

 3000  PRINT 3000: GOTO 10000

 4000  PRINT 4000: GOTO 10000

 5000  PRINT 5000: GOTO 10000

 6000  PRINT 6000: GOTO 10000

 7000  PRINT 7000: GOTO 10000

 8000  PRINT 8000: GOTO 10000

 9000  PRINT 9000

10000  POKE 766,140: POKE 767,0: CALL 768


Apple Assembly Line is published monthly by S-C SOFTWARE, P. O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $12 per year in the U.S.A., Canada, and Mexico. Other countries add $12/year for extra postage. Back issues are available for $1.20 each (other countries add $1 per back issue for 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.)