Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: bscreator am 03. September 2009, 19:32
-
Hallo,
bin grad dabei, eine Funktion zu schreiben, die
- wartet bis eine Taste gedrückt wird und dieses Zeichen am Bildschirm ausgibt.
Das Zeichen auszugeben ist ja kein Problem, aber wie kann ich ohne Verwendung der Interrupts ein Zeichen von der Tastatur einlesen ?
(bzw. welche Ports brauch ich, dass die Tastatur bspw. jetzt auf einen Tastendruck wartet ?)
(den Tastaturpuffer auszulesen is ja auch kein Problem, aber die Aufforderung, jetzt auf einen Tastendruck von Tastatur zu warten bereitet mir Probleme...)
Mit den Interrupts ist das ja alles kein Problem, aber geht das auch ohne Interrupts (auch wenn es intern immernoch über Interrupts passiert...) ?
-
Nene,
das Problem liegt darin, abzufragen, wann eine Taste gedrückt wird
(welche Ports, abgesehen vom Tastaturpuffer, sind dazu nötig ????)
-
Du willst alsoein zeichen von der Tastatur haben?
WOFÜR BRAUCHST DU DANN DIE ZEIT WANN EINE TASTE GEDRÜCKT WURDE :?
wenn der Interrupt ausgelöst wird springt der doch automatisch zu deinem Handler ohne dass der rest des Systems davon überhaupt was mitkriegt.
Wenn du wissen willst welches Zeichen aktueller ist kanst du dir einen PIT Treiber schreiben, und von dem eine Systemzeit holen. Die hängst du dann an das Zeichen. Die nidrigste Signatur ist dann das älteste Zeichen.
(erklär mir mal genau was du brauchst :|)
-
Wenn eine Tastatur gedrückt wurde, ist das niederwertigste Bit in Port 0x64 gesetzt. Du kannst also in einer Schleife einfach darauf warten bis das gesetzt ist.
-
Wenn eine Tastatur gedrückt wurde, ist das niederwertigste Bit in Port 0x64 gesetzt. Du kannst also in einer Schleife einfach darauf warten bis das gesetzt ist.
Genau sowas mein ich. Mit Hilfe eines Ports die Tastatur abfragen.
Der ASCII-Code des Zeichens is dann im Tastaturpuffer, oder ?
-
Ich denke ja, wenn das BIOS wie gehabt funktioniert.
-
So wie ich das verstehe bist du im Realmode und das BIOS verarbeitet den Tastaturinterrupt. Dann kannst du nicht einfach den I/O Port pollen, denn wahrscheinlich (?) wird der Interrupt erst ausgelöst und anschließend ist ein neuer Wert im I/O Port, d.h. zuerst wird das BIOS aufgerufen welches den Interrupt handhabt, dann ist natürlich wieder das Bit gelöscht und dann kommt erst dein Code an der Reihe, der schön in die Ewigkeit loopt.
Falls du jetzt eine Lösung haben willst, solltest du vielleicht genauer sagen, in welchem Modus du überhaupt bist, ob die BIOS Interrupt (das wird doch wohl einen Interrupt zum lesen eines Zeichens von der Tastatur haben) verwenden willst und warum genau du "ohne Interrupts" auskommen willst... vielleicht bin auch nur ich verwirrt...
-
Nochmal :
Ich will nur eine Möglichkeit haben, ein Zeichen von der Tastatur lesen ohne dabei irgendwelche Interrupt-Funktionen selbst zu verwenden
Das mit dem 0x64 klappt leider nicht, wie bluecode schon vorhergesagt hat.
Ich arbeite noch im Real-Mode ! Muss ich vielleicht zuerst das A20 aktivieren ?
-
ist zwar ne blöde antwort, aber hast du schon mal versucht die interrupts abzuschalten? vllt gehts ja dann.
-
Mein Code bisher :
read_keyb:
cli ;Interrupts deaktivieren
in al,0x64h ;lese Port 0x64
cmp al,0x01
jne readkeyb ;Wenn al = 0x01, dann wurde Taste gedrückt
in al,0x60 ;lese ASCII-Code der gedrückten Taste
sti ;Interrupts wieder zulassen
ret
...und in der Schleife read_keyb bleibt er hängen...
-
Um zu testen, ob ein Bit gesetzt ist, musst du "test" nehmen nicht "cmp". Außerdem ist die Bedingung dann jz read_keyb. Und das funktioniert, wenn du 0x64h schreibt? Ist da nicht 0x oder h zu viel?
-
Dann eben so:
read_keyb:
cli ;Interrupts deaktivieren
in al,0x64h ;lese Port 0x64
test al,00000001b
jz read_keyb
in al,0x60 ;lese ASCII-Code der gedrückten Taste
sti ;Interrupts wieder zulassen
ret
Bewirkt aber dasselbe, und zwar dass das Lesen von Port 0x64 immer 0 liefert
-
Hm, also bei mir funktionierts in Bochs und qemu.
-
Aber qemu aktiviert doch das A20-Gate und springt in den Protected Mode, oder ?
Dann hast ja gar nicht die selben Arbeitsbedingungen (sprich Real Mode)
-
Genau dann wenn das Gast-OS es macht...
-
ist zwar ne blöde antwort, aber hast du schon mal versucht die interrupts abzuschalten?
Das würde ich auch vorschlagen... Deine Phobie gegen BIOS-Interrupts (siehe hier (http://www.ctyme.com/intr/int-16.htm)) im Realmode verstehe ich allerdings nicht. Würde mich da definitiv über eine Erklärung freuen. :wink:
-
Naja, weil zu den Aufgaben eines Betriebssystems ja auch die Geräteverwaltung gehört.
Deswegen wollt ich halt die Aufgabe selbst in die Hand nehmen und mir einen Tastaturtreiber schreiben, damit ich diese Aufgabe bereits erledigt hab. Wenn man die Interrupts verwendet braucht man ja keinen Tastaturtreiber mehr, oder ?
-
Ich möchte dich darauf hinweisen, dass
* du momentan Code für den Realmode produzierst. Dein Code wird nicht einfach so im Protectedmode laufen bzw. es ist nicht unbedingt sinnvoll das zu tun
* du dir mit dem Realmode kein modernes OS schreiben wirst/kannst
* es m.E. wenig Sinn macht im Realmode auf die BIOS-Interrupts zu verzichten
* zwischen "auf Interrupts verzichten" und "auf BIOS-Interrupts verzichten" ein rießiger Unterschied ist. Ersteres ist kompletter Blödsinn, weil du dich auf Polling festlegst und das heißt nunmal, dass du unnötig die ganze Zeit in einer Schleife rumloopst. So wird das sicherlich nie was mit Multitasking und einem "modernen" OS.
-
du momentan Code für den Realmode produzierst. Dein Code wird nicht einfach so im Protectedmode laufen bzw. es ist nicht unbedingt sinnvoll das zu tun
Hab noch nicht vor, in den PM zu springen
m.E. wenig Sinn macht im Realmode auf die BIOS-Interrupts zu verzichten
Das ist mir klar, aber nur so kann ich einen "Treiber" für die Tastatur schreiben, oder ?
-
Die Frage ist halt, warum du einen Treiber schreiben willst, wenn das BIOS das alles schon macht.
-
Das ist mir klar, aber nur so kann ich einen "Treiber" für die Tastatur schreiben, oder ?
Wenn du einen richtigen Treiber schreiben willst dann verwende doch den entsprechenden IRQ/Interrupt der Tastatur, wie gesagt Polling/Busy Waiting ist in diesem Fall kompletter Müll und kaum später wiederverwendbar.
Ganze Sätze als fett markieren ist m.E. zuviel des Guten btw. :-)
-
Ähm, das kapier ich jetzt nicht ganz.
den entsprechenden IRQ/Interrupt der Tastatur
Für die Tastatur gibts doch viele INTs, wie Zeichen lesen und ausgeben, Zeichen lesen, Tastaturpuffer abfragen,....
Meinst Du ich soll doch die ganzen vorgegebenen Interrupts verwenden, die ich selbst schreiben wollte ??????????
Dann brauch ich doch gar keinen Treiber mehr (welchen ich ja selbst schreiben wollte)
-
den entsprechenden IRQ/Interrupt der Tastatur
Für die Tastatur gibts doch viele INTs, wie Zeichen lesen und ausgeben, Zeichen lesen, Tastaturpuffer abfragen,....
zwischen "auf Interrupts verzichten" und "auf BIOS-Interrupts verzichten" ein rießiger Unterschied ist.
Wie bluecode damit gesagt hat, gibt es einen himmelweiten Unterschied zwischen IRQs (bzw. "einfachen" Interrupts) und den BIOS-Interrupts.
-
Und was sind dann die einfachen Interrupts, bzw. welche Nummern haben die ?
Sind BIOS-Ints oder einfache INTs besser, bzw. hardware-unabhängiger ?
-
Was den Unterschied angeht: Gibt keinen. Interruptnummern werden via einer Tabelle Codestücke zugeordnet, die angesprungen werden (vereinfacht). bios-ints werden halt nur beim rechnerstart initialisiert, mit sinnvollen handlern die definierte tätigkeiten ausführen.
Zum was besser ist, Kommt wie immer dadrauf an was du jetzt genau vor hast. Solange du im Realmode bist ist es eigentlich doofe Codeduplikation wenn du nen eigenen Tastaturtreiber schreiben willst, ergo sind bios-ints angebracht. Da du im PMode eigentlich keine bios-ints mehr hast erübrigt sich die Frage da auch ;)
Wie du auf Hardware(un)abhängigkeit kommst ist mir jetzt ein Rätsel. Solange du auf x86 (und kompatiblen) arbeitest gibt es ints, die funktionieren halt so, und fertig. Hardwareabhängigkeit kommt ja erst rein wenn du mit spezifischer Hardware arbeitest. Für Tastaturen musst du dich aber um nix kümmern (eigentlich, sobald nen USB-Treiber ins Spiel kommt fällt für USB-Tastaturen die PS/2-Emulation weg).
Generell, siehe die Wiki-Artikel zu Interrupts und KBC, die sollten eigentlich alle Fragen beantworten ;)
-
Was ich meinte ist folgendes: Es ist eine Sache keine BIOS-Interrupts (Das sind bestimmte Interrupts, die das BIOS registriert um Funktionalität zur Verfügung zu stellen) zu verwenden. Es ist aber eine ganz andere Sache keine IRQs (Das sind bestimmte Interrupts, die die Hardware verwendet um Ereignisse anzuzeigen) zu verwenden. Auf letzteres zu verzichten bedeutet wie gesagt Polling und das hat keine Zukunft in einem Treiber.
-
Okay, aber die Sache mit den Interrupts beschäftigt mich noch. Bitte korrigiert mich, wenn ich irgendwie falsch liege :
- BIOS-Interrupts sind INTs, die vom BIOS zur Verfügung gestellt werden und die jedes x86-kompatible BIOS, egal ob BIOS aktuell oder nicht, zur Verfügung gestellt werden
- Aber woher kommen dann einfache Interrupts ?
-
Also, mal ganz von vorne: Mal ganz grob haben wir drei Arten von Interruptquellen. Das wären IRQs (Hardwareinterrupts), Exceptions und Softwareinterrupts. Einem Interrupt wird über die IVT (Real Mode) oder IDT (Protected Mode) ein ISR (Interrupthandler) zugewiesen. "Einfache" oder "komplexe" Interrupts gibt es nicht.
Wenn man von BIOS-Interrupt redet, meint man im allgemeinen, dass dein Code einen Softwareinterrupt auslöst, desser ISR eine BIOS-Funktion ist (das BIOS setzt beim Booten ein paar Einträge in der IVT auf seinen eigenen Code). Dadurch kannst du BIOS-Code ausführen. Das Prinzip ist ungefähr das gleiche wie wenn später ein Programm per Interrupt einen Syscall in deinem Kernel aufruft.
-
Dann eben so:
read_keyb:
cli ;Interrupts deaktivieren
in al,0x64h ;lese Port 0x64
test al,00000001b
jz read_keyb
in al,0x60 ;lese ASCII-Code der gedrückten Taste
sti ;Interrupts wieder zulassen
ret
Bewirkt aber dasselbe, und zwar dass das Lesen von Port 0x64 immer 0 liefert
Ich mache es so (MASM-Syntax):
; Zum Anfang sperre ich IRQ 1:
cli ; Software-Interrupts ausschalten
mov al, 2 ; IRQ 1 sperren
out 21h, al
sti ; Software-Interrupts einschalten
;-------------------------------------------------------------------------
; In der Hauptschleife kommt die eigentliche Tastatur-Abfrage:
MAIN:
in al, 64h ; Tastatur-Status holen
test al, 1
jz NOKEY ; wenn keine Taste weiter
test al, 20h
jnz NOKEY ; wenn PS2-Mouse weiter
in al, 60h ; Tasten-Code holen
dec al ; Escape-Taste ?
jz HOME ; Escape-Taste = Programm-Ende
inc al
;-------------------------------------------------------------------------
; E x t r a - T a s t e n a b f r a g e n
;-------------------------------------------------------------------------
mov si, OFFSET SONTAB ; Zeiger auf Extra-Tasten-Tabelle
mov cl, Extablen ; länge
XSUCH: cmp al, [si] ; Taste suchen
jz XFOUND ; gefunden ?
lea si, [si+1]
dec cl
jnz XSUCH
;-------------------------------------------------------------------------
; T a s t e n a b f r a g e n
;-------------------------------------------------------------------------
mov si, OFFSET TASTTAB ; Zeiger auf Tasten-Tabelle
mov cx, tablen ; länge
mov bx, OFFSET TEXTTAB ; Offset auf Text
SUCH: cmp al, [si] ; Taste suchen
jz FOUND ; gefunden ?
lea si, [si+1]
dec cx
jnz SUCH
jmp NOKEY
FOUND:
XFOUND:
NOKEY:
jmp MAIN
; .....................................
; Zum Ende erlaube ich IRQ 1 wieder:
; .....................................
HOME: in al, 60h ; Tasten-Code holen (Puffer leeren)
xor cl, cl ; kein Fehler
RAUS: cli
xor al, al ; IRQ 1 freigeben (Taste)
out 21h
sti
mov ah, 1 ; Tastatur-Puffer löschen
int 16h
mov al, cl ; ERRORLEVEL holen
mov ah, 4Ch ; Programm beenden
int 21h
;----------------------------------------------------
; Unser Datenbereich:
;.....................
TASTTAB DB 02h,03h,04h,05h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Dh
DB 10h,11h,12h,13h,14h,15h,16h,17h,18h,19h,1Ah,1Bh,1Eh,1Fh
DB 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Bh,2Ch,2Dh,2Eh,2Fh
DB 30h,31h,32h,33h,34h,35h,39h
DB 56h
tablen = ($-TASTTAB)
TEXTTAB DB "1234567890ß'"
DB "qwertzuiopü+as"
DB "dfghjklöä^#yxcv"
DB "bnm,.- "
DB "<"
Textablen = ($-TEXTTAB)
;----------------------------------------------------
; Tab,shift li.,shift re.,HOME,UP,LEFT,RIGHT,END,DOWN
;----------
SONTAB DB 0Fh,2Ah,36h,47h,48h,4Bh,4Dh,4Fh,50h
Extablen = ($-SONTAB)
DB 0,0,0
SHIFT DW 0
Dirk