Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | # ========== Copyright Header Begin ========================================== |
2 | # | |
3 | # OpenSPARC T2 Processor File: RunScript.py | |
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 | # A collection of functions that help display executed instructions and | |
23 | # collect informaiton leading to a specified breakpoint. | |
24 | # Use execfile('RunScript.py') to load this module into samfe python | |
25 | # environment. This script is valid only when the samfe is in python mode, | |
26 | # it cannot be used in line-oriented command mode. When in line-oriented | |
27 | # command mode, use 'pym' command to enter python mode. Use 'pym_off()' in | |
28 | # python mode to switch back to line-oriented command mode. | |
29 | # | |
30 | ||
31 | # available functions at the SAM UI: | |
32 | # python showi() | |
33 | # python runshow() | |
34 | # python runbreak() | |
35 | # python runbreak2() | |
36 | # python runforever() | |
37 | # python allpc() | |
38 | ||
39 | print 'loading RunScript...' | |
40 | ||
41 | import os, sys | |
42 | import sam | |
43 | ||
44 | # change this as needed | |
45 | try: | |
46 | import Rk_Python | |
47 | except: | |
48 | print 'need to import proper XX_Python module' | |
49 | sys.exit(1) | |
50 | ||
51 | ||
52 | symbol_table_filename = 'symbol.tbl' | |
53 | symbol_table = None | |
54 | ||
55 | if os.path.exists(symbol_table_filename): | |
56 | try: | |
57 | import Pfe_SymbolTbl | |
58 | symbol_table = Pfe_SymbolTbl.Pfe_SymbolTbl() | |
59 | except: | |
60 | symbol_table = None | |
61 | ||
62 | # global instruction count | |
63 | icount = 0L | |
64 | ||
65 | def disassemble(sid,va): | |
66 | paddr = sim.s[sid].va2pa(va) | |
67 | if paddr == 0: | |
68 | paddr = sim.s[sid].ra2pa(va) | |
69 | if paddr == 0: | |
70 | paddr = va & 0xffffffffffff | |
71 | iword = sim.mem.w[paddr] | |
72 | return '[%08x] %s' % (iword, Rk_Python.dis(iword,0x0)) | |
73 | ||
74 | ||
75 | # | |
76 | # show the latest executed instruction. If the execution is continuing at | |
77 | # the background, we may not get the pc & instrWord of the same execution, | |
78 | # because we access pc and instrWord in two function calls, so there is a | |
79 | # possibility that the values are not matched. In other case, if a va is | |
80 | # provided, we will need to translate that into pa, which can be tricky, as | |
81 | # the execution may be at a different state, which may affect the va->pa | |
82 | # translation. | |
83 | # | |
84 | def showi(sid=0,va=0): | |
85 | """ | |
86 | sid: strand id, default is 0 | |
87 | """ | |
88 | # if va=0, use the instruction to be executed next, otherwise use the | |
89 | # provided va to access the instruction word and disassemble it. | |
90 | if va == 0: | |
91 | instr = disassemble(sid, sim.s[sid].pc) | |
92 | print 'sid=%d, pc=%#x, %s' % (sid, sim.s[sid].pc, instr) | |
93 | else: | |
94 | instr = disassemble(sid, va) | |
95 | print 'sid=%d, pc=%#x, %s' % (sid, va, instr) | |
96 | ||
97 | # | |
98 | # if there are breakpoints set up by "break" command, hitting one of those | |
99 | # breakpoints will terminate runshow(), runbreak(), or runbreak2() function | |
100 | # and return control to UI prompt. The breakpoints list specified in runbreak() | |
101 | # or runbreak2() function will have the same effect on execution. | |
102 | # | |
103 | ||
104 | # execute instructions and display executed instructions along the way | |
105 | # e.g., "runshow(100,1)" will run 100 instructions on strand1 and display | |
106 | # every instruction executed. | |
107 | # | |
108 | def runshow(step=1,sid=0,fd=sys.stdout,sym=1): | |
109 | """ | |
110 | step: number of instruction to be executed, default is 1 | |
111 | sid: strand id, default is 0 | |
112 | fd: write the output to a file descriptor, default to stdout | |
113 | sym: show (PC) symbol if available | |
114 | ||
115 | example: | |
116 | sam>>> fd1=open('0-tmp','w') | |
117 | sam>>> runshow(10,fd=fd1) | |
118 | sam>>> runshow(100,fd=fd1) | |
119 | sam>>> fd1.close() | |
120 | """ | |
121 | global icount | |
122 | global symbol_table | |
123 | prevPC = 0x0L | |
124 | newPC = 0x0L | |
125 | prevTL = 0 | |
126 | newTL = 0 | |
127 | i = 0 | |
128 | done = 0 | |
129 | while (done == 0) and (i < step): | |
130 | i += 1 | |
131 | icount += 1 | |
132 | newPC = sim.s[sid].pc | |
133 | instr = disassemble(sid, newPC) | |
134 | sam.ui_exec('stepi') | |
135 | newTL = sim.s[sid].tl | |
136 | # check for hitting breakpoint | |
137 | for s in sim.s: | |
138 | if s.brk.hit(): | |
139 | done = 1 | |
140 | break | |
141 | if done == 0: | |
142 | if (newPC != prevPC+4) or (newTL != prevTL): | |
143 | # display PC or related symbol when PC moves to a different | |
144 | # path | |
145 | if (sym == 1) and (symbol_table != None): | |
146 | fd.write('%s, TL=%d:\n' % (symbol_table.va2id(newPC), newTL)) | |
147 | else: | |
148 | fd.write('PC=%#x, TL=%d:\n' % (newPC, newTL)) | |
149 | fd.write('sid=%d, ic=%d, pc=%#x, %s\n' % (sid, icount, newPC, instr)) | |
150 | prevPC = newPC | |
151 | prevTL = newTL | |
152 | ||
153 | # | |
154 | # execute instructions and check for breakpoints along the way | |
155 | # e.g., runbreak(100,bpoints=[0x40070,0x40078,0x83400]) will run 100 | |
156 | # instructions on strand0 and display every instruction executed, if PC has a | |
157 | # hit with any value in bpoints, then the execution will stop. | |
158 | # | |
159 | def runbreak(step=1,sid=0,bpoints=[0x83400,0xfffffffff0000080L,0x00122000],fd=sys.stdout,sym=1): | |
160 | """ | |
161 | step: number of instruction to be executed, default is 1 | |
162 | sid: strand id, default is 0 | |
163 | bpoints: a list of PC breakpoints, default is empty list | |
164 | fd: output file descriptor, default to stdout | |
165 | sym: show (PC) symbol if available | |
166 | """ | |
167 | global symbol_table | |
168 | global icount | |
169 | prevPC = 0x0L | |
170 | newPC = 0x0L | |
171 | prevTL = 0 | |
172 | newTL = 0 | |
173 | i = 0 | |
174 | done = 0 | |
175 | while (done == 0) and (i < step): | |
176 | i += 1 | |
177 | icount += 1 | |
178 | newPC = sim.s[sid].pc | |
179 | instr = disassemble(sid, newPC) | |
180 | # check breakpoints | |
181 | if newPC in bpoints: | |
182 | if symbol_table != None: | |
183 | fd.write('BREAKPOINT: sid=%d, pc=%#x [%s]\n' % (sid, newPC, symbol_table.va2id(newPC))) | |
184 | else: | |
185 | fd.write('BREAKPOINT: sid=%d, pc=%#x\n' % (sid, newPC)) | |
186 | done = 1 | |
187 | else: | |
188 | # execute the next instr if no breakpoint is hit | |
189 | sam.ui_exec('stepi') | |
190 | newTL = sim.s[sid].tl | |
191 | for s in sim.s: | |
192 | if s.brk.hit(): | |
193 | done = 1 | |
194 | break | |
195 | if done == 0: | |
196 | if (newPC != prevPC+4) or (newTL != prevTL): | |
197 | # display PC or related symbol when PC moves to a | |
198 | # different path | |
199 | if (sym == 1) and (symbol_table != None): | |
200 | fd.write('%s, TL=%d:\n' % (symbol_table.va2id(newPC), newTL)) | |
201 | else: | |
202 | fd.write('PC=%#x, TL=%d:\n' % (newPC, newTL)) | |
203 | fd.write('sid=%d, ic=%d, pc=%#x, %s\n' % (sid, icount, newPC, instr)) | |
204 | prevPC = newPC | |
205 | prevTL = newTL | |
206 | ||
207 | # | |
208 | # execute instructions and check for breakpoints along the way | |
209 | # e.g., runbreak2(100,bpoints=[0x40070,0x40078,0x83400],size=50) will run | |
210 | # 100 instructions on strand0 and display every instruction executed, if PC | |
211 | # has a hit with any value in bpoints, then the execution will stop. The last | |
212 | # 'size' instructions will be kept in specified file. | |
213 | # | |
214 | def runbreak2(step=1,sid=0,bpoints=[0x83400,0xfffffffff0000080L,0x00122000],fd=sys.stdout,size=10000): | |
215 | """ | |
216 | step: number of instruction to be executed, default is 1 | |
217 | sid: strand id, default is 0 | |
218 | bpoints: a list of PC breakpoints, default is empty list | |
219 | fd: output file descriptor, default to stdout | |
220 | size: instr buffer size, the last 'size' instructions before the breakpoint | |
221 | will be written to fd | |
222 | ||
223 | example: | |
224 | sam>>> fd1=open('0-tmp','w') | |
225 | sam>>> runbreak2(10,bpoints=[0x83400],fd=fd1,size=100) | |
226 | sam>>> fd1.close() | |
227 | """ | |
228 | global symbol_table | |
229 | global icount | |
230 | buffer = { } | |
231 | index = 0 | |
232 | prevPC = 0x0L | |
233 | newPC = 0x0L | |
234 | prevTL = 0 | |
235 | newTL = 0 | |
236 | i = 0 | |
237 | done = 0 | |
238 | while (done == 0) and (i < step): | |
239 | i += 1 | |
240 | icount += 1 | |
241 | newPC = sim.s[sid].pc | |
242 | instr = disassemble(sid, newPC) | |
243 | # check breakpoints | |
244 | if newPC in bpoints: | |
245 | bs = sim.s[sid] | |
246 | done = 1 | |
247 | else: | |
248 | # execute the next instr if no breakpoint is hit | |
249 | sam.ui_exec('stepi') | |
250 | for s in sim.s: | |
251 | if s.brk.hit(): | |
252 | done = 1 | |
253 | bs = s | |
254 | break | |
255 | if done == 0: | |
256 | index = (i-1) % size | |
257 | buffer[index] = 'PC=%#x, %s' % (newPC, instr) | |
258 | # dump out buffer if hit a breakpoint | |
259 | if done == 1: | |
260 | jj = 1 | |
261 | for ii in range(index+1, size): | |
262 | if buffer.has_key(ii): | |
263 | fd.write('sid=%d, ic=%d, %s\n' % (sid, jj, buffer[ii])) | |
264 | jj += 1 | |
265 | for ii in range(0,index+1): | |
266 | if buffer.has_key(ii): | |
267 | fd.write('sid=%d, ic=%d, %s\n' % (sid, jj, buffer[ii])) | |
268 | jj += 1 | |
269 | if symbol_table != None: | |
270 | fd.write('BREAKPOINT: sid=%d, pc=%#x [%s]\n' % (bs.strand_id, bs.pc, symbol_table.va2id(bs.pc))) | |
271 | else: | |
272 | fd.write('BREAKPOINT: sid=%d, pc=%#x\n' % (bs.strand_id, bs.pc)) | |
273 | ||
274 | # | |
275 | # check PASS/FAIL at the end of an execution, and return exit code | |
276 | # accordingly. | |
277 | # | |
278 | def runforever(insts=0x7fffffffffffffff,ss=None,bout=1,va_pass=[0x122000],va_fail=[0x122020]): | |
279 | """ | |
280 | insts: number of instructions to run per strand, default is MAXINT | |
281 | ss: array of strand-ids, e.g., [0,1,2]. default is None, means all strands | |
282 | bout: upon hitting pass/fail, 1 means exit, 0 means returns to caller | |
283 | va_pass: array of 'pass' VAs, default is 0x122000 | |
284 | va_fail: array of 'fail' VAs, default is 0x122020 | |
285 | """ | |
286 | strands = [] | |
287 | if ss == None: | |
288 | # special case, step through all strands | |
289 | for s in sim.s: | |
290 | strands.append(s) | |
291 | else: | |
292 | # otherwise only step through specified strands | |
293 | for sid in ss: | |
294 | strands.append(sim.s[sid]) | |
295 | # set 'pass' breakpoints | |
296 | bp_pass = {} | |
297 | for s in strands: | |
298 | bp_pass[s.strand_id] = [] | |
299 | for va in va_pass: | |
300 | bp_pass[s.strand_id].append(s.brk.on_inst_va(va)) | |
301 | # set 'fail' breakpoints | |
302 | bp_fail = {} | |
303 | for s in strands: | |
304 | bp_fail[s.strand_id] = [] | |
305 | for va in va_fail: | |
306 | bp_fail[s.strand_id].append(s.brk.on_inst_va(va)) | |
307 | # step through strands | |
308 | sam.ui_exec('stepi %d' % insts) | |
309 | # check for pass/fail breakpoint | |
310 | for s in strands: | |
311 | bp = s.brk.hit() | |
312 | if bp: | |
313 | if bp[0] in bp_pass[s.strand_id]: | |
314 | if bout: | |
315 | sys.exit(0) | |
316 | else: | |
317 | return 0 | |
318 | elif bp[0] in bp_fail[s.strand_id]: | |
319 | if bout: | |
320 | sys.exit(1) | |
321 | else: | |
322 | return 1 | |
323 | # if nothing hit, consider it is good | |
324 | if bout: | |
325 | sys.exit(0) | |
326 | else: | |
327 | return 0 | |
328 | ||
329 | # | |
330 | # display the PC of all strands | |
331 | # | |
332 | def allpc(): | |
333 | for s in sim.s: | |
334 | print 'T%d: PC=%#x' % (s.strand_id, s.pc) | |
335 | ||
336 | ############################################################################### | |
337 | ### SAM UI workaround. Use old commands prefixed with python | |
338 | ############################################################################### | |
339 | ||
340 | def python(*args): | |
341 | try: | |
342 | exec(" ".join(args[1:])) | |
343 | except: | |
344 | print "ERROR: command is/went wrong" | |
345 | ||
346 | sam.ui_register('python','python SAM UI fixer',python) | |
347 | ||
348 | ############################################################################### | |
349 | ### python memory debugging, for developers' internal use. | |
350 | ############################################################################### | |
351 | ||
352 | import gc | |
353 | ||
354 | def gc_dbx_on(): | |
355 | """ | |
356 | """ | |
357 | gc.enable() | |
358 | gc.set_debug(gc.DEBUG_LEAK|gc.DEBUG_STATS) | |
359 | ||
360 | def gc_dbx_off(): | |
361 | """ | |
362 | """ | |
363 | gc.set_debug(0x0) | |
364 | ||
365 | def gc_dump(): | |
366 | """ | |
367 | """ | |
368 | gc.collect() | |
369 | print '\nGARBAGE OBJECTS:' | |
370 | for x in gc.garbage: | |
371 | xx = str(x) | |
372 | if len(xx) > 80: | |
373 | xx = xx[:77]+'...' | |
374 | print '%s ---> %s' % (type(x), xx) | |
375 | ||
376 |