Add translation of ao/aoi compound gates.

This commit is contained in:
Brian Taylor 2022-05-04 21:50:20 -07:00 committed by Holger Vogt
parent 4de648c8de
commit e27881fe44
1 changed files with 260 additions and 45 deletions

View File

@ -47,7 +47,7 @@
#include "ngspice/udevices.h"
/*
TODO check for name collisions when creating new names
TODO add support for compound gates, srff, pullup/down
TODO add support for oa and oai gates, srff, pullup/down
*/
#define TRACE
@ -94,6 +94,16 @@ struct gate_instance {
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;
@ -203,10 +213,8 @@ static char *find_xspice_for_delay(char *itype)
if (strcmp(itype, "and3") == 0) { return xspice_tab[D_AND]; }
if (strcmp(itype, "and3a") == 0) { return xspice_tab[D_AND]; }
/* Not implemented
if (strcmp(itype, "ao") == 0) { return xspice_tab[D_AO]; }
if (strcmp(itype, "aoi") == 0) { return xspice_tab[D_AOI]; }
*/
break;
}
case 'b': {
@ -522,6 +530,7 @@ static Xlatep find_in_xlator(Xlatep x, Xlatorp xlp)
}
return NULL;
}
static Xlatep find_in_model_xlator(Xlatep x)
{
Xlatep x1;
@ -911,6 +920,42 @@ static struct gate_instance *create_gate_instance(struct instance_hdr *hdrp)
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;
@ -1266,6 +1311,116 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip)
return xxp;
}
static Xlatorp gen_compound_instance(struct compound_instance *compi)
{
char **inarr, *itype, *output, *tmodel, *outgate = 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;
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 (strcmp(itype, "aoi") == 0) {
outgate = "d_nor";
} else if (strcmp(itype, "ao") == 0) {
outgate = "d_or";
} 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 */
for (j = 0; j < width; j++) {
if (strcmp(inarr[k], "$d_hi") != 0) {
num_ins_kept++;
sprintf(tmp + strlen(tmp), " %s", inarr[k]);
}
k++;
}
if (num_ins_kept >= 2) {
new_inst = tprintf("a%s_%d [%s ] %s %s", inst, i,
tmp, connector[i], model_name);
xdata = create_xlate_translated(new_inst);
xxp = add_xlator(xxp, xdata);
tfree(new_inst);
} else if (num_ins_kept == 1) {
/*
connector[i] is the remaining input connected
directly to the OR/NOR final gate.
*/
tfree(connector[i]);
connector[i] = tprintf("%s", tmp);
} else {
assert(FALSE);
}
}
model_stmt = tprintf(".model %s d_and", model_name);
xdata = create_xlate_translated(model_stmt);
xxp = add_xlator(xxp, xdata);
tfree(model_stmt);
/* Final OR/NOR 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]);
}
new_stmt = tprintf("a%s_out [%s ] %s %s",
inst, tmp, output, final_model_name);
xdata = create_xlate_translated(new_stmt);
xxp = add_xlator(xxp, xdata);
tfree(new_stmt);
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;
@ -1709,10 +1864,13 @@ static char *get_estimate(struct timing_data *tdp)
or finished with this return value.
*/
if (!tdp) { return NULL; }
if (tdp->estimate == EST_MIN) { return tdp->min; }
if (tdp->estimate == EST_TYP) { return tdp->typ; }
if (tdp->estimate == EST_MAX) { return tdp->max; }
if (tdp->estimate == EST_AVE) { return tdp->ave; }
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;
}
@ -1903,22 +2061,35 @@ static char *get_delays_ugff(char *rem, char *d_name)
return delays;
}
static void print_delays(char *delays)
{
if (delays) {
printf("<%s>\n", delays);
} else {
printf("<(null)>\n");
}
return;
}
static BOOL u_process_model(char *nline, char *original,
char *newname, char *xspice)
{
char *tok, *remainder, *delays = NULL, *utype, *tmodel;
BOOL retval = TRUE;
BOOL retval = TRUE, verbose = FALSE;
#ifdef TRACE
//verbose = TRUE;
#endif
/* .model */
tok = strtok(nline, " \t");
/* model name */
tok = strtok(NULL, " \t");
printf("\nmodel_name -> %s\n", tok);
if (verbose) printf("\nmodel_name -> %s\n", tok);
tmodel = TMALLOC(char, strlen(tok) + 1);
memcpy(tmodel, tok, strlen(tok) + 1);
/* model utype */
tok = strtok(NULL, " \t(");
printf("model_utype -> %s\n", tok);
if (verbose) printf("model_utype -> %s\n", tok);
utype = TMALLOC(char, strlen(tok) + 1);
memcpy(utype, tok, strlen(tok) + 1);
@ -1927,52 +2098,32 @@ static BOOL u_process_model(char *nline, char *original,
if (remainder) {
if (strcmp(utype, "ugate") == 0) {
delays = get_delays_ugate(remainder, xspice);
if (delays) {
printf("<%s>\n", delays);
add_delays_to_model_xlator(delays, utype, "", tmodel);
} else {
printf("<(null)>\n");
add_delays_to_model_xlator("", utype, "", tmodel);
}
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (verbose) print_delays(delays);
if (delays) { tfree(delays); }
} else if (strcmp(utype, "utgate") == 0) {
delays = get_delays_utgate(remainder, xspice);
if (delays) {
printf("<%s>\n", delays);
add_delays_to_model_xlator(delays, utype, "", tmodel);
} else {
printf("<(null)>\n");
add_delays_to_model_xlator("", utype, "", tmodel);
}
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (verbose) print_delays(delays);
if (delays) { tfree(delays); }
} else if (strcmp(utype, "ueff") == 0) {
delays = get_delays_ueff(remainder, xspice);
if (delays) {
printf("<%s>\n", delays);
add_delays_to_model_xlator(delays, utype, "", tmodel);
} else {
printf("<(null)>\n");
add_delays_to_model_xlator("", utype, "", tmodel);
}
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
if (verbose) print_delays(delays);
if (delays) { tfree(delays); }
} else if (strcmp(utype, "ugff") == 0) {
delays = get_delays_ugff(remainder, "d_dlatch");
if (delays) {
printf("<%s>\n", delays);
add_delays_to_model_xlator(delays, utype, "d_dlatch", tmodel);
} else {
printf("<(null)>\n");
add_delays_to_model_xlator("", utype, "d_dlatch", tmodel);
}
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_dlatch", tmodel);
if (verbose) print_delays(delays);
if (delays) { tfree(delays); }
delays = get_delays_ugff(remainder, "d_srlatch");
if (delays) {
printf("<%s>\n", delays);
add_delays_to_model_xlator(delays, utype, "d_srlatch", tmodel);
} else {
printf("<(null)>\n");
add_delays_to_model_xlator("", utype, "d_srlatch", tmodel);
}
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_srlatch", tmodel);
if (verbose) print_delays(delays);
if (delays) { tfree(delays); }
} else {
retval = FALSE;
@ -2166,6 +2317,59 @@ static struct jkff_instance *add_jkff_inout_timing_model(
return jkffip;
}
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 (strcmp(itype, "aoi") == 0 || strcmp(itype, "ao") == 0) {
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)
{
@ -2398,6 +2602,7 @@ static Xlatorp translate_gate(struct instance_hdr *hdr, char *start)
/* if unable to translate return 0, else return 1 */
char *itype;
struct gate_instance *igatep;
struct compound_instance *compi;
Xlatorp xp;
itype = hdr->instance_type;
@ -2415,6 +2620,13 @@ static Xlatorp translate_gate(struct instance_hdr *hdr, char *start)
delete_gate_instance(igatep);
return xp;
}
} else if (strcmp(itype, "aoi") == 0 || strcmp(itype, "ao") == 0) {
compi = add_compound_inout_timing_model(hdr, start);
if (compi) {
xp = gen_compound_instance(compi);
delete_compound_instance(compi);
return xp;
}
} else {
assert(FALSE);
return NULL;
@ -2455,12 +2667,15 @@ BOOL u_process_instance(char *nline)
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 (strcmp(itype, "aoi") == 0 || strcmp(itype, "ao") == 0) {
xp = translate_gate(hdr, p1);
} else if (strcmp(itype, "dff") == 0 || strcmp(itype, "jkff") == 0 ||
strcmp(itype, "dltch") == 0) {
xp = translate_ff_latch(hdr, p1);