ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/CPU1541.h
Revision: 1.5
Committed: 2010-04-22T15:08:18Z (14 years, 6 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +8 -1 lines
Log Message:
better interrupt timing

File Contents

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