RocketChip RISC-V生成RTL到仿真全流程

news2024/12/26 21:16:23

一、Scala配置项修改和RTL代码生成

可以通过对scala中的配置项修改,来达到定制化配置RISC-V的目的,这里总结几个比较常用的配置项、配置项含义和所在的scala中的位置:

1.$rocket-chip/src/main/scala/system/Config.scala

1)new WithNExtTopInterrupts(128) ++,修改中断输入数量,这里是128个外部中断;

2)new WithDefaultMemPort ++、new WithDefaultMMIOPort ++、new WithDefaultSlavePort ++,添加、删除和修改AXI4 MEM、IOMaster和L2Slave接口;(支持AXI/AHB/TileLink)

3)new WithNSmallCores(2),修改内核数量,这里配置的是2;

4)new WithNMemoryChannels(2) ++,修改AXI4 MEM接口数量,这里会产生2组AXI4 MEM接口;

5)class Default2RV64SmallConfig extends Config(new WithNSmallCores(2) ++ new WithCoherentBusTopology ++ new BaseConfig),按照自己的配置定义RISC-V核,其中Default2RV64SmallConfig名称会被RTL生成器调用。

2.$rocket-chip/src/main/scala/subsystem/Config.scala

1)beatBytes = site(XLen)/8,修改AXI4数据位宽,如果是RV32,这里数据位宽是32bits;

2)case ExtMem => Some(MemoryPortParams(MasterPortParams(

base = x"8000_0000",

size = x"1000_0000",

beatBytes = site(MemoryBusKey).beatBytes,

idBits = 4), 1))

修改MEM/IO空间地址段位置和大小,这里MEM空间地址为0x8000_0000到0x1000_0000;

3)dcache = Some(DCacheParams(

nSets = 64,

nWays = 1,

nTLBSets = 1,

nTLBWays = 4,

tagECC = Some("secded"),

dataECC = Some("secded"),

dataECCBytes = 4,

修改Cache大小、组相连数量、添加Cache ECC支持等。

4)case BootROMLocated(InSubsystem) => Some(BootROMParams(contentFileName = "./bootrom/bootrom.img")),修改bootrom.img所在位置,这里是默认所在位置;

3.$rocket-chip/src/main/scala/rocket/RocketCore.scala

1) useVM: Boolean = false,修改虚拟内存使能,这里是关闭了虚拟内存;

2) haveCFlush: Boolean = true,修改Flush Cache使能,是否能通过指令Flush Cache数据;

3) clockGate: Boolean = true,时钟Gate是否使能,打开可降低功耗;

4) nPMPs: Int = 8,设置PMP内存保护地址段数量,RV32最大是8,RV64最大是16;

除此以外,还可配置:原子操作支持、压缩指令支持、断点数、不可屏蔽中断、特权模式使能、乘法除法等功能,这里不一一介绍了。

4.$rocket-chip/src/main/scala/devices/debug/Periphery.scala

1)protocols: Set[DebugExportProtocol] = Set(JTAG),修改Debug接口,可以选DMI/JTAG/APB等,这里选JTAG。

5.$rocket-chip/src/main/scala/devices/debug/Periphery.scala

require(reset_vector_source.getWidth >= params.address.bitLength, s"BootROM defined with a reset vector (${params.address})too large for physical address space ${reset_vector_source.getWidth})") bootROMResetVectorSourceNode.bundle := params.address.U,修改复位向量地址,修改后系统复位从该地址开始读取数据,这里改成了0x1000。

除此以外,还可以修改使能如TLB、分支预测、配置时钟异步、本地中断等功能,需要研究对应的scala代码并进行修改。

Scala代码修改完成后,在$rocket-chip/vsim或者$rocket-chip/vsim目录下运行:

make verilog CONFIG=freechips.rocketchip.system.Default2RV32SmallConfig

其中CONFIG的名称为$rocket-chip/src/main/scala/system/Config.scala中修改的名称。RocketChip生成器会将scala语言转换成RTL代码,并生成其他相关文件,最终得到如下图所示的verilog代码和相关仿真测试文件。

二、工具链和编译库生成

工具链和编译库可以在网上下载,或者通过$rocket-tools目录下的build.sh/build-rv32ima.sh对当前配置进行一次交叉编译。在进行交叉编译前,指定编译出来的工具链所在位置,可在bashrc中指定如下位置:

