好的,有一些错误。我注释了源代码并添加了“BUG:”来高亮显示它们。然后,我创建了清理和纠正版本
这是你的原码 - 无bug修复,只是注释[请原谅无偿风格清理]:
# int
# count(int a[], int n, int x)
# {
# int res = 0;
# int i = 0;
# int j = 0;
# int loc[n];
#
# for (i = 0; i != n; i++) {
# if (a[i] == x) {
# res = res + 1;
# loc[j] = i;
# j = j + 1;
# }
# }
#
# return res, loc;
# }
.data
a: .word 5,6,7,8,9,10
n: .word
x: .word
res: .word 0
i: .word 0
jj: .word 0
loc: .space 40
nl: .asciiz "\n"
.text
.globl main
main:
la $s0,a
lw $s1,res
lw $s2,x
lw $t0,i
lw $t1,jj
lw $t2,n
la $s3,loc
li $t4,6 # BUG: extraneous (gets trashed below)
start:
sll $t3,$t0,2 # get i << 2
add $t5,$t3,$s0 # get &a[i]
lw $t4,0($t5) # fetch it
# BUG: we're comparing a[i] against i but we want to compare against x
# _and_ we want to flip the sense of the branch
beq $t0,$t4,start # is it a match? if yes, loop
addi $t0,$t0,1 # increment i
beq $t0,$t2,exit # i == n? if no, loop. if yes, exit
# BUG: the indexing here is wrong
addi $s1,$s1,1 # j += 1
sll $t7,$t1,2 # get jj << j
add $t6,$s3,$t7 # &loc[jj << j] (BUG: we want &loc[j])
sw $t0,0($t6) # set it to i
addi $t1,$t1,1 # jj += 1
# BUG: we should loop here and _not_ fall through
exit:
# print j (with newline)
li $v0,1
add $a0,$s1,$zero
syscall
li $v0,4
la $a0,nl
syscall
# print _address_ of loc[0]
# BUG: if we care to print anything, we should print the _values_ of the
# whole array
li $v0,1
# BUG: this should be a0 and _not_ a1
###add $a1,$s3,$zero
add $a0,$s3,$zero
syscall
li $v0,4
la $a0,nl
syscall
li $v0,10 # exit program
syscall
这里的清洁并修正版本。我不得不做一些重组和简化工作,所以它起初看起来有点“外星人”。不过,我尽量保留您的注册使用情况。
我还增加了a
阵列的尺寸,并增加了用户提示用于x
值:
# int
# count(int a[], int n, int x)
# {
# int i = 0;
# int j = 0;
# int loc[n];
#
# for (i = 0; i != n; i++) {
# if (a[i] == x) {
# loc[j] = i;
# j += 1;
# }
# }
#
# return j, loc;
# }
.data
a: .word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
ae:
loc: .space 1000
prompt: .asciiz "Enter x value: "
msgnl: .asciiz "\n"
msgj: .asciiz "j: "
msgloc: .asciiz "loc: "
.text
# main -- main program
#
# RETURNS [sort of as this is a main program]:
# s1 -- j value (count of elements in "loc")
# loc -- filled in indexes into "a" array of matches to x
#
# registers:
# s0 -- a (base address of "a" array)
# t2 -- n (number of elements in "a" array)
#
# s2 -- x (value to match)
# t0 -- i (current index into "a" array)
# s3 -- loc (base address of "loc" array)
# s1 -- j (current index into "loc" array)
#
# t6 -- quick temporary [reusable]
# t7 -- used in array offset/index calculations [reusable]
.globl main
main:
# prompt for x value
li $v0,4 # syscall: print string
la $a0,prompt
syscall
# read in x value
li $v0,5 # syscall: read integer
syscall
move $s2,$v0
# get address of "a" array and compute length
la $s0,a # get &a[0]
la $t2,ae # get address of &a[n]
sub $t2,$t2,$s0 # get number of bytes in a
srl $t2,$t2,2 # get number of words in a (i.e. n)
li $t0,0 # i = 0
li $s1,0 # j = 0
la $s3,loc # base address of loc array
# main matching loop
loop:
sll $t7,$t0,2 # get i << 2
add $t7,$t7,$s0 # get &a[i]
lw $t6,0($t7) # fetch from it
bne $t6,$s2,next # a[i] == x? if no, advance to next element
# add new "i" value to loc array
sll $t7,$s1,2 # get j << 2
add $t7,$s3,$t7 # &loc[j << 2]
sw $t0,0($t7) # store i into loc
addi $s1,$s1,1 # j += 1
next:
addi $t0,$t0,1 # i += 1
blt $t0,$t2,loop # i < n? if yes, loop (or, we're done)
# done with calculation/fill loop
done:
la $s6,msgj # get prefix string
move $s7,$s1 # get j
jal prtnum # pretty print the number
blez $s1,exit # bug out if _no_ values in loc
# prepare to print all values of loc
la $t6,loc # base address of "loc"
li $t7,0 # initial index
# loop and print all values of loc
prtlocloop:
la $s6,msgloc # prefix string
lw $s7,($t6) # get loc[...]
jal prtnum # pretty print the number
add $t6,$t6,4 # increment address
add $t7,$t7,1 # increment index
blt $t7,$s1,prtlocloop # done? if no, loop
exit:
li $v0,10 # exit program
syscall
# prtnum -- print a number with a prefix string on a single line
#
# arguments:
# s6 -- prefix string
# s7 -- value to print
#
# registers:
# v0 -- syscall number [trashed]
# a0 -- syscall argument [trashed]
prtnum:
li $v0,4 # syscall: print string
move $a0,$s6 # string to print
syscall
li $v0,1 # syscall: print integer
move $a0,$s7 # value to print
syscall
li $v0,4 # syscall: print string
la $a0,msgnl
syscall
jr $ra # return
UPDATE:
究竟是什么print
之间的差和prtnum
?
print
是打印loc
中的值的循环顶部的标签。 prtnum
是子程序/函数,用于打印单个的号码。
我加了prtnum
来演示函数的使用并避免一些代码的不必要的复制。
它们不能被正确合并吗?
当然,有一些注意事项。我做了一些轻微/美化的编辑,试图让事情更清楚。特别是,我将print:
更名为prtlocloop:
,试图使其作用更加清晰。
的syscall(1)
为“打印整数”只是打印整数,但确实不添加任何空格或换行符将它们分开(即它究竟像printf("%d",a0)
)。所以,我们需要东西。
最初,我只有syscall(print_integer)
。与此同时,我们得到一个“非常长”号码。然后,我添加了syscall(4)
以打印换行符。这很好,除了输出有点混淆,哪个值是j
,哪个值是loc
值。
(1)所以,我添加了“前缀”字符串。所以,这成为每个数字的三个系统调用。
(2)这地方使用:要打印j
和打印loc
值。
在两个或更多地方使用相同的代码。这是任何语言的“拆分代码到功能”的标准标准。这是一个设计/风格的选择[所以没有绝对的答案]。 (1)和(2),我将它移动到prtnum
函数。实际上,我写了prtnum
函数第一个,因为我已经知道了结构,并在输出“看上去很难看”之后在前面添加了前缀参数。
当我第一次对它进行编码时,我使用"j: "
作为j
,并且使用了的" "
前缀。它仍然看起来有点时髦。所以,我将前缀改为"loc: "
以保持一致。
是否可以内联?当然。但是,除了打印号码本身之外,我们还需要添加分隔符。所以,我们需要两个系统调用每个号码来做到这一点。
如果我们希望将所有数字放在同一输出行上,分隔符可以是一个空格。对于短载体很好。这需要对代码进行细微更改,因为它现在存在,我们必须添加换行符的最终输出来关闭该行。对于更长的数组[可能不适合在单行上],每行一个[可能]更整齐。
我们只需要打印j
和loc
。如果问题表明我们不得不打印a
,然后j
,然后loc
,我会走另一条路。
我会将prtlocloop
更改为另一个函数(例如prtarray
),它将在给定数组上循环,并为每个元素调用prtnum
。
第一步是让计算循环正确。第二个是印刷。但是,有时候,他们必须一起完成。 (即)如何调试你看不到的东西?
因此,如果计算正确,您可以自由地以任何方式重新编码输出打印。 prtnum
只是我的的方式。但是,它是由没有意味着唯一的方法。
除了使用asm指令的基本机制之外,选择和其他任何语言一样[特别是C]。评论一下,选择最简单和最有效的方法来构建/拆分代码,使用描述性变量名称等。评论应该显示“意图”,“什么/为什么”。 asm指令是“如何”。
旁注:一些有机磷农药有了解如何sll
[你已经明白]工作了严重的困难。他们只是没有“得到”左移2乘以4而将索引值转换为字节/地址偏移的事实。所以,你可能已经提前出局......
昨天,我给了,我去的其他方式,并建议内联两种功能的MIPS问题的答案。问题是计算sin(x)
使用形式的泰勒级数展开[求和项]:x**(2n)/factorial(2n-1)
。
使用内联,有可能重新使用系列中前一项的部分结果,而无需必须重新从头开始重新计算每个项。这对于多个功能来说不会[方便]可能。
我没有写mips代码,但是我写了C /伪代码:mips program to calculate sin(x)由此产生的mips代码会[可能]更简单,肯定会运行得更快。
'INT LOC [];'在C代码是没有意义的。 – EOF
'return res,loc;'很好,纯粹*技术上*它是有效的C - 但它没有明确的目的。这条线应该做什么? – usr2564301
@RadLexus在MIPS asm中,即使使用标准约定,也可以返回_two_值(在'v0'和'v1'中)。使用内部约定,任何fnc都可以将尽可能多的“返回”值存入所选择的寄存器中。这里的C,更像是对所提出的ASM –