symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/sun4c_intctl.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU Sparc Sun4c interrupt controller emulation
       
     3  *
       
     4  * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 #include "hw.h"
       
    25 #include "sun4m.h"
       
    26 #include "console.h"
       
    27 //#define DEBUG_IRQ_COUNT
       
    28 //#define DEBUG_IRQ
       
    29 
       
    30 #ifdef DEBUG_IRQ
       
    31 #define DPRINTF(fmt, args...) \
       
    32 do { printf("IRQ: " fmt , ##args); } while (0)
       
    33 #else
       
    34 #define DPRINTF(fmt, args...)
       
    35 #endif
       
    36 
       
    37 /*
       
    38  * Registers of interrupt controller in sun4c.
       
    39  *
       
    40  */
       
    41 
       
    42 #define MAX_PILS 16
       
    43 
       
    44 typedef struct Sun4c_INTCTLState {
       
    45 #ifdef DEBUG_IRQ_COUNT
       
    46     uint64_t irq_count;
       
    47 #endif
       
    48     qemu_irq *cpu_irqs;
       
    49     const uint32_t *intbit_to_level;
       
    50     uint32_t pil_out;
       
    51     uint8_t reg;
       
    52     uint8_t pending;
       
    53 } Sun4c_INTCTLState;
       
    54 
       
    55 #define INTCTL_SIZE 1
       
    56 
       
    57 static void sun4c_check_interrupts(void *opaque);
       
    58 
       
    59 static uint32_t sun4c_intctl_mem_readb(void *opaque, target_phys_addr_t addr)
       
    60 {
       
    61     Sun4c_INTCTLState *s = opaque;
       
    62     uint32_t ret;
       
    63 
       
    64     ret = s->reg;
       
    65     DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
       
    66 
       
    67     return ret;
       
    68 }
       
    69 
       
    70 static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr,
       
    71                                     uint32_t val)
       
    72 {
       
    73     Sun4c_INTCTLState *s = opaque;
       
    74 
       
    75     DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
       
    76     val &= 0xbf;
       
    77     s->reg = val;
       
    78     sun4c_check_interrupts(s);
       
    79 }
       
    80 
       
    81 static CPUReadMemoryFunc *sun4c_intctl_mem_read[3] = {
       
    82     sun4c_intctl_mem_readb,
       
    83     NULL,
       
    84     NULL,
       
    85 };
       
    86 
       
    87 static CPUWriteMemoryFunc *sun4c_intctl_mem_write[3] = {
       
    88     sun4c_intctl_mem_writeb,
       
    89     NULL,
       
    90     NULL,
       
    91 };
       
    92 
       
    93 void sun4c_pic_info(void *opaque)
       
    94 {
       
    95     Sun4c_INTCTLState *s = opaque;
       
    96 
       
    97     term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending,
       
    98                 s->reg);
       
    99 }
       
   100 
       
   101 void sun4c_irq_info(void *opaque)
       
   102 {
       
   103 #ifndef DEBUG_IRQ_COUNT
       
   104     term_printf("irq statistic code not compiled.\n");
       
   105 #else
       
   106     Sun4c_INTCTLState *s = opaque;
       
   107     int64_t count;
       
   108 
       
   109     term_printf("IRQ statistics:\n");
       
   110     count = s->irq_count[i];
       
   111     if (count > 0)
       
   112         term_printf("%2d: %" PRId64 "\n", i, count);
       
   113 #endif
       
   114 }
       
   115 
       
   116 static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
       
   117 
       
   118 static void sun4c_check_interrupts(void *opaque)
       
   119 {
       
   120     Sun4c_INTCTLState *s = opaque;
       
   121     uint32_t pil_pending;
       
   122     unsigned int i;
       
   123 
       
   124     DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
       
   125     pil_pending = 0;
       
   126     if (s->pending && !(s->reg & 0x80000000)) {
       
   127         for (i = 0; i < 8; i++) {
       
   128             if (s->pending & (1 << i))
       
   129                 pil_pending |= 1 << intbit_to_level[i];
       
   130         }
       
   131     }
       
   132 
       
   133     for (i = 0; i < MAX_PILS; i++) {
       
   134         if (pil_pending & (1 << i)) {
       
   135             if (!(s->pil_out & (1 << i)))
       
   136                 qemu_irq_raise(s->cpu_irqs[i]);
       
   137         } else {
       
   138             if (s->pil_out & (1 << i))
       
   139                 qemu_irq_lower(s->cpu_irqs[i]);
       
   140         }
       
   141     }
       
   142     s->pil_out = pil_pending;
       
   143 }
       
   144 
       
   145 /*
       
   146  * "irq" here is the bit number in the system interrupt register
       
   147  */
       
   148 static void sun4c_set_irq(void *opaque, int irq, int level)
       
   149 {
       
   150     Sun4c_INTCTLState *s = opaque;
       
   151     uint32_t mask = 1 << irq;
       
   152     uint32_t pil = intbit_to_level[irq];
       
   153 
       
   154     DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
       
   155             level);
       
   156     if (pil > 0) {
       
   157         if (level) {
       
   158 #ifdef DEBUG_IRQ_COUNT
       
   159             s->irq_count[pil]++;
       
   160 #endif
       
   161             s->pending |= mask;
       
   162         } else {
       
   163             s->pending &= ~mask;
       
   164         }
       
   165         sun4c_check_interrupts(s);
       
   166     }
       
   167 }
       
   168 
       
   169 static void sun4c_intctl_save(QEMUFile *f, void *opaque)
       
   170 {
       
   171     Sun4c_INTCTLState *s = opaque;
       
   172 
       
   173     qemu_put_8s(f, &s->reg);
       
   174     qemu_put_8s(f, &s->pending);
       
   175 }
       
   176 
       
   177 static int sun4c_intctl_load(QEMUFile *f, void *opaque, int version_id)
       
   178 {
       
   179     Sun4c_INTCTLState *s = opaque;
       
   180 
       
   181     if (version_id != 1)
       
   182         return -EINVAL;
       
   183 
       
   184     qemu_get_8s(f, &s->reg);
       
   185     qemu_get_8s(f, &s->pending);
       
   186     sun4c_check_interrupts(s);
       
   187 
       
   188     return 0;
       
   189 }
       
   190 
       
   191 static void sun4c_intctl_reset(void *opaque)
       
   192 {
       
   193     Sun4c_INTCTLState *s = opaque;
       
   194 
       
   195     s->reg = 1;
       
   196     s->pending = 0;
       
   197     sun4c_check_interrupts(s);
       
   198 }
       
   199 
       
   200 void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq,
       
   201                         qemu_irq *parent_irq)
       
   202 {
       
   203     int sun4c_intctl_io_memory;
       
   204     Sun4c_INTCTLState *s;
       
   205 
       
   206     s = qemu_mallocz(sizeof(Sun4c_INTCTLState));
       
   207     if (!s)
       
   208         return NULL;
       
   209 
       
   210     sun4c_intctl_io_memory = cpu_register_io_memory(0, sun4c_intctl_mem_read,
       
   211                                                     sun4c_intctl_mem_write, s);
       
   212     cpu_register_physical_memory(addr, INTCTL_SIZE, sun4c_intctl_io_memory);
       
   213     s->cpu_irqs = parent_irq;
       
   214 
       
   215     register_savevm("sun4c_intctl", addr, 1, sun4c_intctl_save,
       
   216                     sun4c_intctl_load, s);
       
   217 
       
   218     qemu_register_reset(sun4c_intctl_reset, s);
       
   219     *irq = qemu_allocate_irqs(sun4c_set_irq, s, 8);
       
   220 
       
   221     sun4c_intctl_reset(s);
       
   222     return s;
       
   223 }