FAST GELÖST: Hilfe beim beim Sektorenlesen (DMA im P-Mode) - der 18. Sektor!



  • Ich nochmal,

    nach langem experimentieren bin ich nervlich am Ende 🙄

    Erstmal etwas zum Programm selbst:

    Das Einlesen eines Sektors geschieht mit 4 Funktionen.

    call setsektor			;Log. Sektor umwandeln
    		call setdma			;DMA Einstellungen festlegen		
    		call dmaread			;DMA auf lesen stellen		
    		call read				;Sektor einlesen
    		call fdd_ready			;Warten bis FDD bereit
    

    Funktion "setsektor" wandelt den logischen Sektor in seine Bestandteile
    Spur, Kopf und Sektornummer um:

    ;wandelt den logischen in einen "echten" Sektor um (Kopf, Spur und Sektor)
    setsektor:		;Sektor berechnen und in Variablen eintragen
    	pushad
    		;inc word [logsektor]	;nächsten logischen Sektor lesen
    
    		movzx eax, word [logsektor]
    	push eax
    		xor edx, edx
    		xor ebx, ebx
    		mov bl, byte [sekzahl]
    		div ebx
    		mov eax, edx
    		inc eax
    		mov byte [aktsektor], al	;der aktuelle Sektor
    
    	pop eax
    	push eax
    		xor edx, edx
    		xor ebx, ebx
    		mov bl, byte [sekzahl]
    		div ebx
    		and eax, 1d
    		mov byte [aktkopf], al	;der aktuelle Kopf
    
    	pop eax
    		mov ecx, 36d
    		xor edx, edx
    		div ecx
    		mov byte [aktspur], al     ;die aktuelle Spur
    
    	popad
    ret
    

    Funktion "setdma" konfiguriert den DMA Controller mit der Adresse 0x300000 (3MB)

    ;setzt die DMA Einstellungen
    setdma:
    	pushad
    		mov al, 0x6
    		mov edx, 0xa
    		out dx, al		;mask dma channel 2
    
    		mov al, 0xff
    		mov edx, 0d8h
    		out dx, al		;reset master flip-flop
    
    		mov edx, 0x4
    		mov ebx, dword [address]
    		mov al, bl
    		out dx, al
    		mov al, bh
    		out dx, al		;Adresse festlegen von Buffer
    
    		mov al, 0xff
    		mov edx, 0xd8
    		out dx, al		;reset master flip-flop
    
    		mov edx, 0x5
    		mov al, 0xFF
    		out dx, al
    		mov al, 0x1	;0x1 nur für einen Sektor
    		out dx, al		;511 = 512 Byte einlesen
    
    		xor eax, eax
    		mov ax, word [address +2]
    		mov edx, 0x81
    		out dx, al		;Page Register laden
    
    		;DMA aktivieren
    		mov al, 0x2
    		mov edx, 0xa
    		out dx, al		;unmask dma channel 2
    
    	popad
    ret
    

    Die Funktion "dmaread" stellt den DMA auf schreiben in den Speicher ein.

    ;Setzt DMA auf lesen (Gerät ----> Speicher)
    dmaread:
    	pushad
    		mov al, 0x6
    		mov edx, 0xa	;d4
    		out dx, al		;mask dma channel 2
    
    		mov edx, 0xb	;d6
    		mov al, 0x56	;single transfer, address increment, autoinit, write, channel 2
    		out dx, al	;
    
    		mov al, 0x2
    		mov edx, 0xa	;d4
    		out dx, al		;unmask dma channel 2
    	popad
    ret
    

    Und zuletzt noch die Funktion "read", diese übergibt die Befehle zum
    lesen eines Sektors an den FDD.

    ;liest den gewählten logischen Sektor ein
    ;setdma muss immer aus die Größe einer ganzen Spur eingestellt werden
    ;sonst kann man immer nur einen Sektor lesen
    ;Bei der Befehlsübergabe (read) übergibt man die Anzahl der zu lesenden
    ;Sektoren (max. 17) und alles läuft :-)
    read:
    	pushad
    
    		mov edx, 0x3f2
    		mov al, 0x1c
    		out dx, al		;Daten ins DOR schreiben = Aktivieren
    
    		mov edx, 0xFFFF
    .warten:		
    		nop
    		dec edx
    		jnz .warten		;Warteschleife zum aktivieren des Motors im LW
    
    		mov edx, 03f5h			;Datenregister
    		mov al, 11100110b
    		out dx, al
    
    		xor eax, eax
    		mov al, byte [aktkopf]
    		shl ax, 2
    		and al, 11111100b
    		out dx, al				;Kopf und Laufwerk Bit 0 - 2
    
    		xor eax, eax
    		mov al, byte [aktspur]
    		out dx, al				;Zylinder (Spur)
    
    		xor eax, eax
    		mov al, byte [aktkopf]
    		out dx, al				;Kopf wie Befehl 2
    
    		mov al, byte [aktsektor] 	;Sektornummer
    		out dx, al				
    
    		mov al, 0x2
    		out dx, al				;Sektorgröße = 2 (512 Byte)
    
    		mov al, byte [aktsektor]
    		out dx, al				;Anzahl zu lesender Sektoren, sollte = Sektornummer sein
    ;							damit nur ein Sektor gelesen wird
    
    		mov al, 27d			;GAP Nummer = 27 (Standard)
    		out dx, al
    
    		mov al, 0xff
    		out dx, al				;Länge der Daten (immer 0FFh)
    	popad
    ret
    

    Damit kann ich (fast) jeden Sektor, auch mehrere in einer Schleife einlesen.

    Nun zu dem fast:
    Den Aufruf jedes 18. Sektors quittiert mein Programm mit Stillstand 😞
    Alle anderen (Sektor 1 bis 17 auf jeder Spur) kann ich problemlos einlesen und auf dem Schirm anzeigen.

    Ich habe alle Funktionen zum lesen und schreiben der FAT fertig, jedoch kann
    ich diese nicht richtig nutzen wenn ich nicht auf die ganze Disk zugreifen kann.

    Kann mir bitte jemand sagen was das Geheimnis des 18. Sektors ist?😕

    Nicky



  • das selbe Problem (18. Sektor) ist bei einlesen einer ganzen Spur...

    Nicky



  • Hallo,

    Das Programm habe ich gestern abend auf einem "echten" PC getestet.
    Läuft tadellos, ebenfalls erhalte ich ganz andere Ergebnisbytes nach der
    Befehlsphase. Liegt wohl doch an der virtuellen Maschine.

    👍 Nicky



  • des Rätsels Lösung war das Bit 4 im Modusregister des DMA Controllers.
    Virtual PC kommt damit wohl nicht zurecht.

    😃 Nicky


Anmelden zum Antworten