Revision 5ef98b47
b/hw/etraxfs.c | ||
---|---|---|
30 | 30 |
#include "devices.h" |
31 | 31 |
#include "boards.h" |
32 | 32 |
|
33 |
#include "etraxfs_dma.h" |
|
34 |
|
|
35 |
/* Init functions for different blocks. */ |
|
36 |
extern qemu_irq *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); |
|
37 |
void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, |
|
38 |
target_phys_addr_t base); |
|
39 |
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
|
40 |
qemu_irq *irq, target_phys_addr_t base); |
|
41 |
void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, |
|
42 |
target_phys_addr_t base); |
|
33 |
#include "etraxfs.h" |
|
43 | 34 |
|
44 | 35 |
#define FLASH_SIZE 0x2000000 |
45 | 36 |
#define INTMEM_SIZE (128 * 1024) |
... | ... | |
62 | 53 |
const char *initrd_filename, const char *cpu_model) |
63 | 54 |
{ |
64 | 55 |
CPUState *env; |
65 |
qemu_irq *pic;
|
|
56 |
struct etraxfs_pic *pic;
|
|
66 | 57 |
void *etraxfs_dmac; |
67 | 58 |
struct etraxfs_dma_client *eth[2] = {NULL, NULL}; |
68 | 59 |
int kernel_size; |
... | ... | |
110 | 101 |
etraxfs_dmac = etraxfs_dmac_init(env, 0xb0000000, 10); |
111 | 102 |
for (i = 0; i < 10; i++) { |
112 | 103 |
/* On ETRAX, odd numbered channels are inputs. */ |
113 |
etraxfs_dmac_connect(etraxfs_dmac, i, pic + 7 + i, i & 1); |
|
104 |
etraxfs_dmac_connect(etraxfs_dmac, i, pic->irq + 7 + i, i & 1);
|
|
114 | 105 |
} |
115 | 106 |
|
116 | 107 |
/* Add the two ethernet blocks. */ |
117 |
eth[0] = etraxfs_eth_init(&nd_table[0], env, pic + 25, 0xb0034000); |
|
108 |
eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0xb0034000);
|
|
118 | 109 |
if (nb_nics > 1) |
119 |
eth[1] = etraxfs_eth_init(&nd_table[1], env, pic + 26, 0xb0036000); |
|
110 |
eth[1] = etraxfs_eth_init(&nd_table[1], env, pic->irq + 26, 0xb0036000);
|
|
120 | 111 |
|
121 | 112 |
/* The DMA Connector block is missing, hardwire things for now. */ |
122 | 113 |
etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); |
... | ... | |
127 | 118 |
} |
128 | 119 |
|
129 | 120 |
/* 2 timers. */ |
130 |
etraxfs_timer_init(env, pic + 0x1b, 0xb001e000);
|
|
131 |
etraxfs_timer_init(env, pic + 0x1b, 0xb005e000);
|
|
121 |
etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0xb001e000);
|
|
122 |
etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0xb005e000);
|
|
132 | 123 |
|
133 | 124 |
for (i = 0; i < 4; i++) { |
134 | 125 |
if (serial_hds[i]) { |
135 |
etraxfs_ser_init(env, pic + 0x14 + i, |
|
126 |
etraxfs_ser_init(env, pic->irq + 0x14 + i,
|
|
136 | 127 |
serial_hds[i], 0xb0026000 + i * 0x2000); |
137 | 128 |
} |
138 | 129 |
} |
b/hw/etraxfs.h | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU ETRAX System Emulator |
|
3 |
* |
|
4 |
* Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "etraxfs_dma.h" |
|
26 |
|
|
27 |
struct etraxfs_pic |
|
28 |
{ |
|
29 |
qemu_irq *irq; |
|
30 |
qemu_irq *nmi; |
|
31 |
qemu_irq *guru; |
|
32 |
|
|
33 |
void *internal; |
|
34 |
}; |
|
35 |
|
|
36 |
struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); |
|
37 |
void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi, |
|
38 |
target_phys_addr_t base); |
|
39 |
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
|
40 |
qemu_irq *irq, target_phys_addr_t base); |
|
41 |
void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, |
|
42 |
target_phys_addr_t base); |
b/hw/etraxfs_pic.c | ||
---|---|---|
24 | 24 |
|
25 | 25 |
#include <stdio.h> |
26 | 26 |
#include "hw.h" |
27 |
#include "etraxfs.h" |
|
27 | 28 |
|
28 | 29 |
#define D(x) |
29 | 30 |
|
... | ... | |
143 | 144 |
{ |
144 | 145 |
} |
145 | 146 |
|
146 |
static void etraxfs_pic_handler(void *opaque, int irq, int level)
|
|
147 |
static void irq_handler(void *opaque, int irq, int level)
|
|
147 | 148 |
{ |
148 | 149 |
struct fs_pic_state_t *fs = (void *)opaque; |
149 | 150 |
CPUState *env = fs->env; |
... | ... | |
187 | 188 |
} |
188 | 189 |
} |
189 | 190 |
|
190 |
qemu_irq *etraxfs_pic_init(CPUState *env, target_phys_addr_t base) |
|
191 |
static void nmi_handler(void *opaque, int irq, int level) |
|
192 |
{ |
|
193 |
struct fs_pic_state_t *fs = (void *)opaque; |
|
194 |
CPUState *env = fs->env; |
|
195 |
uint32_t mask; |
|
196 |
|
|
197 |
mask = 1 << irq; |
|
198 |
if (level) |
|
199 |
fs->r_nmi |= mask; |
|
200 |
else |
|
201 |
fs->r_nmi &= ~mask; |
|
202 |
|
|
203 |
if (fs->r_nmi) |
|
204 |
cpu_interrupt(env, CPU_INTERRUPT_NMI); |
|
205 |
else |
|
206 |
cpu_reset_interrupt(env, CPU_INTERRUPT_NMI); |
|
207 |
} |
|
208 |
|
|
209 |
static void guru_handler(void *opaque, int irq, int level) |
|
210 |
{ |
|
211 |
struct fs_pic_state_t *fs = (void *)opaque; |
|
212 |
CPUState *env = fs->env; |
|
213 |
cpu_abort(env, "%s unsupported exception\n", __func__); |
|
214 |
|
|
215 |
} |
|
216 |
|
|
217 |
|
|
218 |
struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base) |
|
191 | 219 |
{ |
192 |
struct fs_pic_state_t *fs; |
|
193 |
qemu_irq *pic;
|
|
220 |
struct fs_pic_state_t *fs = NULL;
|
|
221 |
struct etraxfs_pic *pic = NULL;
|
|
194 | 222 |
int intr_vect_regs; |
195 | 223 |
|
196 |
fs = qemu_mallocz(sizeof *fs);
|
|
197 |
if (!fs)
|
|
198 |
return NULL;
|
|
199 |
fs->env = env;
|
|
224 |
pic = qemu_mallocz(sizeof *pic);
|
|
225 |
pic->internal = fs = qemu_mallocz(sizeof *fs);
|
|
226 |
if (!fs || !pic)
|
|
227 |
goto err;
|
|
200 | 228 |
|
201 |
pic = qemu_allocate_irqs(etraxfs_pic_handler, fs, 30); |
|
229 |
fs->env = env; |
|
230 |
pic->irq = qemu_allocate_irqs(irq_handler, fs, 30); |
|
231 |
pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2); |
|
232 |
pic->guru = qemu_allocate_irqs(guru_handler, fs, 1); |
|
202 | 233 |
|
203 | 234 |
intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs); |
204 | 235 |
cpu_register_physical_memory(base, 0x14, intr_vect_regs); |
205 | 236 |
fs->base = base; |
206 | 237 |
|
207 | 238 |
return pic; |
239 |
err: |
|
240 |
free(pic); |
|
241 |
free(fs); |
|
242 |
return NULL; |
|
208 | 243 |
} |
b/hw/etraxfs_timer.c | ||
---|---|---|
46 | 46 |
struct fs_timer_t { |
47 | 47 |
CPUState *env; |
48 | 48 |
qemu_irq *irq; |
49 |
qemu_irq *nmi; |
|
49 | 50 |
target_phys_addr_t base; |
50 | 51 |
|
51 | 52 |
QEMUBH *bh_t0; |
... | ... | |
56 | 57 |
ptimer_state *ptimer_wd; |
57 | 58 |
struct timeval last; |
58 | 59 |
|
60 |
int wd_hits; |
|
61 |
|
|
59 | 62 |
/* Control registers. */ |
60 | 63 |
uint32_t rw_tmr0_div; |
61 | 64 |
uint32_t r_tmr0_data; |
... | ... | |
129 | 132 |
unsigned int freq_hz; |
130 | 133 |
unsigned int div; |
131 | 134 |
uint32_t ctrl; |
135 |
|
|
132 | 136 |
ptimer_state *timer; |
133 | 137 |
|
134 | 138 |
if (tnum == 0) { |
... | ... | |
163 | 167 |
|
164 | 168 |
D(printf ("freq_hz=%d div=%d\n", freq_hz, div)); |
165 | 169 |
div = div * TIMER_SLOWDOWN; |
166 |
div >>= 15;
|
|
167 |
freq_hz >>= 15;
|
|
170 |
div >>= 10;
|
|
171 |
freq_hz >>= 10;
|
|
168 | 172 |
ptimer_set_freq(timer, freq_hz); |
169 | 173 |
ptimer_set_limit(timer, div, 0); |
170 | 174 |
|
... | ... | |
216 | 220 |
|
217 | 221 |
static void watchdog_hit(void *opaque) |
218 | 222 |
{ |
219 |
qemu_system_reset_request(); |
|
223 |
struct fs_timer_t *t = opaque; |
|
224 |
if (t->wd_hits == 0) { |
|
225 |
/* real hw gives a single tick before reseting but we are |
|
226 |
a bit friendlier to compensate for our slower execution. */ |
|
227 |
ptimer_set_count(t->ptimer_wd, 10); |
|
228 |
ptimer_run(t->ptimer_wd, 1); |
|
229 |
qemu_irq_raise(t->nmi[0]); |
|
230 |
} |
|
231 |
else |
|
232 |
qemu_system_reset_request(); |
|
233 |
|
|
234 |
t->wd_hits++; |
|
220 | 235 |
} |
221 | 236 |
|
222 | 237 |
static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value) |
... | ... | |
237 | 252 |
D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", |
238 | 253 |
wd_en, new_key, wd_key, new_cmd, wd_cnt)); |
239 | 254 |
|
255 |
if (t->wd_hits) |
|
256 |
qemu_irq_lower(t->nmi[0]); |
|
257 |
|
|
258 |
t->wd_hits = 0; |
|
259 |
|
|
240 | 260 |
ptimer_set_freq(t->ptimer_wd, 760); |
241 | 261 |
if (wd_cnt == 0) |
242 | 262 |
wd_cnt = 256; |
... | ... | |
320 | 340 |
qemu_irq_lower(t->irq[0]); |
321 | 341 |
} |
322 | 342 |
|
323 |
void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, |
|
343 |
void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi,
|
|
324 | 344 |
target_phys_addr_t base) |
325 | 345 |
{ |
326 | 346 |
static struct fs_timer_t *t; |
... | ... | |
337 | 357 |
t->ptimer_t1 = ptimer_init(t->bh_t1); |
338 | 358 |
t->ptimer_wd = ptimer_init(t->bh_wd); |
339 | 359 |
t->irq = irqs; |
360 |
t->nmi = nmi; |
|
340 | 361 |
t->env = env; |
341 | 362 |
t->base = base; |
342 | 363 |
|
Also available in: Unified diff