二、E906移植----项目解读与FPGA基本工程搭建

二、E906移植----项目解读与FPGA基本工程搭建

上篇介绍了基本的环境搭建,并跑了一下官方例程,查看了一下仿真波形。本篇则主要讲一下官方的例程是如何跑通的,涉及到哪些必要步骤,以及对应步骤具体是在干嘛,哪些步骤是可综合的,哪些是必须通过添加额外功能模块才能实现的,最后将在FPGA上部署一个基本的可综合工程,并拉通在FPGA上的项目综合。值得注意的是,本篇结束后搭建的FPGA工程只是包含了项目所需的绝大部分源文件,要实现fpga上基本的跑通还需要进行四五处修改,具体在下一篇介绍。

不同人的了解程度不同,我介绍的是必要的一些流程但不一定够细,所有这些其实都可以通过读源文件来分析出个大概,然后不确定的地方可以多尝试几下。

1. Hello_world 仿真是如何跑起来的?

1.1 可行性

首先评估一下移植的可行性,即 ‘官方的smart_run平台跑通’ —— ‘FPGA能跑通’ 靠谱程度。 因为我们知道qemu的存在,是可以在指令集层面上进行模拟运行环境的,实际上也有很多人做了不少在qemu上模拟riscv运行的有意义的工作,如果这个smart_run是通过qemu来模拟运行的,那这个逆向分析涉及面就可以直接宣布挂机了。

实际上,上一篇博客也大致介绍过,vcs下make rancase后是会生成一个simv的,直接运行这个simv和通过runcase后的打印输出结果一样。那么就可以大概率说明,这个smart_run的命令就是写RTL标准的三板斧:搭建工程RTL源代码 —— 构建testbench,写激励 —— vcs等逻辑仿真工具解释编译生成输出结果文件。

既如此,那我们只需要看看工程到底用了哪些源码,testbench写了哪些激励,然后copy一下源码到FPGA工程,再把testbench里的激励换成实际上FPGA的引脚信号输入,或者PLL时钟输入仿真运行涉及到的所有行为,即可完成移植了,这个难度还是可以接受的。

1.2 项目文件结构简介

opene906-main 2级目录如下
.
├── doc
│ ├── opene906_datasheet.pdf
│ ├── QR_code_openXuantie.png
│ ├── \347\216\204\351\223\201E906\351\233\206\346\210\220\346\211\213\345\206\214.pdf
│ └── \347\216\204\351\223\201E906\347\224\250\346\210\267\346\211\213\345\206\214.pdf
├── E906_RTL_FACTORY
│ ├── gen_rtl
│ └── setup
├── LICENSE
├── README.md
└── smart_run
├── impl
├── logical
├── Makefile
├── setup
├── tests
└── work

其中比较重要的、需要反复查看的:
E906_RTL_FACTORY / gen_rtl ---- 所谓RTL工厂,存放了e906 riscv核心的所有源代码包括:时钟、复位、取指、译码、执行等等基本内核ip源码。

smart_run/logical ---- 一个soc要跑起来光核心不行,还需要外设总线,寄存器/内存模型也得有,基本的GPIO和UART也得有吧,还得有下载调试的模块,另外比较重要的是testbench也在这里,还有一些filelist的汇总。

smart_run/tests ---- 一个cpu要跑起来除了基本的硬件RTL结构,还得需要软件代码才行,该文件目录下就存放了c代码例程以及库文件。

smart_run/work ---- 是自行创建的,用于跑例程仿真的目录,一些中间输出文件包括c代码的编译、汇编、链接输出文件存在于此。

另外,Makefile 也需要反复查看来分析make buildcase/runcase 命令到底具有哪些行为,甚至可以理解为整个FPGA的移植过程其实就是把make runcase命令的仿真行为放到FPGA上来执行而已。 其实在后面也可以看到,如果修改后的文件make runcase没有结果输出,那么同样的一些源文件放到FPGA上也绝大概率挂了。

1.3 Makefile文件大致解读与make runcase运行流程分析

先在后面贴一下smart_run路径下的Makefile,内容略多,但是结构还是比较清晰的。

  1. 上来先引用了setup下的两个文件,其中 smart_cfg.mk 主要包含了调用gcc工具链对c代码项目进行build的命令,env_check.mk则检查 TOOL_EXTENSION 这个工具链路径环境变量是否定义。

  2. 接着是Simulation related 的命令,先检查外部调用时传入的 DUMP和SIM命令字, 特别是根据SIM 传入的值设置不同的编译选项,如熟悉的添加timescale、设置编译支持systemverilog、指定输出log文件等配置。 再下一段有个 SIM_FILELIST 的配置,这个信息比较重要,它告诉我们vcs等仿真器编译时到底调用了哪些文件。 最后就是具体的 compile 和 cleansim 的命令实现。

  3. 再接着就是 Cases related的命令,包括showcase、buildcase、cleancase。showcase就是把 CASE_LIST的值打印出来,CASE_LIST呢则是在引用的smart_cfg.mk中定义的,包含了hello_world等几个可用的测试例程。cleancase就清理一下文件。

    着重看一下buildcase命令的实现,匹配到CASE_LIST后,显示清理了一下,然后调了$(CASE)_build 命令,如果外部输入的是make buildcase CASE=hello_world , 那么实际调用的就是make hello_world_build 命令,这个命令的实现是在smart_cfg.mk中:
    hello_world_build:
    @cp ./tests/cases/hello_world/* ./work
    @find ./tests/lib/ -maxdepth 1 -type f -exec cp {} ./work/ ;
    @cp ./tests/lib/clib/* ./work
    @cp ./tests/lib/newlib_wrap/* ./work
    @cd ./work && make -s clean && make -s all CPU_ARCH_FLAG_0=e906f CPU_ARCH_FLAG_1=nodsp ENDIAN_MODE=little-endian CASENAME=hello_world FILE=hello_world_main >& hello_world_build.case.log
    具体做的就是把hello_world中的文件(只有main函数)、还有相关的c库文件copy到work下,另外tests/lib/下有一个Makefile也被复制了进去,然后就make all。 这个行为可以理解为在keil等CDK中将写好的c代码compile、build的过程。

  4. 最后比较重要的就是这个runcase命令。首先在CASE_LIST中匹配到CASE后,
    首先调用了compile ,也即verilog 硬件描述 RTL的编译;
    接着 buildcase 命令,软件代码综合生成二进制;

    最后视不同的编译器,分别执行生成的文件,vcs 就是./simv,iverilog 就是 vvp xxx.vvp 。

  5. 最后 regress是测试所有案例的,clean 和 help 不多解释。

总之,两点比较关键,一是使用 SIM_FILELIST 中的RTL和tb进行compile,二是对test case进行build。

·····················

1.4 smart_run下的Makefile 文件
#/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd.
#
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.
#*/
include ./setup/smart_cfg.mk
include ./setup/env_check.mk
################################################################################
# Simulation related
################################################################################
SIM = iverilog
DUMP = off

ifeq ($(DUMP), on)
SIM_DUMP :=
else
ifeq (${SIM}, iverilog)
SIM_DUMP = -DNO_DUMP
else
SIM_DUMP := +define+NO_DUMP
endif
endif

ifeq ($(SIM), vcs)
TIMESCALE := -timescale=1ns/100fs
SIMULATOR_OPT := -sverilog -full64 -kdb -lca -debug_access +nospecify +notimingchecks
SIMULATOR_DEF := +define+no_warning +define+TSMC_NO_WARNING
SIMULATOR_LOG := -l comp.vcs.log
else 
    ifeq ($(SIM), nc) 
    TIMESCALE := -timescale 1ns/100fs
    SIMULATOR_OPT := +v2k -sysv +sv +access+wrc +notimingcheck -default_ext verilog -elaborate +tcl+../setup/nc.tcl
    SIMULATOR_DEF := +define+no_warning +define+TSMC_NO_WARNING +define+VMC +define+NC_SIM 
    SIMULATOR_LOG := -l comp.nc.log
    else
    ifeq ($(SIM), iverilog)
      TIMESCALE := 
      SIMULATOR_OPT := -o xuantie_core.vvp -Diverilog=1 -g2012
      SIMULATOR_DEF := -DIVERILOG_SIM
      SIMULATOR_LOG := 
    endif
    endif
endif

ifeq ($(SIM), iverilog)
SIM_FILELIST := $(SIM_FILELIST) -f ${CODE_BASE_PATH}/gen_rtl/filelists/E906_asic_rtl.fl -f ${CODE_BASE_PATH}/gen_rtl/filelists/tdt_dmi_top_rtl.fl -c ../logical/filelists/smart.fl -c ../logical/filelists/tb.fl
else
SIM_FILELIST := $(SIM_FILELIST) -f ../logical/filelists/sim.fl
endif

compile:
	@echo "  [THead-smart] Compiling smart now ... "
	@echo "  [THead-smart] SIM = $(SIM)"
