不清楚的地方欢迎提问!小弟水平不高,请多指教。
我的环境:win8+emu8086
8个十六进制转二进制输出
; .486
;定义数据段
DATA SEGMENT USE16
INBUF DB 9,0,9 DUP(0) ;数据缓冲区 保存输入的字符串 \
;第一个9-表示包括回车在内的9个字符
;0-字符计数器 由DOS调用
;最后一个9 DUP(0)9个字节的存储空间
MSG1 DB 'INPUT A HEX NUMBER(1-8 DIGITS): ','$' ;字符串1
MSG2 DB 0DH,0AH,'NUMBER FORMAT ERROR!',0DH,0AH,' $' ;字符串2
MSG3 DB 0DH,0AH,'BINARY NUMBER IS: $' ;字符串3
COUNT DW 0 ;;
FLAG DW 0 ;;
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA ;段约定
BEG: MOV AX,DATA
MOV DS,AX ;段寄存器初始化
MOV AH,9 ;DOS功能调用【09】显示字符串 入口参数: DX=字符串首地址
LEA DX,MSG1 ;LEA指令把字符串MEG1的首地址赋值给DX
INT 21H ;调用DOS功能,输出'INPUT A HEX NUMBER(1-8 DIGITS):'
LEA DX,INBUF ;把INBUF首地址赋值给DX
MOV AH,0AH ;DOS功能调用【0AH】等待用户输入一串字符串送入用户程序数据缓存区
INT 21H ;调用DOS功能
LEA SI,INBUF ;把INBUF首地址赋值给SI
INC SI ;SI的地址加1,目的是跳过第一个字节(里面的内容为9,总共输入的字符个数)
MOV AL,[SI] ;把[SI]即输入字符的个数不包括回车赋值给AL
XOR AH,AH ;异或操作,把AH置0
MOV CX,AX ;把AX里面的内容赋值给CX(循环计数器),因为AH为0,所以AX的值等于AL的值也即是字符串个数(不包括回车)
INC SI ;SI加1,现在SI已经到第一个字符处了
VLD: MOV AL,[SI] ;把第一个字符赋值给AL
CMP AL,30H ;把第一个字符的ASCII码和30H(也就是字符'0')比较大小
JC DEER ;JC指令,当前C标志为1则转移到DEER,目的在于判断第一个字符和'0'的大小,若字符小于'0',则C=1
CMP AL,40H ;把当前字符和'9'比较,如果字符的ASCII码小于'9',则转移到NVLD
;(此段的功能是把SI加1,再调用VLD,判断下一个字符是否合法)
JC NVLD
CMP AL,'A' ;如果字符大于'9',则表示为'A'~'F','a'~'f'字符,需在进行下面的判断
JC DEER ;JC指令,如果字符的ASCII码小于'A',则是不合法字符,转移到DEER(此段输出不合法提示并退出程序)
CMP AL,'H' ;如果字符不小于'A',则需判断是否不大于'F'
JC NVLD ;如果字符不大于于'F',则字符合法,转移到NVLD(此段的功能是把SI加1,再调用VLD,判断下一个字符是否合法)
CMP AL,'a' ;如果字符大于'F',则需再判断是否在'a'~'f'之间
JC DEER ;如果小于'a',则字符不合法,转移到DEER,即退出
CMP AL,'h' ;如果字符不大于'f',则字符合法,转移到NVLD(.....同上)
;***********以上为陷阱处,上述比较中原为 39H,'F','f' 代码中已更正
JC NVLD
DEER: MOV AH,9
LEA DX,MSG2
INT 21H
JMP EXIT
;change
NVLD:
CMP AL,40H
JC SUB48 ;将字符值减去48
CMP AL ,'H'
JC SUB55 ;将字符值减去55
CMP AL ,'h'
JC SUB87 ;将字符值减去87
CON: INC SI
LOOP VLD ;当判断到最后一个字符结束的时候,此时CX里面的值为0,不能在进行循环,则继续下面的代码,输出二进制
MOV AH,9 ;DOS功能调用,【09H】输出字符串
LEA DX,MSG3 ;LEA指令把字符串MEG1的首地址赋值给DX
INT 21H ;调用DOS功能,输出'BINARY NUMBER IS:'
LEA SI,INBUF ;把INBUF的首地址给SI
INC SI ;SI加1,到字符个数计数也即输入的字符个数,不包括回车
MOV AL,[SI] ;把字符个数赋值给AL
XOR AH,AH ;异或操作,AH置0
MOV CX,AX ;把AX赋值给CX(循环计数器)
INC SI ;SI加1,到第一个字符处
DISP: MOV BL,[SI] ;把第一个字符赋值给BL
ADD COUNT ,1
CALL DISPBL ;调用过程语句DISPBL(作用是把当前字符以二进制显示输出)
INC SI ;SI加1,到下一个字符处
LOOP DISP ;循环DISP
MOV DL,'B' ;把字符'B'赋值给DL
MOV AH,2 ;DOS功能调用[02H]显示一个字符
INT 21H ;调用DOS功能
EXIT: MOV AH,4CH ;EXIT逻辑段,退出程序
INT 21H
SUB48: ;该段的作用是如果字符是在'0'~'9'之间,则把字符的ASCII码变为真正的 0~9
SUB BYTE PTR [SI],'0'
JMP CON
SUB55: ;该段的作用是如果字符是在'A'~'F'之间,则把字符的ASCII码变为真正的 A~F
SUB BYTE PTR [SI], 55
JMP CON
SUB87: ;该段的作用是如果字符是在'a'~'f'之间,则把字符的ASCII码变为真正的 a~f
SUB BYTE PTR [SI],87
JMP CON
;=======================================
DISPBL PROC ;过程定义语句
PUSH CX ;把当前计数器的值压入堆栈(保存外面循环的状态)
PUSH BX ;把BX的值压入堆栈
CMP CX ,1
JNZ DO1 ;判断CX是不是等于1,如果不等于1,则转移到DO1,即将BL左移四位再输出
TEST COUNT ,01H ;如果CX等于1,则再判断count是不是2的倍数,如果是则转移到DO1,即将BL左移四位再输出
JZ DO1
JMP DO2 ;这条语句就是说CX等于1,但是count不是2的倍数,则转移到DO2,即不需要将BL左移四位,
;可直接输出BL8位二进制数
LAST:
MOV DL,'0' ;DL赋值为字符'0'(目的是为了输出字符'0',DL是入口参数)
RCL BL,1 ;RCL(带进位的循环左移),移1位
JNC NEXT ;JNC(当前的C标志为0转移),也就是说如果当前移的二进制数是0,则转移到NEXT
MOV DL,'1' ;说明转移的不是0而是1,把DL赋值为'1'
NEXT: MOV AH,2 ;DOS功能调用【02H】输出一个字符,输出的字符是DL中的字符
INT 21H ;DOS功能调用
LOOP LAST ;循环LAST,需要判断CX的内容,之前已经被赋值为8
TEST COUNT, 01H
JZ SHOWSPACE ;转移到SHOWSPACE,输出空格
RETDO: POP BX ;把BX的值重新赋值为外面的BX,即出栈
POP CX ;把CX的值重新赋值给外面循环的CX,即出栈
RET ;返回
DO1: ;将BL左移4位
MOV CX,4
ROL BL,1
ROL BL,1
ROL BL,1
ROL BL,1 ;循环不进位左移
JMP LAST
DO2: ;不要将BL左移4位
MOV CX,8
JMP LAST
SHOWSPACE: ;该逻辑段的作用是输出一个空格
MOV DL,20H
MOV AH,2 ;20H就是空格的ASCII码,DOS功能调用【02H】输出一个字符
INT 21H ;DOS功能调用
JMP RETDO
DISPBL ENDP
CODE ENDS
END BEG ;汇编结束
带笑脸的helloworld
;.486 ;方式定义
DATA SEGMENT USE16 ;定义数据段
MESG DB 2,20H,'HELLO WORLD!', 0DH, 0AH, '$'
DATA ENDS
STACK SEGMENT PARA STACK 'STACK' USE 16 ;定义堆栈段
DB 100 DUP(0)
STACK ENDS
CODE SEGMENT USE16
ASSUME CS:CODE, DS:DATA ;说明段约定
BEG: MOV AX, DATA ; beg为启动地址
MOV DS, AX ;DS初始化
MOV CX, 6
LAST: MOV AH, 9
MOV DX, OFFSET MESG
INT 21H
LOOP LAST
MOV AH, 4CH
INT 21H ;返回dos
CODE ENDS
END BEG
hello彩色显示
;.486
DATA SEGMENT USE16
MESG1 DB 'HELLO$'
MESG2 DB 'I AM A STUDENT'
LL = $-MESG2 ; mesg2长度
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE
ASSUME DS:DATA
ASSUME ES:DATA ;
BEG:MOV AX, DATA
MOV DS, AX
MOV ES, AX ;ES:BP = 待显字符串首地址
MOV AX, 0003H ; 80X25 彩色文本方式
INT 10H ;
MOV AH, 9
MOV DX, OFFSET MESG1
INT 21H
MOV AX,1301H ;13是bios屏显功能号,课本119页
MOV BH, 0 ; 页号
MOV BL, 01001111B ; 属性字(AL为0、1时有效)
MOV CX, LL ; 串长度
MOV DH, 12 ; 行
MOV DL, (80-LL)/2 ; 列
MOV BP, OFFSET MESG2 ;
INT 10H
MOV AH, 4CH
INT 21H
CODE ENDS
END BEG
登录1
;.486
DATA SEGMENT USE16
RETRY DB 3 ;chance
UBUF DB 10,0,10 DUP(0) ;username's buffer
PBUF DB 8 DUP(0) ;PASSWORD BUFFER
MSG1 DB '====EXP2: Login System by B13041031 ====', 0dh, 0ah, '$'
MSG2 DB 0dh, 0ah, 'UserName: $'
MSG2_1 DB 0dh, 0ah, 'UserName Error! Retry...$'
MSG3 DB 0dh, 0ah, 'Password: $'
MSG3_1 DB 0dh, 0ah, 'Password Error! Retry...$'
MSG4 DB 0dh, 0ah, 'Login failed... :($'
MSG5 DB 0dh, 0ah, '==== Login Success, Welcome! ====', 0dh, 0ah, '$'
UID DB 'nixiaojun'
ULEN EQU $-UID
PASWD DB 'njupt'
PLEN EQU $-PASWD
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE, DS:DATA, ES:DATA
BEG: MOV AX, DATA ;Initializes the segment registers
MOV DS, AX
MOV ES, AX
MOV AX, 0003H ;Clear Screen
INT 10H
MOV AH, 9 ;
MOV DX, OFFSET MSG1
INT 21H
MOV RETRY, 3 ;
DISP1: MOV AH, 9 ;
MOV DX, OFFSET MSG2
INT 21H
MOV AH, 0AH ;
MOV DX, OFFSET UBUF
INT 21H
MOV AL, UBUF+1 ;
CMP AL, ULEN
JNZ ERR1 ;
LEA SI, UID ;
LEA DI, UBUF+1
MOV CX, ULEN
CLD
REPE CMPSB
JNZ ERR1 ;
JMP PPSWD ;
ERR1: DEC RETRY ;
JZ ERREXIT ;
MOV AH, 9 ;
MOV DX, OFFSET MSG2_1
INT 21H
JMP DISP1
PPSWD: MOV RETRY, 3 ;
DISP2: MOV AH, 9
MOV DX, OFFSET MSG3
INT 21H
MOV BX, OFFSET PBUF ;
PSWDIN: MOV AH, 07H
INT 21H
CMP AL, 0DH ;
JZ CMP_PSWD ;
MOV [BX],AL ;
INC BX ;
CMP BX, PLEN
JZ CMP_PSWD ;
JMP PSWDIN ;
CMP_PSWD:
LEA SI, PBUF
LEA DI, PASWD
MOV CX, PLEN
CLD
REPE CMPSB
JNZ ERR2 ;
JMP WELCOME ;
ERR2: DEC RETRY
JZ ERREXIT ;
MOV AH, 9 ;
MOV DX, OFFSET MSG3_1
INT 21H
JMP DISP2
ERREXIT:
MOV AH, 9
MOV DX, OFFSET MSG4
INT 21H
MOV AL, 0 ;
JMP EXIT
WELCOME:
MOV AH, 9
MOV DX, OFFSET MSG5
INT 21H
MOV AL, 1 ;
EXIT: MOV AH, 4CH
INT 21H
CODE ENDS
END BEG
登录2
;.486
SetPos MACRO Row,Col
MOV AH,2 ;设置光标位置
MOV BH,0 ;显示页0
MOV DH,Row ;设置行
MOV DL,Col ;设置列
INT 10H
ENDM
DATA SEGMENT USE16 ;定义数据段
MSG1 DB '***************************************************',0DH,0AH
DB '* *',0DH,0AH
DB '* User name: *',0DH,0AH
DB '* *',0DH,0AH
DB '* *',0DH,0AH
DB '***************************************************',0DH,0AH,'$'
LEN1 EQU $-MSG1
MSG2 DB '* Password : *','$'
LEN2 EQU $-MSG2
UNAME DB 32
DB 0
DB 32 DUP(0)
UPASS DB 32 DUP(0)
USER DB 'nixiaojun'
PASSWD DB 'njupt'
ERRTXT DB 'Error!'
LEN3 EQU $-ERRTXT
HELLO DB 'Welcome!'
LEN4 EQU $-HELLO
DATA ENDS
CODE SEGMENT USE16 ;定义代码段
ASSUME CS:CODE,DS:DATA,ES:DATA ;说明段约定
BEG: MOV AX,DATA ;BEG为启动地址标号
MOV DS,AX
MOV ES,AX
START: MOV AX,3
INT 10H ;设置显示模式80×25彩色文本
MOV AH,9
MOV DX,OFFSET MSG1
INT 21H ;显示提示字符串
SetPos 2,20 ;设置光标位置
MOV AH,0AH
MOV DX,OFFSET UNAME
INT 21H ;接收用户名输入
SetPos 3,0
MOV AH,9
MOV DX,OFFSET MSG2
INT 21H ;显示要求输入密码
SetPos 3,18
MOV DI,OFFSET UPASS
CLD
REDO1: MOV AH,7 ;将用户输入保存到UPASS中,直到回车为止
INT 21H
STOSB ;保存输入内容
CMP AL,0DH ;如果不是回车就继续输入
JNZ REDO1
MOV SI,OFFSET UPASS ;准备比较密码
MOV DI,OFFSET PASSWD
MOV CX,5
CLD
REPZ CMPSB ;源、目的串必须完全相等循环才能全部完成
MOV AX,CX
JNZ DERR ;如果退出循环时CX不为0,则说明源、目的串不完全相等,转出错显示
MOV AX,1301H ;否则说明密码核对正确,显示欢迎信息
MOV BH,0
MOV BL,97H
MOV CX,LEN4
MOV DH,5
MOV DL,21
MOV BP,OFFSET HELLO
INT 10H
JMP BACK ;准备返回DOS
DERR: MOV AX,1301H ;检测是否相等
MOV BH,0
MOV BL,4FH
MOV CX,LEN3
MOV DH,3
MOV DL,18
MOV BP,OFFSET ERRTXT
INT 10H
MOV AH,7
INT 21H ;必须按一个键才能继续
JMP START
BACK: MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END BEG
顺序结构test
;.486
DATA SEGMENT USE16
BUF DB 0
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE, DS:DATA
BEG:
MOV AX, DATA
MOV DS, AX
MOV AH, 1 ;输入字符
INT 21H
MOV BUF, AL
MOV AH, 4CH
INT 21H
CODE ENDS
END BEG
累加1~10输出
DATA SEGMENT ;输出0037, 看不太懂
BUFFER DW 1,2,3,4,5,6,7,8,9,10
SUM DW ?
DATA ENDS
STACK SEGMENT
DB 100 DUP(0)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
START:
MOV AX,DATA
MOV DS,AX
MOV AX,0
MOV DI,OFFSET SUM
MOV BX,OFFSET BUFFER
MOV CX,10
LOOP1:
ADD AX,[BX]
INC BX
INC BX
DEC CX
JNZ LOOP1
MOV [DI],AX
call dishex
MOV AX,4C00H
INT 21H
dishex proc near
mov cx,0404h
dis1:
rol ax,cl
mov dx,ax
and dl,0fh
call dischar
dec ch
jnz dis1
ret
dishex endp
dischar proc near
push ax
cmp dl,0ah
jl print
add dl,7
print:
add dl,30h
mov ah,2
int 21h
pop ax
ret
dischar endp
CODE ENDS
END START
延时子程序
;.486 ;就是赋值给ax, dx, 然后自减, 中间有nop空指令占用时间
dly: push ax
push dx
mov dx, 3ffh
time1: mov ax, 0fffh
time2: dec ax
nop
jne time2
dec dx
jne time1
pop dx
pop ax
ret
宏定义test
; multi-segment executable file template.
data segment
; add your data here!
pkey db "press any key...$"
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
crlf macro
mov ah, 0eh
mov al, 0dh
int 10h
mov al, 0ah
int 10h
endm
mov ah, 2
mov dl, 'A'
int 21h
crlf
crlf
mov ah, 2
mov dl, 0dh
int 21h
mov dl, 0ah
int 21h
crlf
lea dx, pkey
mov ah, 9
int 21h ; output string at ds:dx
; wait for any key....
mov ah, 1
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
ends
end start ; set entry point and stop the assembler.
寻找字符串最大的
;.486
data segment use 16 ;空格不空格都行
buf db 'qwertyuiop123'
flag db -1 ;在db末尾加上-1标志作为串结束标志
;count equ $-buf
max db 'max=', 0, 0dh, 0ah, '$'
data ends
code segment use16
assume cs:code, ds:data
crlf macro ;回车宏定义
mov ah, 0eh
mov al, 0dh;huiche
int 10h
mov al, 0ah;huanhang
int 10h
endm
beg: mov ax, data
mov ds, ax
mov al, 0
lea bx, buf
;mov cx, count
last: cmp byte ptr [bx], -1 ;[bx]<串结束标志-1?
je disp ;等于转移
cmp [bx], al
jc next
mov al, [bx] ;大数→AL
next: inc bx
;loop last ;循环计数
jmp last
;加上disp
disp:
mov max+4, al
mov ah, 9
mov dx, offset max
int 21h
mov ah, 4ch
int 21h
mov ah, 2
mov dl, 'A'
int 21h
crlf ;回车宏
code ends
end beg
一位十进制转二进制
;.486
data segment use16
mesg1 db 'Please Enter:', 0dh, 0ah, '$'
mesg2 db '--Error!$'
data ends
code segment use16
assume cs:code, ds:data
beg: mov ax, data
mov ds, ax
mov ah, 9
mov dx, offset mesg1
int 21h
mov ah, 1
int 21h
cmp al, 3ah
jnc err ;>9,wrong
cmp al, 30h
jc err ;<9,right
sub al, 30h
mov bl, al ;BL现在为0-9二进制数
mov ah, 2
mov dl, '='
int 21h
call disp ;转换并输出
mov ah, 2
mov dl, 'B'
int 21h
jmp exit
err:
mov ah, 9
lea dx, mesg2
int 21h
exit:
mov ah, 4ch
int 21h
;-------------------------
disp proc ;子程序
mov cx, 8
last: mov dl, '0' ;bl带进位左移, 为0出0, 为1出1
rcl bl, 1
jnc next ;c为0,跳,就 出0
mov dl, '1' ;否则出1
next:
mov ah, 2
int 21h
loop last
ret ;
endp
code ends
end beg
我的16进制转2进制
; .486
data segment use16
inbuf db 9, 0, 9 dup(0) ;第一个9是包括回车在内的9个字符
;0是输入几个dos就记录几个
;最后一个9是9个字节的存储空间
msg1 db 'Input a hex number(1-8 digits): $'
msg2 db 0dh, 0ah, 'Number format error!', 0dh, 0ah, '$'
msg3 db 0dh, 0ah, 'Binary number is: $'
count dw 0 ;
flag dw 0 ;
data ends
code segment use16
assume cs:code, ds:data
;---------------------------------------------------------------------------
beg: mov ax, data
mov ds, ax ;初始化ds
mov ah, 9
lea dx,msg1 ;dx(字符串首地址)指向msg1
int 21h
lea dx, inbuf ;inbuf首地址赋给dx
mov ah, 0ah ;等待用户输入一串字符串送入用户程序数据缓冲区
int 21h
lea si, inbuf ;si指向inbuf, 用于记录字符串下标
inc si ;si地址加1
mov al, [si] ;[si]输入字符个数(不含回车)赋给al
xor ah, ah ;异或, ah置0
mov cx, ax ;cx计数, 值为al即[si]
inc si ;使si到第一个字符处
vld: mov al, [si]
cmp al, 30h ;cmp功能是根据“目标-源”结果设置 apocsz状态
jc deer ;c为1时, 转到deer(显示出错)
cmp al, 40h
jc nvld
cmp al, 'A'
jc deer
cmp al, 'H' ;如果只是'F',就出错了
jc nvld
cmp al, 'a'
jc deer
cmp al, 'h'
jc nvld
deer: mov ah, 09h
lea dx, msg2
int 21h ;输出错误提示
jmp exit
nvld: cmp al, 40h
jc sub48 ;跳到sub48(字符值-48),'48'为30h的十进制
cmp al, 'H'
jc sub55
cmp al, 'h'
jc sub87
con: inc si
loop vld ;vld里最后一个字符结束的时候,继续下面代码
mov ah, 9
lea dx, msg3
int 21h ;输出' Binary Number is: '
lea si, inbuf ;si指向inbuf
inc si ;si++
mov al, [si]
xor ah, ah ;异或,把ah置0
mov cx, ax
inc si
disp: mov bl, [si] ;把第一个字符赋值给bl
add count, 1
call dispbl ;调用dispbl子程序(把当前字符以二进制显示输出)
inc si
loop disp
mov dl, 'B'
mov ah, 2 ;dos功能02h显示一个字符
int 21h
exit: mov ah, 4ch
int 21h ;退出
sub48: ;让30h-39h, ascii变为0-9 ;48是30h的二进制
sub byte ptr [si], '0'
jmp con
sub55: ;让41h-46h, ascii变为A-F
sub byte ptr [si], 55 ;如'A',二进制65-55为10
jmp con
sub87:
sub byte ptr [si], 87 ; 如'a', 二进制97-87为10
jmp con
;----------------------------------------------------------
dispbl proc ;子程序
push cx
push bx
cmp cx, 1
jnz do1 ;z(全0标志), cx==1时, 转移到do1(将bl左移四位再输出)
test count, 01h ;测试指令
jz do1 ;z=1 , 全0, 转到do1
jmp do2 ;
last:
mov dl, '0' ;
rcl bl, 1
jnc next
mov dl, '1'
next: mov ah, 2
int 21h
loop last
test count, 01h
jz showspace
retdo: pop bx
pop cx
ret
do1:
mov cx, 4
rol bl, 1
rol bl, 1
rol bl, 1
rol bl, 1
jmp last
do2:
mov cx, 8
jmp last
showspace:
mov dl, 20h
mov ah, 2
int 21h
jmp retdo
dispbl endp
;----------子程序结束--------------------------------
code ends
end beg