1000 * RECDUP.M65 1010 .PAGE "MINIDUP -- o.s. and DUP equates" 1020 * 1030 * RECONSTRUCTION OF RESIDENT DUP (MINIDUP) FOR DOS 2.5 1040 * 1050 * althrough minidup is part of the Disk Utility Programs, 1060 * it is included with the FMS in the DOS.SYS file 1070 * 1080 .LOCAL 1090 * o.s. equates for DUP, not used by DOS 1100 WARMST = $08 warmstart flag 1110 DOSVEC = $0A start vector for DUP 1120 DOSINI = $0C DOS init vector 1130 CHKSNT = $3B checksum sent flag 1140 STAK0 = $0100 hardware stack 1150 VSEROR = $020C serial i/o transmit ready interrupt vector 1160 CARTSA = $BFFA (left) cartridge start address 1170 CIOV = $E456 central input/output entry 1180 CIOINV = $E46E CIO utility initialization 1190 WARMSV = $E474 warm start vector 1200 * equates from the DUP.SYS source 1210 RAMLO = $1A zero page variable (called DSKUTL by the o.s.) 1220 RUNAD = $02E0 run address 1230 INITAD = $02E2 initialization address 1240 JDOSOS = $2075 disk operating system monitor entry point 1250 CIO1 = $31A5 call CIO and go to DOS menu if break key abort 1260 NMDUP = $3305 end of non-resident portion of DUP 1270 .PAGE "RAMDISK INIT" 1280 * 1290 * initialization of ramdisk (called from DUPINIT) 1300 * 1310 D8INIT ASL DRVBYT shift bit 7 away 1320 LSR DRVBYT to indicate no drive 8 1330 LDA #'1 indicate DUP file on drive 1 1340 STA DDSKNO 1350 LDA # RDTXT 1370 JSR DUP1 1380 LDA # AF 1400 JMP DUP1 and rtn 1410 RDTXT .BYTE "D:RAMDISK.COM",EOL 1420 * 1430 * check for 2.5 DUP 1440 * 1450 CHKD25 LDA #$4C is it 2.5? 1460 CMP JDOSOS 1470 BNE :DOCHK no, br 1480 JMP CIO1 o.k., call CIO and go to DOS menu if break key abort 1490 :DOCHK LDA #0 set no DUP in memory 1500 STA DUPFLG 1510 LDA # NDTXT 1530 JSR ERR2 1540 JMP :DOCHK loop until return is pressed 1550 * 1560 * patch for o.s. Rev.1 serial output interrupt service routine 1570 * only installed if Rev.1 o.s. is active 1580 * 1590 ISRODN LDA CHKSNT test checksum sent 1600 BNE :SENT br if sent 1610 JMP $EA90 to o.s. ISRODN entry point 1620 :SENT TYA stack Y register 1630 PHA 1640 JMP $EAB3 to o.s. CHKDON entry point 1650 * 1660 .BYTE $B3,$EA,0,0,0,0,0 fossil filler bytes 1670 * 1680 * go read VTOC 1690 * 1700 XRDVT TSX save stack level 1710 STX ENTSTK 1720 JSR RDVTOC do VTOC read 1730 LDY #1 set o.k. status 1740 RTS 1750 * 1760 * go write VTOC 1770 * 1780 XWTVT TSX save stack level 1790 STX ENTSTK 1800 JSR WRTVTOC do VTOC write 1810 LDY #1 set o.k. status 1820 RTS 1830 .PAGE "MINIDUP -- init code for DUP" 1840 DDSKNO .BYTE '8 drive number of DUP.SYS file 1850 * 1860 * initialization code for DUP - calls FMS init code 1870 * called on warm start and cold start 1880 * 1890 DUPINIT LDA #0 reset option 1900 STA OPT 1910 LDA # MNDUP 1940 STA DOSVEC+1 1950 LDA $EA9C test for o.s. version (Rev.2 $A5, XL $85) 1960 CMP #$90 1970 BNE XINIT if not rev.1 skip SIO patch 1980 LDA # ISRODN 2010 STA VSEROR+1 2020 XINIT JSR DINIT FMS initialization 2030 NOP 2040 NOP 2050 NOP 2060 LDA WARMST test for coldstart 2070 BNE CKMDOS br if warm 2080 JSR D8INIT load and run RAMDISK.COM and AUTORUN.SYS files 2090 RTS return control to o.s. 2100 * run disk file (RAMDISK/AUTORUN), pointed to by A/X -- called from D8INIT 2110 DUP1 STA ICBAL+16 store low byte filename 2120 STX ICBAH+16 hi byte 2130 JSR INITX clear DUPFLG show DUP not in memory 2140 LDA #$C0 2150 JSR STLOAD load, init and run the file 2160 JMP CLOSX make sure iocb #1 is closed & return 2170 * warmstart 2180 CKMDOS LDA DUPFLG see if DUP was in memory 2190 BEQ INITX if zero then wasn't 2200 LDA MEMFLG see if user area written to MEM.SAV 2210 BEQ CLDSET if zero then wasn't 2220 JSR LDMEM1 else get user memory back in 2230 JSR RELDIN reload saved DOSINI vector 2240 JSR INITX clear DUP in memory flag 2250 JSR WARMSV redo warm start 2260 INITX LDA #0 say DUP not in memory 2270 STA DUPFLG clear flag 2280 RTS 2290 * 2300 CLDSET STA WARMST no valid user memory 2310 BEQ INITX set to cold start 2320 .PAGE "MINIDUP -- loader routine" 2330 * 2340 * loads from the file (must be load format) into memory 2350 * returns: X=0 load o.k. 2360 * X=1 open errors Y=CIO code 2370 * X=2 read errors Y=CIO code 2380 * X=3 bad load file 2390 * on entry, IOCB 1 points to filename 2400 * 2410 DUPFLG .BYTE 0 flag - if DUP in memory not zero 2420 OPT .BYTE 0 holds value of option given by user 2430 LOADFLG .BYTE 0 flag = $80 if memory file doesn't have to be loaded 2440 HDBUF .WORD 0,0 temp for start/end address 2450 * open file 2460 SFLOAD LDA #$80 2470 STLOAD STA LOADFLG 2480 LOAD LDA # LRTS 2510 STA RUNAD+1 make run at eof default to LRTS 2520 LDX #$10 iocb #1 2530 LDA #3 open 2540 STA ICCOM,X 2550 LDA #4 open type=input 2560 STA ICAUX1,X 2570 JSR GOCIO try to open file 2580 BPL RDLF cont if o.k. 2590 LDA #1 open errors 2600 BNE CLFX close and exit 2610 * read two header bytes 2620 RDLF LDX #$10 iocb #1 2630 LDA # DBUF 2660 STA ICBAH,X 2670 LDA #2 2680 STA ICBLL,X 2690 LDA #0 2700 STA ICBLH,X 2710 STA MEMLDD clear MEM.SAV loaded flag 2720 LDA #7 get char 2730 STA ICCOM,X 2740 JSR CIOV 2750 BMI ERST if errs 2760 LDA #$FF 2770 CMP DBUF check for valid load file 2780 BNE LNLF 2790 CMP DBUF+1 2800 BNE LNLF branch if not a load file 2810 * get section of load file 2820 * read start/end address to HDBUF 2830 RDDRC LDX #$10 2840 LDA # HDBUF 2870 STA ICBAH,X 2880 LDA #4 2890 RDDRC1 STA ICBLL,X 2900 LDA #0 2910 STA ICBLH,X 2920 JSR CIOV no error check so can catch eof 2930 BPL STOK if no error 2940 CPY #$88 see if eof 2950 BNE ERST if some error status 2960 * eof so done, exit 2970 JSR CLOSX close iocb's 1 and 2 2980 BIT OPT 2990 BMI DRUN branch if no run option 3000 JSR JMPRUN jump through run vector 3010 DRUN LDA #0 o.k. status 3020 BIT LOADFLG was memory swapped? 3030 STA LOADFLG reset flag 3040 BMI CLFX branch if memory wasn't swapped 3050 JSR MEMSVG does memory save file exist? 3060 BMI DRUN1 branch if not 3070 PLA 3080 PLA 3090 JMP GOOD write memory and reload DUP 3100 * 3110 * See if DUP written over. If is reload & tell 3120 * user need MEM.SAV to load this file. 3130 * 3140 DRUN1 LDA DUPFLG see if DUP globbered 3150 BNE DRUN2 no, then return 3160 LDA # NMSF 3180 JSR PRNTMSG print msg 3190 JMP RRDUP reload & run DUP 3200 * return to calling routine 3210 DRUN2 LDA #0 no DUP err msg on eof 3220 CLFX TAX 3230 LRTS RTS 3240 * error returns 3250 LNLF JSR CLOSX 3260 LDA #3 bad load file 3270 BNE CLFX (always) 3280 ERST TYA 3290 PHA 3300 JSR CLOSX 3310 PLA 3320 TAY 3330 BNE CLFX (always) 3340 * continue with load - check load address for header 3350 * if have concatenated load files 3360 STOK LDX #$10 3370 LDA HDBUF move params to iocb 3380 STA ICBAL,X 3390 PHA 3400 LDA HDBUF+1 3410 STA ICBAH,X 3420 TAY 3430 PLA 3440 INY was address FF? 3450 BNE ADOK branch if not 3460 TAY 3470 INY other byte FF? 3480 BNE ADOK branch if not 3490 * have a header & start address - get end address for text & do again 3500 LDA HDBUF+2 3510 STA HDBUF 3520 LDA HDBUF+3 3530 STA HDBUF+1 move load address 3540 LDA # HDBUF+2 3570 STA ICBAH,X so load address doesn't get wiped out 3580 LDA #2 3590 JMP RDDRC1 read end address 3600 * get length of text, then determine if in DUP 3610 ADOK LDA HDBUF+2 3620 SEC 3630 SBC HDBUF 3640 STA ICBLL,X 3650 LDA HDBUF+3 3660 SBC HDBUF+1 3670 STA ICBLH,X 3680 LDA HDBUF+1 is beginning address within DUP? 3690 CMP # >[NMDUP+1] 3700 NOP 3710 BCS ANWD branch if hi byte outside DUP addr space 3720 LDA HDBUF+3 is ending address within DUP? 3730 CMP # >NDOS end of system buffers and minidup 3740 NOP 3750 BCS AWD br if less, since in DUP, load MEM.SAV is neccesary 3760 * outside DUP, load MEM.SAV not neccesary 3770 ANWD LDA MEMLDD 3780 BMI AWD branch if MEM.SAV already loaded 3790 LDA #$80 3800 ORA LOADFLG 3810 STA LOADFLG set MEM.SAV doesn't have to be loaded flag 3820 * adjust length & load 3830 AWD INC ICBLL,X 3840 BNE :AWD1 3850 INC ICBLH,X 3860 :AWD1 BIT LOADFLG does memory have to be loaded 3870 BMI DLM branch if not 3880 LDA MEMLDD was MEM.SAV already loaded? 3890 BMI DLM branch if so 3900 DEC MEMLDD 3910 JSR LDMEM load MEM.SAV file (if it exists) 3920 LDA #0 show user area not DUP in memory 3930 STA DUPFLG 3940 JSR RELDIN restore DOS init vector from saved location 3950 * set no init addr default then read in text & attempt init 3960 DLM LDX #$10 3970 LDA # LRTS 4000 STA INITAD+1 init defaults to a rts 4010 JSR CIOV read data directly to memory 4020 BPL DLM1 4030 JMP ERST if errors 4040 DLM1 BIT OPT 4050 BMI DIN branch if no go option 4060 JSR JMPINT do init 4070 DIN JMP RDDRC get next section of load file 4080 * the following code is a fossil 4090 * it used to determine if an address is within DUP space 4100 CMP # >NDOS 4110 BCC :AWDQR branch if hi byte lt DUP start 4120 CMP # >[NMDUP+1] 4130 :USRDOS ROL A label mentioned in 'Mapping' 4140 EOR #1 4150 LSR A complement carry 4160 :AWDQR RTS 4170 * 4180 JMPINT JMP (INITAD) 4190 JMPRUN JMP (RUNAD) 4200 * 4210 MEMLDD .BYTE 0 MEM.SAV already loaded flag 4220 AF .BYTE "D1:AUTORUN.SYS",EOL 4230 NMSF .BYTE "NEED MEM.SAV TO LOAD THIS FILE.",EOL 4240 .PAGE "MINIDUP -- create MEM.SAV file" 4250 * 4260 * routine written by M.E., april 21, 1980 4270 * this routine creates a file on disk of data from memory 4280 * create file called 'Dn:MEM.SAV', set Y=1 4290 * able to create file then set reg. Y=error returned from CIO 4300 * the ram to be occupied by DUP is stored by this routine into MEM.SAV 4310 .LOCAL 4320 MSTXT .BYTE "D8:MEM.SAV",EOL 4330 * 4340 MWRITE JSR CLOSX close iocb's and open #2 to write 4350 LDA #8 4360 STA ICAUX1,X 4370 JSR OREST 4380 BMI ERRWR if error then jmp and ret 4390 * write memory block 4400 LDA #11 put char 4410 STA ICCOM,X 4420 LDA # NDOS start addr (high) 4450 STA ICBAH,X 4460 LDA # LEN length (high) 4490 STA ICBLH,X 4500 JSR CIOV write data block 4510 BMI ERRWR if write error then jmp 4520 JSR CLOSX 4530 BMI ERRWR 4540 LDY #0 4550 RTS 4560 * routine to complete open of 'Dn:MEM.SAV' -- calling 4570 * sub supplies 'read' or 'write' in ICAX1 4580 OREST LDA #3 open 4590 STA ICCOM,X 4600 LDA # MSTXT 4630 STA ICBAH,X 4640 JMP GOCIO 4650 * 4660 ERRWR RTS error rtn 4670 * to CIO after storing DUP drive 4680 GOCIO LDA DDSKNO get drive # of DUP.SYS file 4690 STA MSTXT+1 set at Dn:MEM.SAV filename 4700 STA DUPSYS+1 set at Dn:DUP.SYS filename 4710 JMP CIOV call CIO and rtn 4720 * 4730 .BYTE $17,$A0,$90,$60 fossil filler bytes 4740 .PAGE "MINIDUP -- entry point on 'DOS' call" 4750 INISAV .WORD 0 DOSINI vector save loc 4760 MEMFLG .BYTE 0 set to FF for memory written to MEM.SAV, else zero 4770 * 4780 MNDUP LDX #0 4790 STX MEMFLG memory not saved 4800 STX LOADFLG memory should be saved 4810 DEX 4820 STX WARMST assume no cold start needed 4830 JSR INITIO close iocb's and reopen E: 4840 JSR MEMSVG find out if file Dn:MEM.SAV exists 4850 BPL GOOD branch if so 4860 LDA #0 4870 STA WARMST clear warm start flag 4880 BEQ FINAL (always) 4890 * write memory file 4900 GOOD JSR MWRITE write user area to MEM.SAV 4910 BMI PERROR 4920 DEC MEMFLG show memory written 4930 BMI FINAL (always) 4940 * MEM.SAV failed, print error message 4950 PERROR LDA # ERRMES 4970 JSR PRNTMSG goto msg printer 4980 LDA # ERR 5000 ERR2 JSR PRNTMSG 5010 * wait for Y to run DOS 5020 LDA #5 get record 5030 STA ICCOM 5040 LDA # STAK0 5070 STA ICBAH 5080 LDA #2 5090 STA ICBLL 5100 LDA #0 5110 STA ICBLH 5120 JSR CIOV 5130 LDA STAK0 see if Y typed 5140 CMP #'Y 5150 BNE RTCART branch if not 5160 LDA #0 5170 STA WARMST 5180 * 5190 FINAL LDX #$20 close MEM.SAV file 5200 LDA #12 5210 STA ICCOM,X 5220 JSR CIOV 5230 * 5240 RRDUP LDA DOSINI save DOS init vector 5250 STA INISAV 5260 LDA DOSINI+1 5270 STA INISAV+1 5280 LDA # DUPINIT 5310 STA DOSINI+1 5320 RRDUP1 LDA # DUPSYS 5360 STA ICBAH,X 5370 LDY #0 5380 STY OPT assure no /N option in effect 5390 DEY show that DUP is in memory 5400 STY DUPFLG 5410 JSR SFLOAD load DUP.SYS and run it 5420 RTCART RTS 5430 * 5440 EC .BYTE "E:",EOL 5450 DUPSYS .BYTE "D8:DUP.SYS",EOL 5460 ERRMES .BYTE "ERROR-SAVING USER MEMORY ON DISK",EOL 5470 ERR .BYTE "TYPE Y TO STILL RUN DOS",EOL 5480 .PAGE "MINIDUP -- subroutines" 5490 * routine tests if MEM.SAV is present on the disk 5500 * returns - minus if not there 5510 * plus if MEM.SAV is there 5520 * 5530 MEMSVG JSR CLOS20 close iocb #2 5540 LDA #3 open 5550 STA ICCOM,X 5560 LDA # MSTXT 5590 STA ICBAH,X 5600 LDA #12 read/write 5610 STA ICAUX1,X try to open Dn:MEM.SAV for read/write 5620 JSR GOCIO 5630 PHP save status 5640 JSR CLOS20 close MEM.SAV 5650 PLP restore status 5660 RTS 5670 * 5680 * save file subroutine - write file body, init, & run vectors 5690 * 5700 WDR1 LDA #0 this immediate value modified 5710 BEQ WDR2 br if mem file doesn't have to be loaded 5720 JSR LDMEM reload saved memory 5730 WDR2 LDX #$10 5740 JSR CIOV do save - write body to disk 5750 INITQ LDA #0 this immed value changed during save 5760 BEQ RUNQ set to FF when an init vector is present 5770 INC INITQ+1 5780 LDA INITAD 5790 STA VECTR if init vector for file save it 5800 LDA INITAD+1 5810 STA VECTR+1 5820 LDA # INITAD 5860 JSR WRVEC 5870 RUNQ LDA #0 this immediate value modified 5880 BEQ NORNAD set to FF when a run vector is present 5890 INC RUNQ+1 5900 LDA RUNAD 5910 STA VECTR if run vector for file save it 5920 LDA RUNAD+1 5930 STA VECTR+1 5940 LDA # RUNAD 5980 JSR WRVEC 5990 NORNAD JSR CLOSX close iocb's 1&2 6000 LDA MEMFLG 6010 AND WDR1+1 6020 BEQ DRRDUP 6030 INC WDR1+1 reset mem needs to be loaded flag 6040 JMP RRDUP1 reload & run DUP 6050 DRRDUP JMP JDOSOS run the swapped in DUP 6060 * 6070 WRVEC STA LDST+1 6080 INX 6090 STX LDND 6100 STA LDND+1 6110 LDX #$10 6120 LDA # LDST 6150 STA ICBAH,X 6160 LDA #6 6170 STA ICBLL,X 6180 LDA #0 6190 STA ICBLH,X 6200 JMP CIOV write init or run address 6210 * 6220 * jump to cartridge 6230 * 6240 CLMJMP JSR LDMEM 6250 LDA #0 show DUP no longer in memory 6260 STA DUPFLG 6270 JSR RELDIN restore DOS init vector saved 6280 JMP (CARTSA) jump to cartridge 6290 * 6300 * load MEM.SAV (if it exists) before run at address 6310 * 6320 LMTR JSR LDMEM load MEM.SAV if it exists 6330 LDA #0 show that DUP no longer in memory 6340 STA DUPFLG 6350 JSR RELDIN restore DOS init vector saved 6360 JMP (RAMLO) run at address 6370 * 6380 * restore DOSINI vector from saved location 6390 * 6400 RELDIN LDA INISAV 6410 STA DOSINI 6420 LDA INISAV+1 6430 STA DOSINI+1 6440 RTS 6450 * 6460 * subroutine LDMEM - load MEM.SAV if it exists 6470 * 6480 LDMEM LDA MEMFLG 6490 BNE LDMEM1 branch if memory was saved 6500 RTS 6510 LDMEM1 JSR MEMSVG 6520 BPL LDMEM2 branch if MEM.SAV file does exist 6530 LDA #0 tell cart pgm area clobbered 6540 STA WARMST 6550 BEQ CLOS2 go close and goto cart 6560 * 6570 LDMEM2 LDA #3 open 6580 STA ICCOM,X 6590 JSR GOCIO reopen MEM.SAV 6600 LDA #7 get char 6610 STA ICCOM,X 6620 LDA #[ LEN 6650 STA ICBLH,X 6660 LDA # NDOS 6690 STA ICBAH,X 6700 JSR CIOV 6710 CLOS2 LDA #12 close 6720 STA ICCOM,X 6730 JMP CIOV close MEM.SAV 6740 * 6750 * close all iocbs & re-open zero as screen editor 6760 * 6770 INITIO JSR CIOINV this routine closes all iocbs 6780 LDX #0 then reopens the screen editor 6790 LDA #3 open 6800 STA ICCOM,X 6810 LDA # EC 6840 STA ICBAH,X 6850 LDA #12 read/write 6860 STA ICAUX1,X 6870 JMP CIOV call CIO and rtn 6880 * 6890 * CLOSX - close iocbs 1 & 2 6900 * 6910 CLOSX LDA #12 close 6920 LDX #$10 6930 STA ICCOM,X 6940 JSR CIOV 6950 * entry point to close iocb #2 only 6960 CLOS20 LDX #$20 6970 LDA #12 close 6980 STA ICCOM,X 6990 XCIO JMP CIOV also used by PRNTMSG subroutine 7000 * 7010 * subroutine PRNTMSG 7020 * puts a character string terminated by a 7030 * carriage return char to screen editor 7040 * entry - lo/hi byte msg address in A/X 7050 * put params in iocb - use iocb 0 for screen editor 7060 * 7070 PRNTMSG STA ICBAL set msg addr in iocb buff addr 7080 STX ICBAH 7090 * set up rest of iocb 7100 LDX #1 set in buffer length 7110 STX ICBLH assume 256 bytes max, or some more 7120 DEX use reg X to set in iocb index for CIO 7130 LDA #9 put msg 7140 STA ICCOM 7150 NOP 7160 NOP 7170 * test if DUP is resident - if is then use indirect CIO routine 7180 * to test break key abort 7190 LDA DUPFLG if zero non-resident DUP not in memory 7200 BEQ XCIO go direct to CIO & return 7210 JMP CHKD25 in memory, so use it, but be sure it's 2.5 version 7220 * 7230 * file header 7240 * 7250 SAVH .BYTE $FF,$FF 7260 LDST .WORD 0 load address 7270 LDND .WORD 0 end address 7280 VECTR .WORD 0 run/init vector 7290 * 7300 .BYTE $95,$20,$16 fossil filler bytes 7310 * 7320 ENDFMS ; end of FMS 7330 * Used by 144 byte drive buffers & 128 byte sector buffers. 7340 * Each active drive and each simultaneously open file needs 7350 * a buffer. Without loading the DOS menu, there will be 7360 * enough space. Using the menu limits the buffer space to 7370 * the $3B0 bytes gap between ENDFMS and NDOS. 7380 * With 1 drive, 6 open files are possible without affecting 7390 * the DOS menu. 7400 * 2 drives allow 5 open files 7410 * 3 drives allow 4 open files 7420 * 4 drives allow 2 open files 7430 * (a ramdisk needs a drive buffer as any other drive) 7440 *= *+$03B0 7450 NDOS ; end of system buffers and minidup (DUP file equate) 7460 *= *+120 parameter area & type in line buffer for DUP 7470 DBUF ; data buffer for copy 7480 * length of non-resident portion of DUP 7490 LEN = NMDUP-NDOS