summaryrefslogtreecommitdiffstats
path: root/target/avr/helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/avr/helper.c')
-rw-r--r--target/avr/helper.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/target/avr/helper.c b/target/avr/helper.c
index db76452f9a..156dde4e92 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -28,36 +28,41 @@
bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
- bool ret = false;
- CPUClass *cc = CPU_GET_CLASS(cs);
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
+ /*
+ * We cannot separate a skip from the next instruction,
+ * as the skip would not be preserved across the interrupt.
+ * Separating the two insn normally only happens at page boundaries.
+ */
+ if (env->skip) {
+ return false;
+ }
+
if (interrupt_request & CPU_INTERRUPT_RESET) {
if (cpu_interrupts_enabled(env)) {
cs->exception_index = EXCP_RESET;
- cc->tcg_ops->do_interrupt(cs);
+ avr_cpu_do_interrupt(cs);
cs->interrupt_request &= ~CPU_INTERRUPT_RESET;
-
- ret = true;
+ return true;
}
}
if (interrupt_request & CPU_INTERRUPT_HARD) {
if (cpu_interrupts_enabled(env) && env->intsrc != 0) {
int index = ctz32(env->intsrc);
cs->exception_index = EXCP_INT(index);
- cc->tcg_ops->do_interrupt(cs);
+ avr_cpu_do_interrupt(cs);
env->intsrc &= env->intsrc - 1; /* clear the interrupt */
if (!env->intsrc) {
cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
-
- ret = true;
+ return true;
}
}
- return ret;
+ return false;
}
void avr_cpu_do_interrupt(CPUState *cs)
@@ -102,38 +107,50 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
- int prot = 0;
- MemTxAttrs attrs = {};
+ int prot, page_size = TARGET_PAGE_SIZE;
uint32_t paddr;
address &= TARGET_PAGE_MASK;
if (mmu_idx == MMU_CODE_IDX) {
- /* access to code in flash */
+ /* Access to code in flash. */
paddr = OFFSET_CODE + address;
prot = PAGE_READ | PAGE_EXEC;
- if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) {
+ if (paddr >= OFFSET_DATA) {
+ /*
+ * This should not be possible via any architectural operations.
+ * There is certainly not an exception that we can deliver.
+ * Accept probing that might come from generic code.
+ */
+ if (probe) {
+ return false;
+ }
error_report("execution left flash memory");
abort();
}
- } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
- /*
- * access to CPU registers, exit and rebuilt this TB to use full access
- * incase it touches specially handled registers like SREG or SP
- */
- AVRCPU *cpu = AVR_CPU(cs);
- CPUAVRState *env = &cpu->env;
- env->fullacc = 1;
- cpu_loop_exit_restore(cs, retaddr);
} else {
- /* access to memory. nothing special */
+ /* Access to memory. */
paddr = OFFSET_DATA + address;
prot = PAGE_READ | PAGE_WRITE;
+ if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
+ /*
+ * Access to CPU registers, exit and rebuilt this TB to use
+ * full access in case it touches specially handled registers
+ * like SREG or SP. For probing, set page_size = 1, in order
+ * to force tlb_fill to be called for the next access.
+ */
+ if (probe) {
+ page_size = 1;
+ } else {
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+ env->fullacc = 1;
+ cpu_loop_exit_restore(cs, retaddr);
+ }
+ }
}
- tlb_set_page_with_attrs(cs, address, paddr, attrs, prot,
- mmu_idx, TARGET_PAGE_SIZE);
-
+ tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size);
return true;
}