Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | |
2 | import re | |
3 | freg=re.compile('^f[0-9]$|^f[1-5][0-9]$|^f6[0-3]$') | |
4 | greg = re.compile('^g[0-7]$') | |
5 | wreg = re.compile('^[ilo][0-7]$') | |
6 | ||
7 | import Pfe_Strand | |
8 | import Pfe_Tlb | |
9 | ||
10 | from SS_Break import * | |
11 | ||
12 | ||
13 | class AsiStateError(Exception): | |
14 | def __init__(self,asi,va): | |
15 | Exception.__init__(self) | |
16 | self.asi = asi | |
17 | self.va = va | |
18 | ||
19 | def __str__(self): | |
20 | return "The strand has no mapping for: asi="+hex(self.asi)+" va="+hex(self.va) | |
21 | ||
22 | ||
23 | class AsiState: | |
24 | def __init__(self,asi,va): | |
25 | self.asi = asi | |
26 | self.va = va | |
27 | ||
28 | def get(self,strand): | |
29 | data = strand.get_asi(self.asi,self.va) | |
30 | if strand.asi_error != 0: | |
31 | raise AsiStateError(self.asi,self.va) | |
32 | return data | |
33 | ||
34 | def set(self,strand,data): | |
35 | strand.set_asi(self.asi,self.va,data) | |
36 | if strand.asi_error != 0: | |
37 | raise AsiStateError(self.asi,self.va) | |
38 | ||
39 | ||
40 | ||
41 | def __getreg__(index): | |
42 | return lambda strand: strand.get_reg(index) | |
43 | ||
44 | def __setreg__(index): | |
45 | return lambda strand,value: strand.set_reg(index,value) | |
46 | ||
47 | def __getreg_tl__(index): | |
48 | return lambda strand,tl: strand.get_reg_tl(tl,index) | |
49 | ||
50 | def __setreg_tl__(index): | |
51 | return lambda strand,tl,value: strand.set_reg_tl(tl,index,value) | |
52 | ||
53 | def __getreg_gl__(index): | |
54 | return lambda strand,gl: strand.get_reg_gl(gl,index) | |
55 | ||
56 | def __setreg_gl__(index): | |
57 | return lambda strand,gl,value: strand.set_reg_gl(gl,index,value) | |
58 | ||
59 | def __getreg_wp__(index): | |
60 | return lambda strand,wp: strand.get_reg_wp(wp,index) | |
61 | ||
62 | def __setreg_wp__(index): | |
63 | return lambda strand,wp,value: strand.set_reg_wp(wp,index,value) | |
64 | ||
65 | # Good old Python is a little sick. The Py_BuildValue api routine | |
66 | # does not treat uint64_t as unsigned and converts the unsigned value | |
67 | # to an signed value. The abs64 function below fixes this problem. | |
68 | # Currently the onlu code using By_BuildValue with K format is SS_PythonTracer | |
69 | ||
70 | def abs64(x): | |
71 | if x < 0: | |
72 | return 0x10000000000000000 + x | |
73 | return x; | |
74 | ||
75 | ||
76 | class Tracer: | |
77 | def __init__(self,strand,tracer): | |
78 | self.strand = strand | |
79 | self.__vonk__ = strand.__vonk__ | |
80 | self.__tracer__ = tracer | |
81 | self.opt_exe_instr = False | |
82 | self.opt_reg_value = False | |
83 | self.opt_trap = False | |
84 | self.opt_mem_access = 0 | |
85 | self.opt_tlb_update = 0 | |
86 | self.state = {} | |
87 | self.trc_connected = False | |
88 | # instruction count | |
89 | self.icount = 0 | |
90 | # output in n2 sas.log format | |
91 | self.n2_format = False | |
92 | ||
93 | def set_format(self,format=None): | |
94 | if format == None: | |
95 | return self.n2_format | |
96 | elif type(format) == bool: | |
97 | self.n2_format = format | |
98 | else: | |
99 | raise TypeError | |
100 | ||
101 | def set_tracer(self): | |
102 | if self.opt_exe_instr or self.opt_reg_value or self.opt_trap or self.opt_mem_access or self.opt_tlb_update: | |
103 | if not self.trc_connected: | |
104 | self.strand.__strand__.add_tracer(self.__tracer__) | |
105 | self.trc_connected = True | |
106 | else: | |
107 | if self.trc_connected: | |
108 | self.strand.__strand__.del_tracer(self.__tracer__) | |
109 | self.trc_connected = False | |
110 | ||
111 | def exe_instr(self,on=None): | |
112 | if on == None: | |
113 | return self.opt_exe_instr | |
114 | elif type(on) == bool: | |
115 | self.opt_exe_instr = on | |
116 | if on: | |
117 | if not self.n2_format: | |
118 | self.__tracer__.set_exe_instr(self.trc_exe_instr) | |
119 | else: | |
120 | self.__tracer__.set_exe_instr(self.trc_exe_instr_n2) | |
121 | else: | |
122 | self.__tracer__.clr_exe_instr() | |
123 | else: | |
124 | raise TypeError | |
125 | self.set_tracer() | |
126 | ||
127 | def trc_exe_instr(self,pc,tte,i): | |
128 | pc = abs64(pc) | |
129 | opc = self.__vonk__.ss_instr(i).get_opc() & 0xffffffffL | |
130 | pa = self.__vonk__.ss_tte(tte).trans(pc) | |
131 | self.icount += 1 | |
132 | str = self.__vonk__.dis(opc,pc) | |
133 | print "%d:" % self.strand.strand_id,pc,':',pa,"[0x%08x] %s" % (opc,str) | |
134 | ||
135 | ||
136 | def trc_exe_instr_n2(self,pc,tte,i): | |
137 | """ | |
138 | N2 cosim sas.log format | |
139 | """ | |
140 | # the function is embedded in SS_PliSocket.cc so that we have consistent | |
141 | # content in sas.log and vcs.log | |
142 | return | |
143 | ||
144 | ||
145 | def reg_value(self,on=None): | |
146 | if on == None: | |
147 | return self.opt_reg_value | |
148 | elif type(on) == bool: | |
149 | self.opt_reg_value = on | |
150 | if on: | |
151 | if not self.n2_format: | |
152 | self.__tracer__.set_reg_value(self.trc_reg_value) | |
153 | else: | |
154 | self.__tracer__.set_reg_value(self.trc_reg_value_n2) | |
155 | else: | |
156 | self.__tracer__.clr_reg_value() | |
157 | else: | |
158 | raise TypeError | |
159 | self.set_tracer() | |
160 | ||
161 | ||
162 | def trc_reg_value(self,index,value): | |
163 | if index >= self.__vonk__.SS_Registers.ALIAS_END: | |
164 | return | |
165 | value = abs64(value) | |
166 | reg = self.strand.__vonk__.SS_Registers.get_alias_name(index) | |
167 | if reg == 'asi_reg': | |
168 | reg = 'asi' | |
169 | if self.state.has_key(index): | |
170 | print "%d:\t%s:" % (self.strand.strand_id,reg),self.state[index],"->",value | |
171 | else: | |
172 | print "%d:\t%s: None ->" % (self.strand.strand_id,reg),value | |
173 | self.state[index] = value | |
174 | ||
175 | ||
176 | def trc_reg_value_n2(self,index,value): | |
177 | """ | |
178 | N2 cosim sas.log format | |
179 | """ | |
180 | # the function is embedded in SS_PliSocket.cc so that we have consistent | |
181 | # content in sas.log and vcs.log | |
182 | return | |
183 | ||
184 | ||
185 | def trap(self,on=None): | |
186 | if on == None: | |
187 | return self.opt_trap | |
188 | elif type(on) == bool: | |
189 | self.opt_trap = on | |
190 | if on: | |
191 | self.__tracer__.set_trap(self.trc_trap) | |
192 | else: | |
193 | self.__tracer__.clr_trap() | |
194 | else: | |
195 | raise TypeError | |
196 | self.set_tracer() | |
197 | ||
198 | def trc_trap(self,type,mode,addr): | |
199 | addr = abs64(addr) | |
200 | if mode == self.__tracer__.TRAP: | |
201 | print "%d: 0x%x trap: 0x%x" % (self.strand.strand_id,self.strand.pc,type) | |
202 | elif mode == self.__tracer__.INST_TRAP: | |
203 | print "%d: 0x%x trap: 0x%x inst mmu pc=0x%x" % (self.strand.strand_id,self.strand.pc,type,addr) | |
204 | elif mode == self.__tracer__.DATA_TRAP: | |
205 | print "%d: 0x%x trap: 0x%x data mmu ea=0x%x" % (self.strand.strand_id,self.strand.pc,type,addr) | |
206 | ||
207 | ||
208 | MEM_CODE = 1 | |
209 | MEM_DATA = 2 | |
210 | ||
211 | def mem_access(self,on=None): | |
212 | if on == None: | |
213 | return self.opt_mem_access | |
214 | elif type(on) == bool: | |
215 | self.opt_mem_access = self.MEM_CODE | self.MEM_DATA | |
216 | elif type(on) == int: | |
217 | self.opt_mem_access = on | |
218 | else: | |
219 | raise TypeError | |
220 | if (self.opt_mem_access & (self.MEM_CODE | self.MEM_DATA)) != 0: | |
221 | self.__tracer__.set_mem_access(self.trc_mem_access) | |
222 | else: | |
223 | self.__tracer__.clr_mem_access() | |
224 | self.set_tracer() | |
225 | ||
226 | def trc_mem_access(self,type,va,tte,size,data): | |
227 | va = abs64(va) | |
228 | for i in len(data): | |
229 | data[i] = abs64(data[i]) | |
230 | ||
231 | pa = self.__vonk__.ss_tte(tte).trans(va) | |
232 | if type == self.__tracer__.LD_CODE: | |
233 | if (self.opt_mem_access & self.MEM_CODE) == 0: | |
234 | return | |
235 | op = 'fetch' | |
236 | elif (self.opt_mem_access & self.MEM_DATA) == 0: | |
237 | return | |
238 | elif type == self.__tracer__.LD_DATA: | |
239 | op = 'ld' | |
240 | elif type == self.__tracer__.ST_DATA: | |
241 | op = 'st' | |
242 | elif type == self.__tracer__.ST_PART: | |
243 | op = 'st-partial' | |
244 | elif type == self.__tracer__.ST_SWAP: | |
245 | op = 'st-swap' | |
246 | elif type == self.__tracer__.LD_SWAP: | |
247 | op = 'ld-swap' | |
248 | elif type == self.__tracer__.ST_CAS: | |
249 | op = 'st-cas' | |
250 | elif type == self.__tracer__.LD_CAS: | |
251 | op = 'ld-cas' | |
252 | elif type == self.__tracer__.ST_LDST: | |
253 | op = 'st-ldst' | |
254 | elif type == self.__tracer__.LD_LDST: | |
255 | op = 'ld-ldst' | |
256 | # ToDo need unsigned python function | |
257 | print '%d: 0x%016x : 0x%015x %s%d' % (self.strand.strand_id,va,pa,op,size),data | |
258 | ||
259 | ||
260 | TLB_INSERT = 1 | |
261 | TLB_REMOVE = 2 | |
262 | ||
263 | def tlb_update(self,on=None): | |
264 | """ | |
265 | 0 - tlb update traceing disable | |
266 | 1 - tlb insert traceing enable | |
267 | 2 - tlb remove traceing enable | |
268 | 3 - tlb update traceing enable | |
269 | """ | |
270 | if on == None: | |
271 | return self.opt_tlb_update | |
272 | elif type(on) == bool: | |
273 | self.opt_tlb_update = self.TLB_INSERT | self.TLB_REMOVE | |
274 | elif type(on) == int: | |
275 | self.opt_tlb_update = on | |
276 | else: | |
277 | raise TypeError | |
278 | if (self.opt_tlb_update & (self.TLB_INSERT | self.TLB_REMOVE)) != 0: | |
279 | self.__tracer__.set_tlb_update(self.trc_tlb_update) | |
280 | else: | |
281 | self.__tracer__.clr_tlb_update() | |
282 | self.set_tracer() | |
283 | ||
284 | def trc_tlb__fun__(self,tte): | |
285 | return tte | |
286 | ||
287 | def trc_tlb_update(self,insert,tlb,index,tte): | |
288 | tte = Pfe_Tlb.TlbTte(None,self.trc_tlb__fun__,self.__vonk__.ss_tte(tte)) | |
289 | ss_tlb = self.__vonk__.ss_tlb(tlb) | |
290 | ||
291 | if not ss_tlb.is_inst_tlb(): | |
292 | type = 'tlb.d%02x' % ss_tlb.tlb_id() | |
293 | elif not ss_tlb.is_data_tlb(): | |
294 | type = 'tlb.i%02x' % ss_tlb.tlb_id() | |
295 | else: | |
296 | type = 'tlb.u%02x' % ss_tlb.tlb_id() | |
297 | ||
298 | if insert == 1: | |
299 | if (self.opt_tlb_update & self.TLB_INSERT) != 0: | |
300 | print "%s: insert %03x: %s" % (type,index,str(tte)) | |
301 | else: | |
302 | if (self.opt_tlb_update & self.TLB_REMOVE) != 0: | |
303 | print "%s: remove %03x: %s" % (type,index,str(tte)) | |
304 | ||
305 | ||
306 | class Strand(Pfe_Strand.Strand): | |
307 | __first_strand__ = True | |
308 | ||
309 | def __init__(self,strand,ref,vonk): | |
310 | Pfe_Strand.Strand.__init__(self,strand,ref) | |
311 | self.__dict__['__asierr__'] = vonk.SS_AsiSpace | |
312 | self.__dict__['__vonk__'] = vonk | |
313 | self.brk = BreakDict(strand,vonk) | |
314 | self.__dict__['trc'] = Tracer(self,vonk.SS_PythonTracer()) | |
315 | ||
316 | if Strand.__first_strand__: | |
317 | Strand.__first_strand__ = False | |
318 | ||
319 | __getfun__ = Pfe_Strand.Strand.__getfun__ | |
320 | __setfun__ = Pfe_Strand.Strand.__setfun__ | |
321 | ||
322 | for index in range(vonk.SS_Registers.INDEX_BEGIN,vonk.SS_Registers.INDEX_END): | |
323 | name = vonk.SS_Registers.get_name(index) | |
324 | __getfun__[name] = __getreg__(index) | |
325 | __setfun__[name] = __setreg__(index) | |
326 | ||
327 | alias = strand.get_state_name(index) | |
328 | if alias == "asi_reg": | |
329 | alias = "asi" | |
330 | if alias != 0: | |
331 | __getfun__[alias] = __getreg__(index) | |
332 | __setfun__[alias] = __setreg__(index) | |
333 | ||
334 | for index in range(vonk.SS_Registers.ALIAS_BEGIN,vonk.SS_Registers.ALIAS_END): | |
335 | name = vonk.SS_Registers.get_name(index) | |
336 | __getfun__[name] = __getreg__(index) | |
337 | __setfun__[name] = __setreg__(index) | |
338 | ||
339 | for name in __asi_va__: | |
340 | __getfun__[name] = __asi_va__[name].get | |
341 | __setfun__[name] = __asi_va__[name].set | |
342 | ||
343 | for i,g in enumerate(Pfe_Strand.Strand.__irf__[:8]): | |
344 | Pfe_Strand.GlobalStack.__getfun__[g] = __getreg_gl__(i) | |
345 | Pfe_Strand.GlobalStack.__getfun__[i] = __getreg_gl__(i) | |
346 | Pfe_Strand.GlobalStack.__setfun__[g] = __setreg_gl__(i) | |
347 | Pfe_Strand.GlobalStack.__setfun__[i] = __setreg_gl__(i) | |
348 | ||
349 | for i,w in enumerate(Pfe_Strand.Strand.__irf__[8:]): | |
350 | Pfe_Strand.WindowStack.__getfun__[w] = __getreg_wp__(i+8) | |
351 | Pfe_Strand.WindowStack.__getfun__[i+8] = __getreg_wp__(i+8) | |
352 | Pfe_Strand.WindowStack.__setfun__[w] = __setreg_wp__(i+8) | |
353 | Pfe_Strand.WindowStack.__setfun__[i+8] = __setreg_wp__(i+8) | |
354 | ||
355 | Pfe_Strand.TrapStack.__getfun__['tt'] = __getreg_tl__(vonk.SS_Registers.PR_TT) | |
356 | Pfe_Strand.TrapStack.__setfun__['tt'] = __setreg_tl__(vonk.SS_Registers.PR_TT) | |
357 | Pfe_Strand.TrapStack.__getfun__['tpc'] = __getreg_tl__(vonk.SS_Registers.PR_TPC) | |
358 | Pfe_Strand.TrapStack.__setfun__['tpc'] = __setreg_tl__(vonk.SS_Registers.PR_TPC) | |
359 | Pfe_Strand.TrapStack.__getfun__['tnpc'] = __getreg_tl__(vonk.SS_Registers.PR_TNPC) | |
360 | Pfe_Strand.TrapStack.__setfun__['tnpc'] = __setreg_tl__(vonk.SS_Registers.PR_TNPC) | |
361 | Pfe_Strand.TrapStack.__getfun__['tstate'] = __getreg_tl__(vonk.SS_Registers.PR_TSTATE) | |
362 | Pfe_Strand.TrapStack.__setfun__['tstate'] = __setreg_tl__(vonk.SS_Registers.PR_TSTATE) | |
363 | Pfe_Strand.TrapStack.__getfun__['htstate'] = __getreg_tl__(vonk.SS_Registers.HPR_HTSTATE) | |
364 | Pfe_Strand.TrapStack.__setfun__['htstate'] = __setreg_tl__(vonk.SS_Registers.HPR_HTSTATE) | |
365 | ||
366 | # default step attribute | |
367 | self.step = self.__runstep__ | |
368 | self.__listing__ = 0 | |
369 | self.trc.exe_instr(False) | |
370 | self.trc.reg_value(False) | |
371 | self.trc.trap(False) | |
372 | ||
373 | def rdasi(self,asi,va): | |
374 | data = self.__strand__.get_asi(asi,va) | |
375 | if self.__strand__.asi_error != self.__asierr__.OK: | |
376 | raise AsiStateError(asi,va) | |
377 | return data | |
378 | ||
379 | def wrasi(self,asi,va,data): | |
380 | self.__strand__.set_asi(asi,va,data) | |
381 | if self.__strand__.asi_error != self.__asierr__.OK: | |
382 | raise AsiStateError(asi,va) | |
383 | ||
384 | def set_format(self,format=None): | |
385 | if format == None: | |
386 | return self.trc.set_format(format) | |
387 | else: | |
388 | self.trc.set_format(format) | |
389 | ||
390 | def lstmode(self,on=None): | |
391 | if on == None: | |
392 | return Pfe_Strand.Strand.lstmode(self,on) | |
393 | else: | |
394 | Pfe_Strand.Strand.lstmode(self,on) | |
395 | if on == 1: | |
396 | self.trc.exe_instr(False) | |
397 | self.trc.reg_value(False) | |
398 | self.trc.trap(True) | |
399 | elif on == 2: | |
400 | self.trc.exe_instr(True) | |
401 | self.trc.reg_value(False) | |
402 | self.trc.trap(True) | |
403 | elif on == 3: | |
404 | self.trc.exe_instr(True) | |
405 | self.trc.reg_value(True) | |
406 | self.trc.trap(True) | |
407 | elif on in [91,92,93,94]: | |
408 | # on = -sas_run_args=-DPLI_DEBUG + 90 | |
409 | # set by cosim -sas_run_args=-DPLI_DEBUG option, in this case the | |
410 | # instr & delta are handled in backend, not at pfe layer. | |
411 | self.trc.exe_instr(False) | |
412 | self.trc.reg_value(False) | |
413 | self.trc.trap(True) | |
414 | else: | |
415 | self.trc.exe_instr(False) | |
416 | self.trc.reg_value(False) | |
417 | self.trc.trap(False) | |
418 | ||
419 | def __runstep__(self,n=None): | |
420 | if n == None: | |
421 | n = 1 | |
422 | n = self.__strand__.run_step(n) | |
423 | if n: | |
424 | id = self.brk.hit_id() | |
425 | if id == None: | |
426 | pass # flush break loop for flush broadcast sync | |
427 | elif self.brk.callback[id] == None: | |
428 | print self.ref+': Stopped at pc='+hex(self.pc)+': '+str(self.brk.hit_bp()) | |
429 | else: | |
430 | self.brk.callback[id](self) | |
431 | return n | |
432 | return 0 | |
433 | ||
434 | def __lststep__(self,n=None): | |
435 | if n == None: | |
436 | n = 1 | |
437 | while n > 0: | |
438 | n = self.__strand__.trc_step(n) | |
439 | if n: | |
440 | id = self.brk.hit_id() | |
441 | if id == None: | |
442 | pass # flush break loop for flush broadcast sync | |
443 | elif self.brk.callback[id] == None: | |
444 | print self.ref+': Stopped at pc='+hex(self.pc)+': '+str(self.brk.hit_bp()) | |
445 | else: | |
446 | self.brk.callback[id](self) | |
447 | return n | |
448 | return 0 | |
449 | ||
450 | def va2pa(self,va,ctx=None,pid=None): | |
451 | if ctx == None: | |
452 | return self.__strand__.va2pa(va) | |
453 | elif pid == None: | |
454 | return self.__strand__.va2pa(va,ctx) | |
455 | else: | |
456 | return self.__strand__.va2pa(va,ctx,pid) | |
457 | ||
458 | def ra2pa(self,ra,pid=None): | |
459 | if pid == None: | |
460 | return self.__strand__.ra2pa(ra) | |
461 | else: | |
462 | return self.__strand__.ra2pa(ra,pid) | |
463 | ||
464 | def icache_info(self,pa): | |
465 | print self.__strand__.icache_info(pa) | |
466 | return 0 | |
467 | ||
468 | def icache_set(self,set): | |
469 | print self.__strand__.icache_set(set) | |
470 | return 0 | |
471 | ||
472 | def dcache_set(self,set): | |
473 | print self.__strand__.dcache_set(set) | |
474 | return 0 | |
475 | ||
476 | def l2cache_set(self,set): | |
477 | print self.__strand__.l2cache_set(set) | |
478 | return 0 | |
479 |