有关汉字系统的关键技术/纯汇编显示中文/汉字显示/Nasm源码

一、实模式下

    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、内存分页等功能打开后,就可以进入内核程序了。内核程序,多在实模式下先加载好。

三、关键代码,部分

  1. ;Linyee write ,2008-9
  2. ;mythinker@2911.net
  3. ;QQ:249033420
  4. ;NASM源码,32位代码
  5. ;----------------------------------------------------------------------------------------------
  6. ;void setColor(dd * color)
  7. ;;设置颜色  
  8. ;----------------------------------------------------------------------------------------------
  9. setColor
  10.     push    ebp
  11.     mov ebp,esp
  12.     add ebp,8
  13.     sub esp,8
  14.     push    eax
  15.     push    edx
  16.     
  17.     mov word [bp-8],ax
  18.     
  19.     mov dx,0x3ce        ;图形控制器
  20.     xor al,al
  21.     mov ah,[ebp+0]
  22.     out dx,ax           ;低位设置颜色索引,高位颜色值
  23.     mov ax,0x0f01
  24.     out dx,ax           ;打开颜色设置
  25. ;;设置屏蔽
  26.     mov ah,[bp-8]
  27.     mov al,0x08
  28.     out dx,ax           ;打开颜色设置
  29.     
  30.     pop edx
  31.     pop eax
  32.     add esp,8
  33.     pop ebp
  34.     ret
  35. ;----------------------------------------------------------------------------------------------
  36. ;----------------------------------------------------------------------------------------------
  37. ;void setColor(dd * color)
  38. ;;设置颜色  
  39. ;----------------------------------------------------------------------------------------------
  40. clsColor
  41.     push    ebp
  42.     mov ebp,esp
  43.     add ebp,8
  44.     push    eax
  45.     push    edx
  46.     
  47. ;;设置屏蔽
  48.     mov ah,0xff
  49.     mov al,0x8
  50.     out dx,ax           ;恢复显示所有位
  51.     
  52.     mov dx,0x3ce        ;图形控制器
  53.     mov ax,0xFF01
  54.     out dx,ax           ;允许所有颜色
  55.     mov ax,0x0f00       ;恢复为白色
  56.     out dx,ax           ;低位设置颜色索引,高位颜色值
  57.     pop edx
  58.     pop eax
  59.     pop ebp
  60.     ret
  61. ;----------------------------------------------------------------------------------------------
  62. ;----------------------------------------------------------------------------------------------
  63. ;void putIntPixDef32(dd *,color,dd *type, dd *esi)  ;注意:保证ESI指向CS的基址。CX象素列,DX字节行
  64. ;type为'ASC'时,输出一字节8位宽度
  65. ;根据AX输出行点阵  ;注意:本函数保持与ShowBytePix接口数一致
  66. ;----------------------------------------------------------------------------------------------
  67. putIntPixDef32
  68.     push    ebp
  69.     mov ebp,esp
  70.     add ebp,8
  71.     sub esp,8
  72.     push    eax
  73.     push    ebx
  74.     push    ecx
  75.     push    edx
  76.     push    edi
  77.     push    esi
  78.     
  79.     mov word [bp-4],ax      ;保存AX
  80.     ;mov    word [bp-8],dx      ;保存dx
  81.     ;mov    word [bp-6],cx      ;保存cx
  82.     ;call   getScrWidth     ;取得屏宽
  83. ;;es:bx为显存位置。   
  84.     mov eax,[ebp+0]
  85.     mov esi,eax
  86.     mov eax,edx         ;取出行
  87.     mov bx,[esi+_screenWidth]
  88.     mul bx          ;计算Y的偏移 ;注意加上CS段
  89.     shr ecx,3           ;象素列转成字符列
  90.     mov edi,eax         ;
  91.     add di,cx           ;得到总偏移
  92.     mov ax,SelectorVideoPix ;图形模式选择子
  93.     mov gs,ax           ;象素段
  94.     
  95.     mov ax,[bp-4]
  96.     mov bx,[ebp+8]
  97.     cmp bx,0xFFFF
  98.     jz  .noColor
  99. .havColor   
  100.     push    dword [ebp+8]
  101.     call    setColor
  102.     add sp,4
  103.     cmp dword [ebp+4],'ASC'     ;ASC方式
  104.     jz  .ASC
  105.     
  106.     mov byte [gs:di],al     ;写HZ源点阵
  107.     xchg    al,ah
  108.     push    dword [ebp+8]
  109.     call    setColor
  110.     add sp,4
  111.     mov byte [gs:di+1],al       ;写HZ源点阵
  112.     call    clsColor
  113.     jmp .out
  114.     
  115. .noColor
  116.     cmp dword [ebp+4],'ASC'     ;ASC方式
  117.     jz  .nocASC
  118.     mov word [gs:di],ax     ;写HZ源点阵
  119.     jmp .out
  120. .nocASC
  121.     mov byte [gs:di],al     ;写HZ源点阵
  122.     jmp .out
  123. .ASC
  124.     mov byte [gs:di],al     ;写HZ源点阵
  125.     call    clsColor
  126. .out    
  127.     pop esi
  128.     pop edi
  129.     pop edx
  130.     pop ecx
  131.     pop ebx
  132.     pop eax
  133.     add esp,8
  134.     pop ebp
  135.     ret
  136. ;----------------------------------------------------------------------------------------------
  137. ;0 black(黑) 0 0 0 0 
  138. ;1 blue(兰)   1 0 0 42 
  139. ;2 green(绿) 2 0 42 0 
  140. ;3 cyan(青) 3 0 42 42 
  141. ;4 red(红) 4 42 0 0 
  142. ;5 magenta(洋红) 5 42 0 42 
  143. ;6 brown(棕) 6 42 42 0 
  144. ;7 lightgray(浅灰) 20 42 42 42 
  145. ;8 darkgray(深灰) 56 0 0 21 
  146. ;9 lightblue(亮兰) 57 0 0 63 
  147. ;10 lightgreen(亮绿) 58 0 42 21 
  148. ;11 lightcyan(亮青) 59 0 42 63 
  149. ;12 lightred(亮红) 60 42 0 21 
  150. ;13 lightmagenta(亮洋红) 61 42 0 63 
  151. ;14 yellow(黄) 62 42 42 21 
  152. ;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)

 

[c-sharp]  view plain copy
  1. ;----------------------------------------------------------------------------------------------  
  2. ;printS: 1+ ;后面跟字符串  
  3. ;显示输出信息  
  4. ;----------------------------------------------------------------------------------------------  
  5. ;重载支持中文显示  
  6. %macro printS 1+  
  7.     push    si  
  8.   
  9.     jmp %%endstr  
  10. %%str:  db %1,0     ;增加结束符  
  11. %%endstr:  
  12.     mov si,%%str  
  13.     push    word BaseLoadGB2312  
  14.     push    word BaseOfGBFile  
  15.     call    ShowMsgAuto  
  16.     add sp,4  
  17.       
  18.     pop si  
  19. %endmacro  
  20. ;----------------------------------------------------------------------------------------------  

 

4)检测汉字库是否已加载并启用相关函数

[c-sharp]  view plain copy
  1. ;----------------------------------------------------------------------------------------------  
  2. ;void ShowMsgAuto(int *ds,int *si)  ;指向GB2312点阵库  
  3. ;显示字符;指向GB2312点阵库  
  4. ;----------------------------------------------------------------------------------------------  
  5. ShowMsgAuto  
  6.     push    ax  
  7.     push    ds  
  8.     push    si  
  9.     mov bp,sp  
  10.     add bp,2+6  
  11.       
  12.     cmp word [HzGB2312LoadOk],200H  
  13.     jnz .noload  
  14.       
  15.     push    word [bp+2]  
  16.     push    word [bp+0]  
  17.     call    ShowHzASC  
  18.     add sp,4  
  19.     jmp .out  
  20.       
  21. .noload  
  22.     call    ShowMsg  
  23. .out  
  24.     pop si  
  25.     pop ds  
  26.     pop ax  
  27.     ret  
  28. ;----------------------------------------------------------------------------------------------  

 

 5)判断调用输出ASC或ShowFont16

 

完成。打印一个汉字是需要花费很多功夫的,只要你不觉得输出个汉字都这么多代码。自己多看看一法二法的思想就懂得怎么去找怎么去组织了。

当然或许我的方法比较土,弄个汉字显示写了80KB+的代码。如果你有更犀利的代码,欢迎发到mythinker@2911.net,共资以历。

 

目前WriteOS卡在内核里。内核之前的东东已基本OK,方方面面都涉及到了一些。欢迎同好一起玩研DiyOS。

  1. ;Linyee write ,2008-9
  2. ;mythinker@2911.net
  3. ;QQ:249033420
  4. ;NASM源码,16位下的代码。
  5. ;----------------------------------------------------------------------------------------------
  6. ;void ShowFont16(int *ds,int *si)   ;输出点    ;dx行;cx列;
  7. ;输出汉字单字点阵   ;dx行;cx列;
  8. ;----------------------------------------------------------------------------------------------
  9. ShowFont16  
  10.     push    ax
  11.     push    bx
  12.     push    bp
  13.     push    ds
  14.     push    si
  15.     mov bp,sp
  16.     add bp,2+10
  17.     sub sp,8
  18.     
  19.     call    getCurPix   ;取坐标
  20.     mov word [bp-6],cx  ;列坐标
  21.     mov word [bp-4],dx  ;行坐标
  22.     mov bx,[bp+0]
  23.     mov si,bx
  24.     mov bx,[bp+2]
  25.     mov ds,bx       ;指向点阵库内指定字
  26.     mov bx,16
  27. .sl_nextLine:
  28.     cmp bx,0
  29.     jz .sl_return
  30.     lodsw
  31.     call    putIntPixDef
  32.     ;lodsb              ;本注释段为中断输出字符
  33.     ;call   ShowBytePix
  34.     ;mov    ah,al
  35.     ;lodsb
  36.     ;call   ShowBytePix
  37.     ;mov    cx,[bp-6]
  38.     inc dx
  39.     dec bx
  40.     jmp .sl_nextLine    ;下一行
  41. .sl_return:
  42.     
  43.     call    setCurMoveNext  ;光标下移
  44.     add cx,16       ;下移一个字宽
  45.     mov dx,[bp-4]   ;恢复到本行
  46. .out        
  47.     add sp,8
  48.     pop si
  49.     pop ds
  50.     pop bp
  51.     pop bx
  52.     pop ax
  53.     ret
  54.     
  55. ;----------------------------------------------------------------------------------------------
  56. ;----------------------------------------------------------------------------------------------
  57. ShowBytePix ;输出点    ;dx行;cx列;汉字库多从低字节高位开始打印
  58. ;----------------------------------------------------------------------------------------------
  59.     push    ax
  60.     push    bx
  61.     push    bp
  62.     mov bp,sp
  63.     sub sp,2
  64.     mov word [bp-2],ax
  65.     mov bx,8
  66. .test   
  67.     cmp bx,0
  68.     jz  .out
  69.     
  70.     mov al,[bp-2]
  71.     mov ah,0
  72.     shl al,1
  73.     mov word [bp-2],ax
  74.     jnc .point
  75.     
  76.     mov al,0FH      ;为白
  77.     jmp .point2
  78. .point
  79.     mov al,00H      ;为黑
  80. .point2
  81.     mov ah,0cH
  82.     int 10H
  83.     
  84.     dec bx
  85.     inc cx
  86.     jmp .test
  87. .out
  88.     ;call   cls0CH
  89.     add sp,2
  90.     pop bp
  91.     pop bx
  92.     pop ax
  93.     ret
  94. ;----------------------------------------------------------------------------------------------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值