2 * Altera Nios II helper routines.
4 * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
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.1 of the License, or (at your option) any later version.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
21 #include "qemu/osdep.h"
24 #include "qemu/host-utils.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
28 #include "exec/helper-proto.h"
29 #include "semihosting/semihost.h"
32 static void do_exception(Nios2CPU
*cpu
, uint32_t exception_addr
,
33 uint32_t tlbmisc_set
, bool is_break
)
35 CPUNios2State
*env
= &cpu
->env
;
36 CPUState
*cs
= CPU(cpu
);
37 uint32_t old_status
= env
->ctrl
[CR_STATUS
];
38 uint32_t new_status
= old_status
;
40 /* With shadow regs, exceptions are always taken into CRS 0. */
41 new_status
&= ~R_CR_STATUS_CRS_MASK
;
42 env
->regs
= env
->shadow_regs
[0];
44 if ((old_status
& CR_STATUS_EH
) == 0) {
45 int r_ea
= R_EA
, cr_es
= CR_ESTATUS
;
51 env
->ctrl
[cr_es
] = old_status
;
52 env
->regs
[r_ea
] = env
->pc
;
54 if (cpu
->mmu_present
) {
55 new_status
|= CR_STATUS_EH
;
58 * There are 4 bits that are always written.
59 * Explicitly clear them, to be set via the argument.
61 env
->ctrl
[CR_TLBMISC
] &= ~(CR_TLBMISC_D
|
65 env
->ctrl
[CR_TLBMISC
] |= tlbmisc_set
;
69 * With shadow regs, and EH == 0, PRS is set from CRS.
70 * At least, so says Table 3-9, and some other text,
71 * though Table 3-38 says otherwise.
73 new_status
= FIELD_DP32(new_status
, CR_STATUS
, PRS
,
74 FIELD_EX32(old_status
, CR_STATUS
, CRS
));
77 new_status
&= ~(CR_STATUS_PIE
| CR_STATUS_U
);
79 env
->ctrl
[CR_STATUS
] = new_status
;
81 env
->ctrl
[CR_EXCEPTION
] = FIELD_DP32(0, CR_EXCEPTION
, CAUSE
,
84 env
->pc
= exception_addr
;
87 static void do_iic_irq(Nios2CPU
*cpu
)
89 do_exception(cpu
, cpu
->exception_addr
, 0, false);
92 static void do_eic_irq(Nios2CPU
*cpu
)
94 CPUNios2State
*env
= &cpu
->env
;
95 uint32_t old_status
= env
->ctrl
[CR_STATUS
];
96 uint32_t new_status
= old_status
;
97 uint32_t old_rs
= FIELD_EX32(old_status
, CR_STATUS
, CRS
);
98 uint32_t new_rs
= cpu
->rrs
;
100 new_status
= FIELD_DP32(new_status
, CR_STATUS
, CRS
, new_rs
);
101 new_status
= FIELD_DP32(new_status
, CR_STATUS
, IL
, cpu
->ril
);
102 new_status
= FIELD_DP32(new_status
, CR_STATUS
, NMI
, cpu
->rnmi
);
103 new_status
&= ~(CR_STATUS_RSIE
| CR_STATUS_U
);
104 new_status
|= CR_STATUS_IH
;
106 if (!(new_status
& CR_STATUS_EH
)) {
107 new_status
= FIELD_DP32(new_status
, CR_STATUS
, PRS
, old_rs
);
109 env
->ctrl
[CR_ESTATUS
] = old_status
;
111 if (new_rs
!= old_rs
) {
112 old_status
|= CR_STATUS_SRS
;
114 env
->shadow_regs
[new_rs
][R_SSTATUS
] = old_status
;
116 env
->shadow_regs
[new_rs
][R_EA
] = env
->pc
;
119 env
->ctrl
[CR_STATUS
] = new_status
;
120 nios2_update_crs(env
);
125 void nios2_cpu_do_interrupt(CPUState
*cs
)
127 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
128 CPUNios2State
*env
= &cpu
->env
;
129 uint32_t tlbmisc_set
= 0;
131 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
132 const char *name
= NULL
;
134 switch (cs
->exception_index
) {
140 if (env
->ctrl
[CR_STATUS
] & CR_STATUS_EH
) {
141 name
= "TLB MISS (double)";
143 name
= "TLB MISS (fast)";
153 name
= "SUPERVISOR (address)";
156 name
= "SUPERVISOR (insn)";
159 name
= "ILLEGAL insn";
162 name
= "Misaligned (data)";
165 name
= "Misaligned (destination)";
177 name
= "SEMIHOST insn";
181 qemu_log("%s at pc=0x%08x\n", name
, env
->pc
);
183 qemu_log("Unknown exception %d at pc=0x%08x\n",
184 cs
->exception_index
, env
->pc
);
188 switch (cs
->exception_index
) {
190 /* Note that PC is advanced for interrupts as well. */
192 if (cpu
->eic_present
) {
200 tlbmisc_set
= CR_TLBMISC_D
;
203 if (env
->ctrl
[CR_STATUS
] & CR_STATUS_EH
) {
204 tlbmisc_set
|= CR_TLBMISC_DBL
;
206 * Normally, we don't write to tlbmisc unless !EH,
207 * so do it manually for the double-tlb miss exception.
209 env
->ctrl
[CR_TLBMISC
] &= ~(CR_TLBMISC_D
|
212 env
->ctrl
[CR_TLBMISC
] |= tlbmisc_set
;
213 do_exception(cpu
, cpu
->exception_addr
, 0, false);
215 tlbmisc_set
|= CR_TLBMISC_WE
;
216 do_exception(cpu
, cpu
->fast_tlb_miss_addr
, tlbmisc_set
, false);
222 tlbmisc_set
= CR_TLBMISC_D
;
225 tlbmisc_set
|= CR_TLBMISC_PERM
;
226 if (!(env
->ctrl
[CR_STATUS
] & CR_STATUS_EH
)) {
227 tlbmisc_set
|= CR_TLBMISC_WE
;
229 do_exception(cpu
, cpu
->exception_addr
, tlbmisc_set
, false);
234 tlbmisc_set
= CR_TLBMISC_D
;
238 tlbmisc_set
|= CR_TLBMISC_BAD
;
239 do_exception(cpu
, cpu
->exception_addr
, tlbmisc_set
, false);
246 do_exception(cpu
, cpu
->exception_addr
, 0, false);
250 do_exception(cpu
, cpu
->exception_addr
, 0, true);
254 do_nios2_semihosting(env
);
258 cpu_abort(cs
, "unhandled exception type=%d\n", cs
->exception_index
);
262 hwaddr
nios2_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
264 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
265 CPUNios2State
*env
= &cpu
->env
;
266 target_ulong vaddr
, paddr
= 0;
270 if (cpu
->mmu_present
&& (addr
< 0xC0000000)) {
271 hit
= mmu_translate(env
, &lu
, addr
, 0, 0);
273 vaddr
= addr
& TARGET_PAGE_MASK
;
274 paddr
= lu
.paddr
+ vaddr
- lu
.vaddr
;
277 qemu_log("cpu_get_phys_page debug MISS: %#" PRIx64
"\n", addr
);
280 paddr
= addr
& TARGET_PAGE_MASK
;
286 void nios2_cpu_do_unaligned_access(CPUState
*cs
, vaddr addr
,
287 MMUAccessType access_type
,
288 int mmu_idx
, uintptr_t retaddr
)
290 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
291 CPUNios2State
*env
= &cpu
->env
;
293 env
->ctrl
[CR_BADADDR
] = addr
;
294 cs
->exception_index
= EXCP_UNALIGN
;
295 nios2_cpu_loop_exit_advance(env
, retaddr
);
298 bool nios2_cpu_tlb_fill(CPUState
*cs
, vaddr address
, int size
,
299 MMUAccessType access_type
, int mmu_idx
,
300 bool probe
, uintptr_t retaddr
)
302 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
303 CPUNios2State
*env
= &cpu
->env
;
305 target_ulong vaddr
, paddr
;
309 if (!cpu
->mmu_present
) {
311 address
&= TARGET_PAGE_MASK
;
312 tlb_set_page(cs
, address
, address
, PAGE_BITS
,
313 mmu_idx
, TARGET_PAGE_SIZE
);
317 if (MMU_SUPERVISOR_IDX
== mmu_idx
) {
318 if (address
>= 0xC0000000) {
319 /* Kernel physical page - TLB bypassed */
320 address
&= TARGET_PAGE_MASK
;
321 tlb_set_page(cs
, address
, address
, PAGE_BITS
,
322 mmu_idx
, TARGET_PAGE_SIZE
);
326 if (address
>= 0x80000000) {
327 /* Illegal access from user mode */
331 cs
->exception_index
= (access_type
== MMU_INST_FETCH
332 ? EXCP_SUPERA_X
: EXCP_SUPERA_D
);
333 env
->ctrl
[CR_BADADDR
] = address
;
334 nios2_cpu_loop_exit_advance(env
, retaddr
);
339 hit
= mmu_translate(env
, &lu
, address
, access_type
, mmu_idx
);
341 vaddr
= address
& TARGET_PAGE_MASK
;
342 paddr
= lu
.paddr
+ vaddr
- lu
.vaddr
;
344 if (((access_type
== MMU_DATA_LOAD
) && (lu
.prot
& PAGE_READ
)) ||
345 ((access_type
== MMU_DATA_STORE
) && (lu
.prot
& PAGE_WRITE
)) ||
346 ((access_type
== MMU_INST_FETCH
) && (lu
.prot
& PAGE_EXEC
))) {
347 tlb_set_page(cs
, vaddr
, paddr
, lu
.prot
,
348 mmu_idx
, TARGET_PAGE_SIZE
);
352 /* Permission violation */
353 excp
= (access_type
== MMU_DATA_LOAD
? EXCP_PERM_R
:
354 access_type
== MMU_DATA_STORE
? EXCP_PERM_W
: EXCP_PERM_X
);
356 excp
= (access_type
== MMU_INST_FETCH
? EXCP_TLB_X
: EXCP_TLB_D
);
363 env
->ctrl
[CR_TLBMISC
] = FIELD_DP32(env
->ctrl
[CR_TLBMISC
], CR_TLBMISC
, D
,
364 access_type
!= MMU_INST_FETCH
);
365 env
->ctrl
[CR_PTEADDR
] = FIELD_DP32(env
->ctrl
[CR_PTEADDR
], CR_PTEADDR
, VPN
,
366 address
>> TARGET_PAGE_BITS
);
367 env
->mmu
.pteaddr_wr
= env
->ctrl
[CR_PTEADDR
];
369 cs
->exception_index
= excp
;
370 env
->ctrl
[CR_BADADDR
] = address
;
371 nios2_cpu_loop_exit_advance(env
, retaddr
);