Revision e96e2044 hw/sh_intc.c

b/hw/sh_intc.c
14 14
#include "sh.h"
15 15

  
16 16
//#define DEBUG_INTC
17
//#define DEBUG_INTC_SOURCES
17 18

  
18 19
#define INTC_A7(x) ((x) & 0x1fffffff)
19 20
#define INTC_ARRAY(x) (sizeof(x) / sizeof(x[0]))
20 21

  
22
void sh_intc_toggle_source(struct intc_source *source,
23
			   int enable_adj, int assert_adj)
24
{
25
    int enable_changed = 0;
26
    int pending_changed = 0;
27
    int old_pending;
28

  
29
    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
30
        enable_changed = -1;
31

  
32
    source->enable_count += enable_adj;
33

  
34
    if (source->enable_count == source->enable_max)
35
        enable_changed = 1;
36

  
37
    source->asserted += assert_adj;
38

  
39
    old_pending = source->pending;
40
    source->pending = source->asserted &&
41
      (source->enable_count == source->enable_max);
42

  
43
    if (old_pending != source->pending)
44
        pending_changed = 1;
45

  
46
    if (pending_changed) {
47
        if (source->pending) {
48
            source->parent->pending++;
49
	    if (source->parent->pending == 1)
50
                cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
51
	}
52
	else {
53
            source->parent->pending--;
54
	    if (source->parent->pending == 0)
55
                cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
56
	}
57
    }
58

  
59
  if (enable_changed || assert_adj || pending_changed) {
60
#ifdef DEBUG_INTC_SOURCES
61
            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
62
		   source->parent->pending,
63
		   source->asserted,
64
		   source->enable_count,
65
		   source->enable_max,
66
		   source->vect,
67
		   source->asserted ? "asserted " :
68
		   assert_adj ? "deasserted" : "",
69
		   enable_changed == 1 ? "enabled " :
70
		   enable_changed == -1 ? "disabled " : "",
71
		   source->pending ? "pending" : "");
72
#endif
73
  }
74
}
75

  
76
int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
77
{
78
    unsigned int i;
79

  
80
    /* slow: use a linked lists of pending sources instead */
81
    /* wrong: take interrupt priority into account (one list per priority) */
82

  
83
    if (imask == 0x0f) {
84
        return -1; /* FIXME, update code to include priority per source */
85
    }
86

  
87
    for (i = 0; i < desc->nr_sources; i++) {
88
        struct intc_source *source = desc->sources + i;
89

  
90
	if (source->pending) {
91
#ifdef DEBUG_INTC_SOURCES
92
            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
93
		   desc->pending, source->vect);
94
#endif
95
            return source->vect;
96
	}
97
    }
98

  
99
    assert(0);
100
}
101

  
21 102
#define INTC_MODE_NONE       0
22 103
#define INTC_MODE_DUAL_SET   1
23 104
#define INTC_MODE_DUAL_CLR   2
......
94 175
    assert(0);
95 176
}
96 177

  
97
static void sh_intc_toggle(struct intc_desc *desc, intc_enum id,
98
			   int enable, int is_group)
178
static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
179
				int enable, int is_group)
99 180
{
100 181
    struct intc_source *source = desc->sources + id;
101
    int old = source->enable_count;
102 182

  
103 183
    if (!id)
104 184
	return;
105 185

  
106 186
    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
107
#ifdef DEBUG_INTC
187
#ifdef DEBUG_INTC_SOURCES
108 188
        printf("sh_intc: reserved interrupt source %d modified\n", id);
109 189
#endif
110 190
	return;
111 191
    }
112 192

  
113
    if (source->vect) {
114
        if (enable)
115
            source->enable_count++;
116
	else 
117
            source->enable_count--;
193
    if (source->vect)
194
        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
118 195

  
119
        if (source->enable_count == source->enable_max) {
120
#ifdef DEBUG_INTC
121
            printf("sh_intc: enabling interrupt source %d -> 0x%04x\n",
122
		   id, source->vect);
123
#endif
124
	}
125

  
126
        if (old == source->enable_max) {
127
#ifdef DEBUG_INTC
128
            printf("sh_intc: disabling interrupt source %d -> 0x%04x\n",
129
		   id, source->vect);
130
#endif
131
	}
132
    }
133 196
#ifdef DEBUG_INTC
134 197
    else {
135 198
        printf("setting interrupt group %d to %d\n", id, !!enable);
......
137 200
#endif
138 201

  
139 202
    if ((is_group || !source->vect) && source->next_enum_id) {
140
        sh_intc_toggle(desc, source->next_enum_id, enable, 1);
203
        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
141 204
    }
142 205

  
143 206
#ifdef DEBUG_INTC
......
200 263
	printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
201 264
	       k, first, enum_ids[k], (unsigned int)mask);
202 265
#endif
203
        sh_intc_toggle(desc, enum_ids[k], value & mask, 0);
266
        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
204 267
    }
205 268

  
206 269
    *valuep = value;
......
309 372
	if (s)
310 373
	    s->vect = vect->vect;
311 374

  
312
#ifdef DEBUG_INTC
375
#ifdef DEBUG_INTC_SOURCES
313 376
	printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
314 377
	       vect->enum_id, s->vect, s->enable_count, s->enable_max);
315 378
#endif
......
330 393
		s->next_enum_id = gr->enum_ids[k];
331 394
	    }
332 395

  
333
#ifdef DEBUG_INTC
396
#ifdef DEBUG_INTC_SOURCES
334 397
	    printf("sh_intc: registered group %d (%d/%d)\n",
335 398
		   gr->enum_id, s->enable_count, s->enable_max);
336 399
#endif
......
347 410
{
348 411
    unsigned int i;
349 412

  
413
    desc->pending = 0;
350 414
    desc->nr_sources = nr_sources;
351 415
    desc->mask_regs = mask_regs;
352 416
    desc->nr_mask_regs = nr_mask_regs;
......
359 423
        return -1;
360 424

  
361 425
    memset(desc->sources, 0, i);
426
    for (i = 0; i < desc->nr_sources; i++) {
427
        struct intc_source *source = desc->sources + i;
428

  
429
        source->parent = desc;
430
    }
362 431
 
363 432
    desc->iomemtype = cpu_register_io_memory(0, sh_intc_readfn,
364 433
					     sh_intc_writefn, desc);

Also available in: Unified diff