mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-19 21:55:48 +00:00
Bump to latest
This commit is contained in:
commit
60d969530b
171 changed files with 2574 additions and 1077 deletions
|
|
@ -100,7 +100,7 @@ struct BitPatternPool
|
|||
bits_t sig2bits(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits;
|
||||
bits.bitdata = sig.as_const().bits();
|
||||
bits.bitdata = sig.as_const().to_bits();
|
||||
for (auto &b : bits.bitdata)
|
||||
if (b > RTLIL::State::S1)
|
||||
b = RTLIL::State::Sa;
|
||||
|
|
|
|||
|
|
@ -33,10 +33,7 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
|
|||
if (arg.size() > 0 && is_signed)
|
||||
padding = arg.back();
|
||||
|
||||
while (GetSize(arg) < width)
|
||||
arg.bits().push_back(padding);
|
||||
|
||||
arg.bits().resize(width);
|
||||
arg.resize(width, padding);
|
||||
}
|
||||
|
||||
static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
|
||||
|
|
@ -79,12 +76,12 @@ static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_b
|
|||
{
|
||||
mag--;
|
||||
for (auto i = 0; i < result_len; i++)
|
||||
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
result.set(i, mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = 0; i < result_len; i++)
|
||||
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
result.set(i, mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,11 +137,11 @@ RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, boo
|
|||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||
for (auto i = 0; i < result_len; i++) {
|
||||
if (i >= GetSize(arg1_ext))
|
||||
result.bits()[i] = RTLIL::State::S0;
|
||||
else if (arg1_ext.bits()[i] == RTLIL::State::S0)
|
||||
result.bits()[i] = RTLIL::State::S1;
|
||||
else if (arg1_ext.bits()[i] == RTLIL::State::S1)
|
||||
result.bits()[i] = RTLIL::State::S0;
|
||||
result.set(i, RTLIL::State::S0);
|
||||
else if (arg1_ext[i] == RTLIL::State::S0)
|
||||
result.set(i, RTLIL::State::S1);
|
||||
else if (arg1_ext[i] == RTLIL::State::S1)
|
||||
result.set(i, RTLIL::State::S0);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -161,9 +158,9 @@ static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL:
|
|||
|
||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||
for (auto i = 0; i < result_len; i++) {
|
||||
RTLIL::State a = i < GetSize(arg1) ? arg1.bits()[i] : RTLIL::State::S0;
|
||||
RTLIL::State b = i < GetSize(arg2) ? arg2.bits()[i] : RTLIL::State::S0;
|
||||
result.bits()[i] = logic_func(a, b);
|
||||
RTLIL::State a = i < GetSize(arg1) ? arg1[i] : RTLIL::State::S0;
|
||||
RTLIL::State b = i < GetSize(arg2) ? arg2[i] : RTLIL::State::S0;
|
||||
result.set(i, logic_func(a, b));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -197,8 +194,8 @@ static RTLIL::Const logic_reduce_wrapper(RTLIL::State initial, RTLIL::State(*log
|
|||
temp = logic_func(temp, arg1[i]);
|
||||
|
||||
RTLIL::Const result(temp);
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -222,9 +219,9 @@ RTLIL::Const RTLIL::const_reduce_xnor(const RTLIL::Const &arg1, const RTLIL::Con
|
|||
RTLIL::Const buffer = logic_reduce_wrapper(RTLIL::State::S0, logic_xor, arg1, result_len);
|
||||
if (!buffer.empty()) {
|
||||
if (buffer.front() == RTLIL::State::S0)
|
||||
buffer.bits().front() = RTLIL::State::S1;
|
||||
buffer.set(0, RTLIL::State::S1);
|
||||
else if (buffer.front() == RTLIL::State::S1)
|
||||
buffer.bits().front() = RTLIL::State::S0;
|
||||
buffer.set(0, RTLIL::State::S0);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
|
@ -239,9 +236,8 @@ RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const
|
|||
int undef_bit_pos_a = -1;
|
||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
||||
RTLIL::Const result(a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S1 : RTLIL::State::S0);
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -254,9 +250,8 @@ RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const
|
|||
RTLIL::State bit_a = a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||
RTLIL::Const result(logic_and(bit_a, bit_b));
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -269,9 +264,8 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
|
|||
RTLIL::State bit_a = a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||
RTLIL::Const result(logic_or(bit_a, bit_b));
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -295,11 +289,11 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
|
|||
for (int i = 0; i < result_len; i++) {
|
||||
BigInteger pos = BigInteger(i) + offset;
|
||||
if (pos < 0)
|
||||
result.bits()[i] = vacant_bits;
|
||||
result.set(i, vacant_bits);
|
||||
else if (pos >= BigInteger(GetSize(arg1)))
|
||||
result.bits()[i] = sign_ext ? arg1.back() : vacant_bits;
|
||||
result.set(i, sign_ext ? arg1.back() : vacant_bits);
|
||||
else
|
||||
result.bits()[i] = arg1[pos.toInt()];
|
||||
result.set(i, arg1[pos.toInt()]);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -346,9 +340,8 @@ RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
|
||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -357,9 +350,8 @@ RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
|
||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +375,7 @@ RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
matched_status = RTLIL::State::Sx;
|
||||
}
|
||||
|
||||
result.bits().front() = matched_status;
|
||||
result.set(0, matched_status);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -391,9 +383,9 @@ RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
{
|
||||
RTLIL::Const result = RTLIL::const_eq(arg1, arg2, signed1, signed2, result_len);
|
||||
if (result.front() == RTLIL::State::S0)
|
||||
result.bits().front() = RTLIL::State::S1;
|
||||
result.set(0, RTLIL::State::S1);
|
||||
else if (result.front() == RTLIL::State::S1)
|
||||
result.bits().front() = RTLIL::State::S0;
|
||||
result.set(0, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +404,7 @@ RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
|||
return result;
|
||||
}
|
||||
|
||||
result.bits().front() = RTLIL::State::S1;
|
||||
result.set(0, RTLIL::State::S1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -420,9 +412,9 @@ RTLIL::Const RTLIL::const_nex(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
|||
{
|
||||
RTLIL::Const result = RTLIL::const_eqx(arg1, arg2, signed1, signed2, result_len);
|
||||
if (result.front() == RTLIL::State::S0)
|
||||
result.bits().front() = RTLIL::State::S1;
|
||||
result.set(0, RTLIL::State::S1);
|
||||
else if (result.front() == RTLIL::State::S1)
|
||||
result.bits().front() = RTLIL::State::S0;
|
||||
result.set(0, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -431,9 +423,8 @@ RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
|
||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -442,9 +433,8 @@ RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
|||
int undef_bit_pos = -1;
|
||||
bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
|
||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||
|
||||
while (GetSize(result) < result_len)
|
||||
result.bits().push_back(RTLIL::State::S0);
|
||||
if (GetSize(result) < result_len)
|
||||
result.resize(result_len, RTLIL::State::S0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +618,7 @@ RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
|||
RTLIL::Const ret = arg1;
|
||||
for (auto i = 0; i < ret.size(); i++)
|
||||
if (ret[i] != arg2[i])
|
||||
ret.bits()[i] = State::Sx;
|
||||
ret.set(i, State::Sx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -703,7 +693,7 @@ RTLIL::Const RTLIL::const_bweqx(const RTLIL::Const &arg1, const RTLIL::Const &ar
|
|||
log_assert(arg2.size() == arg1.size());
|
||||
RTLIL::Const result(RTLIL::State::S0, arg1.size());
|
||||
for (auto i = 0; i < arg1.size(); i++)
|
||||
result.bits()[i] = arg1[i] == arg2[i] ? State::S1 : State::S0;
|
||||
result.set(i, arg1[i] == arg2[i] ? State::S1 : State::S0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -715,7 +705,7 @@ RTLIL::Const RTLIL::const_bwmux(const RTLIL::Const &arg1, const RTLIL::Const &ar
|
|||
RTLIL::Const result(RTLIL::State::Sx, arg1.size());
|
||||
for (auto i = 0; i < arg1.size(); i++) {
|
||||
if (arg3[i] != State::Sx || arg1[i] == arg2[i])
|
||||
result.bits()[i] = arg3[i] == State::S1 ? arg2[i] : arg1[i];
|
||||
result.set(i, arg3[i] == State::S1 ? arg2[i] : arg1[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
|
|||
return true;
|
||||
}
|
||||
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
if (cell->is_builtin_ff()) {
|
||||
ff_op(this, cell);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ struct CellTypes
|
|||
setup_type(ID($original_tag), {ID::A}, {ID::Y});
|
||||
setup_type(ID($future_ff), {ID::A}, {ID::Y});
|
||||
setup_type(ID($scopeinfo), {}, {});
|
||||
setup_type(ID($input_port), {}, {ID::Y});
|
||||
setup_type(ID($connect), {ID::A, ID::B}, {});
|
||||
}
|
||||
|
||||
void setup_internals_eval()
|
||||
|
|
@ -320,6 +322,16 @@ struct CellTypes
|
|||
return it != cell_types.end() && it->second.inputs.count(port) != 0;
|
||||
}
|
||||
|
||||
RTLIL::PortDir cell_port_dir(RTLIL::IdString type, RTLIL::IdString port) const
|
||||
{
|
||||
auto it = cell_types.find(type);
|
||||
if (it == cell_types.end())
|
||||
return RTLIL::PD_UNKNOWN;
|
||||
bool is_input = it->second.inputs.count(port);
|
||||
bool is_output = it->second.outputs.count(port);
|
||||
return RTLIL::PortDir(is_input + is_output * 2);
|
||||
}
|
||||
|
||||
bool cell_evaluable(const RTLIL::IdString &type) const
|
||||
{
|
||||
auto it = cell_types.find(type);
|
||||
|
|
@ -328,7 +340,7 @@ struct CellTypes
|
|||
|
||||
static RTLIL::Const eval_not(RTLIL::Const v)
|
||||
{
|
||||
for (auto &bit : v.bits())
|
||||
for (auto bit : v)
|
||||
if (bit == State::S0) bit = State::S1;
|
||||
else if (bit == State::S1) bit = State::S0;
|
||||
return v;
|
||||
|
|
@ -421,16 +433,14 @@ struct CellTypes
|
|||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type == ID($slice)) {
|
||||
RTLIL::Const ret;
|
||||
int width = cell->parameters.at(ID::Y_WIDTH).as_int();
|
||||
int offset = cell->parameters.at(ID::OFFSET).as_int();
|
||||
ret.bits().insert(ret.bits().end(), arg1.begin()+offset, arg1.begin()+offset+width);
|
||||
return ret;
|
||||
return arg1.extract(offset, width);
|
||||
}
|
||||
|
||||
if (cell->type == ID($concat)) {
|
||||
RTLIL::Const ret = arg1;
|
||||
ret.bits().insert(ret.bits().end(), arg2.begin(), arg2.end());
|
||||
ret.append(arg2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ struct ConstEval
|
|||
|
||||
for (int i = 0; i < GetSize(coval); i++) {
|
||||
carry = (sig_g[i] == State::S1) || (sig_p[i] == RTLIL::S1 && carry);
|
||||
coval.bits()[i] = carry ? State::S1 : State::S0;
|
||||
coval.set(i, carry ? State::S1 : State::S0);
|
||||
}
|
||||
|
||||
set(sig_co, coval);
|
||||
|
|
@ -249,7 +249,7 @@ struct ConstEval
|
|||
|
||||
for (int i = 0; i < GetSize(val_y); i++)
|
||||
if (val_y[i] == RTLIL::Sx)
|
||||
val_x.bits()[i] = RTLIL::Sx;
|
||||
val_x.set(i, RTLIL::Sx);
|
||||
|
||||
set(sig_y, val_y);
|
||||
set(sig_x, val_x);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ unsigned int CellCosts::get(RTLIL::Cell *cell)
|
|||
if (design_ && design_->module(cell->type) && cell->parameters.empty()) {
|
||||
log_debug("%s is a module, recurse\n", cell->name.c_str());
|
||||
return get(design_->module(cell->type));
|
||||
} else if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
} else if (cell->is_builtin_ff()) {
|
||||
log_assert(cell->hasPort(ID::Q) && "Weird flip flop");
|
||||
log_debug("%s is ff\n", cell->name.c_str());
|
||||
return cell->getParam(ID::WIDTH).as_int();
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ bool DriveChunkMultiple::try_append(DriveBitMultiple const &bit)
|
|||
switch (single.type())
|
||||
{
|
||||
case DriveType::CONSTANT: {
|
||||
single.constant().bits().push_back(constant);
|
||||
single.constant().append(RTLIL::Const(constant));
|
||||
} break;
|
||||
case DriveType::WIRE: {
|
||||
single.wire().width += 1;
|
||||
|
|
@ -295,8 +295,7 @@ bool DriveChunkMultiple::try_append(DriveChunkMultiple const &chunk)
|
|||
switch (single.type())
|
||||
{
|
||||
case DriveType::CONSTANT: {
|
||||
auto &bits = single.constant().bits();
|
||||
bits.insert(bits.end(), constant.bits().begin(), constant.bits().end());
|
||||
single.constant().append(constant);
|
||||
} break;
|
||||
case DriveType::WIRE: {
|
||||
single.wire().width += width;
|
||||
|
|
@ -349,7 +348,7 @@ bool DriveChunk::try_append(DriveBit const &bit)
|
|||
none_ += 1;
|
||||
return true;
|
||||
case DriveType::CONSTANT:
|
||||
constant_.bits().push_back(bit.constant());
|
||||
constant_.append(RTLIL::Const(bit.constant()));
|
||||
return true;
|
||||
case DriveType::WIRE:
|
||||
return wire_.try_append(bit.wire());
|
||||
|
|
@ -375,7 +374,7 @@ bool DriveChunk::try_append(DriveChunk const &chunk)
|
|||
none_ += chunk.none_;
|
||||
return true;
|
||||
case DriveType::CONSTANT:
|
||||
constant_.bits().insert(constant_.bits().end(), chunk.constant_.begin(), chunk.constant_.end());
|
||||
constant_.append(chunk.constant_);
|
||||
return true;
|
||||
case DriveType::WIRE:
|
||||
return wire_.try_append(chunk.wire());
|
||||
|
|
|
|||
31
kernel/ff.cc
31
kernel/ff.cc
|
|
@ -287,6 +287,16 @@ FfData FfData::slice(const std::vector<int> &bits) {
|
|||
res.pol_clr = pol_clr;
|
||||
res.pol_set = pol_set;
|
||||
res.attributes = attributes;
|
||||
std::optional<Const::Builder> arst_bits;
|
||||
if (has_arst)
|
||||
arst_bits.emplace(bits.size());
|
||||
std::optional<Const::Builder> srst_bits;
|
||||
if (has_srst)
|
||||
srst_bits.emplace(bits.size());
|
||||
std::optional<Const::Builder> init_bits;
|
||||
if (initvals)
|
||||
init_bits.emplace(bits.size());
|
||||
|
||||
for (int i : bits) {
|
||||
res.sig_q.append(sig_q[i]);
|
||||
if (has_clk || has_gclk)
|
||||
|
|
@ -298,12 +308,19 @@ FfData FfData::slice(const std::vector<int> &bits) {
|
|||
res.sig_set.append(sig_set[i]);
|
||||
}
|
||||
if (has_arst)
|
||||
res.val_arst.bits().push_back(val_arst[i]);
|
||||
arst_bits->push_back(val_arst[i]);
|
||||
if (has_srst)
|
||||
res.val_srst.bits().push_back(val_srst[i]);
|
||||
srst_bits->push_back(val_srst[i]);
|
||||
if (initvals)
|
||||
res.val_init.bits().push_back(val_init[i]);
|
||||
init_bits->push_back(val_init[i]);
|
||||
}
|
||||
|
||||
if (has_arst)
|
||||
res.val_arst = arst_bits->build();
|
||||
if (has_srst)
|
||||
res.val_srst = srst_bits->build();
|
||||
if (initvals)
|
||||
res.val_init = init_bits->build();
|
||||
res.width = GetSize(res.sig_q);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -688,10 +705,10 @@ void FfData::flip_rst_bits(const pool<int> &bits) {
|
|||
|
||||
for (auto bit: bits) {
|
||||
if (has_arst)
|
||||
val_arst.bits()[bit] = invert(val_arst[bit]);
|
||||
val_arst.set(bit, invert(val_arst[bit]));
|
||||
if (has_srst)
|
||||
val_srst.bits()[bit] = invert(val_srst[bit]);
|
||||
val_init.bits()[bit] = invert(val_init[bit]);
|
||||
val_srst.set(bit, invert(val_srst[bit]));
|
||||
val_init.set(bit, invert(val_init[bit]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -760,7 +777,7 @@ void FfData::flip_bits(const pool<int> &bits) {
|
|||
|
||||
Const mask = Const(State::S0, width);
|
||||
for (auto bit: bits)
|
||||
mask.bits()[bit] = State::S1;
|
||||
mask.set(bit, State::S1);
|
||||
|
||||
if (has_clk || has_gclk)
|
||||
sig_d = module->Xor(NEW_ID4_SUFFIX("d"), sig_d, mask, false, attributes[ID::src].decode_string()); // SILIMATE: Improve the naming
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ struct FfInitVals
|
|||
|
||||
RTLIL::Const operator()(const RTLIL::SigSpec &sig) const
|
||||
{
|
||||
RTLIL::Const res;
|
||||
RTLIL::Const::Builder res_bits(GetSize(sig));
|
||||
for (auto bit : sig)
|
||||
res.bits().push_back((*this)(bit));
|
||||
return res;
|
||||
res_bits.push_back((*this)(bit));
|
||||
return res_bits.build();
|
||||
}
|
||||
|
||||
void set_init(RTLIL::SigBit bit, RTLIL::State val)
|
||||
|
|
@ -93,12 +93,12 @@ struct FfInitVals
|
|||
initbits[mbit] = std::make_pair(val,abit);
|
||||
auto it2 = abit.wire->attributes.find(ID::init);
|
||||
if (it2 != abit.wire->attributes.end()) {
|
||||
it2->second.bits()[abit.offset] = val;
|
||||
it2->second.set(abit.offset, val);
|
||||
if (it2->second.is_fully_undef())
|
||||
abit.wire->attributes.erase(it2);
|
||||
} else if (val != State::Sx) {
|
||||
Const cval(State::Sx, GetSize(abit.wire));
|
||||
cval.bits()[abit.offset] = val;
|
||||
cval.set(abit.offset, val);
|
||||
abit.wire->attributes[ID::init] = cval;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
|
|||
ff.sig_d.append(bit);
|
||||
ff.sig_clr.append(State::Sx);
|
||||
ff.sig_set.append(State::Sx);
|
||||
ff.val_init.bits().push_back(State::Sx);
|
||||
ff.val_srst.bits().push_back(State::Sx);
|
||||
ff.val_arst.bits().push_back(State::Sx);
|
||||
ff.val_init.append(RTLIL::Const(State::Sx));
|
||||
ff.val_srst.append(RTLIL::Const(State::Sx));
|
||||
ff.val_arst.append(RTLIL::Const(State::Sx));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -147,9 +147,9 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
|
|||
ff.sig_q.append(cur_ff.sig_q[idx]);
|
||||
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
|
||||
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
|
||||
ff.val_arst.bits().push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx);
|
||||
ff.val_srst.bits().push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx);
|
||||
ff.val_init.bits().push_back(cur_ff.val_init[idx]);
|
||||
ff.val_arst.append(RTLIL::Const(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx));
|
||||
ff.val_srst.append(RTLIL::Const(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx));
|
||||
ff.val_init.append(RTLIL::Const(cur_ff.val_init[idx]));
|
||||
found = true;
|
||||
}
|
||||
|
||||
|
|
@ -174,9 +174,9 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
|
|||
// These two will be fixed up later.
|
||||
ff.sig_clr.append(State::Sx);
|
||||
ff.sig_set.append(State::Sx);
|
||||
ff.val_init.bits().push_back(bit.data);
|
||||
ff.val_srst.bits().push_back(bit.data);
|
||||
ff.val_arst.bits().push_back(bit.data);
|
||||
ff.val_init.append(RTLIL::Const(bit.data));
|
||||
ff.val_srst.append(RTLIL::Const(bit.data));
|
||||
ff.val_arst.append(RTLIL::Const(bit.data));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -274,9 +274,9 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
|
|||
ff.sig_q.append(cur_ff.sig_q[idx]);
|
||||
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
|
||||
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
|
||||
ff.val_arst.bits().push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx);
|
||||
ff.val_srst.bits().push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx);
|
||||
ff.val_init.bits().push_back(cur_ff.val_init[idx]);
|
||||
ff.val_arst.append(RTLIL::Const(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx));
|
||||
ff.val_srst.append(RTLIL::Const(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx));
|
||||
ff.val_init.append(RTLIL::Const(cur_ff.val_init[idx]));
|
||||
found = true;
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ void FfMergeHelper::set(FfInitVals *initvals_, RTLIL::Module *module_)
|
|||
}
|
||||
|
||||
for (auto cell : module->cells()) {
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
if (cell->is_builtin_ff()) {
|
||||
if (cell->hasPort(ID::D)) {
|
||||
SigSpec d = (*sigmap)(cell->getPort(ID::D));
|
||||
for (int i = 0; i < GetSize(d); i++)
|
||||
|
|
|
|||
|
|
@ -401,11 +401,11 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
part = {};
|
||||
}
|
||||
if (++i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
if (++arg == args.end()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name, fmtarg - args.begin() + 1);
|
||||
}
|
||||
part.sig = arg->sig;
|
||||
part.signed_ = arg->signed_;
|
||||
|
|
@ -420,7 +420,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
} else break;
|
||||
}
|
||||
if (i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
bool has_leading_zero = false, has_width = false;
|
||||
|
|
@ -465,15 +465,15 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
if (!has_width && !has_leading_zero)
|
||||
part.width = 20;
|
||||
} else {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name, fmt[i], fmtarg - args.begin() + 1);
|
||||
}
|
||||
} else {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name, fmt[i], fmtarg - args.begin() + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i == fmt.size()) {
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1);
|
||||
}
|
||||
|
||||
if (part.padding == '\0') {
|
||||
|
|
@ -486,7 +486,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
|||
}
|
||||
|
||||
if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS)
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
|
||||
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1);
|
||||
|
||||
if (part.base != 10)
|
||||
part.signed_ = false;
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ private:
|
|||
}
|
||||
Node node = handle_memory(mem);
|
||||
factory.update_pending(cell_outputs.at({cell, ID(RD_DATA)}), node);
|
||||
} else if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
} else if (cell->is_builtin_ff()) {
|
||||
FfData ff(&ff_initvals, cell);
|
||||
if (!ff.has_gclk)
|
||||
log_error("The design contains a %s flip-flop at %s. This is not supported by the functional backend. "
|
||||
|
|
|
|||
|
|
@ -103,11 +103,11 @@ gzip_istream::ibuf::~ibuf() {
|
|||
// Never returns nullptr or failed state istream*
|
||||
std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) {
|
||||
if (!check_file_exists(filename))
|
||||
log_cmd_error("File `%s' not found or is a directory\n", filename.c_str());
|
||||
log_cmd_error("File `%s' not found or is a directory\n", filename);
|
||||
std::ifstream* f = new std::ifstream();
|
||||
f->open(filename, mode);
|
||||
if (f->fail())
|
||||
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
|
||||
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename, strerror(errno));
|
||||
// Check for gzip magic
|
||||
unsigned char magic[3];
|
||||
int n = 0;
|
||||
|
|
@ -131,7 +131,7 @@ std::istream* uncompressed(const std::string filename, std::ios_base::openmode m
|
|||
log_assert(ok && "Failed to open gzipped file.\n");
|
||||
return s;
|
||||
#else
|
||||
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
|
||||
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename);
|
||||
#endif // YOSYS_ENABLE_ZLIB
|
||||
} else {
|
||||
f->clear();
|
||||
|
|
|
|||
|
|
@ -169,8 +169,17 @@ struct hash_ops {
|
|||
} else if constexpr (std::is_pointer_v<T>) {
|
||||
return hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);
|
||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
||||
for (auto c : a)
|
||||
h.hash32(c);
|
||||
int size = a.size();
|
||||
int i = 0;
|
||||
while (i + 8 < size) {
|
||||
uint64_t v;
|
||||
memcpy(&v, a.data() + i, 8);
|
||||
h.hash64(v);
|
||||
i += 8;
|
||||
}
|
||||
uint64_t v = 0;
|
||||
memcpy(&v, a.data() + i, size - i);
|
||||
h.hash64(v);
|
||||
return h;
|
||||
} else {
|
||||
return a.hash_into(h);
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@ int log_debug_suppressed = 0;
|
|||
|
||||
vector<int> header_count;
|
||||
vector<char*> log_id_cache;
|
||||
vector<shared_str> string_buf;
|
||||
int string_buf_index = -1;
|
||||
|
||||
static struct timeval initial_tv = { 0, 0 };
|
||||
static bool next_print_log = false;
|
||||
|
|
@ -189,7 +187,7 @@ static void logv_string(std::string_view format, std::string str) {
|
|||
if (!linebuffer.empty() && linebuffer.back() == '\n') {
|
||||
for (auto &re : log_warn_regexes)
|
||||
if (std::regex_search(linebuffer, re))
|
||||
log_warning("Found log message matching -W regex:\n%s", str.c_str());
|
||||
log_warning("Found log message matching -W regex:\n%s", str);
|
||||
|
||||
for (auto &[_, item] : log_expect_log)
|
||||
if (std::regex_search(linebuffer, item.pattern))
|
||||
|
|
@ -447,8 +445,6 @@ void log_pop()
|
|||
{
|
||||
header_count.pop_back();
|
||||
log_id_cache_clear();
|
||||
string_buf.clear();
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
}
|
||||
|
||||
|
|
@ -554,8 +550,6 @@ void log_reset_stack()
|
|||
while (header_count.size() > 1)
|
||||
header_count.pop_back();
|
||||
log_id_cache_clear();
|
||||
string_buf.clear();
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
}
|
||||
|
||||
|
|
@ -580,38 +574,19 @@ void log_dump_val_worker(RTLIL::State v) {
|
|||
log("%s", log_signal(v));
|
||||
}
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
|
||||
std::string log_signal(const RTLIL::SigSpec &sig, bool autoint)
|
||||
{
|
||||
std::stringstream buf;
|
||||
RTLIL_BACKEND::dump_sigspec(buf, sig, autoint);
|
||||
|
||||
if (string_buf.size() < 100) {
|
||||
string_buf.push_back(buf.str());
|
||||
return string_buf.back().c_str();
|
||||
} else {
|
||||
if (++string_buf_index == 100)
|
||||
string_buf_index = 0;
|
||||
string_buf[string_buf_index] = buf.str();
|
||||
return string_buf[string_buf_index].c_str();
|
||||
}
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
const char *log_const(const RTLIL::Const &value, bool autoint)
|
||||
std::string log_const(const RTLIL::Const &value, bool autoint)
|
||||
{
|
||||
if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0)
|
||||
return log_signal(value, autoint);
|
||||
|
||||
std::string str = "\"" + value.decode_string() + "\"";
|
||||
|
||||
if (string_buf.size() < 100) {
|
||||
string_buf.push_back(str);
|
||||
return string_buf.back().c_str();
|
||||
} else {
|
||||
if (++string_buf_index == 100)
|
||||
string_buf_index = 0;
|
||||
string_buf[string_buf_index] = str;
|
||||
return string_buf[string_buf_index].c_str();
|
||||
}
|
||||
return "\"" + value.decode_string() + "\"";
|
||||
}
|
||||
|
||||
const char *log_id(const RTLIL::IdString &str)
|
||||
|
|
@ -729,7 +704,7 @@ dict<std::string, std::pair<std::string, int>> get_coverage_data()
|
|||
|
||||
for (auto &it : extra_coverage_data) {
|
||||
if (coverage_data.count(it.first))
|
||||
log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str());
|
||||
log_warning("found duplicate coverage id \"%s\".\n", it.first);
|
||||
coverage_data[it.first].first = it.second.first;
|
||||
coverage_data[it.first].second += it.second.second;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,11 @@ inline void log_warning(FmtString<TypeIdentity<Args>...> fmt, const Args &... ar
|
|||
{
|
||||
log_formatted_warning("Warning: ", fmt.format(args...));
|
||||
}
|
||||
|
||||
inline void log_formatted_warning_noprefix(std::string str)
|
||||
{
|
||||
log_formatted_warning("", str);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void log_warning_noprefix(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
|
||||
{
|
||||
|
|
@ -253,8 +258,8 @@ extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, lo
|
|||
extern dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;
|
||||
void log_check_expected();
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
||||
const char *log_const(const RTLIL::Const &value, bool autoint = true);
|
||||
std::string log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
||||
std::string log_const(const RTLIL::Const &value, bool autoint = true);
|
||||
const char *log_id(const RTLIL::IdString &id);
|
||||
|
||||
template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ struct Macc
|
|||
|
||||
bool eval(RTLIL::Const &result) const
|
||||
{
|
||||
for (auto &bit : result.bits())
|
||||
for (auto bit : result)
|
||||
bit = State::S0;
|
||||
|
||||
for (auto &port : terms)
|
||||
|
|
|
|||
|
|
@ -131,9 +131,6 @@ void Mem::emit() {
|
|||
cell->parameters[ID::WIDTH] = Const(width);
|
||||
cell->parameters[ID::OFFSET] = Const(start_offset);
|
||||
cell->parameters[ID::SIZE] = Const(size);
|
||||
Const rd_wide_continuation, rd_clk_enable, rd_clk_polarity, rd_transparency_mask, rd_collision_x_mask;
|
||||
Const wr_wide_continuation, wr_clk_enable, wr_clk_polarity, wr_priority_mask;
|
||||
Const rd_ce_over_srst, rd_arst_value, rd_srst_value, rd_init_value;
|
||||
SigSpec rd_clk, rd_en, rd_addr, rd_data;
|
||||
SigSpec wr_clk, wr_en, wr_addr, wr_data;
|
||||
SigSpec rd_arst, rd_srst;
|
||||
|
|
@ -147,6 +144,15 @@ void Mem::emit() {
|
|||
for (int i = 0; i < GetSize(wr_ports); i++)
|
||||
for (int j = 0; j < (1 << wr_ports[i].wide_log2); j++)
|
||||
wr_port_xlat.push_back(i);
|
||||
Const::Builder rd_wide_continuation_builder;
|
||||
Const::Builder rd_clk_enable_builder;
|
||||
Const::Builder rd_clk_polarity_builder;
|
||||
Const::Builder rd_transparency_mask_builder;
|
||||
Const::Builder rd_collision_x_mask_builder;
|
||||
Const::Builder rd_ce_over_srst_builder;
|
||||
Const::Builder rd_arst_value_builder;
|
||||
Const::Builder rd_srst_value_builder;
|
||||
Const::Builder rd_init_value_builder;
|
||||
for (auto &port : rd_ports) {
|
||||
for (auto attr: port.attributes)
|
||||
if (!cell->has_attribute(attr.first))
|
||||
|
|
@ -157,10 +163,10 @@ void Mem::emit() {
|
|||
}
|
||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++)
|
||||
{
|
||||
rd_wide_continuation.bits().push_back(State(sub != 0));
|
||||
rd_clk_enable.bits().push_back(State(port.clk_enable));
|
||||
rd_clk_polarity.bits().push_back(State(port.clk_polarity));
|
||||
rd_ce_over_srst.bits().push_back(State(port.ce_over_srst));
|
||||
rd_wide_continuation_builder.push_back(State(sub != 0));
|
||||
rd_clk_enable_builder.push_back(State(port.clk_enable));
|
||||
rd_clk_polarity_builder.push_back(State(port.clk_polarity));
|
||||
rd_ce_over_srst_builder.push_back(State(port.ce_over_srst));
|
||||
rd_clk.append(port.clk);
|
||||
rd_arst.append(port.arst);
|
||||
rd_srst.append(port.srst);
|
||||
|
|
@ -170,18 +176,27 @@ void Mem::emit() {
|
|||
rd_addr.append(addr);
|
||||
log_assert(GetSize(addr) == abits);
|
||||
for (auto idx : wr_port_xlat) {
|
||||
rd_transparency_mask.bits().push_back(State(bool(port.transparency_mask[idx])));
|
||||
rd_collision_x_mask.bits().push_back(State(bool(port.collision_x_mask[idx])));
|
||||
rd_transparency_mask_builder.push_back(State(bool(port.transparency_mask[idx])));
|
||||
rd_collision_x_mask_builder.push_back(State(bool(port.collision_x_mask[idx])));
|
||||
}
|
||||
}
|
||||
rd_data.append(port.data);
|
||||
for (auto bit : port.arst_value)
|
||||
rd_arst_value.bits().push_back(bit);
|
||||
rd_arst_value_builder.push_back(bit);
|
||||
for (auto bit : port.srst_value)
|
||||
rd_srst_value.bits().push_back(bit);
|
||||
rd_srst_value_builder.push_back(bit);
|
||||
for (auto bit : port.init_value)
|
||||
rd_init_value.bits().push_back(bit);
|
||||
rd_init_value_builder.push_back(bit);
|
||||
}
|
||||
Const rd_wide_continuation = rd_wide_continuation_builder.build();
|
||||
Const rd_clk_enable = rd_clk_enable_builder.build();
|
||||
Const rd_clk_polarity = rd_clk_polarity_builder.build();
|
||||
Const rd_transparency_mask = rd_transparency_mask_builder.build();
|
||||
Const rd_collision_x_mask = rd_collision_x_mask_builder.build();
|
||||
Const rd_ce_over_srst = rd_ce_over_srst_builder.build();
|
||||
Const rd_arst_value = rd_arst_value_builder.build();
|
||||
Const rd_srst_value = rd_srst_value_builder.build();
|
||||
Const rd_init_value = rd_init_value_builder.build();
|
||||
if (rd_ports.empty()) {
|
||||
rd_wide_continuation = State::S0;
|
||||
rd_clk_enable = State::S0;
|
||||
|
|
@ -212,6 +227,10 @@ void Mem::emit() {
|
|||
cell->setPort(ID::RD_SRST, rd_srst);
|
||||
cell->setPort(ID::RD_ADDR, rd_addr);
|
||||
cell->setPort(ID::RD_DATA, rd_data);
|
||||
Const::Builder wr_wide_continuation_builder;
|
||||
Const::Builder wr_clk_enable_builder;
|
||||
Const::Builder wr_clk_polarity_builder;
|
||||
Const::Builder wr_priority_mask_builder;
|
||||
for (auto &port : wr_ports) {
|
||||
for (auto attr: port.attributes)
|
||||
if (!cell->has_attribute(attr.first))
|
||||
|
|
@ -222,12 +241,12 @@ void Mem::emit() {
|
|||
}
|
||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++)
|
||||
{
|
||||
wr_wide_continuation.bits().push_back(State(sub != 0));
|
||||
wr_clk_enable.bits().push_back(State(port.clk_enable));
|
||||
wr_clk_polarity.bits().push_back(State(port.clk_polarity));
|
||||
wr_wide_continuation_builder.push_back(State(sub != 0));
|
||||
wr_clk_enable_builder.push_back(State(port.clk_enable));
|
||||
wr_clk_polarity_builder.push_back(State(port.clk_polarity));
|
||||
wr_clk.append(port.clk);
|
||||
for (auto idx : wr_port_xlat)
|
||||
wr_priority_mask.bits().push_back(State(bool(port.priority_mask[idx])));
|
||||
wr_priority_mask_builder.push_back(State(bool(port.priority_mask[idx])));
|
||||
SigSpec addr = port.sub_addr(sub);
|
||||
addr.extend_u0(abits, false);
|
||||
wr_addr.append(addr);
|
||||
|
|
@ -236,6 +255,10 @@ void Mem::emit() {
|
|||
wr_en.append(port.en);
|
||||
wr_data.append(port.data);
|
||||
}
|
||||
Const wr_wide_continuation = wr_wide_continuation_builder.build();
|
||||
Const wr_clk_enable = wr_clk_enable_builder.build();
|
||||
Const wr_clk_polarity = wr_clk_polarity_builder.build();
|
||||
Const wr_priority_mask = wr_priority_mask_builder.build();
|
||||
if (wr_ports.empty()) {
|
||||
wr_wide_continuation = State::S0;
|
||||
wr_clk_enable = State::S0;
|
||||
|
|
@ -414,7 +437,7 @@ void Mem::coalesce_inits() {
|
|||
if (!init.en.is_fully_ones()) {
|
||||
for (int i = 0; i < GetSize(init.data); i++)
|
||||
if (init.en[i % width] != State::S1)
|
||||
init.data.bits()[i] = State::Sx;
|
||||
init.data.set(i, State::Sx);
|
||||
init.en = Const(State::S1, width);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -427,7 +450,7 @@ void Mem::coalesce_inits() {
|
|||
log_assert(offset + GetSize(init.data) <= GetSize(cdata));
|
||||
for (int i = 0; i < GetSize(init.data); i++)
|
||||
if (init.en[i % width] == State::S1)
|
||||
cdata.bits()[i+offset] = init.data[i];
|
||||
cdata.set(i+offset, init.data[i]);
|
||||
init.removed = true;
|
||||
}
|
||||
MemInit new_init;
|
||||
|
|
@ -446,7 +469,7 @@ Const Mem::get_init_data() const {
|
|||
int offset = (init.addr.as_int() - start_offset) * width;
|
||||
for (int i = 0; i < GetSize(init.data); i++)
|
||||
if (0 <= i+offset && i+offset < GetSize(init_data) && init.en[i % width] == State::S1)
|
||||
init_data.bits()[i+offset] = init.data[i];
|
||||
init_data.set(i+offset, init.data[i]);
|
||||
}
|
||||
return init_data;
|
||||
}
|
||||
|
|
@ -1700,7 +1723,7 @@ MemContents::MemContents(Mem *mem) :
|
|||
RTLIL::Const previous = (*this)[addr + i];
|
||||
for(int j = 0; j < _data_width; j++)
|
||||
if(init.en[j] != State::S1)
|
||||
data.bits()[_data_width * i + j] = previous[j];
|
||||
data.set(_data_width * i + j, previous[j]);
|
||||
}
|
||||
insert_concatenated(init.addr.as_int(), data);
|
||||
}
|
||||
|
|
@ -1846,7 +1869,7 @@ std::map<MemContents::addr_t, RTLIL::Const>::iterator MemContents::_reserve_rang
|
|||
// we have two different ranges touching at either end, we need to merge them
|
||||
auto upper_end = _range_end(upper_it);
|
||||
// make range bigger (maybe reserve here instead of resize?)
|
||||
lower_it->second.bits().resize(_range_offset(lower_it, upper_end), State::Sx);
|
||||
lower_it->second.resize(_range_offset(lower_it, upper_end), State::Sx);
|
||||
// copy only the data beyond our range
|
||||
std::copy(_range_data(upper_it, end_addr), _range_data(upper_it, upper_end), _range_data(lower_it, end_addr));
|
||||
// keep lower_it, but delete upper_it
|
||||
|
|
@ -1854,16 +1877,16 @@ std::map<MemContents::addr_t, RTLIL::Const>::iterator MemContents::_reserve_rang
|
|||
return lower_it;
|
||||
} else if (lower_touch) {
|
||||
// we have a range to the left, just make it bigger and delete any other that may exist.
|
||||
lower_it->second.bits().resize(_range_offset(lower_it, end_addr), State::Sx);
|
||||
lower_it->second.resize(_range_offset(lower_it, end_addr), State::Sx);
|
||||
// keep lower_it and upper_it
|
||||
_values.erase(std::next(lower_it), upper_it);
|
||||
return lower_it;
|
||||
} else if (upper_touch) {
|
||||
// we have a range to the right, we need to expand it
|
||||
// since we need to erase and reinsert to a new address, steal the data
|
||||
RTLIL::Const data = std::move(upper_it->second);
|
||||
// note that begin_addr is not in upper_it, otherwise the whole range covered check would have tripped
|
||||
data.bits().insert(data.bits().begin(), (_range_begin(upper_it) - begin_addr) * _data_width, State::Sx);
|
||||
RTLIL::Const data(State::Sx, (_range_begin(upper_it) - begin_addr) * _data_width);
|
||||
data.append(std::move(upper_it->second));
|
||||
// delete lower_it and upper_it, then reinsert
|
||||
_values.erase(lower_it, std::next(upper_it));
|
||||
return _values.emplace(begin_addr, std::move(data)).first;
|
||||
|
|
@ -1886,7 +1909,7 @@ void MemContents::insert_concatenated(addr_t addr, RTLIL::Const const &values) {
|
|||
std::fill(to_begin + values.size(), to_begin + words * _data_width, State::S0);
|
||||
}
|
||||
|
||||
std::vector<State>::iterator MemContents::_range_write(std::vector<State>::iterator it, RTLIL::Const const &word) {
|
||||
RTLIL::Const::iterator MemContents::_range_write(RTLIL::Const::iterator it, RTLIL::Const const &word) {
|
||||
auto from_end = word.size() <= _data_width ? word.end() : word.begin() + _data_width;
|
||||
auto to_end = std::copy(word.begin(), from_end, it);
|
||||
auto it_next = std::next(it, _data_width);
|
||||
|
|
|
|||
|
|
@ -255,11 +255,13 @@ private:
|
|||
// return the offset the addr would have in the range at `it`
|
||||
size_t _range_offset(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) const { return (addr - it->first) * _data_width; }
|
||||
// assuming _range_contains(it, addr), return an iterator pointing to the data at addr
|
||||
std::vector<State>::iterator _range_data(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) { return it->second.bits().begin() + _range_offset(it, addr); }
|
||||
RTLIL::Const::iterator _range_data(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) {
|
||||
return RTLIL::Const::iterator(it->second, _range_offset(it, addr));
|
||||
}
|
||||
// internal version of reserve_range that returns an iterator to the range
|
||||
std::map<addr_t, RTLIL::Const>::iterator _reserve_range(addr_t begin_addr, addr_t end_addr);
|
||||
// write a single word at addr, return iterator to next word
|
||||
std::vector<State>::iterator _range_write(std::vector<State>::iterator it, RTLIL::Const const &data);
|
||||
RTLIL::Const::iterator _range_write(RTLIL::Const::iterator it, RTLIL::Const const &data);
|
||||
public:
|
||||
class range {
|
||||
int _data_width;
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
|
|||
while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
|
||||
cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
|
||||
cmd_buf.resize(cmd_buf.size()-1);
|
||||
log_header(design, "Shell command: %s\n", cmd_buf.c_str());
|
||||
log_header(design, "Shell command: %s\n", cmd_buf);
|
||||
int retCode = run_command(cmd_buf);
|
||||
if (retCode != 0)
|
||||
log_cmd_error("Shell command returned error code %d.\n", retCode);
|
||||
|
|
@ -262,7 +262,7 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
|
|||
}
|
||||
|
||||
if (pass_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str());
|
||||
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0]);
|
||||
|
||||
if (pass_register[args[0]]->experimental_flag)
|
||||
log_experimental(args[0]);
|
||||
|
|
@ -521,7 +521,7 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string
|
|||
if (args.size() == 0)
|
||||
return;
|
||||
if (frontend_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such frontend: %s\n", args[0].c_str());
|
||||
log_cmd_error("No such frontend: %s\n", args[0]);
|
||||
|
||||
if (f != NULL) {
|
||||
auto state = frontend_register[args[0]]->pre_execute();
|
||||
|
|
@ -596,7 +596,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
|
|||
gzip_ostream *gf = new gzip_ostream;
|
||||
if (!gf->open(filename)) {
|
||||
delete gf;
|
||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
|
||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename, strerror(errno));
|
||||
}
|
||||
yosys_output_files.insert(filename);
|
||||
f = gf;
|
||||
|
|
@ -609,7 +609,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
|
|||
yosys_output_files.insert(filename);
|
||||
if (ff->fail()) {
|
||||
delete ff;
|
||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
|
||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename, strerror(errno));
|
||||
}
|
||||
f = ff;
|
||||
}
|
||||
|
|
@ -641,7 +641,7 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f
|
|||
if (args.size() == 0)
|
||||
return;
|
||||
if (backend_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such backend: %s\n", args[0].c_str());
|
||||
log_cmd_error("No such backend: %s\n", args[0]);
|
||||
|
||||
size_t orig_sel_stack_pos = design->selection_stack.size();
|
||||
|
||||
|
|
@ -956,13 +956,7 @@ struct HelpPass : public Pass {
|
|||
auto name = it.first.str();
|
||||
if (cell_help_messages.contains(name)) {
|
||||
auto cell_help = cell_help_messages.get(name);
|
||||
if (groups.count(cell_help.group) != 0) {
|
||||
auto group_cells = &groups.at(cell_help.group);
|
||||
group_cells->push_back(name);
|
||||
} else {
|
||||
auto group_cells = new vector<string>(1, name);
|
||||
groups.emplace(cell_help.group, *group_cells);
|
||||
}
|
||||
groups[cell_help.group].emplace_back(name);
|
||||
auto cell_pair = pair<SimHelper, CellType>(cell_help, it.second);
|
||||
cells.emplace(name, cell_pair);
|
||||
} else {
|
||||
|
|
@ -972,7 +966,7 @@ struct HelpPass : public Pass {
|
|||
}
|
||||
for (auto &it : cell_help_messages.cell_help) {
|
||||
if (cells.count(it.first) == 0) {
|
||||
log_warning("Found cell model '%s' without matching cell type.\n", it.first.c_str());
|
||||
log_warning("Found cell model '%s' without matching cell type.\n", it.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
465
kernel/rtlil.cc
465
kernel/rtlil.cc
|
|
@ -89,7 +89,7 @@ static_assert(check_well_known_id_order());
|
|||
|
||||
dict<std::string, std::string> RTLIL::constpad;
|
||||
|
||||
const pool<IdString> &RTLIL::builtin_ff_cell_types() {
|
||||
static const pool<IdString> &builtin_ff_cell_types_internal() {
|
||||
static const pool<IdString> res = {
|
||||
ID($sr),
|
||||
ID($ff),
|
||||
|
|
@ -240,14 +240,28 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
|
|||
return res;
|
||||
}
|
||||
|
||||
const pool<IdString> &RTLIL::builtin_ff_cell_types() {
|
||||
return builtin_ff_cell_types_internal();
|
||||
}
|
||||
|
||||
#define check(condition) log_assert(condition && "malformed Const union")
|
||||
|
||||
Const::bitvectype& Const::get_bits() const {
|
||||
const Const::bitvectype& Const::get_bits() const {
|
||||
check(is_bits());
|
||||
return *get_if_bits();
|
||||
}
|
||||
|
||||
std::string& Const::get_str() const {
|
||||
const std::string& Const::get_str() const {
|
||||
check(is_str());
|
||||
return *get_if_str();
|
||||
}
|
||||
|
||||
Const::bitvectype& Const::get_bits() {
|
||||
check(is_bits());
|
||||
return *get_if_bits();
|
||||
}
|
||||
|
||||
std::string& Const::get_str() {
|
||||
check(is_str());
|
||||
return *get_if_str();
|
||||
}
|
||||
|
|
@ -259,9 +273,34 @@ RTLIL::Const::Const(const std::string &str)
|
|||
tag = backing_tag::string;
|
||||
}
|
||||
|
||||
RTLIL::Const::Const(int val, int width)
|
||||
RTLIL::Const::Const(long long val) // default width 32
|
||||
{
|
||||
flags = RTLIL::CONST_FLAG_NONE;
|
||||
char bytes[] = {
|
||||
(char)(val >> 24), (char)(val >> 16), (char)(val >> 8), (char)val
|
||||
};
|
||||
new ((void*)&str_) std::string(bytes, 4);
|
||||
tag = backing_tag::string;
|
||||
}
|
||||
|
||||
RTLIL::Const::Const(long long val, int width)
|
||||
{
|
||||
flags = RTLIL::CONST_FLAG_NONE;
|
||||
if ((width & 7) == 0) {
|
||||
new ((void*)&str_) std::string();
|
||||
tag = backing_tag::string;
|
||||
std::string& str = get_str();
|
||||
int bytes = width >> 3;
|
||||
signed char sign_byte = val < 0 ? -1 : 0;
|
||||
str.resize(bytes, sign_byte);
|
||||
bytes = std::min<int>(bytes, sizeof(val));
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
str[str.size() - 1 - i] = val;
|
||||
val = val >> 8;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
new ((void*)&bits_) bitvectype();
|
||||
tag = backing_tag::bits;
|
||||
bitvectype& bv = get_bits();
|
||||
|
|
@ -365,6 +404,11 @@ bool RTLIL::Const::operator<(const RTLIL::Const &other) const
|
|||
|
||||
bool RTLIL::Const::operator ==(const RTLIL::Const &other) const
|
||||
{
|
||||
if (is_str() && other.is_str())
|
||||
return get_str() == other.get_str();
|
||||
if (is_bits() && other.is_bits())
|
||||
return get_bits() == other.get_bits();
|
||||
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
|
||||
|
|
@ -380,9 +424,9 @@ bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
|
|||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::vector<RTLIL::State>& RTLIL::Const::bits()
|
||||
std::vector<RTLIL::State>& RTLIL::Const::bits_internal()
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectorize_internal();
|
||||
return get_bits();
|
||||
}
|
||||
|
||||
|
|
@ -396,8 +440,14 @@ std::vector<RTLIL::State> RTLIL::Const::to_bits() const
|
|||
|
||||
bool RTLIL::Const::as_bool() const
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
if (is_str()) {
|
||||
for (char ch : get_str())
|
||||
if (ch != 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
for (size_t i = 0; i < bv.size(); i++)
|
||||
if (bv[i] == State::S1)
|
||||
return true;
|
||||
|
|
@ -406,15 +456,25 @@ bool RTLIL::Const::as_bool() const
|
|||
|
||||
int RTLIL::Const::as_int(bool is_signed) const
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
int32_t ret = 0;
|
||||
for (size_t i = 0; i < bv.size() && i < 32; i++)
|
||||
if (const std::string *s = get_if_str()) {
|
||||
int size = GetSize(*s);
|
||||
// Ignore any bytes after the first 4 since bits beyond 32 are truncated.
|
||||
for (int i = std::min(4, size); i > 0; i--)
|
||||
ret |= static_cast<unsigned char>((*s)[size - i]) << ((i - 1) * 8);
|
||||
// If is_signed and the string is shorter than 4 bytes then apply sign extension.
|
||||
if (is_signed && size > 0 && size < 4 && ((*s)[0] & 0x80))
|
||||
ret |= UINT32_MAX << size*8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
int significant_bits = std::min(GetSize(bv), 32);
|
||||
for (int i = 0; i < significant_bits; i++)
|
||||
if (bv[i] == State::S1)
|
||||
ret |= 1 << i;
|
||||
if (is_signed && bv.back() == State::S1)
|
||||
for (size_t i = bv.size(); i < 32; i++)
|
||||
ret |= 1 << i;
|
||||
if (is_signed && significant_bits > 0 && significant_bits < 32 && bv.back() == State::S1 )
|
||||
ret |= UINT32_MAX << significant_bits;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -434,7 +494,7 @@ bool RTLIL::Const::convertible_to_int(bool is_signed) const
|
|||
if (size == 32) {
|
||||
if (is_signed)
|
||||
return true;
|
||||
return get_bits().at(31) != State::S1;
|
||||
return back() != State::S1;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -455,7 +515,7 @@ int RTLIL::Const::as_int_saturating(bool is_signed) const
|
|||
|
||||
const auto min_size = get_min_size(is_signed);
|
||||
log_assert(min_size > 0);
|
||||
const auto neg = get_bits().at(min_size - 1);
|
||||
const auto neg = (*this)[min_size - 1];
|
||||
return neg ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
|
||||
}
|
||||
return as_int(is_signed);
|
||||
|
|
@ -488,7 +548,7 @@ int RTLIL::Const::get_min_size(bool is_signed) const
|
|||
void RTLIL::Const::compress(bool is_signed)
|
||||
{
|
||||
auto idx = get_min_size(is_signed);
|
||||
bits().erase(bits().begin() + idx, bits().end());
|
||||
resize(idx, RTLIL::State::S0);
|
||||
}
|
||||
|
||||
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
||||
|
|
@ -498,18 +558,17 @@ std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
|||
|
||||
std::string RTLIL::Const::as_string(const char* any) const
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
int sz = size();
|
||||
std::string ret;
|
||||
ret.reserve(bv.size());
|
||||
for (size_t i = bv.size(); i > 0; i--)
|
||||
switch (bv[i-1]) {
|
||||
case S0: ret += "0"; break;
|
||||
case S1: ret += "1"; break;
|
||||
case Sx: ret += "x"; break;
|
||||
case Sz: ret += "z"; break;
|
||||
ret.reserve(sz);
|
||||
for (int i = sz - 1; i >= 0; --i)
|
||||
switch ((*this)[i]) {
|
||||
case S0: ret.push_back('0'); break;
|
||||
case S1: ret.push_back('1'); break;
|
||||
case Sx: ret.push_back('x'); break;
|
||||
case Sz: ret.push_back('z'); break;
|
||||
case Sa: ret += any; break;
|
||||
case Sm: ret += "m"; break;
|
||||
case Sm: ret.push_back('m'); break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -536,8 +595,7 @@ std::string RTLIL::Const::decode_string() const
|
|||
if (auto str = get_if_str())
|
||||
return *str;
|
||||
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
const bitvectype& bv = get_bits();
|
||||
const int n = GetSize(bv);
|
||||
const int n_over_8 = n / 8;
|
||||
std::string s;
|
||||
|
|
@ -585,7 +643,7 @@ bool RTLIL::Const::empty() const {
|
|||
}
|
||||
}
|
||||
|
||||
void RTLIL::Const::bitvectorize() const {
|
||||
void RTLIL::Const::bitvectorize_internal() {
|
||||
if (tag == backing_tag::bits)
|
||||
return;
|
||||
|
||||
|
|
@ -611,26 +669,33 @@ void RTLIL::Const::bitvectorize() const {
|
|||
}
|
||||
|
||||
void RTLIL::Const::append(const RTLIL::Const &other) {
|
||||
bitvectorize();
|
||||
bitvectorize_internal();
|
||||
bitvectype& bv = get_bits();
|
||||
bv.insert(bv.end(), other.begin(), other.end());
|
||||
}
|
||||
|
||||
RTLIL::State RTLIL::Const::const_iterator::operator*() const {
|
||||
if (auto bv = parent.get_if_bits())
|
||||
if (auto bv = parent->get_if_bits())
|
||||
return (*bv)[idx];
|
||||
|
||||
int char_idx = parent.get_str().size() - idx / 8 - 1;
|
||||
bool bit = (parent.get_str()[char_idx] & (1 << (idx % 8)));
|
||||
int char_idx = parent->get_str().size() - idx / 8 - 1;
|
||||
bool bit = (parent->get_str()[char_idx] & (1 << (idx % 8)));
|
||||
return bit ? State::S1 : State::S0;
|
||||
}
|
||||
|
||||
bool RTLIL::Const::is_fully_zero() const
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
cover("kernel.rtlil.const.is_fully_zero");
|
||||
|
||||
if (auto str = get_if_str()) {
|
||||
for (char ch : *str)
|
||||
if (ch != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
|
||||
for (const auto &bit : bv)
|
||||
if (bit != RTLIL::State::S0)
|
||||
return false;
|
||||
|
|
@ -640,10 +705,16 @@ bool RTLIL::Const::is_fully_zero() const
|
|||
|
||||
bool RTLIL::Const::is_fully_ones() const
|
||||
{
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
cover("kernel.rtlil.const.is_fully_ones");
|
||||
|
||||
if (auto str = get_if_str()) {
|
||||
for (char ch : *str)
|
||||
if (ch != (char)0xff)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
for (const auto &bit : bv)
|
||||
if (bit != RTLIL::State::S1)
|
||||
return false;
|
||||
|
|
@ -655,9 +726,10 @@ bool RTLIL::Const::is_fully_def() const
|
|||
{
|
||||
cover("kernel.rtlil.const.is_fully_def");
|
||||
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
if (is_str())
|
||||
return true;
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
for (const auto &bit : bv)
|
||||
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
|
||||
return false;
|
||||
|
|
@ -669,9 +741,10 @@ bool RTLIL::Const::is_fully_undef() const
|
|||
{
|
||||
cover("kernel.rtlil.const.is_fully_undef");
|
||||
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
if (auto str = get_if_str())
|
||||
return str->empty();
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
for (const auto &bit : bv)
|
||||
if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz)
|
||||
return false;
|
||||
|
|
@ -683,9 +756,10 @@ bool RTLIL::Const::is_fully_undef_x_only() const
|
|||
{
|
||||
cover("kernel.rtlil.const.is_fully_undef_x_only");
|
||||
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
if (auto str = get_if_str())
|
||||
return str->empty();
|
||||
|
||||
const bitvectype& bv = get_bits();
|
||||
for (const auto &bit : bv)
|
||||
if (bit != RTLIL::State::Sx)
|
||||
return false;
|
||||
|
|
@ -697,12 +771,10 @@ bool RTLIL::Const::is_onehot(int *pos) const
|
|||
{
|
||||
cover("kernel.rtlil.const.is_onehot");
|
||||
|
||||
bitvectorize();
|
||||
bitvectype& bv = get_bits();
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < GetSize(*this); i++) {
|
||||
auto &bit = bv[i];
|
||||
int size = GetSize(*this);
|
||||
for (int i = 0; i < size; i++) {
|
||||
State bit = (*this)[i];
|
||||
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
|
||||
return false;
|
||||
if (bit == RTLIL::State::S1) {
|
||||
|
|
@ -716,6 +788,40 @@ bool RTLIL::Const::is_onehot(int *pos) const
|
|||
return found;
|
||||
}
|
||||
|
||||
Hasher RTLIL::Const::hash_into(Hasher h) const
|
||||
{
|
||||
if (auto str = get_if_str())
|
||||
return hashlib::hash_ops<std::string>::hash_into(*str, h);
|
||||
|
||||
// If the bits are all 0/1, hash packed bits using the string hash.
|
||||
// Otherwise hash the leading packed bits with the rest of the bits individually.
|
||||
const bitvectype &bv = get_bits();
|
||||
int size = GetSize(bv);
|
||||
std::string packed;
|
||||
int packed_size = (size + 7) >> 3;
|
||||
packed.resize(packed_size, 0);
|
||||
for (int bi = 0; bi < packed_size; ++bi) {
|
||||
char ch = 0;
|
||||
int end = std::min((bi + 1)*8, size);
|
||||
for (int i = bi*8; i < end; ++i) {
|
||||
RTLIL::State b = bv[i];
|
||||
if (b > RTLIL::State::S1) {
|
||||
// Hash the packed bits we've seen so far, plus the remaining bits.
|
||||
h = hashlib::hash_ops<std::string>::hash_into(packed, h);
|
||||
h = hashlib::hash_ops<char>::hash_into(ch, h);
|
||||
for (; i < size; ++i) {
|
||||
h = hashlib::hash_ops<RTLIL::State>::hash_into(bv[i], h);
|
||||
}
|
||||
h.eat(size);
|
||||
return h;
|
||||
}
|
||||
ch |= static_cast<int>(b) << (i & 7);
|
||||
}
|
||||
packed[packed_size - 1 - bi] = ch;
|
||||
}
|
||||
return hashlib::hash_ops<std::string>::hash_into(packed, h);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::Const::extract(int offset, int len, RTLIL::State padding) const {
|
||||
bitvectype ret_bv;
|
||||
ret_bv.reserve(len);
|
||||
|
|
@ -2361,6 +2467,19 @@ namespace {
|
|||
check_expected();
|
||||
return;
|
||||
}
|
||||
if (cell->type.in(ID($input_port))) {
|
||||
param(ID::WIDTH);
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
if (cell->type.in(ID($connect))) {
|
||||
param(ID::WIDTH);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::B, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Checklist for adding internal cell types
|
||||
* ========================================
|
||||
|
|
@ -2741,7 +2860,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell)
|
|||
log_assert(cells_.count(cell->name) != 0);
|
||||
log_assert(refcount_cells_ == 0);
|
||||
cells_.erase(cell->name);
|
||||
delete cell;
|
||||
if (design && design->flagBufferedNormalized && buf_norm_cell_queue.count(cell)) {
|
||||
cell->type.clear();
|
||||
cell->name.clear();
|
||||
pending_deleted_cells.insert(cell);
|
||||
} else {
|
||||
delete cell;
|
||||
}
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(RTLIL::Process *process)
|
||||
|
|
@ -2932,6 +3057,14 @@ void RTLIL::Module::fixup_ports()
|
|||
|
||||
std::sort(all_ports.begin(), all_ports.end(), fixup_ports_compare);
|
||||
|
||||
if (design && design->flagBufferedNormalized) {
|
||||
for (auto &w : wires_)
|
||||
if (w.second->driverCell_ && w.second->driverCell_->type == ID($input_port))
|
||||
buf_norm_wire_queue.insert(w.second);
|
||||
|
||||
buf_norm_wire_queue.insert(all_ports.begin(), all_ports.end());
|
||||
}
|
||||
|
||||
ports.clear();
|
||||
for (size_t i = 0; i < all_ports.size(); i++) {
|
||||
ports.push_back(all_ports[i]->name);
|
||||
|
|
@ -4097,190 +4230,7 @@ bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const
|
|||
return connections_.count(portname) != 0;
|
||||
}
|
||||
|
||||
void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
|
||||
{
|
||||
RTLIL::SigSpec signal;
|
||||
auto conn_it = connections_.find(portname);
|
||||
|
||||
if (conn_it != connections_.end())
|
||||
{
|
||||
for (auto mon : module->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (module->design)
|
||||
for (auto mon : module->design->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Unconnect %s.%s.%s\n", log_id(this->module), log_id(this), log_id(portname));
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
connections_.erase(conn_it);
|
||||
}
|
||||
}
|
||||
|
||||
void RTLIL::Design::bufNormalize(bool enable)
|
||||
{
|
||||
if (!enable)
|
||||
{
|
||||
if (!flagBufferedNormalized)
|
||||
return;
|
||||
|
||||
for (auto module : modules()) {
|
||||
module->bufNormQueue.clear();
|
||||
for (auto wire : module->wires()) {
|
||||
wire->driverCell_ = nullptr;
|
||||
wire->driverPort_ = IdString();
|
||||
}
|
||||
}
|
||||
|
||||
flagBufferedNormalized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flagBufferedNormalized)
|
||||
{
|
||||
for (auto module : modules())
|
||||
{
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (!cell->output(conn.first) || GetSize(conn.second) == 0)
|
||||
continue;
|
||||
if (conn.second.is_wire()) {
|
||||
Wire *wire = conn.second.as_wire();
|
||||
log_assert(wire->driverCell_ == nullptr);
|
||||
wire->driverCell_ = cell;
|
||||
wire->driverPort_ = conn.first;
|
||||
} else {
|
||||
pair<RTLIL::Cell*, RTLIL::IdString> key(cell, conn.first);
|
||||
module->bufNormQueue.insert(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flagBufferedNormalized = true;
|
||||
}
|
||||
|
||||
for (auto module : modules())
|
||||
module->bufNormalize();
|
||||
}
|
||||
|
||||
void RTLIL::Module::bufNormalize()
|
||||
{
|
||||
if (!design->flagBufferedNormalized)
|
||||
return;
|
||||
|
||||
while (GetSize(bufNormQueue) || !connections_.empty())
|
||||
{
|
||||
pool<pair<RTLIL::Cell*, RTLIL::IdString>> queue;
|
||||
bufNormQueue.swap(queue);
|
||||
|
||||
pool<Wire*> outWires;
|
||||
for (auto &conn : connections())
|
||||
for (auto &chunk : conn.first.chunks())
|
||||
if (chunk.wire) outWires.insert(chunk.wire);
|
||||
|
||||
SigMap sigmap(this);
|
||||
new_connections({});
|
||||
|
||||
Module *module = this; // SILIMATE: Improve the naming
|
||||
|
||||
for (auto &key : queue)
|
||||
{
|
||||
Cell *cell = key.first;
|
||||
const IdString &portname = key.second;
|
||||
const SigSpec &sig = cell->getPort(portname);
|
||||
if (GetSize(sig) == 0) continue;
|
||||
|
||||
if (sig.is_wire()) {
|
||||
Wire *wire = sig.as_wire();
|
||||
if (wire->driverCell_) {
|
||||
log_error("Conflict between %s %s in module %s\n",
|
||||
log_id(cell), log_id(wire->driverCell_), log_id(this));
|
||||
}
|
||||
log_assert(wire->driverCell_ == nullptr);
|
||||
wire->driverCell_ = cell;
|
||||
wire->driverPort_ = portname;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &chunk : sig.chunks())
|
||||
if (chunk.wire) outWires.insert(chunk.wire);
|
||||
|
||||
Wire *wire = addWire(NEW_ID2_SUFFIX(portname.str()), GetSize(sig)); // SILIMATE: Improve the naming
|
||||
sigmap.add(sig, wire);
|
||||
cell->setPort(portname, wire);
|
||||
|
||||
// FIXME: Move init attributes from old 'sig' to new 'wire'
|
||||
}
|
||||
|
||||
for (auto wire : outWires)
|
||||
{
|
||||
SigSpec outsig = wire, insig = sigmap(wire);
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
if (insig[i] == outsig[i])
|
||||
insig[i] = State::Sx;
|
||||
addBuf(NEW_ID4_SUFFIX("buf"), insig, outsig); // SILIMATE: Improve the naming
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
|
||||
{
|
||||
auto r = connections_.insert(portname);
|
||||
auto conn_it = r.first;
|
||||
if (!r.second && conn_it->second == signal)
|
||||
return;
|
||||
|
||||
for (auto mon : module->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (module->design)
|
||||
for (auto mon : module->design->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Connect %s.%s.%s = %s (%d)\n", log_id(this->module), log_id(this), log_id(portname), log_signal(signal), GetSize(signal));
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
while (module->design && module->design->flagBufferedNormalized && output(portname))
|
||||
{
|
||||
pair<RTLIL::Cell*, RTLIL::IdString> key(this, portname);
|
||||
|
||||
if (conn_it->second.is_wire()) {
|
||||
Wire *w = conn_it->second.as_wire();
|
||||
if (w->driverCell_ == this && w->driverPort_ == portname) {
|
||||
w->driverCell_ = nullptr;
|
||||
w->driverPort_ = IdString();
|
||||
}
|
||||
}
|
||||
|
||||
if (GetSize(signal) == 0) {
|
||||
module->bufNormQueue.erase(key);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!signal.is_wire()) {
|
||||
module->bufNormQueue.insert(key);
|
||||
break;
|
||||
}
|
||||
|
||||
Wire *w = signal.as_wire();
|
||||
if (w->driverCell_ != nullptr) {
|
||||
pair<RTLIL::Cell*, RTLIL::IdString> other_key(w->driverCell_, w->driverPort_);
|
||||
module->bufNormQueue.insert(other_key);
|
||||
}
|
||||
w->driverCell_ = this;
|
||||
w->driverPort_ = portname;
|
||||
|
||||
module->bufNormQueue.erase(key);
|
||||
break;
|
||||
}
|
||||
|
||||
conn_it->second = std::move(signal);
|
||||
}
|
||||
// bufnorm
|
||||
|
||||
const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const
|
||||
{
|
||||
|
|
@ -4325,6 +4275,22 @@ bool RTLIL::Cell::output(const RTLIL::IdString& portname) const
|
|||
return false;
|
||||
}
|
||||
|
||||
RTLIL::PortDir RTLIL::Cell::port_dir(const RTLIL::IdString& portname) const
|
||||
{
|
||||
if (yosys_celltypes.cell_known(type))
|
||||
return yosys_celltypes.cell_port_dir(type, portname);
|
||||
if (module && module->design) {
|
||||
RTLIL::Module *m = module->design->module(type);
|
||||
if (m == nullptr)
|
||||
return PortDir::PD_UNKNOWN;
|
||||
RTLIL::Wire *w = m->wire(portname);
|
||||
if (w == nullptr)
|
||||
return PortDir::PD_UNKNOWN;
|
||||
return PortDir(w->port_input + w->port_output * 2);
|
||||
}
|
||||
return PortDir::PD_UNKNOWN;
|
||||
}
|
||||
|
||||
bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const
|
||||
{
|
||||
return parameters.count(paramname) != 0;
|
||||
|
|
@ -4454,6 +4420,10 @@ bool RTLIL::Cell::is_mem_cell() const
|
|||
return type.in(ID($mem), ID($mem_v2)) || has_memid();
|
||||
}
|
||||
|
||||
bool RTLIL::Cell::is_builtin_ff() const {
|
||||
return builtin_ff_cell_types_internal().count(type) > 0;
|
||||
}
|
||||
|
||||
RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
|
||||
{
|
||||
wire = bit.wire;
|
||||
|
|
@ -5479,6 +5449,15 @@ bool RTLIL::SigSpec::is_mostly_const() const
|
|||
return (constbits > width_/2);
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::known_driver() const
|
||||
{
|
||||
pack();
|
||||
for (auto &chunk : chunks_)
|
||||
if (chunk.is_wire() && !chunk.wire->known_driver())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::is_fully_const() const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.is_fully_const");
|
||||
|
|
@ -5561,6 +5540,18 @@ bool RTLIL::SigSpec::has_const() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::has_const(State state) const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.has_const");
|
||||
|
||||
pack();
|
||||
for (auto it = chunks_.begin(); it != chunks_.end(); it++)
|
||||
if (it->width > 0 && it->wire == NULL && std::find(it->data.begin(), it->data.end(), state) != it->data.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool RTLIL::SigSpec::has_marked_bits() const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.has_marked_bits");
|
||||
|
|
@ -5943,7 +5934,11 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R
|
|||
}
|
||||
}
|
||||
|
||||
return parse(sig, module, str);
|
||||
if (!parse(sig, module, str))
|
||||
return false;
|
||||
if (sig.width_ > lhs.width_)
|
||||
sig.remove(lhs.width_, sig.width_ - lhs.width_);
|
||||
return true;
|
||||
}
|
||||
|
||||
RTLIL::CaseRule::~CaseRule()
|
||||
|
|
|
|||
158
kernel/rtlil.h
158
kernel/rtlil.h
|
|
@ -91,6 +91,13 @@ namespace RTLIL
|
|||
STATIC_ID_END,
|
||||
};
|
||||
|
||||
enum PortDir : unsigned char {
|
||||
PD_UNKNOWN = 0,
|
||||
PD_INPUT = 1,
|
||||
PD_OUTPUT = 2,
|
||||
PD_INOUT = 3
|
||||
};
|
||||
|
||||
struct Const;
|
||||
struct AttrObject;
|
||||
struct NamedObject;
|
||||
|
|
@ -557,6 +564,7 @@ template <> struct IDMacroHelper<-1> {
|
|||
namespace RTLIL {
|
||||
extern dict<std::string, std::string> constpad;
|
||||
|
||||
[[deprecated("Call cell->is_builtin_ff() instead")]]
|
||||
const pool<IdString> &builtin_ff_cell_types();
|
||||
|
||||
static inline std::string escape_id(const std::string &str) {
|
||||
|
|
@ -829,38 +837,61 @@ private:
|
|||
using bitvectype = std::vector<RTLIL::State>;
|
||||
enum class backing_tag: bool { bits, string };
|
||||
// Do not access the union or tag even in Const methods unless necessary
|
||||
mutable backing_tag tag;
|
||||
backing_tag tag;
|
||||
union {
|
||||
mutable bitvectype bits_;
|
||||
mutable std::string str_;
|
||||
bitvectype bits_;
|
||||
std::string str_;
|
||||
};
|
||||
|
||||
// Use these private utilities instead
|
||||
bool is_bits() const { return tag == backing_tag::bits; }
|
||||
bool is_str() const { return tag == backing_tag::string; }
|
||||
|
||||
bitvectype* get_if_bits() const { return is_bits() ? &bits_ : NULL; }
|
||||
std::string* get_if_str() const { return is_str() ? &str_ : NULL; }
|
||||
bitvectype* get_if_bits() { return is_bits() ? &bits_ : NULL; }
|
||||
std::string* get_if_str() { return is_str() ? &str_ : NULL; }
|
||||
const bitvectype* get_if_bits() const { return is_bits() ? &bits_ : NULL; }
|
||||
const std::string* get_if_str() const { return is_str() ? &str_ : NULL; }
|
||||
|
||||
bitvectype& get_bits();
|
||||
std::string& get_str();
|
||||
const bitvectype& get_bits() const;
|
||||
const std::string& get_str() const;
|
||||
std::vector<RTLIL::State>& bits_internal();
|
||||
void bitvectorize_internal();
|
||||
|
||||
bitvectype& get_bits() const;
|
||||
std::string& get_str() const;
|
||||
public:
|
||||
Const() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector<RTLIL::State>()) {}
|
||||
Const(const std::string &str);
|
||||
Const(int val, int width = 32);
|
||||
Const(long long val); // default width is 32
|
||||
Const(long long val, int width);
|
||||
Const(RTLIL::State bit, int width = 1);
|
||||
Const(const std::vector<RTLIL::State> &bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(bits) {}
|
||||
Const(std::vector<RTLIL::State> bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::move(bits)) {}
|
||||
Const(const std::vector<bool> &bits);
|
||||
Const(const RTLIL::Const &other);
|
||||
Const(RTLIL::Const &&other);
|
||||
RTLIL::Const &operator =(const RTLIL::Const &other);
|
||||
~Const();
|
||||
|
||||
struct Builder
|
||||
{
|
||||
Builder() {}
|
||||
Builder(int expected_width) { bits.reserve(expected_width); }
|
||||
void push_back(RTLIL::State b) { bits.push_back(b); }
|
||||
int size() const { return static_cast<int>(bits.size()); }
|
||||
Const build() { return Const(std::move(bits)); }
|
||||
private:
|
||||
std::vector<RTLIL::State> bits;
|
||||
};
|
||||
|
||||
bool operator <(const RTLIL::Const &other) const;
|
||||
bool operator ==(const RTLIL::Const &other) const;
|
||||
bool operator !=(const RTLIL::Const &other) const;
|
||||
|
||||
std::vector<RTLIL::State>& bits();
|
||||
[[deprecated("Don't use direct access to the internal std::vector<State>, that's an implementation detail.")]]
|
||||
std::vector<RTLIL::State>& bits() { return bits_internal(); }
|
||||
[[deprecated("Don't call bitvectorize() directly, it's an implementation detail.")]]
|
||||
void bitvectorize() const { const_cast<Const*>(this)->bitvectorize_internal(); }
|
||||
|
||||
bool as_bool() const;
|
||||
|
||||
// Convert the constant value to a C++ int.
|
||||
|
|
@ -889,37 +920,42 @@ public:
|
|||
std::string decode_string() const;
|
||||
int size() const;
|
||||
bool empty() const;
|
||||
void bitvectorize() const;
|
||||
|
||||
void append(const RTLIL::Const &other);
|
||||
void set(int i, RTLIL::State state) {
|
||||
bits_internal()[i] = state;
|
||||
}
|
||||
void resize(int size, RTLIL::State fill) {
|
||||
bits_internal().resize(size, fill);
|
||||
}
|
||||
|
||||
class const_iterator {
|
||||
private:
|
||||
const Const& parent;
|
||||
const Const* parent;
|
||||
size_t idx;
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = State;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const State*;
|
||||
using reference = const State&;
|
||||
|
||||
const_iterator(const Const& c, size_t i) : parent(c), idx(i) {}
|
||||
const_iterator(const Const& c, size_t i) : parent(&c), idx(i) {}
|
||||
|
||||
State operator*() const;
|
||||
|
||||
const_iterator& operator++() { ++idx; return *this; }
|
||||
const_iterator& operator--() { --idx; return *this; }
|
||||
const_iterator& operator++(int) { ++idx; return *this; }
|
||||
const_iterator& operator--(int) { --idx; return *this; }
|
||||
const_iterator operator++(int) { const_iterator result(*this); ++idx; return result; }
|
||||
const_iterator operator--(int) { const_iterator result(*this); --idx; return result; }
|
||||
const_iterator& operator+=(int i) { idx += i; return *this; }
|
||||
|
||||
const_iterator operator+(int add) {
|
||||
return const_iterator(parent, idx + add);
|
||||
return const_iterator(*parent, idx + add);
|
||||
}
|
||||
const_iterator operator-(int sub) {
|
||||
return const_iterator(parent, idx - sub);
|
||||
return const_iterator(*parent, idx - sub);
|
||||
}
|
||||
int operator-(const const_iterator& other) {
|
||||
return idx - other.idx;
|
||||
|
|
@ -934,12 +970,69 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class iterator {
|
||||
private:
|
||||
Const* parent;
|
||||
size_t idx;
|
||||
|
||||
public:
|
||||
class proxy {
|
||||
private:
|
||||
Const* parent;
|
||||
size_t idx;
|
||||
public:
|
||||
proxy(Const* parent, size_t idx) : parent(parent), idx(idx) {}
|
||||
operator State() const { return (*parent)[idx]; }
|
||||
proxy& operator=(State s) { parent->set(idx, s); return *this; }
|
||||
proxy& operator=(const proxy& other) { parent->set(idx, (*other.parent)[other.idx]); return *this; }
|
||||
};
|
||||
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = State;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = proxy*;
|
||||
using reference = proxy;
|
||||
|
||||
iterator(Const& c, size_t i) : parent(&c), idx(i) {}
|
||||
|
||||
proxy operator*() const { return proxy(parent, idx); }
|
||||
iterator& operator++() { ++idx; return *this; }
|
||||
iterator& operator--() { --idx; return *this; }
|
||||
iterator operator++(int) { iterator result(*this); ++idx; return result; }
|
||||
iterator operator--(int) { iterator result(*this); --idx; return result; }
|
||||
iterator& operator+=(int i) { idx += i; return *this; }
|
||||
|
||||
iterator operator+(int add) {
|
||||
return iterator(*parent, idx + add);
|
||||
}
|
||||
iterator operator-(int sub) {
|
||||
return iterator(*parent, idx - sub);
|
||||
}
|
||||
int operator-(const iterator& other) {
|
||||
return idx - other.idx;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& other) const {
|
||||
return idx == other.idx;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(*this, 0);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(*this, size());
|
||||
}
|
||||
iterator begin() {
|
||||
return iterator(*this, 0);
|
||||
}
|
||||
iterator end() {
|
||||
return iterator(*this, size());
|
||||
}
|
||||
State back() const {
|
||||
return *(end() - 1);
|
||||
}
|
||||
|
|
@ -971,20 +1064,14 @@ public:
|
|||
std::optional<int> as_int_compress(bool is_signed) const;
|
||||
|
||||
void extu(int width) {
|
||||
bits().resize(width, RTLIL::State::S0);
|
||||
resize(width, RTLIL::State::S0);
|
||||
}
|
||||
|
||||
void exts(int width) {
|
||||
bitvectype& bv = bits();
|
||||
bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());
|
||||
resize(width, empty() ? RTLIL::State::Sx : back());
|
||||
}
|
||||
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(size());
|
||||
for (auto b : *this)
|
||||
h.eat(b);
|
||||
return h;
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
struct RTLIL::AttrObject
|
||||
|
|
@ -1040,7 +1127,8 @@ struct RTLIL::SigChunk
|
|||
SigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {}
|
||||
SigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {}
|
||||
SigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {}
|
||||
SigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {}
|
||||
SigChunk(int val) /*default width 32*/ : SigChunk(RTLIL::Const(val)) {}
|
||||
SigChunk(int val, int width) : SigChunk(RTLIL::Const(val, width)) {}
|
||||
SigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {}
|
||||
SigChunk(const RTLIL::SigBit &bit);
|
||||
|
||||
|
|
@ -1250,12 +1338,16 @@ public:
|
|||
inline bool is_bit() const { return width_ == 1; }
|
||||
|
||||
bool is_mostly_const() const;
|
||||
|
||||
bool known_driver() const;
|
||||
|
||||
bool is_fully_const() const;
|
||||
bool is_fully_zero() const;
|
||||
bool is_fully_ones() const;
|
||||
bool is_fully_def() const;
|
||||
bool is_fully_undef() const;
|
||||
bool has_const() const;
|
||||
bool has_const(State state) const;
|
||||
bool has_marked_bits() const;
|
||||
bool is_onehot(int *pos = nullptr) const;
|
||||
|
||||
|
|
@ -1651,7 +1743,11 @@ public:
|
|||
std::vector<RTLIL::IdString> ports;
|
||||
void fixup_ports();
|
||||
|
||||
pool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;
|
||||
pool<RTLIL::Cell *> buf_norm_cell_queue;
|
||||
pool<pair<RTLIL::Cell *, RTLIL::IdString>> buf_norm_cell_port_queue;
|
||||
pool<RTLIL::Wire *> buf_norm_wire_queue;
|
||||
pool<RTLIL::Cell *> pending_deleted_cells;
|
||||
dict<RTLIL::Wire *, pool<RTLIL::Cell *>> buf_norm_connect_index;
|
||||
void bufNormalize();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
|
|
@ -1987,6 +2083,8 @@ public:
|
|||
int width, start_offset, port_id;
|
||||
bool port_input, port_output, upto, is_signed;
|
||||
|
||||
bool known_driver() const { return driverCell_ != nullptr; }
|
||||
|
||||
RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };
|
||||
RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };
|
||||
|
||||
|
|
@ -2058,6 +2156,7 @@ public:
|
|||
bool known() const;
|
||||
bool input(const RTLIL::IdString &portname) const;
|
||||
bool output(const RTLIL::IdString &portname) const;
|
||||
PortDir port_dir(const RTLIL::IdString &portname) const;
|
||||
|
||||
// access cell parameters
|
||||
bool hasParam(const RTLIL::IdString ¶mname) const;
|
||||
|
|
@ -2083,6 +2182,7 @@ public:
|
|||
|
||||
bool has_memid() const;
|
||||
bool is_mem_cell() const;
|
||||
bool is_builtin_ff() const;
|
||||
};
|
||||
|
||||
struct RTLIL::CaseRule : public RTLIL::AttrObject
|
||||
|
|
|
|||
679
kernel/rtlil_bufnorm.cc
Normal file
679
kernel/rtlil_bufnorm.cc
Normal file
|
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
*
|
||||
* 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/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/modtools.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
void RTLIL::Design::bufNormalize(bool enable)
|
||||
{
|
||||
if (!enable)
|
||||
{
|
||||
if (!flagBufferedNormalized)
|
||||
return;
|
||||
|
||||
for (auto module : modules()) {
|
||||
module->buf_norm_cell_queue.clear();
|
||||
module->buf_norm_wire_queue.clear();
|
||||
module->buf_norm_cell_port_queue.clear();
|
||||
for (auto wire : module->wires()) {
|
||||
wire->driverCell_ = nullptr;
|
||||
wire->driverPort_ = IdString();
|
||||
}
|
||||
}
|
||||
|
||||
flagBufferedNormalized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flagBufferedNormalized)
|
||||
{
|
||||
for (auto module : modules())
|
||||
{
|
||||
// When entering buf normalized mode, we need the first module-level bufNormalize
|
||||
// call to know about all drivers, about all module ports (whether represented by
|
||||
// a cell or not) and about all used but undriven wires (whether represented by a
|
||||
// cell or not). We ensure this by enqueing all cell output ports and all wires.
|
||||
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT))
|
||||
continue;
|
||||
module->buf_norm_cell_queue.insert(cell);
|
||||
module->buf_norm_cell_port_queue.emplace(cell, conn.first);
|
||||
}
|
||||
for (auto wire : module->wires())
|
||||
module->buf_norm_wire_queue.insert(wire);
|
||||
|
||||
}
|
||||
|
||||
flagBufferedNormalized = true;
|
||||
}
|
||||
|
||||
for (auto module : modules())
|
||||
module->bufNormalize();
|
||||
}
|
||||
|
||||
struct bit_drive_data_t {
|
||||
int drivers = 0;
|
||||
int inout = 0;
|
||||
int users = 0;
|
||||
};
|
||||
|
||||
typedef ModWalker::PortBit PortBit;
|
||||
|
||||
void RTLIL::Module::bufNormalize()
|
||||
{
|
||||
// Since this is kernel code, we only log with yosys_xtrace set to not get
|
||||
// in the way when using `debug` to debug specific passes.q
|
||||
#define xlog(...) do { if (yosys_xtrace) log("#X [bufnorm] " __VA_ARGS__); } while (0)
|
||||
|
||||
if (!design->flagBufferedNormalized)
|
||||
return;
|
||||
|
||||
if (!buf_norm_cell_queue.empty() || !buf_norm_wire_queue.empty() || !connections_.empty())
|
||||
{
|
||||
// Ensure that every enqueued input port is represented by a cell
|
||||
for (auto wire : buf_norm_wire_queue) {
|
||||
if (wire->port_input && !wire->port_output) {
|
||||
if (wire->driverCell_ != nullptr && wire->driverCell_->type != ID($input_port)) {
|
||||
wire->driverCell_ = nullptr;
|
||||
wire->driverPort_.clear();
|
||||
}
|
||||
if (wire->driverCell_ == nullptr) {
|
||||
Cell *input_port_cell = addCell(NEW_ID, ID($input_port));
|
||||
input_port_cell->setParam(ID::WIDTH, GetSize(wire));
|
||||
input_port_cell->setPort(ID::Y, wire); // this hits the fast path that doesn't mutate the queues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next we will temporarily undo buf normalization locally for
|
||||
// everything enqueued. This means we will turn $buf and $connect back
|
||||
// into connections. When doing this we also need to enqueue the other
|
||||
// end of $buf and $connect cells, so we use a queue and do this until
|
||||
// reaching a fixed point.
|
||||
|
||||
// While doing this, we will also discover all drivers fully connected
|
||||
// to enqueued wires. We keep track of which wires are driven by a
|
||||
// unique and full cell ports (in which case the wire can stay
|
||||
// connected to the port) and which cell ports will need to be
|
||||
// reconnected to a fresh intermediate wire to re-normalize the module.
|
||||
|
||||
idict<Wire *> wire_queue_entries; // Ordered queue of wires to process
|
||||
int wire_queue_pos = 0; // Index up to which we processed the wires
|
||||
|
||||
// Wires with their unique driving cell port. If we know a wire is
|
||||
// driven by multiple (potential) drivers, this is indicated by a
|
||||
// nullptr as cell.
|
||||
dict<Wire *, std::pair<Cell *, IdString>> direct_driven_wires;
|
||||
|
||||
// Set of non-unique or driving cell ports for each processed wire.
|
||||
dict<Wire *, pool<std::pair<Cell *, IdString>>> direct_driven_wires_conflicts;
|
||||
|
||||
// Set of cell ports that need a fresh intermediate wire.
|
||||
pool<std::pair<Cell *, IdString>> pending_ports;
|
||||
|
||||
// This helper will be called for every output/inout cell port that is
|
||||
// already enqueued or becomes reachable when denormalizing $buf or
|
||||
// $connect cells.
|
||||
auto enqueue_cell_port = [&](Cell *cell, IdString port) {
|
||||
xlog("processing cell port %s.%s\n", log_id(cell), log_id(port));
|
||||
|
||||
// An empty cell type means the cell got removed
|
||||
if (cell->type.empty())
|
||||
return;
|
||||
|
||||
|
||||
SigSpec const &sig = cell->getPort(port);
|
||||
if (cell->type == ID($input_port)) {
|
||||
// If an `$input_port` cell isn't fully connected to a full
|
||||
// input port wire, we remove it since the wires are still the
|
||||
// canonical source of module ports and the `$input_port` cells
|
||||
// are just helpers to simplfiy the bufnorm invariant.
|
||||
log_assert(port == ID::Y);
|
||||
if (!sig.is_wire()) {
|
||||
buf_norm_cell_queue.insert(cell);
|
||||
remove(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
Wire *w = sig.as_wire();
|
||||
if (!w->port_input || w->port_output) {
|
||||
buf_norm_cell_queue.insert(cell);
|
||||
remove(cell);
|
||||
return;
|
||||
}
|
||||
w->driverCell_ = cell;
|
||||
w->driverPort_ = ID::Y;
|
||||
} else if (cell->type == ID($buf) && cell->attributes.empty() && !cell->name.isPublic()) {
|
||||
// For a plain `$buf` cell, we enqueue all wires on its input
|
||||
// side, bypass it using module level connections (skipping 'z
|
||||
// bits) and then remove the cell. Eventually the module level
|
||||
// connections will turn back into `$buf` and `$connect` cells,
|
||||
// but since we also need to handle externally added module
|
||||
// level connections, turning everything into connections first
|
||||
// simplifies the logic for doing so.
|
||||
|
||||
// TODO: We could defer removing the $buf cells here, and
|
||||
// re-use them in case we would create a new identical cell
|
||||
// later.
|
||||
log_assert(port == ID::Y);
|
||||
SigSpec sig_a = cell->getPort(ID::A);
|
||||
SigSpec sig_y = sig;
|
||||
|
||||
for (auto const &s : {sig_a, sig})
|
||||
for (auto const &chunk : s.chunks())
|
||||
if (chunk.wire)
|
||||
wire_queue_entries(chunk.wire);
|
||||
|
||||
if (sig_a.has_const(State::Sz)) {
|
||||
SigSpec new_a;
|
||||
SigSpec new_y;
|
||||
for (int i = 0; i < GetSize(sig_a); ++i) {
|
||||
SigBit b = sig_a[i];
|
||||
if (b == State::Sz)
|
||||
continue;
|
||||
new_a.append(b);
|
||||
new_y.append(sig_y[i]);
|
||||
}
|
||||
sig_a = std::move(new_a);
|
||||
sig_y = std::move(new_y);
|
||||
}
|
||||
|
||||
if (!sig_y.empty())
|
||||
connect(sig_y, sig_a);
|
||||
buf_norm_cell_queue.insert(cell);
|
||||
remove(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure all wires of the cell port are enqueued, ensuring we
|
||||
// detect other connected drivers (output and inout).
|
||||
for (auto const &chunk : sig.chunks())
|
||||
if (chunk.wire)
|
||||
wire_queue_entries(chunk.wire);
|
||||
|
||||
if (sig.is_wire()) {
|
||||
// If the full cell port is connected to a full wire, we might be
|
||||
// able to keep that connection if this is a unique output port driving that wire
|
||||
Wire *w = sig.as_wire();
|
||||
|
||||
// We try to store the current port as unique driver, if this
|
||||
// succeeds we're done with the port.
|
||||
auto [found, inserted] = direct_driven_wires.emplace(w, {cell, port});
|
||||
if (inserted || (found->second.first == cell && found->second.second == port))
|
||||
return;
|
||||
|
||||
// When this failed, we store this port as a conflict. If we
|
||||
// had already stored a candidate for a unique driver, we also
|
||||
// move it to the conflicts, leaving a nullptr marker.
|
||||
|
||||
auto &conflicts = direct_driven_wires_conflicts[w];
|
||||
if (Cell *other_cell = found->second.first) {
|
||||
if (other_cell->type == ID($input_port)) {
|
||||
// Multiple input port cells
|
||||
log_assert(cell->type != ID($input_port));
|
||||
} else {
|
||||
pending_ports.insert(found->second);
|
||||
conflicts.emplace(found->second);
|
||||
found->second = {nullptr, {}};
|
||||
}
|
||||
}
|
||||
if (cell->type == ID($input_port)) {
|
||||
found->second = {cell, port};
|
||||
} else {
|
||||
conflicts.emplace(cell, port);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds this port to the ports that need a fresh intermediate wire.
|
||||
// For full wires uniquely driven by a full output port, this isn't
|
||||
// reached due to the `return` above.
|
||||
pending_ports.emplace(cell, port);
|
||||
};
|
||||
|
||||
// We process all explicitly enqueued cell ports (clearing the module level queue).
|
||||
for (auto const &[cell, port_name] : buf_norm_cell_port_queue)
|
||||
enqueue_cell_port(cell, port_name);
|
||||
buf_norm_cell_port_queue.clear();
|
||||
|
||||
// And enqueue all wires for `$buf`/`$connect` processing (clearing the module level queue).
|
||||
for (auto wire : buf_norm_wire_queue)
|
||||
wire_queue_entries(wire);
|
||||
buf_norm_wire_queue.clear();
|
||||
|
||||
// We also enqueue all wires that saw newly added module level connections.
|
||||
for (auto &[a, b] : connections_)
|
||||
for (auto &sig : {a, b})
|
||||
for (auto const &chunk : sig.chunks())
|
||||
if (chunk.wire)
|
||||
wire_queue_entries(chunk.wire);
|
||||
|
||||
// We then process all wires by processing known driving cell ports
|
||||
// (previously buf normalized) and following all `$connect` cells (that
|
||||
// have a dedicated module level index while the design is in buf
|
||||
// normalized mode).
|
||||
while (wire_queue_pos < GetSize(wire_queue_entries)) {
|
||||
auto wire = wire_queue_entries[wire_queue_pos++];
|
||||
xlog("processing wire %s\n", log_id(wire));
|
||||
|
||||
if (wire->driverCell_) {
|
||||
Cell *cell = wire->driverCell_;
|
||||
IdString port = wire->driverPort_;
|
||||
enqueue_cell_port(cell, port);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto found = buf_norm_connect_index.find(wire);
|
||||
if (found == buf_norm_connect_index.end())
|
||||
break;
|
||||
while (!found->second.empty()) {
|
||||
Cell *connect_cell = *found->second.begin();
|
||||
log_assert(connect_cell->type == ID($connect));
|
||||
SigSpec const &sig_a = connect_cell->getPort(ID::A);
|
||||
SigSpec const &sig_b = connect_cell->getPort(ID::B);
|
||||
xlog("found $connect cell %s: %s <-> %s\n", log_id(connect_cell), log_signal(sig_a), log_signal(sig_b));
|
||||
for (auto &side : {sig_a, sig_b})
|
||||
for (auto chunk : side.chunks())
|
||||
if (chunk.wire)
|
||||
wire_queue_entries(chunk.wire);
|
||||
connect(sig_a, sig_b);
|
||||
buf_norm_cell_queue.insert(connect_cell);
|
||||
remove(connect_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we know all cell ports and wires that need to be
|
||||
// re-normalized and know their connectivity is represented by module
|
||||
// level connections.
|
||||
|
||||
// As a first step for re-normalization we add all require intermediate
|
||||
// wires for cell output and inout ports.
|
||||
for (auto &[cell, port] : pending_ports) {
|
||||
SigSpec const &sig = cell->getPort(port);
|
||||
Wire *w = addWire(NEW_ID, GetSize(sig));
|
||||
|
||||
// We update the module level connections, `direct_driven_wires`
|
||||
// and `direct_driven_wires_conflicts` in such a way that they
|
||||
// correspond to what you would get if the intermediate wires had
|
||||
// been in place from the beginning.
|
||||
connect(sig, w);
|
||||
auto port_dir = cell->port_dir(port);
|
||||
if (port_dir == RTLIL::PD_INOUT || port_dir == RTLIL::PD_UNKNOWN) {
|
||||
direct_driven_wires.emplace(w, {nullptr, {}});
|
||||
direct_driven_wires_conflicts[w].emplace(cell, port);
|
||||
} else {
|
||||
direct_driven_wires.emplace(w, {cell, port});
|
||||
}
|
||||
|
||||
cell->setPort(port, w);
|
||||
wire_queue_entries(w);
|
||||
}
|
||||
|
||||
// At this point we're done with creating wires and know which ones are
|
||||
// fully driven by full output ports of existing cells.
|
||||
|
||||
// First we clear the bufnorm data for all processed wires, all of
|
||||
// these will be reassigned later, but we use `driverCell_ == nullptr`
|
||||
// to keep track of the wires that we still have to update.
|
||||
for (auto wire : wire_queue_entries) {
|
||||
wire->driverCell_ = nullptr;
|
||||
wire->driverPort_.clear();
|
||||
}
|
||||
|
||||
// For the unique output cell ports fully connected to a full wire, we
|
||||
// can update the bufnorm data right away. For all other wires we will
|
||||
// have to create new `$buf` cells.
|
||||
for (auto const &[wire, cellport] : direct_driven_wires) {
|
||||
wire->driverCell_ = cellport.first;
|
||||
wire->driverPort_ = cellport.second;
|
||||
}
|
||||
|
||||
|
||||
// To create fresh `$buf` cells for all remaining wires, we need to
|
||||
// process the module level connectivity to figure out what the input
|
||||
// of those `$buf` cells should be and to figure out whether we need
|
||||
// any `$connect` cells to represent bidirectional inout connections
|
||||
// (or driver conflicts).
|
||||
|
||||
if (yosys_xtrace)
|
||||
for (auto const &[lhs, rhs] : connections_)
|
||||
xlog("connection %s <-> %s\n", log_signal(lhs), log_signal(rhs));
|
||||
|
||||
|
||||
// We transfer the connectivity into a sigmap and then clear the module
|
||||
// level connections. This forgets about the structure of module level
|
||||
// connections, but bufnorm only guarantees that the connectivity as
|
||||
// maintained by a `SigMap` is preserved.
|
||||
SigMap sigmap(this);
|
||||
new_connections({});
|
||||
|
||||
pool<SigBit> conflicted;
|
||||
pool<SigBit> driven;
|
||||
|
||||
// We iterate over all direct driven wires and try to make that wire's
|
||||
// sigbits the representative sigbit for the net. We do a second pass
|
||||
// to detect conflicts to then remove the conflicts from `driven`.
|
||||
for (bool check : {false, true}) {
|
||||
for (auto const &[wire, cellport] : direct_driven_wires) {
|
||||
if (cellport.first == nullptr)
|
||||
continue;
|
||||
auto const &[cell, port] = cellport;
|
||||
|
||||
SigSpec z_mask;
|
||||
if (cell->type == ID($buf))
|
||||
z_mask = cell->getPort(ID::A);
|
||||
|
||||
for (int i = 0; i != GetSize(wire); ++i) {
|
||||
SigBit driver = SigBit(wire, i);
|
||||
if (!z_mask.empty() && z_mask[i] == State::Sz)
|
||||
continue;
|
||||
if (check) {
|
||||
SigBit repr = sigmap(driver);
|
||||
if (repr != driver)
|
||||
conflicted.insert(repr);
|
||||
else
|
||||
driven.insert(repr);
|
||||
} else {
|
||||
sigmap.database.promote(driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that module level inout ports are directly driven or
|
||||
// connected using `$connect` cells and never `$buf`fered.
|
||||
for (auto wire : wire_queue_entries) {
|
||||
if (!wire->port_input || !wire->port_output)
|
||||
continue;
|
||||
for (int i = 0; i != GetSize(wire); ++i) {
|
||||
SigBit driver = SigBit(wire, i);
|
||||
SigBit repr = sigmap(driver);
|
||||
if (driver != repr)
|
||||
driven.erase(repr);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &bit : conflicted)
|
||||
driven.erase(bit);
|
||||
|
||||
// Module level bitwise connections not representable by `$buf` cells
|
||||
pool<pair<SigBit, SigBit>> undirected_connections;
|
||||
|
||||
// Starts out empty but is updated with the connectivity realized by freshly added `$buf` cells
|
||||
SigMap buf_connected;
|
||||
|
||||
// For every enqueued wire, we compute a SigSpec of representative
|
||||
// drivers. If there are any bits without a unique driver we represent
|
||||
// that with `Sz`. If there are multiple drivers for a net, they become
|
||||
// connected via `$connect` cells but every wire of the net has the
|
||||
// corresponding bit still driven by a buffered `Sz`.
|
||||
for (auto wire : wire_queue_entries) {
|
||||
SigSpec wire_drivers;
|
||||
for (int i = 0; i < GetSize(wire); ++i) {
|
||||
SigBit bit(wire, i);
|
||||
SigBit mapped = sigmap(bit);
|
||||
xlog("bit %s -> mapped %s\n", log_signal(bit), log_signal(mapped));
|
||||
|
||||
|
||||
buf_connected.apply(bit);
|
||||
buf_connected.add(bit, mapped);
|
||||
buf_connected.database.promote(mapped);
|
||||
|
||||
if (wire->driverCell_ == nullptr) {
|
||||
if (!mapped.is_wire() || driven.count(mapped)) {
|
||||
wire_drivers.append(mapped);
|
||||
continue;
|
||||
} else {
|
||||
wire_drivers.append(State::Sz);
|
||||
}
|
||||
}
|
||||
|
||||
if (bit < mapped)
|
||||
undirected_connections.emplace(bit, mapped);
|
||||
else if (mapped < bit)
|
||||
undirected_connections.emplace(mapped, bit);
|
||||
}
|
||||
|
||||
if (wire->driverCell_ == nullptr) {
|
||||
xlog("wire %s drivers %s\n", log_id(wire), log_signal(wire_drivers));
|
||||
addBuf(NEW_ID, wire_drivers, wire);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we group the bitwise connections to emit word-level $connect cells
|
||||
|
||||
static auto sort_key = [](std::pair<SigBit, SigBit> const &p) {
|
||||
int first_offset = p.first.is_wire() ? p.first.offset : 0;
|
||||
int second_offset = p.second.is_wire() ? p.second.offset : 0;
|
||||
return std::make_tuple(p.first.wire, p.second.wire, first_offset - second_offset, p);
|
||||
};
|
||||
|
||||
undirected_connections.sort([](std::pair<SigBit, SigBit> const &p, std::pair<SigBit, SigBit> const &q) {
|
||||
return sort_key(p) < sort_key(q);
|
||||
});
|
||||
|
||||
SigSpec tmp_a, tmp_b;
|
||||
|
||||
for (auto &[bit_a, bit_b] : undirected_connections) {
|
||||
tmp_a.append(bit_a);
|
||||
tmp_b.append(bit_b);
|
||||
}
|
||||
|
||||
xlog("LHS: %s\n", log_signal(tmp_a));
|
||||
xlog("RHS: %s\n", log_signal(tmp_b));
|
||||
|
||||
|
||||
SigSpec sig_a, sig_b;
|
||||
SigBit next_a, next_b;
|
||||
|
||||
auto emit_connect_cell = [&]() {
|
||||
if (sig_a.empty())
|
||||
return;
|
||||
xlog("connect %s <-> %s\n", log_signal(sig_a), log_signal(sig_b));
|
||||
Cell *connect_cell = addCell(NEW_ID, ID($connect));
|
||||
connect_cell->setParam(ID::WIDTH, GetSize(sig_a));
|
||||
connect_cell->setPort(ID::A, sig_a);
|
||||
connect_cell->setPort(ID::B, sig_b);
|
||||
sig_a = SigSpec();
|
||||
sig_b = SigSpec();
|
||||
};
|
||||
|
||||
for (auto &[bit_a, bit_b] : undirected_connections) {
|
||||
if (bit_a == bit_b)
|
||||
continue;
|
||||
if (bit_a != next_a || bit_b != next_b)
|
||||
emit_connect_cell();
|
||||
|
||||
sig_a.append(bit_a);
|
||||
sig_b.append(bit_b);
|
||||
next_a = bit_a;
|
||||
next_b = bit_b;
|
||||
if (next_a.is_wire())
|
||||
next_a.offset++;
|
||||
if (next_b.is_wire())
|
||||
next_b.offset++;
|
||||
|
||||
}
|
||||
emit_connect_cell();
|
||||
|
||||
buf_norm_cell_queue.clear();
|
||||
|
||||
log_assert(buf_norm_cell_port_queue.empty());
|
||||
log_assert(buf_norm_wire_queue.empty());
|
||||
log_assert(connections_.empty());
|
||||
}
|
||||
|
||||
for (auto cell : pending_deleted_cells) {
|
||||
delete cell;
|
||||
}
|
||||
pending_deleted_cells.clear();
|
||||
}
|
||||
|
||||
void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
|
||||
{
|
||||
RTLIL::SigSpec signal;
|
||||
auto conn_it = connections_.find(portname);
|
||||
|
||||
if (conn_it != connections_.end())
|
||||
{
|
||||
for (auto mon : module->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (module->design)
|
||||
for (auto mon : module->design->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Unconnect %s.%s.%s\n", log_id(this->module), log_id(this), log_id(portname));
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
if (module->design && module->design->flagBufferedNormalized) {
|
||||
if (conn_it->second.is_wire()) {
|
||||
Wire *w = conn_it->second.as_wire();
|
||||
if (w->driverCell_ == this && w->driverPort_ == portname) {
|
||||
w->driverCell_ = nullptr;
|
||||
w->driverPort_ = IdString();
|
||||
module->buf_norm_wire_queue.insert(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ID($connect)) {
|
||||
for (auto &[port, sig] : connections_) {
|
||||
for (auto &chunk : sig.chunks()) {
|
||||
if (!chunk.wire)
|
||||
continue;
|
||||
auto it = module->buf_norm_connect_index.find(chunk.wire);
|
||||
if (it == module->buf_norm_connect_index.end())
|
||||
continue;
|
||||
it->second.erase(this);
|
||||
if (it->second.empty())
|
||||
module->buf_norm_connect_index.erase(it);
|
||||
}
|
||||
}
|
||||
connections_.erase(conn_it);
|
||||
for (auto &[port, sig] : connections_) {
|
||||
for (auto &chunk : sig.chunks()) {
|
||||
if (!chunk.wire)
|
||||
continue;
|
||||
module->buf_norm_connect_index[chunk.wire].insert(this);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
connections_.erase(conn_it);
|
||||
}
|
||||
}
|
||||
|
||||
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
|
||||
{
|
||||
auto r = connections_.insert(portname);
|
||||
auto conn_it = r.first;
|
||||
if (!r.second && conn_it->second == signal)
|
||||
return;
|
||||
|
||||
for (auto mon : module->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (module->design)
|
||||
for (auto mon : module->design->monitors)
|
||||
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Connect %s.%s.%s = %s (%d)\n", log_id(this->module), log_id(this), log_id(portname), log_signal(signal), GetSize(signal));
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
if (module->design && module->design->flagBufferedNormalized)
|
||||
{
|
||||
// We eagerly clear a driver that got disconnected by changing this port connection
|
||||
if (conn_it->second.is_wire()) {
|
||||
Wire *w = conn_it->second.as_wire();
|
||||
if (w->driverCell_ == this && w->driverPort_ == portname) {
|
||||
w->driverCell_ = nullptr;
|
||||
w->driverPort_ = IdString();
|
||||
module->buf_norm_wire_queue.insert(w);
|
||||
}
|
||||
}
|
||||
|
||||
auto dir = port_dir(portname);
|
||||
// This is a fast path that handles connecting a full driverless wire to an output port,
|
||||
// everything else is goes through the bufnorm queues and is handled during the next
|
||||
// bufNormalize call
|
||||
if ((dir == RTLIL::PD_OUTPUT || dir == RTLIL::PD_INOUT) && signal.is_wire()) {
|
||||
Wire *w = signal.as_wire();
|
||||
if (w->driverCell_ == nullptr) {
|
||||
w->driverCell_ = this;
|
||||
w->driverPort_ = portname;
|
||||
|
||||
conn_it->second = std::move(signal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == RTLIL::PD_OUTPUT || dir == RTLIL::PD_INOUT) {
|
||||
module->buf_norm_cell_queue.insert(this);
|
||||
module->buf_norm_cell_port_queue.emplace(this, portname);
|
||||
} else {
|
||||
for (auto &chunk : signal.chunks())
|
||||
if (chunk.wire != nullptr && chunk.wire->driverCell_ == nullptr)
|
||||
module->buf_norm_wire_queue.insert(chunk.wire);
|
||||
}
|
||||
|
||||
if (type == ID($connect)) {
|
||||
for (auto &[port, sig] : connections_) {
|
||||
for (auto &chunk : sig.chunks()) {
|
||||
if (!chunk.wire)
|
||||
continue;
|
||||
auto it = module->buf_norm_connect_index.find(chunk.wire);
|
||||
if (it == module->buf_norm_connect_index.end())
|
||||
continue;
|
||||
it->second.erase(this);
|
||||
if (it->second.empty())
|
||||
module->buf_norm_connect_index.erase(it);
|
||||
}
|
||||
}
|
||||
conn_it->second = std::move(signal);
|
||||
for (auto &[port, sig] : connections_) {
|
||||
for (auto &chunk : sig.chunks()) {
|
||||
if (!chunk.wire)
|
||||
continue;
|
||||
module->buf_norm_connect_index[chunk.wire].insert(this);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
conn_it->second = std::move(signal);
|
||||
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
@ -1202,7 +1202,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)))
|
||||
if (timestep > 0 && (cell->is_builtin_ff() || cell->type == ID($anyinit)))
|
||||
{
|
||||
FfData ff(nullptr, cell);
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
|
|||
if (err.empty()) {
|
||||
Tcl_SetObjResult(interp, json_to_tcl(interp, json));
|
||||
} else
|
||||
log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str());
|
||||
log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err);
|
||||
} else if ((result = scratchpad.find("result.string")) != scratchpad.end()) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size()));
|
||||
}
|
||||
|
|
@ -214,18 +214,19 @@ bool mp_int_to_const(mp_int *a, Const &b, bool is_signed)
|
|||
buf.resize(mp_unsigned_bin_size(a));
|
||||
mp_to_unsigned_bin(a, buf.data());
|
||||
|
||||
b.bits().reserve(mp_count_bits(a) + is_signed);
|
||||
Const::Builder b_bits(mp_count_bits(a) + is_signed);
|
||||
for (int i = 0; i < mp_count_bits(a);) {
|
||||
for (int j = 0; j < 8 && i < mp_count_bits(a); j++, i++) {
|
||||
bool bv = ((buf.back() & (1 << j)) != 0) ^ negative;
|
||||
b.bits().push_back(bv ? RTLIL::S1 : RTLIL::S0);
|
||||
b_bits.push_back(bv ? RTLIL::S1 : RTLIL::S0);
|
||||
}
|
||||
buf.pop_back();
|
||||
}
|
||||
|
||||
if (is_signed) {
|
||||
b.bits().push_back(negative ? RTLIL::S1 : RTLIL::S0);
|
||||
b_bits.push_back(negative ? RTLIL::S1 : RTLIL::S0);
|
||||
}
|
||||
b = b_bits.build();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,6 @@ RTLIL::Const ReadWitness::get_bits(int t, int bits_offset, int width) const
|
|||
const std::string &bits = steps[t].bits;
|
||||
|
||||
RTLIL::Const result(State::Sa, width);
|
||||
result.bits().reserve(width);
|
||||
|
||||
int read_begin = GetSize(bits) - 1 - bits_offset;
|
||||
int read_end = max(-1, read_begin - width);
|
||||
|
|
@ -200,7 +199,7 @@ RTLIL::Const ReadWitness::get_bits(int t, int bits_offset, int width) const
|
|||
default:
|
||||
log_abort();
|
||||
}
|
||||
result.bits()[j] = bit;
|
||||
result.set(j, bit);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue