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 | #ifndef XTENSA_CPU_H |
29 | #define XTENSA_CPU_H |
30 | |
31 | #include "cpu-qom.h" |
32 | #include "exec/cpu-defs.h" |
33 | #include "xtensa-isa.h" |
34 | |
35 | /* Xtensa processors have a weak memory model */ |
36 | #define TCG_GUEST_DEFAULT_MO (0) |
37 | |
38 | enum { |
39 | /* Additional instructions */ |
40 | XTENSA_OPTION_CODE_DENSITY, |
41 | XTENSA_OPTION_LOOP, |
42 | XTENSA_OPTION_EXTENDED_L32R, |
43 | XTENSA_OPTION_16_BIT_IMUL, |
44 | XTENSA_OPTION_32_BIT_IMUL, |
45 | XTENSA_OPTION_32_BIT_IMUL_HIGH, |
46 | XTENSA_OPTION_32_BIT_IDIV, |
47 | XTENSA_OPTION_MAC16, |
48 | XTENSA_OPTION_MISC_OP_NSA, |
49 | XTENSA_OPTION_MISC_OP_MINMAX, |
50 | XTENSA_OPTION_MISC_OP_SEXT, |
51 | XTENSA_OPTION_MISC_OP_CLAMPS, |
52 | XTENSA_OPTION_COPROCESSOR, |
53 | XTENSA_OPTION_BOOLEAN, |
54 | XTENSA_OPTION_FP_COPROCESSOR, |
55 | XTENSA_OPTION_MP_SYNCHRO, |
56 | XTENSA_OPTION_CONDITIONAL_STORE, |
57 | XTENSA_OPTION_ATOMCTL, |
58 | XTENSA_OPTION_DEPBITS, |
59 | |
60 | /* Interrupts and exceptions */ |
61 | XTENSA_OPTION_EXCEPTION, |
62 | XTENSA_OPTION_RELOCATABLE_VECTOR, |
63 | XTENSA_OPTION_UNALIGNED_EXCEPTION, |
64 | XTENSA_OPTION_INTERRUPT, |
65 | XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT, |
66 | XTENSA_OPTION_TIMER_INTERRUPT, |
67 | |
68 | /* Local memory */ |
69 | XTENSA_OPTION_ICACHE, |
70 | XTENSA_OPTION_ICACHE_TEST, |
71 | XTENSA_OPTION_ICACHE_INDEX_LOCK, |
72 | XTENSA_OPTION_DCACHE, |
73 | XTENSA_OPTION_DCACHE_TEST, |
74 | XTENSA_OPTION_DCACHE_INDEX_LOCK, |
75 | XTENSA_OPTION_IRAM, |
76 | XTENSA_OPTION_IROM, |
77 | XTENSA_OPTION_DRAM, |
78 | XTENSA_OPTION_DROM, |
79 | XTENSA_OPTION_XLMI, |
80 | XTENSA_OPTION_HW_ALIGNMENT, |
81 | XTENSA_OPTION_MEMORY_ECC_PARITY, |
82 | |
83 | /* Memory protection and translation */ |
84 | XTENSA_OPTION_REGION_PROTECTION, |
85 | XTENSA_OPTION_REGION_TRANSLATION, |
86 | XTENSA_OPTION_MPU, |
87 | XTENSA_OPTION_MMU, |
88 | XTENSA_OPTION_CACHEATTR, |
89 | |
90 | /* Other */ |
91 | XTENSA_OPTION_WINDOWED_REGISTER, |
92 | XTENSA_OPTION_PROCESSOR_INTERFACE, |
93 | XTENSA_OPTION_MISC_SR, |
94 | XTENSA_OPTION_THREAD_POINTER, |
95 | XTENSA_OPTION_PROCESSOR_ID, |
96 | XTENSA_OPTION_DEBUG, |
97 | XTENSA_OPTION_TRACE_PORT, |
98 | XTENSA_OPTION_EXTERN_REGS, |
99 | }; |
100 | |
101 | enum { |
102 | EXPSTATE = 230, |
103 | THREADPTR = 231, |
104 | FCR = 232, |
105 | FSR = 233, |
106 | }; |
107 | |
108 | enum { |
109 | LBEG = 0, |
110 | LEND = 1, |
111 | LCOUNT = 2, |
112 | SAR = 3, |
113 | BR = 4, |
114 | LITBASE = 5, |
115 | SCOMPARE1 = 12, |
116 | ACCLO = 16, |
117 | ACCHI = 17, |
118 | MR = 32, |
119 | PREFCTL = 40, |
120 | WINDOW_BASE = 72, |
121 | WINDOW_START = 73, |
122 | PTEVADDR = 83, |
123 | MMID = 89, |
124 | RASID = 90, |
125 | MPUENB = 90, |
126 | ITLBCFG = 91, |
127 | DTLBCFG = 92, |
128 | MPUCFG = 92, |
129 | ERACCESS = 95, |
130 | IBREAKENABLE = 96, |
131 | MEMCTL = 97, |
132 | CACHEATTR = 98, |
133 | CACHEADRDIS = 98, |
134 | ATOMCTL = 99, |
135 | DDR = 104, |
136 | MEPC = 106, |
137 | MEPS = 107, |
138 | MESAVE = 108, |
139 | MESR = 109, |
140 | MECR = 110, |
141 | MEVADDR = 111, |
142 | IBREAKA = 128, |
143 | DBREAKA = 144, |
144 | DBREAKC = 160, |
145 | CONFIGID0 = 176, |
146 | EPC1 = 177, |
147 | DEPC = 192, |
148 | EPS2 = 194, |
149 | CONFIGID1 = 208, |
150 | EXCSAVE1 = 209, |
151 | CPENABLE = 224, |
152 | INTSET = 226, |
153 | INTCLEAR = 227, |
154 | INTENABLE = 228, |
155 | PS = 230, |
156 | VECBASE = 231, |
157 | EXCCAUSE = 232, |
158 | DEBUGCAUSE = 233, |
159 | CCOUNT = 234, |
160 | PRID = 235, |
161 | ICOUNT = 236, |
162 | ICOUNTLEVEL = 237, |
163 | EXCVADDR = 238, |
164 | CCOMPARE = 240, |
165 | MISC = 244, |
166 | }; |
167 | |
168 | #define PS_INTLEVEL 0xf |
169 | #define PS_INTLEVEL_SHIFT 0 |
170 | |
171 | #define PS_EXCM 0x10 |
172 | #define PS_UM 0x20 |
173 | |
174 | #define PS_RING 0xc0 |
175 | #define PS_RING_SHIFT 6 |
176 | |
177 | #define PS_OWB 0xf00 |
178 | #define PS_OWB_SHIFT 8 |
179 | #define PS_OWB_LEN 4 |
180 | |
181 | #define PS_CALLINC 0x30000 |
182 | #define PS_CALLINC_SHIFT 16 |
183 | #define PS_CALLINC_LEN 2 |
184 | |
185 | #define PS_WOE 0x40000 |
186 | |
187 | #define DEBUGCAUSE_IC 0x1 |
188 | #define DEBUGCAUSE_IB 0x2 |
189 | #define DEBUGCAUSE_DB 0x4 |
190 | #define DEBUGCAUSE_BI 0x8 |
191 | #define DEBUGCAUSE_BN 0x10 |
192 | #define DEBUGCAUSE_DI 0x20 |
193 | #define DEBUGCAUSE_DBNUM 0xf00 |
194 | #define DEBUGCAUSE_DBNUM_SHIFT 8 |
195 | |
196 | #define DBREAKC_SB 0x80000000 |
197 | #define DBREAKC_LB 0x40000000 |
198 | #define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB) |
199 | #define DBREAKC_MASK 0x3f |
200 | |
201 | #define MEMCTL_INIT 0x00800000 |
202 | #define MEMCTL_IUSEWAYS_SHIFT 18 |
203 | #define MEMCTL_IUSEWAYS_LEN 5 |
204 | #define MEMCTL_IUSEWAYS_MASK 0x007c0000 |
205 | #define MEMCTL_DALLOCWAYS_SHIFT 13 |
206 | #define MEMCTL_DALLOCWAYS_LEN 5 |
207 | #define MEMCTL_DALLOCWAYS_MASK 0x0003e000 |
208 | #define MEMCTL_DUSEWAYS_SHIFT 8 |
209 | #define MEMCTL_DUSEWAYS_LEN 5 |
210 | #define MEMCTL_DUSEWAYS_MASK 0x00001f00 |
211 | #define MEMCTL_ISNP 0x4 |
212 | #define MEMCTL_DSNP 0x2 |
213 | #define MEMCTL_IL0EN 0x1 |
214 | |
215 | #define MAX_INSN_LENGTH 64 |
216 | #define MAX_INSN_SLOTS 32 |
217 | #define MAX_OPCODE_ARGS 16 |
218 | #define MAX_NAREG 64 |
219 | #define MAX_NINTERRUPT 32 |
220 | #define MAX_NLEVEL 6 |
221 | #define MAX_NNMI 1 |
222 | #define MAX_NCCOMPARE 3 |
223 | #define MAX_TLB_WAY_SIZE 8 |
224 | #define MAX_NDBREAK 2 |
225 | #define MAX_NMEMORY 4 |
226 | #define MAX_MPU_FOREGROUND_SEGMENTS 32 |
227 | |
228 | #define REGION_PAGE_MASK 0xe0000000 |
229 | |
230 | #define PAGE_CACHE_MASK 0x700 |
231 | #define PAGE_CACHE_SHIFT 8 |
232 | #define PAGE_CACHE_INVALID 0x000 |
233 | #define PAGE_CACHE_BYPASS 0x100 |
234 | #define PAGE_CACHE_WT 0x200 |
235 | #define PAGE_CACHE_WB 0x400 |
236 | #define PAGE_CACHE_ISOLATE 0x600 |
237 | |
238 | enum { |
239 | /* Static vectors */ |
240 | EXC_RESET0, |
241 | EXC_RESET1, |
242 | EXC_MEMORY_ERROR, |
243 | |
244 | /* Dynamic vectors */ |
245 | EXC_WINDOW_OVERFLOW4, |
246 | EXC_WINDOW_UNDERFLOW4, |
247 | EXC_WINDOW_OVERFLOW8, |
248 | EXC_WINDOW_UNDERFLOW8, |
249 | EXC_WINDOW_OVERFLOW12, |
250 | EXC_WINDOW_UNDERFLOW12, |
251 | EXC_IRQ, |
252 | EXC_KERNEL, |
253 | EXC_USER, |
254 | EXC_DOUBLE, |
255 | EXC_DEBUG, |
256 | EXC_MAX |
257 | }; |
258 | |
259 | enum { |
260 | ILLEGAL_INSTRUCTION_CAUSE = 0, |
261 | SYSCALL_CAUSE, |
262 | INSTRUCTION_FETCH_ERROR_CAUSE, |
263 | LOAD_STORE_ERROR_CAUSE, |
264 | LEVEL1_INTERRUPT_CAUSE, |
265 | ALLOCA_CAUSE, |
266 | INTEGER_DIVIDE_BY_ZERO_CAUSE, |
267 | PC_VALUE_ERROR_CAUSE, |
268 | PRIVILEGED_CAUSE, |
269 | LOAD_STORE_ALIGNMENT_CAUSE, |
270 | EXTERNAL_REG_PRIVILEGE_CAUSE, |
271 | EXCLUSIVE_ERROR_CAUSE, |
272 | INSTR_PIF_DATA_ERROR_CAUSE, |
273 | LOAD_STORE_PIF_DATA_ERROR_CAUSE, |
274 | INSTR_PIF_ADDR_ERROR_CAUSE, |
275 | LOAD_STORE_PIF_ADDR_ERROR_CAUSE, |
276 | INST_TLB_MISS_CAUSE, |
277 | INST_TLB_MULTI_HIT_CAUSE, |
278 | INST_FETCH_PRIVILEGE_CAUSE, |
279 | INST_FETCH_PROHIBITED_CAUSE = 20, |
280 | LOAD_STORE_TLB_MISS_CAUSE = 24, |
281 | LOAD_STORE_TLB_MULTI_HIT_CAUSE, |
282 | LOAD_STORE_PRIVILEGE_CAUSE, |
283 | LOAD_PROHIBITED_CAUSE = 28, |
284 | STORE_PROHIBITED_CAUSE, |
285 | |
286 | COPROCESSOR0_DISABLED = 32, |
287 | }; |
288 | |
289 | typedef enum { |
290 | INTTYPE_LEVEL, |
291 | INTTYPE_EDGE, |
292 | INTTYPE_NMI, |
293 | INTTYPE_SOFTWARE, |
294 | INTTYPE_TIMER, |
295 | INTTYPE_DEBUG, |
296 | INTTYPE_WRITE_ERR, |
297 | INTTYPE_PROFILING, |
298 | INTTYPE_IDMA_DONE, |
299 | INTTYPE_IDMA_ERR, |
300 | INTTYPE_GS_ERR, |
301 | INTTYPE_MAX |
302 | } interrupt_type; |
303 | |
304 | struct CPUXtensaState; |
305 | |
306 | typedef struct xtensa_tlb_entry { |
307 | uint32_t vaddr; |
308 | uint32_t paddr; |
309 | uint8_t asid; |
310 | uint8_t attr; |
311 | bool variable; |
312 | } xtensa_tlb_entry; |
313 | |
314 | typedef struct xtensa_tlb { |
315 | unsigned nways; |
316 | const unsigned way_size[10]; |
317 | bool varway56; |
318 | unsigned nrefillentries; |
319 | } xtensa_tlb; |
320 | |
321 | typedef struct xtensa_mpu_entry { |
322 | uint32_t vaddr; |
323 | uint32_t attr; |
324 | } xtensa_mpu_entry; |
325 | |
326 | typedef struct XtensaGdbReg { |
327 | int targno; |
328 | unsigned flags; |
329 | int type; |
330 | int group; |
331 | unsigned size; |
332 | } XtensaGdbReg; |
333 | |
334 | typedef struct XtensaGdbRegmap { |
335 | int num_regs; |
336 | int num_core_regs; |
337 | /* PC + a + ar + sr + ur */ |
338 | XtensaGdbReg reg[1 + 16 + 64 + 256 + 256]; |
339 | } XtensaGdbRegmap; |
340 | |
341 | typedef struct XtensaCcompareTimer { |
342 | struct CPUXtensaState *env; |
343 | QEMUTimer *timer; |
344 | } XtensaCcompareTimer; |
345 | |
346 | typedef struct XtensaMemory { |
347 | unsigned num; |
348 | struct XtensaMemoryRegion { |
349 | uint32_t addr; |
350 | uint32_t size; |
351 | } location[MAX_NMEMORY]; |
352 | } XtensaMemory; |
353 | |
354 | typedef struct opcode_arg { |
355 | uint32_t imm; |
356 | uint32_t raw_imm; |
357 | void *in; |
358 | void *out; |
359 | } OpcodeArg; |
360 | |
361 | typedef struct DisasContext DisasContext; |
362 | typedef void (*XtensaOpcodeOp)(DisasContext *dc, const OpcodeArg arg[], |
363 | const uint32_t par[]); |
364 | typedef bool (*XtensaOpcodeBoolTest)(DisasContext *dc, |
365 | const OpcodeArg arg[], |
366 | const uint32_t par[]); |
367 | typedef uint32_t (*XtensaOpcodeUintTest)(DisasContext *dc, |
368 | const OpcodeArg arg[], |
369 | const uint32_t par[]); |
370 | |
371 | enum { |
372 | XTENSA_OP_ILL = 0x1, |
373 | XTENSA_OP_PRIVILEGED = 0x2, |
374 | XTENSA_OP_SYSCALL = 0x4, |
375 | XTENSA_OP_DEBUG_BREAK = 0x8, |
376 | |
377 | XTENSA_OP_OVERFLOW = 0x10, |
378 | XTENSA_OP_UNDERFLOW = 0x20, |
379 | XTENSA_OP_ALLOCA = 0x40, |
380 | XTENSA_OP_COPROCESSOR = 0x80, |
381 | |
382 | XTENSA_OP_DIVIDE_BY_ZERO = 0x100, |
383 | |
384 | /* Postprocessing flags */ |
385 | XTENSA_OP_CHECK_INTERRUPTS = 0x200, |
386 | XTENSA_OP_EXIT_TB_M1 = 0x400, |
387 | XTENSA_OP_EXIT_TB_0 = 0x800, |
388 | XTENSA_OP_SYNC_REGISTER_WINDOW = 0x1000, |
389 | |
390 | XTENSA_OP_POSTPROCESS = |
391 | XTENSA_OP_CHECK_INTERRUPTS | |
392 | XTENSA_OP_EXIT_TB_M1 | |
393 | XTENSA_OP_EXIT_TB_0 | |
394 | XTENSA_OP_SYNC_REGISTER_WINDOW, |
395 | |
396 | XTENSA_OP_NAME_ARRAY = 0x8000, |
397 | |
398 | XTENSA_OP_CONTROL_FLOW = 0x10000, |
399 | XTENSA_OP_STORE = 0x20000, |
400 | XTENSA_OP_LOAD = 0x40000, |
401 | XTENSA_OP_LOAD_STORE = |
402 | XTENSA_OP_LOAD | XTENSA_OP_STORE, |
403 | }; |
404 | |
405 | typedef struct XtensaOpcodeOps { |
406 | const void *name; |
407 | XtensaOpcodeOp translate; |
408 | XtensaOpcodeBoolTest test_ill; |
409 | XtensaOpcodeUintTest test_overflow; |
410 | const uint32_t *par; |
411 | uint32_t op_flags; |
412 | uint32_t coprocessor; |
413 | } XtensaOpcodeOps; |
414 | |
415 | typedef struct XtensaOpcodeTranslators { |
416 | unsigned num_opcodes; |
417 | const XtensaOpcodeOps *opcode; |
418 | } XtensaOpcodeTranslators; |
419 | |
420 | extern const XtensaOpcodeTranslators xtensa_core_opcodes; |
421 | extern const XtensaOpcodeTranslators xtensa_fpu2000_opcodes; |
422 | |
423 | struct XtensaConfig { |
424 | const char *name; |
425 | uint64_t options; |
426 | XtensaGdbRegmap gdb_regmap; |
427 | unsigned nareg; |
428 | int excm_level; |
429 | int ndepc; |
430 | unsigned inst_fetch_width; |
431 | unsigned max_insn_size; |
432 | uint32_t vecbase; |
433 | uint32_t exception_vector[EXC_MAX]; |
434 | unsigned ninterrupt; |
435 | unsigned nlevel; |
436 | uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1]; |
437 | uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1]; |
438 | uint32_t inttype_mask[INTTYPE_MAX]; |
439 | struct { |
440 | uint32_t level; |
441 | interrupt_type inttype; |
442 | } interrupt[MAX_NINTERRUPT]; |
443 | unsigned nccompare; |
444 | uint32_t timerint[MAX_NCCOMPARE]; |
445 | unsigned nextint; |
446 | unsigned extint[MAX_NINTERRUPT]; |
447 | |
448 | unsigned debug_level; |
449 | unsigned nibreak; |
450 | unsigned ndbreak; |
451 | |
452 | unsigned icache_ways; |
453 | unsigned dcache_ways; |
454 | unsigned dcache_line_bytes; |
455 | uint32_t memctl_mask; |
456 | |
457 | XtensaMemory instrom; |
458 | XtensaMemory instram; |
459 | XtensaMemory datarom; |
460 | XtensaMemory dataram; |
461 | XtensaMemory sysrom; |
462 | XtensaMemory sysram; |
463 | |
464 | uint32_t configid[2]; |
465 | |
466 | void *isa_internal; |
467 | xtensa_isa isa; |
468 | XtensaOpcodeOps **opcode_ops; |
469 | const XtensaOpcodeTranslators **opcode_translators; |
470 | xtensa_regfile a_regfile; |
471 | void ***regfile; |
472 | |
473 | uint32_t clock_freq_khz; |
474 | |
475 | xtensa_tlb itlb; |
476 | xtensa_tlb dtlb; |
477 | |
478 | uint32_t mpu_align; |
479 | unsigned n_mpu_fg_segments; |
480 | unsigned n_mpu_bg_segments; |
481 | const xtensa_mpu_entry *mpu_bg; |
482 | }; |
483 | |
484 | typedef struct XtensaConfigList { |
485 | const XtensaConfig *config; |
486 | struct XtensaConfigList *next; |
487 | } XtensaConfigList; |
488 | |
489 | #ifdef HOST_WORDS_BIGENDIAN |
490 | enum { |
491 | FP_F32_HIGH, |
492 | FP_F32_LOW, |
493 | }; |
494 | #else |
495 | enum { |
496 | FP_F32_LOW, |
497 | FP_F32_HIGH, |
498 | }; |
499 | #endif |
500 | |
501 | typedef struct CPUXtensaState { |
502 | const XtensaConfig *config; |
503 | uint32_t regs[16]; |
504 | uint32_t pc; |
505 | uint32_t sregs[256]; |
506 | uint32_t uregs[256]; |
507 | uint32_t phys_regs[MAX_NAREG]; |
508 | union { |
509 | float32 f32[2]; |
510 | float64 f64; |
511 | } fregs[16]; |
512 | float_status fp_status; |
513 | uint32_t windowbase_next; |
514 | uint32_t exclusive_addr; |
515 | uint32_t exclusive_val; |
516 | |
517 | #ifndef CONFIG_USER_ONLY |
518 | xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; |
519 | xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; |
520 | xtensa_mpu_entry mpu_fg[MAX_MPU_FOREGROUND_SEGMENTS]; |
521 | unsigned autorefill_idx; |
522 | bool runstall; |
523 | AddressSpace *address_space_er; |
524 | MemoryRegion *system_er; |
525 | int pending_irq_level; /* level of last raised IRQ */ |
526 | qemu_irq *irq_inputs; |
527 | qemu_irq ext_irq_inputs[MAX_NINTERRUPT]; |
528 | qemu_irq runstall_irq; |
529 | XtensaCcompareTimer ccompare[MAX_NCCOMPARE]; |
530 | uint64_t time_base; |
531 | uint64_t ccount_time; |
532 | uint32_t ccount_base; |
533 | #endif |
534 | |
535 | int exception_taken; |
536 | int yield_needed; |
537 | unsigned static_vectors; |
538 | |
539 | /* Watchpoints for DBREAK registers */ |
540 | struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; |
541 | } CPUXtensaState; |
542 | |
543 | /** |
544 | * XtensaCPU: |
545 | * @env: #CPUXtensaState |
546 | * |
547 | * An Xtensa CPU. |
548 | */ |
549 | struct XtensaCPU { |
550 | /*< private >*/ |
551 | CPUState parent_obj; |
552 | /*< public >*/ |
553 | |
554 | CPUNegativeOffsetState neg; |
555 | CPUXtensaState env; |
556 | }; |
557 | |
558 | |
559 | bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size, |
560 | MMUAccessType access_type, int mmu_idx, |
561 | bool probe, uintptr_t retaddr); |
562 | void xtensa_cpu_do_interrupt(CPUState *cpu); |
563 | bool xtensa_cpu_exec_interrupt(CPUState *cpu, int interrupt_request); |
564 | void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, |
565 | unsigned size, MMUAccessType access_type, |
566 | int mmu_idx, MemTxAttrs attrs, |
567 | MemTxResult response, uintptr_t retaddr); |
568 | void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags); |
569 | hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); |
570 | void xtensa_count_regs(const XtensaConfig *config, |
571 | unsigned *n_regs, unsigned *n_core_regs); |
572 | int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); |
573 | int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); |
574 | void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, |
575 | MMUAccessType access_type, |
576 | int mmu_idx, uintptr_t retaddr); |
577 | |
578 | #define cpu_signal_handler cpu_xtensa_signal_handler |
579 | #define cpu_list xtensa_cpu_list |
580 | |
581 | #define XTENSA_CPU_TYPE_SUFFIX "-" TYPE_XTENSA_CPU |
582 | #define XTENSA_CPU_TYPE_NAME(model) model XTENSA_CPU_TYPE_SUFFIX |
583 | #define CPU_RESOLVING_TYPE TYPE_XTENSA_CPU |
584 | |
585 | #ifdef TARGET_WORDS_BIGENDIAN |
586 | #define XTENSA_DEFAULT_CPU_MODEL "fsf" |
587 | #define XTENSA_DEFAULT_CPU_NOMMU_MODEL "fsf" |
588 | #else |
589 | #define XTENSA_DEFAULT_CPU_MODEL "dc232b" |
590 | #define XTENSA_DEFAULT_CPU_NOMMU_MODEL "de212" |
591 | #endif |
592 | #define XTENSA_DEFAULT_CPU_TYPE \ |
593 | XTENSA_CPU_TYPE_NAME(XTENSA_DEFAULT_CPU_MODEL) |
594 | #define XTENSA_DEFAULT_CPU_NOMMU_TYPE \ |
595 | XTENSA_CPU_TYPE_NAME(XTENSA_DEFAULT_CPU_NOMMU_MODEL) |
596 | |
597 | void xtensa_collect_sr_names(const XtensaConfig *config); |
598 | void xtensa_translate_init(void); |
599 | void **xtensa_get_regfile_by_name(const char *name); |
600 | void xtensa_breakpoint_handler(CPUState *cs); |
601 | void xtensa_register_core(XtensaConfigList *node); |
602 | void xtensa_sim_open_console(Chardev *chr); |
603 | void check_interrupts(CPUXtensaState *s); |
604 | void xtensa_irq_init(CPUXtensaState *env); |
605 | qemu_irq *xtensa_get_extints(CPUXtensaState *env); |
606 | qemu_irq xtensa_get_runstall(CPUXtensaState *env); |
607 | int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); |
608 | void xtensa_cpu_list(void); |
609 | void xtensa_sync_window_from_phys(CPUXtensaState *env); |
610 | void xtensa_sync_phys_from_window(CPUXtensaState *env); |
611 | void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta); |
612 | void xtensa_restore_owb(CPUXtensaState *env); |
613 | void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); |
614 | |
615 | static inline void xtensa_select_static_vectors(CPUXtensaState *env, |
616 | unsigned n) |
617 | { |
618 | assert(n < 2); |
619 | env->static_vectors = n; |
620 | } |
621 | void xtensa_runstall(CPUXtensaState *env, bool runstall); |
622 | |
623 | #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) |
624 | #define XTENSA_OPTION_ALL (~(uint64_t)0) |
625 | |
626 | static inline bool xtensa_option_bits_enabled(const XtensaConfig *config, |
627 | uint64_t opt) |
628 | { |
629 | return (config->options & opt) != 0; |
630 | } |
631 | |
632 | static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt) |
633 | { |
634 | return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt)); |
635 | } |
636 | |
637 | static inline int xtensa_get_cintlevel(const CPUXtensaState *env) |
638 | { |
639 | int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; |
640 | if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) { |
641 | level = env->config->excm_level; |
642 | } |
643 | return level; |
644 | } |
645 | |
646 | static inline int xtensa_get_ring(const CPUXtensaState *env) |
647 | { |
648 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { |
649 | return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; |
650 | } else { |
651 | return 0; |
652 | } |
653 | } |
654 | |
655 | static inline int xtensa_get_cring(const CPUXtensaState *env) |
656 | { |
657 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) && |
658 | (env->sregs[PS] & PS_EXCM) == 0) { |
659 | return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; |
660 | } else { |
661 | return 0; |
662 | } |
663 | } |
664 | |
665 | #ifndef CONFIG_USER_ONLY |
666 | int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, |
667 | uint32_t vaddr, int is_write, int mmu_idx, |
668 | uint32_t *paddr, uint32_t *page_size, unsigned *access); |
669 | void reset_mmu(CPUXtensaState *env); |
670 | void dump_mmu(CPUXtensaState *env); |
671 | |
672 | static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env) |
673 | { |
674 | return env->system_er; |
675 | } |
676 | #endif |
677 | |
678 | static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) |
679 | { |
680 | return env->sregs[WINDOW_START] | |
681 | (env->sregs[WINDOW_START] << env->config->nareg / 4); |
682 | } |
683 | |
684 | /* MMU modes definitions */ |
685 | #define MMU_MODE0_SUFFIX _ring0 |
686 | #define MMU_MODE1_SUFFIX _ring1 |
687 | #define MMU_MODE2_SUFFIX _ring2 |
688 | #define MMU_MODE3_SUFFIX _ring3 |
689 | #define MMU_USER_IDX 3 |
690 | |
691 | static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch) |
692 | { |
693 | return xtensa_get_cring(env); |
694 | } |
695 | |
696 | #define XTENSA_TBFLAG_RING_MASK 0x3 |
697 | #define XTENSA_TBFLAG_EXCM 0x4 |
698 | #define XTENSA_TBFLAG_LITBASE 0x8 |
699 | #define XTENSA_TBFLAG_DEBUG 0x10 |
700 | #define XTENSA_TBFLAG_ICOUNT 0x20 |
701 | #define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0 |
702 | #define XTENSA_TBFLAG_CPENABLE_SHIFT 6 |
703 | #define XTENSA_TBFLAG_EXCEPTION 0x4000 |
704 | #define XTENSA_TBFLAG_WINDOW_MASK 0x18000 |
705 | #define XTENSA_TBFLAG_WINDOW_SHIFT 15 |
706 | #define XTENSA_TBFLAG_YIELD 0x20000 |
707 | #define XTENSA_TBFLAG_CWOE 0x40000 |
708 | #define XTENSA_TBFLAG_CALLINC_MASK 0x180000 |
709 | #define XTENSA_TBFLAG_CALLINC_SHIFT 19 |
710 | |
711 | #define XTENSA_CSBASE_LEND_MASK 0x0000ffff |
712 | #define XTENSA_CSBASE_LEND_SHIFT 0 |
713 | #define XTENSA_CSBASE_LBEG_OFF_MASK 0x00ff0000 |
714 | #define XTENSA_CSBASE_LBEG_OFF_SHIFT 16 |
715 | |
716 | typedef CPUXtensaState CPUArchState; |
717 | typedef XtensaCPU ArchCPU; |
718 | |
719 | #include "exec/cpu-all.h" |
720 | |
721 | static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, |
722 | target_ulong *cs_base, uint32_t *flags) |
723 | { |
724 | CPUState *cs = env_cpu(env); |
725 | |
726 | *pc = env->pc; |
727 | *cs_base = 0; |
728 | *flags = 0; |
729 | *flags |= xtensa_get_ring(env); |
730 | if (env->sregs[PS] & PS_EXCM) { |
731 | *flags |= XTENSA_TBFLAG_EXCM; |
732 | } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) { |
733 | target_ulong lend_dist = |
734 | env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS)); |
735 | |
736 | /* |
737 | * 0 in the csbase_lend field means that there may not be a loopback |
738 | * for any instruction that starts inside this page. Any other value |
739 | * means that an instruction that ends at this offset from the page |
740 | * start may loop back and will need loopback code to be generated. |
741 | * |
742 | * lend_dist is 0 when LEND points to the start of the page, but |
743 | * no instruction that starts inside this page may end at offset 0, |
744 | * so it's still correct. |
745 | * |
746 | * When an instruction ends at a page boundary it may only start in |
747 | * the previous page. lend_dist will be encoded as TARGET_PAGE_SIZE |
748 | * for the TB that contains this instruction. |
749 | */ |
750 | if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) { |
751 | target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG]; |
752 | |
753 | *cs_base = lend_dist; |
754 | if (lbeg_off < 256) { |
755 | *cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT; |
756 | } |
757 | } |
758 | } |
759 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && |
760 | (env->sregs[LITBASE] & 1)) { |
761 | *flags |= XTENSA_TBFLAG_LITBASE; |
762 | } |
763 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) { |
764 | if (xtensa_get_cintlevel(env) < env->config->debug_level) { |
765 | *flags |= XTENSA_TBFLAG_DEBUG; |
766 | } |
767 | if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { |
768 | *flags |= XTENSA_TBFLAG_ICOUNT; |
769 | } |
770 | } |
771 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { |
772 | *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; |
773 | } |
774 | if (cs->singlestep_enabled && env->exception_taken) { |
775 | *flags |= XTENSA_TBFLAG_EXCEPTION; |
776 | } |
777 | if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) && |
778 | (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) { |
779 | uint32_t windowstart = xtensa_replicate_windowstart(env) >> |
780 | (env->sregs[WINDOW_BASE] + 1); |
781 | uint32_t w = ctz32(windowstart | 0x8); |
782 | |
783 | *flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE; |
784 | *flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT, |
785 | PS_CALLINC_LEN) << XTENSA_TBFLAG_CALLINC_SHIFT; |
786 | } else { |
787 | *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; |
788 | } |
789 | if (env->yield_needed) { |
790 | *flags |= XTENSA_TBFLAG_YIELD; |
791 | } |
792 | } |
793 | |
794 | #endif |
795 | |