#! /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 = < 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 = <> $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 = < $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); }