⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 star.c

📁 著名ARC模拟器源码,包括多个平台
💻 C
📖 第 1 页 / 共 5 页
字号:
	** If s680x0exec() is already running, then the interrupts are about	** to get flushed anyway.  So ignore this call.	*/	emit("test byte[__execinfo],1\n");	emit("jnz .noflush\n");	/* Make registers "live" */	emit("pushad\n");	emit("mov esi,[__pc]\n");	emit("xor ebp,ebp\n");	cache_ccr();	emit("xor edi,edi\n"); /* well, semi-live */	emit("call flush_interrupts\n");	emit("sub [__odometer],edi\n"); /* edi will be <= 0 here */	emit("mov [__pc],esi\n"); /* PC guaranteed unbased */	writeback_ccr();	emit("popad\n");	emit(".noflush:\n");	emit("ret\n");/***************************************************************************//***  s680x0GetContextSize()****  Entry: Nothing**  Exit:  Size of context array (in bytes)*/	begin_source_proc("GetContextSize");	emit("mov eax,contextend-contextbegin\n");	emit("ret\n");/***************************************************************************//***  s680x0GetContext(context)****  Entry: Address of context in EAX**  Exit:  Nothing*/	begin_source_proc("GetContext");	emit("push edx\n");	emit("push edi\n");	if(use_stack) emit("mov edi,[esp+12]\n");	else          emit("mov edi,eax\n");	emit("%%assign i 0\n");	emit("%%rep ((contextend-contextbegin) / 8)\n");	emit("  mov eax,[contextbegin+i+0]\n");	emit("  mov edx,[contextbegin+i+4]\n");	emit("  mov [edi+i+0],eax\n");	emit("  mov [edi+i+4],edx\n");	emit("%%assign i i+8\n");	emit("%%endrep\n");	emit("%%if ((contextend-contextbegin) %% 8)!=0\n");	emit("  mov eax,[contextbegin+i+0]\n");	emit("  mov [edi+i+0],eax\n");	emit("%%endif\n");	emit("pop edi\n");	emit("pop edx\n");	emit("xor eax,eax\n");	emit("ret\n");/***************************************************************************//***  s680x0SetContext(context)****  Entry: Address of context in EAX**  Exit:  Nothing*/	begin_source_proc("SetContext");	emit("push edx\n");	emit("push esi\n");	if(use_stack) emit("mov esi,[esp+12]\n");	else          emit("mov esi,eax\n");	emit("%%assign i 0\n");	emit("%%rep ((contextend-contextbegin) / 8)\n");	emit("  mov eax,[esi+i+0]\n");	emit("  mov edx,[esi+i+4]\n");	emit("  mov [contextbegin+i+0],eax\n");	emit("  mov [contextbegin+i+4],edx\n");	emit("%%assign i i+8\n");	emit("%%endrep\n");	emit("%%if ((contextend-contextbegin) %% 8)!=0\n");	emit("  mov eax,[esi+i+0]\n");	emit("  mov [contextbegin+i+0],eax\n");	emit("%%endif\n");	emit("pop esi\n");	emit("pop edx\n");	emit("xor eax,eax\n");	emit("ret\n");/***************************************************************************//***  s680x0fetch(address)****  (Will need to be rewritten to handle function codes)****  Reads a word from memory using the _supervisor_ fetch map.**  Entry: Address in EAX**  Exit:  The fetched word (or -1 if the address was invalid)*/	begin_source_proc("fetch");	if(use_stack) emit("mov eax,[esp+4]\n");	emit("push ebx\n");	emit("push esi\n");	emit("push edi\n");/* can be destroyed by rebase */	emit("push ebp\n");	emit("push dword[__fetch]\n");	emit("mov ebx,[__s_fetch]\n");	emit("mov [__fetch],ebx\n");	/* Must save the fetch region cache as well */	emit("push dword[__fetch_region_start]\n");	emit("push dword[__fetch_region_end]\n");	/* and __execinfo */	emit("mov bl,[__execinfo]\n");	emit("push ebx\n");	emit("xor ebp,ebp\n");	emit("mov esi,eax\n");	emit("and byte[__execinfo],0FDh\n");	/* Force re-base */	emit("call basefunction\n");	emit("test byte[__execinfo],2\n");	emit("mov eax,-1\n");	emit("jnz short .badfetch\n");	emit("add esi,ebp\n");	emit("inc eax\n"); /* make eax zero */	emit("mov ax,[esi]\n");	emit(".badfetch:\n");	emit("pop ebx\n");	emit("mov [__execinfo],bl\n");	emit("pop dword[__fetch_region_end]\n");	emit("pop dword[__fetch_region_start]\n");	emit("pop dword[__fetch]\n");	emit("pop ebp\n");	emit("pop edi\n");	emit("pop esi\n");	emit("pop ebx\n");	emit("ret\n");/***************************************************************************//***  s680x0readOdometer()****  Reads the odometer (works from anywhere)**  Entry: Nothing**  Exit:  Odometer in EAX*/	begin_source_proc("readOdometer");	emit("mov eax,[__cycles_needed]\n");	emit("sub eax,[__io_cycle_counter]\n");	emit("dec eax\n");               /* eax = elapsed cycles */	emit("sub eax,[__cycles_leftover]\n");	emit("add eax,[__odometer]\n");  /* add to old __odometer */	emit("ret\n");/***************************************************************************//***  s680x0tripOdometer()****  Reads and then clears the odometer (works from anywhere)**  Entry: Nothing**  Exit:  Old odometer value in EAX*/	begin_source_proc("tripOdometer");	/* Read */	emit("mov eax,[__cycles_needed]\n");	emit("sub eax,[__io_cycle_counter]\n");	emit("dec eax\n");               /* eax = elapsed cycles */	emit("sub eax,[__cycles_leftover]\n");	emit("add [__odometer],eax\n");  /* add to old __odometer */	/* Clear */	emit("mov eax,[__io_cycle_counter]\n");	emit("inc eax\n");	emit("mov [__cycles_needed],eax\n");	emit("mov eax,[__odometer]\n");	emit("mov dword[__odometer],0\n");	emit("ret\n");/***************************************************************************//***  s680x0controlOdometer(n)****  Reads the odometer, clears it only if n != 0**  Entry: n in EAX**  Exit:  Old odometer value in EAX*/	begin_source_proc("controlOdometer");	if(use_stack) emit("mov eax,[esp+4]\n");	emit("or eax,eax\n");	emit("jnz short _%stripOdometer\n", sourcename);	emit("jmp short _%sreadOdometer\n", sourcename);/***************************************************************************//***  s680x0releaseTimeslice()****  Ends the s680x0exec call prematurely.  The early exit is reflected in**  __odometer.**  Entry: Nothing**  Exit:  Nothing*/	begin_source_proc("releaseTimeslice");	emit("mov eax,[__cycles_needed]\n");	emit("sub [__io_cycle_counter],eax\n");	emit("xor eax,eax\n");	emit("mov [__cycles_needed],eax\n");	emit("ret\n");/***************************************************************************//***  s680x0readPC()****  Returns the current program counter.  Works anywhere, including I/O,**  RESET, and BKPT handlers.****  Note that the value returned won't necessarily coincide exactly with the**  beginning of an instruction.*/	begin_source_proc("readPC");	emit("test byte[__execinfo],1\n");	emit("jnz short .live\n");	emit("mov eax,[__pc]\n");	emit("ret\n");	emit(".live:\n");	emit("mov eax,[__io_fetchbased_pc]\n");	emit("sub eax,[__io_fetchbase]\n");	emit("ret\n");}/***************************************************************************//*** Routine that flushes pending interrupts (with correct priority).** Assumes "live" registers, including EDI and EBP.**** Does not rebase the PC.  In fact, it will un-base the PC even if there** aren't any pending interrupts.**** s680x0flushInterrupts() is actually a wrapper for this.*/static void gen_flush_interrupts(void) {	int cycles = (cputype == 68010) ? 46 : 44;	align(16);	emit("flush_interrupts:\n");	/* Unbase PC */	emit("sub esi,ebp\n");	emit("xor ebp,ebp\n");	/* This loop is intentionally post-tested because interrupt level 7	** is non-maskable. */	emit("mov edx,7\n");	emit("mov cl,80h\n");	emit("mov ch,[__sr+1]\n"); /* current PPL */	emit("and ch,7\n");	emit(".loop:\n");	emit("test [__interrupts],cl\n");	emit("jz short .noint\n");	emit("mov dl,[__interrupts+edx]\n");	emit("not cl\n");	emit("and [__interrupts],cl\n");	emit("shl edx,2\n");	emit("call group_1_exception\n");	emit("sub edi,byte %d\n", cycles);	emit("jmp short .intdone\n");	emit(".noint:\n");	emit("dec edx\n");	emit("jz short .intdone\n");	emit("shr cl,1\n");	emit("cmp dl,ch\n");	emit("jg short .loop\n");	emit(".intdone:\n");	emit("ret\n");}/***************************************************************************/static void ret_timing(int n) {	if(n) {		emit("sub edi,%s%d\n", (n < 128) ? "byte " : "", n);	} else {		emit("or edi,edi\n");	}	/* If hog mode is off, jump back to the main loop */	if(!hog) {		emit("jmp execend\n");	/* If hog mode is on, fetch and execute the next instruction */	} else {		emit("js near execquit\n");		emit("mov bx,[esi]\n");		emit("add esi,byte 2\n");		emit("jmp dword[__jmptbl+ebx*4]\n");	}}/*** This version of ret_timing does a trace flag check.**** Note: this only needs to be used for instructions which can potentially**  _set_ the trace flag.  Instructions which can't set the trace flag (even**  if they can clear it) are OK to use ret_timing as usual.  Why?  Well, if**  an instruction is run in trace mode, that instruction is doomed to be**  traced, regardless if it clears the trace flag during its execution.**  Furthermore, the trace exception (being a group 1 exception after all)**  will clear the trace tricky bit as well as the trace flag.*/static void ret_timing_checkpoint(int n) {	if(n) {		emit("sub edi,%s%d\n", (n < 128) ? "byte " : "", n);	} else {		emit("or edi,edi\n");	}	emit("jmp exec_checkpoint\n");}/***************************************************************************//* This routine decodes an extension word into EDX. */static void gen_decode_ext(void) {	align(16);	emit("decode_ext:\n");	if(cputype <= 68010) {		emit("push ecx\n");		emit("movzx edx,word[esi]\n");		emit("movsx ecx,dl\n");		emit("add esi,byte 2\n");		emit("shr edx,12\n");		emit("mov edx,[__reg+edx*4]\n");		emit("jc short .long\n");		emit("movsx edx,dx\n");		emit(".long:\n");		emit("add edx,ecx\n");		emit("pop ecx\n");		emit("ret\n");	} else {		/* For future expansion... */		/* need an extra jump table here */	}}/***************************************************************************//*** Perform a cached rebase*/void perform_cached_rebase(void) {	int myline = linenum; linenum += 2;	emit("cmp esi,[__fetch_region_start]\n");	emit("jb short ln%d\n", myline);	emit("cmp esi,[__fetch_region_end]\n");	emit("jbe short ln%d\n", myline + 1);	emit("ln%d:\n", myline);	emit("call basefunction\n");	emit("ln%d:\n", myline + 1);	emit("add esi,ebp\n");}/***************************************************************************//*** This is the function that generates a base for a given 68K PC.****  Entry: 68K PC in ESI**  Exit:  Newly calculated base in EBP**** Sounds like a simple lookup into the __fetch array, and in the case of** 32-bit addresses, it is.  But for anything less, we'll need to compensate** for potential garbage in the unused address bits, by subtracting the value** of these unused bits from the base.  This way the full 32 bits of the PC** are preserved, even if they're not used.**** The only registers which need to be "live" here are ESI and EBP.  The** fetch region cache is updated, and bit 1 of __execinfo is set if the base** couldn't be calculated.*/static void gen_basefunction(void) {	align(16);	emit("basefunction:\n");	/*	** Prepare ESI by masking off unused address bits (but save it	** first).	*/	if(addressbits < 32) {		emit("push esi\n");		maskaddress("esi");	}	emit("mov ebp,[__fetch]\n");	emit(".check:\n");	emit("db 3Eh\n");	emit("cmp esi,[ebp]\n");           /* Are we smaller? */	emit("jb short .next\n");          /* Yes, go to next address */	emit("db 3Eh\n");	emit("cmp esi,[ebp+4]\n");         /* Are we bigger? */	emit("jbe short .base\n");	emit(".next:\n");	emit("db 3Eh\n");	emit("cmp dword [ebp],byte -1\n"); /* End of list? */	emit("je short .outofrange\n");	emit("add ebp,byte 12\n");         /* To the next structure */	emit("jmp short .check\n");	/* Bad news... we jumped out into the weeds. */	emit(".outofrange:\n");	if(addressbits < 32) emit("pop esi\n");	emit("xor ebp,ebp\n");	emit("mov dword[__fetch_region_start],-1\n");	emit("mov dword[__fetch_region_end],ebp\n");	force_context_switch();	emit("or byte[__execinfo],2\n");	emit("ret\n");	emit(".base:\n");	/*	** Dealing with addressbits < 32 again... if the unused PC bits are	** anything but zero, then we'll need to adjust the base to	** compensate.	*/	if(addressbits < 32) {		emit("mov esi,[esp]\n");		emit("and esi,%d\n", 0xFFFFFFFF << addressbits);	}	emit("push edx\n");	emit("mov edx,ebp\n");	/*	** Update the fetch region cache, adding in the garbage bits where	** applicable.	*/	emit("mov ebp,[edx]\n");	if(addressbits < 32) emit("or ebp,esi\n");	emit("mov [__fetch_region_start],ebp\n");	emit("mov ebp,[edx+4]\n");	if(addressbits < 32) emit("or ebp,esi\n");	emit("mov [__fetch_region_end],ebp\n");	emit("mov ebp,[edx+8]\n");	emit("pop edx\n");	if(addressbits < 32) {		/*		** Subtract garbage bits from the base, and restore the		** original 32-bit PC value.		*/		emit("sub ebp,esi\n");		emit("pop esi\n");	}	emit("ret\n");}/***************************************************************************//* Read flags from CL into our CCR.  CX is unmodified. */static void cl2ccr(void){	emit("mov al,cl\n");        /* read CCR -> AL */                 /* ???????????XNZVC */	emit("mov ah,al\n");        /* copy to AH */                     /* ???XNZVC???XNZVC */	emit("and ax,0C10h\n");     /* isolate NZ...X */                 /* 0000NZ00000X0000 */	emit("shl ah,3\n");       /* put NZ almost where we want it */   /* 0NZ00000000X0000 */	emit("shr al,4\n");         /* shift X flag into bit 0 */        /* 0NZ000000000000X */	emit("mov [__xflag],al\n"); /* store X flag */                   /* 0NZ000000000000X al -> xflag */	emit("mov al,cl\n");        /* read CCR -> AL again */           /* 0NZ00000000XNZVC */	emit("and al,3\n");         /* isolate VC */                     /* 0NZ00000000000VC */	emit("shr al,1\n");         /* just V */                         /* 0NZ000000000000V carry */	emit("adc ah,ah\n");        /* append C to rest of flags */      /* NZ00000C0000000V */}/*** Read flags from CX into our SR, performing a mode switch where applicable.** CX is unmodified.  Uses 4 bytes of stack.**** This does not do any of the trace flag mojo, so be sure to check for it** explicitly where applicable (hint: ret_timing_checkpoint).*/static void cx2sr(void){	int myline = linenum; linenum += 2;	emit("push ecx\n");	/* Step 1: switch supervisor mode */	/* Is the new mode different from the last? */	emit("mov cl,[__sr+1]\n");	emit("and cx,2020h\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -