* Bare skeleton implementation of everything * Testbench builds with Verilator * Test runs
337 lines
18 KiB
Perl
Executable File
337 lines
18 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
use strict;
|
|
use warnings;
|
|
use Data::Dumper;
|
|
|
|
my $app = {};
|
|
|
|
get_axi_intf_data($app);
|
|
augment_intf_data($app);
|
|
#print Dumper($app->{'intf_data'}); # Debugging output
|
|
|
|
gen_intf($app);
|
|
|
|
# -----------------
|
|
# Subroutines
|
|
# -----------------
|
|
sub gen_intf {
|
|
my ($app) = @_;
|
|
|
|
print "// Generated AXI Interface\n";
|
|
print "// This file is automatically generated by $0\n";
|
|
print "// Do not edit this file directly.\n";
|
|
print "//\n";
|
|
print "// Interface Name: $app->{'intf_data'}->{'name'}\n";
|
|
print "interface axi_intf #(\n";
|
|
|
|
my @plines = get_param_lines($app);
|
|
print join(",\n", @plines);
|
|
print "\n)\n";
|
|
my @eplines = get_ext_ports_lines($app);
|
|
print "\n(\n";
|
|
print join(",\n", @eplines);
|
|
print "\n);\n";
|
|
|
|
show_interface($app);
|
|
|
|
show_modport($app, 'Manager');
|
|
show_modport($app, 'Subordinate');
|
|
|
|
print "endinterface // axi_intf\n";
|
|
}
|
|
|
|
# -----------------
|
|
sub get_param_lines {
|
|
my ($app) = @_;
|
|
my @plines;
|
|
|
|
foreach my $p (sort { $a cmp $b } keys %{$app->{'intf_data'}->{'params'}}) {
|
|
my $param_value = $app->{'intf_data'}->{'params'}->{$p}->{'d'};
|
|
push(@plines, sprintf(" parameter %$app->{'intf_data'}->{'info'}->{'param_width'}s = %d",
|
|
$p, $param_value));
|
|
}
|
|
|
|
return @plines;
|
|
}
|
|
|
|
# -----------------
|
|
sub get_ext_ports_lines {
|
|
my ($app) = @_;
|
|
my @eplines;
|
|
|
|
foreach my $p (sort { $a cmp $b } @{$app->{'intf_data'}->{'ext_sigs'}}) {
|
|
push(@eplines, sprintf(" input %s",
|
|
$p->{'n'}));
|
|
}
|
|
|
|
return @eplines;
|
|
}
|
|
|
|
# -----------------
|
|
sub show_interface {
|
|
my ($app) = @_;
|
|
|
|
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
|
print "\n";
|
|
print " // $section->{'name'}\n";
|
|
|
|
# Display signals
|
|
foreach my $signal (@{$section->{'signals'}}) {
|
|
if ($signal->{'s'} eq 'External') {
|
|
printf " // External signal: %-$app->{'intf_data'}->{'info'}->{'sig_width'}s // $signal->{'d'} [$signal->{'s'}]\n",
|
|
"$signal->{'n'};";
|
|
} else {
|
|
printf " logic %$app->{'intf_data'}->{'info'}->{'dim_width'}s %-$app->{'intf_data'}->{'info'}->{'sig_width'}s // $signal->{'d'} [$signal->{'s'}]\n",
|
|
get_dimension($app, $signal->{'w'}), "$signal->{'n'};";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# -----------------
|
|
sub show_modport{
|
|
my ($app, $role) = @_;
|
|
my $last = 0;
|
|
|
|
print "\n";
|
|
print " // Modport for $role role\n";
|
|
print " modport " . uc($role) . " (\n";
|
|
|
|
my $num_sections = scalar @{$app->{'intf_data'}->{'sections'}};
|
|
my $section_count = 0;
|
|
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
|
print "\n";
|
|
print " // $section->{'name'}\n";
|
|
|
|
$section_count++;
|
|
|
|
# Display signals
|
|
my $num_signals = scalar @{$section->{'signals'}};
|
|
my $signal_count = 0;
|
|
foreach my $signal (@{$section->{'signals'}}) {
|
|
# When role is Manager, signals with 'Manager' source are output, others are input
|
|
# When role is Subordinate, signals with 'Subordinate' source are output, others are input
|
|
my $direction = ($role eq 'Global') ? 'input' : ($role eq $signal->{'s'}) ? 'output' : 'input';
|
|
|
|
$signal_count++;
|
|
|
|
$last = 1 if ($num_signals == $signal_count && $num_sections == $section_count);
|
|
|
|
printf " %-8s $signal->{'n'}" . (($last == 1) ? "" : ","). "\n", $direction;
|
|
}
|
|
}
|
|
print " );\n";
|
|
}
|
|
|
|
# -----------------
|
|
sub augment_intf_data {
|
|
my ($app) = @_;
|
|
|
|
# Pretty print widths
|
|
$app->{'intf_data'}->{'info'}->{'param_width'} = 0;
|
|
$app->{'intf_data'}->{'info'}->{'dim_width'} = 0;
|
|
$app->{'intf_data'}->{'info'}->{'sig_width'} = 0;
|
|
|
|
# Capture parameters from signals
|
|
$app->{'intf_data'}->{'params'} = {};
|
|
# Capture external signals
|
|
$app->{'intf_data'}->{'ext_sigs'} = [];
|
|
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
|
foreach my $signal (@{$section->{'signals'}}) {
|
|
my $width = $signal->{'w'};
|
|
if ($width !~ /^\d+$/) {
|
|
unless (exists $app->{'intf_data'}->{'params'}->{$width}) {
|
|
$app->{'intf_data'}->{'params'}->{$width} = {
|
|
'd' => 1, # Default value for the parameter
|
|
};
|
|
$app->{'intf_data'}->{'info'}->{'param_width'} = length($width)
|
|
if (length($width) > $app->{'intf_data'}->{'info'}->{'param_width'});
|
|
}
|
|
}
|
|
if ($signal->{'s'} eq 'External') {
|
|
push(@{$app->{'intf_data'}->{'ext_sigs'}}, $signal);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Find the maximum width of the parameters
|
|
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
|
|
|
foreach my $signal (@{$section->{'signals'}}) {
|
|
$app->{'intf_data'}->{'info'}->{'dim_width'} = length(get_dimension($app, $signal->{'w'}))
|
|
if (length(get_dimension($app, $signal->{'w'})) > $app->{'intf_data'}->{'info'}->{'dim_width'});
|
|
$app->{'intf_data'}->{'info'}->{'sig_width'} = length($signal->{'n'})
|
|
if (length($signal->{'n'}) > $app->{'intf_data'}->{'info'}->{'sig_width'});
|
|
}
|
|
$app->{'intf_data'}->{'info'}->{'sig_width'} += 1; # Account for the semi-colon
|
|
}
|
|
}
|
|
|
|
# -----------------
|
|
sub get_dimension {
|
|
my ($app, $width) = @_;
|
|
|
|
if ($width =~ /^\d+$/) {
|
|
if ($width == 1) {
|
|
return ""; # Single bit width
|
|
} else {
|
|
return "[" . ($width-1) . ":0]"; # Specific width
|
|
}
|
|
} else {
|
|
return "[$width-1:0]"; # Width parameter
|
|
}
|
|
}
|
|
|
|
# -----------------
|
|
sub get_axi_intf_data {
|
|
my ($app) = @_;
|
|
|
|
$app->{'intf_data'} = {
|
|
'name' => "AXI Signal List",
|
|
'sections' =>
|
|
[
|
|
{
|
|
'name' => 'A2.4.1 Clock and reset signals',
|
|
'signals' => [
|
|
{ 'n' => 'ACLK', 'w' => '1', 's' => 'External', 'd' => 'External Global clock signal'},
|
|
{ 'n' => 'ARESETn', 'w' => '1', 's' => 'External', 'd' => 'External Global reset signal'}
|
|
]
|
|
},
|
|
{
|
|
'name' => 'A2.1.1 Write request channel',
|
|
'signals' => [
|
|
# n: name, w: width, s: source, d: description
|
|
{'n' =>'AWVALID','w' =>'1','s' =>'Manager','d' =>'Valid indicator' },
|
|
{'n' =>'AWREADY','w' =>'1','s' =>'Subordinate','d' =>'Ready indicator' },
|
|
{'n' =>'AWID','w' =>'ID_W_WIDTH','s' =>'Manager','d' =>'Transaction identifier for the write channels' },
|
|
{'n' =>'AWADDR','w' =>'ADDR_WIDTH','s' =>'Manager','d' =>'Transaction address' },
|
|
{'n' =>'AWREGION','w' =>'4','s' =>'Manager','d' =>'Region identifier' },
|
|
{'n' =>'AWLEN','w' =>'8','s' =>'Manager','d' =>'Transaction length' },
|
|
{'n' =>'AWSIZE','w' =>'3','s' =>'Manager','d' =>'Transaction size' },
|
|
{'n' =>'AWBURST','w' =>'2','s' =>'Manager','d' =>'Burst attribute' },
|
|
{'n' =>'AWLOCK','w' =>'1','s' =>'Manager','d' =>'Exclusive access indicator' },
|
|
{'n' =>'AWCACHE','w' =>'4','s' =>'Manager','d' =>'Memory attributes' },
|
|
{'n' =>'AWPROT','w' =>'3','s' =>'Manager','d' =>'Access attributes' },
|
|
{'n' =>'AWNSE','w' =>'1','s' =>'Manager','d' =>'Non-secure extension bit for RME' },
|
|
{'n' =>'AWQOS','w' =>'4','s' =>'Manager','d' =>'QoS identifier' },
|
|
{'n' =>'AWUSER','w' =>'USER_REQ_WIDTH','s' =>'Manager','d' =>'User-defined extension to a request' },
|
|
{'n' =>'AWDOMAIN','w' =>'2','s' =>'Manager','d' =>'Shareability domain of a request' },
|
|
{'n' =>'AWSNOOP','w' =>'AWSNOOP_WIDTH','s' =>'Manager','d' =>'Write request opcode' },
|
|
{'n' =>'AWSTASHNID','w' =>'11','s' =>'Manager','d' =>'Stash Node ID' },
|
|
{'n' =>'AWSTASHNIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Node ID enable' },
|
|
{'n' =>'AWSTASHLPID','w' =>'5','s' =>'Manager','d' =>'Stash Logical Processor ID' },
|
|
{'n' =>'AWSTASHLPIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Logical Processor ID enable' },
|
|
{'n' =>'AWTRACE','w' =>'1','s' =>'Manager','d' =>'Trace signal' },
|
|
{'n' =>'AWLOOP','w' =>'LOOP_W_WIDTH','s' =>'Manager','d' =>'Loopback signals on the write channels' },
|
|
{'n' =>'AWMMUVALID','w' =>'1','s' =>'Manager','d' =>'MMU signal qualifier' },
|
|
{'n' =>'AWMMUSECSID','w' =>'SECSID_WIDTH','s' =>'Manager','d' =>'Secure Stream ID' },
|
|
{'n' =>'AWMMUSID','w' =>'SID_WIDTH','s' =>'Manager','d' =>'StreamID' },
|
|
{'n' =>'AWMMUSSIDV','w' =>'1','s' =>'Manager','d' =>'SubstreamID valid' },
|
|
{'n' =>'AWMMUSSID','w' =>'SSID_WIDTH','s' =>'Manager','d' =>'SubstreamID' },
|
|
{'n' =>'AWMMUATST','w' =>'1','s' =>'Manager','d' =>'Address translated indicator' },
|
|
{'n' =>'AWMMUFLOW','w' =>'2','s' =>'Manager','d' =>'SMMU flow type' },
|
|
{'n' =>'AWPBHA','w' =>'4','s' =>'Manager','d' =>'Page-based Hardware Attributes' },
|
|
{'n' =>'AWNSAID','w' =>'4','s' =>'Manager','d' =>'Non-secure Access ID' },
|
|
{'n' =>'AWSUBSYSID','w' =>'SUBSYSID_WIDTH','s' =>'Manager','d' =>'Subsystem ID' },
|
|
{'n' =>'AWATOP','w' =>'6','s' =>'Manager','d' =>'Atomic transaction opcode' },
|
|
{'n' =>'AWMPAM','w' =>'MPAM_WIDTH','s' =>'Manager','d' =>'MPAM information with a request' },
|
|
{'n' =>'AWIDUNQ','w' =>'1','s' =>'Manager','d' =>'Unique ID indicator' },
|
|
{'n' =>'AWCMO','w' =>'AWCMO_WIDTH','s' =>'Manager','d' =>'CMO type' },
|
|
{'n' =>'AWTAGOP','w' =>'2','s' =>'Manager','d' =>'Memory Tag operation for write requests' },
|
|
{'n' =>'AWMECID','w' =>'MECID_WIDTH','s' =>'Manager','d' =>'Memory Encryption Context identifier' },
|
|
]
|
|
},
|
|
{
|
|
'name' => 'A2.1.1 Write request channel',
|
|
'signals' => [
|
|
{ 'n' => 'WVALID', 'w' => '1', 's' => 'Manager', 'd' => 'Valid indicator' },
|
|
{ 'n' => 'WREADY', 'w' => '1', 's' => 'Subordinate', 'd' => 'Ready indicator' },
|
|
{ 'n' => 'WDATA', 'w' => 'DATA_WIDTH', 's' => 'Manager', 'd' => 'Write data' },
|
|
{ 'n' => 'WSTRB', 'w' => 'DATA_WIDTH_DIV_8', 's' => 'Manager', 'd' => 'Write data strobes' },
|
|
{ 'n' => 'WTAG', 'w' => 'CEIL_DATA_WIDTH_DIV_128_TMS_4', 's' => 'Manager', 'd' => 'Memory Tag' },
|
|
{ 'n' => 'WTAGUPDATE', 'w' => 'CEIL_DATA_WIDTH_DIV_128', 's' => 'Manager', 'd' => 'Memory Tag update' },
|
|
{ 'n' => 'WLAST', 'w' => '1', 's' => 'Manager', 'd' => 'Last write data' },
|
|
{ 'n' => 'WUSER', 'w' => 'USER_DATA_WIDTH', 's' => 'Manager', 'd' => 'User-defined extension to write data' },
|
|
{ 'n' => 'WPOISON', 'w' => 'CEIL_DATA_WIDTH_DIV_64', 's' => 'Manager', 'd' => 'Poison indicator' },
|
|
{ 'n' => 'WTRACE', 'w' => '1', 's' => 'Manager', 'd' => 'Trace signal' },
|
|
]
|
|
},
|
|
{
|
|
'name' => 'A2.1.3 Write response channel',
|
|
'signals' => [
|
|
{ 'n' => 'BVALID', 'w' => '1', 's' => 'Subordinate', 'd' => 'Valid indicator' },
|
|
{ 'n' => 'BREADY', 'w' => '1', 's' => 'Manager', 'd' => 'Ready indicator' },
|
|
{ 'n' => 'BID', 'w' => 'ID_W_WIDTH', 's' => 'Subordinate', 'd' => 'Transaction identifier for the write channels' },
|
|
{ 'n' => 'BIDUNQ', 'w' => '1', 's' => 'Subordinate', 'd' => 'Unique ID indicator' },
|
|
{ 'n' => 'BRESP', 'w' => 'BRESP_WIDTH', 's' => 'Subordinate', 'd' => 'Write response code' },
|
|
{ 'n' => 'BCOMP', 'w' => '1', 's' => 'Subordinate', 'd' => 'Completion response indicator' },
|
|
{ 'n' => 'BPERSIST', 'w' => '1', 's' => 'Subordinate', 'd' => "Persist response" },
|
|
{ 'n' => 'BTAGMATCH', 'w' => '2', 's' => 'Subordinate', 'd' => 'Memory Tag Match response' },
|
|
{ 'n' => 'BUSER', 'w' => 'USER_RESP_WIDTH', 's' => 'Subordinate', 'd' => 'User-defined extension to a write response' },
|
|
{ 'n' => 'BTRACE', 'w' => '1', 's' => 'Subordinate', 'd' => 'Trace signal' },
|
|
{ 'n' => 'BLOOP', 'w' => 'LOOP_W_WIDTH', 's' => 'Subordinate', 'd' => 'Loopback signals on the write channels' },
|
|
{ 'n' => 'BBUSY', 'w' => '2', 's' => 'Subordinate', 'd' => "Busy indicator" },
|
|
]
|
|
},
|
|
{
|
|
'name' => 'A2.2.1 Read request channel',
|
|
'signals' => [
|
|
{ 'n' => 'ARVALID', 'w' => '1', 's' => 'Manager', 'd' => 'Valid indicator' },
|
|
{ 'n' => 'ARREADY', 'w' => '1', 's' => 'Subordinate', 'd' => 'Ready indicator' },
|
|
{ 'n' => 'ARID', 'w' => 'ID_R_WIDTH', 's' => 'Manager', 'd' => 'Transaction identifier for the read channels' },
|
|
{ 'n' => 'ARADDR', 'w' => 'ADDR_WIDTH', 's' => 'Manager', 'd' => 'Transaction address' },
|
|
{ 'n' => 'ARREGION', 'w' => '4', 's' => 'Manager', 'd' => 'Region identifier' },
|
|
{ 'n' => 'ARLEN', 'w' => '8', 's' => 'Manager', 'd'=> "Transaction length" },
|
|
{ 'n' => 'ARSIZE', 'w' => '3', 's' => 'Manager', 'd' => 'Transaction size' },
|
|
{ 'n' => 'ARBURST', 'w' => '2', 's' => 'Manager', 'd' => 'Burst attribute' },
|
|
{ 'n' => 'ARLOCK', 'w' => '1', 's' => 'Manager', 'd' => 'Exclusive access indicator' },
|
|
{ 'n' => 'ARCACHE', 'w' => '4', 's' => 'Manager', 'd' => 'Memory attributes' },
|
|
{ 'n' => 'ARPROT', 'w' => '3', 's' => 'Manager', 'd' => 'Access attributes' },
|
|
{ 'n' => 'ARNSE', 'w' => '1', 's' => 'Manager', 'd' => 'Non-secure extension bit for RME' },
|
|
{ 'n' => 'ARQOS', 'w' => '4', 's' => 'Manager', 'd' => 'QoS identifier' },
|
|
{ 'n' => 'ARUSER', 'w' => 'USER_REQ_WIDTH', 's' => 'Manager', 'd' => 'User-defined extension to a request' },
|
|
{ 'n' => 'ARDOMAIN', 'w' => '2', 's' => 'Manager', 'd' => 'Shareability domain of a request' },
|
|
{ 'n' => 'ARSNOOP', 'w' => 'ARSNOOP_WIDTH', 's' => 'Manager', 'd' => 'Read request opcode' },
|
|
{ 'n' => 'ARTRACE', 'w' => '1', 's' => 'Manager', 'd' => 'Trace signal' },
|
|
{ 'n' => 'ARLOOP', 'w' => 'LOOP_R_WIDTH', 's' => 'Manager', 'd' => 'Loopback signals on the read channels' },
|
|
{ 'n' => 'ARMMUVALID', 'w' => '1', 's' => 'Manager', 'd' => 'MMU signal qualifier' },
|
|
{ 'n' => 'ARMMUSECSID', 'w' => 'SECSID_WIDTH', 's' => 'Manager', 'd' => 'Secure Stream ID' },
|
|
{ 'n' => 'ARMMUSID', 'w' => 'SID_WIDTH', 's' => 'Manager', 'd' => 'StreamID' },
|
|
{ 'n' => 'ARMMUSSIDV', 'w' => '1', 's' => 'Manager', 'd' => 'SubstreamID valid' },
|
|
{ 'n' => 'ARMMUSSID', 'w' => 'SSID_WIDTH', 's' => 'Manager', 'd' => 'SubstreamID' },
|
|
{ 'n' => 'ARMMUATST', 'w' => '1', 's' => 'Manager', 'd' => 'Address translated indicator' },
|
|
{ 'n' => 'ARMMUFLOW', 'w' => '2', 's' => 'Manager', 'd' => 'SMMU flow type' },
|
|
{ 'n' => 'ARPBHA', 'w' => '4', 's' => 'Manager', 'd' => 'Page-based Hardware Attributes' },
|
|
{ 'n' => 'ARNSAID', 'w' => '4', 's' => 'Manager', 'd' => 'Non-secure Access ID' },
|
|
{ 'n' => 'ARSUBSYSID', 'w' => 'SUBSYSID_WIDTH', 's' => 'Manager', 'd' => 'Subsystem ID' },
|
|
{ 'n' => 'ARCHUNKEN','w' => '1','s' => 'Manager','d' => 'Read data chunking enable'},
|
|
{ 'n' => 'ARIDUNQ','w' => '1','s' => 'Manager','d' => 'Unique ID indicator'},
|
|
{ 'n' => 'ARTAGOP','w' => '2','s' => 'Manager','d' => 'Memory Tag operation for read requests'},
|
|
{ 'n' => 'ARMECID','w' => 'MECID_WIDTH','s' => 'Manager','d' => 'Memory Encryption Context identifier'},
|
|
]
|
|
},
|
|
{
|
|
'name' => 'A2.2.2 Read data channel',
|
|
'signals' => [
|
|
{ 'n' => 'RVALID', 'w' => '1', 's' => 'Subordinate', 'd' => 'Valid indicator' },
|
|
{ 'n' => 'RREADY', 'w' => '1', 's' => 'Manager', 'd' => 'Ready indicator' },
|
|
{ 'n' => 'RID', 'w' => 'ID_R_WIDTH', 's' => 'Subordinate', 'd' => 'Transaction identifier for the read channels' },
|
|
{ 'n' => 'RIDUNQ', 'w' => '1', 's' => 'Subordinate', 'd' => 'Unique ID indicator' },
|
|
{ 'n' => 'RDATA', 'w' => 'DATA_WIDTH', 's' => 'Subordinate', 'd' => 'Read data' },
|
|
{ 'n' => 'RTAG', 'w' => 'CEIL_DATA_WIDTH_DIV_128_TMS_4', 's' => 'Subordinate', 'd' => 'Memory Tag' },
|
|
{ 'n' => 'RRESP', 'w' => 'RRESP_WIDTH', 's' => 'Subordinate', 'd' => 'Read response' },
|
|
{ 'n' => 'RLAST', 'w' => '1', 's' => 'Subordinate', 'd' => 'Last read data' },
|
|
{ 'n' => 'RUSER', 'w' => 'SUM_USER_DATA_WIDTH_USER_RESP_WIDTH', 's' => 'Subordinate', 'd' => 'User-defined extension to read data and response' },
|
|
{ 'n' => 'RPOISON', 'w' => 'CEIL_DATA_WIDTH_DIV_64', 's' => 'Subordinate', 'd' => 'Poison indicator' },
|
|
{ 'n' => 'RTRACE', 'w' => '1', 's' => 'Subordinate', 'd' => 'Trace signal' },
|
|
{ 'n' => 'RLOOP', 'w' => 'LOOP_R_WIDTH', 's' => 'Subordinate', 'd' => 'Loopback signals on the read channels' },
|
|
{ 'n' => 'RCHUNKV','w' => '1', 's' => 'Subordinate', 'd' => 'Read data chunking valid' },
|
|
{ 'n' => 'RCHUNKNUM', 'w' => 'RCHUNKNUM_WIDTH', 's' => 'Subordinate', 'd' => 'Read data chunk number' },
|
|
{ 'n' => 'RCHUNKSTRB', 'w' => 'RCHUNKSTRB_WIDTH', 's' => 'Subordinate', 'd' => 'Read data chunk strobe' },
|
|
{ 'n' => 'RBUSY', 'w' => '2', 's' => 'Subordinate', 'd' => 'Busy indicator' },
|
|
]
|
|
},
|
|
]
|
|
}
|
|
}
|