首先了解内存排布
在屏幕打印启动信息
;Realize the UI
;Carry ui data from presupposed place to the place where Graphics peripherals was mapped at
jmp near start
ui_string: db 'L',0x07, \
'u',0x07, \
'y',0x07, \
'u',0x07, \
'a',0x07, \
'n',0x07, \
'O',0x07, \
'S',0x07
number:db 0,0,0,0,0
start:
;往显卡外设映射的逻辑地址上写值
mov ax,0x07c0 ;数据段使用0x7c0作为基址 而不是0x0000 否则每次寻址到数据都要加上偏移[0x7c0+number+0x00]这种形式
mov ds,ax
mov ax,0xb800 ;显卡被映射在逻辑地址0xb8000的地方
mov es,ax ;默认数据段应该是DS 但是DS有其他用处 使用ES附加段
cld ;clear direction 重置方向 FLAGS中的DF(Direction Flag)=0 表示传送为正方向 为数据搬运做准备
mov si,ui_string ;DS:SI组成源地址 0x07c0:ui_string ui_string在编译时变为汇编地址(立即数)
mov di,0 ;ES:DI组成目的地址 0xb800:0x0000 显卡外设所映射的地址
mov cx,(number-ui_string)/2 ;根据数据在内存中被排布的方式计算ui_string 计算ui_string中一共有多少组元素 一组元素占据一个word大小. 搬运次数存放在CX寄存器中 (count)
rep movsw ;movsw只会搬运一次 一次一个word 使用rep可以重复搬运 直到CX寄存器值清零
;为下面循环除法做准备
mov dx,0
mov ax,number ;要开始做32位除法 准备被除数
mov bx,ax ;number要作为暂存各个位上的值的空间
mov cx,5 ;循环次数
mov si,10 ;除数
;取数据 保存在number地址开始的5个btye上
getx:
xor dx,dx
div si
mov [bx],dl ;保存取出的数据
inc bx
loop getx
;每个位上的数据都取到后 需要在屏幕上显示
mov bx,number ;暂存数据的起始地址
mov si,4 ;显示五个数据就可以
;循环取出显示
show:
mov al,[bx+si] ;从第四个数据开始显示 后取出来的数据是高位 放在暂存区的后部 BX+0 ~ BX+4
add al,0x30 ;从数据向ASCII转换
mov ah,0x04 ;显示属性 黑底红字
mov [es:di],ax ;搬运
add di,2 ;显存上的指针+2 跳过一组数据(ASCII和属性值)
dec si ;暂存区的指针往前移动 拿到低位上的数据
jns show ;循环 si!=0执行
mov word [es:di],0x0744 ;07属性 白底黑字 44 'D'
jmp near $ ;$ 表示本行的汇编地址
times 510-($ - $$) db 0 ;510 整个显卡一个扇区是512字节 标志0X55 0XAA占据了俩字节 $$ 表示本段其实汇编地址 没分段的话就是0
db 0x55,0xaa ;向没有使用到的内存上填充0 最后追加标记0X55 0XAA