Partial Public Class x8086
    Public Enum SelPrm
        First = 0
        Second = 1
        Thrid = 2
    End Enum

    Public Enum DataSize
        UseAddressingMode = -1
        [Byte] = 0
        Word = 1
        DWord = 2
    End Enum

    Public Enum Operation
        Add
        AddWithCarry
        Substract
        SubstractWithCarry
        LogicOr
        LogicAnd
        LogicXor
        Increment
        Decrement
        Compare
        Test
        Unknown
    End Enum

    Private Structure AddressingMode
        Public Direction As Byte
        Public Size As DataSize
        Public Modifier As Byte
        Public Rm As Byte
        Public Reg As Byte
        Public Register1 As GPRegisters.RegistersTypes
        Public Register2 As GPRegisters.RegistersTypes
        Public IsDirect As Boolean
        Public IndAdr As Integer    ' Indirect Address
        Public IndMem As Integer    ' Indirect Memory Contents

        Public Sub Decode(data As Byte, addressingModeByte As Byte)
            Direction = (data And &H2) >> 1 '                      (00000010)
            Size = data And &H1 '                                  (00000001)

            Modifier = addressingModeByte >> 6 '                   (11000000)
            Reg = (addressingModeByte And &H38) >> 3 '             (00111000)
            Rm = addressingModeByte And &H7 '                      (00000111)

            Register1 = CType(Reg Or (Size << 3), GPRegisters.RegistersTypes)
            If Register1 > GPRegisters.RegistersTypes.BX Then Register1 += (GPRegisters.RegistersTypes.BX + 1)

            Register2 = CType(Rm Or (Size << 3), GPRegisters.RegistersTypes)
            If Register2 > GPRegisters.RegistersTypes.BX Then Register2 += (GPRegisters.RegistersTypes.BX + 1)
        End Sub
    End Structure

    Private parityLUT() As Byte = {
        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
    }

    Private Sub SetRegister1(data As Byte)
        addrMode.Register1 = CType((data And &H7) Or shl3, GPRegisters.RegistersTypes)
        If addrMode.Register1 > GPRegisters.RegistersTypes.BX Then addrMode.Register1 += GPRegisters.RegistersTypes.ES
    End Sub

    Private Sub SetRegister2(data As Byte)
        data = (data And &H38) >> 3
        If data < &H4 Then
            addrMode.Register2 = (data + GPRegisters.RegistersTypes.ES) Mod GPRegisters.RegistersTypes.DI
        Else
            ' Shouldn't happen!
            data = data And &H3
            addrMode.Register2 = CType(data, GPRegisters.RegistersTypes)
        End If
    End Sub

    Private Sub SetAddressing(Optional forceSize As DataSize = DataSize.UseAddressingMode)
        addrMode.Decode(opCode, ParamNOPS(SelPrm.First, , DataSize.Byte))

        If forceSize <> DataSize.UseAddressingMode Then addrMode.Size = forceSize

        If (Not mRegisters.ActiveSegmentChanged) AndAlso (addrMode.Modifier <> &H3) AndAlso (addrMode.Rm = 2 OrElse addrMode.Rm = 3 OrElse (addrMode.Rm = 6 AndAlso addrMode.Modifier <> 0)) Then
            mRegisters.ActiveSegmentRegister = GPRegisters.RegistersTypes.SS
            clkCyc += 2
        End If

        ' http://umcs.maine.edu/~cmeadow/courses/cos335/Asm07-MachineLanguage.pdf
        ' http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH04/CH04-2.html#HEADING2-35
        Select Case addrMode.Modifier
            Case 0 ' 00
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : clkCyc += 5                                            ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : clkCyc += 5                                            ' 101 [DI]
                    Case 6                                                                                            ' 110 Direct Addressing
                        addrMode.IndAdr = ParamNOPS(SelPrm.First, 2, DataSize.Word)
                        opCodeSize += 2
                        clkCyc += 9
                    Case 7 : addrMode.IndAdr = mRegisters.BX : clkCyc += 5                                                 ' 111 [BX]
                End Select
                addrMode.IndMem = RAMn

            Case 1 ' 01 - 8bit
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : clkCyc += 5                                            ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : clkCyc += 5                                            ' 101 [DI]
                    Case 6 : addrMode.IndAdr = mRegisters.BP : clkCyc += 5                                            ' 110 [BP]
                    Case 7 : addrMode.IndAdr = mRegisters.BX : clkCyc += 5                                            ' 111 [BX]
                End Select

                addrMode.IndAdr = AddValues(addrMode.IndAdr, To16bitsWithSign(ParamNOPS(SelPrm.First, 2, DataSize.Byte)), DataSize.Word)
                addrMode.IndMem = RAMn
                opCodeSize += 1

            Case 2 ' 10 - 16bit
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : clkCyc += 5                                            ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : clkCyc += 5                                            ' 101 [DI]
                    Case 6 : addrMode.IndAdr = mRegisters.BP : clkCyc += 5                                            ' 110 [BP]
                    Case 7 : addrMode.IndAdr = mRegisters.BX : clkCyc += 5                                            ' 111 [BX]
                End Select

                addrMode.IndAdr = AddValues(addrMode.IndAdr, ParamNOPS(SelPrm.First, 2, DataSize.Word), DataSize.Word)
                addrMode.IndMem = RAMn
                opCodeSize += 2

            Case 3 ' 11
                addrMode.IsDirect = True

        End Select
        opCodeSize += 1
    End Sub

    Private Function To16bitsWithSign(v As Integer) As Integer
        If (v And &H80) <> 0 Then
            Return &HFF00 Or (v And &HFF)
        Else
            Return v
        End If
    End Function

    Private Sub SetDecoderAddressing(Optional forceSize As DataSize = DataSize.UseAddressingMode)
        addrMode.Decode(decOpCode, ParamNOPS(SelPrm.First, , DataSize.Byte))

        If forceSize <> DataSize.UseAddressingMode Then addrMode.Size = forceSize

        If (Not mRegisters.ActiveSegmentChanged) AndAlso (addrMode.Modifier <> &H3) AndAlso (addrMode.Rm = 2 OrElse addrMode.Rm = 3 OrElse (addrMode.Rm = 6 And addrMode.Modifier <> 0)) Then
            mRegisters.ActiveSegmentRegister = GPRegisters.RegistersTypes.SS
            clkCyc += 2
        End If

        ' http://umcs.maine.edu/~cmeadow/courses/cos335/Asm07-MachineLanguage.pdf
        ' http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH04/CH04-2.html#HEADING2-35
        Select Case addrMode.Modifier
            Case 0 ' 00
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : indASM = "[BX + SI]" : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : indASM = "[BX + DI]" : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : indASM = "[BP + SI]" : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : indASM = "[BP + DI]" : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : indASM = "[SI]" : clkCyc += 5                                                 ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : indASM = "[DI]" : clkCyc += 5                                                 ' 101 [DI]
                    Case 6                                                                                                              ' 110 Direct Addressing
                        addrMode.IndAdr = ParamNOPS(SelPrm.First, 2, DataSize.Word)
                        indASM = "[" + ToHex(ParamNOPS(SelPrm.First, 2, DataSize.Word), DataSize.Word) + "]"
                        opCodeSize += 2
                        clkCyc += 9
                    Case 7 : addrMode.IndAdr = mRegisters.BX : indASM = "[BX]" : clkCyc += 5                                                 ' 111 [BX]
                End Select
                If addrMode.Size = DataSize.Byte Then
                    addrMode.IndMem = RAM8(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                Else
                    addrMode.IndMem = RAM16(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                End If
            Case 1 ' 01 - 8bit
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : indASM = "[BX + SI]" : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : indASM = "[BX + DI]" : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : indASM = "[BP + SI]" : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : indASM = "[BP + DI]" : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : indASM = "[SI]" : clkCyc += 5                                                 ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : indASM = "[DI]" : clkCyc += 5                                                 ' 101 [DI]
                    Case 6 : addrMode.IndAdr = mRegisters.BP : indASM = "[BP]" : clkCyc += 5                                                 ' 110 [BP]
                    Case 7 : addrMode.IndAdr = mRegisters.BX : indASM = "[BX]" : clkCyc += 5                                                 ' 111 [BX]
                End Select

                Dim p As Byte = ParamNOPS(SelPrm.First, 2, DataSize.Byte)
                Dim s As Integer
                If p > &H80 Then
                    p = &H100 - p
                    s = -1
                Else
                    s = 1
                End If
                indASM += IIf(s = -1, " - ", " + ") + p.ToHex()
                addrMode.IndAdr = AddValues(addrMode.IndAdr, s * p, DataSize.Word)
                If addrMode.Size = DataSize.Byte Then
                    addrMode.IndMem = RAM8(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                Else
                    addrMode.IndMem = RAM16(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                End If
                opCodeSize += 1
            Case 2 ' 10 - 16bit
                addrMode.IsDirect = False
                Select Case addrMode.Rm
                    Case 0 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.SI, DataSize.Word) : indASM = "[BX + SI]" : clkCyc += 7 ' 000 [BX+SI]
                    Case 1 : addrMode.IndAdr = AddValues(mRegisters.BX, mRegisters.DI, DataSize.Word) : indASM = "[BX + DI]" : clkCyc += 8 ' 001 [BX+DI]
                    Case 2 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.SI, DataSize.Word) : indASM = "[BP + SI]" : clkCyc += 8 ' 010 [BP+SI]
                    Case 3 : addrMode.IndAdr = AddValues(mRegisters.BP, mRegisters.DI, DataSize.Word) : indASM = "[BP + DI]" : clkCyc += 7 ' 011 [BP+DI]
                    Case 4 : addrMode.IndAdr = mRegisters.SI : indASM = "[SI]" : clkCyc += 5                                                 ' 100 [SI]
                    Case 5 : addrMode.IndAdr = mRegisters.DI : indASM = "[DI]" : clkCyc += 5                                                 ' 101 [DI]
                    Case 6 : addrMode.IndAdr = mRegisters.BP : indASM = "[BP]" : clkCyc += 5                                                 ' 110 [BP]
                    Case 7 : addrMode.IndAdr = mRegisters.BX : indASM = "[BX]" : clkCyc += 5                                                 ' 111 [BX]
                End Select

                indASM += " + " + ParamNOPS(SelPrm.First, 2, DataSize.Word).ToHex(DataSize.Word)
                addrMode.IndAdr = AddValues(addrMode.IndAdr, ParamNOPS(SelPrm.First, 2, DataSize.Word), DataSize.Word)
                If addrMode.Size = DataSize.Byte Then
                    addrMode.IndMem = RAM8(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                Else
                    addrMode.IndMem = RAM16(mRegisters.ActiveSegmentValue, addrMode.IndAdr)
                End If
                opCodeSize += 2
            Case 3 ' 11
                addrMode.IsDirect = True
        End Select
        opCodeSize += 1
    End Sub

    Private Sub SendToPort(portAddress As Integer, value As Integer)
        For Each p In mPorts
            If p.ValidPortAddress.Contains(portAddress) Then
                p.Out(portAddress, value)
                'x8086.Notify(String.Format("Write {0} to Port {1} on Adapter ({2})", value.ToHex(DataSize.Byte).TrimEnd("h"), portAddress.ToHex(DataSize.Word).TrimEnd("h"), p.Name))
                'FlushCycles()
                Exit Sub
            End If
        Next

        For Each a In mAdapters
            If a.ValidPortAddress.Contains(portAddress) Then
                a.Out(portAddress, value)
                'x8086.Notify(String.Format("Write {0} to Port {1} on Adapter ({2})", value.ToHex(DataSize.Byte).TrimEnd("h"), portAddress.ToHex(DataSize.Word).TrimEnd("h"), a.Name))
                'FlushCycles()
                Exit Sub
            End If
        Next

        NoIOPort(portAddress)
    End Sub

    Private Function ReceiveFromPort(portAddress As Integer) As Integer
        For Each p In mPorts
            If p.ValidPortAddress.Contains(portAddress) Then
                'x8086.Notify(String.Format("Read From Port {0} on Adapter ({1})", portAddress.ToHex(DataSize.Word).TrimEnd("h"), p.Name))
                FlushCycles()
                Return p.In(portAddress)
            End If
        Next

        For Each a In mAdapters
            If a.ValidPortAddress.Contains(portAddress) Then
                'x8086.Notify(String.Format("Read From Port {0} on Adapter ({1})", portAddress.ToHex(DataSize.Word).TrimEnd("h"), a.Name))
                FlushCycles()
                Return a.In(portAddress)
            End If
        Next

        NoIOPort(portAddress)

        Return &HFF
    End Function

    Private ReadOnly Property Param(index As SelPrm, Optional ipOffset As Integer = 1, Optional size As DataSize = DataSize.UseAddressingMode) As Integer
        Get
            If size = DataSize.UseAddressingMode Then size = addrMode.Size

            If size = DataSize.Byte Then
                opCodeSize += 1
                Return RAM8(mRegisters.CS, AddValues(mRegisters.IP, ipOffset + index, DataSize.Word))
            Else
                If mRegisters.IP Mod 2 <> 0 Then clkCyc += 4
                opCodeSize += 2
                Return RAM16(mRegisters.CS, AddValues(mRegisters.IP, ipOffset + index * 2, DataSize.Word))
            End If
        End Get
    End Property

    Private ReadOnly Property ParamNOPS(index As SelPrm, Optional ipOffset As Integer = 1, Optional size As DataSize = DataSize.UseAddressingMode) As Integer
        Get
            If size = DataSize.UseAddressingMode Then size = addrMode.Size

            If size = DataSize.Byte Then
                Return RAM8(mRegisters.CS, AddValues(mRegisters.IP, ipOffset + index, DataSize.Word))
            Else
                Return RAM16(mRegisters.CS, AddValues(mRegisters.IP, ipOffset + index * 2, DataSize.Word))
            End If
        End Get
    End Property

    Public Sub IncIP(value As Integer)
        mRegisters.IP = AddValues(mRegisters.IP, value, DataSize.Word)
    End Sub

    Private Function OffsetIP(paramSize As DataSize) As Integer
        Dim value As Integer = Param(SelPrm.First, , paramSize)

        If paramSize = DataSize.Byte Then value = To16bitsWithSign(value)

        Return AddValues(mRegisters.IP, value + opCodeSize, DataSize.Word)

        'Return AddValues(
        '        AddValues(mRegisters.IP,
        '            AddValues(
        '                AddValues(value, -65536, DataSize.Word), 1, DataSize.Word),
        '            DataSize.Word),
        '        opCodeSize - 1, DataSize.Word)
    End Function

    Public Function AddValues(b1 As Integer, b2 As Integer, size As DataSize) As Integer
        If size = DataSize.Byte Then
            Return (b1 + b2) And &HFF
        Else
            Return (b1 + b2) And &HFFFF
        End If
    End Function

    Private Function DoOper(b1 As Integer, b2 As Integer, Optional size As DataSize = DataSize.UseAddressingMode, Optional opMode As Operation = Operation.Unknown) As Integer
        If size = DataSize.UseAddressingMode Then size = addrMode.Size

        Dim result As Integer
        Select Case opMode
            Case Operation.Add
                result = b1 + b2
                SetAddSubFlags(result, b1, b2, size)

            Case Operation.AddWithCarry
                result = b1 + b2 + mFlags.CF
                SetAddSubFlags(result, b1, b2 + mFlags.CF, size)

            Case Operation.Substract, Operation.Compare
                result = b1 - b2
                SetAddSubFlags(result, b1, -b2, size)

            Case Operation.SubstractWithCarry
                result = b1 - b2 - mFlags.CF
                SetAddSubFlags(result, b1, -b2 - mFlags.CF, size)

            Case Operation.LogicOr
                result = b1 Or b2
                SetLogicFlags(result, size)

            Case Operation.LogicAnd, Operation.Test
                result = b1 And b2
                SetLogicFlags(result, size)

            Case Operation.LogicXor
                result = b1 Xor b2
                SetLogicFlags(result, size)

            Case Operation.Increment
                result = b1 + b2
                Dim cf = mFlags.CF
                SetAddSubFlags(result, b1, b2, size)
                mFlags.CF = cf

            Case Operation.Decrement
                result = b1 - b2
                Dim cf = mFlags.CF
                SetAddSubFlags(result, b1, -b2, size)
                mFlags.CF = cf
        End Select

        If size = DataSize.Byte Then
            Return result And &HFF
        Else
            Return result And &HFFFF
        End If
    End Function

    Private Sub SetSZPFlags(result As Integer, size As DataSize)
        mFlags.PF = parityLUT(result And &HFF)

        Select Case size
            Case DataSize.Byte
                mFlags.ZF = If((result And &HFF) = 0, 1, 0)
                mFlags.SF = If((result And &H80) = 0, 0, 1)
            Case DataSize.Word
                mFlags.ZF = If((result And &HFFFF) = 0, 1, 0)
                mFlags.SF = If((result And &H8000) = 0, 0, 1)
        End Select
    End Sub

    Private Sub SetLogicFlags(result As Integer, size As DataSize)
        SetSZPFlags(result, size)

        mFlags.CF = 0
        mFlags.OF = 0
    End Sub

    Private Sub SetAddSubFlags(result As Integer, v1 As Integer, v2 As Integer, size As DataSize)
        SetSZPFlags(result, size)

        Dim m1 As Integer
        Dim m2 As Integer
        If size = DataSize.Byte Then
            m1 = &HFF00
            m2 = &H80
        Else
            m1 = &HFFFF0000
            m2 = &H8000
        End If

        mFlags.CF = If((result And m1) = 0, 0, 1)
        mFlags.OF = If(((result Xor v1) And (result Xor v2) And m2) = 0, 0, 1)
        mFlags.AF = If(((v1 Xor v2 Xor result) And &H10) = 0, 0, 1)
    End Sub

    Public Shared Function BitsArrayToWord(b() As Boolean) As Integer
        Dim r As Integer = 0
        For i As Integer = 0 To b.Length - 1
            r += If(b(i), 1, 0) * 2 ^ i
        Next
        Return r
    End Function

    Public Shared Function WordToBitsArray(value As Integer, size As Byte) As Boolean()
        Dim b(size - 1) As Boolean
        For i As Integer = 0 To size - 1
            b(i) = (value And 2 ^ i) <> 0
        Next
        Return b
    End Function

    Protected Friend Sub SetUpAdapter(adapter As Adapter)
        adapter.Emulator = Me
        Select Case adapter.Type
            Case adapter.AdapterType.Keyboard
                mKeyboard = adapter
            Case adapter.AdapterType.Video
                Try
                    mVideoAdapter = adapter
                Catch ex As Exception
                    Stop
                End Try
            Case x8086NetEmu.Adapter.AdapterType.Floppy
                mFloppyController = adapter
        End Select
    End Sub

    'Private Sub PrintStack()
    '    For i = &HFFFE To mRegisters.SP Step -2
    '        x8086.Notify(String.Format("{0}: {1}", i.ToString("X").PadLeft(4, "0"), RAM16(mRegisters.SS, i).ToString("X").PadLeft(4, "0")))
    '    Next
    'End Sub

    Private Sub PrintOpCodes(n As Integer)
        For i As Integer = mRegisters.IP To mRegisters.IP + n - 1
            Debug.Write(RAM8(mRegisters.CS, i).ToHex() + " ")
        Next
    End Sub

    Private Sub PrintRegisters()
        x8086.Notify(String.Format("AX: {0}   SP: {1} ", mRegisters.AX.ToHex(DataSize.Word), mRegisters.SP.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("BX: {0}   DI: {1} ", mRegisters.BX.ToHex(DataSize.Word), mRegisters.DI.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("CX: {0}   BP: {1} ", mRegisters.CX.ToHex(DataSize.Word), mRegisters.BP.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("DX: {0}   SI: {1} ", mRegisters.DX.ToHex(DataSize.Word), mRegisters.SI.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("ES: {0}   CS: {1} ", mRegisters.ES.ToHex(DataSize.Word), mRegisters.CS.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("SS: {0}   DS: {1} ", mRegisters.SS.ToHex(DataSize.Word), mRegisters.DS.ToHex(DataSize.Word)))
        x8086.Notify(String.Format("IP: {0} FLGS: {1}{2}{3}{4}{5}{6}{7}{8}", mRegisters.IP.ToHex(DataSize.Word),
                                                        mFlags.CF,
                                                        mFlags.ZF,
                                                        mFlags.SF,
                                                        mFlags.OF,
                                                        mFlags.PF,
                                                        mFlags.AF,
                                                        mFlags.IF,
                                                        mFlags.DF))
        x8086.Notify("                CZSOPAID")
        For i As Integer = 0 To 3
            Debug.Write(RAM8(mRegisters.CS, mRegisters.IP + i).ToHex().TrimEnd("h") + " ")
        Next
    End Sub

    Private Sub PrintFlags()
        x8086.Notify(String.Format("{0}{1}{2}{3}{4}{5}{6}{7}",
                                                        mFlags.CF,
                                                        mFlags.ZF,
                                                        mFlags.SF,
                                                        mFlags.OF,
                                                        mFlags.PF,
                                                        mFlags.AF,
                                                        mFlags.IF,
                                                        mFlags.DF))
        x8086.Notify("CZSOPAID")
    End Sub

    Private Sub PrintStack()
        Dim f As Integer = Math.Min(mRegisters.SP + (&HFFFF - mRegisters.SP) - 1, mRegisters.SP + 10)
        Dim t As Integer = Math.Max(0, mRegisters.SP - 10)

        For i = f To t Step -2
            x8086.Notify("{0}:{1}  {2}{3}", mRegisters.SS.ToHex(DataSize.Word),
                                              i.ToHex(DataSize.Word),
                                              RAM16(mRegisters.SS, i).ToHex(DataSize.Word),
                                              IIf(i = mRegisters.SP, "<<", ""))
        Next
    End Sub
End Class
