1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25: #include "hw.h"
26: #include "ppc_mac.h"
27: #include "qemu-timer.h"
28: #include "sysemu.h"
29:
30:
31:
32:
33:
34:
35:
36: #define TREQ 0x08
37: #define TACK 0x10
38: #define TIP 0x20
39:
40:
41: #define SR_CTRL 0x1c
42: #define SR_EXT 0x0c
43: #define SR_OUT 0x10
44:
45:
46: #define IER_SET 0x80
47: #define IER_CLR 0
48: #define SR_INT 0x04
49: #define T1_INT 0x40
50: #define T2_INT 0x20
51:
52:
53: #define T1MODE 0xc0
54: #define T1MODE_CONT 0x40
55:
56:
57: #define ADB_PACKET 0
58: #define CUDA_PACKET 1
59: #define ERROR_PACKET 2
60: #define TIMER_PACKET 3
61: #define POWER_PACKET 4
62: #define MACIIC_PACKET 5
63: #define PMU_PACKET 6
64:
65:
66:
67: #define CUDA_WARM_START 0x0
68: #define CUDA_AUTOPOLL 0x1
69: #define CUDA_GET_6805_ADDR 0x2
70: #define CUDA_GET_TIME 0x3
71: #define CUDA_GET_PRAM 0x7
72: #define CUDA_SET_6805_ADDR 0x8
73: #define CUDA_SET_TIME 0x9
74: #define CUDA_POWERDOWN 0xa
75: #define CUDA_POWERUP_TIME 0xb
76: #define CUDA_SET_PRAM 0xc
77: #define CUDA_MS_RESET 0xd
78: #define CUDA_SEND_DFAC 0xe
79: #define CUDA_BATTERY_SWAP_SENSE 0x10
80: #define CUDA_RESET_SYSTEM 0x11
81: #define CUDA_SET_IPL 0x12
82: #define CUDA_FILE_SERVER_FLAG 0x13
83: #define CUDA_SET_AUTO_RATE 0x14
84: #define CUDA_GET_AUTO_RATE 0x16
85: #define CUDA_SET_DEVICE_LIST 0x19
86: #define CUDA_GET_DEVICE_LIST 0x1a
87: #define CUDA_SET_ONE_SECOND_MODE 0x1b
88: #define CUDA_SET_POWER_MESSAGES 0x21
89: #define CUDA_GET_SET_IIC 0x22
90: #define CUDA_WAKEUP 0x23
91: #define CUDA_TIMER_TICKLE 0x24
92: #define CUDA_COMBINED_FORMAT_IIC 0x25
93:
94: #define CUDA_TIMER_FREQ (4700000 / 6)
95: #define CUDA_ADB_POLL_FREQ 50
96:
97:
98: #define RTC_OFFSET 2082844800
99:
100: typedef struct CUDATimer {
101: int index;
102: uint16_t latch;
103: uint16_t counter_value;
104: int64_t load_time;
105: int64_t next_irq_time;
106: QEMUTimer *timer;
107: } CUDATimer;
108:
109: typedef struct CUDAState {
110:
111: uint8_t b;
112: uint8_t a;
113: uint8_t dirb;
114: uint8_t dira;
115: uint8_t sr;
116: uint8_t acr;
117: uint8_t pcr;
118: uint8_t ifr;
119: uint8_t ier;
120: uint8_t anh;
121:
122: CUDATimer timers[2];
123:
124: uint8_t last_b;
125: uint8_t last_acr;
126:
127: int data_in_size;
128: int data_in_index;
129: int data_out_index;
130:
131: qemu_irq irq;
132: uint8_t autopoll;
133: uint8_t data_in[128];
134: uint8_t data_out[16];
135: QEMUTimer *adb_poll_timer;
136: } CUDAState;
137:
138: static CUDAState cuda_state;
139: ADBBusState adb_bus;
140:
141: static void cuda_update(CUDAState *s);
142: static void cuda_receive_packet_from_host(CUDAState *s,
143: const uint8_t *data, int len);
144: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
145: int64_t current_time);
146:
147: static void cuda_update_irq(CUDAState *s)
148: {
149: if (s->ifr & s->ier & (SR_INT | T1_INT)) {
150: qemu_irq_raise(s->irq);
151: } else {
152: qemu_irq_lower(s->irq);
153: }
154: }
155:
156: static unsigned int get_counter(CUDATimer *s)
157: {
158: int64_t d;
159: unsigned int counter;
160:
161: d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
162: CUDA_TIMER_FREQ, ticks_per_sec);
163: if (s->index == 0) {
164:
165: if (d <= (s->counter_value + 1)) {
166: counter = (s->counter_value - d) & 0xffff;
167: } else {
168: counter = (d - (s->counter_value + 1)) % (s->latch + 2);
169: counter = (s->latch - counter) & 0xffff;
170: }
171: } else {
172: counter = (s->counter_value - d) & 0xffff;
173: }
174: return counter;
175: }
176:
177: static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
178: {
179: #ifdef DEBUG_CUDA
180: printf("cuda: T%d.counter=%d\n",
181: 1 + (ti->timer == NULL), val);
182: #endif
183: ti->load_time = qemu_get_clock(vm_clock);
184: ti->counter_value = val;
185: cuda_timer_update(s, ti, ti->load_time);
186: }
187:
188: static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
189: {
190: int64_t d, next_time;
191: unsigned int counter;
192:
193:
194: d = muldiv64(current_time - s->load_time,
195: CUDA_TIMER_FREQ, ticks_per_sec);
196:
197: if (d <= (s->counter_value + 1)) {
198: counter = (s->counter_value - d) & 0xffff;
199: } else {
200: counter = (d - (s->counter_value + 1)) % (s->latch + 2);
201: counter = (s->latch - counter) & 0xffff;
202: }
203:
204:
205: if (counter == 0xffff) {
206: next_time = d + s->latch + 1;
207: } else if (counter == 0) {
208: next_time = d + s->latch + 2;
209: } else {
210: next_time = d + counter;
211: }
212: #if 0
213: #ifdef DEBUG_CUDA
214: printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
215: s->latch, d, next_time - d);
216: #endif
217: #endif
218: next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
219: s->load_time;
220: if (next_time <= current_time)
221: next_time = current_time + 1;
222: return next_time;
223: }
224:
225: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
226: int64_t current_time)
227: {
228: if (!ti->timer)
229: return;
230: if ((s->acr & T1MODE) != T1MODE_CONT) {
231: qemu_del_timer(ti->timer);
232: } else {
233: ti->next_irq_time = get_next_irq_time(ti, current_time);
234: qemu_mod_timer(ti->timer, ti->next_irq_time);
235: }
236: }
237:
238: static void cuda_timer1(void *opaque)
239: {
240: CUDAState *s = opaque;
241: CUDATimer *ti = &s->timers[0];
242:
243: cuda_timer_update(s, ti, ti->next_irq_time);
244: s->ifr |= T1_INT;
245: cuda_update_irq(s);
246: }
247:
248: static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
249: {
250: CUDAState *s = opaque;
251: uint32_t val;
252:
253: addr = (addr >> 9) & 0xf;
254: switch(addr) {
255: case 0:
256: val = s->b;
257: break;
258: case 1:
259: val = s->a;
260: break;
261: case 2:
262: val = s->dirb;
263: break;
264: case 3:
265: val = s->dira;
266: break;
267: case 4:
268: val = get_counter(&s->timers[0]) & 0xff;
269: s->ifr &= ~T1_INT;
270: cuda_update_irq(s);
271: break;
272: case 5:
273: val = get_counter(&s->timers[0]) >> 8;
274: cuda_update_irq(s);
275: break;
276: case 6:
277: val = s->timers[0].latch & 0xff;
278: break;
279: case 7:
280:
281: val = (s->timers[0].latch >> 8) & 0xff;
282: break;
283: case 8:
284: val = get_counter(&s->timers[1]) & 0xff;
285: s->ifr &= ~T2_INT;
286: break;
287: case 9:
288: val = get_counter(&s->timers[1]) >> 8;
289: break;
290: case 10:
291: val = s->sr;
292: s->ifr &= ~SR_INT;
293: cuda_update_irq(s);
294: break;
295: case 11:
296: val = s->acr;
297: break;
298: case 12:
299: val = s->pcr;
300: break;
301: case 13:
302: val = s->ifr;
303: if (s->ifr & s->ier)
304: val |= 0x80;
305: break;
306: case 14:
307: val = s->ier | 0x80;
308: break;
309: default:
310: case 15:
311: val = s->anh;
312: break;
313: }
314: #ifdef DEBUG_CUDA
315: if (addr != 13 || val != 0)
316: printf("cuda: read: reg=0x%x val=%02x\n", addr, val);
317: #endif
318: return val;
319: }
320:
321: static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
322: {
323: CUDAState *s = opaque;
324:
325: addr = (addr >> 9) & 0xf;
326: #ifdef DEBUG_CUDA
327: printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
328: #endif
329:
330: switch(addr) {
331: case 0:
332: s->b = val;
333: cuda_update(s);
334: break;
335: case 1:
336: s->a = val;
337: break;
338: case 2:
339: s->dirb = val;
340: break;
341: case 3:
342: s->dira = val;
343: break;
344: case 4:
345: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
346: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
347: break;
348: case 5:
349: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
350: s->ifr &= ~T1_INT;
351: set_counter(s, &s->timers[0], s->timers[0].latch);
352: break;
353: case 6:
354: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
355: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
356: break;
357: case 7:
358: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
359: s->ifr &= ~T1_INT;
360: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
361: break;
362: case 8:
363: s->timers[1].latch = val;
364: set_counter(s, &s->timers[1], val);
365: break;
366: case 9:
367: set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
368: break;
369: case 10:
370: s->sr = val;
371: break;
372: case 11:
373: s->acr = val;
374: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
375: cuda_update(s);
376: break;
377: case 12:
378: s->pcr = val;
379: break;
380: case 13:
381:
382: s->ifr &= ~val;
383: cuda_update_irq(s);
384: break;
385: case 14:
386: if (val & IER_SET) {
387:
388: s->ier |= val & 0x7f;
389: } else {
390:
391: s->ier &= ~val;
392: }
393: cuda_update_irq(s);
394: break;
395: default:
396: case 15:
397: s->anh = val;
398: break;
399: }
400: }
401:
402:
403: static void cuda_update(CUDAState *s)
404: {
405: int packet_received, len;
406:
407: packet_received = 0;
408: if (!(s->b & TIP)) {
409:
410:
411: if (s->acr & SR_OUT) {
412:
413: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
414: if (s->data_out_index < sizeof(s->data_out)) {
415: #ifdef DEBUG_CUDA
416: printf("cuda: send: %02x\n", s->sr);
417: #endif
418: s->data_out[s->data_out_index++] = s->sr;
419: s->ifr |= SR_INT;
420: cuda_update_irq(s);
421: }
422: }
423: } else {
424: if (s->data_in_index < s->data_in_size) {
425:
426: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
427: s->sr = s->data_in[s->data_in_index++];
428: #ifdef DEBUG_CUDA
429: printf("cuda: recv: %02x\n", s->sr);
430: #endif
431:
432: if (s->data_in_index >= s->data_in_size) {
433: s->b = (s->b | TREQ);
434: }
435: s->ifr |= SR_INT;
436: cuda_update_irq(s);
437: }
438: }
439: }
440: } else {
441:
442: if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
443:
444: if (s->b & TACK)
445: s->b = (s->b | TREQ);
446: else
447: s->b = (s->b & ~TREQ);
448: s->ifr |= SR_INT;
449: cuda_update_irq(s);
450: } else {
451: if (!(s->last_b & TIP)) {
452:
453: packet_received = (s->data_out_index > 0);
454:
455: s->ifr |= SR_INT;
456: cuda_update_irq(s);
457: }
458:
459: if (s->data_in_index < s->data_in_size) {
460: s->b = (s->b & ~TREQ);
461: }
462: }
463: }
464:
465: s->last_acr = s->acr;
466: s->last_b = s->b;
467:
468:
469:
470: if (packet_received) {
471: len = s->data_out_index;
472: s->data_out_index = 0;
473: cuda_receive_packet_from_host(s, s->data_out, len);
474: }
475: }
476:
477: static void cuda_send_packet_to_host(CUDAState *s,
478: const uint8_t *data, int len)
479: {
480: #ifdef DEBUG_CUDA_PACKET
481: {
482: int i;
483: printf("cuda_send_packet_to_host:\n");
484: for(i = 0; i < len; i++)
485: printf(" %02x", data[i]);
486: printf("\n");
487: }
488: #endif
489: memcpy(s->data_in, data, len);
490: s->data_in_size = len;
491: s->data_in_index = 0;
492: cuda_update(s);
493: s->ifr |= SR_INT;
494: cuda_update_irq(s);
495: }
496:
497: static void cuda_adb_poll(void *opaque)
498: {
499: CUDAState *s = opaque;
500: uint8_t obuf[ADB_MAX_OUT_LEN + 2];
501: int olen;
502:
503: olen = adb_poll(&adb_bus, obuf + 2);
504: if (olen > 0) {
505: obuf[0] = ADB_PACKET;
506: obuf[1] = 0x40;
507: cuda_send_packet_to_host(s, obuf, olen + 2);
508: }
509: qemu_mod_timer(s->adb_poll_timer,
510: qemu_get_clock(vm_clock) +
511: (ticks_per_sec / CUDA_ADB_POLL_FREQ));
512: }
513:
514: static void cuda_receive_packet(CUDAState *s,
515: const uint8_t *data, int len)
516: {
517: uint8_t obuf[16];
518: int ti, autopoll;
519:
520: switch(data[0]) {
521: case CUDA_AUTOPOLL:
522: autopoll = (data[1] != 0);
523: if (autopoll != s->autopoll) {
524: s->autopoll = autopoll;
525: if (autopoll) {
526: qemu_mod_timer(s->adb_poll_timer,
527: qemu_get_clock(vm_clock) +
528: (ticks_per_sec / CUDA_ADB_POLL_FREQ));
529: } else {
530: qemu_del_timer(s->adb_poll_timer);
531: }
532: }
533: obuf[0] = CUDA_PACKET;
534: obuf[1] = data[1];
535: cuda_send_packet_to_host(s, obuf, 2);
536: break;
537: case CUDA_GET_TIME:
538: case CUDA_SET_TIME:
539:
540: ti = time(NULL) + RTC_OFFSET;
541: obuf[0] = CUDA_PACKET;
542: obuf[1] = 0;
543: obuf[2] = 0;
544: obuf[3] = ti >> 24;
545: obuf[4] = ti >> 16;
546: obuf[5] = ti >> 8;
547: obuf[6] = ti;
548: cuda_send_packet_to_host(s, obuf, 7);
549: break;
550: case CUDA_FILE_SERVER_FLAG:
551: case CUDA_SET_DEVICE_LIST:
552: case CUDA_SET_AUTO_RATE:
553: case CUDA_SET_POWER_MESSAGES:
554: obuf[0] = CUDA_PACKET;
555: obuf[1] = 0;
556: cuda_send_packet_to_host(s, obuf, 2);
557: break;
558: case CUDA_POWERDOWN:
559: