Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ 6af0bf9c

History | View | Annotate | Download (14.9 kB)

1 6af0bf9c bellard
/*
2 6af0bf9c bellard
 *  MIPS emulation helpers for qemu.
3 6af0bf9c bellard
 * 
4 6af0bf9c bellard
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5 6af0bf9c bellard
 *
6 6af0bf9c bellard
 * This library is free software; you can redistribute it and/or
7 6af0bf9c bellard
 * modify it under the terms of the GNU Lesser General Public
8 6af0bf9c bellard
 * License as published by the Free Software Foundation; either
9 6af0bf9c bellard
 * version 2 of the License, or (at your option) any later version.
10 6af0bf9c bellard
 *
11 6af0bf9c bellard
 * This library is distributed in the hope that it will be useful,
12 6af0bf9c bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 6af0bf9c bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 6af0bf9c bellard
 * Lesser General Public License for more details.
15 6af0bf9c bellard
 *
16 6af0bf9c bellard
 * You should have received a copy of the GNU Lesser General Public
17 6af0bf9c bellard
 * License along with this library; if not, write to the Free Software
18 6af0bf9c bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 6af0bf9c bellard
 */
20 6af0bf9c bellard
#include <math.h>
21 6af0bf9c bellard
#include "exec.h"
22 6af0bf9c bellard
23 6af0bf9c bellard
#define MIPS_DEBUG_DISAS
24 6af0bf9c bellard
25 6af0bf9c bellard
/*****************************************************************************/
26 6af0bf9c bellard
/* Exceptions processing helpers */
27 6af0bf9c bellard
void cpu_loop_exit(void)
28 6af0bf9c bellard
{
29 6af0bf9c bellard
    longjmp(env->jmp_env, 1);
30 6af0bf9c bellard
}
31 6af0bf9c bellard
32 6af0bf9c bellard
__attribute__ (( regparm(2) ))
33 6af0bf9c bellard
void do_raise_exception_err (uint32_t exception, int error_code)
34 6af0bf9c bellard
{
35 6af0bf9c bellard
#if 1
36 6af0bf9c bellard
    if (logfile && exception < 0x100)
37 6af0bf9c bellard
        fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
38 6af0bf9c bellard
#endif
39 6af0bf9c bellard
    env->exception_index = exception;
40 6af0bf9c bellard
    env->error_code = error_code;
41 6af0bf9c bellard
    T0 = 0;
42 6af0bf9c bellard
    cpu_loop_exit();
43 6af0bf9c bellard
}
44 6af0bf9c bellard
45 6af0bf9c bellard
__attribute__ (( regparm(1) ))
46 6af0bf9c bellard
void do_raise_exception (uint32_t exception)
47 6af0bf9c bellard
{
48 6af0bf9c bellard
    do_raise_exception_err(exception, 0);
49 6af0bf9c bellard
}
50 6af0bf9c bellard
51 6af0bf9c bellard
#define MEMSUFFIX _raw
52 6af0bf9c bellard
#include "op_helper_mem.c"
53 6af0bf9c bellard
#undef MEMSUFFIX
54 6af0bf9c bellard
#if !defined(CONFIG_USER_ONLY)
55 6af0bf9c bellard
#define MEMSUFFIX _user
56 6af0bf9c bellard
#include "op_helper_mem.c"
57 6af0bf9c bellard
#undef MEMSUFFIX
58 6af0bf9c bellard
#define MEMSUFFIX _kernel
59 6af0bf9c bellard
#include "op_helper_mem.c"
60 6af0bf9c bellard
#undef MEMSUFFIX
61 6af0bf9c bellard
#endif
62 6af0bf9c bellard
63 6af0bf9c bellard
/* 64 bits arithmetic for 32 bits hosts */
64 6af0bf9c bellard
#if (HOST_LONG_BITS == 32)
65 6af0bf9c bellard
static inline uint64_t get_HILO (void)
66 6af0bf9c bellard
{
67 6af0bf9c bellard
    return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
68 6af0bf9c bellard
}
69 6af0bf9c bellard
70 6af0bf9c bellard
static inline void set_HILO (uint64_t HILO)
71 6af0bf9c bellard
{
72 6af0bf9c bellard
    env->LO = HILO & 0xFFFFFFFF;
73 6af0bf9c bellard
    env->HI = HILO >> 32;
74 6af0bf9c bellard
}
75 6af0bf9c bellard
76 6af0bf9c bellard
void do_mult (void)
77 6af0bf9c bellard
{
78 6af0bf9c bellard
    set_HILO((int64_t)T0 * (int64_t)T1);
79 6af0bf9c bellard
}
80 6af0bf9c bellard
81 6af0bf9c bellard
void do_multu (void)
82 6af0bf9c bellard
{
83 6af0bf9c bellard
    set_HILO((uint64_t)T0 * (uint64_t)T1);
84 6af0bf9c bellard
}
85 6af0bf9c bellard
86 6af0bf9c bellard
void do_madd (void)
87 6af0bf9c bellard
{
88 6af0bf9c bellard
    int64_t tmp;
89 6af0bf9c bellard
90 6af0bf9c bellard
    tmp = ((int64_t)T0 * (int64_t)T1);
91 6af0bf9c bellard
    set_HILO((int64_t)get_HILO() + tmp);
92 6af0bf9c bellard
}
93 6af0bf9c bellard
94 6af0bf9c bellard
void do_maddu (void)
95 6af0bf9c bellard
{
96 6af0bf9c bellard
    uint64_t tmp;
97 6af0bf9c bellard
98 6af0bf9c bellard
    tmp = ((uint64_t)T0 * (uint64_t)T1);
99 6af0bf9c bellard
    set_HILO(get_HILO() + tmp);
100 6af0bf9c bellard
}
101 6af0bf9c bellard
102 6af0bf9c bellard
void do_msub (void)
103 6af0bf9c bellard
{
104 6af0bf9c bellard
    int64_t tmp;
105 6af0bf9c bellard
106 6af0bf9c bellard
    tmp = ((int64_t)T0 * (int64_t)T1);
107 6af0bf9c bellard
    set_HILO((int64_t)get_HILO() - tmp);
108 6af0bf9c bellard
}
109 6af0bf9c bellard
110 6af0bf9c bellard
void do_msubu (void)
111 6af0bf9c bellard
{
112 6af0bf9c bellard
    uint64_t tmp;
113 6af0bf9c bellard
114 6af0bf9c bellard
    tmp = ((uint64_t)T0 * (uint64_t)T1);
115 6af0bf9c bellard
    set_HILO(get_HILO() - tmp);
116 6af0bf9c bellard
}
117 6af0bf9c bellard
#endif
118 6af0bf9c bellard
119 6af0bf9c bellard
/* CP0 helpers */
120 6af0bf9c bellard
__attribute__ (( regparm(2) ))
121 6af0bf9c bellard
void do_mfc0 (int reg, int sel)
122 6af0bf9c bellard
{
123 6af0bf9c bellard
    const unsigned char *rn;
124 6af0bf9c bellard
125 6af0bf9c bellard
    if (sel != 0 && reg != 16 && reg != 28) {
126 6af0bf9c bellard
        rn = "invalid";
127 6af0bf9c bellard
        goto print;
128 6af0bf9c bellard
    }
129 6af0bf9c bellard
    switch (reg) {
130 6af0bf9c bellard
    case 0:
131 6af0bf9c bellard
        T0 = env->CP0_index;
132 6af0bf9c bellard
        rn = "Index";
133 6af0bf9c bellard
        break;
134 6af0bf9c bellard
    case 1:
135 6af0bf9c bellard
        T0 = cpu_mips_get_random(env);
136 6af0bf9c bellard
        rn = "Random";
137 6af0bf9c bellard
        break;
138 6af0bf9c bellard
    case 2:
139 6af0bf9c bellard
        T0 = env->CP0_EntryLo0;
140 6af0bf9c bellard
        rn = "EntryLo0";
141 6af0bf9c bellard
        break;
142 6af0bf9c bellard
    case 3:
143 6af0bf9c bellard
        T0 = env->CP0_EntryLo1;
144 6af0bf9c bellard
        rn = "EntryLo1";
145 6af0bf9c bellard
        break;
146 6af0bf9c bellard
    case 4:
147 6af0bf9c bellard
        T0 = env->CP0_Context;
148 6af0bf9c bellard
        rn = "Context";
149 6af0bf9c bellard
        break;
150 6af0bf9c bellard
    case 5:
151 6af0bf9c bellard
        T0 = env->CP0_PageMask;
152 6af0bf9c bellard
        rn = "PageMask";
153 6af0bf9c bellard
        break;
154 6af0bf9c bellard
    case 6:
155 6af0bf9c bellard
        T0 = env->CP0_Wired;
156 6af0bf9c bellard
        rn = "Wired";
157 6af0bf9c bellard
        break;
158 6af0bf9c bellard
    case 8:
159 6af0bf9c bellard
        T0 = env->CP0_BadVAddr;
160 6af0bf9c bellard
        rn = "BadVaddr";
161 6af0bf9c bellard
        break;
162 6af0bf9c bellard
    case 9:
163 6af0bf9c bellard
        T0 = cpu_mips_get_count(env);
164 6af0bf9c bellard
        rn = "Count";
165 6af0bf9c bellard
        break;
166 6af0bf9c bellard
    case 10:
167 6af0bf9c bellard
        T0 = env->CP0_EntryHi;
168 6af0bf9c bellard
        rn = "EntryHi";
169 6af0bf9c bellard
        break;
170 6af0bf9c bellard
    case 11:
171 6af0bf9c bellard
        T0 = env->CP0_Compare;
172 6af0bf9c bellard
        rn = "Compare";
173 6af0bf9c bellard
        break;
174 6af0bf9c bellard
    case 12:
175 6af0bf9c bellard
        T0 = env->CP0_Status;
176 6af0bf9c bellard
        if (env->hflags & MIPS_HFLAG_UM)
177 6af0bf9c bellard
            T0 |= CP0St_UM;
178 6af0bf9c bellard
        if (env->hflags & MIPS_HFLAG_ERL)
179 6af0bf9c bellard
            T0 |= CP0St_ERL;
180 6af0bf9c bellard
        if (env->hflags & MIPS_HFLAG_EXL)
181 6af0bf9c bellard
            T0 |= CP0St_EXL;
182 6af0bf9c bellard
        rn = "Status";
183 6af0bf9c bellard
        break;
184 6af0bf9c bellard
    case 13:
185 6af0bf9c bellard
        T0 = env->CP0_Cause;
186 6af0bf9c bellard
        rn = "Cause";
187 6af0bf9c bellard
        break;
188 6af0bf9c bellard
    case 14:
189 6af0bf9c bellard
        T0 = env->CP0_EPC;
190 6af0bf9c bellard
        rn = "EPC";
191 6af0bf9c bellard
        break;
192 6af0bf9c bellard
    case 15:
193 6af0bf9c bellard
        T0 = env->CP0_PRid;
194 6af0bf9c bellard
        rn = "PRid";
195 6af0bf9c bellard
        break;
196 6af0bf9c bellard
    case 16:
197 6af0bf9c bellard
        switch (sel) {
198 6af0bf9c bellard
        case 0:
199 6af0bf9c bellard
            T0 = env->CP0_Config0;
200 6af0bf9c bellard
            rn = "Config";
201 6af0bf9c bellard
            break;
202 6af0bf9c bellard
        case 1:
203 6af0bf9c bellard
            T0 = env->CP0_Config1;
204 6af0bf9c bellard
            rn = "Config1";
205 6af0bf9c bellard
            break;
206 6af0bf9c bellard
        default:
207 6af0bf9c bellard
            rn = "Unknown config register";
208 6af0bf9c bellard
            break;
209 6af0bf9c bellard
        }
210 6af0bf9c bellard
        break;
211 6af0bf9c bellard
    case 17:
212 6af0bf9c bellard
        T0 = env->CP0_LLAddr >> 4;
213 6af0bf9c bellard
        rn = "LLAddr";
214 6af0bf9c bellard
        break;
215 6af0bf9c bellard
    case 18:
216 6af0bf9c bellard
        T0 = env->CP0_WatchLo;
217 6af0bf9c bellard
        rn = "WatchLo";
218 6af0bf9c bellard
        break;
219 6af0bf9c bellard
    case 19:
220 6af0bf9c bellard
        T0 = env->CP0_WatchHi;
221 6af0bf9c bellard
        rn = "WatchHi";
222 6af0bf9c bellard
        break;
223 6af0bf9c bellard
    case 23:
224 6af0bf9c bellard
        T0 = env->CP0_Debug;
225 6af0bf9c bellard
        if (env->hflags & MIPS_HFLAG_DM)
226 6af0bf9c bellard
            T0 |= 1 << CP0DB_DM;
227 6af0bf9c bellard
        rn = "Debug";
228 6af0bf9c bellard
        break;
229 6af0bf9c bellard
    case 24:
230 6af0bf9c bellard
        T0 = env->CP0_DEPC;
231 6af0bf9c bellard
        rn = "DEPC";
232 6af0bf9c bellard
        break;
233 6af0bf9c bellard
    case 28:
234 6af0bf9c bellard
        switch (sel) {
235 6af0bf9c bellard
        case 0:
236 6af0bf9c bellard
            T0 = env->CP0_TagLo;
237 6af0bf9c bellard
            rn = "TagLo";
238 6af0bf9c bellard
            break;
239 6af0bf9c bellard
        case 1:
240 6af0bf9c bellard
            T0 = env->CP0_DataLo;
241 6af0bf9c bellard
            rn = "DataLo";
242 6af0bf9c bellard
            break;
243 6af0bf9c bellard
        default:
244 6af0bf9c bellard
            rn = "unknown sel";
245 6af0bf9c bellard
            break;
246 6af0bf9c bellard
        }
247 6af0bf9c bellard
        break;
248 6af0bf9c bellard
    case 30:
249 6af0bf9c bellard
        T0 = env->CP0_ErrorEPC;
250 6af0bf9c bellard
        rn = "ErrorEPC";
251 6af0bf9c bellard
        break;
252 6af0bf9c bellard
    case 31:
253 6af0bf9c bellard
        T0 = env->CP0_DESAVE;
254 6af0bf9c bellard
        rn = "DESAVE";
255 6af0bf9c bellard
        break;
256 6af0bf9c bellard
    default:
257 6af0bf9c bellard
        rn = "unknown";
258 6af0bf9c bellard
        break;
259 6af0bf9c bellard
    }
260 6af0bf9c bellard
 print:
261 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
262 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {
263 6af0bf9c bellard
        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
264 6af0bf9c bellard
                env->PC, rn, T0, reg, sel);
265 6af0bf9c bellard
    }
