@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr d M * @  $ % CC$$)%1 Udߥ$9%: !0 S$%} DD˙`  }J)Lr J  ((  p L ()   J}L= ( L 0q A    IB JC;? D W } LL  ` W )LA!  ߰")-݆ p" } $G@LL 08`Q")<2Q0 -G$Ș݆ UL# ; p8(()(0ʥ)NQ` }$GȘ݆LU )L ݆ L GȘ ݆LL )W>Z   HH)H }p h  hyhy D L> L JJ    ! LA*` BF }7'8  M HN H` 8 Z  \LdJJ!"! GFE@F (!L }EE !E^ ^ E E7EȩEdE/EȩE  D } .L }  ;F d  ;?F7F? ( .   Z D LL d } . D  L    p  E` , d)  D L) 0BM݊L݉} ML  N݆ L NLML [ TEqEHȱEqEh 0Gȹ G} HLL GɛL  LFREE SECTORS G) *Gȩ GȽG GȌ*jj >G} C8jJ3j2CD( C202C ԠBX` N 1? l LlD:RAMDISK}.COMLu L1 L ;LHL  T`  `1  ɐ     `TU  } L ? .  t`GBJ ~DEHI B V0dV!}QDEHI VF9 ,0 ,0 s0hhL  L` H hDHEh"}DEL8HI4 0 HI,0 0  9 .G VLO#},0 L4*IJ`llD1:AUTORUN.SYSNEED MEM.SAV TO LOAD THIS FILE.D1:MEM.SAV J y08 B|DEHI$} V0 0`B;DEL`?<0LV`@ʆ v s? F0Ξ05: [ BDEHI%} VY8 B V  @  /DE `E:D1:DUP.SYSERROR-SAVING USER MEMORY ON DISKTYPE Y TO &}STILL RUN DOS B;DE J  (` 9 V⪍ ઍ  -'}LLu ÝDEHILV 9 .l 9 .l  `` s$B BH(}I|DE V BLV nB,DE JLV B V BLVDEIʩ BꭝLu  } 3E:}DISK OPERATING SYSTEM II VERSION COPYRIGHT 1984 ATARI CORP.A. DISK DIRECTORY I. FORMAT DISKB. RUN CARTRIDG*}E J. DUPLICATE DISKC. COPY FILE K. BINARY SAVED. DELETE FILE(S) L. BINARY LOADE. RENAME FILE M. RUN AT ADDRES+}SF. LOCK FILE N. CREATE MEM.SAVG. UNLOCK FILE O. DUPLICATE FILEH. WRITE DOS FILES P. FORMAT SINGLEL !N',}#"&))9(&*)/h)''-&؆莟R'S  vL/ˢ L }Insert DOS 2.0s, type Y Λx -}DEfHI 1莏#q! @ y0ɛ8A0,' ȅ 1 1ild! 1L!NO SUCH ITEMSELECT.} ITEM OR FOR MENU! 0 .z:*{}.|{ 1 0 0JB 18L%|DL/}%DIRECTORY--SEARCH SPEC,LIST FILE?[# 0 0 &|D3" 1L!NOT A DISK FILEN !B 1L!E# 1 !BD0}ED:}:1BJ|DE 1DEBHI 1 h0ߢ 0.1}  0?詛 1 y0YЛ 1 ;#L" ;#L! BL1TYPE "Y" TO DELETE...DELETE FILE SPEC2}COPY--FROM, TO?OPTION NOT ALLOWED736 FREE SECTORS COPYING---D1:DIRECK.COMl# 0|D .L/%#3}##JB|DE 1BHID#E 1#0: B 1L!#͑### B 1#c$0SY4}S1}:## # # .#Ƚ# # 𩛙## 1,#PD#ELJ- <.BJD#E 5}1 1HH 0hh|DL%1}:̳# L% #D#EL% 1 0 . .0O% 1L!WILD CARDS NOT A6}LLOWED IN DESTINATION 0 <.|K}N 2 FORMAT. t* 5) 1L!`) 0NΞ 0 L1) 1 L!BAD LOAD FILELOAD FROM WHAT FILE?) 0 ?}0#B 1L!WHAT FILE TO LOCK?) 0 0$B 1L!WHAT FILE TO UNLOCK?DUP DISK-SOURCE,DEST DRIVES?TYPE "Y" IF OK TO US@}E PROGRAM AREACAUTION: A "Y" INVALIDATES MEM.SAV.FE! +L1   `*  70 2 2A} 0.* 1 y0 0)INSERT BOTH DISKS, TYPE RETURN^, 1 y038逍 N, 1L! ,B}C, t*  Lx+, 0 ^, 1 y0 , ,0,0 ,L+ ,I0 ,Vǭ0C}Ξ, 0 }, 1 y0C,ШC, 0K'!" H H 'h h Lx+!EF 5L1L!D,I,HhD}` NOT ENOUGH ROOMINSERT SOURCE DISK,TYPE RETURNINSERT DESTINATION DISK,TYPE RETURNE}`  `8 rL1`-* 1P* 1 y0Y`hhL!NAME OF FILE TO MOVE?- 0 0|DL% <.F},^ 1 70 0 .@L# .BJ 1  DEHIB V L1 ,} 1 70,L.  G}JB|,#P#DE 1 HI BDEHHII 1 B 1 ,^ 1 70,0La- B V,#PH},^ 1 70 0L#L!-* 1P* 1 y0Yj383}mm ݭI}}`8}``|* ? ɛ,`|:-)| / 1L!`DESTINATION CANT BE DOJ}S.SYS0 0H{ 24Δ 28/L!/) 2 Π 2 0 ξK}hAΞB,0 J 1 BDEHI,HÝDE 1HIHIDELSAVE-GIVE L}FILE,START,END(,INIT,RUN)O S0 1`BDEPHI V` S0H 1 L!M}0 0 1L~0`PLEASE TYPE 1 LETTER,0`hhL! 70 1L0L<1 ,;ɛ7,"ɛ:ݦ1ݥN}A"D|ݤD|ȩ:|ȩ|ɛ,,(/+.ީ1 1,ɛ`轤{NAMEO} TOO LONG B VL!` L1I H1EΝDL1|mDiE` V0`8d/8 i:222 1 LP}!ERROR- 138ɛ+,' 20*.. өr2 1``2TOO MANY DIGITSINVALID HEXAQ}DECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8uR} ECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8uEF,=x;chars/line for compressed printing= ;suppress form feed,=P;lines/page for compressed printinT}g.ARECONSTRUCTION of DOS 2.5 with commentsA$X* Rob Bishoff ---------- 31/3/86$$X* 16/7/86 format-routine checked.X* U}final check-up, june 19878X* version 21/6/87B&X* *** checked with object code ***LX*V'X* main changed after first versiV}on:`X* ERRNO --> CURFCBjX* SVD3 --> TEMP4tX* EXTRA --> DRIVE8~X* EXT2 --> D8INITX* EXT3 --> CHKD25X* EXT4 -W}-> XRDVTX* EXT5 --> XWTVTX* ANDPB --> XBANKX* APB1 --> SBANKX* SPARE1/2 --> SABUFL/HX* SPARE --> FCBSPRX*X} ERAPO --> ERRORX* SPARE5 --> BURFLG X* ERROR --> PERROR (in DUP)X* DSKUTL --> RAMLOX*X* link parts of FMS souY}rce X*>D:RECDOS1.M65>D:RECDOS2.M65(>D:RECDOS3.M652>D:RECDOS4.M65<X*FX* link resident part of DUPPX*Z}Z>D:RECDUP.M65dX*n>D:RECDOS2.M65(>D:RECDOS3.M652>D:RECDOS4.M65<X*FX* link resident part of DUPPX*[}>D:RECDOS2.M65(>D:RECDOS3.M652>D:RECDOS4.M65<X*FX* link resident part of DUPPX*$X* RECDOS1.M65Aauthor noticeAX*AX* Atari FMS was originally written in the second half of 1978=X* by Paul ]}Laughton, assisted by Paul and Kathleen O'Brien8X* It was updated (19 Aug. 1980) by Paul Laughton for$X* the Atari DOS 2. ^}0S..7X* The DOS 2.5 version (adapted for enhanced density86X* by Bill Wilkinson???) was released in late 1984.BX*L8X* Th _}is is a reconstructed & commented version of theV+X* enhanced density DOS.SYS source file.`X*j9X* A description of Atari `}DOS is published by COMPUTE!tX* as INSIDE ATARI DOS.~X*X* system equatesX*'ZICB ;zero page i/o control block a}/FMSZPGC;DOS zero page registers (7 bytes)#STAK;stack loc for put byte4DSKTIMF;addr of o.s. worst case disk t b}ime outILMADR;pointer to bottom of free memory (called MEMLO by the o.s.)0DVSTAT;device status registers (4 byt c}es)#DCBORG;device control block7DEVTAB;device table (called HATABS by the o.s.)"IOCBORG@;i/o control bloc d}ksFMSORG;start of DOS?OSBTM5;hi byte of addr less than (Rev.1/2) o.s.space GDHADRS;device handler vect e}or address (called DSKINV by the o.s.)!EOL;Atari end of line charLMASK;link mask((TIMOUT;time out value of f}15 secs.2X*<%X* more equates (from o.s. source)FX*PRTCLOK;realtime clockZ6BUFRLO2;pointer to data buffer, used g} for ramdiskd BUFRHI3nCRITICB;critical i/o flagx5PORTB;memory management register (XL/XE only)+NMIEN;no h}n-maskable interrupt enable+SIOVY;serial i/o utility entry point AIOCBA IOCBORGX*IX* IOCB - i/o control bl i}ock. There are 8 i/o control blocks, 1 iocb is6X* required for each currently open device or file.X*IOCBICHID  j};device handlerICDNO ;device numberICCOM ;i/o commandICSTA ;i/o statusICBAL  ICBAH ; k}buffer addr (L,H)ICPUT ;put char DH addr"ICBLL ,ICBLH ;buffer len (L,H)6ICAUX1 ;aux 1@ ;au l}x 2 (unused)JICAUX3 ;aux 3TICAUX4 ;aux 4^ICAUX5 ;aux 5h ;aux 6 (unused)rICLEN IOCB|' ICL m}EN;space for 7 more iocb'sX*X* zero page iocb labelsX*ICDNOZICDNOIOCBZICB&ICBLLZICBLLIOCBZICB; n}buff lenICBLHZICBLHIOCBZICB'ICBALZICBALIOCBZICB;buff addrICBAHZICBAHIOCBZICBICCOMZICCOMI o}OCBZICBICAX1ZICAUX1IOCBZICB ADCBA DCBORGX*JX* DCB - data control block. The DCB is an iocb like cont p}rol block usedGX* to interface the disk file management system to the disk handler.X*&DCBSBI ;serial bus id0DC q}BDRV ;disk drive #:DCBCMD ;commandDDCBSTA ;i/o statusN%DCBBUF ;i/o buffer addr (L,H)XDCBTO ;ti r}me out countbDCBCNT ;i/o byte countl!DCBSEC ;i/o sector numbervX*X* DCBCMD value equatesX*DCBCRS R; s}read sectorDCBCWS P;put sectorDCBCST S;status request$DCBCFS !;format diskette single&DCBCFE ";format diske t}tte enhancedX*X* ** special note:IX* DCBCWS may be changed to 'W ($57) if desired to have disk perform aFX* verifyi u}ng read after each write. Disk write ('W) operations will-X* take longer, but will be more reliable.X*X* zero page ce v}lls X* FMSZPG ZBUFP ;buffer pointer*&ZDRVA ;zero page drive pointer4%ZSBA ;zero pg sector buff ptr> w}'CURFCB ;current FCB (iocb also)HABOOT RECORDARX*\HX* The following bytes are stored on disk sector 1. They compr x}ise thefX* boot load record.pX*z FMSORG BFLG ;boot flag unused = 00BRCNT ;no. consective boot records to y} read!BLDADR FMSORG;boot load addrBINTADR DUPINIT;init addr%BCONT!XBCONT;boot read cont. pt.X*JX* The follo z}wing bytes are set by the console processor. They are actedFX* upon during FMS init only. They are part of the boot record {}thus0X* defining the default initialization parms.X*)SABYTE ;max # concurrent open filesDRVBYT ;drive bits 0 |}SAFBFW ;storage allocation dir sw (unused) .SASA ENDFMS;storage allocation start addr X*$ GX* The following code read }}s the FMS and console processor (DOS) from. X* the DOS.SYS file.8 X*B @DFSFLG ;DOS flag (00 no DOS file, 01 128 byte sec ~}tor disk)L *DFLINK ;DOS file start sector numberV "BLDISP };displ to sector link` -DFLADR DFMSDH;addr start of DOS.SYS } filej X*t XBCONT%DFSFLG;get DOS flag~ FBFAIL;br if no DOS.SYS file # MVSA;move load addr to pointer QDFLINK;ge }t 1st sector # %DFLINK #XBC1$ICBALZ;move zero page ptr &DCBBUF;to DCB $ICBAHZ &DCBBUF ,  BSIO;go read }DOS sector GBFAIL %BLDISP;point to link Q@ICBALZ7;get hi link M>LMASK;mask to link bits > 3 L@ICBALZ7( F }XBRTN;done if link = 02 Q@ICBALZ7;get low link< 5F 3P #Q@ICBALZ7;get # bytes in sectorZ 8 INCBA;go increment buff addr }(by # bytes in sector)d 7;low link to Y regn ?x A;hi link to accu !XBC1;go read next sector BFAILQ>;set for carry }set )XBRTNT?;prepare carry & Y reg for rtn ? :;back to operating system X* INCBQ> +INCBA,;incr buffer pointer }by # in accu OICBALZ PICBALZ DEXBT #ICBAHZ EXBT: X* %MVSAQDFLADR;move load start addr PICBALZ;to zero }page ptr" QDFLADR, PICBAHZ6 :@  =;filler bytesJ ASECTOR I/OAT X*^ X* BSIO - do sector i/oh 7X* on entry: Y/ }A - sector number, X - doesn't matterr )X* carry clear for read, set for write| X* !BSIOPDCBSEC;set sector hi 'DCBS }EC;sector lo %BSIORQ>DCBCRS;assume read sector %>@;and get data D:BSIO3;br if read VQ>DCBCWS;else load write secto }r (change this operand to $57 for write with verify) %>;and put data &:BSIO36;save processor status word $ICDNOZ;che }ck for drive 8 (> HDSIO1;br if not 8;restore PSW + DRIVE8;use DRIVE8 routine for drive #8 !DSIOE;exit (DSIO18 };restore processor status word PDCBCMD;set command& #Q>TIMOUT;timeout default loaded0 DSIO2PDCBTO;set time out: 'TEM }P3;save SIO cmdD Q>1;disk serial bus idN PDCBSBI;set idX Q>;set retry countb PRETRYl Q>;set i/o byte countv PDC }BCNT T?;shift accu to zero (PDCBCNT;set byte count hi to zero DSIOXQTEMP3;recall SIO cmd PDCBSTA;set SIO cmd  } SIOV;call serial i/o IDSIOE;if good i/o then rts *"RETRY;test if another retry available IDSIOX;retry the i/o $DS }IOE$CURFCB;reload current FCB C;i/o status set flags : ASTATUSA X* X* DFMSTA - get a file status X* DFMSTA }SETUP;setup 2 XSTAT;go decode file name and search for file*  TSTLOCK;test locked4 #!GREAT;file exists and unlocked>  }=;filler bytesH AFILE MANAGER ENTRY POINTAR X*\ 5X* DFMSDH - disk file management disk vector tablef .X* (entered int }o the handler address table)p X*z DFMSDH  DFMOPN;open file  DFMCLS;close file  DFMGET;get file  DFMPU }T;put byte  DFMSTA;status # DFMDDC;device dependent cmd X* -X* bit value table for FRESECT & GETSECTOR X* } "SECTAB =@= ===== :X* following byte is read, but never changed by DOS/DUP 9XBFLG ;skip delay loop in ba }nk switch routine if FF X*;insure fixed init addrX*X* set up drive info$UX* DRVTBL - 8 bytes, one for each po }ssible drive (0 = no drive, set to mark drive).RX* DBUFA(L,H) - 8 two byte entries for the drive (VTOC) buffer addr for a dr }ive8X*B#DINITQSASA;move start of allocLPICBALZ;area to ICBAL/HZV QSASA` PICBAHZj,QDRVBYT;move drive excess b }its from boott PZBUFP~$>;dr # minus 1DIAQ>;assume no drive TZBUFP;shift dr bit to carryDDIB;br if dr doesn }'t exist#%>DVDWRQ;set write required off&P@ICBALZ7;in the drive VTOC buffer,QICBALZ;move current alloc addr to DBUFA } PDBUFAL9 QICBAHZ PDBUFAH9!Q>;go incr buff alloc by $90 INCBAQ>d;indicate drive present%DIBPDRVTBL9; }set drive into table 0;dec driveIDIA;br if more to test&QICBALZ;save start of sector buffs( PSABUFL2 QICBAHZ< P }SABUFHFX*PJX* Set up sector allocation table. The sector allocation table (SECTBL)ZDX* has 8 one byte entries, one for e }ach possible 128 byte buffer.dCX* SABYTE in the boot record determines the number of entries ton-X* allocate. Non allocated } byte are minus.xX*%SABYTE;get count$>"DINXTS1;dec count of allocated'C;if plus allocate, else de allocate }PSECTBL9;set allocate byte5GDIC;if not allocated, then don't allocate buffer$ INCB;else, incr buff ptr by $80DIC2; }incr buffer #(>;if not all 8HDINXTS;do againX*AX* NOTE: The non-resident part of DUP starts at $1D7F (labeled }AX* NDOS), giving only limited room for drive & sector buffers.@X* With a gap of only $3B0 bytes between ENDFMS and NDOS on }lyAX* 3 drives (including ramdisk!) & 4 simultaneously open files@X* (or 4 drives & 2 files) are possible. Althrough DOS }itself"AX* will be fine, the DOS menu will not work properly with more,X* buffer space used.6X*@X* set low memJX*T }QICBALZ;move final addr^PLMADR;to low mem ptrh QICBAHZr PLMADR|X*X* clear FCB's to zeroX*Q>?CF }CBXPFCB83%ICFCBX;loop until all 128 clearedX*$X* set device handler table entryX*?;reset index ADI1QDEV }TAB8;find an unused FADI2R> D;or disk entry FADI23&303:)>D HADI1N+;else breakXADI2Q> D;set diskb }PDEVTAB8lQ>4DFMSDH;set FMS addrvPDEVTAB8 Q>5DFMSDHPDEVTAB8:ADI1N+;else breakXADI2Q> D;set diskb }kXADI2Q> D;set diskb dy,X* RECDOS2.M65 AOPENAX*.X* DFMOPN - file open execution entry pointX*DFMOPN SETUP;do FCB set up$ F}NDCODE;go decode file name.'QICAUX19;get aux1 (open type codes)8PFCBOTC9;put into FCBB#M>OPDIR;is this list directory?}LFOPN1;br if notV!LISTDIR;goto dir list code`"OPN1 SFDIR;go search file dirj6;stack resulttQFCBOTC9;get open ty}pe code~R>OPIN;input FDFOINR>OPOUT;output FDFOOUTR>OPINOPOUT;update FDFOUPDR>OPOUTOPAPND;append} FDFOAPN*GOERD ERROR;error: device cmd invalid ;(error # 168)X*X* DFOIN - open for inputX*DFOIN8;get s}earch flag EOPNER1;error if not found DDFOUIX*(X* DFOUPD - open for update2X*<DFOUPD8;get search flagFEOPN}ER1;br not foundP TSTLOCK;test lockZ!DFOUI DFRDSU;set up for readd!GREAT;donen OPNER1 ERROR;file not foundx ;}(error # 170)X*X* DFOAPN - open for appendX*DFOAPN8;get read statusEOPNER1;br not found%CDIRD;get file f}lagQFILDIRDFDFL18PFCBSPR9;save flag(M>DFDNLD;if old file type then error FAPOER TSTLOCK;test locked2 O}PVTOC;read VTOC (insure not write protected) GETSECTOR;get a new sector.PFCBSSN9;move sector # to link sector # Q}FCBLSN9 PFCBSSN9"!DHFOX2;continue as open,0APOER ERROR;attempt append to old type file6 ;(error # 172)@X*JX}* DFOOUT - open for outputTX*^DFOOUT8;get search flagh EDFOX1r# XDEL0;delete the file or files| %CDIRD !OPN1A}'X* make a new entry in the directory"DFOX1QDHOLES;was there a holeGOPNER2;br if no hole.PCDIRS;save hole sector a}s current dir sec% RDDIR;go read current dir sector0QDHOLED;move hole displ to current dir displ PCDIRD#QDHFNUM;m}ove hole FN to current PSFNUM OPVTOC %CDIRD$> Q> >OPN1BPFILDIRDFDPFN8;blank fill file entry for file }name3&00 IOPN1B:5X* allocate data sector, prepare & write dir entryDOPN1A$CURFCBN(Q>DFDINUDFDNLD;set dir flag} in useX PFCBSPR9b GETSECTOR;get a sectorl%CDIRD;get dir displv/PFILDIRDFDSSN8;put sector into dir rec QFCB}LSN9PFILDIRDFDSSN8BQ>DFDINUDFDOUTDFDNLD;set dir entry in use, open for outputPFILDIRDFDFL18Q>%PFIL}DIRDFDCNT8;set count = 0PFILDIRDFDCNT8$>OPN2QFNAME9;move file nameR> ?;if wild cardFOPN2A;change }to blank!PFILDIRDFDPFN8;to directory OPN2A32 (>  DOPN2  WRTDIR;go write directory*X* finish open output}/append4DHFOX2 SETFCB> WRTN6;fix up as if writeHQ>FCBFAS;set new fileR PFCBFLG9\X* was DOS file opened?f TST}DOS;if not DOSpHDHFOX3;brz#!WRTDOS;else write DOS.SYS fileDHFOX3!GREAT OPNER2 ERROR;directory full ;(error} # 169)X* setup FCBSETFCBQ>;clearPFCBFLG9;flag"QSFNUM;move file number to FCBT?T? PFCBFNO9Q>}PFCBDLN9;data lengthPFCBCNT9;set count = 0 PFCBCNT9 : X* set up for read$ DFRDSU SETFCB;setup FCB. $%CDIRD};move start sector to link8 QDFDFL1FILDIR8B PFCBSPR9;get file flagL M>DFDNLD;set new sector flagV PFCBSLT9` &QFILD}IRDFDSSN8;move start sectorj PFCBLSN9t QFILDIRDFDSSN8~ PFCBLSN9 "!RDNSO;read 1st sector and rtn APUT BY}TEA X* X* DFMPUT - put a file byte X* DFMPUTPSVDBYT QICDNO9 PICDNOZ SETUP .%ENTSTK;chk to see if entry }wasn't for CIO -QSTAK8;if hi byte rts is not in o.s. addr &R>OSBTM;space then a non-CIO entry EFRMCIO;br if from CIO })Q>;else prevent from doing burst i/o PICCOMZ FRMCIOQFCBOTC9;if not open( M>OPOUT;output2 FPUTER;error< %FCBDL}N9;get data lengthF CP RFCBMLN9;if sector not fullZ DPUT1;then brd " WRTNXS;else write full sectorn EPEOF;br if EOFx } WTBUR;test burst %> EPUT1;br if not burst Q@ICBALZ7;put next byte PSVDBYT;after burst area PUT1#FCBDLN9;i}nc data len QSVDBYT;get data byte $P@ZSBA7;and put in sector buffer %Q>FCBFSM;indicate sector modified LFCBFLG9 P}FCBFLG9 !GREAT;done 'PUTER!GOERD;device command invalid !PEOF ERROR;end of file error  ;(error # 136) ABURS}T I/OA " X*, 'X* Test burst i/o and do if possible6 X*@ ;X* burst i/o operates by reading or writing data sectorsJ ;X* d}irectly into the user buffer instead of transferringT +X* only one byte each time CIO is called^ X*h CWTBURQFCBFLG9;if not} aquiring sectors then update and no burstr GTBURST| ;;indicate no burst : X* RTBURQ>;set read type X* !TBURS}TPBURTYP;set burst type Q>;assume no burst $PBURFLG;flag stays 1 if no burst QICCOMZ;if cmd M>;is text mode F}NOBURST;then no burst (HBBINC;otherwise, test buffer length X* do burst i/o 5NXTBURTBURFLG;shift to indicate burst di}d occure QBURTYP;get burst type GWRBUR;minus, so write % RDNXTS;otherwise, do sector read& ENOBURST;br if eof0 !%>};otherwise, move data etc.: ":LABT3Q@ZSBA7;move data bytesD P@ICBALZ7;to user bufferN 3X Cb &RFCBMLN9;end of sector d}ata bytes?l D:LABT3;loop if lessv 6 INCBA;incr user buff ptr by number of bytes moved 9!:LABT4;adjust buffer length and }test for another try $WRBUR MVDAT;move data for write  WRTNXS;do sector write :LABT4; "QICBLLZ;dec user buffer len} by 'SFCBMLN9;actual data len got or put PICBLLZ EBBINC "ICBLHZ .X* enough bytes for at least a full sector? 'B}BINCQICBLLZ;if lo buff len >= $80 GNXTBUR;do burst QICBLHZ;if hi buff len > 0 HNXTBUR;do burst X* no (more) burst} 0NOBURSTVBURFLG;set carry if no burst at all :;and rtn* X* move data for write4 MVDAT%>> 3:MV2Q@ICBALZ7;move dat}a bytes from user bufferH P@ZSBA7;to sector bufferR 3\ Cf &RFCBMLN9;end of sector data bytes?p D:MV2;loop if lessz 1P}FCBDLN9;save in current sector buff data len !INCBA;incr buff ptr and rtn AGET BYTEA X* X* DFMGET - get a file byt}e X* DFMGET SETUP;go set up !QFCBOTC9;if open for dir read M>OPDIR FGET1 .!GDCHAR;then go to get next dir cha}r & rtn GET1QFCBDLN9;get data len RFCBMLN9;test empty sector DGET2;br if not empty RTBUR;do burst if possible} RDNXTS;get next sectorDGET1;br if not eof$!PEOF;else eof error. GET2?8Q@ZSBA7;get data byteBPSVDBYT;save th}e byteL3VC`PFCBDLN9;and set new valuej%FCBLSN9;do eof look aheadtHGET3;if lsn not zero~%FCBLSN9;thenHG}ET3;not eof.RFCBMLN9;if lsn=0 then check for last byte DGET35Q>;if last byte then rts with impending eof code !R}ETURNGET3!GREAT ACLOSEAX*X* DFMCLS - close a fileX*DFMCLS SETUPQFCBOTC9;get open codeM>OPOUT;i}f not output FCLDONE;then done%UFCBFLG9;if not acquiring sectorsDCLUPDT;then is update( WRTLSEC;write last secto}r2 RRDIR;go get directory<"QFCBCNT9;get cnt of sectorsF5P QFCBCNT9Z5dQFCBOTC9;get open codenM>OPAPND;if n}ot appendx FCLOUT;br!QFCBSPR9;else stack file flag5 DFRDSU;set up for read7;restore file flag PFCBSPR9A}PP1 RDNXTS;read to eof DAPP1QFCBSSN9;move start sectorPFCBLSN9;to eof link sectorQFCBSSN9PFCBLSN9} WRTN2;then write as not eofCLOUT%CDIRD;get dir displ,;update sector count7OFILDIRDFDCNT8"PFILDIRDFDC}NT8,76OFILDIRDFDCNT8@PFILDIRDFDCNT8J QFCBSPR9;set entry to in useTPFILDIRDFDFL18^ WRTDIR;write di}rh WRTVTOC;write VTOCrCLDONEQ>;clear open code| PFCBOTC9 !FGREATX**CLUPDTUFCBFLG9;if sector not modified}DCLDONE;then done WRCSIO;else write it!CLDONE;then doneA AX*X* re-read dir recordX*7RRDIRQFCBFNO}9;get file number (in 6 leftmost bits)V?V? PSFNUM FNSHFT;set accu = file no/8PCDIRS;to get dir sector&2 FN}SHFT;move low nibble of file number to high0 FNSHF1:T?DPCDIRD;to get dir displN !RDDIRXX*bFNSHFTQ>l0FNSHF1}%>;shift 3 bits of file no into accuvFNSHF2TFCBFNO9U?1 HFNSHF2:ADEVICE DEPENDENT COMMANDAX*.X}* DFMDDC -- device dependent cmd executionX*&DFMDDC SETUP;set up for executionQICCOM9;get command-R>;is it for}mat (try enhanced & single)?FXFV;br if)R>;other format (forced single/enh)? FXFVS;br ifR>MAXDDC;test range E}DVDCER;br out of range*;4S> ;subtract base of cmds>DDVDCER;br out of rangeHT?R?\ QDVDCVT8f5;push execution a}ddrpQDVDCVT8z5 :;execute+X* device dependent command vector table DVDCVT XRENAME;20-rename XDELETE};21-delete DVDCER;invalid cmd XLOCK;23-lock XUNLOCK;24-unlock XPOINT;25-point XNOTE;26-n}oteMAXDDC';max DVDC+1DVDCER!GOERD;error AFORMATAX*X* format a disketteX*$0X* table contains: length }of VTOC, type code,.DCBCFS;format single if aux = 0+:LBL1$>;indicate format mode = forcedF:LBL2;(always)7X* f}ormat, try enhanced but if impossible, do single XFVQ>DCBCFE;format enhanced>;indicate 'try it' mode4:LBL2&TEMP1;s}ave format mode (0 = forced sd/md)!:LBL2APDCBCMD;command to DCBQICDNOZ;get drive #'$> ;offset in table, assume ram}diskR> 'FXF1;skip physical formating if D8:X* do physical formatingQZDRVA;move VTOC buf adr(PDCBBUF;to} DCB2 QZDRVA< PDCBBUFF%>@;tell SIO receiving dataP%QDSKTIM;get format time out valueZ, DSIO2;goto local disk handl}er, then SIOdIXF0;if no errors contnX* act upon errorx)>;device NAK? H:LBL4$TEMP1;recall format modeFXFER}R;error if forced mode/Q>DCBCFS;otherwise set cmd to format single&RDCBCMD;actual cmd already single? H:LBL2A;no, ha}ve another tryXFERR!RETURN;do error exit&:LBL4)>;ck for device done errorHXFERR;no, then error exit#%>;else} ck for bad sector infoQ>;returned by controller R@ZDRVA7"HXFBAD;bad sectors ret err msg3 R@ZDRVA7(FXFERR};not bad sec err, req err exit"'XFBAD ERROR;return with error #173, ;(bad format)6.X* recall density, set X as offset} in table@XF0$>;assume singleJQDCBCMD;ck cmdT R>DCBCFS^FXF1;br if ish $>;if not, must be enhancedrX* do log}ical formating|XF1Q>;zero VTOC buffer%>;144 bytes longXF2P@ZDRVA71HXF2 Q:TABLE9;move length of VTOC} PDRVTYPXF32Q:TABLE9;move entriesP@ZDRVA7;to VTOC buffer3)>HXF3X* write VTOC sector(s)!%>DVDS}MP;get start of bit map)Q>;deallocate 1st 4 sectors for bootXF4P@ZDRVA7&"Q>;set sector map to all ones03:)DR}VTYP;ck for end of VTOCDHXF4N#%>DVDSMP-;deallocate middle 9XQ>b"P@ZDRVA7;for VTOC and file dirl3vQ> P@Z}DRVA7$DRVTYP;more to do?IXF5;br if not enhanced%%>DVDSMPZ;deallocate sector 720 P@ZDRVA71%>DVDESA;get end }of VTOC for enh sector count)Q>4/;tell 303 more sectors available P@ZDRVA73 Q>5/ P@ZDRVA7XF5 WRTVTOC;wr}ite the VTOC#X* write empty directory sectorsQ>;zero filler dir sectors ?$XF6PFILDIR8;use file dir buffer 3*}IXF64"Q>;write to all 8 dir sectors> PCDIRSH"XF7 WRTDIR;write the file dirR "CDIRS\IXF7f DELDOS;set no DOSp}!FGREAT;donerite to all 8 dir sectors> PCDIRSH"XF7 WRTDIR;write the file dirR "CDIRS\IXF7f DELDOS;set no DOSp}o all 8 dir sectors> PCDIRSH"XF7 WRTDIR;write the file dirR "CDIRS\IXF7f DELDOS;set no DOSpD9X* RECDOS3.M65 ARENAMEAX*&X* XRENAME - rename a file or filesX*$%XRENAME FNDCODE;decode file name.}$ FNDCNX;go decode next file name8$> ;move new filenameB:LBL1QFNAME9L PAFNAME9V0` I:LBL1j< XSTAT;decode old f}ilename, dont rtn if not in directorytXRN1 TSTLOCK;test lock~ TSTDOS;test old file entry 6;indicate DOS in stacked P }SW$> &TEMP1.%CDIRD;get index to filename in dir sector,X* move filename from AFNAME to dir entry'XRN2QFNAME9 };don't change wild cardR> ? H:LBL2"TEMP1;indicate wild cardRAFNAME9;ck with new name-H:LBL3;br to error exit } if not also a '?'$:LBL2QAFNAME9;get new name charR> ?;wild card? FXRN3;skip if so.PFILDIRDFDPFN8;otherwise, s }tore new char XRN33(22(> <HXRN2;loop until doneF%8;unstack PSW to indicate (no) DOSP H:LBL4Z. DELDOS;tell no  }DOS if DOS.SYS was renamedd%:LBL4 TSTDOS;test new file entrynH:LBL5;skip if no DOSx$CDIRD;otherwise, set indexQF}ILDIRDFDSSN9-%FILDIRDFDSSN9;A,Y new DOS start sector SETDSO;go write sector one):LBL5 WRTDIR;go write cur d}ir recordQTEMP1;wild card used?F:LBL6;no, done# CSFDIR;yes, cont search of dirDXRN1;br if found another#:LB}L6!FGREAT;go to good ending!:LBL3!FNDERR;file name error ADELETEAX*/X* XDELETE - delete all filenames that matc}hX*GXDELETE XSTAT;decode filename & search dir, don't rtn if not foundXDELX XDEL0;delete" TSTDOS;was it DOS?,}HXDELY;br if not6* DELDOS;otherwise re-write boot record@!XDELY WRTDIR;write dir entryJ CSFDIR;look for next matchT}DXDELX;br if found^ WRTVTOC;write VTOCh!FGREAT;donerX*|3XDEL0 OPVTOC;don't rtn if disk write protected%CDIR}D;get dir displ TSTLOCK;go test lockQ>DFDEDE;load deleted flag PFILDIRDFDFL18;delete file DFRDSU;read first }sector"XDEL2 FRESECT;free cur sector RDNXTS;read next sector DXDEL2#%>DVDWRQ;turn on write requiredC P@ZD}RVA7 :EXIT:ALOCK AND UNLOCKAX*X* XLOCK - lock a fileX* XUNLOCK - unlock a file&X*0XLOCKQ>DFDLOC;set lo}ck:( ,;skip word by nonsense instructionDX*NXUNLOCKQ>;set unlockXX* common continuationb PTEMP4l. XSTAT;decode} file name and find 1st matchv!XLC1%CDIRD;get current displ"QFILDIRDFDFL18;get lock byteM>;turn off lockLTEM}P4;or in lock/unlock&PFILDIRDFDFL18;set new lock byte WRTDIR;go write CSFDIR;look for next matchDXLC1;br fou}nd!FGREAT;else doneX* X* TSTLOCK - test file lockedX* don't rtn if file lockedX* TSTLOCK%CDIRD;get dir dis}pl#QFILDIRDFDFL18;load lock byte M>DFDLOC;mask lock bit!F:EXIT;br & rtn if not locked  ERROR;error: file locked}* ;(error # 167)4 APOINTA>X*HX* XPOINT - point requestRX*\?X* sets diskette location of next byte to be read or} writtenf-X* (file must have been opened for update)p1X* expects sector number in ICAUX3/4 (lsb/msb)z0X* and relative sect}or displacement in ICAUX5X*&XPOINTQFCBFLG9;if acquire sectorsGPERR1;point invalid.QICAUX49;if request is not sa}me as currentRFCBCSN9HXP1;then br QICAUX39 RFCBCSN9FXP2;else no need to change XP1QFCBFLG9;if not mo }dified FXP1A;br WRCSIO;else write itQ> PFCBFLG9 XP1AQICAUX49 PFCBLSN9$ QICAUX39. PFCBLSN98  RD!}NSO;read req sectorB EXPERRL "XP2QICAUX59;test req data lenV RFCBMLN9;less then max` DXP3j FXP3t 5XPERR ERROR;if "}not then: point data length error~  ;(error # 166) !XP3PFCBDLN9;set new data len !GREAT %PERR1 ERROR;error: inval#}id point  ;(error # 171) ANOTEA X* "X* XNOTE - execute note request X* >X* returns the diskette location of nex$}t byte to be read or X* written )X* sector number in ICAUX3/4 (lsb/msb) %X* relative sector displ in ICAUX5 X* $XNOTE%}QFCBDLN9;data length value PICAUX59;to aux5 'QFCBCSN9;current sector number (lo)( PICAUX39;to aux32 QFCBCSN9;cur&}r sec no (hi)< PICAUX49;to aux4F !GREATP ALIST DIRECTORYAZ d X*n 5X* LISTDIR -- list the directory, called by DFMOP'}Nx 8X* GDCHAR -- get next dir character, called by DFMGET X* 5X* the directory is listed via open list directory 4X* func(}tion. Each dir entry that matches the file 4X* spec is converted to a printable format into a 6X* sector buffer. The get by)}te entry is used to get 6X* the printable characters one at a time. The last 5X* line printed is always a count of the numb*}er of "X* sectors remaining available. X* ?X* Files invisible to single density DOS 2.0 will have their X* A directory opened with ICAUX1 set to 7 will return with :X* brackets, if ne,}cessary. The traditional ICAUX1 value X* of 6 will not. X* )LISTDIR SFDIR;search for a file name" DLDENT1;br if foun-}d, X* prepare SECTORS FREE line6 LDCNT RDVTOC;read VTOC@ 6%>DVDESA;get enhanced # sector available (lo byte)J Q@ZDRVA7.}T &%>DVDNSA;add to # sector available^ ,h O@ZDRVA7r 5;save on stack| 3;do hi byte #Q@ZDRVA7;get # sector available /}%>DVDESA %O@ZDRVA7;add to enhanced # sector >;save hi byte in X reg 7 ?;lo byte in Y reg A;hi byte in accu $>0};set char cnt = 0 &TEMP2  CVDX;and convert %>;set to position 3 A;put there a blank or a '+' P@ZSBA7 3;inc1}r to position 4 (MVFSCMQFSCM8;text 'FREE SECTORS' P@ZSBA7& 30 )>: HMVFSCM;loop until 16 bytesD  CVDY;do eolN2} GDCRTN!GREAT;and rtnX X* get next dir charb )GDCHAR%TEMP2;get count of chars sentl I:LBL1;br if o.k.v !PEOF;set to3} $80 if all done :LBL1Q@ZSBA7;get next char PSVDBYT;in SVDBYT #TEMP2;inc count R>EOL;test if eol done HGDCRTN4};br not eol )>;was this an entry ELDENT;br if it was Q>;else indicate end PTEMP2;in char counter !FGREAT;don5}e X* look for more matches 'LDENT CSFDIR;search for next match ELDCNT;br no more matches X* LDENT1 FDENT;format6} entry !GREAT;done X* message* FSCM AFREE SECTORSA4 +X* format dir entry into a sector buffer> #FDENT$CDIRD;get cur7}r dir displH %>;start at displ zeroR Q> ;start with a blank\ P@ZSBA7f QFILDIRDFDFL19p M>DFDLOC;but if file locke8}dz FLD1 Q> *;change to asterix P@ZSBA7 LD13 Q> ;followed by a blank P@ZSBA7 3 )LD2QFILDIRDFDPFN9;move 9}the 12 char P@ZSBA7;file name 2 3 )> DLD2 Q> ;followed by a blank P@ZSBA73'TEMP2;save line index$:} $CDIRD;recall file dir index.!X* place brackets if necessary8QICAX1Z;get aux1BW?L&D:SKIP;skip brackets if bit 0 zer;}oVQFILDIRDFDFL19;get flag`W?j$D:SKIP;no brackets if bit 0 zerot1;else, change last blank~Q> >;to right bracket<} P@ZSBA7$%>;change bracket at position 1Q> <;to left bracket P@ZSBA72:SKIP%FILDIRDFDCNT9;set A,Y to sector c=}ountQFILDIRDFDCNT9"X* calculate decimal sector cntCVDX$>d;convert and move CVDIGIT;100s digit$>  >}CVDIGIT;10s digit$> CVDIGIT;1s digit $$> ;prepare for a trailing blankC;test if any value leftF:L4;no, skip?} the '+'(!$> +;otherwise, change to plus2:L4%>;then put out<CVDYQ>EOL;an eolF P@ZSBA7P%>Z'TEMP2;set char c@}nt = 0d :;donenX* convert digitx"CVDIGIT&SVD2;save digit value$>(CVD1PZBUFP;save current value hi'ZBUFPA};and lo2;inc digit counter;;subtract digit valueQZBUFP;from curr value SSVD2? QZBUFPS> DSTDIGITB};if gone minus, done1(> ;otherwise, check for 9 (don't exceed 999) HCVD1;if not equal, do againSTDIGITA;digit to acC}cuL>0;plus ascii zero%TEMP2;get output index"P@ZSBA7;and set digit,#TEMP2;inc output index6QZBUFP;load vaD}lue hi@%ZBUFP;and value loJ:TAFILE NAME DECODEA^X*h#X* FNDCODE -- decode a file namerX*|7X* The user filename E}is pointed to by ICBAL/H. It is6X* on the form P.X where P is the primary file name4X* (1 to 8 chars) and X is the extendF}ed file name4X* (0 to 3 chars). The period is optional (if not3X* present, then no extension). The decoded file7X* nameG} will be 11 chars in length. The P field will7X* be left justified in the 1st 8 bytes. The X field8X* will be left justifH}ied in the last 3 bytes. Blanks5X* are used to pad the fields to full size. If the4X* user specified P or X fields contaiI}n more than5X* 8 or 3 chars, then the extra chars are ignored.7X* The '*' wild card char will cause the rest of the9X* J}field to be filled with the '?' wild card char. Any4X* non-alphanumeric char terminates the filename.X*FNDCODE%>;fK}ind the ':'FD0AQ@ICBALZ7&10&GFNDERR;br if not 2nd or 3rd place:R> :DHFD0A;not found, try againN3;found, restoL}re indexXX* decode next charb3FNDCNX3;inc ICBALZ index to start of primary fnlQ>;set primary fn lengthv$>;index tM}o FNAME$:LBL5PEXTSW;set length of field:LUSQ@ICBALZ7;get char R> .;was char field seperatorHFD3;br if notX*N} process period(>;at end of P fieldH:LBL4;br if so)3;otherwise, advance to extender fieldQ> ;set P + X field lO}engthH:LBL5;(always)D:LBL4D:L6;br if index less than field length to pad with blanksX* process chars'FD3R> *;teP}st for asterix wild cardsHFD4;br if not Q> ?(EXTSW;end of field? #EFD6;yes, advance to next field*+DFD6A;no, paQ}d field with question marks4 X* NOTE:>;X* Contrary to DOS 2.0, this version accepts numeric andH7X* alpha chars in all posR}itions, including a primaryR>X* filename beginning with a numeric. Lowercase is accepted\:X* as input, but changed to, and S}handled as, uppercase.fFD4R> ?;was it ? wild cardpFFD6;yes, brzR> 0;is char numeric/DFD5;br not numeric (period orT} end of name)R> 9;test numeric hiDFD6;o.k., br!M>;change lowercase to upperR> A;is char alphaDFD5;br notU} alphaR> Z;test hi alphaDFD6;o.k., br&X* process period or non legal char"FD5Q> ;set P + X field length PEV}XTSW!(> ;complete file name moved?F:LBL3;br if so&:L6Q> ;otherwise, pad with blanksHFD6A;(always)X* char toW} FNAME$FD63.FD6A(EXTSW;end of field?8F:LUS;br if soB)PFNAME9;otherwise, set char into nameL2;inc to next charVX}H:LUS;(always)`X* test filenamej,:LBL3QFNAME;is first char fname a blanktR> ~FFNDERR;yes, error$CURFCB;no, rY}estore FCB:X* error exit!FNDERR ERROR;file name error ;(error # 165)ADIRECTORY SEARCHAX*$X* SFDIZ}R -- search file directoryX* CSFDIR -- continue searchX*CX* The file directory is searched for the filename in FNAME.[} TheAX* search starts at the central sector+1 and will continue for CX* up to a total of 8 sectors. When testing for FNAME\} match, '?'BX* FNAME chars will always match the corresponding dir filename;X* char. If a match is found CDIRS contains t]}he relative(=X* directory sector number (0-7) and CDIRD (and the Y reg)2?X* contains the displacement of the entry. After a^} match has<AX* been found, the directory can be searched for another matchFDX* via the CSFDIR entry point. If a match has n_}ot been found thenPBX* DHOLES and DHOLED will point to a directory hole that can beZ@X* used. If DHOLED = FF then the direc`}tory is full. The carryd=X* is returned clear if file found, set if file not found.nX*xX* Dir entries are flaged:X* a}bit 7 - deleted (if set)X* 6 - in useX* 5 - lockedX* 1 - created by DOS 2+X* 0 - open for outpb}ut if bit 6 set3X* - in used by enh sectors if bit 6 zeroX*SFDIRQ>;init to -1PDHOLES;dir hole sectorc}PCDIRS;curr dir sectorPSFNUM;file number#Q>p;init to -16 (-entry length)PCDIRD;curr dir displX*CSFDIR#SFNd}UM,"$QCDIRD;CDIRD = CDIRD + entry len, O>DFDELN69ISFD2;if result <128 then br, else at end of dir sect@!#CDIRS;ince} to next dir sectorJQ>;test end of dirT RCDIRS^DSFD1;br not endh FSDRTNr(SFD1 RDDIR;read the next dir record|f}Q>;set dir displ = 0!SFD2PCDIRD;set new dir displ?;put displ in Y as indexQFILDIRDFDFL18;get flag 1-FSFDSH;g}br if unused (end of used entries)GSFDSH;br if deletedM>C;mask off lock bit#R>;is it enhanced sector file?F:Lq}MB%DOS SYSB*)DUP SYSB SRECDOS M65BM\RECDOS1 M65B]RECDOS2 M65BwRECDOS3 M65BRECDOS4 M65B}RECDUP M65BL1;br if soM>DFDOUT;if open outputHCSFDIR;don't find it"X* entry in use, test for match$:LBL1$>;test match onr} 11 charsSFD3QFNAME9;file name charR> ?;is fnc wild cardFSFD4;then it matches0RFILDIRDFDPFN8;else it must mas}tch for real&&HCSFDIR;if not match then try next0SFD42;inc char count:3D(> ;test allNHSFD3;and continue checkXt},;we have a matchb DSDRTNlX* empty or deletedv%SFDSHQDHOLES;if DHOLES not minus)ISFDSH1;then already have a good hou}le'QCDIRS;else, move curr displ sector!PDHOLES;and current dir displ#QCDIRD;to hole sector and displ PDHOLEDQv}SFNUM;save holePDHFNUM;file number/SFDSH1QFILDIRDFDFL18;if hole was deleted6GCSFDIR;entry then continue, else wew} are at end of%;;used entries thus file not foundSDRTN$CURFCB;restore FCB:ASTATUS SUBROUTINEAX* 0X* searchx} for a file (don't rtn if not found)X* #XSTAT FNDCODE;decode file name* SFDIR;search for file4E:ERR;br not found>y}:;rtn if o.k.HA:ERR!OPNER1;not found, so go with error 170 (file not found)RAWRITE DATA SECTORA\X*f X* WRTNXS - wz}rite next sectorpX*z(WRTNXSQFCBFLG9;if acquiring sectorsGWRTN1;then no updateX* process updateT?;if sector not{} modifiedIWRU1;then skip writeT?PFCBFLG9;turn off flag bits WRCSIO;write current sectorGWRNERR;br if bad i|}/o&WRU1!RDNXTS;else read next sectorX* process no update%WRTN1 GETSECTOR;get a new sector:X* entry point for wri}}te last sector, called from CLOSE!WRTLSECQFCBDLN9;get data len%>;into last byteP@ZSBA7;of sector&WRTN2QFCBLS~}N9;move link sector$LFCBFNO9;plus file number.%>};to bytes 125-1268P@ZSBA7;of sector buffB3L3QFCBLSN9;link se}ctor in msb/lsb order (10 bits)V P@ZSBA7` WRCSIO;write sectorjIWRTN5;br no errortWRNERRQ>;close file~ PFCBOTC9} QDCBSTA;recover error status !RETURNX* update FCB#WRTN5#FCBCNT9;inc sector count HWRTN6#FCBCNT9-WR}TN6 MVLSN;link acquired sector to currQ>PFCBLSN9;set link to zeroPFCBLSN9PFCBDLN9;data length alsoQ>}};set max data length PFCBMLN9 ,:X*(%WRCSIO;;set for write curr sector2-X* read/write current sector (# in FCBC}SN)<RWCSIOQFCBCSN9F %FCBCSN9P !DSIOZ,X* move link sector no to current sect nodMVLSNQFCBLSN9;move linkn PFC}BCSN9xQFCBLSN9PFCBCSN9: !DSIOZ,X* move link sector no to current sect nodMVLSNQFCBLSN9;move linkn PFC}NQFCBLSN9;move linkn PFCb=X* RECDOS4.M65AREAD DATA SECTORAX*X* RDNXTS - read next sectorX*#RDNXTSQFCBFLG9;if not upd mode$ F}RDNSO;br.!WRTNXS;else write first8"RDNSOQFCBLSN9;if LSN not zeroBLFCBLSN9L HRDNS1;brV ;;else eof`:j%RDNS1 }MVLSN;move link to currentt ,;read~ RWCSIO;current sectorGRDIOER;br if i/o error%>}!Q@ZSBA7;test for same fil}e noM>;mask off sector bits RFCBFNO9HRDFNMM;if not, then errorX* update FCBQ@ZSBA7;move link sectorM>};mask off file no bitsPFCBLSN9$3;get lower part of link sector # Q@ZSBA7 PFCBLSN9 3;inc to len byteQ@ZSB}A7;get len byte 5;save it( QFCBSLT9;get sector len type2HRDNS3;br if new type< 7;get lenF!GRDNS2;br if old short se}ctorPQ>};else set full sectorZRDNS2M>;turn off msbd5;balance stackn RDNS37xPFCBMLN9;set max lenQ>;set cur}r data len = 0 PFCBDLN9,:RDIOER ERRIO;i/o errorX* file number mismatchRDFNMMQICCOM9;recall cmndR>!;}was this delete?FRDDELE;br if delete* ERROR;otherwise, file number mismatch ;(error # 164)"RDDELE;;indicate eo}f to delete:AREAD/WRITE DIRAX*")X* RDDIR/WRTDIR - read/write directory,X*6RDDIR,;set read@ DDIRIOJX*}TWRTDIR;;set write^5X* calls DSYSIO with lo byte dir sector in Y, fileh.X* dir buff in X/A (lo/hi) and r/w in carryrD}IRIO6;save read/write|,QCDIRS;CDIRS +,O>i;((40*18)/2)+1 (is dir sector number)?;into Y (lo byte)8*$>5FILDIR};file directory buffer in X/A Q>4FILDIR,HDSYSIO;(unconditional) go do system i/oAREAD/WRITE VTOCAX*&X* RDVTOC}/WRTVTOC - read/write VTOCX*X* read VTOC!RDVTOC%>DVDWRQ;if write reqdQ@ZDRVA7;non zero#H:EXIT;VTOC already i}n buff, goX* get VTOC length&%ICDNOZ;get drive #0"Q>J;assume ramdisk VTOC length:)>DF:RDSK;br if drive 8N'D}CBDRV;drive # to DCBXQ>DCBCST;get statusb PDCBCMDl DHADRv)Q>d;assume single density VTOC length%DVSTAT;ck statu}sI:RDSK;br if single Q>;set enhanced VTOC length0:RDSK%ICDNOZ;drive # as displ in table (+1)!PDRVTBL8;store} VTOC lengthPDRVTYP;also as drive typeX* read VTOC to drive buffer ,;set read$ DSYSIA;do i/o for enhanced VTOC} :SUB1;save enh VTOC %>DVDWRQ;turn off write reqd P@ZDRVA7 ,;set read VTIO;do i/o for normal VTOC  :SUB2;reca}ll enh VTOC :EXIT: X**,X* open VTOC (insure not write protected)4X*>)OPVTOC RDVTOC;read it, then write itHX*RX}* write VTOC\X*f#WRTVTOCQ>;turn off write reqdp %>DVDWRQz P@ZDRVA7 :SUB1;save enh VTOC;;set write VTIO;d}o i/o for normal VTOC :SUB2;recall enh VTOC;;set write%!DSYSIA;do i/o for enh VTOC & rtn X* set up for VTOC read/}write(VTIOQZDRVA;move buff addr to DCB $ZDRVA %>h;move lo byte VTOC sectorX*X* system i/o+X* expects buf}fer address in X/A (lo/hi) @X* and lo byte sector number in Y, sets hi byte sector # to 1 X* %DSYSIO'DCBSEC;set sector }for DCB$ %>. 'DCBSEC8 *:LBL1PDCBBUF;set buff addr for DCBB &DCBBUFL  BSIOR;go do i/oV I:EXT;rtn if o.k.` })>;was it data error?j F:ERR;br if wast !ERRIO;else user problem~ (:ERR ERROR;fatal sys data i/o error  ;(error #} 163) &X* read/write enhanced part of VTOC !DSYSIAQDRVTYP;get drive type I:EXT;exit if not enhanced 6;save r/w Q>};set sector $400 PDCBSEC Q> PDCBSEC $QZDRVA;bump VTOC buff addr by 16 , O> >;move lo byte in X QZD}RVA O>;msb in accu 8;recall r/w( !:LBL1;and join system i/o2 )X* save enh VTOC and clear buffer area< >X* SUB1/2 u}ses a 44 byte buffer area at end of misc storageF ):SUB1%>d;index to single VTOC lengthP :LBL2Q@ZDRVA7;move enh VTOCZ P}Zd8;to temp buffd Q>;clear enh VTOC buffn P@ZDRVA7x 3 )>;done? H:LBL2;not yet, cont :EXT: X* recall enh }VTOC :SUB2%DRVTYP;get drive type I:LBL5;go if not enhanced %>d -:LBL3QZd8;move enh VTOC from temp buff P@ZD}RVA7;to VTOC buff 3 )>;done? H:LBL3;cont if not done :LBL5: AFREE SECTORA X* #X* FRESECT - free current se}ctor" ;mask off bit 3-7| $?;use bit 0-2 }as index for SECTAB 7 LFCBCSN9 FFSRTS;exit if CSN = 0 QSECTAB8;get bit mask 5;to stack QFCBCSN9 %>;div}ide sector # by 8 &FS1VFCBCSN9;to get byte number W? 1 HFS1 , O>DVDSMP;add offset to SMAP ?;result is VTO}C index 7;recall bit mask L@ZDRVA7;of bit to bit map& P@ZDRVA7;and set result0 5)>d;enh sector? assume normal free se}ctor counter: %>DVDNSAD D:LBL4;br if not enh sectorN -%>DVDESA;enh, use enh free sector counterX 3:LBL4Q@ZDRVA7;incr n}umber of sectors availableb ,l O>v P@ZDRVA7 3 Q@ZDRVA7 O> P@ZDRVA7 FSRTS: AGET SECTORA X* 7X* GET} SECTOR -- get a free sector for use in FCB at 7X* X reg. The sector number is placed in FCBLSN. The 9X* search for a free }sector starts at the DVDSMP byte. 4X* Sectors are numbered sequentially from zero to DVDSMP;set Y to start map-1 GS13;inc SMAP index )DRVTYP;at end of map? E}GSERR;br if at end* Q@ZDRVA7;get a map byte4 "FGS1;br no free sector in byte> X* allocate sectorH $>;set bit counter =} -1R GS22;shift map byte\ T?;until a free sector foundf DGS2p QSECTAB9;get bit maskz N@ZDRVA7;bit set to zero to P}@ZDRVA7;allocate sector A;stack bit mask index 5 $CURFCB;recall curr FCB 6X* calculate sector # (byte number * 8 + b}it-value) C ;;index-DVDSMP S>DVDSMP #PFCBLSN9;byte number in bit map %Q>;set bits to shift/rol 3 times :LUSTF}CBLSN9 U? E:LUS&PFCBLSN9;msb link sector number7;recall bit mask indexLFCBLSN9;or as bit 0-2$PFCBLSN9;in} lsb of LSN.5)>d;enh sector? assume normal free sector counter8 %>DVDNSABD:LAB1;br if not enhLX* indicate enh sector} usedV(%>DVDESA;use enh free sector counter`QFCBSPR9;get file flagjM>;reset bit 6tL>;set bit 0~(PFCBSPR9;mark }in use with enh sector&X* decr number of sectors available :LAB1; Q@ZDRVA7S> P@ZDRVA73 Q@ZDRVA7S>} P@ZDRVA7%>;VTOC changed, soC;set write required byte P@ZDRVA7&QFCBLSN9;rtn with LSN+1 in accu : GSER}R ERROR;disk full error ;(error # 162)(ASETUP ROUTINEA2X*<4X* SETUP - a routine used for all commands to setF6X}* up FMS control cells to access a particular filePX*ZSETUP&CURFCB;save FCBd@;save entry stack leveln2x2 &ENTS}TK$ICDNOZ;move drive no&DCBDRV;to DCB0;dec for access to tablesQDBUFAL9;move drive buffer PZDRVA;addr to ze}ro page ptr QDBUFAH9 PZDRVAQDRVTBL9;get drive typeFDERR1;br if not existsPDRVTYP;set type$CURFCB;rec}all FCB%FCBBUF9;get sector buff # HSSBA;br if one is allocated!X* try to find a sector bufferGSB1QSECTBL8"IG}SB5;br one found,3;inc try count6)>@DGSB1;br more to tryJ$ ERROR;too many files open errorT ;(error # 161)^X}* allocate sector bufferh)GSB5Q>;allocate & indicate not freer PSECTBL8|.3;incr buff number (so not zero) for FCBBUF}C)PFCBBUF9;put buff number + 1 into FCB'X* move buffer addr to zero page ptrSSBA1;decr to true offsetCV?;divi}de by 25;save result!Q>;possible carry from LSR AW?;to bit 7 OSABUFL;so, bump ZSBA by $80!PZSBA;if buff offse}t not even7;recall buff offset/2(OSABUFH;add to sector buffer pointer"PZSBA;and move to zero page:+DERR1 E}RROR;drive number unknown error& ;(error # 160)0AFREE SECTOR BUFFERSA:X*DX* free sector buffersNX*X FRESBUF%}FCBBUF9;get buff nobFFSBR;br if nonel1;dec for table accessv Q>;freePFCBBUF9;in FCBPSECTBL8;and table FSBR}:ADATA SECTOR I/OAX*X* DSIO - data sector i/oX*%DSIO$ZSBA;sector buff addr moved&DCBBUF;to DCB $ZSBA}&DCBBUF!BSIO;do the i/o and rtnAWRITE DOSAX*  X* WRTDOS - write DOS to diskX* #WRTDOS%FCBCSN9;mo}ve start addr*QFCBCSN94 SETDSO;write sector 1-3> WDO;write DOSH !GREATRX*\&X* indicate DOS.SYS does not exis}tsfX*p"DELDOSQ>;set file not existszX* (re)write boot recordDD1PDFSFLG(Q>5FMSORG;move DOS start addr to DCB}PDCBBUF %>4FMSORG 'DCBBUF$WRNBS3;inc sector number lo byteQ>;sect number hi byte;;set carry for write} BSIO;do the writeQDCBBUF;inc mem addrN> PDCBBUF G:LBL6#DCBBUF4:LBL6%DCBSEC;test for write of all} boot sectors )BRCNT$HWRNBS;br not all.:8X* indicate DOS.SYS existsB!SETDSO'DFLINK;set link startLPDFLINKV}Q>;set file exists`,HDD1;(unconditional) go write sector 1-3jX* write FMS to DOS.SYS filet.WDO MVSA;move file star}t addr to ICBAL/HZ~)Q>};set max sector data length to 125 PFCBMLN90:LUS2 MVDAT;move 125 bytes to sector buffer)QI}CBALZ;if not end or past end of DOS RSASA QICBAHZ SSASAEWD4" WRTNXS;then write next sector!:LUS2;and c}ontinue7WD4:;otherwise, done: CLOSE will write final sectorATEST DOS FILE NAMEAX*)X* TSTDOS - test for DOS.SYS f}ile name X*TSTDOS$>%CDIRD;current dir displ(,TDF1QFILDIRDFDPFN8;test filename char2 RDFN9;with DOS filenam}e char<'H:LBLGD;br not match, rtn not equalF3P2Z(> ;look at 11 charsd$HTDF1;br if more, else rtn equaln:LBLGD6;}stack PSWx$CURFCB;restore current FCB8;restore PSW:DFN ADOS SYSAAEXITS FROM FMSAX*4X* error routi}ne -- don't rtn, but get error codeX* just after JSR ERROR callX*ERROR7;unstack rtn addr PZBUFP7 PZBUFP}%>;add oneQ@ZBUFP7;get error codeX* return from FMS (to CIO)X* expects status in accu"&RETURN$ENTSTK;get en}try stack ptr,B;and restore6$CURFCB;restore current FCB@&PICSTA9;put i/o error code in iocbJ?;and Y-registerTQSVD}BYT;get saved data byte^:hX* test SIO statusr$ERRIOQDCBSTA;get i/o error code|GRETURN;br if errorX*(X* exit po}ints after normal operationX*3FGREAT$CURFCB;(otherwise,) restore current FCB FRESBUF;free sector bufferX*GR}EATQ>;set all o.k.HRETURN;(unconditional)ASWITCH PORTBAX*#X* bank switching for XE ramdiskX*:X* Memory m}anagement on XL/XE's is controlled by PORTB,X* set to $FD at power-up.7X* - bit 0 controls o.s. ROM (1 = o.s. ROM, 0 = R}AM)5X* - bit 1 controls Basic (1 = RAM, 0 = Basic ROM)&KX* - bit 7 controls Self-test ROM (1 = RAM at $5000-57FF, 0 = Self}-test)0%X* - bits 2-6 are unused on the XL:AX* XE's use bits 2-5 for bank switching, bit 6 is still unusedDBX* - bits 2-3 }select a memory bank (0-3), which is only enabledN=X* if one or both of the following enable bits are resetXJX* - bit 4 (}CPE) for CPU bank enable (1 = main bank, 0 = extended bank)bLX* - bit 5 (VBE) for video bank enable (1 = main bank, 0 = exte}nded bank)l>X* An enabled 16K bank is accessed at $4000-7FFF by the CPUv$X* (if CPE) and/or Antic (if VBE)X*X* prepar}e, set critical i/oX*XBANK%>;set critical i/o 'CRITIC$XBFLG;(set to $FF)G:XB2;skip loop$RTCLOK;wai}t for vblank:XBL(RTCLOK F:XBL":XB2'NMIEN;disable interrupts=X* select a memory bank)X* 0-3 in accu acc}esses mem bank # 0-3 3X; 4 accesses main memory by setting bit 4 (CPE)%SBANKT?;shift bank # to bit 2 & 3 T?*PZBUFP};in temp reg4 QPORTB>M>;clear bits 2-4HLZBUFP;or in bank #RPPORTB;do switching\:fX*p*X* NDTXT -- used as} msg by DUP's CHKD25zX*NDTXT };clear screen% ANeed DOS2.5,type Y A=EOLAMISC STORAGEA+DRVTYP ;dri}ve type (length of VTOC) RETRY ;i/o retry counter!ENTSTK ;entry stack levelDHOLES ;dir hole sectorD}HOLED ;dir hole displ DHFNUM ;dir hole file no CDIRD ;current dir displ!CDIRS ;current dir sector}SFNUM ;file number&SVDBYT ;saved output data byte)EXTSW ;index for file name decode.SVD2 ;temp for }convert digit (CVDIGIT)TEMP4 ;lock/unlock temp$9TEMP1 ;format mode flag/wild card flag for RENAME.%TEMP2 };char count for LISTDIR8'TEMP3 ;temp for SIO cmd in BSIOBBURTYP ;burst i/o typeL'X* following values are set by} DINITVHDRVTBL ;drive table, set to length of VTOC by RDVTOC, 0 = unused`YSECTBL ;positive if free to allocate, o}therwise minus, set/reset by SETUP/FRESBUFj,DBUFAL ;VTOC buffer ptr for drive notDBUFAH ~'SABUFL ;start of} sector buffersSABUFH X*FNAME  ;file name#AFNAME  ;auxillary file nameBURFLG ;burst flag Z} ;temp storage of enh VTOCAFILE CONTROLE BLOCKA)X* put on same boundary as version 2.0FCBFCBFNO ;f}ile #FCBOTC ;open type codeRFCBSPR ;curr file flag (set to $42, but changed to $03 if enh sector used) RFCBS}LT ;flag for new sector len type (set: new type, zero: DOS 1.0 format)FCBFLG ;working flag#FCBMLN ;max sec}tor data len()FCBDLN ;curr sector buff data len2$FCBBUF ;sector buff no (1-8)<'FCBCSN ;curr sector no (0-10}23)F&FCBLSN ;link/allocate sector #P+FCBSSN ;curr file relative sector #ZFCBCNT ;sector countdFCBLEN }FCB;FCB lengthn&FCBLEN ;allocate 7 more FCB'sx X* openOPIN;inputOPOUT;outputOPDIR;list director}yOPAPND;appendX* values for FCBFLGFCBFAS;acq sectorsFCBFSM@;sector modifiedAFILE DIRECTORYAX* }file directory offsetsDFDFL1;flag1 (1)"DFDCNT;sector counter (low)#DFDSSN;start sector no (low)#DFDPFN};primary file name (8)DFDELN;entry lengthX* values for file flagDFDEUU;entry unused"DFDEDE;entry del}eted,DFDINU@;entry in use6$DFDOUT;file opened for output@DFDLOC ;entry lockedJ/DFDNLD;file has new type s}ector len byteT=X* with bit 6 reset, the value of 3 indicates entry in use^-X* by a file which uses enhanced sector(s)hX*}r"X* file directory sector buffer|X*%FILDIR ;resume file dir spaceAVOLUME DIRECTORYAX* VTOC offsets(DVDT}CD;volume directory type code$DVDMSN;max sectors number (1)DVDNSA;no sectors availDVDWRQ;write require}dDVDSMP ;sector map start'DVDESA;no enhanced sectors availARAMDISK ACCESSAX*X* read/write to ramdi}skX*%DRIVE8QDCBSEC;lo sector in ZBUFP PZBUFP&6;save read/write0 QDCBSEC;hi sector in accu:TZBUFP;sector *} 2DU?NR>;test for $400X$D:GOON;br if less (sector 0-511)b8;otherwise, balance stackl-%>;and rtn with device NAK }error (# 139)v H:EXITX* select bank*X* on entry: msb sector*2 (0-3) in accuX* lsb sector*2 in ZBUFP:GOON XBANK};switch QZBUFP;W?V??PBUFRHI;bit 6 set (point to $4000-7FFF area), plus sector/2Q>W?8PBUFRLO;bit 7 o}f lo pointer set if sector # not even$QDCBBUF;move buff addr to zp ptr PZBUFP QDCBBUF PZBUFP %>;index f}or 128 bytes*8;recall read/write4D:READ;go read>X* write to ramdiskH$:WRITEQ@ZBUFP7;move from bufferRP@BUFRLO7;t}o mem bank\1f I:WRITEp G:DONEzX* read from ramdisk&:READQ@BUFRLO7;move from mem bankP@ZBUFP7;to buffer1 }I:READX* select main memory:DONEQ>;select main SBANK;switch%>;enable NMI 'NMIEN%>;clear critic i/o} 'CRITIC.;enable IRQ3;set o.k. status :EXIT: ==;filler bytesenable NMI 'NMIEN%>;clear critic i/o}}1<X* RECDUP.M65&AMINIDUP -- o.s. and DUP equatesAX*:X* RECONSTRUCTION OF RESIDENT DUP (MINIDUP) FOR DOS 2.5X}*=X* althrough minidup is part of the Disk Utility Programs,$5X* it is included with the FMS in the DOS.SYS file.X*8B}+X* o.s. equates for DUP, not used by DOSLWARMST;warmstart flagV"DOSVEC ;start vector for DUP`DOSINI ;DOS ini }t vectorj CHKSNT;;checksum sent flagtSTAK0;hardware stack~9VSEROR ;serial i/o transmit ready interrupt vector }-CARTSA;(left) cartridge start address'CIOVV;central input/output entry)CIOINVn;CIO utility initialization } WARMSVt;warm start vector%X* equates from the DUP.SYS source;RAMLO;zero page variable (called DSKUTL by the o. }s.)RUNAD;run address%INITAD;initialization address8JDOSOSu ;disk operating system monitor entry point; }CIO11;call CIO and go to DOS menu if break key abort0NMDUP3;end of non-resident portion of DUPARAMDISK INITA}X* 5X* initialization of ramdisk (called from DUPINIT)X*#D8INITTDRVBYT;shift bit 7 away("VDRVBYT;to indicate no dri}ve 82$Q> 1;indicate DUP file on drive 1< PDDSKNOF&Q>4RDTXT;load/run RAMDISK.COM fileP $>5RDTXTZ DUP1d#Q>4AF;load/}run AUTORUN.SYS filen $>5AFx!DUP1;and rtnRDTXT AD:RAMDISK.COMA=EOLX*X* check for 2.5 DUPX*CHKD25Q>L;}is it 2.5? RJDOSOSH:DOCHK;no, br>!CIO1;o.k., call CIO and go to DOS menu if break key abort#:DOCHKQ>;set no DU}P in memory PDUPFLG+Q>4NDTXT;show msg and wait for response $>5NDTXT ERR2(!:DOCHK;loop until return is presse}dX*BX* patch for o.s. Rev.1 serial output interrupt service routine",X* only installed if Rev.1 o.s. is active,X*6%}ISRODNQCHKSNT;test checksum sent@H:SENT;br if sentJ"!;to o.s. ISRODN entry pointT:SENTC;stack Y register^5h"!};to o.s. CHKDON entry pointrX*|, ======;fossil filler bytesX*X* go read VTOCX*XRDVT@;save stac}k level &ENTSTK RDVTOC;do VTOC read%>;set o.k. status:X*X* go write VTOCX*XWTVT@;save stack level} &ENTSTK WRTVTOC;do VTOC write%>;set o.k. status:&#AMINIDUP -- init code for DUPA0*DDSKNO 8;drive number} of DUP.SYS file:X*D7X* initialization code for DUP - calls FMS init codeN)X* called on warm start and cold startXX*b}DUPINITQ>;reset optionlPOPTv$Q>4MNDUP;entry point on DOS call PDOSVEC Q>5MNDUPPDOSVEC1Q;test for o.}s. version (Rev.2 $A5, XL $85)R>&HXINIT;if not rev.1 skip SIO patch3Q>4ISRODN;set up interrupt vector for SIO patc}hHPVSEROR;instead of using the serial output interrupt service routine Q>5ISRODNPVSEROR#XINIT DINIT;FMS init}ialization444 QWARMST;test for coldstartHCKMDOS;br if warm : D8INIT;load and run RAMDISK.COM and AUTORUN.SY}S files*:;return control to o.s.4NX* run disk file (RAMDISK/AUTORUN), pointed to by A/X -- called from D8INIT>*DUP1PICB}AL;store low byte filenameH&ICBAH;hi byteR. INITX;clear DUPFLG show DUP not in memory\Q>f' STLOAD;load, init} and run the filep/!CLOSX;make sure iocb #1 is closed & returnzX* warmstart+CKMDOSQDUPFLG;see if DUP was in memory }FINITX;if zero then wasn't/QMEMFLG;see if user area written to MEM.SAVFCLDSET;if zero then wasn't( LDMEM1;else get!} user memory back in& RELDIN;reload saved DOSINI vector# INITX;clear DUP in memory flag WARMSV;redo warm start#I"}NITXQ>;say DUP not in memoryPDUPFLG;clear flag:X*'CLDSETPWARMST;no valid user memory FINITX;set to cold st#}art AMINIDUP -- loader routineA X*$ ;X* loads from the file (must be load format) into memory. X* returns: X=0 load o.$}k.8 )X* X=1 open errors Y=CIO codeB )X* X=2 read errors Y=CIO codeL X* X=3 bad load fileV )X* on %}entry, IOCB 1 points to filename` X*j .DUPFLG ;flag - if DUP in memory not zerot .OPT ;holds value of option given by &}user~ BLOADFLG ;flag = $80 if memory file doesn't have to be loaded *HDBUF =;temp for start/end address X* open fi'}le SFLOADQ> STLOADPLOADFLG LOADQ>4LRTS PRUNAD Q>5LRTS -PRUNAD;make run at eof default to LRTS $>;(}iocb #1 Q>;open PICCOM9 Q>;open type=input PICAUX19  GOCIO;try to open file IRDLF;cont if o.k. Q>;ope)}n errors( HCLFX;close and exit2 X* read two header bytes< RDLF$>;iocb #1F Q>4DBUF;use copy bufferP PICBAL9Z Q>5D*}BUFd PICBAH9n Q>x PICBLL9 Q> PICBLH9 %PMEMLDD;clear MEM.SAV loaded flag Q>;get char PICCOM9 CIOV +}GERST;if errs Q> #RDBUF;check for valid load file HLNLF RDBUF #HLNLF;branch if not a load file X* get se,}ction of load file %X* read start/end address to HDBUF RDDRC$> Q>4HDBUF" PICBAL9, Q>5HDBUF6 PICBAH9@ Q>J -}RDDRC1PICBLL9T Q>^ PICBLH9h ) CIOV;no error check so can catch eofr ISTOK;if no error| )>;see if eof HERST;if .}some error status X* eof so done, exit  CLOSX;close iocb's 1 and 2 *OPT !GDRUN;branch if no run option # JMPRUN;j/}ump through run vector DRUNQ>;o.k. status *LOADFLG;was memory swapped? PLOADFLG;reset flag )GCLFX;branch if memo0}ry wasn't swapped ( MEMSVG;does memory save file exist? GDRUN1;branch if not 7 7 %!GOOD;write memory and reload DU1}P X*& 2X* See if DUP written over. If is reload & tell0 *X* user need MEM.SAV to load this file.: X*D &DRUN1QDUPFLG;see 2}if DUP globberedN HDRUN2;no, then returnX 'Q>4NMSF;else tell user need MEM.SAVb $>5NMSFl  PRNTMSG;print msgv !RRDUP;3}reload & run DUP X* return to calling routine #DRUN2Q>;no DUP err msg on eof CLFX> LRTS: X* error returns LN4}LF CLOSX Q>;bad load file HCLFX;(always) ERSTC 5 CLOSX 7 ? HCLFX;(always) 8X* continue with load - c5}heck load address for header %X* if have concatenated load files STOK$>* QHDBUF;move params to iocb4 PICBAL9> 5H 6}QHDBUFR PICBAH9\ ?f 7p 3;was address FF?z HADOK;branch if not ? 3;other byte FF? HADOK;branch if not IX* h7}ave a header & start address - get end address for text & do again QHDBUF PHDBUF QHDBUF PHDBUF;move load8} address Q>4HDBUF PICBAL9 Q>5HDBUF 1PICBAH9;so load address doesn't get wiped out Q>!RDDRC1;read end9} address2X* get length of text, then determine if in DUPADOKQHDBUF$;. SHDBUF8 PICBLL9B QHDBUFL SHDBUF:}V PICBLH9`.QHDBUF;is beginning address within DUP?jR>5NMDUP t4~2EANWD;branch if hi byte outside DUP addr ;}space+QHDBUF;is ending address within DUP?-R>5NDOS;end of system buffers and minidup4 LLOADFLG7PLOADFLG;set MEM.SAV doesn't have to be loaded flagX* adjust length & loadAWD#ICBLL9>} H:AWD1  #ICBLH90:AWD1*LOADFLG;does memory have to be loadedGDLM;branch if not('QMEMLDD;was MEM.SAV already loa?}ded?2GDLM;branch if so< "MEMLDDF+ LDMEM;load MEM.SAV file (if it exists)P(Q>;show user area not DUP in memoryZ PD@}UPFLGd7 RELDIN;restore DOS init vector from saved locationn?X* set no init addr default then read in text & attempt initxA} DLM$> Q>4LRTS PINITAD Q>5LRTS%PINITAD;init defaults to a rts& CIOV;read data directly to memory IDLMB}1!ERST;if errors DLM1*OPTGDIN;branch if no go option JMPINT;do init,DIN!RDDRC;get next section of load fiC}le$X* the following code is a fossil5NDOS*D:AWDQR;branD}ch if hi byte lt DUP startR>5NMDUP "*:USRDOSU?;label mentioned in 'Mapping',N>6V?;complement carry@ :AWDQR:E}JX*TJMPINT!@INITAD:^JMPRUN!@RUNAD:hX*r)MEMLDD ;MEM.SAV already loaded flag|AF AD1:AUTORUN.SYSA=EOL0NMF}SF ANEED MEM.SAV TO LOAD THIS FILE.A=EOL%AMINIDUP -- create MEM.SAV fileAX*-X* routine written by M.E., april 21, G}1980=X* this routine creates a file on disk of data from memory.X* create file called 'Dn:MEM.SAV', set Y=1AX* able to H}create file then set reg. Y=error returned from CIOJX* the ram to be occupied by DUP is stored by this routine into MEM.SAVI}MSTXT AD8:MEM.SAVA=EOLX*3MWRITE CLOSX;close iocb's and open #2 to writeQ> PICAUX19 OREST$GERRJ}WR;if error then jmp and ret&X* write memory block0Q> ;put char: PICCOM9D(Q>4NDOS;store start of block for CION PIK}CBAL9XQ>5NDOS;start addr (high)b PICBAH9lQ>4LEN;length of blockv PICBLL9Q>5LEN;length (high) PICBLH9 CIOL}V;write data block"GERRWR;if write error then jmp CLOSX GERRWR%>:9X* routine to complete open of 'Dn:MEM.M}SAV' -- calling-X* sub supplies 'read' or 'write' in ICAX1ORESTQ>;open PICCOM9 Q>4MSTXT;filename Dn:MEM.SAV PN}ICBAL9  Q>5MSTXT PICBAH9  !GOCIO*X*4ERRWR:;error rtn>$X* to CIO after storing DUP driveH-GOCIOQDDSKNO;get drO}ive # of DUP.SYS fileR(PMSTXT;set at Dn:MEM.SAV filename\)PDUPSYS;set at Dn:DUP.SYS filenamef!CIOV;call CIO and P}rtnpX*z# ===`;fossil filler bytes+AMINIDUP -- entry point on 'DOS' callA$INISAV ;DOSINI vector save loc@Q}MEMFLG ;set to FF for memory written to MEM.SAV, else zeroX* MNDUP$>&MEMFLG;memory not saved#&LOADFLG;memorR}y should be saved0'&WARMST;assume no cold start needed& INITIO;close iocb's and reopen E:. MEMSVG;find out if filS}e Dn:MEM.SAV existsIGOOD;branch if soQ>!PWARMST;clear warm start flagFFINAL;(always)X* write memory file$T}+GOOD MWRITE;write user area to MEM.SAV. GPERROR8"MEMFLG;show memory writtenBGFINAL;(always)L)X* MEM.SAV failed, pU}rint error messageV"PERRORQ>4ERRMES;error occured` $>5ERRMESj PRNTMSG;goto msg printert!Q>4ERR;print query to run DV}OS~ $>5ERRERR2 PRNTMSGX* wait for Y to run DOSQ>;get record PICCOM Q>4STAK0 PICBAL Q>5STAK0 PICW}BAHQ> PICBLLQ> PICBLH CIOV QSTAK0;see if Y typedR> YHRTCART;branch if not(Q>2 PWARMST<XX}*F FINAL$> ;close MEM.SAV filePQ> Z PICCOM9d CIOVnX*x&RRDUPQDOSINI;save DOS init vector PINISAVQDOSINIY}PINISAV&Q>4DUPINIT;set up DUP init addr asPDOSINI;DOS init vectorQ>5DUPINITPDOSINIRRDUP1Q>4DZ}UPSYS$> PICBAL9 Q>5DUPSYS PICBAH9%>&'OPT;assure no /N option in effect1;show that DUP is in memory[} 'DUPFLG"# SFLOAD;load DUP.SYS and run it, RTCART:6X*@EC AE:A=EOLJDUPSYS AD8:DUP.SYSA=EOLT3ERRMES AERROR-\}SAVING USER MEMORY ON DISKA=EOL^'ERR ATYPE Y TO STILL RUN DOSA=EOLhAMINIDUP -- subroutinesAr5X* routine tests if ME]}M.SAV is present on the disk|"X* returns - minus if not there(X* plus if MEM.SAV is thereX* MEMSVG CLOS20^};close iocb #2 Q>;open PICCOM9 Q>4MSTXT PICBAL9 Q>5MSTXT PICBAH9Q> ;read/write2PICAUX19;try to open_} Dn:MEM.SAV for read/write GOCIO6;save status CLOS20;close MEM.SAV8;restore status:&X*0AX* save file subr`}outine - write file body, init, & run vectors:X*D*WDR1Q>;this immediate value modifiedN2FWDR2;br if mem file doesn't a}have to be loadedX LDMEM;reload saved memoryb WDR2$>l& CIOV;do save - write body to diskv2INITQQ>;this immed valb}ue changed during save2FRUNQ;set to FF when an init vector is present #INITQ QINITAD*PVECTR;if init vector forc} file save itQINITAD PVECTR Q>4INITAD> PLDST Q>5INITAD WRVEC*RUNQQ>;this immediate value mod}dified2FNORNAD;set to FF when a run vector is present #RUNQ  QRUNAD)PVECTR;if run vector for file save it  QRe}UNAD* PVECTR4 Q>4RUNAD>>H PLDSTR Q>5RUNAD\ WRVECf"NORNAD CLOSX;close iocb's 1&2p QMEMFLGz MWDR1f} FDRRDUP.#WDR1;reset mem needs to be loaded flag!RRDUP1;reload & run DUP)DRRDUP!JDOSOS;run the swapped in DUPg}X*WRVECPLDST2 &LDND PLDND$> Q>4LDST PICBAL9 Q>5LDST PICBAH9Q> PICBLL9$Q>.h} PICBLH98#!CIOV;write init or run addressBX*LX* jump to cartridgeVX*`CLMJMP LDMEMj$Q>;show DUP no longer in i}memoryt PDUPFLG~) RELDIN;restore DOS init vector saved!@CARTSA:;jump to cartridgeX*7X* load MEM.SAV (if it existj}s) before run at addressX*)LMTR LDMEM;load MEM.SAV if it exists)Q>;show that DUP no longer in memory PDUPFLG)k} RELDIN;restore DOS init vector saved!@RAMLO:;run at addressX*/X* restore DOSINI vector from saved locationX*l}RELDINQINISAV  PDOSINIQINISAVPDOSINI(:2X*<2X* subroutine LDMEM - load MEM.SAV if it existsFX*PLDMm}EMQMEMFLGZ&HLDMEM1;branch if memory was savedd:nLDMEM1 MEMSVGx-ILDMEM2;branch if MEM.SAV file does exist$Q>;ten}ll cart pgm area clobbered PWARMST!FCLOS2;go close and goto cartX*LDMEM2Q>;open PICCOM9 GOCIO;reopen MEo}M.SAVQ>;get char PICCOM9Q>4LEN  PICBLL9 Q>5LEN PICBLH9 Q>4NDOS PICBAL9 Q>5NDOS" PICBAH9,p} CIOV6CLOS2Q> ;close@ PICCOM9J!CIOV;close MEM.SAVTX*^5X* close all iocbs & re-open zero as screen editorhX*rq}0INITIO CIOINV;this routine closes all iocbs|&$>;then reopens the screen editor Q>;open PICCOM9 Q>4EC PICBAr}L9 Q>5EC PICBAH9Q> ;read/write PICAUX19!CIOV;call CIO and rtnX*X* CLOSX - close iocbs 1 & 2X*CLs}OSXQ> ;close$> PICCOM9 CIOV&'X* entry point to close iocb #2 only0CLOS20$> : Q> ;closeD PICCOM9N.XCIOt}!CIOV;also used by PRNTMSG subroutineXX*bX* subroutine PRNTMSGl-X* puts a character string terminated by av+X* carriagu}e return char to screen editor+X* entry - lo/hi byte msg address in A/X7X* put params in iocb - use iocb 0 for screen ediv}torX*1PRNTMSGPICBAL;set msg addr in iocb buff addr &ICBAHX* set up rest of iocb$>;set in buffer length-&w}ICBLH;assume 256 bytes max, or some more+0;use reg X to set in iocb index for CIOQ> ;put msg PICCOM44CX* tesx}t if DUP is resident - if is then use indirect CIO routine X* to test break key abort2QDUPFLG;if zero non-resident DUP ny}ot in memory #FXCIO;go direct to CIO & return*>!CHKD25;in memory, so use it, but be sure it's 2.5 version4X*>X* file z}headerHX*RSAVH =\LDST ;load addressfLDND ;end addresspVECTR ;run/init vectorzX* = =;fossil {}filler bytesX*ENDFMS;end of FMS?X* Used by 144 byte drive buffers & 128 byte sector buffers.?X* Each active drive|} and each simultaneously open file needs;X* a buffer. Without loading the DOS menu, there will be=X* enough space. Using }}the menu limits the buffer space to1X* the $3B0 bytes gap between ENDFMS and NDOS.?X* With 1 drive, 6 open files are poss~}ible without affectingX* the DOS menu.!X* 2 drives allow 5 open files!X* 3 drives allow 4 open files!X* 4 drives all}ow 2 open files9X* (a ramdisk needs a drive buffer as any other drive)  =NDOS;end of system buffers and minidup }(DUP file equate)$5 x;parameter area & type in line buffer for DUP.DBUF;data buffer for copy8+X* length of non-resid}ent portion of DUPBLENNMDUPNDOSea & type in line buffer for DUP.DBUF;data buffer for copy8+X* length of non-resid}non-residt