]>
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" |
29d8ec7b | 35 | #include "exec/address-spaces.h" |
0f590e74 | 36 | #include "qemu/timer.h" |
2328826b | 37 | |
ba7651fb MF |
38 | #ifndef CONFIG_USER_ONLY |
39 | ||
59a71f75 MF |
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) | |
b994e91b | 51 | { |
59a71f75 MF |
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 | } | |
b994e91b MF |
59 | } |
60 | ||
59a71f75 | 61 | void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) |
b994e91b | 62 | { |
59a71f75 MF |
63 | uint64_t dcc; |
64 | ||
fa92bd4a MF |
65 | atomic_and(&env->sregs[INTSET], |
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, | |
70 | env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); | |
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 | ||
9e03ade4 MF |
133 | void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v) |
134 | { | |
135 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) { | |
136 | if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) > | |
137 | env->config->icache_ways) { | |
138 | deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN, | |
139 | env->config->icache_ways); | |
140 | } | |
141 | } | |
142 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { | |
143 | if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) > | |
144 | env->config->dcache_ways) { | |
145 | deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN, | |
146 | env->config->dcache_ways); | |
147 | } | |
148 | if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) > | |
149 | env->config->dcache_ways) { | |
150 | deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN, | |
151 | env->config->dcache_ways); | |
152 | } | |
153 | } | |
154 | env->sregs[MEMCTL] = v & env->config->memctl_mask; | |
155 | } | |
156 | ||
ba7651fb | 157 | #endif |
dd519cbe | 158 | |
3a3c9dc4 MF |
159 | uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr) |
160 | { | |
ba7651fb | 161 | #ifndef CONFIG_USER_ONLY |
3a3c9dc4 | 162 | return address_space_ldl(env->address_space_er, addr, |
2c5b1d2a | 163 | MEMTXATTRS_UNSPECIFIED, NULL); |
ba7651fb MF |
164 | #else |
165 | return 0; | |
166 | #endif | |
3a3c9dc4 MF |
167 | } |
168 | ||
169 | void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr) | |
170 | { | |
ba7651fb | 171 | #ifndef CONFIG_USER_ONLY |
3a3c9dc4 | 172 | address_space_stl(env->address_space_er, addr, data, |
2c5b1d2a | 173 | MEMTXATTRS_UNSPECIFIED, NULL); |
ba7651fb | 174 | #endif |
3a3c9dc4 | 175 | } |