diff options
Diffstat (limited to 'passes')
-rw-r--r-- | passes/sat/sim.cc | 743 |
1 files changed, 555 insertions, 188 deletions
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index ff3a30889..5b69dd3bf 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -65,9 +65,19 @@ static double stringToTime(std::string str) return value * pow(10.0, g_units.at(endptr)); } +struct SimWorker; +struct OutputWriter +{ + OutputWriter(SimWorker *w) { worker = w;}; + virtual ~OutputWriter() {}; + virtual void write(std::map<int, bool> &use_signal) = 0; + SimWorker *worker; +}; + struct SimShared { bool debug = false; + bool verbose = true; bool hide_internal = true; bool writeback = false; bool zinit = false; @@ -77,6 +87,10 @@ struct SimShared double stop_time = -1; SimulationMode sim_mode = SimulationMode::sim; bool cycles_set = false; + std::vector<std::unique_ptr<OutputWriter>> outputfiles; + std::vector<std::pair<int,std::map<int,Const>>> output_data; + bool ignore_x = false; + bool date = false; }; void zinit(State &v) @@ -140,8 +154,7 @@ struct SimInstance std::vector<Mem> memories; - dict<Wire*, pair<int, Const>> vcd_database; - dict<Wire*, pair<fstHandle, Const>> fst_database; + dict<Wire*, pair<int, Const>> signal_database; dict<Wire*, fstHandle> fst_handles; SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : @@ -170,7 +183,7 @@ 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()); + log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str()); fst_handles[wire] = id; } @@ -315,6 +328,16 @@ struct SimInstance return did_something; } + void set_memory_state(IdString memid, Const addr, Const data) + { + auto &state = mem_database[memid]; + + int offset = (addr.as_int() - state.mem->start_offset) * state.mem->width; + for (int i = 0; i < GetSize(data); i++) + if (0 <= i+offset && i+offset < GetSize(data)) + state.data.bits[i+offset] = data.bits[i]; + } + void update_cell(Cell *cell) { if (ff_database.count(cell)) @@ -685,100 +708,53 @@ struct SimInstance it.second->writeback(wbmods); } - void write_vcd_header(std::ofstream &f, int &id) + void register_signals(int &id) { - f << stringf("$scope module %s $end\n", log_id(name())); - for (auto wire : module->wires()) { if (shared->hide_internal && wire->name[0] == '$') continue; - f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); - vcd_database[wire] = make_pair(id++, Const()); + signal_database[wire] = make_pair(id, Const()); + id++; } for (auto child : children) - child.second->write_vcd_header(f, id); - - f << stringf("$upscope $end\n"); + child.second->register_signals(id); } - void write_vcd_step(std::ofstream &f) + void write_output_header(std::function<void(IdString)> enter_scope, std::function<void()> exit_scope, std::function<void(Wire*, int)> register_signal) { - for (auto &it : vcd_database) - { - Wire *wire = it.first; - Const value = get_state(wire); - int id = it.second.first; + enter_scope(name()); - if (it.second.second == value) - continue; - - it.second.second = value; - - f << "b"; - for (int i = GetSize(value)-1; i >= 0; i--) { - switch (value[i]) { - case State::S0: f << "0"; break; - case State::S1: f << "1"; break; - case State::Sx: f << "x"; break; - default: f << "z"; - } - } - - f << stringf(" n%d\n", id); - } - - 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()) + for (auto signal : signal_database) { - 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()); + register_signal(signal.first, signal.second.first); } for (auto child : children) - child.second->write_fst_header(f); + child.second->write_output_header(enter_scope, exit_scope, register_signal); - fstWriterSetUpscope(f); + exit_scope(); } - void write_fst_step(struct fstContext *f) + void register_output_step_values(std::map<int,Const> *data) { - for (auto &it : fst_database) + for (auto &it : signal_database) { Wire *wire = it.first; Const value = get_state(wire); - fstHandle id = it.second.first; + int 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()); + data->emplace(id, value); } for (auto child : children) - child.second->write_fst_step(f); + child.second->register_output_step_values(data); } void setInitState() @@ -790,7 +766,7 @@ struct SimInstance 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()); + log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str()); if (id!=0) { Const fst_val = Const::from_string(shared->fst->valueOf(id)); set_state(qsig, fst_val); @@ -801,14 +777,15 @@ struct SimInstance child.second->setInitState(); } - void setState(std::vector<std::pair<SigBit,bool>> bits, std::string values) + void setState(dict<int, std::pair<SigBit,bool>> bits, std::string values) { - for(size_t i=0;i<bits.size();i++) { - switch(values.at(i)) { - case '0' : set_state(bits.at(i).first,bits.at(i).second ? State::S1 : State::S0); break; - case '1' : set_state(bits.at(i).first,bits.at(i).second ? State::S0 : State::S1); break; - default: - set_state(bits.at(i).first,State::Sx); break; + for(auto bit : bits) { + if (bit.first >= GetSize(values)) + log_error("Too few input data bits in file.\n"); + switch(values.at(bit.first)) { + case '0': set_state(bit.second.first, bit.second.second ? State::S1 : State::S0); break; + case '1': set_state(bit.second.first, bit.second.second ? State::S0 : State::S1); break; + default: set_state(bit.second.first, State::Sx); break; } } } @@ -856,8 +833,6 @@ struct SimInstance 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; @@ -866,75 +841,41 @@ struct SimWorker : SimShared ~SimWorker() { + outputfiles.clear(); delete top; } - void write_vcd_header() + void register_signals() { - vcdfile << stringf("$version %s $end\n", yosys_version_str); - - std::time_t t = std::time(nullptr); - char mbstr[255]; - if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) { - vcdfile << stringf("$date ") << mbstr << stringf(" $end\n"); - } - - if (!timescale.empty()) - vcdfile << stringf("$timescale %s $end\n", timescale.c_str()); - int id = 1; - top->write_vcd_header(vcdfile, id); - - vcdfile << stringf("$enddefinitions $end\n"); - } - - void write_vcd_step(int t) - { - 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(); + top->register_signals(id); } - void write_output_step(int t) + void register_output_step(int t) { - if (vcdfile.is_open()) - write_vcd_step(t); - if (fstfile) - write_fst_step(t); + std::map<int,Const> data; + top->register_output_step_values(&data); + output_data.emplace_back(t, data); } - void write_output_end() + void write_output_files() { - if (fstfile) - fstWriterClose(fstfile); + std::map<int, bool> use_signal; + bool first = ignore_x; + for(auto& d : output_data) + { + if (first) { + for (auto &data : d.second) + use_signal[data.first] = !data.second.is_fully_undef(); + first = false; + } else { + for (auto &data : d.second) + use_signal[data.first] = true; + } + if (!ignore_x) break; + } + for(auto& writer : outputfiles) + writer->write(use_signal); } void update() @@ -976,10 +917,11 @@ struct SimWorker : SimShared { log_assert(top == nullptr); top = new SimInstance(this, scope, topmod); + register_signals(); if (debug) log("\n===== 0 =====\n"); - else + else if (verbose) log("Simulating cycle 0.\n"); set_inports(reset, State::S1); @@ -990,24 +932,23 @@ struct SimWorker : SimShared update(); - write_output_header(); - write_output_step(0); + register_output_step(0); for (int cycle = 0; cycle < numcycles; cycle++) { if (debug) log("\n===== %d =====\n", 10*cycle + 5); - else + else if (verbose) log("Simulating cycle %d.\n", (cycle*2)+1); set_inports(clock, State::S0); set_inports(clockn, State::S1); update(); - write_output_step(10*cycle + 5); + register_output_step(10*cycle + 5); if (debug) log("\n===== %d =====\n", 10*cycle + 10); - else + else if (verbose) log("Simulating cycle %d.\n", (cycle*2)+2); set_inports(clock, State::S1); @@ -1019,12 +960,12 @@ struct SimWorker : SimShared } 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_end(); + write_output_files(); if (writeback) { pool<Module*> wbmods; @@ -1032,7 +973,7 @@ struct SimWorker : SimShared } } - void run_cosim(Module *topmod, int numcycles) + void run_cosim_fst(Module *topmod, int numcycles) { log_assert(top == nullptr); fst = new FstData(sim_filename); @@ -1041,6 +982,7 @@ struct SimWorker : SimShared log_error("Scope must be defined for co-simulation.\n"); top = new SimInstance(this, scope, topmod); + register_signals(); std::vector<fstHandle> fst_clock; @@ -1123,19 +1065,21 @@ struct SimWorker : SimShared 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()); + if (verbose) + log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString()); + bool did_something = false; for(auto &item : inputs) { std::string v = fst->valueOf(item.second); - top->set_state(item.first, Const::from_string(v)); + did_something |= top->set_state(item.first, Const::from_string(v)); } if (initial) { top->setInitState(); - write_output_header(); initial = false; } - update(); - write_output_step(5*cycle); + if (did_something) + update(); + register_output_step(time); bool status = top->checkSignals(); if (status) @@ -1151,23 +1095,27 @@ struct SimWorker : SimShared } catch(fst_end_of_data_exception) { // end of data detected } - write_output_step(5*(cycle-1)+2); - write_output_end(); + + write_output_files(); if (writeback) { pool<Module*> wbmods; top->writeback(wbmods); } + delete fst; } - void run_cosim_witness(Module *topmod) + void run_cosim_aiger_witness(Module *topmod) { log_assert(top == nullptr); + if ((clock.size()+clockn.size())==0) + log_error("Clock signal must be specified.\n"); std::ifstream mf(map_filename); std::string type, symbol; int variable, index; - std::vector<std::pair<SigBit,bool>> inputs; - std::vector<std::pair<SigBit,bool>> latches; + dict<int, std::pair<SigBit,bool>> inputs, inits, latches; + if (mf.fail()) + log_cmd_error("Not able to read AIGER witness map file.\n"); while (mf >> type >> variable >> index >> symbol) { RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); Wire *w = topmod->wire(escaped_s); @@ -1176,11 +1124,13 @@ struct SimWorker : SimShared if (index < w->start_offset || index > w->start_offset + w->width) log_error("Index %d for wire %s is out of range\n", index, log_signal(w)); if (type == "input") { - inputs.emplace_back(SigBit(w,index),false); + inputs[variable] = {SigBit(w,index), false}; + } else if (type == "init") { + inits[variable] = {SigBit(w,index), false}; } else if (type == "latch") { - latches.emplace_back(SigBit(w,index),false); + latches[variable] = {SigBit(w,index), false}; } else if (type == "invlatch") { - latches.emplace_back(SigBit(w,index),true); + latches[variable] = {SigBit(w,index), true}; } } @@ -1189,46 +1139,415 @@ struct SimWorker : SimShared if (f.fail() || GetSize(sim_filename) == 0) log_error("Can not open file `%s`\n", sim_filename.c_str()); - bool init = true; + int state = 0; + std::string status; int cycle = 0; top = new SimInstance(this, scope, topmod); + register_signals(); + while (!f.eof()) { std::string line; std::getline(f, line); if (line.size()==0 || line[0]=='#') continue; - if (init) { - if (line.size()!=latches.size()) - log_error("Wrong number of initialization bits in file.\n"); - write_output_header(); - top->setState(latches, line); - init = false; - } else { - log("Simulating cycle %d.\n", cycle); - if (line.size()!=inputs.size()) - log_error("Wrong number of input data bits in file.\n"); - top->setState(inputs, line); - if (cycle) { + if (line[0]=='.') break; + if (state==0 && line.size()!=1) { + // old format detected, latch data + state = 2; + } + if (state==1 && line[0]!='b' && line[0]!='c') { + // was old format but with 1 bit latch + top->setState(latches, status); + state = 3; + } + + switch(state) + { + case 0: + status = line; + state = 1; + break; + case 1: + state = 2; + break; + case 2: + top->setState(latches, line); + state = 3; + break; + default: + if (verbose) + log("Simulating cycle %d.\n", cycle); + top->setState(inputs, line); + if (cycle) { + set_inports(clock, State::S1); + set_inports(clockn, State::S0); + } else { + top->setState(inits, line); + set_inports(clock, State::S0); + set_inports(clockn, State::S1); + } + update(); + register_output_step(10*cycle); + if (cycle) { + set_inports(clock, State::S0); + set_inports(clockn, State::S1); + update(); + register_output_step(10*cycle + 5); + } + cycle++; + break; + } + } + register_output_step(10*cycle); + write_output_files(); + } + + std::vector<std::string> split(std::string text, const char *delim) + { + std::vector<std::string> list; + char *p = strdup(text.c_str()); + char *t = strtok(p, delim); + while (t != NULL) { + list.push_back(t); + t = strtok(NULL, delim); + } + free(p); + return list; + } + + std::string signal_name(std::string const & name) + { + size_t pos = name.find_first_of("@"); + if (pos==std::string::npos) { + pos = name.find_first_of("#"); + if (pos==std::string::npos) + log_error("Line does not contain proper signal name `%s`\n", name.c_str()); + } + return name.substr(0, pos); + } + + void run_cosim_btor2_witness(Module *topmod) + { + log_assert(top == nullptr); + if ((clock.size()+clockn.size())==0) + log_error("Clock signal must be specified.\n"); + std::ifstream f; + f.open(sim_filename.c_str()); + if (f.fail() || GetSize(sim_filename) == 0) + log_error("Can not open file `%s`\n", sim_filename.c_str()); + + int state = 0; + int cycle = 0; + top = new SimInstance(this, scope, topmod); + register_signals(); + int prev_cycle = 0; + int curr_cycle = 0; + std::vector<std::string> parts; + size_t len = 0; + while (!f.eof()) + { + std::string line; + std::getline(f, line); + if (line.size()==0) continue; + + if (line[0]=='#' || line[0]=='@' || line[0]=='.') { + if (line[0]!='.') + curr_cycle = atoi(line.c_str()+1); + else + curr_cycle = -1; // force detect change + + if (curr_cycle != prev_cycle) { + if (verbose) + log("Simulating cycle %d.\n", cycle); set_inports(clock, State::S1); set_inports(clockn, State::S0); - } else { - set_inports(clock, State::S0); - set_inports(clockn, State::S1); - } - update(); - write_output_step(10*cycle); - if (cycle) { + update(); + register_output_step(10*cycle+0); set_inports(clock, State::S0); set_inports(clockn, State::S1); update(); - write_output_step(10*cycle + 5); + register_output_step(10*cycle+5); + cycle++; + prev_cycle = curr_cycle; } - cycle++; + if (line[0]=='.') break; + continue; + } + + switch(state) + { + case 0: + if (line=="sat") + state = 1; + break; + case 1: + if (line[0]=='b' || line[0]=='j') + state = 2; + else + log_error("Line does not contain property.\n"); + break; + default: // set state or inputs + parts = split(line, " "); + len = parts.size(); + if (len<3 || len>4) + log_error("Invalid set state line content.\n"); + + RTLIL::IdString escaped_s = RTLIL::escape_id(signal_name(parts[len-1])); + if (len==3) { + Wire *w = topmod->wire(escaped_s); + if (!w) { + Cell *c = topmod->cell(escaped_s); + if (!c) + log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod)); + else if (c->type.in(ID($anyconst), ID($anyseq))) { + SigSpec sig_y= c->getPort(ID::Y); + if ((int)parts[1].size() != GetSize(sig_y)) + log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y)); + top->set_state(sig_y, Const::from_string(parts[1])); + } + } else { + if ((int)parts[1].size() != w->width) + log_error("Size of wire %s is different than provided data.\n", log_signal(w)); + top->set_state(w, Const::from_string(parts[1])); + } + } else { + Cell *c = topmod->cell(escaped_s); + if (!c) + log_error("Cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod)); + if (!c->is_mem_cell()) + log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s),log_id(topmod)); + + Const addr = Const::from_string(parts[1].substr(1,parts[1].size()-2)); + Const data = Const::from_string(parts[2]); + top->set_memory_state(c->parameters.at(ID::MEMID).decode_string(), addr, data); + } + break; + } + } + register_output_step(10*cycle); + write_output_files(); + } +}; + +struct VCDWriter : public OutputWriter +{ + VCDWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) { + vcdfile.open(filename.c_str()); + } + + void write(std::map<int, bool> &use_signal) override + { + if (!vcdfile.is_open()) return; + vcdfile << stringf("$version %s $end\n", worker->date ? yosys_version_str : "Yosys"); + + if (worker->date) { + std::time_t t = std::time(nullptr); + char mbstr[255]; + if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) { + vcdfile << stringf("$date ") << mbstr << stringf(" $end\n"); + } + } + + if (!worker->timescale.empty()) + vcdfile << stringf("$timescale %s $end\n", worker->timescale.c_str()); + + worker->top->write_output_header( + [this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); }, + [this]() { vcdfile << stringf("$upscope $end\n");}, + [this,use_signal](Wire *wire, int id) { if (use_signal.at(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"); + + for(auto& d : worker->output_data) + { + vcdfile << stringf("#%d\n", d.first); + for (auto &data : d.second) + { + if (!use_signal.at(data.first)) continue; + Const value = data.second; + 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", data.first); + } + } + } + + std::ofstream vcdfile; +}; + +struct FSTWriter : public OutputWriter +{ + FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) { + fstfile = (struct fstContext *)fstWriterCreate(filename.c_str(),1); + } + + virtual ~FSTWriter() + { + fstWriterClose(fstfile); + } + + void write(std::map<int, bool> &use_signal) override + { + if (!fstfile) return; + std::time_t t = std::time(nullptr); + fstWriterSetVersion(fstfile, worker->date ? yosys_version_str : "Yosys"); + if (worker->date) + fstWriterSetDate(fstfile, asctime(std::localtime(&t))); + else + fstWriterSetDate(fstfile, ""); + if (!worker->timescale.empty()) + fstWriterSetTimescaleFromString(fstfile, worker->timescale.c_str()); + + fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ); + fstWriterSetRepackOnClose(fstfile, 1); + + worker->top->write_output_header( + [this](IdString name) { fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr); }, + [this]() { fstWriterSetUpscope(fstfile); }, + [this,use_signal](Wire *wire, int id) { + if (!use_signal.at(id)) return; + 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); + + mapping.emplace(id, fst_id); + } + ); + + for(auto& d : worker->output_data) + { + fstWriterEmitTimeChange(fstfile, d.first); + for (auto &data : d.second) + { + if (!use_signal.at(data.first)) continue; + Const value = data.second; + 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(fstfile, mapping[data.first], ss.str().c_str()); + } + } + } + + struct fstContext *fstfile = nullptr; + std::map<int,fstHandle> mapping; +}; + +struct AIWWriter : public OutputWriter +{ + AIWWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) { + aiwfile.open(filename.c_str()); + } + + virtual ~AIWWriter() + { + aiwfile << '.' << '\n'; + } + + void write(std::map<int, bool> &) override + { + if (!aiwfile.is_open()) return; + if (worker->map_filename.empty()) + log_cmd_error("For AIGER witness file map parameter is mandatory.\n"); + + std::ifstream mf(worker->map_filename); + std::string type, symbol; + int variable, index; + if (mf.fail()) + log_cmd_error("Not able to read AIGER witness map file.\n"); + while (mf >> type >> variable >> index >> symbol) { + RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); + Wire *w = worker->top->module->wire(escaped_s); + if (!w) + log_error("Wire %s not present in module %s\n",log_id(escaped_s),log_id(worker->top->module)); + if (index < w->start_offset || index > w->start_offset + w->width) + log_error("Index %d for wire %s is out of range\n", index, log_signal(w)); + if (type == "input") { + aiw_inputs[variable] = SigBit(w,index); + } else if (type == "init") { + aiw_inits[variable] = SigBit(w,index); + } else if (type == "latch") { + aiw_latches[variable] = {SigBit(w,index), false}; + } else if (type == "invlatch") { + aiw_latches[variable] = {SigBit(w,index), true}; } } - write_output_step(10*cycle); - write_output_end(); + + worker->top->write_output_header( + [](IdString) {}, + []() {}, + [this](Wire *wire, int id) { mapping[wire] = id; } + ); + + std::map<int, Yosys::RTLIL::Const> current; + bool first = true; + for(auto& d : worker->output_data) + { + for (auto &data : d.second) + { + current[data.first] = data.second; + } + if (first) { + for (int i = 0;; i++) + { + if (aiw_latches.count(i)) { + SigBit bit = aiw_latches.at(i).first; + auto v = current[mapping[bit.wire]].bits.at(bit.offset); + 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; + } + + 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; + dict<int, std::pair<SigBit, bool>> aiw_latches; + dict<int, SigBit> aiw_inputs, aiw_inits; + std::map<Wire*,int> mapping; }; struct SimPass : public Pass { @@ -1247,6 +1566,16 @@ struct SimPass : public Pass { log(" -fst <filename>\n"); log(" write the simulation results to the given FST file\n"); log("\n"); + log(" -aiw <filename>\n"); + log(" write the simulation results to an AIGER witness file\n"); + log(" (requires a *.aim file via -map)\n"); + log("\n"); + log(" -x\n"); + log(" ignore constant x outputs in simulation file.\n"); + log("\n"); + log(" -date\n"); + log(" include date and full version info in output.\n"); + log("\n"); log(" -clock <portname>\n"); log(" name of top-level clock input\n"); log("\n"); @@ -1283,7 +1612,7 @@ struct SimPass : public Pass { log(" -map <filename>\n"); log(" read file with port and latch symbols, needed for AIGER witness input\n"); log("\n"); - log(" -scope\n"); + log(" -scope <name>\n"); log(" scope of simulation top model\n"); log("\n"); log(" -at <time>\n"); @@ -1307,10 +1636,20 @@ struct SimPass : public Pass { log(" -sim-gate\n"); log(" co-simulation, x in FST can match any value in simulation\n"); log("\n"); + log(" -q\n"); + log(" disable per-cycle/sample log message\n"); + log("\n"); log(" -d\n"); log(" enable debug output\n"); log("\n"); } + + + static std::string file_base_name(std::string const & path) + { + return path.substr(path.find_last_of("/\\") + 1); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) override { SimWorker worker; @@ -1324,13 +1663,19 @@ struct SimPass : public Pass { if (args[argidx] == "-vcd" && argidx+1 < args.size()) { std::string vcd_filename = args[++argidx]; rewrite_filename(vcd_filename); - worker.vcdfile.open(vcd_filename.c_str()); + worker.outputfiles.emplace_back(std::unique_ptr<VCDWriter>(new VCDWriter(&worker, 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); + worker.outputfiles.emplace_back(std::unique_ptr<FSTWriter>(new FSTWriter(&worker, fst_filename.c_str()))); + continue; + } + if (args[argidx] == "-aiw" && argidx+1 < args.size()) { + std::string aiw_filename = args[++argidx]; + rewrite_filename(aiw_filename); + worker.outputfiles.emplace_back(std::unique_ptr<AIWWriter>(new AIWWriter(&worker, aiw_filename.c_str()))); continue; } if (args[argidx] == "-n" && argidx+1 < args.size()) { @@ -1366,6 +1711,10 @@ struct SimPass : public Pass { worker.hide_internal = false; continue; } + if (args[argidx] == "-q") { + worker.verbose = false; + continue; + } if (args[argidx] == "-d") { worker.debug = true; continue; @@ -1426,6 +1775,14 @@ struct SimPass : public Pass { worker.sim_mode = SimulationMode::gate; continue; } + if (args[argidx] == "-x") { + worker.ignore_x = true; + continue; + } + if (args[argidx] == "-date") { + worker.date = true; + continue; + } break; } extra_args(args, argidx, design); @@ -1450,11 +1807,21 @@ struct SimPass : public Pass { if (worker.sim_filename.empty()) worker.run(top_mod, numcycles); - else - if (worker.map_filename.empty()) - worker.run_cosim(top_mod, numcycles); - else - worker.run_cosim_witness(top_mod); + else { + std::string filename_trim = file_base_name(worker.sim_filename); + if (filename_trim.size() > 4 && ((filename_trim.compare(filename_trim.size()-4, std::string::npos, ".fst") == 0) || + filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0)) { + worker.run_cosim_fst(top_mod, numcycles); + } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".aiw") == 0) { + if (worker.map_filename.empty()) + log_cmd_error("For AIGER witness file map parameter is mandatory.\n"); + worker.run_cosim_aiger_witness(top_mod); + } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".wit") == 0) { + worker.run_cosim_btor2_witness(top_mod); + } else { + log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker.sim_filename.c_str()); + } + } } } SimPass; |