Revision 6af0bf9c
b/Makefile.target | ||
---|---|---|
72 | 72 |
PROGS+=$(QEMU_SYSTEM) |
73 | 73 |
endif |
74 | 74 |
|
75 |
endif # TARGET_ARCH = ppc |
|
76 |
|
|
77 |
ifeq ($(TARGET_ARCH), mips) |
|
78 |
|
|
75 | 79 |
ifeq ($(ARCH), i386) |
76 | 80 |
ifdef CONFIG_SOFTMMU |
77 | 81 |
PROGS+=$(QEMU_SYSTEM) |
... | ... | |
84 | 88 |
endif |
85 | 89 |
endif # ARCH = x86_64 |
86 | 90 |
|
87 |
endif # TARGET_ARCH = ppc
|
|
91 |
endif # TARGET_ARCH = mips
|
|
88 | 92 |
|
89 | 93 |
ifeq ($(TARGET_ARCH), sparc) |
90 | 94 |
|
... | ... | |
263 | 267 |
LIBOBJS+= op_helper.o helper.o |
264 | 268 |
endif |
265 | 269 |
|
270 |
ifeq ($(TARGET_ARCH), mips) |
|
271 |
LIBOBJS+= op_helper.o helper.o |
|
272 |
endif |
|
273 |
|
|
266 | 274 |
ifeq ($(TARGET_BASE_ARCH), sparc) |
267 | 275 |
LIBOBJS+= op_helper.o helper.o |
268 | 276 |
endif |
... | ... | |
288 | 296 |
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) |
289 | 297 |
LIBOBJS+=ppc-dis.o |
290 | 298 |
endif |
299 |
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips) |
|
300 |
LIBOBJS+=mips-dis.o |
|
301 |
endif |
|
291 | 302 |
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc) |
292 | 303 |
LIBOBJS+=sparc-dis.o |
293 | 304 |
endif |
... | ... | |
348 | 359 |
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o |
349 | 360 |
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o |
350 | 361 |
endif |
362 |
ifeq ($(TARGET_ARCH), mips) |
|
363 |
VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o #ide.o ne2000.o pckbd.o |
|
364 |
VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o |
|
365 |
endif |
|
351 | 366 |
ifeq ($(TARGET_BASE_ARCH), sparc) |
352 | 367 |
ifeq ($(TARGET_ARCH), sparc64) |
353 | 368 |
VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o |
... | ... | |
455 | 470 |
op_helper.o: op_helper_mem.h |
456 | 471 |
endif |
457 | 472 |
|
473 |
ifeq ($(TARGET_ARCH), mips) |
|
474 |
op.o: op.c op_template.c op_mem.c |
|
475 |
op_helper.o: op_helper_mem.c |
|
476 |
endif |
|
477 |
|
|
458 | 478 |
mixeng.o: mixeng.c mixeng.h mixeng_template.h |
459 | 479 |
|
460 | 480 |
%.o: %.c |
b/cpu-all.h | ||
---|---|---|
617 | 617 |
#define cpu_gen_code cpu_ppc_gen_code |
618 | 618 |
#define cpu_signal_handler cpu_ppc_signal_handler |
619 | 619 |
|
620 |
#elif defined(TARGET_MIPS) |
|
621 |
#define CPUState CPUMIPSState |
|
622 |
#define cpu_init cpu_mips_init |
|
623 |
#define cpu_exec cpu_mips_exec |
|
624 |
#define cpu_gen_code cpu_mips_gen_code |
|
625 |
#define cpu_signal_handler cpu_mips_signal_handler |
|
626 |
|
|
620 | 627 |
#else |
621 | 628 |
|
622 | 629 |
#error unsupported target CPU |
b/cpu-exec.c | ||
---|---|---|
182 | 182 |
saved_regwptr = REGWPTR; |
183 | 183 |
#endif |
184 | 184 |
#elif defined(TARGET_PPC) |
185 |
#elif defined(TARGET_MIPS) |
|
185 | 186 |
#else |
186 | 187 |
#error unsupported target CPU |
187 | 188 |
#endif |
... | ... | |
220 | 221 |
env->exception_next_eip, 0); |
221 | 222 |
#elif defined(TARGET_PPC) |
222 | 223 |
do_interrupt(env); |
224 |
#elif defined(TARGET_MIPS) |
|
225 |
do_interrupt(env); |
|
223 | 226 |
#elif defined(TARGET_SPARC) |
224 | 227 |
do_interrupt(env->exception_index); |
225 | 228 |
#endif |
... | ... | |
301 | 304 |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
302 | 305 |
} |
303 | 306 |
} |
307 |
#elif defined(TARGET_MIPS) |
|
308 |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
|
309 |
(env->CP0_Status & (1 << CP0St_IE)) && |
|
310 |
(env->CP0_Cause & 0x0000FC00) && |
|
311 |
!(env->hflags & MIPS_HFLAG_EXL) && |
|
312 |
!(env->hflags & MIPS_HFLAG_ERL) && |
|
313 |
!(env->hflags & MIPS_HFLAG_DM)) { |
|
314 |
/* Raise it */ |
|
315 |
env->exception_index = EXCP_EXT_INTERRUPT; |
|
316 |
env->error_code = 0; |
|
317 |
do_interrupt(env); |
|
318 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
|
319 |
} |
|
304 | 320 |
#elif defined(TARGET_SPARC) |
305 | 321 |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
306 | 322 |
(env->psret != 0)) { |
... | ... | |
376 | 392 |
cpu_dump_state(env, logfile, fprintf, 0); |
377 | 393 |
#elif defined(TARGET_PPC) |
378 | 394 |
cpu_dump_state(env, logfile, fprintf, 0); |
395 |
#elif defined(TARGET_MIPS) |
|
396 |
cpu_dump_state(env, logfile, fprintf, 0); |
|
379 | 397 |
#else |
380 | 398 |
#error unsupported target CPU |
381 | 399 |
#endif |
... | ... | |
407 | 425 |
(msr_se << MSR_SE) | (msr_le << MSR_LE); |
408 | 426 |
cs_base = 0; |
409 | 427 |
pc = env->nip; |
428 |
#elif defined(TARGET_MIPS) |
|
429 |
flags = env->hflags & MIPS_HFLAGS_TMASK; |
|
430 |
cs_base = NULL; |
|
431 |
pc = env->PC; |
|
410 | 432 |
#else |
411 | 433 |
#error unsupported CPU |
412 | 434 |
#endif |
... | ... | |
684 | 706 |
REGWPTR = saved_regwptr; |
685 | 707 |
#endif |
686 | 708 |
#elif defined(TARGET_PPC) |
709 |
#elif defined(TARGET_MIPS) |
|
687 | 710 |
#else |
688 | 711 |
#error unsupported target CPU |
689 | 712 |
#endif |
... | ... | |
935 | 958 |
/* never comes here */ |
936 | 959 |
return 1; |
937 | 960 |
} |
961 |
|
|
962 |
#elif defined (TARGET_MIPS) |
|
963 |
static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
|
964 |
int is_write, sigset_t *old_set, |
|
965 |
void *puc) |
|
966 |
{ |
|
967 |
TranslationBlock *tb; |
|
968 |
int ret; |
|
969 |
|
|
970 |
if (cpu_single_env) |
|
971 |
env = cpu_single_env; /* XXX: find a correct solution for multithread */ |
|
972 |
#if defined(DEBUG_SIGNAL) |
|
973 |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", |
|
974 |
pc, address, is_write, *(unsigned long *)old_set); |
|
975 |
#endif |
|
976 |
/* XXX: locking issue */ |
|
977 |
if (is_write && page_unprotect(address, pc, puc)) { |
|
978 |
return 1; |
|
979 |
} |
|
980 |
|
|
981 |
/* see if it is an MMU fault */ |
|
982 |
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0); |
|
983 |
if (ret < 0) |
|
984 |
return 0; /* not an MMU fault */ |
|
985 |
if (ret == 0) |
|
986 |
return 1; /* the MMU fault was handled without causing real CPU fault */ |
|
987 |
|
|
988 |
/* now we have a real cpu fault */ |
|
989 |
tb = tb_find_pc(pc); |
|
990 |
if (tb) { |
|
991 |
/* the PC is inside the translated code. It means that we have |
|
992 |
a virtual CPU fault */ |
|
993 |
cpu_restore_state(tb, env, pc, puc); |
|
994 |
} |
|
995 |
if (ret == 1) { |
|
996 |
#if 0 |
|
997 |
printf("PF exception: NIP=0x%08x error=0x%x %p\n", |
|
998 |
env->nip, env->error_code, tb); |
|
999 |
#endif |
|
1000 |
/* we restore the process signal mask as the sigreturn should |
|
1001 |
do it (XXX: use sigsetjmp) */ |
|
1002 |
sigprocmask(SIG_SETMASK, old_set, NULL); |
|
1003 |
do_raise_exception_err(env->exception_index, env->error_code); |
|
1004 |
} else { |
|
1005 |
/* activate soft MMU for this block */ |
|
1006 |
cpu_resume_from_signal(env, puc); |
|
1007 |
} |
|
1008 |
/* never comes here */ |
|
1009 |
return 1; |
|
1010 |
} |
|
1011 |
|
|
938 | 1012 |
#else |
939 | 1013 |
#error unsupported target CPU |
940 | 1014 |
#endif |
b/dis-asm.h | ||
---|---|---|
404 | 404 |
|
405 | 405 |
bfd_vma bfd_getl32 (const bfd_byte *addr); |
406 | 406 |
bfd_vma bfd_getb32 (const bfd_byte *addr); |
407 |
bfd_vma bfd_getl16 (const bfd_byte *addr); |
|
408 |
bfd_vma bfd_getb16 (const bfd_byte *addr); |
|
407 | 409 |
typedef enum bfd_boolean {false, true} boolean; |
408 | 410 |
|
409 | 411 |
#endif /* ! defined (DIS_ASM_H) */ |
b/disas.c | ||
---|---|---|
108 | 108 |
return (bfd_vma) v; |
109 | 109 |
} |
110 | 110 |
|
111 |
bfd_vma bfd_getl16 (const bfd_byte *addr) |
|
112 |
{ |
|
113 |
unsigned long v; |
|
114 |
|
|
115 |
v = (unsigned long) addr[0]; |
|
116 |
v |= (unsigned long) addr[1] << 8; |
|
117 |
return (bfd_vma) v; |
|
118 |
} |
|
119 |
|
|
120 |
bfd_vma bfd_getb16 (const bfd_byte *addr) |
|
121 |
{ |
|
122 |
unsigned long v; |
|
123 |
|
|
124 |
v = (unsigned long) addr[0] << 24; |
|
125 |
v |= (unsigned long) addr[1] << 16; |
|
126 |
return (bfd_vma) v; |
|
127 |
} |
|
128 |
|
|
111 | 129 |
#ifdef TARGET_ARM |
112 | 130 |
static int |
113 | 131 |
print_insn_thumb1(bfd_vma pc, disassemble_info *info) |
... | ... | |
162 | 180 |
if (cpu_single_env->msr[MSR_LE]) |
163 | 181 |
disasm_info.endian = BFD_ENDIAN_LITTLE; |
164 | 182 |
print_insn = print_insn_ppc; |
183 |
#elif defined(TARGET_MIPS) |
|
184 |
print_insn = print_insn_big_mips; |
|
165 | 185 |
#else |
166 | 186 |
fprintf(out, "0x" TARGET_FMT_lx |
167 | 187 |
": Asm output not supported on this arch\n", code); |
... | ... | |
222 | 242 |
print_insn = print_insn_sparc; |
223 | 243 |
#elif defined(__arm__) |
224 | 244 |
print_insn = print_insn_arm; |
245 |
#elif defined(__MIPSEB__) |
|
246 |
print_insn = print_insn_big_mips; |
|
247 |
#elif defined(__MIPSEL__) |
|
248 |
print_insn = print_insn_little_mips; |
|
225 | 249 |
#else |
226 | 250 |
fprintf(out, "0x%lx: Asm output not supported on this arch\n", |
227 | 251 |
(long) code); |
... | ... | |
332 | 356 |
print_insn = print_insn_sparc; |
333 | 357 |
#elif defined(TARGET_PPC) |
334 | 358 |
print_insn = print_insn_ppc; |
359 |
#elif defined(TARGET_MIPS) |
|
360 |
print_insn = print_insn_big_mips; |
|
335 | 361 |
#else |
336 | 362 |
term_printf("0x" TARGET_FMT_lx |
337 | 363 |
": Asm output not supported on this arch\n", pc); |
b/elf.h | ||
---|---|---|
31 | 31 |
#define PT_LOPROC 0x70000000 |
32 | 32 |
#define PT_HIPROC 0x7fffffff |
33 | 33 |
#define PT_MIPS_REGINFO 0x70000000 |
34 |
#define PT_MIPS_OPTIONS 0x70000001 |
|
34 | 35 |
|
35 | 36 |
/* Flags in the e_flags field of the header */ |
37 |
/* MIPS architecture level. */ |
|
38 |
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ |
|
39 |
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ |
|
40 |
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ |
|
41 |
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ |
|
42 |
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ |
|
43 |
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ |
|
44 |
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ |
|
45 |
|
|
46 |
/* The ABI of a file. */ |
|
47 |
#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ |
|
48 |
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ |
|
49 |
|
|
36 | 50 |
#define EF_MIPS_NOREORDER 0x00000001 |
37 | 51 |
#define EF_MIPS_PIC 0x00000002 |
38 | 52 |
#define EF_MIPS_CPIC 0x00000004 |
53 |
#define EF_MIPS_ABI2 0x00000020 |
|
54 |
#define EF_MIPS_OPTIONS_FIRST 0x00000080 |
|
55 |
#define EF_MIPS_32BITMODE 0x00000100 |
|
56 |
#define EF_MIPS_ABI 0x0000f000 |
|
39 | 57 |
#define EF_MIPS_ARCH 0xf0000000 |
40 | 58 |
|
41 | 59 |
/* These constants define the different elf file types */ |
b/exec-all.h | ||
---|---|---|
582 | 582 |
is_user = ((env->hflags & HF_CPL_MASK) == 3); |
583 | 583 |
#elif defined (TARGET_PPC) |
584 | 584 |
is_user = msr_pr; |
585 |
#elif defined (TARGET_MIPS) |
|
586 |
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); |
|
585 | 587 |
#elif defined (TARGET_SPARC) |
586 | 588 |
is_user = (env->psrs == 0); |
587 | 589 |
#else |
b/hw/mips_r4k.c | ||
---|---|---|
1 |
#include "vl.h" |
|
2 |
|
|
3 |
#define DEBUG_IRQ_COUNT |
|
4 |
|
|
5 |
#define BIOS_FILENAME "mips_bios.bin" |
|
6 |
//#define BIOS_FILENAME "system.bin" |
|
7 |
#define KERNEL_LOAD_ADDR 0x80010000 |
|
8 |
#define INITRD_LOAD_ADDR 0x80800000 |
|
9 |
|
|
10 |
/* MIPS R4K IRQ controler */ |
|
11 |
#if defined(DEBUG_IRQ_COUNT) |
|
12 |
static uint64_t irq_count[16]; |
|
13 |
#endif |
|
14 |
|
|
15 |
extern FILE *logfile; |
|
16 |
|
|
17 |
void mips_set_irq (int n_IRQ, int level) |
|
18 |
{ |
|
19 |
uint32_t mask; |
|
20 |
|
|
21 |
if (n_IRQ < 0 || n_IRQ >= 8) |
|
22 |
return; |
|
23 |
mask = 0x100 << n_IRQ; |
|
24 |
if (level != 0) { |
|
25 |
#if 1 |
|
26 |
if (logfile) { |
|
27 |
fprintf(logfile, "%s n %d l %d mask %08x %08x\n", |
|
28 |
__func__, n_IRQ, level, mask, cpu_single_env->CP0_Status); |
|
29 |
} |
|
30 |
#endif |
|
31 |
cpu_single_env->CP0_Cause |= mask; |
|
32 |
if ((cpu_single_env->CP0_Status & 0x00000001) && |
|
33 |
(cpu_single_env->CP0_Status & mask)) { |
|
34 |
#if defined(DEBUG_IRQ_COUNT) |
|
35 |
irq_count[n_IRQ]++; |
|
36 |
#endif |
|
37 |
#if 1 |
|
38 |
if (logfile) |
|
39 |
fprintf(logfile, "%s raise IRQ\n", __func__); |
|
40 |
#endif |
|
41 |
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); |
|
42 |
} |
|
43 |
} else { |
|
44 |
cpu_single_env->CP0_Cause &= ~mask; |
|
45 |
} |
|
46 |
} |
|
47 |
|
|
48 |
void pic_set_irq (int n_IRQ, int level) |
|
49 |
{ |
|
50 |
mips_set_irq(n_IRQ + 2, level); |
|
51 |
} |
|
52 |
|
|
53 |
void pic_info (void) |
|
54 |
{ |
|
55 |
term_printf("IRQ asserted: %02x mask: %02x\n", |
|
56 |
(cpu_single_env->CP0_Cause >> 8) & 0xFF, |
|
57 |
(cpu_single_env->CP0_Status >> 8) & 0xFF); |
|
58 |
} |
|
59 |
|
|
60 |
void irq_info (void) |
|
61 |
{ |
|
62 |
#if !defined(DEBUG_IRQ_COUNT) |
|
63 |
term_printf("irq statistic code not compiled.\n"); |
|
64 |
#else |
|
65 |
int i; |
|
66 |
int64_t count; |
|
67 |
|
|
68 |
term_printf("IRQ statistics:\n"); |
|
69 |
for (i = 0; i < 8; i++) { |
|
70 |
count = irq_count[i]; |
|
71 |
if (count > 0) |
|
72 |
term_printf("%2d: %lld\n", i, count); |
|
73 |
} |
|
74 |
#endif |
|
75 |
} |
|
76 |
|
|
77 |
void cpu_mips_irqctrl_init (void) |
|
78 |
{ |
|
79 |
} |
|
80 |
|
|
81 |
/* MIPS R4K timer */ |
|
82 |
uint32_t cpu_mips_get_random (CPUState *env) |
|
83 |
{ |
|
84 |
uint64_t now = qemu_get_clock(vm_clock); |
|
85 |
|
|
86 |
return (uint32_t)now & 0x0000000F; |
|
87 |
} |
|
88 |
|
|
89 |
uint32_t cpu_mips_get_count (CPUState *env) |
|
90 |
{ |
|
91 |
return env->CP0_Count + |
|
92 |
(uint32_t)muldiv64(qemu_get_clock(vm_clock), |
|
93 |
100 * 1000 * 1000, ticks_per_sec); |
|
94 |
} |
|
95 |
|
|
96 |
static void cpu_mips_update_count (CPUState *env, uint32_t count, |
|
97 |
uint32_t compare) |
|
98 |
{ |
|
99 |
uint64_t now, next; |
|
100 |
uint32_t tmp; |
|
101 |
|
|
102 |
tmp = count; |
|
103 |
if (count == compare) |
|
104 |
tmp++; |
|
105 |
now = qemu_get_clock(vm_clock); |
|
106 |
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); |
|
107 |
if (next == now) |
|
108 |
next++; |
|
109 |
#if 1 |
|
110 |
if (logfile) { |
|
111 |
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", |
|
112 |
__func__, now, count, compare, next - now); |
|
113 |
} |
|
114 |
#endif |
|
115 |
/* Store new count and compare registers */ |
|
116 |
env->CP0_Compare = compare; |
|
117 |
env->CP0_Count = |
|
118 |
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); |
|
119 |
/* Adjust timer */ |
|
120 |
qemu_mod_timer(env->timer, next); |
|
121 |
} |
|
122 |
|
|
123 |
void cpu_mips_store_count (CPUState *env, uint32_t value) |
|
124 |
{ |
|
125 |
cpu_mips_update_count(env, value, env->CP0_Compare); |
|
126 |
} |
|
127 |
|
|
128 |
void cpu_mips_store_compare (CPUState *env, uint32_t value) |
|
129 |
{ |
|
130 |
cpu_mips_update_count(env, cpu_mips_get_count(env), value); |
|
131 |
pic_set_irq(5, 0); |
|
132 |
} |
|
133 |
|
|
134 |
static void mips_timer_cb (void *opaque) |
|
135 |
{ |
|
136 |
CPUState *env; |
|
137 |
|
|
138 |
env = opaque; |
|
139 |
#if 1 |
|
140 |
if (logfile) { |
|
141 |
fprintf(logfile, "%s\n", __func__); |
|
142 |
} |
|
143 |
#endif |
|
144 |
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); |
|
145 |
pic_set_irq(5, 1); |
|
146 |
} |
|
147 |
|
|
148 |
void cpu_mips_clock_init (CPUState *env) |
|
149 |
{ |
|
150 |
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); |
|
151 |
env->CP0_Compare = 0; |
|
152 |
cpu_mips_update_count(env, 1, 0); |
|
153 |
} |
|
154 |
|
|
155 |
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
156 |
{ |
|
157 |
if (logfile) |
|
158 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); |
|
159 |
cpu_outb(NULL, addr & 0xffff, value); |
|
160 |
} |
|
161 |
|
|
162 |
static uint32_t io_readb (void *opaque, target_phys_addr_t addr) |
|
163 |
{ |
|
164 |
uint32_t ret = cpu_inb(NULL, addr & 0xffff); |
|
165 |
if (logfile) |
|
166 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); |
|
167 |
return ret; |
|
168 |
} |
|
169 |
|
|
170 |
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
171 |
{ |
|
172 |
if (logfile) |
|
173 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); |
|
174 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
175 |
value = bswap16(value); |
|
176 |
#endif |
|
177 |
cpu_outw(NULL, addr & 0xffff, value); |
|
178 |
} |
|
179 |
|
|
180 |
static uint32_t io_readw (void *opaque, target_phys_addr_t addr) |
|
181 |
{ |
|
182 |
uint32_t ret = cpu_inw(NULL, addr & 0xffff); |
|
183 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
184 |
ret = bswap16(ret); |
|
185 |
#endif |
|
186 |
if (logfile) |
|
187 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); |
|
188 |
return ret; |
|
189 |
} |
|
190 |
|
|
191 |
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
192 |
{ |
|
193 |
if (logfile) |
|
194 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); |
|
195 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
196 |
value = bswap32(value); |
|
197 |
#endif |
|
198 |
cpu_outl(NULL, addr & 0xffff, value); |
|
199 |
} |
|
200 |
|
|
201 |
static uint32_t io_readl (void *opaque, target_phys_addr_t addr) |
|
202 |
{ |
|
203 |
uint32_t ret = cpu_inl(NULL, addr & 0xffff); |
|
204 |
|
|
205 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
206 |
ret = bswap32(ret); |
|
207 |
#endif |
|
208 |
if (logfile) |
|
209 |
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); |
|
210 |
return ret; |
|
211 |
} |
|
212 |
|
|
213 |
CPUWriteMemoryFunc *io_write[] = { |
|
214 |
&io_writeb, |
|
215 |
&io_writew, |
|
216 |
&io_writel, |
|
217 |
}; |
|
218 |
|
|
219 |
CPUReadMemoryFunc *io_read[] = { |
|
220 |
&io_readb, |
|
221 |
&io_readw, |
|
222 |
&io_readl, |
|
223 |
}; |
|
224 |
|
|
225 |
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, |
|
226 |
DisplayState *ds, const char **fd_filename, int snapshot, |
|
227 |
const char *kernel_filename, const char *kernel_cmdline, |
|
228 |
const char *initrd_filename) |
|
229 |
{ |
|
230 |
char buf[1024]; |
|
231 |
target_ulong kernel_base, kernel_size, initrd_base, initrd_size; |
|
232 |
unsigned long bios_offset; |
|
233 |
int io_memory; |
|
234 |
int linux_boot; |
|
235 |
int ret; |
|
236 |
|
|
237 |
printf("%s: start\n", __func__); |
|
238 |
linux_boot = (kernel_filename != NULL); |
|
239 |
/* allocate RAM */ |
|
240 |
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); |
|
241 |
bios_offset = ram_size + vga_ram_size; |
|
242 |
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); |
|
243 |
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE); |
|
244 |
ret = load_image(buf, phys_ram_base + bios_offset); |
|
245 |
if (ret != BIOS_SIZE) { |
|
246 |
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf); |
|
247 |
exit(1); |
|
248 |
} |
|
249 |
cpu_register_physical_memory((uint32_t)(0x1fc00000), |
|
250 |
BIOS_SIZE, bios_offset | IO_MEM_ROM); |
|
251 |
#if 0 |
|
252 |
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE); |
|
253 |
cpu_single_env->PC = 0x80010004; |
|
254 |
#else |
|
255 |
cpu_single_env->PC = 0xBFC00004; |
|
256 |
#endif |
|
257 |
if (linux_boot) { |
|
258 |
kernel_base = KERNEL_LOAD_ADDR; |
|
259 |
/* now we can load the kernel */ |
|
260 |
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); |
|
261 |
if (kernel_size < 0) { |
|
262 |
fprintf(stderr, "qemu: could not load kernel '%s'\n", |
|
263 |
kernel_filename); |
|
264 |
exit(1); |
|
265 |
} |
|
266 |
/* load initrd */ |
|
267 |
if (initrd_filename) { |
|
268 |
initrd_base = INITRD_LOAD_ADDR; |
|
269 |
initrd_size = load_image(initrd_filename, |
|
270 |
phys_ram_base + initrd_base); |
|
271 |
if (initrd_size < 0) { |
|
272 |
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
|
273 |
initrd_filename); |
|
274 |
exit(1); |
|
275 |
} |
|
276 |
} else { |
|
277 |
initrd_base = 0; |
|
278 |
initrd_size = 0; |
|
279 |
} |
|
280 |
cpu_single_env->PC = KERNEL_LOAD_ADDR; |
|
281 |
} else { |
|
282 |
kernel_base = 0; |
|
283 |
kernel_size = 0; |
|
284 |
initrd_base = 0; |
|
285 |
initrd_size = 0; |
|
286 |
} |
|
287 |
/* XXX: should not be ! */ |
|
288 |
printf("%s: init VGA\n", __func__); |
|
289 |
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, |
|
290 |
vga_ram_size); |
|
291 |
|
|
292 |
|
|
293 |
/* Init internal devices */ |
|
294 |
cpu_mips_clock_init(cpu_single_env); |
|
295 |
cpu_mips_irqctrl_init(); |
|
296 |
|
|
297 |
isa_mem_base = 0x78000000; |
|
298 |
/* Register 64 KB of ISA IO space at random address */ |
|
299 |
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); |
|
300 |
cpu_register_physical_memory(0x70000000, 0x00010000, io_memory); |
|
301 |
serial_init(0x3f8, 4, serial_hds[0]); |
|
302 |
printf("%s: done\n", __func__); |
|
303 |
} |
|
304 |
|
|
305 |
QEMUMachine mips_machine = { |
|
306 |
"mips", |
|
307 |
"mips r4k platform", |
|
308 |
mips_r4k_init, |
|
309 |
}; |
b/softmmu_header.h | ||
---|---|---|
55 | 55 |
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) |
56 | 56 |
#elif defined (TARGET_PPC) |
57 | 57 |
#define CPU_MEM_INDEX (msr_pr) |
58 |
#elif defined (TARGET_MIPS) |
|
59 |
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) |
|
58 | 60 |
#elif defined (TARGET_SPARC) |
59 | 61 |
#define CPU_MEM_INDEX ((env->psrs) == 0) |
60 | 62 |
#endif |
... | ... | |
66 | 68 |
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) |
67 | 69 |
#elif defined (TARGET_PPC) |
68 | 70 |
#define CPU_MEM_INDEX (msr_pr) |
71 |
#elif defined (TARGET_MIPS) |
|
72 |
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) |
|
69 | 73 |
#elif defined (TARGET_SPARC) |
70 | 74 |
#define CPU_MEM_INDEX ((env->psrs) == 0) |
71 | 75 |
#endif |
b/target-mips/cpu.h | ||
---|---|---|
1 |
#if !defined (__MIPS_CPU_H__) |
|
2 |
#define __MIPS_CPU_H__ |
|
3 |
|
|
4 |
#include "mips-defs.h" |
|
5 |
#include "cpu-defs.h" |
|
6 |
#include "config.h" |
|
7 |
#include "softfloat.h" |
|
8 |
|
|
9 |
typedef union fpr_t fpr_t; |
|
10 |
union fpr_t { |
|
11 |
double d; |
|
12 |
float f; |
|
13 |
uint32_t u[2]; |
|
14 |
}; |
|
15 |
|
|
16 |
#if defined(MIPS_USES_R4K_TLB) |
|
17 |
typedef struct tlb_t tlb_t; |
|
18 |
struct tlb_t { |
|
19 |
target_ulong VPN; |
|
20 |
target_ulong end; |
|
21 |
uint8_t ASID; |
|
22 |
uint8_t G; |
|
23 |
uint8_t C[2]; |
|
24 |
uint8_t V[2]; |
|
25 |
uint8_t D[2]; |
|
26 |
target_ulong PFN[2]; |
|
27 |
}; |
|
28 |
#endif |
|
29 |
|
|
30 |
typedef struct CPUMIPSState CPUMIPSState; |
|
31 |
struct CPUMIPSState { |
|
32 |
/* General integer registers */ |
|
33 |
target_ulong gpr[32]; |
|
34 |
/* Special registers */ |
|
35 |
target_ulong PC; |
|
36 |
uint32_t HI, LO; |
|
37 |
uint32_t DCR; /* ? */ |
|
38 |
#if defined(MIPS_USES_FPU) |
|
39 |
/* Floating point registers */ |
|
40 |
fpr_t fpr[16]; |
|
41 |
/* Floating point special purpose registers */ |
|
42 |
uint32_t fcr0; |
|
43 |
uint32_t fcr25; |
|
44 |
uint32_t fcr26; |
|
45 |
uint32_t fcr28; |
|
46 |
uint32_t fcsr; |
|
47 |
#endif |
|
48 |
#if defined(MIPS_USES_R4K_TLB) |
|
49 |
tlb_t tlb[16]; |
|
50 |
#endif |
|
51 |
uint32_t CP0_index; |
|
52 |
uint32_t CP0_random; |
|
53 |
uint32_t CP0_EntryLo0; |
|
54 |
uint32_t CP0_EntryLo1; |
|
55 |
uint32_t CP0_Context; |
|
56 |
uint32_t CP0_PageMask; |
|
57 |
uint32_t CP0_Wired; |
|
58 |
uint32_t CP0_BadVAddr; |
|
59 |
uint32_t CP0_Count; |
|
60 |
uint32_t CP0_EntryHi; |
|
61 |
uint32_t CP0_Compare; |
|
62 |
uint32_t CP0_Status; |
|
63 |
#define CP0St_CU3 31 |
|
64 |
#define CP0St_CU2 30 |
|
65 |
#define CP0St_CU1 29 |
|
66 |
#define CP0St_CU0 28 |
|
67 |
#define CP0St_RP 27 |
|
68 |
#define CP0St_RE 25 |
|
69 |
#define CP0St_BEV 22 |
|
70 |
#define CP0St_TS 21 |
|
71 |
#define CP0St_SR 20 |
|
72 |
#define CP0St_NMI 19 |
|
73 |
#define CP0St_IM 8 |
|
74 |
#define CP0St_UM 4 |
|
75 |
#define CP0St_ERL 2 |
|
76 |
#define CP0St_EXL 1 |
|
77 |
#define CP0St_IE 0 |
|
78 |
uint32_t CP0_Cause; |
|
79 |
#define CP0Ca_IV 23 |
|
80 |
uint32_t CP0_EPC; |
|
81 |
uint32_t CP0_PRid; |
|
82 |
uint32_t CP0_Config0; |
|
83 |
#define CP0C0_M 31 |
|
84 |
#define CP0C0_K23 28 |
|
85 |
#define CP0C0_KU 25 |
|
86 |
#define CP0C0_MDU 20 |
|
87 |
#define CP0C0_MM 17 |
|
88 |
#define CP0C0_BM 16 |
|
89 |
#define CP0C0_BE 15 |
|
90 |
#define CP0C0_AT 13 |
|
91 |
#define CP0C0_AR 10 |
|
92 |
#define CP0C0_MT 7 |
|
93 |
#define CP0C0_K0 0 |
|
94 |
uint32_t CP0_Config1; |
|
95 |
#define CP0C1_MMU 25 |
|
96 |
#define CP0C1_IS 22 |
|
97 |
#define CP0C1_IL 19 |
|
98 |
#define CP0C1_IA 16 |
|
99 |
#define CP0C1_DS 13 |
|
100 |
#define CP0C1_DL 10 |
|
101 |
#define CP0C1_DA 7 |
|
102 |
#define CP0C1_PC 4 |
|
103 |
#define CP0C1_WR 3 |
|
104 |
#define CP0C1_CA 2 |
|
105 |
#define CP0C1_EP 1 |
|
106 |
#define CP0C1_FP 0 |
|
107 |
uint32_t CP0_LLAddr; |
|
108 |
uint32_t CP0_WatchLo; |
|
109 |
uint32_t CP0_WatchHi; |
|
110 |
uint32_t CP0_Debug; |
|
111 |
#define CPDB_DBD 31 |
|
112 |
#define CP0DB_DM 30 |
|
113 |
#define CP0DB_LSNM 28 |
|
114 |
#define CP0DB_Doze 27 |
|
115 |
#define CP0DB_Halt 26 |
|
116 |
#define CP0DB_CNT 25 |
|
117 |
#define CP0DB_IBEP 24 |
|
118 |
#define CP0DB_DBEP 21 |
|
119 |
#define CP0DB_IEXI 20 |
|
120 |
#define CP0DB_VER 15 |
|
121 |
#define CP0DB_DEC 10 |
|
122 |
#define CP0DB_SSt 8 |
|
123 |
#define CP0DB_DINT 5 |
|
124 |
#define CP0DB_DIB 4 |
|
125 |
#define CP0DB_DDBS 3 |
|
126 |
#define CP0DB_DDBL 2 |
|
127 |
#define CP0DB_DBp 1 |
|
128 |
#define CP0DB_DSS 0 |
|
129 |
uint32_t CP0_DEPC; |
|
130 |
uint32_t CP0_TagLo; |
|
131 |
uint32_t CP0_DataLo; |
|
132 |
uint32_t CP0_ErrorEPC; |
|
133 |
uint32_t CP0_DESAVE; |
|
134 |
/* Qemu */ |
|
135 |
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU) |
|
136 |
double ft0, ft1, ft2; |
|
137 |
#endif |
|
138 |
struct QEMUTimer *timer; /* Internal timer */ |
|
139 |
int interrupt_request; |
|
140 |
jmp_buf jmp_env; |
|
141 |
int exception_index; |
|
142 |
int error_code; |
|
143 |
int user_mode_only; /* user mode only simulation */ |
|
144 |
uint32_t hflags; /* CPU State */ |
|
145 |
/* TMASK defines different execution modes */ |
|
146 |
#define MIPS_HFLAGS_TMASK 0x00FF |
|
147 |
#define MIPS_HFLAG_MODE 0x001F /* execution modes */ |
|
148 |
#define MIPS_HFLAG_UM 0x0001 /* user mode */ |
|
149 |
#define MIPS_HFLAG_ERL 0x0002 /* Error mode */ |
|
150 |
#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */ |
|
151 |
#define MIPS_HFLAG_DM 0x0008 /* Debug mode */ |
|
152 |
#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ |
|
153 |
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ |
|
154 |
#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */ |
|
155 |
/* Those flags keep the branch state if the translation is interrupted |
|
156 |
* between the branch instruction and the delay slot |
|
157 |
*/ |
|
158 |
#define MIPS_HFLAG_BMASK 0x0F00 |
|
159 |
#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ |
|
160 |
#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ |
|
161 |
#define MIPS_HFLAG_BL 0x0400 /* Likely branch */ |
|
162 |
#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ |
|
163 |
target_ulong btarget; /* Jump / branch target */ |
|
164 |
int bcond; /* Branch condition (if needed) */ |
|
165 |
struct TranslationBlock *current_tb; /* currently executing TB */ |
|
166 |
/* soft mmu support */ |
|
167 |
/* in order to avoid passing too many arguments to the memory |
|
168 |
write helpers, we store some rarely used information in the CPU |
|
169 |
context) */ |
|
170 |
target_ulong mem_write_pc; /* host pc at which the memory was |
|
171 |
written */ |
|
172 |
unsigned long mem_write_vaddr; /* target virtual addr at which the |
|
173 |
memory was written */ |
|
174 |
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ |
|
175 |
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; |
|
176 |
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; |
|
177 |
/* ice debug support */ |
|
178 |
target_ulong breakpoints[MAX_BREAKPOINTS]; |
|
179 |
int nb_breakpoints; |
|
180 |
int singlestep_enabled; /* XXX: should use CPU single step mode instead */ |
|
181 |
/* user data */ |
|
182 |
void *opaque; |
|
183 |
}; |
|
184 |
|
|
185 |
#include "cpu-all.h" |
|
186 |
|
|
187 |
/* Memory access type : |
|
188 |
* may be needed for precise access rights control and precise exceptions. |
|
189 |
*/ |
|
190 |
enum { |
|
191 |
/* 1 bit to define user level / supervisor access */ |
|
192 |
ACCESS_USER = 0x00, |
|
193 |
ACCESS_SUPER = 0x01, |
|
194 |
/* 1 bit to indicate direction */ |
|
195 |
ACCESS_STORE = 0x02, |
|
196 |
/* Type of instruction that generated the access */ |
|
197 |
ACCESS_CODE = 0x10, /* Code fetch access */ |
|
198 |
ACCESS_INT = 0x20, /* Integer load/store access */ |
|
199 |
ACCESS_FLOAT = 0x30, /* floating point load/store access */ |
|
200 |
}; |
|
201 |
|
|
202 |
/* Exceptions */ |
|
203 |
enum { |
|
204 |
EXCP_NONE = -1, |
|
205 |
EXCP_RESET = 0, |
|
206 |
EXCP_SRESET, |
|
207 |
EXCP_DSS, |
|
208 |
EXCP_DINT, |
|
209 |
EXCP_NMI, |
|
210 |
EXCP_MCHECK, |
|
211 |
EXCP_EXT_INTERRUPT, |
|
212 |
EXCP_DFWATCH, |
|
213 |
EXCP_DIB, /* 8 */ |
|
214 |
EXCP_IWATCH, |
|
215 |
EXCP_AdEL, |
|
216 |
EXCP_AdES, |
|
217 |
EXCP_TLBF, |
|
218 |
EXCP_IBE, |
|
219 |
EXCP_DBp, |
|
220 |
EXCP_SYSCALL, |
|
221 |
EXCP_BREAK, |
|
222 |
EXCP_CpU, /* 16 */ |
|
223 |
EXCP_RI, |
|
224 |
EXCP_OVERFLOW, |
|
225 |
EXCP_TRAP, |
|
226 |
EXCP_DDBS, |
|
227 |
EXCP_DWATCH, |
|
228 |
EXCP_LAE, /* 22 */ |
|
229 |
EXCP_SAE, |
|
230 |
EXCP_LTLBL, |
|
231 |
EXCP_TLBL, |
|
232 |
EXCP_TLBS, |
|
233 |
EXCP_DBE, |
|
234 |
EXCP_DDBL, |
|
235 |
EXCP_MTCP0 = 0x104, /* mtmsr instruction: */ |
|
236 |
/* may change privilege level */ |
|
237 |
EXCP_BRANCH = 0x108, /* branch instruction */ |
|
238 |
EXCP_ERET = 0x10C, /* return from interrupt */ |
|
239 |
EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */ |
|
240 |
EXCP_FLUSH = 0x109, |
|
241 |
}; |
|
242 |
|
|
243 |
/* MIPS opcodes */ |
|
244 |
#define EXT_SPECIAL 0x100 |
|
245 |
#define EXT_SPECIAL2 0x200 |
|
246 |
#define EXT_REGIMM 0x300 |
|
247 |
#define EXT_CP0 0x400 |
|
248 |
#define EXT_CP1 0x500 |
|
249 |
#define EXT_CP2 0x600 |
|
250 |
#define EXT_CP3 0x700 |
|
251 |
|
|
252 |
enum { |
|
253 |
/* indirect opcode tables */ |
|
254 |
OPC_SPECIAL = 0x00, |
|
255 |
OPC_BREGIMM = 0x01, |
|
256 |
OPC_CP0 = 0x10, |
|
257 |
OPC_CP1 = 0x11, |
|
258 |
OPC_CP2 = 0x12, |
|
259 |
OPC_CP3 = 0x13, |
|
260 |
OPC_SPECIAL2 = 0x1C, |
|
261 |
/* arithmetic with immediate */ |
|
262 |
OPC_ADDI = 0x08, |
|
263 |
OPC_ADDIU = 0x09, |
|
264 |
OPC_SLTI = 0x0A, |
|
265 |
OPC_SLTIU = 0x0B, |
|
266 |
OPC_ANDI = 0x0C, |
|
267 |
OPC_ORI = 0x0D, |
|
268 |
OPC_XORI = 0x0E, |
|
269 |
OPC_LUI = 0x0F, |
|
270 |
/* Jump and branches */ |
|
271 |
OPC_J = 0x02, |
|
272 |
OPC_JAL = 0x03, |
|
273 |
OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ |
|
274 |
OPC_BEQL = 0x14, |
|
275 |
OPC_BNE = 0x05, |
|
276 |
OPC_BNEL = 0x15, |
|
277 |
OPC_BLEZ = 0x06, |
|
278 |
OPC_BLEZL = 0x16, |
|
279 |
OPC_BGTZ = 0x07, |
|
280 |
OPC_BGTZL = 0x17, |
|
281 |
OPC_JALX = 0x1D, /* MIPS 16 only */ |
|
282 |
/* Load and stores */ |
|
283 |
OPC_LB = 0x20, |
|
284 |
OPC_LH = 0x21, |
|
285 |
OPC_LWL = 0x22, |
|
286 |
OPC_LW = 0x23, |
|
287 |
OPC_LBU = 0x24, |
|
288 |
OPC_LHU = 0x25, |
|
289 |
OPC_LWR = 0x26, |
|
290 |
OPC_SB = 0x28, |
|
291 |
OPC_SH = 0x29, |
|
292 |
OPC_SWL = 0x2A, |
|
293 |
OPC_SW = 0x2B, |
|
294 |
OPC_SWR = 0x2E, |
|
295 |
OPC_LL = 0x30, |
|
296 |
OPC_SC = 0x38, |
|
297 |
/* Floating point load/store */ |
|
298 |
OPC_LWC1 = 0x31, |
|
299 |
OPC_LWC2 = 0x32, |
|
300 |
OPC_LDC1 = 0x35, |
|
301 |
OPC_LDC2 = 0x36, |
|
302 |
OPC_SWC1 = 0x39, |
|
303 |
OPC_SWC2 = 0x3A, |
|
304 |
OPC_SDC1 = 0x3D, |
|
305 |
OPC_SDC2 = 0x3E, |
|
306 |
/* Cache and prefetch */ |
|
307 |
OPC_CACHE = 0x2F, |
|
308 |
OPC_PREF = 0x33, |
|
309 |
}; |
|
310 |
|
|
311 |
/* MIPS special opcodes */ |
|
312 |
enum { |
|
313 |
/* Shifts */ |
|
314 |
OPC_SLL = 0x00 | EXT_SPECIAL, |
|
315 |
/* NOP is SLL r0, r0, 0 */ |
|
316 |
/* SSNOP is SLL r0, r0, 1 */ |
|
317 |
OPC_SRL = 0x02 | EXT_SPECIAL, |
|
318 |
OPC_SRA = 0x03 | EXT_SPECIAL, |
|
319 |
OPC_SLLV = 0x04 | EXT_SPECIAL, |
|
320 |
OPC_SRLV = 0x06 | EXT_SPECIAL, |
|
321 |
OPC_SRAV = 0x07 | EXT_SPECIAL, |
|
322 |
/* Multiplication / division */ |
|
323 |
OPC_MULT = 0x18 | EXT_SPECIAL, |
|
324 |
OPC_MULTU = 0x19 | EXT_SPECIAL, |
|
325 |
OPC_DIV = 0x1A | EXT_SPECIAL, |
|
326 |
OPC_DIVU = 0x1B | EXT_SPECIAL, |
|
327 |
/* 2 registers arithmetic / logic */ |
|
328 |
OPC_ADD = 0x20 | EXT_SPECIAL, |
|
329 |
OPC_ADDU = 0x21 | EXT_SPECIAL, |
|
330 |
OPC_SUB = 0x22 | EXT_SPECIAL, |
|
331 |
OPC_SUBU = 0x23 | EXT_SPECIAL, |
|
332 |
OPC_AND = 0x24 | EXT_SPECIAL, |
|
333 |
OPC_OR = 0x25 | EXT_SPECIAL, |
|
334 |
OPC_XOR = 0x26 | EXT_SPECIAL, |
|
335 |
OPC_NOR = 0x27 | EXT_SPECIAL, |
|
336 |
OPC_SLT = 0x2A | EXT_SPECIAL, |
|
337 |
OPC_SLTU = 0x2B | EXT_SPECIAL, |
|
338 |
/* Jumps */ |
|
339 |
OPC_JR = 0x08 | EXT_SPECIAL, |
|
340 |
OPC_JALR = 0x09 | EXT_SPECIAL, |
|
341 |
/* Traps */ |
|
342 |
OPC_TGE = 0x30 | EXT_SPECIAL, |
|
343 |
OPC_TGEU = 0x31 | EXT_SPECIAL, |
|
344 |
OPC_TLT = 0x32 | EXT_SPECIAL, |
|
345 |
OPC_TLTU = 0x33 | EXT_SPECIAL, |
|
346 |
OPC_TEQ = 0x34 | EXT_SPECIAL, |
|
347 |
OPC_TNE = 0x36 | EXT_SPECIAL, |
|
348 |
/* HI / LO registers load & stores */ |
|
349 |
OPC_MFHI = 0x10 | EXT_SPECIAL, |
|
350 |
OPC_MTHI = 0x11 | EXT_SPECIAL, |
|
351 |
OPC_MFLO = 0x12 | EXT_SPECIAL, |
|
352 |
OPC_MTLO = 0x13 | EXT_SPECIAL, |
|
353 |
/* Conditional moves */ |
|
354 |
OPC_MOVZ = 0x0A | EXT_SPECIAL, |
|
355 |
OPC_MOVN = 0x0B | EXT_SPECIAL, |
|
356 |
|
|
357 |
OPC_MOVCI = 0x01 | EXT_SPECIAL, |
|
358 |
|
|
359 |
/* Special */ |
|
360 |
OPC_PMON = 0x05 | EXT_SPECIAL, |
|
361 |
OPC_SYSCALL = 0x0C | EXT_SPECIAL, |
|
362 |
OPC_BREAK = 0x0D | EXT_SPECIAL, |
|
363 |
OPC_SYNC = 0x0F | EXT_SPECIAL, |
|
364 |
}; |
|
365 |
|
|
366 |
enum { |
|
367 |
/* Mutiply & xxx operations */ |
|
368 |
OPC_MADD = 0x00 | EXT_SPECIAL2, |
|
369 |
OPC_MADDU = 0x01 | EXT_SPECIAL2, |
|
370 |
OPC_MUL = 0x02 | EXT_SPECIAL2, |
|
371 |
OPC_MSUB = 0x04 | EXT_SPECIAL2, |
|
372 |
OPC_MSUBU = 0x05 | EXT_SPECIAL2, |
|
373 |
/* Misc */ |
|
374 |
OPC_CLZ = 0x20 | EXT_SPECIAL2, |
|
375 |
OPC_CLO = 0x21 | EXT_SPECIAL2, |
|
376 |
/* Special */ |
|
377 |
OPC_SDBBP = 0x3F | EXT_SPECIAL2, |
|
378 |
}; |
|
379 |
|
|
380 |
/* Branch REGIMM */ |
|
381 |
enum { |
|
382 |
OPC_BLTZ = 0x00 | EXT_REGIMM, |
|
383 |
OPC_BLTZL = 0x02 | EXT_REGIMM, |
|
384 |
OPC_BGEZ = 0x01 | EXT_REGIMM, |
|
385 |
OPC_BGEZL = 0x03 | EXT_REGIMM, |
|
386 |
OPC_BLTZAL = 0x10 | EXT_REGIMM, |
|
387 |
OPC_BLTZALL = 0x12 | EXT_REGIMM, |
|
388 |
OPC_BGEZAL = 0x11 | EXT_REGIMM, |
|
389 |
OPC_BGEZALL = 0x13 | EXT_REGIMM, |
|
390 |
OPC_TGEI = 0x08 | EXT_REGIMM, |
|
391 |
OPC_TGEIU = 0x09 | EXT_REGIMM, |
|
392 |
OPC_TLTI = 0x0A | EXT_REGIMM, |
|
393 |
OPC_TLTIU = 0x0B | EXT_REGIMM, |
|
394 |
OPC_TEQI = 0x0C | EXT_REGIMM, |
|
395 |
OPC_TNEI = 0x0E | EXT_REGIMM, |
|
396 |
}; |
|
397 |
|
|
398 |
enum { |
|
399 |
/* Coprocessor 0 (MMU) */ |
|
400 |
OPC_MFC0 = 0x00 | EXT_CP0, |
|
401 |
OPC_MTC0 = 0x04 | EXT_CP0, |
|
402 |
OPC_TLBR = 0x01 | EXT_CP0, |
|
403 |
OPC_TLBWI = 0x02 | EXT_CP0, |
|
404 |
OPC_TLBWR = 0x06 | EXT_CP0, |
|
405 |
OPC_TLBP = 0x08 | EXT_CP0, |
|
406 |
OPC_ERET = 0x18 | EXT_CP0, |
|
407 |
OPC_DERET = 0x1F | EXT_CP0, |
|
408 |
OPC_WAIT = 0x20 | EXT_CP0, |
|
409 |
}; |
|
410 |
|
|
411 |
int cpu_mips_exec(CPUMIPSState *s); |
|
412 |
CPUMIPSState *cpu_mips_init(void); |
|
413 |
uint32_t cpu_mips_get_clock (void); |
|
414 |
|
|
415 |
#endif /* !defined (__MIPS_CPU_H__) */ |
b/target-mips/exec.h | ||
---|---|---|
1 |
#if !defined(__QEMU_MIPS_EXEC_H__) |
|
2 |
#define __QEMU_MIPS_EXEC_H__ |
|
3 |
|
|
4 |
#define DEBUG_OP |
|
5 |
|
|
6 |
#include "mips-defs.h" |
|
7 |
#include "dyngen-exec.h" |
|
8 |
|
|
9 |
register struct CPUMIPSState *env asm(AREG0); |
|
10 |
|
|
11 |
#if defined (USE_64BITS_REGS) |
|
12 |
typedef int64_t host_int_t; |
|
13 |
typedef uint64_t host_uint_t; |
|
14 |
#else |
|
15 |
typedef int32_t host_int_t; |
|
16 |
typedef uint32_t host_uint_t; |
|
17 |
#endif |
|
18 |
|
|
19 |
register host_uint_t T0 asm(AREG1); |
|
20 |
register host_uint_t T1 asm(AREG2); |
|
21 |
register host_uint_t T2 asm(AREG3); |
|
22 |
register host_int_t Ts0 asm(AREG1); |
|
23 |
register host_int_t Ts1 asm(AREG2); |
|
24 |
register host_int_t Ts2 asm(AREG3); |
|
25 |
|
|
26 |
#define PARAM(n) ((uint32_t)PARAM##n) |
|
27 |
#define SPARAM(n) ((int32_t)PARAM##n) |
|
28 |
|
|
29 |
#if defined (USE_HOST_FLOAT_REGS) |
|
30 |
register double FT0 asm(FREG0); |
|
31 |
register double FT1 asm(FREG1); |
|
32 |
register double FT2 asm(FREG2); |
|
33 |
register float FTS0 asm(FREG0); |
|
34 |
register float FTS1 asm(FREG1); |
|
35 |
register float FTS2 asm(FREG2); |
|
36 |
#else |
|
37 |
#define FT0 (env->ft0.d) |
|
38 |
#define FT1 (env->ft1.d) |
|
39 |
#define FT2 (env->ft2.d) |
|
40 |
#define FTS0 (env->ft0.f) |
|
41 |
#define FTS1 (env->ft1.f) |
|
42 |
#define FTS2 (env->ft2.f) |
|
43 |
#endif |
|
44 |
|
|
45 |
#if defined (DEBUG_OP) |
|
46 |
#define RETURN() __asm__ __volatile__("nop"); |
|
47 |
#else |
|
48 |
#define RETURN() __asm__ __volatile__(""); |
|
49 |
#endif |
|
50 |
|
|
51 |
#include "cpu.h" |
|
52 |
#include "exec-all.h" |
|
53 |
|
|
54 |
#if !defined(CONFIG_USER_ONLY) |
|
55 |
|
|
56 |
#define ldul_user ldl_user |
|
57 |
#define ldul_kernel ldl_kernel |
|
58 |
|
|
59 |
#define ACCESS_TYPE 0 |
|
60 |
#define MEMSUFFIX _kernel |
|
61 |
#define DATA_SIZE 1 |
|
62 |
#include "softmmu_header.h" |
|
63 |
|
|
64 |
#define DATA_SIZE 2 |
|
65 |
#include "softmmu_header.h" |
|
66 |
|
|
67 |
#define DATA_SIZE 4 |
|
68 |
#include "softmmu_header.h" |
|
69 |
|
|
70 |
#define DATA_SIZE 8 |
|
71 |
#include "softmmu_header.h" |
|
72 |
#undef ACCESS_TYPE |
|
73 |
#undef MEMSUFFIX |
|
74 |
|
|
75 |
#define ACCESS_TYPE 1 |
|
76 |
#define MEMSUFFIX _user |
|
77 |
#define DATA_SIZE 1 |
|
78 |
#include "softmmu_header.h" |
|
79 |
|
|
80 |
#define DATA_SIZE 2 |
|
81 |
#include "softmmu_header.h" |
|
82 |
|
|
83 |
#define DATA_SIZE 4 |
|
84 |
#include "softmmu_header.h" |
|
85 |
|
|
86 |
#define DATA_SIZE 8 |
|
87 |
#include "softmmu_header.h" |
|
88 |
#undef ACCESS_TYPE |
|
89 |
#undef MEMSUFFIX |
|
90 |
|
|
91 |
/* these access are slower, they must be as rare as possible */ |
|
92 |
#define ACCESS_TYPE 2 |
|
93 |
#define MEMSUFFIX _data |
|
94 |
#define DATA_SIZE 1 |
|
95 |
#include "softmmu_header.h" |
|
96 |
|
|
97 |
#define DATA_SIZE 2 |
|
98 |
#include "softmmu_header.h" |
|
99 |
|
|
100 |
#define DATA_SIZE 4 |
|
101 |
#include "softmmu_header.h" |
|
102 |
|
|
103 |
#define DATA_SIZE 8 |
|
104 |
#include "softmmu_header.h" |
|
105 |
#undef ACCESS_TYPE |
|
106 |
#undef MEMSUFFIX |
|
107 |
|
|
108 |
#define ldub(p) ldub_data(p) |
|
109 |
#define ldsb(p) ldsb_data(p) |
|
110 |
#define lduw(p) lduw_data(p) |
|
111 |
#define ldsw(p) ldsw_data(p) |
|
112 |
#define ldl(p) ldl_data(p) |
|
113 |
#define ldq(p) ldq_data(p) |
|
114 |
|
|
115 |
#define stb(p, v) stb_data(p, v) |
|
116 |
#define stw(p, v) stw_data(p, v) |
|
117 |
#define stl(p, v) stl_data(p, v) |
|
118 |
#define stq(p, v) stq_data(p, v) |
|
119 |
|
|
120 |
#endif /* !defined(CONFIG_USER_ONLY) */ |
|
121 |
|
|
122 |
static inline void env_to_regs(void) |
|
123 |
{ |
|
124 |
} |
|
125 |
|
|
126 |
static inline void regs_to_env(void) |
|
127 |
{ |
|
128 |
} |
|
129 |
|
|
130 |
#if (HOST_LONG_BITS == 32) |
|
131 |
void do_mult (void); |
|
132 |
void do_multu (void); |
|
133 |
void do_madd (void); |
|
134 |
void do_maddu (void); |
|
135 |
void do_msub (void); |
|
136 |
void do_msubu (void); |
|
137 |
#endif |
|
138 |
__attribute__ (( regparm(2) )) |
|
139 |
void do_mfc0(int reg, int sel); |
|
140 |
__attribute__ (( regparm(2) )) |
|
141 |
void do_mtc0(int reg, int sel); |
|
142 |
void do_tlbwi (void); |
|
143 |
void do_tlbwr (void); |
|
144 |
void do_tlbp (void); |
|
145 |
void do_tlbr (void); |
|
146 |
void do_lwl_raw (void); |
|
147 |
void do_lwr_raw (void); |
|
148 |
void do_swl_raw (void); |
|
149 |
void do_swr_raw (void); |
|
150 |
#if !defined(CONFIG_USER_ONLY) |
|
151 |
void do_lwl_user (void); |
|
152 |
void do_lwl_kernel (void); |
|
153 |
void do_lwr_user (void); |
|
154 |
void do_lwr_kernel (void); |
|
155 |
void do_swl_user (void); |
|
156 |
void do_swl_kernel (void); |
|
157 |
void do_swr_user (void); |
|
158 |
void do_swr_kernel (void); |
|
159 |
#endif |
|
160 |
__attribute__ (( regparm(1) )) |
|
161 |
void do_pmon (int function); |
|
162 |
|
|
163 |
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
164 |
int is_user, int is_softmmu); |
|
165 |
void do_interrupt (CPUState *env); |
|
166 |
|
|
167 |
void cpu_loop_exit(void); |
|
168 |
__attribute__ (( regparm(2) )) |
|
169 |
void do_raise_exception_err (uint32_t exception, int error_code); |
|
170 |
__attribute__ (( regparm(1) )) |
|
171 |
void do_raise_exception (uint32_t exception); |
|
172 |
|
|
173 |
void cpu_dump_state(CPUState *env, FILE *f, |
|
174 |
int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
|
175 |
int flags); |
|
176 |
void cpu_mips_irqctrl_init (void); |
|
177 |
uint32_t cpu_mips_get_random (CPUState *env); |
|
178 |
uint32_t cpu_mips_get_count (CPUState *env); |
|
179 |
void cpu_mips_store_count (CPUState *env, uint32_t value); |
|
180 |
void cpu_mips_store_compare (CPUState *env, uint32_t value); |
|
181 |
void cpu_mips_clock_init (CPUState *env); |
|
182 |
|
|
183 |
#endif /* !defined(__QEMU_MIPS_EXEC_H__) */ |
b/target-mips/helper.c | ||
---|---|---|
1 |
/* |
|
2 |
* MIPS emulation helpers for qemu. |
|
3 |
* |
|
4 |
* Copyright (c) 2004-2005 Jocelyn Mayer |
|
5 |
* |
|
6 |
* This library is free software; you can redistribute it and/or |
|
7 |
* modify it under the terms of the GNU Lesser General Public |
|
8 |
* License as published by the Free Software Foundation; either |
|
9 |
* version 2 of the License, or (at your option) any later version. |
|
10 |
* |
|
11 |
* This library is distributed in the hope that it will be useful, |
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
* Lesser General Public License for more details. |
|
15 |
* |
|
16 |
* You should have received a copy of the GNU Lesser General Public |
|
17 |
* License along with this library; if not, write to the Free Software |
|
18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
19 |
*/ |
|
20 |
|
|
21 |
#include "exec.h" |
|
22 |
|
|
23 |
/* MIPS32 4K MMU emulation */ |
|
24 |
#if MIPS_USES_4K_TLB |
|
25 |
static int map_address (CPUState *env, target_ulong *physical, int *prot, |
|
26 |
target_ulong address, int rw, int access_type) |
|
27 |
{ |
|
28 |
tlb_t *tlb; |
|
29 |
target_ulong tag; |
|
30 |
uint8_t ASID; |
|
31 |
int i, n; |
|
32 |
int ret; |
|
33 |
|
|
34 |
ret = -2; |
|
35 |
tag = (address & 0xFFFFE000); |
|
36 |
ASID = env->CP0_EntryHi & 0x000000FF; |
|
37 |
for (i = 0; i < 16; i++) { |
|
38 |
tlb = &env->tlb[i]; |
|
39 |
/* Check ASID, virtual page number & size */ |
|
40 |
if ((tlb->G == 1 || tlb->ASID == ASID) && |
|
41 |
tlb->VPN == tag && address < tlb->end) { |
|
42 |
/* TLB match */ |
|
43 |
n = (address >> 12) & 1; |
|
44 |
/* Check access rights */ |
|
45 |
if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) { |
|
46 |
*physical = tlb->PFN[n] | (address & 0xFFF); |
|
47 |
*prot = PROT_READ; |
|
48 |
if (tlb->D[n]) |
|
49 |
*prot |= PROT_WRITE; |
|
50 |
return 0; |
|
51 |
} else if (!(tlb->V[n] & 2)) { |
|
52 |
return -3; |
|
53 |
} else { |
|
54 |
return -4; |
|
55 |
} |
|
56 |
} |
|
57 |
} |
|
58 |
|
|
59 |
return ret; |
|
60 |
} |
|
61 |
#endif |
|
62 |
|
|
63 |
int get_physical_address (CPUState *env, target_ulong *physical, int *prot, |
|
64 |
target_ulong address, int rw, int access_type) |
|
65 |
{ |
|
66 |
int user_mode; |
|
67 |
int ret; |
|
68 |
|
|
69 |
/* User mode can only access useg */ |
|
70 |
user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0; |
|
71 |
#if 0 |
|
72 |
if (logfile) { |
|
73 |
fprintf(logfile, "user mode %d h %08x\n", |
|
74 |
user_mode, env->hflags); |
|
75 |
} |
|
76 |
#endif |
|
77 |
if (user_mode && address > 0x7FFFFFFFUL) |
|
78 |
return -1; |
|
79 |
ret = 0; |
|
80 |
if (address < 0x80000000UL) { |
|
81 |
if (user_mode || !(env->hflags & MIPS_HFLAG_ERL)) { |
|
82 |
#if MIPS_USES_4K_TLB |
|
83 |
ret = map_address(env, physical, prot, address, rw); |
|
84 |
#else |
|
85 |
*physical = address + 0x40000000UL; |
|
86 |
*prot = PAGE_READ | PAGE_WRITE; |
|
87 |
#endif |
|
88 |
} else { |
|
89 |
*physical = address; |
|
90 |
*prot = PAGE_READ | PAGE_WRITE; |
|
91 |
} |
|
92 |
} else if (address < 0xA0000000UL) { |
|
93 |
/* kseg0 */ |
|
94 |
/* XXX: check supervisor mode */ |
|
95 |
*physical = address - 0x80000000UL; |
|
96 |
*prot = PAGE_READ | PAGE_WRITE; |
|
97 |
} else if (address < 0xC0000000UL) { |
|
98 |
/* kseg1 */ |
|
99 |
/* XXX: check supervisor mode */ |
|
100 |
*physical = address - 0xA0000000UL; |
|
101 |
*prot = PAGE_READ | PAGE_WRITE; |
|
102 |
} else if (address < 0xE0000000UL) { |
|
103 |
/* kseg2 */ |
|
104 |
#if MIPS_USES_4K_TLB |
|
105 |
ret = map_address(env, physical, prot, address, rw); |
|
106 |
#else |
|
107 |
*physical = address; |
|
108 |
*prot = PAGE_READ | PAGE_WRITE; |
|
109 |
#endif |
|
110 |
} else { |
|
111 |
/* kseg3 */ |
|
112 |
/* XXX: check supervisor mode */ |
|
113 |
/* XXX: debug segment is not emulated */ |
|
114 |
#if MIPS_USES_4K_TLB |
|
115 |
ret = map_address(env, physical, prot, address, rw); |
|
116 |
#else |
|
117 |
*physical = address; |
|
118 |
*prot = PAGE_READ | PAGE_WRITE; |
|
119 |
#endif |
|
120 |
} |
|
121 |
#if 0 |
|
122 |
if (logfile) { |
|
123 |
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw, |
|
124 |
access_type, *physical, *prot, ret); |
|
125 |
} |
|
126 |
#endif |
|
127 |
|
|
128 |
return ret; |
|
129 |
} |
|
130 |
|
|
131 |
#if defined(CONFIG_USER_ONLY) |
|
132 |
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
|
133 |
{ |
|
134 |
return addr; |
|
135 |
} |
|
136 |
#else |
|
137 |
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
|
138 |
{ |
|
139 |
target_ulong phys_addr; |
|
140 |
int prot; |
|
141 |
|
|
142 |
if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) |
|
143 |
return -1; |
|
144 |
return phys_addr; |
|
145 |
} |
|
146 |
#endif |
|
147 |
|
|
148 |
#if !defined(CONFIG_USER_ONLY) |
|
149 |
|
|
150 |
#define MMUSUFFIX _mmu |
|
151 |
#define GETPC() (__builtin_return_address(0)) |
|
152 |
|
|
153 |
#define SHIFT 0 |
|
154 |
#include "softmmu_template.h" |
|
155 |
|
|
156 |
#define SHIFT 1 |
|
157 |
#include "softmmu_template.h" |
|
158 |
|
|
159 |
#define SHIFT 2 |
|
160 |
#include "softmmu_template.h" |
|
161 |
|
|
162 |
#define SHIFT 3 |
|
163 |
#include "softmmu_template.h" |
|
164 |
|
|
165 |
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) |
|
166 |
{ |
|
167 |
TranslationBlock *tb; |
|
168 |
CPUState *saved_env; |
|
169 |
unsigned long pc; |
|
170 |
int ret; |
|
171 |
|
|
172 |
/* XXX: hack to restore env in all cases, even if not called from |
|
173 |
generated code */ |
|
174 |
saved_env = env; |
|
175 |
env = cpu_single_env; |
|
176 |
ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1); |
|
177 |
if (ret) { |
|
178 |
if (retaddr) { |
|
179 |
/* now we have a real cpu fault */ |
|
180 |
pc = (unsigned long)retaddr; |
|
181 |
tb = tb_find_pc(pc); |
|
182 |
if (tb) { |
|
183 |
/* the PC is inside the translated code. It means that we have |
|
184 |
a virtual CPU fault */ |
|
185 |
cpu_restore_state(tb, env, pc, NULL); |
|
186 |
} |
|
187 |
} |
|
188 |
do_raise_exception_err(env->exception_index, env->error_code); |
|
189 |
} |
|
190 |
env = saved_env; |
|
191 |
} |
|
192 |
|
|
193 |
void cpu_mips_init_mmu (CPUState *env) |
|
194 |
{ |
|
195 |
} |
|
196 |
|
|
197 |
#endif /* !defined(CONFIG_USER_ONLY) */ |
|
198 |
|
|
199 |
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
200 |
int is_user, int is_softmmu) |
|
201 |
{ |
|
202 |
target_ulong physical; |
|
203 |
int prot; |
|
204 |
int exception = 0, error_code = 0; |
|
205 |
int access_type; |
|
206 |
int ret = 0; |
|
207 |
|
|
208 |
if (logfile) { |
Also available in: Unified diff