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 | } | ... | ... |