#RISC-V gnu toolchain
export RISCV=/home/alanwu/Documents/RISCV/rocket-tools
export PATH=/opt/riscv/bin:$PATH

如果指定的是/opt/文件夹下,需要注意权限的设置,完成后使用如下命令进行交叉编译:

./build.sh #RV64使用该命令
./build-rv32ima.sh #RV32使用该命令

交叉编译的时间有点长,最终会在指定目录下产生如下图所示的工具链文件。

如果是网上下载的,可以直接把文件放到对应目录,然后在bashrc中指定路径即可。

三、VCS硬件仿真环境搭建

建立一个RISCV-SIM文件夹,VCS硬件仿真都在该文件夹中完成,如下图所示,其中case_log文件夹用来放跑vcs的log信息,hardware_code文件夹用来放RTL代码,program_code文件夹用来放需要跑的case,wave_dump_log文件夹用来放跑出来的case波形。

1.程序编译

这里从仿真需要的顺序依次介绍下脚本的使用,首先是make_debug.sh脚本,该脚本是用来编译case,把基于C的case编译成镜像文件。首先会调用program_code文件夹下的riscv2bin.sh文件,该文件将c编译出来的.riscv文件转换成.bin/.elf文件。

#!/bin/bash
#make_debug.sh
GCC=riscv32-unknown-elf-gcc
OBJCOPY=riscv32-unknown-elf-objcopy
OBJDUMP=riscv32-unknown-elf-objdump

ELF_NAME=$1
BIN_NAME=`basename $ELF_NAME .bin`
HEX_NAME=`basename $ELF_NAME .hex`
#convert elf to bin
$OBJCOPY -O binary ${ELF_NAME}.riscv ${BIN_NAME}.bin

然后把bin/elf文件转换成纯二进制的hex文件,该文件实际没有文件格式,就是CPU可执行的二进制机器码,理论上应该叫.img文件。这里需要注意.hex的数据格式的转换,由于该二进制文件最终要放入仿真的mem中,因此需要根据mem位宽进行数据转换,使用program_code文件夹下的bin2hex_128.sh或bin2hex_256.sh脚本自动转换。

#!/bin/bash
BIN_NAME=$1
BASE_NAME=`basename $BIN_NAME .bin`
HEX_NAME=`basename $BIN_NAME .hex`
#dump hex for 32 bits width
hexdump -v -e/'4 "%08x\n"' ${BIN_NAME}.bin > temp.hex
#swap even and add rows
sed '$!N;s/\([^\n]*\)\n\([^\n]*\)/\2\n\1/' temp.hex | tee > temp1.hex
#merge 2 lines into 1 line, 32bits -> 64bits
awk '{if(NR%2==0) {printf $0 "\n"} else{printf $0}}' temp1.hex | tee > temp2.hex
#swap even and add rows again
sed '$!N;s/\([^\n]*\)\n\([^\n]*\)/\2\n\1/' temp2.hex | tee > temp1.hex
#merge 2 lines into 1 line again, 64bits -> 128bits
awk '{if(NR%2==0) {printf $0 "\n"} else{printf $0}}' temp1.hex | tee > temp2.hex
#swap even and add rows again
sed '$!N;s/\([^\n]*\)\n\([^\n]*\)/\2\n\1/' temp2.hex | tee > temp1.hex
#merge 2 lines into 1 line again, 128bits -> 256bits
awk '{if(NR%2==0) {printf $0 "\n"} else{printf $0}}' temp1.hex | tee > ${HEX_NAME}.hex

rm temp.hex temp1.hex temp2.hex
chmod 755 ${HEX_NAME}.hex

完成后,将hex文件复制到RSICV-SIM文件夹下,该文件最终会在top.v中的verilog仿真代码中调用,并被初始化到MEM中。

initial begin
  #1ns;
  $readmemh("./program.hex", top.TestHarness.mem.srams.mem.mem_ext.ram);
end

2.VCS硬件仿真

在跑VCS之前,需要指定RTL代码路径和include文件,编写filelist文件,把需要的内容添加到仿真中。除此之外,还需要完成testbech的编写和波形dump的参数,也就是top.v的代码编写。波形dump可以参考如下代码实现,这里是全脚本自动化的过程,也就是说每个case自动跑并自动判断结束条件,然后进行一个case,方便全case的自动化回归测试。

initial begin
//  #490us;
    $fsdbDumpfile("./wave_dump_log/helloworld.fsdb");
