/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/macc.h"
#include "kernel/celltypes.h"
#include "frontends/verilog/verilog_frontend.h"
#include "backends/ilang/ilang_backend.h"
#include <string.h>
#include <algorithm>
YOSYS_NAMESPACE_BEGIN
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
RTLIL::Const::Const()
{
flags = RTLIL::CONST_FLAG_NONE;
}
RTLIL::Const::Const(std::string str)
{
flags = RTLIL::CONST_FLAG_STRING;
for (int i = str.size()-1; i >= 0; i--) {
unsigned char ch = str[i];
for (int j = 0; j < 8; j++) {
bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
ch = ch >> 1;
}
}
}
RTLIL::Const::Const(int val, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
for (int i = 0; i < width; i++) {
bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
val = val >> 1;
}
}
RTLIL::Const::Const(RTLIL::State bit, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
for (int i = 0; i < width; i++)
bits.push_back(bit);
}
RTLIL::Const::Const(const std::vector<bool> &bits)
{
flags = RTLIL::CONST_FLAG_NONE;
for (auto b : bits)
this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0);
}
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if (bits.size() != other.bits.size())
return bits.size() < other.bits.size();
for (size_t i = 0; i < bits.size(); i++)
if (bits[i] != other.bits[i])
return bits[i] < other.bits[i];
return false;
}
bool RTLIL::Const::operator ==(const RTLIL::Const &other) const
{
return bits == other.bits;
}
bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
{
return bits != other.bits;
}
bool RTLIL::Const::as_bool() const
{
for (size_t i = 0; i < bits.size(); i++)
if (bits[i] == RTLIL::S1)
return true;
return false;
}
int RTLIL::Const::as_int(bool is_signed) const
{
int32_t ret = 0;
for (size_t i = 0; i < bits.size() && i < 32; i++)
if (bits[i] == RTLIL::S1)
ret |= 1 << i;
if (is_signed && bits.back() == RTLIL::S1)
for (size_t i = bits.size(); i < 32; i++)
ret |= 1 << i;
return ret;
}
std::string RTLIL::Const::as_string() const
{
std::string ret;
for (size_t i = bits.size(); i > 0; i--)
switch (bits[i-1]) {
case S0: ret += "0"; break;
case S1: ret += "1"; break;
case Sx: ret += "x"; break;
case Sz: ret += "z"; break;
case Sa: ret += "-"; break;
case Sm: ret += "m"; break;
}
return ret;
}
RTLIL::Const RTLIL::Const::from_string(std::string str)
{
Const c;
for (auto it = str.rbegin(); it != str.rend(); it++)
switch (*it) {
case '0': c.bits.push_back(State::S0); break;
case '1': c.bits.push_back(State::S1); break;
case 'x': c.bits.push_back(State::Sx); break;
case 'z': c.bits.push_back(State::Sz); break;
case 'm': c.bits.push_back(State::Sm); break;
default: c.bits.push_back(State::Sa);
}
return c;
}
std::string RTLIL::Const::decode_string() const
{
std::string string;
std::vector<char> string_chars;
for (int i = 0; i < int (bits.size()); i += 8) {
char ch = 0;
for (int j = 0; j < 8 && i + j < int (bits.size()); j++)
if (bits[i + j] == RTLIL::State::S1)
ch |= 1 << j;
if (ch != 0)
string_chars.push_back(ch);
}
for (int i = int (string_chars.size()) - 1; i >= 0; i--)
string += string_chars[i];
return string;
}
bool RTLIL::Const::is_fully_zero() const
{
cover("kernel.rtlil.const.is_fully_zero");
for (auto bit : bits)
if (bit != RTLIL::State::S0)
return false;
return true;
}
bool RTLIL::Const::is_fully_ones() const
{
cover("kernel.rtlil.const.is_fully_ones");
for (auto bit : bits)
if (bit != RTLIL::State::S1)
return false;
return true;
}
bool RTLIL::Const::is_fully_def() const
{
cover("kernel.rtlil.const.is_fully_def");
for (auto bit : bits)
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
return false;
return true;
}
bool RTLIL::Const::is_fully_undef() const
{
cover("kernel.rtlil.const.is_fully_undef");
for (auto bit : bits)
if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz)
return false;
return true;
}
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id)
{
attributes[id] = RTLIL::Const(1);
}
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{
if (attributes.count(id) == 0)
return false;
return attributes.at(id).as_bool();
}
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
{
string attrval;
for (auto &s : data) {
if (!attrval.empty())
attrval += "|";
attrval += s;
}
attributes[id] = RTLIL::Const(attrval);
}
void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
{
pool<string> union_data = get_strpool_attribute(id);
union_data.insert(data.begin(), data.end());
if (!union_data.empty())
set_strpool_attribute(id, union_data);
}
pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
{
pool<string> data;
if (attributes.count(id) != 0)
for (auto s : split_tokens(attributes.at(id).decode_string(), "|"))
data.insert(s);
return data;
}
void RTLIL::AttrObject::set_src_attribute(const std::string &src)
{
if (src.empty())
attributes.erase("\\src");
else
attributes["\\src"] = src;
}
std::string RTLIL::AttrObject::get_src_attribute() const
{
std::string src;
if (attributes.count("\\src"))
src = attributes.at("\\src").decode_string();
return src;
}
bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
{
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
return true;
if (selected_members.count(mod_name) > 0)
return true;
return false;
}
bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const
{
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
return true;
return false;
}
bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
{
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
return true;
if (selected_members.count(mod_name) > 0)
if (selected_members.at(mod_name).count(memb_name) > 0)
return true;
return false;
}
void RTLIL::Selection::optimize(RTLIL::Design *design)
{
if (full_selection) {
selected_modules.clear();
selected_members.clear();
return;
}
std::vector<RTLIL::IdString> del_list, add_list;
del_list.clear();
for (auto mod_name : selected_modules) {
if (design->modules_.count(mod_name) == 0)
del_list.push_back(mod_name);
selected_members.erase(mod_name);
}
for (auto mod_name : del_list)
selected_modules.erase(mod_name);
del_list.clear();
for (auto &it : selected_members)
if (design->modules_.count(it.first) == 0)
del_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
for (auto &it : selected_members) {
del_list.clear();
for (auto memb_name : it.second)
if (design->modules_[it.first]->count_id(memb_name) == 0)
del_list.push_back(memb_name);
for (auto memb_name : del_list)
it.second.erase(memb_name);
}
del_list.clear();
add_list.clear();
for (auto &it : selected_members)
if (it.second.size() == 0)
del_list.push_back(it.first);
else if (it.second.size() == design->modules_[it.first]->wires_.size() + design->modules_[it.first]->memories.size() +
design->modules_[it.first]->cells_.size() + design->modules_[it.first]->processes.size())
add_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
for (auto mod_name : add_list) {
selected_members.erase(mod_name);
selected_modules.insert(mod_name);
}
if (selected_modules.size() == design->modules_.size()) {
full_selection = true;
selected_modules.clear();
selected_members.clear();
}
}
RTLIL::Design::Design()
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
hashidx_ = hashidx_count;
refcount_modules_ = 0;
selection_stack.push_back(RTLIL::Selection());
}
RTLIL::Design::~Design()
{
for (auto it = modules_.begin(); it != modules_.end(); ++it)
delete it->second;
for (auto n : verilog_packages)
delete n;
for (auto n : verilog_globals)
delete n;
}
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
{
return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
}
RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
RTLIL::Module *RTLIL::Design::top_module()
{
RTLIL::Module *module = nullptr;
int module_count = 0;
for (auto mod : selected_modules()) {
if (mod->get_bool_attribute("\\top"))
return mod;
module_count++;
module = mod;
}
return module_count == 1 ? module : nullptr;
}
void RTLIL::Design::add(RTLIL::Module *module)
{
log_assert(modules_.count(module->name) == 0);
log_assert(refcount_modules_ == 0);
modules_[module->name] = module;
module->design = this;
for (auto mon : monitors)
mon->notify_module_add(module);
if (yosys_xtrace) {
log("#X# New Module: %s\n", log_id(module));
log_backtrace("-X- ", yosys_xtrace-1);
}
}
RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
{
log_assert(modules_.count(name) == 0);
log_assert(refcount_modules_ == 0);
RTLIL::Module *module = new RTLIL::Module;
modules_[name] = module;
module->design = this;
module->name = name;
for (auto mon : monitors)
mon->notify_module_add(module);
if (yosys_xtrace) {
log("#X# New Module: %s\n", log_id(module));
log_backtrace("-X- ", yosys_xtrace-1);
}
return module;
}
void RTLIL::Design::scratchpad_unset(std::string varname)
{
scratchpad.erase(varname);
}
void RTLIL::Design::scratchpad_set_int(std::string varname, int value)
{
scratchpad[varname] = stringf("%d", value);
}
void RTLIL::Design::scratchpad_set_bool(std::string varname, bool value)
{
scratchpad[varname] = value ? "true" : "false";
}
void RTLIL::Design::scratchpad_set_string(std::string varname, std::string value)
{
scratchpad[varname] = value;
}
int RTLIL::Design::scratchpad_get_int(std::string varname, int default_value) const
{
if (scratchpad.count(varname) == 0)
return default_value;
std::string str = scratchpad.at(varname);
if (str == "0" || str == "false")
return 0;
if (str == "1" || str == "true")
return 1;
char *endptr = nullptr;
long int parsed_value = strtol(str.c_str(), &endptr, 10);
return *endptr ? default_value : parsed_value;
}
bool RTLIL::Design::scratchpad_get_bool(std::string varname, bool default_value) const
{
if (scratchpad.count(varname) == 0)
return default_value;
std::string str = scratchpad.at(varname);
if (str == "0" || str == "false")
return false;
if (str == "1" || str == "true")
return true;
return default_value;
}
std::string RTLIL::Design::scratchpad_get_string(std::string varname, std::string default_value) const
{
if (scratchpad.count(varname) == 0)
return default_value;
return scratchpad.at(varname);
}
void RTLIL::Design::remove(RTLIL::Module *module)
{
for (auto mon : monitors)
mon->notify_module_del(module);
if (yosys_xtrace) {
log("#X# Remove Module: %s\n", log_id(module));
log_backtrace("-X- ", yosys_xtrace-1);
}
log_assert(modules_.at(module->name) == module);
modules_.erase(module->name);
delete module;
}
void RTLIL::Design::rename(RTLIL::Module *module, RTLIL::IdString new_name)
{
modules_.erase(module->name);
module->name = new_name;
add(module);
}
void RTLIL::Design::sort()
{
scratchpad.sort();
modules_.sort(sort_by_id_str());
for (auto &it : modules_)
it.second->sort();
}
void RTLIL::Design::check()
{
#ifndef NDEBUG
for (auto &it : modules_) {
log_assert(this == it.second->design);
log_assert(it.first == it.second->name);
log_assert(!it.first.empty());
it.second->check();
}
#endif
}
void RTLIL::Design::optimize()
{
for (auto &it : modules_)
it.second->optimize();
for (auto &it : selection_stack)
it.optimize(this);
for (auto &it : selection_vars)
it.second.optimize(this);
}
bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_module(mod_name);
}
bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_whole_module(mod_name);
}
bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_member(mod_name, memb_name);
}
bool RTLIL::Design::selected_module(RTLIL::Module *mod) const
{
return selected_module(mod->name);
}
bool RTLIL::Design::selected_whole_module(RTLIL::Module *mod) const
{
return selected_whole_module(mod->name);
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
result.push_back(it.second);
return result;
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
result.push_back(it.second);
return result;
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (it.second->get_bool_attribute("\\blackbox"))
continue;
else if (selected_whole_module(it.first))
result.push_back(it.second);
else if (selected_module(it.first))
log_warning("Ignoring partially selected module %s.\n", log_id(it.first));
return result;
}
RTLIL::Module::Module()
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
hashidx_ = hashidx_count;
design = nullptr;
refcount_wires_ = 0;
refcount_cells_ = 0;
}
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;
}
void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
{
log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
}
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
{
if (mayfail)
return RTLIL::IdString();
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail)
{
if (mayfail)
return RTLIL::IdString();
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
size_t RTLIL::Module::count_id(RTLIL::IdString id)
{
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
}
#ifndef NDEBUG
namespace {
struct InternalCellChecker
{
RTLIL::Module *module;
RTLIL::Cell *cell;
pool<RTLIL::IdString> expected_params, expected_ports;
InternalCellChecker(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) { }
void error(int linenr)
{
std::stringstream buf;
ILANG_BACKEND::dump_cell(buf, " ", cell);
log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s",
module ? module->name.c_str() : "", module ? "." : "",
cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str());
}
int param(const char *name)
{
if (cell->parameters.count(name) == 0)
error(__LINE__);
expected_params.insert(name);
return cell->parameters.at(name).as_int();
}
int param_bool(const char *name)
{
int v = param(name);
if (cell->parameters.at(name).bits.size() > 32)
error(__LINE__);
if (v != 0 && v != 1)
error(__LINE__);
return v;
}
void param_bits(const char *name, int width)
{
param(name);
if (int(cell->parameters.at(name).bits.size()) != width)
error(__LINE__);
}
void port(const char *name, int width)
{
if (!cell->hasPort(name))
error(__LINE__);
if (cell->getPort(name).size() != width)
error(__LINE__);
expected_ports.insert(name);
}
void check_expected(bool check_matched_sign = true)
{
for (auto ¶ : cell->parameters)
if (expected_params.count(para.first) == 0)
error(__LINE__);
for (auto &conn : cell->connections())
if (expected_ports.count(conn.first) == 0)
error(__LINE__);
if (expected_params.count("\\A_SIGNED") != 0 && expected_params.count("\\B_SIGNED") && check_matched_sign) {
bool a_is_signed = param("\\A_SIGNED") != 0;
bool b_is_signed = param("\\B_SIGNED") != 0;
if (a_is_signed != b_is_signed)
error(__LINE__);
}
}
void check_gate(const char *ports)
{
if (cell->parameters.size() != 0)
error(__LINE__);
for (const char *p = ports; *p; p++) {
char portname[3] = { '\\', *p, 0 };
if (!cell->hasPort(portname))
error(__LINE__);
if (cell->getPort(portname).size() != 1)
error(__LINE__);
}
for (auto &conn : cell->connections()) {
if (conn.first.size() != 2 || conn.first[0] != '\\')
error(__LINE__);
if (strchr(ports, conn.first[1]) == NULL)
error(__LINE__);
}
}
void check()
{
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
return;
if (cell->type.in("$not", "$pos", "$neg")) {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type.in("$and", "$or", "$xor", "$xnor")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected(false);
return;
}
if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected(cell->type != "$pow");
return;
}
if (cell->type == "$fa") {
port("\\A", param("\\WIDTH"));
port("\\B", param("\\WIDTH"));
port("\\C", param("\\WIDTH"));
port("\\X", param("\\WIDTH"));
port("\\Y", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$lcu") {
port("\\P", param("\\WIDTH"));
port("\\G", param("\\WIDTH"));
port("\\CI", 1);
port("\\CO", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$alu") {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\CI", 1);
port("\\BI", 1);
port("\\X", param("\\Y_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
port("\\CO", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type == "$macc") {
param("\\CONFIG");
param("\\CONFIG_WIDTH");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
Macc().from_cell(cell);
return;
}
if (cell->type == "$logic_not") {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected();
return;
}
if (cell->type == "$logic_and" || cell->type == "$logic_or") {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
check_expected(false);
return;
}
if (cell->type == "$slice") {
param("\\OFFSET");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
if (param("\\OFFSET") + param("\\Y_WIDTH") > param("\\A_WIDTH"))
error(__LINE__);
check_expected();
return;
}
if (cell->type == "$concat") {
port("\\A", param("\\A_WIDTH"));
port("\\B", param("\\B_WIDTH"));
port("\\Y", param("\\A_WIDTH") + param("\\B_WIDTH"));
check_expected();
return;
}
if (cell->type == "$mux") {
port("\\A", param("\\WIDTH"));
port("\\B", param("\\WIDTH"));
port("\\S", 1);
port("\\Y", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$pmux") {
port("\\A", param("\\WIDTH"));
port("\\B", param("\\WIDTH") * param("\\S_WIDTH"));
port("\\S", param("\\S_WIDTH"));
port("\\Y", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$lut") {
param("\\LUT");
port("\\A", param("\\WIDTH"));
port("\\Y", 1);
check_expected();
return;
}
if (cell->type == "$sop") {
param("\\DEPTH");
param("\\TABLE");
port("\\A", param("\\WIDTH"));
port("\\Y", 1);
check_expected();
return;
}
if (cell->type == "$sr") {
param_bool("\\SET_POLARITY");
param_bool("\\CLR_POLARITY");
port("\\SET", param("\\WIDTH"));
port("\\CLR", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$ff") {
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$dff") {
param_bool("\\CLK_POLARITY");
port("\\CLK", 1);
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$dffe") {
param_bool("\\CLK_POLARITY");
param_bool("\\EN_POLARITY");
port("\\CLK", 1);
port("\\EN", 1);
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$dffsr") {
param_bool("\\CLK_POLARITY");
param_bool("\\SET_POLARITY");
param_bool("\\CLR_POLARITY");
port("\\CLK", 1);
port("\\SET", param("\\WIDTH"));
port("\\CLR", param("\\WIDTH"));
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$adff") {
param_bool("\\CLK_POLARITY");
param_bool("\\ARST_POLARITY");
param_bits("\\ARST_VALUE", param("\\WIDTH"));
port("\\CLK", 1);
port("\\ARST", 1);
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$dlatch") {
param_bool("\\EN_POLARITY");
port("\\EN", 1);
port("\\D", param("\\WIDTH"));
port("\\Q", param("\\WIDTH"));
check_expected();
return;
}
if (cell->type == "$dlatchsr") {
param_bool("\\EN_POLARITY");
param_bool("\\SET_POLARITY");
param_bool("\\CLR_POLARITY");
port("\\EN", 1);
port("\\SET", param("\\WIDTH"));
port("\\CLR", param("\\WIDTH"));