Revision e96e2044

b/cpu-exec.c
511 511
                        BREAK_CHAIN;
512 512
                    }
513 513
#elif defined(TARGET_SH4)
514
		    /* XXXXX */
514
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
515
                        do_interrupt(env);
516
                        BREAK_CHAIN;
517
                    }
515 518
#elif defined(TARGET_ALPHA)
516 519
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
517 520
                        do_interrupt(env);
b/hw/sh7750.c
551 551
			     _INTC_ARRAY(vectors),
552 552
			     _INTC_ARRAY(groups));
553 553

  
554
    cpu->intc_handle = &s->intc;
555

  
554 556
    sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]);
555 557
    sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF,
556 558
		   s->periph_freq, serial_hds[1]);
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);
b/hw/sh_intc.h
35 35
    unsigned short vect;
36 36
    intc_enum next_enum_id;
37 37

  
38
    int asserted;
38
    int asserted; /* emulates the interrupt signal line from device to intc */
39 39
    int enable_count;
40 40
    int enable_max;
41
    int pending; /* emulates the result of signal and masking */
42
    struct intc_desc *parent;
41 43
};
42 44

  
43 45
struct intc_desc {
......
49 51
    int nr_prio_regs;
50 52

  
51 53
    int iomemtype;
54
    int pending; /* number of interrupt sources that has pending set */
52 55
};
53 56

  
57
int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
54 58
struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
59
void sh_intc_toggle_source(struct intc_source *source,
60
			   int enable_adj, int assert_adj);
55 61

  
56 62
void sh_intc_register_sources(struct intc_desc *desc,
57 63
			      struct intc_vect *vectors,
b/target-sh4/cpu.h
121 121
    int exception_index;
122 122
     CPU_COMMON tlb_t utlb[UTLB_SIZE];	/* unified translation table */
123 123
    tlb_t itlb[ITLB_SIZE];	/* instruction translation table */
124
    void *intc_handle;
124 125
} CPUSH4State;
125 126

  
126 127
CPUSH4State *cpu_sh4_init(const char *cpu_model);
b/target-sh4/helper.c
27 27

  
28 28
#include "cpu.h"
29 29
#include "exec-all.h"
30
#include "hw/sh_intc.h"
30 31

  
31 32
#if defined(CONFIG_USER_ONLY)
32 33

  
......
74 75

  
75 76
void do_interrupt(CPUState * env)
76 77
{
78
    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
79
    int do_exp, irq_vector = env->exception_index;
80

  
81
    /* prioritize exceptions over interrupts */
82

  
83
    do_exp = env->exception_index != -1;
84
    do_irq = do_irq && (env->exception_index == -1);
85

  
86
    if (env->sr & SR_BL) {
87
        if (do_exp && env->exception_index != 0x1e0) {
88
            env->exception_index = 0x000; /* masked exception -> reset */
89
        }
90
        if (do_irq) {
91
            return; /* masked */
92
        }
93
    }
94

  
95
    if (do_irq) {
96
        irq_vector = sh_intc_get_pending_vector(env->intc_handle,
97
						(env->sr >> 4) & 0xf);
98
        if (irq_vector == -1) {
99
            return; /* masked */
100
	}
101
    }
102

  
77 103
    if (loglevel & CPU_LOG_INT) {
78 104
	const char *expname;
79 105
	switch (env->exception_index) {
......
117 143
	    expname = "trapa";
118 144
	    break;
119 145
	default:
120
	    expname = "???";
121
	    break;
146
            expname = do_irq ? "interrupt" : "???";
147
            break;
122 148
	}
123 149
	fprintf(logfile, "exception 0x%03x [%s] raised\n",
124
		env->exception_index, expname);
150
		irq_vector, expname);
125 151
	cpu_dump_state(env, logfile, fprintf, 0);
126 152
    }
127 153

  
128 154
    env->ssr = env->sr;
129
    env->spc = env->spc;
155
    env->spc = env->pc;
130 156
    env->sgr = env->gregs[15];
131 157
    env->sr |= SR_BL | SR_MD | SR_RB;
132 158

  
133
    env->expevt = env->exception_index & 0x7ff;
134
    switch (env->exception_index) {
135
    case 0x040:
136
    case 0x060:
137
    case 0x080:
138
	env->pc = env->vbr + 0x400;
139
	break;
140
    case 0x140:
141
	env->pc = 0xa0000000;
142
	break;
143
    default:
144
	env->pc = env->vbr + 0x100;
145
	break;
159
    if (do_exp) {
160
        env->expevt = env->exception_index;
161
        switch (env->exception_index) {
162
        case 0x000:
163
        case 0x020:
164
        case 0x140:
165
            env->sr &= ~SR_FD;
166
            env->sr |= 0xf << 4; /* IMASK */
167
            env->pc = 0xa0000000;
168
            break;
169
        case 0x040:
170
        case 0x060:
171
            env->pc = env->vbr + 0x400;
172
            break;
173
        case 0x160:
174
            env->spc += 2; /* special case for TRAPA */
175
            /* fall through */
176
        default:
177
            env->pc = env->vbr + 0x100;
178
            break;
179
        }
180
        return;
181
    }
182

  
183
    if (do_irq) {
184
        env->intevt = irq_vector;
185
        env->pc = env->vbr + 0x600;
186
        return;
146 187
    }
147 188
}
148 189

  
b/target-sh4/op.c
419 419

  
420 420
void OPPROTO op_trapa(void)
421 421
{
422
    env->tra = PARAM1 * 2;
422
    env->tra = PARAM1 << 2;
423 423
    env->exception_index = 0x160;
424 424
    do_raise_exception();
425 425
    RETURN();

Also available in: Unified diff