Blame | Last modification | View Log | Download | RSS feed
;******************************************************************************;* *;* Includedatei fuer SECMAIN.ASM *;* liefert low-level-Routinen fuer SecMain *;* Version hier fuer WD1003-kompatible Kontroller: *;* MFM, RLL, ESDI, AT-Bus *;* *;* Historie: 28.12.1994 herueberkopiert aus Hauptmodul *;* 30.12.1994 LowLevelIdent *;* 19. 1.1995 Workaround fuer LCS6220 *;******************************************************************************section wd1003atBase1 equ 170h ; Basisadresse Task-FileBase2 equ 370h ; Basisadresse Floppy-TeilTask_Data equ Base1+0 ; Datentransferregister (R/W)Task_Error equ Base1+1 ; genauerer Fehlercode (R)Task_PreComp equ Base1+1 ; erster Zylinder Praekomp. (/4, nur W)Task_SecCnt equ Base1+2 ; Zahl zu transferierender Sektoren (R/W)Task_SecNum equ Base1+3 ; Startsektor (R/W)Task_CylLo equ Base1+4 ; Startzylinder Bit 0..7 (R/W)Task_CylHi equ Base1+5 ; Startzylinder Bit 8..n (R/W)Task_DrHead equ Base1+6 ; Laufwerk/Startkopf (R/W)Task_Status equ Base1+7 ; Status Laufwerk & Controller (R)Task_Command equ Base1+7 ; Kommando Controller (W)Task_FDiskReg equ Base2+6 ; Bit 3=1: >8 KoepfeCmd_Restore equ 10h ; Kommando: RekalibrierenCmd_Seek equ 70h ; Kommando: Zylinder anfahrenCmd_Read equ 20h ; Kommando: Sektoren lesenCmd_Write equ 30h ; Kommando: Sektoren schreibenCmd_Format equ 50h ; Kommando: Spur formatierenCmd_Verify equ 40h ; Kommando: Sektoren auf Lesbarkeit pruefenCmd_Diagnose equ 90h ; Kommando: SelbsttestCmd_SetParams equ 91h ; Kommando: Laufwerksparameter setzenproc WriteParamsmov [axsave],axmov [cxsave],cxPrChar ' 'mov ax,bxmov cl,5call WriteDecPrChar ' 'mov al,byte ptr[axsave+1]mov ah,0mov cl,2call WriteDecPrChar ' 'mov al,byte ptr[cxsave+1]mov ah,0mov cl,2call WriteDecPrChar ' 'mov al,byte ptr[cxsave]mov ah,0mov cl,2call WriteDecPrChar ' 'mov ax,esmov cl,4call WriteHexPrChar ':'mov ax,bpmov cl,4call WriteHexmov ax,[axsave]mov cx,[cxsave]retcxsave dw ?axsave dw ?endp;******************************************************************************;* Workaround fuer LCS6220: Wird direkt nach dem Einschalten ein Seek ausge- *;* fuehrt, gibt der Kontroller faelschlicherweise Daten aus und blockiert alle*;* weiteren Kommandos. Diese Routine raeumt einfach den Puffer leer... *;******************************************************************************proc ClearBufferpush dx ; Register rettenpush axRdLoop: mov dx,Task_Status ; Bit 3 noch gesetzt ?in al,dxbtst al,3jz RdLoopEnd ; nein --> fertigmov dx,Task_Datain ax,dxjmp RdLoopRdLoopEnd:pop ax ; Register zurueckpop dxretendp;******************************************************************************;* Interleave-Tabelle berechnen *;* In : AL = Sektorzahl *;* AH = Interleave *;* DH = Bad-Flag *;******************************************************************************proc SetInterleaveBufferpusha ; Register rettenpush espush ax ; Sektorpuffer initialisierenmov ax,dsmov es,axsub ax,axlea di,[SectorBuffer]mov cx,SecSize/2cldrep stoswpop axsub di,di ; DI=Adresse in Puffer=(phys. Sektor-1)*2mov dl,dh ; DL = Bad-Flagmov dh,1 ; DH=log. Sektornummermov cl,al ; CX=Schleifenzaehlermov ch,0mov bl,al ; Sektorzahl*2 nach BXmov bh,0add bx,bxmov si,ax ; Interleave*2 nach SIshr si,8add si,siInterLoop: cmp byte ptr SectorBuffer[di],0 ; Eintrag frei ?je Inter_FreeFound ; ja, beendenadd di,2 ; nein, linear weitersuchencmp di,bxjb InterLoopmov di,0 ; Wrap-Around beruecksichtigenjmp InterLoopInter_FreeFound:mov word ptr SectorBuffer[di],dx ; Sektor einschreibenadd di,si ; Interleave-Sprung dazucmp di,bx ; Modulo Sektorzahljb Inter_NoWrapsub di,bxInter_NoWrap: inc dh ; naechster log. Sektorloop InterLooppop es ; Register zurueckpoparetendp;******************************************************************************;* Laufwerk und Sonderwerte einprogrammieren *;* In : AL = Laufwerk *;* AH = Kopf *;******************************************************************************proc SetDriveEnvpush di ; Register rettenpush dxmov dx,ax ; Laufwerk/Kopf rettencall GetPTabAdr ; Tabellenadresse holenmov al,dl ; Laufwerk und Kopf zusammenbauenshl al,4or al,dhor al,0a0hmov dx,Task_DrHeadout dx,almov ax,[di+DrPar_PrComp] ; Startzylinder Praekompensationshr ax,2mov dl,Lo(Task_PreComp)out dx,almov al,[di+DrPar_CByte] ; Wert fuer Fixed Disk Registermov dx,Task_FDiskRegout dx,alcall WaitBusyclc ; Ende ohne Fehlerpop dxpop diretendp;******************************************************************************;* Zylinder- und Sektorparameter an Kontroller ausgeben *;* In : BX = Startzylinder *;* CL = Sektorzahl *;* CH = Startsektor *;******************************************************************************proc SetTransParamspush dx ; Register rettenmov dx,Task_CylLo ; Startzylinder programmierenmov al,blout dx,almov dx,Task_CylHi ;***mov al,bhout dx,almov dx,Task_SecNum ; Startsektor... ;***mov al,chout dx,almov dx,Task_SecCnt ; ...und Sektorzahl ;***mov al,clout dx,alpop dx ; Register zurueckretendp;******************************************************************************;* warten, bis Controller bereit oder Fehler *;* Out : AL = letzter Status *;******************************************************************************proc WaitBusypush dx ; Register rettenmov dx,Task_Status ; auf StatusregisterLoop: in al,dx ; Status lesenbtst al,7 ; Bit 7 noch gesetzt ?jnz Loop ; ja--> weiter pollenpop dx ; Register zurueckretendp;******************************************************************************;* warten, bis Laufwerk bereit *;* Out : AL = letzter Status *;******************************************************************************proc WaitDrivepush dx ; Register rettenmov dx,Task_Status ; auf StatusregisterLoop: in al,dx ; Status lesenbtst al,7 ; Bit 7 = 0 ? ( Controller Busy )jnz Loopbtst al,6 ; Bit 6 = 1 ? ( Drive not Ready )jz Loopbtst al,4 ; Bit 4 = 1 ? ( Seek not complete )jz Looppop dxretendp;******************************************************************************;* warten, bis Datentransfer erforderlich *;* Out : AL = letzter Status *;* C = 1, falls Fehler *;******************************************************************************proc WaitDatapush dx ; Register rettenmov dx,Task_Status ; auf StatusregisterLoop: in al,dx ; Status lesenbtst al,7 ; Bit 7 = 0 ?jnz Loopbtst al,3 ; Bit 3 = 1 ?jz Looppop dx ; Register zurueckretendp;******************************************************************************;* Status bilden *;* Out : C+AX = Status *;******************************************************************************proc BuildErrorpush dx ; Register rettenmov dx,Task_Status ; Statusregister lesenin al,dxmov ah,albtst ah,0 ; Fehlerflag gesetzt ?clcjz End ; kein Fehlermov dx,Task_Error ; ja: Error-Register lesen ;***in al,dxstcEnd: pop dx ; Register zurueckretendp;******************************************************************************;* Begruessungsmeldung ausgeben: *;******************************************************************************globproc LowLevelIdentpush ax ; Register rettenPrMsg IdentMsgpop axretIdentMsg db "Low-Level-Routinen f",UUML,"r WD1003-WAH und kompatible Controller",CR,LF,'$'endp;******************************************************************************;* Controller-Diagnose: *;* Out : AL = Diagnosecode *;******************************************************************************globproc ContDiagpush cx ; Register rettenpush dxmov dx,Task_Status ; das erste Mal mit Timeout wartensub cx,cxBWait: in al,dxbtst al,7 ; auf NOT BUSY wartenloopnz BWait ; oder bis 64K Durchlaeufe durchor cx,cx ; Timeout ?jne NTOutmov al,Diag_Timeout ; ja: Fehlercode setzen...jmp End ; ...und FeierabendNTOut: mov al,CMD_Diagnose ; Selbsttest startenmov dl,Lo(Task_Command)out dx,alcall WaitBusy ; auf Fertigstellung wartenmov dl,Lo(Task_Error) ; Ergebnis ladenin al,dxEnd: pop dx ; Register zurueckpop cxretendp;******************************************************************************;* Dem Kontroller die Laufwerksgeometrie mitteilen *;* In : AL = Laufwerk *;* Out : C = 1-->Fehler *;******************************************************************************globproc SetDriveParamspush di ; Register rettenpush dxmov dl,al ; Laufwerk rettencall GetPTabAdr ; Adresse Parametertabelle holencall WaitBusy ; Kontroller muss frei seinmov al,dl ; Kopfzahl/Laufwerk vorbesetzenshl al,4mov ah,[di+DrPar_Heads]dec ah ; Maximalnummer anstelle Gesamtzahlor al,ahor al,0a0hmov dx,Task_DrHeadout dx,almov dl,Lo(Task_SecCnt) ; Sektorzahl setzenmov al,[di+DrPar_NSecs]out dx,almov dl,Lo(Task_Command) ; Parameter uebertragenmov al,Cmd_SetParamsout dx,alcall WaitBusy ; auf Fertigstellung wartenclc ; Ende ohne Fehlerpop dxpop diretendp;******************************************************************************;* Laufwerk rekalibrieren, gleichzeitig Test, ob vorhanden *;* In : AL = Laufwerk *;* Out : C + AX = Status *;******************************************************************************globproc Recalibratepush cx ; Register rettenpush dxmov cx,ax ; Laufwerk rettencall WaitBusy ; warten, bis Controller freimov dx,Task_DrHead ; Laufwerk eintragenmov al,clshl al,4add al,0a0hout dx,almov dl,Lo(Task_Status) ; Laufwerk muss jetzt bereit sein,in al,dx ; da sich einige Kontroller sonst imand al,50h ; folgenden aufhaengen, fallscmp al,50h ; keine Platte angeschlossen ist.stc ; falls nicht bereit, Fehler simulierenmov al,4 ; "Aborted Command"jne TotEndemov al,0mov dl,Lo(Task_CylLo) ; erstmal auf die sanfte Tour:out dx,al ; Spur 0 anfahrenmov dl,Lo(Task_CylHi)out dx,almov dl,Lo(Task_Command)mov al,Cmd_Seekout dx,alcall WaitBusycall BuildErrorjnc Ende ; wenn OK: fertigcall ClearBuffer ; falls sich der Longshine verheddert...mov dl,Lo(Task_Command) ; 2. Anlauf: echtes Restoremov al,Cmd_Restoreout dx,alcall WaitBusy ; auf Controller wartenEnde: call BuildError ; Status einlesenTotEnde:pop dx ; Register zurueckpop cxretendp;******************************************************************************;* Sektor(en) lesen *;* In : AL = Laufwerk *;* AH = Startkopf *;* BX = Startzylinder *;* CL = Sektorzahl *;* CH = Startsektor *;* ES:DI = Zeiger auf Datenpuffer *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc ReadSectorspush si ; Register sichernpush dxpush bpif debugPrChar 'R'mov bp,dicall WriteParamsendifsub bp,bp ; Fehlerzaehler auf 0Retry: push ax ; Parameter sichernpush bxpush cxpush dimov si,ax ; Laufwerk/Kopf rettencall WaitBusy ; warten, bis Ruhe im Waldmov ax,sicall SetDriveEnv ; Laufwerk jetzt schon setzen, damit; korr. Ready-Signal abgefragt wirdcall WaitDrive ; bis Laufwerk bereitcall SetTransParams ; restliche Parameter ausgebenmov ch,0 ; Sektorzahl nach SImov si,cxmov dx,Task_Command ; Kommando triggernmov al,Cmd_Readout dx,almov dx,Task_Data ; Vorbereitung fuer INSWcldLoop: call WaitBusy ; auf gelesenen Sektor wartenbtst al,0 ; Fehler ?jnz Again ; -->neu aufsetzencall WaitDatabtst al,0jnz Againcall WaitDrivebtst al,0jnz Againmov cx,SecSize/2 ; Daten transferierenrep insw ; bagger, schaufeldec si ; naechster Sektorjnz LoopEnd: pop di ; Parameter nicht mehr gebrauchtpop cxpop bxpop axTerm: if debugPrChar CRPrChar LFendifcall BuildErrorpop bppop dxpop siretAgain: inc bp ; Fehlerzaehler raufcmp bp,MaxRetry ; zu oft aufgetreten ?jae Endpop di ; nein: Parameter vom Stackpop cxpop bxpop axmov si,ax ; Laufwerk rettencall Recalibrate ; auf Spur 0 zurueckjc Term ; bei erneutem Fehler Abbruchmov ax,sicall SetDriveParams ; Parameter neu initialisierenmov ax,sijmp Retry ; neuer Versuchendp;******************************************************************************;* Sektor(en) verifizieren *;* In : AL = Laufwerk *;* AH = Startkopf *;* BX = Startzylinder *;* CL = Sektorzahl *;* CH = Startsektor *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc VeriSectorspush si ; Register sichernpush dxpush bpif debugPrChar 'V'mov bp,0call WriteParamsendifsub bp,bp ; Fehlerzaehler auf 0Retry: push ax ; Parameter sichernpush bxpush cxmov si,ax ; Laufwerk/Kopf rettencall WaitBusy ; warten, bis Ruhe im Waldmov ax,sicall SetDriveEnv ; Laufwerk jetzt schon setzen, damit; korr. Ready-Signal abgefragt wirdcall WaitDrive ; bis Laufwerk bereitcall SetTransParams ; restliche Parameter ausgebenmov dx,Task_Command ; Kommando triggernmov al,Cmd_Verifyout dx,alcall WaitBusy ; auf Fertigstellung wartenmov cx,16 ; einige Kontroller brauchenDelStat: loop DelStat ; etwas fuer das Fehlerflagmov dx,Task_Statusin al,dxbtst al,0 ; Fehler ?jnz Again ; -->neu aufsetzencall WaitDrivebtst al,0jnz AgainEnde: pop cx ; Parameter nicht mehr gebrauchtpop bxpop axTerm: if debugPrChar CRPrChar LFendifcall BuildErrorpop bppop dxpop siretAgain: inc bp ; Fehlerzaehler raufcmp bp,MaxRetry ; zu oft aufgetreten ?jae Endepop cx ; nein: Parameter vom Stackpop bxpop axmov si,ax ; Laufwerk rettencall Recalibrate ; auf Spur 0 zurueckjc Term ; bei erneutem Fehler Abbruchmov ax,sicall SetDriveParams ; Parameter neu initialisierenmov ax,sijmp Retry ; neuer Versuchmov ax,siendp;******************************************************************************;* Sektor(en) schreiben *;* In : AL = Laufwerk *;* AH = Startkopf *;* BX = Startzylinder *;* CL = Sektorzahl *;* CH = Startsektor *;* ES:SI = Zeiger auf Datenpuffer *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc WriteSectorspush di ; Register sichernpush dxpush bpif debugPrChar 'W'mov bp,sicall WriteParamsendifxor bp,bp ; Fehlerzaehler auf 0Retry: push ax ; Parameter sichernpush bxpush cxpush simov di,ax ; Laufwerk/Kopf rettencall WaitBusy ; warten, bis Ruhe im Waldmov ax,dicall SetDriveEnv ; Laufwerk jetzt schon setzen, damit; korr. Ready-Signal abgefragt wirdcall WaitDrive ; bis Laufwerk bereitcall SetTransParams ; restliche Parameter ausgebenmov ch,0 ; Sektorzahl nach DImov di,cxmov dx,Task_Command ; Kommando triggernmov al,Cmd_Writeout dx,almov dx,Task_Data ; Vorbereitung fuer OUTSWcldLoop: call WaitBusy ; auf Datenbereitschaft wartenbtst al,0 ; Fehler ?jnz Again ; ja-->neu aufsetzencall WaitDatabtst al,0jnz Againcall WaitDrivebtst al,0jnz Againmov cx,SecSize/2 ; Daten transferierensegesrep outsw ; bagger, schaufelcall WaitBusy ; warten, bis Transfer fertigbtst al,0jnz Againdec di ; naechster Sektorjnz LoopEnd: pop si ; Parameter nicht mehr gebrauchtpop cxpop bxpop axTerm: if debugPrChar CRPrChar LFendifcall BuildErrorpop bppop dxpop diretAgain: inc bp ; Fehlerzaehler raufcmp bp,MaxRetry ; zu oft aufgetreten ?jae Endpop si ; nein: Parameter vom Stackpop cxpop bxpop axmov di,ax ; Laufwerk rettencall Recalibrate ; auf Spur 0 zurueckjc Term ; bei erneutem Fehler Abbruchmov ax,dicall SetDriveParams ; Parameter neu initialisierenmov ax,dijmp Retry ; neuer Versuchendp;******************************************************************************;* Laufwerk formatieren *;* In : AL = Laufwerk *;* AH = Interleave *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc FormatUnitpush bxpush cxpush dxpush sipush dipush bpmov bx,ax ; Interleave rettenPrMsg ESCMsgmov ax,bxcall GetPTabAdr ; Parametertabelle->DImov ax,bxmov dh,0 ; gute Spuren schreibenmov al,[di+DrPar_NSecs]call SetInterleaveBuffer ; Tabelle berechnenmov ax,bxcall Recalibrate ; Kontroller reinitialisierenjc Finmov ax,bxmov bp,[di+DrPar_Cyls] ; Zylinderzaehler in BP (abwaerts)dec bpmov dl,al ; Laufwerk in DLcldCylLoop: mov dh,0 ; Kopf in dhHeadLoop: call WaitBusy ; warten, bis WD1003 freicall WriteCoords ; Bildschirmausgabemov ax,dx ; Laufwerk+Kopf progr.call SetDriveEnvmov bx,bp ; Zylinder+Sektor progr.mov cl,[di+DrPar_NSecs]mov ch,1call SetTransParamsmov bx,dxmov dx,Task_Commandmov al,Cmd_Formatout dx,alcall WaitData ; Sektortabelle schickenmov cx,SecSize/2mov dx,Task_Datalea si,[SectorBuffer]rep outswcall WaitBusy ; warten, bis Kontroller fertigshr al,1 ; Fehlerbit in Carry ladenjnc GoOnPrMsg ErrorMsg ; falls Fehler, Meldung ausgebenmov dx,bxcall WriteCoordsPrChar LFGoOn: mov dx,bx ; Laufwerk und Kopf zurueckcall BreakOnESC ; will der Benutzer abbrechen ?jc UserTerm ; ja, Abbruchinc dh ; naechster Kopfcmp dh,[di+DrPar_Heads]jb HeadLoopdec bp ; naechster Zylinderjns CylLoopTermLoop: mov al,dl ; damit die Seek-Rate wieder stimmtcall RecalibrateFin: push ax ; Fehlerstatus haltenpushfPrChar LFpopf ; Fehlerstatus zurueckpop axpop bppop dipop sipop dxpop cxpop bxretUserTerm: mov al,dl ; Abbruch durch Benutzer: noch schnellcall Recalibrate ; rekalibrierenjc Fin ; Fehler dabei ?stc ; Ansonsten Sonderfehlercodemov al,DErr_UserTermjmp FinWriteCoords: push ax ; Kopf/Zylinder ausgebenpush cxPrMsg CylMsgmov ax,bpmov cl,6call WriteDecPrMsg HeadMsgmov al,dhmov ah,0mov cl,3call WriteDecPrChar CRpop cxpop axretESCMsg: db "Abbruch mit <ESC>",CR,LF,'$'CylMsg: db "Zylinder $"HeadMsg: db ", Kopf $"ErrorMsg: db "Formatierfehler auf $"endp;******************************************************************************;* Spur formatieren *;* In : AL = Laufwerk *;* AH = Kopf *;* BX = Zylinder *;* CL = Interleave *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc FormatTrackpush bx ; Register rettenpush cxpush dxpush sipush dipush bpmov bp,ax ; Laufwerk & Kopf rettencall Recalibrate ; Laufwerk sicherheitshalber rekalibrierenmov ax,bpcall GetPTabAdr ; Sektortabelle aufbauenmov dh,0 ; fehlerhafte Sektoren schreibenmov ah,cl ; Interleave vorgebenmov al,[di+DrPar_NSecs]call SetInterleaveBuffermov ax,bp ; Laufwerk und Kopf zurueckcall SetDriveEnv ; in Kontroller einprogrammierenmov cl,[di+DrPar_NSecs] ; Sektor& Zylinder einschreibenmov ch,1call SetTransParamsmov dx,Task_Command ; Kommando schickenmov al,Cmd_Formatout dx,alcall WaitData ; Sektortabelle schickenmov cx,SecSize/2mov dx,Task_Datalea si,[SectorBuffer]rep outswcall WaitBusy ; warten, bis Kontroller fertigjc Fin ; Abbruch bei Fehlermov ax,bp ; Laufwerk nochmal rekalibrierencall Recalibrate ; damit Steprate stimmtFin: pop bppop dipop sipop dxpop cxpop bxretendp;******************************************************************************;* Spur als defekt markieren *;* In : AL = Laufwerk *;* AH = Kopf *;* BX = Zylinder *;* Out : C+AX = Fehlerstatus *;******************************************************************************globproc MarkBadpush bx ; Register rettenpush cxpush dxpush sipush dipush bpmov bp,ax ; Laufwerk & Kopf rettencall Recalibrate ; Laufwerk sicherheitshalber rekalibrierenmov ax,bpcall GetPTabAdr ;Sektortabelle aufbauenmov dh,80h ; fehlerhafte Sektoren schreibenmov ah,3 ; Interleave ist ziemlich egal...mov al,[di+DrPar_NSecs]call SetInterleaveBuffermov ax,bp ; Laufwerk und Kopf zurueckcall SetDriveEnv ; in Kontroller einprogrammierenmov cl,[di+DrPar_NSecs] ; Sektor& Zylinder einschreibenmov ch,1call SetTransParamsmov dx,Task_Command ; Kommando schickenmov al,Cmd_Formatout dx,alcall WaitData ; Sektortabelle schickenmov cx,SecSize/2mov dx,Task_Datalea si,[SectorBuffer]rep outswcall WaitBusy ; warten, bis Kontroller fertigjc Fin ; Abbruch bei Fehlermov ax,bp ; Laufwerk nochmal rekalibrierencall Recalibrate ; damit Steprate stimmtFin: pop bppop dipop sipop dxpop cxpop bxretendpendsection