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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -13,6 +19,8 @@
|
||||||
#include "ngspice/logicexp.h"
|
#include "ngspice/logicexp.h"
|
||||||
#include "ngspice/udevices.h"
|
#include "ngspice/udevices.h"
|
||||||
|
|
||||||
|
/* #define TRACE */
|
||||||
|
|
||||||
/* Start of btree symbol table */
|
/* Start of btree symbol table */
|
||||||
#define SYM_INPUT 1
|
#define SYM_INPUT 1
|
||||||
#define SYM_OUTPUT 2
|
#define SYM_OUTPUT 2
|
||||||
|
|
@ -525,6 +533,21 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line)
|
||||||
}
|
}
|
||||||
return NULL;
|
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 */
|
/* End parse table */
|
||||||
|
|
||||||
/* Start of logicexp parser */
|
/* Start of logicexp parser */
|
||||||
|
|
@ -589,12 +612,12 @@ static void gen_inverters(SYM_TAB t)
|
||||||
gen_inverters(t->left);
|
gen_inverters(t->left);
|
||||||
if (t->attribute & SYM_INVERTER) {
|
if (t->attribute & SYM_INVERTER) {
|
||||||
if (t->ref_count >= 1) {
|
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_clear(&instance);
|
||||||
ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay",
|
ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay",
|
||||||
get_inst_name(), t->name, get_inverter_output_name(t->name));
|
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));
|
u_add_instance(ds_get_buf(&instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -606,6 +629,7 @@ static void gen_models(void)
|
||||||
{
|
{
|
||||||
DS_CREATE(model, 64);
|
DS_CREATE(model, 64);
|
||||||
|
|
||||||
|
#ifdef TRACE
|
||||||
printf(".model d_inv_zero_delay d_inverter\n");
|
printf(".model d_inv_zero_delay d_inverter\n");
|
||||||
printf(".model d__inverter__1 d_inverter\n");
|
printf(".model d__inverter__1 d_inverter\n");
|
||||||
printf(".model d__buffer__1 d_buffer\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__xor__1 d_xor\n");
|
||||||
printf(".model d__nor__1 d_nor\n");
|
printf(".model d__nor__1 d_nor\n");
|
||||||
printf(".model d__or__1 d_or\n");
|
printf(".model d__or__1 d_or\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
ds_clear(&model);
|
ds_clear(&model);
|
||||||
ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter");
|
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);
|
delete_lexer(lxr);
|
||||||
lxr = new_lexer(t->line);
|
lxr = new_lexer(t->line);
|
||||||
}
|
}
|
||||||
|
#ifdef TRACE
|
||||||
printf("%s\n", ds_get_buf(&instance));
|
printf("%s\n", ds_get_buf(&instance));
|
||||||
|
#endif
|
||||||
u_add_instance(ds_get_buf(&instance));
|
u_add_instance(ds_get_buf(&instance));
|
||||||
}
|
}
|
||||||
delete_lexer(lxr);
|
delete_lexer(lxr);
|
||||||
|
|
@ -1259,8 +1284,13 @@ static void bparse(char *line, BOOL new_lexer)
|
||||||
ds_cat_str(&stmt, lx->lexer_buf);
|
ds_cat_str(&stmt, lx->lexer_buf);
|
||||||
end_pos = bstmt();
|
end_pos = bstmt();
|
||||||
|
|
||||||
|
#ifdef TRACE
|
||||||
ds_cat_mem(&stmt, &lx->lexer_line[start_pos], end_pos - start_pos);
|
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));
|
printf("\n* Stmt(%d): %s\n\n", stmt_num, ds_get_buf(&stmt));
|
||||||
|
#else
|
||||||
|
(void) start_pos;
|
||||||
|
(void) end_pos;
|
||||||
|
#endif
|
||||||
|
|
||||||
beval_order();
|
beval_order();
|
||||||
|
|
||||||
|
|
@ -1278,7 +1308,6 @@ static void bparse(char *line, BOOL new_lexer)
|
||||||
gen_inverters(lx->lexer_sym_tab);
|
gen_inverters(lx->lexer_sym_tab);
|
||||||
gen_models();
|
gen_models();
|
||||||
ds_free(&stmt);
|
ds_free(&stmt);
|
||||||
#define TRACE
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
if (!new_lexer)
|
if (!new_lexer)
|
||||||
print_sym_tab(lx->lexer_sym_tab, FALSE);
|
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;
|
int t, num_ins = 0, num_outs = 0, i;
|
||||||
char *endp;
|
char *endp;
|
||||||
|
|
||||||
|
#ifdef TRACE
|
||||||
printf("\nf_logicexp: %s\n", line);
|
printf("\nf_logicexp: %s\n", line);
|
||||||
|
#endif
|
||||||
lex_init(line);
|
lex_init(line);
|
||||||
(void) add_sym_tab_entry("logic", SYM_KEY_WORD,
|
(void) add_sym_tab_entry("logic", SYM_KEY_WORD,
|
||||||
&parse_lexer->lexer_sym_tab);
|
&parse_lexer->lexer_sym_tab);
|
||||||
|
|
@ -1354,7 +1385,6 @@ BOOL f_logicexp(char *line)
|
||||||
delete_lexer(parse_lexer);
|
delete_lexer(parse_lexer);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10);
|
|
||||||
t = lex_scan();
|
t = lex_scan();
|
||||||
if (!expect_token(t, ')', NULL, TRUE)) return FALSE;
|
if (!expect_token(t, ')', NULL, TRUE)) return FALSE;
|
||||||
t = lex_scan(); // pwr
|
t = lex_scan(); // pwr
|
||||||
|
|
@ -1382,7 +1412,7 @@ BOOL f_logicexp(char *line)
|
||||||
/* timing model */
|
/* timing model */
|
||||||
t = lex_scan();
|
t = lex_scan();
|
||||||
if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE;
|
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,
|
(void) add_sym_tab_entry(parse_lexer->lexer_buf,
|
||||||
SYM_TMODEL, &parse_lexer->lexer_sym_tab);
|
SYM_TMODEL, &parse_lexer->lexer_sym_tab);
|
||||||
bparse(line, FALSE);
|
bparse(line, FALSE);
|
||||||
|
|
@ -1390,9 +1420,182 @@ BOOL f_logicexp(char *line)
|
||||||
return TRUE;
|
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)
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue