>HADFS9 v5.74 1 Low-level device drivers and disk load/save 1 =========================================== (> v5.27 Internal/External drives and cleaner floppy access 2J Need to expand SECT and hold addr in zeropage for (addr),Y use <% v5.29 GoMMC driver on drive 'M' F# v5.30 IDE driver on drive 4,5 P@ This section now includes DiskMainLoop and Tube code Z9 SetContext checks drives for default mounting d" v5.33 IDE uses 24-bit access n6 v5.40 16-bit/24-bit IDE configurable on assembly x# v5.64 Updated vramSelect code L v5.66 Removed IDE16, OldVRAM code, directory header copied to/from HDR E Code still very untidy, but any changes likely to kill it B Needs work on workspace thrashing with DFS in MOS 3.50 R v5.69 Tidied up disk access, 8x4G IDE drives, OSWORD 90 temp'y selects HADFS [ v5.70 For Electron, DrvIDE checks for &FC for absence, DrvFlop checks returned result S v5.71 Moved main code to start, drivers to end, enables DFS 2.4x when calling ) Tweeked IDE error translation Y v5.72 Shadow screen detection and selection works on BBC again, CheckAddr no longer U preserves X, caller preserves X, allows DiskMain to corrupt all registers R v5.73 GoMMC driver disabled if DFS 0.90 present to avoid DFS 0.90 OSWORD bug ` v5.74 IDE driver better detects absence, on Compact absent device gives random port values : EIDEdata =&FC40:IDEerror=&FC41:IDEcount =&FC42:IDEsector=&FC43 EIDEcylinder=&FC44:IDEhead =&FC46:IDEcommand=&FC47:IDEstatus=&FC47 : "Assembling S.HADFS9" "O%=P%-Block%+mcode% , [OPT0 6"\ ============================ @"\ OSWORD 90 - User Disk Access J"\ ============================ T.NotOsw90:LDA #8:RTS ^ .Osword90 hGLDY #01:LDA (&F0),Y:CMP #6:BNE NotOsw90 :\ Second byte must be &06 r?LDY #11:LDA (&F0),Y:BPL NotOsw90 :\ cmd<&80, ignore |?CMP #&82:BCS NotOsw90 :\ cmd>&81, ignore : >\ We may not own HADFS's workspace, so we need to claim it >\ -------------------------------------------------------- @\ NB, don't need the filing system, just need the workspace. K\ Calls GrabAbs, then doesn't need to release, just allows any previous P\ owner to reclaim it. Needs to restore DFS24x workspace flag, as DFS may be \ the owner when calling. K\ However, may still need to select HADFS so that DFS gets initialised. \ P\\PHA:LDA &F1:PHA:LDA &F0:PHA :\ Save byte for oldFS and OSWORD pointer LJSR GrabAbs :\ Ensure access to HADFS's workspace D\\JSR EnsureHADFS:\TSX:\STA &103,X :\ Select HADFS, saving oldFS LTSX:LDA &102,X:STA &F1 :\ Get OSWORD pointer back from stack LDA &101,X:STA &F0:LDY #1 .DoOsw90lp1  &00/&FF vDSTX action:JSR CheckAddr :\ Allowed to corrupt A,X,Y,P bSEC:JSR DiskMainOsw:TAX :\ Call main disk transfer code, allowed to corrupt A,X,Y,P @PLA:STA &F0:PLA:STA &F1:LDY #2 :\ Restore OSWORD pointer .DoOsw90lp3 QLDA addr-2,Y:STA (&F0),Y :\ Copy updated addr/sect to control block INY:CPY #6:BNE DoOsw90lp3 !LDA len+1:LDY #10:STA (&F0),Y TXA:INY:STA (&F0),Y =\\PLA:\JSR RestoreFS :\ Restore previous fs ?LDA #0:RTS :\ Claim the OSWORD call : : 2\ ============================================ 2\ DiskMain - main disk sector transfer routine 2\ ============================================  "\ Read/Write number of sectors \ On entry,  +\ action =0 - read, action=&FF - write *\ sect =sector start 4(\ addr =data address (any memory) > \ len+1/2=number of sectors H.\ SEC at DiskMainOsw to return error in A R\ \\ On exit, f\ sect =sector after end p%\ addr =data address after end z%\ len+1/2=sectors not transfered 0\ A=error number when called with SEC \ EQ=no error occured \ X=corrupted \ Y=corrupted :  .DiskMain DJSR CheckAddr :\ Allowed to corrupt A,X,Y,P M.DiskMainGBPB :\ OSGBPB has already called CheckAddr ;CLC :\ CLC=report errors .DiskMainOsw DPHP:JSR ScreenOn :\ Allowed to corrupt A,X,Y,P =&10000, transfer 64 sectors FCPY len+1:BCC DiskMainBlock :\ >=&4000, transfer 64 sectors $DLDY len+1 :\ Transfer remaining sectors ..DiskMainBlock 8CSTY num :\ Transfer block of sectors B?LDA len+1:SEC:SBC num:STA len+1 :\ Decrease sector count LILDA len+2:SBC #0:STA len+2 :\ Should do this *after* transfer VJJSR DiskAcc:BEQ DiskMainLp1 :\ addr and sect updated by DiskAcc `LPLP:BCS P%+5:JMP DiskErrors:PHP :\ CC=generate error, CS=return error j.DiskMainEnd tLPLP:PHA:JSR ScreenOff:PLA:RTS :\ X,Y corrupted, A=result, flags set ~: : :\ CheckAddr - Check transfer addr for screen selection :\ ==================================================== 8\ On exit, shadow=0 for non-screen or <>0 for screen \ addr modified &\ all registers corrupted .CheckAddr >LDA #0:STA shadow :\ Set 'no shadow selected' CLDX &27A:BPL AddrIO :\ No Tube, always use IO memory CLDX addr+3:INX:BNE AddrTube :\ Tube present, addr<>&FFxxxxxx :  .AddrIO LDX addr+2  CINX:BEQ AddrIOGo :\ &FFFFxxxx - current IO memory AINX:BEQ AddrDisplay :\ &FFFExxxx - current display ?INX:BNE AddrIOGo :\ &FFFDxxxx - shadow memory (.z% 2IJSR WhatMOS:BCC AddrShadow :\ Master, don't need to check display <0:]: base$>=5.79:z%=P%-z%:P%=P%-z%:O%=O%-z% F.z% PIBIT WHATOS:BMI AddrShadow :\ Master, don't need to check display Z/:]: base$<5.79:z%=P%-z%:P%=P%-z%:O%=O%-z% d@INC shadow:INC shadow :\ BBC, b1=always page memory n.AddrDisplay x;LDA #&84:JSR OSBYTE :\ Get top of I/O memory 6CPY #&70:BEQ AddrShadow :\ 16K Aries screen @TYA:BPL AddrIOGo :\ <&8000 - non-shadow screen .AddrShadow 4INC shadow :\ b0=screen bank :  .AddrIOGo ALDA #&FF:STA addr+2:STA addr+3 :\ Ensure addr is in IO memory  .AddrTube RTS : \ Screen selection routines \ ------------------------- 9\ On entry, shadow=0 for non-screen or <>0 for screen '\ On exit, all registers corrupted  .ScreenOn SEC:BCS P%+3 ".ScreenOff ,BCLC:LDA shadow:BEQ vramDone :\ No paging required 6HBCS P%+4: #1 :\ Toggle bit 0 if screen off @X #1:LDY #108:JSR vramSel:BVC vramDone :\ Attempt to select Master/Integra video RAM JO #1:LDY #34:JSR vramSel:BVC vramDone :\ Attempt to select old Watford RAM TWLDY #111 :\ Attempt to select Aries/new Watford RAM ^ .vramSel hPHA:TAX:TYA:JSR OSBYTE:PLA r .vramDone |RTS : \ Tube access routines \ -------------------- .TubeClaimLoad  LDA #1 .TubeClaimDo PHA:JSR TubeClaim:PLA .TubeAction LDX #addr:LDY #0:JMP &406 .TubeClaim LDA #&C0+progID+16 JSR &406:BCC TubeClaim:RTS : .TubeRelease LDA #&80+progID+16:JMP &406 : &\ 48cycle, 24us delay 0\ ------------------- :.TubeWait:JSR TubeW1 D.TubeW1:JSR TubeW2 N.TubeW2:RTS X$\\TXA:\PHA:\LDX #10:\.TubeWaitLp b(\\DEX:\BNE TubeWaitLp:\PLA:\TAX:\RTS l: v: &\ Load FSM, Check HADFS disk, etc. &\ -------------------------------- .CheckHadfsDiskX NJSR ReadFSM:BNE NotHADFSError0 :\ Check disk without copying disk name .ChkHadfsChng &LDA HDR+&10:CMP &F18:BNE DskChgErr &LDA HDR+&11:CMP &F19:BNE DskChgErr RTS : 0\ Load a directory and check it is same disk 0\ ------------------------------------------ .get_chk_dir #LDA HDR+&10:PHA:LDA HDR+&11:PHA $LDA CURR:A CURR+1:A CURR+2:PHA  LDA CURR+d:PHA JSR GetDir  #PLA:CMP CURR+d:BNE GetChkDirOk1 *PLA:BEQ GetChkDirOk2 4!PLA:CMP HDR+&11:BNE DskChgErr >$PLA:CMP HDR+&10:BEQ GetChkDirOk4 H.DskChgErr RJMP DiskChanged \.GetChkDirOk1:PLA f.GetChkDirOk2:PLA:PLA p.GetChkDirOk4 zRTS : -\ Load FSM and error if not an HADFS disk -\ --------------------------------------- .CheckHADFSDisk "JSR ReadFSM:BNE NotHADFSError0 LDX #&F:.ChkNameLp .LDA &F00,X:STA DSKNAME,X:DEX:BPL ChkNameLp -LDA VFLG:A #128: #&E0:A drive:STA VFLG (LDA #0:RTS:\ Does A need to be zero? : .NotHADFSError0 'BCS CheckDskErr:\ Drive not present LDA #0:STA VFLG .NotHADFSDisk 4JSR errors:EQUB 200:EQUS "Not an HADFS disk":BRK : $.SectRootAbs .JSR SetAbs 8 .SectRoot BLDA #71:BNE P%+4 L .SectFSM VLDA #70:STA sect+0 `$LDA #0:STA sect+1:STA sect+2:RTS j: t.SetAddrFSM ~LDA #&0F:STA addr+1 .SetAddrIO "LDA #&FF:STA addr+3:STA addr+2 "LDA #&00:STA addr+0:STA shadow RTS : /\ Load FSM and check if it is an HADFS disk /\ ----------------------------------------- \ On exit, EQ -- HADFS #\ NE CC Not HADFS disk (\ NE CS Drive ? not present &\ addr, sect, Y preserved \ A, X corrupted .ReadFSM [TYA:PHA:LDY #6 :\ Save Y as called by SearchPath and SetContext  .RdFSMlp1 =LDA addr,Y:PHA:DEY:BPL RdFSMlp1 :\ Save addr, sect (CJSR SectFSM:STA action :\ sect=FSM, action=read 2CJSR SetAddrFSM:LDA #1:STA num :\ addr=&FFFF0F00, num=1 <\\LDA #&00:\STA addr+0 F\\LDA #&0F:\STA addr+1 P&\\LDA #&FF:\STA addr+2:\STA addr+3 ZAJSR ClearFSM:JSR DiskAcc:TAX:LDY #0 :\ Read FSM from drive d .RdFSMlp2 n@PLA:STA addr,Y:INY:CPY #7:BNE RdFSMlp2 :\ Restore addr, sect xJPLA:TAY:TXA:BEQ ChkJGH :\ Disk read ok, check if HADFS BCMP #&18:BCS ChkJGH1 :\ CS=Drive not present .CheckDskErr FJMP DiskErrors :\ Bad read, generate error : .ChkJGH:LDX #7 .ChkJGHlp ?LDA &F10,X:CMP JGHName,X:CLC:BNE ChkJGH2 :\ NE+CC=Not HADFS ;DEX:BPL ChkJGHlp:INX:CLC :\ EQ+CC=HADFS @.ChkJGH1:TXA :\ Set EQ/NE from X .ChkJGH2:RTS : \ Claim the buffer at &0F00 \ ------------------------- 7\ If this is a Master, this is not a channel buffer  .ClearFSM .z% "AJSR WhatMOS:BCC ClearFSMok :\ Master, not using &0F00 ,0:]: base$>=5.79:z%=P%-z%:P%=P%-z%:O%=O%-z% 6.z% @ABIT WHATOS:BMI ClearFSMok :\ Master, not using &0F00 J/:]: base$<5.79:z%=P%-z%:P%=P%-z%:O%=O%-z% T9LDA CHN25: #&FE:STA CHN25 :\ Clear Ch25 buffer ^.ClearFSMok hRTS r: | \ Clear the directory buffer \ -------------------------- .ClearDIR 6LDA #0:STA CURR+0:STA CURR+1:STA CURR+2:STA CURR+d RTS : \ Load a directory \ ---------------- ;\ GetDir, PutDir, ReadFSM, SaveFSM should preserve addr ,\ Need to save Y as called by SearchPath D.GetDirX :\ Fetch directory from CSD,X JSR DIRtoSect G.GetDir :\ Fetch directory in sect/drive )LDA sect+0:CMP CURR+0:BNE Get3Sectors )LDA sect+1:CMP CURR+1:BNE Get3Sectors )LDA sect+2:CMP CURR+2:BNE Get3Sectors FLDA drive:CMP CURR+d:BEQ Got3Sectors:\ Directory already in memory &.Get3Sectors 0,JSR ClearDIR:STA action:\LDA #3:\STA num :0TYA:PHA:LDY #7 :\ Save Y D.GetDirLp1 N9LDA addr,Y:PHA:DEY:BPL GetDirLp1 :\ Save addr, sect XBJSR DiskAccDir3 :\ Load to directory buffer bFJSR DirToAddr2:LDY #32 :\ addr=>DIR, Y=max header size l.GetDirLp2 vBDEY:LDA (addr),Y:STA HDR,Y :\ Copy header to workspace CPY #10:BNE GetDirLp2:LDY #0 .GetDirLp3 =PLA:STA addr,Y:INY:CPY #4:BNE GetDirLp3 :\ Restore addr .GetDirLp4 EPLA:STA CURR-4,Y:INY:CPY #8:BNE GetDirLp4 :\ Restore sect to CURR ?\STA CURR+d:PLA:TAY :\ Store drive in CURR+d .Got3Sectors RTS : .DirToAddr @JSR dirSize:TAY :\ Y=header size from HDR .DirToAddr2 3JSR dirAddr:STA addr+1 :\ addr=>DIR DLDA #0:STA addr+0:RTS :\ Y=HDR size, addr=>DIR, A=0 : \ Save FSM \ -------- * .SaveFSM 42JSR SectFSM :\ sect=FSM >: H\ Save FSM buffer R\ --------------- \.SavePageF f8LDA #&0F:STA addr+1 :\ addr=&xxxx0Fxx pBLDA #&FF:BNE DiskOneSector :\ Jump to write one sector z: \ Load to FSM buffer \ ------------------ .GetToFSM =JSR ClearFSM:LDA #&0F :\ Point to FSM buffer .GetOneAddr BSTA addr+1 :\ Set address to &xxxxAAxx .GetOneSector FLDA #0 :\ Read one sector to &FFFFxx00 .DiskOneSector 8STA action :\ Set Read/Write ;LDA #1:STA num:BNE DiskAccIO :\ Access one sector : \ Save current directory \ ---------------------- .SaveThisDir GJSR CURRtoSect:INC HDR+&0D :\ sect=CURR, increment cycle no $ .PutDir .FJSR DirToAddr :\ addr=>DIR, Y=HDR header size 8 .PutDirLp BHDEY:LDA HDR,Y:STA (addr),Y :\ Copy header back to DIR buffer LCPY #10:BNE PutDirLp V.PutDirNoHdr `OLDA #&FF:STA action :\ Write 3 sectors from directory buffer j: t.DiskAccDir3 ~\\LDA #&00:\STA addr+0:\STA shadow :\ No shadow access F\\LDA #&FF:\STA addr+2:\STA addr+3 :\ Set address to &FFFFxx00 : : G\ ================================================================= ?\ DiskAccess - X,Y preserved, disk errors generate an error 7\ DiskAcc - X,Y corrupted, A holds result, EQ=ok G\ ================================================================= )\ addr = address, updated after call  (\ sect = sector, updated after call \ drive = drive number +\ num = number of sectors to transfer (\ action= 0=read, FF=write 2\ shadow= shadow flags =LDA num:BEQ AccDrvOk :\ Nothing to transfer HKJSR AddrToDaddr :\ Copy addr/sect/num to Daddr block R: \#\ Try accessing external driver f#\ ----------------------------- pLLDX drive:CPX #8:BCS AccDrvExt :\ High numbered drives, no / flags zCLDA BitTable,X :\ Index into external flags E DRVEXT:BEQ P%+5:JMP AccDrvInt :\ Ignore external, try internal : F.AccDrvExt :\ Try accessing external drive 'STY Daddr-2:LDA #progID:STA Daddr-1 DLDA action:CLC:ADC #2:STA Daddr+9 :\ Fill rest of control block >LDA #90:LDX #(Daddr-2)255 :\ Point to control block MJSR OswordY:JSR DaddrToAddr :\ Try external drivers with OSWORD 90 4LDA Daddr+9:BEQ AccDrvOk :\ =&00 - Ok 7CMP #6:BCS AccDrvOk :\ >=&06 - error : LLDX drive:CPX #8:BCS AccDrvInt2 :\ High numbered drives, no / flags ULDA BitTable,X:A DRVEXT:STA DRVEXT:\ No external support, flag it for this drive : #\ Try accessing internal driver #\ ----------------------------- .AccDrvInt $LDA BitTable,X .T DRVINT:BNE AccDrvNone :\ Ignore internal driver, exit with 'no drive' 8.AccDrvInt2 BI.z%:CPX #2:BCS P%+5:JMP DrvFloppy :\ Drive 0-1 - floppy LF.z%:CPX #4:BCC P%+9:CPX #12:BCS P%+5:JMP DrvIDE :\ Drive 4-B - IDE V.:]: _NoIDEDrv%:z%=P%-z%:P%=P%-z%:O%=O%-z% `D.z%:CPX #"M"-&37:BNE P%+5:JMP DrvMMC :\ Drive M - MMC j.:]: _NoMMCDrv%:z%=P%-z%:P%=P%-z%:O%=O%-z% t.AccDrvNone ~DLDA #&FE :\ Return 'Drive not present'  .AccDrvOk BTAX:RTS :\ Set EQ from A and return : \ ----------------------- \ Copy transfer addresses \ ----------------------- .AddrToDaddr ELDY #10:.AddrToLp:LDA addr-1,Y:STA Daddr-1,Y:DEY:BNE AddrToLp:RTS .DaddrToAddr FLDY #8:.DaddrToLp:LDA Daddr-1,Y:STA addr-1,Y:DEY:BNE DaddrToLp:RTS : \ ------------------------- \ Update transfer addresses  \ ------------------------- ;.UpdateScAd :\ Update sect, addr  PHA:CLC (ADC sect+0:STA sect+0 2 LDA sect+1:ADC #0:STA sect+1 <$LDA sect+2:ADC #0:STA sect+2:PLA F5.UpdateAddr :\ Update addr PCLC Z@.UpdateAddrCy :\ Update addr with carry d, ADC addr+1:STA addr+1:STA Daddr+1 n,LDA addr+2:ADC #0:STA addr+2:STA Daddr+2 x,LDA addr+3:ADC #0:STA addr+3:STA Daddr+3 RTS : : \ ===================== \ FLOPPY DRIVE ROUTINES \ ===================== .DrvFloppy 8LDA sect+2:BNE FlopTooBig :\ Sector>&00FFFF 8LDA sect+1:CMP #7:BCS FlopTooBig :\ Sector>&0006FF ALDY #&FF:SEC :\ Prepare to divide by 10 H.DskDiv10 :\ Convert Sector to sector&track 'INY:LDA Daddr+4:SBC #10:STA Daddr+4 "LDA Daddr+5:SBC #0:STA Daddr+5 BBCS DskDiv10:LDA Daddr+4:ADC #10 :\ Y=sect 10, A=sect 10 FSTA Dsec:STY Dtrk:STX Ddrv :\ Initial sector, track, drive : "&\ Daddr, Ddrv, Dtrk, Dsec, num set ,&\ -------------------------------- 6=.FlopLp :\ Loop for each track @ALDA num:PHA:CLC:ADC Dsec:CMP #11 :\ Wrap past end of track? JJPLA:BCC FlopNum :\ Single track, no stepping needed TILDA #10:SBC Dsec :\ Number to the end of this track ^ .FlopNum hJA #&20:STA Dnum :\ Set number of sectors to transfer rHLDA Dtrk:CMP #80:BCC FlopTrk :\ Is track past end of one side? |ISBC #80:STA Dtrk :\ Reduce to physical track number =LDX Ddrv:INX:INX:STX Ddrv :\ Set drive to side 2 FCPX #4:BCC FlopTrk :\ Not wrapped past end of disk .FlopTooBig ALDA #&18:RTS :\ Return Sector not found : +\ Daddr, Ddrv, Dtrk, Dsec, Dnum all set +\ ------------------------------------- ;.FlopTrk :\ Do a single track BLDA #&53:BIT action:BPL P%+4:LDA #&4B :\ Read or Write command OSTA Dcmd:LDY #5 :\ Set command, prepare for five retries : .FlopRetry 6TYA:PHA :\ Save retries ?LDA Ddrv:LDY #4 :\ Prepare to save drive .FlopSave1 : H LDY #0 R.FlopRest1 \JLDA Daddr+10,Y:STA &B0,Y:STA Daddr,Y :\ Restore workspace and Daddr f+PLA:STA &C0,Y:INY:CPY #16:BNE FlopRest1 p.FlopRest2 zDLDA Ddrv+11,Y:STA Dcmd-16,Y:INY:CPY #21 :\ Restore control block BNE FlopRest2:STA Ddrv : EPLA:TAY:TXA:BEQ FlopNext :\ Restore retries, get result GCMP #&10:BEQ FlopRetryJmp :\ DriveNotReady - always ignore >CMP #&12:BEQ FlopExit :\ DiskProtected - exit ;DEY:BEQ FlopExit :\ Exit if retries=0 .FlopRetryJmp @JMP FlopRetry :\ Retry this disk access  .FlopExit ATAX:RTS :\ Set EQ flag from result :  .FlopNext FSTA Dsec:INC Dtrk :\ Step to next track, sector 0 >LDA Dnum: #31:PHA:JSR UpdateScAd:\ Update three addresses IPLA: #&FF:SEC:ADC num:STA num :\ Decrease NUM by amount transfered =BEQ FlopExit:JMP FlopLp :\ Loop for all tracks $: . .Osword7F 8LDA #&7F:LDX #Ddrv 255 B .OswordY LLDY #Ddrv 256:JMP OSWORD V: `6\ EnableDFS - Enable OSWORD &7F on Master MOS 3.50 j6\ ------------------------------------------------ t7\ Running on a Master, so able to use 65C02 opcodes ~.EnableDFS @BPL EnableDFSok :\ b7=0, patch not needed @ #15:CMP &F4:BEQ EnableDFSok :\ ROM=HADFS, not DFS patch AEQUB &DA:TAX:LDA &DF0,X:STA addr+1 :\ PHX, Find DFS workspace GLDA #&D4:STA addr+0 :\ Point to 'OSWORD enable' flag CEQUB &B2:EQUB addr:TAX:TYA :\ LDA (addr) - get old flag HEQUB &92:EQUB addr:TXA:EQUB &FA :\ STA (addr) - set new flag, PLX .EnableDFSok RTS : : \ ================== \ IDE DRIVE ROUTINES \ ==================  .IDEAbsent >LDA #254:RTS :\ No IDE present : ( .DrvIDE 2LDX #4:.IDETest PHA :\ Save Tube flag : GLDA IDEstatus:BMI P%-3 :\ Wait until IDE not busy "DLDA num:PHA:LDY #2 :\ Use num as workspace , .IDElp 6JLDA sect+2-2,Y:LSR A:LSR A:STA num :\ sect.b18-b23, sect.b10-b15 @JLDA sect+3-2,Y:ROR A:ROR A:ROR A :\ drive.b1-b2, sect.b16-b17 J: T>\\DEY:\BEQ P%+5:\ROR A:\ #&80 :\ Invert drive.b2 ^:\\ #&C0:\A num:\STA IDEcylinder+1-1,Y:\ Set cylinder h\\TYA:\BNE IDElp r: |9 #&C0:A num:STA IDEcylinder-1,Y :\ Set cylinder DEY:BNE IDElp ?LDA sect+0:ROL A:ROL A:ROL A: #&03:STA num :\ sect.b6-b7 >LDA sect+1:ASL A:ASL A: #&0C:A num :\ sect.b8-b9 JSR IDESetHead:CLC 8LDA sect+0: #63:ADC #1:STA IDEsector :\ sect.b0-b5 DLDA #1:STA IDEcount :\ One sector at a time ;PLA:STA num :\ Restore num : ALDA action:ROR A :\ CC=read, CS=write D #&10:A #&20:STA IDEcommand :\ Create IDE command byte  .IDEWait cLDA IDEstatus:BMI P%-3:BEQ IDENotPresent :\ Wait until IDE not busy, if Status=&00 Drive absent ;TAY: #&21:BNE IDEError :\ Error occured : M\\LDY IDEstatus:\INY:\BEQ IDENotPresent :\ Status=&FF - Interface absent ^\\DEY:\BMI IDEWait:\BEQ IDENotPresent :\ Wait until BSY=0, if Status=&00 - Drive absent &A\\\\LDA IDEstatus:\BMI IDEWait :\ Wait for not busy 06\\\\ #&40:\BNE P%+5:\JMP IDENotPresent:\ No drive :@\\TYA:\ #&21:\BNE IDEError :\ Check if not found D: N:TYA: #8:BEQ IDEWait:LDY #0 :\ Wait for DRQ X=PLA:PHA:BPL IDETube:BCC IDEIORead :\ Get Tube flag b: lG.IDEIOWrite :\ Write 256 byte from I/O v;LDA (addr),Y:STA IDEdata:INY:BNE IDEIOWrite:BEQ IDENext ?.IDEIORead :\ Read 256 to I/O :LDA IDEdata:STA (addr),Y:INY:BNE IDEIORead:BEQ IDENext :  .IDETube GJSR TubeW2:BCS IDETubeWrite :\ Requires >20cycles/byte W.IDETubeRead :\ Read 256 bytes from Tube, 23cycles/byte 5LDA IDEdata:STA &FEE5:INY:BNE IDETube:BEQ IDENext X.IDETubeWrite :\ Write 256 bytes from Tube, 24cycles/byte 6LDA &FEE5:STA IDEdata:INY:BNE IDETube:\BEQ IDENext :  .IDENext ;LDA IDEstatus: #&21:BNE IDEError :\ Error occured DPLA:DEX:BEQ P%+5:JMP IDETwice :\ Do each action twice DTAY:LDA #1:JSR UpdateScAd :\ Update sect and addr  SDEC num:BEQ P%+5:JMP IDELoop :\ Loop for each sector, X=0 when done  .IDEDone  TYA:BMI P%+5:JSR TubeRelease *?TXA:RTS :\ A=result, EQ=Ok 4: >.IDESetHead HE\\PHA:\LDA drive:\LSR A:\PLA :\ Move odd drives to Cy RDPHA:LDA drive:CMP #8:PLA :\ Move drive 8-B to Cy \7BCC P%+4:A #&10 :\ drive.b0 fSTA IDEhead:RTS p: z.IDENotPresent ILDX #&FE:BNE IDEError2 :\ Becomes 'IDE not present'  .IDEError RLDX #&16: #&20:BNE IDEError2 :\ Status &20 becomes &16 'Write error' FLDA IDEerror:CMP #&10:BNE IDEError1 :\ Not 'sector not found' GLDX sect+2:BNE IDEError1 :\ Not low numbered sector HLDX sect+1:BEQ IDENotPresent :\ Convert to 'not present' .IDEError1  LDX #8  .IDEErrLp AASL A:DEX:BCC IDEErrLp:LDA IDEErrs,X:TAX :\ Convert IDE error .IDEError2 APLA:TAY:JMP IDEDone :\ Return IDE result  .IDEErrs EEQUD &1C0A140C:EQUD &080E1A18 :\ Translated IDE errors 8\ IDE errors Disk errors 9\ &20xx Write error -> &16 Write error $;\ &80 Bad block -> &08 Disk error 08 .<\ &40 Uncorrectable error -> &0E Data CRC error 8;\ &20 Media changed -> &1A Disk error 1A B>\ &10 Sector not found -> &18 Sector not found L;\ &08 Media Change Request -> &1C Disk error 1C V;\ &04 Abort -> &0A Disk error 0A `?\ &02 Track 0 not found -> &14 Track 0 not found j:\ &01 Address mark not found -> &0C ID CRC error t\ ~5:]: _NoIDEDrv%:z%=P%-IDEAbsent:P%=P%-z%:O%=O%-z% : : \ ================= \ MMC DRIVE ROUTINE \ ================= <.DrvMMC :\ GoMMC driver &C000:y%=P%-y%:P%=P%-y%:O%=O%-y% NY:]: P%<&C000:"EQUS STRING$(";&C000-P%;",CHR$&FF)": z%=0&C000-P%:?O%=&FF:O%=O%+1: X: b] l? 11;20,9);(O%-mcode%)1024":";(O%-mcode%)1024" Kbytes" v2"PAGE=&";~;" TOP=&";~P;" LOMEM=&";~ A"VARTOP=&";~!2 &FFFF;" STKEND=&";~!4 &FFFF;" HIMEM=&";~ ."Variable length: ";(!2-)&FFFF;" bytes" /"Free memory: ";(!4-!2)&FFFF;" bytes" A"SAVE ROMc "+~(mcode%)+" "+~(O%)+" 3000 "+~(Block%-&5000) 7:A%=-T%: O%>L%:L%=O% @"Assembly done in ";(A%6000);"m";"0"+((A%100)60),2)"s" f"Now do:"'"*LOAD ROMa"'"*LOAD ROMb"'"*LOAD ROMc"'"*SAVE ROM 3000+";~P%-&8000;" FFFF0000 FFFBBC00"