diff --git a/target/common/common.mk b/target/common/common.mk
index f890017bd..faf66fe41 100644
--- a/target/common/common.mk
+++ b/target/common/common.mk
@@ -44,15 +44,9 @@ VLT_ROOT        ?= ${VERILATOR_ROOT}
 VLT_JOBS        ?= $(shell nproc)
 VLT_NUM_THREADS ?= 1
 
-MATCH_END := '/+incdir+/ s/$$/\/*\/*/'
-MATCH_BGN := 's/+incdir+//g'
-MATCH_DEF := '/+define+/d'
-SED_SRCS  := sed -e ${MATCH_END} -e ${MATCH_BGN} -e ${MATCH_DEF}
-
 COMMON_BENDER_FLAGS += -t rtl -t snitch_cluster
 
 VSIM_BENDER   += $(COMMON_BENDER_FLAGS) -t test -t simulation -t vsim
-VSIM_SOURCES   = $(shell ${BENDER} script flist-plus ${VSIM_BENDER} | ${SED_SRCS})
 VSIM_BUILDDIR ?= work-vsim
 VSIM_FLAGS    += -t 1ps
 ifeq ($(DEBUG), ON)
@@ -65,7 +59,6 @@ endif
 # VCS_BUILDDIR should to be the same as the `DEFAULT : ./work-vcs`
 # in target/snitch_cluster/synopsys_sim.setup
 VCS_BENDER   += $(COMMON_BENDER_FLAGS) -t test -t simulation -t vcs
-VCS_SOURCES   = $(shell ${BENDER} script flist-plus ${VCS_BENDER} | ${SED_SRCS})
 VCS_BUILDDIR := work-vcs
 
 # fesvr is being installed here
@@ -73,7 +66,6 @@ FESVR         ?= ${MKFILE_DIR}work
 FESVR_VERSION ?= 35d50bc40e59ea1d5566fbd3d9226023821b1bb6
 
 VLT_BENDER   += $(COMMON_BENDER_FLAGS) -DCOMMON_CELLS_ASSERTS_OFF
-VLT_SOURCES   = $(shell ${BENDER} script flist-plus ${VLT_BENDER} | ${SED_SRCS})
 VLT_BUILDDIR := $(abspath work-vlt)
 VLT_FESVR     = $(VLT_BUILDDIR)/riscv-isa-sim
 VLT_FLAGS    += --timing
@@ -88,7 +80,7 @@ VLT_FLAGS    += -Wno-UNSIGNED
 VLT_FLAGS    += -Wno-UNOPTFLAT
 VLT_FLAGS    += -Wno-fatal
 VLT_FLAGS    += --unroll-count 1024
-VLT_FLAGS	   += --threads $(VLT_NUM_THREADS)
+VLT_FLAGS	 += --threads $(VLT_NUM_THREADS)
 VLT_CFLAGS   += -std=c++20 -pthread
 VLT_CFLAGS   += -I $(VLT_FESVR)/include -I $(TB_DIR) -I ${MKFILE_DIR}test
 
@@ -167,15 +159,6 @@ $(VLT_BUILDDIR)/lib/libfesvr.a: $(VLT_FESVR)/${FESVR_VERSION}_unzip
 	mkdir -p $(dir $@)
 	cp $(dir $<)libfesvr.a $@
 
-#######
-# VCS #
-#######
-$(VCS_BUILDDIR)/compile.sh:
-	mkdir -p $(VCS_BUILDDIR)
-	${BENDER} script vcs ${VCS_BENDER} --vlog-arg="${VLOGAN_FLAGS}" --vcom-arg="${VHDLAN_FLAGS}" > $@
-	chmod +x $@
-	$(VCS_SEPP) $@ > $(VCS_BUILDDIR)/compile.log
-
 ########
 # Util #
 ########
diff --git a/target/common/vcs.mk b/target/common/vcs.mk
new file mode 100644
index 000000000..0c477c09f
--- /dev/null
+++ b/target/common/vcs.mk
@@ -0,0 +1,37 @@
+# Copyright 2024 ETH Zurich and University of Bologna.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+VCS_TOP_MODULE = tb_bin
+
+$(VCS_BUILDDIR):
+	mkdir -p $@
+
+$(VCS_BUILDDIR)/compile.sh: $(BENDER_YML) $(BENDER_LOCK) | $(VCS_BUILDDIR)
+	$(BENDER) script vcs $(VCS_BENDER) --vlog-arg="$(VLOGAN_FLAGS)" --vcom-arg="$(VHDLAN_FLAGS)" > $@
+	chmod +x $@
+
+# Generate dependency file with RTL sources and headers using Verilator
+$(VCS_BUILDDIR)/$(VCS_TOP_MODULE).d: $(BENDER_YML) $(BENDER_LOCK) $(GENERATED_RTL_SOURCES) | $(VCS_BUILDDIR)
+	$(VLT) $(shell $(BENDER) script verilator $(VCS_BENDER)) \
+		--Mdir $(VCS_BUILDDIR) --MMD -E --top-module $(VCS_TOP_MODULE) > /dev/null
+	mv $(VCS_BUILDDIR)/V$(VCS_TOP_MODULE)__ver.d $@
+	sed -i 's|^[^:]*:|$(BIN_DIR)/$(TARGET).vcs:|' $@
+
+# Run compilation script and create VCS simulation binary
+$(BIN_DIR)/$(TARGET).vcs: $(VCS_BUILDDIR)/compile.sh $(TB_CC_SOURCES) $(RTL_CC_SOURCES) work/lib/libfesvr.a | $(BIN_DIR)
+	$(VCS_SEPP) $< > $(VCS_BUILDDIR)/compile.log
+	$(VCS) -Mlib=$(VCS_BUILDDIR) -Mdir=$(VCS_BUILDDIR) -o $@ -cc $(CC) -cpp $(CXX) \
+		-assert disable_cover -override_timescale=1ns/1ps -full64 $(VCS_TOP_MODULE) $(TB_CC_SOURCES) $(RTL_CC_SOURCES) \
+		-CFLAGS "$(TB_CC_FLAGS)" -LDFLAGS "-L$(FESVR)/lib" -lfesvr
+
+# Clean all build directories and temporary files for VCS simulation
+.PHONY: clean-vcs
+clean-vcs: clean-work
+	rm -rf $(BIN_DIR)/$(TARGET).vcs $(VCS_BUILDDIR) vc_hdrs.h
+
+clean: clean-vcs
+
+ifneq ($(filter-out clean%,$(MAKECMDGOALS)),)
+-include $(VCS_BUILDDIR)/$(VCS_TOP_MODULE).d
+endif
diff --git a/target/common/verilator.mk b/target/common/verilator.mk
index eb02ee346..518a71de8 100644
--- a/target/common/verilator.mk
+++ b/target/common/verilator.mk
@@ -2,16 +2,29 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
-$(BIN_DIR)/$(TARGET).vlt: $(VLT_SOURCES) $(TB_CC_SOURCES) $(VLT_CC_SOURCES) $(VLT_BUILDDIR)/lib/libfesvr.a | $(BIN_DIR)
+VLT_TOP_MODULE = testharness
+
+# Generate dependency file with RTL sources and headers using Verilator
+$(VLT_BUILDDIR)/$(VLT_TOP_MODULE).d: $(BENDER_YML) $(BENDER_LOCK) $(GENERATED_RTL_SOURCES) | $(VLT_BUILDDIR)
+	$(VLT) $(shell $(BENDER) script verilator $(VLT_BENDER)) \
+		--Mdir $(VLT_BUILDDIR) --MMD -E --top-module $(VLT_TOP_MODULE) > /dev/null
+	mv $(VLT_BUILDDIR)/V$(VLT_TOP_MODULE)__ver.d $@
+	sed -i 's|^[^:]*:|$(BIN_DIR)/$(TARGET).vlt:|' $@
+
+$(BIN_DIR)/$(TARGET).vlt: $(TB_CC_SOURCES) $(VLT_CC_SOURCES) $(VLT_BUILDDIR)/lib/libfesvr.a | $(BIN_DIR)
 	$(VLT) $(shell $(BENDER) script verilator $(VLT_BENDER)) \
 		$(VLT_FLAGS) --Mdir $(VLT_BUILDDIR) \
 		-CFLAGS "$(VLT_CFLAGS)" \
 		-LDFLAGS "$(VLT_LDFLAGS)" \
 		-j $(VLT_JOBS) \
-		-o ../$@ --cc --exe --build --top-module testharness $(TB_CC_SOURCES) $(VLT_CC_SOURCES)
+		-o ../$@ --cc --exe --build --top-module $(VLT_TOP_MODULE) $(TB_CC_SOURCES) $(VLT_CC_SOURCES)
 
 .PHONY: clean-vlt
 clean-vlt: clean-work
 	rm -rf $(BIN_DIR)/$(TARGET).vlt $(VLT_BUILDDIR)
 
 clean: clean-vlt
+
+ifneq ($(filter-out clean%,$(MAKECMDGOALS)),)
+-include $(VLT_BUILDDIR)/$(VLT_TOP_MODULE).d
+endif
diff --git a/target/common/vsim.mk b/target/common/vsim.mk
index 38019240b..d5d05495d 100644
--- a/target/common/vsim.mk
+++ b/target/common/vsim.mk
@@ -2,34 +2,47 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
+VSIM_TOP_MODULE = tb_bin
+
 $(VSIM_BUILDDIR):
 	mkdir -p $@
 
-$(VSIM_BUILDDIR)/compile.vsim.tcl: $(BENDER_LOCK) | $(VSIM_BUILDDIR)
+$(VSIM_BUILDDIR)/compile.vsim.tcl: $(BENDER_YML) $(BENDER_LOCK) | $(VSIM_BUILDDIR)
 	$(VLIB) $(dir $@)
 	$(BENDER) script vsim $(VSIM_BENDER) --vlog-arg="$(VLOG_FLAGS) -work $(dir $@) " > $@
 	echo '$(VLOG) -work $(dir $@) $(TB_CC_SOURCES) $(RTL_CC_SOURCES) -vv -ccflags "$(TB_CC_FLAGS)"' >> $@
 	echo 'return 0' >> $@
 
-# Build compilation script and compile all sources for Questasim simulation
-$(BIN_DIR)/$(TARGET).vsim: $(VSIM_BUILDDIR)/compile.vsim.tcl $(VSIM_SOURCES) $(TB_SRCS) $(TB_CC_SOURCES) $(RTL_CC_SOURCES) work/lib/libfesvr.a | $(BIN_DIR)
+# Intermediate file required to avoid "Argument list too long" errors in Occamy
+# when invoking Verilator
+$(VSIM_BUILDDIR)/$(TARGET).f: $(BENDER_YML) $(BENDER_LOCK) | $(VSIM_BUILDDIR)
+	$(BENDER) script verilator $(VSIM_BENDER) > $@
+
+# Generate dependency file with RTL sources and headers using Verilator
+$(VSIM_BUILDDIR)/$(VSIM_TOP_MODULE).d: $(VSIM_BUILDDIR)/$(TARGET).f $(GENERATED_RTL_SOURCES) | $(VSIM_BUILDDIR)
+	$(VLT) -f $< --Mdir $(VSIM_BUILDDIR) --MMD -E --top-module $(VSIM_TOP_MODULE) > /dev/null
+	mv $(VSIM_BUILDDIR)/V$(VSIM_TOP_MODULE)__ver.d $@
+	sed -i 's|^[^:]*:|$(BIN_DIR)/$(TARGET).vsim:|' $@
+
+# Run compilation script and create Questasim simulation binary
+$(BIN_DIR)/$(TARGET).vsim: $(VSIM_BUILDDIR)/compile.vsim.tcl $(TB_CC_SOURCES) $(RTL_CC_SOURCES) work/lib/libfesvr.a | $(BIN_DIR)
 	$(VSIM) -c -do "source $<; quit" | tee $(dir $<)vlog.log
 	@! grep -P "Errors: [1-9]*," $(dir $<)vlog.log
