2011-02-07 05:08:23 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2011 Cary R. (cygcary@yahoo.com)
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <string.h>
|
|
|
|
|
# include "config.h"
|
|
|
|
|
# include "vlog95_priv.h"
|
|
|
|
|
|
|
|
|
|
static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun)
|
|
|
|
|
{
|
|
|
|
|
const char *value = 0;
|
|
|
|
|
switch(entry) {
|
|
|
|
|
case '0':
|
|
|
|
|
value = " 0 ";
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
value = " 1 ";
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
value = " x ";
|
|
|
|
|
break;
|
|
|
|
|
case '?': /* 0, 1 or x */
|
|
|
|
|
value = " ? ";
|
|
|
|
|
break;
|
|
|
|
|
case 'b': /* 0 or 1 */
|
|
|
|
|
value = " b ";
|
|
|
|
|
break;
|
|
|
|
|
case '-': /* Current value. */
|
|
|
|
|
value = " - ";
|
|
|
|
|
break;
|
|
|
|
|
case '*': /* (??) */
|
|
|
|
|
value = " * ";
|
|
|
|
|
break;
|
|
|
|
|
case 'r': /* (01) */
|
|
|
|
|
value = " r ";
|
|
|
|
|
break;
|
|
|
|
|
case 'f': /* (10) */
|
|
|
|
|
value = " f ";
|
|
|
|
|
break;
|
|
|
|
|
case 'p': /* (01), (0x) or (x1) */
|
|
|
|
|
value = " p ";
|
|
|
|
|
break;
|
|
|
|
|
case 'n': /* (10), (1x) or (x0) */
|
|
|
|
|
value = " n ";
|
|
|
|
|
break;
|
|
|
|
|
/* Icarus encodings/extensions. */
|
|
|
|
|
case 'h':
|
|
|
|
|
if (*rerun) {
|
|
|
|
|
value = " x ";
|
|
|
|
|
} else {
|
|
|
|
|
value = " 1 ";
|
|
|
|
|
*rerun = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
|
|
|
|
if (*rerun) {
|
|
|
|
|
value = " x ";
|
|
|
|
|
} else {
|
|
|
|
|
value = " 0 ";
|
|
|
|
|
*rerun = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'q':
|
|
|
|
|
value = "(bx)";
|
|
|
|
|
break;
|
|
|
|
|
case 'B':
|
|
|
|
|
value = "(x?)";
|
|
|
|
|
break;
|
|
|
|
|
case 'F':
|
|
|
|
|
value = "(x0)";
|
|
|
|
|
break;
|
|
|
|
|
case 'M':
|
|
|
|
|
value = "(1x)";
|
|
|
|
|
break;
|
|
|
|
|
case 'N':
|
|
|
|
|
value = "(1?)";
|
|
|
|
|
break;
|
|
|
|
|
case 'P':
|
|
|
|
|
value = "(0?)";
|
|
|
|
|
break;
|
|
|
|
|
case 'Q':
|
|
|
|
|
value = "(0x)";
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
value = "(x1)";
|
|
|
|
|
break;
|
|
|
|
|
case '%': /* This is effectively the same as q. */
|
|
|
|
|
value = "(?x)";
|
|
|
|
|
break;
|
|
|
|
|
case '+':
|
|
|
|
|
value = "(?1)";
|
|
|
|
|
break;
|
|
|
|
|
case '_':
|
|
|
|
|
value = "(?0)";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "%s:%u: vlog95 error: Unknown primitive table "
|
|
|
|
|
"entry %c in primitive %s.\n", ivl_udp_file(udp),
|
|
|
|
|
ivl_udp_lineno(udp), entry, ivl_udp_name(udp));
|
|
|
|
|
vlog_errors += 1;
|
|
|
|
|
value = "<?> ";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
fprintf(vlog_out, "%s ", value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_sequ_table(ivl_udp_t udp)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx, count = ivl_udp_rows(udp);
|
|
|
|
|
for (idx = 0; idx < count; idx += 1) {
|
|
|
|
|
const char *row = ivl_udp_row(udp, idx);
|
|
|
|
|
unsigned need_to_rerun = 0;
|
|
|
|
|
do {
|
|
|
|
|
unsigned entry, inputs = ivl_udp_nin(udp);
|
|
|
|
|
unsigned rerun, rerunning = need_to_rerun;
|
|
|
|
|
need_to_rerun = 0;
|
|
|
|
|
fprintf(vlog_out, "%*c", 2*indent_incr, ' ');
|
|
|
|
|
for (entry = 1; entry <= inputs; entry += 1) {
|
|
|
|
|
rerun = rerunning;
|
|
|
|
|
emit_entry(udp, row[entry], &rerun);
|
|
|
|
|
if (rerun && ! rerunning) need_to_rerun = rerun;
|
|
|
|
|
}
|
|
|
|
|
fprintf(vlog_out, ": ");
|
|
|
|
|
/* The first entry is the current state. */
|
|
|
|
|
rerun = rerunning;
|
|
|
|
|
emit_entry(udp, row[0], &rerun);
|
|
|
|
|
if (rerun && ! rerunning) need_to_rerun = rerun;
|
|
|
|
|
fprintf(vlog_out, ": ");
|
|
|
|
|
/* The new value is after the inputs. */
|
|
|
|
|
rerun = rerunning;
|
|
|
|
|
emit_entry(udp, row[inputs+1], &rerun);
|
|
|
|
|
if (rerun && ! rerunning) need_to_rerun = rerun;
|
|
|
|
|
fprintf(vlog_out, ";\n");
|
|
|
|
|
} while (need_to_rerun);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_comb_table(ivl_udp_t udp)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx, count = ivl_udp_rows(udp);
|
|
|
|
|
for (idx = 0; idx < count; idx += 1) {
|
|
|
|
|
const char *row = ivl_udp_row(udp, idx);
|
|
|
|
|
unsigned need_to_rerun = 0;
|
|
|
|
|
do {
|
|
|
|
|
unsigned entry, inputs = ivl_udp_nin(udp);
|
|
|
|
|
unsigned rerun, rerunning = need_to_rerun;
|
|
|
|
|
need_to_rerun = 0;
|
|
|
|
|
fprintf(vlog_out, "%*c", 2*indent_incr, ' ');
|
|
|
|
|
for (entry = 0; entry < inputs; entry += 1) {
|
|
|
|
|
rerun = rerunning;
|
|
|
|
|
emit_entry(udp, row[entry], &rerun);
|
|
|
|
|
if (rerun && ! rerunning) need_to_rerun = rerun;
|
|
|
|
|
}
|
|
|
|
|
/* The new value is after the inputs. */
|
|
|
|
|
fprintf(vlog_out, ": ");
|
|
|
|
|
rerun = rerunning;
|
|
|
|
|
emit_entry(udp, row[inputs], &rerun);
|
|
|
|
|
if (rerun && ! rerunning) need_to_rerun = rerun;
|
|
|
|
|
fprintf(vlog_out, ";\n");
|
|
|
|
|
} while (need_to_rerun);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_udp(ivl_udp_t udp)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx, count;
|
|
|
|
|
fprintf(vlog_out, "\n");
|
|
|
|
|
fprintf(vlog_out, "/* This primitive was originally defined in "
|
|
|
|
|
"file %s at line %u. */\n",
|
|
|
|
|
ivl_udp_file(udp), ivl_udp_lineno(udp));
|
|
|
|
|
fprintf(vlog_out, "primitive %s (", ivl_udp_name(udp));
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, "%s", ivl_udp_port(udp, 0));
|
2011-02-07 05:08:23 +01:00
|
|
|
count = ivl_udp_nin(udp);
|
|
|
|
|
for (idx = 1; idx <= count; idx += 1) {
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, ", %s", ivl_udp_port(udp, idx));
|
2011-02-07 05:08:23 +01:00
|
|
|
}
|
|
|
|
|
fprintf(vlog_out, ");\n");
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, "%*coutput %s;\n", indent_incr, ' ',
|
|
|
|
|
ivl_udp_port(udp, 0));
|
2011-02-07 05:08:23 +01:00
|
|
|
for (idx = 1; idx <= count; idx += 1) {
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, "%*cinput %s;\n", indent_incr, ' ',
|
|
|
|
|
ivl_udp_port(udp, idx));
|
2011-02-07 05:08:23 +01:00
|
|
|
}
|
|
|
|
|
if (ivl_udp_sequ(udp)) {
|
|
|
|
|
char init = ivl_udp_init(udp);
|
|
|
|
|
fprintf(vlog_out, "\n");
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, "%*creg %s;\n", indent_incr, ' ',
|
|
|
|
|
ivl_udp_port(udp, 0));
|
2011-02-07 05:08:23 +01:00
|
|
|
switch (init) {
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
init = 'x';
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-20 19:59:54 +01:00
|
|
|
fprintf(vlog_out, "%*cinitial %s = 1'b%c;\n",
|
|
|
|
|
indent_incr, ' ', ivl_udp_port(udp, 0), init);
|
2011-02-07 05:08:23 +01:00
|
|
|
}
|
|
|
|
|
fprintf(vlog_out, "\n");
|
|
|
|
|
fprintf(vlog_out, "%*ctable\n", indent_incr, ' ');
|
|
|
|
|
if (ivl_udp_sequ(udp)) emit_sequ_table(udp);
|
|
|
|
|
else emit_comb_table(udp);
|
|
|
|
|
fprintf(vlog_out, "%*cendtable\n", indent_incr, ' ');
|
|
|
|
|
fprintf(vlog_out, "endprimitive /* %s */\n", ivl_udp_name(udp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ivl_udp_t *udps = 0;
|
|
|
|
|
static unsigned num_udps = 0;
|
|
|
|
|
|
|
|
|
|
void add_udp_to_list(ivl_udp_t udp)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
/* Look to see if the UDP is already in the list. */
|
|
|
|
|
for (idx = 0; idx < num_udps; idx += 1) {
|
|
|
|
|
if ((ivl_udp_lineno(udp) == ivl_udp_lineno(udps[idx])) &&
|
|
|
|
|
(strcmp(ivl_udp_name(udp), ivl_udp_name(udps[idx])) == 0)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
num_udps += 1;
|
|
|
|
|
udps = realloc(udps, num_udps * sizeof(ivl_udp_t));
|
|
|
|
|
udps[num_udps-1] = udp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void emit_udp_list()
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0; idx < num_udps; idx += 1) {
|
|
|
|
|
emit_udp(udps[idx]);
|
|
|
|
|
}
|
|
|
|
|
free(udps);
|
|
|
|
|
udps = 0;
|
|
|
|
|
num_udps = 0;
|
|
|
|
|
}
|