コードを修正しました。可能な限り忠実であり続けようとしましたが、かなりのリストラをしなければなりませんでした。
注意すべき点がいくつかあります。
関数を作成しました(問題の説明に従って)。つまり、1 つの longmain
に相当する代わりに、C で行うのと同じように分割します。各関数にブロック コメントを追加しました。
ではmain
、配列カウントを にロードし$s0
、配列ベース アドレスをにロードしました$s1
。計算関数は、コードを複製するのではなく、これらから値を設定します。(つまり) 必要に応じて、アレイのアドレスとカウントを1か所で設定/変更できます。
サイドバーのコメントの一部を変更して、単に説明の仕組みを再度説明するのではなく、意図をより説明するようにしました。
また、ラベルを変更して、それらが含まれていた関数に一致させやすくしました(たとえば、関数内のすべてのラベルは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
これは、ある種のトリックを使用した、よりコンパクトなバリエーションです。各計算関数で印刷コードを複製する代わりに、「末尾呼び出しの最適化」に相当するものを使用して、共通の印刷ルーチンを作成します。
つまり、「トリック」は、計算関数が印刷の引数を設定し、[第2レベルを実行する代わりに]経由でそれにジャンプし、印刷関数が計算関数によって通常行われることを実行することです。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を好みます。