mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 02:18:37 +00:00
Discovered sometimes a SLINE stabs entry is the last one (which broke an
assertion). In such a case, we must guess the line's instruction address
range -- I've guessed 4, arbitrarily.
vg_cachegen.in, vg_cachesim_{I1,D1,L2}.c:
Discovered a bad bug in the cache simulation: when determining if a
references straddles two memory blocks, to find the end of the range I was
adding 'size' to the base address, rather than 'size - 1'. This was
causing way too many straddled references, which would inflate the miss
counts.
vg_cachesim.c:
Minor stuff
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@176
301 lines
8.8 KiB
Perl
Executable File
301 lines
8.8 KiB
Perl
Executable File
#! /usr/bin/perl -w
|
|
##--------------------------------------------------------------------##
|
|
##--- The cache simulator generator ---##
|
|
##--- vg_cachegen ---##
|
|
##--------------------------------------------------------------------##
|
|
|
|
# This file is part of Valgrind, an x86 protected-mode emulator
|
|
# designed for debugging and profiling binaries on x86-Unixes.
|
|
#
|
|
# Copyright (C) 2000-2002 Julian Seward
|
|
# jseward@acm.org
|
|
# Julian_Seward@muraroa.demon.co.uk
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
# published by the Free Software Foundation; either version 2 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
# 02111-1307, USA.
|
|
#
|
|
# The GNU General Public License is contained in the file LICENSE.
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Cache simulator generator, creates files vg_cachesim_{I1,D1,L2}.c to be
|
|
# #included in vg_cachesim.c.
|
|
#
|
|
# Notes:
|
|
# - simulates a write-allocate cache
|
|
# - (block --> set) hash function uses simple bit selection
|
|
# - handling references straddling two cache blocks:
|
|
# - counts as only one cache access (not two)
|
|
# - both blocks hit --> one hit
|
|
# - one block hits, the other misses --> one miss
|
|
# - both blocks miss --> one miss (not two)
|
|
|
|
use strict;
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Global variables
|
|
#----------------------------------------------------------------------------
|
|
my %log2 =
|
|
( 1 => 0,
|
|
2 => 1,
|
|
4 => 2,
|
|
8 => 3,
|
|
16 => 4,
|
|
32 => 5,
|
|
64 => 6,
|
|
128 => 7,
|
|
256 => 8,
|
|
512 => 9,
|
|
1024 => 10,
|
|
2048 => 11,
|
|
4096 => 12,
|
|
8192 => 13,
|
|
16384 => 14,
|
|
32768 => 15,
|
|
65536 => 16,
|
|
131072 => 17,
|
|
262144 => 18,
|
|
524288 => 19,
|
|
1048576 => 20,
|
|
2097152 => 21,
|
|
4194304 => 22,
|
|
8388608 => 23,
|
|
16777216 => 24,
|
|
33554432 => 25,
|
|
67108864 => 26,
|
|
134217728 => 27,
|
|
268435456 => 28,
|
|
536870912 => 29,
|
|
1073741824 => 30);
|
|
|
|
my @valid_types =
|
|
("I1", "D1", "L2");
|
|
|
|
my @valid_sizes =
|
|
(1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
|
|
1048576, 2097152, 4194304, 8388608, 16777216, 67108864, 134217728);
|
|
|
|
my @valid_linesizes =
|
|
(8, 16, 32, 64, 128);
|
|
|
|
my @valid_ways =
|
|
(1, 2, 4, 8, 256);
|
|
|
|
my %valid_types; for my $i (@valid_types) { $valid_types{$i} = 1; }
|
|
my %valid_sizes; for my $i (@valid_sizes) { $valid_sizes{$i} = 1; }
|
|
my %valid_linesizes; for my $i (@valid_linesizes) { $valid_linesizes{$i} = 1; }
|
|
my %valid_ways; for my $i (@valid_ways) { $valid_ways{$i} = 1; }
|
|
|
|
my ($L, $size, $line_size, $n_ways);
|
|
|
|
my @caches;
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Argument and option handling
|
|
#----------------------------------------------------------------------------
|
|
sub process_cmd_line ()
|
|
{
|
|
#----
|
|
my $usage = <<END
|
|
usage: cachegen [options]
|
|
|
|
options are:
|
|
--I1=size,line_size,number_of_ways
|
|
--D1=size,line_size,number_of_ways
|
|
--L2=size,line_size,number_of_ways
|
|
|
|
where
|
|
size is one of @valid_sizes
|
|
line_size is one of @valid_linesizes
|
|
number_of_ways is one of @valid_ways
|
|
|
|
Valgrind is Copyright (C) 2000-2002 Julian Seward
|
|
and licensed under the GNU General Public License, version 2.
|
|
Bug reports, feedback, admiration, abuse, etc, to: jseward\@acm.org.
|
|
|
|
END
|
|
;
|
|
#----
|
|
(@ARGV > 0) or die($usage);
|
|
for my $arg (@ARGV) {
|
|
|
|
if ($arg =~ /--(I1|D1|L2)=(\d+),(\d+),(\d+)/) {
|
|
my ($L, $size, $line_size, $n_ways) = ($1, $2, $3, $4);
|
|
|
|
(defined $valid_sizes{$size} &&
|
|
defined $valid_linesizes{$line_size} &&
|
|
defined $valid_ways{$n_ways}) or die($usage);
|
|
|
|
# Remember cache type too, and save
|
|
push(@caches, [ $L, $size, $line_size, $n_ways ]);
|
|
|
|
}
|
|
|
|
else { # -h and --help fall under this case
|
|
die($usage);
|
|
}
|
|
}
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Printing machinery (I)
|
|
#----------------------------------------------------------------------------
|
|
sub shiftSequence ($$$)
|
|
{
|
|
my $s = "";
|
|
my ($i, $n, $L) = @_;
|
|
|
|
while ($i > 0) {
|
|
$s .= " ${L}_tags[set$n][$i] = ";
|
|
$i--;
|
|
$s .= "${L}_tags[set$n][$i];\n"
|
|
}
|
|
return $s;
|
|
}
|
|
|
|
sub trySet ($$$$$)
|
|
{
|
|
my $s = "";
|
|
my ($k, $n, $L, $hit_ending, $miss_ending) = @_;
|
|
|
|
for (my $i = 0; $i < $k; $i++) {
|
|
$s .= " "
|
|
. (0 == $i ? "if" : "else if")
|
|
. " (tag == ${L}_tags[set$n][$i]) {\n"
|
|
. shiftSequence($i, $n, $L)
|
|
. (0 == $i ? "" : " ${L}_tags[set$n][0] = tag;\n")
|
|
. ("" eq $hit_ending ? "" : " $hit_ending\n")
|
|
. " }\n";
|
|
}
|
|
|
|
$s .= " else {\n"
|
|
. " /* A miss */\n"
|
|
. shiftSequence($k - 1, $n, $L) # not if exclusive
|
|
. " ${L}_tags[set$n][0] = tag;\n" # not if exclusive
|
|
. "\n"
|
|
. " $miss_ending\n"
|
|
. " }\n";
|
|
return $s;
|
|
}
|
|
|
|
sub print_cache_simulator (@)
|
|
{
|
|
my ($L, $size, $line_size, $n_ways) = @_;
|
|
|
|
my $n_lines = $size / $line_size;
|
|
my $n_sets = $n_lines / $n_ways;
|
|
my $n_line_bits = $log2{$line_size};
|
|
my $n_set_bits = $log2{$n_sets};
|
|
|
|
my $assoc = (1 == $n_ways ? "direct-mapped" : "$n_ways-way associative");
|
|
my $L1_args = "Addr a, UChar size, ULong* m1, ULong *m2";
|
|
my $L2_args = "Addr a, UChar size, ULong *m2";
|
|
my $L_args = ($L ne "L2" ? $L1_args : $L2_args);
|
|
|
|
#----
|
|
my $comments_cache_init_desc_and_doref_start = <<END
|
|
/* $L cache simulator, generated by vg_cachegen.
|
|
* total size = $size bytes
|
|
* line size = $line_size bytes
|
|
* associativity = $assoc
|
|
*
|
|
* This file should be #include-d into vg_cachesim.c
|
|
*/
|
|
|
|
static char ${L}_desc_line[] =
|
|
"desc: ${L} cache: $size B, $line_size B, $assoc\\n";
|
|
|
|
static UInt ${L}_tags[$n_sets][$n_ways];
|
|
|
|
static void cachesim_${L}_initcache(void)
|
|
{
|
|
UInt set, way;
|
|
for (set = 0; set < $n_sets; set++)
|
|
for (way = 0; way < $n_ways; way++)
|
|
${L}_tags[set][way] = 0;
|
|
}
|
|
|
|
static __inline__
|
|
void cachesim_${L}_doref($L_args)
|
|
{
|
|
register UInt set1 = ( a >> $n_line_bits) & ($n_sets-1);
|
|
register UInt set2 = ((a + size - 1) >> $n_line_bits) & ($n_sets-1);
|
|
register UInt tag = a >> ($n_line_bits + $n_set_bits);
|
|
|
|
if (set1 == set2) {
|
|
|
|
END
|
|
;
|
|
#----
|
|
my $doref_middle = <<END
|
|
|
|
} else if ((set1 + 1) % $n_sets == set2) {
|
|
|
|
Bool is_${L}_miss = False;
|
|
|
|
END
|
|
;
|
|
#----
|
|
my $L1_miss_treatment = "(*m1)++;\n" .
|
|
" cachesim_L2_doref(a, size, m2);";
|
|
my $L2_miss_treatment = "(*m2)++;";
|
|
my $L_miss_treatment =
|
|
( $L ne "L2" ? $L1_miss_treatment : $L2_miss_treatment );
|
|
|
|
my $straddle_case_miss_treatment = <<END
|
|
/* Miss treatment */
|
|
if (is_${L}_miss) {
|
|
$L_miss_treatment
|
|
}
|
|
END
|
|
;
|
|
#----
|
|
my $doref_end = <<END
|
|
|
|
} else {
|
|
VG_(printf)("\\nERROR: Data item 0x%x of size %u bytes is in two non-adjacent\\n", a, size);
|
|
VG_(printf)("sets %d and %d.\\n", set1, set2);
|
|
VG_(panic)("$L cache set mismatch");
|
|
}
|
|
}
|
|
END
|
|
;
|
|
#----
|
|
my $outfile = "vg_cachesim_${L}.c";
|
|
open(OUTFILE, "> $outfile") or die("Couldn't open $outfile for writing\n");
|
|
|
|
print(OUTFILE $comments_cache_init_desc_and_doref_start);
|
|
print(OUTFILE trySet($n_ways, 1, $L, "return;", $L_miss_treatment));
|
|
print(OUTFILE $doref_middle);
|
|
print(OUTFILE " /* Block one */\n");
|
|
print(OUTFILE trySet($n_ways, 1, $L, "", "is_${L}_miss = True;"));
|
|
print(OUTFILE "\n");
|
|
print(OUTFILE " /* Block two */\n");
|
|
print(OUTFILE trySet($n_ways, 2, $L, "", "is_${L}_miss = True;"));
|
|
print(OUTFILE "\n");
|
|
print(OUTFILE $straddle_case_miss_treatment);
|
|
print(OUTFILE $doref_end);
|
|
|
|
close(OUTFILE);
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
# main()
|
|
#----------------------------------------------------------------------------
|
|
process_cmd_line();
|
|
foreach my $cache (@caches) {
|
|
print_cache_simulator(@$cache);
|
|
}
|
|
|