Assembly 中断10h的功能06h。滚动文本行

Assembly 中断10h的功能06h。滚动文本行,assembly,x86,bootloader,fasm,video-memory,Assembly,X86,Bootloader,Fasm,Video Memory,我需要使用中断10h的功能06h实现滚动排队。问题是我有滚动的行,但符号没有显示,光标消失,什么也没有发生。也许我忘了要考虑的事情了?要编写代码,我使用FASM。该代码是引导加载程序的一部分。下面是一段与滚动相关的代码: cmp cx, 2001 je ScrollLine 我有一个计数器,当它达到2001(从1开始计数)时,控制传递到ScrollLine 滚动线: mov ah, 06h mov al, 1 mov bh, 07 mov cx, 0000h mov dx, 184

我需要使用中断10h的功能06h实现滚动排队。问题是我有滚动的行,但符号没有显示,光标消失,什么也没有发生。也许我忘了要考虑的事情了?要编写代码,我使用
FASM
。该代码是引导加载程序的一部分。下面是一段与滚动相关的代码:

cmp cx, 2001
je ScrollLine
我有一个计数器,当它达到2001(从1开始计数)时,控制传递到ScrollLine

滚动线:

mov ah, 06h
mov al, 1
mov bh, 07      
mov cx, 0000h
mov dx, 184Fh 
int 10h
ret
我的完整引导加载程序代码如下:

use16
org 7C00h

start:
    mov ah, 00h  
    mov al, 02h              
    int 10h

    mov ax, NewInt40
    call ChangeIVT

    mov cx, 0

wait_loop:
    xor ax, ax

    inc cx

    cmp cx, 2001
    je ScrollLine

    mov ah, 0
    int 16h

    push ax
    call PrintChar

    jmp wait_loop

NewInt40:   
    sti
    push ax
    mov ax, msg
    cmp bl, 3
    je PrintChar
    cmp bl, 2
    je PrintString
    cmp bl, 1
    je Clear
    cmp bl, 4
    je Scroll
    pop ax
    iret

ChangeIVT:

    push bx
    xor bx, bx

    mov es, bx
    mov bx, 40h
    shl bx, 2

    mov word [es:bx], ax
    mov word [es:bx+2], 0

    pop bx
    ret

PrintString:

    push si
    push bx
    push es
    mov si, ax

    mov ax, 0B800h
    mov es, ax

    xor bx, bx
    xor dx, dx

@@:
    lodsb   

    cmp al, 0
    je @f

    mov byte [es:bx], al
    mov byte [es:bx+1], 1Eh

    mov ah, 0Eh
    add bx, 2
    inc dx
    mov ah,02h
    mov al,02h  
    int 10h
    jmp @b

@@:
    pop es
    pop bx
    pop si
    ret

PrintChar:

    push bp
    mov bp, sp
    push bx
    push es
    push cx

    mov ax, 0B800h
    mov es, ax

    xor bx, bx
    xor dx, dx

    mov ah,3
    int 0x10

    movzx ax, dh
    movzx bx, dl
    mov cx, 80
    push dx
    mul cx
    pop dx
    add bx, ax  ; bx = 80 * dh + dl
    shl bx, 1   ; bx = 2 * (80 * dh + dl)



    mov ax, [bp + 4]
    mov byte [es:bx], al
    mov byte [es:bx+1], 1Eh

    cmp dl, 79
    jl @f

    inc dh
    mov dl, -1
@@:
    inc dl

    pop cx
    mov bh, 0

    mov ah, 2
    int 0x10

    pop es
    pop bx
    mov sp, bp
    pop bp
    ret

Clear:
   mov  AH,0      
   mov  AL,2      
   int  10H       
   ret

Scroll:
    mov ah, 06h
    mov al, 1
    mov bh, 07      
    mov cx, 0000h
    mov dx, 184Fh 
    int 10h
    ret

ScrollLine:
    mov bl, 4
    int 40h
    xor cx, cx
    ret

msg db "Hello, world!", 0Dh, 0Ah, 0

db 510-($-$$) dup (0)

db 55h, 0AAh
你在用跳跃呼叫

NewInt40
ISR中,您可以有条件地跳转到子例程
PrintString
PrintChar
滚动
,等等,但从这些子例程返回
ret

我不知道代码是如何构造的,所以我只介绍了使其工作所需的最小的更改,没有什么可以称为良好实践

由于您正在编写引导加载程序,您现在肯定知道要修复什么了

NewInt40:   
    sti
    push ax

    push bp             ;; Save caller's BP
    mov bp, sp          ;; Save SP, so we can restore the stack pointer

    push WORD _ni40_end ;; Push return address of every routine

    mov ax, msg
    cmp bl, 3
    je PrintChar
    cmp bl, 2
    je PrintString
    cmp bl, 1
    je Clear
    cmp bl, 4
    je Scroll


_ni40_end:          ;; NASM label
    mov sp, bp      ;; Restore stack pointer (in any case) 
    pop bp          ;; Restore caller BP

    pop ax
    iret
对不起,我是为NASM写的,不过翻译成FASM应该很容易

附加说明
当您的引导加载程序“变得疯狂”时,如不响应或自行行动,很可能是您“失去了执行流程”的症状。
这意味着您正在执行的字节不是您的代码,当您返回的堆栈不平衡时,就会发生这种情况。

如果类似情况再次发生,请仔细检查您的报税表。

因此,您在报税表上显示了一个字符,例如,在报税表上显示了一个字符,而这正是问题出现的时间?文本滚动,但随后输出出现问题?您可以发布更多代码吗?简单的演示程序(用于NASM)使用与您相同的中断调用,运行良好。@MargaretBloom:有点吹毛求疵,但在您的代码中,当您创建COM程序时设置SS:SP、DS等有什么意义(我假设从org 100h开始)?DOS加载器自动加载COM程序,并将其全部设置为同一段,并在64k段的顶部适当设置堆栈。CS=DS=SS全部指向PSP段的开始。@MichaelPetch。啊。。引导加载程序的坏习惯(编码:)@汤米:是的。我有一个处理键盘输入的循环<代码>等待循环:xor ax,ax inc cx cmp cx,2001 je滚动线mov ah,0 int 16h jmp等待循环他在执行时也会犯类似错误。Scrollline还做了一个
ret
代码中的另一个特殊问题是
push ax
调用PrintChar
。我从未见过他在调用完成后清理堆栈和删除参数。@MichaelPetch我完全理解,但我需要一个条件跳转,返回到程序。毕竟,如果我要使用
调用
,我就不能进入条件。我为我的英语感到抱歉。谢谢你的评论和建议corrections@MargaretBloom@MichaelPetch我知道我犯了一个错误。但我不知道如何在条件允许的情况下拨打
电话。我只知道一种方法-
cmp
和j(e、ne、a等)。是的,不使用
call
ret
是不可接受的。我明白了。我只是有点困惑,对吗now@P.Fiona玛格丽特提出了一个可能的解决办法。手动将返回地址推送到堆栈上,执行条件跳转,然后
ret
将返回推送到堆栈上的地址。或者(对于您的思维方式来说可能更简单)是有条件地跳转到一个标签,然后调用预期的函数。