Add new code model function cm_irreversible(). This may only be
called from an XSPICE code model's INIT call and has three effects: the instance is treated as "hybrid" even when it does not use both port types; its position in the hybrids array is adusted; and it is explicitly notifed when called just befoore the end of an analog time-step.
This commit is contained in:
parent
34e6c4abea
commit
12fe7b90c4
|
|
@ -52,6 +52,7 @@ NON-STANDARD FEATURES
|
|||
|
||||
#define ANALOG MIF_ANALOG
|
||||
#define EVENT MIF_EVENT_DRIVEN
|
||||
#define STEP_PENDING MIF_STEP_PENDING
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ int cm_message_printf(const char *fmt, ...);
|
|||
double cm_netlist_get_c(void);
|
||||
double cm_netlist_get_l(void);
|
||||
|
||||
void cm_irreversible(unsigned int);
|
||||
const char *cm_get_node_name(const char *, unsigned int);
|
||||
bool cm_probe_node(unsigned int, unsigned int, void *);
|
||||
bool cm_schedule_output(unsigned int, unsigned int, double, void *);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ struct coreInfo_t {
|
|||
int ((*dllitf_cm_message_send)(char *));
|
||||
double ((*dllitf_cm_netlist_get_c)(void));
|
||||
double ((*dllitf_cm_netlist_get_l)(void));
|
||||
void ((*dllitf_cm_irreversible)(unsigned int));
|
||||
const char * ((*dllitf_cm_get_node_name)(const char *, unsigned int));
|
||||
bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int,
|
||||
void *));
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ void EVTdequeue(CKTcircuit *ckt, double time);
|
|||
|
||||
int EVTload(CKTcircuit *ckt, MIFinstance *inst);
|
||||
|
||||
int EVTload_with_event(CKTcircuit *ckt, MIFinstance *inst, Mif_Call_Type_t type);
|
||||
|
||||
void EVTprint(wordlist *wl);
|
||||
void EVTprintvcd(wordlist *wl);
|
||||
void EVTsave(wordlist *wl);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct MIFinstance {
|
|||
|
||||
Mif_Boolean_t analog; /* true if this inst is analog or hybrid type */
|
||||
Mif_Boolean_t event_driven; /* true if this inst is event-driven or hybrid type */
|
||||
unsigned int irreversible; /* non-zero for special treatment */
|
||||
|
||||
int inst_index; /* Index into inst_table in evt struct in ckt */
|
||||
Mif_Callback_t callback; /* instance callback function */
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ typedef enum {
|
|||
typedef enum {
|
||||
MIF_ANALOG, /* Analog call */
|
||||
MIF_EVENT_DRIVEN, /* Event-driven call */
|
||||
MIF_STEP_PENDING, /* Special event call for irreversible Code Models */
|
||||
} Mif_Call_Type_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ INTERFACES
|
|||
cm_get_path()
|
||||
cm_get_circuit()
|
||||
|
||||
cm_irreversible()
|
||||
cm_get_node_name()
|
||||
cm_probe_node()
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/enh.h"
|
||||
#include "ngspice/mif.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/cpextern.h"
|
||||
//#include "util.h"
|
||||
|
||||
|
||||
|
|
@ -730,6 +732,100 @@ CKTcircuit *cm_get_circuit(void)
|
|||
return(g_mif_info.ckt);
|
||||
}
|
||||
|
||||
/* Set the "irreversible" flag on the current instance and shuffle it to the
|
||||
* requested position among any other irreversibles in the hybrid_index array.
|
||||
* Array entries are sorted so that non-zero values of instance->irreversible
|
||||
* are decreasing: an instance with instance->irreversible == 1 is fully
|
||||
* protected.
|
||||
*/
|
||||
|
||||
static void duplicate(MIFinstance *instance)
|
||||
{
|
||||
fprintf(cp_err,
|
||||
"Warning: Duplicate value %d in cm_irreversible() "
|
||||
"for instance %s.\n",
|
||||
instance->irreversible, instance->gen.GENname);
|
||||
}
|
||||
|
||||
void cm_irreversible(unsigned int place)
|
||||
{
|
||||
MIFinstance *instance;
|
||||
Evt_Ckt_Data_t *evt;
|
||||
int num_hybrids;
|
||||
MIFinstance **hybrids;
|
||||
int old_index, i;
|
||||
unsigned int value;
|
||||
|
||||
instance = g_mif_info.instance;
|
||||
if (!g_mif_info.circuit.init) {
|
||||
fprintf(cp_err,
|
||||
"%s: Ignoring call to cm_irreversible(): not in INIT\n",
|
||||
instance->gen.GENname);
|
||||
return;
|
||||
}
|
||||
if (instance->irreversible || place == 0) {
|
||||
if (instance->irreversible != place) {
|
||||
fprintf(cp_err, "%s: Ignoring new value %d in cm_irreversible()\n",
|
||||
instance->gen.GENname, place);
|
||||
}
|
||||
return;
|
||||
}
|
||||
instance->irreversible = place;
|
||||
|
||||
evt = g_mif_info.ckt->evt;
|
||||
num_hybrids = evt->counts.num_hybrids;
|
||||
hybrids = evt->info.hybrids;
|
||||
|
||||
/* Already a hybrid? */
|
||||
|
||||
for (old_index = 0; old_index < num_hybrids; ++old_index) {
|
||||
if (hybrids[old_index] == instance)
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_index < num_hybrids) {
|
||||
/* Existing hybrid, move down, shuffling other entries up. */
|
||||
|
||||
for (i = old_index + 1; i < num_hybrids; ++i) {
|
||||
value = hybrids[i]->irreversible;
|
||||
if (value == 0 || value > place) {
|
||||
hybrids[i - 1] = hybrids[i];
|
||||
} else if (value == place) {
|
||||
duplicate(instance);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
hybrids[i - 1] = instance;
|
||||
} else {
|
||||
/* Instance is not hybrid, add an entry. */
|
||||
|
||||
num_hybrids++;
|
||||
hybrids = TREALLOC(MIFinstance *, hybrids, num_hybrids);
|
||||
evt->counts.num_hybrids = num_hybrids;
|
||||
evt->info.hybrids = hybrids;
|
||||
if (hybrids == NULL) {
|
||||
fprintf(cp_err, "Allocation failed in cm_irreversible()\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Shuffle entries down. */
|
||||
|
||||
for (i = num_hybrids - 2; i >= 0; --i) {
|
||||
value = hybrids[i]->irreversible;
|
||||
if (value != 0 && value < place) {
|
||||
hybrids[i + 1] = hybrids[i];
|
||||
} else if (value == place) {
|
||||
duplicate(instance);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
hybrids[i + 1] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the name of a circuit node connected to a port. */
|
||||
|
||||
const char *cm_get_node_name(const char *port_name, unsigned int index)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ struct coreInfo_t coreInfo =
|
|||
cm_message_send,
|
||||
cm_netlist_get_c,
|
||||
cm_netlist_get_l,
|
||||
cm_irreversible,
|
||||
cm_get_node_name,
|
||||
cm_probe_node,
|
||||
cm_schedule_output,
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@ MODIFICATIONS
|
|||
SUMMARY
|
||||
|
||||
This file contains function EVTcall_hybrids which calls all models
|
||||
which have both analog and event-driven ports. It is called following
|
||||
which have both analog and event-driven ports or have declared
|
||||
themselves to be irreversible (no back-out). It is called following
|
||||
successful evaluation of an analog iteration attempt to allow
|
||||
events to be scheduled by the hybrid models. The 'CALL_TYPE' is set
|
||||
to 'EVENT_DRIVEN' when the model is called from this function.
|
||||
to 'EVENT_DRIVEN' or 'STEP_PENDING' when the model is called
|
||||
from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
|
|
@ -71,6 +73,7 @@ void EVTcall_hybrids(
|
|||
hybrids = ckt->evt->info.hybrids;
|
||||
|
||||
/* Call EVTload for all hybrids */
|
||||
|
||||
for(i = 0; i < num_hybrids; i++)
|
||||
EVTload(ckt, hybrids[i]);
|
||||
EVTload_with_event(ckt, hybrids[i], MIF_STEP_PENDING);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ int EVTload(
|
|||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *inst) /* The instance to call */
|
||||
{
|
||||
return EVTload_with_event(ckt, inst, MIF_EVENT_DRIVEN);
|
||||
}
|
||||
|
||||
/* "Internal" version, also used by EVTcall_hybrids(). */
|
||||
|
||||
int EVTload_with_event(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *inst, /* The instance to call */
|
||||
Mif_Call_Type_t type) /* Type of call (EVENT or STEP_PENDING). */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
|
@ -104,8 +114,7 @@ int EVTload(
|
|||
/* Prepare the code model inputs */
|
||||
/* ***************************** */
|
||||
|
||||
/* Get pointer to instance data structure and other data */
|
||||
/* needed for fast access */
|
||||
/* Get pointer to data structure needed for fast access */
|
||||
|
||||
node_data = ckt->evt->data.node;
|
||||
|
||||
|
|
@ -124,7 +133,14 @@ int EVTload(
|
|||
else
|
||||
cm_data.circuit.time = 0.0;
|
||||
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
/* Instances that have declared themselves as irreversible
|
||||
* are expected to distinguish STEP_PENDING from ordinary events.
|
||||
*/
|
||||
|
||||
if (type == MIF_STEP_PENDING && inst->irreversible)
|
||||
cm_data.circuit.call_type = MIF_STEP_PENDING;
|
||||
else
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
|
||||
|
||||
/* Setup data needed by cm_... functions */
|
||||
|
|
@ -141,9 +157,11 @@ int EVTload(
|
|||
|
||||
|
||||
/* If after initialization and in transient analysis mode */
|
||||
/* create a new state for the instance */
|
||||
/* create a new state for the instance, */
|
||||
/* except analog-only irreversibles. */
|
||||
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized &&
|
||||
inst->inst_index >= 0)
|
||||
EVTcreate_state(ckt, inst->inst_index);
|
||||
|
||||
/* Loop through all connections on the instance and setup */
|
||||
|
|
|
|||
|
|
@ -340,6 +340,11 @@ double cm_netlist_get_l(void) {
|
|||
return (coreitf->dllitf_cm_netlist_get_l)();
|
||||
}
|
||||
|
||||
void cm_irreversible(unsigned int place)
|
||||
{
|
||||
(coreitf->dllitf_cm_irreversible)(place);
|
||||
}
|
||||
|
||||
const char *cm_get_node_name(const char *port, unsigned int index) {
|
||||
return coreitf->dllitf_cm_get_node_name(port, index);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue