;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISASSEMBLER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; TODO: prepare to work independently from debugger

;-----------------------------------------------------------------------------
;                      Read next byte for disassembly
;
; out: AL = byte
disasm_get_byte:
        push    ecx
        mov     ecx, [disasm_cur_pos]
        sub     ecx, [disasm_start_pos]
        cmp     ecx, [disasm_buf_size]
        jae     disasm_err
        mov     al, [disasm_buffer+ecx]
        pop     ecx
        inc     [disasm_cur_pos]
        ret

;-----------------------------------------------------------------------------
;                      Read next word for disassembly
;
; out: AX = word
disasm_get_word:
        push    ecx
        mov     ecx, [disasm_cur_pos]
        sub     ecx, [disasm_start_pos]
        inc     ecx
        cmp     ecx, [disasm_buf_size]
        jae     disasm_err
        mov     ax, word [disasm_buffer-1+ecx]
        pop     ecx
        add     [disasm_cur_pos], 2
        ret

;-----------------------------------------------------------------------------
;                     Read next dword for disassembly
;
; out: EAX = dword
disasm_get_dword:
        push    ecx
        mov     ecx, [disasm_cur_pos]
        sub     ecx, [disasm_start_pos]
        add     ecx, 3
        cmp     ecx, [disasm_buf_size]
        jae     disasm_err
        mov     eax, dword [disasm_buffer-3+ecx]
        pop     ecx
        add     [disasm_cur_pos], 4
        ret

;-----------------------------------------------------------------------------

disasm_err:
        mov     esp, ebp

; TODO: make it local?
stc_ret:
        stc
        ret

;-----------------------------------------------------------------------------
;                       Exit from disassembly loop

disasm_ret:
        mov     esp, ebp
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------
;                       Disassembly one instruction
;
; Read data, in loop, to read multibyte instruction opcodes

disasm_instr:
        mov     ebp, esp
        cmp     [debuggee_pid], 0
        jz      stc_ret
        mov     edi, disasm_string
        xor     ecx, ecx

; TODO: make it local?
; ecx=flags (IN or OUT?)
disasm_loop1:
        xor     eax, eax
        call    disasm_get_byte
        jmp     dword [disasm_table_1 + eax*4]

;-----------------------------------------------------------------------------

cop0:
clock:
csegcs:
csegds:
cseges:
csegss:
csegfs:
cseggs:
        mov     esi, cmd1

iglobal
cmd1:
        db      0x2E,3,'cs:'
        db      0x36,3,'ss:'
        db      0x3E,3,'ds:'
        db      0x26,3,'es:'
        db      0x64,3,'fs:'
        db      0x65,3,'gs:'
        db      0x06,10,'push    es'
        db      0x07,10,'pop     es'
        db      0x0E,10,'push    cs'
        db      0x16,10,'push    ss'
        db      0x17,10,'pop     ss'
        db      0x1E,10,'push    ds'
        db      0x1F,10,'pop     ds'
        db      0x27,3,'daa'
        db      0x2F,3,'das'
        db      0x37,3,'aaa'
        db      0x3F,3,'aas'
        db      0x60,6,0,'pusha'
        db      0x61,5,0,'popa'
        db      0x90,3,'nop'
        db      0x9B,5,'fwait'
        db      0x9C,6,0,'pushf'
        db      0x9D,5,0,'popf'
        db      0x9E,4,'sahf'
        db      0x9F,4,'lahf'
        db      0xA4,5,'movsb'
        db      0xA5,5,0,'movs'
        db      0xA6,5,'cmpsb'
        db      0xA7,5,0,'cmps'
        db      0xAA,5,'stosb'
        db      0xAB,5,0,'stos'
        db      0xAC,5,'lodsb'
        db      0xAD,5,0,'lods'
        db      0xAE,5,'scasb'
        db      0xAF,5,0,'scas'
        db      0xC3,3,'ret'
        db      0xC9,5,'leave'
        db      0xCC,4,'int3'
        db      0xF0,4,'lock'
        db      0xF5,3,'cmc'
        db      0xF8,3,'clc'
        db      0xF9,3,'stc'
        db      0xFA,3,'cli'
        db      0xFB,3,'sti'
        db      0xFC,3,'cld'
        db      0xFD,3,'std'

cmd2:
        db      0x05,7,'syscall'
        db      0x06,4,'clts'
        db      0x31,5,'rdtsc'
        db      0x34,8,'sysenter'
        db      0xA2,5,'cpuid'
        db      0x77,4,'emms'

endg
        jmp     @f

;-----------------------------------------------------------------------------

ccpuid:
crdtsc:
cemms:
cop0_F:
        mov     esi, cmd2

    @@:
        cmp     al, [esi]
        jz      .found
        inc     esi
        movzx   edx, byte [esi]
        inc     esi
        add     esi, edx
        jmp     @b

    .found:
        inc     esi
        lodsb
        cmp     byte [esi], 0
        jz      @f
        movzx   ecx, al

    disasm_1:
        rep movsb
        and     byte [edi], 0
        ret

    @@:
        mov     dl, ch
        movzx   ecx, al
        dec     ecx
        inc     esi
        rep movsb
        test    dl, 1
        mov     al, 'w'
        jnz     @f
        mov     al, 'd'

    @@:
        stosb
        and     byte [edi], 0
        ret

    c67:
        or      ch, 2
        jmp     disasm_loop1

    c66:
        or      ch, 1
        jmp     disasm_loop1

;-----------------------------------------------------------------------------

cxlat:
cunk:
cerr:
        mov     eax, '???'
        stosd
        clc
        ret

cF:
        call    disasm_get_byte
        jmp     dword [disasm_table_2 + eax*4]

;-----------------------------------------------------------------------------
;                        Parse operand prefixes

crep:
        push    [disasm_cur_pos]
        call    disasm_get_byte
        cmp     al, 0x0F
        jz      .sse
        mov     dl, al
        mov     eax, 'rep '
        stosd
        mov     al, dl

    @@:
        and     eax, not 1
        cmp     al, 0x66
        jnz     @f
        call    disasm_get_byte
        mov     dl, al
        jmp     @b

    @@:
        cmp     al, 0xA6
        jz      .repz
        cmp     al, 0xAE
        jz      .repz
        cmp     al, 0xA4
        jz      .prefix
        cmp     al, 0xAA
        jz      .prefix
        cmp     al, 0xAC
        jz      .prefix
        cmp     al, 0x6C
        jz      .prefix
        cmp     al, 0x6E
        jz      .prefix

    .noprefix:
        pop     [disasm_cur_pos]
        and     byte [edi-1], 0
        ret

    .repz:
        mov     byte [edi-1], 'z'
        mov     al, ' '
        stosb

    .prefix:
        pop     [disasm_cur_pos]
        jmp     disasm_loop1

    .sse:
        pop     eax
        call    disasm_get_byte

;-----------------------------------------------------------------------------

iglobal
rep_sse_cmds:
        db      0x58,3,'add'
        db      0xC2,3,'cmp'
        db      0,0
endg
        mov     esi, rep_sse_cmds+1

    @@:
        movzx   edx, byte [esi]
        cmp     al, [esi-1]
        jz      @f
        lea     esi, [esi+edx+2]
        cmp     byte [esi], 0
        jnz     @b
        sub     [disasm_cur_pos], 2
        mov     eax, 'rep'
        stosd
        ret

    @@:
        push    ecx
        mov     ecx, edx
        inc     esi
        rep movsb
        pop     ecx
        mov     al, 's'
        stosb
        jmp     rep_sse_final

;-----------------------------------------------------------------------------

crepnz:
        call    disasm_get_byte
        cmp     al, 0x0F
        jz      .sse
        mov     dl, al
        mov     eax, 'repn'
        stosd
        mov     al, 'z'
        stosb
        mov     al, ' '
        stosb
        movzx   eax, dl
        cmp     al, 0x6C
        jb      crep.noprefix
        cmp     al, 0x6F
        jbe     .prefix
        cmp     al, 0xA4
        jb      crep.noprefix
        cmp     al, 0xA7
        jbe     .prefix
        cmp     al, 0xAA
        jb      crep.noprefix
        cmp     al, 0xAF
        ja      crep.noprefix

    .prefix:
        jmp     cop0

    .sse:
        call    disasm_get_byte
        mov     esi, rep_sse_cmds+1

    @@:
        movzx   edx, byte [esi]
        cmp     al, [esi-1]
        jz      .found0
        lea     esi, [esi+edx+2]
        cmp     byte [esi], 0
        jnz     @b
        mov     esi, sse_cmds2+1

    @@:
        movzx   edx, byte [esi]
        cmp     al, [esi-1]
        jz      .found1
        lea     esi, [esi+edx+2]
        cmp     byte [esi], 0
        jnz     @b
        sub     [disasm_cur_pos], 2
        mov     eax, 'repn'
        stosd
        mov     al, 'z'
        stosb
        and     byte [edi], 0
        ret

    .found0:
        push    ecx
        mov     ecx, edx
        inc     esi
        rep movsb
        pop     ecx
        mov     al, 's'
        stosb
        mov     al, 'd'
        jmp     rep_sse_final

    .found1:
        push    ecx
        mov     ecx, edx
        inc     esi
        rep movsb
        pop     ecx
        mov     al, 'p'
        stosb
        mov     al, 's'

    rep_sse_final:
        stosb
        push    ecx
        push    5
        pop     ecx
        sub     ecx, edx
        adc     ecx, 1
        mov     al, ' '
        rep stosb
        pop     ecx
        or      ch, 1
        jmp     disasm_mmx1

;-----------------------------------------------------------------------------

macro disasm_set_modew
{
        test    al, 1
        jz      @f
        or      ch, 80h
    @@:
}

;-----------------------------------------------------------------------------

cmov2:
        disasm_set_modew
    ; mov r/m,i
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        test    al, 00111000b
        jnz     cunk
        mov     eax, 'mov '
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        xor     eax, eax
        test    ch, 80h
        jnz     .1
        call    disasm_get_byte
        jmp     .3

    .1:
        test    ch, 1
        jnz     .2
        call    disasm_get_dword
        jmp     .3

    .2:
        call    disasm_get_word

    .3:
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cret2:
        mov     eax, 'ret '
        stosd
        mov     eax, '    '
        stosd
        xor     eax, eax
        jmp     cmov2.2

;-----------------------------------------------------------------------------

disasm_write_num:
        push    esi
        cmp     eax, 0x80
        jl      .nosymb
        lea     esi, [eax-1]
        test    eax, esi
        jz      .nosymb
        call    find_symbol
        jc      .nosymb

    @@:
        lodsb
        test    al, al
        jz      @f
        stosb
        jmp     @b

    @@:
        pop     esi
        ret

    .nosymb:
        pop     esi
        push    ecx eax
        inc     edi

    @@:
        mov     ecx, eax
        shr     eax, 4
        jz      @f
        inc     edi
        jmp     @b

    @@:
        pop     eax
        cmp     ecx, 10
        jb      @f
        inc     edi

    @@:
        push    edi eax

    @@:
        mov     ecx, eax
        and     al, 0xF
        cmp     al, 10
        sbb     al, 69h
        das
        dec     edi
        mov     [edi], al
        mov     eax, ecx
        shr     eax, 4
        jnz     @b
        cmp     ecx, 10
        jb      @f
        mov     byte [edi-1], '0'

    @@:
        pop     eax edi ecx
        cmp     eax, 10
        jb      @f
        mov     byte [edi], 'h'
        inc     edi

    @@:
        ret

;-----------------------------------------------------------------------------

iglobal
label disasm_regs32 dword
label disasm_regs dword
        db      'eax',0
        db      'ecx',0
        db      'edx',0
        db      'ebx',0
        db      'esp',0
        db      'ebp',0
        db      'esi',0
        db      'edi',0

disasm_regs16   dw      'ax','cx','dx','bx','sp','bp','si','di'
disasm_regs8    dw      'al','cl','dl','bl','ah','ch','dh','bh'
disasm_scale    db      '1248'
endg

;-----------------------------------------------------------------------------

