Autor Thema: ASM Tastaturtreiber geht nicht  (Gelesen 6102 mal)

Biehler Productions

  • Beiträge: 51
    • Profil anzeigen
    • http://bielos.de.tk
Gespeichert
« am: 24. June 2006, 19:37 »
Hallo,
ich bin nun wieder dabei für mein RM OS einen Tastaturtreiber in ASM zu schreiben.
Aber wieder das gleiche Problem, wie vor einem Jahr: Er geht nicht.
Das letzte Mal hatte ich auch einen Thread aufgemacht, leider kam es da zu keinem Ergebniss.
Deshalb versuche ich es hier erneut.

Code:

[...]
CLI
MOV WORD [ES:6H*4],INT6H
MOV WORD [ES:6H*4+2],CS
MOV WORD [ES:4*9h],int9h
MOV WORD [ES:4*9h+2],CS
MOV WORD [ES:4*16h],int16h
MOV WORD [ES:4*16h+2],CS
MOV AX,9000H
MOV SS,AX
MOV SP,200H
STI

int 16h
[...]

int16h:
tests:
CMP BYTE [ds:scan], 0
MOV AH, 0eh
mov al, "W"
int 10h
JE tests
MOV AH, 0eh
mov al, [scan]
int 10h
iret
;hier beginnt der Keyboardtreiber
int9h:

pusha                       ;alle Register retten
;PUSH ES
;PUSH DS
MOV AX,CS
MOV ES,AX
MOV DS,AX
in AL,60h                   ;Port 60 lesen
;and AL,AL                   ;AND mit sich selbst - setzt "Sign" Flag, wenn >=128
;js Weiter                  ;Taste losgelassen - also nichts tun
cmp al,129
JAE Weiter
;:::::::::::::
;Hier das tun, was immer man tun will, wenn einer ne Taste drückt.
mov bl,al
lea si,[scancode]
check_scan:
lodsb
cmp bl,al
JE scan_ok
cmp word [si],0AAAAh
JE Weiter
inc si
inc si
inc si
jmp check_scan

scan_ok:
lodsb
mov byte [scan],al
;:::::::::::::
Weiter:                    ;hierhin wird gesprungen, wenn nur losgelassen
mov AL,20h                  ;Code 20h für "reset PIC"
out 20h,AL                  ;in den PIC (Port 20h) schreiben
;POP DS
;POP ES
popa                        ;alle Register wiederholen
iret                        ;und Int beenden





;Scancodes deutsche tastatur
scan db 0
scancode:
db 10h,"q","Q","@"
db 11h,"w","W",0
db 12h,"e","E",238
db 13h,"r","R",0
db 14h,"t","T",0
db 15h,"z","Z",0
db 16h,"u","U",0
db 17h,"i","I",0
db 18h,"o","O",0
db 1ch,13,0,0
dw 0aaaah




DB 510-$ DUP(0)
DW 0AA55h


Das Problem ist bei der INt 16H Routine.
ich biege den INT 16H um und rufe ihn auf.
Doch anstatt einen ASCII Code zurückzuliefern, besteht eine Endlosschleife.
Der INT16H fragt das Byte "scan" ab. In dieses wird vom INT 9 der ASCII Code hineingeschrieben, wenn eine Tatse gedrückt worden ist.
Die segmentregister sind alle gleich, da dr gesamte Code im Bootloader an 07C0H:0H ist.

Das komische:
Führe ich den Code

tests:
CMP BYTE [ds:scan], 0
MOV AH, 0eh
mov al, "W"
int 10h
JE tests
MOV AH, 0eh
mov al, [scan]
int 10h

Außerhalb einer Interrupt Routine aus, so funktioniert er schon.

Anzumerken ist, dass ich den BOCHS Emulator benutze.

Osbios

  • Beiträge: 247
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 24. June 2006, 21:03 »
Hatte keine Lust deinen Code zu lesen, hab daher kurzum etwas funktionierendes geschrieben. :D

use16
org 0x7C00

;CS:IP=7C0:$
jmp 0x0:start
start:

;CPU: Interrupts auschalten
cli

;IVT: neue Adresse fuer IRQ 1 bzw. Interrupt 0x9 setzen
mov word[0x9*4  ], IRQ1
mov word[0x9*4+2], 0

;CPU: Interrups einschalten
sti

jmp $


;IN: al = char
draw_char:
  pusha

  MOV AH,0Eh
  INT 10h

  popa
ret


Keyboard_layout_de db 0,0,49,50,51,52,53,54,55,56,57,48,225,39,1,0,113,119,101,114,116,122,117,105,111,112,129,43,2,0,97,115,100,102,103,104,106,107,108,148,132,94,0,35,121,120,99,118,98,110,109,44,46,45,0,42,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,0,43,0,0,0,0,0,0,0,60,0,0

IRQ1:
  pusha

  in   al, 0x60
  cmp  al, 128
  jae  .end

  push word 0
  pop  ds
  mov  bl, al
  mov  bh, 0
  mov  al, [Keyboard_layout_de+bx] ;Scancode zu ASCII machen
  call draw_char

.end:
  mov  al, 0x20
  out  0x20, al ;Set PIC1 back

  popa
iret


;510 Byte
times 510-($-$$) db 0
;Bootsignatur
dw 0xAA55


Copyleft!
db 0x55AA

Biehler Productions

  • Beiträge: 51
    • Profil anzeigen
    • http://bielos.de.tk
Gespeichert
« Antwort #2 am: 25. June 2006, 12:12 »
OK. Ich probier den mal aus und hoffe, dass der funktioniert  :D

Biehler Productions

  • Beiträge: 51
    • Profil anzeigen
    • http://bielos.de.tk
Gespeichert
« Antwort #3 am: 25. June 2006, 14:07 »
Also, der Code ist leider nicht das, was ich brauchen würde :(
Das, was ich will, ist, dass der Code "draw_char" in eine Interruptroutine verlagert wird.
Ich habs nun so gemacht:

MOV AX,0
MOV ES,AX
mov BYTE [es:0], 0
CLI
MOV WORD [ES:4*9h],IRQ1w
MOV WORD [ES:4*9h+2],CS
mov word [es:4*16h], int16h
mov word [es:4*16h+2], cs
STI

int 16h ;rufe INT 16H auf
jmp $

[...]

scan db 0
;IN: al = char
int16h:
cli
draw_char:
  pusha
  assd:
  mov ax, 0
  mov es, ax
  CMP BYTE [scan], 0
  JE assd
  mov al, [scan]
  MOV AH,0Eh
  INT 10h

  popa
 sti
iret


Und das funktioniert wieder nicht.
Ich hab mir auch schon den ASM Code eines IBM Bios angeschaut, werd aber nicht schlau daraus, was die so großartig anders gemacht haben.

Falls noch wer den Code der IRQ1 Routine benötigt, momentan sieht er so aus:


Keyboard_layout_de db 0,0,49,50,51,52,53,54,55,56,57,48,225,39,1,0,113,119,101,114,116,122,117,105,111,112,129,43,2,0,97,115,100,102,103,104,106,107,108,148,132,94,0,35,121,120,99,118,98,110,109,44,46,45,0,42,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,0,43,0,0,0,0,0,0,0,60,0,0

IRQ1w:
cli
  pusha
IN AL,60h ; Read the scan code
PUSH AX ;  ...save it
IN AL,61h ; Get control port status
PUSH AX ;  ...save it
OR AL,80h
OUT 61h,AL ; Reset keyboard
POP AX ;  ...restore control status
OUT 61h,AL ;  ...keyboard has been reset
POP AX ;  ...restore scan code


  ;in   al, 0x60
  ;cmp  al, 128
  ;jae  endd

  ;push word 0
  ;pop  ds
  mov  bl, al
  mov  bh, 0
  mov  al, [Keyboard_layout_de+bx] ;Scancode zu ASCII machen
  MOV [scan], al

endd:
  mov  al, 0x20
  out  0x20, al ;Set PIC1 back

  popa
  sti
iret


Osbios

  • Beiträge: 247
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 25. June 2006, 15:53 »
Wenn ichs richtig verstandan habe willst du, dass IRQ1 die gedrückte Taste in einen Zwischenspeicher schreibt und man diesen dann über einen Software-Interrupt auslesen kann, bzw. dieser Software-Interrupt darauf wartet bis eine Taste gedrückt wurde?

Habsch mal was weiter geschrieben. Allerdings nicht nur mit einer Variable zum zwischenspeichern der Tasten, sondern gleich einen richtigen 16 Byte Ringbuffer.

Hierbei ist das STI in der INT16h-Funktion zu beachten, denn auch Softwareinterrupts löschen das Interruptflag (CLI), und dann kann man natürlich lange auf den IRQ1 warten. :]

