皋陶 发表于 2020-8-23 22:16:57

从零开始学RISC-V之邮箱和邮件的秘密

本帖最后由 皋陶 于 2020-8-26 18:10 编辑

文章目录
[*]从零开始学RISC-V之邮箱和邮件的秘密

[*]背景介绍
[*]可执行文件的生成
[*]设计一个简单的IRAM
[*]总结一下

背景介绍
当一个应用软件被编译成可执行代码后,这种二进制数据会保存在各种不同类型的存储器中。对于xf100项目来讲,这个存储器就是指令RAM(简称IRAM,下同)。注意由于RAM在掉电后会丢失内部保存的数据,因此在实际应用中真实的程序会保存在ROM中,器件在上电之初会将该代码搬运到RAM中并按照设定的起始地址开始工作。如果将指令比喻为邮件的话,那么指令RAM就是专用的邮箱。
基于以上介绍,本节内容将围绕指令存储器展开。它包含两个任务:首先是生成一个实际的RISC-V可执行文件,我们将看到具体的risv指令,并分析cpu是如何识别该指令的。然后将会基于逻辑门设计一个SRAM模型。这两个任务的完成与否将直接关系到IFU(Instruction Fetch Unit,取指令单元)的功能。因此需要重视。
可执行文件的生成我们常见的编程语言,基本上越好读懂,越高级,也就越抽象。所有的高级语言,需要被计算机认识,必须有一套翻译工具,就是编译,链接等等。以最常见的C代码为例,需要经过如下步骤才能成为可执行文件:

[*]预处理:将代码中的各种文件包含,宏定义,以及注释等内容做替换或者展开,生成一份“明文”式的代码,这个时候还是高级语言的代码,只不过看起来就完整一些。你可以理解成把论文的参考文献直接贴在论文后面,预处理之前的参考文献链接,变成了处理之后的参考文献全文。
[*]**编译:**属于整个程序构建的核心,这一步会将预处理后的代码文件,转化成汇编代码文件。这种文件是早期计算机程序形式的一种。这一过程是将高级编程语言的代码转换成低级语言代码,它与计算机指令集强相关。这里,人类还能从中大致看出源程序的一些影子,也就是说我们还能看懂部分这转换后的代码。从此处开始,后面的代码就完全脱离了人类的思维了。那个时候的产物就只有电脑能认识了。
[*]**汇编:**将之前生成的汇编代码转化成机器码。
[*]链接: 将机器码做最后的规整,包括代码的重定位之类的,生成最终的可执行文件。

那么具体到本项目,按如下过程操作:

[*]进入xf100/verify/riscv-tools/riscv-tests/isa目录。在该目录下你将看到各种官方的测试样例。此处我们仅关心一个例子rv32ui-p-add,它在rv32ui目录下。
[*]修改该路径下的Makefile文件

[*]修改35行的RISCV_PREFIX,这个参数用于定位gcc-riscv工具链。你需要将其正确指向工具链的存放位置,就是第二节里的那个软连接。如果该参数错误,会导致生成时出现如下错误:make: xxx/bin/riscv-nuclei-elf-gcc: Command not found

[*]

make: xxx/bin/riscv-nuclei-elf-gcc: Command not found

[*]删除第79~88行,并修改78行的-march=rv32i。此处修改一是为了节省生成可执行文件的时间(毕竟我们只关注一个测试样例);其次是指定可执行文件所支持的指令集。由于xf100仅作为一个简单的核,因此不支持MACFD这一系列特性。为避免可执行文件中出现xf100不支持的指令,需要修改这个参数。


[*]在该路径下执行生成可执行文件命令
sh clean.sh// 删除之前生成的文件
sh regen.sh// 重新生成可执行文件
如果中间没有任何错误,经过一段时间后,你将会在该路径下的generate文件夹下看到生成的文件。其对应的汇编dump文件如下图所示:

更多关于指令如何被识别的知识,请参见这里
设计一个简单的IRAM
RAM是一种掉电易丢失的存储器。一种常见的仿真模型是使用基于DFF触发器的一维数组来构建RAM的仿真模型。数组的下标就是RAM访问的地址,数组的每个元素记录的就是需要读写的内容。就本项目来讲,我们对IRAM做如下约束:

