📄 armsupp.c
字号:
{ CLEARN; CLEARZ; }}/* Compute whether an addition of A and B, giving RESULT, overflowed. */intAddOverflow (ARMword a, ARMword b, ARMword result){ return ((NEG (a) && NEG (b) && POS (result)) || (POS (a) && POS (b) && NEG (result)));}/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */intSubOverflow (ARMword a, ARMword b, ARMword result){ return ((NEG (a) && POS (b) && POS (result)) || (POS (a) && NEG (b) && NEG (result)));}/* Assigns the C flag after an addition of a and b to give result. */voidARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result){ ASSIGNC ((NEG (a) && NEG (b)) || (NEG (a) && POS (result)) || (NEG (b) && POS (result)));}/* Assigns the V flag after an addition of a and b to give result. */voidARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result){ ASSIGNV (AddOverflow (a, b, result));}/* Assigns the C flag after an subtraction of a and b to give result. */voidARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result){ ASSIGNC ((NEG (a) && POS (b)) || (NEG (a) && POS (result)) || (POS (b) && POS (result)));}/* Assigns the V flag after an subtraction of a and b to give result. */voidARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result){ ASSIGNV (SubOverflow (a, b, result));}/* This function does the work of generating the addresses used in an LDC instruction. The code here is always post-indexed, it's up to the caller to get the input address correct and to handle base register modification. It also handles the Busy-Waiting. */voidARMul_LDC (ARMul_State * state, ARMword instr, ARMword address){ unsigned cpab; ARMword data; UNDEF_LSCPCBaseWb; if (! CP_ACCESS_ALLOWED (state, CPNum)) { ARMul_UndefInstr (state, instr); return; } if (ADDREXCEPT (address)) INTERNALABORT (address); cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); while (cpab == ARMul_BUSY) { ARMul_Icycles (state, 1, 0); if (IntPending (state)) { cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0); return; } else cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0); } if (cpab == ARMul_CANT) { CPTAKEABORT; return; } cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0); data = ARMul_LoadWordN (state, address); BUSUSEDINCPCN; if (BIT (21)) LSBase = state->Base; cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); while (cpab == ARMul_INC) { address += 4; data = ARMul_LoadWordN (state, address); cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); } if (state->abortSig || state->Aborted) TAKEABORT;}/* This function does the work of generating the addresses used in an STC instruction. The code here is always post-indexed, it's up to the caller to get the input address correct and to handle base register modification. It also handles the Busy-Waiting. */voidARMul_STC (ARMul_State * state, ARMword instr, ARMword address){ unsigned cpab; ARMword data; UNDEF_LSCPCBaseWb; if (! CP_ACCESS_ALLOWED (state, CPNum)) { ARMul_UndefInstr (state, instr); return; } if (ADDREXCEPT (address) || VECTORACCESS (address)) INTERNALABORT (address); cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); while (cpab == ARMul_BUSY) { ARMul_Icycles (state, 1, 0); if (IntPending (state)) { cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0); return; } else cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data); } if (cpab == ARMul_CANT) { CPTAKEABORT; return; }#ifndef MODE32 if (ADDREXCEPT (address) || VECTORACCESS (address)) INTERNALABORT (address);#endif BUSUSEDINCPCN; if (BIT (21)) LSBase = state->Base; cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); ARMul_StoreWordN (state, address, data); while (cpab == ARMul_INC) { address += 4; cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); ARMul_StoreWordN (state, address, data); } if (state->abortSig || state->Aborted) TAKEABORT;}/* This function does the Busy-Waiting for an MCR instruction. */voidARMul_MCR (ARMul_State * state, ARMword instr, ARMword source){ unsigned cpab; if (! CP_ACCESS_ALLOWED (state, CPNum)) { ARMul_UndefInstr (state, instr); return; } cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); while (cpab == ARMul_BUSY) { ARMul_Icycles (state, 1, 0); if (IntPending (state)) { cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0); return; } else cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source); } if (cpab == ARMul_CANT) ARMul_Abort (state, ARMul_UndefinedInstrV); else { BUSUSEDINCPCN; ARMul_Ccycles (state, 1, 0); }}/* This function does the Busy-Waiting for an MRC instruction. */ARMwordARMul_MRC (ARMul_State * state, ARMword instr){ unsigned cpab; ARMword result = 0; if (! CP_ACCESS_ALLOWED (state, CPNum)) { ARMul_UndefInstr (state, instr); return; } cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result); while (cpab == ARMul_BUSY) { ARMul_Icycles (state, 1, 0); if (IntPending (state)) { cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0); return (0); } else cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result); } if (cpab == ARMul_CANT) { ARMul_Abort (state, ARMul_UndefinedInstrV); /* Parent will destroy the flags otherwise. */ result = ECC; } else { BUSUSEDINCPCN; ARMul_Ccycles (state, 1, 0); ARMul_Icycles (state, 1, 0); } return result;}/* This function does the Busy-Waiting for an CDP instruction. */voidARMul_CDP (ARMul_State * state, ARMword instr){ unsigned cpab; if (! CP_ACCESS_ALLOWED (state, CPNum)) { ARMul_UndefInstr (state, instr); return; } cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr); while (cpab == ARMul_BUSY) { ARMul_Icycles (state, 1, 0); if (IntPending (state)) { cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr); return; } else cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr); } if (cpab == ARMul_CANT) ARMul_Abort (state, ARMul_UndefinedInstrV); else BUSUSEDN;}/* This function handles Undefined instructions, as CP isntruction. */voidARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED){ ARMul_Abort (state, ARMul_UndefinedInstrV);}/* Return TRUE if an interrupt is pending, FALSE otherwise. */unsignedIntPending (ARMul_State * state){ if (state->Exception) { /* Any exceptions. */ if (state->NresetSig == LOW) { ARMul_Abort (state, ARMul_ResetV); return TRUE; } else if (!state->NfiqSig && !FFLAG) { ARMul_Abort (state, ARMul_FIQV); return TRUE; } else if (!state->NirqSig && !IFLAG) { ARMul_Abort (state, ARMul_IRQV); return TRUE; } } return FALSE;}/* Align a word access to a non word boundary. */ARMwordARMul_Align (state, address, data) ARMul_State * state ATTRIBUTE_UNUSED; ARMword address; ARMword data;{ /* This code assumes the address is really unaligned, as a shift by 32 is undefined in C. */ address = (address & 3) << 3; /* Get the word address. */ return ((data >> address) | (data << (32 - address))); /* rot right */}/* This routine is used to call another routine after a certain number of cycles have been executed. The first parameter is the number of cycles delay before the function is called, the second argument is a pointer to the function. A delay of zero doesn't work, just call the function. */voidARMul_ScheduleEvent (ARMul_State * state, unsigned long delay, unsigned (*what) (ARMul_State *)){ unsigned long when; struct EventNode *event; if (state->EventSet++ == 0) state->Now = ARMul_Time (state); when = (state->Now + delay) % EVENTLISTSIZE; event = (struct EventNode *) malloc (sizeof (struct EventNode)); event->func = what; event->next = *(state->EventPtr + when); *(state->EventPtr + when) = event;}/* This routine is called at the beginning of every cycle, to envoke scheduled events. */voidARMul_EnvokeEvent (ARMul_State * state){ static unsigned long then; then = state->Now; state->Now = ARMul_Time (state) % EVENTLISTSIZE; if (then < state->Now) /* Schedule events. */ EnvokeList (state, then, state->Now); else if (then > state->Now) { /* Need to wrap around the list. */ EnvokeList (state, then, EVENTLISTSIZE - 1L); EnvokeList (state, 0L, state->Now); }}/* Envokes all the entries in a range. */static voidEnvokeList (ARMul_State * state, unsigned long from, unsigned long to){ for (; from <= to; from++) { struct EventNode *anevent; anevent = *(state->EventPtr + from); while (anevent) { (anevent->func) (state); state->EventSet--; anevent = anevent->next; } *(state->EventPtr + from) = NULL; }}/* This routine is returns the number of clock ticks since the last reset. */unsigned longARMul_Time (ARMul_State * state){ return (state->NumScycles + state->NumNcycles + state->NumIcycles + state->NumCcycles + state->NumFcycles);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -