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 (13 years, 11 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

# User Rev Content
1 cebix 1.1 /*
2     * CPU1541.h - 6502 (1541) emulation (line based)
3     *
4 cebix 1.5 * Frodo Copyright (C) Christian Bauer
5 cebix 1.1 *
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 cebix 1.5 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 cebix 1.1 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