[*]IRAM的读写数据位宽为32bit,即我们不支持16bit位宽的读写访问。由于xf100仅支持RV32I指令集,因此这个设置是合理的。
[*]IRAM地址位宽设置为16bit,即访问空间从0~65535字节。
[*]IRAM不存在写访问,由于IRAM只存储指令,也没必要对其存储内容进行修改,因此该设置也是合理的。
[*]读IRAM的数据在当拍就可以输出。这当然是一种理想的状况,尽管存在与实际RAM的工作状态不相符的缺点,但是xf100是一个简单的入门级项目,没必要在此处花费精力。就RAM模型来讲,只要符合其存储数据的基本应用需求即可。我们的重点在于厘清核内部的原理机制,此处简单实用即可。


基于以上设定,一个简单版本的IRAM的实现代码如下所示:
///
// 首先我们定义一个带负边沿复位(rst_n)和更新使能(lden)的D触发器。
module xf100_gnrl_dfflr #(
parameter DW = 32
)(
input clk,
input rst_n,
input          lden,
input din,
input dout
);

reg dout_r;
always @ (posedge clk or negedge rst_n) begin
if (~rst_n) begin
      dout_r <= 1'b0;
end else if (lden) begin
      dout_r <= din;
end
end

assign dout = dout_r;
endmodule

///
// 然后根据前述D触发器,构建一个32位宽的,深度可配置的RAM
module gnrl_sram #(
parameter DW=32, //数据位宽(Data Width)固定不变
parameter AW=8 ,
parameter DP=256 // 深度可配置
)(
input         clk,
input         rst_n,
input         cs ,
input         wen,
input din,
input addr,
output dout
);

// DFF数组,用于模拟RAM的存储区
reg ram_r ;

写端口实现,在IRAM中不会使用到
wire ram_nxt = din;
wire ram_wen = cs& wen;
xf100_gnrl_dfflr #(8) ram_dfflr_0
    (clk, rst_n, ram_wen,ram_nxt, ram_r);
xf100_gnrl_dfflr #(8) ram_dfflr_1
    (clk, rst_n, ram_wen,ram_nxt, ram_r);
xf100_gnrl_dfflr #(8) ram_dfflr_2
    (clk, rst_n, ram_wen,ram_nxt, ram_r);
xf100_gnrl_dfflr #(8) ram_dfflr_3
    (clk, rst_n, ram_wen,ram_nxt, ram_r);

读端口实现,数据在读请求有效的当拍就被输出。
wire ram_ren = cs & ~wen;

assign dout = ram_r & {DW{ram_ren}};
assign dout = ram_r & {DW{ram_ren}};
assign dout = ram_r & {DW{ram_ren}};
assign dout = ram_r & {DW{ram_ren}};

endmodule

例化一个IRAM,大小为16384*32bit
module xf100_inst_ram_16384x32 #(
parameter DW=32,
parameter AW=14,
parameter DP=16384
)(
input         clk,
input         rst_n,
input         cs ,
input         wen,
input din,
input addr,
output dout
);

gnrl_sram#(
.DW(DW),
.AW(AW),
.DP(DP)
) u_gnrl_inst_ram (
.clk   (clk),
.rst_n   (rst_n),
.cs      (cs   ),
.wen   (wen),
.din   (din),
.addr    (addr ),
.dout    (dout )
);

endmodule
至此,IRAM设计结束。后续在仿真时,只需要使用readmemh函数初始化该IRAM,就可以满足IFU取指的需求了。具体内容后续会有介绍。关于IRAM的仿真,将在下一节IFU的设计完成之后一起进行。
总结一下

[*]所有的高级语言写的代码,都需要通过编译工具做一道转化手续,这个看起来复杂,实际上也真的很复杂。
[*]IRAM就是一个存储指令的只读存储器,掉电易丢失,只处理IFU发送过来的读请求信号。
[*]数据在读请求信号有效的当拍就可以输出。但是这个行为并不很好,因为实际的RAM器件的时序并不是如此理想。
[*]IRAM的设计以符合要求为原则,大小可配置方便后续进一步优化设计。

本篇完,感谢关注:RISC-V单片机中文网

页: [1]
查看完整版本: 从零开始学RISC-V之邮箱和邮件的秘密