Commit e972b096 authored by Stefan Tauner's avatar Stefan Tauner
Browse files

instrumentation: refine new scheme: defer creation of intermediate net

 - do not create vectored intermediate net if that's not needed.
 - instrument driving ports (almost) correctly
parent c5d3f293
......@@ -526,78 +526,19 @@ sub instrument_net {
# Add an intermediate net to allow patching without rewriting connections everywhere
#
# We use the requested signal as sink/destination.
# That way we only need to change the driver to drive our intermediate net later
# That way we only need to change the driver to drive our intermediate net.
#
# 1.) Choose a suitable name for the tmp net.
# 2.) Generate the tmp net.
# 3.) Assign injected signal from input pin to original signal.
# 4.) If original signal is a bus forward orignal data from tmp net to untouched bits of original signal
# 5.) Forward (injected bit of) intermediate net to FIC by assigning it to the output pin
#
# The only thing that remains to do after that is to switch the driver from the
# original signal to the intermediate net.
# We first generate a suitable name for the intermediate net,
# then change the driver accordingly and handle other aspects of
# the intermediate net at the very bottom of this function.
# 1.) Choose intermediate net name
# Choose intermediate net name
my $net_name_tmp = _sanitize_identifier(FIJI_NAMESPACE_PREFIX . $net_name . "_in_tmp");
my $msg = _check_name_in_hierarchy($mod, $net_name_tmp);
my $net_tmp;
# If the name is already taken then assume we need to instrument another bit of a bus
# FIXME: maybe we should try harder to find out the reason why _check_name_in_hierarchy failed
if (defined($msg)) {
if (!defined($net->msb)) {
my $err = "Tried to instrument non-vector signal (\"$net_name\") twice or we really have a naming conflict.";
$logger->error($err);
return $err;
}
$net_tmp = $mod->find_net($net_name_tmp);
# We need to undo the previous assignment of the respective bit
foreach my $statement ($mod->statements) {
if ($statement->rhs =~ /^[ \t]*~?[ \t]*\Q$net_name_tmp\E(\[(\Q$msb\E)\])?$/) {
$logger->debug(" unassigning \"" . $statement->lhs . " = " . $statement->rhs . "\"");
$statement->delete();
}
}
$logger->debug(" reassigning \"" . $net_name."[".$msb."] = " . $ip->net->name . "\"");
generate_contassign($mod, $net_name."[".$msb."]", $ip->net->name);
} else {
# 2.) Generate intermediate (tmp) nets for easier input and output routing
$logger->debug("Generating intermediate wire named \"" . $net_name_tmp . "\" to patch \"$net_name\"");
$net_tmp = $mod->new_net(
name => $net_name_tmp,
msb => $net->msb,
lsb => $net->lsb,
);
# 3+4.) Assign injected (and uninjected bits of vectors) to previous signal.
# Below we assign the altered signal from the FIC to the original signal.
# For busses we need to connect all non-instrumented bits of the tmp net
# additionally to preserve their unmodified values.
if (!defined($net->msb)) {
generate_contassign($mod, $net_name, $ip->net->name);
} else {
my ($low, $high) = _extract_low_high($net->lsb, $net->msb);
for (my $i = $low ; $i <= $high ; $i++) {
if ($i == $msb) {
generate_contassign($mod, $net_name."[".$i."]", $ip->net->name);
} else {
generate_contassign($mod, $net_name."[".$i."]", $net_name_tmp."[".$i."]");
}
}
}
}
my $name_check = _check_name_in_hierarchy($mod, $net_name_tmp);
# 5.) Connect the tmp net to the output pin that forwards the signal to the FIC
if (!defined($net->msb)) {
$logger->debug(" assigning \"" . $op->net->name . " = " . $net_name_tmp . "\"");
generate_contassign($mod, $op->net->name, $net_name_tmp);
} else {
$logger->debug(" assigning \"" . $op->net->name . " = " . $net_name_tmp ."[".$msb."]\"");
generate_contassign($mod, $op->net->name, $net_name_tmp."[".$msb."]");
}
# connecting newly created output to driver
# Switch the driver from the original signal to the intermediate net.
my $driver_is_vector = 0;
my $driver_is_port = 0;
foreach my $connection (@{$connections{'drivers'}}) {
if (ref($connection) eq "Verilog::Netlist::Pin") {
# If the driver is a pin of a (sub)cell, connect this pin to the intermediate net
......@@ -605,14 +546,33 @@ sub instrument_net {
# FIXME: do concatenations really work? They are apparently split already by Verilog::perl but...
for my $netname (@{$connection->netnames}) {
if ($netname->{'netname'} eq $net->name) {
$netname->{'netname'} = $net_name_tmp;
$netname->{'netname'} = $net_name_tmp; # FIXME: do we need to force a re-link (by deleting $connection->nets)?
# This net is a vector if the underlying net is a bus and we do not just select a single bit
if (defined($net->msb) || (!defined($netname->{'msb'}) || $netname->{'msb'} != $netname->{'lsb'})) {
$driver_is_vector = 1;
}
}
}
# $connection->port(undef); # resolved by link
} else {
if (ref($connection) eq "Verilog::Netlist::Port") {
# If the driver is a port of a module, connect this port to the intermediate net
$driver_is_port = 1;
# If instrumented net is a vector we will need an intermediate bus
if (defined($net->msb)) {
$driver_is_vector = 1;
# If port is vector change type of existing non-instrumented input to wire -
# practically transforming it to an ordinary wire that can easily be intrumented
$connection->net->net_type("wire");
$connection->net->port(undef);
$logger->debug("Transforming previous port named \"". $connection->name . "\" into an ordinary wire");
}
# FIXME: rename port in instantiation of current module
$logger->warn("Instantiation of module \"" . $mod->name . "\" needs to change port \"" . $connection->name . "\" to \"$net_name_tmp\" - not supported yet...");
# if ($mod->is_top) {
# FIXME: add naming information for wrapper generator
# } else {
# }
# Eventually connect this port to the intermediate net by changing its name
$logger->debug("Connecting (input) port \"" . $connection->name . "\" to intermediate net \"$net_name_tmp\"");
$connection->name($net_name_tmp);
} elsif (ref($connection) eq "Verilog::Netlist::ContAssign") {
......@@ -635,11 +595,20 @@ sub instrument_net {
$logger->fatal("Found port name in continuous assignment. This is not supported yet.");
return "BORKED";
}
if (!defined($lhs_net->msb)) {
# If the signal in LHS is not a vector at all we simply drive the new port instead, easy.
$logger->debug("Connecting to intermediate net \"" . $net_name_tmp . "\" the continuous assignment of \"" . $connection->rhs . "\"");
$connection->lhs($net_name_tmp);
} else {
my $rhs_elems = $self->_extract_netstring_elements($connection->rhs);
my $rhs_net_name = $rhs_elems->{'net_name'};
my $rhs_net = $mod->find_net($rhs_net_name);
# If driver is a vector we need a vectored intermediate bus.
# This is the case if on the RHS
# - the underlying net is a vector and there are no indices
# - the underlying net is a vector and there are two different indices
if (defined($rhs_net->msb) && (!defined($rhs_elems->{'msb'}) || ($rhs_elems->{'msb'} != $rhs_elems->{'msb'}))) {
$driver_is_vector = 1;
}
$logger->debug("Connecting to intermediate net \"" . $net_name_tmp . "\" the continuous assignment of \"" . $connection->rhs . "\"");
$connection->lhs($net_name_tmp);
if(1) {} else {
# If LHS is a bus however we need to drive the bit we want to instrument only
$logger->debug("Connecting to intermediate net \"" . $net_name_tmp."[".$msb."]" . "\" the continuous assignment of \"" . $connection->rhs . "\"");
$connection->lhs($net_name_tmp."[".$msb."]");
......@@ -653,6 +622,87 @@ sub instrument_net {
}
}
# Below we create the intermediate net as needed.
# A suitable name for the tmp net was already determined.
# 1.) Generate the tmp net.
# 2.) Assign injected signal from input pin to original signal.
# 3.) If original signal is a bus forward orignal data from tmp net to untouched bits of original signal
# 4.) Forward (injected bit of) intermediate net to FIC by assigning it to the output pin
#
my $net_tmp;
# If the name is already taken then assume we need to instrument another bit of a bus
# FIXME: maybe we should try harder to find out the reason why _check_name_in_hierarchy failed
if (defined($name_check)) {
if (!defined($net->msb)) {
my $err = "Tried to instrument non-vector signal (\"$net_name\") twice or we really have a naming conflict.";
$logger->error($err);
return $err;
}
$net_tmp = $mod->find_net($net_name_tmp);
# We need to undo the previous assignment of the respective bit
foreach my $statement ($mod->statements) {
if ($statement->rhs =~ /^[ \t]*~?[ \t]*\Q$net_name_tmp\E(\[(\Q$msb\E)\])?$/) {
$logger->debug(" unassigning \"" . $statement->lhs . " = " . $statement->rhs . "\"");
$statement->delete();
}
}
$logger->debug(" reassigning \"" . $net_name."[".$msb."] = " . $ip->net->name . "\"");
generate_contassign($mod, $net_name."[".$msb."]", $ip->net->name);
} else {
# 2.) Generate intermediate (tmp) net for easier input and output routing
# If the driver is a vector then we will generate a vectored intermediate net as well.
# However, if the driver is a single-bit net or a single bit of a vector we get away
# without an intermediate net.
my @net_cfg = (name => $net_name_tmp);
push(@net_cfg, net_type => 'input') if $driver_is_port;
if ($driver_is_vector) {
$logger->debug("Generating intermediate " . ($driver_is_port ? 'port' : 'wire') . " named \"" . $net_name_tmp . "[" . $net->msb .":". $net->lsb . "]\" to patch \"$net_name\"");
push(@net_cfg,
msb => $net->msb,
lsb => $net->lsb,
);
} else {
$logger->debug("Generating intermediate " . ($driver_is_port ? 'port' : 'wire') . " named \"" . $net_name_tmp . "\" to patch \"$net_name\"");
}
$net_tmp = $mod->new_net(@net_cfg,);
# 3+4.) Assign injected (and uninjected bits of vectors) to previous signal.
# Below we assign the altered signal from the FIC to the original signal.
# For busses we need to connect all non-instrumented bits of the tmp net
# additionally to preserve their unmodified values.
if (!defined($net->msb)) {
# If the instrumented net is not a vector we simply assign the injected signal
generate_contassign($mod, $net_name, $ip->net->name);
} elsif (!defined($net_tmp->msb)) {
# If the net is a vector but the driver was driving only one bit
# then we need to drive the originally driven bit only
generate_contassign($mod, $net_name."[".$msb."]", $ip->net->name);
} else {
# For drivers of complete busses we need to connect all non-instrumented bits of the tmp net
# additionally to preserve their unmodified values.
my ($low, $high) = _extract_low_high($net_tmp->lsb, $net_tmp->msb);
for (my $i = $low ; $i <= $high ; $i++) {
if ($i == $msb) {
generate_contassign($mod, $net_name."[".$i."]", $ip->net->name);
} else {
generate_contassign($mod, $net_name."[".$i."]", $net_name_tmp."[".$i."]");
}
}
}
}
# 5.) Connect the tmp net to the output pin that forwards the signal to the FIC
if (!defined($net_tmp->msb)) {
$logger->debug(" assigning \"" . $op->net->name . " = " . $net_name_tmp . "\"");
generate_contassign($mod, $op->net->name, $net_name_tmp);
} else {
$logger->debug(" assigning \"" . $op->net->name . " = " . $net_name_tmp ."[".$msb."]\"");
generate_contassign($mod, $op->net->name, $net_name_tmp."[".$msb."]");
}
$mod->link;
return undef;
}
......@@ -1004,7 +1054,8 @@ sub _get_net_connections {
next;
}
$logger->debug(" pin (" . ((defined($pin->port) && $pin->port->direction eq 'in') ? "in" : "out") . ") \"" . $pin->cell->name . HIERSEP . $pin->name . "\"");
my $dir = (!defined($pin->port)) ? "unknown" : ($pin->port->direction eq 'in') ? "in" : "out";
$logger->debug(" pin (" . $dir . ") \"" . $pin->cell->name . HIERSEP . $pin->name . "\"");
# The pin might be the driver but we can't be sure without a preselection.
# However, we can note that it is connected for sure.
# FIXME: is that really the case? In case we know the direction we can make a pretty well educated guess, no? :)
......@@ -1146,7 +1197,7 @@ sub _extract_netpath_elements {
# @param net_descriptor (optional) a hashref to store found elements into
#
# @returns STRING if an error occurred
# @returns HASHREF with the keys 'mod_name', 'net_name' if successful (and no net_elems is given).
# @returns HASHREF with the keys 'net_name', 'msb', 'lsb', 'prefix' if successful (and no net_elems is given).
# @returns undef if successful and net_elems is given
sub _extract_netstring_elements {
my $logger = get_logger("");
......@@ -1156,18 +1207,20 @@ sub _extract_netstring_elements {
return "Can not parse an empty net.";
}
$net_string =~ /(.*?)(\[([^:]+)(:(.*))?\])?$/;
my $net_name = $1;
my $msb = $3;
my $lsb = defined($5) ? $5 : $3;
$net_string =~ /(~)?(.*?)(\[([^:]+)(:(.*))?\])?$/;
my $prefix = $1;
my $net_name = $2;
my $msb = $4;
my $lsb = defined($6) ? $6 : $4;
if (defined($net_descriptor)) {
$net_descriptor->{net_name} = $net_name;
$net_descriptor->{prefix} = $prefix;
$net_descriptor->{lsb} = $lsb;
$net_descriptor->{msb} = $msb;
return undef;
}
return {'net_name' => $net_name, 'lsb' => $lsb, 'msb' => $msb};
return {'net_name' => $net_name, 'prefix' => $prefix, 'lsb' => $lsb, 'msb' => $msb};
}
## @method public get_net_from_path($netpath)
......@@ -1234,9 +1287,9 @@ sub get_netdescriptor_from_path {
}
if (!defined($lsb)) {
$logger->trace("Determined netpath \"" . $net->name . "\" to be a single-bit signal.");
$logger->trace("Determined netpath \"" . $netpath . "\" to be a single-bit signal.");
} else {
$logger->trace("Determined netpath \"" . $net->name . "\" to be a vector with lsb = $lsb and msb = $msb.");
$logger->trace("Determined netpath \"" . $netpath . "\" to be a vector with lsb = $lsb and msb = $msb.");
}
return $net_descr;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment