前言
当FPGA开发者需要做RTL和C/C++联合仿真的时候,一些常用的方法包括使用MicroBlaze软核,或者使用QEMU仿真ZYNQ的PS部分。
此教程介绍一种通过SystemC做RTL/C/C++联合仿真的方法,所有的BFMs(Bus Function Module)都是通过SystemC完成。
文中所涉及的所有代码均在Vivado和Modelsim/Questasim上做了验证。
简介
SystemC基础
SystemC是标准C/C++语言的延伸,即可以描述硬件,也具有C/C++的特性。这个特点让SystemC特别适合做系统级别的设计、建模以及验证。
SystemC是周期精确的,其主要的组包括
信号,用来连接两个或者多个模块,提供了传输系统间传输与交流数据的通道。
模块,类似VHDL里面的Entity和敏感列表。
主函数(sc_main),与C/C++一致,函数的入口。
在SystemC中实例化一个RTL的实体
在SystemC中实例化一个RTL的实体很直观,你只需要为其RTL实体手写一个对应的SystemC的外部模块,之后这个模块就可以在SystemC的环境被被其它类调用。
下面将举例说明如果在SystemC中构建一个VHDL的实体
示例 VHDL的设计
entitycounteris port( clk:instd_logic; reset:instd_logic; count:std_logic_vector(7downto0) ); end; architecturertlofcounteris … endrtl;
对应的SystemC模块
classcounter:publicsc_foreign_module{ public: sc_inclk; sc_inreset; sc_out>count; counter(sc_module_namenm):sc_foreign_module(nm,"work.counter"), clk("clk"), reset("reset"), count("count"){ } };
需要注意的是,你还可以通过ModelSim/QuestaSim提供的scgenmod工具自动生成VHDL、Verilog对应的SystemC的模块。
用SystemC设计BFMs
因为SytemC是通过时钟驱动的, 在SystemC里面写BFMs就变得很直接在SystemC中实现AXI4-Lite的读操作可以如下,
u32Xil_In32(UINTPTRAddr){ u32data; if(aresetn_i.read()==SC_LOGIC_0){ awaddr.write(0); awvalid.write(SC_LOGIC_0); wdata.write(0); wvalid.write(SC_LOGIC_0); bready.write(SC_LOGIC_1); araddr.write(0); arvalid.write(SC_LOGIC_0); rready.write(SC_LOGIC_1); } else{ sc_core::wait(aclk_i.posedge_event()); araddr.write(addr); arvalid.write(SC_LOGIC_1); uint32_tnum_clocks=0; while(arready.read()!=SC_LOGIC_1){ sc_core::wait(aclk_i.posedge_event()); num_clocks++; if(num_clocks==m_timeout_clks){ arvalid.write(SC_LOGIC_0); return-1; } } arvalid.write(SC_LOGIC_0); num_clocks=0; while(rvalid.read()!=SC_LOGIC_1){ sc_core::wait(aclk_i.posedge_event()); num_clocks++; if(num_clocks==m_timeout_clks){ return-1; } } data=rdata.read().to_uint(); } returndata; }
在SystemC中实现AXI4-Lite的写操作可以如下
voidXil_Out32(UINTPTRAddr,u32Value){ if(aresetn_i.read()==SC_LOGIC_0){ awaddr.write(0); awvalid.write(SC_LOGIC_0); wdata.write(0); wvalid.write(SC_LOGIC_0); bready.write(SC_LOGIC_1); araddr.write(0); arvalid.write(SC_LOGIC_0); rready.write(SC_LOGIC_1); } else{ sc_core::wait(aclk_i.posedge_event()); awaddr.write(Addr); awvalid.write(SC_LOGIC_1); wdata.write(Value); wvalid.write(SC_LOGIC_1); uint32_tnum_clocks=0; boolm_awready=false; boolm_wready=false; while((!m_awready)||(!m_wready)){ sc_core::wait(aclk_i.posedge_event()); if(awready.read()==SC_LOGIC_1){ m_awready.write(true); awvalid.write(SC_LOGIC_0); } if(wready.read()==SC_LOGIC_1){ m_wready.write(true); wvalid.write(SC_LOGIC_0); } num_clocks++; if(num_clocks==m_timeout_clks){ awvalid.write(SC_LOGIC_0); wvalid.write(SC_LOGIC_0); return; } } num_clocks=0; while(bvalid.read()!=SC_LOGIC_1){ sc_core::wait(aclk_i.posedge_event()); num_clocks++; if(num_clocks==m_timeout_clks){ return; } } } }
系统设计框图
完整的系统框图如下所示。清楚的展示是SystemC /DUT之间的调用关系。
软件需求
在教程中,需要以下设计工具
Vivado Design Suite
Modelsim/Questasim
预先编译的Vivado IP的仿真库
示例工程
打开Vivado,创建一个空的工程。
在Vivado里面,打开Create and Package New IP wizard,选择Create a new AXI4 peripheral,之后create an AXI4 peripheral using the default template。
使用scgenmod指令创建SystemC的外部模块。
重写xil_io.c文件,其实现是通过上面介绍的SystemC完成BFMs的方法。
编译,连接。最后运行vsim。
测试结果
以下是Questasim的仿真结果,通过打印的信息可以看到 RTL和C/C++的联合仿真功能的运行。
#vsim-t1psxil_defaultlib.Envxil_defaultlib.glbl-onfinishstop-Lxpm-Lunisims_ver-Lsecureip-Lunimacro_ver-Lxil_defaultlib-lsimlog.txt-assertdebug #****************************** #*UserPeripheralSelfTest #****************************** #Userlogicslavemoduletest... # #-slaveregisterwrite/readpassed # #**Note:(vsim-6574)SystemCsimulationstoppedbyuser.
审核编辑:汤梓红
-
FPGA
+关注
关注
1624文章
21608浏览量
601088 -
仿真
+关注
关注
50文章
4015浏览量
133317 -
RTL
+关注
关注
1文章
385浏览量
59655 -
C++
+关注
关注
21文章
2096浏览量
73447 -
systemc
+关注
关注
2文章
25浏览量
14538
发布评论请先 登录
相关推荐
评论