2016-04-03 201 views
1

目前,我正在学习MIPS大会,我尝试下面的C函数转换成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 

任何帮助,指针或建议将是非常赞赏。

编辑:我修改了我的代码,现在收到0为res返回和“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

'INT LOC [];'在C代码是没有意义的。 – EOF

+1

'return res,loc;'很好,纯粹*技术上*它是有效的C - 但它没有明确的目的。这条线应该做什么? – usr2564301

+1

@RadLexus在MIPS asm中,即使使用标准约定,也可以返回_two_值(在'v0'和'v1'中)。使用内部约定,任何fnc都可以将尽可能多的“返回”值存入所选择的寄存器中。这里的C,更像是对所提出的ASM –

回答

4

好的,有一些错误。我注释了源代码并添加了“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: "以保持一致。

是否可以内联?当然。但是,除了打印号码本身之外,我们还需要添加分隔符。所以,我们需要两个系统调用每个号码来做到这一点。

如果我们希望将所有数字放在同一输出行上,分隔符可以是一个空格。对于短载体很好。这需要对代码进行细微更改,因为它现在存在,我们必须添加换行符的最终输出来关闭该行。对于更长的数组[可能不适合在单行上],每行一个[可能]更整齐。

我们只需要打印jloc。如果问题表明我们不得不打印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代码会[可能]更简单,肯定会运行得更快。