From nobody Mon Nov 25 09:50:43 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1716752326; cv=none; d=zohomail.com; s=zohoarc; b=kOXa9ksQNrVZIe3tbMiq3I1yXVAu2YYwrfIwRK/jtNmvL1yutzO3h8lVCwfzmCHqjb51r7vSCw7gjj5pRFXrspgeUqB7d7X93o1Fiytzgj8qf2xZyBOcMAOyzShpCl5YfyQBh4TjxUfXiFUssW0+1kUz5bzW4IAzOZd+Ze5hD5E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1716752326; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=MCy66KKepWlHqXyVaIB/ACSSH0v8RsXCcqK/IUUC3fY=; b=AwUT/Nn1f0+mF7MU3DNvwbV8Jo5Ld3Ph/NM+GOMNsrnInUMjpsM+Hph8Gfp4fxyZbVHykPPQOA4SNrlpIGWwwlde6YqGuZkpz9YULrHlLA4SYyMU3VR3b/GNFqi9CCuANQxQ6gs4nkxIgRui8uiIKX8v2jdHK6Hu1UhDd+3kVq4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1716752326415525.2060226865062; Sun, 26 May 2024 12:38:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sBJfx-00082V-10; Sun, 26 May 2024 15:37:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sBJfr-000802-Eo for qemu-devel@nongnu.org; Sun, 26 May 2024 15:36:55 -0400 Received: from mail-pj1-x1034.google.com ([2607:f8b0:4864:20::1034]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sBJfl-0006UF-Mq for qemu-devel@nongnu.org; Sun, 26 May 2024 15:36:55 -0400 Received: by mail-pj1-x1034.google.com with SMTP id 98e67ed59e1d1-2bf5e177ebdso2095946a91.1 for ; Sun, 26 May 2024 12:36:45 -0700 (PDT) Received: from stoup.. (174-21-72-5.tukw.qwest.net. [174.21.72.5]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2bf5f6155b6sm4943761a91.29.2024.05.26.12.36.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 26 May 2024 12:36:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1716752204; x=1717357004; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=MCy66KKepWlHqXyVaIB/ACSSH0v8RsXCcqK/IUUC3fY=; b=D6Kxh3PNvStWvdIF1Uwmdal0jzLgBgNr7BzfvZv/FBTVqDsk0dAVI7NE7NbpiQgnmL Ki0/s8cUITn9ltHkBPFA3eb+uoDSwtQOwdTYyfDJMLAvuYGw7FBpkFlB8ocEFaoIFEI2 BPasuMkY5hT354aBPdM781iWSB3X7guk7G1l8t3Uo3oKMabl68xBLic+Yz3OdLrjdI6/ BBEh8R5MLaTfQDCgZ4vtqDlXJ73d+N3Iu4iJvk6jpI6PdiTWiOZrzivcIw4x0ktfwbrJ XIBvCNOigTi7NW0jgulRlccUUj0ZX3lziEjCCfw1HVSVf5oTuoGuq8gbwmvSYv1Avhay Eyhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716752204; x=1717357004; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MCy66KKepWlHqXyVaIB/ACSSH0v8RsXCcqK/IUUC3fY=; b=d2opU/KtLMD8Wl6/4K9nh/8jL5c6gnnSIWKbuaQdcFLTJhzQErP/833LKKDREt9owm HtkP7eOU8SUPwGue2J6MEKZnBysXtwagph52P9/pWmSndqmeuj/vgEI/CJyE2Dr7BOYz dSuVjFN0Q6uE/vvmAY9MYbT82X4dVtQhPxTZQaEVZka1gXAt3q+4SO4u22/VWztHz9bT /ndHdsw5p1D2ILm2PNjdv/HHPBnsCXu8SbpItRaH6vTOUT0abGpFHJGU1QBUkk3SgR5D IXF+8Yvo+GeoeBIiCIgPLoZb7tHiMRFpgUWTlFr9J6GJcGTr30zLpK+ef0U5wj3bKnbC RaTA== X-Gm-Message-State: AOJu0YxXLZvLTOQ1vM5bCkk06hAWi2KEJ+j66Z/VIJtV+aVbfvsKfvqU Z4i4CzPvZSqmQyoiqhMBtr9axQC76zgfn2ViuXfxkQQnbbeZDBqZYzpmVAsVRZcMgq8OxqKDHHn B X-Google-Smtp-Source: AGHT+IHu0Hm01icjL+LtRk7j5ELkhLGgxJqq4i5B/ZVSxYbB9W7qmuzwzdF2znM/YY72RUoQVCbZ4g== X-Received: by 2002:a17:90b:d98:b0:2bd:8cf6:107d with SMTP id 98e67ed59e1d1-2bf5e84ace6mr7449859a91.7.1716752204058; Sun, 26 May 2024 12:36:44 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Cc: mark.cave-ayland@ilande.co.uk Subject: [PATCH RISU v2 06/13] risugen: Add sparc64 support Date: Sun, 26 May 2024 12:36:30 -0700 Message-Id: <20240526193637.459064-7-richard.henderson@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240526193637.459064-1-richard.henderson@linaro.org> References: <20240526193637.459064-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1034; envelope-from=richard.henderson@linaro.org; helo=mail-pj1-x1034.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1716752327620100002 Content-Type: text/plain; charset="utf-8" Signed-off-by: Richard Henderson --- risugen | 10 +- risugen_common.pm | 50 +++++- risugen_sparc64.pm | 385 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 risugen_sparc64.pm diff --git a/risugen b/risugen index 2800b8b..830dfd3 100755 --- a/risugen +++ b/risugen @@ -310,6 +310,8 @@ Valid options: Useful to test before support for FP is available. --sve : enable sve floating point --be : generate instructions in Big-Endian byte order (ppc64 o= nly). + --cross prefix : prefix for the assembler and linker + --keep : do not remove intermediate files --help : print this message EOT } @@ -322,6 +324,8 @@ sub main() my $fp_enabled =3D 1; my $sve_enabled =3D 0; my $big_endian =3D 0; + my $cross_prefix =3D ""; + my $keep =3D 0; my ($infile, $outfile); =20 GetOptions( "help" =3D> sub { usage(); exit(0); }, @@ -339,6 +343,8 @@ sub main() "be" =3D> sub { $big_endian =3D 1; }, "no-fp" =3D> sub { $fp_enabled =3D 0; }, "sve" =3D> sub { $sve_enabled =3D 1; }, + "cross-prefix=3Ds" =3D> \$cross_prefix, + "keep" =3D> sub { $keep =3D 1; }, ) or return 1; # allow "--pattern re,re" and "--pattern re --pattern re" @pattern_re =3D split(/,/,join(',',@pattern_re)); @@ -372,7 +378,9 @@ sub main() 'keys' =3D> \@insn_keys, 'arch' =3D> $full_arch[0], 'subarch' =3D> $full_arch[1] || '', - 'bigendian' =3D> $big_endian + 'bigendian' =3D> $big_endian, + 'cross_prefix' =3D> $cross_prefix, + 'keep' =3D> $keep, ); =20 write_test_code(\%params); diff --git a/risugen_common.pm b/risugen_common.pm index 5207c0e..228082f 100644 --- a/risugen_common.pm +++ b/risugen_common.pm @@ -26,7 +26,8 @@ BEGIN { our @EXPORT =3D qw(open_bin close_bin set_endian insn32 insn16 $byteco= unt progress_start progress_update progress_end eval_with_fields is_pow_of_2 sextract ctz - dump_insn_details); + dump_insn_details + open_asm close_asm assemble_and_link); } =20 our $bytecount; @@ -66,6 +67,53 @@ sub insn16($) $bytecount +=3D 2; } =20 +sub open_asm($) +{ + my ($basename) =3D @_; + my $fname =3D $basename . ".s"; + open(ASM, ">", $fname) or die "can't open $fname: $!"; + select ASM; +} + +sub close_asm +{ + close(ASM) or die "can't close asm file: $!"; + select STDOUT; +} + +sub assemble_and_link($$$@) +{ + my ($basename, $cross_prefix, $keep, @asflags) =3D @_; + my $asmfile =3D $basename . ".s"; + my $ldfile =3D $basename . ".ld"; + my $objfile =3D $basename . ".o"; + + open(LD, ">", $ldfile) or die "can't open $ldfile: $!"; + print LD ' + ENTRY(start) + PHDRS { text PT_LOAD FILEHDR PHDRS; } + SECTIONS { + . =3D SIZEOF_HEADERS; + PROVIDE(start =3D .); + .text : { *(.text) } :text + .data : { *(.data) } :text + } + '; + close(LD); + + my @as =3D ($cross_prefix . "as", @asflags, "-o", $objfile, $asmfile); + system(@as) =3D=3D 0 or die "system @as failed: $?"; + + my @ld =3D ($cross_prefix . "ld", "-o", $basename, "-T", $ldfile, $obj= file); + system(@ld) =3D=3D 0 or die "system @ld failed: $?"; + + if (!$keep) { + unlink $asmfile; + unlink $ldfile; + unlink $objfile; + } +} + # Progress bar implementation my $lastprog; my $proglen; diff --git a/risugen_sparc64.pm b/risugen_sparc64.pm new file mode 100644 index 0000000..c9f2ede --- /dev/null +++ b/risugen_sparc64.pm @@ -0,0 +1,385 @@ +#!/usr/bin/perl -w +##########################################################################= ##### +# Copyright (c) 2024 Linaro Limited +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +##########################################################################= ##### + +# risugen -- generate a test binary file for use with risu +# See 'risugen --help' for usage information. +package risugen_sparc64; + +use strict; +use warnings; + +use risugen_common; + +require Exporter; + +our @ISA =3D qw(Exporter); +our @EXPORT =3D qw(write_test_code); + +my $periodic_reg_random =3D 1; + +# Maximum alignment restriction permitted for a memory op. +my $MAXALIGN =3D 64; +my $MAXBLOCK =3D 2048; +my $PARAMREG =3D 15; # %o7 + +my $OP_COMPARE =3D 0; # compare registers +my $OP_TESTEND =3D 1; # end of test, stop +my $OP_SETMEMBLOCK =3D 2; # g1 is address of memory block (8192 bytes) +my $OP_GETMEMBLOCK =3D 3; # add the address of memory block to g1 +my $OP_COMPAREMEM =3D 4; # compare memory block + +my @GREGS =3D ( "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i6", "%i7" ); + +sub write_data32($) +{ + my ($val) =3D @_; + printf "\t.word\t%#x\n", $val; +} + +sub write_data64($) +{ + my ($val) =3D @_; + printf "\t.quad\t%#x\n", $val; +} + +sub write_risuop($) +{ + my ($op) =3D @_; + printf "\tilltrap\t%#x\n", 0xdead0 + $op; +} + +sub write_mov_rr($$) +{ + my ($rd, $rs) =3D @_; + printf "\tmov\t%s,%s\n", $GREGS[$rs], $GREGS[$rd]; +} + +sub write_mov_ri($$) +{ + my ($rd, $imm) =3D @_; + + if (-0x1000 <=3D $imm < 0x1000) { + printf "\tmov\t%d,%s\n", $imm, $GREGS[$rd]; + } else { + my $immhi =3D $imm & 0xfffff000; + my $immlo =3D $imm & 0x00000fff; + + if ($imm < 0) { + $immhi ^=3D 0xfffff000; + $immlo |=3D -0x1000; + } + printf "\tsethi\t%%hi(%d),%s\n", $immhi, $GREGS[$rd]; + if ($immlo !=3D 0) { + printf "\txor\t%s,%d,%s\n", $GREGS[$rd], $immlo, $GREGS[$rd]; + } + } +} + +sub write_add_rri($$$) +{ + my ($rd, $rs, $imm) =3D @_; + die "bad imm!" if ($imm < -0x1000 || $imm >=3D 0x1000); + + printf "\txor\t%s,%d,%s\n", $GREGS[$rs], $imm, $GREGS[$rd]; +} + +sub write_sub_rrr($$$) +{ + my ($rd, $rs1, $rs2) =3D @_; + + printf "\tsub\t%s,%s,%s\n", $GREGS[$rs1], $GREGS[$rs2], $GREGS[$rd]; +} + +sub begin_datablock($$) +{ + my ($align, $label) =3D @_; + die "bad align!" if ($align < 4 || $align > 255 || !is_pow_of_2($align= )); + + printf ".data\n"; + printf "\t.balign %d\n", $align; + printf "%s:\n", $label; +} + +sub end_datablock() +{ + printf ".text\n" +} + +sub write_ref_datablock($$$$) +{ + my ($rd, $offset, $scratch, $label) =3D @_; + + printf "\trd\t%%pc,%s\n", $GREGS[$rd]; + printf "\tsethi\t%%pc22(%s+%d),%s\n", + $label, $offset + 4, $GREGS[$scratch]; + printf "\tor\t%s,%%pc10(%s+%d),%s\n", + $GREGS[$scratch], $label, $offset + 8, $GREGS[$scratch]; + printf "\tadd\t%s,%s,%s\n", $GREGS[$scratch], $GREGS[$rd], $GREGS[$rd]; +} + +sub write_random_register_data($$) +{ + my ($fp_enabled, $fsr) =3D @_; + my $size =3D 32 * 8; + + if ($fp_enabled) { + # random data for 32 double-precision regs plus %gsr + $size +=3D $fp_enabled ? 33 * 8 : 0; + } + + begin_datablock(8, "1"); + for (my $i =3D 0; $i < $size; $i +=3D 4) { + write_data32(rand(0xffffffff)); + } + if ($fp_enabled) { + # %fsr gets constant data + write_data64($fsr); + } + end_datablock(); + + write_ref_datablock(1, 0, 2, "1b"); + + # Load floating point / SIMD registers + if ($fp_enabled) { + for (my $rt =3D 0; $rt < 64; $rt +=3D 2) { + printf "\tldd\t[%s+%d],%%f%d\n", $GREGS[1], 32 * 8 + $rt * 4, = $rt; + } + printf "\tldx\t[%s+%d],%s\n", $GREGS[1], 64 * 8, $GREGS[2]; + printf "\twr\t%s,0,%%gsr\n", $GREGS[2]; + printf "\tldx\t[%s+%d],%%fsr\n", $GREGS[1], 65 * 8; + } + + # Load Y + printf "\tldx\t[%s],%s\n", $GREGS[1], $GREGS[2]; + printf "\twr\t%s,0,%%y\n", $GREGS[2]; + + # Clear flags + printf "\twr\t%%g0,0,%%ccr\n"; + + # Load general purpose registers + for (my $i =3D 31; $i >=3D 1; --$i) { + if (reg_ok($i)) { + printf "\tldx\t[%s+%d],%s\n", $GREGS[1], $i * 8, $GREGS[$i]; + } + } + + write_risuop($OP_COMPARE); +} + +sub write_memblock_setup() +{ + begin_datablock($MAXALIGN, "2"); + + for (my $i =3D 0; $i < $MAXBLOCK; $i +=3D 4) { + write_data32(rand(0xffffffff)); + } + + end_datablock(); + write_ref_datablock($PARAMREG, 0, 1, "2b"); + write_risuop($OP_SETMEMBLOCK); +} + +# Functions used in memory blocks to handle addressing modes. +# These all have the same basic API: they get called with parameters +# corresponding to the interesting fields of the instruction, +# and should generate code to set up the base register to be +# valid. They must return the register number of the base register. +# The last (array) parameter lists the registers which are trashed +# by the instruction (ie which are the targets of the load). +# This is used to avoid problems when the base reg is a load target. + +# Global used to communicate between align(x) and reg() etc. +my $alignment_restriction; + +sub align($) +{ + my ($a) =3D @_; + if (!is_pow_of_2($a) || !(0 < $a <=3D $MAXALIGN)) { + die "bad align() value $a\n"; + } + $alignment_restriction =3D $a; +} + +sub gen_memblock_offset() +{ + # Generate a random offset within the memory block, of the correct + # alignment. We require the offset to not be within 16 bytes of either + # end, to (more than) allow for the worst case data transfer. + return (rand($MAXBLOCK - 32) + 16) & ~($alignment_restriction - 1); +} + +sub reg_ok($) +{ + my ($r) =3D @_; + + # Avoid special registers %g7 (tp), %o6 (sp), %i6 (fp). + return $r !=3D 7 && $r !=3D 14 && $r !=3D 30; +} + +sub reg_plus_imm($$@) +{ + # Handle reg + immediate addressing mode + my ($base, $imm, @trashed) =3D @_; + my $offset =3D gen_memblock_offset(); + my $scratch =3D $base !=3D 1 ? 1 : 2; + + write_ref_datablock($base, $offset - $imm, $scratch, "2b"); + write_mov_ri($scratch, 0); + + if (grep $_ =3D=3D $base, @trashed) { + return -1; + } + return $base; +} + +sub reg($@) +{ + my ($base, @trashed) =3D @_; + return reg_plus_imm($base, 0, @trashed); +} + +sub reg_plus_reg($$@) +{ + # Handle reg + reg addressing mode + my ($base, $idx, @trashed) =3D @_; + my $offset =3D gen_memblock_offset(); + my $scratch =3D 1; + + if ($base =3D=3D $idx) { + return -1; + } + + while ($base =3D=3D $scratch || $idx =3D=3D $scratch) { + ++$scratch; + } + + write_ref_datablock($base, $offset, $scratch, "2b"); + write_mov_ri($scratch, 0); + write_sub_rrr($base, $base, $idx); + + if (grep $_ =3D=3D $base, @trashed) { + return -1; + } + return $base; +} + +sub gen_one_insn($) +{ + my ($rec) =3D @_; + my $insnname =3D $rec->{name}; + my $insnwidth =3D $rec->{width}; + my $fixedbits =3D $rec->{fixedbits}; + my $fixedbitmask =3D $rec->{fixedbitmask}; + my $constraint =3D $rec->{blocks}{"constraints"}; + my $memblock =3D $rec->{blocks}{"memory"}; + + # Given an instruction-details array, generate an instruction + my $constraintfailures =3D 0; + + INSN: while(1) { + my $insn =3D int(rand(0xffffffff)); + + $insn &=3D ~$fixedbitmask; + $insn |=3D $fixedbits; + + if (defined $constraint) { + # User-specified constraint: evaluate in an environment + # with variables set corresponding to the variable fields. + my $v =3D eval_with_fields($insnname, $insn, $rec, "constraint= s", $constraint); + if (!$v) { + $constraintfailures++; + if ($constraintfailures > 10000) { + print "10000 consecutive constraint failures for $insn= name constraints string:\n$constraint\n"; + exit (1); + } + next INSN; + } + } + + # OK, we got a good one + $constraintfailures =3D 0; + + my $basereg; + + 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. + align(16); + $basereg =3D eval_with_fields($insnname, $insn, $rec, "memory"= , $memblock); + } + + write_data32($insn); + + if (defined $memblock) { + # Clean up following a memory access instruction: + # we need to turn the (possibly written-back) basereg + # into an offset from the base of the memory block, + # to avoid making register values depend on memory layout. + # $basereg -1 means the basereg was a target of a load + # (and so it doesn't contain a memory address after the op) + if ($basereg !=3D -1) { + write_mov_ri($basereg, 0); + } + write_risuop($OP_COMPAREMEM); + } + return; + } +} + +sub write_test_code($) +{ + my ($params) =3D @_; + + my $fp_enabled =3D $params->{ 'fp_enabled' }; + my $fsr =3D $params->{ 'fpscr' }; + my $numinsns =3D $params->{ 'numinsns' }; + my $outfile =3D $params->{ 'outfile' }; + + my %insn_details =3D %{ $params->{ 'details' } }; + my @keys =3D @{ $params->{ 'keys' } }; + + open_asm($outfile); + + # TODO better random number generator? + srand(0); + + print STDOUT "Generating code using patterns: @keys...\n"; + progress_start(78, $numinsns); + + if (grep { defined($insn_details{$_}->{blocks}->{"memory"}) } @keys) { + write_memblock_setup(); + } + + # memblock setup doesn't clean its registers, so this must come afterw= ards. + write_random_register_data($fp_enabled, $fsr); + + for my $i (1..$numinsns) { + my $insn_enc =3D $keys[int rand (@keys)]; + gen_one_insn($insn_details{$insn_enc}); + write_risuop($OP_COMPARE); + # Rewrite the registers periodically. + if ($periodic_reg_random && ($i % 100) =3D=3D 0) { + write_random_register_data($fp_enabled, $fsr); + } + progress_update($i); + } + write_risuop($OP_TESTEND); + progress_end(); + + close_asm(); + assemble_and_link($outfile, $params->{ 'cross_prefix' }, + $params->{ 'keep' }, "-Av9a"); +} + +1; --=20 2.34.1