我目前正在学习MIPS汇编,我正在尝试将以下C函数转换为MIPS汇编:
int count (int a[], int n, int x)
{
int res = 0;
int i = 0;
int j = 0;
int loc[];
for(i = 0; i != n; i++)
if(a[i] == x)
{
res = res + 1;
loc [j] = i;
j = j + 1;
}
return res, loc;
}
我已经成功转换了大部分内容,我相信我已成功返回res(值为1),虽然我不确定返回loc(我也得到值为1,并且我不认为这是对的)。但是,我在使用这个程序时遇到了困难,我不确定如何确保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
.text
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
start:
sll $t3, $t0, 2
add $t5, $t3, $s0
lw $t4, 0($t5)
beq $t0, $t4, start
addi $t0, $t0, 1
beq $t0, $t2, exit
addi $s1, $s1, 1
sll $t7, $t1, 2
add $t6, $s3, $t7
sw $t0, 0($t6)
addi $t1, $t1, 1
exit:
li $v0, 1
add $a0, $s1, $zero
syscall
li $v0, 1
add $a1, $s3, $zero
syscall
非常感谢任何帮助,指示或建议。
编辑:我修改了我的代码,现在收到res
返回0和" 268501028"为loc
。不知道这个号码的来源。
.data
a: .word 5,6,7,8,9,10
n: .word #n
x: .word #x
res: .word 0
i: .word 0
jj: .word 0
loc: .space 40
.text
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
start:
beq $t0, $t2, exit #for(i = 0; i != n; i++)
bne $s0, $s2, else #if(a[i] == x)
j start
else:
addi $s1, $s1, 1 #res = res + 1;
sw $t0, ($t1) #loc [j] = i;
addi $t1, $t1, 1 #j = j+1
addi $t0, $t0, 1 #Increment i
addi $s3, $s3, 4 #Setting next element for loc
addi $s0, $s0, 4 #Setting next element for a
j start
exit:
li $v0, 1
move $a0, $s1
syscall
li $v0, 1
move $a0, $s3
syscall
答案 0 :(得分:4)
好的,有一些错误。我已经注释了源代码并添加了#B; 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
这里是已清理和更正的版本。我不得不做一些重组和简化以使其工作,所以它可能看起来有点&#34;外星人&#34;首先。但是,我尽可能保留您的注册用法。
我还增加了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
<强>更新强>
prtnum
之间究竟有什么区别?
print
是循环顶部的标签,用于打印loc
中的值。 prtnum
是子例程/函数,用于打印单个号码。
我添加了prtnum
来演示函数的使用,并避免不必要地复制某些代码。
他们不能正确合并吗?
当然,有一些警告。我做了一些轻微的/化妆品编辑,试图让事情变得更清晰。特别是,我将print:
重命名为prtlocloop:
,以使其角色更加清晰。
syscall(1)
for&#34; print integer&#34;只打印整数,但不添加任何空格或换行符来分隔它们(即它正好,如printf("%d",a0)
)。所以,我们需要某些东西。
最初,我刚才有syscall(print_integer)
。有了这个,我们得到一个&#34;非常长的&#34; 号码。然后,我添加了syscall(4)
来打印换行符。这很好,除了输出有点混淆,哪个值是j
,哪个是loc
值。
(1)所以,我添加了&#34;前缀&#34;串。因此,每个号码都会变成三个系统调用。
(2)这在两个位置使用:打印j
和以打印loc
值。
两个或多个地方的相同代码。这是&#34;将代码拆分为功能&#34;的标准标准。在任何语言中。这是一个设计/风格选择[所以没有绝对的答案]。
因此,在(1)和(2)中,我将其移至prtnum
函数。实际上,我首先编写了prtnum
函数 ,因为我已经知道了结构,并在输出后添加了前缀参数&#34;看起来很丑陋&#34; [对我]。
当我第一次对其进行编码时,我使用"j: "
作为j
,并为" "
使用loc
前缀。它看起来仍然有点时髦。因此,我将前缀更改为"loc: "
以保持一致。
可以内联吗?当然。但是,除了打印数字本身,我们仍然需要添加分离器。因此,我们需要每个数字两个系统调用来执行此操作。
如果我们想将所有数字放在同一输出线上,则分离器可以是空格。很好的短矢量。这需要稍微改变现在存在的代码,我们必须添加换行的最终输出以关闭该行。对于较长的阵列[可能不适合单行],每行一个[可能]更整洁。
我们只需要打印j
和loc
。如果问题表明我们必须打印a
,然后j
,然后打印loc
,我就会采取相反的方式。
我会将prtlocloop
更改为另一个函数(例如prtarray
),它将在给定数组上循环并为每个元素调用prtnum
。
第一步是让计算循环正确。第二个是印刷。但是,有时,它们必须一起完成。 (即)你如何调试你无法看到的东西?
因此,如果计算正确,您可以以您选择的任何方式自由重新编码输出打印。 prtnum
只是我的方式。但是,它是没有意味着唯一的方式。
除了使用asm指令的基本机制之外,选择与任何其他语言一样[特别是C]。好的评论,选择最简单,最有效的方法来构建/拆分代码,使用描述性变量名称等。评论应该显示&#34; intent&#34;,&#34; what / why&#34;。 asm指令是&#34; how&#34;。
旁注:有些OP很难理解{<1}} [你已经了解]的工作原理。他们只是没有&#34;得到&#34;左移2乘以4乘以并将索引值转换为字节/地址偏移的事实。所以,你可能已经领先于游戏......
昨天,我给出了一个mips问题的答案,我走了另一条路,建议内联两个函数。问题是使用形式为sll
的泰勒级数展开[项的总和]来计算sin(x)
。
使用内联,可以重复使用系列中上一个术语的部分结果,而不必从头开始重新计算每个术语。对于多种功能而言,[方便]这是不可能的。
我没有编写mips代码,但我编写了C /伪代码:mips program to calculate sin(x)生成的mips代码[可能]会更简单,并且肯定会运行得更快。