关于编写汇编以调用数组上的函数的MIPS问题 [英] MIPS questions about writing assembly to call functions on an array
问题描述
我目前正在上汇编课程,并且在执行以下作业时遇到麻烦.
I currently am taking a course in assembly and am having trouble with the following assignment.
编写一个程序(在适当的提示下)读取20个整数的序列并将其存储在数组中,然后调用以下三个函数并以可读格式打印结果.
Write a program that reads (with an appropriate prompt) a sequence of 20 integers and stores them in an array, and then calls the following three functions and prints the results in a readable format.
这三个功能是: smallestLargest :计算数组中的最小和最大值. 可整除:计算数组中可被4整除的整数的数量 SumProduct::计算整数之和和.
The three functions are: smallestLargest: computes the smallest and the largest values in the array. divisible: computes the number of integers in the array which are divisible by 4 SumProduct: computes the sum and the product of the integers.
我编写了汇编代码(如下)以尝试解决此问题,但是除了数组中的最大数字外,我无法获得正确的输出.其他一切都给我带来了问题.我不知道出什么问题了,过去一个半星期我一直在努力解决这个问题,因此,我们将不胜感激.
I wrote assembly code (below) to try to solve this problem but I can't get the right output except for the largest number in the array. Everything else is giving me a problem. I have no clue what's wrong, and I've been working on this for the past week and a half, so any help would be greatly appreciated.
.data
array: .space 80
newLine:.asciiz "\n" # I will use it to start a new line
space: .asciiz " " # I will use it to have a space
Prompt: .asciiz "\n Enter an integer: "
Result1:.asciiz "The smallest value in the array is "
Result2:.asciiz "The largest value in the array is "
Result3:.asciiz "The number of integers divisible by 4 is "
Result4:.asciiz "The sum of the integers is "
Result5:.asciiz "The product of the integers is "
.globl main
.text
main:
li $t0,20 # $t0 keeps track of the number of integers to be read
la $t1,array # loading the starting address of an array
loopQ:
la $a0,Prompt
li $v0,4
syscall
li $v0,5 # reading an integer
syscall
sw $v0,0($t1) # storing the integer entered
add $t0,$t0,-1 # decrement the number of integers by one
add $t1,$t1,4 # load the address of the next integer
bgtz $t0,loopQ # branch to read and store the next integer
li $t0,20
la $t1,array
smallestLargest:
lw $v0,0($t1) # $v0 = Mem($t1)
move $v1,$v0 # $v1 = $v0
addi $t0,$t0,-1 # decrement $t0
blez $t0,ret1 # while ($t0 > 0)
loopR:
addi $t1,$t1,4
lw $t2,0($t1) # load $t1 to $t2
bge $t2,$v0,next# if ($t2 < $v0)
move $v0,$t2 # $v0 = $t2
b chk
next:
ble $t2,$v1,chk # if ($t2 > $v1)
move $v1,$t2 # $v1 = $t2
chk:
addi $t0,$t0,-1 # decrement t0
bgtz $t0,loopR
ret1:
li $v0,4 # system call code for print_str
la $a0,Result1 # load address of Result1 into $a0
syscall
move $a0,$v0 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
li $v0,4 # system call code for print_str
la $a0,Result2 # load address of Result2 into $a0
syscall
move $a0,$v1 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
li $t0,20 # initialize length parameter
la $t1,array # initialize address parameter
Div4:
li $v0,0 # $v0 = 0
li $t3,3 # $t3 = 3
b skip
loopS:
lw $t2,0($t1) # $t2 = Mem($t1)
addi $t1,$t1,4 # $t1 = $t1 + 4
and $t4,$t2,$t3 # $t4 = $t2 & $t3
bnez $t4,skip # if ($t4 == 0)
addi $v0,$v0,1 # $v0 = $v0 + 1
skip:
addi $t0,$t0,-1 # $t0 = $t0 - 1
bgez $t0,loopS # if $t0 > 0
ret2:
li $v0,4 # system call code for print_str
la $a0,Result3 # load address of Result3 into $a0
syscall
move $a0,$v0 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
SumAMult:
la $a0,newLine # start a new line
li $v0,4
syscall
li $v0,4 # system call code for print_str
la $a0,Result4 # load address of Result4 into $a0
syscall
li $t0,20 # initialize length parameter
la $t1,array # initialize address parameter
jal sum # call sum
move $t1,$v0 # move value to be printed to $t1
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
li $v0,4 # system call code for print_str
la $a0,Result5 # load address of Result5 into $a0
syscall
li $v0,1 # system call code for print_int
move $t1,$v1 # move value to be printed from $v1
syscall
li $v0,10
syscall
sum:
li $v0,0 # $v0 will hold the sum
li $v1,0 # $v1 will hold the product
loopT:
blez $t0, retzz # If t0 <= branch
addi $t0,$t0,-1 # decrement loop count
lw $t5,0($t1) # get a value from the array
addi $t1,$t1,4 # increment array pointer
word:
add $v0,$v0,$t5 # add to sum
# mult $v1,$t5 # multiply to product
b loopT # branch to loopT
retzz:
jr $ra
下面是输入整数1-20后得到的输出
Below is the output I am getting after entering integers 1-20
The smallest value in the array is 4
The largest value in the array is 20
The number of integers divisible by 4 is 4
The sum of the integers is 268501210
The product of the integers is 268501238
推荐答案
我已经修复了您的代码.我试图尽可能忠实于此,但是,我必须进行大量的重组.
I've fixed your code. I tried to remain faithful to it where possible, but, I had to do considerable restructuring.
一些注意事项.
我创建了函数(根据问题陈述).也就是说,就像您在C语言中一样,我将内容拆分成一个长main
,而不是等效.我为每个函数添加了块注释.
I created functions (per the problem statement). That is, instead of the equivalent of one long main
, I split things up, just like you'd do in C. I added block comments for each function.
在main
中,我将数组计数加载到$s0
中,并将数组基地址加载到$s1
中.计算功能从这些功能中设置其值,而不是复制代码. (即)如果需要,可以在一个位置设置/更改阵列地址和计数.
In main
, I loaded the array count into $s0
and the array base address into $s1
. The calculation functions set up their values from these rather than replicating the code. (i.e.) The array address and count can be set up/changed in one place, if desired.
我更改了一些侧边栏注释,以便更能说明意图,而不仅仅是重述所执行指令的机制.
I changed some of the sidebar comments to be more descriptive of intent instead of merely restating the mechanics of the instruction they're on.
我还更改了标签,以便更轻松地将其与它们所在的功能匹配(例如,功能foo
中的所有标签均为foo_blah
)
I also changed the labels so it was easier to match them to the functions they were in (e.g. all labels in function foo
are foo_blah
)
我创建了静态测试数据以加快测试速度.请注意,注释掉的jal dataread
会实际提示用户.
I created static test data to speed up testing. Note the commented out jal dataread
to actually prompt the user.
这是更正的代码:
.data
array: .space 80
array2: .word 3, 3, 3, 17, 3
.word 3, 24, 3, 3, 4
.word -4, -8, 97, 3, 2
.word 3, 3, 3, 3, 3
newLine: .asciiz "\n" # I will use it to start a new line
space: .asciiz " " # I will use it to have a space
Prompt: .asciiz "\n Enter an integer: "
msg_min: .asciiz "The smallest value in the array is "
msg_max: .asciiz "The largest value in the array is "
msg_div4: .asciiz "The number of integers divisible by 4 is "
msg_sum: .asciiz "The sum of the integers is "
msg_prod: .asciiz "The product of the integers is "
.globl main
.text
main:
li $s0,20 # set array count
la $s1,array2 # set array address
# NOTE: uncomment this to really prompt user (vs. testing)
###jal dataread # prompt user for data
jal minmax # compute minimum/maximum
jal div4 # count number divisible by 4
jal sumprod # compute sum and product
li $v0,10
syscall
# dataread -- prompt user for data
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
dataread:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
dataread_loop:
la $a0,Prompt
li $v0,4
syscall
li $v0,5 # reading an integer
syscall
sw $v0,0($t1) # storing the integer entered
add $t0,$t0,-1 # decrement the number of integers by one
add $t1,$t1,4 # load the address of the next integer
bgtz $t0,dataread_loop # branch to read and store the next integer
jr $ra # return
# minmax -- compute min/max
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- minimum value
# t3 -- maximum value
# t4 -- current array value
minmax:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
lw $t2,0($t1) # initialize smallest
move $t3,$t2 # initialize largest
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
minmax_loop:
blez $t0,minmax_done # at end of array? if yes, fly
lw $t4,0($t1) # fetch current array element
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
bge $t4,$t2,minmax_notlt # new minimum? if no, fly
move $t2,$t4 # yes, set it
minmax_notlt:
ble $t4,$t3,minmax_loop # new maximum? if no, loop
move $t3,$t4 # yes, set it
b minmax_loop
minmax_done:
li $v0,4 # system call code for print_str
la $a0,msg_min # message to print
syscall
move $a0,$t2 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
li $v0,4 # system call code for print_str
la $a0,msg_max # message to print
syscall
move $a0,$t3 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
jr $ra # return
# div4 -- get number of integers divisible by 4
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- count of array elements divisible by 4
# t4 -- current array value
div4:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
li $t2,0 # initialize count
div4_loop:
blez $t0,div4_done # at end of array? if yes, fly
lw $t4,0($t1) # fetch current array value
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
andi $t4,$t4,0x03 # divisible by 4?
bnez $t4,div4_loop # no, loop
addi $t2,$t2,1 # yes, increment count
b div4_loop # loop
div4_done:
li $v0,4 # system call code for print_str
la $a0,msg_div4 # message to print
syscall
move $a0,$t2 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
jr $ra
# sumprod -- compute sum and product
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- summation value
# t3 -- product value
# t4 -- current array value
sumprod:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
li $t2,0 # initialize sum
li $t3,1 # initialize product
sumprod_loop:
blez $t0,sumprod_done # at end of array? if yes, fly
lw $t4,0($t1) # fetch current array value
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
add $t2,$t2,$t4 # compute the sum
mul $t3,$t3,$t4 # compute the product
b sumprod_loop
sumprod_done:
li $v0,4 # system call code for print_str
la $a0,msg_sum # message to print
syscall
move $a0,$t2 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
li $v0,4 # system call code for print_str
la $a0,msg_prod # message to print
syscall
move $a0,$t3 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
jr $ra # return
这是一个更紧凑的变体,它使用了各种技巧.它使用等效于尾部调用优化"的方法来拥有通用的打印例程,而不是在每个计算函数中复制打印代码.
Here's a more compact variation that uses a trick of sorts. It uses the equivalent of "tail call optimization" to have a common print routine instead of replicating the printing code in each calculation function.
也就是说,技巧"是计算函数,它为打印设置参数,然后通过j
跳转到 [而不是进行第二级jal
]和打印函数执行通常由计算功能完成的jr $ra
.
That is, the "trick" is the calculation functions set up arguments for the print and then jump to it via j
[instead of doing a second level jal
] and the print function does the jr $ra
that would normally be done by the calculation functions.
无论如何,这是代码:
.data
array: .space 80
array2: .word 3, 3, 3, 17, 3
.word 3, 24, 3, 3, 4
.word -4, -8, 97, 3, 2
.word 3, 3, 3, 3, 3
newLine: .asciiz "\n" # I will use it to start a new line
space: .asciiz " " # I will use it to have a space
Prompt: .asciiz "\n Enter an integer: "
msg_min: .asciiz "The smallest value in the array is "
msg_max: .asciiz "The largest value in the array is "
msg_div4: .asciiz "The number of integers divisible by 4 is "
msg_sum: .asciiz "The sum of the integers is "
msg_prod: .asciiz "The product of the integers is "
.globl main
.text
main:
li $s0,20 # set array count
la $s1,array2 # set array address
# NOTE: uncomment this to really prompt user (vs. testing)
###jal dataread # prompt user for data
jal minmax # compute minimum/maximum
jal div4 # count number divisible by 4
jal sumprod # compute sum and product
li $v0,10
syscall
# dataread -- prompt user for data
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
dataread:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
dataread_loop:
la $a0,Prompt
li $v0,4
syscall
li $v0,5 # reading an integer
syscall
sw $v0,0($t1) # storing the integer entered
add $t0,$t0,-1 # decrement the number of integers by one
add $t1,$t1,4 # load the address of the next integer
bgtz $t0,dataread_loop # branch to read and store the next integer
jr $ra # return
# minmax -- compute min/max
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- minimum value
# t3 -- maximum value
# t4 -- current array value
minmax:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
lw $t2,0($t1) # initialize smallest
move $t3,$t2 # initialize largest
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
minmax_loop:
blez $t0,minmax_done # at end of array? if yes, fly
lw $t4,0($t1) # $v0 = Mem($t1)
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
bge $t4,$t2,minmax_notlt # new minimum? if no, fly
move $t2,$t4 # yes, set it
minmax_notlt:
ble $t4,$t3,minmax_loop # new maximum? if no, loop
move $t3,$t4 # yes, set it
b minmax_loop
minmax_done:
la $a2,msg_min # first message
la $a3,msg_max # second message
j print
# div4 -- get number of integers divisible by 4
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- count of array elements divisible by 4
# t4 -- current array value
div4:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
li $t2,0 # initialize count
div4_loop:
blez $t0,div4_done # at end of array? if yes, fly
lw $t4,0($t1) # fetch current array value
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
andi $t4,$t4,0x03 # divisible by 4?
bnez $t4,div4_loop # no, loop
addi $t2,$t2,1 # yes, increment count
b div4_loop # loop
div4_done:
la $a2,msg_div4 # first message
li $a3,0 # _no_ second message
j print
# sumprod -- compute sum and product
#
# registers:
# t0 -- remaining count
# t1 -- array address pointer
# t2 -- summation value
# t3 -- product value
# t4 -- current array value
sumprod:
move $t0,$s0 # initialize array count
move $t1,$s1 # initialize array pointer
li $t2,0 # initialize sum
li $t3,1 # initialize product
sumprod_loop:
blez $t0,sumprod_done # at end of array? if yes, fly
lw $t4,0($t1) # fetch current array value
add $t1,$t1,4 # load the address of the next integer
addi $t0,$t0,-1 # decrement remaining count
add $t2,$t2,$t4 # compute the sum
mul $t3,$t3,$t4 # compute the product
b sumprod_loop
sumprod_done:
la $a2,msg_sum # first message
la $a3,msg_prod # second message
j print
# print -- common print function
#
# arguments:
# a2 -- first message
# t2 -- first value
# a3 -- second message
# t3 -- second value
print:
beqz $a2,print_skip1 # skip if no first argument
li $v0,4 # system call code for print_str
move $a0,$a2 # get address of first message
syscall
move $a0,$t2 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
print_skip1:
beqz $a3,print_skip2 # skip if no second argument
li $v0,4 # system call code for print_str
move $a0,$a3 # get address of second message
syscall
move $a0,$t3 # move value to be printed to $a0
li $v0,1 # system call code for print_int
syscall
la $a0,newLine # start a new line
li $v0,4
syscall
print_skip2:
jr $ra # return
这是我用于比较测试和验证的C程序:
Here's a C program that I used for comparison testing and validation:
// mipsmmdsp/mipsmmdsp -- check validity of mask for divisibility
#include <stdio.h>
#include <stdlib.h>
int array2[20] = {
3,3,3,17,3,
3,24,3,3,4,
-4,-8,97,3,2,
3,3,3,3,3
};
// sumprod -- calculate sum and product
void
sumprod(void)
{
int idx;
int val;
int sum;
int prod;
int div4;
int min;
int max;
sum = 0;
prod = 1;
div4 = 0;
min = array2[0];
max = array2[0];
for (idx = 0; idx < 20; ++idx) {
val = array2[idx];
if (val < min)
min = val;
if (val > max)
max = val;
if ((val % 4) == 0)
++div4;
sum += val;
prod *= val;
}
printf("min=%d max=%d div4=%d sum=%d prod=%d\n",min,max,div4,sum,prod);
}
// modcheck -- check validity of mod mask
void
modcheck(void)
{
int lo;
int hi;
int val;
int mskflg;
int modflg;
long long cnt;
lo = -100;
hi = 100;
lo = -2000000000;
hi = 2000000000;
cnt = 0;
for (val = lo; val <= hi; ++val, ++cnt) {
mskflg = ((val & 0x03) == 0);
modflg = ((val % 4) == 0);
#if 0
printf("modcheck: %4d/%8.8X: mskflg=%d modflg=%d\n",
$val,$val,$mskflg,$modflg);
#endif
if (mskflg != modflg) {
printf("modcheck: FAIL %4d/%8.8X: mskflg=%d modflg=%d\n",
val,val,mskflg,modflg);
exit(1);
}
}
printf("modcheck: cnt=%lld\n",cnt);
}
// main -- main program
int
main(void)
{
modcheck();
sumprod();
return 0;
}
旁注:
除了spim
模拟器外,还有mars
模拟器.可以在这里找到: http://courses.missouristate.edu/KenVollmar/MARS/
In addition to the spim
simulator, there is the mars
simulator. It can be found here: http://courses.missouristate.edu/KenVollmar/MARS/
在大多数情况下-YMMV我都使用过并且更喜欢mars
I've used both and prefer mars
in most cases--YMMV
这篇关于关于编写汇编以调用数组上的函数的MIPS问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!