当前位置: 首页 > 工具软件 > Verilator > 使用案例 >

verilator编译 更新文件的规则

桂梓
2023-12-01

本文请读者【直接关闭】,我后面的实践结果似乎和本文的实践结果不一样,真是见鬼了!我不知道发生了什么,还没有来得及进一步校验!

在其他文件不变的前提下,如果即将生成的mk文件和已有的mk文件不一样,就更新全部的源文件

这个事情说起来就有点诡异了,我们解释一下

  1. 我们只使用--exe,完成到生成全部的源文件,以及获取生成可执行文件的makefile文件这一步
  2. 编译的命令保持不变,例如 verilator --cc --exe Top.v main.cpp
  3. 命令中提及的文件全都保持不变,例如Top.v main.cpp,这里的保持不变,是指其时间戳保持不变
  4. 对于生成的VTop.mk文件,是本次测试唯一的变量,我们接下来看一看
测试一:不改变mk文件

假设,我们已经运行了指令verilator --cc --exe Top.v main.cpp,生成了相关的文件。

接下来:

首先,我们运行

ls obj_dir/ --full-time > 1.txt

把测试前的文件时间戳存储起来

total 128
-rw-rw-r-- 1 jht jht 19595 2022-04-17 11:44:49.941869470 +0800 VTop___024root.cpp
-rw-rw-r-- 1 jht jht  1846 2022-04-17 11:44:49.941869470 +0800 VTop___024root.h
-rw-rw-r-- 1 jht jht 11606 2022-04-17 11:44:49.941869470 +0800 VTop___024root__Slow.cpp
...

这里展示一小部分,太多了没必要展示。

接下来,我们再次运行verilator --cc --exe Top.v main.cpp,然后运行ls obj_dir/ --full-time > 2.txt,把新的时间戳存储起来。

紧接着,使用colordiff 1.txt 2.txt 进行对比,没有任何输出,说明前后文件时间戳完全一样,这意味着,第二次运行的指令,没有导致生成结果的更新!

要知道,生成的结果

  1. 是从外面其他文件(c/cpp)拷贝过来的
  2. 是编译Verilog文件生成的

而第二次没有更新,没有重新编译和拷贝,证明verilator本身是有检测机制的,不会每次无脑编译更新

测试2:修改mk文件

接下来,做一个新的测试。

假设,我们已经运行了指令verilator --cc --exe Top.v main.cpp,生成了相关的文件。

  1. 运行ls obj_dir/ --full-time > 1.txt
  2. 修改VTop.mk文件,比如给其任意位置,加一个注释,运行sed -i "1 i # test" obj_dir/VTop.mk或者手动修改该文件
  3. 再次运行verilator --cc --exe Top.v main.cpp
  4. 运行ls obj_dir/ --full-time > 2.txt
  5. 使用colordiff 1.txt 2.txt 进行对比

神奇的事情发生了!,所有的源文件,都被修改了时间戳,也就是说这些源文件都是新生成或者新拷贝的!

2,16c2,16
< -rw-rw-r-- 1 jht jht 19595 2022-04-17 11:52:02.256126245 +0800 VTop___024root.cpp
< -rw-rw-r-- 1 jht jht  1846 2022-04-17 11:52:02.252126217 +0800 VTop___024root.h
< -rw-rw-r-- 1 jht jht 11606 2022-04-17 11:52:02.256126245 +0800 VTop___024root__Slow.cpp
...
---
> -rw-rw-r-- 1 jht jht 19595 2022-04-17 11:52:16.824228142 +0800 VTop___024root.cpp
> -rw-rw-r-- 1 jht jht  1846 2022-04-17 11:52:16.824228142 +0800 VTop___024root.h
> -rw-rw-r-- 1 jht jht 11606 2022-04-17 11:52:16.824228142 +0800 VTop___024root__Slow.cpp
...

这里只展示一部分,事实上,是所有的源文件都更新了。

另外经过测试,给mk文件加个空行也可以达到该效果。

这就意味着什么呢……至少

在生成文件更新的检测机制上,verilator会检测,当前命令生成的mk文件和已有的mk文件是否有不同,如果不同,就重新生成和更新全部源文件。
实验3:仅修改Verilog文件

这里,同样是命令verilator --cc --exe Top.v main.cpp,我们单独修改Top.v,再查看前后对比结果。

发现也是全部更新源文件,和上面一样。

实验4:仅修改cpp文件

仅仅修改main.cpp

NOTE:不会更新!

因为cpp文件没有被拷贝进去,而是直接编译的外面的源文件。

实验5:修改obj_dir中任意一个文件(生成的源文件)

随便修改一个文件,前后对比,发现仍然是更新全部源文件。

结论

经过这么多的测试,你就应该明白了,对于verilator的--cc --exe阶段,也就是生成可执行文件之前的阶段,无论你是修改命令中给出的源文件(指Verilog源文件,c/cpp不算),还是修改生成之后的任意一个文件,都会导致下一次重新运行该命令的时候,全部重新编译和更新。

注意,修改生成的文件,是指的运行VTop.mk之前的那些文件,运行make之后生成内些文件不会跟着更新,它们的更新依靠的是make规则。

应用

好了,这个在文档没有找到,估计只能在源码中找了,先不管,反正测试结果就是这样!

我们看一下,这个特性能够让我们有什么应用呢?

  1. VTop.mk文件,生成VTop的规则,是依赖于obj_dir文件夹中源文件的,外部文件它是不管的!
  2. 如果你引入了外部生成的.o文件,这个文件不会被放在obj_dir文件夹中,只是在VTop.mk中提供外部.o文件的路径,以供链接使用
  3. 也就是说,如果你更新了外部的.o文件,按照生成规则来说,verilator的不知道这件事的,它会默认你的.o文件是一直不变的,这就意味着,你需要额外的规则来改变这件事
  4. 我们的放在工程,会在外部直接编译.c文件到.o文件,但是verilator不知道这件事,我们有两种方法
    1. 强制每次都重新编译Verilog和拷贝cpp源文件,这种方式就用了我们上面提到的那个特点,你只需要编译完成之后,再给VTop.mk随便编辑一下,下一次编译一定会全部更新的。但是这样似乎不太好……
      2.通过makefile来执行编译指令,并且识别.o文件是否更新,如果更新,则可以
      1. 强制编译和更新源文件,但是没有必要这么做,毕竟其他文件又没变
      2. 删除掉生成的VTop可执行文件,重新进行链接即可。这种方式是可取的,如果其他的都没变的话,只是外部的.o文件改变,只需要重新链接就可以

加粗部分,是提倡采取的方案。

下面是提供的复杂工程的示例

simulate
├── csrc # c/cpp 源文件和可重定位目标文件
│   ├── build # 由 .c 文件生成,.o文件提供给verilator
│   │   ├── memory
│   │   │   └── mem.o
│   │   └── monitor
│   │       ├── monitor.o
│   │       └── sdb
│   │           └── sdb.o
│   ├── include # 头文件
│   │   ├── common.h
│   │   ├── main.h
│   │   └── mem.h
│   ├── main.cpp # 提供给verilator的cpp文件
│   ├── Makefile  # 生成 build 的规则
│   ├── memory  # c 源文件
│   │   └── mem.c
│   ├── monitor
│   │   ├── monitor.c
│   │   └── sdb
│   │       └── sdb.c
│   └── utils
├── Makefile # verilator编译和生成规则
└── obj_dir   # verilator生成目录
# 备注:Verilog文件在其他路径,可由verilator来指定位置和文件
 类似资料: