Imports System.Threading

'The MAIN Guide: http://docs.huihoo.com/help-pc/int.html
' http://www.delorie.com/djgpp/doc/rbinter/ix/

Partial Public Class x8086
    Public Sub HandleHardwareInterrupt(intNum As Byte)
        HandleInterrupt(intNum, True)
        mRegisters.IP = IPAddrOff
    End Sub

    Private Sub HandleInterrupt(intNum As Byte, isHard As Boolean)
        If intNum = &H13 AndAlso mEmulateINT13 Then 'OrElse intNum = &HFD Then
            HandleINT13()
        Else
            PushIntoStack(mFlags.EFlags)
            PushIntoStack(mRegisters.CS)

            If isHard Then
                PushIntoStack(mRegisters.IP)
            Else
                PushIntoStack(AddValues(mRegisters.IP, opCodeSize, DataSize.Word))
            End If

            Dim intOffset As Integer = intNum * 4
            IPAddrOff = RAM16(0, intOffset)
            mRegisters.CS = RAM16(0, intOffset + 2)
        End If

        mFlags.IF = 0
        mFlags.TF = 0
        trapEnabled = False
        mIsHalted = False

        'If intNum > &HF0 Then x8086.Notify("Interrupt: {0:X} : {1:X}", intNum, mRegisters.AH)

        clkCyc += 51
    End Sub

    Private Sub HandleINT13()
        If mFloppyController Is Nothing Then DiskAdapterNotFound()

        Dim ret As Integer

        ' Select floppy drive
        Dim dskImg As DiskImage = mFloppyController.DiskImage(mRegisters.DL)
        If dskImg Is Nothing Then
            x8086.Notify(String.Format("Get Drive Parameters: Drive {0} Not Ready", mRegisters.DL))

            'ret = &H180 ' no such drive
            ret = &H1AA ' fixed disk drive not ready
        Else
            Select Case mRegisters.AH
                Case &H0 ' reset drive
                    x8086.Notify("Drive {0} Reset", mRegisters.DL)

                    ret = 0

                Case &H1 ' get last operation status
                    x8086.Notify("Drive {0} Get Last Operation Status", mRegisters.DL)

                    ret = RAM8(&H40, &H41)
                    ret = ret << 8

                Case &H2  ' read sectors
                    Dim address As Integer = (mRegisters.ES << 4) + mRegisters.BX
                    Dim offset As Long = dskImg.LBA(mRegisters.CH, mRegisters.DH, mRegisters.CL)

                    If offset < 0 OrElse offset >= dskImg.FileLength Then
                        x8086.Notify(String.Format("Read Sectors: Drive {0} Seek Fail", mRegisters.DL))

                        ret = &H140 ' seek failed
                        Exit Select
                    End If

                    x8086.Notify("Drive {0} Read H{1:00} T{2:000} S{3:000} x {4:000} {5:000000} -> {6}:{7}",
                                                                                        mRegisters.DL,
                                                                                        mRegisters.DH,
                                                                                        mRegisters.CH,
                                                                                        mRegisters.CL,
                                                                                        mRegisters.AL,
                                                                                        offset.ToHex(DataSize.DWord).Replace("h", ""),
                                                                                        mRegisters.ES.ToHex(DataSize.Word).Replace("h", ""),
                                                                                        mRegisters.BX.ToHex(DataSize.Word).Replace("h", ""))

                    Dim buf(mRegisters.AL * dskImg.SectorSize - 1) As Byte
                    ret = dskImg.Read(offset, buf)
                    If ret = DiskImage.EIO Then
                        x8086.Notify("Read Sectors: Drive {0} CRC Error", mRegisters.DL)

                        ret = &H110 ' CRC error
                        Exit Select
                    ElseIf ret = DiskImage.EOF Then
                        x8086.Notify("Read Sectors: Drive {0} Sector Not Found", mRegisters.DL)

                        ret = &H104 ' sector not found
                        Exit Select
                    End If
                    CopyToRAM(buf, address)
                    ret = mRegisters.AL

                Case &H3 ' write sectors
                    If dskImg.IsReadOnly Then
                        x8086.Notify("Write Sectors: Drive {0} Failed / Read Only", mRegisters.DL)

                        ret = &H103 ' write protected
                        Exit Select
                    End If

                    Dim address As Integer = (mRegisters.ES << 4) + mRegisters.BX
                    Dim offset As Long = dskImg.LBA(mRegisters.CH, mRegisters.DH, mRegisters.CL)

                    If offset < 0 OrElse offset >= dskImg.FileLength Then
                        x8086.Notify("Write Sectors: Drive {0} Seek Failed", mRegisters.DL)

                        ret = &H140 ' seek failed
                        Exit Select
                    End If

                    x8086.Notify("Drive {0} Write H{1:00} T{2:000} S{3:000} x {4:000} {5:000000} -> {6}:{7}",
                                                                                        mRegisters.DL,
                                                                                        mRegisters.DH,
                                                                                        mRegisters.CH,
                                                                                        mRegisters.CL,
                                                                                        mRegisters.AL,
                                                                                        offset.ToHex(DataSize.DWord).Replace("h", ""),
                                                                                        mRegisters.ES.ToHex(DataSize.Word).Replace("h", ""),
                                                                                        mRegisters.BX.ToHex(DataSize.Word).Replace("h", ""))

                    Dim buf(mRegisters.AL * dskImg.SectorSize - 1) As Byte
                    ReadFromRAM(buf, address)
                    ret = dskImg.Write(offset, buf)
                    If ret = DiskImage.EIO Then
                        x8086.Notify("Write Sectors: Drive {0} CRC Error", mRegisters.DL)

                        ret = &H110 ' CRC error
                        Exit Select
                    ElseIf ret = DiskImage.EOF Then
                        x8086.Notify("Write Sectors: Drive {0} Sector Not Found", mRegisters.DL)

                        ret = &H104 ' sector not found
                        Exit Select
                    End If
                    ret = mRegisters.AL

                Case &H4, &H5
                    ret = 0

                Case &H8 ' get drive parameters
                    If dskImg.Tracks <= 0 Then
                        x8086.Notify("Get Drive Parameters: Drive {0} Unknown Geometry", mRegisters.DL)

                        ret = &H107
                    Else
                        mRegisters.CH = (dskImg.Cylinders - 1) And &HFF
                        mRegisters.CL = (dskImg.Sectors And 63)
                        mRegisters.CL = mRegisters.CL + (dskImg.Cylinders / 256) * 64
                        mRegisters.DH = dskImg.Heads - 1

                        If mRegisters.DL < &H80 Then
                            mRegisters.BL = 4
                            mRegisters.DL = 2
                        Else
                            'mRegisters.BL = 255
                            mRegisters.DL = DiskImage.HardDiskCount
                        End If

                        x8086.Notify("Drive {0} Get Parameters", mRegisters.DL)

                        ret = 0
                    End If

                    'Case &H15
                    'If mRegisters.DL < &H80 Then
                    '    If diskImage IsNot Nothing Then
                    '        ret = 100
                    '    Else
                    '        ret = &HFF00
                    '    End If
                    'Else
                    '    Dim n As Integer = diskImage.Sectors
                    '    mRegisters.CX = n / 256
                    '    mRegisters.DX = n And &HFF
                    '    ret = 300
                    'End If

                Case Else
                    x8086.Notify(String.Format("Drive {0} Unknown Request {1}", mRegisters.DL,
                                                                                ((mRegisters.AX And &HFF00) >> 8).ToHex(DataSize.Byte)))

                    ret = &H101
            End Select
        End If

        ' Store return status
        RAM8(&H40, &H41) = (ret >> 8) 'And &HFF
        mFlags.CF = If((ret And &HFF00) <> 0, 1, 0)

        If (mRegisters.DL And &H80) <> 0 Then Memory(&H474) = mRegisters.AH

        mRegisters.AX = ret
    End Sub
End Class
