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

📄 star.c

📁 著名ARC模拟器源码,包括多个平台
💻 C
📖 第 1 页 / 共 5 页
字号:
#define RAINE/*Raine version:- fixed writel trashing ecx- commented out read/writel_split checks- commented out address offset subs, raine does them beforehand*//*** Starscream 680x0 emulation library** Copyright 1997, 1998, 1999 Neill Corlett**** Refer to STARDOC.TXT for terms of use, API reference, and directions on** how to compile.*/#ifndef RAINE#define VERSION "0.26a"#else#define VERSION "0.26r"#endif/***************************************************************************//*** NOTE**** All 68020-related variables and functions are currently experimental, and** unsupported.*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>/***************************************************************************//*** Register Usage** --------------**** This is fairly consistent throughout the file.  Occasionally, EAX or EDX** will be used as a scratch register (in some cases the x86 instruction set** demands this).**** EAX: Bit   0  : V flag**      Bit  1-7 : MUST BE ZERO**      Bit   8  : C flag**      Bit  14  : Z flag**      Bit  15  : N flag**      Bit 16-31: undefined** EBX: Lower 16 bits: Current instruction word or register number**      Upper 16 bits: zero** ECX: Primary data** EDX: Primary address** EBP: Current base offset of PC** ESI: Current PC, including base offset** EDI: Cycle counter*//***************************************************************************//***  68010 Loop Mode Timing**  ----------------------****  Loop mode is implemented entirely in the DBRA instruction.  It will**  detect when it's supposed to be in loop mode, and adjust its timing when**  applicable.****  The __loopmode variable controls when loop mode is active.  It is set to**  1 after an eligible loop is completed.  It is set to 0 when the loop**  terminates, or when an interrupt / exception occurs.****  Loop info byte:****  Bits 1-3:  Continuation cycles / 2**  Bits 4-6:  Termination cycles / 2**  Bits 7-0:  (Expiration cycles - continuation cycles) / 2**  (bit 7 wraps around to bit 0)****  With the loop info byte in AL:**     To get the continuation cycles:**          and eax,byte 0Eh**     To get the termination cycles:**          shr al,3**          and eax,byte 0Eh**     To get the continue/expire difference:**          rol al,2**          and eax,byte 06h****  Default = DBh**           (11011011)**                101 : 101 = 5   2*5            = 10 continuation cycles**             101    : 101 = 5   2*5            = 10 termination cycles**            1      1:  11 = 3   2*3 = 6   10+6 = 16 expiration cycles****  (10/10/16 corresponds to the normal DBRA timing behavior)*//***************************************************************************//*** Algorithm for trace checkpoint in s680x0exec:**** If the SR trace flag is set {**   Set the trace trickybit.  This differentiates us from the out-of-time**    case above.**   Set cycles_leftover = cycles_needed.**   Force a context switch.** } otherwise {**   Clear the trace trickybit.** }** Begin the fetch/decode/execute loop as usual.****** In selected ret_timing routines:**** Subtract usual number of cycles from edi** If I'm out of time (edi is negative) {**   Jump to execend with SF set, as usual.** } otherwise (guaranteed at least one more instruction) {**   Jump to the s680x0exec trace checkpoint.** }****** Make sure that the group 1 exception handler clears the trace trickybit.****** Upon reaching execend:**** If the trace trickybit is set {**   Set cycles_needed = cycles_leftover.**   Add cycles_needed to edi.**   Generate a trace exception (clearing the SR trace flag in the process).**   Clear the trace trickybit.**   If edi is positive, resume the fetch/decode/execute loop.**    Otherwise, fall through to the usual epilogue code.** }*//***************************************************************************//*** Rebasing notes** --------------**** Cached rebase happens on:**  * JMP, JSR, RTS, RTE, RTR, RTD**  * Exceptions (except hardware interrupts)**** Uncached rebase happens on:**  * Entry to s680x0exec()**  * Hardware interrupts**  * Supervisor flag change**  * Cache disable/invalidate (68020+)**** I can't think of any good reason why the hardware interrupt case should be** uncached, except it happens to be convenient.*/typedef unsigned char  byte;typedef unsigned short word;typedef unsigned int   dword;static int use_stack   = -1;static int hog         = -1;static int addressbits = -1;static int cputype     = -1;static char *sourcename = NULL;/* This counts the number of instruction handling routines.  There's not much** point to it except for curiosity. */static int routine_counter = 0;/* Misc. constants */static char *x86ax   [5] = {"?", "al"  , "ax"  , "?", "eax"  };static char *x86bx   [5] = {"?", "bl"  , "bx"  , "?", "ebx"  };static char *x86cx   [5] = {"?", "cl"  , "cx"  , "?", "ecx"  };static char *x86dx   [5] = {"?", "dl"  , "dx"  , "?", "edx"  };static char *sizename[5] = {"?", "byte", "word", "?", "dword"};static int quickvalue[8] = {8, 1, 2, 3, 4, 5, 6, 7};static char direction[2] = {'r','l'};/* Output file where code will be emitted */static FILE *codefile;/* Line number - used to make temporary labels i.e. "ln1234" */static int linenum;/* Effective address modes */enum eamode {	dreg, areg, aind, ainc, adec, adsp,	axdp, absw, absl, pcdp, pcxd, immd};/* Loop information (68010) */static int loop_c_cycles;static int loop_t_cycles;static int loop_x_cycles;static unsigned char loopinfo[0x10000];/*** Misc. global variables which are used while generating instruction** handling routines.  Some of these may assume more than one role.*/static enum eamode main_eamode;   /* EA mode, usually source */static enum eamode main_destmode; /* EA mode, destination (for MOVE) */static int main_size;             /* Operand size (1, 2, or 4) */static int sizedef;               /* Size field in instruction word */static int main_reg;              /* Register number */static int main_cc;               /* Condition code (0-F) */static int main_dr;               /* Direction (right or left) */static int main_ir;               /* Immediate or register (for shifts) */static int main_qv;               /* Quick value *//* Emit a line of code (format string with other junk) */static void emit(const char *fmt, ...) {	va_list a;	va_start(a, fmt);	if(codefile) {		vfprintf(codefile, fmt, a);	} else {		fprintf(stderr, "Bad news: Tried to emit() to null file\n");		exit(1);	}}/* Dump all options.  This is delivered to stderr and to the code file. */static void optiondump(FILE *o, char *prefix) {	fprintf(o, "%sCPU type: %d (%d-bit addresses)\n", prefix,		cputype, addressbits);	fprintf(o, "%sIdentifiers begin with \"%s\"\n", prefix,		sourcename);	fprintf(o, "%s%s calling conventions\n", prefix,		use_stack ? "Stack" : "Register");	fprintf(o, "%sHog mode: %s\n", prefix,		hog ? "On" : "Off");}static void gen_banner(void) {	emit("; Generated by STARSCREAM version " VERSION "\n");	emit("; For assembly by NASM only\n");	emit(";\n");	emit("; Options:\n");	optiondump(codefile, "; *  ");	emit(";\n");	emit("bits 32\n");}static void align(int n) {	emit("times ($$-$)&%d db 0\n", n - 1);}static void maskaddress(char *reg) {	if(addressbits < 32) {		emit("and %s,%d\n", reg, (1 << addressbits) - 1);	}}static void begin_source_proc(char *fname) {	emit("global _%s%s\n", sourcename, fname);	emit("global %s%s_\n", sourcename, fname);	emit("_%s%s:\n", sourcename, fname);	emit("%s%s_:\n", sourcename, fname);}/* Generate variables */static void gen_variables(void) {	emit("section .data\n");	emit("bits 32\n");	emit("global _%scontext\n", sourcename);	align(8);	emit("_%scontext:\n", sourcename);	emit("contextbegin:\n");	/*	** CONTEXTINFO_MEM16	** CONTEXTINFO_MEM16FC	**	** 16-bit memory interface	*/	if(cputype <= 68010) {		emit("__fetch                dd 0\n");		emit("__readbyte             dd 0\n");		emit("__readword             dd 0\n");		emit("__writebyte            dd 0\n");		emit("__writeword            dd 0\n");		emit("__s_fetch              dd 0\n");		emit("__s_readbyte           dd 0\n");		emit("__s_readword           dd 0\n");		emit("__s_writebyte          dd 0\n");		emit("__s_writeword          dd 0\n");		emit("__u_fetch              dd 0\n");		emit("__u_readbyte           dd 0\n");		emit("__u_readword           dd 0\n");		emit("__u_writebyte          dd 0\n");		emit("__u_writeword          dd 0\n");		if(cputype == 68010) {			emit("__f_readbyte           dd 0\n");			emit("__f_readword           dd 0\n");			emit("__f_writebyte          dd 0\n");			emit("__f_writeword          dd 0\n");		}	/*	** CONTEXTINFO_MEM32	**	** 32-bit memory interface	*/	} else {		emit("__fetch                dd 0\n");		emit("__readbus              dd 0\n");		emit("__writebus             dd 0\n");		emit("__s_fetch              dd 0\n");		emit("__s_readbus            dd 0\n");		emit("__s_writebus           dd 0\n");		emit("__u_fetch              dd 0\n");		emit("__u_readbus            dd 0\n");		emit("__u_writebus           dd 0\n");		emit("__f_readbus            dd 0\n");		emit("__f_writebus           dd 0\n");	}	/*	** CONTEXTINFO_COMMON	**	** Registers and other info common to all CPU types	**	** It should be noted that on a double fault, bit 0 of both __pc and	** __interrupts will be set to 1.	*/	if(cputype >= 68000) {		emit("__resethandler         dd 0\n");		emit("__reg:\n");		emit("__dreg                 dd 0,0,0,0,0,0,0,0\n");		emit("__areg                 dd 0,0,0,0,0,0,0\n");		emit("__a7                   dd 0\n");		emit("__asp                  dd 0\n");		emit("__pc                   dd 0\n");		emit("__odometer             dd 0\n");		/* Bit 0 of __interrupts = stopped state */		emit("__interrupts           db 0,0,0,0,0,0,0,0\n");		emit("__sr                   dw 0\n");	}	/*	** CONTEXTINFO_68000SPECIFIC	*/	if(cputype == 68000) {		emit("__contextfiller00      dw 0\n");	}	/*	** CONTEXTINFO_68010	**	** Registers used on the 68010 and higher	*/	if(cputype >= 68010) {		emit("__sfc                  db 0\n");		emit("__dfc                  db 0\n");		emit("__vbr                  dd 0\n");		emit("__bkpthandler          dd 0\n");	}	/*	** CONTEXTINFO_68010SPECIFIC	**	** Registers used only on the 68010	*/	if(cputype == 68010) {		emit("__loopmode             db 0\n");		emit("__contextfiller10      db 0,0,0\n");	}	/*	** CONTEXTINFO_68020	**	** Registers used on the 68020 and higher	*/	if(cputype >= 68020) {		/*		** 68020 stack pointer rules (tentative)		**		** First of all, the 68000/68010 stack pointer behavior has		** not changed:		**		** 1. In supervisor mode, __a7 contains the supervisor stack		**    pointer and __asp contains the user stack pointer.		** 2. In user mode, __a7 contains the user stack pointer and		**    __asp contains the supervisor stack pointer.		**		** The only difference is that the "supervisor stack pointer"		** can be either ISP or MSP.  __xsp contains whichever stack		** pointer is _not_ the current "supervisor stack pointer".		**		** Here's a table summarizing the above rules:		**		**   S M | __a7 __asp __xsp		**   ----+-----------------		**   0 0 |  USP   ISP   MSP		**   0 1 |  USP   MSP   ISP		**   1 0 |  ISP   USP   MSP		**   1 1 |  MSP   USP   ISP		**		** As usual, whenever SR changes, we have to play Stack		** Pointer Switcheroo:		**		**  * If S changes: swap __asp and __a7 (as usual)		**  * If M changes:		**    - If S=0, swap __xsp and __asp		**    - If S=1, swap __xsp and __a7		*/		emit("__xsp                  dd 0\n");	}/*	align(4);*/	emit("contextend:\n");	emit("__cycles_needed        dd 0\n");	emit("__cycles_leftover      dd 0\n");	emit("__fetch_region_start   dd 0\n");/* Fetch region cache */	emit("__fetch_region_end     dd 0\n");	emit("__xflag                db 0\n");	/*	**  Format of __execinfo:	**  Bit 0:  s680x0exec currently running	**  Bit 1:  PC out of bounds	**  Bit 2:  Special I/O section	**	** "Special I/O section" is enabled during group 0 exception	** processing, and it means a couple things:	**   * Address and bus errors will not be tolerated (the CPU will	**     just keel over and die).  Therefore, information such as the	**     current PC is not relevant.	**   * Registers are not necessarily live.  Since special I/O	**     sections are guaranteed not to cause exceptions, this is not a	**     problem.	*/	emit("__execinfo             db 0\n");	emit("__trace_trickybit      db 0\n");/* Pending trace exception */	emit("__filler               db 0\n");	emit("__io_cycle_counter     dd -1\n");/*always -1 when idle*/	emit("__io_fetchbase         dd 0\n");	emit("__io_fetchbased_pc     dd 0\n");	emit("__access_address       dd 0\n");}/* Prepare to leave into the cold, dark world of compiled C code */static void airlock_exit(void) {	emit("mov [__io_cycle_counter],edi\n");	emit("mov [__io_fetchbase],ebp\n");	emit("mov [__io_fetchbased_pc],esi\n");	emit("push ebx\n");	emit("push eax\n");}/* Prepare to return to the warm fuzzy world of assembly code** (where everybody knows your name) */static void airlock_enter(void) {	emit("pop eax\n");	emit("pop ebx\n");	emit("mov edi,[__io_cycle_counter]\n");	emit("mov ebp,[__io_fetchbase]\n");	emit("mov esi,[__io_fetchbased_pc]\n");}enum { airlock_stacksize = 8 };static void cache_ccr(void) {	emit("mov al,[__sr]\n");    /* read CCR -> AL */                 /* ????????000XNZVC */	emit("mov ah,al\n");        /* copy to AH */                     /* 000XNZVC000XNZVC */	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,[__sr]\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 */}static void writeback_ccr(void) {	emit("shr ah,1\n");         /* C flag -> x86 carry */            /* 0NZ?????0000000V carry */	emit("adc ax,ax\n");        /* append to V flag */               /* NZ?????0000000VC */	emit("and ax,0C003h\n");    /* isolate NZ.......VC */            /* NZ000000000000VC */	emit("or ah,[__xflag]\n");  /* load X flag */                    /* NZ00000X000000VC */	emit("ror ah,4\n");         /* now we have XNZ....VC */          /* 000XNZ00000000VC */	emit("or al,ah\n");         /* OR them together */               /* 000XNZ00000XNZVC */	emit("mov [__sr],al\n");    /* store the result */               /* 000XNZ00000XNZVC al -> sr */}

⌨️ 快捷键说明

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