diff --git a/qucs/CMakeLists.txt b/qucs/CMakeLists.txt index f5806bf8..6c472643 100755 --- a/qucs/CMakeLists.txt +++ b/qucs/CMakeLists.txt @@ -106,6 +106,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/dialogs #${qucs_SOURCE_DIR}/octave ->no sources here ${PROJECT_SOURCE_DIR}/paintings + ${PROJECT_SOURCE_DIR}/third_party ) #ADD_SUBDIRECTORY( bitmaps ) -> added as resources diff --git a/qucs/schematic_file.cpp b/qucs/schematic_file.cpp index e30f20f4..e8fe8ee4 100644 --- a/qucs/schematic_file.cpp +++ b/qucs/schematic_file.cpp @@ -44,12 +44,22 @@ #include "misc.h" #include "extsimkernels/abstractspicekernel.h" #include "extsimkernels/s2spice.h" +#include "osdi/osdi_0_3.h" // Here the subcircuits, SPICE components etc are collected. It must be // global to also work within the subcircuits. SubMap FileList; +// Dummy function for osdi_log callback. +// Without it, the program will crash if print or display function called +// in verilog-a model. +extern void osdi_log_skip(void *handle, char* msg, uint32_t lvl) +{ + (void)handle; + (void)msg; + (void)lvl; +} // ------------------------------------------------------------- // Creates a Qucs file format (without document properties) in the returning @@ -256,53 +266,56 @@ int Schematic::saveSymbolCpp (void) int Schematic::savePropsJSON() { - QFileInfo info (DocName); - QString jsonfile = info.absolutePath () + QDir::separator() + QFileInfo info (DocName); + QString jsonfile = info.absolutePath () + QDir::separator() + info.baseName() + "_props.json"; - QString vafilename = info.absolutePath () + QDir::separator() - + info.baseName() + ".va"; + QString vafilename = info.absolutePath () + QDir::separator() + + info.baseName() + ".va"; + QString osdifile = info.absolutePath() + QDir::separator() + + info.baseName() + ".osdi"; - QFile vafile(vafilename); - if (!vafile.open (QIODevice::ReadOnly)) { - QMessageBox::critical (0, QObject::tr("Error"), - QObject::tr("Cannot open Verilog-A file \"%1\"!").arg(vafilename)); - return -1; - } + QFile vafile(vafilename); + if (!vafile.open (QIODevice::ReadOnly)) { + QMessageBox::critical (0, QObject::tr("Error"), + QObject::tr("Cannot open Verilog-A file \"%1\"!").arg(vafilename)); + return -1; + } + // if no osdi file exits, generete json file in the old way + if (!QFile::exists(osdifile)){ QString module; QStringList prop_name; QStringList prop_val; QTextStream vastream (&vafile); while(!vastream.atEnd()) { - QString line = vastream.readLine(); - line = line.toLower(); - if (line.contains("module")) { - auto tokens = line.split(QRegularExpression("[\\s()]")); - if (tokens.count() > 1) module = tokens.at(1); + QString line = vastream.readLine(); + line = line.toLower(); + if (line.contains("module")) { + auto tokens = line.split(QRegularExpression("[\\s()]")); + if (tokens.count() > 1) module = tokens.at(1); module = module.trimmed(); - continue; - } - if (line.contains("parameter")) { - auto tokens = line.split(QRegularExpression("[\\s=;]"),qucs::SkipEmptyParts); - if (tokens.count() >= 4) { - for(int ic = 0; ic <= tokens.count(); ic++) { - if (tokens.at(ic) == "parameter") { - prop_name.append(tokens.at(ic+2)); - prop_val.append(tokens.at(ic+3)); - break; - } - } + continue; + } + if (line.contains("parameter")) { + auto tokens = line.split(QRegularExpression("[\\s=;]"),qucs::SkipEmptyParts); + if (tokens.count() >= 4) { + for(int ic = 0; ic <= tokens.count(); ic++) { + if (tokens.at(ic) == "parameter") { + prop_name.append(tokens.at(ic+2)); + prop_val.append(tokens.at(ic+3)); + break; } + } } + } } vafile.close(); - QFile file (jsonfile); if (!file.open (QIODevice::WriteOnly)) { QMessageBox::critical (0, QObject::tr("Error"), - QObject::tr("Cannot save JSON props file \"%1\"!").arg(jsonfile)); + QObject::tr("Cannot save JSON props file \"%1\"!").arg(jsonfile)); return -1; } @@ -315,8 +328,8 @@ int Schematic::savePropsJSON() auto name = prop_name.begin(); auto val = prop_val.begin(); for(; name != prop_name.end(); name++,val++) { - stream << QString(" { \"name\" : \"%1\", \"value\" : \"%2\", \"display\" : \"false\", \"desc\" : \"-\"},\n") - .arg(*name,*val); + stream << QString(" { \"name\" : \"%1\", \"value\" : \"%2\", \"display\" : \"false\", \"desc\" : \"-\"},\n") + .arg(*name,*val); } stream << " ],\n\n"; stream << " \"tx\" : 4,\n"; @@ -329,7 +342,130 @@ int Schematic::savePropsJSON() stream << "}"; file.close (); - return 0; + }else{ + QString module; + QStringList prop_name; + QStringList prop_val; + QStringList prop_disp; + QStringList prop_desc; + + QLibrary osdilib (osdifile); + if (!osdilib.load()){ + QMessageBox::critical(0, QObject::tr("Error"), + QObject::tr("No valid osdi file. Re-compile verilog-a file first!")); + return -1; + } + + // log function is disabled here. + // the dummy function osdi_log_backup is assigned to callback pointer + // to avoid program crash. + void** osdi_log_ = reinterpret_cast(osdilib.resolve("osdi_log")); + void* osdi_log_backup = nullptr; + if (osdi_log_){ + osdi_log_backup = *osdi_log_; + } + *osdi_log_ = (void*)osdi_log_skip; + + OsdiDescriptor* descriptors = reinterpret_cast(osdilib.resolve("OSDI_DESCRIPTORS")); + auto descriptor = descriptors[0]; + void* handler = nullptr; + + // OsdiSimParas and OsdiInitInfo have to be initialized before setup_model and setup_instance + std::vector sim_params_names_vec={nullptr}; + std::vector sim_params_vals_vec={}; + std::vector sim_params_str_vec = {nullptr}; + OsdiSimParas sim_params = { + .names = sim_params_names_vec.data(), + .vals = sim_params_vals_vec.data(), + .names_str = sim_params_str_vec.data(), + .vals_str = nullptr + }; + OsdiInitInfo sim_info = { + .flags = 0, + .num_errors = 0, + .errors = nullptr + }; + + void* model = calloc(1,descriptor.model_size); + void* instance = calloc(1,descriptor.instance_size); + + descriptor.setup_model(handler,model,&sim_params,&sim_info); + descriptor.setup_instance(handler,instance,model,300,descriptor.num_terminals,&sim_params,&sim_info); + + module = QString(descriptor.name); + for(uint32_t i=1;iflags & PARA_TY_MASK) + { + case PARA_TY_INT: + prop_val.append(QString::number(*static_cast(value))); + break; + case PARA_TY_REAL: + prop_val.append(QString::number(*static_cast(value))); + break; + case PARA_TY_STR: + prop_val.append(QString(static_cast(value))); + break; + default: + prop_val.append(""); + break; + } + + prop_name.append(param->name[0]); + prop_desc.append(param->description); + } + + free(model); + free(instance); + if (osdi_log_backup) { + *osdi_log_ = osdi_log_backup; + } + osdilib.unload(); + + QFile file (jsonfile); + + if (!file.open (QIODevice::WriteOnly)) { + QMessageBox::critical (0, QObject::tr("Error"), + QObject::tr("Cannot save JSON props file \"%1\"!").arg(jsonfile)); + return -1; + } + + QTextStream stream (&file); + + stream << "{\n"; + + stream << QString(" \"description\" : \"%1 verilog device\",\n").arg(module); + stream << " \"property\" : [\n"; + auto name = prop_name.begin(); + auto val = prop_val.begin(); + auto disp = prop_disp.begin(); + auto desc = prop_desc.begin(); + for(; name != prop_name.end(); name++,val++,disp++,desc++) { + stream << QString(" { \"name\" : \"%1\", \"value\" : \"%2\", \"display\" : \"%3\", \"desc\" : \"%4\"},\n") + .arg(*name,*val,*disp,*desc); + } + stream << " ],\n\n"; + stream << " \"tx\" : 4,\n"; + stream << " \"ty\" : 4,\n"; + stream << QString(" \"Model\" : \"%1\",\n").arg(module); + stream << " \"NetName\" : \"T\",\n\n\n"; + stream << QString(" \"SymName\" : \"%1\",\n").arg(module); + stream << QString(" \"BitmapFile\" : \"%1\",\n").arg(module); + + stream << "}"; + + file.close (); + } + return 0; } // save symbol paintings in JSON format diff --git a/qucs/third_party/osdi/osdi_0_3.h b/qucs/third_party/osdi/osdi_0_3.h new file mode 100644 index 00000000..c7688b1d --- /dev/null +++ b/qucs/third_party/osdi/osdi_0_3.h @@ -0,0 +1,198 @@ +#pragma once + +#ifndef NO_STD +#include +#include +#include +#endif + + +#define OSDI_VERSION_MAJOR_CURR 0 +#define OSDI_VERSION_MINOR_CURR 3 + +#define PARA_TY_MASK 3 +#define PARA_TY_REAL 0 +#define PARA_TY_INT 1 +#define PARA_TY_STR 2 +#define PARA_KIND_MASK (3 << 30) +#define PARA_KIND_MODEL (0 << 30) +#define PARA_KIND_INST (1 << 30) +#define PARA_KIND_OPVAR (2 << 30) + +#define ACCESS_FLAG_READ 0 +#define ACCESS_FLAG_SET 1 +#define ACCESS_FLAG_INSTANCE 4 + +#define JACOBIAN_ENTRY_RESIST_CONST 1 +#define JACOBIAN_ENTRY_REACT_CONST 2 +#define JACOBIAN_ENTRY_RESIST 4 +#define JACOBIAN_ENTRY_REACT 8 + +#define CALC_RESIST_RESIDUAL 1 +#define CALC_REACT_RESIDUAL 2 +#define CALC_RESIST_JACOBIAN 4 +#define CALC_REACT_JACOBIAN 8 +#define CALC_NOISE 16 +#define CALC_OP 32 +#define CALC_RESIST_LIM_RHS 64 +#define CALC_REACT_LIM_RHS 128 +#define ENABLE_LIM 256 +#define INIT_LIM 512 +#define ANALYSIS_NOISE 1024 +#define ANALYSIS_DC 2048 +#define ANALYSIS_AC 4096 +#define ANALYSIS_TRAN 8192 +#define ANALYSIS_IC 16384 +#define ANALYSIS_STATIC 32768 +#define ANALYSIS_NODESET 65536 + +#define EVAL_RET_FLAG_LIM 1 +#define EVAL_RET_FLAG_FATAL 2 +#define EVAL_RET_FLAG_FINISH 4 +#define EVAL_RET_FLAG_STOP 8 + + +#define LOG_LVL_MASK 7 +#define LOG_LVL_DEBUG 0 +#define LOG_LVL_DISPLAY 1 +#define LOG_LVL_INFO 2 +#define LOG_LVL_WARN 3 +#define LOG_LVL_ERR 4 +#define LOG_LVL_FATAL 5 +#define LOG_FMT_ERR 16 + +#define INIT_ERR_OUT_OF_BOUNDS 1 + + + +typedef struct OsdiLimFunction { + char *name; + uint32_t num_args; + void *func_ptr; +}OsdiLimFunction; + +typedef struct OsdiSimParas { + char **names; + double *vals; + char **names_str; + char **vals_str; +}OsdiSimParas; + +typedef struct OsdiSimInfo { + OsdiSimParas paras; + double abstime; + double *prev_solve; + double *prev_state; + double *next_state; + uint32_t flags; +}OsdiSimInfo; + +typedef union OsdiInitErrorPayload { + uint32_t parameter_id; +}OsdiInitErrorPayload; + +typedef struct OsdiInitError { + uint32_t code; + OsdiInitErrorPayload payload; +}OsdiInitError; + +typedef struct OsdiInitInfo { + uint32_t flags; + uint32_t num_errors; + OsdiInitError *errors; +}OsdiInitInfo; + +typedef struct OsdiNodePair { + uint32_t node_1; + uint32_t node_2; +}OsdiNodePair; + +typedef struct OsdiJacobianEntry { + OsdiNodePair nodes; + uint32_t react_ptr_off; + uint32_t flags; +}OsdiJacobianEntry; + +typedef struct OsdiNode { + char *name; + char *units; + char *residual_units; + uint32_t resist_residual_off; + uint32_t react_residual_off; + uint32_t resist_limit_rhs_off; + uint32_t react_limit_rhs_off; + bool is_flow; +}OsdiNode; + +typedef struct OsdiParamOpvar { + char **name; + uint32_t num_alias; + char *description; + char *units; + uint32_t flags; + uint32_t len; +}OsdiParamOpvar; + +typedef struct OsdiNoiseSource { + char *name; + OsdiNodePair nodes; +}OsdiNoiseSource; + +typedef struct OsdiDescriptor { + char *name; + + uint32_t num_nodes; + uint32_t num_terminals; + OsdiNode *nodes; + + uint32_t num_jacobian_entries; + OsdiJacobianEntry *jacobian_entries; + + uint32_t num_collapsible; + OsdiNodePair *collapsible; + uint32_t collapsed_offset; + + OsdiNoiseSource *noise_sources; + uint32_t num_noise_src; + + uint32_t num_params; + uint32_t num_instance_params; + uint32_t num_opvars; + OsdiParamOpvar *param_opvar; + + uint32_t node_mapping_offset; + uint32_t jacobian_ptr_resist_offset; + + uint32_t num_states; + uint32_t state_idx_off; + + uint32_t bound_step_offset; + + uint32_t instance_size; + uint32_t model_size; + + void *(*access)(void *inst, void *model, uint32_t id, uint32_t flags); + + void (*setup_model)(void *handle, void *model, OsdiSimParas *sim_params, + OsdiInitInfo *res); + void (*setup_instance)(void *handle, void *inst, void *model, + double temperature, uint32_t num_terminals, + OsdiSimParas *sim_params, OsdiInitInfo *res); + + uint32_t (*eval)(void *handle, void *inst, void *model, OsdiSimInfo *info); + void (*load_noise)(void *inst, void *model, double freq, double *noise_dens); + void (*load_residual_resist)(void *inst, void* model, double *dst); + void (*load_residual_react)(void *inst, void* model, double *dst); + void (*load_limit_rhs_resist)(void *inst, void* model, double *dst); + void (*load_limit_rhs_react)(void *inst, void* model, double *dst); + void (*load_spice_rhs_dc)(void *inst, void* model, double *dst, + double* prev_solve); + void (*load_spice_rhs_tran)(void *inst, void* model, double *dst, + double* prev_solve, double alpha); + void (*load_jacobian_resist)(void *inst, void* model); + void (*load_jacobian_react)(void *inst, void* model, double alpha); + void (*load_jacobian_tran)(void *inst, void* model, double alpha); +}OsdiDescriptor; + + +