| 1 | # ========== Copyright Header Begin ========================================== |
| 2 | # |
| 3 | # OpenSPARC T2 Processor File: arch_diags.pm |
| 4 | # Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved |
| 5 | # 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
| 6 | # |
| 7 | # * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 8 | # |
| 9 | # This program is free software; you can redistribute it and/or modify |
| 10 | # it under the terms of the GNU General Public License as published by |
| 11 | # the Free Software Foundation; version 2 of the License. |
| 12 | # |
| 13 | # This program is distributed in the hope that it will be useful, |
| 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | # GNU General Public License for more details. |
| 17 | # |
| 18 | # You should have received a copy of the GNU General Public License |
| 19 | # along with this program; if not, write to the Free Software |
| 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | # |
| 22 | # For the avoidance of doubt, and except that if any non-GPL license |
| 23 | # choice is available it will apply instead, Sun elects to use only |
| 24 | # the General Public License version 2 (GPLv2) at this time for any |
| 25 | # software where a choice of GPL license versions is made |
| 26 | # available with the language indicating that GPLv2 or any later version |
| 27 | # may be used, or where a choice of which version of the GPL is applied is |
| 28 | # otherwise unspecified. |
| 29 | # |
| 30 | # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 31 | # CA 95054 USA or visit www.sun.com if you need additional information or |
| 32 | # have any questions. |
| 33 | # |
| 34 | # ========== Copyright Header End ============================================ |
| 35 | |
| 36 | package arch_diags; |
| 37 | |
| 38 | use strict; |
| 39 | use BigIntSupport; |
| 40 | use Getopt::Long; |
| 41 | |
| 42 | require Exporter; |
| 43 | use vars qw(@ISA @EXPORT); |
| 44 | |
| 45 | my @ISA = qw(Exporter); |
| 46 | use vars qw(%opt); |
| 47 | my @EXPORT = qw(%opt); |
| 48 | |
| 49 | my @ld_freg = ("ld", "ldd", "ldq", "ldx"); |
| 50 | |
| 51 | my @fregs = ( "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", |
| 52 | "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", |
| 53 | "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", |
| 54 | "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31" ); |
| 55 | |
| 56 | my @fregs_dbl = ( 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, |
| 57 | 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, |
| 58 | 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, |
| 59 | 60, 62); |
| 60 | |
| 61 | |
| 62 | my @iregs = ( "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", |
| 63 | "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", |
| 64 | "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23", |
| 65 | "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31" ); |
| 66 | |
| 67 | my @walking1_iregs = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x1f); |
| 68 | my @walking1_imm13 = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20,0x40,0x80, |
| 69 | 0x100, 0x200, 0x400, 0x800, 0x1000, 0x1fc0); |
| 70 | |
| 71 | my $ILLIMM = 0x80000000; |
| 72 | |
| 73 | |
| 74 | #my @all_fbfcc = ("fba", "fbn", "fbu", "fbg", "fbug", "fbl", "fbul", "fblg", "fbne", "fbe", "fbue", |
| 75 | # "fbge", "fbuge", "fble", "fbule", "fbo"); |
| 76 | my @imm22_targets = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x3ff000, 0x3ffff0); |
| 77 | |
| 78 | my @imm19_targets = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x7f000, 0x7fff0); |
| 79 | |
| 80 | my %mem_inst = (ld => 1, ldd => 1, lda => 1, ldda => 1); |
| 81 | |
| 82 | my %cti_inst = ( |
| 83 | ba => 1, bn => 1, bne => 1, be => 1, bg => 1, ble => 1, |
| 84 | bge => 1, bl => 1, bgu => 1, bleu => 1, bcc => 1, bcs => 1, |
| 85 | bpos => 1, bneg => 1, bvc => 1, bvs => 1, |
| 86 | fba => 1, fbn => 1, fbu => 1, fbg => 1, fbug => 1, fbl => 1, |
| 87 | fbul => 1, fblg => 1, fbne => 1, fbe => 1, fbue => 1, fbge => 1, |
| 88 | fbuge => 1, fble => 1, fbule => 1, fbo => 1 |
| 89 | ); |
| 90 | |
| 91 | %opt = ( |
| 92 | name => "", # name of the diag |
| 93 | thrd_count => 1, |
| 94 | thrd_stride => 1, |
| 95 | super => 0, # run in supervisor mode |
| 96 | hyper => 0, # run in hypervisor mode |
| 97 | enboff => 0, # run in hypervisor mode |
| 98 | inst => "", # instruction to execute |
| 99 | inst_group => "", # instruction to execute |
| 100 | illinst => 0, # generate illinst trap |
| 101 | fpdis => 0, # generate fpdisable trap |
| 102 | dmisalgn => 0, # generate double-misalign trap |
| 103 | misalgn => 0, # generate misalign trap |
| 104 | dataacc => 0, # generate dataacc trap |
| 105 | privact => 0, # generate privact trap |
| 106 | vawatch => 0, # generate vamatch trap |
| 107 | seltrap => 0, # generate vamatch trap |
| 108 | alldest => 0, # try all dest regs |
| 109 | range_param => 0, # generic range.. of any type |
| 110 | mem_inst => 0, |
| 111 | cti_inst => 0 |
| 112 | ); |
| 113 | |
| 114 | |
| 115 | my @options = |
| 116 | qw( |
| 117 | name=s |
| 118 | thrd_count=i |
| 119 | thrd_stride=i |
| 120 | super=i |
| 121 | hyper=i |
| 122 | enboff=i |
| 123 | inst=s |
| 124 | inst_group=s |
| 125 | illinst=i |
| 126 | fpdis=i |
| 127 | dmisalgn=i |
| 128 | misalgn=i |
| 129 | dataacc=i |
| 130 | privact=i |
| 131 | vawatch=i |
| 132 | seltrap=i |
| 133 | alldest=i |
| 134 | range_param=i |
| 135 | mem_inst=i |
| 136 | cti_inst=i |
| 137 | ); |
| 138 | |
| 139 | sub setup_diag_options() { |
| 140 | GetOptions(\%opt, @options); |
| 141 | |
| 142 | my @diag_run_args = split(/_/, $opt{name}); |
| 143 | my $index = 0; |
| 144 | printf("!Diag run options :\n"); |
| 145 | foreach my $diag_run_arg (@diag_run_args) { |
| 146 | if($index == 0) { |
| 147 | $opt{inst_group} = $diag_run_arg; |
| 148 | printf("!inst_group = %-20s\n", $opt{inst_group}); |
| 149 | } |
| 150 | elsif($index == 1) { |
| 151 | $opt{inst} = $diag_run_arg; |
| 152 | printf("!inst = %-20s\n", $opt{inst}); |
| 153 | } |
| 154 | else { |
| 155 | $opt{$diag_run_arg}=1; |
| 156 | printf("!%s = %d\n", $diag_run_arg, $opt{$diag_run_arg}); |
| 157 | } |
| 158 | $index++; |
| 159 | } |
| 160 | $opt{mem_inst} = 1 if($mem_inst{$opt{inst}}); |
| 161 | $opt{cti_inst} = 1 if($cti_inst{$opt{inst}}); |
| 162 | } |
| 163 | |
| 164 | my $locked_regs = 0; |
| 165 | sub lock_regs() { |
| 166 | my (@regs) = @_; |
| 167 | foreach my $reg (@regs) { |
| 168 | if(($locked_regs & (0x1 << $reg)) == 0) { |
| 169 | $locked_regs |= (0x1 << $reg); |
| 170 | } |
| 171 | else { |
| 172 | printf("ERROR: reg %d is already locked\n", $reg); |
| 173 | } |
| 174 | } |
| 175 | printf("!lock_temp_reg locked regs = 0x%x\n", $locked_regs); |
| 176 | } |
| 177 | sub release_regs() { |
| 178 | my (@regs) = @_; |
| 179 | foreach my $reg (@regs) { |
| 180 | if($locked_regs & (0x1 << $reg)) { |
| 181 | $locked_regs ^= (0x1 << $reg); |
| 182 | } |
| 183 | else { |
| 184 | printf("ERROR: reg %d was never locked\n", $reg); |
| 185 | } |
| 186 | } |
| 187 | printf("!release_temp_reg locked regs = 0x%x\n", $locked_regs); |
| 188 | } |
| 189 | sub release_all_regs() { |
| 190 | $locked_regs = 0; |
| 191 | printf("!release all locked regs = 0x%x\n", $locked_regs); |
| 192 | } |
| 193 | |
| 194 | sub pick_tmp_reg() { |
| 195 | my ($ex1, $ex2) = @_; |
| 196 | foreach my $reg (1..31) { |
| 197 | if($reg != $ex1 && $reg != $ex2 && (($locked_regs & (0x1 << $reg)) == 0)) { |
| 198 | $locked_regs |= (0x1 << $reg); |
| 199 | printf("!pick temp locked regs = 0x%x\n", $locked_regs); |
| 200 | return ($reg); |
| 201 | } |
| 202 | } |
| 203 | printf("ERROR: If here, means something went wrong in pick_tmp_reg\n"); |
| 204 | } |
| 205 | |
| 206 | sub possible_tmp_reg() { |
| 207 | my ($ex1, $ex2) = @_; |
| 208 | foreach my $reg (1..31) { |
| 209 | if($reg != $ex1 && $reg != $ex2 && (($locked_regs & (0x1 << $reg)) == 0)) { |
| 210 | printf("!possible temp locked regs = 0x%x\n", $locked_regs); |
| 211 | return ($reg); |
| 212 | } |
| 213 | } |
| 214 | printf("ERROR: If here, means something went wrong in pick_tmp_reg\n"); |
| 215 | } |
| 216 | |
| 217 | sub setx() { |
| 218 | my ($va, $tmp_reg, $dest) = @_; |
| 219 | printf("setx 0x%s, %%r%d, %%r%d\n", bigint2hex($va), $tmp_reg, $dest); |
| 220 | } |
| 221 | |
| 222 | sub setx_label() { |
| 223 | my ($label, $tmp_reg, $dest) = @_; |
| 224 | printf("setx %s, %%r%d, %%r%d\n", $label, $tmp_reg, $dest); |
| 225 | } |
| 226 | |
| 227 | sub mov() { |
| 228 | my ($rs1, $imm, $dest) = @_; |
| 229 | if($imm == $ILLIMM) { |
| 230 | printf("mov %%r%d, %%r%d\n", $rs1, $dest); |
| 231 | } |
| 232 | else { |
| 233 | printf("mov 0x%x, %%r%d\n", $imm, $dest); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | sub or_regs() { |
| 238 | my ($rs1, $rs2, $imm, $dest) = @_; |
| 239 | if($imm == $ILLIMM) { |
| 240 | printf("or %%r%d, %%r%d, %%r%d\n", $rs1, $rs2, $dest); |
| 241 | } |
| 242 | else { |
| 243 | printf("or %%r%d, 0x%x, %%r%d\n", $rs1, $imm, $dest); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | sub and_regs() { |
| 248 | my ($rs1, $rs2, $imm, $dest) = @_; |
| 249 | if($imm == $ILLIMM) { |
| 250 | printf("and %%r%d, %%r%d, %%r%d\n", $rs1, $rs2, $dest); |
| 251 | } |
| 252 | else { |
| 253 | printf("and %%r%d, 0x%x, %%r%d\n", $rs1, $imm, $dest); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | sub add_regs() { |
| 258 | my ($rs1, $rs2, $imm, $dest) = @_; |
| 259 | if($imm == $ILLIMM) { |
| 260 | printf("add %%r%d, %%r%d, %%r%d\n", $rs1, $rs2, $dest); |
| 261 | } |
| 262 | else { |
| 263 | printf("add %%r%d, 0x%x, %%r%d\n", $rs1, $imm, $dest); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | sub load_reg() { |
| 268 | my ($inst, $rs1, $rs2, $imm, $imm_asi, $dest_type, $dest_num) = @_; |
| 269 | if($inst eq "ldub" || $inst eq "ld" || $inst eq "ldd") { |
| 270 | &load($inst, $rs1, $rs2, $imm, $dest_type, $dest_num); |
| 271 | } |
| 272 | if($inst eq "lda" || $inst eq "ldda" || $inst eq "ldxa") { |
| 273 | &load_alt($inst, $rs1, $rs2, $imm, $imm_asi, $dest_type, $dest_num); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | sub load() { |
| 278 | my ($inst, $rs1, $rs2, $imm, $dest_type, $dest_num) = @_; |
| 279 | if($imm == $ILLIMM) { |
| 280 | printf("%s [%%r%d+%%r%d], %s%d\n", $inst, $rs1, $rs2, $dest_type, $dest_num); |
| 281 | } |
| 282 | else { |
| 283 | printf("%s [%%r%d+0x%x], %s%d\n", $inst, $rs1, $imm, $dest_type, $dest_num); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | sub store() { |
| 288 | my ($inst, $src_type, $src_num, $rs1, $rs2, $imm) = @_; |
| 289 | if($imm == $ILLIMM) { |
| 290 | printf("%s %s%d, [%%r%d+%%r%d]\n", $inst, $src_type, $src_num, $rs1, $rs2); |
| 291 | } |
| 292 | else { |
| 293 | printf("%s %s%d, [%%r%d+0x%x]\n", $inst, $src_type, $src_num, $rs1, $imm); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | sub load_alt() { |
| 298 | my ($inst, $rs1, $rs2, $imm, $imm_asi, $dest_type, $dest_num) = @_; |
| 299 | if($imm == $ILLIMM) { |
| 300 | if($imm_asi == $ILLIMM) { |
| 301 | printf("%s [%%r%d+%%r%d] %%asi, %s%d\n", $inst, $rs1, $rs2, $dest_type, $dest_num); |
| 302 | } |
| 303 | else { |
| 304 | printf("%s [%%r%d+%%r%d] 0x%x, %s%d\n", $inst, $rs1, $rs2, $imm_asi, $dest_type, $dest_num); |
| 305 | } |
| 306 | } |
| 307 | else { |
| 308 | if($imm_asi == $ILLIMM) { |
| 309 | printf("%s [%%r%d+0x%x] %%asi, %s%d\n", $inst, $rs1, $imm, $dest_type, $dest_num); |
| 310 | } |
| 311 | else { |
| 312 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 313 | printf("wr %%r0, 0x%x, %%asi\n", $imm_asi); |
| 314 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 315 | printf("%s [%%r%d+0x%x] %%asi, %s%d\n", $inst, $rs1, $imm, $dest_type, $dest_num); |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | sub store_alt() { |
| 321 | my ($inst, $dest_type, $dest_num, $rs1, $rs2, $imm, $imm_asi) = @_; |
| 322 | |
| 323 | if($imm == $ILLIMM) { |
| 324 | if($imm_asi == $ILLIMM) { |
| 325 | printf("%s %s%d, [%%r%d+%%r%d] %%asi\n", $inst, $dest_type, $dest_num, $rs1, $rs2); |
| 326 | } |
| 327 | else { |
| 328 | printf("%s %s%d, [%%r%d+%%r%d] 0x%x\n", $inst, $dest_type, $dest_num, $rs1, $rs2, $imm_asi); |
| 329 | } |
| 330 | } |
| 331 | else { |
| 332 | if($imm_asi == $ILLIMM) { |
| 333 | printf("%s %s%d, [%%r%d+0x%x] %%asi\n", $inst, $dest_type, $dest_num, $rs1, $imm); |
| 334 | } |
| 335 | else { |
| 336 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 337 | printf("wr %%r0, 0x%x, %%asi\n", $imm_asi); |
| 338 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 339 | printf("%s %s%d, [%%r%d+0x%x] %%asi\n", $inst, $dest_type, $dest_num, $rs1, $imm); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | } |
| 344 | |
| 345 | sub cas() { |
| 346 | my ($inst, $rs1, $rs2, $imm, $dest_type, $dest_num) = @_; |
| 347 | if($imm == $ILLIMM) { |
| 348 | printf("%s [%%r%d], %%r%d, %s%d\n", $inst, $rs1, $rs2, $dest_type, $dest_num); |
| 349 | } |
| 350 | else { |
| 351 | my $tmp1 = &pick_tmp_reg(); |
| 352 | &add_regs($rs1, 0, $imm, $tmp1); |
| 353 | printf("%s [%%r%d], %%r%d, %s%d\n", $inst, $tmp1, $rs2, $dest_type, $dest_num); |
| 354 | &release_regs($tmp1); |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | sub cas_alt() { |
| 359 | my ($inst, $rs1, $rs2, $imm, $imm_asi, $dest_type, $dest_num) = @_; |
| 360 | if($imm == $ILLIMM) { |
| 361 | if($imm_asi == $ILLIMM) { |
| 362 | printf("%s [%%r%d] %%asi, %%r%d, %s%d\n", $inst, $rs1, $rs2, $dest_type, $dest_num); |
| 363 | } |
| 364 | else { |
| 365 | printf("%s [%%r%d] 0x%x, %%r%d, %s%d\n", $inst, $rs1, $imm_asi, $rs2, $dest_type, $dest_num); |
| 366 | } |
| 367 | } |
| 368 | else { |
| 369 | my $tmp1 = &pick_tmp_reg(); |
| 370 | &add_regs($rs1, 0, $imm, $tmp1); |
| 371 | if($imm_asi == $ILLIMM) { |
| 372 | printf("%s [%%r%d] %%asi, %%r%d, %s%d\n", $inst, $tmp1, $rs2, $dest_type, $dest_num); |
| 373 | } |
| 374 | else { |
| 375 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 376 | printf("wr %%r0, 0x%x, %%asi\n", $imm_asi); |
| 377 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 378 | printf("%s [%%r%d] %%asi, %%r%d, %s%d\n", $inst, $tmp1, $rs2, $dest_type, $dest_num); |
| 379 | } |
| 380 | &release_regs($tmp1); |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | # va == net va |
| 385 | # imm == required imm in va |
| 386 | sub setup_addr_in_rs1_rs2() { |
| 387 | my ($va, $rs1, $rs2, $imm, $err_ref) = @_; |
| 388 | my ($tmp_reg) = 0; |
| 389 | |
| 390 | $$err_ref = 0; |
| 391 | if($imm != $ILLIMM) { |
| 392 | if($rs1 != 0) { |
| 393 | my ($remainder) = $va; |
| 394 | if($imm & 0x1000) { |
| 395 | $imm |= 0xffffe000; |
| 396 | $imm = ~$imm; $imm += 1; # 2's complement |
| 397 | $remainder = $va + $imm; |
| 398 | } |
| 399 | else { |
| 400 | $remainder = $va - $imm; |
| 401 | } |
| 402 | $tmp_reg = &pick_tmp_reg($rs1); |
| 403 | &lock_regs($rs1); |
| 404 | &setx($remainder, $tmp_reg, $rs1); |
| 405 | &release_regs($tmp_reg); |
| 406 | return $va; |
| 407 | } |
| 408 | else { |
| 409 | return $imm; |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | if($rs1 == 0 && $rs2 == 0) { |
| 414 | # no init needed, load will come from 0x0. |
| 415 | return 0; |
| 416 | } |
| 417 | elsif($rs1 == 0) { |
| 418 | $tmp_reg = &pick_tmp_reg($rs2); |
| 419 | &setx($va, $tmp_reg, $rs2); |
| 420 | &lock_regs($rs2); |
| 421 | &release_regs($tmp_reg); |
| 422 | } |
| 423 | elsif($rs2 == 0) { |
| 424 | $tmp_reg = &pick_tmp_reg($rs1); |
| 425 | &setx($va, $tmp_reg, $rs1); |
| 426 | &lock_regs($rs1); |
| 427 | &release_regs($tmp_reg); |
| 428 | } |
| 429 | else { |
| 430 | $tmp_reg = &pick_tmp_reg($rs1, $rs2); |
| 431 | my ($half_addr) = 0; |
| 432 | if($rs1 == $rs2) { |
| 433 | if($va%2 != 0) { |
| 434 | $$err_ref = 1; # Can't get this addr setup. |
| 435 | return $va; |
| 436 | } |
| 437 | else { |
| 438 | $half_addr = $va/2; |
| 439 | } |
| 440 | } |
| 441 | else { |
| 442 | $half_addr = int($va/2 + $va/4); |
| 443 | } |
| 444 | my ($other_half) = $va - $half_addr; |
| 445 | &setx($half_addr, $tmp_reg, $rs1); |
| 446 | &setx($other_half, $tmp_reg, $rs2); |
| 447 | &lock_regs($rs1); |
| 448 | &lock_regs($rs2) if($rs1 != $rs2); |
| 449 | &release_regs($tmp_reg); |
| 450 | } |
| 451 | return $va; |
| 452 | } |
| 453 | |
| 454 | sub gen_instr_sec() { |
| 455 | |
| 456 | # printf("SECTION .BIG_MAIN TEXT_VA=0x30000000\n"); |
| 457 | printf("SECTION .BIG_MAIN TEXT_VA=0x20000000\n"); |
| 458 | printf("attr_text {\n"); |
| 459 | printf("Name = .BIG_MAIN,\n"); |
| 460 | # printf("VA= 0x30000000,\n"); |
| 461 | printf("VA= 0x20000000,\n"); |
| 462 | # printf("RA= 0x120000000,\n"); |
| 463 | printf("RA= 0x130000000,\n"); |
| 464 | # printf("PA=ra2pa\(0x120000000,0\),\n"); |
| 465 | printf("PA=ra2pa\(0x130000000,0\),\n"); |
| 466 | printf("compressimage,\n"); |
| 467 | # printf("part_0_i_ctx_nonzero_ps0_tsb,\n"); |
| 468 | printf("part_0_ctx_nonzero_tsb_config_1,\n"); |
| 469 | printf("TTE_G=1, TTE_Context=0x44, TTE_V=1, TTE_Size=5, TTE_Size_Ptr=0, TTE_NFO=0,\n"); |
| 470 | printf("TTE_IE=0, TTE_Soft2=0, TTE_Diag=0, TTE_Soft=0,\n"); |
| 471 | printf("TTE_L=0, TTE_CP=1, TTE_CV=0, TTE_E=0, TTE_P=0, TTE_W=1\n"); |
| 472 | printf("}\n"); |
| 473 | if($opt{hyper}) { |
| 474 | printf("attr_text {\n"); |
| 475 | printf("Name = .BIG_MAIN,\n"); |
| 476 | printf("hypervisor\n"); |
| 477 | printf("}\n"); |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | sub gen_data_sec() { |
| 482 | my ($data_va, $last_data_va, $dataacc, $super) = @_; |
| 483 | |
| 484 | printf("SECTION RAND_DATA%s DATA_VA=0x%s\n", bigint2hex($data_va), bigint2hex($data_va)); |
| 485 | printf("attr_data {\n"); |
| 486 | printf(" Name = RAND_DATA%s,\n",bigint2hex($data_va)); |
| 487 | if($opt{hyper} && (($opt{inst_group} ne "asi") || |
| 488 | (($opt{inst} ne "0x10") && ($opt{inst} ne "0x11") && |
| 489 | ($opt{inst} ne "0x14") && ($opt{inst} ne "0x15") && |
| 490 | ($opt{inst} ne "0x16") && ($opt{inst} ne "0x17") && |
| 491 | ($opt{inst} ne "0x1c") && ($opt{inst} ne "0x1d") && |
| 492 | ($opt{inst} ne "0x1e") && ($opt{inst} ne "0x1f") && |
| 493 | ($opt{inst} ne "0x22") && ($opt{inst} ne "0x23") && |
| 494 | ($opt{inst} ne "0x26") && ($opt{inst} ne "0x2e") && |
| 495 | ($opt{inst} ne "0x2a") && ($opt{inst} ne "0x2b") && |
| 496 | ($opt{inst} ne "0x18") && ($opt{inst} ne "0x19")))) { |
| 497 | printf("hypervisor\n"); |
| 498 | } |
| 499 | else { |
| 500 | printf(" RA=0x%s,\n",bigint2hex($data_va)); |
| 501 | if($dataacc) { |
| 502 | printf(" tsbonly,\n"); |
| 503 | } |
| 504 | else { |
| 505 | if(($data_va >> 39) & 0x1) { #if bit39 on va is set, make it equal to PA |
| 506 | printf(" PA=0x%s,\n", bigint2hex($data_va)); |
| 507 | } |
| 508 | else { |
| 509 | printf(" PA=ra2pa\(0x%s,0\),\n", bigint2hex($data_va)); |
| 510 | } |
| 511 | } |
| 512 | # printf(" part_0_d_ctx_nonzero_ps0_tsb, \n"); |
| 513 | printf(" part_0_ctx_nonzero_tsb_config_0, \n"); |
| 514 | if((($opt{inst_group} eq "asi") && (($opt{inst} eq "0x4") || ($opt{inst} eq "0xc") || |
| 515 | ($opt{inst} eq "0x24") || ($opt{inst} eq "0x26") || |
| 516 | ($opt{inst} eq "0x2c") || ($opt{inst} eq "0x2e") || |
| 517 | ($opt{inst} eq "0x27") || ($opt{inst} eq "0x2f"))) || |
| 518 | (($opt{inst_group} eq "ldst") && ($opt{inst} eq "tl1"))) { |
| 519 | # printf(" part_0_d_ctx_zero_ps0_tsb, \n"); |
| 520 | printf(" part_0_ctx_zero_tsb_config_0, \n"); |
| 521 | } |
| 522 | if(($opt{inst_group} eq "asi") && (($opt{inst} eq "0x11") || ($opt{inst} eq "0x19") || |
| 523 | ($opt{inst} eq "0x81") || ($opt{inst} eq "0x83") || |
| 524 | ($opt{inst} eq "0x89") || ($opt{inst} eq "0x8b") || |
| 525 | ($opt{inst} eq "0x17") || ($opt{inst} eq "0x1f") || |
| 526 | ($opt{inst} eq "0x23") || ($opt{inst} eq "0x2b") || |
| 527 | ($opt{inst} eq "0xe3") || ($opt{inst} eq "0xeb") || |
| 528 | ($opt{inst} eq "0xf1") || ($opt{inst} eq "0xf9"))) { |
| 529 | printf("TTE_Context=SCONTEXT\n"); |
| 530 | } |
| 531 | else { |
| 532 | printf("TTE_Context=PCONTEXT\n"); |
| 533 | } |
| 534 | printf(" TTE_G=1, TTE_Size=0x0, \n"); |
| 535 | if(($opt{inst_group} eq "asi") && (($opt{inst} eq "0x82") || ($opt{inst} eq "0x83") || |
| 536 | ($opt{inst} eq "0x8a") || ($opt{inst} eq "0x8b"))) { |
| 537 | printf("TTE_NFO=1,\n"); |
| 538 | } |
| 539 | else { |
| 540 | printf("TTE_NFO=0,\n"); |
| 541 | } |
| 542 | printf(" TTE_IE=0, TTE_Soft2=0, TTE_Diag=0, TTE_Soft=0,\n"); |
| 543 | printf(" TTE_L=0, TTE_CP=1, TTE_CV=0, TTE_E=0, "); |
| 544 | if(($dataacc && $opt{inst_group} ne "asi") || $opt{super}) { |
| 545 | if(($opt{inst_group} eq "asi") && ($opt{inst} eq "0x10" || $opt{inst} eq "0x11" || |
| 546 | $opt{inst} eq "0x18" || $opt{inst} eq "0x19" || |
| 547 | $opt{inst} eq "0x22" || $opt{inst} eq "0x23" || |
| 548 | $opt{inst} eq "0x2a" || $opt{inst} eq "0x2b" || |
| 549 | $opt{inst} eq "0x80" || $opt{inst} eq "0x81" || |
| 550 | $opt{inst} eq "0x82" || $opt{inst} eq "0x83" || |
| 551 | $opt{inst} eq "0x88" || $opt{inst} eq "0x89" || |
| 552 | $opt{inst} eq "0x8a" || $opt{inst} eq "0x8b")) { |
| 553 | printf("TTE_P=0, TTE_W=1, TTE_V=1\n"); |
| 554 | } |
| 555 | else { |
| 556 | printf("TTE_P=1, TTE_W=1, TTE_V=1\n"); |
| 557 | } |
| 558 | } |
| 559 | else { |
| 560 | printf("TTE_P=0, TTE_W=1, TTE_V=1\n"); |
| 561 | } |
| 562 | } |
| 563 | printf(" }\n"); |
| 564 | printf(".data\n"); |
| 565 | printf(".global data_sec%s\n",bigint2hex($data_va)); |
| 566 | printf("normal_addr_range_data%s:\n",bigint2hex($data_va)); |
| 567 | if($dataacc == 0) { |
| 568 | for (my $i=0; $i<($last_data_va-$data_va)/4; $i++) { |
| 569 | printf(".word 0x%x\n", int(rand(0xffffffff))); |
| 570 | } |
| 571 | } |
| 572 | else { |
| 573 | printf(".skip %d\n", ($last_data_va-$data_va)); |
| 574 | printf(".byte 0x%x\n", int(rand(0xff))); |
| 575 | } |
| 576 | |
| 577 | printf(".end\n"); |
| 578 | } |
| 579 | |
| 580 | |
| 581 | sub gen_high_data_sec() { |
| 582 | my ($dataacc, $super) = @_; |
| 583 | |
| 584 | # printf("SECTION RAND_DATAffffffffffffe000 DATA_VA=0xffffffffffffe000\n"); |
| 585 | printf("SECTION RAND_DATAffffffffff838000 DATA_VA=0xffffffffff838000\n"); |
| 586 | printf("attr_data {\n"); |
| 587 | # printf(" Name = RAND_DATAffffffffffffe000,\n"); |
| 588 | printf(" Name = RAND_DATAffffffffff838000,\n"); |
| 589 | if($opt{hyper}) { |
| 590 | printf("hypervisor\n"); |
| 591 | } |
| 592 | else { |
| 593 | # printf(" RA=0x20010000,\n"); |
| 594 | printf(" RA=0x17f000000,\n"); |
| 595 | if($dataacc) { |
| 596 | printf(" tsbonly,\n"); |
| 597 | } |
| 598 | else { |
| 599 | # printf(" PA=ra2pa\(0x20010000,0\),\n"); |
| 600 | printf(" PA=ra2pa\(0x17f000000,0\),\n"); |
| 601 | } |
| 602 | if($super) { |
| 603 | # printf(" part_0_d_ctx_nonzero_ps0_tsb, TTE_Context=PCONTEXT\n"); |
| 604 | printf(" part_0_ctx_nonzero_tsb_config_2, TTE_Context=PCONTEXT\n"); |
| 605 | } |
| 606 | else { |
| 607 | # printf(" part_0_d_ctx_nonzero_ps0_tsb, TTE_Context=PCONTEXT\n"); |
| 608 | printf(" part_0_ctx_nonzero_tsb_config_2, TTE_Context=PCONTEXT\n"); |
| 609 | } |
| 610 | printf(" TTE_G=1, TTE_Size=0x0, TTE_NFO=0,\n"); |
| 611 | printf(" TTE_IE=0, TTE_Soft2=0, TTE_Diag=0, TTE_Soft=0,\n"); |
| 612 | printf(" TTE_L=0, TTE_CP=1, TTE_CV=0, TTE_E=0, "); |
| 613 | if($dataacc) { |
| 614 | if($opt{super}) { |
| 615 | printf("TTE_P=0, TTE_W=1, TTE_V=0\n"); |
| 616 | } |
| 617 | else { |
| 618 | printf("TTE_P=1, TTE_W=1, TTE_V=1\n"); |
| 619 | } |
| 620 | } |
| 621 | else { |
| 622 | printf("TTE_P=0, TTE_W=1, TTE_V=1\n"); |
| 623 | } |
| 624 | } |
| 625 | printf(" }\n"); |
| 626 | printf(".data\n"); |
| 627 | # printf(".global data_secffffffffffffe000\n"); |
| 628 | printf(".global data_secffffffffff838000\n"); |
| 629 | # printf("normal_addr_range_dataffffffffffffe000:\n"); |
| 630 | printf("normal_addr_range_dataffffffffff838000:\n"); |
| 631 | if($dataacc == 0) { |
| 632 | for (my $i=0; $i<8188/4; $i++) { |
| 633 | printf(".word 0x%x\n", int(rand(0xffffffff))); |
| 634 | } |
| 635 | } |
| 636 | else { |
| 637 | printf(".skip 8180\n"); |
| 638 | printf(".byte 0x%x\n", int(rand(0xff))); |
| 639 | } |
| 640 | |
| 641 | printf(".end\n"); |
| 642 | } |
| 643 | |
| 644 | sub gen_scratch_mem_area() { |
| 645 | # printf("SECTION SCRATCH_MEM DATA_VA=0x1ffffe000\n"); |
| 646 | printf("SECTION SCRATCH_MEM DATA_VA=0x17fff0000\n"); |
| 647 | # printf("attr_data {\n"); |
| 648 | # printf(" Name = SCRATCH_MEM,\n"); |
| 649 | # printf(" hypervisor\n"); |
| 650 | # printf(" }\n"); |
| 651 | printf("attr_data {\n"); |
| 652 | printf(" Name = SCRATCH_MEM,\n"); |
| 653 | # printf(" RA=0x1ffffe000,\n"); |
| 654 | printf(" RA=0x17fff0000,\n"); |
| 655 | # printf(" PA=ra2pa\(0x1ffffe000,0\),\n"); |
| 656 | printf(" PA=ra2pa\(0x17fff0000,0\),\n"); |
| 657 | # printf(" part_0_d_ctx_nonzero_ps0_tsb, \n"); |
| 658 | printf(" part_0_ctx_nonzero_tsb_config_1, \n"); |
| 659 | # printf(" part_0_d_ctx_zero_ps0_tsb, \n"); |
| 660 | printf(" part_0_ctx_zero_tsb_config_1, \n"); |
| 661 | printf(" TTE_Context=PCONTEXT\n"); |
| 662 | printf(" TTE_G=1, TTE_Size=0x0, TTE_NFO=0,\n"); |
| 663 | printf(" TTE_IE=0, TTE_Soft2=0, TTE_Diag=0, TTE_Soft=0,\n"); |
| 664 | printf(" TTE_L=0, TTE_CP=1, TTE_CV=0, TTE_E=0, "); |
| 665 | printf(" TTE_P=0, TTE_W=1, TTE_V=1\n"); |
| 666 | printf(" }\n"); |
| 667 | printf(".data\n"); |
| 668 | printf(".global scratch_mem\n"); |
| 669 | printf("scratch_mem:\n"); |
| 670 | for (my $i=0; $i<1024/4; $i++) { |
| 671 | printf(".word 0x%x\n", int(rand(0xffffffff))); |
| 672 | } |
| 673 | } |
| 674 | |
| 675 | sub setup_va_watchpoint() { |
| 676 | my ($addr, $rd_en, $wr_en) = @_; |
| 677 | |
| 678 | if(($opt{enboff} == 0) && ($opt{hyper} == 0)) { |
| 679 | printf("ta T_CHANGE_HPRIV\n") |
| 680 | } |
| 681 | elsif ($opt{enboff} && ($opt{super} == 0)) { |
| 682 | printf("ta T_CHANGE_PRIV\n") |
| 683 | } |
| 684 | else { |
| 685 | # hyper mode, or enboff.super mode requires nothing. |
| 686 | } |
| 687 | my $tmp_reg_lsu_ctl = &pick_tmp_reg(); |
| 688 | &load_alt("ldxa", 0, 0, $ILLIMM, 0x45, "%r", $tmp_reg_lsu_ctl); |
| 689 | my $tmp1 = &pick_tmp_reg(); |
| 690 | my $tmp2 = &pick_tmp_reg(); |
| 691 | my $tmp_rst_mask = hex2bigint("0x000fffff"); |
| 692 | &setx($tmp_rst_mask, $tmp1, $tmp2); |
| 693 | &and_regs($tmp2, $tmp_reg_lsu_ctl, $ILLIMM, $tmp_reg_lsu_ctl); |
| 694 | |
| 695 | my $ctl_reg_mask = hex2bigint("0x7fe000000"); |
| 696 | $ctl_reg_mask |= ($wr_en << 23); |
| 697 | $ctl_reg_mask |= ($rd_en << 24); |
| 698 | &setx($ctl_reg_mask, $tmp1, $tmp2); |
| 699 | &or_regs($tmp_reg_lsu_ctl, $tmp2, $ILLIMM, $tmp_reg_lsu_ctl); |
| 700 | &store_alt("stxa", "%r", $tmp_reg_lsu_ctl, 0, 0, $ILLIMM, 0x45); |
| 701 | |
| 702 | #now setup addr |
| 703 | if($rd_en || $wr_en) { # only then address matters |
| 704 | my $big_addr = Math::BigInt->new($addr); |
| 705 | if(($big_addr & 0xfffff000) == 0x1000) { |
| 706 | my $big_tmp = Math::BigInt->new(0xffffffff); |
| 707 | $big_tmp <<= 32; |
| 708 | $big_addr = $big_tmp | 0xffffe000 | $big_addr; |
| 709 | } |
| 710 | &setx($big_addr, $tmp1, $tmp2); |
| 711 | &mov(0, 0x38, $tmp1); |
| 712 | &store_alt("stxa", "%r", $tmp2, $tmp1, 0, $ILLIMM, 0x58); |
| 713 | } |
| 714 | if(($opt{hyper} == 0) && ($opt{enboff} == 0)) { |
| 715 | printf("ta T_CHANGE_NONHPRIV\n") |
| 716 | } |
| 717 | elsif ($opt{enboff} && ($opt{super} == 0)) { |
| 718 | printf("ta T_CHANGE_NONPRIV\n") |
| 719 | } |
| 720 | else { |
| 721 | # hyper mode, or enboff.super mode requires nothing. |
| 722 | } |
| 723 | &release_regs($tmp_reg_lsu_ctl, $tmp1, $tmp2); |
| 724 | } |
| 725 | |
| 726 | sub setup_tte_entry() { |
| 727 | my ($addr) = @_; |
| 728 | |
| 729 | printf("!func: setup_tte_entry : 0x%x\n", $addr); |
| 730 | |
| 731 | my $err = 0; |
| 732 | my $tmp1 = &pick_tmp_reg(); |
| 733 | my $tmp2 = &pick_tmp_reg(); |
| 734 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 735 | &setx($addr, $tmp1, $tmp2); |
| 736 | &load("ldub", $tmp2, 0, $ILLIMM, "%r", 0); |
| 737 | &release_regs($tmp1, $tmp2); |
| 738 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 739 | } |
| 740 | |
| 741 | sub gen_all_ldf() { |
| 742 | my ($ldf_inst, $next_addr_ref, $next_0addr_ref, $all_dest, $misalgn_offset, $vawatch, $preloadtlb) = @_; |
| 743 | |
| 744 | my $factor = 1; |
| 745 | $factor = 2 if($ldf_inst eq "ldd" || $ldf_inst eq "ldda"); |
| 746 | |
| 747 | my @fdest = (); |
| 748 | if($all_dest) { |
| 749 | @fdest = (0..31); |
| 750 | } |
| 751 | else { |
| 752 | @fdest = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x1f); |
| 753 | } |
| 754 | |
| 755 | my ($ldf_dest, $rs1, $rs2, $err); |
| 756 | foreach $ldf_dest (@fdest) { #pick dest freg |
| 757 | my $dest = $ldf_dest*$factor; |
| 758 | foreach $rs1 (@walking1_iregs) { #mem addr combination rs1 |
| 759 | my @rep_rs2 = (0, $rs1, 31); |
| 760 | foreach $rs2 (@rep_rs2) { #mem addr combination rs2 |
| 761 | my ($imm) = $ILLIMM; |
| 762 | my $setup_va = &setup_addr_in_rs1_rs2($$next_addr_ref+$misalgn_offset, $rs1, $rs2, $imm, \$err); |
| 763 | if($err == 0) { |
| 764 | if($setup_va == ($$next_addr_ref+$misalgn_offset)) { |
| 765 | $$next_addr_ref += (4*$factor); |
| 766 | } |
| 767 | else { |
| 768 | push(@$next_0addr_ref, $setup_va); |
| 769 | } |
| 770 | if($misalgn_offset == 0 || $setup_va != 0) { |
| 771 | &setup_tte_entry($setup_va) if($preloadtlb); |
| 772 | &setup_va_watchpoint($setup_va, 1, 0) if($vawatch); |
| 773 | &load_reg($ldf_inst, $rs1, $rs2, $imm, 0x88, "%f", $dest); |
| 774 | &setup_va_watchpoint($setup_va, 0, 0) if($vawatch); |
| 775 | printf("\n"); |
| 776 | } |
| 777 | } |
| 778 | &release_all_regs(); |
| 779 | } |
| 780 | |
| 781 | my @rep_imm13 = (0, 0x800, 0x1000, 0x1fc0); |
| 782 | foreach my $imm (@rep_imm13) { #mem addr combination imm |
| 783 | my $setup_va = &setup_addr_in_rs1_rs2($$next_addr_ref+$misalgn_offset, $rs1, $rs2, $imm+$misalgn_offset, \$err); |
| 784 | if($err == 0) { |
| 785 | if($setup_va == ($$next_addr_ref+$misalgn_offset)) { |
| 786 | $$next_addr_ref += (4*$factor); |
| 787 | } |
| 788 | else { |
| 789 | push(@$next_0addr_ref, $setup_va); |
| 790 | } |
| 791 | if($misalgn_offset == 0 || $setup_va != 0) { |
| 792 | &setup_tte_entry($setup_va) if($preloadtlb); |
| 793 | &setup_va_watchpoint($setup_va, 1, 0) if($vawatch); |
| 794 | &load_reg($ldf_inst, $rs1, $rs2, $imm+$misalgn_offset, 0x88, "%f", $dest); |
| 795 | &setup_va_watchpoint($setup_va, 0, 0) if($vawatch); |
| 796 | printf("\n"); |
| 797 | } |
| 798 | } |
| 799 | &release_all_regs(); |
| 800 | } |
| 801 | } |
| 802 | |
| 803 | foreach $rs2 (@walking1_iregs) { #mem addr combination rs1 |
| 804 | my @rep_rs1 = (0, $rs2, 31); |
| 805 | foreach $rs1 (@rep_rs1) { #mem addr combination rs2 |
| 806 | my ($imm) = $ILLIMM; |
| 807 | my $setup_va = &setup_addr_in_rs1_rs2($$next_addr_ref+$misalgn_offset, $rs1, $rs2, $imm, \$err); |
| 808 | if($err == 0) { |
| 809 | if($setup_va == ($$next_addr_ref+$misalgn_offset)) { |
| 810 | $$next_addr_ref += (4*$factor); |
| 811 | } |
| 812 | else { |
| 813 | push(@$next_0addr_ref, $setup_va); |
| 814 | } |
| 815 | if($misalgn_offset == 0 || $setup_va != 0) { |
| 816 | &setup_tte_entry($setup_va) if($preloadtlb); |
| 817 | &setup_va_watchpoint($setup_va, 1, 0) if($vawatch); |
| 818 | &load_reg($ldf_inst, $rs1, $rs2, $imm, 0x88, "%f", $dest); |
| 819 | &setup_va_watchpoint($setup_va, 0, 0) if($vawatch); |
| 820 | printf("\n"); |
| 821 | } |
| 822 | } |
| 823 | &release_all_regs(); |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | foreach my $imm (@walking1_imm13) { #mem addr combination rs1 |
| 828 | my @rep_rs1 = (0, 31); |
| 829 | foreach $rs1 (@rep_rs1) { #mem addr combination rs2 |
| 830 | if($rs1 == 0 && ($imm & 0x3f)) { |
| 831 | #skip |
| 832 | } |
| 833 | else { |
| 834 | my $setup_va = &setup_addr_in_rs1_rs2($$next_addr_ref+$misalgn_offset, $rs1, $rs2, $imm+$misalgn_offset, \$err); |
| 835 | if($err == 0) { |
| 836 | if($setup_va == ($$next_addr_ref+$misalgn_offset)) { |
| 837 | $$next_addr_ref += (4*$factor); |
| 838 | } |
| 839 | else { |
| 840 | push(@$next_0addr_ref, $setup_va); |
| 841 | } |
| 842 | if($misalgn_offset == 0 || $setup_va != 0) { |
| 843 | &setup_tte_entry($setup_va) if($preloadtlb); |
| 844 | &setup_va_watchpoint($setup_va, 1, 0) if($vawatch); |
| 845 | &load_reg($ldf_inst, $rs1, $rs2, $imm+$misalgn_offset, 0x88, "%f", $dest); |
| 846 | &setup_va_watchpoint($setup_va, 0, 0) if($vawatch); |
| 847 | printf("\n"); |
| 848 | } |
| 849 | } |
| 850 | &release_all_regs(); |
| 851 | } |
| 852 | } |
| 853 | } |
| 854 | } |
| 855 | } |
| 856 | |
| 857 | |
| 858 | sub gen_all_fbfcc() { |
| 859 | my ($th_id, $inst, $inst_group) = @_; |
| 860 | foreach my $taken (0..1) { |
| 861 | foreach my $cc_combo (0..3) { |
| 862 | my $setup_ok = &setup_fcc_for_fbpfcc($inst, $inst_group, $taken, 0, $cc_combo, $th_id); |
| 863 | if($setup_ok) { |
| 864 | foreach my $annul (0..1) { |
| 865 | foreach my $target (@imm22_targets) { |
| 866 | &gen_fbpfcc($inst, $inst_group, $annul, 0, 0, $cc_combo, $target, $taken, $th_id); |
| 867 | } |
| 868 | } |
| 869 | } |
| 870 | } |
| 871 | } |
| 872 | } |
| 873 | |
| 874 | sub gen_all_fbpfcc() { |
| 875 | my ($th_id, $inst, $inst_group) = @_; |
| 876 | foreach my $taken (0..1) { |
| 877 | foreach my $which_fcc (0..3) { |
| 878 | foreach my $cc_combo (0..3) { |
| 879 | my $setup_ok = &setup_fcc_for_fbpfcc($inst, $inst_group, $taken, $which_fcc, $cc_combo, $th_id); |
| 880 | if($setup_ok) { |
| 881 | foreach my $ptn (0..1) { |
| 882 | foreach my $annul (0..1) { |
| 883 | foreach my $target (@imm19_targets) { |
| 884 | &gen_fbpfcc($inst, $inst_group, $annul, $ptn, $which_fcc, $cc_combo, $target, $taken, $th_id); |
| 885 | } |
| 886 | } |
| 887 | } |
| 888 | } |
| 889 | } |
| 890 | } |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | sub gen_fbpfcc() { |
| 895 | my ($inst, $inst_group, $annul, $ptn, $which_fcc, $cc_combo, $target, $taken, $th_id) = @_; |
| 896 | |
| 897 | return if(($taken == 0) && ($opt{fpdis} == 0) && ($inst eq "fba")); |
| 898 | return if(($taken == 1) && ($opt{fpdis} == 0) && ($inst eq "fbn")); |
| 899 | |
| 900 | my $target_limit = 0x200000; |
| 901 | $target_limit = 0x40000 if($inst_group eq "fbpfcc"); |
| 902 | |
| 903 | if($taken && ($opt{fpdis} == 0) && $target == 0) { |
| 904 | #taken branch on self will be inf-loop |
| 905 | } |
| 906 | else { |
| 907 | if($target & $target_limit) { |
| 908 | printf("setx th%d_nxt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x, %%g2, %%g3\n", $th_id, $inst, $which_fcc, $cc_combo, |
| 909 | $ptn, $annul, $taken, $target); |
| 910 | printf("th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 911 | printf("jmp %%g3\n"); |
| 912 | printf("nop\n"); |
| 913 | } |
| 914 | |
| 915 | printf("th%d_nxt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 916 | printf("th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target) if($target == 0); |
| 917 | if($target & $target_limit) { |
| 918 | printf("add %%g3, 0xc, %%g3\n"); |
| 919 | } |
| 920 | printf("%s", $inst); |
| 921 | printf(",a") if($annul); |
| 922 | printf(",pt") if($ptn == 1 && ($inst_group eq "fbpfcc")); |
| 923 | printf(",pn") if($ptn == 0 && ($inst_group eq "fbpfcc")); |
| 924 | printf(" %%fcc%d, ", $which_fcc) if($inst_group eq "fbpfcc"); |
| 925 | printf(" th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 926 | if($target == 1) { |
| 927 | printf("th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 928 | printf("nop ! delay slot & branch target\n"); |
| 929 | printf("\n"); |
| 930 | } |
| 931 | else { |
| 932 | if(($inst eq "fba" || $inst eq "fbn") && $annul && ($opt{fpdis} == 0)) { |
| 933 | #eat annuled instr(make it illegal) |
| 934 | printf(".word 0x0\n"); |
| 935 | } |
| 936 | elsif(($taken == 0) && $annul && ($opt{fpdis} == 0)) { |
| 937 | #eat annuled instr(make it illegal) |
| 938 | printf(".word 0x0\n"); |
| 939 | } |
| 940 | else { |
| 941 | printf("nop ! delay slot\n"); |
| 942 | } |
| 943 | if(($target != 0) && (($target & $target_limit) == 0)) { |
| 944 | if(($target > 2) && (($taken == 0) || $opt{fpdis})) { |
| 945 | printf("call th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 946 | printf("nop\n"); |
| 947 | printf(".skip %d\n", ($target-4)*4) if($target > 4); |
| 948 | } |
| 949 | else { |
| 950 | printf(".skip %d\n", ($target-2)*4) if($target > 2); |
| 951 | } |
| 952 | printf("th%d_tgt_%s_fcc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_fcc, $cc_combo, $ptn, $annul, $taken, $target); |
| 953 | printf("nop ! branch target\n"); |
| 954 | } |
| 955 | printf("\n"); |
| 956 | } |
| 957 | } |
| 958 | } |
| 959 | |
| 960 | sub setup_fcc_for_fbpfcc() { |
| 961 | my ($inst, $inst_group, $taken, $which_fcc, $cc_combo, $th_id) = @_; |
| 962 | |
| 963 | my $ext_on = 0; |
| 964 | $ext_on = 1 if($inst_group eq "fbpfcc"); |
| 965 | |
| 966 | my $value = $cc_combo; |
| 967 | my $cc_E = 0; |
| 968 | my $cc_L = 1; |
| 969 | my $cc_G = 2; |
| 970 | my $cc_U = 3; |
| 971 | |
| 972 | if($inst eq "fba" || $inst eq "fbn") { |
| 973 | # all cc-combos are ok |
| 974 | } |
| 975 | elsif($inst eq "fbu") { |
| 976 | return 0 if(($taken == 1) && ($value != $cc_U)); |
| 977 | return 0 if(($taken == 0) && ($value == $cc_U)); |
| 978 | } |
| 979 | elsif($inst eq "fbg") { |
| 980 | return 0 if(($taken == 1) && ($value != $cc_G)); |
| 981 | return 0 if(($taken == 0) && ($value == $cc_G)); |
| 982 | } |
| 983 | elsif($inst eq "fbug") { |
| 984 | return 0 if(($taken == 1) && (($value != $cc_U) && ($value != $cc_G))); |
| 985 | return 0 if(($taken == 0) && (($value == $cc_U) || ($value == $cc_G))); |
| 986 | } |
| 987 | elsif($inst eq "fbl") { |
| 988 | return 0 if(($taken == 1) && ($value != $cc_L)); |
| 989 | return 0 if(($taken == 0) && ($value == $cc_L)); |
| 990 | } |
| 991 | elsif($inst eq "fbul") { |
| 992 | return 0 if(($taken == 1) && (($value != $cc_L) && ($value != $cc_U))); |
| 993 | return 0 if(($taken == 0) && (($value == $cc_L) || ($value == $cc_U))); |
| 994 | } |
| 995 | elsif($inst eq "fblg") { |
| 996 | return 0 if(($taken == 1) && (($value != $cc_L) && ($value != $cc_G))); |
| 997 | return 0 if(($taken == 0) && (($value == $cc_L) || ($value == $cc_G))); |
| 998 | } |
| 999 | elsif($inst eq "fbne") { |
| 1000 | return 0 if(($taken == 1) && (($value != $cc_L) && ($value != $cc_G) && ($value != $cc_U))); |
| 1001 | return 0 if(($taken == 0) && (($value == $cc_L) || ($value == $cc_G) || ($value == $cc_U))); |
| 1002 | } |
| 1003 | elsif($inst eq "fbe") { |
| 1004 | return 0 if(($taken == 1) && ($value != $cc_E)); |
| 1005 | return 0 if(($taken == 0) && ($value == $cc_E)); |
| 1006 | } |
| 1007 | elsif($inst eq "fbue") { |
| 1008 | return 0 if(($taken == 1) && (($value != $cc_U) && ($value != $cc_E))); |
| 1009 | return 0 if(($taken == 0) && (($value == $cc_U) || ($value == $cc_E))); |
| 1010 | } |
| 1011 | elsif($inst eq "fbge") { |
| 1012 | return 0 if(($taken == 1) && (($value != $cc_G) && ($value != $cc_E))); |
| 1013 | return 0 if(($taken == 0) && (($value == $cc_G) || ($value == $cc_E))); |
| 1014 | } |
| 1015 | elsif($inst eq "fbuge") { |
| 1016 | return 0 if(($taken == 1) && (($value != $cc_U) && ($value != $cc_G) && ($value != $cc_E))); |
| 1017 | return 0 if(($taken == 0) && (($value == $cc_U) || ($value == $cc_G) || ($value == $cc_E))); |
| 1018 | } |
| 1019 | elsif($inst eq "fble") { |
| 1020 | return 0 if(($taken == 1) && (($value != $cc_E) && ($value != $cc_L))); |
| 1021 | return 0 if(($taken == 0) && (($value == $cc_E) || ($value == $cc_L))); |
| 1022 | } |
| 1023 | elsif($inst eq "fbule") { |
| 1024 | return 0 if(($taken == 1) && (($value != $cc_E) && ($value != $cc_L) && ($value != $cc_U))); |
| 1025 | return 0 if(($taken == 0) && (($value == $cc_E) || ($value == $cc_L) || ($value == $cc_U))); |
| 1026 | } |
| 1027 | elsif($inst eq "fbo") { |
| 1028 | return 0 if(($taken == 1) && (($value != $cc_E) && ($value != $cc_L) && ($value != $cc_G))); |
| 1029 | return 0 if(($taken == 0) && (($value == $cc_E) || ($value == $cc_L) || ($value == $cc_G))); |
| 1030 | } |
| 1031 | else { |
| 1032 | printf("ERROR: bad instruction type\n"); |
| 1033 | return 0; |
| 1034 | } |
| 1035 | my $others = (~$value) & 0x3; |
| 1036 | |
| 1037 | if($which_fcc == 0) { |
| 1038 | &setup_xfsr_fcc($ext_on, $others, $others, $others, $value, $th_id); |
| 1039 | } |
| 1040 | if($which_fcc == 1) { |
| 1041 | &setup_xfsr_fcc($ext_on, $others, $others, $value, $others, $th_id); |
| 1042 | } |
| 1043 | if($which_fcc == 2) { |
| 1044 | &setup_xfsr_fcc($ext_on, $others, $value, $others, $others, $th_id); |
| 1045 | } |
| 1046 | if($which_fcc == 3) { |
| 1047 | &setup_xfsr_fcc($ext_on, $value, $others, $others, $others, $th_id); |
| 1048 | } |
| 1049 | return 1; |
| 1050 | } |
| 1051 | |
| 1052 | sub setup_xfsr_fcc() { |
| 1053 | my ($ext_on, $fcc3, $fcc2, $fcc1, $fcc0, $th_id) = @_; |
| 1054 | |
| 1055 | my $big_value = Math::BigInt->new(($fcc3<<4) | ($fcc2<<2) | ($fcc1)); |
| 1056 | $big_value <<=32 ; |
| 1057 | $big_value |= ($fcc0<<10); |
| 1058 | |
| 1059 | if($ext_on) { |
| 1060 | printf("stx %%fsr, [%%g0+%d]\n", $th_id*8); |
| 1061 | } |
| 1062 | else { |
| 1063 | printf("st %%fsr, [%%g0+%d]\n", $th_id*4); |
| 1064 | } |
| 1065 | my $tmp_fsr = &pick_tmp_reg(); |
| 1066 | if($ext_on) { |
| 1067 | printf("ldx [%%g0+%d], %%r%d\n", $th_id*8, $tmp_fsr); |
| 1068 | } |
| 1069 | else { |
| 1070 | printf("ld [%%g0+%d], %%r%d\n", $th_id*4, $tmp_fsr); |
| 1071 | } |
| 1072 | my $tmp1 = &pick_tmp_reg(); |
| 1073 | my $tmp2 = &pick_tmp_reg(); |
| 1074 | &setx(0xfffff3ff, $tmp1, $tmp2); |
| 1075 | &and_regs($tmp_fsr, $tmp2, $ILLIMM, $tmp_fsr); |
| 1076 | &setx($big_value, $tmp1, $tmp2); |
| 1077 | &or_regs($tmp_fsr, $tmp2, $ILLIMM, $tmp_fsr); |
| 1078 | if($ext_on) { |
| 1079 | printf("stx %%r%d, [%%g0+%d]\n", $tmp_fsr, $th_id*8); |
| 1080 | printf("ldx [%%g0+%d], %%fsr\n", $th_id*8); |
| 1081 | } |
| 1082 | else { |
| 1083 | printf("st %%r%d, [%%g0+%d]\n", $tmp_fsr, $th_id*4); |
| 1084 | printf("ld [%%g0+%d], %%fsr\n", $th_id*4); |
| 1085 | } |
| 1086 | &release_regs($tmp_fsr, $tmp1, $tmp2); |
| 1087 | } |
| 1088 | |
| 1089 | |
| 1090 | |
| 1091 | sub gen_all_bicc() { |
| 1092 | my ($th_id, $inst, $inst_group) = @_; |
| 1093 | foreach my $taken (0..1) { |
| 1094 | my @cc_combo_range = (0..15); |
| 1095 | foreach my $cc_combo (@cc_combo_range) { |
| 1096 | my $setup_ok = &setup_cc_for_bpcc($inst, $inst_group, $taken, 0, $cc_combo, $th_id); |
| 1097 | if($setup_ok) { |
| 1098 | foreach my $annul (0..1) { |
| 1099 | foreach my $target (@imm22_targets) { |
| 1100 | &gen_bpcc($inst, $inst_group, $annul, 0, 0, $cc_combo, $target, $taken, $th_id); |
| 1101 | } |
| 1102 | } |
| 1103 | } |
| 1104 | } |
| 1105 | } |
| 1106 | } |
| 1107 | |
| 1108 | sub gen_all_bpcc() { |
| 1109 | my ($th_id, $inst, $inst_group) = @_; |
| 1110 | |
| 1111 | foreach my $taken (0..1) { |
| 1112 | my @cc = (0,2); |
| 1113 | @cc = (1,3) if($opt{illinst}); |
| 1114 | foreach my $which_cc (@cc) { |
| 1115 | my @cc_combo_range = (0..15); |
| 1116 | foreach my $cc_combo (@cc_combo_range) { |
| 1117 | my $setup_ok = &setup_cc_for_bpcc($inst, $inst_group, $taken, $which_cc, $cc_combo, $th_id); |
| 1118 | if($setup_ok) { |
| 1119 | foreach my $ptn (0..1) { |
| 1120 | foreach my $annul (0..1) { |
| 1121 | foreach my $target (@imm19_targets) { |
| 1122 | &gen_bpcc($inst, $inst_group, $annul, $ptn, $which_cc, $cc_combo, $target, $taken, $th_id); |
| 1123 | } |
| 1124 | } |
| 1125 | } |
| 1126 | } |
| 1127 | } |
| 1128 | } |
| 1129 | } |
| 1130 | } |
| 1131 | |
| 1132 | sub gen_bpcc() { |
| 1133 | my ($inst, $inst_group, $annul, $ptn, $which_cc, $cc_combo, $target, $taken, $th_id) = @_; |
| 1134 | |
| 1135 | my %bpcc_cond = ( |
| 1136 | ba => 0x8, bn => 0x0, bne => 0x9, be => 0x1, bg => 0xa, |
| 1137 | ble => 0x2, bge => 0xb, bl => 0x3, bgu => 0xc, bleu => 0x4, |
| 1138 | bcc => 0xd, bcs => 0x5, bpos => 0xe, bneg => 0x6, bvc => 0xf, |
| 1139 | bvs => 0x7 |
| 1140 | ); |
| 1141 | |
| 1142 | return if(($taken == 0) && ($opt{illinst} == 0) && ($inst eq "ba")); |
| 1143 | return if(($taken == 1) && ($opt{illinst} == 0) && ($inst eq "bn")); |
| 1144 | |
| 1145 | my $target_limit = 0x200000; |
| 1146 | $target_limit = 0x40000 if($inst_group eq "bpcc"); |
| 1147 | |
| 1148 | if($taken && ($opt{illinst} == 0) && $target == 0) { |
| 1149 | #taken branch on self will be inf-loop |
| 1150 | } |
| 1151 | else { |
| 1152 | if($target & $target_limit) { |
| 1153 | printf("setx th%d_nxt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x, %%g2, %%g3\n", $th_id, $inst, $which_cc, $cc_combo, |
| 1154 | $ptn, $annul, $taken, $target); |
| 1155 | printf("th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1156 | printf("jmp %%g3\n"); |
| 1157 | printf("nop\n"); |
| 1158 | } |
| 1159 | |
| 1160 | printf("th%d_nxt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1161 | printf("th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target) if($target == 0); |
| 1162 | if($target & $target_limit) { |
| 1163 | printf("add %%g3, 0xc, %%g3\n"); |
| 1164 | } |
| 1165 | if($opt{illinst}) { |
| 1166 | my $inst_word = (($annul & 0x1)<<29) | (($bpcc_cond{$inst} & 0xf)<<25) | (0x1<<22) | (($which_cc & 0x3)<<20) | |
| 1167 | (($ptn & 0x1)<<19) | ($target & 0x7ffff); |
| 1168 | printf(".word 0x%x\n", $inst_word); |
| 1169 | } |
| 1170 | else { |
| 1171 | printf("%s", $inst); |
| 1172 | printf(",a") if($annul); |
| 1173 | printf(",pt") if($ptn == 1 && ($inst_group eq "bpcc")); |
| 1174 | printf(",pn") if($ptn == 0 && ($inst_group eq "bpcc")); |
| 1175 | if($inst_group eq "bpcc") { |
| 1176 | printf(" %%icc, ") if($which_cc == 0); |
| 1177 | printf(" %%xcc, ") if($which_cc == 2); |
| 1178 | } |
| 1179 | printf(" th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1180 | } |
| 1181 | if($target == 1) { |
| 1182 | printf("th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1183 | printf("nop ! delay slot & branch target\n"); |
| 1184 | printf("\n"); |
| 1185 | } |
| 1186 | else { |
| 1187 | if(($inst eq "ba" || $inst eq "bn") && $annul && ($opt{illinst} == 0)) { |
| 1188 | #eat annuled instr(make it illegal) |
| 1189 | printf(".word 0x0\n"); |
| 1190 | } |
| 1191 | elsif(($taken == 0) && $annul && ($opt{illinst} == 0)) { |
| 1192 | #eat annuled instr(make it illegal) |
| 1193 | printf(".word 0x0\n"); |
| 1194 | } |
| 1195 | else { |
| 1196 | printf("nop ! delay slot\n"); |
| 1197 | } |
| 1198 | if(($target != 0) && (($target & $target_limit) == 0)) { |
| 1199 | if(($target > 2) && (($taken == 0) || $opt{illinst})) { |
| 1200 | printf("call th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1201 | printf("nop\n"); |
| 1202 | printf(".skip %d\n", ($target-4)*4) if($target > 4); |
| 1203 | } |
| 1204 | else { |
| 1205 | printf(".skip %d\n", ($target-2)*4) if($target > 2); |
| 1206 | } |
| 1207 | printf("th%d_tgt_%s_cc%x_combo%x_ptn%x_a%x_t%x_tgt%x:\n", $th_id, $inst, $which_cc, $cc_combo, $ptn, $annul, $taken, $target); |
| 1208 | printf("nop ! branch target\n"); |
| 1209 | } |
| 1210 | printf("\n"); |
| 1211 | } |
| 1212 | } |
| 1213 | } |
| 1214 | |
| 1215 | sub setup_cc_for_bpcc() { |
| 1216 | my ($inst, $inst_group, $taken, $which_cc, $cc_combo, $th_id) = @_; |
| 1217 | |
| 1218 | my $ext_on = 0; |
| 1219 | $ext_on = 1 if($inst_group eq "bpcc"); |
| 1220 | |
| 1221 | my $cc = $cc_combo; |
| 1222 | my $cc_C = ($cc_combo & 0x1); |
| 1223 | my $cc_V = ($cc_combo & 0x2)>>1; |
| 1224 | my $cc_Z = ($cc_combo & 0x4)>>2; |
| 1225 | my $cc_N = ($cc_combo & 0x8)>>3; |
| 1226 | |
| 1227 | if($inst eq "ba" || $inst eq "bn") { |
| 1228 | # all cc combos are ok |
| 1229 | } |
| 1230 | elsif($inst eq "bne") { |
| 1231 | return 0 if (($taken == 1) && ($cc_Z == 1)); |
| 1232 | return 0 if (($taken == 0) && ($cc_Z == 0)); |
| 1233 | } |
| 1234 | elsif($inst eq "be") { |
| 1235 | return 0 if (($taken == 1) && ($cc_Z == 0)); |
| 1236 | return 0 if (($taken == 0) && ($cc_Z == 1)); |
| 1237 | } |
| 1238 | elsif($inst eq "bg") { |
| 1239 | return 0 if (($taken == 1) && ( ($cc_Z == 1) || |
| 1240 | (($cc_N == 1) && ($cc_V == 0)) || |
| 1241 | (($cc_N == 0) && ($cc_V == 1)) ) ); |
| 1242 | return 0 if (($taken == 0) && ( ($cc_Z == 0) && |
| 1243 | (($cc_N == 1) && ($cc_V == 1)) || |
| 1244 | (($cc_N == 0) && ($cc_V == 0)) ) ); |
| 1245 | } |
| 1246 | elsif($inst eq "ble") { |
| 1247 | return 0 if (($taken == 1) && ( ($cc_Z == 0) && |
| 1248 | (($cc_N == 1) && ($cc_V == 1)) || |
| 1249 | (($cc_N == 0) && ($cc_V == 0)) ) ); |
| 1250 | return 0 if (($taken == 0) && ( ($cc_Z == 1) || |
| 1251 | (($cc_N == 1) && ($cc_V == 0)) || |
| 1252 | (($cc_N == 0) && ($cc_V == 1)) ) ); |
| 1253 | } |
| 1254 | elsif($inst eq "bge") { |
| 1255 | return 0 if (($taken == 1) && ( (($cc_N == 1) && ($cc_V == 0)) || |
| 1256 | (($cc_N == 0) && ($cc_V == 1)) ) ); |
| 1257 | return 0 if (($taken == 0) && ( (($cc_N == 1) && ($cc_V == 1)) || |
| 1258 | (($cc_N == 0) && ($cc_V == 0)) ) ); |
| 1259 | } |
| 1260 | elsif($inst eq "bl") { |
| 1261 | return 0 if (($taken == 1) && ( (($cc_N == 1) && ($cc_V == 1)) || |
| 1262 | (($cc_N == 0) && ($cc_V == 0)) ) ); |
| 1263 | return 0 if (($taken == 0) && ( (($cc_N == 1) && ($cc_V == 0)) || |
| 1264 | (($cc_N == 0) && ($cc_V == 1)) ) ); |
| 1265 | } |
| 1266 | elsif($inst eq "bgu") { |
| 1267 | return 0 if (($taken == 1) && (($cc_C == 1) || ($cc_Z == 1))); |
| 1268 | return 0 if (($taken == 0) && (($cc_C == 0) && ($cc_Z == 0))); |
| 1269 | } |
| 1270 | elsif($inst eq "bleu") { |
| 1271 | return 0 if (($taken == 1) && (($cc_C == 0) && ($cc_Z == 0))); |
| 1272 | return 0 if (($taken == 0) && (($cc_C == 1) || ($cc_Z == 1))); |
| 1273 | } |
| 1274 | elsif($inst eq "bcc") { |
| 1275 | return 0 if (($taken == 1) && ($cc_C == 1)); |
| 1276 | return 0 if (($taken == 0) && ($cc_C == 0)); |
| 1277 | } |
| 1278 | elsif($inst eq "bcs") { |
| 1279 | return 0 if (($taken == 1) && ($cc_C == 0)); |
| 1280 | return 0 if (($taken == 0) && ($cc_C == 1)); |
| 1281 | } |
| 1282 | elsif($inst eq "bpos") { |
| 1283 | return 0 if (($taken == 1) && ($cc_N == 1)); |
| 1284 | return 0 if (($taken == 0) && ($cc_N == 0)); |
| 1285 | } |
| 1286 | elsif($inst eq "bneg") { |
| 1287 | return 0 if (($taken == 1) && ($cc_N == 0)); |
| 1288 | return 0 if (($taken == 0) && ($cc_N == 1)); |
| 1289 | } |
| 1290 | elsif($inst eq "bvc") { |
| 1291 | return 0 if (($taken == 1) && ($cc_V == 1)); |
| 1292 | return 0 if (($taken == 0) && ($cc_V == 0)); |
| 1293 | } |
| 1294 | elsif($inst eq "bvs") { |
| 1295 | return 0 if (($taken == 1) && ($cc_V == 0)); |
| 1296 | return 0 if (($taken == 0) && ($cc_V == 1)); |
| 1297 | } |
| 1298 | else { |
| 1299 | printf("ERROR: unknown instruction\n"); |
| 1300 | } |
| 1301 | |
| 1302 | if($which_cc == 0 || $which_cc == 1) { |
| 1303 | &setup_cc($ext_on, ((~$cc)&0xf), $cc, $th_id); |
| 1304 | } |
| 1305 | if($which_cc == 2 || $which_cc == 3) { |
| 1306 | &setup_cc($ext_on, $cc, ((~$cc)&0xf), $th_id); |
| 1307 | } |
| 1308 | return 1; |
| 1309 | } |
| 1310 | |
| 1311 | sub setup_cc() { |
| 1312 | my ($ext_on, $xcc, $icc, $th_id) = @_; |
| 1313 | |
| 1314 | my $value = ($xcc<<4) | $icc; |
| 1315 | |
| 1316 | printf("wr %%g0, 0x%x, %%ccr\n", $value); |
| 1317 | } |
| 1318 | |
| 1319 | my @asi_lda_insts = ("ldsba", "ldsha", "ldswa", "lduba", "lduha", "lduwa", |
| 1320 | "ldxa", "ldda", "ldaf", "lddaf", "ldqaf", "prefetcha"); |
| 1321 | |
| 1322 | my @asi_sta_insts = ("stba", "stha", "stwa", "stxa", "stda", |
| 1323 | "staf", "stdaf", "stqaf", "casa", "casxa", "ldstuba", "swapa"); |
| 1324 | |
| 1325 | my $big_va = Math::BigInt->new(0xc0); |
| 1326 | $big_va <<=32; |
| 1327 | #my @asi_va_addrs = (0x0); |
| 1328 | my @asi_va_addrs = (0x0, $big_va); |
| 1329 | |
| 1330 | my %asi_spc_traps = ( |
| 1331 | 0x15 => ("P:casa:dataacc,P:casxa:dataacc"), # Real_IO |
| 1332 | 0x1d => ("P:casa:dataacc,P:casxa:dataacc"), # Real_IO_L |
| 1333 | |
| 1334 | 0x16 => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_LOAD_P |
| 1335 | 0x17 => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_LOAD_S |
| 1336 | 0x1e => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_LOAD_P_L |
| 1337 | 0x1f => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_LOAD_S_L |
| 1338 | |
| 1339 | 0x66 => ("N:stxa:dataacc,N:stdaf:dataacc,N:ldxa:dataacc"), # ICACHE_INSTR |
| 1340 | 0x67 => ("N:stxa:dataacc,N:stdaf:dataacc,N:ldxa:dataacc"), # ICACHE_TAG |
| 1341 | |
| 1342 | 0x24 => ("N:ldda:dataacc"), # QUAD_LDDA |
| 1343 | 0x26 => ("N:ldda:dataacc"), # QUAD_LDDA |
| 1344 | 0x2c => ("N:ldda:dataacc"), # QUAD_LDDA |
| 1345 | 0x2e => ("N:ldda:dataacc"), # QUAD_LDDA |
| 1346 | |
| 1347 | 0x45 => ("N:stxa:dataacc,N:ldxa:dataacc"), # LSU_CTL |
| 1348 | 0x4c => ("N:stxa:dataacc,N:ldxa:dataacc"), # SPARC_ERROR_STATUS |
| 1349 | |
| 1350 | 0x22 => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1351 | 0x23 => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1352 | 0x2a => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1353 | 0x2b => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1354 | 0xe2 => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1355 | 0xe3 => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1356 | 0xea => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1357 | 0xeb => ("N:stba:dataacc,N:stha:dataacc,N:stwa:dataacc,N:stxa:dataacc,N:stda:dataacc,N:ldda:dataacc"), # BLK_INIT |
| 1358 | |
| 1359 | 0x82 => ("P:stba:dataacc,P:stha:dataacc,P:stwa:dataacc,P:stxa:dataacc,P:stda:dataacc,P:staf:dataacc," . |
| 1360 | "P:stdaf:dataacc,P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # NFO |
| 1361 | 0x83 => ("P:stba:dataacc,P:stha:dataacc,P:stwa:dataacc,P:stxa:dataacc,P:stda:dataacc,P:staf:dataacc," . |
| 1362 | "P:stdaf:dataacc,P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # NFO |
| 1363 | 0x8a => ("P:stba:dataacc,P:stha:dataacc,P:stwa:dataacc,P:stxa:dataacc,P:stda:dataacc,P:staf:dataacc," . |
| 1364 | "P:stdaf:dataacc,P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # NFO |
| 1365 | 0x8b => ("P:stba:dataacc,P:stha:dataacc,P:stwa:dataacc,P:stxa:dataacc,P:stda:dataacc,P:staf:dataacc," . |
| 1366 | "P:stdaf:dataacc,P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # NFO |
| 1367 | |
| 1368 | 0xf0 => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_P |
| 1369 | 0xf1 => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_S |
| 1370 | 0xf8 => ("N:stdaf:dataacc,N:lddaf:dataacc"), # BLK_PL |
| 1371 | 0xf9 => ("N:stdaf:dataacc,N:lddaf:dataacc") # BLK_SL |
| 1372 | ); |
| 1373 | |
| 1374 | my %asi_io_space_traps = ( |
| 1375 | 0x4 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIN |
| 1376 | 0xc => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIN |
| 1377 | 0x10 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1378 | 0x11 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUS |
| 1379 | 0x18 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1380 | 0x19 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUS |
| 1381 | 0x2a => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1382 | 0x2b => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUS |
| 1383 | 0x14 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # REAL_MEM |
| 1384 | 0x1c => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1385 | 0x80 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1386 | 0x81 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1387 | 0x82 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1388 | 0x83 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1389 | 0x88 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1390 | 0x89 => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1391 | 0x8a => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc"), # AIUP |
| 1392 | 0x8b => ("P:casa:dataacc,P:casxa:dataacc,P:ldstuba:dataacc,P:swapa:dataacc") # AIUP |
| 1393 | ); |
| 1394 | |
| 1395 | my %asi_rbw = ( |
| 1396 | 0x42 => ("stxa,stdaf"), # ASI_BIST_CONTROL |
| 1397 | 0x43 => ("stxa,stdaf"), # ASI_ERR_INJECT |
| 1398 | 0x44 => ("stxa,stdaf"), # ASI_STRM_CTL |
| 1399 | 0x73 => ("stxa,stdaf"), # ASI_SWVR_UDB_INTR_W |
| 1400 | 0x45 => ("stxa,stdaf") # ASI_LSU_CTL_REG |
| 1401 | ); |
| 1402 | |
| 1403 | my %store_rbw_inst = ( |
| 1404 | stxa => "ldxa", |
| 1405 | stdaf => "ldda" |
| 1406 | ); |
| 1407 | |
| 1408 | my %trap_decode = ( |
| 1409 | illinst => 0x10, |
| 1410 | dataacc => 0x16 |
| 1411 | ); |
| 1412 | |
| 1413 | my %external_asi = ( |
| 1414 | 0x4 => 1, 0xc => 1, 0x10 => 1, 0x11 => 1, 0x18 => 1, 0x19 => 1, |
| 1415 | 0x80 => 1, 0x81 => 1, 0x82 => 1, 0x83 => 1, 0x88 => 1, 0x89 => 1, 0x8a => 1, 0x8b => 1, |
| 1416 | 0x14 => 1, 0x15 => 1, 0x16 => 1, 0x17 => 1, 0x1c => 1, 0x1d => 1, 0x1e => 1, 0x1f => 1, |
| 1417 | 0x22 => 1, 0x23 => 1, 0x24 => 1, 0x26 => 1, 0x27 => 1, 0x2a => 1, 0x2b => 1, 0x2c => 1, |
| 1418 | 0x2e => 1, 0x2f => 1, 0xe2 => 1, 0xe3 => 1, 0xea => 1, 0xeb => 1, 0xf0 => 1, 0xf1 => 1, |
| 1419 | 0xf8 => 1, 0xf9 => 1 |
| 1420 | ); |
| 1421 | |
| 1422 | |
| 1423 | sub read_before_write() { |
| 1424 | my ($asi, $inst) = @_; |
| 1425 | my ($rbw_inst); |
| 1426 | if($opt{hyper} || ($opt{super} && $opt{enboff})) { |
| 1427 | } |
| 1428 | else { |
| 1429 | return 0; |
| 1430 | } |
| 1431 | foreach my $rbw (split(/,/, $asi_rbw{$asi})) { |
| 1432 | ($rbw_inst) = split(/:/, $rbw); |
| 1433 | if($rbw_inst eq $inst) { |
| 1434 | return 1; |
| 1435 | } |
| 1436 | } |
| 1437 | return 0; |
| 1438 | } |
| 1439 | |
| 1440 | sub enable_trap() { |
| 1441 | my ($asi, $inst) = @_; |
| 1442 | my $neg_dec_vld = 1; |
| 1443 | my ($pos,$trap_inst,$trap_type); |
| 1444 | foreach my $traps (split(/,/, $asi_spc_traps{$asi})) { |
| 1445 | ($pos,$trap_inst,$trap_type) = split(/:/, $traps); |
| 1446 | if($pos eq "P") { |
| 1447 | if($trap_inst eq $inst) { |
| 1448 | &enable_trap_type($trap_type); |
| 1449 | return 1; |
| 1450 | } |
| 1451 | } |
| 1452 | else { |
| 1453 | if($trap_inst eq $inst) { |
| 1454 | $neg_dec_vld = 0; |
| 1455 | } |
| 1456 | } |
| 1457 | } |
| 1458 | if($pos eq "N" && $neg_dec_vld) { |
| 1459 | &enable_trap_type($trap_type); |
| 1460 | return 1; |
| 1461 | } |
| 1462 | return 0; |
| 1463 | } |
| 1464 | |
| 1465 | |
| 1466 | sub enable_io_space_traps() { |
| 1467 | my ($asi, $inst) = @_; |
| 1468 | my $neg_dec_vld = 1; |
| 1469 | my ($pos,$trap_inst,$trap_type); |
| 1470 | |
| 1471 | foreach my $traps (split(/,/, $asi_io_space_traps{$asi})) { |
| 1472 | ($pos,$trap_inst,$trap_type) = split(/:/, $traps); |
| 1473 | if($pos eq "P") { |
| 1474 | if($trap_inst eq $inst) { |
| 1475 | &enable_trap_type($trap_type); |
| 1476 | return 1; |
| 1477 | } |
| 1478 | } |
| 1479 | else { |
| 1480 | if($trap_inst eq $inst) { |
| 1481 | $neg_dec_vld = 0; |
| 1482 | } |
| 1483 | } |
| 1484 | } |
| 1485 | if($pos eq "N" && $neg_dec_vld) { |
| 1486 | &enable_trap_type($trap_type); |
| 1487 | return 1; |
| 1488 | } |
| 1489 | return 0; |
| 1490 | |
| 1491 | } |
| 1492 | |
| 1493 | sub enable_trap_type() { |
| 1494 | my ($trap) = @_; |
| 1495 | printf("set 0x%x, %%o0\n", $trap_decode{$trap}); |
| 1496 | printf("set 0xff, %%o1\n"); |
| 1497 | if($opt{enboff}) { |
| 1498 | printf("ta T_TRAP_EN_N_TIMES\n"); |
| 1499 | } |
| 1500 | else { |
| 1501 | printf("ta T_HTRAP_EN_N_TIMES\n"); |
| 1502 | } |
| 1503 | } |
| 1504 | |
| 1505 | sub gen_all_asi_insts() { |
| 1506 | my ($th_id, $asi_str) = @_; |
| 1507 | my $asi = hex($asi_str); |
| 1508 | |
| 1509 | &lock_regs(16); |
| 1510 | my $tmp1 = &pick_tmp_reg(); |
| 1511 | my $tmp2 = &pick_tmp_reg(); |
| 1512 | my $tmp3 = &pick_tmp_reg(); |
| 1513 | |
| 1514 | &setx_label("scratch_mem", $tmp1, $tmp2); |
| 1515 | printf("ldx [%%r%d+%d], %%r16\n", $tmp2, ($th_id*2*64)); |
| 1516 | printf("ldx [%%r%d+%d], %%r17\n", $tmp2, ($th_id*2*64)+8); |
| 1517 | for(my $i=0; $i<8; $i++) { |
| 1518 | printf("ldd [%%r%d+%d], %%f%d\n", $tmp2, ((($th_id*2)+1)*64+($i*8)), (16+$i*2)); |
| 1519 | } |
| 1520 | if($asi == 0x4c) { |
| 1521 | &setx_label("0xffffffffffffffff", $tmp1, 16); |
| 1522 | } |
| 1523 | |
| 1524 | foreach my $va (@asi_va_addrs) { |
| 1525 | if($va >> 39) { # this is an io space. |
| 1526 | &setx($va, $tmp1, $tmp3); |
| 1527 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1528 | printf("wr %%g0, 0x14, %%asi\n"); |
| 1529 | printf("stxa %%r16, [%%r%d+%d] %asi\n", $tmp3, ($th_id*2*64)); |
| 1530 | printf("stxa %%r17, [%%r%d+%d] %asi\n", $tmp3, ($th_id*2*64)+8); |
| 1531 | for(my $i=0; $i<8; $i++) { |
| 1532 | printf("stda %%f%d, [%%r%d+%d] %asi\n", (16+$i*2), $tmp3, ((($th_id*2)+1)*64+($i*8))); |
| 1533 | } |
| 1534 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1535 | } |
| 1536 | } |
| 1537 | |
| 1538 | my $va_offset = 0; |
| 1539 | $va_offset = ($th_id*2*64) if($external_asi{$asi}); |
| 1540 | |
| 1541 | my @asi_modes = ("normal", "redbit_on", "ambit_on", "redbit_on_ambit_on", |
| 1542 | "oor_addr", "oor_addr_redbit_on", "oor_addr_ambit_on", "oor_addr_redbit_on_ambit_on", |
| 1543 | "dtlb_off", "dtlb_off_redbit_on", "dtlb_off_ambit_on", "dtlb_off_redbit_on_ambit_on", |
| 1544 | "oor_addr_dtlb_off", "oor_addr_dtlb_off_redbit_on", "oor_addr_dtlb_off_ambit_on", |
| 1545 | "oor_addr_dtlb_off_redbit_on_ambit_on"); |
| 1546 | #my @asi_modes = ("normal", "redbit_on", "oor_addr", "oor_addr_redbit_on", "dtlb_off", "dtlb_off_redbit_on", |
| 1547 | # "oor_addr_dtlb_off", "oor_addr_dtlb_off_redbit_on"); |
| 1548 | foreach my $asi_mode (@asi_modes) { |
| 1549 | if($asi_mode =~ /dtlb_off/) { |
| 1550 | printf("mov 0x1, %%o7\n"); |
| 1551 | printf("ta T_HTRAP_INST0\n"); |
| 1552 | } |
| 1553 | else { |
| 1554 | printf("mov 0x2, %%o7\n"); |
| 1555 | printf("ta T_HTRAP_INST0\n"); |
| 1556 | } |
| 1557 | if($asi_mode =~ /redbit_on/) { |
| 1558 | printf("mov 0x8, %%o7\n"); |
| 1559 | printf("ta T_HTRAP_INST0\n"); |
| 1560 | } |
| 1561 | else { |
| 1562 | printf("mov 0x4, %%o7\n"); |
| 1563 | printf("ta T_HTRAP_INST0\n"); |
| 1564 | } |
| 1565 | if($asi_mode =~ /ambit_on/) { |
| 1566 | printf("!turn on AM bit\n"); |
| 1567 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1568 | printf("rdpr %%pstate, %%r%d\n", $tmp1); |
| 1569 | printf("or %%r%d, 0x8, %%r%d\n", $tmp1, $tmp1); |
| 1570 | printf("wrpr %%r%d, 0x0, %%pstate\n", $tmp1); |
| 1571 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1572 | } |
| 1573 | else { |
| 1574 | printf("!turn off AM bit\n"); |
| 1575 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1576 | printf("rdpr %%pstate, %%r%d\n", $tmp1); |
| 1577 | printf("or %%r%d, 0x8, %%r%d\n", $tmp1, $tmp1); |
| 1578 | printf("wrpr %%r%d, 0x8, %%pstate\n", $tmp1); |
| 1579 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1580 | } |
| 1581 | my $oor_va = 0x0; |
| 1582 | if($asi_mode =~ /oor_addr/) { |
| 1583 | $oor_va = Math::BigInt->new(0x10000); |
| 1584 | $oor_va <<=32; |
| 1585 | } |
| 1586 | foreach my $va (@asi_va_addrs) { |
| 1587 | &setx($va|$oor_va, $tmp2, $tmp1); |
| 1588 | foreach my $stinst (@asi_sta_insts) { |
| 1589 | my $trap_enabled = 0; |
| 1590 | if($stinst eq "stqaf") { |
| 1591 | $trap_enabled = &enable_trap_type("illinst"); |
| 1592 | } |
| 1593 | else { |
| 1594 | $trap_enabled = &enable_trap($asi, $stinst) if($opt{seltrap}); |
| 1595 | } |
| 1596 | if($trap_enabled == 0 && (($va>>39)&0x1)) { |
| 1597 | $trap_enabled = &enable_io_space_traps($asi, $stinst); |
| 1598 | } |
| 1599 | if($external_asi{$asi} == undef && $stinst eq "stdaf") { |
| 1600 | #skip this HACK |
| 1601 | } |
| 1602 | else { |
| 1603 | my $inst = $stinst; |
| 1604 | my $src_type = "%r"; |
| 1605 | $src_type = "%f" if($stinst eq "staf" || $stinst eq "stdaf" || $stinst eq "stqaf"); |
| 1606 | $src_type = "" if($stinst eq "prefetcha"); |
| 1607 | $inst =~ s/(.*)f$/$1/g if($stinst eq "staf" || $stinst eq "stdaf" || $stinst eq "stqaf"); |
| 1608 | |
| 1609 | if($inst eq "casa" || $inst eq "casxa") { |
| 1610 | &cas_alt($inst, $tmp1, 16, $va_offset, $asi, $src_type, 16); |
| 1611 | } |
| 1612 | elsif($inst eq "ldstuba" || $inst eq "swapa") { |
| 1613 | &load_alt($inst, $tmp1, 0, $va_offset, $asi, $src_type, 16); |
| 1614 | } |
| 1615 | else { |
| 1616 | &load_alt($store_rbw_inst{$stinst}, $tmp1, 0, $va_offset, $asi, $src_type, 16) if(&read_before_write($asi, $stinst)); |
| 1617 | &store_alt($inst, $src_type, 16, $tmp1, 0, $va_offset, $asi); |
| 1618 | } |
| 1619 | } #end HACK |
| 1620 | } |
| 1621 | } |
| 1622 | foreach my $va (@asi_va_addrs) { |
| 1623 | &setx($va|$oor_va, $tmp2, $tmp1); |
| 1624 | foreach my $ldinst (@asi_lda_insts) { |
| 1625 | if($ldinst eq "ldqaf") { |
| 1626 | &enable_trap_type("illinst"); |
| 1627 | } |
| 1628 | else { |
| 1629 | &enable_trap($asi, $ldinst); |
| 1630 | } |
| 1631 | if($external_asi{$asi} == undef && $ldinst eq "lddaf") { |
| 1632 | #skip this HACK |
| 1633 | } |
| 1634 | else { |
| 1635 | my $inst = $ldinst; |
| 1636 | my $dest_type = "%r"; |
| 1637 | $dest_type = "%f" if($ldinst eq "ldaf" || $ldinst eq "lddaf" || $ldinst eq "ldqaf"); |
| 1638 | $dest_type = "" if($ldinst eq "prefetcha"); |
| 1639 | $inst =~ s/(.*)f$/$1/g if($ldinst eq "ldaf" || $ldinst eq "lddaf" || $ldinst eq "ldqaf"); |
| 1640 | &load_alt($inst, $tmp1, 0, $va_offset, $asi, $dest_type, 16); |
| 1641 | } #end HACK |
| 1642 | } |
| 1643 | } |
| 1644 | } |
| 1645 | &release_regs(16,$tmp1,$tmp2,$tmp3); |
| 1646 | } |
| 1647 | |
| 1648 | sub gen_required_data_sections() { |
| 1649 | if($opt{inst_group} eq "asi" || $opt{inst_group} eq "ldst") { |
| 1650 | foreach my $va (@asi_va_addrs) { |
| 1651 | &gen_data_sec($va, $va+1024, $opt{dataacc}, $opt{super}) if($va != 0x0); |
| 1652 | } |
| 1653 | } |
| 1654 | } |
| 1655 | |
| 1656 | sub hyp_helper_apis() { |
| 1657 | my ($tmp1, $tmp2) = (1,2); |
| 1658 | printf("SECTION .HTRAPS\n"); |
| 1659 | printf(".text\n"); |
| 1660 | printf(".global hyp_api\n"); |
| 1661 | printf("hyp_api:\n"); |
| 1662 | printf("and %%o7, 0x1, %%o6\n"); |
| 1663 | printf("brnz %%o6, turnoff_dtlb\n"); |
| 1664 | printf("nop\n"); |
| 1665 | printf("and %%o7, 0x2, %%o6\n"); |
| 1666 | printf("brnz %%o6, turnon_dtlb\n"); |
| 1667 | printf("nop\n"); |
| 1668 | printf("and %%o7, 0x4, %%o6\n"); |
| 1669 | printf("brnz %%o6, turnoff_redbit\n"); |
| 1670 | printf("nop\n"); |
| 1671 | printf("and %%o7, 0x8, %%o6\n"); |
| 1672 | printf("brnz %%o6, turnon_redbit\n"); |
| 1673 | printf("nop\n"); |
| 1674 | printf("ba api_done\n"); |
| 1675 | printf("nop\n"); |
| 1676 | |
| 1677 | printf("turnoff_dtlb:\n"); |
| 1678 | printf("ldxa [%%g0] 0x45, %%r%d\n", $tmp1); |
| 1679 | printf("sllx %%r%d, 60, %%r%d\n", $tmp1, $tmp2); |
| 1680 | printf("srlx %%r%d, 63, %%r%d\n", $tmp2, $tmp2); |
| 1681 | printf("sllx %%r%d, 3, %%r%d\n", $tmp2, $tmp2); |
| 1682 | printf("xor %%r%d, %%r%d, %%r%d\n", $tmp1, $tmp2, $tmp1); |
| 1683 | printf("stxa %%r%d, [%%g0] 0x45\n", $tmp1); |
| 1684 | printf("ba api_done\n"); |
| 1685 | printf("nop\n"); |
| 1686 | |
| 1687 | printf("turnon_dtlb:\n"); |
| 1688 | printf("ldxa [%%g0] 0x45, %%r%d\n", $tmp1); |
| 1689 | printf("or %%r%d, 0x8, %%r%d\n", $tmp1, $tmp1); |
| 1690 | printf("stxa %%r%d, [%%g0] 0x45\n", $tmp1); |
| 1691 | printf("ba api_done\n"); |
| 1692 | printf("nop\n"); |
| 1693 | |
| 1694 | printf("turnon_redbit:\n"); |
| 1695 | printf("rdhpr %%hpstate, %%r%d\n", $tmp1); |
| 1696 | printf("or %%r%d, 0x20, %%r%d\n", $tmp1, $tmp1); |
| 1697 | printf("wrhpr %%r%d, 0x0, %%hpstate\n", $tmp1); |
| 1698 | printf("ba api_done\n"); |
| 1699 | printf("nop\n"); |
| 1700 | |
| 1701 | printf("turnoff_redbit:\n"); |
| 1702 | printf("rdhpr %%hpstate, %%r%d\n", $tmp1); |
| 1703 | printf("sllx %%r%d, 58, %%r%d\n", $tmp1, $tmp2); |
| 1704 | printf("srlx %%r%d, 63, %%r%d\n", $tmp2, $tmp2); |
| 1705 | printf("sllx %%r%d, 5, %%r%d\n", $tmp2, $tmp2); |
| 1706 | printf("wrhpr %%r%d, %%r%d, %%hpstate\n", $tmp1, $tmp2); |
| 1707 | printf("ba api_done\n"); |
| 1708 | printf("nop\n"); |
| 1709 | |
| 1710 | printf("api_done:\n"); |
| 1711 | printf("done\n"); |
| 1712 | } |
| 1713 | |
| 1714 | |
| 1715 | my @asi_ld_insts = ("ldsb", "ldsh", "ldsw", "ldub", "lduh", "lduw", |
| 1716 | "ldx", "ldd", "ldf", "lddf", "ldqf", "prefetch"); |
| 1717 | |
| 1718 | my @asi_st_insts = ("stb", "sth", "stw", "stx", "std", |
| 1719 | "stf", "stdf", "stqf", "cas", "casx", "ldstub", "swap"); |
| 1720 | |
| 1721 | sub gen_all_ldst_insts() { |
| 1722 | my ($th_id) = @_; |
| 1723 | |
| 1724 | &lock_regs(16); |
| 1725 | my $tmp1 = &pick_tmp_reg(); |
| 1726 | my $tmp2 = &pick_tmp_reg(); |
| 1727 | my $tmp3 = &pick_tmp_reg(); |
| 1728 | |
| 1729 | &setx_label("scratch_mem", $tmp1, $tmp2); |
| 1730 | printf("ldx [%%r%d+%d], %%r16\n", $tmp2, ($th_id*2*64)); |
| 1731 | printf("ldx [%%r%d+%d], %%r17\n", $tmp2, ($th_id*2*64)+8); |
| 1732 | for(my $i=0; $i<8; $i++) { |
| 1733 | printf("ldd [%%r%d+%d], %%f%d\n", $tmp2, ((($th_id*2)+1)*64+($i*8)), (16+$i*2)); |
| 1734 | } |
| 1735 | |
| 1736 | foreach my $va (@asi_va_addrs) { |
| 1737 | if($va >> 39) { # this is an io space. |
| 1738 | &setx($va, $tmp1, $tmp3); |
| 1739 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1740 | printf("wr %%g0, 0x14, %%asi\n"); |
| 1741 | printf("stxa %%r16, [%%r%d+%d] %asi\n", $tmp3, ($th_id*2*64)); |
| 1742 | printf("stxa %%r17, [%%r%d+%d] %asi\n", $tmp3, ($th_id*2*64)+8); |
| 1743 | for(my $i=0; $i<8; $i++) { |
| 1744 | printf("stda %%f%d, [%%r%d+%d] %asi\n", (16+$i*2), $tmp3, ((($th_id*2)+1)*64+($i*8))); |
| 1745 | } |
| 1746 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1747 | } |
| 1748 | } |
| 1749 | |
| 1750 | my $va_offset = ($th_id*2*64); |
| 1751 | |
| 1752 | my @asi_modes = ("normal", "redbit_on", "ambit_on", "redbit_on_ambit_on", |
| 1753 | "oor_addr", "oor_addr_redbit_on", "oor_addr_ambit_on", "oor_addr_redbit_on_ambit_on", |
| 1754 | "dtlb_off", "dtlb_off_redbit_on", "dtlb_off_ambit_on", "dtlb_off_redbit_on_ambit_on", |
| 1755 | "oor_addr_dtlb_off", "oor_addr_dtlb_off_redbit_on", "oor_addr_dtlb_off_ambit_on", |
| 1756 | "oor_addr_dtlb_off_redbit_on_ambit_on"); |
| 1757 | #my @asi_modes = ("normal", "redbit_on", "oor_addr", "oor_addr_redbit_on", "dtlb_off", "dtlb_off_redbit_on", |
| 1758 | # "oor_addr_dtlb_off", "oor_addr_dtlb_off_redbit_on"); |
| 1759 | foreach my $asi_mode (@asi_modes) { |
| 1760 | if($asi_mode =~ /dtlb_off/) { |
| 1761 | printf("mov 0x1, %%o7\n"); |
| 1762 | printf("ta T_HTRAP_INST0\n"); |
| 1763 | } |
| 1764 | else { |
| 1765 | printf("mov 0x2, %%o7\n"); |
| 1766 | printf("ta T_HTRAP_INST0\n"); |
| 1767 | } |
| 1768 | if($asi_mode =~ /redbit_on/) { |
| 1769 | printf("mov 0x8, %%o7\n"); |
| 1770 | printf("ta T_HTRAP_INST0\n"); |
| 1771 | } |
| 1772 | else { |
| 1773 | printf("mov 0x4, %%o7\n"); |
| 1774 | printf("ta T_HTRAP_INST0\n"); |
| 1775 | } |
| 1776 | if($asi_mode =~ /ambit_on/) { |
| 1777 | printf("!turn on AM bit\n"); |
| 1778 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1779 | printf("rdpr %%pstate, %%r%d\n", $tmp1); |
| 1780 | printf("or %%r%d, 0x8, %%r%d\n", $tmp1, $tmp1); |
| 1781 | printf("wrpr %%r%d, 0x0, %%pstate\n", $tmp1); |
| 1782 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1783 | } |
| 1784 | else { |
| 1785 | printf("!turn off AM bit\n"); |
| 1786 | printf("ta T_CHANGE_PRIV\n") if($opt{super} == 0); |
| 1787 | printf("rdpr %%pstate, %%r%d\n", $tmp1); |
| 1788 | printf("or %%r%d, 0x8, %%r%d\n", $tmp1, $tmp1); |
| 1789 | printf("wrpr %%r%d, 0x8, %%pstate\n", $tmp1); |
| 1790 | printf("ta T_CHANGE_NONPRIV\n") if($opt{super} == 0); |
| 1791 | } |
| 1792 | my $oor_va = 0x0; |
| 1793 | if($asi_mode =~ /oor_addr/) { |
| 1794 | $oor_va = Math::BigInt->new(0x10000); |
| 1795 | $oor_va <<=32; |
| 1796 | } |
| 1797 | foreach my $va (@asi_va_addrs) { |
| 1798 | &setx($va|$oor_va, $tmp2, $tmp1); |
| 1799 | foreach my $stinst (@asi_st_insts) { |
| 1800 | my $trap_enabled = 0; |
| 1801 | if($stinst eq "stqf") { |
| 1802 | $trap_enabled = &enable_trap_type("illinst"); |
| 1803 | } |
| 1804 | if($trap_enabled == 0 && (($va>>39)&0x1)) { |
| 1805 | if($stinst eq "cas" || $stinst eq "casx" || |
| 1806 | $stinst eq "ldstub" || $stinst eq "swap") { |
| 1807 | $trap_enabled = &enable_trap_type("dataacc"); |
| 1808 | } |
| 1809 | } |
| 1810 | my $inst = $stinst; |
| 1811 | my $src_type = "%r"; |
| 1812 | $src_type = "%f" if($stinst eq "stf" || $stinst eq "stdf" || $stinst eq "stqf"); |
| 1813 | $src_type = "" if($stinst eq "prefetch"); |
| 1814 | $inst =~ s/(.*)f$/$1/g if($stinst eq "stf" || $stinst eq "stdf" || $stinst eq "stqf"); |
| 1815 | |
| 1816 | if($inst eq "cas" || $inst eq "casx") { |
| 1817 | &cas($inst, $tmp1, 16, $va_offset, $src_type, 16); |
| 1818 | } |
| 1819 | elsif($inst eq "ldstub" || $inst eq "swap") { |
| 1820 | &load($inst, $tmp1, 0, $va_offset, $src_type, 16); |
| 1821 | } |
| 1822 | else { |
| 1823 | &store($inst, $src_type, 16, $tmp1, 0, $va_offset); |
| 1824 | } |
| 1825 | } |
| 1826 | } |
| 1827 | foreach my $va (@asi_va_addrs) { |
| 1828 | &setx($va|$oor_va, $tmp2, $tmp1); |
| 1829 | foreach my $ldinst (@asi_ld_insts) { |
| 1830 | if($ldinst eq "ldqf") { |
| 1831 | &enable_trap_type("illinst"); |
| 1832 | } |
| 1833 | my $inst = $ldinst; |
| 1834 | my $dest_type = "%r"; |
| 1835 | $dest_type = "%f" if($ldinst eq "ldf" || $ldinst eq "lddf" || $ldinst eq "ldqf"); |
| 1836 | $dest_type = "" if($ldinst eq "prefetch"); |
| 1837 | $inst =~ s/(.*)f$/$1/g if($ldinst eq "ldf" || $ldinst eq "lddf" || $ldinst eq "ldqf"); |
| 1838 | &load($inst, $tmp1, 0, $va_offset, $dest_type, 16); |
| 1839 | } |
| 1840 | } |
| 1841 | } |
| 1842 | &release_regs(16,$tmp1,$tmp2,$tmp3); |
| 1843 | } |
| 1844 | |
| 1845 | 1; |