static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset) { struct timer_state *s = (struct timer_state *)opaque; switch(offset) { case TIMER_TIME_LOW: s->now_ns = tks2ns(qemu_get_clock(vm_clock)); return s->now_ns; case TIMER_TIME_HIGH: return s->now_ns >> 32; default: cpu_abort (cpu_single_env, "goldfish_timer_read: Bad offset %x\n", offset); return 0; } }
static uint32_t goldfish_rtc_read(void *opaque, target_phys_addr_t offset) { struct rtc_state *s = (struct rtc_state *)opaque; switch(offset) { case 0x0: s->now = (int64_t)time(NULL) * 1000000000; return s->now; case 0x4: return s->now >> 32; default: cpu_abort (cpu_single_env, "goldfish_rtc_read: Bad offset %x\n", offset); return 0; } }
static uint32_t goldfish_tty_read(void *opaque, target_phys_addr_t offset) { struct tty_state *s = (struct tty_state *)opaque; //printf("goldfish_tty_read %x %x\n", offset, size); switch (offset) { case TTY_BYTES_READY: return s->data_count; default: cpu_abort (cpu_single_env, "goldfish_tty_read: Bad offset %x\n", offset); return 0; } }
/* I/O read */ static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset) { trace_dev_state *s = (trace_dev_state *)opaque; offset -= s->base; switch (offset >> 2) { case TRACE_DEV_REG_ENABLE: // tracing enable return tracing; default: cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); return 0; } return 0; }
LowCore *cpu_map_lowcore(CPUS390XState *env) { S390CPU *cpu = s390_env_get_cpu(env); LowCore *lowcore; hwaddr len = sizeof(LowCore); lowcore = cpu_physical_memory_map(env->psa, &len, 1); if (len < sizeof(LowCore)) { cpu_abort(CPU(cpu), "Could not map lowcore\n"); } return lowcore; }
static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val) { struct goldfish_battery_state *s = opaque; switch(offset) { case BATTERY_INT_ENABLE: s->int_enable = val; break; default: cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset); } }
void openrisc_cpu_do_interrupt(CPUState *cs) { OpenRISCCPU *cpu = OPENRISC_CPU(cs); CPUOpenRISCState *env = &cpu->env; #ifndef CONFIG_USER_ONLY if (env->flags & D_FLAG) { /* Delay Slot insn */ env->flags &= ~D_FLAG; env->sr |= SR_DSX; if (env->exception_index == EXCP_TICK || env->exception_index == EXCP_INT || env->exception_index == EXCP_SYSCALL || env->exception_index == EXCP_FPE) { env->epcr = env->jmp_pc; } else { env->epcr = env->pc - 4; } } else { if (env->exception_index == EXCP_TICK || env->exception_index == EXCP_INT || env->exception_index == EXCP_SYSCALL || env->exception_index == EXCP_FPE) { env->epcr = env->npc; } else { env->epcr = env->pc; } } /* For machine-state changed between user-mode and supervisor mode, we need flush TLB when we enter&exit EXCP. */ tlb_flush(env, 1); env->esr = env->sr; env->sr &= ~SR_DME; env->sr &= ~SR_IME; env->sr |= SR_SM; env->sr &= ~SR_IEE; env->sr &= ~SR_TEE; env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; if (env->exception_index > 0 && env->exception_index < EXCP_NR) { env->pc = (env->exception_index << 8); } else { cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); } #endif env->exception_index = -1; }
static void arm_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value) { arm_timer_state *s = (arm_timer_state *)opaque; int freq; switch (offset >> 2) { case 0: /* TimerLoad */ s->limit = value; arm_timer_recalibrate(s, 1); break; case 1: /* TimerValue */ /* ??? Linux seems to want to write to this readonly register. Ignore it. */ break; case 2: /* TimerControl */ if (s->control & TIMER_CTRL_ENABLE) { /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other messyness. */ ptimer_stop(s->timer); } s->control = value; freq = s->freq; /* ??? Need to recalculate expiry time after changing divisor. */ switch ((value >> 2) & 3) { case 1: freq >>= 4; break; case 2: freq >>= 8; break; } arm_timer_recalibrate(s, 0); ptimer_set_freq(s->timer, freq); if (s->control & TIMER_CTRL_ENABLE) { /* Restart the timer if still enabled. */ ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0); } break; case 3: /* TimerIntClr */ s->int_level = 0; break; case 6: /* TimerBGLoad */ s->limit = value; arm_timer_recalibrate(s, 0); break; default: cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", (int)offset); } arm_timer_update(s); }
static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) { switch (float_compare) { case float_relation_equal: return 0; case float_relation_less: return 1; case float_relation_greater: return 2; case float_relation_unordered: return 3; default: cpu_abort(env, "unknown return value for float compare\n"); } }
static void goldfish_sensor_write(void *opaque, target_phys_addr_t offset, uint32_t val) { struct goldfish_sensor_state *s = opaque; offset -= s->dev.base; switch(offset) { case INT_ENABLE: /* enable interrupts */ s->int_enable = val; break; default: cpu_abort (cpu_single_env, "goldfish_sensor_write: Bad offset %x\n", offset); } }
static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val) { GoldfishBatteryDevice *s = (GoldfishBatteryDevice *)opaque; switch(offset) { case BATTERY_INT_ENABLE: /* enable interrupts */ s->int_enable = val; // s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); // goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); break; default: cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset); } }
static void pl031_write(void * opaque, target_phys_addr_t offset, uint32_t value) { pl031_state *s = (pl031_state *)opaque; offset -= s->base; switch (offset) { case RTC_LR: s->tick_offset += value - pl031_get_count(s); pl031_set_alarm(s); break; case RTC_MR: s->mr = value; pl031_set_alarm(s); break; case RTC_IMSC: s->im = value & 1; DPRINTF("Interrupt mask %d\n", s->im); pl031_update(s); break; case RTC_ICR: /* The PL031 documentation (DDI0224B) states that the interupt is cleared when bit 0 of the written value is set. However the arm926e documentation (DDI0287B) states that the interrupt is cleared when any value is written. */ DPRINTF("Interrupt cleared"); s->is = 0; pl031_update(s); break; case RTC_CR: /* Written value is ignored. */ break; case RTC_DR: case RTC_MIS: case RTC_RIS: fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n", (int)offset); break; default: cpu_abort(cpu_single_env, "pl031_write: Bad offset 0x%x\n", (int)offset); break; } }
static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset, uint32_t value) { SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; DPRINTF("reg write %d\n", (int)offset); offset &= 0xfff; switch (offset >> 2) { case KBD_INT_ENABLE: s->int_enabled = value; syborg_keyboard_update(s); break; default: cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n", (int)offset); } }
/* I/O read */ static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset) { nand_dev_controller_state *s = (nand_dev_controller_state *)opaque; nand_dev *dev; switch (offset) { case NAND_VERSION: return NAND_VERSION_CURRENT; case NAND_NUM_DEV: return nand_dev_count; case NAND_RESULT: return s->result; } if(s->dev >= nand_dev_count) return 0; dev = nand_devs + s->dev; switch (offset) { case NAND_DEV_FLAGS: return dev->flags; case NAND_DEV_NAME_LEN: return dev->devname_len; case NAND_DEV_PAGE_SIZE: return dev->page_size; case NAND_DEV_EXTRA_SIZE: return dev->extra_size; case NAND_DEV_ERASE_SIZE: return dev->erase_size; case NAND_DEV_SIZE_LOW: return (uint32_t)dev->max_size; case NAND_DEV_SIZE_HIGH: return (uint32_t)(dev->max_size >> 32); default: cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset); return 0; } }
static uint32_t syborg_rtc_read(void *opaque, target_phys_addr_t offset) { SyborgRTCState *s = (SyborgRTCState *)opaque; offset &= 0xfff; switch (offset >> 2) { case RTC_ID: return SYBORG_ID_RTC; case RTC_DATA_LOW: return (uint32_t)s->data; case RTC_DATA_HIGH: return (uint32_t)(s->data >> 32); default: cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n", (int)offset); return 0; } }
static void goldfish_battery_write(void *opaque, hwaddr offset, uint32_t val) { struct goldfish_battery_state *s = opaque; switch(offset) { case BATTERY_INT_ENABLE: /* enable interrupts */ s->int_enable = val; // s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); // goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); break; default: cpu_abort(cpu_single_env, "goldfish_audio_write: Bad offset %" HWADDR_PRIx "\n", offset); } }
void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) { switch (reg) { case 0x02: /* CACR */ env->cacr = val; m68k_switch_sp(env); break; case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ /* TODO: Implement Access Control Registers. */ break; case 0x801: /* VBR */ env->vbr = val; break; /* TODO: Implement control registers. */ default: cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n", reg, val); } }
static uint32_t pl022_read(void *opaque, target_phys_addr_t offset) { pl022_state *s = (pl022_state *)opaque; int val; offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { return pl022_id[(offset - 0xfe0) >> 2]; } switch (offset) { case 0x00: /* CR0 */ return s->cr0; case 0x04: /* CR1 */ return s->cr1; case 0x08: /* DR */ if (s->rx_fifo_len) { val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7]; DPRINTF("RX %02x\n", val); s->rx_fifo_len--; pl022_xfer(s); } else { val = 0; } return val; case 0x0c: /* SR */ return s->sr; case 0x10: /* CPSR */ return s->cpsr; case 0x14: /* IMSC */ return s->im; case 0x18: /* RIS */ return s->is; case 0x1c: /* MIS */ return s->im & s->is; case 0x20: /* DMACR */ /* Not implemented. */ return 0; default: cpu_abort (cpu_single_env, "pl022_read: Bad offset %x\n", (int)offset); return 0; } }
void openrisc_cpu_do_interrupt(CPUState *cs) { #ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = OPENRISC_CPU(cs); CPUOpenRISCState *env = &cpu->env; env->epcr = env->pc; if (env->flags & D_FLAG) { env->flags &= ~D_FLAG; env->sr |= SR_DSX; env->epcr -= 4; } if (cs->exception_index == EXCP_SYSCALL) { env->epcr += 4; } /* For machine-state changed between user-mode and supervisor mode, we need flush TLB when we enter&exit EXCP. */ tlb_flush(cs, 1); env->esr = env->sr; env->sr &= ~SR_DME; env->sr &= ~SR_IME; env->sr |= SR_SM; env->sr &= ~SR_IEE; env->sr &= ~SR_TEE; env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) { #ifdef OR32_ARCH_DEFAULT env->pc = (cs->exception_index << 8); #else env->pc = 0x100000 + (cs->exception_index << 8); #endif //printf("pc = 0x%x\n", env->pc); } else { cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } #endif cs->exception_index = -1; }
static void syborg_int_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { SyborgIntState *s = (SyborgIntState *)opaque; int i; offset &= 0xfff; DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value); switch (offset >> 2) { case INT_DISABLE_ALL: s->pending_count = 0; for (i = 0; i < s->num_irqs; i++) s->flags[i].enabled = 0; break; case INT_DISABLE: if (value >= s->num_irqs) break; if (s->flags[value].enabled) { if (s->flags[value].enabled) s->pending_count--; s->flags[value].enabled = 0; } break; case INT_ENABLE: if (value >= s->num_irqs) break; if (!(s->flags[value].enabled)) { if(s->flags[value].level) s->pending_count++; s->flags[value].enabled = 1; } break; default: cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n", (int)offset); return; } syborg_int_update(s); }
/* I/O read */ static uint32_t trace_dev_read(void *opaque, hwaddr offset) { trace_dev_state *s = (trace_dev_state *)opaque; (void)s; switch (offset >> 2) { case TRACE_DEV_REG_ENABLE: // tracing enable return tracing; default: if (offset < 4096) { cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); } else { D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset); } return 0; } return 0; }
static uint32_t goldfish_rfkill_read(void *opaque, target_phys_addr_t offset) { struct rfkill_state *s = opaque; switch(offset) { case OFFSET_INT: D("read inta 0x%08x\n", s->inta); return s->inta; case OFFSET_HWBLOCK: D("read hw_block 0x%08x\n", s->hw_block); return s->hw_block; default: cpu_abort (cpu_single_env, "goldfish_rfkill_read: bad offset %x\n", offset); return 0; } }
static void gptm_tick(void *opaque) { gptm_state **p = (gptm_state **)opaque; gptm_state *s; int n; s = *p; n = p - s->opaque; if (s->config == 0) { s->state |= 1; if ((s->control & 0x20)) { /* Output trigger. */ qemu_irq_raise(s->trigger); qemu_irq_lower(s->trigger); } if (s->mode[0] & 1) { /* One-shot. */ s->control &= ~1; } else { /* Periodic. */ gptm_reload(s, 0, 0); } } else if (s->config == 1) { /* RTC. */ uint32_t match; s->rtc++; match = s->match[0] | (s->match[1] << 16); if (s->rtc > match) s->rtc = 0; if (s->rtc == 0) { s->state |= 8; } gptm_reload(s, 0, 0); } else if (s->mode[n] == 0xa) { /* PWM mode. Not implemented. */ } else { cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", s->mode[n]); } gptm_update_irq(s); }
static uint32_t goldfish_bus_read(void *opaque, hwaddr offset) { struct bus_state *s = (struct bus_state *)opaque; switch (offset) { case PDEV_BUS_OP: if(s->current) { s->current->reported_state = 1; s->current = s->current->next; } else { s->current = first_device; } while(s->current && s->current->reported_state == 1) s->current = s->current->next; if(s->current) return PDEV_BUS_OP_ADD_DEV; else { goldfish_device_set_irq(&s->dev, 0, 0); return PDEV_BUS_OP_DONE; } case PDEV_BUS_NAME_LEN: return s->current ? strlen(s->current->name) : 0; case PDEV_BUS_ID: return s->current ? s->current->id : 0; case PDEV_BUS_IO_BASE: return s->current ? s->current->base : 0; case PDEV_BUS_IO_SIZE: return s->current ? s->current->size : 0; case PDEV_BUS_IRQ: return s->current ? s->current->irq : 0; case PDEV_BUS_IRQ_COUNT: return s->current ? s->current->irq_count : 0; default: cpu_abort(cpu_single_env, "goldfish_bus_read: Bad offset %" HWADDR_PRIx "\n", offset); return 0; } }
static void arm_pic_cpu_handler(void *opaque, int irq, int level) { arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque; switch (irq) { case ARM_PIC_CPU_IRQ: if (level) cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); else cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); break; case ARM_PIC_CPU_FIQ: if (level) cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); else cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); break; default: cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq); } }
static uint32_t goldfish_int_read(void *opaque, target_phys_addr_t offset) { GoldfishInterruptDevice *s = (GoldfishInterruptDevice *)opaque; switch (offset) { case INTERRUPT_STATUS: /* IRQ_STATUS */ return s->pending_count; case INTERRUPT_NUMBER: { int i; uint32_t pending = s->level & s->irq_enabled; for(i = 0; i < 32; i++) { if(pending & (1U << i)) return i; } return 0; } default: cpu_abort (cpu_single_env, "goldfish_int_read: Bad offset %x\n", offset); return 0; } }
static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, uint8_t byte) { hwaddr dest_phys; hwaddr len = l; void *dest_p; uint64_t asc = env->psw.mask & PSW_MASK_ASC; int flags; if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { cpu_stb_data(env, dest, byte); cpu_abort(env, "should never reach here"); } dest_phys |= dest & ~TARGET_PAGE_MASK; dest_p = cpu_physical_memory_map(dest_phys, &len, 1); memset(dest_p, byte, len); cpu_physical_memory_unmap(dest_p, 1, len, len); }
void lm32_cpu_do_interrupt(CPUState *cs) { LM32CPU *cpu = LM32_CPU(cs); CPULM32State *env = &cpu->env; qemu_log_mask(CPU_LOG_INT, "exception at pc=%x type=%x\n", env->pc, env->exception_index); switch (env->exception_index) { case EXCP_INSN_BUS_ERROR: case EXCP_DATA_BUS_ERROR: case EXCP_DIVIDE_BY_ZERO: case EXCP_IRQ: case EXCP_SYSTEMCALL: /* non-debug exceptions */ env->regs[R_EA] = env->pc; env->ie |= (env->ie & IE_IE) ? IE_EIE : 0; env->ie &= ~IE_IE; if (env->dc & DC_RE) { env->pc = env->deba + (env->exception_index * 32); } else { env->pc = env->eba + (env->exception_index * 32); } log_cpu_state_mask(CPU_LOG_INT, env, 0); break; case EXCP_BREAKPOINT: case EXCP_WATCHPOINT: /* debug exceptions */ env->regs[R_BA] = env->pc; env->ie |= (env->ie & IE_IE) ? IE_BIE : 0; env->ie &= ~IE_IE; env->pc = env->deba + (env->exception_index * 32); log_cpu_state_mask(CPU_LOG_INT, env, 0); break; default: cpu_abort(env, "unhandled exception type=%d\n", env->exception_index); break; } }
static void goldfish_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value) { struct rtc_state *s = (struct rtc_state *)opaque; int64_t alarm; switch(offset) { case 0x8: s->alarm_low = value; alarm = s->alarm_low | (int64_t)s->alarm_high << 32; //printf("next alarm at %lld, tps %lld\n", alarm, ticks_per_sec); //qemu_mod_timer(s->timer, alarm); break; case 0xc: s->alarm_high = value; //printf("alarm_high %d\n", s->alarm_high); break; case 0x10: goldfish_device_set_irq(&s->dev, 0, 0); break; default: cpu_abort (cpu_single_env, "goldfish_rtc_write: Bad offset %x\n", offset); } }
static uint32_t goldfish_sensor_read(void *opaque, target_phys_addr_t offset) { uint32_t ret; struct goldfish_sensor_state *s = opaque; offset -= s->dev.base; switch(offset) { case INT_ENABLE: // return current buffer status flags ret = s->int_status & s->int_enable; if (ret) { goldfish_device_set_irq(&s->dev, 0, 0); s->int_status = 0; } return ret; case ACCEL_X: return s->accel_x; case ACCEL_Y: return s->accel_y; case ACCEL_Z: return s->accel_z; case COMPASS_X: return s->compass_x; case COMPASS_Y: return s->compass_y; case COMPASS_Z: return s->compass_z; case ORIENT_X: return s->orient_x; case ORIENT_Y: return s->orient_y; case ORIENT_Z: return s->orient_z; default: cpu_abort (cpu_single_env, "goldfish_sensor_read: Bad offset %x\n", offset); return 0; } }