;SYS12/ASM - LS-DOS 6.2 TITLE ; CR EQU 13 *LIST OFF ;Get SYS0/EQU *GET SYS0/EQU:2 ;Xref from lowcore/sysres *LIST ON *GET COPYCOM:3 ;Copyright message ; ORG 1E00H ; SYS12 AND 70H ;Strip bit 7 RET Z ;Back on zero entry CP 30H ;Locate module address? JP Z,GTMOD CP 20H ;Mini dir? JP Z,MDIR CP 10H ;RAMDIR? RET NZ ;Ret if any other entry ; ; RAMDIR interfacing ; HL = user buffer area ; B = drive # ; C = 0 for entire directory ; C = 1-254 for selected DEC-1 (02-FF) ; C = 255 for disk space; in use/free ; RAMDIR LD A,7 ;Ck on valid drive # CP B LD A,32 ;Init "illegal drive RET C CALL LNKFCB@ ;Save regs LD A,B ;Get drive where needed LD B,C ;Xfer DEC to B LD C,A ; & drive to C OR '0' ;Make it ASCII LD (DSTDRV+1),A ;Stuff for STUFBUF CALL CKDRV ;Be sure disk is there RET NZ INC B ;Test 0, 1-254, 255 JR NZ,DIRINFO ;Go if directory req ; ; Get FREE SPACE info ; PUSH HL ;Save buffer pointer CALL SPACE ;Get our info LD B,(HL) ;P/u free space in K DEC HL ; into BC LD C,(HL) DEC HL LD A,(HL) ;Get total space in K DEC HL ; into HL LD L,(HL) LD H,A SBC HL,DE ;Calc "in use" (CF=0) EX DE,HL ;Xfer to DE POP HL ;Rcvr user buf ptr LD (HL),E ;Stuff "in use" INC HL LD (HL),D INC HL LD (HL),C ;Stuff "free to use" INC HL LD (HL),B XOR A ;Show no error RET ; ; Do RAMDIR directory info ; DIRINFO DEC B ;If DEC=0, do it all JR Z,DOALL ;Go if all of it INC B ;1=>2, 2=>3, ..., FE=>FF ; ; Calculate the number of directory sectors ; = (#sectors x #heads) - 2 for GAT & HIT ; LD A,7 ;Get highest # sector CALL @DCTBYT LD D,A ;Store heads & sectors AND 1FH ;Rake off # sectors LD E,A ; & stuff into E INC E ;Bump for 0 offset XOR D ;Recover # heads RLCA ; into bits 0-2 RLCA RLCA INC A ;Bump for 0 offset CALL @MUL8 ;Multiply sectors x heads LD E,A ;Now check double bit LD A,4 CALL @DCTBYT BIT 5,A ;Set if 2-sided LD A,E JR Z,ONESID ;Go if not set else ADD A,A ; double value ONESID SUB 2 ;Reduce for GAT & HIT LD D,A ;D => # dir sectors LD A,B ;Get requested DEC AND 1FH CP D ;See if in range JR C,DIRINF1 ;Go if so LD A,16 ;"Illegal logical file # OR A ;Return out of range error RET ; DIRINF1 PUSH HL ;Save buffer ptr CALL @DIRRD ;Get its directory record POP DE ;Rcvr buf ptr RET NZ ;Back on an error LD A,(HL) ;Get attributes AND 0D8H ;Only if in use & VIS XOR 10H ;Flip state so NZ=no LD A,25 ;Init file access denied RET NZ ;Back on no file, SYS, INV GETSTUF PUSH HL ;Save DIR ptr CALL STUFBUF ;Stuff the filespec POP HL LD A,(HL) AND 7 ;Keep the access level LD (DE),A INC DE INC L ;Go up to EOF offset INC L INC L LDI ;Move in the offset & LRL LDI LD A,L ;Bump to ERN ADD A,15 LD L,A LD A,(HL) ;P/u ERN LD (DE),A ; and xfer it INC L INC DE LD H,(HL) LD L,A ;# sectors to HL EX DE,HL ; hence to DE LD (HL),D ;Stuff ERN High-order INC HL ;Bump buf ptr INC DE ;Adjust for rounding INC DE INC DE SRL D ;Divide by 4 to calc K RR E SRL D RR E LD (HL),E ;Xfer result into buffer INC HL LD (HL),D INC HL LD (HL),'+' ;Stuff buffer terminator EX DE,HL XOR A RET ; ; RAMDIR - Do all of the directory ; DOALL EX DE,HL ;Buffer pointer to DE CALL HITRD1 ;Read in the HIT RET NZ ;Exit if read error JR DOALL3 ; DOALL1 POP BC ;Recover HIT pointer lo LD H,DIRBUF$<-8 LD L,B ;Advance to next dir DOALL2 LD A,L ; record of this sector ADD A,32 LD L,A JR NC,DOALL3 ;Bypass if still same INC L ; else point to next one BIT 5,L ;Finished with JR Z,DOALL3 ; this drive? XOR A RET ; DOALL3 LD A,(HL) ;P/u HIT entry OR A JR Z,DOALL2 ;Jump if spare LD B,L ;Save DEC in regB PUSH BC ; & to stack LD A,L ;Pt to dir record for AND 0E0H ; this DEC LD L,A ;Get the dir sector for XOR B ; this DEC DOALL4 CP 0FFH ;Same as one in core? JR Z,DOALL5 ;Jump if so else LD (DOALL4+1),A ; update one we have and CALL @DIRRD ; read it into buffer JP NZ,MDIR12 ;Jump on read error DOALL5 LD H,SBUFF$<-8 ;Sysbuf hi order LD A,(HL) ;P/u attributes AND 0D8H ;Test FXDE & in-use XOR 10H ;If not used or FXDE JR NZ,DOALL1 ; then back to DOALL1 PUSH HL CALL GETSTUF ;Get the dir info POP HL JR DOALL1 ; ; Routine to display a mini directory ; C => drive number in binary (0-7) ; B => option, 0 = display, 1 = buffer stuff ; 2 = display /EXT, 3 = buffer /EXT ; 4 = space into buffer ; HL => address of buffer to stuff dir info & EXT ; Z <= set on valid conclusion ; NZ <= set on any error ; MDIR LD A,7 ;Test for bad drive # CP C LD A,32 ;Init "illegal drive... RET C CALL CKDRV ;Be sure disk is there RET NZ CALL LNKFCB@ ;Save the regs LD A,B ;Stuff the option LD (TSTOPT+1),A CP 4 ;If option 4, go get JP Z,SPACE0 ; space info LD A,43 ;Init "SVC parm error RET NC ;Back if option > 4 PUSH HL ;Save possible buffer PUSH BC LD DE,LILBUF ;Save possible /EXT LD BC,3 LDIR POP BC LD A,C ;Get drive # and OR '0' ; make it ASCII LD (DSTDRV+1),A LD A,5 ;Init to 5 files/line LD (MDIR11+1),A LD A,23 ; & 23 lines/page LD (CKPAGE+1),A CALL HITRD1 ;Read in the HIT POP DE ;Rcvr possible buffer RET NZ ;Exit if read error JR MDIR3 MDIR1 POP BC ;Recover HIT pointer lo LD H,DIRBUF$<-8 LD L,B ;Advance to next dir MDIR2 LD A,L ; record of this sector ADD A,32 LD L,A JR NC,MDIR3 ;Bypass if still same INC L ; else point to next one BIT 5,L ;Finished with JR Z,MDIR3 ; this drive? LD A,(TSTOPT+1) ;If option 1 or 3, AND 1 ; must stuff buffer end JR NZ,CLSBUF LD A,CR ; else do a blank line CALL @DSP XOR A RET ; CLSBUF LD A,0FFH ;Put in buffer terminator LD (DE),A XOR A RET ; MDIR3 LD A,(HL) ;P/u HIT entry OR A JR Z,MDIR2 ;Jump if spare LD B,L ;Save DEC in reg B PUSH BC ; & to stack LD A,L ;Pt to dir record for AND 0E0H ; this DEC LD L,A ;Get the dir sector for XOR B ; this DEC MDIR4 CP 0FFH ;Same as one in core? JR Z,MDIR5 ;Jump if so LD (MDIR4+1),A ;Else update one we have CALL @DIRRD ; and read it into buf JR NZ,MDIR12 ;Jump on read error MDIR5 LD H,SBUFF$<-8 ;Sysbuf hi order LD BC,MDIR1 ;Set up the return addr PUSH BC TSTOPT LD A,0 ;P/u option number PUSH HL PUSH DE CALL TSTSAM ;Check for extension match POP DE POP HL RET NZ ;Back to MDIR1 LD A,(TSTOPT+1) RRCA ;Test option 1 or 3 LD A,(HL) JR NC,DSPLYIT ;Go if 0 or 2 AND 90H ;Test FXDE & in-use XOR 10H ;If not used, FXDE RET NZ ;Back to MDIR1 LD BC,16 LDIR ;User's buffer INC L ;Bypass stored passwords INC L INC L INC L LD C,2 ; and xfer ERN LDIR RET ;Back to MDIR1 ; DSPLYIT AND 0D8H ;Test if we want this XOR 10H ;Only if in-use & VIS RET NZ ;Back to MDIR1 LD DE,LILBUF+3 PUSH DE CALL STUFBUF ;Move filespec to buffer POP HL ;Rcvr LILBUF ptr CALL @DSPLY ;Display the file MDIR11 LD A,0 ;Count down 5-across DEC A LD (MDIR11+1),A ;Update count RET NZ ;Loop if more to go LD A,5 ; else re-init LD (MDIR11+1),A LD A,CR CALL @DSP ;New line CKPAGE LD A,0 ;P/u display count DEC A LD (CKPAGE+1),A RET NZ LD A,23 LD (CKPAGE+1),A ;Reset for max CALL @KEY ;Wait for keyboard input JP @CLS ;Clear screen and ret ; MDIR12 POP BC RET ; TSTSAM BIT 1,A ;Ck if /EXT option RET Z ;Ret with Z if LD BC,13 ; option <> /EXT ADD HL,BC ;Else point to /EXT LD B,3 ; field of dir record LD DE,LILBUF ; & check for match TSTS1 LD A,(DE) CP '$' ;'$' matches with all JR Z,TSTS2 CP 'A' ;If numeric, don't cvrt JR C,$+4 ; to upper case RES 5,A ;Cvrt to UC if lc CP (HL) RET NZ ;Ret on no match TSTS2 INC HL INC DE DJNZ TSTS1 ;Loop for 3 chars RET ; ; Routine to construct the filespec field ; STUFBUF LD A,L ADD A,5 ;Pt to start of filename LD L,A LD C,13 ;Init for 15 (-2) chars LD B,8 ;Filename STUFB1 LD A,(HL) INC HL CP ' ' ;Exit on 1st space JR Z,STUFB2 LD (DE),A ;Stuff the char INC DE DEC C ;String count down DJNZ STUFB1 ;Field loop JR STUFB3 ;Bypass ext calculation STUFB2 LD A,L ;Calculate start of ADD A,B ;EXT field in dir record DEC A LD L,A STUFB3 LD A,(HL) ;Display EXT if present CP ' ' JR Z,STUFB5 ;Exit if no EXT LD A,'/' ;Display slash LD (DE),A ;Stuff the char INC DE DEC C ;Dsplay char countdown LD B,3 ;3 chars max for EXT STUFB4 LD A,(HL) INC HL CP ' ' JR Z,STUFB5 ;Exit on 1st blank LD (DE),A ; else stuff the char INC DE DEC C DJNZ STUFB4 ;Loop 3 chars STUFB5 LD A,':' ;Stuff a drive sep LD (DE),A ;Reg C already accounted INC DE ; for in the init DSTDRV LD A,0 ;P/u drive # LD (DE),A INC DE STUFB6 LD A,' ' ;Stuff a space LD (DE),A INC DE DEC C ;Count down JR NZ,STUFB6 ;Display trailing spaces LD A,3 ;Stuff the ETX LD (DE),A RET ; ; Routine to get the free space info ; SPACE0 PUSH HL ;Save buf start LD DE,16 ;Index for space PUSH DE ADD HL,DE CALL SPACE ;Get the space data POP BC ; name & date POP DE ;Now shift in the LD HL,DIRBUF$+0D0H ; disk name and date LDIR XOR A RET ; SPACE CALL @GATRD ;Read GAT RET NZ ;Ret on GAT read error PUSH IY CALL @GTDCT ;Get DCT vector EX DE,HL ;User buf ptr to DE LD H,0 ;P/u highest # cylinder LD L,(IY+6) ; & adjust for 0 offset INC HL LD A,(IY+8) ;P/u # of sectors/granule AND 1FH INC A ;Adjust for zero offset PUSH AF ;Save # of sectors/gran PUSH DE ;Save user buf ptr LD E,A LD A,(IY+8) ;P/u # of granules/cyl AND 0E0H RLCA ; & shift to bits 0-2 RLCA RLCA INC A ;Adjust for zero offset CALL @MUL8 ;Calc # of sectors/cyl BIT 5,(IY+4) ;Double sided? JR Z,$+3 ;Bypass if one-sided ADD A,A ; else double the count POP BC ;Rcvr user buf ptr CALL DOMUL16 ;Calculate total sectors INC HL ;Bump to next buf pos PUSH HL ; & save pointer LD HL,DIRBUF$ ;Pt to start of GAT LD DE,0 ;Init gran counter LD A,(DIRBUF$+0CCH) ;P/u cyl excess ADD A,35 ;Add base LD B,A ;Set loop counter PUGAT LD A,(HL) ;P/u GAT byte KEEP7 SCF ;Keep bit 7 set RRA ;Slide gran bit to carry JR C,BYTEND? ;Ignore if in use INC DE ;Free, bump gran counter BYTEND? CP 0FFH ;End of byte? JR NZ,KEEP7 ;Loop if not INC L ;Bump GAT byte pointer DJNZ PUGAT ;Loop for # cyls EX DE,HL ;# free grans -> HL POP BC ;Pop user buf ptr POP AF ;Rcvr # of sectors/gran POP IY DOMUL16 CALL @MUL16 ;Calc # of free sectors LD H,B ;Cvrt # of free sectors LD D,L LD L,C ;To free space in K by LD E,A INC DE ; dividing the # by 4 INC DE ;Round up adjustment SRL D ;Divide 16-bit reg by 2 RR E SRL D ; & divide again RR E LD (HL),E ;Stuff the value INC HL LD (HL),D RET ; ; Read the hash index table ; HITRD1 LD HL,DIRBUF$ ;Pt to buffer PUSH BC PUSH DE CALL @DIRCYL ;Dir cyl to reg D LD E,1 ;Sector one CALL @RDSSC POP DE POP BC LD A,22 ;"HIT read error" RET ; ; Routine to locate the address of a module ; DE => pointer to module name ; HL <= address of module start if found ; DE <= address of end-of-module name + 1 if found ; Z <= if found, else NZ & A = 8 ; GTMOD PUSH BC ;Save this reg pair LD C,0FFH ;Init length counter PUSH DE ;Save name start GTM1 INC C ;Bump counter LD A,(DE) ;Search for end-of-name INC DE CP ' '+1 JR NC,GTM1 POP DE ; ; Start search at system core ; LD HL,@$SYS ;Pointer to driver start ; ; Loop through core searching names ; GTM2 LD A,H ;Are we currently IF @BLD631 CP @BYTEIO<-8+1 ;<631>the driver zone? (<1400H) ELSE CP @BYTEIO<-8 ; the driver zone ? ENDIF JR NC,GTM2A ;No - check himem ; ; In the Driver zone - is it allocated ? ; PUSH BC ;Save BC LD BC,(DVRHI$) ;P/u next available OR A ; addr in Driver zone. PUSH HL ;Is this module SBC HL,BC ; accounted for in POP HL ; the driver zone ? POP BC ; JR NC,GTM8 ;No - get out of d/z ; ; Does this module have a legal header ? ; GTM2A LD A,(HL) ;Ck for "JR xx" CP 18H JR NZ,GTM7 ;Exit on non-JR PUSH HL ;Save pointer to start INC HL ;Advance to length/name INC HL INC HL INC HL LD A,(HL) ;P/u length field AND 0FH ;Strip flags CP C ;Lengths match? JR NZ,GTM5 INC HL ;Point to start of name LD B,A ;Set loop counter PUSH DE ;Save user's name pointer GTM3 LD A,(DE) ;Compare the name strings CP (HL) JR NZ,GTM4 ;Go if no match INC HL INC DE DJNZ GTM3 EX DE,HL ;Name+1 to DE ; ; Found a match - exit with info ; POP HL ;Keep DE to name end+1 POP HL ;Module start address POP BC ;Reg restoral XOR A ;Set Z-flag for return RET ; ; No match - loop to next module ; GTM4 POP DE GTM5 POP HL INC HL ;Point to last byte used INC HL LD A,(HL) ;P/u low-order INC HL LD H,(HL) ;P/u high-order LD L,A GTM5A INC HL ;Bump to next address LD A,H ;Ck for wrap to zero OR L JR NZ,GTM2 ;Loop if not through GTM6 POP BC ;Restore reg LD A,8 ;Set "device not avail... OR A RET ; ; Found non-JR - Advance to high memory? ; GTM7 LD A,H ;Past driver core? CP @BYTEIO<-8 JR NC,GTM6 ;Exit with "not found" GTM8 LD HL,(HIGH$) ; else p/u himem pointer JR GTM5A ; & hop to it if in use ; ; Check a drive for availability ; CKDRV PUSH IY ;We use IY in disk I/O CALL @GTDCT ;Get driver routine addr LD A,(IY+0) ;P/u drive vector CP 0C3H ;Ck for enabled LD A,32 ;Drive not ready JP NZ,CKDR5 ;Bypass if disabled PUSH HL PUSH DE LD A,(IY+6) ;Make sure that the current CP (IY+5) ; cylinder count is in range JP NC,CKDRV1 ;Go if in range CALL @RSTOR ;Restore drive JP NZ,CKDR7A ;Go if error ; CKDRV1 LD D,(IY+5) ;P/u current track LD E,0 ;Set for sector 0 CALL @SEEK ;Set track info to FDC JR NZ,CKDR7A ;Go if error CALL @RSLCT ;Wait until not busy JR NZ,CKDR7A ;Not there - ret NZ BIT 3,(IY+3) ;If hard drive, bypass JR NZ,CKDR3A ; GAT data update BIT 4,(IY+4) ;If "ALIEN" by pass JR NZ,CKDR2B ; test of index pulses IF @MOD4 LD A,(FDDINT$) ;Check 'SMOOTH' state OR A LD A,09 ;Set MSB of count down JR Z,INTRON ;Go if not SMOOTH SRL A ;Divide the count by two DI ENDIF IF @MOD2 LD A,20 ENDIF INTRON LD (CDCNT+1),A ;Store in 'LD H' instruction LD HL,0020H ;Set up count (short) ; ; Test for diskette in drive & rotating ; CKDR1 CALL INDEX ;Test index pulse JR NZ,CKDR1 ;Jump on index BIT 7,(IY+4) ;Check CKDRV inhibit bit JR NZ,CKDR2B ; if on skip index test CDCNT LD H,00H ;CKDRV counter (long) ;Count set from above CKDR2 CALL INDEX ;Test index pulse JR Z,CKDR2 ;Jump on no index IF @MOD4 EI ;OK for INTs now ENDIF LD HL,0020H ;Index off wait (short) CKDR2A CALL INDEX JR NZ,CKDR2A ;Jump on index ; ; Diskette is rotating ; CKDR2B PUSH AF ;Save FDC status CALL @DIRCYL ;Get directory track in D LD HL,SBUFF$ ;Point to HIT buffer LD E,L ;Sector 0 for GAT CALL @RDSSC ;Read the GAT JR NZ,CKDR7 ;Jump on error LD HL,(SBUFF$+0CCH) ;P/u excess tracks LD A,22H ;Add offset ADD A,L LD (IY+6),A ;Max track # to DCT RES 5,(IY+4) ;Set to side 0 BIT 5,H ;Test double sided JR Z,CKDR3 ;Jump if only single SET 5,(IY+4) ;Set for side 2 CKDR3 POP AF ;Recover FDC status CKDR3A RLCA ;Shift write prot to 7 OR (IY+3) ;Merge Soft WP bit AND 80H ;Strip all but 7 ADD A,A ;Write prot to carry flg ; CKDR4 EQU $ EI POP DE POP HL CKDR5 POP IY RET ; INDEX LD A,H ;Check countdown timer OR L JR Z,CKDR7 ;Err exit if 0 DEC HL CALL @RSLCT ;Check for index pulse BIT 1,A ;Test index RET ; CKDR7 POP AF CKDR7A LD A,8 ;Set Device not avail OR A ;Set NZ ret JR CKDR4 ;Exit ; IF @BLD631 LAST EQU $ ;<631> LILBUF DS 18 ;<631> ELSE LILBUF DS 18 LAST EQU $ ENDIF IFGT $,DIRBUF$ ERR 'Module too big' ENDIF ORG MAXCOR$-2 DW LAST-SYS12 ;Overlay size ; END SYS12