diff --git a/kernel/driver.cc b/kernel/driver.cc
index 7a1dce497..bec872c24 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -34,12 +34,17 @@
 #include <limits.h>
 #include <errno.h>
 
-#ifdef __linux__
+#if defined (__linux__) || defined(__FreeBSD__)
 #  include <sys/resource.h>
 #  include <sys/types.h>
 #  include <unistd.h>
 #endif
 
+#ifdef __FreeBSD__
+#  include <sys/sysctl.h>
+#  include <sys/user.h>
+#endif
+
 #if !defined(_WIN32) || defined(__MINGW32__)
 #  include <unistd.h>
 #else
@@ -510,7 +515,7 @@ int main(int argc, char **argv)
 #else
 		std::string meminfo;
 		std::string stats_divider = ", ";
-#  ifdef __linux__
+#  if defined(__linux__)
 		std::ifstream statm;
 		statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
 		if (statm.is_open()) {
@@ -521,6 +526,19 @@ int main(int argc, char **argv)
 					sz_resident * (getpagesize() / 1024.0 / 1024.0));
 			stats_divider = "\n";
 		}
+#  elif defined(__FreeBSD__)
+		pid_t pid = getpid();
+		int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid};
+		struct kinfo_proc kip;
+		size_t kip_len = sizeof(kip);
+		if (sysctl(mib, 4, &kip, &kip_len, NULL, 0) == 0) {
+			vm_size_t sz_total = kip.ki_size;
+			segsz_t sz_resident = kip.ki_rssize;
+			meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
+				(int)sz_total / 1024.0 / 1024.0,
+				(int)sz_resident * (getpagesize() / 1024.0 / 1024.0));
+			stats_divider = "\n";
+		}
 #  endif
 
 		struct rusage ru_buffer;
@@ -564,7 +582,7 @@ int main(int argc, char **argv)
 		}
 	}
 
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
 	if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
 	{
 		string filename;
diff --git a/kernel/log.cc b/kernel/log.cc
index ff171f3e6..6d562b9e6 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -25,7 +25,7 @@
 #  include <sys/time.h>
 #endif
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 #  include <dlfcn.h>
 #endif
 
@@ -392,7 +392,7 @@ void log_pop()
 	log_flush();
 }
 
-#if defined(__linux__) && defined(YOSYS_ENABLE_PLUGINS)
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(YOSYS_ENABLE_PLUGINS)
 void log_backtrace(const char *prefix, int levels)
 {
 	if (levels <= 0) return;
@@ -587,7 +587,7 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
 // ---------------------------------------------------
 // This is the magic behind the code coverage counters
 // ---------------------------------------------------
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
 
 dict<std::string, std::pair<std::string, int>> extra_coverage_data;
 
diff --git a/kernel/log.h b/kernel/log.h
index 457229c87..a2aacfd4d 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -114,7 +114,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
 // This is the magic behind the code coverage counters
 // ---------------------------------------------------
 
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
 
 #define cover(_id) do { \
     static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 49d644548..aa5901271 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -46,10 +46,15 @@
 #  include <unistd.h>
 #  include <dirent.h>
 #  include <sys/types.h>
+#  include <sys/wait.h>
 #  include <sys/stat.h>
 #  include <glob.h>
 #endif
 
+#ifdef __FreeBSD__
+#  include <sys/sysctl.h>
+#endif
+
 #include <limits.h>
 #include <errno.h>
 
@@ -72,7 +77,7 @@ std::vector<void*> memhasher_store;
 
 void memhasher_on()
 {
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 	memhasher_rng += time(NULL) << 16 ^ getpid();
 #endif
 	memhasher_store.resize(0x10000);
@@ -667,6 +672,26 @@ std::string proc_self_dirname()
 		buflen--;
 	return std::string(path, buflen);
 }
+#elif defined(__FreeBSD__)
+std::string proc_self_dirname()
+{
+	int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+	size_t buflen;
+	char *buffer;
+	std::string path;
+	if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0)
+		log_error("sysctl failed: %s\n", strerror(errno));
+	buffer = (char*)malloc(buflen);
+	if (buffer == NULL)
+		log_error("malloc failed: %s\n", strerror(errno));
+	if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0)
+		log_error("sysctl failed: %s\n", strerror(errno));
+	while (buflen > 0 && buffer[buflen-1] != '/')
+		buflen--;
+	path.assign(buffer, buflen);
+	free(buffer);
+	return path;
+}
 #elif defined(__APPLE__)
 std::string proc_self_dirname()
 {
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 1475475c3..ef4f3f7d0 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -128,7 +128,7 @@ struct CoverPass : public Pass {
 			log("\n");
 		}
 
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
 		for (auto &it : get_coverage_data()) {
 			if (!patterns.empty()) {
 				for (auto &p : patterns)