diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-09-30 22:13:50 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-09-30 22:13:50 +0000 |
commit | 420557e8981347368427849ff89ecd3fe537dafa (patch) | |
tree | 986c9023d271a0999c8e7f61918439ec08f17d77 /hw/sched.c | |
parent | 6d5e216de979afdc0a26410580ad31376f7107f7 (diff) | |
download | qemu-420557e8981347368427849ff89ecd3fe537dafa.zip qemu-420557e8981347368427849ff89ecd3fe537dafa.tar.gz qemu-420557e8981347368427849ff89ecd3fe537dafa.tar.bz2 |
full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1085 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/sched.c')
-rw-r--r-- | hw/sched.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/hw/sched.c b/hw/sched.c new file mode 100644 index 0000000..c9a685d --- /dev/null +++ b/hw/sched.c @@ -0,0 +1,346 @@ +/* + * QEMU interrupt controller & timer emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define PHYS_JJ_CLOCK 0x71D00000 +#define PHYS_JJ_CLOCK1 0x71D10000 +#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ + +/* These registers are used for sending/receiving irqs from/to + * different cpu's. + */ +struct sun4m_intreg_percpu { + unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ + /* These next two registers are WRITE-ONLY and are only + * "on bit" sensitive, "off bits" written have NO affect. + */ + unsigned int clear; /* Clear this cpus irqs here. */ + unsigned int set; /* Set this cpus irqs here. */ +}; +/* + * djhr + * Actually the clear and set fields in this struct are misleading.. + * according to the SLAVIO manual (and the same applies for the SEC) + * the clear field clears bits in the mask which will ENABLE that IRQ + * the set field sets bits in the mask to DISABLE the IRQ. + * + * Also the undirected_xx address in the SLAVIO is defined as + * RESERVED and write only.. + * + * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor + * sun4m machines, for MP the layout makes more sense. + */ +struct sun4m_intreg_master { + unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ + unsigned int irqs; /* Master IRQ bits. */ + + /* Again, like the above, two these registers are WRITE-ONLY. */ + unsigned int clear; /* Clear master IRQ's by setting bits here. */ + unsigned int set; /* Set master IRQ's by setting bits here. */ + + /* This register is both READ and WRITE. */ + unsigned int undirected_target; /* Which cpu gets undirected irqs. */ +}; +/* + * Registers of hardware timer in sun4m. + */ +struct sun4m_timer_percpu { + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ + volatile unsigned int l14_cur_count; +}; + +struct sun4m_timer_global { + volatile unsigned int l10_timer_limit; + volatile unsigned int l10_cur_count; +}; + +#define SUN4M_INT_ENABLE 0x80000000 +#define SUN4M_INT_E14 0x00000080 +#define SUN4M_INT_E10 0x00080000 + +#define SUN4M_HARD_INT(x) (0x000000001 << (x)) +#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) + +#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ +#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ +#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ +#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ +#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ +#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ +#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ +#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ +#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ +#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ +#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ +#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ +#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ + +#define SUN4M_INT_SBUS(x) (1 << (x+7)) +#define SUN4M_INT_VME(x) (1 << (x)) + +typedef struct SCHEDState { + uint32_t intreg_pending; + uint32_t intreg_enabled; + uint32_t intregm_pending; + uint32_t intregm_enabled; + uint32_t timer_regs[2]; + uint32_t timerm_regs[2]; +} SCHEDState; + +static SCHEDState *ps; + +static int intreg_io_memory, intregm_io_memory, + timer_io_memory, timerm_io_memory; + +static void sched_reset(SCHEDState *s) +{ +} + +static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR0) >> 2; + switch (saddr) { + case 0: + return s->intreg_pending; + break; + default: + break; + } + return 0; +} + +static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR0) >> 2; + switch (saddr) { + case 0: + s->intreg_pending = val; + break; + case 1: // clear + s->intreg_enabled &= ~val; + break; + case 2: // set + s->intreg_enabled |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *intreg_mem_read[3] = { + intreg_mem_readl, + intreg_mem_readl, + intreg_mem_readl, +}; + +static CPUWriteMemoryFunc *intreg_mem_write[3] = { + intreg_mem_writel, + intreg_mem_writel, + intreg_mem_writel, +}; + +static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR_G) >> 2; + switch (saddr) { + case 0: + return s->intregm_pending; + break; + case 1: + return s->intregm_enabled; + break; + default: + break; + } + return 0; +} + +static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR_G) >> 2; + switch (saddr) { + case 0: + s->intregm_pending = val; + break; + case 1: + s->intregm_enabled = val; + break; + case 2: // clear + s->intregm_enabled &= ~val; + break; + case 3: // set + s->intregm_enabled |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *intregm_mem_read[3] = { + intregm_mem_readl, + intregm_mem_readl, + intregm_mem_readl, +}; + +static CPUWriteMemoryFunc *intregm_mem_write[3] = { + intregm_mem_writel, + intregm_mem_writel, + intregm_mem_writel, +}; + +static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK) >> 2; + switch (saddr) { + default: + return s->timer_regs[saddr]; + break; + } + return 0; +} + +static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK) >> 2; + switch (saddr) { + default: + s->timer_regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *timer_mem_read[3] = { + timer_mem_readl, + timer_mem_readl, + timer_mem_readl, +}; + +static CPUWriteMemoryFunc *timer_mem_write[3] = { + timer_mem_writel, + timer_mem_writel, + timer_mem_writel, +}; + +static uint32_t timerm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; + switch (saddr) { + default: + return s->timerm_regs[saddr]; + break; + } + return 0; +} + +static void timerm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; + switch (saddr) { + default: + s->timerm_regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *timerm_mem_read[3] = { + timerm_mem_readl, + timerm_mem_readl, + timerm_mem_readl, +}; + +static CPUWriteMemoryFunc *timerm_mem_write[3] = { + timerm_mem_writel, + timerm_mem_writel, + timerm_mem_writel, +}; + +void pic_info() {} +void irq_info() {} + +static const unsigned int intr_to_mask[16] = { + 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +void pic_set_irq(int irq, int level) +{ + if (irq < 16) { + unsigned int mask = intr_to_mask[irq]; + ps->intreg_pending |= 1 << irq; + if (ps->intregm_enabled & mask) { + cpu_single_env->interrupt_index = irq; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } +} + +void sched_init() +{ + SCHEDState *s; + + s = qemu_mallocz(sizeof(SCHEDState)); + if (!s) + return; + + intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_INTR0, 3, intreg_io_memory); + + intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_INTR_G, 5, intregm_io_memory); + + timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_CLOCK, 2, timer_io_memory); + + timerm_io_memory = cpu_register_io_memory(0, timerm_mem_read, timerm_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_CLOCK1, 2, timerm_io_memory); + + sched_reset(s); + ps = s; +} + |