Commit 61271e5c2d3eff4cc0c4845be291172c2015b6f1
1 parent
aefce9af
more precise cuda timers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1508 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
47 additions
and
22 deletions
hw/cuda.c
| @@ -23,6 +23,8 @@ | @@ -23,6 +23,8 @@ | ||
| 23 | */ | 23 | */ |
| 24 | #include "vl.h" | 24 | #include "vl.h" |
| 25 | 25 | ||
| 26 | +/* XXX: implement all timer modes */ | ||
| 27 | + | ||
| 26 | //#define DEBUG_CUDA | 28 | //#define DEBUG_CUDA |
| 27 | //#define DEBUG_CUDA_PACKET | 29 | //#define DEBUG_CUDA_PACKET |
| 28 | 30 | ||
| @@ -41,6 +43,7 @@ | @@ -41,6 +43,7 @@ | ||
| 41 | #define IER_CLR 0 /* clear bits in IER */ | 43 | #define IER_CLR 0 /* clear bits in IER */ |
| 42 | #define SR_INT 0x04 /* Shift register full/empty */ | 44 | #define SR_INT 0x04 /* Shift register full/empty */ |
| 43 | #define T1_INT 0x40 /* Timer 1 interrupt */ | 45 | #define T1_INT 0x40 /* Timer 1 interrupt */ |
| 46 | +#define T2_INT 0x20 /* Timer 2 interrupt */ | ||
| 44 | 47 | ||
| 45 | /* Bits in ACR */ | 48 | /* Bits in ACR */ |
| 46 | #define T1MODE 0xc0 /* Timer 1 mode */ | 49 | #define T1MODE 0xc0 /* Timer 1 mode */ |
| @@ -91,7 +94,8 @@ | @@ -91,7 +94,8 @@ | ||
| 91 | #define RTC_OFFSET 2082844800 | 94 | #define RTC_OFFSET 2082844800 |
| 92 | 95 | ||
| 93 | typedef struct CUDATimer { | 96 | typedef struct CUDATimer { |
| 94 | - unsigned int latch; | 97 | + int index; |
| 98 | + uint16_t latch; | ||
| 95 | uint16_t counter_value; /* counter value at load time */ | 99 | uint16_t counter_value; /* counter value at load time */ |
| 96 | int64_t load_time; | 100 | int64_t load_time; |
| 97 | int64_t next_irq_time; | 101 | int64_t next_irq_time; |
| @@ -154,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s) | @@ -154,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s) | ||
| 154 | 158 | ||
| 155 | d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, | 159 | d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, |
| 156 | CUDA_TIMER_FREQ, ticks_per_sec); | 160 | CUDA_TIMER_FREQ, ticks_per_sec); |
| 157 | - if (d <= s->counter_value) { | ||
| 158 | - counter = d; | 161 | + if (s->index == 0) { |
| 162 | + /* the timer goes down from latch to -1 (period of latch + 2) */ | ||
| 163 | + if (d <= (s->counter_value + 1)) { | ||
| 164 | + counter = (s->counter_value - d) & 0xffff; | ||
| 165 | + } else { | ||
| 166 | + counter = (d - (s->counter_value + 1)) % (s->latch + 2); | ||
| 167 | + counter = (s->latch - counter) & 0xffff; | ||
| 168 | + } | ||
| 159 | } else { | 169 | } else { |
| 160 | - counter = s->latch - 1 - ((d - s->counter_value) % s->latch); | 170 | + counter = (s->counter_value - d) & 0xffff; |
| 161 | } | 171 | } |
| 162 | return counter; | 172 | return counter; |
| 163 | } | 173 | } |
| @@ -175,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) | @@ -175,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) | ||
| 175 | 185 | ||
| 176 | static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) | 186 | static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) |
| 177 | { | 187 | { |
| 178 | - int64_t d, next_time, base; | 188 | + int64_t d, next_time; |
| 189 | + unsigned int counter; | ||
| 190 | + | ||
| 179 | /* current counter value */ | 191 | /* current counter value */ |
| 180 | d = muldiv64(current_time - s->load_time, | 192 | d = muldiv64(current_time - s->load_time, |
| 181 | CUDA_TIMER_FREQ, ticks_per_sec); | 193 | CUDA_TIMER_FREQ, ticks_per_sec); |
| 182 | - if (d < s->counter_value) { | ||
| 183 | - next_time = s->counter_value + 1; | ||
| 184 | - } else | ||
| 185 | - { | ||
| 186 | - base = ((d - s->counter_value + 1) / s->latch); | ||
| 187 | - base = (base * s->latch) + s->counter_value; | ||
| 188 | - next_time = base + s->latch; | 194 | + /* the timer goes down from latch to -1 (period of latch + 2) */ |
| 195 | + if (d <= (s->counter_value + 1)) { | ||
| 196 | + counter = (s->counter_value - d) & 0xffff; | ||
| 197 | + } else { | ||
| 198 | + counter = (d - (s->counter_value + 1)) % (s->latch + 2); | ||
| 199 | + counter = (s->latch - counter) & 0xffff; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + /* Note: we consider the irq is raised on 0 */ | ||
| 203 | + if (counter == 0xffff) { | ||
| 204 | + next_time = d + s->latch + 1; | ||
| 205 | + } else if (counter == 0) { | ||
| 206 | + next_time = d + s->latch + 2; | ||
| 207 | + } else { | ||
| 208 | + next_time = d + counter; | ||
| 189 | } | 209 | } |
| 190 | #if 0 | 210 | #if 0 |
| 191 | #ifdef DEBUG_CUDA | 211 | #ifdef DEBUG_CUDA |
| @@ -249,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) | @@ -249,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) | ||
| 249 | break; | 269 | break; |
| 250 | case 5: | 270 | case 5: |
| 251 | val = get_counter(&s->timers[0]) >> 8; | 271 | val = get_counter(&s->timers[0]) >> 8; |
| 252 | - s->ifr &= ~T1_INT; | ||
| 253 | cuda_update_irq(s); | 272 | cuda_update_irq(s); |
| 254 | break; | 273 | break; |
| 255 | case 6: | 274 | case 6: |
| 256 | val = s->timers[0].latch & 0xff; | 275 | val = s->timers[0].latch & 0xff; |
| 257 | break; | 276 | break; |
| 258 | case 7: | 277 | case 7: |
| 278 | + /* XXX: check this */ | ||
| 259 | val = (s->timers[0].latch >> 8) & 0xff; | 279 | val = (s->timers[0].latch >> 8) & 0xff; |
| 260 | break; | 280 | break; |
| 261 | case 8: | 281 | case 8: |
| 262 | val = get_counter(&s->timers[1]) & 0xff; | 282 | val = get_counter(&s->timers[1]) & 0xff; |
| 283 | + s->ifr &= ~T2_INT; | ||
| 263 | break; | 284 | break; |
| 264 | case 9: | 285 | case 9: |
| 265 | val = get_counter(&s->timers[1]) >> 8; | 286 | 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) | @@ -317,12 +338,13 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
| 317 | s->dira = val; | 338 | s->dira = val; |
| 318 | break; | 339 | break; |
| 319 | case 4: | 340 | case 4: |
| 320 | - val = val | (get_counter(&s->timers[0]) & 0xff00); | ||
| 321 | - set_counter(s, &s->timers[0], val); | 341 | + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; |
| 342 | + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); | ||
| 322 | break; | 343 | break; |
| 323 | case 5: | 344 | case 5: |
| 324 | - val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); | ||
| 325 | - set_counter(s, &s->timers[0], val); | 345 | + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); |
| 346 | + s->ifr &= ~T1_INT; | ||
| 347 | + set_counter(s, &s->timers[0], s->timers[0].latch); | ||
| 326 | break; | 348 | break; |
| 327 | case 6: | 349 | case 6: |
| 328 | s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; | 350 | 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) | @@ -330,15 +352,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
| 330 | break; | 352 | break; |
| 331 | case 7: | 353 | case 7: |
| 332 | s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); | 354 | s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); |
| 355 | + s->ifr &= ~T1_INT; | ||
| 333 | cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); | 356 | cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); |
| 334 | break; | 357 | break; |
| 335 | case 8: | 358 | case 8: |
| 336 | - val = val | (get_counter(&s->timers[1]) & 0xff00); | 359 | + s->timers[1].latch = val; |
| 337 | set_counter(s, &s->timers[1], val); | 360 | set_counter(s, &s->timers[1], val); |
| 338 | break; | 361 | break; |
| 339 | case 9: | 362 | case 9: |
| 340 | - val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); | ||
| 341 | - set_counter(s, &s->timers[1], val); | 363 | + set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); |
| 342 | break; | 364 | break; |
| 343 | case 10: | 365 | case 10: |
| 344 | s->sr = val; | 366 | s->sr = val; |
| @@ -620,10 +642,13 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) | @@ -620,10 +642,13 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) | ||
| 620 | s->irq_opaque = irq_opaque; | 642 | s->irq_opaque = irq_opaque; |
| 621 | s->irq = irq; | 643 | s->irq = irq; |
| 622 | 644 | ||
| 645 | + s->timers[0].index = 0; | ||
| 623 | s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); | 646 | s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); |
| 624 | - s->timers[0].latch = 0x10000; | 647 | + s->timers[0].latch = 0xffff; |
| 625 | set_counter(s, &s->timers[0], 0xffff); | 648 | set_counter(s, &s->timers[0], 0xffff); |
| 626 | - s->timers[1].latch = 0x10000; | 649 | + |
| 650 | + s->timers[1].index = 1; | ||
| 651 | + s->timers[1].latch = 0; | ||
| 627 | // s->ier = T1_INT | SR_INT; | 652 | // s->ier = T1_INT | SR_INT; |
| 628 | s->ier = 0; | 653 | s->ier = 0; |
| 629 | set_counter(s, &s->timers[1], 0xffff); | 654 | set_counter(s, &s->timers[1], 0xffff); |