mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
Merge branch 'master' into clk2ff-better-names
This commit is contained in:
commit
49545c73f7
757 changed files with 49469 additions and 8717 deletions
29
kernel/binding.cc
Normal file
29
kernel/binding.cc
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 "binding.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
RTLIL::Binding::Binding(RTLIL::IdString target_type,
|
||||
RTLIL::IdString target_name)
|
||||
: target_type(target_type), target_name(target_name)
|
||||
{}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
60
kernel/binding.h
Normal file
60
kernel/binding.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* -*- c++ -*-
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BINDING_H
|
||||
#define BINDING_H
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct RTLIL::Binding
|
||||
{
|
||||
// Represents a bind construct.
|
||||
//
|
||||
// The target of the binding is represented by target_type and
|
||||
// target_name (see comments above the fields).
|
||||
|
||||
Binding(RTLIL::IdString target_type,
|
||||
RTLIL::IdString target_name);
|
||||
|
||||
virtual ~Binding() {}
|
||||
|
||||
// Return a string describing the binding
|
||||
virtual std::string describe() const = 0;
|
||||
|
||||
protected:
|
||||
// May be empty. If not, it's the name of the module or interface to
|
||||
// bind to.
|
||||
RTLIL::IdString target_type;
|
||||
|
||||
// If target_type is nonempty (the usual case), this is a hierarchical
|
||||
// reference to the bind target. If target_type is empty, we have to
|
||||
// wait until the hierarchy pass to figure out whether this was the name
|
||||
// of a module/interface type or an instance.
|
||||
RTLIL::IdString target_name;
|
||||
|
||||
// An attribute name which contains an ID that's unique across binding
|
||||
// instances (used to ensure we don't apply a binding twice to a module)
|
||||
RTLIL::IdString attr_name;
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -609,5 +609,56 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo
|
|||
return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
|
||||
{
|
||||
std::vector<RTLIL::State> t = arg1.bits;
|
||||
|
||||
for (int i = GetSize(arg2)-1; i >= 0; i--)
|
||||
{
|
||||
RTLIL::State sel = arg2.bits.at(i);
|
||||
std::vector<RTLIL::State> new_t;
|
||||
if (sel == State::S0)
|
||||
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
|
||||
else if (sel == State::S1)
|
||||
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
|
||||
else
|
||||
for (int j = 0; j < GetSize(t)/2; j++)
|
||||
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
|
||||
t.swap(new_t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
|
||||
{
|
||||
int width = GetSize(arg1);
|
||||
int s_width = GetSize(arg2);
|
||||
std::vector<RTLIL::State> res;
|
||||
for (int i = 0; i < (1 << s_width); i++)
|
||||
{
|
||||
bool ne = false;
|
||||
bool x = false;
|
||||
for (int j = 0; j < s_width; j++) {
|
||||
bool bit = i & 1 << j;
|
||||
if (arg2[j] == (bit ? RTLIL::S0 : RTLIL::S1))
|
||||
ne = true;
|
||||
else if (arg2[j] != RTLIL::S0 && arg2[j] != RTLIL::S1)
|
||||
x = true;
|
||||
}
|
||||
if (ne) {
|
||||
for (int j = 0; j < width; j++)
|
||||
res.push_back(State::S0);
|
||||
} else if (x) {
|
||||
for (int j = 0; j < width; j++)
|
||||
res.push_back(arg1.bits[j] == State::S0 ? State::S0 : State::Sx);
|
||||
} else {
|
||||
for (int j = 0; j < width; j++)
|
||||
res.push_back(arg1.bits[j]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -142,6 +142,36 @@ void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
||||
{
|
||||
int width = GetSize(cell->getPort(ID::Y));
|
||||
int a_width = GetSize(cell->getPort(ID::A));
|
||||
int s_width = GetSize(cell->getPort(ID::S));
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
for (int k = i; k < a_width; k += width)
|
||||
db->add_edge(cell, ID::A, k, ID::Y, i, -1);
|
||||
|
||||
for (int k = 0; k < s_width; k++)
|
||||
db->add_edge(cell, ID::S, k, ID::Y, i, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
||||
{
|
||||
int width = GetSize(cell->getPort(ID::Y));
|
||||
int a_width = GetSize(cell->getPort(ID::A));
|
||||
int s_width = GetSize(cell->getPort(ID::S));
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1);
|
||||
for (int k = 0; k < s_width; k++)
|
||||
db->add_edge(cell, ID::S, k, ID::Y, i, -1);
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
||||
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
|
||||
|
@ -187,6 +217,16 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($bmux)) {
|
||||
bmux_op(this, cell);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($demux)) {
|
||||
demux_op(this, cell);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
|
||||
// FIXME: $lut $sop $alu $lcu $macc $fa
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -127,6 +127,9 @@ struct CellTypes
|
|||
for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
|
||||
setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);
|
||||
|
||||
for (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))
|
||||
setup_type(type, {ID::A, ID::S}, {ID::Y}, true);
|
||||
|
||||
setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
|
||||
setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
|
||||
setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
|
||||
|
@ -142,6 +145,8 @@ struct CellTypes
|
|||
setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q});
|
||||
setup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q});
|
||||
setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q});
|
||||
setup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q});
|
||||
setup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q});
|
||||
setup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q});
|
||||
setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});
|
||||
setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});
|
||||
|
@ -155,9 +160,13 @@ struct CellTypes
|
|||
setup_internals_ff();
|
||||
|
||||
setup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA});
|
||||
setup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA});
|
||||
setup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});
|
||||
setup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});
|
||||
|
||||
setup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT});
|
||||
}
|
||||
|
@ -220,6 +229,15 @@ struct CellTypes
|
|||
for (auto c4 : list_np)
|
||||
setup_type(stringf("$_DFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
setup_type(stringf("$_ALDFF_%c%c_", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
for (auto c3 : list_np)
|
||||
setup_type(stringf("$_ALDFFE_%c%c%c_", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
for (auto c3 : list_np)
|
||||
|
@ -396,6 +414,16 @@ struct CellTypes
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (cell->type == ID($bmux))
|
||||
{
|
||||
return const_bmux(arg1, arg2);
|
||||
}
|
||||
|
||||
if (cell->type == ID($demux))
|
||||
{
|
||||
return const_demux(arg1, arg2);
|
||||
}
|
||||
|
||||
if (cell->type == ID($lut))
|
||||
{
|
||||
int width = cell->parameters.at(ID::WIDTH).as_int();
|
||||
|
@ -405,21 +433,7 @@ struct CellTypes
|
|||
t.push_back(State::S0);
|
||||
t.resize(1 << width);
|
||||
|
||||
for (int i = width-1; i >= 0; i--) {
|
||||
RTLIL::State sel = arg1.bits.at(i);
|
||||
std::vector<RTLIL::State> new_t;
|
||||
if (sel == State::S0)
|
||||
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
|
||||
else if (sel == State::S1)
|
||||
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
|
||||
else
|
||||
for (int j = 0; j < GetSize(t)/2; j++)
|
||||
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
|
||||
t.swap(new_t);
|
||||
}
|
||||
|
||||
log_assert(GetSize(t) == 1);
|
||||
return t;
|
||||
return const_bmux(t, arg1);
|
||||
}
|
||||
|
||||
if (cell->type == ID($sop))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -135,8 +135,6 @@ struct ConstEval
|
|||
|
||||
if (cell->hasPort(ID::S)) {
|
||||
sig_s = cell->getPort(ID::S);
|
||||
if (!eval(sig_s, undef, cell))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cell->hasPort(ID::A))
|
||||
|
@ -151,6 +149,9 @@ struct ConstEval
|
|||
int count_maybe_set_s_bits = 0;
|
||||
int count_set_s_bits = 0;
|
||||
|
||||
if (!eval(sig_s, undef, cell))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < sig_s.size(); i++)
|
||||
{
|
||||
RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
|
||||
|
@ -198,6 +199,36 @@ struct ConstEval
|
|||
else
|
||||
set(sig_y, y_values.front());
|
||||
}
|
||||
else if (cell->type == ID($bmux))
|
||||
{
|
||||
if (!eval(sig_s, undef, cell))
|
||||
return false;
|
||||
|
||||
if (sig_s.is_fully_def()) {
|
||||
int sel = sig_s.as_int();
|
||||
int width = GetSize(sig_y);
|
||||
SigSpec res = sig_a.extract(sel * width, width);
|
||||
if (!eval(res, undef, cell))
|
||||
return false;
|
||||
set(sig_y, res.as_const());
|
||||
} else {
|
||||
if (!eval(sig_a, undef, cell))
|
||||
return false;
|
||||
set(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));
|
||||
}
|
||||
}
|
||||
else if (cell->type == ID($demux))
|
||||
{
|
||||
if (!eval(sig_a, undef, cell))
|
||||
return false;
|
||||
if (sig_a.is_fully_zero()) {
|
||||
set(sig_y, Const(0, GetSize(sig_y)));
|
||||
} else {
|
||||
if (!eval(sig_s, undef, cell))
|
||||
return false;
|
||||
set(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));
|
||||
}
|
||||
}
|
||||
else if (cell->type == ID($fa))
|
||||
{
|
||||
RTLIL::SigSpec sig_c = cell->getPort(ID::C);
|
||||
|
|
|
@ -11,9 +11,12 @@ X(abc9_mergeability)
|
|||
X(abc9_scc_id)
|
||||
X(abcgroup)
|
||||
X(ABITS)
|
||||
X(AD)
|
||||
X(ADDR)
|
||||
X(allconst)
|
||||
X(allseq)
|
||||
X(ALOAD)
|
||||
X(ALOAD_POLARITY)
|
||||
X(always_comb)
|
||||
X(always_ff)
|
||||
X(always_latch)
|
||||
|
@ -32,6 +35,7 @@ X(bugpoint_keep)
|
|||
X(B_WIDTH)
|
||||
X(C)
|
||||
X(cells_not_processed)
|
||||
X(CE_OVER_SRST)
|
||||
X(CFG_ABITS)
|
||||
X(CFG_DBITS)
|
||||
X(CFG_INIT)
|
||||
|
@ -46,6 +50,7 @@ X(CLK_POLARITY)
|
|||
X(CLR)
|
||||
X(CLR_POLARITY)
|
||||
X(CO)
|
||||
X(COLLISION_X_MASK)
|
||||
X(CONFIG)
|
||||
X(CONFIG_WIDTH)
|
||||
X(CTRL_IN)
|
||||
|
@ -95,6 +100,7 @@ X(hdlname)
|
|||
X(hierconn)
|
||||
X(I)
|
||||
X(INIT)
|
||||
X(INIT_VALUE)
|
||||
X(init)
|
||||
X(initial_top)
|
||||
X(interface_modport)
|
||||
|
@ -133,19 +139,31 @@ X(onehot)
|
|||
X(P)
|
||||
X(parallel_case)
|
||||
X(parameter)
|
||||
X(PORTID)
|
||||
X(PRIORITY)
|
||||
X(PRIORITY_MASK)
|
||||
X(Q)
|
||||
X(qwp_position)
|
||||
X(R)
|
||||
X(RD_ADDR)
|
||||
X(RD_ARST)
|
||||
X(RD_ARST_VALUE)
|
||||
X(RD_CE_OVER_SRST)
|
||||
X(RD_CLK)
|
||||
X(RD_CLK_ENABLE)
|
||||
X(RD_CLK_POLARITY)
|
||||
X(RD_COLLISION_X_MASK)
|
||||
X(RD_DATA)
|
||||
X(RD_EN)
|
||||
X(RD_INIT_VALUE)
|
||||
X(RD_PORTS)
|
||||
X(RD_SRST)
|
||||
X(RD_SRST_VALUE)
|
||||
X(RD_TRANSPARENCY_MASK)
|
||||
X(RD_TRANSPARENT)
|
||||
X(RD_WIDE_CONTINUATION)
|
||||
X(reg)
|
||||
X(reprocess_after)
|
||||
X(S)
|
||||
X(SET)
|
||||
X(SET_POLARITY)
|
||||
|
@ -161,6 +179,7 @@ X(SRC_WIDTH)
|
|||
X(SRST)
|
||||
X(SRST_POLARITY)
|
||||
X(SRST_VALUE)
|
||||
X(sta_arrival)
|
||||
X(STATE_BITS)
|
||||
X(STATE_NUM)
|
||||
X(STATE_NUM_LOG2)
|
||||
|
@ -195,6 +214,7 @@ X(T_LIMIT_TYP)
|
|||
X(to_delete)
|
||||
X(top)
|
||||
X(TRANS_NUM)
|
||||
X(TRANSPARENCY_MASK)
|
||||
X(TRANSPARENT)
|
||||
X(TRANS_TABLE)
|
||||
X(T_RISE_MAX)
|
||||
|
@ -220,6 +240,8 @@ X(WR_CLK_POLARITY)
|
|||
X(WR_DATA)
|
||||
X(WR_EN)
|
||||
X(WR_PORTS)
|
||||
X(WR_PRIORITY_MASK)
|
||||
X(WR_WIDE_CONTINUATION)
|
||||
X(X)
|
||||
X(Y)
|
||||
X(Y_WIDTH)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -118,7 +118,7 @@ int main(int argc, char **argv)
|
|||
if (argc == 2)
|
||||
{
|
||||
// Run the first argument as a script file
|
||||
run_frontend(argv[1], "script", 0, 0, 0);
|
||||
run_frontend(argv[1], "script");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,12 +202,13 @@ int main(int argc, char **argv)
|
|||
std::string output_filename = "";
|
||||
std::string scriptfile = "";
|
||||
std::string depsfile = "";
|
||||
std::string topmodule = "";
|
||||
bool scriptfile_tcl = false;
|
||||
bool got_output_filename = false;
|
||||
bool print_banner = true;
|
||||
bool print_stats = true;
|
||||
bool call_abort = false;
|
||||
bool timing_details = false;
|
||||
bool run_shell = true;
|
||||
bool mode_v = false;
|
||||
bool mode_q = false;
|
||||
|
||||
|
@ -288,6 +289,9 @@ int main(int argc, char **argv)
|
|||
printf(" -A\n");
|
||||
printf(" will call abort() at the end of the script. for debugging\n");
|
||||
printf("\n");
|
||||
printf(" -r <module_name>\n");
|
||||
printf(" elaborate command line arguments using the specified top module\n");
|
||||
printf("\n");
|
||||
printf(" -D <macro>[=<value>]\n");
|
||||
printf(" set the specified Verilog define (via \"read -define\")\n");
|
||||
printf("\n");
|
||||
|
@ -342,7 +346,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:x:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
@ -366,6 +370,7 @@ int main(int argc, char **argv)
|
|||
exit(0);
|
||||
case 'S':
|
||||
passes_commands.push_back("synth");
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'g':
|
||||
log_force_debug++;
|
||||
|
@ -378,19 +383,23 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 'H':
|
||||
passes_commands.push_back("help");
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'h':
|
||||
passes_commands.push_back(stringf("help %s", optarg));
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'b':
|
||||
backend_command = optarg;
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'p':
|
||||
passes_commands.push_back(optarg);
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'o':
|
||||
output_filename = optarg;
|
||||
got_output_filename = true;
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
|
@ -422,10 +431,12 @@ int main(int argc, char **argv)
|
|||
case 's':
|
||||
scriptfile = optarg;
|
||||
scriptfile_tcl = false;
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'c':
|
||||
scriptfile = optarg;
|
||||
scriptfile_tcl = true;
|
||||
run_shell = false;
|
||||
break;
|
||||
case 'W':
|
||||
log_warn_regexes.push_back(YS_REGEX_COMPILE(optarg));
|
||||
|
@ -436,6 +447,9 @@ int main(int argc, char **argv)
|
|||
case 'e':
|
||||
log_werror_regexes.push_back(YS_REGEX_COMPILE(optarg));
|
||||
break;
|
||||
case 'r':
|
||||
topmodule = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
vlog_defines.push_back(optarg);
|
||||
break;
|
||||
|
@ -506,12 +520,6 @@ int main(int argc, char **argv)
|
|||
for (auto &fn : plugin_filenames)
|
||||
load_plugin(fn, {});
|
||||
|
||||
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
|
||||
if (!got_output_filename)
|
||||
backend_command = "";
|
||||
shell(yosys_design);
|
||||
}
|
||||
|
||||
if (!vlog_defines.empty()) {
|
||||
std::string vdef_cmd = "read -define";
|
||||
for (auto vdef : vlog_defines)
|
||||
|
@ -520,7 +528,11 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
while (optind < argc)
|
||||
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
|
||||
if (run_frontend(argv[optind++], frontend_command))
|
||||
run_shell = false;
|
||||
|
||||
if (!topmodule.empty())
|
||||
run_pass("hierarchy -top " + topmodule);
|
||||
|
||||
if (!scriptfile.empty()) {
|
||||
if (scriptfile_tcl) {
|
||||
|
@ -531,13 +543,15 @@ int main(int argc, char **argv)
|
|||
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
|
||||
#endif
|
||||
} else
|
||||
run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
|
||||
run_frontend(scriptfile, "script");
|
||||
}
|
||||
|
||||
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
|
||||
run_pass(*it);
|
||||
|
||||
if (!backend_command.empty())
|
||||
if (run_shell)
|
||||
shell(yosys_design);
|
||||
else
|
||||
run_backend(output_filename, backend_command);
|
||||
|
||||
yosys_design->check();
|
||||
|
|
755
kernel/ff.cc
Normal file
755
kernel/ff.cc
Normal file
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
|
||||
*
|
||||
* 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/ff.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name)
|
||||
{
|
||||
cell = cell_;
|
||||
sig_q = cell->getPort(ID::Q);
|
||||
width = GetSize(sig_q);
|
||||
attributes = cell->attributes;
|
||||
|
||||
if (initvals)
|
||||
val_init = (*initvals)(sig_q);
|
||||
|
||||
std::string type_str = cell->type.str();
|
||||
|
||||
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
|
||||
if (cell->type == ID($ff)) {
|
||||
has_gclk = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
} else if (cell->type == ID($sr)) {
|
||||
// No data input at all.
|
||||
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
|
||||
has_aload = true;
|
||||
sig_aload = cell->getPort(ID::EN);
|
||||
pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
|
||||
sig_ad = cell->getPort(ID::D);
|
||||
} else {
|
||||
has_clk = true;
|
||||
sig_clk = cell->getPort(ID::CLK);
|
||||
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
|
||||
sig_d = cell->getPort(ID::D);
|
||||
}
|
||||
if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
|
||||
has_ce = true;
|
||||
sig_ce = cell->getPort(ID::EN);
|
||||
pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
|
||||
}
|
||||
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
|
||||
has_sr = true;
|
||||
sig_clr = cell->getPort(ID::CLR);
|
||||
sig_set = cell->getPort(ID::SET);
|
||||
pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
|
||||
pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
|
||||
}
|
||||
if (cell->type.in(ID($aldff), ID($aldffe))) {
|
||||
has_aload = true;
|
||||
sig_aload = cell->getPort(ID::ALOAD);
|
||||
pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
|
||||
sig_ad = cell->getPort(ID::AD);
|
||||
}
|
||||
if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
|
||||
has_arst = true;
|
||||
sig_arst = cell->getPort(ID::ARST);
|
||||
pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
|
||||
val_arst = cell->getParam(ID::ARST_VALUE);
|
||||
}
|
||||
if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
|
||||
has_srst = true;
|
||||
sig_srst = cell->getPort(ID::SRST);
|
||||
pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
|
||||
val_srst = cell->getParam(ID::SRST_VALUE);
|
||||
ce_over_srst = cell->type == ID($sdffce);
|
||||
}
|
||||
} else if (cell->type == ID($_FF_)) {
|
||||
is_fine = true;
|
||||
has_gclk = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
} else if (type_str.substr(0, 5) == "$_SR_") {
|
||||
is_fine = true;
|
||||
has_sr = true;
|
||||
pol_set = type_str[5] == 'P';
|
||||
pol_clr = type_str[6] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[6] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_ce = true;
|
||||
pol_ce = type_str[8] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[6] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[7] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[8] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[8] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
|
||||
has_ce = true;
|
||||
pol_ce = type_str[10] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[8] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_aload = true;
|
||||
pol_aload = type_str[9] == 'P';
|
||||
sig_aload = cell->getPort(ID::L);
|
||||
sig_ad = cell->getPort(ID::AD);
|
||||
} else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[9] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_aload = true;
|
||||
pol_aload = type_str[10] == 'P';
|
||||
sig_aload = cell->getPort(ID::L);
|
||||
sig_ad = cell->getPort(ID::AD);
|
||||
has_ce = true;
|
||||
pol_ce = type_str[11] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[8] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_sr = true;
|
||||
pol_set = type_str[9] == 'P';
|
||||
pol_clr = type_str[10] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[9] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_sr = true;
|
||||
pol_set = type_str[10] == 'P';
|
||||
pol_clr = type_str[11] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
has_ce = true;
|
||||
pol_ce = type_str[12] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[8] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[9] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[8] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[9] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
|
||||
has_ce = true;
|
||||
pol_ce = type_str[11] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[9] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[10] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
|
||||
has_ce = true;
|
||||
pol_ce = type_str[12] == 'P';
|
||||
sig_ce = cell->getPort(ID::E);
|
||||
ce_over_srst = true;
|
||||
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
|
||||
is_fine = true;
|
||||
has_aload = true;
|
||||
sig_ad = cell->getPort(ID::D);
|
||||
has_aload = true;
|
||||
pol_aload = type_str[9] == 'P';
|
||||
sig_aload = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
|
||||
is_fine = true;
|
||||
has_aload = true;
|
||||
sig_ad = cell->getPort(ID::D);
|
||||
has_aload = true;
|
||||
pol_aload = type_str[9] == 'P';
|
||||
sig_aload = cell->getPort(ID::E);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[10] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
|
||||
is_fine = true;
|
||||
has_aload = true;
|
||||
sig_ad = cell->getPort(ID::D);
|
||||
has_aload = true;
|
||||
pol_aload = type_str[11] == 'P';
|
||||
sig_aload = cell->getPort(ID::E);
|
||||
has_sr = true;
|
||||
pol_set = type_str[12] == 'P';
|
||||
pol_clr = type_str[13] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else {
|
||||
log_assert(0);
|
||||
}
|
||||
if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
|
||||
// Plain D latches with const D treated specially.
|
||||
has_aload = false;
|
||||
has_arst = true;
|
||||
sig_arst = sig_aload;
|
||||
pol_arst = pol_aload;
|
||||
val_arst = sig_ad.as_const();
|
||||
}
|
||||
}
|
||||
|
||||
FfData FfData::slice(const std::vector<int> &bits) {
|
||||
FfData res(module, initvals, NEW_ID);
|
||||
res.sig_clk = sig_clk;
|
||||
res.sig_ce = sig_ce;
|
||||
res.sig_aload = sig_aload;
|
||||
res.sig_arst = sig_arst;
|
||||
res.sig_srst = sig_srst;
|
||||
res.has_clk = has_clk;
|
||||
res.has_gclk = has_gclk;
|
||||
res.has_ce = has_ce;
|
||||
res.has_aload = has_aload;
|
||||
res.has_arst = has_arst;
|
||||
res.has_srst = has_srst;
|
||||
res.has_sr = has_sr;
|
||||
res.ce_over_srst = ce_over_srst;
|
||||
res.is_fine = is_fine;
|
||||
res.pol_clk = pol_clk;
|
||||
res.pol_ce = pol_ce;
|
||||
res.pol_aload = pol_aload;
|
||||
res.pol_arst = pol_arst;
|
||||
res.pol_srst = pol_srst;
|
||||
res.pol_clr = pol_clr;
|
||||
res.pol_set = pol_set;
|
||||
res.attributes = attributes;
|
||||
for (int i : bits) {
|
||||
res.sig_q.append(sig_q[i]);
|
||||
if (has_clk || has_gclk)
|
||||
res.sig_d.append(sig_d[i]);
|
||||
if (has_aload)
|
||||
res.sig_ad.append(sig_ad[i]);
|
||||
if (has_sr) {
|
||||
res.sig_clr.append(sig_clr[i]);
|
||||
res.sig_set.append(sig_set[i]);
|
||||
}
|
||||
if (has_arst)
|
||||
res.val_arst.bits.push_back(val_arst[i]);
|
||||
if (has_srst)
|
||||
res.val_srst.bits.push_back(val_srst[i]);
|
||||
if (initvals)
|
||||
res.val_init.bits.push_back(val_init[i]);
|
||||
}
|
||||
res.width = GetSize(res.sig_q);
|
||||
return res;
|
||||
}
|
||||
|
||||
void FfData::add_dummy_ce() {
|
||||
if (has_ce)
|
||||
return;
|
||||
has_ce = true;
|
||||
pol_ce = true;
|
||||
sig_ce = State::S1;
|
||||
ce_over_srst = false;
|
||||
}
|
||||
|
||||
void FfData::add_dummy_srst() {
|
||||
if (has_srst)
|
||||
return;
|
||||
has_srst = true;
|
||||
pol_srst = true;
|
||||
sig_srst = State::S0;
|
||||
val_srst = Const(State::Sx, width);
|
||||
ce_over_srst = false;
|
||||
}
|
||||
|
||||
void FfData::add_dummy_arst() {
|
||||
if (has_arst)
|
||||
return;
|
||||
has_arst = true;
|
||||
pol_arst = true;
|
||||
sig_arst = State::S0;
|
||||
val_arst = Const(State::Sx, width);
|
||||
}
|
||||
|
||||
void FfData::add_dummy_aload() {
|
||||
if (has_aload)
|
||||
return;
|
||||
has_aload = true;
|
||||
pol_aload = true;
|
||||
sig_aload = State::S0;
|
||||
sig_ad = Const(State::Sx, width);
|
||||
}
|
||||
|
||||
void FfData::add_dummy_sr() {
|
||||
if (has_sr)
|
||||
return;
|
||||
has_sr = true;
|
||||
pol_clr = true;
|
||||
pol_set = true;
|
||||
sig_clr = Const(State::S0, width);
|
||||
sig_set = Const(State::S0, width);
|
||||
}
|
||||
|
||||
void FfData::add_dummy_clk() {
|
||||
if (has_clk)
|
||||
return;
|
||||
has_clk = true;
|
||||
pol_clk = true;
|
||||
sig_clk = State::S0;
|
||||
sig_d = Const(State::Sx, width);
|
||||
}
|
||||
|
||||
void FfData::arst_to_aload() {
|
||||
log_assert(has_arst);
|
||||
log_assert(!has_aload);
|
||||
pol_aload = pol_arst;
|
||||
sig_aload = sig_arst;
|
||||
sig_ad = val_arst;
|
||||
has_aload = true;
|
||||
has_arst = false;
|
||||
}
|
||||
|
||||
void FfData::arst_to_sr() {
|
||||
log_assert(has_arst);
|
||||
log_assert(!has_sr);
|
||||
pol_clr = pol_arst;
|
||||
pol_set = pol_arst;
|
||||
sig_clr = Const(pol_arst ? State::S0 : State::S1, width);
|
||||
sig_set = Const(pol_arst ? State::S0 : State::S1, width);
|
||||
has_sr = true;
|
||||
has_arst = false;
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (val_arst[i] == State::S1)
|
||||
sig_set[i] = sig_arst;
|
||||
else
|
||||
sig_clr[i] = sig_arst;
|
||||
}
|
||||
}
|
||||
|
||||
void FfData::aload_to_sr() {
|
||||
log_assert(has_aload);
|
||||
log_assert(!has_sr);
|
||||
has_sr = true;
|
||||
has_aload = false;
|
||||
if (!is_fine) {
|
||||
pol_clr = false;
|
||||
pol_set = true;
|
||||
if (pol_aload) {
|
||||
sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload);
|
||||
sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload);
|
||||
} else {
|
||||
sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload);
|
||||
sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload);
|
||||
}
|
||||
} else {
|
||||
pol_clr = pol_aload;
|
||||
pol_set = pol_aload;
|
||||
if (pol_aload) {
|
||||
sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad);
|
||||
sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad);
|
||||
} else {
|
||||
sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad);
|
||||
sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FfData::convert_ce_over_srst(bool val) {
|
||||
if (!has_ce || !has_srst || ce_over_srst == val)
|
||||
return;
|
||||
if (val) {
|
||||
// sdffe to sdffce
|
||||
if (!is_fine) {
|
||||
if (pol_ce) {
|
||||
if (pol_srst) {
|
||||
sig_ce = module->Or(NEW_ID, sig_ce, sig_srst);
|
||||
} else {
|
||||
SigSpec tmp = module->Not(NEW_ID, sig_srst);
|
||||
sig_ce = module->Or(NEW_ID, sig_ce, tmp);
|
||||
}
|
||||
} else {
|
||||
if (pol_srst) {
|
||||
SigSpec tmp = module->Not(NEW_ID, sig_srst);
|
||||
sig_ce = module->And(NEW_ID, sig_ce, tmp);
|
||||
} else {
|
||||
sig_ce = module->And(NEW_ID, sig_ce, sig_srst);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pol_ce) {
|
||||
if (pol_srst) {
|
||||
sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst);
|
||||
} else {
|
||||
sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst);
|
||||
}
|
||||
} else {
|
||||
if (pol_srst) {
|
||||
sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst);
|
||||
} else {
|
||||
sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// sdffce to sdffe
|
||||
if (!is_fine) {
|
||||
if (pol_srst) {
|
||||
if (pol_ce) {
|
||||
sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce);
|
||||
} else {
|
||||
SigSpec tmp = module->Not(NEW_ID, sig_ce);
|
||||
sig_srst = cell->module->And(NEW_ID, sig_srst, tmp);
|
||||
}
|
||||
} else {
|
||||
if (pol_ce) {
|
||||
SigSpec tmp = module->Not(NEW_ID, sig_ce);
|
||||
sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp);
|
||||
} else {
|
||||
sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pol_srst) {
|
||||
if (pol_ce) {
|
||||
sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce);
|
||||
} else {
|
||||
sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce);
|
||||
}
|
||||
} else {
|
||||
if (pol_ce) {
|
||||
sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce);
|
||||
} else {
|
||||
sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ce_over_srst = val;
|
||||
}
|
||||
|
||||
void FfData::unmap_ce() {
|
||||
if (!has_ce)
|
||||
return;
|
||||
log_assert(has_clk);
|
||||
if (has_srst && ce_over_srst)
|
||||
unmap_srst();
|
||||
|
||||
if (!is_fine) {
|
||||
if (pol_ce)
|
||||
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
|
||||
else
|
||||
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
|
||||
} else {
|
||||
if (pol_ce)
|
||||
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
|
||||
else
|
||||
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
|
||||
}
|
||||
has_ce = false;
|
||||
}
|
||||
|
||||
void FfData::unmap_srst() {
|
||||
if (!has_srst)
|
||||
return;
|
||||
if (has_ce && !ce_over_srst)
|
||||
unmap_ce();
|
||||
|
||||
if (!is_fine) {
|
||||
if (pol_srst)
|
||||
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
|
||||
else
|
||||
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
|
||||
} else {
|
||||
if (pol_srst)
|
||||
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
|
||||
else
|
||||
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
|
||||
}
|
||||
has_srst = false;
|
||||
}
|
||||
|
||||
Cell *FfData::emit() {
|
||||
remove();
|
||||
if (!width)
|
||||
return nullptr;
|
||||
if (!has_aload && !has_clk && !has_gclk && !has_sr) {
|
||||
if (has_arst) {
|
||||
// Convert this case to a D latch.
|
||||
arst_to_aload();
|
||||
} else {
|
||||
// No control inputs left. Turn into a const driver.
|
||||
module->connect(sig_q, val_init);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (initvals)
|
||||
initvals->set_init(sig_q, val_init);
|
||||
if (!is_fine) {
|
||||
if (has_gclk) {
|
||||
log_assert(!has_clk);
|
||||
log_assert(!has_ce);
|
||||
log_assert(!has_aload);
|
||||
log_assert(!has_arst);
|
||||
log_assert(!has_srst);
|
||||
log_assert(!has_sr);
|
||||
cell = module->addFf(name, sig_d, sig_q);
|
||||
} else if (!has_aload && !has_clk) {
|
||||
log_assert(has_sr);
|
||||
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
||||
} else if (!has_clk) {
|
||||
log_assert(!has_srst);
|
||||
if (has_sr)
|
||||
cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
|
||||
else if (has_arst)
|
||||
cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
|
||||
else
|
||||
cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
|
||||
} else {
|
||||
if (has_sr) {
|
||||
if (has_ce)
|
||||
cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
|
||||
else
|
||||
cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
|
||||
} else if (has_arst) {
|
||||
if (has_ce)
|
||||
cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
|
||||
else
|
||||
cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
|
||||
} else if (has_aload) {
|
||||
if (has_ce)
|
||||
cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
|
||||
else
|
||||
cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
|
||||
} else if (has_srst) {
|
||||
if (has_ce)
|
||||
if (ce_over_srst)
|
||||
cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
|
||||
else
|
||||
cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
|
||||
else
|
||||
cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
|
||||
} else {
|
||||
if (has_ce)
|
||||
cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
|
||||
else
|
||||
cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (has_gclk) {
|
||||
log_assert(!has_clk);
|
||||
log_assert(!has_ce);
|
||||
log_assert(!has_aload);
|
||||
log_assert(!has_arst);
|
||||
log_assert(!has_srst);
|
||||
log_assert(!has_sr);
|
||||
cell = module->addFfGate(name, sig_d, sig_q);
|
||||
} else if (!has_aload && !has_clk) {
|
||||
log_assert(has_sr);
|
||||
cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
||||
} else if (!has_clk) {
|
||||
log_assert(!has_srst);
|
||||
if (has_sr)
|
||||
cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
|
||||
else if (has_arst)
|
||||
cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
|
||||
else
|
||||
cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
|
||||
} else {
|
||||
if (has_sr) {
|
||||
if (has_ce)
|
||||
cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
|
||||
else
|
||||
cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
|
||||
} else if (has_arst) {
|
||||
if (has_ce)
|
||||
cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
|
||||
else
|
||||
cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
|
||||
} else if (has_aload) {
|
||||
if (has_ce)
|
||||
cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
|
||||
else
|
||||
cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
|
||||
} else if (has_srst) {
|
||||
if (has_ce)
|
||||
if (ce_over_srst)
|
||||
cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
|
||||
else
|
||||
cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
|
||||
else
|
||||
cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
|
||||
} else {
|
||||
if (has_ce)
|
||||
cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
|
||||
else
|
||||
cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
|
||||
}
|
||||
}
|
||||
}
|
||||
cell->attributes = attributes;
|
||||
return cell;
|
||||
}
|
||||
|
||||
void FfData::remove() {
|
||||
if (cell) {
|
||||
remove_init();
|
||||
module->remove(cell);
|
||||
cell = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
State invert(State s) {
|
||||
switch (s) {
|
||||
case State::S0: return State::S1;
|
||||
case State::S1: return State::S0;
|
||||
default: return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FfData::flip_bits(const pool<int> &bits) {
|
||||
if (!bits.size())
|
||||
return;
|
||||
|
||||
remove_init();
|
||||
|
||||
Wire *new_q = module->addWire(NEW_ID, width);
|
||||
|
||||
for (auto bit: bits) {
|
||||
if (has_arst)
|
||||
val_arst[bit] = invert(val_arst[bit]);
|
||||
if (has_srst)
|
||||
val_srst[bit] = invert(val_srst[bit]);
|
||||
val_init[bit] = invert(val_init[bit]);
|
||||
}
|
||||
|
||||
if (has_sr && cell) {
|
||||
log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
|
||||
}
|
||||
|
||||
if (is_fine) {
|
||||
if (has_sr) {
|
||||
bool new_pol_clr = pol_set;
|
||||
SigSpec new_sig_clr;
|
||||
if (pol_set) {
|
||||
if (pol_clr) {
|
||||
new_sig_clr = module->AndnotGate(NEW_ID, sig_set, sig_clr);
|
||||
} else {
|
||||
new_sig_clr = module->AndGate(NEW_ID, sig_set, sig_clr);
|
||||
}
|
||||
} else {
|
||||
if (pol_clr) {
|
||||
new_sig_clr = module->OrGate(NEW_ID, sig_set, sig_clr);
|
||||
} else {
|
||||
new_sig_clr = module->OrnotGate(NEW_ID, sig_set, sig_clr);
|
||||
}
|
||||
}
|
||||
pol_set = pol_clr;
|
||||
sig_set = sig_clr;
|
||||
pol_clr = new_pol_clr;
|
||||
sig_clr = new_sig_clr;
|
||||
}
|
||||
if (has_clk || has_gclk)
|
||||
sig_d = module->NotGate(NEW_ID, sig_d);
|
||||
if (has_aload)
|
||||
sig_ad = module->NotGate(NEW_ID, sig_ad);
|
||||
module->addNotGate(NEW_ID, new_q, sig_q);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_sr) {
|
||||
SigSpec not_clr;
|
||||
if (!pol_clr) {
|
||||
not_clr = sig_clr;
|
||||
sig_clr = module->Not(NEW_ID, sig_clr);
|
||||
pol_clr = true;
|
||||
} else {
|
||||
not_clr = module->Not(NEW_ID, sig_clr);
|
||||
}
|
||||
if (!pol_set) {
|
||||
sig_set = module->Not(NEW_ID, sig_set);
|
||||
pol_set = true;
|
||||
}
|
||||
|
||||
SigSpec masked_set = module->And(NEW_ID, sig_set, not_clr);
|
||||
for (auto bit: bits) {
|
||||
sig_set[bit] = sig_clr[bit];
|
||||
sig_clr[bit] = masked_set[bit];
|
||||
}
|
||||
}
|
||||
|
||||
Const mask = Const(State::S0, width);
|
||||
for (auto bit: bits)
|
||||
mask.bits[bit] = State::S1;
|
||||
|
||||
if (has_clk || has_gclk)
|
||||
sig_d = module->Xor(NEW_ID, sig_d, mask);
|
||||
if (has_aload)
|
||||
sig_ad = module->Xor(NEW_ID, sig_ad, mask);
|
||||
module->addXor(NEW_ID, new_q, mask, sig_q);
|
||||
}
|
||||
|
||||
sig_q = new_q;
|
||||
}
|
544
kernel/ff.h
544
kernel/ff.h
|
@ -25,460 +25,190 @@
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// Describes a flip-flop or a latch.
|
||||
//
|
||||
// If has_gclk, this is a formal verification FF with implicit global clock:
|
||||
// Q is simply previous cycle's D.
|
||||
//
|
||||
// Otherwise, the FF/latch can have any number of features selected by has_*
|
||||
// attributes that determine Q's value (in order of decreasing priority):
|
||||
//
|
||||
// - on start, register is initialized to val_init
|
||||
// - if has_sr is present:
|
||||
// - sig_clr is per-bit async clear, and sets the corresponding bit to 0
|
||||
// if active
|
||||
// - sig_set is per-bit async set, and sets the corresponding bit to 1
|
||||
// if active
|
||||
// - if has_arst is present:
|
||||
// - sig_arst is whole-reg async reset, and sets the whole register to val_arst
|
||||
// - if has_aload is present:
|
||||
// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole
|
||||
// register to sig_ad
|
||||
// - if has_clk is present, and we're currently on a clock edge:
|
||||
// - if has_ce is present and ce_over_srst is true:
|
||||
// - ignore clock edge (don't change value) unless sig_ce is active
|
||||
// - if has_srst is present:
|
||||
// - sig_srst is whole-reg sync reset and sets the register to val_srst
|
||||
// - if has_ce is present and ce_over_srst is false:
|
||||
// - ignore clock edge (don't change value) unless sig_ce is active
|
||||
// - set whole reg to sig_d
|
||||
// - if nothing of the above applies, the reg value remains unchanged
|
||||
//
|
||||
// Since the yosys FF cell library isn't fully generic, not all combinations
|
||||
// of the features above can be supported:
|
||||
//
|
||||
// - only one of has_srst, has_arst, has_sr can be used
|
||||
// - if has_clk is used together with has_aload, then has_srst, has_arst,
|
||||
// has_sr cannot be used
|
||||
//
|
||||
// The valid feature combinations are thus:
|
||||
//
|
||||
// - has_clk + optional has_ce [dff/dffe]
|
||||
// - has_clk + optional has_ce + has_arst [adff/adffe]
|
||||
// - has_clk + optional has_ce + has_aload [aldff/aldffe]
|
||||
// - has_clk + optional has_ce + has_sr [dffsr/dffsre]
|
||||
// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce]
|
||||
// - has_aload [dlatch]
|
||||
// - has_aload + has_arst [adlatch]
|
||||
// - has_aload + has_sr [dlatchsr]
|
||||
// - has_sr [sr]
|
||||
// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
|
||||
// - empty set [not a cell — will be emitted as a simple direct connection]
|
||||
|
||||
struct FfData {
|
||||
Module *module;
|
||||
FfInitVals *initvals;
|
||||
Cell *cell;
|
||||
IdString name;
|
||||
// The FF output.
|
||||
SigSpec sig_q;
|
||||
// The sync data input, present if has_clk or has_gclk.
|
||||
SigSpec sig_d;
|
||||
// The async data input, present if has_aload.
|
||||
SigSpec sig_ad;
|
||||
// The sync clock, present if has_clk.
|
||||
SigSpec sig_clk;
|
||||
SigSpec sig_en;
|
||||
// The clock enable, present if has_ce.
|
||||
SigSpec sig_ce;
|
||||
// The async load enable, present if has_aload.
|
||||
SigSpec sig_aload;
|
||||
// The async reset, preset if has_arst.
|
||||
SigSpec sig_arst;
|
||||
// The sync reset, preset if has_srst.
|
||||
SigSpec sig_srst;
|
||||
// The async clear (per-lane), present if has_sr.
|
||||
SigSpec sig_clr;
|
||||
// The async set (per-lane), present if has_sr.
|
||||
SigSpec sig_set;
|
||||
bool has_d;
|
||||
// True if this is a clocked (edge-sensitive) flip-flop.
|
||||
bool has_clk;
|
||||
bool has_en;
|
||||
// True if this is a $ff, exclusive with every other has_*.
|
||||
bool has_gclk;
|
||||
// True if this FF has a clock enable. Depends on has_clk.
|
||||
bool has_ce;
|
||||
// True if this FF has async load function — this includes D latches.
|
||||
// If this and has_clk are both set, has_arst and has_sr cannot be set.
|
||||
bool has_aload;
|
||||
// True if this FF has sync set/reset. Depends on has_clk, exclusive
|
||||
// with has_arst, has_sr, has_aload.
|
||||
bool has_srst;
|
||||
// True if this FF has async set/reset. Exclusive with has_srst,
|
||||
// has_sr. If this and has_clk are both set, has_aload cannot be set.
|
||||
bool has_arst;
|
||||
// True if this FF has per-bit async set + clear. Exclusive with
|
||||
// has_srst, has_arst. If this and has_clk are both set, has_aload
|
||||
// cannot be set.
|
||||
bool has_sr;
|
||||
// If has_ce and has_srst are both set, determines their relative
|
||||
// priorities: if true, inactive ce disables srst; if false, srst
|
||||
// operates independent of ce.
|
||||
bool ce_over_srst;
|
||||
// True if this FF is a fine cell, false if it is a coarse cell.
|
||||
// If true, width must be 1.
|
||||
bool is_fine;
|
||||
// Polarities, corresponding to sig_*. True means active-high, false
|
||||
// means active-low.
|
||||
bool pol_clk;
|
||||
bool pol_en;
|
||||
bool pol_ce;
|
||||
bool pol_aload;
|
||||
bool pol_arst;
|
||||
bool pol_srst;
|
||||
bool pol_clr;
|
||||
bool pol_set;
|
||||
// The value loaded by sig_arst.
|
||||
Const val_arst;
|
||||
// The value loaded by sig_srst.
|
||||
Const val_srst;
|
||||
// The initial value at power-up.
|
||||
Const val_init;
|
||||
Const val_d;
|
||||
bool d_is_const;
|
||||
// The FF data width in bits.
|
||||
int width;
|
||||
dict<IdString, Const> attributes;
|
||||
|
||||
FfData(FfInitVals *initvals, Cell *cell = nullptr) : initvals(initvals) {
|
||||
FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
|
||||
width = 0;
|
||||
has_d = true;
|
||||
has_clk = false;
|
||||
has_en = false;
|
||||
has_gclk = false;
|
||||
has_ce = false;
|
||||
has_aload = false;
|
||||
has_srst = false;
|
||||
has_arst = false;
|
||||
has_sr = false;
|
||||
ce_over_srst = false;
|
||||
is_fine = false;
|
||||
pol_clk = false;
|
||||
pol_en = false;
|
||||
pol_aload = false;
|
||||
pol_ce = false;
|
||||
pol_arst = false;
|
||||
pol_srst = false;
|
||||
pol_clr = false;
|
||||
pol_set = false;
|
||||
d_is_const = false;
|
||||
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
sig_q = cell->getPort(ID::Q);
|
||||
width = GetSize(sig_q);
|
||||
attributes = cell->attributes;
|
||||
|
||||
if (initvals)
|
||||
val_init = (*initvals)(sig_q);
|
||||
|
||||
std::string type_str = cell->type.str();
|
||||
|
||||
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
|
||||
if (cell->type == ID($sr)) {
|
||||
has_d = false;
|
||||
} else {
|
||||
sig_d = cell->getPort(ID::D);
|
||||
}
|
||||
if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
|
||||
has_clk = true;
|
||||
sig_clk = cell->getPort(ID::CLK);
|
||||
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
|
||||
}
|
||||
if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
|
||||
has_en = true;
|
||||
sig_en = cell->getPort(ID::EN);
|
||||
pol_en = cell->getParam(ID::EN_POLARITY).as_bool();
|
||||
}
|
||||
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
|
||||
has_sr = true;
|
||||
sig_clr = cell->getPort(ID::CLR);
|
||||
sig_set = cell->getPort(ID::SET);
|
||||
pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
|
||||
pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
|
||||
}
|
||||
if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
|
||||
has_arst = true;
|
||||
sig_arst = cell->getPort(ID::ARST);
|
||||
pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
|
||||
val_arst = cell->getParam(ID::ARST_VALUE);
|
||||
}
|
||||
if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
|
||||
has_srst = true;
|
||||
sig_srst = cell->getPort(ID::SRST);
|
||||
pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
|
||||
val_srst = cell->getParam(ID::SRST_VALUE);
|
||||
ce_over_srst = cell->type == ID($sdffce);
|
||||
}
|
||||
} else if (cell->type == ID($_FF_)) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
} else if (type_str.substr(0, 5) == "$_SR_") {
|
||||
is_fine = true;
|
||||
has_d = false;
|
||||
has_sr = true;
|
||||
pol_set = type_str[5] == 'P';
|
||||
pol_clr = type_str[6] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[6] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_en = true;
|
||||
pol_en = type_str[8] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[6] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[7] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[8] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[8] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
|
||||
has_en = true;
|
||||
pol_en = type_str[10] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[8] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_sr = true;
|
||||
pol_set = type_str[9] == 'P';
|
||||
pol_clr = type_str[10] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[9] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_sr = true;
|
||||
pol_set = type_str[10] == 'P';
|
||||
pol_clr = type_str[11] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
has_en = true;
|
||||
pol_en = type_str[12] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[7] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[8] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[9] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[8] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[9] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
|
||||
has_en = true;
|
||||
pol_en = type_str[11] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_clk = true;
|
||||
pol_clk = type_str[9] == 'P';
|
||||
sig_clk = cell->getPort(ID::C);
|
||||
has_srst = true;
|
||||
pol_srst = type_str[10] == 'P';
|
||||
sig_srst = cell->getPort(ID::R);
|
||||
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
|
||||
has_en = true;
|
||||
pol_en = type_str[12] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
ce_over_srst = true;
|
||||
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_en = true;
|
||||
pol_en = type_str[9] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_en = true;
|
||||
pol_en = type_str[9] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
has_arst = true;
|
||||
pol_arst = type_str[10] == 'P';
|
||||
sig_arst = cell->getPort(ID::R);
|
||||
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
|
||||
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
|
||||
is_fine = true;
|
||||
sig_d = cell->getPort(ID::D);
|
||||
has_en = true;
|
||||
pol_en = type_str[11] == 'P';
|
||||
sig_en = cell->getPort(ID::E);
|
||||
has_sr = true;
|
||||
pol_set = type_str[12] == 'P';
|
||||
pol_clr = type_str[13] == 'P';
|
||||
sig_set = cell->getPort(ID::S);
|
||||
sig_clr = cell->getPort(ID::R);
|
||||
} else {
|
||||
log_assert(0);
|
||||
}
|
||||
if (has_d && sig_d.is_fully_const()) {
|
||||
d_is_const = true;
|
||||
val_d = sig_d.as_const();
|
||||
if (has_en && !has_clk && !has_sr && !has_arst) {
|
||||
// Plain D latches with const D treated specially.
|
||||
has_en = has_d = false;
|
||||
has_arst = true;
|
||||
sig_arst = sig_en;
|
||||
pol_arst = pol_en;
|
||||
val_arst = val_d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FfData(FfInitVals *initvals, Cell *cell_);
|
||||
|
||||
// Returns a FF identical to this one, but only keeping bit indices from the argument.
|
||||
FfData slice(const std::vector<int> &bits) {
|
||||
FfData res(initvals);
|
||||
res.sig_clk = sig_clk;
|
||||
res.sig_en = sig_en;
|
||||
res.sig_arst = sig_arst;
|
||||
res.sig_srst = sig_srst;
|
||||
res.has_d = has_d;
|
||||
res.has_clk = has_clk;
|
||||
res.has_en = has_en;
|
||||
res.has_arst = has_arst;
|
||||
res.has_srst = has_srst;
|
||||
res.has_sr = has_sr;
|
||||
res.ce_over_srst = ce_over_srst;
|
||||
res.is_fine = is_fine;
|
||||
res.pol_clk = pol_clk;
|
||||
res.pol_en = pol_en;
|
||||
res.pol_arst = pol_arst;
|
||||
res.pol_srst = pol_srst;
|
||||
res.pol_clr = pol_clr;
|
||||
res.pol_set = pol_set;
|
||||
res.attributes = attributes;
|
||||
for (int i : bits) {
|
||||
res.sig_q.append(sig_q[i]);
|
||||
if (has_d)
|
||||
res.sig_d.append(sig_d[i]);
|
||||
if (has_sr) {
|
||||
res.sig_clr.append(sig_clr[i]);
|
||||
res.sig_set.append(sig_set[i]);
|
||||
}
|
||||
if (has_arst)
|
||||
res.val_arst.bits.push_back(val_arst[i]);
|
||||
if (has_srst)
|
||||
res.val_srst.bits.push_back(val_srst[i]);
|
||||
res.val_init.bits.push_back(val_init[i]);
|
||||
}
|
||||
res.width = GetSize(res.sig_q);
|
||||
// Slicing bits out may cause D to become const.
|
||||
if (has_d && res.sig_d.is_fully_const()) {
|
||||
res.d_is_const = true;
|
||||
res.val_d = res.sig_d.as_const();
|
||||
}
|
||||
return res;
|
||||
FfData slice(const std::vector<int> &bits);
|
||||
|
||||
void add_dummy_ce();
|
||||
void add_dummy_srst();
|
||||
void add_dummy_arst();
|
||||
void add_dummy_aload();
|
||||
void add_dummy_sr();
|
||||
void add_dummy_clk();
|
||||
|
||||
void arst_to_aload();
|
||||
void arst_to_sr();
|
||||
|
||||
void aload_to_sr();
|
||||
|
||||
// Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and
|
||||
// fixes up control signals appropriately to preserve semantics.
|
||||
void convert_ce_over_srst(bool val);
|
||||
|
||||
void unmap_ce();
|
||||
void unmap_srst();
|
||||
|
||||
void unmap_ce_srst() {
|
||||
unmap_ce();
|
||||
unmap_srst();
|
||||
}
|
||||
|
||||
void unmap_ce(Module *module) {
|
||||
if (!has_en)
|
||||
return;
|
||||
log_assert(has_clk);
|
||||
if (has_srst && ce_over_srst)
|
||||
unmap_srst(module);
|
||||
Cell *emit();
|
||||
|
||||
if (!is_fine) {
|
||||
if (pol_en)
|
||||
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
|
||||
else
|
||||
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
|
||||
} else {
|
||||
if (pol_en)
|
||||
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
|
||||
else
|
||||
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
|
||||
}
|
||||
has_en = false;
|
||||
// Removes init attribute from the Q output, but keeps val_init unchanged.
|
||||
// It will be automatically reattached on emit. Use this before changing sig_q.
|
||||
void remove_init() {
|
||||
if (initvals)
|
||||
initvals->remove_init(sig_q);
|
||||
}
|
||||
|
||||
void unmap_srst(Module *module) {
|
||||
if (!has_srst)
|
||||
return;
|
||||
if (has_en && !ce_over_srst)
|
||||
unmap_ce(module);
|
||||
void remove();
|
||||
|
||||
if (!is_fine) {
|
||||
if (pol_srst)
|
||||
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
|
||||
else
|
||||
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
|
||||
} else {
|
||||
if (pol_srst)
|
||||
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
|
||||
else
|
||||
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
|
||||
}
|
||||
has_srst = false;
|
||||
}
|
||||
|
||||
void unmap_ce_srst(Module *module) {
|
||||
unmap_ce(module);
|
||||
unmap_srst(module);
|
||||
}
|
||||
|
||||
Cell *emit(Module *module, IdString name) {
|
||||
if (!width)
|
||||
return nullptr;
|
||||
if (!has_d && !has_sr) {
|
||||
if (has_arst) {
|
||||
// Convert this case to a D latch.
|
||||
has_d = has_en = true;
|
||||
has_arst = false;
|
||||
sig_d = val_arst;
|
||||
sig_en = sig_arst;
|
||||
pol_en = pol_arst;
|
||||
} else {
|
||||
// No control inputs left. Turn into a const driver.
|
||||
initvals->remove_init(sig_q);
|
||||
module->connect(sig_q, val_init);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
initvals->set_init(sig_q, val_init);
|
||||
Cell *cell;
|
||||
if (!is_fine) {
|
||||
if (!has_d) {
|
||||
log_assert(has_sr);
|
||||
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
||||
} else if (!has_clk && !has_en) {
|
||||
log_assert(!has_arst);
|
||||
log_assert(!has_srst);
|
||||
log_assert(!has_sr);
|
||||
cell = module->addFf(name, sig_d, sig_q);
|
||||
} else if (!has_clk) {
|
||||
log_assert(!has_srst);
|
||||
if (has_sr)
|
||||
cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
|
||||
else if (has_arst)
|
||||
cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
|
||||
else
|
||||
cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
|
||||
} else {
|
||||
if (has_sr) {
|
||||
if (has_en)
|
||||
cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
|
||||
else
|
||||
cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
|
||||
} else if (has_arst) {
|
||||
if (has_en)
|
||||
cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
|
||||
else
|
||||
cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
|
||||
} else if (has_srst) {
|
||||
if (has_en)
|
||||
if (ce_over_srst)
|
||||
cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
|
||||
else
|
||||
cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
|
||||
else
|
||||
cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
|
||||
} else {
|
||||
if (has_en)
|
||||
cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
|
||||
else
|
||||
cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!has_d) {
|
||||
log_assert(has_sr);
|
||||
cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
||||
} else if (!has_clk && !has_en) {
|
||||
log_assert(!has_arst);
|
||||
log_assert(!has_srst);
|
||||
log_assert(!has_sr);
|
||||
cell = module->addFfGate(name, sig_d, sig_q);
|
||||
} else if (!has_clk) {
|
||||
log_assert(!has_srst);
|
||||
if (has_sr)
|
||||
cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
|
||||
else if (has_arst)
|
||||
cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
|
||||
else
|
||||
cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
|
||||
} else {
|
||||
if (has_sr) {
|
||||
if (has_en)
|
||||
cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
|
||||
else
|
||||
cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
|
||||
} else if (has_arst) {
|
||||
if (has_en)
|
||||
cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, pol_arst);
|
||||
else
|
||||
cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
|
||||
} else if (has_srst) {
|
||||
if (has_en)
|
||||
if (ce_over_srst)
|
||||
cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
|
||||
else
|
||||
cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
|
||||
else
|
||||
cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
|
||||
} else {
|
||||
if (has_en)
|
||||
cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
|
||||
else
|
||||
cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
|
||||
}
|
||||
}
|
||||
}
|
||||
cell->attributes = attributes;
|
||||
return cell;
|
||||
}
|
||||
// Flip the sense of the given bit slices of the FF: insert inverters on data
|
||||
// inputs and output, flip the corresponding init/reset bits, swap clr/set
|
||||
// inputs with proper priority fix.
|
||||
void flip_bits(const pool<int> &bits);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -28,7 +28,6 @@ YOSYS_NAMESPACE_BEGIN
|
|||
struct FfInitVals
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
RTLIL::Module *module;
|
||||
dict<SigBit, std::pair<State,SigBit>> initbits;
|
||||
|
||||
void set(const SigMap *sigmap_, RTLIL::Module *module)
|
||||
|
|
359
kernel/ffmerge.cc
Normal file
359
kernel/ffmerge.cc
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
|
||||
*
|
||||
* 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/ffmerge.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) {
|
||||
for (auto bit : (*sigmap)(sig))
|
||||
if (sigbit_users_count[bit] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
|
||||
ff = FfData(module, initvals, NEW_ID);
|
||||
sigmap->apply(sig);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto bit : sig)
|
||||
{
|
||||
if (bit.wire == NULL || sigbit_users_count[bit] == 0) {
|
||||
ff.width++;
|
||||
ff.sig_q.append(bit);
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sigbit_users_count[bit] != 1)
|
||||
return false;
|
||||
|
||||
auto &sinks = dff_sink[bit];
|
||||
if (sinks.size() != 1)
|
||||
return false;
|
||||
|
||||
Cell *cell;
|
||||
int idx;
|
||||
std::tie(cell, idx) = *sinks.begin();
|
||||
bits.insert(std::make_pair(cell, idx));
|
||||
|
||||
FfData cur_ff(initvals, cell);
|
||||
|
||||
// Reject latches and $ff.
|
||||
if (!cur_ff.has_clk)
|
||||
return false;
|
||||
|
||||
log_assert((*sigmap)(cur_ff.sig_d[idx]) == bit);
|
||||
|
||||
if (!found) {
|
||||
ff.sig_clk = cur_ff.sig_clk;
|
||||
ff.sig_ce = cur_ff.sig_ce;
|
||||
ff.sig_aload = cur_ff.sig_aload;
|
||||
ff.sig_srst = cur_ff.sig_srst;
|
||||
ff.sig_arst = cur_ff.sig_arst;
|
||||
ff.has_clk = cur_ff.has_clk;
|
||||
ff.has_ce = cur_ff.has_ce;
|
||||
ff.has_aload = cur_ff.has_aload;
|
||||
ff.has_srst = cur_ff.has_srst;
|
||||
ff.has_arst = cur_ff.has_arst;
|
||||
ff.has_sr = cur_ff.has_sr;
|
||||
ff.ce_over_srst = cur_ff.ce_over_srst;
|
||||
ff.pol_clk = cur_ff.pol_clk;
|
||||
ff.pol_ce = cur_ff.pol_ce;
|
||||
ff.pol_aload = cur_ff.pol_aload;
|
||||
ff.pol_arst = cur_ff.pol_arst;
|
||||
ff.pol_srst = cur_ff.pol_srst;
|
||||
ff.pol_clr = cur_ff.pol_clr;
|
||||
ff.pol_set = cur_ff.pol_set;
|
||||
} else {
|
||||
if (ff.has_clk != cur_ff.has_clk)
|
||||
return false;
|
||||
if (ff.has_ce != cur_ff.has_ce)
|
||||
return false;
|
||||
if (ff.has_aload != cur_ff.has_aload)
|
||||
return false;
|
||||
if (ff.has_srst != cur_ff.has_srst)
|
||||
return false;
|
||||
if (ff.has_arst != cur_ff.has_arst)
|
||||
return false;
|
||||
if (ff.has_sr != cur_ff.has_sr)
|
||||
return false;
|
||||
if (ff.has_clk) {
|
||||
if (ff.sig_clk != cur_ff.sig_clk)
|
||||
return false;
|
||||
if (ff.pol_clk != cur_ff.pol_clk)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_ce) {
|
||||
if (ff.sig_ce != cur_ff.sig_ce)
|
||||
return false;
|
||||
if (ff.pol_ce != cur_ff.pol_ce)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_aload) {
|
||||
if (ff.sig_aload != cur_ff.sig_aload)
|
||||
return false;
|
||||
if (ff.pol_aload != cur_ff.pol_aload)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_srst) {
|
||||
if (ff.sig_srst != cur_ff.sig_srst)
|
||||
return false;
|
||||
if (ff.pol_srst != cur_ff.pol_srst)
|
||||
return false;
|
||||
if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_arst) {
|
||||
if (ff.sig_arst != cur_ff.sig_arst)
|
||||
return false;
|
||||
if (ff.pol_arst != cur_ff.pol_arst)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_sr) {
|
||||
if (ff.pol_clr != cur_ff.pol_clr)
|
||||
return false;
|
||||
if (ff.pol_set != cur_ff.pol_set)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ff.width++;
|
||||
ff.sig_d.append(cur_ff.sig_d[idx]);
|
||||
ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
|
||||
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]);
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
|
||||
ff = FfData(module, initvals, NEW_ID);
|
||||
sigmap->apply(sig);
|
||||
|
||||
bool found = false;
|
||||
|
||||
pool<int> const_bits;
|
||||
|
||||
for (auto bit : sig)
|
||||
{
|
||||
if (bit.wire == NULL) {
|
||||
const_bits.insert(ff.width);
|
||||
ff.width++;
|
||||
ff.sig_q.append(bit);
|
||||
ff.sig_d.append(bit);
|
||||
// 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);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!dff_driver.count(bit))
|
||||
return false;
|
||||
|
||||
Cell *cell;
|
||||
int idx;
|
||||
std::tie(cell, idx) = dff_driver[bit];
|
||||
bits.insert(std::make_pair(cell, idx));
|
||||
|
||||
FfData cur_ff(initvals, cell);
|
||||
|
||||
log_assert((*sigmap)(cur_ff.sig_q[idx]) == bit);
|
||||
|
||||
if (!found) {
|
||||
ff.sig_clk = cur_ff.sig_clk;
|
||||
ff.sig_ce = cur_ff.sig_ce;
|
||||
ff.sig_aload = cur_ff.sig_aload;
|
||||
ff.sig_srst = cur_ff.sig_srst;
|
||||
ff.sig_arst = cur_ff.sig_arst;
|
||||
ff.has_clk = cur_ff.has_clk;
|
||||
ff.has_gclk = cur_ff.has_gclk;
|
||||
ff.has_ce = cur_ff.has_ce;
|
||||
ff.has_aload = cur_ff.has_aload;
|
||||
ff.has_srst = cur_ff.has_srst;
|
||||
ff.has_arst = cur_ff.has_arst;
|
||||
ff.has_sr = cur_ff.has_sr;
|
||||
ff.ce_over_srst = cur_ff.ce_over_srst;
|
||||
ff.pol_clk = cur_ff.pol_clk;
|
||||
ff.pol_ce = cur_ff.pol_ce;
|
||||
ff.pol_aload = cur_ff.pol_aload;
|
||||
ff.pol_arst = cur_ff.pol_arst;
|
||||
ff.pol_srst = cur_ff.pol_srst;
|
||||
ff.pol_clr = cur_ff.pol_clr;
|
||||
ff.pol_set = cur_ff.pol_set;
|
||||
} else {
|
||||
if (ff.has_gclk != cur_ff.has_gclk)
|
||||
return false;
|
||||
if (ff.has_clk != cur_ff.has_clk)
|
||||
return false;
|
||||
if (ff.has_ce != cur_ff.has_ce)
|
||||
return false;
|
||||
if (ff.has_aload != cur_ff.has_aload)
|
||||
return false;
|
||||
if (ff.has_srst != cur_ff.has_srst)
|
||||
return false;
|
||||
if (ff.has_arst != cur_ff.has_arst)
|
||||
return false;
|
||||
if (ff.has_sr != cur_ff.has_sr)
|
||||
return false;
|
||||
if (ff.has_clk) {
|
||||
if (ff.sig_clk != cur_ff.sig_clk)
|
||||
return false;
|
||||
if (ff.pol_clk != cur_ff.pol_clk)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_ce) {
|
||||
if (ff.sig_ce != cur_ff.sig_ce)
|
||||
return false;
|
||||
if (ff.pol_ce != cur_ff.pol_ce)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_aload) {
|
||||
if (ff.sig_aload != cur_ff.sig_aload)
|
||||
return false;
|
||||
if (ff.pol_aload != cur_ff.pol_aload)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_srst) {
|
||||
if (ff.sig_srst != cur_ff.sig_srst)
|
||||
return false;
|
||||
if (ff.pol_srst != cur_ff.pol_srst)
|
||||
return false;
|
||||
if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_arst) {
|
||||
if (ff.sig_arst != cur_ff.sig_arst)
|
||||
return false;
|
||||
if (ff.pol_arst != cur_ff.pol_arst)
|
||||
return false;
|
||||
}
|
||||
if (ff.has_sr) {
|
||||
if (ff.pol_clr != cur_ff.pol_clr)
|
||||
return false;
|
||||
if (ff.pol_set != cur_ff.pol_set)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ff.width++;
|
||||
ff.sig_d.append((ff.has_clk || ff.has_gclk) ? cur_ff.sig_d[idx] : State::Sx);
|
||||
ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
|
||||
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]);
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && ff.has_sr) {
|
||||
for (auto i: const_bits) {
|
||||
if (ff.sig_d[i] == State::S0) {
|
||||
ff.sig_set[i] = ff.pol_set ? State::S0 : State::S1;
|
||||
} else if (ff.sig_d[i] == State::S1) {
|
||||
ff.sig_clr[i] = ff.pol_clr ? State::S0 : State::S1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
void FfMergeHelper::remove_output_ff(const pool<std::pair<Cell *, int>> &bits) {
|
||||
for (auto &it : bits) {
|
||||
Cell *cell = it.first;
|
||||
int idx = it.second;
|
||||
SigSpec q = cell->getPort(ID::Q);
|
||||
initvals->remove_init(q[idx]);
|
||||
dff_driver.erase((*sigmap)(q[idx]));
|
||||
q[idx] = module->addWire(stringf("$ffmerge_disconnected$%d", autoidx++));
|
||||
cell->setPort(ID::Q, q);
|
||||
}
|
||||
}
|
||||
|
||||
void FfMergeHelper::mark_input_ff(const pool<std::pair<Cell *, int>> &bits) {
|
||||
for (auto &it : bits) {
|
||||
Cell *cell = it.first;
|
||||
int idx = it.second;
|
||||
if (cell->hasPort(ID::D)) {
|
||||
SigSpec d = cell->getPort(ID::D);
|
||||
// The user count was already at least 1
|
||||
// (for the D port). Bump it as it is now connected
|
||||
// to the merged-to cell as well. This suffices for
|
||||
// it to not be considered for output merging.
|
||||
sigbit_users_count[d[idx]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FfMergeHelper::set(FfInitVals *initvals_, RTLIL::Module *module_)
|
||||
{
|
||||
clear();
|
||||
initvals = initvals_;
|
||||
sigmap = initvals->sigmap;
|
||||
module = module_;
|
||||
|
||||
for (auto wire : module->wires()) {
|
||||
if (wire->port_output)
|
||||
for (auto bit : (*sigmap)(wire))
|
||||
sigbit_users_count[bit]++;
|
||||
}
|
||||
|
||||
for (auto cell : module->cells()) {
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
if (cell->hasPort(ID::D)) {
|
||||
SigSpec d = (*sigmap)(cell->getPort(ID::D));
|
||||
for (int i = 0; i < GetSize(d); i++)
|
||||
dff_sink[d[i]].insert(std::make_pair(cell, i));
|
||||
}
|
||||
SigSpec q = (*sigmap)(cell->getPort(ID::Q));
|
||||
for (int i = 0; i < GetSize(q); i++)
|
||||
dff_driver[q[i]] = std::make_pair(cell, i);
|
||||
}
|
||||
for (auto &conn : cell->connections())
|
||||
if (!cell->known() || cell->input(conn.first))
|
||||
for (auto bit : (*sigmap)(conn.second))
|
||||
sigbit_users_count[bit]++;
|
||||
}
|
||||
}
|
||||
|
||||
void FfMergeHelper::clear() {
|
||||
dff_driver.clear();
|
||||
dff_sink.clear();
|
||||
sigbit_users_count.clear();
|
||||
}
|
141
kernel/ffmerge.h
Normal file
141
kernel/ffmerge.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FFMERGE_H
|
||||
#define FFMERGE_H
|
||||
|
||||
#include "kernel/ffinit.h"
|
||||
#include "kernel/ff.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// A helper class for passes that want to merge FFs on the input or output
|
||||
// of a cell into the cell itself.
|
||||
//
|
||||
// The procedure is:
|
||||
//
|
||||
// 1. Construct this class (at beginning of processing for a given module).
|
||||
// 2. For every considered cell:
|
||||
//
|
||||
// a. Call find_output_ff for every considered output.
|
||||
// b. Call find_input_ff for every considered input.
|
||||
// c. Look at the FF description returned (if any) from each call, reject
|
||||
// results that cannot be merged into given cell for any reason.
|
||||
// If both inputs and outputs are being merged, take care of FF bits that
|
||||
// are returned in both input and output results (a FF bit cannot be
|
||||
// merged to both). Decide on the final set of FF bits to merge.
|
||||
// d. Call remove_output_ff for every find_output_ff result that will be used
|
||||
// for merging. This removes the actual FF bits from design and from index.
|
||||
// e. Call mark_input_ff for every find_input_ff result that will be used
|
||||
// for merging. This updates the index disallowing further usage of these
|
||||
// FF bits for output FF merging, if they were eligible before. The actual
|
||||
// FF bits are still left in the design and can be merged into other inputs.
|
||||
// If the FF bits are not otherwise used, they will be removed by later
|
||||
// opt passes.
|
||||
// f. Merge the FFs into the cell.
|
||||
//
|
||||
// Note that, if both inputs and outputs are being considered for merging in
|
||||
// a single pass, the result may be nondeterministic (depending on cell iteration
|
||||
// order) because a given FF bit could be eligible for both input and output merge,
|
||||
// perhaps in different cells. For this reason, it may be a good idea to separate
|
||||
// input and output merging.
|
||||
|
||||
struct FfMergeHelper
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
RTLIL::Module *module;
|
||||
FfInitVals *initvals;
|
||||
|
||||
dict<SigBit, std::pair<Cell*, int>> dff_driver;
|
||||
dict<SigBit, pool<std::pair<Cell*, int>>> dff_sink;
|
||||
dict<SigBit, int> sigbit_users_count;
|
||||
|
||||
// Returns true if all bits in sig are completely unused.
|
||||
bool is_output_unused(RTLIL::SigSpec sig);
|
||||
|
||||
// Finds the FF to merge into a given cell output. Takes sig, which
|
||||
// is the current cell output — it will be the sig_d of the found FF.
|
||||
// If found, returns true, and fills the two output arguments.
|
||||
//
|
||||
// For every bit of sig, this function finds a FF bit that has
|
||||
// the same sig_d, and fills the output FfData according to the FF
|
||||
// bits found. This function will only consider FF bits that are
|
||||
// the only user of the given sig bits — if any bit in sig is used
|
||||
// by anything other than a single FF, this function will return false.
|
||||
//
|
||||
// The returned FfData structure does not correspond to any actual FF
|
||||
// cell in the design — it is the amalgamation of extracted FF bits,
|
||||
// possibly coming from several FF cells.
|
||||
//
|
||||
// If some of the bits in sig have no users at all, this function
|
||||
// will accept them as well (and fill returned FfData with dummy values
|
||||
// for the given bit, effectively synthesizing an unused FF bit of the
|
||||
// appropriate type). However, if all bits in sig are completely
|
||||
// unused, this function will fail and return false (having no idea
|
||||
// what kind of FF to produce) — use the above helper if that case
|
||||
// is important to handle.
|
||||
//
|
||||
// Note that this function does not remove the FF bits returned from
|
||||
// the design — this is so that the caller can decide whether to accept
|
||||
// this FF for merging or not. If the result is accepted,
|
||||
// remove_output_ff should be called on the second output argument.
|
||||
bool find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);
|
||||
|
||||
// Like above, but returns a FF to merge into a given cell input. Takes
|
||||
// sig_q, which is the current cell input — it will search for FFs with
|
||||
// matching sig_q.
|
||||
//
|
||||
// As opposed to find_output_ff, this function doesn't care about usage
|
||||
// counts, and may return FF bits that also have other fanout. This
|
||||
// should not be a problem for input FF merging.
|
||||
//
|
||||
// As a special case, if some of the bits in sig_q are constant, this
|
||||
// function will accept them as well, by synthesizing in-place
|
||||
// a constant-input FF bit (with matching initial value and reset value).
|
||||
// However, this will not work if the input is all-constant — if the caller
|
||||
// cares about this case, it needs to check for it explicitely.
|
||||
bool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);
|
||||
|
||||
// To be called on find_output_ff result that will be merged. This
|
||||
// marks the given FF bits as used up (and not to be considered for
|
||||
// further merging as inputs), and reconnects their Q ports to a dummy
|
||||
// wire (since the wire previously connected there will now be driven
|
||||
// by the merged-to cell instead).
|
||||
void remove_output_ff(const pool<std::pair<Cell *, int>> &bits);
|
||||
|
||||
// To be called on find_input_ff result that will be merged. This
|
||||
// marks the given FF bits as used, and disallows merging them as
|
||||
// outputs. They can, however, still be merged as inputs again
|
||||
// (perhaps for another cell).
|
||||
void mark_input_ff(const pool<std::pair<Cell *, int>> &bits);
|
||||
|
||||
void set(FfInitVals *initvals_, RTLIL::Module *module_);
|
||||
|
||||
void clear();
|
||||
|
||||
FfMergeHelper(FfInitVals *initvals, RTLIL::Module *module) {
|
||||
set(initvals, module);
|
||||
}
|
||||
|
||||
FfMergeHelper() {}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
252
kernel/fstdata.cc
Normal file
252
kernel/fstdata.cc
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2022 Miodrag Milanovic <micko@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/fstdata.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
|
||||
FstData::FstData(std::string filename) : ctx(nullptr)
|
||||
{
|
||||
const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
|
||||
ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
|
||||
if (!ctx)
|
||||
log_error("Error opening '%s'\n", filename.c_str());
|
||||
int scale = (int)fstReaderGetTimescale(ctx);
|
||||
timescale = pow(10.0, scale);
|
||||
timescale_str = "";
|
||||
int unit = 0;
|
||||
int zeros = 0;
|
||||
if (scale > 0) {
|
||||
zeros = scale;
|
||||
} else {
|
||||
if ((scale % 3) == 0) {
|
||||
zeros = (-scale % 3);
|
||||
unit = (-scale / 3);
|
||||
} else {
|
||||
zeros = 3 - (-scale % 3);
|
||||
unit = (-scale / 3) + 1;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<zeros; i++) timescale_str += "0";
|
||||
timescale_str += g_units[unit];
|
||||
extractVarNames();
|
||||
}
|
||||
|
||||
FstData::~FstData()
|
||||
{
|
||||
if (ctx)
|
||||
fstReaderClose(ctx);
|
||||
}
|
||||
|
||||
uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
|
||||
|
||||
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
|
||||
|
||||
fstHandle FstData::getHandle(std::string name) {
|
||||
if (name_to_handle.find(name) != name_to_handle.end())
|
||||
return name_to_handle[name];
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
|
||||
static std::string remove_spaces(std::string str)
|
||||
{
|
||||
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
void FstData::extractVarNames()
|
||||
{
|
||||
struct fstHier *h;
|
||||
intptr_t snum = 0;
|
||||
|
||||
while ((h = fstReaderIterateHier(ctx))) {
|
||||
switch (h->htyp) {
|
||||
case FST_HT_SCOPE: {
|
||||
snum++;
|
||||
std::string fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, (void *)(snum));
|
||||
scopes.push_back(fst_scope_name);
|
||||
break;
|
||||
}
|
||||
case FST_HT_UPSCOPE: {
|
||||
fstReaderPopScope(ctx);
|
||||
snum = fstReaderGetCurrentScopeLen(ctx) ? (intptr_t)fstReaderGetCurrentScopeUserInfo(ctx) : 0;
|
||||
break;
|
||||
}
|
||||
case FST_HT_VAR: {
|
||||
FstVar var;
|
||||
var.id = h->u.var.handle;
|
||||
var.is_alias = h->u.var.is_alias;
|
||||
var.name = remove_spaces(h->u.var.name);
|
||||
var.scope = scopes.back();
|
||||
var.width = h->u.var.length;
|
||||
vars.push_back(var);
|
||||
if (!var.is_alias)
|
||||
handle_to_var[h->u.var.handle] = var;
|
||||
std::string clean_name;
|
||||
for(size_t i=0;i<strlen(h->u.var.name);i++)
|
||||
{
|
||||
char c = h->u.var.name[i];
|
||||
if(c==' ') break;
|
||||
clean_name += c;
|
||||
}
|
||||
if (clean_name[0]=='\\')
|
||||
clean_name = clean_name.substr(1);
|
||||
//log("adding %s.%s\n",var.scope.c_str(), clean_name.c_str());
|
||||
|
||||
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reconstruct_edges_varlen(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
|
||||
{
|
||||
FstData *ptr = (FstData*)user_data;
|
||||
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
|
||||
}
|
||||
|
||||
static void reconstruct_edges(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
|
||||
{
|
||||
FstData *ptr = (FstData*)user_data;
|
||||
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
|
||||
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
|
||||
}
|
||||
|
||||
void FstData::reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
||||
{
|
||||
std::string val = std::string((const char *)pnt_value);
|
||||
std::string prev = last_data[pnt_facidx];
|
||||
if (pnt_time>=start_time) {
|
||||
if (prev!="1" && val=="1")
|
||||
edges.push_back(pnt_time);
|
||||
if (prev!="0" && val=="0")
|
||||
edges.push_back(pnt_time);
|
||||
}
|
||||
last_data[pnt_facidx] = val;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> FstData::getAllEdges(std::vector<fstHandle> &signal, uint64_t start, uint64_t end)
|
||||
{
|
||||
start_time = start;
|
||||
end_time = end;
|
||||
last_data.clear();
|
||||
for(auto &s : signal) {
|
||||
last_data[s] = "x";
|
||||
}
|
||||
edges.clear();
|
||||
fstReaderSetLimitTimeRange(ctx, start_time, end_time);
|
||||
fstReaderClrFacProcessMaskAll(ctx);
|
||||
for(const auto sig : signal)
|
||||
fstReaderSetFacProcessMask(ctx,sig);
|
||||
fstReaderIterBlocks2(ctx, reconstruct_edges, reconstruct_edges_varlen, this, nullptr);
|
||||
return edges;
|
||||
}
|
||||
|
||||
static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
|
||||
{
|
||||
FstData *ptr = (FstData*)user_data;
|
||||
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
|
||||
}
|
||||
|
||||
static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
|
||||
{
|
||||
FstData *ptr = (FstData*)user_data;
|
||||
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
|
||||
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
|
||||
}
|
||||
|
||||
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
||||
{
|
||||
if (sample_times_ndx >= sample_times.size()) return;
|
||||
|
||||
uint64_t time = sample_times[sample_times_ndx];
|
||||
// if we are past the timestamp
|
||||
if (pnt_time > time) {
|
||||
for (auto const& c : last_data)
|
||||
{
|
||||
handle_to_data[c.first].push_back(std::make_pair(time,c.second));
|
||||
size_t index = handle_to_data[c.first].size() - 1;
|
||||
time_to_index[c.first][time] = index;
|
||||
}
|
||||
sample_times_ndx++;
|
||||
}
|
||||
// always update last_data
|
||||
last_data[pnt_facidx] = std::string((const char *)pnt_value);
|
||||
}
|
||||
|
||||
void FstData::reconstructAtTimes(std::vector<fstHandle> &signal, std::vector<uint64_t> time)
|
||||
{
|
||||
handle_to_data.clear();
|
||||
time_to_index.clear();
|
||||
last_data.clear();
|
||||
sample_times_ndx = 0;
|
||||
sample_times = time;
|
||||
fstReaderSetUnlimitedTimeRange(ctx);
|
||||
fstReaderClrFacProcessMaskAll(ctx);
|
||||
for(const auto sig : signal)
|
||||
fstReaderSetFacProcessMask(ctx,sig);
|
||||
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
||||
|
||||
if (time_to_index[signal.back()].count(time.back())==0) {
|
||||
for (auto const& c : last_data)
|
||||
{
|
||||
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
|
||||
size_t index = handle_to_data[c.first].size() - 1;
|
||||
time_to_index[c.first][time.back()] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FstData::reconstructAllAtTimes(std::vector<uint64_t> time)
|
||||
{
|
||||
handle_to_data.clear();
|
||||
time_to_index.clear();
|
||||
last_data.clear();
|
||||
sample_times_ndx = 0;
|
||||
sample_times = time;
|
||||
|
||||
fstReaderSetUnlimitedTimeRange(ctx);
|
||||
fstReaderSetFacProcessMaskAll(ctx);
|
||||
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
||||
|
||||
if (time_to_index[1].count(time.back())==0) {
|
||||
for (auto const& c : last_data)
|
||||
{
|
||||
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
|
||||
size_t index = handle_to_data[c.first].size() - 1;
|
||||
time_to_index[c.first][time.back()] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string FstData::valueAt(fstHandle signal, uint64_t time)
|
||||
{
|
||||
if (handle_to_data.find(signal) == handle_to_data.end())
|
||||
log_error("Signal id %d not found\n", (int)signal);
|
||||
auto &data = handle_to_data[signal];
|
||||
if (time_to_index[signal].count(time)!=0) {
|
||||
size_t index = time_to_index[signal][time];
|
||||
return data.at(index).second;
|
||||
} else {
|
||||
log_error("No data for signal %d at time %d\n", (int)signal, (int)time);
|
||||
}
|
||||
}
|
81
kernel/fstdata.h
Normal file
81
kernel/fstdata.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2022 Miodrag Milanovic <micko@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FSTDATA_H
|
||||
#define FSTDATA_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "libs/fst/fstapi.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct FstVar
|
||||
{
|
||||
fstHandle id;
|
||||
std::string name;
|
||||
bool is_alias;
|
||||
std::string scope;
|
||||
int width;
|
||||
};
|
||||
|
||||
class FstData
|
||||
{
|
||||
public:
|
||||
FstData(std::string filename);
|
||||
~FstData();
|
||||
|
||||
uint64_t getStartTime();
|
||||
uint64_t getEndTime();
|
||||
|
||||
std::vector<FstVar>& getVars() { return vars; };
|
||||
|
||||
void reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
|
||||
std::vector<uint64_t> getAllEdges(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time);
|
||||
|
||||
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
|
||||
void reconstructAtTimes(std::vector<fstHandle> &signal,std::vector<uint64_t> time);
|
||||
void reconstructAllAtTimes(std::vector<uint64_t> time);
|
||||
|
||||
std::string valueAt(fstHandle signal, uint64_t time);
|
||||
fstHandle getHandle(std::string name);
|
||||
double getTimescale() { return timescale; }
|
||||
const char *getTimescaleString() { return timescale_str.c_str(); }
|
||||
private:
|
||||
void extractVarNames();
|
||||
|
||||
struct fstReaderContext *ctx;
|
||||
std::vector<std::string> scopes;
|
||||
std::vector<FstVar> vars;
|
||||
std::map<fstHandle, FstVar> handle_to_var;
|
||||
std::map<std::string, fstHandle> name_to_handle;
|
||||
std::map<fstHandle, std::vector<std::pair<uint64_t, std::string>>> handle_to_data;
|
||||
std::map<fstHandle, std::string> last_data;
|
||||
std::map<fstHandle, std::map<uint64_t, size_t>> time_to_index;
|
||||
std::vector<uint64_t> sample_times;
|
||||
size_t sample_times_ndx;
|
||||
double timescale;
|
||||
std::string timescale_str;
|
||||
uint64_t start_time;
|
||||
uint64_t end_time;
|
||||
std::vector<uint64_t> edges;
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -6,7 +6,7 @@
|
|||
// means.
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Written by Clifford Wolf <clifford@clifford.at> in 2014
|
||||
// Written by Claire Xenia Wolf <claire@yosyshq.com> in 2014
|
||||
// -------------------------------------------------------
|
||||
|
||||
#ifndef HASHLIB_H
|
||||
|
@ -66,6 +66,12 @@ struct hash_int_ops {
|
|||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<bool> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(bool a) {
|
||||
return a ? 1 : 0;
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<int32_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(int32_t a) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -71,8 +71,6 @@ int string_buf_index = -1;
|
|||
static struct timeval initial_tv = { 0, 0 };
|
||||
static bool next_print_log = false;
|
||||
static int log_newline_count = 0;
|
||||
static bool check_expected_logs = true;
|
||||
static bool display_error_log_msg = true;
|
||||
|
||||
static void log_id_cache_clear()
|
||||
{
|
||||
|
@ -339,8 +337,7 @@ static void logv_error_with_prefix(const char *prefix,
|
|||
f = stderr;
|
||||
|
||||
log_last_error = vstringf(format, ap);
|
||||
if (display_error_log_msg)
|
||||
log("%s%s", prefix, log_last_error.c_str());
|
||||
log("%s%s", prefix, log_last_error.c_str());
|
||||
log_flush();
|
||||
|
||||
log_make_debug = bak_log_make_debug;
|
||||
|
@ -349,8 +346,7 @@ static void logv_error_with_prefix(const char *prefix,
|
|||
if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern))
|
||||
item.second.current_count++;
|
||||
|
||||
if (check_expected_logs)
|
||||
log_check_expected();
|
||||
log_check_expected();
|
||||
|
||||
if (log_error_atexit)
|
||||
log_error_atexit();
|
||||
|
@ -667,9 +663,14 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
|
|||
|
||||
void log_check_expected()
|
||||
{
|
||||
check_expected_logs = false;
|
||||
// copy out all of the expected logs so that they cannot be re-checked
|
||||
// or match against themselves
|
||||
dict<std::string, LogExpectedItem> expect_log, expect_warning, expect_error;
|
||||
std::swap(expect_warning, log_expect_warning);
|
||||
std::swap(expect_log, log_expect_log);
|
||||
std::swap(expect_error, log_expect_error);
|
||||
|
||||
for (auto &item : log_expect_warning) {
|
||||
for (auto &item : expect_warning) {
|
||||
if (item.second.current_count == 0) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
|
||||
|
@ -681,7 +682,7 @@ void log_check_expected()
|
|||
}
|
||||
}
|
||||
|
||||
for (auto &item : log_expect_log) {
|
||||
for (auto &item : expect_log) {
|
||||
if (item.second.current_count == 0) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
|
||||
|
@ -693,7 +694,7 @@ void log_check_expected()
|
|||
}
|
||||
}
|
||||
|
||||
for (auto &item : log_expect_error)
|
||||
for (auto &item : expect_error)
|
||||
if (item.second.current_count == item.second.expected_count) {
|
||||
log_warn_regexes.clear();
|
||||
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
|
||||
|
@ -705,7 +706,6 @@ void log_check_expected()
|
|||
_Exit(0);
|
||||
#endif
|
||||
} else {
|
||||
display_error_log_msg = false;
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
|
||||
}
|
||||
|
|
28
kernel/log.h
28
kernel/log.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -24,9 +24,29 @@
|
|||
|
||||
#include <time.h>
|
||||
|
||||
// In GCC 4.8 std::regex is not working correctlty, in order to make features
|
||||
// using regular expressions to work replacement regex library is used
|
||||
#if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8)
|
||||
// In the libstdc++ headers that are provided by GCC 4.8, std::regex is not
|
||||
// working correctly. In order to make features using regular expressions
|
||||
// work, a replacement regex library is used. Just checking for GCC version
|
||||
// is not enough though, because at least on RHEL7/CentOS7 even when compiling
|
||||
// with Clang instead of GCC, the GCC 4.8 headers are still used for std::regex.
|
||||
// We have to check the version of the libstdc++ headers specifically, not the
|
||||
// compiler version. GCC headers of libstdc++ before version 3.4 define
|
||||
// __GLIBCPP__, later versions define __GLIBCXX__. GCC 7 and newer additionaly
|
||||
// define _GLIBCXX_RELEASE with a version number.
|
||||
// Include limits std C++ header, so we get the version macros defined:
|
||||
#if defined(__cplusplus)
|
||||
# include <limits>
|
||||
#endif
|
||||
// Check if libstdc++ is from GCC
|
||||
#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
// Check if version could be 4.8 or lower (this also matches for some 4.9 and
|
||||
// 5.0 releases). See:
|
||||
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
|
||||
# if !defined(_GLIBCXX_RELEASE) && (defined(__GLIBCPP__) || __GLIBCXX__ <= 20150623)
|
||||
# define YS_HAS_BAD_STD_REGEX
|
||||
# endif
|
||||
#endif
|
||||
#if defined(YS_HAS_BAD_STD_REGEX)
|
||||
#include <boost/xpressive/xpressive.hpp>
|
||||
#define YS_REGEX_TYPE boost::xpressive::sregex
|
||||
#define YS_REGEX_MATCH_TYPE boost::xpressive::smatch
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
1388
kernel/mem.cc
1388
kernel/mem.cc
File diff suppressed because it is too large
Load diff
185
kernel/mem.h
185
kernel/mem.h
|
@ -21,38 +21,76 @@
|
|||
#define MEM_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/ffinit.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct MemRd {
|
||||
dict<IdString, Const> attributes;
|
||||
struct MemRd : RTLIL::AttrObject {
|
||||
bool removed;
|
||||
Cell *cell;
|
||||
bool clk_enable, clk_polarity;
|
||||
bool transparent;
|
||||
SigSpec clk, en, addr, data;
|
||||
MemRd() : cell(nullptr) {}
|
||||
int wide_log2;
|
||||
bool clk_enable, clk_polarity, ce_over_srst;
|
||||
Const arst_value, srst_value, init_value;
|
||||
// One bit for every write port, true iff simultanous read on this
|
||||
// port and write on the other port will bypass the written data
|
||||
// to this port's output (default behavior is to read old value).
|
||||
// Can only be set for write ports that have the same clock domain.
|
||||
std::vector<bool> transparency_mask;
|
||||
// One bit for every write port, true iff simultanous read on this
|
||||
// port and write on the other port will return an all-X (don't care)
|
||||
// value. Mutually exclusive with transparency_mask.
|
||||
// Can only be set for write ports that have the same clock domain.
|
||||
// For optimization purposes, this will also be set if we can
|
||||
// determine that the two ports can never be active simultanously
|
||||
// (making the above vacuously true).
|
||||
std::vector<bool> collision_x_mask;
|
||||
SigSpec clk, en, arst, srst, addr, data;
|
||||
|
||||
MemRd() : removed(false), cell(nullptr) {}
|
||||
|
||||
// Returns the address of given subword index accessed by this port.
|
||||
SigSpec sub_addr(int sub) {
|
||||
SigSpec res = addr;
|
||||
for (int i = 0; i < wide_log2; i++)
|
||||
res[i] = State(sub >> i & 1);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
struct MemWr {
|
||||
dict<IdString, Const> attributes;
|
||||
struct MemWr : RTLIL::AttrObject {
|
||||
bool removed;
|
||||
Cell *cell;
|
||||
int wide_log2;
|
||||
bool clk_enable, clk_polarity;
|
||||
std::vector<bool> priority_mask;
|
||||
SigSpec clk, en, addr, data;
|
||||
MemWr() : cell(nullptr) {}
|
||||
|
||||
MemWr() : removed(false), cell(nullptr) {}
|
||||
|
||||
// Returns the address of given subword index accessed by this port.
|
||||
SigSpec sub_addr(int sub) {
|
||||
SigSpec res = addr;
|
||||
for (int i = 0; i < wide_log2; i++)
|
||||
res[i] = State(sub >> i & 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<SigSpec, std::vector<int>> compress_en();
|
||||
SigSpec decompress_en(const std::vector<int> &swizzle, SigSpec sig);
|
||||
};
|
||||
|
||||
struct MemInit {
|
||||
dict<IdString, Const> attributes;
|
||||
struct MemInit : RTLIL::AttrObject {
|
||||
bool removed;
|
||||
Cell *cell;
|
||||
Const addr;
|
||||
Const data;
|
||||
MemInit() : cell(nullptr) {}
|
||||
Const en;
|
||||
MemInit() : removed(false), cell(nullptr) {}
|
||||
};
|
||||
|
||||
struct Mem {
|
||||
struct Mem : RTLIL::AttrObject {
|
||||
Module *module;
|
||||
IdString memid;
|
||||
dict<IdString, Const> attributes;
|
||||
bool packed;
|
||||
RTLIL::Memory *mem;
|
||||
Cell *cell;
|
||||
|
@ -61,15 +99,128 @@ struct Mem {
|
|||
std::vector<MemRd> rd_ports;
|
||||
std::vector<MemWr> wr_ports;
|
||||
|
||||
// Removes this memory from the module. The data in helper structures
|
||||
// is unaffected except for the cell/mem fields.
|
||||
void remove();
|
||||
|
||||
// Commits all changes in helper structures into the module — ports and
|
||||
// inits marked as removed are actually removed, new ports/inits create
|
||||
// new cells, modified port/inits are commited into their existing
|
||||
// cells. Note that this reindexes the ports and inits array (actually
|
||||
// removing the ports/inits marked as removed).
|
||||
void emit();
|
||||
void remove_wr_port(int idx);
|
||||
void remove_rd_port(int idx);
|
||||
|
||||
// Marks all inits as removed.
|
||||
void clear_inits();
|
||||
|
||||
// Coalesces inits: whenever two inits have overlapping or touching
|
||||
// address ranges, they are combined into one, with the higher-priority
|
||||
// one's data overwriting the other. Running this results in
|
||||
// an inits list equivalent to the original, in which all entries
|
||||
// cover disjoint (and non-touching) address ranges, and all enable
|
||||
// masks are all-1.
|
||||
void coalesce_inits();
|
||||
|
||||
// Checks consistency of this memory and all its ports/inits, using
|
||||
// log_assert.
|
||||
void check();
|
||||
|
||||
// Gathers all initialization data into a single big const covering
|
||||
// the whole memory. For all non-initialized bits, Sx will be returned.
|
||||
Const get_init_data() const;
|
||||
|
||||
// Constructs and returns the helper structures for all memories
|
||||
// in a module.
|
||||
static std::vector<Mem> get_all_memories(Module *module);
|
||||
|
||||
// Constructs and returns the helper structures for all selected
|
||||
// memories in a module.
|
||||
static std::vector<Mem> get_selected_memories(Module *module);
|
||||
Cell *extract_rdff(int idx);
|
||||
|
||||
// Converts a synchronous read port into an asynchronous one by
|
||||
// extracting the data (or, in some rare cases, address) register
|
||||
// into a separate cell, together with any soft-transparency
|
||||
// logic necessary to preserve its semantics. Returns the created
|
||||
// register cell, if any. Note that in some rare cases this function
|
||||
// may succeed and perform a conversion without creating a new
|
||||
// register — a nullptr result doesn't imply nothing was done.
|
||||
Cell *extract_rdff(int idx, FfInitVals *initvals);
|
||||
|
||||
// Splits all wide ports in this memory into equivalent narrow ones.
|
||||
// This function performs no modifications at all to the actual
|
||||
// netlist unless and until emit() is called.
|
||||
void narrow();
|
||||
|
||||
// If write port idx2 currently has priority over write port idx1,
|
||||
// inserts extra logic on idx1's enable signal to disable writes
|
||||
// when idx2 is writing to the same address, then removes the priority
|
||||
// from the priority mask. If there is a memory port that is
|
||||
// transparent with idx1, but not with idx2, that port is converted
|
||||
// to use soft transparency logic.
|
||||
void emulate_priority(int idx1, int idx2, FfInitVals *initvals);
|
||||
|
||||
// Creates soft-transparency logic on read port ridx, bypassing the
|
||||
// data from write port widx. Should only be called when ridx is
|
||||
// transparent wrt widx in the first place. Once we're done, the
|
||||
// transparency_mask bit will be cleared, and the collision_x_mask
|
||||
// bit will be set instead (since whatever value is read will be
|
||||
// replaced by the soft transparency logic).
|
||||
void emulate_transparency(int widx, int ridx, FfInitVals *initvals);
|
||||
|
||||
// Prepares for merging write port idx2 into idx1 (where idx1 < idx2).
|
||||
// Specifically, takes care of priority masks: any priority relations
|
||||
// that idx2 had are replicated onto idx1, unless they conflict with
|
||||
// priorities already present on idx1, in which case emulate_priority
|
||||
// is called. Likewise, ensures transparency and undefined collision
|
||||
// masks of all read ports have the same values for both ports,
|
||||
// calling emulate_transparency if necessary.
|
||||
void prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals);
|
||||
|
||||
// Prepares for merging read port idx2 into idx1.
|
||||
// Specifically, makes sure the transparency and undefined collision
|
||||
// masks of both ports are equal, by changing undefined behavior
|
||||
// of one port to the other's defined behavior, or by calling
|
||||
// emulate_transparency if necessary.
|
||||
void prepare_rd_merge(int idx1, int idx2, FfInitVals *initvals);
|
||||
|
||||
// Prepares the memory for widening a port to a given width. This
|
||||
// involves ensuring that start_offset and size are aligned to the
|
||||
// target width.
|
||||
void widen_prep(int wide_log2);
|
||||
|
||||
// Widens a write port up to a given width. The newly port is
|
||||
// equivalent to the original, made by replicating enable/data bits
|
||||
// and masking enable bits with decoders on the low part of the
|
||||
// original address.
|
||||
void widen_wr_port(int idx, int wide_log2);
|
||||
|
||||
// Emulates a sync read port's enable functionality in soft logic,
|
||||
// changing the actual read port's enable to be always-on.
|
||||
void emulate_rden(int idx, FfInitVals *initvals);
|
||||
|
||||
// Emulates a sync read port's initial/reset value functionality in
|
||||
// soft logic, removing it from the actual read port.
|
||||
void emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals);
|
||||
|
||||
// Given a read port with ce_over_srst set, converts it to a port
|
||||
// with ce_over_srst unset without changing its behavior by adding
|
||||
// emulation logic.
|
||||
void emulate_rd_ce_over_srst(int idx);
|
||||
|
||||
// Given a read port with ce_over_srst unset, converts it to a port
|
||||
// with ce_over_srst set without changing its behavior by adding
|
||||
// emulation logic.
|
||||
void emulate_rd_srst_over_ce(int idx);
|
||||
|
||||
// Returns true iff emulate_read_first makes sense to call.
|
||||
bool emulate_read_first_ok();
|
||||
|
||||
// Emulates all read-first read-write port relationships in terms of
|
||||
// all-transparent ports, by delaying all write ports by one cycle.
|
||||
// This can only be used when all read ports and all write ports are
|
||||
// in the same clock domain.
|
||||
void emulate_read_first(FfInitVals *initvals);
|
||||
|
||||
Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -380,9 +380,11 @@ struct ModWalker
|
|||
}
|
||||
}
|
||||
|
||||
ModWalker(RTLIL::Design *design) : design(design), module(NULL)
|
||||
ModWalker(RTLIL::Design *design, RTLIL::Module *module = nullptr) : design(design), module(NULL)
|
||||
{
|
||||
ct.setup(design);
|
||||
ct.setup(design);
|
||||
if (module)
|
||||
setup(module);
|
||||
}
|
||||
|
||||
void setup(RTLIL::Module *module, CellTypes *filter_ct = NULL)
|
||||
|
@ -395,6 +397,8 @@ struct ModWalker
|
|||
signal_consumers.clear();
|
||||
signal_inputs.clear();
|
||||
signal_outputs.clear();
|
||||
cell_inputs.clear();
|
||||
cell_outputs.clear();
|
||||
|
||||
for (auto &it : module->wires_)
|
||||
add_wire(it.second);
|
||||
|
|
102
kernel/qcsat.cc
Normal file
102
kernel/qcsat.cc
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
|
||||
*
|
||||
* 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/qcsat.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
std::vector<int> QuickConeSat::importSig(SigSpec sig)
|
||||
{
|
||||
sig = modwalker.sigmap(sig);
|
||||
for (auto bit : sig)
|
||||
bits_queue.insert(bit);
|
||||
return satgen.importSigSpec(sig);
|
||||
}
|
||||
|
||||
int QuickConeSat::importSigBit(SigBit bit)
|
||||
{
|
||||
bit = modwalker.sigmap(bit);
|
||||
bits_queue.insert(bit);
|
||||
return satgen.importSigBit(bit);
|
||||
}
|
||||
|
||||
void QuickConeSat::prepare()
|
||||
{
|
||||
while (!bits_queue.empty())
|
||||
{
|
||||
pool<ModWalker::PortBit> portbits;
|
||||
modwalker.get_drivers(portbits, bits_queue);
|
||||
|
||||
for (auto bit : bits_queue)
|
||||
if (bit.wire && bit.wire->get_bool_attribute(ID::onehot) && !imported_onehot.count(bit.wire))
|
||||
{
|
||||
std::vector<int> bits = satgen.importSigSpec(bit.wire);
|
||||
for (int i : bits)
|
||||
for (int j : bits)
|
||||
if (i != j)
|
||||
ez->assume(ez->NOT(i), j);
|
||||
imported_onehot.insert(bit.wire);
|
||||
}
|
||||
|
||||
bits_queue.clear();
|
||||
|
||||
for (auto &pbit : portbits)
|
||||
{
|
||||
if (imported_cells.count(pbit.cell))
|
||||
continue;
|
||||
if (cell_complexity(pbit.cell) > max_cell_complexity)
|
||||
continue;
|
||||
if (max_cell_outs && GetSize(modwalker.cell_outputs[pbit.cell]) > max_cell_outs)
|
||||
continue;
|
||||
auto &inputs = modwalker.cell_inputs[pbit.cell];
|
||||
bits_queue.insert(inputs.begin(), inputs.end());
|
||||
satgen.importCell(pbit.cell);
|
||||
imported_cells.insert(pbit.cell);
|
||||
}
|
||||
|
||||
if (max_cell_count && GetSize(imported_cells) > max_cell_count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
|
||||
{
|
||||
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($_BUF_)))
|
||||
return 0;
|
||||
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
|
||||
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
|
||||
ID($reduce_xnor), ID($reduce_bool),
|
||||
ID($logic_not), ID($logic_and), ID($logic_or),
|
||||
ID($eq), ID($ne), ID($eqx), ID($nex), ID($fa),
|
||||
ID($mux), ID($pmux), ID($bmux), ID($demux), ID($lut), ID($sop),
|
||||
ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
|
||||
ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
|
||||
ID($_MUX_), ID($_NMUX_), ID($_MUX4_), ID($_MUX8_), ID($_MUX16_),
|
||||
ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
|
||||
return 1;
|
||||
if (cell->type.in(ID($neg), ID($add), ID($sub), ID($alu), ID($lcu),
|
||||
ID($lt), ID($le), ID($gt), ID($ge)))
|
||||
return 2;
|
||||
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
|
||||
return 3;
|
||||
if (cell->type.in(ID($mul), ID($macc), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
|
||||
return 4;
|
||||
// Unknown cell.
|
||||
return 5;
|
||||
}
|
76
kernel/qcsat.h
Normal file
76
kernel/qcsat.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCSAT_H
|
||||
#define QCSAT_H
|
||||
|
||||
#include "kernel/satgen.h"
|
||||
#include "kernel/modtools.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// This is a helper class meant for easy construction of quick SAT queries
|
||||
// to a combinatorial input cone of some set of signals, meant for SAT-based
|
||||
// optimizations. Various knobs are provided to set just how much of the
|
||||
// cone should be included in the model — since this class is meant for
|
||||
// optimization, it should not be a correctness problem when some cells are
|
||||
// skipped and the solver spuriously returns SAT with a solution that
|
||||
// cannot exist in reality due to skipped constraints (ie. only UNSAT results
|
||||
// from this class should be considered binding).
|
||||
struct QuickConeSat {
|
||||
ModWalker &modwalker;
|
||||
ezSatPtr ez;
|
||||
SatGen satgen;
|
||||
|
||||
// The effort level knobs.
|
||||
|
||||
// The maximum "complexity level" of cells that will be imported.
|
||||
// - 1: bitwise operations, muxes, equality comparisons, lut, sop, fa
|
||||
// - 2: addition, subtraction, greater/less than comparisons, lcu
|
||||
// - 3: shifts
|
||||
// - 4: multiplication, division, power
|
||||
int max_cell_complexity = 2;
|
||||
// The maximum number of cells to import, or 0 for no limit.
|
||||
int max_cell_count = 0;
|
||||
// If non-0, skip importing cells with more than this number of output bits.
|
||||
int max_cell_outs = 0;
|
||||
|
||||
// Internal state.
|
||||
pool<RTLIL::Cell*> imported_cells;
|
||||
pool<RTLIL::Wire*> imported_onehot;
|
||||
pool<RTLIL::SigBit> bits_queue;
|
||||
|
||||
QuickConeSat(ModWalker &modwalker) : modwalker(modwalker), ez(), satgen(ez.get(), &modwalker.sigmap) {}
|
||||
|
||||
// Imports a signal into the SAT solver, queues its input cone to be
|
||||
// imported in the next prepare() call.
|
||||
std::vector<int> importSig(SigSpec sig);
|
||||
int importSigBit(SigBit bit);
|
||||
|
||||
// Imports the input cones of all previously importSig'd signals into
|
||||
// the SAT solver.
|
||||
void prepare();
|
||||
|
||||
// Returns the "complexity level" of a given cell.
|
||||
static int cell_complexity(RTLIL::Cell *cell);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
481
kernel/rtlil.cc
481
kernel/rtlil.cc
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -20,6 +20,7 @@
|
|||
#include "kernel/yosys.h"
|
||||
#include "kernel/macc.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/binding.h"
|
||||
#include "frontends/verilog/verilog_frontend.h"
|
||||
#include "frontends/verilog/preproc.h"
|
||||
#include "backends/rtlil/rtlil_backend.h"
|
||||
|
@ -57,6 +58,8 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
|
|||
ID($dffsre),
|
||||
ID($adff),
|
||||
ID($adffe),
|
||||
ID($aldff),
|
||||
ID($aldffe),
|
||||
ID($sdff),
|
||||
ID($sdffe),
|
||||
ID($sdffce),
|
||||
|
@ -117,6 +120,18 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
|
|||
ID($_DFFE_PP0P_),
|
||||
ID($_DFFE_PP1N_),
|
||||
ID($_DFFE_PP1P_),
|
||||
ID($_ALDFF_NN_),
|
||||
ID($_ALDFF_NP_),
|
||||
ID($_ALDFF_PN_),
|
||||
ID($_ALDFF_PP_),
|
||||
ID($_ALDFFE_NNN_),
|
||||
ID($_ALDFFE_NNP_),
|
||||
ID($_ALDFFE_NPN_),
|
||||
ID($_ALDFFE_NPP_),
|
||||
ID($_ALDFFE_PNN_),
|
||||
ID($_ALDFFE_PNP_),
|
||||
ID($_ALDFFE_PPN_),
|
||||
ID($_ALDFFE_PPP_),
|
||||
ID($_SDFF_NN0_),
|
||||
ID($_SDFF_NN1_),
|
||||
ID($_SDFF_NP0_),
|
||||
|
@ -363,6 +378,26 @@ bool RTLIL::Const::is_fully_undef() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool RTLIL::Const::is_onehot(int *pos) const
|
||||
{
|
||||
cover("kernel.rtlil.const.is_onehot");
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < GetSize(*this); i++) {
|
||||
auto &bit = bits[i];
|
||||
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
|
||||
return false;
|
||||
if (bit == RTLIL::State::S1) {
|
||||
if (found)
|
||||
return false;
|
||||
if (pos)
|
||||
*pos = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
|
||||
{
|
||||
return attributes.count(id);
|
||||
|
@ -445,6 +480,35 @@ vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
|
|||
return split_tokens(get_string_attribute(ID::hdlname), " ");
|
||||
}
|
||||
|
||||
void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<int> &data)
|
||||
{
|
||||
std::stringstream attrval;
|
||||
for (auto &i : data) {
|
||||
if (attrval.tellp() > 0)
|
||||
attrval << " ";
|
||||
attrval << i;
|
||||
}
|
||||
attributes[id] = RTLIL::Const(attrval.str());
|
||||
}
|
||||
|
||||
vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
|
||||
{
|
||||
vector<int> data;
|
||||
auto it = attributes.find(id);
|
||||
if (it != attributes.end())
|
||||
for (const auto &s : split_tokens(attributes.at(id).decode_string())) {
|
||||
char *end = nullptr;
|
||||
errno = 0;
|
||||
long value = strtol(s.c_str(), &end, 10);
|
||||
if (end != s.c_str() + s.size())
|
||||
log_cmd_error("Literal for intvec attribute has invalid format");
|
||||
if (errno == ERANGE || value < INT_MIN || value > INT_MAX)
|
||||
log_cmd_error("Literal for intvec attribute is out of range");
|
||||
data.push_back(value);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
|
||||
{
|
||||
if (full_selection)
|
||||
|
@ -551,8 +615,10 @@ RTLIL::Design::Design()
|
|||
|
||||
RTLIL::Design::~Design()
|
||||
{
|
||||
for (auto it = modules_.begin(); it != modules_.end(); ++it)
|
||||
delete it->second;
|
||||
for (auto &pr : modules_)
|
||||
delete pr.second;
|
||||
for (auto n : bindings_)
|
||||
delete n;
|
||||
for (auto n : verilog_packages)
|
||||
delete n;
|
||||
for (auto n : verilog_globals)
|
||||
|
@ -580,6 +646,11 @@ RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
|
|||
return modules_.count(name) ? modules_.at(name) : NULL;
|
||||
}
|
||||
|
||||
const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
|
||||
{
|
||||
return modules_.count(name) ? modules_.at(name) : NULL;
|
||||
}
|
||||
|
||||
RTLIL::Module *RTLIL::Design::top_module()
|
||||
{
|
||||
RTLIL::Module *module = nullptr;
|
||||
|
@ -611,9 +682,16 @@ void RTLIL::Design::add(RTLIL::Module *module)
|
|||
}
|
||||
}
|
||||
|
||||
void RTLIL::Design::add(RTLIL::Binding *binding)
|
||||
{
|
||||
log_assert(binding != nullptr);
|
||||
bindings_.push_back(binding);
|
||||
}
|
||||
|
||||
RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
|
||||
{
|
||||
log_assert(modules_.count(name) == 0);
|
||||
if (modules_.count(name) != 0)
|
||||
log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name.c_str());
|
||||
log_assert(refcount_modules_ == 0);
|
||||
|
||||
RTLIL::Module *module = new RTLIL::Module;
|
||||
|
@ -807,12 +885,12 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
|
||||
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn(bool include_wb) const
|
||||
{
|
||||
std::vector<RTLIL::Module*> result;
|
||||
result.reserve(modules_.size());
|
||||
for (auto &it : modules_)
|
||||
if (it.second->get_blackbox_attribute())
|
||||
if (it.second->get_blackbox_attribute(include_wb))
|
||||
continue;
|
||||
else if (selected_whole_module(it.first))
|
||||
result.push_back(it.second);
|
||||
|
@ -838,14 +916,16 @@ RTLIL::Module::Module()
|
|||
|
||||
RTLIL::Module::~Module()
|
||||
{
|
||||
for (auto it = wires_.begin(); it != wires_.end(); ++it)
|
||||
delete it->second;
|
||||
for (auto it = memories.begin(); it != memories.end(); ++it)
|
||||
delete it->second;
|
||||
for (auto it = cells_.begin(); it != cells_.end(); ++it)
|
||||
delete it->second;
|
||||
for (auto it = processes.begin(); it != processes.end(); ++it)
|
||||
delete it->second;
|
||||
for (auto &pr : wires_)
|
||||
delete pr.second;
|
||||
for (auto &pr : memories)
|
||||
delete pr.second;
|
||||
for (auto &pr : cells_)
|
||||
delete pr.second;
|
||||
for (auto &pr : processes)
|
||||
delete pr.second;
|
||||
for (auto binding : bindings_)
|
||||
delete binding;
|
||||
#ifdef WITH_PYTHON
|
||||
RTLIL::Module::get_all_modules()->erase(hashidx_);
|
||||
#endif
|
||||
|
@ -885,9 +965,14 @@ void RTLIL::Module::makeblackbox()
|
|||
set_bool_attribute(ID::blackbox);
|
||||
}
|
||||
|
||||
void RTLIL::Module::reprocess_module(RTLIL::Design *, const dict<RTLIL::IdString, RTLIL::Module *> &)
|
||||
void RTLIL::Module::expand_interfaces(RTLIL::Design *, const dict<RTLIL::IdString, RTLIL::Module *> &)
|
||||
{
|
||||
log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
|
||||
log_error("Class doesn't support expand_interfaces (module: `%s')!\n", id2cstr(name));
|
||||
}
|
||||
|
||||
bool RTLIL::Module::reprocess_if_necessary(RTLIL::Design *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dict<RTLIL::IdString, RTLIL::Const> &, bool mayfail)
|
||||
|
@ -1166,6 +1251,22 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($bmux)) {
|
||||
port(ID::A, param(ID::WIDTH) << param(ID::S_WIDTH));
|
||||
port(ID::S, param(ID::S_WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($demux)) {
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::S, param(ID::S_WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH) << param(ID::S_WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($lut)) {
|
||||
param(ID::LUT);
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
|
@ -1300,6 +1401,32 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($aldff)) {
|
||||
param_bool(ID::CLK_POLARITY);
|
||||
param_bool(ID::ALOAD_POLARITY);
|
||||
port(ID::CLK, 1);
|
||||
port(ID::ALOAD, 1);
|
||||
port(ID::D, param(ID::WIDTH));
|
||||
port(ID::AD, param(ID::WIDTH));
|
||||
port(ID::Q, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($aldffe)) {
|
||||
param_bool(ID::CLK_POLARITY);
|
||||
param_bool(ID::EN_POLARITY);
|
||||
param_bool(ID::ALOAD_POLARITY);
|
||||
port(ID::CLK, 1);
|
||||
port(ID::EN, 1);
|
||||
port(ID::ALOAD, 1);
|
||||
port(ID::D, param(ID::WIDTH));
|
||||
port(ID::AD, param(ID::WIDTH));
|
||||
port(ID::Q, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($dlatch)) {
|
||||
param_bool(ID::EN_POLARITY);
|
||||
port(ID::EN, 1);
|
||||
|
@ -1366,6 +1493,26 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($memrd_v2)) {
|
||||
param(ID::MEMID);
|
||||
param_bool(ID::CLK_ENABLE);
|
||||
param_bool(ID::CLK_POLARITY);
|
||||
param(ID::TRANSPARENCY_MASK);
|
||||
param(ID::COLLISION_X_MASK);
|
||||
param_bool(ID::CE_OVER_SRST);
|
||||
param_bits(ID::ARST_VALUE, param(ID::WIDTH));
|
||||
param_bits(ID::SRST_VALUE, param(ID::WIDTH));
|
||||
param_bits(ID::INIT_VALUE, param(ID::WIDTH));
|
||||
port(ID::CLK, 1);
|
||||
port(ID::EN, 1);
|
||||
port(ID::ARST, 1);
|
||||
port(ID::SRST, 1);
|
||||
port(ID::ADDR, param(ID::ABITS));
|
||||
port(ID::DATA, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($memwr)) {
|
||||
param(ID::MEMID);
|
||||
param_bool(ID::CLK_ENABLE);
|
||||
|
@ -1379,6 +1526,20 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($memwr_v2)) {
|
||||
param(ID::MEMID);
|
||||
param_bool(ID::CLK_ENABLE);
|
||||
param_bool(ID::CLK_POLARITY);
|
||||
param(ID::PORTID);
|
||||
param(ID::PRIORITY_MASK);
|
||||
port(ID::CLK, 1);
|
||||
port(ID::EN, param(ID::WIDTH));
|
||||
port(ID::ADDR, param(ID::ABITS));
|
||||
port(ID::DATA, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($meminit)) {
|
||||
param(ID::MEMID);
|
||||
param(ID::PRIORITY);
|
||||
|
@ -1388,6 +1549,16 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($meminit_v2)) {
|
||||
param(ID::MEMID);
|
||||
param(ID::PRIORITY);
|
||||
port(ID::ADDR, param(ID::ABITS));
|
||||
port(ID::DATA, param(ID::WIDTH) * param(ID::WORDS));
|
||||
port(ID::EN, param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($mem)) {
|
||||
param(ID::MEMID);
|
||||
param(ID::SIZE);
|
||||
|
@ -1410,6 +1581,38 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($mem_v2)) {
|
||||
param(ID::MEMID);
|
||||
param(ID::SIZE);
|
||||
param(ID::OFFSET);
|
||||
param(ID::INIT);
|
||||
param_bits(ID::RD_CLK_ENABLE, max(1, param(ID::RD_PORTS)));
|
||||
param_bits(ID::RD_CLK_POLARITY, max(1, param(ID::RD_PORTS)));
|
||||
param_bits(ID::RD_TRANSPARENCY_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
|
||||
param_bits(ID::RD_COLLISION_X_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
|
||||
param_bits(ID::RD_WIDE_CONTINUATION, max(1, param(ID::RD_PORTS)));
|
||||
param_bits(ID::RD_CE_OVER_SRST, max(1, param(ID::RD_PORTS)));
|
||||
param_bits(ID::RD_ARST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
||||
param_bits(ID::RD_SRST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
||||
param_bits(ID::RD_INIT_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
||||
param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS)));
|
||||
param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS)));
|
||||
param_bits(ID::WR_WIDE_CONTINUATION, max(1, param(ID::WR_PORTS)));
|
||||
param_bits(ID::WR_PRIORITY_MASK, max(1, param(ID::WR_PORTS) * param(ID::WR_PORTS)));
|
||||
port(ID::RD_CLK, param(ID::RD_PORTS));
|
||||
port(ID::RD_EN, param(ID::RD_PORTS));
|
||||
port(ID::RD_ARST, param(ID::RD_PORTS));
|
||||
port(ID::RD_SRST, param(ID::RD_PORTS));
|
||||
port(ID::RD_ADDR, param(ID::RD_PORTS) * param(ID::ABITS));
|
||||
port(ID::RD_DATA, param(ID::RD_PORTS) * param(ID::WIDTH));
|
||||
port(ID::WR_CLK, param(ID::WR_PORTS));
|
||||
port(ID::WR_EN, param(ID::WR_PORTS) * param(ID::WIDTH));
|
||||
port(ID::WR_ADDR, param(ID::WR_PORTS) * param(ID::ABITS));
|
||||
port(ID::WR_DATA, param(ID::WR_PORTS) * param(ID::WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($tribuf)) {
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
|
@ -1535,6 +1738,15 @@ namespace {
|
|||
ID($_DFFE_PP0N_), ID($_DFFE_PP0P_), ID($_DFFE_PP1N_), ID($_DFFE_PP1P_)))
|
||||
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; }
|
||||
|
||||
if (cell->type.in(
|
||||
ID($_ALDFF_NN_), ID($_ALDFF_NP_), ID($_ALDFF_PN_), ID($_ALDFF_PP_)))
|
||||
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); check_expected(); return; }
|
||||
|
||||
if (cell->type.in(
|
||||
ID($_ALDFFE_NNN_), ID($_ALDFFE_NNP_), ID($_ALDFFE_NPN_), ID($_ALDFFE_NPP_),
|
||||
ID($_ALDFFE_PNN_), ID($_ALDFFE_PNP_), ID($_ALDFFE_PPN_), ID($_ALDFFE_PPP_)))
|
||||
{ port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); port(ID::E,1); check_expected(); return; }
|
||||
|
||||
if (cell->type.in(
|
||||
ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
|
||||
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
|
||||
|
@ -1640,7 +1852,7 @@ void RTLIL::Module::check()
|
|||
log_assert(!it.second->type.empty());
|
||||
for (auto &it2 : it.second->connections()) {
|
||||
log_assert(!it2.first.empty());
|
||||
it2.second.check();
|
||||
it2.second.check(this);
|
||||
}
|
||||
for (auto &it2 : it.second->attributes)
|
||||
log_assert(!it2.first.empty());
|
||||
|
@ -1686,8 +1898,8 @@ void RTLIL::Module::check()
|
|||
for (auto &it : connections_) {
|
||||
log_assert(it.first.size() == it.second.size());
|
||||
log_assert(!it.first.has_const());
|
||||
it.first.check();
|
||||
it.second.check();
|
||||
it.first.check(this);
|
||||
it.second.check(this);
|
||||
}
|
||||
|
||||
for (auto &it : attributes)
|
||||
|
@ -1813,6 +2025,20 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
|
|||
cell->module = this;
|
||||
}
|
||||
|
||||
void RTLIL::Module::add(RTLIL::Process *process)
|
||||
{
|
||||
log_assert(!process->name.empty());
|
||||
log_assert(count_id(process->name) == 0);
|
||||
processes[process->name] = process;
|
||||
process->module = this;
|
||||
}
|
||||
|
||||
void RTLIL::Module::add(RTLIL::Binding *binding)
|
||||
{
|
||||
log_assert(binding != nullptr);
|
||||
bindings_.push_back(binding);
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||
{
|
||||
log_assert(refcount_wires_ == 0);
|
||||
|
@ -1869,6 +2095,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell)
|
|||
delete cell;
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(RTLIL::Process *process)
|
||||
{
|
||||
log_assert(processes.count(process->name) != 0);
|
||||
processes.erase(process->name);
|
||||
delete process;
|
||||
}
|
||||
|
||||
void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
|
||||
{
|
||||
log_assert(wires_[wire->name] == wire);
|
||||
|
@ -2094,11 +2327,19 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor
|
|||
return mem;
|
||||
}
|
||||
|
||||
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
|
||||
{
|
||||
RTLIL::Process *proc = new RTLIL::Process;
|
||||
proc->name = name;
|
||||
add(proc);
|
||||
return proc;
|
||||
}
|
||||
|
||||
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other)
|
||||
{
|
||||
RTLIL::Process *proc = other->clone();
|
||||
proc->name = name;
|
||||
processes[name] = proc;
|
||||
add(proc);
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
@ -2219,6 +2460,26 @@ DEF_METHOD(Mux, ID($mux), 0)
|
|||
DEF_METHOD(Pmux, ID($pmux), 1)
|
||||
#undef DEF_METHOD
|
||||
|
||||
#define DEF_METHOD(_func, _type, _demux) \
|
||||
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \
|
||||
RTLIL::Cell *cell = addCell(name, _type); \
|
||||
cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \
|
||||
cell->parameters[ID::S_WIDTH] = sig_s.size(); \
|
||||
cell->setPort(ID::A, sig_a); \
|
||||
cell->setPort(ID::S, sig_s); \
|
||||
cell->setPort(ID::Y, sig_y); \
|
||||
cell->set_src_attribute(src); \
|
||||
return cell; \
|
||||
} \
|
||||
RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \
|
||||
RTLIL::SigSpec sig_y = addWire(NEW_ID, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \
|
||||
add ## _func(name, sig_a, sig_s, sig_y, src); \
|
||||
return sig_y; \
|
||||
}
|
||||
DEF_METHOD(Bmux, ID($bmux), 0)
|
||||
DEF_METHOD(Demux, ID($demux), 1)
|
||||
#undef DEF_METHOD
|
||||
|
||||
#define DEF_METHOD_2(_func, _type, _P1, _P2) \
|
||||
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \
|
||||
RTLIL::Cell *cell = addCell(name, _type); \
|
||||
|
@ -2533,6 +2794,40 @@ RTLIL::Cell* RTLIL::Module::addAdffe(RTLIL::IdString name, const RTLIL::SigSpec
|
|||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addAldff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src)
|
||||
{
|
||||
RTLIL::Cell *cell = addCell(name, ID($aldff));
|
||||
cell->parameters[ID::CLK_POLARITY] = clk_polarity;
|
||||
cell->parameters[ID::ALOAD_POLARITY] = aload_polarity;
|
||||
cell->parameters[ID::WIDTH] = sig_q.size();
|
||||
cell->setPort(ID::CLK, sig_clk);
|
||||
cell->setPort(ID::ALOAD, sig_aload);
|
||||
cell->setPort(ID::D, sig_d);
|
||||
cell->setPort(ID::AD, sig_ad);
|
||||
cell->setPort(ID::Q, sig_q);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addAldffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src)
|
||||
{
|
||||
RTLIL::Cell *cell = addCell(name, ID($aldffe));
|
||||
cell->parameters[ID::CLK_POLARITY] = clk_polarity;
|
||||
cell->parameters[ID::EN_POLARITY] = en_polarity;
|
||||
cell->parameters[ID::ALOAD_POLARITY] = aload_polarity;
|
||||
cell->parameters[ID::WIDTH] = sig_q.size();
|
||||
cell->setPort(ID::CLK, sig_clk);
|
||||
cell->setPort(ID::EN, sig_en);
|
||||
cell->setPort(ID::ALOAD, sig_aload);
|
||||
cell->setPort(ID::D, sig_d);
|
||||
cell->setPort(ID::AD, sig_ad);
|
||||
cell->setPort(ID::Q, sig_q);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addSdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
|
||||
{
|
||||
|
@ -2723,6 +3018,33 @@ RTLIL::Cell* RTLIL::Module::addAdffeGate(RTLIL::IdString name, const RTLIL::SigS
|
|||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addAldffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src)
|
||||
{
|
||||
RTLIL::Cell *cell = addCell(name, stringf("$_ALDFF_%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N'));
|
||||
cell->setPort(ID::C, sig_clk);
|
||||
cell->setPort(ID::L, sig_aload);
|
||||
cell->setPort(ID::D, sig_d);
|
||||
cell->setPort(ID::AD, sig_ad);
|
||||
cell->setPort(ID::Q, sig_q);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addAldffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src)
|
||||
{
|
||||
RTLIL::Cell *cell = addCell(name, stringf("$_ALDFFE_%c%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
|
||||
cell->setPort(ID::C, sig_clk);
|
||||
cell->setPort(ID::L, sig_aload);
|
||||
cell->setPort(ID::E, sig_en);
|
||||
cell->setPort(ID::D, sig_d);
|
||||
cell->setPort(ID::AD, sig_ad);
|
||||
cell->setPort(ID::Q, sig_q);
|
||||
cell->set_src_attribute(src);
|
||||
return cell;
|
||||
}
|
||||
|
||||
RTLIL::Cell* RTLIL::Module::addSdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
bool srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
|
||||
{
|
||||
|
@ -2894,6 +3216,13 @@ RTLIL::Memory::Memory()
|
|||
#endif
|
||||
}
|
||||
|
||||
RTLIL::Process::Process() : module(nullptr)
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
hashidx_count = mkhash_xorshift(hashidx_count);
|
||||
hashidx_ = hashidx_count;
|
||||
}
|
||||
|
||||
RTLIL::Cell::Cell() : module(nullptr)
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
|
@ -3065,14 +3394,21 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
|
||||
return;
|
||||
|
||||
if (type == ID($mux) || type == ID($pmux)) {
|
||||
if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
|
||||
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
|
||||
if (type == ID($pmux))
|
||||
if (type != ID($mux))
|
||||
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
||||
check();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ID($demux)) {
|
||||
parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
|
||||
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
||||
check();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ID($lut) || type == ID($sop)) {
|
||||
parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
|
||||
return;
|
||||
|
@ -3119,6 +3455,16 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
check();
|
||||
}
|
||||
|
||||
bool RTLIL::Cell::has_memid() const
|
||||
{
|
||||
return type.in(ID($memwr), ID($memwr_v2), ID($memrd), ID($memrd_v2), ID($meminit), ID($meminit_v2));
|
||||
}
|
||||
|
||||
bool RTLIL::Cell::is_mem_cell() const
|
||||
{
|
||||
return type.in(ID($mem), ID($mem_v2)) || has_memid();
|
||||
}
|
||||
|
||||
RTLIL::SigChunk::SigChunk()
|
||||
{
|
||||
wire = NULL;
|
||||
|
@ -3275,8 +3621,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.const");
|
||||
|
||||
chunks_.emplace_back(value);
|
||||
width_ = chunks_.back().width;
|
||||
if (GetSize(value) != 0) {
|
||||
chunks_.emplace_back(value);
|
||||
width_ = chunks_.back().width;
|
||||
} else {
|
||||
width_ = 0;
|
||||
}
|
||||
hash_ = 0;
|
||||
check();
|
||||
}
|
||||
|
@ -3285,8 +3635,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.chunk");
|
||||
|
||||
chunks_.emplace_back(chunk);
|
||||
width_ = chunks_.back().width;
|
||||
if (chunk.width != 0) {
|
||||
chunks_.emplace_back(chunk);
|
||||
width_ = chunks_.back().width;
|
||||
} else {
|
||||
width_ = 0;
|
||||
}
|
||||
hash_ = 0;
|
||||
check();
|
||||
}
|
||||
|
@ -3295,8 +3649,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.wire");
|
||||
|
||||
chunks_.emplace_back(wire);
|
||||
width_ = chunks_.back().width;
|
||||
if (wire->width != 0) {
|
||||
chunks_.emplace_back(wire);
|
||||
width_ = chunks_.back().width;
|
||||
} else {
|
||||
width_ = 0;
|
||||
}
|
||||
hash_ = 0;
|
||||
check();
|
||||
}
|
||||
|
@ -3305,8 +3663,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.wire_part");
|
||||
|
||||
chunks_.emplace_back(wire, offset, width);
|
||||
width_ = chunks_.back().width;
|
||||
if (width != 0) {
|
||||
chunks_.emplace_back(wire, offset, width);
|
||||
width_ = chunks_.back().width;
|
||||
} else {
|
||||
width_ = 0;
|
||||
}
|
||||
hash_ = 0;
|
||||
check();
|
||||
}
|
||||
|
@ -3315,8 +3677,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.str");
|
||||
|
||||
chunks_.emplace_back(str);
|
||||
width_ = chunks_.back().width;
|
||||
if (str.size() != 0) {
|
||||
chunks_.emplace_back(str);
|
||||
width_ = chunks_.back().width;
|
||||
} else {
|
||||
width_ = 0;
|
||||
}
|
||||
hash_ = 0;
|
||||
check();
|
||||
}
|
||||
|
@ -3325,7 +3691,8 @@ RTLIL::SigSpec::SigSpec(int val, int width)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.int");
|
||||
|
||||
chunks_.emplace_back(val, width);
|
||||
if (width != 0)
|
||||
chunks_.emplace_back(val, width);
|
||||
width_ = width;
|
||||
hash_ = 0;
|
||||
check();
|
||||
|
@ -3335,7 +3702,8 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.state");
|
||||
|
||||
chunks_.emplace_back(bit, width);
|
||||
if (width != 0)
|
||||
chunks_.emplace_back(bit, width);
|
||||
width_ = width;
|
||||
hash_ = 0;
|
||||
check();
|
||||
|
@ -3345,11 +3713,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.init.bit");
|
||||
|
||||
if (bit.wire == NULL)
|
||||
chunks_.emplace_back(bit.data, width);
|
||||
else
|
||||
for (int i = 0; i < width; i++)
|
||||
chunks_.push_back(bit);
|
||||
if (width != 0) {
|
||||
if (bit.wire == NULL)
|
||||
chunks_.emplace_back(bit.data, width);
|
||||
else
|
||||
for (int i = 0; i < width; i++)
|
||||
chunks_.push_back(bit);
|
||||
}
|
||||
width_ = width;
|
||||
hash_ = 0;
|
||||
check();
|
||||
|
@ -3794,7 +4164,13 @@ void RTLIL::SigSpec::remove_const()
|
|||
width_ = 0;
|
||||
for (auto &chunk : chunks_)
|
||||
if (chunk.wire != NULL) {
|
||||
new_chunks.push_back(chunk);
|
||||
if (!new_chunks.empty() &&
|
||||
new_chunks.back().wire == chunk.wire &&
|
||||
new_chunks.back().offset + new_chunks.back().width == chunk.offset) {
|
||||
new_chunks.back().width += chunk.width;
|
||||
} else {
|
||||
new_chunks.push_back(chunk);
|
||||
}
|
||||
width_ += chunk.width;
|
||||
}
|
||||
|
||||
|
@ -3941,7 +4317,7 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const
|
|||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void RTLIL::SigSpec::check() const
|
||||
void RTLIL::SigSpec::check(Module *mod) const
|
||||
{
|
||||
if (width_ > 64)
|
||||
{
|
||||
|
@ -3954,6 +4330,7 @@ void RTLIL::SigSpec::check() const
|
|||
int w = 0;
|
||||
for (size_t i = 0; i < chunks_.size(); i++) {
|
||||
const RTLIL::SigChunk &chunk = chunks_[i];
|
||||
log_assert(chunk.width != 0);
|
||||
if (chunk.wire == NULL) {
|
||||
if (i > 0)
|
||||
log_assert(chunks_[i-1].wire != NULL);
|
||||
|
@ -3966,6 +4343,8 @@ void RTLIL::SigSpec::check() const
|
|||
log_assert(chunk.width >= 0);
|
||||
log_assert(chunk.offset + chunk.width <= chunk.wire->width);
|
||||
log_assert(chunk.data.size() == 0);
|
||||
if (mod != nullptr)
|
||||
log_assert(chunk.wire->module == mod);
|
||||
}
|
||||
w += chunk.width;
|
||||
}
|
||||
|
@ -3976,6 +4355,12 @@ void RTLIL::SigSpec::check() const
|
|||
{
|
||||
cover("kernel.rtlil.sigspec.check.unpacked");
|
||||
|
||||
if (mod != nullptr) {
|
||||
for (size_t i = 0; i < bits_.size(); i++)
|
||||
if (bits_[i].wire != nullptr)
|
||||
log_assert(bits_[i].wire->module == mod);
|
||||
}
|
||||
|
||||
log_assert(width_ == GetSize(bits_));
|
||||
log_assert(chunks_.empty());
|
||||
}
|
||||
|
@ -4164,6 +4549,19 @@ bool RTLIL::SigSpec::has_marked_bits() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::is_onehot(int *pos) const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.is_onehot");
|
||||
|
||||
pack();
|
||||
if (!is_fully_const())
|
||||
return false;
|
||||
log_assert(GetSize(chunks_) <= 1);
|
||||
if (width_)
|
||||
return RTLIL::Const(chunks_[0].data).is_onehot(pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::as_bool() const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.as_bool");
|
||||
|
@ -4537,6 +4935,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
|
|||
new_syncrule->type = type;
|
||||
new_syncrule->signal = signal;
|
||||
new_syncrule->actions = actions;
|
||||
new_syncrule->mem_write_actions = mem_write_actions;
|
||||
return new_syncrule;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -69,8 +69,10 @@ namespace RTLIL
|
|||
struct SigSpec;
|
||||
struct CaseRule;
|
||||
struct SwitchRule;
|
||||
struct MemWriteAction;
|
||||
struct SyncRule;
|
||||
struct Process;
|
||||
struct Binding;
|
||||
|
||||
typedef std::pair<SigSpec, SigSpec> SigSig;
|
||||
|
||||
|
@ -165,7 +167,8 @@ namespace RTLIL
|
|||
log_assert(p[0] == '$' || p[0] == '\\');
|
||||
log_assert(p[1] != 0);
|
||||
for (const char *c = p; *c; c++)
|
||||
log_assert((unsigned)*c > (unsigned)' ');
|
||||
if ((unsigned)*c <= (unsigned)' ')
|
||||
log_error("Found control character or space (0x%02hhx) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
|
||||
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
if (global_free_idx_list_.empty()) {
|
||||
|
@ -482,6 +485,9 @@ namespace RTLIL
|
|||
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||
|
||||
RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
|
||||
RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
|
||||
|
||||
|
||||
// This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().
|
||||
// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
|
||||
|
@ -660,6 +666,7 @@ struct RTLIL::Const
|
|||
bool is_fully_ones() const;
|
||||
bool is_fully_def() const;
|
||||
bool is_fully_undef() const;
|
||||
bool is_onehot(int *pos = nullptr) const;
|
||||
|
||||
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
|
||||
RTLIL::Const ret;
|
||||
|
@ -714,6 +721,9 @@ struct RTLIL::AttrObject
|
|||
|
||||
void set_hdlname_attribute(const vector<string> &hierarchy);
|
||||
vector<string> get_hdlname_attribute() const;
|
||||
|
||||
void set_intvec_attribute(RTLIL::IdString id, const vector<int> &data);
|
||||
vector<int> get_intvec_attribute(RTLIL::IdString id) const;
|
||||
};
|
||||
|
||||
struct RTLIL::SigChunk
|
||||
|
@ -752,7 +762,7 @@ struct RTLIL::SigBit
|
|||
|
||||
SigBit();
|
||||
SigBit(RTLIL::State bit);
|
||||
SigBit(bool bit);
|
||||
explicit SigBit(bool bit);
|
||||
SigBit(RTLIL::Wire *wire);
|
||||
SigBit(RTLIL::Wire *wire, int offset);
|
||||
SigBit(const RTLIL::SigChunk &chunk);
|
||||
|
@ -834,7 +844,7 @@ public:
|
|||
SigSpec(const std::vector<RTLIL::SigBit> &bits);
|
||||
SigSpec(const pool<RTLIL::SigBit> &bits);
|
||||
SigSpec(const std::set<RTLIL::SigBit> &bits);
|
||||
SigSpec(bool bit);
|
||||
explicit SigSpec(bool bit);
|
||||
|
||||
SigSpec(RTLIL::SigSpec &&other) {
|
||||
width_ = other.width_;
|
||||
|
@ -932,6 +942,7 @@ public:
|
|||
bool is_fully_undef() const;
|
||||
bool has_const() const;
|
||||
bool has_marked_bits() const;
|
||||
bool is_onehot(int *pos = nullptr) const;
|
||||
|
||||
bool as_bool() const;
|
||||
int as_int(bool is_signed = false) const;
|
||||
|
@ -960,9 +971,9 @@ public:
|
|||
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check() const;
|
||||
void check(Module *mod = nullptr) const;
|
||||
#else
|
||||
void check() const { }
|
||||
void check(Module *mod = nullptr) const { (void)mod; }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1029,6 +1040,8 @@ struct RTLIL::Design
|
|||
|
||||
int refcount_modules_;
|
||||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||
std::vector<RTLIL::Binding*> bindings_;
|
||||
|
||||
std::vector<AST::AstNode*> verilog_packages, verilog_globals;
|
||||
std::unique_ptr<define_map_t> verilog_defines;
|
||||
|
||||
|
@ -1041,6 +1054,7 @@ struct RTLIL::Design
|
|||
|
||||
RTLIL::ObjRange<RTLIL::Module*> modules();
|
||||
RTLIL::Module *module(RTLIL::IdString name);
|
||||
const RTLIL::Module *module(RTLIL::IdString name) const;
|
||||
RTLIL::Module *top_module();
|
||||
|
||||
bool has(RTLIL::IdString id) const {
|
||||
|
@ -1048,6 +1062,8 @@ struct RTLIL::Design
|
|||
}
|
||||
|
||||
void add(RTLIL::Module *module);
|
||||
void add(RTLIL::Binding *binding);
|
||||
|
||||
RTLIL::Module *addModule(RTLIL::IdString name);
|
||||
void remove(RTLIL::Module *module);
|
||||
void rename(RTLIL::Module *module, RTLIL::IdString new_name);
|
||||
|
@ -1110,7 +1126,7 @@ struct RTLIL::Design
|
|||
|
||||
std::vector<RTLIL::Module*> selected_modules() const;
|
||||
std::vector<RTLIL::Module*> selected_whole_modules() const;
|
||||
std::vector<RTLIL::Module*> selected_whole_modules_warn() const;
|
||||
std::vector<RTLIL::Module*> selected_whole_modules_warn(bool include_wb = false) const;
|
||||
#ifdef WITH_PYTHON
|
||||
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
|
||||
#endif
|
||||
|
@ -1124,6 +1140,7 @@ struct RTLIL::Module : public RTLIL::AttrObject
|
|||
protected:
|
||||
void add(RTLIL::Wire *wire);
|
||||
void add(RTLIL::Cell *cell);
|
||||
void add(RTLIL::Process *process);
|
||||
|
||||
public:
|
||||
RTLIL::Design *design;
|
||||
|
@ -1134,7 +1151,9 @@ public:
|
|||
|
||||
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
|
||||
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
|
||||
std::vector<RTLIL::SigSig> connections_;
|
||||
|
||||
std::vector<RTLIL::SigSig> connections_;
|
||||
std::vector<RTLIL::Binding*> bindings_;
|
||||
|
||||
RTLIL::IdString name;
|
||||
idict<RTLIL::IdString> avail_parameters;
|
||||
|
@ -1147,7 +1166,8 @@ public:
|
|||
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail = false);
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
|
||||
virtual size_t count_id(RTLIL::IdString id);
|
||||
virtual void reprocess_module(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
|
||||
virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
|
||||
virtual bool reprocess_if_necessary(RTLIL::Design *design);
|
||||
|
||||
virtual void sort();
|
||||
virtual void check();
|
||||
|
@ -1189,12 +1209,24 @@ public:
|
|||
return it == cells_.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
const RTLIL::Wire* wire(RTLIL::IdString id) const{
|
||||
auto it = wires_.find(id);
|
||||
return it == wires_.end() ? nullptr : it->second;
|
||||
}
|
||||
const RTLIL::Cell* cell(RTLIL::IdString id) const {
|
||||
auto it = cells_.find(id);
|
||||
return it == cells_.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }
|
||||
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
|
||||
|
||||
void add(RTLIL::Binding *binding);
|
||||
|
||||
// Removing wires is expensive. If you have to remove wires, remove them all at once.
|
||||
void remove(const pool<RTLIL::Wire*> &wires);
|
||||
void remove(RTLIL::Cell *cell);
|
||||
void remove(RTLIL::Process *process);
|
||||
|
||||
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
|
||||
void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
|
||||
|
@ -1214,6 +1246,7 @@ public:
|
|||
|
||||
RTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other);
|
||||
|
||||
RTLIL::Process *addProcess(RTLIL::IdString name);
|
||||
RTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other);
|
||||
|
||||
// The add* methods create a cell and return the created cell. All signals must exist in advance.
|
||||
|
@ -1266,6 +1299,8 @@ public:
|
|||
|
||||
RTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
|
||||
RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = "");
|
||||
RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
|
||||
|
@ -1286,6 +1321,8 @@ public:
|
|||
RTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
|
||||
|
@ -1323,6 +1360,10 @@ public:
|
|||
bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = "");
|
||||
RTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
|
||||
|
@ -1339,7 +1380,6 @@ public:
|
|||
|
||||
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Bu0 (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
|
||||
RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
|
||||
|
@ -1386,6 +1426,8 @@ public:
|
|||
|
||||
RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
|
||||
RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
|
||||
RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
|
||||
RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
|
||||
|
||||
RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
|
||||
RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
|
||||
|
@ -1511,6 +1553,9 @@ public:
|
|||
#ifdef WITH_PYTHON
|
||||
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
|
||||
#endif
|
||||
|
||||
bool has_memid() const;
|
||||
bool is_mem_cell() const;
|
||||
};
|
||||
|
||||
struct RTLIL::CaseRule : public RTLIL::AttrObject
|
||||
|
@ -1520,7 +1565,6 @@ struct RTLIL::CaseRule : public RTLIL::AttrObject
|
|||
std::vector<RTLIL::SwitchRule*> switches;
|
||||
|
||||
~CaseRule();
|
||||
void optimize();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
|
@ -1543,11 +1587,21 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
|
|||
RTLIL::SwitchRule *clone() const;
|
||||
};
|
||||
|
||||
struct RTLIL::MemWriteAction : RTLIL::AttrObject
|
||||
{
|
||||
RTLIL::IdString memid;
|
||||
RTLIL::SigSpec address;
|
||||
RTLIL::SigSpec data;
|
||||
RTLIL::SigSpec enable;
|
||||
RTLIL::Const priority_mask;
|
||||
};
|
||||
|
||||
struct RTLIL::SyncRule
|
||||
{
|
||||
RTLIL::SyncType type;
|
||||
RTLIL::SigSpec signal;
|
||||
std::vector<RTLIL::SigSig> actions;
|
||||
std::vector<RTLIL::MemWriteAction> mem_write_actions;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
|
@ -1556,12 +1610,21 @@ struct RTLIL::SyncRule
|
|||
|
||||
struct RTLIL::Process : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
protected:
|
||||
// use module->addProcess() and module->remove() to create or destroy processes
|
||||
friend struct RTLIL::Module;
|
||||
Process();
|
||||
~Process();
|
||||
|
||||
public:
|
||||
RTLIL::IdString name;
|
||||
RTLIL::Module *module;
|
||||
RTLIL::CaseRule root_case;
|
||||
std::vector<RTLIL::SyncRule*> syncs;
|
||||
|
||||
~Process();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::Process *clone() const;
|
||||
|
@ -1695,6 +1758,11 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
|
|||
functor(it.first);
|
||||
functor(it.second);
|
||||
}
|
||||
for (auto &it : mem_write_actions) {
|
||||
functor(it.address);
|
||||
functor(it.data);
|
||||
functor(it.enable);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -1704,6 +1772,11 @@ void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
|
|||
for (auto &it : actions) {
|
||||
functor(it.first, it.second);
|
||||
}
|
||||
for (auto &it : mem_write_actions) {
|
||||
functor(it.address);
|
||||
functor(it.data);
|
||||
functor(it.enable);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
122
kernel/satgen.cc
122
kernel/satgen.cc
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -252,6 +252,106 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($bmux))
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||
std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
std::vector<int> undef_a, undef_s, undef_y;
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
|
||||
undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
|
||||
undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
}
|
||||
|
||||
if (GetSize(s) == 0) {
|
||||
ez->vec_set(a, y);
|
||||
if (model_undef)
|
||||
ez->vec_set(undef_a, undef_y);
|
||||
} else {
|
||||
for (int i = GetSize(s)-1; i >= 0; i--)
|
||||
{
|
||||
std::vector<int> out = (i == 0) ? y : ez->vec_var(a.size() / 2);
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(out.size()) : out;
|
||||
|
||||
std::vector<int> a0(a.begin(), a.begin() + a.size() / 2);
|
||||
std::vector<int> a1(a.begin() + a.size() / 2, a.end());
|
||||
ez->assume(ez->vec_eq(ez->vec_ite(s.at(i), a1, a0), yy));
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
std::vector<int> undef_out = (i == 0) ? undef_y : ez->vec_var(a.size() / 2);
|
||||
std::vector<int> undef_a0(undef_a.begin(), undef_a.begin() + a.size() / 2);
|
||||
std::vector<int> undef_a1(undef_a.begin() + a.size() / 2, undef_a.end());
|
||||
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a0, a1));
|
||||
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a0, undef_a1));
|
||||
std::vector<int> yX = ez->vec_ite(undef_s.at(i), undef_ab, ez->vec_ite(s.at(i), undef_a1, undef_a0));
|
||||
ez->assume(ez->vec_eq(yX, undef_out));
|
||||
undefGating(out, yy, undef_out);
|
||||
|
||||
undef_a = undef_out;
|
||||
}
|
||||
|
||||
a = out;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($demux))
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||
std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
||||
std::vector<int> undef_a, undef_s, undef_y;
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
|
||||
undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
|
||||
undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
}
|
||||
|
||||
if (GetSize(s) == 0) {
|
||||
ez->vec_set(a, y);
|
||||
if (model_undef)
|
||||
ez->vec_set(undef_a, undef_y);
|
||||
} else {
|
||||
for (int i = 0; i < (1 << GetSize(s)); i++)
|
||||
{
|
||||
std::vector<int> ss;
|
||||
for (int j = 0; j < GetSize(s); j++) {
|
||||
if (i & 1 << j)
|
||||
ss.push_back(s[j]);
|
||||
else
|
||||
ss.push_back(ez->NOT(s[j]));
|
||||
}
|
||||
int sss = ez->expression(ezSAT::OpAnd, ss);
|
||||
|
||||
for (int j = 0; j < GetSize(a); j++) {
|
||||
ez->SET(ez->AND(sss, a[j]), yy.at(i * GetSize(a) + j));
|
||||
}
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
int s0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(ss), ez->vec_not(undef_s)));
|
||||
int us = ez->AND(ez->NOT(s0), ez->expression(ezSAT::OpOr, undef_s));
|
||||
for (int j = 0; j < GetSize(a); j++) {
|
||||
int a0 = ez->AND(ez->NOT(a[j]), ez->NOT(undef_a[j]));
|
||||
int yX = ez->AND(ez->OR(us, undef_a[j]), ez->NOT(ez->OR(s0, a0)));
|
||||
ez->SET(yX, undef_y.at(i * GetSize(a) + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model_undef)
|
||||
undefGating(y, yy, undef_y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($pmux))
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||
|
@ -1081,7 +1181,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
FfData ff(nullptr, cell);
|
||||
|
||||
// Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first.
|
||||
if (!ff.has_d || ff.has_arst || ff.has_sr || (ff.has_en && !ff.has_clk))
|
||||
if (ff.has_aload || ff.has_arst || ff.has_sr)
|
||||
return false;
|
||||
|
||||
if (timestep == 1)
|
||||
|
@ -1094,7 +1194,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
std::vector<int> undef_d;
|
||||
if (model_undef)
|
||||
undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
|
||||
if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
|
||||
if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
|
||||
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
|
||||
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
|
||||
int undef_srst;
|
||||
|
@ -1108,21 +1208,21 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
else
|
||||
std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
|
||||
}
|
||||
if (ff.has_en) {
|
||||
int en = importDefSigSpec(ff.sig_en, timestep-1).at(0);
|
||||
if (ff.has_ce) {
|
||||
int ce = importDefSigSpec(ff.sig_ce, timestep-1).at(0);
|
||||
std::vector<int> old_q = importDefSigSpec(ff.sig_q, timestep-1);
|
||||
int undef_en;
|
||||
int undef_ce;
|
||||
std::vector<int> undef_old_q;
|
||||
if (model_undef) {
|
||||
undef_en = importUndefSigSpec(ff.sig_en, timestep-1).at(0);
|
||||
undef_ce = importUndefSigSpec(ff.sig_ce, timestep-1).at(0);
|
||||
undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1);
|
||||
}
|
||||
if (ff.pol_en)
|
||||
std::tie(d, undef_d) = mux(en, undef_en, old_q, undef_old_q, d, undef_d);
|
||||
if (ff.pol_ce)
|
||||
std::tie(d, undef_d) = mux(ce, undef_ce, old_q, undef_old_q, d, undef_d);
|
||||
else
|
||||
std::tie(d, undef_d) = mux(en, undef_en, d, undef_d, old_q, undef_old_q);
|
||||
std::tie(d, undef_d) = mux(ce, undef_ce, d, undef_d, old_q, undef_old_q);
|
||||
}
|
||||
if (ff.has_srst && !(ff.has_en && ff.ce_over_srst)) {
|
||||
if (ff.has_srst && !(ff.has_ce && ff.ce_over_srst)) {
|
||||
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
|
||||
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
|
||||
int undef_srst;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
* (C) 2020 Eddie Hung <eddie@fpgeh.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
|
@ -49,9 +49,9 @@ struct TimingInfo
|
|||
|
||||
struct ModuleTiming
|
||||
{
|
||||
RTLIL::IdString type;
|
||||
dict<BitBit, int> comb;
|
||||
dict<NameBit, int> arrival, required;
|
||||
dict<NameBit, std::pair<int,NameBit>> arrival, required;
|
||||
bool has_inputs;
|
||||
};
|
||||
|
||||
dict<RTLIL::IdString, ModuleTiming> data;
|
||||
|
@ -120,11 +120,10 @@ struct TimingInfo
|
|||
}
|
||||
}
|
||||
else if (cell->type == ID($specify3)) {
|
||||
auto src = cell->getPort(ID::SRC);
|
||||
auto src = cell->getPort(ID::SRC).as_bit();
|
||||
auto dst = cell->getPort(ID::DST);
|
||||
for (const auto &c : src.chunks())
|
||||
if (!c.wire->port_input)
|
||||
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
|
||||
if (!src.wire || !src.wire->port_input)
|
||||
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
|
||||
for (const auto &c : dst.chunks())
|
||||
if (!c.wire->port_output)
|
||||
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
|
||||
|
@ -136,34 +135,49 @@ struct TimingInfo
|
|||
max = 0;
|
||||
}
|
||||
for (const auto &d : dst) {
|
||||
auto &v = t.arrival[NameBit(d)];
|
||||
v = std::max(v, max);
|
||||
auto r = t.arrival.insert(NameBit(d));
|
||||
auto &v = r.first->second;
|
||||
if (r.second || v.first < max) {
|
||||
v.first = max;
|
||||
v.second = NameBit(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cell->type == ID($specrule)) {
|
||||
auto type = cell->getParam(ID::TYPE).decode_string();
|
||||
if (type != "$setup" && type != "$setuphold")
|
||||
IdString type = cell->getParam(ID::TYPE).decode_string();
|
||||
if (type != ID($setup) && type != ID($setuphold))
|
||||
continue;
|
||||
auto src = cell->getPort(ID::SRC);
|
||||
auto dst = cell->getPort(ID::DST);
|
||||
auto dst = cell->getPort(ID::DST).as_bit();
|
||||
for (const auto &c : src.chunks())
|
||||
if (!c.wire->port_input)
|
||||
if (!c.wire || !c.wire->port_input)
|
||||
log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
|
||||
for (const auto &c : dst.chunks())
|
||||
if (!c.wire->port_input)
|
||||
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
|
||||
if (!dst.wire || !dst.wire->port_input)
|
||||
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
|
||||
int max = cell->getParam(ID::T_LIMIT_MAX).as_int();
|
||||
if (max < 0) {
|
||||
log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
|
||||
max = 0;
|
||||
}
|
||||
for (const auto &s : src) {
|
||||
auto &v = t.required[NameBit(s)];
|
||||
v = std::max(v, max);
|
||||
auto r = t.required.insert(NameBit(s));
|
||||
auto &v = r.first->second;
|
||||
if (r.second || v.first < max) {
|
||||
v.first = max;
|
||||
v.second = NameBit(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto port_name : module->ports) {
|
||||
auto wire = module->wire(port_name);
|
||||
if (wire->port_input) {
|
||||
t.has_inputs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -67,6 +67,7 @@
|
|||
# define INIT_MODULE initlibyosys
|
||||
extern "C" void INIT_MODULE();
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
@ -137,7 +138,7 @@ void yosys_banner()
|
|||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> |\n");
|
||||
log(" | Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | |\n");
|
||||
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
|
||||
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
|
||||
|
@ -540,6 +541,7 @@ void yosys_setup()
|
|||
PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
|
||||
Py_Initialize();
|
||||
PyRun_SimpleString("import sys");
|
||||
signal(SIGINT, SIG_DFL);
|
||||
#endif
|
||||
|
||||
Pass::init_register();
|
||||
|
@ -814,7 +816,9 @@ std::string proc_self_dirname()
|
|||
path = (char *) realloc((void *) path, buflen);
|
||||
while (buflen > 0 && path[buflen-1] != '/')
|
||||
buflen--;
|
||||
return std::string(path, buflen);
|
||||
std::string str(path, buflen);
|
||||
free(path);
|
||||
return str;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
std::string proc_self_dirname()
|
||||
|
@ -969,7 +973,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
|
|||
}
|
||||
}
|
||||
|
||||
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
|
||||
bool run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *from_to_label)
|
||||
{
|
||||
if (design == nullptr)
|
||||
design = yosys_design;
|
||||
|
@ -979,11 +983,11 @@ void run_frontend(std::string filename, std::string command, std::string *backen
|
|||
if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0)
|
||||
filename_trim.erase(filename_trim.size()-3);
|
||||
if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0)
|
||||
command = "verilog";
|
||||
command = " -vlog2k";
|
||||
else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0)
|
||||
command = "verilog -sv";
|
||||
command = " -sv";
|
||||
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0)
|
||||
command = "vhdl";
|
||||
command = " -vhdl";
|
||||
else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0)
|
||||
command = "blif";
|
||||
else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0)
|
||||
|
@ -1069,10 +1073,12 @@ void run_frontend(std::string filename, std::string command, std::string *backen
|
|||
if (filename != "-")
|
||||
fclose(f);
|
||||
|
||||
if (backend_command != NULL && *backend_command == "auto")
|
||||
*backend_command = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
return;
|
||||
if (command == "tcl") {
|
||||
Pass::call(design, vector<string>({command, filename}));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (filename == "-") {
|
||||
|
@ -1081,16 +1087,15 @@ void run_frontend(std::string filename, std::string command, std::string *backen
|
|||
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
|
||||
}
|
||||
|
||||
if (command == "tcl")
|
||||
Pass::call(design, vector<string>({command, filename}));
|
||||
else
|
||||
if (command[0] == ' ') {
|
||||
auto argv = split_tokens("read" + command);
|
||||
argv.push_back(filename);
|
||||
Pass::call(design, argv);
|
||||
} else
|
||||
Frontend::frontend_call(design, NULL, filename, command);
|
||||
design->check();
|
||||
}
|
||||
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
|
||||
{
|
||||
run_frontend(filename, command, nullptr, nullptr, design);
|
||||
design->check();
|
||||
return false;
|
||||
}
|
||||
|
||||
void run_pass(std::string command, RTLIL::Design *design)
|
||||
|
@ -1404,7 +1409,7 @@ struct ScriptCmdPass : public Pass {
|
|||
else if (args.size() == 2)
|
||||
run_frontend(args[1], "script", design);
|
||||
else if (args.size() == 3)
|
||||
run_frontend(args[1], "script", NULL, &args[2], design);
|
||||
run_frontend(args[1], "script", design, &args[2]);
|
||||
else
|
||||
extra_args(args, 2, design, false);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 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
|
||||
|
@ -33,7 +33,7 @@
|
|||
// This header is very boring. It just defines some general things that
|
||||
// belong nowhere else and includes the interesting headers.
|
||||
//
|
||||
// Find more information in the "CodingReadme" file.
|
||||
// Find more information in the "guidelines/GettingStarted" file.
|
||||
|
||||
|
||||
#ifndef YOSYS_H
|
||||
|
@ -147,9 +147,7 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p
|
|||
# define YS_ATTRIBUTE(...)
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
# define YS_MAYBE_UNUSED [[maybe_unused]];
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_MAYBE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define YS_MAYBE_UNUSED
|
||||
|
@ -222,6 +220,7 @@ namespace RTLIL {
|
|||
struct Wire;
|
||||
struct Cell;
|
||||
struct Memory;
|
||||
struct Process;
|
||||
struct Module;
|
||||
struct Design;
|
||||
struct Monitor;
|
||||
|
@ -245,6 +244,7 @@ namespace hashlib {
|
|||
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
|
||||
|
@ -253,6 +253,7 @@ namespace hashlib {
|
|||
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
|
||||
|
@ -349,8 +350,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern);
|
|||
void rewrite_filename(std::string &filename);
|
||||
|
||||
void run_pass(std::string command, RTLIL::Design *design = nullptr);
|
||||
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
|
||||
bool run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr, std::string *from_to_label = nullptr);
|
||||
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
|
||||
void shell(RTLIL::Design *design);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue