98_hzk_gb2312_v0.4.asm
来自「汇编语言 参考书 包含作业与答案 从入门到精通 通俗易懂」· 汇编 代码 · 共 486 行
ASM
486 行
.model small
.stack 100h
.data
file_cclib db 'hzk16',0
handle_cclib dw ? ; CCLIB 文件句柄
buffer_cclib db 32 DUP(?),'$'
file_read db 'test.txt',0
handle_read dw ? ;读取文件句柄
buffer_read dw ?
char_offset db 4 DUP(?),'$'
print_buffer db 3 DUP(?),' $'
linex dw ?
liney dw ?
msg_open_error db 'File open wrong!','$'
msg_read_error db 'File read wrong!','$'
.code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
main proc far
mov ax,@data
mov ds,ax
;;;;;;;;;;;;;;
mov bh,0h ;读当前光标的位置
mov ah,3h
INT 10h
mov ax,16 ;保存光标位置,按象素点的行列保存
mul dh
mov linex,ax
mov ax,16
mul dl
mov liney,ax
mov al,12h ;设置显示模式为640*480,16色模式
mov ah,0h
INT 10h
;;*************************************************************************
open_file:
lea dx,file_read ;打开所读文件
mov al,0
mov ah,3dh
INT 21h
jc open_error
mov handle_read,ax ;保存文件句柄
lea dx,file_cclib ;打开CCLIB
mov al,0
mov ah,3dh
INT 21h
jc open_error
mov handle_cclib,ax ;保存字库句柄
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 读取并显示一个汉字,并循环
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_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_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
;;************************************************************** ;输出汉字
call print_normal
;call print_left
;call print_right
;call print_reverse
;;****************************************************************************
change: ;屏幕满时开始上滚一行
cmp linex,480
jz reset_x
jmp changerow
reset_x:
mov al,1
mov ah,6h
xor cx,cx
mov dh,30
mov dl,80
mov bh,0
INT 10h
sub linex,16 ;恢复到上一行
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;换行
changerow:
cmp liney,624
jae reset_y ;大于等于跳至换行
add liney,16
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
;add linex,16
jmp change
gogogo:
mov bl,16
mov ax,linex
cmp ax,0
jz cannotdiv_x
div bl
mov dh,al
jmp get_y
cannotdiv_x:
mov dh,0
get_y:
mov ax,liney
cmp ax,0
jz cannotdiv_y
mov bl,8
div bl
mov dl,al
jmp positionisok
cannotdiv_y:
mov dl,0
positionisok:
mov ah,2h
INT 10h
mov dx,buffer_read
mov ah,2h
INT 21h
;sub liney,8
jmp change
;;**************************************************************** ;错误处理程序
open_error:
lea dx,msg_open_error
mov ah,9h
INT 21h
jmp done
read_error:
lea dx,msg_read_error
mov ah,9h
INT 21h
jmp done
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
done:
mov ah,4ch
INT 21h
main ENDP
;;**************************************************************** ;正常显示汉字子程序
print_normal proc near
mov dx,linex ;设置X轴的坐标
mov cx,16 ;每个汉字显示为16行
lea si,buffer_cclib
writex:
push cx
mov bx,liney ;设置Y轴的坐标
;;;;;;;;;;
mov cx,8 ;一个汉字为16列,此为第一个字节显示
mov ah,[si]
writey:
shl ah,1
jc iszero
xor al,al
jmp goon
iszero:
mov al,7h
goon:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc bx
loop writey
;;;;;;;;;;;;;
inc si
mov cx,8
mov ah,[si]
writey2:
shl ah,1
jc iszero2
xor al,al
jmp goon2
iszero2:
mov al,7h
goon2:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc bx ;bx代替CX来计算列地址,右移一列
loop writey2
;;;;;;;;;;;;;;;;
pop cx
inc dx ;DX为行地址,下移一行
inc si
loop writex ;开始行循环
RET
print_normal ENDP
;;**************************************************************** ;左转90度显示汉字子程序
print_left proc near
mov bx,liney ;设置X轴的坐标
;add bx,16
mov cx,16 ;每个汉字显示为16行
lea si,buffer_cclib
writex:
push cx
mov dx,linex ;设置Y轴的坐标
add dx,16
;;;;;;;;;;
mov cx,8 ;一个汉字为16列,此为第一个字节显示
mov ah,[si]
writey:
shl ah,1
jc iszero
xor al,al
jmp goon
iszero:
mov al,7h
goon:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
dec dx
loop writey
;;;;;;;;;;;;;
inc si
mov cx,8
mov ah,[si]
writey2:
shl ah,1
jc iszero2
xor al,al
jmp goon2
iszero2:
mov al,7h
goon2:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
dec dx ;bx代替CX来计算列地址,右移一列
loop writey2
;;;;;;;;;;;;;;;;
pop cx
inc bx ;DX为行地址,下移一行
inc si
loop writex ;开始行循环
RET
print_left ENDP
;;**************************************************************** ;右转90度显示汉字子程序
print_right proc near
mov bx,liney ;设置X轴的坐标
add bx,16
mov cx,16 ;每个汉字显示为16行
lea si,buffer_cclib
writex:
push cx
mov dx,linex ;设置Y轴的坐标
;add dx,16
;;;;;;;;;;
mov cx,8 ;一个汉字为16列,此为第一个字节显示
mov ah,[si]
writey:
shl ah,1
jc iszero
xor al,al
jmp goon
iszero:
mov al,7h
goon:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc dx
loop writey
;;;;;;;;;;;;;
inc si
mov cx,8
mov ah,[si]
writey2:
shl ah,1
jc iszero2
xor al,al
jmp goon2
iszero2:
mov al,7h
goon2:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc dx ;bx代替CX来计算列地址,右移一列
loop writey2
;;;;;;;;;;;;;;;;
pop cx
dec bx ;DX为行地址,下移一行
inc si
loop writex ;开始行循环
RET
print_right ENDP
;;**************************************************************** ;倒转显示汉字子程序
print_reverse proc near
mov dx,linex ;设置X轴的坐标
add dx,16
mov cx,16 ;每个汉字显示为16行
lea si,buffer_cclib
writex:
push cx
mov bx,liney ;设置Y轴的坐标
;;;;;;;;;;
mov cx,8 ;一个汉字为16列,此为第一个字节显示
mov ah,[si]
writey:
shl ah,1
jc iszero
xor al,al
jmp goon
iszero:
mov al,7h
goon:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc bx
loop writey
;;;;;;;;;;;;;
inc si
mov cx,8
mov ah,[si]
writey2:
shl ah,1
jc iszero2
xor al,al
jmp goon2
iszero2:
mov al,7h
goon2:
push ax
mov ah,0ch
xchg cx,bx
push bx
xor bx,bx
INT 10h
pop bx
xchg cx,bx
pop ax
inc bx ;bx代替CX来计算列地址,右移一列
loop writey2
;;;;;;;;;;;;;;;;
pop cx
dec dx ;DX为行地址,下移一行
inc si
loop writex ;开始行循环
RET
print_reverse ENDP
;;********************************************************************************************
END main
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?