disasm_readrmop:
        call    disasm_get_byte
        test    ch, 40h
        jnz     .skip_size
        push    eax
        and     al, 0xC0
        cmp     al, 0xC0
        pop     eax
        jz      .skip_size
        test    ch, 80h
        jz      .byte
        test    ch, 1
        jnz     .word
        mov     dword [edi], 'dwor'
        mov     byte [edi+4], 'd'
        inc     edi
        jmp     @f

    .byte:
        test    ch, 20h
        jz      .qb
        mov     byte [edi], 't'
        inc     edi

    .qb:
        mov     dword [edi], 'byte'
        jmp     @f

    .word:
        test    ch, 20h
        jz      .qw
        mov     byte [edi], 'q'
        inc     edi

    .qw:
        mov     dword [edi], 'word'

    @@:
        mov     byte [edi+4], ' '
        add     edi, 5

    .skip_size:
        test    ch, 2
        jnz     disasm_readrmop16
        push    ecx
        movzx   ecx, al
        and     eax, 7
        shr     ecx, 6
        jz      .vmod0
        jp      .vmod3
        mov     byte [edi], '['
        inc     edi
        cmp     al, 4
        jz      .sib1
        mov     eax, [disasm_regs+eax*4]
        stosd
        dec     edi
        jmp     @f

    .sib1:
        call    .parse_sib

    @@:
        mov     al, '+'
        stosb
        dec     ecx
        jz      .vmod1
        call    disasm_get_dword
        jmp     @f

    .vmod1:
        call    disasm_get_byte
        movsx   eax, al

    @@:
        test    eax, eax
        jns     .2
        neg     eax
        mov     byte [edi-1], '-'

    .2:
        call    disasm_write_num

    .2a:
        mov     al, ']'
        stosb
        pop     ecx
        ret

    .vmod3:
        pop     ecx
        test    ch, 10h
        jnz     .vmod3_mmi
        test    ch, 80h
        jz      .vmod3_byte
        test    ch, 1
        jnz     .vmod3_word
        test    ch, 20h
        jnz     .vmod3_sti
        mov     eax, [disasm_regs32+eax*4]
        stosd
        dec     edi
        ret

    .vmod3_byte:
        mov     ax, [disasm_regs8+eax*2]

    @@:
        stosw
        ret

    .vmod3_word:
        mov     ax, [disasm_regs16+eax*2]
        jmp     @b

    .vmod3_sti:
        mov     word [edi], 'st'
        add     al, '0'
        mov     byte [edi+2], al
        add     edi, 3
        ret

    .vmod3_mmi:
    
    disasm_write_mmreg = $

        test    ch, 1
        jz      @f
        mov     byte [edi], 'x'
        inc     edi

    @@:
        mov     word [edi], 'mm'
        add     al, '0'
        mov     byte [edi+2], al
        add     edi, 3
        ret

    .vmod0:
        mov     byte [edi], '['
        inc     edi
        cmp     al, 4
        jz      .sib2
        cmp     al, 5
        jz      .ofs32
        mov     eax, [disasm_regs+eax*4]
        stosd
        mov     byte [edi-1], ']'
        pop     ecx
        ret

    .ofs32:
        call    disasm_get_dword
        jmp     .2

    .sib2:
        call    .parse_sib
        mov     al, ']'
        stosb
        pop     ecx
        ret

    .parse_sib:
        call    disasm_get_byte
        push    edx
        mov     dl, al
        mov     dh, 0
        and     eax, 7
        cmp     al, 5
        jnz     @f
        jecxz   .sib0

    @@:
        mov     eax, [disasm_regs+eax*4]
        stosd
        dec     edi
        mov     dh, 1

    .sib0:
        mov     al, dl
        shr     eax, 3
        and     eax, 7
        cmp     al, 4
        jz      .sibret
        test    dh, dh
        jz      @f
        mov     byte [edi], '+'
        inc     edi

    @@:
        mov     eax, [disasm_regs+eax*4]
        stosd
        dec     edi
        shr     dl, 6
        jz      @f
        mov     al, '*'
        stosb
        movzx   eax, dl
        mov     al, [disasm_scale+eax]
        stosb

    @@:
    .sibret:
        test    dh, dh
        jnz     .sibret2
        call    disasm_get_dword
        cmp     byte [edi-1], '['
        jz      @f
        mov     byte [edi], '+'
        test    eax, eax
        jns     .sibns
        neg     eax
        mov     byte [edi], '-'

    .sibns:
        inc     edi

    @@:
        call    disasm_write_num

    .sibret2:
        pop     edx
        ret

;-----------------------------------------------------------------------------

iglobal
disasm_rm16_1   dd      'bxsi','bxdi','bpsi','bpdi'
disasm_rm16_2   dw      'si','di','bp','bx'
endg

;-----------------------------------------------------------------------------

disasm_readrmop16:
        push    ecx
        movzx   ecx, al
        and     eax, 7
        shr     ecx, 6
        jz      .vmod0
        jp      disasm_readrmop.vmod3   ; mod=3 is the same in 16- and 32-bit code
    ; 1 or 2
        mov     byte [edi], '['
        inc     edi
        cmp     al, 4
        jae     @f
        mov     eax, [disasm_rm16_1+eax*4]
        stosw
        mov     al, '+'
        stosb
        shr     eax, 16
        jmp     .1

    @@:
        mov     eax, dword [disasm_rm16_2+eax*2-4*2]

    .1:
        stosw
        mov     al, '+'
        stosb
        xor     eax, eax
        dec     ecx
        jnz     .2
        call    disasm_get_byte
        cbw
        jmp     @f

    .2:
        call    disasm_get_word

    @@:
        test    ax, ax
        jns     @f
        mov     byte [edi-1], '-'
        neg     ax

    @@:
        call    disasm_write_num

    .done1:
        mov     al, ']'
        stosb
        pop     ecx
        ret

    .vmod0:
        mov     byte [edi], '['
        inc     edi
        cmp     al, 6
        jz      .ofs16
        cmp     al, 4
        jae     @f
        mov     eax, [disasm_rm16_1+eax*4]
        stosw
        mov     al, '+'
        stosb
        shr     eax, 16
        jmp     .3

    @@:
        mov     eax, dword [disasm_rm16_2+eax*2-4*2]

    .3:
        stosw
        jmp     .done1

    .ofs16:
        xor     eax, eax
        call    disasm_get_word
        call    disasm_write_num
        jmp     .done1

;-----------------------------------------------------------------------------

cpush21:
        mov     eax, 'push'
        stosd
        mov     eax, '    '
        stosd

disasm_i32:
        call    disasm_get_dword
        call    disasm_write_num
        and     byte [edi], 0
        ret

cpush22:
        mov     eax, 'push'
        stosd
        mov     eax, '    '
        stosd
        call    disasm_get_byte
        movsx   eax, al

    @@:
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

center:
        mov     eax, 'ente'
        stosd
        mov     eax, 'r   '
        stosd
        xor     eax, eax
        call    disasm_get_word
        call    disasm_write_num
        mov     al, ','
        stosb
        mov     al, ' '
        stosb
        xor     eax, eax
        call    disasm_get_byte
        jmp     @b

;-----------------------------------------------------------------------------

cinc1:
; inc reg32
cdec1:
; dec reg32
cpush1:
; push reg32
cpop1:
; pop reg32
cbswap:
; bswap reg32
        mov     edx, eax
        and     edx, 7
        shr     eax, 3
        sub     al, 8
        mov     esi, 'inc '
        jz      @f
        mov     esi, 'dec '
        dec     al
        jz      @f
        mov     esi, 'push'
        dec     al
        jz      @f
        mov     esi, 'pop '
        dec     al
        jz      @f
        mov     esi, 'bswa'

    @@:
        xchg    eax, esi
        stosd
        mov     eax, '    '
        jz      @f
        mov     al, 'p'

    @@:
        stosd
        xchg    eax, edx
        call    disasm_write_reg1632
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cxchg1:
; xchg eax,reg32
        and     eax, 7
        xchg    eax, edx
        mov     eax, 'xchg'
        stosd
        mov     eax, '    '
        stosd
        xor     eax, eax
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        xchg    eax, edx
        call    disasm_write_reg1632
        and     byte [edi], 0
        ret

