blob: 1bdb7e26b7969a88aca7be9a6af7291b60d8b450 [file] [log] [blame]
ths81fdc5f2007-10-08 13:04:02 +00001/*
2 * CRIS helper routines.
3 *
4 * Copyright (c) 2007 AXIS Communications AB
5 * Written by Edgar E. Iglesias.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
ths81fdc5f2007-10-08 13:04:02 +000019 */
20
ths81fdc5f2007-10-08 13:04:02 +000021#include "cpu.h"
22#include "mmu.h"
ths941db522007-10-28 01:44:40 +000023#include "host-utils.h"
ths81fdc5f2007-10-08 13:04:02 +000024
aliguorid12d51d2009-01-15 21:48:06 +000025
26//#define CRIS_HELPER_DEBUG
27
28
29#ifdef CRIS_HELPER_DEBUG
30#define D(x) x
aliguori93fcfe32009-01-15 22:34:14 +000031#define D_LOG(...) qemu_log(__VA__ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000032#else
edgar_igle62b5b12008-03-14 01:04:24 +000033#define D(x)
aliguorid12d51d2009-01-15 21:48:06 +000034#define D_LOG(...) do { } while (0)
35#endif
edgar_igle62b5b12008-03-14 01:04:24 +000036
ths81fdc5f2007-10-08 13:04:02 +000037#if defined(CONFIG_USER_ONLY)
38
Andreas Färbera1170bf2012-03-14 01:38:21 +010039void do_interrupt (CPUCRISState *env)
ths81fdc5f2007-10-08 13:04:02 +000040{
edgar_iglbbaf29c2008-03-01 17:25:33 +000041 env->exception_index = -1;
42 env->pregs[PR_ERP] = env->pc;
ths81fdc5f2007-10-08 13:04:02 +000043}
44
Andreas Färbera1170bf2012-03-14 01:38:21 +010045int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
Blue Swirl97b348e2011-08-01 16:12:17 +000046 int mmu_idx)
ths81fdc5f2007-10-08 13:04:02 +000047{
edgar_iglbbaf29c2008-03-01 17:25:33 +000048 env->exception_index = 0xaa;
edgar_igl30abcfc2008-05-27 21:10:56 +000049 env->pregs[PR_EDA] = address;
edgar_iglbbaf29c2008-03-01 17:25:33 +000050 cpu_dump_state(env, stderr, fprintf, 0);
edgar_iglbbaf29c2008-03-01 17:25:33 +000051 return 1;
ths81fdc5f2007-10-08 13:04:02 +000052}
53
ths81fdc5f2007-10-08 13:04:02 +000054#else /* !CONFIG_USER_ONLY */
55
ths81fdc5f2007-10-08 13:04:02 +000056
Andreas Färbera1170bf2012-03-14 01:38:21 +010057static void cris_shift_ccs(CPUCRISState *env)
ths81fdc5f2007-10-08 13:04:02 +000058{
59 uint32_t ccs;
60 /* Apply the ccs shift. */
edgar_igl90046272008-02-28 08:28:32 +000061 ccs = env->pregs[PR_CCS];
edgar_iglb41f7df2008-05-02 22:16:17 +000062 ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
edgar_igl90046272008-02-28 08:28:32 +000063 env->pregs[PR_CCS] = ccs;
ths81fdc5f2007-10-08 13:04:02 +000064}
65
Andreas Färbera1170bf2012-03-14 01:38:21 +010066int cpu_cris_handle_mmu_fault (CPUCRISState *env, target_ulong address, int rw,
Blue Swirl97b348e2011-08-01 16:12:17 +000067 int mmu_idx)
edgar_igle62b5b12008-03-14 01:04:24 +000068{
Edgar E. Iglesias2fa73ec2009-04-25 15:51:53 +020069 struct cris_mmu_result res;
edgar_igle62b5b12008-03-14 01:04:24 +000070 int prot, miss;
71 int r = -1;
72 target_ulong phy;
73
edgar_iglb41f7df2008-05-02 22:16:17 +000074 D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
Edgar E. Iglesiasbe9f2de2009-10-08 12:07:11 +020075 miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
Edgar E. Iglesias9f5a1fa2010-07-05 11:39:04 +020076 rw, mmu_idx, 0);
edgar_igle62b5b12008-03-14 01:04:24 +000077 if (miss)
78 {
edgar_igl1b1a38b2008-06-09 23:18:06 +000079 if (env->exception_index == EXCP_BUSFAULT)
Edgar E. Iglesias7a977352010-02-15 11:47:34 +010080 cpu_abort(env,
edgar_iglef29a702008-05-06 08:04:40 +000081 "CRIS: Illegal recursive bus fault."
Edgar E. Iglesias7a977352010-02-15 11:47:34 +010082 "addr=%x rw=%d\n",
83 address, rw);
edgar_iglef29a702008-05-06 08:04:40 +000084
Edgar E. Iglesiasbe9f2de2009-10-08 12:07:11 +020085 env->pregs[PR_EDA] = address;
edgar_igl1b1a38b2008-06-09 23:18:06 +000086 env->exception_index = EXCP_BUSFAULT;
edgar_igle62b5b12008-03-14 01:04:24 +000087 env->fault_vector = res.bf_vec;
88 r = 1;
89 }
90 else
91 {
edgar_igl980f8a02008-09-05 17:17:55 +000092 /*
93 * Mask off the cache selection bit. The ETRAX busses do not
94 * see the top bit.
95 */
96 phy = res.phy & ~0x80000000;
edgar_iglb41f7df2008-05-02 22:16:17 +000097 prot = res.prot;
Paul Brookd4c430a2010-03-17 02:14:28 +000098 tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
Edgar E. Iglesias58aebb92010-09-18 12:34:59 +020099 prot, mmu_idx, TARGET_PAGE_SIZE);
Paul Brookd4c430a2010-03-17 02:14:28 +0000100 r = 0;
edgar_igle62b5b12008-03-14 01:04:24 +0000101 }
edgar_iglb41f7df2008-05-02 22:16:17 +0000102 if (r > 0)
Blue Swirl97b348e2011-08-01 16:12:17 +0000103 D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
104 __func__, r, env->interrupt_request, address, res.phy,
105 res.bf_vec, env->pc);
edgar_igle62b5b12008-03-14 01:04:24 +0000106 return r;
107}
108
Andreas Färbera1170bf2012-03-14 01:38:21 +0100109static void do_interruptv10(CPUCRISState *env)
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100110{
111 int ex_vec = -1;
112
113 D_LOG( "exception index=%d interrupt_req=%d\n",
114 env->exception_index,
115 env->interrupt_request);
116
117 assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
118 switch (env->exception_index)
119 {
120 case EXCP_BREAK:
121 /* These exceptions are genereated by the core itself.
122 ERP should point to the insn following the brk. */
123 ex_vec = env->trap_vector;
Edgar E. Iglesiasf756c7a2011-07-05 12:56:41 +0200124 env->pregs[PRV10_BRP] = env->pc;
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100125 break;
126
127 case EXCP_NMI:
128 /* NMI is hardwired to vector zero. */
129 ex_vec = 0;
Lars Persson82193142012-06-14 16:23:55 +0200130 env->pregs[PR_CCS] &= ~M_FLAG_V10;
Edgar E. Iglesiasf756c7a2011-07-05 12:56:41 +0200131 env->pregs[PRV10_BRP] = env->pc;
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100132 break;
133
134 case EXCP_BUSFAULT:
Blue Swirl43dc2a62010-03-18 18:41:57 +0000135 cpu_abort(env, "Unhandled busfault");
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100136 break;
137
138 default:
139 /* The interrupt controller gives us the vector. */
140 ex_vec = env->interrupt_vector;
141 /* Normal interrupts are taken between
142 TB's. env->pc is valid here. */
143 env->pregs[PR_ERP] = env->pc;
144 break;
145 }
146
147 if (env->pregs[PR_CCS] & U_FLAG) {
148 /* Swap stack pointers. */
149 env->pregs[PR_USP] = env->regs[R_SP];
150 env->regs[R_SP] = env->ksp;
151 }
152
153 /* Now that we are in kernel mode, load the handlers address. */
Aurelien Jarnocf7e0c82012-09-07 16:13:27 +0200154 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100155 env->locked_irq = 1;
Stefan Sandstrom774d5c52011-12-12 11:38:31 +0100156 env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100157
158 qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
159 __func__, env->pc, ex_vec,
160 env->pregs[PR_CCS],
161 env->pregs[PR_PID],
162 env->pregs[PR_ERP]);
163}
164
Andreas Färbera1170bf2012-03-14 01:38:21 +0100165void do_interrupt(CPUCRISState *env)
ths81fdc5f2007-10-08 13:04:02 +0000166{
edgar_igle62b5b12008-03-14 01:04:24 +0000167 int ex_vec = -1;
ths81fdc5f2007-10-08 13:04:02 +0000168
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100169 if (env->pregs[PR_VR] < 32)
170 return do_interruptv10(env);
171
aliguorid12d51d2009-01-15 21:48:06 +0000172 D_LOG( "exception index=%d interrupt_req=%d\n",
edgar_iglb41f7df2008-05-02 22:16:17 +0000173 env->exception_index,
aliguorid12d51d2009-01-15 21:48:06 +0000174 env->interrupt_request);
ths81fdc5f2007-10-08 13:04:02 +0000175
176 switch (env->exception_index)
177 {
178 case EXCP_BREAK:
edgar_igle62b5b12008-03-14 01:04:24 +0000179 /* These exceptions are genereated by the core itself.
180 ERP should point to the insn following the brk. */
181 ex_vec = env->trap_vector;
edgar_igla1aebcb2008-10-07 22:48:41 +0000182 env->pregs[PR_ERP] = env->pc;
ths81fdc5f2007-10-08 13:04:02 +0000183 break;
edgar_igle62b5b12008-03-14 01:04:24 +0000184
edgar_igl1b1a38b2008-06-09 23:18:06 +0000185 case EXCP_NMI:
186 /* NMI is hardwired to vector zero. */
187 ex_vec = 0;
Lars Persson82193142012-06-14 16:23:55 +0200188 env->pregs[PR_CCS] &= ~M_FLAG_V32;
edgar_igl1b1a38b2008-06-09 23:18:06 +0000189 env->pregs[PR_NRP] = env->pc;
190 break;
191
192 case EXCP_BUSFAULT:
edgar_igle62b5b12008-03-14 01:04:24 +0000193 ex_vec = env->fault_vector;
edgar_iglb41f7df2008-05-02 22:16:17 +0000194 env->pregs[PR_ERP] = env->pc;
ths81fdc5f2007-10-08 13:04:02 +0000195 break;
196
197 default:
edgar_igl1b1a38b2008-06-09 23:18:06 +0000198 /* The interrupt controller gives us the vector. */
edgar_iglb41f7df2008-05-02 22:16:17 +0000199 ex_vec = env->interrupt_vector;
200 /* Normal interrupts are taken between
201 TB's. env->pc is valid here. */
202 env->pregs[PR_ERP] = env->pc;
203 break;
ths81fdc5f2007-10-08 13:04:02 +0000204 }
edgar_iglb41f7df2008-05-02 22:16:17 +0000205
edgar_iglcddffe32008-10-08 14:22:17 +0000206 /* Fill in the IDX field. */
207 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
208
edgar_iglcf1d97f2008-05-13 10:59:14 +0000209 if (env->dslot) {
aliguorid12d51d2009-01-15 21:48:06 +0000210 D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
edgar_iglcf1d97f2008-05-13 10:59:14 +0000211 " ERP=%x pid=%x ccs=%x cc=%d %x\n",
212 ex_vec, env->pc, env->dslot,
edgar_iglef29a702008-05-06 08:04:40 +0000213 env->regs[R_SP],
edgar_iglb41f7df2008-05-02 22:16:17 +0000214 env->pregs[PR_ERP], env->pregs[PR_PID],
215 env->pregs[PR_CCS],
aliguorid12d51d2009-01-15 21:48:06 +0000216 env->cc_op, env->cc_mask);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000217 /* We loose the btarget, btaken state here so rexec the
218 branch. */
219 env->pregs[PR_ERP] -= env->dslot;
220 /* Exception starts with dslot cleared. */
221 env->dslot = 0;
edgar_iglb41f7df2008-05-02 22:16:17 +0000222 }
223
edgar_iglb41f7df2008-05-02 22:16:17 +0000224 if (env->pregs[PR_CCS] & U_FLAG) {
225 /* Swap stack pointers. */
226 env->pregs[PR_USP] = env->regs[R_SP];
227 env->regs[R_SP] = env->ksp;
228 }
229
230 /* Apply the CRIS CCS shift. Clears U if set. */
edgar_igle62b5b12008-03-14 01:04:24 +0000231 cris_shift_ccs(env);
Edgar E. Iglesias218951e2009-10-10 17:34:27 +0200232
Edgar E. Iglesiasabdfd952010-09-16 15:40:27 +0200233 /* Now that we are in kernel mode, load the handlers address.
234 This load may not fault, real hw leaves that behaviour as
235 undefined. */
Aurelien Jarnocf7e0c82012-09-07 16:13:27 +0200236 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
Edgar E. Iglesias218951e2009-10-10 17:34:27 +0200237
Edgar E. Iglesiasabdfd952010-09-16 15:40:27 +0200238 /* Clear the excption_index to avoid spurios hw_aborts for recursive
239 bus faults. */
240 env->exception_index = -1;
241
Edgar E. Iglesias7a977352010-02-15 11:47:34 +0100242 D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
243 __func__, env->pc, ex_vec,
edgar_iglb41f7df2008-05-02 22:16:17 +0000244 env->pregs[PR_CCS],
245 env->pregs[PR_PID],
aliguorid12d51d2009-01-15 21:48:06 +0000246 env->pregs[PR_ERP]);
ths81fdc5f2007-10-08 13:04:02 +0000247}
248
Andreas Färbera1170bf2012-03-14 01:38:21 +0100249target_phys_addr_t cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
ths81fdc5f2007-10-08 13:04:02 +0000250{
ths81fdc5f2007-10-08 13:04:02 +0000251 uint32_t phy = addr;
Edgar E. Iglesias2fa73ec2009-04-25 15:51:53 +0200252 struct cris_mmu_result res;
ths81fdc5f2007-10-08 13:04:02 +0000253 int miss;
Edgar E. Iglesias3c4fe422010-07-05 10:24:56 +0200254
Edgar E. Iglesias9f5a1fa2010-07-05 11:39:04 +0200255 miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
Edgar E. Iglesias3c4fe422010-07-05 10:24:56 +0200256 /* If D TLB misses, try I TLB. */
257 if (miss) {
Edgar E. Iglesias9f5a1fa2010-07-05 11:39:04 +0200258 miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
Edgar E. Iglesias3c4fe422010-07-05 10:24:56 +0200259 }
260
ths81fdc5f2007-10-08 13:04:02 +0000261 if (!miss)
262 phy = res.phy;
edgar_igle62b5b12008-03-14 01:04:24 +0000263 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
ths81fdc5f2007-10-08 13:04:02 +0000264 return phy;
265}
266#endif