微机原理常用代码

选择结构(简单分支程序设计)

1.编写程序,计算下面函数的值并输出。

​ ![img](file:///C:\Users\COOL·~1\AppData\Local\Temp\ksohtml24868\wps1.png)

	include io32.inc

​	 .data

​	 .code

start:

​	 call readuid

​	 cmp eax,0

​	 jge xge0

​	 imul eax,2

​	 jmp display

xge0:

​	cmp eax,10

​	jg xg10

​	imul eax,3

​	jmp display

xg10:

​	imul eax,4

display:

​	call dispuid

​	exit 0

​	end start

2.输入一个年份(可调用readuid子程序,读入年份),判断是否是闰年.

提示:采用伪代码描述如下:

include io32.inc
	 .data
	 msg1 byte 'is leap year', 13, 10, 0
	 msg2 byte 'is not leap year', 13, 10, 0
.code
start :
		  call readuid
		  mov edx,0
		  mov ecx,4
		  div ecx
		  cmp edx,0
		  je s1
		  jmp s2
		  exit 0
s1:
		  mov edx,0
		  mov ecx,100
		  div ecx
		  jne leap
		  jmp s2
s2:
		  mov edx,0
		  mov ecx,400
		  div ecx
		  je leap
		  jmp noleap
 leap:
		  mov eax,offset msg1
		  call dispmsg
		  exit 0
noleap:
		  mov eax,offset msg2
		  call dispmsg
		  exit 0
end start

3. 输入三个无符号整数(可调用rebulid子程序),判断并输出这三个数能否构成一个三角形的三条边

include vcio.inc

.data	;setdata segment
	yes byte '可以构成',0
	no byte '不能构成', 0
	dengbian byte '等边三角形',0
	dengyao byte '等腰三角形',0
	x dword ?
	y dword ?
	z dword ?
	fmt byte '%d %d %d',0
	fmts byte '%s',0
.code
main proc
	invoke scanf,offset fmt,offset x,offset y,offset z
    mov eax,x
    add eax,y
    mov ebx,x
    add eax,z
    mov ecx,y
    add ecx,z
    mov esi,x;	做运算时不能两个同为memory变量 所以esi
    mov edi,y
    .if(eax>z)&&(ebx>y)&&(ecx>x)
    	invoke printf,offset fmts,offset yes;	//如果是字符串一定要加offset
    	.if(esi==y)&&(esi==z)
    		invoke printf,offset fmts,offset dengbian
    	.else if(esi==y||esi==z||edi==z)
    		invoke printf,offset fmts,offset dengyao
    	.endif
    
    .else
    	invoke printf,offset fmts,offset no
    .endif
    
   ret
  main endp
  end main

4. 采用无条件和有条件转移指令构造while和do while 循环结构,完成下面的求和任务并输出sum(sum为双字)。

inclued vcio.inc
.data
    fmt bate 'sum=%d',0
.code
    start:
		mov eax,0
        mov ecx,1
        .while ecx<101
        	add eax,ecx
        	inc ecx
        .endw
       invoke printf,offset fmt,eax
   ret
end start


//**思考题:假设双字为无符号整数,sum=1+2+...n,在和不溢出的情况下求出n的最大值;q求出sum和n的值。

include vcio.inc
.data
	fmt byte 'sum=%u n=%d',0
.code
start:
	mov eax,0
	mov ecx,1
again:
	add eax,ecx
	jc next
	inc ecx
	jmp again
next:
	sub eax,ecx	//加上ecx数超线
	dec ecx//  ecx减
	invoke printf,offset fmt,eax,ecx
ret 
end start
	
	


     

5. 编写一个程序,先提示输入数字“input number:0~9”,然后再下一行显示输入的数字,结束;如果不是键入了0~9数字,就提示错误“Error”,继续等待输入数字。

include vcio.inc
.data
	inmsg byte 'input number(0~9):',10,0
	ermsg byte 'ERROR!',10,0
	fmt byte '%c',0
    fmtin byte '%s',0
    fmeter byte '%s',0
    chd byte ?
    tt bytr ?	
.code
start:

L1:	invoke printf,offset fmtin,offset inmsg
	invoke scanf,offset fmt,offset chd
	.if chd>='0'&&chd<='9'
		invoke printf,offset fmt,chd
	.else
		invoke printf,offset fmter,offset ermsg
		invoke scanf,offset fmt,offset tt//tt吸收无效字符
		jmp L1
	.endif
ret
end start
    

循环结构

1. 有一个首地址为array的10个有符号的双字数组,编程分别求出偶数和与奇数和并输出。思考:改求最大值,最小值,正数和,负数和。

include vcio.inc
.data
	array dword 1,2,3,6
	fmt byte 'evensum=%d oddsum=%d',0
.code
start:
	mov ecx,lengthof array
	xor eax,eax//oushu
	xor ebx,ebx//奇数
	mov esi,0 ;数组下标-0开始
	.while ecx>0
		test array[esi*4],1//奇数  结果为0 zf为1 
		.if zero?
			add eax,array[esi*4];偶数和
		.else
			add ebx,array[esi*4];
		.endif
	inc esi  下标增加
	dec ecx
	endw
	invoke printf,offset fmt,eax,ebx
  ret
 end start
	
	

最大最小

include vcio.inv
.data
	array dword 11,3,4,6,55,9
	fmt byte 'max = %d  min=%d',0
.code
	mov esi,0
	mov eax,array[esi*4]
	mov ebx,eax
	mov ecx,lebgthof array
	.while esi<ecx
		.if eax<array[esi*4]
			mov eax,array[esi*4];最大
		.else if
			mov ebx,array[esi*4];最小
		.endif
		inc esi
	.endw
	invoke printf,offset fmt,eax,ebx
  ret
 end start	
	

正数和负数

include vcio.inv
.data
	array dword 11,3,4,6,55,9
	fmt byte 'Positive = %d  Negetive=%d',0
.code
	mov esi,0
	mov eax,0
	mov ebx,0
	mov ecx,lebgthof array
	.while esi<ecx
		cmp array[esi*4],0   //和0相比  大于0 eax正数
		jl next
		add eax,array[esi*4]
		jmp lab
		
	next: (负数)
		add ebx,array[esi*4]
	lab:
		inc esi
	.endw
	invoke printf,offset fmt,eax,ebx
  ret
 end start	
	

2. 有一个首地址为array的10个有符号的双字数组,编程逆置数组并输出。

;逆置一个一维数组
;算法描述
;left,right分别指向数组的第一个和最后一个元素,采用首尾交换。
;	1.left=0,right=n-1;
;		2.while left<right do
		{
			swap a[left],a[right];
			left++;
			right--;
		}
;合理分配寄存器:left=esi,right=edi
;采用带比例因子和相对寻址处理数组


;

include vcio.inc
.data 
	array dword 1,2,3,4,5,6,7,8
	fmt byte '%5d',0
.code
start:
	mov ecx,lengthof array-1
	mov esi,0;数组下标
	mov edi,ecx;最后一个下标
	.while esi<edi
		mov eax,array[esi*4]
		xchg array[esi*4],eax
		mov array[esi*4],eax
		inc esi
		dec edi
	.endw
	mov esi,o
	.while esi<=ecx
		pushad
			invoke printf,offset fmt,array[esi*4]
		popad
	inc esi
	.endw
ret
end start

3. Fibonacci 给出前30项,思考:在不产生溢出的情况下n的最大值

1. print 1,1
2. esi=esi+edi
	2.1 if cy=1 then goto done
	
	2.2print esi
	2.3exchange esi,edi
	2.4goto 2

4. 编程写一个完整的程序,求出2012年~2099年中的所有闰年年份,存入Lyear数组中

include vcio.inc
.data 
	array dword 100,dup(?)
	fmt byte '%d',0
	fmto byte '%d' ,0
.code 
start:
	mov esi,0
again:
	mov ecx,2020
	.while ecx<=2020
	
		mov eax,ecx
		xor edx,edx
		mov ebx,400
		div ebx
		cmp edx,0
		
		jz yes
		
		mov eax,ecx
		xoe edx,edx
		mov ebx 4
		div ebx
		cmp edx,0
		
		jnz no
		
		mov eax,ecx
		xoe edx,edx
		mov ebx 100
		div ebx
		cmp edx,0
		
		jz no
yes:
	mov array[esi*4],ecx
	inc esi
no:
	inc ecx
.endw
	mov ebx,0
.while ebx<esi
	invoke printf,offset fmto,array[ebx*4]
	inc ebx
.endw

ret
end start


		

5. 有一个首地址为string的字符串 ,分别统计string中空格、英文字母、数字和其它字符的个数并输出。

include vcio.inc

.data
	msg byte '12 ahi'
	space dword ?
	letter dword ?
	digit dword ?
	other dword ?
	fmt byte 'space = %d digit=%d other=%d',0
.code
main proc
	mov edi,lengthof msg-1   为了不判断0
	xor eax,eax	;space=eax=0
	mov ebx,eax ;letter=ebx=0
	mov ecx,eax ;digit=ecx=0
	mov edx,eax ;other=edx=0
	
	mov esi,0
	.while esi<edi
		.if(msg[esi]==' ')
			 inc eax;
			 space++
		.elseif(msg[esi]>='a'&&msg[esi]<='z')||(msg[esi]>='A'&&msg[esi]<='Z')
			inc ebx;
			letter++
		.elaseif(msg[esi]>='1'&&msg[esi]<='9')
			inc edx;
			digit++
		.else
			inc edx
			other ++
			
	.endif
	inc esi
	.endw
	invoke printf,offset fmt,eax,ebx,ecx,edx
ret
main endp
end start
	
	
	
	

6. palindrome(回文)是指正读和反读都一样的数或文本。例如:11、121、12321等,编写程序,求10到10000之间所有回文数并输出。要求每行输出10个数。

include vcio.inc
.data
	fmt byte '%4d',0
.code
start:
	mov ecx,10
	mov ebx,ecx	//ecx=10除数
	.while ecx<=100
		xor edz,edx	//edx被除数的高32位
		div ebx
		imul esi 10
		add esi,edx//逆序生成新数,esi=esi*10+edx
	.endw
	.if esi==ecx
		pushad
			invoke pritf,offset fmt,ecx
			popad
	.endif	
		inc ecx
	.endw
ret
end start
		

子程序

1..编写一个求n!的子程序,利用它求1!+2! +3! +4! +5! +6! +7! +8! 的和并输出。要求参数的传递分别采用寄存器传递,全局变量传递,堆栈传递。

;寄存器传参
include vcio.inc
.data
	fmt byte 'result =%d',10,0
.code
main proc
	mov edx,1
	.while ebx<=8
	call jcc;阶层子程序
	inoke printf,offset fmt,eax	;;eax传回来的值
	inc ebx
	.endw
ret
main endp
jcc proc
	mov ecx,1
	mov eax,1
	.while ecx<=ebx		;ebx是主程序传参进来的 寄存器传递
		imul eax,ecx	;阶层的和在eax
		inc ecx
	.endw
	ret
jcc endp
end main
	
	
	
	
	
;堆栈传参
;ebp+4断点地址,ebp+8 call 植爱玲前的入栈就是参数 子程序里找ebp

include vcio.inc
.data
	fmt byte 'result=%d',10,0
.code
main proc
	.while mov ebx<=8
		push ebx
		call jcc
		invoke printf,offset fmt,eax
		inc ebx
	.endw
ret
main endp
jcc proc
;ret 1*4是平衡ebx call

	push ebp
	mov ebp,esp
	mov ecx,1
	mov eax,1
	mov ebx,[ebp+8]
	.while ecx<=ebx
		imul eax,ecx
		inc ecx
	.endw
	pop ebp
	ret 1*4
jcc endp
end main
	
    
    
;全局变量传递


2. 编写一个判断闰年的子程序,利用它求出2010到2060之间所有的闰年并输出。

3. 编程写一个名为Prime的子程序,用于测试一个整数是否是素数,主子程序间的参数传递通过堆栈完成。调用Prime子程序求出2~100之间的所有素数,并将它们存入Parray数组中,素数的个数存入变量Pcounter中

#include<stdio.h>
void main()
{
	int j,i,k;
	for(i=2;i<=100;i++)
	{
		k=1/2;
		for(j=k;j>=2;j--)
			if(i%i==0)
				break;
		if(j<2)
			printf("%5d",i);
	}
}

;换一个思路设置标记位
#include<stdio.h>
voide main()
{
    int j,i,k,flag;
    for(i=2;i<=100;i++)
    {
        k=i/2;
        for(j=k;j>=2;j--)
            if(i%j==0)
                flag=0;
        	else
                flag==1;
        if(flag==1)
            printf("%5d",i);
    }
}

;汇编
include vcio.inc
.data
    Prime dword 100 dup(?)
    flag byte 1
    fmt byte '%3d',0
    fmtn byte 'Pcounter=%d',0
.code
main proc
    xor esi,esi;下标
	mov ecx,2;	2~10
    .while(ecx<=10)
        call prime
        .if flag==1
            mov Prime[esi*4],ecx
        .else
            jmp L1
     	.endif
     pushad
         invoke printf,offset fmt,Prime[esi*4]
     popad
	 inc esi
L1:
	inc ecx
    .endw
    invoke printf,offset fmtn,esi
ret
main endp

prime proc
     push ecx
     push esi
     mov eax,ecx ;x
     mov ebx,ecx ;x
     shr ecx,1 ;ecx=x/2
     .while(ecx>=2)
     	mov eax,ebx
     	div ecx
     	.if edx==0
     		mov flag,0
     	.else
     		mov flag,1
     	.endif
     		dec ecx
     	.endw
     	pop esi
     	pop ecx
   ret
prime endp
end main
     	
     

4. 编程写一个名为Gcd的求两个数最大公约数子程序,主子程序间的参数传递通过堆栈完成。调用Gcd子程序求出三个双自变量:dvar1、dvar2与dvar3的最大公约数并输出。(欧几里得算法 辗转相除法)

;算法思想:gcd(a,o)=a; gcd(a,b)=gcd(b,a mod b)

;in c 

int gcdx(int m,int n)
{
	int r;
	while(n!=0)
	{
		r=m%n;
		m=n;
		n=r;
	}
	return m;
}


;汇编

include vcio.inc
.data
	m dword ?
	n dword ?
	r dword ?
	dgcd dword ?	;2个数的最大公约数
	fmtout byte 'gcd($d,%d,%d)=%d',10,0
	fmtin byte '%d %d %d',0
.code
main proc
	invoke scanf,offset fmtin,offset m,offset n,offset r
	mov eax,m
	mov ebx,n
	mov ecx,r
	call Gcd   ;求a,b的最大公约数
	mov eax,dgcd
	mov ebx,ecx
	call Gcd	;(a,b)和c的最大公约数
ret
main endp
;全局寄存器变量
Gcd proc;求两个数的最大公约数
	.while(ebx!=0)
		xor edx,edx
		div ebx
		mov eax,ebx;m=n
		mov	ebx,edx;n=r edx=余数
	.endw
	mov dgcd,eax	;dgcd最大公约数
	ret
Gcd endp
end main

        
        //多次强调输出

5. 编写一子程序,将一个32位二进制数用8位十六进制形式在屏幕上显示出来。采用堆栈方法传递这个32位二进制数,并写主程序验证它。

include vcio.inc
.data
	dvar dword 1234abcd
	table byte '0123456789abcdef'	;查表法
	fmt byte '%c',0
.code
main proc
	call btoh
ret
main endp

btoh proc
	mov eax,dvar
	mov ecx,1
	.while ecx<=8
		rol eax,4	;eax的最高四位移动到最低4位
		mov ebx,eax
		and eax,0fh	;保留eax的最低的四位
		mov al,table[eax]
		pushad
			invoke printf,offset fmt,al
		popad
		mov eax,ebx
		inc ecx
	.endw
ret
btoh endp

6. 编程写一个名为Bubble的冒泡排序子程序,主子程序间的参数传递通过堆栈完成;并写主程序验证它。显示一个无符号数的子程序为:dispuid,入口参数:EAX=要显示无符号数的值。

include vcio.inc
.data
	array dword 2,3,1
	num dword lengthof array-1
	fmt byte '%3d',0
.code
main proc
	call Bubble
	mov esi,0
	.while(esi<=num)
		invoke printf,offset fmt,array[esi*4]
	inc esi
	.endw
ret
main endp

Bubble proc
	mov esi,0	;i
	mov edi,1	;j
	mov ecx,1	;pass
	.while ecx<=num
		mov esi,0	;i
		mov edi,0	;j
		.while esi<num
			mov eax,array[esi*4]
			.if eax>array[edi*4]
				mov edx,array[esi*4]
				xchg edx,array[edi*4]
				mov array[esi*4],edx
			.endif
			inc esi
			inc edi
		.endw
		inc ecx
	.endw
ret
Bubble endp
end main
                
 ;if a[i]>a[i+1]  i+1用j表示 

上课汇编程序

1. 数据比较程序

	; 数据段
in_msg1	byte 'Enter a number: ',0
in_msg2	byte 'Enter another number: ',0
out_msg1	byte 'Two numbers are equal: ',0
out_msg2	byte 'The less number is: ',0
out_msg3	byte 13,10,'The greater number is: ',0
	; 代码段
	mov eax,offset in_msg1	; 提示输入
	call dispmsg
	call readsid	; 输入第一个数据
	mov ebx,eax	; 保存到EBX
	mov eax,offset in_msg2	; 提示输入
	call dispmsg
	call readsid	; 输入第二个数据
	mov ecx,eax	; 保存到ECX
	cmp ebx,ecx	; 二个数据进行比较
	jne nequal	; 两数不相等,转移
	mov eax,offset out_msg1
	call dispmsg	; 显示两数相等
	mov eax,ebx
	call dispsid	; 显示相等的数据
	jmp done	; 转移到结束
nequal:	jl first
	; EBX较小,不需要交换,转移
	xchg ebx,ecx
	; EBX保存较小数,ECX保存较大数
first:	mov eax,offset out_msg2
	; 显示较小数
	call dispmsg
	mov eax,ebx	; 较小数在EBX中
	call dispsid
	mov eax,offset out_msg3
	; 显示较大数
	call dispmsg
	mov eax,ecx	; 较大数在ECX中
	call dispsid 
done:

2. 显示符号最高位程序

	; 数据段
dvar	dword 0bd630422h	; 假设一个数据
	; 代码段
	mov ebx,dvar
	shl ebx,1	; EBX最高位移入CF标志
	jc one
	; CF=1,即最高位为1,转移
	mov al,'0'
	; CF=0,即最高位为0:AL←'0'
	jmp two	; 一定要跳过另一个分支
one:	mov al,'1'	; AL←'1'
two:	call dispc	; 显示 
	mov ebx,dvar
	mov al,'0'
	; 假设最高位为0:AL←'0'
	shl ebx,1	; EBX最高位移入CF标志
	jnc two
	; CF=0,即最高位为0,转移
	mov al,'1'
	; CF=1,即最高位为1,AL←'1'
two:	call dispc	; 显示

3. 有符号位运算溢出程序

	; 数据段
dvar1	dword 1234567890	; 假设两个数据
dvar2	dword -999999999
dvar3	dword ?
okmsg	byte 'Correct!',0	; 正确信息
errmsg	byte 'ERROR ! Overflow!',0	; 错误信息
	; 代码段
	mov eax,dvar1 
	sub eax,dvar2	; 求差
	jo error	; 有溢出,转移
	mov dvar3,eax	; 无溢出,保存差值
	mov eax,offset okmsg	; 显示正确
	jmp disp
error:	mov eax,offset errmsg	; 显示错误
disp:	call dispmsg 

4. 简单加密解密程序

	; 数据段
key	byte 234
bufnum	= 255
buffer	byte bufnum+1 dup(0)
	; 定义键盘输入需要的缓冲区
msg1	byte 'Enter messge: ',0
msg2	byte 'Encrypted message: ',0
msg3	byte 13,10,'Original messge: ',0
	; 代码段
	mov eax,offset msg1	; 提示输入字符串
	call dispmsg
	mov eax,offset buffer	; 设置入口参数EAX
	call readmsg	; 调用输入字符串子程序
	push eax	; 字符个数保存进入堆栈
	mov ecx,eax
	; ECX=实际输入的字符个数,作为循环的次数
	xor ebx,ebx	; EBX指向输入字符
	mov al,key	; AL=加密关键字
encrypt:	xor buffer[ebx],al	; 异或加密
	inc ebx
	dec ecx	; 等同于指令:loop encrypt
	jnz encrypt	; 处理下一个字符
	mov eax,offset msg2
	call dispmsg
	mov eax,offset buffer	; 显示密文
	call dispmsg
	pop ecx
	; 从堆栈弹出字符个数,作为循环的次数
	xor ebx,ebx	; EBX指向输入字符
	mov al,key	; AL=解密关键字
decrypt:	xor buffer[ebx],al	; 异或解密
	inc ebx
	dec ecx
	jnz decrypt	; 处理下一个字符
	mov eax,offset msg3
	call dispmsg
	mov eax,offset buffer	; 显示明文
	call dispmsg

5.字符个数统计程序

	; 数据段
string	byte ‘Do you have fun with Assembly?’,0
	; 以0结尾的字符串
	; 代码段
	xor ebx,ebx
	; EBX用于记录字符个数,也用于指向字符的指针
again:	mov al,string[ebx]
	cmp al,0
	; 用指令“test al,al”更好
	jz done
	inc ebx	; 个数加1
	jmp again	; 继续循环
done:	mov eax,ebx	; 显示个数
	call dispuid

6.字符剔除程序

	mov eax,offset string
	; 显示处理前字符串
	call dispmsg
	mov esi,offset string
outlp:	cmp byte ptr [esi],0
	; 外循环,先判断后循环
	jz done	; 为0结束
again:	cmp byte ptr [esi],' ' ; 是否是空格
	jnz next	; 不是空格继续循环
	mov edi,esi	; 是空格,剔除空格分支
inlp:	inc edi	; 该分支是循环程序
	mov al,[edi]	; 前移一个位置
	mov [edi-1],al
	cmp byte ptr [edi],0
	; 内循环,先循环后判断
	jnz inlp	; 内循环结束处
	jmp again
	; 再次判断是否为空格(处理连续空格)
next:	inc esi
	; 继续对后续字符进行判断处理
	jmp outlp	; 外循环结束处
done:	mov eax,offset string
	; 显示处理后字符串
	call dispmsg

7. 计算有符号数平均值

; 数据段
array	dword 675,354,-34, ...
; 代码段
	push lengthof array	; 压入数据个数
	push offset array	; 压数组的偏移地址
	call mean
	; 调用求平均值子程序
	;出口参数:EAX=平均值(整数部分)
	add esp,8
	; 平衡堆栈(压入了8个字节数据)
	call dispsid	; 显示
		; 计算32位有符号数平均值子程序
mean	proc
	; 入口参数:顺序压入数据个数和数组偏移地址
	push ebp	;出口参数:EAX=平均值
	mov ebp,esp
	push ebx	; 保护寄存器
	push ecx
	push edx
	mov ebx,[ebp+8]	; EBX=取出的偏移地址
	mov ecx,[ebp+12]	; ECX=取出的数据个数
	xor eax,eax	; EAX保存和值
	xor edx,edx	; EDX=指向数组元素
mean1:	add eax,[ebx+edx*4]	; 求和
	add edx,1	; 指向下一个数据
	cmp edx,ecx	; 比较个数
	jb mean1	; 循环
	cdq	; 将累加和EAX符号扩展到EDX
	idiv ecx	; 有符号数除法,EAX=平均值
	pop edx	; 恢复寄存器
	pop ecx
	pop ebx
	pop ebp
	ret
mean	endp


猜你喜欢

转载自www.cnblogs.com/moguli/p/13204644.html