如何从实模式写入显存地址为 0xb8000 的屏幕? [英] How to write to screen with video memory address 0xb8000 from real mode?

查看:47
本文介绍了如何从实模式写入显存地址为 0xb8000 的屏幕?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created simple code to load second sector from hard drive, and then write to whole screen, with spaces with red background. The problem is that always instead of spaces I got @ signs. This is the code:

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

根据这个代码屏幕应该用空格填充,但它不是.

according to this code screen should be filled with spaces but it is not.

推荐答案

当写入视频内存(从@0xb8000 开始)时,屏幕上的每个单元格都有 2 个字节.要显示的字符在第一个字节中,属性在第二个字节中.要将红色(颜色代码 0x40)空格(0x20)字符打印到屏幕上的第一个单元格,需要将字节放入内存中,如下所示:

When writing to video memory (starting @ 0xb8000) there are 2 bytes for every cell on the screen. The character to display is in the first byte, and the attribute in the second. To print out a red (color code 0x40) space (0x20) character to the first cell on the screen the bytes need to be placed in memory like this:

0xb800:0x0000 :  0x20         ; ASCII char for 0x20 is ' '
0xb800:0x0001 :  0x40         ; Red background, black foreground

在您的代码中,您似乎正在尝试使用以下代码执行此操作:

In your code it seems you were trying to do this with code like:

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 时).您有包含 0x2040AX 并将带有 mov WORD [es:bx], ax 的整个 WORD 移动到视频记忆.例如,它会将这些字节写入第一个单元格:

Unfortunately because x86 architecture is little-endian, the values that get placed into memory have the least significant byte first and most significant byte last (when dealing with a 16-bit WORD). You have AX containing 0x2040 and moved the entire WORD with mov WORD [es:bx], ax to video memory. For example it would have written these bytes to the first cell:

0xb800:0x0000 :  0x40         ; ASCII char for 0x40 is `@'
0xb800:0x0001 :  0x20         ; Green background, black foreground

我相信这是一个绿色的 @ 但由于第二个错误,我会提到它可能看起来是红色的.要解决此问题,您需要反转 AX 寄存器中字符和属性的位置(交换 AHAL 中的值).代码如下所示:

I believe this is a green @ but because of the second bug I will mention it may have appeared red. To fix this you need to reverse the position of the character and attribute in the AX register (swap the values in AH and AL). The code would look like this:

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.您的代码可以:

The second bug is related to traversing the video area. Because each cell takes 2 bytes you need to increment the BX counter by 2 on each iteration. Your code does:

mov WORD [es:bx], ax
inc bx                 ; Only increments 1 byte where it should be 2 
jmp .red

修改代码,将BX加2:

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).代码可能如下所示:

You could have simplified the code by using the STOSW instruction that takes the value in AX and copies it to ES:[DI]. You can prefix this instruction with REP which will repeat it CX times (it will update DI accordingly during each iteration). The code could have looked like this:

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 就会递减.

Your code already clears the direction flag with CLD at the beginning of your code, so REP will increase DI during each iteration. Had the direction flag been set with STD, DI would have been decremented.

这篇关于如何从实模式写入显存地址为 0xb8000 的屏幕?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