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