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