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