vlog95: add support for case statements and initial module instantiation.
This patch adds support for the various case statements and adds preliminary support for instantiating modules. The module instantiation, just like the module definition, is still missing ports. Adding this will require modification to the compiler to get the port order correct. Because of defparams and passed parameters any module that has a parameter must be generated uniquely for each instance since they may not all be the same. Modules without parameters are only generated once.
This commit is contained in:
parent
dc17190f4d
commit
3c10eb2956
|
|
@ -24,6 +24,7 @@
|
|||
# include <stdlib.h>
|
||||
# include "config.h"
|
||||
# include "vlog95_priv.h"
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
void emit_scaled_delay(ivl_scope_t scope, uint64_t delay)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
# include <string.h>
|
||||
# include "config.h"
|
||||
# include "vlog95_priv.h"
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
static char*get_time_const(int time_value)
|
||||
{
|
||||
|
|
@ -48,8 +49,7 @@ static char*get_time_const(int time_value)
|
|||
case -14: return "10fs";
|
||||
case -15: return "1fs";
|
||||
default:
|
||||
fprintf(stderr, "Invalid time constant %d\n", time_value);
|
||||
assert(0);
|
||||
fprintf(stderr, "Invalid time constant value %d.\n", time_value);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
|
@ -177,16 +177,98 @@ void emit_net_def(ivl_signal_t sig)
|
|||
}
|
||||
}
|
||||
|
||||
static char *get_mangled_name(ivl_scope_t scope)
|
||||
{
|
||||
char *name;
|
||||
/* If the module has parameters than it may not be unique
|
||||
* so we create a mangled name version instead. */
|
||||
if (ivl_scope_params(scope)) {
|
||||
unsigned idx;
|
||||
size_t len = strlen(ivl_scope_name(scope)) +
|
||||
strlen(ivl_scope_tname(scope)) + 2;
|
||||
name = (char *)malloc(len);
|
||||
(void) strcpy(name, ivl_scope_tname(scope));
|
||||
(void) strcat(name, "_");
|
||||
(void) strcat(name, ivl_scope_name(scope));
|
||||
assert(name[len-1] == 0);
|
||||
for (idx = 0; idx < len; idx += 1) {
|
||||
if (name[idx] == '.') name[idx] = '_';
|
||||
}
|
||||
} else {
|
||||
name = strdup(ivl_scope_tname(scope));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* This search method may be slow for a large structural design with a
|
||||
* large number of gate types. That's not what this converter was built
|
||||
* for so this is probably OK. If this becomes an issue then we need a
|
||||
* better method/data structure.
|
||||
*/
|
||||
static const char **scopes_emitted = 0;
|
||||
static unsigned num_scopes_emitted = 0;
|
||||
|
||||
static unsigned scope_has_been_emitted(ivl_scope_t scope)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < num_scopes_emitted; idx += 1) {
|
||||
if (! strcmp(ivl_scope_tname(scope), scopes_emitted[idx])) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_scope_to_list(ivl_scope_t scope)
|
||||
{
|
||||
num_scopes_emitted += 1;
|
||||
scopes_emitted = realloc(scopes_emitted, num_scopes_emitted *
|
||||
sizeof(char *));
|
||||
scopes_emitted[num_scopes_emitted-1] = ivl_scope_tname(scope);
|
||||
}
|
||||
|
||||
void free_emitted_scope_list()
|
||||
{
|
||||
free(scopes_emitted);
|
||||
scopes_emitted = 0;
|
||||
num_scopes_emitted = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A list of module scopes that need to have their definition emitted when
|
||||
* the current root scope (module) is finished is kept here.
|
||||
*/
|
||||
static ivl_scope_t *scopes_to_emit = 0;
|
||||
static unsigned num_scopes_to_emit = 0;
|
||||
static unsigned emitting_scopes = 0;
|
||||
|
||||
int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
||||
{
|
||||
ivl_scope_type_t sc_type = ivl_scope_type(scope);
|
||||
unsigned is_auto = ivl_scope_is_auto(scope);
|
||||
unsigned idx, count, start = 0;
|
||||
char *name;
|
||||
|
||||
/* Output the scope definition. */
|
||||
switch (sc_type) {
|
||||
case IVL_SCT_MODULE:
|
||||
assert(!is_auto);
|
||||
name = get_mangled_name(scope);
|
||||
/* This is an instantiation. */
|
||||
if (parent) {
|
||||
assert(indent != 0);
|
||||
/* If the module has parameters than it may not be unique
|
||||
* so we create a mangled name version instead. */
|
||||
fprintf(vlog_out, "\n%*c%s %s(", indent, ' ', name,
|
||||
ivl_scope_basename(scope));
|
||||
// HERE: Still need to add port information.
|
||||
fprintf(vlog_out, ");\n");
|
||||
free(name);
|
||||
num_scopes_to_emit += 1;
|
||||
scopes_to_emit = realloc(scopes_to_emit, num_scopes_to_emit *
|
||||
sizeof(ivl_scope_t));
|
||||
scopes_to_emit[num_scopes_to_emit-1] = scope;
|
||||
return 0;
|
||||
}
|
||||
assert(indent == 0);
|
||||
/* Set the time scale for this scope. */
|
||||
fprintf(vlog_out, "\n`timescale %s/%s\n",
|
||||
|
|
@ -195,10 +277,12 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
if (ivl_scope_is_cell(scope)) {
|
||||
fprintf(vlog_out, "`celldefine\n");
|
||||
}
|
||||
fprintf(vlog_out, "module %s", ivl_scope_tname(scope));
|
||||
fprintf(vlog_out, "module %s", name);
|
||||
free(name);
|
||||
// HERE: Still need to add port information.
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*cfunction", indent, ' ');
|
||||
assert(ivl_scope_ports(scope) >= 2);
|
||||
/* The function return information is the zero port. */
|
||||
|
|
@ -213,6 +297,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
}
|
||||
break;
|
||||
case IVL_SCT_TASK:
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*ctask %s", indent, ' ',
|
||||
ivl_scope_tname(scope));
|
||||
if (is_auto) {
|
||||
|
|
@ -224,6 +309,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
break;
|
||||
case IVL_SCT_BEGIN:
|
||||
case IVL_SCT_FORK:
|
||||
assert(indent != 0);
|
||||
return 0; /* A named begin/fork is handled in line. */
|
||||
default:
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type "
|
||||
|
|
@ -282,7 +368,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
ivl_signal_t sig = ivl_scope_sig(scope, idx);
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||
/* Do not output the implicit function return register. */
|
||||
if (sc_type == IVL_SCT_FUNCTION &&
|
||||
if (sc_type == IVL_SCT_FUNCTION &&
|
||||
strcmp(ivl_signal_basename(sig),
|
||||
ivl_scope_tname(scope)) == 0) continue;
|
||||
emit_var_def(sig);
|
||||
|
|
@ -291,6 +377,9 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
}
|
||||
}
|
||||
|
||||
// HERE: Need to find and print any continuous assignments/logic cells or
|
||||
// initial/always blocks.
|
||||
|
||||
/* Output the function/task body. */
|
||||
if (sc_type == IVL_SCT_TASK || sc_type == IVL_SCT_FUNCTION) {
|
||||
emit_stmt(scope, ivl_scope_def(scope));
|
||||
|
|
@ -308,6 +397,25 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
fprintf(vlog_out, "endmodule /* %s */\n", ivl_scope_tname(scope));
|
||||
if (ivl_scope_is_cell(scope)) {
|
||||
fprintf(vlog_out, "`endcelldefine\n");
|
||||
}
|
||||
/* If this is a root scope then emit any saved instance scopes.
|
||||
* Save any scope that does not have parameters/a mangled name
|
||||
* to a list so we don't print duplicate module definitions. */
|
||||
if (!emitting_scopes) {
|
||||
emitting_scopes = 1;
|
||||
for (idx =0; idx < num_scopes_to_emit; idx += 1) {
|
||||
ivl_scope_t scope_to_emit = scopes_to_emit[idx];
|
||||
if (scope_has_been_emitted(scope_to_emit)) continue;
|
||||
(void) emit_scope(scope_to_emit, 0);
|
||||
/* If we used a mangled name then the instance is
|
||||
* unique so don't add it to the list. */
|
||||
if (ivl_scope_params(scope_to_emit)) continue;
|
||||
add_scope_to_list(scope_to_emit);
|
||||
}
|
||||
free(scopes_to_emit);
|
||||
scopes_to_emit = 0;
|
||||
num_scopes_to_emit = 0;
|
||||
emitting_scopes = 0;
|
||||
}
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
|
|
|
|||
|
|
@ -143,7 +143,49 @@ void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
|
||||
static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
assert(0);
|
||||
char *name;
|
||||
unsigned idx, default_case, count = ivl_stmt_case_count(stmt);
|
||||
switch(ivl_statement_type(stmt)) {
|
||||
case IVL_ST_CASE:
|
||||
case IVL_ST_CASER:
|
||||
name = "case";
|
||||
break;
|
||||
case IVL_ST_CASEX:
|
||||
name = "casex";
|
||||
break;
|
||||
case IVL_ST_CASEZ:
|
||||
name = "casez";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
fprintf(vlog_out, "%*c%s (", get_indent(), ' ', name);
|
||||
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
|
||||
fprintf(vlog_out, ")\n");
|
||||
indent += indent_incr;
|
||||
default_case = count;
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_expr_t expr = ivl_stmt_case_expr(stmt, idx);
|
||||
/* This is the default case so emit it last. */
|
||||
if (expr == 0) {
|
||||
assert(default_case == count);
|
||||
default_case = idx;
|
||||
continue;
|
||||
}
|
||||
fprintf(vlog_out, "%*c", get_indent(), ' ');
|
||||
emit_expr(scope, expr, 0);
|
||||
fprintf(vlog_out, ":");
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, ivl_stmt_case_stmt(stmt, idx));
|
||||
}
|
||||
if (default_case < count) {
|
||||
fprintf(vlog_out, "%*cdefault:", get_indent(), ' ');
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, ivl_stmt_case_stmt(stmt, default_case));
|
||||
}
|
||||
assert(indent >= indent_incr);
|
||||
indent -= indent_incr;
|
||||
fprintf(vlog_out, "%*cendcase\n", get_indent(), ' ');
|
||||
}
|
||||
|
||||
static void emit_stmt_cassign(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ int target_design(ivl_design_t des)
|
|||
ivl_design_roots(des, &roots, &nroots);
|
||||
for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0);
|
||||
|
||||
free_emitted_scope_list();
|
||||
|
||||
fclose(vlog_out);
|
||||
|
||||
return vlog_errors;
|
||||
|
|
|
|||
|
|
@ -70,4 +70,9 @@ extern void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned width);
|
|||
*/
|
||||
extern void emit_scaled_delay(ivl_scope_t scope, uint64_t delay);
|
||||
|
||||
/*
|
||||
* Cleanup functions.
|
||||
*/
|
||||
extern void free_emitted_scope_list();
|
||||
|
||||
#endif /* __vlog95_priv_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue