]>
Commit | Line | Data |
---|---|---|
e67db06e JL |
1 | /* |
2 | * OpenRISC virtual CPU header. | |
3 | * | |
4 | * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
07f5a258 MA |
20 | #ifndef OPENRISC_CPU_H |
21 | #define OPENRISC_CPU_H | |
e67db06e JL |
22 | |
23 | #define TARGET_LONG_BITS 32 | |
e67db06e JL |
24 | |
25 | #define CPUArchState struct CPUOpenRISCState | |
26 | ||
726fe045 JL |
27 | /* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */ |
28 | struct OpenRISCCPU; | |
29 | ||
e67db06e | 30 | #include "qemu-common.h" |
022c62cb | 31 | #include "exec/cpu-defs.h" |
14cccb61 | 32 | #include "qom/cpu.h" |
e67db06e | 33 | |
4a09d0bb | 34 | #define TYPE_OPENRISC_CPU "or1k-cpu" |
e67db06e JL |
35 | |
36 | #define OPENRISC_CPU_CLASS(klass) \ | |
37 | OBJECT_CLASS_CHECK(OpenRISCCPUClass, (klass), TYPE_OPENRISC_CPU) | |
38 | #define OPENRISC_CPU(obj) \ | |
39 | OBJECT_CHECK(OpenRISCCPU, (obj), TYPE_OPENRISC_CPU) | |
40 | #define OPENRISC_CPU_GET_CLASS(obj) \ | |
41 | OBJECT_GET_CLASS(OpenRISCCPUClass, (obj), TYPE_OPENRISC_CPU) | |
42 | ||
43 | /** | |
44 | * OpenRISCCPUClass: | |
c296262b | 45 | * @parent_realize: The parent class' realize handler. |
e67db06e JL |
46 | * @parent_reset: The parent class' reset handler. |
47 | * | |
48 | * A OpenRISC CPU model. | |
49 | */ | |
50 | typedef struct OpenRISCCPUClass { | |
51 | /*< private >*/ | |
52 | CPUClass parent_class; | |
53 | /*< public >*/ | |
54 | ||
c296262b | 55 | DeviceRealize parent_realize; |
e67db06e JL |
56 | void (*parent_reset)(CPUState *cpu); |
57 | } OpenRISCCPUClass; | |
58 | ||
59 | #define NB_MMU_MODES 3 | |
24c32852 | 60 | #define TARGET_INSN_START_EXTRA_WORDS 1 |
e67db06e | 61 | |
726fe045 JL |
62 | enum { |
63 | MMU_NOMMU_IDX = 0, | |
64 | MMU_SUPERVISOR_IDX = 1, | |
65 | MMU_USER_IDX = 2, | |
66 | }; | |
67 | ||
e67db06e JL |
68 | #define TARGET_PAGE_BITS 13 |
69 | ||
70 | #define TARGET_PHYS_ADDR_SPACE_BITS 32 | |
71 | #define TARGET_VIRT_ADDR_SPACE_BITS 32 | |
72 | ||
73 | #define SET_FP_CAUSE(reg, v) do {\ | |
74 | (reg) = ((reg) & ~(0x3f << 12)) | \ | |
75 | ((v & 0x3f) << 12);\ | |
76 | } while (0) | |
77 | #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) | |
78 | #define UPDATE_FP_FLAGS(reg, v) do {\ | |
79 | (reg) |= ((v & 0x1f) << 2);\ | |
80 | } while (0) | |
81 | ||
4dd044c6 JL |
82 | /* Version Register */ |
83 | #define SPR_VR 0xFFFF003F | |
84 | ||
b6a71ef7 JL |
85 | /* Interrupt */ |
86 | #define NR_IRQS 32 | |
87 | ||
e67db06e JL |
88 | /* Unit presece register */ |
89 | enum { | |
90 | UPR_UP = (1 << 0), | |
91 | UPR_DCP = (1 << 1), | |
92 | UPR_ICP = (1 << 2), | |
93 | UPR_DMP = (1 << 3), | |
94 | UPR_IMP = (1 << 4), | |
95 | UPR_MP = (1 << 5), | |
96 | UPR_DUP = (1 << 6), | |
97 | UPR_PCUR = (1 << 7), | |
98 | UPR_PMP = (1 << 8), | |
99 | UPR_PICP = (1 << 9), | |
100 | UPR_TTP = (1 << 10), | |
101 | UPR_CUP = (255 << 24), | |
102 | }; | |
103 | ||
104 | /* CPU configure register */ | |
105 | enum { | |
106 | CPUCFGR_NSGF = (15 << 0), | |
107 | CPUCFGR_CGF = (1 << 4), | |
108 | CPUCFGR_OB32S = (1 << 5), | |
109 | CPUCFGR_OB64S = (1 << 6), | |
110 | CPUCFGR_OF32S = (1 << 7), | |
111 | CPUCFGR_OF64S = (1 << 8), | |
112 | CPUCFGR_OV64S = (1 << 9), | |
356a2db3 TA |
113 | /* CPUCFGR_ND = (1 << 10), */ |
114 | /* CPUCFGR_AVRP = (1 << 11), */ | |
115 | CPUCFGR_EVBARP = (1 << 12), | |
116 | /* CPUCFGR_ISRP = (1 << 13), */ | |
117 | /* CPUCFGR_AECSRP = (1 << 14), */ | |
e67db06e JL |
118 | }; |
119 | ||
120 | /* DMMU configure register */ | |
121 | enum { | |
122 | DMMUCFGR_NTW = (3 << 0), | |
123 | DMMUCFGR_NTS = (7 << 2), | |
124 | DMMUCFGR_NAE = (7 << 5), | |
125 | DMMUCFGR_CRI = (1 << 8), | |
126 | DMMUCFGR_PRI = (1 << 9), | |
127 | DMMUCFGR_TEIRI = (1 << 10), | |
128 | DMMUCFGR_HTR = (1 << 11), | |
129 | }; | |
130 | ||
131 | /* IMMU configure register */ | |
132 | enum { | |
133 | IMMUCFGR_NTW = (3 << 0), | |
134 | IMMUCFGR_NTS = (7 << 2), | |
135 | IMMUCFGR_NAE = (7 << 5), | |
136 | IMMUCFGR_CRI = (1 << 8), | |
137 | IMMUCFGR_PRI = (1 << 9), | |
138 | IMMUCFGR_TEIRI = (1 << 10), | |
139 | IMMUCFGR_HTR = (1 << 11), | |
140 | }; | |
141 | ||
f4d1414a SH |
142 | /* Power management register */ |
143 | enum { | |
144 | PMR_SDF = (15 << 0), | |
145 | PMR_DME = (1 << 4), | |
146 | PMR_SME = (1 << 5), | |
147 | PMR_DCGE = (1 << 6), | |
148 | PMR_SUME = (1 << 7), | |
149 | }; | |
150 | ||
e67db06e JL |
151 | /* Float point control status register */ |
152 | enum { | |
153 | FPCSR_FPEE = 1, | |
154 | FPCSR_RM = (3 << 1), | |
155 | FPCSR_OVF = (1 << 3), | |
156 | FPCSR_UNF = (1 << 4), | |
157 | FPCSR_SNF = (1 << 5), | |
158 | FPCSR_QNF = (1 << 6), | |
159 | FPCSR_ZF = (1 << 7), | |
160 | FPCSR_IXF = (1 << 8), | |
161 | FPCSR_IVF = (1 << 9), | |
162 | FPCSR_INF = (1 << 10), | |
163 | FPCSR_DZF = (1 << 11), | |
164 | }; | |
165 | ||
166 | /* Exceptions indices */ | |
167 | enum { | |
168 | EXCP_RESET = 0x1, | |
169 | EXCP_BUSERR = 0x2, | |
170 | EXCP_DPF = 0x3, | |
171 | EXCP_IPF = 0x4, | |
172 | EXCP_TICK = 0x5, | |
173 | EXCP_ALIGN = 0x6, | |
174 | EXCP_ILLEGAL = 0x7, | |
175 | EXCP_INT = 0x8, | |
176 | EXCP_DTLBMISS = 0x9, | |
177 | EXCP_ITLBMISS = 0xa, | |
178 | EXCP_RANGE = 0xb, | |
179 | EXCP_SYSCALL = 0xc, | |
180 | EXCP_FPE = 0xd, | |
181 | EXCP_TRAP = 0xe, | |
182 | EXCP_NR, | |
183 | }; | |
184 | ||
185 | /* Supervisor register */ | |
186 | enum { | |
187 | SR_SM = (1 << 0), | |
188 | SR_TEE = (1 << 1), | |
189 | SR_IEE = (1 << 2), | |
190 | SR_DCE = (1 << 3), | |
191 | SR_ICE = (1 << 4), | |
192 | SR_DME = (1 << 5), | |
193 | SR_IME = (1 << 6), | |
194 | SR_LEE = (1 << 7), | |
195 | SR_CE = (1 << 8), | |
196 | SR_F = (1 << 9), | |
197 | SR_CY = (1 << 10), | |
198 | SR_OV = (1 << 11), | |
199 | SR_OVE = (1 << 12), | |
200 | SR_DSX = (1 << 13), | |
201 | SR_EPH = (1 << 14), | |
202 | SR_FO = (1 << 15), | |
203 | SR_SUMRA = (1 << 16), | |
204 | SR_SCE = (1 << 17), | |
205 | }; | |
206 | ||
99f575ed JL |
207 | /* Tick Timer Mode Register */ |
208 | enum { | |
209 | TTMR_TP = (0xfffffff), | |
210 | TTMR_IP = (1 << 28), | |
211 | TTMR_IE = (1 << 29), | |
212 | TTMR_M = (3 << 30), | |
213 | }; | |
214 | ||
215 | /* Timer Mode */ | |
216 | enum { | |
217 | TIMER_NONE = (0 << 30), | |
218 | TIMER_INTR = (1 << 30), | |
219 | TIMER_SHOT = (2 << 30), | |
220 | TIMER_CONT = (3 << 30), | |
221 | }; | |
222 | ||
726fe045 JL |
223 | /* TLB size */ |
224 | enum { | |
1cc9e5d8 | 225 | TLB_SIZE = 128, |
56c3a141 | 226 | TLB_MASK = TLB_SIZE - 1, |
726fe045 JL |
227 | }; |
228 | ||
229 | /* TLB prot */ | |
230 | enum { | |
231 | URE = (1 << 6), | |
232 | UWE = (1 << 7), | |
233 | SRE = (1 << 8), | |
234 | SWE = (1 << 9), | |
235 | ||
236 | SXE = (1 << 6), | |
237 | UXE = (1 << 7), | |
238 | }; | |
239 | ||
726fe045 JL |
240 | typedef struct OpenRISCTLBEntry { |
241 | uint32_t mr; | |
242 | uint32_t tr; | |
243 | } OpenRISCTLBEntry; | |
244 | ||
245 | #ifndef CONFIG_USER_ONLY | |
246 | typedef struct CPUOpenRISCTLBContext { | |
56c3a141 RH |
247 | OpenRISCTLBEntry itlb[TLB_SIZE]; |
248 | OpenRISCTLBEntry dtlb[TLB_SIZE]; | |
726fe045 JL |
249 | |
250 | int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu, | |
a8170e5e | 251 | hwaddr *physical, |
726fe045 JL |
252 | int *prot, |
253 | target_ulong address, int rw); | |
254 | int (*cpu_openrisc_map_address_data)(struct OpenRISCCPU *cpu, | |
a8170e5e | 255 | hwaddr *physical, |
726fe045 JL |
256 | int *prot, |
257 | target_ulong address, int rw); | |
258 | } CPUOpenRISCTLBContext; | |
259 | #endif | |
260 | ||
e67db06e | 261 | typedef struct CPUOpenRISCState { |
d89e71e8 SH |
262 | target_ulong shadow_gpr[16][32]; /* Shadow registers */ |
263 | ||
e67db06e | 264 | target_ulong pc; /* Program counter */ |
e67db06e JL |
265 | target_ulong ppc; /* Prev PC */ |
266 | target_ulong jmp_pc; /* Jump PC */ | |
267 | ||
6f7332ba | 268 | uint64_t mac; /* Multiply registers MACHI:MACLO */ |
e67db06e | 269 | |
e67db06e JL |
270 | target_ulong epcr; /* Exception PC register */ |
271 | target_ulong eear; /* Exception EA register */ | |
272 | ||
84775c43 | 273 | target_ulong sr_f; /* the SR_F bit, values 0, 1. */ |
97458071 RH |
274 | target_ulong sr_cy; /* the SR_CY bit, values 0, 1. */ |
275 | target_long sr_ov; /* the SR_OV bit (in the sign bit only) */ | |
276 | uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */ | |
e67db06e JL |
277 | uint32_t vr; /* Version register */ |
278 | uint32_t upr; /* Unit presence register */ | |
e67db06e JL |
279 | uint32_t dmmucfgr; /* DMMU configure register */ |
280 | uint32_t immucfgr; /* IMMU configure register */ | |
281 | uint32_t esr; /* Exception supervisor register */ | |
356a2db3 | 282 | uint32_t evbar; /* Exception vector base address register */ |
f4d1414a | 283 | uint32_t pmr; /* Power Management Register */ |
e67db06e JL |
284 | uint32_t fpcsr; /* Float register */ |
285 | float_status fp_status; | |
286 | ||
930c3d00 RH |
287 | target_ulong lock_addr; |
288 | target_ulong lock_value; | |
289 | ||
a01deb36 | 290 | uint32_t dflag; /* In delay slot (boolean) */ |
e67db06e | 291 | |
455d45d2 RH |
292 | #ifndef CONFIG_USER_ONLY |
293 | CPUOpenRISCTLBContext tlb; | |
294 | #endif | |
295 | ||
1f5c00cf AB |
296 | /* Fields up to this point are cleared by a CPU reset */ |
297 | struct {} end_reset_fields; | |
298 | ||
e67db06e JL |
299 | CPU_COMMON |
300 | ||
f0c3c505 | 301 | /* Fields from here on are preserved across CPU reset. */ |
48a1b62b SH |
302 | uint32_t cpucfgr; /* CPU configure register */ |
303 | ||
e67db06e | 304 | #ifndef CONFIG_USER_ONLY |
1246b259 | 305 | QEMUTimer *timer; |
e67db06e | 306 | uint32_t ttmr; /* Timer tick mode register */ |
6b4bbd6a | 307 | int is_counting; |
e67db06e JL |
308 | |
309 | uint32_t picmr; /* Interrupt mask register */ | |
310 | uint32_t picsr; /* Interrupt contrl register*/ | |
311 | #endif | |
b6a71ef7 | 312 | void *irq[32]; /* Interrupt irq input */ |
e67db06e JL |
313 | } CPUOpenRISCState; |
314 | ||
315 | /** | |
316 | * OpenRISCCPU: | |
317 | * @env: #CPUOpenRISCState | |
318 | * | |
319 | * A OpenRISC CPU. | |
320 | */ | |
321 | typedef struct OpenRISCCPU { | |
322 | /*< private >*/ | |
323 | CPUState parent_obj; | |
324 | /*< public >*/ | |
325 | ||
326 | CPUOpenRISCState env; | |
327 | ||
e67db06e JL |
328 | } OpenRISCCPU; |
329 | ||
330 | static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) | |
331 | { | |
6e42be7c | 332 | return container_of(env, OpenRISCCPU, env); |
e67db06e JL |
333 | } |
334 | ||
335 | #define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e)) | |
336 | ||
fadf9825 AF |
337 | #define ENV_OFFSET offsetof(OpenRISCCPU, env) |
338 | ||
0442428a | 339 | void cpu_openrisc_list(void); |
97a8ea5a | 340 | void openrisc_cpu_do_interrupt(CPUState *cpu); |
fbb96c4b | 341 | bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req); |
90c84c56 | 342 | void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); |
00b941e5 | 343 | hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); |
5b50e790 AF |
344 | int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); |
345 | int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); | |
e67db06e | 346 | void openrisc_translate_init(void); |
98670d47 | 347 | int openrisc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, |
726fe045 | 348 | int rw, int mmu_idx); |
d962783e | 349 | int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc); |
d5cabcce | 350 | int print_insn_or1k(bfd_vma addr, disassemble_info *info); |
e67db06e JL |
351 | |
352 | #define cpu_list cpu_openrisc_list | |
d962783e | 353 | #define cpu_signal_handler cpu_openrisc_signal_handler |
e67db06e JL |
354 | |
355 | #ifndef CONFIG_USER_ONLY | |
da697214 AF |
356 | extern const struct VMStateDescription vmstate_openrisc_cpu; |
357 | ||
dd29c7fb JL |
358 | /* hw/openrisc_pic.c */ |
359 | void cpu_openrisc_pic_init(OpenRISCCPU *cpu); | |
360 | ||
99f575ed JL |
361 | /* hw/openrisc_timer.c */ |
362 | void cpu_openrisc_clock_init(OpenRISCCPU *cpu); | |
6b4bbd6a SH |
363 | uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu); |
364 | void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val); | |
99f575ed | 365 | void cpu_openrisc_count_update(OpenRISCCPU *cpu); |
d5155217 | 366 | void cpu_openrisc_timer_update(OpenRISCCPU *cpu); |
99f575ed JL |
367 | void cpu_openrisc_count_start(OpenRISCCPU *cpu); |
368 | void cpu_openrisc_count_stop(OpenRISCCPU *cpu); | |
e67db06e JL |
369 | #endif |
370 | ||
a6772731 IM |
371 | #define OPENRISC_CPU_TYPE_SUFFIX "-" TYPE_OPENRISC_CPU |
372 | #define OPENRISC_CPU_TYPE_NAME(model) model OPENRISC_CPU_TYPE_SUFFIX | |
0dacec87 | 373 | #define CPU_RESOLVING_TYPE TYPE_OPENRISC_CPU |
a6772731 | 374 | |
022c62cb | 375 | #include "exec/cpu-all.h" |
e67db06e | 376 | |
b9bed1b9 RH |
377 | #define TB_FLAGS_SM SR_SM |
378 | #define TB_FLAGS_DME SR_DME | |
379 | #define TB_FLAGS_IME SR_IME | |
a01deb36 | 380 | #define TB_FLAGS_OVE SR_OVE |
b9bed1b9 RH |
381 | #define TB_FLAGS_DFLAG 2 /* reuse SR_TEE */ |
382 | #define TB_FLAGS_R0_0 4 /* reuse SR_IEE */ | |
a01deb36 | 383 | |
d89e71e8 SH |
384 | static inline uint32_t cpu_get_gpr(const CPUOpenRISCState *env, int i) |
385 | { | |
386 | return env->shadow_gpr[0][i]; | |
387 | } | |
388 | ||
389 | static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val) | |
390 | { | |
391 | env->shadow_gpr[0][i] = val; | |
392 | } | |
393 | ||
e67db06e JL |
394 | static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, |
395 | target_ulong *pc, | |
89fee74a | 396 | target_ulong *cs_base, uint32_t *flags) |
e67db06e JL |
397 | { |
398 | *pc = env->pc; | |
399 | *cs_base = 0; | |
b9bed1b9 RH |
400 | *flags = (env->dflag ? TB_FLAGS_DFLAG : 0) |
401 | | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0) | |
402 | | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE)); | |
e67db06e JL |
403 | } |
404 | ||
97ed5ccd | 405 | static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) |
e67db06e | 406 | { |
b9bed1b9 RH |
407 | int ret = MMU_NOMMU_IDX; /* mmu is disabled */ |
408 | ||
409 | if (env->sr & (ifetch ? SR_IME : SR_DME)) { | |
410 | /* The mmu is enabled; test supervisor state. */ | |
411 | ret = env->sr & SR_SM ? MMU_SUPERVISOR_IDX : MMU_USER_IDX; | |
726fe045 | 412 | } |
b9bed1b9 RH |
413 | |
414 | return ret; | |
e67db06e JL |
415 | } |
416 | ||
84775c43 RH |
417 | static inline uint32_t cpu_get_sr(const CPUOpenRISCState *env) |
418 | { | |
97458071 RH |
419 | return (env->sr |
420 | + env->sr_f * SR_F | |
421 | + env->sr_cy * SR_CY | |
422 | + (env->sr_ov < 0) * SR_OV); | |
84775c43 RH |
423 | } |
424 | ||
425 | static inline void cpu_set_sr(CPUOpenRISCState *env, uint32_t val) | |
426 | { | |
427 | env->sr_f = (val & SR_F) != 0; | |
97458071 RH |
428 | env->sr_cy = (val & SR_CY) != 0; |
429 | env->sr_ov = (val & SR_OV ? -1 : 0); | |
430 | env->sr = (val & ~(SR_F | SR_CY | SR_OV)) | SR_FO; | |
84775c43 RH |
431 | } |
432 | ||
b6a71ef7 | 433 | #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 |
e67db06e | 434 | |
07f5a258 | 435 | #endif /* OPENRISC_CPU_H */ |