xref: /qemu/target/sh4/helper.c (revision 795bec96522356b5afb6c9ebb3ea0974fa3d4a27)
1fdf9b3e8Sbellard /*
2fdf9b3e8Sbellard  *  SH4 emulation
3fdf9b3e8Sbellard  *
4fdf9b3e8Sbellard  *  Copyright (c) 2005 Samuel Tardieu
5fdf9b3e8Sbellard  *
6fdf9b3e8Sbellard  * This library is free software; you can redistribute it and/or
7fdf9b3e8Sbellard  * modify it under the terms of the GNU Lesser General Public
8fdf9b3e8Sbellard  * License as published by the Free Software Foundation; either
96faf2b6cSThomas Huth  * version 2.1 of the License, or (at your option) any later version.
10fdf9b3e8Sbellard  *
11fdf9b3e8Sbellard  * This library is distributed in the hope that it will be useful,
12fdf9b3e8Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fdf9b3e8Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14fdf9b3e8Sbellard  * Lesser General Public License for more details.
15fdf9b3e8Sbellard  *
16fdf9b3e8Sbellard  * You should have received a copy of the GNU Lesser General Public
178167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fdf9b3e8Sbellard  */
1954d31236SMarkus Armbruster 
209d4c9946SPeter Maydell #include "qemu/osdep.h"
21fdf9b3e8Sbellard 
22fdf9b3e8Sbellard #include "cpu.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24508127e2SPaolo Bonzini #include "exec/log.h"
25b279e5efSBenoît Canet 
26b279e5efSBenoît Canet #if !defined(CONFIG_USER_ONLY)
270d09e41aSPaolo Bonzini #include "hw/sh4/sh_intc.h"
2854d31236SMarkus Armbruster #include "sysemu/runstate.h"
29b279e5efSBenoît Canet #endif
30fdf9b3e8Sbellard 
31fdf9b3e8Sbellard #define MMU_OK                   0
32fdf9b3e8Sbellard #define MMU_ITLB_MISS            (-1)
33fdf9b3e8Sbellard #define MMU_ITLB_MULTIPLE        (-2)
34fdf9b3e8Sbellard #define MMU_ITLB_VIOLATION       (-3)
35fdf9b3e8Sbellard #define MMU_DTLB_MISS_READ       (-4)
36fdf9b3e8Sbellard #define MMU_DTLB_MISS_WRITE      (-5)
37fdf9b3e8Sbellard #define MMU_DTLB_INITIAL_WRITE   (-6)
38fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_READ  (-7)
39fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_WRITE (-8)
40fdf9b3e8Sbellard #define MMU_DTLB_MULTIPLE        (-9)
41fdf9b3e8Sbellard #define MMU_DTLB_MISS            (-10)
42cf7055bdSaurel32 #define MMU_IADDR_ERROR          (-11)
43cf7055bdSaurel32 #define MMU_DADDR_ERROR_READ     (-12)
44cf7055bdSaurel32 #define MMU_DADDR_ERROR_WRITE    (-13)
45fdf9b3e8Sbellard 
46f98bce2bSRichard Henderson #if defined(CONFIG_USER_ONLY)
47f98bce2bSRichard Henderson 
48f98bce2bSRichard Henderson int cpu_sh4_is_cached(CPUSH4State *env, target_ulong addr)
49f98bce2bSRichard Henderson {
50f98bce2bSRichard Henderson     /* For user mode, only U0 area is cacheable. */
51f98bce2bSRichard Henderson     return !(addr & 0x80000000);
52f98bce2bSRichard Henderson }
53f98bce2bSRichard Henderson 
54f98bce2bSRichard Henderson #else /* !CONFIG_USER_ONLY */
55f98bce2bSRichard Henderson 
5697a8ea5aSAndreas Färber void superh_cpu_do_interrupt(CPUState *cs)
57fdf9b3e8Sbellard {
58*795bec96SPhilippe Mathieu-Daudé     CPUSH4State *env = cpu_env(cs);
59259186a7SAndreas Färber     int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD;
6027103424SAndreas Färber     int do_exp, irq_vector = cs->exception_index;
61e96e2044Sths 
62e96e2044Sths     /* prioritize exceptions over interrupts */
63e96e2044Sths 
6427103424SAndreas Färber     do_exp = cs->exception_index != -1;
6527103424SAndreas Färber     do_irq = do_irq && (cs->exception_index == -1);
66e96e2044Sths 
675ed9a259SAurelien Jarno     if (env->sr & (1u << SR_BL)) {
6827103424SAndreas Färber         if (do_exp && cs->exception_index != 0x1e0) {
6973479c5cSAurelien Jarno             /* In theory a masked exception generates a reset exception,
7073479c5cSAurelien Jarno                which in turn jumps to the reset vector. However this only
7173479c5cSAurelien Jarno                works when using a bootloader. When using a kernel and an
7273479c5cSAurelien Jarno                initrd, they need to be reloaded and the program counter
7373479c5cSAurelien Jarno                should be loaded with the kernel entry point.
7473479c5cSAurelien Jarno                qemu_system_reset_request takes care of that.  */
7573479c5cSAurelien Jarno             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
7673479c5cSAurelien Jarno             return;
77e96e2044Sths         }
78efac4154SAurelien Jarno         if (do_irq && !env->in_sleep) {
79e96e2044Sths             return; /* masked */
80e96e2044Sths         }
81e96e2044Sths     }
82efac4154SAurelien Jarno     env->in_sleep = 0;
83e96e2044Sths 
84e96e2044Sths     if (do_irq) {
85e96e2044Sths         irq_vector = sh_intc_get_pending_vector(env->intc_handle,
86e96e2044Sths                                                 (env->sr >> 4) & 0xf);
87e96e2044Sths         if (irq_vector == -1) {
88e96e2044Sths             return; /* masked */
89e96e2044Sths         }
90e96e2044Sths     }
91e96e2044Sths 
928fec2b8cSaliguori     if (qemu_loglevel_mask(CPU_LOG_INT)) {
93fdf9b3e8Sbellard         const char *expname;
9427103424SAndreas Färber         switch (cs->exception_index) {
95fdf9b3e8Sbellard         case 0x0e0:
96fdf9b3e8Sbellard             expname = "addr_error";
97fdf9b3e8Sbellard             break;
98fdf9b3e8Sbellard         case 0x040:
99fdf9b3e8Sbellard             expname = "tlb_miss";
100fdf9b3e8Sbellard             break;
101fdf9b3e8Sbellard         case 0x0a0:
102fdf9b3e8Sbellard             expname = "tlb_violation";
103fdf9b3e8Sbellard             break;
104fdf9b3e8Sbellard         case 0x180:
105fdf9b3e8Sbellard             expname = "illegal_instruction";
106fdf9b3e8Sbellard             break;
107fdf9b3e8Sbellard         case 0x1a0:
108fdf9b3e8Sbellard             expname = "slot_illegal_instruction";
109fdf9b3e8Sbellard             break;
110fdf9b3e8Sbellard         case 0x800:
111fdf9b3e8Sbellard             expname = "fpu_disable";
112fdf9b3e8Sbellard             break;
113fdf9b3e8Sbellard         case 0x820:
114fdf9b3e8Sbellard             expname = "slot_fpu";
115fdf9b3e8Sbellard             break;
116fdf9b3e8Sbellard         case 0x100:
117fdf9b3e8Sbellard             expname = "data_write";
118fdf9b3e8Sbellard             break;
119fdf9b3e8Sbellard         case 0x060:
120fdf9b3e8Sbellard             expname = "dtlb_miss_write";
121fdf9b3e8Sbellard             break;
122fdf9b3e8Sbellard         case 0x0c0:
123fdf9b3e8Sbellard             expname = "dtlb_violation_write";
124fdf9b3e8Sbellard             break;
125fdf9b3e8Sbellard         case 0x120:
126fdf9b3e8Sbellard             expname = "fpu_exception";
127fdf9b3e8Sbellard             break;
128fdf9b3e8Sbellard         case 0x080:
129fdf9b3e8Sbellard             expname = "initial_page_write";
130fdf9b3e8Sbellard             break;
131fdf9b3e8Sbellard         case 0x160:
132fdf9b3e8Sbellard             expname = "trapa";
133fdf9b3e8Sbellard             break;
134fdf9b3e8Sbellard         default:
135e96e2044Sths             expname = do_irq ? "interrupt" : "???";
136fdf9b3e8Sbellard             break;
137fdf9b3e8Sbellard         }
13893fcfe39Saliguori         qemu_log("exception 0x%03x [%s] raised\n",
139e96e2044Sths                   irq_vector, expname);
140a0762859SAndreas Färber         log_cpu_state(cs, 0);
141fdf9b3e8Sbellard     }
142fdf9b3e8Sbellard 
14334086945SAurelien Jarno     env->ssr = cpu_read_sr(env);
144e96e2044Sths     env->spc = env->pc;
145fdf9b3e8Sbellard     env->sgr = env->gregs[15];
1465ed9a259SAurelien Jarno     env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB);
147f85da308SRichard Henderson     env->lock_addr = -1;
148fdf9b3e8Sbellard 
149ab419fd8SRichard Henderson     if (env->flags & TB_FLAG_DELAY_SLOT_MASK) {
150274a9e70Saurel32         /* Branch instruction should be executed again before delay slot. */
151274a9e70Saurel32         env->spc -= 2;
152274a9e70Saurel32         /* Clear flags for exception/interrupt routine. */
153ab419fd8SRichard Henderson         env->flags &= ~TB_FLAG_DELAY_SLOT_MASK;
154274a9e70Saurel32     }
155274a9e70Saurel32 
156e96e2044Sths     if (do_exp) {
15727103424SAndreas Färber         env->expevt = cs->exception_index;
15827103424SAndreas Färber         switch (cs->exception_index) {
159e96e2044Sths         case 0x000:
160e96e2044Sths         case 0x020:
161fdf9b3e8Sbellard         case 0x140:
1625ed9a259SAurelien Jarno             env->sr &= ~(1u << SR_FD);
163e96e2044Sths             env->sr |= 0xf << 4; /* IMASK */
164fdf9b3e8Sbellard             env->pc = 0xa0000000;
165fdf9b3e8Sbellard             break;
166e96e2044Sths         case 0x040:
167e96e2044Sths         case 0x060:
168e96e2044Sths             env->pc = env->vbr + 0x400;
169e96e2044Sths             break;
170e96e2044Sths         case 0x160:
171e96e2044Sths             env->spc += 2; /* special case for TRAPA */
172e96e2044Sths             /* fall through */
173fdf9b3e8Sbellard         default:
174fdf9b3e8Sbellard             env->pc = env->vbr + 0x100;
175fdf9b3e8Sbellard             break;
176fdf9b3e8Sbellard         }
177e96e2044Sths         return;
178e96e2044Sths     }
179e96e2044Sths 
180e96e2044Sths     if (do_irq) {
181e96e2044Sths         env->intevt = irq_vector;
182e96e2044Sths         env->pc = env->vbr + 0x600;
183e96e2044Sths         return;
184e96e2044Sths     }
185fdf9b3e8Sbellard }
186fdf9b3e8Sbellard 
18773e5716cSAndreas Färber static void update_itlb_use(CPUSH4State * env, int itlbnb)
188fdf9b3e8Sbellard {
189fdf9b3e8Sbellard     uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
190fdf9b3e8Sbellard 
191fdf9b3e8Sbellard     switch (itlbnb) {
192fdf9b3e8Sbellard     case 0:
193ea2b542aSaurel32         and_mask = 0x1f;
194fdf9b3e8Sbellard         break;
195fdf9b3e8Sbellard     case 1:
196fdf9b3e8Sbellard         and_mask = 0xe7;
197fdf9b3e8Sbellard         or_mask = 0x80;
198fdf9b3e8Sbellard         break;
199fdf9b3e8Sbellard     case 2:
200fdf9b3e8Sbellard         and_mask = 0xfb;
201fdf9b3e8Sbellard         or_mask = 0x50;
202fdf9b3e8Sbellard         break;
203fdf9b3e8Sbellard     case 3:
204fdf9b3e8Sbellard         or_mask = 0x2c;
205fdf9b3e8Sbellard         break;
206fdf9b3e8Sbellard     }
207fdf9b3e8Sbellard 
208ea2b542aSaurel32     env->mmucr &= (and_mask << 24) | 0x00ffffff;
209fdf9b3e8Sbellard     env->mmucr |= (or_mask << 24);
210fdf9b3e8Sbellard }
211fdf9b3e8Sbellard 
21273e5716cSAndreas Färber static int itlb_replacement(CPUSH4State * env)
213fdf9b3e8Sbellard {
214a47dddd7SAndreas Färber     if ((env->mmucr & 0xe0000000) == 0xe0000000) {
215fdf9b3e8Sbellard         return 0;
216a47dddd7SAndreas Färber     }
217a47dddd7SAndreas Färber     if ((env->mmucr & 0x98000000) == 0x18000000) {
218fdf9b3e8Sbellard         return 1;
219a47dddd7SAndreas Färber     }
220a47dddd7SAndreas Färber     if ((env->mmucr & 0x54000000) == 0x04000000) {
221fdf9b3e8Sbellard         return 2;
222a47dddd7SAndreas Färber     }
223a47dddd7SAndreas Färber     if ((env->mmucr & 0x2c000000) == 0x00000000) {
224fdf9b3e8Sbellard         return 3;
225a47dddd7SAndreas Färber     }
226dad1c8ecSRichard Henderson     cpu_abort(env_cpu(env), "Unhandled itlb_replacement");
227fdf9b3e8Sbellard }
228fdf9b3e8Sbellard 
229fdf9b3e8Sbellard /* Find the corresponding entry in the right TLB
230fdf9b3e8Sbellard    Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
231fdf9b3e8Sbellard */
23273e5716cSAndreas Färber static int find_tlb_entry(CPUSH4State * env, target_ulong address,
233fdf9b3e8Sbellard                           tlb_t * entries, uint8_t nbtlb, int use_asid)
234fdf9b3e8Sbellard {
235fdf9b3e8Sbellard     int match = MMU_DTLB_MISS;
236fdf9b3e8Sbellard     uint32_t start, end;
237fdf9b3e8Sbellard     uint8_t asid;
238fdf9b3e8Sbellard     int i;
239fdf9b3e8Sbellard 
240fdf9b3e8Sbellard     asid = env->pteh & 0xff;
241fdf9b3e8Sbellard 
242fdf9b3e8Sbellard     for (i = 0; i < nbtlb; i++) {
243fdf9b3e8Sbellard         if (!entries[i].v)
244fdf9b3e8Sbellard             continue; /* Invalid entry */
245eeda6778Saurel32         if (!entries[i].sh && use_asid && entries[i].asid != asid)
246fdf9b3e8Sbellard             continue; /* Bad ASID */
247fdf9b3e8Sbellard         start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
248fdf9b3e8Sbellard         end = start + entries[i].size - 1;
249fdf9b3e8Sbellard         if (address >= start && address <= end) { /* Match */
250ea2b542aSaurel32             if (match != MMU_DTLB_MISS)
251fdf9b3e8Sbellard                 return MMU_DTLB_MULTIPLE; /* Multiple match */
252fdf9b3e8Sbellard             match = i;
253fdf9b3e8Sbellard         }
254fdf9b3e8Sbellard     }
255fdf9b3e8Sbellard     return match;
256fdf9b3e8Sbellard }
257fdf9b3e8Sbellard 
25873e5716cSAndreas Färber static void increment_urc(CPUSH4State * env)
25929e179bcSaurel32 {
26029e179bcSaurel32     uint8_t urb, urc;
26129e179bcSaurel32 
26229e179bcSaurel32     /* Increment URC */
26329e179bcSaurel32     urb = ((env->mmucr) >> 18) & 0x3f;
26429e179bcSaurel32     urc = ((env->mmucr) >> 10) & 0x3f;
26529e179bcSaurel32     urc++;
266927e3a4eSaurel32     if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1))
26729e179bcSaurel32         urc = 0;
26829e179bcSaurel32     env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
26929e179bcSaurel32 }
27029e179bcSaurel32 
271829a4927SAurelien Jarno /* Copy and utlb entry into itlb
272829a4927SAurelien Jarno    Return entry
273fdf9b3e8Sbellard */
27473e5716cSAndreas Färber static int copy_utlb_entry_itlb(CPUSH4State *env, int utlb)
275fdf9b3e8Sbellard {
276829a4927SAurelien Jarno     int itlb;
277fdf9b3e8Sbellard 
27806afe2c8Saurel32     tlb_t * ientry;
279829a4927SAurelien Jarno     itlb = itlb_replacement(env);
280829a4927SAurelien Jarno     ientry = &env->itlb[itlb];
28106afe2c8Saurel32     if (ientry->v) {
282dad1c8ecSRichard Henderson         tlb_flush_page(env_cpu(env), ientry->vpn << 10);
28306afe2c8Saurel32     }
284829a4927SAurelien Jarno     *ientry = env->utlb[utlb];
285829a4927SAurelien Jarno     update_itlb_use(env, itlb);
286829a4927SAurelien Jarno     return itlb;
287829a4927SAurelien Jarno }
288829a4927SAurelien Jarno 
289829a4927SAurelien Jarno /* Find itlb entry
290829a4927SAurelien Jarno    Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
291829a4927SAurelien Jarno */
29273e5716cSAndreas Färber static int find_itlb_entry(CPUSH4State * env, target_ulong address,
293829a4927SAurelien Jarno                            int use_asid)
294829a4927SAurelien Jarno {
295829a4927SAurelien Jarno     int e;
296829a4927SAurelien Jarno 
297829a4927SAurelien Jarno     e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
298829a4927SAurelien Jarno     if (e == MMU_DTLB_MULTIPLE) {
299829a4927SAurelien Jarno         e = MMU_ITLB_MULTIPLE;
300829a4927SAurelien Jarno     } else if (e == MMU_DTLB_MISS) {
301ea2b542aSaurel32         e = MMU_ITLB_MISS;
302829a4927SAurelien Jarno     } else if (e >= 0) {
303fdf9b3e8Sbellard         update_itlb_use(env, e);
304829a4927SAurelien Jarno     }
305fdf9b3e8Sbellard     return e;
306fdf9b3e8Sbellard }
307fdf9b3e8Sbellard 
308fdf9b3e8Sbellard /* Find utlb entry
309fdf9b3e8Sbellard    Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
31073e5716cSAndreas Färber static int find_utlb_entry(CPUSH4State * env, target_ulong address, int use_asid)
311fdf9b3e8Sbellard {
31229e179bcSaurel32     /* per utlb access */
31329e179bcSaurel32     increment_urc(env);
314fdf9b3e8Sbellard 
315fdf9b3e8Sbellard     /* Return entry */
316fdf9b3e8Sbellard     return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
317fdf9b3e8Sbellard }
318fdf9b3e8Sbellard 
319fdf9b3e8Sbellard /* Match address against MMU
320fdf9b3e8Sbellard    Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
321fdf9b3e8Sbellard    MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
322fdf9b3e8Sbellard    MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
323cf7055bdSaurel32    MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
324cf7055bdSaurel32    MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
325fdf9b3e8Sbellard */
32673e5716cSAndreas Färber static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
327fdf9b3e8Sbellard                            int *prot, target_ulong address,
328be617b44SPhilippe Mathieu-Daudé                            MMUAccessType access_type)
329fdf9b3e8Sbellard {
330cf7055bdSaurel32     int use_asid, n;
331fdf9b3e8Sbellard     tlb_t *matching = NULL;
332fdf9b3e8Sbellard 
3335ed9a259SAurelien Jarno     use_asid = !(env->mmucr & MMUCR_SV) || !(env->sr & (1u << SR_MD));
334fdf9b3e8Sbellard 
335be617b44SPhilippe Mathieu-Daudé     if (access_type == MMU_INST_FETCH) {
336829a4927SAurelien Jarno         n = find_itlb_entry(env, address, use_asid);
337fdf9b3e8Sbellard         if (n >= 0) {
338fdf9b3e8Sbellard             matching = &env->itlb[n];
3395ed9a259SAurelien Jarno             if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) {
340fdf9b3e8Sbellard                 n = MMU_ITLB_VIOLATION;
3415ed9a259SAurelien Jarno             } else {
3425a25cc2bSAurelien Jarno                 *prot = PAGE_EXEC;
3435ed9a259SAurelien Jarno             }
344829a4927SAurelien Jarno         } else {
345829a4927SAurelien Jarno             n = find_utlb_entry(env, address, use_asid);
346829a4927SAurelien Jarno             if (n >= 0) {
347829a4927SAurelien Jarno                 n = copy_utlb_entry_itlb(env, n);
348829a4927SAurelien Jarno                 matching = &env->itlb[n];
3495ed9a259SAurelien Jarno                 if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) {
350829a4927SAurelien Jarno                     n = MMU_ITLB_VIOLATION;
351829a4927SAurelien Jarno                 } else {
352829a4927SAurelien Jarno                     *prot = PAGE_READ | PAGE_EXEC;
353829a4927SAurelien Jarno                     if ((matching->pr & 1) && matching->d) {
354829a4927SAurelien Jarno                         *prot |= PAGE_WRITE;
355829a4927SAurelien Jarno                     }
356829a4927SAurelien Jarno                 }
357829a4927SAurelien Jarno             } else if (n == MMU_DTLB_MULTIPLE) {
358829a4927SAurelien Jarno                 n = MMU_ITLB_MULTIPLE;
359829a4927SAurelien Jarno             } else if (n == MMU_DTLB_MISS) {
360829a4927SAurelien Jarno                 n = MMU_ITLB_MISS;
361829a4927SAurelien Jarno             }
362fdf9b3e8Sbellard         }
363fdf9b3e8Sbellard     } else {
364fdf9b3e8Sbellard         n = find_utlb_entry(env, address, use_asid);
365fdf9b3e8Sbellard         if (n >= 0) {
366fdf9b3e8Sbellard             matching = &env->utlb[n];
3675ed9a259SAurelien Jarno             if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) {
368be617b44SPhilippe Mathieu-Daudé                 n = (access_type == MMU_DATA_STORE)
3698d2b06fbSPhilippe Mathieu-Daudé                     ? MMU_DTLB_VIOLATION_WRITE : MMU_DTLB_VIOLATION_READ;
370be617b44SPhilippe Mathieu-Daudé             } else if ((access_type == MMU_DATA_STORE) && !(matching->pr & 1)) {
371fdf9b3e8Sbellard                 n = MMU_DTLB_VIOLATION_WRITE;
372be617b44SPhilippe Mathieu-Daudé             } else if ((access_type == MMU_DATA_STORE) && !matching->d) {
373628b61a0SAurelien Jarno                 n = MMU_DTLB_INITIAL_WRITE;
374628b61a0SAurelien Jarno             } else {
375fdf9b3e8Sbellard                 *prot = PAGE_READ;
376628b61a0SAurelien Jarno                 if ((matching->pr & 1) && matching->d) {
377628b61a0SAurelien Jarno                     *prot |= PAGE_WRITE;
378628b61a0SAurelien Jarno                 }
379fdf9b3e8Sbellard             }
380fdf9b3e8Sbellard         } else if (n == MMU_DTLB_MISS) {
381be617b44SPhilippe Mathieu-Daudé             n = (access_type == MMU_DATA_STORE)
3828d2b06fbSPhilippe Mathieu-Daudé                 ? MMU_DTLB_MISS_WRITE : MMU_DTLB_MISS_READ;
383fdf9b3e8Sbellard         }
384fdf9b3e8Sbellard     }
385fdf9b3e8Sbellard     if (n >= 0) {
386628b61a0SAurelien Jarno         n = MMU_OK;
3878d2b06fbSPhilippe Mathieu-Daudé         *physical = ((matching->ppn << 10) & ~(matching->size - 1))
3888d2b06fbSPhilippe Mathieu-Daudé                     | (address & (matching->size - 1));
389fdf9b3e8Sbellard     }
390fdf9b3e8Sbellard     return n;
391fdf9b3e8Sbellard }
392fdf9b3e8Sbellard 
39373e5716cSAndreas Färber static int get_physical_address(CPUSH4State * env, target_ulong * physical,
394fdf9b3e8Sbellard                                 int *prot, target_ulong address,
395be617b44SPhilippe Mathieu-Daudé                                 MMUAccessType access_type)
396fdf9b3e8Sbellard {
397fdf9b3e8Sbellard     /* P1, P2 and P4 areas do not use translation */
3988d2b06fbSPhilippe Mathieu-Daudé     if ((address >= 0x80000000 && address < 0xc0000000) || address >= 0xe0000000) {
3995ed9a259SAurelien Jarno         if (!(env->sr & (1u << SR_MD))
40003e3b61eSAurelien Jarno                 && (address < 0xe0000000 || address >= 0xe4000000)) {
401fdf9b3e8Sbellard             /* Unauthorized access in user mode (only store queues are available) */
402324189baSAurelien Jarno             qemu_log_mask(LOG_GUEST_ERROR, "Unauthorized access\n");
403be617b44SPhilippe Mathieu-Daudé             if (access_type == MMU_DATA_LOAD) {
404cf7055bdSaurel32                 return MMU_DADDR_ERROR_READ;
405be617b44SPhilippe Mathieu-Daudé             } else if (access_type == MMU_DATA_STORE) {
406cf7055bdSaurel32                 return MMU_DADDR_ERROR_WRITE;
4078d2b06fbSPhilippe Mathieu-Daudé             } else {
408cf7055bdSaurel32                 return MMU_IADDR_ERROR;
409fdf9b3e8Sbellard             }
4108d2b06fbSPhilippe Mathieu-Daudé         }
41129e179bcSaurel32         if (address >= 0x80000000 && address < 0xc0000000) {
41229e179bcSaurel32             /* Mask upper 3 bits for P1 and P2 areas */
41329e179bcSaurel32             *physical = address & 0x1fffffff;
41429e179bcSaurel32         } else {
41529e179bcSaurel32             *physical = address;
41629e179bcSaurel32         }
4175a25cc2bSAurelien Jarno         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
418fdf9b3e8Sbellard         return MMU_OK;
419fdf9b3e8Sbellard     }
420fdf9b3e8Sbellard 
421fdf9b3e8Sbellard     /* If MMU is disabled, return the corresponding physical page */
4220c16e71eSAurelien Jarno     if (!(env->mmucr & MMUCR_AT)) {
423fdf9b3e8Sbellard         *physical = address & 0x1FFFFFFF;
4245a25cc2bSAurelien Jarno         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
425fdf9b3e8Sbellard         return MMU_OK;
426fdf9b3e8Sbellard     }
427fdf9b3e8Sbellard 
428fdf9b3e8Sbellard     /* We need to resort to the MMU */
429be617b44SPhilippe Mathieu-Daudé     return get_mmu_address(env, physical, prot, address, access_type);
430fdf9b3e8Sbellard }
431fdf9b3e8Sbellard 
43200b941e5SAndreas Färber hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
433355fb23dSpbrook {
434355fb23dSpbrook     target_ulong physical;
435355fb23dSpbrook     int prot;
436355fb23dSpbrook 
437*795bec96SPhilippe Mathieu-Daudé     if (get_physical_address(cpu_env(cs), &physical, &prot, addr, MMU_DATA_LOAD)
43852a1c621SPhilippe Mathieu-Daudé             == MMU_OK) {
439355fb23dSpbrook         return physical;
440355fb23dSpbrook     }
441355fb23dSpbrook 
44252a1c621SPhilippe Mathieu-Daudé     return -1;
44352a1c621SPhilippe Mathieu-Daudé }
44452a1c621SPhilippe Mathieu-Daudé 
445ef7ec1c1Saurel32 void cpu_load_tlb(CPUSH4State * env)
446ea2b542aSaurel32 {
447dad1c8ecSRichard Henderson     CPUState *cs = env_cpu(env);
448ea2b542aSaurel32     int n = cpu_mmucr_urc(env->mmucr);
449ea2b542aSaurel32     tlb_t * entry = &env->utlb[n];
450ea2b542aSaurel32 
45106afe2c8Saurel32     if (entry->v) {
45206afe2c8Saurel32         /* Overwriting valid entry in utlb. */
45306afe2c8Saurel32         target_ulong address = entry->vpn << 10;
454dad1c8ecSRichard Henderson         tlb_flush_page(cs, address);
45506afe2c8Saurel32     }
45606afe2c8Saurel32 
457ea2b542aSaurel32     /* Take values into cpu status from registers. */
458ea2b542aSaurel32     entry->asid = (uint8_t)cpu_pteh_asid(env->pteh);
459ea2b542aSaurel32     entry->vpn  = cpu_pteh_vpn(env->pteh);
460ea2b542aSaurel32     entry->v    = (uint8_t)cpu_ptel_v(env->ptel);
461ea2b542aSaurel32     entry->ppn  = cpu_ptel_ppn(env->ptel);
462ea2b542aSaurel32     entry->sz   = (uint8_t)cpu_ptel_sz(env->ptel);
463ea2b542aSaurel32     switch (entry->sz) {
464ea2b542aSaurel32     case 0: /* 00 */
465ea2b542aSaurel32         entry->size = 1024; /* 1K */
466ea2b542aSaurel32         break;
467ea2b542aSaurel32     case 1: /* 01 */
468ea2b542aSaurel32         entry->size = 1024 * 4; /* 4K */
469ea2b542aSaurel32         break;
470ea2b542aSaurel32     case 2: /* 10 */
471ea2b542aSaurel32         entry->size = 1024 * 64; /* 64K */
472ea2b542aSaurel32         break;
473ea2b542aSaurel32     case 3: /* 11 */
474ea2b542aSaurel32         entry->size = 1024 * 1024; /* 1M */
475ea2b542aSaurel32         break;
476ea2b542aSaurel32     default:
477dad1c8ecSRichard Henderson         cpu_abort(cs, "Unhandled load_tlb");
478ea2b542aSaurel32         break;
479ea2b542aSaurel32     }
480ea2b542aSaurel32     entry->sh   = (uint8_t)cpu_ptel_sh(env->ptel);
481ea2b542aSaurel32     entry->c    = (uint8_t)cpu_ptel_c(env->ptel);
482ea2b542aSaurel32     entry->pr   = (uint8_t)cpu_ptel_pr(env->ptel);
483ea2b542aSaurel32     entry->d    = (uint8_t)cpu_ptel_d(env->ptel);
484ea2b542aSaurel32     entry->wt   = (uint8_t)cpu_ptel_wt(env->ptel);
485ea2b542aSaurel32     entry->sa   = (uint8_t)cpu_ptea_sa(env->ptea);
486ea2b542aSaurel32     entry->tc   = (uint8_t)cpu_ptea_tc(env->ptea);
487ea2b542aSaurel32 }
488ea2b542aSaurel32 
489e0bcb9caSAurelien Jarno  void cpu_sh4_invalidate_tlb(CPUSH4State *s)
490e0bcb9caSAurelien Jarno {
491e0bcb9caSAurelien Jarno     int i;
492e0bcb9caSAurelien Jarno 
493e0bcb9caSAurelien Jarno     /* UTLB */
494e0bcb9caSAurelien Jarno     for (i = 0; i < UTLB_SIZE; i++) {
495e0bcb9caSAurelien Jarno         tlb_t * entry = &s->utlb[i];
496e0bcb9caSAurelien Jarno         entry->v = 0;
497e0bcb9caSAurelien Jarno     }
498e0bcb9caSAurelien Jarno     /* ITLB */
499e40a67beSAlexandre Courbot     for (i = 0; i < ITLB_SIZE; i++) {
500e40a67beSAlexandre Courbot         tlb_t * entry = &s->itlb[i];
501e0bcb9caSAurelien Jarno         entry->v = 0;
502e0bcb9caSAurelien Jarno     }
503e0bcb9caSAurelien Jarno 
504dad1c8ecSRichard Henderson     tlb_flush(env_cpu(s));
505e0bcb9caSAurelien Jarno }
506e0bcb9caSAurelien Jarno 
507bc656a29SAurelien Jarno uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
508a8170e5eSAvi Kivity                                        hwaddr addr)
509bc656a29SAurelien Jarno {
510bc656a29SAurelien Jarno     int index = (addr & 0x00000300) >> 8;
511bc656a29SAurelien Jarno     tlb_t * entry = &s->itlb[index];
512bc656a29SAurelien Jarno 
513bc656a29SAurelien Jarno     return (entry->vpn  << 10) |
514bc656a29SAurelien Jarno            (entry->v    <<  8) |
515bc656a29SAurelien Jarno            (entry->asid);
516bc656a29SAurelien Jarno }
517bc656a29SAurelien Jarno 
518a8170e5eSAvi Kivity void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, hwaddr addr,
519c0f809c4SAurelien Jarno                                     uint32_t mem_value)
520c0f809c4SAurelien Jarno {
521c0f809c4SAurelien Jarno     uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
522c0f809c4SAurelien Jarno     uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
523c0f809c4SAurelien Jarno     uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
524c0f809c4SAurelien Jarno 
5259f97309aSAurelien Jarno     int index = (addr & 0x00000300) >> 8;
526c0f809c4SAurelien Jarno     tlb_t * entry = &s->itlb[index];
527c0f809c4SAurelien Jarno     if (entry->v) {
528c0f809c4SAurelien Jarno         /* Overwriting valid entry in itlb. */
529c0f809c4SAurelien Jarno         target_ulong address = entry->vpn << 10;
530dad1c8ecSRichard Henderson         tlb_flush_page(env_cpu(s), address);
531c0f809c4SAurelien Jarno     }
532c0f809c4SAurelien Jarno     entry->asid = asid;
533c0f809c4SAurelien Jarno     entry->vpn = vpn;
534c0f809c4SAurelien Jarno     entry->v = v;
535c0f809c4SAurelien Jarno }
536c0f809c4SAurelien Jarno 
537bc656a29SAurelien Jarno uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
538a8170e5eSAvi Kivity                                        hwaddr addr)
539bc656a29SAurelien Jarno {
540bc656a29SAurelien Jarno     int array = (addr & 0x00800000) >> 23;
541bc656a29SAurelien Jarno     int index = (addr & 0x00000300) >> 8;
542bc656a29SAurelien Jarno     tlb_t * entry = &s->itlb[index];
543bc656a29SAurelien Jarno 
544bc656a29SAurelien Jarno     if (array == 0) {
545bc656a29SAurelien Jarno         /* ITLB Data Array 1 */
546bc656a29SAurelien Jarno         return (entry->ppn << 10) |
547bc656a29SAurelien Jarno                (entry->v   <<  8) |
548bc656a29SAurelien Jarno                (entry->pr  <<  5) |
549bc656a29SAurelien Jarno                ((entry->sz & 1) <<  6) |
550bc656a29SAurelien Jarno                ((entry->sz & 2) <<  4) |
551bc656a29SAurelien Jarno                (entry->c   <<  3) |
552bc656a29SAurelien Jarno                (entry->sh  <<  1);
553bc656a29SAurelien Jarno     } else {
554bc656a29SAurelien Jarno         /* ITLB Data Array 2 */
555bc656a29SAurelien Jarno         return (entry->tc << 1) |
556bc656a29SAurelien Jarno                (entry->sa);
557bc656a29SAurelien Jarno     }
558bc656a29SAurelien Jarno }
559bc656a29SAurelien Jarno 
560a8170e5eSAvi Kivity void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, hwaddr addr,
5619f97309aSAurelien Jarno                                     uint32_t mem_value)
5629f97309aSAurelien Jarno {
5639f97309aSAurelien Jarno     int array = (addr & 0x00800000) >> 23;
5649f97309aSAurelien Jarno     int index = (addr & 0x00000300) >> 8;
5659f97309aSAurelien Jarno     tlb_t * entry = &s->itlb[index];
5669f97309aSAurelien Jarno 
5679f97309aSAurelien Jarno     if (array == 0) {
5689f97309aSAurelien Jarno         /* ITLB Data Array 1 */
5699f97309aSAurelien Jarno         if (entry->v) {
5709f97309aSAurelien Jarno             /* Overwriting valid entry in utlb. */
5719f97309aSAurelien Jarno             target_ulong address = entry->vpn << 10;
572dad1c8ecSRichard Henderson             tlb_flush_page(env_cpu(s), address);
5739f97309aSAurelien Jarno         }
5749f97309aSAurelien Jarno         entry->ppn = (mem_value & 0x1ffffc00) >> 10;
5759f97309aSAurelien Jarno         entry->v   = (mem_value & 0x00000100) >> 8;
5769f97309aSAurelien Jarno         entry->sz  = (mem_value & 0x00000080) >> 6 |
5779f97309aSAurelien Jarno                      (mem_value & 0x00000010) >> 4;
5789f97309aSAurelien Jarno         entry->pr  = (mem_value & 0x00000040) >> 5;
5799f97309aSAurelien Jarno         entry->c   = (mem_value & 0x00000008) >> 3;
5809f97309aSAurelien Jarno         entry->sh  = (mem_value & 0x00000002) >> 1;
5819f97309aSAurelien Jarno     } else {
5829f97309aSAurelien Jarno         /* ITLB Data Array 2 */
5839f97309aSAurelien Jarno         entry->tc  = (mem_value & 0x00000008) >> 3;
5849f97309aSAurelien Jarno         entry->sa  = (mem_value & 0x00000007);
5859f97309aSAurelien Jarno     }
5869f97309aSAurelien Jarno }
5879f97309aSAurelien Jarno 
588bc656a29SAurelien Jarno uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
589a8170e5eSAvi Kivity                                        hwaddr addr)
590bc656a29SAurelien Jarno {
591bc656a29SAurelien Jarno     int index = (addr & 0x00003f00) >> 8;
592bc656a29SAurelien Jarno     tlb_t * entry = &s->utlb[index];
593bc656a29SAurelien Jarno 
594bc656a29SAurelien Jarno     increment_urc(s); /* per utlb access */
595bc656a29SAurelien Jarno 
596bc656a29SAurelien Jarno     return (entry->vpn  << 10) |
597bc656a29SAurelien Jarno            (entry->v    <<  8) |
598bc656a29SAurelien Jarno            (entry->asid);
599bc656a29SAurelien Jarno }
600bc656a29SAurelien Jarno 
601a8170e5eSAvi Kivity void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, hwaddr addr,
60229e179bcSaurel32                                     uint32_t mem_value)
60329e179bcSaurel32 {
60429e179bcSaurel32     int associate = addr & 0x0000080;
60529e179bcSaurel32     uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
60629e179bcSaurel32     uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
60729e179bcSaurel32     uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
60829e179bcSaurel32     uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
6095ed9a259SAurelien Jarno     int use_asid = !(s->mmucr & MMUCR_SV) || !(s->sr & (1u << SR_MD));
61029e179bcSaurel32 
61129e179bcSaurel32     if (associate) {
61229e179bcSaurel32         int i;
61329e179bcSaurel32         tlb_t * utlb_match_entry = NULL;
61429e179bcSaurel32         int needs_tlb_flush = 0;
61529e179bcSaurel32 
61629e179bcSaurel32         /* search UTLB */
61729e179bcSaurel32         for (i = 0; i < UTLB_SIZE; i++) {
61829e179bcSaurel32             tlb_t * entry = &s->utlb[i];
61929e179bcSaurel32             if (!entry->v)
62029e179bcSaurel32                 continue;
62129e179bcSaurel32 
622eeda6778Saurel32             if (entry->vpn == vpn
623eeda6778Saurel32                 && (!use_asid || entry->asid == asid || entry->sh)) {
62429e179bcSaurel32                 if (utlb_match_entry) {
625dad1c8ecSRichard Henderson                     CPUState *cs = env_cpu(s);
62627103424SAndreas Färber 
62729e179bcSaurel32                     /* Multiple TLB Exception */
62827103424SAndreas Färber                     cs->exception_index = 0x140;
62929e179bcSaurel32                     s->tea = addr;
63029e179bcSaurel32                     break;
63129e179bcSaurel32                 }
63229e179bcSaurel32                 if (entry->v && !v)
63329e179bcSaurel32                     needs_tlb_flush = 1;
63429e179bcSaurel32                 entry->v = v;
63529e179bcSaurel32                 entry->d = d;
63629e179bcSaurel32                 utlb_match_entry = entry;
63729e179bcSaurel32             }
63829e179bcSaurel32             increment_urc(s); /* per utlb access */
63929e179bcSaurel32         }
64029e179bcSaurel32 
64129e179bcSaurel32         /* search ITLB */
64229e179bcSaurel32         for (i = 0; i < ITLB_SIZE; i++) {
64329e179bcSaurel32             tlb_t * entry = &s->itlb[i];
644eeda6778Saurel32             if (entry->vpn == vpn
645eeda6778Saurel32                 && (!use_asid || entry->asid == asid || entry->sh)) {
64629e179bcSaurel32                 if (entry->v && !v)
64729e179bcSaurel32                     needs_tlb_flush = 1;
64829e179bcSaurel32                 if (utlb_match_entry)
64929e179bcSaurel32                     *entry = *utlb_match_entry;
65029e179bcSaurel32                 else
65129e179bcSaurel32                     entry->v = v;
65229e179bcSaurel32                 break;
65329e179bcSaurel32             }
65429e179bcSaurel32         }
65529e179bcSaurel32 
65631b030d4SAndreas Färber         if (needs_tlb_flush) {
657dad1c8ecSRichard Henderson             tlb_flush_page(env_cpu(s), vpn << 10);
65831b030d4SAndreas Färber         }
65929e179bcSaurel32     } else {
66029e179bcSaurel32         int index = (addr & 0x00003f00) >> 8;
66129e179bcSaurel32         tlb_t * entry = &s->utlb[index];
66229e179bcSaurel32         if (entry->v) {
663dad1c8ecSRichard Henderson             CPUState *cs = env_cpu(s);
66431b030d4SAndreas Färber 
66529e179bcSaurel32             /* Overwriting valid entry in utlb. */
66629e179bcSaurel32             target_ulong address = entry->vpn << 10;
66731b030d4SAndreas Färber             tlb_flush_page(cs, address);
66829e179bcSaurel32         }
66929e179bcSaurel32         entry->asid = asid;
67029e179bcSaurel32         entry->vpn = vpn;
67129e179bcSaurel32         entry->d = d;
67229e179bcSaurel32         entry->v = v;
67329e179bcSaurel32         increment_urc(s);
67429e179bcSaurel32     }
67529e179bcSaurel32 }
67629e179bcSaurel32 
677bc656a29SAurelien Jarno uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
678a8170e5eSAvi Kivity                                        hwaddr addr)
679bc656a29SAurelien Jarno {
680bc656a29SAurelien Jarno     int array = (addr & 0x00800000) >> 23;
681bc656a29SAurelien Jarno     int index = (addr & 0x00003f00) >> 8;
682bc656a29SAurelien Jarno     tlb_t * entry = &s->utlb[index];
683bc656a29SAurelien Jarno 
684bc656a29SAurelien Jarno     increment_urc(s); /* per utlb access */
685bc656a29SAurelien Jarno 
686bc656a29SAurelien Jarno     if (array == 0) {
687bc656a29SAurelien Jarno         /* ITLB Data Array 1 */
688bc656a29SAurelien Jarno         return (entry->ppn << 10) |
689bc656a29SAurelien Jarno                (entry->v   <<  8) |
690bc656a29SAurelien Jarno                (entry->pr  <<  5) |
691bc656a29SAurelien Jarno                ((entry->sz & 1) <<  6) |
692bc656a29SAurelien Jarno                ((entry->sz & 2) <<  4) |
693bc656a29SAurelien Jarno                (entry->c   <<  3) |
694bc656a29SAurelien Jarno                (entry->d   <<  2) |
695bc656a29SAurelien Jarno                (entry->sh  <<  1) |
696bc656a29SAurelien Jarno                (entry->wt);
697bc656a29SAurelien Jarno     } else {
698bc656a29SAurelien Jarno         /* ITLB Data Array 2 */
699bc656a29SAurelien Jarno         return (entry->tc << 1) |
700bc656a29SAurelien Jarno                (entry->sa);
701bc656a29SAurelien Jarno     }
702bc656a29SAurelien Jarno }
703bc656a29SAurelien Jarno 
704a8170e5eSAvi Kivity void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, hwaddr addr,
7059f97309aSAurelien Jarno                                     uint32_t mem_value)
7069f97309aSAurelien Jarno {
7079f97309aSAurelien Jarno     int array = (addr & 0x00800000) >> 23;
7089f97309aSAurelien Jarno     int index = (addr & 0x00003f00) >> 8;
7099f97309aSAurelien Jarno     tlb_t * entry = &s->utlb[index];
7109f97309aSAurelien Jarno 
7119f97309aSAurelien Jarno     increment_urc(s); /* per utlb access */
7129f97309aSAurelien Jarno 
7139f97309aSAurelien Jarno     if (array == 0) {
7149f97309aSAurelien Jarno         /* UTLB Data Array 1 */
7159f97309aSAurelien Jarno         if (entry->v) {
7169f97309aSAurelien Jarno             /* Overwriting valid entry in utlb. */
7179f97309aSAurelien Jarno             target_ulong address = entry->vpn << 10;
718dad1c8ecSRichard Henderson             tlb_flush_page(env_cpu(s), address);
7199f97309aSAurelien Jarno         }
7209f97309aSAurelien Jarno         entry->ppn = (mem_value & 0x1ffffc00) >> 10;
7219f97309aSAurelien Jarno         entry->v   = (mem_value & 0x00000100) >> 8;
7229f97309aSAurelien Jarno         entry->sz  = (mem_value & 0x00000080) >> 6 |
7239f97309aSAurelien Jarno                      (mem_value & 0x00000010) >> 4;
7249f97309aSAurelien Jarno         entry->pr  = (mem_value & 0x00000060) >> 5;
7259f97309aSAurelien Jarno         entry->c   = (mem_value & 0x00000008) >> 3;
7269f97309aSAurelien Jarno         entry->d   = (mem_value & 0x00000004) >> 2;
7279f97309aSAurelien Jarno         entry->sh  = (mem_value & 0x00000002) >> 1;
7289f97309aSAurelien Jarno         entry->wt  = (mem_value & 0x00000001);
7299f97309aSAurelien Jarno     } else {
7309f97309aSAurelien Jarno         /* UTLB Data Array 2 */
7319f97309aSAurelien Jarno         entry->tc = (mem_value & 0x00000008) >> 3;
7329f97309aSAurelien Jarno         entry->sa = (mem_value & 0x00000007);
7339f97309aSAurelien Jarno     }
7349f97309aSAurelien Jarno }
7359f97309aSAurelien Jarno 
736852d481fSedgar_igl int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
737852d481fSedgar_igl {
738852d481fSedgar_igl     int n;
7395ed9a259SAurelien Jarno     int use_asid = !(env->mmucr & MMUCR_SV) || !(env->sr & (1u << SR_MD));
740852d481fSedgar_igl 
741852d481fSedgar_igl     /* check area */
7425ed9a259SAurelien Jarno     if (env->sr & (1u << SR_MD)) {
74367cc32ebSVeres Lajos         /* For privileged mode, P2 and P4 area is not cacheable. */
744852d481fSedgar_igl         if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr)
745852d481fSedgar_igl             return 0;
746852d481fSedgar_igl     } else {
74767cc32ebSVeres Lajos         /* For user mode, only U0 area is cacheable. */
748852d481fSedgar_igl         if (0x80000000 <= addr)
749852d481fSedgar_igl             return 0;
750852d481fSedgar_igl     }
751852d481fSedgar_igl 
752852d481fSedgar_igl     /*
753852d481fSedgar_igl      * TODO : Evaluate CCR and check if the cache is on or off.
754852d481fSedgar_igl      *        Now CCR is not in CPUSH4State, but in SH7750State.
7554abf79a4SDong Xu Wang      *        When you move the ccr into CPUSH4State, the code will be
756852d481fSedgar_igl      *        as follows.
757852d481fSedgar_igl      */
758852d481fSedgar_igl #if 0
759852d481fSedgar_igl     /* check if operand cache is enabled or not. */
760852d481fSedgar_igl     if (!(env->ccr & 1))
761852d481fSedgar_igl         return 0;
762852d481fSedgar_igl #endif
763852d481fSedgar_igl 
764852d481fSedgar_igl     /* if MMU is off, no check for TLB. */
765852d481fSedgar_igl     if (env->mmucr & MMUCR_AT)
766852d481fSedgar_igl         return 1;
767852d481fSedgar_igl 
768852d481fSedgar_igl     /* check TLB */
769852d481fSedgar_igl     n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid);
770852d481fSedgar_igl     if (n >= 0)
771852d481fSedgar_igl         return env->itlb[n].c;
772852d481fSedgar_igl 
773852d481fSedgar_igl     n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid);
774852d481fSedgar_igl     if (n >= 0)
775852d481fSedgar_igl         return env->utlb[n].c;
776852d481fSedgar_igl 
777852d481fSedgar_igl     return 0;
778852d481fSedgar_igl }
779852d481fSedgar_igl 
780f47ede19SRichard Henderson bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
781f47ede19SRichard Henderson {
782f47ede19SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
7835c6f3eb7SAurelien Jarno         /* Delay slots are indivisible, ignore interrupts */
784*795bec96SPhilippe Mathieu-Daudé         if (cpu_env(cs)->flags & TB_FLAG_DELAY_SLOT_MASK) {
7855c6f3eb7SAurelien Jarno             return false;
7865c6f3eb7SAurelien Jarno         } else {
787f47ede19SRichard Henderson             superh_cpu_do_interrupt(cs);
788f47ede19SRichard Henderson             return true;
789f47ede19SRichard Henderson         }
7905c6f3eb7SAurelien Jarno     }
791f47ede19SRichard Henderson     return false;
792f47ede19SRichard Henderson }
793f98bce2bSRichard Henderson 
794f98bce2bSRichard Henderson bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
795f98bce2bSRichard Henderson                          MMUAccessType access_type, int mmu_idx,
796f98bce2bSRichard Henderson                          bool probe, uintptr_t retaddr)
797f98bce2bSRichard Henderson {
798*795bec96SPhilippe Mathieu-Daudé     CPUSH4State *env = cpu_env(cs);
799f98bce2bSRichard Henderson     int ret;
800f98bce2bSRichard Henderson 
801f98bce2bSRichard Henderson     target_ulong physical;
80231ffda71SPhilippe Mathieu-Daudé     int prot;
803f98bce2bSRichard Henderson 
80431ffda71SPhilippe Mathieu-Daudé     ret = get_physical_address(env, &physical, &prot, address, access_type);
805f98bce2bSRichard Henderson 
806f98bce2bSRichard Henderson     if (ret == MMU_OK) {
807f98bce2bSRichard Henderson         address &= TARGET_PAGE_MASK;
808f98bce2bSRichard Henderson         physical &= TARGET_PAGE_MASK;
809f98bce2bSRichard Henderson         tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
810f98bce2bSRichard Henderson         return true;
811f98bce2bSRichard Henderson     }
812f98bce2bSRichard Henderson     if (probe) {
813f98bce2bSRichard Henderson         return false;
814f98bce2bSRichard Henderson     }
815f98bce2bSRichard Henderson 
816f98bce2bSRichard Henderson     if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
817f98bce2bSRichard Henderson         env->pteh = (env->pteh & PTEH_ASID_MASK) | (address & PTEH_VPN_MASK);
818f98bce2bSRichard Henderson     }
819f98bce2bSRichard Henderson 
820f98bce2bSRichard Henderson     env->tea = address;
821f98bce2bSRichard Henderson     switch (ret) {
822f98bce2bSRichard Henderson     case MMU_ITLB_MISS:
823f98bce2bSRichard Henderson     case MMU_DTLB_MISS_READ:
824f98bce2bSRichard Henderson         cs->exception_index = 0x040;
825f98bce2bSRichard Henderson         break;
826f98bce2bSRichard Henderson     case MMU_DTLB_MULTIPLE:
827f98bce2bSRichard Henderson     case MMU_ITLB_MULTIPLE:
828f98bce2bSRichard Henderson         cs->exception_index = 0x140;
829f98bce2bSRichard Henderson         break;
830f98bce2bSRichard Henderson     case MMU_ITLB_VIOLATION:
831f98bce2bSRichard Henderson         cs->exception_index = 0x0a0;
832f98bce2bSRichard Henderson         break;
833f98bce2bSRichard Henderson     case MMU_DTLB_MISS_WRITE:
834f98bce2bSRichard Henderson         cs->exception_index = 0x060;
835f98bce2bSRichard Henderson         break;
836f98bce2bSRichard Henderson     case MMU_DTLB_INITIAL_WRITE:
837f98bce2bSRichard Henderson         cs->exception_index = 0x080;
838f98bce2bSRichard Henderson         break;
839f98bce2bSRichard Henderson     case MMU_DTLB_VIOLATION_READ:
840f98bce2bSRichard Henderson         cs->exception_index = 0x0a0;
841f98bce2bSRichard Henderson         break;
842f98bce2bSRichard Henderson     case MMU_DTLB_VIOLATION_WRITE:
843f98bce2bSRichard Henderson         cs->exception_index = 0x0c0;
844f98bce2bSRichard Henderson         break;
845f98bce2bSRichard Henderson     case MMU_IADDR_ERROR:
846f98bce2bSRichard Henderson     case MMU_DADDR_ERROR_READ:
847f98bce2bSRichard Henderson         cs->exception_index = 0x0e0;
848f98bce2bSRichard Henderson         break;
849f98bce2bSRichard Henderson     case MMU_DADDR_ERROR_WRITE:
850f98bce2bSRichard Henderson         cs->exception_index = 0x100;
851f98bce2bSRichard Henderson         break;
852f98bce2bSRichard Henderson     default:
853f98bce2bSRichard Henderson         cpu_abort(cs, "Unhandled MMU fault");
854f98bce2bSRichard Henderson     }
855f98bce2bSRichard Henderson     cpu_loop_exit_restore(cs, retaddr);
856f98bce2bSRichard Henderson }
857cac720ecSRichard Henderson #endif /* !CONFIG_USER_ONLY */
858