1 /*
2 * CPUC64.h - 6510 (C64) emulation (line based)
3 *
4 * Frodo (C) 1994-1997,2002 Christian Bauer
5 */
6
7 #ifndef _CPU_C64_H
8 #define _CPU_C64_H
9
10 #include "C64.h"
11
12
13 // Set this to 1 if the 6502 PC should be represented by a real pointer
14 #ifndef FRODO_SC
15 #ifndef PC_IS_POINTER
16 #define PC_IS_POINTER 1
17 #endif
18 #endif
19
20 // Set this to 1 for more precise CPU cycle calculation
21 #ifndef PRECISE_CPU_CYCLES
22 #define PRECISE_CPU_CYCLES 0
23 #endif
24
25 // Set this to 1 for instruction-aligned CIA emulation
26 #ifndef PRECISE_CIA_CYCLES
27 #define PRECISE_CIA_CYCLES 0
28 #endif
29
30
31 // Interrupt types
32 enum {
33 INT_VICIRQ,
34 INT_CIAIRQ,
35 INT_NMI
36 // INT_RESET (private)
37 };
38
39
40 class MOS6569;
41 class MOS6581;
42 class MOS6526_1;
43 class MOS6526_2;
44 class REU;
45 class IEC;
46 struct MOS6510State;
47
48
49 // 6510 emulation (C64)
50 class MOS6510 {
51 public:
52 MOS6510(C64 *c64, uint8 *Ram, uint8 *Basic, uint8 *Kernal, uint8 *Char, uint8 *Color);
53
54 #ifdef FRODO_SC
55 void EmulateCycle(void); // Emulate one clock cycle
56 #else
57 int EmulateLine(int cycles_left); // Emulate until cycles_left underflows
58 #endif
59 void Reset(void);
60 void AsyncReset(void); // Reset the CPU asynchronously
61 void AsyncNMI(void); // Raise NMI asynchronously (NMI pulse)
62 void GetState(MOS6510State *s);
63 void SetState(MOS6510State *s);
64 uint8 ExtReadByte(uint16 adr);
65 void ExtWriteByte(uint16 adr, uint8 byte);
66 uint8 REUReadByte(uint16 adr);
67 void REUWriteByte(uint16 adr, uint8 byte);
68
69 void TriggerVICIRQ(void);
70 void ClearVICIRQ(void);
71 void TriggerCIAIRQ(void);
72 void ClearCIAIRQ(void);
73 void TriggerNMI(void);
74 void ClearNMI(void);
75
76 int ExtConfig; // Memory configuration for ExtRead/WriteByte (0..7)
77
78 MOS6569 *TheVIC; // Pointer to VIC
79 MOS6581 *TheSID; // Pointer to SID
80 MOS6526_1 *TheCIA1; // Pointer to CIA 1
81 MOS6526_2 *TheCIA2; // Pointer to CIA 2
82 REU *TheREU; // Pointer to REU
83 IEC *TheIEC; // Pointer to drive array
84
85 #ifdef FRODO_SC
86 bool BALow; // BA line for Frodo SC
87 #endif
88
89 private:
90 uint8 read_byte(uint16 adr);
91 uint8 read_byte_io(uint16 adr);
92 uint16 read_word(uint16 adr);
93 void write_byte(uint16 adr, uint8 byte);
94 void write_byte_io(uint16 adr, uint8 byte);
95
96 uint8 read_zp(uint16 adr);
97 uint16 read_zp_word(uint16 adr);
98 void write_zp(uint16 adr, uint8 byte);
99
100 void new_config(void);
101 void jump(uint16 adr);
102 void illegal_op(uint8 op, uint16 at);
103 void illegal_jump(uint16 at, uint16 to);
104
105 void do_adc(uint8 byte);
106 void do_sbc(uint8 byte);
107
108 uint8 read_emulator_id(uint16 adr);
109
110 C64 *the_c64; // Pointer to C64 object
111
112 uint8 *ram; // Pointer to main RAM
113 uint8 *basic_rom, *kernal_rom, *char_rom, *color_ram; // Pointers to ROMs and color RAM
114
115 union { // Pending interrupts
116 uint8 intr[4]; // Index: See definitions above
117 unsigned long intr_any;
118 } interrupt;
119 bool nmi_state; // State of NMI line
120
121 uint8 n_flag, z_flag;
122 bool v_flag, d_flag, i_flag, c_flag;
123 uint8 a, x, y, sp;
124
125 #if PC_IS_POINTER
126 uint8 *pc, *pc_base;
127 #else
128 uint16 pc;
129 #endif
130
131 #ifdef FRODO_SC
132 uint32 first_irq_cycle, first_nmi_cycle;
133
134 uint8 state, op; // Current state and opcode
135 uint16 ar, ar2; // Address registers
136 uint8 rdbuf; // Data buffer for RMW instructions
137 uint8 ddr, pr; // Processor port
138 #else
139 int borrowed_cycles; // Borrowed cycles from next line
140 #endif
141
142 bool basic_in, kernal_in, char_in, io_in;
143 uint8 dfff_byte;
144 };
145
146 // 6510 state
147 struct MOS6510State {
148 uint8 a, x, y;
149 uint8 p; // Processor flags
150 uint8 ddr, pr; // Port
151 uint16 pc, sp;
152 uint8 intr[4]; // Interrupt state
153 bool nmi_state;
154 uint8 dfff_byte;
155 bool instruction_complete;
156 };
157
158
159 // Interrupt functions
160 #ifdef FRODO_SC
TriggerVICIRQ(void)161 inline void MOS6510::TriggerVICIRQ(void)
162 {
163 if (!(interrupt.intr[INT_VICIRQ] || interrupt.intr[INT_CIAIRQ]))
164 first_irq_cycle = the_c64->CycleCounter;
165 interrupt.intr[INT_VICIRQ] = true;
166 }
167
TriggerCIAIRQ(void)168 inline void MOS6510::TriggerCIAIRQ(void)
169 {
170 if (!(interrupt.intr[INT_VICIRQ] || interrupt.intr[INT_CIAIRQ]))
171 first_irq_cycle = the_c64->CycleCounter;
172 interrupt.intr[INT_CIAIRQ] = true;
173 }
174
TriggerNMI(void)175 inline void MOS6510::TriggerNMI(void)
176 {
177 if (!nmi_state) {
178 nmi_state = true;
179 interrupt.intr[INT_NMI] = true;
180 first_nmi_cycle = the_c64->CycleCounter;
181 }
182 }
183 #else
TriggerVICIRQ(void)184 inline void MOS6510::TriggerVICIRQ(void)
185 {
186 interrupt.intr[INT_VICIRQ] = true;
187 }
188
TriggerCIAIRQ(void)189 inline void MOS6510::TriggerCIAIRQ(void)
190 {
191 interrupt.intr[INT_CIAIRQ] = true;
192 }
193
TriggerNMI(void)194 inline void MOS6510::TriggerNMI(void)
195 {
196 if (!nmi_state) {
197 nmi_state = true;
198 interrupt.intr[INT_NMI] = true;
199 }
200 }
201 #endif
ClearVICIRQ(void)202 inline void MOS6510::ClearVICIRQ(void)
203 {
204 interrupt.intr[INT_VICIRQ] = false;
205 }
206
ClearCIAIRQ(void)207 inline void MOS6510::ClearCIAIRQ(void)
208 {
209 interrupt.intr[INT_CIAIRQ] = false;
210 }
211
ClearNMI(void)212 inline void MOS6510::ClearNMI(void)
213 {
214 nmi_state = false;
215 }
216
217 #endif
218