18 #include "rapidjson/document.h"
19 #include "rapidjson/filereadstream.h"
21 #include <QCoreApplication>
25 #include <QTemporaryDir>
33 :
QObject(parent), mId(
id), mName(
QString::fromStdString(nam)), mState(NoGatesSelected), mSimulationEngine(nullptr), mTempDir(nullptr), mWaveDataList(nullptr),
50 templatePath +=
"hal_simulation_" + mName +
"_XXXXXX";
52 mWorkDir = mTempDir->
path();
58 QDir saleaeDir(
QDir(mWorkDir).absoluteFilePath(
"saleae"));
61 if (!
QFileInfo(saleaeDirectoryFilename).exists())
63 QFile of(saleaeDirectoryFilename);
69 mWaveDataList =
new WaveDataList(saleaeDirectoryFilename);
75 :
QObject(parent), mId(
id), mState(NoGatesSelected), mSimulationEngine(nullptr), mTempDir(nullptr), mWaveDataList(nullptr), mSimulationInput(new
SimulationInput), mLogReceiver(nullptr)
77 FILE*
ff = fopen(filename.c_str(),
"rb");
80 log_warning(
"simulation_plugin",
"Error opening file '{}'.", filename);
85 rapidjson::FileReadStream frs(
ff, buffer,
sizeof(buffer));
86 rapidjson::Document document;
87 document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs);
90 if (document.HasParseError() || !document.HasMember(
"netlist_simulator_controller"))
92 log_warning(
"simulation_plugin",
"Cannot restore simulation controller from file '{}'.", filename);
95 auto jnsc = document[
"netlist_simulator_controller"].GetObject();
96 if (jnsc.HasMember(
"name"))
102 std::vector<Gate*> simulatedGates;
103 if (jnsc.HasMember(
"gates"))
105 for (
auto& jgate : jnsc[
"gates"].GetArray())
107 u32 gateId = jgate.HasMember(
"id") ? jgate[
"id"].GetUint() : 0;
111 log_warning(
"simulation_plugin",
"Simulated gate ID={} not found in netlist.", gateId);
114 if (jgate.HasMember(
"name") && jgate[
"name"].GetString() != g->
get_name() && g->
get_name().find(
"UNKNOWN") != 0)
116 log_warning(
"simulation_plugin",
"Gate name for ID={} differs in simulation '{}' and netlist '{}'", gateId, jgate[
"name"].GetString(), g->
get_name());
119 simulatedGates.push_back(g);
129 mSimulationInput->
add_gates(simulatedGates);
134 if (jnsc.HasMember(
"clocks"))
136 for (
auto& jclock : jnsc[
"clocks"].GetArray())
138 u32 clkId = jclock.HasMember(
"id") ? jclock[
"id"].GetUint() : 0;
145 bool startAtZero = jclock.HasMember(
"start_value") ? (jclock[
"start_value"].GetInt() == 0) :
true;
146 int period = jclock.HasMember(
"switch_time") ? jclock[
"switch_time"].GetInt() * 2 : 1000;
151 if (jnsc.HasMember(
"engine"))
153 auto jengine = jnsc[
"engine"].GetObject();
154 if (jengine.HasMember(
"name"))
157 if (mSimulationEngine && jengine.HasMember(
"properties"))
159 auto jprop = jengine[
"properties"].GetObject();
161 for (
auto it = jprop.MemberBegin(); it != jprop.MemberEnd(); ++it)
178 delete mSimulationInput;
184 mLogReceiver = logrec;
187 void NetlistSimulatorController::setState(SimulationState stat)
213 if (mSimulationEngine)
215 mSimulationEngine->
failed();
257 if (mSimulationEngine)
259 delete mSimulationEngine;
265 return mSimulationEngine;
270 return mSimulationEngine;
278 void NetlistSimulatorController::initSimulator()
295 for (
const Net* n : probes)
297 mSimulateOnlyProbes.
insert(n->get_id());
303 mSimulateOnlyProbes = probes;
308 if (trigger_waves.empty())
318 for (
int tov : trigger_on_values)
332 if (expression.empty())
346 if (input_waves.empty() || accepted_combination.empty())
356 for (
int acc : accepted_combination)
375 waveVector.
reserve(nets.size());
381 log_warning(
get_name(),
"Cannot add unkown waveform for net '{}(id={})' to group '{}'.", n->get_name(), n->get_id(),
name);
399 log_warning(
get_name(),
"Invalid 'add_waveform_group' call with nullptr instead of module pin group");
402 std::vector<Net*> nets;
403 for (
const auto pin : pin_group->
get_pins())
405 nets.push_back(pin->get_net());
413 if (!gate || !pin_group)
415 log_warning(
get_name(),
"Invalid 'add_waveform_group' call with nullptr instead of {}", (gate ?
"gate pin group" :
"gate"));
418 std::vector<Net*> nets;
419 for (
const auto pin : pin_group->
get_pins())
422 switch (pin->get_direction())
447 log_warning(
get_name(),
"Invalid 'add_waveform_group' call with name='{}' and nullptr instead of module pin group",
name);
450 std::vector<Net*> nets;
451 for (
const auto pin : pin_group->
get_pins())
453 nets.push_back(pin->get_net());
476 if (reader.
importVcd(filename, mWorkDir, onlyNets))
487 jnsc[
"id"] = (int)
get_id();
495 jgate[
"id"] = (int)g->get_id();
496 jgate[
"name"] = g->get_name();
505 jclock[
"id"] = (int)clk.clock_net->get_id();
506 jclock[
"name"] = clk.clock_net->get_name();
507 jclock[
"switch_time"] = (int)clk.switch_time;
508 jclock[
"start_value"] = clk.start_at_zero ? 0 : 1;
513 if (mSimulationEngine)
516 jengine[
"name"] = mSimulationEngine->
name();
520 jprops[it->first] = it->second;
532 if (!mSimulationEngine)
542 bool engPropMapModified =
false;
543 for (
auto it = engPropMap.
begin(); it != engPropMap.
end(); ++it)
545 std::string prop = it.
key().toStdString();
546 std::string valu = it.value().toStdString();
549 if (userAssignedValue.empty())
556 if (userAssignedValue != valu)
558 log_info(
get_name(),
"Default value for engine property '{}' changed from '{}' to '{}'.", prop, valu, userAssignedValue);
560 engPropMapModified =
true;
564 if (engPropMapModified)
579 qApp->processEvents();
581 for (
auto it = mBadAssignInputWarnings.
constBegin(); it != mBadAssignInputWarnings.
constEnd(); ++it)
585 log_warning(
get_name(),
"Totally {} attempts to set input values for net ID={}, but net is not an input.", it.value(), it.key());
608 if (testClk.clock_net == n)
619 qApp->processEvents();
630 if (!mSimulationEngine->
run(
this, mLogReceiver))
677 std::vector<const Net*> NetlistSimulatorController::getFilterNets(FilterInputFlag filter)
const
681 return std::vector<const Net*>();
690 std::vector<Net*> tmp = (*mSimulationInput->
get_gates().begin())->get_netlist()->get_nets();
691 return std::vector<const Net*>(tmp.begin(), tmp.end());
696 return std::vector<const Net*>();
721 for (
const Net* n : getFilterNets(filter))
748 for (
const Net* n : getFilterNets(filter))
778 if (!
QFileInfo(sourceSaleaeLookup).isReadable())
780 log_warning(
get_name(),
"cannot import SALEAE data from '{}', cannot read lookup table.", dirname);
788 QFile::copy(sourceSaleaeLookup, targetSaleaeLookup);
790 nameFilters <<
"digital_*.bin";
795 QFile::copy(sourceFileInfo.absoluteFilePath(), targetFile);
801 std::unordered_map<Net*, int> lookupTable;
802 for (
const Net* n : getFilterNets(filter))
809 lookupTable.insert(std::make_pair((
Net*)n, inx));
822 void NetlistSimulatorController::restoreComposed(
const SaleaeDirectory& sd)
828 for (
int childKey : sdce.get_children())
848 wd = mWaveDataList->
at(iwave);
857 for (
int dat : sdce.get_data())
861 if (!wds.
isEmpty() && wds.
size() == (
int)sdce.get_children().size())
871 new WaveDataBoolean(mWaveDataList, wds.
toList(), data);
875 WaveDataTrigger* wdTrig =
new WaveDataTrigger(mWaveDataList, wds.
toList(), data);
876 if (sdce.get_filter_entry())
878 int filterKey = sdce.get_filter_entry();
881 WaveData* wd =
nullptr;
899 wd = mWaveDataList->
at(iwave);
904 wdTrig->set_filter_wave(wd);
947 bool success = getResultsInternal();
952 bool NetlistSimulatorController::getResultsInternal()
971 if (resultFile.is_relative())
975 VcdSerializer reader(mWorkDir,
false,
this);
977 if (!info.exists() || !info.isReadable())
985 if (!mSimulateOnlyProbes.
empty() && !mSimulateOnlyProbes.
contains(n->get_id()))
1001 if (!mSimulateOnlyProbes.
isEmpty())
1011 u64 period = 1'000'000'000'000ul / frequency;
1015 void NetlistSimulatorController::checkReadyState()
1091 log_warning(
get_name(),
"Command failed, gates for simulation already selected in this controller.");
1100 u32 nid = n->get_id();
1101 if (!previousInputSet.
contains(nid))
1106 currentInputSet.
insert(nid);
1108 previousInputSet -= currentInputSet;
1109 for (
u32 id : previousInputSet)
1111 mWaveDataList->
remove(
id);
1132 std::vector<InputColumnHeader> retval;
1133 std::unordered_set<const Net*> clkNets;
1136 clkNets.insert(clk.clock_net);
1142 ipc.
nets.push_back(n);
1143 ipc.
name = n->get_name();
1144 ipc.
is_clock = (clkNets.find(n) != clkNets.end());
1145 retval.push_back(ipc);
1155 ipc.
name = ng.get_name();
1158 std::vector<const Net*> temp_nets = ng.get_nets();
1159 ipc.
nets = ng.ascending ? temp_nets : std::vector<const Net*>(temp_nets.rbegin(),temp_nets.rend());
1160 for (
const Net* n : temp_nets)
1162 if (clkNets.find(n) != clkNets.end())
1166 retval.erase(std::remove_if(retval.begin(), retval.end(), [n](
const auto& s) { return s.nets.size() == 1 && s.nets.at(0) == n; }), retval.end());
1168 retval.push_back(ipc);
1188 if (mBadAssignInputWarnings[
net->get_id()]++ < 3)
1216 if (nets.size() != values.size())
1218 log_error(
get_name(),
"Cannot set vector of nets to vector of values, because vectors are not of equal size! {} vs. {}", nets.size(), values.size());
1222 for (
u32 idx = 0; idx < nets.size(); idx++)
1224 set_input(nets.at(idx), values.at(idx));
1231 if (wave_forms.size() != values.size())
1234 get_name(),
"Cannot set WaveDataGroup to vector of values, because the amount of grouped wave forms is not equal to the vector size! {} vs. {}", wave_forms.size(), values.size());
1238 for (
u32 idx = 0; idx < wave_forms.size(); idx++)
1240 set_input(wave_forms.at(idx), values.at(idx));
1252 std::vector<Net*> nets;
1253 for (
const auto pin : pin_group->
get_pins())
1255 nets.push_back(pin->get_net());
1272 mSimulationInput->
clear();
1297 for (
const WaveData* wd : *mWaveDataList)
1304 for (
const Net* n : nets)
1313 if (!start_time && !end_time)
1336 mMap.insert(
id, ctrl);
1342 auto it = mMap.find(
id);
1343 if (it == mMap.end())
1353 for (
auto it = mMap.begin(); it != mMap.end(); ++it)
Value
represents the type of the node
Net * get_fan_in_net(const std::string &pin_name) const
Net * get_fan_out_net(const std::string &pin_name) const
const std::string & get_name() const
JsonWriteObject & add_object()
bool serialize(const std::string &filename)
JsonWriteObject & add_object(const std::string &tag)
JsonWriteArray & add_array(const std::string &tag)
std::shared_ptr< spdlog::logger > add_channel(const std::string &channel_name, const std::vector< std::shared_ptr< log_sink >> &sinks, const std::string &level="info")
static LogManager * get_instance(const std::filesystem::path &file_name="")
Gate * get_gate_by_id(const u32 gate_id) const
Net * get_net_by_id(u32 net_id) const
void engineFinished(bool success)
void simulate(u64 picoseconds)
const std::unordered_set< const Gate * > & get_gates() const
bool import_vcd(const std::string &filename, FilterInputFlag filter)
bool generate_vcd(const std::filesystem::path &path, u32 start_time=0, u32 end_time=0, std::set< const Net * > nets={}) const
void add_clock_frequency(const Net *clock_net, u64 frequency, bool start_at_zero=true)
const std::vector< const Net * > & get_output_nets() const
void compute_waveform_groups()
bool is_legal_directory_name() const
std::string get_working_directory() const
WaveDataGroup * get_waveform_group_by_id(u32 id) const
std::vector< InputColumnHeader > get_input_column_headers() const
void add_gates(const std::vector< Gate * > &gates)
u64 get_max_simulated_time() const
void set_input(const Net *net, BooleanFunction::Value value)
void handleOpenInputFile(const QString &filename)
WaveDataTrigger * get_trigger_time_by_id(u32 id) const
void import_csv(const std::string &filename, FilterInputFlag filter, u64 timescale=1000000000)
const std::vector< const Net * > & get_partial_netlist_nets() const
std::filesystem::path get_saleae_directory_filename() const
void remove_waveform_group(u32 group_id)
~NetlistSimulatorController()
void stateChanged(hal::NetlistSimulatorController::SimulationState state)
void emitLoadProgress(int percent)
void handleRunFinished(bool success)
void load_waveform_groups(bool inputs)
WaveDataBoolean * get_waveform_boolean_by_id(u32 id) const
void add_clock_period(const Net *clock_net, u64 period, bool start_at_zero=true, u64 duration=0)
u32 add_trigger_time(const std::vector< WaveData * > &trigger_waves, const std::vector< int > &trigger_on_values=std::vector< int >())
void setLogReceiver(SimulationLogReceiver *logrec)
WaveData * get_waveform_by_net(const Net *n) const
u32 add_boolean_accept_list_waveform(const std::vector< WaveData * > &input_waves, const std::vector< int > &accepted_combination)
SimulationEngine * create_simulation_engine(const std::string &name)
void import_simulation(const std::string &dirname, FilterInputFlag filter, u64 timescale=1000000000)
static const char * sPersistFile
void set_saleae_timescale(u64 timescale=1000000000)
void import_saleae(const std::string &dirname, std::unordered_map< Net *, int > lookupTable, u64 timescale=1000000000)
SimulationEngine * get_simulation_engine() const
u32 add_waveform_group(const std::string &name, const std::vector< Net * > &nets)
void set_timeframe(u64 tmin=0, u64 tmax=0)
void loadProgress(int percent)
u32 add_boolean_expression_waveform(const std::string &expression)
bool can_import_data() const
std::string get_name() const
std::vector< std::string > get_engine_names() const
const std::unordered_set< const Net * > & get_input_nets() const
void simulate_only_probes(const std::vector< const Net * > &probes)
void rename_waveform(WaveData *wd, std::string name)
bool is_no_clock_used() const
NetlistSimulatorController(u32 id, const std::string nam, const std::string &workdir, QObject *parent=nullptr)
void controllerRemoved(u32 id)
static NetlistSimulatorControllerMap * instance()
void removeController(u32 id)
void addController(NetlistSimulatorController *ctrl)
void controllerAdded(u32 id)
static SimulationSettings * sSimulationSettings
std::vector< T * > get_pins(const std::function< bool(T *)> &filter=nullptr) const
const std::string & get_name() const
static ProjectManager * instance()
The SaleaeDirectoryComposedEntry class represents a composed waveform. There are currently three type...
The SaleaeDirectory class provides the API for the SALEAE directory file. The SALEAE directory file w...
int get_datafile_index(const std::string &nam, uint32_t id) const
Get waveform datafile index for net identified by name and id.
std::string get_directory() const
Get path to SALEAE directory without filename.
std::vector< SaleaeDirectoryComposedEntry > get_composed_list() const
Getter to list of all composed waveform entries.
std::string get_filename() const
Get full path to saleae directory file including filename (/.../saleae.json)
static const int sComposedBaseKey
static bool sWriteDisabled
static uint64_t sTimeScaleFactor
conversion factor to be applied when converting double values from original SALEAE file to integer va...
virtual std::vector< WaveEvent > get_simulation_events(u32 netId) const
std::vector< std::string > factoryNames() const
static SimulationEngineFactories * instance()
SimulationEngineFactory * factoryByName(const std::string nam) const
virtual SimulationEngine * createEngine() const =0
virtual bool run(NetlistSimulatorController *controller, SimulationLogReceiver *logReceiver=nullptr)=0
bool clock_events_required() const
virtual void set_engine_property(const std::string &key, const std::string &value)
virtual std::string get_engine_property(const std::string &key)
virtual bool setSimulationInput(SimulationInput *simInput)=0
bool can_share_memory() const
std::string get_result_filename() const
void set_working_directory(const std::string &workDir)
virtual const std::unordered_map< std::string, std::string > & get_engine_properties() const
QMap< QString, QString > engineProperties() const
void setEngineProperties(const QMap< QString, QString > &engProp)
QString baseDirectory() const
bool importSaleae(const QString &saleaeDirecotry, const std::unordered_map< Net *, int > &lookupTable, const QString &workdir=QString(), u64 timeScale=1000000000)
bool exportVcd(const QString &filename, const QList< const WaveData * > &waves, u32 startTime, u32 endTime, u32 timeShift=0)
bool importCsv(const QString &csvFilename, const QString &workdir=QString(), const QList< const Net * > &onlyNets=QList< const Net * >(), u64 timeScale=1000000000)
bool importVcd(const QString &vcdFilename, const QString &workdir=QString(), const QList< const Net * > &onlyNets=QList< const Net * >())
std::vector< WaveData * > get_waveforms() const
bool rename(const QString &nam)
void insertBooleanValueWithoutSync(u64 t, BooleanFunction::Value bval)
void updateWaveName(int iwave, const QString &nam)
QMap< u32, WaveDataGroup * > mDataGroups
void addWavesToGroup(u32 grpId, const QVector< WaveData * > &wds)
QMap< u32, WaveDataBoolean * > mDataBooleans
int waveIndexByNetId(u32 id) const
SaleaeDirectory & saleaeDirectory()
void addOrReplace(WaveData *wd)
void setValueForEmpty(int val)
const WaveDataTimeframe & timeFrame() const
void emitTimeframeChanged()
WaveData * waveDataByNet(const Net *n)
void incrementSimulTime(u64 deltaT)
void setUserTimeframe(u64 t0=0, u64 t1=0)
QSet< u32 > toSet() const
void triggerAddToView(u32 id) const
void removeGroup(u32 grpId)
void emitGroupUpdated(int grpId)
void insertBooleanValue(WaveData *wd, u64 t, BooleanFunction::Value bval)
QMap< u32, WaveDataTrigger * > mDataTrigger
u64 simulateMaxTime() const
#define log_error(channel,...)
#define log_info(channel,...)
#define log_warning(channel,...)
QString absoluteFilePath(const QString &fileName) const const
QString absolutePath() const const
QFileInfoList entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const const
bool mkpath(const QString &dirPath) const const
bool copy(const QString &newName)
virtual bool open(QIODevice::OpenMode mode) override
QHash::const_iterator constBegin() const const
QHash::const_iterator constEnd() const const
qint64 write(const char *data, qint64 maxSize)
void append(const T &value)
const T & at(int i) const const
bool isEmpty() const const
const Key key(const T &value, const Key &defaultKey) const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
bool isEmpty() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
std::string toStdString() const const
QString path() const const
void append(const T &value)
bool isEmpty() const const
QList< T > toList() const const