; File DISKS.S contains most of the routines for ; creating, reading, and writing disk images and ; ramdisks. This file is part of SIO2PC ; includes: ; ΥΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΈ ; ³ ³ ; ³ ³ ; ³ XCHANGE; CRUD; DO_BLANK; READ_DSK; WRITE_DISK ³ ; ³ ZSTARS; INEXTS; SET_BP; UN_DISK; FIND_MT ³ ; ³ GET_FSPC; ORDER; DELETE; DO_BLANK; CUS_SIZE ³ ; ³ STD_SIZE; REL_DEL; WRITE_ERROR; PART_REC ³ ; ³ GET_DISKNO; USE_4K; V_CHECK; GET_PNAME ³ ; ³ SIM_IO; SHO_MOR; DO_CFINFO; W_CRC; BLANK_RFS ³ ; ³ INST_PC; SIM_READ; D_OPENF ³ ; ³ ³ ; ³ ³ ; ³ ³ ; ΤΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΎ ; CRUD - Create an Atari ramdisk based on user ; supplied parameters. ; Get disk number and see if it already exists: CRUD: CALL GET_DISKNO JNC >L1 ; No error CMP ERROR, 27; ESCAPE? PSTATUS PRMT_DSK, ATTR9 ; 4.11d JMP CRUD; For other than ESC, try again STC RET; Return with error status L1: MOV LOAD_OPT, ' '; 3.17 start with neutral load option CMP ERROR,'N' JE >L1 PSTATUS X10, ATTR10 TICKS 36 CALL FLUSH JMP CRUD ; Now, the disk chosen did NOT exist, so now find an open structure ; record and set BP to base of it. L1: CALL FIND_MT ; carry clear means one was available JNC >L1 PSTATUS ALLUSED, ATTR10 TICKS 50 STC RET L1: MOV AX,080h; assume single density AND B[TYPE_CODE+BP], 11111011xB CMP CCRUD, 'C' JE >L1 MOV AX,0100h; If CCRUD <> 'C' density is double OR B[TYPE_CODE+BP], 00000100xB L1: MOV [SEC_SIZE+BP], AX ; AND B[TYPE_CODE+BP], 11111011xB; single density 3.17 removed ; Now get disk size from user: MOV AL, DISK MOV [N_DISK+BP], AL ; disk # was ok, so record it MOV B[N_DISK+BP+1], ':' PSTATUS GET_DSIZE, ATTR9 CALL GET_TORK; Now get size info... CMP AL, 27 ; escape pressed? JNE >L1 CALL UN_DISK STC RET L1: SUB AL, '1' ; convert to range of 0 to 5 CMP AL,06; 3.05 - WAS 5 JB >L1 PSTATUS VOR, ATTR10; Value out of range TICKS 36 JMP RE_CRUD L1: MOV SIZE_CH, AL ; save for reference CMP AL, 4; 5 means custom size (rev. 3.00) JB >L1; 0,1,2,3 are the old standard sizes CALL CUS_SIZE; routine handles getting size, etc. CMP ERROR, 'E' JNE ENTRY CALL UN_DISK ; 3.17 - formerly fell thru to RE_CRUD STC RET RE_CRUD: CALL UN_DISK ; clear disk record fields JMP CRUD; for error in - start over @ CRUD L1: CALL STD_SIZE ENTRY: ; This is the entry point for call from READ_DSK ; procedure. It will have AX & DX & SEC_SIZE & BP & BX set up. ; and MAX_SEC[BP] (BX holds SIZE_CH * 2) ; NOTE: [02] BELOW IS A VARIABLE IN THE PSP. IF THIS FILE IS ; CHANGED FROM COM TO EXE, THIS MAY HAVE TO CHANGE *** ; REV 3.00: first, if DX <> 0, we KNOW this is too big to be ; a ramdisk: CMP B[LOAD_OPT], 'P'; force physical file access? JE ACS CMP DX, 0 JNE ACS ; can't be ramdisk, don't bother checking MOV AX, [LO_SIZE+BP] ADD AX, NEXTS; Check new top against memory size. JC ACS; overflow means too big ... rev 3.00 ; Note below: QUICK ASSEMBLER requires segment modifier (even in ; default segment) when using an absolute address (offset). CMP AX,DS:[02]; PSP memory top JAE ACS JMP NEAR > L1 ACS: CMP LOAD_OPT, 'P'; user requested file access? (3.17) JNE > P1 PSTATUS X111, ATTR9 JMP > P2 P1: PSTATUS X11, ATTR9 P2: TICKS 27 ; REV 3.00 no error - don't flush MOV B[WRITTN+BP], 'F' MOV B[WRITTN+BP+1], ',' CALL COLOR_FFIELD ; At this point, we know the disk size is too big for a ramdisk. ; If this is a CREATE operation, we will now ask for a filename and ; create a blank file of the desired size. If this is a LOAD operation ; we just continue setting up the data for the disk, with the flag ; showing it's a FILE disk and not a RAM disk. CMP XCRUD, 'L' ; Load file operation? JE ACT CALL DO_BLANK JNC ACT ; carry set means abort crud operation CALL UN_DISK STC ; Bad status return RET ; error return ; Now, there is enough memory so make old top [NEXTS] be new ; start [STARS], and old top plus size equal new top [NEXTS]. L1: MOV CX, NEXTS MOV [STARS+BP],CX; save start'g seg. of new disk MOV NEXTS, AX; New next available segment MOV CX, DS:[02]; top of memory SUB CX, AX ; get free ram in paragraphs MOV RAM, CX CALL PUT_RAM CMP SIZE_CH, 4; For custom, stuff below has been done JAE ACT; 3.06 ; Changed above 9/11. was [NEXTS+DI], but there's only one ; NEXTS, right? ; Now set up the max. number of sectors variable, equal ; to size in para's divided by sector size in para's. MOV AX,[SIZES+BX]; Lookup size in paragraphs MOV [LO_SIZE+BP],AX; Also store size this specific disk MOV W[HI_SIZE+BP], 0 ; REV 3.00 MOV BX,[SEC_SIZE+BP]; Sector size; *** 11/27/89 MOV CL,4; CAN'T USE SHR BL,4 ON 8086 SHR BX,CL; Since numerator is in paragraphs **** 11/27/89 MOV DX,0; high 16 bits of numerator DIV BX; DX:AX/BX, result is in AX and equals max sectors MOV [MAX_SEX+BP],AX CMP W[SEC_SIZE+BP], 080h; single? JE >L1 ; then no adjustment ADD W[MAX_SEX+BP], 2 L1: CALL CLR_ALL ; Now, set up the text info for the ramdisk info lines ; First, ramdisk size: ACT: CALL ASCI_SIZE ; Set up DSTATS density information based on size choice. ; For 130K, status = 144, else = 16. MOV B[STATS+3+BP],16; assume <> 143K CMP W[LO_SIZE+BP], (1040/16)*128 JNE >L1 CMP W[HI_SIZE+BP],0 JNE >L1 MOV B[STATS+3+BP],144 ; Make bit 5 = 1 for double density L1: CMP W[SEC_SIZE+BP],0100h ; this loc had no label before REV 3.00 JNE >L1 OR B[STATS+3+BP],020h ; Then, ramdisk density: L1: PUSH CS POP ES MOV AX,[SEC_SIZE+BP] MOV CL,8 SHR AX,CL; makes 1 for 256, 0 for 128 SHL AX,1; 4 for 256, 0 for 128: string pntr SHL AX,1; counting this shift MOV SI, OFFSET ASDNS; String 'SD, ' ADD SI,AX; Or string 'DD, ' MOV DI, OFFSET ADENS ADD DI,BP MOV CX,4 CLD REP MOVSB CMP B[WRITTN+BP], 'F' JNE >L1 MOV B[STATS+1+BP], 060h ; long timeout for physical format JMP ADA ; Now, show this ramdisk hasn't been written yet: L1: MOV B[WRITTN+BP],'N' MOV B[WRITTN+1+BP],',' CALL COLOR_FFIELD MOV B[STATS+1+BP],020h ; Normal timeout value for ramdisk ; 3.01A BELOW - ADA: CALL DO_CFINFO; Put config. into into 12 byte table CALL SU_DSKHDR CLC ; Good return status RET ; DGET_FSPC is a new entry point for GET_FSPC which doesn't print ; on the status line, it uses the current cursor position ... DGET_FSPC: PRINTL RD3 MOV TAG_RD3, 0FFh ; tag that don't want to fix screen JMP > D1 ; GET_FSPC - This subroutine gets a filespec from the ; user. If ESC is pressed, the carry is set on return. ; The string is stored at RFSPEC and terminated by 0. GET_FSPC: PSTATUS RD3, ATTR9 ; rev. 4.11 - if tail isn't empty then get the string all at once ; from it. Else, use the drop down file list D1: CMP TAIL_CNT, 0 ; tail empty? (Note: D1 is separate entry point) JE > F1 MOV DI, RFSPEC ; GET_TAILS puts string in [DI] CALL GET_TAILS ; get filename from tail MOV B [DI], 0 ; make it ASCIIZ JMP ABK F1: MOV CX, 54; Max chars allowed (note D1 is separate entry point) MOV DI, 0; Index counter to put chars in buffer ;AAI: L0: CALL GET_TORK; WAS K6 CMP AL, 08; Backspace? JNE >L1 CMP DI, 0; Don't backspace if at start JE L0 DEC DI; Backspace actions INC CX; Note: I'm not preventing screen bkspce. CALL PRINT1 ; backspace just moves cursor left ... MOV AL, ' ' ; so print a space over deleted character CALL PRINT1 ; and then MOV AL, 08 ; move character left again! CALL PRINT1 JMP L0 L1: CMP AL,27; ESC? ESC means cancel function... JNE > L4 F4: MOV [ERROR], 27 STC RET L4: CMP AL,' '; Space means end of filename... JE >L1 CMP AL, 0Dh; So does return JE >L1 ; REV 3.17: CMP AL, ' '; reject all codes below 020H JB L0 CMP AL, 127 JA L0 ; OK, its just a regular character... MOV [RFSPEC+DI], AL; Put it in filespec block, INC DI CALL PRINT1 LOOP L0 ;AAI; Get more if haven't used 54 JMP ABK ; Now, put zeroes for rest of field. L1: MOV AL,0 L1: MOV [RFSPEC+DI], AL INC DI LOOP L1 ABK: MOV AL,0 MOV [RFSPEC+54], AL; 3.17, # was 55 CLC RET LDGET_FSPC: MOV TAG_RD3, 0FFh ; tag that we don't want to fix screen JMP > D1 ; LGET_FSPC will get a filespec from the drop down list using FILELIST ; It's generally for READ FILE needs where a user will select from the ; directory. WRITE FILE functions will still ask for manual entry via ; GET_FSPC ; The filename is moved to RFSPEC, and DI points to 1 past the 0 at the ; end of the string (String is ASCIIZ) if status is good (carry clear) LGET_FSPC: MOV TAG_RD3, 0 ; tell FILELIST to restore SIO2PC screen D1: CMP TAIL_CNT, 0 ; tail empty? (Note: D1 is separate entry point) JE > F1 MOV DI, RFSPEC ; GET_TAILS puts string in [DI] CALL GET_TAILS ; get filename from tail MOV B [DI], 0 ; make it ASCIIZ JMP SHORT > K1 F1: CALL FILELIST ; get choice from drop down list JC > F4 ; error exit ; filelist returns the filename with spaces following. Change 1st space ; to a 0 FIND_BYTE RFSPEC, ' ', 54 MOV B [DI-1], 0 JMP SHORT > K1 F4: MOV [ERROR], 27 STC JC > F5 K1: CLC F5: RET ; sub fills RFSPEC with blanks BLANK_RFS: PUSH AX, SI, CX FILL ' ', RFSPEC, 55 POP CX, SI, AX RET ; A subroutine to order the disk table pointers in MIN_TABLE ; in order of increasing size of STARS, for use by the DELETE ; routine in ensuring that the lowest ramdisk gets moved down first. ; MIN_TABLE's 4 word entries are the BLOCK_SIZE * 0, 1, 2, 3 ; Note: This is a "bubble sort" ORDER: PUSH CX,BX,BP,SI,DX ORDER1: MOV SORT_FLAG,0; No swaps were required if = 0 MOV CX,3; Routine checks in pairs, 1,2 2,3 3,4 ORDER2: MOV BX,3 SUB BX,CX; Make BX = 0,1,2 for CX = 3,2,1 SHL BX,1; Point to WORD entry in MIN_TABLE MOV BP,MIN_TABLE[BX]; Get pointer to lower entry of pair MOV SI,MIN_TABLE[BX+2]; Get pointer to next higher MOV DX,[BP+STARS]; Get lower # STARS MOV DI,[SI+STARS]; FOR DEBUGGING ONLY MOV DI, OFFSET STARS MOV DI, BLOCK_SIZE CMP DX,[SI+STARS]; Compare to next higher JBE >L1; No change needed if lower or equal MOV MIN_TABLE[BX+2],BP ; else, swap pointer entries MOV MIN_TABLE[BX],SI MOV SORT_FLAG,1; And flag that swap was necessary L1: LOOP ORDER2 CMP SORT_FLAG,1 JE ORDER1 POP DX,SI,BP,BX,CX RET ; DELETE - A routine which deletes a ramdisk and moves the ; others in memory so there is no gap containing unused ; data. On entry, the ramdisk has been verified to exist ; and DISK & DISKW & BP have been set up by GET_DISKNO ; NOTE: since DS is out of whack in loop, MOV's use CS ; over-ride, unless BP is used, then SS is assumed. DELETE: CMP B[WRITTN+BP], 'S'; Simulated disk? (4.11 added this) JE > S1 CMP B[WRITTN+BP], 'F'; Real disk gets spcl treatment JNE >L1 ; REV 3.00 S1: JMP REL_DEL ; exit for physical file disks L1: CMP B[WRITTN+BP], 'W' ; as of REV 3.00, will issue a JNE >L1 ; warning for disks not saved PSTATUS NOT_SAVED, ATTR9 CALL GET_TORK AND AL, 11011111xB; REV 3.03 CONV. TO UPPERCASE CMP AL, 'Y' ; 'Y' means delete anyway JE >L1 RET L1: CALL ORDER; Sort MIN_TABLE by MIN to MAX STARS MOV DX,[LO_SIZE+BP]; Save size (para's) of disk to delete MOV DELSIZE,DX SUB NEXTS,DX; Lower NEXTS by amount of RAM freed ADD RAM, DX; # of paras of free RAM CALL PUT_RAM MOV AX,[STARS+BP]; Keep starting segment in AX PUSH BP; Save pointer for deleted disk ; No need to check 1st ramdisk, it's guaranted at lowest RAM MOV CX,3; loop counter, 3 ramdisks CLD; Increment in UP direction NXT_DSK: MOV BP,4; Make disk # count up, 1,2,3 SUB BP,CX SHL BP,1; Make point to word, now BP = 2,4,6 MOV BP,[MIN_TABLE+BP]; Disk #*2 type index MOV DX,[LO_SIZE+BP]; Get size of disk to be moved MOV CS:DMOVSIZE,DX; And store it in DMOVSIZE CMP AX,[STARS+BP]; Is current ramdisk below deleted one? JAE CKNEXT; No need to move if above or same disk ; Now the part to move, 32K at a time PUSH CX MOV SI,0; Using offsets of 0 MOV DI,SI MOV DX,[STARS+BP]; Current (source) segment base MOV DS,DX; Source SUB DX,CS:DELSIZE MOV ES,DX; Destination MOV [STARS+BP],DX; New base address for ramdisk ; Now, do 32K block (assumes at least 32K to move): L1: MOV CX,04000h; 16K of words = 32K REP MOVSW; Move 32K bytes from DS:SI to ES:DI MOV DX,ES ADD DX,0800h; Point up to next 32K block MOV ES,DX MOV DX,DS ADD DX,0800h; Same MOV DS,DX MOV DI,0 MOV SI,DI SUB CS:DMOVSIZE,0800h; Count down # to move CMP CS:DMOVSIZE,0800h; 32K or less to go? JA L1 ; Now move last dab, if there is one: MOV CL,3; To multiply by 8 (moving words, not bytes) SHL CS:DMOVSIZE,CL MOV CX,CS:DMOVSIZE; # of words to move CMP CX,0; Don't bother moving 0 words JE >L1 REP MOVSW L1: POP CX CKNEXT: LOOP NXT_DSK; Now check next disk POP BP MOV W[STARS+BP],0; Show that disk no longer exists PUSH CS; Fix segment registers PUSH CS POP DS POP ES CALL UN_DISK ; clear disk's text fields ; REV 3.00 made this a subroutine CALL SU_DSKHDR RET ; label below is where physical file disks exit DELETE. rev 3.00 ; this label is also called as a subroutine from the QUIT area REL_DEL: ; CALL UN_DISK ; Clear text field 4.11 move till after HANDLE used MOV BX, [HANDLE+BP] #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF MOV AH, 03Eh ; Close file PUSH BX, AX CALL UN_DISK POP AX, BX INT 021h JNC >L1 PSTATUS ECLOSE, ATTR9 MOV AH,0; AX contains error code ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 50 L1: CALL SU_DSKHDR RET ; Clear the text fields of disk addressed by BP ; also, set STARS = 0 ; makes simulated disk sector # = 401 ; As of 4.11, this routine just copies an entire undisturbed header ; over the one being vacated. All bytes are reinitialized. UN_DISK: MOV CX, BLOCK_SIZE PUSH DS POP ES MOV DI, OFFSET HANDLE ; start of header ADD DI, BP MOV SI, GOOD_COPY ; undisturbed header CLD REP MOVSB ; MOV CX,(OFFSET DOLL - OFFSET N_DISK) ; Length of text fields to be cleared ;L1: MOV DI,CX ; MOV BYTE PTR [N_DISK-1][DI][BP], ' ' ; LOOP L1 ; MOV W[STARS+BP], 0 ; MOV B[DSK_FLAGS+BP], 0 ; clear flags - 4.02 RET ; FIND_MT ; This routine will search the 4 disk structure records for ; the first unused one. If it finds one, the carry will be ; clear and BP will point to the base. Else, the carry will be ; set FIND_MT: PUSH CX MOV BP, 0 MOV CX, 4 L0: CMP B[N_DISK+BP], ' '; means record is unused if space JE >L1 ADD BP, BLOCK_SIZE LOOP L0 POP CX STC ; Not found RET L1: POP CX CLC RET ; SET_BP ; This routine will take the ASCII disk # ('1' to '8') in AL ; and see if it exists in one of the four N_DISK fields. If it ; does exist, BP will be set to the start of the disk structure, ; and the carry will be clear. Otherwise, it will be set: ; NOTE: for device #'s 039h and 03Ah, carry will be clear. For ; device 040h, carry will be clear if PRINTHRU <> 0. ; Also, VALID will be made 0 for non VALID devices, 0FFh otherwise SET_BP: ; For this first group of SPECIAL device IDs, BP will not be changed: CMP AL, 040h ; no valid devices above 40h JA ADJ CMP AL, 031h ; or below 31h JB ADJ CMP AL, 039h ; remote control? JE ADI CMP AL, 03Ah ; FILE2PC? JE ADI CMP AL, 040h ; PRINTHRU JNE >L1 CMP [PRINTHRU],0 JE ADJ ; PRINT THRU function not enabled JNE ADI L1: PUSH CX MOV BP, 0 MOV CX, 4 L0: CMP [N_DISK+BP], AL JE >L1 ADD BP, BLOCK_SIZE LOOP L0 POP CX ADJ: MOV VALID, 0 STC ; Not found RET L1: POP CX ADI: MOV VALID, 0FFh CLC RET ; GET_DISKNO ; This subroutine gets disk # from user, and checks to ; see if it exists. If, so, variable ERROR contains E, else ; N. If ESC char is encountered, carry is set and ESC is ; returned in ERROR. For value out of range, message is printed ; and then carry is set. Routine also sets up DISK, AND ; BP to access BLOCK. FOR REV. 3.00: If the disk is a physical disk ; file, STARS will be 0, but WRITTN = 'F' will indicate that the ; disk exists. Same stuff returned in this case. GET_DISKNO: MOV ERROR, 0; Init error CALL GET_TORK; Get disk # CMP AL,' '; Reject space JE GET_DISKNO CMP AL,27; ESCAPE JNE > L2 MOV ERROR, AL STC RET; Escape error return L2: CMP AL,39h ; 4.11d - label was L1 JAE > L3 CMP AL, 031h ; 4.11d added - program did accept disk #0 JAE > L1 L3: PSTATUS VOR, ATTR10; Value out of range TICKS 16 STC RET; Error exit L1: MOV DISK, AL; Save disk # for ref. ; Now, get disk table pointer into BP: MOV ERROR,'N'; Assume disk doesn't exist CALL SET_BP ; carry clear will mean disk exists JC >L1 MOV ERROR, 'E' L1: CLC ; No error return RET ; WRITE_DISK ; This subroutine will write out a ramdisk to a physical ; disk file. When the setup program receives 'W' from user, ; this subroutine is called. WRITE_DISK: PSTATUS PRMT_DSK, ATTR9 CALL GET_DISKNO JNC >L1 CMP ERROR, 27 JNE WRITE_DISK; Value out of range if not ESC STC RET; Return with error if ESC L1: CMP ERROR,'E' JE AAK; OK if disk does exist... PSTATUS DDNE, ATTR10; Else, give error msg and retry TICKS 36 CALL FLUSH JMP WRITE_DISK AAK: CMP B[WRITTN+BP], 'F'; see if this is physical file JNE >L1 ; REV. 3.00 PSTATUS NO_WRITE, ATTR9 TICKS 50 RET L1: CMP B[F_SPEC+BP],0; See if a filename already exists JNE >L1; and don't ask if it does. 10/14/89 JMP AAJ ; Filename is assoc. with this ramdisk... L1: PSTATUS QUEFS, ATTR10; OK to use it? CALL GET_TORK CMP AL,27 JNE >L1 MOV ERROR, AL STC RET L1: AND AL,11011111xB; uppercase CMP AL,'Y' JNE AAJ ; Now, use old file spec: MOV DX,OFFSET F_SPEC ADD DX,BP MOV AH,03Dh; Open file MOV AL,1; Write access INT 021h; Call DOS JC > L1 ; 4.11 - this line did follow next line before MOV [HANDLE+BP],AX #IF DEBUGX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD #ENDIF JMP WL4 L1: PSTATUS EOPF, ATTR10; Error opening file MOV AH,0 ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 36 CALL FLUSH JMP WRITE_DISK ; Get file spec from user: AAJ: CALL GET_FSPC JNC >L1 RET; ERROR RETURN on ESC code ; Open file for write: L1: MOV DX,OFFSET RFSPEC MOV AH,03Dh MOV AL,1 INT 021h JC >L1 ; If no error, file already exists. Get permission to ; overwrite: MOV [HANDLE+BP],AX; First, save handle #IF DEBUGX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD #ENDIF PSTATUS FARE, ATTR10 CALL GET_TORK AND AL,11011111xB; Uppercase CMP AL,'Y' JNE ABH JMP WL4 ABH: MOV BX,[HANDLE+BP] MOV AH,03Eh; Close file INT 021h JMP AAK; Ask for new filename L1: CMP AX,02; ERROR 2 means file doesn't exist, JE >L1; so, go down and create it @ W6. PSTATUS EOPF, ATTR10; If other error, print error msg MOV AH,0; and retry. ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 36 CALL FLUSH JMP AAK; retry ; Now, if file not found (AX = 2), go and create new file: L1: MOV CX,0; Normal file attribute MOV AH,03Ch; Create file MOV DX, OFFSET RFSPEC; (DS assumed = CS) INT 021h JC XAAM; *** REV 2.4: THIS STMT WAS AFTER NEXT STMT*** MOV [HANDLE+BP],AX; Save handle #IF DEBUGX PUSH AX, BX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF ; Now, put pathname in field for this disk: PUSH CS POP DS MOV SI,-1 MOV CX,54; 54 bytes, max W19: INC SI; Move 54 bytes, or until byte = 0 moved. MOV AL,[RFSPEC+SI] MOV [F_SPEC+BP+SI],AL LOOP W19 JMP WL4 XAAM: PSTATUS ECF, ATTR10 MOV AH,0 ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 36 CALL FLUSH JMP AAK ; Now, set up the header and put it: WL4: MOV AX, CATARI; File type identifier MOV HEADER,AX MOV AX,[LO_SIZE+BP]; Ramdisk size in para's MOV XSIZE, AX MOV AX,[SEC_SIZE+BP] MOV SEC_XSIZE, AX MOV AL, B[DSK_FLAGS] ; rev 4.05 saves disk flags with header MOV H_FLAGS, AL ; Put 16 bytes: ; *** NOTE: ASSUMED THAT CREATE FUNCTION ALSO ; LEFT FILE OPEN FOR WRITE. CALL HEADER_0 ; fill unused header bytes w/0s MOV AH,040h; Write MOV BX,[HANDLE+BP] MOV CX,16 PUSH CS POP DS MOV DX,OFFSET HEADER INT 021h JNC >L1; No error CALL WRITE_ERROR; status and close file JMP WRITE_DISK ; Now, do # of bytes written match # requested to write? L1: CMP AX,CX JE >L1; OK if equal CALL PART_REC; status and close file JMP WRITE_DISK ; Now, put the rest of the file: L1: MOV AX, [LO_SIZE+BP]; Size in paragraphs MOV BX,0 MOV CX,4 L1: SHL BX,1; Need to shift BX too, it's a 32 bit shift! SHL AX,1; four shifts will give # of bytes ADC BX,0; and carries will be # of 64K segments LOOP L1 ; Now since DOS can't handle 64K at a time, I'll split ; the 64K chunks into 32K each: SHL BX,1; Twice as many ; Now, BX has # of 32K segments and AX has remainder PUSH AX; Save remainder MOV DI,0 CMP BX,0; No 32K segments? JE AAN AAO: PUSH BX MOV BX,[HANDLE+BP] MOV AX,[STARS+BP]; Starting segment for ramdisk ADD AX,DI; DI increments 32K per iteration MOV DS,AX MOV DX,0; Write data to DS:0000 MOV AH,040h; WRITE command MOV CX,08000h; Write 32K bytes INT 021h PUSH CS POP DS JNC >L1 CALL WRITE_ERROR POP BX,AX JMP WRITE_DISK ; Now, do # of bytes written match # requested to write? L1: CMP AX,CX JE >L1; OK if equal CALL PART_REC POP BX,AX JMP WRITE_DISK ; Now, are there more 32K sections? L1: ADD DI,0800h; INC DI by 32K in paragraphs POP BX DEC BX CMP BX,0 JNE AAO ; Now, put the remainder bytes if there are any: AAN: POP CX; This value went on stack as 'AX' CMP CX,0; Any remainder? JE AAP MOV AX,[STARS+BP] ADD AX,DI MOV DS,AX MOV DX,0 MOV AH,040h MOV BX,[HANDLE+BP] INT 021h PUSH CS POP DS JNC >L1 CALL WRITE_ERROR JMP WRITE_DISK ; Now, do # of bytes written match # requested to write? L1: CMP AX,CX JE AAP; OK if equal CALL PART_REC JMP WRITE_DISK AAP: MOV AH,03Eh; Close file MOV BX,[HANDLE+BP] #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h MOV B[WRITTN+BP],'N'; REV 1.07 - *** SHOW HAS BEEN SAVED *** CALL COLOR_FFIELD CALL SU_DSKHDR; Update filename field RET; DONE! 10/1/89 ; WRITE_ERROR ; A subroutine to report a write error and then close ; the file of handle @ [HANDLE+BP] WRITE_ERROR: PSTATUS EWF, ATTR10; NOTIFY... MOV AH,03Eh; and close file MOV BX,[HANDLE+BP] #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h TICKS 36 CALL FLUSH RET ; PART_REC ; A subroutine to report a partial record has been written, ; and close the affected file of handle @ [HANDLE+BP] PART_REC: PSTATUS PARTW, ATTR10 MOV AH,03Eh MOV BX,[HANDLE+BP] #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h TICKS 36 RET ; INEXTS - init the NEXTS variable: ; create a segment starting at the end of this program ; for the ramdisk area. Assumed free memory above. Could check ; limit against top of memory found at 2nd word of PSP. W[0002] INEXTS: PUSH CS ; get program segment POP BX MOV AX,OFFSET NEXT_SEG ; end of last module ADD AX,4 ; padding MOV CL,4 ; divide it by 16 for # paragraphs SHR AX,CL ADD BX,AX ; create ramdisk segment INC BX ; Plus 1 for safety MOV NEXTS, BX ; save for CRUD routine. MOV CX,DS:[02] ; top of memory in para's SUB CX,BX ; compute amount of free ram MOV RAM, CX RET ; ZSTARS - a routine to set the STARS variables to 0 to ; indicate no ramdisks have been set up. ZSTARS: MOV AX,0 MOV [STARS+BLOCK_SIZE],AX MOV [STARS],AX MOV [STARS+2*BLOCK_SIZE],AX MOV [STARS+3*BLOCK_SIZE],AX RET ; HEADER_0 - sets unused header bytes to 0s ; to be used before writing file HEADER_0: PUSH CX, AX, SI FILL 0, [TUNUSED], 5 POP SI, AX, CX RET ; ******************************************************************* ; ; READ_DSK ; ; This is the subroutine which will load an atari disk image ; from a PC disk file into a ramdisk area. When user chooses ; option 'L' this subroutine is executed. READ_DSK: MOV LOAD_OPT, ' '; 3.17 clear any former /P option ; First, tell the user what info is needed: CALL CLR_INFO PRINTL RD1 L7: PSTATUS RD2, ATTR9 ; Get disk # from user: CALL GET_TORK CMP AL, 27; ESC? JE >X7 SUB AL, '1' ; make AL 0 -7 CMP AL, 8 JB >X5 JAE >X6 X7: CALL CLR_ALL MOV AX, ' ' ; in case calling program expects disk # RET; ESC means quit this subroutine X6: PSTATUS VOR, ATTR10 TICKS 36 CALL FLUSH JMP L7 X5: ADD AL, '1' ; convert back to ASCII '1' - '8' MOV DISK,AL; Save disk # ; PUSH AX ; MOVED TO LOCATION F2 BELOW ; CURSET C_INFO1 ; PRINTLA SLASHES, ATTR9 ; POP AX ; Now, see if disk already installed. As of REV 3.00 I'm not going ; to allow loading a ramdisk over an existing image! User should ; renumber the existing disk or uninstall it first! CALL SET_BP ; carry clear if disk already exists JC >X4 PSTATUS X10, ATTR10 ; disk already exists!! TICKS 45 JMP READ_DSK ; Now, get filespec X4: CALL FIND_MT ; assign an open block and set up BP for it JNC > L1 PSTATUS ALLUSED, ATTR10 TICKS 50 CALL UN_DISK JMP X7 L1: MOV AL, DISK MOV [N_DISK+BP], AL MOV B[N_DISK+BP+1], ':' ;BUG_HERE: CMP TAIL_CNT, 0 ; any chars in tail? JE > F1 MOV DI, RFSPEC CALL GET_TAILS MOV B[DI], 0 ; make it ASCII, DI is pointed to end of string + 1 JMP AL1 F1: CALL LGET_FSPC ; 4.11 - get from file list JNC > F2; Carry means ESC pressed MOV B[N_DISK+BP], ' ' MOV B[N_DISK+BP+1], ' ' JMP X7 ; At F2, the file name came from LGET_FSPC, DI is pointing to 1 + the 0 ; of the ASCIIZ filename ... ; So now, request the load options and add them to the string ... F2: DEC DI PUSH DI MOV OPT_CNT, 0 ; initialized count of options (2 max) CURSET C_INFO1 PRINTLA SLASHES, ATTR9 MOV AL, ' ' CALL PRINT1 POP DI F4: CALL GET_UP CALL PRINT1 INC OPT_CNT CMP AL, 13; CR? JE > L1 CMP AL, 'P' JNE > F3 F5: MOV B [DI], '/' INC DI MOV B [DI], AL INC DI CMP OPT_CNT, 2 JNE F4 JE > L1 F3: CMP AL, 'N' JE F5 DEC OPT_CNT ; invalid keypresses don't count JMP F4 ; At L1, we have the filename and load options at RFSPEC, regardless of where ; they came from. AL1: L1: MOV B[LOAD_OPT], ' ' ; assume no load option FIND_BYTE RFSPEC, '/', 54 JNZ >L1; not found MOV AL, [DI]; DI points to 1 past '/' AND AL, 11011111xB; convert to uppercase ; load option P gets used later in LOAD_OPT, so put any P found there ; load option N gets used to set the "don't clear" bit, so just use it ; that way. So both load options can be used. MOV BYTE PTR [DI-1], 0; pathname must be ASCIIZ cover 1st "/" CMP AL, 'P' JNE > O1 MOV [LOAD_OPT], AL JE > O2 ; forced branch O1: CMP AL, 'N' JNE > O2 OR B[DSK_FLAGS+BP],1; set 'don't clear file' bit ; Now, see if there's a second load option (leading / is optional) O2: MOV AL, [DI+1] CALL TO_UPPER O6: CMP AL, 'P' JNE > O3 MOV [LOAD_OPT], AL JE > L1 ; O4 for finished with load options - forced branch O3: CMP AL, 'N' JNE > O5 OR B[DSK_FLAGS+BP], 1; set 'don't clear file' bit JE > L1 ; forced branch O5: CMP AL, '/' ; if leading /, check one more byte JNE > L1 ; Not P, N, or /, so no more load options MOV AL, [DI+2] CALL TO_UPPER JE O6 ; forced branch ; Now, we have a filespec, so try to open it... L1: MOV DX, OFFSET RFSPEC ; the filespec string... MOV AL,00000010xB ; Read/WRITE access mode REV 3.00 MOV AH,03Dh ; Open file command INT 021h ; Call DOS JNC >L1 ; Carry clear means no error... ; If error opening file: PSTATUS EOPF, ATTR10 MOV AH,0 ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 36 CALL FLUSH MOV B[N_DISK+BP], ' '; disk does no longer exist! MOV B[N_DISK+BP+1], ' ' JMP X4 ; If file open was OK: L1: MOV [HANDLE+BP], AX ; Save the file handle #IF DEBUGX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC field #ENDIF ; Now, read in 16 bytes of file header READ_FILE [HANDLE+BP], 16, HEADER, K11 PSTATUS WERF, ATTR10 TICKS 36 CALL FLUSH MOV B[N_DISK+BP], ' ' MOV B[N_DISK+BP+1], ' ' JMP X4 ; Is first byte the checksum ATARI identifier? K11: MOV W[SEC_PTR+BP],1; in case this ends up as file access MOV AX, HEADER; K11 used in macro call above CMP AX, CATARI JE >L1; Jump if good I.D. PSTATUS NATDSK, ATTR10 TICKS 36 CALL FLUSH MOV WORD PTR [N_DISK+BP], 02020h ; two spaces JMP COUT ; Close file and re-start ; Now, see if user wants to FIX word in pre-rev 3.00 file: ; 4.11 - this is no longer advertised in instructions L1: CMP B[LOAD_OPT], 'X' JNE >L1 ; nope CMP HI_XSIZE, 0; if already 0, it's no big deal JE >L1 PSTATUS FIXBUG, ATTR10 CALL GET_TORK AND AL, 255 - 32; convert to upper: rev 3.08 CMP AL, 'Y' JNE >L1 PSTATUS REMIND, ATTR10 TICKS 54 MOV HI_XSIZE, 0 ; This fixes it!!! ; This part is to get size 'choice' from actual size in ; paragraphs, to use in status update: L1: MOV SIZE_CH, 4 ; assume custom CMP HI_XSIZE, 0 ; IF there's a high word, it's custom JNE >L1 MOV AX,CS MOV ES,AX MOV AX, XSIZE MOV DI, OFFSET SIZES CLD MOV CX,5; THREE DISK SIZES AVAILABLE, PLUS ERROR REPNE SCASW; Scan SIZES table, CX = 3 - ENTRY #. MOV AL,4 SUB AL,CL; Now, AX holds choice 0,1,2,3 and 4 if custom. MOV SIZE_CH, AL ; Now set up additional information: L1: MOV AL, H_FLAGS ; 4.01 - copy flags from header to TABLE AND AL, 00110000xB ; at present just look at b4 and b5 OR [DSK_FLAGS+BP], AL ; transfer copy protect & write protect bits MOV AX, XSIZE; Set up info for CRUD routine MOV [LO_SIZE+BP],AX MOV DX, HI_XSIZE ; REV 3.00 MOV HI_SIZE[BP], DX ; "" MOV BX, SEC_XSIZE MOV [SEC_SIZE+BP],BX AND B[TYPE_CODE+BP],11111011xB MOV CCRUD,'C'; CRUD needs user's choice of density, C or 2... CMP BX,128 JE >L1 MOV CCRUD,'Z' OR B[TYPE_CODE+BP], 00000100xB ; Now set up the max. number of sectors variable, equal ; to size in para's divided by sector size in para's. ; except for double density, add 2 because first 3 sectors ; are always 128 bytes L1: MOV CL,4; CAN'T USE SHR BL,4 ON 8086 SHR BX,CL; Since numerator is in paragraphs **** 11/27/89 DIV BX; DX:AX/BX, result is in AX and equals max sectors MOV [MAX_SEX+BP],AX CMP W[SEC_SIZE+BP], 080h; single? JE >L1 ; then no adjustment ADD W[MAX_SEX+BP], 2 L1: MOV DX, HI_XSIZE MOV AX, XSIZE MOV BL, SIZE_CH; CRUD needs SIZE_CH*2 in BX, so... MOV BH,0 SHL BX,1 CALL ENTRY; Entry point into CRUD when above info set. JC >L1; No carry, no error CMP B[WRITTN+BP], 'F' JNE ADB ; read disk data into RAM for RAM disk JMP AAY ; update screen and return for "F" disk ; continue below if CRUD reported an ERROR: L1: MOV WORD PTR[SEC_SIZE+BP],080h; Cancel size entry if error MOV WORD PTR [LO_SIZE+BP],0; Same MOV WORD PTR [N_DISK+BP], 02020h ; 2 spaces COUT: MOV BX,[HANDLE+BP]; ENTRY FOR CLOSE AND RESTART MOV AH, 03Eh; Close file #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h JMP X4; Start over ; Now, we're at last ready to move disk info into RAMDISK ; First put the header info into the table: ADB: MOV AX, XSIZE MOV [LO_SIZE+BP],AX MOV CX, SEC_XSIZE MOV [SEC_SIZE+BP],CX ; Status disk as NOT written: MOV B[WRITTN+BP],'N' MOV B[WRITTN+1+BP],',' CALL COLOR_FFIELD ; Now read in the file into the RAMDISK area: MOV BX,0 MOV CX,4 L1: SHL BX,1 SHL AX,1 ADC BX,0; Add in carry LOOP L1 ; Now since DOS can't read 64K at a time, break BX into ; 32K sections: SHL BX,1 ; Now AX holds remainder and BX holds # of 32K blocks PUSH AX MOV DI,0; Segment counter CMP BX,0; First pass: no 32K blocks JNE AAW; REV 1.05 HAD TO ADD JMP AAV JMP AAV AAW: PUSH BX MOV BX,[HANDLE+BP] MOV CX,08000h; Read 32K MOV AX,[STARS+BP] ADD AX,DI MOV DS,AX MOV DX,0 MOV AH,03Fh; Read from file INT 021h PUSH CS POP DS JNC AAX; Jump if no error CMP AX,CX JAE >L1 PSTATUS REOF, ATTR10; End of file error TICKS 54 CALL FLUSH JMP AAX L1: PSTATUS WERF, ATTR10; Other type error TICKS 36 AAX: ADD DI,0800h; Increment to next 32K block POP BX DEC BX CMP BX,0; Any 32K blocks to go? JE AAV; Loop back if yes JMP AAW ; Now, get the remainder bytes... AAV: POP AX MOV CX,AX MOV BX,[HANDLE+BP] MOV AX,[STARS+BP] ADD AX,DI MOV DS,AX MOV DX,0 MOV AH,03Fh INT 021h PUSH CS POP DS JNC AAY; No error CMP AX,CX; AXL1 PSTATUS REOF, ATTR10 TICKS 36 JMP AAY L1: PSTATUS WERF, ATTR10; For other type read errors... TICKS 36 AAY: CALL MOV_FSPEC ; move RFSPEC to F_SPEC[BP] CALL SU_DSKHDR CMP B[WRITTN+BP], 'F' ; if file access, don't close JE > L2 MOV BX,[HANDLE+BP] ; 4.11 - added close file, wasn't getting done MOV AH, 03Eh; Close file #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h JNC > L2 ; if no error closing file ... PSTATUS ECLOSE, ATTR9 MOV AH,0; AX contains error code ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 50 L2: RET ; A routine to move the filespec from RFSPEC to the filespec area ; pointed to by F_SPEC[BP]: ; replace MOV_FSPEC with one which gets the whole path. 4.11 COMMENT\ MOV_FSPEC: ; Put the filespec string to the status area of BLOCK: PUSH CS PUSH CS POP ES POP DS CLD MOV CX,54 MOV DI,OFFSET F_SPEC ADD DI,BP MOV SI,OFFSET RFSPEC REP MOVSB RET ENDOFCOMMENT\ ; MOV_FSPEC - 4.11 adapted from GETPATH MOV_FSPEC: FIND_BYTE NEWDRIVE, 0, 67 ;; DI will point to end + 1 L1: DEC DI CMP B [DI], '\' ; search backwards for last \ JNE L1 MOV CX, DI SUB CX, NEWDRIVE INC CX ; get # of bytes to move MOV DI,OFFSET F_SPEC ; want to put string at F_SPEC + BP ADD DI,BP MOV SI, NEWDRIVE CLD REP MOVSB ; That gets drive and path and last \, now get filename. DI should already ; point to proper next location MOV SI, RFSPEC ; location of filename only L2: MOV AL, B [SI] MOV B [DI], AL CMP AL, 0 ; was ending 0 just moved? JE > L1 ; if so, we're done INC SI INC DI JMP SHORT L2 L1: RET ; This routine takes the choice for the standard disk size ; (64K, 92K, 143K, 184K) and puts the information into the ; required fields. AL will contain the choice, 0 - 3, on entry. ; The size in paragraphs is returned: low part in AX, high in DX. ; BX contains SIZE_CH * 2 on return STD_SIZE: MOV BH,0 MOV BL,AL SHL BX, 1 ; address word PUSH BX MOV AX, [SIZES+BX] ; get size in paragraphs MOV DX, 0 MOV [HI_SIZE+BP], DX MOV [LO_SIZE+BP], AX MOV BX,[SEC_SIZE+BP]; Sector size; *** 11/27/89 MOV CL,4; CAN'T USE SHR BL,4 ON 8086 SHR BX,CL; Since numerator is in paragraphs MOV DX,0; high 16 bits of numerator DIV BX; DX:AX/BX, result is in AX and equals max sectors MOV [MAX_SEX+BP],AX CMP W[SEC_SIZE+BP], 080h; single? JE >L1 ; then no adjustment ADD W[MAX_SEX+BP], 2 L1: POP BX OR b[DSK_FLAGS+BP], 00000010xb; rev 3.06 - start not configurable RET ; This routine is called from CRUD and gets information from the ; user as to the desired size of the ramdisk. It gets the size ; in sectors and converts to memory size. *** REV 3.00 *** CUS_SIZE: MOV ERROR, ' ' CMP AL, 5 JNE >L2 CALL SHO_MOR JNC AEN MOV ERROR, 'E' RET L2: ; MOV AL, 'Q'; 'Q' is location code ; CALL PUT_LOC MOV ERROR, 'N' ; plan to return no error PSTATUS CUSTOM, ATTR9 COMMENT\ REMOVING DOS CALL MOV MAXDEC, 6 ; Max # of digits to read; 3.01 made 5 - 6 MOV AH,0Ah; DOS buffered input function PUSH CS POP DS MOV DX, OFFSET MAXDEC INT 021h CMP B[DECIMAL],0Dh; just ENTER pressed? JNE >L1 ENDOFCOMMENT\ ; REV 3.17 uses GET_TORK type input instead of DOS MOV CX, 5 MOV BX, OFFSET DECIMAL CALL GET_STR JNC > L1 CSIZRT: MOV ERROR, 'E' ; means error; abort command RET L1: MOV BX, OFFSET DECIMAL CALL RANGE10; make sure digits rcvd are OK, carry clear is good JC CSIZRT ; go back if digits are bad ; now move digits to printing field: SMOVE DECIMAL, USRSZ, 6 MOV BX, OFFSET DECIMAL CALL DECTOINT; convert ASCII number to integer in AX AEN: MOV W[MAX_SEX+BP], AX ; keep max # of sectors MOV W[SEC_SIZE+BP], 080h; assumed for now AND B[TYPE_CODE+BP], 11111011xB; single density CMP AX, 3; 3 is minimum number of sectors allowed JA >L1 MOV W[MAX_SEX+BP], 3 MOV W[LO_SIZE+BP], (128*3)/16; size in para L1: SUB DX, DX; DX will hold high bits of result SUB AX, 3; subtract off 3 single density sectors CMP CCRUD,'Z' ; 'Z' means double density JNE >L1 MOV W[SEC_SIZE+BP], 0100h; 256 byte double density OR B[TYPE_CODE+BP], 00000100xB; set bit for double SHL AX, 1; this, plus 3 shifts below makes 16 para/sector ADC DX, 0 ; Rev 3.01 change: I was previously shifting only AX and adding ; the carries to DX. DX must be shifted too! L1: SHL DX,1 SHL AX, 1 ; times 2 ADC DX, 0 ; carry to DX SHL DX,1 SHL AX, 1 ; times 4 ADC DX, 0 SHL DX,1 SHL AX, 1 ; times 8 ADC DX, 0 ; Now, add in the constant # of paragraphs for the first 3 ; single density sectors: ADD AX, 08h*3 ; 08 is 080h/010h: paras in 1 sector ADC DX, 0 ; At this point AX holds the low # of paragraphs and DX holds the high MOV LO_SIZE [BP], AX ; Update table MOV HI_SIZE [BP], DX ; and high part too ; Return to CRUD RET ; SHO_MOR gives the user a list of standard disk sizes to choose from ; and returns with carry clear and # of sectors in AX. SHO_MOR: CALL CLR_SCRN PSTATUS ASS_SIZE, ATTR9 CURSET 0300h CMP CCRUD, 'Z' JNE >L2 PRINTL DS_SIZES ; Here, do double density. # of choices is 7 CALL GET_TORK SUB AL, '1' CMP AL, 7 JB >L1 CALL FIX_SCRN STC RET L1: XOR AH, AH SHL AX, 1 ; Point to word MOV BX, AX MOV AX, [DN_SECTS+BX] JMP > L5 ; good exit ; Below, do single density; # of choices is 12 L2: PRINTL SS_SIZES CALL GET_TORK CALL HEXDIGIT ; convert hex digit to number in AL DEC AL ; tables 0 based JNC > L1 L4: CALL FIX_SCRN STC RET L1: CMP AL, 11 JA L4 L1: XOR AH, AH SHL AX, 1 ; Point to word MOV BX, AX MOV AX, [SN_SECTS+BX] L5: PUSH AX CALL FIX_SCRN POP AX CLC RET ; This subroutine attempts to set up the 12 byte configuration table ; based on the disk size in paragraphs and density. If this doesn't ; match a standard, a default is used. DO_CFINFO: SUB SI,SI; counter for byte tables MOV AX, [HI_SIZE+BP] MOV BX, [LO_SIZE+BP] MOV CX, 12; Number of standard sizes to check for single MOV DI, OFFSET SPARAS; Assume single density TEST B[TYPE_CODE+BP], 4; DOUBLE DENSITY IF b2 SET JE >L9 MOV DI, OFFSET DPARAS MOV CX, 7 ; 7 sizes to check for double density L9: CMP BX, [DI]; low word JNE >L1 CMP AX, [DI+2]; high word JE FOUNDIT L1: ADD DI, 4; address next DWORD INC SI LOOP L9 JMP NO_MATCH FOUNDIT: TEST B[TYPE_CODE+BP], 4; DOUBLE DENSITY IF b1 SET JE >X1 ; go there for single density MOV AL, [DSTRACKS+SI] MOV [TRACKS_SIDE+BP],AL MOV AL,[DSSECS+SI] MOV AH,0 MOV [SECS_TRAK+BP],AX MOV AL,[DSSIDES+SI] MOV [SIDE_CODE+BP],AL JMP > X2 ; normal exit X1: MOV AL, [STRACKS+SI] MOV [TRACKS_SIDE+BP],AL MOV AL,[SSECS+SI] MOV AH,0 MOV [SECS_TRAK+BP],AX MOV AL,[SSIDES+SI] MOV [SIDE_CODE+BP],AL X2: MOV ERR_CHAR,'~'; to tell user std size has been found; 3.07 CALL PUT_ERCH RET ; If non standard, assign all sectors to tracks per sector and ; make # tracks = 1, per MYDOS convention NO_MATCH: MOV AX, [MAX_SEX+BP] MOV [SECS_TRAK+BP],AX MOV B[TRACKS_SIDE+BP],1 MOV B[SIDE_CODE+BP],0 ; single side RET ; A routine to create a blank disk file in response to a CREATE ; command when the requested disk is too large to be a ramdisk: ; Returns with carry set if user wants to call it all off. DO_BLANK: ; MOV AL, 'R'; 'R' is location code for this routine ; CALL PUT_LOC CALL GET_FSPC ; ASCIIZ pathname is @ RFSPEC on return JC ACK; Escape not pressed if carry clear ; Now, see if file already exists: L1: MOV AH,4Eh; DOS find first match MOV CX,00h; Attribute to find normal files & directories PUSH CS POP DS MOV CRITIC, 0; critical error not ignored MOV DX,OFFSET RFSPEC INT 021h ; Note: carry set on error. AX = 2 means no match found; 3 means ; invalid path ( note AX = 12h means no more files. How that differs ; from no match, I don't know.) JNC >L1; No carry means file already exists XOR AX, 010h; to make 012h = 02h ( trim hi nybble of AL ) CMP AX, 2; No match means ok to create JE ACJ CMP AX, 3 ; Bad path? JNE ACK; if AX not 2 or 3 - must have been critical error PSTATUS BADPATH, ATTR10 TICKS 45 JMP DO_BLANK ACK: STC RET L1: PSTATUS FARE, ATTR10 CALL GET_TORK AND AL,11011111xB; Uppercase CMP AL,'Y' JE ACJ JMP DO_BLANK ; Now, open file for READ/WRITE: ; Note: function used will CREATE a file, or truncate an existing ; one to zero length. Leaves open for read/write: ACJ: MOV AH, 03Ch; DOS function MOV CX, 00h ; Normal file attribute MOV DX, OFFSET RFSPEC MOV CRITIC, 0 INT 021h JNC >L1 ; Branch to no error PSTATUS EOPF, ATTR10 MOV AH,0; AX contains error code ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 54 JMP DO_BLANK ; Now, set up the header and put it: L1: CALL HEADER_0 ; zero unused header bytes MOV HANDLE[BP], AX ; Save handle #IF DEBUGX PUSH AX, BX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF MOV AX, CATARI; File type identifier MOV HEADER,AX MOV AX,[LO_SIZE+BP]; Ramdisk size in para's MOV XSIZE, AX MOV AX,[HI_SIZE+BP] ; Hi part of above MOV HI_XSIZE, AX MOV AX,[SEC_SIZE+BP] MOV SEC_XSIZE, AX ; Put 16 bytes: ; *** NOTE: ASSUMED THAT CREATE FUNCTION ALSO ; LEFT FILE OPEN FOR WRITE. MOV AH,040h; Write MOV BX,[HANDLE+BP] MOV CX,16 PUSH CS POP DS MOV DX,OFFSET HEADER INT 021h JNC >L1; No error CALL WRITE_ERROR; status and close file ADU: JMP ACK ; Return with carry set ; Now, do # of bytes written match # requested to write? L1: CMP AX,CX JE >L1; OK if equal CALL PART_REC; status and close file JMP ACK ; Now, it's time to fill the file with all blanks ; first see if there's enough ram to do 4K at a time: L1: CMP RAM, 0100h; 100h paras = 4K JB >L1 CALL USE_4K JC ADU ; carry set is bad return JMP ADT CALL Z_SECBUF; Fill SECBUF with all zeroes MOV CX, MAX_SEX[BP]; Loop counter: # of sectors ; Loop to fill entire file with 0s: ATU: PUSH CX ; Save loop counter MOV BX, [HANDLE+BP] MOV AH, 040h; Write to file MOV CX, SEC_XSIZE; # of bytes to write MOV DX, OFFSET SECBUF INT 021h JNC >L1 ; no error CMP AX, CX ; Check for partial record (disk full) JE ACL CALL PART_REC POP CX ; Fix stack JMP ACK ACL: CALL WRITE_ERROR POP CX JMP ACK L1: POP CX LOOP ATU ; Now the whole file has been written. Position the file ; pointer to sector #1 and update sector pointer ADT: MOV BX, HANDLE[BP] MOV AH, 042h ; Set file pointer MOV AL, 00 ; Method: offset from start of file SUB CX, CX ; MSB of offset = 0 MOV DX, 16 ; Start access with 17th byte INT 021h JNC >L1 PSTATUS ESFP, ATTR10 ; Error setting file ptr MOV AH,0; AX contains error code ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 54 JMP ACK L1: MOV W[SEC_PTR+BP], 1 MOV B[WRITTN+BP],'F' ; Show this is physical file MOV B[WRITTN+1+BP], ',' ; access CALL COLOR_FFIELD ; Make the field green ; (some of the code below was copied from WRITE_DISK) ; Now, put pathname in field for this disk: PUSH CS POP DS MOV SI,-1 MOV CX,54; 54 bytes, max W19X: INC SI; Move 54 bytes, or until byte = 0 moved. MOV AL,[RFSPEC+SI] MOV [F_SPEC+BP+SI],AL LOOP W19X CALL SU_DSKHDR ; Update screen MOV DUN_BLANK, 0FFh CLC ; Good return RET ; USE_4K fills up a disk 4K at a time instead of a sector at a time ; before calling, make sure 4K is available starting at NEXTS USE_4K: ; first, fill that 4K block with 0's: MOV ES, NEXTS ; starting segment of free memory MOV CX, 2048 ; # of words to move MOV DI, 0 ; starting offset MOV AX, 0 ; word to write into memory REP STOSW MOV DX, [HI_SIZE+BP] ; high part of size in paragraphs MOV AX, [LO_SIZE+BP] ; low part MOV BX, 0100h DIV BX ; gets # of 4K blocks into AX, remainder to DX MOV REMAIN, AX ; actually, saving quotient here... ; first take care of the remainder #: MOV CL, 4 SHL DX, CL ; remainder is in paragraphs MOV CX, DX ; # of bytes to write MOV BX, [HANDLE+BP] MOV AH, 040h; Write to file MOV DX, 0 ; offset of memory block PUSH DS MOV DS, NEXTS ; segment INT 021h POP DS JNC >L1 ; no error CMP AX, CX ; Check for partial record (disk full) JE ADS ; other type error CALL PART_REC POP CX ; Fix stack JMP ADQ ; now write 4K blocks of 0's, CX times L1: MOV CX, REMAIN; recover # of 4K blocks ADR: PUSH CX ; Save loop counter MOV BX, [HANDLE+BP] MOV AH, 040h; Write to file MOV CX, 4096; # of bytes to write MOV DX, 0 ; offset of memory block PUSH DS MOV DS, NEXTS INT 021h POP DS JNC >L1 ; no error CMP AX, CX ; Check for partial record (disk full) JE ADS ; other type error CALL PART_REC POP CX ; Fix stack JMP ADQ ADS: CALL WRITE_ERROR POP CX JMP ADQ L1: POP CX LOOP ADR ; we're done, so do good return: CLC RET ADQ: STC ; error return RET ; XCHANGE - A routine to swap the ID's of two ramdisks. XCHANGE: PSTATUS TX11, ATTR9 CALL GET_TORK CMP AL,27 ; cancel command? JNE > L1 RET L1: CALL RANGE ; converts '1' to '8' to 0 - 7 JC XCHANGE; Out of range MOV BL, AL; Save first value L2: PSTATUS TX12, ATTR9 ; 4.11d: L2 was L1 CALL GET_TORK CMP AL,27 JNE > L1 RET L1: CALL RANGE JC L2 ; 4.11d - this formerly went to L1 ADD AL, '1' ; convert them back to ASCII ADD BL, '1' ; Now, I have two good values, one in BL and one in AL CMP [N_DISK], AL JNE >L1 MOV [N_DISK], BL JMP ADG L1: CMP [N_DISK], BL JNE ADG MOV [N_DISK], AL ADG: CMP [N_DISK+BLOCK_SIZE], AL JNE >L1 MOV [N_DISK+BLOCK_SIZE], BL JMP ADE L1: CMP [N_DISK+BLOCK_SIZE], BL JNE ADE MOV [N_DISK+BLOCK_SIZE], AL ADE: CMP [N_DISK+2*BLOCK_SIZE], AL JNE >L1 MOV [N_DISK+2*BLOCK_SIZE], BL JMP ADF L1: CMP [N_DISK+2*BLOCK_SIZE], BL JNE ADF MOV [N_DISK+2*BLOCK_SIZE], AL ADF: CMP [N_DISK+3*BLOCK_SIZE], AL JNE >L1 MOV [N_DISK+3*BLOCK_SIZE], BL JMP XC_OUT L1: CMP [N_DISK+3*BLOCK_SIZE], BL JNE XC_OUT MOV [N_DISK+3*BLOCK_SIZE], AL XC_OUT: CALL SU_DSKHDR RET ; A routine to get the pathname that this program was loaded ; with. The intent is to load a new copy and virus check it. ; REV 3.03 ADDITIONS; Note: CRC calc routines are in NUMBERS.S GET_PNAME: MOV DI, 0 XOR AX,AX MOV ES, DS:[02Ch]; Get segment of environment L1: CMP WORD PTR ES:[DI],0; Checking for word 0000, but on JE >L2 ; byte boundaries, INC DI JNZ L1; don't loop forever if not found L2: ADD DI, 4; there's another word after the 0 word RET ; ES:DI now points to pathname V_CHECK: ; did user choose "no check" option? COMMENT\ ; Charley Allen birthday check MOV AH, 02Ah; get date function INT 021h CMP DL, 19 ; greater than or equal 19th of month?? JB > B1 ; skip if less JA > B2 ; don't check time if later than 19th MOV AH, 02Ch ; get time function INT 021h CMP CH, 19 ; later than 7 pm?? JB > B1 ; skip if the 19th and not later than 7 pm B2: PRINTL BDAY TICKS 150 PRINTL BDAY2 TICKS 150 PRINTL KEYWAIT CALL WAIT4KEY ; End of Charlie Allen Stuff ENDOFCOMMENT\ B1: MOV CX, 07Eh ; # bytes to check MOV DI, 081h ; command tail L1: CMP WORD PTR [DI],'V/' ; Checking for word /V, but on JE >L2 ; byte boundaries, CMP WORD PTR [DI], 'v/'; also lowercase JE >L2 INC DI LOOP L1 JMP >L3 L2: RET ; ; is there enough ram available to read in another copy of SIO2PC? L3: MOV AX, (OFFSET NEXT_SEG + 1 - 0100h) ; file length MOV CL, 4 SHR AX, CL; convert to segments INC AX; add 1 for safety = # of paras needed MOV BX, DS:[02] ; top of memory from PSP SUB BX, NEXTS ; # of paras available SUB BX, 010h; I'm going to load at NEXTS:0100 CMP AX, BX; BX is number of segments available JB >L1 PSTATUS NO_VMEM, ATTR9 TICKS 54 RET L1: CALL GET_PNAME; point ES:DI to pathname ; Now, open the file for READ MOV DX, DI MOV AH, 03Dh MOV AL, 0; READ access PUSH DS PUSH ES POP DS INT 021h POP DS JNC >L1 AEE: PSTATUS EVCF, ATTR9 RET ; now, read in the file for checking: L1: #IF DEBUGX PUSH AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP AX #ENDIF MOV BX, AX; get handle MOV VHANDLE, BX; save handle for close MOV CX, 0FFFFh; max bytes to read MOV AH, 03Fh; read file PUSH DS PUSH NEXTS POP DS MOV DX, 0100h; read file at DS:DX INT 021h POP DS JC AEE ; now check # of bytes read is correct: SUB AX, (OFFSET NEXT_SEG + 1 - 0100h) JZ >L1 MOV DI, OFFSET SAY_VLN CALL INT2DEC PSTATUS VW_LEN, ATTR9 TICKS 72 L1: MOV AH, 03Eh; first, close the file MOV BX, VHANDLE #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h CALL DO_CRC RET ; Routines to write the correct CRC to the file: W_CRC: CALL GET_PNAME; point ES:DI to pathname ; Now, open the file for WRITE: MOV DX, DI MOV AH, 03Dh MOV AL, 1; WRITE access PUSH DS PUSH ES POP DS INT 021h POP DS JNC >L1 RET L1: #IF DEBUGX PUSH AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP AX #ENDIF MOV BX, AX; get handle MOV VHANDLE, BX; save handle for close MOV AH, 042h; move pointer MOV AL, 00 ; from beginning of file MOV CX, 0 ; MSD of offset MOV DX, (CRCA-0100h); LSD of offset INT 021h MOV AH, 040h ; Write to file MOV CX, 2 ; # of bytes to write MOV BX, VHANDLE MOV DX, CAL_CRCA ; Addr of calculated CRC INT 021h ; Write file MOV AH, 03Eh ; Close file MOV BX, VHANDLE #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h RET ; SIM_IO answers all bus commands for the simulated disk SIM_IO: CMP CMND, 'R' JE SIM_READ CMP CMND, 'S'; status? JNE >L1 CALL STATUS; use existing STATUS routine CLC RET L1: CMP CMND, 'W' JE >L1 CMP CMND, 'P' JE >L1 MOV AL, 'N'; NAK for all other commands CALL PUT1 CLC RET L1: CALL PUTSEC; REV. 3.10 pretend to write to SIM disk MOV ERR_CHAR,'S'; flag write attempt to SIM disk CALL PUT_ERCH CLC RET SIM_TOTAL DW 0 SIM_READ: MOV BX, T1 CALL TIMER_0 MOV AL, 'A' CALL PUT1 MOV AL, CFAUX1 MOV AH, CFAUX2 MOV SECTOR, AX TEST B[DSK_FLAGS+BP],8; BOOT file? JE >L2 ; jump if not CMP AX, 1 ; will point to start of file if sector 1 JNE >L3 CALL POINT_0 L3: CALL GET_125 ; 128, in this case JMP SENDSEC L2: CMP AX, 361 JNE >L1 CALL SET_SIMDIR; SEND THE DIRECTORY SECTOR MOV SIM_TOTAL, 0 ; FOR DEBUGGING JMP SENDSEC L1: CMP AX, 1 JNE >L6 CALL DO_SEC1; SEND THE BOOT RECORD - SECTOR 1 JMP SENDSEC L6: CMP AX, 360 JNE >L1 CALL DO_360; SEND THE VTOC SECTOR JMP SENDSEC L1: CALL GET_125 JMP SENDSEC ; here, we are sending a data sector SENDSEC: MOV BYTE PTR [STATS+2+BP], 0FFh MOV BX, T4 CALL TIMER_0 MOV AL, 'C' CALL PUT1 MOV BX,T5; *** REV 2.5 - WASN'T ANY DELAY HERE BEFORE *** CALL TIMER_0 MOV BL,0 ; checksum MOV CX, 128 MOV SI, 0 L1: MOV AL, [SECBUF+SI] ; Get the data byte CLC ADC BL,AL ADC BL,0 CALL PUT1A ; Send it INC SI LOOP L1 MOV AL,BL CALL PUT1 ; send checksum ; TEST B[DSK_FLAGS+BP],8 ; JNE >L1 CMP [VMAX_SEX+BP],0 JNE >L1 ; now, if /N option was chosen as indicated by DSK_FLAGS B2 set ; don't clear out disk, otherwise do... TEST B[DSK_FLAGS+BP],4 JE DO_CLR_SIM CALL POINT_0 JMP >L1 DO_CLR_SIM: CALL CLOSE_SIM CALL UN_DISK CALL SU_DSKHDR L1: CLC RET DO_SEC1: SMOVE SECTOR_1, SECBUF, 16 RET DO_360: SMOVE SEC_360, SECBUF, 16 RET ; SET_SIMDIR puts a simulated directory sector in SECBUF and ; makes sure the file pointer is at the beginning of the file SET_SIMDIR: CALL Z_SECBUF; fill secbuf with 0's PUSH DS POP ES LEA SI, [SIM_ENTRY+BP] MOV DI, OFFSET SECBUF MOV CX, 16 REP MOVSB CMP B[AT_START], 0 JE >L1 CALL POINT_0 JNC >L1 PSTATUS ESFP, ATTR10 ; Error setting file ptr MOV AH,0; AX contains error code ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 54 CALL UN_DISK STC RET L1: MOV AX, [MAX_SEX+BP] MOV [VMAX_SEX+BP], AX CLC RET ; GET_125 - read in 125 bytes to SECBUF ; BP must point to data structure of simulated disk ; it also sets up the other 3 bytes for file 0, next sector 100 ; rev 3.10: If this is a BOOT disk, get 128 bytes and don't set ; up any pointers ... GET_125: MOV AH, 03Fh MOV BX, [HANDLE+BP] MOV CX, 128; ASSUME BOOT SECTOR TEST B[DSK_FLAGS+BP],8 JNE >L1 MOV CX, 125 L1: MOV DX, OFFSET SECBUF INT 021h ; On return, AX = number of bytes read, or if carry set ; AX = 5 for access denied and 6 for invalid handle. If AX < CX, then ; it was a partial read and end of file has been reached. If carry set ; and AX = 0, EOF was reached before function call ... JNC >L3 PSTATUS ERRRF, ATTR10 TICKS 55 STC ; bad return RET L3: TEST B[DSK_FLAGS+BP], 8 JNE >L1; if BOOT file; 3.11 L2: CALL S_SNXT ; GET NEW SEC # IN BX MOV [SECBUF+125],BH MOV [SECBUF+126],BL MOV [SECBUF+127], AL CMP AL, 125 ; end of file/partial sector? JE >L1 MOV B[SECBUF+126], 0; pointer of 0 means last sector MOV B[SECBUF+125],0 ; NOTE FOR BELOW: SHOULD AT_START BE PART OF STRUCTURE [BP]? L1: MOV B[AT_START], 0; file pointer not at start of file DEC [VMAX_SEX+BP] INC SIM_TOTAL JNE >L1 TEST B[DSK_FLAGS+BP],8; 3.11 JNZ >L1 MOV B[SECBUF+126], 0; just in case last sector was 125 bytes ; commemted out below line - 4.02 2/26/95 ; MOV B[SECBUF+125], 0; added with rev 4.01 ... word pointer ... AND B[SECBUF+125], 11111100xB ; bits 0 and 1 are part of pointer 4.02 L1: CLC ; good return RET ; INCREMENT SEC # AND PUT SIMULATED SECTOR # IN BX S_SNXT: MOV BX, SECTOR INC BX; SECTOR # WILL GO FROM 401 TO 700 CMP BX, 701; AND START OVER JNE >L1 MOV BX,401 L1: RET ; Close "simulated" disk file CLOSE_SIM: MOV BX, [HANDLE+BP] MOV AH, 03Eh #IF DEBUGX PUSH AX, BX MOV AX, BX ; get handle into AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP BX, AX #ENDIF INT 021h RET ; Move the file pointer to the beginning of the file NO_PTS DB 0 ; DEBUGGING: HOW MANY TIMES POINTED TO START? POINT_0: MOV AH, 042h MOV AL, 00 MOV BX, [HANDLE+BP] MOV DX, 0 MOV CX, 0 INT 021h MOV B[AT_START], 0FFh INC NO_PTS RET ; Get the size of the file in "sectors", returned in AX GET_125S: MOV AH, 042h; move pointer MOV AL, 02; from end of file XOR CX, CX XOR DX, DX MOV BX, [HANDLE+BP] INT 021h JNC >L1 RET L1: MOV BX, 125; divide DX:AX by 125; assume DOS type SIM DISK TEST B[DSK_FLAGS+BP],8 JZ >L2 MOV BX, 128 ; BOOT SIM disk; REV 3.11 L2: DIV BX; quotient to AX, remainder to DX CMP DX, 0 JE >L1; no partial sectors INC AX L1: CLC RET ; INST_PC - installs a PC file to be read as a simulated Atari ; disk image. INST_PC: L7: PSTATUS RD2, ATTR9 ; Get disk # from user: CALL GET_TORK CMP AL, 27; ESC? JE >X7 SUB AL, '1' ; make AL 0 -7 CMP AL, 8 JB >X5 JAE >X6 X7: CALL CLR_ALL MOV AX, ' ' ; in case calling program expects disk # RET; ESC means quit this subroutine X6: PSTATUS VOR, ATTR10 TICKS 36 CALL FLUSH JMP L7 X5: ADD AL, '1' ; convert back to ASCII '1' - '8' MOV DISK,AL; Save disk # ; Now, see if disk already installed. As of REV 3.00 I'm not going ; to allow loading a ramdisk over an existing image! User should ; renumber the existing disk or uninstall it first! CALL SET_BP ; carry clear if disk exists JC >X4 PSTATUS X10, ATTR10 ; disk already exists!! TICKS 45 JMP INST_PC ; Now, get filespec X4: CALL FIND_MT JNC >L1 PSTATUS ALLUSED, ATTR10 TICKS 50 JMP X7 L1: CALL CLR_INFO ; 4.11 moved these lines from start of routine to PRINTL RD1 ; here to get options after disk number INFO2 ; " PRINTL SIM_DISK ; " AND B[DSK_FLAGS+BP], 0FFh-4-8; clr bit 2&3 (default) OR B[DSK_FLAGS+BP], 2 ; make SIM disks non-configurable MOV AL, ' ' ; print a space CALL PRINT1 CMP TAIL_CNT, 0 JNE > L1 ; if chars in tail, get from there ... Q4: CALL GET_UP ; get uppercase from GET_TORK CMP AL, 13 ; Enter pressed? JE > L1 L2: CMP AL, 'B'; BOOT FILE? JNE > L4 CALL PRINT1 OR B[DSK_FLAGS+BP], 8 ; set "boot file" bit L4: CMP AL, 'N' JNE Q4 CALL PRINT1 OR B[DSK_FLAGS+BP], 4 ; set "don't clear" bit JMP Q4; GET NEXT OPTION L1: MOV AL, DISK MOV [N_DISK+BP], AL MOV B[N_DISK+BP+1], ':' ; CALL GET_FSPC ; REV 4.11 ; Here, see if bytes are available in command tail - If so, get file ; name and options from there, otherwise use FILELIST: D1: CMP TAIL_CNT, 0 ; tail empty? (Note: D1 is separate entry point) JE > F1 MOV DI, RFSPEC ; GET_TAILS puts string in [DI] CALL GET_TAILS ; get filename from tail JMP > L1 ; get any options (must follow name/no space) ; MOV B [DI], 0 ; make it ASCIIZ - later F1: CALL FILELIST ; REV 4.11 JNC > N7; Carry means ESC pressed; skip old style of entry since ; file name came from FILELIST MOV B[N_DISK+BP], ' ' MOV B[N_DISK+BP+1], ' ' JMP X7 L1: ;AND B[DSK_FLAGS+BP], 0FFh-4-8; clr bit 2&3 (default) BUG_ME: FIND_BYTE RFSPEC, '/', 54 JNZ > N7; not found MOV B[DI-1], 0 ; 3.10: file must be ASCIIZ A5: MOV AL, [DI]; DI points to 1 past '/' CALL TO_UPPER CMP AL, 'B' JE > L2 CMP AL, 'N' JE > L6 JNE > N7 ; if neither option is any good ... L4: INC DI CMP B [DI], '/' ; another slash - another option? JNE > N7 INC DI ; and get next JMP A5 L6: OR B[DSK_FLAGS+BP], 4 ; set "don't clear" bit JMP L4; GET NEXT OPTION L2: OR B[DSK_FLAGS+BP], 8 ; set "boot file" bit JMP L4 ;OR B[DSK_FLAGS+BP], 2 ; make SIM disks non-configurable ; 4.11 moved above line up ; Rev 3.05: set up /N option meaning don't clear disk when read ; is complete; reset pointer to start instead: ; Now, we have a filespec, so try to open it... N7: MOV DX, OFFSET RFSPEC ; the filespec string... MOV AL,00000000Xb ; Read access MOV AH,03Dh ; Open file command INT 021h ; Call DOS JNC >L1 ; Carry clear means no error... ; If error opening file: PSTATUS EOPF, ATTR10 MOV AH,0 ADD AL,'0'; Convert to ASCII digit CALL PRINT1 TICKS 36 CALL FLUSH MOV B[N_DISK+BP], ' '; disk does no longer exist! MOV B[N_DISK+BP+1], ' ' JMP X4 ; If file open was OK: L1: #IF DEBUGX PUSH AX CALL BYTE2HEX MOV AL, BH CALL PUT_LOC ; put handle to LOC FIELD POP AX #ENDIF MOV [HANDLE+BP], AX ; Save the file handle MOV B[WRITTN+BP], 'S' ; Flag "simulated" disk MOV W[SEC_SIZE+BP], 080h CALL GET_125S; Get # of sectors MOV [MAX_SEX+BP], AX MOV [VMAX_SEX+BP], AX MOV B[AT_START], 0FFh; file pointer is at start of file CALL MOV_FSPEC ; Move RFSPEC TO F_SPEC[BP] ; now, add /B & /N chars to status line if needed ... ; DI should be pointing to the right place due to MOV_FSPEC ; DI is pointing to 0 at end of string if it came from FILELIST CMP B [DI], 0 JNE > B2 ; don't add if string came from cmnd tail INC DI MOV AL, 8 AND AL, B[DSK_FLAGS+BP] ; boot file bit set? JZ > B1 MOV B[DI], '/' INC DI MOV B[DI], 'B' INC DI B1: MOV AL, 4 AND AL, B[DSK_FLAGS+BP] JZ > B2 MOV B[DI], '/' INC DI MOV B[DI], 'N' B2: CALL SA_PCFILE ; 4.11 ; I don't see what good any of the rest of this junk does, so ... ; YOU KNUCKLEHEAD!! This puts the simulated file's filename in the ; simulated sector so the Atari can ask for a directory and see the ; filename. 4.13 put this back in!! (Removed the COMMENT commands) ;COMMENT\ MOV CX, 11 ; clear Atari filename field LEA DI, [SIM_FN+BP] L1: MOV BYTE PTR [DI], ' ' INC DI LOOP L1 ; extract filename from pathname: CALL GET_FILENAM; returns with DI pointing to filename LEA SI, [SIM_FN+BP] PUSH DS POP ES B1: MOV AL, [DI] CMP AL, '/'; start of option JE >L1 CMP AL, 0; end of ASCIIZ JE >L1 CMP AL, '.'; start extension JE DO_EXT CALL TO_UPPER MOV [SI], AL INC DI INC SI JMP B1 DO_EXT: LEA SI, [SIM_FN+BP+8] INC DI JMP B1 L1: LEA DI, [N_DISK+BP+3] PUSH DS POP ES MOV SI, OFFSET A_PCFILE MOV CX, 7 CLD REP MOVSB ; REV 4.02 below ; PSTATUS QSIM_SPAR, ATTR9 ;; SPARTADOS FORMAT? ; CALL GET_TORK ; CALL TO_UPPER ; CMP AL, 'Y' ; JNE > S1 ; TEST B[DSK_FLAGS+BP], 00001000xB ; bit 3 means boot disk ; JNZ > S1 ; can't be both boot disk and SPARTA disk ... ; OR B[DSK_FLAGS+BP], 01000000xB ; flag this is SPARTA disk ;ENDOFCOMMENT\ S1: CALL SU_DSKHDR RET ; SA_PCFILE puts the string "PC FILE" in the string area which normally ; shows number of sectors, etc. SA_PCFILE: LEA DI, [N_DISK+BP+3] PUSH DS POP ES MOV SI, OFFSET A_PCFILE MOV CX, 7 CLD REP MOVSB RET ; GET_FILENAM searches RFSPEC and returns pointing just to the ; first character of the name, not the path: GET_FILENAM: PUSH DS POP ES MOV DI, OFFSET RFSPEC ADD DI, 54; point to high end STD ; search in downward direction MOV AL, '\'; byte to search for MOV CX, 55 REPNE SCASB JNE >L1 INC DI ; if '\' was not found, need only one INC L1: INC DI CLD; fix direction flag back RET; DS:DI (ES:DI) now points to start of name - 1.