X86架构(三)——汇编语言与显卡控制

书接上文,本章将基于采用汇编语言,编写一段在ROM-BIOS中的程序,帮助理解X86汇编语言与显卡控制原理。

显卡和显存

无论是独显还是集显,控制显示器的最小单位是像素,一个像素对应屏幕上的一个点,通过控制这些像素,可以形成文字和美丽的图像。显卡控制像素的方式是通过自身的存储器——Video RAM(VRAM),也就是显存,要显示的内容都预先写入显存。
NOTE: 显存是按字节访问的

工作模式

文本模式图形模式是显卡的两种基本工作模式,可以用指令访问显卡,设置它的显示模式。在不同的工作模式下,显卡对显存内容的解释是不同的。本文仅讨论文本模式,图形模式大概就是多个字节或比特去控制一个像素的属性,从而构成多彩的图形吧,咱也不知道瞎猜吧😅。
在文本模式下,显卡从显存中依次提取字符的ASCII码交给字符发生器和控制电路,从而控制显示器进行显示。
字符在屏幕上的显示原理
所以要显示字符,处理器需要访问显存,把字符的ASCII 码写入显存。为加快显存的读写速率,芯片的设计者们将显存映射到内存空间中,如下图展示的8086的显存映射。可见0xB8000~0xBFFFF这段物理地址空间,由显卡来提供,用来显示文本。
显存映射

汇编指令

  • ; —— 注释
  • mov —— 数据传送指令
    mov dst, src
    dst - 目的操作数
    src - 源操作数
    目的操作数是通用寄存器或者内存单元;源操作数是和目的操作数具有相同位宽的通用寄存器、内存单元、立即数。
mov ah, bh     ;将bh寄存器中的内容复制到ah中
mov ax, dx     ;将dx寄存器中的内容复制到ax中

;以下两条指令通过寄存器限制了位宽
mov [0x02], bh ;将bh寄存器中的内容复制到偏移地址为0x028位内存单元中
mov ax, [0x06] ;将偏移地址为0x0616位内存单元里的内容复制到ax寄存器中

; 偏移地址0x00,可以是字节单元或字单元,无法判断
; 0x4c即解释为8位的0x4c,也可解释为16位的0x004c
; 在这种情况下,编译器将报错,所以必须用“byte”或者“word”进行修饰
mov byte [0x00], 0x4c
mov word [0x00], 0x4c
; 目的操作数和源操作数不允许同时为内存单元
  • jmp —— 转移指令
    用于使处理器脱离当前的执行序列,转移到指定的地方执行
    jmp [option] addr
    option - 可选项
    addr - 目标地址
jmp 0x5000:0xf0c0 ;转移到段地址为0x5000,偏移地址为0xf0c0的地址执行
jmp near 0x001E ;关键字`near`表示目标位置在当前代码段内,无需指定段地址
  • xor —— 异或指令
    xor dst, src
    dst - 通用寄存器和内存单元
    src - 通用寄存器、内存单元和立即数
mov ax, 0x0002
xor ax, 0xf0f1 ; 结果保存在ax中,此时ax = 0xf0f3
  • add —— 加法指令
    add dst, src
    dst - 目的操作数:8 位或者16 位的通用寄存器;指向8 位或者16 位实际操作数的内存地址
    src - 源操作数:与目的操作数相同数据宽度的8 位或者16 位通用寄存器;指向8 位或者16 位实际操作数的内存地址;立即数
add ax, 0x0002 ; 寄存器AX的内容和立即数0x0002想加,结果在AX中
add ax, bx
add [lable_a], cx ; 内存单元的值和寄存器cx的值想加,结果写会内存
  • div —— 除法指令
    8086处理器可以做两种类型的除法
    1、用16 位的二进制数除以8 位的二进制数
    在这种情况下,被除数必须在寄存器AX 中,必须事先传送到AX 寄存器里。除数可以由8 位的通用寄存器或者内存单元提供。指令执行后,商在寄存器AL 中,余数在寄存器AH中
mov ax, 0x0005
mov cl, 0x02
div cl ; AL 中的商是0x02AH 中的余数是0x01

2、用32 位的二进制数除以16 位的二进制数
在这种情况下,因为16 位的处理器无法直接提供32 位的被除数,故要求被除数的高16 位在DX 中,低16 位在AX 中。除数可以由16 位的通用寄存器或者内存单元提供,指令执行后,**商在AX 中,余数在DX **中。

mov ax, 0x0005
mov dx, 0x0002 ;DX:AX = 0x00020005
mov cx, 0x2000 ;AX 中的商是0x0010DX 中的余数是0x0005
  • 段超越前缀
    一般情况下,如果没有附加任何指示,段地址默认在段寄存器DS中,如果我们希望使用段寄存器ES来访问内存,需要使用段超越前缀es:
mov ax [es:0x01] ;ES寄存器中的值+0x01为地址的内存单元
  • DB、DW、DD、DQ —— 伪指令
    DB(Declare Byte)用于声明字节数据
    DW(Declare Word)用于声明字数据
    DD(Declare Double Word)用于声明双字数据
    DQ(Declare Quad Word)用于声明四字数据。
DB 0x55 ; 声明一个值为0x55的数据,占位一个字节

NOTE
虽然我们定义一个字节数据,但是我们并不知道这个数据的内存地址,也就无法访问它!!!这个时候,我们可以 借助标号来代表数据的起始地址。

  • 标号 —— 代表并指示指令所在的汇编地址
    在NASM 汇编语言里,每条指令的前面都可以拥有一个标号,以代表和指示该指令的汇编地址。标号并不是必需的,只有在我们需要引用某条指令的汇编地址时,才使用标号。
data_1:
    DB 0x55 ; 标号data_1指向DB定义的数据的起始地址

显示例程

屏幕上的每个字符对应着显存中的两个连续字节,前一个是字符的ASCII 代码,后面是字符的显示属性,包括字符颜色(前景色)和底色(背景色)。如下图所示,字符“H”的ASCII 代码是0x48,其显示属性是0x07;字符“e”的ASCII 代码是0x65,其显示属性是0x07。
字符代码与字符属性
字符的显示属性的编码如下图所示
文本模式颜色表

         ;代码清单5-1 
         ;文件名:c05_mbr.asm
         ;文件说明:硬盘主引导扇区代码
         ;创建日期:2011-3-31 21:15
         ;主引导扇区代码,ROM-BOIS将这段代码加载到0x0000:0x7c00执行
         ;此时段地址为0x0000,CS寄存器=0x0000
         
         mov ax,0xb800           ;初始化ES段寄存器,0xb800为显存段起始地址
         mov es,ax
 
         ; 以下显示字符串"Label offset:"
         ; 屏幕上的每个字符对应着显存中的两个连续字节,前一个是字符的ASCII; 后面是字符的显示属性,包括字符颜色(前景色)和底色(背景色)
         mov byte [es:0x00],'L'
         mov byte [es:0x01],0x07
         mov byte [es:0x02],'a'
         mov byte [es:0x03],0x07
         mov byte [es:0x04],'b'
         mov byte [es:0x05],0x07
         mov byte [es:0x06],'e'
         mov byte [es:0x07],0x07
         mov byte [es:0x08],'l'
         mov byte [es:0x09],0x07
         mov byte [es:0x0a],' '
         mov byte [es:0x0b],0x07
         mov byte [es:0x0c],"o"
         mov byte [es:0x0d],0x07
         mov byte [es:0x0e],'f'
         mov byte [es:0x0f],0x07
         mov byte [es:0x10],'f'
         mov byte [es:0x11],0x07
         mov byte [es:0x12],'s'
         mov byte [es:0x13],0x07
         mov byte [es:0x14],'e'
         mov byte [es:0x15],0x07
         mov byte [es:0x16],'t'
         mov byte [es:0x17],0x07
         mov byte [es:0x18],':'
         mov byte [es:0x19],0x07
 
         mov ax,number   ;取得标号number的偏移地址(0x012E),并将其传送到ax中
         mov bx,10       ;初始化除数
 
         ;设置数据段的基地址
         mov cx,cs 		 ;CS代码段寄存器,CS = 0x0000
         mov ds,cx 		 ;DS数据段寄存器,数据和代码公用一个段,数据放置最后
 
         ;求个位上的数字
         mov dx,0  		 ;使用32位被除数的方式,dx高位清零,低16位在ax中
         div bx          ;bx = 10
         ; 进行div运算后,余数在dx中,余数小于10,使用dl即可访问
         ; number是段内偏移地址,被加载到0x0000:0x7c00处后,
         ; 实际的段偏移地址应该加载0x7c00,因为DS=0x0000
         mov [0x7c00+number+0x00],dl ;保存个位上的数字
 
         ;求十位上的数字
         xor dx,dx                   ;使用异或运算清零dx,商保留在ax中无需处理
         div bx
         mov [0x7c00+number+0x01],dl ;保存十位上的数字
 
         ;求百位上的数字
         xor dx,dx
         div bx
         mov [0x7c00+number+0x02],dl   ;保存百位上的数字
 
         ;求千位上的数字
         xor dx,dx
         div bx
         mov [0x7c00+number+0x03],dl   ;保存千位上的数字
 
         ;求万位上的数字 
         xor dx,dx
         div bx
         mov [0x7c00+number+0x04],dl   ;保存万位上的数字
 
         ;以下用十进制显示标号的偏移地址
         mov al,[0x7c00+number+0x04]
         add al,0x30      ; ASCII转换
         mov [es:0x1a],al ; 数据传送到显存
         mov byte [es:0x1b],0x04 ;显示属性
         
         mov al,[0x7c00+number+0x03]
         add al,0x30
         mov [es:0x1c],al
         mov byte [es:0x1d],0x04
         
         mov al,[0x7c00+number+0x02]
         add al,0x30
         mov [es:0x1e],al
         mov byte [es:0x1f],0x04
 
         mov al,[0x7c00+number+0x01]
         add al,0x30
         mov [es:0x20],al
         mov byte [es:0x21],0x04
 
         mov al,[0x7c00+number+0x00]
         add al,0x30
         mov [es:0x22],al
         mov byte [es:0x23],0x04
         
         mov byte [es:0x24],'D'
         mov byte [es:0x25],0x07
          
   infi: jmp near infi                 ;无限循环,自己跳自己
      
  number db 0,0,0,0,0
  
  times 203 db 0         ;伪指令times 可用于重复它后面的指令若干次
            db 0x55,0xaa ; 主引导扇区有效标志 0x550xAA

最后,因为时间关系,本章就写下这些内容了,后面将完善更多的汇编指令或另立章节阐述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值