ifeq ($(SIM), vcs)
	@make -s cleansim
	@cd ./work && vcs $(SIMULATOR_OPT) $(TIMESCALE) $(SIMULATOR_DEF) $(SIM_FILELIST) $(SIM_DUMP) $(SIMULATOR_LOG) 
else 
    ifeq ($(SIM), nc)
	@cd ./work && irun $(SIMULATOR_OPT) $(TIMESCALE) $(SIMULATOR_DEF) $(SIM_FILELIST) $(SIM_DUMP) $(SIMULATOR_LOG) 
    else
        ifeq ($(SIM), iverilog)
	  @cd ./work && iverilog $(TIMESCALE) $(SIMULATOR_OPT) $(SIMULATOR_DEF) $(SIM_FILELIST) $(SIM_DUMP) $(SIMULATOR_LOG)
        else
	  @echo "  [THead-smart] Please specify SIM = vcs to use VCS, or SIM = nc to use irun ..."
        endif
    endif 
endif 

cleansim:
	@cd ./work && rm -rf simv* csrc ucli.key *.vcs.log novas_dump.log *.fsdb
################################################################################
# Cases related
################################################################################
showcase:
	@echo "  Case lists:" \ 
	@for case in $(CASE_LIST) ; do \
          echo "    $$case"; \
        done
        
buildcase: tool-chain-chk
ifeq ($(CASE),)
	$(error Please specify CASE=xxx on the command line, like: \
        $(newline)   > make buildcase CASE=xxx... \
        $(newline)   The list of valid cases can be obtained by executing: \
        $(newline)   > make showcase ...)
endif
ifeq ($(findstring $(CASE), $(CASE_LIST)), $(CASE))
	@make -s cleancase
	@make -s $(CASE)_build
else
	$(error Argument CASE=xxx is not valid: \
        $(newline)   The list of valid cases can be obtained by executing: \
        $(newline)   > make showcase ...)
endif

cleancase:
	@cd ./work && rm -rf *.s *.S *.c *.o *.pat *.h *.lcf *.hex *.obj *.vh *.v *.report *.elf Makefile *.case.log
################################################################################
# Combined flows
################################################################################
# Execute one case
runcase:
ifeq ($(CASE),)
	$(error Please specify CASE=xxx on the command line, like: \
        $(newline)   > make buildcase CASE=xxx... \
        $(newline)   The list of valid cases can be obtained by executing: \
        $(newline)   > make showcase ...)
endif
ifeq ($(findstring $(CASE), $(CASE_LIST)), $(CASE))
	@make -s compile
	@make -s buildcase CASE=$(CASE)
ifeq ($(SIM), vcs)
	cd ./work && ./simv -l run.vcs.log
else
        ifeq ($(SIM), nc)	
	cd ./work && irun -R -l run.irun.log
        else
	cd ./work && vvp xuantie_core.vvp -l run.iverilog.log
        endif
endif
else
	$(error Argument CASE=xxx is not valid: \
        $(newline)   The list of valid cases can be obtained by executing: \
        $(newline)   > make showcase ...)
endif

# Execute all cases
regress:
	rm -rf ./tests/regress/regress_result/*
	@(for case in $(CASE_LIST) ; do \
	 rm -rf ./work/* ; \
	 make -s runcase CASE=$$case; \
	 cp ./work/run_case.report ./tests/regress/regress_result/$$case.report; \
	 done)
	cd ./tests/regress && perl report_gen.pl
	cat ./tests/regress/regress_report
################################################################################
# Misc
################################################################################
.DEFAULT_GOAL := help

clean:
	@cd ./work && rm -rf * 

help:
	@echo "  ########## Smart Help Info ##########"
	...

1.5 项目文件结构、testbench 文件分析与移植思路

现在有点方向了,就是把仿真中的SIM_FILELIST中的RTL源文件扔进FPGA工程中,然后把不可综合的激励模块换成板子上的时钟、引脚信号输入。实际的,我们可以先打开仿真中的硬件项目,看一下目录文件组织结构以获取下一步的思路。

①项目文件结构
smart_run 目录下,打开终端,进入csh, 跑一下 make runcase,最后verdi 运行一下仿真输出simv。

[ICer@IC_EDA smart_run]$ csh
[ICer@IC_EDA smart_run]$ make clean
[ICer@IC_EDA smart_run]$ make runcase CASE=hello_world SIM=vcs
[ICer@IC_EDA smart_run]$ ./work/simv -verdi

verdi 界面下工程大体结构:
在这里插入图片描述
仿真的顶层文件就是tb,tb里面例化了 soc、uart_mnt、mnt这3个模块;更进一步的x_soc里面还有更多的子级结构,实际上包含了数百个文件。

② tb.v文件
在路径 /opene906-main/smart_run/logical/tb 下存放了仿真运行的顶层文件,先找一找里面仅有的可综合代码:
在这里插入图片描述
就是结构中前面提到的 mnt 、 uart_mnt、soc三个模块的例化, 这个tb的所有其他模块应该就是围绕着这3个例化模块来进行信号输入输出操作的,更进一步,soc是整个核心块,uart_mnt其实就是监测soc的uart0_sout输出信号线来模拟uart协议的数据流解析与仿真输出的,mnt 应该是monitor缩写,是用于运行状态监测的。

回过头来,再梳理一遍tb.v文件的流程,重点看一下围绕soc的信号流动方向,尤其是输入信号,因为输出信号的作用多是用于监测,我不监测只是看不到相关信息而已,系统是能运行的(当然$error 等终止语句还是得看看):

i. 先是将模块内部的一些信号定义成宏变量 ;
ii. 然后是关于系统和jtag的时钟与复位信号的激励模块 ;
iii. 接着对memory进行了初始化 ;
iiii. 后面的大都是各种信号监测模块了,但是有个地方需要注意,
在这里插入图片描述
$deposit 语句 是具有强制改变模块内部信号量值的作用的,这里大概是和pmu电源管理有关,如进入睡眠、低功耗模式等,需要标记留意一下。 其实后面还有几个force语句,简单分析发现其并没有向soc模块内部传递信号。
iiiii. 其实保险起见,tb内例化的另外两个模块uart_mnt和mnt也可以进去看看信号流向,可以发现均是对x_soc模块相关信号的输出监测,没有对x_soc信号输入。

那么到这里,移植的思路已经很明确了——soc模块就是最核心的模块,把它包含的RTL文件找出来放进fpga中那么整个基本工程就比较完整了;接着是时钟和复位的激励,时钟通过PLL产生,复位接到外部按键;还有一个非常重要的memory初始化,这个其实就是把cpu要运行的指令数据存进memeory中,但是tb的这种写法不可综合,后面的换个方法;最后就是这个pmu的信号控制,以及uart引脚输入输出外接。

2. FPGA基本工程搭建

现在开始搭建FPGA的工程,我这里基于vivado2019.1, 使用的开发板是正点原子的zynq7020板子,如果手里没有开发板子其实也可以先搭建工程跑跑综合、布局看看一看资源占用、时序违例等等方便后面挑选合适的板子,毕竟vivado建立工程的芯片型号是自己随便选的。

2.1 抽取RTL源文件

前面有提到,/opene906-main/E906_RTL_FACTORY/gen_rtl 和 /opene906-main/smart_run/logical 下包含了绝大部分RTL源代码,实际上这里面有3类文件 verilog 文件(xx.v) 、头文件(xx.h)和文件列表(xx.fl),后面看到这里面有几十个文件是多余的,具体哪些多余我们也可以根据Makefile里提到的SIM_FILELIST里的内容去逐个挑选,但是vivado软件是可以自动分析出各个verilog文件之间的包含关系的,所以全部拎出来扔进去就好了,没用到的disable掉就好。

具体的,/opene906-main下新建一个FPGA文件夹,/FPGA 下再新建一个 source文件夹用于存放源代码,然后将/opene906-main/E906_RTL_FACTORY/gen_rtl 和 /opene906-main/smart_run/logical 下文件全部复制进来:

在这里插入图片描述
为了更精确点,其实里面的filelists相关文件可以全部删掉,当然不删除后面disable也是可以的。
另外,默认的tb.v是作为top文件的,这个是仿真用的不可综合的,后面必须要把它替换成自己的顶层文件,这里可以先留着用于参考soc模块是如何调用的。

2.2 vivado 下fpga工程创建
  1. /opene906-main/FPGA 下打开终端, 输入vivado 打开,新建工程命名为e906_fpga,添加初始源文件路径-source 至工程: !!!注意,第3步那里最好不要勾选copy into project选项,否则后面单独修改工程内的文件必须去工程路径下慢慢找,不利于统一管理。
    在这里插入图片描述
  2. 约束文件先不添加,FPGA器件型号我手里是z7020 ,但是E906默认的bram是不够的,可以先选一个资源稍微丰富点的z045,后面工程里面再改回来。
    在这里插入图片描述
  3. 创建工程后,vivado已经大致帮我们整理好了各个文件之间的包含关系,整体目录结构和仿真过程的./simv -verdi显示得差不多。
    在这里插入图片描述
  4. 可以看到工程下有58个报错文件,随便点开几个文件看一下,都是提示引用的宏定义量没有定义。此时把Non-module Files下的xxxx.h文件全部设置为全局头文件类型。
    在这里插入图片描述
    稍作等待后,可以看到只剩下mnt.v 和tb.v两个报错文件。
    在这里插入图片描述
  5. 因为前面讲了这两个文件和uart_mnt都是用于仿真的,包含了很多不可综合语句,所以我们需要重新编写整个工程的顶层文件。

i. create design file , 命名为e906_top ,只把soc模块例化进去,注意输入输出和inout信号,可以参考下面的。

module e906_top(
    clk,
    rst_b,
    uart0_sin,
    uart0_sout,
    b_pad_gpio_porta,
    jclk,
    jrst_b,
    nrst_b,
    jtg_tdi,
    jtg_tdo,
    jtg_tms
 );
    input clk;
    input rst_b;
    input uart0_sin;
    output uart0_sout;
    inout[7:0] b_pad_gpio_porta;
    input jclk;
    input jrst_b;
    input nrst_b;
    input jtg_tdi;
    output jtg_tdo;
    input jtg_tms ;  
    
    //instantiate soc    
soc u_soc(
  .i_pad_clk            ( clk                  ),
  .i_pad_uart0_sin      ( uart0_sin            ),
  .o_pad_uart0_sout   	( uart0_sout           ),
  .i_pad_jtg_tclk       ( jclk                 ),
  .i_pad_jtg_trst_b     ( jrst_b               ),
  .i_pad_jtg_nrst_b     ( nrst_b               ),
  .b_pad_gpio_porta   	( b_pad_gpio_porta     ),
  .i_pad_jtg_tdi        ( jtg_tdi              ),
  .o_pad_jtg_tdo        ( jtg_tdo              ),
  .i_pad_jtg_tms        ( jtg_tms              ),   
  .i_pad_rst_b          ( rst_b                )
);

ii . disable 掉报错的tb 和 mnt模块,uart_mnt也禁能掉,都是仿真用的,其他的pa_spram也可以禁用掉,没报错不禁关系也不大。
在这里插入图片描述

iii .将刚才创建的e906_top设置为top,现在就可以跑SYNTHESIS了,注意没添加约束文件还不能跑implemention。
在这里插入图片描述
Utilization:
在这里插入图片描述
···
···
lut 占用 35.4k , ff 占用14.4k , bram用了384个;
这里也可以看到bram占用有点高,后面换到zynq7020等资源少一点的片子就不够用了,需要对源文件进行相应的修改。

3. 总结

本篇分析了项目的大致运行流程,并最后搭建了E906的基本FGPA工程,用过一些修改配置后完成了synthesis。下一篇将就进一步修改工程来适配具体的板子,并生成比特流下载进板。

  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
当将ASIC设计移植FPGA芯片时,需要进行一些重要的工作和优化。首先,ASIC设计的不同部分需要分别映射到不同的FPGA芯片中,通常以功能模块为划分边界。这个划分和优化的过程相对复杂,需要考虑系统成本、整体性能、资源容量、FPGA芯片之间的互联以及划分的复杂度等因素。 移植ASIC设计到FPGA芯片中需要进行大量的重编码和优化工作。尤其是时钟树结构,需要正确地分配到FPGA芯片的各种时钟资源上。这是一个非常具有挑战性的任务。 尽管FPGA工具和设计流程与ASIC相似,但是由于一些根本性的差异,工程师仍然需要解决一些问题。ASIC综合工具通常对Verilog语法的支持更宽松,而且ASIC和FPGA综合工具在引导语句和工具选项方面也有所不同。此外,无论是资源占用还是布线密度,ASIC工具需要处理的工作比FPGA复杂得多。在某些复杂情况下,FPGA工具甚至可能无法成功布局和布线。因此,在某些情况下,可能需要修改RTL源代码,甚至重新规划多芯片划分方案。 总结起来,将ASIC设计移植FPGA芯片中需要进行划分和优化工作,并需解决RTL源代码的重编码和时钟树结构的挑战。此外,需要注意ASIC和FPGA综合工具的差异,并可能需修改RTL源代码和重新规划多芯片划分方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [FPGA知识汇集-ASIC向FPGA移植](https://blog.csdn.net/mochenbaobei/article/details/128677191)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值