REM >HADFS1 v5.28 REM Block 1 of HADFS source REM *ASSEM after part 0 REM 27/11/1993: split from HADFS0 REM 27/11/1993: New FindLib, usernum extended REM Power-On message temp'y removed to save space REM 17/05/2007: NullKBD temp'y here : PRINT "Assembling S.HADFS1" REM P%=hadfs1 O%=P%-Block%+mcode% [OPT0 \ ======================= \ Filing system selection \ ----------------------- \.Hadfs:\ Shouldn't *HADFS->fx143go? .HadfsOn \JSR HadfsOn4 :\ Select HADFS \JSR WhatOS:\CPX #2:\BNE HadfsOn8 :\ BBC B+ needs to be done twice \.HadfsOn4 JSR CheckForDFS :\ Initialise DFS LDA #6:JSR FSC :\ Warn vectors about to change LDY #0:LDX #27 .TrapFSlp LDA vectors+0,Y:STA &D9F,X :\ Set extended address LDA vectors+1,Y:STA &DA0,X LDA &F4:STA &DA1,X :\ Set extended ROM number TXA:STA FILEV,Y :\ Set extended vector LDA #255:STA FILEV+1,Y INY:INY:INX:INX:INX :\ Step to next vector CPX #48:BNE TrapFSlp LDX #15:JSR fx143 :\ Vectors changed JSR GrabAbs :\ Claim and restore workspace .HadfsOn8 LDA #0:RTS :\ A=0 - claimed : .vectors EQUW file:EQUW args:EQUW bget EQUW bput:EQUW gbpb:EQUW find EQUW fsc : .CheckForDFS LDA &DF00:PHA:LDA &DF01:PHA LDA &DF03:PHA :\ Save current FS context LDY #4:JSR fx143fs :\ Try to select DFS PLA:STA &DF03:PLA:STA &DF01 :\ Restore FS context PLA:STA &DF00:TXA:RTS :\ Return A=0 - DFS present : \ ============================== \ Arithmetic and number routines \ ------------------------------ .BINtoBCD:\ Corrupts tmp PHA:LDA #10:STA tmp:PLA .BINtoBCDlp CMP tmp:BCC BCDdone ADC #5:PHA LDA tmp:ADC #16:STA tmp PLA:BCC BINtoBCDlp .BCDdone RTS : .BCDtoBIN:\ Corrupts X TAX:LDA tmp:PHA:TXA AND #&F0:LSR A:STA tmp:\ 8s LSR A:LSR A:CLC:ADC tmp:STA tmp TXA:AND #15:CLC:ADC tmp:TAX PLA:STA tmp:TXA:RTS : .HexTopDigit LSR A:LSR A:LSR A:LSR A .HexDigit AND #15:BPL DrvChr .GetDrvChr LDA drive .DrvChr CMP #10:BCC P%+4:ADC #6 ADC #48 RTS : : .PrDec32 :\ Print 32bit decimal number .PrDec24 :\ Print 24bit decimal number LDA #&98:LDY #&96:LDX #&80:JSR SubNumP:\ 10000000s LDA #&0F:LDY #&42:LDX #&40:JSR SubNumP:\ 1000000s .z% JSR PrComma :]:IF _NoCommas%:z%=P%-z%:P%=P%-z%:O%=O%-z% LDA #&01:LDY #&86:LDX #&A0:JSR SubNumP:\ 100000s : .PrDec16 :\ Print 16bit decimal number LDA #&00:LDY #&27:LDX #&10:JSR SubNumP:\ 10000s LDA #&00:LDY #&03:LDX #&E8:JSR SubNumP:\ 1000s .z% JSR PrComma :]:IF _NoCommas%:z%=P%-z%:P%=P%-z%:O%=O%-z% : .PrDec8 :\ Print 8bit decimal number LDX #&64:JSR SubNumZero :\ 100s LDX #&0A:JSR SubNumZero :\ 10s LDA numstore:BPL SubDigit :\ 1s : .SubNumZero LDA #0:TAY .SubNumP:\ sub and print JSR SubNum:BEQ SubZero .SubDigit ORA #48:JSR OSWRCH:LDA #48:STA numflg .SubZeroOk RTS .SubZero LDA numflg:BEQ SubZeroOk JMP OSASCI .PrComma LDA numflg:CMP #ASC"0":BCC SubZero :\ "" or " ", do it LDA #ASC",":JMP OSASCI :\ "0", output a comma :]:IF _NoCommas%:z%=P%-PrComma:P%=P%-z%:O%=O%-z% : \ On entry, numstore=number, &AYX = 24bit divisor \ On exit, A=numstore DIV &AYX, Z=(A=0) \ numstore=numstore MOD &AYX .SubNum STX numsub+0:STY numsub+1:STA numsub+2 .do_subs:LDX #255:SEC .SubLp:INX LDA numstore+0:SBC numsub+0:STA numstore+0 LDA numstore+1:SBC numsub+1:STA numstore+1 LDA numstore+2:SBC numsub+2:STA numstore+2 BCS SubLp:JSR AddNum \\LDA numstore+0:\ADC numsub+0:\STA numstore+0 \\LDA numstore+1:\ADC numsub+1:\STA numstore+1 \\LDA numstore+2:\ADC numsub+2:\STA numstore+2 TXA:RTS : .Get1Hex JSR GetHexNum:LDA numstore:RTS : .GetDecNum CLC:BCC GetNumber .GetHexNum SEC .GetNumber PHP:JSR Get1Num:BCS BadNumber STA numstore LDA #0:STA numstore+1:STA numstore+2 .GetNumLp PLP:PHP:JSR Get1Num BCS GotNumOk:\ PLP, JMP SkipSpc PLP:PHP:PHA:JSR Times10or16 PLA:ADC numstore:STA numstore LDA numstore+1:ADC #0:STA numstore+1 LDA numstore+2:ADC #0:STA numstore+2 BCC GetNumLp .BadNumber JSR errors:EQUB 252 EQUS "Bad number":BRK : .GotNumOk PLP:JMP SkipSpc \ Returns A=next char \ numstore=number : .TimesTen CLC .Times10or16 PHP:JSR TimesTwo:\ *2 LDA numstore+0:STA numsub+0 LDA numstore+1:STA numsub+1 LDA numstore+2:STA numsub+2 JSR TimesTwo:JSR TimesTwo:\ *8 PLP:BCS TimesTwo .AddNum LDA numstore+0:ADC numsub+0:STA numstore+0 LDA numstore+1:ADC numsub+1:STA numstore+1 LDA numstore+2:ADC numsub+2:STA numstore+2 RTS .TimesTwo ASL numstore:ROL numstore+1 ROL numstore+2:BCS BadNumber RTS : .Get1Num \ C=0, dec; C=1, hex PHP:JSR GetChar:BEQ Not1Num CMP #ASC"0":BCC Not1Num CMP #ASC"9"+1:BCC Got1Num PLP:BCC NotNumber AND #&DF CMP #ASC"A":BCC NotNumber CMP #ASC"F"+1:BCS NotNumber SBC #6:PHP .Got1Num AND #15:PLP:INY:CLC RTS:\ Valid digit .Not1Num PLP .NotNumber SEC RTS:\ Invalid digit : \ ====================== \ Text printout routines \ ---------------------- \ Corrupts tmp at &B2 and tptr at &B0/1 \ ----------------------------------------------- .PrText STA tmp:PLA:STA tptr:PLA:STA tptr+1 TYA:PHA:LDY #1:BNE PrTextInc .PrTextLp LDY #0:LDA (tptr),Y:BEQ P%+5:JSR OSASCI .PrTextInc PHP:INC tptr:BNE P%+4:INC tptr+1 PLP:BNE PrTextLp PLA:TAY:LDA tmp:JMP (tptr) : \ ================ \ Error generation \ ---------------- .file_errors :\ generates 'OBJECT errormessage' LDA #32:STA OBJECT+10:LDX #0 :\ Ensure OBJECT terminated .file_ErLp LDA OBJECT,X:STA &102,X:INX :\ Copy OBJECT to error buffer CMP #32:BNE file_ErLp STA &102,X:INX:BNE errors2 : .errors :\ Generates 'errormessage' LDX #1:.errors2 PLA:STA &B0:PLA:STA &B1:LDY #1 .error_lp:INX:INY:LDA (&B0),Y STA &100,X:BNE error_lp:STA &100 LDY #1:LDA (&B0),Y:STA &101 JMP &100 : \ ================== \ Workspace routines \ =============================== \ FindWS - Find private workspace \ ------------------------------- \ Returns ws=>private workspace \ All registers and flags preserved \ ----------------------------------------- .FindWS PHP:PHA:TXA:PHA:LDX &F4:LDA &DF0,X:AND #&F:CLC ADC #&14:STA ws+1:LDA #0:STA ws:PLA:TAX:PLA:PLP:RTS : \ ============================================= \ GrabAbs - Claim and update absolute workspace \ ------------------------------- \ Returns All registers preserved \ ------------------------------- .GrabAbs PHA:TXA:PHA:TYA:PHA:LDA ws:PHA:LDA ws+1:PHA :\ Save things JSR TimeSave:JSR GetOwnWS:BNE GrabAbsOk :\ Exit if I already own ws LDX #10:JSR fx143:JSR SetOwnWS :\ Claim ws and set flag JSR FindWS:LDY #0 .GrabAbsLp2 LDA (ws),Y:STA WS,Y:INY:BNE GrabAbsLp2 :\ Copy info to workspace LDY #CHNINFO AND 255 .GrabAbsLp3 LDA WS,Y:AND #&FC:STA WS,Y TYA:CLC:ADC #32:TAY:BCC GrabAbsLp3 :\ Clear channel flags JSR ClearDIR:STA VFLG :\ No directory in memory .GrabAbsOk PLA:STA ws+1:PLA:STA ws:PLA:TAY:PLA:TAX:PLA :\ Restore things RTS : \ ============ \ Line parsing \ ============ .SkipSpc1 INY .SkipSpc LDA(&F2),Y:CMP#ASC" ":BEQ SkipSpc1 .GetChar LDA (&F2),Y:CMP #13 RTS : .XYtoF2 STX &F2:STY &F3:LDY #0:RTS : .F2toXY PHA:TYA:CLC:ADC &F2:TAX LDA &F3:ADC #0:TAY:PLA:RTS : \ ================== \ Null Keyboard code \ ================== \\ Should move this to NullKBD module .KeyboardChk :\ Insert NullKBD if no keyboard found PHP:SEI:LDA &28F:BNE Serv1bKbd LDA &229:BPL Serv1bKbd :\ Already claimed LDX #7:.Serv1KbdLp LDA NewK,X:STA &3D0,X:DEX:BPL Serv1KbdLp :\ Copy new KEYV code LDA &228:STA &3D8:LDA &229:STA &3D9 :\ Copy old KEYV LDA #&D0:STA &228:LDA #3:STA &229 :\ Point KEYV to new code .Serv1bKbd PLP:JMP Serv1Exit : .NewK BVS OldKeyJmp:BCS OldKeyJmp:LDA #0:RTS:.OldKeyJmp:EQUB &4C : \ ====================== \ Time and date routines \ ============================================== \ TimeSave - Save current TIME, called regularly \ ---------------------------------------------- .TimeSave PHA:TXA:PHA:LDX #2:.SvTimeLp LDA &294,X:STA &3DA,X:DEX BPL SvTimeLp:PLA:TAX:PLA:RTS : \ =========================================== \ *SETDATE - Set current date and day of week \ ------------------------------------------- .SetDate JSR GetChar:BEQ setdate1 :\ No parameters, disable JSR Get1Hex:INY :\ Get date ORA #&C0:STA &3DD :\ Set date+flags in b6-b7 JSR Get1Hex:STA &3DE:INY :\ Get and set month JSR Get1Hex:STA &3DF :\ Get and set year LDX #0:JSR GetChar:BEQ setdate3:\ Exit if no day set JSR Get1Hex:ASL A:ASL A:ASL A :\ Get day, move into b5-b7 ASL A:ASL A:ORA &3DE:::BNE setdate2 :\ Store and exit ::\\STA &3DE::\\.setdate3::\\RTS .setdate1 STA &3DD:STA &3DF :\ All same=No date .setdate2 STA &3DE:::.setdate3:RTS : \ ================================== \ *TIME - Display current RTC string \ ---------------------------------- \ Returns A=length of RTC string \ EQ=no RTC available \ ---------------------------------- .Time LDY #0:STY &108:LDA #14:LDX #8 :\ Use 25 bytes at &108 INY:JSR OSWORD:LDA &108:BEQ NoTime LDX #0 .z% LDA &114:CMP #ASC"9":BNE TimeLp :\ Not 19xx, use unmodified LDA &115:CMP #ASC"8":BCS TimeLp :\ 1980+, use unmodified LDA #ASC"2":STA &113 LDA #ASC"0":STA &114 :\ Change to 20xx :]:z%=P%-z%:P%=P%-z%:O%=O%-z% .TimeLp :\ Could do BCD->RTC LDA &108,X:JSR OSASCI:INX :\ Print RTC string CPX #25:BNE TimeLp:TXA :\ Set flags .NoTime RTS :\ A=length of RTC string : \ ====================== \ Check if RTC available \ ---------------------- \ Returns EQ=RTC available \ NE=No RTC available \ --------------------------- .CheckClock1 JSR WhatOS:BCC CheckClock CPX #5:BNE CheckClockOk .CheckClock LDA &3DD:JSR CheckClock2 :\ Date LDA &3DE:JSR CheckClock2 :\ Month LDA &3DF:JSR CheckClock2b :\ Year .CheckClockOk LDA #0:RTS .CheckClock2 BEQ CheckClockNo .CheckClock2b AND #15:CMP #10:BCC CheckClockOk .CheckClockNo PLA:PLA :\ Lose return address .Osw14Quit LDA #8:RTS :\ A=8 used later : \ ================================ \ OSWORD 14 - Read Real Time Clock \ -------------------------------- .Osword14 LDY #0:LDA (&F0),Y:LDY #7 :\ Get action byte CMP #2:BCC Osw14RTC:BNE Osw14Quit:\ Check action byte .Osw14_2 :\ Convert BCD to text LDA (&F0),Y:DEY:STA &100,Y :\ Copy to workspace BNE Osw14_2 .ConvertDate :\ Convert &100-&106 to text LDY #0:LDA &103:AND #7:CLC ADC #12:JSR PutDayMonth LDA #ASC",":JSR PutChar LDA &102:JSR PutDec:JSR PutSpace LDA &101:JSR BCDtoBIN:AND #15 JSR PutDayMonth:JSR PutSpace \LDA &100:\EOR #&FF:\CMP #&B0 :\ Ignore 19xx now \LDA #19:\ADC #0:\JSR BINtoBCD:\JSR PutDec LDA #&20:JSR PutDec :\ Year 20xx LDA &100:JSR PutDec:LDA #ASC".":JSR PutChar :\ Year xxyy LDA &104:JSR PutHour:LDA &105:JSR PutHour :\ Time hh;mm; LDA &106:JSR PutDec:LDA #13:JSR PutChar :\ Time ss .Osw14Claim LDA #0:RTS : .Osw14RTC TAX:JSR CheckClock:BNE Osw14Quit :\ No time available LDA &3DE:AND #&1F:STA &101 :\ Get month LDA &3DF:STA &100 :\ Get year LDA &3DD:AND #&3F:STA &102 :\ Get date LDA &3DE:LSR A:LSR A:LSR A:LSR A LSR A:STA &103 :\ Get day of week TXA:PHA:LDA &F0:PHA:LDA &F1:PHA :\ Save action and pointer LDX #8:.Osw14Save:LDA numsub,X:PHA:DEX:BPL Osw14Save LDA #1:JSR OsTIME :\ Read TIME LDA #&83:LDY #&D6:LDX #&00:JSR Osw14Div :\ Calculate days BEQ osw14noflow :\ Not past midnight LDA #2:JSR OsTIME :\ Set TIME : \LDA numstore+2:\CMP #&83 :\ Has TIME overflowed past midnight? \BCC osw14noflow:\BNE osw14sub \LDA numstore+1:\CMP #&D6:\BCC osw14noflow \.osw14sub :\ Decrease by 24 hours \LDA numstore+1:\SBC #&D6:\STA numstore+1 \LDA numstore+2:\SBC #&83:\STA numstore+2 \LDA #2:\JSR OsTIME :\ Set TIME : .osw14noflow LDA #&05:LDY #&7E:LDX #&40:JSR Osw14Div:STA &104 :\ Calculate hours LDA #&00:LDY #&17:LDX #&70:JSR Osw14Div:STA &105 :\ Calculate minutes LDA #&00:TAY:LDX #&64:JSR Osw14Div:STA &106 :\ Calculate seconds :\ Centisecs ignored LDX #0:.Osw14Rest:PLA:STA numsub,X:INX:CPX #9:BNE Osw14Rest PLA:STA &F1:PLA:STA &F0 :\ Restore pointer PLA:BNE P%+5:JMP ConvertDate :\ A=0, return as string LDY #6:.NoDateLp LDA &100,Y:STA (&F0),Y:DEY :\ Copy back to control block BPL NoDateLp:JMP Osw14Claim : .Osw14Div \\ Move to with BINtoBCD JSR SubNum:JMP BINtoBCD : .OsTIME LDX #numstore AND 255:LDY #numstore DIV 256:JMP OSWORD : .PutSpace :\ Store a space LDA #ASC" ":BNE PutChar .PutHour :\ Store hour/minute/colon JSR PutDec:LDA #ASC":":BNE PutChar .PutDec :\ Store decimal PHA:JSR HexTopDigit:JSR PutChar PLA:JSR HexDigit .PutChar :\ Store a character STA (&F0),Y:INY:RTS .PutDayMonth :\ Look up and store day/month STA tmp:ASL A:ADC tmp:TAX LDA MonthText-3,X:.PutDayLp STA (&F0),Y:INX:INY LDA MonthText-3,X:CMP #ASC"`" BCS PutDayLp:RTS : .MonthText EQUS "JanFebMarAprMayJunJulAugSepOctNovDec" EQUS "SunMonTueWedThuFriSat" EQUB &00 :\ Byte<'`' table terminator : : \ ==================================== \ Translate *commands to further calls \ ------------------------------------ .Close :LDA #0:TAY:JMP OSFIND :\ Close all files .Shut :LDX #&26:BNE fx143 :\ Send *SHUT service call .Config:LDX #&28:BNE fx143 :\ Send *CONFIGURE service call .Status:LDX #&29:BNE fx143 :\ Send *STATUS service call : .Hadfs :\ Select HADFS with *fx143 .fx143go:LDY #HADFSnum :\ Select HADFS as filing system .fx143fs:LDX #&12 :\ Select filing system in Y .fx143 :LDA #143:JMP OSBYTE :\ Issue a service call : .Ex :LDA #9 :BNE FSC_F2 :\ Pass *EX to FSCV .Info :LDA #10:BNE FSC_F2 :\ Pass *INFO to FSCV .Rename :LDA #12 :\ Pass *RENAME to FSCV .FSC_F2 :JSR F2toXY :\ Convert (&F2),Y pointer to XY .FSC :JMP (FSCV) : .Delete :\ Pass *DELETE to OSFILE LDA #6:JSR OSFile:CMP #0:BNE MountOk JMP FileNotFound .CDir :LDA #8 :\ Pass *CDIR to OSFILE .OSFile :JSR F2toXY :\ Convert (&F2),Y pointer to XY .OSFileXY STX Ctrl:STY Ctrl+1 :\ Store X and Y in control block LDX #Ctrl AND 255:LDY #Ctrl DIV 256 :\ Point to control block JMP OSFILE :\ Jump to do OSFILE action : : \ ================================= \ Directory/disk selection commands \ --------------------------------- .Bye JSR Close :\ Should also do Osw90,5 :\ Fall through into MountClear .MountClear LDA DRVINT:PHA:LDA DRVEXT:PHA :\ Save Internal/External flags LDA OPTFLG:PHA:LDA #0:TAX .MntClr STA WS,X:INX:BNE MntClr :\ Clear entire workspace PLA:STA OPTFLG PLA:STA DRVEXT:PLA:STA DRVINT :\ Restore Internal/External flags .MountOk RTS : .Mount JSR GetDriveEQ:PHP:PHA :\ Get any drive parameter LDX #0 :\ Forget Spool/Exec if HADFS channels LDA &256:JSR ChannelRange:BCC P%+5:STX &256 LDA &257:JSR ChannelRange:BCC P%+5:STX &257 JSR MountClear:PLA:PLP:BEQ MountOk:\ No drive specified STA CSD+d:STA LIB+d:STA URD+d LDA #71:STA CSD:LDA #0:STA CSD+1:STA CSD+2 RTS : .I_AmXY JSR XYtoF2 .I_Am TYA:PHA:JSR Bye:PLA:TAY :\ Close all and clear workspace JSR SetContext :\ Look for drives LDA URD+d:JSR LookFromRoot :\ Search from '$' on URD drive BNE I_Am2 :\ Not found, use '$' LDX #CSD-CSD:JSR SectToDIR :\ Set CSD=Sect of found directory .I_Am2 LDX #URD-CSD:JSR CSDtoDIR :\ Set URD=CSD, ='$' or dir LDA LIB+d:PHA :\ LIB=000000, save LIB drive LDA CSD+d:STA LIB+d :\ Try looking on CSD drive JSR FindLib:BNE I_Am4 :\ '$.Library' found, use it PLA:CMP LIB+d:BEQ I_Am3 :\ Get LIB drive back STA LIB+d :\ Try original drive if not <00> JSR FindLib:BNE I_Am5 :\ '$.Library' found, use it .I_Am3 LDA #71:STA LIB:BNE I_Am5 :\ Set LIB to '$' on lib drive .I_Am4 PLA .I_Am5 LDX #URD-CSD:JSR GetDirX :\ Get URD directory LDA &1113:STA USERNUM :\ Get user b0-b7 LDA &1112:ORA #4:STA OPTNUM :\ Get user b8-b11 and boot option AND #3:BEQ I_AmEnd :\ Option 0 -> do nothing TAX:LDA BootTable-1,X:TAX :\ Index to Boot command LDY #BootTable DIV 256:JMP oscli :\ Execute the command : .BootTable EQUB Boot1:EQUB Boot2:EQUB Boot3 :\ Low bytes of Boot commands .Boot1:EQUS "L.!BOOT":EQUB 13 :\ Option 1 - *Load !Boot .Boot2:EQUS "/!BOOT" :EQUB 13 :\ Option 2 - */!BOOT .Boot3:EQUS "E.!BOOT":EQUB 13 :\ Option 3 - *Exec !Boot :]:IF(BootTable AND &FF00)<>(P%AND&FF00):PRINT"WARNING: BootTable overlaps page" : .Dir JSR TryADir:BPL Dir2 :\ Dir F LDX #URD-CSD:JSR DIRtoSect :\ Null path, set Sect=URD : .Dir2 LDX #CSD-CSD:LDA #&3F:BNE SectToDIRa :\ Jump to set CSD : .Lib JSR TryADir:LDX #LIB-CSD:LDA #&DF :\ Continue to set LIB .SectToDIRa AND VFLG:STA VFLG :\ Clear name flags : \ ------------------------------------------------- \ SectToDIR - Set context variable at CSD,X to Sect \ ------------------------------------------------- .SectToDIR LDA sect+0:STA CSD+0,X LDA sect+1:STA CSD+1,X LDA sect+2:STA CSD+2,X LDA drive :STA CSD+d,X .I_AmEnd RTS : \ --------------------------- \ CSDtoSect - Set Sect to CSD \ --------------------------- .CSDtoSect LDX #CSD-CSD : \ ------------------------------------------------- \ DIRtoSect - Set Sect to context variable at CSD,X \ ------------------------------------------------- .DIRtoSect LDA CSD+0,X:STA sect+0 LDA CSD+1,X:STA sect+1 LDA CSD+2,X:STA sect+2 LDA CSD+d,X:STA drive RTS : \ ----------------------------------------------- \ CSDtoDIR - Set context variable at CSD,X to CSD \ ----------------------------------------------- .CSDtoDIR:\.SetFromCSD LDA CSD+0:STA CSD+0,X LDA CSD+1:STA CSD+1,X LDA CSD+2:STA CSD+2,X LDA CSD+3:STA CSD+3,X .TryADirOk RTS : .TryADir JSR SearchPathname:BMI TryADirOk CMP #2:BEQ TryADirOk CMP #0:BNE Not_A_Dir JMP FileNotFound .Not_A_Dir JSR file_errors:EQUB 190:EQUS "is not a directory":BRK : .Enable LDA #&FF:STA ENABLE:RTS : ] PRINT CHR$11;STRING$(20,CHR$9);(O%-mcode%)DIV1024;":";(O%-mcode%)MOD1024;" Kbytes" >"S.HADFS2"