Commit | Line | Data |
---|---|---|
86530b38 AT |
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; |