Revision 61271e5c hw/cuda.c
b/hw/cuda.c | ||
---|---|---|
23 | 23 |
*/ |
24 | 24 |
#include "vl.h" |
25 | 25 |
|
26 |
/* XXX: implement all timer modes */ |
|
27 |
|
|
26 | 28 |
//#define DEBUG_CUDA |
27 | 29 |
//#define DEBUG_CUDA_PACKET |
28 | 30 |
|
... | ... | |
41 | 43 |
#define IER_CLR 0 /* clear bits in IER */ |
42 | 44 |
#define SR_INT 0x04 /* Shift register full/empty */ |
43 | 45 |
#define T1_INT 0x40 /* Timer 1 interrupt */ |
46 |
#define T2_INT 0x20 /* Timer 2 interrupt */ |
|
44 | 47 |
|
45 | 48 |
/* Bits in ACR */ |
46 | 49 |
#define T1MODE 0xc0 /* Timer 1 mode */ |
... | ... | |
91 | 94 |
#define RTC_OFFSET 2082844800 |
92 | 95 |
|
93 | 96 |
typedef struct CUDATimer { |
94 |
unsigned int latch; |
|
97 |
int index; |
|
98 |
uint16_t latch; |
|
95 | 99 |
uint16_t counter_value; /* counter value at load time */ |
96 | 100 |
int64_t load_time; |
97 | 101 |
int64_t next_irq_time; |
... | ... | |
154 | 158 |
|
155 | 159 |
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, |
156 | 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 | 169 |
} else { |
160 |
counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
|
|
170 |
counter = (s->counter_value - d) & 0xffff;
|
|
161 | 171 |
} |
162 | 172 |
return counter; |
163 | 173 |
} |
... | ... | |
175 | 185 |
|
176 | 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 | 191 |
/* current counter value */ |
180 | 192 |
d = muldiv64(current_time - s->load_time, |
181 | 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 | 210 |
#if 0 |
191 | 211 |
#ifdef DEBUG_CUDA |
... | ... | |
249 | 269 |
break; |
250 | 270 |
case 5: |
251 | 271 |
val = get_counter(&s->timers[0]) >> 8; |
252 |
s->ifr &= ~T1_INT; |
|
253 | 272 |
cuda_update_irq(s); |
254 | 273 |
break; |
255 | 274 |
case 6: |
256 | 275 |
val = s->timers[0].latch & 0xff; |
257 | 276 |
break; |
258 | 277 |
case 7: |
278 |
/* XXX: check this */ |
|
259 | 279 |
val = (s->timers[0].latch >> 8) & 0xff; |
260 | 280 |
break; |
261 | 281 |
case 8: |
262 | 282 |
val = get_counter(&s->timers[1]) & 0xff; |
283 |
s->ifr &= ~T2_INT; |
|
263 | 284 |
break; |
264 | 285 |
case 9: |
265 | 286 |
val = get_counter(&s->timers[1]) >> 8; |
... | ... | |
317 | 338 |
s->dira = val; |
318 | 339 |
break; |
319 | 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 | 343 |
break; |
323 | 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 | 348 |
break; |
327 | 349 |
case 6: |
328 | 350 |
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; |
... | ... | |
330 | 352 |
break; |
331 | 353 |
case 7: |
332 | 354 |
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); |
355 |
s->ifr &= ~T1_INT; |
|
333 | 356 |
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); |
334 | 357 |
break; |
335 | 358 |
case 8: |
336 |
val = val | (get_counter(&s->timers[1]) & 0xff00);
|
|
359 |
s->timers[1].latch = val;
|
|
337 | 360 |
set_counter(s, &s->timers[1], val); |
338 | 361 |
break; |
339 | 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 | 364 |
break; |
343 | 365 |
case 10: |
344 | 366 |
s->sr = val; |
... | ... | |
620 | 642 |
s->irq_opaque = irq_opaque; |
621 | 643 |
s->irq = irq; |
622 | 644 |
|
645 |
s->timers[0].index = 0; |
|
623 | 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 | 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 | 652 |
// s->ier = T1_INT | SR_INT; |
628 | 653 |
s->ier = 0; |
629 | 654 |
set_counter(s, &s->timers[1], 0xffff); |
Also available in: Unified diff