-	$(VOPT) $(VOPT_FLAGS) -work $(VSIM_BUILDDIR) tb_bin -o tb_bin_opt | tee $(dir $<)vopt.log
+	$(VOPT) $(VOPT_FLAGS) -work $(VSIM_BUILDDIR) $(VSIM_TOP_MODULE) -o $(VSIM_TOP_MODULE)_opt | tee $(dir $<)vopt.log
 	@! grep -P "Errors: [1-9]*," $(dir $<)vopt.log
 	@echo "#!/bin/bash" > $@
 	@echo 'binary=$$(realpath $$1)' >> $@
 	@echo 'echo $$binary > .rtlbinary' >> $@
 	@echo '$(VSIM) +permissive $(VSIM_FLAGS) $$3 -work $(MKFILE_DIR)/$(VSIM_BUILDDIR) -c \
 				-ldflags "-Wl,-rpath,$(FESVR)/lib -L$(FESVR)/lib -lfesvr -lutil" \
-				tb_bin_opt +permissive-off ++$$binary ++$$2' >> $@
+				$(VSIM_TOP_MODULE)_opt +permissive-off ++$$binary ++$$2' >> $@
 	@chmod +x $@
 	@echo "#!/bin/bash" > $@.gui
 	@echo 'binary=$$(realpath $$1)' >> $@.gui
 	@echo 'echo $$binary > .rtlbinary' >> $@.gui
 	@echo '$(VSIM) +permissive $(VSIM_FLAGS) -work $(MKFILE_DIR)/$(VSIM_BUILDDIR) \
 				-ldflags "-Wl,-rpath,$(FESVR)/lib -L$(FESVR)/lib -lfesvr -lutil" \
-				tb_bin_opt +permissive-off ++$$binary ++$$2' >> $@.gui
+				$(VSIM_TOP_MODULE)_opt +permissive-off ++$$binary ++$$2' >> $@.gui
 	@chmod +x $@.gui
 
 # Clean all build directories and temporary files for Questasim simulation
@@ -38,3 +51,7 @@ clean-vsim: clean-work
 	rm -rf $(BIN_DIR)/$(TARGET).vsim $(BIN_DIR)/$(TARGET).vsim.gui $(VSIM_BUILDDIR) vsim.wlf
 
 clean: clean-vsim
+
+ifneq ($(filter-out clean%,$(MAKECMDGOALS)),)
+-include $(VSIM_BUILDDIR)/$(VSIM_TOP_MODULE).d
+endif
diff --git a/target/snitch_cluster/Makefile b/target/snitch_cluster/Makefile
index ae6ec0ec0..dea529fb4 100644
--- a/target/snitch_cluster/Makefile
+++ b/target/snitch_cluster/Makefile
@@ -202,18 +202,7 @@ include $(ROOT)/target/common/vsim.mk
 # VCS #
 #######
 
-.PHONY: clean-vcs
-
-# Clean all build directories and temporary files for VCS simulation
-clean-vcs: clean-work
-	rm -rf $(BIN_DIR)/$(TARGET).vcs $(VCS_BUILDDIR) vc_hdrs.h
-
-# Build compilation script and compile all sources for VCS simulation
-$(BIN_DIR)/$(TARGET).vcs: ${VCS_SOURCES} ${TB_SRCS} $(TB_CC_SOURCES) $(RTL_CC_SOURCES) $(VCS_BUILDDIR)/compile.sh work/lib/libfesvr.a
-	mkdir -p $(BIN_DIR)
-	$(VCS) -Mlib=$(VCS_BUILDDIR) -Mdir=$(VCS_BUILDDIR) -o $(BIN_DIR)/$(TARGET).vcs -cc $(CC) -cpp $(CXX) \
-		-assert disable_cover -override_timescale=1ns/1ps -full64 tb_bin $(TB_CC_SOURCES) $(RTL_CC_SOURCES) \
-		-CFLAGS "$(TB_CC_FLAGS)" -LDFLAGS "-L${FESVR}/lib" -lfesvr
+include $(ROOT)/target/common/vcs.mk
 
 ########
 # Util #