qemu/target-sh4/helper.c
<<
>>
Prefs
   1/*
   2 *  SH4 emulation
   3 *
   4 *  Copyright (c) 2005 Samuel Tardieu
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include <stdarg.h>
  20#include <stdlib.h>
  21#include <stdio.h>
  22#include <string.h>
  23#include <inttypes.h>
  24#include <signal.h>
  25
  26#include "cpu.h"
  27
  28#if !defined(CONFIG_USER_ONLY)
  29#include "hw/sh4/sh_intc.h"
  30#endif
  31
  32#if defined(CONFIG_USER_ONLY)
  33
  34void superh_cpu_do_interrupt(CPUState *cs)
  35{
  36    SuperHCPU *cpu = SUPERH_CPU(cs);
  37    CPUSH4State *env = &cpu->env;
  38
  39    env->exception_index = -1;
  40}
  41
  42int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
  43                             int mmu_idx)
  44{
  45    env->tea = address;
  46    env->exception_index = -1;
  47    switch (rw) {
  48    case 0:
  49        env->exception_index = 0x0a0;
  50        break;
  51    case 1:
  52        env->exception_index = 0x0c0;
  53        break;
  54    case 2:
  55        env->exception_index = 0x0a0;
  56        break;
  57    }
  58    return 1;
  59}
  60
  61int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
  62{
  63    /* For user mode, only U0 area is cachable. */
  64    return !(addr & 0x80000000);
  65}
  66
  67#else /* !CONFIG_USER_ONLY */
  68
  69#define MMU_OK                   0
  70#define MMU_ITLB_MISS            (-1)
  71#define MMU_ITLB_MULTIPLE        (-2)
  72#define MMU_ITLB_VIOLATION       (-3)
  73#define MMU_DTLB_MISS_READ       (-4)
  74#define MMU_DTLB_MISS_WRITE      (-5)
  75#define MMU_DTLB_INITIAL_WRITE   (-6)
  76#define MMU_DTLB_VIOLATION_READ  (-7)
  77#define MMU_DTLB_VIOLATION_WRITE (-8)
  78#define MMU_DTLB_MULTIPLE        (-9)
  79#define MMU_DTLB_MISS            (-10)
  80#define MMU_IADDR_ERROR          (-11)
  81#define MMU_DADDR_ERROR_READ     (-12)
  82#define MMU_DADDR_ERROR_WRITE    (-13)
  83
  84void superh_cpu_do_interrupt(CPUState *cs)
  85{
  86    SuperHCPU *cpu = SUPERH_CPU(cs);
  87    CPUSH4State *env = &cpu->env;
  88    int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD;
  89    int do_exp, irq_vector = env->exception_index;
  90
  91    /* prioritize exceptions over interrupts */
  92
  93    do_exp = env->exception_index != -1;
  94    do_irq = do_irq && (env->exception_index == -1);
  95
  96    if (env->sr & SR_BL) {
  97        if (do_exp && env->exception_index != 0x1e0) {
  98            env->exception_index = 0x000; /* masked exception -> reset */
  99        }
 100        if (do_irq && !env->in_sleep) {
 101            return; /* masked */
 102        }
 103    }
 104    env->in_sleep = 0;
 105
 106    if (do_irq) {
 107        irq_vector = sh_intc_get_pending_vector(env->intc_handle,
 108                                                (env->sr >> 4) & 0xf);
 109        if (irq_vector == -1) {
 110            return; /* masked */
 111        }
 112    }
 113
 114    if (qemu_loglevel_mask(CPU_LOG_INT)) {
 115        const char *expname;
 116        switch (env->exception_index) {
 117        case 0x0e0:
 118            expname = "addr_error";
 119            break;
 120        case 0x040:
 121            expname = "tlb_miss";
 122            break;
 123        case 0x0a0:
 124            expname = "tlb_violation";
 125            break;
 126        case 0x180:
 127            expname = "illegal_instruction";
 128            break;
 129        case 0x1a0:
 130            expname = "slot_illegal_instruction";
 131            break;
 132        case 0x800:
 133            expname = "fpu_disable";
 134            break;
 135        case 0x820:
 136            expname = "slot_fpu";
 137            break;
 138        case 0x100:
 139            expname = "data_write";
 140            break;
 141        case 0x060:
 142            expname = "dtlb_miss_write";
 143            break;
 144        case 0x0c0:
 145            expname = "dtlb_violation_write";
 146            break;
 147        case 0x120:
 148            expname = "fpu_exception";
 149            break;
 150        case 0x080:
 151            expname = "initial_page_write";
 152            break;
 153        case 0x160:
 154            expname = "trapa";
 155            break;
 156        default:
 157            expname = do_irq ? "interrupt" : "???";
 158            break;
 159        }
 160        qemu_log("exception 0x%03x [%s] raised\n",
 161                  irq_vector, expname);
 162        log_cpu_state(cs, 0);
 163    }
 164
 165    env->ssr = env->sr;
 166    env->spc = env->pc;
 167    env->sgr = env->gregs[15];
 168    env->sr |= SR_BL | SR_MD | SR_RB;
 169
 170    if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
 171        /* Branch instruction should be executed again before delay slot. */
 172        env->spc -= 2;
 173        /* Clear flags for exception/interrupt routine. */
 174        env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE);
 175    }
 176    if (env->flags & DELAY_SLOT_CLEARME)
 177        env->flags = 0;
 178
 179    if (do_exp) {
 180        env->expevt = env->exception_index;
 181        switch (env->exception_index) {
 182        case 0x000:
 183        case 0x020:
 184        case 0x140:
 185            env->sr &= ~SR_FD;
 186            env->sr |= 0xf << 4; /* IMASK */
 187            env->pc = 0xa0000000;
 188            break;
 189        case 0x040:
 190        case 0x060:
 191            env->pc = env->vbr + 0x400;
 192            break;
 193        case 0x160:
 194            env->spc += 2; /* special case for TRAPA */
 195            /* fall through */
 196        default:
 197            env->pc = env->vbr + 0x100;
 198            break;
 199        }
 200        return;
 201    }
 202
 203    if (do_irq) {
 204        env->intevt = irq_vector;
 205        env->pc = env->vbr + 0x600;
 206        return;
 207    }
 208}
 209
 210static void update_itlb_use(CPUSH4State * env, int itlbnb)
 211{
 212    uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
 213
 214    switch (itlbnb) {
 215    case 0:
 216        and_mask = 0x1f;
 217        break;
 218    case 1:
 219        and_mask = 0xe7;
 220        or_mask = 0x80;
 221        break;
 222    case 2:
 223        and_mask = 0xfb;
 224        or_mask = 0x50;
 225        break;
 226    case 3:
 227        or_mask = 0x2c;
 228        break;
 229    }
 230
 231    env->mmucr &= (and_mask << 24) | 0x00ffffff;
 232    env->mmucr |= (or_mask << 24);
 233}
 234
 235static int itlb_replacement(CPUSH4State * env)
 236{
 237    if ((env->mmucr & 0xe0000000) == 0xe0000000)
 238        return 0;
 239    if ((env->mmucr & 0x98000000) == 0x18000000)
 240        return 1;
 241    if ((env->mmucr & 0x54000000) == 0x04000000)
 242        return 2;
 243    if ((env->mmucr & 0x2c000000) == 0x00000000)
 244        return 3;
 245    cpu_abort(env, "Unhandled itlb_replacement");
 246}
 247
 248/* Find the corresponding entry in the right TLB
 249   Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
 250*/
 251static int find_tlb_entry(CPUSH4State * env, target_ulong address,
 252                          tlb_t * entries, uint8_t nbtlb, int use_asid)
 253{
 254    int match = MMU_DTLB_MISS;
 255    uint32_t start, end;
 256    uint8_t asid;
 257    int i;
 258
 259    asid = env->pteh & 0xff;
 260
 261    for (i = 0; i < nbtlb; i++) {
 262        if (!entries[i].v)
 263            continue;           /* Invalid entry */
 264        if (!entries[i].sh && use_asid && entries[i].asid != asid)
 265            continue;           /* Bad ASID */
 266        start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
 267        end = start + entries[i].size - 1;
 268        if (address >= start && address <= end) {       /* Match */
 269            if (match != MMU_DTLB_MISS)
 270                return MMU_DTLB_MULTIPLE;       /* Multiple match */
 271            match = i;
 272        }
 273    }
 274    return match;
 275}
 276
 277static void increment_urc(CPUSH4State * env)
 278{
 279    uint8_t urb, urc;
 280
 281    /* Increment URC */
 282    urb = ((env->mmucr) >> 18) & 0x3f;
 283    urc = ((env->mmucr) >> 10) & 0x3f;
 284    urc++;
 285    if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1))
 286        urc = 0;
 287    env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
 288}
 289
 290/* Copy and utlb entry into itlb
 291   Return entry
 292*/
 293static int copy_utlb_entry_itlb(CPUSH4State *env, int utlb)
 294{
 295    int itlb;
 296
 297    tlb_t * ientry;
 298    itlb = itlb_replacement(env);
 299    ientry = &env->itlb[itlb];
 300    if (ientry->v) {
 301        tlb_flush_page(env, ientry->vpn << 10);
 302    }
 303    *ientry = env->utlb[utlb];
 304    update_itlb_use(env, itlb);
 305    return itlb;
 306}
 307
 308/* Find itlb entry
 309   Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
 310*/
 311static int find_itlb_entry(CPUSH4State * env, target_ulong address,
 312                           int use_asid)
 313{
 314    int e;
 315
 316    e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
 317    if (e == MMU_DTLB_MULTIPLE) {
 318        e = MMU_ITLB_MULTIPLE;
 319    } else if (e == MMU_DTLB_MISS) {
 320        e = MMU_ITLB_MISS;
 321    } else if (e >= 0) {
 322        update_itlb_use(env, e);
 323    }
 324    return e;
 325}
 326
 327/* Find utlb entry
 328   Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
 329static int find_utlb_entry(CPUSH4State * env, target_ulong address, int use_asid)
 330{
 331    /* per utlb access */
 332    increment_urc(env);
 333
 334    /* Return entry */
 335    return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
 336}
 337
 338/* Match address against MMU
 339   Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
 340   MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
 341   MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
 342   MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
 343   MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
 344*/
 345static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
 346                           int *prot, target_ulong address,
 347                           int rw, int access_type)
 348{
 349    int use_asid, n;
 350    tlb_t *matching = NULL;
 351
 352    use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
 353
 354    if (rw == 2) {
 355        n = find_itlb_entry(env, address, use_asid);
 356        if (n >= 0) {
 357            matching = &env->itlb[n];
 358            if (!(env->sr & SR_MD) && !(matching->pr & 2))
 359                n = MMU_ITLB_VIOLATION;
 360            else
 361                *prot = PAGE_EXEC;
 362        } else {
 363            n = find_utlb_entry(env, address, use_asid);
 364            if (n >= 0) {
 365                n = copy_utlb_entry_itlb(env, n);
 366                matching = &env->itlb[n];
 367                if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
 368                      n = MMU_ITLB_VIOLATION;
 369                } else {
 370                    *prot = PAGE_READ | PAGE_EXEC;
 371                    if ((matching->pr & 1) && matching->d) {
 372                        *prot |= PAGE_WRITE;
 373                    }
 374                }
 375            } else if (n == MMU_DTLB_MULTIPLE) {
 376                n = MMU_ITLB_MULTIPLE;
 377            } else if (n == MMU_DTLB_MISS) {
 378                n = MMU_ITLB_MISS;
 379            }
 380        }
 381    } else {
 382        n = find_utlb_entry(env, address, use_asid);
 383        if (n >= 0) {
 384            matching = &env->utlb[n];
 385            if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
 386                n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
 387                    MMU_DTLB_VIOLATION_READ;
 388            } else if ((rw == 1) && !(matching->pr & 1)) {
 389                n = MMU_DTLB_VIOLATION_WRITE;
 390            } else if ((rw == 1) && !matching->d) {
 391                n = MMU_DTLB_INITIAL_WRITE;
 392            } else {
 393                *prot = PAGE_READ;
 394                if ((matching->pr & 1) && matching->d) {
 395                    *prot |= PAGE_WRITE;
 396                }
 397            }
 398        } else if (n == MMU_DTLB_MISS) {
 399            n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
 400                MMU_DTLB_MISS_READ;
 401        }
 402    }
 403    if (n >= 0) {
 404        n = MMU_OK;
 405        *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
 406            (address & (matching->size - 1));
 407    }
 408    return n;
 409}
 410
 411static int get_physical_address(CPUSH4State * env, target_ulong * physical,
 412                                int *prot, target_ulong address,
 413                                int rw, int access_type)
 414{
 415    /* P1, P2 and P4 areas do not use translation */
 416    if ((address >= 0x80000000 && address < 0xc0000000) ||
 417        address >= 0xe0000000) {
 418        if (!(env->sr & SR_MD)
 419            && (address < 0xe0000000 || address >= 0xe4000000)) {
 420            /* Unauthorized access in user mode (only store queues are available) */
 421            fprintf(stderr, "Unauthorized access\n");
 422            if (rw == 0)
 423                return MMU_DADDR_ERROR_READ;
 424            else if (rw == 1)
 425                return MMU_DADDR_ERROR_WRITE;
 426            else
 427                return MMU_IADDR_ERROR;
 428        }
 429        if (address >= 0x80000000 && address < 0xc0000000) {
 430            /* Mask upper 3 bits for P1 and P2 areas */
 431            *physical = address & 0x1fffffff;
 432        } else {
 433            *physical = address;
 434        }
 435        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 436        return MMU_OK;
 437    }
 438
 439    /* If MMU is disabled, return the corresponding physical page */
 440    if (!(env->mmucr & MMUCR_AT)) {
 441        *physical = address & 0x1FFFFFFF;
 442        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 443        return MMU_OK;
 444    }
 445
 446    /* We need to resort to the MMU */
 447    return get_mmu_address(env, physical, prot, address, rw, access_type);
 448}
 449
 450int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
 451                             int mmu_idx)
 452{
 453    target_ulong physical;
 454    int prot, ret, access_type;
 455
 456    access_type = ACCESS_INT;
 457    ret =
 458        get_physical_address(env, &physical, &prot, address, rw,
 459                             access_type);
 460
 461    if (ret != MMU_OK) {
 462        env->tea = address;
 463        if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
 464            env->pteh = (env->pteh & PTEH_ASID_MASK) |
 465                    (address & PTEH_VPN_MASK);
 466        }
 467        switch (ret) {
 468        case MMU_ITLB_MISS:
 469        case MMU_DTLB_MISS_READ:
 470            env->exception_index = 0x040;
 471            break;
 472        case MMU_DTLB_MULTIPLE:
 473        case MMU_ITLB_MULTIPLE:
 474            env->exception_index = 0x140;
 475            break;
 476        case MMU_ITLB_VIOLATION:
 477            env->exception_index = 0x0a0;
 478            break;
 479        case MMU_DTLB_MISS_WRITE:
 480            env->exception_index = 0x060;
 481            break;
 482        case MMU_DTLB_INITIAL_WRITE:
 483            env->exception_index = 0x080;
 484            break;
 485        case MMU_DTLB_VIOLATION_READ:
 486            env->exception_index = 0x0a0;
 487            break;
 488        case MMU_DTLB_VIOLATION_WRITE:
 489            env->exception_index = 0x0c0;
 490            break;
 491        case MMU_IADDR_ERROR:
 492        case MMU_DADDR_ERROR_READ:
 493            env->exception_index = 0x0e0;
 494            break;
 495        case MMU_DADDR_ERROR_WRITE:
 496            env->exception_index = 0x100;
 497            break;
 498        default:
 499            cpu_abort(env, "Unhandled MMU fault");
 500        }
 501        return 1;
 502    }
 503
 504    address &= TARGET_PAGE_MASK;
 505    physical &= TARGET_PAGE_MASK;
 506
 507    tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
 508    return 0;
 509}
 510
 511hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 512{
 513    SuperHCPU *cpu = SUPERH_CPU(cs);
 514    target_ulong physical;
 515    int prot;
 516
 517    get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0);
 518    return physical;
 519}
 520
 521void cpu_load_tlb(CPUSH4State * env)
 522{
 523    int n = cpu_mmucr_urc(env->mmucr);
 524    tlb_t * entry = &env->utlb[n];
 525
 526    if (entry->v) {
 527        /* Overwriting valid entry in utlb. */
 528        target_ulong address = entry->vpn << 10;
 529        tlb_flush_page(env, address);
 530    }
 531
 532    /* Take values into cpu status from registers. */
 533    entry->asid = (uint8_t)cpu_pteh_asid(env->pteh);
 534    entry->vpn  = cpu_pteh_vpn(env->pteh);
 535    entry->v    = (uint8_t)cpu_ptel_v(env->ptel);
 536    entry->ppn  = cpu_ptel_ppn(env->ptel);
 537    entry->sz   = (uint8_t)cpu_ptel_sz(env->ptel);
 538    switch (entry->sz) {
 539    case 0: /* 00 */
 540        entry->size = 1024; /* 1K */
 541        break;
 542    case 1: /* 01 */
 543        entry->size = 1024 * 4; /* 4K */
 544        break;
 545    case 2: /* 10 */
 546        entry->size = 1024 * 64; /* 64K */
 547        break;
 548    case 3: /* 11 */
 549        entry->size = 1024 * 1024; /* 1M */
 550        break;
 551    default:
 552        cpu_abort(env, "Unhandled load_tlb");
 553        break;
 554    }
 555    entry->sh   = (uint8_t)cpu_ptel_sh(env->ptel);
 556    entry->c    = (uint8_t)cpu_ptel_c(env->ptel);
 557    entry->pr   = (uint8_t)cpu_ptel_pr(env->ptel);
 558    entry->d    = (uint8_t)cpu_ptel_d(env->ptel);
 559    entry->wt   = (uint8_t)cpu_ptel_wt(env->ptel);
 560    entry->sa   = (uint8_t)cpu_ptea_sa(env->ptea);
 561    entry->tc   = (uint8_t)cpu_ptea_tc(env->ptea);
 562}
 563
 564 void cpu_sh4_invalidate_tlb(CPUSH4State *s)
 565{
 566    int i;
 567
 568    /* UTLB */
 569    for (i = 0; i < UTLB_SIZE; i++) {
 570        tlb_t * entry = &s->utlb[i];
 571        entry->v = 0;
 572    }
 573    /* ITLB */
 574    for (i = 0; i < ITLB_SIZE; i++) {
 575        tlb_t * entry = &s->itlb[i];
 576        entry->v = 0;
 577    }
 578
 579    tlb_flush(s, 1);
 580}
 581
 582uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
 583                                       hwaddr addr)
 584{
 585    int index = (addr & 0x00000300) >> 8;
 586    tlb_t * entry = &s->itlb[index];
 587
 588    return (entry->vpn  << 10) |
 589           (entry->v    <<  8) |
 590           (entry->asid);
 591}
 592
 593void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, hwaddr addr,
 594                                    uint32_t mem_value)
 595{
 596    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
 597    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
 598    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
 599
 600    int index = (addr & 0x00000300) >> 8;
 601    tlb_t * entry = &s->itlb[index];
 602    if (entry->v) {
 603        /* Overwriting valid entry in itlb. */
 604        target_ulong address = entry->vpn << 10;
 605        tlb_flush_page(s, address);
 606    }
 607    entry->asid = asid;
 608    entry->vpn = vpn;
 609    entry->v = v;
 610}
 611
 612uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
 613                                       hwaddr addr)
 614{
 615    int array = (addr & 0x00800000) >> 23;
 616    int index = (addr & 0x00000300) >> 8;
 617    tlb_t * entry = &s->itlb[index];
 618
 619    if (array == 0) {
 620        /* ITLB Data Array 1 */
 621        return (entry->ppn << 10) |
 622               (entry->v   <<  8) |
 623               (entry->pr  <<  5) |
 624               ((entry->sz & 1) <<  6) |
 625               ((entry->sz & 2) <<  4) |
 626               (entry->c   <<  3) |
 627               (entry->sh  <<  1);
 628    } else {
 629        /* ITLB Data Array 2 */
 630        return (entry->tc << 1) |
 631               (entry->sa);
 632    }
 633}
 634
 635void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, hwaddr addr,
 636                                    uint32_t mem_value)
 637{
 638    int array = (addr & 0x00800000) >> 23;
 639    int index = (addr & 0x00000300) >> 8;
 640    tlb_t * entry = &s->itlb[index];
 641
 642    if (array == 0) {
 643        /* ITLB Data Array 1 */
 644        if (entry->v) {
 645            /* Overwriting valid entry in utlb. */
 646            target_ulong address = entry->vpn << 10;
 647            tlb_flush_page(s, address);
 648        }
 649        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
 650        entry->v   = (mem_value & 0x00000100) >> 8;
 651        entry->sz  = (mem_value & 0x00000080) >> 6 |
 652                     (mem_value & 0x00000010) >> 4;
 653        entry->pr  = (mem_value & 0x00000040) >> 5;
 654        entry->c   = (mem_value & 0x00000008) >> 3;
 655        entry->sh  = (mem_value & 0x00000002) >> 1;
 656    } else {
 657        /* ITLB Data Array 2 */
 658        entry->tc  = (mem_value & 0x00000008) >> 3;
 659        entry->sa  = (mem_value & 0x00000007);
 660    }
 661}
 662
 663uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
 664                                       hwaddr addr)
 665{
 666    int index = (addr & 0x00003f00) >> 8;
 667    tlb_t * entry = &s->utlb[index];
 668
 669    increment_urc(s); /* per utlb access */
 670
 671    return (entry->vpn  << 10) |
 672           (entry->v    <<  8) |
 673           (entry->asid);
 674}
 675
 676void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, hwaddr addr,
 677                                    uint32_t mem_value)
 678{
 679    int associate = addr & 0x0000080;
 680    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
 681    uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
 682    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
 683    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
 684    int use_asid = (s->mmucr & MMUCR_SV) == 0 || (s->sr & SR_MD) == 0;
 685
 686    if (associate) {
 687        int i;
 688        tlb_t * utlb_match_entry = NULL;
 689        int needs_tlb_flush = 0;
 690
 691        /* search UTLB */
 692        for (i = 0; i < UTLB_SIZE; i++) {
 693            tlb_t * entry = &s->utlb[i];
 694            if (!entry->v)
 695                continue;
 696
 697            if (entry->vpn == vpn
 698                && (!use_asid || entry->asid == asid || entry->sh)) {
 699                if (utlb_match_entry) {
 700                    /* Multiple TLB Exception */
 701                    s->exception_index = 0x140;
 702                    s->tea = addr;
 703                    break;
 704                }
 705                if (entry->v && !v)
 706                    needs_tlb_flush = 1;
 707                entry->v = v;
 708                entry->d = d;
 709                utlb_match_entry = entry;
 710            }
 711            increment_urc(s); /* per utlb access */
 712        }
 713
 714        /* search ITLB */
 715        for (i = 0; i < ITLB_SIZE; i++) {
 716            tlb_t * entry = &s->itlb[i];
 717            if (entry->vpn == vpn
 718                && (!use_asid || entry->asid == asid || entry->sh)) {
 719                if (entry->v && !v)
 720                    needs_tlb_flush = 1;
 721                if (utlb_match_entry)
 722                    *entry = *utlb_match_entry;
 723                else
 724                    entry->v = v;
 725                break;
 726            }
 727        }
 728
 729        if (needs_tlb_flush)
 730            tlb_flush_page(s, vpn << 10);
 731        
 732    } else {
 733        int index = (addr & 0x00003f00) >> 8;
 734        tlb_t * entry = &s->utlb[index];
 735        if (entry->v) {
 736            /* Overwriting valid entry in utlb. */
 737            target_ulong address = entry->vpn << 10;
 738            tlb_flush_page(s, address);
 739        }
 740        entry->asid = asid;
 741        entry->vpn = vpn;
 742        entry->d = d;
 743        entry->v = v;
 744        increment_urc(s);
 745    }
 746}
 747
 748uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
 749                                       hwaddr addr)
 750{
 751    int array = (addr & 0x00800000) >> 23;
 752    int index = (addr & 0x00003f00) >> 8;
 753    tlb_t * entry = &s->utlb[index];
 754
 755    increment_urc(s); /* per utlb access */
 756
 757    if (array == 0) {
 758        /* ITLB Data Array 1 */
 759        return (entry->ppn << 10) |
 760               (entry->v   <<  8) |
 761               (entry->pr  <<  5) |
 762               ((entry->sz & 1) <<  6) |
 763               ((entry->sz & 2) <<  4) |
 764               (entry->c   <<  3) |
 765               (entry->d   <<  2) |
 766               (entry->sh  <<  1) |
 767               (entry->wt);
 768    } else {
 769        /* ITLB Data Array 2 */
 770        return (entry->tc << 1) |
 771               (entry->sa);
 772    }
 773}
 774
 775void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, hwaddr addr,
 776                                    uint32_t mem_value)
 777{
 778    int array = (addr & 0x00800000) >> 23;
 779    int index = (addr & 0x00003f00) >> 8;
 780    tlb_t * entry = &s->utlb[index];
 781
 782    increment_urc(s); /* per utlb access */
 783
 784    if (array == 0) {
 785        /* UTLB Data Array 1 */
 786        if (entry->v) {
 787            /* Overwriting valid entry in utlb. */
 788            target_ulong address = entry->vpn << 10;
 789            tlb_flush_page(s, address);
 790        }
 791        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
 792        entry->v   = (mem_value & 0x00000100) >> 8;
 793        entry->sz  = (mem_value & 0x00000080) >> 6 |
 794                     (mem_value & 0x00000010) >> 4;
 795        entry->pr  = (mem_value & 0x00000060) >> 5;
 796        entry->c   = (mem_value & 0x00000008) >> 3;
 797        entry->d   = (mem_value & 0x00000004) >> 2;
 798        entry->sh  = (mem_value & 0x00000002) >> 1;
 799        entry->wt  = (mem_value & 0x00000001);
 800    } else {
 801        /* UTLB Data Array 2 */
 802        entry->tc = (mem_value & 0x00000008) >> 3;
 803        entry->sa = (mem_value & 0x00000007);
 804    }
 805}
 806
 807int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
 808{
 809    int n;
 810    int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
 811
 812    /* check area */
 813    if (env->sr & SR_MD) {
 814        /* For previledged mode, P2 and P4 area is not cachable. */
 815        if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr)
 816            return 0;
 817    } else {
 818        /* For user mode, only U0 area is cachable. */
 819        if (0x80000000 <= addr)
 820            return 0;
 821    }
 822
 823    /*
 824     * TODO : Evaluate CCR and check if the cache is on or off.
 825     *        Now CCR is not in CPUSH4State, but in SH7750State.
 826     *        When you move the ccr into CPUSH4State, the code will be
 827     *        as follows.
 828     */
 829#if 0
 830    /* check if operand cache is enabled or not. */
 831    if (!(env->ccr & 1))
 832        return 0;
 833#endif
 834
 835    /* if MMU is off, no check for TLB. */
 836    if (env->mmucr & MMUCR_AT)
 837        return 1;
 838
 839    /* check TLB */
 840    n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid);
 841    if (n >= 0)
 842        return env->itlb[n].c;
 843
 844    n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid);
 845    if (n >= 0)
 846        return env->utlb[n].c;
 847
 848    return 0;
 849}
 850
 851#endif
 852