aboutsummaryrefslogtreecommitdiff
path: root/target-cris/helper.c
diff options
context:
space:
mode:
authoredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-03-14 01:04:24 +0000
committeredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-03-14 01:04:24 +0000
commite62b5b133b97e07711741e2a4e2bf3e4dbc254f8 (patch)
treeb8ce3c5c96656259bf42a99be2f71b2ba5e461b7 /target-cris/helper.c
parent1ec6d2ea991a1605b9e0898aa9b6e0a2f56c6881 (diff)
* Add a model of the ETRAX interrupt controller.
* Clean up the interrupt handling a bit. * Connect some NOR flash to the test board. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4055 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/helper.c')
-rw-r--r--target-cris/helper.c107
1 files changed, 51 insertions, 56 deletions
diff --git a/target-cris/helper.c b/target-cris/helper.c
index 7482e0893f..8872138ca4 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -28,6 +28,8 @@
#include "exec-all.h"
#include "host-utils.h"
+#define D(x)
+
#if defined(CONFIG_USER_ONLY)
void do_interrupt (CPUState *env)
@@ -53,71 +55,68 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
#else /* !CONFIG_USER_ONLY */
+
+static void cris_shift_ccs(CPUState *env)
+{
+ uint32_t ccs;
+ /* Apply the ccs shift. */
+ ccs = env->pregs[PR_CCS];
+ ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2);
+ env->pregs[PR_CCS] = ccs;
+}
+
int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
struct cris_mmu_result_t res;
int prot, miss;
+ int r = -1;
target_ulong phy;
+ D(printf ("%s addr=%x pc=%x\n", __func__, address, env->pc));
address &= TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
miss = cris_mmu_translate(&res, env, address, rw, mmu_idx);
if (miss)
{
- /* handle the miss. */
- phy = 0;
- env->exception_index = EXCP_MMU_MISS;
+ env->exception_index = EXCP_MMU_FAULT;
+ env->fault_vector = res.bf_vec;
+ r = 1;
}
else
{
phy = res.phy;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu);
}
- return tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu);
-}
-
-
-static void cris_shift_ccs(CPUState *env)
-{
- uint32_t ccs;
- /* Apply the ccs shift. */
- ccs = env->pregs[PR_CCS];
- ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2);
- env->pregs[PR_CCS] = ccs;
+ D(printf("%s returns %d irqreq=%x addr=%x ismmu=%d\n",
+ __func__, r, env->interrupt_request,
+ address, is_softmmu));
+ return r;
}
void do_interrupt(CPUState *env)
{
- uint32_t ebp, isr;
- int irqnum;
-
- fflush(NULL);
+ int ex_vec = -1;
-#if 0
- printf ("exception index=%d interrupt_req=%d\n",
- env->exception_index,
- env->interrupt_request);
-#endif
+ D(fprintf (stderr, "exception index=%d interrupt_req=%d\n",
+ env->exception_index,
+ env->interrupt_request));
switch (env->exception_index)
{
case EXCP_BREAK:
- irqnum = env->trapnr;
- ebp = env->pregs[PR_EBP];
- isr = ldl_code(ebp + irqnum * 4);
+ /* These exceptions are genereated by the core itself.
+ ERP should point to the insn following the brk. */
+ ex_vec = env->trap_vector;
env->pregs[PR_ERP] = env->pc + 2;
- env->pc = isr;
-
- cris_shift_ccs(env);
-
break;
- case EXCP_MMU_MISS:
- irqnum = 4;
- ebp = env->pregs[PR_EBP];
- isr = ldl_code(ebp + irqnum * 4);
- env->pregs[PR_ERP] = env->pc;
- env->pc = isr;
- cris_shift_ccs(env);
+
+ case EXCP_MMU_FAULT:
+ /* ERP is already setup by translate-all.c through
+ re-translation of the aborted TB combined with
+ pc searching. */
+ ex_vec = env->fault_vector;
break;
default:
@@ -125,34 +124,29 @@ void do_interrupt(CPUState *env)
/* Maybe the irq was acked by sw before we got a
change to take it. */
if (env->interrupt_request & CPU_INTERRUPT_HARD) {
- if (!env->pending_interrupts)
+ /* Vectors below 0x30 are internal
+ exceptions, i.e not interrupt requests
+ from the interrupt controller. */
+ if (env->interrupt_vector < 0x30)
return;
+ /* Is the core accepting interrupts? */
if (!(env->pregs[PR_CCS] & I_FLAG)) {
return;
}
-
- irqnum = 31 - clz32(env->pending_interrupts);
- irqnum += 0x30;
- ebp = env->pregs[PR_EBP];
- isr = ldl_code(ebp + irqnum * 4);
+ /* The interrupt controller gives us the
+ vector. */
+ ex_vec = env->interrupt_vector;
+ /* Normal interrupts are taken between
+ TB's. env->pc is valid here. */
env->pregs[PR_ERP] = env->pc;
- env->pc = isr;
-
- cris_shift_ccs(env);
-#if 0
- printf ("%s ebp=%x %x isr=%x %d"
- " ir=%x pending=%x\n",
- __func__,
- ebp, ebp + irqnum * 4,
- isr, env->exception_index,
- env->interrupt_request,
- env->pending_interrupts);
-#endif
}
-
}
break;
}
+ env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
+ /* Apply the CRIS CCS shift. */
+ cris_shift_ccs(env);
+ D(printf ("%s ebp=%x isr=%x vec=%x\n", __func__, ebp, isr, ex_vec));
}
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
@@ -163,6 +157,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
miss = cris_mmu_translate(&res, env, addr, 0, 0);
if (!miss)
phy = res.phy;
+ D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
return phy;
}
#endif