1 /* z80.c: z80 supplementary functions
2    Copyright (c) 1999-2013 Philip Kendall
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18    Author contact information:
19 
20    E-mail: philip-fuse@shadowmagic.org.uk
21 
22 */
23 
24 #include <config.h>
25 
26 #include <libspectrum.h>
27 
28 #include "event.h"
29 #include "fuse.h"
30 #include "memory.h"
31 #include "module.h"
32 #include "peripherals/scld.h"
33 #include "peripherals/spectranet.h"
34 #include "rzx.h"
35 #include "spectrum.h"
36 #include "ui/ui.h"
37 #include "z80.h"
38 #include "z80_macros.h"
39 
40 /* Whether a half carry occurred or not can be determined by looking at
41    the 3rd bit of the two arguments and the result; these are hashed
42    into this table in the form r12, where r is the 3rd bit of the
43    result, 1 is the 3rd bit of the 1st argument and 2 is the
44    third bit of the 2nd argument; the tables differ for add and subtract
45    operations */
46 const libspectrum_byte halfcarry_add_table[] =
47   { 0, FLAG_H, FLAG_H, FLAG_H, 0, 0, 0, FLAG_H };
48 const libspectrum_byte halfcarry_sub_table[] =
49   { 0, 0, FLAG_H, 0, FLAG_H, 0, FLAG_H, FLAG_H };
50 
51 /* Similarly, overflow can be determined by looking at the 7th bits; again
52    the hash into this table is r12 */
53 const libspectrum_byte overflow_add_table[] = { 0, 0, 0, FLAG_V, FLAG_V, 0, 0, 0 };
54 const libspectrum_byte overflow_sub_table[] = { 0, FLAG_V, 0, 0, 0, 0, FLAG_V, 0 };
55 
56 /* Some more tables; initialised in z80_init_tables() */
57 
58 libspectrum_byte sz53_table[0x100]; /* The S, Z, 5 and 3 bits of the index */
59 libspectrum_byte parity_table[0x100]; /* The parity of the lookup value */
60 libspectrum_byte sz53p_table[0x100]; /* OR the above two tables together */
61 
62 /* This is what everything acts on! */
63 processor z80;
64 
65 int z80_interrupt_event, z80_nmi_event;
66 
67 static void z80_init_tables(void);
68 static void z80_from_snapshot( libspectrum_snap *snap );
69 static void z80_to_snapshot( libspectrum_snap *snap );
70 static void z80_nmi( libspectrum_dword ts, int type, void *user_data );
71 
72 static module_info_t z80_module_info = {
73 
74   z80_reset,
75   NULL,
76   NULL,
77   z80_from_snapshot,
78   z80_to_snapshot,
79 
80 };
81 
82 static void
z80_interrupt_event_fn(libspectrum_dword tstates,int type,void * user_data)83 z80_interrupt_event_fn( libspectrum_dword tstates, int type, void *user_data )
84 {
85   /* Retriggered interrupt; firstly, ignore if we're doing RZX playback
86      as all interrupts are generated by the RZX code */
87   if( rzx_playback ) return;
88 
89   /* Otherwise, see if we actually accept an interrupt. If we do and
90      we're doing RZX recording, store a frame */
91   if( z80_interrupt() ) rzx_frame();
92 }
93 
94 /* Set up the z80 emulation */
95 void
z80_init(void)96 z80_init( void )
97 {
98   z80_init_tables();
99 
100   z80_interrupt_event = event_register( z80_interrupt_event_fn,
101 					"Retriggered interrupt" );
102   z80_nmi_event = event_register( z80_nmi, "Non-maskable interrupt" );
103 
104   module_register( &z80_module_info );
105 }
106 
107 /* Initalise the tables used to set flags */
z80_init_tables(void)108 static void z80_init_tables(void)
109 {
110   int i,j,k;
111   libspectrum_byte parity;
112 
113   for(i=0;i<0x100;i++) {
114     sz53_table[i]= i & ( FLAG_3 | FLAG_5 | FLAG_S );
115     j=i; parity=0;
116     for(k=0;k<8;k++) { parity ^= j & 1; j >>=1; }
117     parity_table[i]= ( parity ? 0 : FLAG_P );
118     sz53p_table[i] = sz53_table[i] | parity_table[i];
119   }
120 
121   sz53_table[0]  |= FLAG_Z;
122   sz53p_table[0] |= FLAG_Z;
123 
124 }
125 
126 /* Reset the z80 */
127 void
z80_reset(int hard_reset GCC_UNUSED)128 z80_reset( int hard_reset GCC_UNUSED )
129 {
130   AF =BC =DE =HL =0;
131   AF_=BC_=DE_=HL_=0;
132   IX=IY=0;
133   I=R=R7=0;
134   SP=PC=0;
135   IFF1=IFF2=IM=0;
136   z80.halted=0;
137 
138   z80.interrupts_enabled_at = -1;
139 }
140 
141 /* Process a z80 maskable interrupt */
142 int
z80_interrupt(void)143 z80_interrupt( void )
144 {
145   /* An interrupt will occur if IFF1 is set and the /INT line hasn't
146      gone high again. On a Timex machine, we also need the SCLD's
147      INTDISABLE to be clear */
148   if( IFF1 &&
149       tstates < machine_current->timings.interrupt_length &&
150       !scld_last_dec.name.intdisable ) {
151 
152     /* If interrupts have just been enabled, don't accept the interrupt now,
153        but check after the next instruction has been executed */
154     if( tstates == z80.interrupts_enabled_at ) {
155       event_add( tstates + 1, z80_interrupt_event );
156       return 0;
157     }
158 
159     if( z80.halted ) { PC++; z80.halted = 0; }
160 
161     IFF1=IFF2=0;
162 
163     writebyte( --SP, PCH ); writebyte( --SP, PCL );
164 
165     R++; rzx_instructions_offset--;
166 
167     switch(IM) {
168       case 0: PC = 0x0038; tstates += 7; break;
169       case 1: PC = 0x0038; tstates += 7; break;
170       case 2:
171 	{
172 	  libspectrum_word inttemp=(0x100*I)+0xff;
173 	  PCL = readbyte(inttemp++); PCH = readbyte(inttemp);
174 	  tstates += 7;
175 	  break;
176 	}
177       default:
178 	ui_error( UI_ERROR_ERROR, "Unknown interrupt mode %d", IM );
179 	fuse_abort();
180     }
181 
182     return 1;			/* Accepted an interrupt */
183 
184   } else {
185 
186     return 0;			/* Did not accept an interrupt */
187 
188   }
189 }
190 
191 /* Process a z80 non-maskable interrupt */
192 static void
z80_nmi(libspectrum_dword ts,int type,void * user_data)193 z80_nmi( libspectrum_dword ts, int type, void *user_data )
194 {
195   /* TODO: this isn't ideal */
196   if( spectranet_available && spectranet_nmi_flipflop() )
197     return;
198 
199   if( z80.halted ) { PC++; z80.halted = 0; }
200 
201   IFF1 = 0;
202 
203   writebyte( --SP, PCH ); writebyte( --SP, PCL );
204 
205   if( machine_current->capabilities &
206       LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ) {
207 
208     /* Page in ROM 2 */
209     writeport_internal( 0x1ffd, machine_current->ram.last_byte2 | 0x02 );
210 
211   } else if( beta_available ) {
212 
213     /* Page in TR-DOS ROM */
214     beta_page();
215   } else if( spectranet_available ) {
216 
217     /* Page in spectranet */
218     spectranet_nmi();
219   }
220 
221   /* FIXME: how is R affected? */
222 
223   /* FIXME: how does contention apply here? */
224   tstates += 11; PC = 0x0066;
225 }
226 
227 /* Special peripheral processing for RETN */
228 void
z80_retn(void)229 z80_retn( void )
230 {
231   spectranet_retn();
232 }
233 
234 /* Routines for transferring the Z80 contents to and from snapshots */
235 static void
z80_from_snapshot(libspectrum_snap * snap)236 z80_from_snapshot( libspectrum_snap *snap )
237 {
238   A  = libspectrum_snap_a ( snap ); F  = libspectrum_snap_f ( snap );
239   A_ = libspectrum_snap_a_( snap ); F_ = libspectrum_snap_f_( snap );
240 
241   BC  = libspectrum_snap_bc ( snap ); DE  = libspectrum_snap_de ( snap );
242   HL  = libspectrum_snap_hl ( snap ); BC_ = libspectrum_snap_bc_( snap );
243   DE_ = libspectrum_snap_de_( snap ); HL_ = libspectrum_snap_hl_( snap );
244 
245   IX = libspectrum_snap_ix( snap ); IY = libspectrum_snap_iy( snap );
246   I  = libspectrum_snap_i ( snap ); R = R7 = libspectrum_snap_r( snap );
247   SP = libspectrum_snap_sp( snap ); PC = libspectrum_snap_pc( snap );
248 
249   IFF1 = libspectrum_snap_iff1( snap ); IFF2 = libspectrum_snap_iff2( snap );
250   IM = libspectrum_snap_im( snap );
251 
252   z80.halted = libspectrum_snap_halted( snap );
253 
254   z80.interrupts_enabled_at =
255     libspectrum_snap_last_instruction_ei( snap ) ? tstates : -1;
256 }
257 
258 static void
z80_to_snapshot(libspectrum_snap * snap)259 z80_to_snapshot( libspectrum_snap *snap )
260 {
261   libspectrum_byte r_register;
262 
263   r_register = ( R7 & 0x80 ) | ( R & 0x7f );
264 
265   libspectrum_snap_set_a  ( snap, A   ); libspectrum_snap_set_f  ( snap, F   );
266   libspectrum_snap_set_a_ ( snap, A_  ); libspectrum_snap_set_f_ ( snap, F_  );
267 
268   libspectrum_snap_set_bc ( snap, BC  ); libspectrum_snap_set_de ( snap, DE  );
269   libspectrum_snap_set_hl ( snap, HL  ); libspectrum_snap_set_bc_( snap, BC_ );
270   libspectrum_snap_set_de_( snap, DE_ ); libspectrum_snap_set_hl_( snap, HL_ );
271 
272   libspectrum_snap_set_ix ( snap, IX  ); libspectrum_snap_set_iy ( snap, IY  );
273   libspectrum_snap_set_i  ( snap, I   );
274   libspectrum_snap_set_r  ( snap, r_register );
275   libspectrum_snap_set_sp ( snap, SP  ); libspectrum_snap_set_pc ( snap, PC  );
276 
277   libspectrum_snap_set_iff1( snap, IFF1 );
278   libspectrum_snap_set_iff2( snap, IFF2 );
279   libspectrum_snap_set_im( snap, IM );
280 
281   libspectrum_snap_set_halted( snap, z80.halted );
282   libspectrum_snap_set_last_instruction_ei(
283     snap, z80.interrupts_enabled_at == tstates
284   );
285 }
286