ngspice/src/frontend/udevices.c

3124 lines
91 KiB
C

/*
udevices.c translate PSPICE U* instances and timing models.
Notes: To translate Pspice U* devices in a subcircuit containing
U* instance and Pspice .model cards, two passes through the subcircuit
are necessary. The first pass is to translate the timing models from
the .model cards. This timing delay information is stored. The second
pass is for translating the U* instance cards to generate equivalent
Xspice digital device instances and their timing delay .model cards
using the previously stored delays.
Some limitations are:
No support for logicexp, pindly, and constraint behavioral primitives.
Approximations to the Pspice timing delays. Typical values for delays
are estimated. Pspice has a rich set of timing simulation features,
such as checks for setup/hold violations, minimum pulse width, and
hazard detection.
Only the common logic gates, flip-flops, and latches are supported.
First pass through a subcircuit. Call initialize_udevice() and read the
.model cards by calling u_process_model_line() (or similar) for each card,
The delays for the different types (ugate, utgate, ueff, ugff) are stored
by get_delays_...() and add_delays_to_model_xlator(). Also, during the
first pass, check that each U* instance can be translated to Xspice.
If there are any .model or U* instance cards that cannot be processed
in the .subckt, then there is no second pass and the .subckt is skipped.
Second pass through a subcircuit. To translate each U* instance call
u_process_instance_line() (or similar). This calls translate_...()
functions for gates, tristate, flip-flops and latches. translate_...()
calls add_..._inout_timing_model() to parse the U* card, and then calls
gen_..._instance(). Creating new cards to replace the U* and .model
cards is done by calling replacement_udevice_cards(), which returns a
list of new cards. The list of cards is then to be inserted after the
.subckt card and before the .ends card. This occurs in the driver
function u_instances() in frontend/inpcom.c.
Finally, call cleanup_udevice() before repeating the sequence for
another subcircuit.
More explanations are provided below in comments with NOTE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "ngspice/ngspice.h"
#include "ngspice/memory.h"
#include "ngspice/bool.h"
#include "ngspice/stringskip.h"
#include "ngspice/stringutil.h"
#include "ngspice/inpdefs.h"
#include "ngspice/macros.h"
#include "ngspice/udevices.h"
extern struct card* insert_new_line(
struct card* card, char* line, int linenum, int linenum_orig);
/* device types */
#define D_AND 0
#define D_AO 1
#define D_AOI 2
#define D_BUF 3
#define D_INV 4
#define D_NAND 5
#define D_NOR 6
#define D_NXOR 7
#define D_OA 8
#define D_OAI 9
#define D_OR 10
#define D_XOR 11
#define D_DFF 12
#define D_JKFF 13
#define D_DLTCH 14
#define D_SRFF 15
#define D_UP 16
#define D_DOWN 17
#define D_TRI 18
#define XSPICESZ 19
/* structs for parsed gate U... instances */
struct instance_hdr {
char *instance_name;
char *instance_type;
int num1;
int num2;
};
struct gate_instance {
struct instance_hdr *hdrp;
int num_gates;
int width;
int num_ins;
char **inputs;
char *enable;
int num_outs;
char **outputs;
char *tmodel;
};
struct compound_instance {
struct instance_hdr *hdrp;
int num_gates;
int width;
int num_ins;
char **inputs;
char *output;
char *tmodel;
};
struct dff_instance {
struct instance_hdr *hdrp;
char *prebar;
char *clrbar;
char *clk;
int num_gates;
char **d_in;
char **q_out;
char **qb_out;
char *tmodel;
};
struct jkff_instance {
struct instance_hdr *hdrp;
char *prebar;
char *clrbar;
char *clkbar;
int num_gates;
char **j_in;
char **k_in;
char **q_out;
char **qb_out;
char *tmodel;
};
struct srff_instance {
struct instance_hdr *hdrp;
char *prebar;
char *clrbar;
char *gate;
int num_gates;
char **s_in;
char **r_in;
char **q_out;
char **qb_out;
char *tmodel;
};
struct dltch_instance {
struct instance_hdr *hdrp;
char *prebar;
char *clrbar;
char *gate;
int num_gates;
char **d_in;
char **q_out;
char **qb_out;
char *tmodel;
};
/* structs for instances and timing models which have been translated */
typedef struct s_xlate *Xlatep;
typedef struct s_xlate {
Xlatep next;
char *translated; // the translated instance line
char *delays; // the delays from the pspice timing model
char *utype; // pspice model type ugate, utgate, ueff, ugff
char *xspice; // xspice device type such as d_and, d_dff, etc.
char *tmodel; // timing model name of pspice instance or model
char *mname; // name of the xspice timing model of the instance
} Xlate;
typedef struct s_xlator *Xlatorp;
typedef struct s_xlator {
Xlatep head;
Xlatep tail;
Xlatep iter;
} Xlator;
/* For timing model extraction */
#define EST_UNK -1
#define EST_MIN 0
#define EST_TYP 1
#define EST_MAX 2
#define EST_AVE 3
struct timing_data {
char *min;
char *typ;
char *max;
char *ave;
int estimate;
};
/*
static data cleared and reset by initialize_udevice(),
cleared by cleanup_udevice().
*/
/* .model d_zero_inv99 d_inverter just once per subckt */
static BOOL add_zero_delay_inverter_model = FALSE;
/*
Compound gates have delays added to the final gate.
*/
static char *xspice_tab[XSPICESZ] = {
"d_and", // D_AND
"d_or", // D_AO
"d nor", // D_AOI
"d_buffer", // D_BUF
"d_inverter", // D_INV
"d_nand", // D_NAND
"d_nor", // D_NOR
"d_xnor", // D_NXOR
"d_and", // D_OA
"d_nand", // D_OAI
"d_or", // D_OR
"d_xor", // D_XOR
"d_dff", // D_DFF
"d_jkff", // D_JKFF
"d_dlatch", // D_DLTCH
"d_srlatch", // D_SRFF
"d_pullup", // D_UP
"d_pulldown", // D_DOWN
"d_tristate", // D_TRI
};
static char *find_xspice_for_delay(char *itype)
{
/*
Returns xspice device name of the timing model corresponding to itype
*/
switch (itype[0]) {
case 'a': {
/* and anda and3 and3a */
if (eq(itype, "and")) { return xspice_tab[D_AND]; }
if (eq(itype, "anda")) { return xspice_tab[D_AND]; }
if (eq(itype, "and3")) { return xspice_tab[D_AND]; }
if (eq(itype, "and3a")) { return xspice_tab[D_AND]; }
if (eq(itype, "ao")) { return xspice_tab[D_AO]; }
if (eq(itype, "aoi")) { return xspice_tab[D_AOI]; }
break;
}
case 'b': {
/* buf3 buf3a */
if (eq(itype, "buf3a")) { return xspice_tab[D_TRI]; }
if (eq(itype, "buf")) { return xspice_tab[D_BUF]; }
if (eq(itype, "bufa")) { return xspice_tab[D_BUF]; }
if (eq(itype, "buf3")) { return xspice_tab[D_TRI]; }
break;
}
case 'd': {
if (eq(itype, "dff")) { return xspice_tab[D_DFF]; }
if (eq(itype, "dltch")) { return xspice_tab[D_DLTCH]; }
break;
}
case 'i': {
/* inv inva inv3 inv3a */
if (eq(itype, "inv")) { return xspice_tab[D_INV]; }
if (eq(itype, "inv3a")) { return xspice_tab[D_INV]; }
if (eq(itype, "inva")) { return xspice_tab[D_INV]; }
if (eq(itype, "inv3")) { return xspice_tab[D_INV]; }
break;
}
case 'j': {
if (eq(itype, "jkff")) { return xspice_tab[D_JKFF]; }
break;
}
case 'n': {
/* nand nanda nand3 nand3a */
if (eq(itype, "nand")) { return xspice_tab[D_NAND]; }
if (eq(itype, "nanda")) { return xspice_tab[D_NAND]; }
if (eq(itype, "nand3")) { return xspice_tab[D_NAND]; }
if (eq(itype, "nand3a")) { return xspice_tab[D_NAND]; }
/* nor nora nor3 nor3a */
if (eq(itype, "nor")) { return xspice_tab[D_NOR]; }
if (eq(itype, "nora")) { return xspice_tab[D_NOR]; }
if (eq(itype, "nor3")) { return xspice_tab[D_NOR]; }
if (eq(itype, "nor3a")) { return xspice_tab[D_NOR]; }
/* nxor nxora nxor3 nxor3a */
if (eq(itype, "nxor")) { return xspice_tab[D_NXOR]; }
if (eq(itype, "nxora")) { return xspice_tab[D_NXOR]; }
if (eq(itype, "nxor3")) { return xspice_tab[D_NXOR]; }
if (eq(itype, "nxor3a")) { return xspice_tab[D_NXOR]; }
break;
}
case 'o': {
/* or ora or3 or3a */
if (eq(itype, "or")) { return xspice_tab[D_OR]; }
if (eq(itype, "ora")) { return xspice_tab[D_OR]; }
if (eq(itype, "or3")) { return xspice_tab[D_OR]; }
if (eq(itype, "or3a")) { return xspice_tab[D_OR]; }
if (eq(itype, "oa")) { return xspice_tab[D_OA]; }
if (eq(itype, "oai")) { return xspice_tab[D_OAI]; }
break;
}
case 'p': {
if (eq(itype, "pulldn")) { return xspice_tab[D_DOWN]; }
if (eq(itype, "pullup")) { return xspice_tab[D_UP]; }
break;
}
case 's': {
if (eq(itype, "srff")) { return xspice_tab[D_SRFF]; }
break;
}
case 'x': {
/* xor xora xor3 xor3a */
if (eq(itype, "xor")) { return xspice_tab[D_XOR]; }
if (eq(itype, "xora")) { return xspice_tab[D_XOR]; }
if (eq(itype, "xor3")) { return xspice_tab[D_XOR]; }
if (eq(itype, "xor3a")) { return xspice_tab[D_XOR]; }
break;
}
default:
break;
};
return NULL;
}
/* NOTE
Xlator and Xlate
Xlate struct data is stored in an Xlator list struct.
Used to save translated instance and model statements.
After an Xlator has been created, Xlate data is generated via
create_xlate() and entered into the Xlator by add_xlator().
A first_xlator() ... next_xlator() iteration loop will retrieve
the Xlate data entries in an Xlator.
*/
static void delete_xlate(Xlatep p)
{
if (p) {
if (p->translated) { tfree(p->translated); }
if (p->delays) { tfree(p->delays); }
if (p->utype) { tfree(p->utype); }
if (p->xspice) { tfree(p->xspice); }
if (p->tmodel) { tfree(p->tmodel); }
if (p->mname) { tfree(p->mname); }
tfree(p);
}
return;
}
static Xlatep create_xlate(char *translated, char *delays, char *utype,
char *xspice, char *tmodel, char *mname)
{
/* Any unused parameter is called with an empty string "" */
Xlatep xlp;
xlp = TMALLOC(Xlate, 1);
xlp->next = NULL;
xlp->translated = TMALLOC(char, strlen(translated) + 1);
strcpy(xlp->translated, translated);
xlp->delays = TMALLOC(char, strlen(delays) + 1);
strcpy(xlp->delays, delays);
xlp->utype = TMALLOC(char, strlen(utype) + 1);
strcpy(xlp->utype, utype);
xlp->xspice = TMALLOC(char, strlen(xspice) + 1);
strcpy(xlp->xspice, xspice);
xlp->tmodel = TMALLOC(char, strlen(tmodel) + 1);
strcpy(xlp->tmodel, tmodel);
xlp->mname = TMALLOC(char, strlen(mname) + 1);
strcpy(xlp->mname, mname);
return xlp;
}
static Xlatep create_xlate_translated(char *translated)
{
return create_xlate(translated, "", "", "", "", "");
}
static Xlatep create_xlate_instance(
char *translated, char *xspice, char *tmodel, char *mname)
{
return create_xlate(translated, "", "", xspice, tmodel, mname);
}
/*
static void print_xlate(Xlatep xp)
{
if (!xp) { return; }
printf("translated %s\n", xp->translated);
printf("delays %s\n", xp->delays);
printf("utype %s ", xp->utype);
printf("xspice %s ", xp->xspice);
printf("tmodel %s ", xp->tmodel);
printf("mname %s\n", xp->mname);
}
*/
static Xlatorp create_xlator(void)
{
Xlatorp xp;
xp = TMALLOC(Xlator, 1);
xp->head = NULL;
xp->tail = NULL;
xp->iter = NULL;
return xp;
}
static void delete_xlator(Xlatorp xp)
{
Xlatep x, next;
if (xp) {
if (xp->head) {
x = xp->head;
next = x->next;
delete_xlate(x);
while (next) {
x = next;
next = x->next;
delete_xlate(x);
}
}
tfree(xp);
}
return;
}
static Xlatorp add_xlator(Xlatorp xp, Xlatep x)
{
Xlatep prev;
if (!xp || !x) { return NULL; }
if (!xp->head) {
xp->head = x;
xp->tail = x;
xp->iter = x;
x->next = NULL;
} else {
prev = xp->tail;
prev->next = x;
x->next = NULL;
xp->tail = x;
}
return xp;
}
static Xlatep first_xlator(Xlatorp xp)
{
Xlatep xret;
if (!xp) { return NULL; }
xp->iter = xp->head;
if (!xp->iter) {
return NULL;
} else {
xret = xp->iter;
xp->iter = xret->next;
return xret;
}
}
static Xlatep next_xlator(Xlatorp xp)
{
Xlatep ret;
if (!xp) { return NULL; }
ret = xp->iter;
if (!ret) {
return ret;
}
xp->iter = ret->next;
return ret;
}
static Xlatorp append_xlator(Xlatorp dest, Xlatorp src)
{
Xlatep x1, copy;
if (!dest || !src) { return NULL; }
for (x1 = first_xlator(src); x1; x1 = next_xlator(src)) {
copy = create_xlate(x1->translated, x1->delays, x1->utype,
x1->xspice, x1->tmodel, x1->mname);
dest = add_xlator(dest, copy);
}
return dest;
}
/* static Xlatorp for collecting timing model delays */
static Xlatorp model_xlatorp = NULL;
/* static Xlatorp for default zero delay models */
static Xlatorp default_models = NULL;
/* static Xlatorp for storing translated instance and model statements */
static Xlatorp translated_p = NULL;
static void create_translated_xlator(void)
{
translated_p = create_xlator();
}
static void cleanup_translated_xlator(void)
{
delete_xlator(translated_p);
translated_p = NULL;
}
/* NOTE
replacement_udevice_cards() is called by the driver function u_instances()
in frontend/inpcom.c so that the new Xspice instance and model statements
can be spliced into the card deck.
*/
struct card *replacement_udevice_cards(void)
{
struct card *newcard = NULL, *nextcard = NULL;
char *new_str = NULL;
Xlatep x;
int count = 0;
if (!translated_p) { return NULL; }
if (add_zero_delay_inverter_model) {
x = create_xlate_translated(".model d_zero_inv99 d_inverter");
translated_p = add_xlator(translated_p, x);
}
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
new_str = copy(x->translated);
if (count == 0) {
count++;
newcard = insert_new_line(NULL, new_str, 0, 0);
} else if (count == 1) {
count++;
nextcard = insert_new_line(newcard, new_str, 0, 0);
} else {
count++;
nextcard = insert_new_line(nextcard, new_str, 0, 0);
}
}
return newcard;
}
void initialize_udevice(void)
{
Xlatep xdata;
create_translated_xlator();
model_xlatorp = create_xlator();
default_models = create_xlator();
/* .model d0_gate ugate () */
xdata = create_xlate("", "", "ugate", "", "d0_gate", "");
(void) add_xlator(default_models, xdata);
/* .model d0_gff ugff () */
xdata = create_xlate("", "", "ugff", "", "d0_gff", "");
(void) add_xlator(default_models, xdata);
/* .model d0_eff ueff () */
xdata = create_xlate("", "", "ueff", "", "d0_eff", "");
(void) add_xlator(default_models, xdata);
/* .model d0_tgate utgate () */
xdata = create_xlate("", "", "utgate", "", "d0_tgate", "");
(void) add_xlator(default_models, xdata);
/* reset for the new subckt */
add_zero_delay_inverter_model = FALSE;
}
void cleanup_udevice(void)
{
cleanup_translated_xlator();
delete_xlator(model_xlatorp);
model_xlatorp = NULL;
delete_xlator(default_models);
default_models = NULL;
add_zero_delay_inverter_model = FALSE;
}
static Xlatep create_xlate_model(char *delays,
char *utype, char *xspice, char *tmodel)
{
return create_xlate("", delays, utype, xspice, tmodel, "");
}
static Xlatep find_tmodel_in_xlator(Xlatep x, Xlatorp xlp)
{
/* Only for timing model xlators */
Xlatep x1;
if (!x) { return NULL; }
if (!xlp) { return NULL; }
for (x1 = first_xlator(xlp); x1; x1 = next_xlator(xlp)) {
if (eq(x1->tmodel, x->tmodel) && eq(x1->utype, x->utype)) {
if (eq(x1->xspice, x->xspice)) {
return x1;
}
if (xlp == default_models && eq(x->utype, "ugff") &&
eq(x->tmodel, "d0_gff")) {
return x1;
}
}
}
return NULL;
}
static Xlatep find_in_model_xlator(Xlatep x)
{
Xlatep x1;
x1 = find_tmodel_in_xlator(x, model_xlatorp);
if (x1) { return x1; }
x1 = find_tmodel_in_xlator(x, default_models);
return x1;
}
static void add_delays_to_model_xlator(char *delays,
char *utype, char *xspice, char *tmodel)
{
/*
Specify xspice as "d_dlatch" or "d_srlatch" for ugff
otherwise xspice == ""
*/
Xlatep x = NULL, x1 = NULL;
if (!model_xlatorp) { return; }
x = create_xlate_model(delays, utype, xspice, tmodel);
x1 = find_in_model_xlator(x);
if (x1) {
/*
printf("Already found timing model %s utype %s\n",
x1->tmodel, x1->utype);
*/
delete_xlate(x);
return;
}
(void) add_xlator(model_xlatorp, x);
}
/* classify gate variants */
static BOOL is_tristate_buf_array(char *itype)
{
if (eq(itype, "buf3a")) { return TRUE; }
if (eq(itype, "inv3a")) { return TRUE; }
return FALSE;
}
static BOOL is_tristate_xor_array(char *itype)
{
/* xor/nxor have vector inputs */
if (eq(itype, "xor3a")) { return TRUE; }
if (eq(itype, "nxor3a")) { return TRUE; }
return FALSE;
}
static BOOL is_tristate_vector_array(char *itype)
{
if (eq(itype, "and3a")) { return TRUE; }
if (eq(itype, "nand3a")) { return TRUE; }
if (eq(itype, "or3a")) { return TRUE; }
if (eq(itype, "nor3a")) { return TRUE; }
return FALSE;
}
static BOOL is_tristate_array(char *itype)
{
if (is_tristate_buf_array(itype)) { return TRUE; }
if (is_tristate_vector_array(itype)) { return TRUE; }
if (is_tristate_xor_array(itype)) { return TRUE; }
return FALSE;
}
static BOOL is_buf_tristate(char *itype)
{
if (eq(itype, "buf3")) { return TRUE; }
if (eq(itype, "inv3")) { return TRUE; }
return FALSE;
}
static BOOL is_xor_tristate(char *itype)
{
/* xor/nxor have vector inputs */
if (eq(itype, "xor3")) { return TRUE; }
if (eq(itype, "nxor3")) { return TRUE; }
return FALSE;
}
static BOOL is_vector_tristate(char *itype)
{
if (eq(itype, "and3")) { return TRUE; }
if (eq(itype, "nand3")) { return TRUE; }
if (eq(itype, "or3")) { return TRUE; }
if (eq(itype, "nor3")) { return TRUE; }
return FALSE;
}
static BOOL is_tristate(char *itype)
{
if (is_buf_tristate(itype)) { return TRUE; }
if (is_vector_tristate(itype)) { return TRUE; }
if (is_xor_tristate(itype)) { return TRUE; }
return FALSE;
}
static BOOL is_vector_gate_array(char *itype)
{
if (eq(itype, "anda")) { return TRUE; }
if (eq(itype, "nanda")) { return TRUE; }
if (eq(itype, "ora")) { return TRUE; }
if (eq(itype, "nora")) { return TRUE; }
return FALSE;
}
static BOOL is_buf_gate_array(char *itype)
{
if (eq(itype, "bufa")) { return TRUE; }
if (eq(itype, "inva")) { return TRUE; }
return FALSE;
}
static BOOL is_xor_gate_array(char *itype)
{
/* xor/nxor have vector inputs */
if (eq(itype, "xora")) { return TRUE; }
if (eq(itype, "nxora")) { return TRUE; }
return FALSE;
}
static BOOL is_gate_array(char *itype)
{
if (is_vector_gate_array(itype)) { return TRUE; }
if (is_buf_gate_array(itype)) { return TRUE; }
if (is_xor_gate_array(itype)) { return TRUE; }
return FALSE;
}
static BOOL is_vector_gate(char *itype)
{
if (eq(itype, "nand")) { return TRUE; }
if (eq(itype, "and")) { return TRUE; }
if (eq(itype, "nor")) { return TRUE; }
if (eq(itype, "or")) { return TRUE; }
return FALSE;
}
static BOOL is_buf_gate(char *itype)
{
if (eq(itype, "inv")) { return TRUE; }
if (eq(itype, "buf")) { return TRUE; }
return FALSE;
}
static BOOL is_xor_gate(char *itype)
{
/* xor/nxor have vector inputs */
if (eq(itype, "xor")) { return TRUE; }
if (eq(itype, "nxor")) { return TRUE; }
return FALSE;
}
static BOOL is_gate(char *itype)
{
if (is_vector_gate(itype)) { return TRUE; }
if (is_buf_gate(itype)) { return TRUE; }
if (is_xor_gate(itype)) { return TRUE; }
return FALSE;
}
static BOOL is_compound_gate(char *itype)
{
if (eq(itype, "aoi")) { return TRUE; }
if (eq(itype, "ao")) { return TRUE; }
if (eq(itype, "oa")) { return TRUE; }
if (eq(itype, "oai")) { return TRUE; }
return FALSE;
}
static BOOL has_vector_inputs(char *itype)
{
switch (itype[0]) {
case 'a': {
if (strncmp(itype, "and", 3) == 0) { return TRUE; }
break;
}
case 'n': {
if (strncmp(itype, "nand", 4) == 0) { return TRUE; }
if (strncmp(itype, "nor", 3) == 0) { return TRUE; }
if (strncmp(itype, "nxor", 4) == 0) { return TRUE; }
break;
}
case 'o': {
if (strncmp(itype, "or", 2) == 0) { return TRUE; }
break;
}
case 'x': {
if (strncmp(itype, "xor", 3) == 0) { return TRUE; }
break;
}
default:
break;
};
return FALSE;
}
static void delete_instance_hdr(struct instance_hdr *hdr)
{
if (!hdr) { return; }
if (hdr->instance_name) { tfree(hdr->instance_name); }
if (hdr->instance_type) { tfree(hdr->instance_type); }
tfree(hdr);
return;
}
/* NOTE
There are translate_...() functions for each instance type (gates, arrays
of gates, compound gates, dff, jkff, dltch, srff).
For each type (except pullup/down) an instance struct is created by calling
the corresponding create_..._instance() then add_..._inout_timing_model()
functions. The instance struct returned by add_..._inout_timing_model()
is passed to the corresponding gen_..._instance() function, and the Xspice
translations are stored in Xlator translated_p.
*/
static struct dff_instance *create_dff_instance(struct instance_hdr *hdrp)
{
struct dff_instance *dffip;
dffip = TMALLOC(struct dff_instance, 1);
dffip->hdrp = hdrp;
dffip->prebar = NULL;
dffip->clrbar = NULL;
dffip->clk = NULL;
dffip->num_gates = 0;
dffip->d_in = NULL;
dffip->q_out = NULL;
dffip->qb_out = NULL;
dffip->tmodel = NULL;
return dffip;
}
static void delete_dff_instance(struct dff_instance *dp)
{
char **arr;
int i;
if (!dp) { return; }
if (dp->hdrp) { delete_instance_hdr(dp->hdrp); }
if (dp->prebar) { tfree(dp->prebar); }
if (dp->clrbar) { tfree(dp->clrbar); }
if (dp->clk) { tfree(dp->clk); }
if (dp->tmodel) { tfree(dp->tmodel); }
if (dp->num_gates > 0) {
if (dp->d_in) {
arr = dp->d_in;
for (i = 0; i < dp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dp->d_in);
}
if (dp->q_out) {
arr = dp->q_out;
for (i = 0; i < dp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dp->q_out);
}
if (dp->qb_out) {
arr = dp->qb_out;
for (i = 0; i < dp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dp->qb_out);
}
}
tfree(dp);
return;
}
static struct dltch_instance *create_dltch_instance(struct instance_hdr *hdrp)
{
struct dltch_instance *dlp;
dlp = TMALLOC(struct dltch_instance, 1);
dlp->hdrp = hdrp;
dlp->prebar = NULL;
dlp->clrbar = NULL;
dlp->gate = NULL;
dlp->num_gates = 0;
dlp->d_in = NULL;
dlp->q_out = NULL;
dlp->qb_out = NULL;
dlp->tmodel = NULL;
return dlp;
}
static void delete_dltch_instance(struct dltch_instance *dlp)
{
char **arr;
int i;
if (!dlp) { return; }
if (dlp->hdrp) { delete_instance_hdr(dlp->hdrp); }
if (dlp->prebar) { tfree(dlp->prebar); }
if (dlp->clrbar) { tfree(dlp->clrbar); }
if (dlp->gate) { tfree(dlp->gate); }
if (dlp->tmodel) { tfree(dlp->tmodel); }
if (dlp->num_gates > 0) {
if (dlp->d_in) {
arr = dlp->d_in;
for (i = 0; i < dlp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dlp->d_in);
}
if (dlp->q_out) {
arr = dlp->q_out;
for (i = 0; i < dlp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dlp->q_out);
}
if (dlp->qb_out) {
arr = dlp->qb_out;
for (i = 0; i < dlp->num_gates; i++) {
tfree(arr[i]);
}
tfree(dlp->qb_out);
}
}
tfree(dlp);
return;
}
static struct jkff_instance *create_jkff_instance(struct instance_hdr *hdrp)
{
struct jkff_instance *jkffip;
jkffip = TMALLOC(struct jkff_instance, 1);
jkffip->hdrp = hdrp;
jkffip->prebar = NULL;
jkffip->clrbar = NULL;
jkffip->clkbar = NULL;
jkffip->num_gates = 0;
jkffip->j_in = NULL;
jkffip->k_in = NULL;
jkffip->q_out = NULL;
jkffip->qb_out = NULL;
jkffip->tmodel = NULL;
return jkffip;
}
static void delete_jkff_instance(struct jkff_instance *jkp)
{
char **arr;
int i;
if (!jkp) { return; }
if (jkp->hdrp) { delete_instance_hdr(jkp->hdrp); }
if (jkp->prebar) { tfree(jkp->prebar); }
if (jkp->clrbar) { tfree(jkp->clrbar); }
if (jkp->clkbar) { tfree(jkp->clkbar); }
if (jkp->tmodel) { tfree(jkp->tmodel); }
if (jkp->num_gates > 0) {
if (jkp->j_in) {
arr = jkp->j_in;
for (i = 0; i < jkp->num_gates; i++) {
tfree(arr[i]);
}
tfree(jkp->j_in);
}
if (jkp->k_in) {
arr = jkp->k_in;
for (i = 0; i < jkp->num_gates; i++) {
tfree(arr[i]);
}
tfree(jkp->k_in);
}
if (jkp->q_out) {
arr = jkp->q_out;
for (i = 0; i < jkp->num_gates; i++) {
tfree(arr[i]);
}
tfree(jkp->q_out);
}
if (jkp->qb_out) {
arr = jkp->qb_out;
for (i = 0; i < jkp->num_gates; i++) {
tfree(arr[i]);
}
tfree(jkp->qb_out);
}
}
tfree(jkp);
return;
}
static struct srff_instance *create_srff_instance(struct instance_hdr *hdrp)
{
struct srff_instance *srffp;
srffp = TMALLOC(struct srff_instance, 1);
srffp->hdrp = hdrp;
srffp->prebar = NULL;
srffp->clrbar = NULL;
srffp->gate = NULL;
srffp->num_gates = 0;
srffp->s_in = NULL;
srffp->r_in = NULL;
srffp->q_out = NULL;
srffp->qb_out = NULL;
srffp->tmodel = NULL;
return srffp;
}
static void delete_srff_instance(struct srff_instance *srffp)
{
char **arr;
int i;
if (!srffp) { return; }
if (srffp->hdrp) { delete_instance_hdr(srffp->hdrp); }
if (srffp->prebar) { tfree(srffp->prebar); }
if (srffp->clrbar) { tfree(srffp->clrbar); }
if (srffp->gate) { tfree(srffp->gate); }
if (srffp->tmodel) { tfree(srffp->tmodel); }
if (srffp->num_gates > 0) {
if (srffp->s_in) {
arr = srffp->s_in;
for (i = 0; i < srffp->num_gates; i++) {
tfree(arr[i]);
}
tfree(srffp->s_in);
}
if (srffp->r_in) {
arr = srffp->r_in;
for (i = 0; i < srffp->num_gates; i++) {
tfree(arr[i]);
}
tfree(srffp->r_in);
}
if (srffp->q_out) {
arr = srffp->q_out;
for (i = 0; i < srffp->num_gates; i++) {
tfree(arr[i]);
}
tfree(srffp->q_out);
}
if (srffp->qb_out) {
arr = srffp->qb_out;
for (i = 0; i < srffp->num_gates; i++) {
tfree(arr[i]);
}
tfree(srffp->qb_out);
}
}
tfree(srffp);
return;
}
static struct gate_instance *create_gate_instance(struct instance_hdr *hdrp)
{
struct gate_instance *gip;
gip = TMALLOC(struct gate_instance, 1);
gip->hdrp = hdrp;
gip->num_gates = 0;
gip->width = 0;
gip->num_ins = 0;
gip->inputs = NULL;
gip->enable = NULL;
gip->num_outs = 0;
gip->outputs = NULL;
gip->tmodel = NULL;
return gip;
}
static struct compound_instance *create_compound_instance(
struct instance_hdr *hdrp)
{
struct compound_instance *ci;
ci = TMALLOC(struct compound_instance, 1);
ci->hdrp = hdrp;
ci->num_gates = 0;
ci->width = 0;
ci->num_ins = 0;
ci->inputs = NULL;
ci->output = NULL;
ci->tmodel = NULL;
return ci;
}
static void delete_compound_instance(struct compound_instance *ci)
{
char **namearr;
int i;
if (!ci) { return; }
if (ci->hdrp) { delete_instance_hdr(ci->hdrp); }
if (ci->num_ins > 0 && ci->inputs) {
namearr = ci->inputs;
for (i = 0; i < ci->num_ins; i++) {
tfree(namearr[i]);
}
tfree(ci->inputs);
}
if (ci->output) { tfree(ci->output); }
if (ci->tmodel) { tfree(ci->tmodel); }
tfree(ci);
return;
}
static void delete_gate_instance(struct gate_instance *gip)
{
char **namearr;
int i;
if (!gip) { return; }
if (gip->hdrp) { delete_instance_hdr(gip->hdrp); }
if (gip->enable) { tfree(gip->enable); }
if (gip->num_ins > 0 && gip->inputs) {
namearr = gip->inputs;
for (i = 0; i < gip->num_ins; i++) {
tfree(namearr[i]);
}
tfree(gip->inputs);
}
if (gip->num_outs > 0 && gip->outputs) {
namearr = gip->outputs;
for (i = 0; i < gip->num_outs; i++) {
tfree(namearr[i]);
}
tfree(gip->outputs);
}
if (gip->tmodel) { tfree(gip->tmodel); }
tfree(gip);
return;
}
static struct instance_hdr *create_instance_header(char *line)
{
char *tok, *p1, *p3, *p4, *endp, *newline, *tmp, *tmp1;
struct instance_hdr *hdr = NULL;
newline = TMALLOC(char, strlen(line) + 1);
(void) memcpy(newline, line, strlen(line) + 1);
hdr = TMALLOC(struct instance_hdr, 1);
hdr->num1 = -1;
hdr->num2 = -1;
/* instance name */
tok = strtok(newline, " \t");
tmp = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(tmp, tok, strlen(tok) + 1);
hdr->instance_name = tmp;
/* instance type */
tok = strtok(NULL, " \t");
p1 = strchr(tok, '(');
if (p1) {
/* ...(n1,n2) or ...(n1) */
tmp = TMALLOC(char, strlen(tok) + 1);
strcpy(tmp, tok);
p4 = strchr(tmp, '(');
*p4 = '\0';
tmp1 = TMALLOC(char, strlen(tmp) + 1);
(void) memcpy(tmp1, tmp, strlen(tmp) + 1);
hdr->instance_type = tmp1;
tfree(tmp);
p3 = strchr(tok, ',');
if (p3) {
hdr->num1 = (int) strtol(p1 + 1, &endp, 10);
hdr->num2 = (int) strtol(p3 + 1, &endp, 10);
} else {
hdr->num1 = (int) strtol(p1 + 1, &endp, 10);
}
} else {
tmp = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(tmp, tok, strlen(tok) + 1);
hdr->instance_type = tmp;
}
tfree(newline);
return hdr;
}
char *new_inverter(char *iname, char *node, Xlatorp xlp)
{
/* Return the name of the output of the new inverter */
/* tfree the returned string after it has been used by the caller */
char *tmp = NULL, *instance_name = NULL, *not_node = NULL;
Xlatep xdata = NULL;
instance_name = tprintf("a%s_%s", iname, node);
not_node = tprintf("not_%s", instance_name);
tmp = tprintf("%s %s %s d_zero_inv99",
instance_name, node, not_node);
/* instantiate the new inverter */
/* e.g. au5_s1bar s1bar not_au5_s1bar d_zero_inv99 */
xdata = create_xlate_translated(tmp);
(void) add_xlator(xlp, xdata);
tfree(tmp);
tfree(instance_name);
tfree(not_node);
/* the name of the inverter output */
tmp = tprintf("not_a%s_%s", iname, node);
return tmp;
}
static BOOL gen_timing_model(
char *tmodel, char *utype, char *xspice, char *newname, Xlatorp xlp)
{
/*
tmodel is the name of the pspice model of type utype.
If the model is found in the model_xlatorp list, the delays are used.
A new xspice model is created using newname and xspice(d_and etc.):
.model <newname> <xspice>[<delays>] where <delays> maybe zero/blank.
The new .model statement is added to the Xlatorp of the translated
xspice instance and model lines (not to be confused with model_xlatorp.
*/
Xlatep xin = NULL, xout = NULL, newdata;
char *s1;
BOOL retval;
if (eq(utype, "ugff")) {
xin = create_xlate_model("", utype, xspice, tmodel);
} else {
xin = create_xlate_model("", utype, "", tmodel);
}
xout = find_in_model_xlator(xin);
if (xout) {
/* Don't delete xout or the model_xlatorp will be corrupted */
//print_xlate(xout);
if (xout->delays && strlen(xout->delays) > 0) {
s1 = tprintf(".model %s %s%s", newname, xspice, xout->delays);
} else {
s1 = tprintf(".model %s %s", newname, xspice);
}
newdata = create_xlate_translated(s1);
tfree(s1);
(void) add_xlator(xlp, newdata);
retval = TRUE;
} else {
retval = FALSE;
}
delete_xlate(xin);
return retval;
}
static Xlatorp gen_dff_instance(struct dff_instance *ip)
{
char *itype, *iname, **darr, **qarr, **qbarr;
char *preb, *clrb, *clk, *tmodel, *qout, *qbout;
int i, num_gates;
char *modelnm, *s1;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!ip) { return NULL; }
itype = ip->hdrp->instance_type;
iname = ip->hdrp->instance_name;
num_gates = ip->num_gates;
darr = ip->d_in;
qarr = ip->q_out;
qbarr = ip->qb_out;
preb = ip->prebar;
clrb = ip->clrbar;
xxp = create_xlator();
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
need_preb_inv = TRUE;
preb = new_inverter(iname, preb, xxp);
}
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
need_clrb_inv = TRUE;
clrb = new_inverter(iname, clrb, xxp);
}
clk = ip->clk;
tmodel = ip->tmodel;
/* model name, same for each dff */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
if (eq(qout, "$d_nc")) {
qout = "NULL";
}
qbout = qbarr[i];
if (eq(qbout, "$d_nc")) {
qbout = "NULL";
}
instance_name = tprintf("a%s_%d", iname, i);
s1 = tprintf( "%s %s %s %s %s %s %s %s",
instance_name, darr[i], clk, preb, clrb, qout, qbout, modelnm
);
xdata = create_xlate_instance(s1, " d_dff", tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(s1);
tfree(instance_name);
}
if (!gen_timing_model(tmodel, "ueff", "d_dff", modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s d_dff\n",
tmodel, modelnm);
}
if (need_preb_inv || need_clrb_inv) {
add_zero_delay_inverter_model = TRUE;
}
if (need_preb_inv) { tfree(preb); }
if (need_clrb_inv) { tfree(clrb); }
tfree(modelnm);
return xxp;
}
static Xlatorp gen_jkff_instance(struct jkff_instance *ip)
{
char *itype, *iname, **jarr, **karr, **qarr, **qbarr;
char *preb, *clrb, *clkb, *tmodel, *qout, *qbout;
int i, num_gates;
char *modelnm, *s1;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!ip) { return NULL; }
itype = ip->hdrp->instance_type;
iname = ip->hdrp->instance_name;
num_gates = ip->num_gates;
jarr = ip->j_in;
karr = ip->k_in;
qarr = ip->q_out;
qbarr = ip->qb_out;
preb = ip->prebar;
clrb = ip->clrbar;
xxp = create_xlator();
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
need_preb_inv = TRUE;
preb = new_inverter(iname, preb, xxp);
}
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
need_clrb_inv = TRUE;
clrb = new_inverter(iname, clrb, xxp);
}
/* require a positive edge clock */
clkb = ip->clkbar;
clkb = new_inverter(iname, clkb, xxp);
tmodel = ip->tmodel;
/* model name, same for each jkff */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
if (eq(qout, "$d_nc")) {
qout = "NULL";
}
qbout = qbarr[i];
if (eq(qbout, "$d_nc")) {
qbout = "NULL";
}
instance_name = tprintf("a%s_%d", iname, i);
s1 = tprintf("%s %s %s %s %s %s %s %s %s",
instance_name, jarr[i], karr[i], clkb, preb, clrb,
qout, qbout, modelnm
);
xdata = create_xlate_instance(s1, " d_jkff", tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(s1);
tfree(instance_name);
}
if (!gen_timing_model(tmodel, "ueff", "d_jkff", modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s d_jkff\n",
tmodel, modelnm);
}
add_zero_delay_inverter_model = TRUE;
tfree(clkb);
if (need_preb_inv) { tfree(preb); }
if (need_clrb_inv) { tfree(clrb); }
tfree(modelnm);
return xxp;
}
static Xlatorp gen_dltch_instance(struct dltch_instance *ip)
{
char *itype, *iname, **darr, **qarr, **qbarr;
char *preb, *clrb, *gate, *tmodel, *qout, *qbout;
int i, num_gates;
char *modelnm, *s1, *s2, *s3;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!ip) { return NULL; }
itype = ip->hdrp->instance_type;
iname = ip->hdrp->instance_name;
num_gates = ip->num_gates;
darr = ip->d_in;
qarr = ip->q_out;
qbarr = ip->qb_out;
preb = ip->prebar;
clrb = ip->clrbar;
xxp = create_xlator();
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
need_preb_inv = TRUE;
preb = new_inverter(iname, preb, xxp);
}
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
need_clrb_inv = TRUE;
clrb = new_inverter(iname, clrb, xxp);
}
gate = ip->gate;
tmodel = ip->tmodel;
/* model name, same for each latch */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
instance_name = tprintf("a%s_%d", iname, i);
if (eq(qout, "$d_nc")) {
/* NULL not allowed??? */
s1 = tprintf("%s %s %s %s %s nco_%s_%d",
instance_name, darr[i], gate, preb, clrb, iname, i);
} else {
s1 = tprintf("%s %s %s %s %s %s",
instance_name, darr[i], gate, preb, clrb, qout);
}
qbout = qbarr[i];
if (eq(qbout, "$d_nc")) {
/* NULL not allowed??? */
s2 = tprintf(" ncn_%s_%d %s", iname, i, modelnm);
} else {
s2 = tprintf(" %s %s", qbout, modelnm);
}
s3 = tprintf("%s%s", s1, s2);
xdata = create_xlate_instance(s3, " d_dlatch", tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(s1);
tfree(s2);
tfree(s3);
tfree(instance_name);
}
if (!gen_timing_model(tmodel, "ugff", "d_dlatch", modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s d_dlatch\n",
tmodel, modelnm);
}
if (need_preb_inv || need_clrb_inv) {
add_zero_delay_inverter_model = TRUE;
}
if (need_preb_inv) { tfree(preb); }
if (need_clrb_inv) { tfree(clrb); }
tfree(modelnm);
return xxp;
}
static Xlatorp gen_srff_instance(struct srff_instance *srffp)
{
char *itype, *iname, **sarr, **rarr, **qarr, **qbarr;
char *preb, *clrb, *gate, *tmodel, *qout, *qbout;
int i, num_gates;
char *modelnm, *s1, *s2, *s3;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!srffp) { return NULL; }
itype = srffp->hdrp->instance_type;
iname = srffp->hdrp->instance_name;
num_gates = srffp->num_gates;
sarr = srffp->s_in;
rarr = srffp->r_in;
qarr = srffp->q_out;
qbarr = srffp->qb_out;
preb = srffp->prebar;
clrb = srffp->clrbar;
xxp = create_xlator();
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
need_preb_inv = TRUE;
preb = new_inverter(iname, preb, xxp);
}
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
need_clrb_inv = TRUE;
clrb = new_inverter(iname, clrb, xxp);
}
gate = srffp->gate;
tmodel = srffp->tmodel;
/* model name, same for each latch */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
instance_name = tprintf("a%s_%d", iname, i);
if (eq(qout, "$d_nc")) {
/* NULL not allowed??? */
s1 = tprintf("%s %s %s %s %s %s nco_%s_%d",
instance_name, sarr[i], rarr[i], gate, preb, clrb, iname, i);
} else {
s1 = tprintf("%s %s %s %s %s %s %s",
instance_name, sarr[i], rarr[i], gate, preb, clrb, qout);
}
qbout = qbarr[i];
if (eq(qbout, "$d_nc")) {
/* NULL not allowed??? */
s2 = tprintf(" ncn_%s_%d %s", iname, i, modelnm);
} else {
s2 = tprintf(" %s %s", qbout, modelnm);
}
s3 = tprintf("%s%s", s1, s2);
xdata = create_xlate_instance(s3, " d_srlatch", tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(s1);
tfree(s2);
tfree(s3);
tfree(instance_name);
}
if (!gen_timing_model(tmodel, "ugff", "d_srlatch", modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s d_srlatch\n",
tmodel, modelnm);
}
if (need_preb_inv || need_clrb_inv) {
add_zero_delay_inverter_model = TRUE;
}
if (need_preb_inv) { tfree(preb); }
if (need_clrb_inv) { tfree(clrb); }
tfree(modelnm);
return xxp;
}
static Xlatorp gen_compound_instance(struct compound_instance *compi)
{
char **inarr, *itype, *output, *tmodel;
char *outgate = NULL, *ingates = NULL, *logic_val = NULL;
int i, j, k, width, num_gates;
int num_ins_kept = 0;
char *model_name = NULL, *inst = NULL, **connector = NULL;
char *new_inst = NULL, *model_stmt = NULL, *final_model_name = NULL;
char *new_stmt = NULL, *instance_name = NULL;
char *tmp;
size_t sz = 0;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
if (!compi) { return NULL; }
itype = compi->hdrp->instance_type;
inst = compi->hdrp->instance_name;
if (eq(itype, "aoi")) {
outgate = "d_nor";
ingates = "d_and";
logic_val = "$d_hi";
} else if (eq(itype, "ao")) {
outgate = "d_or";
ingates = "d_and";
logic_val = "$d_hi";
} else if (eq(itype, "oai")) {
outgate = "d_nand";
ingates = "d_or";
logic_val = "$d_lo";
} else if (eq(itype, "oa")) {
outgate = "d_and";
ingates = "d_or";
logic_val = "$d_lo";
} else {
return NULL;
}
inarr = compi->inputs;
width = compi->width;
num_gates = compi->num_gates;
output = compi->output;
tmodel = compi->tmodel;
model_name = tprintf("d_%s_%s", inst, itype);
connector = TMALLOC(char *, num_gates);
xxp = create_xlator();
k = 0;
for (i = 0; i < num_gates; i++) {
for (j = 0; j < width; j++) {
sz += strlen(inarr[k]) + 8; // Room for space between each name
k++;
}
}
tmp = TMALLOC(char, sz);
tmp[0] = '\0';
k = 0;
for (i = 0; i < num_gates; i++) {
connector[i] = tprintf("con_%s_%d", inst, i);
num_ins_kept = 0;
tmp[0] = '\0';
/* $d_hi AND gate inputs are ignored */
/* $d_lo OR gate inputs are ignored */
for (j = 0; j < width; j++) {
if (!eq(inarr[k], logic_val)) {
num_ins_kept++;
sprintf(tmp + strlen(tmp), " %s", inarr[k]);
}
k++;
}
if (num_ins_kept >= 2) {
instance_name = tprintf("a%s_%d", inst, i);
new_inst = tprintf("%s [%s ] %s %s", instance_name,
tmp, connector[i], model_name);
xdata = create_xlate_translated(new_inst);
xxp = add_xlator(xxp, xdata);
tfree(new_inst);
tfree(instance_name);
} else if (num_ins_kept == 1) {
/*
connector[i] is the remaining input connected
directly to the OR/NOR, AND/NAND final gate.
*/
tfree(connector[i]);
connector[i] = tprintf("%s", tmp);
}
}
/* .model statement for the input gates */
model_stmt = tprintf(".model %s %s", model_name, ingates);
xdata = create_xlate_translated(model_stmt);
xxp = add_xlator(xxp, xdata);
tfree(model_stmt);
/* Final OR/NOR, AND/NAND gate */
final_model_name = tprintf("%s_out", model_name);
tfree(tmp);
sz = 0;
for (i = 0; i < num_gates; i++) {
sz += strlen(connector[i]) + 8; // Room for space between each name
}
tmp = TMALLOC(char, sz);
tmp[0] = '\0';
for (i = 0; i < num_gates; i++) {
sprintf(tmp + strlen(tmp), " %s", connector[i]);
}
/* instance statement for the final gate */
instance_name = tprintf("a%s_out", inst);
new_stmt = tprintf("%s [%s ] %s %s",
instance_name, tmp, output, final_model_name);
xdata = create_xlate_translated(new_stmt);
xxp = add_xlator(xxp, xdata);
tfree(new_stmt);
tfree(instance_name);
tfree(tmp);
/* timing model for output gate */
if (!gen_timing_model(tmodel, "ugate", outgate,
final_model_name, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, final_model_name, outgate);
}
tfree(final_model_name);
for (i = 0; i < num_gates; i++) {
if (connector[i]) { tfree(connector[i]); }
}
if (connector) { tfree(connector); }
tfree(model_name);
return xxp;
}
static Xlatorp gen_gate_instance(struct gate_instance *gip)
{
char **inarr, **outarr, *itype, *iname, *enable, *tmodel;
char *xspice = NULL, *connector = NULL;
BOOL vector = FALSE, tristate_gate = FALSE, simple_gate = FALSE;
BOOL tristate_array = FALSE, simple_array = FALSE;
BOOL add_tristate = FALSE;
char *modelnm = NULL, *startvec = NULL, *endvec = NULL;
char *input_buf = NULL, *instance_name = NULL;
int i, j, k, width, num_gates, num_ins, num_outs;
size_t sz;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
if (!gip) { return NULL; }
itype = gip->hdrp->instance_type;
iname = gip->hdrp->instance_name;
inarr = gip->inputs;
outarr = gip->outputs;
width = gip->width;
num_gates = gip->num_gates;
num_ins = gip->num_ins;
num_outs = gip->num_outs;
enable = gip->enable;
tmodel = gip->tmodel;
vector = has_vector_inputs(itype);
if (num_gates == 1) {
char *inst_begin = NULL;
simple_gate = is_gate(itype);
tristate_gate = is_tristate(itype);
if (!simple_gate && !tristate_gate) { return NULL; }
add_tristate = FALSE;
if (simple_gate) {
xspice = find_xspice_for_delay(itype);
} else if (tristate_gate) {
xspice = find_xspice_for_delay(itype);
if (!eq(itype, "buf3")) {
add_tristate = TRUE;
}
}
xxp = create_xlator();
/* Now build the instance name and inputs section */
if (vector) {
startvec = "[";
endvec = " ]";
} else {
startvec = "";
endvec = "";
}
/* inputs */
/* First calculate the space */
sz = 0;
for (i = 0; i < width; i++) {
sz += strlen(inarr[i]) + 4; // Extra 4 spaces separating
}
input_buf = TMALLOC(char, sz);
input_buf[0] = '\0';
for (i = 0; i < width; i++) {
sprintf(input_buf + strlen(input_buf), " %s", inarr[i]);
}
/* instance name and inputs */
/* add the tristate enable if required on original */
if (enable) {
if (!add_tristate) {
/* Warning: changing the format string affects input_buf sz */
inst_begin = tprintf("a%s %s%s%s %s",
iname, startvec, input_buf, endvec, enable);
} else {
/* Warning: changing the format string affects input_buf sz */
inst_begin = tprintf("a%s %s%s%s",
iname, startvec, input_buf, endvec);
}
} else {
/* Warning: changing the format string affects input_buf sz */
inst_begin = tprintf("a%s %s%s%s",
iname, startvec, input_buf, endvec);
}
tfree(input_buf);
/* connector if required for tristate */
connector = tprintf("con_a%s_%s", iname, outarr[0]);
/* keep a copy of the model name of original gate */
modelnm = tprintf("d_a%s_%s", iname, itype);
if (!add_tristate) {
char *instance_stmt = NULL;
/* add output + model name => translated instance */
instance_stmt = tprintf("%s %s %s",
inst_begin, outarr[0], modelnm);
xdata = create_xlate_instance(instance_stmt,
xspice, tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(instance_stmt);
if (simple_gate) {
if (!gen_timing_model(tmodel, "ugate", xspice,
modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, modelnm, xspice);
}
} else { /* must be trstate gate buf3 */
if (!gen_timing_model(tmodel, "utgate", xspice,
modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, modelnm, xspice);
}
}
} else {
char *new_model_nm = NULL;
char *new_stmt = NULL;
/*
Use connector as original gate output and tristate input;
tristate has original gate output and utgate delay;
original gate has zero delay timing model.
Complete the translation of the original gate adding
the connector as output + model name.
*/
new_stmt = tprintf("%s %s %s", inst_begin, connector, modelnm);
xdata = create_xlate_instance(new_stmt, xspice, "", modelnm);
xxp = add_xlator(xxp, xdata);
tfree(new_stmt);
/* new model statement e.g. .model d_au2nand3 d_nand */
new_stmt = tprintf(".model %s %s", modelnm, xspice);
xdata = create_xlate_translated(new_stmt);
xxp = add_xlator(xxp, xdata);
tfree(new_stmt);
/* now the added tristate */
/* model name of added tristate */
new_model_nm = tprintf("d_a%s_tribuf", iname);
new_stmt = tprintf("a%s_tri %s %s %s %s",
iname, connector, enable, outarr[0], new_model_nm);
xdata = create_xlate_instance(new_stmt, "d_tristate",
tmodel, new_model_nm);
xxp = add_xlator(xxp, xdata);
tfree(new_stmt);
if (!gen_timing_model(tmodel, "utgate", "d_tristate",
new_model_nm, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, new_model_nm, xspice);
}
tfree(new_model_nm);
}
tfree(connector);
tfree(modelnm);
tfree(inst_begin);
return xxp;
} else {
char *primary_model = NULL, *s1 = NULL, *s2 = NULL, *s3 = NULL;
int ksave;
/* arrays of gates */
/* NOTE (n)and3a, (n)or3a, (n)xor3a types are not supported */
simple_array = is_gate_array(itype);
tristate_array = is_tristate_array(itype);
add_tristate = FALSE;
if (simple_array) {
xspice = find_xspice_for_delay(itype);
} else if (tristate_array) {
xspice = find_xspice_for_delay(itype);
if (eq("inv3a", itype)) {
add_tristate = TRUE;
} else if (!eq(itype, "buf3a")) {
return NULL;
}
}
xxp = create_xlator();
k = 0;
connector = NULL;
if (vector) {
startvec = "[";
endvec = " ]";
} else {
startvec = "";
endvec = "";
}
/* model name, same for all primary gates */
primary_model = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
/* inputs */
/* First calculate the space */
ksave = k;
sz = 0;
for (j = 0; j < width; j++) {
/* inputs for primary gate */
sz += strlen(inarr[k]) + 4; // Extra 4 spaces separating
k++;
}
k = ksave;
input_buf = TMALLOC(char, sz);
input_buf[0] = '\0';
for (j = 0; j < width; j++) {
/* inputs for primary gate */
/* Warning: changing the format string affects input_buf sz */
sprintf(input_buf + strlen(input_buf), " %s", inarr[k]);
k++;
}
/* create new instance name for primary gate */
if (enable) {
if (!add_tristate) {
s1 = tprintf("a%s_%d %s%s%s %s",
iname, i, startvec, input_buf, endvec, enable);
} else {
s1 = tprintf("a%s_%d %s%s%s",
iname, i, startvec, input_buf, endvec);
/* connector if required for tristate */
connector = tprintf("con_a%s_%d_%s", iname, i, outarr[i]);
}
} else {
s1 = tprintf("a%s_%d %s%s%s",
iname, i, startvec, input_buf, endvec);
}
tfree(input_buf);
/* output of primary gate */
if (add_tristate) {
s2 = tprintf(" %s %s", connector, primary_model);
} else {
s2 = tprintf(" %s %s", outarr[i], primary_model);
}
/* translated instance */
s3 = tprintf("%s%s", s1, s2);
if (add_tristate) {
xdata = create_xlate_instance(s3, xspice, "", primary_model);
xxp = add_xlator(xxp, xdata);
} else {
xdata = create_xlate_instance(s3, xspice, tmodel,
primary_model);
xxp = add_xlator(xxp, xdata);
}
tfree(s1);
tfree(s2);
tfree(s3);
if (!add_tristate) {
if (tristate_array) {
if (i == 0 && !gen_timing_model(tmodel, "utgate",
xspice, primary_model, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, primary_model, xspice);
}
} else {
if (i == 0 && !gen_timing_model(tmodel, "ugate",
xspice, primary_model, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, primary_model, xspice);
}
}
}
if (add_tristate) {
char *s1 = NULL, *modelnm = NULL;
if (i == 0) {
/* Zero delay model for all original array instances */
s1 = tprintf(".model %s %s", primary_model, xspice);
xdata = create_xlate_translated(s1);
xxp = add_xlator(xxp, xdata);
tfree(s1);
}
/* model name of added tristate */
modelnm = tprintf("d_a%s_tribuf", iname);
/*
instance name of added tristate, connector,
enable, original primary gate output, timing model.
*/
instance_name = tprintf("a%s_%d_tri", iname, i);
s1 = tprintf("%s %s %s %s %s", instance_name, connector,
enable, outarr[i], modelnm);
xdata = create_xlate_instance(s1, "d_tristate",
tmodel, modelnm);
xxp = add_xlator(xxp, xdata);
tfree(s1);
tfree(instance_name);
if (i == 0 && !gen_timing_model(tmodel, "utgate",
"d_tristate", modelnm, xxp)) {
printf("WARNING unable to find tmodel %s for %s %s\n",
tmodel, modelnm, "d_tristate");
}
tfree(modelnm);
tfree(connector);
}
}
tfree(primary_model);
return xxp;
}
return NULL;
}
static void extract_model_param(char *rem, char *pname, char *buf)
{
char *p1, *p2, *p3;
p1 = strstr(rem, pname);
if (p1) {
p2 = strchr(p1, '=');
if (isspace(p2[1])) {
p3 = skip_ws(&p2[1]);
} else {
p3 = &p2[1];
}
while (!isspace(p3[0]) && p3[0] != ')') {
*buf = p3[0];
buf++;
p3++;
}
*buf = '\0';
} else {
buf[0] = '\0';
}
}
static void delete_timing_data(struct timing_data *tdp)
{
if (!tdp) { return; }
if (tdp->min) { tfree(tdp->min); }
if (tdp->typ) { tfree(tdp->typ); }
if (tdp->max) { tfree(tdp->max); }
if (tdp->ave) { tfree(tdp->ave); }
tfree(tdp);
return;
}
static struct timing_data *create_min_typ_max(char *prefix, char *rem)
{
char *mntymxstr;
char *buf, *bufsave;
size_t n = strlen(prefix) + 4;
struct timing_data *tdp = NULL;
tdp = TMALLOC(struct timing_data, 1);
mntymxstr = TMALLOC(char, n);
buf = TMALLOC(char, strlen(rem) + 1);
bufsave = buf;
tdp->ave = NULL;
tdp->estimate = EST_UNK;
strcpy(mntymxstr, prefix);
strcat(mntymxstr, "mn=");
extract_model_param(rem, mntymxstr, buf);
tdp->min = NULL;
if (bufsave[0]) {
tdp->min = TMALLOC(char, strlen(bufsave) + 1);
(void) memcpy(tdp->min, bufsave, strlen(bufsave) + 1);
}
buf = bufsave;
strcpy(mntymxstr, prefix);
strcat(mntymxstr, "ty=");
extract_model_param(rem, mntymxstr, buf);
tdp->typ = NULL;
if (bufsave[0]) {
tdp->typ = TMALLOC(char, strlen(bufsave) + 1);
(void) memcpy(tdp->typ, bufsave, strlen(bufsave) + 1);
}
buf = bufsave;
strcpy(mntymxstr, prefix);
strcat(mntymxstr, "mx=");
extract_model_param(rem, mntymxstr, buf);
tdp->max = NULL;
if (bufsave[0]) {
tdp->max = TMALLOC(char, strlen(bufsave) + 1);
(void) memcpy(tdp->max, bufsave, strlen(bufsave) + 1);
}
tfree(bufsave);
tfree(mntymxstr);
return tdp;
}
static void estimate_typ(struct timing_data *tdp)
{
char *tmpmax = NULL, *tmpmin = NULL;
char *min, *typ, *max;
float valmin, valmax, average;
char *units1, *units2;
if (!tdp) { return; }
min = tdp->min;
typ = tdp->typ;
max = tdp->max;
if (typ && strlen(typ) > 0 && typ[0] != '-') {
tdp->estimate = EST_TYP;
return;
}
if (max && strlen(max) > 0 && max[0] != '-') {
tmpmax = max;
}
if (min && strlen(min) > 0 && min[0] != '-') {
tmpmin = min;
}
if (tmpmin && tmpmax) {
if (strlen(tmpmin) > 0 && strlen(tmpmax) > 0) {
valmin = strtof(tmpmin, &units1);
valmax = strtof(tmpmax, &units2);
average = (valmin + valmax) / 2.0;
tdp->ave = tprintf("%.2f%s", average, units2);
if (!eq(units1, units2)) {
printf("WARNING units do not match\n");
}
tdp->estimate = EST_AVE;
return;
}
} else if (tmpmax && strlen(tmpmax) > 0) {
tdp->estimate = EST_MAX;
return;
} else if (tmpmin && strlen(tmpmin) > 0) {
tdp->estimate = EST_MIN;
return;
} else {
tdp->estimate = EST_UNK;
return;
}
tdp->estimate = EST_UNK;
return;
}
static char *get_estimate(struct timing_data *tdp)
{
/*
Call after estimate_typ.
Don't call delete_timing_data until you have copied
or finished with this return value.
*/
if (!tdp) { return NULL; }
switch (tdp->estimate) {
case EST_MIN: return tdp->min;
case EST_TYP: return tdp->typ;
case EST_MAX: return tdp->max;
case EST_AVE: return tdp->ave;
default: break;
}
return NULL;
}
/* NOTE
The get_delays_...() functions calculate estimates of typical delays
from the Pspice ugate, utgate, ueff, and ugff timing models.
These functions are called from u_process_model(), and the delay strings
are added to the timing model Xlator by add_delays_to_model_xlator().
*/
static char *get_delays_ugate(char *rem)
{
char *rising, *falling, *delays = NULL;
struct timing_data *tdp1, *tdp2;
tdp1 = create_min_typ_max("tplh", rem);
estimate_typ(tdp1);
rising = get_estimate(tdp1);
tdp2 = create_min_typ_max("tphl", rem);
estimate_typ(tdp2);
falling = get_estimate(tdp2);
if (rising && falling) {
if (strlen(rising) > 0 && strlen(falling) > 0) {
delays = tprintf("(rise_delay = %s fall_delay = %s)",
rising, falling);
}
}
delete_timing_data(tdp1);
delete_timing_data(tdp2);
return delays;
}
static char *get_delays_utgate(char *rem)
{
/* Return estimate of tristate delay (delay = val3) */
char *rising, *falling, *delays = NULL;
struct timing_data *tdp1, *tdp2;
tdp1 = create_min_typ_max("tplh", rem);
estimate_typ(tdp1);
rising = get_estimate(tdp1);
tdp2 = create_min_typ_max("tphl", rem);
estimate_typ(tdp2);
falling = get_estimate(tdp2);
if (rising && falling) {
if (strlen(rising) > 0 && strlen(falling) > 0) {
delays = tprintf("(delay = %s)", rising);
}
}
delete_timing_data(tdp1);
delete_timing_data(tdp2);
return delays;
}
static char *get_delays_ueff(char *rem)
{
char *delays = NULL;
char *clkqrise, *clkqfall, *pcqrise, *pcqfall;
char *clkd, *setd, *resetd;
struct timing_data *tdp1, *tdp2, *tdp3, *tdp4;
tdp1 = create_min_typ_max("tpclkqlh", rem);
estimate_typ(tdp1);
clkqrise = get_estimate(tdp1);
tdp2 = create_min_typ_max("tpclkqhl", rem);
estimate_typ(tdp2);
clkqfall = get_estimate(tdp2);
tdp3 = create_min_typ_max("tppcqlh", rem);
estimate_typ(tdp3);
pcqrise = get_estimate(tdp3);
tdp4 = create_min_typ_max("tppcqhl", rem);
estimate_typ(tdp4);
pcqfall = get_estimate(tdp4);
clkd = NULL;
if (clkqrise && strlen(clkqrise) > 0) {
clkd = clkqrise;
} else if (clkqfall && strlen(clkqfall) > 0) {
clkd = clkqfall;
}
setd = NULL;
resetd = NULL;
if (pcqrise && strlen(pcqrise) > 0) {
setd = resetd = pcqrise;
} else if (pcqfall && strlen(pcqfall) > 0) {
setd = resetd = pcqfall;
}
if (clkd && setd) {
delays = tprintf("(clk_delay = %s "
"set_delay = %s reset_delay = %s "
"rise_delay = 1.0ns fall_delay = 2.0ns)",
clkd, setd, resetd);
} else if (clkd) {
delays = tprintf("(clk_delay = %s "
"rise_delay = 1.0ns fall_delay = 2.0ns)",
clkd);
} else if (setd) {
delays = tprintf("(set_delay = %s reset_delay = %s "
"rise_delay = 1.0ns fall_delay = 2.0ns)",
setd, resetd);
} else {
delays = tprintf("(rise_delay = 1.0ns fall_delay = 2.0ns)");
}
delete_timing_data(tdp1);
delete_timing_data(tdp2);
delete_timing_data(tdp3);
delete_timing_data(tdp4);
return delays;
}
static char *get_delays_ugff(char *rem, char *d_name)
{
char *delays = NULL, *dname;
char *tpdqlh, *tpdqhl, *tpgqlh, *tpgqhl, *tppcqlh, *tppcqhl;
char *d_delay, *enab, *setd, *resetd;
char *s1, *s2;
struct timing_data *tdp1, *tdp2, *tdp3, *tdp4, *tdp5, *tdp6;
if (eq(d_name, "d_dlatch")) {
dname = "data_delay";
} else if (eq(d_name, "d_srlatch")) {
dname = "sr_delay";
} else {
return NULL;
}
tdp1 = create_min_typ_max("tpdqlh", rem);
estimate_typ(tdp1);
tpdqlh = get_estimate(tdp1);
tdp2 = create_min_typ_max("tpdqhl", rem);
estimate_typ(tdp2);
tpdqhl = get_estimate(tdp2);
tdp3 = create_min_typ_max("tpgqlh", rem);
estimate_typ(tdp3);
tpgqlh = get_estimate(tdp3);
tdp4 = create_min_typ_max("tpgqhl", rem);
estimate_typ(tdp4);
tpgqhl = get_estimate(tdp4);
tdp5 = create_min_typ_max("tppcqlh", rem);
estimate_typ(tdp5);
tppcqlh = get_estimate(tdp5);
tdp6 = create_min_typ_max("tppcqhl", rem);
estimate_typ(tdp6);
tppcqhl = get_estimate(tdp6);
d_delay = NULL;
if (tpdqlh && strlen(tpdqlh) > 0) {
d_delay = tpdqlh;
} else if (tpdqhl && strlen(tpdqhl) > 0) {
d_delay = tpdqhl;
}
enab = NULL;
if (tpgqlh && strlen(tpgqlh) > 0) {
enab = tpgqlh;
} else if (tpgqhl && strlen(tpgqhl) > 0) {
enab = tpgqhl;
}
s1 = NULL;
if (enab) {
if (d_delay) {
s1 = tprintf("%s = %s enable_delay = %s ",
dname, d_delay, enab);
} else {
s1 = tprintf("enable_delay = %s ", enab);
}
} else {
if (d_delay) {
s1 = tprintf("%s = %s ", dname, d_delay);
}
}
setd = NULL;
resetd = NULL;
if (tppcqlh && strlen(tppcqlh) > 0) {
setd = resetd = tppcqlh;
} else if (tppcqhl && strlen(tppcqhl) > 0) {
setd = resetd = tppcqhl;
}
if (setd) {
s2 = tprintf("set_delay = %s reset_delay = %s "
"rise_delay = 1.0ns fall_delay = 2.0ns)",
setd, resetd);
} else {
s2 = tprintf("rise_delay = 1.0ns fall_delay = 2.0ns)");
}
if (s1) {
delays = tprintf("(%s%s", s1, s2);
tfree(s1);
} else {
delays = tprintf("(%s", s2);
}
tfree(s2);
delete_timing_data(tdp1);
delete_timing_data(tdp2);
delete_timing_data(tdp3);
delete_timing_data(tdp4);
delete_timing_data(tdp5);
delete_timing_data(tdp6);
return delays;
}
static BOOL u_process_model(char *nline, char *original)
{
char *tok, *remainder, *delays = NULL, *utype, *tmodel;
BOOL retval = TRUE;
/* .model */
tok = strtok(nline, " \t");
/* model name */
tok = strtok(NULL, " \t");
tmodel = TMALLOC(char, strlen(tok) + 1);
memcpy(tmodel, tok, strlen(tok) + 1);
/* model utype */
tok = strtok(NULL, " \t(");
utype = TMALLOC(char, strlen(tok) + 1);
memcpy(utype, tok, strlen(tok) + 1);
/* delay info */
remainder = strchr(original, '(');
if (remainder) {
if (eq(utype, "ugate")) {
delays = get_delays_ugate(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (delays) { tfree(delays); }
} else if (eq(utype, "utgate")) {
delays = get_delays_utgate(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (delays) { tfree(delays); }
} else if (eq(utype, "ueff")) {
delays = get_delays_ueff(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (delays) { tfree(delays); }
} else if (eq(utype, "ugff")) {
delays = get_delays_ugff(remainder, "d_dlatch");
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_dlatch", tmodel);
if (delays) { tfree(delays); }
delays = get_delays_ugff(remainder, "d_srlatch");
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_srlatch", tmodel);
if (delays) { tfree(delays); }
} else {
retval = FALSE;
delays = NULL;
}
} else {
retval = FALSE;
}
tfree(tmodel);
tfree(utype);
return retval;
}
static struct dff_instance *add_dff_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline;
char *name, **arrp;
int i, num_gates = hdr->num1;
struct dff_instance *dffip = NULL;
dffip = create_dff_instance(hdr);
dffip->num_gates = num_gates;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/* prebar, clrbar, clk */
tok = strtok(copyline, " \t");
dffip->prebar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dffip->prebar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
dffip->clrbar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dffip->clrbar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
dffip->clk = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dffip->clk, tok, strlen(tok) + 1);
/* d inputs */
dffip->d_in = TMALLOC(char *, num_gates);
arrp = dffip->d_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* q_out outputs */
dffip->q_out = TMALLOC(char *, num_gates);
arrp = dffip->q_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* qb_out outputs */
dffip->qb_out = TMALLOC(char *, num_gates);
arrp = dffip->qb_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* timing model */
tok = strtok(NULL, " \t");
dffip->tmodel = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dffip->tmodel, tok, strlen(tok) + 1);
tfree(copyline);
/* Reject incompatible inputs */
arrp = dffip->d_in;
for (i = 0; i < num_gates; i++) {
if (strncmp(arrp[i], "$d_", 3) == 0) {
tfree(dffip);
return NULL;
}
}
if (eq(dffip->prebar, "$d_lo") || eq(dffip->prebar, "$d_nc")) {
tfree(dffip);
return NULL;
}
if (eq(dffip->clrbar, "$d_lo") || eq(dffip->clrbar, "$d_nc")) {
tfree(dffip);
return NULL;
}
return dffip;
}
static struct dltch_instance *add_dltch_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline;
char *name, **arrp;
int i, num_gates = hdr->num1;
struct dltch_instance *dlp = NULL;
dlp = create_dltch_instance(hdr);
dlp->num_gates = num_gates;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/* prebar, clrbar, clk */
tok = strtok(copyline, " \t");
dlp->prebar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dlp->prebar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
dlp->clrbar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dlp->clrbar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
dlp->gate = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dlp->gate, tok, strlen(tok) + 1);
/* d inputs */
dlp->d_in = TMALLOC(char *, num_gates);
arrp = dlp->d_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* q_out outputs */
dlp->q_out = TMALLOC(char *, num_gates);
arrp = dlp->q_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* qb_out outputs */
dlp->qb_out = TMALLOC(char *, num_gates);
arrp = dlp->qb_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* timing model */
tok = strtok(NULL, " \t");
dlp->tmodel = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(dlp->tmodel, tok, strlen(tok) + 1);
tfree(copyline);
/* Reject incompatible inputs */
arrp = dlp->d_in;
for (i = 0; i < num_gates; i++) {
if (strncmp(arrp[i], "$d_", 3) == 0) {
tfree(dlp);
return NULL;
}
}
if (strncmp(dlp->gate, "$d_", 3) == 0) {
tfree(dlp);
return NULL;
}
if (eq(dlp->prebar, "$d_lo") || eq(dlp->prebar, "$d_nc")) {
tfree(dlp);
return NULL;
}
if (eq(dlp->clrbar, "$d_lo") || eq(dlp->clrbar, "$d_nc")) {
tfree(dlp);
return NULL;
}
return dlp;
}
static struct jkff_instance *add_jkff_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline;
char *name, **arrp, **arrpk;
int i, num_gates = hdr->num1;
struct jkff_instance *jkffip = NULL;
jkffip = create_jkff_instance(hdr);
jkffip->num_gates = num_gates;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/* prebar, clrbar, clkbar */
tok = strtok(copyline, " \t");
jkffip->prebar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(jkffip->prebar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
jkffip->clrbar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(jkffip->clrbar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
jkffip->clkbar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(jkffip->clkbar, tok, strlen(tok) + 1);
/* j inputs */
jkffip->j_in = TMALLOC(char *, num_gates);
arrp = jkffip->j_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* k inputs */
jkffip->k_in = TMALLOC(char *, num_gates);
arrp = jkffip->k_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* q_out outputs */
jkffip->q_out = TMALLOC(char *, num_gates);
arrp = jkffip->q_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* qb_out outputs */
jkffip->qb_out = TMALLOC(char *, num_gates);
arrp = jkffip->qb_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* timing model */
tok = strtok(NULL, " \t");
jkffip->tmodel = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(jkffip->tmodel, tok, strlen(tok) + 1);
tfree(copyline);
/* Reject incompatible inputs */
arrp = jkffip->j_in;
arrpk = jkffip->k_in;
for (i = 0; i < num_gates; i++) {
if (strncmp(arrp[i], "$d_", 3) == 0 ||
strncmp(arrpk[i], "$d_", 3) == 0) {
tfree(jkffip);
return NULL;
}
}
if (eq(jkffip->prebar, "$d_lo") || eq(jkffip->prebar, "$d_nc")) {
tfree(jkffip);
return NULL;
}
if (eq(jkffip->clrbar, "$d_lo") || eq(jkffip->clrbar, "$d_nc")) {
tfree(jkffip);
return NULL;
}
return jkffip;
}
static struct srff_instance *add_srff_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline;
char *name, **arrp, **arrpr;
int i, num_gates = hdr->num1;
struct srff_instance *srffp = NULL;
srffp = create_srff_instance(hdr);
srffp->num_gates = num_gates;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/* prebar, clrbar, gate */
tok = strtok(copyline, " \t");
srffp->prebar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(srffp->prebar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
srffp->clrbar = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(srffp->clrbar, tok, strlen(tok) + 1);
tok = strtok(NULL, " \t");
srffp->gate = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(srffp->gate, tok, strlen(tok) + 1);
/* s inputs */
srffp->s_in = TMALLOC(char *, num_gates);
arrp = srffp->s_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* r inputs */
srffp->r_in = TMALLOC(char *, num_gates);
arrp = srffp->r_in;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* q_out outputs */
srffp->q_out = TMALLOC(char *, num_gates);
arrp = srffp->q_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* qb_out outputs */
srffp->qb_out = TMALLOC(char *, num_gates);
arrp = srffp->qb_out;
for (i = 0; i < num_gates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
arrp[i] = name;
}
/* timing model */
tok = strtok(NULL, " \t");
srffp->tmodel = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(srffp->tmodel, tok, strlen(tok) + 1);
tfree(copyline);
/* Reject incompatible inputs */
arrp = srffp->s_in;
arrpr = srffp->r_in;
for (i = 0; i < num_gates; i++) {
if (strncmp(arrp[i], "$d_", 3) == 0 ||
strncmp(arrpr[i], "$d_", 3) == 0) {
tfree(srffp);
return NULL;
}
}
if (strncmp(srffp->gate, "$d_", 3) == 0) {
tfree(srffp);
return NULL;
}
if (eq(srffp->prebar, "$d_lo") || eq(srffp->prebar, "$d_nc")) {
tfree(srffp);
return NULL;
}
if (eq(srffp->clrbar, "$d_lo") || eq(srffp->clrbar, "$d_nc")) {
tfree(srffp);
return NULL;
}
return srffp;
}
static struct compound_instance *add_compound_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline, *itype = hdr->instance_type, *name;
int i, j, k, n1 =hdr->num1, n2 = hdr->num2, inwidth, numgates;
struct compound_instance *compi;
char **inarr;
BOOL first = TRUE;
if (is_compound_gate(itype)) {
inwidth = n1;
numgates = n2;
} else {
return NULL;
}
compi = create_compound_instance(hdr);
compi->num_gates = numgates;
compi->width = inwidth;
compi->num_ins = numgates * inwidth;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
inarr = TMALLOC(char *, compi->num_ins);
compi->inputs = inarr;
/* all the inputs, inwidth inputs per gate */
k = 0;
for (i = 0; i < numgates; i++) {
for (j = 0; j < inwidth; j++) {
if (first) {
tok = strtok(copyline, " \t");
first = FALSE;
} else {
tok = strtok(NULL, " \t");
}
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
inarr[k] = name;
k++;
}
}
/* one output */
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
compi->output = name;
/* timing model */
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
compi->tmodel = name;
tfree(copyline);
return compi;
}
static struct gate_instance *add_array_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline, *itype = hdr->instance_type;
BOOL first = TRUE, tristate = FALSE;
int i, j, k, n1 =hdr->num1, n2 = hdr->num2, inwidth, numgates;
struct gate_instance *gip = NULL;
char **inarr = NULL, **outarr = NULL, *name;
if (is_tristate_buf_array(itype)) {
inwidth = 1;
numgates = n1;
tristate = TRUE;
} else if (is_buf_gate_array(itype)) {
inwidth = 1;
numgates = n1;
} else if (is_vector_gate_array(itype)) {
inwidth = n1;
numgates = n2;
} else if (is_tristate_vector_array(itype)) {
inwidth = n1;
numgates = n2;
tristate = TRUE;
} else if (is_xor_gate_array(itype)) {
inwidth = 2;
numgates = n1;
} else if (is_tristate_xor_array(itype)) {
inwidth = 2;
numgates = n1;
tristate = TRUE;
} else {
return NULL;
}
gip = create_gate_instance(hdr);
gip->num_gates = numgates;
gip->width = inwidth;
gip->num_ins = numgates * inwidth;
gip->num_outs = numgates;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/*
numgates gates, each gate has inwidth inputs and 1 output
inputs first
*/
inarr = TMALLOC(char *, gip->num_ins);
gip->inputs = inarr;
k = 0;
for (i = 0; i < numgates; i++) {
for (j = 0; j < inwidth; j++) {
if (first) {
tok = strtok(copyline, " \t");
first = FALSE;
} else {
tok = strtok(NULL, " \t");
}
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
inarr[k] = name;
k++;
}
}
/* enable for tristate */
if (tristate) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
gip->enable = name;
}
/* outputs next */
outarr = TMALLOC(char *, numgates);
gip->outputs = outarr;
for (i = 0; i < numgates; i++) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
outarr[i] = name;
}
/* timing model last */
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
gip->tmodel = name;
tfree(copyline);
return gip;
}
static struct gate_instance *add_gate_inout_timing_model(
struct instance_hdr *hdr, char *start)
{
char *tok, *copyline, *itype = hdr->instance_type;
int i, n1 = hdr->num1, inwidth;
BOOL first = TRUE, tristate = FALSE;
struct gate_instance *gip = NULL;
char **inarr = NULL, **outarr = NULL, *name;
if (is_vector_gate(itype)) {
inwidth = n1;
} else if (is_vector_tristate(itype)) {
inwidth = n1;
tristate = TRUE;
} else if (is_buf_gate(itype)) {
inwidth = 1;
} else if (is_buf_tristate(itype)) {
inwidth = 1;
tristate = TRUE;
} else if (is_xor_gate(itype)) {
inwidth = 2;
} else if (is_xor_tristate(itype)) {
inwidth = 2;
tristate = TRUE;
} else {
return NULL;
}
gip = create_gate_instance(hdr);
gip->num_gates = 1;
gip->width = inwidth;
gip->num_ins = inwidth;
gip->num_outs = 1;
copyline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(copyline, start, strlen(start) + 1);
/* inputs */
inarr = TMALLOC(char *, gip->num_ins);
gip->inputs = inarr;
for (i = 0; i < inwidth; i++) {
if (first) {
tok = strtok(copyline, " \t");
first = FALSE;
} else {
tok = strtok(NULL, " \t");
}
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
inarr[i] = name;
}
/* enable for tristate */
if (tristate) {
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
gip->enable = name;
}
/* output */
outarr = TMALLOC(char *, gip->num_outs);
gip->outputs = outarr;
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
outarr[0] = name;
/* timing model last */
tok = strtok(NULL, " \t");
name = TMALLOC(char, strlen(tok) + 1);
(void) memcpy(name, tok, strlen(tok) + 1);
gip->tmodel = name;
tfree(copyline);
return gip;
}
static char *skip_past_words(char *start, int count)
{
char *p1;
int i;
if (count < 1) { return start; }
p1 = start;
p1 = skip_ws(p1);
for (i = 0; i < count; i++) {
p1 = skip_non_ws(p1);
p1 = skip_ws(p1);
}
return p1;
}
static Xlatorp translate_pull(struct instance_hdr *hdr, char *start)
{
char *itype, *xspice, *iname, *newline = NULL, *tok;
char *model_name, *inst_stmt, *model_stmt;
int i, numpulls;
Xlatorp xp = NULL;
Xlatep xdata = NULL;
itype = hdr->instance_type;
iname = hdr->instance_name;
numpulls = hdr->num1;
xp = create_xlator();
/* pull devices do not have a timing model, just need the xspice name */
xspice = find_xspice_for_delay(itype);
newline = TMALLOC(char, strlen(start) + 1);
(void) memcpy(newline, start, strlen(start) + 1);
model_name = tprintf("d_%s_%s", iname, itype);
for (i = 0; i < numpulls; i++) {
if (i == 0) {
tok = strtok(newline, " \t");
} else {
tok = strtok(NULL, " \t");
}
inst_stmt = tprintf("a%s_%d %s %s", iname, i, tok, model_name);
xdata = create_xlate_translated(inst_stmt);
xp = add_xlator(xp, xdata);
tfree(inst_stmt);
}
model_stmt = tprintf(".model %s %s(load = 1pf)", model_name, xspice);
xdata = create_xlate_translated(model_stmt);
xp = add_xlator(xp, xdata);
tfree(model_stmt);
tfree(model_name);
tfree(newline);
delete_instance_hdr(hdr);
return xp;
}
static Xlatorp translate_ff_latch(struct instance_hdr *hdr, char *start)
{
/* If OK return Xlatorp else return NULL */
char *itype;
struct dff_instance *dffp = NULL;
struct jkff_instance *jkffp = NULL;
struct srff_instance *srffp = NULL;
struct dltch_instance *dltchp = NULL;
Xlatorp xp;
itype = hdr->instance_type;
if (eq(itype, "dff")) {
dffp = add_dff_inout_timing_model(hdr, start);
if (dffp) {
xp = gen_dff_instance(dffp);
delete_dff_instance(dffp);
return xp;
}
} else if (eq(itype, "jkff")) {
jkffp = add_jkff_inout_timing_model(hdr, start);
if (jkffp) {
xp = gen_jkff_instance(jkffp);
delete_jkff_instance(jkffp);
return xp;
}
} else if (eq(itype, "srff")) {
srffp = add_srff_inout_timing_model(hdr, start);
if (srffp) {
xp = gen_srff_instance(srffp);
delete_srff_instance(srffp);
return xp;
}
} else if (eq(itype, "dltch")) {
dltchp = add_dltch_inout_timing_model(hdr, start);
if (dltchp) {
xp = gen_dltch_instance(dltchp);
delete_dltch_instance(dltchp);
return xp;
}
} else {
return NULL;
}
return NULL;
}
static Xlatorp translate_gate(struct instance_hdr *hdr, char *start)
{
/* If OK return Xlatorp else return NULL */
char *itype;
struct gate_instance *igatep;
struct compound_instance *compi;
Xlatorp xp;
itype = hdr->instance_type;
if (is_gate(itype) || is_tristate(itype)) {
igatep = add_gate_inout_timing_model(hdr, start);
if (igatep) {
xp = gen_gate_instance(igatep);
delete_gate_instance(igatep);
return xp;
}
} else if (is_gate_array(itype) || is_tristate_array(itype)) {
igatep = add_array_inout_timing_model(hdr, start);
if (igatep) {
xp = gen_gate_instance(igatep);
delete_gate_instance(igatep);
return xp;
}
} else if (is_compound_gate(itype)) {
compi = add_compound_inout_timing_model(hdr, start);
if (compi) {
xp = gen_compound_instance(compi);
delete_compound_instance(compi);
return xp;
}
} else {
return NULL;
}
return NULL;
}
BOOL u_check_instance(char *line)
{
/*
Check to see if the U* instance is a type which can be translated.
Return TRUE if it can be translated
*/
char *xspice, *itype;
struct instance_hdr *hdr = create_instance_header(line);
itype = hdr->instance_type;
xspice = find_xspice_for_delay(itype);
delete_instance_hdr(hdr);
if (!xspice) {
return FALSE;
} else {
return TRUE;
}
}
/* NOTE
The input nline is expected to be a card in the deck which contains
a Pspice u* instance statement with all the '+' continuations added
minus the '+'.
*/
BOOL u_process_instance(char *nline)
{
/* Return TRUE if ok */
char *p1, *itype, *xspice;
struct instance_hdr *hdr = create_instance_header(nline);
Xlatorp xp = NULL;
itype = hdr->instance_type;
xspice = find_xspice_for_delay(itype);
if (!xspice) {
delete_instance_hdr(hdr);
return FALSE;
}
// printf("iname %s itype %s\n", hdr->instance_name, itype);
/* Skip past instance name, type, pwr, gnd */
p1 = skip_past_words(nline, 4);
if (is_gate(itype) || is_gate_array(itype)) {
xp = translate_gate(hdr, p1);
} else if (is_tristate(itype) || is_tristate_array(itype)) {
xp = translate_gate(hdr, p1);
} else if (is_compound_gate(itype)) {
xp = translate_gate(hdr, p1);
} else if (eq(itype, "dff") || eq(itype, "jkff") ||
eq(itype, "dltch") || eq(itype, "srff")) {
xp = translate_ff_latch(hdr, p1);
} else if (eq(itype, "pullup") || eq(itype, "pulldn")) {
xp = translate_pull(hdr, p1);
} else {
delete_instance_hdr(hdr);
return FALSE;
}
if (xp) {
append_xlator(translated_p, xp);
delete_xlator(xp);
return TRUE;
} else {
return FALSE;
}
}
/* NOTE
The input line is expected to be a card in the deck which contains
a Pspice .model timing model statement with all the '+' continuations
added minus the '+'.
*/
BOOL u_process_model_line(char *line)
{
/* Translate a .model line to find the delays */
/* Return TRUE if ok */
char *newline;
BOOL retval;
size_t n = strlen(line) - 1;
if (n > 0 && line[n] == '\n') line[n] = '\0';
if (strncmp(line, ".model ", strlen(".model ")) == 0) {
newline = TMALLOC(char, strlen(line) + 1);
(void) memcpy(newline, line, strlen(line) + 1);
retval = u_process_model(newline, line);
tfree(newline);
return retval;
} else {
return FALSE;
}
}