一、实模式下
1、使用图形模式,通常使用12H的600*480,这个模式下也一样可能使用0EH功能,直接输出ASC。
2、从网络上下HZ16的字库(大约262KB),或着GB2312的16点阵字库(大约256KB),UCDOS里含的16*8的ASC字库(大约4KB)
3、使用0C功能写象素,将汉字库写出并根据当前光标计算当前象素行列,使可以与ASC的显示连续。
二、保护模式
4、在进入保护模式后,中断的方式会与实模式的不一样,所以在将进入保护模式时,取得光标位置及当前代码段的32位基址,保存入寄存器中。
5、使用显存直接操作的方式,重写32位下的象素输出功能函数。在刚进入保护模式时也可以使用汉字输出功能,在保护模式下ASC也改成象素输出。否则象素模式下,显存操作无法显示ASC。
6、内存分页等功能打开后,就可以进入内核程序了。内核程序,多在实模式下先加载好。
三、关键代码,部分
- ;Linyee write ,2008-9
- ;mythinker@2911.net
- ;QQ:249033420
- ;NASM源码,32位代码
- ;----------------------------------------------------------------------------------------------
- ;void setColor(dd * color)
- ;;设置颜色
- ;----------------------------------------------------------------------------------------------
- setColor
- push ebp
- mov ebp,esp
- add ebp,8
- sub esp,8
- push eax
- push edx
- mov word [bp-8],ax
- mov dx,0x3ce ;图形控制器
- xor al,al
- mov ah,[ebp+0]
- out dx,ax ;低位设置颜色索引,高位颜色值
- mov ax,0x0f01
- out dx,ax ;打开颜色设置
- ;;设置屏蔽
- mov ah,[bp-8]
- mov al,0x08
- out dx,ax ;打开颜色设置
- pop edx
- pop eax
- add esp,8
- pop ebp
- ret
- ;----------------------------------------------------------------------------------------------
- ;----------------------------------------------------------------------------------------------
- ;void setColor(dd * color)
- ;;设置颜色
- ;----------------------------------------------------------------------------------------------
- clsColor
- push ebp
- mov ebp,esp
- add ebp,8
- push eax
- push edx
- ;;设置屏蔽
- mov ah,0xff
- mov al,0x8
- out dx,ax ;恢复显示所有位
- mov dx,0x3ce ;图形控制器
- mov ax,0xFF01
- out dx,ax ;允许所有颜色
- mov ax,0x0f00 ;恢复为白色
- out dx,ax ;低位设置颜色索引,高位颜色值
- pop edx
- pop eax
- pop ebp
- ret
- ;----------------------------------------------------------------------------------------------
- ;----------------------------------------------------------------------------------------------
- ;void putIntPixDef32(dd *,color,dd *type, dd *esi) ;注意:保证ESI指向CS的基址。CX象素列,DX字节行
- ;type为'ASC'时,输出一字节8位宽度
- ;根据AX输出行点阵 ;注意:本函数保持与ShowBytePix接口数一致
- ;----------------------------------------------------------------------------------------------
- putIntPixDef32
- push ebp
- mov ebp,esp
- add ebp,8
- sub esp,8
- push eax
- push ebx
- push ecx
- push edx
- push edi
- push esi
- mov word [bp-4],ax ;保存AX
- ;mov word [bp-8],dx ;保存dx
- ;mov word [bp-6],cx ;保存cx
- ;call getScrWidth ;取得屏宽
- ;;es:bx为显存位置。
- mov eax,[ebp+0]
- mov esi,eax
- mov eax,edx ;取出行
- mov bx,[esi+_screenWidth]
- mul bx ;计算Y的偏移 ;注意加上CS段
- shr ecx,3 ;象素列转成字符列
- mov edi,eax ;
- add di,cx ;得到总偏移
- mov ax,SelectorVideoPix ;图形模式选择子
- mov gs,ax ;象素段
- mov ax,[bp-4]
- mov bx,[ebp+8]
- cmp bx,0xFFFF
- jz .noColor
- .havColor
- push dword [ebp+8]
- call setColor
- add sp,4
- cmp dword [ebp+4],'ASC' ;ASC方式
- jz .ASC
- mov byte [gs:di],al ;写HZ源点阵
- xchg al,ah
- push dword [ebp+8]
- call setColor
- add sp,4
- mov byte [gs:di+1],al ;写HZ源点阵
- call clsColor
- jmp .out
- .noColor
- cmp dword [ebp+4],'ASC' ;ASC方式
- jz .nocASC
- mov word [gs:di],ax ;写HZ源点阵
- jmp .out
- .nocASC
- mov byte [gs:di],al ;写HZ源点阵
- jmp .out
- .ASC
- mov byte [gs:di],al ;写HZ源点阵
- call clsColor
- .out
- pop esi
- pop edi
- pop edx
- pop ecx
- pop ebx
- pop eax
- add esp,8
- pop ebp
- ret
- ;----------------------------------------------------------------------------------------------
- ;0 black(黑) 0 0 0 0
- ;1 blue(兰) 1 0 0 42
- ;2 green(绿) 2 0 42 0
- ;3 cyan(青) 3 0 42 42
- ;4 red(红) 4 42 0 0
- ;5 magenta(洋红) 5 42 0 42
- ;6 brown(棕) 6 42 42 0
- ;7 lightgray(浅灰) 20 42 42 42
- ;8 darkgray(深灰) 56 0 0 21
- ;9 lightblue(亮兰) 57 0 0 63
- ;10 lightgreen(亮绿) 58 0 42 21
- ;11 lightcyan(亮青) 59 0 42 63
- ;12 lightred(亮红) 60 42 0 21
- ;13 lightmagenta(亮洋红) 61 42 0 63
- ;14 yellow(黄) 62 42 42 21
- ;15 white(白) 63 42 42 63
;Linyee 2011-03补充
记得去年有人问我到底怎么使用这个程式。自己当时没在玩编程一时也想不起。最近又玩起OS又接触到了。
这里给大家透露下汉字显示的思想有二。
一、
;调试未成功
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
; 演示文本方式下显示汉字的汇编源程序
;
; 文件名:myname.asm
;
; 作者: 黄志斌 2001年12月4日于广西河池
;
; 说明: 本程序通过调用BIOS 10h替换系统字模来显示汉字
; 入口: ax=1100h
; bh=字模的高度(有效值:0~20h,默认值:10h)
; bl=被替换的字模集代号(有效值:0~7)
; cx=要替换的字模数
; dx=被替换的第一个字模所对应的字符的ASCII
; es:bp=新字模起始地址
; int 10h
; 要恢复系统字符集,可作如下调用:
; ax=1104h
; bl=字模集代号(有效值:0~7)
; int 10h
;
; 使用方法:
; masm myname;;
; link myname;;
; exe2bin myname.exe myname.com
;
; 注意:本程序未按该字的机内码替换字模,因此不能运行在汉字操作系统下
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
codeseg segment public 'code'
;==============================
org 100h
assume es:codeseg,ss:codeseg
assume cs:codeseg,ds:codeseg,es:codeseg
;-----------------------------
main proc near
mov ax,1100h
mov bh,10h
mov bl,0
mov cx,6
mov dx,200
lea bp,mode
int 10h
mov ah,09h
lea dx,myname
int 21h
mov ah,7
int 21h
mov ax,1104h
mov bl,0
int 10h
mov ax,4c00h
int 21h
;(or int 20h)
main endp
;---------------------
mode db 100B,100B,111111B,100B,100B,11111111B,1B,11111B,10001B,11111B,10001B,11111B,10000B,100B,11000B,1100000B
db 01000000B,01010000B,11111000B,01000000B,01000100B,11111110B,00010000B,11111000B,00010000B,11110000B,00010000B,11110000B,00000000B,01100000B,00011000B,00000100B
db 1B,1B,1B,11111111B,1B,1B,1B,111111B,0B,10B,10001B,1010000B,1010000B,10010000B,1111B,0B
db 00000000B,00000000B,00000100B,11111110B,00000000B,00000000B,00010000B,11111000B,0B,00000000B,10000000B,10000100B,00010010B,00010010B,11110000B,0B
db 0B,100000B,10001B,0B,11111100B,1011B,1001000B,101000B,101001B,10001B,101001B,100101B,1000101B,10000001B,11B,0B
db 10000B,00010000B,11110100B,10010B,00010000B,11111110B,00010000B,01010000B,01010000B,01110000B,01010000B,01001000B,01001000B,01101010B,10000110B,10B
myname db 200,201,202,203,204,205,'$'
;======================
codeseg ends
end main
根据以上代码可以加载一个新字模。此法适用于B000或B800 文本输出。
其中200至205是因dx=200,所以顺着推其它码值。些法只适用于输出少量中文字,至FFH以内。
二、
;编译成DOS-EXE
;看看我的DOS下的汉字显示方法:
InitScreen macro color,StartRow,EndRow
pusha
mov bh,color
mov cx,startRow
mov dx,EndRow
mov ax,0600H
int 10h
popa
endm
set_screen_graphics macro StartRow,StartCol,EndRow,EndCol,Color
local again1,again2
pusha
mov dx,StartRow
again1:
mov cx,StartCol
again2:
mov ah,0ch
mov al,Color
mov bh,0
int 10H
inc cx
cmp cx,EndCol
jnz again2
inc dx
cmp dx,EndRow
jnz again1
popa
endm
.MODEL small
.data
font_table label word
; 吴 offset:0x000218e0 GB:0xcee2 QW:4666
DB 016,000,248,031,016,016,016,016,240,031,000,000,016,000,248,063,000,001,004,001,254,255,128,002,064,002,032,004,028,024,008,096
; 荣 offset:0x0001d140 GB:0xc8d9 QW:4057
DB 064,004,068,004,254,255,064,004,000,000,254,127,002,065,004,129,000,001,252,127,128,003,064,005,032,009,028,017,008,097,000,001
; 华 offset:0x000132a0 GB:0xbbaa QW:2710
DB 064,004,072,004,088,008,096,008,192,024,064,041,068,074,068,008,060,009,000,001,254,255,000,001,000,001,000,001,000,001,000,001
; 置
;DW 07ff0h,04890h,07ff0h,00200h,0fff8h,00200h,03fe0h,02020h,03fe0h,02020h,03fe0h,02020h,03fe0h,02028h,0fffch,00000h
StartRow dw 100
StartCol dw 100
loopFlagCol db 0
.code
.586
.startup
mov ah,0
mov al,12H
int 10H
mov ax,0001H ;show mouse pointer
int 33H
mov cl,1
Back_again:
mov al,cl
;set_screen_graphics 50,100,330,540,al
; inc cl
; cmp cl,10H
; jnz back_Again
call show_ch_font
mov ah,0
int 16H
mov ax,0003H
int 10H
.exit
show_ch_font proc
pusha
xor si,si
mov dx,StartRow
next_Row:
mov cx,StartCol
next_col:
push cx
mov ax,8000H
mov cl,loopFlagCol
shr ax,cl
pop cx
and ax, [font_table+si]
inc loopFlagCol
cmp loopFlagCol,17
jnz @F
mov loopFlagCol,0
add si,2
cmp si,32
jz show_font_end
inc dx
jmp next_Row
@@: inc cx
call int10_0C
jmp next_col
show_font_end:
popa
ret
show_ch_font endp
int10_0C proc
pusha
test ax,ax
jnz @F
mov al,02H ;color
jmp short start_output
@@:
mov al,05H ;color
start_output:
mov ah,0ch
mov bh,0
int 10H
popa
ret
int10_0C endp
end
以上这种方法适用于向A000显存段输出。
1、先要加载字库。汉字库(一般是32字节/汉字)ASC库(一般16字节/每ASC),也有8*8的8字节字模。
2、再根据汉字编码查找到字库中相应的字模。ASC也同理。
3、根据这个字的起址,进行多次重复输出点阵就实现了汉字的输出。
注意象素模式下,ASC也必须是有字库的,这种方式适用于很多汉字的输出。而且在象素模式下还可以加载图片等等。
另外显卡带的显存空间也可以利用起来。这样WriteOS时就实现了windows模式。
最初的代码正是第二方式的部分代码。其实关键代码都已经在了,只缺了编程思想有得头晕。
现举例执行过程
1)
;加载汉字支持
printS 'runing loader ...',0
call openHZ16GB2312
call loadASC16
printS '~~LinyeeOS loading kernel ,Please wait ... ',13,10,0
printS '~~LinyeeOS 正在测试加载内核,请稍候……',13,10,0
;加载内核
2)
;----------------------------------------------------------------------------------------------
;printS: 1+ ;后面跟字符串
;显示输出信息
;----------------------------------------------------------------------------------------------
%macro printS 1+
push si
jmp %%endstr
%%str: db %1,0 ;增加结束符
%%endstr:
mov si,%%str
call ShowMsg
pop si
%endmacro
;----------------------------------------------------------------------------------------------
3)
- ;----------------------------------------------------------------------------------------------
- ;printS: 1+ ;后面跟字符串
- ;显示输出信息
- ;----------------------------------------------------------------------------------------------
- ;重载支持中文显示
- %macro printS 1+
- push si
- jmp %%endstr
- %%str: db %1,0 ;增加结束符
- %%endstr:
- mov si,%%str
- push word BaseLoadGB2312
- push word BaseOfGBFile
- call ShowMsgAuto
- add sp,4
- pop si
- %endmacro
- ;----------------------------------------------------------------------------------------------
4)检测汉字库是否已加载并启用相关函数
- ;----------------------------------------------------------------------------------------------
- ;void ShowMsgAuto(int *ds,int *si) ;指向GB2312点阵库
- ;显示字符;指向GB2312点阵库
- ;----------------------------------------------------------------------------------------------
- ShowMsgAuto
- push ax
- push ds
- push si
- mov bp,sp
- add bp,2+6
- cmp word [HzGB2312LoadOk],200H
- jnz .noload
- push word [bp+2]
- push word [bp+0]
- call ShowHzASC
- add sp,4
- jmp .out
- .noload
- call ShowMsg
- .out
- pop si
- pop ds
- pop ax
- ret
- ;----------------------------------------------------------------------------------------------
5)判断调用输出ASC或ShowFont16
完成。打印一个汉字是需要花费很多功夫的,只要你不觉得输出个汉字都这么多代码。自己多看看一法二法的思想就懂得怎么去找怎么去组织了。
当然或许我的方法比较土,弄个汉字显示写了80KB+的代码。如果你有更犀利的代码,欢迎发到mythinker@2911.net,共资以历。
目前WriteOS卡在内核里。内核之前的东东已基本OK,方方面面都涉及到了一些。欢迎同好一起玩研DiyOS。
- ;Linyee write ,2008-9
- ;mythinker@2911.net
- ;QQ:249033420
- ;NASM源码,16位下的代码。
- ;----------------------------------------------------------------------------------------------
- ;void ShowFont16(int *ds,int *si) ;输出点 ;dx行;cx列;
- ;输出汉字单字点阵 ;dx行;cx列;
- ;----------------------------------------------------------------------------------------------
- ShowFont16
- push ax
- push bx
- push bp
- push ds
- push si
- mov bp,sp
- add bp,2+10
- sub sp,8
- call getCurPix ;取坐标
- mov word [bp-6],cx ;列坐标
- mov word [bp-4],dx ;行坐标
- mov bx,[bp+0]
- mov si,bx
- mov bx,[bp+2]
- mov ds,bx ;指向点阵库内指定字
- mov bx,16
- .sl_nextLine:
- cmp bx,0
- jz .sl_return
- lodsw
- call putIntPixDef
- ;lodsb ;本注释段为中断输出字符
- ;call ShowBytePix
- ;mov ah,al
- ;lodsb
- ;call ShowBytePix
- ;mov cx,[bp-6]
- inc dx
- dec bx
- jmp .sl_nextLine ;下一行
- .sl_return:
- call setCurMoveNext ;光标下移
- add cx,16 ;下移一个字宽
- mov dx,[bp-4] ;恢复到本行
- .out
- add sp,8
- pop si
- pop ds
- pop bp
- pop bx
- pop ax
- ret
- ;----------------------------------------------------------------------------------------------
- ;----------------------------------------------------------------------------------------------
- ShowBytePix ;输出点 ;dx行;cx列;汉字库多从低字节高位开始打印
- ;----------------------------------------------------------------------------------------------
- push ax
- push bx
- push bp
- mov bp,sp
- sub sp,2
- mov word [bp-2],ax
- mov bx,8
- .test
- cmp bx,0
- jz .out
- mov al,[bp-2]
- mov ah,0
- shl al,1
- mov word [bp-2],ax
- jnc .point
- mov al,0FH ;为白
- jmp .point2
- .point
- mov al,00H ;为黑
- .point2
- mov ah,0cH
- int 10H
- dec bx
- inc cx
- jmp .test
- .out
- ;call cls0CH
- add sp,2
- pop bp
- pop bx
- pop ax
- ret
- ;----------------------------------------------------------------------------------------------
-