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