计算机组成原理汇编语言程序设计.docx
- 文档编号:14146496
- 上传时间:2023-06-21
- 格式:DOCX
- 页数:23
- 大小:164.43KB
计算机组成原理汇编语言程序设计.docx
《计算机组成原理汇编语言程序设计.docx》由会员分享,可在线阅读,更多相关《计算机组成原理汇编语言程序设计.docx(23页珍藏版)》请在冰点文库上搜索。
计算机组成原理汇编语言程序设计
《计算机组成原理实验》
实验报告
(实验二)
学院名称
:
数据科学与计算机学院
专业(班级)
:
学生姓名
:
学号
时间
:
2019
年
10
月
19
日
成绩
:
实验二
:
MIPS汇编语言程序设计实验
一.实验目的
1.初步认识和掌握MIPS汇编语言程序设计的基本方法;
2.熟悉QEMU模拟器和GNU/Linux下x86-MIPS交叉编译环境的使用。
二.实验内容
我的题目为31%4+1,第四题。
【密码】编写一个程序,先从键盘输入一个字符串(有英文字母,可能也有数字),
然后显示其中数字符的个数、英文字母的个数和字符串的长度;字符串中不能有空格,若有
将其删除,并将改变后的字符串按相反的顺序显示出来;输入第二个字符串,然后将输入的
字符串与前面处理后的字符串比较是否相同,若相同,输出“PasswordRight!
”,否则输
出“PasswordError!
”。
三.实验器材
PC机一台,装有Linux操作系统的虚拟机一套,QEMU模拟器软件一套,GNU跨平台交叉编译环境一套。
四.实验过程与结果
说明:
根据需要书写相关内容,如:
程序流程图、设计的思想与方法、分析、实验步骤和实验结果及分析等。
1、程序流程图
首先,遍历输入字符串并记录字符串长度,字母个数,数字个数,并把非空格字符存到分配好的空间。
然后,逆转字符串并再存入另一个空间。
随后再读入一个字符串,判断两者是否相等。
如果相等就输出PasswordRight!
,否则输出PasswordError!
2、可能用到的指令
lb/lh/lw:
从存储器中读取一个byte/halfword/word的数据到寄存器中.如lb$1,0($2)
sb/sh/sw:
把一个byte/halfword/word的数据从寄存器存储到存储器中.如sb$1,0($2)
add/addu:
把两个定点寄存器的内容相加add$1,$2,$3($1=$2+$3);u为不带符号加。
addi/addiu:
把一个寄存器的内容加上一个立即数add$1,$2,#3($1=$2+3);u为不带符号加。
sub/subu:
把两个定点寄存器的内容相减。
and/andi:
与运算,两个寄存器中的内容相与and$1,$2,$3($1=$2&$3);i为立即数。
or/ori:
或运算。
xor/xori:
异或运算。
beq/beqz/benz/bne:
条件转移eq相等,z零,ne不等。
j/jr/jal/jalr:
j直接跳转;jr使用寄存器跳转;
slt/slti/sltui:
如果$2的值小于$3,那么设置$1的值为1,否则设置$1的值为0。
slt$1,$2,$3。
mov/movz/movn:
复制,n为负,z为零。
mov$1,$2;movz$1,$2,$3($3为零则复制$2到$1)。
本实验主要涉及字符串和字符的操作,此外还涉及到计数。
所以一般使用lb/sb和lw/sw来解决寄存器存储数据空间不足的情况。
本实验涉及判断单个字符的类型,需要用到大小比较。
我使用slt/slti和beq/beqz/benz/bne来跳转。
另外,必须用到的还有加减法、寄存器赋值、逻辑运算等指令。
3、设计流程
首先我们为输入字符串和操作后的字符串分配内存空间,分配:
origin_str:
.space1000#原始输入字符串
nospace_str:
.space1000#去除空格后的字符串
reversed_str:
.space1000#翻转后的字符串
然后分配存储计数的整形变量的内存空间:
str_len:
.word0#字符串长度
num_let:
.word0#字母字符数量
num_dig:
.word0#数字字符数量
打印特定的字符串使用syscall4,预设一些可能用到的asciiz字符串。
输入字符串使用syscall8,需要把目的地址放入寄存器,如下:
la$a0,str
li$a1,100
li$v0,8
syscall
遍历字符串取字符的操作可以使用不断自增当前地址+寻址的方式进行:
loop:
lb$t2,($t0)
add$t0,$t0,1#$t0地址加一
jloop
题目涉及连续判断的条件。
判断大于和小于都可以通过slti和slt来进行,只需要颠倒寄存器的位置即可。
对连续判断条件,可以分别计算并作逻辑运算,
例如,判断字符是不是数字:
slti$t6,$t2,58#$t2<'9'+1时置位
slti$t7,$t2,48#$t2<'0'时置位
nor$t7,$zero,$t7#$t7取反
and$t6,$t6,$t7#$t6='0'<=$t2<='9'
beq$t6,1,adddigit
需要一个取反操作,或者把48放入寄存器中。
类似的,判断是不是字母,是不是空格也使用类似的方法。
循环过程中进行存数操作,每次存一个字节然后地址增加一个字节。
save1:
sb$t2,($t5)
addi$t5,$t5,1
jjudge
遍历结束后,使用另一块空间把字符串作逆转,使用C代码的指针实现如下。
char*p1=str;
char*p2=reversed_str+length-1;
while(*p1!
=0)
{
*p2=*p1;
p2--;
p1++;
}
指针可以直接用地址代替,使用MIPS汇编实现如下:
reverse:
la$t0,nospace_str
la$t1,reversed_str
add$t2,$t3,$t4#$t2=nospace_str字符串的有效长度
#做一个t2次的循环,不断存字节使(reversed_str+$t2-i-1)=i(nospace_str)
add$t1,$t1,$t2
addi$t1,$t1,-1
li$t3,0
loop:
beq$t3,$t2,Retype
add$t4,$t3,$t0
lb$t5,($t4)
sub$t6,$t1,$t3
sb$t5,($t6)
addi$t3,1
jloop
然后再次输入一个字符串,比较两个字符串是否相等。
如流程图所示,先判断长度相等与否,再判断每个字符的相等与否。
length_equal:
la$t0,num_let
lb$t2,($t0)
la$t0,num_dig
lb$t3,($t0)
add$t2,$t2,$t3
bne$t1,$t2,not_equal
la$t0,origin_str
la$t1,reversed_str
li$t3,0
if_equal:
beq$t2,$t3,equal
lb$t4,($t0)
lb$t5,($t1)
bne$t4,$t5,not_equal
add$t0,$t0,1
add$t1,$t1,1
add$t3,$t3,1
jif_equal
not_equal:
li$v0,4
la$a0,error
syscall
jexit
equal:
li$v0,4
la$a0,right
syscall
exit:
li$v0,10#退出
syscall#系统调用
如果都相等就打印right,否则打印error。
先使用PCSPIM进行调试,在修改了部分bug后模拟结果如下。
图1输入正确时的程序输出
图2输入错误时的程序输出
可以看到基础的功能都得到实现,尝试在x86环境下汇编链接代码并生成MIPS可执行文件,随后使用QEMU来运行。
QEMU和PCSPIM的不同点在于使用的是linux内核调用,所以与syscall相关的代码必须得到修改。
此外,由于写整数的接口无法使用,我们需要自己实现一个把整数转换为字符串的函数,用于打印该整数。
基本思路还是把整数不断除10,把余数放入对应的地址,如下:
#打印一个整数的代码,整数保存在t1中,返回地址保存在ra中
Printint:
#先确定该整数长度
la$t0,int_str
li$t2,10
li$t4,0
move$t3,$t1
get_int_len:
div$t3,$t2#除10
mflo$t3
add$t4,$t4,1
bnez$t3,get_int_len
add$t5,$t0,$t4
sb$zero,($t5)#置末尾为0
addi$t4,$t4,-1
assign:
blt$t1,$t2,saveint#如果t1小于10
div$t1,$t2#除10
mflo$t1#商
mfhi$t3#余数
addi$t3,$t3,48#acsii码
add$t5,$t0,$t4#t5为存字节的地址
sb$t3,($t5)#存数
addi$t4,$t4,-1#调整地址
jassign#循环
saveint:
addi$t1,$t1,48#acsii码
add$t5,$t0,$t4#t5为存字节的地址
sb$t1,($t5)#存数
printStr:
li$a0,1
la$a1,int_str
li$a2,100
li$v0,4004
syscall
jr$ra
这样我们用jal调用它时,就可以直接打印出$t1中的整数了。
自此程序设计环节完成。
4、实验测试结果与分析
尝试在linux虚拟机上运行这段程序的MIPS可执行文件,并使用不同的输入例来寻找程序的不足。
①基础输入例
使用例子中的输入,查看到输出如下:
图3QEMU的执行结果1
符合我们的预期,再尝试一下其他的测试例。
②长度不同的输入例
查看到输出如下:
图4QEMU的执行结果2
③长度相同字符不同的输入例
查看到输出如下:
图5QEMU的执行结果3
④全都是空格的输入例
输出如下:
图6QEMU的执行结果4
可见程序已经能够实现我们题目中给定的逻辑,并能应对一些特殊情况。
五.实验心得
实验的主题是使用MIPS汇编进行程序设计,应该说MIPS汇编的难度比起X86要小了很多。
比起X86它拥有更灵活的跳转语句,由此可以带来更精简的循环和递归调用;算术和逻辑运算的数据传输也变得更清晰;此外还有比较容易的变量空间分配和声明。
用MIPS来做程序设计是一个很好的提升自己的过程。
实验中要实现的功能很简单,如果使用C++等高级语言很快就能实现,但当我们只能使用纯粹的汇编码时,难度就上升了一个等级。
原本方便的数据类型、循环等操作都要用汇编码和编译器实现,体验上和高级语言的设计过程有很大的不同。
实验的另一个特点就是要在linux环境下用QEMU进行模拟。
QEMU的环境和普通的MIPS环境有所不同,这要求我们灵活地进行代码修改和系统功能的调用。
对我的题目,需要设计itoa的汇编代码,对别的题目可能还需要atoi的函数。
这种扩展性的问题有助于我们提升资源有限情况下的解决问题能力。
总之,本实验通过汇编程序设计,不仅能够提升我们的编程能力,更能加深我们对机器码的运行原理,内存空间和数据的关系,以及编译器、计算机硬件和操作系统之间的交互和协同工作关系的理解。
【程序代码】
.data
origin_str:
.space1000#原始输入字符串
nospace_str:
.space1000#去除空格后的字符串
reversed_str:
.space1000#翻转后的字符串
int_str:
.space100#用于储存整形的字符串
input:
.asciiz"Inputstring:
"
stringlength:
.asciiz"StringLength:
"
letternum:
.asciiz"Numberofletters:
"
digitnum:
.asciiz"Numberofdigits:
"
reversedstr:
.asciiz"ReversedString:
"
retype:
.asciiz"Retype:
"
right:
.asciiz"PasswordRight!
\n"
error:
.asciiz"PasswordError!
\n"
endl:
.asciiz"\n"
str_len:
.word0#字符串长度
num_let:
.word0#字母字符数量
num_dig:
.word0#数字字符数量
.text
.globalmain
main:
li$v0,4004
li$a0,1
la$a1,input#提示输入字符串
li$a2,14
syscall
li$a0,0
la$a1,origin_str#a0=原始字符串地址
li$a2,900
li$v0,4003
syscall
la$t0,origin_str#使用寄存器保存三个计数
li$t1,0
li$t3,0
li$t4,0
la$t5,nospace_str
#循环,计数字符串长度,字母和数字个数
#并把除空格以外的字符录入nospace_str
count:
lb$t2,($t0)
beq$t2,0,endcount#结束count循环
li$t6,32
bne$t6,$t2,save1#$t2!
=''时存字符到nospace_str
judge:
add$t0,$t0,1#$t0地址加一
add$t1,$t1,1#字符串长度加一
slti$t6,$t2,58#$t2<'9'+1时置位
slti$t7,$t2,48#$t2<'0'时置位
nor$t7,$zero,$t7#$t7取反
and$t6,$t6,$t7#$t6='0'<=$t2<='9'
beq$t6,1,adddigit
slti$t6,$t2,91#$t2<'Z'+1时置位
slti$t7,$t2,65#$t2<'A'时置位
nor$t7,$zero,$t7#$t7取反
and$t6,$t6,$t7#$t6='A'<=$t2<='Z'
beq$t6,1,addletter
slti$t6,$t2,123#$t2<'z'+1时置位
slti$t7,$t2,97#$t2<'a'时置位
nor$t7,$zero,$t7#$t7取反
and$t6,$t6,$t7#$t6='A'<=$t2<='Z'
beq$t6,1,addletter
jcount
save1:
#存数
sb$t2,($t5)
addi$t5,$t5,1
jjudge
adddigit:
#数字字符计数加一
add$t3,$t3,1
jcount
addletter:
#字母字符计数加一
add$t4,$t4,1
jcount
#打印一个整数的代码,整数保存在t1中,返回地址保存在ra中
Printint:
#先确定该整数长度
la$t0,int_str
li$t2,10
li$t4,0
move$t3,$t1
get_int_len:
div$t3,$t2#除10
mflo$t3
add$t4,$t4,1
bnez$t3,get_int_len
add$t5,$t0,$t4
sb$zero,($t5)#置末尾为0
addi$t4,$t4,-1
assign:
blt$t1,$t2,saveint#如果t1小于10
div$t1,$t2#除10
mflo$t1#商
mfhi$t3#余数
addi$t3,$t3,48#acsii码
add$t5,$t0,$t4#t5为存字节的地址
sb$t3,($t5)#存数
addi$t4,$t4,-1#调整地址
jassign#循环
saveint:
addi$t1,$t1,48#acsii码
add$t5,$t0,$t4#t5为存字节的地址
sb$t1,($t5)#存数
printStr:
li$a0,1
la$a1,int_str
li$a2,100
li$v0,4004
syscall
jr$ra
endcount:
la$t0,str_len
addi$t1,$t1,-1#输入的origin_str最后一个字符为\n,所以长度要减一
sw$t1,($t0)
la$t0,num_let
sw$t3,($t0)
la$t0,num_dig
sw$t4,($t0)
li$v0,4004#打印stringlength的一行
li$a0,1
la$a1,stringlength
li$a2,15
syscall
la$t0,str_len
lw$t1,($t0)
jalPrintint
li$v0,4004
li$a0,1
la$a1,endl
li$a2,1
syscall
li$v0,4004#打印letternum的一行
li$a0,1
la$a1,letternum
li$a2,19
syscall
#打印整形
la$t0,num_let
lw$t1,($t0)
jalPrintint
li$v0,4004
li$a0,1
la$a1,endl
li$a2,1
syscall
li$v0,4004#打印digitnum的一行
li$a0,1
la$a1,digitnum
li$a2,18
syscall
#打印整形
la$t0,num_dig
lw$t1,($t0)
jalPrintint
li$v0,4004
li$a0,1
la$a1,endl
li$a2,1
syscall
reverse:
#逆向字符串
la$t0,num_let
lw$t3,($t0)
la$t0,num_dig
lw$t4,($t0)
la$t0,nospace_str
la$t1,reversed_str
add$t2,$t3,$t4#$t2=nospace_str字符串的有效长度
#做一个t2次的循环,不断存字节使(reversed_str+$t2-i-1)=i(nospace_str)
add$t1,$t1,$t2
addi$t1,$t1,-1
li$t3,0
loop:
#循环,直到到达有效长度
beq$t3,$t2,Retype
add$t4,$t3,$t0
lb$t5,($t4)
sub$t6,$t1,$t3
sb$t5,($t6)
addi$t3,1
jloop
Retype:
#打印reversed_str的一行,并请求重新输入
li$v0,4004
li$a0,1
la$a1,reversedstr
li$a2,17
syscall
li$v0,4004
li$a0,1
la$a1,reversed_str
li$a2,100
syscall
li$v0,4004
li$a0,1
la$a1,endl
li$a2,1
syscall
li$v0,4004
li$a0,1
la$a1,retype
li$a2,8
syscall
#再次获取输入
li$a0,0
la$a1,origin_str
li$a2,900
li$v0,4003
syscall
la$t0,origin_str
li$t1,0
li$t2,10#代表字符'\n’
getlen:
#获取新字符串长度
lb$t3,($t0)
beq$t2,$t3,length_equal#到达换行符时停止
add$t1,$t1,1
add$t0,$t0,1
jgetlen
length_equal:
#判断长度是否相等
la$t0,num_let
lw$t2,($t0)
la$t0,num_dig
lw$t3,($t0)
add$t2,$t2,$t3
bne$t1,$t2,not_equal#不相等则跳转到not_equal
la$t0,origin_str
la$t1,reversed_str
li$t3,0
if_equal:
#长度相等则判断字符是否相等
beq$t2,$t3,equal#都相等就跳转到equal
lb$t4,($t0)
lb$t5,($t1)
bne$t4,$t5,not_equal
add$t0,$t0,1
add$t1,$t1,1
add$t3,$t3,1
jif_equal
not_equal:
#输
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 组成 原理 汇编语言 程序设计