Add support for '_props.json' generation from osdi file.

Signed-off-by: Linfeng He <akirt@outlook.com>
This commit is contained in:
Linfeng He 2024-03-08 00:41:23 +08:00
parent d7b3118561
commit bfa2a00e1d
3 changed files with 367 additions and 32 deletions

View File

@ -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

View File

@ -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<void**>(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<OsdiDescriptor*>(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<char*> sim_params_names_vec={nullptr};
std::vector<double> sim_params_vals_vec={};
std::vector<char*> 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;i<descriptor.num_params;i++) {
auto param = descriptor.param_opvar+i;
void* value;
if (i<descriptor.num_instance_params){
value = descriptor.access(instance,model,i,ACCESS_FLAG_INSTANCE);
prop_disp.append("true");
}else{
value = descriptor.access(instance,model,i,ACCESS_FLAG_READ);
prop_disp.append("false");
}
switch (param->flags & PARA_TY_MASK)
{
case PARA_TY_INT:
prop_val.append(QString::number(*static_cast<uint32_t*>(value)));
break;
case PARA_TY_REAL:
prop_val.append(QString::number(*static_cast<double*>(value)));
break;
case PARA_TY_STR:
prop_val.append(QString(static_cast<char*>(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

198
qucs/third_party/osdi/osdi_0_3.h vendored Normal file
View File

@ -0,0 +1,198 @@
#pragma once
#ifndef NO_STD
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#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;