RegInfo* NewRegInfo (const RegContents* RC) /* Allocate a new register info, initialize and return it. If RC is not * a NULL pointer, it is used to initialize both, the input and output * registers. If the pointer is NULL, all registers are set to unknown. */ { /* Allocate memory */ RegInfo* RI = xmalloc (sizeof (RegInfo)); /* Initialize the registers */ if (RC) { RI->In = *RC; RI->Out = *RC; RI->Out2 = *RC; } else { RC_Invalidate (&RI->In); RC_Invalidate (&RI->Out); RC_Invalidate (&RI->Out2); } /* Return the new struct */ return RI; }
void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) /* Generate register info for this instruction. If an old info exists, it is ** overwritten. */ { /* Pointers to the register contents */ RegContents* In; RegContents* Out; /* Function register usage */ unsigned short Use, Chg; /* If we don't have a register info struct, allocate one. */ if (E->RI == 0) { E->RI = NewRegInfo (InputRegs); } else { if (InputRegs) { E->RI->In = *InputRegs; } else { RC_Invalidate (&E->RI->In); } E->RI->Out2 = E->RI->Out = E->RI->In; } /* Get pointers to the register contents */ In = &E->RI->In; Out = &E->RI->Out; /* Handle the different instructions */ switch (E->OPC) { case OP65_ADC: /* We don't know the value of the carry, so the result is ** always unknown. */ Out->RegA = UNKNOWN_REGVAL; break; case OP65_AND: if (RegValIsKnown (In->RegA)) { if (CE_IsConstImm (E)) { Out->RegA = In->RegA & (short) E->Num; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Out->RegA = In->RegA & In->Tmp1; break; case REG_PTR1_LO: Out->RegA = In->RegA & In->Ptr1Lo; break; case REG_PTR1_HI: Out->RegA = In->RegA & In->Ptr1Hi; break; case REG_SREG_LO: Out->RegA = In->RegA & In->SRegLo; break; case REG_SREG_HI: Out->RegA = In->RegA & In->SRegHi; break; default: Out->RegA = UNKNOWN_REGVAL; break; } } else { Out->RegA = UNKNOWN_REGVAL; } } else if (CE_IsKnownImm (E, 0)) { /* A and $00 does always give zero */ Out->RegA = 0; } break; case OP65_ASL: if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA << 1) & 0xFF; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Chg & REG_ZP, In)) { case REG_TMP1: Out->Tmp1 = (In->Tmp1 << 1) & 0xFF; break; case REG_PTR1_LO: Out->Ptr1Lo = (In->Ptr1Lo << 1) & 0xFF; break; case REG_PTR1_HI: Out->Ptr1Hi = (In->Ptr1Hi << 1) & 0xFF; break; case REG_SREG_LO: Out->SRegLo = (In->SRegLo << 1) & 0xFF; break; case REG_SREG_HI: Out->SRegHi = (In->SRegHi << 1) & 0xFF; break; } } else if (E->AM == AM65_ZPX) { /* Invalidates all ZP registers */ RC_InvalidateZP (Out); } break; case OP65_BCC: break; case OP65_BCS: break; case OP65_BEQ: break; case OP65_BIT: break; case OP65_BMI: break; case OP65_BNE: break; case OP65_BPL: break; case OP65_BRA: break; case OP65_BRK: break; case OP65_BVC: break; case OP65_BVS: break; case OP65_CLC: break; case OP65_CLD: break; case OP65_CLI: break; case OP65_CLV: break; case OP65_CMP: break; case OP65_CPX: break; case OP65_CPY: break; case OP65_DEA: if (RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA - 1) & 0xFF; } break; case OP65_DEC: if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA - 1) & 0xFF; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Chg & REG_ZP, In)) { case REG_TMP1: Out->Tmp1 = (In->Tmp1 - 1) & 0xFF; break; case REG_PTR1_LO: Out->Ptr1Lo = (In->Ptr1Lo - 1) & 0xFF; break; case REG_PTR1_HI: Out->Ptr1Hi = (In->Ptr1Hi - 1) & 0xFF; break; case REG_SREG_LO: Out->SRegLo = (In->SRegLo - 1) & 0xFF; break; case REG_SREG_HI: Out->SRegHi = (In->SRegHi - 1) & 0xFF; break; } } else if (E->AM == AM65_ZPX) { /* Invalidates all ZP registers */ RC_InvalidateZP (Out); } break; case OP65_DEX: if (RegValIsKnown (In->RegX)) { Out->RegX = (In->RegX - 1) & 0xFF; } break; case OP65_DEY: if (RegValIsKnown (In->RegY)) { Out->RegY = (In->RegY - 1) & 0xFF; } break; case OP65_EOR: if (RegValIsKnown (In->RegA)) { if (CE_IsConstImm (E)) { Out->RegA = In->RegA ^ (short) E->Num; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Out->RegA = In->RegA ^ In->Tmp1; break; case REG_PTR1_LO: Out->RegA = In->RegA ^ In->Ptr1Lo; break; case REG_PTR1_HI: Out->RegA = In->RegA ^ In->Ptr1Hi; break; case REG_SREG_LO: Out->RegA = In->RegA ^ In->SRegLo; break; case REG_SREG_HI: Out->RegA = In->RegA ^ In->SRegHi; break; default: Out->RegA = UNKNOWN_REGVAL; break; } } else { Out->RegA = UNKNOWN_REGVAL; } } break; case OP65_INA: if (RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA + 1) & 0xFF; } break; case OP65_INC: if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA + 1) & 0xFF; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Chg & REG_ZP, In)) { case REG_TMP1: Out->Tmp1 = (In->Tmp1 + 1) & 0xFF; break; case REG_PTR1_LO: Out->Ptr1Lo = (In->Ptr1Lo + 1) & 0xFF; break; case REG_PTR1_HI: Out->Ptr1Hi = (In->Ptr1Hi + 1) & 0xFF; break; case REG_SREG_LO: Out->SRegLo = (In->SRegLo + 1) & 0xFF; break; case REG_SREG_HI: Out->SRegHi = (In->SRegHi + 1) & 0xFF; break; } } else if (E->AM == AM65_ZPX) { /* Invalidates all ZP registers */ RC_InvalidateZP (Out); } break; case OP65_INX: if (RegValIsKnown (In->RegX)) { Out->RegX = (In->RegX + 1) & 0xFF; } break; case OP65_INY: if (RegValIsKnown (In->RegY)) { Out->RegY = (In->RegY + 1) & 0xFF; } break; case OP65_JCC: break; case OP65_JCS: break; case OP65_JEQ: break; case OP65_JMI: break; case OP65_JMP: break; case OP65_JNE: break; case OP65_JPL: break; case OP65_JSR: /* Get the code info for the function */ GetFuncInfo (E->Arg, &Use, &Chg); if (Chg & REG_A) { Out->RegA = UNKNOWN_REGVAL; } if (Chg & REG_X) { Out->RegX = UNKNOWN_REGVAL; } if (Chg & REG_Y) { Out->RegY = UNKNOWN_REGVAL; } if (Chg & REG_TMP1) { Out->Tmp1 = UNKNOWN_REGVAL; } if (Chg & REG_PTR1_LO) { Out->Ptr1Lo = UNKNOWN_REGVAL; } if (Chg & REG_PTR1_HI) { Out->Ptr1Hi = UNKNOWN_REGVAL; } if (Chg & REG_SREG_LO) { Out->SRegLo = UNKNOWN_REGVAL; } if (Chg & REG_SREG_HI) { Out->SRegHi = UNKNOWN_REGVAL; } /* ## FIXME: Quick hack for some known functions: */ if (strcmp (E->Arg, "complax") == 0) { if (RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA ^ 0xFF); } if (RegValIsKnown (In->RegX)) { Out->RegX = (In->RegX ^ 0xFF); } } else if (strcmp (E->Arg, "tosandax") == 0) { if (In->RegA == 0) { Out->RegA = 0; } if (In->RegX == 0) { Out->RegX = 0; } } else if (strcmp (E->Arg, "tosaslax") == 0) { if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) { printf ("Hey!\n"); Out->RegA = 0; } } else if (strcmp (E->Arg, "tosorax") == 0) { if (In->RegA == 0xFF) { Out->RegA = 0xFF; } if (In->RegX == 0xFF) { Out->RegX = 0xFF; } } else if (strcmp (E->Arg, "tosshlax") == 0) { if ((In->RegA & 0x0F) >= 8) { Out->RegA = 0; } } else if (FindBoolCmpCond (E->Arg) != CMP_INV || FindTosCmpCond (E->Arg) != CMP_INV) { /* Result is boolean value, so X is zero on output */ Out->RegX = 0; } break; case OP65_JVC: break; case OP65_JVS: break; case OP65_LDA: if (CE_IsConstImm (E)) { Out->RegA = (unsigned char) E->Num; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Out->RegA = In->Tmp1; break; case REG_PTR1_LO: Out->RegA = In->Ptr1Lo; break; case REG_PTR1_HI: Out->RegA = In->Ptr1Hi; break; case REG_SREG_LO: Out->RegA = In->SRegLo; break; case REG_SREG_HI: Out->RegA = In->SRegHi; break; default: Out->RegA = UNKNOWN_REGVAL; break; } } else { /* A is now unknown */ Out->RegA = UNKNOWN_REGVAL; } break; case OP65_LDX: if (CE_IsConstImm (E)) { Out->RegX = (unsigned char) E->Num; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Out->RegX = In->Tmp1; break; case REG_PTR1_LO: Out->RegX = In->Ptr1Lo; break; case REG_PTR1_HI: Out->RegX = In->Ptr1Hi; break; case REG_SREG_LO: Out->RegX = In->SRegLo; break; case REG_SREG_HI: Out->RegX = In->SRegHi; break; default: Out->RegX = UNKNOWN_REGVAL; break; } } else { /* X is now unknown */ Out->RegX = UNKNOWN_REGVAL; } break; case OP65_LDY: if (CE_IsConstImm (E)) { Out->RegY = (unsigned char) E->Num; } else if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Out->RegY = In->Tmp1; break; case REG_PTR1_LO: Out->RegY = In->Ptr1Lo; break; case REG_PTR1_HI: Out->RegY = In->Ptr1Hi; break; case REG_SREG_LO: Out->RegY = In->SRegLo; break; case REG_SREG_HI: Out->RegY = In->SRegHi; break; default: Out->RegY = UNKNOWN_REGVAL; break; } } else { /* Y is now unknown */ Out->RegY = UNKNOWN_REGVAL; } break; case OP65_LSR: if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) { Out->RegA = (In->RegA >> 1) & 0xFF; } else if (E->AM == AM65_ZP) {
void CS_GenRegInfo (CodeSeg* S) /* Generate register infos for all instructions */ { unsigned I; RegContents Regs; /* Initial register contents */ RegContents* CurrentRegs; /* Current register contents */ int WasJump; /* True if last insn was a jump */ int Done; /* All runs done flag */ /* Be sure to delete all register infos */ CS_FreeRegInfo (S); /* We may need two runs to get back references right */ do { /* Assume we're done after this run */ Done = 1; /* On entry, the register contents are unknown */ RC_Invalidate (&Regs); CurrentRegs = &Regs; /* Walk over all insns and note just the changes from one insn to the * next one. */ WasJump = 0; for (I = 0; I < CS_GetEntryCount (S); ++I) { CodeEntry* P; /* Get the next instruction */ CodeEntry* E = CollAtUnchecked (&S->Entries, I); /* If the instruction has a label, we need some special handling */ unsigned LabelCount = CE_GetLabelCount (E); if (LabelCount > 0) { /* Loop over all entry points that jump here. If these entry * points already have register info, check if all values are * known and identical. If all values are identical, and the * preceeding instruction was not an unconditional branch, check * if the register value on exit of the preceeding instruction * is also identical. If all these values are identical, the * value of a register is known, otherwise it is unknown. */ CodeLabel* Label = CE_GetLabel (E, 0); unsigned Entry; if (WasJump) { /* Preceeding insn was an unconditional branch */ CodeEntry* J = CL_GetRef(Label, 0); if (J->RI) { Regs = J->RI->Out2; } else { RC_Invalidate (&Regs); } Entry = 1; } else { Regs = *CurrentRegs; Entry = 0; } while (Entry < CL_GetRefCount (Label)) { /* Get this entry */ CodeEntry* J = CL_GetRef (Label, Entry); if (J->RI == 0) { /* No register info for this entry. This means that the * instruction that jumps here is at higher addresses and * the jump is a backward jump. We need a second run to * get the register info right in this case. Until then, * assume unknown register contents. */ Done = 0; RC_Invalidate (&Regs); break; } if (J->RI->Out2.RegA != Regs.RegA) { Regs.RegA = UNKNOWN_REGVAL; } if (J->RI->Out2.RegX != Regs.RegX) { Regs.RegX = UNKNOWN_REGVAL; } if (J->RI->Out2.RegY != Regs.RegY) { Regs.RegY = UNKNOWN_REGVAL; } if (J->RI->Out2.SRegLo != Regs.SRegLo) { Regs.SRegLo = UNKNOWN_REGVAL; } if (J->RI->Out2.SRegHi != Regs.SRegHi) { Regs.SRegHi = UNKNOWN_REGVAL; } if (J->RI->Out2.Tmp1 != Regs.Tmp1) { Regs.Tmp1 = UNKNOWN_REGVAL; } ++Entry; } /* Use this register info */ CurrentRegs = &Regs; } /* Generate register info for this instruction */ CE_GenRegInfo (E, CurrentRegs); /* Remember for the next insn if this insn was an uncondition branch */ WasJump = (E->Info & OF_UBRA) != 0; /* Output registers for this insn are input for the next */ CurrentRegs = &E->RI->Out; /* If this insn is a branch on zero flag, we may have more info on * register contents for one of both flow directions, but only if * there is a previous instruction. */ if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) { /* Get the branch condition */ bc_t BC = GetBranchCond (E->OPC); /* Check the previous instruction */ switch (P->OPC) { case OP65_ADC: case OP65_AND: case OP65_DEA: case OP65_EOR: case OP65_INA: case OP65_LDA: case OP65_ORA: case OP65_PLA: case OP65_SBC: /* A is zero in one execution flow direction */ if (BC == BC_EQ) { E->RI->Out2.RegA = 0; } else { E->RI->Out.RegA = 0; } break; case OP65_CMP: /* If this is an immidiate compare, the A register has * the value of the compare later. */ if (CE_IsConstImm (P)) { if (BC == BC_EQ) { E->RI->Out2.RegA = (unsigned char)P->Num; } else { E->RI->Out.RegA = (unsigned char)P->Num; } } break; case OP65_CPX: /* If this is an immidiate compare, the X register has * the value of the compare later. */ if (CE_IsConstImm (P)) { if (BC == BC_EQ) { E->RI->Out2.RegX = (unsigned char)P->Num; } else { E->RI->Out.RegX = (unsigned char)P->Num; } } break; case OP65_CPY: /* If this is an immidiate compare, the Y register has * the value of the compare later. */ if (CE_IsConstImm (P)) { if (BC == BC_EQ) { E->RI->Out2.RegY = (unsigned char)P->Num; } else { E->RI->Out.RegY = (unsigned char)P->Num; } } break; case OP65_DEX: case OP65_INX: case OP65_LDX: case OP65_PLX: /* X is zero in one execution flow direction */ if (BC == BC_EQ) { E->RI->Out2.RegX = 0; } else { E->RI->Out.RegX = 0; } break; case OP65_DEY: case OP65_INY: case OP65_LDY: case OP65_PLY: /* X is zero in one execution flow direction */ if (BC == BC_EQ) { E->RI->Out2.RegY = 0; } else { E->RI->Out.RegY = 0; } break; case OP65_TAX: case OP65_TXA: /* If the branch is a beq, both A and X are zero at the * branch target, otherwise they are zero at the next * insn. */ if (BC == BC_EQ) { E->RI->Out2.RegA = E->RI->Out2.RegX = 0; } else { E->RI->Out.RegA = E->RI->Out.RegX = 0; } break; case OP65_TAY: case OP65_TYA: /* If the branch is a beq, both A and Y are zero at the * branch target, otherwise they are zero at the next * insn. */ if (BC == BC_EQ) { E->RI->Out2.RegA = E->RI->Out2.RegY = 0; } else { E->RI->Out.RegA = E->RI->Out.RegY = 0; } break; default: break; } } } } while (!Done); }