Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/m68k/m68kcpu.c
2 views
1
#include "../cinterface/callbacks.h"
2
3
/* ======================================================================== */
4
/* MAIN 68K CORE */
5
/* ======================================================================== */
6
7
extern int vdp_68k_irq_ack(int int_level);
8
9
#define m68ki_cpu m68k
10
#define MUL (7)
11
12
/* ======================================================================== */
13
/* ================================ INCLUDES ============================== */
14
/* ======================================================================== */
15
16
#ifndef BUILD_TABLES
17
#include "m68ki_cycles.h"
18
#endif
19
20
#include "m68kconf.h"
21
#include "m68kcpu.h"
22
#include "m68kops.h"
23
#include "shared.h"
24
25
/* ======================================================================== */
26
/* ================================= DATA ================================= */
27
/* ======================================================================== */
28
29
#ifdef BUILD_TABLES
30
static unsigned char m68ki_cycles[0x10000];
31
#endif
32
33
static int irq_latency;
34
35
m68ki_cpu_core m68k;
36
37
38
/* ======================================================================== */
39
/* =============================== CALLBACKS ============================== */
40
/* ======================================================================== */
41
42
/* Default callbacks used if the callback hasn't been set yet, or if the
43
* callback is set to NULL
44
*/
45
46
#if M68K_EMULATE_INT_ACK == OPT_ON
47
/* Interrupt acknowledge */
48
static int default_int_ack_callback(int int_level)
49
{
50
CPU_INT_LEVEL = 0;
51
return M68K_INT_ACK_AUTOVECTOR;
52
}
53
#endif
54
55
#if M68K_EMULATE_RESET == OPT_ON
56
/* Called when a reset instruction is executed */
57
static void default_reset_instr_callback(void)
58
{
59
}
60
#endif
61
62
#if M68K_TAS_HAS_CALLBACK == OPT_ON
63
/* Called when a tas instruction is executed */
64
static int default_tas_instr_callback(void)
65
{
66
return 1; // allow writeback
67
}
68
#endif
69
70
#if M68K_EMULATE_FC == OPT_ON
71
/* Called every time there's bus activity (read/write to/from memory */
72
static void default_set_fc_callback(unsigned int new_fc)
73
{
74
}
75
#endif
76
77
78
/* ======================================================================== */
79
/* ================================= API ================================== */
80
/* ======================================================================== */
81
82
/* Access the internals of the CPU */
83
unsigned int m68k_get_reg(m68k_register_t regnum)
84
{
85
switch(regnum)
86
{
87
case M68K_REG_D0: return m68ki_cpu.dar[0];
88
case M68K_REG_D1: return m68ki_cpu.dar[1];
89
case M68K_REG_D2: return m68ki_cpu.dar[2];
90
case M68K_REG_D3: return m68ki_cpu.dar[3];
91
case M68K_REG_D4: return m68ki_cpu.dar[4];
92
case M68K_REG_D5: return m68ki_cpu.dar[5];
93
case M68K_REG_D6: return m68ki_cpu.dar[6];
94
case M68K_REG_D7: return m68ki_cpu.dar[7];
95
case M68K_REG_A0: return m68ki_cpu.dar[8];
96
case M68K_REG_A1: return m68ki_cpu.dar[9];
97
case M68K_REG_A2: return m68ki_cpu.dar[10];
98
case M68K_REG_A3: return m68ki_cpu.dar[11];
99
case M68K_REG_A4: return m68ki_cpu.dar[12];
100
case M68K_REG_A5: return m68ki_cpu.dar[13];
101
case M68K_REG_A6: return m68ki_cpu.dar[14];
102
case M68K_REG_A7: return m68ki_cpu.dar[15];
103
case M68K_REG_PC: return MASK_OUT_ABOVE_32(m68ki_cpu.pc);
104
case M68K_REG_SR: return m68ki_cpu.t1_flag |
105
(m68ki_cpu.s_flag << 11) |
106
m68ki_cpu.int_mask |
107
((m68ki_cpu.x_flag & XFLAG_SET) >> 4) |
108
((m68ki_cpu.n_flag & NFLAG_SET) >> 4) |
109
((!m68ki_cpu.not_z_flag) << 2) |
110
((m68ki_cpu.v_flag & VFLAG_SET) >> 6) |
111
((m68ki_cpu.c_flag & CFLAG_SET) >> 8);
112
case M68K_REG_SP: return m68ki_cpu.dar[15];
113
case M68K_REG_USP: return m68ki_cpu.s_flag ? m68ki_cpu.sp[0] : m68ki_cpu.dar[15];
114
case M68K_REG_ISP: return m68ki_cpu.s_flag ? m68ki_cpu.dar[15] : m68ki_cpu.sp[4];
115
#if M68K_EMULATE_PREFETCH
116
case M68K_REG_PREF_ADDR: return m68ki_cpu.pref_addr;
117
case M68K_REG_PREF_DATA: return m68ki_cpu.pref_data;
118
#endif
119
case M68K_REG_IR: return m68ki_cpu.ir;
120
default: return 0;
121
}
122
}
123
124
void m68k_set_reg(m68k_register_t regnum, unsigned int value)
125
{
126
switch(regnum)
127
{
128
case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
129
case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
130
case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
131
case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
132
case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
133
case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
134
case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
135
case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
136
case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
137
case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
138
case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
139
case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
140
case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
141
case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
142
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
143
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
144
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
145
case M68K_REG_SR: m68ki_set_sr(value); return;
146
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
147
case M68K_REG_USP: if(FLAG_S)
148
REG_USP = MASK_OUT_ABOVE_32(value);
149
else
150
REG_SP = MASK_OUT_ABOVE_32(value);
151
return;
152
case M68K_REG_ISP: if(FLAG_S)
153
REG_SP = MASK_OUT_ABOVE_32(value);
154
else
155
REG_ISP = MASK_OUT_ABOVE_32(value);
156
return;
157
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
158
#if M68K_EMULATE_PREFETCH
159
case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return;
160
#endif
161
default: return;
162
}
163
}
164
165
/* Set the callbacks */
166
#if M68K_EMULATE_INT_ACK == OPT_ON
167
void m68k_set_int_ack_callback(int (*callback)(int int_level))
168
{
169
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
170
}
171
#endif
172
173
#if M68K_EMULATE_RESET == OPT_ON
174
void m68k_set_reset_instr_callback(void (*callback)(void))
175
{
176
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
177
}
178
#endif
179
180
#if M68K_TAS_HAS_CALLBACK == OPT_ON
181
void m68k_set_tas_instr_callback(int (*callback)(void))
182
{
183
CALLBACK_TAS_INSTR = callback ? callback : default_tas_instr_callback;
184
}
185
#endif
186
187
#if M68K_EMULATE_FC == OPT_ON
188
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
189
{
190
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
191
}
192
#endif
193
194
#ifdef LOGVDP
195
extern void error(char *format, ...);
196
extern uint16 v_counter;
197
#endif
198
199
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
200
/* KS: Modified so that IPL* bits match with mask positions in the SR
201
* and cleaned out remenants of the interrupt controller.
202
*/
203
void m68k_update_irq(unsigned int mask)
204
{
205
/* Update IRQ level */
206
CPU_INT_LEVEL |= (mask << 8);
207
208
#ifdef LOGVDP
209
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
210
#endif
211
}
212
213
void m68k_set_irq(unsigned int int_level)
214
{
215
/* Set IRQ level */
216
CPU_INT_LEVEL = int_level << 8;
217
218
#ifdef LOGVDP
219
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
220
#endif
221
}
222
223
/* IRQ latency (Fatal Rewind, Sesame's Street Counting Cafe)*/
224
void m68k_set_irq_delay(unsigned int int_level)
225
{
226
/* Prevent reentrance */
227
if (!irq_latency)
228
{
229
/* This is always triggered from MOVE instructions (VDP CTRL port write) */
230
/* We just make sure this is not a MOVE.L instruction as we could be in */
231
/* the middle of its execution (first memory write). */
232
if ((REG_IR & 0xF000) != 0x2000)
233
{
234
/* Finish executing current instruction */
235
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
236
237
/* One instruction delay before interrupt */
238
irq_latency = 1;
239
m68ki_trace_t1() /* auto-disable (see m68kcpu.h) */
240
m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */
241
REG_IR = m68ki_read_imm_16();
242
m68ki_instruction_jump_table[REG_IR]();
243
m68ki_exception_if_trace() /* auto-disable (see m68kcpu.h) */
244
irq_latency = 0;
245
}
246
247
/* Set IRQ level */
248
CPU_INT_LEVEL = int_level << 8;
249
}
250
251
#ifdef LOGVDP
252
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
253
#endif
254
255
/* Check interrupt mask to process IRQ */
256
m68ki_check_interrupts(); /* Level triggered (IRQ) */
257
}
258
259
260
extern uint8 work_ram[0x10000]; /* 68K RAM */
261
262
void CDLog68k(uint addr, uint flags)
263
{
264
addr &= 0x00FFFFFF;
265
266
//check for sram region first
267
if(sram.on)
268
{
269
if(addr >= sram.start && addr <= sram.end)
270
{
271
biz_cdcallback(addr - sram.start, eCDLog_AddrType_SRAM, flags);
272
return;
273
}
274
}
275
276
if(addr < 0x400000)
277
{
278
uint block64k_rom;
279
280
//apply memory map to process rom address
281
unsigned char* block64k = m68ki_cpu.memory_map[((addr)>>16)&0xff].base;
282
283
//outside the ROM range. complex mapping logic/accessories; not sure how to handle any of this
284
if(block64k < cart.rom || block64k >= cart.rom + cart.romsize)
285
return;
286
287
block64k_rom = block64k - cart.rom;
288
addr = ((addr) & 0xffff) + block64k_rom;
289
290
//outside the ROM range somehow
291
if(addr >= cart.romsize)
292
return;
293
294
biz_cdcallback(addr, eCDLog_AddrType_MDCART, flags);
295
return;
296
}
297
298
if(addr > 0xFF0000)
299
{
300
//no memory map needed
301
biz_cdcallback(addr & 0xFFFF, eCDLog_AddrType_RAM68k, flags);
302
return;
303
}
304
}
305
306
void m68k_run(unsigned int cycles)
307
{
308
/* Make sure CPU is not already ahead */
309
if (m68k.cycles >= cycles)
310
{
311
return;
312
}
313
314
/* Check interrupt mask to process IRQ if needed */
315
m68ki_check_interrupts();
316
317
/* Make sure we're not stopped */
318
if (CPU_STOPPED)
319
{
320
m68k.cycles = cycles;
321
return;
322
}
323
324
/* Save end cycles count for when CPU is stopped */
325
m68k.cycle_end = cycles;
326
327
/* Return point for when we have an address error (TODO: use goto) */
328
m68ki_set_address_error_trap() /* auto-disable (see m68kcpu.h) */
329
330
#ifdef LOGVDP
331
error("[%d][%d] m68k run to %d cycles (%x), irq mask = %x (%x)\n", v_counter, m68k.cycles, cycles, m68k.pc,FLAG_INT_MASK, CPU_INT_LEVEL);
332
#endif
333
334
while (m68k.cycles < cycles)
335
{
336
/* Set tracing accodring to T1. */
337
m68ki_trace_t1() /* auto-disable (see m68kcpu.h) */
338
339
/* Set the address space for reads */
340
m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */
341
342
if (biz_tracecb)
343
biz_tracecb();
344
345
if (biz_execcb)
346
biz_execcb(REG_PC);
347
348
if(biz_cdcallback)
349
{
350
CDLog68k(REG_PC,eCDLog_Flags_Exec68k);
351
CDLog68k(REG_PC+1,eCDLog_Flags_Exec68k);
352
}
353
354
biz_lastpc = REG_PC;
355
356
/* Decode next instruction */
357
REG_IR = m68ki_read_imm_16();
358
359
/* Execute instruction */
360
m68ki_instruction_jump_table[REG_IR]();
361
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
362
363
/* Trace m68k_exception, if necessary */
364
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
365
}
366
}
367
368
void m68k_init(void)
369
{
370
#ifdef BUILD_TABLES
371
static uint emulation_initialized = 0;
372
373
/* The first call to this function initializes the opcode handler jump table */
374
if(!emulation_initialized)
375
{
376
m68ki_build_opcode_table();
377
emulation_initialized = 1;
378
}
379
#endif
380
381
#if M68K_EMULATE_INT_ACK == OPT_ON
382
m68k_set_int_ack_callback(NULL);
383
#endif
384
#if M68K_EMULATE_RESET == OPT_ON
385
m68k_set_reset_instr_callback(NULL);
386
#endif
387
#if M68K_TAS_HAS_CALLBACK == OPT_ON
388
m68k_set_tas_instr_callback(NULL);
389
#endif
390
#if M68K_EMULATE_FC == OPT_ON
391
m68k_set_fc_callback(NULL);
392
#endif
393
}
394
395
/* Pulse the RESET line on the CPU */
396
void m68k_pulse_reset(void)
397
{
398
/* Clear all stop levels */
399
CPU_STOPPED = 0;
400
#if M68K_EMULATE_ADDRESS_ERROR
401
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
402
#endif
403
404
/* Turn off tracing */
405
FLAG_T1 = 0;
406
m68ki_clear_trace()
407
408
/* Interrupt mask to level 7 */
409
FLAG_INT_MASK = 0x0700;
410
CPU_INT_LEVEL = 0;
411
irq_latency = 0;
412
413
/* Go to supervisor mode */
414
m68ki_set_s_flag(SFLAG_SET);
415
416
/* Invalidate the prefetch queue */
417
#if M68K_EMULATE_PREFETCH
418
/* Set to arbitrary number since our first fetch is from 0 */
419
CPU_PREF_ADDR = 0x1000;
420
#endif /* M68K_EMULATE_PREFETCH */
421
422
/* Read the initial stack pointer and program counter */
423
m68ki_jump(0);
424
REG_SP = m68ki_read_imm_32();
425
REG_PC = m68ki_read_imm_32();
426
m68ki_jump(REG_PC);
427
428
#if M68K_EMULATE_ADDRESS_ERROR
429
CPU_RUN_MODE = RUN_MODE_NORMAL;
430
#endif
431
432
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
433
}
434
435
void m68k_pulse_halt(void)
436
{
437
/* Pulse the HALT line on the CPU */
438
CPU_STOPPED |= STOP_LEVEL_HALT;
439
}
440
441
void m68k_clear_halt(void)
442
{
443
/* Clear the HALT line on the CPU */
444
CPU_STOPPED &= ~STOP_LEVEL_HALT;
445
}
446
447
/* ======================================================================== */
448
/* ============================== END OF FILE ============================= */
449
/* ======================================================================== */
450
451