diff mbox

[5/9] Add risugen_ppc.pm file

Message ID 25595416-4E28-4276-AC25-9E62D30D9B74@gmail.com
State New
Headers show

Commit Message

Programmingkid April 25, 2017, 3:21 a.m. UTC
Add the risugen_ppc.pm file. It is used to generate the instructions  
that risu
runs.

Signed-off-by: John Arbuckle <programmingkidx@gmail.com>
---
  risugen_ppc.pm | 744 +++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++
  1 file changed, 744 insertions(+)
  create mode 100644 risugen_ppc.pm

+    srand();
+
+    # Get a list of the insn keys which are permitted by the re  
patterns
+    my @keys = sort keys %insn_details;
+    if (@pattern_re) {
+        my $re = '\b((' . join(')|(',@pattern_re) . '))\b';
+        @keys = grep /$re/, @keys;
+    }
+    # exclude any specifics
+    if (@not_pattern_re) {
+        my $re = '\b((' . join(')|(',@not_pattern_re) . '))\b';
+        @keys = grep !/$re/, @keys;
+    }
+    if (!@keys) {
+        print STDERR "No instruction patterns available! (bad config  
file or --pattern argument?)\n";
+        exit(1);
+    }
+    print "Generating code using patterns: @keys...\n";
+    progress_start(78, $numinsns);
+
+    # initialize all the UISA registers
+    write_init_gpr_code();
+
+    if ($fp_enabled) {
+        write_init_float_registers_code();
+        write_init_fpscr_code($fpscr);
+    }
+
+    write_init_xer_code();
+    write_init_lr_code();
+    write_init_ctr_code();
+    write_init_cr_code();
+    write_risuop($OP_COMPARE);
+
+    for my $i (1..$numinsns) {
+        my $insn_enc = $keys[int rand (@keys)];
+        #dump_insn_details($insn_enc, $insn_details{$insn_enc});
+        gen_one_insn($insn_details{$insn_enc});
+        write_risuop($OP_COMPARE);
+      if ($debug != 1) {
+          progress_update($i);
+      }
+    }
+    write_risuop($OP_TESTEND);
+    progress_end();
+    close_bin();
+}
+
+1;
diff mbox

Patch

