写入视频内存时(从 @ 0xb8000开始),屏幕上的每个单元格都有 2 个字节。要显示的字符在第一个字节中,属性在第二个字节中。要将红色(颜色代码 0x40)空格 (0x20) 字符打印到屏幕上的第一个单元格,需要将字节放置在内存中,如下所示:
0xb800:0x0000 : 0x20 ; ASCII char for 0x20 is ' '
0xb800:0x0001 : 0x40 ; Red background, black foreground
在您的代码中,您似乎正在尝试使用以下代码执行此操作:
mov al,0x40 ;colour
mov ah,' ' ;character
.red:
cmp bx,0x0FA0
je .end
mov WORD [es:bx], ax
inc bx
jmp .red
不幸的是,因为 x86 架构是小端序,所以放入内存的值首先是最低有效字节,最后是最高有效字节(在处理 16 位WORD时)。您有AX包含0x2040并将整个WORD移动到mov WORD [es:bx], ax
视频内存。例如,它会将这些字节写入第一个单元格:
0xb800:0x0000 : 0x40 ; ASCII char for 0x40 is `@'
0xb800:0x0001 : 0x20 ; Green background, black foreground
我相信这是绿色@
的,但由于我要提到的第二个错误,它可能看起来是红色的。要解决此问题,您需要反转AX寄存器中字符和属性的位置(交换AH和AL中的值)。代码如下所示:
mov ah,0x40 ;colour is now in AH, not AL
mov al,' ' ;character is now in AL, not AH
.red:
cmp bx,0x0FA0
je .end
mov WORD [es:bx], ax
inc bx
jmp .red
第二个错误与遍历视频区域有关。因为每个单元格占用 2 个字节,您需要在每次迭代时将BX计数器增加 2。您的代码可以:
mov WORD [es:bx], ax
inc bx ; Only increments 1 byte where it should be 2
jmp .red
修改代码以将 2 添加到BX:
mov WORD [es:bx], ax
add bx,2 ; Increment 2 since each cell is char/attribute pair
jmp .red
您可以使用STOSW指令简化代码,该指令将AX中的值复制到ES:[DI]。您可以在该指令前加上REP,它将重复CX次(它将在每次迭代期间相应地更新 DI)。代码可能看起来像这样:
error:
mov ax,0xb800
mov es,ax ;Set video segment to 0xb800
mov ax,0x4020 ;colour + space character(0x20)
mov cx,2000 ;Number of cells to update 80*25=2000
xor di,di ;Video offset starts at 0 (upper left of screen)
rep stosw ;Store AX to CX # of words starting at ES:[DI]
您的代码已经在代码开头使用CLD清除了方向标志,因此REP将在每次迭代期间增加DI 。如果使用STD设置了方向标志,则DI将被递减。