yosys/kernel/celltypes.h

442 lines
14 KiB
C
Raw Permalink Normal View History

2013-01-05 11:13:26 +01:00
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
2015-07-02 11:14:30 +02:00
*
2013-01-05 11:13:26 +01:00
* 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.
2015-07-02 11:14:30 +02:00
*
2013-01-05 11:13:26 +01:00
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef CELLTYPES_H
#define CELLTYPES_H
2017-12-13 22:27:52 +01:00
#include "kernel/yosys.h"
2026-02-20 12:44:30 +01:00
#include "kernel/gen_celltypes_data.h"
2013-01-05 11:13:26 +01:00
2014-09-06 15:47:46 +02:00
YOSYS_NAMESPACE_BEGIN
2013-05-24 14:38:36 +02:00
2014-08-14 15:46:51 +02:00
struct CellType
{
RTLIL::IdString type;
2014-12-28 19:24:24 +01:00
pool<RTLIL::IdString> inputs, outputs;
2014-08-16 16:12:14 +02:00
bool is_evaluable;
2024-05-16 02:15:57 +02:00
bool is_combinatorial;
bool is_synthesizable;
2014-08-14 15:46:51 +02:00
};
2013-01-05 11:13:26 +01:00
struct CellTypes
{
2014-12-28 19:24:24 +01:00
dict<RTLIL::IdString, CellType> cell_types;
2013-01-05 11:13:26 +01:00
2026-02-20 12:44:30 +01:00
static constexpr uint16_t BIT_INTERNALS_OTHER = 0x0001;
static constexpr uint16_t BIT_INTERNALS_EVAL = 0x0002;
static constexpr uint16_t BIT_INTERNALS_FF = 0x0004;
static constexpr uint16_t BIT_INTERNALS_ANYINIT = 0x0008;
static constexpr uint16_t BIT_INTERNALS_MEM = 0x0010;
static constexpr uint16_t BIT_STDCELLS_EVAL = 0x0020;
static constexpr uint16_t BIT_STDCELLS_TRISTATE = 0x0040;
static constexpr uint16_t BIT_STDCELLS_FF = 0x0080;
2026-02-20 12:44:30 +01:00
static constexpr uint16_t BITS_ALL = BIT_INTERNALS_OTHER | BIT_INTERNALS_EVAL |
BIT_INTERNALS_FF | BIT_INTERNALS_ANYINIT | BIT_INTERNALS_MEM |
BIT_STDCELLS_EVAL | BIT_STDCELLS_TRISTATE | BIT_STDCELLS_FF;
uint16_t enabled_cats = 0;
CellTypes() {}
CellTypes(RTLIL::Design *design) { setup(design); }
2014-08-14 15:46:51 +02:00
void setup(RTLIL::Design *design = NULL)
2013-03-14 15:57:47 +01:00
{
if (design)
setup_design(design);
setup_internals();
setup_internals_mem();
setup_internals_anyinit();
2013-03-14 15:57:47 +01:00
setup_stdcells();
setup_stdcells_mem();
}
2024-05-16 02:15:57 +02:00
void setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false)
2013-03-14 15:57:47 +01:00
{
2024-05-16 02:15:57 +02:00
CellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable};
2014-08-14 15:46:51 +02:00
cell_types[ct.type] = ct;
}
void setup_module(RTLIL::Module *module)
{
2014-12-28 19:24:24 +01:00
pool<RTLIL::IdString> inputs, outputs;
2014-08-14 16:13:42 +02:00
for (RTLIL::IdString wire_name : module->ports) {
RTLIL::Wire *wire = module->wire(wire_name);
2014-08-14 15:46:51 +02:00
if (wire->port_input)
inputs.insert(wire->name);
if (wire->port_output)
outputs.insert(wire->name);
}
2014-08-16 16:12:14 +02:00
setup_type(module->name, inputs, outputs);
2014-08-14 15:46:51 +02:00
}
void setup_design(RTLIL::Design *design)
{
for (auto module : design->modules())
setup_module(module);
2013-03-14 15:57:47 +01:00
}
2026-02-20 13:51:25 +01:00
void setup_internals() { enabled_cats |= BIT_INTERNALS_OTHER | BIT_INTERNALS_EVAL; }
2026-02-20 12:44:30 +01:00
void setup_internals_eval() { enabled_cats |= BIT_INTERNALS_EVAL; }
void setup_internals_ff() { enabled_cats |= BIT_INTERNALS_FF; }
void setup_internals_anyinit() { enabled_cats |= BIT_INTERNALS_ANYINIT; }
void setup_internals_mem() { enabled_cats |= BIT_INTERNALS_FF | BIT_INTERNALS_MEM; }
2026-02-20 13:51:25 +01:00
void setup_stdcells() { enabled_cats |= BIT_STDCELLS_EVAL | BIT_STDCELLS_TRISTATE; }
2026-02-20 12:44:30 +01:00
void setup_stdcells_eval() { enabled_cats |= BIT_STDCELLS_EVAL; }
void setup_stdcells_mem() { enabled_cats |= BIT_STDCELLS_FF; }
2013-01-05 11:13:26 +01:00
2026-02-20 12:44:30 +01:00
void clear()
{
2026-02-20 12:44:30 +01:00
cell_types.clear();
enabled_cats = 0;
2013-01-05 11:13:26 +01:00
}
2026-02-20 12:44:30 +01:00
bool builtin_match(size_t idx) const
{
2026-02-20 12:44:30 +01:00
if (!enabled_cats || idx >= (size_t)StaticCellTypes::GEN_MAX_CELLS)
return false;
using namespace StaticCellTypes::GeneratedData;
if (!is_known[idx])
return false;
if (!is_stdcell[idx]) {
if ((enabled_cats & BIT_INTERNALS_EVAL) && is_evaluable[idx])
return true;
if ((enabled_cats & BIT_INTERNALS_FF) && is_ff[idx])
return true;
if ((enabled_cats & BIT_INTERNALS_ANYINIT) && is_anyinit[idx])
return true;
if ((enabled_cats & BIT_INTERNALS_MEM) && is_mem_noff[idx])
return true;
if (enabled_cats & BIT_INTERNALS_OTHER) {
if (!is_evaluable[idx] && !is_ff[idx] && !is_mem_noff[idx] && !is_anyinit[idx])
return true;
}
} else {
if ((enabled_cats & BIT_STDCELLS_EVAL) && is_evaluable[idx])
return true;
if ((enabled_cats & BIT_STDCELLS_TRISTATE) && is_tristate[idx])
return true;
if ((enabled_cats & BIT_STDCELLS_FF) && is_ff[idx])
return true;
}
2026-02-20 12:44:30 +01:00
return false;
2013-01-05 11:13:26 +01:00
}
2026-02-20 12:44:30 +01:00
bool builtin_is_known(size_t idx) const
2013-01-05 11:13:26 +01:00
{
2026-02-20 12:44:30 +01:00
return enabled_cats && idx < (size_t)StaticCellTypes::GEN_MAX_CELLS &&
2026-02-21 12:23:15 +01:00
StaticCellTypes::GeneratedData::is_known[idx];
2013-01-05 11:13:26 +01:00
}
2026-02-20 12:44:30 +01:00
bool cell_known(const RTLIL::IdString &type) const
2013-01-05 11:13:26 +01:00
{
2026-02-20 12:44:30 +01:00
if (enabled_cats == BITS_ALL) {
if (builtin_is_known(type.index_))
return true;
} else if (builtin_match(type.index_)) {
return true;
}
2014-08-14 15:46:51 +02:00
return cell_types.count(type) != 0;
2013-01-05 11:13:26 +01:00
}
2026-02-23 13:46:34 +01:00
bool cell_output(const RTLIL::IdString &type, const RTLIL::IdString &port) const
2013-01-05 11:13:26 +01:00
{
2026-02-23 13:46:34 +01:00
auto it = cell_types.find(type);
if (it != cell_types.end())
return it->second.outputs.count(port) != 0;
2026-02-20 12:44:30 +01:00
size_t idx = type.index_;
bool is_builtin = (enabled_cats == BITS_ALL) ? builtin_is_known(idx) : builtin_match(idx);
if (is_builtin) {
uint32_t target = (uint32_t)port.index_;
uint16_t count = StaticCellTypes::GeneratedData::port_outputs_counts[idx];
for (uint16_t i = 0; i < count; i++)
if (StaticCellTypes::GeneratedData::port_outputs_ports[idx][i] == target)
return true;
}
2026-02-23 13:46:34 +01:00
return false;
2013-01-05 11:13:26 +01:00
}
2026-02-20 12:44:30 +01:00
bool cell_input(const RTLIL::IdString &type, const RTLIL::IdString &port) const
2013-01-05 11:13:26 +01:00
{
2026-02-23 13:46:34 +01:00
auto it = cell_types.find(type);
if (it != cell_types.end())
return it->second.inputs.count(port) != 0;
2026-02-20 12:44:30 +01:00
size_t idx = type.index_;
bool is_builtin = (enabled_cats == BITS_ALL) ? builtin_is_known(idx) : builtin_match(idx);
if (is_builtin) {
uint32_t target = (uint32_t)port.index_;
uint16_t count = StaticCellTypes::GeneratedData::port_inputs_counts[idx];
for (uint16_t i = 0; i < count; i++)
if (StaticCellTypes::GeneratedData::port_inputs_ports[idx][i] == target)
return true;
}
2026-02-23 13:46:34 +01:00
return false;
2013-01-05 11:13:26 +01:00
}
RTLIL::PortDir cell_port_dir(RTLIL::IdString type, RTLIL::IdString port) const
{
2026-02-23 13:46:34 +01:00
auto it = cell_types.find(type);
if (it != cell_types.end()) {
bool is_input = it->second.inputs.count(port);
bool is_output = it->second.outputs.count(port);
return RTLIL::PortDir(is_input + is_output * 2);
}
2026-02-20 12:44:30 +01:00
size_t idx = type.index_;
bool is_builtin = (enabled_cats == BITS_ALL) ? builtin_is_known(idx) : builtin_match(idx);
if (is_builtin) {
bool is_in = false, is_out = false;
uint32_t target = (uint32_t)port.index_;
uint16_t ic = StaticCellTypes::GeneratedData::port_inputs_counts[idx];
for (uint16_t i = 0; i < ic; i++)
2026-02-21 12:23:15 +01:00
if (StaticCellTypes::GeneratedData::port_inputs_ports[idx][i] == target)
{ is_in = true; break; }
2026-02-20 12:44:30 +01:00
uint16_t oc = StaticCellTypes::GeneratedData::port_outputs_counts[idx];
for (uint16_t i = 0; i < oc; i++)
2026-02-21 12:23:15 +01:00
if (StaticCellTypes::GeneratedData::port_outputs_ports[idx][i] == target)
{ is_out = true; break; }
2026-02-20 12:44:30 +01:00
return RTLIL::PortDir(is_in + is_out * 2);
}
2026-02-23 13:46:34 +01:00
return RTLIL::PD_UNKNOWN;
}
2026-02-20 12:44:30 +01:00
bool cell_evaluable(const RTLIL::IdString &type) const
2014-08-16 16:12:14 +02:00
{
2026-02-23 13:46:34 +01:00
auto it = cell_types.find(type);
if (it != cell_types.end())
return it->second.is_evaluable;
2026-02-20 12:44:30 +01:00
size_t idx = type.index_;
bool is_builtin = (enabled_cats == BITS_ALL) ? builtin_is_known(idx) : builtin_match(idx);
if (is_builtin)
2026-02-21 12:23:15 +01:00
return idx < (size_t)StaticCellTypes::GEN_MAX_CELLS &&
StaticCellTypes::GeneratedData::is_cell_evaluable[idx];
2026-02-23 13:46:34 +01:00
return false;
2014-08-16 16:12:14 +02:00
}
static RTLIL::Const eval_not(RTLIL::Const v)
{
2025-08-28 03:55:47 +02:00
for (auto bit : v)
if (bit == State::S0) bit = State::S1;
else if (bit == State::S1) bit = State::S0;
return v;
}
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
2013-01-05 11:13:26 +01:00
{
if (type == ID($sshr) && !signed1)
type = ID($shr);
if (type == ID($sshl) && !signed1)
type = ID($shl);
if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&
type != ID($pos) && type != ID($buf) && type != ID($neg) && type != ID($not)) {
if (!signed1 || !signed2)
signed1 = false, signed2 = false;
}
#define HANDLE_CELL_TYPE(_t) if (type == ID($##_t)) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);
2013-01-05 11:13:26 +01:00
HANDLE_CELL_TYPE(not)
HANDLE_CELL_TYPE(and)
HANDLE_CELL_TYPE(or)
HANDLE_CELL_TYPE(xor)
HANDLE_CELL_TYPE(xnor)
HANDLE_CELL_TYPE(reduce_and)
HANDLE_CELL_TYPE(reduce_or)
HANDLE_CELL_TYPE(reduce_xor)
HANDLE_CELL_TYPE(reduce_xnor)
HANDLE_CELL_TYPE(reduce_bool)
HANDLE_CELL_TYPE(logic_not)
HANDLE_CELL_TYPE(logic_and)
HANDLE_CELL_TYPE(logic_or)
HANDLE_CELL_TYPE(shl)
HANDLE_CELL_TYPE(shr)
HANDLE_CELL_TYPE(sshl)
HANDLE_CELL_TYPE(sshr)
HANDLE_CELL_TYPE(shift)
HANDLE_CELL_TYPE(shiftx)
2013-01-05 11:13:26 +01:00
HANDLE_CELL_TYPE(lt)
HANDLE_CELL_TYPE(le)
HANDLE_CELL_TYPE(eq)
HANDLE_CELL_TYPE(ne)
HANDLE_CELL_TYPE(eqx)
HANDLE_CELL_TYPE(nex)
2013-01-05 11:13:26 +01:00
HANDLE_CELL_TYPE(ge)
HANDLE_CELL_TYPE(gt)
HANDLE_CELL_TYPE(add)
HANDLE_CELL_TYPE(sub)
HANDLE_CELL_TYPE(mul)
HANDLE_CELL_TYPE(div)
HANDLE_CELL_TYPE(mod)
HANDLE_CELL_TYPE(divfloor)
HANDLE_CELL_TYPE(modfloor)
2013-01-05 11:13:26 +01:00
HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos)
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
2024-09-18 16:53:56 +02:00
if (type.in(ID($_BUF_), ID($buf)))
2014-10-03 10:12:28 +02:00
return arg1;
if (type == ID($_NOT_))
return eval_not(arg1);
if (type == ID($_AND_))
2013-01-05 11:13:26 +01:00
return const_and(arg1, arg2, false, false, 1);
if (type == ID($_NAND_))
return eval_not(const_and(arg1, arg2, false, false, 1));
if (type == ID($_OR_))
2013-01-05 11:13:26 +01:00
return const_or(arg1, arg2, false, false, 1);
if (type == ID($_NOR_))
2017-02-16 12:17:03 +01:00
return eval_not(const_or(arg1, arg2, false, false, 1));
if (type == ID($_XOR_))
2013-01-05 11:13:26 +01:00
return const_xor(arg1, arg2, false, false, 1);
if (type == ID($_XNOR_))
return const_xnor(arg1, arg2, false, false, 1);
if (type == ID($_ANDNOT_))
return const_and(arg1, eval_not(arg2), false, false, 1);
if (type == ID($_ORNOT_))
return const_or(arg1, eval_not(arg2), false, false, 1);
2013-01-05 11:13:26 +01:00
if (errp != nullptr) {
*errp = true;
return State::Sm;
}
2013-05-24 14:38:36 +02:00
log_abort();
2013-01-05 11:13:26 +01:00
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
2013-01-05 11:13:26 +01:00
{
if (cell->type == ID($slice)) {
int width = cell->parameters.at(ID::Y_WIDTH).as_int();
int offset = cell->parameters.at(ID::OFFSET).as_int();
2025-08-28 03:55:47 +02:00
return arg1.extract(offset, width);
2014-02-07 17:44:57 +01:00
}
if (cell->type == ID($concat)) {
2014-02-07 17:44:57 +01:00
RTLIL::Const ret = arg1;
2025-08-28 03:55:47 +02:00
ret.append(arg2);
2014-02-07 17:44:57 +01:00
return ret;
}
2022-01-24 16:02:29 +01:00
if (cell->type == ID($bmux))
return const_bmux(arg1, arg2);
if (cell->type == ID($demux))
return const_demux(arg1, arg2);
if (cell->type == ID($bweqx))
return const_bweqx(arg1, arg2);
if (cell->type == ID($lut))
2014-08-31 17:42:38 +02:00
{
int width = cell->parameters.at(ID::WIDTH).as_int();
2014-08-31 17:42:38 +02:00
std::vector<RTLIL::State> t = cell->parameters.at(ID::LUT).to_bits();
while (GetSize(t) < (1 << width))
t.push_back(State::S0);
2014-08-31 17:42:38 +02:00
t.resize(1 << width);
2022-01-24 16:02:29 +01:00
return const_bmux(t, arg1);
2014-08-31 17:42:38 +02:00
}
if (cell->type == ID($sop))
2016-06-17 13:46:01 +02:00
{
int width = cell->parameters.at(ID::WIDTH).as_int();
int depth = cell->parameters.at(ID::DEPTH).as_int();
std::vector<RTLIL::State> t = cell->parameters.at(ID::TABLE).to_bits();
2016-06-17 13:46:01 +02:00
2026-02-21 12:23:15 +01:00
while (GetSize(t) < width*depth*2)
t.push_back(State::S0);
2016-06-17 13:46:01 +02:00
2016-06-17 16:31:16 +02:00
RTLIL::State default_ret = State::S0;
2016-06-17 13:46:01 +02:00
for (int i = 0; i < depth; i++)
{
bool match = true;
2016-06-17 16:31:16 +02:00
bool match_x = true;
2016-06-17 13:46:01 +02:00
for (int j = 0; j < width; j++) {
RTLIL::State a = arg1.at(j);
2026-02-21 12:23:15 +01:00
if (t.at(2*width*i + 2*j + 0) == State::S1) {
2016-06-17 16:31:16 +02:00
if (a == State::S1) match_x = false;
if (a != State::S0) match = false;
}
2026-02-21 12:23:15 +01:00
if (t.at(2*width*i + 2*j + 1) == State::S1) {
2016-06-17 16:31:16 +02:00
if (a == State::S0) match_x = false;
if (a != State::S1) match = false;
}
2016-06-17 13:46:01 +02:00
}
if (match)
return State::S1;
2016-06-17 16:31:16 +02:00
if (match_x)
default_ret = State::Sx;
2016-06-17 13:46:01 +02:00
}
2016-06-17 16:31:16 +02:00
return default_ret;
2016-06-17 13:46:01 +02:00
}
bool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool();
bool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool();
int result_len = cell->parameters.count(ID::Y_WIDTH) > 0 ? cell->parameters[ID::Y_WIDTH].as_int() : -1;
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
2013-01-05 11:13:26 +01:00
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
2013-01-05 11:13:26 +01:00
{
if (cell->type.in(ID($mux), ID($_MUX_)))
return const_mux(arg1, arg2, arg3);
if (cell->type == ID($_NMUX_))
return eval_not(const_mux(arg1, arg2, arg3));
if (cell->type == ID($bwmux))
return const_bwmux(arg1, arg2, arg3);
if (cell->type == ID($pmux))
return const_pmux(arg1, arg2, arg3);
if (cell->type == ID($_AOI3_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
if (cell->type == ID($_OAI3_))
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));
log_assert(arg3.size() == 0);
return eval(cell, arg1, arg2, errp);
2013-01-05 11:13:26 +01:00
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
{
if (cell->type == ID($_AOI4_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == ID($_OAI4_))
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.size() == 0);
return eval(cell, arg1, arg2, arg3, errp);
}
2013-01-05 11:13:26 +01:00
};
2014-12-29 14:30:33 +01:00
extern CellTypes yosys_celltypes;
2014-09-06 15:47:46 +02:00
YOSYS_NAMESPACE_END
2013-01-05 11:13:26 +01:00
#endif