cint:
        mov     eax, 'int '
        stosd
        mov     eax, '    '
        stosd

disasm_i8u:
        xor     eax, eax
        call    disasm_get_byte
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmov11:
; mov r8,i8
        mov     ecx, eax
        mov     eax, 'mov '
        stosd
        mov     eax, '    '
        stosd
        and     ecx, 7
        mov     ax, [disasm_regs8+ecx*2]
        stosw
        mov     ax, ', '
        stosw
        jmp     disasm_i8u

;-----------------------------------------------------------------------------

cmov12:
; mov r32,i32
        xchg    eax, edx
        mov     eax, 'mov '
        stosd
        mov     eax, '    '
        stosd
        xchg    eax, edx
        and     eax, 7
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        jmp     cmov2.1

;-----------------------------------------------------------------------------

iglobal
disasm_shifts   dd      'rol ','ror ','rcl ','rcr ','shl ','shr ','sal ','sar '
endg

;-----------------------------------------------------------------------------

cshift2:
; shift r/m,1 = D0/D1
cshift3:
; shift r/m,cl = D2/D3
        disasm_set_modew
        mov     dl, al
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        mov     eax, [disasm_shifts+eax*4]
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        cmp     dl, 0xD2
        jb      .s1
        mov     eax, ', cl'
        stosd
        and     byte [edi], 0
        ret

    .s1:
        mov     eax, ', 1'
        stosd
        clc
        ret

;-----------------------------------------------------------------------------

cshift1:
; shift r/m,i8 = C0/C1
        disasm_set_modew
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        mov     eax, [disasm_shifts+eax*4]
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        jmp     disasm_i8u

;-----------------------------------------------------------------------------

caam:
        mov     eax, 'aam '
        jmp     @f

caad:
        mov     eax, 'aad '

    @@:
        stosd
        mov     eax, '    '
        stosd
        xor     eax, eax
        call    disasm_get_byte
        cmp     al, 10
        jz      @f
        call    disasm_write_num

    @@:
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmov3:
; A0: mov al,[ofs32]
; A1: mov ax/eax,[ofs32]
; A2: mov [ofs32],al
; A3: mov [ofs32],ax/eax
        mov     edx, 'mov '
        xchg    eax, edx
        stosd
        mov     eax, '    '
        stosd
        test    dl, 2
        jnz     .1
        call    .write_acc
        mov     ax, ', '
        stosw
        call    .write_ofs32
        jmp     .2

    .1:
        call    .write_ofs32
        mov     ax, ', '
        stosw
        call    .write_acc

    .2:
        and     byte [edi], 0
        ret

    .write_acc:
        test    dl, 1
        jz      .8bit
        test    ch, 1
        jnz     .16bit
        mov     eax, 'eax'
        stosd
        dec     edi
        ret

    .16bit:
        mov     ax, 'ax'
        stosw
        ret

    .8bit:
        mov     ax, 'al'
        stosw
        ret

    .write_ofs32:
        mov     al, '['
        stosb
        call    disasm_get_dword
        call    disasm_write_num
        mov     al, ']'
        stosb
        ret

;-----------------------------------------------------------------------------

disasm_write_reg:
        test    ch, 80h
        jnz     disasm_write_reg1632
        mov     ax, [disasm_regs8+eax*2]
        stosw
        ret

;-----------------------------------------------------------------------------

disasm_write_reg1632:
        test    ch, 1
        jnz     @f
        mov     eax, [disasm_regs32+eax*4]
        stosd
        dec     edi
        ret

    @@:
        mov     ax, [disasm_regs16+eax*2]
        stosw
        ret

;-----------------------------------------------------------------------------

; 0F B6/B7
cmovzx:
; 0F BE/BF
cmovsx:
        mov     edx, eax
        disasm_set_modew
        mov     eax, 'movz'
        cmp     dl, 0xB8
        jb      @f
        mov     eax, 'movs'

    @@:
        stosd
        mov     eax, 'x   '
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        or      ch, 1   ; 2nd operand - 8 or 16 bits
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
disasm_op2cmds  dd 'add ','or  ','adc ','sbb ','and ','sub ','xor ','cmp '
endg

;-----------------------------------------------------------------------------

cop21:
        disasm_set_modew
        mov     esi, 'test'
        cmp     al, 0A8h
        jae     @f
        shr     al, 3
        and     eax, 7
        mov     esi, [disasm_op2cmds+eax*4]

    @@:
        xchg    eax, esi
        stosd
        mov     eax, '    '
        stosd
        test    ch, 80h
        jnz     .1632
        mov     eax, 'al, '
        stosd
        jmp     disasm_i8u

    .1632:
        test    ch, 1
        jnz     .16
        mov     eax, 'eax,'
        stosd
        mov     al, ' '
        stosb
        call    disasm_get_dword
        jmp     .x

    .16:
        mov     eax, 'ax, '
        stosd
        xor     eax, eax
        call    disasm_get_word

    .x:
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

carpl:
        xor     edx, edx
        or      ch, 0C1h
        mov     eax, 'arpl'
        jmp     cop22.d2

;-----------------------------------------------------------------------------

ccmpxchg:
        xor     edx, edx
        disasm_set_modew
        or      ch, 40h
        mov     eax, 'cmpx'
        stosd
        mov     eax, 'chg '
        jmp     cop22.d1

;-----------------------------------------------------------------------------

cbsf:
cbsr:
        or      ch, 80h

;-----------------------------------------------------------------------------

cop22:
        disasm_set_modew
        or      ch, 40h
        mov     edx, eax
        mov     esi, 'lea '
        cmp     al, 8Dh
        jz      @f
        mov     esi, 'imul'
        cmp     al, 0xAF
        jz      @f
        mov     esi, 'bsf '
        cmp     al, 0BCh
        jz      @f
        mov     esi, 'bsr '
        cmp     al, 0BDh
        jz      @f
        mov     esi, 'mov '
        cmp     al, 88h
        jae     @f
        mov     esi, 'xchg'
        cmp     al, 86h
        jae     @f
        mov     esi, 'test'
        cmp     al, 84h
        jae     @f
        shr     al, 3
        and     eax, 7
        mov     esi, [disasm_op2cmds+eax*4]

    @@:
        xchg    eax, esi

    .d2:
        stosd
        mov     eax, '    '

    .d1:
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        cmp     dl, 0x8D
        jz      @f
        cmp     dl, 0x86
        jz      @f
        cmp     dl, 0x87
        jz      @f
        cmp     dl, 0xBC
        jz      @f
        cmp     dl, 0xBD
        jz      @f
        test    dl, 2
        jz      .d0

    @@:
        call    disasm_write_reg
        mov     ax, ', '
        stosw
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .d0:
        push    eax
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        pop     eax
        call    disasm_write_reg
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cbound:
        mov     edx, eax
        mov     eax, 'boun'
        stosd
        mov     eax, 'd   '
        or      ch, 0xC0
        jmp     cop22.d1

