Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Biehler Productions 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.
-
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!
-
OK. Ich probier den mal aus und hoffe, dass der funktioniert :D
-
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
-
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
-
Danke, es lag an dem STI.
Ich wusste nicht, dass bei einem INT Aufruf das Int flag gelöscht wird.
Nun gehts endlich :D