1 /*
2 * CPU1541.h - 6502 (1541) emulation (line based)
3 *
4 * Frodo (C) 1994-1997,2002 Christian Bauer
5 */
6
7 #ifndef _CPU_1541_H
8 #define _CPU_1541_H
9
10 #include "CIA.h"
11 #include "C64.h"
12
13
14 // Set this to 1 if the 6502 PC should be represented by a real pointer
15 #ifndef FRODO_SC
16 #ifndef PC_IS_POINTER
17 #define PC_IS_POINTER 1
18 #endif
19 #endif
20
21 // Set this to 1 for more precise CPU cycle calculation
22 #ifndef PRECISE_CPU_CYCLES
23 #define PRECISE_CPU_CYCLES 0
24 #endif
25
26
27 // Interrupt types
28 enum {
29 INT_VIA1IRQ,
30 INT_VIA2IRQ,
31 INT_IECIRQ
32 // INT_RESET (private)
33 };
34
35
36 class C64;
37 class Job1541;
38 class C64Display;
39 struct MOS6502State;
40
41
42 // 6502 emulation (1541)
43 class MOS6502_1541 {
44 public:
45 MOS6502_1541(C64 *c64, Job1541 *job, C64Display *disp, uint8 *Ram, uint8 *Rom);
46
47 #ifdef FRODO_SC
48 void EmulateCycle(void); // Emulate one clock cycle
49 #else
50 int EmulateLine(int cycles_left); // Emulate until cycles_left underflows
51 #endif
52 void Reset(void);
53 void AsyncReset(void); // Reset the CPU asynchronously
54 void GetState(MOS6502State *s);
55 void SetState(MOS6502State *s);
56 uint8 ExtReadByte(uint16 adr);
57 void ExtWriteByte(uint16 adr, uint8 byte);
58 void CountVIATimers(int cycles);
59 void NewATNState(void);
60 void IECInterrupt(void);
61 void TriggerJobIRQ(void);
62 bool InterruptEnabled(void);
63
64 MOS6526_2 *TheCIA2; // Pointer to C64 CIA 2
65
66 uint8 IECLines; // State of IEC lines (bit 7 - DATA, bit 6 - CLK)
67 bool Idle; // true: 1541 is idle
68
69 private:
70 uint8 read_byte(uint16 adr);
71 uint8 read_byte_io(uint16 adr);
72 uint16 read_word(uint16 adr);
73 void write_byte(uint16 adr, uint8 byte);
74 void write_byte_io(uint16 adr, uint8 byte);
75
76 uint8 read_zp(uint16 adr);
77 uint16 read_zp_word(uint16 adr);
78 void write_zp(uint16 adr, uint8 byte);
79
80 void jump(uint16 adr);
81 void illegal_op(uint8 op, uint16 at);
82 void illegal_jump(uint16 at, uint16 to);
83
84 void do_adc(uint8 byte);
85 void do_sbc(uint8 byte);
86
87 uint8 *ram; // Pointer to main RAM
88 uint8 *rom; // Pointer to ROM
89 C64 *the_c64; // Pointer to C64 object
90 C64Display *the_display; // Pointer to C64 display object
91 Job1541 *the_job; // Pointer to 1541 job object
92
93 union { // Pending interrupts
94 uint8 intr[4]; // Index: See definitions above
95 unsigned long intr_any;
96 } interrupt;
97
98 uint8 n_flag, z_flag;
99 bool v_flag, d_flag, i_flag, c_flag;
100 uint8 a, x, y, sp;
101 #if PC_IS_POINTER
102 uint8 *pc, *pc_base;
103 #else
104 uint16 pc;
105 #endif
106
107 #ifdef FRODO_SC
108 uint32 first_irq_cycle;
109
110 uint8 state, op; // Current state and opcode
111 uint16 ar, ar2; // Address registers
112 uint8 rdbuf; // Data buffer for RMW instructions
113 uint8 ddr, pr; // Processor port
114 #else
115 int borrowed_cycles; // Borrowed cycles from next line
116 #endif
117
118 uint8 via1_pra; // PRA of VIA 1
119 uint8 via1_ddra; // DDRA of VIA 1
120 uint8 via1_prb; // PRB of VIA 1
121 uint8 via1_ddrb; // DDRB of VIA 1
122 uint16 via1_t1c; // T1 Counter of VIA 1
123 uint16 via1_t1l; // T1 Latch of VIA 1
124 uint16 via1_t2c; // T2 Counter of VIA 1
125 uint16 via1_t2l; // T2 Latch of VIA 1
126 uint8 via1_sr; // SR of VIA 1
127 uint8 via1_acr; // ACR of VIA 1
128 uint8 via1_pcr; // PCR of VIA 1
129 uint8 via1_ifr; // IFR of VIA 1
130 uint8 via1_ier; // IER of VIA 1
131
132 uint8 via2_pra; // PRA of VIA 2
133 uint8 via2_ddra; // DDRA of VIA 2
134 uint8 via2_prb; // PRB of VIA 2
135 uint8 via2_ddrb; // DDRB of VIA 2
136 uint16 via2_t1c; // T1 Counter of VIA 2
137 uint16 via2_t1l; // T1 Latch of VIA 2
138 uint16 via2_t2c; // T2 Counter of VIA 2
139 uint16 via2_t2l; // T2 Latch of VIA 2
140 uint8 via2_sr; // SR of VIA 2
141 uint8 via2_acr; // ACR of VIA 2
142 uint8 via2_pcr; // PCR of VIA 2
143 uint8 via2_ifr; // IFR of VIA 2
144 uint8 via2_ier; // IER of VIA 2
145 };
146
147 // 6502 state
148 struct MOS6502State {
149 uint8 a, x, y;
150 uint8 p; // Processor flags
151 uint16 pc, sp;
152
153 uint8 intr[4]; // Interrupt state
154 bool instruction_complete;
155 bool idle;
156
157 uint8 via1_pra; // VIA 1
158 uint8 via1_ddra;
159 uint8 via1_prb;
160 uint8 via1_ddrb;
161 uint16 via1_t1c;
162 uint16 via1_t1l;
163 uint16 via1_t2c;
164 uint16 via1_t2l;
165 uint8 via1_sr;
166 uint8 via1_acr;
167 uint8 via1_pcr;
168 uint8 via1_ifr;
169 uint8 via1_ier;
170
171 uint8 via2_pra; // VIA 2
172 uint8 via2_ddra;
173 uint8 via2_prb;
174 uint8 via2_ddrb;
175 uint16 via2_t1c;
176 uint16 via2_t1l;
177 uint16 via2_t2c;
178 uint16 via2_t2l;
179 uint8 via2_sr;
180 uint8 via2_acr;
181 uint8 via2_pcr;
182 uint8 via2_ifr;
183 uint8 via2_ier;
184 };
185
186
187
188 /*
189 * Trigger job loop IRQ
190 */
191
192 #ifdef FRODO_SC
TriggerJobIRQ(void)193 inline void MOS6502_1541::TriggerJobIRQ(void)
194 {
195 if (!(interrupt.intr[INT_VIA2IRQ]))
196 first_irq_cycle = the_c64->CycleCounter;
197 interrupt.intr[INT_VIA2IRQ] = true;
198 Idle = false;
199 }
200 #else
TriggerJobIRQ(void)201 inline void MOS6502_1541::TriggerJobIRQ(void)
202 {
203 interrupt.intr[INT_VIA2IRQ] = true;
204 Idle = false;
205 }
206 #endif
207
208
209 /*
210 * Count VIA timers
211 */
212
CountVIATimers(int cycles)213 inline void MOS6502_1541::CountVIATimers(int cycles)
214 {
215 unsigned long tmp;
216
217 via1_t1c = tmp = via1_t1c - cycles;
218 if (tmp > 0xffff) {
219 if (via1_acr & 0x40) // Reload from latch in free-run mode
220 via1_t1c = via1_t1l;
221 via1_ifr |= 0x40;
222 }
223
224 if (!(via1_acr & 0x20)) { // Only count in one-shot mode
225 via1_t2c = tmp = via1_t2c - cycles;
226 if (tmp > 0xffff)
227 via1_ifr |= 0x20;
228 }
229
230 via2_t1c = tmp = via2_t1c - cycles;
231 if (tmp > 0xffff) {
232 if (via2_acr & 0x40) // Reload from latch in free-run mode
233 via2_t1c = via2_t1l;
234 via2_ifr |= 0x40;
235 if (via2_ier & 0x40)
236 TriggerJobIRQ();
237 }
238
239 if (!(via2_acr & 0x20)) { // Only count in one-shot mode
240 via2_t2c = tmp = via2_t2c - cycles;
241 if (tmp > 0xffff)
242 via2_ifr |= 0x20;
243 }
244 }
245
246
247 /*
248 * ATN line probably changed state, recalc IECLines
249 */
250
NewATNState(void)251 inline void MOS6502_1541::NewATNState(void)
252 {
253 uint8 byte = ~via1_prb & via1_ddrb;
254 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80 // DATA (incl. ATN acknowledge)
255 | (byte << 3) & 0x40; // CLK
256 }
257
258
259 /*
260 * Interrupt by negative edge of ATN on IEC bus
261 */
262
IECInterrupt(void)263 inline void MOS6502_1541::IECInterrupt(void)
264 {
265 ram[0x7c] = 1;
266
267 // Wake up 1541
268 Idle = false;
269 }
270
271
272 /*
273 * Test if interrupts are enabled (for job loop)
274 */
275
InterruptEnabled(void)276 inline bool MOS6502_1541::InterruptEnabled(void)
277 {
278 return !i_flag;
279 }
280
281 #endif
282