I attached the output. My code for IN and OUT is this. Its C# and a little complex.
Emulate is called when those Instructions are ran.
IN:
Code: Select all
/// <summary>
/// The outline of a IN Opcode.
/// </summary>
public class IN : Opcode
{
/// <summary>
/// A new IN Opcode.
/// </summary>
/// <param name="value"></param>
/// <param name="bits16"></param>
public IN(Register.Type reg, ushort value, bool bits16)
{
base.Type = OpCodeType.Opcode_IN;
base.Operand1.Type = Operand.OperandType.Operand_Register;
base.Operand1.Value = (uint)reg;
if (bits16)
{
base.Operand2.Type = Operand.OperandType.Operand_Short;
}
else
{
base.Operand2.Type = Operand.OperandType.Operand_Byte;
}
base.Operand2.Value = value;
base.Supported = true;
base.EmulateCallback = Action.ConvertFromAction(Emulate);
}
/// <summary>
/// A new IN Opcode.
/// </summary>
/// <param name="reg"></param>
/// <param name="reg2"></param>
public IN(Register.Type reg, Register.Type reg2)
{
base.Type = OpCodeType.Opcode_IN;
base.Operand1.Type = Operand.OperandType.Operand_Register;
base.Operand1.Value = (uint)reg;
base.Operand2.Type = Operand.OperandType.Operand_Register;
base.Operand2.Value = (uint)reg2;
base.Supported = true;
base.EmulateCallback = Action.ConvertFromAction(Emulate);
}
/// <summary>
/// Emulates a IN Opcode.
/// </summary>
/// <param name="x8086"></param>
/// <param name="op"></param>
public void Emulate()
{
ushort port = Operand2.GetValue(this);
//Now see if the operand is a 8bit register or a 16bit register.
if (Operand1.IsWord())
{
ushort value = (ushort)Hardware.IOPort.Read_16((short)port);
Operand1.SetValue(value, this);
}
else
{
byte value = Hardware.IOPort.Read_8((short)port);
Operand1.SetValue(value, this);
}
}
}
OUT:
Code: Select all
/// <summary>
/// The outline of a OUT Opcode.
/// </summary>
public class OUT : Opcode
{
/// <summary>
/// A new OUT Opcode.
/// </summary>
/// <param name="value"></param>
/// <param name="bits16"></param>
/// <param name="reg"></param>
public OUT(ushort value, bool bits16, Register.Type reg)
{
base.Type = OpCodeType.Opcode_OUT;
if (bits16)
{
base.Operand1.Type = Operand.OperandType.Operand_Short;
}
else
{
base.Operand1.Type = Operand.OperandType.Operand_Byte;
}
base.Operand1.Value = value;
base.Operand2.Type = Operand.OperandType.Operand_Register;
base.Operand2.Value = (uint)reg;
base.Supported = true;
base.EmulateCallback = Action.ConvertFromAction(Emulate);
}
/// <summary>
/// A new OUT Opcode.
/// </summary>
/// <param name="reg"></param>
/// <param name="reg2"></param>
public OUT(Register.Type reg, Register.Type reg2)
{
base.Type = OpCodeType.Opcode_OUT;
base.Operand1.Type = Operand.OperandType.Operand_Register;
base.Operand1.Value = (uint)reg;
base.Operand2.Type = Operand.OperandType.Operand_Register;
base.Operand2.Value = (uint)reg2;
base.Supported = true;
base.EmulateCallback = Action.ConvertFromAction(Emulate);
}
/// <summary>
/// Emulates a OUT Opcode.
/// </summary>
/// <param name="x8086"></param>
/// <param name="op"></param>
public void Emulate()
{
ushort port = Operand1.GetValue(this);
ushort value = Operand2.GetValue(this);
if (Operand2.IsWord())
{
Hardware.IOPort.Write_16((short)port, (short)value);
}
else
{
Hardware.IOPort.Write_8((short)port, (byte)value);
}
}
}
Opcode
Code: Select all
/// <summary>
/// The class that outlines what a Opcode is.
/// This is used by the emulator a lot.
///
/// Opcodes look like this:
///
///[Prefix] Opcode [Address Mode] [Low Disp] [High Disp] [Low data] [High data]
///
/// Course this changes a lot. The best source for information on 8086 opcodes was here:
/// http://umcs.maine.edu/~cmeadow/courses/cos335/8086-instformat.pdf
/// </summary>
public class Opcode
{
/// <summary>
/// The different types of Opcodes.
/// </summary>
public enum OpCodeType
{
Opcode_Unknown,
Opcode_Mov,
Opcode_Pop,
Opcode_Push,
Opcode_Inc,
Opcode_Dec,
Opcode_Add,
Opcode_Sub,
Opcode_Cli,
Opcode_Sti,
Opcode_Std,
Opcode_Cld,
Opcode_Clc,
Opcode_Stc,
Opcode_Test,
Opcode_And,
Opcode_Or,
Opcode_Adc,
Opcode_Sbb,
Opcode_Daa,
Opcode_Das,
Opcode_Xor,
Opcode_AAA,
Opcode_Cmp,
Opcode_AAS,
Opcode_Pusha,
Opcode_Popa,
Opcode_Jo,
Opcode_Jno,
Opcode_Jb,
Opcode_Jnb,
Opcode_Jz,
Opcode_Jnz,
Opcode_Jbe,
Opcode_Ja,
Opcode_Js,
Opcode_Jns,
Opcode_Jpe,
Opcode_Jpo,
Opcode_Jl,
Opcode_Jge,
Opcode_Jle,
Opcode_Jg,
Opcode_XCHG,
Opcode_LEA,
Opcode_Nop,
Opcode_CBW,
Opcode_CWD,
Opcode_Call,
Opcode_Wait,
Opcode_Pushf,
Opcode_Popf,
Opcode_Sahf,
Opcode_Lahf,
Opcode_Movsb,
Opcode_Movsw,
Opcode_Cmpsb,
Opcode_Cmpsw,
Opcode_Stosb,
Opcode_Stosw,
Opcode_Lodsb,
Opcode_Lodsw,
Opcode_Ret,
Opcode_Retf,
Opcode_INT,
Opcode_IRET,
Opcode_IN,
Opcode_OUT,
Opcode_Jmp,
Opcode_Hlt,
Opcode_Rol,
Opcode_ROR,
Opcode_RCR,
Opcode_SHL,
Opcode_SHR,
Opcode_SAR,
Opcode_RCL,
Opcode_NOT,
Opcode_NEG,
Opcode_MUL,
Opcode_IMUL,
Opcode_DIV,
Opcode_IDIV,
};
/// <summary>
/// The different displacement registers for certain opcodes.
/// </summary>
public enum OpDisp
{
SI,
DI,
BP,
BX,
BX_PLUS_SI,
BP_PLUS_SI,
BX_PLUS_DI,
BP_PLUS_DI,
None,
}
/// <summary>
/// The Opcode Prefixes Availible.
///
/// If no Segment Prefix, the defualt segment DS is used.
/// If the BP register is used the defualt will be SS rather than DS.
/// A segment prefix will override that condition as well.
/// </summary>
public enum OpcodePrefix
{
Prefix_OperandSizeOverride = 0x66,
Prefix_AddressSizeOverride = 0x67,
Prefix_Lock = 0xF0,
Prefix_SegmentOverride_CS = 0x2E,
Prefix_SegmentOverride_DS = 0x3E,
Prefix_SegmentOverride_ES = 0x26,
Prefix_SegmentOverride_SS = 0x36,
Prefix_Repetition_REPREPEREPZ = 0xF3,
Prefix_Repetition_REPNEREPNZ = 0xF2,
Prefix_None = 0,
};
/// <summary>
/// The type of Opcode this is
/// </summary>
public OpCodeType Type = OpCodeType.Opcode_Unknown;
/// <summary>
/// The Opcodes defualt segment to use.
/// </summary>
public Register.Type Segment = Register.Type.DS;
/// <summary>
/// Operand1 of the Opcode.
/// </summary>
public Operand Operand1 = new Operand();
/// <summary>
/// Operand2 of the Opcode.
/// </summary>
public Operand Operand2 = new Operand();
/// <summary>
/// The Opcode's Prefix.
/// </summary>
public OpcodePrefix Prefix = OpcodePrefix.Prefix_None;
/// <summary>
/// The Opcodes Displacement. This is by defualt None.
/// </summary>
public OpDisp Displacement = OpDisp.None;
/// <summary>
/// Whether or not this Opcode is supported.
/// </summary>
public bool Supported = false;
/// <summary>
/// The Emultion address used for Calling the Opcodes Emulation method.
/// </summary>
public uint EmulateCallback;
/// <summary>
/// The CPU That his Opcode belongs to.
/// </summary>
public CPU x8086;
/// <summary>
/// Called when a Opcode has been created.
/// </summary>
public Opcode()
{
((Object)(object)this).DestroyEvent.Attach(Destroy);
}
/// <summary>
/// Called when we need to destroy the Opcode.
/// </summary>
private void Destroy()
{
//We just have to destroy our objects and thats it.
Object.Destroy(Operand1);
Object.Destroy(Operand2);
}
/// <summary>
/// Returns a String That Represents this Opcode.
/// </summary>
/// <returns></returns>
public string GetString()
{
string str = ConvertOpcode(this.Type);
((String)(object)str).AddByte((byte)' ');
//Print out the prefix
str = String.Append(str, ConvertPrefix(this.Prefix), true);
((String)(object)str).AddByte((byte)' ');
//Now print out Operand 1's Data.
str = String.Append(str, Operand1.GetString(this), true);
//Now print a ,
((String)(object)str).AddByte((byte)',');
//Now print our Operand 2's Data.
str = String.Append(str, Operand2.GetString(this), true);
//Return our string.
return str;
}
/// <summary>
/// Converts a OpcodeType to a string.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static string ConvertOpcode(OpCodeType type)
{
switch (type)
{
case OpCodeType.Opcode_AAA:
return "AAA";
case OpCodeType.Opcode_AAS:
return "AAS";
case OpCodeType.Opcode_Adc:
return "ADC";
case OpCodeType.Opcode_Add:
return "ADD";
case OpCodeType.Opcode_And:
return "AND";
case OpCodeType.Opcode_Call:
return "CALL";
case OpCodeType.Opcode_CBW:
return "CBW";
case OpCodeType.Opcode_Clc:
return "CLC";
case OpCodeType.Opcode_Cld:
return "CLD";
case OpCodeType.Opcode_Cli:
return "CLI";
case OpCodeType.Opcode_Cmp:
return "CMP";
case OpCodeType.Opcode_Cmpsb:
return "CMPSB";
case OpCodeType.Opcode_Cmpsw:
return "CMPSW";
case OpCodeType.Opcode_CWD:
return "CWD";
case OpCodeType.Opcode_Daa:
return "DAA";
case OpCodeType.Opcode_Das:
return "DAS";
case OpCodeType.Opcode_Dec:
return "DEC";
case OpCodeType.Opcode_DIV:
return "DIV";
case OpCodeType.Opcode_Hlt:
return "HLT";
case OpCodeType.Opcode_IDIV:
return "IDIV";
case OpCodeType.Opcode_IMUL:
return "IMUL";
case OpCodeType.Opcode_IN:
return "IN";
case OpCodeType.Opcode_Inc:
return "INC";
case OpCodeType.Opcode_INT:
return "INT";
case OpCodeType.Opcode_IRET:
return "IRET";
case OpCodeType.Opcode_Ja:
return "JA";
case OpCodeType.Opcode_Jb:
return "JB";
case OpCodeType.Opcode_Jbe:
return "JBE";
case OpCodeType.Opcode_Jg:
return "JG";
case OpCodeType.Opcode_Jge:
return "JGE";
case OpCodeType.Opcode_Jl:
return "JL";
case OpCodeType.Opcode_Jle:
return "JLE";
case OpCodeType.Opcode_Jmp:
return "JMP";
case OpCodeType.Opcode_Jnb:
return "JNB";
case OpCodeType.Opcode_Jno:
return "JNO";
case OpCodeType.Opcode_Jns:
return "JNS";
case OpCodeType.Opcode_Jnz:
return "JNZ";
case OpCodeType.Opcode_Jo:
return "JO";
case OpCodeType.Opcode_Jpe:
return "JPE";
case OpCodeType.Opcode_Jpo:
return "JPO";
case OpCodeType.Opcode_Js:
return "JS";
case OpCodeType.Opcode_Jz:
return "JZ";
case OpCodeType.Opcode_Lahf:
return "LAHF";
case OpCodeType.Opcode_LEA:
return "LEA";
case OpCodeType.Opcode_Lodsb:
return "LODSB";
case OpCodeType.Opcode_Lodsw:
return "LODSW";
case OpCodeType.Opcode_Mov:
return "MOV";
case OpCodeType.Opcode_Movsb:
return "MOVSB";
case OpCodeType.Opcode_Movsw:
return "MOVSW";
case OpCodeType.Opcode_MUL:
return "MUL";
case OpCodeType.Opcode_NEG:
return "NEG";
case OpCodeType.Opcode_Nop:
return "NOP";
case OpCodeType.Opcode_NOT:
return "NOT";
case OpCodeType.Opcode_Or:
return "OR";
case OpCodeType.Opcode_OUT:
return "OUT";
case OpCodeType.Opcode_Pop:
return "POP";
case OpCodeType.Opcode_Popa:
return "POPA";
case OpCodeType.Opcode_Popf:
return "POPF";
case OpCodeType.Opcode_Push:
return "PUSH";
case OpCodeType.Opcode_Pusha:
return "PUSHA";
case OpCodeType.Opcode_Pushf:
return "PUSHF";
case OpCodeType.Opcode_RCL:
return "RCL";
case OpCodeType.Opcode_RCR:
return "RCR";
case OpCodeType.Opcode_Ret:
return "RET";
case OpCodeType.Opcode_Retf:
return "RETF";
case OpCodeType.Opcode_Rol:
return "ROL";
case OpCodeType.Opcode_ROR:
return "ROR";
case OpCodeType.Opcode_Sahf:
return "SAHF";
case OpCodeType.Opcode_SAR:
return "SAR";
case OpCodeType.Opcode_Sbb:
return "SBB";
case OpCodeType.Opcode_SHL:
return "SHL";
case OpCodeType.Opcode_SHR:
return "SHR";
case OpCodeType.Opcode_Stc:
return "STC";
case OpCodeType.Opcode_Std:
return "STD";
case OpCodeType.Opcode_Sti:
return "STI";
case OpCodeType.Opcode_Stosb:
return "STOSB";
case OpCodeType.Opcode_Stosw:
return "STOSW";
case OpCodeType.Opcode_Sub:
return "SUB";
case OpCodeType.Opcode_Test:
return "TEST";
case OpCodeType.Opcode_Unknown:
return "Unkown";
case OpCodeType.Opcode_Wait:
return "WAIT";
case OpCodeType.Opcode_XCHG:
return "XCHG";
case OpCodeType.Opcode_Xor:
return "XOR";
}
//Bad if we reach here.
return "Invalid Opcode";
}
/// <summary>
/// Converts a Register Type to a string.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static string ConvertRegister(Register.Type type)
{
switch (type)
{
case Register.Type.AH:
return "AH";
case Register.Type.AL:
return "AL";
case Register.Type.AX:
return "AX";
case Register.Type.BH:
return "BH";
case Register.Type.BL:
return "BL";
case Register.Type.BP:
return "BP";
case Register.Type.BX:
return "BX";
case Register.Type.CH:
return "CH";
case Register.Type.CL:
return "CL";
case Register.Type.CS:
return "CS";
case Register.Type.CX:
return "CX";
case Register.Type.DH:
return "DH";
case Register.Type.DI:
return "DI";
case Register.Type.DL:
return "DL";
case Register.Type.DS:
return "DS";
case Register.Type.DX:
return "DX";
case Register.Type.ES:
return "ES";
case Register.Type.None:
return "None";
case Register.Type.SI:
return "SI";
case Register.Type.SP:
return "SP";
case Register.Type.SS:
return "SS";
}
return "Unkown";
}
/// <summary>
/// Converts a Operand Type to a string.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static string ConvertOperandType(Operand.OperandType type)
{
switch (type)
{
case Operand.OperandType.Operand_Byte:
return "Byte";
case Operand.OperandType.Operand_Byte_Memory_Byte:
return "Byte";
case Operand.OperandType.Operand_Byte_Memory_Short:
return "Byte";
case Operand.OperandType.Operand_Register:
return "Register";
case Operand.OperandType.Operand_Short:
return "Short";
case Operand.OperandType.Operand_Short_Memory_Short:
return "Short";
case Operand.OperandType.Operand_Short_Memory_Byte:
return "Short";
case Operand.OperandType.Operand_Unkown:
return "Unkown";
}
return "Unkown";
}
/// <summary>
/// Convets a Prefix Type to a string.
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
public static string ConvertPrefix(Opcode.OpcodePrefix prefix)
{
switch (prefix)
{
case OpcodePrefix.Prefix_Lock:
return "Lock";
}
return "";
}
/// <summary>
/// Converts a Opcode Displacement to a String.
/// </summary>
/// <param name="disp"></param>
/// <returns></returns>
public static string ConvertDisplacement(OpDisp disp)
{
switch (disp)
{
case OpDisp.BP:
return "BP";
case OpDisp.BP_PLUS_DI:
return "BP+DI";
case OpDisp.BP_PLUS_SI:
return "BP+SI";
case OpDisp.BX:
return "BX";
case OpDisp.BX_PLUS_DI:
return "BX+DI";
case OpDisp.BX_PLUS_SI:
return "BX+SI";
case OpDisp.DI:
return "DI";
case OpDisp.None:
return "";
case OpDisp.SI:
return "SI";
}
return "";
}
/// <summary>
/// Returns whether or not the Opcode is a word. (Used by some opcodes)
/// </summary>
/// <returns></returns>
public bool IsWord()
{
if (Operand1.Type == Operand.OperandType.Operand_Register && Register.IsWord((Register.Type)Operand1.Value))
{
return true;
}
else if (Operand1.Type == Operand.OperandType.Operand_Short)
{
return true;
}
else if (Operand1.Type == Operand.OperandType.Operand_Short_Memory_Short)
{
return true;
}
else if (Operand1.Type == Operand.OperandType.Operand_Short_Memory_Byte)
{
return true;
}
else if (Operand2.Type == Operand.OperandType.Operand_Register && Register.IsWord((Register.Type)Operand2.Value))
{
return true;
}
else if (Operand2.Type == Operand.OperandType.Operand_Short)
{
return true;
}
else if (Operand2.Type == Operand.OperandType.Operand_Short_Memory_Byte)
{
return true;
}
else if (Operand2.Type == Operand.OperandType.Operand_Short_Memory_Short)
{
return true;
}
else
{
return false;
}
}
}
Operand:
Code: Select all
/// <summary>
/// A Operand is basically a parameter passed with a Opcode.
/// </summary>
public class Operand
{
/// <summary>
/// The Operand Types Availible
/// </summary>
public enum OperandType
{
Operand_Unkown,
Operand_Register,
Operand_Byte,
Operand_Byte_Memory_Byte,
Operand_Byte_Memory_Short,
Operand_Short,
Operand_Short_Memory_Byte,
Operand_Short_Memory_Short,
};
/// <summary>
/// The type of Operand this is.
/// </summary>
public OperandType Type = OperandType.Operand_Unkown;
/// <summary>
/// The Value of the Operand.
/// </summary>
public uint Value = 0;
/// <summary>
/// Returns the value for a Operand whether its a Register, a Immediate byte, or a byte in Memory.
/// </summary>
/// <param name="x8086"></param>
/// <returns></returns>
public ushort GetValue(Opcode op)
{
#region " Gets Offset "
uint offset = 0;
if (op.Displacement != Opcode.OpDisp.None)
{
switch (op.Displacement)
{
case Opcode.OpDisp.BP:
offset = op.x8086.GetRegister(Register.Type.BP);
break;
case Opcode.OpDisp.BP_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BP_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.BX:
offset = op.x8086.GetRegister(Register.Type.BX);
break;
case Opcode.OpDisp.BX_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BX_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.DI:
offset = op.x8086.GetRegister(Register.Type.DI);
break;
case Opcode.OpDisp.SI:
offset = op.x8086.GetRegister(Register.Type.SI);
break;
}
}
#endregion
//Get the value.
uint address = (ushort)this.Value;
//Now check a few things.
if (this.Type == OperandType.Operand_Register)
{
return (ushort)op.x8086.GetRegister((Register.Type)this.Value);
}
else if (this.Type == OperandType.Operand_Byte || this.Type == OperandType.Operand_Short)
{
return (ushort)this.Value;
}
else if (this.Type == OperandType.Operand_Byte_Memory_Byte || this.Type == OperandType.Operand_Short_Memory_Byte)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80));
}
}
}
else if (this.Type == OperandType.Operand_Byte_Memory_Short || this.Type == OperandType.Operand_Short_Memory_Short)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
}
}
}
else
{
return 0;
}
//Check for General Protection Fault.
if (this.IsWord())
{
if (((address + 2) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
else
{
if (((address + 1) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
//If we get here it means were working with memory so lets calculate our address here.
uint segment = 0;
//See if we have a prefix.
if (op.Prefix != Opcode.OpcodePrefix.Prefix_None)
{
switch (op.Prefix)
{
case Opcode.OpcodePrefix.Prefix_SegmentOverride_CS:
//We have to use CS.
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_DS:
//We have to use DS.
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_ES:
//We have to use ES.
segment = (uint)(op.x8086.Extra_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_SS:
//We have to use SS.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
else
{
//Now if were using BP as a displacement then we have to use SS rather than DS.
if (op.Displacement == Opcode.OpDisp.BP || op.Displacement == Opcode.OpDisp.BP_PLUS_DI || op.Displacement == Opcode.OpDisp.BP_PLUS_SI)
{
//Use ss as the segment.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
}
else
{
//Use the segment the opcode specifies.
switch (op.Segment)
{
case Register.Type.CS:
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Register.Type.DS:
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Register.Type.SS:
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
}
//Now just return what we want based on the Memory.
switch (this.Type)
{
case OperandType.Operand_Byte_Memory_Byte:
return (ushort)op.x8086.GetMemoryByte((uint)(segment + (address & 0xFFFF)));
case OperandType.Operand_Byte_Memory_Short:
return (ushort)op.x8086.GetMemoryByte((uint)(segment + (address & 0xFFFF)));
case OperandType.Operand_Short_Memory_Byte:
return (ushort)op.x8086.GetMemoryWord((uint)(segment + (address & 0xFFFF)));
case OperandType.Operand_Short_Memory_Short:
return (ushort)op.x8086.GetMemoryWord((uint)(segment + (address & 0xFFFF)));
}
//Otherwise return 0.
return 0;
}
/// <summary>
/// Returns the value for a Operand whether its a Register, a Immediate byte, or a byte in Memory.
/// </summary>
/// <param name="x8086"></param>
/// <returns></returns>
public ushort GetSegAddress(Opcode op)
{
#region " Gets Offset "
uint offset = 0;
if (op.Displacement != Opcode.OpDisp.None)
{
switch (op.Displacement)
{
case Opcode.OpDisp.BP:
offset = op.x8086.GetRegister(Register.Type.BP);
break;
case Opcode.OpDisp.BP_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BP_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.BX:
offset = op.x8086.GetRegister(Register.Type.BX);
break;
case Opcode.OpDisp.BX_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BX_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.DI:
offset = op.x8086.GetRegister(Register.Type.DI);
break;
case Opcode.OpDisp.SI:
offset = op.x8086.GetRegister(Register.Type.SI);
break;
}
}
#endregion
//Get the value.
uint address = (ushort)this.Value;
//Now check a few things.
if (this.Type == OperandType.Operand_Byte_Memory_Byte || this.Type == OperandType.Operand_Short_Memory_Byte)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80));
}
}
}
else if (this.Type == OperandType.Operand_Byte_Memory_Short || this.Type == OperandType.Operand_Short_Memory_Short)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
}
}
}
else
{
return 0;
}
//Check for General Protection Fault.
if (this.IsWord())
{
if (((address + 2) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
else
{
if (((address + 1) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
//If we get here it means were working with memory so lets calculate our address here.
uint segment = 0;
//See if we have a prefix.
if (op.Prefix != Opcode.OpcodePrefix.Prefix_None)
{
switch (op.Prefix)
{
case Opcode.OpcodePrefix.Prefix_SegmentOverride_CS:
//We have to use CS.
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_DS:
//We have to use DS.
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_ES:
//We have to use ES.
segment = (uint)(op.x8086.Extra_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_SS:
//We have to use SS.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
else
{
//Now if were using BP as a displacement then we have to use SS rather than DS.
if (op.Displacement == Opcode.OpDisp.BP || op.Displacement == Opcode.OpDisp.BP_PLUS_DI || op.Displacement == Opcode.OpDisp.BP_PLUS_SI)
{
//Use ss as the segment.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
}
else
{
//Use the segment the opcode specifies.
switch (op.Segment)
{
case Register.Type.CS:
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Register.Type.DS:
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Register.Type.SS:
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
}
//Now just return what we want based on the Memory.
uint physical = (uint)(segment + (address & 0xFFFF));
return (ushort)(physical - segment);
}
/// <summary>
/// Sets a Value into the Operand whether its a register or memory this will do the real thing.
/// </summary>
/// <param name="x8086"></param>
/// <param name="value"></param>
public void SetValue(ushort value, Opcode op)
{
#region " Gets Offset "
uint offset = 0;
if (op.Displacement != Opcode.OpDisp.None)
{
switch (op.Displacement)
{
case Opcode.OpDisp.BP:
offset = op.x8086.GetRegister(Register.Type.BP);
break;
case Opcode.OpDisp.BP_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BP_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BP) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.BX:
offset = op.x8086.GetRegister(Register.Type.BX);
break;
case Opcode.OpDisp.BX_PLUS_DI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.DI));
break;
case Opcode.OpDisp.BX_PLUS_SI:
offset = (ushort)(op.x8086.GetRegister(Register.Type.BX) + op.x8086.GetRegister(Register.Type.SI));
break;
case Opcode.OpDisp.DI:
offset = op.x8086.GetRegister(Register.Type.DI);
break;
case Opcode.OpDisp.SI:
offset = op.x8086.GetRegister(Register.Type.SI);
break;
}
}
#endregion
//Get the address
uint address = (ushort)this.Value;
//Now check a few things.
if (this.Type == OperandType.Operand_Register)
{
//Just set the value into the appropriate register.
op.x8086.SetRegister((Register.Type)this.Value, value);
//Just return
return;
}
else if (this.Type == OperandType.Operand_Byte_Memory_Byte || this.Type == OperandType.Operand_Short_Memory_Byte)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x80)
{
//Negative.
address = (uint)(0x80 - (address - 0x80)); ;
}
}
}
else if (this.Type == OperandType.Operand_Byte_Memory_Short || this.Type == OperandType.Operand_Short_Memory_Short)
{
//Check for a displacement.
if (op.Displacement != Opcode.OpDisp.None)
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
//Now we take the offset and subtract the value from it.
address = (uint)(offset - address);
}
else
{
//Positive.
//So we simply add the offset.
address = (uint)(address + offset);
}
}
else
{
//Now we need to check for a negative.
if (address >= 0x8000)
{
//Negative.
address = (uint)(0x8000 - (address - 0x8000));
}
}
}
else
{
//We return because this isn't right.
return;
}
//Check for general protection fault.
if (this.IsWord())
{
if (((address + 2) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
else
{
if (((address + 1) & 0xFFFF) > 0xFFFF)
{
Console.WriteLine("General Protection Fault!");
Console.ReadLine();
}
}
//If we get here it means were working with memory so lets calculate our address here.
uint segment = 0;
//See if we have a prefix.
if (op.Prefix != Opcode.OpcodePrefix.Prefix_None)
{
switch (op.Prefix)
{
case Opcode.OpcodePrefix.Prefix_SegmentOverride_CS:
//We have to use CS.
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_DS:
//We have to use DS.
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_ES:
//We have to use ES.
segment = (uint)(op.x8086.Extra_Seg.Low16 * 0x10);
break;
case Opcode.OpcodePrefix.Prefix_SegmentOverride_SS:
//We have to use SS.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
else
{
//Now if were using BP as a displacement then we have to use SS rather than DS.
if (op.Displacement == Opcode.OpDisp.BP || op.Displacement == Opcode.OpDisp.BP_PLUS_DI || op.Displacement == Opcode.OpDisp.BP_PLUS_SI)
{
//Use ss as the segment.
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
}
else
{
//Use the segment the opcode specifies.
switch (op.Segment)
{
case Register.Type.CS:
segment = (uint)(op.x8086.Code_Seg.Low16 * 0x10);
break;
case Register.Type.DS:
segment = (uint)(op.x8086.Data_Seg.Low16 * 0x10);
break;
case Register.Type.SS:
segment = (uint)(op.x8086.Stack_Seg.Low16 * 0x10);
break;
}
}
}
//Now just return what we want based on the Memory.
switch (this.Type)
{
case OperandType.Operand_Byte_Memory_Byte:
op.x8086.SetMemoryByte((uint)(segment + (address & 0xFFFF)), (byte)value);
break;
case OperandType.Operand_Byte_Memory_Short:
op.x8086.SetMemoryByte((uint)(segment + (address & 0xFFFF)), (byte)value);
break;
case OperandType.Operand_Short_Memory_Byte:
op.x8086.SetMemoryWord((uint)(segment + (address & 0xFFFF)), (ushort)value);
break;
case OperandType.Operand_Short_Memory_Short:
op.x8086.SetMemoryWord((uint)(segment + (address & 0xFFFF)), (ushort)value);
break;
}
}
/// <summary>
/// Returns whether or not this opcode is a word.
/// </summary>
/// <returns></returns>
public bool IsWord()
{
if (this.Type == Operand.OperandType.Operand_Register && Register.IsWord((Register.Type)this.Value))
{
return true;
}
else if (this.Type == Operand.OperandType.Operand_Short)
{
return true;
}
else if (this.Type == Operand.OperandType.Operand_Short_Memory_Short)
{
return true;
}
else if (this.Type == Operand.OperandType.Operand_Short_Memory_Byte)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// Returns a string representing this opcode.
/// </summary>
/// <returns></returns>
public string GetString(Opcode op)
{
if (this.Type == OperandType.Operand_Unkown)
{
return "";
}
else
{
string str = Opcode.ConvertOperandType(this.Type);
((String)(object)str).AddByte((byte)' ');
if (this.Type == OperandType.Operand_Register)
{
str = String.Append(str, Opcode.ConvertRegister((Register.Type)this.Value), true);
}
else if (this.Type == OperandType.Operand_Byte || this.Type == OperandType.Operand_Short)
{
str = String.Append(str, Integer.ToHex(this.Value, 4), true);
}
else
{
((String)(object)str).AddByte((byte)'[');
if (op.Displacement != Opcode.OpDisp.None)
{
str = String.Append(str, Opcode.ConvertDisplacement(op.Displacement), true);
}
((String)(object)str).AddByte((byte)' ');
if (this.Type == OperandType.Operand_Short_Memory_Byte || this.Type == OperandType.Operand_Byte_Memory_Byte)
{
str = String.Append(str, "Byte", true);
}
else
{
str = String.Append(str, "Short", true);
}
((String)(object)str).AddByte((byte)' ');
str = String.Append(str, Integer.ToHex(this.Value, 4), true);
((String)(object)str).AddByte((byte)']');
}
return str;
}
}
}
I think I did it right, but maybe not.
Thanks a ton, Matt