import t, c


def cli():
    c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])

def sti():
    c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY])

def hlt():
    c.Asm("hlt", [t.ASM_DESCR.CLOBBER_MEMORY])

def nop():
    c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY])

def pause():
    c.Asm("pause", op=[t.ASM_DESCR.CLOBBER_MEMORY])

def inb(port: t.CUInt16T) -> t.CUInt8T:
    value: t.CUInt32T
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              in al, dx
              movzx eax, al""",
    out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
    op =[t.ASM_DESCR.CLOBBER_RDX])
    return t.CUInt8T(value)

def outb(port: t.CUInt16T, value: t.CUInt8T):
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)}
              out dx, al""",
    op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])


def inw(port: t.CUInt16T) -> t.CUInt16T:
    value: t.CUInt32T
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              in ax, dx
              movzx eax, ax""",
    out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
    op =[t.ASM_DESCR.CLOBBER_RDX])
    return t.CUInt16T(value)

def outw(port: t.CUInt16T, value: t.CUInt16T):
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)}
              out dx, ax""",
    op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])

def inl(port: t.CUInt16T) -> t.CUInt32T:
    value: t.CUInt32T
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              in eax, dx""",
    out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
    op =[t.ASM_DESCR.CLOBBER_RDX])
    return value

def outl(port: t.CUInt16T, value: t.CUInt32T):
    c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
              mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
              out dx, eax""",
    op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])

def io_wait():
    c.Asm(f"mov dx, 0x80; out dx, al",
    op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_DX])

def pushall() -> t.CInline | t.CVoid:
    c.Asm(f"""
        push rax
        push rbx
        push rcx
        push rdx
        push rsi
        push rdi
        push rbp
        push r8
        push r9
        push r10
        push r11
        push r12
        push r13
        push r14
        push r15""",
        [t.ASM_DESCR.CLOBBER_MEMORY]
    )

def popall() -> t.CInline | t.CVoid:
    c.Asm(f"""
        pop r15
        pop r14
        pop r13
        pop r12
        pop r11
        pop r10
        pop r9
        pop r8
        pop rbp
        pop rdi
        pop rsi
        pop rdx
        pop rcx
        pop rbx
        pop rax""",
        [t.ASM_DESCR.CLOBBER_MEMORY]
    )

def cpu_switch_context(old_stack: t.CUInt64T | t.CPtr, new_stack: t.CUInt64T):
    c.Asm(f"""
        push rax
        push rbx
        push rcx
        push rdx
        push rsi
        push rdi
        push rbp
        push r8
        push r9
        push r10
        push r11
        push r12
        push r13
        push r14
        push r15
        mov [{c.AsmInp(old_stack, t.ASM_DESCR.REG_ANY)}], rsp
        mov rsp, {c.AsmInp(new_stack, t.ASM_DESCR.REG_ANY)}
        pop r15
        pop r14
        pop r13
        pop r12
        pop r11
        pop r10
        pop r9
        pop r8
        pop rbp
        pop rdi
        pop rsi
        pop rdx
        pop rcx
        pop rbx
        pop rax""",
        op=[t.ASM_DESCR.CLOBBER_MEMORY])

def BSSClean():
    c.Asm(
        "lea rdi, [rip + __bss_start]\n"
        "lea rcx, [rip + __bss_end]\n"
        "sub rcx, rdi\n"
        "xor eax, eax\n"
        "cld\n"
        "rep stosb",
        op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX]
    )
