Commit 703243a044c8b7d5c52fdf67e4c1aacf1d6c4d76
1 parent
b7d35e65
Adds interrupt support to the sh specific timer code (Magnus Damm).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3812 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
33 additions
and
18 deletions
hw/sh.h
| ... | ... | @@ -2,6 +2,8 @@ |
| 2 | 2 | #define QEMU_SH_H |
| 3 | 3 | /* Definitions for SH board emulation. */ |
| 4 | 4 | |
| 5 | +#include "sh_intc.h" | |
| 6 | + | |
| 5 | 7 | /* sh7750.c */ |
| 6 | 8 | struct SH7750State; |
| 7 | 9 | |
| ... | ... | @@ -25,7 +27,10 @@ int sh7750_register_io_device(struct SH7750State *s, |
| 25 | 27 | #define TMU012_FEAT_TOCR (1 << 0) |
| 26 | 28 | #define TMU012_FEAT_3CHAN (1 << 1) |
| 27 | 29 | #define TMU012_FEAT_EXTCLK (1 << 2) |
| 28 | -void tmu012_init(uint32_t base, int feat, uint32_t freq); | |
| 30 | +void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, | |
| 31 | + struct intc_source *ch0_irq, struct intc_source *ch1_irq, | |
| 32 | + struct intc_source *ch2_irq0, struct intc_source *ch2_irq1); | |
| 33 | + | |
| 29 | 34 | |
| 30 | 35 | /* sh_serial.c */ |
| 31 | 36 | #define SH_SERIAL_FEAT_SCIF (1 << 0) | ... | ... |
hw/sh7750.c
| ... | ... | @@ -559,8 +559,11 @@ SH7750State *sh7750_init(CPUSH4State * cpu) |
| 559 | 559 | |
| 560 | 560 | tmu012_init(0x1fd80000, |
| 561 | 561 | TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, |
| 562 | - s->periph_freq); | |
| 563 | - | |
| 562 | + s->periph_freq, | |
| 563 | + sh_intc_source(&s->intc, TMU0), | |
| 564 | + sh_intc_source(&s->intc, TMU1), | |
| 565 | + sh_intc_source(&s->intc, TMU2_TUNI), | |
| 566 | + sh_intc_source(&s->intc, TMU2_TICPI)); | |
| 564 | 567 | |
| 565 | 568 | if (cpu_model & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { |
| 566 | 569 | sh_intc_register_sources(&s->intc, |
| ... | ... | @@ -578,7 +581,10 @@ SH7750State *sh7750_init(CPUSH4State * cpu) |
| 578 | 581 | sh_intc_register_sources(&s->intc, |
| 579 | 582 | _INTC_ARRAY(vectors_tmu34), |
| 580 | 583 | NULL, 0); |
| 581 | - tmu012_init(0x1e100000, 0, s->periph_freq); | |
| 584 | + tmu012_init(0x1e100000, 0, s->periph_freq, | |
| 585 | + sh_intc_source(&s->intc, TMU3), | |
| 586 | + sh_intc_source(&s->intc, TMU4), | |
| 587 | + NULL, NULL); | |
| 582 | 588 | } |
| 583 | 589 | |
| 584 | 590 | if (cpu_model & (SH_CPU_SH7751_ALL)) { | ... | ... |
hw/sh_timer.c
| ... | ... | @@ -33,23 +33,23 @@ typedef struct { |
| 33 | 33 | uint32_t tcpr; |
| 34 | 34 | int freq; |
| 35 | 35 | int int_level; |
| 36 | + int old_level; | |
| 36 | 37 | int feat; |
| 37 | 38 | int enabled; |
| 38 | - qemu_irq irq; | |
| 39 | + struct intc_source *irq; | |
| 39 | 40 | } sh_timer_state; |
| 40 | 41 | |
| 41 | 42 | /* Check all active timers, and schedule the next timer interrupt. */ |
| 42 | 43 | |
| 43 | 44 | static void sh_timer_update(sh_timer_state *s) |
| 44 | 45 | { |
| 45 | -#if 0 /* not yet */ | |
| 46 | - /* Update interrupts. */ | |
| 47 | - if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) { | |
| 48 | - qemu_irq_raise(s->irq); | |
| 49 | - } else { | |
| 50 | - qemu_irq_lower(s->irq); | |
| 51 | - } | |
| 52 | -#endif | |
| 46 | + int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE); | |
| 47 | + | |
| 48 | + if (new_level != s->old_level) | |
| 49 | + sh_intc_toggle_source(s->irq, 0, new_level ? 1 : -1); | |
| 50 | + | |
| 51 | + s->old_level = s->int_level; | |
| 52 | + s->int_level = new_level; | |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) |
| ... | ... | @@ -185,7 +185,7 @@ static void sh_timer_tick(void *opaque) |
| 185 | 185 | sh_timer_update(s); |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | -static void *sh_timer_init(uint32_t freq, int feat) | |
| 188 | +static void *sh_timer_init(uint32_t freq, int feat, struct intc_source *irq) | |
| 189 | 189 | { |
| 190 | 190 | sh_timer_state *s; |
| 191 | 191 | QEMUBH *bh; |
| ... | ... | @@ -198,6 +198,7 @@ static void *sh_timer_init(uint32_t freq, int feat) |
| 198 | 198 | s->tcpr = 0xdeadbeef; |
| 199 | 199 | s->tcor = 0; |
| 200 | 200 | s->enabled = 0; |
| 201 | + s->irq = irq; | |
| 201 | 202 | |
| 202 | 203 | bh = qemu_bh_new(sh_timer_tick, s); |
| 203 | 204 | s->timer = ptimer_init(bh); |
| ... | ... | @@ -305,7 +306,9 @@ static CPUWriteMemoryFunc *tmu012_writefn[] = { |
| 305 | 306 | tmu012_write |
| 306 | 307 | }; |
| 307 | 308 | |
| 308 | -void tmu012_init(uint32_t base, int feat, uint32_t freq) | |
| 309 | +void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, | |
| 310 | + struct intc_source *ch0_irq, struct intc_source *ch1_irq, | |
| 311 | + struct intc_source *ch2_irq0, struct intc_source *ch2_irq1) | |
| 309 | 312 | { |
| 310 | 313 | int iomemtype; |
| 311 | 314 | tmu012_state *s; |
| ... | ... | @@ -314,10 +317,11 @@ void tmu012_init(uint32_t base, int feat, uint32_t freq) |
| 314 | 317 | s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); |
| 315 | 318 | s->base = base; |
| 316 | 319 | s->feat = feat; |
| 317 | - s->timer[0] = sh_timer_init(freq, timer_feat); | |
| 318 | - s->timer[1] = sh_timer_init(freq, timer_feat); | |
| 320 | + s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq); | |
| 321 | + s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq); | |
| 319 | 322 | if (feat & TMU012_FEAT_3CHAN) |
| 320 | - s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT); | |
| 323 | + s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, | |
| 324 | + ch2_irq0); /* ch2_irq1 not supported */ | |
| 321 | 325 | iomemtype = cpu_register_io_memory(0, tmu012_readfn, |
| 322 | 326 | tmu012_writefn, s); |
| 323 | 327 | cpu_register_physical_memory(base, 0x00001000, iomemtype); | ... | ... |