|
|
1.1 ! root 1: /* ! 2: * Cisco 7200 (Predator) simulation platform. ! 3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected]) ! 4: * ! 5: * MIPS64 JIT compiler. ! 6: */ ! 7: ! 8: #include <stdio.h> ! 9: #include <stdlib.h> ! 10: #include <unistd.h> ! 11: #include <string.h> ! 12: #include <sys/types.h> ! 13: #include <sys/stat.h> ! 14: #include <sys/mman.h> ! 15: #include <signal.h> ! 16: #include <fcntl.h> ! 17: #include <assert.h> ! 18: ! 19: #include ARCH_INC_FILE ! 20: ! 21: #include "rbtree.h" ! 22: #include "cp0.h" ! 23: #include "memory.h" ! 24: #include "cpu.h" ! 25: #include "device.h" ! 26: #include "mips64_exec.h" ! 27: #include "insn_lookup.h" ! 28: #include "ptask.h" ! 29: ! 30: extern rbtree_tree *sym_tree; ! 31: ! 32: #if DEBUG_BLOCK_TIMESTAMP ! 33: static volatile m_uint64_t jit_jiffies = 0; ! 34: #endif ! 35: ! 36: /* MIPS jump instructions for block scan */ ! 37: struct insn_jump mips64_insn_jumps[] = { ! 38: { "b" , 0xffff0000, 0x10000000, 16, 1 }, ! 39: { "bal" , 0xffff0000, 0x04110000, 16, 1 }, ! 40: { "beq" , 0xfc000000, 0x10000000, 16, 1 }, ! 41: { "beql" , 0xfc000000, 0x50000000, 16, 1 }, ! 42: { "bgez" , 0xfc1f0000, 0x04010000, 16, 1 }, ! 43: { "bgezl" , 0xfc1f0000, 0x04030000, 16, 1 }, ! 44: { "bgezal" , 0xfc1f0000, 0x04110000, 16, 1 }, ! 45: { "bgezall" , 0xfc1f0000, 0x04130000, 16, 1 }, ! 46: { "bgtz" , 0xfc1f0000, 0x1c000000, 16, 1 }, ! 47: { "bgtzl" , 0xfc1f0000, 0x5c000000, 16, 1 }, ! 48: { "blez" , 0xfc1f0000, 0x18000000, 16, 1 }, ! 49: { "blezl" , 0xfc1f0000, 0x58000000, 16, 1 }, ! 50: { "bltz" , 0xfc1f0000, 0x04000000, 16, 1 }, ! 51: { "bltzl" , 0xfc1f0000, 0x04020000, 16, 1 }, ! 52: { "bltzal" , 0xfc1f0000, 0x04100000, 16, 1 }, ! 53: { "bltzall" , 0xfc1f0000, 0x04120000, 16, 1 }, ! 54: { "bne" , 0xfc000000, 0x14000000, 16, 1 }, ! 55: { "bnel" , 0xfc000000, 0x54000000, 16, 1 }, ! 56: { "j" , 0xfc000000, 0x08000000, 26, 0 }, ! 57: { NULL , 0x00000000, 0x00000000, 0, 0 }, ! 58: }; ! 59: ! 60: /* Instruction Lookup Table */ ! 61: static insn_lookup_t *ilt = NULL; ! 62: ! 63: static void *mips64_jit_get_insn(int index) ! 64: { ! 65: return(&mips64_insn_tags[index]); ! 66: } ! 67: ! 68: static int mips64_jit_chk_lo(struct insn_tag *tag,int value) ! 69: { ! 70: return((value & tag->mask) == (tag->value & 0xFFFF)); ! 71: } ! 72: ! 73: static int mips64_jit_chk_hi(struct insn_tag *tag,int value) ! 74: { ! 75: return((value & (tag->mask >> 16)) == (tag->value >> 16)); ! 76: } ! 77: ! 78: /* Initialize instruction lookup table */ ! 79: void mips64_jit_create_ilt(void) ! 80: { ! 81: int i,count; ! 82: ! 83: for(i=0,count=0;mips64_insn_tags[i].emit;i++) ! 84: count++; ! 85: ! 86: ilt = ilt_create(count, ! 87: (ilt_get_insn_cbk_t)mips64_jit_get_insn, ! 88: (ilt_check_cbk_t)mips64_jit_chk_lo, ! 89: (ilt_check_cbk_t)mips64_jit_chk_hi); ! 90: } ! 91: ! 92: /* Find the JIT code emitter for the specified MIPS instruction */ ! 93: struct insn_tag *insn_tag_find(mips_insn_t ins) ! 94: { ! 95: struct insn_tag *tag = NULL; ! 96: int index; ! 97: ! 98: index = ilt_lookup(ilt,ins); ! 99: tag = mips64_jit_get_insn(index); ! 100: return tag; ! 101: } ! 102: ! 103: /* Check if the specified MIPS instruction is a jump */ ! 104: struct insn_jump *insn_jump_find(mips_insn_t ins) ! 105: { ! 106: struct insn_jump *jump = NULL; ! 107: int i; ! 108: ! 109: for(i=0;mips64_insn_jumps[i].name;i++) ! 110: if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) { ! 111: jump = &mips64_insn_jumps[i]; ! 112: break; ! 113: } ! 114: ! 115: return(jump); ! 116: } ! 117: ! 118: /* Fetch a MIPS instruction */ ! 119: static inline mips_insn_t insn_fetch(insn_block_t *b) ! 120: { ! 121: return(vmtoh32(b->mips_code[b->mips_trans_pos])); ! 122: } ! 123: ! 124: /* Emit a breakpoint if necessary */ ! 125: static void insn_emit_breakpoint(cpu_mips_t *cpu,insn_block_t *b) ! 126: { ! 127: m_uint64_t pc; ! 128: int i; ! 129: ! 130: pc = b->start_pc+((b->mips_trans_pos-1)<<2); ! 131: ! 132: for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) ! 133: if (pc == cpu->breakpoints[i]) { ! 134: mips64_emit_breakpoint(b); ! 135: break; ! 136: } ! 137: } ! 138: ! 139: /* Fetch a MIPS instruction and emit corresponding translated code */ ! 140: struct insn_tag *insn_fetch_and_emit(cpu_mips_t *cpu,insn_block_t *block, ! 141: int delay_slot) ! 142: { ! 143: struct insn_tag *tag; ! 144: mips_insn_t code; ! 145: ! 146: code = insn_fetch(block); ! 147: tag = insn_tag_find(code); ! 148: assert(tag); ! 149: ! 150: if (delay_slot && !tag->delay_slot) { ! 151: fprintf(stderr,"%% Invalid instruction 0x%8.8x in delay slot.\n",code); ! 152: return NULL; ! 153: } ! 154: ! 155: if (!delay_slot) { ! 156: block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; ! 157: } ! 158: ! 159: if (delay_slot != 2) ! 160: block->mips_trans_pos++; ! 161: ! 162: #if BREAKPOINT_ENABLE ! 163: if (cpu->breakpoints_enabled) ! 164: insn_emit_breakpoint(cpu,block); ! 165: #endif ! 166: ! 167: mips64_inc_cp0_count_reg(block); ! 168: ! 169: if (!delay_slot) ! 170: mips64_check_pending_irq(block); ! 171: ! 172: tag->emit(cpu,block,code); ! 173: return tag; ! 174: } ! 175: ! 176: /* ! 177: * This is a special case of MIPS instruction emitting, when this fucking ! 178: * GCC compiler has been able to optimize a lot and to branch in a delay ! 179: * slot. ! 180: */ ! 181: u_char *insn_special_emit(cpu_mips_t *cpu,insn_block_t *block,m_uint64_t vaddr) ! 182: { ! 183: struct insn_tag *tag; ! 184: mips_insn_t code; ! 185: u_int offset; ! 186: u_char *cptr; ! 187: ! 188: /* the caller will patch to this address */ ! 189: cptr = block->jit_ptr; ! 190: ! 191: offset = (vaddr - block->start_pc) >> 2; ! 192: block->jit_insn_ptr[offset] = cptr; ! 193: code = vmtoh32(block->mips_code[offset]); ! 194: tag = insn_tag_find(code); ! 195: assert(tag); ! 196: ! 197: tag->emit(cpu,block,code); ! 198: mips64_set_pc(block,vaddr+4); ! 199: insn_block_push_epilog(block); ! 200: return cptr; ! 201: } ! 202: ! 203: /* Add end of JIT block */ ! 204: void insn_block_add_end(insn_block_t *b) ! 205: { ! 206: mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2)); ! 207: insn_block_push_epilog(b); ! 208: } ! 209: ! 210: /* Create a instruction block */ ! 211: insn_block_t *insn_block_create(cpu_mips_t *cpu,m_uint64_t vaddr) ! 212: { ! 213: insn_block_t *block = NULL; ! 214: ! 215: if (!(block = malloc(sizeof(*block)))) ! 216: goto error; ! 217: ! 218: memset(block,0,sizeof(*block)); ! 219: block->start_pc = vaddr; ! 220: block->jit_bufsize = MIPS_JIT_BUFSIZE; ! 221: ! 222: if (!(block->jit_buffer = malloc(block->jit_bufsize))) ! 223: goto error; ! 224: ! 225: block->jit_ptr = block->jit_buffer; ! 226: block->mips_code = cpu->mem_op_lookup(cpu,block->start_pc); ! 227: ! 228: if (!block->mips_code) { ! 229: fprintf(stderr,"%% No memory map for code execution at 0x%llx\n", ! 230: block->start_pc); ! 231: goto error; ! 232: } ! 233: ! 234: #if DEBUG_BLOCK_TIMESTAMP ! 235: block->tm_first_use = block->tm_last_use = jit_jiffies; ! 236: #endif ! 237: return block; ! 238: ! 239: error: ! 240: free(block); ! 241: fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n", ! 242: vaddr); ! 243: return NULL; ! 244: } ! 245: ! 246: /* Record a patch to apply in a compiled block */ ! 247: int insn_block_record_patch(insn_block_t *block,u_char *jit_ptr, ! 248: m_uint64_t vaddr) ! 249: { ! 250: struct insn_patch_table *ipt = block->patch_table; ! 251: struct insn_patch *patch; ! 252: ! 253: /* pc must be 32-bit aligned */ ! 254: if (vaddr & 0x03) { ! 255: fprintf(stderr,"Block 0x%8.8llx: trying to record an invalid PC " ! 256: "(0x%8.8llx) - mips_trans_pos=%d.\n", ! 257: block->start_pc,vaddr,block->mips_trans_pos); ! 258: return(-1); ! 259: } ! 260: ! 261: if (!ipt || (ipt->cur_patch >= INSN_PATCH_TABLE_SIZE)) ! 262: { ! 263: /* full table or no table, create a new one */ ! 264: ipt = malloc(sizeof(*ipt)); ! 265: if (!ipt) { ! 266: fprintf(stderr,"%% Unable to create patch table.\n"); ! 267: return(-1); ! 268: } ! 269: ! 270: memset(ipt,0,sizeof(*ipt)); ! 271: ipt->next = block->patch_table; ! 272: block->patch_table = ipt; ! 273: } ! 274: ! 275: #if DEBUG_BLOCK_PATCH ! 276: printf("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], " ! 277: "MTP=%d\n",block->start_pc,jit_ptr,vaddr,block->mips_trans_pos); ! 278: #endif ! 279: ! 280: patch = &ipt->patches[ipt->cur_patch]; ! 281: patch->jit_insn = jit_ptr; ! 282: patch->mips_pc = vaddr; ! 283: ipt->cur_patch++; ! 284: return(0); ! 285: } ! 286: ! 287: /* Apply all patches */ ! 288: int insn_block_apply_patches(cpu_mips_t *cpu,insn_block_t *block) ! 289: { ! 290: struct insn_patch_table *ipt; ! 291: struct insn_patch *patch; ! 292: u_char *jit_dst; ! 293: int i; ! 294: ! 295: for(ipt=block->patch_table;ipt;ipt=ipt->next) ! 296: for(i=0;i<ipt->cur_patch;i++) ! 297: { ! 298: patch = &ipt->patches[i]; ! 299: jit_dst = insn_block_get_jit_ptr(block,patch->mips_pc); ! 300: ! 301: if (!jit_dst) { ! 302: #if DEBUG_BLOCK_PATCH ! 303: printf("Block 0x%8.8llx: trying to apply a null patch " ! 304: "(PC=0x%llx)\n", ! 305: block->start_pc,patch->mips_pc); ! 306: #endif ! 307: jit_dst = insn_special_emit(cpu,block,patch->mips_pc); ! 308: } ! 309: ! 310: insn_block_set_patch(patch->jit_insn,jit_dst); ! 311: ! 312: #if DEBUG_BLOCK_PATCH ! 313: printf("Block 0x%8.8llx: applying patch " ! 314: "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n", ! 315: block->start_pc,patch->jit_insn,patch->mips_pc,jit_dst); ! 316: #endif ! 317: } ! 318: ! 319: return(0); ! 320: } ! 321: ! 322: /* Adjust the JIT buffer if its size is not sufficient */ ! 323: int insn_block_adjust_jit_buffer(insn_block_t *block) ! 324: { ! 325: u_char *new_ptr; ! 326: ! 327: if ((block->jit_ptr - block->jit_buffer) <= (block->jit_bufsize - 512)) ! 328: return(0); ! 329: ! 330: #if DEBUG_BLOCK_CHUNK ! 331: printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc); ! 332: #endif ! 333: ! 334: if (block->jit_chunk_pos >= INSN_MAX_CHUNKS) { ! 335: fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc); ! 336: return(-1); ! 337: } ! 338: ! 339: /* save the current JIT block */ ! 340: block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer; ! 341: ! 342: if (!(new_ptr = malloc(block->jit_bufsize))) ! 343: return(-1); ! 344: ! 345: /* jump to the new block */ ! 346: insn_block_set_jump(block->jit_ptr,new_ptr); ! 347: block->jit_ptr = block->jit_buffer = new_ptr; ! 348: return(0); ! 349: } ! 350: ! 351: /* Scan an instruction block to determine its length */ ! 352: int insn_block_scan(insn_block_t *block) ! 353: { ! 354: struct insn_jump *jump; ! 355: m_uint64_t cur_pc,last_jrra_pc; ! 356: m_uint64_t next_pc,max_next_pc; ! 357: m_int64_t offset; ! 358: mips_insn_t code; ! 359: size_t len; ! 360: ! 361: last_jrra_pc = max_next_pc = 0; ! 362: ! 363: for(block->mips_code_len = 0, cur_pc = block->start_pc; ! 364: block->mips_code_len < MIPS_MAX_BLOCK_INSN; ! 365: block->mips_code_len++, cur_pc += 4) ! 366: { ! 367: code = vmtoh32(block->mips_code[block->mips_code_len]); ! 368: ! 369: #if DEBUG_BLOCK_SCAN ! 370: printf("insn_block_scan: cur_pc = 0x%llx, instruction = 0x%8.8x\n", ! 371: cur_pc,code); ! 372: #endif ! 373: ! 374: /* jr ra = jump to return address */ ! 375: if (code == MIPS_INSN_JR_RA) { ! 376: last_jrra_pc = cur_pc; ! 377: ! 378: if (last_jrra_pc >= max_next_pc) { ! 379: block->mips_code_len++; /* account delay slot */ ! 380: break; ! 381: } ! 382: ! 383: continue; ! 384: } ! 385: ! 386: /* check if we have a jump instruction */ ! 387: if (!(jump = insn_jump_find(code))) ! 388: continue; ! 389: ! 390: #if DEBUG_BLOCK_SCAN ! 391: printf("insn_block_scan: jump \"%s\" detected (max_next_pc=0x%llx)\n", ! 392: jump->name, max_next_pc); ! 393: #endif ! 394: ! 395: /* we have a jump, compute next pc */ ! 396: offset = (code & ((1 << jump->offset_bits) - 1)) << 2; ! 397: ! 398: if (jump->relative) { ! 399: next_pc = cur_pc + 4 + sign_extend(offset,jump->offset_bits+2); ! 400: } else { ! 401: next_pc = (cur_pc & ~((1 << (jump->offset_bits + 2)) - 1)) | offset; ! 402: } ! 403: ! 404: if (next_pc > max_next_pc) ! 405: max_next_pc = next_pc; ! 406: ! 407: #if DEBUG_BLOCK_SCAN ! 408: printf("insn_block_scan: next_pc=0x%llx, max_next_pc=0x%llx\n", ! 409: next_pc,max_next_pc); ! 410: #endif ! 411: } ! 412: ! 413: block->mips_code_len++; ! 414: block->end_pc = block->start_pc + (block->mips_code_len * 4); ! 415: ! 416: len = block->mips_code_len * sizeof(u_char *); ! 417: ! 418: if (!(block->jit_insn_ptr = malloc(len))) { ! 419: fprintf(stderr,"insn_block_scan: unable to create JIT/mips mapping.\n"); ! 420: return(-1); ! 421: } ! 422: ! 423: memset(block->jit_insn_ptr,0,len); ! 424: ! 425: #if DEBUG_BLOCK_SCAN ! 426: printf("insn_block_scan: start_pc = 0x%llx, end_pc = 0x%llx\n", ! 427: block->start_pc, block->end_pc); ! 428: #endif ! 429: ! 430: return(0); ! 431: } ! 432: ! 433: /* Compile a MIPS instruction block */ ! 434: static inline int insn_block_compile(cpu_mips_t *cpu,insn_block_t *block) ! 435: { ! 436: struct insn_tag *tag; ! 437: ! 438: block->mips_trans_pos = 0; ! 439: ! 440: while(block->mips_trans_pos < block->mips_code_len) ! 441: { ! 442: if (!(tag = insn_fetch_and_emit(cpu,block,0))) ! 443: return(-1); ! 444: ! 445: #if DEBUG_BLOCK_COMPILE ! 446: printf("Block 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n", ! 447: block->start_pc,tag->mask,tag->value); ! 448: #endif ! 449: ! 450: insn_block_adjust_jit_buffer(block); ! 451: } ! 452: ! 453: insn_block_add_end(block); ! 454: insn_block_apply_patches(cpu,block); ! 455: return(0); ! 456: } ! 457: ! 458: /* Compile a MIPS instruction block */ ! 459: static insn_block_t *insn_block_scan_and_compile(cpu_mips_t *cpu, ! 460: m_uint64_t vaddr) ! 461: { ! 462: insn_block_t *block; ! 463: ! 464: if (!(block = insn_block_create(cpu,vaddr))) ! 465: return NULL; ! 466: ! 467: if ((insn_block_scan(block) == -1) || (insn_block_compile(cpu,block) == -1)) ! 468: return NULL; ! 469: ! 470: rbtree_insert(cpu->insn_block_tree,block,block); ! 471: return block; ! 472: } ! 473: ! 474: /* Run a compiled MIPS instruction block */ ! 475: static inline void insn_block_run(cpu_mips_t *cpu,insn_block_t *block) ! 476: { ! 477: #if DEBUG_SYM_TREE ! 478: struct symbol *sym = NULL; ! 479: int mark = FALSE; ! 480: #endif ! 481: ! 482: if (unlikely(cpu->pc & 0x03)) { ! 483: fprintf(stderr,"insn_block_run: Invalid PC 0x%llx.\n",cpu->pc); ! 484: mips64_dump_regs(cpu); ! 485: tlb_dump(cpu); ! 486: exit(EXIT_FAILURE); ! 487: } ! 488: ! 489: #if DEBUG_SYM_TREE ! 490: if (sym_tree) ! 491: { ! 492: if ((sym = sym_lookup(cpu->pc)) != NULL) { ! 493: fprintf(log_file, ! 494: "function_run: %s (PC=0x%llx) " ! 495: "RA = 0x%llx\na0=0x%llx, " ! 496: "a1=0x%llx, a2=0x%llx, a3=0x%llx\n", ! 497: sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA], ! 498: cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], ! 499: cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]); ! 500: mark = TRUE; ! 501: } ! 502: } ! 503: #endif ! 504: ! 505: #if DEBUG_INSN_ITRACE ! 506: if (insn_itrace) { ! 507: fprintf(log_file, ! 508: "block_run(S): PC = 0x%llx [start_pc=0x%llx,end_pc=0x%llx] " ! 509: "RA = 0x%llx\na0=0x%llx, a1=0x%llx, a2=0x%llx, a3=0x%llx\n", ! 510: cpu->pc,block->start_pc,block->end_pc, ! 511: cpu->gpr[MIPS_GPR_RA], ! 512: cpu->gpr[MIPS_GPR_A0], ! 513: cpu->gpr[MIPS_GPR_A1], ! 514: cpu->gpr[MIPS_GPR_A2], ! 515: cpu->gpr[MIPS_GPR_A3]); ! 516: } ! 517: #endif ! 518: ! 519: /* Execute JIT compiled code */ ! 520: insn_block_exec_jit_code(cpu,block); ! 521: ! 522: #if DEBUG_SYM_TREE ! 523: if (mark) { ! 524: fprintf(log_file,"function_end: %s, v0 = 0x%llx\n", ! 525: sym->name,cpu->gpr[MIPS_GPR_V0]); ! 526: } ! 527: #endif ! 528: ! 529: #if DEBUG_INSN_ITRACE ! 530: if (insn_itrace) { ! 531: fprintf(log_file,"block_run(E): PC = 0x%llx, v0 = 0x%llx\n", ! 532: cpu->pc, cpu->gpr[MIPS_GPR_V0]); ! 533: } ! 534: #endif ! 535: } ! 536: ! 537: /* Tree comparison function */ ! 538: int insn_block_cmp(m_uint64_t *vaddr,insn_block_t *b) ! 539: { ! 540: if (*vaddr < b->start_pc) ! 541: return(-1); ! 542: ! 543: if (*vaddr >= b->end_pc) ! 544: return(1); ! 545: ! 546: return(0); ! 547: } ! 548: ! 549: /* Check if the specified address belongs to the specified block */ ! 550: int insn_block_local_addr(insn_block_t *block,m_uint64_t vaddr, ! 551: u_char **jit_addr) ! 552: { ! 553: if ((vaddr >= block->start_pc) && (vaddr < block->end_pc)) { ! 554: *jit_addr = insn_block_get_jit_ptr(block,vaddr); ! 555: return(1); ! 556: } ! 557: return(0); ! 558: } ! 559: ! 560: /* Execute a compiled MIPS code */ ! 561: void *insn_block_execute(cpu_mips_t *cpu) ! 562: { ! 563: insn_block_t *block; ! 564: ! 565: start_cpu: ! 566: for(;;) { ! 567: if (unlikely(!cpu->pc) || unlikely(cpu->state != MIPS_CPU_RUNNING)) ! 568: break; ! 569: ! 570: block = insn_block_locate_fast(cpu,cpu->pc); ! 571: ! 572: if (!block) { ! 573: block = insn_block_scan_and_compile(cpu,cpu->pc); ! 574: if (unlikely(!block)) { ! 575: cpu->pc = 0; ! 576: break; ! 577: } ! 578: } ! 579: ! 580: #if DEBUG_BLOCK_TIMESTAMP ! 581: block->tm_last_use = jit_jiffies++; ! 582: #endif ! 583: block->acc_count++; ! 584: insn_block_run(cpu,block); ! 585: } ! 586: ! 587: if (!cpu->pc) { ! 588: cpu_stop(cpu); ! 589: m_log("CPU","CPU%u has PC=0, halting CPU.\n",cpu->id); ! 590: } ! 591: ! 592: /* check regularly if the CPU has been restarted */ ! 593: do { ! 594: if (cpu->state == MIPS_CPU_RUNNING) ! 595: goto start_cpu; ! 596: ! 597: usleep(200000); ! 598: }while(1); ! 599: ! 600: return NULL; ! 601: } ! 602: ! 603: /* Dump an instruction block */ ! 604: void insn_block_dump_tree_node(insn_block_t *b,void *empty,m_tmcnt_t *ct) ! 605: { ! 606: #if DEBUG_BLOCK_TIMESTAMP ! 607: m_uint64_t deltaT = jit_jiffies - b->tm_last_use; ! 608: ! 609: m_log("RBTREE","Block 0x%llx (end=0x%llx): count=%10llu, deltaT=%12llu\n", ! 610: b->start_pc,b->end_pc,b->acc_count,deltaT); ! 611: #else ! 612: m_log("RBTREE","Block 0x%llx (end=0x%llx): count=%llu\n", ! 613: b->start_pc,b->end_pc,b->acc_count); ! 614: #endif ! 615: } ! 616: ! 617: /* Dump the instruction block tree */ ! 618: void insn_block_dump_tree(cpu_mips_t *cpu) ! 619: { ! 620: m_log("RBTREE","Height: %d\n",rbtree_height(cpu->insn_block_tree)); ! 621: ! 622: rbtree_foreach(cpu->insn_block_tree, ! 623: (tree_fforeach)insn_block_dump_tree_node, ! 624: NULL); ! 625: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.