qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

op_helper.c (7214B)


      1 /*
      2  * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *     * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above copyright
     10  *       notice, this list of conditions and the following disclaimer in the
     11  *       documentation and/or other materials provided with the distribution.
     12  *     * Neither the name of the Open Source and Linux Lab nor the
     13  *       names of its contributors may be used to endorse or promote products
     14  *       derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "qemu/osdep.h"
     29 #include "qemu/main-loop.h"
     30 #include "cpu.h"
     31 #include "exec/helper-proto.h"
     32 #include "qemu/host-utils.h"
     33 #include "exec/exec-all.h"
     34 #include "exec/cpu_ldst.h"
     35 #include "qemu/timer.h"
     36 
     37 #ifndef CONFIG_USER_ONLY
     38 
     39 void HELPER(update_ccount)(CPUXtensaState *env)
     40 {
     41     XtensaCPU *cpu = XTENSA_CPU(env_cpu(env));
     42     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     43 
     44     env->ccount_time = now;
     45     env->sregs[CCOUNT] = env->ccount_base +
     46         (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base);
     47 }
     48 
     49 void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v)
     50 {
     51     int i;
     52 
     53     HELPER(update_ccount)(env);
     54     env->ccount_base += v - env->sregs[CCOUNT];
     55     for (i = 0; i < env->config->nccompare; ++i) {
     56         HELPER(update_ccompare)(env, i);
     57     }
     58 }
     59 
     60 void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
     61 {
     62     XtensaCPU *cpu = XTENSA_CPU(env_cpu(env));
     63     uint64_t dcc;
     64 
     65     qatomic_and(&env->sregs[INTSET],
     66                ~(1u << env->config->timerint[i]));
     67     HELPER(update_ccount)(env);
     68     dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1;
     69     timer_mod(env->ccompare[i].timer,
     70               env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc));
     71     env->yield_needed = 1;
     72 }
     73 
     74 /*!
     75  * Check vaddr accessibility/cache attributes and raise an exception if
     76  * specified by the ATOMCTL SR.
     77  *
     78  * Note: local memory exclusion is not implemented
     79  */
     80 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
     81 {
     82     uint32_t paddr, page_size, access;
     83     uint32_t atomctl = env->sregs[ATOMCTL];
     84     int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
     85             xtensa_get_cring(env), &paddr, &page_size, &access);
     86 
     87     /*
     88      * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions,
     89      * see opcode description in the ISA
     90      */
     91     if (rc == 0 &&
     92             (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) {
     93         rc = STORE_PROHIBITED_CAUSE;
     94     }
     95 
     96     if (rc) {
     97         HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
     98     }
     99 
    100     /*
    101      * When data cache is not configured use ATOMCTL bypass field.
    102      * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
    103      * under the Conditional Store Option.
    104      */
    105     if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
    106         access = PAGE_CACHE_BYPASS;
    107     }
    108 
    109     switch (access & PAGE_CACHE_MASK) {
    110     case PAGE_CACHE_WB:
    111         atomctl >>= 2;
    112         /* fall through */
    113     case PAGE_CACHE_WT:
    114         atomctl >>= 2;
    115         /* fall through */
    116     case PAGE_CACHE_BYPASS:
    117         if ((atomctl & 0x3) == 0) {
    118             HELPER(exception_cause_vaddr)(env, pc,
    119                     LOAD_STORE_ERROR_CAUSE, vaddr);
    120         }
    121         break;
    122 
    123     case PAGE_CACHE_ISOLATE:
    124         HELPER(exception_cause_vaddr)(env, pc,
    125                 LOAD_STORE_ERROR_CAUSE, vaddr);
    126         break;
    127 
    128     default:
    129         break;
    130     }
    131 }
    132 
    133 void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr,
    134                              uint32_t is_write)
    135 {
    136     uint32_t paddr, page_size, access;
    137     uint32_t atomctl = env->sregs[ATOMCTL];
    138     int rc = xtensa_get_physical_addr(env, true, vaddr, is_write,
    139                                       xtensa_get_cring(env), &paddr,
    140                                       &page_size, &access);
    141 
    142     if (rc) {
    143         HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
    144     }
    145 
    146     /* When data cache is not configured use ATOMCTL bypass field. */
    147     if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
    148         access = PAGE_CACHE_BYPASS;
    149     }
    150 
    151     switch (access & PAGE_CACHE_MASK) {
    152     case PAGE_CACHE_WB:
    153         atomctl >>= 2;
    154         /* fall through */
    155     case PAGE_CACHE_WT:
    156         atomctl >>= 2;
    157         /* fall through */
    158     case PAGE_CACHE_BYPASS:
    159         if ((atomctl & 0x3) == 0) {
    160             HELPER(exception_cause_vaddr)(env, pc,
    161                                           EXCLUSIVE_ERROR_CAUSE, vaddr);
    162         }
    163         break;
    164 
    165     case PAGE_CACHE_ISOLATE:
    166         HELPER(exception_cause_vaddr)(env, pc,
    167                 LOAD_STORE_ERROR_CAUSE, vaddr);
    168         break;
    169 
    170     default:
    171         break;
    172     }
    173 }
    174 
    175 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
    176 {
    177     if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
    178         if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) >
    179             env->config->icache_ways) {
    180             deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN,
    181                       env->config->icache_ways);
    182         }
    183     }
    184     if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
    185         if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) >
    186             env->config->dcache_ways) {
    187             deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN,
    188                       env->config->dcache_ways);
    189         }
    190         if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) >
    191             env->config->dcache_ways) {
    192             deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN,
    193                       env->config->dcache_ways);
    194         }
    195     }
    196     env->sregs[MEMCTL] = v & env->config->memctl_mask;
    197 }
    198 
    199 #endif
    200 
    201 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr)
    202 {
    203 #ifndef CONFIG_USER_ONLY
    204     return address_space_ldl(env->address_space_er, addr,
    205                              MEMTXATTRS_UNSPECIFIED, NULL);
    206 #else
    207     return 0;
    208 #endif
    209 }
    210 
    211 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr)
    212 {
    213 #ifndef CONFIG_USER_ONLY
    214     address_space_stl(env->address_space_er, addr, data,
    215                       MEMTXATTRS_UNSPECIFIED, NULL);
    216 #endif
    217 }