1 /*****************************************************************************
2  *
3  *	 opsce02.h
4  *	 Addressing mode and opcode macros for 65ce02 CPU
5  *
6  *	 Copyright (c) 2000 Peter Trauner, all rights reserved.
7  *   documentation preliminary databook
8  *	 documentation by michael steil mist@c64.org
9  *	 available at ftp://ftp.funet.fi/pub/cbm/c65
10  *
11  *	 - This source code is released as freeware for non-commercial purposes.
12  *	 - You are free to use and redistribute this code in modified or
13  *	   unmodified form, provided you list me in the credits.
14  *	 - If you modify this source code, you must add a notice to each modified
15  *	   source file that it has been changed.  If you're a nice person, you
16  *	   will clearly mark each change too.  :)
17  *	 - If you wish to use this for commercial purposes, please contact me at
18  *	   pullmoll@t-online.de
19  *	 - The author of this copywritten work reserves the right to change the
20  *	   terms of its usage and license at any time, including retroactively
21  *	 - This entire notice must remain in the source code.
22  *
23  *****************************************************************************/
24 
25 #define m6502 m65ce02
26 #define m6502_ICount m65ce02_ICount
27 
28 /* stack disable extended (word) mode */
29 #undef F_T
30 #define F_E 0x20
31 
32 /* some shortcuts for improved readability */
33 #define Z	m65ce02.z
34 #define B	m65ce02.zp.b.h
35 #define SW m6502.sp.w.l
36 #define SPL m6502.sp.b.l
37 #define SPH m6502.sp.b.h
38 
39 #define PEEK_OP() cpu_readop(PCW)
40 
41 #define RDMEM_WORD(addr, pair)			\
42    pair.b.l=RDMEM( addr );				\
43    pair.b.h=RDMEM( (addr+1) & 0xffff )
44 
45 #define WRMEM_WORD(addr,pair)			\
46    WRMEM(addr,pair.b.l);				\
47    WRMEM((addr+1)&0xffff,pair.b.h)
48 
49 #define WB_EA_WORD	WRMEM_WORD(EAD, tmp)
50 
51 
52 #define SET_NZ_WORD(n)											\
53 	if( n.w.l == 0 )											\
54 		P = (P & ~F_N) | F_Z;									\
55 	else														\
56 		P = (P & ~(F_N | F_Z)) | ((n.b.h) & F_N)
57 
58 /* EA_IDY
59  *  ???? subtract 1 cycle if page boundary is crossed */
60 
61 
62 /***************************************************************
63  *	EA = zero page indirect + Z (post indexed)
64  *  ???? subtract 1 cycle if page boundary is crossed
65  ***************************************************************/
66 #define EA_IDZ													\
67 	ZPL = RDOPARG();											\
68 	EAL = RDMEM(ZPD);											\
69 	ZPL++;														\
70 	EAH = RDMEM(ZPD);											\
71 	if (EAL + Z > 0xff) 										\
72 		m6502_ICount--; 										\
73 	EAW += Z
74 
75 /***************************************************************
76  *	EA = zero page indexed stack, indirect + Y (post indexed)
77  *	??? subtract 1 cycle if page boundary is crossed
78  ***************************************************************/
79 /* i think its based on stack high byte instead of of bank register */
80 #define EA_ZP_INSP_INY											\
81 {																\
82 	PAIR pair={{0}};											\
83 	pair.b.l = SPL+RDOPARG();									\
84 	pair.b.h = SPH; 											\
85 	EAL = RDMEM(pair.d);										\
86 	if( P & F_E )												\
87 		pair.b.l++; 											\
88 	else														\
89 		pair.w.l++; 											\
90 	EAH = RDMEM(pair.d);										\
91 	if( EAL + Y > 0xff )										\
92 		m6502_ICount--; 										\
93 	EAW += Y;													\
94 }
95 
96 #define RD_IMM_WORD tmp.b.l = RDOPARG(); tmp.b.h=RDOPARG()
97 #define RD_IDZ	EA_IDZ; tmp = RDMEM(EAD)
98 #define WR_IDZ	EA_IDZ; WRMEM(EAD, tmp)
99 
100 #define RD_INSY EA_ZP_INSP_INY; tmp = RDMEM(EAD)
101 #define WR_INSY EA_ZP_INSP_INY; WRMEM(EAD, tmp)
102 
103 #define RD_ABS_WORD EA_ABS; RDMEM_WORD(EAD, tmp)
104 #define WR_ABS_WORD EA_ABS; WRMEM_WORD(EAD, tmp)
105 
106 #define RD_ZPG_WORD EA_ZPG; RDMEM_WORD(EAD, tmp)
107 #define WR_ZPG_WORD EA_ZPG; WRMEM_WORD(EAD, tmp)
108 
109 /***************************************************************
110  * push a register onto the stack
111  ***************************************************************/
112 #undef PUSH
113 #define PUSH(Rg) WRMEM(SPD, Rg); if (P&F_E) { S--; } else { SW--; }
114 
115 /***************************************************************
116  * pull a register from the stack
117  ***************************************************************/
118 #undef PULL
119 #define PULL(Rg) if (P&F_E) { S++; } else { SW++; } Rg = RDMEM(SPD)
120 
121 /* the order in which the args are pushed is correct! */
122 #define PUSH_WORD(pair) PUSH(pair.b.l);PUSH(pair.b.h)
123 
124 /***************************************************************
125  *	BRA  branch relative
126  *	extra cycle if page boundary is crossed
127  ***************************************************************/
128 #undef BRA
129 #define BRA(cond)												\
130 	if (cond)													\
131 	{															\
132 		tmp = RDOPARG();										\
133 		EAW = PCW + (signed char)tmp;							\
134 		PCD = EAD;												\
135 		CHANGE_PC;												\
136 	}															\
137 	else														\
138 	{															\
139 		PCW++;													\
140 	}
141 
142 /***************************************************************
143  *	BRA  branch relative
144  ***************************************************************/
145 #define BRA_WORD(cond)											\
146 	if (cond)													\
147 	{															\
148 		EAL = RDOPARG();										\
149 		EAH = RDOPARG();										\
150 		EAW = PCW + (short)(EAW-1); 							\
151 		PCD = EAD;												\
152 		CHANGE_PC;												\
153 	}															\
154 	else														\
155 	{															\
156 		PCW += 2;												\
157 	}
158 
159 /* 65ce02 ******************************************************
160  *	cle clear disable extended stack flag
161  ***************************************************************/
162 #define CLE 													\
163 		P|=F_E
164 
165 /* 65ce02 ******************************************************
166  *	see set disable extended stack flag
167  ***************************************************************/
168 #define SEE 													\
169 		P&=~F_E
170 
171 /* 65ce02 ******************************************************
172  *	augment
173  ***************************************************************/
174 #define AUG 													\
175  t1=RDOPARG(); t2=RDOPARG(); t3=RDOPARG(); \
176  logerror("m65ce02 at pc:%.4x reserved op aug %.2x %.2x %.2x\n", \
177   t1,t2,t3);
178 
179 /* 65ce02 ******************************************************
180  *	rts imm
181  ***************************************************************/
182 #define RTN 												\
183   if (P&F_E) { S+=tmp; } else { SW+=tmp; }
184 
185 /* 65ce02 ******************************************************
186  *	NEG accu
187  * twos complement
188  ***************************************************************/
189 #define NEG 													\
190 	A= (A^0xff)+1;												\
191 	SET_NZ(A)
192 
193 /* 65ce02 ******************************************************
194  *	ASR arithmetic (signed) shift right
195  *	[7] -> [7][6][5][4][3][2][1][0] -> C
196  ***************************************************************/
197 #define ASR_65CE02												\
198 	P = (P & ~F_C) | (tmp & F_C);								\
199 	tmp = (signed char)tmp >> 1;								\
200 	SET_NZ(tmp)
201 
202 /* 65ce02 ******************************************************
203  *	ASW arithmetic shift left word
204  *	[c] <- [15]..[6][5][4][3][2][1][0]
205  ***************************************************************/
206 /* not sure about how 16 bit memory modifying is executed */
207 #define ASW 													\
208 	tmp.w.l = tmp.w.l << 1; 									\
209 	P = (P & ~F_C) | (tmp.b.h2 & F_C);							\
210 	SET_NZ_WORD(tmp);
211 
212 /* 65ce02 ******************************************************
213  *	ROW rotate left word
214  *	[c] <- [15]..[6][5][4][3][2][1][0] <- C
215  ***************************************************************/
216 /* not sure about how 16 bit memory modifying is executed */
217 #define ROW 													\
218 	tmp.d =(tmp.d << 1);										\
219 	tmp.w.l |= (P & F_C);										\
220 	P = (P & ~F_C) | (tmp.w.l & F_C);							\
221 	SET_NZ_WORD(tmp);											\
222 
223 /* 65ce02 ******************************************************
224  *	CPZ Compare index Z
225  ***************************************************************/
226 #define CPZ 													\
227 	P &= ~F_C;													\
228 	if (Z >= tmp)												\
229 		P |= F_C;												\
230 	SET_NZ((UINT8)(Z - tmp))
231 
232 /* 65ce02 ******************************************************
233  *	DEZ Decrement index Z
234  ***************************************************************/
235 #define DEZ 													\
236 	Z = (UINT8)--Z; 											\
237 	SET_NZ(Z)
238 
239 /* 65ce02 ******************************************************
240  *	DEC Decrement memory word
241  ***************************************************************/
242 /* not sure about this */
243 #define DEW 													\
244 	tmp.w.l = --tmp.w.l;										\
245 	SET_NZ_WORD(tmp)
246 
247 /* 65ce02 ******************************************************
248  *	DEZ Decrement index Z
249  ***************************************************************/
250 #define INZ 													\
251 	Z = (UINT8)++Z; 											\
252 	SET_NZ(Z)
253 
254 /* 65ce02 ******************************************************
255  *	INW Increment memory word
256  ***************************************************************/
257 #define INW 													\
258 	tmp.w.l = ++tmp.w.l;										\
259 	SET_NZ_WORD(tmp)
260 
261 /* 65ce02 ******************************************************
262  *	LDZ Load index Z
263  ***************************************************************/
264 #define LDZ 													\
265 	Z = (UINT8)tmp; 											\
266 	SET_NZ(Z)
267 
268 /* 65ce02 ******************************************************
269  * STZ	Store index Z
270  ***************************************************************/
271 #define STZ_65CE02												\
272 	tmp = Z
273 
274 /* 65ce02 ******************************************************
275  *	PHZ Push index z
276  ***************************************************************/
277 #define PHZ 													\
278 	PUSH(Z)
279 
280 /* 65ce02 ******************************************************
281  *	PLA Pull accumulator
282  ***************************************************************/
283 #define PLZ 													\
284 	PULL(Z); \
285     SET_NZ(Z)
286 
287 /* 65ce02 ******************************************************
288  * TAZ	Transfer accumulator to index z
289  ***************************************************************/
290 #define TAZ 													\
291 	Z = A;														\
292 	SET_NZ(Z)
293 
294 /* 65ce02 ******************************************************
295  * TZA	Transfer index z to accumulator
296  ***************************************************************/
297 #define TZA 													\
298 	A = Z;														\
299 	SET_NZ(A)
300 
301 /* 65ce02 ******************************************************
302  * TSY	Transfer stack pointer to index y
303  ***************************************************************/
304 #define TSY 													\
305 	Y = SPH;													\
306 	SET_NZ(Y)
307 
308 /* 65ce02 ******************************************************
309  * TYS	Transfer index y to stack pointer
310  ***************************************************************/
311 #define TYS 													\
312 	SPH = Y;
313 
314 /* 65ce02 ******************************************************
315  * TAB	Transfer accumulator to Direct Page
316  ***************************************************************/
317 #define TAB 													\
318 	B = A;														\
319 	SET_NZ(B)
320 
321 /* 65ce02 ******************************************************
322  * TBA	Transfer direct page to accumulator
323  ***************************************************************/
324 #define TBA 													\
325 	A = B;														\
326 	SET_NZ(A)
327 
328 /* 65ce02 ******************************************************
329  *	BCC Branch if carry clear
330  ***************************************************************/
331 #define BCC_WORD BRA_WORD(!(P & F_C))
332 
333 /* 65ce02 ******************************************************
334  *	BCS Branch if carry set
335  ***************************************************************/
336 #define BCS_WORD BRA_WORD(P & F_C)
337 
338 /* 65ce02 ******************************************************
339  *	BEQ Branch if equal
340  ***************************************************************/
341 #define BEQ_WORD BRA_WORD(P & F_Z)
342 
343 /* 65ce02 ******************************************************
344  *	BMI Branch if minus
345  ***************************************************************/
346 #define BMI_WORD BRA_WORD(P & F_N)
347 
348 /* 65ce02 ******************************************************
349  *	BNE Branch if not equal
350  ***************************************************************/
351 #define BNE_WORD BRA_WORD(!(P & F_Z))
352 
353 /* 65ce02 ******************************************************
354  *	BPL Branch if plus
355  ***************************************************************/
356 #define BPL_WORD BRA_WORD(!(P & F_N))
357 
358 /* 65ce02 ******************************************************
359  * BVC	Branch if overflow clear
360  ***************************************************************/
361 #define BVC_WORD BRA_WORD(!(P & F_V))
362 
363 /* 65ce02 ******************************************************
364  * BVS	Branch if overflow set
365  ***************************************************************/
366 #define BVS_WORD BRA_WORD(P & F_V)
367 
368 /* 65ce02 ******************************************************
369  *	JSR Jump to subroutine
370  *	decrement PC (sic!) push PC hi, push PC lo and set
371  *	PC to the effective address
372  ***************************************************************/
373 #define JSR_IND 												\
374 	EAL = RDOPARG();											\
375 	PUSH(PCH);													\
376 	PUSH(PCL);													\
377 	EAH = RDOPARG();											\
378 	PCL = RDMEM(EAD);											\
379 	EAL++;	/* booby trap: stay in same page! ;-) */			\
380 	PCH = RDMEM(EAD);											\
381 	CHANGE_PC
382 
383 /* 65ce02 ******************************************************
384  *	JSR Jump to subroutine
385  *	decrement PC (sic!) push PC hi, push PC lo and set
386  *	PC to the effective address
387  ***************************************************************/
388 #define JSR_INDX												\
389 	EAL = RDOPARG()+X;											\
390 	PUSH(PCH);													\
391 	PUSH(PCL);													\
392 	EAH = RDOPARG();											\
393 	PCL = RDMEM(EAD);											\
394 	EAL++;	/* booby trap: stay in same page! ;-) */			\
395 	PCH = RDMEM(EAD);											\
396 	CHANGE_PC
397 
398 /* 65ce02 ******************************************************
399  *	PLP Pull processor status (flags)
400  ***************************************************************/
401 #undef PLP
402 #define PLP 													\
403 	if ( P & F_I )												\
404 	{															\
405 		UINT8 temp; \
406 		PULL(temp);												\
407 		P=(P&F_E)|F_B|(temp&~F_E); \
408 		if( m6502.irq_state != CLEAR_LINE && !(P & F_I) )		\
409 		{														\
410 			LOG(("M65ce02#%d PLP sets after_cli\n",             \
411 				cpu_getactivecpu()));							\
412 			m6502.after_cli = 1;								\
413 		}														\
414 	}															\
415 	else														\
416 	{															\
417 		UINT8 temp; \
418 		PULL(temp);												\
419 		P=(P&F_E)|F_B|(temp&~F_E); \
420 	}
421 
422 /* 65ce02 ********************************************************
423  * RTI	Return from interrupt
424  * pull flags, pull PC lo, pull PC hi and increment PC
425  *	PCW++;
426  ***************************************************************/
427 #undef RTI
428 #define RTI 													\
429 { UINT8 temp;PULL(temp);P=(P&F_E)|F_B|(temp&~F_E); } \
430 	PULL(PCL);													\
431 	PULL(PCH);													\
432 	if( m65ce02.irq_state != CLEAR_LINE && !(P & F_I) ) 		\
433 	{															\
434 		LOG(("M65ce02#%d RTI sets after_cli\n",                 \
435 			cpu_getactivecpu()));								\
436 		m6502.after_cli = 1;									\
437 	}															\
438 	CHANGE_PC
439 
440 /* 65ce02 ********************************************************
441  * TXS	Transfer index X to stack LSB
442  * no flags changed (sic!)
443  * txs tys not interruptable
444  ***************************************************************/
445 #undef TXS
446 #define TXS 													\
447 		S = X;													\
448 		if (PEEK_OP() == 0x2b /*TYS*/ ) 						\
449 		{														\
450 				UINT8 op = RDOP();								\
451 				(*m65ce02.insn[op])();							\
452 		}
453