/[dynamips]/trunk/mips64_jit.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/mips64_jit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 22134 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
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 "sbox.h"
20 #include "cpu.h"
21 #include "device.h"
22 #include "mips64.h"
23 #include "mips64_cp0.h"
24 #include "mips64_exec.h"
25 #include "mips64_jit.h"
26 #include "insn_lookup.h"
27 #include "memory.h"
28 #include "ptask.h"
29
30 #include MIPS64_ARCH_INC_FILE
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 mips64_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 mips64_insn_tag *tag,int value)
69 {
70 return((value & tag->mask) == (tag->value & 0xFFFF));
71 }
72
73 static int mips64_jit_chk_hi(struct mips64_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("mips64j",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 /* Initialize the JIT structure */
93 int mips64_jit_init(cpu_mips_t *cpu)
94 {
95 insn_exec_page_t *cp;
96 u_char *cp_addr;
97 u_int area_size;
98 size_t len;
99 int i;
100
101 /* Physical mapping for executable pages */
102 len = MIPS_JIT_PC_HASH_SIZE * sizeof(void *);
103 cpu->exec_blk_map = m_memalign(4096,len);
104 memset(cpu->exec_blk_map,0,len);
105
106 /* Get area size */
107 if (!(area_size = cpu->vm->exec_area_size))
108 area_size = MIPS_EXEC_AREA_SIZE;
109
110 /* Create executable page area */
111 cpu->exec_page_area_size = area_size * 1048576;
112 cpu->exec_page_area = mmap(NULL,cpu->exec_page_area_size,
113 PROT_EXEC|PROT_READ|PROT_WRITE,
114 MAP_SHARED|MAP_ANONYMOUS,-1,(off_t)0);
115
116 if (!cpu->exec_page_area) {
117 fprintf(stderr,
118 "mips64_jit_init: unable to create exec area (size %lu)\n",
119 (u_long)cpu->exec_page_area_size);
120 return(-1);
121 }
122
123 /* Carve the executable page area */
124 cpu->exec_page_count = cpu->exec_page_area_size / MIPS_JIT_BUFSIZE;
125
126 cpu->exec_page_array = calloc(cpu->exec_page_count,
127 sizeof(insn_exec_page_t));
128
129 if (!cpu->exec_page_array) {
130 fprintf(stderr,"mips64_jit_init: unable to create exec page array\n");
131 return(-1);
132 }
133
134 for(i=0,cp_addr=cpu->exec_page_area;i<cpu->exec_page_count;i++) {
135 cp = &cpu->exec_page_array[i];
136
137 cp->ptr = cp_addr;
138 cp_addr += MIPS_JIT_BUFSIZE;
139
140 cp->next = cpu->exec_page_free_list;
141 cpu->exec_page_free_list = cp;
142 }
143
144 printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n",
145 cpu->gen->id,
146 (u_long)(cpu->exec_page_area_size / 1048576),
147 (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024);
148 return(0);
149 }
150
151 /* Flush the JIT */
152 u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold)
153 {
154 mips64_jit_tcb_t *p,*next;
155 m_uint32_t pc_hash;
156 u_int count = 0;
157
158 if (!threshold)
159 threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */
160
161 for(p=cpu->tcb_list;p;p=next) {
162 next = p->next;
163
164 if (p->acc_count <= threshold) {
165 pc_hash = mips64_jit_get_pc_hash(p->start_pc);
166 cpu->exec_blk_map[pc_hash] = NULL;
167 mips64_jit_tcb_free(cpu,p,TRUE);
168 count++;
169 }
170 }
171
172 cpu->compiled_pages -= count;
173 return(count);
174 }
175
176 /* Shutdown the JIT */
177 void mips64_jit_shutdown(cpu_mips_t *cpu)
178 {
179 mips64_jit_tcb_t *p,*next;
180
181 /* Flush the JIT */
182 mips64_jit_flush(cpu,0);
183
184 /* Free the instruction blocks */
185 for(p=cpu->tcb_free_list;p;p=next) {
186 next = p->next;
187 free(p);
188 }
189
190 /* Unmap the executable page area */
191 if (cpu->exec_page_area)
192 munmap(cpu->exec_page_area,cpu->exec_page_area_size);
193
194 /* Free the exec page array */
195 free(cpu->exec_page_array);
196
197 /* Free physical mapping for executable pages */
198 free(cpu->exec_blk_map);
199 }
200
201 /* Allocate an exec page */
202 static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu)
203 {
204 insn_exec_page_t *p;
205 u_int count;
206
207 /* If the free list is empty, flush JIT */
208 if (unlikely(!cpu->exec_page_free_list))
209 {
210 if (cpu->jit_flush_method) {
211 cpu_log(cpu->gen,
212 "JIT","flushing data structures (compiled pages=%u)\n",
213 cpu->compiled_pages);
214 mips64_jit_flush(cpu,0);
215 } else {
216 count = mips64_jit_flush(cpu,100);
217 cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count);
218
219 if (!cpu->exec_page_free_list)
220 mips64_jit_flush(cpu,0);
221 }
222
223 /* Use both methods alternatively */
224 cpu->jit_flush_method = 1 - cpu->jit_flush_method;
225 }
226
227 if (unlikely(!(p = cpu->exec_page_free_list)))
228 return NULL;
229
230 cpu->exec_page_free_list = p->next;
231 cpu->exec_page_alloc++;
232 return p;
233 }
234
235 /* Free an exec page and returns it to the pool */
236 static inline void exec_page_free(cpu_mips_t *cpu,insn_exec_page_t *p)
237 {
238 if (p) {
239 p->next = cpu->exec_page_free_list;
240 cpu->exec_page_free_list = p;
241 cpu->exec_page_alloc--;
242 }
243 }
244
245 /* Find the JIT code emitter for the specified MIPS instruction */
246 static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins)
247 {
248 struct mips64_insn_tag *tag = NULL;
249 int index;
250
251 index = ilt_lookup(ilt,ins);
252 tag = mips64_jit_get_insn(index);
253 return tag;
254 }
255
256 /* Check if the specified MIPS instruction is a jump */
257 static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins)
258 {
259 struct mips64_insn_jump *jump = NULL;
260 int i;
261
262 for(i=0;mips64_insn_jumps[i].name;i++)
263 if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) {
264 jump = &mips64_insn_jumps[i];
265 break;
266 }
267
268 return(jump);
269 }
270
271 /* Fetch a MIPS instruction */
272 static forced_inline mips_insn_t insn_fetch(mips64_jit_tcb_t *b)
273 {
274 return(vmtoh32(b->mips_code[b->mips_trans_pos]));
275 }
276
277 /* Emit a breakpoint if necessary */
278 #if BREAKPOINT_ENABLE
279 static void insn_emit_breakpoint(cpu_mips_t *cpu,mips64_jit_tcb_t *b)
280 {
281 m_uint64_t pc;
282 int i;
283
284 pc = b->start_pc+((b->mips_trans_pos-1)<<2);
285
286 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
287 if (pc == cpu->breakpoints[i]) {
288 mips64_emit_breakpoint(b);
289 break;
290 }
291 }
292 #endif /* BREAKPOINT_ENABLE */
293
294 /* Get host pointer for the physical address */
295 static inline void *physmem_get_hptr(vm_instance_t *vm,m_uint64_t paddr,
296 u_int op_size,u_int op_type,
297 m_uint64_t *data)
298 {
299 struct vdevice *dev;
300 m_uint32_t offset;
301 void *ptr;
302 int cow;
303
304 if (!(dev = dev_lookup(vm,paddr,FALSE)))
305 return NULL;
306
307 if (dev->flags & VDEVICE_FLAG_SPARSE) {
308 ptr = (void *)dev_sparse_get_host_addr(vm,dev,paddr,op_type,&cow);
309 if (!ptr) return NULL;
310
311 return(ptr + (paddr & VM_PAGE_IMASK));
312 }
313
314 if ((dev->host_addr != 0) && !(dev->flags & VDEVICE_FLAG_NO_MTS_MMAP))
315 return((void *)dev->host_addr + (paddr - dev->phys_addr));
316
317 if (op_size == 0)
318 return NULL;
319
320 offset = paddr - dev->phys_addr;
321 return(dev->handler(vm->boot_cpu,dev,offset,op_size,op_type,data));
322 }
323
324 /* Check if an instruction is in a delay slot or not */
325 int mips64_jit_is_delay_slot(mips64_jit_tcb_t *b,m_uint64_t pc)
326 {
327 struct mips64_insn_tag *tag;
328 m_uint32_t offset,insn;
329
330 offset = (pc - b->start_pc) >> 2;
331
332 if (!offset)
333 return(FALSE);
334
335 /* Fetch the previous instruction to determine if it is a jump */
336 insn = vmtoh32(b->mips_code[offset-1]);
337 tag = insn_tag_find(insn);
338 assert(tag != NULL);
339 return(!tag->delay_slot);
340 }
341
342 /* Fetch a MIPS instruction and emit corresponding translated code */
343 struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu,
344 mips64_jit_tcb_t *block,
345 int delay_slot)
346 {
347 struct mips64_insn_tag *tag;
348 mips_insn_t code;
349
350 code = insn_fetch(block);
351 tag = insn_tag_find(code);
352 assert(tag);
353
354 /* Branch-delay slot is in another page: slow exec */
355 if ((block->mips_trans_pos == (MIPS_INSN_PER_PAGE-1)) && !tag->delay_slot) {
356 block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr;
357
358 mips64_set_pc(block,block->start_pc + (block->mips_trans_pos << 2));
359 mips64_emit_single_step(block,code);
360 mips64_jit_tcb_push_epilog(block);
361 block->mips_trans_pos++;
362 return tag;
363 }
364
365 if (delay_slot && !tag->delay_slot) {
366 mips64_emit_invalid_delay_slot(block);
367 return NULL;
368 }
369
370 if (!delay_slot)
371 block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr;
372
373 if (delay_slot != 2)
374 block->mips_trans_pos++;
375
376 #if DEBUG_INSN_PERF_CNT
377 mips64_inc_perf_counter(block);
378 #endif
379
380 if (!delay_slot) {
381 /* Check for IRQs + Increment count register before jumps */
382 if (!tag->delay_slot) {
383 mips64_inc_cp0_count_reg(block);
384 mips64_check_pending_irq(block);
385 }
386 }
387
388 #if BREAKPOINT_ENABLE
389 if (cpu->breakpoints_enabled)
390 insn_emit_breakpoint(cpu,block);
391 #endif
392
393 tag->emit(cpu,block,code);
394 return tag;
395 }
396
397 /* Add end of JIT block */
398 static void mips64_jit_tcb_add_end(mips64_jit_tcb_t *b)
399 {
400 mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2));
401 mips64_jit_tcb_push_epilog(b);
402 }
403
404 /* Record a patch to apply in a compiled block */
405 int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *jit_ptr,
406 m_uint64_t vaddr)
407 {
408 struct mips64_jit_patch_table *ipt = block->patch_table;
409 struct mips64_insn_patch *patch;
410
411 /* pc must be 32-bit aligned */
412 if (vaddr & 0x03) {
413 fprintf(stderr,"Block 0x%8.8llx: trying to record an invalid PC "
414 "(0x%8.8llx) - mips_trans_pos=%d.\n",
415 block->start_pc,vaddr,block->mips_trans_pos);
416 return(-1);
417 }
418
419 if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE))
420 {
421 /* full table or no table, create a new one */
422 ipt = malloc(sizeof(*ipt));
423 if (!ipt) {
424 fprintf(stderr,"Block 0x%8.8llx: unable to create patch table.\n",
425 block->start_pc);
426 return(-1);
427 }
428
429 memset(ipt,0,sizeof(*ipt));
430 ipt->next = block->patch_table;
431 block->patch_table = ipt;
432 }
433
434 #if DEBUG_BLOCK_PATCH
435 printf("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], "
436 "MTP=%d\n",block->start_pc,jit_ptr,vaddr,block->mips_trans_pos);
437 #endif
438
439 patch = &ipt->patches[ipt->cur_patch];
440 patch->jit_insn = jit_ptr;
441 patch->mips_pc = vaddr;
442 ipt->cur_patch++;
443 return(0);
444 }
445
446 /* Apply all patches */
447 static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu,
448 mips64_jit_tcb_t *block)
449 {
450 struct mips64_jit_patch_table *ipt;
451 struct mips64_insn_patch *patch;
452 u_char *jit_dst;
453 int i;
454
455 for(ipt=block->patch_table;ipt;ipt=ipt->next)
456 for(i=0;i<ipt->cur_patch;i++)
457 {
458 patch = &ipt->patches[i];
459 jit_dst = mips64_jit_tcb_get_host_ptr(block,patch->mips_pc);
460
461 if (jit_dst) {
462 #if DEBUG_BLOCK_PATCH
463 printf("Block 0x%8.8llx: applying patch "
464 "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n",
465 block->start_pc,patch->jit_insn,patch->mips_pc,jit_dst);
466 #endif
467 mips64_jit_tcb_set_patch(patch->jit_insn,jit_dst);
468 }
469 }
470
471 return(0);
472 }
473
474 /* Free the patch table */
475 static void mips64_jit_tcb_free_patches(mips64_jit_tcb_t *block)
476 {
477 struct mips64_jit_patch_table *p,*next;
478
479 for(p=block->patch_table;p;p=next) {
480 next = p->next;
481 free(p);
482 }
483
484 block->patch_table = NULL;
485 }
486
487 /* Adjust the JIT buffer if its size is not sufficient */
488 static int mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu,
489 mips64_jit_tcb_t *block)
490 {
491 insn_exec_page_t *new_buffer;
492
493 if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512))
494 return(0);
495
496 #if DEBUG_BLOCK_CHUNK
497 printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc);
498 #endif
499
500 if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) {
501 fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc);
502 return(-1);
503 }
504
505 if (!(new_buffer = exec_page_alloc(cpu)))
506 return(-1);
507
508 /* record the new exec page */
509 block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer;
510 block->jit_buffer = new_buffer;
511
512 /* jump to the new exec page (link) */
513 mips64_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr);
514 block->jit_ptr = new_buffer->ptr;
515 return(0);
516 }
517
518 /* Allocate an instruction block */
519 static inline mips64_jit_tcb_t *mips64_jit_tcb_alloc(cpu_mips_t *cpu)
520 {
521 mips64_jit_tcb_t *p;
522
523 if (cpu->tcb_free_list) {
524 p = cpu->tcb_free_list;
525 cpu->tcb_free_list = p->next;
526 } else {
527 if (!(p = malloc(sizeof(*p))))
528 return NULL;
529 }
530
531 memset(p,0,sizeof(*p));
532 return p;
533 }
534
535 /* Free an instruction block */
536 void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block,
537 int list_removal)
538 {
539 int i;
540
541 if (block) {
542 if (list_removal) {
543 /* Remove the block from the linked list */
544 if (block->next)
545 block->next->prev = block->prev;
546 else
547 cpu->tcb_last = block->prev;
548
549 if (block->prev)
550 block->prev->next = block->next;
551 else
552 cpu->tcb_list = block->next;
553 }
554
555 /* Free the patch tables */
556 mips64_jit_tcb_free_patches(block);
557
558 /* Free code pages */
559 for(i=0;i<MIPS_JIT_MAX_CHUNKS;i++)
560 exec_page_free(cpu,block->jit_chunks[i]);
561
562 /* Free the current JIT buffer */
563 exec_page_free(cpu,block->jit_buffer);
564
565 /* Free the MIPS-to-native code mapping */
566 free(block->jit_insn_ptr);
567
568 /* Make the block return to the free list */
569 block->next = cpu->tcb_free_list;
570 cpu->tcb_free_list = block;
571 }
572 }
573
574 /* Create an instruction block */
575 static mips64_jit_tcb_t *mips64_jit_tcb_create(cpu_mips_t *cpu,
576 m_uint64_t vaddr)
577 {
578 mips64_jit_tcb_t *block = NULL;
579
580 if (!(block = mips64_jit_tcb_alloc(cpu)))
581 goto err_block_alloc;
582
583 block->start_pc = vaddr;
584
585 /* Allocate the first JIT buffer */
586 if (!(block->jit_buffer = exec_page_alloc(cpu)))
587 goto err_jit_alloc;
588
589 block->jit_ptr = block->jit_buffer->ptr;
590 block->mips_code = cpu->mem_op_lookup(cpu,block->start_pc);
591
592 if (!block->mips_code) {
593 fprintf(stderr,"%% No memory map for code execution at 0x%llx\n",
594 block->start_pc);
595 goto err_lookup;
596 }
597
598 #if DEBUG_BLOCK_TIMESTAMP
599 block->tm_first_use = block->tm_last_use = jit_jiffies;
600 #endif
601 return block;
602
603 err_lookup:
604 err_jit_alloc:
605 mips64_jit_tcb_free(cpu,block,FALSE);
606 err_block_alloc:
607 fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n",
608 vaddr);
609 return NULL;
610 }
611
612 /* Compile a MIPS instruction page */
613 static inline
614 mips64_jit_tcb_t *mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr)
615 {
616 mips64_jit_tcb_t *block;
617 struct mips64_insn_tag *tag;
618 m_uint64_t page_addr;
619 size_t len;
620
621 page_addr = vaddr & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
622
623 if (unlikely(!(block = mips64_jit_tcb_create(cpu,page_addr)))) {
624 fprintf(stderr,"insn_page_compile: unable to create JIT block.\n");
625 return NULL;
626 }
627
628 /* Allocate the array used to convert MIPS code ptr to native code ptr */
629 len = MIPS_MIN_PAGE_SIZE / sizeof(mips_insn_t);
630
631 if (!(block->jit_insn_ptr = calloc(len,sizeof(u_char *)))) {
632 fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n");
633 goto error;
634 }
635
636 /* Emit native code for each instruction */
637 block->mips_trans_pos = 0;
638
639 while(block->mips_trans_pos < MIPS_INSN_PER_PAGE)
640 {
641 if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,block,0)))) {
642 fprintf(stderr,"insn_page_compile: unable to fetch instruction.\n");
643 goto error;
644 }
645
646 #if DEBUG_BLOCK_COMPILE
647 printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n",
648 block->start_pc,tag->mask,tag->value);
649 #endif
650
651 mips64_jit_tcb_adjust_buffer(cpu,block);
652 }
653
654 mips64_jit_tcb_add_end(block);
655 mips64_jit_tcb_apply_patches(cpu,block);
656 mips64_jit_tcb_free_patches(block);
657
658 /* Add the block to the linked list */
659 block->next = cpu->tcb_list;
660 block->prev = NULL;
661
662 if (cpu->tcb_list)
663 cpu->tcb_list->prev = block;
664 else
665 cpu->tcb_last = block;
666
667 cpu->tcb_list = block;
668
669 cpu->compiled_pages++;
670 return block;
671
672 error:
673 mips64_jit_tcb_free(cpu,block,FALSE);
674 return NULL;
675 }
676
677 /* Run a compiled MIPS instruction block */
678 static forced_inline
679 void mips64_jit_tcb_run(cpu_mips_t *cpu,mips64_jit_tcb_t *block)
680 {
681 #if DEBUG_SYM_TREE
682 struct symbol *sym = NULL;
683 int mark = FALSE;
684 #endif
685
686 if (unlikely(cpu->pc & 0x03)) {
687 fprintf(stderr,"mips64_jit_tcb_run: Invalid PC 0x%llx.\n",cpu->pc);
688 mips64_dump_regs(cpu->gen);
689 mips64_tlb_dump(cpu->gen);
690 cpu_stop(cpu->gen);
691 return;
692 }
693
694 #if DEBUG_SYM_TREE
695 if (cpu->sym_trace && cpu->sym_tree)
696 {
697 if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) {
698 cpu_log(cpu,"mips64_jit_tcb_run(start)",
699 "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, "
700 "a1=0x%llx, a2=0x%llx, a3=0x%llx\n",
701 sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA],
702 cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],
703 cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);
704 mark = TRUE;
705 }
706 }
707 #endif
708
709 /* Execute JIT compiled code */
710 mips64_jit_tcb_exec(cpu,block);
711
712 #if DEBUG_SYM_TREE
713 if (mark) {
714 cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n",
715 sym->name,cpu->gpr[MIPS_GPR_V0]);
716 }
717 #endif
718 }
719
720 /* Execute compiled MIPS code */
721 void *mips64_jit_run_cpu(cpu_gen_t *gen)
722 {
723 cpu_mips_t *cpu = CPU_MIPS64(gen);
724 pthread_t timer_irq_thread;
725 mips64_jit_tcb_t *block;
726 int timer_irq_check = 0;
727 m_uint32_t pc_hash;
728
729 if (pthread_create(&timer_irq_thread,NULL,
730 (void *)mips64_timer_irq_run,cpu))
731 {
732 fprintf(stderr,
733 "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
734 cpu->vm->name,gen->id);
735 cpu_stop(cpu->gen);
736 return NULL;
737 }
738
739 gen->cpu_thread_running = TRUE;
740 cpu_exec_loop_set(gen);
741
742 start_cpu:
743 gen->idle_count = 0;
744
745 for(;;) {
746 if (unlikely(gen->state != CPU_STATE_RUNNING))
747 break;
748
749 #if DEBUG_BLOCK_PERF_CNT
750 cpu->perf_counter++;
751 #endif
752 /* Handle virtual idle loop */
753 if (unlikely(cpu->pc == cpu->idle_pc)) {
754 if (++gen->idle_count == gen->idle_max) {
755 cpu_idle_loop(gen);
756 gen->idle_count = 0;
757 }
758 }
759
760 /* Handle the virtual CPU clock */
761 if (++timer_irq_check == cpu->timer_irq_check_itv) {
762 timer_irq_check = 0;
763
764 if (cpu->timer_irq_pending && !cpu->irq_disable) {
765 mips64_trigger_timer_irq(cpu);
766 mips64_trigger_irq(cpu);
767 cpu->timer_irq_pending--;
768 }
769 }
770
771 pc_hash = mips64_jit_get_pc_hash(cpu->pc);
772 block = cpu->exec_blk_map[pc_hash];
773
774 /* No block found, compile the page */
775 if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block)))
776 {
777 if (block != NULL) {
778 mips64_jit_tcb_free(cpu,block,TRUE);
779 cpu->exec_blk_map[pc_hash] = NULL;
780 }
781
782 block = mips64_jit_tcb_compile(cpu,cpu->pc);
783 if (unlikely(!block)) {
784 fprintf(stderr,
785 "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
786 cpu->vm->name,gen->id,cpu->pc);
787 cpu_stop(gen);
788 break;
789 }
790
791 cpu->exec_blk_map[pc_hash] = block;
792 }
793
794 #if DEBUG_BLOCK_TIMESTAMP
795 block->tm_last_use = jit_jiffies++;
796 #endif
797 block->acc_count++;
798 mips64_jit_tcb_run(cpu,block);
799 }
800
801 if (!cpu->pc) {
802 cpu_stop(gen);
803 cpu_log(gen,"JIT","PC=0, halting CPU.\n");
804 }
805
806 /* Check regularly if the CPU has been restarted */
807 while(gen->cpu_thread_running) {
808 gen->seq_state++;
809
810 switch(gen->state) {
811 case CPU_STATE_RUNNING:
812 gen->state = CPU_STATE_RUNNING;
813 goto start_cpu;
814
815 case CPU_STATE_HALTED:
816 gen->cpu_thread_running = FALSE;
817 pthread_join(timer_irq_thread,NULL);
818 break;
819 }
820
821 /* CPU is paused */
822 usleep(200000);
823 }
824
825 return NULL;
826 }

  ViewVC Help
Powered by ViewVC 1.1.26