虽然对于微机原理与接口技术这门课已经比较摆了,但还是记录一下学的一点东西。
(汇编代码都是本来就有的)
例1: 在屏幕上依次显示“1”“2”“3”“A” “B” “C”个字符。
;定义数据段
DATA SEGMENT
STR DB ‘123ABC’
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX, DATA
MOV DS,AX ;初始化DS
LEA BX,STR ;取字符变量的偏移地址到BX
MOV CX,6 ;设置循环次数(6个字符)
LPP: MOV AH,2 ;将功能号2送AH
MOV DL, [BX] ;取一个要显示的字符到DL
; 二号功能调用,显示一个字符
INC BX ;修改指针
INT 21H ;调用中断21H
LOOP LPP
MOV AH, 4CH
INT 21H ;返回DOS
CODE ENDS
END START
;这段代码没有使用CX啊???
;LOOP与CX搭配使用,LOOP语句会使CX自动减一,如果CX=0,结束循环
例2: 在屏幕上显示欢迎字符串“Hello, World”。
DSEG SEGMENT
STRING DB ‘Hello, World’,0DH, 0AH, $’ ;定义要显示的字符串
;0DH,0AH,结合使用,起到换行效果
;$是字符串结束的标志
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
START: MOV AX, DSEG
MOV DS, AX ;初始化DS
LEA DX ,STRING ;获取要显示字串首地址
MOV AH, 09H ;调用字符串显示功能
;09H号功能显示字符串
INT 21H ;调用中断21H
MOV AH, 4CH
INT 21H ;返回DOS
CSEG ENDS
END START
例3 编写S=86H×34H-21H的程序,式中的3个数均为无符号数。
题目分析算:
(1)有3个数参加运算,所以要定义3个源操作数,因它们的类型相同,题目中没有要求分别存放,故只需定义一个字节类型变量来标识存放3个数的地址;
86H,34H,21H都是8位
(2)还需要定义一个变量来存放运算结果,因运算中有乘法,故结果应为16位,因而存放结果的变量应定义为字类型的变量;
注意乘法导致结果位数由8位变为16位。
(3)运算中要用到乘法指令,因3个操作数为无符号数,所以乘法指令用MUL。程序如下:
DATA SEGMENT
NUM DB 86H,34H,21H ;定义源操作数
RESULT DW ? ;定义结果存放单元
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA ;初始化DS
MOV DS, AX
LEA SI,NUM ;NUM的偏移地址送SI
LEA DI,RESULT ;RESULT偏移地址送DI
MOV AL, [SI] ;AL86H
MOV BL, [SI+1] ;BL34H
MUL BL ;AX86H×34H
;MUL: AX=AL*BL
MOV BL, [SI+2] ;BL21H
MOV BH, 0 ;把高8位置为0
SUB AX, BX ;AX86H×34H-21H
MOV [DI], AX ;结果送RESULT
MOV AH, 4CH
INT 21H ;返回DOS
CODE ENDS
END START
例4 两个多字节二进制数求和程序。
题目分析:
由于8088/8086CPU的内部寄存器均为16位。所以,在进行两个多字节数的求和运算时,一次只能完成一个字节或一个字的相加。低位字节(或字)相加的和可能会产生进位,那么在高位字节(或字)相加时则必须考虑该进位,否则就会使结果出错。因此,在多字节数求和运算中,要使用ADC指令,而不能使用ADD指令。
程序如下:
DATA SEGMENT
BUFF1 DB 4FH, OB6H,7CH, 34H, 56H, 1FH ;数1
;6个字节
BUFF2 DB 13H, 24H, 57H, 68H, OFDH, 9AH ;数2
SUM DB 6 DUP(?) ;和
CONT DB 3 ;数的字长为3
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV SI,OFFSET BUFE1 ;SI指向数1
MOV DI, OFFSET BUFF2 ;DI指向数2
MOV BX, OFFSET SUM ;BX指向存放和的单元
MOV CL, CONT ;共3个字,要做3次加法
MOV CH, O
CLC ;CF0(进位标志位)
COON:MOV AX, [SI] ;取数1的一个字
ADC AX, [DI] ;加上数2的相应字
ADD SI, 2 ;修改指针
ADD DI, 2
MOV [BX], AX ;存本次加的结果
ADD BX, 2
LOOP GOON ;未加完,则循环(共循环3次)
MOV AH, 4CH
INT 21H ;返回Dos
CODE ENDS
END START
例5:在当前数据段中DATA1开始的顺序80个单元中,存放着80位同学某门功课的考试成绩(0~100)。编写程序统计≥90分、80~89分、70~79分、60~69分以及<60分的人数,并将结果放到同一数据段的DATA2开始的5个单元中。
题目分析:
(1)这是一个具有多个分支的分支程序,结构如图1所示。需要将每一位学生的成绩依次与90、80、70、60进行比较,因是无符号数,所以用CF标志作为分支条件,相应指令为JC;
(2)由于对每一位学生的成绩都要进行判断,所以需要用循环来处理,每次循环处理一个学生的成绩;
(3)因为无论成绩还是学生人数都不超过一个字节所能表示的数的范围,故所有定义的变量均为字节类型
(4)统计结果可用一个数组存放,元素0存放90分以上的人数,元素1存放80分以上的人数,元素2存放70分以上的人数,元素3存放60分以上的人数,元素4存放60分以下的人数。
DATA SEGMENT
DATAI DB 80 DUP(?) ;假定学生成绩已放入这80个单元中
DATA2 DB 5 DUP(0) ;统计结果:≥90、80-89、70~79、60-69、<60
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV CX, 80 ;统计人数送CX
LEA SI, DATAI ;SI指向学生成绩
LEA DI, DATA2 ;DI指向统计结果
AGAIN: MOV AL, [SI] ;取一个学生的成绩
CMP AL, 90 ;大于90分吗?
JC NEXT1 ;若不大于,继续判断(跳转到NEXT1)
INC BYTE PTR[DI] ;否则90分以上的人数加1
JMP STO ;转循环控制处理
NEXT1: CMP AL, 80 ;大于80分吗?
JC NEXT2 ;若不大于,继续判断
INC BYTE PTR[DI+1] ;否则80分以上的人数加1
JMP STO ;转循环控制处理
NEXT2: CMP AL, 70 ;大于70分吗
JC NEXT3 ;若不大于,继续判断
INC BYTE PTR[DI+2] ;否则70分以上的人数加1
JMP STO ;循环控制处理
NEXT3: CMP AL, 60 ;大于60分吗?
JC NEXT4 ;若不大于,继续判断
INC BYTE PTR[DI+3] ;否则60分以上的人数加1
JMP STO ;转循环控制处理
NEXT4: INC BYTE PTR[DI+4] ; 60分以下的人数加1
STO: INC SI ;指向下一个学生成绩
LOOP AGAIN ;循环,直到所有成绩都统计完
MOV AH, 4CH
INT 21H ;返回DOS
CODE ENDS
END START
例6:把从MEM单元开始的100个16位无符号数按从大到小的顺序排列。
题目分析:
(1)这是一个排序问题,由于是无符号数的比较,可以直接用比较指令CMP和条转移指令JNC来实现;
(2)这是一个双重循环程序,先使第一个数与下一个数比较,若大于则使其位置保持不变,小于则将大数放低地址,小数放高地址(即两数交换位置);
(3)以上完成了一次排序工作,再通过第二重的99次循环,即可实现对100个无符号数的大小排序。
(冒泡排序)
每次产生一个最小数放在最右边。
DSEG MEMENG
MEM DW 100 DUP(?) ;假定要排序的数已存人这100个字单元中
DSEG ENDS
CSEG SEGMENT
ABGUME CS:CSEG, DS: DSEG
START: MOV AX, DSEG
MOV DB, AX
LEA DI, MEM ;DI指向待排序数的首址
MOV BL, 99 ;外循环只需99次即可
;外循环体从这里开始
NEXT1: MOV SI, DI ;SI指向当前要比较的数
MOV CL, BL ; CL为内循环计数器(不断减小)
;以下为内循环
NEXT2: MOV AX,[SI] ;取第一个数Ni
ADD SI, 2 ;指向下一个数Nj
CMP AX,[SI] ;Ni≥Nj?
;CMP的功能相当于减法指令,只是对操作数之间运算比较
;不保存结果,对标志寄存器产生影响。
JNC NEXT3 ;若大于,则不交换
;JNC: jump if not carry:没有借位,即大于
MOV DX,[SI] ;否则,交换Ni和Nj
MOV [SI-2], DX
MOV [SI], AX
NEXT3: DEC CL ;内循环结東?
JNZ NEXT2 ;若未结東,则继续
;JNZ:结果不为0则转移
;内循环到此结束
DEC BL ;外循环结東?
JNZ NEXT1; ;若未结束,则继续
;外循环体结束
MOV AH, 4CH
INT 21H ;返回DOS
CSEG ENDS
END START
小感想:
现在大三了,从c到c++,到汇编, 甚至python,很多东西都学的浅尝辄止(学校授课)
大一大作业是用c写贪吃蛇,之后是银行管理系统,之后是学生成绩管理系统(带数据库)
感觉还是要自学,去看见漫无边际的程序世界。不是就是写各种语言的"hello world"。
有点可笑。
对于程序的思考:
逻辑+熟练使用各种语句,明白各种语句的含义。