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