我正在尝试编写一些ASM代码,它会使用BIOS中断将一些文本写入显示器。此代码将从引导扇区运行。
我有
msgText DB "Hello" ;Text
msgCol DB 0x07,0x08,0x09,0x0A,0x0B ;Colours
msgXY DW 0x0E26 ;Col/Row
msgLen DB 0x05 ;Length
消息只是“你好”,每个字母都有不同的颜色。消息在屏幕上的位置大致位于中间,长度为5。
我想编写一个函数,将任何消息/颜色/ xy / length写入屏幕,但是现在,让我们专注于这个。
print:
MOV AH,0x02 ;Tell BIOS we want to set the cursor position
MOV DX,[msgXY] ;Tell BIOS where the cursor should go
INT 0x10 ;Call BIOS video interrupt
XOR ECX,ECX ;Clear ECX
MOV CX,[msgLen] ;Set CX = msgLen
MOV AH,0x0E ;We want to print characters on the screen
_loop:
MOV EDX,msgText ;Move address of text to EDX
DEC ECX ;Temporarily decrement ECX
ADD EDX,ECX ;Add ECX to the address of msgText
INC ECX ;Increment ECX back to what it was
MOV AL,BYTE[EDX] ;Put the contents of the memory at EDX into AL
MOV EDX,msgCol ;Move address of text colour to EDX
DEC ECX ;Temporarily decrement ECX
ADD EDX,ECX ;Add ECX to the address of msgCol
INC ECX ;Increment ECX back to what it was
MOV BL,BYTE[EDX] ;Put the contents of the memory at EDX into BL
INT 0x10 ;Call BIOS video interrupt
LOOP _loop
RET
现在,我应该可以使用CALL print
来调用它。
(是的,我知道这会向后打印“Hello”,我并不担心。我可以将它作为“olleH”存储在内存中,我不在乎 - 我有更大的问题)< / p>
首先,我将CX
设置为[msgLen]
的行会导致问题。我必须对其进行硬编码才能使CX
等于0x05
而且我不确定原因。
其次,大概是出于同样的原因,当我尝试设置颜色代码时,我遇到与文本长度相同的问题。如果我摆脱这些行并只是硬编码MOV BL,0x0C
,那么它可以正常工作。
然而奇怪的是,MOV DX,[msgXY]
部分似乎工作正常。
我不能给出任何确切的问题,因为我一直试图通过改变很多东西来解决这个问题,而且我在这里改变的一些小事情似乎都有非常不可预测的结果。此外,调用各种BIOS中断似乎更改一些寄存器,这非常烦人。此外,当我将东西推到堆栈上并稍后将其弹回时,它会有所不同,所以我一直在完全避免使用PUSH
和POP
。
顺便说一句,在这个阶段我仍然处于真实模式x86。
当然,我正在做的事情不是那么难。也许我只需要一杯咖啡。还是一些帮助? :)
答案 0 :(得分:2)
嗯,“首先”,您已将msgLen
定义为db
。当您mov cx, [msgLen]
时,加载两个字节。这是否会导致问题取决于msgLen
之后的内容(如果有的话)。将msgLen
定义为dw
,或执行mov cl, [msgLen]
(因为您已清除高位)。
我没有看到“Second”的类似问题 - 你正在将一个字节移动到一个8位寄存器中。在本节中使用32位寄存器似乎很奇怪。 “应该”有效,但它会使你的代码膨胀一些。 [dx]
当然不是有效的16位寻址模式 - 您必须使用bx
(用于其他目的),si
或{{1} }。由于您使用的是32位寄存器,di
应该可以执行您想要的操作而不会临时递减和递增lea edx, [edx + ecx - 1]
。 (但我认为这不会对你的问题有所帮助)
预计某些BIOS中断会改变寄存器。它是否奇怪取决于中断正在做什么。大多数情况下他们没有。 ecx
pop
无法使用push
相同的值是很奇怪的。要么你发现了一个CPU错误,要么你做错了什么。猜猜哪个更有可能。 :)它们是有用的指令,所以不能使用它们是一种耻辱。你没有显示你的bootsector的“act I”,你初始化ds
和es
并建立一个合理的堆栈 - 也许那里有问题?
你看过10h / 13h吗?我认为它会做你想要的(“彩虹”文字)。这是一个奇怪的中断,因为它希望文本地址在es:bp
,但很有用。另一种方法是将字符和颜色直接戳到B800h的“屏幕内存”:xxxx - 字符一个字节,颜色一个字节。
bootsector不是特别容易编写。如果你有真正的dos可用(甚至Dosbox),它可能有助于“试用”你的例程作为.com文件的一部分(DEBUG可用)。 bootsector是一个与dos不同的环境,因此它无法解决您的所有问题,但可能有助于缩小范围。
咖啡可能会有所帮助,但主要是......勇气!
最佳, 弗兰克
答案 1 :(得分:0)
您可以使用此代码:
mov si,msg_text
call print_colored
print_colored:
.loop:
lodsb
cmp al,0
je .done
inc bl
mov ah,0x0E
Int 0x10
jmp .loop
.done:
ret
它使您的字符串着色,但不适合您的选择。