Initial handling of PINDLY. Output buffers without rise/fall delay estimates.
This commit is contained in:
parent
9d239dc2f7
commit
3eb0a089e5
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue