xref: /qemu/target/tricore/helper.c (revision cc944932ecef3b7a56ae62d89dd92fb9e56c5cc8)
1 /*
2  *  Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "qemu/osdep.h"
19 #include "qemu/log.h"
20 #include "hw/registerfields.h"
21 #include "cpu.h"
22 #include "exec/cputlb.h"
23 #include "accel/tcg/cpu-mmu-index.h"
24 #include "exec/page-protection.h"
25 #include "fpu/softfloat-helpers.h"
26 #include "qemu/qemu-print.h"
27 
28 enum {
29     TLBRET_DIRTY = -4,
30     TLBRET_INVALID = -3,
31     TLBRET_NOMATCH = -2,
32     TLBRET_BADADDR = -1,
33     TLBRET_MATCH = 0
34 };
35 
36 static int get_physical_address(CPUTriCoreState *env, hwaddr *physical,
37                                 int *prot, target_ulong address,
38                                 MMUAccessType access_type, int mmu_idx)
39 {
40     int ret = TLBRET_MATCH;
41 
42     *physical = address & 0xFFFFFFFF;
43     *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
44 
45     return ret;
46 }
47 
48 hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
49 {
50     TriCoreCPU *cpu = TRICORE_CPU(cs);
51     hwaddr phys_addr;
52     int prot;
53     int mmu_idx = cpu_mmu_index(cs, false);
54 
55     if (get_physical_address(&cpu->env, &phys_addr, &prot, addr,
56                              MMU_DATA_LOAD, mmu_idx)) {
57         return -1;
58     }
59     return phys_addr;
60 }
61 
62 /* TODO: Add exception support */
63 static void raise_mmu_exception(CPUTriCoreState *env, target_ulong address,
64                                 int rw, int tlb_error)
65 {
66 }
67 
68 bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
69                           MMUAccessType rw, int mmu_idx,
70                           bool probe, uintptr_t retaddr)
71 {
72     CPUTriCoreState *env = cpu_env(cs);
73     hwaddr physical;
74     int prot;
75     int ret = 0;
76 
77     rw &= 1;
78     ret = get_physical_address(env, &physical, &prot,
79                                address, rw, mmu_idx);
80 
81     qemu_log_mask(CPU_LOG_MMU, "%s address=0x%" VADDR_PRIx " ret %d physical "
82                   HWADDR_FMT_plx " prot %d\n",
83                   __func__, address, ret, physical, prot);
84 
85     if (ret == TLBRET_MATCH) {
86         tlb_set_page(cs, address & TARGET_PAGE_MASK,
87                      physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
88                      mmu_idx, TARGET_PAGE_SIZE);
89         return true;
90     } else {
91         assert(ret < 0);
92         if (probe) {
93             return false;
94         }
95         raise_mmu_exception(env, address, rw, ret);
96         cpu_loop_exit_restore(cs, retaddr);
97     }
98 }
99 
100 void fpu_set_state(CPUTriCoreState *env)
101 {
102     switch (extract32(env->PSW, 24, 2)) {
103     case 0:
104         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
105         break;
106     case 1:
107         set_float_rounding_mode(float_round_up, &env->fp_status);
108         break;
109     case 2:
110         set_float_rounding_mode(float_round_down, &env->fp_status);
111         break;
112     case 3:
113         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
114         break;
115     }
116 
117     set_flush_inputs_to_zero(1, &env->fp_status);
118     set_flush_to_zero(1, &env->fp_status);
119     set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
120     set_float_ftz_detection(float_ftz_before_rounding, &env->fp_status);
121     set_default_nan_mode(1, &env->fp_status);
122     /* Default NaN pattern: sign bit clear, frac msb set */
123     set_float_default_nan_pattern(0b01000000, &env->fp_status);
124 }
125 
126 uint32_t psw_read(CPUTriCoreState *env)
127 {
128     /* clear all USB bits */
129     env->PSW &= 0x7ffffff;
130     /* now set them from the cache */
131     env->PSW |= ((env->PSW_USB_C != 0) << 31);
132     env->PSW |= ((env->PSW_USB_V   & (1 << 31))  >> 1);
133     env->PSW |= ((env->PSW_USB_SV  & (1 << 31))  >> 2);
134     env->PSW |= ((env->PSW_USB_AV  & (1 << 31))  >> 3);
135     env->PSW |= ((env->PSW_USB_SAV & (1 << 31))  >> 4);
136 
137     return env->PSW;
138 }
139 
140 void psw_write(CPUTriCoreState *env, uint32_t val)
141 {
142     env->PSW_USB_C = (val & MASK_USB_C);
143     env->PSW_USB_V = (val & MASK_USB_V) << 1;
144     env->PSW_USB_SV = (val & MASK_USB_SV) << 2;
145     env->PSW_USB_AV = (val & MASK_USB_AV) << 3;
146     env->PSW_USB_SAV = (val & MASK_USB_SAV) << 4;
147     env->PSW = val;
148 
149     fpu_set_state(env);
150 }
151 
152 #define FIELD_GETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE)     \
153 uint32_t NAME(CPUTriCoreState *env)                             \
154 {                                                                \
155     if (tricore_has_feature(env, TRICORE_FEATURE_##FEATURE)) {   \
156         return FIELD_EX32(env->REG, REG, FIELD ## _ ## FEATURE); \
157     }                                                            \
158     return FIELD_EX32(env->REG, REG, FIELD ## _13);              \
159 }
160 
161 #define FIELD_GETTER(NAME, REG, FIELD)       \
162 uint32_t NAME(CPUTriCoreState *env)         \
163 {                                            \
164     return FIELD_EX32(env->REG, REG, FIELD); \
165 }
166 
167 #define FIELD_SETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE)              \
168 void NAME(CPUTriCoreState *env, uint32_t val)                            \
169 {                                                                         \
170     if (tricore_has_feature(env, TRICORE_FEATURE_##FEATURE)) {            \
171         env->REG = FIELD_DP32(env->REG, REG, FIELD ## _ ## FEATURE, val); \
172     }                                                                     \
173     env->REG = FIELD_DP32(env->REG, REG, FIELD ## _13, val);              \
174 }
175 
176 #define FIELD_SETTER(NAME, REG, FIELD)                \
177 void NAME(CPUTriCoreState *env, uint32_t val)        \
178 {                                                     \
179     env->REG = FIELD_DP32(env->REG, REG, FIELD, val); \
180 }
181 
182 FIELD_GETTER_WITH_FEATURE(pcxi_get_pcpn, PCXI, PCPN, 161)
183 FIELD_SETTER_WITH_FEATURE(pcxi_set_pcpn, PCXI, PCPN, 161)
184 FIELD_GETTER_WITH_FEATURE(pcxi_get_pie, PCXI, PIE, 161)
185 FIELD_SETTER_WITH_FEATURE(pcxi_set_pie, PCXI, PIE, 161)
186 FIELD_GETTER_WITH_FEATURE(pcxi_get_ul, PCXI, UL, 161)
187 FIELD_SETTER_WITH_FEATURE(pcxi_set_ul, PCXI, UL, 161)
188 FIELD_GETTER(pcxi_get_pcxs, PCXI, PCXS)
189 FIELD_GETTER(pcxi_get_pcxo, PCXI, PCXO)
190 
191 FIELD_GETTER_WITH_FEATURE(icr_get_ie, ICR, IE, 161)
192 FIELD_SETTER_WITH_FEATURE(icr_set_ie, ICR, IE, 161)
193 FIELD_GETTER(icr_get_ccpn, ICR, CCPN)
194 FIELD_SETTER(icr_set_ccpn, ICR, CCPN)
195