MIPS汇编程序设计
北京大学-计算机组成原理 第二讲 指令系统体系结构 互评作业
使用MARS(MIPS Assembler and Runtime Simulator)集成开发环境作为实验平台
考察MIPS汇编程序设计,要求熟悉MIPS指令系统的常见指令,掌握MARS集成开发环境基本使用方法,完成自编MIPS汇编语言程序的上机调试过程
第一题:用系统功能调用实现简单输入输出
利用系统功能调用从键盘输入,转换后在屏幕上显示,具体要求如下:
如果输入的是字母(A
Z,区分大小写)或数字(09),则将其转换成对应的英文单词后在屏幕上显示,对应关系见下表若输入的不是字母或数字,则在屏幕上输出字符
*
每输入一个字符,即时转换并在屏幕上显示
支持反复输入,直到按
?
键结束程序
A | Alpha | N | November | 1 | First | a | alpha | n | november |
B | Bravo | O | Oscar | 2 | Second | b | bravo | o | oscar |
C | China | P | Paper | 3 | Third | c | china | p | paper |
D | Delta | Q | Quebec | 4 | Fourth | d | delta | q | quebec |
E | Echo | R | Research | 5 | Fifth | e | echo | r | research |
F | Foxtrot | S | Sierra | 6 | Sixth | f | foxtrot | s | sierra |
G | Golf | T | Tango | 7 | Seventh | g | golf | t | tango |
H | Hotel | U | Uniform | 8 | Eighth | h | hotel | u | uniform |
I | India | V | Victor | 9 | Ninth | i | india | v | victor |
J | Juliet | W | Whisky | 0 | zero | j | juliet | w | whisky |
K | Kilo | X | X-ray | k | kilo | x | x-ray | ||
L | Lima | Y | Yankee | l | lima | y | yankee | ||
M | Mary | Z | Zulu | m | mary | z | zulu |
思路
由于 alphabet 中的字符串保存的时候将以\0
结尾,我又在单词后面加了一个\n
故可用=
替换这些字符,将文本保存形似 Alpha== Bravo== China
的计算字符串
以计算空格的总数量来确定每个单词开头字母的位置,从而计算出偏移量
为了算出每个单词的在数组里的位置,使用了Java编写一段用于计算偏移量的程序:
args[0]:保存计算字符串的文本的路径
public class Main {
public static void main(String[] args) throws IOException {
File f = new File(args[0]);
InputStreamReader isr = new InputStreamReader(new FileInputStream(f));
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
char[] chars = s.toCharArray();
Integer sum = 0;
System.out.println(s);
for (char c : chars) {
sum++;
if (c == ' ') System.out.print(sum - 1 + ",");
}
}
}
解答
用Java写汇编算作弊吗 ( ̄▽ ̄)
alphabetU:
.asciiz " Alpha\n"," Bravo\n"," China\n"," Delta\n"," Echo\n"," Foxtrot\n"," Golf\n"," Hotel\n",
" India\n"," Juliet\n"," Kilo\n"," Lima\n"," Mary\n"," November\n"," Oscar\n"," Paper\n"," Quebec\n",
" Research\n"," Sierra\n"," Tango\n"," Uniform\n"," Victor\n"," Whisky\n"," X-ray\n"," Yankee\n"," Zulu\n"
alphabetL:
.asciiz " alpha\n"," bravo\n"," china\n"," delta\n"," echo\n"," foxtrot\n"," golf\n"," hotel\n"," india\n",
" juliet\n"," kilo\n"," lima\n"," mary\n"," november\n"," oscar\n"," paper\n"," quebec\n"," research\n",
" sierra\n"," tango\n"," uniform\n"," victor\n"," whisky\n"," x-ray\n"," yankee\n"," zulu\n"
al_offset:
0,8,16,24,32,39,49,56,64,72,81,88,95,102,113,121,129,138,149,158,166,176,185,194,202,211
# 使用 Java 算出的偏移量
number:
.asciiz " Zero\n"," First\n"," Second\n"," Third\n"," Fourth\n"," Fifth\n"," Sixth\n"," Seventh\n"," Eighth\n"," Ninth\n"
n_offset:
0,7,15,24,32,41,49,57,67,76
exit_str: .asciiz "#Stop program#"
.globl main
main:
li $v0, 12 # $v0 contains character read
syscall
beq $v0, '?', exit # if (v0 == '?') then exit
# is symble ?
sub $t1, $v0, '0' # t1 = v0 - '0'
blt $t1, $zero, symble # if (t1 < 0) then symble
# is number ?
sub $t2, $t1, 10 # t2 = t1 - 10
blt $t2, $zero, getnum # if (t2 < 0) then getnum
# is upper case?
sub $t2, $v0, 91
slt $s3, $t2, $0 # if (v0 < 'Z') then s3 = 1
sub $t3, $v0, 64
sgt $s4, $t3, $0 # if (v0 > 'A') then s4 = 1
and $s0, $s3, $s4 # s0 = s3 && s4
bnez $s0, getuword # if (s0 == 1) then getword
# is lower case?
sub $t2, $v0, 123
slt $s3, $t2, $0 # if (v0 <= 'z') then s3 = 1
sub $t3, $v0, 96
sgt $s4, $t3, $0 # if (v0 >= 'a') then s4 = 1
and $s0, $s3, $s4 # s0 = s3 && s4
bnez $s0, getlword # if (s0 == 1) then getword
j symble
getnum:
add $t2, $t2, 10 # judge during [is number ?] 补回判断时减去的ASCII
sll $t2, $t2, 2 # every word use 1 byte (no.9 at address of 9<<2)
#
#add $a0, $t2, $zero
#li $v0, 1
#syscall
#
la $s0, n_offset # load address to s0
add $s0, $s0, $t2 # s0 = s0 + offset
lw $s1, ($s0) # Load Word at address of s0
add $a0, $0, '*' # '*' ascii
li $v0, 11
la $a0, number # load address to a0
add $a0, $a0, $s1
li $v0, 4
syscall
j main
getuword:
# a0: alphabet
# s1: offset
sub $t3, $t3, 1
sll $t3, $t3, 2
la $s0, al_offset # load address
add $s0, $s0, $t3
lw $s1, ($s0) # load word
la $a0, alphabetU # load address
add $a0, $s1, $a0
li $v0, 4 # print null-terminated string string at $a0
syscall
j main
getlword:
# a0: alphabet
# s1: offset
sub $t3, $t3, 1
sll $t3, $t3, 2
la $s0, al_offset # load address
add $s0, $s0, $t3
lw $s1, ($s0) # load word
la $a0, alphabetL # load address
add $a0, $s1, $a0
li $v0, 4 # print null-terminated string string at $a0
syscall
j main
symble:
li $v0, 11 # $a0 = char to print
add $a0, $t0, 32 # load value into argument register $a0
syscall
add $a0, $a0, 10 # 32 + 10 = '*'
syscall
sub $a0, $a0, 32 # '*' - 32 == '\n'
syscall
j main
exit:
add $a0, $0, '\n'
li $v0, 11
syscall
la $a0, exit_str
li $v0, 4
syscall
第二题:字符串查找比较
利用系统功能调用从键盘输入一个字符串,然后输入单个字符,查找该字符串中是否有该字符(区分大小写)。具体要求如下:
如果找到,则在屏幕上显示:
Success! Location: X
其中,X为该字符在字符串中第一次出现的位置
如果没找到,则在屏幕上显示:
Fail!
输入一个字符串后,可以反复输入希望查询的字符,直到按
?
键结束程序每个输入字符独占一行,输出查找结果独占一行,位置编码从1开始。
提示:为避免歧义,字符串内不包含?
符号
格式示例如下:
abcdefgh
a
Success! Location: 1
x
Fail!
思路
因为只是查找一个字符串中的一个字符,因此可以直接遍历每个字符串,进行字符匹配,具体到实现,就是高级语言中的 if-else 以及 for 所实现的功能。
解答
suces_str: .asciiz "\nSuccess! Location: "
fail_str: .asciiz "\nFail!"
buffer: 20
exit_str: .asciiz "\n#Stop program#"
str1: .asciiz "Enter string: "
str2: .asciiz "Enter char: "
.globl main
main:
# a0 = input/result string
# a1 = input string length
# a2 = input char
# a3 = loop donefail
# initialize
add $a3, $zero, $zero
add $t0, $zero, $zero # i = 0
# take string
la $a0, buffer # load byte address
li $a1, 20 # length of string
li $v0, 8 # read string at a0
syscall
takechar:
li $v0, 12 # char read to v0
syscall
beq $v0, '?', exit # if (v0 == '?') then exit
move $a2, $v0 # a2 = char
search:
# t0 = int i
beq $t0, $a1, donefail # if (i = length) then donefail
la $a0, buffer # else load byte
add $t2, $a0, $t0 # t2 = &str + offset
lb $s1, ($t2) # s1 = *t2
beq $s1, $a2, sucess # if (this.char = char) then sucess
add $t0, $t0, 1 # else i++
j search
fail:
la $a0, fail_str
li $v0, 4
syscall
li $v0, 11
add $a0, $zero, '\n'
syscall
j takechar
sucess:
la $a0, suces_str
li $v0, 4
syscall
li $v0, 1
add $a0, $t0, 1 # print index begin from 1
syscall
li $v0, 11
add $a0, $zero, '\n'
syscall
j takechar
donefail:
add $a3, $zero, 1 # flag donefail = 1
add $t0, $zero, $zero # reset int i = 0
j fail
exit:
la $a0, exit_str
li $v0, 4
syscall