2014-07-27 07:50:25 -05:00
|
|
|
/*
|
|
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-08-16 17:56:47 -05:00
|
|
|
// This file contains various c++ utility routines and helper classes that
|
|
|
|
// do not depend on any other components of yosys (except stuff like log_*).
|
|
|
|
|
|
|
|
#include "kernel/yosys.h"
|
|
|
|
|
|
|
|
#ifndef UTILS_H
|
|
|
|
#define UTILS_H
|
|
|
|
|
2014-09-27 09:17:53 -05:00
|
|
|
YOSYS_NAMESPACE_BEGIN
|
|
|
|
|
2014-08-16 17:56:47 -05:00
|
|
|
// ------------------------------------------------
|
|
|
|
// A map-like container, but you can save and restore the state
|
|
|
|
// ------------------------------------------------
|
|
|
|
|
2014-12-28 12:24:24 -06:00
|
|
|
template<typename Key, typename T, typename OPS = hash_ops<Key>>
|
2014-08-16 17:56:47 -05:00
|
|
|
struct stackmap
|
|
|
|
{
|
|
|
|
private:
|
2014-12-28 12:24:24 -06:00
|
|
|
std::vector<dict<Key, T*, OPS>> backup_state;
|
|
|
|
dict<Key, T, OPS> current_state;
|
2014-08-16 17:56:47 -05:00
|
|
|
static T empty_tuple;
|
|
|
|
|
|
|
|
public:
|
|
|
|
stackmap() { }
|
2014-12-28 12:24:24 -06:00
|
|
|
stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
|
2014-08-16 17:56:47 -05:00
|
|
|
|
|
|
|
template<typename Other>
|
|
|
|
void operator=(const Other &other)
|
|
|
|
{
|
|
|
|
for (auto &it : current_state)
|
|
|
|
if (!backup_state.empty() && backup_state.back().count(it.first) == 0)
|
|
|
|
backup_state.back()[it.first] = new T(it.second);
|
|
|
|
current_state.clear();
|
|
|
|
|
|
|
|
for (auto &it : other)
|
|
|
|
set(it.first, it.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool has(const Key &k)
|
|
|
|
{
|
|
|
|
return current_state.count(k) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(const Key &k, const T &v)
|
|
|
|
{
|
|
|
|
if (!backup_state.empty() && backup_state.back().count(k) == 0)
|
|
|
|
backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
|
|
|
|
current_state[k] = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void unset(const Key &k)
|
|
|
|
{
|
|
|
|
if (!backup_state.empty() && backup_state.back().count(k) == 0)
|
|
|
|
backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
|
|
|
|
current_state.erase(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
const T &get(const Key &k)
|
|
|
|
{
|
|
|
|
if (current_state.count(k) == 0)
|
|
|
|
return empty_tuple;
|
|
|
|
return current_state.at(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset(const Key &k)
|
|
|
|
{
|
2014-10-10 09:59:44 -05:00
|
|
|
for (int i = GetSize(backup_state)-1; i >= 0; i--)
|
2014-08-16 17:56:47 -05:00
|
|
|
if (backup_state[i].count(k) != 0) {
|
|
|
|
if (backup_state[i].at(k) == nullptr)
|
|
|
|
current_state.erase(k);
|
|
|
|
else
|
|
|
|
current_state[k] = *backup_state[i].at(k);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
current_state.erase(k);
|
|
|
|
}
|
|
|
|
|
2014-12-28 12:24:24 -06:00
|
|
|
const dict<Key, T, OPS> &stdmap()
|
2014-08-16 17:56:47 -05:00
|
|
|
{
|
|
|
|
return current_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void save()
|
|
|
|
{
|
|
|
|
backup_state.resize(backup_state.size()+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void restore()
|
|
|
|
{
|
|
|
|
log_assert(!backup_state.empty());
|
|
|
|
for (auto &it : backup_state.back())
|
|
|
|
if (it.second != nullptr) {
|
|
|
|
current_state[it.first] = *it.second;
|
|
|
|
delete it.second;
|
|
|
|
} else
|
|
|
|
current_state.erase(it.first);
|
|
|
|
backup_state.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
~stackmap()
|
|
|
|
{
|
|
|
|
while (!backup_state.empty())
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------
|
|
|
|
// A simple class for topological sorting
|
|
|
|
// ------------------------------------------------
|
2014-07-27 07:50:25 -05:00
|
|
|
|
2014-11-07 08:21:03 -06:00
|
|
|
template<typename T, typename C = std::less<T>>
|
2014-07-27 07:50:25 -05:00
|
|
|
struct TopoSort
|
|
|
|
{
|
|
|
|
bool analyze_loops, found_loops;
|
2014-11-07 08:21:03 -06:00
|
|
|
std::map<T, std::set<T, C>, C> database;
|
|
|
|
std::set<std::set<T, C>> loops;
|
2014-07-27 07:50:25 -05:00
|
|
|
std::vector<T> sorted;
|
|
|
|
|
|
|
|
TopoSort()
|
|
|
|
{
|
|
|
|
analyze_loops = true;
|
|
|
|
found_loops = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void node(T n)
|
|
|
|
{
|
|
|
|
if (database.count(n) == 0)
|
2014-11-07 08:21:03 -06:00
|
|
|
database[n] = std::set<T, C>();
|
2014-07-27 07:50:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void edge(T left, T right)
|
|
|
|
{
|
|
|
|
node(left);
|
|
|
|
database[right].insert(left);
|
|
|
|
}
|
|
|
|
|
2014-11-07 08:21:03 -06:00
|
|
|
void sort_worker(const T &n, std::set<T, C> &marked_cells, std::set<T, C> &active_cells, std::vector<T> &active_stack)
|
2014-07-27 07:50:25 -05:00
|
|
|
{
|
|
|
|
if (active_cells.count(n)) {
|
2014-09-21 05:57:33 -05:00
|
|
|
found_loops = true;
|
2014-07-27 07:50:25 -05:00
|
|
|
if (analyze_loops) {
|
2014-11-07 08:21:03 -06:00
|
|
|
std::set<T, C> loop;
|
2014-10-10 09:59:44 -05:00
|
|
|
for (int i = GetSize(active_stack)-1; i >= 0; i--) {
|
2014-07-27 07:50:25 -05:00
|
|
|
loop.insert(active_stack[i]);
|
|
|
|
if (active_stack[i] == n)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
loops.insert(loop);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (marked_cells.count(n))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!database.at(n).empty())
|
|
|
|
{
|
|
|
|
if (analyze_loops)
|
|
|
|
active_stack.push_back(n);
|
|
|
|
active_cells.insert(n);
|
|
|
|
|
|
|
|
for (auto &left_n : database.at(n))
|
|
|
|
sort_worker(left_n, marked_cells, active_cells, active_stack);
|
|
|
|
|
|
|
|
if (analyze_loops)
|
|
|
|
active_stack.pop_back();
|
|
|
|
active_cells.erase(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
marked_cells.insert(n);
|
|
|
|
sorted.push_back(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool sort()
|
|
|
|
{
|
|
|
|
loops.clear();
|
|
|
|
sorted.clear();
|
|
|
|
found_loops = false;
|
|
|
|
|
2014-11-07 08:21:03 -06:00
|
|
|
std::set<T, C> marked_cells;
|
|
|
|
std::set<T, C> active_cells;
|
2014-07-27 07:50:25 -05:00
|
|
|
std::vector<T> active_stack;
|
|
|
|
|
|
|
|
for (auto &it : database)
|
|
|
|
sort_worker(it.first, marked_cells, active_cells, active_stack);
|
|
|
|
|
2014-10-10 09:59:44 -05:00
|
|
|
log_assert(GetSize(sorted) == GetSize(database));
|
2014-07-27 07:50:25 -05:00
|
|
|
return !found_loops;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-27 09:17:53 -05:00
|
|
|
YOSYS_NAMESPACE_END
|
|
|
|
|
2014-07-27 07:50:25 -05:00
|
|
|
#endif
|