266 6af0bf9c bellard
#endif
267 6af0bf9c bellard
    return;
268 6af0bf9c bellard
}
269 6af0bf9c bellard
270 6af0bf9c bellard
__attribute__ (( regparm(2) ))
271 6af0bf9c bellard
void do_mtc0 (int reg, int sel)
272 6af0bf9c bellard
{
273 6af0bf9c bellard
    const unsigned char *rn;
274 6af0bf9c bellard
    uint32_t val, old, mask;
275 6af0bf9c bellard
    int i, raise;
276 6af0bf9c bellard
277 6af0bf9c bellard
    if (sel != 0 && reg != 16 && reg != 28) {
278 6af0bf9c bellard
        val = -1;
279 6af0bf9c bellard
        old = -1;
280 6af0bf9c bellard
        rn = "invalid";
281 6af0bf9c bellard
        goto print;
282 6af0bf9c bellard
    }
283 6af0bf9c bellard
    switch (reg) {
284 6af0bf9c bellard
    case 0:
285 6af0bf9c bellard
        val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
286 6af0bf9c bellard
        old = env->CP0_index;
287 6af0bf9c bellard
        env->CP0_index = val;
288 6af0bf9c bellard
        rn = "Index";
289 6af0bf9c bellard
        break;
290 6af0bf9c bellard
    case 2:
291 6af0bf9c bellard
        val = T0 & 0x03FFFFFFF;
292 6af0bf9c bellard
        old = env->CP0_EntryLo0;
293 6af0bf9c bellard
        env->CP0_EntryLo0 = val;
294 6af0bf9c bellard
        rn = "EntryLo0";
295 6af0bf9c bellard
        break;
296 6af0bf9c bellard
    case 3:
297 6af0bf9c bellard
        val = T0 & 0x03FFFFFFF;
298 6af0bf9c bellard
        old = env->CP0_EntryLo1;
299 6af0bf9c bellard
        env->CP0_EntryLo1 = val;
300 6af0bf9c bellard
        rn = "EntryLo1";
301 6af0bf9c bellard
        break;
302 6af0bf9c bellard
    case 4:
303 6af0bf9c bellard
        val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
304 6af0bf9c bellard
        old = env->CP0_Context;
305 6af0bf9c bellard
        env->CP0_Context = val;
306 6af0bf9c bellard
        rn = "Context";
307 6af0bf9c bellard
        break;
308 6af0bf9c bellard
    case 5:
309 6af0bf9c bellard
        val = T0 & 0x01FFE000;
310 6af0bf9c bellard
        old = env->CP0_PageMask;
311 6af0bf9c bellard
        env->CP0_PageMask = val;
312 6af0bf9c bellard
        rn = "PageMask";
313 6af0bf9c bellard
        break;
314 6af0bf9c bellard
    case 6:
315 6af0bf9c bellard
        val = T0 & 0x0000000F;
316 6af0bf9c bellard
        old = env->CP0_Wired;
317 6af0bf9c bellard
        env->CP0_Wired = val;
318 6af0bf9c bellard
        rn = "Wired";
319 6af0bf9c bellard
        break;
320 6af0bf9c bellard
    case 9:
321 6af0bf9c bellard
        val = T0;
322 6af0bf9c bellard
        old = cpu_mips_get_count(env);
323 6af0bf9c bellard
        cpu_mips_store_count(env, val);
324 6af0bf9c bellard
        rn = "Count";
325 6af0bf9c bellard
        break;
326 6af0bf9c bellard
    case 10:
327 6af0bf9c bellard
        val = T0 & 0xFFFFF0FF;
328 6af0bf9c bellard
        old = env->CP0_EntryHi;
329 6af0bf9c bellard
        env->CP0_EntryHi = val;
330 6af0bf9c bellard
        rn = "EntryHi";
331 6af0bf9c bellard
        break;
332 6af0bf9c bellard
    case 11:
333 6af0bf9c bellard
        val = T0;
334 6af0bf9c bellard
        old = env->CP0_Compare;
335 6af0bf9c bellard
        cpu_mips_store_compare(env, val);
336 6af0bf9c bellard
        rn = "Compare";
337 6af0bf9c bellard
        break;
338 6af0bf9c bellard
    case 12:
339 6af0bf9c bellard
        val = T0 & 0xFA78FF01;
340 6af0bf9c bellard
        if (T0 & (1 << CP0St_UM))
341 6af0bf9c bellard
            env->hflags |= MIPS_HFLAG_UM;
342 6af0bf9c bellard
        else
343 6af0bf9c bellard
            env->hflags &= ~MIPS_HFLAG_UM;
344 6af0bf9c bellard
        if (T0 & (1 << CP0St_ERL))
345 6af0bf9c bellard
            env->hflags |= MIPS_HFLAG_ERL;
346 6af0bf9c bellard
        else
347 6af0bf9c bellard
            env->hflags &= ~MIPS_HFLAG_ERL;
348 6af0bf9c bellard
        if (T0 & (1 << CP0St_EXL))
349 6af0bf9c bellard
            env->hflags |= MIPS_HFLAG_EXL;
350 6af0bf9c bellard
        else
351 6af0bf9c bellard
            env->hflags &= ~MIPS_HFLAG_EXL;
352 6af0bf9c bellard
        old = env->CP0_Status;
353 6af0bf9c bellard
        env->CP0_Status = val;
354 6af0bf9c bellard
        /* If we unmasked an asserted IRQ, raise it */
355 6af0bf9c bellard
        mask = 0x0000FC00;
356 6af0bf9c bellard
        if (loglevel & CPU_LOG_TB_IN_ASM) {
357 6af0bf9c bellard
            fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
358 6af0bf9c bellard
                    old, val, env->CP0_Cause, old & mask, val & mask,
359 6af0bf9c bellard
                    env->CP0_Cause & mask);
360 6af0bf9c bellard
        }
361 6af0bf9c bellard
#if 1
362 6af0bf9c bellard
        if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
363 6af0bf9c bellard
            !(env->hflags & MIPS_HFLAG_EXL) &&
364 6af0bf9c bellard
            !(env->hflags & MIPS_HFLAG_ERL) &&
365 6af0bf9c bellard
            !(env->hflags & MIPS_HFLAG_DM) && 
366 6af0bf9c bellard
            (env->CP0_Cause & mask)) {
367 6af0bf9c bellard
            if (logfile)
368 6af0bf9c bellard
                fprintf(logfile, "Raise pending IRQs\n");
369 6af0bf9c bellard
            env->interrupt_request |= CPU_INTERRUPT_HARD;
370 6af0bf9c bellard
            do_raise_exception(EXCP_EXT_INTERRUPT);
371 6af0bf9c bellard
        } else if (!(val & 0x00000001) && (old & 0x00000001)) {
372 6af0bf9c bellard
            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
373 6af0bf9c bellard
        }
374 6af0bf9c bellard
#endif
375 6af0bf9c bellard
        rn = "Status";
376 6af0bf9c bellard
        break;
377 6af0bf9c bellard
    case 13:
378 6af0bf9c bellard
        val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
379 6af0bf9c bellard
        old = env->CP0_Cause;
380 6af0bf9c bellard
        env->CP0_Cause = val;
381 6af0bf9c bellard
#if 0
382 6af0bf9c bellard
        /* Check if we ever asserted a software IRQ */
383 6af0bf9c bellard
        for (i = 0; i < 2; i++) {
384 6af0bf9c bellard
            mask = 0x100 << i;
385 6af0bf9c bellard
            if ((val & mask) & !(old & mask))
386 6af0bf9c bellard
                mips_set_irq(i);
387 6af0bf9c bellard
        }
388 6af0bf9c bellard
#endif
389 6af0bf9c bellard
        rn = "Cause";
390 6af0bf9c bellard
        break;
391 6af0bf9c bellard
    case 14:
392 6af0bf9c bellard
        val = T0;
393 6af0bf9c bellard
        old = env->CP0_EPC;
394 6af0bf9c bellard
        env->CP0_EPC = val;
395 6af0bf9c bellard
        rn = "EPC";
396 6af0bf9c bellard
        break;
397 6af0bf9c bellard
    case 16:
398 6af0bf9c bellard
        switch (sel) {
399 6af0bf9c bellard
        case 0:
400 6af0bf9c bellard
#if defined(MIPS_USES_R4K_TLB)
401 6af0bf9c bellard
            val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
402 6af0bf9c bellard
#else
403 6af0bf9c bellard
            val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
404 6af0bf9c bellard
#endif
405 6af0bf9c bellard
            old = env->CP0_Config0;
406 6af0bf9c bellard
            env->CP0_Config0 = val;
407 6af0bf9c bellard
            rn = "Config0";
408 6af0bf9c bellard
            break;
409 6af0bf9c bellard
        default:
410 6af0bf9c bellard
            val = -1;
411 6af0bf9c bellard
            old = -1;
412 6af0bf9c bellard
            rn = "bad config selector";
413 6af0bf9c bellard
            break;
414 6af0bf9c bellard
        }
415 6af0bf9c bellard
        break;
416 6af0bf9c bellard
    case 18:
417 6af0bf9c bellard
        val = T0;
418 6af0bf9c bellard
        old = env->CP0_WatchLo;
419 6af0bf9c bellard
        env->CP0_WatchLo = val;
420 6af0bf9c bellard
        rn = "WatchLo";
421 6af0bf9c bellard
        break;
422 6af0bf9c bellard
    case 19:
423 6af0bf9c bellard
        val = T0 & 0x40FF0FF8;
424 6af0bf9c bellard
        old = env->CP0_WatchHi;
425 6af0bf9c bellard
        env->CP0_WatchHi = val;
426 6af0bf9c bellard
        rn = "WatchHi";
427 6af0bf9c bellard
        break;
428 6af0bf9c bellard
    case 23:
429 6af0bf9c bellard
        val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
430 6af0bf9c bellard
        if (T0 & (1 << CP0DB_DM))
431 6af0bf9c bellard
            env->hflags |= MIPS_HFLAG_DM;
432 6af0bf9c bellard
        else
433 6af0bf9c bellard
            env->hflags &= ~MIPS_HFLAG_DM;
434 6af0bf9c bellard
        old = env->CP0_Debug;
435 6af0bf9c bellard
        env->CP0_Debug = val;
436 6af0bf9c bellard
        rn = "Debug";
437 6af0bf9c bellard
        break;
438 6af0bf9c bellard
    case 24:
439 6af0bf9c bellard
        val = T0;
440 6af0bf9c bellard
        old = env->CP0_DEPC;
441 6af0bf9c bellard
        env->CP0_DEPC = val;
442 6af0bf9c bellard
        rn = "DEPC";
443 6af0bf9c bellard
        break;
444 6af0bf9c bellard
    case 28:
445 6af0bf9c bellard
        switch (sel) {
446 6af0bf9c bellard
        case 0:
447 6af0bf9c bellard
            val = T0 & 0xFFFFFCF6;
448 6af0bf9c bellard
            old = env->CP0_TagLo;
449 6af0bf9c bellard
            env->CP0_TagLo = val;
450 6af0bf9c bellard
            rn = "TagLo";
451 6af0bf9c bellard
            break;
452 6af0bf9c bellard
        default:
453 6af0bf9c bellard
            val = -1;
454 6af0bf9c bellard
            old = -1;
455 6af0bf9c bellard
            rn = "invalid sel";
456 6af0bf9c bellard
            break;
457 6af0bf9c bellard
        }
458 6af0bf9c bellard
        break;
459 6af0bf9c bellard
    case 30:
460 6af0bf9c bellard
        val = T0;
461 6af0bf9c bellard
        old = env->CP0_ErrorEPC;
462 6af0bf9c bellard
        env->CP0_ErrorEPC = val;
463 6af0bf9c bellard
        rn = "EPC";
464 6af0bf9c bellard
        break;
465 6af0bf9c bellard
    case 31:
466 6af0bf9c bellard
        val = T0;
467 6af0bf9c bellard
        old = env->CP0_DESAVE;
468 6af0bf9c bellard
        env->CP0_DESAVE = val;
469 6af0bf9c bellard
        rn = "DESAVE";
470 6af0bf9c bellard
        break;
471 6af0bf9c bellard
    default:
472 6af0bf9c bellard
        val = -1;
473 6af0bf9c bellard
        old = -1;
474 6af0bf9c bellard
        rn = "unknown";
475 6af0bf9c bellard
        break;
476 6af0bf9c bellard
    }
477 6af0bf9c bellard
 print:
478 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
479 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {
480 6af0bf9c bellard
        fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
481 6af0bf9c bellard
                env->PC, rn, T0, val, reg, sel, old);
482 6af0bf9c bellard
    }
483 6af0bf9c bellard
#endif
484 6af0bf9c bellard
    return;
485 6af0bf9c bellard
}
486 6af0bf9c bellard
487 6af0bf9c bellard
/* TLB management */
488 6af0bf9c bellard
#if defined(MIPS_USES_R4K_TLB)
489 6af0bf9c bellard
__attribute__ (( regparm(1) ))
490 6af0bf9c bellard
static void invalidate_tb (int idx)
491 6af0bf9c bellard
{
492 6af0bf9c bellard
    tlb_t *tlb;
493 6af0bf9c bellard
    target_ulong addr, end;
494 6af0bf9c bellard
495 6af0bf9c bellard
    tlb = &env->tlb[idx];
496 6af0bf9c bellard
    if (tlb->V[0]) {
497 6af0bf9c bellard
        addr = tlb->PFN[0];
498 6af0bf9c bellard
        end = addr + (tlb->end - tlb->VPN);
499 6af0bf9c bellard
        tb_invalidate_page_range(addr, end);
500 6af0bf9c bellard
    }
501 6af0bf9c bellard
    if (tlb->V[1]) {
502 6af0bf9c bellard
        addr = tlb->PFN[1];
503 6af0bf9c bellard
        end = addr + (tlb->end - tlb->VPN);
504 6af0bf9c bellard
        tb_invalidate_page_range(addr, end);
505 6af0bf9c bellard
    }
506 6af0bf9c bellard
}
507 6af0bf9c bellard
508 6af0bf9c bellard
__attribute__ (( regparm(1) ))
509 6af0bf9c bellard
static void fill_tb (int idx)
510 6af0bf9c bellard
{
511 6af0bf9c bellard
    tlb_t *tlb;
512 6af0bf9c bellard
    int size;
513 6af0bf9c bellard
514 6af0bf9c bellard
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
515 6af0bf9c bellard
    tlb = &env->tlb[idx];
516 6af0bf9c bellard
    tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
517 6af0bf9c bellard
    tlb->ASID = env->CP0_EntryHi & 0x000000FF;
518 6af0bf9c bellard
    size = env->CP0_PageMask >> 13;
519 6af0bf9c bellard
    size = 4 * (size + 1);
520 6af0bf9c bellard
    tlb->end = tlb->VPN + (1 << (8 + size));
521 6af0bf9c bellard
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
522 6af0bf9c bellard
    tlb->V[0] = env->CP0_EntryLo0 & 2;
523 6af0bf9c bellard
    tlb->D[0] = env->CP0_EntryLo0 & 4;
524 6af0bf9c bellard
    tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
525 6af0bf9c bellard
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
526 6af0bf9c bellard
    tlb->V[1] = env->CP0_EntryLo1 & 2;
527 6af0bf9c bellard
    tlb->D[1] = env->CP0_EntryLo1 & 4;
528 6af0bf9c bellard
    tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
529 6af0bf9c bellard
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
530 6af0bf9c bellard
}
531 6af0bf9c bellard
532 6af0bf9c bellard
void do_tlbwi (void)
533 6af0bf9c bellard
{
534 6af0bf9c bellard
    invalidate_tb(env->CP0_index & 0xF);
535 6af0bf9c bellard
    fill_tb(env->CP0_index & 0xF);
536 6af0bf9c bellard
}
537 6af0bf9c bellard
538 6af0bf9c bellard
void do_tlbwr (void)
539 6af0bf9c bellard
{
540 6af0bf9c bellard
    int r = cpu_mips_get_random(env);
541 6af0bf9c bellard
542 6af0bf9c bellard
    invalidate_tb(r);
543 6af0bf9c bellard
    fill_tb(r);
544 6af0bf9c bellard
}
545 6af0bf9c bellard
546 6af0bf9c bellard
void do_tlbp (void)
547 6af0bf9c bellard
{
548 6af0bf9c bellard
    tlb_t *tlb;
549 6af0bf9c bellard
    target_ulong tag;
550 6af0bf9c bellard
    uint8_t ASID;
551 6af0bf9c bellard
    int i;
552 6af0bf9c bellard
553 6af0bf9c bellard
    tag = (env->CP0_EntryHi & 0xFFFFE000);
554 6af0bf9c bellard
    ASID = env->CP0_EntryHi & 0x000000FF;
555 6af0bf9c bellard
        for (i = 0; i < 16; i++) {
556 6af0bf9c bellard
        tlb = &env->tlb[i];
557 6af0bf9c bellard
        /* Check ASID, virtual page number & size */
558 6af0bf9c bellard
        if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
559 6af0bf9c bellard
            /* TLB match */
560 6af0bf9c bellard
            env->CP0_index = i;
561 6af0bf9c bellard
            break;
562 6af0bf9c bellard
        }
563 6af0bf9c bellard
    }
