Initial handling of PINDLY. Output buffers without rise/fall delay estimates.

This commit is contained in:
Brian Taylor 2022-10-23 17:04:37 -07:00 committed by Holger Vogt
parent 9d239dc2f7
commit 3eb0a089e5
1 changed files with 212 additions and 9 deletions

View File

@ -1,3 +1,9 @@
/*
logicexp.c
Convert PSpice LOGICEXP logic expressions into XSPICE gates.
Extract timing delay estimates from PINDLY statements.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -13,6 +19,8 @@
#include "ngspice/logicexp.h"
#include "ngspice/udevices.h"
/* #define TRACE */
/* Start of btree symbol table */
#define SYM_INPUT 1
#define SYM_OUTPUT 2
@ -525,6 +533,21 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line)
}
return NULL;
}
//#define TABLE_PRINT
#ifdef TABLE_PRINT
static void table_print(TLINE first)
{
TLINE t;
if (!first)
return;
t = first;
while (t) {
printf("%s\n", t->line);
t = t->next;
}
}
#endif
/* End parse table */
/* Start of logicexp parser */
@ -589,12 +612,12 @@ static void gen_inverters(SYM_TAB t)
gen_inverters(t->left);
if (t->attribute & SYM_INVERTER) {
if (t->ref_count >= 1) {
printf("%s %s %s d_inv_zero_delay\n", get_inst_name(),
t->name, get_inverter_output_name(t->name));
ds_clear(&instance);
ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay",
get_inst_name(), t->name, get_inverter_output_name(t->name));
#ifdef TRACE
printf("%s\n", ds_get_buf(&instance));
#endif
u_add_instance(ds_get_buf(&instance));
}
}
@ -606,6 +629,7 @@ static void gen_models(void)
{
DS_CREATE(model, 64);
#ifdef TRACE
printf(".model d_inv_zero_delay d_inverter\n");
printf(".model d__inverter__1 d_inverter\n");
printf(".model d__buffer__1 d_buffer\n");
@ -615,6 +639,7 @@ static void gen_models(void)
printf(".model d__xor__1 d_xor\n");
printf(".model d__nor__1 d_nor\n");
printf(".model d__or__1 d_or\n");
#endif
ds_clear(&model);
ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter");
@ -1107,9 +1132,9 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols)
delete_lexer(lxr);
lxr = new_lexer(t->line);
}
#ifdef TRACE
printf("%s\n", ds_get_buf(&instance));
#endif
u_add_instance(ds_get_buf(&instance));
}
delete_lexer(lxr);
@ -1259,8 +1284,13 @@ static void bparse(char *line, BOOL new_lexer)
ds_cat_str(&stmt, lx->lexer_buf);
end_pos = bstmt();
#ifdef TRACE
ds_cat_mem(&stmt, &lx->lexer_line[start_pos], end_pos - start_pos);
printf("\n* Stmt(%d): %s\n\n", stmt_num, ds_get_buf(&stmt));
#else
(void) start_pos;
(void) end_pos;
#endif
beval_order();
@ -1278,7 +1308,6 @@ static void bparse(char *line, BOOL new_lexer)
gen_inverters(lx->lexer_sym_tab);
gen_models();
ds_free(&stmt);
#define TRACE
#ifdef TRACE
if (!new_lexer)
print_sym_tab(lx->lexer_sym_tab, FALSE);
@ -1323,7 +1352,9 @@ BOOL f_logicexp(char *line)
int t, num_ins = 0, num_outs = 0, i;
char *endp;
#ifdef TRACE
printf("\nf_logicexp: %s\n", line);
#endif
lex_init(line);
(void) add_sym_tab_entry("logic", SYM_KEY_WORD,
&parse_lexer->lexer_sym_tab);
@ -1354,7 +1385,6 @@ BOOL f_logicexp(char *line)
delete_lexer(parse_lexer);
return FALSE;
}
num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10);
t = lex_scan();
if (!expect_token(t, ')', NULL, TRUE)) return FALSE;
t = lex_scan(); // pwr
@ -1382,7 +1412,7 @@ BOOL f_logicexp(char *line)
/* timing model */
t = lex_scan();
if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
printf("TMODEL: %s\n", parse_lexer->lexer_buf);
//printf("TMODEL: %s\n", parse_lexer->lexer_buf);
(void) add_sym_tab_entry(parse_lexer->lexer_buf,
SYM_TMODEL, &parse_lexer->lexer_sym_tab);
bparse(line, FALSE);
@ -1390,9 +1420,182 @@ BOOL f_logicexp(char *line)
return TRUE;
}
/* pindly handling */
static PTABLE ios_in_tab = NULL;
static PTABLE ios_out_tab = NULL;
static void init_ios_tab(void)
{
ios_in_tab = new_parse_table();
ios_out_tab = new_parse_table();
}
static void cleanup_pindly(void)
{
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);
else
return add_to_parse_table(ios_out_tab, ioname, TRUE);
}
static void print_ios_tabs(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);
}
#endif
}
static void gen_output_buffers(void)
{
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;
}
u_add_instance(
".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)");
ds_free(&instance);
}
}
}
static BOOL pexpect_token(
int tok, int expected_tok, char *expected_str, BOOL msg)
{
BOOL val;
val = expect_token(tok, expected_tok, expected_str, msg);
if (!val)
cleanup_pindly();
return val;
}
BOOL f_pindly(char *line)
{
//printf("\nf_pindly: %s\n", line);
int t, num_ios = 0, num_refs = 0, num_ena = 0, i;
char *endp;
#ifdef TRACE
printf("\nf_pindly: %s\n", line);
#endif
init_ios_tab();
lex_init(line);
t = lex_scan(); // U*
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
/* pindly ( int , int, int ) */
t = lex_scan();
if (!pexpect_token(t, LEX_ID, "pindly", TRUE)) return FALSE;
t = lex_scan();
if (!pexpect_token(t, '(', NULL, TRUE)) return FALSE;
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
if (lex_all_digits(parse_lexer->lexer_buf)) {
num_ios = (int) strtol(parse_lexer->lexer_buf, &endp, 10);
} else {
printf("ERROR pindly io count is not an integer\n");
delete_lexer(parse_lexer);
cleanup_pindly();
return FALSE;
}
t = lex_scan();
if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE;
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
if (lex_all_digits(parse_lexer->lexer_buf)) {
num_ena = (int) strtol(parse_lexer->lexer_buf, &endp, 10);
} else {
printf("ERROR pindly enable count is not an integer\n");
delete_lexer(parse_lexer);
cleanup_pindly();
return FALSE;
}
if (num_ena != 0) {
delete_lexer(parse_lexer);
cleanup_pindly();
return FALSE;
}
t = lex_scan();
if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE;
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
if (lex_all_digits(parse_lexer->lexer_buf)) {
num_refs = (int) strtol(parse_lexer->lexer_buf, &endp, 10);
} else {
printf("ERROR pindly refs count is not an integer\n");
delete_lexer(parse_lexer);
cleanup_pindly();
return FALSE;
}
t = lex_scan();
if (!pexpect_token(t, ')', NULL, TRUE)) return FALSE;
t = lex_scan(); // pwr
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
t = lex_scan(); // gnd
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
/* num_ios input ids */
for (i = 0; i < num_ios; i++) {
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) {
return FALSE;
}
(void) ios_tab_add(parse_lexer->lexer_buf, TRUE);
}
/* num_refs reference nodes which are ignored */
for (i = 0; i < num_refs; i++) {
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) {
return FALSE;
}
}
/* num_ios output ids */
for (i = 0; i < num_ios; i++) {
t = lex_scan();
if (!pexpect_token(t, LEX_ID, NULL, TRUE)) {
return FALSE;
}
(void) ios_tab_add(parse_lexer->lexer_buf, FALSE);
}
print_ios_tabs();
gen_output_buffers();
delete_lexer(parse_lexer);
cleanup_pindly();
return TRUE;
}