Commit 819e712bfe40f0706689a98f9968f842e3aaccd1
1 parent
28b9b5af
cuda fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@950 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
138 additions
and
66 deletions
hw/adb.c
... | ... | @@ -63,8 +63,8 @@ void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len) |
63 | 63 | int devaddr, cmd, i; |
64 | 64 | uint8_t obuf[4]; |
65 | 65 | |
66 | - cmd = buf[1] & 0xf; | |
67 | - devaddr = buf[1] >> 4; | |
66 | + cmd = buf[0] & 0xf; | |
67 | + devaddr = buf[0] >> 4; | |
68 | 68 | if (buf[1] == ADB_BUSRESET) { |
69 | 69 | obuf[0] = 0x00; |
70 | 70 | obuf[1] = 0x00; | ... | ... |
hw/cuda.c
... | ... | @@ -23,6 +23,9 @@ |
23 | 23 | */ |
24 | 24 | #include "vl.h" |
25 | 25 | |
26 | +//#define DEBUG_CUDA | |
27 | +//#define DEBUG_CUDA_PACKET | |
28 | + | |
26 | 29 | /* Bits in B data register: all active low */ |
27 | 30 | #define TREQ 0x08 /* Transfer request (input) */ |
28 | 31 | #define TACK 0x10 /* Transfer acknowledge (output) */ |
... | ... | @@ -114,6 +117,7 @@ typedef struct CUDAState { |
114 | 117 | int data_out_index; |
115 | 118 | |
116 | 119 | int irq; |
120 | + openpic_t *openpic; | |
117 | 121 | uint8_t autopoll; |
118 | 122 | uint8_t data_in[128]; |
119 | 123 | uint8_t data_out[16]; |
... | ... | @@ -125,13 +129,15 @@ ADBBusState adb_bus; |
125 | 129 | static void cuda_update(CUDAState *s); |
126 | 130 | static void cuda_receive_packet_from_host(CUDAState *s, |
127 | 131 | const uint8_t *data, int len); |
132 | +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, | |
133 | + int64_t current_time); | |
128 | 134 | |
129 | 135 | static void cuda_update_irq(CUDAState *s) |
130 | 136 | { |
131 | - if (s->ifr & s->ier & SR_INT) { | |
132 | - pic_set_irq(s->irq, 1); | |
137 | + if (s->ifr & s->ier & (SR_INT | T1_INT)) { | |
138 | + openpic_set_irq(s->openpic, s->irq, 1); | |
133 | 139 | } else { |
134 | - pic_set_irq(s->irq, 0); | |
140 | + openpic_set_irq(s->openpic, s->irq, 0); | |
135 | 141 | } |
136 | 142 | } |
137 | 143 | |
... | ... | @@ -150,10 +156,15 @@ static unsigned int get_counter(CUDATimer *s) |
150 | 156 | return counter; |
151 | 157 | } |
152 | 158 | |
153 | -static void set_counter(CUDATimer *s, unsigned int val) | |
159 | +static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) | |
154 | 160 | { |
155 | - s->load_time = qemu_get_clock(vm_clock); | |
156 | - s->counter_value = val; | |
161 | +#ifdef DEBUG_CUDA | |
162 | + printf("cuda: T%d.counter=%d\n", | |
163 | + 1 + (ti->timer == NULL), val); | |
164 | +#endif | |
165 | + ti->load_time = qemu_get_clock(vm_clock); | |
166 | + ti->counter_value = val; | |
167 | + cuda_timer_update(s, ti, ti->load_time); | |
157 | 168 | } |
158 | 169 | |
159 | 170 | static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) |
... | ... | @@ -165,10 +176,14 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) |
165 | 176 | if (d <= s->counter_value) { |
166 | 177 | next_time = s->counter_value + 1; |
167 | 178 | } else { |
168 | - base = ((d - s->counter_value) % s->latch); | |
179 | + base = ((d - s->counter_value) / s->latch); | |
169 | 180 | base = (base * s->latch) + s->counter_value; |
170 | 181 | next_time = base + s->latch; |
171 | 182 | } |
183 | +#ifdef DEBUG_CUDA | |
184 | + printf("latch=%d counter=%lld delta_next=%lld\n", | |
185 | + s->latch, d, next_time - d); | |
186 | +#endif | |
172 | 187 | next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + |
173 | 188 | s->load_time; |
174 | 189 | if (next_time <= current_time) |
... | ... | @@ -176,13 +191,25 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) |
176 | 191 | return next_time; |
177 | 192 | } |
178 | 193 | |
194 | +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, | |
195 | + int64_t current_time) | |
196 | +{ | |
197 | + if (!ti->timer) | |
198 | + return; | |
199 | + if ((s->acr & T1MODE) != T1MODE_CONT) { | |
200 | + qemu_del_timer(ti->timer); | |
201 | + } else { | |
202 | + ti->next_irq_time = get_next_irq_time(ti, current_time); | |
203 | + qemu_mod_timer(ti->timer, ti->next_irq_time); | |
204 | + } | |
205 | +} | |
206 | + | |
179 | 207 | static void cuda_timer1(void *opaque) |
180 | 208 | { |
181 | 209 | CUDAState *s = opaque; |
182 | 210 | CUDATimer *ti = &s->timers[0]; |
183 | 211 | |
184 | - ti->next_irq_time = get_next_irq_time(ti, ti->next_irq_time); | |
185 | - qemu_mod_timer(ti->timer, ti->next_irq_time); | |
212 | + cuda_timer_update(s, ti, ti->next_irq_time); | |
186 | 213 | s->ifr |= T1_INT; |
187 | 214 | cuda_update_irq(s); |
188 | 215 | } |
... | ... | @@ -229,11 +256,9 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) |
229 | 256 | val = get_counter(&s->timers[1]) >> 8; |
230 | 257 | break; |
231 | 258 | case 10: |
232 | - if (s->data_in_index < s->data_in_size) { | |
233 | - val = s->data_in[s->data_in_index]; | |
234 | - } else { | |
235 | - val = 0; | |
236 | - } | |
259 | + val = s->sr; | |
260 | + s->ifr &= ~SR_INT; | |
261 | + cuda_update_irq(s); | |
237 | 262 | break; |
238 | 263 | case 11: |
239 | 264 | val = s->acr; |
... | ... | @@ -253,7 +278,8 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) |
253 | 278 | break; |
254 | 279 | } |
255 | 280 | #ifdef DEBUG_CUDA |
256 | - printf("cuda: read: reg=0x%x val=%02x\n", addr, val); | |
281 | + if (addr != 13 || val != 0) | |
282 | + printf("cuda: read: reg=0x%x val=%02x\n", addr, val); | |
257 | 283 | #endif |
258 | 284 | return val; |
259 | 285 | } |
... | ... | @@ -283,44 +309,34 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
283 | 309 | break; |
284 | 310 | case 4: |
285 | 311 | val = val | (get_counter(&s->timers[0]) & 0xff00); |
286 | - set_counter(&s->timers[0], val); | |
312 | + set_counter(s, &s->timers[0], val); | |
287 | 313 | break; |
288 | 314 | case 5: |
289 | 315 | val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); |
290 | - set_counter(&s->timers[0], val); | |
316 | + set_counter(s, &s->timers[0], val); | |
291 | 317 | break; |
292 | 318 | case 6: |
293 | 319 | s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; |
320 | + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); | |
294 | 321 | break; |
295 | 322 | case 7: |
296 | 323 | s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); |
324 | + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); | |
297 | 325 | break; |
298 | 326 | case 8: |
299 | 327 | val = val | (get_counter(&s->timers[1]) & 0xff00); |
300 | - set_counter(&s->timers[1], val); | |
328 | + set_counter(s, &s->timers[1], val); | |
301 | 329 | break; |
302 | 330 | case 9: |
303 | 331 | val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); |
304 | - set_counter(&s->timers[1], val); | |
332 | + set_counter(s, &s->timers[1], val); | |
305 | 333 | break; |
306 | 334 | case 10: |
307 | 335 | s->sr = val; |
308 | 336 | break; |
309 | 337 | case 11: |
310 | 338 | s->acr = val; |
311 | - if ((s->acr & T1MODE) == T1MODE_CONT) { | |
312 | - if ((s->last_acr & T1MODE) != T1MODE_CONT) { | |
313 | - CUDATimer *ti = &s->timers[0]; | |
314 | - /* activate timer interrupt */ | |
315 | - ti->next_irq_time = get_next_irq_time(ti, qemu_get_clock(vm_clock)); | |
316 | - qemu_mod_timer(ti->timer, ti->next_irq_time); | |
317 | - } | |
318 | - } else { | |
319 | - if ((s->last_acr & T1MODE) == T1MODE_CONT) { | |
320 | - CUDATimer *ti = &s->timers[0]; | |
321 | - qemu_del_timer(ti->timer); | |
322 | - } | |
323 | - } | |
339 | + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); | |
324 | 340 | cuda_update(s); |
325 | 341 | break; |
326 | 342 | case 12: |
... | ... | @@ -351,47 +367,90 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
351 | 367 | /* NOTE: TIP and TREQ are negated */ |
352 | 368 | static void cuda_update(CUDAState *s) |
353 | 369 | { |
354 | - if (s->data_in_index < s->data_in_size) { | |
355 | - /* data input */ | |
356 | - if (!(s->b & TIP) && | |
357 | - (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | |
358 | - s->sr = s->data_in[s->data_in_index++]; | |
359 | - s->ifr |= SR_INT; | |
360 | - cuda_update_irq(s); | |
361 | - } | |
362 | - } | |
363 | - if (s->data_in_index < s->data_in_size) { | |
364 | - /* there is some data to read */ | |
365 | - s->b = (s->b & ~TREQ); | |
366 | - } else { | |
367 | - s->b = (s->b | TREQ); | |
368 | - } | |
370 | + int packet_received, len; | |
371 | + | |
372 | + packet_received = 0; | |
373 | + if (!(s->b & TIP)) { | |
374 | + /* transfer requested from host */ | |
369 | 375 | |
370 | - if (s->acr & SR_OUT) { | |
371 | - /* data output */ | |
372 | - if (!(s->b & TIP) && | |
373 | - (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | |
374 | - if (s->data_out_index < sizeof(s->data_out)) { | |
375 | - s->data_out[s->data_out_index++] = s->sr; | |
376 | + if (s->acr & SR_OUT) { | |
377 | + /* data output */ | |
378 | + if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | |
379 | + if (s->data_out_index < sizeof(s->data_out)) { | |
380 | +#ifdef DEBUG_CUDA | |
381 | + printf("cuda: send: %02x\n", s->sr); | |
382 | +#endif | |
383 | + s->data_out[s->data_out_index++] = s->sr; | |
384 | + s->ifr |= SR_INT; | |
385 | + cuda_update_irq(s); | |
386 | + } | |
387 | + } | |
388 | + } else { | |
389 | + if (s->data_in_index < s->data_in_size) { | |
390 | + /* data input */ | |
391 | + if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | |
392 | + s->sr = s->data_in[s->data_in_index++]; | |
393 | +#ifdef DEBUG_CUDA | |
394 | + printf("cuda: recv: %02x\n", s->sr); | |
395 | +#endif | |
396 | + /* indicate end of transfer */ | |
397 | + if (s->data_in_index >= s->data_in_size) { | |
398 | + s->b = (s->b | TREQ); | |
399 | + } | |
400 | + s->ifr |= SR_INT; | |
401 | + cuda_update_irq(s); | |
402 | + } | |
376 | 403 | } |
404 | + } | |
405 | + } else { | |
406 | + /* no transfer requested: handle sync case */ | |
407 | + if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) { | |
408 | + /* update TREQ state each time TACK change state */ | |
409 | + if (s->b & TACK) | |
410 | + s->b = (s->b | TREQ); | |
411 | + else | |
412 | + s->b = (s->b & ~TREQ); | |
377 | 413 | s->ifr |= SR_INT; |
378 | 414 | cuda_update_irq(s); |
415 | + } else { | |
416 | + if (!(s->last_b & TIP)) { | |
417 | + /* handle end of host to cuda transfert */ | |
418 | + packet_received = (s->data_out_index > 0); | |
419 | + /* always an IRQ at the end of transfert */ | |
420 | + s->ifr |= SR_INT; | |
421 | + cuda_update_irq(s); | |
422 | + } | |
423 | + /* signal if there is data to read */ | |
424 | + if (s->data_in_index < s->data_in_size) { | |
425 | + s->b = (s->b & ~TREQ); | |
426 | + } | |
379 | 427 | } |
380 | 428 | } |
381 | 429 | |
382 | - /* check end of data output */ | |
383 | - if (!(s->acr & SR_OUT) && (s->last_acr & SR_OUT)) { | |
384 | - if (s->data_out_index > 0) | |
385 | - cuda_receive_packet_from_host(s, s->data_out, s->data_out_index); | |
386 | - s->data_out_index = 0; | |
387 | - } | |
388 | 430 | s->last_acr = s->acr; |
389 | 431 | s->last_b = s->b; |
432 | + | |
433 | + /* NOTE: cuda_receive_packet_from_host() can call cuda_update() | |
434 | + recursively */ | |
435 | + if (packet_received) { | |
436 | + len = s->data_out_index; | |
437 | + s->data_out_index = 0; | |
438 | + cuda_receive_packet_from_host(s, s->data_out, len); | |
439 | + } | |
390 | 440 | } |
391 | 441 | |
392 | 442 | static void cuda_send_packet_to_host(CUDAState *s, |
393 | 443 | const uint8_t *data, int len) |
394 | 444 | { |
445 | +#ifdef DEBUG_CUDA_PACKET | |
446 | + { | |
447 | + int i; | |
448 | + printf("cuda_send_packet_to_host:\n"); | |
449 | + for(i = 0; i < len; i++) | |
450 | + printf(" %02x", data[i]); | |
451 | + printf("\n"); | |
452 | + } | |
453 | +#endif | |
395 | 454 | memcpy(s->data_in, data, len); |
396 | 455 | s->data_in_size = len; |
397 | 456 | s->data_in_index = 0; |
... | ... | @@ -425,7 +484,7 @@ static void cuda_receive_packet(CUDAState *s, |
425 | 484 | break; |
426 | 485 | case CUDA_GET_TIME: |
427 | 486 | /* XXX: add time support ? */ |
428 | - ti = 0; | |
487 | + ti = time(NULL); | |
429 | 488 | obuf[0] = CUDA_PACKET; |
430 | 489 | obuf[1] = 0; |
431 | 490 | obuf[2] = 0; |
... | ... | @@ -452,6 +511,15 @@ static void cuda_receive_packet(CUDAState *s, |
452 | 511 | static void cuda_receive_packet_from_host(CUDAState *s, |
453 | 512 | const uint8_t *data, int len) |
454 | 513 | { |
514 | +#ifdef DEBUG_CUDA_PACKET | |
515 | + { | |
516 | + int i; | |
517 | + printf("cuda_receive_packet_to_host:\n"); | |
518 | + for(i = 0; i < len; i++) | |
519 | + printf(" %02x", data[i]); | |
520 | + printf("\n"); | |
521 | + } | |
522 | +#endif | |
455 | 523 | switch(data[0]) { |
456 | 524 | case ADB_PACKET: |
457 | 525 | adb_receive_packet(&adb_bus, data + 1, len - 1); |
... | ... | @@ -492,16 +560,20 @@ static CPUReadMemoryFunc *cuda_read[] = { |
492 | 560 | &cuda_readl, |
493 | 561 | }; |
494 | 562 | |
495 | -int cuda_init(void) | |
563 | +int cuda_init(openpic_t *openpic, int irq) | |
496 | 564 | { |
497 | 565 | CUDAState *s = &cuda_state; |
498 | 566 | int cuda_mem_index; |
499 | 567 | |
500 | - s->timers[0].latch = 0x10000; | |
501 | - set_counter(&s->timers[0], 0xffff); | |
568 | + s->openpic = openpic; | |
569 | + s->irq = irq; | |
570 | + | |
502 | 571 | s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); |
572 | + s->timers[0].latch = 0x10000; | |
573 | + set_counter(s, &s->timers[0], 0xffff); | |
503 | 574 | s->timers[1].latch = 0x10000; |
504 | - set_counter(&s->timers[1], 0xffff); | |
575 | + s->ier = T1_INT | SR_INT; | |
576 | + set_counter(s, &s->timers[1], 0xffff); | |
505 | 577 | cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); |
506 | 578 | return cuda_mem_index; |
507 | 579 | } | ... | ... |