diff options
-rw-r--r-- | hw/cuda.c | 69 |
1 files changed, 47 insertions, 22 deletions
@@ -23,6 +23,8 @@ */ #include "vl.h" +/* XXX: implement all timer modes */ + //#define DEBUG_CUDA //#define DEBUG_CUDA_PACKET @@ -41,6 +43,7 @@ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ #define T1_INT 0x40 /* Timer 1 interrupt */ +#define T2_INT 0x20 /* Timer 2 interrupt */ /* Bits in ACR */ #define T1MODE 0xc0 /* Timer 1 mode */ @@ -91,7 +94,8 @@ #define RTC_OFFSET 2082844800 typedef struct CUDATimer { - unsigned int latch; + int index; + uint16_t latch; uint16_t counter_value; /* counter value at load time */ int64_t load_time; int64_t next_irq_time; @@ -154,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s) d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); - if (d <= s->counter_value) { - counter = d; + if (s->index == 0) { + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (s->counter_value + 1)) { + counter = (s->counter_value - d) & 0xffff; + } else { + counter = (d - (s->counter_value + 1)) % (s->latch + 2); + counter = (s->latch - counter) & 0xffff; + } } else { - counter = s->latch - 1 - ((d - s->counter_value) % s->latch); + counter = (s->counter_value - d) & 0xffff; } return counter; } @@ -175,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) { - int64_t d, next_time, base; + int64_t d, next_time; + unsigned int counter; + /* current counter value */ d = muldiv64(current_time - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); - if (d < s->counter_value) { - next_time = s->counter_value + 1; - } else - { - base = ((d - s->counter_value + 1) / s->latch); - base = (base * s->latch) + s->counter_value; - next_time = base + s->latch; + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (s->counter_value + 1)) { + counter = (s->counter_value - d) & 0xffff; + } else { + counter = (d - (s->counter_value + 1)) % (s->latch + 2); + counter = (s->latch - counter) & 0xffff; + } + + /* Note: we consider the irq is raised on 0 */ + if (counter == 0xffff) { + next_time = d + s->latch + 1; + } else if (counter == 0) { + next_time = d + s->latch + 2; + } else { + next_time = d + counter; } #if 0 #ifdef DEBUG_CUDA @@ -249,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) break; case 5: val = get_counter(&s->timers[0]) >> 8; - s->ifr &= ~T1_INT; cuda_update_irq(s); break; case 6: val = s->timers[0].latch & 0xff; break; case 7: + /* XXX: check this */ val = (s->timers[0].latch >> 8) & 0xff; break; case 8: val = get_counter(&s->timers[1]) & 0xff; + s->ifr &= ~T2_INT; break; case 9: val = get_counter(&s->timers[1]) >> 8; @@ -317,12 +338,13 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->dira = val; break; case 4: - val = val | (get_counter(&s->timers[0]) & 0xff00); - set_counter(s, &s->timers[0], val); + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 5: - val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); - set_counter(s, &s->timers[0], val); + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; + set_counter(s, &s->timers[0], s->timers[0].latch); break; case 6: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; @@ -330,15 +352,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 7: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 8: - val = val | (get_counter(&s->timers[1]) & 0xff00); + s->timers[1].latch = val; set_counter(s, &s->timers[1], val); break; case 9: - val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); - set_counter(s, &s->timers[1], val); + set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); break; case 10: s->sr = val; @@ -620,10 +642,13 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) s->irq_opaque = irq_opaque; s->irq = irq; + s->timers[0].index = 0; s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); - s->timers[0].latch = 0x10000; + s->timers[0].latch = 0xffff; set_counter(s, &s->timers[0], 0xffff); - s->timers[1].latch = 0x10000; + + s->timers[1].index = 1; + s->timers[1].latch = 0; // s->ier = T1_INT | SR_INT; s->ier = 0; set_counter(s, &s->timers[1], 0xffff); |