|
1 | 1 |
|
2 |
| -//cRSID CIA emulation |
3 |
| - |
4 |
| - |
5 |
| -void cRSID_createCIAchip (cRSID_C64instance* C64, cRSID_CIAinstance* CIA, unsigned short baseaddress) { |
6 |
| - CIA->C64 = C64; |
7 |
| - CIA->ChipModel = 0; |
8 |
| - CIA->BaseAddress = baseaddress; |
9 |
| - CIA->BasePtrWR = &C64->IObankWR[baseaddress]; CIA->BasePtrRD = &C64->IObankRD[baseaddress]; |
10 |
| - cRSID_initCIAchip(CIA); |
| 2 | +// cRSID CIA emulation |
| 3 | + |
| 4 | +void cRSID_createCIAchip(cRSID_C64instance *C64, cRSID_CIAinstance *CIA, unsigned short baseaddress) |
| 5 | +{ |
| 6 | + CIA->C64 = C64; |
| 7 | + CIA->ChipModel = 0; |
| 8 | + CIA->BaseAddress = baseaddress; |
| 9 | + CIA->BasePtrWR = &C64->IObankWR[baseaddress]; |
| 10 | + CIA->BasePtrRD = &C64->IObankRD[baseaddress]; |
| 11 | + cRSID_initCIAchip(CIA); |
11 | 12 | }
|
12 | 13 |
|
13 |
| - |
14 |
| -void cRSID_initCIAchip (cRSID_CIAinstance* CIA) { |
15 |
| - unsigned char i; |
16 |
| - for (i=0; i<0x10; ++i) CIA->BasePtrWR[i] = CIA->BasePtrRD[i] = 0x00; |
| 14 | +void cRSID_initCIAchip(cRSID_CIAinstance *CIA) |
| 15 | +{ |
| 16 | + unsigned char i; |
| 17 | + for (i = 0; i < 0x10; ++i) |
| 18 | + CIA->BasePtrWR[i] = CIA->BasePtrRD[i] = 0x00; |
17 | 19 | }
|
18 | 20 |
|
19 |
| - |
20 |
| -static inline char cRSID_emulateCIA (cRSID_CIAinstance* CIA, char cycles) { |
21 |
| - static int Tmp; |
22 |
| - |
23 |
| - enum CIAregisters { PORTA=0, PORTB=1, DDRA=2, DDRB=3, |
24 |
| - TIMERAL=4, TIMERAH=5, TIMERBL=6, TIMERBH=7, //Write:Set Timer-latch, Read: read Timer |
25 |
| - TOD_TENTHSECONDS=8, TOD_SECONDS=9, TOD_MINUTES=0xA, TOD_HOURS=0xB, |
26 |
| - SERIAL_DATA=0xC, INTERRUPTS=0xD, CONTROLA=0xE, CONTROLB=0xF }; |
27 |
| - |
28 |
| - enum InterruptBitVal { INTERRUPT_HAPPENED=0x80, SET_OR_CLEAR_FLAGS=0x80, //(Read or Write operation determines which one:) |
29 |
| - FLAGn=0x10, SERIALPORT=0x08, ALARM=0x04, TIMERB=0x02, TIMERA=0x01 }; //flags/masks of interrupt-sources |
30 |
| - |
31 |
| - enum ControlAbitVal { ENABLE_TIMERA=0x01, PORTB6_TIMERA=0x02, TOGGLED_PORTB6=0x04, ONESHOT_TIMERA=0x08, |
32 |
| - FORCELOADA_STROBE=0x10, TIMERA_FROM_CNT=0x20, SERIALPORT_IS_OUTPUT=0x40, TIMEOFDAY_50Hz=0x80 }; |
33 |
| - |
34 |
| - enum ControlBbitVal { ENABLE_TIMERB=0x01, PORTB7_TIMERB=0x02, TOGGLED_PORTB7=0x04, ONESHOT_TIMERB=0x08, |
35 |
| - FORCELOADB_STROBE=0x10, TIMERB_FROM_CPUCLK=0x00, TIMERB_FROM_CNT=0x20, TIMERB_FROM_TIMERA=0x40, |
36 |
| - TIMERB_FROM_TIMERA_AND_CNT = 0x60, TIMEOFDAY_WRITE_SETS_ALARM = 0x80 }; |
37 |
| - |
38 |
| - //TimerA |
39 |
| - if (CIA->BasePtrWR[CONTROLA] & FORCELOADA_STROBE) { //force latch into counter (strobe-input) |
40 |
| - CIA->BasePtrRD[TIMERAH] = CIA->BasePtrWR[TIMERAH]; CIA->BasePtrRD[TIMERAL] = CIA->BasePtrWR[TIMERAL]; |
41 |
| - } |
42 |
| - else if ( (CIA->BasePtrWR[CONTROLA] & (ENABLE_TIMERA|TIMERA_FROM_CNT)) == ENABLE_TIMERA ) { //Enabled, counts Phi2 |
43 |
| - Tmp = ( (CIA->BasePtrRD[TIMERAH]<<8) + CIA->BasePtrRD[TIMERAL] ) - cycles; //count timer |
44 |
| - if (Tmp <= 0) { //Timer counted down |
45 |
| - Tmp += (CIA->BasePtrWR[TIMERAH]<<8) + CIA->BasePtrWR[TIMERAL]; //reload timer |
46 |
| - if (CIA->BasePtrWR[CONTROLA] & ONESHOT_TIMERA) CIA->BasePtrWR[CONTROLA] &= ~ENABLE_TIMERA; //disable if one-shot |
47 |
| - CIA->BasePtrRD[INTERRUPTS] |= TIMERA; |
48 |
| - if (CIA->BasePtrWR[INTERRUPTS] & TIMERA) { //generate interrupt if mask allows |
49 |
| - CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED; |
50 |
| - } |
51 |
| - } |
52 |
| - CIA->BasePtrRD[TIMERAH] = (Tmp >> 8); CIA->BasePtrRD[TIMERAL] = Tmp & 0xFF; |
53 |
| - } |
54 |
| - CIA->BasePtrWR[CONTROLA] &= ~FORCELOADA_STROBE; //strobe is edge-sensitive |
55 |
| - CIA->BasePtrRD[CONTROLA] = CIA->BasePtrWR[CONTROLA]; //control-registers are readable |
56 |
| - |
57 |
| - //TimerB |
58 |
| - if (CIA->BasePtrWR[CONTROLB] & FORCELOADB_STROBE) { //force latch into counter (strobe-input) |
59 |
| - CIA->BasePtrRD[TIMERBH] = CIA->BasePtrWR[TIMERBH]; CIA->BasePtrRD[TIMERBL] = CIA->BasePtrWR[TIMERBL]; |
60 |
| - } //what about clocking TimerB by TimerA? (maybe not used in any music) |
61 |
| - else if ( (CIA->BasePtrWR[CONTROLB] & (ENABLE_TIMERB|TIMERB_FROM_TIMERA)) == ENABLE_TIMERB ) { //Enabled, counts Phi2 |
62 |
| - Tmp = ( (CIA->BasePtrRD[TIMERBH]<<8) + CIA->BasePtrRD[TIMERBL] ) - cycles;//count timer |
63 |
| - if (Tmp <= 0) { //Timer counted down |
64 |
| - Tmp += (CIA->BasePtrWR[TIMERBH]<<8) + CIA->BasePtrWR[TIMERBL]; //reload timer |
65 |
| - if (CIA->BasePtrWR[CONTROLB] & ONESHOT_TIMERB) CIA->BasePtrWR[CONTROLB] &= ~ENABLE_TIMERB; //disable if one-shot |
66 |
| - CIA->BasePtrRD[INTERRUPTS] |= TIMERB; |
67 |
| - if (CIA->BasePtrWR[INTERRUPTS] & TIMERB) { //generate interrupt if mask allows |
68 |
| - CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED; |
69 |
| - } |
70 |
| - } |
71 |
| - CIA->BasePtrRD[TIMERBH] = (Tmp >> 8); CIA->BasePtrRD[TIMERBL] = Tmp & 0xFF; |
72 |
| - } |
73 |
| - CIA->BasePtrWR[CONTROLB] &= ~FORCELOADB_STROBE; //strobe is edge-sensitive |
74 |
| - CIA->BasePtrRD[CONTROLB] = CIA->BasePtrWR[CONTROLB]; //control-registers are readable |
75 |
| - |
76 |
| - return (CIA->BasePtrRD[INTERRUPTS] & INTERRUPT_HAPPENED); |
| 21 | +static inline char cRSID_emulateCIA(cRSID_CIAinstance *CIA, char cycles) |
| 22 | +{ |
| 23 | + static int Tmp; |
| 24 | + |
| 25 | + enum CIAregisters |
| 26 | + { |
| 27 | + PORTA = 0, |
| 28 | + PORTB = 1, |
| 29 | + DDRA = 2, |
| 30 | + DDRB = 3, |
| 31 | + TIMERAL = 4, |
| 32 | + TIMERAH = 5, |
| 33 | + TIMERBL = 6, |
| 34 | + TIMERBH = 7, // Write:Set Timer-latch, Read: read Timer |
| 35 | + TOD_TENTHSECONDS = 8, |
| 36 | + TOD_SECONDS = 9, |
| 37 | + TOD_MINUTES = 0xA, |
| 38 | + TOD_HOURS = 0xB, |
| 39 | + SERIAL_DATA = 0xC, |
| 40 | + INTERRUPTS = 0xD, |
| 41 | + CONTROLA = 0xE, |
| 42 | + CONTROLB = 0xF |
| 43 | + }; |
| 44 | + |
| 45 | + enum InterruptBitVal |
| 46 | + { |
| 47 | + INTERRUPT_HAPPENED = 0x80, |
| 48 | + SET_OR_CLEAR_FLAGS = 0x80, //(Read or Write operation determines which one:) |
| 49 | + FLAGn = 0x10, |
| 50 | + SERIALPORT = 0x08, |
| 51 | + ALARM = 0x04, |
| 52 | + TIMERB = 0x02, |
| 53 | + TIMERA = 0x01 |
| 54 | + }; // flags/masks of interrupt-sources |
| 55 | + |
| 56 | + enum ControlAbitVal |
| 57 | + { |
| 58 | + ENABLE_TIMERA = 0x01, |
| 59 | + PORTB6_TIMERA = 0x02, |
| 60 | + TOGGLED_PORTB6 = 0x04, |
| 61 | + ONESHOT_TIMERA = 0x08, |
| 62 | + FORCELOADA_STROBE = 0x10, |
| 63 | + TIMERA_FROM_CNT = 0x20, |
| 64 | + SERIALPORT_IS_OUTPUT = 0x40, |
| 65 | + TIMEOFDAY_50Hz = 0x80 |
| 66 | + }; |
| 67 | + |
| 68 | + enum ControlBbitVal |
| 69 | + { |
| 70 | + ENABLE_TIMERB = 0x01, |
| 71 | + PORTB7_TIMERB = 0x02, |
| 72 | + TOGGLED_PORTB7 = 0x04, |
| 73 | + ONESHOT_TIMERB = 0x08, |
| 74 | + FORCELOADB_STROBE = 0x10, |
| 75 | + TIMERB_FROM_CPUCLK = 0x00, |
| 76 | + TIMERB_FROM_CNT = 0x20, |
| 77 | + TIMERB_FROM_TIMERA = 0x40, |
| 78 | + TIMERB_FROM_TIMERA_AND_CNT = 0x60, |
| 79 | + TIMEOFDAY_WRITE_SETS_ALARM = 0x80 |
| 80 | + }; |
| 81 | + |
| 82 | + // TimerA |
| 83 | + if (CIA->BasePtrWR[CONTROLA] & FORCELOADA_STROBE) |
| 84 | + { // force latch into counter (strobe-input) |
| 85 | + CIA->BasePtrRD[TIMERAH] = CIA->BasePtrWR[TIMERAH]; |
| 86 | + CIA->BasePtrRD[TIMERAL] = CIA->BasePtrWR[TIMERAL]; |
| 87 | + } |
| 88 | + else if ((CIA->BasePtrWR[CONTROLA] & (ENABLE_TIMERA | TIMERA_FROM_CNT)) == ENABLE_TIMERA) |
| 89 | + { // Enabled, counts Phi2 |
| 90 | + Tmp = ((CIA->BasePtrRD[TIMERAH] << 8) + CIA->BasePtrRD[TIMERAL]) - cycles; // count timer |
| 91 | + if (Tmp <= 0) |
| 92 | + { // Timer counted down |
| 93 | + Tmp += (CIA->BasePtrWR[TIMERAH] << 8) + CIA->BasePtrWR[TIMERAL]; // reload timer |
| 94 | + if (CIA->BasePtrWR[CONTROLA] & ONESHOT_TIMERA) |
| 95 | + CIA->BasePtrWR[CONTROLA] &= ~ENABLE_TIMERA; // disable if one-shot |
| 96 | + CIA->BasePtrRD[INTERRUPTS] |= TIMERA; |
| 97 | + if (CIA->BasePtrWR[INTERRUPTS] & TIMERA) |
| 98 | + { // generate interrupt if mask allows |
| 99 | + CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED; |
| 100 | + } |
| 101 | + } |
| 102 | + CIA->BasePtrRD[TIMERAH] = (Tmp >> 8); |
| 103 | + CIA->BasePtrRD[TIMERAL] = Tmp & 0xFF; |
| 104 | + } |
| 105 | + CIA->BasePtrWR[CONTROLA] &= ~FORCELOADA_STROBE; // strobe is edge-sensitive |
| 106 | + CIA->BasePtrRD[CONTROLA] = CIA->BasePtrWR[CONTROLA]; // control-registers are readable |
| 107 | + |
| 108 | + // TimerB |
| 109 | + if (CIA->BasePtrWR[CONTROLB] & FORCELOADB_STROBE) |
| 110 | + { // force latch into counter (strobe-input) |
| 111 | + CIA->BasePtrRD[TIMERBH] = CIA->BasePtrWR[TIMERBH]; |
| 112 | + CIA->BasePtrRD[TIMERBL] = CIA->BasePtrWR[TIMERBL]; |
| 113 | + } // what about clocking TimerB by TimerA? (maybe not used in any music) |
| 114 | + else if ((CIA->BasePtrWR[CONTROLB] & (ENABLE_TIMERB | TIMERB_FROM_TIMERA)) == ENABLE_TIMERB) |
| 115 | + { // Enabled, counts Phi2 |
| 116 | + Tmp = ((CIA->BasePtrRD[TIMERBH] << 8) + CIA->BasePtrRD[TIMERBL]) - cycles; // count timer |
| 117 | + if (Tmp <= 0) |
| 118 | + { // Timer counted down |
| 119 | + Tmp += (CIA->BasePtrWR[TIMERBH] << 8) + CIA->BasePtrWR[TIMERBL]; // reload timer |
| 120 | + if (CIA->BasePtrWR[CONTROLB] & ONESHOT_TIMERB) |
| 121 | + CIA->BasePtrWR[CONTROLB] &= ~ENABLE_TIMERB; // disable if one-shot |
| 122 | + CIA->BasePtrRD[INTERRUPTS] |= TIMERB; |
| 123 | + if (CIA->BasePtrWR[INTERRUPTS] & TIMERB) |
| 124 | + { // generate interrupt if mask allows |
| 125 | + CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED; |
| 126 | + } |
| 127 | + } |
| 128 | + CIA->BasePtrRD[TIMERBH] = (Tmp >> 8); |
| 129 | + CIA->BasePtrRD[TIMERBL] = Tmp & 0xFF; |
| 130 | + } |
| 131 | + CIA->BasePtrWR[CONTROLB] &= ~FORCELOADB_STROBE; // strobe is edge-sensitive |
| 132 | + CIA->BasePtrRD[CONTROLB] = CIA->BasePtrWR[CONTROLB]; // control-registers are readable |
| 133 | + |
| 134 | + return (CIA->BasePtrRD[INTERRUPTS] & INTERRUPT_HAPPENED); |
77 | 135 | }
|
78 | 136 |
|
79 |
| - |
80 |
| -static inline void cRSID_writeCIAIRQmask (cRSID_CIAinstance* CIA, unsigned char value) { |
81 |
| - if (value&0x80) CIA->BasePtrWR[0xD] |= (value&0x1F); |
82 |
| - else CIA->BasePtrWR[0xD] &= ~(value&0x1F); |
| 137 | +static inline void cRSID_writeCIAIRQmask(cRSID_CIAinstance *CIA, unsigned char value) |
| 138 | +{ |
| 139 | + if (value & 0x80) |
| 140 | + CIA->BasePtrWR[0xD] |= (value & 0x1F); |
| 141 | + else |
| 142 | + CIA->BasePtrWR[0xD] &= ~(value & 0x1F); |
83 | 143 | }
|
84 | 144 |
|
85 |
| - |
86 |
| -static inline void cRSID_acknowledgeCIAIRQ (cRSID_CIAinstance* CIA) { |
87 |
| - CIA->BasePtrRD[0xD] = 0x00; //reading a CIA interrupt-register clears its read-part and IRQ-flag |
| 145 | +static inline void cRSID_acknowledgeCIAIRQ(cRSID_CIAinstance *CIA) |
| 146 | +{ |
| 147 | + CIA->BasePtrRD[0xD] = 0x00; // reading a CIA interrupt-register clears its read-part and IRQ-flag |
88 | 148 | }
|
89 | 149 |
|
90 |
| - |
91 |
| -//static inline void cRSID_writeCIARWreg () { |
92 |
| - //mirroring write-latch to read-latch for Readable-Writeable registers? |
| 150 | +// static inline void cRSID_writeCIARWreg () { |
| 151 | +// mirroring write-latch to read-latch for Readable-Writeable registers? |
93 | 152 | //}
|
0 commit comments