symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mcf_intc.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * ColdFire Interrupt Controller emulation.
       
     3  *
       
     4  * Copyright (c) 2007 CodeSourcery.
       
     5  *
       
     6  * This code is licenced under the GPL
       
     7  */
       
     8 #include "hw.h"
       
     9 #include "mcf.h"
       
    10 
       
    11 typedef struct {
       
    12     uint64_t ipr;
       
    13     uint64_t imr;
       
    14     uint64_t ifr;
       
    15     uint64_t enabled;
       
    16     uint8_t icr[64];
       
    17     CPUState *env;
       
    18     int active_vector;
       
    19 } mcf_intc_state;
       
    20 
       
    21 static void mcf_intc_update(mcf_intc_state *s)
       
    22 {
       
    23     uint64_t active;
       
    24     int i;
       
    25     int best;
       
    26     int best_level;
       
    27 
       
    28     active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
       
    29     best_level = 0;
       
    30     best = 64;
       
    31     if (active) {
       
    32         for (i = 0; i < 64; i++) {
       
    33             if ((active & 1) != 0 && s->icr[i] >= best_level) {
       
    34                 best_level = s->icr[i];
       
    35                 best = i;
       
    36             }
       
    37             active >>= 1;
       
    38         }
       
    39     }
       
    40     s->active_vector = ((best == 64) ? 24 : (best + 64));
       
    41     m68k_set_irq_level(s->env, best_level, s->active_vector);
       
    42 }
       
    43 
       
    44 static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr)
       
    45 {
       
    46     int offset;
       
    47     mcf_intc_state *s = (mcf_intc_state *)opaque;
       
    48     offset = addr & 0xff;
       
    49     if (offset >= 0x40 && offset < 0x80) {
       
    50         return s->icr[offset - 0x40];
       
    51     }
       
    52     switch (offset) {
       
    53     case 0x00:
       
    54         return (uint32_t)(s->ipr >> 32);
       
    55     case 0x04:
       
    56         return (uint32_t)s->ipr;
       
    57     case 0x08:
       
    58         return (uint32_t)(s->imr >> 32);
       
    59     case 0x0c:
       
    60         return (uint32_t)s->imr;
       
    61     case 0x10:
       
    62         return (uint32_t)(s->ifr >> 32);
       
    63     case 0x14:
       
    64         return (uint32_t)s->ifr;
       
    65     case 0xe0: /* SWIACK.  */
       
    66         return s->active_vector;
       
    67     case 0xe1: case 0xe2: case 0xe3: case 0xe4:
       
    68     case 0xe5: case 0xe6: case 0xe7:
       
    69         /* LnIACK */
       
    70         cpu_abort(cpu_single_env, "mcf_intc_read: LnIACK not implemented\n");
       
    71     default:
       
    72         return 0;
       
    73     }
       
    74 }
       
    75 
       
    76 static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val)
       
    77 {
       
    78     int offset;
       
    79     mcf_intc_state *s = (mcf_intc_state *)opaque;
       
    80     offset = addr & 0xff;
       
    81     if (offset >= 0x40 && offset < 0x80) {
       
    82         int n = offset - 0x40;
       
    83         s->icr[n] = val;
       
    84         if (val == 0)
       
    85             s->enabled &= ~(1ull << n);
       
    86         else
       
    87             s->enabled |= (1ull << n);
       
    88         mcf_intc_update(s);
       
    89         return;
       
    90     }
       
    91     switch (offset) {
       
    92     case 0x00: case 0x04:
       
    93         /* Ignore IPR writes.  */
       
    94         return;
       
    95     case 0x08:
       
    96         s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
       
    97         break;
       
    98     case 0x0c:
       
    99         s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
       
   100         break;
       
   101     default:
       
   102         cpu_abort(cpu_single_env, "mcf_intc_write: Bad write offset %d\n",
       
   103                   offset);
       
   104         break;
       
   105     }
       
   106     mcf_intc_update(s);
       
   107 }
       
   108 
       
   109 static void mcf_intc_set_irq(void *opaque, int irq, int level)
       
   110 {
       
   111     mcf_intc_state *s = (mcf_intc_state *)opaque;
       
   112     if (irq >= 64)
       
   113         return;
       
   114     if (level)
       
   115         s->ipr |= 1ull << irq;
       
   116     else
       
   117         s->ipr &= ~(1ull << irq);
       
   118     mcf_intc_update(s);
       
   119 }
       
   120 
       
   121 static void mcf_intc_reset(mcf_intc_state *s)
       
   122 {
       
   123     s->imr = ~0ull;
       
   124     s->ipr = 0;
       
   125     s->ifr = 0;
       
   126     s->enabled = 0;
       
   127     memset(s->icr, 0, 64);
       
   128     s->active_vector = 24;
       
   129 }
       
   130 
       
   131 static CPUReadMemoryFunc *mcf_intc_readfn[] = {
       
   132    mcf_intc_read,
       
   133    mcf_intc_read,
       
   134    mcf_intc_read
       
   135 };
       
   136 
       
   137 static CPUWriteMemoryFunc *mcf_intc_writefn[] = {
       
   138    mcf_intc_write,
       
   139    mcf_intc_write,
       
   140    mcf_intc_write
       
   141 };
       
   142 
       
   143 qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
       
   144 {
       
   145     mcf_intc_state *s;
       
   146     int iomemtype;
       
   147 
       
   148     s = qemu_mallocz(sizeof(mcf_intc_state));
       
   149     s->env = env;
       
   150     mcf_intc_reset(s);
       
   151 
       
   152     iomemtype = cpu_register_io_memory(0, mcf_intc_readfn,
       
   153                                        mcf_intc_writefn, s);
       
   154     cpu_register_physical_memory(base, 0x100, iomemtype);
       
   155 
       
   156     return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
       
   157 }