Revision 979d98ca
b/hw/etraxfs_pic.c | ||
---|---|---|
29 | 29 |
|
30 | 30 |
#define D(x) |
31 | 31 |
|
32 |
#define R_RW_MASK 0
|
|
33 |
#define R_R_VECT 1
|
|
34 |
#define R_R_MASKED_VECT 2
|
|
35 |
#define R_R_NMI 3
|
|
36 |
#define R_R_GURU 4
|
|
37 |
#define R_MAX 5
|
|
32 |
#define R_RW_MASK 0
|
|
33 |
#define R_R_VECT 1
|
|
34 |
#define R_R_MASKED_VECT 2
|
|
35 |
#define R_R_NMI 3
|
|
36 |
#define R_R_GURU 4
|
|
37 |
#define R_MAX 5
|
|
38 | 38 |
|
39 | 39 |
struct fs_pic_state |
40 | 40 |
{ |
41 |
CPUState *env;
|
|
42 |
uint32_t regs[R_MAX];
|
|
41 |
CPUState *env;
|
|
42 |
uint32_t regs[R_MAX];
|
|
43 | 43 |
}; |
44 | 44 |
|
45 | 45 |
static void pic_update(struct fs_pic_state *fs) |
46 |
{
|
|
47 |
CPUState *env = fs->env;
|
|
48 |
uint32_t vector = 0;
|
|
49 |
int i;
|
|
50 |
|
|
51 |
fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
|
|
52 |
|
|
53 |
/* The ETRAX interrupt controller signals interrupts to teh core
|
|
54 |
through an interrupt request wire and an irq vector bus. If
|
|
55 |
multiple interrupts are simultaneously active it chooses vector
|
|
56 |
0x30 and lets the sw choose the priorities. */
|
|
57 |
if (fs->regs[R_R_MASKED_VECT]) {
|
|
58 |
uint32_t mv = fs->regs[R_R_MASKED_VECT];
|
|
59 |
for (i = 0; i < 31; i++) {
|
|
60 |
if (mv & 1) {
|
|
61 |
vector = 0x31 + i;
|
|
62 |
/* Check for multiple interrupts. */
|
|
63 |
if (mv > 1)
|
|
64 |
vector = 0x30;
|
|
65 |
break;
|
|
66 |
}
|
|
67 |
mv >>= 1;
|
|
68 |
}
|
|
69 |
if (vector) {
|
|
70 |
env->interrupt_vector = vector;
|
|
71 |
D(printf("%s vector=%x\n", __func__, vector));
|
|
72 |
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
|
73 |
}
|
|
74 |
} else {
|
|
75 |
env->interrupt_vector = 0;
|
|
76 |
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
|
77 |
D(printf("%s reset irqs\n", __func__));
|
|
78 |
}
|
|
46 |
{
|
|
47 |
CPUState *env = fs->env;
|
|
48 |
uint32_t vector = 0;
|
|
49 |
int i;
|
|
50 |
|
|
51 |
fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
|
|
52 |
|
|
53 |
/* The ETRAX interrupt controller signals interrupts to teh core
|
|
54 |
through an interrupt request wire and an irq vector bus. If
|
|
55 |
multiple interrupts are simultaneously active it chooses vector
|
|
56 |
0x30 and lets the sw choose the priorities. */
|
|
57 |
if (fs->regs[R_R_MASKED_VECT]) {
|
|
58 |
uint32_t mv = fs->regs[R_R_MASKED_VECT];
|
|
59 |
for (i = 0; i < 31; i++) {
|
|
60 |
if (mv & 1) {
|
|
61 |
vector = 0x31 + i;
|
|
62 |
/* Check for multiple interrupts. */
|
|
63 |
if (mv > 1)
|
|
64 |
vector = 0x30;
|
|
65 |
break;
|
|
66 |
}
|
|
67 |
mv >>= 1;
|
|
68 |
}
|
|
69 |
if (vector) {
|
|
70 |
env->interrupt_vector = vector;
|
|
71 |
D(printf("%s vector=%x\n", __func__, vector));
|
|
72 |
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
|
73 |
}
|
|
74 |
} else {
|
|
75 |
env->interrupt_vector = 0;
|
|
76 |
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
|
77 |
D(printf("%s reset irqs\n", __func__));
|
|
78 |
}
|
|
79 | 79 |
} |
80 | 80 |
|
81 | 81 |
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) |
82 | 82 |
{ |
83 |
struct fs_pic_state *fs = opaque;
|
|
84 |
uint32_t rval;
|
|
83 |
struct fs_pic_state *fs = opaque;
|
|
84 |
uint32_t rval;
|
|
85 | 85 |
|
86 |
rval = fs->regs[addr >> 2];
|
|
87 |
D(printf("%s %x=%x\n", __func__, addr, rval));
|
|
88 |
return rval;
|
|
86 |
rval = fs->regs[addr >> 2];
|
|
87 |
D(printf("%s %x=%x\n", __func__, addr, rval));
|
|
88 |
return rval;
|
|
89 | 89 |
} |
90 | 90 |
|
91 | 91 |
static void |
92 | 92 |
pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
93 | 93 |
{ |
94 |
struct fs_pic_state *fs = opaque;
|
|
95 |
D(printf("%s addr=%x val=%x\n", __func__, addr, value));
|
|
94 |
struct fs_pic_state *fs = opaque;
|
|
95 |
D(printf("%s addr=%x val=%x\n", __func__, addr, value));
|
|
96 | 96 |
|
97 |
if (addr == R_RW_MASK) {
|
|
98 |
fs->regs[R_RW_MASK] = value;
|
|
99 |
pic_update(fs);
|
|
100 |
}
|
|
97 |
if (addr == R_RW_MASK) {
|
|
98 |
fs->regs[R_RW_MASK] = value;
|
|
99 |
pic_update(fs);
|
|
100 |
}
|
|
101 | 101 |
} |
102 | 102 |
|
103 | 103 |
static CPUReadMemoryFunc *pic_read[] = { |
104 |
NULL, NULL,
|
|
105 |
&pic_readl,
|
|
104 |
NULL, NULL,
|
|
105 |
&pic_readl,
|
|
106 | 106 |
}; |
107 | 107 |
|
108 | 108 |
static CPUWriteMemoryFunc *pic_write[] = { |
109 |
NULL, NULL,
|
|
110 |
&pic_writel,
|
|
109 |
NULL, NULL,
|
|
110 |
&pic_writel,
|
|
111 | 111 |
}; |
112 | 112 |
|
113 | 113 |
void pic_info(Monitor *mon) |
... | ... | |
119 | 119 |
} |
120 | 120 |
|
121 | 121 |
static void nmi_handler(void *opaque, int irq, int level) |
122 |
{
|
|
123 |
struct fs_pic_state *fs = (void *)opaque;
|
|
124 |
CPUState *env = fs->env;
|
|
125 |
uint32_t mask;
|
|
126 |
|
|
127 |
mask = 1 << irq;
|
|
128 |
if (level)
|
|
129 |
fs->regs[R_R_NMI] |= mask;
|
|
130 |
else
|
|
131 |
fs->regs[R_R_NMI] &= ~mask;
|
|
132 |
|
|
133 |
if (fs->regs[R_R_NMI])
|
|
134 |
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
|
135 |
else
|
|
136 |
cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
|
|
122 |
{
|
|
123 |
struct fs_pic_state *fs = (void *)opaque;
|
|
124 |
CPUState *env = fs->env;
|
|
125 |
uint32_t mask;
|
|
126 |
|
|
127 |
mask = 1 << irq;
|
|
128 |
if (level)
|
|
129 |
fs->regs[R_R_NMI] |= mask;
|
|
130 |
else
|
|
131 |
fs->regs[R_R_NMI] &= ~mask;
|
|
132 |
|
|
133 |
if (fs->regs[R_R_NMI])
|
|
134 |
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
|
135 |
else
|
|
136 |
cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
|
|
137 | 137 |
} |
138 | 138 |
|
139 | 139 |
static void irq_handler(void *opaque, int irq, int level) |
140 |
{
|
|
141 |
struct fs_pic_state *fs = (void *)opaque;
|
|
140 |
{
|
|
141 |
struct fs_pic_state *fs = (void *)opaque;
|
|
142 | 142 |
|
143 |
if (irq >= 30)
|
|
144 |
return nmi_handler(opaque, irq, level);
|
|
143 |
if (irq >= 30)
|
|
144 |
return nmi_handler(opaque, irq, level);
|
|
145 | 145 |
|
146 |
irq -= 1;
|
|
147 |
fs->regs[R_R_VECT] &= ~(1 << irq);
|
|
148 |
fs->regs[R_R_VECT] |= (!!level << irq);
|
|
149 |
pic_update(fs);
|
|
146 |
irq -= 1;
|
|
147 |
fs->regs[R_R_VECT] &= ~(1 << irq);
|
|
148 |
fs->regs[R_R_VECT] |= (!!level << irq);
|
|
149 |
pic_update(fs);
|
|
150 | 150 |
} |
151 | 151 |
|
152 | 152 |
qemu_irq *etraxfs_pic_init(CPUState *env, target_phys_addr_t base) |
153 | 153 |
{ |
154 |
struct fs_pic_state *fs = NULL;
|
|
155 |
qemu_irq *irq;
|
|
156 |
int intr_vect_regs;
|
|
154 |
struct fs_pic_state *fs = NULL;
|
|
155 |
qemu_irq *irq;
|
|
156 |
int intr_vect_regs;
|
|
157 | 157 |
|
158 |
fs = qemu_mallocz(sizeof *fs);
|
|
159 |
fs->env = env;
|
|
160 |
irq = qemu_allocate_irqs(irq_handler, fs, 32);
|
|
158 |
fs = qemu_mallocz(sizeof *fs);
|
|
159 |
fs->env = env;
|
|
160 |
irq = qemu_allocate_irqs(irq_handler, fs, 32);
|
|
161 | 161 |
|
162 |
intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
|
|
163 |
cpu_register_physical_memory(base, R_MAX * 4, intr_vect_regs);
|
|
164 |
return irq;
|
|
162 |
intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
|
|
163 |
cpu_register_physical_memory(base, R_MAX * 4, intr_vect_regs);
|
|
164 |
return irq;
|
|
165 | 165 |
} |
Also available in: Unified diff