📄 omap.c.svn-base
字号:
/* * TI OMAP processors emulation. * * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */#include "hw.h"#include "arm-misc.h"#include "omap.h"#include "sysemu.h"#include "qemu-timer.h"/* We use pc-style serial ports. */#include "pc.h"/* Should signal the TCMI */uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr){ uint8_t ret; OMAP_8B_REG(addr); cpu_physical_memory_read(addr, (void *) &ret, 1); return ret;}void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, uint32_t value){ uint8_t val8 = value; OMAP_8B_REG(addr); cpu_physical_memory_write(addr, (void *) &val8, 1);}uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr){ uint16_t ret; OMAP_16B_REG(addr); cpu_physical_memory_read(addr, (void *) &ret, 2); return ret;}void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, uint32_t value){ uint16_t val16 = value; OMAP_16B_REG(addr); cpu_physical_memory_write(addr, (void *) &val16, 2);}uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr){ uint32_t ret; OMAP_32B_REG(addr); cpu_physical_memory_read(addr, (void *) &ret, 4); return ret;}void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, uint32_t value){ OMAP_32B_REG(addr); cpu_physical_memory_write(addr, (void *) &value, 4);}/* Interrupt Handlers */struct omap_intr_handler_bank_s { uint32_t irqs; uint32_t inputs; uint32_t mask; uint32_t fiq; uint32_t sens_edge; unsigned char priority[32];};struct omap_intr_handler_s { qemu_irq *pins; qemu_irq parent_intr[2]; target_phys_addr_t base; unsigned char nbanks; /* state */ uint32_t new_agr[2]; int sir_intr[2]; struct omap_intr_handler_bank_s banks[];};static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq){ int i, j, sir_intr, p_intr, p, f; uint32_t level; sir_intr = 0; p_intr = 255; /* Find the interrupt line with the highest dynamic priority. * Note: 0 denotes the hightest priority. * If all interrupts have the same priority, the default order is IRQ_N, * IRQ_N-1,...,IRQ_0. */ for (j = 0; j < s->nbanks; ++j) { level = s->banks[j].irqs & ~s->banks[j].mask & (is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq); for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, level >>= f) { p = s->banks[j].priority[i]; if (p <= p_intr) { p_intr = p; sir_intr = 32 * j + i; } f = ffs(level >> 1); } } s->sir_intr[is_fiq] = sir_intr;}static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq){ int i; uint32_t has_intr = 0; for (i = 0; i < s->nbanks; ++i) has_intr |= s->banks[i].irqs & ~s->banks[i].mask & (is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq); if (s->new_agr[is_fiq] && has_intr) { s->new_agr[is_fiq] = 0; omap_inth_sir_update(s, is_fiq); qemu_set_irq(s->parent_intr[is_fiq], 1); }}#define INT_FALLING_EDGE 0#define INT_LOW_LEVEL 1static void omap_set_intr(void *opaque, int irq, int req){ struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; uint32_t rise; struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5]; int n = irq & 31; if (req) { rise = ~bank->irqs & (1 << n); if (~bank->sens_edge & (1 << n)) rise &= ~bank->inputs & (1 << n); bank->inputs |= (1 << n); if (rise) { bank->irqs |= rise; omap_inth_update(ih, 0); omap_inth_update(ih, 1); } } else { rise = bank->sens_edge & bank->irqs & (1 << n); bank->irqs &= ~rise; bank->inputs &= ~(1 << n); }}static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr){ struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; int i, offset = addr - s->base; int bank_no = offset >> 8; int line_no; struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; offset &= 0xff; switch (offset) { case 0x00: /* ITR */ return bank->irqs; case 0x04: /* MIR */ return bank->mask; case 0x10: /* SIR_IRQ_CODE */ case 0x14: /* SIR_FIQ_CODE */ if (bank_no != 0) break; line_no = s->sir_intr[(offset - 0x10) >> 2]; bank = &s->banks[line_no >> 5]; i = line_no & 31; if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) bank->irqs &= ~(1 << i); return line_no; case 0x18: /* CONTROL_REG */ if (bank_no != 0) break; return 0; case 0x1c: /* ILR0 */ case 0x20: /* ILR1 */ case 0x24: /* ILR2 */ case 0x28: /* ILR3 */ case 0x2c: /* ILR4 */ case 0x30: /* ILR5 */ case 0x34: /* ILR6 */ case 0x38: /* ILR7 */ case 0x3c: /* ILR8 */ case 0x40: /* ILR9 */ case 0x44: /* ILR10 */ case 0x48: /* ILR11 */ case 0x4c: /* ILR12 */ case 0x50: /* ILR13 */ case 0x54: /* ILR14 */ case 0x58: /* ILR15 */ case 0x5c: /* ILR16 */ case 0x60: /* ILR17 */ case 0x64: /* ILR18 */ case 0x68: /* ILR19 */ case 0x6c: /* ILR20 */ case 0x70: /* ILR21 */ case 0x74: /* ILR22 */ case 0x78: /* ILR23 */ case 0x7c: /* ILR24 */ case 0x80: /* ILR25 */ case 0x84: /* ILR26 */ case 0x88: /* ILR27 */ case 0x8c: /* ILR28 */ case 0x90: /* ILR29 */ case 0x94: /* ILR30 */ case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; return (bank->priority[i] << 2) | (((bank->sens_edge >> i) & 1) << 1) | ((bank->fiq >> i) & 1); case 0x9c: /* ISR */ return 0x00000000; } OMAP_BAD_REG(addr); return 0;}static void omap_inth_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; int i, offset = addr - s->base; int bank_no = offset >> 8; struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; offset &= 0xff; switch (offset) { case 0x00: /* ITR */ /* Important: ignore the clearing if the IRQ is level-triggered and the input bit is 1 */ bank->irqs &= value | (bank->inputs & bank->sens_edge); return; case 0x04: /* MIR */ bank->mask = value; omap_inth_update(s, 0); omap_inth_update(s, 1); return; case 0x10: /* SIR_IRQ_CODE */ case 0x14: /* SIR_FIQ_CODE */ OMAP_RO_REG(addr); break; case 0x18: /* CONTROL_REG */ if (bank_no != 0) break; if (value & 2) { qemu_set_irq(s->parent_intr[1], 0); s->new_agr[1] = ~0; omap_inth_update(s, 1); } if (value & 1) { qemu_set_irq(s->parent_intr[0], 0); s->new_agr[0] = ~0; omap_inth_update(s, 0); } return; case 0x1c: /* ILR0 */ case 0x20: /* ILR1 */ case 0x24: /* ILR2 */ case 0x28: /* ILR3 */ case 0x2c: /* ILR4 */ case 0x30: /* ILR5 */ case 0x34: /* ILR6 */ case 0x38: /* ILR7 */ case 0x3c: /* ILR8 */ case 0x40: /* ILR9 */ case 0x44: /* ILR10 */ case 0x48: /* ILR11 */ case 0x4c: /* ILR12 */ case 0x50: /* ILR13 */ case 0x54: /* ILR14 */ case 0x58: /* ILR15 */ case 0x5c: /* ILR16 */ case 0x60: /* ILR17 */ case 0x64: /* ILR18 */ case 0x68: /* ILR19 */ case 0x6c: /* ILR20 */ case 0x70: /* ILR21 */ case 0x74: /* ILR22 */ case 0x78: /* ILR23 */ case 0x7c: /* ILR24 */ case 0x80: /* ILR25 */ case 0x84: /* ILR26 */ case 0x88: /* ILR27 */ case 0x8c: /* ILR28 */ case 0x90: /* ILR29 */ case 0x94: /* ILR30 */ case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; bank->priority[i] = (value >> 2) & 0x1f; bank->sens_edge &= ~(1 << i); bank->sens_edge |= ((value >> 1) & 1) << i; bank->fiq &= ~(1 << i); bank->fiq |= (value & 1) << i; return; case 0x9c: /* ISR */ for (i = 0; i < 32; i ++) if (value & (1 << i)) { omap_set_intr(s, 32 * bank_no + i, 1); return; } return; } OMAP_BAD_REG(addr);}static CPUReadMemoryFunc *omap_inth_readfn[] = { omap_badwidth_read32, omap_badwidth_read32, omap_inth_read,};static CPUWriteMemoryFunc *omap_inth_writefn[] = { omap_inth_write, omap_inth_write, omap_inth_write,};void omap_inth_reset(struct omap_intr_handler_s *s){ int i; for (i = 0; i < s->nbanks; ++i){ s->banks[i].irqs = 0x00000000; s->banks[i].mask = 0xffffffff; s->banks[i].sens_edge = 0x00000000; s->banks[i].fiq = 0x00000000; s->banks[i].inputs = 0x00000000; memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority)); } s->new_agr[0] = ~0; s->new_agr[1] = ~0; s->sir_intr[0] = 0; s->sir_intr[1] = 0; qemu_set_irq(s->parent_intr[0], 0); qemu_set_irq(s->parent_intr[1], 0);}struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, unsigned long size, unsigned char nbanks, qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk){ int iomemtype; struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) qemu_mallocz(sizeof(struct omap_intr_handler_s) + sizeof(struct omap_intr_handler_bank_s) * nbanks); s->parent_intr[0] = parent_irq; s->parent_intr[1] = parent_fiq; s->base = base; s->nbanks = nbanks; s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); omap_inth_reset(s); iomemtype = cpu_register_io_memory(0, omap_inth_readfn, omap_inth_writefn, s); cpu_register_physical_memory(s->base, size, iomemtype); return s;}/* OMAP1 DMA module */struct omap_dma_channel_s { /* transfer data */ int burst[2]; int pack[2]; enum omap_dma_port port[2]; target_phys_addr_t addr[2]; omap_dma_addressing_t mode[2]; uint16_t elements; uint16_t frames; int16_t frame_index[2]; int16_t element_index[2]; int data_type; /* transfer type */ int transparent_copy; int constant_fill; uint32_t color; /* auto init and linked channel data */ int end_prog; int repeat; int auto_init; int link_enabled; int link_next_ch; /* interruption data */ int interrupts; int status; /* state data */ int active; int enable; int sync; int pending_request; int waiting_end_prog; uint16_t cpc; /* sync type */ int fs; int bs; /* compatibility */ int omap_3_1_compatible_disable; qemu_irq irq; struct omap_dma_channel_s *sibling; struct omap_dma_reg_set_s { target_phys_addr_t src, dest; int frame; int element; int frame_delta[2]; int elem_delta[2]; int frames; int elements; } active_set; /* unused parameters */ int priority; int interleave_disabled; int type;};struct omap_dma_s {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -