aboutsummaryrefslogtreecommitdiffstats
path: root/passes/sat
diff options
context:
space:
mode:
authorMiodrag Milanovic <mmicko@gmail.com>2022-02-15 09:30:42 +0100
committerMiodrag Milanovic <mmicko@gmail.com>2022-02-16 13:27:59 +0100
commitfb22d7cdc411ec52672cb7f13364651c564872db (patch)
tree0b69b27f9806a39772b0980f7c8ab701234e754f /passes/sat
parent15860000487e2d6748843888b78289f95f3ea46b (diff)
downloadyosys-fb22d7cdc411ec52672cb7f13364651c564872db.tar.gz
yosys-fb22d7cdc411ec52672cb7f13364651c564872db.tar.bz2
yosys-fb22d7cdc411ec52672cb7f13364651c564872db.zip
Add support for various ff/latch cells simulation
Diffstat (limited to 'passes/sat')
-rw-r--r--passes/sat/sim.cc264
1 files changed, 204 insertions, 60 deletions
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
index a7c109374..47f48e67d 100644
--- a/passes/sat/sim.cc
+++ b/passes/sat/sim.cc
@@ -22,6 +22,7 @@
#include "kernel/celltypes.h"
#include "kernel/mem.h"
#include "kernel/fstdata.h"
+#include "kernel/ff.h"
#include <ctime>
@@ -76,6 +77,7 @@ struct SimShared
double stop_time = -1;
SimulationMode sim_mode = SimulationMode::sim;
bool cycles_set = false;
+ const pool<IdString> ff_types = RTLIL::builtin_ff_cell_types();
};
void zinit(State &v)
@@ -113,8 +115,13 @@ struct SimInstance
struct ff_state_t
{
- State past_clock;
Const past_d;
+ Const past_ad;
+ SigSpec past_clk;
+ SigSpec past_ce;
+ SigSpec past_srst;
+
+ FfData data;
};
struct mem_state_t
@@ -209,10 +216,15 @@ struct SimInstance
}
}
- if (cell->type.in(ID($dff))) {
+ if (shared->ff_types.count(cell->type)) {
+ FfData ff_data(nullptr, cell);
ff_state_t ff;
- ff.past_clock = State::Sx;
- ff.past_d = Const(State::Sx, cell->getParam(ID::WIDTH).as_int());
+ ff.past_d = Const(State::Sx, ff_data.width);
+ ff.past_ad = Const(State::Sx, ff_data.width);
+ ff.past_clk = State::Sx;
+ ff.past_ce = State::Sx;
+ ff.past_srst = State::Sx;
+ ff.data = ff_data;
ff_database[cell] = ff;
}
@@ -229,11 +241,10 @@ struct SimInstance
{
for (auto &it : ff_database)
{
- Cell *cell = it.first;
ff_state_t &ff = it.second;
zinit(ff.past_d);
- SigSpec qsig = cell->getPort(ID::Q);
+ SigSpec qsig = it.second.data.sig_q;
Const qdata = get_state(qsig);
zinit(qdata);
set_state(qsig, qdata);
@@ -466,20 +477,138 @@ struct SimInstance
for (auto &it : ff_database)
{
- Cell *cell = it.first;
ff_state_t &ff = it.second;
+ FfData ff_data = ff.data;
+
+ if (ff_data.has_clk) {
+ // flip-flops
+ State current_clk = get_state(ff_data.sig_clk)[0];
+
+ // handle set/reset
+ if (ff.data.has_sr) {
+ Const current_q = get_state(ff.data.sig_q);
+ Const current_clr = get_state(ff.data.sig_clr);
+ Const current_set = get_state(ff.data.sig_set);
+
+ for(int i=0;i<ff.past_d.size();i++) {
+
+ if (current_clr[i] == (ff_data.pol_clr ? State::S1 : State::S0)) {
+ current_q[i] = State::S0;
+ }
+ else if (current_set[i] == (ff_data.pol_set ? State::S1 : State::S0)) {
+ current_q[i] = State::S1;
+ } else {
+ // all below is in sync with clk
+ if (ff_data.pol_clk ? (ff.past_clk == State::S1 || current_clk != State::S1) :
+ (ff.past_clk == State::S0 || current_clk != State::S0))
+ continue;
+
+ if (ff_data.has_ce) {
+ if (ff.past_ce == (ff_data.pol_ce ? State::S1 : State::S0))
+ current_q[i] = ff.past_d[i];
+ } else {
+ current_q[i] = ff.past_d[i];
+ }
+ }
+ }
+ if (set_state(ff_data.sig_q, current_q))
+ did_something = true;
+ } else {
+ // async reset
+ if (ff_data.has_arst) {
+ State current_arst = get_state(ff_data.sig_arst)[0];
+ if (current_arst == (ff_data.pol_arst ? State::S1 : State::S0)) {
+ if (set_state(ff_data.sig_q, ff_data.val_arst))
+ did_something = true;
+ continue;
+ }
+ }
+ // async load
+ if (ff_data.has_aload) {
+ State current_aload = get_state(ff_data.sig_aload)[0];
+ if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) {
+ if (set_state(ff_data.sig_q, ff.past_ad))
+ did_something = true;
+ continue;
+ }
+ }
- if (cell->type.in(ID($dff)))
- {
- bool clkpol = cell->getParam(ID::CLK_POLARITY).as_bool();
- State current_clock = get_state(cell->getPort(ID::CLK))[0];
+ // all below is in sync with clk
+ if (ff_data.pol_clk ? (ff.past_clk == State::S1 || current_clk != State::S1) :
+ (ff.past_clk == State::S0 || current_clk != State::S0))
+ continue;
+
+ // chip enable priority over reset
+ if (ff_data.ce_over_srst && ff_data.has_ce) {
+ if (ff.past_ce != (ff_data.pol_ce ? State::S1 : State::S0))
+ continue;
+ }
- if (clkpol ? (ff.past_clock == State::S1 || current_clock != State::S1) :
- (ff.past_clock == State::S0 || current_clock != State::S0))
- continue;
+ // handle sync reset
+ if (ff_data.has_srst) {
+ if (ff.past_srst == (ff_data.pol_srst ? State::S1 : State::S0)) {
+ if (set_state(ff_data.sig_q, ff_data.val_srst))
+ did_something = true;
+ continue;
+ }
+ }
+
+ // reset had priority over chip enable
+ if (!ff_data.ce_over_srst && ff_data.has_ce) {
+ if (ff.past_ce != (ff_data.pol_ce ? State::S1 : State::S0))
+ continue;
+ }
+ if (set_state(ff_data.sig_q, ff.past_d))
+ did_something = true;
+ }
+ } else {
+ // handle set/reset
+ if (ff.data.has_sr) {
+ Const current_q = get_state(ff.data.sig_q);
+ Const current_clr = get_state(ff.data.sig_clr);
+ Const current_set = get_state(ff.data.sig_set);
+
+ for(int i=0;i<current_q.size();i++) {
+ if (current_clr[i] == (ff_data.pol_clr ? State::S1 : State::S0)) {
+ current_q[i] = State::S0;
+ }
+ else if (current_set[i] == (ff_data.pol_set ? State::S1 : State::S0)) {
+ current_q[i] = State::S1;
+ } else {
+ if (ff_data.has_aload) {
+ Const current_ad = get_state(ff.data.sig_ad);
+ State current_aload = get_state(ff_data.sig_aload)[0];
+ if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) {
+ current_q[i] = current_ad[i];
+ }
+ }
+ }
+ }
+ if (set_state(ff_data.sig_q, current_q))
+ did_something = true;
+ }
+ // async load is true for all latches
+ else if (ff_data.has_aload) {
+ // async reset
+ if (ff_data.has_arst) {
+ State current_arst = get_state(ff_data.sig_arst)[0];
+ if (current_arst == (ff_data.pol_arst ? State::S1 : State::S0)) {
+ if (set_state(ff_data.sig_q, ff_data.val_arst))
+ did_something = true;
+ continue;
+ }
+ }
- if (set_state(cell->getPort(ID::Q), ff.past_d))
- did_something = true;
+ State current_aload = get_state(ff_data.sig_aload)[0];
+ if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) {
+ if (set_state(ff_data.sig_q, get_state(ff.data.sig_ad)))
+ did_something = true;
+ }
+ } else if (ff_data.has_gclk) {
+ // $ff
+ if (set_state(ff_data.sig_q, ff.past_d))
+ did_something = true;
+ }
}
}
@@ -538,13 +667,22 @@ struct SimInstance
{
for (auto &it : ff_database)
{
- Cell *cell = it.first;
ff_state_t &ff = it.second;
- if (cell->type.in(ID($dff))) {
- ff.past_clock = get_state(cell->getPort(ID::CLK))[0];
- ff.past_d = get_state(cell->getPort(ID::D));
- }
+ if (ff.data.has_aload)
+ ff.past_ad = get_state(ff.data.sig_ad);
+
+ if (ff.data.has_clk || ff.data.has_gclk)
+ ff.past_d = get_state(ff.data.sig_d);
+
+ if (ff.data.has_clk)
+ ff.past_clk = get_state(ff.data.sig_clk)[0];
+
+ if (ff.data.has_ce)
+ ff.past_ce = get_state(ff.data.sig_ce)[0];
+
+ if (ff.data.has_srst)
+ ff.past_srst = get_state(ff.data.sig_srst)[0];
}
for (auto &it : mem_database)
@@ -595,8 +733,7 @@ struct SimInstance
for (auto &it : ff_database)
{
- Cell *cell = it.first;
- SigSpec sig_q = cell->getPort(ID::Q);
+ SigSpec sig_q = it.second.data.sig_q;
Const initval = get_state(sig_q);
for (int i = 0; i < GetSize(sig_q); i++)
@@ -722,34 +859,32 @@ struct SimInstance
child.second->write_fst_step(f);
}
- void setInitState(uint64_t time)
+ void setInitState()
{
for (auto &it : ff_database)
{
- Cell *cell = it.first;
-
- SigSpec qsig = cell->getPort(ID::Q);
+ SigSpec qsig = it.second.data.sig_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));
+ Const fst_val = Const::from_string(shared->fst->valueOf(id));
set_state(qsig, fst_val);
}
}
}
for (auto child : children)
- child.second->setInitState(time);
+ child.second->setInitState();
}
- bool checkSignals(uint64_t time)
+ bool checkSignals()
{
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 fst_val = Const::from_string(shared->fst->valueOf(item.second));
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));
@@ -779,7 +914,7 @@ struct SimInstance
}
}
for (auto child : children)
- retVal |= child.second->checkSignals(time);
+ retVal |= child.second->checkSignals();
return retVal;
}
};
@@ -998,8 +1133,6 @@ struct SimWorker : SimShared
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;
@@ -1044,37 +1177,48 @@ struct SimWorker : SimShared
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();
+ log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
+ if (cycles_set)
+ log(" for %d clock cycle(s)",numcycles);
+ log("\n");
+ bool all_samples = fst_clock.empty();
+
+ try {
+ fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
+ log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
+ for(auto &item : inputs) {
+ std::string v = fst->valueOf(item.second);
+ top->set_state(item.first, Const::from_string(v));
+ }
- bool status = top->checkSignals(time);
- if (status)
- log_error("Signal difference\n");
- cycle++;
+ if (initial) {
+ top->setInitState();
+ write_output_header();
+ initial = false;
+ }
+ update();
+ write_output_step(5*cycle);
+
+ bool status = top->checkSignals();
+ if (status)
+ log_error("Signal difference\n");
+ cycle++;
+
+ // Limit to number of cycles if provided
+ if (cycles_set && cycle > numcycles *2)
+ throw fst_end_of_data_exception();
+ if (time==stopCount)
+ throw fst_end_of_data_exception();
+ });
+ } catch(fst_end_of_data_exception) {
+ // end of data detected
}
+ write_output_step(5*(cycle-1)+2);
+ write_output_end();
+
if (writeback) {
pool<Module*> wbmods;
top->writeback(wbmods);