为什么显卡在内存中的映射是0b8000H

作者:北极
链接:https://www.zhihu.com/question/269649445/answer/351632444
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

显存基地址虽然是人为确定的,但真要追究原因的话,还是可以找到一些原因的。
首先,16位时代8086的寻址范围是0000:0000~FFFF:000F,最早划给RAM的区域是640KB,范围0000:0000~9FFF:000F,这在第一代IBM x86 PC时代基本就定下来了。剩下的区域要划给BIOS和硬件使用。当时的设计思路是,BIOS的东西尽量往后放,所以BIOS的ROM代码被放到了F000段这里。
然后就是决定显存放在哪的问题。
可以使用的区域包括A000:0000,B000:0000,C000:0000,D000:0000,E000:0000这几大段内存。
先说看A000段:这段内存有一个问题,就是A000段会跟9FFF段有重叠,也就是9FFF:0010~9FFF:FFFF, 可能是为了防止有内存重叠,设计的时候把显存往后挪一段,也就是B000这一段。
早期的显存基地址是B0000而不是B8000,早在1981年最早的IBM PC机出来的时候,显示器还是单色的,显存只有4KB(80*50),占用的内存范围是B0000~B0FFF。
这里需要特别提一句,显卡上是有RAM也有ROM的,RAM映射到了B000段上,ROM映射到C000段(实际范围是C0000~C7FFF),当时因为外设还不多(硬盘都属于罕见的设备),所以内存地址空间可以说是随便用,虽然显卡RAM只有4K,ROM只有8K,但各自占用了很大一段的地址空间。
到了1983年,显卡技术进一步发展,显示器可以显示彩色字符了,但考虑到兼容性的问题,需要兼容原来的单色显卡,而C000段已经被用掉了,B000段还有很多剩余空间,于是B000段被拆成了两部分,B000~B7FF段兼容单色显卡显存,B800~BFFF段留给彩色字符显存。
因为现在显卡已经默认工作在彩色字符模式下了,所以B800就成了默认的显存基地址了,实际上早期的基地址是B000而不是B800。事实上现在的很多显卡仍然能通过配置切换到单色模式,切换过去以后,显存的基地址就是B0000了。
再后来,显卡发展出VGA模式,显卡的显存也增长到了256KB,而这个时候因为BIOS的东西太多,硬件数量也变多了,已经把D000, E000都占了,此时可用的地址空间只剩下A000,所以A000就用来做VGA的图形模式的显存了。
至此,A0000以后的地址空间就基本确定下来了:
A0000~AFFFF: VGA图形模式显存空间
B0000~B7FFF: MDA单色字符模式显存空间
B8000~BFFFF: CGA彩色字符模式显存空间
C0000~C7FFF: 显卡ROM空间(后来被改造成多种用途,也可以映射显存)
C8000~FFFFE: 留给BIOS以及其它硬件使用(比如硬盘ROM之类的)。
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用汇编语言实现在屏幕间分别显示绿色、绿底红色、白底蓝色的字符串‘welcome to masm’,并向`B8000H~BFFFFH`写入数据的代码: ``` assume cs:code data segment msg1 db 'welcome to masm', 0ah, 0dh, '$' msg2 db 'welcome to masm', 0ah, 0dh, '$' msg3 db 'welcome to masm', 0ah, 0dh, '$' data ends code segment start: mov ax, data mov ds, ax ; 获取屏幕宽度和高度 mov ah, 0fh int 10h mov bh, 0 mov bl, 7 mov cx, 80 div cx mov cx, ax mov dx, bx ; 计算字符串的长度 mov si, offset msg1 mov di, offset msg2 mov bp, offset msg3 mov al, 0 mov cx, 0 mov dl, byte ptr [si] cmp dl, '$' je calc_end calc_loop: inc si inc cx mov dl, byte ptr [si] cmp dl, '$' jne calc_loop calc_end: mov al, 0 mov dl, byte ptr [di] cmp dl, '$' je calc2_end calc2_loop: inc di add al, 2 mov dl, byte ptr [di] cmp dl, '$' jne calc2_loop calc2_end: mov al, 0 mov dl, byte ptr [bp] cmp dl, '$' je calc3_end calc3_loop: inc bp add al, 2 mov dl, byte ptr [bp] cmp dl, '$' jne calc3_loop calc3_end: ; 显示绿色字符串 mov ah, 0ah mov al, 7 mov bh, 0 mov cx, dx sub cx, byte ptr [si] shr cx, 1 mov dx, byte ptr [si] mov bp, sp add bp, 2 mov byte ptr [bp], dl inc bp mov byte ptr [bp], al inc bp mov si, offset msg1 mov ah, 0 rep movsb ; 显示绿底红色字符串 mov ah, 0ah mov al, 4 mov bh, 0 mov cx, dx sub cx, byte ptr [di] shr cx, 1 mov dx, byte ptr [di] mov bp, sp add bp, 2 mov byte ptr [bp], dl inc bp mov byte ptr [bp], al inc bp mov si, offset msg2 mov ah, 0 rep movsb ; 显示白底蓝色字符串 mov ah, 0ah mov al, 1 mov bh, 0 mov cx, dx sub cx, byte ptr [bp] shr cx, 1 mov dx, byte ptr [bp] mov bp, sp add bp, 2 mov byte ptr [bp], dl inc bp mov byte ptr [bp], al inc bp mov si, offset msg3 mov ah, 0 rep movsb ; 向B8000H~BFFFFH写入数据 mov bx, 0b800h mov es, bx xor bx, bx lea si, [msg1] mov cx, dx mov dl, byte ptr [si] cmp dl, '$' je write_end write_loop: inc si mov al, byte ptr [si] mov ah, byte ptr [si+1] shl ah, 4 or al, ah mov es:[bx], ax add bx, 2 mov dl, byte ptr [si] cmp dl, '$' jne write_loop write_end: ; 退出程序 mov ah, 4ch int 21h code ends end start ``` 解释一下代码: 首先,我们使用`assume cs:code`语句来声明代码段的名称为`code`。 然后,在`data segment`,我们定义了三个字符串`msg1`、`msg2`和`msg3`,分别用于显示绿色、绿底红色和白底蓝色的字符串。每个字符串后面都加上了换行和回车符号,并以`$`作为结束符号。 接着,在`code segment`,我们定义了一个`start`标签,表示程序的入口点。 然后,我们使用`mov ax, data`和`mov ds, ax`语句将数据段的地址加载到`DS`寄存器,以便我们可以访问定义的字符串。 接下来,我们使用`int 10h`断调用来获取屏幕的宽度和高度,并保存在`CX`和`DX`寄存器。然后,我们计算出每个字符串在屏幕上的起始位置和长度。 然后,我们分别使用`mov ah, 0ah`和`int 10h`断调用来显示三个字符串。其,`mov al, 7`、`mov al, 4`和`mov al, 1`分别表示要显示的字符串的颜色。 接下来,我们使用`mov bx, 0b800h`和`mov es, bx`语句将`ES`寄存器加载到显存地址`0b800h`,以便我们可以向显存写入数据。然后,我们使用`rep movsb`指令向显存写入数据,从而在屏幕上显示字符串。 最后,我们使用`mov ah, 4ch`和`int 21h`来退出程序。 注意:上面的代码是在`DOS`环境下编写和运行的。如果你使用的是`Windows`或其他操作系统,需要使用相应的系统调用来向显存写入数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值