Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: nore am 03. April 2006, 19:49
-
hi, ich hab zum lesen eines tracks von diskette einen kleinen sofware-interrupt geschrieben, den ich dann mit einer funktion aufrufe. der hat anfangs sowohl unter bochs als auch an diversen richtigen PCs funktioniert. seit ungefähr einer woche tut er dies allerdings nicht mehr. unter bochs funktioniert es noch, aber am richtigen PC nicht mehr.
das interessante daran ist: ich habe unmittelbar davor an der ISR dieses interrupts nichts geändert. ich habe jetzt schon einige stunden mit fehlersuchen verbracht und bin mittlerweile echt am verzweifeln.
anbei poste ich den code der ISR und hoffe, ihr könnt mir helfen.
kurze bemerkungen: in eax steht beim aufruf die adresse, an die der track geladen werden soll, in ch steht der kopf und in cl der zylinder.
die funktion delay funktioniert (unabhängig von diesem interrupt getestet) und erwartet millisekunden in einem unsigned long.
ob der track in den arbeitsspeicher geladen wurde teste ich mit einer funktion, die mit sehr großer wahrscheinlichkeit fehlerfrei läuft (andere speicherstellen werden richtig angezeigt).
hier also der code der ISR:
_int_0x30:
push edx
push eax
mov al, 0x14
out 0x08, al ; dma deaktivieren
mov al, 0x56
out 0x0b, al ; einzel, adressinc, kein autoinit, schreiben, kanal2
pop eax
out 0x0c, al ; flip-flop leeren
out 0x04, al ; niederwertiges adressbyte schicken
shr eax, 8
out 0x04, al ; höherwertiges adressbyte schicken
shr eax, 8
out 0x81, al ; page-byte senden
out 0x0c, al ; flip-flop leeren
mov al, 0xFF
out 0x05, al ; wie viele zugriffe (bytes)(niederwertiges byte) (gesamtzugriffe-1=angegebene zahl)
mov al, 0x23
out 0x05, al ; wie viele zugriffe (bytes)(höherwertiges byte)
mov al, 0x02
out 0x0A, al ; mögliche maskierung aufheben
mov al, 0x10
out 0x08, al ; dma wieder aktivieren
mov al, 0x1c
mov dx, 0x03f2
out dx ,al ; diskettenlaufwerks-motor einschalten (laufwerk A, über dma, ...)
mov al,7
call writediskdata
mov al,0
call writediskdata ; neu kalibrieren
mov al,3
call writediskdata
mov al,0x0F
call writediskdata
mov al,2
call writediskdata ; laufwerkdaten festlegen
mov al, 0x46 ; erstes byte des read-befehls
call writediskdata
mov al, ch
shl al, 2 ; head
call writediskdata
mov al, cl ; cylinder
call writediskdata
mov al, ch ; head
call writediskdata
mov al, 1 ; sector
call writediskdata
mov al, 2 ; sectorsize (128*2^2)
call writediskdata
mov al, 18 ; secpertrack
call writediskdata
mov al, 27 ; länge von GAP3 (??)
call writediskdata
mov al, 0xFF ; bytes to read (standaradwert, da sectorsize!=0) (??)
call writediskdata
push dword 0x400 ;1024
call _delay
pop eax
mov al, 00h
mov dx, 0x03f2
out dx,al ; motor wieder aus
pop edx
iret
-
Hmm... also wo positioniert du denn den Kopf? Das war nämlich früher auch mein Fehler, als es nur unter den Emulatoren funktionierte, aber nicht auf echten PCs. Dann habe ich den Kopf positioniert und es funktionierte. Hier wie man das macht:
mov bl,0Fh ;Seek (positionier) Kommando
call fdc_sendbyte
mov bl,Drive ;Laufwerk
call fdc_sendbyte
mov bx,di ;Spur
call fdc_sendbyte
bitmaster
PS: Dann hätte ich noch eine Bitte. Wie sieht der Code deiner delay-Funktion aus? Ich versuche nämlich so eine Funktion in den PM zum laufen zu bekommen. Bis jetzt vergeblich.
Danke!!!
-
zunächst mal danke für den tipp.
für mein delay brauch ich einmal irq0:
_int_irq_0:
cli
push eax
mov eax, [_timer]
inc eax
mov [_timer], eax
mov al, 0x20
out 0x20, al
pop eax
sti
iret
_timer dd 0
und dann noch die funktion an sich (in c):
void delay(unsigned long ms)
{
unsigned long startz;
ms*=182;
ms/=10000;
if (ms>(0x0-timer)) timer=0;
startz=timer;
while (startz+ms>timer){;};
}
ich konnte deinen tipp mit dem seek gar nicht testen, weil jetzt auf einmal (war vorher wirklich noch nicht und besteht auch, wenn ich den seek-teil wieder rausnehme) an der stelle, an der ich die delay-funktion aufrufe eine endlosschleife entsteht. ich hab sogar nochmal geguckt, wie c die funktion aufruft und das ganze dann auch so gemacht. ich bin bald echt am verzweifeln.
ich poste jetzt nochmal den code meiner momentanen isr, die einen track von diskette head ch, cylinder cl an [eax] laden soll. ich bin mir ziemlich sicher, dass die endlosschleife bei "call _delay" entsteht. wenn ich das wegmache, entsteht keine. außerdem bleibt der diskettenlaufwerksmotor an.
_int_0x30:
push edx
push eax
mov al, 0x14
out 0x08, al ; dma deaktivieren
mov al, 0x56
out 0x0b, al ; einzel, adressinc, kein autoinit, schreiben, kanal2
pop eax
out 0x0c, al ; flip-flop leeren
out 0x04, al ; niederwertiges adressbyte schicken
shr eax, 8
out 0x04, al ; höherwertiges adressbyte schicken
shr eax, 8
out 0x81, al ; page-byte senden
out 0x0c, al ; flip-flop leeren
mov al, 0xFF
out 0x05, al ; wie viele zugriffe (bytes)(niederwertiges byte) (gesamtzugriffe-1=angegebene zahl)
mov al, 0x23
out 0x05, al ; wie viele zugriffe (bytes)(höherwertiges byte)
mov al, 0x02
out 0x0A, al ; mögliche maskierung aufheben
mov al, 0x10
out 0x08, al ; dma wieder aktivieren
mov al, 0x1c
mov dx, 0x03f2
out dx ,al ; diskettenlaufwerks-motor einschalten (laufwerk A, über dma, ...)
mov al,7
call writediskdata
mov al,0
call writediskdata ; neu kalibrieren
mov al,3
call writediskdata
mov al,0x0F
call writediskdata
mov al,2
call writediskdata ; laufwerkdaten festlegen
mov al,0Fh ;Seek (positionier) Kommando
call writediskdata
mov al, ch
shl al, 2 ; head
call writediskdata
mov al,cl ;Spur
call writediskdata
mov al, 0x46 ; erstes byte des read-befehls
call writediskdata
mov al, ch
shl al, 2 ; head
call writediskdata
mov al, cl ; cylinder
call writediskdata
mov al, ch ; head
call writediskdata
mov al, 1 ; sector
call writediskdata
mov al, 2 ; sectorsize (128*2^2)
call writediskdata
mov al, 18 ; secpertrack
call writediskdata
mov al, 27 ; länge von GAP3 (??)
call writediskdata
mov al, 0x00 ; bytes to read (standardwert, da sectorsize!=0) (??)
call writediskdata
push dword 0x7d0 ; 2000
call _delay
add esp, 0x4
mov al, 00h
mov dx, 0x03f2
out dx,al ; motor wieder aus
pop edx
iret
-
ok, mein letztes problem hebt sich auf, wenn ich den delay-aufruf und das ausschalten des motors aus der isr rausnehme. werden, wenn ein software-interrupt noch nicht fertig abgearbeitet ist, keiner hardwareinterrupts zugelassen?
aber trotz seek-kommando stehen an der stelle im arbeitsspeicher, an die ich den track lesen will immer nur nullen. muss ich da vllt auch noch delays einfügen oder sonst irgendwie abfragen, ob das seek-kommando beendet ist? ich werd mal gucken, ob ich das hinbekomme, ich editier dann später noch was rein.
EDIT1: anscheinend braucht das seek-kommando wirklich zeit.
EDIT2: da anscheinend weder ein hardwareinterrupt aufgerufen wird, noch sonst etwas funtkioniert, um rauszufinden, ob der vefehl fertig ist, muss ich wohl oder über nach dem calibrate und nach dem seek je ein selay einfügen.
-
ok, mein letztes problem hebt sich auf, wenn ich den delay-aufruf und das ausschalten des motors aus der isr rausnehme. werden, wenn ein software-interrupt noch nicht fertig abgearbeitet ist, keiner hardwareinterrupts zugelassen?
aber trotz seek-kommando stehen an der stelle im arbeitsspeicher, an die ich den track lesen will immer nur nullen. muss ich da vllt auch noch delays einfügen oder sonst irgendwie abfragen, ob das seek-kommando beendet ist? ich werd mal gucken, ob ich das hinbekomme, ich editier dann später noch was rein.
EDIT1: anscheinend braucht das seek-kommando wirklich zeit.
EDIT2: da anscheinend weder ein hardwareinterrupt aufgerufen wird, noch sonst etwas funtkioniert, um rauszufinden, ob der vefehl fertig ist, muss ich wohl oder über nach dem calibrate und nach dem seek je ein selay einfügen.
Ich habe zwar gehört das nach dem positionieren des Kopfes eine delay-Funktion eingebaut werden muss. Aber ich habe bei mir keine delay-Funktionen und es funktioniert auf allen PCs die ich besitze und auf allen Emulatoren die ich kenne. Nur ist das bei mir alles ziemlich langsam. Ich werde es später mal mit einer delay-Funktion bei mir ausprobieren. Intel spricht glaube ich von 500 Millisekunden. Der IRQ6 wird nur nach einem Schreib-/Lesebefehl ausgeführt und wenn der Kopf positioniert wird. Mein Code des IRQ6 setzt lediglich eine Variable auf 1. Und nach dem Schreib-/Lesebefehl und Positionieren des Kopfes prüfe ich einfach ob die Variable den Wert eins hat. Wenn nicht dann wird weiter geprüft, solange halt bis die Variable den Wert eins hat. Dann wenn sie den Wert eins hat, kann vortgefahren werden (aber dann auch die Variable wieder auf Null setzten bzw <> 1). Das heißt, dass erst weiter gemacht wird, wenn der IRQ6 ausgeführt wurde. Deswegen finde ich es auch blöd das man zusetzlich noch eine delay-Funktion einbauen sollte. Aber der fdc ist meiner Meinung nach sowieso schlecht durchdacht.
bitmaster
-
ok, danke. aber ich löse das trotzdem jetzt mit delay, weil ichs anders nicht hinbekomme.
EDIT: ich mach mal nen neuen thread für die neue frage auf, ist ja nicht mehr das gleiche.