/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-09-15     QiuYi        The first version
 */

/**
 * @addtogroup I386
 */
/*@{*/

#define ENTRY(proc)\
    .align 2;\
    .globl proc;\
    .type proc,@function;\
    proc:
#define HDINTERRUPTFNC(name,num) \
    ENTRY(name)\
    pushl $(num);\
    jmp _hdinterrupts;\
    .data;\
    .long name;\
    .text

.globl hdinterrupt_func
    .data
    .align 4
    .type hdinterrupt_func,@object
    hdinterrupt_func :
.text

/* the external device interrupts */
HDINTERRUPTFNC(irq0, 0)
HDINTERRUPTFNC(irq1, 1)
HDINTERRUPTFNC(irq2, 2)
HDINTERRUPTFNC(irq3, 3)
HDINTERRUPTFNC(irq4, 4)
HDINTERRUPTFNC(irq5, 5)
HDINTERRUPTFNC(irq6, 6)
HDINTERRUPTFNC(irq7, 7)
HDINTERRUPTFNC(irq8, 8)
HDINTERRUPTFNC(irq9, 9)
HDINTERRUPTFNC(irq10, 10)
HDINTERRUPTFNC(irq11, 11)
HDINTERRUPTFNC(irq12, 12)
HDINTERRUPTFNC(irq13, 13)
HDINTERRUPTFNC(irq14, 14)
HDINTERRUPTFNC(irq15, 15)

.p2align 4,0x90
.globl _hdinterrupts
.type _hdinterrupts,@function
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_hw_isr
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread

_hdinterrupts:
    push %ds
    push %es
    pushal
    movw $0x10, %ax
    movw %ax, %ds
    movw %ax, %es
    pushl %esp

    call rt_interrupt_enter

    movl %esp, %eax       /* copy esp to eax */
    addl $0x2c, %eax      /* move to vector address */
    movl (%eax), %eax     /* vector(eax) = *eax */

    pushl %eax            /* push argument : int vector */
    call rt_hw_isr
    add $4, %esp          /* restore argument */

    call rt_interrupt_leave

    /* if rt_thread_switch_interrupt_flag set, jump to _interrupt_thread_switch and don't return */
    movl $rt_thread_switch_interrupt_flag, %eax
    movl (%eax), %ebx
    cmp $0x1, %ebx
    jz _interrupt_thread_switch

    popl %esp
    popal
    pop %es
    pop %ds
    add $4,%esp
    iret

_interrupt_thread_switch:
    popl %esp

    movl $0x0, %ebx
    movl %ebx, (%eax)

    movl $rt_interrupt_from_thread, %eax
    movl (%eax), %ebx
    movl %esp, (%ebx)

    movl $rt_interrupt_to_thread, %ecx
    movl (%ecx), %edx
    movl (%edx), %esp

    popal
    pop %es
    pop %ds
    add $4,%esp
    iret

/*@}*/
