문제

I'm trying to learn some deep programming through assembler x86 in DOS, as it enables real adress mode. But in my attempt to do this im trying to make a program that prints out wether the user is has pressed one of the control keys; CTRL, CAPS LOCK or SCROLL LOCK but the problem is that the program dont print out. It feels like there is som lack of some kind of fundamental knowledge so I ask if someone here maybe knows whats wrong with my program. It doesn't write out anything but is able to shut down if I press q (as in quit)?.. Thanks

;reads the key and prints out whether a control key has been entered 
; (CTRL, CAPS LOCK or SCROLL LOCK)

[BITS 16]

SEGMENT data
ctrlmsg           db    'ctrl has been pressed', '$'
capslockmsg       db    'caps lock has been pressed', '$'
scrollmsg         db    'scroll lock has been pressed', '$'

SEGMENT code
..start:
mov ax, pile
mov ss, ax
mov ax, topofstack
mov sp, ax
mov ax, data
mov ds, ax
mov ax, ctrlmsg

WAITER:
    mov ah, 00h
    int 16h
    cmp al, 71h          ; user pressed q, and wants to end program
    je END
    mov ah, 02h          ; wait until user press keyboard and return keyboard flag in AL
    int 16h
    add al, 71h          ; add 71h back to al, so it goes unchanged in other comparisons
    cmp al, 02h          ; if key board flag is 02h then I expect user to have pressed CTRL
    je CTRL              ; then jump to CTRL label, in the same way it goes...
    add al, 02h
    cmp al, 04h
    je SCROLLOCK
    add al, 04h
    cmp al, 06h
    je CAPSLOCK
    jmp WAITER

END:
    mov ax, 04c00h        ; ends program
    int 21h

WRITESTRING:
    mov ah, 13h           ; 13h of int 10 is print string
    mov al, 00h           ; write mode 0 (no attributes)
    mov bh, 0h            ; video page number
    mov bl, 07h           ; foreground color
    mov cx, 05h           ; string length
    mov dh, 25            ; row
    mov dl, 80            ; col
    int 10h
    ret

CTRL:                     ; the other labels CAPS LOCK and SCROLL LOCK are quite similar why I haven't included them in the codesnippet
    push ds               ; save ds for subroutine 
    pop es                ; pop it in es
    push bp
    move bp, ctrlmsg      ; base pointer point to string
    call WRITESTRING
    pop bs
    jmp waiter            ; loop
도움이 되었습니까?

해결책

Greg is right. You shouldn't have to load ss:sp. I know it shows that in the example in the Manual, but dos does it for you... if your stack is declared correctly. You don't show that. Should be something like:

segment pile stack ; the "stack" is important!
    resw 100h ; should be enough for anybody

You do have to load ds as you've done. I'd do es too, at this time, rather than leave it until "CTRL:". Your "Writestring" depends on it. (weird interrupt, 10h/13h!)

int 16h, ah=0 is correct for old 83-key keyboards. It'll get "almost" all keystrokes, but it misses a few. I've confused myself quite badly on that one! (long time ago, but I still remember it!) Use ah=10h for modern keyboards. Either way, you check for 'q' and exit. So far so good!

Then you get flags with int 16h/2. Your logic after that eludes me! You're adding 71h to keyboard flags? And then comparing it to 2? I don't think any of your conditional jumps are being taken. That would explain why nothing is being printed! :) (you're also printing to line 25, column 80, which seems strange)

I think you want to test flags with the... (wait for it) "test" instruction. Since more than one of these conditions could be true, maybe something like...

    test al, 4 ; bit 2 - control key
    jnz notctrl
    call print_control
notctrl:
    test al, 16 ; bit 4 - scrollock active
    jnz not_scrl
    call print_scroll
notscrl:
    test al, 64 ; bit 6 - capslock active
; etc...

You'll have to preserve al in your subroutines, obviously. Greg is also right that, if you were writing your own int 9 (irq 1) handler for the keyboard, you'd save this information in a buffer. The existing handler does exactly that. In the Bios Data Area, segment 40h... I forget the offset... you'll find these flags. That's where int 16h/2 finds 'em, I'm pretty sure. You could access them there yourself, but the BIOS interrupt might be easier (maybe try it as an exercise?).

Last but not least, wtf is "pop bs"? BS is not a segment register. Nasm won't take no BS! The CPU won't take no BS! :)

Best, Frank

다른 팁

My memory of the exact behaviour of int 16h BIOS calls is vague, but I don't think toggle (capslock/numlock/scrollock) or modifier (shift/ctrl/alt) keys pressed by themselves return anything at all from int 16h. Those keys are used to modify what actually does get returned, once the user presses a non-modifier key.

To get the actual keystrokes pressed, you will probably need to write an ISR for IRQ 9 (I'm pretty sure that is the number for the keyboard hardware interrupt). At that point you can get the raw "make" and "break" scan codes for every key on the keyboard, and take whatever action you want. (In an ISR, of course, that action probably should be limited to storing the keypress info in a buffer for later processing outside the ISR.)

Also, I note that you're setting ss and sp at the start of your program, but DOS automatically sets up a stack for you. Normally you don't have to do that at all. If you do that however, you should always use cli and sti to disable interrupts during the time you're modifying the registers. If an interrupt happens when you have changed ss but not yet sp, the ISR will overwrite something you probably didn't intend.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top