xref: /openbmc/qemu/target/xtensa/op_helper.c (revision f550805d)
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 "exec/address-spaces.h"
36 #include "qemu/timer.h"
37 
38 #ifndef CONFIG_USER_ONLY
39 
40 void HELPER(update_ccount)(CPUXtensaState *env)
41 {
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)((now - env->time_base) *
47                    env->config->clock_freq_khz / 1000000);
48 }
49 
50 void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v)
51 {
52     int i;
53 
54     HELPER(update_ccount)(env);
55     env->ccount_base += v - env->sregs[CCOUNT];
56     for (i = 0; i < env->config->nccompare; ++i) {
57         HELPER(update_ccompare)(env, i);
58     }
59 }
60 
61 void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
62 {
63     uint64_t dcc;
64 
65     HELPER(update_ccount)(env);
66     dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1;
67     timer_mod(env->ccompare[i].timer,
68               env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz);
69     env->yield_needed = 1;
70 }
71 
72 /*!
73  * Check vaddr accessibility/cache attributes and raise an exception if
74  * specified by the ATOMCTL SR.
75  *
76  * Note: local memory exclusion is not implemented
77  */
78 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
79 {
80     uint32_t paddr, page_size, access;
81     uint32_t atomctl = env->sregs[ATOMCTL];
82     int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
83             xtensa_get_cring(env), &paddr, &page_size, &access);
84 
85     /*
86      * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions,
87      * see opcode description in the ISA
88      */
89     if (rc == 0 &&
90             (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) {
91         rc = STORE_PROHIBITED_CAUSE;
92     }
93 
94     if (rc) {
95         HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
96     }
97 
98     /*
99      * When data cache is not configured use ATOMCTL bypass field.
100      * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
101      * under the Conditional Store Option.
102      */
103     if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
104         access = PAGE_CACHE_BYPASS;
105     }
106 
107     switch (access & PAGE_CACHE_MASK) {
108     case PAGE_CACHE_WB:
109         atomctl >>= 2;
110         /* fall through */
111     case PAGE_CACHE_WT:
112         atomctl >>= 2;
113         /* fall through */
114     case PAGE_CACHE_BYPASS:
115         if ((atomctl & 0x3) == 0) {
116             HELPER(exception_cause_vaddr)(env, pc,
117                     LOAD_STORE_ERROR_CAUSE, vaddr);
118         }
119         break;
120 
121     case PAGE_CACHE_ISOLATE:
122         HELPER(exception_cause_vaddr)(env, pc,
123                 LOAD_STORE_ERROR_CAUSE, vaddr);
124         break;
125 
126     default:
127         break;
128     }
129 }
130 
131 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
132 {
133     if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
134         if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) >
135             env->config->icache_ways) {
136             deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN,
137                       env->config->icache_ways);
138         }
139     }
140     if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
141         if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) >
142             env->config->dcache_ways) {
143             deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN,
144                       env->config->dcache_ways);
145         }
146         if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) >
147             env->config->dcache_ways) {
148             deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN,
149                       env->config->dcache_ways);
150         }
151     }
152     env->sregs[MEMCTL] = v & env->config->memctl_mask;
153 }
154 
155 #endif
156 
157 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr)
158 {
159 #ifndef CONFIG_USER_ONLY
160     return address_space_ldl(env->address_space_er, addr,
161                              MEMTXATTRS_UNSPECIFIED, NULL);
162 #else
163     return 0;
164 #endif
165 }
166 
167 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr)
168 {
169 #ifndef CONFIG_USER_ONLY
170     address_space_stl(env->address_space_er, addr, data,
171                       MEMTXATTRS_UNSPECIFIED, NULL);
172 #endif
173 }
174