mirror of
https://github.com/YosysHQ/yosys
synced 2025-08-07 03:31:24 +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
|
@ -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
|
||||
|
@ -41,8 +41,6 @@ struct Async2syncPass : public Pass {
|
|||
log("reset value in the next cycle regardless of the data-in value at the time of\n");
|
||||
log("the clock edge.\n");
|
||||
log("\n");
|
||||
log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
|
@ -74,16 +72,13 @@ struct Async2syncPass : public Pass {
|
|||
FfData ff(&initvals, cell);
|
||||
|
||||
// Skip for $_FF_ and $ff cells.
|
||||
if (ff.has_d && !ff.has_clk && !ff.has_en)
|
||||
if (ff.has_gclk)
|
||||
continue;
|
||||
|
||||
if (ff.has_clk)
|
||||
{
|
||||
if (!ff.has_sr && !ff.has_arst)
|
||||
continue;
|
||||
|
||||
if (ff.has_sr) {
|
||||
ff.unmap_ce_srst(module);
|
||||
ff.unmap_ce_srst();
|
||||
|
||||
log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
|
@ -128,8 +123,41 @@ struct Async2syncPass : public Pass {
|
|||
ff.sig_d = new_d;
|
||||
ff.sig_q = new_q;
|
||||
ff.has_sr = false;
|
||||
} else if (ff.has_aload) {
|
||||
ff.unmap_ce_srst();
|
||||
|
||||
log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_d), log_signal(ff.sig_q));
|
||||
|
||||
initvals.remove_init(ff.sig_q);
|
||||
|
||||
Wire *new_d = module->addWire(NEW_ID, ff.width);
|
||||
Wire *new_q = module->addWire(NEW_ID, ff.width);
|
||||
|
||||
if (ff.pol_aload) {
|
||||
if (!ff.is_fine) {
|
||||
module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
|
||||
module->addMux(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
|
||||
} else {
|
||||
module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
|
||||
module->addMuxGate(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
|
||||
}
|
||||
} else {
|
||||
if (!ff.is_fine) {
|
||||
module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
|
||||
module->addMux(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
|
||||
} else {
|
||||
module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
|
||||
module->addMuxGate(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
|
||||
}
|
||||
}
|
||||
|
||||
ff.sig_d = new_d;
|
||||
ff.sig_q = new_q;
|
||||
ff.has_aload = false;
|
||||
} else if (ff.has_arst) {
|
||||
ff.unmap_srst(module);
|
||||
ff.unmap_srst();
|
||||
|
||||
log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
|
@ -154,9 +182,12 @@ struct Async2syncPass : public Pass {
|
|||
ff.sig_q = new_q;
|
||||
ff.has_arst = false;
|
||||
ff.has_srst = true;
|
||||
ff.ce_over_srst = false;
|
||||
ff.val_srst = ff.val_arst;
|
||||
ff.sig_srst = ff.sig_arst;
|
||||
ff.pol_srst = ff.pol_arst;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -164,25 +195,25 @@ struct Async2syncPass : public Pass {
|
|||
// Latch.
|
||||
log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
|
||||
log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
|
||||
|
||||
initvals.remove_init(ff.sig_q);
|
||||
|
||||
Wire *new_q = module->addWire(NEW_ID, ff.width);
|
||||
Wire *new_d;
|
||||
|
||||
if (ff.has_d) {
|
||||
if (ff.has_aload) {
|
||||
new_d = module->addWire(NEW_ID, ff.width);
|
||||
if (ff.pol_en) {
|
||||
if (ff.pol_aload) {
|
||||
if (!ff.is_fine)
|
||||
module->addMux(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
|
||||
module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
|
||||
else
|
||||
module->addMuxGate(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
|
||||
module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
|
||||
} else {
|
||||
if (!ff.is_fine)
|
||||
module->addMux(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
|
||||
module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
|
||||
else
|
||||
module->addMuxGate(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
|
||||
module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
|
||||
}
|
||||
} else {
|
||||
new_d = new_q;
|
||||
|
@ -231,15 +262,12 @@ struct Async2syncPass : public Pass {
|
|||
|
||||
ff.sig_d = new_d;
|
||||
ff.sig_q = new_q;
|
||||
ff.has_en = false;
|
||||
ff.has_aload = false;
|
||||
ff.has_arst = false;
|
||||
ff.has_sr = false;
|
||||
ff.has_d = true;
|
||||
ff.has_gclk = true;
|
||||
}
|
||||
|
||||
IdString name = cell->name;
|
||||
module->remove(cell);
|
||||
ff.emit(module, name);
|
||||
ff.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -151,18 +151,36 @@ struct Clk2fflogicPass : public Pass {
|
|||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
FfData ff(&initvals, cell);
|
||||
|
||||
if (ff.has_d && !ff.has_clk && !ff.has_en) {
|
||||
if (ff.has_gclk) {
|
||||
// Already a $ff or $_FF_ cell.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ff.has_clk) {
|
||||
log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q));
|
||||
} else if (ff.has_aload) {
|
||||
log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
|
||||
} else {
|
||||
// $sr.
|
||||
log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
|
||||
}
|
||||
|
||||
ff.remove();
|
||||
|
||||
// Strip spaces from signal name, since Yosys IDs can't contain spaces
|
||||
// Spaces only occur when have a signal that's a slice of a larger bus,
|
||||
// Spaces only occur when we have a signal that's a slice of a larger bus,
|
||||
// e.g. "\myreg [5:0]", so removing spaces shouldn't result in loss of uniqueness
|
||||
std::string sig_q_str = log_signal(ff.sig_q);
|
||||
sig_q_str.erase(std::remove(sig_q_str.begin(), sig_q_str.end(), ' '), sig_q_str.end());
|
||||
|
||||
Wire *past_q = module->addWire(NEW_ID_SUFFIX(stringf("%s#past_q_wire", sig_q_str.c_str())), ff.width);
|
||||
|
||||
if (!ff.is_fine) {
|
||||
module->addFf(NEW_ID, ff.sig_q, past_q);
|
||||
} else {
|
||||
|
@ -172,7 +190,7 @@ struct Clk2fflogicPass : public Pass {
|
|||
initvals.set_init(past_q, ff.val_init);
|
||||
|
||||
if (ff.has_clk) {
|
||||
ff.unmap_ce_srst(module);
|
||||
ff.unmap_ce_srst();
|
||||
|
||||
Wire *past_clk = module->addWire(NEW_ID_SUFFIX(stringf("%s#past_clk#%s", sig_q_str.c_str(), log_signal(ff.sig_clk))));
|
||||
initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0);
|
||||
|
@ -182,10 +200,6 @@ struct Clk2fflogicPass : public Pass {
|
|||
else
|
||||
module->addFfGate(NEW_ID, ff.sig_clk, past_clk);
|
||||
|
||||
log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q));
|
||||
|
||||
SigSpec clock_edge_pattern;
|
||||
|
||||
if (ff.pol_clk) {
|
||||
|
@ -211,25 +225,17 @@ struct Clk2fflogicPass : public Pass {
|
|||
qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
|
||||
else
|
||||
qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
|
||||
} else if (ff.has_d) {
|
||||
} else {
|
||||
qval = past_q;
|
||||
}
|
||||
|
||||
log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
|
||||
|
||||
SigSpec sig_en = wrap_async_control(module, ff.sig_en, ff.pol_en);
|
||||
if (ff.has_aload) {
|
||||
SigSpec sig_aload = wrap_async_control(module, ff.sig_aload, ff.pol_aload);
|
||||
|
||||
if (!ff.is_fine)
|
||||
qval = module->Mux(NEW_ID, past_q, ff.sig_d, sig_en);
|
||||
qval = module->Mux(NEW_ID, qval, ff.sig_ad, sig_aload);
|
||||
else
|
||||
qval = module->MuxGate(NEW_ID, past_q, ff.sig_d, sig_en);
|
||||
} else {
|
||||
|
||||
log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type),
|
||||
log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
|
||||
|
||||
qval = past_q;
|
||||
qval = module->MuxGate(NEW_ID, qval, ff.sig_ad, sig_aload);
|
||||
}
|
||||
|
||||
if (ff.has_sr) {
|
||||
|
@ -254,10 +260,6 @@ struct Clk2fflogicPass : public Pass {
|
|||
} else {
|
||||
module->connect(ff.sig_q, qval);
|
||||
}
|
||||
|
||||
initvals.remove_init(ff.sig_q);
|
||||
module->remove(cell);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
// [[CITE]] VlogHammer Verilog Regression Test Suite
|
||||
// http://www.clifford.at/yosys/vloghammer.html
|
||||
// https://yosyshq.net/yosys/vloghammer.html
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -21,12 +21,49 @@
|
|||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/mem.h"
|
||||
#include "kernel/fstdata.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
enum class SimulationMode {
|
||||
sim,
|
||||
cmp,
|
||||
gold,
|
||||
gate,
|
||||
};
|
||||
|
||||
static const std::map<std::string, int> g_units =
|
||||
{
|
||||
{ "", -9 }, // default is ns
|
||||
{ "s", 0 },
|
||||
{ "ms", -3 },
|
||||
{ "us", -6 },
|
||||
{ "ns", -9 },
|
||||
{ "ps", -12 },
|
||||
{ "fs", -15 },
|
||||
{ "as", -18 },
|
||||
{ "zs", -21 },
|
||||
};
|
||||
|
||||
static double stringToTime(std::string str)
|
||||
{
|
||||
if (str=="END") return -1;
|
||||
|
||||
char *endptr;
|
||||
long value = strtol(str.c_str(), &endptr, 10);
|
||||
|
||||
if (g_units.find(endptr)==g_units.end())
|
||||
log_error("Cannot parse '%s', bad unit '%s'\n", str.c_str(), endptr);
|
||||
|
||||
if (value < 0)
|
||||
log_error("Time value '%s' must be positive\n", str.c_str());
|
||||
|
||||
return value * pow(10.0, g_units.at(endptr));
|
||||
}
|
||||
|
||||
struct SimShared
|
||||
{
|
||||
bool debug = false;
|
||||
|
@ -34,6 +71,11 @@ struct SimShared
|
|||
bool writeback = false;
|
||||
bool zinit = false;
|
||||
int rstlen = 1;
|
||||
FstData *fst = nullptr;
|
||||
double start_time = 0;
|
||||
double stop_time = -1;
|
||||
SimulationMode sim_mode = SimulationMode::sim;
|
||||
bool cycles_set = false;
|
||||
};
|
||||
|
||||
void zinit(State &v)
|
||||
|
@ -51,7 +93,8 @@ void zinit(Const &v)
|
|||
struct SimInstance
|
||||
{
|
||||
SimShared *shared;
|
||||
|
||||
|
||||
std::string scope;
|
||||
Module *module;
|
||||
Cell *instance;
|
||||
|
||||
|
@ -92,9 +135,11 @@ struct SimInstance
|
|||
std::vector<Mem> memories;
|
||||
|
||||
dict<Wire*, pair<int, Const>> vcd_database;
|
||||
dict<Wire*, pair<fstHandle, Const>> fst_database;
|
||||
dict<Wire*, fstHandle> fst_handles;
|
||||
|
||||
SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
|
||||
shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
|
||||
SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
|
||||
shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module)
|
||||
{
|
||||
log_assert(module);
|
||||
|
||||
|
@ -116,6 +161,13 @@ struct SimInstance
|
|||
}
|
||||
}
|
||||
|
||||
if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {
|
||||
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
|
||||
if (id==0 && wire->name.isPublic())
|
||||
log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str());
|
||||
fst_handles[wire] = id;
|
||||
}
|
||||
|
||||
if (wire->attributes.count(ID::init)) {
|
||||
Const initval = wire->attributes.at(ID::init);
|
||||
for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
|
||||
|
@ -144,7 +196,7 @@ struct SimInstance
|
|||
Module *mod = module->design->module(cell->type);
|
||||
|
||||
if (mod != nullptr) {
|
||||
dirty_children.insert(new SimInstance(shared, mod, cell, this));
|
||||
dirty_children.insert(new SimInstance(shared, scope + "." + RTLIL::unescape_id(cell->name), mod, cell, this));
|
||||
}
|
||||
|
||||
for (auto &port : cell->connections()) {
|
||||
|
@ -164,7 +216,7 @@ struct SimInstance
|
|||
ff_database[cell] = ff;
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($mem), ID($meminit), ID($memwr), ID($memrd)))
|
||||
if (cell->is_mem_cell())
|
||||
{
|
||||
mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string();
|
||||
}
|
||||
|
@ -271,7 +323,7 @@ struct SimInstance
|
|||
{
|
||||
auto child = children.at(cell);
|
||||
for (auto &conn: cell->connections())
|
||||
if (cell->input(conn.first)) {
|
||||
if (cell->input(conn.first) && GetSize(conn.second)) {
|
||||
Const value = get_state(conn.second);
|
||||
child->set_state(child->module->wire(conn.first), value);
|
||||
}
|
||||
|
@ -313,6 +365,12 @@ struct SimInstance
|
|||
return;
|
||||
}
|
||||
|
||||
// (A,S -> Y) cells
|
||||
if (has_a && !has_b && !has_c && !has_d && has_s && has_y) {
|
||||
set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_s)));
|
||||
return;
|
||||
}
|
||||
|
||||
// (A,B,S -> Y) cells
|
||||
if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
|
||||
set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
|
||||
|
@ -334,7 +392,7 @@ struct SimInstance
|
|||
{
|
||||
auto &port = mem.rd_ports[port_idx];
|
||||
Const addr = get_state(port.addr);
|
||||
Const data = Const(State::Sx, mem.width);
|
||||
Const data = Const(State::Sx, mem.width << port.wide_log2);
|
||||
|
||||
if (port.clk_enable)
|
||||
log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid));
|
||||
|
@ -342,7 +400,7 @@ struct SimInstance
|
|||
if (addr.is_fully_def()) {
|
||||
int index = addr.as_int() - mem.start_offset;
|
||||
if (index >= 0 && index < mem.size)
|
||||
data = mdb.data.extract(index*mem.width, mem.width);
|
||||
data = mdb.data.extract(index*mem.width, mem.width << port.wide_log2);
|
||||
}
|
||||
|
||||
set_state(port.data, data);
|
||||
|
@ -457,7 +515,7 @@ struct SimInstance
|
|||
{
|
||||
int index = addr.as_int() - mem.start_offset;
|
||||
if (index >= 0 && index < mem.size)
|
||||
for (int i = 0; i < mem.width; i++)
|
||||
for (int i = 0; i < (mem.width << port.wide_log2); i++)
|
||||
if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) {
|
||||
mdb.data.bits.at(index*mem.width+i) = data[i];
|
||||
dirty_memories.insert(mem.memid);
|
||||
|
@ -559,6 +617,7 @@ struct SimInstance
|
|||
MemInit minit;
|
||||
minit.addr = mem.mem->start_offset;
|
||||
minit.data = mem.data;
|
||||
minit.en = Const(State::S1, mem.mem->width);
|
||||
mem.mem->inits.push_back(minit);
|
||||
mem.mem->emit();
|
||||
}
|
||||
|
@ -615,14 +674,125 @@ struct SimInstance
|
|||
for (auto child : children)
|
||||
child.second->write_vcd_step(f);
|
||||
}
|
||||
|
||||
void write_fst_header(struct fstContext *f)
|
||||
{
|
||||
fstWriterSetScope(f, FST_ST_VCD_MODULE, stringf("%s",log_id(name())).c_str(), nullptr);
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (shared->hide_internal && wire->name[0] == '$')
|
||||
continue;
|
||||
|
||||
fstHandle id = fstWriterCreateVar(f, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
|
||||
stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
|
||||
fst_database[wire] = make_pair(id, Const());
|
||||
}
|
||||
|
||||
for (auto child : children)
|
||||
child.second->write_fst_header(f);
|
||||
|
||||
fstWriterSetUpscope(f);
|
||||
}
|
||||
|
||||
void write_fst_step(struct fstContext *f)
|
||||
{
|
||||
for (auto &it : fst_database)
|
||||
{
|
||||
Wire *wire = it.first;
|
||||
Const value = get_state(wire);
|
||||
fstHandle id = it.second.first;
|
||||
|
||||
if (it.second.second == value)
|
||||
continue;
|
||||
|
||||
it.second.second = value;
|
||||
std::stringstream ss;
|
||||
for (int i = GetSize(value)-1; i >= 0; i--) {
|
||||
switch (value[i]) {
|
||||
case State::S0: ss << "0"; break;
|
||||
case State::S1: ss << "1"; break;
|
||||
case State::Sx: ss << "x"; break;
|
||||
default: ss << "z";
|
||||
}
|
||||
}
|
||||
fstWriterEmitValueChange(f, id, ss.str().c_str());
|
||||
}
|
||||
|
||||
for (auto child : children)
|
||||
child.second->write_fst_step(f);
|
||||
}
|
||||
|
||||
void setInitState(uint64_t time)
|
||||
{
|
||||
for (auto &it : ff_database)
|
||||
{
|
||||
Cell *cell = it.first;
|
||||
|
||||
SigSpec qsig = cell->getPort(ID::Q);
|
||||
if (qsig.is_wire()) {
|
||||
IdString name = qsig.as_wire()->name;
|
||||
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(name));
|
||||
if (id==0 && name.isPublic())
|
||||
log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str());
|
||||
if (id!=0) {
|
||||
Const fst_val = Const::from_string(shared->fst->valueAt(id, time));
|
||||
set_state(qsig, fst_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto child : children)
|
||||
child.second->setInitState(time);
|
||||
}
|
||||
|
||||
bool checkSignals(uint64_t time)
|
||||
{
|
||||
bool retVal = false;
|
||||
for(auto &item : fst_handles) {
|
||||
if (item.second==0) continue; // Ignore signals not found
|
||||
Const fst_val = Const::from_string(shared->fst->valueAt(item.second, time));
|
||||
Const sim_val = get_state(item.first);
|
||||
if (sim_val.size()!=fst_val.size())
|
||||
log_error("Signal '%s' size is different in gold and gate.\n", log_id(item.first));
|
||||
if (shared->sim_mode == SimulationMode::sim) {
|
||||
// No checks performed when using stimulus
|
||||
} else if (shared->sim_mode == SimulationMode::gate && !fst_val.is_fully_def()) { // FST data contains X
|
||||
for(int i=0;i<fst_val.size();i++) {
|
||||
if (fst_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
|
||||
log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (shared->sim_mode == SimulationMode::gold && !sim_val.is_fully_def()) { // sim data contains X
|
||||
for(int i=0;i<sim_val.size();i++) {
|
||||
if (sim_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
|
||||
log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fst_val!=sim_val) {
|
||||
log_warning("Signal '%s' in file %s in simulation '%s'\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto child : children)
|
||||
retVal |= child.second->checkSignals(time);
|
||||
return retVal;
|
||||
}
|
||||
};
|
||||
|
||||
struct SimWorker : SimShared
|
||||
{
|
||||
SimInstance *top = nullptr;
|
||||
std::ofstream vcdfile;
|
||||
struct fstContext *fstfile = nullptr;
|
||||
pool<IdString> clock, clockn, reset, resetn;
|
||||
std::string timescale;
|
||||
std::string sim_filename;
|
||||
std::string scope;
|
||||
|
||||
~SimWorker()
|
||||
{
|
||||
|
@ -631,9 +801,6 @@ struct SimWorker : SimShared
|
|||
|
||||
void write_vcd_header()
|
||||
{
|
||||
if (!vcdfile.is_open())
|
||||
return;
|
||||
|
||||
vcdfile << stringf("$version %s $end\n", yosys_version_str);
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
|
@ -653,13 +820,53 @@ struct SimWorker : SimShared
|
|||
|
||||
void write_vcd_step(int t)
|
||||
{
|
||||
if (!vcdfile.is_open())
|
||||
return;
|
||||
|
||||
vcdfile << stringf("#%d\n", t);
|
||||
top->write_vcd_step(vcdfile);
|
||||
}
|
||||
|
||||
void write_fst_header()
|
||||
{
|
||||
std::time_t t = std::time(nullptr);
|
||||
fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
|
||||
fstWriterSetVersion(fstfile, yosys_version_str);
|
||||
if (!timescale.empty())
|
||||
fstWriterSetTimescaleFromString(fstfile, timescale.c_str());
|
||||
|
||||
fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
|
||||
fstWriterSetRepackOnClose(fstfile, 1);
|
||||
|
||||
top->write_fst_header(fstfile);
|
||||
}
|
||||
|
||||
void write_fst_step(int t)
|
||||
{
|
||||
fstWriterEmitTimeChange(fstfile, t);
|
||||
|
||||
top->write_fst_step(fstfile);
|
||||
}
|
||||
|
||||
void write_output_header()
|
||||
{
|
||||
if (vcdfile.is_open())
|
||||
write_vcd_header();
|
||||
if (fstfile)
|
||||
write_fst_header();
|
||||
}
|
||||
|
||||
void write_output_step(int t)
|
||||
{
|
||||
if (vcdfile.is_open())
|
||||
write_vcd_step(t);
|
||||
if (fstfile)
|
||||
write_fst_step(t);
|
||||
}
|
||||
|
||||
void write_output_end()
|
||||
{
|
||||
if (fstfile)
|
||||
fstWriterClose(fstfile);
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
while (1)
|
||||
|
@ -698,7 +905,7 @@ struct SimWorker : SimShared
|
|||
void run(Module *topmod, int numcycles)
|
||||
{
|
||||
log_assert(top == nullptr);
|
||||
top = new SimInstance(this, topmod);
|
||||
top = new SimInstance(this, scope, topmod);
|
||||
|
||||
if (debug)
|
||||
log("\n===== 0 =====\n");
|
||||
|
@ -713,24 +920,25 @@ struct SimWorker : SimShared
|
|||
|
||||
update();
|
||||
|
||||
write_vcd_header();
|
||||
write_vcd_step(0);
|
||||
write_output_header();
|
||||
write_output_step(0);
|
||||
|
||||
for (int cycle = 0; cycle < numcycles; cycle++)
|
||||
{
|
||||
if (debug)
|
||||
log("\n===== %d =====\n", 10*cycle + 5);
|
||||
|
||||
else
|
||||
log("Simulating cycle %d.\n", (cycle*2)+1);
|
||||
set_inports(clock, State::S0);
|
||||
set_inports(clockn, State::S1);
|
||||
|
||||
update();
|
||||
write_vcd_step(10*cycle + 5);
|
||||
write_output_step(10*cycle + 5);
|
||||
|
||||
if (debug)
|
||||
log("\n===== %d =====\n", 10*cycle + 10);
|
||||
else
|
||||
log("Simulating cycle %d.\n", cycle+1);
|
||||
log("Simulating cycle %d.\n", (cycle*2)+2);
|
||||
|
||||
set_inports(clock, State::S1);
|
||||
set_inports(clockn, State::S0);
|
||||
|
@ -741,11 +949,132 @@ struct SimWorker : SimShared
|
|||
}
|
||||
|
||||
update();
|
||||
write_vcd_step(10*cycle + 10);
|
||||
write_output_step(10*cycle + 10);
|
||||
}
|
||||
|
||||
write_vcd_step(10*numcycles + 2);
|
||||
write_output_step(10*numcycles + 2);
|
||||
|
||||
write_output_end();
|
||||
|
||||
if (writeback) {
|
||||
pool<Module*> wbmods;
|
||||
top->writeback(wbmods);
|
||||
}
|
||||
}
|
||||
|
||||
void run_cosim(Module *topmod, int numcycles)
|
||||
{
|
||||
log_assert(top == nullptr);
|
||||
fst = new FstData(sim_filename);
|
||||
|
||||
if (scope.empty())
|
||||
log_error("Scope must be defined for co-simulation.\n");
|
||||
|
||||
top = new SimInstance(this, scope, topmod);
|
||||
|
||||
std::vector<fstHandle> fst_clock;
|
||||
|
||||
for (auto portname : clock)
|
||||
{
|
||||
Wire *w = topmod->wire(portname);
|
||||
if (!w)
|
||||
log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
|
||||
if (!w->port_input)
|
||||
log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
|
||||
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
|
||||
if (id==0)
|
||||
log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
|
||||
fst_clock.push_back(id);
|
||||
}
|
||||
for (auto portname : clockn)
|
||||
{
|
||||
Wire *w = topmod->wire(portname);
|
||||
if (!w)
|
||||
log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
|
||||
if (!w->port_input)
|
||||
log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
|
||||
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
|
||||
if (id==0)
|
||||
log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
|
||||
fst_clock.push_back(id);
|
||||
}
|
||||
if (fst_clock.size()==0)
|
||||
log_error("No clock signals defined for input file\n");
|
||||
|
||||
SigMap sigmap(topmod);
|
||||
std::map<Wire*,fstHandle> inputs;
|
||||
|
||||
for (auto wire : topmod->wires()) {
|
||||
if (wire->port_input) {
|
||||
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
|
||||
if (id==0)
|
||||
log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
|
||||
inputs[wire] = id;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t startCount = 0;
|
||||
uint64_t stopCount = 0;
|
||||
if (start_time==0) {
|
||||
if (start_time < fst->getStartTime())
|
||||
log_warning("Start time is before simulation file start time\n");
|
||||
startCount = fst->getStartTime();
|
||||
} else if (start_time==-1)
|
||||
startCount = fst->getEndTime();
|
||||
else {
|
||||
startCount = start_time / fst->getTimescale();
|
||||
if (startCount > fst->getEndTime()) {
|
||||
startCount = fst->getEndTime();
|
||||
log_warning("Start time is after simulation file end time\n");
|
||||
}
|
||||
}
|
||||
if (stop_time==0) {
|
||||
if (stop_time < fst->getStartTime())
|
||||
log_warning("Stop time is before simulation file start time\n");
|
||||
stopCount = fst->getStartTime();
|
||||
} else if (stop_time==-1)
|
||||
stopCount = fst->getEndTime();
|
||||
else {
|
||||
stopCount = stop_time / fst->getTimescale();
|
||||
if (stopCount > fst->getEndTime()) {
|
||||
stopCount = fst->getEndTime();
|
||||
log_warning("Stop time is after simulation file end time\n");
|
||||
}
|
||||
}
|
||||
if (stopCount<startCount) {
|
||||
log_error("Stop time is before start time\n");
|
||||
}
|
||||
auto samples = fst->getAllEdges(fst_clock, startCount, stopCount);
|
||||
|
||||
// Limit to number of cycles if provided
|
||||
if (cycles_set && ((size_t)(numcycles *2) < samples.size()))
|
||||
samples.erase(samples.begin() + (numcycles*2), samples.end());
|
||||
|
||||
// Add setup time (start time)
|
||||
if (samples.empty() || samples.front()!=startCount)
|
||||
samples.insert(samples.begin(), startCount);
|
||||
|
||||
fst->reconstructAllAtTimes(samples);
|
||||
bool initial = true;
|
||||
int cycle = 0;
|
||||
log("Co-simulation from %lu%s to %lu%s\n", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
|
||||
for(auto &time : samples) {
|
||||
log("Co-simulating cycle %d [%lu%s].\n", cycle, (unsigned long)time, fst->getTimescaleString());
|
||||
for(auto &item : inputs) {
|
||||
std::string v = fst->valueAt(item.second, time);
|
||||
top->set_state(item.first, Const::from_string(v));
|
||||
}
|
||||
if (initial) {
|
||||
top->setInitState(time);
|
||||
initial = false;
|
||||
}
|
||||
update();
|
||||
|
||||
bool status = top->checkSignals(time);
|
||||
if (status)
|
||||
log_error("Signal difference\n");
|
||||
cycle++;
|
||||
}
|
||||
if (writeback) {
|
||||
pool<Module*> wbmods;
|
||||
top->writeback(wbmods);
|
||||
|
@ -766,6 +1095,9 @@ struct SimPass : public Pass {
|
|||
log(" -vcd <filename>\n");
|
||||
log(" write the simulation results to the given VCD file\n");
|
||||
log("\n");
|
||||
log(" -fst <filename>\n");
|
||||
log(" write the simulation results to the given FST file\n");
|
||||
log("\n");
|
||||
log(" -clock <portname>\n");
|
||||
log(" name of top-level clock input\n");
|
||||
log("\n");
|
||||
|
@ -788,14 +1120,41 @@ struct SimPass : public Pass {
|
|||
log(" include the specified timescale declaration in the vcd\n");
|
||||
log("\n");
|
||||
log(" -n <integer>\n");
|
||||
log(" number of cycles to simulate (default: 20)\n");
|
||||
log(" number of clock cycles to simulate (default: 20)\n");
|
||||
log("\n");
|
||||
log(" -a\n");
|
||||
log(" include all nets in VCD output, not just those with public names\n");
|
||||
log(" use all nets in VCD/FST operations, not just those with public names\n");
|
||||
log("\n");
|
||||
log(" -w\n");
|
||||
log(" writeback mode: use final simulation state as new init state\n");
|
||||
log("\n");
|
||||
log(" -r\n");
|
||||
log(" read simulation results file (file formats supported: FST)\n");
|
||||
log("\n");
|
||||
log(" -scope\n");
|
||||
log(" scope of simulation top model\n");
|
||||
log("\n");
|
||||
log(" -at <time>\n");
|
||||
log(" sets start and stop time\n");
|
||||
log("\n");
|
||||
log(" -start <time>\n");
|
||||
log(" start co-simulation in arbitary time (default 0)\n");
|
||||
log("\n");
|
||||
log(" -stop <time>\n");
|
||||
log(" stop co-simulation in arbitary time (default END)\n");
|
||||
log("\n");
|
||||
log(" -sim\n");
|
||||
log(" simulation with stimulus from FST (default)\n");
|
||||
log("\n");
|
||||
log(" -sim-cmp\n");
|
||||
log(" co-simulation expect exact match\n");
|
||||
log("\n");
|
||||
log(" -sim-gold\n");
|
||||
log(" co-simulation, x in simulation can match any value in FST\n");
|
||||
log("\n");
|
||||
log(" -sim-gate\n");
|
||||
log(" co-simulation, x in FST can match any value in simulation\n");
|
||||
log("\n");
|
||||
log(" -d\n");
|
||||
log(" enable debug output\n");
|
||||
log("\n");
|
||||
|
@ -804,6 +1163,7 @@ struct SimPass : public Pass {
|
|||
{
|
||||
SimWorker worker;
|
||||
int numcycles = 20;
|
||||
bool start_set = false, stop_set = false, at_set = false;
|
||||
|
||||
log_header(design, "Executing SIM pass (simulate the circuit).\n");
|
||||
|
||||
|
@ -815,8 +1175,15 @@ struct SimPass : public Pass {
|
|||
worker.vcdfile.open(vcd_filename.c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-fst" && argidx+1 < args.size()) {
|
||||
std::string fst_filename = args[++argidx];
|
||||
rewrite_filename(fst_filename);
|
||||
worker.fstfile = (struct fstContext *)fstWriterCreate(fst_filename.c_str(),1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-n" && argidx+1 < args.size()) {
|
||||
numcycles = atoi(args[++argidx].c_str());
|
||||
worker.cycles_set = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
|
||||
|
@ -859,9 +1226,55 @@ struct SimPass : public Pass {
|
|||
worker.zinit = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-r" && argidx+1 < args.size()) {
|
||||
std::string sim_filename = args[++argidx];
|
||||
rewrite_filename(sim_filename);
|
||||
worker.sim_filename = sim_filename;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-scope" && argidx+1 < args.size()) {
|
||||
worker.scope = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-start" && argidx+1 < args.size()) {
|
||||
worker.start_time = stringToTime(args[++argidx]);
|
||||
start_set = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-stop" && argidx+1 < args.size()) {
|
||||
worker.stop_time = stringToTime(args[++argidx]);
|
||||
stop_set = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-at" && argidx+1 < args.size()) {
|
||||
worker.start_time = stringToTime(args[++argidx]);
|
||||
worker.stop_time = worker.start_time;
|
||||
at_set = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sim") {
|
||||
worker.sim_mode = SimulationMode::sim;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sim-cmp") {
|
||||
worker.sim_mode = SimulationMode::cmp;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sim-gold") {
|
||||
worker.sim_mode = SimulationMode::gold;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sim-gate") {
|
||||
worker.sim_mode = SimulationMode::gate;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
if (at_set && (start_set || stop_set || worker.cycles_set))
|
||||
log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
|
||||
if (stop_set && worker.cycles_set)
|
||||
log_error("'stop' and 'n' can only be used exclusively'\n");
|
||||
|
||||
Module *top_mod = nullptr;
|
||||
|
||||
|
@ -877,7 +1290,10 @@ struct SimPass : public Pass {
|
|||
top_mod = mods.front();
|
||||
}
|
||||
|
||||
worker.run(top_mod, numcycles);
|
||||
if (worker.sim_filename.empty())
|
||||
worker.run(top_mod, numcycles);
|
||||
else
|
||||
worker.run_cosim(top_mod, numcycles);
|
||||
}
|
||||
} SimPass;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue