vlog95: Add code to output specify block path delays.
There are limitations with this since the compiler does not pass all the information that was present in the original source, but it is enough to get a valid simulation result. It is not enough for timing analysis! specparams are also incorrectly translated to parameters so they show up in the wrong place.
This commit is contained in:
parent
69705ef32b
commit
1b36aa5560
|
|
@ -665,6 +665,125 @@ static int emit_tf_process(ivl_scope_t scope, ivl_scope_t parent)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void emit_path_delay(ivl_scope_t scope, ivl_delaypath_t dpath)
|
||||||
|
{
|
||||||
|
unsigned idx, count = 6;
|
||||||
|
uint64_t pdlys [12];
|
||||||
|
pdlys[0] = ivl_path_delay(dpath, IVL_PE_01);
|
||||||
|
pdlys[1] = ivl_path_delay(dpath, IVL_PE_10);
|
||||||
|
pdlys[2] = ivl_path_delay(dpath, IVL_PE_0z);
|
||||||
|
pdlys[3] = ivl_path_delay(dpath, IVL_PE_z1);
|
||||||
|
pdlys[4] = ivl_path_delay(dpath, IVL_PE_1z);
|
||||||
|
pdlys[5] = ivl_path_delay(dpath, IVL_PE_z0);
|
||||||
|
pdlys[6] = ivl_path_delay(dpath, IVL_PE_0x);
|
||||||
|
pdlys[7] = ivl_path_delay(dpath, IVL_PE_x1);
|
||||||
|
pdlys[8] = ivl_path_delay(dpath, IVL_PE_1x);
|
||||||
|
pdlys[9] = ivl_path_delay(dpath, IVL_PE_x0);
|
||||||
|
pdlys[10] = ivl_path_delay(dpath, IVL_PE_xz);
|
||||||
|
pdlys[11] = ivl_path_delay(dpath, IVL_PE_zx);
|
||||||
|
/* If the first six pdlys match then this may be a 1 delay form. */
|
||||||
|
if ((pdlys[0] == pdlys[1]) &&
|
||||||
|
(pdlys[0] == pdlys[2]) &&
|
||||||
|
(pdlys[0] == pdlys[3]) &&
|
||||||
|
(pdlys[0] == pdlys[4]) &&
|
||||||
|
(pdlys[0] == pdlys[5])) count = 1;
|
||||||
|
/* Check to see if only a rise and fall value are given for the first
|
||||||
|
* six pdlys. */
|
||||||
|
else if ((pdlys[0] == pdlys[2]) &&
|
||||||
|
(pdlys[0] == pdlys[3]) &&
|
||||||
|
(pdlys[1] == pdlys[4]) &&
|
||||||
|
(pdlys[1] == pdlys[5])) count = 2;
|
||||||
|
/* Check to see if a rise, fall and high-Z value are given for the
|
||||||
|
* first six pdlys. */
|
||||||
|
else if ((pdlys[0] == pdlys[3]) &&
|
||||||
|
(pdlys[1] == pdlys[5]) &&
|
||||||
|
(pdlys[2] == pdlys[4])) count = 3;
|
||||||
|
/* Now check to see if the 'bx related pdlys match the reduced
|
||||||
|
* delay form. If not then this is a twelve delay value. */
|
||||||
|
if ((pdlys[6] != ((pdlys[0] < pdlys[2]) ? pdlys[0] : pdlys[2])) ||
|
||||||
|
(pdlys[8] != ((pdlys[1] < pdlys[4]) ? pdlys[1] : pdlys[4])) ||
|
||||||
|
(pdlys[11] != ((pdlys[3] < pdlys[5]) ? pdlys[3] : pdlys[5])) ||
|
||||||
|
(pdlys[7] != ((pdlys[0] > pdlys[3]) ? pdlys[0] : pdlys[3])) ||
|
||||||
|
(pdlys[9] != ((pdlys[1] > pdlys[5]) ? pdlys[1] : pdlys[5])) ||
|
||||||
|
(pdlys[10] != ((pdlys[2] > pdlys[4]) ? pdlys[2] : pdlys[4]))) {
|
||||||
|
count = 12;
|
||||||
|
}
|
||||||
|
emit_scaled_delay(scope, pdlys[0]);
|
||||||
|
for(idx = 1; idx < count; idx += 1) {
|
||||||
|
fprintf(vlog_out, ", ");
|
||||||
|
emit_scaled_delay(scope, pdlys[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_specify_paths(ivl_scope_t scope, ivl_signal_t sig)
|
||||||
|
{
|
||||||
|
unsigned idx, count = ivl_signal_npath(sig);
|
||||||
|
for(idx = 0; idx < count; idx += 1) {
|
||||||
|
ivl_delaypath_t dpath = ivl_signal_path(sig, idx);
|
||||||
|
ivl_nexus_t cond = ivl_path_condit(dpath);
|
||||||
|
ivl_nexus_t source = ivl_path_source(dpath);
|
||||||
|
unsigned has_edge = 0;
|
||||||
|
fprintf(vlog_out, "%*c", indent, ' ');
|
||||||
|
if (cond) {
|
||||||
|
fprintf(vlog_out, "if (");
|
||||||
|
emit_nexus_as_ca(scope, cond, 0);
|
||||||
|
fprintf(vlog_out, ") ");
|
||||||
|
} else if (ivl_path_is_condit(dpath)) {
|
||||||
|
fprintf(vlog_out, "ifnone ");
|
||||||
|
}
|
||||||
|
fprintf(vlog_out, "(");
|
||||||
|
if (ivl_path_source_posedge(dpath)) {
|
||||||
|
fprintf(vlog_out, "posedge ");
|
||||||
|
has_edge = 1;
|
||||||
|
}
|
||||||
|
if (ivl_path_source_negedge(dpath)) {
|
||||||
|
fprintf(vlog_out, "negedge ");
|
||||||
|
has_edge = 1;
|
||||||
|
}
|
||||||
|
emit_nexus_as_ca(scope, source, 0);
|
||||||
|
fprintf(vlog_out, " =>");
|
||||||
|
/* The compiler does not keep the source expression for an edge
|
||||||
|
* sensitive path so add a constant to get the syntax right. */
|
||||||
|
if (has_edge) {
|
||||||
|
fprintf(vlog_out, "(%s : 1'bx /* Missing */)",
|
||||||
|
ivl_signal_basename(sig));
|
||||||
|
} else {
|
||||||
|
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
||||||
|
}
|
||||||
|
fprintf(vlog_out, ") = (");
|
||||||
|
emit_path_delay(scope, dpath);
|
||||||
|
fprintf(vlog_out, ");\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The path delay information from the specify block is attached to the
|
||||||
|
* output ports.
|
||||||
|
*/
|
||||||
|
static void emit_specify(ivl_scope_t scope)
|
||||||
|
{
|
||||||
|
unsigned word, idx, count = ivl_scope_ports(scope);
|
||||||
|
unsigned need_specify = 0;
|
||||||
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
|
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
|
||||||
|
ivl_signal_t port = get_port_from_nexus(scope, nex, &word);
|
||||||
|
// HERE: Do we need to use word? See emit_module_port_def().
|
||||||
|
assert(port);
|
||||||
|
if (ivl_signal_npath(port)) {
|
||||||
|
if (! need_specify) {
|
||||||
|
fprintf(vlog_out, "\n%*cspecify\n", indent, ' ');
|
||||||
|
need_specify = 1;
|
||||||
|
indent += indent_incr;
|
||||||
|
}
|
||||||
|
emit_specify_paths(scope, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (need_specify) {
|
||||||
|
indent -= indent_incr;
|
||||||
|
fprintf(vlog_out, "%*cendspecify\n", indent, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This search method may be slow for a large structural design with a
|
* 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
|
* large number of gate types. That's not what this converter was built
|
||||||
|
|
@ -852,9 +971,12 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
||||||
emit_stmt(scope, ivl_scope_def(scope));
|
emit_stmt(scope, ivl_scope_def(scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now print out any sub-scopes. */
|
/* Print any sub-scopes. */
|
||||||
ivl_scope_children(scope, (ivl_scope_f*) emit_scope, scope);
|
ivl_scope_children(scope, (ivl_scope_f*) emit_scope, scope);
|
||||||
|
|
||||||
|
/* And finally print a specify block when needed. */
|
||||||
|
if (sc_type == IVL_SCT_MODULE) emit_specify(scope);
|
||||||
|
|
||||||
/* Output the scope ending. */
|
/* Output the scope ending. */
|
||||||
assert(indent >= indent_incr);
|
assert(indent >= indent_incr);
|
||||||
indent -= indent_incr;
|
indent -= indent_incr;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue