98_hzk_gb2312_v1.2_2005.1.20.asm
来自「汇编语言 参考书 包含作业与答案 从入门到精通 通俗易懂」· 汇编 代码 · 共 533 行 · 第 1/2 页
ASM
533 行
;╔━┅━┅━┅━┅━┅━┅━┅━┅━━┅━┅━┅━┅━┅━┅━ ╗
;┃≡TYPEGB of HZK V1.0 -----powered by BlasterKai! ≡ ┃
;┃ - ¤╭⌒╮ ╭⌒╮ ┃
;┃ ╱◥██◣ ╭ ⌒ ┃
;┃ |田︱田田| ╰---------一切都精彩-------缘自Buaa!! ┃
;┃︵﹏~︵﹏~︵﹏~︵﹏~︵﹏~︵ ┃
;╚┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━┅━ ╝
;----------------------------------------------------------------
; ╭═══════════════╮
; ║ TYPEGB of HZK V1.0 ║
; ╭══════┤ -powered by BlasterKai! ├═════╮
; ║ ║ --2004.10.31 ║ ║
; ║ ╰═══════════════╯ ║
; ║ ★ 汇编语言 (研究型大作业)★ ║
; ║ |---------------------------------------------| ║
; ║ 3. 在VGA 12h模式下,在屏幕上显示汉字,字库源于UCDOS中的 ║
; ║CCLIB或24X24字库。并让其支持字型转置。 ║
; ║ ║
; ║ ║
; ║ 算法简述 ║
; ║ ----------------------- ║
; ║ ;调用 21号中断的a号功能,读入文件名及路径信息 ║
; ║ ;再读入字型转置方式,默认为正常显示 ║
; ║ ;打开所读文件 ║
; ║ ;读当前光标的位置 ║
; ║ ;从待显示的文件中读取两个字节 ║
; ║ ;测试文件是否结束当为0时,表示EOF ║
; ║ ;计算在CCLIB中的偏移量 qh=c1-0xa0 wh=c2-0xa0 ║
; ║ ;从CCLIB中读入16*16的点阵,32个字节 ║
; ║ ;依据字型转置方式来输出汉字 ║
; ║ ;屏幕满时开始上滚一行 ║
; ║ ;用来显示一些非汉字字符,即ASCII字符 ║
; ║ ;错误处理程序 ║
; ║ ;显示汉字子程序 ║
; ║ ║
; ║ ║
; ║ ╭──────────────────────╮ ║
; ╰══┤ ★★★ Made in Buaa ★★★ ├══╯
; ╰──────────────────────╯
;━┅━┅━┅━┅━┅━┅━┅━┅━━┅━┅━┅━┅━┅━┅━┅━
;TypeGB of HZK v1.1 ---2004.11.12
; update: 1。汉字显示过程得到精简。 2。真正实现30行一滚屏,并有滚屏提示信息
; 2005.1.20 1.可以用直接写屏的方法,可以得到更高的显示速度。
; 2.程序的大部分集中在一个主程序中,应该多用子程序。
; 可读性比较差,有待改进。
; 3.现在感觉实现点阵汉字显示并不是很复杂,而当时却是花了很多时间。但还是有收获的。
;----------------------------------------------------------------
.MODEL SMALL
.STACK 100H
.DATA
inputfilename db 'Please input the file path and name : ','$'
maxlen db 32
actlen db ?
filename db 32 DUP(?)
inputmodel db 'Please input the model(normal,left,right,iverse) : ','$'
model db 'n'
file_cclib db 'hzk16',0
handle_cclib dw ? ; CCLIB 文件句柄
buffer_cclib db 32 DUP(?),'$'
handle_read dw ? ;读取文件句柄
buffer_read dw ?
linex dw ?
liney dw ?
msg_screenfull db 'Press any key to continue ...','$'
msg_goonscroll db ' ','$'
scrollnum db 27
msg_open_cclib_error db 'Could not find HZK16!','$'
msg_open_read_error db 'There is no such file!','$'
msg_read_cclib_error db 'HZK16 read wrong!','$'
msg_read_read_error db 'File read wrong!','$'
.CODE
;;*****************************************************************************************************************
MAIN PROC FAR
MOV AX,@DATA
MOV DS,AX
CALL GET_FILE_NAME
;;*************************************************************************
LEA DX,FILENAME ;打开所读文件
MOV AL,0
MOV AH,3DH
INT 21H
JC OPEN_READ_ERROR
MOV HANDLE_READ,AX ;保存文件句柄
LEA DX,FILE_CCLIB ;打开CCLIB
MOV AL,0
MOV AH,3DH
INT 21H
JC OPEN_CCLIB_ERROR
MOV HANDLE_CCLIB,AX ;保存字库句柄
;;*************************************************************************
MOV BH,0H ;读当前光标的位置
MOV AH,3H
INT 10H
MOV AX,16 ;保存光标位置,按象素点的行列保存
MUL DH
;MOV LINEX,0
MOV LINEX,AX
MOV LINEY,0
MOV AL,12H ;设置显示模式为640*480,16色模式
MOV AH,0H
INT 10H
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 读取并显示一个汉字,并循环
GETWORD_FILE: ;从待显示的文件中读取两个字节
MOV BX,HANDLE_READ ;INT 21H 42号功能移动文件指针
MOV CX,0
MOV DX,0H
MOV AL,1 ;移动方式,从当前位置开始移动
MOV AH,42H
INT 21H
;上面的好像有点多余
MOV BX,HANDLE_READ ;读文件,INT 21H,3F号功能
MOV CX,1 ;只读取一个字节
LEA DX,BUFFER_READ ;保存位置
MOV AH,3FH
INT 21H
JC READ_READ_ERROR
;;;;;;;;;;;;;;;
TEST AX,0FFFFH ;测试文件是否结束,AX中为实际写入的字节数,当为0时,表示EOF
JZ DONE
;;;;;;;;;;;;;;;
MOV AX,BUFFER_READ ;判断读到的字符是否为ACSII字符,是则用INT 21H号中断显示
CMP AL,0A0H
JB PRINT_ANSI_CHAR
;;;;;;;;;;;;;;;;
MOV BX,HANDLE_READ ;若为汉字,则再读取一个字节,并保存之后
MOV CX,1
LEA DX,BUFFER_READ+1
MOV AH,3FH
INT 21H
JC READ_READ_ERROR
;***************************************************************
COUNT_OFFSET: ;计算在CCLIB中的偏移量 QH=C1-0XA0 WH=C2-0XA0
;;;;;;;;;;;;;;;;;;;;;; ;该汉字在字库中离起点的位置是: OFFSET=(94*(QH-1)+(WH-1))*32L
MOV BX,BUFFER_READ
SUB BH,0A0H
SUB BL,0A0H
DEC BH
DEC BL
XOR AX,AX
MOV AL,BL
MOV CL,94 ;此时不会溢出
MUL CL
XOR CX,CX
MOV CL,BH
ADD AX,CX
MOV CX,32
MUL CX
;MOV BUFFER_READ,AX ;结果保存在DX+AX中,可再写入BUFFER_READ
;;****************************************************************
READ_CCLIB: ;从CCLIB中读入16*16的点阵,32个字节,并保存在BUFFER_CCLIB中
MOV BX,HANDLE_CCLIB
MOV CX,DX ;COUNT_OFFSET计算所得偏移量保存在DX:AX中,现在放入CX:DX中,42号功能
MOV DX,AX
MOV AL,0 ;从文件头开始读取,与待显示的文件指针移动方式不同
MOV AH,42H
INT 21H
MOV BX,HANDLE_CCLIB
MOV CX,32 ;32个字节
LEA DX,BUFFER_CCLIB
MOV AH,3FH
INT 21H
JC READ_CCLIB_ERROR
;;************************************************************** ;依据字型转置方式来输出汉字
MOV BH,MODEL
MOV BL,BH
CMP BL,'l'
JZ ISLEFT
MOV BL,BH
CMP BL,'r'
JZ ISRIGHT
MOV BL,BH
CMP BL,'i'
JZ ISREVERSE
CALL PRINT_NORMAL
JMP CHANGE
ISLEFT:
CALL PRINT_LEFT
JMP CHANGE
ISRIGHT:
CALL PRINT_RIGHT
JMP CHANGE
ISREVERSE:
CALL PRINT_REVERSE
JMP CHANGE
;;****************************************************************************
CHANGE: ;屏幕满时开始上滚一行
CMP LINEX,448
JAE RESET_X
JMP CHANGEROW
RESET_X:
INC SCROLLNUM
CMP SCROLLNUM,28
JE FULLSCREEN
JMP GOONSCROLL
;;;;;;;;;;;;;;;;;; ;换页功能
FULLSCREEN: ;可用来在最下端提示按键换页,实现
MOV DH,29
MOV DL,0
MOV AH,2
INT 10H
LEA DX,MSG_SCREENFULL ;最下端换页信息
MOV AH,9
INT 21H
MOV AH,00H ;按键但不回显,并且上滚20行
INT 16H ;用DOS 21--8号功能可能出现按一次键滚两屏的现象,用BIOS16号则不会有???
MOV SCROLLNUM,0
MOV DH,29 ;删除换页提示信息
MOV DL,0
MOV AH,2
INT 10H
LEA DX,MSG_GOONSCROLL ;
MOV AH,9
INT 21H
;;;;;;;;;;;;;;
GOONSCROLL: ;滚屏
MOV AL,1
MOV AH,6H
XOR CX,CX
MOV DH,28
MOV DL,80
MOV BH,0
INT 10H
SUB LINEX,16 ;恢复到上一行
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;换行
CHANGEROW:
CMP LINEY,616
JAE RESET_Y ;大于等于跳至换行
ADD LINEY,16
MOV DX,BUFFER_READ
CMP DL,0A0H ;由于输出为非汉字,只占用8个象素,所以要-8
JB NEEDSUB8
JMP NEXT
NEEDSUB8:
SUB LINEY,8
JMP NEXT
RESET_Y:
MOV LINEY,0H
ADD LINEX,16
;;************************************************************ ;开始读第二个字
NEXT:
JMP GETWORD_FILE ;LOOP GETWORD_FILE ;为什么用LOOP提示超出NEAR的范围,如何解决?
;;******************************************************** ;附加的一些处理程序段
PRINT_ANSI_CHAR: ;用来显示一些非汉字字符,即ASCII字符
MOV DX,BUFFER_READ
CMP DL,10 ;手动输出换行符
JZ NEEDCHANGELINE
JMP GOGOGO
NEEDCHANGELINE:
MOV LINEY,624 ;置Y轴的坐标大于边界,跳至上边会自动换行。 不用在此强制换行MOV LINEY,0并且不会产生换行多两个字符的BUG
JMP CHANGE
GOGOGO:
MOV BL,16 ;计算行列值,非象素值
MOV AX,LINEX
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?