| Volume 8 -- Issue 4 | January 1988 |
The Apple Assembly Line is still growing! I now am sending out over 300 copies per month! It is also growing in size, as you can see: this is the first 20 page issue.
In This Issue...
New Subscription Rates
For the first time since January of 1984, we are going to have to increase our subscription rates. The Post Office is raising the postage again, for the third time since then, and we have to respond. Of course postage is not the only expense that has increased, just the most recent, and most noticeable. Here are the old and new rates for a year's subscription:
Newsletter Only, 12 issues: Current New
Bulk Mail (USA only) . . . . . . . . . . $18 ---
First Class Mail (USA, Canada, Mexico) . $21 $24
All Other Countries . . . . . . . . . . $32 $36
Newsletter plus the Monthly Disk, 12 issues:
USA, Canada, Mexico . . . . . . . . . . $64 $64
All Other Countries . . . . . . . . . . $87 $90
You will notice that the Bulk Mail option is being phased out, as I am planning to mail by First Class to all USA subscribers. The reliability of Bulk Mail has been entirely too erratic, and increasingly so.
You will also notice that the price of a subscription including disk, delivered in the USA, Canada, or Mexico, has not increased at all. Maybe now is the time to upgrade, and save yourself a lot of typing?
The new prices go into effect for new subscriptions as of March 15, 1988. Renewals at the old prices (but no more bulk mail) will continue to be accepted through the 4th of April.
| Another Peek Inside AppleWorks: Interpretive String Display Subroutine |
Bob Sander-Cederlof |
At least twice in the last eight years I have published fancy message display subroutines. In the original Volume 1, Number 1, way back in October, 1980, I gave a really nice 40-column version. That one was actually used in a slightly different form inside a system that we developed for the American Heart Association for teaching Cardio-Pulmonary Resuscitation (CPR).
In the April 1987 issue I published an 80-column version for the //e and //c, which had similar but more powerful capabilities.
Last month I started revealing some of the code from inside AppleWorks (version 1.3). I covered parameter passing and some string handling subroutines, plus block move. I also described and printed the subroutine which polls the keyboard, so that you can type before being asked. POLL.KEYBOARD is called from all over everywhere, just to be sure no characters are lost. I mention that, because there is a call to it from the code I am unveiling this month. In the listing which follows, I have put a dummy POLL.KEYBOARD subroutine which simply does an RTS. In the real AppleWorks code, DISPLAY.STRING calls the real POLL.KEYBOARD.
As I mentioned last month, I am NOT showing in these pages the exact code you would find inside AppleWorks. Since my purpose is not to document AppleWorks, but rather to cull out generally useful code which we can adapt and use, I have rearranged and modified a little. My versions are, in general, shorter and faster. Maybe whoever is currently maintaining AppleWorks at Claris will notice and use these improvements.
In case you ARE interested in documenting AppleWorks, or just want to see what I changed, I have included comment lines with each segment of code which show what the corresponding address was inside AppleWorks 1.3. As was true last month, all the code shown here is found in the main segment called APLWORKS.SYSTEM, which begins at $1000 once it is up and running.
I will begin with a general description of features. DISPLAY.STRING began at $14D1, and there are numerous calls to it in the code. There is also a JMP vector to it in the JMP table which begins at $1000; if you find any JSR $1015 instructions in any of the other segments, they are calling this DISPLAY.STRING subroutine. Unlike all of the subroutines I discussed last month, this subroutine does not expect to find parameters following the JSR which called it. Instead, it expects the length of the string to be in the A-register, and the address of the string to be in locations $80,81. (There is another subroutine which uses the parameter-passing protocol to display a string which starts with a length byte; it simply sets up $80, $81, and the A-register and calls DISPLAY.STRING. You can find it at $2093, with a JMP vector at $1087.)
DISPLAY.STRING does not use any Apple firmware at all. The display techniques used here work faster than the firmware, because they are dedicated to 80-columns and do not have to retain any compatibility with older machines. If you remember that the original Apple //e firmware scrolled the 80-column screen with a slow zigzag motion, you can see why Rupert Lissner decided to code his own.
The characters within the string to be displayed consist of control codes and displayable characters. Displayable characters include the full upper- and lower-case alphabet, numbers, and punctuation signs; all of these can be displayed in both normal and inverse mode. All 32 "mouse-text" characters can also be displayed, although the only one I have noticed in quickly scanning through the AppleWorks messages is the open-apple.
Inverse and normal mode is controlled by a flag byte, which I have called INVERSE.FLAG in my code. It is located at $14D0 in AppleWorks. If that byte contains $00, characters will display in inverse; if $80, normal. A pair of control codes lets you switch INVERSE.FLAG back and forth from within a string, or you can directly set it between calls to DISPLAY.STRING.
The following table shows the hex values for the various character groups as interpreted by DISPLAY.STRING:
00-1F Control Codes
20-7F 96 ASCII Characters
80-9F 32 Mouse Text Characters
The codes 20-7F display in either normal or inverse, depending on INVERSE.FLAG, as described above. Codes C0-DF duplicate 80-9F, displaying the mouse text characters; codes A0-BF and E0-FF both display the 32 lower-case characters in inverse mode.
There are a couple of un-features in DISPLAY.STRING. There is a JMP $1815 instruction located at $1815 inside AppleWorks 1.3. This, of course, hangs up the Apple. The only way out is by hitting RESET. DISPLAY.STRING goes to this HANG.UP code under some circumstances. Since it is a deadly trap, I assume the author of AppleWorks used to have some debugging code there. It gets called from all over, when errors occur that are programming bugs. There is even a JMP vector to it in the JMP table, at $101B! I have left the jumps and branches to HANG.UP in my version, but you might want to modify them to do something reasonable if you are going to use DISPLAY.STRING yourself.
The other un-feature is what happens if you try to print past the right edge of the text window. You might think it would automatically wrap to the next line, like the standard Apple firmware does; no, it just piles up the characters at the end of the line like old manual typewriters used to do. Possibly you might consider a third un-feature to be the limitation of 255 characters in a string, but this is easy enough to work around. My demonstration program, included at the end of the following listing, shows one way.
There are 17 control codes interpreted by DISPLAY.STRING, and room for adding 15 more. Most of these are single byte codes, but two are followed by parameter bytes. Here is a table of the codes:
01 -- Clear from cursor to end of line.
02 -- Clear entire line cursor is on.
03 -- Home (go to 0,0 and clear window).
04 -- Clear from cursor to end of window.
05xxyy -- Move cursor to column xx, row yy of window
(HANG.UP if string ends with no xxyy).
06 -- Move cursor left (HANG.UP if beyond window).
07 -- Move cursor right (HANG.UP if beyond window).
08 -- Move cursor up, scroll if already at top.
09 -- Move cursor down, scroll if alread at bottom.
0A -- Set inverse mode.
0B -- Set normal mode.
0C -- Store current cursor position as bottom-right
corner of the window.
0D -- Move cursor to beginning of current line.
0E -- Store current cursor position as top-left
corner of the window.
0F -- Set up a full-screen window.
10 -- Beep! (the AppleWorks low-tone bell).
11xx -- Slide the screen sideways xx columns.
If xx>0 slide to right; if xx<0, slide left.
You can see that setting windows is fairly easy. Use code 05xxyy to position the cursor where you want the bottom-right corner of the new window to be, and then use code 0C to store it; then use 05xxyy to position the cursor where you want the top-left corner of the new window to be, and then use code 0E to make the new window. Since all 05xxyy moves are relative to the current window, you need to set the new bottom-right corner first. (You should now have a clue how AppleWorks nests the file folders on the screen.)
Since AppleWorks does not use any of the Apple firmware, it is also not tied to the standard page-zero locations for window info and cursor position. DISPLAY.STRING uses $10 through $13 to store the window definition. It is not the same as Apple's window definition bytes at $20-$23. Apple's firmware uses a starting column and a width, whereas AppleWorks uses a starting column and an ending column. The bytes are in a different order, too. See lines 1030-1130 for DISPLAY.STRINGs page zero-usage. The two bytes defined in lines 1120-1130, at $F0 and $F1, are the ones AppleWorks uses. However, you could change those two lines to share $18 and $19 with the labels defined on lines 1090-1100, if you wish.
Lines 1150-1320 define two macros, one for storing a byte on the screen and one for picking a byte off the screen. There is another macro definition in lines 4820-4840, for the function vector table. I decided to put these in as macros to shorten the program listing so it would fit in this issue of AAL. It also makes the code in the left-right scroll subroutine easier to follow. My code inside these macros is different from the code in AppleWorks: it is shorter, and on the average one cycle SLOWER. I more than made up for the speed loss in other places, though.
You will find the main body of DISPLAY.STRING in lines 1390-1920. Lines 1470-1480 are curious. They cause the entire call to DISPLAY.STRING to be ignored if the contents of $A4 is non-zero. I don't know why or when AppleWorks would use this. Probably you will want to delete these two lines if you use a revision of DISPLAY.STRING in your own programs. In that case, you would want to substitute a LDA #0 instruction, so that line 1490 would store a zero as the beginning position in the string to be displayed. Line 1500 calls the POLL.KEYBOARD subroutine, which as I mentioned above is just a dummy routine in this listing. You will probably want to delete this line too.
By the time we get to line 1520, everything is set up. A pointer to the first character of the string is in $80,81; POSITION.IN.STRING holds the index relative to that pointer for the next character to be processed; INVERSE.FLAG is either 00 or 80; and BYTES.IN.STRING is set to the string length. We come back to line 1520 for each character in the string, except for the parameter bytes on control codes 05 and 11.
Lines 1520-1540 test to see if we have finished the string, and go to an RTS if so. Lines 1550-1670 pick up the next character, and decide how to process it according to the range: values 80-FF are treated as mouse text, even though we only expect 80-9F for these; values 00-1F are control (function) codes; and values 20-7F are regular ASCII characters.
Mouse text characters are really put on the screen by using values from $40 to $5F, so lines 1680-1700 do the honors.
Regular ASCII characters are EORed with the INVERSE.FLAG in line 1600. If the result is negative, we have a "normal" character; if positive, "inverse". Normal characters are ready now to display, but inverse take some care. The range 40-5F should print as letters rather than mouse text, so they are mapped down to 00-1F in lines 1620-1670.
Control codes are handled in lines 1830-1920. This is not the same way AppleWorks did it. AppleWorks used the trick of pushing the table address on the stack and doing an RTS to effectively JMP to the function code; then each function code processor finished by doing a JMP $14E1 (my line 1520, label .1). My code effectively does a JSR to the function code, so each processor can finish by doing an RTS. This saves space, but is a tiny bit slower. However, I made up for the speed loss by eliminating one unnecessary range check. AppleWorks tested the function code range to be sure it was no larger than $11; if it was larger, AppleWorks jumped to HANG.UP. My code gives the same results, by merely extending the function code table in lines 4870-5190 to include all 32 vectors. The extra 28 bytes of table are more than saved elsewhere. By making the function code processors into subroutines which end with an RTS I have made them accessible to JSR calls from anywhere. This could save even more space.
You can see that to add more functions you merely have to write the processing subroutines and enter the vectors in the function code table using the >VEC macro. I can think of several neat additions. For example, I might use code 00 to initialize full screen, home, normal mode all in one code. It might also be useful to add a code to draw a file folder in the current window. A single code could shrink the window one notch, clear it, and draw a folder. Another code could pop back out to the next larger window. Let your imagination and creativity loose!
I wrote a little demonstration program, shown in lines 6040-6270. This program steps through a list of strings. Each string starts with a length byte. When a length byte of 00 is found, the demonstration stops. I have listed the demonstration strings in raw form to save paper, in lines 6290-6970. The demonstration is not too fancy, but it is fun. I display some characters, then move them around the screen in all four directions, with intermittent beeps to slow it down enough to see. Then I wipe it clean and display the entire character set.
Let me know how you like this series of articles, and what kind of uses you find for the code. If you come up with some really great new function codes for DISPLAY.STRING, send them in and we'll share them in future issues.
1000 .LIST MOFF Do not show Macro Expansions (save paper)
1010 *SAVE AW.SUBS.2
1020 *--------------------------------
1030 AW.LEFT .EQ $10 DEFINES CURRENT WINDOW
1040 AW.TOP .EQ $11 "
1050 AW.RIGHT .EQ $12 "
1060 AW.BOTTOM .EQ $13 "
1070 AW.CH .EQ $14 CURSOR HORIZONTAL
1080 AW.CV .EQ $15 CURSOR VERTICAL
1090 AW.BASE .EQ $16,17
1100 AW.BASE2 .EQ $18,19
1110 *--------------------------------
1120 SHUFFLE.SOURCE .EQ $F0
1130 SHUFFLE.DEST .EQ $F1
1140 *--------------------------------
1150 .MA ST.SCRN
1160 LSR LSB into Carry
1170 TAY Index into Y-reg
1180 PLA Get char again
1190 BCS :1 ...Odd character, in Main RAM
1200 STA $C055 ...Even character, in Aux RAM
1210 :1 STA (AW.BASE),Y
1220 STA $C054
1230 .EM
1240 *--------------------------------
1250 .MA LD.SCRN
1260 LSR LSB into Carry
1270 TAY Index into Y-reg
1280 BCS :1 ...Odd character, in Main RAM
1290 STA $C055 ...Even character, in Aux RAM
1300 :1 LDA (AW.BASE),Y
1310 STA $C054
1320 .EM
1330 *--------------------------------
1340 INVERSE.FLAG .BS 1 00=display chars inverse, 80=display chars normal
1350 BYTES.IN.STRING .BS 1
1360 POSITION.IN.STRING .BS 1
1370 SCROLL.DIRECTION .BS 1
1380 *--------------------------------
1390 * DISPLAY A STRING WITH FUNCTION CODES
1400 * (A) = # BYTES IN STRING
1410 * ($80,81) = Address of string
1420 * ($A4) = flag: if 00 display, else ignore.
1430 * at $14D1 in AppleWorks 1.3
1440 *--------------------------------
1450 DISPLAY.STRING
1460 STA BYTES.IN.STRING
1470 LDA $A4 If non-zero, don't display anything
1480 BNE .99 ...to an RTS
1490 STA POSITION.IN.STRING
1500 JSR POLL.KEYBOARD GET KEY IF ANY
1510 *--------------------------------
1520 .1 LDY POSITION.IN.STRING
1530 CPY BYTES.IN.STRING
1540 BCS .99 ...to an RTS
1550 INC POSITION.IN.STRING
1560 LDA ($80),Y GET CHAR FROM STRING
1570 BMI .2 ...80-FF, Mouse char for screen
1580 CMP #$20
1590 BCC .5 ...00-1F
1600 EOR INVERSE.FLAG
1610 BMI .3 ...Normal Char
1620 CMP #$40 ...Inverse char
1630 BCC .3 ...00-3F, inverse A-Z, 0-9, punctuation
1640 CMP #$60
1650 BCS .3 ...60-7F, inverse a-z, punctuation
1660 AND #$BF map 40-5F into 00-1F, more A-Z
1670 BCC .3 ...always
1680 *---Display a Mouse Char---------
1690 .2 AND #$7F ...map into 40-5F, mouse char range
1700 ORA #$40
1710 *---Display Char in A-register---
1720 .3 PHA Save the character
1730 JSR BASE.CALC.CV
1740 LDA AW.CH Char position on line
1750 >ST.SCRN Store character on screen
1760 *--------------------------------
1770 LDX AW.CH
1780 CPX #79 End of line yet?
1790 BCS .1 ...yes, stick there, pile em' up
1800 INC AW.CH ...no, advance CH
1810 BNE .1 ...always
1820 *--------------------------------
1830 .5 JSR .6 CALL THE FUNCTION
1840 JMP .1 ...ALWAYS
1850 *--------------------------------
1860 .6 ASL Convert code to index
1870 TAX
1880 LDA FUNTBL+1,X
1890 PHA
1900 LDA FUNTBL,X
1910 PHA
1920 .99 RTS
1930 *--------------------------------
1940 * FUNCTION 03 -- CLEAR ENTIRE WINDOW, CURSOR TO TOP-LEFT
1950 * at $154A in AppleWorks 1.3
1960 *--------------------------------
1970 FUN.HOME
1980 LDA AW.LEFT
1990 STA AW.CH
2000 LDA AW.TOP
2010 STA AW.CV
2020 *--------------------------------
2030 * FUNCTION 04 -- CLEAR REST OF WINDOW
2040 * at $1552 in AppleWorks 1.3
2050 *--------------------------------
2060 FUN.CLR.CH.TO.EOS
2070 LDA AW.CH SAVE CH AND CV
2080 PHA
2090 LDA AW.CV
2100 PHA
2110 .1 JSR CLR.CH.TO.EOL
2120 LDA AW.CV
2130 CMP AW.BOTTOM
2140 BCS .2 ...THAT WAS THE BOTTOM LINE
2150 INC AW.CV
2160 LDA AW.LEFT
2170 STA AW.CH
2180 BCC .1 ...ALWAYS
2190 .2 PLA
2200 STA AW.CV
2210 PLA
2220 STA AW.CH
2230 RTS
2240 *--------------------------------
2250 * FUNCTION 05 -- GO TO X,Y IN THIS WINDOW
2260 * Equivalent to HTAB X, VTAB Y
2270 * 05 XX YY in string
2280 * at $1576 in AppleWorks 1.3
2290 *--------------------------------
2300 FUN.GOTO.XY
2310 LDY POSITION.IN.STRING
2320 LDA ($80),Y
2330 INY
2340 CPY BYTES.IN.STRING
2350 BCS FUN.HANG.UP
2360 ADC AW.LEFT
2370 STA AW.CH
2380 LDA ($80),Y
2390 ADC AW.TOP
2400 STA AW.CV
2410 INY
2420 STY POSITION.IN.STRING
2430 RTS
2440 *--------------------------------
2450 * FUNCTION 06 -- BACK UP CURSOR
2460 * at $1593 in AppleWorks 1.3
2470 *--------------------------------
2480 FUN.CURSOR.LEFT
2490 LDA AW.CH
2500 CMP AW.LEFT
2510 BEQ FUN.HANG.UP
2520 DEC AW.CH
2530 RTS
2540 *--------------------------------
2550 * at $1599 and $1815 in AppleWorks 1.3
2560 FUN.HANG.UP JMP FUN.HANG.UP
2570 *--------------------------------
2580 * FUNCTION 07 -- CURSOR RIGHT
2590 * at $15A1 in AppleWorks 1.3
2600 *--------------------------------
2610 FUN.CURSOR.RIGHT
2620 LDA AW.CH
2630 CMP AW.RIGHT
2640 BEQ FUN.HANG.UP
2650 INC AW.CH
2660 RTS
2670 *--------------------------------
2680 * FUNCTION 08 -- CURSOR UP (SCROLL DOWN IF NECESSARY)
2690 * at $15AB in AppleWorks 1.3
2700 *--------------------------------
2710 FUN.CURSOR.UP
2720 LDA AW.CV
2730 CMP AW.TOP
2740 BEQ .1 ...ALREADY AT TOP, SCROLL DOWN
2750 DEC AW.CV
2760 RTS
2770 .1 LDA AW.BOTTOM
2780 LDX #-1
2790 BNE SCROLL ...ALWAYS
2800 *--------------------------------
2810 * FUNCTION 09 -- CURSOR DOWN (SCROLL UP IF NECESSARY)
2820 * at $15BC in AppleWorks 1.3
2830 *--------------------------------
2840 FUN.CURSOR.DOWN
2850 LDA AW.CV
2860 CMP AW.BOTTOM
2870 BEQ .1 ...ALREADY AT BOTTOM, SCROLL UP
2880 INC AW.CV
2890 RTS
2900 .1 LDA AW.TOP
2910 LDX #1
2920 SCROLL
2930 STX SCROLL.DIRECTION 01 IF UP, FF IF DOWN
2940 PHA SAVE LINE NUMBER
2950 JSR BASE.CALC.A
2960 .1 LDA AW.BASE
2970 STA AW.BASE2
2980 LDA AW.BASE+1
2990 STA AW.BASE2+1
3000 PLA GET LINE NUMBER AGAIN
3010 CMP AW.CV IS IT THE LAST LINE?
3020 BEQ FUN.CLR.LINE
3030 CLC
3040 ADC SCROLL.DIRECTION
3050 PHA SAVE SOURCE LINE NUMBER
3060 JSR BASE.CALC.A
3070 LDA AW.LEFT
3080 TAX
3090 LSR
3100 TAY
3110 BCS .3 START WITH ODD COLUMN
3120 .2 STA $C055 EVEN COLUMNS IN AUX MEM
3130 LDA (AW.BASE),Y
3140 STA (AW.BASE2),Y
3150 STA $C054 BACK TO MAIN MEM
3160 CPX AW.RIGHT
3170 BEQ .1 ...END OF THIS LINE
3180 INX
3190 .3 LDA (AW.BASE),Y
3200 STA (AW.BASE2),Y
3210 CPX AW.RIGHT
3220 BEQ .1 ...END OF THIS LINE
3230 INX
3240 INY
3250 BNE .2 ...ALWAYS
3260 *--------------------------------
3270 * FUNCTION 02 -- CLEAR ENTIRE CURRENT LINE
3280 * at $1540 in AppleWorks 1.3
3290 *--------------------------------
3300 FUN.CLR.LINE
3310 LDA AW.LEFT
3320 STA AW.CH
3330 *--------------------------------
3340 * FUNCTION 01 -- CLEAR REST OF CURRENT LINE
3350 * at $1544 in AppleWorks 1.3
3360 *--------------------------------
3370 FUN.CLR.CH.TO.EOL
3380 JMP CLR.CH.TO.EOL
3390 *--------------------------------
3400 * FUNCTION 0A -- INVERSE
3410 * at $160B in AppleWorks 1.3
3420 *--------------------------------
3430 FUN.INVERSE
3440 LDA #$00
3450 .HS 2C SKIP OVER LDA #$80
3460 *--------------------------------
3470 * FUNCTION 0B -- NORMAL
3480 * at $160F in AppleWorks 1.3
3490 *--------------------------------
3500 FUN.NORMAL
3510 LDA #$80
3520 STA INVERSE.FLAG
3530 RTS
3540 *--------------------------------
3550 * FUNCTION 0C -- DEFINE BOTTOM RIGHT CORNER
3560 * at $1617 in AppleWorks 1.3
3570 *--------------------------------
3580 FUN.CORNER.BR
3590 LDA AW.CH
3600 LDX AW.CV
3610 SET.CORNER.BR
3620 STA AW.RIGHT
3630 STX AW.BOTTOM
3640 RTS
3650 *--------------------------------
3660 * FUNCTION 0D -- CURSOR TO BEGINNING OF LINE
3670 * Equivalent to RETURN without LINEFEED
3680 * at $1622 in AppleWorks 1.3
3690 *--------------------------------
3700 FUN.CURSOR.BOL
3710 LDA AW.LEFT
3720 STA AW.CH
3730 RTS
3740 *--------------------------------
3750 * FUNCTION 0E -- DEFINE TOP LEFT CORNER
3760 * at $1629 in AppleWorks 1.3
3770 *--------------------------------
3780 FUN.CORNER.TL
3790 LDA AW.CH
3800 LDX AW.CV
3810 STA AW.LEFT
3820 STX AW.TOP
3830 RTS
3840 *--------------------------------
3850 * FUNCTION 0F -- SET FULL SCREEN WINDOW
3860 * at $1634 in AppleWorks 1.3
3870 *--------------------------------
3880 FUN.FULL.SCREEN
3890 LDA #0
3900 STA AW.TOP
3910 STA AW.LEFT
3920 LDA #79
3930 LDX #23
3940 BNE SET.CORNER.BR ...ALWAYS
3950 *--------------------------------
3960 * FUNCTION 10 -- "BEEP!"
3970 * at $1645 in AppleWorks 1.3
3980 *--------------------------------
3990 FUN.BEEP
4000 LDY #149
4010 .1 LDA #149
4020 .2 SEC
4030 SBC #1
4040 SEC
4050 SEC
4060 BNE .2 11*149-1 = 1638 CYCLES IN INNER LOOP
4070 LDA $C030 TOGGLE SPEAKER
4080 DEY
4090 BNE .1 1649 CYCLES BETWEEN CLICKS
4100 LDA #1 DELAY ABOUT 1/10 SECOND
4110 JMP DELAY.TENTHS
4120 *--------------------------------
4130 * FUNCTION 11 -- SHUFFLE SCREEN LEFT OR RIGHT
4140 * Following byte is scroll distance and direction:
4150 * If positive, SCROLL RIGHT; else SCROLL LEFT.
4160 * at $165E in AppleWorks 1.3
4170 *--------------------------------
4180 FUN.SHUFFLE
4190 LDY POSITION.IN.STRING
4200 LDA ($80),Y If positive, SCROLL RIGHT; else SCROLL LEFT
4210 STA SCROLL.DIRECTION
4220 INC POSITION.IN.STRING
4230 LDA AW.TOP POINT TO TOP LINE FIRST
4240 .1 PHA
4250 JSR BASE.CALC.A
4260 LDA AW.RIGHT
4270 BIT SCROLL.DIRECTION
4280 BPL .2
4290 LDA AW.LEFT
4300 .2 STA SHUFFLE.DEST
4310 SEC
4320 SBC SCROLL.DIRECTION
4330 STA SHUFFLE.SOURCE
4340 JSR SCROLL.LEFT.OR.RIGHT
4350 PLA
4360 CMP AW.BOTTOM
4370 BEQ .3
4380 CLC
4390 ADC #1
4400 BNE .1
4410 .3 RTS
4420 *--------------------------------
4430 SCROLL.LEFT.OR.RIGHT
4440 LDA SCROLL.DIRECTION
4450 BPL .6 ...shuffle right
4460 BMI .2 ...shuffle left
4470 *---Scroll Left------------------
4480 .1 INC SHUFFLE.DEST
4490 INC SHUFFLE.SOURCE
4500 .2 LDA #" " blank, in case off edge
4510 LDY SHUFFLE.SOURCE
4520 CPY AW.RIGHT
4530 BCC .3
4540 BNE .4 ...off the edge, use a blank
4550 .3 TYA Get source pointer
4560 >LD.SCRN Get character from screen
4570 .4 PHA Save the character
4580 LDA SHUFFLE.DEST destination pointer
4590 >ST.SCRN Store the character on the screen
4600 LDA SHUFFLE.DEST destination pointer
4610 CMP AW.RIGHT was it the right edge?
4620 BNE .1 ...no, keep shuffling
4630 RTS
4640 *---Scroll Right-----------------
4650 .5 DEC SHUFFLE.DEST
4660 DEC SHUFFLE.SOURCE
4670 .6 LDA #" " blank, in case off edge
4680 LDY SHUFFLE.SOURCE
4690 BMI .7 ...off edge, use blank
4700 CPY AW.LEFT
4710 BCC .7 ...off edge, use blank
4720 TYA Get source pointer
4730 >LD.SCRN Get character from screen
4740 .7 PHA Save the character
4750 LDA SHUFFLE.DEST destination pointer
4760 >ST.SCRN Store the character on the screen
4770 LDA SHUFFLE.DEST destination pointer
4780 CMP AW.LEFT was it the left edge?
4790 BNE .5 ...no, keep shuffling
4800 RTS
4810 *--------------------------------
4820 .MA VEC
4830 .DA FUN.]1-1
4840 .EM
4850 *--------------------------------
4860 * at $1779 in AppleWorks 1.3
4870 FUNTBL
4880 >VEC HANG.UP 00
4890 >VEC CLR.CH.TO.EOL 01
4900 >VEC CLR.LINE 02
4910 >VEC HOME 03
4920 >VEC CLR.CH.TO.EOS 04
4930 >VEC GOTO.XY 05
4940 >VEC CURSOR.LEFT 06
4950 >VEC CURSOR.RIGHT 07
4960 >VEC CURSOR.UP 08
4970 >VEC CURSOR.DOWN 09
4980 >VEC INVERSE 0A
4990 >VEC NORMAL 0B
5000 >VEC CORNER.BR 0C
5010 >VEC CURSOR.BOL 0D
5020 >VEC CORNER.TL 0E
5030 >VEC FULL.SCREEN 0F
5040 >VEC BEEP 10
5050 >VEC SHUFFLE 11
5060 >VEC HANG.UP 12
5070 >VEC HANG.UP 13
5080 >VEC HANG.UP 14
5090 >VEC HANG.UP 15
5100 >VEC HANG.UP 16
5110 >VEC HANG.UP 17
5120 >VEC HANG.UP 18
5130 >VEC HANG.UP 19
5140 >VEC HANG.UP 1A
5150 >VEC HANG.UP 1B
5160 >VEC HANG.UP 1C
5170 >VEC HANG.UP 1D
5180 >VEC HANG.UP 1E
5190 >VEC HANG.UP 1F
5200 *--------------------------------
5210 POLL.KEYBOARD RTS (at $1FA7 in AppleWorks 1.3)
5220 *--------------------------------
5230 * Calculate Address of Screen Line
5240 * at $1717 in AppleWorks 1.3
5250 *--------------------------------
5260 BASE.CALC.CV
5270 LDA AW.CV
5280 BASE.CALC.A
5290 CMP #$FF <<<filled in with current line number>>>
5300 CURR.LINE .EQ *-1
5310 BEQ .2
5320 STA CURR.LINE
5330 LSR 0000ABCD--E
5340 AND #$03 000000CD--E
5350 ORA #$04 000001CD--E
5360 STA AW.BASE+1
5370 LDA CURR.LINE
5380 AND #$18 000AB000--E
5390 BCC .1 E=0
5400 ADC #$7F E00AB000
5410 .1 STA AW.BASE
5420 ASL 00AB0000
5430 ASL 0AB00000
5440 ORA AW.BASE EABAB000
5450 STA AW.BASE
5460 .2 RTS
5470 *--------------------------------
5480 * Blank Line from Cursor to End of Line
5490 * at $173A in AppleWorks 1.3
5500 *--------------------------------
5510 CLR.CH.TO.EOL
5520 LDA AW.RIGHT
5530 LSR
5540 STA N.OVER.2
5550 ROL GET AW.RIGHT AGAIN
5560 SEC
5570 SBC #1
5580 LSR
5590 STA N.MINUS.1.OVER.2
5600 JSR BASE.CALC.CV
5610 LDA AW.CH
5620 LSR
5630 PHA
5640 *---Clear Even Columns-----------
5650 TAY
5660 LDA #" "
5670 STA $C055 INTO AUX MEM
5680 BCC .2
5690 .1 INY
5700 .2 CPY N.OVER.2
5710 BEQ .3
5720 BCS .4
5730 .3 STA (AW.BASE),Y
5740 JMP .1
5750 .4 STA $C054 BACK TO MAIN MEM
5760 *---Clear Odd Columns------------
5770 PLA
5780 TAY
5790 LDA #" "
5800 .5 STA (AW.BASE),Y
5810 INY
5820 CPY N.MINUS.1.OVER.2
5830 BCC .5
5840 BEQ .5
5850 RTS
5860 *--------------------------------
5870 N.OVER.2 .BS 1
5880 N.MINUS.1.OVER.2 .BS 1
5890 *--------------------------------
5900 * DELAY ABOUT (A) TENTHS OF A SECOND
5910 * at $1FD1 in AppleWorks 1.3
5920 *--------------------------------
5930 DELAY.TENTHS
5940 TAY
5950 .1 LDX #100 ...ABOUT 100 MILLISECONDS
5960 .2 CLC
5970 .3 ADC #1
5980 BCC .3 ...LOOP IS 256*5 CYCLES
5990 DEX
6000 BNE .2 (5*256+6)*100 = 128600 CYCLES
6010 DEY
6020 BNE .1 128606*A CYCLES
6030 RTS
6040 *--------------------------------
6050 * Some Demonstrations
6060 *--------------------------------
6070 T
6080 LDA #MY.STRINGS
6090 LDX /MY.STRINGS
6100 .1 STA $80
6110 STX $81
6120 LDY #0
6130 LDA ($80),Y
6140 BEQ .99 ...FINISHED
6150 PHA SAVE LENGTH
6160 INC $80
6170 BNE .2
6180 INC $81
6190 .2 JSR DISPLAY.STRING
6200 CLC
6210 PLA GET LENGTH
6220 ADC $80 ADD TO POINTER
6230 LDX $81
6240 BCC .1
6250 INX
6260 BCS .1 ...ALWAYS
6270 .99 RTS
6280 *--------------------------------
6290 MY.STRINGS
6300 .DA #Z1
6310 A1 .HS 0F.03.0B Full Scrn, Home, Normal
6320 .AS /ABCDECDEFGHIJKLMNOPQRSTUVWXYZ !@#$%^&*()-+=[]\;:'",.<>?{}|/
6330 .HS 0A.0D.09 Inverse, RETURN, LINEFEED
6340 .AS /ABCDECDEFGHIJKLMNOPQRSTUVWXYZ !@#$%^&*()-+=[]\;:'",.<>?{}|/
6350 Z1 .EQ *-A1
6360 *--------------------------------
6370 .DA #Z2
6380 A2 .HS 0B.0D.09 Normal, RETURN, LINEFEED
6390 .AS "abcdefghijklmnopqrstuvwxyz / 0123456789 _ "
6400 .HS 0A.0D.09 Inverse, RETURN, LINEFEED
6410 .AS "abcdefghijklmnopqrstuvwxyz / 0123456789 _ "
6420 Z2 .EQ *-A2
6430 *--------------------------------
6440 .DA #Z3
6450 A3 .HS 0B.0D.09 Normal, RETURN, LINEFEED
6460 .AS -/@ABCDECDEFGHIJKLMNOPQRSTUVWXYZ[\]^_/
6470 .HS 05.00.00 GO TO 0,0
6480 .HS 10.08.08.08.08.08.08.08 Beep, 7 cursor ups
6490 .HS 10.08.08.08.08.08.08.08 Beep, 7 cursor ups
6500 .HS 05.00.17 GO TO 0,23
6510 .HS 10.09.09.09.09.09.09.09 Beep, 7 cursor downs
6520 .HS 10.09.09.09.09.09.09.09 Beep, 7 cursor downs
6530 Z3 .EQ *-A3
6540 *--------------------------------
6550 .DA #Z4
6560 A4 .HS 10.11.08 Beep, Shuffle Right 8
6570 .HS 10.11.F8 Beep, Shuffle Left 8
6580 .HS 10.11.01.11.01.11.01.11.01.11.01.11.01.11.01
6590 .HS 10.11.FF.11.FF.11.FF.11.FF.11.FF.11.FF.11.FF
6600 .HS 10.11.F8
6610 .HS 10.11.08
6620 .HS 10.11.28
6630 .HS 10.11.D8
6640 Z4 .EQ *-A4
6650 *--------------------------------
6660 .DA #Z5
6670 A5 .HS 03 HOME
6680 .HS 20.21.22.23.24.25.26.27.28.29.2A.2B.2C.2D.2E.2F
6690 .HS 30.31.32.33.34.35.36.37.38.39.3A.3B.3C.3D.3E.3F.0D.09
6700 .HS 40.41.42.43.44.45.46.47.48.49.4A.4B.4C.4D.4E.4F
6710 .HS 50.51.52.53.54.55.56.57.58.59.5A.5B.5C.5D.5E.5F.0D.09
6720 .HS 60.61.62.63.64.65.66.67.68.69.6A.6B.6C.6D.6E.6F
6730 .HS 70.71.72.73.74.75.76.77.78.79.7A.7B.7C.7D.7E.7F.0D.09
6740 .HS 0A INVERSE
6750 .HS 20.21.22.23.24.25.26.27.28.29.2A.2B.2C.2D.2E.2F
6760 .HS 30.31.32.33.34.35.36.37.38.39.3A.3B.3C.3D.3E.3F.0D.09
6770 .HS 40.41.42.43.44.45.46.47.48.49.4A.4B.4C.4D.4E.4F
6780 .HS 50.51.52.53.54.55.56.57.58.59.5A.5B.5C.5D.5E.5F.0D.09
6790 .HS 60.61.62.63.64.65.66.67.68.69.6A.6B.6C.6D.6E.6F
6800 .HS 70.71.72.73.74.75.76.77.78.79.7A.7B.7C.7D.7E.7F.0D.09
6810 .HS 0B NORMAL
6820 Z5 .EQ *-A5
6830 *--------------------------------
6840 .DA #Z6
6850 A6 .HS 0D.09 CRLF
6860 .HS 80.81.82.83.84.85.86.87.88.89.8A.8B.8C.8D.8E.8F
6870 .HS 90.91.92.93.94.95.96.97.98.99.9A.9B.9C.9D.9E.9F.0D.09
6880 .HS A0.A1.A2.A3.A4.A5.A6.A7.A8.A9.AA.AB.AC.AD.AE.AF
6890 .HS B0.B1.B2.B3.B4.B5.B6.B7.B8.B9.BA.BB.BC.BD.BE.BF.0D.09
6900 .HS C0.C1.C2.C3.C4.C5.C6.C7.C8.C9.CA.CB.CC.CD.CE.CF
6910 .HS D0.D1.D2.D3.D4.D5.D6.D7.D8.D9.DA.DB.DC.DD.DE.DF.0D.09
6920 .HS E0.E1.E2.E3.E4.E5.E6.E7.E8.E9.EA.EB.EC.ED.EE.EF
6930 .HS F0.F1.F2.F3.F4.F5.F6.F7.F8.F9.FA.FB.FC.FD.FE.FF.0D.09
6940 Z6 .EQ *-A6
6950 *--------------------------------
6960 .HS 00
6970 *--------------------------------
|
| Overhauling the S-C Program Selector | Bob Sander-Cederlof |
About a year and a half ago, in the July 1986 issue of Apple Assembly Line, I published my replacement for the ProDOS "QUIT" code. It turned out to be a very popular article and program, and various updates and corrections were printed in the August, September, October, and December issues that same year.
In review, the QUIT code is a 768-byte program inside ProDOS-8 which is executed when you leave a system program, such as FILER, AppleWorks, BASIC.SYSTEM (Applesoft), Copy II Plus, the S-C Macro Assembler, and so on. When you QUIT you are really executing the MLI Quit call ($65), which copies those 768 bytes down to RAM starting at $1000 and jumps there. Apple's built-in QUIT code is about as user-friendly as an angry porcupine: if you haven't MEMORIZED the volume names and file names of all your system programs, you almost always end up resetting and re-booting instead of filling in the blanks.
My 1986 Program Selector exactly fits in the 768-byte space Apple's version occupies in the ProDOS system file. It puts a menu of online volumes on the screen, allowing you to select one with the arrow keys and RETURN. Once you select a volume, you see a menu of the SYS and DIR files in the main directory of that volume. Using the arrows and RETURN you can either start up a SYS program or select a subdirectory. If you choose a subdirectory, you get a menu of SYS and DIR files inside it. Hitting ESCAPE always takes you back to the Volume Menu. As I wrote the Program Selector, it requires an Apple //e, //c, or //gs, and works in 80-columns.
The modifications already published include fixing one bug, making it work with a Videx-compatible 80-column card for Apple II Plus owners, following Apple's published spec's for substitute QUIT-code, and making it begin with the menu bar on something other than the first volume in the menu.
Quite a few readers of AAL are now using this Program Selector. Some have gone the extra mile by adapting the S-C Program Selector to their own preferences. Jim Hammond (of FastFind SUPER INDEX) liked it so well he turned it into a product which he sells (with my permission) as "STARTER/QUITTER". Larry Skutchan (a blind user who adapted the S-C Word Processor into a talking version) adapted it to work with the Echo Speech Synthesizer. Brooke Boering (creator of CeeMac and Fire Organ) put in a feature allowing you to limit the Volume Menu to a particular disk drive. Brooke's ideas are what led me to try to improve and upgrade my program.
The main computer here at the office is an Apple //e with a 10-meg Sider (ProDOS sees it as two drives in slot 7), two standard Apple floppies in slot 6, a RamFactor card in slot 4 (simulates one drive), a 1-meg RamWorks card in the AuxSlot (simulates a drive in slot 3, Drive 2), and a 3.5 inch drive in slot 2 (ProDOS thinks there are two drives there, even though I only have one). When I type BYE or in some other way select the ProDOS QUIT code, my S-C Program Selector takes over. The old version seemed to go away and die for several seconds while ProDOS did a complete ONLINE check to find out what volume if any was mounted in each and every drive. If my hard disk is not turned on, that takes several seconds for the firmware to timeout. If no floppies are in the 5.25 drives, they go through spinning, re-calibration, and the works before giving up.
It finally dawned on me that what I wanted was to direct the Program Selector to only try the slot and drive I booted from. Most likely if I booted from it, there is some kind of volume there. Of course I still wanted the capability of seeing every volume, but I did not want to waste all that time EVERY time!
Brooke told me six months or more ago that I could plug a drive ID into my ONLINE call (line 2760 of the original program) and it would limit the display to that one volume. It turned out to be a little harder than that, but I did get that to work. But I could not decide on just one slot and drive. I wanted that byte to be set up by ProDOS at boot-time to point to the booting drive.
I remembered that the ProDOS startup code began by plugging the boot drive ID into its own ONLINE call, which it uses to get the Volume Name. I looked up the code in the Supplement to "Beneath Apple ProDOS", and found it. In ProDOS 1.1.1 it is done by the first two instructions at $2000; in ProDOS 1.2, 1.3, and 1.4 it starts six bytes later at $2006. The first instruction is "LDA $43", which picks up the drive ID (slot number times 16) that was used to load the PRODOS or P8 file. The second one is "STA $21FE" for ProDOS 1.1.1, and "STA" somewhere else for later versions. I decided I could patch into that "STA" instruction a call to a piece of patch code which would not only do the patched-over STA for Apple, but also an additional one for me. More on this later, when we get into the code for my new Program Selector.
Anyway, the Program Selector now comes up only showing the Volume Name of the volume currently in the drive ProDOS was booted from. If that is the volume I want, I just hit RETURN and see the menu of SYS and DIR files on that volume. If I booted from RamFactor, this all happens at blinding speed.
If the boot-drive is not the drive I want, I can type a digit and select a different drive or all drives. Typing a digit 1 through 7 changes to drive 1 of that slot and displays the Volume Name in that drive. Typing the digit "8" changes to drive 2 in the same slot. Why 8? Why not? It made the code shorter, and it worked. Typing "0" changes back to the old way, making a menu of all online volumes. If you select a drive which has no volume mounted, you will get an empty menu. No problem, just select a different drive or all-drives, and continue.
I also made various other improvements here and there, such as making sure that text mode with a full-screen window is selected. I had to revise the "help" message at the bottom of the menu display to include information on the digits 0-8.
A major constraint in adding new features was that I wanted to retain the advantage of fitting inside the 768-byte hole in the ProDOS file. In developing the new version I decided not to worry about size too much until all the new features were working. I tested them by BRUNning the code at $1000, instead of going through the process of putting it into ProDOS every time. Then when it was all ready, I started looking for ways to shrink the code and make it fit in only 768 bytes.
It ran about 32 bytes over, so I needed a lot of shrinking. For some reason I don't remember, back in 1986 I decided to keep a lot of variables out of page zero. There is no requirement to do this, so I moved these variables and saved almost all the bytes I wanted. All instructions referencing these variables shrank from three to two bytes. The rest of the savings were found by careful study of the code. If you compare the new listing which follows with the one I published in 1986 you can find the tricks I pulled. The new version, even with all the new features, is now shorter than the original! There are actually four unused bytes!
I also wrote a program to automatically install the new Program Selector inside the ProDOS file. Well, almost automatically. You still have to BLOAD PRODOS or BLOAD P8, and UNLOCK the file if it is LOCKed. Then you "-" or BRUN my INSTALL.QUITTER program, and it automatically does the installation. If successful, you get a nice message to that effect; then you have to BSAVE the image and re-LOCK it. I thought it would be too dangerous to make all of the above entirely automatic. If my installer made a mistake.... So, I left the crucial part manual.
The auto-installer does differentiate between ProDOS 1.1.1 and the later versions. It makes the boot-drive patch at either $2002 or $2008, depending on where it finds the STA instruction. And if it cannot find that instruction, it tells you so and quits. The Program Selector image is copied either to $5700 (for ProDOS 1.1.1) or $5900 (for later versions).
The code for the auto-installer is executed when you BRUN INSTALL.QUITTER. Lines 1460-2270 are the installation code, and lines 2280 to the end are the Program Selector image. Lines 1490-1710 try to determine which version of ProDOS, if any, is in memory starting at $2000. If it finds a recognizable version, it sets up various pointers according to the version. If not, it prints out the long message from lines 2160-2220.
Lines 1720-1800 copy a JSR to my patch code over the top of the STA xxxx instruction which starts at either $2002 or $2008. It also modifies my patch code to include exactly the correct STA xxxx instruction which we are patching over. The patch code is at the very end of the Program Selector image, in lines 5970-6020. Later, when this patched ProDOS file is booted or otherwise executed, my patch code will install the boot drive ID into the ONLINE call block at line 5880.
Lines 1810-1950 copy the Program Selector image into the ProDOS image, at either $5700 or $5900 depending on version. Assuming we got this far, lines 1970-1990 will print out the "SUCCESSFUL" message.
900 .LIST MOFF 1000 *SAVE NEW.QUIT.CODE 1010 *-------------------------------- 1020 * Installation: 1030 * 1. BLOAD PRODOS,TSYS,A$2000 1040 * 2. BRUN INSTALL.QUITTER 1050 * 3. BSAVE PRODOS,TSYS,A$2000 1051 *-------------------------------- 1052 .MA ASC Macro to shorten listing 1053 .AS -"]1" 1054 .EM 1060 *-------------------------------- 1070 .DUMMY 1080 .OR 0000 1090 BPNTR .BS 2 1100 SPNTR .BS 2 1110 DPNTR .BS 2 1120 DIR.INDEX .BS 1 1130 DIR.START .BS 1 1140 MAX.DIRPNT .BS 1 1150 SEL.LINE .BS 1 1160 MAX.LINE .BS 1 1170 UNIT .BS 1 1180 LENGTH .BS 1 1190 CURTYP .BS 1 1200 CURBLK .BS 1 1210 *-------------------------------- 1220 .OR $800 1230 OPNBUF .BS 1024 1240 DIRBUF .BS 512 1250 .ED 1260 *-------------------------------- 1270 PATHNAME .EQ $280 1280 BUFFER .EQ $2000 1290 ENTLEN .EQ BUFFER+$23 ENTRY LENGTH 1300 ENTCNT .EQ BUFFER+$24 # ENTRIES PER BLOCK 1310 *-------------------------------- 1320 CV .EQ $25 1330 INVFLG .EQ $32 1340 *-------------------------------- 1350 INIT .EQ $FB2F 1360 HOME .EQ $FC58 1370 CLREOL .EQ $FC9C 1380 COUT .EQ $FDED 1390 CROUT .EQ $FD8E 1400 SETINV .EQ $FE80 1410 SETNORM .EQ $FE84 1420 *-------------------------------- 1430 MLI .EQ $BF00 1440 BITMAP .EQ $BF58 1450 *-------------------------------- 1460 .OR $1000 1470 .TF INSTALL.QUITTER 1480 *-------------------------------- 1490 INSTALL.QUITTER 1500 LDX /$5700 WHERE IMAGE IS IN 1.1.1 1510 LDA /$2000 WHERE LDA $43 IS IN 1.1.1 1520 STA BPNTR+1 1530 LDY #0 1540 STY DPNTR 1550 LDA $2000 SEE IF PRODOS IMAGE IS HERE 1560 CMP #$4C IF "JMP" THEN PROBABLY 1.4 1570 BNE .1 ...PROBABLY 1.1.1 1580 LDY #6 WHERE LDA $43 IS IN 1.4 1590 LDX /$5900 WHERE IMAGE IS IN 1.4 1600 .1 STY BPNTR POINT AT LDA $43 1610 STX DPNTR+1 POINT AT IMAGE OF QUITTER 1620 INX 1630 INX 1640 STX QPATCH+2 ADDRESS IN IMAGE OF "ONLINE+1" 1650 STX JSR.QPATCH+2 ADDRESS IN IMAGE OF QPATCH 1660 LDY #2 1670 .2 LDA PRODOS.ID.STRING,Y 1680 CMP (BPNTR),Y 1690 BNE .99 ...NEITHER, QUIT. 1700 DEY 1710 BPL .2 1720 *---Trust we have ProDOS image--- 1730 LDY #2 POINT AT STA XXXX 1740 .3 LDA (BPNTR),Y 1750 STA QPATCH-2+3,Y 1760 LDA JSR.QPATCH-2,Y 1770 STA (BPNTR),Y 1780 INY 1790 CPY #5 1800 BCC .3 1810 *---Copy Quitter into ProDOS----- 1820 LDA #QUIT.IMAGE 1830 STA SPNTR 1840 LDA /QUIT.IMAGE 1850 STA SPNTR+1 1860 LDX #3 COPY 3 PAGES 1870 LDY #0 1880 .4 LDA (SPNTR),Y 1890 STA (DPNTR),Y 1900 INY 1910 BNE .4 1920 INC SPNTR+1 1930 INC DPNTR+1 1940 DEX 1950 BNE .4 1960 *---Successful, say so and end--- 1970 LDY #IQ.GOOD 1980 JSR IQ.PRINT 1990 RTS FINISHED 2000 *---No ProDOS, or already patched--- 2010 .99 LDY #IQ.BAD 2020 JSR IQ.PRINT 2030 RTS 2040 *-------------------------------- 2050 IQ.OUT JSR COUT 2060 INY 2070 IQ.PRINT 2080 LDA IQ,Y 2090 BNE IQ.OUT 2100 RTS 2110 *-------------------------------- 2120 IQ .EQ * 2130 IQ.GOOD .EQ *-IQ 2140 >ASC "SUCCESSFULLY INSTALLED NEW QUIT CODE." 2150 .HS 8D00 2160 IQ.BAD .EQ *-IQ 2170 >ASC "EITHER PRODOS NOT HERE," 2180 .HS 8D 2190 >ASC "OR NOT VERSION 1.1.1 OR 1.4," 2200 .HS 8D 2210 >ASC "OR ALREADY INSTALLED QUIT CODE." 2220 .HS 8D00 2230 *-------------------------------- 2240 PRODOS.ID.STRING 2250 .HS A5.43.8D 2260 JSR.QPATCH 2270 JSR QPATCH.EP 2280 *-------------------------------- 2290 QUIT.IMAGE 2300 .PH $1000 2310 *-------------------------------- 2320 QUITTER 2330 CLD REQUIRED BY "STANDARDS" 2340 LDA $C082 MOTHERBOARD ROMS 2350 JSR INIT TEXT MODE, FULL SCREEN WINDOW 2360 JSR SETNORM 2370 LDX #$16 2380 LDA #0 PREPARE VIRGIN BITMAP 2390 .1 STA BITMAP,X 2400 STX BITMAP+$17 LAST TIME STORES $01, LOCK OUT $BF00 PAGE 2410 DEX 2420 BNE .1 2430 LDA #$CF 2440 STA BITMAP 2450 *---LIST VOLUME NAMES------------ 2460 .2 LDA #$99 CTRL-Y 2470 JSR $C300 SET I/O HOOKS, 80-COL MODE, CLEAR SCREEN 2480 LDY #Q.SDV 2490 JSR MSG 2500 JSR CLOSE.ALL.FILES 2510 LDY #0 2520 STY MAX.DIRPNT 2530 STY DIR.START 2540 STY PATHNAME 2550 STY BUFFER+16 (IN CASE "ONLINE" PRESET TO SPECIFIC S/D) 2560 JSR MLI 2570 .DA #$C5,ONLINE 2580 .3 STY SEL.LINE 2590 JSR DISPLAY.VOLUMES 2600 LDY #Q.VHELP 2610 JSR MSG 2620 JSR GET.KEY 2630 BCC .3 ...ARROW KEYS 2640 BNE .2 ...ESCAPE KEY 2650 *---READ DIRECTORY--------------- 2660 .4 JSR READ.THE.FILE 2670 BCS .7 2680 *---PRINT PATHNAME--------------- 2690 JSR HOME 2700 LDY #0 2710 .5 LDA PATHNAME+1,Y 2720 ORA #$80 2730 JSR COUT 2740 INY 2750 CPY PATHNAME 2760 BCC .5 2770 *---COLLECT FILENAMES------------ 2780 LDX #0 2790 LDA #$FF FIRST JUST "SYS" FILES 2800 JSR SCAN.DIRECTORY 2810 LDA #$0F THEN JUST "DIR" FILES 2820 JSR SCAN.DIRECTORY 2830 TXA SEE IF ANY FILES FOUND 2840 BEQ .2 ...NO, BACK TO THE TOP 2850 LDA #0 MARK END OF LIST 2860 STA DIRBUF+256,X 2870 STX MAX.DIRPNT 2880 *---LIST THE FILENAMES----------- 2890 TAY Y=0 2900 STY DIR.START 2910 .6 STY SEL.LINE 2920 JSR DISPLAY.FILES 2930 LDY #Q.VHELP 2940 JSR MSG 2950 JSR GET.KEY 2960 BCC .6 ...ARROW KEYS 2970 BNE .2 ...ESCAPE KEY 2980 LDY #$10 2990 LDA (SPNTR),Y GET FILE TYPE 3000 BPL .4 DIRECTORY ($0F) 3010 *---SYS FILE, LOAD & EXECUTE----- 3020 JSR MLI SET PREFIX 3030 .DA #$C6,PATH 3040 JSR READ.THE.FILE 3050 BCS .7 ...ERROR IN READING 3060 JMP BUFFER 3070 .7 JMP QUITTER 3080 *-------------------------------- 3090 READ.THE.FILE 3100 LDY #0 APPEND CURRENTLY SELECTED NAME 3110 LDA (SPNTR),Y GET LENGTH OF NAME 3120 AND #$0F 3130 STA LENGTH 3140 LDX PATHNAME CURRENT LENGTH 3150 LDA #'/' 3160 .1 INX 3170 INY 3180 STA PATHNAME,X 3190 LDA (SPNTR),Y 3200 DEC LENGTH 3210 BPL .1 3220 STX PATHNAME 3230 JSR MLI OPEN THE FILE 3240 .DA #$C8,OPEN 3250 BCS RF.ERR 3260 LDA O.REF FILE REFERENCE NUMBER 3270 STA R.REF 3280 JSR MLI READ THE WHOLE FILE 3290 .DA #$CA,READ 3300 BCC CLOSE.ALL.FILES 3310 CMP #$4C IS IT JUST EOF? 3320 SEC 3330 BNE RF.ERR ...NO 3340 CLOSE.ALL.FILES 3350 JSR MLI CLOSE THE FILE 3360 .DA #$CC,CLOSE 3370 RF.ERR RTS 3380 *-------------------------------- 3390 SCAN.DIRECTORY 3400 STA CURTYP TYPE WE ARE COLLECTING 3410 LDA #0 START WITH FIRST BLOCK 3420 .1 STA CURBLK 3430 LDA #BUFFER+4 FIRST 4 BYTES OF BLOCK SKIPPED 3440 STA DPNTR 3450 CLC COMPUTE PAGE OF PNTR 3460 LDA /BUFFER+4 3470 ADC CURBLK 3480 STA DPNTR+1 3490 LDA ENTCNT 3500 STA LENGTH 3510 *-------------------------------- 3520 .2 LDY #0 3530 LDA (DPNTR),Y 3540 AND #$F0 3550 BEQ .4 ...DELETED FILE 3560 CMP #$E0 ...HEADER? 3570 BCS .4 ...YES 3580 LDY #$10 3590 LDA (DPNTR),Y LOOK AT FILE TYPE 3600 CMP CURTYP 3610 BNE .4 ...NOT CURRENT TYPE 3620 *---DIR or SYS file-------------- 3630 .3 LDA DPNTR 3640 STA DIRBUF,X 3650 LDA DPNTR+1 3660 STA DIRBUF+256,X 3670 INX 3680 *---ADVANCE TO NEXT ENTRY-------- 3690 .4 CLC 3700 LDA DPNTR 3710 ADC ENTLEN 3720 STA DPNTR 3730 BCC .5 3740 INC DPNTR+1 3750 .5 DEC LENGTH AT END OF BLOCK YET? 3760 BNE .2 ...NO, CONTINUE IN BLOCK 3770 CLC 3780 LDA CURBLK 3790 ADC #2 3800 CMP ACTLEN+1 3810 BCC .1 ...YES, READ NEXT BLOCK 3820 RTS 3830 *-------------------------------- 3840 DISPLAY.VOLUMES 3850 JSR SETUP.DISPLAY.LOOP 3860 LDA /BUFFER 3870 STA BPNTR+1 3880 LDA #BUFFER 3890 .1 STA BPNTR 3900 LDY #0 3910 LDA (BPNTR),Y 3920 BEQ .5 ...END OF LIST 3930 AND #$0F 3940 BEQ .3 ...NO VOLUME HERE 3950 *-------------------------------- 3960 JSR CHECK.FOR.SEL.LINE 3970 *-------------------------------- 3980 LDA (BPNTR),Y GET UNIT NUMBER 3990 LSR ISOLATE SLOT NUMBER 4000 LSR 4010 LSR 4020 LSR 4030 AND #7 4040 ORA #"0" 4050 JSR COUT PRINT SLOT NUMBER 4060 LDA #"/" 4070 JSR COUT 4080 LDA (BPNTR),Y GET UNIT NUMBER AGAIN 4090 ASL SET CARRY IF DRIVE 2 4100 LDA #"1" ASSUME DRIVE 1 4110 ADC #0 CHANGE TO 2 IF TRUE 4120 JSR COUT 4130 LDA #" " PRINT TWO SPACES 4140 JSR COUT 4150 JSR COUT 4160 JSR PRINT.BPNTR.NAME 4170 *-------------------------------- 4180 .3 CLC POINT TO NEXT VOLUME NAME 4190 LDA BPNTR 4200 ADC #16 4210 BCC .1 STILL IN SAME PAGE 4220 .5 RTS 4230 *-------------------------------- 4240 PRINT.BPNTR.NAME 4250 LDY #0 4260 LDA (BPNTR),Y GET NAME LENGTH 4270 AND #$0F 4280 TAX 4290 .1 INY PRINT THE VOLUME OR FILE NAME 4300 LDA (BPNTR),Y 4310 ORA #$80 4320 JSR COUT 4330 DEX 4340 BNE .1 4350 *-------------------------------- 4360 .2 LDA #" " PRINT TRAILING BLANKS 4370 JSR COUT 4380 INY 4390 CPY #16 4400 BCC .2 4410 JSR SETNORM NORMAL MODE NOW 4420 INC MAX.LINE COUNT THE LINE 4430 JMP CROUT 4440 *-------------------------------- 4450 GET.KEY 4460 LDY SEL.LINE CURRENT BRIGHT LINE 4470 .1 LDA $C000 READ KEY FROM KEYBOARD 4480 BPL .1 4490 STA $C010 CLEAR THE STROBE 4500 CMP #$B0 CHECK FOR "0"..."7" 4510 BCC .12 4520 CMP #$B8 4530 BEQ .25 4540 BCS .1 4550 ASL 4560 ASL 4570 ASL 4580 ASL LEAVE SLOT*16 IN A, CARRY SET 4590 .11 STA ONLINE+1 CHANGE ONLINE CALL 4600 LDA #$9B SIMULATE AN <ESCAPE> 4610 .12 CMP #$8D 4620 BEQ .2 <RETURN> 4630 CMP #$88 <-- 4640 BEQ .3 4650 CMP #$95 --> 4660 BEQ .7 4670 CMP #$8A DOWN ARROW 4680 BEQ .7 4690 CMP #$8B UP ARROW 4700 BEQ .3 4710 CMP #$9B ESCAPE 4720 BNE .1 GET ANOTHER CHARACTER 4730 ASL ...SET .NE. and CARRY 4740 .2 RTS 4750 .25 LDA ONLINE+1 4760 ORA #$80 TRY DRIVE 2 4770 BNE .11 ...ALWAYS 4780 *---<UP OR LEFT ARROW>----------- 4790 .3 CLC 4800 DEY IS CURRENT BRIGHT LINE TOP LINE? 4810 BPL .8 ...NOT TOP LINE 4820 LDY DIR.START ARE WE DISPLAYING THE FIRST ONE? 4830 BEQ .5 ...YES 4840 DEC DIR.START ...NO, MOVE TOWARD FIRST LINE 4850 .4 LDY #0 MAKE FIRST LINE BRIGHT 4860 RTS 4870 .5 LDY MAX.LINE MAKE LAST LINE BRIGHT 4880 DEY 4890 RTS 4900 *---<DOWN OR RIGHT ARROW>-------- 4910 .7 INY MOVE TOWARD LAST LINE 4920 CPY MAX.LINE BEYOND END OF SCREEN? 4930 BCC .8 ...NO 4940 LDA MAX.DIRPNT ...YES, CHECK IF SHOWING LAST LINE 4950 SBC #17 4960 BCC .4 ...YES 4970 CMP DIR.START 4980 BCC .4 ...YES 4990 INC DIR.START ...NO, MOVE TOWARD LAST LINE 5000 LDY SEL.LINE 5010 CLC 5020 .8 RTS 5030 *-------------------------------- 5040 DISPLAY.FILES 5050 JSR SETUP.DISPLAY.LOOP 5060 LDA DIR.START 5070 STA DIR.INDEX 5080 JSR CLEAR.LINE.OR.PRINT.MORE.MSG 5090 *-------------------------------- 5100 .1 LDX DIR.INDEX 5110 LDY DIRBUF+256,X 5120 BEQ .4 ...END OF LIST 5130 STY BPNTR+1 5140 LDA DIRBUF,X 5150 STA BPNTR 5160 JSR CHECK.FOR.SEL.LINE 5170 *-------------------------------- 5180 .2 LDY #$10 5190 LDA (BPNTR),Y 5200 BMI .3 ...SYS FILE 5210 LDY #Q.DIR 5220 .HS 2C 5230 .3 LDY #Q.SYS 5240 JSR MSG 5250 JSR PRINT.BPNTR.NAME 5260 *-------------------------------- 5270 INC DIR.INDEX 5280 DEC LENGTH 5290 BNE .1 5300 .4 LDA DIR.INDEX 5310 CMP MAX.DIRPNT 5320 *-------------------------------- 5330 CLEAR.LINE.OR.PRINT.MORE.MSG 5340 BEQ .1 CLEAR LINE 5350 LDY #Q.MORE 5360 BNE MSG ...ALWAYS 5370 .1 JSR CLREOL 5380 JMP CROUT 5390 *-------------------------------- 5400 SETUP.DISPLAY.LOOP 5410 LDA #16 MAX 16 LINES IN LIST 5420 STA LENGTH 5430 LDY #0 5440 STY MAX.LINE 5450 INY SAME AS VTAB 3, HTAB 1 5460 STY CV 5470 JMP CROUT 5480 *-------------------------------- 5490 CHECK.FOR.SEL.LINE 5500 LDA MAX.LINE SEE IF CURRENT LINE SHOULD 5510 CMP SEL.LINE BE INVERSE MODE 5520 BNE .1 ...NO 5530 LDA BPNTR ...YES, SO SETUP POINTER 5540 STA SPNTR 5550 LDA BPNTR+1 5560 STA SPNTR+1 5570 LDA #$3F & SET INVERSE MODE 5580 STA INVFLG 5590 .1 RTS 5600 *-------------------------------- 5610 MSG1 JSR COUT 5620 INY 5630 MSG LDA QTS,Y 5640 BNE MSG1 5650 RTS 5660 *-------------------------------- 5670 QTS .EQ * 5680 Q.SDV .EQ *-QTS 5690 >ASC "S/D Volume Name" 5700 .HS 00 5710 Q.VHELP .EQ *-QTS 5720 .HS 8D 5730 >ASC "Select with ARROWS and <RETURN>" 5740 .HS 8D 5750 >ASC "See Volumes with <ESCAPE> or 0-8" 5760 .HS 8D00 5770 Q.SYS .EQ *-QTS 5780 >ASC "SYS -- " 5790 .HS 00 5800 Q.DIR .EQ *-QTS 5810 >ASC "DIR -- " 5820 .HS 00 5830 Q.MORE .EQ *-QTS 5840 >ASC "<<<MORE>>>" 5850 .HS 8D00 5860 *-------------------------------- 5870 CLOSE .DA #1,#0 5880 ONLINE .DA #2,#0,BUFFER 5890 OPEN .DA #3,PATHNAME,OPNBUF 5900 O.REF .BS 1 5910 READ .DA #4 5920 R.REF .BS 1 5930 .DA BUFFER,$9F00 5940 ACTLEN .BS 2 5950 PATH .DA #1,PATHNAME 5960 *-------------------------------- 5970 .BS $1300-*-7 5980 QPATCH.EP 5990 .EP 6000 QPATCH STA ONLINE+1 6010 STA * 6020 RTS 6030 *-------------------------------- |
| Special Version of S-C Macro for Huge Symbol Tables | Bob Sander-Cederlof |
Sometimes there just is not enough memory to hold the entire symbol table of a large assembly, especially in the ProDOS version of the S-C Macro Assembler. In that version, the symbol table normally begins at $1000 and grows upward, while the source program snugs up against $7400, hanging downward from there. Even with the use of the .INB directive to bring in segments of the source code one disk block at a time, extra-large programs can run out of memory during assembly. It can be especially frustrating in an Apple //e or later machine, when you know there is a lot of free memory just across the Soft-Switch River, over there in Aux-land.
Until now I have resisted using this memory, trying to remain fully compatible with older 64K machines and trying to keep the speed advantages of all-main-memory. But finally, the need became personal enough. I created a special version which puts the entire symbol table in Aux RAM. It will run on a 128K or larger //e, //c, or IIgs; I haven't tried it, but it should also run in an Apple II Plus with an Applied Engineering Transwarp card plugged and turned on. The symbol table still begins at $1000, but in AuxRAM; and it can rise as high as $BFFF without challenge. That is $B000 total bytes, or about twice as many as were available between $1000 and the bottom of the source program in MainRAM. The space below $1000, down as far as $800, is occupied by macro private labels, if you use any. Obviously, there is also now more room in Main RAM for your source code and/or object code. A Minus: if you have a /RAM disk installed in AuxRAM, the symbol table walks all over it. However, if you are using a RamWorks card or the like, with their PRODRIVE software, bank 0 of AuxRAM is left available for just these type uses.
If you need something like this, it's finally here. I'm calling it Version 2.1, and as a registered owner of the ProDOS version of the S-C Macro Assembler you can have a copy for only $10.
| "IIgs Toolbox Reference" Now Available | Bob Sander-Cederlof |
At long last, Addison-Wesley assures me they have printed the "IIgs Toolbox Reference" manuals, Volumes 1 and 2. These are probably indispensable tools for any serious IIgs programmers. Until now, you could only get them in beta versions through APDA. They are over 750 pages each, and cost $26.95 each ($24 plus shipping charge if you order from us). Each of the standard tools is described in great detail, with examples in both assembly language and C.
If they kept the same arrangement as my pre-beta copy (dated Nov 1986), there are a total of 23 chapters in the set. In my edition, Volume 1 covers toolsets in general, Desktop Bus, Control Mngr, Desk Mngr, Dialog Mngr, Event Mngr, Font Mngr, Integer Math, Line Edit, Memory Mngr, Menu Mngr, Misc.Tools, and Print Mngr; Volume 2 covers Quickdraw, SANE, Scheduler, Scrap Mngr, Sound Mngr, Std. File Operations, Text.tools, Tool Locater, and Window Manager. Volume 2 also includes an appendix on writing your own tool set.
There remains one more book in the IIgs series, the "IIgs Programmer's Introduction". A-W is now predicting April '88 for the publishing date, and a price of $32.95. I guess I am old-fashioned, but to my mind this book should have been published FIRST, and included FREE with every IIgs purchase. Oh, well.... We will accept orders on this one now, and hold them until the book comes, at a price of $30 plus shipping (see note on page 3 for details on shipping charges).
| Display Volumes | Bob Sander-Cederlof |
BONUS PROGRAM (not printed in the original newsletter)
1000 .LIST XOFF
1010 *SAVE ONLINE.CMD
1020 *--------------------------------
1030 BUFFER .EQ $2000
1040 *--------------------------------
1050 PRBYTE .EQ $FDDA
1060 COUT .EQ $FDED
1070 CROUT .EQ $FD8E
1080 *--------------------------------
1090 MLI .EQ $BF00
1100 *--------------------------------
1110 T
1120 DISPLAY.VOLUMES
1130 JSR MLI
1140 .DA #$C5,ONLINE
1150 LDA #0
1160 .1 PHA
1170 TAY
1180 LDA BUFFER,Y
1190 BEQ .5 ...END OF LIST
1200 PHA
1210 LDA #"S"
1220 JSR COUT
1230 PLA
1240 PHA
1250 LSR ISOLATE SLOT NUMBER
1260 LSR
1270 LSR
1280 LSR
1290 AND #7
1300 ORA #"0"
1310 JSR COUT PRINT SLOT NUMBER
1320 LDA #","
1330 JSR COUT
1340 LDA #"D"
1350 JSR COUT
1360 PLA
1370 PHA
1380 ASL SET CARRY IF DRIVE 2
1390 LDA #"1" ASSUME DRIVE 1
1400 ADC #0 CHANGE TO 2 IF TRUE
1410 JSR COUT
1420 LDA #" " PRINT SPACE
1430 JSR COUT
1440 PLA get dsssllll again
1450 AND #$0F isolate length
1460 BEQ .3 no name, show error code
1470 TAX
1480 LDA #"/"
1490 .2 JSR COUT
1500 INY PRINT THE VOLUME OR FILE NAME
1510 LDA BUFFER,Y
1520 ORA #$80
1530 DEX
1540 BPL .2
1550 LDA #"/"
1560 BNE .4 ...ALWAYS
1570 .3 LDA #"("
1580 JSR COUT
1590 LDA BUFFER+1,Y GET ERROR CODE
1600 JSR PRBYTE
1610 LDA #")"
1620 .4 JSR COUT
1630 JSR CROUT
1640 *--------------------------------
1650 .5 CLC POINT TO NEXT VOLUME NAME
1660 PLA
1670 ADC #16
1680 BCC .1 STILL IN SAME PAGE
1690 RTS
1700 *--------------------------------
1710 ONLINE .DA #2,#0,BUFFER
1720 *--------------------------------
1730 .LIF
|
Apple Assembly Line (ISSN 0889-4302) is published monthly by S-C SOFTWARE CORPORATION,
P. O. Box 280300, Dallas, TX 75228 Phone (214) 324-2050.
Subscription rate is $24 per year in the USA, Canada, and Mexico, or $36 in other countries.
Back issues are $1.80 each for Volumes 1-7, $2.40 each for Volume 8
(plus postage). A subscription tothe newsletter with a Monthly
Disk containing all program source code and article text is $64 per year in
the USA, Canada and Mexico, and $90 to other countries.
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.)