gpt4 book ai didi

assembly - 如何从实模式下写入视频存储地址为0xb8000的屏幕?

转载 作者:行者123 更新时间:2023-12-04 06:34:43 25 4
gpt4 key购买 nike

我创建了简单的代码来从硬盘驱动器加载第二个扇区,然后写入到整个屏幕,并带有红色背景的空格。问题在于,我总是得到@符号而不是空格。这是代码:

org 0x7C00
bits 16

xor ax,ax
mov ds,ax
mov es,ax

mov bx,0x8000
cli
mov ss,bx
mov sp,ax
sti

cld
clc

xor ah,ah
int 0x13
mov bx,0x07E0
mov es,bx
xor bx,bx
mov ah,0x2 ;function
mov al,0x5 ;sectors to read
mov ch,0x0 ;track
mov cl,0x2 ;sector
mov dh,0x0 ;head
int 0x13
;jc error
;mov ah, [0x7E00]
;cmp ah,0x0
;je error
jmp error
cli
hlt
jmp 0x07E0:0x0000

error:
xor bx,bx
mov ax,0xb800
mov es,ax
mov al,0x40 ;colour
mov ah,' ' ;character
.red:
cmp bx,0x0FA0
je .end
mov WORD [es:bx], ax
inc bx
jmp .red
.end:
cli
hlt

times 0x1FE - ($ - $$) db 0x0
db 0x55
db 0xAA

根据此代码屏幕应填充空格,但不能填充空格。

最佳答案

写入视频内存(从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时)。您有包含0x2040的AX,并将带有 mov WORD [es:bx], ax的整个WORD移动到了视频内存。例如,它将把这些字节写入第一个单元格:
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将减少。

关于assembly - 如何从实模式下写入视频存储地址为0xb8000的屏幕?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33681795/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com