more precise cuda timers

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1508 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2005-07-07 21:45:18 +00:00
parent aefce9af41
commit 61271e5c2d

View File

@ -23,6 +23,8 @@
*/ */
#include "vl.h" #include "vl.h"
/* XXX: implement all timer modes */
//#define DEBUG_CUDA //#define DEBUG_CUDA
//#define DEBUG_CUDA_PACKET //#define DEBUG_CUDA_PACKET
@ -41,6 +43,7 @@
#define IER_CLR 0 /* clear bits in IER */ #define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */ #define SR_INT 0x04 /* Shift register full/empty */
#define T1_INT 0x40 /* Timer 1 interrupt */ #define T1_INT 0x40 /* Timer 1 interrupt */
#define T2_INT 0x20 /* Timer 2 interrupt */
/* Bits in ACR */ /* Bits in ACR */
#define T1MODE 0xc0 /* Timer 1 mode */ #define T1MODE 0xc0 /* Timer 1 mode */
@ -91,7 +94,8 @@
#define RTC_OFFSET 2082844800 #define RTC_OFFSET 2082844800
typedef struct CUDATimer { typedef struct CUDATimer {
unsigned int latch; int index;
uint16_t latch;
uint16_t counter_value; /* counter value at load time */ uint16_t counter_value; /* counter value at load time */
int64_t load_time; int64_t load_time;
int64_t next_irq_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, d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec); CUDA_TIMER_FREQ, ticks_per_sec);
if (d <= s->counter_value) { if (s->index == 0) {
counter = d; /* 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 { } else {
counter = s->latch - 1 - ((d - s->counter_value) % s->latch); counter = (s->counter_value - d) & 0xffff;
} }
return counter; 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) 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 */ /* current counter value */
d = muldiv64(current_time - s->load_time, d = muldiv64(current_time - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec); CUDA_TIMER_FREQ, ticks_per_sec);
if (d < s->counter_value) { /* the timer goes down from latch to -1 (period of latch + 2) */
next_time = s->counter_value + 1; if (d <= (s->counter_value + 1)) {
} else counter = (s->counter_value - d) & 0xffff;
{ } else {
base = ((d - s->counter_value + 1) / s->latch); counter = (d - (s->counter_value + 1)) % (s->latch + 2);
base = (base * s->latch) + s->counter_value; counter = (s->latch - counter) & 0xffff;
next_time = base + s->latch; }
/* 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 #if 0
#ifdef DEBUG_CUDA #ifdef DEBUG_CUDA
@ -249,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
break; break;
case 5: case 5:
val = get_counter(&s->timers[0]) >> 8; val = get_counter(&s->timers[0]) >> 8;
s->ifr &= ~T1_INT;
cuda_update_irq(s); cuda_update_irq(s);
break; break;
case 6: case 6:
val = s->timers[0].latch & 0xff; val = s->timers[0].latch & 0xff;
break; break;
case 7: case 7:
/* XXX: check this */
val = (s->timers[0].latch >> 8) & 0xff; val = (s->timers[0].latch >> 8) & 0xff;
break; break;
case 8: case 8:
val = get_counter(&s->timers[1]) & 0xff; val = get_counter(&s->timers[1]) & 0xff;
s->ifr &= ~T2_INT;
break; break;
case 9: case 9:
val = get_counter(&s->timers[1]) >> 8; 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; s->dira = val;
break; break;
case 4: case 4:
val = val | (get_counter(&s->timers[0]) & 0xff00); s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
set_counter(s, &s->timers[0], val); cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break; break;
case 5: case 5:
val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
set_counter(s, &s->timers[0], val); s->ifr &= ~T1_INT;
set_counter(s, &s->timers[0], s->timers[0].latch);
break; break;
case 6: case 6:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 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; break;
case 7: case 7:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 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)); cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break; break;
case 8: case 8:
val = val | (get_counter(&s->timers[1]) & 0xff00); s->timers[1].latch = val;
set_counter(s, &s->timers[1], val); set_counter(s, &s->timers[1], val);
break; break;
case 9: case 9:
val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
set_counter(s, &s->timers[1], val);
break; break;
case 10: case 10:
s->sr = val; 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_opaque = irq_opaque;
s->irq = irq; s->irq = irq;
s->timers[0].index = 0;
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); 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); 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 = T1_INT | SR_INT;
s->ier = 0; s->ier = 0;
set_counter(s, &s->timers[1], 0xffff); set_counter(s, &s->timers[1], 0xffff);