-ML   X c0C)HCCH Mhhݩh `eCDiCD`  RyHPX;SAVE #D9:FMSEQU.M656AFMS - Dual Density for Atari 1050 drives (2.50)A/A --- Copyright and Author Notice --AX;X;,X; Copyright (c) 1978,1979,1980,1982,1984$.X; Optimized Systems Software, Incorporated.X; San Jose, Califoria8X;B)X; THIS PROGRAM MAY NOT BE REPRODUCED,L&X; STORED IN A RETRIEVAL SYSTEM, ORV&X; TRANSMITTED IN WHOLE OR IN PART,)X; IN ANY FORM, OR BY ANY MEANS, BE ITj*X; ELECTRONIC,MECHANICAL, PHOTOCOPYING,t)X; RECORDING, OR OTHERWISE WITHOUT THE~!X; PRIOR WRITTEN PERMISSION OF+X; OPTIMIZED SYSTEMS SOFTWARE, INC.!X; 1221-B KENTWOOD AVENUE.X; SAN JOE, CALIFORNIA 95129 (U.S.A.)X;!X; PHONE: (408) 446-3099X;X;(X;***********************************X;&; Originally designed and coded by7X; Paul Laughton of Shepardson Microsystems, Inc.X;*X; Modified for Atari 1050 nd 130XE by #X; Mark Rose & Bill WilkinsonX; of O.S.S., Inc.X;(X; January, 19852X;<X;F(X;**********************************PX;ZA System EquatesAd(X;***********************************nX;xX;+X; === Universl Atari OS Equates ===X;BOSBTM5 ;; OS ROMs always call FMS from $E000-$FFFF ???(FMSORG;; normal boot-inlocation, FMSZPGC;; seven bytes reserved for FMSX;+IOCBORG@;; 8 IOCB's of 16 bytes each)ZICB ;; current IOB is copied hereLMASK;;LINK MASKX;&DCBORG;; command block for SIO"SIOVY;; vector for SIO callX;,DHADRS;; vec tor for resident disk I/O0DHSTAT;; where DHADR returns disk status4DSKTIMF;; format disk time ou (DHADR result)"X;,1PIABPORT;; data port, memory select, etc.6'EOL;; ATASCII "Return" character@7LMADR;; ointer to bottom o f application memoryJ)DEVTAB;; device name & addr tableTX;^!CRITICB;; critical I/O flagh2NMIN;; NMI disable/enable (1-bit enables)r,CLOCKLSB;; lowest byte of jiffy clock|X;X;6X; === Equates Preserved y FMS in all versions ===!SECVTOCh;; where regular V.EVSECNUM;; becuz DOS only uses to 1023X;+DUPINIT@; initial addr for mini-DUP-STAK;;stack offset of FMS caller addr,TIMOUT;; time out for normal disk I/OX;'; Size of VTOC in MFM mo de on 1050:X;5VTOCSIZE;; 10 (header)+128 (bit map)+6 (evtoc)X;$X; LENGTH OF SECTOR ANDNUMBER OFX; DATA BYTES:X;& DRVMDL}0 DRVLBT:X;DA IOCBAN IOCBORGXX;bX; IOCB - IO CONTROL BLOCK$X; THERE ARE 8 I/O CONTROL BLOCKSv!X; 1 IOCB IS REQUIRED FOR EACH#X; CURRENTLY OPEN DEVICE OR FILEX;IOCBICHI ;;DEVICE NUMBERICDNO ;;DEVICE HANDLERICCOM ;; I/O COMMANDICSTA ;;I/O STATUSICBAL  ICAH ;;BUFFER ADR (H,L) ICPUT ;;PUT CHAR DH ADDRICBLL  ICBLH ;;BUFFER LEN (H,L)ICAUX1 ;;AUX ICAUX2 ;;AUX 2 ICAUX3 ;;AUX 3ICAUX4 ;;AUX 4 ICAUX5 ;;AUX 5*ICAUX6 ;;AUX 64ICLEN ICB>X;H( ICLEN;;SPACE FOR 7 MORE IOCB'SRX;\X; ICCOM VALUE EQUATESfX;pICOIN;;OPEN INPUTzICOOUT;;OPE OUTPUTICIO;;OPEN UN/OUTICGBR;;GET BINARY RECORDICGTR;; GET TEXT RECORDICGBC;;GET BINARY CHARICGTC;;GET TEXT CHARICPBR;;GET BINARY RECORDICPTR ;;PUT TEXT RECORDICPBC ;;PUT BINARY CHARICPTC ;PUT TEXT CHAR ICCLOSE ;;CLOSE FILEICSTAT ;;GET STATUSICDDC;;DEVICE DEPENDENTICMAX;;MAX VALUE "IFREE;;IOCB FREE INDICATOR X; X; ICSTA VALUE EQUATES$ X;. $ICSOK;;STATUS GOOD, NO ERRORS8 ICSTR;;TRUNCAIATEDRECORDB ICSEOF;;END OF FILEL ICSBRK;;BREAK KEY ABORTV ICSDNR;;DEVICE NOT READY` "ICSNED;;NON EXISTENT DEVCEj ICSDER;;DATA ERRORt ICSIVC;;INVALID COMMAND~ #ICSNOP;;DEVICE/FILE NOT OPEN ICSIVN;;INVALID IOCB # ICSWPC;;WRITE PROTECT ICSNAK;; NAK from device X; X; ZERO PAGE IOCB LABELS X; ICDNOZICDNOIOCBZICB &ICBLLZICBLLIOCBZICB;;BUF LEN ICBLHZICBLHIOCBZICB 'ICBALZICBALIOCBZICB;;BUF ADDR ICBAHZICBAHIOCZICB ICCOMZICCOMIOCBZICB +ICPUTZICPUTIOCBZICB;;PUT RTN ADDR &ICAX1ZICAUX1IOCBZICB;; aux 1 A DCBA DCBORG( X;2 X; DCB - DATA CONTROL BLOCK< (X; THE DCB IS A CONTROL/COMMAND BLOCKF -X; USED TO INTERFACE TO SERIA I/O DEVICESP -X; SUCH AS THE DISK DRIVE(S) FROM RESIDENTZ X; HANDLERS SUCH AS FMS.d X;n DCBx DCBSBI ;;SERIAL BUS D DCBDRV ;;DISK DRIVE # DCBCMD ;;COMMAND DCBSTA ;;I/O STATUS &DCBBUF ;;I/O BUFFER ADDR (H,L) DBTO ;;TIME OUT CNT DCBCNT ;;I/O BYTE COUNT "DCBSEC ;;I/O SECTOR NUMBER X; X; DCBCMD VALUE EQUATES X;$DCBCRS R;;Read sector ($52) $DCBCWS W;;Write sector ($50) $DCBCST S;;Status request ($53) $DCBCFD !;;Forat Diskette ($21) *DCBCFMFM ";;Format MFM diskette ($22) X;" X; *** SPECIAL NOTE:, /X; DCBCWS may be changed o 'P ($50)6 -X; if desired to have disk DISABLE@ 2X; the verifying read after each write.J -X; Disk rite ('W) operations takeT ,X; longer, but are more reliable.^ .X; Put ('P) is much faster, though.h X;r X DCBSTA VALUE EQUATES| X; DCBSOK;;STATUS NORMAL DCBDNR;;DEVICE NOT READY #DCBCNR;;CONTROLLER NOT READY CBDER;;DATA ERROR DCBIVC;;INVALID COMMAND DCBWPR;;WRITE PROTECT DCBNAK;;NAK from device A ZERO AGEA X; (X; Device drivers in general--and FMS ,X; in particular--are allocated seven (7) #X; temporary bytes in zero pge. X; (X; A device can NOT assume that these 'X; bytes will survive intact between +X; CIO calls to the device driver!979 ;& FMSZPG0 X;: "ZBUFPICBALZ;; BUFFER POINTERD .ERPTR ;; HOLDS POINTER TO ERROR NUMBERN *VTOCPTR ;; poiner to current VTOCX 0ZSBA ;; pointer to current sector bufferb 4CURFCB ;; CURrent FCB number ($10,$20, etc.)l X;vX; other uses of ERPTR X; &ZTEMP1ERPTR;; just a 1 byte temp )ZTEMP2ERPTR;; just a 1 byte temp BUFPTRZSBA; a better name !ZDRVAVTOCPTR;; the old name X; "A Macros and Error CodesA X; )X; Macro for generating error eturns: X; @ERROR ERROR    X; X; X; ERROR CODES* X;4 (E.DBAD;;BAD SECTOR AT FORMAT TIME> -E.AO;;ATTEMPT APPEND TO OLD TYPE FILEH E.POT;;POINT INVALIDR E.FNF;;FILE NOT FOUND\ E.DFULL;;DIRECTORY FULLf E.DVDC;;DEVICE COMMAND INVALIDp E.FLOCK;;FILE LOCKEDz E.PDL;;POINT DATA LENGTH E.FN;;FILE NAME ERROR #.FNMM;;FILE NUMBER MISMATCH &E.SYS;;FATAL SYS DATA I/O ERROR E.NSA;;NO SECTOR AVAIL %E.NSB;;NO SECTOR BUFERS AVAIL E.DNO;;DRIVE NO ERROR E.EOF;; END OF FILE ERROR $E.NAK;; ??? simulated NAK ??? X; X; $X; thefollowing MACRO is used to (X; ensure entry point compatibility $X; with original Atari DOS 2.0sX; @ORG    $: AEntry point error! Can not be placed where needed!A.'SPACE  ;; GET PURPOSEFUL ERROR!8B-SPACE   ;; !! available space !!!L V`jX;t%X; macros to generate 1 and 2 byte~X; unconditional branches#X; (actually jst first bytes of&X; BIT zeropage and BIT absoluteX; @SKIP1  $!X; @SKIP2  ,X;   ;; !! available space !!!L V`jX;t%X; macros to generate 1 and 2 byte~X; unconditional branches#X; (actually jst first bytes of&X; BIT zeropage and BIT absoluteX; @SKIP1  $X;SAVE #D9:FMSBOOT.M65ABOOT RECORDA FMSORGX;$X; THE FOLLOWING BYTES ARE STORED$X; ON DISK SECTOR 0 THEY OMPRISE$X; THE BOOT LOAD RECORD.X;8BFLG ;;BOOT FLAG UNUSED=0B0BRCNT ;;NO CONSECTIVE BOOT RECORDS TO READL"BLD#DR FMSORG;;BOOT LOAD ADDRVBINTADR DUPINIT;;INIT ADDR`$BCONT!XBCONT;;BOOT READ CONT PTjX;t%X; THE FOLLOWING BYTES RE SET BY ~%X; THE CONSOLE PROCESSOR. THEY ARE&X; ACTED UPON DURING FMS INIT ONLY.&X; THEY ARE PART OF THE BOOT RECORDX;$ THUS DEFINING THE DEFAULTX;INITIALIZATION PARMSX;*SABYTE ;;MAX # CONCURRENT OPEN FILES3DRVBYT ;;one bit er drive...03 is two drives(SAFBFW ;;STORAGE ALLOCATION DIR SW/SASA ENDFMS;;STORAGE ALLOCATION START ADDRX;&X;THE FO%LLOWING CODE READS THE FMS&X; AND CONSOLE PROCESSOR (DOS) FROMX; THE DOS.SYS FILE X;DFSFLG ;;DOS FLAGX(X; 00 NO DOS FILE2X; 01 128 BYTE SECTOR DISK<'X; NOT USED! 02 256 BYTE SECTOR DISKFX;P.DFLINK =;;DOS FILE STAR SECTOR N&UMBERZ#BLDISP };;DISPL TO SECTOR LINKd.DFLADR DFMSDH;;ADDR START OF DOS.SYS FILEnX;x XBCONT%DFSFLG;;GT DOS FLAG!FBFAIL;;BR IF NO DOS.SYS FILEX;$ MOVESTART;;MOVE LOAD START ADDRX; QDFLINK;;GET 1ST SECTOR # DFLINK%X'BC1$ZBUFP;; MOVE ADDRESS TO DCB &DCBBUF $ZBUFP&DCBBUFX;, BSIO;;GO READ BOOT SECTOR BFAILX;"%BLDISP;;POINT TO LINK ,Q@ZBUFP7;;GET LINK HI6M>LMASK;;MASK TO LINK BITS@>;; AND SAVE LINK HIGHJ3TL@ZBUFP7^ FB(GOODhQ@ZBUFP7;;GET LINK LOWr5;; SAVE IT|3;; AND GET LENGTH OF SECTOR Q@ZBUFP7# INCZBUFP;;GO INCRMENT BUF ADR7;; GET LINK LOW AGAIN?X;A;;RESTORE LINK HI!XBC1;;GO READ NEXT SECTORX; BFAILQ>;;SET FORCARRY SET;AND )P,Y = $80X; BGOOD ;;SET FOR CARRY CLEART??:X;&&X; BUMP ZBUFP POINTER BY BYTE VALUE0X:'DINCBPQ>;; ENTRY POINT TO ADD 128D"INCZBUFP,;; AND A-REG TO ZBUFPN OZBUFPX PZBUFPb D:INCZ1l #ZBUFPv :INZ1:X;(X; MOVE ST*ART ADDRESS OF DOS.SYS FILEX; TO ZBUFP POINTERX;MOVESTARTQDFLADR PZBUFPQDFLADR PZBUFP:X;;; ENTRY POINT TO ADD 128D"INCZBUFP,;; AND A-REG TO ZBUFPN OZBUFPX PZBUFPb D:INCZ1l #ZBUFPv :INZ1:X;(X; MOVE STyX;SAVE #D9:FMSBSIO.M65ASECTOR I/OAX;X; BSIO - DO SECTOR I/OX; @ORG l$X;. BSIO 8X;BPDCBSEC;; SET SECTOR HIL'DCBSEC;;SECTOR LOVX;`&BSIORQ>DCBCRS;;ASSUME READ SECTORj%>@;;AND GET DATAtDDSIO1;;BR IF REA,~X;3WRITEMODE ;; LDY# can get either 'W' or 'P'$Q>DCBCWS;;ELSE LOAD WRITE SECTOR%>;;AND PUT DATAX; DSO1X; RAMDISK6;; save read/write flag$ICDNOZ;; drive number(>;; RAMDISK?H:REALDISKX;X; do RAMDIS se-ctor I/O! X;8;; recover flag% RAMIO;; real work done elsewhere(!DSIO5;; join up for return2X;<X; end of RA DISK I/OFX;P :REALDISKZ8;; just to clean up stackdX;nxX;PDCBCMD;;SET COMMAND$Q>TIMOUT;;TIMEOUT DEFAULT OADED.X; DSIO2PDCBTO;;SET TIME OUT'SIOCMD;;AND SIO CMDX;Q>1;;DISK SERIAL BUS IDPDCBSBI;;SET IDX;Q>;;SET RETRY COUNT PRETRYX;'Q>;; data length: always 128 bytesPDCBCNT;; (lower byte=128)T?;; (gets 0 toA reg)"/PDCBCNT;; (upper byte=0),X;6X;@ DSIO4J*QSIOCMD;; $40 or $80, as saved earlierTPDCBSTA;; needed by SI^ SIOV;;CALL SERIAL I/Oh IDSIO5;;IF GOOD I/O THEN RTSrX;|"RETRY;;Test: retry again?IDSIO4;; yes...loopX;;%DSIO5$0CURFCB;;RELOAD CURRENT FCB#C;; Y-reg has DCBSTA--SIO Status:X;0, as saved earlierTPDCBSTA;; needed by SI^ SIOV;;CALL SERIAL I/Oh IDSIO5;;IF GOOD I/O THEN RTSrX;|"RETRY;;Test: retry again?IDSIO4;; yes...loopX;;%DSIO5$F X;SAVE #D9:FMSINIT.M65AFILE MANGER ENTRY POINTAX;(X; DFMSDH - DISK FILE MANAGEMENT DISKX; HANDLER ENTRY POITX;$ @ORG .X;8 DFMSDHB DFMOPN;;OPEN FILEL DFMCLS;;CLOSE FILEV DFMGET;;GET FILE` DFMPUT; 2PUT BYTEj DFMSTA;;STATUSt$ DFMDDC;;DEVICE DEPENDENT CMD~X;,X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X;0X This table of single bit values is used by.X; GETSECTOR and FRESECt, the allocation/X; deallocation routines.X;GX 3; This is a crazy place to put it, but we had the bytes spare here.X; BITTBL =@= = ===X;-X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X;)X; and this flag, one byte below FMS's.X; initialization entry, is used todisabl 4e(,X; RAMIO's wait for vertical blank before2&X; doing a sector transfer...speeds<!X; up RAMDISK I/O tremendouslyFX;P(FASTRAM ;; a negative value allowsZ;the faster transfer rate.dX;nx+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X;X; 5 INITIALIZATION CODEX;X; @ORG  DINIT X;X; SET UP DRIVE INFOX;2X; DRVTBL - 8 BYTES-ONE FR EACH POSSIBLE DRIVEX;X; 0 = NO DRIVEX; NON-ZERO = DRIVE EXISTSX;&X; DBUFA(L,H) 8 TWO BYTE ENTRYS THE)X; DRIVE (V 6TOC) BUFFER ADR FOR A DRIVE"X;,QSASA;;MOVE START OF ALLOC6PZBUFP;;AREA TO ZBUFP@ QSASAJ PZBUFPX;^QDRVBYT;;TEMP 1 IS DRIVEh"PZTEMP1;;EXCESS BITS FROM BOOTrX;|$>;;TEMP 2 ISX;3VTOCLOOPQ>;; PUT ZERO FO NON-EXISTANT D 7RIVES"TZTEMP1;;SHIFT DR BIT TO CARRY D:DECDRV;;BR IF DR NOT THEREX; %>DVDWRQ;;SET WRITE READ OFF‚!P@ZBUFP7;;IN THE DRIVE BUFFERX;QZBUFP;;MOVE CURRENT ALLOCPDBUFAL9;;ADDR TO DBUFAQZBUFP;;AND INC ALLOCDBUFAH9;;BY 144 B 8YTESQ>VTOCSIZE INCZBUFP;;VIA DINCBPX;*Q>DVDVTOP;; set length of regular vtoc&X;0&:DECDRVDRVTBL9;; SET TABLE ENTRY:0;; DEC DRIVE NUMBERD!IVTOCLOOP;;BR IF MORE TO TESTNX;X$X; SET UP SECTOR ALLOCATION TABLEbX;l*X; THE SECTOR A 9LLOCATION TABLE (SECTBL)v$X; HAS 8 ONE BYTE ENTRIES-ONE FOR+X; EACH POSSIBLE 128 BYTE BUFFER. SABYTE'X; IN THE BOOT RECORD DETERMINES THE"X; NUMBER OF ENTRYS TO ALLOCATE(X; ALLOCATED ENTRIES ARE SET TO ZERO.X;)QZBFP;; SAVE START OF SECTO :R BUFFERSPSBUFSTART QZBUFPPSBUFSTARTX;)%SABYTE;; GET COUNT OF SECTOR BUFFERS$>X;)SECTLOOP1;; CHECK IF STILL ALLOCATING C PSECTBL9;; SET ALLOCATE BYTE .G:NEXTBUF;; SKIP BUFFER ALLOCATIO IF DONE* DINCBP4:NEX ;TBUF2;; INC BUF#>(>;; ALL 8 DONE?H HSECTLOOPRX;\X; SET LOW MEMfX;pQZBUFP;;MOVE FINL ADDRzPLMADR;;TO LOW MEM PTR QZBUFP PLMADRX;X; CLEAR FCBS TO ZEROX; CLRFCB Q>;;128 OF FCBʂ?CFCBXPFCB8;;TO BE CLEAR V HADI1` +;;ELSE BREAKj X;t ADI2Q> D;;SET DISK~ PDEVTAB8 Q>DFMSDH;;SET FMS ADDR PDEVTAB8 Q =>DFMSDH PDEVTAB8 X; :T Y TO ZERO ADI1QDEVTAB8;;FIND AH FADI2;;UNUSED R D;;OR DISK$ FADI2;;EMPTY. 38 3B 3L )>V HADI1` +;;ELSE BREAKj X;t ADI2Q> D;;SET DISK~ PDEVTAB8 Q>DFMSDH;;SET FMS ADDR PDEVTAB8 Q $ X;SAVE #D9:FMSOPEN.M65 AOPENAX;+X; DFMOPN - FILE OPEN EXECUTION ENTRY PTX; DFMOPN$ SETUP;; DO FCB SET P.! FNDCODE;;GO DECODE FILE NAME8)QICAUX19;; GET AUX1 (OPEN TYPE CODES)BPFCBOTC9;;PUT INTO FCBL$M>OPDIR;; IS THIS L?ST DIRECTORYVFOPN1;;BR IF NOT` !LISTDIR;;GOTO DIR LIST CODEjX;t#OPN1 SFDIR;;GO SEARCH FILE DIR~6X; QFCBOTC;;GET OPEN TYPE CODER>OPIN;;INPUT FDFOINR>OPOUT;;OUTPUT FDFOOUTR>OPINOPOUT;;UPDATE FDFOUPDR>OPOUTOP@APND;;APPEND FDFOAPNERDVDC@ERROR E.DVDCX;X; DFOIN - OPEN FOR INPUT X; DFOIN 8;;GET SEARCH FLAG(EOPNER1;;ERROR IF NOT FOUND2 DDFOUI<X;FX; DFOUPD - OPEN FOR UPDATAPX;Z DFOUPD d8;;GET SEARCH FLAGnEOPNER1;;R NOT AFOUNDx TSTLOCK;;TEST LOCKX; DFOUI  DFRDSU;;SET UP FOR READ!GREAT;;DONEX; OPNER1)ERFNF@ERRR E.FNF;; FILE NOT FOUNDX;X; DFOAPN - OPEN APPENDX; DFOAPN 8;;GET READ STATUSEOPNER1;;BR NOT FOUND%CDIRD;B;IF OLDQFILDIRDFDFL18;;FILE TYPE"PFCBEFLAG9;; SAVE FILE TYPE,M>DFDNLD;;THEN6FAPOER;;ERROR@ TSTLOC;;TEST LOCKEDJ OPVTOC;;READ VTOCT GETSECTOR;;GET A SECTOR^$PFCBSSN9;;MOVE START SECTOR #hQFCBLSN9;;TO START SETOR #r PFCCBSSN9|!DHFOX2;;CONTINUE AS OPEN APOERERAPO@ERROR E.APOX;X; DFOOUT - OPEN FOR OUTPUTX; DOOUT 8;;GET SEARCH FLAG EDFOX1X;! XDEL0;; delete a single file %CDIRD !OPN1AX; DFOX1 QDHOLES;;AS THERE A HOLEDGOPNER2;;BR IF NO HOLE&/PCDIRS;;SAVE HOLE SECTOR AS CURRENT DIR SEC0& RDDIR;;GO READ CURRENT DIR SECTR:QDHOLED;;MOVE HOLE DISPL TODPCDIRD;;CUR DIR DISPLNQDHFNUM;;MOVE HOLE FNXPSFNUM;;TO CURRENTb OPVTOCl %CDIRv$> Q> ?EOPN1BPFILDIRDFDPFN8;;BLANK FILL FILE ENTRY FOR FILE NAME30 IOPN1BX; OPN1A  $CURFCBQ>DFDINUDFDNLD;; SET FILE TYPE INTO FCBPFCBEFLAG9X; GETSECTOR;;GET A SECTOR%CDIRD;;GET DIR DISPL0PFILDIDFDSSN8;;PUT SECFTOR INTO DIR REC  QFCBLSN9PFILDIRDFDSSN8 X;*2Q>DFDINUDFDOUTDFDNLD;;SET DIR ENTRY IN USEPFILDIRDFDFL18>Q>;; SET NOT LOCKEDH&PFILDIRDFDCNT8;;SET COUNT = 0RPFILDIRDFDCNT8\X;f$>p OPN2QFAME9;;MOVE FILE NAMEzRG> ?;;IF WILD CARDFOPN2A;;CHANGE TO BLANK"PFILDIRDFDPFN8;;TO DIRECTORY OPN2A 32>  DOPN2X; WRTDIR;;GO WRITE DIRECTORY DHFOX2  SETFCB WRTN6;;FIX UP AS IF WRITEQ>FCBFAS;;SET NEW FLE PFCBFLG9  TSTDOS;;HIF NOT DOS HDHFOX3;;BR$ !WRTDOS;;ELSE DO IT. DHFOX3 8 !GREATB X;L OPNER2V -ERDFULL@ERROR E.DFULL;; DIRECTORY FULL` X;j X;t !X; SET UP FCB FOR FILE OPENING~ X; SETFCB Q>;;CLEAR PFCBFLG9;;FLAG &OPNF1QSFNUM;;MOVE FILE NUMI TO FCB T? T? PFCBFNO9 Q> PFCBDLN9;;DATA LENGTH PFCBCNT9;;SET CNT = 0 PFCBNT9 : X; X; X; SET UP FOR READ OPERATION "X; (INCLUDES "DELETE", "APPEND"( %X; AND "UPDATE" AS WELL AS "READ")2 X;< DFRDSU SETFCB;;SET UP FCBFJ %%CDIRD;;MOVE START SECTOR TO LINKP QDFDFL1FILDIR8Z PFCBEFLAG9;; SAVE TYPEd M>DFDLD;;SET NEW SECTORn PFCBSLT9;;FLAGx QFILDIRDFDSSN8 PFCBLSN9 QFILDIRDFDSSN8 PFCBLSN9 !RDNSO;;READ 1T SECTORDFRDSU SETFCB;;SET UP FCBF APUT BYTEAX;X; DFMPUT - PUT A FILE BYTEX; DFMPUT PSVDBYT$ QICDNO9.PICDNOIOCBZICB8 SETUPB0%ENTSTK;;CHK TO SEE IF ENTRY WASN'T FROM CIOL,QSTAK8;;IF HI BYTE RTS IS NOT IN OS ADDRV'R>OSBTM;;SPACE THEN A NON-CIO ENTLY`EFRMCIO;;BR IF FROM CIOj*Q>;;ELSE PREVENT FROM DOING BURST I/Ot PICCOMZ~ FRMCIOQFCBOTC9;;IF NOT OPENM>OPOUT;OUTPUTFPUTER;;ERROR%FCBDLN9;;GET DATA LENGTHC RFCBMLN9;;IF SECTOR NOT FULLDPUT1;;THEN BR# WRTNXS;;ELSEWRIMTE FULL SECTOREPEOF;;BR IF EOF WTBUR;;TEST BURST%>EPUT1;;BR IF NOT BURSTQ@ICBALZ7;;PUT NEXT BYTEPSVDBYT;;AFTER BURST AREA X;PUT1#FCBDLN9;;INC DATA LENQSVDBYT;;GET DATA BYTE(%P@ZSBA7;;AND PUT IN SECTOR BUFFER2X;<&NQ>FCBFSM;;INDICATE SECTOR MODIFIEDF LFCBFLG9P PFCBFLG9ZX;d!GREAT;;DONEnX;xPUTER!ERDVDCPEOFERREF@ERROR E.EOFX;ABURST I/OAX;'X; TEST BURST I/O AND DO IF POSSIBLEX;+WTBURQFCBFLG9;;IF NOT AQUIRING SETORSGOTBURST;;NO BURST;:X;RTBURQ>;;SET READ TYPEX;"TBURSTPBURTYP;;SET BURST TYPE Q>;; SHOW NO BRST OCCURREDPBURSTFLAGQICCOMZ;;IF CMDM>;;IS TEXT MODE"FBURSTEND;;THEN NO BURST,,HTBURLEN;; GO CHECK IF BURT IS POSSIBLPE6X;@)NXTBUR ;; LOOP FOR EACH BURST SECTORJ$TBURSTFLAG;; SHOW BURST OCCURREDTQBURTYP;; CHECK R/W FLAG^ GWRBURhX;rX; READ BURST I/O|X;' RDNXTS;; GET NEXT SECTOR TO BUFFEREBURSTEND;; IF EOF, ABORTX;)%>;; COP DATA FROM BUFFQER TO MEMORY:TOMEMQ@ZSBA7 P@ZBUFP73C;; CHECK FOR END OF DATA RFCBMLN9 D:TOMEMX;- INZBUFP;; BUMP POINTER TO MEMORY BUFFER&!DECLENGTH;; AND GO TO LENGTH TESTX;X; WRITE BURST I/OX;&5WRBUR MOVEDAT;; MOVE DATA FROM RMEMORY TO BUFFER0" WRTNXS;; AND WRITE THE SECTOR:X;D1DECLENGTH;;; SUBTRACT FROM IOCB BUFFER LENGTHNQICBLLZX SFCBMLN9b PICBLLZl ETBURLENv "ICBLHZ+TBURLENQICBLLZ;; TEST LOWER BYTE AGAIN"GNXTBUR;; IF LENGTH >= 28, OKQICBLHZ;; CSHECK UPPER BYTE HNXTBURX;+BURSTENDVBURSTFLAG;; CC=BURST OCCURRED:X;#X; MOVE DATA FROMMEMORY AREA TOX; SECTOR BUFFERX;MOVEDATA%>:MOVELOOPQ@ZBUFP7 P@ZSBA7 3C;; CHECK FOR END OF DATA  RCBMLN9*D:MOVELOOP4XT;>)PFCBDLN9;; SET DATA LENGTH TO MAXIMUMH,!INCZBUFP;; AND INCREMENT MEMORY POINTERRX;\AGETBYTEAfX;pX;zX; DFMGET - GET A FILE BYTEX; DFMGET  SETUP;;GO SET UPQFCBOTC9;;IF OPEN FORM>OPDIR;;DIRCNT FGET1!GDCHAR;;THUEN GO TO DIR RTNX;GET1QFCBDLN9;;GET DATA LENRFCBMLN9;;TEST EMPTY SECTORDGET2;;BR F NOT EMPTY RTBUR;;DO BURST IF POSSIBLE RDNXTS;;GET NEXT SECTOR DGET1;;BR IF NOT EOF !ERREOF;;ELSE EOF ERROR$ X;. GET2?8 Q@ZSBA7;;GET DAVTA BYTEB PSVDBYT;;SAVE THE BYTEL 3V C` PFCBDLN9;;AND SET NEW VALUEt %FCBLSN9;;DO EOF LOK AHEAD~ HGET3;;IF LSN NOT ZERO %FCBLSN9;;THEN HGET3;;NOT EOF &RFCBMLN9;;IF LSN=0 THEN CHECK FOR DGET3;;LAT BYTE Q>;;IF LAST BYTE THEN WRTS !RETURN X; GET3!GREAT 3V C` PFCBDLN9;;AND SET NEW VALUEt %FCBLSN9;;DO EOF LOK AHEAD~ HGET3;;IF LSN NOT ZERO %FCBLSN9;;THEN HGET3;;NOT EOF &RFCBMLN9;;IF LSN=0 THEN CHECK FOR DGET3;;LAT BYTE Q>;;IF LAST BYTE THEN "X;SAVE #D9:FMSCLOSE.M65 ACLOSEAX;X; DFMCLOSE - CLOSE A FILEX; DFMCLS$ SETUP.QFCBOTC9;;GET OPEN COD8M>OPOUT;;IF NOT OUTPUTBFCLDONE;;THEN DONELX;V&UFCBFLG9;;IF NOT ACQUIRING SECTORS`DCLUPDT;;THEN IS UPDATEjX;tY WRTLSEC;;WRITE LAST SECTOR~X; RRDIR;;GO GET DIRECTORY#QFCBCNT9;;GET CNT OF SECTORS5 QFCBCNT95X;QFCBOTC9;;GET OPEN CODEM>OPAPND;;IF NOT APPENDFCLOUT;;BRX;QFCBEFLAG9;; SAVE FILE TYPE5! DFRDSU;;ELSE ST UZP FOR READ 7;; AND RESTORE ITPFCBEFLAG9X;(APP1 RDNXTS;;READ TO EOF2 DAPP1<X;FQFCBSSN9;;MOVE START SECORPPFCBLSN9;TO EOF LINK SECTORZQFCBSSN9dPFCBLSN9n! WRTN2;;THEN WRITE AS NOT EOFxX;CLOUT%CDIRD;;GET DR DISP[L,7OFILDIRDFDCNT8PFILDIRDFDCNT87OFILDIRDFDCNT8PFILDIRDFDCNT8X;'QFCBEFLAG9; GET FILE TYPE FROM FCBPFILDIRDFDFL18 WRTDIR;;WRITE DIR WRTVTOC;;WRITE VTOCX;CLDONEQ>;;CLEAR OPEN COE PFCB\OTC9" !FGREAT,X;6 CLUPDT @$UFCBFLG9;;IF SECTOR NOT MODIFIEDJDCLDONE;;THEN DONET WRCSIO;;ELSE WRITE I^!CLDONE;; THEN DONEhX;r|X;X; RE-READ DIR RECORDX; RRDIR QFCBFNO9;;GET FILE NUMBERV?V? PSFNMX;X;] FNSHFT;;SET ACU=FILE NO/64PCDIRS;;TO GET DIR SECTOR FNSHFT;;SET ACU TO REM=16 FNSHF1T?PCDRD;;TO GET DIR DISPLX;& !RDDIR0FNSHFTQ>:FNSHF1%>;;SHIFT 3 BITS OFD%FNSHF2TFCBFNO9;;FILE NO INTO ACUNU?X1b HFNSHF2l^: FNSHFT;;SET ACU=FILE NO/64PCDIRS;;TO GET DIR SECTOR FNSHFT;;SET ACU TO REM=16 FNSHF1T?PCDRD;;TO GET DIR DISPLX;& !RDDIR0FNSHFTQ>:FNSHF1%>;;SHIFT 3 BITS OFD%FNSHF2TFCBFNO9;;FILE NO INTO ACUNU?X1b HFNSHF2lX;SAVE #D9:FMSXIO.M65 ARENAMEAX;%X;XRENAME - RENAME A FILE OR FILESX; XRENAME$ FNDCODE;; get past old ame.# FNDCNX;; get new name to FNAME8X;B$> ;; 11 character nameL :SVFNLPV QFNAME9`PNEWNAME9;; save new namej`tI:SVFNLP;; all of it~X;X;,X; new name in NENAME, get old name againX; and ensure it exists! NEEDFILE;;does all that!X;/X; found at least one match on old file nameX; :RNMLP$ TSTLOCK;; abort if file locked!( TSDOSa;; ask: is this file DOS.SYS?#6;; save answer to that questionX;$X; here we do the actual renaming X;$>;; bginning of name&WILDFLAG;; initialize flag('%CDIRD;; offset in directory sector2X;< :CHARLPF)QFNAME9;; char fromas-givben old namePR> ?;; wild card?ZH:NOTWILD;; nod""WILDFLAG;; yes...set the flagn/RNEWNAME9;; also wild in as-givn new name?x!H:ERFNM;; no! illegal rename!X; :NOTWILD+QNEWNAME9;; a char of as-given new nameR> ?;; wild?FWILD;; yecs0PFILDIRDFDPFN8;; store a char of new name! :WILD3;; next char in dir sector2;; next char in NEWNAME$(> ;; 11 chars in file name yet?H:CHARLP;; nopeX;-X; okay...we managed to do a valid rename!X;&8;; but was he old name d"DOS.SYS"?H:NDOS1;; no"' DELDOS;; yes...change boot sectors,X;6 :NDOS1@& TSTDOS;; what about the newname?J+H:NDOS2;; not "DOS.SYS"...okay to go onTX;^X; new name is "DOS.SYS"hX;r'$CDIRD;; offset in directory sector,QFILDIRDFDeSSN9;; msb: start of file#%FILDIRDFDSSN9;; lsb: ditto! SETDSO;; change boot sectorsX; :NDO2$ WRTDIR;; write directory sectorX;+QWILDFLAG;; any wild cards in old name?F:RNMRTS;; noX;+ CSFDIR;; seach for next matchifng name&D:RNMLP;; found another...continueX;X; no more names to renameX; :RNMRTS&!FGREAT; we don't need the buffer&X;0 :ERFNM:!ERFNAME;; bad file nameD ADELETEANX;X/X; XDELETE - DELETE ALL FILENAMES HAT MATCHbX;l XDEgLETEv- NEEDFILE;; decode name, ensure it exists XDELX  XDEL0 TSTDOS HXDELY DELDOS XDELYX; WRTDIR;;WRITE DIR ENTRY CSFDIR;;LOOK FOR NEXT MATCHDXDELX;;BR IF FOUND WRTVTOC !FGREATX;$X; to delete a file, weh must read #X; all its sectors, deallocating)X; them from the VTOC bit map as we go X;*XDEL0OPVTOC4X;>XDEL1%CDIRD;;GET DIR DISPLH TSTLOCK;;GO TEST LOCKRQ>DFDEDE;;LOAD DELETED FLAG\!PFILDIRDFDFL18;;DEETE FILEfX;p DFRDSUz#i:XDEL2 FRESECT;; FREE A SECTOR* RDNXTS;; GET THE NEXT ONE INTO BUFFER*D:XDEL2;; AND REPEA UNTIL END-OF-FILEX; XDEL4 !%>DVDWRQ;;TURN ON WRITE REQ'D*C;; BY PUTTING NON-ZERO VALUE INTO VTOCP@VTOCPTR7ʂ :XDLRT:X;ALOCK ANjD UNLOCKAX;X; XLOCK - LOCK A FILE X; XUNLOCK - UNLOCK A FILE X; XLOCK$ Q>DFDLOC; SET LOCK. @SKIP2 ;; (skips to XLCOM)8 XUNLOCKB Q>;;SET UNLOCKL XLCOM ;; common code!V PTEMP4` X;j . NEEDFIL;; decode name & ensure it existskt X;~ "XLC1%CDIRD;;GET CURRENT DISPL #QFILDIRDFDFL18;;GET LOCK BYTE M>;;TURN OFFLOCK LTEMP4;;OR IN LOCK/UNLOCK 'PFILDIRDFDFL18;;SET NEW LOCK BYTE  WRTDIR;;GO WRITE X; CSFDIR;;LOOK FOR NEXTMATCH DXLC1;;BR FOUND !FGREAT;l;ELSE DONE X; ;X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; !X; TSTOCK - TEST FILE LOCKED X; TSTLOCK %CDIRD;;GET DIR DISPL( $QFILDIRDFDFL18;;LOAD LOCK BYTE2 M>DFDLOC;;MASK LOCK IT< (F:XDLRT;; not locked...normal retmurnF ;(fall thru to error)P X;Z TLFd ERFLOCK@ERROR E.FLOCKn APOINTAx X; X; XPOINT - POINT REQUEST X; XPOINT QFCBFLG9;;IF ARQ SECTORS GPERR1;;POINT INVALID QICAUX49;;IF REQUEST IS NT RFCBCSN9;;SAME AS CURRENT HXP1;n;THEN BR QICAUX39 RFCBCSN9 FXP2;;ELSE NO NEED TO CHANGE X; !XP1QFCBFG9;;IF NOT MODIFIED FXP1A;;BR  WRCSIO;;ELSE WRITE IT Q>" PFCBFLG9, XP1A 6 QICAUX49@ PFCBLSN9J QICAUX9T PFCBLSN9^  RDNSO;;READ REQ SECTORh EoXPERRr X;| #XP2QICAUX59;;TEST REQ DATA LEN RFCBMLN9;;LESS THEN MAX DXP FXP3 XPERR ,ERRPDL@ERROR E.PDL;;IF NOT THEN ERROR X; "XP3PFCBDLN9;;SET NEW DATA LEN !GREAT X; PER1 ERRPOT@ERROR E.POT ANOTEA X; "X; pXNOTE - EXECUTE NOTE REQUEST X; XNOTE& QFCBDLN9;;DATA LENGHT VALUE0 ICAUX59;;TO AUX 2: QFCBCSN9;;CUR SEC NO (LO)D PICAUX39;;TO AUX 3N QFCBCSN9;;CUR SEC NO (HI)X PICAUX49;;TO AUX 4b !GREATERRPOT@ERROR E.POT ANOTEA X; "X; X;SAVE #D9:FMSFMT.M65ADEVICE DEPENDENT COMMANDAX;-X; DFMDDC - DEVICE DEPENDENT CMD EXECUTIONX; DFMDDC$ SETUP;;SET UP FOR EXECUTION.QICCOM9;;GET COMMAND8R>;;is it regular format?B%F:FMT1;;yes...go try for MFM modeL'R> r;;what about forced density fmt?VF:FMT2;;yes...do it`X;jX; not a format request...t&X; ...try for one of the stanard~X; FMS capabilities.X;R>MAXDDC;;TEST RANGEEDVDCER;;BR OUT OF RANGE;S> ;;SUBTRACT BASE OF CMDSDD sVDCER;;BR OUT OF RANGET?? QDVDCVT85;;PUSH EXECUTION ADDRQDVDCVT85: X; DVDCVT XRENAME; $20-RENAME( XDELETE;; $21-DELETE2 DVDCER;; $INVALID CMD< XLOCK;; $23-LOCKF XUNLOCK;; $24-ULOCKP t XPOINT;; $25-POINTZ XNOTE;; $26-NOTEdX;nMAXDDC';;MAX DVDC+1xX;DVDCER!ERDVDCX;A FORMAT DISKETTEAX;X; the format tables:1X; each table gives (1) number of vtoc bytes2X; for a given drve type, uand (2) firstX; five bytes of vtocX; TYPETBL TYPE810 DVDVTOP;; 720 sectors ;; dos type3  = ;; max sectors, current sector cntX; TYPE1050" DVDETOP;; 1024 sectors, ;; dos type63 = ;; max sec vtors, current sector cnt@X;J TYPERAMT DVDRTOP;; 512 sectors^ ;; dos typeh3  = ;; max sectos, current sector cntrX;|X;!X; XFORMAT - FORMAT A DISKETTEX;!:FMT2 ;; New XIO 253 command(QICAUX19;; diduser specify de wnsity?H:FMT2A;; yes)Q>DCBCFD;; no...assume single density :FMT2A$>;; used as flag F:FMTJNX;X;%:FMT1 ;; Original XIO 254 format$Q>DCBCFMFM;; start with MFM mode!>;; any non-zero value is flagX; fall hru&X;0 :FMTJN x:*&WILDFLAG;; otherwise used only by REND XFORMATN+PDCBCMD;; set up for use by XIO vectorsX!QICDNO;; what device number?b2$>TYPERAMTYPETBL;; loc'n of RAMDISK size tbllR>;; ram disk?vF:NOSIO;; yes...no SIO callX;"QVTOCPTR;;MO yVE VTOC BUF ADRPDCBBUF;;TO DCB QVTOCPTR PDCBBUF %>@;;TELL SIO RECIEVING DATA&QDSKTIM;GET FORMAT TIME OUT VALUE, DSIO2;;GOTO LOCAL DISK HANDLER THEN SIOX;*I:FMTSIZE;;IF NO ERRORS CONT FORMATING*X; gt an error from SIO form zat request)>E.NAK;; bad request?&H:OOPS;; no...has to be real error($WILDFLAG;; was this XO 254 or 253? FXFERR;; 253...no retryX; 0Q>DCBCFD;; yes...what kind of format was it?*RDCBCMD;; standard FM type?$HXFORMAT;; no...so try t {hat now!>'X; either tried both types of formatH)X; or got error on single density typeR XFERR!RETURN;; quit with errorfX;p*X; if here, got an error other than NAKzX; :OOPS&)>;;ELSE CK FOR DEVICE DONE ERORHXFERR;;NO, THEN ERROR E |XITX;(X; if DEVICE DONE error, there can be)X; several causes (no disk, door open,)X;write protect set, etc.), so we see'X; if reason for DEVICE DONE was bad"X; sectors found in formatting.X;!;ELSE CK FOR BAD SECTOR INFO%>;;RET }URNED BY CONTROLLER"Q>;; drive uses $FFFF to mark ;end of bad sector list in #;dat returned from format call R@VTOCPTR7;; is list empty?$ /HXFBAD;;no...so there were some bad sectors. 38 +R@VTOCPTR7;;till trying for list emptyB $FXFERR ~;;aha! list is empty...soL 2XFBAD ;; ...DEVICE DONE is for another reasonV @ERROR E.DBAD;; sigh.` X;j 1X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;t X;~ *X; format was ok...how big is the disk? X; FMTSIZE .$>TYPE810TYPETBL;; assume single density "QDCBCMD;; which format worked? R>DCBCFD;; single density? !F:NSIO;; yes...tbl ptr in X! 1$>TYPE1050TYPETBL;; no...assume MFM density X; *X; when here, X-reg is offset to proper ; VTOC set-up table... X; :NOSIO %X; first, we zero all of vtoc area Q> +%>DVD2.5;; max size of extended vtoc :ZLPP@VTOCPTR7( 12 H:ZLP< *X; we didn't change byte 0 of the vtoc,F (X; but that's okay becuz the tableP &X; chnges first 5 bytes anyway!Z X;d X; when her e, Y-reg is zeron #X; X-reg pts to a tblx X; %QTYPETBL9;; first bte from table 'PMAXVTOC;; is top of pertinent VTOC X; X; :VTSLP 2;; to next byte of tbl $QTYPETBL9;; a byte fro table... 'P@VTOCPTR7;; sets up a byte in vtoc 3 )>;; did 5 bytes yet? H:VTSLP;; no X; (X; now, we have to setup the bit map X; X; %>DVDSMP;; start of map" Q>;; for first sector, :BITLP6 P@VTOCPTR7@ ,Q>;; all other secors get all one bitsJ 3T -)MAXVTOC;; wasn't it ni ce we set this up?^ H:BITLPh X;r (X; we have to special case a few bit| X; $%>DVDSMP-;;DEALLOCATE MIDDLE 9 Q> P@VTOCPTR7;;FOR 3;;VTOC AND FILE DIR Q> P@VTOCPTR7 X; 1X; no, RAMDISK and regular VTOC are set up... !X; ...but w hat about MFM VTOC? X; %$MAXVTOC;; just to test the value I:FMTX;; not extended X; extended! (%>DVDVTOP;; we deallocate sector 720 P@VTOCPTR7;; for safety X;& )%>DVDAUX;; where xtended count goes!0 /Q>4 ;; # of sectors in exte nded area: P@VTOCPTR7;; LSB...D 3N Q>5 X P@VTOCPTR7;;...and MSBb :FMTNXl X;v X; vtoc is ready to use  WRTVTOC;; so write it out! X; 2X; now, we need to ensure the diretory sectors X; are filled with zero bytes X; Q>;; t husly... ? %XF3PFILDIR8;;USE FILE DIR BUFFER 3 IXF3 ; #Q>;;WRITE TO ALL 8 DIR SECTORS PCDIRS XF4 WRTDIR "CDIRS IXF4 X;*  DELDOS;;SET NO DOS4 X;> !FGREAT;DONEory sectors X; are filled with zero bytes X; Q>;; t X;SAVE #D9:FMSDIR.M65ALIST DIRECTORYAX;"X; LISTDIR - LIST THE DIRECTORY%X; GDCHAR - GET NEXT DIR CHARACTERX; THE DIRECTORY IS LISTED VIA OPEN$&X; LIST DIRECTORY FUNCTION EACH DIR.&X; ENTRY THAT MATCHES THE FILE SPEC8(X; IS CONV$RTED TO A PRINTABLE FORMATB)X; INTO A SECTOR BUFFER. THE GET BYTEL(X; ENTRY IS USED TO GET THE PRINTABLEV$X; CHARACTERS NE AT A TIME. THE`#X; LAST LINE PRINTED IS ALWAYS Aj+X; COUNT OF THE NUMBET OF SECTORS IN USEt0X; AND THE NUMBER REMAINIG A$VAILABLE SECTORS~X; LISTDIR" SFDIR;; Search for first name+D:LDJN;; found a name...join with FDENTX;'X; n more name matches in directoryX; :LDFREE" RDVTOC;; ensure VTOC in place %>DVDAUX*Q@VTOCPTR7;; get LSB of auxsector$ cnt %>DVDNSA,-O@VTOCPTR7;; add in LSB or std sector cnt 5;; save for a nonce3+Q@VTOCPTR7;; MSB of stndard sector cnt(%>DVDAUX2+O@VTOCPTR7;; is added to MSB of aux cnt<>;; we need this in A-reg...F7;; ...but this.P?;; ..$.has to be in Y-regZ!A;; so now it is back in A-regdX;n&X; free sector cnt in Y,A (lsb,msb)xX;$>0&DIRPTR;; so that cnt is at start of buffer% CVDX;; convert to decimal number%>;; right after count...A$P@ZSBA7;; ut space or $plus sign3;; to start of msgX; add FREE SECTORS message :FRMSGLP2Q:FSMSG8;; becuz Y starts at 4 i this loopP@ZSBA7;; a byte of msg3)>;; at end ?H:FRMSGLP;; no- :CVEOL;; add RETURN and set DIRCPTR to 0:GREATEXIT""!$GREAT;; exit with good status,#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6X;@!X; This entry point is used byJ X; he FMS get-a-byte routineT"X; when it discovers that input^#X; is occurring from a file openhX; in DIRECTORY mode.rX;|#X; Here, we simpl$y pass back the#X; formatted entry one byte at a'X; time until an entry is exhausted.(X; Then we go ormat another line, ifX; there is more to do.X; GDCHAR#%DIRCPTR;; get and test pointer I:GDOK$!ERREOF;; nomore char's to get!$X; :GDOKQ@ZSBA7;;GET NEXT CHARPSVDBYT;; IN SVDBYT#DIRCPTR;;INC COUNTR>EOL;;TEST IF OL DONEH:GREATEXIT;;BR NOT EOL&)>;;WAS THIS AN ENTRY0ELDENT;;BR IF IT WAS:Q>;;ELSE INDICATE ENDDPDIRCPTR;;N DIRCPTRN-!FGREAT;;DO$NE...release the sector bufferXX;b3X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lX;v1X; LDET is used to get another file name line(X; formatted into the sector bufferX; LDENT " CSFDIR;;SEARCH FOR NEXT ATCH,E:LDFREE;;NO MORE M$ATCHES, give free cnt :LDJN FDENT;;FORMAT ENTRY!GREAT;;DONEX;X;-X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X; :FSMSG AFREE SECTORSA X; X;*+X; FORMAT DIR ENTRY INTO A SECTOR BUFFER4X;> FDENTH$CDIRD;; current di$r entryR%>;;START AT DISPL ZERO\Q> ;;START WITH A BLANKf P@ZSBA7;;formatted in bufferQFILDIRDFDFL19z M>DFDLOC;;BUT IF FILE LOCKED F:LD1Q> *;;CHANGE TO ASTERISK P@ZSBA7:LD13Q> ;;FOLLOED BY A BLANK P@ZSBA73X;$0X; now move the name from directory to bufferX;*LD2QFILDIRDFDPFN9;;MOVE THE 11 HARP@ZSBA7;;FILE NAME 2 3 )> $ DLD2. X;8 Q> ;;FOLLOWED BY A BLANKB P@ZSBA7L 3V )'DIRCPTR;; where we want# of sectors` X;j X;t %X; now we c$heck to see if extended~ %X; file type needs to be indicated X; ($CDIRD;; back to lok at current dir QICAX1Z;; what kind of open? W?;; (mode 6 or mode 7?) D:LD3;; mode 6...do nothing X; indicate wheher extended QFILDIRDFDFL19;; file$ type #W?;; extended file is $03 or $23 !D:LD3;; not extended...ignore &1;; back o where we just put space Q> > 'P@ZSBA7;; form becomes "" %>;; right after asterisk Q> < %P@ZSBA7;; oter half of indicator X;( :LD32 X;< X$; ready for cnt of sectorsF X;P X;Z %FILDIRDFDCNT9;;SET A,Yd &QFILDIRDFDCT9;;=SECTOR COUNTn X;x CVDX $>d;;CONVERT AND MOVE  CVDIGIT;;100S DIGIT $>  CVDIGIT;;10S DIGIT $>  VDIGIT;;1S DIGIT X; )X; but this routine g$ives a max number 'X; of 999...and free sector cnt gets #X; a plus sign if cn is greater X; $> ;; assume a space C;; remainder !F:LT1000;; less than 1000, ok +$> +;; greater than 999...need pus sign :LT1000" X;, %>;; where we want t$he EOL6 X;@ ,X; put out an EOL and reset entry pointerJ X;T :CVEOL^ Q>OL;;AND EOLh P@ZSBA7r %>| 'DIRCPTR;;SET CHAR CNT = 0 : X; -X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; (X; VDIGIT -- routine puts next digit X; of numbe$r into entry X; CVDIGIT &TEMP3;;SAVE DIGIT VALUE $> X; :VD1 PZTEMP2;;SAVE CURR VALUE HI 'ZTEMP1;;AND LOW 2;; INC DIGIT COUNTER ;;;SUBRTACT DIGIT VALUE& QZTEMP1;;FROM CU VALUE0 STEMP3: ?D QZTEMP2N S>X -D:CVD2;; wen$t minus...we went one too farb X;l "(> ;; got max digit value yet?v H:CVD1;; no ;yes...fall through! X; :CVD2 X; A;;DIGIT TO ACU L>0;;PLUS ASCII ZERO %DIRCPTR;;GET OUTPUT INEX P@ZSBA7;;AND SET DIGIT #DIRCPTR;; INC OUTPUT IND$EX *QZTEMP2;;LOAD VALUE HI (for next call) %ZTEMP1;;AND VALUE O ::CVD1;; no ;yes...fall through! X; :CVD2 X; A;;DIGIT TO ACU L>0;;PLUS ASCII ZERO %DIRCPTR;;GET OUTPUT INEX P@ZSBA7;;AND SET DIGIT #DIRCPTR;; INC OUTPUT IND$I X;SAVE #D9:FMSFNAME.M65AFILE NAME DECODEAX;"X; FNDCODE - DECODE A FILE NAMEX;(X; THE USER FILENAME IS POITED TO BY$+X; ICBALZ, IT IS ON THE FORM P X WHERE P.-X; IS THE PRIMARY FILE NAME (1 TO 8 CHARS)8%X; AND X IS THE EXTENDED(FILE NAMEB-X; (0 TO 3 CHARS). THE PERIOD IS OPTIONALL*X; (IF NOT PRESENT, THEN NO EXTENSION).V+X; THE DECODED FILENAME WLL BE 12 CHARS`&X; IN LENGTH. THE P FIELD WILL BE j(X; LEFT JUSTIFIED IN THE 1ST 8 BYTES.t+X; THE X FIELD WILL BE LEFT JSTI(FIED IN~(X; THE LAST 3 BYTES. BLANKS ARE USED%X; TO PAD THE FIELDS TO FULL SIZE.)X; IF THE USER SPECIFIED P OR X FIEDS.X; CONTAIN MORE THAN 8 OR 3 CHARS, THEN THE'X; EXTRA CHARS ARE IGNORED. THE '*'(X; WILD CARD CHAR WILL CAUSE THE EST&(X; OF THE FIELDS TO FILLED WITH THE/X; '?' WILD CARD CHAR. ANY NON-ALPHANUMERIC#X; CHAR TERMINATES THE FILENAME.؂X; FNDCODE$%>;;find beginning of real name:FDCLPQ@ICBALZ71 $G:FNERR;;we only allow D: or Dn:R> : H:FCLP(3;;( POINT PAST THE COLON2X;<X; secondary entry point:F1X; Y points one byte before name to decodePX;Z FNDNXd 3;; to real beginning of namen"Q>;; max chars in name properxX;$>;; destination indexX; :FDLPSPCL-PETSW;; save e(nd of current portion here:FDMAINLOOPQ@ICBALZ7;; get a characterR> .;; start extension?H:FDNP;; nX; found a period:!(>;; at end of primary name?6H:FDPERIOD;;not exactly in right place, space fillX;3X; got aperiod & we hav(e space filled if needed*X; ....time to switch over to extensionX;%3;; now we can get past the period"!Q> ;; and switch to extension,&H:FDLPSPCL;; special loop re-entry6X;@ :FDPERIODJ-D:FDSPACE;; in main name, space fll onlyT)X; other(wise, treat period as bad char^-X; ...so fall thru to discover it is 'bad'hX;r :FDNP|!R> *;; rest ofthis part wild?H:FDNSTAR;; no+Q> ?;; yes...fill with single wild cards$(EXTSW;; at end of this portion?#E:FDOK;;force Y off of the '*('D:FDFILL;; just fillX;2X; if here, not one of the repeating charactersX; :FDNSTARR> ;; the wild card?F:FDOK;; yesR> 0;; a numeric?)D:FDBAD;; no...bad char...end of name&R> 9;; maybe...numeric ck againD:FDOK;; yes.(..'0 to '9)M>;; not numeric...change lower case&R> A;; alpha?0D:FDBAD;; nope...kablooey:$R Z;; maybe...try alpha againDD:FDOK;; yep...A to ZNX;X%X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bX;l(X; if bad characte, fill with spacesvX; (:FDBAD)Q> ;; ensure we go all the way to end PEXTSW#(> ;; is this bad char after...)FFDEXIT;; we already have full name?';if here, no...need to keep fillingX; :FDSPACEQ> ;; space fill H:FDFILLX;/X; if here, is legitimat(e filename characterX; :FDOK 3;; so bump to next charX; 'X; now, put char in FNAME if proper*X;4 :FDFILL>$(EXTSW;; at end of this portion?H0F:FDMAINLOOP;; yes...don't put char in FNAMER)PFNAME9;; o...finally, a legit char!\2;; (to next characterfX;p"H:FDMAINLOOP;; and do it againzX;-X; have now stored 11 charaters in FNAME!X; :FDEXIT%QFNAME;; what is first character?R> ;; a space?F:FNERR;; yes#$CURFCB;; can neve forget this:;; no...name is deco(dedX;X;&X; oops...no characters in filenameX; ERFNAME :FNERR !@ERRORE.FN;;filename error X;:FDEXIT%QFNAME;; what is first character?R> ;; a space?F:FNERR;; yes#$CURFCB;; can neve forget this:;; no...name is deco(s X;SAVE #D9:FMSSRCH.M65ADIRECTORY SEARCHAX;#X; SFDIR - SEARCH FILE DIRECTORY$X; CSFDIR - FILE DIRECTORY SEARCX;$,X; THE FILE DIRECTORY IS SEARCHED FOR THE.+X; FILENAME IN FNAME. THE SEARCH STARTS8/X; AT THE CENTRAL SECTOR+1 AN, WILL CONTINUEB+X; FOR UP TO A TOTAL OF 8 SECTORS. WHENL(X; TESTING FOR FNAME MATCH, '?' FNAMEV.X; CHARS WILL ALWAYS MATH THE CORESPONDING`-X; DIR FILENAME CHAR. IF A MATCH IS FOUNDj2X; CDIRS CONTAINS THE RELATIVE DIRECTORY SECTORt,X; NUMBE (0,-7) AND CDIRD (AND THE Y REG)~-X; CONTAINS THE DISPLACEMENT OF THE ENTRY.5X; AFTER A MATCH HAS BEEN FOUND, THE DIRECTOY CAN2X; BE SEARCHED FOR ANOTHER MATCH VIA THE CSFDIR1X; ENTRY POINT. IF A MATCH HAS NOT BEEN FOUND-X; THEN DHOLES AN DHOLE,D WILL POINT TO A &X; DIRECTORY HOLE THAT CAN BE USED.0X; IF DHOLED = FF THEN THE DIRECTORY IS FULL.0X; THE CARR IS RETURNED CLEAR IF FILE FOUND,X; SET IF FILE NOT FOUND.X; SFDIRQ>;;INIT TO -1PDHOLES;;DIR HOLE SECTORPCDIRS;;,CUR DIR SECTOR PSFNUM;;FILE NUMBER$Q>p;;INIT TO -16 (-ENTRY LENGTH)PCDIRD;;CUR DIR DISPL(X;2 CSFDIR<#SFNUMF,P!QCDIRD;;CDIRD=CDIRD+ENTRY LENZ O>DFDELNd!ISFD2;;IF RESULT <128 THEN BRnX; ELSE AT END OF DIR SECTx"#CIRS;;INC TO ,NEXT DIR SECTORQ>;;TEST END OF DIR RCDIRSDSFD1;;BR NOT END FSDRTNX;)SFD1 RDDIR;;READ THE NXT DIR RECORDQ>;;SET DIR DISPL = 0X;"SFD2PCDIRD;;SET NEW DIR DISPL?;;PUT DISPL IN Y AS INDEXX; QFILDIRDFDFL18;;GET FL,AG 1.FSFDSH;;BR IF UNUSED (END OF USED ENTRIES)GSFDSH;;BR IF DELETED&M>DFDEXTDFDINU;; mask for saety$R>DFDEXT;; BR IF "EXTENDED" FILE" F:INUSE,M>DFDOUT;;IF OPEN OUTPUT6HCSFDIR;;DON'T FIND IT@X;J"X; ENTRY IN SE, TEST FOR MATCH,T&:INUSE$>;;TEST MATCH ON 11 CHARS^ SFD3QFNAME9;;FILE NAME CHARhR> ?;;IS FNC WILD CARDrFSFD4;;HEN IT MATCHES|1RFILDIRDFDPFN8;;ELSE IT MUST MATCH FOR REAC'HCSFDIR;;IF NOT MATCH THEN TRY NEXTSFD42;;INC CHAR CN3(> ;;TEST ALL,HSFD3;;AND CONTINUE CHECKX;,;;WE HAVE A MATCH DSDRTNX; SFDSH QDHOLES;;IF DHOLES NT MINUS*ISFDSH1;;THEN ALREADY HAVE A GOOD HOLEX; X; ELSEX;"QCDIRS;;MOVE CURR DISPL SECTOR&"PDHOLES;;AND CURRNT DIR DISPL0$QCDIRD;;,TO HOLE SECTOR AND DISPL: PDHOLEDDQSFNUM;;SAVE HOLENPDHFNUM;;FILE NUMBERXX;b2SFDSH1QFILIRDFDFL18;;IF HOLE WAS A DELETEDl GCSFDIR;;ENTRY THEN CONTINUEvX;X; ELSE WE ARE AT END OFX;&;;;USED ENTRIES THS FILE NOT FOUND SDRTN$,CURFCB;;RESTORE X REG:X;!X; routine to do three things:X; 1. decode file name'X; 2. search for file in directory0X; 3. abort with file name error if not fndX; NEEDFILE FNDCODE;; what's the nae? NEEDSRCH  SFDIR;; sea,rch for itE:NEEDBAD;; oops :*X;4 :NEEDBAD>!ERFNF;; file not foundHX;le name'X; 2. search for file in directory0X; 3. abort with file name error if not fndX; NEEDFILE FNDCODE;; what's the nae? NEEDSRCH  SFDIR;; sea,SX;SAVE #D9:FMSRWSEC.M65AWRITE DATA SECTORAX; X; WRTNXS - WRITE NEXT SECTORX; WRTNXS$"QFCBFLG9;;IF ACQURING SECTORS.GWRTN1;;THEN NOT UPDATE8X;BT?;;IF SECTOR NOT MODIFIEDLIWRU1;;THEN DON'T ITVX;`T?j PFCBFLG9;;TUR0 OFF FLAG BITSt! WRCSIO;;WRITE CURRENT SECTOR~GWRNERR;;BR IF BAD I/O'WRU1!RDNXTS;;ELSE READ NEXT SECTORX;&WRT1 GETSECTOR;;GET A NEW SECTORX;"WRTLSECQFCBDLN9;;GET DATA LEN%>DRVLBT;;INTO LAST BYTEP@ZSBA7;;OF SECTORX;'0WRTN2QFCBLSN9;;MOVE LINK SECTORLFCBFNO9;;PLUS FILE NUM%>DRVMDL;;TO BYTES 126,127P@ZSBA7;;OF SECTOR BUFF3  QFCBLSN9 P@ZSBA7X;( WRCSIO;;WRITE SECTOR2IWRTN5;;BR NOT ERROR<X;F WRNERRPQ>;;CLOSE FILEZ PFCBOTC9QDC0BSTA;;RECOVER ERROR CODEn !RETURNxX; WRTN5#FCBCNT9;;INC SECTOR CNT HWRTN6#FCBCNT9 WRTN6 MVSN;;LINK TO CURQ>PFCBLSN9;;LINK = 0PFCBLSN9PFCBDLN9;;DLN = 0 Q>DRVMDL PFCBMLN9,:X;WRCIO;;;WRIT0E CUR SECTOR"RWCSIOQFCBCSN9, %FCBCSN96 !DSIO@X;JMVLSNQFCBLSN9;;MOVE LINKT PFCBCSN9^QFCBLSNhPFCBCSN9r:|X;AREAD DATA SECTORAX;X; RDNXTS - READ NEXT SECTORX; RDNXTSQFCBFLG9;;IF NOT UPD MDEFRDNSO0;;BR!WRTNXS;;ELSE WRITE FIRST RDNSO QFCBLSN9;;IF LSN NOTLFCBLSN9;;ZEROHRDNS1;;BR;;;ELS EOF:&RDNS1 MVLSN;;MOVE LINK TO CURRENT ,;;READ& RWCSIO;;CURRENT SECTOR0GRDIOER;;BR IF OK READ:X;DX; ELSEGOTO I/O ERRORN0X;X %>DRVMDLbQ@ZSBA7;;TEST FOR SAMElM>;;FILE NOv RFCBFNO9HRDFNMM;;IF NOT THEN ERRORX;QZSBA7;;MOVE LINK SECTORM>PFCBLSN93 Q@ZSBA7 PFCBLSN9X;3;;INC TO LEN BYTEQ@ZSBA7;;GET LEN BYTE 5;;SAVE IT!QF0CBSLT9;;GET SECTOR LEN TYPEHRDNS3;;BR IF NEW TYPE X; 7;;GET LEN "GRDNS2;;BR IF OLD SHORT SECTOR*Q>};;ELSE SET FULL SECTOR4RDNS2M>;;TURN OFF MSB>5;;BALANCE STACKHX;R RDNS37\PFCBMLN9;;SET MAX LENfX;pQ>;;SET CUR DATA LEN = 00z PFCBDLN9,:RDIOER ERRIO;;I/O ERROR"RDFNMM ;;FILE NUMBER MISMATCH QICCOM9R>!;;AS THIS DELETEFRDDELE;;BR IF DELETEERFNMM@ERROR E.FNMM#RDDELE;;;INDICATE EOF TO DELETE:X;MAX LENfX;pQ>;;SET CUR DATA LEN = 0X;SAVE #D9:FMSVTOC.M65AREAD/WRITE DIRAX;&X; RDDIR/WRDIR READ/WRITE DIRECTORYX;$ RDDIR.,;;SET READ8DDIRIOBX;L WRTDIRV;;;SET WRITE`X;j DIRIOt6;;SAVE READ WRITE~X;,QCDIRS;;CDIRS+3O>4SECVTOC ;; LSB4of beginning of directory?;;needed in Y!8;; recover read/write request$>FILDIR,Q>FILDIR;;we want to read/rite thisX;HDSYSIO;;GO DO SYSTEM I/OX;AREAD/WRITE VTOCAX;%X; RDVTOC/WRCTOC - READ/WRITE VTOC X; RDVOC4 %>DVDWRQ($Q@VTOCPTR7;; need to write VTOC?20H:RWRTS;; yes...so don't read a new one now!<X;F.X; do we read norml vtoc or extended vtoc?PX;Z%ICDNOZ;; drive #d RAMDISKn$Q>DVDRTOP;; top of RAM disk vtocx)>;; is this a RAMDIS?F4:RV3;; yesX;'DCBDRV;; for DHADR call"Q>DCBCST;; status request ('S)PDCBCMD;; also set up& DHADR;;call ROM disk I/O routine&Q>DVDVTOP;; assume 810 style drive%DHSTAT;; is it?I:RV3;; yesQ>DVDETOP;; MFM mode:RV3(%4ICDNOZ;; once again, drv # (1 to 8),PDRVTBL8;; set vtoc top as drive type$PMAXVTOC;; same thing SETUP doeX;""X; now MAXVTOC is a useful flag,X;6"X; have to handle extended vtoc@,;; set up for readJ0 EVTOCIO;; read exteded vtoc (ig4nore error)T& SAVEEV;; and save it for a moment^!X; (count on A=0 after SAVEEV)h)%>DVDWRQ;; 0-->flag...avois problemsr+P@VTOCPTR7;; ...with reading junk VTOCs|X;,$ VTOCIO;; then read regular vtoc+ RESTOREEV;; and get etended vtoc bac4k :RWRTS:'X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X;X; OPEN VTOCX; OPVTOC RDVTOC;;READ IT ;then fall thru to write it!X;'X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X;#X; WRVTOC -- write the full VTOC&X;0 RTVTOC:Q>D%>4DVDWRQ;; turn off flag:N)P@VTOCPTR7;; write no longer requiredX% SAVEEV;; then save extended VTOCb;) VTOCIO;; while we write regular vtocv& RESTOREEV;; recover extended VTOC;&!EVTOCIO;; and write extended VTOCX#X;;;;;;;;;;;;;;;;;4;;;;;;;;;;;;;;X;-X; VTOCIO -- read/write (based on CLC/SEC)#X; primary VTOC sectorXX; VTOCIO QVTOCPTR;; BUF ADDR, high$VTOCPTR;; and lowX;,%>4SECVTOC;; primary vtoc sector # (lsb) X;$X;;;;;;;;;;;;;;;;;;;;;;4;;;;;;;;;; X;*,X; DSYSIO -- read/write VTOC or DIRECTORY4.X; sector--buffer addr in X nd A>,X; (lsb and msb), lsb of sectorH,X; number in Y (msb always $01)R DSYSIO\ 'DCBSECf%>5SECVOCp)'DCBSEC;; form ful4l sector addressz;fall thru to SECAXIOX;$X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X;)X; SECAIO -- read/write (CLC/SEC) any/X; sector--buffer addr in X and A,X; (lsb and msb), sector number!; already in DCBSEC4X; SECAXIOPDCBBUF;; address to DCB &DCBBUF BSIOR;;GO DO I/OI:EVRTS;; god status X; ")>DCBDER;; what kind of error? FDEAD;; data error$ ,!ERRIO;; serial I/O error...user handles. X;8 (DED@ERROR E.SYS;; tch tch, fatal4B X;L *X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;V !X; EVTOCIO -- extended vtoc IO` X;j EVOCIOt 1QMAXVTOC;; does this disk have an ext'd vtoc?~ (I:EVRTS;; no...so don't try anything X; 6;; save READ/WRITE fla Q>4EVSECNUM "PDCBSEC;; set up 4sector number Q>5EVSECNUM PDCBSEC;; (both bytes) X; "QVTOCPTR;; (also calle ZDRVA) , &O>EVOFFSET;;; adjust start of vtoc >;; lsb to X QVTOCPTR O>;; msb to A 8 '!SECAXIO;; do I/O va buffer at A/X X;( X;2 X;< )X;;;;;4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;F X;P 6X; SAVEEV -- save the 44 bytes of the extende vtocZ 3X; which are also in regular vtoc aread SAVEEVn (%>DVDVTOP;; 1 byte past regular vtocx :SEV2 Q@VTOPTR7 PFIXEDBITSDVDVTOP8 !Q>;; zero4 area as we save it P@VTOCPTR7 3 )>DVD2.5;; (144 bytes) H:SEV2 :EVRT : X; ,X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; %X; RESTOREEV -- the 44 bytes again X; RESTOREEV &%MAXVTO;; any point in restoring?" )I:RERTS;; no...4leave zero bytes alone, %>DVDVTOP6 :REV2@ QFIXEDBITSDVDVTOP8J P@VTOCPR7T 3^ )>DVD2.5;; (144 bytes)h H:REV2r :RERTS| : X; %X; RESTOREEV -- the 44 bytes again X; RESTOREEV &%MAXVTO;; any point in restoring?" )I:RERTS;; no...4X;SAVE #D9:FMSALLOC.M65AFREE SECTORAX;#X; FRESECT - FREE CURRENT SECTORX; FRESECT$'QFCBCSN9;; get lsb f sector number."5;; save for just a tick or two8)M>;; use 3 least significant bits...B?;; ...as an indexL7;; get FC8CSN,X backV,LFCBCSN9;; check out complete sec num`%F:FRRTS;; can't free sector zero!jX;t/X; okay...real sector andY-reg has index...~#X; ...into single bit mask tableX;"QBITTBL8;; so get a single bit#5;; save mask until ready forit8X;QFCBCSN9;; get lsb again#%>;; shifting right 3 times.../:FRE1VFCBCSN9;; will divide sector #...$W?;;...by 8, making a byte index1 H:FRE1X;,.O>DVDSMP;; offset to start of vtoc bit map ?;; ...true index..."7; (rec8over proper bit number)L@VTOCPTR7;; set bit..(,P@VTOCPTR7;; ...meaning sector available2X;<2X; now we must inrement one of the sector cntsFX;PX; which one?ZX;d))>DVDVTOP;; past top of regular vtoc?n"%>DVDNSA;; assume regula vtocxD8:FRE2;; it is regular(%>DVDAUX;; not regular...use aux cnt :FRE2-Q@VTOCPTR7;; clumsy way to bump by one..,;; but only way with 6502O>;; instruction set when$P@VTOCPTR7;; using (xxx),Y form.3Q@VTOCPTR7O>PVTOCPTR78X; :FRRTS :X;AGET SECTORAX;"(X; GET SECTOR - GET A FREE SECTOR FOR,%X; USE BY FCB POINTED TOBY X-reg.6+X; The sector number is placed in FCBLSN@X;J)X; THE SEARCH FOR A FREE SECTOR STARTST&X; AT THE DVDSMP BYTE. SECTORS ARE^(X8; NUMBERED SEQUENTIALLY FROM ZERO TOh2X; MAXVTOC*8-1, WITH THE LEFT BIT OF THE DVDSMPrX; BEING BIT #ZERO.|X; GETSECTOR+%>DVDSMP;; start one byte before mapX;:GS13;; to next byte of map&)MAXVTOC;; at end of thismap yet?'EGSERR8;; yes...no sectors available*Q@VTOCPTR7;; no...try this byte of map'F:GS1;; no free sector in this yteX;&X; found a byte with a free sector!X;X;.X; before proceeding, let's find bit numberX; and flip the btX;*$>;; simpl8y initializing the bit cntr&X;0 :GSBIT:2;; count a bitDT?;; is this it?ND:GSBIT;; noXX;b; X has bit numberlQBITTBL9;; get the bitv N@VTOCPTR7;; flip it in vtocP@VTOCPTR7;; thusly.X;*X; VTOC bit map hanged, bit # in X-reg8X;A;; so we save bit number!5;; on stack for a bit of timeX;)X; now generate the sector #in FCBLSNX;!$CURFCB;; work with FCB againX;C;; byte displacement to A;%S>DVDSMP;; becomes INT(sector#/8) PFCBLSN9;; prepare to firs8t mult by 8X; 'Q>;; 2 upper bits on=3 left shifts*X;4-X; note that after shifting A thre times,>$X; we will shift out a zero bitH(X; and, if nothing gets shifted in,R)X; A will hold zero. Thus $C0 is as%X; good as $00 for initial8 valuefX; of MSByte of LSNpX;zX; :GSLP1 TFCBLSN9;; shift low byte...U?;; ...ito high byteE:GSLP1;; 3 times?X;&PFCBLSN9;; and set up high byte7;; recover bit number'LFCBLSN9;; becomespart of sector #PFCBLSN9;; th8usX;X;2X; now we must decrement one of the sector cntsX; X; which one? X; )>DVDVTOP;; past top of regular vtoc?$ "%>DVDNSA;; assume regular vtoc. D:GS2;; it is regular8 (%>DVDAUX;; not regular..use aux cntB +QFCBEFLAG9;; AHA! If8 this sector is...L &M>;; ...in extended VTOC, then...V %L>;; ...we must change its FLAG` -PFCBEFLAG9;; to indicated 'extended file'j :GS2t #;;; the only 6502 way to do this~ Q@VTOCPTR7 S> P@VTOCPR7 3 Q@VTOCPTR7 S> P@VTOCPT8R7 X; ,X; as long as we are messing with VTOC... X; +%>DVDWRQ;; set WRITE VTOCREQUIRED flag #C;; (any non-zero value will do) P@VTOCPTR7 4QFCBLSN9;; for callers: expected of GETSECTOR :;; andthat's it X; X;;;;;;;;;;;;;;;;;;;;;;;;8;;;;( X;2 -GSERR@ERROR E.NSA;;NO SECTOR AVAILABLE< X;%>DVDWRQ;; set WRITE VTOCREQUIRED flag #C;; (any non-zero value will do) P@VTOCPTR7 4QFCBLSN9;; for callers: expected of GETSECTOR :;; andthat's it X; X;;;;;;;;;;;;;;;;;;;;;;;;8;X;SAVE #D9:FMSSETUP.M65ASETUP ROUTINEAX;-X; SETUP - A ROUTINE USED FOR ALL COMMANDS"X; TO SET UP FMS CONTROL CELLS"X; TO ACCESS A PARTICULAR FILE.$X;. SETUP8 &CURFCBB@L2V2` &ENTSTKjX;t$ICDNOZ;;MOVE DRIVE NO~&<D:SU1;;BR MORE TO TRYFX;P2ERRNSB@ERROR E.NSB;;NO SECTOR UFFERS< AVAILZX;d:SU2Q>;;ALLOCATE BUFFERn PSECTBL8x3C!PFCBBUF9;;PUT BUF NO INTO FCBX;&:SU31;; NOW COMPTE BUFFER ADDRESS"C;; BY MULTIPLYING INDEX BY 128V?5Q>W?;; A NOW = 0 OR $80, C = 00OSBUFSTART;; AND ADDIN BUFFER S;;FREE<PFCBBUF9;;IN FCBPSECTBL8;;AND TABLE FSBR:X;ADATA SECTOR I/OAX;X; DSIO - DATA SECTOR I/OX;DSIO$ZSBA;;WRITE SECTOR BUF&DCBBUF;;ADR MOVED TO$ZSBA;;DCB&DCBBUF!BSIO;;DO THE I/OX;ACCESSQ>;;FREE<X;SAVE #D9:FMSDOS.M65AWRITE DOSAX; X; WRTDOS - WRITE DOS TO DISKX; WRTDOS$%FCBCSN9;;MOVE START ADDR.QFCBCSN98! SETDSO;;WRITE SECTORS 1 TO 3B WRDOSSYS;;WRITE DOSL !GREATVX;` DELDOSjQ>;;SET FILE NOT EXISTSt@WRTBOOT~ PDFSFLGX; Q>FMSORG;;MOVE FMS STARTPDCBBUF;;ADDR TO DCB%>FMSORG 'DCBBUFX;4X; !!! aution: ASSUME Y-REG IS ZERO !!!!!!!!!!!X;WRNBS3;;INC SECTOR NOQ>; BSIO;;DO THE WRITEX; 'QDCBBUF;; DD @128 TO BUFFER ADDRESSN> PDCBBUF( G:WRB12#DCBBUF<X;F!:WRB1%DCBSEC;;TEST FOR WRITEP)BRCNT;;OF ALL BOT SECTORSZHWRNBS;;BR NOT ALLdX;n:xX;"SETDSO'DFLINK;;SET LINK STARTPDFLINK"Q>;; SET DOS FLAG TO NON-ERO@HWRTBOOT;;GO WRITE SECTOR 0X;4WRDOSSYS MOVESTART;; MOVE START OF DOS TO ZBUFP#Q>};; SET SECTOR MAXIMUM ENGTH PFCBMLN9X;3:WRDOSLOOP MOVEDATA;; MOVE NEXT SECTOR OF DATA QZBUFP;; TEST FOR END OF DOS RSASA QZBUFP SSA@SA E:LASTSEC"X;,( WRTNXS;; NOT THE LAST, WRITE IT OUT6!:WRDOSLOOP@X;J7:LASTSEC:;; JUST RETURN SO COSE WRITES LAST SECTORTX;^ATEST DOS FILE NAMEAhX;r*X; TSTDOS - TEST FOR DOS SYS FILE NAME;|X; TSTDOS($>;; egin looking@ at start of name,%CDIRD;; current directory sector offset :TDOSLP0QFILDIRDFDPFN8;;TEST FILENAME in Drectory'RDFN9;;WITH "DOS.SYS" FILENAME CHARH:TDFR;;BR NOT MATCH3;; to next char in DIR2;; to next char in DOS.SS(> ;; 11 c@haracters yet?%H:TDOSLP;;BR IF MORE, ELSE RTN EQ :TDFR6;; must save status!$$CURFCB;; a must for ome caller8;; answer to is it DOS.SYS?:&X;0DFN ADOS SYSAH3;; to next char in DIR2;; to next char in DOS.SS(> ;; 11 c@ AERROR ROUTINE AND CLEANUPAX;X; ERROR ROUTINESX;'ERROR7;; RETRIEVE ERROR NUMBER FROMPERPTR;; JSR AREA$7. PERPTR8%>B Q@ERPTR7L X; AND FALL THROUGH TO RETURNVX;$RETURN$ENTSTK;; GET ENTRY STACKB;;AND RESTORED $CURFCBPICSTA9;;PUT IN FCB? QSVDBYT;;GET SAVED DATA BYTE:X; %ERRIOQDCBSTA;;GET I/O ERROR CODE GRETUNX;(FGREAT$CURFCB2 FRESBUF;;FREE SECTOR BUFFER<GREATQ>;;SET ALL OKF HRETURNdX;T ENTRY STACKB;;AND RESTOREDX;SAVE #D9:FMSRAM.M65AMISC STORAGEA @ORG X;%X; MISC NON ZERO PAGE STORAGE AREAX;$%MAXVTOC ;; MXIMUM VTOC INDEX.!RETRY ;;I/O RETRY COUNTER8"ENTSTK ;;ENTRY STACK LEVELB DHOLES ;;DIR HOLE SECTORLDHOLEH ;;DIR HOLE DISPLV DHFNUM ;DIR HOLE FILE NO`!CDIRD ;;CURRENT DIR DISPLj"CDIRS ;;CURRENT DIR SECTORtFNUM ;;FILE NUMBER~'SVDBYT ;;SAVED OUTPUT DATA BYTE#EXTSW ;; flag for FN DecodeTEMP3 ;;TEMP3TEM4 H;;TEMP4,WILDFLAG ;;WILD CARD CHECK IN RENAME5DIRCPTR ;;CURRENT CHAR IN FORMATTED DIR ENTRYX;'SIOCM ;; saves value of DCBCMDBURTYP ;;BURST I/O TYPEX;DRVTBL ;;DRIVE TABLESECTBL ;;DBUFAL ;;VTOCH BUFFER DBUFAH ;;PTR FOR DRIVE N 7SBUFSTART ;; ADDRESS OF START OF SECTOR BUFFERSFNAME  ;;FILE NAM(NEWNAME  ;;USED BY RENAME ROUTINE(>BURSTFLAG ;; FLAG TO INDICATE BURST I/O WAS SUCCESSFUL2X;<(FIXEDBITS ;; saves Hextended vtocFAFILE CONTROL BLOCKSAPX;ZX; FILE CONTROL BLOCKd-X; ONE FILE CONTROL BLOCK IS USED FOR EACHnX; OPEN FILE. THE RELATIVE FCB USEDx$X; RELATES DIRECTLY TO THE IOCB #+X; THAT OPENED THE FILE. THUS THERE ARE'X; 8 FBS. THE FCBH ARE (CONVIENTLY)'X; THE SAME SIZE AS IOCBS. EACH FCB+X; CONTAINS ALL THE INFORMATION REQUIRED%X; TO CONTOL THE PROCESSING ON ANX; OPEN FILEX; @ORG X;FCB&FCBFNO ;;FILE # LEFT JUSTIFIEDFCBOTC ;;OEN TYPE CODE#DFDOUT;;FILE OPEN FOR OUTPUTHDFDLOC ;ENTRY LOCKEDR0DFDNLD;;FILE HAS NEW TYPE SECTOR LEN BYTE\6DFDEXT;; "EXTENDED" FILE (INVISIBLE TO DOS 2.0SfX;pX;AVOLUME DIRECTORYAX;X; DISHK VOLUME DIRECTORY/X; THE VOLUME DIRECTORY OCCUPIES THE CENTRAL*X; VOLUME SECTOR. TE VOLUME DIRECTORY(X; CONTAINS INFORMATION PERTAINING TO!X; THE ENTIRE DISKETTE VOLUME.X;&X; THE LABELS BELOW, MAP HE VOLUMEX; DIRECTORY SECTOR.X;H-DVDTCD;;VOLUME DIRECTORY TYEP CODE )1)X; X; USED TO DELINATE MAJOR (1) X;FMS SYSTEM FORMAT CHANGES X; $DVDMSN;;MAX SECTOR NUMBER (1)$ (DVDNSA;; cnt of sectors available. X;8 DVDWRQ;WRITE REQUIREDB DVDSMP ;;SECTOR MAP SHTARTL X;V 2DVDRTOPDVDSMP ;; top of RAMDISK vtoc` 2DVDVTOPDVDSMPЂ ;; top of regular vtocj 0DVDETOPDVDSMP ;; top of ext'd vtoct 3DVDAUXDVDETOP;; aux cntr of sectors availabl~ X; (DVD2.5;; size of version 2.5 vtocH (DVD2.0;; size of version 2.0 vtoc X; 7EVOFFSETDVD2.5DVD2.0;; diference in VTOC sizes X; "X; EACH BIT REPRESENTS A SECTOR &X; IF THE BIT IS ON THEN THE SECTOR $X; IS FREE AND AVAILABLE IF THE "X; BIT IS OFF, THE SECTOR IS IN 'X; IUSE OR BAD. THE MOST SIGNIFICANT +X; BIT OF THE FIRST BYTE IS SECTOR ZERO.diference in VTOC sizes X; "X; EACH BIT REPRESENTS A SECTOR &X; IF THE BIT IS ON THEN THE SECTOR $X; IS FREE AND AVAILABLE IF THE "X; BIT IS OFF, THE SECTOR IS IN 'X; HL EI=EF D2:FMSEQU.M65X; .ERROR "D2:FMSBOOT.M65">D2:FMSBOOT.M65X; .ERROR "D2:FMSBSIO.M65">D2:FMSBSIO.M65X; .ERROR "D2:FMSSTAT.M65"M>D2:FMSSTAT.M65X; .ERROR "D2:FMSINIT.M65">D2:FMSINIT.M65X; .ERROR "D2:FMSOPEN.M65">D2:FMSOPEN.M65X; .ERROR "D2:FMSBYTE.M65">D2:FMSBYTE.M65X; .ERROR "D2:FMSCLOSE.M65">D2:FMSCLOSE.M65X; .ERROR "D2:FMSFMT.M65"M>D2:FMSFMT.M65X; .ERROR "D2:FMSXIO.M65">D2:FMSXIO.M65 X; .ERROR "D2:FMSDIR.M65"!>D2:FMSDIR.M65"X; .EROR "D2:FMSFNAME.M65"#>D2:FMSFNAME.M65$X; .ERROR "D2:FMSSRCH.M65"%>D2:FMSSRCH.M65&X; .ERROR "D2:FMSRWSEC.M65"'>D2:MFMSRWSEC.M65(X; .ERROR "D2:FMSVTOC.M65")>D2:FMSVTOC.M65*X; .ERROR "D2:FMSALLOC.M65"+>D2:FMSALLOC.M65,X .ERROR "D2:FMSSETUP.M65"->D2:FMSSETUP.M65.X; .ERROR "D2:FMSDOS.M65"/>D2:FMSDOS.M650X; .ERROR "D2:FMSEXIT.M651>D2:MFMSEXIT.M652X; .ERROR "D2:FMSBANK.M65"3>D2:FMSBANK.M654X; .ERROR "D2:FMSRAM.M65"5>D2:FMSRAM.M656X; .ERROR "D2:FMSRAMIO.M65"7>D2:FMSRAMIO.M658X; .ERROR "D2:FMSEND.M65"9>D2:FMSEND.M65:50X; .ERROR "D2:FMSEXIT.M651>D2:LX;SAVE #D9:FMSSTAT.M65 ASTATUSAX; X; DFMSTA - GET A FILE STATUSX; DFMSTA$ SETUP;; SETUP.2 NEEDFILE;;decode, find, and insist it exists8 TSTLOCK;;TEST LOCKEDB$!GREAT;;FILE EXISTS AND UNLOCKEDLX;"D2:FMSEXIT.M651>D2:P EI=EF D2:FMSEQU.M65 AD2:FMSBOO.M65A>D2:FMSBOOT.M65 AD2:FMSBSIO.M65A>D2:FMSBSIO.M65 AD2:FMSSTAT.M65A>D2:FMSSTAT.M65 AD2:FMSINIT.U65A>D2:FMSINIT.M65 AD2:FMSOPEN.M65A>D2:FMSOPEN.M65 AD2:FMSBYTE.M65A>D2:FMSBYTE.M65 AD2:FMSCLOSE.M5A>D2:FMSCLOSE.M65 AD2:FMSFMT.M65A>D2:FMSFMT.M65 AD2:FMSXIO.M65A>D2:FMSXIO.M65  AD2:FMSDIR.M65A!>DU 2:FMSDIR.M65" AD2:FMSFNAME.M65A#>D2:FMSFNAME.M65$ AD2:FMSSRCH.M65A%>D2:FMSSRCH.M65& AD2:FMSRWSEC.M65A'>D2:FMSRWSEC.M65( AD2:FMSVTOC.M65A)>D2:FMSVTOC.M65* AD2:FMSALLOC.M65A+>D2:FMSALLOC.M65, AD2:FMSSETUP.M65A->D2U :FMSSETUP.M65. AD2:FMSDOS.M65A/>D2:FMSDOS.M650 AD2:FMSEXIT.M65A1>D2:FMSEXIT.M652 AD2:FMSBANK.M65A3D2:FMSBANK.M654 AD2:FMSRAM.M65A5>D2:FMSRAM.M656 AD2:FMSRAMIO.M65A7>D2:FMSRAMIO.M658 AD2:FMSEND.M65A9>D:FMSEND.MU 65:TUP.M65. AD2:FMSDOS.M65A/>D2:FMSDOS.M650 AD2:FMSEXIT.M65A1>D2:FMSEXIT.M652 AD2:FMSBANK.M65A3D2:FMSBANK.M654 AD2:FMSRAM.M65A5>D2:FMSRAM.M656 AD2:FMSRAMIO.M65A7>D2:FMSRAMIO.M658 AD2:FMSEND.M65A9>D:FMSEND.MT)5ANXcoyʄք !-&;GAS]hs~̄؄S*4?JU`kvY  DŽ݄҄ %1=IUhSNaSNmSNySNSNsSN SNSNcʄք)5 AMx[gs &5yńY҄܄҄ Ņ 4$0;FQ^jwĄχچ򅅇)8 )  -8DP\hr~8~XYԄ脇:ڄB.$/:)/UXc!nyyocc܅ͅ$ڄB8P ڄB-,hYhP8S_k-w8DDŽӄ    )  6  A K V a A V m V y ^  K m  Y ̈́ F      * 9 E 9 Q  ]0  a h s ~ h  ք ڄ ~  * և E    ! + 6 6 !A Q M Y dY  p | ̈́ Q M p Ѕ < M  E E 肄 hhSN    V  " . 8 D N .y .  Y p p̈́  D eć  N p q }Y q    " 턇& 8 a "a m a m Ă " 󅄺    #  " / } Շ   e / E 9 E 9 " 9 C 9ͅ  V Op [ g t  Yy   9 E 9 E      A  O  [ p O O t Ї Ą Є ܅s   "/ <GT`  kxwYAM҄UknχA C $ xkAk (Ŝk>kŅ W>W> w{    A  " + | Y + " | ! A: F/S s |^^ A:S * s i t  ՄSŅ < 8G  A:  ܄j T pY  p  p E E % "00%9w ‚0 ̈́E; ` ͅ ) 6i{u{Ŧ҇"ͅ # e  :ͅ>Y  ҄ ҇ $  ҇ Һ     ^ & &x腄yZnynn>n + +܄F   6  ք:  Y  ' ' :? +I :I? S ÄS :܄_ 6 ˅ 8 p{ p  Մ{ * g G҄ E ;҇ E   C Y Є Y E E ;Y "  E E p 8 E EȄ;  E E ܇ " Ąs   $ $ A$ /iSU5ywU>YQ^Sjv i0 S^jvQjŇ/$  jQ>Ň ^ww( v>ww(Wwu{ŅY *W>ŇlŦ܇W E E E E E wu{ SŇ E . U_k@>Lv nL҅@ ^LL҇ޅY !̈́~))އ  ! " hh 8 | ܄  C ~   C  C օ2.ڄBY$> Ä ք τ n&DŽ҄y _k + ڄBބ   ܄ p " ĄL E 9; ЄGG A V y d Y  S _tY  'k wuSWWwWW{(X  ".ʅrڄB y d Y  S _tXX;SAVE #D9:FMSBANK.M65X;X; RAMDISKX;-X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$X;.$X; RAMSYNC -- ensue RAMIO occurs8*X; only with interrupts disabled andBX; during VBLANK intervalLX;V RAMSYNC`%>j+'CRITIC;; ]!ell VBLANK this is critical!t.$FASTRAM;; special: ignore sync w/ vblank?~G:FASTER;; yesX; $CLOCKLSB :SYNC!(LOCKLSB;; got a VBLANK yet?F:SYNC;; noX; :FASTER 'NMIEN;; disable VBI and DLI=;; and disable IRQ'sX;X;fal]"l thru to SETBANK...we#X; didn't disturb A-register!X; =X; SETBANK -- subroutine to set PIA to proper RAMDISK bakX;$X; enter: A-reg has 0,1,2,3 or 4(X;2 SETBANK<T?F&T?;; get bank number to proper bitsP'PZTEMP2;; and hold hem fo]#r a nonceZ'QPIABPORT;; the memory control bitsd#M>;; zero out bits PB2,PB3,PB4n'LZTEMP2;; then include our new itsx&PPIABPORT;; and reconfigure memory:X;SETBANK<T?F&T?;; get bank number to proper bitsP'PZTEMP2;; and hold hem fo\X;SAVE #D9:FMSRAMIO.M653A Simulated Sector I/O to RAMDISK (130XE)AX;!RAMDISK;; only if asked for!X;;$/X; first, some equates unique to RAMDISK I/O.X;8 ZSECPTR2;; share with SIO!B0ZRAMPTRZTEMP1;; share with error a%xit ptr!LX;V"MAINMEMORY;; per Atari spec`X;jX;tX; do RAMDISK sector I/O!~X; RAMIO QDCBSEC PZTEMP1;; ust be preserved!6;; save read/write flag+QDCBSEC;; high byte of sector number/X; (ramdisk sector # is 1 through 11,a& $1FF)X;+TZTEMP1;; 128 sectors=16K bytes, a bankU?;; so A has bank numberX; (safety check)(R>;; A must ave a value of 0 to 3!D:SECOK;; phew!8;; clean up stack .%>E.NAK;; "disk" didn't like sector number"H:RAMRTS;; rturn wa'ith boo-booX;( :SECOK2, RAMSYNC;; synchronize with VBLANK, etc.<;(also sets up bank select)F%QZTEMP1;; becuse of ASL above...P.;...A has sector remainder (0-127) times 2Z;;; this is sneaky:dW?;; high bit of A is setn,V?;; A01xx xxxxa(, where xxxxxx is senum/2x6PZSECPTR;; forces address to $4000-$7FFF range!Q>W?;; A gets $00 or $80'PZSECPTR;; neat? a perfect pointer+X; address of RAMDISK "sector" is set up QDCBBUF PZRAMPTRQDCBBUF/PZRAMPR;; set ua)p pointer to data bufferX;%>;; 128 bytes in a sector8;; read or write?D:READRAM;; read request;X; write sector to RAMDISKX; :WRITERAM""Q@ZRAMPTR7;; move 128 bytes...,P@ZSECPTR7;; ...to RAMDISK61@I:WRTERAMJG:RAMJa*N;; all bytes writtenTX;^X; read sector from RAMDISKhX;r :READRAM|Q@ZSECPTR7P@ZRAMPTR7;; move 28 bytes1 I:READRAMX;X; clean up RAMDISK I/OX; :RAMJN9Q>MAINMEMORY;; deselect RAMDISK, select normal meory SETBANK;; a+thuslyX;X; reenable interrupts, etc.X;%>#'NMIEN;; enable VBI's and DLI's%>$'CRITI;; no longer critical I/O&.;; and IRQ's are now legal0$3;; now Y=1...a good return value:X;D :RAMRTSN:Xct normal meory SETBANK;; `X;SAVE #D9:FMSEND.M65AEND OF FMSAX; ENDFMS X;)X; space for who knows what, including$X; MINIDUP if eeded.X;8 @ORG @BX; legal0$3;; now Y=1...a good return value:X;D :RAMRTSN:Xct normal meory SETBANK;; d@_LBL@"#$$c(c(c(c(c(KD # <QAD8i.i/LGBLELEL+DL>ELF,^`LDLBLBLBLBLCLCL7FLCLL$CL*C? &Gr@? HR RF D0$ɂ F= r@ ELRB BLRB 3D ,F~ iE pH VC 6Eɛ,/H FLGhA[ Bբ BLB8A LHLH`Ɵ` Di0 D D` F`LGL0F eHLDH ZHLOH 6EƟɛ,/`Ġ (` B B sC LR B sC0` D800  ţ` B @C0 ~ iE` 6EɛA+-H Dh+ oFLC }HLCƟ D 6E+-Ɵi1` Cв CL!D 0Cii` C` F 0C C` DLHr@ pHd@օ@ B @C0*ŧ&~ Ɵ iELZDĦ iELZD BLZDHh` 0CLG` 6E. FƟ@ 6EX D DeeLDƟ D` L@C Bi2$ G` F wC Ɵ* wC!  GeiL EƟ` D ` ` ED H Ch`LRFHHH BLRBCɛB ɀ.H Bh LGBB BB ( BƵhhh`LG6GHE G. i3iEh`}~ gEɛ iE`=2(.)* gE 7F 7F  7FHJJJJ @Fh)ii@LiE$0 HH iE`qq`LiEB@ BLGLHŁŀ`FLG=ASXZ`}LiE66&&8HYei4hYeƤհyy` gE RF RF R BLRBc$d%BBB  @@bA @ @ @ @ eH膬 F RFG iELB Copyright 1982 McStuff Co.ш`&&66 Hi5 oFhƤ襎`LFHH`X@ #H`@ @@A@@`6;@`6@`6;@`6@`Hr@h`8񐕀񐕁`a{)`ɀɶ ii?`> ERROR!BG/65 Version 2.0COMMANi6DIMMMEDIATE CMDPROTECTIONPARAMREGISTERBREAKPOINTPRINTERSYNTAX*** ERROR - MNEMONICOPERANDANGETOO MANY LABEL REFSUNDEFINED - I/O ERROR - = USER RUNBREAK! A X Y SP NV_BDIZC PC INSTRADANASBCBCӂEBIBMBNBPBRBVBVCLCi7LCLCLCMCPCPDEDEDEEOINININJMJSLDLDLDLSNOORPHPHPLPLRORORTRTSBSESESESTSTSTTATATSTXTXTY**a! 0PpXʈAL BHh("b@`8x    i8    Jx x x x d B x x x x x x x Mx x x x x x x f g x x x x x x lx x x x ix x x x c ` x x x x x x Ox xx x jx x x x e h x i9 x x x x x nx x x x x x x x Vx ux x x x x wx x x x  x x s rx x x x x Ptx x x x x Z Ux x x x x x Nx x x x x x x Y ai:x x x x x x mx x x x 5MMMNNNNNO=O[OOPPPPPP9M_QbQQQRRRLG D0rp OE @C0hf ,F F LF F C @C0F FLWM_ ƂƃLqM $ @ CLM OE惥ɛТ` D` C VC FB i;H Hь F bE )F "F bE 7F GLM` C Dii VC Fg F H )FƤ G 奤 ,F ,F ,FƤ H EƤ G LN` R pH Sdɛ R?LBi< C D VC F G`LS C D oF F }HL0F gE8OVASLR S0 iE VCL'OLRD:*.* R Dɛ DH %Shɛ RLRB C gEH  Fi0Hh iELO` gE C 0C VCFqH 0ChhH(DŋNŊi=F 6E*&Ɵ C H拱ň恥ТLO "FLO 0C` C~x }H扢Ł'ŀ oFƄƅ VC HH Fh oF FƈƉ`LGB`B` 0C Di>SƫPƬ`LG@ @ Pl l R -S D R SZ SS S򥀍AAeeee SH Fh G S0LRLRLT C ZH OH>@?@QHzHl<@ eHLDH RF@ )FQ0-A1 iE ,FAA "F ,FAi?A -ULgE @W -S 6E: DAB ƟH ChH Rh %S %S %S H %S GLRLG D @C0PN R ,FR iE F B @C053 $ iE OE @C0$HR@Ahɛ LQR GLGR`AXYSPFLTL8XH 6E#7 0C Di@VA#VAh S0` RF bO R BLRBLG ZRLVZVTAU S0`XYբ S0`H 6E'"hƟ`hhh'   @ D&   D DW@ YLRmiAm   Ƴƴ` #H膖膄 T@Ɵ CAA TɂLG C TR D Rۆ T C TI T D愢 RF@@@eTLW0@Ƅƅ VLOT RFLQ 0ChhLJTLD D=LT` DSƚƟ DiB VC V QƄƅ` C C VC F ,F ,FHH -Uhh ,椥 W H )FƱ쥄 F` VH)? I0IH) iEh ,F ,Fh lU{UHzUH`   UUUUUUUUjUjUUUUU VL0FXYH UhLV VL7FXYiCH V 7FLU F V 7FX VLF F V 7F FYLV# iELU WL0F F ULF HL7F V V` HJ&& oFȱ`،A@h@h)Ah8AhAA@@@@X eH DH #Hl@H, iEhLiE恢 H`@ @#@@ FAiDцц`LGAA V @)? vLW)LW*LW Wei@@ՠTLWH WhH Wh) TW-AL WTW-A壟@@LW@L W  VGW V H HL WLVA膂膂L WiEA膂膂L W VHhee悂`JJJJJJ`@@ V ZH OH@@@=VAAHAHAH@@A@ D0CA OE: gEPA F ,F ,F C @C ED XLUX j]` 6E/+(Ɵ X Y Y \% :]` \iFLX \ +]LX  H RFh RF` \AL9ȱ02:.)ȱ # AAAA`AŴAAH) \7H惢 FhLY惢 F FhAС Z ,FA iET iE ,F 0FhL0YiG \7I)ђ ȽI0轱I轱I*ܱ ɛ` LX g[eJ JJŲ򦱽J93 J 9ZH8ZH`mZaZaZ[Z[ZaZ[Z^Z[Z^ZdZ[ZsZZ` LX Z ZLZ Z ZLZ G Z Z9 Z Z+ `iH聾ᥲ ZHZH`Z[[,[6[6[:[>B[H[P[Za[ 2] \!LXJ &] +] +]LTZJ ܩ &]L[ 2]LTZ &]LTZJL/[ L [ F \ 5\ \ }\`H 6EL D0 :)L[L/\ iIAAaZAA A0< XLRBiAAA慦J慩L)\H 6E# \ h`h`H [&hH 6E.X0*:A"GƟ C \ \L)\L/\H 6E(5 >\0& D) iJD) \ L)\L/\XY, ȊђȄ` >\` \` 6EƟɛ` }HƄƅƄƅ0 0 `0`]J`]JL+]+ ,F F膂 )Fƭ` A6A/ RFL iE 0 iE ,F RF? iE D0iK OE #Y津 `iLiMhfi@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`l  R@W!( L(1   Y I`  d  Ld M * @ d $ %mO CC$$)%1 Udߥ$9%: !0 S$% DD˙`e  }J)Lr J  ((  p L ()   JL= ( L qmP A    IB JC;? D W  LL  a ` W )L A!  ߰")-݆ p" $G@mQLL 08`Q")<2Q0 -G$Ș݆ UL# ; p8(()(0ʥ)NQ`$GȘ݆LU )L ݆ L GȘ ݆L L * )W>Z   HH)H p h mR hyhy D L> L JJ    ! LA*`+ & BF7'  M HN H` 8 Z  \LdJJ!"! GFE@F (!LEE mS!E^ ^ E E7EȩEdE/EȩE ' 8  D.L9 4 }  ;F d  ;?F7F? ( .   Z D LL d  . D  mTL    p  E` , d)  D L) 0BM݊L݉ 5 q ML  N݆ L NLMLr m [ TEqEHȱEqEh 0Gȹ G HLmUL GɛL  LFREE SECTORS G) *Gȩ GȽG GȌ*jj >G C8jJ3j2CD( C202C ԠBX` ` _} ; $ %  pLl`lmBFMSEQU M65B "FMSBOOT M65B+FMSBSIO M65B 1FMSINIT M65B >FMSOPEN M65B KFMSBYTE M65BXFMSCLOSEM65B_FMSXIO M65BqFMSFMT M65BFMSDIR M65BFMSFNAMEM65B FMSSRCH M65B FMSRWSECM65BFMSVTOC M65BFMSALLOCM65BFMSSETUPM65BFMSDOS M65BFMSEXIT M65BFMSRAM M65BFMS M65BFMSSTAT M65BFMSTEST M65B FMS REFB FMSBANK M65B$FMSRAMIOM65B,FMSEND M65B!-BUG4000 COMB NFMS OBJ