Write simulation files after simulation is performed

This commit is contained in:
Miodrag Milanovic 2022-03-02 15:23:07 +01:00
parent 2ca69e1b88
commit 48b56a4f7f
1 changed files with 152 additions and 146 deletions

View File

@ -70,12 +70,7 @@ struct OutputWriter
{ {
OutputWriter(SimWorker *w) { worker = w;}; OutputWriter(SimWorker *w) { worker = w;};
virtual ~OutputWriter() {}; virtual ~OutputWriter() {};
virtual void write_header() = 0; virtual void write() = 0;
virtual void write_step_header(int t) = 0;
virtual void enter_scope(IdString) {};
virtual void exit_scope() {};
virtual void register_signal(Wire *, int) {};
virtual void write_value(int, Const&) {};
SimWorker *worker; SimWorker *worker;
}; };
@ -92,6 +87,7 @@ struct SimShared
SimulationMode sim_mode = SimulationMode::sim; SimulationMode sim_mode = SimulationMode::sim;
bool cycles_set = false; bool cycles_set = false;
std::vector<std::unique_ptr<OutputWriter>> outputfiles; std::vector<std::unique_ptr<OutputWriter>> outputfiles;
std::vector<std::pair<int,std::map<int,Const>>> output_data;
}; };
void zinit(State &v) void zinit(State &v)
@ -699,27 +695,37 @@ struct SimInstance
it.second->writeback(wbmods); it.second->writeback(wbmods);
} }
void write_output_header(OutputWriter *writer, int &id) void register_signals(int &id)
{ {
writer->enter_scope(name());
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (shared->hide_internal && wire->name[0] == '$') if (shared->hide_internal && wire->name[0] == '$')
continue; continue;
signal_database[wire] = make_pair(id, Const()); signal_database[wire] = make_pair(id, Const());
writer->register_signal(wire, id);
id++; id++;
} }
for (auto child : children) for (auto child : children)
child.second->write_output_header(writer, id); child.second->register_signals(id);
writer->exit_scope();
} }
void write_output_step_values() void write_output_header(std::function<void(IdString)> enter_scope, std::function<void()> exit_scope, std::function<void(Wire*, int)> register_signal)
{
enter_scope(name());
for (auto signal : signal_database)
{
register_signal(signal.first, signal.second.first);
}
for (auto child : children)
child.second->write_output_header(enter_scope, exit_scope, register_signal);
exit_scope();
}
void register_output_step_values(std::map<int,Const> *data)
{ {
for (auto &it : signal_database) for (auto &it : signal_database)
{ {
@ -731,13 +737,11 @@ struct SimInstance
continue; continue;
it.second.second = value; it.second.second = value;
data->emplace(id, value);
for(auto& writer : shared->outputfiles)
writer->write_value(id, value);
} }
for (auto child : children) for (auto child : children)
child.second->write_output_step_values(); child.second->register_output_step_values(data);
} }
void setInitState() void setInitState()
@ -828,20 +832,24 @@ struct SimWorker : SimShared
delete top; delete top;
} }
void write_output_header() void register_signals()
{ {
for(auto& writer : outputfiles) int id = 1;
writer->write_header(); top->register_signals(id);
} }
void write_output_step(int t) void register_output_step(int t)
{ {
for(auto& writer : outputfiles) std::map<int,Const> data;
writer->write_step_header(t); top->register_output_step_values(&data);
output_data.emplace_back(t, data);
top->write_output_step_values();
} }
void write_output_files()
{
for(auto& writer : outputfiles)
writer->write();
}
void update() void update()
{ {
@ -882,6 +890,7 @@ struct SimWorker : SimShared
{ {
log_assert(top == nullptr); log_assert(top == nullptr);
top = new SimInstance(this, scope, topmod); top = new SimInstance(this, scope, topmod);
register_signals();
if (debug) if (debug)
log("\n===== 0 =====\n"); log("\n===== 0 =====\n");
@ -896,8 +905,7 @@ struct SimWorker : SimShared
update(); update();
write_output_header(); register_output_step(0);
write_output_step(0);
for (int cycle = 0; cycle < numcycles; cycle++) for (int cycle = 0; cycle < numcycles; cycle++)
{ {
@ -909,7 +917,7 @@ struct SimWorker : SimShared
set_inports(clockn, State::S1); set_inports(clockn, State::S1);
update(); update();
write_output_step(10*cycle + 5); register_output_step(10*cycle + 5);
if (debug) if (debug)
log("\n===== %d =====\n", 10*cycle + 10); log("\n===== %d =====\n", 10*cycle + 10);
@ -925,10 +933,12 @@ struct SimWorker : SimShared
} }
update(); update();
write_output_step(10*cycle + 10); register_output_step(10*cycle + 10);
} }
write_output_step(10*numcycles + 2); register_output_step(10*numcycles + 2);
write_output_files();
if (writeback) { if (writeback) {
pool<Module*> wbmods; pool<Module*> wbmods;
@ -945,6 +955,7 @@ struct SimWorker : SimShared
log_error("Scope must be defined for co-simulation.\n"); log_error("Scope must be defined for co-simulation.\n");
top = new SimInstance(this, scope, topmod); top = new SimInstance(this, scope, topmod);
register_signals();
std::vector<fstHandle> fst_clock; std::vector<fstHandle> fst_clock;
@ -1036,12 +1047,11 @@ struct SimWorker : SimShared
if (initial) { if (initial) {
top->setInitState(); top->setInitState();
write_output_header();
initial = false; initial = false;
} }
if (did_something) if (did_something)
update(); update();
write_output_step(time); register_output_step(time);
bool status = top->checkSignals(); bool status = top->checkSignals();
if (status) if (status)
@ -1058,6 +1068,8 @@ struct SimWorker : SimShared
// end of data detected // end of data detected
} }
write_output_files();
if (writeback) { if (writeback) {
pool<Module*> wbmods; pool<Module*> wbmods;
top->writeback(wbmods); top->writeback(wbmods);
@ -1098,6 +1110,8 @@ struct SimWorker : SimShared
std::string status; std::string status;
int cycle = 0; int cycle = 0;
top = new SimInstance(this, scope, topmod); top = new SimInstance(this, scope, topmod);
register_signals();
while (!f.eof()) while (!f.eof())
{ {
std::string line; std::string line;
@ -1109,7 +1123,6 @@ struct SimWorker : SimShared
state = 2; state = 2;
} }
if (state==1 && line[0]!='b' && line[0]!='c') { if (state==1 && line[0]!='b' && line[0]!='c') {
write_output_header();
// was old format but with 1 bit latch // was old format but with 1 bit latch
top->setState(latches, status); top->setState(latches, status);
state = 3; state = 3;
@ -1125,7 +1138,6 @@ struct SimWorker : SimShared
state = 2; state = 2;
break; break;
case 2: case 2:
write_output_header();
top->setState(latches, line); top->setState(latches, line);
state = 3; state = 3;
break; break;
@ -1141,18 +1153,19 @@ struct SimWorker : SimShared
set_inports(clockn, State::S1); set_inports(clockn, State::S1);
} }
update(); update();
write_output_step(10*cycle); register_output_step(10*cycle);
if (cycle) { if (cycle) {
set_inports(clock, State::S0); set_inports(clock, State::S0);
set_inports(clockn, State::S1); set_inports(clockn, State::S1);
update(); update();
write_output_step(10*cycle + 5); register_output_step(10*cycle + 5);
} }
cycle++; cycle++;
break; break;
} }
} }
write_output_step(10*cycle); register_output_step(10*cycle);
write_output_files();
} }
}; };
@ -1162,7 +1175,7 @@ struct VCDWriter : public OutputWriter
vcdfile.open(filename.c_str()); vcdfile.open(filename.c_str());
} }
void write_header() override void write() override
{ {
if (!vcdfile.is_open()) return; if (!vcdfile.is_open()) return;
vcdfile << stringf("$version %s $end\n", yosys_version_str); vcdfile << stringf("$version %s $end\n", yosys_version_str);
@ -1176,46 +1189,33 @@ struct VCDWriter : public OutputWriter
if (!worker->timescale.empty()) if (!worker->timescale.empty())
vcdfile << stringf("$timescale %s $end\n", worker->timescale.c_str()); vcdfile << stringf("$timescale %s $end\n", worker->timescale.c_str());
int id = 1; worker->top->write_output_header(
worker->top->write_output_header(this, id); [this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); },
[this]() { vcdfile << stringf("$upscope $end\n");},
[this](Wire *wire, int id) { vcdfile << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); }
);
vcdfile << stringf("$enddefinitions $end\n"); vcdfile << stringf("$enddefinitions $end\n");
}
void write_step_header(int t) override for(auto& d : worker->output_data)
{ {
if (!vcdfile.is_open()) return; vcdfile << stringf("#%d\n", d.first);
vcdfile << stringf("#%d\n", t); for (auto &data : d.second)
} {
void enter_scope(IdString name) override
{
vcdfile << stringf("$scope module %s $end\n", log_id(name));
}
void exit_scope() override Const value = data.second;
{ vcdfile << "b";
vcdfile << stringf("$upscope $end\n"); for (int i = GetSize(value)-1; i >= 0; i--) {
} switch (value[i]) {
case State::S0: vcdfile << "0"; break;
void register_signal(Wire *wire, int id) override case State::S1: vcdfile << "1"; break;
{ case State::Sx: vcdfile << "x"; break;
vcdfile << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); default: vcdfile << "z";
} }
}
void write_value(int id, Const& value) override vcdfile << stringf(" n%d\n", data.first);
{
if (!vcdfile.is_open()) return;
vcdfile << "b";
for (int i = GetSize(value)-1; i >= 0; i--) {
switch (value[i]) {
case State::S0: vcdfile << "0"; break;
case State::S1: vcdfile << "1"; break;
case State::Sx: vcdfile << "x"; break;
default: vcdfile << "z";
} }
} }
vcdfile << stringf(" n%d\n", id);
} }
std::ofstream vcdfile; std::ofstream vcdfile;
@ -1232,7 +1232,7 @@ struct FSTWriter : public OutputWriter
fstWriterClose(fstfile); fstWriterClose(fstfile);
} }
void write_header() override void write() override
{ {
if (!fstfile) return; if (!fstfile) return;
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
@ -1244,47 +1244,35 @@ struct FSTWriter : public OutputWriter
fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ); fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
fstWriterSetRepackOnClose(fstfile, 1); fstWriterSetRepackOnClose(fstfile, 1);
int id = 1; worker->top->write_output_header(
worker->top->write_output_header(this, id); [this](IdString name) { fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr); },
} [this]() { fstWriterSetUpscope(fstfile); },
[this](Wire *wire, int id) {
void write_step_header(int t) override fstHandle fst_id = fstWriterCreateVar(fstfile, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
{
if (!fstfile) return;
fstWriterEmitTimeChange(fstfile, t);
}
void enter_scope(IdString name) override
{
fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr);
}
void exit_scope() override
{
fstWriterSetUpscope(fstfile);
}
void register_signal(Wire *wire, int id) override
{
fstHandle fst_id = fstWriterCreateVar(fstfile, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0); stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
mapping.emplace(id, fst_id); mapping.emplace(id, fst_id);
} }
);
void write_value(int id, Const& value) override for(auto& d : worker->output_data)
{ {
if (!fstfile) return; fstWriterEmitTimeChange(fstfile, d.first);
std::stringstream ss; for (auto &data : d.second)
for (int i = GetSize(value)-1; i >= 0; i--) { {
switch (value[i]) { Const value = data.second;
case State::S0: ss << "0"; break; std::stringstream ss;
case State::S1: ss << "1"; break; for (int i = GetSize(value)-1; i >= 0; i--) {
case State::Sx: ss << "x"; break; switch (value[i]) {
default: ss << "z"; case State::S0: ss << "0"; break;
case State::S1: ss << "1"; break;
case State::Sx: ss << "x"; break;
default: ss << "z";
}
}
fstWriterEmitValueChange(fstfile, mapping[data.first], ss.str().c_str());
} }
} }
fstWriterEmitValueChange(fstfile, mapping[id], ss.str().c_str());
} }
struct fstContext *fstfile = nullptr; struct fstContext *fstfile = nullptr;
@ -1302,7 +1290,7 @@ struct AIWWriter : public OutputWriter
aiwfile << '.' << '\n'; aiwfile << '.' << '\n';
} }
void write_header() override void write() override
{ {
if (!aiwfile.is_open()) return; if (!aiwfile.is_open()) return;
std::ifstream mf(worker->map_filename); std::ifstream mf(worker->map_filename);
@ -1326,50 +1314,68 @@ struct AIWWriter : public OutputWriter
} }
} }
for (int i = 0;; i++) worker->top->write_output_header(
{ [](IdString) {},
if (aiw_latches.count(i)) { []() {},
auto v = worker->top->get_state(aiw_latches.at(i).first); [this](Wire *wire, int id) { mapping[wire] = id; }
if (v == State::S1) );
aiwfile << (aiw_latches.at(i).second ? '0' : '1');
else
aiwfile << (aiw_latches.at(i).second ? '1' : '0');
continue;
}
aiwfile << '\n';
break;
}
}
void write_step_header(int) override std::map<int, Yosys::RTLIL::Const> current;
{ bool first = true;
if (!aiwfile.is_open()) return; for(auto& d : worker->output_data)
for (int i = 0;; i++)
{ {
if (aiw_inputs.count(i)) { for (auto &data : d.second)
auto v = worker->top->get_state(aiw_inputs.at(i)); {
if (v == State::S1) current[data.first] = data.second;
aiwfile << '1';
else
aiwfile << '0';
continue;
} }
if (aiw_inits.count(i)) { if (first) {
auto v = worker->top->get_state(aiw_inits.at(i)); for (int i = 0;; i++)
if (v == State::S1) {
aiwfile << '1'; if (aiw_latches.count(i)) {
else SigBit bit = aiw_latches.at(i).first;
aiwfile << '0'; auto v = current[mapping[bit.wire]].bits.at(bit.offset);
continue; if (v == State::S1)
aiwfile << (aiw_latches.at(i).second ? '0' : '1');
else
aiwfile << (aiw_latches.at(i).second ? '1' : '0');
continue;
}
aiwfile << '\n';
break;
}
first = false;
} }
aiwfile << '\n';
break; for (int i = 0;; i++)
} {
if (aiw_inputs.count(i)) {
SigBit bit = aiw_inputs.at(i);
auto v = current[mapping[bit.wire]].bits.at(bit.offset);
if (v == State::S1)
aiwfile << '1';
else
aiwfile << '0';
continue;
}
if (aiw_inits.count(i)) {
SigBit bit = aiw_inits.at(i);
auto v = current[mapping[bit.wire]].bits.at(bit.offset);
if (v == State::S1)
aiwfile << '1';
else
aiwfile << '0';
continue;
}
aiwfile << '\n';
break;
}
}
} }
std::ofstream aiwfile; std::ofstream aiwfile;
dict<int, std::pair<SigBit, bool>> aiw_latches; dict<int, std::pair<SigBit, bool>> aiw_latches;
dict<int, SigBit> aiw_inputs, aiw_inits; dict<int, SigBit> aiw_inputs, aiw_inits;
std::map<Wire*,int> mapping;
}; };
struct SimPass : public Pass { struct SimPass : public Pass {