Search code examples
assemblyx86keyboardinterrupt

String doesn't print out in assembler


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

Solution

  • 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