From e27881fe442e5ca5c71c5d362c6b517bb48b25ae Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 4 May 2022 21:50:20 -0700 Subject: [PATCH] Add translation of ao/aoi compound gates. --- src/frontend/udevices.c | 305 ++++++++++++++++++++++++++++++++++------ 1 file changed, 260 insertions(+), 45 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 3f3bcc7f5..3176ff5cb 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -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);