diff options
Diffstat (limited to 'lib/rbcodec/codecs/cRSID/C64/CIA.c')
-rw-r--r-- | lib/rbcodec/codecs/cRSID/C64/CIA.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/cRSID/C64/CIA.c b/lib/rbcodec/codecs/cRSID/C64/CIA.c new file mode 100644 index 0000000000..b562417480 --- /dev/null +++ b/lib/rbcodec/codecs/cRSID/C64/CIA.c | |||
@@ -0,0 +1,93 @@ | |||
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); | ||
11 | } | ||
12 | |||
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; | ||
17 | } | ||
18 | |||
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); | ||
77 | } | ||
78 | |||
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); | ||
83 | } | ||
84 | |||
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 | ||
88 | } | ||
89 | |||
90 | |||
91 | //static inline void cRSID_writeCIARWreg () { | ||
92 | //mirroring write-latch to read-latch for Readable-Writeable registers? | ||
93 | //} | ||