|
|
1.1 root 1: /*
1.1.1.3 root 2: * QEMU PowerMac CUDA device support
3: *
4: * Copyright (c) 2004-2007 Fabrice Bellard
5: * Copyright (c) 2007 Jocelyn Mayer
6: *
1.1 root 7: * Permission is hereby granted, free of charge, to any person obtaining a copy
8: * of this software and associated documentation files (the "Software"), to deal
9: * in the Software without restriction, including without limitation the rights
10: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11: * copies of the Software, and to permit persons to whom the Software is
12: * furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included in
15: * all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23: * THE SOFTWARE.
24: */
1.1.1.3 root 25: #include "hw.h"
26: #include "ppc_mac.h"
27: #include "qemu-timer.h"
28: #include "sysemu.h"
1.1 root 29:
30: /* XXX: implement all timer modes */
31:
1.1.1.4 ! root 32: /* debug CUDA */
1.1 root 33: //#define DEBUG_CUDA
1.1.1.4 ! root 34:
! 35: /* debug CUDA packets */
1.1 root 36: //#define DEBUG_CUDA_PACKET
37:
1.1.1.4 ! root 38: #ifdef DEBUG_CUDA
! 39: #define CUDA_DPRINTF(fmt, args...) \
! 40: do { printf("CUDA: " fmt , ##args); } while (0)
! 41: #else
! 42: #define CUDA_DPRINTF(fmt, args...)
! 43: #endif
! 44:
1.1 root 45: /* Bits in B data register: all active low */
46: #define TREQ 0x08 /* Transfer request (input) */
47: #define TACK 0x10 /* Transfer acknowledge (output) */
48: #define TIP 0x20 /* Transfer in progress (output) */
49:
50: /* Bits in ACR */
51: #define SR_CTRL 0x1c /* Shift register control bits */
52: #define SR_EXT 0x0c /* Shift on external clock */
53: #define SR_OUT 0x10 /* Shift out if 1 */
54:
55: /* Bits in IFR and IER */
56: #define IER_SET 0x80 /* set bits in IER */
57: #define IER_CLR 0 /* clear bits in IER */
58: #define SR_INT 0x04 /* Shift register full/empty */
59: #define T1_INT 0x40 /* Timer 1 interrupt */
60: #define T2_INT 0x20 /* Timer 2 interrupt */
61:
62: /* Bits in ACR */
63: #define T1MODE 0xc0 /* Timer 1 mode */
64: #define T1MODE_CONT 0x40 /* continuous interrupts */
65:
66: /* commands (1st byte) */
67: #define ADB_PACKET 0
68: #define CUDA_PACKET 1
69: #define ERROR_PACKET 2
70: #define TIMER_PACKET 3
71: #define POWER_PACKET 4
72: #define MACIIC_PACKET 5
73: #define PMU_PACKET 6
74:
75:
76: /* CUDA commands (2nd byte) */
77: #define CUDA_WARM_START 0x0
78: #define CUDA_AUTOPOLL 0x1
79: #define CUDA_GET_6805_ADDR 0x2
80: #define CUDA_GET_TIME 0x3
81: #define CUDA_GET_PRAM 0x7
82: #define CUDA_SET_6805_ADDR 0x8
83: #define CUDA_SET_TIME 0x9
84: #define CUDA_POWERDOWN 0xa
85: #define CUDA_POWERUP_TIME 0xb
86: #define CUDA_SET_PRAM 0xc
87: #define CUDA_MS_RESET 0xd
88: #define CUDA_SEND_DFAC 0xe
89: #define CUDA_BATTERY_SWAP_SENSE 0x10
90: #define CUDA_RESET_SYSTEM 0x11
91: #define CUDA_SET_IPL 0x12
92: #define CUDA_FILE_SERVER_FLAG 0x13
93: #define CUDA_SET_AUTO_RATE 0x14
94: #define CUDA_GET_AUTO_RATE 0x16
95: #define CUDA_SET_DEVICE_LIST 0x19
96: #define CUDA_GET_DEVICE_LIST 0x1a
97: #define CUDA_SET_ONE_SECOND_MODE 0x1b
98: #define CUDA_SET_POWER_MESSAGES 0x21
99: #define CUDA_GET_SET_IIC 0x22
100: #define CUDA_WAKEUP 0x23
101: #define CUDA_TIMER_TICKLE 0x24
102: #define CUDA_COMBINED_FORMAT_IIC 0x25
103:
104: #define CUDA_TIMER_FREQ (4700000 / 6)
105: #define CUDA_ADB_POLL_FREQ 50
106:
107: /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
108: #define RTC_OFFSET 2082844800
109:
110: typedef struct CUDATimer {
1.1.1.3 root 111: int index;
1.1 root 112: uint16_t latch;
113: uint16_t counter_value; /* counter value at load time */
114: int64_t load_time;
115: int64_t next_irq_time;
116: QEMUTimer *timer;
117: } CUDATimer;
118:
119: typedef struct CUDAState {
120: /* cuda registers */
121: uint8_t b; /* B-side data */
122: uint8_t a; /* A-side data */
123: uint8_t dirb; /* B-side direction (1=output) */
124: uint8_t dira; /* A-side direction (1=output) */
125: uint8_t sr; /* Shift register */
126: uint8_t acr; /* Auxiliary control register */
127: uint8_t pcr; /* Peripheral control register */
128: uint8_t ifr; /* Interrupt flag register */
129: uint8_t ier; /* Interrupt enable register */
130: uint8_t anh; /* A-side data, no handshake */
131:
132: CUDATimer timers[2];
1.1.1.3 root 133:
1.1.1.4 ! root 134: uint32_t tick_offset;
! 135:
1.1 root 136: uint8_t last_b; /* last value of B register */
137: uint8_t last_acr; /* last value of B register */
1.1.1.3 root 138:
1.1 root 139: int data_in_size;
140: int data_in_index;
141: int data_out_index;
142:
1.1.1.3 root 143: qemu_irq irq;
1.1 root 144: uint8_t autopoll;
145: uint8_t data_in[128];
146: uint8_t data_out[16];
147: QEMUTimer *adb_poll_timer;
148: } CUDAState;
149:
150: static CUDAState cuda_state;
151: ADBBusState adb_bus;
152:
153: static void cuda_update(CUDAState *s);
1.1.1.3 root 154: static void cuda_receive_packet_from_host(CUDAState *s,
1.1 root 155: const uint8_t *data, int len);
1.1.1.3 root 156: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
1.1 root 157: int64_t current_time);
158:
159: static void cuda_update_irq(CUDAState *s)
160: {
161: if (s->ifr & s->ier & (SR_INT | T1_INT)) {
1.1.1.3 root 162: qemu_irq_raise(s->irq);
1.1 root 163: } else {
1.1.1.3 root 164: qemu_irq_lower(s->irq);
1.1 root 165: }
166: }
167:
168: static unsigned int get_counter(CUDATimer *s)
169: {
170: int64_t d;
171: unsigned int counter;
172:
1.1.1.3 root 173: d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
1.1 root 174: CUDA_TIMER_FREQ, ticks_per_sec);
175: if (s->index == 0) {
176: /* the timer goes down from latch to -1 (period of latch + 2) */
177: if (d <= (s->counter_value + 1)) {
178: counter = (s->counter_value - d) & 0xffff;
179: } else {
180: counter = (d - (s->counter_value + 1)) % (s->latch + 2);
1.1.1.3 root 181: counter = (s->latch - counter) & 0xffff;
1.1 root 182: }
183: } else {
184: counter = (s->counter_value - d) & 0xffff;
185: }
186: return counter;
187: }
188:
189: static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
190: {
1.1.1.4 ! root 191: CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
1.1 root 192: ti->load_time = qemu_get_clock(vm_clock);
193: ti->counter_value = val;
194: cuda_timer_update(s, ti, ti->load_time);
195: }
196:
197: static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
198: {
199: int64_t d, next_time;
200: unsigned int counter;
201:
202: /* current counter value */
1.1.1.3 root 203: d = muldiv64(current_time - s->load_time,
1.1 root 204: CUDA_TIMER_FREQ, ticks_per_sec);
205: /* the timer goes down from latch to -1 (period of latch + 2) */
206: if (d <= (s->counter_value + 1)) {
207: counter = (s->counter_value - d) & 0xffff;
208: } else {
209: counter = (d - (s->counter_value + 1)) % (s->latch + 2);
1.1.1.3 root 210: counter = (s->latch - counter) & 0xffff;
1.1 root 211: }
1.1.1.3 root 212:
1.1 root 213: /* Note: we consider the irq is raised on 0 */
214: if (counter == 0xffff) {
215: next_time = d + s->latch + 1;
216: } else if (counter == 0) {
217: next_time = d + s->latch + 2;
218: } else {
219: next_time = d + counter;
220: }
1.1.1.4 ! root 221: CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
! 222: s->latch, d, next_time - d);
1.1.1.3 root 223: next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
1.1 root 224: s->load_time;
225: if (next_time <= current_time)
226: next_time = current_time + 1;
227: return next_time;
228: }
229:
1.1.1.3 root 230: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
1.1 root 231: int64_t current_time)
232: {
233: if (!ti->timer)
234: return;
235: if ((s->acr & T1MODE) != T1MODE_CONT) {
236: qemu_del_timer(ti->timer);
237: } else {
238: ti->next_irq_time = get_next_irq_time(ti, current_time);
239: qemu_mod_timer(ti->timer, ti->next_irq_time);
240: }
241: }
242:
243: static void cuda_timer1(void *opaque)
244: {
245: CUDAState *s = opaque;
246: CUDATimer *ti = &s->timers[0];
247:
248: cuda_timer_update(s, ti, ti->next_irq_time);
249: s->ifr |= T1_INT;
250: cuda_update_irq(s);
251: }
252:
253: static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
254: {
255: CUDAState *s = opaque;
256: uint32_t val;
257:
258: addr = (addr >> 9) & 0xf;
259: switch(addr) {
260: case 0:
261: val = s->b;
262: break;
263: case 1:
264: val = s->a;
265: break;
266: case 2:
267: val = s->dirb;
268: break;
269: case 3:
270: val = s->dira;
271: break;
272: case 4:
273: val = get_counter(&s->timers[0]) & 0xff;
274: s->ifr &= ~T1_INT;
275: cuda_update_irq(s);
276: break;
277: case 5:
278: val = get_counter(&s->timers[0]) >> 8;
279: cuda_update_irq(s);
280: break;
281: case 6:
282: val = s->timers[0].latch & 0xff;
283: break;
284: case 7:
285: /* XXX: check this */
286: val = (s->timers[0].latch >> 8) & 0xff;
287: break;
288: case 8:
289: val = get_counter(&s->timers[1]) & 0xff;
290: s->ifr &= ~T2_INT;
291: break;
292: case 9:
293: val = get_counter(&s->timers[1]) >> 8;
294: break;
295: case 10:
296: val = s->sr;
297: s->ifr &= ~SR_INT;
298: cuda_update_irq(s);
299: break;
300: case 11:
301: val = s->acr;
302: break;
303: case 12:
304: val = s->pcr;
305: break;
306: case 13:
307: val = s->ifr;
1.1.1.3 root 308: if (s->ifr & s->ier)
1.1 root 309: val |= 0x80;
310: break;
311: case 14:
312: val = s->ier | 0x80;
313: break;
314: default:
315: case 15:
316: val = s->anh;
317: break;
318: }
319: if (addr != 13 || val != 0)
1.1.1.4 ! root 320: CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
1.1 root 321: return val;
322: }
323:
324: static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
325: {
326: CUDAState *s = opaque;
1.1.1.3 root 327:
1.1 root 328: addr = (addr >> 9) & 0xf;
1.1.1.4 ! root 329: CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);
1.1 root 330:
331: switch(addr) {
332: case 0:
333: s->b = val;
334: cuda_update(s);
335: break;
336: case 1:
337: s->a = val;
338: break;
339: case 2:
340: s->dirb = val;
341: break;
342: case 3:
343: s->dira = val;
344: break;
345: case 4:
346: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
347: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
348: break;
349: case 5:
350: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
351: s->ifr &= ~T1_INT;
352: set_counter(s, &s->timers[0], s->timers[0].latch);
353: break;
354: case 6:
355: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
356: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
357: break;
358: case 7:
359: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
360: s->ifr &= ~T1_INT;
361: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
362: break;
363: case 8:
364: s->timers[1].latch = val;
365: set_counter(s, &s->timers[1], val);
366: break;
367: case 9:
368: set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
369: break;
370: case 10:
371: s->sr = val;
372: break;
373: case 11:
374: s->acr = val;
375: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
376: cuda_update(s);
377: break;
378: case 12:
379: s->pcr = val;
380: break;
381: case 13:
382: /* reset bits */
383: s->ifr &= ~val;
384: cuda_update_irq(s);
385: break;
386: case 14:
387: if (val & IER_SET) {
388: /* set bits */
389: s->ier |= val & 0x7f;
390: } else {
391: /* reset bits */
392: s->ier &= ~val;
393: }
394: cuda_update_irq(s);
395: break;
396: default:
397: case 15:
398: s->anh = val;
399: break;
400: }
401: }
402:
403: /* NOTE: TIP and TREQ are negated */
404: static void cuda_update(CUDAState *s)
405: {
406: int packet_received, len;
407:
408: packet_received = 0;
409: if (!(s->b & TIP)) {
410: /* transfer requested from host */
411:
412: if (s->acr & SR_OUT) {
413: /* data output */
414: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
415: if (s->data_out_index < sizeof(s->data_out)) {
1.1.1.4 ! root 416: CUDA_DPRINTF("send: %02x\n", s->sr);
1.1 root 417: s->data_out[s->data_out_index++] = s->sr;
418: s->ifr |= SR_INT;
419: cuda_update_irq(s);
420: }
421: }
422: } else {
423: if (s->data_in_index < s->data_in_size) {
424: /* data input */
425: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
426: s->sr = s->data_in[s->data_in_index++];
1.1.1.4 ! root 427: CUDA_DPRINTF("recv: %02x\n", s->sr);
1.1 root 428: /* indicate end of transfer */
429: if (s->data_in_index >= s->data_in_size) {
430: s->b = (s->b | TREQ);
431: }
432: s->ifr |= SR_INT;
433: cuda_update_irq(s);
434: }
435: }
436: }
437: } else {
438: /* no transfer requested: handle sync case */
439: if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
440: /* update TREQ state each time TACK change state */
441: if (s->b & TACK)
442: s->b = (s->b | TREQ);
443: else
444: s->b = (s->b & ~TREQ);
445: s->ifr |= SR_INT;
446: cuda_update_irq(s);
447: } else {
448: if (!(s->last_b & TIP)) {
1.1.1.3 root 449: /* handle end of host to cuda transfer */
1.1 root 450: packet_received = (s->data_out_index > 0);
1.1.1.3 root 451: /* always an IRQ at the end of transfer */
1.1 root 452: s->ifr |= SR_INT;
453: cuda_update_irq(s);
454: }
455: /* signal if there is data to read */
456: if (s->data_in_index < s->data_in_size) {
457: s->b = (s->b & ~TREQ);
458: }
459: }
460: }
461:
462: s->last_acr = s->acr;
463: s->last_b = s->b;
464:
465: /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
466: recursively */
467: if (packet_received) {
468: len = s->data_out_index;
469: s->data_out_index = 0;
470: cuda_receive_packet_from_host(s, s->data_out, len);
471: }
472: }
473:
1.1.1.3 root 474: static void cuda_send_packet_to_host(CUDAState *s,
1.1 root 475: const uint8_t *data, int len)
476: {
477: #ifdef DEBUG_CUDA_PACKET
478: {
479: int i;
480: printf("cuda_send_packet_to_host:\n");
481: for(i = 0; i < len; i++)
482: printf(" %02x", data[i]);
483: printf("\n");
484: }
485: #endif
486: memcpy(s->data_in, data, len);
487: s->data_in_size = len;
488: s->data_in_index = 0;
489: cuda_update(s);
490: s->ifr |= SR_INT;
491: cuda_update_irq(s);
492: }
493:
494: static void cuda_adb_poll(void *opaque)
495: {
496: CUDAState *s = opaque;
497: uint8_t obuf[ADB_MAX_OUT_LEN + 2];
498: int olen;
499:
500: olen = adb_poll(&adb_bus, obuf + 2);
501: if (olen > 0) {
502: obuf[0] = ADB_PACKET;
503: obuf[1] = 0x40; /* polled data */
504: cuda_send_packet_to_host(s, obuf, olen + 2);
505: }
1.1.1.3 root 506: qemu_mod_timer(s->adb_poll_timer,
507: qemu_get_clock(vm_clock) +
1.1 root 508: (ticks_per_sec / CUDA_ADB_POLL_FREQ));
509: }
510:
1.1.1.3 root 511: static void cuda_receive_packet(CUDAState *s,
1.1 root 512: const uint8_t *data, int len)
513: {
514: uint8_t obuf[16];
1.1.1.4 ! root 515: int autopoll;
! 516: uint32_t ti;
1.1 root 517:
518: switch(data[0]) {
519: case CUDA_AUTOPOLL:
520: autopoll = (data[1] != 0);
521: if (autopoll != s->autopoll) {
522: s->autopoll = autopoll;
523: if (autopoll) {
1.1.1.3 root 524: qemu_mod_timer(s->adb_poll_timer,
525: qemu_get_clock(vm_clock) +
1.1 root 526: (ticks_per_sec / CUDA_ADB_POLL_FREQ));
527: } else {
528: qemu_del_timer(s->adb_poll_timer);
529: }
530: }
531: obuf[0] = CUDA_PACKET;
532: obuf[1] = data[1];
533: cuda_send_packet_to_host(s, obuf, 2);
534: break;
535: case CUDA_SET_TIME:
1.1.1.4 ! root 536: ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
! 537: s->tick_offset = ti - (qemu_get_clock(vm_clock) / ticks_per_sec);
! 538: obuf[0] = CUDA_PACKET;
! 539: obuf[1] = 0;
! 540: obuf[2] = 0;
! 541: cuda_send_packet_to_host(s, obuf, 3);
! 542: break;
! 543: case CUDA_GET_TIME:
! 544: ti = s->tick_offset + (qemu_get_clock(vm_clock) / ticks_per_sec);
1.1 root 545: obuf[0] = CUDA_PACKET;
546: obuf[1] = 0;
547: obuf[2] = 0;
548: obuf[3] = ti >> 24;
549: obuf[4] = ti >> 16;
550: obuf[5] = ti >> 8;
551: obuf[6] = ti;
552: cuda_send_packet_to_host(s, obuf, 7);
553: break;
554: case CUDA_FILE_SERVER_FLAG:
555: case CUDA_SET_DEVICE_LIST:
556: case CUDA_SET_AUTO_RATE:
557: case CUDA_SET_POWER_MESSAGES:
558: obuf[0] = CUDA_PACKET;
559: obuf[1] = 0;
560: cuda_send_packet_to_host(s, obuf, 2);
561: break;
562: case CUDA_POWERDOWN:
563: obuf[0] = CUDA_PACKET;
564: obuf[1] = 0;
565: cuda_send_packet_to_host(s, obuf, 2);
1.1.1.4 ! root 566: qemu_system_shutdown_request();
! 567: break;
1.1.1.3 root 568: case CUDA_RESET_SYSTEM:
569: obuf[0] = CUDA_PACKET;
570: obuf[1] = 0;
571: cuda_send_packet_to_host(s, obuf, 2);
572: qemu_system_reset_request();
573: break;
1.1 root 574: default:
575: break;
576: }
577: }
578:
1.1.1.3 root 579: static void cuda_receive_packet_from_host(CUDAState *s,
1.1 root 580: const uint8_t *data, int len)
581: {
582: #ifdef DEBUG_CUDA_PACKET
583: {
584: int i;
585: printf("cuda_receive_packet_from_host:\n");
586: for(i = 0; i < len; i++)
587: printf(" %02x", data[i]);
588: printf("\n");
589: }
590: #endif
591: switch(data[0]) {
592: case ADB_PACKET:
593: {
594: uint8_t obuf[ADB_MAX_OUT_LEN + 2];
595: int olen;
596: olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
597: if (olen > 0) {
598: obuf[0] = ADB_PACKET;
599: obuf[1] = 0x00;
600: } else {
601: /* error */
602: obuf[0] = ADB_PACKET;
603: obuf[1] = -olen;
604: olen = 0;
605: }
606: cuda_send_packet_to_host(s, obuf, olen + 2);
607: }
608: break;
609: case CUDA_PACKET:
610: cuda_receive_packet(s, data + 1, len - 1);
611: break;
612: }
613: }
614:
615: static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
616: {
617: }
618:
619: static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
620: {
621: }
622:
623: static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
624: {
625: return 0;
626: }
627:
628: static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
629: {
630: return 0;
631: }
632:
633: static CPUWriteMemoryFunc *cuda_write[] = {
634: &cuda_writeb,
635: &cuda_writew,
636: &cuda_writel,
637: };
638:
639: static CPUReadMemoryFunc *cuda_read[] = {
640: &cuda_readb,
641: &cuda_readw,
642: &cuda_readl,
643: };
644:
1.1.1.4 ! root 645: static void cuda_save_timer(QEMUFile *f, CUDATimer *s)
! 646: {
! 647: qemu_put_be16s(f, &s->latch);
! 648: qemu_put_be16s(f, &s->counter_value);
! 649: qemu_put_sbe64s(f, &s->load_time);
! 650: qemu_put_sbe64s(f, &s->next_irq_time);
! 651: if (s->timer)
! 652: qemu_put_timer(f, s->timer);
! 653: }
! 654:
! 655: static void cuda_save(QEMUFile *f, void *opaque)
! 656: {
! 657: CUDAState *s = (CUDAState *)opaque;
! 658:
! 659: qemu_put_ubyte(f, s->b);
! 660: qemu_put_ubyte(f, s->a);
! 661: qemu_put_ubyte(f, s->dirb);
! 662: qemu_put_ubyte(f, s->dira);
! 663: qemu_put_ubyte(f, s->sr);
! 664: qemu_put_ubyte(f, s->acr);
! 665: qemu_put_ubyte(f, s->pcr);
! 666: qemu_put_ubyte(f, s->ifr);
! 667: qemu_put_ubyte(f, s->ier);
! 668: qemu_put_ubyte(f, s->anh);
! 669: qemu_put_sbe32s(f, &s->data_in_size);
! 670: qemu_put_sbe32s(f, &s->data_in_index);
! 671: qemu_put_sbe32s(f, &s->data_out_index);
! 672: qemu_put_ubyte(f, s->autopoll);
! 673: qemu_put_buffer(f, s->data_in, sizeof(s->data_in));
! 674: qemu_put_buffer(f, s->data_out, sizeof(s->data_out));
! 675: qemu_put_be32s(f, &s->tick_offset);
! 676: cuda_save_timer(f, &s->timers[0]);
! 677: cuda_save_timer(f, &s->timers[1]);
! 678: }
! 679:
! 680: static void cuda_load_timer(QEMUFile *f, CUDATimer *s)
! 681: {
! 682: qemu_get_be16s(f, &s->latch);
! 683: qemu_get_be16s(f, &s->counter_value);
! 684: qemu_get_sbe64s(f, &s->load_time);
! 685: qemu_get_sbe64s(f, &s->next_irq_time);
! 686: if (s->timer)
! 687: qemu_get_timer(f, s->timer);
! 688: }
! 689:
! 690: static int cuda_load(QEMUFile *f, void *opaque, int version_id)
! 691: {
! 692: CUDAState *s = (CUDAState *)opaque;
! 693:
! 694: if (version_id != 1)
! 695: return -EINVAL;
! 696:
! 697: s->b = qemu_get_ubyte(f);
! 698: s->a = qemu_get_ubyte(f);
! 699: s->dirb = qemu_get_ubyte(f);
! 700: s->dira = qemu_get_ubyte(f);
! 701: s->sr = qemu_get_ubyte(f);
! 702: s->acr = qemu_get_ubyte(f);
! 703: s->pcr = qemu_get_ubyte(f);
! 704: s->ifr = qemu_get_ubyte(f);
! 705: s->ier = qemu_get_ubyte(f);
! 706: s->anh = qemu_get_ubyte(f);
! 707: qemu_get_sbe32s(f, &s->data_in_size);
! 708: qemu_get_sbe32s(f, &s->data_in_index);
! 709: qemu_get_sbe32s(f, &s->data_out_index);
! 710: s->autopoll = qemu_get_ubyte(f);
! 711: qemu_get_buffer(f, s->data_in, sizeof(s->data_in));
! 712: qemu_get_buffer(f, s->data_out, sizeof(s->data_out));
! 713: qemu_get_be32s(f, &s->tick_offset);
! 714: cuda_load_timer(f, &s->timers[0]);
! 715: cuda_load_timer(f, &s->timers[1]);
! 716:
! 717: return 0;
! 718: }
! 719:
! 720: static void cuda_reset(void *opaque)
! 721: {
! 722: CUDAState *s = opaque;
! 723:
! 724: s->b = 0;
! 725: s->a = 0;
! 726: s->dirb = 0;
! 727: s->dira = 0;
! 728: s->sr = 0;
! 729: s->acr = 0;
! 730: s->pcr = 0;
! 731: s->ifr = 0;
! 732: s->ier = 0;
! 733: // s->ier = T1_INT | SR_INT;
! 734: s->anh = 0;
! 735: s->data_in_size = 0;
! 736: s->data_in_index = 0;
! 737: s->data_out_index = 0;
! 738: s->autopoll = 0;
! 739:
! 740: s->timers[0].latch = 0xffff;
! 741: set_counter(s, &s->timers[0], 0xffff);
! 742:
! 743: s->timers[1].latch = 0;
! 744: set_counter(s, &s->timers[1], 0xffff);
! 745: }
! 746:
1.1.1.3 root 747: void cuda_init (int *cuda_mem_index, qemu_irq irq)
1.1 root 748: {
1.1.1.4 ! root 749: struct tm tm;
1.1 root 750: CUDAState *s = &cuda_state;
751:
752: s->irq = irq;
753:
754: s->timers[0].index = 0;
755: s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
756:
757: s->timers[1].index = 1;
1.1.1.4 ! root 758:
! 759: qemu_get_timedate(&tm, 0);
! 760: s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
1.1 root 761:
762: s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
1.1.1.3 root 763: *cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
1.1.1.4 ! root 764: register_savevm("cuda", -1, 1, cuda_save, cuda_load, s);
! 765: qemu_register_reset(cuda_reset, s);
! 766: cuda_reset(s);
1.1 root 767: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.