我已经修复了你的代码。我试图尽可能地忠实于它,但是,我不得不进行大量的重组。
有几点需要注意。
我创建了函数(根据问题陈述)。也就是说,我不是等价的 long main
,而是将它们分开,就像你在 C 中所做的那样。我为每个函数添加了块注释。
在main
中,我将数组计数$s0
和数组基地址加载到$s1
. 计算函数根据这些设置它们的值,而不是复制代码。(ie) 如果需要,可以在一处设置/更改阵列地址和计数。
我更改了一些侧边栏评论,使其更能描述意图,而不是仅仅重申他们所使用的指令的机制。
我还更改了标签,因此更容易将它们与它们所在的函数匹配(例如,函数中的所有标签foo
都是foo_blah
)
我创建了静态测试数据以加快测试速度。请注意注释掉jal dataread
以实际提示用户。
这是更正后的代码:
.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
这是一个更紧凑的变体,它使用了某种技巧。它使用等效的“尾调用优化”来拥有一个通用的打印例程,而不是在每个计算函数中复制打印代码。
也就是说,“技巧”是计算函数为打印设置参数,然后通过[而不是第二级]跳转到它,并且打印函数执行通常由计算函数完成的操作。j
jal
jr $ra
无论如何,这是代码:
.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 程序:
// 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/
在大多数情况下,我都使用过并且更喜欢mars
--YMMV