makefile脚本写了好久了,在这里记录一下makefile的使用和心得。
在我的理解里,makefile只是对于在Linux工作站中,对C/C++文件进行编译和链接生成结果的一个工具,make实现的是最简单的自动化编译功能,具体可以参考《跟我一起写 Makefile》-陈皓著这本书,书里面详细讲解了如何编写makefile文件(是以c/c++为例的),我也是通过学习这本书,掌握如何编写makefile文件的。
这里我不介绍makefile的基本知识,而是结合脚本的需求,来说明我编写脚本的步骤。
1,准备工作
这里我们用vcs来作为仿真工具来说明,对于其他工具方式相同。
1.1vcs的编译命令:
VCS = vcs \
-full64 \
-sverilog \
-ntb_opts uvm-1.1 \
-debug_pp \
-lca \
-P ${VERDI_HOME}/share/PLI/VCS/LINUX64/novas.tab \
${VERDI_HOME}/share/PLI/VCS/LINUX64/pli.a \
-l vcs.log
1.2 USER_DEFINE:
通常在仿真时,需要加入一些用户自定义的define,这部分可以通过参数的方式,从terminal获取
USER_DEFINE = +define+ABCDEF \
+define+aabbcc \
+define+abcdef \
+define+$(ABC)
1.3包含编译文件:
这里的处理方式有所不同,有的人会通过incdir的方式将整个文件夹都包含进来,有人会吧所有需要incldue的文件都放在一个include文件里,各有各的好处,如果懒惰一点直接incdir吧,并且对于一个大项目的通用脚本来讲,在编译和仿真不同子模块时,采用incdir这种方式会更方便,但是按照后一种方式也可以做,就是稍微麻烦一点。
USER_INCDIR = $(PROJECT_DIR)/$(TB)/$(MODULE_NAME)
1.4 UVM和波形生成需要添加的define
与添加USER_DEFINE是一样的,这块对UVM来说仿真时必须添加的一些宏定义,以及在sim_top中调用fsdb波形生成的函数:$fsdbAutoSwitchDumpfile()和$fsdbDumpvars()必须添加-fsdb这条命令。
OTHER_DEFINE = +define+fsdb \
+define+UVM_REG_DATA_WIDTH=1024 \
+define+UVM_PACKER_MAX_BYTES=1500000 \
+define+UVM_DISABLE_AUTO_ITEM_RECORDING \
+define+SYNOPSYS_SV
2,check
我们在这一步检查的目的主要是用来检查,我们要生成的目录是否存在,如果不存在需要重新生成 。
check:
ifeq($(TC_RESULT_DIR),)
##@echo "path not exist"
mkdir -p $(TC_RESULT_DIR)
else
@echo $(TC_RESULT_DIR)
3,VCS编译
代码如下:
comp: mkdir check
cd $(TC_RESULT_DIR) && $(TOOL) $(USER_DEFINE) $(OTHER_DEFINE) $(USER_INDIR) -TOP $(TOP) -f $(USER_F)
4,VCS仿真
仿真与编译类似,需要一整套完整的参数,代码如下:
SIM = simv \
-l simv.log \
+UVM_TESTNAME=$(TC_NAME) \
+UVM_VERBOSITY=$(VERBOSITY) \
+ntb_random_seed=$(TC_SEED) \
仿真命令如下:
sim:
cd $(TC_RESULT_DIR) &&$ (SIM)
5,verdi的打开命令
对于verdi的打开命令和vcs的编译命令类似,可以直接用,命令如下:
verdi:
cd $(TC_RESULT_DIR) && $(VERDI_RUN) -top $(TOP) $(USER_DEFINE) $(OTHER_DEFINE) $(USER_INCDIR) -f $(USER_F) +UVM_TESTNAME=$(TC_NAME)
最后,根据makefile的特性,我们可以用一条命令,将上面整个过程的多条命令全部代替(这是由makefile的本身的命令的依赖关系决定的),如下:
all: clean check comp sim
对于clean命令,一般我们都需要删除旧的仿真环境,然后在生成一个新的编译和仿真环境,但是对于clean的方式也有多种,最粗暴的办法就是直接删掉整个文件夹,这种方法显然是不可取的,但是也是最快的办法,另外一种方式,就是和check的方式相同,每次当我需要重新生成一套环境时,根据输入的参数决定,是需要删掉旧的生成一个新的环境,还是重新生成一个仿真结果而保留原有的环境。
6,clean命令
clean:
rm -rf $(TC_RESULT_DIR)/*
这种方式时最粗暴的,调试前期可以用这种简单直接的办法
对于第二种办法,我们可以将判断是否新建仿真环境的方式放到check里面,放到clean里面也可以,但是个人推荐放到check里。
clean:
ifeq($(GEN),-n)
@echo "new $(testname), new dir"
mkdir -p $(TC_RESULT_DIR_FINAL)
else ifeq($(GEN),-c)
rm -rf $(TC_RESULT_DIR)/*
添加一个变量 GEN 表示仿真的方式,是-n就是生成一个新的,需要重新指定文件夹,这个个人可以有自己的新策略,-c就是clean所有重新生成的意思。
到这里我们又会有人想了,我就想重新生成到同一个目录里,我也不想删了现在的目录重新弄一个,这种方式也是可以的,那我们就需要借助 shell或者其他任何脚本语言,给makefile指定你要保存的目录即可,如下:
WORK_DIR = $(shell find -P ${PROJECT}/work/${TESTNAME} - type d -name '*sim*')
这样就利用shell脚本将仿真的目录指定到 *sim*匹配到的目录里了,那么问题来了,如果你文件夹里面有多个文件夹被匹配到了呢?那shell脚本会匹配“就近的”文件夹中。
Makefile虽然简单好用,但是同样的也有局限性,如果你想要批量的提交job到工作站,该怎么做,我目前还没有想到好办法,但是如果是使用perl或者python,那么多线程可以解决这个问题,同样的这些脚本也有一些其他的限制,这里暂且不表,到写这些脚本的使用时也会提到。好了,以上就是所有关于makefile编写仿真脚本的内容,希望能帮助到你们。