📄 star.c
字号:
/*** This will make edi _very_ negative... far enough negative that the** leftover cycle incorporation at the end of s68000exec() shouldn't be** enough to make it positive.*/static void force_context_switch(void) { emit("sub edi,[__cycles_needed]\n"); emit("mov dword[__cycles_needed],0\n");}/*** Put all the unused cycles in the leftover cycle bank, so we can call** attention to the tricky bit processor.*/static void force_trickybit_process(void) { emit("inc edi\n"); emit("add [__cycles_leftover],edi\n"); emit("or edi,byte -1\n");/* smaller than a mov */}/* "newpc" has been renamed to this */void perform_cached_rebase(void);/* Copy either __s_* or __u_* memory map pointers */static void copy_memory_map(char *map, char *reg) { emit("mov %s,[__%s_fetch]\n", reg, map); emit("mov [__fetch],%s\n", reg); if(cputype < 68020) { emit("mov %s,[__%s_readbyte]\n" , reg, map); emit("mov [__readbyte],%s\n" , reg); emit("mov %s,[__%s_readword]\n" , reg, map); emit("mov [__readword],%s\n" , reg); emit("mov %s,[__%s_writebyte]\n", reg, map); emit("mov [__writebyte],%s\n", reg); emit("mov %s,[__%s_writeword]\n", reg, map); emit("mov [__writeword],%s\n", reg); } else { emit("mov %s,[__%s_readbus]\n" , reg, map); emit("mov [__readbus],%s\n" , reg); emit("mov %s,[__%s_writebus]\n" , reg, map); emit("mov [__writebus],%s\n" , reg); }}/***************************************************************************/static void gen_interface(void) { emit("section .text\n"); emit("bits 32\n"); emit("top:\n");/***************************************************************************//*** s680x0init()**** Entry: Nothing** Exit: Zero**** This must be called before anything else. It decompresses the main jump** table (and loop info, in the case of the 68010).*/ begin_source_proc("init"); emit("pushad\n"); emit("mov edi,__jmptbl\n"); emit("mov esi,__jmptblcomp\n"); if(cputype == 68010) { emit("mov ebx,__looptbl\n"); } emit(".decomp:\n"); emit("lodsd\n"); emit("mov ecx,eax\n"); emit("and eax,0FFFFFFh\n"); emit("shr ecx,24\n"); emit("add eax,top\n"); emit("inc ecx\n"); if(cputype == 68010) { emit("mov ebp,ecx\n"); } emit(".jloop:\n"); emit("mov [edi],eax\n"); emit("add edi,byte 4\n"); emit("dec ecx\n"); emit("jnz short .jloop\n"); if(cputype == 68010) { emit("lodsb\n"); emit(".lloop:\n"); emit("mov [ebx],al\n"); emit("inc ebx\n"); emit("dec ebp\n"); emit("jnz short .lloop\n"); } emit("cmp edi,__jmptbl+262144\n"); emit("jne short .decomp\n"); emit("popad\n"); emit("xor eax,eax\n"); emit("ret\n");/***************************************************************************//*** s680x0exec(cycles)**** Entry: EAX = # cycles to execute** Exit: 80000000h: success** 80000001h: PC out of range** 80000002h: unsupported stack frame** FFFFFFFFh: CPU is dead because of a double fault** < 80000000h: invalid instruction = address of invalid instr.*/ begin_source_proc("exec"); if(use_stack) emit("mov eax,[esp+4]\n"); /* ** Check for stopped and double-faulted states. */ emit("test byte[__interrupts],1\n"); emit("jz .notstopped\n"); emit("test byte[__pc],1\n"); emit("jz .notfaulted\n"); emit("or eax,byte -1\n"); emit("ret\n"); emit(".notfaulted:\n"); emit("add [__odometer],eax\n"); emit("mov eax,80000000h\n"); emit("ret\n"); emit(".notstopped:\n"); emit("push ebp\n"); emit("push ebx\n"); emit("push ecx\n"); emit("push edx\n"); emit("push esi\n"); emit("push edi\n"); emit("mov [__cycles_needed],eax\n"); emit("mov edi,eax\n");/* store # of cycles to execute */ emit("dec edi\n"); emit("xor ebx,ebx\n"); emit("mov esi,[__pc]\n"); cache_ccr(); emit("xor ebp,ebp\n"); emit("mov byte[__execinfo],1\n"); /* ** Force an uncached re-base. ** This fulfills the "Entry to s680x0exec()" case. */ emit("call basefunction\n"); emit("add esi,ebp\n"); emit("test byte[__execinfo],2\n"); /* Check for PC out of bounds */ emit("jnz near exec_bounderror\n"); emit("mov dword[__cycles_leftover],0\n");/* an extra precaution */ /* PPL and Trace checkpoint */ emit("exec_checkpoint:\n"); emit("js short execquit\n"); /* Check PPL */ emit("mov cl,[__sr+1]\n"); emit("and ecx,byte 7\n"); emit("inc ecx\n"); emit("mov ch,[__interrupts]\n"); emit("or ch,ch\n"); emit("js short .yesint\n"); emit("shr ch,cl\n"); emit("jz short .noint\n"); emit(".yesint:\n"); emit("call flush_interrupts\n"); /* Force an uncached re-base */ emit("call basefunction\n"); emit("add esi,ebp\n"); emit("test byte[__execinfo],2\n"); /* Check for PC out of bounds */ emit("jnz near exec_bounderror\n"); emit(".noint:\n"); /* ** If the SR Trace flag is set, generate a pending trace exception. */ emit("mov ch,[__sr+1]\n"); emit("and ch,80h\n"); /* isolate trace flag */ emit("mov [__trace_trickybit],ch\n"); emit("jz short execloop\n"); /* ** Activate the tricky bit processor. ** ** Because edi isn't checked for negativity before entering the ** fetch/decode/execute loop, we're guaranteed to execute at least ** one more instruction before any trace exception. ** ** If another group 1 exception happens in the course of executing ** this next instruction, then the group_1_exception routine will ** clear the trace tricky bit and re-adjust the cycle counters, and ** we'll pretend none of this ever happened. */ force_trickybit_process(); emit("execloop:\n");/* emit("xor ebx,ebx\n");suffice to say, bits 16-31 should be zero... */ emit("mov bx,[esi]\n"); emit("add esi,byte 2\n"); emit("jmp dword[__jmptbl+ebx*4]\n"); /* Traditional loop - used when hog mode is off */ if(!hog) { emit("execend:\n"); emit("jns short execloop\n"); } emit("execquit:\n"); /* ** Tricky Bit Processor */ /* Look for trace tricky bit */ emit("cmp byte[__trace_trickybit],0\n"); emit("je short execquit_notrace\n"); /* Generate trace exception */ emit("mov edx,24h\n"); emit("call group_1_exception\n"); perform_cached_rebase(); /* Subtract time used by exception processing */ emit("sub edi,byte %d\n", (cputype == 68010) ? 38 : 34); emit("execquit_notrace:\n"); /* ** Look for pending interrupts that exceed the current PPL. These ** are higher priority and are therefore processed last (the ISR will ** end up getting control). */ emit("mov cl,[__sr+1]\n"); emit("and ecx,byte 7\n"); emit("inc ecx\n"); emit("mov ch,[__interrupts]\n"); emit("or ch,ch\n"); emit("js short execquit_yesinterrupt\n"); emit("shr ch,cl\n"); emit("jz short execquit_nointerrupt\n"); emit("execquit_yesinterrupt:\n"); emit("call flush_interrupts\n"); /* ** Force an uncached re-base. ** This fulfills the "Hardware interrupt" case. */ emit("call basefunction\n"); emit("add esi,ebp\n"); emit("test byte[__execinfo],2\n"); /* Check for PC out of bounds */ emit("jnz short exec_bounderror\n"); emit("execquit_nointerrupt:\n"); /* ** Incorporate leftover cycles (if any) and see if we should keep ** running. */ emit("add edi,[__cycles_leftover]\n"); emit("mov dword[__cycles_leftover],0\n"); emit("jns short execloop\n"); /* Leave s680x0exec with "Success" code. */ emit("mov ecx,80000000h\n"); /* ** Exit the s680x0exec routine. By this time the return code should ** already be in ecx. */ emit("execexit:\n"); emit("sub esi,ebp\n"); writeback_ccr(); emit("mov [__pc],esi\n"); emit("inc edi\n"); emit("mov edx,[__cycles_needed]\n"); emit("sub edx,edi\n"); emit("add [__odometer],edx\n"); emit("mov byte[__execinfo],0\n"); /* ** Remember: __io_cycle_counter is always -1 when idle! ** ** This prevents us from having to check __execinfo during the ** readOdometer / tripOdometer calls. */ emit("mov dword[__cycles_needed],0\n"); emit("mov dword[__io_cycle_counter],-1\n"); emit("mov eax,ecx\n");/* return code */ emit("pop edi\n"); emit("pop esi\n"); emit("pop edx\n"); emit("pop ecx\n"); emit("pop ebx\n"); emit("pop ebp\n"); emit("ret\n"); /* ** Leave s680x0exec with "Out of bounds" code. */ emit("exec_bounderror:\n"); emit("mov ecx,80000001h\n"); emit("jmp short execexit\n"); /* ** Invalid instruction handler */ emit("invalidins:\n"); emit("sub esi,byte 2\n"); /* back up one word */ emit("mov ecx,esi\n");/* get address in ecx */ emit("sub ecx,ebp\n");/* subtract base */ maskaddress("ecx"); if(addressbits == 32) { emit("and ecx,7FFFFFFFh\n"); }/* emit("or byte[__stopped],2\n");*/ emit("jmp short execexit\n");/***************************************************************************//*** s680x0reset()**** Entry: Nothing** Exit: 0 on success** 1 on failure:** * if there's no Supervisor Program entry for address 0** * if s680x0exec() is active** -1 on double fault*/ begin_source_proc("reset"); emit("mov eax,1\n"); emit("test [__execinfo],al\n"); /* Ensure s680x0exec() inactive */ emit("jnz near .return\n"); emit("cmp dword[__s_fetch],0\n"); emit("je near .return\n"); emit("dec eax\n"); emit("mov [__execinfo],al\n"); emit("sub eax,byte 16\n"); emit(".gp:\n"); emit("mov dword[__reg+64+eax*4],0\n"); emit("inc eax\n"); emit("jnz short .gp\n"); emit("mov [__asp],eax\n"); if(cputype >= 68020) emit("mov [__xsp],eax\n"); /* Set up SR for no tracing, supervisor mode, ISP, PPL 7 */ emit("mov word[__sr],2700h\n"); if(cputype >= 68010) { emit("mov [__vbr],eax\n"); emit("mov [__sfc],al\n"); emit("mov [__dfc],al\n"); } if(cputype == 68010) { emit("mov [__loopmode],al\n"); } /* Copy supervisor address space information */ copy_memory_map("s", "eax"); /* Generate Supervisor Program Space reads to get the initial PC and ** SSP/ISP */ emit("mov eax,1\n"); /* assume failure */ emit("mov [__pc],eax\n"); emit("mov [__interrupts],al\n"); emit("push esi\n"); emit("push ebp\n"); emit("xor esi,esi\n"); emit("call basefunction\n");/* will preserve eax */ emit("test byte[__execinfo],2\n"); emit("jnz short .exit\n"); emit("add esi,ebp\n"); emit("mov eax,[esi]\n"); emit("rol eax,16\n"); emit("mov [__a7],eax\n"); emit("mov eax,[esi+4]\n"); emit("rol eax,16\n"); emit("mov [__pc],eax\n"); /* An address error here will cause a double fault */ emit("and eax,byte 1\n"); emit("mov [__interrupts],al\n"); emit("neg eax\n"); /* -1 on double fault, 0 on success */ emit(".exit:\n"); emit("pop ebp\n"); emit("pop esi\n"); emit(".return:\n"); emit("ret\n");/***************************************************************************//*** s680x0interrupt(level, vector)**** Entry: EAX = interrupt level** EDX = vector (-1 for auto, -2 for spurious)** Exit: EAX = 0 on success** 1 on failure, previous vector exists** 2 on invalid input*/ begin_source_proc("interrupt"); emit("push edx\n"); if(use_stack) { emit("mov eax,[esp+8]\n"); /* eax = level */ emit("mov edx,[esp+12]\n"); /* edx = vector */ } /* ** Verify parameters. */ emit("cmp eax,byte 7\n"); emit("ja short .badinput\n"); emit("or eax,eax\n"); emit("jz short .badinput\n"); emit("cmp edx,255\n"); emit("jg short .badinput\n"); emit("cmp edx,byte -2\n"); emit("jl short .badinput\n"); /* ** Calculate the vector number. */ emit("jne short .notspurious\n"); emit("mov edx,18h\n"); emit(".notspurious:\n"); emit("or edx,edx\n"); emit("jns short .notauto\n"); emit("lea edx,[eax+18h]\n"); emit(".notauto:\n"); /* ** Test to see if this interrupt level is already pending. ** If it is, return with failure. */ emit("push ecx\n"); emit("mov cl,al\n"); emit("mov ah,1\n"); emit("shl ah,cl\n"); emit("pop ecx\n"); emit("test [__interrupts],ah\n"); emit("jnz .failure\n"); /* ** Commit the given interrupt and vector number. */ emit("or [__interrupts],ah\n"); emit("mov ah,0\n"); emit("mov [__interrupts+eax],dl\n"); emit("and byte[__interrupts],0FEh\n"); /* ** Notify the tricky bit handler. If we're doing this outside of ** s680x0exec(), then the notification will have no effect, because ** __io_cycle_counter is always -1 when idle. */ emit("mov edx,[__io_cycle_counter]\n"); emit("inc edx\n"); emit("add [__cycles_leftover],edx\n"); emit("mov dword[__io_cycle_counter],-1\n"); /* ** Success (0) */ emit("pop edx\n"); emit("xor eax,eax\n"); emit("ret\n"); /* ** Failure (1) */ emit(".failure:\n"); emit("pop edx\n"); emit("mov eax,1\n"); emit("ret\n"); /* ** Bad input (2) */ emit(".badinput:\n"); emit("pop edx\n"); emit("mov eax,2\n"); emit("ret\n");/***************************************************************************//*** s680x0flushInterrupts()**** Flushes all pending interrupts.**** Entry: Nothing** Exit: Nothing*/ begin_source_proc("flushInterrupts"); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -