A Concise Guide to Makefile in Chip Design

What can Makefile do?

Makefile can execute commands based on specified dependency rules and whether files have been modified. It is commonly used to compile software source code, only recompiling modified files, which significantly speeds up the compilation process.

The Basic Format of Makefile

Target: Dependencies

Command

The target is the result to be generated, dependencies are the source files and results from the previous steps required to generate the result, command is the command executed when the target does not exist or when dependencies are updated. Note that commands must be indented with a tab, not spaces.

Example 1:

simv: tb.sv dut.v

vcs -full64 -sverilog tb.sv dut.v

In this example, simv is the target, which is the simulation executable we want to generate. tb.sv and dut.v are dependencies, and the command will first check whether tb.sv and dut.v exist and if they have been modified. When the dependency files have been modified, or the target does not exist, the command vcs -full64 -sverilog tb.sv dut.v will be executed to generate simv.

Phony Targets

Sometimes, targets are not real files to be generated. For example, we want to use Makefile to call simv for simulation, and there is no actual target file named sim. This situation is called a phony target.

Example 2:

sim: simv

./simv -xxx

In this example, sim is not a result file to be generated but just a name we give to the operation. Since phony targets never exist, the command will always be executed again, even if simv has not been modified.

We often explicitly indicate phony targets at the beginning of the Makefile using .PHONY.

Example 3:

.PHONY: sim

sim: simv

./simv -xxx

Thus, we can use make sim in the terminal to invoke the simulation command.

Default Target

If we simply type make (without specifying a target), it will call the first target in the Makefile. To prevent errors, we usually define the first target as all (to execute the complete process) or help (to display a help menu). I prefer the latter, as it can help us remember how to use the Makefile script.

Example 4:

.PHONY: help sim

help:

echo “make help”

echo “make simv to compile”

echo “make sim to run simulation”

simv: tb.sv dut.v

vcs -full64 -sverilog tb.sv dut.v

sim:

./simv -xxx

Thus, when we forget how to use the Makefile, simply typing make will display the usage help menu. Additionally, we can see that multiple commands can be executed after one target, as shown with the three echo commands here.

Suppressing Echo

Before executing commands, make will echo the commands (i.e., print out the commands). The above make help will output:

echo “make help”

make help

echo “make simv to compile”

make simv to compile

echo “make sim to run simulation”

make sim to run simulation

This looks a bit repetitive. Adding @ before the command can suppress the echo, which is exactly what we need. The improved Makefile is shown in Example 5.

Example 5:

.PHONY: help

help:

@echo “make help”

@echo “make simv to compile”

@echo “make sim to run simulation”

Defining Variables in Makefile

When there are many source files that frequently need to be added or removed, we can define the dependencies as a variable at the beginning of the file, as shown below.

Example 6:

tbfile := tb.sv env_pkg.sv test_pkg.sv

rtlfile := dut.v a.v b.v c.v

simv: $(tbfile) $(rtlfile)

vcs -full64 -sverilog $(tbfile) $(rtlfile)

When adding or removing files, you only need to modify the beginning of the file.

Calling Shell Commands

If there are too many rtl files, you can also call shell commands in the Makefile to help generate them. As shown in the example below:

Example 7:

tbfile := $(shell ls *.sv)

rtlfile := $(shell find rtl -name “*.v”)

simv: $(tbfile) $(rtlfile)

vcs -full64 -sverilog $(tbfile) $(rtlfile)

In Example 7, writing tb and rtl files twice is a bit cumbersome. It is better to simplify this. In Makefile, there are several special variables, such as $@ representing the target and $^ representing the dependencies. Thus, the command in Example 7 can be simplified as:

simv: $(tbfile) $(rtlfile)

vcs -full64 -sverilog $^

By now, you should be able to write most Makefile scripts.

Adding Options to Makefile

However, we also need to further learn two important features: options and directory recursion.

We often need to provide some options during simulation, such as testcase names, whether it is post-simulation, and whether to dump waveforms. So how do we achieve this? Actually, Makefile allows additional variables to be provided from the command line in the format OPTION=value. As shown in the example below, assuming there are three options, TC, POST, DUMP:

Example 8:

ifeq ($(POST),1)

SRC := “netlist.v”

else

SRC := “rtl.v”

endif

ifeq ($(DUMP),1)

DUMP_DEF := “+define+DUMP”

else

DUMP_DEF := “”

endif

sim:

@echo “vcs -full64 -sverilog $(SRC) $(DUMP_DEF) +UVM_TESTNAME=$(TC)”

Then, when using it, you can control the options from the command line:

make sim TC=basic_test

make sim TC=basic_test POST=1

make sim TC=basic_test DUMP=1

make sim TC=basic_test POST=1 DUMP=1

The Ultimate Weapon of Makefile: Directory Recursion

Another important feature is directory recursion, which has a typical application: make clean. When you run make clean in the top-level directory, it will automatically call make clean in the subdirectories. How is this achieved? See the example below:

Example 9:

./Makefile

clean:

rm -f *~

make -C a clean

make -C b clean

./a/Makefile

clean:

rm -f *~

./b/Makefile

clean:

rm -f *~

make -C c clean

./b/c/Makefile

clean:

rm -f *~

We see that a make -C subdir clean means that we can pass the target clean to the subdirectory, effectively calling another Makefile within the Makefile. This way, when we run make clean at the top level, it will automatically recurse into all subdirectories.

Referencing and Reusing Makefiles

Finally, we often encounter the practice of writing shared Makefile scripts into common.mk and then including common.mk, which can make the Makefile look cleaner.

Connection with IC Flow

By now, having learned so much, you can write some complex Makefiles. But the emphasis is on application; in IC design, we often use Makefiles to string together multiple tools to implement a complete flow. Below is an enlightening example.

Example 10:

.PHONY: help clean rtl lint sim syn lec pr pt lvs

help:

@echo “make help”

clean:

rm -rf *~ *.log *.fsdb csrc simv* …

make -C xxx clean

rtl:

python3 …

lint:

sg_shell/nLint …

sim:

vcs/irun …

syn:

dc_shell -64bit -topographical -f run_syn.tcl | tee log/syn.log

lec:

fm_shell/lec …

pt:

pt_shell …

pr:

innovus/icc …

lvs:

calibre …

Exercises:

According to your company’s situation, complete Example 10.

A Concise Guide to Makefile in Chip Design

Leave a Comment