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