|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * CIA chip support
5: *
6: * Copyright 1995 Bernd Schmidt, Alessandro Bissacco
7: */
8:
9: #include <stdio.h>
10: #include <assert.h>
11: #include <time.h>
12:
13: #include "config.h"
14: #include "amiga.h"
15: #include "options.h"
16: #include "events.h"
17: #include "memory.h"
18: #include "custom.h"
19: #include "cia.h"
20: #include "disk.h"
21: #include "xwin.h"
22: #include "keybuf.h"
23:
24: #define DIV10 5 /* Yes, a bad identifier. */
25:
26: static UBYTE ciaaicr,ciaaimask,ciabicr,ciabimask;
27: static UBYTE ciaacra,ciaacrb,ciabcra,ciabcrb;
28: static ULONG ciaata,ciaatb,ciabta,ciabtb;
29: static UWORD ciaala,ciaalb,ciabla,ciablb;
30: static ULONG ciaatod,ciabtod,ciaatol,ciabtol,ciaaalarm,ciabalarm;
31: static bool ciaatlatch,ciabtlatch;
32: static UBYTE ciaapra,ciaaprb,ciaadra,ciaadrb,ciaasdr;
33: static UBYTE ciabpra,ciabprb,ciabdra,ciabdrb,ciabsdr;
34: static int div10;
35: static int kbstate;
36: static bool kback;
37:
38: static void setclr(UBYTE *p, UBYTE val)
39: {
40: if (val & 0x80) {
41: *p |= val & 0x7F;
42: } else {
43: *p &= ~val;
44: }
45: }
46:
47: static void RethinkICRA(void)
48: {
49: if (ciaaimask & ciaaicr) {
50: ciaaicr |= 0x80;
51: custom_bank.wput(0xDFF09C,0x8008);
52: } else {
53: ciaaicr &= 0x7F;
54: custom_bank.wput(0xDFF09C,0x0008);
55: }
56: }
57:
58: static void RethinkICRB(void)
59: {
60: if (ciabimask & ciabicr) {
61: ciabicr |= 0x80;
62: custom_bank.wput(0xDFF09C,0xA000);
63: } else {
64: ciabicr &= 0x7F;
65: custom_bank.wput(0xDFF09C,0x2000);
66: }
67: }
68:
69: static int lastdiv10;
70:
71: static void CIA_update(void)
72: {
73: unsigned long int ccount = cycles - eventtab[ev_cia].oldcycles + lastdiv10;
74: unsigned long int ciaclocks = ccount / DIV10;
75:
76: int aovfla = 0, aovflb = 0, bovfla = 0, bovflb = 0;
77:
78: lastdiv10 = div10;
79: div10 = ccount % DIV10;
80:
81: /* CIA A timers */
82: if ((ciaacra & 0x21) == 0x01) {
83: assert((ciaata+1) >= ciaclocks);
84: if ((ciaata+1) == ciaclocks) {
85: aovfla = 1;
86: if ((ciaacrb & 0x61) == 0x41) {
87: if (ciaatb-- == 0) aovflb = 1;
88: }
89: }
90: ciaata -= ciaclocks;
91: }
92: if ((ciaacrb & 0x61) == 0x01) {
93: assert((ciaatb+1) >= ciaclocks);
94: if ((ciaatb+1) == ciaclocks) aovflb = 1;
95: ciaatb -= ciaclocks;
96: }
97:
98: /* CIA B timers */
99: if ((ciabcra & 0x21) == 0x01) {
100: assert((ciabta+1) >= ciaclocks);
101: if ((ciabta+1) == ciaclocks) {
102: bovfla = 1;
103: if ((ciabcrb & 0x61) == 0x41) {
104: if (ciabtb-- == 0) bovflb = 1;
105: }
106: }
107: ciabta -= ciaclocks;
108: }
109: if ((ciabcrb & 0x61) == 0x01) {
110: assert ((ciabtb+1) >= ciaclocks);
111: if ((ciabtb+1) == ciaclocks) bovflb = 1;
112: ciabtb -= ciaclocks;
113: }
114: if (aovfla) {
115: ciaaicr |= 1; RethinkICRA();
116: ciaata = ciaala;
117: if (ciaacra & 0x8) ciaacra &= ~1;
118: }
119: if (aovflb) {
120: ciaaicr |= 2; RethinkICRA();
121: ciaatb = ciaalb;
122: if (ciaacrb & 0x8) ciaacrb &= ~1;
123: }
124: if (bovfla) {
125: ciabicr |= 1; RethinkICRB();
126: ciabta = ciabla;
127: if (ciabcra & 0x8) ciabcra &= ~1;
128: }
129: if (bovflb) {
130: ciabicr |= 2; RethinkICRA();
131: ciabtb = ciablb;
132: if (ciabcrb & 0x8) ciabcrb &= ~1;
133: }
134: }
135:
136: static void CIA_calctimers(void)
137: {
138: int ciaatimea = -1, ciaatimeb = -1, ciabtimea = -1, ciabtimeb = -1;
139:
140: eventtab[ev_cia].oldcycles = cycles;
141:
142: if ((ciaacra & 0x21) == 0x01) {
143: ciaatimea = (DIV10-div10) + DIV10*ciaata;
144: }
145: if ((ciaacrb & 0x61) == 0x41) {
146: /* Timer B will not get any pulses if Timer A is off. */
147: if (ciaatimea >= 0) {
148: /* If Timer A is in one-shot mode, and Timer B needs more than
149: * one pulse, it will not underflow. */
150: if (ciaatb == 0 || (ciaacra & 0x8) == 0) {
151: /* Otherwise, we can determine the time of the underflow. */
152: ciaatimeb = ciaatimea + ciaala * DIV10 * ciaatb;
153: }
154: }
155: }
156: if ((ciaacrb & 0x61) == 0x01) {
157: ciaatimeb = (DIV10-div10) + DIV10*ciaatb;
158: }
159:
160: if ((ciabcra & 0x21) == 0x01) {
161: ciabtimea = (DIV10-div10) + DIV10*ciabta;
162: }
163: if ((ciabcrb & 0x61) == 0x41) {
164: /* Timer B will not get any pulses if Timer A is off. */
165: if (ciabtimea >= 0) {
166: /* If Timer A is in one-shot mode, and Timer B needs more than
167: * one pulse, it will not underflow. */
168: if (ciabtb == 0 || (ciabcra & 0x8) == 0) {
169: /* Otherwise, we can determine the time of the underflow. */
170: ciabtimeb = ciabtimea + ciabla * DIV10 * ciabtb;
171: }
172: }
173: }
174: if ((ciabcrb & 0x61) == 0x01) {
175: ciabtimeb = (DIV10-div10) + DIV10*ciabtb;
176: }
177: eventtab[ev_cia].active = (ciaatimea != -1 || ciaatimeb != -1
178: || ciabtimea != -1 || ciabtimeb != -1);
179: if (eventtab[ev_cia].active) {
180: unsigned long int ciatime = ~0L;
181: if (ciaatimea != -1) ciatime = ciaatimea;
182: if (ciaatimeb != -1 && ciaatimeb < ciatime) ciatime = ciaatimeb;
183: if (ciabtimea != -1 && ciabtimea < ciatime) ciatime = ciabtimea;
184: if (ciabtimeb != -1 && ciabtimeb < ciatime) ciatime = ciabtimeb;
185: eventtab[ev_cia].evtime = ciatime;
186: }
187: events_schedule();
188: }
189:
190: void CIA_handler(void)
191: {
192: CIA_update();
193: CIA_calctimers();
194: }
195:
196: void CIA_hsync_handler(void)
197: {
198: static int keytime = 0;
199:
200: ciabtod++;
201: ciabtod &= 0xFFFFFF;
202: if (ciabtod == ciabalarm) {
203: ciabicr |= 4; RethinkICRB();
204: }
205: if (keys_available() && kback && (++keytime & 15) == 0) {
206: switch(kbstate) {
207: case 0:
208: ciaasdr = (BYTE)~0xFB; /* aaarghh... stupid compiler */
209: kbstate++;
210: break;
211: case 1:
212: kbstate++;
213: ciaasdr = (BYTE)~0xFD;
214: break;
215: case 2:
216: ciaasdr = ~get_next_key();
217: break;
218: }
219: ciaaicr |= 8; RethinkICRA();
220: }
221: }
222:
223: void CIA_vsync_handler()
224: {
225: ciaatod++;
226: ciaatod &= 0xFFFFFF;
227: if (ciaatod == ciaaalarm) {
228: ciaaicr |= 4; RethinkICRA();
229: }
230: }
231:
232: static UBYTE ReadCIAA(UWORD addr)
233: {
234: UBYTE tmp;
235:
236: switch(addr & 0xf){
237: case 0:
238: tmp = (DISK_status() & 0x3C);
239: if (!buttonstate[0]) tmp |= 0x40;
240: if (!buttonstate[1]) tmp |= 0x80;
241: return tmp;
242: case 1:
243: return ciaaprb;
244: case 2:
245: return ciaadra;
246: case 3:
247: return ciaadrb;
248: case 4:
249: return ciaata & 0xff;
250: case 5:
251: return ciaata >> 8;
252: case 6:
253: return ciaatb & 0xff;
254: case 7:
255: return ciaatb >> 8;
256: case 8:
257: if (ciaatlatch) {
258: ciaatlatch = 0;
259: return ciaatol & 0xff;
260: } else return ciaatod & 0xff;
261: case 9:
262: if (ciaatlatch) return (ciaatol >> 8) & 0xff;
263: else return (ciaatod >> 8) & 0xff;
264: case 10:
265: ciaatlatch = 1; ciaatol = ciaatod; /* ??? only if not already latched? */
266: return (ciaatol >> 16) & 0xff;
267: case 12:
268: return ciaasdr;
269: case 13:
270: tmp = ciaaicr; ciaaicr = 0; RethinkICRA(); return tmp;
271: case 14:
272: return ciaacra;
273: case 15:
274: return ciaacrb;
275: }
276: return 0;
277: }
278:
279: static UBYTE ReadCIAB(UWORD addr)
280: {
281: UBYTE tmp;
282:
283: switch(addr & 0xf){
284: case 0:
285: return ciabpra;
286: case 1:
287: return ciabprb;
288: case 2:
289: return ciabdra;
290: case 3:
291: return ciabdrb;
292: case 4:
293: return ciabta & 0xff;
294: case 5:
295: return ciabta >> 8;
296: case 6:
297: return ciabtb & 0xff;
298: case 7:
299: return ciabtb >> 8;
300: case 8:
301: if (ciabtlatch) {
302: ciabtlatch = 0;
303: return ciabtol & 0xff;
304: } else return ciabtod & 0xff;
305: case 9:
306: if (ciabtlatch) return (ciabtol >> 8) & 0xff;
307: else return (ciabtod >> 8) & 0xff;
308: case 10:
309: ciabtlatch = 1; ciabtol = ciabtod;
310: return (ciabtol >> 16) & 0xff;
311: case 12:
312: return ciabsdr;
313: case 13:
314: tmp = ciabicr; ciabicr = 0; RethinkICRB();
315: if (!dskdmaen)
316: if (indexpulse == 0){
317: tmp |= 0x10;
318: DISK_Index();
319: indexpulse = 100; /* whatever */
320: } else {
321: indexpulse--;
322: }
323: return tmp;
324: case 14:
325: return ciabcra;
326: case 15:
327: return ciabcrb;
328: }
329: return 0;
330: }
331:
332: static void WriteCIAA(UWORD addr,UBYTE val)
333: {
334: switch(addr & 0xf){
335: case 0:
336: ciaapra = (ciaapra & ~0x3) | (val & 0x3); LED(ciaapra & 0x2); break;
337: case 1:
338: ciaaprb = val; break;
339: case 2:
340: ciaadra = val; break;
341: case 3:
342: ciaadrb = val; break;
343: case 4:
344: CIA_update();
345: ciaala = (ciaala & 0xff00) | val;
346: CIA_calctimers();
347: break;
348: case 5:
349: CIA_update();
350: ciaala = (ciaala & 0xff) | (val << 8);
351: if ((ciaacra & 1) == 0) {
352: ciaata = ciaala;
353: }
354: if (ciaacra & 8) {
355: ciaata = ciaala;
356: ciaacra |= 1;
357: }/*??? load latch always? */
358: CIA_calctimers();
359: break;
360: case 6:
361: CIA_update();
362: ciaalb = (ciaalb & 0xff00) | val;
363: CIA_calctimers();
364: break;
365: case 7:
366: CIA_update();
367: ciaalb = (ciaalb & 0xff) | (val << 8);
368: if ((ciaacrb & 1) == 0) ciaatb = ciaalb;
369: if (ciaacrb & 8) { ciaatb = ciaalb; ciaacrb |= 1; }
370: CIA_calctimers();
371: break;
372: case 8:
373: if (ciaacrb & 0x80){
374: ciaaalarm = (ciaaalarm & ~0xff) | val;
375: } else {
376: ciaatod = (ciaatod & ~0xff) | val;
377: }
378: break;
379: case 9:
380: if (ciaacrb & 0x80){
381: ciaaalarm = (ciaaalarm & ~0xff00) | (val << 8);
382: } else {
383: ciaatod = (ciaatod & ~0xff00) | (val << 8);
384: }
385: break;
386: case 10:
387: if (ciaacrb & 0x80){
388: ciaaalarm = (ciaaalarm & ~0xff0000) | (val << 16);
389: } else {
390: ciaatod = (ciaatod & ~0xff0000) | (val << 16);
391: }
392: break;
393: case 12:
394: ciaasdr = val; break;
395: case 13:
396: setclr(&ciaaimask,val); break; /* ??? call RethinkICR() ? */
397: case 14:
398: CIA_update();
399: ciaacra = val;
400: if (ciaacra & 0x10){
401: ciaacra &= ~0x10;
402: ciaata = ciaala;
403: }
404: if (ciaacra & 0x40) {
405: kback = true;
406: }
407: CIA_calctimers();
408: break;
409: case 15:
410: CIA_update();
411: ciaacrb = val;
412: if (ciaacrb & 0x10){
413: ciaacrb &= ~0x10;
414: ciaatb = ciaalb;
415: }
416: CIA_calctimers();
417: break;
418: }
419: }
420:
421: static void WriteCIAB(UWORD addr,UBYTE val)
422: {
423: switch(addr & 0xf){
424: case 0:
425: ciabpra = (ciabpra & ~0x3) | (val & 0x3); break;
426: case 1:
427: ciabprb = val; DISK_select(val); break;
428: case 2:
429: ciabdra = val; break;
430: case 3:
431: ciabdrb = val; break;
432: case 4:
433: CIA_update();
434: ciabla = (ciabla & 0xff00) | val;
435: CIA_calctimers();
436: break;
437: case 5:
438: CIA_update();
439: ciabla = (ciabla & 0xff) | (val << 8);
440: if ((ciabcra & 1) == 0) ciabta = ciabla;
441: if (ciabcra & 8) { ciabta = ciabla; ciabcra |= 1; }
442: CIA_calctimers();
443: break;
444: case 6:
445: CIA_update();
446: ciablb = (ciablb & 0xff00) | val;
447: CIA_calctimers();
448: break;
449: case 7:
450: CIA_update();
451: ciablb = (ciablb & 0xff) | (val << 8);
452: if ((ciabcrb & 1) == 0) ciabtb = ciablb;
453: if (ciabcrb & 8) { ciabtb = ciablb; ciabcrb |= 1; }
454: CIA_calctimers();
455: break;
456: case 8:
457: if (ciabcrb & 0x80){
458: ciabalarm = (ciabalarm & ~0xff) | val;
459: } else {
460: ciabtod = (ciabtod & ~0xff) | val;
461: }
462: break;
463: case 9:
464: if (ciabcrb & 0x80){
465: ciabalarm = (ciabalarm & ~0xff00) | (val << 8);
466: } else {
467: ciabtod = (ciabtod & ~0xff00) | (val << 8);
468: }
469: break;
470: case 10:
471: if (ciabcrb & 0x80){
472: ciabalarm = (ciabalarm & ~0xff0000) | (val << 16);
473: } else {
474: ciabtod = (ciabtod & ~0xff0000) | (val << 16);
475: }
476: break;
477: case 12:
478: ciabsdr = val;
479: break;
480: case 13:
481: setclr(&ciabimask,val);
482: break;
483: case 14:
484: CIA_update();
485: ciabcra = val;
486: if (ciabcra & 0x10){
487: ciabcra &= ~0x10;
488: ciabta = ciabla;
489: }
490: CIA_calctimers();
491: break;
492: case 15:
493: CIA_update();
494: ciabcrb = val;
495: if (ciabcrb & 0x10){
496: ciabcrb &= ~0x10;
497: ciabtb = ciablb;
498: }
499: CIA_calctimers();
500: break;
501: }
502: }
503:
504: void CIA_reset(void)
505: {
506: kback = true;
507: kbstate = 0;
508:
509: ciaatlatch = ciabtlatch = 0;
510: ciaatod = ciabtod = 0;
511: ciaaicr = ciabicr = ciaaimask = ciabimask = 0;
512: ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; /* outmode = toggle; */
513: div10 = 0;
514: lastdiv10 = 0;
515: CIA_calctimers();
516: }
517:
518: void dumpcia(void)
519: {
520: printf("A: CRA: %02x, CRB: %02x, IMASK: %02x, TOD: %08lx %7s TA: %04lx, TB: %04lx\n",
521: (int)ciaacra, (int)ciaacrb, (int)ciaaimask, ciaatod,
522: ciaatlatch ? " latched" : "", ciaata, ciaatb);
523: printf("B: CRA: %02x, CRB: %02x, IMASK: %02x, TOD: %08lx %7s TA: %04lx, TB: %04lx\n",
524: (int)ciabcra, (int)ciabcrb, (int)ciabimask, ciabtod,
525: ciabtlatch ? " latched" : "", ciabta, ciabtb);
526: }
527:
528: /* CIA memory access */
529:
530: static ULONG cia_lget(CPTR) REGPARAM;
531: static UWORD cia_wget(CPTR) REGPARAM;
532: static UBYTE cia_bget(CPTR) REGPARAM;
533: static void cia_lput(CPTR, ULONG) REGPARAM;
534: static void cia_wput(CPTR, UWORD) REGPARAM;
535: static void cia_bput(CPTR, UBYTE) REGPARAM;
536:
537: addrbank cia_bank = {
538: cia_lget, cia_wget, cia_bget,
539: cia_lput, cia_wput, cia_bput,
540: default_xlate, default_check
541: };
542:
543: ULONG cia_lget(CPTR addr)
544: {
545: return cia_bget(addr+3);
546: }
547:
548: UWORD cia_wget(CPTR addr)
549: {
550: return cia_bget(addr+1);
551: }
552:
553: UBYTE cia_bget(CPTR addr)
554: {
555: #ifdef DUALCPU
556: customacc = true;
557: #endif
558: if ((addr & 0xF0FF) == 0xE001)
559: return ReadCIAA((addr & 0xF00) >> 8);
560: if ((addr & 0xF0FF) == 0xD000)
561: return ReadCIAB((addr & 0xF00) >> 8);
562: return 0;
563: }
564:
565: void cia_lput(CPTR addr, ULONG value)
566: {
567: cia_bput(addr+3,value); /* FIXME ? */
568: }
569:
570: void cia_wput(CPTR addr, UWORD value)
571: {
572: cia_bput(addr+1,value);
573: }
574:
575: void cia_bput(CPTR addr, UBYTE value)
576: {
577: #ifdef DUALCPU
578: customacc = true;
579: #endif
580: if ((addr & 0xF0FF) == 0xE001)
581: WriteCIAA((addr & 0xF00) >> 8,value);
582: if ((addr & 0xF0FF) == 0xD000)
583: WriteCIAB((addr & 0xF00) >> 8,value);
584: }
585:
586: /* battclock memory access */
587:
588: static ULONG clock_lget(CPTR) REGPARAM;
589: static UWORD clock_wget(CPTR) REGPARAM;
590: static UBYTE clock_bget(CPTR) REGPARAM;
591: static void clock_lput(CPTR, ULONG) REGPARAM;
592: static void clock_wput(CPTR, UWORD) REGPARAM;
593: static void clock_bput(CPTR, UBYTE) REGPARAM;
594:
595: addrbank clock_bank = {
596: clock_lget, clock_wget, clock_bget,
597: clock_lput, clock_wput, clock_bput,
598: default_xlate, default_check
599: };
600:
601: ULONG clock_lget(CPTR addr)
602: {
603: return clock_bget(addr+3);
604: }
605:
606: UWORD clock_wget(CPTR addr)
607: {
608: return clock_bget(addr+1);
609: }
610:
611: UBYTE clock_bget(CPTR addr)
612: {
613: #ifdef DUALCPU
614: customacc = true;
615: #endif
616:
617: time_t t=time(0);
618: struct tm *ct;
619: ct=localtime(&t);
620: switch (addr & 0x3f)
621: {
622: case 0x03: return ct->tm_sec % 10;
623: case 0x07: return ct->tm_sec / 10;
624: case 0x0b: return ct->tm_min % 10;
625: case 0x0f: return ct->tm_min / 10;
626: case 0x13: return ct->tm_hour % 10;
627: case 0x17: return ct->tm_hour / 10;
628: case 0x1b: return ct->tm_mday % 10;
629: case 0x1f: return ct->tm_mday / 10;
630: case 0x23: return (ct->tm_mon+1) % 10;
631: case 0x27: return (ct->tm_mon+1) / 10;
632: case 0x2b: return ct->tm_year % 10;
633: case 0x2f: return ct->tm_year / 10;
634: }
635: return 0;
636: }
637:
638: void clock_lput(CPTR addr, ULONG value)
639: {
640: /* No way */
641: }
642:
643: void clock_wput(CPTR addr, UWORD value)
644: {
645: /* No way */
646: }
647:
648: void clock_bput(CPTR addr, UBYTE value)
649: {
650: /* No way */
651: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.