use16
org 0x7C00

;CS:IP=7C0:$
jmp 0x0:start
start:

;CPU: Interrupts auschalten
cli

;IVT: neue Adresse fuer IRQ 1 bzw. Interrupt 0x9 setzen
mov word[0x9*4  ], IRQ1
mov word[0x9*4+2], 0

;IVT: neue Adresse Interrupt 0x16 setzen
mov word[0x16*4  ], INT16h
mov word[0x16*4+2], 0

;CPU: Interrups einschalten
sti

schleife:
  int  0x16
  call draw_char
jmp schleife


;IN: al = char
draw_char:
  pusha

  MOV AH,0Eh
  INT 10h

  popa
ret


ringbuffer_write_pos db 0
ringbuffer_read_pos db 0
ringbuffer: times 16 db ?

;OUT: al=char
INT16h:
  push bx

  xor  bx, bx

  sti  ;<-- auch bei einem Software-Interrupt wird cli aufgerufen
  mov  bl, [ringbuffer_read_pos]
.wait_for_key:
  cmp  bl, [ringbuffer_write_pos]
  je   .wait_for_key
 
  mov  al, [ringbuffer+bx]
  inc  bl
  and  bl, 0xF
  mov  [ringbuffer_read_pos], bl
 
  pop  bx
iret


Keyboard_layout_de db 0,0,49,50,51,52,53,54,55,56,57,48,225,39,1,0,113,119,101,114,116
db 122,117,105,111,112,129,43,2,0,97,115,100,102,103,104,106,107,108
db 148,132,94,0,35,121,120,99,118,98,110,109,44,46,45,0,42,0,32,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,0,43,0,0,0,0,0,0,0,60,0,0

IRQ1:
  pusha

  in   al, 0x60
  cmp  al, 128
  jae  .end

  push word 0
  pop  ds
  mov  bl, al
  mov  bh, 0
  mov  al, [Keyboard_layout_de+bx] ;Scancode zu ASCII machen

  ;Zeichen im Ringbuffer speichern
  mov  bl, [ringbuffer_write_pos]
  mov  cl, bl
  inc  cl
  and  cl, 0xF
  cmp  cl, [ringbuffer_read_pos]
  je   .end ;ringbuffer is full
 
  mov  [ringbuffer+bx], al
  mov  [ringbuffer_write_pos], cl

.end:
  mov  al, 0x20
  out  0x20, al ;Set PIC1 back

  popa
iret


;510 Byte
times 510-($-$$) db 0
;Bootsignatur
dw 0xAA55
db 0x55AA

Biehler Productions

  • Beiträge: 51
    • Profil anzeigen
    • http://bielos.de.tk
Gespeichert
« Antwort #5 am: 28. June 2006, 16:13 »
Danke, es lag an dem STI.
Ich wusste nicht, dass bei einem INT Aufruf das Int flag gelöscht wird.
Nun gehts endlich  :D

 

Einloggen