1000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1010 ; 1020 ; Special Patch program to allow 800XL owners to use 1030 ; Atari DOS 2.5 with a small RamDisk. 1040 ; 1050 ; Theoretical size of disk is 16KBytes, 1060 ; but 2KBytes are lost to the I/O registers 1070 ; at $D000 to $D7FF and about 1KBytes 1080 ; are lost to overhead. Net is just 1090 ; over 13KBytes. 1100 ; 1110 ; 1120 ; See COMPUTE! magazine, October 1986 issue, 1130 ; for accompanying article: 1140 ; INSIGHT: ATARI 1150 ; 1160 ; Program by Bill Wilkinson 1170 ; released to the public domain 1180 ; 1190 ; Article is Copyright (c) 1986 by COMPUTE! 1200 ; Contact COMPUTE! magazine for reprint 1210 ; permission, etc. 1220 ; 1230 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1240 ; 1250 RAM.DRIVE.NUM = 8 ; RamDisk is drive 8 1260 .PAGE ". Equates to DOS 2.5 Locations" 1270 ; 1280 ; Locations which must be patched to change 1290 ; drive number of RamDisk. 1300 ; 1310 ; (See also August 1986 issue of Compute!) 1320 ; 1330 DPATCH1 = $0780 ; in BSIO routine 1340 DPATCH2 = $0B89 ; in FORMAT routine 1350 ; 1360 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1370 ; 1380 ; Location that says which drive MEM.SAV and DUP.SYS 1390 ; are located on (contains ATASCII character-- 1400 ; not just a byte value) 1410 ; 1420 DRV.MEMDUP = $153F ; just before Mini-DUP 1430 ; 1440 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1450 ; 1460 ; Addresses of subroutines that we must alter 1470 ; 1480 RAMIO.PATCH = $148D ; RamDisk "I/O" routine 1490 SETBANK = $12DE ; sets PIA to select proper bank 1500 ; 1510 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1520 ; 1530 ; Miscellaneous vital locations, equated 1540 ; values, and routines as used by DOS 2.5 1550 ; 1560 RAMSYNC = $12CB ; routine which synchronizes RamDisk transfers 1570 WRTVTOC = $1094 ; write current VTOC back to disk 1580 ; 1590 VTOCPTR = $45 ; pointer to VTOC in memory 1600 ; 1610 DRIVE.MASK = $070A ; the infamous "1802" location 1620 ; 1630 INITDOS = $07E0 ; same as DOS 2.0 and others 1640 FASTRAM = $07DF ; flag: + ==>> sync with VBI 1650 PIABPORT = $D301 ; master bank selector, etc. 1660 DCBSEC = $030A ; sector number in DCB 1670 ZTEMP1 = $43 ; zero page temporary loc'n 1680 E.NAK = $8B ; "NAK" error code from "drive" 1690 ; 1700 ; Equates used to call CIO 1710 ; 1720 XIO.FMT = 254 ; Format command 1730 IOCB = $0340 ; address of first IOCB 1740 IOCB.CMD = IOCB+2 ; where command goes in IOCB 1750 IOCB.BUF = IOCB+4 ; buffer (or name) address 1760 IOCB.AUX1 = IOCB+10 ; Auxilliary byte 1 1770 IOCB.AUX2 = IOCB+11 ; Auxilliary byte 2 1780 ; 1790 CIOV = $E456 ; the classic location 1800 ; 1810 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1820 .PAGE ". Generate Small Patches" 1830 ; 1840 ; First, we generate the single byte patches 1850 ; 1860 *= FASTRAM 1870 .BYTE 0 ; set flag to say we need 1880 ; synchronized transfers 1890 ; 1900 *= DPATCH1 1910 .BYTE RAM.DRIVE.NUM ; we use "-1" as a flag to the 1920 ; BASIC program...it MUST be 1930 ; replaced with a number from 2 to 8 1940 ; 1950 *= DPATCH2 1960 .BYTE RAM.DRIVE.NUM ; ditto 1970 ; 1980 *= DRV.MEMDUP 1990 .BYTE '1 ; forces MEM.SAV and DUP.SYS 2000 ; to reside on physical drive 1 2010 ; 2020 ; 2030 ; 2040 ; 2050 ; Patch to RAMIO: 2060 ; 2070 ; At the beginning of RAMIO, DOS 2.5 validates 2080 ; the sector number to be sure it gets a valid 2090 ; bank number 2100 ; 2110 ; If the bank number is bad, the Y-register 2120 ; is given an error code indicating the 2130 ; "disk" returned a "NAK" code. 2140 ; 2150 ; We patch in where the bank number is being 2160 ; checked...it used to be checked via 2170 ; a "CMP #4" but now we have a smaller "DISK". 2180 ; 2190 *= RAMIO.PATCH 2200 CMP #3 ; sector must be in banks 0,1,2 2210 BCC SECOK ; it is...assume it is okay 2220 PLP ; needed to clean up stack 2230 LDY #E.NAK ; too bad...give error 2240 RTS ; used to be "BNE" to a RTS...dumb! 2250 ; 2260 SECOK 2270 JSR RAMSYNC ; synchronize and select bank 2280 LDA ZTEMP1 ; get sector # times 2 2290 LSR A ; now sector # 2300 LSR A ; now sector # divided by 2 2310 ORA #$C0 ; ensure address is in range ($C000-$FFFF) 2320 ; 2330 ; rest of code is okay! 2340 ; 2350 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2360 ; 2370 ; Patch to SETBANK: 2380 ; 2390 ; The entire routine is replaced 2400 ; 2410 ; ENTER: A-register = 0,1,2,3,4 2420 ; If 4, then Main Memory is needed (ROMs) 2430 ; Else, RAM is needed. 2440 ; 2450 *= SETBANK 2460 ROR A ; If A-register was 4 on entry... 2470 ROR A ; ...then these 3 ROR's... 2480 ROR A ; ...will set the carry bi5z}2490 PHP ; so save the carry for a nonce 2500 LDA PIABPORT ; and get current bank select info 2510 LSR A ; strip it of its LSBit 2520 PLP ; recover the carry... 2530 ROL A ; ...and carry becomes ROM select!!! 2540 STA PIABPORT ; changes RAM to ROM or v.v. 2550 RTS ; saved a byte, actually! 2560 ; 2570 .PAGE ". The FORMAT fixer-upper" 2580 ; 2590 ; Up until now, we have just patched DOS 2.5. 2600 ; 2610 ; Now, we must do several steps: 2620 ; 2630 ; 1. Reinitialize DOS 2640 ; 2. FORMAT the RamDisk 2650 ; 3. Alter the VTOC 2660 ; 2670 ; Step 3 is necessary because DOS 2.5's 2680 ; FORMAT routine assumes (A) that a disk 2690 ; is large enough that the VTOC and 2700 ; DIRECTORY can occupy sectors $168 to 2710 ; $170 and (B) that (except for the boot 2720 ; sectors and the VTOC and DIRECTORY) 2730 ; available sector are continuous from 2740 ; 1 to the max sector number. 2750 ; We set bits to zero in the VTOC to 2760 ; inform DOS 2.5 that the corresponding 2770 ; sectors are not really there! 2780 ; 2790 *= $8000 ; my favorite place 2800 ; 2810 ; begin the actual code: 2820 ; 2830 DOPATCH 2840 LDA DRIVE.MASK ; to active drives... 2850 ORA #$80 ; ...include this drive 2860 STA DRIVE.MASK ; and update the mask 2870 ; 2880 JSR INITDOS ; because the load process 2890 ; changed several things, possibly 2900 ; including the drive table, etc. 2910 ; 2920 ; now set up for the XIO for format 2930 ; 2940 LDX #$70 ; we will use channel 7 for this 2950 LDA #XIO.FMT ; the format command 2960 STA IOCB.CMD,X ; is first item on agenda! 2970 LDA #DRV.NAME&$FF ; LSB of address of drive name 2980 STA IOCB.BUF,X ; to IOCB 2990 LDA #DRV.NAME/$0100 ; then MSB 3000 STA IOCB.BUF+1,X ; also to IOCB 3010 LDA #0 3020 STA IOCB.AUX1,X ; probably unnecessary... 3030 STA IOCB.AUX2,X ; but best to simulate BASIC call 3040 JSR CIOV ; call CIO to FORMAT the disk 3050 BMI OOPS ; but we can't handle an error! (do nothing) 3060 ; 3070 ; okay...time to patch the VTOC 3080 ; 3090 LDY #SIZE.RVTOC 3100 LOOP 3110 LDA NEW.RVTOC,Y ; get a byte of modified VTOC 3120 STA (VTOCPTR),Y ; and put it into system VTOC 3130 DEY ; more to do? 3140 BPL LOOP ; yep 3150 ; 3160 JSR WRTVTOC ; so write out the modified VTOC 3170 OOPS 3180 RTS ; and we are done! 3190 ; 3200 ; A string to hold drive name for XIO command 3210 ; 3220 DRV.NAME 3230 .BYTE "D" ; We want "D2:" through "D8:" 3240 .BYTE '0+RAM.DRIVE.NUM ; flag for BASIC DATA stmts 3250 .BYTE ":" ; end of string... 3260 .BYTE 0 ; except for this 3270 ; 3280 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3290 ; 3300 .PAGE ". New VTOC layout for 14KB RamDisk" 3310 *= $8100 ; (no reason...just to look pretty) 3320 ; 3330 ; Following are 74 bytes which define the appearance 3340 ; of the VTOC for our 14KB RamDisk 3350 ; 3360 ; Some sneakies to observe: 3370 ; even though we only use sector numbers 3380 ; from $01 to $7F, we mark $68 through 3390 ; $6B as being in use...this is because 3400 ; our bank select routine maps sectos 3410 ; $168 through $16B to the same memory 3420 ; locations as those containing $68-$6B. 3430 ; $168 is the VTOC, as is standard with 3440 ; all DOS 2 versions, and $169 to $16B 3450 ; are the directory. Note that $169 to 3460 ; $170 are normally used for directory, 3470 ; but we have opted for a shortened directory 3480 ; in order to give more file space... 3490 ; our directory still allows 24 files... 3500 ; surely more than enough for what is now 3510 ; a 13KB RamDisk. 3520 ; 3530 NEW.RVTOC 3540 .BYTE 2 ; DOS "2" family 3550 .WORD 128-16-1-3-3 ; 128 sectors in 16KBytes, 3560 ; less 16 sectors for 2KB I/O "hole" 3570 ; less 1 sector for VTOC 3580 ; less 3 sectors for shortened directory 3590 ; less 3 sectors for BOOT (useless but needed) 3600 ; (all this to find max # of sectors on disk) 3610 .WORD 128-16-1-3-3 ; ditto...but this is "available" sectors 3620 ; 3630 .BYTE 0,0,0,0,0 ; 5 dummy bytes 3640 .BYTE $0F ; sectors 0,1,2,3 in use 3650 ; 4-7 available 3660 .BYTE $FF,$FF,$FF ; sectors 8-$1f available 3670 ; which uses memory: $C000 to $CFFF 3680 .BYTE 0,0 ; sectors $20-$2F 3690 ; were $D000 to $D7FF, but that 3700 ; is I/O area!! 3710 .BYTE $FF,$FF ; sectors $30-$3f 3720 ; memory $D800 to $DFFF 3730 .BYTE $FF,$FF,$FF,$FF ; sectors $40-$5F 3740 ; memory $E000 to $EFFF 3750 .BYTE $FF ; sectors $60-$67 3760 .BYTE $0F ; sectors $68-$6B marked as in use 3770 ; because $168 to $16F are mapped to this 3780 ; same bank, and we have chosen to allow 3790 ; up to 24 files in the RamDisk 3800 ; so we need 4 "holes" for the 3810 ; VTOC and 3 directory sectors 3820 .BYTE $FF,$FF ; sectors $70-$7F 3830 ; sectors $60-$7F = memory $F000-$FFFF 3840 ; 3850 .BYTE $80 ; sector $80 is same as sector $00... 3860 ; ...at memory location $C000.. 3870 ; ...but sector $00 is not used, so we 3880 ; ...CAN use sector $80!! 3890 ; 3900 .BYTE 0,0,0,0,0,0,0 3910 .BYTE 0,0,0,0,0,0,0,0 ; to sector $FF 3920 .BYTE 0,0,0,0,0,0,0,0 3930 .BYTE 0,0,0,0,0,0,0,0 ; to sector $17F 3940 .BYTE 0,0,0,0,0,0,0,0 3950 .BYTE 0,0,0,0,0,0,0,0 ; to sector $1FF ... 3960 ; end of normal RamDisk 3970 ; 3980 SIZE.RVTOC = *-NEW.RVTOC 3990 .PAGE ". Initialization Vector and Symbol Table" 4000 ; 4010 *= $02E0 ; so DOS knows where this thing runs from 4020 .WORD DOPATCH ; doit toit 4030 ; 4040 .TITLE "DOS 2.5 Patch for 14K Byte RamDisk" 4050 .END DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD