mirror of
https://github.com/YosysHQ/yosys
synced 2025-09-23 18:01:29 +00:00
Run ABCs in parallel.
Large circuits can run hundreds or thousands of ABCs in a single AbcPass. For some circuits, some of those ABC runs can run for hundreds of seconds. Running ABCs in parallel with each other and in parallel with main-thread processing (reading and writing BLIF files, copying ABC BLIF output into the design) can give large speedups.
This commit is contained in:
parent
38f8165c80
commit
27462da208
6 changed files with 362 additions and 88 deletions
14
Makefile
14
Makefile
|
@ -44,7 +44,12 @@ LINK_ABC := 0
|
||||||
# Needed for environments that can't run executables (i.e. emscripten, wasm)
|
# Needed for environments that can't run executables (i.e. emscripten, wasm)
|
||||||
DISABLE_SPAWN := 0
|
DISABLE_SPAWN := 0
|
||||||
# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now)
|
# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now)
|
||||||
|
ENABLE_THREADS := 1
|
||||||
|
ifeq ($(ENABLE_THREADS),1)
|
||||||
DISABLE_ABC_THREADS := 0
|
DISABLE_ABC_THREADS := 0
|
||||||
|
else
|
||||||
|
DISABLE_ABC_THREADS := 1
|
||||||
|
endif
|
||||||
|
|
||||||
# clang sanitizers
|
# clang sanitizers
|
||||||
SANITIZER =
|
SANITIZER =
|
||||||
|
@ -300,6 +305,7 @@ DISABLE_SPAWN := 1
|
||||||
|
|
||||||
ifeq ($(ENABLE_ABC),1)
|
ifeq ($(ENABLE_ABC),1)
|
||||||
LINK_ABC := 1
|
LINK_ABC := 1
|
||||||
|
ENABLE_THREADS := 0
|
||||||
DISABLE_ABC_THREADS := 1
|
DISABLE_ABC_THREADS := 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -457,6 +463,11 @@ CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
|
||||||
STRIP :=
|
STRIP :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_THREADS),1)
|
||||||
|
CXXFLAGS += -DYOSYS_ENABLE_THREADS
|
||||||
|
LIBS += -lpthread
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_ABC),1)
|
ifeq ($(ENABLE_ABC),1)
|
||||||
CXXFLAGS += -DYOSYS_ENABLE_ABC
|
CXXFLAGS += -DYOSYS_ENABLE_ABC
|
||||||
ifeq ($(LINK_ABC),1)
|
ifeq ($(LINK_ABC),1)
|
||||||
|
@ -612,6 +623,7 @@ $(eval $(call add_include_file,kernel/satgen.h))
|
||||||
$(eval $(call add_include_file,kernel/scopeinfo.h))
|
$(eval $(call add_include_file,kernel/scopeinfo.h))
|
||||||
$(eval $(call add_include_file,kernel/sexpr.h))
|
$(eval $(call add_include_file,kernel/sexpr.h))
|
||||||
$(eval $(call add_include_file,kernel/sigtools.h))
|
$(eval $(call add_include_file,kernel/sigtools.h))
|
||||||
|
$(eval $(call add_include_file,kernel/threading.h))
|
||||||
$(eval $(call add_include_file,kernel/timinginfo.h))
|
$(eval $(call add_include_file,kernel/timinginfo.h))
|
||||||
$(eval $(call add_include_file,kernel/utils.h))
|
$(eval $(call add_include_file,kernel/utils.h))
|
||||||
$(eval $(call add_include_file,kernel/yosys.h))
|
$(eval $(call add_include_file,kernel/yosys.h))
|
||||||
|
@ -638,7 +650,7 @@ OBJS += kernel/log_compat.o
|
||||||
endif
|
endif
|
||||||
OBJS += kernel/binding.o kernel/tclapi.o
|
OBJS += kernel/binding.o kernel/tclapi.o
|
||||||
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o
|
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o
|
||||||
OBJS += kernel/drivertools.o kernel/functional.o
|
OBJS += kernel/drivertools.o kernel/functional.o kernel/threading.o
|
||||||
ifeq ($(ENABLE_ZLIB),1)
|
ifeq ($(ENABLE_ZLIB),1)
|
||||||
OBJS += kernel/fstdata.o
|
OBJS += kernel/fstdata.o
|
||||||
endif
|
endif
|
||||||
|
|
45
kernel/threading.cc
Normal file
45
kernel/threading.cc
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "kernel/yosys_common.h"
|
||||||
|
#include "kernel/threading.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void DeferredLogs::flush()
|
||||||
|
{
|
||||||
|
for (auto &m : logs)
|
||||||
|
if (m.error)
|
||||||
|
YOSYS_NAMESPACE_PREFIX log_error("%s", m.text.c_str());
|
||||||
|
else
|
||||||
|
YOSYS_NAMESPACE_PREFIX log("%s", m.text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int ThreadPool::pool_size(int reserved_cores, int max_threads)
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
int num_threads = std::min<int>(std::thread::hardware_concurrency() - reserved_cores, max_threads);
|
||||||
|
return std::max(0, num_threads);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool::ThreadPool(int pool_size, std::function<void(int)> b)
|
||||||
|
: body(std::move(b))
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
threads.reserve(pool_size);
|
||||||
|
for (int i = 0; i < pool_size; i++)
|
||||||
|
threads.emplace_back([i, this]{ body(i); });
|
||||||
|
#else
|
||||||
|
log_assert(pool_size == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool::~ThreadPool()
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
for (auto &t : threads)
|
||||||
|
t.join();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
159
kernel/threading.h
Normal file
159
kernel/threading.h
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "kernel/yosys_common.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
|
||||||
|
#ifndef YOSYS_THREADING_H
|
||||||
|
#define YOSYS_THREADING_H
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// Concurrent queue implementation. Not fast, but simple.
|
||||||
|
// Multi-producer, multi-consumer, optionally bounded.
|
||||||
|
// When YOSYS_ENABLE_THREADS is not defined, this is just a non-thread-safe non-blocking deque.
|
||||||
|
template <typename T>
|
||||||
|
class ConcurrentQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConcurrentQueue(int capacity = INT_MAX)
|
||||||
|
: capacity(capacity) {}
|
||||||
|
// Push an element into the queue. If it's at capacity, block until there is room.
|
||||||
|
void push_back(T t)
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
not_full_condition.wait(lock, [this] { return static_cast<int>(contents.size()) < capacity; });
|
||||||
|
if (contents.empty())
|
||||||
|
not_empty_condition.notify_one();
|
||||||
|
#endif
|
||||||
|
log_assert(!closed);
|
||||||
|
contents.push_back(std::move(t));
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
if (static_cast<int>(contents.size()) < capacity)
|
||||||
|
not_full_condition.notify_one();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Signal that no more elements will be produced. `pop_front()` will return nullopt.
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
not_empty_condition.notify_all();
|
||||||
|
#endif
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
// Pop an element from the queue. Blocks until an element is available
|
||||||
|
// or the queue is closed and empty.
|
||||||
|
std::optional<T> pop_front()
|
||||||
|
{
|
||||||
|
return pop_front_internal(true);
|
||||||
|
}
|
||||||
|
// Pop an element from the queue. Does not block, just returns nullopt if the
|
||||||
|
// queue is empty.
|
||||||
|
std::optional<T> try_pop_front()
|
||||||
|
{
|
||||||
|
return pop_front_internal(false);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
std::optional<T> pop_front_internal(bool wait)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
if (wait) {
|
||||||
|
not_empty_condition.wait(lock, [this] { return !contents.empty() || closed; });
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::optional<T> pop_front_internal(bool)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
if (contents.empty())
|
||||||
|
return std::nullopt;
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
if (static_cast<int>(contents.size()) == capacity)
|
||||||
|
not_full_condition.notify_one();
|
||||||
|
#endif
|
||||||
|
T result = std::move(contents.front());
|
||||||
|
contents.pop_front();
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
if (!contents.empty())
|
||||||
|
not_empty_condition.notify_one();
|
||||||
|
#endif
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
std::mutex mutex;
|
||||||
|
// Signals one waiter thread when the queue changes and is not full.
|
||||||
|
std::condition_variable not_full_condition;
|
||||||
|
// Signals one waiter thread when the queue changes and is not empty.
|
||||||
|
std::condition_variable not_empty_condition;
|
||||||
|
#endif
|
||||||
|
std::deque<T> contents;
|
||||||
|
int capacity;
|
||||||
|
bool closed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeferredLogs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
void log(FmtString<TypeIdentity<Args>...> fmt, Args... args)
|
||||||
|
{
|
||||||
|
logs.push_back({fmt.format(args...), false});
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
void log_error(FmtString<TypeIdentity<Args>...> fmt, Args... args)
|
||||||
|
{
|
||||||
|
logs.push_back({fmt.format(args...), true});
|
||||||
|
}
|
||||||
|
void flush();
|
||||||
|
private:
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
bool error;
|
||||||
|
};
|
||||||
|
std::vector<Message> logs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThreadPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Computes the number of worker threads to use.
|
||||||
|
// `reserved_cores` cores are set aside for other threads (e.g. work on the main thread).
|
||||||
|
// `max_threads` --- don't return more workers than this.
|
||||||
|
// The result may be 0.
|
||||||
|
static int pool_size(int reserved_cores, int max_threads);
|
||||||
|
|
||||||
|
// Create a pool of threads running the given closure (parameterized by thread number).
|
||||||
|
// `pool_size` must be the result of a `pool_size()` call.
|
||||||
|
ThreadPool(int pool_size, std::function<void(int)> b);
|
||||||
|
ThreadPool(ThreadPool &&other) = delete;
|
||||||
|
// Waits for all threads to terminate. Make sure those closures return!
|
||||||
|
~ThreadPool();
|
||||||
|
|
||||||
|
// Return the number of threads in the pool.
|
||||||
|
int num_threads() const
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
return threads.size();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::function<void(int)> body;
|
||||||
|
#ifdef YOSYS_ENABLE_THREADS
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // YOSYS_THREADING_H
|
|
@ -177,7 +177,7 @@ int run_command(const std::string &command, std::function<void(const std::string
|
||||||
|
|
||||||
int ret = pclose(f);
|
int ret = pclose(f);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -2;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -38,6 +38,7 @@ popd
|
||||||
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||||
|
|
||||||
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||||
|
sed -i 's,<PreprocessorDefinitions>,<PreprocessorDefinitions>YOSYS_ENABLE_THREADS;,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||||
if [ -f "/usr/include/FlexLexer.h" ] ; then
|
if [ -f "/usr/include/FlexLexer.h" ] ; then
|
||||||
sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "kernel/ff.h"
|
#include "kernel/ff.h"
|
||||||
#include "kernel/cost.h"
|
#include "kernel/cost.h"
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
|
#include "kernel/threading.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -153,30 +155,41 @@ struct AbcSigVal {
|
||||||
|
|
||||||
using AbcSigMap = SigValMap<AbcSigVal>;
|
using AbcSigMap = SigValMap<AbcSigVal>;
|
||||||
|
|
||||||
struct AbcModuleState {
|
// Used by off-main-threads. Contains no direct or indirect access to RTLIL.
|
||||||
|
struct RunAbcState {
|
||||||
const AbcConfig &config;
|
const AbcConfig &config;
|
||||||
|
|
||||||
int map_autoidx = 0;
|
std::string tempdir_name;
|
||||||
std::vector<gate_t> signal_list;
|
std::vector<gate_t> signal_list;
|
||||||
|
bool did_run = false;
|
||||||
|
bool err = false;
|
||||||
|
DeferredLogs logs;
|
||||||
|
dict<int, std::string> pi_map, po_map;
|
||||||
|
|
||||||
|
RunAbcState(const AbcConfig &config) : config(config) {}
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbcModuleState {
|
||||||
|
RunAbcState run_abc;
|
||||||
|
|
||||||
|
int map_autoidx = 0;
|
||||||
std::vector<RTLIL::SigBit> signal_bits;
|
std::vector<RTLIL::SigBit> signal_bits;
|
||||||
dict<RTLIL::SigBit, int> signal_map;
|
dict<RTLIL::SigBit, int> signal_map;
|
||||||
FfInitVals &initvals;
|
FfInitVals &initvals;
|
||||||
bool had_init = false;
|
bool had_init = false;
|
||||||
bool did_run_abc = false;
|
|
||||||
|
|
||||||
bool clk_polarity = false;
|
bool clk_polarity = false;
|
||||||
bool en_polarity = false;
|
bool en_polarity = false;
|
||||||
bool arst_polarity = false;
|
bool arst_polarity = false;
|
||||||
bool srst_polarity = false;
|
bool srst_polarity = false;
|
||||||
RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig;
|
RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig;
|
||||||
dict<int, std::string> pi_map, po_map;
|
|
||||||
|
|
||||||
int undef_bits_lost = 0;
|
int undef_bits_lost = 0;
|
||||||
|
|
||||||
std::string tempdir_name;
|
|
||||||
|
|
||||||
AbcModuleState(const AbcConfig &config, FfInitVals &initvals)
|
AbcModuleState(const AbcConfig &config, FfInitVals &initvals)
|
||||||
: config(config), initvals(initvals) {}
|
: run_abc(config), initvals(initvals) {}
|
||||||
|
AbcModuleState(AbcModuleState&&) = delete;
|
||||||
|
|
||||||
int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1);
|
int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1);
|
||||||
void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig);
|
void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig);
|
||||||
|
@ -186,7 +199,6 @@ struct AbcModuleState {
|
||||||
void handle_loops(AbcSigMap &assign_map, RTLIL::Module *module);
|
void handle_loops(AbcSigMap &assign_map, RTLIL::Module *module);
|
||||||
void prepare_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector<RTLIL::Cell*> &cells,
|
void prepare_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector<RTLIL::Cell*> &cells,
|
||||||
bool dff_mode, std::string clk_str);
|
bool dff_mode, std::string clk_str);
|
||||||
void run_abc();
|
|
||||||
void extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module);
|
void extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module);
|
||||||
void finish();
|
void finish();
|
||||||
};
|
};
|
||||||
|
@ -200,7 +212,7 @@ int AbcModuleState::map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, g
|
||||||
|
|
||||||
if (signal_map.count(bit) == 0) {
|
if (signal_map.count(bit) == 0) {
|
||||||
gate_t gate;
|
gate_t gate;
|
||||||
gate.id = signal_list.size();
|
gate.id = run_abc.signal_list.size();
|
||||||
gate.type = G(NONE);
|
gate.type = G(NONE);
|
||||||
gate.in1 = -1;
|
gate.in1 = -1;
|
||||||
gate.in2 = -1;
|
gate.in2 = -1;
|
||||||
|
@ -212,11 +224,11 @@ int AbcModuleState::map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, g
|
||||||
gate.init = initvals(bit);
|
gate.init = initvals(bit);
|
||||||
gate.bit_str = std::string(log_signal(bit));
|
gate.bit_str = std::string(log_signal(bit));
|
||||||
signal_map[bit] = gate.id;
|
signal_map[bit] = gate.id;
|
||||||
signal_list.push_back(std::move(gate));
|
run_abc.signal_list.push_back(std::move(gate));
|
||||||
signal_bits.push_back(bit);
|
signal_bits.push_back(bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
gate_t &gate = signal_list[signal_map[bit]];
|
gate_t &gate = run_abc.signal_list[signal_map[bit]];
|
||||||
|
|
||||||
if (gate_type != G(NONE))
|
if (gate_type != G(NONE))
|
||||||
gate.type = gate_type;
|
gate.type = gate_type;
|
||||||
|
@ -236,7 +248,7 @@ void AbcModuleState::mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig)
|
||||||
{
|
{
|
||||||
for (auto &bit : assign_map(sig))
|
for (auto &bit : assign_map(sig))
|
||||||
if (bit.wire != nullptr && signal_map.count(bit) > 0)
|
if (bit.wire != nullptr && signal_map.count(bit) > 0)
|
||||||
signal_list[signal_map[bit]].is_port = true;
|
run_abc.signal_list[signal_map[bit]].is_port = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff)
|
bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff)
|
||||||
|
@ -315,7 +327,7 @@ bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *mo
|
||||||
if (keepff) {
|
if (keepff) {
|
||||||
SigBit bit = ff.sig_q;
|
SigBit bit = ff.sig_q;
|
||||||
if (assign_map(bit).wire != nullptr) {
|
if (assign_map(bit).wire != nullptr) {
|
||||||
signal_list[gate_id].is_port = true;
|
run_abc.signal_list[gate_id].is_port = true;
|
||||||
}
|
}
|
||||||
if (bit.wire != nullptr)
|
if (bit.wire != nullptr)
|
||||||
bit.wire->attributes[ID::keep] = 1;
|
bit.wire->attributes[ID::keep] = 1;
|
||||||
|
@ -467,7 +479,7 @@ std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **o
|
||||||
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
|
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
|
||||||
std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
|
std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
|
||||||
|
|
||||||
if (sid < GetSize(signal_list))
|
if (sid < GetSize(run_abc.signal_list))
|
||||||
{
|
{
|
||||||
const auto &bit = signal_bits.at(sid);
|
const auto &bit = signal_bits.at(sid);
|
||||||
if (bit.wire != nullptr)
|
if (bit.wire != nullptr)
|
||||||
|
@ -507,7 +519,7 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict<int, pool<int>> &edg
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto n : nodes)
|
for (auto n : nodes)
|
||||||
fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, signal_list[n].bit_str.c_str(),
|
fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, run_abc.signal_list[n].bit_str.c_str(),
|
||||||
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
|
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
|
||||||
|
|
||||||
for (auto &e : edges)
|
for (auto &e : edges)
|
||||||
|
@ -529,7 +541,7 @@ void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module)
|
||||||
// (Kahn, Arthur B. (1962), "Topological sorting of large networks")
|
// (Kahn, Arthur B. (1962), "Topological sorting of large networks")
|
||||||
|
|
||||||
dict<int, pool<int>> edges;
|
dict<int, pool<int>> edges;
|
||||||
std::vector<int> in_edges_count(signal_list.size());
|
std::vector<int> in_edges_count(run_abc.signal_list.size());
|
||||||
pool<int> workpool;
|
pool<int> workpool;
|
||||||
|
|
||||||
FILE *dot_f = nullptr;
|
FILE *dot_f = nullptr;
|
||||||
|
@ -538,7 +550,7 @@ void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module)
|
||||||
// uncomment for troubleshooting the loop detection code
|
// uncomment for troubleshooting the loop detection code
|
||||||
// dot_f = fopen("test.dot", "w");
|
// dot_f = fopen("test.dot", "w");
|
||||||
|
|
||||||
for (auto &g : signal_list) {
|
for (auto &g : run_abc.signal_list) {
|
||||||
if (g.type == G(NONE) || g.type == G(FF) || g.type == G(FF0) || g.type == G(FF1)) {
|
if (g.type == G(NONE) || g.type == G(FF) || g.type == G(FF0) || g.type == G(FF1)) {
|
||||||
workpool.insert(g.id);
|
workpool.insert(g.id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -621,29 +633,29 @@ void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module)
|
||||||
for (int id2 : edges[id1]) {
|
for (int id2 : edges[id1]) {
|
||||||
if (first_line)
|
if (first_line)
|
||||||
log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
|
log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
|
||||||
signal_list[id1].bit_str, signal_list[id2].bit_str);
|
run_abc.signal_list[id1].bit_str, run_abc.signal_list[id2].bit_str);
|
||||||
else
|
else
|
||||||
log(" %*s %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
|
log(" %*s %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
|
||||||
signal_list[id1].bit_str, signal_list[id2].bit_str);
|
run_abc.signal_list[id1].bit_str, run_abc.signal_list[id2].bit_str);
|
||||||
first_line = false;
|
first_line = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int id3 = map_signal(assign_map, RTLIL::SigSpec(wire));
|
int id3 = map_signal(assign_map, RTLIL::SigSpec(wire));
|
||||||
signal_list[id1].is_port = true;
|
run_abc.signal_list[id1].is_port = true;
|
||||||
signal_list[id3].is_port = true;
|
run_abc.signal_list[id3].is_port = true;
|
||||||
log_assert(id3 == int(in_edges_count.size()));
|
log_assert(id3 == int(in_edges_count.size()));
|
||||||
in_edges_count.push_back(0);
|
in_edges_count.push_back(0);
|
||||||
workpool.insert(id3);
|
workpool.insert(id3);
|
||||||
|
|
||||||
for (int id2 : edges[id1]) {
|
for (int id2 : edges[id1]) {
|
||||||
if (signal_list[id2].in1 == id1)
|
if (run_abc.signal_list[id2].in1 == id1)
|
||||||
signal_list[id2].in1 = id3;
|
run_abc.signal_list[id2].in1 = id3;
|
||||||
if (signal_list[id2].in2 == id1)
|
if (run_abc.signal_list[id2].in2 == id1)
|
||||||
signal_list[id2].in2 = id3;
|
run_abc.signal_list[id2].in2 = id3;
|
||||||
if (signal_list[id2].in3 == id1)
|
if (run_abc.signal_list[id2].in3 == id1)
|
||||||
signal_list[id2].in3 = id3;
|
run_abc.signal_list[id2].in3 = id3;
|
||||||
if (signal_list[id2].in4 == id1)
|
if (run_abc.signal_list[id2].in4 == id1)
|
||||||
signal_list[id2].in4 = id3;
|
run_abc.signal_list[id2].in4 = id3;
|
||||||
}
|
}
|
||||||
edges[id1].swap(edges[id3]);
|
edges[id1].swap(edges[id3]);
|
||||||
|
|
||||||
|
@ -724,14 +736,14 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho
|
||||||
|
|
||||||
struct abc_output_filter
|
struct abc_output_filter
|
||||||
{
|
{
|
||||||
const AbcModuleState &state;
|
RunAbcState &state;
|
||||||
bool got_cr;
|
bool got_cr;
|
||||||
int escape_seq_state;
|
int escape_seq_state;
|
||||||
std::string linebuf;
|
std::string linebuf;
|
||||||
std::string tempdir_name;
|
std::string tempdir_name;
|
||||||
bool show_tempdir;
|
bool show_tempdir;
|
||||||
|
|
||||||
abc_output_filter(const AbcModuleState& state, std::string tempdir_name, bool show_tempdir)
|
abc_output_filter(RunAbcState& state, std::string tempdir_name, bool show_tempdir)
|
||||||
: state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir)
|
: state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir)
|
||||||
{
|
{
|
||||||
got_cr = false;
|
got_cr = false;
|
||||||
|
@ -759,7 +771,7 @@ struct abc_output_filter
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir));
|
state.logs.log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir));
|
||||||
got_cr = false, linebuf.clear();
|
got_cr = false, linebuf.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -772,7 +784,7 @@ struct abc_output_filter
|
||||||
{
|
{
|
||||||
int pi, po;
|
int pi, po;
|
||||||
if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
|
if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
|
||||||
log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
|
state.logs.log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
|
||||||
pi, state.pi_map.count(pi) ? state.pi_map.at(pi).c_str() : "???",
|
pi, state.pi_map.count(pi) ? state.pi_map.at(pi).c_str() : "???",
|
||||||
po, state.po_map.count(po) ? state.po_map.at(po).c_str() : "???");
|
po, state.po_map.count(po) ? state.po_map.at(po).c_str() : "???");
|
||||||
return;
|
return;
|
||||||
|
@ -858,16 +870,17 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
||||||
if (dff_mode && clk_sig.empty())
|
if (dff_mode && clk_sig.empty())
|
||||||
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
|
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
|
||||||
|
|
||||||
|
const AbcConfig &config = run_abc.config;
|
||||||
if (config.cleanup)
|
if (config.cleanup)
|
||||||
tempdir_name = get_base_tmpdir() + "/";
|
run_abc.tempdir_name = get_base_tmpdir() + "/";
|
||||||
else
|
else
|
||||||
tempdir_name = "_tmp_";
|
run_abc.tempdir_name = "_tmp_";
|
||||||
tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
run_abc.tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
||||||
tempdir_name = make_temp_dir(tempdir_name);
|
run_abc.tempdir_name = make_temp_dir(run_abc.tempdir_name);
|
||||||
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
|
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
|
||||||
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, config.show_tempdir).c_str());
|
module->name.c_str(), replace_tempdir(run_abc.tempdir_name, run_abc.tempdir_name, config.show_tempdir).c_str());
|
||||||
|
|
||||||
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name);
|
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.tempdir_name);
|
||||||
|
|
||||||
if (!config.liberty_files.empty() || !config.genlib_files.empty()) {
|
if (!config.liberty_files.empty() || !config.genlib_files.empty()) {
|
||||||
std::string dont_use_args;
|
std::string dont_use_args;
|
||||||
|
@ -933,15 +946,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
||||||
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
|
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
|
||||||
abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3);
|
abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3);
|
||||||
if (config.abc_dress)
|
if (config.abc_dress)
|
||||||
abc_script += stringf("; dress \"%s/input.blif\"", tempdir_name);
|
abc_script += stringf("; dress \"%s/input.blif\"", run_abc.tempdir_name);
|
||||||
abc_script += stringf("; write_blif %s/output.blif", tempdir_name);
|
abc_script += stringf("; write_blif %s/output.blif", run_abc.tempdir_name);
|
||||||
abc_script = add_echos_to_abc_cmd(abc_script);
|
abc_script = add_echos_to_abc_cmd(abc_script);
|
||||||
|
|
||||||
for (size_t i = 0; i+1 < abc_script.size(); i++)
|
for (size_t i = 0; i+1 < abc_script.size(); i++)
|
||||||
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
|
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
|
||||||
abc_script[i+1] = '\n';
|
abc_script[i+1] = '\n';
|
||||||
|
|
||||||
std::string buffer = stringf("%s/abc.script", tempdir_name);
|
std::string buffer = stringf("%s/abc.script", run_abc.tempdir_name);
|
||||||
FILE *f = fopen(buffer.c_str(), "wt");
|
FILE *f = fopen(buffer.c_str(), "wt");
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
||||||
|
@ -997,12 +1010,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
||||||
handle_loops(assign_map, module);
|
handle_loops(assign_map, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcModuleState::run_abc()
|
void RunAbcState::run()
|
||||||
{
|
{
|
||||||
std::string buffer = stringf("%s/input.blif", tempdir_name);
|
std::string buffer = stringf("%s/input.blif", tempdir_name);
|
||||||
FILE *f = fopen(buffer.c_str(), "wt");
|
FILE *f = fopen(buffer.c_str(), "wt");
|
||||||
if (f == nullptr)
|
if (f == nullptr) {
|
||||||
log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
logs.log("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
||||||
|
err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(f, ".model netlist\n");
|
fprintf(f, ".model netlist\n");
|
||||||
|
|
||||||
|
@ -1117,13 +1133,14 @@ void AbcModuleState::run_abc()
|
||||||
fprintf(f, ".end\n");
|
fprintf(f, ".end\n");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
|
logs.log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
|
||||||
count_gates, GetSize(signal_list), count_input, count_output);
|
count_gates, GetSize(signal_list), count_input, count_output);
|
||||||
if (count_output > 0)
|
if (count_output > 0)
|
||||||
{
|
{
|
||||||
buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file, tempdir_name);
|
buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file, tempdir_name);
|
||||||
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, config.show_tempdir));
|
logs.log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, config.show_tempdir));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
#ifndef YOSYS_LINK_ABC
|
#ifndef YOSYS_LINK_ABC
|
||||||
abc_output_filter filt(*this, tempdir_name, config.show_tempdir);
|
abc_output_filter filt(*this, tempdir_name, config.show_tempdir);
|
||||||
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
|
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
|
||||||
|
@ -1172,10 +1189,10 @@ void AbcModuleState::run_abc()
|
||||||
temp_stdouterr_r.close();
|
temp_stdouterr_r.close();
|
||||||
#endif
|
#endif
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer, ret);
|
logs.log_error("ABC: execution of command \"%s\" failed: return code %d (errno=%d).\n", buffer, ret, errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
did_run_abc = true;
|
did_run = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log("Don't call ABC as there is nothing to map.\n");
|
log("Don't call ABC as there is nothing to map.\n");
|
||||||
|
@ -1242,19 +1259,23 @@ void emit_global_input_files(const AbcConfig &config)
|
||||||
|
|
||||||
void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module)
|
void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module)
|
||||||
{
|
{
|
||||||
if (!did_run_abc) {
|
log_push();
|
||||||
|
log_header(design, "Executed ABC.\n");
|
||||||
|
run_abc.logs.flush();
|
||||||
|
if (!run_abc.did_run) {
|
||||||
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string buffer = stringf("%s/%s", tempdir_name, "output.blif");
|
std::string buffer = stringf("%s/%s", run_abc.tempdir_name, "output.blif");
|
||||||
std::ifstream ifs;
|
std::ifstream ifs;
|
||||||
ifs.open(buffer);
|
ifs.open(buffer);
|
||||||
if (ifs.fail())
|
if (ifs.fail())
|
||||||
log_error("Can't open ABC output file `%s'.\n", buffer);
|
log_error("Can't open ABC output file `%s'.\n", buffer);
|
||||||
|
|
||||||
bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty();
|
bool builtin_lib = run_abc.config.liberty_files.empty() && run_abc.config.genlib_files.empty();
|
||||||
RTLIL::Design *mapped_design = new RTLIL::Design;
|
RTLIL::Design *mapped_design = new RTLIL::Design;
|
||||||
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode);
|
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, run_abc.config.sop_mode);
|
||||||
|
|
||||||
ifs.close();
|
ifs.close();
|
||||||
|
|
||||||
|
@ -1503,7 +1524,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL
|
||||||
for (auto &it : cell_stats)
|
for (auto &it : cell_stats)
|
||||||
log("ABC RESULTS: %15s cells: %8d\n", it.first, it.second);
|
log("ABC RESULTS: %15s cells: %8d\n", it.first, it.second);
|
||||||
int in_wires = 0, out_wires = 0;
|
int in_wires = 0, out_wires = 0;
|
||||||
for (auto &si : signal_list)
|
for (auto &si : run_abc.signal_list)
|
||||||
if (si.is_port) {
|
if (si.is_port) {
|
||||||
char buffer[100];
|
char buffer[100];
|
||||||
snprintf(buffer, 100, "\\ys__n%d", si.id);
|
snprintf(buffer, 100, "\\ys__n%d", si.id);
|
||||||
|
@ -1519,20 +1540,22 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL
|
||||||
}
|
}
|
||||||
connect(assign_map, module, conn);
|
connect(assign_map, module, conn);
|
||||||
}
|
}
|
||||||
log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
|
log("ABC RESULTS: internal signals: %8d\n", int(run_abc.signal_list.size()) - in_wires - out_wires);
|
||||||
log("ABC RESULTS: input signals: %8d\n", in_wires);
|
log("ABC RESULTS: input signals: %8d\n", in_wires);
|
||||||
log("ABC RESULTS: output signals: %8d\n", out_wires);
|
log("ABC RESULTS: output signals: %8d\n", out_wires);
|
||||||
|
|
||||||
delete mapped_design;
|
delete mapped_design;
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcModuleState::finish()
|
void AbcModuleState::finish()
|
||||||
{
|
{
|
||||||
if (config.cleanup)
|
if (run_abc.config.cleanup)
|
||||||
{
|
{
|
||||||
log("Removing temp directory.\n");
|
log("Removing temp directory.\n");
|
||||||
remove_directory(tempdir_name);
|
remove_directory(run_abc.tempdir_name);
|
||||||
}
|
}
|
||||||
|
log_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For every signal that connects cells from different sets, or a cell in a set to a cell not in any set,
|
// For every signal that connects cells from different sets, or a cell in a set to a cell not in any set,
|
||||||
|
@ -2182,12 +2205,8 @@ struct AbcPass : public Pass {
|
||||||
|
|
||||||
AbcModuleState state(config, initvals);
|
AbcModuleState state(config, initvals);
|
||||||
state.prepare_module(design, mod, assign_map, cells, dff_mode, clk_str);
|
state.prepare_module(design, mod, assign_map, cells, dff_mode, clk_str);
|
||||||
log_push();
|
state.run_abc.run();
|
||||||
log_header(design, "Executing ABC.\n");
|
|
||||||
state.run_abc();
|
|
||||||
state.extract(assign_map, design, mod);
|
state.extract(assign_map, design, mod);
|
||||||
state.finish();
|
|
||||||
log_pop();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2332,36 +2351,74 @@ struct AbcPass : public Pass {
|
||||||
}
|
}
|
||||||
|
|
||||||
log_header(design, "Summary of detected clock domains:\n");
|
log_header(design, "Summary of detected clock domains:\n");
|
||||||
for (auto &it : assigned_cells)
|
|
||||||
log(" %d cells in clk=%s%s, en=%s%s, arst=%s%s, srst=%s%s\n", GetSize(it.second),
|
|
||||||
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
|
|
||||||
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)),
|
|
||||||
std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)),
|
|
||||||
std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first)));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::vector<std::vector<RTLIL::Cell*>*> cell_sets;
|
std::vector<std::vector<RTLIL::Cell*>*> cell_sets;
|
||||||
for (auto &it : assigned_cells)
|
for (auto &it : assigned_cells) {
|
||||||
|
log(" %d cells in clk=%s%s, en=%s%s, arst=%s%s, srst=%s%s\n", GetSize(it.second),
|
||||||
|
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
|
||||||
|
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)),
|
||||||
|
std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)),
|
||||||
|
std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first)));
|
||||||
cell_sets.push_back(&it.second);
|
cell_sets.push_back(&it.second);
|
||||||
|
}
|
||||||
assign_cell_connection_ports(mod, cell_sets, assign_map);
|
assign_cell_connection_ports(mod, cell_sets, assign_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reserve one core for our main thread, and don't create more worker threads
|
||||||
|
// than ABC runs.
|
||||||
|
int max_threads = assigned_cells.size();
|
||||||
|
if (max_threads <= 1) {
|
||||||
|
// Just do everything on the main thread.
|
||||||
|
max_threads = 0;
|
||||||
|
}
|
||||||
|
#ifdef YOSYS_LINK_ABC
|
||||||
|
// ABC does't support multithreaded calls so don't call it off the main thread.
|
||||||
|
max_threads = 0;
|
||||||
|
#endif
|
||||||
|
int num_worker_threads = ThreadPool::pool_size(1, max_threads);
|
||||||
|
ConcurrentQueue<std::unique_ptr<AbcModuleState>> work_queue(num_worker_threads);
|
||||||
|
ConcurrentQueue<std::unique_ptr<AbcModuleState>> work_finished_queue;
|
||||||
|
int work_finished_count = 0;
|
||||||
|
ThreadPool worker_threads(num_worker_threads, [&](int){
|
||||||
|
while (std::optional<std::unique_ptr<AbcModuleState>> work =
|
||||||
|
work_queue.pop_front()) {
|
||||||
|
// Only the `run_abc` component is safe to touch here!
|
||||||
|
(*work)->run_abc.run();
|
||||||
|
work_finished_queue.push_back(std::move(*work));
|
||||||
|
}
|
||||||
|
});
|
||||||
for (auto &it : assigned_cells) {
|
for (auto &it : assigned_cells) {
|
||||||
AbcModuleState state(config, initvals);
|
// Process ABC results that have already finished before queueing another ABC.
|
||||||
state.clk_polarity = std::get<0>(it.first);
|
// This should keep our memory usage down.
|
||||||
state.clk_sig = assign_map(std::get<1>(it.first));
|
while (std::optional<std::unique_ptr<AbcModuleState>> work =
|
||||||
state.en_polarity = std::get<2>(it.first);
|
work_finished_queue.try_pop_front()) {
|
||||||
state.en_sig = assign_map(std::get<3>(it.first));
|
(*work)->extract(assign_map, design, mod);
|
||||||
state.arst_polarity = std::get<4>(it.first);
|
++work_finished_count;
|
||||||
state.arst_sig = assign_map(std::get<5>(it.first));
|
}
|
||||||
state.srst_polarity = std::get<6>(it.first);
|
std::unique_ptr<AbcModuleState> state = std::make_unique<AbcModuleState>(config, initvals);
|
||||||
state.srst_sig = assign_map(std::get<7>(it.first));
|
state->clk_polarity = std::get<0>(it.first);
|
||||||
state.prepare_module(design, mod, assign_map, it.second, !state.clk_sig.empty(), "$");
|
state->clk_sig = assign_map(std::get<1>(it.first));
|
||||||
log_push();
|
state->en_polarity = std::get<2>(it.first);
|
||||||
log_header(design, "Executing ABC.\n");
|
state->en_sig = assign_map(std::get<3>(it.first));
|
||||||
state.run_abc();
|
state->arst_polarity = std::get<4>(it.first);
|
||||||
state.extract(assign_map, design, mod);
|
state->arst_sig = assign_map(std::get<5>(it.first));
|
||||||
state.finish();
|
state->srst_polarity = std::get<6>(it.first);
|
||||||
log_pop();
|
state->srst_sig = assign_map(std::get<7>(it.first));
|
||||||
|
state->prepare_module(design, mod, assign_map, it.second, !state->clk_sig.empty(), "$");
|
||||||
|
if (num_worker_threads > 0) {
|
||||||
|
work_queue.push_back(std::move(state));
|
||||||
|
} else {
|
||||||
|
// Just run everything on the main thread.
|
||||||
|
state->run_abc.run();
|
||||||
|
work_finished_queue.push_back(std::move(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
work_queue.close();
|
||||||
|
while (work_finished_count < static_cast<int>(assigned_cells.size())) {
|
||||||
|
std::optional<std::unique_ptr<AbcModuleState>> work =
|
||||||
|
work_finished_queue.pop_front();
|
||||||
|
(*work)->extract(assign_map, design, mod);
|
||||||
|
++work_finished_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue