rem: uae_u32 usp = blomcall_ctx->rts_a7 ; int i;
context: unsigned long REGPARAM2 blomcall_ops (uae_u32 opcode, struct regstruct* regs) {  static unsigned long remaining_cycles = 0;  unsigned long cycles;  uae_u64 start_time;  uae_u64 call_time;  uae_u8* ix86addr;  cycles = limited_cycles(remaining_cycles);//  printf("entry cycles: %ld/%ld\n", cycles, remaining_cycles);  if (cycles != 0) {    remaining_cycles -= cycles;    return cycles;  }  // Sanity check  if (!blomcall_enable) {    return op_illg (opcode, regs);  }  start_time = read_processor_time ();    if (opcode == OP_BRESUME) {    blomcall_ctx = (void*) (uintptr_t) m68k_getpc(regs);    assert (blomcall_ctx->magic == BRESUME_MAGIC &&	    blomcall_ctx->saved_stack_bytes <= sizeof (blomcall_ctx->saved_stack));    /*     printf("BRESUME: stack=%08x context=%p\n", *//* 	   m68k_areg (regs, 7), blomcall_ctx); */  }  else {    uae_u32 bcctx;/*     printf("sp at bjmp: %08x\n", m68k_areg(regs, 7)); */    // TODO: Cache and reuse used contexts    blomcall_ctx = malloc (sizeof (struct blomcall_context));    blomcall_ctx->op_resume         = OP_BRESUME;    blomcall_ctx->saved_stack_bytes = 0;    blomcall_ctx->magic             = BRESUME_MAGIC;    blomcall_ctx->rts_pc            = get_long(m68k_areg(regs, 7));    blomcall_ctx->rts_a7            = m68k_areg(regs, 7) + 4;    blomcall_ctx->regs              = regs;    m68k_areg(regs, 7) = blomcall_ctx->rts_a7;    // Make sure the emulation can access this address    assert ((((uae_u64) (uintptr_t) blomcall_ctx) & 0xffffffff00000000ULL) == 0);    bcctx = ((uae_u32) (uintptr_t) blomcall_ctx) & 0xffff0000;    put_mem_bank (bcctx, &directmem_bank, 0);  }  uae_u32 usp = blomcall_ctx->rts_a7 ;  int i;/*   printf("Dumping rts_a7: %08lx\n", usp); *//*   for (i = -4096; i < 0; i += 32) { *//*     printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	   get_long(usp+i+0), get_long(usp+i+4), get_long(usp+i+8), get_long(usp+i+12), *//* 	   get_long(usp+i+16), get_long(usp+i+20), get_long(usp+i+24), get_long(usp+i+28)); *//*   } *//*   printf("*%08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	 get_long(usp+0), get_long(usp+4), get_long(usp+8), get_long(usp+12), *//* 	 get_long(usp+16), get_long(usp+20), get_long(usp+24), get_long(usp+28)); *//*   for (i = 32; i < 128; i += 32) { *//*     printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	   get_long(usp+i+0), get_long(usp+i+4), get_long(usp+i+8), get_long(usp+i+12), *//* 	   get_long(usp+i+16), get_long(usp+i+20), get_long(usp+i+24), get_long(usp+i+28)); *//*   } */    switch (sigsetjmp(blomcall_ctx->emuljmp, 0)) {    case 0: {      // m68k code executed blomcall trap      if (opcode == OP_BRESUME) {	if (blomcall_ctx->saved_stack_bytes == 0) {	  // Go back after timer break	  pthread_kill(pthread_self(), SIGUSR2);	}	else {	  // Restore stack frame contents and go back after m68k call	  uae_u8* sp = (uae_u8*) get_jmpbuf_sp(&blomcall_ctx->m68kjmp) - RED_ZONE_SIZE;	  memcpy(sp, blomcall_ctx->saved_stack, blomcall_ctx->saved_stack_bytes);	  siglongjmp(blomcall_ctx->m68kjmp, 1);	}      }      else {	void* newpc = (void*) (uintptr_t) get_long(m68k_getpc(blomcall_ctx->regs) + 2);	void* retpc = (opcode == OP_BJMP ?		       (void*) blomcall_exit :		       (void*) blomcall_exitnr);//	newpc = blomcall_test;		assert ((((uae_u64) (uintptr_t) retpc) & 0xffffffff00000000ULL) == 0);	/* 	printf("blomcall from %08lx to %08lx, then via %p back to %08lx\n", *//* 	       m68k_getpc(blomcall_ctx->regs), newpc, *//* 	       retpc, blomcall_ctx->rts_pc); *//* 	m68k_setpc(blomcall_ctx->regs, (uae_u32) (uintptr_t) blomcall_ctx); *//* 	fill_prefetch_slow(blomcall_ctx->regs); *//* 	printf("newpc dump: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x\n", *//* 	       get_byte(newpc+0),get_byte(newpc+1),get_byte(newpc+2),get_byte(newpc+3), *//* 	       get_byte(newpc+4),get_byte(newpc+5),get_byte(newpc+6),get_byte(newpc+7)); *//* 	printf("native stack is ~%p\n", &ix86addr); */		// Don't do this until we have reloaded the stack pointer:	// pthread_sigmask(SIG_UNBLOCK, &blomcall_usr1sigset, NULL);	// Also note that the only memory constraint allowed is the stack	// argument; after the new stack pointer is set, memory arguments will	// most likely be wrong!#if defined (__i386__)	__asm__ __volatile__ ("		\n\		mov   %0,%%esp		\n\		push  %6		\n\		push  $0		\n\		push  %1		\n\		push  %2		\n\		call  pthread_sigmask	\n\		addl  $12,%%esp		\n\		mov   %3,%%eax		\n\		mov   %4,%%edx		\n\		jmp   *%5"			      : :				"m" /* 0 */ (m68k_areg(blomcall_ctx->regs, 7)),				"i" /* 1 */ (&blomcall_usr1sigset),				"i" /* 2 */ (SIG_UNBLOCK),				"r" /* 3 */ (blomcall_ctx->regs->regs),				"r" /* 4 */ (blomcall_ctx->regs->fp),				"r" /* 5 */ (newpc),				"r" /* 6 */ (retpc) :				"memory", "eax", "ecx", "edx");#elif defined (__x86_64__)	__asm__ __volatile__ ("		\n\#		mov   %%rsp,%%rax	\n\		mov   %0,%%esp		\n\#		mov   %%rax,%%rsp	\n\#		jmp   *%6		\n\		push  %6		\n\#		xor   %%edx,%%edx	\n\#		mov   %1,%%esi		\n\#		mov   %2,%%edi		\n\#		call  pthread_sigmask	\n\		mov   %3,%%rdi		\n\		mov   %4,%%rsi		\n\		jmp   *%5"			      : :				"m" /* 0 */ (m68k_areg(blomcall_ctx->regs, 7)),				"i" /* 1 */ (&blomcall_usr1sigset),				"i" /* 2 */ (SIG_UNBLOCK),				"r" /* 3 */ (blomcall_ctx->regs->regs),				"r" /* 4 */ (blomcall_ctx->regs->fp),				"r" /* 5 */ (newpc),				"r" /* 6 */ (retpc) :				"memory", "rax", "rcx", "rdx", "rdi", "rsi",				"r8", "r9", "r10", "r11");#else# error Unsupported architecture!#endif      }            // Never reached      abort();    }    case 1: {      // Native code returned (via blomcall_exit()/blomcall_exitnr())/*       printf("blomcall returned\n"); *//*       printf("native stack is ~%p\n", &ix86addr); */      /*       printf("restored pc: %08x, a7: %08x\n", *//* 	     blomcall_ctx->rts_pc, blomcall_ctx->rts_a7); */      put_long(m68k_areg(regs, 7) - 4, blomcall_ctx->rts_pc);      m68k_areg(blomcall_ctx->regs, 7) = blomcall_ctx->rts_a7;      m68k_setpc (blomcall_ctx->regs, blomcall_ctx->rts_pc);      fill_prefetch_slow(blomcall_ctx->regs);            free(blomcall_ctx);      break;    }    case 2: {      // Native code interrupted by timer/*       printf("blomcall interrupted\n"); */      assert ((((uae_u64) get_sigctx_sp(blomcall_ctx))	       & 0xffffffff00000000ULL) == 0);/*       printf("sc.sp=%p\n", get_sigctx_sp(blomcall_ctx)); */      m68k_areg(blomcall_ctx->regs, 7) =	(uae_u32) get_sigctx_sp(blomcall_ctx) - RED_ZONE_SIZE;      blomcall_ctx->saved_stack_bytes = 0;      break;    }    case 3: {      // Native code called blomcall_callfunc68k()            uae_u8* a7 = (uae_u8*) (uintptr_t) m68k_areg(blomcall_ctx->regs, 7);      uae_u8* sp = (uae_u8*) get_jmpbuf_sp(&blomcall_ctx->m68kjmp) - RED_ZONE_SIZE;/*       printf("blomcall calls m68k function\n"); */      // a7 has been set up by the assembly code and      // __blomcall_callfunc68k() so it's the same as the native stack      // pointer at the time just before blomcall_callfunc68k() was      // called.      //      // sp (which is below a7) is native stack pointer inside      // sigsetjmp(m68kjmp). Since we were running on the m68k stack,      // it's always in the 32-bit address space.      //      // The m68k PC is already setup.      //      // What we need to do now is to push the address of blomcall_ctx      // (which begins with a BRESUME opcode) so that when the m68k      // executes an 'rts', it finds an BRESUME instruction and      // siglongjmps us back to __blomcall_callfunc68k().      //      // However, first we must save the stack frame between sp and a7      // so we can safely return back to __blomcall_callfunc68k. It's      // quite likely that the m68k code will destroy this area      // otherwise! At least we will, when pusing the address to      // BRESUME.      assert ((size_t) (a7 - sp) <= sizeof (blomcall_ctx->saved_stack));      assert ((((uae_u64) (uintptr_t) blomcall_ctx) & 0xffffffff00000000ULL) == 0);      memcpy(blomcall_ctx->saved_stack, sp, (a7 - sp));      blomcall_ctx->saved_stack_bytes = (size_t) (a7 - sp);      m68k_areg(blomcall_ctx->regs, 7) -= 4;      put_long(m68k_areg(blomcall_ctx->regs, 7), (uae_u32) (uintptr_t) blomcall_ctx);      break;    }      }  // BJMP/BRESUME not active at this point  blomcall_ctx = NULL;/*   printf("going back; sp is now %08lx\n", m68k_areg(regs, 7)); *//*   printf("Dumping rts_a7: %08lx\n", usp); *//*   for (i = -4096; i < 0; i += 32) { *//*     printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	   get_long(usp+i+0), get_long(usp+i+4), get_long(usp+i+8), get_long(usp+i+12), *//* 	   get_long(usp+i+16), get_long(usp+i+20), get_long(usp+i+24), get_long(usp+i+28)); *//*   } *//*   printf("*%08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	 get_long(usp+0), get_long(usp+4), get_long(usp+8), get_long(usp+12), *//* 	 get_long(usp+16), get_long(usp+20), get_long(usp+24), get_long(usp+28)); *//*   for (i = 32; i < 128; i += 32) { *//*     printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", *//* 	   get_long(usp+i+0), get_long(usp+i+4), get_long(usp+i+8), get_long(usp+i+12), *//* 	   get_long(usp+i+16), get_long(usp+i+20), get_long(usp+i+24), get_long(usp+i+28)); *//*   } */    call_time = read_processor_time () - start_time;/*   printf("call_time: %lld, syncbase: %ld\n", call_time, syncbase); */  blomcall_cycles += (unsigned long) ((double) call_time / syncbase * 7.09e6 * 0.5);/*   printf("%10.3g; ",  (double) call_time * 16 / 2e9 * 7.14e6 * 256); */  remaining_cycles = (unsigned long) ((double) call_time / syncbase * 7.09e6 * 0.5);  remaining_cycles *= 3;  cycles = limited_cycles(remaining_cycles);/*   printf("exit cycles: %ld/%ld\n", cycles, remaining_cycles); */  remaining_cycles -= cycles;  return cycles;}