1

DOSのアセンブラーx86を使用して、実際のアドレスモードを有効にするための詳細なプログラミングを学習しようとしています。しかし、これを実行しようとすると、ユーザーがコントロールキーの1つを押したかどうかを出力するプログラムを作成しようとします。CTRL、CAPS LOCK、またはSCROLL LOCKですが、問題はプログラムが印刷されないことです。ある種の基礎知識が不足しているような気がするので、ここの誰かが私のプログラムの何が悪いのか知っているのではないかと尋ねます。何も書きませんが、qを押すとシャットダウンできますか?..ありがとう

;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
4

2 に答える 2

1

BIOS呼び出しの正確な動作についての私の記憶int 16hはあいまいですが、トグル(capslock / numlock / scrollock)またはモディファイア(shift / ctrl / alt)キーを単独で押すと、から何も返されないと思いますint 16h。これらのキーは、ユーザーが非修飾キーを押すと、実際に返されるものを修飾するために使用されます。

実際のキーストロークを押すには、おそらくIRQ 9のISRを作成する必要があります(これがキーボードハードウェア割り込みの数であると確信しています)。その時点で、キーボードのすべてのキーの生の「make」および「break」スキャンコードを取得し、必要なアクションを実行できます。(もちろん、ISRでは、そのアクションは、後でISRの外部で処理するために、キー押下情報をバッファーに格納することに限定する必要があります。)

ssまた、プログラムの開始時に設定していることに注意してください。spただし、DOSは自動的にスタックを設定します。通常、それを行う必要はまったくありません。ただし、これを行う場合は、レジスタを変更している間は常にcliとを使用しstiて割り込みを無効にする必要があります。ss変更したがまだ変更していないときに割り込みが発生した場合sp、ISRはおそらく意図していなかったものを上書きします。

于 2012-09-25T00:12:13.500 に答える
1

グレッグは正しい。ss:spをロードする必要はありません。マニュアルの例でそれが示されていることは知っていますが、スタックが正しく宣言されている場合は、dosがそれを行います。あなたはそれを示さない。次のようなものにする必要があります:

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

行ったようにdsをロードする必要があります。現時点では、「CTRL:」までそのままにしておくのではなく、esも実行します。あなたの「書き込み文字列」はそれに依存します。(奇妙な割り込み、10時間/ 13時間!)

int 16h、ah=0は古い83キーキーボードに適しています。「ほぼ」すべてのキーストロークを取得しますが、いくつかのキーストロークを見逃します。私はそれについてかなりひどく混乱しました!(ずっと前ですが、今でも覚えています!)最近のキーボードにはah=10hを使用してください。いずれにせよ、「q」をチェックして終了します。ここまでは順調ですね!

次に、int 16h/2のフラグを取得します。その後のあなたの論理は私を逃れます!キーボードフラグに71hを追加していますか?そしてそれを2と比較しますか?私はあなたの条件付きジャンプのどれも取られていないと思います。それは何も印刷されていない理由を説明するでしょう!:)(25行80列にも印刷していますが、これは奇妙に思えます)

...(それを待つ)"test"命令でフラグをテストしたいと思います。これらの条件の複数が当てはまる可能性があるため、おそらく...

    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...

もちろん、サブルーチンにalを保持する必要があります。グレッグはまた、キーボード用に独自のint 9(irq 1)ハンドラーを作成している場合、この情報をバッファーに保存することも正しいです。既存のハンドラーはまさにそれを行います。BIOSデータエリアのセグメント40h...オフセットを忘れました...これらのフラグがあります。ここでint16h/2が'emを見つけます、私はかなり確信しています。そこで自分でアクセスすることもできますが、BIOS割り込みの方が簡単な場合があります(演習として試してみてください)。

最後になりましたが、wtfは「popbs」ですか?BSはセグメントレジスタではありません。NasmはBSを取りません!CPUはBSを取りません!:)

最高、フランク

于 2012-09-25T08:31:42.887 に答える