;-----------------------------------------------------------------------------

cop23:
        disasm_set_modew
        xchg    eax, edx
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     eax, 3
        and     eax, 7
        mov     eax, [disasm_op2cmds+eax*4]

ctest:
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        test    ch, 80h
        jz      .i8
        cmp     dl, 83h
        jz      .i8
        test    ch, 1
        jnz     .i16
        call    disasm_get_dword
        jmp     .ic

    .i8:
        xor     eax, eax
        call    disasm_get_byte
        cmp     dl, 83h
        jnz     .ic
        movsx   eax, al
        jmp     .ic

    .i16:
        xor     eax, eax
        call    disasm_get_word

    .ic:
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmovcc:
        or      ch, 0C0h
        and     eax, 0xF
        mov     ax, [disasm_jcc_codes + eax*2]
        mov     dword [edi], 'cmov'
        add     edi, 4
        stosw
        mov     ax, '  '
        stosw
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     eax, 3
        and     eax, 7
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        call    disasm_readrmop
        and     byte [edi], 0
        ret

; btx r/m,i8 = 0F BA 
cbtx1:
        or      ch, 80h
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        cmp     al, 4
        jb      cunk
        mov     eax, [btx1codes+eax*4-4*4]
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        jmp     disasm_i8u

;-----------------------------------------------------------------------------

iglobal
btx1codes       dd      'bt  ','bts ','btr ','btc '
endg

;-----------------------------------------------------------------------------

; btx r/m,r = 0F 101xx011 (A3,AB,B3,BB)
cbtx2:
        shr     al, 3
        and     eax, 3
        mov     eax, [btx1codes+eax*4]
        stosd
        mov     eax, '    '
        stosd
        or      ch, 0xC0
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        push    eax
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        pop     eax
        call    disasm_write_reg1632
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

csetcc:
        and     eax, 0xF
        mov     ax, [disasm_jcc_codes + eax*2]
        mov     dword [edi], 'setc'
        add     edi, 3
        stosw
        mov     ax, '  '
        stosw
        stosb
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
disasm_jcc_codes dw 'o ','no','b ','ae','z ','nz','be','a ','s ','ns','p ','np','l ','ge','le','g '
endg

;-----------------------------------------------------------------------------

cjcc1:
cjmp2:
        cmp     al, 0xEB
        jz      .1
        and     eax, 0xF
        mov     ax, [disasm_jcc_codes + eax*2]
        jmp     .2

    .1:
        mov     ax, 'mp'

    .2:
        mov     byte [edi], 'j'
        inc     edi
        stosw
        mov     eax, '    '
        stosb
        stosd
        call    disasm_get_byte
        movsx   eax, al

disasm_rva:
        add     eax, [disasm_cur_pos]
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

ccall1:
cjmp1:
cjcc2:
        mov     edx, 'call'
        cmp     al, 0xE8
        jz      @f
        mov     edx, 'jmp '
        cmp     al, 0xE9
        jz      @f
        mov     edx, '    '
        and     eax, 0xF
        mov     dx, [disasm_jcc_codes+eax*2]
        shl     edx, 8
        mov     dl, 'j'

    @@:
        xchg    eax, edx
        stosd
        mov     eax, '    '
        stosd
        test    ch, 1
        jnz     @f
        call    disasm_get_dword
        jmp     disasm_rva

    @@:
        call    disasm_get_word
        add     eax, [disasm_cur_pos]
        and     eax, 0xFFFF
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

ccallf:
        mov     eax, 'call'
        stosd
        mov     eax, '    '
        stosd
        mov     al, 'd'
        test    ch, 1
        jnz     @f
        mov     al, 'p'

    @@:
        stosb
        mov     eax, 'word'
        stosd
        mov     al, ' '
        stosb
        test    ch, 1
        jnz     .1
        call    disasm_get_dword
        jmp     .2

    .1:
        xor     eax, eax
        call    disasm_get_word

    .2:
        push    eax
        xor     eax, eax
        call    disasm_get_word
        call    disasm_write_num
        mov     al, ':'
        stosb
        pop     eax
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
op11codes       dd      'test',0,'not ','neg ','mul ','imul','div ','idiv'
op12codes       dd      'inc ','dec ','call',0,'jmp ',0,'push',0
endg

;-----------------------------------------------------------------------------

cop1:
        disasm_set_modew
        xchg    eax, edx
        call    disasm_get_byte
        movzx   esi, al
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        cmp     dl, 0xFE
        jnz     @f
        cmp     al, 1
        jbe     @f

    .0:
        inc     [disasm_cur_pos]
        jmp     cunk

    @@:
        and     edx, 8
        add     eax, edx
        cmp     al, 11
        jz      .callfar
        cmp     al, 13
        jz      .jmpfar
        mov     eax, [op11codes+eax*4]
        test    eax, eax
        jz      .0
        cmp     eax, 'test'
        jz      ctest

    .2:
        stosd
        mov     eax, '    '
        stosd
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .callfar:
        mov     eax, 'call'

    .1:
        cmp     esi, 0xC0
        jae     .0
        stosd
        mov     eax, '    '
        stosd
        mov     eax, 'far '
        stosd
        mov     al, 'd'
        test    ch, 1
        jnz     @f
        mov     al, 'p'

    @@:
        stosb
        or      ch, 1
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .jmpfar:
        mov     eax, 'jmp '
        jmp     .1

;-----------------------------------------------------------------------------

cpop2:
        or      ch, 80h
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        test    al, 00111000b
        jnz     cunk
        mov     eax, 'pop '
        jmp     cop1.2

;-----------------------------------------------------------------------------

cloopnz:
        mov     eax, 'loop'
        stosd
        mov     eax, 'nz  '
        test    ch, 2
        jz      @f
        mov     ah, 'w'

    @@:
        jmp     cloop.cmn

cloopz:
        mov     eax, 'loop'
        stosd
        mov     eax, 'z   '
        test    ch, 2
        jz      @f
        mov     eax, 'zw  '

    @@:
        jmp     cloop.cmn

cjcxz:
cloop:
        cmp     al, 0xE2
        jz      .loop
        test    ch, 2
        jnz     .jcxz
        mov     eax, 'jecx'
        stosd
        mov     eax, 'z   '
        jmp     .cmn

    .jcxz:
        mov     eax, 'jcxz'
        stosd
        mov     eax, '    '
        jmp     .cmn

    .loop:
        mov     eax, 'loop'
        stosd
        mov     eax, '    '
        test    ch, 2
        jz      .cmn
        mov     al, 'w'

    .cmn:
        stosd
        call    disasm_get_byte
        movsx   eax, al
        add     eax, [disasm_cur_pos]
        test    ch, 1
        jz      @f
        and     eax, 0xFFFF

;    @@:
disasm_write_num_done:
    @@:
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

; imul r,r/m,i
cimul1:
        or      ch, 80h         ; 32bit operation
        xchg    eax, edx
        mov     eax, 'imul'
        stosd
        mov     eax, '    '
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        test    ch, 1
        jnz     .16
        cmp     dl, 0x69
        jz      .op32
        call    disasm_get_byte
        movsx   eax, al
        jmp     disasm_write_num_done

    .op32:
        call    disasm_get_dword
        jmp     disasm_write_num_done

    .16:
        cmp     dl, 0x69
        jz      .op16
        call    disasm_get_byte
        cbw
        jmp     disasm_write_num_done

    .op16:
        xor     eax, eax
        call    disasm_get_word
        jmp     disasm_write_num_done

;-----------------------------------------------------------------------------

cshld:
cshrd:
        mov     edx, 'shld'
        test    al, 8
        jz      @f
        mov     edx, 'shrd'

    @@:
        xchg    eax, edx
        stosd
        mov     eax, '    '
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        push    eax
        or      ch, 80h
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        pop     eax
        call    disasm_write_reg1632
        mov     ax, ', '
        stosw
        test    dl, 1
        jz      disasm_i8u
        mov     ax, 'cl'
        stosw
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

ccbw:
        mov     eax, 'cbw '
        test    ch, 1
        jnz     @f
        mov     eax, 'cwde'

    @@:
        stosd
        and     byte [edi], 0
        ret

ccwd:
        mov     eax, 'cwd '
        test    ch, 1
        jnz     @b
        mov     eax, 'cdq '
        jmp     @b

;-----------------------------------------------------------------------------

ccmpxchg8b:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     cerr
        shr     al, 3
        and     al, 7
        cmp     al, 1
        jnz     cerr
        dec     [disasm_cur_pos]
        mov     eax, 'cmpx'
        stosd
        mov     eax, 'chg8'
        stosd
        mov     al, 'b'
        stosb
        mov     al, ' '
        stosb
        or      ch, 40h
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
fpuD8   dd      'add ','mul ','com ','comp','sub ','subr','div ','divr'
endg

;-----------------------------------------------------------------------------

cD8:
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        push    eax
        shr     al, 3
        and     eax, 7
        mov     byte [edi], 'f'
        inc     edi
        xchg    eax, edx
        mov     eax, [fpuD8+edx*4]
        stosd
        mov     ax, '  '
        stosw
        stosb
        pop     eax
        cmp     dl, 2
        jb      .1
        cmp     dl, 3
        jbe     .2

    .1:
        cmp     al, 0xC0
        jb      .2
        mov     eax, 'st0,'
        stosd
        mov     al, ' '
        stosb

    .2:
        or      ch, 80h or 20h
        and     ch, not 1
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
fpuD9_2:
        dq      'fchs    ','fabs    ',0,0,'ftst    ','fxam    ',0,0
        db      'fld1    fldl2t  fldl2e  fldpi   fldlg2  fldln2  fldz    '
        dq      0
        db      'f2xm1   fyl2x   fptan   fpatan  fxtract fprem1  fdecstp fincstp '
        db      'fprem   fyl2xp1 fsqrt   fsincos frndint fscale  fsin    fcos    '
fpuD9_fnop      db      'fnop    '
endg

;-----------------------------------------------------------------------------

cD9:
        call    disasm_get_byte
        sub     al, 0xC0
        jae     .l1
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        cmp     al, 7
        jnz     @f
        mov     eax, 'fnst'
        stosd
        mov     eax, 'cw  '
        jmp     .x1

    @@:
        cmp     al, 5
        jnz     @f
        mov     eax, 'fldc'
        stosd
        mov     eax, 'w   '

    .x1:
        stosd
        or      ch, 0C1h
        jmp     .cmn

    @@:
        mov     edx, 'fld '
        test    al, al
        jz      @f
        mov     edx, 'fst '
        cmp     al, 2
        jz      @f
        mov     edx, 'fstp'
        cmp     al, 3
        jnz     cunk

    @@:
        xchg    eax, edx
        stosd
        mov     eax, '    '
        stosd
        or      ch, 80h
        and     ch, not 1

    .cmn:
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .l1:
        cmp     al, 10h
        jae     .l2
        mov     edx, 'fld '
        cmp     al, 8
        jb      @f
        mov     edx, 'fxch'

    @@:
        xchg    eax, edx
        stosd
        mov     eax, '    '
        stosd
        xchg    eax, edx
        and     al, 7
        add     al, '0'
        shl     eax, 16
        mov     ax, 'st'
        stosd
        clc
        ret

    .l2:
        cmp     al, 0x10
        jnz     @f
        mov     esi, fpuD9_fnop
        jmp     .l3

    @@:
        sub     al, 0x20
        jb      cerr
        lea     esi, [fpuD9_2+eax*8]
        cmp     byte [esi], 0
        jz      cerr

    .l3:
        movsd
        movsd
        and     byte [edi-1], 0
        ret

;-----------------------------------------------------------------------------

cDA:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     cunk
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        mov     word [edi], 'fi'
        inc     edi
        inc     edi
        mov     eax, [fpuD8+eax*4]
        stosd
        mov     ax, '  '
        stosw
        or      ch, 80h
        and     ch, not 1       ; 32-bit operand
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
fpuDB   dd      'ild ',0,'ist ','istp',0,'ld  ',0,'stp '
endg

;-----------------------------------------------------------------------------

cDB:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     .1
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        xchg    eax, edx
        mov     eax, [fpuDB+edx*4]
        test    eax, eax
        jz      cerr
        mov     byte [edi], 'f'
        inc     edi
        stosd
        mov     ax, '  '
        stosw
        stosb
        or      ch, 80h
        and     ch, not 1       ; 32-bit operand
        cmp     dl, 4
        jb      @f
        or      ch, 20h
        and     ch, not 80h     ; 80-bit operand

    @@:
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .1:
        cmp     al, 0xE3
        jnz     cunk
        mov     eax, 'fnin'
        stosd
        mov     eax, 'it'
        stosd
        dec     edi
        ret             ; CF cleared

;-----------------------------------------------------------------------------

iglobal
fpuDC   dd      'add ','mul ',0,0,'subr','sub ','divr','div '
endg

;-----------------------------------------------------------------------------

