1 /*
2 * CIA.h - 6526 emulation
3 *
4 * Frodo (C) 1994-1997,2002 Christian Bauer
5 */
6
7 #ifndef _CIA_H
8 #define _CIA_H
9
10 #include "Prefs.h"
11
12
13 class MOS6510;
14 class MOS6502_1541;
15 class MOS6569;
16 struct MOS6526State;
17
18
19 class MOS6526 {
20 public:
21 MOS6526(MOS6510 *CPU);
22
23 void Reset(void);
24 void GetState(MOS6526State *cs);
25 void SetState(MOS6526State *cs);
26 #ifdef FRODO_SC
27 void CheckIRQs(void);
28 void EmulateCycle(void);
29 #else
30 void EmulateLine(int cycles);
31 #endif
32 void CountTOD(void);
33 virtual void TriggerInterrupt(int bit)=0;
34
35 protected:
36 MOS6510 *the_cpu; // Pointer to 6510
37
38 uint8 pra, prb, ddra, ddrb;
39
40 uint16 ta, tb, latcha, latchb;
41
42 uint8 tod_10ths, tod_sec, tod_min, tod_hr;
43 uint8 alm_10ths, alm_sec, alm_min, alm_hr;
44
45 uint8 sdr, icr, cra, crb;
46 uint8 int_mask;
47
48 int tod_divider; // TOD frequency divider
49
50 bool tod_halt, // Flag: TOD halted
51 ta_cnt_phi2, // Flag: Timer A is counting Phi 2
52 tb_cnt_phi2, // Flag: Timer B is counting Phi 2
53 tb_cnt_ta; // Flag: Timer B is counting underflows of Timer A
54
55 #ifdef FRODO_SC
56 bool ta_irq_next_cycle, // Flag: Trigger TA IRQ in next cycle
57 tb_irq_next_cycle, // Flag: Trigger TB IRQ in next cycle
58 has_new_cra, // Flag: New value for CRA pending
59 has_new_crb; // Flag: New value for CRB pending
60 char ta_state, tb_state; // Timer A/B states
61 uint8 new_cra, new_crb; // New values for CRA/CRB
62 #endif
63 };
64
65
66 class MOS6526_1 : public MOS6526 {
67 public:
68 MOS6526_1(MOS6510 *CPU, MOS6569 *VIC);
69
70 void Reset(void);
71 uint8 ReadRegister(uint16 adr);
72 void WriteRegister(uint16 adr, uint8 byte);
73 virtual void TriggerInterrupt(int bit);
74
75 uint8 KeyMatrix[8]; // C64 keyboard matrix, 1 bit/key (0: key down, 1: key up)
76 uint8 RevMatrix[8]; // Reversed keyboard matrix
77
78 uint8 Joystick1; // Joystick 1 AND value
79 uint8 Joystick2; // Joystick 2 AND value
80
81 private:
82 void check_lp(void);
83
84 MOS6569 *the_vic;
85
86 uint8 prev_lp; // Previous state of LP line (bit 4)
87 };
88
89
90 class MOS6526_2 : public MOS6526{
91 public:
92 MOS6526_2(MOS6510 *CPU, MOS6569 *VIC, MOS6502_1541 *CPU1541);
93
94 void Reset(void);
95 uint8 ReadRegister(uint16 adr);
96 void WriteRegister(uint16 adr, uint8 byte);
97 virtual void TriggerInterrupt(int bit);
98
99 uint8 IECLines; // State of IEC lines (bit 7 - DATA, bit 6 - CLK, bit 4 - ATN)
100
101 private:
102 MOS6569 *the_vic;
103 MOS6502_1541 *the_cpu_1541;
104 };
105
106
107 // CIA state
108 struct MOS6526State {
109 uint8 pra;
110 uint8 ddra;
111 uint8 prb;
112 uint8 ddrb;
113 uint8 ta_lo;
114 uint8 ta_hi;
115 uint8 tb_lo;
116 uint8 tb_hi;
117 uint8 tod_10ths;
118 uint8 tod_sec;
119 uint8 tod_min;
120 uint8 tod_hr;
121 uint8 sdr;
122 uint8 int_data; // Pending interrupts
123 uint8 cra;
124 uint8 crb;
125 // Additional registers
126 uint16 latcha; // Timer latches
127 uint16 latchb;
128 uint8 alm_10ths; // Alarm time
129 uint8 alm_sec;
130 uint8 alm_min;
131 uint8 alm_hr;
132 uint8 int_mask; // Enabled interrupts
133 };
134
135
136 /*
137 * Emulate CIA for one cycle/raster line
138 */
139
140 #ifdef FRODO_SC
CheckIRQs(void)141 inline void MOS6526::CheckIRQs(void)
142 {
143 // Trigger pending interrupts
144 if (ta_irq_next_cycle) {
145 ta_irq_next_cycle = false;
146 TriggerInterrupt(1);
147 }
148 if (tb_irq_next_cycle) {
149 tb_irq_next_cycle = false;
150 TriggerInterrupt(2);
151 }
152 }
153 #else
EmulateLine(int cycles)154 inline void MOS6526::EmulateLine(int cycles)
155 {
156 unsigned long tmp;
157
158 // Timer A
159 if (ta_cnt_phi2) {
160 ta = tmp = ta - cycles; // Decrement timer
161
162 if (tmp > 0xffff) { // Underflow?
163 ta = latcha; // Reload timer
164
165 if (cra & 8) { // One-shot?
166 cra &= 0xfe;
167 ta_cnt_phi2 = false;
168 }
169 TriggerInterrupt(1);
170 if (tb_cnt_ta) { // Timer B counting underflows of Timer A?
171 tb = tmp = tb - 1; // tmp = --tb doesn't work
172 if (tmp > 0xffff) goto tb_underflow;
173 }
174 }
175 }
176
177 // Timer B
178 if (tb_cnt_phi2) {
179 tb = tmp = tb - cycles; // Decrement timer
180
181 if (tmp > 0xffff) { // Underflow?
182 tb_underflow:
183 tb = latchb;
184
185 if (crb & 8) { // One-shot?
186 crb &= 0xfe;
187 tb_cnt_phi2 = false;
188 tb_cnt_ta = false;
189 }
190 TriggerInterrupt(2);
191 }
192 }
193 }
194 #endif
195
196 #endif
197