Browse Source

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.
pre-master-46
Giles Atkinson 2 years ago
parent
commit
12fe7b90c4
  1. 1
      src/include/ngspice/cmconstants.h
  2. 1
      src/include/ngspice/cmproto.h
  3. 1
      src/include/ngspice/dllitf.h
  4. 2
      src/include/ngspice/evtproto.h
  5. 1
      src/include/ngspice/mifdefs.h
  6. 1
      src/include/ngspice/miftypes.h
  7. 96
      src/xspice/cm/cm.c
  8. 1
      src/xspice/cm/cmexport.c
  9. 9
      src/xspice/evt/evtcall_hybrids.c
  10. 28
      src/xspice/evt/evtload.c
  11. 5
      src/xspice/icm/dlmain.c

1
src/include/ngspice/cmconstants.h

@ -52,6 +52,7 @@ NON-STANDARD FEATURES
#define ANALOG MIF_ANALOG
#define EVENT MIF_EVENT_DRIVEN
#define STEP_PENDING MIF_STEP_PENDING
#endif

1
src/include/ngspice/cmproto.h

@ -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 *);

1
src/include/ngspice/dllitf.h

@ -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 *));

2
src/include/ngspice/evtproto.h

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

1
src/include/ngspice/mifdefs.h

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

1
src/include/ngspice/miftypes.h

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

96
src/xspice/cm/cm.c

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

1
src/xspice/cm/cmexport.c

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

9
src/xspice/evt/evtcall_hybrids.c

@ -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);
}

28
src/xspice/evt/evtload.c

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

5
src/xspice/icm/dlmain.c

@ -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…
Cancel
Save