Added detection for the unsigned/signed short type
[clinton/Virtual-Jaguar-Rx.git] / src / m68000 / m68kinterface.c
CommitLineData
cf76e892
JPM
1//
2// m68kinterface.c: Code interface to the UAE 68000 core and support code
3//
4// by James Hammons
5// (C) 2011 Underground Software
6//
7// JLH = James Hammons <jlhamm@acm.org>
8//
9// Who When What
10// --- ---------- -------------------------------------------------------------
11// JLH 10/28/2011 Created this file ;-)
12//
13
14#include "m68kinterface.h"
15//#include <pthread.h>
16#include "cpudefs.h"
17#include "inlines.h"
18#include "cpuextra.h"
19#include "readcpu.h"
20
21// Exception Vectors handled by emulation
22#define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */
23#define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */
24#define EXCEPTION_ILLEGAL_INSTRUCTION 4
25#define EXCEPTION_ZERO_DIVIDE 5
26#define EXCEPTION_CHK 6
27#define EXCEPTION_TRAPV 7
28#define EXCEPTION_PRIVILEGE_VIOLATION 8
29#define EXCEPTION_TRACE 9
30#define EXCEPTION_1010 10
31#define EXCEPTION_1111 11
32#define EXCEPTION_FORMAT_ERROR 14
33#define EXCEPTION_UNINITIALIZED_INTERRUPT 15
34#define EXCEPTION_SPURIOUS_INTERRUPT 24
35#define EXCEPTION_INTERRUPT_AUTOVECTOR 24
36#define EXCEPTION_TRAP_BASE 32
37
38// These are found in obj/cpustbl.c (generated by gencpu)
39
40//extern const struct cputbl op_smalltbl_0_ff[]; /* 68040 */
41//extern const struct cputbl op_smalltbl_1_ff[]; /* 68020 + 68881 */
42//extern const struct cputbl op_smalltbl_2_ff[]; /* 68020 */
43//extern const struct cputbl op_smalltbl_3_ff[]; /* 68010 */
44extern const struct cputbl op_smalltbl_4_ff[]; /* 68000 */
45extern const struct cputbl op_smalltbl_5_ff[]; /* 68000 slow but compatible. */
46
47// Externs, supplied by the user...
48//extern int irq_ack_handler(int);
49
50// Function prototypes...
51STATIC_INLINE void m68ki_check_interrupts(void);
52void m68ki_exception_interrupt(uint32_t intLevel);
53STATIC_INLINE uint32_t m68ki_init_exception(void);
54STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr);
55unsigned long IllegalOpcode(uint32_t opcode);
56void BuildCPUFunctionTable(void);
57void m68k_set_irq2(unsigned int intLevel);
58
59// Local "Global" vars
60static int32_t initialCycles;
61cpuop_func * cpuFunctionTable[65536];
62
63// By virtue of the fact that m68k_set_irq() can be called asychronously by
64// another thread, we need something along the lines of this:
65static int checkForIRQToHandle = 0;
66//static pthread_mutex_t executionLock = PTHREAD_MUTEX_INITIALIZER;
67static int IRQLevelToHandle = 0;
68
69#if 0
70#define ADD_CYCLES(A) m68ki_remaining_cycles += (A)
71#define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
72#define SET_CYCLES(A) m68ki_remaining_cycles = A
73#define GET_CYCLES() m68ki_remaining_cycles
74#define USE_ALL_CYCLES() m68ki_remaining_cycles = 0
75
76#define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */
77#define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */
78#define CPU_STOPPED m68ki_cpu.stopped
79#define CPU_PREF_ADDR m68ki_cpu.pref_addr
80#define CPU_PREF_DATA m68ki_cpu.pref_data
81#define CPU_ADDRESS_MASK m68ki_cpu.address_mask
82#define CPU_SR_MASK m68ki_cpu.sr_mask
83#endif
84
85#define CPU_DEBUG
86
87
88void Dasm(uint32_t offset, uint32_t qt)
89{
90#ifdef CPU_DEBUG
91// back up a few instructions...
92//offset -= 100;
93 static char buffer[2048];//, mem[64];
94 int pc = offset, oldpc;
95 uint32_t i;
96
97 for(i=0; i<qt; i++)
98 {
99/* oldpc = pc;
100 for(int j=0; j<64; j++)
101 mem[j^0x01] = jaguar_byte_read(pc + j);
102
103 pc += Dasm68000((char *)mem, buffer, 0);
104 WriteLog("%08X: %s\n", oldpc, buffer);//*/
105 oldpc = pc;
106 pc += m68k_disassemble(buffer, pc, 0, 1);//M68K_CPU_TYPE_68000);
107// WriteLog("%08X: %s\n", oldpc, buffer);//*/
108 printf("%08X: %s\n", oldpc, buffer);//*/
109 }
110#endif
111}
112
113
114#ifdef CPU_DEBUG
115void DumpRegisters(void)
116{
117 uint32_t i;
118
119 for(i=0; i<16; i++)
120 {
121 printf("%s%i: %08X ", (i < 8 ? "D" : "A"), i & 0x7, regs.regs[i]);
122
123 if ((i & 0x03) == 3)
124 printf("\n");
125 }
126}
127#endif
128
129
130int M68KGetCurrentOpcodeFamily(void)
131{
132 return (OpcodeFamily);
133}
134
135
136// Get M68K debug halt status
137int M68KDebugHaltStatus(void)
138{
139 return (regs.spcflags & SPCFLAG_DEBUGGER);
140}
141
142
143// Halt M68k
a8c13b4d 144int M68KDebugHalt(void)
cf76e892 145{
a8c13b4d 146 return (regs.spcflags |= SPCFLAG_DEBUGGER);
cf76e892
JPM
147}
148
149
150// Resume M68k
151void M68KDebugResume(void)
152{
153 regs.spcflags &= ~SPCFLAG_DEBUGGER;
154}
155
156
157void m68k_set_cpu_type(unsigned int type)
158{
159}
160
161
162// Pulse the RESET line on the CPU
163void m68k_pulse_reset(void)
164{
165 static uint32_t emulation_initialized = 0;
166
167 // The first call to this function initializes the opcode handler jump table
168 if (!emulation_initialized)
169 {
170#if 0
171 m68ki_build_opcode_table();
172 m68k_set_int_ack_callback(NULL);
173 m68k_set_bkpt_ack_callback(NULL);
174 m68k_set_reset_instr_callback(NULL);
175 m68k_set_pc_changed_callback(NULL);
176 m68k_set_fc_callback(NULL);
177 m68k_set_instr_hook_callback(NULL);
178#else
179 // Build opcode handler table here...
180 read_table68k();
181 do_merges();
182 BuildCPUFunctionTable();
183#endif
184 emulation_initialized = 1;
185 }
186
187// if (CPU_TYPE == 0) /* KW 990319 */
188// m68k_set_cpu_type(M68K_CPU_TYPE_68000);
189
190#if 0
191 /* Clear all stop levels and eat up all remaining cycles */
192 CPU_STOPPED = 0;
193 SET_CYCLES(0);
194
195 /* Turn off tracing */
196 FLAG_T1 = FLAG_T0 = 0;
197 m68ki_clear_trace();
198 /* Interrupt mask to level 7 */
199 FLAG_INT_MASK = 0x0700;
200 /* Reset VBR */
201 REG_VBR = 0;
202 /* Go to supervisor mode */
203 m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
204
205 /* Invalidate the prefetch queue */
206#if M68K_EMULATE_PREFETCH
207 /* Set to arbitrary number since our first fetch is from 0 */
208 CPU_PREF_ADDR = 0x1000;
209#endif /* M68K_EMULATE_PREFETCH */
210
211 /* Read the initial stack pointer and program counter */
212 m68ki_jump(0);
213 REG_SP = m68ki_read_imm_32();
214 REG_PC = m68ki_read_imm_32();
215 m68ki_jump(REG_PC);
216#else
217 checkForIRQToHandle = 0;
218 regs.spcflags = 0;
219 regs.stopped = 0;
220 regs.remainingCycles = 0;
221
222 regs.intmask = 0x07;
223 regs.s = 1; // Supervisor mode ON
224
225 // Read initial SP and PC
226 m68k_areg(regs, 7) = m68k_read_memory_32(0);
227 m68k_setpc(m68k_read_memory_32(4));
228 refill_prefetch(m68k_getpc(), 0);
229#endif
230}
231
232
233int m68k_execute(int num_cycles)
234{
235 if (regs.stopped)
236 {
237 regs.remainingCycles = 0; // int32_t
238 regs.interruptCycles = 0; // uint32_t
239
240 return num_cycles;
241 }
242
243#if 0
244 /* Set our pool of clock cycles available */
245 SET_CYCLES(num_cycles);
246 m68ki_initial_cycles = num_cycles;
247
248 /* ASG: update cycles */
249 USE_CYCLES(CPU_INT_CYCLES);
250 CPU_INT_CYCLES = 0;
251
252 /* Return point if we had an address error */
253 m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
254#else
255 regs.remainingCycles = num_cycles;
256 /*int32_t*/ initialCycles = num_cycles;
257
258 regs.remainingCycles -= regs.interruptCycles;
259 regs.interruptCycles = 0;
260#endif
261
262 /* Main loop. Keep going until we run out of clock cycles */
263 do
264 {
265 // This is so our debugging code can break in on a dime.
266 // Otherwise, this is just extra slow down :-P
267 if (regs.spcflags & SPCFLAG_DEBUGGER)
268 {
269 // Not sure this is correct... :-P
270 num_cycles = initialCycles - regs.remainingCycles;
271 regs.remainingCycles = 0; // int32_t
272 regs.interruptCycles = 0; // uint32_t
273
274 return num_cycles;
275 }
276#if 0
277 /* Set tracing accodring to T1. (T0 is done inside instruction) */
278 m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
279
280 /* Set the address space for reads */
281 m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
282
283 /* Call external hook to peek at CPU */
284 m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
285
286 /* Record previous program counter */
287 REG_PPC = REG_PC;
288
289 /* Read an instruction and call its handler */
290 REG_IR = m68ki_read_imm_16();
291 m68ki_instruction_jump_table[REG_IR]();
292 USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
293
294 /* Trace m68k_exception, if necessary */
295 m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
296#else
297//Testing Hover Strike...
298#if 0
299//Dasm(regs.pc, 1);
300static int hitCount = 0;
301static int inRoutine = 0;
302static int instSeen;
303
304//if (regs.pc == 0x80340A)
305if (regs.pc == 0x803416)
306{
307 hitCount++;
308 inRoutine = 1;
309 instSeen = 0;
310 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, regs.regs[8], regs.regs[9]);
311}
312else if (regs.pc == 0x803422)
313{
314 inRoutine = 0;
315 printf("(%i instructions)\n", instSeen);
316}
317
318if (inRoutine)
319 instSeen++;
320#endif
321// AvP testing... (problem was: 32 bit addresses on 24 bit address cpu--FIXED)
322#if 0
323 static int go = 0;
324
325 if (regs.pc == 0x94BA)
326 {
327 go = 1;
328 printf("\n");
329 }
330
331 if (regs.pc == 0x94C6)
332 go = 0;
333
334// if (regs.regs[10] == 0xFFFFFFFF && go)
335 if (go)
336 {
337// printf("A2=-1, PC=%08X\n", regs.pc);
338// go = 0;
339// Dasm(regs.pc, 130);
340 Dasm(regs.pc, 1);
341 DumpRegisters();
342 }
343//94BA: 2468 0000 MOVEA.L (A0,$0000) == $0002328A, A2
344//94BE: 200A MOVE.L A2, D0
345//94C0: 6A02 BPL.B $94C4
346//94C2: 2452 MOVEA.L (A2), A2 ; <--- HERE
347//94C4: 4283 CLR.L D3
348#endif
349// pthread_mutex_lock(&executionLock);
350 if (checkForIRQToHandle)
351 {
352 checkForIRQToHandle = 0;
353 m68k_set_irq2(IRQLevelToHandle);
354 }
355
356#ifdef M68K_HOOK_FUNCTION
357 M68KInstructionHook();
358#endif
359 uint32_t opcode = get_iword(0);
360//if ((opcode & 0xFFF8) == 0x31C0)
361//{
362// printf("MOVE.W D%i, EA\n", opcode & 0x07);
363//}
364 int32_t cycles;
365 if (regs.spcflags & SPCFLAG_DEBUGGER)
366 {
367 cycles = 0;
368 }
369 else
370 {
371 cycles = (int32_t)(*cpuFunctionTable[opcode])(opcode);
372 }
373 regs.remainingCycles -= cycles;
374// pthread_mutex_unlock(&executionLock);
375
376//printf("Executed opcode $%04X (%i cycles)...\n", opcode, cycles);
377#endif
378 }
379 while (regs.remainingCycles > 0);
380
381#if 0
382 /* set previous PC to current PC for the next entry into the loop */
383 REG_PPC = REG_PC;
384
385 /* ASG: update cycles */
386 USE_CYCLES(CPU_INT_CYCLES);
387 CPU_INT_CYCLES = 0;
388
389 /* return how many clocks we used */
390 return m68ki_initial_cycles - GET_CYCLES();
391#else
392 regs.remainingCycles -= regs.interruptCycles;
393 regs.interruptCycles = 0;
394
395 // Return # of clock cycles used
396 return initialCycles - regs.remainingCycles;
397#endif
398}
399
400
401void m68k_set_irq(unsigned int intLevel)
402{
403 // We need to check for stopped state as well...
404 if (regs.stopped)
405 {
406 m68k_set_irq2(intLevel);
407 return;
408 }
409
410 // Since this can be called asynchronously, we need to fix it so that it
411 // doesn't fuck up the main execution loop.
412 IRQLevelToHandle = intLevel;
413 checkForIRQToHandle = 1;
414}
415
416
417/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
418void m68k_set_irq2(unsigned int intLevel)
419{
420// pthread_mutex_lock(&executionLock);
421// printf("m68k_set_irq: Could not get the lock!!!\n");
422
423 int oldLevel = regs.intLevel;
424 regs.intLevel = intLevel;
425
426 // A transition from < 7 to 7 always interrupts (NMI)
427 // Note: Level 7 can also level trigger like a normal IRQ
428 if (oldLevel != 0x07 && regs.intLevel == 0x07)
429 m68ki_exception_interrupt(7); // Edge triggered level 7 (NMI)
430 else
431 m68ki_check_interrupts(); // Level triggered (IRQ)
432
433// pthread_mutex_unlock(&executionLock);
434}
435
436
437// Check for interrupts
438STATIC_INLINE void m68ki_check_interrupts(void)
439{
440#if 0
441 if(CPU_INT_LEVEL > FLAG_INT_MASK)
442 m68ki_exception_interrupt(CPU_INT_LEVEL>>8);
443#else
444 if (regs.intLevel > regs.intmask)
445 m68ki_exception_interrupt(regs.intLevel);
446#endif
447}
448
449
450// Service an interrupt request and start exception processing
451void m68ki_exception_interrupt(uint32_t intLevel)
452{
453#if 0
454 uint vector;
455 uint sr;
456 uint new_pc;
457
458 /* Turn off the stopped state */
459 CPU_STOPPED &= ~STOP_LEVEL_STOP;
460
461 /* If we are halted, don't do anything */
462 if(CPU_STOPPED)
463 return;
464
465 /* Acknowledge the interrupt */
466 vector = m68ki_int_ack(int_level);
467
468 /* Get the interrupt vector */
469 if(vector == M68K_INT_ACK_AUTOVECTOR)
470 /* Use the autovectors. This is the most commonly used implementation */
471 vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
472 else if(vector == M68K_INT_ACK_SPURIOUS)
473 /* Called if no devices respond to the interrupt acknowledge */
474 vector = EXCEPTION_SPURIOUS_INTERRUPT;
475 else if(vector > 255)
476 {
477 M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
478 m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
479 return;
480 }
481
482 /* Start exception processing */
483 sr = m68ki_init_exception();
484
485 /* Set the interrupt mask to the level of the one being serviced */
486 FLAG_INT_MASK = int_level<<8;
487
488 /* Get the new PC */
489 new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
490
491 /* If vector is uninitialized, call the uninitialized interrupt vector */
492 if(new_pc == 0)
493 new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR);
494
495 /* Generate a stack frame */
496 m68ki_stack_frame_0000(REG_PC, sr, vector);
497
498 if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
499 {
500 /* Create throwaway frame */
501 m68ki_set_sm_flag(FLAG_S); /* clear M */
502 sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */
503 m68ki_stack_frame_0001(REG_PC, sr, vector);
504 }
505
506 m68ki_jump(new_pc);
507
508 /* Defer cycle counting until later */
509 CPU_INT_CYCLES += CYC_EXCEPTION[vector];
510
511#if !M68K_EMULATE_INT_ACK
512 /* Automatically clear IRQ if we are not using an acknowledge scheme */
513 CPU_INT_LEVEL = 0;
514#endif /* M68K_EMULATE_INT_ACK */
515#else
516 // Turn off the stopped state (N.B.: normal 68K behavior!)
517 regs.stopped = 0;
518
519//JLH: need to add halt state?
520// prolly, for debugging/alpine mode... :-/
521// but then again, this should be handled already by the main execution loop :-P
522 // If we are halted, don't do anything
523// if (regs.halted)
524// return;
525
526 // Acknowledge the interrupt (NOTE: This is a user supplied function!)
527 uint32_t vector = irq_ack_handler(intLevel);
528
529 // Get the interrupt vector
530 if (vector == M68K_INT_ACK_AUTOVECTOR)
531 // Use the autovectors. This is the most commonly used implementation
532 vector = EXCEPTION_INTERRUPT_AUTOVECTOR + intLevel;
533 else if (vector == M68K_INT_ACK_SPURIOUS)
534 // Called if no devices respond to the interrupt acknowledge
535 vector = EXCEPTION_SPURIOUS_INTERRUPT;
536 else if (vector > 255)
537 {
538// M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
539// m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
540 return;
541 }
542
543 // Start exception processing
544 uint32_t sr = m68ki_init_exception();
545
546 // Set the interrupt mask to the level of the one being serviced
547 regs.intmask = intLevel;
548
549#if 0
550extern int startM68KTracing;
551if (startM68KTracing)
552{
553 printf("IRQ: old PC=%06X, ", regs.pc);
554}
555#endif
556
557 // Get the new PC
558 uint32_t newPC = m68k_read_memory_32(vector << 2);
559
560#if 0
561if (startM68KTracing)
562{
563 printf("new PC=%06X, vector=%u, ", newPC, vector);
564}
565#endif
566
567 // If vector is uninitialized, call the uninitialized interrupt vector
568 if (newPC == 0)
569 newPC = m68k_read_memory_32(EXCEPTION_UNINITIALIZED_INTERRUPT << 2);
570
571 // Generate a stack frame
572 m68ki_stack_frame_3word(regs.pc, sr);
573
574 m68k_setpc(newPC);
575#if 0
576if (startM68KTracing)
577{
578 printf("(PC=%06X)\n", regs.pc);
579}
580#endif
581
582 // Defer cycle counting until later
583 regs.interruptCycles += 56; // NOT ACCURATE-- !!! FIX !!!
584// CPU_INT_CYCLES += CYC_EXCEPTION[vector];
585#endif
586}
587
588
589// Initiate exception processing
590STATIC_INLINE uint32_t m68ki_init_exception(void)
591{
592#if 0
593 /* Save the old status register */
594 uint sr = m68ki_get_sr();
595
596 /* Turn off trace flag, clear pending traces */
597 FLAG_T1 = FLAG_T0 = 0;
598 m68ki_clear_trace();
599 /* Enter supervisor mode */
600 m68ki_set_s_flag(SFLAG_SET);
601
602 return sr;
603#else
604 MakeSR();
605 uint32_t sr = regs.sr; // Save old status register
606 regs.s = 1; // Set supervisor mode
607
608 return sr;
609#endif
610}
611
612
613// 3 word stack frame (68000 only)
614STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr)
615{
616#if 0
617 m68ki_push_32(pc);
618 m68ki_push_16(sr);
619#else
620 // Push PC on stack:
621 m68k_areg(regs, 7) -= 4;
622 m68k_write_memory_32(m68k_areg(regs, 7), pc);
623 // Push SR on stack:
624 m68k_areg(regs, 7) -= 2;
625 m68k_write_memory_16(m68k_areg(regs, 7), sr);
626#endif
627}
628
629
630unsigned int m68k_get_reg(void * context, m68k_register_t reg)
631{
632 if (reg <= M68K_REG_A7)
633 return regs.regs[reg];
634 else if (reg == M68K_REG_PC)
635 return regs.pc;
636 else if (reg == M68K_REG_SR)
637 {
638 MakeSR();
639 return regs.sr;
640 }
641 else if (reg == M68K_REG_SP)
642 return regs.regs[15];
643
644 return 0;
645}
646
647
648void m68k_set_reg(m68k_register_t reg, unsigned int value)
649{
650 if (reg <= M68K_REG_A7)
651 regs.regs[reg] = value;
652 else if (reg == M68K_REG_PC)
653 regs.pc = value;
654 else if (reg == M68K_REG_SR)
655 {
656 regs.sr = value;
657 MakeFromSR();
658 }
659 else if (reg == M68K_REG_SP)
660 regs.regs[15] = value;
661}
662
663
664//
665// Check if the instruction is a valid one
666//
667unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type)
668{
669 instruction &= 0xFFFF;
670
671 if (cpuFunctionTable[instruction] == IllegalOpcode)
672 return 0;
673
674 return 1;
675}
676
677
678// Dummy functions, for now, until we prove the concept here. :-)
679
680// Temp, while we're using the Musashi disassembler...
681#if 0
682unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
683{
684 return 0;
685}
686#endif
687
688int m68k_cycles_run(void) {} /* Number of cycles run so far */
689int m68k_cycles_remaining(void) {} /* Number of cycles left */
690//void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */
691//void m68k_end_timeslice(void) {} /* End timeslice now */
692
693
694void m68k_modify_timeslice(int cycles)
695{
696 regs.remainingCycles = cycles;
697}
698
699
700void m68k_end_timeslice(void)
701{
702#if 0
703 m68ki_initial_cycles = GET_CYCLES();
704 SET_CYCLES(0);
705#else
706 initialCycles = regs.remainingCycles;
707 regs.remainingCycles = 0;
708#endif
709}
710
711
712unsigned long IllegalOpcode(uint32_t opcode)
713{
714#if 0
715 uint32_t pc = m68k_getpc ();
716#endif
717 if ((opcode & 0xF000) == 0xF000)
718 {
719 Exception(0x0B, 0, M68000_EXC_SRC_CPU); // LineF exception...
720 return 4;
721 }
722 else if ((opcode & 0xF000) == 0xA000)
723 {
724 Exception(0x0A, 0, M68000_EXC_SRC_CPU); // LineA exception...
725 return 4;
726 }
727
728#if 0
729 write_log ("Illegal instruction: %04x at %08lx\n", opcode, (long)pc);
730#endif
731
732 Exception(0x04, 0, M68000_EXC_SRC_CPU); // Illegal opcode exception...
733 return 4;
734}
735
736
737void BuildCPUFunctionTable(void)
738{
739 int i;
740 unsigned long opcode;
741
742 // We're only using the "fast" 68000 emulation here, not the "compatible"
743 // ("fast" doesn't throw exceptions, so we're using "compatible" now :-P)
744#if 0
745 const struct cputbl * tbl = (currprefs.cpu_compatible
746 ? op_smalltbl_5_ff : op_smalltbl_4_ff);
747#else
748//let's try "compatible" and see what happens here...
749// const struct cputbl * tbl = op_smalltbl_4_ff;
750 const struct cputbl * tbl = op_smalltbl_5_ff;
751#endif
752
753// Log_Printf(LOG_DEBUG, "Building CPU function table (%d %d %d).\n",
754// currprefs.cpu_level, currprefs.cpu_compatible, currprefs.address_space_24);
755
756 // Set all instructions to Illegal...
757 for(opcode=0; opcode<65536; opcode++)
758 cpuFunctionTable[opcode] = IllegalOpcode;
759
760 // Move functions from compact table into our full function table...
761 for(i=0; tbl[i].handler!=NULL; i++)
762 cpuFunctionTable[tbl[i].opcode] = tbl[i].handler;
763
764//JLH: According to readcpu.c, handler is set to -1 and never changes.
765// Actually, it does read this crap in readcpu.c, do_merges() does it... :-P
766// Again, seems like a build time thing could be done here...
767#if 1
768 for(opcode=0; opcode<65536; opcode++)
769 {
770// if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level)
771 if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > 0)
772 continue;
773
774 if (table68k[opcode].handler != -1)
775 {
776//printf("Relocate: $%04X->$%04X\n", table68k[opcode].handler, opcode);
777 cpuop_func * f = cpuFunctionTable[table68k[opcode].handler];
778
779 if (f == IllegalOpcode)
780 abort();
781
782 cpuFunctionTable[opcode] = f;
783 }
784 }
785#endif
786}