Commit 1fbbae33 authored by Christian Fibich's avatar Christian Fibich Committed by Stefan Tauner
Browse files

Started with instrumentation script

parent 7091bb53
......@@ -11,6 +11,14 @@ use warnings;
use Log::Log4perl qw(get_logger :easy);
use Verilog::Netlist;
use Data::Dumper;
use FIJI::VHDL;
my $HIERSEP = "|";
my $FIJI_PORT_PREFIX = "fiji_";
my $FIJI_PORT_IN_POSTFIX = "_inj_i";
my $FIJI_PORT_OUT_POSTFIX = "_ori_o";
sub new ($) {
......@@ -23,6 +31,7 @@ sub new ($) {
# options => $opt,
# keep_comments => 1, # include comments in netlist
link_read_nonfatal => 1, # do not fail if module description not found
use_vars => 1,
);
return $self;
}
......@@ -58,37 +67,281 @@ sub get_nets ($) {
# my $nets_ref = {'metadata' => [], 'names' => [], 'nets' => []};
my $nets_ref = [];
foreach my $mod ($self->{'nl'}->top_modules_sorted) {
$self->_get_subnets($nets_ref, $mod);
$self->_get_subnets($nets_ref, $mod,"");
}
return $nets_ref;
}
sub _get_subnets ($$) {
my ($self, $nets_ref, $mod) = @_;
my ($self, $nets_ref, $mod, $hier) = @_;
$hier .= $HIERSEP if $hier ne "";
$hier .= $mod->name;
foreach my $n ($mod->nets) {
if ((defined $n->msb && defined $n->lsb)) {
print "Net ".$mod->name.".".$n->name." is bussed [".$n->msb.":".$n->lsb."]\n";
print "Net ".$hier.$HIERSEP.$n->name." is bussed [".$n->msb.":".$n->lsb."]\n";
for (my $i = $n->lsb; $i <= $n->msb; $i++) {
push(@{$nets_ref}, $n->name."[$i]");
push(@{$nets_ref}, $hier.$HIERSEP.$n->name."[$i]");
}
} else {
push(@{$nets_ref}, $n->name);
push(@{$nets_ref}, $hier.$HIERSEP.$n->name);
}
#$self->_get_possible_drivers($n,$mod);
#$self->_get_net_connections($n,$mod,$hier);
}
foreach my $cell ($mod->cells_sorted) {
if (defined($cell->submod)) {
$self->_get_subnets($nets_ref, $cell->submod);
$self->_get_subnets($nets_ref, $cell->submod,$hier);
}
}
}
sub _get_possible_drivers ($$) {
my ($self,$net,$mod) = @_;
# checks if a givn name exists as port, net, or cell name in the instantiation
# tree.
#
# params:
# startmod the module to start with
# name the name to check against
#
sub _check_name_in_hierarchy {
my ($startmod,$name) = @_;
my $nl = $startmod->netlist;
print "Checking ".$startmod->name." for name $name\n";
# check if a net is named the same
for my $net ($startmod->nets_sorted) {
if ($net->name eq $name) {
print "Name $name does already exist as net in ".$startmod->name."\n";
return 1;
}
}
# check if a port is named the same
for my $port ($startmod->ports_sorted) {
if ($port->name eq $name) {
print "Name $name does already exist as port in ".$startmod->name."\n";
return 1;
}
}
for my $cell ($startmod->cells_sorted) {
if ($cell->name eq $name) {
print "Name $name does already exist as cell in ".$startmod->name."\n";
return 1;
}
}
# find any module instantiating the current start module
foreach my $mod ($nl->modules_sorted) {
foreach my $cell ($mod->cells_sorted) {
if(defined $cell->submod && $cell->submod == $startmod) {
return 1 if _check_name_in_hierarchy($mod,$name);
}
}
}
return 0;
}
# adds a port to all modules starting from a leaf node
#
# params
# startmod the module to start with
# name the port name to be generated
# function the function of this port in FIJI (FIJI::VHDL->FIJI_PORTTYPE_xxx)
# index for ORIGINAL,MODIFIED and FAULT_DETECT: the index of this net
# (indent just for formatting output)
sub _add_port_to_hierarchy($$$;$) {
my ($startmod,$name,$function,$index,$indent) = @_;
my $nl = $startmod->netlist;
my $direction = "undef";
if(!defined $indent) {
$indent = "";
} else {
$indent .= " ";
}
return if($startmod->find_port($name));
print $indent."Adding port $name to module ".$startmod->name."\n";
# decide direction
if ($function == FIJI::VHDL->FIJI_PORTTYPE_MODIFIED) {
$direction = "in";
} elsif ($function == FIJI::VHDL->FIJI_PORTTYPE_ORIGINAL ||
$function == FIJI::VHDL->FIJI_PORTTYPE_FAULT_DETECTION ||
$function == FIJI::VHDL->FIJI_PORTTYPE_TRIGGER_FROM_DUT ||
$function == FIJI::VHDL->FIJI_PORTTYPE_RESET_FROM_DUT) {
$direction = "out";
}
# generate port
my $np = $startmod->new_port(name=>$name,direction=>$direction);
# set port type for wrapper generation
$np->userdata(FIJI::VHDL->FIJI_USERDATA_PORTTYPE,$function);
# set indices
if ($function == FIJI::VHDL->FIJI_PORTTYPE_MODIFIED ||
$function == FIJI::VHDL->FIJI_PORTTYPE_ORIGINAL) {
$np->userdata(FIJI::VHDL->FIJI_USERDATA_FIU_INDEX,$index);
} elsif ($function == FIJI::VHDL->FIJI_PORTTYPE_FAULT_DETECTION) {
$np->userdata(FIJI::VHDL->FIJI_USERDATA_FD_INDEX,$index);
}
$nl->link;
# find all modules instantiating the current module
foreach my $mod ($nl->modules_sorted) {
foreach my $cell ($mod->cells_sorted) {
if(defined $cell->submod && $cell->submod == $startmod) {
print $indent."Adding pin $name to cell ".$cell->name."\n";
print $indent."Connecting pin ".$cell->name.$HIERSEP.$name." to port ".$np->module->name.$HIERSEP.$np->name."\n";
$cell->new_pin(name=>$name,
port=>$np,netname=>$np->net->name);
$nl->link;
_add_port_to_hierarchy($mod,$name,$function,$index,$indent);
}
}
}
return $np;
}
# generates external access to a specified net
# params
# net the net to instrument
# driver the driver of this net (can be pin, port or contassign)
# fiu_idx the FIU # this external access shall be connected to
sub instrument_net ($$$) {
#FIXME only works with single-bit pins/ports/nets
my ($self,$net,$driver,$fiu_idx) = @_;
my $msg;
my $logger = get_logger();
print "Instrumenting ".$net->module->name.", net ".$net->name."\n";
my %connections;
$self->_get_net_connections($net,\%connections);
if(@{$connections{'drivers'}} == 0) {
foreach my $connection (@{$connections{'connected'}}) {
if($connection == $driver) {
push @{$connections{'drivers'}},$connection;
} else {
push @{$connections{'driven'}},$connection;
}
}
} elsif(@{$connections{'drivers'}} == 1) {
if(@{$connections{'drivers'}}[0] != $driver) {
$msg = "Driver mismatch on net ".$net->name;
return 0;
}
} else {
$msg = "Net ".$net->name." has multiple drivers";
return 0;
}
if(@{$connections{'drivers'}} == 0) {
$msg = "No driver for net ".$net->name;
return 0;
}
my $output_name = (($FIJI_PORT_PREFIX.$net->name.$FIJI_PORT_OUT_POSTFIX) =~ s/__/_/gr);
my $input_name = (($FIJI_PORT_PREFIX.$net->name.$FIJI_PORT_IN_POSTFIX) =~ s/__/_/gr);
return 0 if(_check_name_in_hierarchy($net->module,$output_name) == 1);
print $output_name." can be used as fiji connector.\n";
my $op = _add_port_to_hierarchy($net->module,$output_name,FIJI::VHDL->FIJI_PORTTYPE_ORIGINAL,$fiu_idx);
return 0 if(_check_name_in_hierarchy($net->module,$input_name) == 1);
print $input_name." can be used as fiji connector.\n";
my $ip = _add_port_to_hierarchy($net->module,$input_name,FIJI::VHDL->FIJI_PORTTYPE_MODIFIED,$fiu_idx);
print "Original: Connecting\n";
foreach my $connection (@{$connections{'drivers'}}) {
print " ";
if(ref($connection) eq "Verilog::Netlist::Pin") {
print "pin ".$connection->cell->name.$HIERSEP.$connection->name;
$connection->netname($op->net->name);
$connection->net($op->net);
} elsif (ref($connection) eq "Verilog::Netlist::Port") {
print "port ".$connection->name;
$connection->net($op->net);
} elsif (ref($connection) eq "Verilog::Netlist::Contassign") {
$connection->rhs($connection->rhs =~ s/^\Q$net->name\E$/oip->net->name/r);
print "assignment ".$connection->lhs;
}
print " to generated output ".$op->name.".\n";
$self->{'nl'}->link;
}
print "Modified: Connecting\n";
foreach my $connection (@{$connections{'driven'}}) {
print " ";
if(ref($connection) eq "Verilog::Netlist::Pin") {
print "pin ".$connection->cell->name.$HIERSEP.$connection->name;
$connection->netname($ip->net->name);
$connection->net($ip->net);
} elsif (ref($connection) eq "Verilog::Netlist::Port") {
print "port ".$connection->module->name.$HIERSEP.$connection->name;
$net->module->new_contassign (keyword => "assign",
lhs => $connection->name,
rhs => $ip->name,
module => $net->module,
netlist => $net->module->netlist);
} elsif (ref($connection) eq "Verilog::Netlist::Contassign") {
$connection->lhs($connection->lhs =~ s/\Q$net->name\E)?$/$ip->net->name/r);
print "assignment ".$connection->rhs;
}
print " to generated input ".$ip->name.".\n";
$self->{'nl'}->link;
}
return 1;
}
# prints the type of a connection
#
# params
# connection the connection to print
sub _print_connection($) {
my ($connection) = @_;
if(ref($connection) eq "Verilog::Netlist::Pin") {
print "pin: ".$connection->cell->name.$HIERSEP.$connection->name."\n";
} elsif (ref($connection) eq "Verilog::Netlist::Port") {
print "port: ".$connection->module->name.$HIERSEP.$connection->name."\n";
} elsif (ref($connection) eq "Verilog::Netlist::Contassign") {
print "assign: ".$connection->lhs."\n";
}
}
# gets all pins, ports and assignments a net is connected to
# currently only works for single-bit signals and instantiations not using
# buses and concatenations
#
# params
# net the net to be examined
# connection_hashref a hashref where the results can be placed
sub _get_net_connections ($$) {
my ($self,$net,$connection_hashref) = @_;
my $mod = $net->module;
my $connections = $connection_hashref;
my @drivers = ();
my @driven = ();
my @connected = ();
my $debug = 0;
# FIXME what to do with bussed nets
# FIXME what to do with something like that:
# input [5:0]p_nbus_byte_controller_c_state ;
# FIXME what to do with instantiations like that (concatenated nets):
# input [5:0] p_nbus_byte_controller_c_state ;
# ...
# .p_nbus_byte_controller_c_state (
# {byte_controller_c_state[5],byte_controller_c_state[3]
......@@ -106,39 +359,50 @@ sub _get_possible_drivers ($$) {
}
foreach my $netname (@nnms) {
print "Net ".$mod->name.".".$netname.", possible drivers:\n";
if($netname =~ m/.+\[([0-9]+)\]/) {
my $idx = $1;
}
my $bn = $net->name;
print "Net ".$mod->name.$HIERSEP.$netname.", connections:\n" if $debug;
# find nets driven by continuous assignment (e.g., constant or inverter)
foreach my $statement ($mod->statements) {
if($statement->lhs eq $netname) {
# continuous assign statement to this net, there can't be another driver
print " assign: ".$mod->name.": ".$netname." = ".$statement->rhs."\n";
return;
print " assign: ".$mod->name.": ".$netname." = ".$statement->rhs."\n" if $debug;
push @drivers,$statement;
} elsif ($statement->rhs =~ /\Q$netname\E$/) {
push @driven,$statement;
}
}
# find nets driven by this module's input ports
foreach my $port ($mod->ports_sorted) {
if (defined $port->net && $port->direction ne "out") {
if ($port->net->name eq $netname) {
print " port: ".$mod->name.".".$port->name."\n" ;
return if ($port->direction eq "in")
} elsif ($port->net->name =~ m/\Q$netname\E/) {
print " also possible port: ".$mod->name.".".$port->name."\n" ;
}
if (defined $port->net && ($port->net->name eq $netname)) {
print " port: ".$mod->name.$HIERSEP.$port->name."\n" if $debug ;
# driven from an input, there can't be another driver
}
if ($port->direction eq "in") {
push @drivers,$port;
} elsif ($port->direction eq "out") {
push @driven,$port;
} elsif ($port->direction eq "inout") {
push @connected,$port;
}
}
}
# find nets driven by other cells output ports
# find nets driven by other cells output pins
foreach my $cell ($mod->cells_sorted) {
foreach my $pin ($cell->pins_sorted) {
if ($pin->netname eq $netname) {
print " pin: ".$mod->name.".".$pin->cell->name.".".$pin->name."\n";
} elsif ($pin->netname =~ m/\Q$netname\E/) {
print " also possible pin: ".$mod->name.".".$pin->cell->name.".".$pin->name."\n";
print " pin ".$pin->cell->name.$HIERSEP.$pin->name."\n" if $debug;
push @connected,$pin;
}
}
}
}
}
$connections->{'drivers'} = \@drivers;
$connections->{'driven'} = \@driven;
$connections->{'connected'} = \@connected;
}
1;
; Config::Simple 4.58
; Thu May 28 16:06:37 2015
[FIU1]
FAULT_MODEL=RUNTIME
NET_NAME=a
LFSR_MASK=0x0
[FIU0]
FAULT_MODEL=RUNTIME
NET_NAME=a
LFSR_MASK=0x0
; Mon Jun 8 12:41:48 2015
[CONSTS]
TRIGGER_EXT_ACTIVE=1
TIMER_WIDTH=32
LFSR_WIDTH=16
TRIGGER_DUT_NAME=bb
RESET_DUT_IN_ACTIVE=1
RESET_DUT_IN_EN=0
TRIGGER_DUT_ACTIVE=1
TRIGGER_EXT_EN=0
RESET_EXT_EN=0
CFGS_PER_MSG=2
RESET_DUT_IN_DURATION=4
FIU_NUM=1
TRIGGER_DUT_EN=0
CLOCK_NET=clk
RESET_DUT_IN_NAME=bla
FIU_CFG_BITS=3
FREQUENCY=20000000
ID=0x123
RESET_DUT_OUT_NAME=bla
RESET_EXT_ACTIVE=1
RESET_DUT_OUT_ACTIVE=1
LFSR_SEED=0xcafe
FIU_NUM=2
LFSR_POLY=0x2d
FREQUENCY=50000000
BAUDRATE=115200
FIU_CFG_BITS=3
RESET_DUT_IN_EN=0
LFSR_POLY=0x2d
CFGS_PER_MSG=2
RESET_DUT_OUT_EN=0
RESET_EXT_EN=0
TRIGGER_EXT_EN=0
[FIU0]
FAULT_MODEL=RUNTIME
LFSR_MASK=0x0
NET_NAME=i2c_master_top|i2c_master_byte_ctrl|N_152_tz
......@@ -4,27 +4,97 @@ use strict;
use warnings;
use Log::Log4perl qw(get_logger);
# use FIJI::Settings;
use FIJI::Netlist;
use Clone qw(clone);
use FIJI::Settings;
use FIJI::Netlist;
use Data::Dumper;
sub main {
my $logger = get_logger();
my $nl = new FIJI::Netlist();
if ($nl->read_file("input.v") != 0) {
my $name = $0;
$name =~ s/\.p[lm]//;
$logger->debug("=== Starting new execution of $name ===");
$logger->debug(sprintf("%d argument(s)%s", scalar(@_), scalar(@_) > 0 ? ": @_" : ""));
my $msg;
my %hash;
my $self = bless(\%hash);
# my %cfg;
# my $cfgname = $name . ".cfg";
# if (!Config::Simple->import_from($cfgname, \%cfg)) {
# $logger->fatal("Could not read config file \"$cfgname\": " . Config::Simple->error());
# return 1;
# }
# $hash{'cfg'} = $cfg;
my $settings_ref = FIJI::Settings->new("setup","fiji.cfg");
my $filename = "input.v";
if (!ref($settings_ref)) {
$logger->error($settings_ref);
return 1;
}
# $nl->{'parser'}->dump();
# my $mod = $nl->{'parser'}->find_module("i2c_master_bit_ctrl");
# my $net = $mod->find_net("core_cmd_0");
my @nets;
$nl->get_nets(\@nets);
# print Dumper(@nets);
foreach my $net (@nets) {
printf("%s\n", $net->name);
$self->{'settings'} = $settings_ref;
my $nl = new FIJI::Netlist();
if ($nl->read_file($filename) != 0) {
my $msg = "Netlist could not be loaded correctly from \"$filename\".";
$logger->error($msg);
}
# my $fius = $self->{'settings'}->{'FIUs'};
# foreach my $fiu (@{$fius}) {
# }
# generating test data
my $netpath = "i2c_master_top|i2c_master_bit_ctrl|N_152_tz"; #$fiu->{'FIU_NET_NAME'};
my $driverpath = "";
my @net_split = split(/\|/,$netpath);
my $mod = $nl->{'nl'}->find_module($net_split[-2]);
my $driver =$mod->find_cell("al_RNIHURE")->find_pin("combout");
if (!defined $mod) {
$msg = "Could not find module '".$net_split[-2]."'\n";
$logger->error($msg);
return 0;
}
my $net = $mod->find_net($net_split[-1]);
if (!defined $net) {
$msg = "Could not find net '".$mod->name."|".$net_split[-1]."'\n";
$logger->error($msg);
return 0;
}
if (!defined $driver) {
$msg = "Could not find driver.\n";
$logger->error($msg);
return 0;
}
# start instrumentation for this net
$nl->instrument_net($net,$driver);
print "\n\n//===== START NETLIST =====\n\n";
print $nl->{'nl'}->verilog_text;
print "\n\n//===== END NETLIST =====\n\n";
$logger->trace("=== Stopping execution ===");
return 0;
}
......
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