Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: SS_SamTracer.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | ||
22 | #include <strings.h> | |
23 | ||
24 | #include "SS_SamTracer.h" | |
25 | ||
26 | #include "SS_VirtualStrand.h" | |
27 | #include "SS_Tlb.h" | |
28 | #include "SS_Asi.h" | |
29 | ||
30 | ||
31 | ||
32 | SS_SamTracer::SS_SamTracer(SS_VirtualStrand *strand) | |
33 | : | |
34 | SS_Tracer() | |
35 | { | |
36 | hook_exe_instr = ss_sam_exe_instr; | |
37 | hook_reg_value = ss_sam_reg_value; | |
38 | hook_trap = ss_sam_trap; | |
39 | hook_end_instr = ss_sam_end_instr; | |
40 | hook_mem_access = ss_sam_mem_acc; | |
41 | hook_asi_access = ss_sam_asi_acc; | |
42 | hook_tlb_update = ss_sam_tlb_update; | |
43 | hook_hwop = ss_sam_hwop; | |
44 | ||
45 | irec.nregs = 0; | |
46 | irec.ld_num = 0; | |
47 | irec.st_num = 0; | |
48 | irec.itype = Sam::VCPU_UNKNOWN_ITYPE; | |
49 | irec.exception = 0; | |
50 | ||
51 | trec.is_async = 0; | |
52 | atrec.is_async = 0; | |
53 | ||
54 | vcpu = strand; | |
55 | } | |
56 | ||
57 | ||
58 | ||
59 | ||
60 | // Conditional Branch decoding tables | |
61 | ||
62 | // special case | |
63 | const int BN = 2; // special | |
64 | const int BA = 3; // case | |
65 | ||
66 | static uint8_t bpr_taken[8][4] = | |
67 | { | |
68 | // 0 < 0 > 0 | |
69 | BN, BN, BN, BN, | |
70 | BN, 1, 0, 0, | |
71 | BN, 1, 1, 0, | |
72 | BN, 0, 1, 0, | |
73 | ||
74 | BN, BN, BN, BN, | |
75 | BN, 0, 1, 1, | |
76 | BN, 0, 0, 1, | |
77 | BN, 1, 0, 1, | |
78 | }; | |
79 | ||
80 | static uint8_t fbr_taken[16][4] = | |
81 | { | |
82 | ||
83 | // E L G U | |
84 | ||
85 | BN, BN, BN, BN, | |
86 | 0, 1, 1, 1, | |
87 | 0, 1, 1, 0, | |
88 | 0, 1, 0, 1, | |
89 | 0, 1, 0, 0, | |
90 | 0, 0, 1, 1, | |
91 | 0, 0, 1, 0, | |
92 | 0, 0, 0, 1, | |
93 | ||
94 | BA, BA, BA, BA, | |
95 | 1, 0, 0, 0, | |
96 | 1, 0, 0, 1, | |
97 | 1, 0, 1, 0, | |
98 | 1, 0, 1, 1, | |
99 | 1, 1, 0, 0, | |
100 | 1, 1, 0, 1, | |
101 | 1, 1, 1, 0, | |
102 | }; | |
103 | ||
104 | static uint8_t br_taken [16][16] = | |
105 | { | |
106 | BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, | |
107 | ||
108 | 0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1, | |
109 | 0,0,1,1, 1,1,1,1, 1,1,0,0, 1,1,1,1, | |
110 | 0,0,1,1, 0,0,1,1, 1,1,0,0, 1,1,0,0, | |
111 | 0,1,0,1, 1,1,1,1, 0,1,0,1, 1,1,1,1, | |
112 | 0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1, | |
113 | 0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1, | |
114 | 0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1, | |
115 | ||
116 | BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, BA, | |
117 | ||
118 | 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0, | |
119 | 1,1,0,0, 0,0,0,0, 0,0,1,1, 0,0,0,0, | |
120 | 1,1,0,0, 1,1,0,0, 0,0,1,1, 0,0,1,1, | |
121 | 1,0,1,0, 0,0,0,0, 1,0,1,0, 0,0,0,0, | |
122 | 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0, | |
123 | 1,1,1,1, 1,1,1,1, 0,0,0,0, 0,0,0,0, | |
124 | 1,1,0,0, 1,1,0,0, 1,1,0,0, 1,1,0,0, | |
125 | }; | |
126 | ||
127 | void SS_SamTracer::ss_sam_exe_instr( SS_Tracer* trc, SS_Vaddr pc, SS_Tte* tte, SS_Instr* i ) | |
128 | { | |
129 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
130 | SS_Strand* strand = sam_trc->vcpu->strand; | |
131 | ||
132 | uint32_t iw = i->opc(); | |
133 | ||
134 | // instruction record | |
135 | if(sam_trc->vcpu->config.trace_on && | |
136 | sam_trc->vcpu->sys_intf.vtrace) | |
137 | { | |
138 | sam_trc->irec.cpuid = strand->strand_id(); | |
139 | sam_trc->irec.pid = tte->pid(); | |
140 | sam_trc->irec.icontext = tte->context(); | |
141 | ||
142 | if (tte->is_virt()) | |
143 | sam_trc->irec.pc_type = Sam::VCPU_VADDR; | |
144 | else if (tte->is_real()) | |
145 | sam_trc->irec.pc_type = Sam::VCPU_RADDR; | |
146 | else | |
147 | sam_trc->irec.pc_type = Sam::VCPU_PADDR; | |
148 | ||
149 | sam_trc->irec.pc_va = pc; | |
150 | sam_trc->irec.pc_pa = tte->trans(pc); | |
151 | int64_t npc = sam_trc->irec.npc_va = strand->npc(); | |
152 | sam_trc->irec.opcode = iw; | |
153 | ||
154 | sam_trc->irec.pstate = strand->pstate(); | |
155 | sam_trc->irec.hpstate = strand->hpstate(); | |
156 | ||
157 | sam_trc->irec.immu_asi = strand->inst_dft_asi(); | |
158 | sam_trc->irec.dmmu_asi = i->is_lsu() ? i->asi : 0; | |
159 | ||
160 | sam_trc->irec.ifetch_trap = !tte->valid(); | |
161 | sam_trc->irec.dmmu_trap = 0; // should be detected from trap type | |
162 | ||
163 | ||
164 | // Check for cti instructions | |
165 | // simple check for pc diff does not cover all cases | |
166 | bool taken = false; | |
167 | bool annul = false; | |
168 | bool cti = false; | |
169 | ||
170 | // check if it is CALL, BPcc, Bicc, BPr, FBPfcc or FBfcc instruction | |
171 | SS_Opcode o; | |
172 | o = iw; | |
173 | uint32_t op = o.get_op(); | |
174 | uint32_t op2 = o.get_op2(); | |
175 | ||
176 | bool branch_on_cond = (op==0) && ((op2==1)||(op2==2)||(op2==5)||(op2==6)); | |
177 | bool branch_on_reg = (op==0) && (op2==3); | |
178 | ||
179 | if (op==1) // CALL instruction | |
180 | { | |
181 | taken = true; | |
182 | cti = true; | |
183 | } | |
184 | else if (branch_on_cond) | |
185 | { | |
186 | cti = true; | |
187 | ||
188 | ||
189 | if(o.get_cond() == 8) // branch allways | |
190 | { | |
191 | taken = true; | |
192 | sam_trc->irec.npc_va = pc; | |
193 | } | |
194 | else // check if conditional branch was taken | |
195 | { | |
196 | if (op2==1) // BPcc | |
197 | { | |
198 | uint8_t cc_iw = o.get_cc(); | |
199 | ||
200 | if (cc_iw == 0) // icc | |
201 | taken = br_taken[o.get_cond()][strand->ccr.icc()]==1; | |
202 | else if (cc_iw = 2) // xcc | |
203 | taken = br_taken[o.get_cond()][strand->ccr.xcc()]==1; | |
204 | ||
205 | } | |
206 | else if (op2==2) //Bicc | |
207 | { | |
208 | taken = br_taken[o.get_cond()][strand->ccr.icc()]==1; | |
209 | } | |
210 | else if (op2==5) // FBPfcc | |
211 | { | |
212 | uint8_t fcc = 0; | |
213 | strand->get_fsr(); | |
214 | switch (o.get_cc()) | |
215 | { | |
216 | case 0: // fcc0 | |
217 | fcc = strand->fsr.fcc0(); | |
218 | break; | |
219 | case 1: // fcc1 | |
220 | fcc = strand->fsr.fcc1(); | |
221 | break; | |
222 | case 2: // fcc2 | |
223 | fcc = strand->fsr.fcc2(); | |
224 | break; | |
225 | case 3: // fcc3 | |
226 | fcc = strand->fsr.fcc3(); | |
227 | break; | |
228 | } | |
229 | taken = fbr_taken[o.get_cond()][fcc]==1; | |
230 | } | |
231 | else if (op2==6) // FBfcc | |
232 | { | |
233 | strand->get_fsr(); | |
234 | uint8_t fcc0 = strand->fsr.fcc0(); | |
235 | taken = fbr_taken[o.get_cond()][fcc0]==1; | |
236 | } | |
237 | ||
238 | } | |
239 | // delay slot instruction is annuled when annul bit is set and | |
240 | // it is unconditional branch or conditional branch is not taken | |
241 | annul = ((iw>>29)&1) && ( (o.get_cond() == 8 || o.get_cond() == 0) || !taken ); | |
242 | ||
243 | } | |
244 | else if (branch_on_reg) // check if branch on reg value was taken | |
245 | { | |
246 | cti = true; | |
247 | ||
248 | // get current reg[rs1] value | |
249 | int64_t r1 = sam_trc->vcpu->strand->irf[o.get_rs1()]; | |
250 | uint8_t rv = 0; | |
251 | ||
252 | if (r1 == 0) rv = 1; | |
253 | else if (r1 < 0) rv = 2; | |
254 | else if (r1 > 0) rv = 3; | |
255 | taken = bpr_taken[o.get_cond()][rv]==1; | |
256 | ||
257 | // delay slot instruction is annuled when annul bit is set and | |
258 | // branch is not taken | |
259 | annul = ((iw>>29)&1) && !taken ; | |
260 | } | |
261 | ||
262 | ||
263 | if ( !cti && (op == 2)) | |
264 | { | |
265 | // check if it is DONE, RETRY, JPRIV, JMPL, RETURN instruction | |
266 | uint32_t op3 = (iw>>19) & 0x3f; | |
267 | if ((op3 == 0x3e) ||(op3 == 0x38)||(op3 == 0x39)) | |
268 | { | |
269 | cti = true; | |
270 | taken = true; | |
271 | } | |
272 | else if (op3 == 0x3a) // Tcc | |
273 | { | |
274 | cti = true; | |
275 | } | |
276 | } | |
277 | ||
278 | ||
279 | ||
280 | ||
281 | if (cti) | |
282 | { | |
283 | sam_trc->irec.itype |= Sam::VCPU_BRANCH_ITYPE; | |
284 | } | |
285 | ||
286 | // sanity check if "taken" was calculated correctly | |
287 | if ((npc != (strand->pc() + 4)) && !taken) | |
288 | { | |
289 | taken = true; | |
290 | } | |
291 | sam_trc->irec.annul = annul; | |
292 | sam_trc->irec.taken = taken; | |
293 | ||
294 | ||
295 | ||
296 | } | |
297 | return; | |
298 | } | |
299 | ||
300 | void SS_SamTracer::ss_sam_hwop( SS_Tracer* trc, MemAccess type, SS_Paddr addr, uint_t size, uint64_t *value ) | |
301 | { | |
302 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
303 | ||
304 | if(sam_trc->vcpu->config.trace_on && | |
305 | sam_trc->vcpu->sys_intf.vtrace) | |
306 | { | |
307 | Sam::VCPU_HwOp hwop; | |
308 | ||
309 | hwop.cpuid = sam_trc->vcpu->id(); | |
310 | ||
311 | hwop.op_type = !is_fetch(type); | |
312 | hwop.addr = addr; | |
313 | hwop.data[0] = value[0]; | |
314 | hwop.data[1] = value[1]; | |
315 | ||
316 | // call tracer | |
317 | sam_trc->vcpu->sys_intf.vtrace->hwop(&hwop); | |
318 | } | |
319 | } | |
320 | ||
321 | void SS_SamTracer::ss_sam_tlb_update( SS_Tracer* trc, bool insert, SS_Tlb* tlb, uint_t index, SS_Tte* tte ) | |
322 | { | |
323 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
324 | ||
325 | if( !sam_trc->vcpu->config.trace_on || | |
326 | !sam_trc->vcpu->sys_intf.vtrace) | |
327 | return; | |
328 | ||
329 | ||
330 | ||
331 | Sam::VCPU_TLB tlb_rec; | |
332 | ||
333 | tlb_rec.format = 1; // sun4u | |
334 | tlb_rec.cpuid = sam_trc->vcpu->id(); | |
335 | tlb_rec.demap = !insert; | |
336 | tlb_rec.tlb_type = tlb->is_data_tlb(); | |
337 | tlb_rec.tlb_index = index; | |
338 | tlb_rec.tlb_no = tlb->tlb_id(); | |
339 | ||
340 | tlb_rec.tte_tag = tte->tag(); | |
341 | ||
342 | // data: v:63 nfo:62 taddr: 55-13 ie:12 e:11 cp:10 cv:9 p:8 ep:7 w:6 sz:3-0 | |
343 | tlb_rec.tte_data = tte->taddr() & (0x7ffffffffull << 13); | |
344 | if (tte->valid_bit()) tlb_rec.tte_data |= (1ull<<63); | |
345 | if (tte->nfo()) tlb_rec.tte_data |= (1ull << 62); | |
346 | if (tte->ie()) tlb_rec.tte_data |= (1ull << 12); | |
347 | if (tte->e()) tlb_rec.tte_data |= (1ull << 11); | |
348 | if (tte->cp()) tlb_rec.tte_data |= (1ull << 10); | |
349 | if (tte->cv()) tlb_rec.tte_data |= (1ull << 9); | |
350 | if (tte->p()) tlb_rec.tte_data |= (1ull << 8); | |
351 | if (tte->x()) tlb_rec.tte_data |= (1ull << 7); | |
352 | if (tte->w()) tlb_rec.tte_data |= (1ull << 6); | |
353 | tlb_rec.tte_data |= tte->page_size(); | |
354 | ||
355 | tlb_rec.is_real = tte->real_bit(); | |
356 | tlb_rec.partid = tte->pid(); | |
357 | ||
358 | tlb_rec.tte_page_size = tte->page_size(); | |
359 | tlb_rec.tte_context = tte->context(); | |
360 | ||
361 | // call tracer | |
362 | sam_trc->vcpu->sys_intf.vtrace->tlb(&tlb_rec); | |
363 | ||
364 | } | |
365 | ||
366 | void SS_SamTracer::ss_sam_reg_value( SS_Tracer* trc, SS_Registers::Index index, uint64_t value ) | |
367 | { | |
368 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
369 | ||
370 | // collect reg values | |
371 | if(sam_trc->vcpu->config.trace_on && | |
372 | sam_trc->vcpu->sys_intf.vtrace) | |
373 | { | |
374 | int rid = sam_trc->irec.nregs; | |
375 | ||
376 | if (rid >= (Sam::VCPU_MAX_DEST_REG_NUM-1)) | |
377 | { | |
378 | //fprintf (stderr, "Tracer: too many dest regs\n"); | |
379 | return; | |
380 | } | |
381 | ||
382 | if (SS_Registers::is_irf(index)) | |
383 | { | |
384 | sam_trc->irec.itype |= Sam::VCPU_ALU_ITYPE; | |
385 | sam_trc->irec.dreg[rid].r.id = index - SS_Registers::IRF_OFS; | |
386 | sam_trc->irec.dreg[rid].r.type = Sam::VCPU_INT_RTYPE; | |
387 | sam_trc->irec.dval[rid] = value; | |
388 | } | |
389 | else if (SS_Registers::is_drf(index)) | |
390 | { | |
391 | sam_trc->irec.itype |= Sam::VCPU_FP_ITYPE; | |
392 | sam_trc->irec.dreg[rid].r.id = (index - SS_Registers::DRF_OFS)*2; // @@ note *2 !!! | |
393 | sam_trc->irec.dreg[rid].r.type = Sam::VCPU_FP_DOUBLE_RTYPE; | |
394 | sam_trc->irec.dval[rid] = value; | |
395 | } | |
396 | else if (SS_Registers::is_asr(index)) | |
397 | { | |
398 | if ((index == SS_Registers::ASR_PC) && | |
399 | value == (sam_trc->irec.pc_va + 4)) | |
400 | { | |
401 | // skip pc update | |
402 | return; | |
403 | } | |
404 | sam_trc->irec.dreg[rid].r.id = index - SS_Registers::ASR_OFS; | |
405 | sam_trc->irec.dreg[rid].r.type = Sam::VCPU_ASR_RTYPE; | |
406 | sam_trc->irec.dval[rid] = value; | |
407 | } | |
408 | else if (SS_Registers::is_pr(index)) | |
409 | { | |
410 | sam_trc->irec.dreg[rid].r.id = index - SS_Registers::PR_OFS; | |
411 | sam_trc->irec.dreg[rid].r.type = Sam::VCPU_PR_RTYPE; | |
412 | sam_trc->irec.dval[rid] = value; | |
413 | } | |
414 | else if (SS_Registers::is_hpr(index)) | |
415 | { | |
416 | sam_trc->irec.dreg[rid].r.id = index - SS_Registers::HPR_OFS; | |
417 | sam_trc->irec.dreg[rid].r.type = Sam::VCPU_HPR_RTYPE; | |
418 | sam_trc->irec.dval[rid] = value; | |
419 | } | |
420 | else | |
421 | { | |
422 | return; // unknown reg, ignore | |
423 | } | |
424 | ||
425 | sam_trc->irec.nregs = rid + 1; | |
426 | } | |
427 | ||
428 | } | |
429 | ||
430 | void SS_SamTracer::ss_sam_mem_acc ( SS_Tracer* trc, MemAccess type, SS_Vaddr va, | |
431 | SS_Tte* tte, uint_t size, uint64_t* val ) | |
432 | { | |
433 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
434 | ||
435 | if( !sam_trc->vcpu->config.trace_on || | |
436 | !sam_trc->vcpu->sys_intf.vtrace) | |
437 | return; | |
438 | ||
439 | sam_trc->irec.dcontext = tte ? tte->context() : 0; | |
440 | ||
441 | if (tte == 0) | |
442 | sam_trc->irec.ea_type = Sam::VCPU_VADDR; | |
443 | else if (tte->is_virt()) | |
444 | sam_trc->irec.ea_type = Sam::VCPU_VADDR; | |
445 | else if (tte->is_real()) | |
446 | sam_trc->irec.ea_type = Sam::VCPU_RADDR; | |
447 | else | |
448 | sam_trc->irec.ea_type = Sam::VCPU_PADDR; | |
449 | ||
450 | switch(type) | |
451 | { | |
452 | case PREFETCH: | |
453 | sam_trc->irec.itype |= Sam::VCPU_LOAD_ITYPE; | |
454 | sam_trc->irec.ea_va = va; | |
455 | sam_trc->irec.ea_pa = tte ? tte->trans(va) : 0; // tte == 0 is TLB mis (no trap) | |
456 | sam_trc->irec.ld_bitmask = 0; // zero size load == prefetch | |
457 | break; | |
458 | ||
459 | case FLUSH: | |
460 | sam_trc->irec.itype |= Sam::VCPU_STORE_ITYPE; | |
461 | sam_trc->irec.ea_va = va; | |
462 | sam_trc->irec.ea_pa = tte ? tte->trans(va) : 0; // tte == 0 is TLB mis (no trap) | |
463 | sam_trc->irec.st_bitmask = 0; // zero size store == flush | |
464 | break; | |
465 | ||
466 | case LD_DATA : | |
467 | case LD_SWAP : | |
468 | case LD_CAS : | |
469 | case LD_LDST : | |
470 | ||
471 | sam_trc->irec.itype |= Sam::VCPU_LOAD_ITYPE; | |
472 | sam_trc->irec.ea_va = va; | |
473 | sam_trc->irec.ea_pa = tte->trans(va); | |
474 | sam_trc->irec.ld_bitmask = (size<8)?(uint64_t(1)<<(size*8))-uint64_t(1):~uint64_t(0); | |
475 | ||
476 | switch(size) | |
477 | { | |
478 | case 1: | |
479 | case 2: | |
480 | case 4: | |
481 | case 8: | |
482 | if (sam_trc->irec.ld_num < Sam::VCPU_MAX_MEM_ACCESS_NUM) | |
483 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = *val; | |
484 | break; | |
485 | case 16: | |
486 | ||
487 | if (sam_trc->irec.ld_num < Sam::VCPU_MAX_MEM_ACCESS_NUM-1) | |
488 | { | |
489 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[0]; | |
490 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[1]; | |
491 | } | |
492 | break; | |
493 | case 64: | |
494 | ||
495 | if (sam_trc->irec.ld_num < Sam::VCPU_MAX_MEM_ACCESS_NUM-7) | |
496 | { | |
497 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[0]; | |
498 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[1]; | |
499 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[2]; | |
500 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[3]; | |
501 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[4]; | |
502 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[5]; | |
503 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[6]; | |
504 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = val[7]; | |
505 | } | |
506 | break; | |
507 | default: | |
508 | break; | |
509 | ||
510 | } | |
511 | break; | |
512 | ||
513 | case ST_DATA : | |
514 | case ST_SWAP : | |
515 | case ST_CAS : | |
516 | case ST_LDST : | |
517 | ||
518 | sam_trc->irec.itype |= Sam::VCPU_STORE_ITYPE; | |
519 | sam_trc->irec.ea_va = va; | |
520 | sam_trc->irec.ea_pa = tte->trans(va); | |
521 | sam_trc->irec.st_bitmask = (size<8)?(uint64_t(1)<<(size*8))-uint64_t(1):~uint64_t(0); | |
522 | ||
523 | switch(size) | |
524 | { | |
525 | case 1: | |
526 | case 2: | |
527 | case 4: | |
528 | case 8: | |
529 | ||
530 | if (sam_trc->irec.st_num < Sam::VCPU_MAX_MEM_ACCESS_NUM) | |
531 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = *val; | |
532 | break; | |
533 | case 64: | |
534 | ||
535 | if (sam_trc->irec.st_num < Sam::VCPU_MAX_MEM_ACCESS_NUM-7) | |
536 | { | |
537 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[0]; | |
538 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[1]; | |
539 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[2]; | |
540 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[3]; | |
541 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[4]; | |
542 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[5]; | |
543 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[6]; | |
544 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[7]; | |
545 | } | |
546 | break; | |
547 | default: | |
548 | break; | |
549 | } | |
550 | break; | |
551 | ||
552 | case ST_PART : | |
553 | ||
554 | sam_trc->irec.itype |= Sam::VCPU_STORE_ITYPE; | |
555 | sam_trc->irec.ea_va = va; | |
556 | sam_trc->irec.ea_pa = tte->trans(va); | |
557 | sam_trc->irec.st_bitmask = val[1]; | |
558 | if (sam_trc->irec.st_num < Sam::VCPU_MAX_MEM_ACCESS_NUM) | |
559 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = val[0]; | |
560 | break; | |
561 | ||
562 | default: | |
563 | break; | |
564 | ||
565 | } | |
566 | } | |
567 | ||
568 | void SS_SamTracer::ss_sam_asi_acc ( SS_Tracer* trc, MemAccess type, uint8_t asi, SS_Vaddr va, uint64_t* val ) | |
569 | { | |
570 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
571 | ||
572 | if( !sam_trc->vcpu->config.trace_on || | |
573 | !sam_trc->vcpu->sys_intf.vtrace) | |
574 | return; | |
575 | ||
576 | sam_trc->irec.dmmu_asi = asi; | |
577 | sam_trc->irec.ea_va = va; | |
578 | sam_trc->irec.ea_pa = va; | |
579 | sam_trc->irec.ld_bitmask = ~uint64_t(0); | |
580 | sam_trc->irec.ea_type = Sam::VCPU_VADDR; | |
581 | ||
582 | switch(type) | |
583 | { | |
584 | case LD_DATA: | |
585 | sam_trc->irec.itype |= Sam::VCPU_ASI_LOAD_ITYPE; | |
586 | if (sam_trc->irec.ld_num < Sam::VCPU_MAX_MEM_ACCESS_NUM) | |
587 | sam_trc->irec.ld_mem_value[sam_trc->irec.ld_num++] = *val; | |
588 | break; | |
589 | ||
590 | case ST_DATA : | |
591 | sam_trc->irec.itype |= Sam::VCPU_ASI_STORE_ITYPE; | |
592 | if (sam_trc->irec.st_num < Sam::VCPU_MAX_MEM_ACCESS_NUM) | |
593 | sam_trc->irec.st_mem_value[sam_trc->irec.st_num++] = *val; | |
594 | break; | |
595 | ||
596 | default: | |
597 | break; | |
598 | ||
599 | } | |
600 | ||
601 | } | |
602 | ||
603 | void SS_SamTracer::ss_sam_trap( SS_Tracer* trc, SS_Trap::Type tt, TrapMode mode, SS_Vaddr ea ) | |
604 | { | |
605 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
606 | SS_Strand* strand = sam_trc->vcpu->strand; | |
607 | ||
608 | // trap record | |
609 | if(sam_trc->vcpu->config.trace_on && | |
610 | sam_trc->vcpu->sys_intf.vtrace) | |
611 | { | |
612 | ||
613 | Sam::VCPU_Trap *trap = &sam_trc->trec; | |
614 | if (SS_Trap::table[tt].disrupting) | |
615 | { | |
616 | sam_trc->atrec.is_async = 1; | |
617 | trap = &sam_trc->atrec; | |
618 | } | |
619 | else | |
620 | { | |
621 | sam_trc->irec.exception = 1; | |
622 | } | |
623 | ||
624 | ||
625 | // collect trap record | |
626 | trap->cpuid = sam_trc->vcpu->id(); | |
627 | ||
628 | trap->nregs = 0; | |
629 | ||
630 | uint64_t value=0; | |
631 | trap->pc_va = strand->pc(); | |
632 | trap->npc_va = strand->npc(); | |
633 | trap->tno = tt; | |
634 | ||
635 | if (mode == DATA_TRAP) { | |
636 | sam_trc->irec.ea_va = ea; | |
637 | sam_trc->irec.ea_pa = 0x0; | |
638 | } | |
639 | } | |
640 | return; | |
641 | } | |
642 | ||
643 | void SS_SamTracer::ss_sam_end_instr( SS_Tracer* trc ) | |
644 | { | |
645 | SS_SamTracer* sam_trc = (SS_SamTracer*)trc; | |
646 | ||
647 | if(sam_trc->vcpu->config.trace_on && | |
648 | sam_trc->vcpu->sys_intf.vtrace) | |
649 | { | |
650 | // call tracer - async trap record | |
651 | if(sam_trc->atrec.is_async) | |
652 | sam_trc->vcpu->sys_intf.vtrace->trap(&(sam_trc->atrec)); | |
653 | ||
654 | // instruction record | |
655 | sam_trc->vcpu->sys_intf.vtrace->instr(&(sam_trc->irec)); | |
656 | ||
657 | // trap record | |
658 | if(sam_trc->irec.exception) | |
659 | sam_trc->vcpu->sys_intf.vtrace->trap(&(sam_trc->trec)); | |
660 | ||
661 | // reset the counters | |
662 | bzero(&sam_trc->irec, sizeof(Sam::VCPU_Instruction)); | |
663 | bzero(&sam_trc->trec, sizeof(Sam::VCPU_Trap)); | |
664 | bzero(&sam_trc->atrec, sizeof(Sam::VCPU_Trap)); | |
665 | } | |
666 | } | |
667 |