这些操作码有什么作用?

What do these Opcodes do?

我正在学习 Western Digital 的 RISC-V 汇编教程。我对汇编编程比较陌生。所以我有几个需要澄清的问题,而且我似乎找不到真正的虚拟友好教程。

这是有问题的代码 on GITHub

# SPDX-License-Identifier: Unlicense
# Copyright (c) 2018 Western Digital Corporation or its affiliates.

.section .text
.align 2
.globl setupGPIO

.include "memory_map.inc"
.include "gpio.inc"

setupGPIO:
    addi sp, sp, -16            # Allocate Stack Frame

    #First Question
    sw ra, 12(sp)               # Save return address onto the stack

    li t0, GPIO_CTRL_ADDR       # Load the base GPIO address
    li t1, GPIO_RGB_PINS        # Get the RGP Pins offset
    sw t1, GPIO_OUTPUT_EN(t0)   # Enable RGB pins as output pins
    sw t1, GPIO_OUTPUT_XOR(t0)  # Set the XOR to that the pins are Active High

    #Second Question
    sw x0, GPIO_OUTPUT_VAL(t0)  # Set all writable GPIO pins to zero

    #Third Question
    lw ra, 12(sp)               # Restore the return address
    addi sp, sp, 16             # Deallocate stack frame
    ret

那么,我的问题是:

  1. 12在做什么?我认为堆栈指针已经在前面的指令中移动了 16 位。我通常对为什么在内存中向下移动 16 位,然后再添加 12 位感到困惑。
    此外,此语法在 x86 中是否表示与 [eax+12]?

  2. 相同的内容
  3. 目标操作数一直在左边,难道只有x0寄存器才向后?

  4. 我注意到我们根本没有使用堆栈指针,我们真的需要这样做吗?另外,swlw 有什么区别?它们都被使用过,但我不确定它们的作用是什么,也不知道为什么一个会比另一个被使用。

1) 栈指针减16为当前帧在栈上预留space。为了将内容存储到保留的 space 中,您向递减的堆栈指针添加一个偏移量(在本例中为 12)。

2) sw 将一个单词(在本例中为值 0,x0 始终包含)从寄存器存储到内存,你是对的(IMO)参数的顺序向后比较到语法的其余部分。

3) a) 我们已经使用堆栈指针来保存和恢复 return 地址,在这个本身并不调用的小函数中不需要它,但作为标准函数进入和退出的样板,这是一个有用的模式。堆栈用于存储不适合寄存器(或需要在堆栈上以支持递归)的局部变量,学习如何使用它是他们在这里向您展示的内容的一部分。

3 b) sw 将寄存器中的值存储到内存中,lw 从内存中加载值并存储到寄存器中。在设备驱动程序中,内存位置是您与设备通信的方式 - 存储到内存可以让您向设备提供信息(数据或控制信息),从内存加载是您从设备读取信息的方式。