564 6af0bf9c bellard
    if (i == 16) {
565 6af0bf9c bellard
        env->CP0_index |= 0x80000000;
566 6af0bf9c bellard
    }
567 6af0bf9c bellard
}
568 6af0bf9c bellard
569 6af0bf9c bellard
void do_tlbr (void)
570 6af0bf9c bellard
{
571 6af0bf9c bellard
    tlb_t *tlb;
572 6af0bf9c bellard
    int size;
573 6af0bf9c bellard
574 6af0bf9c bellard
    tlb = &env->tlb[env->CP0_index & 0xF];
575 6af0bf9c bellard
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
576 6af0bf9c bellard
    size = (tlb->end - tlb->VPN) >> 12;
577 6af0bf9c bellard
    env->CP0_PageMask = (size - 1) << 13;
578 6af0bf9c bellard
    env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
579 6af0bf9c bellard
        (tlb->PFN[0] >> 6);
580 6af0bf9c bellard
    env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
581 6af0bf9c bellard
        (tlb->PFN[1] >> 6);
582 6af0bf9c bellard
}
583 6af0bf9c bellard
#endif
584 6af0bf9c bellard
585 6af0bf9c bellard
__attribute__ (( regparm(1) ))
586 6af0bf9c bellard
void op_dump_ldst (const unsigned char *func)
587 6af0bf9c bellard
{
588 6af0bf9c bellard
    if (loglevel)
589 6af0bf9c bellard
        fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
590 6af0bf9c bellard
}
591 6af0bf9c bellard
592 6af0bf9c bellard
void dump_sc (void)
593 6af0bf9c bellard
{
594 6af0bf9c bellard
    if (loglevel) {
595 6af0bf9c bellard
        fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
596 6af0bf9c bellard
                T1, T0, env->CP0_LLAddr);
597 6af0bf9c bellard
    }
598 6af0bf9c bellard
}
599 6af0bf9c bellard
600 6af0bf9c bellard
void debug_eret (void)
601 6af0bf9c bellard
{
602 6af0bf9c bellard
    if (loglevel) {
603 6af0bf9c bellard
        fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
604 6af0bf9c bellard
                env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
605 6af0bf9c bellard
                env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
606 6af0bf9c bellard
    }
607 6af0bf9c bellard
}
608 6af0bf9c bellard
609 6af0bf9c bellard
__attribute__ (( regparm(1) ))
610 6af0bf9c bellard
void do_pmon (int function)
611 6af0bf9c bellard
{
612 6af0bf9c bellard
    function /= 2;
613 6af0bf9c bellard
    switch (function) {
614 6af0bf9c bellard
    case 2: /* TODO: char inbyte(int waitflag); */
615 6af0bf9c bellard
        if (env->gpr[4] == 0)
616 6af0bf9c bellard
            env->gpr[2] = -1;
617 6af0bf9c bellard
        /* Fall through */
618 6af0bf9c bellard
    case 11: /* TODO: char inbyte (void); */
619 6af0bf9c bellard
        env->gpr[2] = -1;
620 6af0bf9c bellard
        break;
621 6af0bf9c bellard
    case 3:
622 6af0bf9c bellard
    case 12:
623 6af0bf9c bellard
        printf("%c", env->gpr[4] & 0xFF);
624 6af0bf9c bellard
        break;
625 6af0bf9c bellard
    case 17:
626 6af0bf9c bellard
        break;
627 6af0bf9c bellard
    case 158:
628 6af0bf9c bellard
        {
629 6af0bf9c bellard
            unsigned char *fmt = (void *)env->gpr[4];
630 6af0bf9c bellard
            printf("%s", fmt);
631 6af0bf9c bellard
        }
632 6af0bf9c bellard
        break;
633 6af0bf9c bellard
    }
634 6af0bf9c bellard
}