Menu Close

RISC-V 仿真工程中block memory 中的数据装载

在使用Xilinx Vivado 做仿真工程时,有时需要快速多次的更改block memory 的初始数据。本文提出一种填装的方法。避免增加额外的Verilog 逻辑来动态填装 block memory 里的内容。

在RISC-V CPU 设计开发中, 仿真是验证代码是否正确的重要手段。在RISC-V FPGA仿真中, 我们会使用双端口作为ITCM ,来存储软件编译出来的机器码,如何快速的更新双端口里的内容,以便加速仿真过程也是我们一直关注的内容。下面将代码加载、程序仿真以分解的方式逐一介绍。

1.将机器码加载到ITCM中

由于在RISC-V CPU开发中会经常用block memory IP实现ITCM,因此先以一个双端口为例介绍机器码加载到双端口RAM的方法, 这样就不用修改双端口RAM的端口a或端口b的逻辑,只修改block memory 里的内容就可以实现我们需要的仿真。以下内容是以FII_RISCV_V2.01.002 CPU工程为例按步骤进行介绍。

  • RISC-V 工程目录:

从图1中可以看出,RISC-V CPU中ITCM的确切位置。

ITCM directory

图1 

我们例化的ITCM (双端口)在 fii_cpu_sys/fii_riscv_cpu_inst/fii_rv32i_core_inst/program_inst, 目录相对来说,还是比较深的。

  • 在仿真文件中增加以下代码:

localparam FILE_NAME = "../../../asm_run_led.sim";
integer file_handle = 0;
initial begin
    file_handle = $fopen(FILE_NAME,"r");
    if(!file_handle)
    begin
        $display("Could not open File \r");
        $stop;
    end
    $readmemh (FILE_NAME, fii_cpu_sys_inst.fii_riscv_cpu_inst.fii_rv32i_core_inst.program_inst.inst.native_mem_module.blk_mem_gen_v8_4_1_inst.memory);
 
    $fclose(file_handle);    
end

仿真文件中:

上面的代码中$readmemh针对block memory的加载非常复杂,如

$readmemh (FILE_NAME, fii_cpu_sys_inst.fii_riscv_cpu_inst.fii_rv32i_core_inst.program_inst.inst.native_mem_module.blk_mem_gen_v8_4_1_inst.memory);
读取asm_run_led.sim文件,并且将文件的内容写入到双端口里去。红色部分是工程模块的例化名称,蓝色部分指向的是 block memory。

像这样的语句,一般使用者很难准确的描述出block memory 的存储单元的正确位置。针对这个问题,IC知识库网站中有一篇文章,专门介绍这个方面的内容。参见仿真工程中$readmemh 使用。

localparam FILE_NAME = “../../../asm_run_led.sim”;
asm_run_led.sim仅仅是*.coe文件中的有效数据部分,并将数据放到.sim 目录下,具体放置的位置参照图2 ,图3。

 

图2

图3

2.软件程序在RISC-V CPU上进行仿真

测试工程:由汇编语言编写在FII-PRX100-D 下的跑马灯实验。(软件控制LED灯)

软件汇编代码:

.globl _start
_start:
            LI   x8,  0xf0000000;   # x8 = 0xf000_0000 gpio base address
            ADDI x6,  x0, 0;        # x6 = 0
            LI   x7,  0x00400000;   # x7 = 0x0040_0000 delay counter
#           LI   x7,  0x4;          # x7 = 0x0040_0000 delay counter
START:      ADDI x10, x0, 0x80;     # x10 = 0x80
            NOT  x18, x10;          # x18 = ~x10
            SH   x18, 0(x8);        # addr[0xf000_0000] = val[0x18]
            SH   x0,  4(x8);        # addr[0xf000_0004] = 0 as output

LOOP:       ADDI x6,  x6, 1;        # x6 = x6 + 1
            BNE  x6,  x7, LOOP;     # if(x6 != x7) goto loop
            ADDI x6,  x0, 0;        # x6 = 0
            
            SRLI x10, x10,1;        # x10 >> 1
            BEQ  x10, x0, START;    # if(x10 == 0x100) goto start

            NOT  x18, x10;          # x18 = ~x10
            SH   x18, 0(x8);        # addr[0xf000_0000] = x18
            JAL  LOOP;              # pc = 0x3c

 

使用asm_compile工具可以将上面的RISC-V 汇编语言生成相应的*.coe,*.sim文件等。

asm_run_led.coe 文件内容为:
memory_initialization_radix = 16;
memory_initialization_vector =
f0000437
00000313
004003b7
08000513
fff54913
01241023
00041223
00130313
fe731ee3
00000313
00155513
fe0500e3
fff54913
01241023
fe5ff0ef
00000000
00000000;

asm_run_led.sim 文件内容为:
f0000437
00000313
004003b7
08000513
fff54913
01241023
00041223
00130313
fe731ee3
00000313
00155513
fe0500e3
fff54913
01241023
fe5ff0ef
00000000
00000000

 

仿真波形:

图4

从图4中可以看出,真实仿真的数据(地址,指令)与从*.sim文件中加载的内容一致。

这样,仿真文件就可以将数据文件的内容,写入到双端口中, 从而不需要改变Verilog 模块逻辑,也不需要重新综合双端口IP core(修改*.coe 文件)。以上的设计仿真方法是非侵入式仿真。在学习RISC-V CPU 时, 这是一个非常好用的方法,快速导入用户所编写的汇编代码到FPGA 工程中, 以便CPU进行仿真。

通过这种机器码的加载方法,之后RISC-V CPU的译码,执行,访存等步骤都可以方便快速的利用仿真工具进行调试和验证。

Posted in FPGA, FPGA 教材教案, Verilog, Vivado, 教材与教案, 文章, 编程语言, 集成电路