1 |
/* |
/* |
2 |
* Cisco 7200 (Predator) simulation platform. |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
* |
5 |
* MIPS64 Step-by-step execution. |
* MIPS64 Step-by-step execution. |
16 |
#include <sys/mman.h> |
#include <sys/mman.h> |
17 |
#include <fcntl.h> |
#include <fcntl.h> |
18 |
|
|
|
#include "rbtree.h" |
|
|
#include "mips64.h" |
|
|
#include "dynamips.h" |
|
|
#include "vm.h" |
|
|
#include "memory.h" |
|
19 |
#include "cpu.h" |
#include "cpu.h" |
20 |
#include "cp0.h" |
#include "vm.h" |
21 |
#include "mips64_exec.h" |
#include "mips64_exec.h" |
22 |
|
#include "memory.h" |
23 |
#include "insn_lookup.h" |
#include "insn_lookup.h" |
24 |
|
#include "dynamips.h" |
25 |
|
|
26 |
/* Forward declaration of instruction array */ |
/* Forward declaration of instruction array */ |
27 |
static struct insn_exec_tag mips64_exec_tags[]; |
static struct mips64_insn_exec_tag mips64_exec_tags[]; |
28 |
static insn_lookup_t *ilt = NULL; |
static insn_lookup_t *ilt = NULL; |
29 |
|
|
30 |
/* ILT */ |
/* ILT */ |
33 |
return(&mips64_exec_tags[index]); |
return(&mips64_exec_tags[index]); |
34 |
} |
} |
35 |
|
|
36 |
static int mips64_exec_chk_lo(struct insn_exec_tag *tag,int value) |
static int mips64_exec_chk_lo(struct mips64_insn_exec_tag *tag,int value) |
37 |
{ |
{ |
38 |
return((value & tag->mask) == (tag->value & 0xFFFF)); |
return((value & tag->mask) == (tag->value & 0xFFFF)); |
39 |
} |
} |
40 |
|
|
41 |
static int mips64_exec_chk_hi(struct insn_exec_tag *tag,int value) |
static int mips64_exec_chk_hi(struct mips64_insn_exec_tag *tag,int value) |
42 |
{ |
{ |
43 |
return((value & (tag->mask >> 16)) == (tag->value >> 16)); |
return((value & (tag->mask >> 16)) == (tag->value >> 16)); |
44 |
} |
} |
51 |
for(i=0,count=0;mips64_exec_tags[i].exec;i++) |
for(i=0,count=0;mips64_exec_tags[i].exec;i++) |
52 |
count++; |
count++; |
53 |
|
|
54 |
ilt = ilt_create(count, |
ilt = ilt_create("mips64e",count, |
55 |
(ilt_get_insn_cbk_t)mips64_exec_get_insn, |
(ilt_get_insn_cbk_t)mips64_exec_get_insn, |
56 |
(ilt_check_cbk_t)mips64_exec_chk_lo, |
(ilt_check_cbk_t)mips64_exec_chk_lo, |
57 |
(ilt_check_cbk_t)mips64_exec_chk_hi); |
(ilt_check_cbk_t)mips64_exec_chk_hi); |
81 |
{ |
{ |
82 |
char insn_name[64],insn_format[32],*name; |
char insn_name[64],insn_format[32],*name; |
83 |
int base,rs,rd,rt,sa,offset,imm; |
int base,rs,rd,rt,sa,offset,imm; |
84 |
struct insn_exec_tag *tag; |
struct mips64_insn_exec_tag *tag; |
85 |
m_uint64_t new_pc; |
m_uint64_t new_pc; |
86 |
int index; |
int index; |
87 |
|
|
322 |
return(0); |
return(0); |
323 |
} |
} |
324 |
|
|
325 |
|
/* Unknown opcode */ |
326 |
|
static fastcall int mips64_exec_unknown(cpu_mips_t *cpu,mips_insn_t insn) |
327 |
|
{ |
328 |
|
printf("MIPS64: unknown opcode 0x%8.8x at pc = 0x%llx\n",insn,cpu->pc); |
329 |
|
mips64_dump_regs(cpu->gen); |
330 |
|
return(0); |
331 |
|
} |
332 |
|
|
333 |
/* Execute a single instruction */ |
/* Execute a single instruction */ |
334 |
static forced_inline int |
static forced_inline int |
335 |
mips64_exec_single_instruction(cpu_mips_t *cpu,mips_insn_t instruction) |
mips64_exec_single_instruction(cpu_mips_t *cpu,mips_insn_t instruction) |
336 |
{ |
{ |
337 |
register fastcall int (*exec)(cpu_mips_t *,mips_insn_t) = NULL; |
register fastcall int (*exec)(cpu_mips_t *,mips_insn_t) = NULL; |
338 |
struct insn_exec_tag *tag; |
struct mips64_insn_exec_tag *tag; |
339 |
int index; |
int index; |
340 |
|
|
341 |
#if DEBUG_PERF_COUNTER |
#if DEBUG_INSN_PERF_CNT |
342 |
cpu->perf_counter++; |
cpu->perf_counter++; |
343 |
#endif |
#endif |
344 |
|
|
350 |
tag = mips64_exec_get_insn(index); |
tag = mips64_exec_get_insn(index); |
351 |
exec = tag->exec; |
exec = tag->exec; |
352 |
|
|
|
if (likely(exec != NULL)) { |
|
353 |
#if NJM_STATS_ENABLE |
#if NJM_STATS_ENABLE |
354 |
cpu->insn_exec_count++; |
cpu->insn_exec_count++; |
355 |
mips64_exec_tags[index].count++; |
mips64_exec_tags[index].count++; |
356 |
#endif |
#endif |
357 |
#if 0 |
#if 0 |
358 |
{ |
{ |
363 |
} |
} |
364 |
#endif |
#endif |
365 |
|
|
366 |
return(exec(cpu,instruction)); |
return(exec(cpu,instruction)); |
|
} |
|
|
|
|
|
printf("MIPS64: unknown opcode 0x%8.8x at pc = 0x%llx\n", |
|
|
instruction,cpu->pc); |
|
|
mips64_dump_regs(cpu); |
|
|
return(0); |
|
367 |
} |
} |
368 |
|
|
369 |
/* Single-step execution */ |
/* Single-step execution */ |
370 |
void mips64_exec_single_step(cpu_mips_t *cpu,mips_insn_t instruction) |
fastcall void mips64_exec_single_step(cpu_mips_t *cpu,mips_insn_t instruction) |
371 |
{ |
{ |
372 |
int res; |
int res; |
373 |
|
|
378 |
} |
} |
379 |
|
|
380 |
/* Run MIPS code in step-by-step mode */ |
/* Run MIPS code in step-by-step mode */ |
381 |
void *mips64_exec_run_cpu(cpu_mips_t *cpu) |
void *mips64_exec_run_cpu(cpu_gen_t *gen) |
382 |
{ |
{ |
383 |
|
cpu_mips_t *cpu = CPU_MIPS64(gen); |
384 |
pthread_t timer_irq_thread; |
pthread_t timer_irq_thread; |
|
mips_insn_t insn; |
|
385 |
int timer_irq_check = 0; |
int timer_irq_check = 0; |
386 |
|
mips_insn_t insn; |
387 |
int res; |
int res; |
388 |
|
|
389 |
if (pthread_create(&timer_irq_thread,NULL, |
if (pthread_create(&timer_irq_thread,NULL, |
390 |
(void *)mips64_timer_irq_run,cpu)) |
(void *)mips64_timer_irq_run,cpu)) |
391 |
{ |
{ |
392 |
fprintf(stderr,"VM '%s': unable to create Timer IRQ thread for CPU%u.\n", |
fprintf(stderr,"VM '%s': unable to create Timer IRQ thread for CPU%u.\n", |
393 |
cpu->vm->name,cpu->id); |
cpu->vm->name,gen->id); |
394 |
cpu_stop(cpu); |
cpu_stop(gen); |
395 |
return NULL; |
return NULL; |
396 |
} |
} |
397 |
|
|
398 |
cpu->cpu_thread_running = TRUE; |
gen->cpu_thread_running = TRUE; |
399 |
|
|
400 |
start_cpu: |
start_cpu: |
401 |
cpu->idle_count = 0; |
gen->idle_count = 0; |
402 |
|
|
403 |
for(;;) { |
for(;;) { |
404 |
if (unlikely(cpu->state != MIPS_CPU_RUNNING)) |
if (unlikely(gen->state != CPU_STATE_RUNNING)) |
405 |
break; |
break; |
406 |
|
|
407 |
/* Handle virtual idle loop */ |
/* Handle virtual idle loop */ |
408 |
if (unlikely(cpu->pc == cpu->idle_pc)) { |
if (unlikely(cpu->pc == cpu->idle_pc)) { |
409 |
if (++cpu->idle_count == cpu->idle_max) { |
if (++gen->idle_count == gen->idle_max) { |
410 |
mips64_idle_loop(cpu); |
cpu_idle_loop(gen); |
411 |
cpu->idle_count = 0; |
gen->idle_count = 0; |
412 |
} |
} |
413 |
} |
} |
414 |
|
|
437 |
res = mips64_exec_single_instruction(cpu,insn); |
res = mips64_exec_single_instruction(cpu,insn); |
438 |
|
|
439 |
/* Normal flow ? */ |
/* Normal flow ? */ |
440 |
if (likely(!res)) cpu->pc += 4; |
if (likely(!res)) cpu->pc += sizeof(mips_insn_t); |
441 |
} |
} |
442 |
|
|
443 |
if (!cpu->pc) { |
if (!cpu->pc) { |
444 |
cpu_stop(cpu); |
cpu_stop(gen); |
445 |
cpu_log(cpu,"SLOW_EXEC","PC=0, halting CPU.\n"); |
cpu_log(gen,"SLOW_EXEC","PC=0, halting CPU.\n"); |
446 |
} |
} |
447 |
|
|
448 |
/* Check regularly if the CPU has been restarted */ |
/* Check regularly if the CPU has been restarted */ |
449 |
while(cpu->cpu_thread_running) { |
while(gen->cpu_thread_running) { |
450 |
cpu->seq_state++; |
gen->seq_state++; |
451 |
|
|
452 |
switch(cpu->state) { |
switch(gen->state) { |
453 |
case MIPS_CPU_RUNNING: |
case CPU_STATE_RUNNING: |
454 |
cpu->state = MIPS_CPU_RUNNING; |
gen->state = CPU_STATE_RUNNING; |
455 |
goto start_cpu; |
goto start_cpu; |
456 |
|
|
457 |
case MIPS_CPU_HALTED: |
case CPU_STATE_HALTED: |
458 |
cpu->cpu_thread_running = FALSE; |
gen->cpu_thread_running = FALSE; |
459 |
pthread_join(timer_irq_thread,NULL); |
pthread_join(timer_irq_thread,NULL); |
460 |
break; |
break; |
461 |
} |
} |
1085 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1086 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1087 |
|
|
1088 |
cp0_exec_cfc0(cpu,rt,rd); |
mips64_cp0_exec_cfc0(cpu,rt,rd); |
1089 |
return(0); |
return(0); |
1090 |
} |
} |
1091 |
|
|
1095 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1096 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1097 |
|
|
1098 |
cp0_exec_ctc0(cpu,rt,rd); |
mips64_cp0_exec_ctc0(cpu,rt,rd); |
1099 |
return(0); |
return(0); |
1100 |
} |
} |
1101 |
|
|
1159 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1160 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1161 |
|
|
1162 |
cp0_exec_dmfc0(cpu,rt,rd); |
mips64_cp0_exec_dmfc0(cpu,rt,rd); |
1163 |
return(0); |
return(0); |
1164 |
} |
} |
1165 |
|
|
1179 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1180 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1181 |
|
|
1182 |
cp0_exec_dmtc0(cpu,rt,rd); |
mips64_cp0_exec_dmtc0(cpu,rt,rd); |
1183 |
return(0); |
return(0); |
1184 |
} |
} |
1185 |
|
|
1543 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1544 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1545 |
|
|
1546 |
cp0_exec_mfc0(cpu,rt,rd); |
mips64_cp0_exec_mfc0(cpu,rt,rd); |
1547 |
return(0); |
return(0); |
1548 |
} |
} |
1549 |
|
|
1591 |
int rt = bits(insn,16,20); |
int rt = bits(insn,16,20); |
1592 |
int rd = bits(insn,11,15); |
int rd = bits(insn,11,15); |
1593 |
|
|
1594 |
cp0_exec_mtc0(cpu,rt,rd); |
mips64_cp0_exec_mtc0(cpu,rt,rd); |
1595 |
return(0); |
return(0); |
1596 |
} |
} |
1597 |
|
|
2029 |
/* TLBP */ |
/* TLBP */ |
2030 |
static fastcall int mips64_exec_TLBP(cpu_mips_t *cpu,mips_insn_t insn) |
static fastcall int mips64_exec_TLBP(cpu_mips_t *cpu,mips_insn_t insn) |
2031 |
{ |
{ |
2032 |
cp0_exec_tlbp(cpu); |
mips64_cp0_exec_tlbp(cpu); |
2033 |
return(0); |
return(0); |
2034 |
} |
} |
2035 |
|
|
2036 |
/* TLBR */ |
/* TLBR */ |
2037 |
static fastcall int mips64_exec_TLBR(cpu_mips_t *cpu,mips_insn_t insn) |
static fastcall int mips64_exec_TLBR(cpu_mips_t *cpu,mips_insn_t insn) |
2038 |
{ |
{ |
2039 |
cp0_exec_tlbr(cpu); |
mips64_cp0_exec_tlbr(cpu); |
2040 |
return(0); |
return(0); |
2041 |
} |
} |
2042 |
|
|
2043 |
/* TLBWI */ |
/* TLBWI */ |
2044 |
static fastcall int mips64_exec_TLBWI(cpu_mips_t *cpu,mips_insn_t insn) |
static fastcall int mips64_exec_TLBWI(cpu_mips_t *cpu,mips_insn_t insn) |
2045 |
{ |
{ |
2046 |
cp0_exec_tlbwi(cpu); |
mips64_cp0_exec_tlbwi(cpu); |
2047 |
return(0); |
return(0); |
2048 |
} |
} |
2049 |
|
|
2050 |
/* TLBWR */ |
/* TLBWR */ |
2051 |
static fastcall int mips64_exec_TLBWR(cpu_mips_t *cpu,mips_insn_t insn) |
static fastcall int mips64_exec_TLBWR(cpu_mips_t *cpu,mips_insn_t insn) |
2052 |
{ |
{ |
2053 |
cp0_exec_tlbwr(cpu); |
mips64_cp0_exec_tlbwr(cpu); |
2054 |
return(0); |
return(0); |
2055 |
} |
} |
2056 |
|
|
2077 |
} |
} |
2078 |
|
|
2079 |
/* MIPS instruction array */ |
/* MIPS instruction array */ |
2080 |
static struct insn_exec_tag mips64_exec_tags[] = { |
static struct mips64_insn_exec_tag mips64_exec_tags[] = { |
2081 |
{ "li" , mips64_exec_LI , 0xffe00000 , 0x24000000, 1, 16 }, |
{ "li" , mips64_exec_LI , 0xffe00000 , 0x24000000, 1, 16 }, |
2082 |
{ "move" , mips64_exec_MOVE , 0xfc1f07ff , 0x00000021, 1, 15 }, |
{ "move" , mips64_exec_MOVE , 0xfc1f07ff , 0x00000021, 1, 15 }, |
2083 |
{ "b" , mips64_exec_B , 0xffff0000 , 0x10000000, 0, 10 }, |
{ "b" , mips64_exec_B , 0xffff0000 , 0x10000000, 0, 10 }, |
2197 |
{ "tlbwr" , mips64_exec_TLBWR , 0xffffffff , 0x42000006, 1, 1 }, |
{ "tlbwr" , mips64_exec_TLBWR , 0xffffffff , 0x42000006, 1, 1 }, |
2198 |
{ "xor" , mips64_exec_XOR , 0xfc0007ff , 0x00000026, 1, 3 }, |
{ "xor" , mips64_exec_XOR , 0xfc0007ff , 0x00000026, 1, 3 }, |
2199 |
{ "xori" , mips64_exec_XORI , 0xfc000000 , 0x38000000, 1, 5 }, |
{ "xori" , mips64_exec_XORI , 0xfc000000 , 0x38000000, 1, 5 }, |
2200 |
|
{ "unknown", mips64_exec_unknown , 0x00000000 , 0x00000000, 1, 0 }, |
2201 |
{ NULL , NULL , 0x00000000 , 0x00000000, 1, 0 }, |
{ NULL , NULL , 0x00000000 , 0x00000000, 1, 0 }, |
2202 |
}; |
}; |
2203 |
|
|