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