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