1 /*
2   Hatari - hatari-glue.c
3 
4   This file is distributed under the GNU General Public License, version 2
5   or at your option any later version. Read the file gpl.txt for details.
6 
7   This file contains some code to glue the UAE CPU core to the rest of the
8   emulator and Hatari's "illegal" opcodes.
9 */
10 const char HatariGlue_fileid[] = "Hatari hatari-glue.c : " __DATE__ " " __TIME__;
11 
12 
13 #include <stdio.h>
14 
15 #include "main.h"
16 #include "configuration.h"
17 #include "cycInt.h"
18 #include "tos.h"
19 #include "gemdos.h"
20 #include "natfeats.h"
21 #include "cart.h"
22 #include "vdi.h"
23 #include "stMemory.h"
24 #include "ikbd.h"
25 #include "screen.h"
26 #include "video.h"
27 #include "psg.h"
28 #include "mfp.h"
29 #include "fdc.h"
30 #include "memorySnapShot.h"
31 
32 #include "sysdeps.h"
33 #include "options_cpu.h"
34 #include "maccess.h"
35 #include "memory.h"
36 #include "m68000.h"
37 #include "newcpu.h"
38 #include "cpu_prefetch.h"
39 #include "savestate.h"
40 #include "hatari-glue.h"
41 
42 
43 struct uae_prefs currprefs, changed_prefs;
44 
45 int pendingInterrupts = 0;
46 
47 
48 /**
49  * Reset custom chips
50  * In case the RESET instruction is called, we must reset all the peripherals
51  * connected to the CPU's reset pin.
52  */
customreset(void)53 void customreset(void)
54 {
55 	pendingInterrupts = 0;
56 
57 	/* Reset the IKBD */
58 	IKBD_Reset ( false );
59 
60 	/* Reseting the GLUE video chip should also set freq/res register to 0 */
61 	Video_Reset_Glue ();
62 
63 	/* Reset the YM2149 (stop any sound) */
64 	PSG_Reset ();
65 
66 	/* Reset the MFP */
67 	MFP_Reset ();
68 
69 	/* Reset the FDC */
70 	FDC_Reset ( false );
71 }
72 
73 
74 /**
75  * Return interrupt number (1 - 7), -1 means no interrupt.
76  * Note that the interrupt stays pending if it can't be executed yet
77  * due to the interrupt level field in the SR.
78  */
intlev(void)79 int intlev(void)
80 {
81 	if ( pendingInterrupts & (1 << 6) )		/* MFP/DSP interrupt ? */
82 		return 6;
83 	else if ( pendingInterrupts & (1 << 4) )	/* VBL interrupt ? */
84 		return 4;
85 	else if ( pendingInterrupts & (1 << 2) )	/* HBL interrupt ? */
86 		return 2;
87 
88 	return -1;
89 }
90 
91 
UAE_Set_Quit_Reset(bool hard)92 void UAE_Set_Quit_Reset ( bool hard )
93 {
94 //fprintf ( stderr , "UAE_Set_Quit_Reset %d\n" , hard );
95 	if ( hard )
96 		quit_program = UAE_RESET_HARD;
97 	else
98 		quit_program = UAE_RESET;
99 }
100 
101 
UAE_Set_State_Save(void)102 void UAE_Set_State_Save ( void )
103 {
104 //fprintf ( stderr , "UAE_Set_State_Save\n" );
105 	savestate_state = STATE_SAVE;
106 }
107 
108 
UAE_Set_State_Restore(void)109 void UAE_Set_State_Restore ( void )
110 {
111 //fprintf ( stderr , "UAE_Set_State_Restore\n" );
112 	savestate_state = STATE_RESTORE;
113 }
114 
115 
116 
117 /**
118  * Replace WinUAE's save_state / restore_state functions with Hatari's specific ones
119  */
save_state(const TCHAR * filename,const TCHAR * description)120 int save_state (const TCHAR *filename, const TCHAR *description)
121 {
122 //fprintf ( stderr , "save_state in\n" );
123 	MemorySnapShot_Capture_Do ();
124 //fprintf ( stderr , "save_state out\n" );
125 	savestate_state = 0;
126 	return 0;					/* return value is not used */
127 }
128 
129 
restore_state(const TCHAR * filename)130 void restore_state (const TCHAR *filename)
131 {
132 	MemorySnapShot_Restore_Do ();
133 }
134 
135 
savestate_restore_finish(void)136 void savestate_restore_finish (void)
137 {
138 //fprintf ( stderr , "savestate_restore_finish in %d\n" , quit_program );
139 	if (!isrestore ())
140 		return;
141 	restore_cpu_finish ();
142 	savestate_state = 0;
143 	quit_program = 0;				/* at this point, quit_program was already processed, we must reset it */
144 //fprintf ( stderr , "savestate_restore_finish out %d\n" , quit_program );
145 }
146 
147 
148 
149 
150 /**
151  * Initialize 680x0 emulation
152  */
Init680x0(void)153 int Init680x0(void)
154 {
155 //fprintf ( stderr , "Init680x0 in\n" );
156 	init_m68k();
157 //fprintf ( stderr , "Init680x0 out\n" );
158 	return true;
159 }
160 
161 
162 /**
163  * Deinitialize 680x0 emulation
164  */
Exit680x0(void)165 void Exit680x0(void)
166 {
167 	memory_uninit();
168 
169 	free(table68k);
170 	table68k = NULL;
171 }
172 
173 
174 /**
175  * Execute a 'NOP' opcode (increment PC by 2 bytes and take care
176  * of prefetch at the CPU level depending on the current CPU mode)
177  * This is used to return from Gemdos / Natfeats interception, by ignoring
178  * the intercepted opcode and executing a NOP instead once the work has been done.
179  */
CpuDoNOP(void)180 static void	CpuDoNOP ( void )
181 {
182 	(*cpufunctbl[0X4E71])(0x4E71);
183 }
184 
185 
186 /**
187  * Check whether PC is currently in ROM cartridge space - used
188  * to test whether our "illegal" Hatari opcodes should be handled
189  * or whether they are just "normal" illegal opcodes.
190  */
is_cart_pc(void)191 static bool is_cart_pc(void)
192 {
193 	Uint32 pc = M68000_GetPC();
194 
195 	if (ConfigureParams.System.bAddressSpace24 || (pc >> 24) == 0xff)
196 	{
197 		pc &= 0x00ffffff;	/* Mask to 24-bit address */
198 	}
199 
200 	return pc >= 0xfa0000 && pc < 0xfc0000;
201 }
202 
203 
204 /**
205  * This function will be called at system init by the cartridge routine
206  * (after gemdos init, before booting floppies).
207  * The GEMDOS vector (#$84) is setup and we also initialize the connected
208  * drive mask and Line-A variables (for an extended VDI resolution) from here.
209  */
OpCode_SysInit(uae_u32 opcode)210 uae_u32 REGPARAM3 OpCode_SysInit(uae_u32 opcode)
211 {
212 	if (is_cart_pc())
213 	{
214 		/* Add any drives mapped by TOS in the interim */
215 		ConnectedDriveMask |= STMemory_ReadLong(0x4c2);
216 		/* Initialize the connected drive mask */
217 		STMemory_WriteLong(0x4c2, ConnectedDriveMask);
218 
219 		/* Init on boot - see cart.c */
220 		GemDOS_Boot();
221 
222 		/* Update LineA for extended VDI res
223 		 * D0: LineA base, A1: Font base
224 		 */
225 		VDI_LineA(regs.regs[0], regs.regs[9]);
226 
227 		CpuDoNOP();
228 	}
229 	else if (!bUseTos)
230 	{
231 		GemDOS_Boot();
232 		CpuDoNOP();
233 	}
234 	else
235 	{
236 		LOG_TRACE(TRACE_OS_GEMDOS | TRACE_OS_BASE | TRACE_OS_VDI | TRACE_OS_AES,
237 			  "SYSINIT opcode invoked outside of cartridge space\n");
238 		/* illegal instruction */
239 		op_illg(opcode);
240 		fill_prefetch();
241 	}
242 
243 	return 4 * CYCLE_UNIT / 2;
244 }
245 
246 
247 /**
248  * Intercept GEMDOS calls.
249  * Used for GEMDOS HD emulation (see gemdos.c).
250  */
OpCode_GemDos(uae_u32 opcode)251 uae_u32 REGPARAM3 OpCode_GemDos(uae_u32 opcode)
252 {
253 	if (is_cart_pc())
254 	{
255 		GemDOS_OpCode();    /* handler code in gemdos.c */
256 		CpuDoNOP();
257 	}
258 	else
259 	{
260 		LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS opcode invoked outside of cartridge space\n");
261 		/* illegal instruction */
262 		op_illg(opcode);
263 		fill_prefetch();
264 	}
265 
266 	return 4 * CYCLE_UNIT / 2;
267 }
268 
269 
270 /**
271  * This is called after completion of each VDI call
272  */
OpCode_VDI(uae_u32 opcode)273 uae_u32 REGPARAM3 OpCode_VDI(uae_u32 opcode)
274 {
275 	/* this is valid only after VDI trap, called from cartridge code */
276 	if (VDI_OldPC && is_cart_pc())
277 	{
278 		VDI_Complete();
279 
280 		/* Set PC back to where originated from to continue instruction decoding */
281 		m68k_setpc(VDI_OldPC);
282 		VDI_OldPC = 0;
283 	}
284 	else
285 	{
286 		LOG_TRACE(TRACE_OS_VDI, "VDI opcode invoked outside of cartridge space\n");
287 		/* illegal instruction */
288 		op_illg(opcode);
289 	}
290 
291 	fill_prefetch();
292 	return 4 * CYCLE_UNIT / 2;
293 }
294 
295 
296 /**
297  * Emulator Native Features ID opcode interception.
298  */
OpCode_NatFeat_ID(uae_u32 opcode)299 uae_u32 REGPARAM3 OpCode_NatFeat_ID(uae_u32 opcode)
300 {
301 	Uint32 stack = Regs[REG_A7] + SIZE_LONG;	/* skip return address */
302 
303 	if (NatFeat_ID(stack, &(Regs[REG_D0])))
304 	{
305 		CpuDoNOP ();
306 	}
307 	return 4 * CYCLE_UNIT / 2;
308 }
309 
310 /**
311  * Emulator Native Features call opcode interception.
312  */
OpCode_NatFeat_Call(uae_u32 opcode)313 uae_u32 REGPARAM3 OpCode_NatFeat_Call(uae_u32 opcode)
314 {
315 	Uint32 stack = Regs[REG_A7] + SIZE_LONG;	/* skip return address */
316 	Uint16 SR = M68000_GetSR();
317 	bool super;
318 
319 	super = ((SR & SR_SUPERMODE) == SR_SUPERMODE);
320 	if (NatFeat_Call(stack, super, &(Regs[REG_D0])))
321 	{
322 		CpuDoNOP ();
323 	}
324 	return 4 * CYCLE_UNIT / 2;
325 }
326 
327 
buf_out(TCHAR * buffer,int * bufsize,const TCHAR * format,...)328 TCHAR* buf_out (TCHAR *buffer, int *bufsize, const TCHAR *format, ...)
329 {
330 	va_list parms;
331 
332 	if (buffer == NULL)
333 	{
334 		return NULL;
335 	}
336 
337 	va_start (parms, format);
338 	vsnprintf (buffer, (*bufsize) - 1, format, parms);
339 	va_end (parms);
340 	*bufsize -= _tcslen (buffer);
341 
342 	return buffer + _tcslen (buffer);
343 }
344 
error_log(const TCHAR * format,...)345 void error_log(const TCHAR *format, ...)
346 {
347 	va_list parms;
348 
349 	va_start(parms, format);
350 	vfprintf(stderr, format, parms);
351 	va_end(parms);
352 
353 	if (format[strlen(format) - 1] != '\n')
354 	{
355 		fputc('\n', stderr);
356 	}
357 }
358