diff --git a/risugen_ppc.pm b/risugen_ppc.pm
new file mode 100644
index 0000000..2faae81
--- /dev/null
+++ b/risugen_ppc.pm
@@ -0,0 +1,744 @@ 
+#!/usr/bin/perl -w
+####################################################################### 
########
+# File: risugen_ppc.pm
+# Date: 4-14-2017
+# Description: Perl module for generating PowerPC instructions with  
risugen.
+# Based on Jose Ricardo Ziviani (IBM) - ppc64 implementation
+####################################################################### 
########
+
+# risugen -- generate a test binary file for use with risu
+# See 'risugen --help' for usage information.
+package risugen_ppc;
+
+use strict;
+use warnings;
+use bigint;
+use risugen_common;
+
+require Exporter;
+
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(write_test_code);
+
+# Has all debug messages printed if set to 1
+my $debug = 0;
+
+# First available slot in the stack
+my $available_stack_slot = 40;
+
+my $OP_COMPARE = 0;        # compare registers
+my $OP_TESTEND = 1;        # end of test, stop
+
+# prints debugging information if DEBUG is set to 1
+sub debug_print {
+    if ($debug == 1) {
+        my $test = sprintf(shift, @_);
+        print $test;
+    }
+}
+
+# setup the environment for a memory access involving two registers
+# first input: general purpose register rA
+# second input: general purpose register rB
+sub reg_plus_reg($$)
+{
+    my ($rA, $rB) = @_;
+    my $value;
+    my $low_bits;
+    my $high_bits;
+
+    $value = rand();
+
+    # Has to be loaded like this because we can't just load a 32 bit  
value
+    $low_bits = $value & 0xffff;
+    $high_bits = $value >> 16;
+
+    # Add a value into the expected memory location
+    write_lis(10, $high_bits);              # lis r10, $high_bits
+    write_ori(10, 10, $low_bits);           # ori r10, r10, $low_bits
+    write_stw(10, $available_stack_slot);   # stw r10,  
$available_stack_slot(r1)
+
+    # setup the two registers to find the memory location
+    write_mr($rA, 1);                       # mr $rA, r1
+    write_li($rB, $available_stack_slot);   # li $rB,  
$available_stack_slot
+    return $rA;
+}
+
+# Handle register + immediate addressing mode
+# first input: base register
+# second input: immediate value (offset)
+sub reg_plus_imm($$)
+{
+    my ($base_register, $number) = @_;
+
+    # load a random floating point value into memory
+    my $float_value = rand();
+    my $ieee_value = convert_to_IEEE($float_value);
+    my $ieee_high_bits; # the upper 16 bits of $ieee_value
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_value
+
+    $ieee_high_bits = $ieee_value >> 16;
+    $ieee_low_bits = $ieee_value & 0xffff;
+    write_lis(10, $ieee_high_bits);       # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);    # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $number);               # stw r10, $number(r1)
+    write_mr($base_register, 1);          # mr $base_register, r1
+    return $base_register;
+}
+
+# convert float value to IEEE 754
+# input: floating point value (e.g. 1.23)
+# output: IEEE 754 single precision value
+sub convert_to_IEEE($)
+{
+    my $float_value = $_[0];
+    my $ieee_value = unpack "L", pack "f", $float_value;
+    return $ieee_value;
+}
+
+# returns a random double precision IEEE 754 value
+# output: 64 bit number
+sub get_random_IEEE_double_value()
+{
+    my @number_array = (0x40273333333333330, 0x405EDCCCCCCCCCCD,
+                        0x40700A6666666666, 0x412E240CA45A1CAC,
+                        0x407C3E8F5C28F5C3, 0x408DBF189374BC6A);
+    my $size_of_array = scalar @number_array;
+    my $index = int rand($size_of_array);
+    return $number_array[$index];
+}
+
+# writes ppc assembly code to load a IEEE 754 double value
+# input one: general purpose register number
+# input two: immediate value (offset)
+# output: IEEE 754 double value
+sub load_double_float_imm($$)
+{
+    my ($rA, $number) = @_;
+
+    my $ieee_double;   # ieee 754 double float value
+    my $ieee_high_bits; # the upper 16 bits of $ieee_double
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_double
+    my $higher_32_bits;
+    my $lower_32_bits;
+
+    $ieee_double = get_random_IEEE_double_value();
+
+    # loading a 64 bit double value is going to take some work
+
+    # load the higher 32 bits
+    $higher_32_bits = $ieee_double >> 32;  # push the lower 32 bits out
+    $ieee_high_bits = $higher_32_bits >> 16;
+    $ieee_low_bits = $higher_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);       # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);    # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $number);               # stw r10, $number(r1)
+
+    # load the lower 32 bits
+    $lower_32_bits = $ieee_double & 0xffffffff;
+    $ieee_high_bits = $lower_32_bits >> 16;
+    $ieee_low_bits = $lower_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);       # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);    # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $number + 4);           # stw r10, $number+4 (r1)
+
+    write_mr($rA, 1);                     # mr $rA, r1
+    return $rA;
+}
+
+
+# writes ppc assembly code to load a IEEE 754 double value into memory
+# input one: general purpose register number
+# input two: general purpose register number
+# output: IEEE 754 double value
+sub load_double_float_indexed($$)
+{
+    my ($rA, $rB) = @_;
+
+    my $ieee_double;   # ieee 754 double float value
+    my $ieee_high_bits; # the upper 16 bits of $ieee_double
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_double
+    my $higher_32_bits;
+    my $lower_32_bits;
+
+    $ieee_double = get_random_IEEE_double_value();
+
+    # loading a 64 bit double value is going to take some work
+
+    # load the higher 32 bits
+    $higher_32_bits = $ieee_double >> 32;  # push the lower 32 bits out
+    $ieee_high_bits = $higher_32_bits >> 16;
+    $ieee_low_bits = $higher_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);         # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);      # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $available_stack_slot);   # stw r10,  
$available_stack_slot(r1)
+
+    # load the lower 32 bits
+    $lower_32_bits = $ieee_double & 0xffffffff;
+    $ieee_high_bits = $lower_32_bits >> 16;
+    $ieee_low_bits = $lower_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);             # lis r10,  
$ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);          # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $available_stack_slot + 4);   # stw r10,  
($available_stack_slot + 4)(r1)
+
+    # setup the registers' value
+    write_li($rB, $available_stack_slot);       # li $rB,  
$available_stack_slot
+    write_mr($rA, 1);                           # mr $rA, r1
+    return $rA;
+}
+
+# Setup a testing environment for an instruction that
+# requires a double precision floating point value in a float register
+# input: floating point register number
+sub load_double_float_to_reg($)
+{
+    my ($fD) = @_;
+    my $ieee_double;   # ieee 754 double float value
+    my $ieee_high_bits; # the upper 16 bits of $ieee_double
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_double
+    my $higher_32_bits;
+    my $lower_32_bits;
+
+    $ieee_double = get_random_IEEE_double_value();
+
+    # loading a 64 bit double value is going to take some work
+
+    # load the higher 32 bits
+    $higher_32_bits = $ieee_double >> 32;   # push the lower 32 bits  
out
+    $ieee_high_bits = $higher_32_bits >> 16;
+    $ieee_low_bits = $higher_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);         # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);      # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $available_stack_slot);   # stw r10,  
$available_stack_slot(r1)
+
+    # load the lower 32 bits
+    $lower_32_bits = $ieee_double & 0xffffffff;
+    $ieee_high_bits = $lower_32_bits >> 16;
+    $ieee_low_bits = $lower_32_bits & 0xffff;
+    write_lis(10, $ieee_high_bits);             # lis r10,  
$ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);          # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $available_stack_slot + 4);   # stw r10,  
($available_stack_slot + 4)(r1)
+
+    write_lfd($fD, $available_stack_slot);      # lfd $fD,  
$available_stack_slot(r1)
+    return -1;
+}
+
+# Setup a testing environment for an instruction that requires
+# a single precision floating point value in a float register
+# input: floating point register number
+sub load_single_float_to_reg($)
+{
+    my ($fD) = @_;
+
+    # load a random single precision floating point value into memory
+    my $float_value = rand();
+    my $ieee_value = convert_to_IEEE($float_value);
+    my $ieee_high_bits; # the upper 16 bits of $ieee_value
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_value
+
+    $ieee_high_bits = $ieee_value >> 16;
+    $ieee_low_bits = $ieee_value & 0xffff;
+    write_lis(10, $ieee_high_bits);         # lis r10, $ieee_high_bits
+    write_ori(10, 10, $ieee_low_bits);      # ori r10, r10,  
$ieee_low_bits
+    write_stw(10, $available_stack_slot);   # stw r10,  
$available_stack_slot(r1)
+    write_lfs($fD, $available_stack_slot);  # lfs $fD,  
$available_stack_slot(r1)
+
+    return -1;  # this just says not not clean up any register
+}
+
+# Compiles the instructions
+# input: hash
+sub gen_one_insn($)
+{
+    # Given an instruction-details array, generate an instruction
+    my $constraintfailures = 0;
+
+    INSN: while(1) {
+        my ($rec) = @_;
+        my $insn = int(rand(0xffffffff));
+        my $insnname = $rec->{name};
+        my $insnwidth = $rec->{width};
+        my $fixedbits = $rec->{fixedbits};
+        my $fixedbitmask = $rec->{fixedbitmask};
+        my $constraint = $rec->{blocks}{"constraints"};
+        my $memblock = $rec->{blocks}{"memory"};
+
+        $insn &= ~$fixedbitmask;
+        $insn |= $fixedbits;
+
+        if (defined $constraint) {
+            # user-specified constraint: evaluate in an environment
+            # with variables set corresponding to the variable fields.
+            my $v = eval_with_fields($insnname, $insn, $rec,  
"constraints", $constraint);
+            if (!$v) {
+                $constraintfailures++;
+                if ($constraintfailures > 10000) {
+                    print "10000 consecutive constraint failures for  
$insnname constraints string:\n$constraint\n";
+                    exit (1);
+                }
+                next INSN;
+            }
+        }
+
+        # OK, we got a good one
+        $constraintfailures = 0;
+
+        my $basereg;    # The GPR that is used to calculate the load  
address
+
+        if (defined $memblock) {
+            # This is a load or store. We simply evaluate the block,
+            # which is expected to be a call to a function which emits
+            # the code to set up the base register and returns the
+            # number of the base register.
+
+            $basereg = eval_with_fields($insnname, $insn, $rec,  
"memory", $memblock);
+        }
+
+        debug_print("0x%x ; %s encoding\n", $insn, $insnname);
+        insn32($insn);
+
+        if (defined $memblock && $basereg >= 0) {
+            # cleanup any updated register
+            write_li($basereg, 0);
+        }
+
+        return;
+    }
+}
+
+# writes the instruction that signals risu
+# input: the signal
+sub write_risuop($)
+{
+    # instr with bits (28:27) == 0 0 are UNALLOCATED
+    my ($op) = @_;
+    debug_print("0x%x ; risu request\n", 0x00005af0 | $op);
+    insn32(0x00005af0 | $op);
+}
+
+# write the addi instruction
+# first input: destination register
+# second input: source register
+# third input: number
+sub write_addi($$$)
+{
+    my ($rD, $rA, $number) = @_;
+
+    debug_print("addi r%d, r%d, %d\n", $rD, $rA, $number);
+    # addi rD, rA, number
+    insn32((0xe << 26) | ($rD << 21) | ($rA << 16) | ($number &  
0xffff));
+}
+
+# writes the mr instruction
+# first input: destination register
+# second input: source register
+sub write_mr($$)
+{
+    my ($rD, $rS) = @_;
+    my $mr_encoding = 31; # it is really a mnemonic for 'or'
+    my $Rc = 0;
+
+    debug_print("mr r%d, r%d\n", $rD, $rS);
+    insn32($mr_encoding << 26 | $rS << 21 | $rD << 16 | $rS << 11 |  
444 << 1 | $Rc);
+}
+
+# writes a stb instruction
+# first input: register number
+# second input: offset from stack pointer
+sub write_stb($$)
+{
+    my ($rS, $offset) = @_;
+    my $stb_encoding = 38;
+    my $stack_pointer = 1;  # r1 is the stack pointer
+    debug_print("stb r$rS, $offset(r1)\n");
+    insn32($stb_encoding << 26 | $rS << 21 | $stack_pointer << 16 |  
$offset);
+}
+
+# writes a stw instruction
+# first input: register number
+# second input: offset from stack pointer
+sub write_stw($$)
+{
+    my ($rS, $offset) = @_;
+    my $stw_encoding = 36;
+    my $stack_pointer = 1;  # r1 is the stack pointer
+    debug_print("stw r$rS, $offset(r1)\n");
+    insn32($stw_encoding << 26 | $rS << 21 | $stack_pointer << 16 |  
$offset);
+}
+
+# writes a lfs instruction
+# first input: floating point register number
+# second input: offset from stack pointer
+sub write_lfs($$)
+{
+    my ($fD, $offset) = @_;
+    my $lfs_encoding = 48;
+    my $stack_pointer = 1; # r1 is the stack pointer
+    debug_print("lfs f$fD, $offset(r1)\n");
+    insn32($lfs_encoding << 26 | $fD << 21 | $stack_pointer << 16 |  
$offset);
+}
+
+# writes a lfd instruction
+# first input: floating point register number
+# second input: offset value
+sub write_lfd($$)
+{
+    my ($fD, $offset) = @_;
+    my $lfd_encoding = 50;
+    my $stack_pointer = 1; # r1 is the stack pointer
+    debug_print("lfd f$fD, $offset(r$stack_pointer)\n");
+    insn32($lfd_encoding << 26 | $fD << 21 | $stack_pointer << 16 |  
$offset);
+}
+
+# write the "li rx, value" instruction
+# first input: the register number
+# second input: the value
+sub write_li($$)
+{
+    my ($rD, $value) = @_;
+    debug_print("li r%d, 0x%x\n", $rD, $value);
+    insn32(0xe << 26 | $rD << 21 | $value);
+}
+
+# writes the lis instruction
+# first input: register number
+# second input: value
+sub write_lis($$)
+{
+    my ($register, $value) = @_;
+    my $lis_encoding = 15;
+    debug_print("lis r%d, 0x%x\n", $register, $value);
+    insn32($lis_encoding << 26 | $register << 21 | 0 << 16 | $value);
+}
+
+# writes the ori instruction
+# first input: destination register
+# second input: source register
+# third input: number
+sub write_ori($$$)
+{
+    my ($dest_reg, $source_reg, $number) = @_;
+    my $ori_encoding = 24;
+    debug_print("ori r%d, r%d, 0x%x\n", $dest_reg, $source_reg,  
$number);
+    insn32($ori_encoding << 26 | $dest_reg << 21 | $source_reg << 16  
| $number);
+}
+
+# writes the mtfsb0 instruction
+# input: fpscr field number
+sub write_mtfsb0($)
+{
+    my $mtfsb0_encoding = 63;
+    my $crbD = $_[0];
+    my $Rc = 0;
+    debug_print("mtfsb0 %d\n", $crbD);
+    insn32($mtfsb0_encoding << 26 | $crbD << 21 | 70 << 1 | $Rc);
+}
+
+# writes the mtfsb1 instruction
+# input: fpscr field number
+sub write_mtfsb1($)
+{
+    my $mtfsb1_encoding = 63;
+    my $crbD = $_[0];
+    my $Rc = 0;
+    debug_print("mtfsb1 %d\n", $crbD);
+    insn32($mtfsb1_encoding << 26 | $crbD << 21 | 38 << 1 | $Rc);
+}
+
+# writes the mtxer instruction
+# first input: source register
+sub write_mtxer($)
+{
+    my ($rS) = @_;
+    my $mtspr_encoding = 31;   # mtxer is really mtspr
+    my $spr = 16;
+    my $raw_encoding;
+
+    debug_print("mtxer r%d\n", $rS);
+    $raw_encoding = $mtspr_encoding << 26 | $rS << 21 | $spr << 12 |  
467 << 1 | 0;
+    insn32($raw_encoding);
+}
+
+# writes the mtcrf instruction
+# first input: condition register mask
+# second input: source register
+sub write_mtcrf($$)
+{
+    my ($CRM, $rS) = @_;
+    my $mtcrf_encoding = 31;
+    debug_print("mtcrf %d, r%d\n", $CRM, $rS);
+    insn32($mtcrf_encoding << 26 | $rS << 21 | $CRM << 12 | 144 << 1);
+}
+
+# setup the testing environment for the lmw instruction
+# first input: general purpose register number
+# second input: general purpose regiser number
+# third input: immediate value
+# ouptut: general purpose register number
+sub setup_lmw_test($$$)
+{
+    my ($rD, $rA, $imm) = @_;
+    for(my $i = 0; $i < (32 - $rD); $i++) {
+        write_li(10, $i);                   # li r10, $i
+        write_stw(10, $imm + ($i * 4));     # stw r10, ($imm + $i *  
4)(r1)
+    }
+    write_mr($rA, 1);                       # mr $rA, r1
+    debug_print("lmw r$rD, $imm(r$rA)\n");
+    return $rA;
+}
+
+# setup the testing environment for the lswi instruction
+# first input: general purpose register number
+# second input: general purpose register number
+# third input: number of bytes to load
+# output: general purpose register number
+sub setup_lswi_test($$$)
+{
+    my ($rD, $rA, $NB) = @_;
+    my $imm;
+
+    write_lis(10, 0xabcd);                      # lis r10, 0x6861
+    write_ori(10, 10, 0xef12);                  # ori r10, r10, 0x636B
+
+    # fill the memory with $NB bytes of data
+    for(my $i = 0; $i < $NB; $i++) {
+        $imm = $available_stack_slot + $i * 4;
+        write_stw(10, $imm);                        # stw r10, $imm(r1)
+    }
+    write_mr($rA, 1);                               # mr $rA, r1
+    write_addi($rA, $rA, $available_stack_slot);    # addi $rA, $rA,  
$available_stack_slot
+    debug_print("lswi r$rD, r$rA, $NB\n");
+    return $rA;
+}
+
+# setup the testing environment for the lswx instruction
+# first input: general purpose register number
+# second input: general purpose register number
+# third input: general purpose register number
+# output: general purpose register number
+sub setup_lswx_test($$$)
+{
+    my ($rD, $rA, $rB) = @_;
+    my $bytes_per_register = 4;   # four bytes can fit in one  
general purpose register
+    my $num_gpr = 32;   # the number of general purpose registers
+
+    # This prevents LSWX from wrapping around and loading r0
+    my $num_bytes = int rand(64);
+    if (($num_bytes/$bytes_per_register) > ($num_gpr - $rD)) {
+        $num_bytes = ($num_gpr - $rD) * $bytes_per_register;
+    }
+
+    # Prevent registers rA and rB from being in the loading path
+
+    my $regA = 0;
+    my $regB = 0;
+    my $closest_register;
+    my $overlap;
+
+    # determine distance from register rD
+    if ($rA - $rD > 0) {
+        $regA = $rA;
+    }
+
+    if ($rB - $rD > 0) {
+        $regB = $rB;
+    }
+
+    # both rA and rB are in the load path
+    if ($regA > 0 && $regB > 0) {
+        # find the register closest to rD
+        $closest_register = ($regA < $regB) ? $regA : $regB;
+    }
+
+    # only rA is in the load path
+    elsif ($regA != 0 && $regB == 0) {
+        $closest_register = $regA;
+    }
+
+    # only rB is in the load path
+    elsif ($regA == 0 && $regB != 0) {
+        $closest_register = $regB;
+    }
+
+    # no register is in the load path
+    else {
+        $closest_register = -1;
+    }
+
+    # calculate new safe value for num_bytes
+    if ($closest_register != -1 && $num_bytes >= ($closest_register  
- $rD) * $bytes_per_register) {
+        $num_bytes = ($closest_register - $rD) * $bytes_per_register;
+    }
+
+    write_li(10, $num_bytes);                            # li r10,  
$num_bytes
+    write_mtxer(10);                                     # mtxer r10
+
+    # Fill memory with values
+    for(my $i = 0; $i < $num_bytes; $i++) {
+        write_li(10, $i + 1);                            # li r10,  
($i+1)
+        write_stb(10, $available_stack_slot + $i);       # stb r10,  
($available_stack_slot + $i)(r1)
+    }
+
+    write_mr($rA, 1);                                    # mr $rA, r1
+    write_li($rB, $available_stack_slot);                # li $rB,  
$available_stack_slot
+
+    debug_print("lswx r$rD, r$rA, r$rB ; xer:$num_bytes\n");
+
+    return $rA;
+}
+
+# writes the code that sets the general purpose registers
+sub write_init_gpr_code()
+{
+    # Set the general purpose registers to a value.
+    # Register r1 is the stack pointer.
+    # It is left alone.
+    for (my $i = 0; $i < 32; $i++) {
+        if ($i == 1) {
+            next;
+        }
+        write_li($i, $i + 1);
+    }
+}
+
+# set the initial value to all floating point registers
+sub write_init_float_registers_code()
+{
+    my $value = 1.1;
+    my $ieee_value;
+    my $ieee_high_bits; # the upper 16 bits of $ieee_value
+    my $ieee_low_bits;  # the lower 16 bits of $ieee_value
+
+    for(my $i = 0; $i < 32; $i++) {
+        $ieee_value = convert_to_IEEE($value + $i);
+        $ieee_high_bits = $ieee_value >> 16;
+        $ieee_low_bits = $ieee_value & 0xffff;
+        write_lis(10, $ieee_high_bits);         # lis r10,  
$ieee_high_bits
+        write_ori(10, 10, $ieee_low_bits);      # ori r10, r10,  
$ieee_low_bits
+        write_stw(10, $available_stack_slot);   # stw r10,  
$available_stack_slot(r1)
+        write_lfs($i, $available_stack_slot);   # lfs fD,  
$available_stack_slot(r1)
+    }
+}
+
+# set the fpscr to the requested value
+# input: value
+sub write_init_fpscr_code($)
+{
+    my ($value) = @_;
+    my $num_fpscr_fields = 32;
+
+    for (my $i = 0; $i < $num_fpscr_fields; $i++) {
+        if (($value >> $i) & 0x1) {
+            write_mtfsb1($i);
+        }
+        else {
+            write_mtfsb0($i);
+        }
+    }
+}
+
+# sets the xer register to zero
+sub write_init_xer_code()
+{
+    my $rS = 10;
+    my $value = 0;
+    write_li($rS, $value);
+    write_mtxer($rS);
+}
+
+# sets the lr to zero
+sub write_init_lr_code()
+{
+    my $rS = 10;
+    my $value = 0;
+    write_li($rS, $value);
+    debug_print("mtlr r%d\n", $rS);
+    insn32(0x7d4803a6);
+}
+
+# set the ctr to zero
+sub write_init_ctr_code()
+{
+    my $rS = 10;
+    my $value = 0;
+    write_li($rS, $value);
+    debug_print("mtctr r%d\n", $rS);
+    insn32(0x7d4903a6);
+}
+
+
+# set the condition register to zero
+sub write_init_cr_code()
+{
+    my $r10 = 10;
+    my $value = 0;
+    my $CRM = 0xff;
+    write_li($r10, $value);
+    write_mtcrf($CRM, $r10);
+}
+
+# This is called by the risugen program.
+# Execution starts here.
+# input: hash
+sub write_test_code($)
+{
+    my ($params) = @_;
+    my $numinsns = $params->{ 'numinsns' };
+    my $fp_enabled = $params->{ 'fp_enabled' };
+    my $outfile = $params->{ 'outfile' };
+    my $fpscr = $params->{ 'fpscr' };
+    my @pattern_re = @{ $params->{ 'pattern_re' } };
+    my @not_pattern_re = @{ $params->{ 'not_pattern_re' } };
+    my %insn_details = %{ $params->{ 'details' } };
+
+    set_endian(1);   # Set to big endian
+    open_bin($outfile);