我想为 FPGA 构建自己的最小 RISC-V 处理器。处理器将尽可能简单,只有一条管道。
我阅读了整个 RISC-V ISA,其中有很多标准扩展。那么可以运行linux的最小RISC-V ISA是多少呢?
我正在学习如何为 RISC-V 处理器编写代码。我想将一个值存储0xFFFFFFFF到内存/寄存器中。
addi我可以通过在指令前面添加 来扩展指令的 12 个立即位lui,如下所示:
lui t0, 0xFFFFF
addi t0, t0, 0x7FF
Run Code Online (Sandbox Code Playgroud)
但结果会是这样的0xFFFFF7FF。
那么,我怎样才能产生这个价值呢?
嘿,我对 RISC-V 还算陌生。
我的练习题之一是:
将 0x0000000000000123 的值右移 4 位。预期结果为0x3000000000000012,即所有十六进制数字右移一位,最右边的一位移到前面*
到目前为止,我了解了一些关于逻辑运算的知识:andi, or, and xori。在我之前的练习中我学到了add, addi, sub, slli, srli, srai。
我从以下开始:
addi x6, 0x, 0x123
Run Code Online (Sandbox Code Playgroud)
然而,我被困在这里了。我的教科书并没有真正正确地描述事物,所以非常感谢任何帮助!
我想知道 ISA 中的任何内容是否会导致堆栈增长(推入增加 sp,弹出减少 sp)性能降低或在其他方面是不可取的?我知道这不是当今工具的工作方式,包括 Linux 和 GCC 端口,但是除了“这将是一项疯狂的工作量”之外,还有什么根本原因吗?
我了解到,jal和jalr都可以用于调用函数,而相反只能jal用于从这样的函数返回:
sum3:
add a0, a0, a1
add a0, a0, a2
jalr x0, 0(ra)
Run Code Online (Sandbox Code Playgroud)
但是,此代码使用jal而不是jalr从函数返回,并且效果很好:
call sum3
ret_sum3:
# following instructions
# ...
sum3:
add a0, a0, a1
add a0, a0, a2
jal x0, ret_sum3
Run Code Online (Sandbox Code Playgroud)
既然如此,为什么说jalr是函数返回的指令呢?我也可以用jal它。
我一直在尝试在RISC-V架构的系统上运行Python程序。该程序涉及运行一个简单的人工神经网络模型,并涉及 numpy 的使用。
然而,运行在RISC-V架构上的操作系统(目前运行在FPGA上)是一个非常基本的Linux系统,无法安装Python3或Pip等软件。但它可以编译C/C++程序并运行它们。所以我认为仍然有办法在这个系统上运行我的Python程序,通过在我的主机系统上将其转换为C/C++,将其传输到RISC-V系统,并在那里进行编译。
问题是我无法在任何地方找到好的 Python 到 C/C++ 转换器软件。我发现有一些软件工具可以将Python代码转换为二进制可执行文件,例如py2exe和pyinstaller。但是,如果我尝试运行机器代码,仅与我的主机系统架构(使用 RISC-V 架构)兼容,则这是无关紧要的。
我还遇到了 Nuitka,它确实将 Python 代码转换为 C/C++ 并将其存储在可移植的分发文件夹中,但随后也为我在程序中导入的库生成共享对象文件 (.so),这又不能在RISC-V系统上执行。此外,根据我在 Nuitka 文档中看到的内容,发行版中没有编译 C/C++ 代码的指南。
所以我有几个问题:
我的问题可能看起来很奇怪,事实上,这是上下文:
我目前面临一个奇怪的问题,同时切换 -在我正在从事的项目上- 从pullinino到CV32的核心(也发生了一些其他变化,例如关于crt0,如一些数据RAM重置)。
这是一个(真实的)示例,说明了一个相当简单的 main 所发生的情况(我无法对startup/crt0 文件进行编辑:我在帖子后面部分给出了它)。
#include <string.h>
#include <inttypes.h>
#include <stdio.h>
typedef struct
{
uintptr_t addr;
uint32_t foo;
} some_struct_t;
static uint32_t text_in_data[8] = {0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888};
uint32_t text_in_data2[8] = {0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888};
some_struct_t text_in = {(uintptr_t)text_in_data, 8};
static some_struct_t text_in2 = {(uintptr_t)text_in_data, 8};
int main(void)
{
some_struct_t text_in3 = {(uintptr_t)text_in_data, 8};
static some_struct_t text_in4 = {(uintptr_t)text_in_data, 8};
static some_struct_t text_in5 = {(uintptr_t)text_in_data2, …Run Code Online (Sandbox Code Playgroud) RISC-V 调用约定规定寄存器 a0 和 a1 可用于返回值,而不是所有 8 个寄存器 a0~a7。当需要“返回”两个以上的值时,我们可以使用堆栈。为什么?这样做有什么好处吗?
我正在学习 RISC-V 语言,作为计算机体系结构研究的一部分。我注意到我们可以使用所有八个 a0~a7 寄存器将参数传递给函数,但根据一些 RISC-V 调用约定,只有其中两个(a0 和 a1)可用于返回返回值,例如了解 RISC-V 调用约定和RISC-V 调用约定。我很困惑为什么约定包含只有 a0 和 a1 应该用于返回的规则。我浏览了上面提到的两篇文章,但没有找到任何解释这一点的内容。在我看来,这些a0~a7寄存器在函数调用之间不被保留,这表明我们可以在函数中自由地使用它们。因此,如果需要,我们可以而且应该使用它们中的任何一个来传递返回值,以方便和高效。总之,有什么理由要求我们限制返回值到a0和a1寄存器吗?
PS我刚刚注意到这个问题Whytworeturnregisters(inmanyprocedurecallsconventions/ABIs),它告诉我连续的寄存器可以用于大数字。然而,我的观点是,为什么我们限制自己在a2~a7中放入更多的返回值,即使看起来没有明显的缺点?或者,如果我使用a2~a7作为返回值,违反约定,会不会很糟糕?