尝试理解汇编语言中的中断,特别是16h功能1H。

3

这是一个作业,我不希望你解决我的问题,只需要一些理解就好了...

我需要在dosbox中使用ASM和C编程。我的第一个问题是我不太明白如何使用BIOS中断(任何带有代码样例的好教程都会非常感谢),好吧,我知道有中断,每个中断都有自己的功能和参数...

不管怎样我已经尝试过了...我需要做的事情从理论上来说很简单,我只需要从键盘获取一个字符,如果是1或0键,就计数,如果我按下五次1键,就打开扬声器,如果扬声器开着,并且我按下三次0键,则关闭扬声器,当鼠标移动到右边时也可以关闭它...

我几乎完成了它,我的问题是如何从中断返回一个字节并检查它。

为了获取字符,我使用INT 16H的01H函数,这就是为什么我不希望asm块等待新的字符出现,问题是我不知道如何获取告诉我是否有新字符到来的零标志,并且如果有的话,获取它并从键盘缓冲区删除它。

这里是我的循环:

// Loop
for(;;) {
        initTimer();

        if (key == ESC) break; // If ESC is pressed...

        if (mouseExist == TRUE) currentX = getMouseX(); // Mouse X position

        /* In that block I wait for the user input, it works...
        asm {
            mov AH, 08H  
            int 21H     // DOS-API
            mov key, AL

        }
        */
            // Block I don't get...UPDATED
        asm {
            mov ah, 01H
            int 16h
                    jz not_set // If zero flag is 1, jump to not_set, else
            mov key, al // Getting key
                    mov ah, 04H  // reset buffer
                    int 16H

        }
            not_set:
            // Count ones
        if (key == ONE && countOnes < MAX_ONES) {
            countOnes++;
            resetBuffer(); // Reset keyboard buffer (NOT WORKING)...
        }
        // Count 0s
        else if (key == ZERO && isPlaying == TRUE) countZeros++;

        // If I have enought zeros OR speaker is on AND mouse have been moved to            
            // the right 
        if (countZeros == MAX_ZERO || (initX < currentX && isPlaying == TRUE)) {
            stop(); // Stop speaker...It works...
            // Restore counters
            countOnes = 0;
            countZeros = 0;
            checkMouse(); // Reset Mouse...Works...
            showMouse(); // Works
            initX = getMouseX();
                currentX = initX;
            isPlaying = FALSE;
        } else if (countOnes == MAX_ONES) { // I have the ones
            isPlaying = TRUE;
            play(); // Turn on the speaker.
        }
            key = '\0';
           // I have also try to reset buffer here...No luck...
           //resetBuffer()
    }

函数ResetBuffer:

void resetBuffer() {
    asm {
        mov AH, 04H // Function reset
        int 16H
    }
}

Thanks in advance...


你在使用 Turbo C 吗? - P0W
是的,我使用dosbox... - josecash
我相信你可能需要重定向 INT 16H 函数 01H,并相应地处理缓冲输入的内部队列。这样,你就可以同时检查鼠标移动和按键。 - P0W
1个回答

1
您可以将标志位推入栈中,然后弹出到寄存器中以检查相应的位:
unsigned short flags;
asm {
    mov ah, 04h
    int 16h
    pushf
    pop ax
    mov flags, ax
}
if (flags & 0x40) {
    // zero flag is set
}

你也可以直接在汇编中检查标志位:

    mov ah, 04h
    int 16h
    jz not_set
    // here, if zero flag was set
not_set:

标签的确切语法取决于您的编译器。

非常感谢您的回答,我现在知道如何获取zero_flag并且我的short需要是无符号的。我已经更改了循环内的块以使用jnz,但现在它显示:未定义标签“not_set”,不知道为什么...它被声明了,我想...我已经更新了帖子... - josecash
我已经有20年没有使用Turbo C了,所以我无法检查内联汇编中标签工作的确切语法 - 但是你可以使用我的答案中的第一个选项(pushf/pop ax)来完成它而不需要标签。 - jlahd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接