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 9fdf9b3e8Sbellard * version 2 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 */ 19fdf9b3e8Sbellard #include <stdarg.h> 20fdf9b3e8Sbellard #include <stdlib.h> 21fdf9b3e8Sbellard #include <stdio.h> 22fdf9b3e8Sbellard #include <string.h> 23fdf9b3e8Sbellard #include <inttypes.h> 24fdf9b3e8Sbellard #include <signal.h> 25fdf9b3e8Sbellard 26fdf9b3e8Sbellard #include "cpu.h" 27fdf9b3e8Sbellard #include "exec-all.h" 28e96e2044Sths #include "hw/sh_intc.h" 29fdf9b3e8Sbellard 30355fb23dSpbrook #if defined(CONFIG_USER_ONLY) 31355fb23dSpbrook 32355fb23dSpbrook void do_interrupt (CPUState *env) 33355fb23dSpbrook { 34355fb23dSpbrook env->exception_index = -1; 35355fb23dSpbrook } 36355fb23dSpbrook 37355fb23dSpbrook int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, 386ebbf390Sj_mayer int mmu_idx, int is_softmmu) 39355fb23dSpbrook { 40355fb23dSpbrook env->tea = address; 41ee0dc6d3SBlue Swirl env->exception_index = -1; 42355fb23dSpbrook switch (rw) { 43355fb23dSpbrook case 0: 44355fb23dSpbrook env->exception_index = 0x0a0; 45355fb23dSpbrook break; 46355fb23dSpbrook case 1: 47355fb23dSpbrook env->exception_index = 0x0c0; 48355fb23dSpbrook break; 49cf7055bdSaurel32 case 2: 50cf7055bdSaurel32 env->exception_index = 0x0a0; 51cf7055bdSaurel32 break; 52355fb23dSpbrook } 53355fb23dSpbrook return 1; 54355fb23dSpbrook } 55355fb23dSpbrook 563c1adf12Sedgar_igl int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) 573c1adf12Sedgar_igl { 583c1adf12Sedgar_igl /* For user mode, only U0 area is cachable. */ 59679dee3cSedgar_igl return !(addr & 0x80000000); 603c1adf12Sedgar_igl } 613c1adf12Sedgar_igl 62355fb23dSpbrook #else /* !CONFIG_USER_ONLY */ 63355fb23dSpbrook 64fdf9b3e8Sbellard #define MMU_OK 0 65fdf9b3e8Sbellard #define MMU_ITLB_MISS (-1) 66fdf9b3e8Sbellard #define MMU_ITLB_MULTIPLE (-2) 67fdf9b3e8Sbellard #define MMU_ITLB_VIOLATION (-3) 68fdf9b3e8Sbellard #define MMU_DTLB_MISS_READ (-4) 69fdf9b3e8Sbellard #define MMU_DTLB_MISS_WRITE (-5) 70fdf9b3e8Sbellard #define MMU_DTLB_INITIAL_WRITE (-6) 71fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_READ (-7) 72fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_WRITE (-8) 73fdf9b3e8Sbellard #define MMU_DTLB_MULTIPLE (-9) 74fdf9b3e8Sbellard #define MMU_DTLB_MISS (-10) 75cf7055bdSaurel32 #define MMU_IADDR_ERROR (-11) 76cf7055bdSaurel32 #define MMU_DADDR_ERROR_READ (-12) 77cf7055bdSaurel32 #define MMU_DADDR_ERROR_WRITE (-13) 78fdf9b3e8Sbellard 79fdf9b3e8Sbellard void do_interrupt(CPUState * env) 80fdf9b3e8Sbellard { 81e96e2044Sths int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD; 82e96e2044Sths int do_exp, irq_vector = env->exception_index; 83e96e2044Sths 84e96e2044Sths /* prioritize exceptions over interrupts */ 85e96e2044Sths 86e96e2044Sths do_exp = env->exception_index != -1; 87e96e2044Sths do_irq = do_irq && (env->exception_index == -1); 88e96e2044Sths 89e96e2044Sths if (env->sr & SR_BL) { 90e96e2044Sths if (do_exp && env->exception_index != 0x1e0) { 91e96e2044Sths env->exception_index = 0x000; /* masked exception -> reset */ 92e96e2044Sths } 93833ed386Saurel32 if (do_irq && !env->intr_at_halt) { 94e96e2044Sths return; /* masked */ 95e96e2044Sths } 96833ed386Saurel32 env->intr_at_halt = 0; 97e96e2044Sths } 98e96e2044Sths 99e96e2044Sths if (do_irq) { 100e96e2044Sths irq_vector = sh_intc_get_pending_vector(env->intc_handle, 101e96e2044Sths (env->sr >> 4) & 0xf); 102e96e2044Sths if (irq_vector == -1) { 103e96e2044Sths return; /* masked */ 104e96e2044Sths } 105e96e2044Sths } 106e96e2044Sths 1078fec2b8cSaliguori if (qemu_loglevel_mask(CPU_LOG_INT)) { 108fdf9b3e8Sbellard const char *expname; 109fdf9b3e8Sbellard switch (env->exception_index) { 110fdf9b3e8Sbellard case 0x0e0: 111fdf9b3e8Sbellard expname = "addr_error"; 112fdf9b3e8Sbellard break; 113fdf9b3e8Sbellard case 0x040: 114fdf9b3e8Sbellard expname = "tlb_miss"; 115fdf9b3e8Sbellard break; 116fdf9b3e8Sbellard case 0x0a0: 117fdf9b3e8Sbellard expname = "tlb_violation"; 118fdf9b3e8Sbellard break; 119fdf9b3e8Sbellard case 0x180: 120fdf9b3e8Sbellard expname = "illegal_instruction"; 121fdf9b3e8Sbellard break; 122fdf9b3e8Sbellard case 0x1a0: 123fdf9b3e8Sbellard expname = "slot_illegal_instruction"; 124fdf9b3e8Sbellard break; 125fdf9b3e8Sbellard case 0x800: 126fdf9b3e8Sbellard expname = "fpu_disable"; 127fdf9b3e8Sbellard break; 128fdf9b3e8Sbellard case 0x820: 129fdf9b3e8Sbellard expname = "slot_fpu"; 130fdf9b3e8Sbellard break; 131fdf9b3e8Sbellard case 0x100: 132fdf9b3e8Sbellard expname = "data_write"; 133fdf9b3e8Sbellard break; 134fdf9b3e8Sbellard case 0x060: 135fdf9b3e8Sbellard expname = "dtlb_miss_write"; 136fdf9b3e8Sbellard break; 137fdf9b3e8Sbellard case 0x0c0: 138fdf9b3e8Sbellard expname = "dtlb_violation_write"; 139fdf9b3e8Sbellard break; 140fdf9b3e8Sbellard case 0x120: 141fdf9b3e8Sbellard expname = "fpu_exception"; 142fdf9b3e8Sbellard break; 143fdf9b3e8Sbellard case 0x080: 144fdf9b3e8Sbellard expname = "initial_page_write"; 145fdf9b3e8Sbellard break; 146fdf9b3e8Sbellard case 0x160: 147fdf9b3e8Sbellard expname = "trapa"; 148fdf9b3e8Sbellard break; 149fdf9b3e8Sbellard default: 150e96e2044Sths expname = do_irq ? "interrupt" : "???"; 151fdf9b3e8Sbellard break; 152fdf9b3e8Sbellard } 15393fcfe39Saliguori qemu_log("exception 0x%03x [%s] raised\n", 154e96e2044Sths irq_vector, expname); 15593fcfe39Saliguori log_cpu_state(env, 0); 156fdf9b3e8Sbellard } 157fdf9b3e8Sbellard 158fdf9b3e8Sbellard env->ssr = env->sr; 159e96e2044Sths env->spc = env->pc; 160fdf9b3e8Sbellard env->sgr = env->gregs[15]; 161fdf9b3e8Sbellard env->sr |= SR_BL | SR_MD | SR_RB; 162fdf9b3e8Sbellard 163274a9e70Saurel32 if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { 164274a9e70Saurel32 /* Branch instruction should be executed again before delay slot. */ 165274a9e70Saurel32 env->spc -= 2; 166274a9e70Saurel32 /* Clear flags for exception/interrupt routine. */ 167274a9e70Saurel32 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE); 168274a9e70Saurel32 } 169274a9e70Saurel32 if (env->flags & DELAY_SLOT_CLEARME) 170274a9e70Saurel32 env->flags = 0; 171274a9e70Saurel32 172e96e2044Sths if (do_exp) { 173e96e2044Sths env->expevt = env->exception_index; 174fdf9b3e8Sbellard switch (env->exception_index) { 175e96e2044Sths case 0x000: 176e96e2044Sths case 0x020: 177fdf9b3e8Sbellard case 0x140: 178e96e2044Sths env->sr &= ~SR_FD; 179e96e2044Sths env->sr |= 0xf << 4; /* IMASK */ 180fdf9b3e8Sbellard env->pc = 0xa0000000; 181fdf9b3e8Sbellard break; 182e96e2044Sths case 0x040: 183e96e2044Sths case 0x060: 184e96e2044Sths env->pc = env->vbr + 0x400; 185e96e2044Sths break; 186e96e2044Sths case 0x160: 187e96e2044Sths env->spc += 2; /* special case for TRAPA */ 188e96e2044Sths /* fall through */ 189fdf9b3e8Sbellard default: 190fdf9b3e8Sbellard env->pc = env->vbr + 0x100; 191fdf9b3e8Sbellard break; 192fdf9b3e8Sbellard } 193e96e2044Sths return; 194e96e2044Sths } 195e96e2044Sths 196e96e2044Sths if (do_irq) { 197e96e2044Sths env->intevt = irq_vector; 198e96e2044Sths env->pc = env->vbr + 0x600; 199e96e2044Sths return; 200e96e2044Sths } 201fdf9b3e8Sbellard } 202fdf9b3e8Sbellard 203fdf9b3e8Sbellard static void update_itlb_use(CPUState * env, int itlbnb) 204fdf9b3e8Sbellard { 205fdf9b3e8Sbellard uint8_t or_mask = 0, and_mask = (uint8_t) - 1; 206fdf9b3e8Sbellard 207fdf9b3e8Sbellard switch (itlbnb) { 208fdf9b3e8Sbellard case 0: 209ea2b542aSaurel32 and_mask = 0x1f; 210fdf9b3e8Sbellard break; 211fdf9b3e8Sbellard case 1: 212fdf9b3e8Sbellard and_mask = 0xe7; 213fdf9b3e8Sbellard or_mask = 0x80; 214fdf9b3e8Sbellard break; 215fdf9b3e8Sbellard case 2: 216fdf9b3e8Sbellard and_mask = 0xfb; 217fdf9b3e8Sbellard or_mask = 0x50; 218fdf9b3e8Sbellard break; 219fdf9b3e8Sbellard case 3: 220fdf9b3e8Sbellard or_mask = 0x2c; 221fdf9b3e8Sbellard break; 222fdf9b3e8Sbellard } 223fdf9b3e8Sbellard 224ea2b542aSaurel32 env->mmucr &= (and_mask << 24) | 0x00ffffff; 225fdf9b3e8Sbellard env->mmucr |= (or_mask << 24); 226fdf9b3e8Sbellard } 227fdf9b3e8Sbellard 228fdf9b3e8Sbellard static int itlb_replacement(CPUState * env) 229fdf9b3e8Sbellard { 230fdf9b3e8Sbellard if ((env->mmucr & 0xe0000000) == 0xe0000000) 231fdf9b3e8Sbellard return 0; 232ea2b542aSaurel32 if ((env->mmucr & 0x98000000) == 0x18000000) 233fdf9b3e8Sbellard return 1; 234fdf9b3e8Sbellard if ((env->mmucr & 0x54000000) == 0x04000000) 235fdf9b3e8Sbellard return 2; 236fdf9b3e8Sbellard if ((env->mmucr & 0x2c000000) == 0x00000000) 237fdf9b3e8Sbellard return 3; 23843dc2a64SBlue Swirl cpu_abort(env, "Unhandled itlb_replacement"); 239fdf9b3e8Sbellard } 240fdf9b3e8Sbellard 241fdf9b3e8Sbellard /* Find the corresponding entry in the right TLB 242fdf9b3e8Sbellard Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE 243fdf9b3e8Sbellard */ 244fdf9b3e8Sbellard static int find_tlb_entry(CPUState * env, target_ulong address, 245fdf9b3e8Sbellard tlb_t * entries, uint8_t nbtlb, int use_asid) 246fdf9b3e8Sbellard { 247fdf9b3e8Sbellard int match = MMU_DTLB_MISS; 248fdf9b3e8Sbellard uint32_t start, end; 249fdf9b3e8Sbellard uint8_t asid; 250fdf9b3e8Sbellard int i; 251fdf9b3e8Sbellard 252fdf9b3e8Sbellard asid = env->pteh & 0xff; 253fdf9b3e8Sbellard 254fdf9b3e8Sbellard for (i = 0; i < nbtlb; i++) { 255fdf9b3e8Sbellard if (!entries[i].v) 256fdf9b3e8Sbellard continue; /* Invalid entry */ 257eeda6778Saurel32 if (!entries[i].sh && use_asid && entries[i].asid != asid) 258fdf9b3e8Sbellard continue; /* Bad ASID */ 259fdf9b3e8Sbellard start = (entries[i].vpn << 10) & ~(entries[i].size - 1); 260fdf9b3e8Sbellard end = start + entries[i].size - 1; 261fdf9b3e8Sbellard if (address >= start && address <= end) { /* Match */ 262ea2b542aSaurel32 if (match != MMU_DTLB_MISS) 263fdf9b3e8Sbellard return MMU_DTLB_MULTIPLE; /* Multiple match */ 264fdf9b3e8Sbellard match = i; 265fdf9b3e8Sbellard } 266fdf9b3e8Sbellard } 267fdf9b3e8Sbellard return match; 268fdf9b3e8Sbellard } 269fdf9b3e8Sbellard 27029e179bcSaurel32 static void increment_urc(CPUState * env) 27129e179bcSaurel32 { 27229e179bcSaurel32 uint8_t urb, urc; 27329e179bcSaurel32 27429e179bcSaurel32 /* Increment URC */ 27529e179bcSaurel32 urb = ((env->mmucr) >> 18) & 0x3f; 27629e179bcSaurel32 urc = ((env->mmucr) >> 10) & 0x3f; 27729e179bcSaurel32 urc++; 278927e3a4eSaurel32 if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1)) 27929e179bcSaurel32 urc = 0; 28029e179bcSaurel32 env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); 28129e179bcSaurel32 } 28229e179bcSaurel32 283829a4927SAurelien Jarno /* Copy and utlb entry into itlb 284829a4927SAurelien Jarno Return entry 285fdf9b3e8Sbellard */ 286829a4927SAurelien Jarno static int copy_utlb_entry_itlb(CPUState *env, int utlb) 287fdf9b3e8Sbellard { 288829a4927SAurelien Jarno int itlb; 289fdf9b3e8Sbellard 29006afe2c8Saurel32 tlb_t * ientry; 291829a4927SAurelien Jarno itlb = itlb_replacement(env); 292829a4927SAurelien Jarno ientry = &env->itlb[itlb]; 29306afe2c8Saurel32 if (ientry->v) { 29406afe2c8Saurel32 tlb_flush_page(env, ientry->vpn << 10); 29506afe2c8Saurel32 } 296829a4927SAurelien Jarno *ientry = env->utlb[utlb]; 297829a4927SAurelien Jarno update_itlb_use(env, itlb); 298829a4927SAurelien Jarno return itlb; 299829a4927SAurelien Jarno } 300829a4927SAurelien Jarno 301829a4927SAurelien Jarno /* Find itlb entry 302829a4927SAurelien Jarno Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE 303829a4927SAurelien Jarno */ 304829a4927SAurelien Jarno static int find_itlb_entry(CPUState * env, target_ulong address, 305829a4927SAurelien Jarno int use_asid) 306829a4927SAurelien Jarno { 307829a4927SAurelien Jarno int e; 308829a4927SAurelien Jarno 309829a4927SAurelien Jarno e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); 310829a4927SAurelien Jarno if (e == MMU_DTLB_MULTIPLE) { 311829a4927SAurelien Jarno e = MMU_ITLB_MULTIPLE; 312829a4927SAurelien Jarno } else if (e == MMU_DTLB_MISS) { 313ea2b542aSaurel32 e = MMU_ITLB_MISS; 314829a4927SAurelien Jarno } else if (e >= 0) { 315fdf9b3e8Sbellard update_itlb_use(env, e); 316829a4927SAurelien Jarno } 317fdf9b3e8Sbellard return e; 318fdf9b3e8Sbellard } 319fdf9b3e8Sbellard 320fdf9b3e8Sbellard /* Find utlb entry 321fdf9b3e8Sbellard Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ 322ef7ec1c1Saurel32 static int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) 323fdf9b3e8Sbellard { 32429e179bcSaurel32 /* per utlb access */ 32529e179bcSaurel32 increment_urc(env); 326fdf9b3e8Sbellard 327fdf9b3e8Sbellard /* Return entry */ 328fdf9b3e8Sbellard return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); 329fdf9b3e8Sbellard } 330fdf9b3e8Sbellard 331fdf9b3e8Sbellard /* Match address against MMU 332fdf9b3e8Sbellard Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, 333fdf9b3e8Sbellard MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, 334fdf9b3e8Sbellard MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, 335cf7055bdSaurel32 MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION, 336cf7055bdSaurel32 MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE. 337fdf9b3e8Sbellard */ 338fdf9b3e8Sbellard static int get_mmu_address(CPUState * env, target_ulong * physical, 339fdf9b3e8Sbellard int *prot, target_ulong address, 340fdf9b3e8Sbellard int rw, int access_type) 341fdf9b3e8Sbellard { 342cf7055bdSaurel32 int use_asid, n; 343fdf9b3e8Sbellard tlb_t *matching = NULL; 344fdf9b3e8Sbellard 34506afe2c8Saurel32 use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; 346fdf9b3e8Sbellard 347cf7055bdSaurel32 if (rw == 2) { 348829a4927SAurelien Jarno n = find_itlb_entry(env, address, use_asid); 349fdf9b3e8Sbellard if (n >= 0) { 350fdf9b3e8Sbellard matching = &env->itlb[n]; 3514d1e4ff6SAurelien Jarno if (!(env->sr & SR_MD) && !(matching->pr & 2)) 352fdf9b3e8Sbellard n = MMU_ITLB_VIOLATION; 353fdf9b3e8Sbellard else 3545a25cc2bSAurelien Jarno *prot = PAGE_EXEC; 355829a4927SAurelien Jarno } else { 356829a4927SAurelien Jarno n = find_utlb_entry(env, address, use_asid); 357829a4927SAurelien Jarno if (n >= 0) { 358829a4927SAurelien Jarno n = copy_utlb_entry_itlb(env, n); 359829a4927SAurelien Jarno matching = &env->itlb[n]; 360829a4927SAurelien Jarno if (!(env->sr & SR_MD) && !(matching->pr & 2)) { 361829a4927SAurelien Jarno n = MMU_ITLB_VIOLATION; 362829a4927SAurelien Jarno } else { 363829a4927SAurelien Jarno *prot = PAGE_READ | PAGE_EXEC; 364829a4927SAurelien Jarno if ((matching->pr & 1) && matching->d) { 365829a4927SAurelien Jarno *prot |= PAGE_WRITE; 366829a4927SAurelien Jarno } 367829a4927SAurelien Jarno } 368829a4927SAurelien Jarno } else if (n == MMU_DTLB_MULTIPLE) { 369829a4927SAurelien Jarno n = MMU_ITLB_MULTIPLE; 370829a4927SAurelien Jarno } else if (n == MMU_DTLB_MISS) { 371829a4927SAurelien Jarno n = MMU_ITLB_MISS; 372829a4927SAurelien Jarno } 373fdf9b3e8Sbellard } 374fdf9b3e8Sbellard } else { 375fdf9b3e8Sbellard n = find_utlb_entry(env, address, use_asid); 376fdf9b3e8Sbellard if (n >= 0) { 377fdf9b3e8Sbellard matching = &env->utlb[n]; 378628b61a0SAurelien Jarno if (!(env->sr & SR_MD) && !(matching->pr & 2)) { 379cf7055bdSaurel32 n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE : 380fdf9b3e8Sbellard MMU_DTLB_VIOLATION_READ; 381628b61a0SAurelien Jarno } else if ((rw == 1) && !(matching->pr & 1)) { 382fdf9b3e8Sbellard n = MMU_DTLB_VIOLATION_WRITE; 3830c16e71eSAurelien Jarno } else if ((rw == 1) && !matching->d) { 384628b61a0SAurelien Jarno n = MMU_DTLB_INITIAL_WRITE; 385628b61a0SAurelien Jarno } else { 386fdf9b3e8Sbellard *prot = PAGE_READ; 387628b61a0SAurelien Jarno if ((matching->pr & 1) && matching->d) { 388628b61a0SAurelien Jarno *prot |= PAGE_WRITE; 389628b61a0SAurelien Jarno } 390fdf9b3e8Sbellard } 391fdf9b3e8Sbellard } else if (n == MMU_DTLB_MISS) { 392cf7055bdSaurel32 n = (rw == 1) ? MMU_DTLB_MISS_WRITE : 393fdf9b3e8Sbellard MMU_DTLB_MISS_READ; 394fdf9b3e8Sbellard } 395fdf9b3e8Sbellard } 396fdf9b3e8Sbellard if (n >= 0) { 397628b61a0SAurelien Jarno n = MMU_OK; 398fdf9b3e8Sbellard *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | 399fdf9b3e8Sbellard (address & (matching->size - 1)); 400fdf9b3e8Sbellard } 401fdf9b3e8Sbellard return n; 402fdf9b3e8Sbellard } 403fdf9b3e8Sbellard 404ef7ec1c1Saurel32 static int get_physical_address(CPUState * env, target_ulong * physical, 405fdf9b3e8Sbellard int *prot, target_ulong address, 406fdf9b3e8Sbellard int rw, int access_type) 407fdf9b3e8Sbellard { 408fdf9b3e8Sbellard /* P1, P2 and P4 areas do not use translation */ 409fdf9b3e8Sbellard if ((address >= 0x80000000 && address < 0xc0000000) || 410fdf9b3e8Sbellard address >= 0xe0000000) { 411fdf9b3e8Sbellard if (!(env->sr & SR_MD) 41203e3b61eSAurelien Jarno && (address < 0xe0000000 || address >= 0xe4000000)) { 413fdf9b3e8Sbellard /* Unauthorized access in user mode (only store queues are available) */ 414fdf9b3e8Sbellard fprintf(stderr, "Unauthorized access\n"); 415cf7055bdSaurel32 if (rw == 0) 416cf7055bdSaurel32 return MMU_DADDR_ERROR_READ; 417cf7055bdSaurel32 else if (rw == 1) 418cf7055bdSaurel32 return MMU_DADDR_ERROR_WRITE; 419cf7055bdSaurel32 else 420cf7055bdSaurel32 return MMU_IADDR_ERROR; 421fdf9b3e8Sbellard } 42229e179bcSaurel32 if (address >= 0x80000000 && address < 0xc0000000) { 42329e179bcSaurel32 /* Mask upper 3 bits for P1 and P2 areas */ 42429e179bcSaurel32 *physical = address & 0x1fffffff; 42529e179bcSaurel32 } else { 42629e179bcSaurel32 *physical = address; 42729e179bcSaurel32 } 4285a25cc2bSAurelien Jarno *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 429fdf9b3e8Sbellard return MMU_OK; 430fdf9b3e8Sbellard } 431fdf9b3e8Sbellard 432fdf9b3e8Sbellard /* If MMU is disabled, return the corresponding physical page */ 4330c16e71eSAurelien Jarno if (!(env->mmucr & MMUCR_AT)) { 434fdf9b3e8Sbellard *physical = address & 0x1FFFFFFF; 4355a25cc2bSAurelien Jarno *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 436fdf9b3e8Sbellard return MMU_OK; 437fdf9b3e8Sbellard } 438fdf9b3e8Sbellard 439fdf9b3e8Sbellard /* We need to resort to the MMU */ 440fdf9b3e8Sbellard return get_mmu_address(env, physical, prot, address, rw, access_type); 441fdf9b3e8Sbellard } 442fdf9b3e8Sbellard 443fdf9b3e8Sbellard int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, 4446ebbf390Sj_mayer int mmu_idx, int is_softmmu) 445fdf9b3e8Sbellard { 4460f3f1ec7SAurelien Jarno target_ulong physical; 447fdf9b3e8Sbellard int prot, ret, access_type; 448fdf9b3e8Sbellard 449fdf9b3e8Sbellard access_type = ACCESS_INT; 450fdf9b3e8Sbellard ret = 451fdf9b3e8Sbellard get_physical_address(env, &physical, &prot, address, rw, 452fdf9b3e8Sbellard access_type); 453fdf9b3e8Sbellard 454fdf9b3e8Sbellard if (ret != MMU_OK) { 455fdf9b3e8Sbellard env->tea = address; 456fdf9b3e8Sbellard switch (ret) { 457fdf9b3e8Sbellard case MMU_ITLB_MISS: 458fdf9b3e8Sbellard case MMU_DTLB_MISS_READ: 459fdf9b3e8Sbellard env->exception_index = 0x040; 460fdf9b3e8Sbellard break; 461fdf9b3e8Sbellard case MMU_DTLB_MULTIPLE: 462fdf9b3e8Sbellard case MMU_ITLB_MULTIPLE: 463fdf9b3e8Sbellard env->exception_index = 0x140; 464fdf9b3e8Sbellard break; 465fdf9b3e8Sbellard case MMU_ITLB_VIOLATION: 466fdf9b3e8Sbellard env->exception_index = 0x0a0; 467fdf9b3e8Sbellard break; 468fdf9b3e8Sbellard case MMU_DTLB_MISS_WRITE: 469fdf9b3e8Sbellard env->exception_index = 0x060; 470fdf9b3e8Sbellard break; 471fdf9b3e8Sbellard case MMU_DTLB_INITIAL_WRITE: 472fdf9b3e8Sbellard env->exception_index = 0x080; 473fdf9b3e8Sbellard break; 474fdf9b3e8Sbellard case MMU_DTLB_VIOLATION_READ: 475fdf9b3e8Sbellard env->exception_index = 0x0a0; 476fdf9b3e8Sbellard break; 477fdf9b3e8Sbellard case MMU_DTLB_VIOLATION_WRITE: 478fdf9b3e8Sbellard env->exception_index = 0x0c0; 479fdf9b3e8Sbellard break; 480cf7055bdSaurel32 case MMU_IADDR_ERROR: 481cf7055bdSaurel32 case MMU_DADDR_ERROR_READ: 482cf7055bdSaurel32 env->exception_index = 0x0c0; 483cf7055bdSaurel32 break; 484cf7055bdSaurel32 case MMU_DADDR_ERROR_WRITE: 485cf7055bdSaurel32 env->exception_index = 0x100; 486cf7055bdSaurel32 break; 487fdf9b3e8Sbellard default: 48843dc2a64SBlue Swirl cpu_abort(env, "Unhandled MMU fault"); 489fdf9b3e8Sbellard } 490fdf9b3e8Sbellard return 1; 491fdf9b3e8Sbellard } 492fdf9b3e8Sbellard 4930f3f1ec7SAurelien Jarno address &= TARGET_PAGE_MASK; 4940f3f1ec7SAurelien Jarno physical &= TARGET_PAGE_MASK; 495fdf9b3e8Sbellard 496d4c430a8SPaul Brook tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE); 497d4c430a8SPaul Brook return 0; 498fdf9b3e8Sbellard } 499355fb23dSpbrook 500c227f099SAnthony Liguori target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) 501355fb23dSpbrook { 502355fb23dSpbrook target_ulong physical; 503355fb23dSpbrook int prot; 504355fb23dSpbrook 505cf7055bdSaurel32 get_physical_address(env, &physical, &prot, addr, 0, 0); 506355fb23dSpbrook return physical; 507355fb23dSpbrook } 508355fb23dSpbrook 509ef7ec1c1Saurel32 void cpu_load_tlb(CPUSH4State * env) 510ea2b542aSaurel32 { 511ea2b542aSaurel32 int n = cpu_mmucr_urc(env->mmucr); 512ea2b542aSaurel32 tlb_t * entry = &env->utlb[n]; 513ea2b542aSaurel32 51406afe2c8Saurel32 if (entry->v) { 51506afe2c8Saurel32 /* Overwriting valid entry in utlb. */ 51606afe2c8Saurel32 target_ulong address = entry->vpn << 10; 51706afe2c8Saurel32 tlb_flush_page(env, address); 51806afe2c8Saurel32 } 51906afe2c8Saurel32 520ea2b542aSaurel32 /* Take values into cpu status from registers. */ 521ea2b542aSaurel32 entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); 522ea2b542aSaurel32 entry->vpn = cpu_pteh_vpn(env->pteh); 523ea2b542aSaurel32 entry->v = (uint8_t)cpu_ptel_v(env->ptel); 524ea2b542aSaurel32 entry->ppn = cpu_ptel_ppn(env->ptel); 525ea2b542aSaurel32 entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); 526ea2b542aSaurel32 switch (entry->sz) { 527ea2b542aSaurel32 case 0: /* 00 */ 528ea2b542aSaurel32 entry->size = 1024; /* 1K */ 529ea2b542aSaurel32 break; 530ea2b542aSaurel32 case 1: /* 01 */ 531ea2b542aSaurel32 entry->size = 1024 * 4; /* 4K */ 532ea2b542aSaurel32 break; 533ea2b542aSaurel32 case 2: /* 10 */ 534ea2b542aSaurel32 entry->size = 1024 * 64; /* 64K */ 535ea2b542aSaurel32 break; 536ea2b542aSaurel32 case 3: /* 11 */ 537ea2b542aSaurel32 entry->size = 1024 * 1024; /* 1M */ 538ea2b542aSaurel32 break; 539ea2b542aSaurel32 default: 54043dc2a64SBlue Swirl cpu_abort(env, "Unhandled load_tlb"); 541ea2b542aSaurel32 break; 542ea2b542aSaurel32 } 543ea2b542aSaurel32 entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); 544ea2b542aSaurel32 entry->c = (uint8_t)cpu_ptel_c(env->ptel); 545ea2b542aSaurel32 entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); 546ea2b542aSaurel32 entry->d = (uint8_t)cpu_ptel_d(env->ptel); 547ea2b542aSaurel32 entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); 548ea2b542aSaurel32 entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); 549ea2b542aSaurel32 entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); 550ea2b542aSaurel32 } 551ea2b542aSaurel32 552e0bcb9caSAurelien Jarno void cpu_sh4_invalidate_tlb(CPUSH4State *s) 553e0bcb9caSAurelien Jarno { 554e0bcb9caSAurelien Jarno int i; 555e0bcb9caSAurelien Jarno 556e0bcb9caSAurelien Jarno /* UTLB */ 557e0bcb9caSAurelien Jarno for (i = 0; i < UTLB_SIZE; i++) { 558e0bcb9caSAurelien Jarno tlb_t * entry = &s->utlb[i]; 559e0bcb9caSAurelien Jarno entry->v = 0; 560e0bcb9caSAurelien Jarno } 561e0bcb9caSAurelien Jarno /* ITLB */ 562e40a67beSAlexandre Courbot for (i = 0; i < ITLB_SIZE; i++) { 563e40a67beSAlexandre Courbot tlb_t * entry = &s->itlb[i]; 564e0bcb9caSAurelien Jarno entry->v = 0; 565e0bcb9caSAurelien Jarno } 566e0bcb9caSAurelien Jarno 567e0bcb9caSAurelien Jarno tlb_flush(s, 1); 568e0bcb9caSAurelien Jarno } 569e0bcb9caSAurelien Jarno 570c0f809c4SAurelien Jarno void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr, 571c0f809c4SAurelien Jarno uint32_t mem_value) 572c0f809c4SAurelien Jarno { 573c0f809c4SAurelien Jarno uint32_t vpn = (mem_value & 0xfffffc00) >> 10; 574c0f809c4SAurelien Jarno uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); 575c0f809c4SAurelien Jarno uint8_t asid = (uint8_t)(mem_value & 0x000000ff); 576c0f809c4SAurelien Jarno 577c0f809c4SAurelien Jarno int index = (addr & 0x00003f00) >> 8; 578c0f809c4SAurelien Jarno tlb_t * entry = &s->itlb[index]; 579c0f809c4SAurelien Jarno if (entry->v) { 580c0f809c4SAurelien Jarno /* Overwriting valid entry in itlb. */ 581c0f809c4SAurelien Jarno target_ulong address = entry->vpn << 10; 582c0f809c4SAurelien Jarno tlb_flush_page(s, address); 583c0f809c4SAurelien Jarno } 584c0f809c4SAurelien Jarno entry->asid = asid; 585c0f809c4SAurelien Jarno entry->vpn = vpn; 586c0f809c4SAurelien Jarno entry->v = v; 587c0f809c4SAurelien Jarno } 588c0f809c4SAurelien Jarno 589c227f099SAnthony Liguori void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, 59029e179bcSaurel32 uint32_t mem_value) 59129e179bcSaurel32 { 59229e179bcSaurel32 int associate = addr & 0x0000080; 59329e179bcSaurel32 uint32_t vpn = (mem_value & 0xfffffc00) >> 10; 59429e179bcSaurel32 uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9); 59529e179bcSaurel32 uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); 59629e179bcSaurel32 uint8_t asid = (uint8_t)(mem_value & 0x000000ff); 597eeda6778Saurel32 int use_asid = (s->mmucr & MMUCR_SV) == 0 || (s->sr & SR_MD) == 0; 59829e179bcSaurel32 59929e179bcSaurel32 if (associate) { 60029e179bcSaurel32 int i; 60129e179bcSaurel32 tlb_t * utlb_match_entry = NULL; 60229e179bcSaurel32 int needs_tlb_flush = 0; 60329e179bcSaurel32 60429e179bcSaurel32 /* search UTLB */ 60529e179bcSaurel32 for (i = 0; i < UTLB_SIZE; i++) { 60629e179bcSaurel32 tlb_t * entry = &s->utlb[i]; 60729e179bcSaurel32 if (!entry->v) 60829e179bcSaurel32 continue; 60929e179bcSaurel32 610eeda6778Saurel32 if (entry->vpn == vpn 611eeda6778Saurel32 && (!use_asid || entry->asid == asid || entry->sh)) { 61229e179bcSaurel32 if (utlb_match_entry) { 61329e179bcSaurel32 /* Multiple TLB Exception */ 61429e179bcSaurel32 s->exception_index = 0x140; 61529e179bcSaurel32 s->tea = addr; 61629e179bcSaurel32 break; 61729e179bcSaurel32 } 61829e179bcSaurel32 if (entry->v && !v) 61929e179bcSaurel32 needs_tlb_flush = 1; 62029e179bcSaurel32 entry->v = v; 62129e179bcSaurel32 entry->d = d; 62229e179bcSaurel32 utlb_match_entry = entry; 62329e179bcSaurel32 } 62429e179bcSaurel32 increment_urc(s); /* per utlb access */ 62529e179bcSaurel32 } 62629e179bcSaurel32 62729e179bcSaurel32 /* search ITLB */ 62829e179bcSaurel32 for (i = 0; i < ITLB_SIZE; i++) { 62929e179bcSaurel32 tlb_t * entry = &s->itlb[i]; 630eeda6778Saurel32 if (entry->vpn == vpn 631eeda6778Saurel32 && (!use_asid || entry->asid == asid || entry->sh)) { 63229e179bcSaurel32 if (entry->v && !v) 63329e179bcSaurel32 needs_tlb_flush = 1; 63429e179bcSaurel32 if (utlb_match_entry) 63529e179bcSaurel32 *entry = *utlb_match_entry; 63629e179bcSaurel32 else 63729e179bcSaurel32 entry->v = v; 63829e179bcSaurel32 break; 63929e179bcSaurel32 } 64029e179bcSaurel32 } 64129e179bcSaurel32 64229e179bcSaurel32 if (needs_tlb_flush) 64329e179bcSaurel32 tlb_flush_page(s, vpn << 10); 64429e179bcSaurel32 64529e179bcSaurel32 } else { 64629e179bcSaurel32 int index = (addr & 0x00003f00) >> 8; 64729e179bcSaurel32 tlb_t * entry = &s->utlb[index]; 64829e179bcSaurel32 if (entry->v) { 64929e179bcSaurel32 /* Overwriting valid entry in utlb. */ 65029e179bcSaurel32 target_ulong address = entry->vpn << 10; 65129e179bcSaurel32 tlb_flush_page(s, address); 65229e179bcSaurel32 } 65329e179bcSaurel32 entry->asid = asid; 65429e179bcSaurel32 entry->vpn = vpn; 65529e179bcSaurel32 entry->d = d; 65629e179bcSaurel32 entry->v = v; 65729e179bcSaurel32 increment_urc(s); 65829e179bcSaurel32 } 65929e179bcSaurel32 } 66029e179bcSaurel32 661852d481fSedgar_igl int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) 662852d481fSedgar_igl { 663852d481fSedgar_igl int n; 664852d481fSedgar_igl int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; 665852d481fSedgar_igl 666852d481fSedgar_igl /* check area */ 667852d481fSedgar_igl if (env->sr & SR_MD) { 668852d481fSedgar_igl /* For previledged mode, P2 and P4 area is not cachable. */ 669852d481fSedgar_igl if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr) 670852d481fSedgar_igl return 0; 671852d481fSedgar_igl } else { 672852d481fSedgar_igl /* For user mode, only U0 area is cachable. */ 673852d481fSedgar_igl if (0x80000000 <= addr) 674852d481fSedgar_igl return 0; 675852d481fSedgar_igl } 676852d481fSedgar_igl 677852d481fSedgar_igl /* 678852d481fSedgar_igl * TODO : Evaluate CCR and check if the cache is on or off. 679852d481fSedgar_igl * Now CCR is not in CPUSH4State, but in SH7750State. 680852d481fSedgar_igl * When you move the ccr inot CPUSH4State, the code will be 681852d481fSedgar_igl * as follows. 682852d481fSedgar_igl */ 683852d481fSedgar_igl #if 0 684852d481fSedgar_igl /* check if operand cache is enabled or not. */ 685852d481fSedgar_igl if (!(env->ccr & 1)) 686852d481fSedgar_igl return 0; 687852d481fSedgar_igl #endif 688852d481fSedgar_igl 689852d481fSedgar_igl /* if MMU is off, no check for TLB. */ 690852d481fSedgar_igl if (env->mmucr & MMUCR_AT) 691852d481fSedgar_igl return 1; 692852d481fSedgar_igl 693852d481fSedgar_igl /* check TLB */ 694852d481fSedgar_igl n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid); 695852d481fSedgar_igl if (n >= 0) 696852d481fSedgar_igl return env->itlb[n].c; 697852d481fSedgar_igl 698852d481fSedgar_igl n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid); 699852d481fSedgar_igl if (n >= 0) 700852d481fSedgar_igl return env->utlb[n].c; 701852d481fSedgar_igl 702852d481fSedgar_igl return 0; 703852d481fSedgar_igl } 704852d481fSedgar_igl 705355fb23dSpbrook #endif 706