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