assembly 我应该如何修改这个RISC-V代码来生成一个中间行宽度为N的对称菱形?

eqfvzcg8  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(92)

我被要求编写一个RISC-V汇编代码,以生成一个由菱形组成的对称菱形,其中间行宽度为N。N是用户输入的奇数。
例如:在终端输入5,结果应该是:

*
 ***
*****
 ***
  *

字符串
由于我是一个初学者,在使用RISC-V方面相对缺乏经验,我无法完全完成这一点。
我在RARS中编写和测试的是:

# CONST
.eqv SYSTEM_EXIT, 93
.eqv SYSTEM_READ, 63
.eqv SYSTEM_WRITE, 64
.eqv STDIN, 0
.eqv STDOUT, 1

# DATA
.data

space:
    .asciz " "
asterisk:
    .asciz "*"
newline:
    .asciz "\n"
in_buffer:
    .space 16

# TEXT
.text
.global _start

_start:

    li a0, STDIN
    la a1, in_buffer
    li a2, 16
    li a7, SYSTEM_READ
    ecall

    la a1, in_buffer
    li t0, 0
    li t1, 10

convert_input:

    lbu t2, 0(a1)
    beqz t2, input_done
    beq t2, t1, input_done
    sb t2, 0(a1)
    addi t2, t2, -48
    mul t0, t0, t1
    add t0, t0, t2
    addi a1, a1, 1
    j convert_input

input_done:

    andi t3, t0, 1
    beqz t3, not_odd

    li t4, 0
    li t5, 0

diamond_outer_loop:

    bge t4, t0, end_pattern

    li t6, 0

print_spaces_before_asterisks:

    blt t5, t0, check_asterisks
    j next_row

check_asterisks:

    bge t5, t6, print_asterisks
    j inc_space

print_asterisks:

    li a0, STDOUT
    li a2, 1
    la a1, asterisk
    li a7, SYSTEM_WRITE
    ecall

    addi t6, t6, 2
    j next_asterisk

inc_space:

    li a0, STDOUT
    li a2, 1
    la a1, space
    li a7, SYSTEM_WRITE
    ecall

    addi t5, t5, 1
    j print_spaces_before_asterisks

next_asterisk:

    li a0, STDOUT
    li a2, 1
    la a1, newline
    li a7, SYSTEM_WRITE
    ecall

    addi t4, t4, 1
    addi t5, t5, -1
    j diamond_outer_loop

next_row:

    li a0, STDOUT
    li a2, 1
    la a1, newline
    li a7, SYSTEM_WRITE
    ecall

    addi t5, t5, 2
    j diamond_outer_loop

not_odd:

    addi t0, t0, -1
    
end_pattern:

    li a0, 0
    li a7, SYSTEM_EXIT
    ecall


这个程序产生的结果,例如输入5是:

*
 *
 *
 *
 *


它根据输入的数字正确地改变大小(例如,如果输入7,则为7行),但星星的数量始终为1,并且格式不正确。

vs91vp4v

vs91vp4v1#

首先,你需要一个可以工作的算法。如果你已经有了它(比如在你的脑海里,或者用C语言,或者你很熟悉的语言),那么你需要调试它。调试的方法是单步调试,观察它在每条指令上做了什么。由于输出立即出错(它应该先打印一些空格),你马上就有东西可以调试了。
在做汇编版本之前,最好有一个使用C或你熟悉的语言的算法。(换句话说,你不必用汇编语言来开发算法。)一旦你有了算法,如果你已经知道代码应该做什么,那么汇编语言会简单得多(您需要的变量和控制流)。
如果你把一个可以工作的C代码转录成汇编语言,那么你就会知道任何错误都是汇编翻译问题,而不是算法问题,这些问题更容易调试。
当你有一个C或其他语言的算法时,你就有了一些东西可以在调试过程中进行比较,它会告诉你汇编代码到底哪里出错了。C和汇编程序都是单步执行,你会看到汇编程序哪里出错了。
你可能认为你不需要一个C版本,但让我们注意到,这将是一个3-5行的代码,它实际上是强制性的,你必须取得进展。
我建议让它在C中工作,然后把它带到C中的“if-goto-label”风格。
例如,像这样的嵌套for循环(用于打印一个简单的方阵):

for ( i = 0; i < 5; i++ ) {
    for ( j = 0; j < 5; j++ ) {
        print ( "*" );
    }
    print ( "\n" );
}
...

字符串
仍然可以在C中转换为if-goto-label:

i = 0;
Loop1:
    if ( i >= 5 ) goto EndLoop1;
    j = 0;

Loop2:
    if ( j >= 5 ) goto EndLoop2;
    print ( "*" );
    j++;
    goto Loop2;
EndLoop2:

    i++;
    goto Loop1;
EndLoop1:
    ...


这是一个简单的嵌套for循环例子中使用的控制结构的精确转录。这个转换将运行与for循环版本相同。
正确地翻译控件结构需要一些工作,因为汇编语言会允许许多无用或错误的东西。:但请放心,每个控制流结构(if-then-else,for/while,顺序语句,嵌套语句)都有一个简单的if-goto-label模式。遵循正确的模式,汇编中的控制流将与C版本一样运行。
(It在这里,尝试在转换到汇编过程中优化某些东西是很容易的,但是要抵制这种冲动,使用简单的模式,即使它们看起来是可优化的。我的偏好是首先对C if-goto-label代码应用优化,然后如果有效,将其带到汇编。)

相关问题