In This Issue...
Jerry Lewis (not the entertainer), a subscriber from New Boston, Michigan, recently worked with Phil Wershba at SCRG to modify chip 0 on the QuikLoader card. The result is the ability to include ProDOS in chip 0. If you already have a QuikLoader, Phil says upgrades are available (there is a small fee this time). Call Phil at 1-800-635-8310. If you do not have a QuikLoader yet, and want one, you can order from us (we wil even save you a few dollars!).
Jim Davis (not the cartoonist), a subscriber in Upland, California, has a business that may be of interest to a lot of you. He will buy broken computers, especially Apple II and IIPlus models. He will also do chip-level repair of computers, power supplies, and 5.25" disk drives. If you have a II or IIPlus that will not quite work with a 65C02, and you wish it would, he will modify the motherboard for you so that it works. I haven't tried out his services yet, but if it sounds interesting call him at (714) 982-0860. Or write to him at Beehive Enterprises, 1476 N. Grove Ave., Upland, CA 91786.
In spite of the ton of documentation Apple has made available to developers about the //gs, there is a lot of nitty-gritty detail that we need and have not got. Or at least it is very difficult to find the important, weed out the inaccurate, sift through the mutually contradictory, and so on.
I have been trying to get a complete and accurate map of the I/O addresses in the $C000-$C07F range, and I think I am getting close. Here is a summary of what I have learned.
The following addresses have exactly the same function in the //e and the //gs:
$C000 - $C01F Keyboard & Memory mapping $C030 Speaker Toggle $C050 - $C05F Graphics modes & Gameport ANx $C061 - $C067 Gameport buttons & Paddles $C070 Paddle Trigger $C080 - $C08F Language card control
The following //e addresses have no function in the //gs, but are reserved for future expansion:
$C020 was cassette output toggle $C040 was gameport utility strobe
The address $C060 was used for cassette input in //e, II+, and II systems. In the //gs some sources say $C060 is used for a fourth gameport switch input, called switch 3 (I cannot find such a signal on any gameport pin in my //gs). $C061 through $C063 are still called switches 0, 1, and 2. $C061 is still attached to the Open-Apple key, and $C062 to the Solid-Apple.
$C071-$C07F is used by the //gs for ROM-based code, rather than soft swtiches. This range of memory is always available, so interrupts vector here.
C071: E2 40 SEP #$40 SET V-BIT C073: 50 (BVC OPCODE, SKIPS NEXT BYTE) C074: B8 CLV CLR V-BIT C075: 5C 10 00 E1 JMP $E10010 C079: 38 SEC C07A: 90 (BCC OPCODE, SKIPS NEXT BYTE) C07B: 18 CLC C07C: 5C 5B B6 FF JMP $FFB65B
Address $C021 controls the NTSC video output. Store $80 to kill color output, or $00 to enable color. This has no effect on the RGB output.
Address $C022 controls the RGB video output text and background color. The high four bits determine the text (foreground) color, and the low four bits determine the background color. The border color is controlled by the low four bits of $C034. In all of these, the color code is the same as lo-res graphics.
$C023 = VGC interrupt status and enable byte. $C024 = Mouse data byte $C025 = Keyboard data register bit 7 = Open-Apple bit 6 = Solid-Apple bit 5 = flags this data updated without a keypress bit 4 = numeric keypad key depressed bit 3 = repeat active bit 2 = caps lock down bit 1 = control key down bit 0 = shift key down $C026 = data register for talking to 50740 chip $C027 = keyboard and mouse status byte $C028 = ROM bank toggle. In the normal state with LCROM and I/O shadowing on addresses $D000-FFFF map directly into the same locations in bank $FF. After one LDA $C028, $D000-FFFF access $9000-BFFF in bank $FF. State of the toggle may be read in $C068 (state register) bit 1. $C029 = control for new video states. bit 7 = enable super hi-res bit 6 = enable linear addressing for hi-res bit 5 = force monochrome in super hi-res bit 0 = enable bank 1 latch Whatever you do to the data in this byte, be sure you do not change bit 0. First read the byte, then change bits 5,6,7 as you like, then store the byte. $C02A = reserved $C02B = foreign language selection bits 765 = 0 for USA English = 1 for UK English = 2 for French = 3 for Danish = 4 for Spanish = 5 for Italian = 6 for German = 7 for Swedish bit 4 = 0 for NTSC, = 1 for PAL bit 3 = 1 for above languages, = 0 for USA The ASCII codes which change are $23, 40, 5B, 5C, 5D, 60, 7B, 7C, 7D, and 7E. $C02C = Address for test mode read of character ROM $C02D = slot ROM enables, where bit x controls slot x. (do not enable slot 0 or 3!) $C02E = vertical video address / 2 $C02F = horizontal video address in bits 6-0 lsb of vertical address in bit 7 In NTSC mode, the vertical address runs from $0FA through $1FF, for 262 lines. The horizontal address runs from 40 through 7F, and 00 (65 different values) $C031 = 3.5" disk drive control bit 7 = head select bit 6 = drive enable $C032 = Clear Scan interrupt bit 6 = 0 to clear 1 second interrupt bit 5 = 0 to clear scanline interrupt $C033 = clock chip data register $C034 = clock chip control register & border color bit 7 = 1 to strobe data into clock = 0 when data has been accepted bit 6 = 1 to read chip, =0 to write chip bit 5 = chip enable after transfer bits 3-0 = border color $C035 = shadow control register bit 6 = 0 to shadow I/O and "Language card". When IOLC shadowing is on, the RAM at $C000-CFFF is folded into a second bank at $D000-DFFF, making a "language card". bit 4 = 0 to shadow aux hi-res page (used with bits 1 and 2 to inhibit shadowing in bank $01) bit 3 = 0 to shadow 32K video buffer ($2000-9FFF in bank $00) bit 2 = 0 to shadow hi-res page 2 ($4000-5FF in banks $00 and $01) bit 1 = 0 to shadow hi-res page 1 ($2000-3FFF in banks $00 and $01) bit 0 = 0 to shadow text pages ($400-7FF in both banks $00 and $01. Text page 2, $800-BFF, is never shadowed.) RESET clears this register, enabling all shadowing. $C036 = speed control and disk motor on detection bit 7 = 0 for slow speed bit 4 = 0 (if you make it =1, it will stop you cold! I got FATAL SYSTEM ERROR 0681. Supposedly it causes shadowing in ALL banks!) bits 3-0 = motor on detection bits for slots 7-4. For example, if bit 2 is on, the system will slow down to 1MHz operation when the address $C0E9 (slot 6 motor-on command) is detected. The system will speed up again when $C0E8 (slot 6 motor-off) is detected, unless bit 7 = 0. $C037 = DMA bank address register $C038 = SCC channel B command register $C039 = SCC channel A command register $C03A = SCC channel B data register $C03B = SCC channel A data register $C03C = sound control bit 7 = 1 if busy bit 6 = 1 to enable auto-increment bit 5 = 0 to access chip, =1 to access RAM bits 3-0 = volume of DAC $C03D = sound data register $C03E = sound address low $C03F = sound address high $C041-$C048 used for mouse $C049-$C04F reserved $C068 = state register (both read and write) same as bit 7 of bit 7 = ALTZP $C016 bit 6 = PAGE2 $C01C bit 5 = RAMRD $C013 bit 4 = RAMWRT $C014 bit 3 = RDROM $C012 bit 2 = LCBANK $C011 bit 1 = ROMBNK ----- reads $C028 toggle bit 0 = SLOTCX $C015 $C069-$C06C reserved $C06D = test mode bit register $C06E = clear test mode $C06F = set test mode
I don't have the foggiest idea what the test mode is or how to use it, but it sounds interesting.
I hope with this information as a start, you can learn a lot more about your //gs. If you find any errors above, please let us know.
C02x C03x C04x C05x C06x 0 --rsvd-- Speaker --rsvd-- Graphics Switch 3?? 1 MONO 3.5 Disk Mouse Int Text Switch 1 2 TXT Color Scan Int --rsvd-- Unmixed Switch 1 3 VGC Int Clock Data --rsvd-- Mixed Switch 2 4 MouseData Clock Ctrl M Delta X Text 1 Paddle 0 5 Key Mods Shadow M Delta Y Text 2 Paddle 1 6 KM Data Speed M Flags Lo Res Paddle 2 7 KM Status DMA Bank VBL Int Hi Res Paddle 3 8 ROM Bank SCC B Cmd XY Int Clr AN0 State Reg 9 New Video SCC A Cmd --rsvd-- Set AN0 --rsvd-- A --rsvd-- SCC B Data --rsvd-- Clr AN1 --rsvd-- B Lang Sel SCC A Data --rsvd-- Set AN1 --rsvd-- C CharROM Sound Ctrl --rsvd-- Clr AN2 --rsvd-- D Slot ROM Sound Data --rsvd-- Set AN2 Test Mode E Vert Cnt Sound AdrL --rsvd-- Clr AN3 Test Off F Horiz Cnt Sound AdrH --rsvd-- Set AN3 Test On
I have been trying to piece together a lot of DOS 3.3 improvements published in back issues of Apple Assembly Line, and I especially wanted to fit the Text File I/O improvements made by Paul Schlyter. (See AAL July 1983: "Speeding Up Text File I/O", by Paul Schlyter; and "Making Paul's Patches Fit in DOS", by Bob Sander-Cederlof.) Bob has said in several phone conversations that he continues to have reservations about using this patch, because of the possibility of DOS becoming confused over the state of the File Manager Workarea. He even suggestED using the space for some other improvements.
Why didn't I follow his advice? I guess the idea of a faster way of handling TEXT files is so attractive that I keep thinking the approach can be made to work. I made some small changes to the 1983 patches, and I believe they are now safe. Bob's last-minute warning on page 17 of the 1983 article still holds, however: do not try to install the patch from inside an EXEC file. You should not patch a piece of code while it is being used! The code as it is here can be BRUN from within a small HELLO program with no trouble.
The boxed comment on page 16 of the 1983 article, about patching $A1B1 to $14, was interesting. This value determines how many locations will be cleared to zero by the loop starting at $A1AE. The loop as coded in DOS clears too many bytes, so Bob's patch fixes it. Then he can use those bytes at the end for a variable of his own. Another loop at $ABDC also clears out the location Bob wanted to use, but it did not interfere with Bob's use. I chose to avoid the problem by using a different location for my PNTR.SAVE variable: $B5FE,B5FF. This is still close enough to $B5C7 (start of FM workarea) to use the indexing trick (at lines 1740,1750 in my program).
I saved the one extra byte Bob mentioned on page 15 of his article, by avoiding the SEC in the CHECK.OPCODE subroutine. I changed the origin of the patch from $B6B3 to $B6B4, to give one more byte to another set of patches I am using.
Bob's main reservation about using the speedup was the danger of FLAG being set without a valid address in PNTR.SAVE. I avoid this by not setting FLAG until after placing a valid address in the pointer (lines 1820-1840), and by clearing FLAG before using the pointer to save the workarea (lines 1730-1760).
FLAG is cleared by all FM commands other than Read and Write, including INIT, so there is no way an initialized disk will have the sign bit of FLAG set. If you follow all abnormal exits from handling text files with the CLOSE command, that will clear FLAG in those cases; it was good policy to do this even before these patches. [Maybe we should find all those abnormal exits, and make them specifically clear FLAG...]
I hope you like my version and agree that the enhancement can be safely used. All my tests, so far, indicate it is safe.
1000 *SAVE S.FAST TEXT (PITZ) 1010 *-------------------------------- 1020 .OR $300 1030 *-------------------------------- 1040 PPNTR .EQ $00,01 1050 PATCH .EQ $02,03 1060 *-------------------------------- 1070 PATCHER 1080 LDA #PATCHES-1 POINT TO SET OF PATCHES 1090 STA PPNTR 1100 LDA /PATCHES-1 1110 STA PPNTR+1 1120 LDY #0 Y = 0 FROM NOW ON 1130 .1 JSR GET.BYTE LENGTH OF NEXT PATCH 1140 BEQ .4 ...FINISHED PATCHING 1150 TAX LENGTH IN X 1160 JSR GET.BYTE ADDRESS OF PATCH 1170 STA PATCH ...INTO POINTER 1180 JSR GET.BYTE 1190 STA PATCH+1 1200 .2 JSR GET.BYTE NEXT BYTE OF PATCH 1210 STA (PATCH),Y TUCK IT AWAY 1220 INC PATCH POINT TO NEXT ONE 1230 BNE .3 1240 INC PATCH+1 1250 .3 DEX ARE WE FINISHED? 1260 BNE .2 ...NO 1270 BEQ .1 ...ALWAYS 1280 .4 RTS 1290 *-------------------------------- 1300 GET.BYTE 1310 INC PPNTR ADVANCE POINTER 1320 BNE .1 1330 INC PPNTR+1 1340 .1 LDA (PPNTR),Y GET BYTE 1350 RTS 1360 *-------------------------------- 1370 .MA PATCH 1380 .DA #LEN.]1,]2 1390 PAT.]1 .PH ]2 1400 .EM 1410 *-------------------------------- 1420 .MA ENDP 1430 .EP 1440 LEN.]1 .EQ *-PAT.]1 1450 .EM 1460 *-------------------------------- 1470 PATCHES 1480 *-------------------------------- 1490 >PATCH 1,$B6B4 1500 *-------------------------------- 1510 * Paul Schlyter's Text File Speed-up, 1520 * as modified by Bob Sander-Cederlof (June 1983) 1530 * as modified by Louis Pitz (December 1986) 1540 *-------------------------------- 1550 PNTR .EQ $42,43 1560 *-------------------------------- 1570 COPY.BUFFER.TO.WORKAREA .EQ $AE6A 1580 SAVE.WORKAREA .EQ $AE81 1590 POINT.TO.WORKAREA .EQ $AF08 1600 SETUP.PNTR .EQ $AF12 1610 FM.OPCODE .EQ $B5BB 1620 FM.WORKAREA .EQ $B5C7 1630 PNTR.SAVE .EQ $B5FE,B5FF **** 1640 *-------------------------------- 1650 PATCH1 JSR CHECK.OPCODE 1660 BCC .1 NOT READ/WRITE 1670 CMP PNTR.SAVE 1680 BNE .1 NO 1690 CPX PNTR.SAVE+1 1700 BEQ PATCH3 YES, RETURN NOW 1710 .1 BIT FLAG 1720 BPL .2 1730 LSR FLAG CLEAR SIGN BIT **** 1740 LDX #PNTR.SAVE-FM.WORKAREA 1750 JSR SETUP.PNTR 1760 JSR SAVE.WORKAREA **** 1770 .2 JMP COPY.BUFFER.TO.WORKAREA 1780 *-------------------------------- 1790 PATCH2 JSR CHECK.OPCODE 1800 BCS .1 ... READ OR WRITE **** 1810 JMP SAVE.WORKAREA **** 1820 .1 STA PNTR.SAVE 1830 STX PNTR.SAVE+1 1840 ROR FLAG SET SIGN BIT 1850 PATCH3 RTS 1860 *-------------------------------- 1870 CHECK.OPCODE 1880 JSR POINT.TO.WORKAREA 1890 LDA FM.OPCODE 1900 CMP #3 READ? **** 1910 BEQ .1 YES 1920 CMP #4 WRITE? **** 1930 BEQ .1 1940 CLC 1950 .1 LDA PNTR 1960 LDX PNTR+1 1970 RTS 1980 *-------------------------------- 1990 FLAG .HS 00 MUST START WITH FLAG=0 2000 *-------------------------------- 2010 >ENDP 1 2020 *-------------------------------- 2030 .LIST MOFF 2040 >PATCH 2,$AB0B 2050 .DA PATCH1 2060 >ENDP 2 2070 *-------------------------------- 2080 >PATCH 3,$B38F 2090 .DA PATCH2 2100 >ENDP 3 2110 *-------------------------------- 2120 .DA #0 <<< END OF PATCHES >>> 2130 *-------------------------------- |
The Apple monitor has always had a control-Y command, called the "user" command. It allows you to add at least one command to the monitor on a temporary basis. The older versions merely JMPed to $03F8, but the //gs does a little more.
If you ran my program from last month's AAL, which printed out the addresses in the //gs monitor command table for each command, you found out that the ctrl-Y command starts at $FE13. To see what that is, enter the monitor L command as follows:
*FF/FE13L
The code in my //gs is CLC, XCE, and JMP $E100A0. The instruction installed at $E100A0 when you turn on the //gs is JMP $FFFE19, and the code at FFFE19 is SEC, XCE, and JMP $03F8. So we end up at $3F8 after all!
If you want to, you can ignore the new stuff and just use ctrl-Y like you did in the old days. Or, you can put a 3-byte address for a Native mode program into the JMP instruction at $E100A0.
I wrote a program to link into the $E100A0 vector and print out the registers, the mode, and the M and X status bits. I wanted to see for certain in what state the monitor called my ctrl-Y code.
Lines 1080-1150 install the address of my ctrl-Y code in the bank $E1 vector.
Lines 1180-1240 save the mode and the three main registers. Lines 1180-1210 on entry operate together with lines 1590-1610 at the exit, allowing me to run in Emulation mode regardless of the mode my caller was in. My program returns to the caller's mode and mx-state when it is finished.
Lines 1250-1350 show the A-, X-, and Y-registers as they were upon entry. I am only showing the low-byte of each of these, even though in the 65816 they have two bytes. Shame on me!
Lines 1410-1540 print either "EMULATION MODE" or "NATIVE MODE: M=1, X=1". If you write a little driver program to call MY.Y with various other combinations of M and X, you will see that MY.Y prints them as you have them.
Lines 1640-1680 print a message followed by the contents of the A-register in hexadecimal. I use it to print the contents of the three registers.
Lines 1700-1740 print "0" if the Z status bit is set upon entry; otherwise, they print a "1".
Lines 1760-1800 are just about the shortest loop for printing out an ASCII string I have come up with in my ten years of Apple programming. Strings are assembled with bit 7 high, and terminated by a 00 byte. On entry, the Y-register points to the string to be printed, relative to the base address QTS. If you read AAL a lot, you have surely seen this little gem a lot.
After assembling the program with the S-C Macro Assembler, type MGO MY.Y to see the state of things when the program is called that way. Then type dollar sign, control-O, control-Y, and the RETURN key, to see the state of things when the ctrl-Y command is used. Or, go to the monitor with the MNTR command, and then just type a control-Y and RETURN. You might also try it with various configurations of hex values before the control-Y.
1000 *SAVE TEST.CTRL.Y 1010 *-------------------------------- 1020 .OP 65816 1030 *-------------------------------- 1040 MON.COUT .EQ $FDED 1050 MON.PRBYTE .EQ $FDDA 1060 MON.CROUT .EQ $FD8E 1070 *-------------------------------- 1080 T 1090 LDA #MY.Y INSTALL CTRL-Y VECTOR 1100 STA $E100A1 1110 LDA /MY.Y 1120 STA $E100A2 1130 LDA #0 1140 STA $E100A3 1150 RTS 1160 *-------------------------------- 1170 MY.Y 1180 PHP SAVE MX BITS 1190 SEC 1200 XCE 1210 PHP SAVE E-BIT 1220 PHA 1230 PHX 1240 PHY 1250 *---Display registers------------ 1260 LDY #Q.AEQ 1270 LDA 3,S 1280 JSR DISPLAY.REG 1290 LDY #Q.XEQ 1300 LDA 2,S 1310 JSR DISPLAY.REG 1320 LDY #Q.YEQ 1330 LDA 1,S 1340 JSR DISPLAY.REG 1350 JSR MON.CROUT 1360 *---Display mode & mx bits------- 1370 LDA 4,S E-BIT 1380 AND #1 1390 BNE .1 ...emulation mode 1400 *---Native mode------------------ 1410 LDY #Q.NATIVE 1420 JSR QTO 1430 LDA 5,S MX BITS 1440 AND #$20 ISOLATE M BIT 1450 JSR PRINT.0.OR.1 1460 LDY #Q.XEQ 1470 JSR QTO 1480 LDA 5,S MX BITS 1490 AND #$10 ISOLATE X BIT 1500 JSR PRINT.0.OR.1 1510 BRA .2 1520 *---Emulation mode--------------- 1530 .1 LDY #Q.EMUL 1540 JSR QTO 1550 *---Return to caller------------- 1560 .2 PLY 1570 PLX 1580 PLA 1590 PLP RESTORE E-BIT 1600 XCE 1610 PLP RESTORE MX BITS 1620 RTS 1630 *-------------------------------- 1640 DISPLAY.REG 1650 PHA 1660 JSR QTO 1670 PLA 1680 JMP MON.PRBYTE 1690 *-------------------------------- 1700 PRINT.0.OR.1 1710 BEQ .1 1720 LDA #1 1730 .1 ORA #"0" CHANGE TO ASCII "0" OR "1" 1740 JMP MON.COUT 1750 *-------------------------------- 1760 QTO1 JSR MON.COUT 1770 INY 1780 QTO LDA QTS,Y 1790 BNE QTO1 1800 RTS 1810 *-------------------------------- 1820 QTS 1830 Q.AEQ .EQ *-QTS 1840 .AS -/A=/ 1850 .HS 00 1860 Q.XEQ .EQ *-QTS 1870 .AS -/, X=/ 1880 .HS 00 1890 Q.YEQ .EQ *-QTS 1900 .AS -/, Y=/ 1910 .HS 00 1920 Q.NATIVE .EQ *-QTS 1930 .AS -/NATIVE MODE: M=/ 1940 .HS 00 1950 Q.EMUL .EQ *-QTS 1960 .AS -/EMULATION MODE/ 1970 .HS 00 1980 *-------------------------------- |
If you are running the DOS 3.3 version of my assembler in a 64K or larger Apple, and if you are not using the Laumer Research Full Screen Editor, then you have a 4K bank of RAM available for adding features. It is a little tricky to use, but I am going to show you a secret which will make it easier.
Version 2.0 of the S-C Macro Assembler has several built-in handles for user extensions: USR, PRT, Esc-U, the "." command, and the .US directive. The program below illustrates how to vector the USR directive into the alternate bank at $D000, and how to get back.
Lines 1160-1480 are a program to install your USR code. The first section copies your code into the $D000 bank, and the second section patches the USR vector in the S-C Macro Assembler. I put the origin at $2000 for the installation code, because that is a free area (big enough to hold all the code which will fit at $D000) right after loading the S-C Macro Assembler. You can either manually install it by typing "BRUN B.USR.CODE", or add that line to the EXEC file used to load the S-C Macro Assembler.
The only patch made in the S-C Macro code is to replace the JMP $D028 which is at $D006 with a LDA $C08B instruction. When you type the USR command S-C will jump to $D006, execute the LDA $C08B, and suddenly find itself at $D009 in the alternate bank. That is where your USR program should begin, as you can see in my program below at lines 1570-1620. I made my first instruction in the USR code be another LDA $C08B, which write-enables the RAM. If my code used any of the $Dxxx area for variables, I would need it to be write-enabled.
To get back to the S-C code, the USR program jumps to $D000 (see line 1720 and lines 1510-1530). The instruction there is a LDA $C083, which switches back to S-C's $D000 bank and continues execution at $D003, which is one of S-C's soft entry points.
You could use the six bytes from $D003 through $D008 for variables, if you wish.
You can also link into the PRT command in this same manner, putting the LDA $C08B instruction at $D009 in the S-C bank, and gaining control at $D00C in the alternate bank. If you want both USR and PRT, you can do that too. Just make the instruction at $D009 in the USR-PRT bank a JMP USR, and start the PRT code at $D00C. The "." command can be set up the same way. The .US directive and the Esc-U keyboard function would take a little more setup, because they do not return to the soft re-entry of S-C Macro.
My code at lines 1630-1700 is purely a demonstration, to prove that the USR command really works. Use your imagination, create some really useful functions, and replace my demo with them.
Phil Goetz has sent me the source code for a Symbolic Step/Trace/Disassembly Utility that would fit into this USR patch very nicely. In fact, he had it set up in a similar manner, and his work led me to the discovery of this technique. If all goes well, we should be able to publish his program soon.
Meanwhile, see what you can do with this new tool.
1000 *SAVE S.USER DEMO 1010 *-------------------------------- 1020 * Demonstration of linking the USR command 1030 * in the DOS 3.3 version of S-C Macro 1040 * Assembler (loaded at $D000), to a 1050 * program located in the alternate bank 1060 * at $D000. 1070 *-------------------------------- 1080 .OR $2000 1090 .TF B.USR.CODE 1100 *-------------------------------- 1110 SRCP .EQ $00,01 1120 DEST .EQ $02,03 1130 *-------------------------------- 1140 USR.VECTOR .EQ $D006 thru $D008 1150 *-------------------------------- 1160 INSTALLER 1170 LDA $C08B Select alternate $D000 bank 1180 LDA $C08B and write-enable it 1190 *---Set up pointers for move----- 1200 LDA #USR.CODE 1210 STA SRCP 1220 LDA /USR.CODE 1230 STA SRCP+1 1240 LDA #$D0 1250 STA DEST+1 1260 LDY #0 1270 STY DEST 1280 LDX /USR.CODE.LEN+255 1290 *---Move code into destination--- 1300 .1 LDA (SRCP),Y 1310 STA (DEST),Y 1320 INY 1330 BNE .1 1340 INC SRCP+1 1350 INC DEST+1 1360 DEX 1370 BNE .1 1380 *---Install User Vector---------- 1390 LDA $C083 Select S-C $D000 bank 1400 LDA $C083 and write-enable it 1410 LDA #$AD "LDA $C08B" 1420 STA USR.VECTOR 1430 LDA #$C08B 1440 STA USR.VECTOR+1 1450 LDA /$C08B 1460 STA USR.VECTOR+2 1470 *---Return to S-C Macro---------- 1480 JMP $D003 1490 *-------------------------------- 1500 USR.CODE .PH $D000 1510 RETURN.TO.SC.MACRO 1520 LDA $C083 Next instruction in other bank 1530 * at S-C Macro "SOFT" entry. 1540 *-------------------------------- 1550 .BS 6 These six bytes could be used 1560 * for variables if you wish. 1570 *-------------------------------- 1580 * USR.ENTRY must be at $D009, because the USR 1590 * command in S-C is a bank switch at $D006-8. 1600 *-------------------------------- 1610 USR.ENTRY 1620 LDA $C08B Finish write-enabling this bank 1630 *---User program here------------ 1640 LDY #0 You substitute a REAL program here! 1650 .1 LDA MESSAGE,Y 1660 BEQ .2 1670 JSR $FDED PRINT A CHARACTER 1680 INY 1690 BNE .1 ...ALWAYS 1700 .2 JSR $FBE2 RING THE BELL JUST FOR FUN 1710 *---Return to S-C Macro---------- 1720 JMP RETURN.TO.SC.MACRO 1730 *-------------------------------- 1740 MESSAGE 1750 .HS 8D 1760 .AS -/This is just a demonstration/ 1770 .HS 8D 1780 .AS -/of the USR command./ 1790 .HS 8D.8D.00 1800 *-------------------------------- 1810 .EP 1820 *-------------------------------- 1830 USR.CODE.LEN .EQ *-USR.CODE 1840 *-------------------------------- |
When a ProDOS device driver reads or writes a block, it is supposed to return an error code in the A-register. If there was an error, this number will be nonzero, and the Carry status bit will be set. If there was no error, the A-register is supposed to contain zero, and Carry will be clear.
The other day I was working with a program that was supposed to read and write blocks from the /RAM drive under ProDOS. My program printed the error code returned by the call, and I was getting a non-zero value in the A-register even when there was no error. I just assumed this was a trivial bug in ProDOS, and ignored it. However, I was not using the standard ProDOS /RAM driver, because I had installed the Applied Engineering driver which uses the entire RAMWORKS card for /RAM. Anyway, I just went on about my business.
A few days later the January 1987 issue of Nibble arrived at my doorstep. In a letter to the editor on page 123, from Steven Humpage, there was an explanation of the bug. The part of the device driver that resides in Main RAM is located at $FF00. At $FF47 is a routine named EXIT, which restores some zero-page locations, restores a vector in page 3, and returns. This code is called with either zero in A and Carry clear, or an error code in A and carry set. The routine begins with PHP, PHA and ends with PLP, PLA. WRONG! This swaps the P- and A-registers. Since the C-bit is bit 0 in the P-register, a zero (from the A- register) results in carry clear. However, the P-register con- tents come back in A, something like $36. Since the only error code the /RAM driver returns is $27, and this has bit 0 set, swapping registers leaves carry set. It also sets the V-bit, which could be unexpected. The error code in A now becomes what the status was, so we get an error code of $35, I believe.
The same bug exists in AE Prodrive. The bug can easily be fixed, by the following sequence. I am showing it as I do it from within the S-C Macro Assembler. If you do it from within BASIC.SYSTEM, you will have to CALL-151 to get into the monitor to install the patch.
:UNLOCK PRODOS :UNLOCK PRODRIVE :BLOAD PRODOS,TSYS,A$2000 :BLOAD PRODRIVE :$2C5F:68 28 :$245F:68 28 :BSAVE PRODOS,TSYS,A$2000 :BSAVE PRODRIVE :LOCK PRODOS :LOCK PRODRIVE
I am assuming ProDOS 1.1.1. The bug has already been fixed in version 1.2.
While we are at it, Humpage also pointed out another bug which affects both ProDOS and Prodrive. The code which ProDOS puts into pages 2 and 3 in the AuxRAM has an error. The CMP #$0D at $34A should be CMP #$0E. As it is it allows writing to block 7, which is then mapped back over the top of page zero and one, clobbering things disastrously. This change write protects that block. You only need to change the PRODOS file, because Prodrive uses it also. Change $2B4B from $0D to $0E.
The //gs Monitor (that which you get by typing CALL -151 in Applesoft, not the video screen) has a lot of neat new features. There are a significant number of new commands, and new capablilities to old ones.
The first thing you need to know is that you can now use 24-bit addresses in the monitor. These are entered by typing the bank number, a slash, and the 16-bit address within the bank. The monitor remembers the last bank number entered, so you do not necessarily have to type the bank number. For example, to examine memory in the monitor ROM itself, you could type the following:
*FF/F800.FFFF
If you try that, you will notice that both hex and ASCII values are shown for each location. If you are in 40-column mode, you get eight bytes per line as in older monitors; however, in 80-column mode you now get sixteen bytes per line. This means you can easily see an entire page in both hex and ASCII on the screen at once.
Another difference in addressing involves accessing so-called "language card" RAM. In older monitors you could flip the soft switches using monitor commands, and then address the language card. Of course, if you flipped it into a mode to read from the language card RAM, you had to first be sure to make a copy of the monitor ROM in RAM. Anyway, this no longer works. Now you cannot really flip those switches, because the //gs monitor will flip them right back before the next command. Now you can address all the RAM from $C000 to $FFFF in any bank directly.
If you have I/O shadowing on, and you almost always do, then addresses in banks $00 and $01 in the range $C000-CFFF are I/O addresses. The I/O addresses are really in banks $E0 and $E1, but shadowing makes them accessible also in these other banks. To access the $Cxxx addresses in RAM in those four banks, you can see them at $Dxxx by changing the value of a monitor variable "L". Type "1=L" to see the $Cxxx region (2nd bank of language card), or "0=L" to see the real $Dxxx region (1st bank of language card).
That reminds me of another difference. Most of the time the //gs monitor does not care whether you type in upper or lower case. However, some commands are case sensitive. Commands which use a register name, such as the "=" command, are case sensitive. Register names MUST be in the proper case. Some registers must be in upper case, and some must be in lower case.
The disassembler in the //gs monitor handles the entire 65816 opcode set. It has all the expected trouble handling immediate mode disassembly, since there is no way the monitor can tell what mode code will be in when it is executed. You have to control the state of the disassembler's m- and x-bits yourself, by entering commands at the appropriate times. You control their state by typing any of these four commands:
0=m 1=m 0=x 1=x
This can be pretty messy and painful, but it is one of those things we have to put up with. Of course, the monitor could be a little smarter, and TRY to follow the XCE, REP, and SEP commands, assuming that normal code will be "nice". Then we could just override when absolutely necessary. However, we have to live with what is there for now.
The disassembler now puts out a status line at the top of each set of 20 lines, which shows the state of the m- and x-bits, and the L-variable mentioned above. This is somewhat of a nuisance when using "LLLLLLL" to print out a long range, but we can live with it too. Another difference is that BRK disassembles with a one-byte value in the operand field. This has always been the correct way to handle BRK, but nobody knew it in the assembler and dis-assembler business until the 65816 came out.
The mini-assembler is also included in the //gs monitor. You get into it by using the "!" command. The prompt changes from "*" to "!". You can leave the mini-assembler and go back to the monitor by typing a RETURN key immediately after the prompt. Operation inside the mini-assembler is just like the old mini-assembler, with a few enhancements. You can assemble to any bank of RAM, specifying the bank before a slash. All of the 65816 opcodes can be assembled. You indicate 16-bit immediate by typing 3- or 4-digit values after a "#", 8-bit immediate by typing 1- or 2-digit values.
You can also enter ASCII and hex values while in the mini- assembler. Type a quotation mark followed by the characters you wish to enter in ASCII mode. Terminate the string with a RETURN. Type a colon to indicate that you are entering hex values. The number of bytes of hex data you store depends on the number of digits you type; you can type from 1 to 8 digits, occupying 1 to 4 bytes. Multi-byte values will be stored with the least significant byte first. Practice with these a while and you will get the hang of it.
Step and Trace commands are included in the //gs monitor, but they are not "plugged in". They point to vectors in bank $E1, and all they do now is print "Step" and "Trace". The TRACE vector is at $E1/0074, and the STEP vector is at $E1/0078. By loading a real Step/Trace program into RAM and hooking into the vectors, you can get them to work. I have seen them work, but I do not know where to put my hands on the working code or how to load it if I had it. Do any of you?
Here are the commands, with brief commentary. (The ^ means "Control-"; "addr" may be in form "bb/aaaa" or "aaaa".)
^B JMP $00E000, initial entry to Applesoft. ^C JMP $00E003, re-enters Applesoft. Q JMP $0003D0, re-enters DOS or ProDOS. ^Y JMP $E000A0, which normally does JMP $0003F8. ^E Examine Stored Registers. Displays the contents of A X Y S D P B K M Q L m x e. ^R Restore Stored Registers to normal monitor mode: A=0000 X=0000 Y=0000 S=01FB D=0000 P=00 B=00 K=00 M=0C Q=80 L=1 m=1 x=1 e=1 value=reg Assign value to a stored register. The register names are case-sensitive: A X Y S D P B K M Q m x e L F. ("F" is Filter for entering ASCII, and will normally be 7F or FF.) s^K Connect input hook to slot s. s^P Connect output hook to slot s. ^S During output, pause-restart. (There appears to also be an entry at the end of the command table for ^S, but it is not really accessible due to the loop counter used.) ^X During memory-range display, terminate command. (This, like ^S, is not really a command.) ^T Similar to Applesoft TEXT command, changes screen display to text page 1. I Switch to Inverse display mode. N Switch to Normal display mode. ^6c Change cursor to new character c. Control-6 DELETE restores original cursor. Control-6 UNDERLINE is especially nice. addrG Pick up stored registers and JSR addr. Only works properly in bank 00, because assumes user returns with RTS. addrX Pick up stored registers and JSL addr. Assumes user returns with RTL. addrR Pick up stored registers and JMP addr. addrL Disassemble 20 lines starting at addr. L Disassemble next 20 lines. addr<addr.addrM Move the range to the target. addr<addr.addrV Compare the range to the target. zz<addr.addrZ Fill the range with single byte value zz. \pattern\<addr.addrP Search range for pattern, which may contain hex values of 1 to 8 digits, hi-ASCII strings ("abcd"), lo-ASCII strings ('abcd'), and may be up to 236 bytes long! \#bytesin #bytesout parm1 ... parmN func# tool#\U Call Tool (tool#) in Toolbox (func#) with parameters (parm1 ... parmN) on the stack. All the items between the \\ must be separated with spaces. #bytesin is total # of bytes that will be pushed onto the stack before calling the tool. #bytesout is the # of bytes the tool will leave on the stack. Wow! I dare you to try it! addrS or S Step, only if loaded into RAM addrT or T Trace, only if loaded into RAM hexvalue= convert hexvalue to decimal =decvalue convert decvalue to hexadecimal =T display date & time mm/dd/yy hh:mm:ss =T=mm/dd/yy hh:mm:ss Set date & time (both must be capital T) addr Display contents of addr. addr.addr Display contents of range. addr:stuff Enter information in hex or ASCII. value+value add value-value subtract value*value multiply value_value divide
An upgrade is now available for the ProDOS version of the S-C XREF program. XREF stands for Cross Reference, and if you are working on large programs with the S-C Macro Assembler you really need it. If you already have it, and are developing programs under ProDOS, you will enjoy this new upgrade.
The new version still fits in the same space, loading between $800 and $FFF. (It is actually a little shorter than the previous release.) There are, however, a lot of new features.
First and foremost, I added the ability to automatically handle a source program which uses the .IN or .INB directive for multiple source files. The previous release required you to create a complex EXEC file to control XREF if you wanted to make a complete cross reference for a program that was spread over several files. Sometimes a lot of juggling was required. For example, when I run XREF on the source code of the S-C Macro Assembler (which consists of over two dozen files on two floppies), I had to make two passes: one pass for symbols beginning with A-L, another for symbols starting with M-Z. The EXEC file for each consisted of over 50 lines. Too much!
Anyway, with the new version I can simply LOAD the main assembly control file (the source file containing the .IN directives) and type "-XREF". The new version automatically letters each included file for purposes of identifying where each cross reference came from. The main file, which contains the .IN directives, is identified by not having a letter. In other words, its identifier is a blank. The first 26 included files are lettered A-Z; the next 26 are lettered a-z; the next 10 are numbered 0-9; if you have another, it gets a punctuation symbol (:). Sixty-four files should be enough!
One reason I have so many separate source files for one program is so that I could squeeze out a meaningful cross reference. With this new version the file size is not so important. During operation, when XREF sees an include directive (either .IN or .INB), only 512 bytes are needed for reading the file. It is read in only one block at a time, equivalent to the normal .INB or .INB1. This leaves a lot more room for symbols.
The new version also prints a legend of the included files, showing the assigned letter or number and the file name for each. This makes it a lot easier to read the printed cross reference listing.
I simplified the syntax analysis portion of XREF, so that tables particularizing it to the opcodes of a single micro- processor are no longer necessary. This means that the same XREF program can operate on the source code of any of our assemblers. Not only 6502, 65C02, and 65816 code, but also 6800, 6805, etc. Now if we could just upgrade all the rest of our cross assemblers to run under ProDOS.... The purpose (in the previous version) for opcode tables was to inform XREF of which opcodes had no operands, and which if any had the option to be used both with and without operands. This is no longer necessary. Instead, I use a single user-set parameter to indicate how many spaces to allow after an opcode before believing the comment field has been reached. The default for this parameter is two, which works well with the 6502 family. Some other micorprocessors, which have opcode names of varying length, might require a higher value. I also added code to terminate the operand scan when a semi-colon is encountered.
Another new user-set parameter allows the user to choose to ignore the ,X and ,Y indexing in the cross reference listing. I personally found no benefit to seeing those two large entries, since X and Y were not really symbol names. The default position for this parameter avoids listing references to X and Y if they are only referenced and never defined within the program. If you liked it the old way, simply change the parameter setting.
I added a third entry point. The first one, at $800, starts with a fresh slate and does a cross reference for the program in memory. $803 continues a cross reference, without erasing the symbols already gathered. The new one, at $806, lists the cross reference that is already in the symbol table. I find this useful when I need a second copy and do not wish to wait for all the files to be processed over again.
I fixed some problems in the processing of the .TI directive, so that titles now appear properly on the cross reference listing. Of course, if you have more than one .TI directive in your source code, the entire cross reference listing will use the last one.
There are more improvements, but this is enough detail for this article. If you already own the S-C XREF, you can get the upgraded ProDOS version for $10. If you purchased the source code with your XREF, we will include the new source code too. If you do not have S-C XREF yet, the price is $50 including source code, with the DOS version on one side and the new ProDOS version on the other.
If you have been thinking about typing in the sample programs from Beneath Apple ProDOS, but just haven't gotten around to it yet, there is an easy way out. Pete Johnson has done all the hard part for you. He typed them in and got them running, after a lot of head-scratching. If you send him $2 and a blank diskette, he will send you a copy. The source files are in the S-C Macro Assembler format, and he includes the binary object files also. The programs are ZAP, FORMAT, TYPE, FIB, and DUMP. He does not include MAP (which is in Basic) and DUMBTERM. Pete's address is P. O. Box 5, New London, Minnesota 56273.
Apple Assembly Line (ISSN 0889-4302) is published monthly by S-C SOFTWARE CORPORATION, P.O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $14 postage for other countries. Back issues are available for $1.80 each (other countries add $1 per back issue for postage).
All material herein is copyrighted by S-C SOFTWARE CORPORATION,
all rights reserved. (Apple is a registered trademark of Apple Computer, Inc.)