//  $fsdbAutoSwitchDumpfile(10000, "WAVEFORM_DEMO/helloworld.fsdb", 10);
//  $fsdbDumpvars(3, top);
//  $fsdbDumpvars(0, "top.TestHarness.mem", "+mda");
    $fsdbDumpvars(0, top);
    #1200us;
    $system("date +%y%m%d%H%M%S > timelog");
    $fscanf(TIME,"%t",data);
    $fwrite(PAT_RESULT, "%t\n", data );         
    $fwrite(PAT_RESULT, "********************************************\n" );         
    $fwrite(PAT_RESULT, "********************************************\n" );         
    $fwrite(PAT_RESULT, "PAT NAME :  helloworld, PASS FAILED\n");
    $fwrite(PAT_RESULT, "********************************************\n" );         
    $fwrite(PAT_RESULT, "********************************************\n\n\n" );         
    $fclose(TIME);
    $fclose(PAT_RESULT);
    $display("\n");
    $display("**************************************************");
    $display("**************************************************");
    $display("****** PAT NAME : helloworld, PASS FAILED***********");
    $display("**************************************************");
    $display("**************************************************");
    $finish;
end

initial    begin
  // delay period
    //#100ns;
    wait(top.TestHarness.ldut.mmio_axi4_0_aw_ready & top.TestHarness.ldut.mmio_axi4_0_aw_valid);
    wait(top.TestHarness.ldut.mmio_axi4_0_aw_bits_addr[30:0] == 31'h7070_7070);
    wait(top.TestHarness.ldut.mmio_axi4_0_w_ready & top.TestHarness.ldut.mmio_axi4_0_w_valid);
    wait(top.TestHarness.ldut.mmio_axi4_0_w_bits_data[31:0] == 32'hdead_beef);
    #10us;
    $system("date +%y%m%d%H%M%S > timelog");
    $fscanf(TIME,"%t",data);
    $fwrite(PAT_RESULT, "%t\n", data );    
    $fwrite(PAT_RESULT, "*************************************************\n" );         
    $fwrite(PAT_RESULT, "*************************************************\n" );         
    $fwrite(PAT_RESULT, "PAT NAME : helloworld, PASS SUCCESSED\n");
    $fwrite(PAT_RESULT, "*************************************************\n" );         
    $fwrite(PAT_RESULT, "*************************************************\n\n\n" );         
    $fclose(TIME);
    $fclose(PAT_RESULT);
    $display("\n");
    $display("**************************************************");
    $display("**************************************************");
    $display("****** PAT NAME : helloworld, PASS SUCCESSED********");
    $display("**************************************************");
    $display("**************************************************");
    $finish;
end

硬件仿真使用make run命令执行,其在Makefile中的命令可以参考如下设置,注意需要添加一些SIMV_DEF的仿真define定义。

#Makefile
SIMV_DEF =  +define+RANDOMIZE_MEM_INIT +define+RANDOMIZE_REG_INIT \
            +define+VIRAGE_FAST_VERILOG +define+MEM_CHECK_OFF \
            +define+RANDOMIZE_DELAY=0 +define+PRINTF_COND=0
run:simv
    ./simv -l run.log
simv:filelist.f    
    vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed \
    -f filelist.f \
    -sverilog +v2k \
    $(SIMV_DEF) \
    -debug_access+all -debug_access+designer \
    -fsdb-max_var_elem=8388608 \
    -kdb $(COV)\
    -timescale=1ns/1ps \
    -deraceclockdata \
    -l com.log

仿真跑完后,可以在regression_result.dat文件中查看每次跑case的结果,是FAILED还是SUCCESSED,并且可以查看这个Case跑的时间。仿真FAILED的条件是超时1200us,这个时间可以根据实际情况进行修改,如果系统超时时间更长,可以修改对应参数;仿真SUCCESSED的条件在1200us内CPU向0x7070_7070地址写数据0xdeadbeef,该地址是保留地址。该动作由程序发出,也就是说在测试程序的结尾,需要添加一段代码以保证CPU发出0x7070_7070地址的magic code。

3.查看波形

默认生成的波形为fsdb格式,也可以手动修改成vcd等其他波形格式,通过verid将波形加载进来,这里编写了段自动加载波形的verdi脚本,可以根据不同的case加载不同的波形,代码如下:

#Makefile
verdi:    
    verdi -sv -f filelist.f $(SIMV_DEF) +systemverilogext+.sv+.v -ssv -ssy -ssz -nologo -top top -ssf ./wave_dump_log/${CASE}.fsdb &

这里同样需要注意仿真和查看波形的define一致性,define不一致可能会导致波形对应的代码段不生效,导致trace信号失效,因此保持跑仿真和看仿真结果的参数一致非常重要。跑完的波形都放在了wave_dump_log文件夹中。

四、功能测试和回归测试

在进行功能测试前,需要对测试功能进行程序编写,按照如下的目录结构将.c、.s、.h等程序文件放在program_code文件夹下,具体放置位置如下图所示:

按照图中所示方法将编写好的所有case放在对应路径下,在跑功能测试时,使用如下命令完成一次功能测试和仿真:

#如果case名是helloworld
make debug
make run
make verdi
#如果case名不是helloworld,使用[case_name]指定需要跑的case名
make debug [case_name]
make run CASE=[case_name]
make verdi CASE=[case_name]

在跑回归测试时,可以将所有的case名称放在case_list中,然后通过脚本依次将case_name替换成需要跑的case名。

仿真环境也支持官方的benchmark或google随机测试pattern生成的测试集,但需要注意的是部分测试benchmark无法在平台上跑通,例如配置的硬件不支持浮点运算,而生成的测试集中存在浮点运算指令,那么仿真结果会FAILED。除此以外,还需要注意仿真能用到的硬件只有CPU、MEM和BootROM。如果想要测试更多的硬件,如总线网络NoC、外设、系统中断等,需要自行添加额外的IP核和RTL电路。

有需要该平台的可以留言邮箱或私信我获取,有相关问题也可以留言私信沟通。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157620.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习-2-安装Python 3.6和Pytorch 1.1.0

0. 说明: 之前根据GPU版本安装了CUDA 9.0,因此现安装与CUDA 9.0相对应的Pytorch版本,但在安装Pytorch之前要先确认一下Python的版本。 1. 查看 CUDA 9.0 对应的 Pytorch 从https://pytorch.org/get-started/previous-versions/中查找CUDA …

程序的机器级表示part1——程序编码与数据格式

目录 1. 汇编语言和机器级语言 1.1 不同的编程语言 1.2 Linux下的汇编语言 2. 程序编码 1.1 机器级代码 1.2 代码示例 3. 数据格式 本文基于CSAPP第三章撰写,主要介绍部分x86-64汇编的相关知识,后续会将该部分内容慢慢完善(PS&a…

Web Spider XHR断点 千千XX 歌曲下载(三)

Web Spider XHR断点 千千XX 歌曲下载 首先声明: 此次案例只为学习交流使用,切勿用于其他非法用途 注:网站url、接口url请使用base64.b64decode自行解码 文章目录Web Spider XHR断点 千千XX 歌曲下载前言一、资源推荐二、任务说明三、网站分析四、XHR断点…

knife4j使用与步骤

1、导入依赖<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version> </dependency>2、knife4j的配置类&#xff08;可有可无&#xff09;package…

为什么程序员的工资比其他行业高这么多?

不止一次听到有人说程序员工资高&#xff0c;更有甚者喊着“把IT工资打下来”。 拜托大哥大姐们&#xff01;看事情要客观好吧&#xff01;&#xff01; 虽然看起来程序员工资是不少&#xff0c;对比其他行业确实会高一些&#xff0c;但并不代表程序员这个岗位工资就要压到三千…

Elasticsearch:如何在 Elasticsearch 中正确使用同义词功能

同义词用于提高搜索质量并扩大匹配范围。 例如&#xff0c;搜索 England 的用户可能希望找到包含 British 或 UK 的文档&#xff0c;尽管这三个词完全不同。 Elasticsearch 中的同义词功能非常强大&#xff0c;如果实施得当&#xff0c;可以使你的搜索引擎更加健壮和强大。 在…

详解结构体内存对齐

目录 前言 一、结构体内存对齐规则 二、 offsetof 宏 三、结构体内存对齐的原因 四、 修改默认对齐数 前言 引入问题&#xff1a; #include <stdio.h>struct S {char c1;int i;char c2; };int main() {printf("%zd\n", sizeof(struct S));return 0; } 程…

干货 | 人脸识别技术的风险及应对方案

以下内容整理自清华大学《数智安全与标准化》课程大作业期末报告同学的汇报内容。第一部分&#xff1a;人脸识别技术概述人脸识别的发展阶段&#xff0c;主要分为三个阶段&#xff1a;起步阶段&#xff08;1950s-1980s&#xff09;&#xff0c;这一阶段的人脸识别只是作为一般性…

房产管理系统---系统安全性需求分析

数图互通高校房产管理系统是基于公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。…

Linux学习笔记——HBase集群安装部署

5.11、大数据NoSQL数据库HBase集群部署 5.11.1、简介 HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库。 和Redis一样&#xff0c;HBase是一款KeyValue型存储的数据库。 不过和Redis设计方向不同&#xff1a; Redis设计为少量数据&#xff0c;超快检索HBase设计…

【部署】Docker容器

Docker 使用 Google 公司推出的 Go 语言进行开发实现&#xff0c;基于 Linux 内核的 cgroup、namespace 以及 OverlayFS 类的 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程&#xff0…

算法刷题打卡第63天:对称二叉树

对称二叉树 难度&#xff1a;简单 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false…

BOM浏览器对象模型

文章目录一、BOM概述1、什么是BOM2、BOM的构成二、window 对象的常见事件1、窗口加载事件&#xff08;1&#xff09;window.onload&#xff08;3&#xff09;DOMContentLoaded2、调整窗口大小事件三、定时器1、两种定时器2、setTimeout()定时器3、停止 setTimeout() 定时器4、s…

如何使用CMD修复硬盘命令来解决硬盘问题?

随着计算机的越来越普及&#xff0c;现在在我们的日常生活中都会使用到计算机电脑。硬盘作为计算机电脑的主要存储设备&#xff0c;里面存储着我们平时使用的软件文件、文档资料、照片等重要的数据文件。一旦硬盘损坏会给我们带来许多不必要的麻烦&#xff0c;那硬盘损坏有哪些…

图解卡尔曼滤波(Kalman Filter)

背景关于滤波首先援引来自知乎大神的解释。“一位专业课的教授给我们上课的时候&#xff0c;曾谈到&#xff1a;filtering is weighting&#xff08;滤波即加权&#xff09;。滤波的作用就是给不同的信号分量不同的权重。最简单的loss pass filter&#xff0c; 就是直接把低频的…

【Linux操作系统】1. Linux操作系统简介、安装

前言 本系列是Linux操作系统的一些知识以及实践内容&#xff0c;Linux操作系统作为开发最常使用的操作系统&#xff0c;是必备的一门求职、提升技术。本文先介绍Linux操作系统&#xff0c;并安装一个Linux操作系统。 Linux操作系统简介 Linux&#xff0c;全称GNU/Linux&#…

Javadoc

Javadoc 在学习JavaSE时&#xff0c;我们知道Java支持三种注释方式&#xff1a; 单行注释多行注释文档注释 Javadoc是文档注释&#xff0c;用来对类或方法进行标准的注释&#xff0c;在开发中写好JavaDoc非常重要。 在调用方法时&#xff0c;你可能会看到这样的情景 这种注…

Unity - 搬砖日志 - 如何设置AssetDatabase.Create(“xxx.asset“, mesh) 的Read/Write=false

最近很忙&#xff0c;想写的 BLOG 都遗漏编写了 踩坑的时间比较多&#xff0c;充电的时间少了很多 为了减少以后自己填坑时间&#xff0c;随便简单的记录一下 搬砖日志 环境 unity : 2020.3.37f1 pipeline : brp 问题 因为之前搜索、购买、使用了各式各样的 LOD 插件、工具…

机器学习100天(三十一):031 K近邻回归算法

机器学习100天,今天讲的是:K 近邻回归算法! 《机器学习100天》完整目录:目录 一、理论介绍 我们之前讲了 K 近邻分类算法,用来处理分类问题。其实 K 近邻也可以用来处理回归问题。 如左图所示,K 近邻分类算法的思路是选取与测试样本距离最近的前 k 个训练样本。然后对…

回收租赁商城系统功能拆解07讲-订单列表

回收租赁系统适用于物品回收、物品租赁、二手买卖交易等三大场景。 可以快速帮助企业搭建类似闲鱼回收/爱回收/爱租机/人人租等回收租赁商城。 回收租赁系统支持智能评估回收价格&#xff0c;后台调整最终回收价&#xff0c;用户同意回收后系统即刻放款&#xff0c;用户微信零…