Better estimates of rise/fall delays in PINDLYs with outputs separated by CASE.

This commit is contained in:
Brian Taylor 2022-10-26 19:31:06 -07:00
parent 07da7d07d0
commit a3419821df
1 changed files with 245 additions and 80 deletions

View File

@ -1413,67 +1413,179 @@ error_return:
}
/* pindly handling */
static PTABLE ios_in_tab = NULL;
static PTABLE ios_out_tab = NULL;
/* C++ with templates would generalize the different TABLEs */
typedef struct pindly_line *PLINE;
struct pindly_line {
char *in_name;
char *out_name;
char *ena_name;
char *delays;
PLINE next;
};
static void init_ios_tab(void)
typedef struct pindly_table *PINTABLE;
struct pindly_table {
PLINE first;
PLINE last;
int num_entries;
};
static PINTABLE new_pindly_table(void)
{
ios_in_tab = new_parse_table();
ios_out_tab = new_parse_table();
PINTABLE pint;
pint = TMALLOC(struct pindly_table, 1);
pint->first = pint->last = NULL;
pint->num_entries = 0;
return pint;
}
static void cleanup_pindly(void)
static int num_pindly_entries(PINTABLE pint)
{
delete_parse_table(ios_in_tab);
delete_parse_table(ios_out_tab);
ios_in_tab = NULL;
ios_out_tab = NULL;
}
static TLINE ios_tab_add(char *ioname, BOOL is_input)
{
if (is_input)
return add_to_parse_table(ios_in_tab, ioname, TRUE);
if (!pint)
return 0;
else
return add_to_parse_table(ios_out_tab, ioname, TRUE);
return pint->num_entries;
}
static void print_ios_tabs(void)
static PLINE new_pindly_line(void)
{
#ifdef TABLE_PRINT
if (ios_in_tab) {
printf("ios_in_tab\n");
table_print(ios_in_tab->first);
}
if (ios_out_tab) {
printf("ios_out_tab\n");
table_print(ios_out_tab->first);
PLINE p = NULL;
p = TMALLOC(struct pindly_line, 1);
p->in_name = p->out_name = p->ena_name = p->delays = NULL;
return p;
}
static PLINE add_new_pindly_line(PINTABLE pint)
{
PLINE p;
p = new_pindly_line();
p->next = NULL;
if (!pint->first) {
pint->first = pint->last = p;
} else {
pint->last->next = p;
pint->last = p;
}
pint->num_entries++;
return p;
}
static PLINE set_in_name(char *s, PLINE p)
{
if (p->in_name) tfree(p->in_name);
p->in_name = TMALLOC(char, (strlen(s) + 1));
strcpy(p->in_name, s);
return p;
}
static PLINE set_out_name(char *s, PLINE p)
{
if (p->out_name) tfree(p->out_name);
p->out_name = TMALLOC(char, (strlen(s) + 1));
strcpy(p->out_name, s);
return p;
}
#if 0
static PLINE set_ena_name(char *s, PLINE p)
{
if (p->ena_name) tfree(p->ena_name);
p->ena_name = TMALLOC(char, (strlen(s) + 1));
strcpy(p->ena_name, s);
return p;
}
#endif
static PLINE set_delays(char *s, PLINE p)
{
if (p->delays) tfree(p->delays);
p->delays = TMALLOC(char, (strlen(s) + 1));
strcpy(p->delays, s);
return p;
}
static void gen_output_buffers(void)
static void delete_pindly_table(PINTABLE pint)
{
TLINE tin, tout;
if (ios_in_tab && ios_out_tab) {
if (!ios_in_tab->first || !ios_out_tab->first) {
return;
} else {
DS_CREATE(instance, 128);
tin = ios_in_tab->first;
tout = ios_out_tab->first;
while (tin && tout) {
ds_clear(&instance);
ds_cat_printf(&instance, "%s %s %s d_pindly_buf",
get_inst_name(), tin->line, tout->line);
u_add_instance(ds_get_buf(&instance));
tin = tin->next;
tout = tout->next;
}
ds_free(&instance);
}
PLINE p, next;
if (!pint)
return;
next = pint->first;
while (next) {
p = next;
if (p->in_name) tfree(p->in_name);
if (p->out_name) tfree(p->out_name);
if (p->ena_name) tfree(p->ena_name);
if (p->delays) tfree(p->delays);
next = p->next;
tfree(p);
}
tfree(pint);
}
static PLINE nth_pindly_entry(PINTABLE pint, int n)
{
/* Entries ore from 0 to num_entries - 1 */
PLINE p, next;
int count = 0;
if (n < 0) return NULL;
if (n > pint->num_entries - 1) return NULL;
next = pint->first;
while (next) {
p = next;
if (count == n) return p;
count++;
next = p->next;
}
return NULL;
}
static PLINE find_pindly_out_name(PINTABLE pint, char *name)
{
PLINE p, next;
if (!pint) return NULL;
next = pint->first;
while (next) {
p = next;
if (strcmp(p->out_name, name) == 0) return p;
next = p->next;
}
return NULL;
}
static PINTABLE pindly_tab = NULL;
static void init_pindly_tab(void)
{
pindly_tab = new_pindly_table();
}
static void cleanup_pindly_tab(void)
{
delete_pindly_table(pindly_tab);
pindly_tab = NULL;
}
static void gen_pindly_buffers(void)
{
DS_CREATE(dbuf, 128);
PLINE pline = NULL;
pline = pindly_tab->first;
while (pline) {
char *iname = NULL;
ds_clear(&dbuf);
iname = get_inst_name();
ds_cat_printf(&dbuf, "%s %s %s d_pindly_buf_%s", iname,
pline->in_name, pline->out_name, iname);
u_add_instance(ds_get_buf(&dbuf));
ds_clear(&dbuf);
ds_cat_printf(&dbuf, ".model d_pindly_buf_%s d_buffer%s",
iname, pline->delays);
u_add_instance(ds_get_buf(&dbuf));
pline = pline->next;
}
}
static char *get_typ_estimate(char *min, char *typ, char *max)
{
char *tmpmax = NULL, *tmpmin = NULL;
@ -1516,35 +1628,73 @@ static char *get_typ_estimate(char *min, char *typ, char *max)
static void gen_output_models(LEXER lx)
{
int val, which = 0;
BOOL in_delay = FALSE;
int val, which = 0, arrlen = 0, idx = 0, i;
BOOL in_delay = FALSE, expect_left = FALSE;
float typ_max_val = 0.0, typ_val = 0.0;
char *units;
BOOL tracing = FALSE;
DS_CREATE(dmin, 16);
DS_CREATE(dtyp, 16);
DS_CREATE(dmax, 16);
DS_CREATE(dtyp_max_str, 16);
DSTRINGPTR dsp = NULL;
PLINE pline = NULL;
PLINE *pline_arr = NULL;
arrlen = num_pindly_entries(pindly_tab);
assert(arrlen > 0);
pline_arr = TMALLOC(PLINE, arrlen);
val = lexer_set_start("pindly:", lx);
val = lexer_scan(lx); // "pindly"
val = lexer_scan(lx); // ':'
val = lexer_scan(lx);
while (val != '\0') {
idx = 0;
while (val != '\0') { /* while val */
if (val == LEX_ID) {
expect_left = FALSE;
if (strcmp(lx->lexer_buf, "delay") == 0) {
ds_clear(&dmin);
ds_clear(&dtyp);
ds_clear(&dmax);
in_delay = TRUE;
} else if (strcmp(lx->lexer_buf, "setup_hold") == 0
|| strcmp(lx->lexer_buf, "width") == 0
|| strcmp(lx->lexer_buf, "freq") == 0
|| strcmp(lx->lexer_buf, "general") == 0) {
break;
}
#ifdef TRACE
printf("ID: \"%s\"\n", lx->lexer_buf);
pline = find_pindly_out_name(pindly_tab, lx->lexer_buf);
if (pline) {
if (tracing) printf("Case for %s comming\n", pline->out_name);
pline_arr[idx++] = pline;
}
if (tracing) printf("ID: \"%s\"\n", lx->lexer_buf);
} else if (val == LEX_OTHER) {
printf("OTHER: \"%s\"\n", lx->lexer_buf);
expect_left = FALSE;
if (tracing) printf("OTHER: \"%s\"\n", lx->lexer_buf);
} else {
printf("TOK: %d <%c>\n", val, val);
#endif
if (tracing) printf("TOK: %d <%c>\n", val, val);
if (val == '{') {
if (expect_left) {
if (tracing) printf("Ready for delays\n");
for (i = 0; i < idx; i++)
if (tracing)
printf("For output %s\n", pline_arr[i]->out_name);
}
expect_left = FALSE;
} else if (val == '=') {
expect_left = TRUE;
} else if (val == '}') {
for (i = 0; i < idx; i++) {
if (tracing) printf("Finished delays for output %s\n",
pline_arr[i]->out_name);
pline_arr[i] = NULL;
}
idx = 0;
expect_left = FALSE;
in_delay = FALSE;
typ_max_val = 0.0;
}
}
if (in_delay) {
switch (which) {
@ -1574,21 +1724,36 @@ static void gen_output_models(LEXER lx)
char *s;
s = get_typ_estimate(ds_get_buf(&dmin),
ds_get_buf(&dtyp), ds_get_buf(&dmax));
#ifdef TRACE
printf("\tMIN: \"%s\"", ds_get_buf(&dmin));
printf(" TYP: \"%s\"", ds_get_buf(&dtyp));
printf(" MAX: \"%s\"", ds_get_buf(&dmax));
if (s)
printf(" ESTIMATE: \"%s\"\n", s);
else
printf(" ESTIMATE: UNKNOWN\n");
#endif
if (tracing) printf("\tMIN: \"%s\"", ds_get_buf(&dmin));
if (tracing) printf(" TYP: \"%s\"", ds_get_buf(&dtyp));
if (tracing) printf(" MAX: \"%s\"", ds_get_buf(&dmax));
if (s) {
if (tracing) printf(" ESTIMATE: \"%s\"\n", s);
} else {
if (tracing) printf(" ESTIMATE: UNKNOWN\n");
}
if (s) {
typ_val = strtof(s, &units);
if (typ_val > typ_max_val) {
DS_CREATE(delay_string, 64);
ds_clear(&delay_string);
ds_clear(&dtyp_max_str);
ds_cat_str(&dtyp_max_str, s);
typ_max_val = typ_val;
if (ds_get_length(&dtyp_max_str) > 0) {
ds_cat_printf(&delay_string,
"(rise_delay=%s fall_delay=%s)",
ds_get_buf(&dtyp_max_str),
ds_get_buf(&dtyp_max_str));
} else {
ds_cat_printf(&delay_string,
"(rise_delay=10ns fall_delay=10ns)");
}
for (i = 0; i < idx; i++) {
(void) set_delays(ds_get_buf(&delay_string),
pline_arr[i]);
}
ds_free(&delay_string);
}
}
}
@ -1596,21 +1761,13 @@ static void gen_output_models(LEXER lx)
which = 0;
}
val = lexer_scan(lx);
}
if (ds_get_length(&dtyp_max_str) > 0) {
ds_clear(&dmax); // dmax was no longer in use
ds_cat_printf(&dmax,
".model d_pindly_buf d_buffer(rise_delay=%s fall_delay=%s)",
ds_get_buf(&dtyp_max_str), ds_get_buf(&dtyp_max_str));
u_add_instance(ds_get_buf(&dmax));
} else {
u_add_instance(
".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)");
}
} /* end while val */
ds_free(&dmin);
ds_free(&dtyp);
ds_free(&dmax);
ds_free(&dtyp_max_str);
tfree(pline_arr);
}
BOOL f_pindly(char *line)
@ -1619,10 +1776,13 @@ BOOL f_pindly(char *line)
char *endp;
LEXER lxr;
PLINE pline = NULL;
#ifdef TRACE
printf("\nf_pindly: %s\n", line);
#endif
init_ios_tab();
init_pindly_tab();
lxr = new_lexer(line);
current_lexer = lxr;
t = lexer_scan(lxr); // U*
@ -1683,7 +1843,8 @@ BOOL f_pindly(char *line)
for (i = 0; i < num_ios; i++) {
t = lexer_scan(lxr);
if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return;
(void) ios_tab_add(lxr->lexer_buf, TRUE);
pline = add_new_pindly_line(pindly_tab);
(void) set_in_name(lxr->lexer_buf, pline);
}
/* num_refs reference nodes which are ignored */
@ -1692,23 +1853,27 @@ BOOL f_pindly(char *line)
if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return;
}
/* num_ios output ids */
pline = NULL;
for (i = 0; i < num_ios; i++) {
t = lexer_scan(lxr);
if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return;
(void) ios_tab_add(lxr->lexer_buf, FALSE);
if (i == 0)
pline = nth_pindly_entry(pindly_tab, i);
else
pline = pline->next;
(void) set_out_name(lxr->lexer_buf, pline);
}
print_ios_tabs();
gen_output_buffers();
gen_output_models(lxr);
gen_pindly_buffers();
delete_lexer(lxr);
cleanup_pindly();
cleanup_pindly_tab();
current_lexer = NULL;
return TRUE;
error_return:
delete_lexer(lxr);
cleanup_pindly();
cleanup_pindly_tab();
current_lexer = NULL;
return FALSE;
}