1 |
#ifndef CPU_MIPS_H |
2 |
#define CPU_MIPS_H |
3 |
|
4 |
/* |
5 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
6 |
* |
7 |
* Redistribution and use in source and binary forms, with or without |
8 |
* modification, are permitted provided that the following conditions are met: |
9 |
* |
10 |
* 1. Redistributions of source code must retain the above copyright |
11 |
* notice, this list of conditions and the following disclaimer. |
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
13 |
* notice, this list of conditions and the following disclaimer in the |
14 |
* documentation and/or other materials provided with the distribution. |
15 |
* 3. The name of the author may not be used to endorse or promote products |
16 |
* derived from this software without specific prior written permission. |
17 |
* |
18 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
* SUCH DAMAGE. |
29 |
* |
30 |
* |
31 |
* $Id: cpu_mips.h,v 1.16 2005/06/26 22:23:43 debug Exp $ |
32 |
*/ |
33 |
|
34 |
#include "misc.h" |
35 |
|
36 |
/* |
37 |
* ENABLE_MIPS16 should be defined on the cc commandline using -D, if you |
38 |
* want it. (This is done by ./configure --mips16) |
39 |
*/ |
40 |
/* #define MFHILO_DELAY */ |
41 |
|
42 |
struct cpu_family; |
43 |
struct emul; |
44 |
struct machine; |
45 |
|
46 |
/* |
47 |
* CPU type definitions: See mips_cpu_types.h. |
48 |
*/ |
49 |
|
50 |
struct mips_cpu_type_def { |
51 |
char *name; |
52 |
int rev; |
53 |
int sub; |
54 |
char flags; |
55 |
char exc_model; /* EXC3K or EXC4K */ |
56 |
char mmu_model; /* MMU3K or MMU4K */ |
57 |
char isa_level; /* 1, 2, 3, 4, 5, 32, 64 */ |
58 |
int nr_of_tlb_entries; /* 32, 48, 64, ... */ |
59 |
char instrs_per_cycle; /* simplified, 1, 2, or 4 */ |
60 |
int default_picache; |
61 |
int default_pdcache; |
62 |
int default_pilinesize; |
63 |
int default_pdlinesize; |
64 |
int default_scache; |
65 |
int default_slinesize; |
66 |
}; |
67 |
|
68 |
#define INITIAL_PC 0xffffffffbfc00000ULL |
69 |
#define INITIAL_STACK_POINTER (0xffffffffa0008000ULL - 256) |
70 |
|
71 |
|
72 |
/* |
73 |
* Coproc 0: |
74 |
*/ |
75 |
#define N_MIPS_COPROC_REGS 32 |
76 |
struct mips_tlb { |
77 |
uint64_t hi; |
78 |
uint64_t lo0; |
79 |
uint64_t lo1; |
80 |
uint64_t mask; |
81 |
}; |
82 |
|
83 |
|
84 |
/* |
85 |
* Coproc 1: |
86 |
*/ |
87 |
#define N_MIPS_FCRS 32 |
88 |
|
89 |
struct mips_coproc { |
90 |
int coproc_nr; |
91 |
uint64_t reg[N_MIPS_COPROC_REGS]; |
92 |
|
93 |
/* Only for COP0: */ |
94 |
struct mips_tlb *tlbs; |
95 |
int nr_of_tlbs; |
96 |
|
97 |
/* Only for COP1: floating point control registers */ |
98 |
/* (Maybe also for COP0?) */ |
99 |
uint64_t fcr[N_MIPS_FCRS]; |
100 |
}; |
101 |
|
102 |
#define N_MIPS_COPROCS 4 |
103 |
|
104 |
#define N_MIPS_GPRS 32 /* General purpose registers */ |
105 |
#define N_MIPS_FPRS 32 /* Floating point registers */ |
106 |
|
107 |
/* |
108 |
* These should all be 2 characters wide: |
109 |
* |
110 |
* NOTE: These are for 32-bit ABIs. For the 64-bit ABI, registers 8..11 |
111 |
* are used to pass arguments and are then called "a4".."a7". |
112 |
* |
113 |
* TODO: Should there be two different variants of this? It's not really |
114 |
* possible to figure out in some easy way if the code running was |
115 |
* written for a 32-bit or 64-bit ABI. |
116 |
*/ |
117 |
#define MIPS_REGISTER_NAMES { \ |
118 |
"zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ |
119 |
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ |
120 |
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ |
121 |
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" } |
122 |
|
123 |
#define MIPS_GPR_ZERO 0 /* zero */ |
124 |
#define MIPS_GPR_AT 1 /* at */ |
125 |
#define MIPS_GPR_V0 2 /* v0 */ |
126 |
#define MIPS_GPR_V1 3 /* v1 */ |
127 |
#define MIPS_GPR_A0 4 /* a0 */ |
128 |
#define MIPS_GPR_A1 5 /* a1 */ |
129 |
#define MIPS_GPR_A2 6 /* a2 */ |
130 |
#define MIPS_GPR_A3 7 /* a3 */ |
131 |
#define MIPS_GPR_T0 8 /* t0 */ |
132 |
#define MIPS_GPR_T1 9 /* t1 */ |
133 |
#define MIPS_GPR_T2 10 /* t2 */ |
134 |
#define MIPS_GPR_T3 11 /* t3 */ |
135 |
#define MIPS_GPR_T4 12 /* t4 */ |
136 |
#define MIPS_GPR_T5 13 /* t5 */ |
137 |
#define MIPS_GPR_T6 14 /* t6 */ |
138 |
#define MIPS_GPR_T7 15 /* t7 */ |
139 |
#define MIPS_GPR_S0 16 /* s0 */ |
140 |
#define MIPS_GPR_S1 17 /* s1 */ |
141 |
#define MIPS_GPR_S2 18 /* s2 */ |
142 |
#define MIPS_GPR_S3 19 /* s3 */ |
143 |
#define MIPS_GPR_S4 20 /* s4 */ |
144 |
#define MIPS_GPR_S5 21 /* s5 */ |
145 |
#define MIPS_GPR_S6 22 /* s6 */ |
146 |
#define MIPS_GPR_S7 23 /* s7 */ |
147 |
#define MIPS_GPR_T8 24 /* t8 */ |
148 |
#define MIPS_GPR_T9 25 /* t9 */ |
149 |
#define MIPS_GPR_K0 26 /* k0 */ |
150 |
#define MIPS_GPR_K1 27 /* k1 */ |
151 |
#define MIPS_GPR_GP 28 /* gp */ |
152 |
#define MIPS_GPR_SP 29 /* sp */ |
153 |
#define MIPS_GPR_FP 30 /* fp */ |
154 |
#define MIPS_GPR_RA 31 /* ra */ |
155 |
|
156 |
/* Meaning of delay_slot: */ |
157 |
#define NOT_DELAYED 0 |
158 |
#define DELAYED 1 |
159 |
#define TO_BE_DELAYED 2 |
160 |
|
161 |
#define N_HI6 64 |
162 |
#define N_SPECIAL 64 |
163 |
#define N_REGIMM 32 |
164 |
|
165 |
/* Number of "tiny" translation cache entries: */ |
166 |
#define N_TRANSLATION_CACHE_INSTR 5 |
167 |
#define N_TRANSLATION_CACHE_DATA 5 |
168 |
|
169 |
struct translation_cache_entry { |
170 |
int wf; |
171 |
uint64_t vaddr_pfn; |
172 |
uint64_t paddr; |
173 |
}; |
174 |
|
175 |
/* This should be a value which the program counter |
176 |
can "never" have: */ |
177 |
#define PC_LAST_PAGE_IMPOSSIBLE_VALUE 3 |
178 |
|
179 |
/* An "impossible" paddr: */ |
180 |
#define IMPOSSIBLE_PADDR 0x1212343456566767ULL |
181 |
|
182 |
#define DEFAULT_PCACHE_SIZE 15 /* 32 KB */ |
183 |
#define DEFAULT_PCACHE_LINESIZE 5 /* 32 bytes */ |
184 |
|
185 |
struct r3000_cache_line { |
186 |
uint32_t tag_paddr; |
187 |
int tag_valid; |
188 |
}; |
189 |
#define R3000_TAG_VALID 1 |
190 |
#define R3000_TAG_DIRTY 2 |
191 |
|
192 |
struct r4000_cache_line { |
193 |
char dummy; |
194 |
}; |
195 |
|
196 |
#define BINTRANS_DONT_RUN_NEXT 0x1000000 |
197 |
#define BINTRANS_N_MASK 0x0ffffff |
198 |
|
199 |
#define N_SAFE_BINTRANS_LIMIT_SHIFT 14 |
200 |
#define N_SAFE_BINTRANS_LIMIT ((1 << (N_SAFE_BINTRANS_LIMIT_SHIFT - 1)) - 1) |
201 |
|
202 |
#define N_BINTRANS_VADDR_TO_HOST 20 |
203 |
|
204 |
/* Virtual to host address translation tables: */ |
205 |
struct vth32_table { |
206 |
void *haddr_entry[1024 * 2]; |
207 |
uint32_t paddr_entry[1024]; |
208 |
uint32_t *bintrans_chunks[1024]; |
209 |
struct vth32_table *next_free; |
210 |
int refcount; |
211 |
}; |
212 |
|
213 |
struct mips_cpu { |
214 |
struct mips_cpu_type_def cpu_type; |
215 |
|
216 |
struct mips_coproc *coproc[N_MIPS_COPROCS]; |
217 |
|
218 |
int compare_register_set; |
219 |
|
220 |
/* Special purpose registers: */ |
221 |
uint64_t pc_last; /* PC of last instruction */ |
222 |
uint64_t hi; |
223 |
uint64_t lo; |
224 |
|
225 |
/* General purpose registers: */ |
226 |
uint64_t gpr[N_MIPS_GPRS]; |
227 |
|
228 |
/* |
229 |
* The translation_cached stuff is used to speed up the |
230 |
* most recent lookups into the TLB. Whenever the TLB is |
231 |
* written to, translation_cached[] must be filled with zeros. |
232 |
*/ |
233 |
#ifdef USE_TINY_CACHE |
234 |
struct translation_cache_entry |
235 |
translation_cache_instr[N_TRANSLATION_CACHE_INSTR]; |
236 |
struct translation_cache_entry |
237 |
translation_cache_data[N_TRANSLATION_CACHE_DATA]; |
238 |
#endif |
239 |
|
240 |
/* |
241 |
* For faster memory lookup when running instructions: |
242 |
* |
243 |
* Reading memory to load instructions is a very common thing in the |
244 |
* emulator, and an instruction is very often read from the address |
245 |
* following the previously executed instruction. That means that we |
246 |
* don't have to go through the TLB each time. |
247 |
* |
248 |
* We then get the vaddr -> paddr translation for free. There is an |
249 |
* even better case when the paddr is a RAM address (as opposed to an |
250 |
* address in a memory mapped device). Then we can figure out the |
251 |
* address in the host's memory directly, and skip the paddr -> host |
252 |
* address calculation as well. |
253 |
* |
254 |
* A modification to the TLB should set the virtual_page variable to |
255 |
* an "impossible" value, so that there won't be a hit on the next |
256 |
* instruction. |
257 |
*/ |
258 |
uint64_t pc_last_virtual_page; |
259 |
uint64_t pc_last_physical_page; |
260 |
unsigned char *pc_last_host_4k_page; |
261 |
|
262 |
#ifdef BINTRANS |
263 |
int dont_run_next_bintrans; |
264 |
int bintrans_instructions_executed; /* set to the |
265 |
number of bintranslated instructions executed |
266 |
when running a bintrans codechunk */ |
267 |
int pc_bintrans_paddr_valid; |
268 |
uint64_t pc_bintrans_paddr; |
269 |
unsigned char *pc_bintrans_host_4kpage; |
270 |
|
271 |
/* Chunk base address: */ |
272 |
unsigned char *chunk_base_address; |
273 |
|
274 |
/* This should work for 32-bit MIPS emulation: */ |
275 |
struct vth32_table *vaddr_to_hostaddr_nulltable; |
276 |
struct vth32_table *vaddr_to_hostaddr_r2k3k_icachetable; |
277 |
struct vth32_table *vaddr_to_hostaddr_r2k3k_dcachetable; |
278 |
struct vth32_table **vaddr_to_hostaddr_table0_kernel; |
279 |
struct vth32_table **vaddr_to_hostaddr_table0_cacheisol_i; |
280 |
struct vth32_table **vaddr_to_hostaddr_table0_cacheisol_d; |
281 |
struct vth32_table **vaddr_to_hostaddr_table0_user; |
282 |
struct vth32_table **vaddr_to_hostaddr_table0; /* should point to kernel or user */ |
283 |
struct vth32_table *next_free_vth_table; |
284 |
|
285 |
/* For 64-bit (generic) emulation: */ |
286 |
unsigned char *(*fast_vaddr_to_hostaddr)(struct cpu *cpu, |
287 |
uint64_t vaddr, int writeflag); |
288 |
int bintrans_next_index; |
289 |
int bintrans_data_writable[N_BINTRANS_VADDR_TO_HOST]; |
290 |
uint64_t bintrans_data_vaddr[N_BINTRANS_VADDR_TO_HOST]; |
291 |
unsigned char *bintrans_data_hostpage[N_BINTRANS_VADDR_TO_HOST]; |
292 |
|
293 |
void (*bintrans_load_32bit)(struct cpu *); /* Note: incorrect args */ |
294 |
void (*bintrans_store_32bit)(struct cpu *); /* Note: incorrect args */ |
295 |
void (*bintrans_jump_to_32bit_pc)(struct cpu *); |
296 |
void (*bintrans_simple_exception)(struct cpu *, int); |
297 |
void (*bintrans_fast_rfe)(struct cpu *); |
298 |
void (*bintrans_fast_eret)(struct cpu *); |
299 |
void (*bintrans_fast_tlbwri)(struct cpu *, int); |
300 |
void (*bintrans_fast_tlbpr)(struct cpu *, int); |
301 |
#endif |
302 |
|
303 |
#ifdef ENABLE_MIPS16 |
304 |
int mips16; /* non-zero if MIPS16 code is allowed */ |
305 |
uint16_t mips16_extend; /* set on 'extend' instructions to the entire 16-bit extend instruction */ |
306 |
#endif |
307 |
|
308 |
#ifdef ENABLE_INSTRUCTION_DELAYS |
309 |
int instruction_delay; |
310 |
#endif |
311 |
|
312 |
int trace_tree_depth; |
313 |
|
314 |
uint64_t delay_jmpaddr; /* only used if delay_slot > 0 */ |
315 |
int delay_slot; |
316 |
int nullify_next; /* set to 1 if next instruction |
317 |
is to be nullified */ |
318 |
|
319 |
/* This is set to non-zero, if it is possible at all that an |
320 |
interrupt will occur. */ |
321 |
int cached_interrupt_is_possible; |
322 |
|
323 |
int show_trace_delay; /* 0=normal, > 0 = delay until show_trace */ |
324 |
uint64_t show_trace_addr; |
325 |
|
326 |
int last_was_jumptoself; |
327 |
int jump_to_self_reg; |
328 |
|
329 |
#ifdef MFHILO_DELAY |
330 |
int mfhi_delay; /* instructions since last mfhi */ |
331 |
int mflo_delay; /* instructions since last mflo */ |
332 |
#endif |
333 |
|
334 |
int rmw; /* Read-Modify-Write */ |
335 |
int rmw_len; /* Length of rmw modification */ |
336 |
uint64_t rmw_addr; /* Address of rmw modification */ |
337 |
|
338 |
/* |
339 |
* TODO: The R5900 has 128-bit registers. I'm not really sure |
340 |
* whether they are used a lot or not, at least with code produced |
341 |
* with gcc they are not. An important case however is lq and sq |
342 |
* (load and store of 128-bit values). These "upper halves" of R5900 |
343 |
* quadwords can be used in those cases. |
344 |
* |
345 |
* TODO: Generalize this. |
346 |
*/ |
347 |
uint64_t gpr_quadhi[N_MIPS_GPRS]; |
348 |
|
349 |
|
350 |
/* |
351 |
* Statistics: |
352 |
*/ |
353 |
long stats_opcode[N_HI6]; |
354 |
long stats__special[N_SPECIAL]; |
355 |
long stats__regimm[N_REGIMM]; |
356 |
long stats__special2[N_SPECIAL]; |
357 |
|
358 |
/* Data and Instruction caches: */ |
359 |
unsigned char *cache[2]; |
360 |
void *cache_tags[2]; |
361 |
uint64_t cache_last_paddr[2]; |
362 |
int cache_size[2]; |
363 |
int cache_linesize[2]; |
364 |
int cache_mask[2]; |
365 |
int cache_miss_penalty[2]; |
366 |
|
367 |
/* Other stuff: */ |
368 |
uint64_t cop0_config_select1; |
369 |
}; |
370 |
|
371 |
|
372 |
/* cpu_mips.c: */ |
373 |
void mips_cpu_show_full_statistics(struct machine *m); |
374 |
void mips_cpu_tlbdump(struct machine *m, int x, int rawflag); |
375 |
void mips_cpu_register_match(struct machine *m, char *name, |
376 |
int writeflag, uint64_t *valuep, int *match_register); |
377 |
void mips_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs); |
378 |
int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, |
379 |
int running, uint64_t addr, int bintrans); |
380 |
int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr); |
381 |
int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr); |
382 |
void mips_cpu_exception(struct cpu *cpu, int exccode, int tlb, uint64_t vaddr, |
383 |
/* uint64_t pagemask, */ int coproc_nr, uint64_t vaddr_vpn2, |
384 |
int vaddr_asid, int x_64); |
385 |
void mips_cpu_cause_simple_exception(struct cpu *cpu, int exc_code); |
386 |
int mips_cpu_run(struct emul *emul, struct machine *machine); |
387 |
void mips_cpu_dumpinfo(struct cpu *cpu); |
388 |
void mips_cpu_list_available_types(void); |
389 |
int mips_cpu_family_init(struct cpu_family *); |
390 |
|
391 |
|
392 |
/* cpu_mips_coproc.c: */ |
393 |
struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr); |
394 |
void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size, |
395 |
uint64_t vaddr, uint64_t paddr0, uint64_t paddr1, |
396 |
int valid0, int valid1, int dirty0, int dirty1, int global, int asid, |
397 |
int cachealgo0, int cachealgo1); |
398 |
void update_translation_table(struct cpu *cpu, uint64_t vaddr_page, |
399 |
unsigned char *host_page, int writeflag, uint64_t paddr_page); |
400 |
void clear_all_chunks_from_all_tables(struct cpu *cpu); |
401 |
void mips_invalidate_translation_caches_paddr(struct cpu *cpu, uint64_t paddr); |
402 |
void coproc_register_read(struct cpu *cpu, |
403 |
struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select); |
404 |
void coproc_register_write(struct cpu *cpu, |
405 |
struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64, |
406 |
int select); |
407 |
void coproc_tlbpr(struct cpu *cpu, int readflag); |
408 |
void coproc_tlbwri(struct cpu *cpu, int randomflag); |
409 |
void coproc_rfe(struct cpu *cpu); |
410 |
void coproc_eret(struct cpu *cpu); |
411 |
void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr, |
412 |
uint32_t function, int unassemble_only, int running); |
413 |
|
414 |
|
415 |
/* memory_mips.c: */ |
416 |
int memory_cache_R3000(struct cpu *cpu, int cache, uint64_t paddr, |
417 |
int writeflag, size_t len, unsigned char *data); |
418 |
int mips_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, |
419 |
unsigned char *data, size_t len, int writeflag, int cache_flags); |
420 |
|
421 |
|
422 |
/* mips16.c: */ |
423 |
int mips16_to_32(struct cpu *cpu, unsigned char *instr16, unsigned char *instr); |
424 |
|
425 |
|
426 |
#endif /* CPU_MIPS_H */ |