1 /* z80_macros.h: Some commonly used z80 things as macros
2    Copyright (c) 1999-2011 Philip Kendall
3 
4    $Id: z80_macros.h 4624 2012-01-09 20:59:35Z pak21 $
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 along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20    Author contact information:
21 
22    E-mail: philip-fuse@shadowmagic.org.uk
23 
24 */
25 
26 #ifndef FUSE_Z80_MACROS_H
27 #define FUSE_Z80_MACROS_H
28 
29 /* Macros used for accessing the registers */
30 #define A   z80.af.b.h
31 #define F   z80.af.b.l
32 #define AF  z80.af.w
33 
34 #define B   z80.bc.b.h
35 #define C   z80.bc.b.l
36 #define BC  z80.bc.w
37 
38 #define D   z80.de.b.h
39 #define E   z80.de.b.l
40 #define DE  z80.de.w
41 
42 #define H   z80.hl.b.h
43 #define L   z80.hl.b.l
44 #define HL  z80.hl.w
45 
46 #define A_  z80.af_.b.h
47 #define F_  z80.af_.b.l
48 #define AF_ z80.af_.w
49 
50 #define B_  z80.bc_.b.h
51 #define C_  z80.bc_.b.l
52 #define BC_ z80.bc_.w
53 
54 #define D_  z80.de_.b.h
55 #define E_  z80.de_.b.l
56 #define DE_ z80.de_.w
57 
58 #define H_  z80.hl_.b.h
59 #define L_  z80.hl_.b.l
60 #define HL_ z80.hl_.w
61 
62 #define IXH z80.ix.b.h
63 #define IXL z80.ix.b.l
64 #define IX  z80.ix.w
65 
66 #define IYH z80.iy.b.h
67 #define IYL z80.iy.b.l
68 #define IY  z80.iy.w
69 
70 #define SPH z80.sp.b.h
71 #define SPL z80.sp.b.l
72 #define SP  z80.sp.w
73 
74 #define PCH z80.pc.b.h
75 #define PCL z80.pc.b.l
76 #define PC  z80.pc.w
77 
78 #define I  z80.i
79 #define R  z80.r
80 #define R7 z80.r7
81 
82 #define IFF1 z80.iff1
83 #define IFF2 z80.iff2
84 #define IM   z80.im
85 
86 #define IR ( ( z80.i ) << 8 | ( z80.r7 & 0x80 ) | ( z80.r & 0x7f ) )
87 
88 /* The flags */
89 
90 #define FLAG_C	0x01
91 #define FLAG_N	0x02
92 #define FLAG_P	0x04
93 #define FLAG_V	FLAG_P
94 #define FLAG_3	0x08
95 #define FLAG_H	0x10
96 #define FLAG_5	0x20
97 #define FLAG_Z	0x40
98 #define FLAG_S	0x80
99 
100 /* Get the appropriate contended memory delay. Use a macro for performance
101    reasons in the main core, but a function for flexibility when building
102    the core tester */
103 
104 #ifndef CORETEST
105 
106 #define contend_read(address,time) \
107   if( memory_map_read[ (address) >> MEMORY_PAGE_SIZE_LOGARITHM ].contended ) \
108     tstates += ula_contention[ tstates ]; \
109   tstates += (time);
110 
111 #define contend_read_no_mreq(address,time) \
112   if( memory_map_read[ (address) >> MEMORY_PAGE_SIZE_LOGARITHM ].contended ) \
113     tstates += ula_contention_no_mreq[ tstates ]; \
114   tstates += (time);
115 
116 #define contend_write_no_mreq(address,time) \
117   if( memory_map_write[ (address) >> MEMORY_PAGE_SIZE_LOGARITHM ].contended ) \
118     tstates += ula_contention_no_mreq[ tstates ]; \
119   tstates += (time);
120 
121 #else				/* #ifndef CORETEST */
122 
123 void contend_read( libspectrum_word address, libspectrum_dword time );
124 void contend_read_no_mreq( libspectrum_word address, libspectrum_dword time );
125 void contend_write_no_mreq( libspectrum_word address, libspectrum_dword time );
126 
127 #endif				/* #ifndef CORETEST */
128 
129 /* Some commonly used instructions */
130 #define AND(value)\
131 {\
132   A &= (value);\
133   F = FLAG_H | sz53p_table[A];\
134 }
135 
136 #define ADC(value)\
137 {\
138   libspectrum_word adctemp = A + (value) + ( F & FLAG_C ); \
139   libspectrum_byte lookup = ( (       A & 0x88 ) >> 3 ) | \
140 			    ( ( (value) & 0x88 ) >> 2 ) | \
141 			    ( ( adctemp & 0x88 ) >> 1 );  \
142   A=adctemp;\
143   F = ( adctemp & 0x100 ? FLAG_C : 0 ) |\
144     halfcarry_add_table[lookup & 0x07] | overflow_add_table[lookup >> 4] |\
145     sz53_table[A];\
146 }
147 
148 #define ADC16(value)\
149 {\
150   libspectrum_dword add16temp= HL + (value) + ( F & FLAG_C ); \
151   libspectrum_byte lookup = ( (        HL & 0x8800 ) >> 11 ) | \
152 			    ( (   (value) & 0x8800 ) >> 10 ) | \
153 			    ( ( add16temp & 0x8800 ) >>  9 );  \
154   HL = add16temp;\
155   F = ( add16temp & 0x10000 ? FLAG_C : 0 )|\
156     overflow_add_table[lookup >> 4] |\
157     ( H & ( FLAG_3 | FLAG_5 | FLAG_S ) ) |\
158     halfcarry_add_table[lookup&0x07]|\
159     ( HL ? 0 : FLAG_Z );\
160 }
161 
162 #define ADD(value)\
163 {\
164   libspectrum_word addtemp = A + (value); \
165   libspectrum_byte lookup = ( (       A & 0x88 ) >> 3 ) | \
166 			    ( ( (value) & 0x88 ) >> 2 ) | \
167 			    ( ( addtemp & 0x88 ) >> 1 );  \
168   A=addtemp;\
169   F = ( addtemp & 0x100 ? FLAG_C : 0 ) |\
170     halfcarry_add_table[lookup & 0x07] | overflow_add_table[lookup >> 4] |\
171     sz53_table[A];\
172 }
173 
174 #define ADD16(value1,value2)\
175 {\
176   libspectrum_dword add16temp = (value1) + (value2); \
177   libspectrum_byte lookup = ( (  (value1) & 0x0800 ) >> 11 ) | \
178 			    ( (  (value2) & 0x0800 ) >> 10 ) | \
179 			    ( ( add16temp & 0x0800 ) >>  9 );  \
180   (value1) = add16temp;\
181   F = ( F & ( FLAG_V | FLAG_Z | FLAG_S ) ) |\
182     ( add16temp & 0x10000 ? FLAG_C : 0 )|\
183     ( ( add16temp >> 8 ) & ( FLAG_3 | FLAG_5 ) ) |\
184     halfcarry_add_table[lookup];\
185 }
186 
187 /* This may look fairly inefficient, but the (gcc) optimiser does the
188    right thing assuming it's given a constant for 'bit' */
189 #define BIT( bit, value ) \
190 { \
191   F = ( F & FLAG_C ) | FLAG_H | ( value & ( FLAG_3 | FLAG_5 ) ); \
192   if( ! ( (value) & ( 0x01 << (bit) ) ) ) F |= FLAG_P | FLAG_Z; \
193   if( (bit) == 7 && (value) & 0x80 ) F |= FLAG_S; \
194 }
195 
196 #define BIT_I( bit, value, address ) \
197 { \
198   F = ( F & FLAG_C ) | FLAG_H | ( ( address >> 8 ) & ( FLAG_3 | FLAG_5 ) ); \
199   if( ! ( (value) & ( 0x01 << (bit) ) ) ) F |= FLAG_P | FLAG_Z; \
200   if( (bit) == 7 && (value) & 0x80 ) F |= FLAG_S; \
201 }
202 
203 #define CALL()\
204 {\
205   libspectrum_byte calltempl, calltemph; \
206   calltempl=readbyte(PC++);\
207   calltemph=readbyte( PC ); \
208   contend_read_no_mreq( PC, 1 ); PC++;\
209   PUSH16(PCL,PCH);\
210   PCL=calltempl; PCH=calltemph;\
211 }
212 
213 #define CP(value)\
214 {\
215   libspectrum_word cptemp = A - value; \
216   libspectrum_byte lookup = ( (       A & 0x88 ) >> 3 ) | \
217 			    ( ( (value) & 0x88 ) >> 2 ) | \
218 			    ( (  cptemp & 0x88 ) >> 1 );  \
219   F = ( cptemp & 0x100 ? FLAG_C : ( cptemp ? 0 : FLAG_Z ) ) | FLAG_N |\
220     halfcarry_sub_table[lookup & 0x07] |\
221     overflow_sub_table[lookup >> 4] |\
222     ( value & ( FLAG_3 | FLAG_5 ) ) |\
223     ( cptemp & FLAG_S );\
224 }
225 
226 /* Macro for the {DD,FD} CB dd xx rotate/shift instructions */
227 #define DDFDCB_ROTATESHIFT(time, target, instruction)\
228 tstates+=(time);\
229 {\
230   (target) = readbyte( tempaddr );\
231   instruction( (target) );\
232   writebyte( tempaddr, (target) );\
233 }\
234 break
235 
236 #define DEC(value)\
237 {\
238   F = ( F & FLAG_C ) | ( (value)&0x0f ? 0 : FLAG_H ) | FLAG_N;\
239   (value)--;\
240   F |= ( (value)==0x7f ? FLAG_V : 0 ) | sz53_table[value];\
241 }
242 
243 #define Z80_IN( reg, port )\
244 {\
245   (reg)=readport((port));\
246   F = ( F & FLAG_C) | sz53p_table[(reg)];\
247 }
248 
249 #define INC(value)\
250 {\
251   (value)++;\
252   F = ( F & FLAG_C ) | ( (value)==0x80 ? FLAG_V : 0 ) |\
253   ( (value)&0x0f ? 0 : FLAG_H ) | sz53_table[(value)];\
254 }
255 
256 #define LD16_NNRR(regl,regh)\
257 {\
258   libspectrum_word ldtemp; \
259   ldtemp=readbyte(PC++);\
260   ldtemp|=readbyte(PC++) << 8;\
261   writebyte(ldtemp++,(regl));\
262   writebyte(ldtemp,(regh));\
263   break;\
264 }
265 
266 #define LD16_RRNN(regl,regh)\
267 {\
268   libspectrum_word ldtemp; \
269   ldtemp=readbyte(PC++);\
270   ldtemp|=readbyte(PC++) << 8;\
271   (regl)=readbyte(ldtemp++);\
272   (regh)=readbyte(ldtemp);\
273   break;\
274 }
275 
276 #define JP()\
277 {\
278   libspectrum_word jptemp=PC; \
279   PCL=readbyte(jptemp++);\
280   PCH=readbyte(jptemp);\
281 }
282 
283 #define JR()\
284 {\
285   libspectrum_signed_byte jrtemp = readbyte( PC ); \
286   contend_read_no_mreq( PC, 1 ); contend_read_no_mreq( PC, 1 ); \
287   contend_read_no_mreq( PC, 1 ); contend_read_no_mreq( PC, 1 ); \
288   contend_read_no_mreq( PC, 1 ); \
289   PC += jrtemp; \
290 }
291 
292 #define OR(value)\
293 {\
294   A |= (value);\
295   F = sz53p_table[A];\
296 }
297 
298 #define POP16(regl,regh)\
299 {\
300   (regl)=readbyte(SP++);\
301   (regh)=readbyte(SP++);\
302 }
303 
304 #define PUSH16(regl,regh)\
305 {\
306   writebyte( --SP, (regh) );\
307   writebyte( --SP, (regl) );\
308 }
309 
310 #define RET()\
311 {\
312   POP16(PCL,PCH);\
313 }
314 
315 #define RL(value)\
316 {\
317   libspectrum_byte rltemp = (value); \
318   (value) = ( (value)<<1 ) | ( F & FLAG_C );\
319   F = ( rltemp >> 7 ) | sz53p_table[(value)];\
320 }
321 
322 #define RLC(value)\
323 {\
324   (value) = ( (value)<<1 ) | ( (value)>>7 );\
325   F = ( (value) & FLAG_C ) | sz53p_table[(value)];\
326 }
327 
328 #define RR(value)\
329 {\
330   libspectrum_byte rrtemp = (value); \
331   (value) = ( (value)>>1 ) | ( F << 7 );\
332   F = ( rrtemp & FLAG_C ) | sz53p_table[(value)];\
333 }
334 
335 #define RRC(value)\
336 {\
337   F = (value) & FLAG_C;\
338   (value) = ( (value)>>1 ) | ( (value)<<7 );\
339   F |= sz53p_table[(value)];\
340 }
341 
342 #define RST(value)\
343 {\
344   PUSH16(PCL,PCH);\
345   PC=(value);\
346 }
347 
348 #define SBC(value)\
349 {\
350   libspectrum_word sbctemp = A - (value) - ( F & FLAG_C ); \
351   libspectrum_byte lookup = ( (       A & 0x88 ) >> 3 ) | \
352 			    ( ( (value) & 0x88 ) >> 2 ) | \
353 			    ( ( sbctemp & 0x88 ) >> 1 );  \
354   A=sbctemp;\
355   F = ( sbctemp & 0x100 ? FLAG_C : 0 ) | FLAG_N |\
356     halfcarry_sub_table[lookup & 0x07] | overflow_sub_table[lookup >> 4] |\
357     sz53_table[A];\
358 }
359 
360 #define SBC16(value)\
361 {\
362   libspectrum_dword sub16temp = HL - (value) - (F & FLAG_C); \
363   libspectrum_byte lookup = ( (        HL & 0x8800 ) >> 11 ) | \
364 			    ( (   (value) & 0x8800 ) >> 10 ) | \
365 			    ( ( sub16temp & 0x8800 ) >>  9 );  \
366   HL = sub16temp;\
367   F = ( sub16temp & 0x10000 ? FLAG_C : 0 ) |\
368     FLAG_N | overflow_sub_table[lookup >> 4] |\
369     ( H & ( FLAG_3 | FLAG_5 | FLAG_S ) ) |\
370     halfcarry_sub_table[lookup&0x07] |\
371     ( HL ? 0 : FLAG_Z) ;\
372 }
373 
374 #define SLA(value)\
375 {\
376   F = (value) >> 7;\
377   (value) <<= 1;\
378   F |= sz53p_table[(value)];\
379 }
380 
381 #define SLL(value)\
382 {\
383   F = (value) >> 7;\
384   (value) = ( (value) << 1 ) | 0x01;\
385   F |= sz53p_table[(value)];\
386 }
387 
388 #define SRA(value)\
389 {\
390   F = (value) & FLAG_C;\
391   (value) = ( (value) & 0x80 ) | ( (value) >> 1 );\
392   F |= sz53p_table[(value)];\
393 }
394 
395 #define SRL(value)\
396 {\
397   F = (value) & FLAG_C;\
398   (value) >>= 1;\
399   F |= sz53p_table[(value)];\
400 }
401 
402 #define SUB(value)\
403 {\
404   libspectrum_word subtemp = A - (value); \
405   libspectrum_byte lookup = ( (       A & 0x88 ) >> 3 ) | \
406 			    ( ( (value) & 0x88 ) >> 2 ) | \
407 			    (  (subtemp & 0x88 ) >> 1 );  \
408   A=subtemp;\
409   F = ( subtemp & 0x100 ? FLAG_C : 0 ) | FLAG_N |\
410     halfcarry_sub_table[lookup & 0x07] | overflow_sub_table[lookup >> 4] |\
411     sz53_table[A];\
412 }
413 
414 #define XOR(value)\
415 {\
416   A ^= (value);\
417   F = sz53p_table[A];\
418 }
419 
420 #endif		/* #ifndef FUSE_Z80_MACROS_H */
421