记录,第一篇英文论文被引用

在看NoCS 2010的会议论文时偶然发现,我在NoCS 2009中发表的论文被今年的一篇会议论文引用。尽管是被当成了反面教材,也小小高兴一下。

C++低级错误

明知道模板使用的是编译时扩展的机制,却仍然把模板类的函数体写到了cpp文件里。链接出错我还纳闷呢。。。。唉

用NC-Verilog进行SystemC与Verilog HDL的混仿

    最近老是要测试自己的模块。前一段时间使用SystemVerilog写了个测试平台,还曾经在自己的Space里面推荐过。不过现在又回到用SystemC的思路上来。首先说说SystemVerilog的问题:
    首先要肯定SystemVerilog是一个很好的语言,提供了对Verilog完美的支持,提供了随机化测试向量生成的功能,提供了面向对象的事务级测试编写环境。但是,它的语法显得有些混乱,同时当前EDA软件对其的支持还不够。
    语法混乱的问题恐怕源于其对Verilog的支持,就像C++是C的超集一样,SystemVerilog作为Verilog HDL的超集也继承了类似静态成员之类的硬件概念,导致一个变量有着静态变量和栈变量的区别。如果没有深刻理解,仿真时的行为会很出人意料。另外一个延伸的问题是对对象的支持让人难以理解。SystemVerilog支持类的建立,但是类和module的连接限制很多,很多问题让人难以掌控。比如如何在一个对象中驱动一个端口给一个硬件模块。当然,接口模块(interface)提供了这样的接口,但真的使用的时候,我的感觉是被软件的语法和编译规则束缚了。有时明明觉得很简洁的代码被改得面目全非,仅仅是为了通过软件的编译规则。
    也许上面的问题也正是另外一个问题的直接结果。无论Synopsys还是Cadence现在都不能支持整个SystemVerilog标准,而且这两个公司所支持的标准子集还不尽相同。这样的直接结果就是一个按照SystemVerilog标准写出来的测试程序很可能不能通过软件的编译。修改测试程序也许可以通过软件的编译,但是这种改变还要取决于最终的软件编译器。我们需要根据Cadence或者Synopsys做不同的修改。
    SystemC的好处在于,它的运行库真实而完整的提供了标准规定的所有特性。这样就保证了一段SystemC代码在任何一个编译器下都能被正确编译。不过他并不是完美的。它是一个C++库,和HDL的连接需要第三方软件的支持。

下面回到正题,如何用NC-Verilog来进行SystemC和Verilog HDL的混仿。这里我假设SystemC被用于编写测试,被测模块(DUT)是一个Verilog HDL模块 (VHDL也没有问题,不过相对复杂)。
1. 和在Verilog中实例化一个黑盒子模块一样,Verilog模块对于SystemC来说也是一个黑盒子,也需要一个黑盒子模块定义。比如一下一个简单模块

module dut ( clk, rstn, d_in, d_out);
input clk, rstn;
input [7:0] d_in;
output [7:0] d_out;
reg [7:0] d_out;
always @(posedge clk or negedge rstn)
if(!rstn)
  d_out <= 0;
else
  d_out <= d_in;
endmodule

它在SystemC中的黑盒子定义为:

File dut.h:
#include "systemc.h"

class dut : public ncsc_foreign_module {
public:
        sc_in < sc_logic > clk;
        sc_in < sc_logic > rstn;
        sc_in < sc_lv <8> > d_in;
        sc_out < sc_lv <8> > d_out;

        dut(
                sc_module_name nm
        ) : ncsc_foreign_module(nm)
                , clk("clk")
                , rstn("rstn")
                , d_in("d_in")
                , d_out("d_out")

        {
        }

        const char* hdl_name() const { return "dut"; }
};

File dut.cpp:
#include "dut.h"

可以看到,所有的端口都被翻译成sc_logic和sc_lv。dut本身是一个ncsc_foreign_module寄生类。这里ncsc_foreign_module就能让NC-Verilog知道这个模块并非SystemC类。生成这个黑盒子定义其实不需要写代码,NC-Verilog提供了一个命令来完成:

ncshell –import verilog –into systemc dut

不过运行之前需要先编译dut的Verilog模块。

2. 有了Verilog模块的黑盒子定义,剩下来的事情就好办了。该黑盒子定义可以作为普通的SystemC类使用于测试环境中。

3. 编译这个混仿的工程有点麻烦。我假设我有一个SystemC的测试环境代码test.h和test.cpp。以下就是在IUS 8.2中编译整个工程的脚本:

export NCSC_GCC=${CDS_LNX86_ROOT}/ius8.2/tools/systemc/gcc/bin/g++

CXXFLAG="-c -g -Wall"

#compile verilog files
ncvlog dut.v

#compile SystemC files
ncsc -compiler $NCSC_GCC -cflags "${CXXFLAG}" test.cpp
ncsc -compiler $NCSC_GCC -cflags “${CXXFLAG}" dut.cpp

#generate the shared library
${NCSC_GCC}  -Wl -shared -o sysc.so -L${CDS_LNX86_ROOT}/ius8.2/tools/lib
dut.o test.o
${CDS_LNX86_ROOT}/ius8.2/tools/systemc/lib/gnu/libncscCoSim_sh.so
${CDS_LNX86_ROOT}/ius8.2/tools/systemc/lib/gnu/libncscCoroutines_sh.so
${CDS_LNX86_ROOT}/ius8.2/tools/systemc/lib/gnu/libsystemc_sh.so

ncelab -timescale 1ns/1ps -access +rwc -loadsc sysc.so worklib.sc_main

首先编译所有的Verilog和SystemC文件。生成动态连接库的过程有点特别。SystemC代码参与NCSIM的仿真可以使用静态或者动态的两种方式。ncelab将所有的模块连接起来时,需要使用-loadsc参数读取生成的动态连接库。在这些都完成后,就可以使用

ncsim –tcl worklib.sc_main

来运行混仿。

以下是我对整个过程的一些建议:
1. 不要用ncsc_run脚本。尽管该脚本省去了以上编写脚本生成动态连接库的麻烦,但是脚本背后的过程还是一样的。如果不明白其内部过程,编译中出现的错误信息会很迷惑。第一次搭建仿真平台的时候使用如我所写的脚本也许能刚方便的找到编译错误。
2. 某些时候会报出找不到/lib/gnu下的so文件,这是因为IUS在安装之后没有正确运行配置程序。请联系你的软件管理员重新配置ISU软件。
3. 在所有的时候调用一个SystemC模块都应该把库的名称带上,比如sc_main应该写成worklib.sc_main。否则会出现进程终止的错误(也许是软件的bug)
4. 出现了软件内部错误往往也是SystemC代码导致的。所以ncsc编译的时候应该加上-g参数,方便生成调试信息。无论是ncelab还是ncsim其实都可以用gdb来调试。实在没有办法的时候不妨一试。
5. 建议在SystemC内部使用sc_uint类型代替sc_lv。sc_uint为bool逻辑,而sc_lv为4值逻辑(0, 1, Z, X)。在SystemC中使用4值逻辑有时会带来很可笑的结果,比如读到了X而导致仿真中止。读取一个sc_lv或者sc_logic请这么做

rd_value = versig.read().is_01() ? versig.read() : 0;

这样就能防止出现X态的问题。
6. 读入sdf文件也许有点小麻烦。我的建议是在Verilog那一端写一个顶层模块,连接所有的端口并读入sdf文件。
7. 用GUI方式仿真在我这里总是失败,我猜可能是我少连接了一些库。有解决办法的人请告诉我。
8. 使用TLM 2.0的话需要连接一些其他的库,具体请参阅文档。
9. IUS中关于SystemC的文档:doc/ncscsim 和doc/ncscref

在Linux上安装无内核支持的Xilinx USB Cable

Xilinx自带的USB Cable驱动程序需要安装windrvr驱动模块,其过程中需要根据内核代码重新编译驱动。而这个重新编译的过程在很多使用最新内核的Linux上失败,特别是使用2.6.18以上内核版本的Linux。显然我们不可能降级内核来安装一个驱动程序。不过幸运的是,外国的Geek们借助于libusb找到了一个不用重新编译内核的方法。以防以后忘记,也为了遇到同样问题的兄弟们,我特地将这个安装过程翻译成中文。需要特别的感谢我们组内的助研Lilian Janin博士提供网站地址(我显然没有这么执着地去找一条非官方的解决办法)。英文的相关内容参看:
http://svenand.blogdrive.com/archive/55.html
http://www.rmdir.de/~michael/xilinx/

具体方法如下:
1. 安装libusb-dev开发包。在Fedora上可以 yum install libusb-devel
2. 下载usb-driver-HEAD驱动程序。
3. 解压缩该驱动程序,编译该驱动程序,生成libusb-driver.so动态连接库
4. 将libusb-driver.so拷贝到/usr/lib  (安装到默认的链接库目录)
5. 在shell的环境中使能该链接库 (在bash中,可以在.bashrc中加上 export LD_PRELOAD=/usr/lib/libusb-driver.so)
6. 在/etc/udev/rules.d文件夹中添加一个新的规则文件50-xilinx-usb-pav.rules
7. 在新的规则文件中加入一条新规则 ACTION=="add",BUS=="usb",SYSFS{idVendor}=="03fd",MODE="666" (在50-xilinx-usb-pav.rules 文件中写入这一行语句)
8. 重新启动udev服务 (sudo /etc/init.d/udev restart)(也可能是其他的命令或者其他的位置,取决于Linux的版本)
9. 连接USB Cable并使用/sbin/lsusb查看所有的usb设备,如果有
    Bus 002 Device 002: ID 03fd:0008 Xilinx, Inc.
    或者类似的设备(有Xilinx, Inc)说明设备被识别并可工作了
10. 在ISE中使用该Cable还需fxload软件包 yum install fxload

如果一切顺利,现在USB Cable的连接灯应该已经亮了。如果还是有问题,就需要采取一些其他的特别操作。请参看http://svenand.blogdrive.com/archive/55.html