ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
(Generate patch)

Comparing SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp (file contents):
Revision 1.8 by gbeauche, 2003-10-19T21:37:43Z vs.
Revision 1.17 by gbeauche, 2003-11-10T16:23:58Z

# Line 28 | Line 28
28   #include "macos_util.h"
29   #include "block-alloc.hpp"
30   #include "sigsegv.h"
31 #include "spcflags.h"
31   #include "cpu/ppc/ppc-cpu.hpp"
32   #include "cpu/ppc/ppc-operations.hpp"
33  
# Line 36 | Line 35
35   #include "video.h"
36   #include "name_registry.h"
37   #include "serial.h"
38 + #include "ether.h"
39  
40   #include <stdio.h>
41  
# Line 44 | Line 44
44   #include "mon_disass.h"
45   #endif
46  
47 < #define DEBUG 1
47 > #define DEBUG 0
48   #include "debug.h"
49  
50 + // Emulation time statistics
51 + #define EMUL_TIME_STATS 1
52 +
53 + #if EMUL_TIME_STATS
54 + static clock_t emul_start_time;
55 + static uint32 interrupt_count = 0;
56 + static clock_t interrupt_time = 0;
57 + static uint32 exec68k_count = 0;
58 + static clock_t exec68k_time = 0;
59 + static uint32 native_exec_count = 0;
60 + static clock_t native_exec_time = 0;
61 + static uint32 macos_exec_count = 0;
62 + static clock_t macos_exec_time = 0;
63 + #endif
64 +
65   static void enter_mon(void)
66   {
67          // Start up mon in real-mode
# Line 57 | Line 72 | static void enter_mon(void)
72   }
73  
74   // Enable multicore (main/interrupts) cpu emulation?
75 < #define MULTICORE_CPU 0
75 > #define MULTICORE_CPU (ASYNC_IRQ ? 1 : 0)
76  
77   // Enable Execute68k() safety checks?
78   #define SAFE_EXEC_68K 1
# Line 74 | Line 89 | static void enter_mon(void)
89   // Pointer to Kernel Data
90   static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
91  
92 + // SIGSEGV handler
93 + static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
94 +
95  
96   /**
97   *              PowerPC emulator glue with special 'sheep' opcodes
98   **/
99  
82 struct sheepshaver_exec_return { };
83
100   class sheepshaver_cpu
101          : public powerpc_cpu
102   {
# Line 89 | Line 105 | class sheepshaver_cpu
105  
106   public:
107  
108 <        sheepshaver_cpu()
109 <                : powerpc_cpu()
94 <                { init_decoder(); }
108 >        // Constructor
109 >        sheepshaver_cpu();
110  
111          // Condition Register accessors
112          uint32 get_cr() const           { return cr().get(); }
113          void set_cr(uint32 v)           { cr().set(v); }
114  
115          // Execution loop
116 <        void execute(uint32 pc);
116 >        void execute(uint32 entry, bool enable_cache = false);
117  
118          // Execute 68k routine
119          void execute_68k(uint32 entry, M68kRegisters *r);
# Line 114 | Line 129 | public:
129  
130          // Handle MacOS interrupt
131          void interrupt(uint32 entry);
132 <
118 <        // spcflags for interrupts handling
119 <        static uint32 spcflags;
132 >        void handle_interrupt();
133  
134          // Lazy memory allocator (one item at a time)
135          void *operator new(size_t size)
# Line 126 | Line 139 | public:
139          // FIXME: really make surre array allocation fail at link time?
140          void *operator new[](size_t);
141          void operator delete[](void *p);
142 +
143 +        // Make sure the SIGSEGV handler can access CPU registers
144 +        friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
145   };
146  
131 uint32 sheepshaver_cpu::spcflags = 0;
147   lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
148  
149 + sheepshaver_cpu::sheepshaver_cpu()
150 +        : powerpc_cpu()
151 + {
152 +        init_decoder();
153 + }
154 +
155   void sheepshaver_cpu::init_decoder()
156   {
157   #ifndef PPC_NO_STATIC_II_INDEX_TABLE
# Line 142 | Line 163 | void sheepshaver_cpu::init_decoder()
163  
164          static const instr_info_t sheep_ii_table[] = {
165                  { "sheep",
166 <                  (execute_fn)&sheepshaver_cpu::execute_sheep,
166 >                  (execute_pmf)&sheepshaver_cpu::execute_sheep,
167                    NULL,
168                    D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP
169                  }
# Line 183 | Line 204 | void sheepshaver_cpu::execute_sheep(uint
204                  break;
205  
206          case 1:         // EXEC_RETURN
207 <                throw sheepshaver_exec_return();
207 >                spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
208                  break;
209  
210          case 2:         // EXEC_NATIVE
# Line 216 | Line 237 | void sheepshaver_cpu::execute_sheep(uint
237          }
238   }
239  
219 // Checks for pending interrupts
220 struct execute_nothing {
221        static inline void execute(powerpc_cpu *) { }
222 };
223
224 struct execute_spcflags_check {
225        static inline void execute(powerpc_cpu *cpu) {
226 #if !ASYNC_IRQ
227                if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) {
228                        if (SPCFLAGS_TEST( SPCFLAG_ENTER_MON )) {
229                                SPCFLAGS_CLEAR( SPCFLAG_ENTER_MON );
230                                enter_mon();
231                        }
232                        if (SPCFLAGS_TEST( SPCFLAG_DOINT )) {
233                                SPCFLAGS_CLEAR( SPCFLAG_DOINT );
234                                HandleInterrupt();
235                        }
236                        if (SPCFLAGS_TEST( SPCFLAG_INT )) {
237                                SPCFLAGS_CLEAR( SPCFLAG_INT );
238                                SPCFLAGS_SET( SPCFLAG_DOINT );
239                        }
240                }
241 #endif
242        }
243 };
244
240   // Execution loop
241 < void sheepshaver_cpu::execute(uint32 entry)
241 > void sheepshaver_cpu::execute(uint32 entry, bool enable_cache)
242   {
243 <        try {
249 <                pc() = entry;
250 <                powerpc_cpu::do_execute<execute_nothing, execute_spcflags_check>();
251 <        }
252 <        catch (sheepshaver_exec_return const &) {
253 <                // Nothing, simply return
254 <        }
255 <        catch (...) {
256 <                printf("ERROR: execute() received an unknown exception!\n");
257 <                QuitEmulator();
258 <        }
243 >        powerpc_cpu::execute(entry, enable_cache);
244   }
245  
246   // Handle MacOS interrupt
247   void sheepshaver_cpu::interrupt(uint32 entry)
248   {
249 + #if EMUL_TIME_STATS
250 +        interrupt_count++;
251 +        const clock_t interrupt_start = clock();
252 + #endif
253 +
254   #if !MULTICORE_CPU
255          // Save program counters and branch registers
256          uint32 saved_pc = pc();
# Line 314 | Line 304 | void sheepshaver_cpu::interrupt(uint32 e
304          ctr()= saved_ctr;
305          gpr(1) = saved_sp;
306   #endif
307 +
308 + #if EMUL_TIME_STATS
309 +        interrupt_time += (clock() - interrupt_start);
310 + #endif
311   }
312  
313   // Execute 68k routine
314   void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
315   {
316 + #if EMUL_TIME_STATS
317 +        exec68k_count++;
318 +        const clock_t exec68k_start = clock();
319 + #endif
320 +
321   #if SAFE_EXEC_68K
322          if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
323                  printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
# Line 401 | Line 400 | void sheepshaver_cpu::execute_68k(uint32
400          lr() = saved_lr;
401          ctr()= saved_ctr;
402          set_cr(saved_cr);
403 +
404 + #if EMUL_TIME_STATS
405 +        exec68k_time += (clock() - exec68k_start);
406 + #endif
407   }
408  
409   // Call MacOS PPC code
410   uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
411   {
412 + #if EMUL_TIME_STATS
413 +        macos_exec_count++;
414 +        const clock_t macos_exec_start = clock();
415 + #endif
416 +
417          // Save program counters and branch registers
418          uint32 saved_pc = pc();
419          uint32 saved_lr = lr();
# Line 444 | Line 452 | uint32 sheepshaver_cpu::execute_macos_co
452          lr() = saved_lr;
453          ctr()= saved_ctr;
454  
455 + #if EMUL_TIME_STATS
456 +        macos_exec_time += (clock() - macos_exec_start);
457 + #endif
458 +
459          return retval;
460   }
461  
# Line 548 | Line 560 | static sigsegv_return_t sigsegv_handler(
560          if ((addr - ROM_BASE) < ROM_SIZE)
561                  return SIGSEGV_RETURN_SKIP_INSTRUCTION;
562  
563 <        // Ignore all other faults, if requested
564 <        if (PrefsFindBool("ignoresegv"))
565 <                return SIGSEGV_RETURN_FAILURE;
563 >        // Get program counter of target CPU
564 >        sheepshaver_cpu * const cpu = current_cpu;
565 >        const uint32 pc = cpu->pc();
566 >        
567 >        // Fault in Mac ROM or RAM?
568 >        bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize));
569 >        if (mac_fault) {
570 >
571 >                // "VM settings" during MacOS 8 installation
572 >                if (pc == ROM_BASE + 0x488160 && cpu->gpr(20) == 0xf8000000)
573 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
574 >        
575 >                // MacOS 8.5 installation
576 >                else if (pc == ROM_BASE + 0x488140 && cpu->gpr(16) == 0xf8000000)
577 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
578 >        
579 >                // MacOS 8 serial drivers on startup
580 >                else if (pc == ROM_BASE + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000))
581 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
582 >        
583 >                // MacOS 8.1 serial drivers on startup
584 >                else if (pc == ROM_BASE + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
585 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
586 >                else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
587 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
588 >
589 >                // Ignore all other faults, if requested
590 >                if (PrefsFindBool("ignoresegv"))
591 >                        return SIGSEGV_RETURN_SKIP_INSTRUCTION;
592 >        }
593   #else
594   #error "FIXME: You don't have the capability to skip instruction within signal handlers"
595   #endif
# Line 587 | Line 626 | void init_emul_ppc(void)
626          mon_add_command("regs", dump_registers, "regs                     Dump PowerPC registers\n");
627          mon_add_command("log", dump_log, "log                      Dump PowerPC emulation log\n");
628   #endif
629 +
630 + #if EMUL_TIME_STATS
631 +        emul_start_time = clock();
632 + #endif
633 + }
634 +
635 + /*
636 + *  Deinitialize emulation
637 + */
638 +
639 + void exit_emul_ppc(void)
640 + {
641 + #if EMUL_TIME_STATS
642 +        clock_t emul_end_time = clock();
643 +
644 +        printf("### Statistics for SheepShaver emulation parts\n");
645 +        const clock_t emul_time = emul_end_time - emul_start_time;
646 +        printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC));
647 +        printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count,
648 +                   (double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time));
649 +
650 + #define PRINT_STATS(LABEL, VAR_PREFIX) do {                                                             \
651 +                printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count);             \
652 +                printf("Total " LABEL " time  : %.1f sec (%.1f%%)\n",                   \
653 +                           double(VAR_PREFIX##_time) / double(CLOCKS_PER_SEC),          \
654 +                           100.0 * double(VAR_PREFIX##_time) / double(emul_time));      \
655 +        } while (0)
656 +
657 +        PRINT_STATS("Execute68k[Trap] execution", exec68k);
658 +        PRINT_STATS("NativeOp execution", native_exec);
659 +        PRINT_STATS("MacOS routine execution", macos_exec);
660 +
661 + #undef PRINT_STATS
662 +        printf("\n");
663 + #endif
664 +
665 +        delete main_cpu;
666 + #if MULTICORE_CPU
667 +        delete interrupt_cpu;
668 + #endif
669   }
670  
671   /*
# Line 596 | Line 675 | void init_emul_ppc(void)
675   void emul_ppc(uint32 entry)
676   {
677          current_cpu = main_cpu;
678 + #if DEBUG
679          current_cpu->start_log();
680 <        current_cpu->execute(entry);
680 > #endif
681 >        // start emulation loop and enable code translation or caching
682 >        current_cpu->execute(entry, true);
683   }
684  
685   /*
686   *  Handle PowerPC interrupt
687   */
688  
689 < // Atomic operations
690 < extern int atomic_add(int *var, int v);
691 < extern int atomic_and(int *var, int v);
692 < extern int atomic_or(int *var, int v);
693 <
694 < #if !ASYNC_IRQ
689 > #if ASYNC_IRQ
690 > void HandleInterrupt(void)
691 > {
692 >        main_cpu->handle_interrupt();
693 > }
694 > #else
695   void TriggerInterrupt(void)
696   {
697   #if 0
698    WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
699   #else
700 <  SPCFLAGS_SET( SPCFLAG_INT );
700 >  // Trigger interrupt to main cpu only
701 >  if (main_cpu)
702 >          main_cpu->trigger_interrupt();
703   #endif
704   }
705   #endif
706  
707 < void HandleInterrupt(void)
707 > void sheepshaver_cpu::handle_interrupt(void)
708   {
709          // Do nothing if interrupts are disabled
710 <        if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
710 >        if (*(int32 *)XLM_IRQ_NEST > 0)
711                  return;
712  
713          // Do nothing if there is no interrupt pending
# Line 639 | Line 723 | void HandleInterrupt(void)
723                  // 68k emulator active, trigger 68k interrupt level 1
724                  assert(current_cpu == main_cpu);
725                  WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
726 <                main_cpu->set_cr(main_cpu->get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
726 >                set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
727                  break;
728      
729   #if INTERRUPTS_IN_NATIVE_MODE
730          case MODE_NATIVE:
731                  // 68k emulator inactive, in nanokernel?
732                  assert(current_cpu == main_cpu);
733 <                if (main_cpu->gpr(1) != KernelDataAddr) {
733 >                if (gpr(1) != KernelDataAddr) {
734                          // Prepare for 68k interrupt level 1
735                          WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
736                          WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
# Line 747 | Line 831 | static void r_get_resource(void);
831  
832   static void NativeOp(int selector)
833   {
834 + #if EMUL_TIME_STATS
835 +        native_exec_count++;
836 +        const clock_t native_exec_start = clock();
837 + #endif
838 +
839          switch (selector) {
840          case NATIVE_PATCH_NAME_REGISTRY:
841                  DoPatchNameRegistry();
# Line 761 | Line 850 | static void NativeOp(int selector)
850                  GPR(3) = (int32)(int16)VideoDoDriverIO((void *)GPR(3), (void *)GPR(4),
851                                                                                             (void *)GPR(5), GPR(6), GPR(7));
852                  break;
853 <        case NATIVE_GET_RESOURCE:
854 <                get_resource();
853 > #ifdef WORDS_BIGENDIAN
854 >        case NATIVE_ETHER_IRQ:
855 >                EtherIRQ();
856                  break;
857 <        case NATIVE_GET_1_RESOURCE:
858 <                get_1_resource();
857 >        case NATIVE_ETHER_INIT:
858 >                GPR(3) = InitStreamModule((void *)GPR(3));
859                  break;
860 <        case NATIVE_GET_IND_RESOURCE:
861 <                get_ind_resource();
860 >        case NATIVE_ETHER_TERM:
861 >                TerminateStreamModule();
862                  break;
863 <        case NATIVE_GET_1_IND_RESOURCE:
864 <                get_1_ind_resource();
863 >        case NATIVE_ETHER_OPEN:
864 >                GPR(3) = ether_open((queue_t *)GPR(3), (void *)GPR(4), GPR(5), GPR(6), (void*)GPR(7));
865 >                break;
866 >        case NATIVE_ETHER_CLOSE:
867 >                GPR(3) = ether_close((queue_t *)GPR(3), GPR(4), (void *)GPR(5));
868 >                break;
869 >        case NATIVE_ETHER_WPUT:
870 >                GPR(3) = ether_wput((queue_t *)GPR(3), (mblk_t *)GPR(4));
871                  break;
872 <        case NATIVE_R_GET_RESOURCE:
873 <                r_get_resource();
872 >        case NATIVE_ETHER_RSRV:
873 >                GPR(3) = ether_rsrv((queue_t *)GPR(3));
874                  break;
875 + #else
876 +        case NATIVE_ETHER_INIT:
877 +                // FIXME: needs more complicated thunks
878 +                GPR(3) = false;
879 +                break;
880 + #endif
881          case NATIVE_SERIAL_NOTHING:
882          case NATIVE_SERIAL_OPEN:
883          case NATIVE_SERIAL_PRIME_IN:
# Line 796 | Line 898 | static void NativeOp(int selector)
898                  GPR(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](GPR(3), GPR(4));
899                  break;
900          }
901 +        case NATIVE_GET_RESOURCE:
902 +        case NATIVE_GET_1_RESOURCE:
903 +        case NATIVE_GET_IND_RESOURCE:
904 +        case NATIVE_GET_1_IND_RESOURCE:
905 +        case NATIVE_R_GET_RESOURCE: {
906 +                typedef void (*GetResourceCallback)(void);
907 +                static const GetResourceCallback get_resource_callbacks[] = {
908 +                        get_resource,
909 +                        get_1_resource,
910 +                        get_ind_resource,
911 +                        get_1_ind_resource,
912 +                        r_get_resource
913 +                };
914 +                get_resource_callbacks[selector - NATIVE_GET_RESOURCE]();
915 +                break;
916 +        }
917          case NATIVE_DISABLE_INTERRUPT:
918                  DisableInterrupt();
919                  break;
# Line 810 | Line 928 | static void NativeOp(int selector)
928                  QuitEmulator();
929                  break;
930          }
931 +
932 + #if EMUL_TIME_STATS
933 +        native_exec_time += (clock() - native_exec_start);
934 + #endif
935   }
936  
937   /*
# Line 902 | Line 1024 | uint32 call_macos7(uint32 tvect, uint32
1024   }
1025  
1026   /*
905 *  Atomic operations
906 */
907
908 int atomic_add(int *var, int v)
909 {
910        int ret = *var;
911        *var += v;
912        return ret;
913 }
914
915 int atomic_and(int *var, int v)
916 {
917        int ret = *var;
918        *var &= v;
919        return ret;
920 }
921
922 int atomic_or(int *var, int v)
923 {
924        int ret = *var;
925        *var |= v;
926        return ret;
927 }
928
929 /*
1027   *  Resource Manager thunks
1028   */
1029  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines