--- SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2004/11/22 22:04:38 1.53 +++ SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2005/06/30 07:34:17 1.62 @@ -1,7 +1,7 @@ /* * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface * - * SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig + * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -93,9 +93,6 @@ extern "C" void check_load_invoc(uint32 // PowerPC EmulOp to exit from emulation looop const uint32 POWERPC_EXEC_RETURN = POWERPC_EMUL_OP | 1; -// Enable interrupt routine safety checks? -#define SAFE_INTERRUPT_PPC 1 - // Enable Execute68k() safety checks? #define SAFE_EXEC_68K 1 @@ -142,21 +139,6 @@ class sheepshaver_cpu void init_decoder(); void execute_sheep(uint32 opcode); - // CPU context to preserve on interrupt - class interrupt_context { - uint32 gpr[32]; - uint32 pc; - uint32 lr; - uint32 ctr; - uint32 cr; - uint32 xer; - sheepshaver_cpu *cpu; - const char *where; - public: - interrupt_context(sheepshaver_cpu *_cpu, const char *_where); - ~interrupt_context(); - }; - public: // Constructor @@ -192,42 +174,51 @@ public: // Handle MacOS interrupt void interrupt(uint32 entry); - void handle_interrupt(); // Make sure the SIGSEGV handler can access CPU registers friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); -}; -// Memory allocator returning areas aligned on 16-byte boundaries -void *operator new(size_t size) -{ - void *p; + // Memory allocator returning areas aligned on 16-byte boundaries + void *operator new(size_t size); + void operator delete(void *p); +}; -#if defined(HAVE_POSIX_MEMALIGN) - if (posix_memalign(&p, 16, size) != 0) +// Memory allocator returning sheepshaver_cpu objects aligned on 16-byte boundaries +// FORMAT: [ alignment ] magic identifier, offset to malloc'ed data, sheepshaver_cpu data +void *sheepshaver_cpu::operator new(size_t size) +{ + const int ALIGN = 16; + + // Allocate enough space for sheepshaver_cpu data + signature + align pad + uint8 *ptr = (uint8 *)malloc(size + ALIGN * 2); + if (ptr == NULL) throw std::bad_alloc(); -#elif defined(HAVE_MEMALIGN) - p = memalign(16, size); -#elif defined(HAVE_VALLOC) - p = valloc(size); // page-aligned! -#else - /* XXX: handle padding ourselves */ - p = malloc(size); -#endif - return p; + // Align memory + int ofs = 0; + while ((((uintptr)ptr) % ALIGN) != 0) + ofs++, ptr++; + + // Insert signature and offset + struct aligned_block_t { + uint32 pad[(ALIGN - 8) / 4]; + uint32 signature; + uint32 offset; + uint8 data[sizeof(sheepshaver_cpu)]; + }; + aligned_block_t *blk = (aligned_block_t *)ptr; + blk->signature = FOURCC('S','C','P','U'); + blk->offset = ofs + (&blk->data[0] - (uint8 *)blk); + assert((((uintptr)&blk->data) % ALIGN) == 0); + return &blk->data[0]; } -void operator delete(void *p) -{ -#if defined(HAVE_MEMALIGN) || defined(HAVE_VALLOC) -#if defined(__GLIBC__) - // this is known to work only with GNU libc - free(p); -#endif -#else - free(p); -#endif +void sheepshaver_cpu::operator delete(void *p) +{ + uint32 *blk = (uint32 *)p; + assert(blk[-2] == FOURCC('S','C','P','U')); + void *ptr = (void *)(((uintptr)p) - blk[-1]); + free(ptr); } sheepshaver_cpu::sheepshaver_cpu() @@ -278,7 +269,7 @@ void sheepshaver_cpu::execute_emul_op(ui for (int i = 0; i < 7; i++) r68.a[i] = gpr(16 + i); r68.a[7] = gpr(1); - uint32 saved_cr = get_cr() & CR_field<2>::mask(); + uint32 saved_cr = get_cr() & 0xff9fffff; // mask_operand::compute(11, 8) uint32 saved_xer = get_xer(); EmulOp(&r68, gpr(24), emul_op); set_cr(saved_cr); @@ -473,46 +464,6 @@ int sheepshaver_cpu::compile1(codegen_co } #endif -// CPU context to preserve on interrupt -sheepshaver_cpu::interrupt_context::interrupt_context(sheepshaver_cpu *_cpu, const char *_where) -{ -#if SAFE_INTERRUPT_PPC >= 2 - cpu = _cpu; - where = _where; - - // Save interrupt context - memcpy(&gpr[0], &cpu->gpr(0), sizeof(gpr)); - pc = cpu->pc(); - lr = cpu->lr(); - ctr = cpu->ctr(); - cr = cpu->get_cr(); - xer = cpu->get_xer(); -#endif -} - -sheepshaver_cpu::interrupt_context::~interrupt_context() -{ -#if SAFE_INTERRUPT_PPC >= 2 - // Check whether CPU context was preserved by interrupt - if (memcmp(&gpr[0], &cpu->gpr(0), sizeof(gpr)) != 0) { - printf("FATAL: %s: interrupt clobbers registers\n", where); - for (int i = 0; i < 32; i++) - if (gpr[i] != cpu->gpr(i)) - printf(" r%d: %08x -> %08x\n", i, gpr[i], cpu->gpr(i)); - } - if (pc != cpu->pc()) - printf("FATAL: %s: interrupt clobbers PC\n", where); - if (lr != cpu->lr()) - printf("FATAL: %s: interrupt clobbers LR\n", where); - if (ctr != cpu->ctr()) - printf("FATAL: %s: interrupt clobbers CTR\n", where); - if (cr != cpu->get_cr()) - printf("FATAL: %s: interrupt clobbers CR\n", where); - if (xer != cpu->get_xer()) - printf("FATAL: %s: interrupt clobbers XER\n", where); -#endif -} - // Handle MacOS interrupt void sheepshaver_cpu::interrupt(uint32 entry) { @@ -521,13 +472,6 @@ void sheepshaver_cpu::interrupt(uint32 e const clock_t interrupt_start = clock(); #endif -#if SAFE_INTERRUPT_PPC - static int depth = 0; - if (depth != 0) - printf("FATAL: sheepshaver_cpu::interrupt() called more than once: %d\n", depth); - depth++; -#endif - // Save program counters and branch registers uint32 saved_pc = pc(); uint32 saved_lr = lr(); @@ -581,10 +525,6 @@ void sheepshaver_cpu::interrupt(uint32 e #if EMUL_TIME_STATS interrupt_time += (clock() - interrupt_start); #endif - -#if SAFE_INTERRUPT_PPC - depth--; -#endif } // Execute 68k routine @@ -862,9 +802,9 @@ sigsegv_return_t sigsegv_handler(sigsegv #error "FIXME: You don't have the capability to skip instruction within signal handlers" #endif - printf("SIGSEGV\n"); - printf(" pc %p\n", fault_instruction); - printf(" ea %p\n", fault_address); + fprintf(stderr, "SIGSEGV\n"); + fprintf(stderr, " pc %p\n", fault_instruction); + fprintf(stderr, " ea %p\n", fault_address); dump_registers(); ppc_cpu->dump_log(); enter_mon(); @@ -984,7 +924,7 @@ void TriggerInterrupt(void) #endif } -void sheepshaver_cpu::handle_interrupt(void) +void HandleInterrupt(powerpc_registers *r) { #ifdef USE_SDL_VIDEO // We must fill in the events queue in the same thread that did call SDL_SetVideoMode() @@ -995,6 +935,10 @@ void sheepshaver_cpu::handle_interrupt(v if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0) return; + // Do nothing if there is no pending interrupt + if (InterruptFlags == 0) + return; + // Current interrupt nest level static int interrupt_depth = 0; ++interrupt_depth; @@ -1002,22 +946,18 @@ void sheepshaver_cpu::handle_interrupt(v interrupt_count++; #endif - // Disable MacOS stack sniffer - WriteMacInt32(0x110, 0); - // Interrupt action depends on current run mode switch (ReadMacInt32(XLM_RUN_MODE)) { case MODE_68K: // 68k emulator active, trigger 68k interrupt level 1 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); - set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2])); + r->cr.set(r->cr.get() | tswap32(kernel_data->v[0x674 >> 2])); break; #if INTERRUPTS_IN_NATIVE_MODE case MODE_NATIVE: // 68k emulator inactive, in nanokernel? - if (gpr(1) != KernelDataAddr && interrupt_depth == 1) { - interrupt_context ctx(this, "PowerPC mode"); + if (r->gpr[1] != KernelDataAddr && interrupt_depth == 1) { // Prepare for 68k interrupt level 1 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); @@ -1039,7 +979,6 @@ void sheepshaver_cpu::handle_interrupt(v case MODE_EMUL_OP: // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { - interrupt_context ctx(this, "68k mode"); #if EMUL_TIME_STATS const clock_t interrupt_start = clock(); #endif @@ -1108,7 +1047,6 @@ void sheepshaver_cpu::execute_native_op( case NATIVE_VIDEO_DO_DRIVER_IO: gpr(3) = (int32)(int16)VideoDoDriverIO(gpr(3), gpr(4), gpr(5), gpr(6), gpr(7)); break; -#ifdef WORDS_BIGENDIAN case NATIVE_ETHER_IRQ: EtherIRQ(); break; @@ -1130,12 +1068,6 @@ void sheepshaver_cpu::execute_native_op( case NATIVE_ETHER_RSRV: gpr(3) = ether_rsrv((queue_t *)gpr(3)); break; -#else - case NATIVE_ETHER_INIT: - // FIXME: needs more complicated thunks - gpr(3) = false; - break; -#endif case NATIVE_SYNC_HOOK: gpr(3) = NQD_sync_hook(gpr(3)); break;