public byte[] this[RegisterTable table, RegisterCapacity cap, XRegCode register] { // An easy way to fetch a register given its information. // Returns a byte[] of length $cap consisting of the bottom $cap bytes of $Registers[$table+$register] // Access to upper byte registers such as AH can be done artifically by fetching AX then using $AX[1] as the upper byte. get { byte[] Output = new byte[(int)cap]; for (int i = 0; i < Output.Length; i++) { Output[i] = Registers[(int)register + (int)table][i]; } return(Output); } set { // If the length of the input byte array is greater than the capacity, data would be lost. Something wrong here would most likely be on my part. if (value.Length > ((int)cap)) { throw new Exception("RegisterGroup.cs Attempt to overflow register in base class"); } // Overwrite the bytes in $Registers[] with $value[] for (int i = 0; i < value.Length; i++) { Registers[(int)register + (int)table][i] = value[i]; } } }
public SplitRegisterHandle(XRegCode lower, XRegCode upper, SplitRegisterHandleSettings settings = SplitRegisterHandleSettings.NONE) { // Create the handles for the two registers ready so they do not have to be created more than once. Upper = new ControlUnit.RegisterHandle(upper, RegisterTable.GP); Lower = new ControlUnit.RegisterHandle(lower, RegisterTable.GP); Settings = settings; }
public RegisterHandle(XRegCode registerCode, RegisterTable table, RegisterCapacity size = RegisterCapacity.NONE, RegisterHandleSettings settings = RegisterHandleSettings.NONE) { // A constructor for infering a register from a set of arguments. // Strictly this isnt done here, rather in the Fetch() and Set() methods Code = registerCode; Table = table; Settings = settings; // If the input register capacity is NONE(or there wasn't one passed in the arguments), do not initialise the size. // This means that attempting to use the register handle before it is initialised will consistently throw the same exception. if (size != RegisterCapacity.NONE) { Size = size; } // If $size was NONE, and the register handle has NO_INIT set, there would never be a possibility of the register handle being used, so throw an exception now. // This rounds down the problem a little more than a "variable not initialised" exception or alike, as it would be a typo or improper class usage. else if ((Settings | RegisterHandleSettings.NO_INIT) == Settings) { throw new System.Exception("Must be a possibility of register size initialising."); } }
public byte GetUpperByte(XRegCode reg) => Registers[(int)reg][1];
public StringOperation(string mnemonic, XRegCode destination, XRegCode source, StringOpSettings settings) { Settings = settings; // Determine capacity as well as an informal mnemonic convention. I haven't seen it defined anywhere, but // in many programs such as GDB and GCC, this is used/accepted. // BYTE => append "B" // WORD => append "W" // DWORD => append "D" // QWORD => append "Q" // E.g, // SCAS RAX, QWORD PTR [RSI] => SCASQ // CMPS BYTE PTR [RDI], BYTE PTR[RSI] => CMPSB // However in my program(as with numerous others), the operands will remain but // without BYTE PTR or equivalent. This does slightly contradict the purpose of // this convention, but I don't expect everyone using the program to know the // operands of every string operation off by heart(as each has a constant set of operands). if ((Settings | StringOpSettings.BYTEMODE) == Settings) { Capacity = RegisterCapacity.BYTE; mnemonic += 'B'; } else if ((ControlUnit.RexByte | REX.W) == ControlUnit.RexByte) { Capacity = RegisterCapacity.QWORD; mnemonic += 'Q'; } else if (ControlUnit.LPrefixBuffer.Contains(PrefixByte.SIZEOVR)) { Capacity = RegisterCapacity.WORD; mnemonic += 'W'; } else { Capacity = RegisterCapacity.DWORD; mnemonic += 'D'; } Mnemonic = mnemonic; // Determine and store the pointer size(There will always be at least one). E.g [RSI] or [ESI]. PtrSize = ControlUnit.LPrefixBuffer.Contains(PrefixByte.ADDROVR) ? RegisterCapacity.DWORD : RegisterCapacity.QWORD; // Create a handle to the destination. If the destination is DI, treat it as a pointer, as DI is always a pointer in a // string operation. destination == XRegCode.DI will also be checked later to mimic the same behaviour. Destination = new ControlUnit.RegisterHandle(destination, RegisterTable.GP, (destination == XRegCode.DI) ? PtrSize : Capacity); // Same as the above Source = new ControlUnit.RegisterHandle(source, RegisterTable.GP, (source == XRegCode.SI) ? PtrSize : Capacity); // Convert the two operands into pointers. These will only be used if their XRegCode is SI or DI, but stored regardless. // Saving these to a variable means that the registers themselves do not have to be operated on until the execution of // the opcode has finished. DestPtr = BitConverter.ToUInt64(Bitwise.ZeroExtend(Destination.FetchOnce(), 8), 0); SrcPtr = BitConverter.ToUInt64(Bitwise.ZeroExtend(Source.FetchOnce(), 8), 0); // Fetch and store the value operand. This will only be ever used if one operand is the A register. This is because // the value of the register is only needed to form the pointers above if the register is SI/DI. There can only // be one operand that is the A register, therefore only the value of that operand needs to be stored. If there // is no A register, SI will be stored in ValueOperand. ValueOperand = (Destination.Code == XRegCode.A) ? Destination.FetchAs(Capacity) : Source.FetchAs(Capacity); OnInitialise(); }