mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
initial import
This commit is contained in:
commit
7764d0ba1d
481 changed files with 54634 additions and 0 deletions
143
kernel/bitpattern.h
Normal file
143
kernel/bitpattern.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BITPATTERN_H
|
||||
#define BITPATTERN_H
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
struct BitPatternPool
|
||||
{
|
||||
int width;
|
||||
typedef std::vector<RTLIL::State> bits_t;
|
||||
std::set<bits_t> pool;
|
||||
|
||||
BitPatternPool(RTLIL::SigSpec sig)
|
||||
{
|
||||
width = sig.width;
|
||||
if (width > 0) {
|
||||
std::vector<RTLIL::State> pattern(width);
|
||||
sig.optimize();
|
||||
for (int i = 0; i < width; i++) {
|
||||
RTLIL::SigSpec s = sig.extract(i, 1);
|
||||
s.optimize();
|
||||
assert(s.chunks.size() == 1);
|
||||
if (s.chunks[0].wire == NULL && s.chunks[0].data.bits[0] <= RTLIL::State::S1)
|
||||
pattern[i] = s.chunks[0].data.bits[0];
|
||||
else
|
||||
pattern[i] = RTLIL::State::Sa;
|
||||
}
|
||||
pool.insert(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
BitPatternPool(int width)
|
||||
{
|
||||
this->width = width;
|
||||
if (width > 0) {
|
||||
std::vector<RTLIL::State> pattern(width);
|
||||
for (int i = 0; i < width; i++)
|
||||
pattern[i] = RTLIL::State::Sa;
|
||||
pool.insert(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
bits_t sig2bits(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.optimize();
|
||||
assert(sig.is_fully_const());
|
||||
assert(sig.chunks.size() == 1);
|
||||
bits_t bits = sig.chunks[0].data.bits;
|
||||
for (auto &b : bits)
|
||||
if (b > RTLIL::State::S1)
|
||||
b = RTLIL::State::Sa;
|
||||
return bits;
|
||||
}
|
||||
|
||||
bool match(bits_t a, bits_t b)
|
||||
{
|
||||
assert(int(a.size()) == width);
|
||||
assert(int(b.size()) == width);
|
||||
for (int i = 0; i < width; i++)
|
||||
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool has_any(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
for (auto &it : pool)
|
||||
if (match(it, bits))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_all(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
for (auto &it : pool)
|
||||
if (match(it, bits)) {
|
||||
for (int i = 0; i < width; i++)
|
||||
if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
|
||||
goto next_pool_entry;
|
||||
return true;
|
||||
next_pool_entry:;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool take(RTLIL::SigSpec sig)
|
||||
{
|
||||
bool status = false;
|
||||
bits_t bits = sig2bits(sig);
|
||||
std::vector<bits_t> pattern_list;
|
||||
for (auto &it : pool)
|
||||
if (match(it, bits))
|
||||
pattern_list.push_back(it);
|
||||
for (auto pattern : pattern_list) {
|
||||
pool.erase(pattern);
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
|
||||
continue;
|
||||
bits_t new_pattern = pattern;
|
||||
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
pool.insert(new_pattern);
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool take_all()
|
||||
{
|
||||
if (pool.empty())
|
||||
return false;
|
||||
pool.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return pool.empty();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
392
kernel/calc.cc
Normal file
392
kernel/calc.cc
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "bigint/BigIntegerLibrary.hh"
|
||||
#include <assert.h>
|
||||
|
||||
static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
|
||||
{
|
||||
BigInteger result = 0, this_bit = 1;
|
||||
for (size_t i = 0; i < val.bits.size(); i++) {
|
||||
if (val.bits[i] == RTLIL::State::S1) {
|
||||
if (as_signed && i+1 == val.bits.size())
|
||||
result -= this_bit;
|
||||
else
|
||||
result += this_bit;
|
||||
}
|
||||
else if (val.bits[i] != RTLIL::State::S0) {
|
||||
if (undef_bit_pos < 0)
|
||||
undef_bit_pos = i;
|
||||
}
|
||||
this_bit *= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_bit_pos)
|
||||
{
|
||||
BigUnsigned mag = val.getMagnitude();
|
||||
RTLIL::Const result(0, result_len);
|
||||
|
||||
if (!mag.isZero())
|
||||
{
|
||||
if (val.getSign() < 0)
|
||||
{
|
||||
mag--;
|
||||
for (int i = 0; i < result_len; i++)
|
||||
result.bits[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < result_len; i++)
|
||||
result.bits[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
}
|
||||
}
|
||||
|
||||
if (undef_bit_pos >= 0)
|
||||
for (int i = undef_bit_pos; i < result_len; i++)
|
||||
result.bits[i] = RTLIL::State::Sx;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static RTLIL::State logic_and(RTLIL::State a, RTLIL::State b)
|
||||
{
|
||||
if (a == RTLIL::State::S0) return RTLIL::State::S0;
|
||||
if (b == RTLIL::State::S0) return RTLIL::State::S0;
|
||||
if (a != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
if (b != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
return RTLIL::State::S1;
|
||||
}
|
||||
|
||||
static RTLIL::State logic_or(RTLIL::State a, RTLIL::State b)
|
||||
{
|
||||
if (a == RTLIL::State::S1) return RTLIL::State::S1;
|
||||
if (b == RTLIL::State::S1) return RTLIL::State::S1;
|
||||
if (a != RTLIL::State::S0) return RTLIL::State::Sx;
|
||||
if (b != RTLIL::State::S0) return RTLIL::State::Sx;
|
||||
return RTLIL::State::S0;
|
||||
}
|
||||
|
||||
static RTLIL::State logic_xor(RTLIL::State a, RTLIL::State b)
|
||||
{
|
||||
if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
return a != b ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
}
|
||||
|
||||
static RTLIL::State logic_xnor(RTLIL::State a, RTLIL::State b)
|
||||
{
|
||||
if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
|
||||
return a == b ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len)
|
||||
{
|
||||
if (result_len < 0)
|
||||
result_len = arg1.bits.size();
|
||||
|
||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||
for (size_t i = 0; i < size_t(result_len); i++) {
|
||||
if (i >= arg1.bits.size())
|
||||
result.bits[i] = RTLIL::State::S0;
|
||||
else if (arg1.bits[i] == RTLIL::State::S0)
|
||||
result.bits[i] = RTLIL::State::S1;
|
||||
else if (arg1.bits[i] == RTLIL::State::S1)
|
||||
result.bits[i] = RTLIL::State::S0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State),
|
||||
const RTLIL::Const &arg1, const RTLIL::Const &arg2, int result_len = -1)
|
||||
{
|
||||
if (result_len < 0)
|
||||
result_len = std::max(arg1.bits.size(), arg2.bits.size());
|
||||
|
||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||
for (size_t i = 0; i < size_t(result_len); i++) {
|
||||
RTLIL::State a = i < arg1.bits.size() ? arg1.bits[i] : RTLIL::State::S0;
|
||||
RTLIL::State b = i < arg2.bits.size() ? arg2.bits[i] : RTLIL::State::S0;
|
||||
result.bits[i] = logic_func(a, b);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return logic_wrapper(logic_and, arg1, arg2, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return logic_wrapper(logic_or, arg1, arg2, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_xor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return logic_wrapper(logic_xor, arg1, arg2, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_xnor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return logic_wrapper(logic_xnor, arg1, arg2, result_len);
|
||||
}
|
||||
|
||||
static RTLIL::Const logic_reduce_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State), const RTLIL::Const &arg1)
|
||||
{
|
||||
RTLIL::State temp = RTLIL::State::S0;
|
||||
|
||||
for (size_t i = 0; i < arg1.bits.size(); i++)
|
||||
temp = logic_func(temp, arg1.bits[i]);
|
||||
|
||||
return RTLIL::Const(temp);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_reduce_and(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
|
||||
{
|
||||
return logic_reduce_wrapper(logic_and, arg1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_reduce_or(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
|
||||
{
|
||||
return logic_reduce_wrapper(logic_or, arg1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_reduce_xor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
|
||||
{
|
||||
return logic_reduce_wrapper(logic_xor, arg1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_reduce_xnor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
|
||||
{
|
||||
return logic_reduce_wrapper(logic_xnor, arg1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_reduce_bool(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
|
||||
{
|
||||
return logic_reduce_wrapper(logic_or, arg1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int)
|
||||
{
|
||||
int undef_bit_pos_a = -1;
|
||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
||||
|
||||
if (a.isZero()) {
|
||||
if (undef_bit_pos_a >= 0)
|
||||
return RTLIL::Const(RTLIL::State::Sx);
|
||||
return RTLIL::Const(RTLIL::State::S1);
|
||||
}
|
||||
|
||||
return RTLIL::Const(RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
|
||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
||||
BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
|
||||
|
||||
if (a.isZero() || b.isZero()) {
|
||||
if (undef_bit_pos_a >= 0 && undef_bit_pos_b >= 0)
|
||||
return RTLIL::Const(RTLIL::State::Sx);
|
||||
return RTLIL::Const(RTLIL::State::S0);
|
||||
}
|
||||
|
||||
return RTLIL::Const(RTLIL::State::S1);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
|
||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
||||
BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
|
||||
|
||||
if (a.isZero() && b.isZero()) {
|
||||
if (undef_bit_pos_a >= 0 || undef_bit_pos_b >= 0)
|
||||
return RTLIL::Const(RTLIL::State::Sx);
|
||||
return RTLIL::Const(RTLIL::State::S0);
|
||||
}
|
||||
|
||||
return RTLIL::Const(RTLIL::State::S1);
|
||||
}
|
||||
|
||||
static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
|
||||
|
||||
if (result_len < 0)
|
||||
result_len = arg1.bits.size();
|
||||
|
||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||
if (undef_bit_pos >= 0)
|
||||
return result;
|
||||
|
||||
for (int i = 0; i < result_len; i++) {
|
||||
BigInteger pos = BigInteger(i) + offset;
|
||||
if (pos < 0)
|
||||
result.bits[i] = RTLIL::State::S0;
|
||||
else if (pos >= arg1.bits.size())
|
||||
result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
|
||||
else
|
||||
result.bits[i] = arg1.bits[pos.toInt()];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return const_shift(arg1, arg2, false, -1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return const_shift(arg1, arg2, false, +1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return const_shift(arg1, arg2, true, -1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
|
||||
{
|
||||
return const_shift(arg1, arg2, true, +1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) == const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) != const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
|
||||
return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) / const2big(arg2, signed2, undef_bit_pos);
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) % const2big(arg2, signed2, undef_bit_pos);
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
int undef_bit_pos = -1;
|
||||
|
||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos);
|
||||
BigInteger b = const2big(arg2, signed2, undef_bit_pos);
|
||||
BigInteger y = 1;
|
||||
|
||||
if (b < 0 || a == 0) {
|
||||
y = 0;
|
||||
} else {
|
||||
while (b > 0) {
|
||||
y = y * a;
|
||||
if (y.getLength() > 0x10000) {
|
||||
undef_bit_pos = 0;
|
||||
break;
|
||||
}
|
||||
b--;
|
||||
}
|
||||
}
|
||||
|
||||
return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||
{
|
||||
RTLIL::Const zero(RTLIL::State::S0, 1);
|
||||
return RTLIL::const_add(zero, arg1, false, signed1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||
{
|
||||
RTLIL::Const zero(RTLIL::State::S0, 1);
|
||||
return RTLIL::const_sub(zero, arg1, false, signed1, result_len);
|
||||
}
|
||||
|
210
kernel/celltypes.h
Normal file
210
kernel/celltypes.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CELLTYPES_H
|
||||
#define CELLTYPES_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct CellTypes
|
||||
{
|
||||
std::set<std::string> cell_types;
|
||||
|
||||
void setup_internals()
|
||||
{
|
||||
cell_types.insert("$not");
|
||||
cell_types.insert("$pos");
|
||||
cell_types.insert("$neg");
|
||||
cell_types.insert("$and");
|
||||
cell_types.insert("$or");
|
||||
cell_types.insert("$xor");
|
||||
cell_types.insert("$xnor");
|
||||
cell_types.insert("$reduce_and");
|
||||
cell_types.insert("$reduce_or");
|
||||
cell_types.insert("$reduce_xor");
|
||||
cell_types.insert("$reduce_xnor");
|
||||
cell_types.insert("$reduce_bool");
|
||||
cell_types.insert("$shl");
|
||||
cell_types.insert("$shr");
|
||||
cell_types.insert("$sshl");
|
||||
cell_types.insert("$sshr");
|
||||
cell_types.insert("$lt");
|
||||
cell_types.insert("$le");
|
||||
cell_types.insert("$eq");
|
||||
cell_types.insert("$ne");
|
||||
cell_types.insert("$ge");
|
||||
cell_types.insert("$gt");
|
||||
cell_types.insert("$add");
|
||||
cell_types.insert("$sub");
|
||||
cell_types.insert("$mul");
|
||||
cell_types.insert("$div");
|
||||
cell_types.insert("$mod");
|
||||
cell_types.insert("$pow");
|
||||
cell_types.insert("$logic_not");
|
||||
cell_types.insert("$logic_and");
|
||||
cell_types.insert("$logic_or");
|
||||
cell_types.insert("$mux");
|
||||
cell_types.insert("$pmux");
|
||||
cell_types.insert("$safe_pmux");
|
||||
}
|
||||
|
||||
void setup_internals_mem()
|
||||
{
|
||||
cell_types.insert("$dff");
|
||||
cell_types.insert("$adff");
|
||||
cell_types.insert("$memrd");
|
||||
cell_types.insert("$memwr");
|
||||
cell_types.insert("$mem");
|
||||
cell_types.insert("$fsm");
|
||||
}
|
||||
|
||||
void setup_stdcells()
|
||||
{
|
||||
cell_types.insert("$_INV_");
|
||||
cell_types.insert("$_AND_");
|
||||
cell_types.insert("$_OR_");
|
||||
cell_types.insert("$_XOR_");
|
||||
cell_types.insert("$_MUX_");
|
||||
}
|
||||
|
||||
void setup_stdcells_mem()
|
||||
{
|
||||
cell_types.insert("$_DFF_N_");
|
||||
cell_types.insert("$_DFF_P_");
|
||||
cell_types.insert("$_DFF_NN0_");
|
||||
cell_types.insert("$_DFF_NN1_");
|
||||
cell_types.insert("$_DFF_NP0_");
|
||||
cell_types.insert("$_DFF_NP1_");
|
||||
cell_types.insert("$_DFF_PN0_");
|
||||
cell_types.insert("$_DFF_PN1_");
|
||||
cell_types.insert("$_DFF_PP0_");
|
||||
cell_types.insert("$_DFF_PP1_");
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
cell_types.clear();
|
||||
}
|
||||
|
||||
bool cell_known(std::string type)
|
||||
{
|
||||
return cell_types.count(type) > 0;
|
||||
}
|
||||
|
||||
bool cell_output(std::string type, std::string port)
|
||||
{
|
||||
if (!cell_known(type))
|
||||
return false;
|
||||
if (port == "\\Y" || port == "\\Q" || port == "\\RD_DATA")
|
||||
return true;
|
||||
if (type == "$memrd" && port == "\\DATA")
|
||||
return true;
|
||||
if (type == "$fsm" && port == "\\CTRL_OUT")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cell_input(std::string type, std::string port)
|
||||
{
|
||||
if (!cell_known(type))
|
||||
return false;
|
||||
return !cell_output(type, port);
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(std::string type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
{
|
||||
#define HANDLE_CELL_TYPE(_t) if (type == "$" #_t) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);
|
||||
HANDLE_CELL_TYPE(not)
|
||||
HANDLE_CELL_TYPE(and)
|
||||
HANDLE_CELL_TYPE(or)
|
||||
HANDLE_CELL_TYPE(xor)
|
||||
HANDLE_CELL_TYPE(xnor)
|
||||
HANDLE_CELL_TYPE(reduce_and)
|
||||
HANDLE_CELL_TYPE(reduce_or)
|
||||
HANDLE_CELL_TYPE(reduce_xor)
|
||||
HANDLE_CELL_TYPE(reduce_xnor)
|
||||
HANDLE_CELL_TYPE(reduce_bool)
|
||||
HANDLE_CELL_TYPE(logic_not)
|
||||
HANDLE_CELL_TYPE(logic_and)
|
||||
HANDLE_CELL_TYPE(logic_or)
|
||||
HANDLE_CELL_TYPE(shl)
|
||||
HANDLE_CELL_TYPE(shr)
|
||||
HANDLE_CELL_TYPE(sshl)
|
||||
HANDLE_CELL_TYPE(sshr)
|
||||
HANDLE_CELL_TYPE(lt)
|
||||
HANDLE_CELL_TYPE(le)
|
||||
HANDLE_CELL_TYPE(eq)
|
||||
HANDLE_CELL_TYPE(ne)
|
||||
HANDLE_CELL_TYPE(ge)
|
||||
HANDLE_CELL_TYPE(gt)
|
||||
HANDLE_CELL_TYPE(add)
|
||||
HANDLE_CELL_TYPE(sub)
|
||||
HANDLE_CELL_TYPE(mul)
|
||||
HANDLE_CELL_TYPE(div)
|
||||
HANDLE_CELL_TYPE(mod)
|
||||
HANDLE_CELL_TYPE(pow)
|
||||
HANDLE_CELL_TYPE(pos)
|
||||
HANDLE_CELL_TYPE(neg)
|
||||
#undef HANDLE_CELL_TYPE
|
||||
|
||||
if (type == "$_INV_")
|
||||
return const_not(arg1, arg2, false, false, 1);
|
||||
if (type == "$_AND_")
|
||||
return const_and(arg1, arg2, false, false, 1);
|
||||
if (type == "$_OR_")
|
||||
return const_or(arg1, arg2, false, false, 1);
|
||||
if (type == "$_XOR_")
|
||||
return const_xor(arg1, arg2, false, false, 1);
|
||||
|
||||
assert(!"Called CellType.eval() with unsupported cell type!");
|
||||
abort();
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
|
||||
{
|
||||
bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
|
||||
bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
|
||||
int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
|
||||
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &sel)
|
||||
{
|
||||
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
|
||||
RTLIL::Const ret = arg1;
|
||||
for (size_t i = 0; i < sel.bits.size(); i++)
|
||||
if (sel.bits[i] == RTLIL::State::S1) {
|
||||
std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
|
||||
ret = RTLIL::Const(bits);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
assert(sel.bits.size() == 0);
|
||||
bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
|
||||
bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
|
||||
int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
|
||||
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
198
kernel/consteval.h
Normal file
198
kernel/consteval.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONSTEVAL_H
|
||||
#define CONSTEVAL_H
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
|
||||
struct ConstEval
|
||||
{
|
||||
RTLIL::Module *module;
|
||||
SigMap assign_map;
|
||||
SigMap values_map;
|
||||
SigPool stop_signals;
|
||||
SigSet<RTLIL::Cell*> sig2driver;
|
||||
std::set<RTLIL::Cell*> busy;
|
||||
std::vector<SigMap> stack;
|
||||
|
||||
ConstEval(RTLIL::Module *module) : module(module), assign_map(module)
|
||||
{
|
||||
CellTypes ct;
|
||||
ct.setup_internals();
|
||||
ct.setup_stdcells();
|
||||
|
||||
for (auto &it : module->cells) {
|
||||
if (!ct.cell_known(it.second->type))
|
||||
continue;
|
||||
for (auto &it2 : it.second->connections)
|
||||
if (ct.cell_output(it.second->type, it2.first))
|
||||
sig2driver.insert(assign_map(it2.second), it.second);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
values_map.clear();
|
||||
stop_signals.clear();
|
||||
}
|
||||
|
||||
void push()
|
||||
{
|
||||
stack.push_back(values_map);
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
values_map.swap(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
void set(RTLIL::SigSpec sig, RTLIL::Const value)
|
||||
{
|
||||
assign_map.apply(sig);
|
||||
#ifndef NDEBUG
|
||||
RTLIL::SigSpec current_val = values_map(sig);
|
||||
current_val.expand();
|
||||
for (size_t i = 0; i < current_val.chunks.size(); i++) {
|
||||
RTLIL::SigChunk &chunk = current_val.chunks[i];
|
||||
assert(chunk.wire != NULL || chunk.data.bits[0] == value.bits[i]);
|
||||
}
|
||||
#endif
|
||||
values_map.add(sig, RTLIL::SigSpec(value));
|
||||
}
|
||||
|
||||
void stop(RTLIL::SigSpec sig)
|
||||
{
|
||||
assign_map.apply(sig);
|
||||
stop_signals.add(sig);
|
||||
}
|
||||
|
||||
bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
|
||||
{
|
||||
RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
|
||||
bool ignore_sig_a = false, ignore_sig_b = false;
|
||||
int sig_b_shift = -1;
|
||||
|
||||
assert(cell->connections.count("\\Y") > 0);
|
||||
sig_y = values_map(assign_map(cell->connections["\\Y"]));
|
||||
if (sig_y.is_fully_const())
|
||||
return true;
|
||||
|
||||
if (cell->connections.count("\\S") > 0) {
|
||||
sig_s = cell->connections["\\S"];
|
||||
if (!eval(sig_s, undef, cell))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
|
||||
bool found_collision = false;
|
||||
for (int i = 0; i < sig_s.width; i++)
|
||||
if (sig_s.extract(i, 1).as_bool()) {
|
||||
if (sig_b_shift >= 0)
|
||||
found_collision = true;
|
||||
sig_b_shift = i;
|
||||
ignore_sig_a = true;
|
||||
if (cell->type != "$safe_pmux")
|
||||
break;
|
||||
}
|
||||
if (found_collision) {
|
||||
sig_b_shift = -1;
|
||||
ignore_sig_a = false;
|
||||
}
|
||||
if (sig_b_shift < 0)
|
||||
ignore_sig_b = true;
|
||||
}
|
||||
|
||||
if (!ignore_sig_a && cell->connections.count("\\A") > 0) {
|
||||
sig_a = cell->connections["\\A"];
|
||||
if (!eval(sig_a, undef, cell))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ignore_sig_b && cell->connections.count("\\B") > 0) {
|
||||
sig_b = cell->connections["\\B"];
|
||||
if (sig_b_shift >= 0)
|
||||
sig_b = sig_b.extract(sig_y.width*sig_b_shift, sig_y.width);
|
||||
if (!eval(sig_b, undef, cell))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_")
|
||||
set(sig_y, sig_s.as_bool() ? sig_b.as_const() : sig_a.as_const());
|
||||
else
|
||||
set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL)
|
||||
{
|
||||
assign_map.apply(sig);
|
||||
values_map.apply(sig);
|
||||
|
||||
if (sig.is_fully_const())
|
||||
return true;
|
||||
|
||||
if (stop_signals.check_any(sig)) {
|
||||
undef = stop_signals.extract(sig);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (busy_cell) {
|
||||
if (busy.count(busy_cell) > 0) {
|
||||
undef = sig;
|
||||
return false;
|
||||
}
|
||||
busy.insert(busy_cell);
|
||||
}
|
||||
|
||||
std::set<RTLIL::Cell*> driver_cells;
|
||||
sig2driver.find(sig, driver_cells);
|
||||
for (auto cell : driver_cells) {
|
||||
if (!eval(cell, undef)) {
|
||||
if (busy_cell)
|
||||
busy.erase(busy_cell);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (busy_cell)
|
||||
busy.erase(busy_cell);
|
||||
|
||||
values_map.apply(sig);
|
||||
if (sig.is_fully_const())
|
||||
return true;
|
||||
|
||||
for (size_t i = 0; i < sig.chunks.size(); i++)
|
||||
if (sig.chunks[i].wire != NULL)
|
||||
undef.append(sig.chunks[i]);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eval(RTLIL::SigSpec &sig)
|
||||
{
|
||||
RTLIL::SigSpec undef;
|
||||
return eval(sig, undef);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
253
kernel/driver.cc
Normal file
253
kernel/driver.cc
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command)
|
||||
{
|
||||
if (command == "auto") {
|
||||
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
|
||||
command = "verilog";
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
|
||||
command = "ilang";
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
|
||||
command = "script";
|
||||
else if (filename == "-")
|
||||
command = "ilang";
|
||||
else
|
||||
log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
|
||||
}
|
||||
|
||||
if (command == "script") {
|
||||
log("\n-- Executing script file `%s' --\n", filename.c_str());
|
||||
FILE *f = fopen(filename.c_str(), "r");
|
||||
if (f == NULL)
|
||||
log_error("Can;t open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
|
||||
char buffer[4096];
|
||||
while (fgets(buffer, 4096, f) != NULL) {
|
||||
Pass::call(design, buffer);
|
||||
design->check();
|
||||
}
|
||||
fclose(f);
|
||||
if (backend_command != NULL && *backend_command == "auto")
|
||||
*backend_command = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename == "-") {
|
||||
log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
|
||||
} else {
|
||||
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
|
||||
}
|
||||
|
||||
Frontend::frontend_call(design, NULL, filename, command);
|
||||
design->check();
|
||||
}
|
||||
|
||||
static void run_pass(std::string command, RTLIL::Design *design)
|
||||
{
|
||||
log("\n-- Running pass `%s' --\n", command.c_str());
|
||||
|
||||
Pass::call(design, command);
|
||||
design->check();
|
||||
}
|
||||
|
||||
static void run_backend(std::string filename, std::string command, RTLIL::Design *design)
|
||||
{
|
||||
if (command == "auto") {
|
||||
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
|
||||
command = "verilog";
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
|
||||
command = "ilang";
|
||||
else if (filename == "-")
|
||||
command = "ilang";
|
||||
else
|
||||
log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
|
||||
}
|
||||
|
||||
if (filename == "-") {
|
||||
log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
|
||||
} else {
|
||||
log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
|
||||
}
|
||||
|
||||
Backend::backend_call(design, NULL, filename, command);
|
||||
design->check();
|
||||
}
|
||||
|
||||
static char *readline_cmd_generator(const char *text, int state)
|
||||
{
|
||||
static std::map<std::string, Pass*>::iterator it;
|
||||
static int len;
|
||||
|
||||
if (!state) {
|
||||
it = REGISTER_INTERN::pass_register.begin();
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
for (; it != REGISTER_INTERN::pass_register.end(); it++) {
|
||||
if (it->first.substr(0, len) == text)
|
||||
return strdup((it++)->first.c_str());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char **readline_completion(const char *text, int start, int)
|
||||
{
|
||||
if (start == 0)
|
||||
return rl_completion_matches(text, readline_cmd_generator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *create_prompt(RTLIL::Design *design)
|
||||
{
|
||||
static char buffer[100];
|
||||
std::string str = "\nyosys";
|
||||
if (!design->selected_active_module.empty())
|
||||
str += stringf(" [%s]", design->selected_active_module.c_str());
|
||||
if (!design->selection_stack.back().full_selection) {
|
||||
if (design->selected_active_module.empty())
|
||||
str += "*";
|
||||
else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
|
||||
design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
|
||||
str += "*";
|
||||
}
|
||||
snprintf(buffer, 100, "%s> ", str.c_str());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string frontend_command = "auto";
|
||||
std::string backend_command = "auto";
|
||||
std::vector<std::string> passes_commands;
|
||||
std::string output_filename = "-";
|
||||
std::string scriptfile = "";
|
||||
bool got_output_filename = false;
|
||||
|
||||
RTLIL::Design *design = new RTLIL::Design;
|
||||
design->selection_stack.push_back(RTLIL::Selection());
|
||||
log_push();
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "f:b:o:p:l:qts:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
frontend_command = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
backend_command = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
passes_commands.push_back(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
output_filename = optarg;
|
||||
got_output_filename = true;
|
||||
break;
|
||||
case 'l':
|
||||
log_files.push_back(fopen(optarg, "wt"));
|
||||
if (log_files.back() == NULL) {
|
||||
fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
log_errfile = stderr;
|
||||
break;
|
||||
case 't':
|
||||
log_time = true;
|
||||
break;
|
||||
case 's':
|
||||
scriptfile = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [-s <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [<infile> [..]]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (log_errfile == NULL)
|
||||
log_files.push_back(stderr);
|
||||
|
||||
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty())
|
||||
{
|
||||
log_cmd_error_throw = true;
|
||||
|
||||
rl_readline_name = "yosys";
|
||||
rl_attempted_completion_function = readline_completion;
|
||||
|
||||
char *command = NULL;
|
||||
while ((command = readline(create_prompt(design))) != NULL)
|
||||
{
|
||||
if (command[strspn(command, " \t\r\n")] == 0)
|
||||
continue;
|
||||
add_history(command);
|
||||
|
||||
try {
|
||||
assert(design->selection_stack.size() == 1);
|
||||
Pass::call(design, command);
|
||||
} catch (int) {
|
||||
while (design->selection_stack.size() > 1)
|
||||
design->selection_stack.pop_back();
|
||||
log_reset_stack();
|
||||
}
|
||||
}
|
||||
|
||||
if (!got_output_filename)
|
||||
backend_command = "";
|
||||
log_cmd_error_throw = false;
|
||||
}
|
||||
|
||||
while (optind < argc)
|
||||
run_frontend(argv[optind++], frontend_command, design, output_filename == "-" ? &backend_command : NULL);
|
||||
|
||||
if (!scriptfile.empty())
|
||||
run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL);
|
||||
|
||||
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
|
||||
run_pass(*it, design);
|
||||
|
||||
if (!backend_command.empty())
|
||||
run_backend(output_filename, backend_command, design);
|
||||
|
||||
delete design;
|
||||
|
||||
log("\nREADY.\n");
|
||||
log_pop();
|
||||
|
||||
for (auto f : log_files)
|
||||
if (f != stderr)
|
||||
fclose(f);
|
||||
log_errfile = NULL;
|
||||
log_files.clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
197
kernel/log.cc
Normal file
197
kernel/log.cc
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "backends/ilang/ilang_backend.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
std::vector<FILE*> log_files;
|
||||
FILE *log_errfile = NULL;
|
||||
bool log_time = false;
|
||||
bool log_cmd_error_throw = false;
|
||||
|
||||
std::vector<int> header_count;
|
||||
std::list<std::string> string_buf;
|
||||
|
||||
static struct timeval initial_tv = { 0, 0 };
|
||||
static bool next_print_log = false;
|
||||
|
||||
std::string stringf(const char *fmt, ...)
|
||||
{
|
||||
std::string string;
|
||||
char *str = NULL;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vasprintf(&str, fmt, ap) < 0)
|
||||
str = NULL;
|
||||
va_end(ap);
|
||||
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
free(str);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void logv(const char *format, va_list ap)
|
||||
{
|
||||
if (log_time) {
|
||||
while (format[0] == '\n' && format[1] != 0) {
|
||||
format++;
|
||||
log("\n");
|
||||
}
|
||||
if (next_print_log || initial_tv.tv_sec == 0) {
|
||||
next_print_log = false;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if (initial_tv.tv_sec == 0)
|
||||
initial_tv = tv;
|
||||
if (tv.tv_usec < initial_tv.tv_usec) {
|
||||
tv.tv_sec--;
|
||||
tv.tv_usec += 1000000;
|
||||
}
|
||||
tv.tv_sec -= initial_tv.tv_sec;
|
||||
tv.tv_usec -= initial_tv.tv_usec;
|
||||
log("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
|
||||
}
|
||||
if (format[0] && format[strlen(format)-1] == '\n')
|
||||
next_print_log = true;
|
||||
}
|
||||
|
||||
for (auto f : log_files) {
|
||||
va_list aq;
|
||||
va_copy(aq, ap);
|
||||
vfprintf(f, format, aq);
|
||||
va_end(aq);
|
||||
}
|
||||
}
|
||||
|
||||
void logv_header(const char *format, va_list ap)
|
||||
{
|
||||
log("\n");
|
||||
if (header_count.size() > 0)
|
||||
header_count.back()++;
|
||||
for (int c : header_count)
|
||||
log("%d.", c);
|
||||
log(" ");
|
||||
logv(format, ap);
|
||||
log_flush();
|
||||
}
|
||||
|
||||
void logv_error(const char *format, va_list ap)
|
||||
{
|
||||
log("ERROR: ");
|
||||
logv(format, ap);
|
||||
if (log_errfile != NULL) {
|
||||
fprintf(log_errfile, "ERROR: ");
|
||||
vfprintf(log_errfile, format, ap);
|
||||
}
|
||||
log_flush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void log(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
logv(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_header(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
logv_header(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_error(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
logv_error(format, ap);
|
||||
}
|
||||
|
||||
void log_cmd_error(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
if (log_cmd_error_throw) {
|
||||
log("ERROR: ");
|
||||
logv(format, ap);
|
||||
log_flush();
|
||||
throw 0;
|
||||
}
|
||||
|
||||
logv_error(format, ap);
|
||||
}
|
||||
|
||||
void log_push()
|
||||
{
|
||||
header_count.push_back(0);
|
||||
}
|
||||
|
||||
void log_pop()
|
||||
{
|
||||
header_count.pop_back();
|
||||
string_buf.clear();
|
||||
log_flush();
|
||||
}
|
||||
|
||||
void log_reset_stack()
|
||||
{
|
||||
while (header_count.size() > 1)
|
||||
header_count.pop_back();
|
||||
string_buf.clear();
|
||||
log_flush();
|
||||
}
|
||||
|
||||
void log_flush()
|
||||
{
|
||||
for (auto f : log_files)
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
|
||||
FILE *f = open_memstream(&ptr, &size);
|
||||
ILANG_BACKEND::dump_sigspec(f, sig, autoint);
|
||||
fputc(0, f);
|
||||
fclose(f);
|
||||
|
||||
string_buf.push_back(ptr);
|
||||
free(ptr);
|
||||
|
||||
return string_buf.back().c_str();
|
||||
}
|
||||
|
51
kernel/log.h
Normal file
51
kernel/log.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
extern std::vector<FILE*> log_files;
|
||||
extern FILE *log_errfile;
|
||||
extern bool log_time;
|
||||
extern bool log_cmd_error_throw;
|
||||
|
||||
std::string stringf(const char *fmt, ...);
|
||||
|
||||
void logv(const char *format, va_list ap);
|
||||
void logv_header(const char *format, va_list ap);
|
||||
void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
|
||||
|
||||
void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
|
||||
void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
|
||||
|
||||
void log_push();
|
||||
void log_pop();
|
||||
|
||||
void log_reset_stack();
|
||||
void log_flush();
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
||||
|
||||
#endif
|
288
kernel/register.cc
Normal file
288
kernel/register.cc
Normal file
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "register.h"
|
||||
#include "log.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace REGISTER_INTERN;
|
||||
|
||||
namespace REGISTER_INTERN {
|
||||
std::map<std::string, Frontend*> frontend_register;
|
||||
std::map<std::string, Pass*> pass_register;
|
||||
std::map<std::string, Backend*> backend_register;
|
||||
}
|
||||
|
||||
std::vector<std::string> Frontend::next_args;
|
||||
|
||||
Pass::Pass(std::string name) : pass_name(name)
|
||||
{
|
||||
assert(pass_register.count(name) == 0);
|
||||
pass_register[name] = this;
|
||||
}
|
||||
|
||||
Pass::~Pass()
|
||||
{
|
||||
pass_register.erase(pass_name);
|
||||
}
|
||||
|
||||
void Pass::help()
|
||||
{
|
||||
log("No help message for this command.\n");
|
||||
}
|
||||
|
||||
void Pass::cmd_log_args(const std::vector<std::string> &args)
|
||||
{
|
||||
if (args.size() <= 1)
|
||||
return;
|
||||
log("Full command line:");
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
log(" %s", args[i].c_str());
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void Pass::cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg)
|
||||
{
|
||||
std::string command_text;
|
||||
int error_pos = 0;
|
||||
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
if (i < argidx)
|
||||
error_pos += args[i].size() + 1;
|
||||
command_text = command_text + (command_text.empty() ? "" : " ") + args[i];
|
||||
}
|
||||
|
||||
log("\nSyntax error in command `%s':\n", command_text.c_str());
|
||||
help();
|
||||
|
||||
log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n",
|
||||
msg.c_str(), command_text.c_str(), error_pos, "");
|
||||
}
|
||||
|
||||
void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *)
|
||||
{
|
||||
for (; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
|
||||
if (arg.substr(0, 1) == "-")
|
||||
cmd_error(args, argidx, "Unkown option or option in arguments.");
|
||||
cmd_error(args, argidx, "Extra argument.");
|
||||
}
|
||||
cmd_log_args(args);
|
||||
}
|
||||
|
||||
void Pass::call(RTLIL::Design *design, std::string command)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
char *s = strdup(command.c_str());
|
||||
for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
|
||||
args.push_back(p);
|
||||
free(s);
|
||||
call(design, args);
|
||||
}
|
||||
|
||||
void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() == 0 || args[0][0] == '#')
|
||||
return;
|
||||
if (pass_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such command: %s\n", args[0].c_str());
|
||||
|
||||
size_t orig_sel_stack_pos = design->selection_stack.size();
|
||||
pass_register[args[0]]->execute(args, design);
|
||||
while (design->selection_stack.size() > orig_sel_stack_pos)
|
||||
design->selection_stack.pop_back();
|
||||
}
|
||||
|
||||
Frontend::Frontend(std::string name) : Pass("read_"+name), frontend_name(name)
|
||||
{
|
||||
assert(frontend_register.count(name) == 0);
|
||||
frontend_register[name] = this;
|
||||
}
|
||||
|
||||
Frontend::~Frontend()
|
||||
{
|
||||
frontend_register.erase(frontend_name);
|
||||
}
|
||||
|
||||
void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
assert(next_args.empty());
|
||||
do {
|
||||
FILE *f = NULL;
|
||||
next_args.clear();
|
||||
execute(f, std::string(), args, design);
|
||||
args = next_args;
|
||||
fclose(f);
|
||||
} while (!args.empty());
|
||||
}
|
||||
|
||||
void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
|
||||
{
|
||||
bool called_with_fp = f != NULL;
|
||||
|
||||
next_args.clear();
|
||||
for (; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
|
||||
if (arg.substr(0, 1) == "-")
|
||||
cmd_error(args, argidx, "Unkown option or option in arguments.");
|
||||
if (f != NULL)
|
||||
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
|
||||
|
||||
filename = arg;
|
||||
f = fopen(filename.c_str(), "r");
|
||||
if (f == NULL)
|
||||
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
|
||||
|
||||
if (argidx+1 < args.size()) {
|
||||
next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
|
||||
next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
|
||||
args.erase(args.begin()+argidx+1, args.end());
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (f == NULL)
|
||||
cmd_error(args, argidx, "No filename given.");
|
||||
|
||||
if (called_with_fp)
|
||||
args.push_back(filename);
|
||||
args[0] = pass_name;
|
||||
cmd_log_args(args);
|
||||
}
|
||||
|
||||
void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
char *s = strdup(command.c_str());
|
||||
for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
|
||||
args.push_back(p);
|
||||
free(s);
|
||||
frontend_call(design, f, filename, args);
|
||||
}
|
||||
|
||||
void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() == 0)
|
||||
return;
|
||||
if (frontend_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such frontend: %s\n", args[0].c_str());
|
||||
|
||||
if (f != NULL) {
|
||||
frontend_register[args[0]]->execute(f, filename, args, design);
|
||||
} else if (filename == "-") {
|
||||
frontend_register[args[0]]->execute(stdin, "<stdin>", args, design);
|
||||
} else {
|
||||
if (!filename.empty())
|
||||
args.push_back(filename);
|
||||
frontend_register[args[0]]->execute(args, design);
|
||||
}
|
||||
}
|
||||
|
||||
Backend::Backend(std::string name) : Pass("write_"+name), backend_name(name)
|
||||
{
|
||||
assert(backend_register.count(name) == 0);
|
||||
backend_register[name] = this;
|
||||
}
|
||||
|
||||
Backend::~Backend()
|
||||
{
|
||||
backend_register.erase(backend_name);
|
||||
}
|
||||
|
||||
void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
execute(f, std::string(), args, design);
|
||||
if (f != stdout)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
|
||||
{
|
||||
bool called_with_fp = f != NULL;
|
||||
|
||||
for (; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
|
||||
if (arg.substr(0, 1) == "-" && arg != "-")
|
||||
cmd_error(args, argidx, "Unkown option or option in arguments.");
|
||||
if (f != NULL)
|
||||
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
|
||||
|
||||
if (arg == "-") {
|
||||
filename = "<stdout>";
|
||||
f = stdout;
|
||||
continue;
|
||||
}
|
||||
|
||||
filename = arg;
|
||||
f = fopen(filename.c_str(), "w");
|
||||
if (f == NULL)
|
||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
|
||||
}
|
||||
|
||||
if (called_with_fp)
|
||||
args.push_back(filename);
|
||||
args[0] = pass_name;
|
||||
cmd_log_args(args);
|
||||
|
||||
if (f == NULL) {
|
||||
filename = "<stdout>";
|
||||
f = stdout;
|
||||
}
|
||||
}
|
||||
|
||||
void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
char *s = strdup(command.c_str());
|
||||
for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
|
||||
args.push_back(p);
|
||||
free(s);
|
||||
backend_call(design, f, filename, args);
|
||||
}
|
||||
|
||||
void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() == 0)
|
||||
return;
|
||||
if (backend_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such backend: %s\n", args[0].c_str());
|
||||
|
||||
size_t orig_sel_stack_pos = design->selection_stack.size();
|
||||
|
||||
if (f != NULL) {
|
||||
backend_register[args[0]]->execute(f, filename, args, design);
|
||||
} else if (filename == "-") {
|
||||
backend_register[args[0]]->execute(stdout, "<stdout>", args, design);
|
||||
} else {
|
||||
if (!filename.empty())
|
||||
args.push_back(filename);
|
||||
backend_register[args[0]]->execute(args, design);
|
||||
}
|
||||
|
||||
while (design->selection_stack.size() > orig_sel_stack_pos)
|
||||
design->selection_stack.pop_back();
|
||||
}
|
||||
|
80
kernel/register.h
Normal file
80
kernel/register.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef REGISTER_H
|
||||
#define REGISTER_H
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
struct Pass
|
||||
{
|
||||
std::string pass_name;
|
||||
Pass(std::string name);
|
||||
virtual ~Pass();
|
||||
virtual void help();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
void cmd_log_args(const std::vector<std::string> &args);
|
||||
void cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg);
|
||||
void extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design);
|
||||
|
||||
static void call(RTLIL::Design *design, std::string command);
|
||||
static void call(RTLIL::Design *design, std::vector<std::string> args);
|
||||
};
|
||||
|
||||
struct Frontend : Pass
|
||||
{
|
||||
std::string frontend_name;
|
||||
Frontend(std::string name);
|
||||
virtual ~Frontend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
|
||||
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
static std::vector<std::string> next_args;
|
||||
void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
|
||||
|
||||
static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
|
||||
static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
|
||||
};
|
||||
|
||||
struct Backend : Pass
|
||||
{
|
||||
std::string backend_name;
|
||||
Backend(std::string name);
|
||||
virtual ~Backend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
|
||||
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
|
||||
|
||||
static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
|
||||
static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
|
||||
};
|
||||
|
||||
namespace REGISTER_INTERN {
|
||||
extern std::map<std::string, Pass*> pass_register;
|
||||
extern std::map<std::string, Frontend*> frontend_register;
|
||||
extern std::map<std::string, Backend*> backend_register;
|
||||
}
|
||||
|
||||
#endif
|
1081
kernel/rtlil.cc
Normal file
1081
kernel/rtlil.cc
Normal file
File diff suppressed because it is too large
Load diff
341
kernel/rtlil.h
Normal file
341
kernel/rtlil.h
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RTLIL_H
|
||||
#define RTLIL_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
|
||||
std::string stringf(const char *fmt, ...);
|
||||
|
||||
namespace RTLIL
|
||||
{
|
||||
enum State {
|
||||
S0 = 0,
|
||||
S1 = 1,
|
||||
Sx = 2, // undefined value or conflict
|
||||
Sz = 3, // high-impedance / not-connected
|
||||
Sa = 4, // don't care (used only in cases)
|
||||
Sm = 5 // marker (used internally by some passes)
|
||||
};
|
||||
enum SyncType {
|
||||
ST0 = 0, // level sensitive: 0
|
||||
ST1 = 1, // level sensitive: 1
|
||||
STp = 2, // edge sensitive: posedge
|
||||
STn = 3, // edge sensitive: negedge
|
||||
STe = 4, // edge sensitive: both edges
|
||||
STa = 5 // always active
|
||||
};
|
||||
|
||||
extern int autoidx;
|
||||
|
||||
struct Const;
|
||||
struct Selection;
|
||||
struct Design;
|
||||
struct Module;
|
||||
struct Wire;
|
||||
struct Memory;
|
||||
struct Cell;
|
||||
struct SigChunk;
|
||||
struct SigSpec;
|
||||
struct CaseRule;
|
||||
struct SwitchRule;
|
||||
struct SyncRule;
|
||||
struct Process;
|
||||
|
||||
typedef std::pair<SigSpec, SigSpec> SigSig;
|
||||
|
||||
#ifdef NDEBUG
|
||||
typedef std::string IdString;
|
||||
#else
|
||||
struct IdString : public std::string {
|
||||
IdString() { }
|
||||
IdString(std::string str) : std::string(str) {
|
||||
check();
|
||||
}
|
||||
IdString(const char *s) : std::string(s) {
|
||||
check();
|
||||
}
|
||||
IdString &operator=(const std::string &str) {
|
||||
std::string::operator=(str);
|
||||
check();
|
||||
return *this;
|
||||
}
|
||||
IdString &operator=(const char *s) {
|
||||
std::string::operator=(s);
|
||||
check();
|
||||
return *this;
|
||||
}
|
||||
bool operator<(const IdString &rhs) {
|
||||
check(), rhs.check();
|
||||
return std::string(*this) < std::string(rhs);
|
||||
}
|
||||
void check() const {
|
||||
assert(empty() || (size() >= 2 && (at(0) == '$' || at(0) == '\\')));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static IdString escape_id(std::string str) __attribute__((unused));
|
||||
static IdString escape_id(std::string str) {
|
||||
if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
|
||||
return "\\" + str;
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string unescape_id(std::string str) __attribute__((unused));
|
||||
static std::string unescape_id(std::string str) {
|
||||
if (str.size() > 0 && str[0] == '\\')
|
||||
return str.substr(1);
|
||||
return str;
|
||||
}
|
||||
|
||||
static IdString new_id(std::string file, int line, std::string func) __attribute__((unused));
|
||||
static IdString new_id(std::string file, int line, std::string func) {
|
||||
std::string str = "$auto$";
|
||||
size_t pos = file.find_last_of('/');
|
||||
str += pos != std::string::npos ? file.substr(pos+1) : file;
|
||||
str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
|
||||
return str;
|
||||
}
|
||||
|
||||
#define NEW_ID \
|
||||
RTLIL::new_id(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
// see calc.cc for the implementation of this functions
|
||||
RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
};
|
||||
|
||||
struct RTLIL::Const {
|
||||
std::string str;
|
||||
std::vector<RTLIL::State> bits;
|
||||
Const(std::string str = std::string());
|
||||
Const(int val, int width = 32);
|
||||
Const(RTLIL::State bit, int width = 1);
|
||||
Const(std::vector<RTLIL::State> bits) : bits(bits) { };
|
||||
bool operator <(const RTLIL::Const &other) const;
|
||||
bool operator ==(const RTLIL::Const &other) const;
|
||||
bool operator !=(const RTLIL::Const &other) const;
|
||||
bool as_bool() const;
|
||||
int as_int() const;
|
||||
std::string as_string() const;
|
||||
};
|
||||
|
||||
struct RTLIL::Selection {
|
||||
bool full_selection;
|
||||
std::set<RTLIL::IdString> selected_modules;
|
||||
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
|
||||
Selection(bool full = true) : full_selection(full) { }
|
||||
bool selected_module(RTLIL::IdString mod_name);
|
||||
bool selected_whole_module(RTLIL::IdString mod_name);
|
||||
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
|
||||
void optimize(RTLIL::Design *design);
|
||||
};
|
||||
|
||||
struct RTLIL::Design {
|
||||
std::map<RTLIL::IdString, RTLIL::Module*> modules;
|
||||
std::vector<RTLIL::Selection> selection_stack;
|
||||
std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
|
||||
std::string selected_active_module;
|
||||
~Design();
|
||||
void check();
|
||||
void optimize();
|
||||
bool selected_module(RTLIL::IdString mod_name);
|
||||
bool selected_whole_module(RTLIL::IdString mod_name);
|
||||
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
|
||||
template<typename T1> bool selected(T1 *module) {
|
||||
return selected_module(module->name);
|
||||
}
|
||||
template<typename T1, typename T2> bool selected(T1 *module, T2 *member) {
|
||||
return selected_member(module->name, member->name);
|
||||
}
|
||||
};
|
||||
|
||||
struct RTLIL::Module {
|
||||
RTLIL::IdString name;
|
||||
std::map<RTLIL::IdString, RTLIL::Wire*> wires;
|
||||
std::map<RTLIL::IdString, RTLIL::Memory*> memories;
|
||||
std::map<RTLIL::IdString, RTLIL::Cell*> cells;
|
||||
std::map<RTLIL::IdString, RTLIL::Process*> processes;
|
||||
std::vector<RTLIL::SigSig> connections;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
virtual ~Module();
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
|
||||
virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
|
||||
virtual size_t count_id(RTLIL::IdString id);
|
||||
virtual void check();
|
||||
virtual void optimize();
|
||||
void add(RTLIL::Wire *wire);
|
||||
void add(RTLIL::Cell *cell);
|
||||
};
|
||||
|
||||
struct RTLIL::Wire {
|
||||
RTLIL::IdString name;
|
||||
int width, start_offset, port_id;
|
||||
bool port_input, port_output, auto_width;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
Wire();
|
||||
};
|
||||
|
||||
struct RTLIL::Memory {
|
||||
RTLIL::IdString name;
|
||||
int width, start_offset, size;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
Memory();
|
||||
};
|
||||
|
||||
struct RTLIL::Cell {
|
||||
RTLIL::IdString name;
|
||||
RTLIL::IdString type;
|
||||
std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
void optimize();
|
||||
};
|
||||
|
||||
struct RTLIL::SigChunk {
|
||||
RTLIL::Wire *wire;
|
||||
RTLIL::Const data; // only used if wire == NULL, LSB at index 0
|
||||
int width, offset;
|
||||
SigChunk();
|
||||
SigChunk(const RTLIL::Const &data);
|
||||
SigChunk(RTLIL::Wire *wire, int width, int offset);
|
||||
SigChunk(const std::string &str);
|
||||
SigChunk(int val, int width = 32);
|
||||
SigChunk(RTLIL::State bit, int width = 1);
|
||||
RTLIL::SigChunk extract(int offset, int length) const;
|
||||
bool operator <(const RTLIL::SigChunk &other) const;
|
||||
bool operator ==(const RTLIL::SigChunk &other) const;
|
||||
bool operator !=(const RTLIL::SigChunk &other) const;
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpec {
|
||||
std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
|
||||
int width;
|
||||
SigSpec();
|
||||
SigSpec(const RTLIL::Const &data);
|
||||
SigSpec(const RTLIL::SigChunk &chunk);
|
||||
SigSpec(RTLIL::Wire *wire, int width = -1, int offset = 0);
|
||||
SigSpec(const std::string &str);
|
||||
SigSpec(int val, int width = 32);
|
||||
SigSpec(RTLIL::State bit, int width = 1);
|
||||
void expand();
|
||||
void optimize();
|
||||
void sort_and_unify();
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
|
||||
void remove(const RTLIL::SigSpec &pattern);
|
||||
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
|
||||
RTLIL::SigSpec extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other = NULL) const;
|
||||
void replace(int offset, const RTLIL::SigSpec &with);
|
||||
void remove_const();
|
||||
void remove(int offset, int length);
|
||||
RTLIL::SigSpec extract(int offset, int length) const;
|
||||
void append(const RTLIL::SigSpec &signal);
|
||||
bool combine(RTLIL::SigSpec signal, RTLIL::State freeState = RTLIL::State::Sz, bool override = false);
|
||||
void extend(int width, bool is_signed = false);
|
||||
void check() const;
|
||||
bool operator <(const RTLIL::SigSpec &other) const;
|
||||
bool operator ==(const RTLIL::SigSpec &other) const;
|
||||
bool operator !=(const RTLIL::SigSpec &other) const;
|
||||
bool is_fully_const() const;
|
||||
bool is_fully_def() const;
|
||||
bool is_fully_undef() const;
|
||||
bool has_marked_bits() const;
|
||||
bool as_bool() const;
|
||||
int as_int() const;
|
||||
std::string as_string() const;
|
||||
RTLIL::Const as_const() const;
|
||||
bool match(std::string pattern) const;
|
||||
};
|
||||
|
||||
struct RTLIL::CaseRule {
|
||||
std::vector<RTLIL::SigSpec> compare;
|
||||
std::vector<RTLIL::SigSig> actions;
|
||||
std::vector<RTLIL::SwitchRule*> switches;
|
||||
~CaseRule();
|
||||
void optimize();
|
||||
};
|
||||
|
||||
struct RTLIL::SwitchRule {
|
||||
RTLIL::SigSpec signal;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
std::vector<RTLIL::CaseRule*> cases;
|
||||
~SwitchRule();
|
||||
void optimize();
|
||||
};
|
||||
|
||||
struct RTLIL::SyncRule {
|
||||
RTLIL::SyncType type;
|
||||
RTLIL::SigSpec signal;
|
||||
std::vector<RTLIL::SigSig> actions;
|
||||
void optimize();
|
||||
};
|
||||
|
||||
struct RTLIL::Process {
|
||||
RTLIL::IdString name;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
RTLIL::CaseRule root_case;
|
||||
std::vector<RTLIL::SyncRule*> syncs;
|
||||
~Process();
|
||||
void optimize();
|
||||
};
|
||||
|
||||
#endif
|
476
kernel/select.cc
Normal file
476
kernel/select.cc
Normal file
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
static std::vector<RTLIL::Selection> work_stack;
|
||||
|
||||
static bool match_ids(RTLIL::IdString id, std::string pattern)
|
||||
{
|
||||
if (!fnmatch(pattern.c_str(), id.c_str(), FNM_NOESCAPE))
|
||||
return true;
|
||||
if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), FNM_NOESCAPE))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
|
||||
{
|
||||
if (lhs.full_selection) {
|
||||
lhs.full_selection = false;
|
||||
lhs.selected_modules.clear();
|
||||
lhs.selected_members.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lhs.selected_modules.size() == 0 && lhs.selected_members.size() == 0) {
|
||||
lhs.full_selection = true;
|
||||
return;
|
||||
}
|
||||
|
||||
RTLIL::Selection new_sel(false);
|
||||
|
||||
for (auto &mod_it : design->modules)
|
||||
{
|
||||
if (lhs.selected_whole_module(mod_it.first))
|
||||
continue;
|
||||
if (!lhs.selected_module(mod_it.first)) {
|
||||
new_sel.selected_modules.insert(mod_it.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
RTLIL::Module *mod = mod_it.second;
|
||||
for (auto &it : mod->wires)
|
||||
if (!lhs.selected_member(mod_it.first, it.first))
|
||||
new_sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->memories)
|
||||
if (!lhs.selected_member(mod_it.first, it.first))
|
||||
new_sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->cells)
|
||||
if (!lhs.selected_member(mod_it.first, it.first))
|
||||
new_sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->processes)
|
||||
if (!lhs.selected_member(mod_it.first, it.first))
|
||||
new_sel.selected_members[mod->name].insert(it.first);
|
||||
}
|
||||
|
||||
lhs.selected_modules.swap(new_sel.selected_modules);
|
||||
lhs.selected_members.swap(new_sel.selected_members);
|
||||
}
|
||||
|
||||
static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
|
||||
{
|
||||
if (rhs.full_selection) {
|
||||
lhs.full_selection = true;
|
||||
lhs.selected_modules.clear();
|
||||
lhs.selected_members.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lhs.full_selection)
|
||||
return;
|
||||
|
||||
for (auto &it : rhs.selected_members)
|
||||
for (auto &it2 : it.second)
|
||||
lhs.selected_members[it.first].insert(it2);
|
||||
|
||||
for (auto &it : rhs.selected_modules) {
|
||||
lhs.selected_modules.insert(it);
|
||||
lhs.selected_members.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
|
||||
{
|
||||
if (rhs.full_selection) {
|
||||
lhs.full_selection = false;
|
||||
lhs.selected_modules.clear();
|
||||
lhs.selected_members.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lhs.full_selection) {
|
||||
if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
|
||||
return;
|
||||
lhs.full_selection = false;
|
||||
for (auto &it : design->modules)
|
||||
lhs.selected_modules.insert(it.first);
|
||||
}
|
||||
|
||||
for (auto &it : rhs.selected_modules) {
|
||||
lhs.selected_modules.erase(it);
|
||||
lhs.selected_members.erase(it);
|
||||
}
|
||||
|
||||
for (auto &it : rhs.selected_members)
|
||||
{
|
||||
if (design->modules.count(it.first) == 0)
|
||||
continue;
|
||||
|
||||
RTLIL::Module *mod = design->modules[it.first];
|
||||
|
||||
if (lhs.selected_modules.count(mod->name) > 0)
|
||||
{
|
||||
for (auto &it : mod->wires)
|
||||
lhs.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->memories)
|
||||
lhs.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->cells)
|
||||
lhs.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->processes)
|
||||
lhs.selected_members[mod->name].insert(it.first);
|
||||
lhs.selected_modules.erase(mod->name);
|
||||
}
|
||||
|
||||
if (lhs.selected_members.count(mod->name) == 0)
|
||||
continue;
|
||||
|
||||
for (auto &it2 : it.second)
|
||||
lhs.selected_members[mod->name].erase(it2);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
|
||||
{
|
||||
if (rhs.full_selection)
|
||||
return;
|
||||
|
||||
if (lhs.full_selection) {
|
||||
lhs.full_selection = false;
|
||||
for (auto &it : design->modules)
|
||||
lhs.selected_modules.insert(it.first);
|
||||
}
|
||||
|
||||
std::vector<RTLIL::IdString> del_list;
|
||||
|
||||
for (auto &it : lhs.selected_modules)
|
||||
if (rhs.selected_modules.count(it) == 0) {
|
||||
if (rhs.selected_members.count(it) > 0)
|
||||
for (auto &it2 : rhs.selected_members.at(it))
|
||||
lhs.selected_members[it].insert(it2);
|
||||
del_list.push_back(it);
|
||||
}
|
||||
for (auto &it : del_list)
|
||||
lhs.selected_modules.erase(it);
|
||||
|
||||
del_list.clear();
|
||||
for (auto &it : lhs.selected_members) {
|
||||
if (rhs.selected_modules.count(it.first) > 0)
|
||||
continue;
|
||||
if (rhs.selected_members.count(it.first) == 0) {
|
||||
del_list.push_back(it.first);
|
||||
continue;
|
||||
}
|
||||
std::vector<RTLIL::IdString> del_list2;
|
||||
for (auto &it2 : it.second)
|
||||
if (rhs.selected_members.at(it.first).count(it2) == 0)
|
||||
del_list2.push_back(it2);
|
||||
for (auto &it2 : del_list2)
|
||||
it.second.erase(it2);
|
||||
if (it.second.size() == 0)
|
||||
del_list.push_back(it.first);
|
||||
}
|
||||
for (auto &it : del_list)
|
||||
lhs.selected_members.erase(it);
|
||||
}
|
||||
|
||||
static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
|
||||
{
|
||||
if (design->selected_active_module.empty())
|
||||
return;
|
||||
|
||||
if (sel.full_selection) {
|
||||
sel.full_selection = false;
|
||||
sel.selected_modules.clear();
|
||||
sel.selected_members.clear();
|
||||
sel.selected_modules.insert(design->selected_active_module);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> del_list;
|
||||
for (auto mod_name : sel.selected_modules)
|
||||
if (mod_name != design->selected_active_module)
|
||||
del_list.push_back(mod_name);
|
||||
for (auto &it : sel.selected_members)
|
||||
if (it.first != design->selected_active_module)
|
||||
del_list.push_back(it.first);
|
||||
for (auto mod_name : del_list) {
|
||||
sel.selected_modules.erase(mod_name);
|
||||
sel.selected_members.erase(mod_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_stmt(RTLIL::Design *design, std::string arg)
|
||||
{
|
||||
std::string arg_mod, arg_memb;
|
||||
|
||||
if (arg.size() == 0)
|
||||
return;
|
||||
|
||||
if (arg[0] == '#') {
|
||||
if (arg == "#") {
|
||||
if (design->selection_stack.size() > 0)
|
||||
work_stack.push_back(design->selection_stack.back());
|
||||
} else
|
||||
if (arg == "#n") {
|
||||
if (work_stack.size() < 1)
|
||||
log_cmd_error("Must have at least one element on stack for operator #n.\n");
|
||||
select_op_neg(design, work_stack[work_stack.size()-1]);
|
||||
} else
|
||||
if (arg == "#u") {
|
||||
if (work_stack.size() < 2)
|
||||
log_cmd_error("Must have at least two elements on stack for operator #u.\n");
|
||||
select_op_union(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
|
||||
work_stack.pop_back();
|
||||
} else
|
||||
if (arg == "#d") {
|
||||
if (work_stack.size() < 2)
|
||||
log_cmd_error("Must have at least two elements on stack for operator #d.\n");
|
||||
select_op_diff(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
|
||||
work_stack.pop_back();
|
||||
} else
|
||||
if (arg == "#i") {
|
||||
if (work_stack.size() < 2)
|
||||
log_cmd_error("Must have at least two elements on stack for operator #i.\n");
|
||||
select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
|
||||
work_stack.pop_back();
|
||||
} else
|
||||
log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
|
||||
select_filter_active_mod(design, work_stack.back());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!design->selected_active_module.empty()) {
|
||||
arg_mod = design->selected_active_module;
|
||||
arg_memb = arg;
|
||||
} else {
|
||||
size_t pos = arg.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
arg_mod = arg;
|
||||
} else {
|
||||
arg_mod = arg.substr(0, pos);
|
||||
arg_memb = arg.substr(pos+1);
|
||||
}
|
||||
}
|
||||
|
||||
work_stack.push_back(RTLIL::Selection());
|
||||
RTLIL::Selection &sel = work_stack.back();
|
||||
|
||||
if (arg == "*" && arg_mod == "*") {
|
||||
select_filter_active_mod(design, work_stack.back());
|
||||
return;
|
||||
}
|
||||
|
||||
sel.full_selection = false;
|
||||
for (auto &mod_it : design->modules)
|
||||
{
|
||||
if (!match_ids(mod_it.first, arg_mod))
|
||||
continue;
|
||||
|
||||
if (arg_memb == "") {
|
||||
sel.selected_modules.insert(mod_it.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
RTLIL::Module *mod = mod_it.second;
|
||||
if (arg_memb.substr(0, 2) == "w:") {
|
||||
for (auto &it : mod->wires)
|
||||
if (match_ids(it.first, arg_memb.substr(2)))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
} else
|
||||
if (arg_memb.substr(0, 2) == "m:") {
|
||||
for (auto &it : mod->memories)
|
||||
if (match_ids(it.first, arg_memb.substr(2)))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
} else
|
||||
if (arg_memb.substr(0, 2) == "c:") {
|
||||
for (auto &it : mod->cells)
|
||||
if (match_ids(it.first, arg_memb.substr(2)))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
} else
|
||||
if (arg_memb.substr(0, 2) == "t:") {
|
||||
for (auto &it : mod->cells)
|
||||
if (match_ids(it.second->type, arg_memb.substr(2)))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
} else
|
||||
if (arg_memb.substr(0, 2) == "p:") {
|
||||
for (auto &it : mod->processes)
|
||||
if (match_ids(it.first, arg_memb.substr(2)))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
} else {
|
||||
if (arg_memb.substr(0, 2) == "n:")
|
||||
arg_memb = arg_memb.substr(2);
|
||||
for (auto &it : mod->wires)
|
||||
if (match_ids(it.first, arg_memb))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->memories)
|
||||
if (match_ids(it.first, arg_memb))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->cells)
|
||||
if (match_ids(it.first, arg_memb))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
for (auto &it : mod->processes)
|
||||
if (match_ids(it.first, arg_memb))
|
||||
sel.selected_members[mod->name].insert(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
select_filter_active_mod(design, work_stack.back());
|
||||
}
|
||||
|
||||
struct SelectPass : public Pass {
|
||||
SelectPass() : Pass("select") { }
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
bool add_mode = false;
|
||||
bool del_mode = false;
|
||||
bool clear_mode = false;
|
||||
bool list_mode = false;
|
||||
bool got_module = false;
|
||||
|
||||
work_stack.clear();
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-add") {
|
||||
add_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-del") {
|
||||
del_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-clear") {
|
||||
clear_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-list") {
|
||||
list_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-module" && argidx+1 < args.size()) {
|
||||
RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
|
||||
if (design->modules.count(mod_name) == 0)
|
||||
log_cmd_error("No such module: %s\n", mod_name.c_str());
|
||||
design->selected_active_module = mod_name;
|
||||
got_module = true;
|
||||
continue;
|
||||
}
|
||||
if (arg.size() > 0 && arg[0] == '-')
|
||||
log_cmd_error("Unkown option %s.\n", arg.c_str());
|
||||
select_stmt(design, arg);
|
||||
}
|
||||
|
||||
if (clear_mode && args.size() != 2)
|
||||
log_cmd_error("Option -clear can not be combined with other options.\n");
|
||||
|
||||
if (add_mode && del_mode)
|
||||
log_cmd_error("Options -add and -del can not be combined.\n");
|
||||
|
||||
if (list_mode && (add_mode || del_mode))
|
||||
log_cmd_error("Option -list can not be combined with -add or -del.\n");
|
||||
|
||||
if (work_stack.size() == 0 && got_module) {
|
||||
RTLIL::Selection sel;
|
||||
select_filter_active_mod(design, sel);
|
||||
work_stack.push_back(sel);
|
||||
}
|
||||
|
||||
while (work_stack.size() > 1) {
|
||||
select_op_union(design, work_stack.front(), work_stack.back());
|
||||
work_stack.pop_back();
|
||||
}
|
||||
|
||||
assert(design->selection_stack.size() > 0);
|
||||
|
||||
if (clear_mode)
|
||||
{
|
||||
design->selection_stack.back() = RTLIL::Selection(true);
|
||||
design->selected_active_module = std::string();
|
||||
return;
|
||||
}
|
||||
|
||||
if (list_mode)
|
||||
{
|
||||
RTLIL::Selection *sel = &design->selection_stack.back();
|
||||
if (work_stack.size() > 0)
|
||||
sel = &work_stack.back();
|
||||
sel->optimize(design);
|
||||
for (auto mod_it : design->modules)
|
||||
{
|
||||
if (design->selected_whole_module(mod_it.first))
|
||||
log("%s\n", mod_it.first.c_str());
|
||||
if (design->selected_module(mod_it.first)) {
|
||||
for (auto &it : mod_it.second->wires)
|
||||
if (design->selected_member(mod_it.first, it.first))
|
||||
log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
|
||||
for (auto &it : mod_it.second->memories)
|
||||
if (design->selected_member(mod_it.first, it.first))
|
||||
log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
|
||||
for (auto &it : mod_it.second->cells)
|
||||
if (design->selected_member(mod_it.first, it.first))
|
||||
log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
|
||||
for (auto &it : mod_it.second->processes)
|
||||
if (design->selected_member(mod_it.first, it.first))
|
||||
log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (add_mode)
|
||||
{
|
||||
if (work_stack.size() == 0)
|
||||
log_cmd_error("Nothing to add to selection.\n");
|
||||
select_op_union(design, design->selection_stack.back(), work_stack.back());
|
||||
design->selection_stack.back().optimize(design);
|
||||
return;
|
||||
}
|
||||
|
||||
if (del_mode)
|
||||
{
|
||||
if (work_stack.size() == 0)
|
||||
log_cmd_error("Nothing to delete from selection.\n");
|
||||
select_op_diff(design, design->selection_stack.back(), work_stack.back());
|
||||
design->selection_stack.back().optimize(design);
|
||||
return;
|
||||
}
|
||||
|
||||
if (work_stack.size() == 0) {
|
||||
RTLIL::Selection &sel = design->selection_stack.back();
|
||||
if (sel.full_selection)
|
||||
log("*\n");
|
||||
for (auto &it : sel.selected_modules)
|
||||
log("%s\n", it.c_str());
|
||||
for (auto &it : sel.selected_members)
|
||||
for (auto &it2 : it.second)
|
||||
log("%s/%s\n", it.first.c_str(), it2.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
design->selection_stack.back() = work_stack.back();
|
||||
design->selection_stack.back().optimize(design);
|
||||
}
|
||||
} SelectPass;
|
||||
|
185
kernel/sha1.cpp
Normal file
185
kernel/sha1.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributors:
|
||||
Gustav
|
||||
Several members in the gamedev.se forum.
|
||||
Gregory Petrosyan
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash)
|
||||
{
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = (const unsigned char*) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void toHexString(const unsigned char* hash, char* hexstring)
|
||||
{
|
||||
const char hexDigits[] = { "0123456789abcdef" };
|
||||
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
|
||||
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
|
||||
}
|
||||
hexstring[40] = 0;
|
||||
}
|
||||
} // namespace sha1
|
49
kernel/sha1.h
Normal file
49
kernel/sha1.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
|
||||
/**
|
||||
@param src points to any kind of data to be hashed.
|
||||
@param bytelength the number of bytes to hash from the src pointer.
|
||||
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
|
||||
*/
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash);
|
||||
|
||||
/**
|
||||
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
|
||||
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
|
||||
*/
|
||||
void toHexString(const unsigned char* hash, char* hexstring);
|
||||
|
||||
} // namespace sha1
|
||||
|
||||
#endif // SHA1_DEFINED
|
343
kernel/show.cc
Normal file
343
kernel/show.cc
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#undef CLUSTER_CELLS_AND_PORTBOXES
|
||||
|
||||
struct ShowWorker
|
||||
{
|
||||
CellTypes ct;
|
||||
|
||||
std::vector<std::string> dot_escape_store;
|
||||
std::map<RTLIL::IdString, int> dot_id2num_store;
|
||||
std::map<RTLIL::IdString, int> autonames;
|
||||
int single_idx_count;
|
||||
|
||||
struct net_conn { std::set<std::string> in, out; };
|
||||
std::map<std::string, net_conn> net_conn_map;
|
||||
|
||||
FILE *f;
|
||||
RTLIL::Design *design;
|
||||
RTLIL::Module *module;
|
||||
int page_counter;
|
||||
|
||||
const char *escape(std::string id, bool is_name = false)
|
||||
{
|
||||
if (id.size() == 0)
|
||||
return "";
|
||||
|
||||
if (id[0] == '$' && is_name) {
|
||||
if (autonames.count(id) == 0) {
|
||||
autonames[id] = autonames.size() + 1;
|
||||
log("Generated short name for internal identifier: _%d_ -> %s\n", autonames[id], id.c_str());
|
||||
}
|
||||
id = stringf("_%d_", autonames[id]);
|
||||
}
|
||||
|
||||
if (id[0] == '\\')
|
||||
id = id.substr(1);
|
||||
|
||||
std::string str;
|
||||
for (char ch : id) {
|
||||
if (ch == '\\' || ch == '"')
|
||||
str += "\\";
|
||||
str += ch;
|
||||
}
|
||||
|
||||
dot_escape_store.push_back(str);
|
||||
return dot_escape_store.back().c_str();
|
||||
}
|
||||
|
||||
int id2num(RTLIL::IdString id)
|
||||
{
|
||||
if (dot_id2num_store.count(id) > 0)
|
||||
return dot_id2num_store[id];
|
||||
return dot_id2num_store[id] = dot_id2num_store.size() + 1;
|
||||
}
|
||||
|
||||
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
|
||||
{
|
||||
sig.optimize();
|
||||
|
||||
if (sig.chunks.size() == 0) {
|
||||
fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
|
||||
return stringf("v%d", single_idx_count++);
|
||||
}
|
||||
|
||||
if (sig.chunks.size() == 1) {
|
||||
RTLIL::SigChunk &c = sig.chunks[0];
|
||||
if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
|
||||
if (!range_check || c.wire->width == c.width)
|
||||
return stringf("n%d", id2num(c.wire->name));
|
||||
} else {
|
||||
fprintf(f, "v%d [ label=\"%s\" ];\n", single_idx_count, escape(log_signal(c), true));
|
||||
return stringf("v%d", single_idx_count++);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node = NULL)
|
||||
{
|
||||
std::string code;
|
||||
std::string net = gen_signode_simple(sig);
|
||||
if (net.empty())
|
||||
{
|
||||
std::string label_string;
|
||||
sig.optimize();
|
||||
int pos = sig.width-1;
|
||||
int idx = single_idx_count++;
|
||||
for (int i = int(sig.chunks.size())-1; i >= 0; i--) {
|
||||
RTLIL::SigChunk &c = sig.chunks[i];
|
||||
net = gen_signode_simple(c, false);
|
||||
assert(!net.empty());
|
||||
if (driver) {
|
||||
label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
|
||||
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
|
||||
} else {
|
||||
label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
|
||||
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
|
||||
}
|
||||
pos -= c.width;
|
||||
}
|
||||
if (label_string[label_string.size()-1] == '|')
|
||||
label_string = label_string.substr(0, label_string.size()-1);
|
||||
code += stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx, label_string.c_str());
|
||||
if (!port.empty()) {
|
||||
if (driver)
|
||||
code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", port.c_str(), idx);
|
||||
else
|
||||
code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", idx, port.c_str());
|
||||
}
|
||||
if (node != NULL)
|
||||
*node = stringf("x%d", idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!port.empty()) {
|
||||
if (driver)
|
||||
net_conn_map[net].in.insert(port);
|
||||
else
|
||||
net_conn_map[net].out.insert(port);
|
||||
}
|
||||
if (node != NULL)
|
||||
*node = net;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
void handle_module()
|
||||
{
|
||||
single_idx_count = 0;
|
||||
dot_escape_store.clear();
|
||||
dot_id2num_store.clear();
|
||||
net_conn_map.clear();
|
||||
|
||||
fprintf(f, "digraph \"%s\" {\n", escape(module->name));
|
||||
fprintf(f, "rankdir=\"LR\";\n");
|
||||
fprintf(f, "remincross=true;\n");
|
||||
|
||||
std::map<std::string, std::string> wires_on_demand;
|
||||
for (auto &it : module->wires) {
|
||||
if (!design->selected_member(module->name, it.first))
|
||||
continue;
|
||||
const char *shape = "diamond";
|
||||
if (it.second->port_input || it.second->port_output)
|
||||
shape = "octagon";
|
||||
if (it.first[0] == '\\')
|
||||
fprintf(f, "n%d [ shape=%s, label=\"%s\" ];\n",
|
||||
id2num(it.first), shape, escape(it.first));
|
||||
else {
|
||||
wires_on_demand[stringf("n%d", id2num(it.first))] = it.first;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : module->cells)
|
||||
{
|
||||
if (!design->selected_member(module->name, it.first))
|
||||
continue;
|
||||
|
||||
std::vector<RTLIL::IdString> in_ports, out_ports;
|
||||
|
||||
for (auto &conn : it.second->connections) {
|
||||
if (ct.cell_input(it.second->type, conn.first))
|
||||
in_ports.push_back(conn.first);
|
||||
else
|
||||
out_ports.push_back(conn.first);
|
||||
}
|
||||
|
||||
std::string label_string = "{{";
|
||||
|
||||
for (auto &p : in_ports)
|
||||
label_string += stringf("<p%d> %s|", id2num(p), escape(p));
|
||||
if (label_string[label_string.size()-1] == '|')
|
||||
label_string = label_string.substr(0, label_string.size()-1);
|
||||
|
||||
label_string += stringf("}|%s\\n%s|{", escape(it.first, true), escape(it.second->type));
|
||||
|
||||
for (auto &p : out_ports)
|
||||
label_string += stringf("<p%d> %s|", id2num(p), escape(p));
|
||||
if (label_string[label_string.size()-1] == '|')
|
||||
label_string = label_string.substr(0, label_string.size()-1);
|
||||
|
||||
label_string += "}}";
|
||||
|
||||
std::string code;
|
||||
for (auto &conn : it.second->connections) {
|
||||
code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
|
||||
conn.second, !ct.cell_input(it.second->type, conn.first));
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_CELLS_AND_PORTBOXES
|
||||
if (!code.empty())
|
||||
fprintf(f, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\" ];\n%s}\n",
|
||||
id2num(it.first), id2num(it.first), label_string.c_str(), code.c_str());
|
||||
else
|
||||
#endif
|
||||
fprintf(f, "c%d [ shape=record, label=\"%s\" ];\n%s",
|
||||
id2num(it.first), label_string.c_str(), code.c_str());
|
||||
}
|
||||
|
||||
for (auto &conn : module->connections)
|
||||
{
|
||||
bool found_lhs_wire = false;
|
||||
for (auto &c : conn.first.chunks) {
|
||||
if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
|
||||
found_lhs_wire = true;
|
||||
}
|
||||
bool found_rhs_wire = false;
|
||||
for (auto &c : conn.second.chunks) {
|
||||
if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
|
||||
found_rhs_wire = true;
|
||||
}
|
||||
if (!found_lhs_wire || !found_rhs_wire)
|
||||
continue;
|
||||
|
||||
std::string code, left_node, right_node;
|
||||
code += gen_portbox("", conn.second, false, &left_node);
|
||||
code += gen_portbox("", conn.first, true, &right_node);
|
||||
fprintf(f, "%s", code.c_str());
|
||||
|
||||
if (left_node[0] == 'x' && right_node[0] == 'x')
|
||||
fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", left_node.c_str(), right_node.c_str());
|
||||
else if (left_node[0] == 'x')
|
||||
net_conn_map[right_node].in.insert(left_node);
|
||||
else if (right_node[0] == 'x')
|
||||
net_conn_map[left_node].out.insert(right_node);
|
||||
else {
|
||||
net_conn_map[right_node].in.insert(stringf("x%d:e", single_idx_count));
|
||||
net_conn_map[left_node].out.insert(stringf("x%d:w", single_idx_count));
|
||||
fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count++);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : net_conn_map)
|
||||
{
|
||||
if (wires_on_demand.count(it.first) > 0) {
|
||||
if (it.second.in.size() == 1 && it.second.out.size() == 1) {
|
||||
fprintf(f, "%s:e -> %s:w;\n", it.second.in.begin()->c_str(), it.second.out.begin()->c_str());
|
||||
continue;
|
||||
}
|
||||
if (it.second.in.size() == 0 || it.second.out.size() == 0)
|
||||
fprintf(f, "%s [ shape=diamond, label=\"%s\" ];\n", it.first.c_str(), escape(wires_on_demand[it.first], true));
|
||||
else
|
||||
fprintf(f, "%s [ shape=point ];\n", it.first.c_str());
|
||||
}
|
||||
for (auto &it2 : it.second.in)
|
||||
fprintf(f, "%s:e -> %s:w;\n", it2.c_str(), it.first.c_str());
|
||||
for (auto &it2 : it.second.out)
|
||||
fprintf(f, "%s:e -> %s:w;\n", it.first.c_str(), it2.c_str());
|
||||
}
|
||||
|
||||
fprintf(f, "};\n");
|
||||
}
|
||||
|
||||
ShowWorker(FILE *f, RTLIL::Design *design) : f(f), design(design)
|
||||
{
|
||||
ct.setup_internals();
|
||||
ct.setup_internals_mem();
|
||||
ct.setup_stdcells();
|
||||
ct.setup_stdcells_mem();
|
||||
|
||||
design->optimize();
|
||||
page_counter = 0;
|
||||
for (auto &mod_it : design->modules)
|
||||
{
|
||||
module = mod_it.second;
|
||||
if (!design->selected_module(module->name))
|
||||
continue;
|
||||
if (design->selected_whole_module(module->name))
|
||||
log("Dumping module %s to page %d.\n", module->name.c_str(), ++page_counter);
|
||||
else
|
||||
log("Dumping selected parts of module %s to page %d.\n", module->name.c_str(), ++page_counter);
|
||||
handle_module();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ShowPass : public Pass {
|
||||
ShowPass() : Pass("show") { }
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
log_header("Generating Graphviz representation of design.\n");
|
||||
|
||||
std::string viewer_exe;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-viewer" && argidx+1 < args.size()) {
|
||||
viewer_exe = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
log("Writing dot description to `yosys-show.dot'.\n");
|
||||
FILE *f = fopen("yosys-show.dot", "w");
|
||||
if (f == NULL)
|
||||
log_cmd_error("Can't open dot file `yosys-show.dot' for writing.\n");
|
||||
ShowWorker worker(f, design);
|
||||
fclose(f);
|
||||
|
||||
if (worker.page_counter == 0)
|
||||
log_cmd_error("Nothing there to show.\n");
|
||||
|
||||
std::string cmd = stringf("dot -Tps -o yosys-show.ps yosys-show.dot");
|
||||
log("Exec: %s\n", cmd.c_str());
|
||||
if (system(cmd.c_str()) != 0)
|
||||
log_cmd_error("Shell command failed!\n");
|
||||
|
||||
if (!viewer_exe.empty()) {
|
||||
cmd = stringf("%s yosys-show.ps &", viewer_exe.c_str());
|
||||
log("Exec: %s\n", cmd.c_str());
|
||||
if (system(cmd.c_str()) != 0)
|
||||
log_cmd_error("Shell command failed!\n");
|
||||
}
|
||||
}
|
||||
} ShowPass;
|
||||
|
415
kernel/sigtools.h
Normal file
415
kernel/sigtools.h
Normal file
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SIGTOOLS_H
|
||||
#define SIGTOOLS_H
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/log.h"
|
||||
#include <assert.h>
|
||||
#include <set>
|
||||
|
||||
struct SigPool
|
||||
{
|
||||
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
|
||||
std::set<bitDef_t> bits;
|
||||
|
||||
void clear()
|
||||
{
|
||||
bits.clear();
|
||||
}
|
||||
|
||||
void add(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
bits.insert(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void add(const SigPool &other)
|
||||
{
|
||||
for (auto &bit : other.bits)
|
||||
bits.insert(bit);
|
||||
}
|
||||
|
||||
void del(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
bits.erase(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void del(const SigPool &other)
|
||||
{
|
||||
for (auto &bit : other.bits)
|
||||
bits.insert(bit);
|
||||
}
|
||||
|
||||
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
|
||||
{
|
||||
from.expand();
|
||||
to.expand();
|
||||
assert(from.chunks.size() == to.chunks.size());
|
||||
for (size_t i = 0; i < from.chunks.size(); i++) {
|
||||
bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset);
|
||||
bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset);
|
||||
if (bit_from.first == NULL || bit_to.first == NULL)
|
||||
continue;
|
||||
if (bits.count(bit_from) > 0)
|
||||
bits.insert(bit_to);
|
||||
}
|
||||
}
|
||||
|
||||
RTLIL::SigSpec extract(RTLIL::SigSpec sig)
|
||||
{
|
||||
RTLIL::SigSpec result;
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (bits.count(bit) > 0)
|
||||
result.append(c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec remove(RTLIL::SigSpec sig)
|
||||
{
|
||||
RTLIL::SigSpec result;
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (bits.count(bit) == 0)
|
||||
result.append(c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool check_any(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (bits.count(bit) != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_all(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (bits.count(bit) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct SigSet
|
||||
{
|
||||
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
|
||||
std::map<bitDef_t, std::set<T>> bits;
|
||||
|
||||
void clear()
|
||||
{
|
||||
bits.clear();
|
||||
}
|
||||
|
||||
void insert(RTLIL::SigSpec sig, T data)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
bits[bit].insert(data);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
bits[bit].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void erase(RTLIL::SigSpec sig, T data)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
bits[bit].erase(data);
|
||||
}
|
||||
}
|
||||
|
||||
void find(RTLIL::SigSpec sig, std::set<T> &result)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks) {
|
||||
if (c.wire == NULL)
|
||||
continue;
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
for (auto &data : bits[bit])
|
||||
result.insert(data);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<T> find(RTLIL::SigSpec sig)
|
||||
{
|
||||
std::set<T> result;
|
||||
find(sig, result);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct SigMap
|
||||
{
|
||||
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
|
||||
|
||||
struct shared_bit_data_t {
|
||||
RTLIL::SigChunk chunk;
|
||||
std::set<bitDef_t> bits;
|
||||
};
|
||||
|
||||
std::map<bitDef_t, shared_bit_data_t*> bits;
|
||||
|
||||
SigMap(RTLIL::Module *module = NULL)
|
||||
{
|
||||
if (module != NULL)
|
||||
set(module);
|
||||
}
|
||||
|
||||
SigMap(const SigMap &other)
|
||||
{
|
||||
copy(other);
|
||||
}
|
||||
|
||||
const SigMap &operator=(const SigMap &other)
|
||||
{
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void copy(const SigMap &other)
|
||||
{
|
||||
clear();
|
||||
for (auto &bit : other.bits) {
|
||||
bits[bit.first] = new shared_bit_data_t;
|
||||
bits[bit.first]->chunk = bit.second->chunk;
|
||||
bits[bit.first]->bits = bit.second->bits;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(SigMap &other)
|
||||
{
|
||||
bits.swap(other.bits);
|
||||
}
|
||||
|
||||
~SigMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::set<shared_bit_data_t*> all_bd_ptr;
|
||||
for (auto &it : bits)
|
||||
all_bd_ptr.insert(it.second);
|
||||
for (auto bd_ptr : all_bd_ptr)
|
||||
delete bd_ptr;
|
||||
bits.clear();
|
||||
}
|
||||
|
||||
void set(RTLIL::Module *module)
|
||||
{
|
||||
clear();
|
||||
for (auto &it : module->connections)
|
||||
add(it.first, it.second);
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
void register_bit(const RTLIL::SigChunk &c)
|
||||
{
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (c.wire && bits.count(bit) == 0) {
|
||||
shared_bit_data_t *bd = new shared_bit_data_t;
|
||||
bd->chunk = c;
|
||||
bd->bits.insert(bit);
|
||||
bits[bit] = bd;
|
||||
}
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
void unregister_bit(const RTLIL::SigChunk &c)
|
||||
{
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (c.wire && bits.count(bit) > 0) {
|
||||
shared_bit_data_t *bd = bits[bit];
|
||||
bd->bits.erase(bit);
|
||||
if (bd->bits.size() == 0)
|
||||
delete bd;
|
||||
bits.erase(bit);
|
||||
}
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
|
||||
{
|
||||
assert(c1.wire != NULL && c2.wire != NULL);
|
||||
assert(c1.width == 1 && c2.width == 1);
|
||||
|
||||
bitDef_t b1(c1.wire, c1.offset);
|
||||
bitDef_t b2(c2.wire, c2.offset);
|
||||
|
||||
shared_bit_data_t *bd1 = bits[b1];
|
||||
shared_bit_data_t *bd2 = bits[b2];
|
||||
assert(bd1 != NULL && bd2 != NULL);
|
||||
|
||||
if (bd1 == bd2)
|
||||
return;
|
||||
|
||||
if (bd1->bits.size() < bd2->bits.size())
|
||||
{
|
||||
for (auto &bit : bd1->bits)
|
||||
bits[bit] = bd2;
|
||||
bd2->bits.insert(bd1->bits.begin(), bd1->bits.end());
|
||||
delete bd1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bd1->chunk = bd2->chunk;
|
||||
for (auto &bit : bd2->bits)
|
||||
bits[bit] = bd1;
|
||||
bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
|
||||
delete bd2;
|
||||
}
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
|
||||
{
|
||||
assert(c1.wire != NULL);
|
||||
assert(c1.width == 1 && c2.width == 1);
|
||||
bitDef_t bit(c1.wire, c1.offset);
|
||||
assert(bits.count(bit) > 0);
|
||||
bits[bit]->chunk = c2;
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
void map_bit(RTLIL::SigChunk &c)
|
||||
{
|
||||
assert(c.width == 1);
|
||||
bitDef_t bit(c.wire, c.offset);
|
||||
if (c.wire && bits.count(bit) > 0)
|
||||
c = bits[bit]->chunk;
|
||||
}
|
||||
|
||||
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
|
||||
{
|
||||
from.expand();
|
||||
to.expand();
|
||||
|
||||
assert(from.chunks.size() == to.chunks.size());
|
||||
for (size_t i = 0; i < from.chunks.size(); i++)
|
||||
{
|
||||
RTLIL::SigChunk &cf = from.chunks[i];
|
||||
RTLIL::SigChunk &ct = to.chunks[i];
|
||||
|
||||
if (cf.wire == NULL)
|
||||
continue;
|
||||
|
||||
register_bit(cf);
|
||||
register_bit(ct);
|
||||
|
||||
if (ct.wire != NULL)
|
||||
merge_bit(cf, ct);
|
||||
else
|
||||
set_bit(cf, ct);
|
||||
}
|
||||
}
|
||||
|
||||
void add(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (size_t i = 0; i < sig.chunks.size(); i++)
|
||||
{
|
||||
RTLIL::SigChunk &c = sig.chunks[i];
|
||||
if (c.wire != NULL) {
|
||||
register_bit(c);
|
||||
set_bit(c, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void del(RTLIL::SigSpec sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks)
|
||||
unregister_bit(c);
|
||||
}
|
||||
|
||||
void apply(RTLIL::SigSpec &sig)
|
||||
{
|
||||
sig.expand();
|
||||
for (auto &c : sig.chunks)
|
||||
map_bit(c);
|
||||
sig.optimize();
|
||||
}
|
||||
|
||||
RTLIL::SigSpec operator()(RTLIL::SigSpec sig)
|
||||
{
|
||||
apply(sig);
|
||||
return sig;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SIGTOOLS_H */
|
Loading…
Add table
Add a link
Reference in a new issue