aboutsummaryrefslogtreecommitdiff
path: root/risugen
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-03-15 15:22:50 +0000
committerPeter Maydell <peter.maydell@linaro.org>2011-03-15 15:22:50 +0000
commit34fad31fd055b501994a6b0cb0abefa4b455f7b7 (patch)
treef4e618a29d8678ea8f4652c1a30b647f9288cd17 /risugen
parentfd71eccde02e340599677870f2a0a2ee09535b19 (diff)
Code cleanup and fix to do initial setup steps in the right order
Clean up our handling of ARM/Thumb switching by distinguishing between "what mode are we in right now?" and "what mode does test code want to be in?". Shuffle things around so write_test_code() is responsible for doing all the prologue stuff, and write_random_register_data() is only called explicitly, not implicitly by other things. This makes it easy to make the actual bug fix, which is to call write_random_register_data() after write_memblock_setup() so that the latter doesn't have to clean its registers to not include any address-location-dependent values.
Diffstat (limited to 'risugen')
-rwxr-xr-xrisugen94
1 files changed, 51 insertions, 43 deletions
diff --git a/risugen b/risugen
index 83d1805..2fb5679 100755
--- a/risugen
+++ b/risugen
@@ -21,7 +21,13 @@ use Text::Balanced qw { extract_bracketed extract_multiple };
my @insns;
my %insn_details;
-my $is_thumb = 0;
+# Note that we always start in ARM mode even if the C code was compiled for
+# thumb because we are called by branch to a lsbit-clear pointer.
+# is_thumb tracks the mode we're actually currently in (ie should we emit
+# an arm or thumb insn?); test_thumb tells us which mode we need to switch
+# to to emit the insns under test.
+my $is_thumb = 0; # are we currently in Thumb mode?
+my $test_thumb = 0; # should test code be Thumb mode?
my @pattern_re = ();
@@ -119,21 +125,38 @@ sub write_risuop($)
sub write_switch_to_thumb()
{
- # Note that we have to clean up r0 afterwards
- # so it isn't tainted with a value which depends
- # on PC (and which might differ between hw and
- # qemu/valgrind/etc)
- insn32(0xe28f0001); # add r0, pc, #1
- insn32(0xe12fff10); # bx r0
- insn16(0x4040); # eor r0,r0 (enc T1)
+ # Switch to thumb if we're not already there
+ if (!$is_thumb) {
+ # Note that we have to clean up r0 afterwards
+ # so it isn't tainted with a value which depends
+ # on PC (and which might differ between hw and
+ # qemu/valgrind/etc)
+ insn32(0xe28f0001); # add r0, pc, #1
+ insn32(0xe12fff10); # bx r0
+ insn16(0x4040); # eor r0,r0 (enc T1)
+ $is_thumb = 1;
+ }
}
sub write_switch_to_arm()
{
- # Switch to ARM mode.
- align4();
- insn16(0x4778); # bx pc
- insn16(0xbf00); # nop
+ # Switch to ARM mode if we're not already there
+ if ($is_thumb) {
+ align4();
+ insn16(0x4778); # bx pc
+ insn16(0xbf00); # nop
+ $is_thumb = 0;
+ }
+}
+
+sub write_switch_to_test_mode()
+{
+ # Switch to whichever mode we need for test code
+ if ($test_thumb) {
+ write_switch_to_thumb();
+ } else {
+ write_switch_to_arm();
+ }
}
sub write_sub_rrr($$$)
@@ -299,9 +322,7 @@ sub write_random_register_data()
{
# TODO hardcoded, also no d16-d31 initialisation
my $vfp = 2; # 0 : no vfp, 1 : vfpd16, 2 : vfpd32
- if ($is_thumb) {
- write_switch_to_arm();
- }
+ write_switch_to_arm();
# initialise all registers
if ($vfp == 1) {
@@ -329,9 +350,6 @@ sub write_random_register_data()
# next:
# clear the flags (NZCVQ and GE): msr APSR_nzcvqg, #0
insn32(0xe32cf000);
- if ($is_thumb) {
- write_switch_to_thumb();
- }
write_risuop($OP_COMPARE);
}
@@ -346,9 +364,7 @@ sub write_memblock_setup()
# Write code which sets up the memory block for loads and stores.
# We just need to set r0 to point to a block of at least 8K length
# of random data, aligned to the maximum desired alignment (32).
- if ($is_thumb) {
- write_switch_to_arm();
- }
+ write_switch_to_arm();
my $align = $MAXALIGN;
my $datalen = 2048 + $align;
@@ -364,31 +380,18 @@ sub write_memblock_setup()
}
# next:
- if ($is_thumb) {
- write_switch_to_thumb();
- }
}
-sub write_arm_prologue($)
+sub write_set_fpscr($)
{
my ($fpscr) = @_;
- # We will start in ARM mode because we're just loaded
- # as binary and jump to the aligned start of it, so
- # the target address LSB is always 0.
-
+ write_switch_to_arm();
# movw r0, imm16
insn32(0xe3000000 | ($fpscr & 0xfff) | (($fpscr & 0xf000) << 4));
# movt r0, imm16
insn32(0xe3400000 | (($fpscr & 0xf0000000) >> 12) | (($fpscr & 0x0fff0000) >> 16));
# vmsr fpscr, r0
insn32(0xeee10a10);
-
- if ($is_thumb) {
- # This mode change will be immediately followed by one
- # in write_random_register_data() but never mind.
- write_switch_to_thumb();
- }
- write_random_register_data();
}
sub dump_insn_details($$)
@@ -681,9 +684,9 @@ sub progress_end()
$| = 0;
}
-sub write_test_code($$)
+sub write_test_code($$$)
{
- my ($condprob, $numinsns) = @_;
+ my ($condprob, $fpscr, $numinsns) = @_;
# convert from probability that insn will be conditional to
# probability of forcing insn to unconditional
$condprob = 1 - $condprob;
@@ -704,9 +707,14 @@ sub write_test_code($$)
print "Generating code using patterns: @keys...\n";
progress_start(78, $numinsns);
+ write_set_fpscr($fpscr);
+
if (grep { defined($insn_details{$_}->{blocks}->{"memory"}) } @keys) {
write_memblock_setup();
}
+ # memblock setup doesn't clean its registers, so this must come afterwards.
+ write_random_register_data();
+ write_switch_to_test_mode();
for my $i (1..$numinsns) {
my $insn_enc = $keys[int rand (@keys)];
@@ -718,9 +726,11 @@ sub write_test_code($$)
# for the VFP registers to decay to NaNs and zeroes.
if (($i % 100) == 0) {
write_random_register_data();
+ write_switch_to_test_mode();
}
progress_update($i);
}
+ write_risuop($OP_TESTEND);
progress_end();
}
@@ -743,9 +753,9 @@ sub parse_risu_directive($$@)
exit(1);
}
if ($rest[0] eq "thumb") {
- $is_thumb = 1;
+ $test_thumb = 1;
} elsif ($rest[0] eq "arm") {
- $is_thumb = 0;
+ $test_thumb = 0;
} else {
print STDERR "$file:$.: .mode: unknown mode $rest[0]\n";
exit(1);
@@ -988,9 +998,7 @@ sub main()
parse_config_file($infile);
open_bin($outfile);
- write_arm_prologue($fpscr);
- write_test_code($condprob, $numinsns);
- write_risuop($OP_TESTEND);
+ write_test_code($condprob, $fpscr, $numinsns);
close_bin();
return 0;
}