Tastatur Interrupt

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
TomCat
MemMaker-Benutzer
Beiträge: 87
Registriert: Do 1. Dez 2011, 17:16

Tastatur Interrupt

Beitrag von TomCat »

Hallo,

bin grad dabei in meinem Grafikprogramm wieder was zu optimieren.
ich habe das Problem, dass mir die Tastatur-Interruptroutine den Timer-Interrupt um ca. 60 Mikrosekunden verzögert, bzw. den Interrupt solange sperrt. Ich würde gerne den Tastatur interrupt verbiegen und selber die Tastatur auslesen, um dies zu vermeiden.
Hat jemand mit der Tastatur Erfahrung, bzw. weiß wie man die ausliest,
bzw. so was schon mal gemacht?

THX, TomCat
DOSferatu
DOS-Übermensch
Beiträge: 1220
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: Tastatur Interrupt

Beitrag von DOSferatu »

Ja, hier, ich!
So gehts:
INT 09h verbiegen auf eine eigene Routine, die man mit IRET beendet (also NICHT "einklinken und normale Routine nach der eigenen aufrufen", SONDERN die Routine durch eigene ersetzen).
In der eigenen Routine Port 60h auslesen, dieser gibt den Scancode der zuletzt gedrückten Taste zurück, oder (wenn Tastencode+128, also oberstes Bit gesetzt), der losgelassenen Taste.
(Eine Liste der Scancodes und dazugehöriger Tasten für die englische und deutsche Tastaturbelegung kann ich liefern.)
Beim Programmieren beachten (wenn man will), daß bestimmte Tasten wie SHIFT, CTRL, ALT usw zusammen mit anderen Tasten gedrückt andere ASCIIs ergeben (z.B. Klein-/Großbuchstaben).
Hinweis dazu:
Manche Tasten liefern einen Doppelcode, erst 224, dann einen Scancode. Dies betrifft den 6erBlock (Einfg/Entf/Pos1/Ende/BildHoch/BildRunter), die Cursortasten und die rechten CTRL und ALT, sowie Enter des Nummernblocks. Die Codes entsprechen den Scancodes der Zweitbelegung des Nummernblocks (also 224 + Scancode), sowie für CTRL, ALT, ENTER die Codes ihrer "linken" Entsprechungen, angeführt von 224. Der Code 224 wird sowohl beim Drücken als auch Loslassen der entsprechenden Taste geliefert.
Eine Ausnahme ist die Pause-Taste, die eine ganze Reihe von Codes liefert (es ist 225 dabei) und die keinen "Loslaß-Code" generiert, sondern Drück/LoslaßCode gleich beim Drücken.
Da es nur max. 128 mögliche Tastencodes gibt (0 bis 127, wobei 0 nicht benutzt wird und einige andere auch nicht), weil ja Codes mit gesetztem oberen Bit für "Loslassen" gelten, mache ich es immer so, daß ich den "Doppelcode" Tasten in einer Tabellenmatrix die Nummern 128-255 zuweise.

Man sollte sich also im INT merken, ob der zuletzt gelieferte Scancode =224 war und dann entsprechend den nächsten Scancode als "Doppelcode-Taste" behandeln.

Anmerkung: Ich mache das so, daß ich mir ein Feld von 256 Bits (oder Bytes oder wasweißich) setze und wenn eine Taste gedrückt wird, setze ich das entsprechende Feld auf 1, wenn losgelassen auf 0.
Es ist zu beachten, daß eine Taste mehrere "Drücken" Codes hintereinander sendet, wenn man sie gedrückt hält. Dies ist die Tastenwiederholung, die nach einer bestimmten Zeitspanne einsetzt und dann mit in festen Zeitintervallen diese wiederholten Codes sendet. Beides kann über Befehle an das Keyboard eingestellt werden.

Falls noch Fragen bestehen, wie man den Tastaturpuffer und die Bits für die gedrückten "Steuertasten" setzt, sowie die LEDs der Tastatur entsprechend an/ausschaltet - auch dazu kann ich weiterhelfen.
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Tastatur Interrupt

Beitrag von freecrac »

TomCat hat geschrieben:Hallo,

bin grad dabei in meinem Grafikprogramm wieder was zu optimieren.
ich habe das Problem, dass mir die Tastatur-Interruptroutine den Timer-Interrupt um ca. 60 Mikrosekunden verzögert, bzw. den Interrupt solange sperrt. Ich würde gerne den Tastatur interrupt verbiegen und selber die Tastatur auslesen, um dies zu vermeiden.
Hat jemand mit der Tastatur Erfahrung, bzw. weiß wie man die ausliest,
bzw. so was schon mal gemacht?

THX, TomCat
Anstelle das man den Tastatur-Interrupt auf seine eigene Interruptroutine legt, kann man auch den Tastatur-Interrupt sperren, so das beim Drücken einer Taste gar kein Interrupt mehr ausgelöst wird.
Stattdessen holen wir dann wenn wir eine Tastenabfrage benötigen den Tastencode vom Port 60h ab und werten ihn aus. (So eine Polling hat aber auch seine Grenzen und ist nicht überall geeignet.)

Beispiel:

Code: Alles auswählen

; Zum Anfang schalte ich den Tastastatur-IRQ ab:
     cli                      ; Software-Interrupts ausschalten
     mov      al, 2           ; IRQ 1 sperren
     out      21h, al
     sti

; Hauptschleife:

P1:
     in       al, 64h          ; Tastatur-Status holen
     test     al, 1
     jz  P1                    ; an dieser Stelle könnte auch die Abfrage weiter nach vorne übersprungen werden (auch  wenn PS2-Mouse-Byte gefunden zwei Befehle tiefer)
     test     al, 20h
     jnz P1                    ; wenn PS2-Mouse weiter
     in       al, 60h          ; Tasten-Code holen
     cmp      al, 1            ;  Escape ?
     jz  XRAUS
;---------------------------------------------
;  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  short FOUND              ;  gefunden ?
     lea      si, [si+1]
     dec      cx
     jnz SUCH
     jmp  P1                      ;  auch von hier könnte man weiter nach vorne springen und erst später nach "P1".
;---------------------------------------------
FOUND:

;---------------------------------------------
XFOUND:

;---------------------------------------------
XRAUS:

; Zum Ende schalte ich den Tastastatur-IRQ wieder an:
          cli
          xor      al, al          ; IRQ 1 freigeben
          out      21h, al
          sti
          mov      ah, 1           ; Tastatur-Puffer löschen
          int   16h

;---------------------------------------------
;  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
TomCat
MemMaker-Benutzer
Beiträge: 87
Registriert: Do 1. Dez 2011, 17:16

Re: Tastatur Interrupt

Beitrag von TomCat »

Vielen Dank erstmal !!

werde ich gleich mal ausprobieren. Weil du dich da so gut auskennst,
ich wollte grad mit BIOS-Funktion 12h INT16h die Num-Taste auf der Tastatur zu aktivieren. Scheint aber nicht zu gehen, weil man da ja den Scan-Code und Ascii-code wohl übergeben muss. Allerdings finde ich nirgens den Scan/Ascii-Code der Num-Taste. :(

Hast du ne Idee, wie man das bewerksteligen könnte?

THX TomCat
TomCat
MemMaker-Benutzer
Beiträge: 87
Registriert: Do 1. Dez 2011, 17:16

Re: Tastatur Interrupt

Beitrag von TomCat »

Hi,

also das Tastenlesen funktioniert perfekt. hab das auf eine eigene Interrupt-Routine umgeleitet und erfasse dort die Tastatur. (Pollingschleife zu zeitraubend)

Für ne Simulation versuche ich grad werte in den Eingangspuffer der Tastatur zu schicken.

um z.B. die Taste "s" zu simulieren habe ich einfach am port 60h den wert
31 ausgegeben.

mov al,31
out 60h,al

leider funktioniert das wohl so nicht so einfach.
Hast du ne Idee wie das geht?

THX TomCat
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Tastatur Interrupt

Beitrag von freecrac »

TomCat hat geschrieben:Hi,

also das Tastenlesen funktioniert perfekt. hab das auf eine eigene Interrupt-Routine umgeleitet und erfasse dort die Tastatur. (Pollingschleife zu zeitraubend)

Für ne Simulation versuche ich grad werte in den Eingangspuffer der Tastatur zu schicken.

um z.B. die Taste "s" zu simulieren habe ich einfach am port 60h den wert
31 ausgegeben.

mov al,31
out 60h,al

leider funktioniert das wohl so nicht so einfach.
Hast du ne Idee wie das geht?

THX TomCat
Ich bin mir nicht sicher ob und wie man so etwas simulieren kann.
Ich glaube bevor man Bytes sendet sollte man überprüfen, ob der interne Eingabepuffer des Kontrollers schon bereit ist um neue Daten aufzunehmen.
Aber der Eingabepuffer unterscheidet sich schon etwas vom Ausgabepuffer und ist mit dem nicht identisch.

RBIL->inter61d.zip->Ports.a
--------K-P0060006F--------------------------
PORT 0060-006F - KEYBOARD CONTROLLER 804x (8041, 8042) (or PPI (8255) on PC,XT)
Note: XT uses ports 60h-63h, AT uses ports 60h-64h

0060 RW KB controller data port or keyboard input buffer (ISA, EISA)
should only be read from after status port bit0 = 1
should only be written to if status port bit1 = 0
....

0064 R- keyboard controller read status (see #P0398,#P0399,#P0400)

Bitfields for keyboard controller read status (ISA, EISA):
Bit(s) Description (Table P0398)
7 parity error on transmission from keyboard
6 receive timeout
5 transmit timeout
4 keyboard interface inhibited by keyboard lock
or by password server mode (IBM PS/2-286 [model bytes FCh/09h],
"Tortuga" [model F8h/19h]) (see #00515 at INT 15/AH=C0h)
3 =1 data written to input register is command (PORT 0064h)
=0 data written to input register is data (PORT 0060h)
2 system flag status: 0=power up or reset 1=selftest OK
1 input buffer full (input 60/64 has data for 8042)
no write access allowed until bit clears
0 output buffer full (output 60 has data for system)
bit is cleared after read access
SeeAlso: PORT 0064h-R,#P0399,#P0400,#P0401

;------------------

0064 -W keyboard controller input buffer (ISA, EISA) (see #P0401)

(Table P0401)
Values for keyboard controller commands (data goes to PORT 0060h):
Value Description
20h read read byte zero of internal RAM, this is the last KB command sent to the 8041/8042 Compaq put current command byte on PORT 0060h (see #P0403,#P0404)
21-3F read reads the byte specified in the lower 5 bits of the command in the 804x's internal RAM (see #P0407)
.....
Dirk
Brueggi

Re: Tastatur Interrupt

Beitrag von Brueggi »

Ich kann mich jetzt irren, aber man kann glaub ich nicht einfach Tasten-Bytes zur Tastatur schicken, in der Annahme, diese sendet das Byte wieder zurück. Vielmehr erwartet die Tastatur bestimmte Befehls-Bytes, die irgendetwas bewirken, zum Beispiel die Tastenwiederholrate setzen, den Controller zurück setzen oder PS/2-Maus-Eigenschaften (Abtastrate usw.) ändern. Allgemein - bei der Tastatur jetzt nicht soo wichtig - würde ich nie "auf gut Glück" irgendwelche Schreibzugriffe auf Ports machen, die ggf. nur zum Auslesen gedacht sind. Das könnte - je nach Chip und PC, sowie der Häufigkeit der Schreibzugriffe - weniger gut für die Hardware sein.

Du kannst aber vielleicht deinen Tastatur-Interrupt erstmal so umschreiben, dass er nicht mit IN ein Byte von der Tastatur holt, sondern den Scancode in AH oder sonstwo erwartet. Dann kannst Du ein Testprogramm basteln, das zur kontrolle diverse Scancodes an den Interrupt übergibt und das Ergebnis entsprechend auswertet. Noch eine Frage an freecrac: War das jetzt der Timer- oder Tastaturinterrupt, der nochmals durch die Hardware abgelenkt wird? IRgendeinen IRQ durfte man doch nicht einfach mit IRET beenden, da zu dem zeitpunkt noch irgendetwas auf dem Stack liegt... Hab jetzt leider grad nicht PC-Intern zur Hand :-(
Brueggi

Re: Tastatur Interrupt

Beitrag von Brueggi »

Ich kann mich jetzt irren, aber man kann glaub ich nicht einfach Tasten-Bytes zur Tastatur schicken, in der Annahme, diese sendet das Byte wieder zurück. Vielmehr erwartet die Tastatur bestimmte Befehls-Bytes, die irgendetwas bewirken, zum Beispiel die Tastenwiederholrate setzen, den Controller zurück setzen oder PS/2-Maus-Eigenschaften (Abtastrate usw.) ändern. Allgemein - bei der Tastatur jetzt nicht soo wichtig - würde ich nie "auf gut Glück" irgendwelche Schreibzugriffe auf Ports machen, die ggf. nur zum Auslesen gedacht sind. Das könnte - je nach Chip und PC, sowie der Häufigkeit der Schreibzugriffe - weniger gut für die Hardware sein.

Du kannst aber vielleicht deinen Tastatur-Interrupt erstmal so umschreiben, dass er nicht mit IN ein Byte von der Tastatur holt, sondern den Scancode in AH oder sonstwo erwartet. Dann kannst Du ein Testprogramm basteln, das zur kontrolle diverse Scancodes an den Interrupt übergibt und das Ergebnis entsprechend auswertet. Noch eine Frage an freecrac: War das jetzt der Timer- oder Tastaturinterrupt, der nochmals durch die Hardware abgelenkt wird? IRgendeinen IRQ durfte man doch nicht einfach mit IRET beenden, da zu dem zeitpunkt noch irgendetwas auf dem Stack liegt... Hab jetzt leider grad nicht PC-Intern zur Hand :-(
TomCat
MemMaker-Benutzer
Beiträge: 87
Registriert: Do 1. Dez 2011, 17:16

Re: Tastatur Interrupt

Beitrag von TomCat »

@Brueggi:

doch kann man schon! Geht sogar übers Bios
Int16h. Ich will das aber gerne low level machen. alleine schon weils mich interessiert.
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Tastatur Interrupt

Beitrag von freecrac »

Brueggi hat geschrieben:Noch eine Frage an freecrac: War das jetzt der Timer- oder Tastaturinterrupt, der nochmals durch die Hardware abgelenkt wird? IRgendeinen IRQ durfte man doch nicht einfach mit IRET beenden, da zu dem zeitpunkt noch irgendetwas auf dem Stack liegt... Hab jetzt leider grad nicht PC-Intern zur Hand :-(
Ich schaue in mein PC-Intern gleich noch einmal rein und melde mich dann zurück.

Meinst du so etwas hier: http://www.delorie.com/djgpp/doc/ug/int ... lers1.html
In case you're wondering how is accomplished the interrupt acknowledge sequence, here's a quick overview :

1. Eight interrupt lines IR0-IR7 are connected to the interrupt request register (IRR). The IRR is eight bits wide, where every bit corresponds to one of the lines IR0-IR7. The device requiring service signals the PIC via one of the eight pins IR0-IR7 setting it to a high level. The 8259A then sets the corresponding bit in the IRR.

2. At the same time, the PIC activates its output INT line to inform the processor about the interrupt request. The INT line is directly connected to the INTR input of the processor. This starts an interrupt acknowledge sequence.

3. The CPU receives the INT signal, finishes the currently executing instruction and outputs a first interrupt acknowledge (INTA) pulse if the IE flag is set (that is, if the interrupts are not masked at the CPU).

4. Upon receival of the first INTA pulse from the CPU the highest priority in the IRR register is cleared and the corresponding bit in the in-service register (ISR) register is set.There is no PIC activity on the data bus in this cycle.

5. The processor initiates a second INTA pulse and thus causes the 8259A to put an 8-bit number onto the data bus. The CPU reads this number as the number of the interrupt handler to call, which is then fetched and executed.

6. In the Automatic End Of Interrupt (AEOI) Mode the ISR bit is reset at the end of the second INTA pulse. Otherwise, the CPU must issue an End of Interrupt (EOI) to the 8259A PIC when executing the interrupt handler to clear the ISR bit manually.

The EOI command has two forms, specific and non-specific. The controller responds to a non-specific EOI command by resetting the highest in-service bit of those set. In a mode that uses a fully-nested interrupt structure, the highest in-service bit set is the level that was just acknowledged and serviced. This is the default mode for PCs. In a mode that can use other than the fully-nested interrupt structure, a Specific EOI command is required to define which in-service bit to reset.

Is this all there is to it? Usually, yes. But things can get a little trickier depending on the environment. For example, as the name indicates the 8259A programmable interrupt controller can be programmed under several different modes and for a defined operation it needs to be initialized first. For instance, it can be programmed to mask certain interrupt request lines. In order to do that the interrupt mask register is implemented. A set bit in this register masks all the interrupt requests of the corresponding peripheral, that is, all requests on the line allocated the set bit are ignored; all others are not affected by the masking.

And what happens if an interrupt comes when another is being processed, and the EOI for it wasn't issued yet? This really depends on interrupt priorities. If a certain interrupt request is in-service (that is, the corresponding bit in the ISR is set), all interrupts of a lower priority are disabled because the in-service request is serviced first. Only an interrupt of a higher priority pushes its way to the front immediately after the INTA sequence of the serviced interrupt. In this case the current INTA sequence is completed and the new interrupt request is already serviced before the old request has been completed by an EOI. Thus, interrupt requests of a lower priority are serviced once the processor has informed the PIC by an EOI that the request has been serviced. Please note that, under certain circumstances, it is favourable also to enable requests of a lower priority using the PIC programming abilities to set the special mask mode (if you're curious check the reference section for further reading).
Dirk
TomCat
MemMaker-Benutzer
Beiträge: 87
Registriert: Do 1. Dez 2011, 17:16

Re: Tastatur Interrupt

Beitrag von TomCat »

Hmmm,

das mit dem Interrupt ist ja ueberhaupt kein Problem. Aber wie schickt man nun, low level, Zeichen an die Tastatur, wenn man nicht den Int 16h benutzen will?

THX,
TomCat
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: Tastatur Interrupt

Beitrag von wobo »

Nee, da hat Brueggi schon Recht: Tastenanschläge kann man an die Tastatur nicht senden. Zumindest nicht bei den AT-Tastaturen bis 1995. Die Tastatur versteht nur Befehlsbyte, aber keine Datenbyte. Die kann sie nur senden, aber nicht empfangen.

Ich schließe auch aus, dass es eine Funktion des Int $16 (BIOS) gibt, das eine Taste an die Tastatur sendet, welches die Tastatur zurücksendet. Welche genaue Funktion von int $16 soll denn das bitte können?

Der Tastaturpuffer hat - nur rein vorsorglich ;-) - auch nichts mit der Tastatur im Hardware-Sinn zu tun. Er ist ein reines Konstrukt des IBM-BIOS.
Brueggi

Re: Tastatur Interrupt

Beitrag von Brueggi »

@freecrac: Hui - Danke für das Posten des Textes. Coole Sache! :-) Da les ich mich mal in Ruhe durch (war die letzten Tage wieder mit BDOS beschäftigt).

@wobo: Genau :-) Die BIOS-Funktion legt eine Taste in den Puffer, so dass beim nächsten Aufruf das BIOS eben denkt, man hätte diese Taste betätigt. Von der Tastatur-Hardware stammt diese aber nicht.
Antworten