]>
Commit | Line | Data |
---|---|---|
2328826b MF |
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 | ||
09aae23d | 28 | #include "qemu/osdep.h" |
47e20887 | 29 | #include "qemu/main-loop.h" |
2328826b | 30 | #include "cpu.h" |
2ef6175a | 31 | #include "exec/helper-proto.h" |
1de7afc9 | 32 | #include "qemu/host-utils.h" |
63c91552 | 33 | #include "exec/exec-all.h" |
f08b6170 | 34 | #include "exec/cpu_ldst.h" |
0f590e74 | 35 | #include "qemu/timer.h" |
2328826b | 36 | |
ba7651fb MF |
37 | #ifndef CONFIG_USER_ONLY |
38 | ||
59a71f75 MF |
39 | void HELPER(update_ccount)(CPUXtensaState *env) |
40 | { | |
9e377be1 | 41 | XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); |
59a71f75 MF |
42 | uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
43 | ||
44 | env->ccount_time = now; | |
45 | env->sregs[CCOUNT] = env->ccount_base + | |
9e377be1 | 46 | (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base); |
59a71f75 MF |
47 | } |
48 | ||
49 | void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) | |
b994e91b | 50 | { |
59a71f75 MF |
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 | } | |
b994e91b MF |
58 | } |
59 | ||
59a71f75 | 60 | void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) |
b994e91b | 61 | { |
9e377be1 | 62 | XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); |
59a71f75 MF |
63 | uint64_t dcc; |
64 | ||
d73415a3 | 65 | qatomic_and(&env->sregs[INTSET], |
fa92bd4a | 66 | ~(1u << env->config->timerint[i])); |
59a71f75 MF |
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, | |
9e377be1 | 70 | env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc)); |
d2132510 | 71 | env->yield_needed = 1; |
b994e91b MF |
72 | } |
73 | ||
fcc803d1 MF |
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; | |
5739006b | 112 | /* fall through */ |
fcc803d1 MF |
113 | case PAGE_CACHE_WT: |
114 | atomctl >>= 2; | |
5739006b | 115 | /* fall through */ |
fcc803d1 MF |
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 | ||
b345e140 MF |
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 | ||
9e03ade4 MF |
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 | ||
ba7651fb | 199 | #endif |
dd519cbe | 200 | |
3a3c9dc4 MF |
201 | uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr) |
202 | { | |
ba7651fb | 203 | #ifndef CONFIG_USER_ONLY |
3a3c9dc4 | 204 | return address_space_ldl(env->address_space_er, addr, |
2c5b1d2a | 205 | MEMTXATTRS_UNSPECIFIED, NULL); |
ba7651fb MF |
206 | #else |
207 | return 0; | |
208 | #endif | |
3a3c9dc4 MF |
209 | } |
210 | ||
211 | void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr) | |
212 | { | |
ba7651fb | 213 | #ifndef CONFIG_USER_ONLY |
3a3c9dc4 | 214 | address_space_stl(env->address_space_er, addr, data, |
2c5b1d2a | 215 | MEMTXATTRS_UNSPECIFIED, NULL); |
ba7651fb | 216 | #endif |
3a3c9dc4 | 217 | } |