cDC:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     .1
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        mov     byte [edi], 'f'
        inc     edi
        mov     eax, [fpuD8+eax*4]
        stosd
        mov     ax, '  '
        stosw
        stosb
        or      ch, 0A1h        ; qword
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .1:
        mov     dl, al
        shr     al, 3
        and     eax, 7
        mov     eax, [fpuDC+eax*4]
        test    eax, eax
        jz      cerr
        mov     byte [edi], 'f'
        inc     edi
        stosd
        mov     eax, '   s'
        stosd
        mov     al, 't'
        stosb
        and     edx, 7
        lea     eax, [edx+'0']
        stosb
        mov     eax, ', st'
        stosd
        mov     ax, '0'
        stosw
        ret     ; CF cleared

;-----------------------------------------------------------------------------

iglobal
fpuDD   dd      'fld ',0,'fst ','fstp',0,0,0,0
fpuDD_2 dq      'ffree   ',0,'fst     ','fstp    ','fucom   ','fucomp  ',0,0
endg

;-----------------------------------------------------------------------------

cDD:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     .1
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        xchg    eax, edx
        mov     eax, [fpuDD+edx*4]
        test    eax, eax
        jz      cunk
        stosd
        mov     eax, '    '
        stosd
        or      ch, 0A1h        ; qword operand
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .1:
        push    eax
        shr     al, 3
        and     eax, 7
        xchg    eax, edx
        mov     eax, dword [fpuDD_2+edx*8]
        test    eax, eax
        jz      cerr
        stosd
        mov     eax, dword [fpuDD_2+4+edx*8]
        stosd
        mov     ax, 'st'
        stosw
        pop     eax
        and     al, 7
        add     al, '0'
        stosb
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
fpuDE   dd      'add ','mul ',0,0,'subr','sub ','divr','div '
endg

;-----------------------------------------------------------------------------

cDE:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     .1
        dec     [disasm_cur_pos]
        mov     word [edi], 'fi'
        inc     edi
        inc     edi
        shr     al, 3
        and     eax, 7
        mov     eax, [fpuD8+eax*4]
        stosd
        mov     ax, '  '
        stosw
        or      ch, 81h         ; force 16-bit
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .1:
        push    eax
        shr     al, 3
        and     eax, 7
        xchg    eax, edx
        mov     eax, [fpuDE+edx*4]
        test    eax, eax
        jz      .fcompp
        mov     byte [edi], 'f'
        inc     edi
        stosd
        mov     al, 'p'
        cmp     byte [edi-1], ' '
        jnz     @f
        mov     byte [edi-1], al
        mov     al, ' '

    @@:
        stosb
        mov     eax, '  st'
        stosd
        pop     eax
        and     al, 7
        add     al, '0'
        stosb
        mov     ax, ', '
        stosw
        mov     eax, 'st0'
        stosd
        ret     ; CF cleared

    .fcompp:
        pop     eax
        cmp     al, 0xD9
        jnz     cerr
        mov     eax, 'fcom'
        stosd
        mov     ax, 'pp'
        stosw
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
fpuDF   dd      'ild ',0,'ist ','istp','bld ','ild ','bstp','istp'
endg

;-----------------------------------------------------------------------------

cDF:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     .1
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        xchg    eax, edx
        mov     eax, [fpuDF+edx*4]
        test    eax, eax
        jz      cerr
        mov     byte [edi], 'f'
        inc     edi
        stosd
        mov     ax, '  '
        stosw
        stosb
        or      ch, 81h         ; force 16-bit operand
        cmp     dl, 4
        jb      @f
        or      ch, 20h
        test    dl, 1
        jnz     @f
        or      ch, 40h

    @@:
        call    disasm_readrmop
        and     byte [edi], 0
        ret

    .1:
        cmp     al, 0xE0
        jnz     cunk
        mov     eax, 'fnst'
        stosd
        mov     eax, 'sw  '
        stosd
        mov     ax, 'ax'
        stosw
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmovd1:
        mov     eax, 'movd'
        stosd
        mov     eax, '    '
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        call    disasm_write_mmreg
        mov     ax, ', '
        stosw
        or      ch, 0C0h
        and     ch, not 1
        call    disasm_readrmop
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmovd2:
        mov     eax, 'movd'
        stosd
        mov     eax, '    '
        stosd
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        push    eax ecx
        or      ch, 0C0h
        and     ch, not 1
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        pop     ecx eax
        call    disasm_write_mmreg
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

cmovq1:
        test    ch, 1
        jz      .mm
        mov     eax, 'movd'
        stosd
        mov     eax, 'qa  '
        stosd
        jmp     disasm_mmx1

    .mm:
        mov     eax, 'movq'
        stosd
        mov     eax, '    '
        stosd
        jmp     disasm_mmx1

;-----------------------------------------------------------------------------

cmovq2:
        test    ch, 1
        jz      .mm
        mov     eax, 'movd'
        stosd
        mov     eax, 'qa  '
        stosd
        jmp     disasm_mmx3

    .mm:
        mov     eax, 'movq'

disasm_mmx2:
        stosd
        mov     eax, '    '
        stosd

disasm_mmx3:
        or      ch, 50h
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        push    eax
        call    disasm_readrmop
        mov     ax, ', '
        stosw
        pop     eax
        shr     al, 3
        and     eax, 7
        call    disasm_write_mmreg
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
mmx_cmds:
        db      0x60,'unpcklbw'
        db      0x61,'unpcklwd'
        db      0x62,'unpckldq'
        db      0x63,'packsswb'
        db      0x64,'pcmpgtb '
        db      0x65,'pcmpgtw '
        db      0x66,'pcmpgtd '
        db      0x67,'packuswb'
        db      0x68,'unpckhbw'
        db      0x69,'unpckhwd'
        db      0x6A,'unpckhdq'
        db      0x6B,'packssdw'
        db      0x74,'pcmpeqb '
        db      0x75,'pcmpeqw '
        db      0x76,'pcmpeqd '
        db      0xD4,'paddq   '
        db      0xD5,'pmullw  '
        db      0xD8,'psubusb '
        db      0xD9,'psubusw '
        db      0xDA,'pminub  '
        db      0xDB,'pand    '
        db      0xDC,'paddusb '
        db      0xDD,'paddusw '
        db      0xDE,'pmaxub  '
        db      0xDF,'pandn   '
        db      0xE0,'pavgb   '
        db      0xE3,'pavgw   '
        db      0xE4,'pmulhuw '
        db      0xE5,'pmulhw  '
        db      0xE8,'psubsb  '
        db      0xE9,'psubsw  '
        db      0xEA,'pminsw  '
        db      0xEB,'por     '
        db      0xEC,'paddsb  '
        db      0xED,'paddsw  '
        db      0xEE,'pmaxsw  '
        db      0xEF,'pxor    '
        db      0xF4,'pmuludq '
        db      0xF5,'pmaddwd '
        db      0xF6,'psadbw  '
        db      0xF8,'psubb   '
        db      0xF9,'psubw   '
        db      0xFA,'psubd   '
        db      0xFB,'psubq   '
        db      0xFC,'paddb   '
        db      0xFD,'paddw   '
        db      0xFE,'paddd   '
endg

;-----------------------------------------------------------------------------

cpcmn:
        mov     esi, mmx_cmds

    @@:
        cmp     al, [esi]
        jz      @f
        add     esi, 9
        jmp     @b

    @@:
        inc     esi
        mov     al, 'p'
        cmp     byte [esi], al
        jz      @f
        stosb

    @@:
        movsd
        movsd
        cmp     byte [edi-1], ' '
        jz      @f
        mov     al, ' '
        stosb

;    @@:

disasm_mmx1:
    @@:
        or      ch, 50h
        call    disasm_get_byte
        dec     [disasm_cur_pos]
        shr     al, 3
        and     eax, 7
        call    disasm_write_mmreg
        mov     ax, ', '
        stosw
        call    disasm_readrmop
        cmp     word [disasm_string], 'cm'
        jz      .cmp
        and     byte [edi], 0
        ret

    .cmp:
        call    disasm_get_byte
        and     eax, 7
        mov     dx, 'eq'
        dec     eax
        js      @f
        mov     dx, 'lt'
        jz      @f
        mov     dh, 'e'
        dec     eax
        jnz     .no2

    @@:
        xchg    dx, word [disasm_string+3]
        mov     word [disasm_string+5], dx
        and     byte [edi], 0
        ret

    .no2:
        dec     eax
        jnz     @f
        add     edi, 2
        push    edi
        lea     esi, [edi-3]
        lea     ecx, [esi-(disasm_string+8)+2]
        std
        rep movsb
        cld
        mov     cx, word [esi-3]
        mov     dword [esi-3], 'unor'
        mov     byte [esi+1], 'd'
        mov     word [esi+2], cx
        pop     edi
        and     byte [edi+1], 0
        ret

    @@:
        mov     edx, 'neq'
        dec     eax
        jz      @f
        mov     edx, 'nlt'
        dec     eax
        jz      @f
        mov     edx, 'nle'
        dec     eax
        jz      @f
        mov     edx, 'ord'

    @@:
        push    edi
        lea     esi, [edi-1]
        lea     ecx, [esi-(disasm_string+8)+2]
        std
        rep movsb
        cld
        mov     cx, word [esi-3]
        mov     dword [esi-3], edx
        mov     word [esi], cx
        pop     edi
        and     byte [edi+1], 0
        ret

;-----------------------------------------------------------------------------

cpsrlw:
        mov     eax, 'psrl'
        jmp     @f

cpsraw:
        mov     eax, 'psra'
        jmp     @f

cpsllw:
        mov     eax, 'psll'

    @@:
        stosd
        mov     eax, 'w   '
        stosd
        jmp     disasm_mmx1

cpsrld:
        mov     eax, 'psrl'
        jmp     @f

cpsrad:
        mov     eax, 'psra'
        jmp     @f

cpslld:
        mov     eax, 'psll'

    @@:
        stosd
        mov     eax, 'd   '
        stosd
        jmp     disasm_mmx1

cpsrlq:
        mov     eax, 'psrl'
        jmp     @f

cpsllq:
        mov     eax, 'psll'

    @@:
        stosd
        mov     eax, 'q   '
        stosd
        jmp     disasm_mmx1

;-----------------------------------------------------------------------------

csse1:
iglobal
sse_cmds1:
        db      0x2F,4,'comi'
        db      0x54,3,'and'
        db      0x55,4,'andn'
        db      0x58,3,'add'
        db      0xC2,3,'cmp'
endg
        mov     esi, sse_cmds1+1

    .1:
    @@:
        movzx   edx, byte [esi]
        cmp     al, [esi-1]
        jz      @f
        lea     esi, [esi+edx+2]
        jmp     @b

    @@:
        push    ecx
        mov     ecx, edx
        inc     esi
        rep movsb
        pop     ecx
        mov     al, 's'
        cmp     byte [edi-1], 'i'
        jz      @f
        mov     al, 'p'

    @@:
        stosb
        mov     al, 'd'
        test    ch, 1
        jnz     @f
        mov     al, 's'

    @@:
        stosb
        push    ecx
        push    5
        pop     ecx
        sub     ecx, edx
        adc     ecx, 1
        mov     al, ' '
        rep stosb
        pop     ecx
        or      ch, 1           ; force XMM reg
        jmp     disasm_mmx1

;-----------------------------------------------------------------------------

csse2:
iglobal
sse_cmds2:
        db      0xD0,6,'addsub'
        db      0,0
endg
        test    ch, 1
        jz      cerr
        mov     esi, sse_cmds2+1
        jmp     csse1.1

cpshift:
        mov     dl, al
        mov     ax, 'ps'
        stosw
        call    disasm_get_byte
        push    eax
        and     al, 0xC0
        cmp     al, 0xC0
        jnz     .pop_cunk
        pop     eax
        push    eax
        shr     al, 3
        and     eax, 7
        cmp     al, 2
        jz      .rl
        cmp     al, 4
        jz      .ra
        cmp     al, 6
        jz      .ll

    .pop_cunk:
        pop     eax
        jmp     cunk

    .ll:
        mov     ax, 'll'
        jmp     @f

    .rl:
        mov     ax, 'rl'
        jmp     @f

    .ra:
        cmp     dl, 0x73
        jz      .pop_cunk
        mov     ax, 'ra'

    @@:
        stosw
        mov     al, 'w'
        cmp     dl, 0x71
        jz      @f
        mov     al, 'd'
        cmp     dl, 0x72
        jz      @f
        mov     al, 'q'

    @@:
        stosb
        mov     ax, '  '
        stosw
        stosb
        pop     eax
        and     eax, 7
        call    disasm_write_mmreg
        mov     ax, ', '
        stosw
        xor     eax, eax
        call    disasm_get_byte
        call    disasm_write_num
        and     byte [edi], 0
        ret

;-----------------------------------------------------------------------------

iglobal
grp15c1 dq      'fxsave  ','fxrstor ','ldmxcsr ','stmxcsr ',0,0,0,'clflush '
endg

;-----------------------------------------------------------------------------

cgrp15:
        call    disasm_get_byte
        cmp     al, 0xC0
        jae     cunk
        shr     al, 3
        and     eax, 7
        mov     edx, eax
        mov     eax, dword [grp15c1+eax*8]
        test    eax, eax
        jz      cerr
        dec     [disasm_cur_pos]
        stosd
        mov     eax, dword [grp15c1+4+edx*8]
        stosd
        or      ch, 40h
        call    disasm_readrmop
        and     byte [edi], 0
        ret

; vim: ft=fasm tabstop=4