Author Topic: Object-oriented programming (OOP) in Asmc  (Read 4347 times)

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #15 on: December 17, 2019, 11:55:14 PM »
Here's a inline version of the InstructionSet class. The whole class is now just a header so no external code needed. Note that the constructor is defined as a PROTO by the CLASS directive so UNDEF is needed there but the member functions will be resolved by INVOKE.
Code: [Select]
include intrin.inc

MAXCPUSTRING    equ 512

.class InstructionSet_Internal

    nIds        int_t ?
    nExIds      int_t ?
    isIntel     int_t ?
    isAMD       int_t ?
    union
     struct
      f_1_ECX   uint_t ?
      f_1_EDX   uint_t ?
     ends
     f_1_RAX    uint64_t ?
    ends
    union
     struct
      f_7_EBX   uint_t ?
      f_7_ECX   uint_t ?
     ends
     f_7_RAX    uint64_t ?
    ends
    union
     struct
      f_81_ECX  uint_t ?
      f_81_EDX  uint_t ?
     ends
     f_81_RAX   uint64_t ?
    ends

    .ends


.class InstructionSet : public InstructionSet_Internal

    GetVendor      proc ; getters
    GetBrand       proc
    GetSSE3        proc
    GetPCLMULQDQ   proc
    GetMONITOR     proc
    GetSSSE3       proc
    GetFMA         proc
    GetCMPXCHG16B  proc
    GetSSE41       proc
    GetSSE42       proc
    GetMOVBE       proc
    GetPOPCNT      proc
    GetAES         proc
    GetXSAVE       proc
    GetOSXSAVE     proc
    GetAVX         proc
    GetF16C        proc
    GetRDRAND      proc
    GetMSR         proc
    GetCX8         proc
    GetSEP         proc
    GetCMOV        proc
    GetCLFSH       proc
    GetMMX         proc
    GetFXSR        proc
    GetSSE         proc
    GetSSE2        proc
    GetFSGSBASE    proc
    GetBMI1        proc
    GetHLE         proc
    GetAVX2        proc
    GetBMI2        proc
    GetERMS        proc
    GetINVPCID     proc
    GetRTM         proc
    GetAVX512F     proc
    GetRDSEED      proc
    GetADX         proc
    GetAVX512PF    proc
    GetAVX512ER    proc
    GetAVX512CD    proc
    GetSHA         proc
    GetPREFETCHWT1 proc
    GetLAHF        proc
    GetLZCNT       proc
    GetABM         proc
    GetSSE4a       proc
    GetXOP         proc
    GetTBM         proc
    GetSYSCALL     proc
    GetMMXEXT      proc
    GetRDTSCP      proc
    Get3DNOWEXT    proc
    Get3DNOW       proc

    .ends

undef InstructionSet_InstructionSet ; flip the PROTO to a MACRO

InstructionSet_InstructionSet macro this ; .NEW cpu : InstructionSet()

  .new vendor[16]:char_t ; add to local stack
  .new brand[64]:char_t

    ifidn @SubStr(this,1,1),<&>
        lea rax,@SubStr(this,2)
    else
        mov rax,this
    endif
    lea     rdx,vendor

    ; new stack frame

    push    rsi
    push    rdi
    push    rbx
    push    rbp
    mov     rbp,rsp
    sub     rsp,MAXCPUSTRING+16+8
    mov     [rbp-24],rdx
    mov     rsi,rax
    assume  rsi: ptr InstructionSet

    ; get the number of the highest valid function ID.

    mov rdi,rsp
    xor r8d,r8d
    xor eax,eax
    xor ecx,ecx
    cpuid
    mov [rsi].nIds,eax

    .fors ( r9 = rdi: r8d <= [rsi].nIds: r8d++, r9 += 16 )

        mov eax,r8d
        xor ecx,ecx
        cpuid
        mov [r9+0x00],eax
        mov [r9+0x04],ebx
        mov [r9+0x08],ecx
        mov [r9+0x0C],edx
    .endf

    ; Capture vendor string

    mov rdx,[rbp-24]
    mov dword ptr [rdx+0x00],[rdi+0x04]
    mov dword ptr [rdx+0x04],[rdi+0x0C]
    mov dword ptr [rdx+0x08],[rdi+0x08]
    mov dword ptr [rdx+0x0C],0
    mov rax,[rdx]
    mov rdx,[rdx+8]
    mov rcx,"IeniuneG"
    mov rbx,"letn"
    .if ( rax == rcx && rdx == rbx )

        mov [rsi].isIntel,TRUE
    .else
        mov rcx,"itnehtuA"
        mov rbx,"DMAc"
        .if ( rax == rcx && rdx == rbx )

            mov [rsi].isAMD,TRUE
        .endif
    .endif

    ; load bitset with flags for function 0x00000001

    .if ( [rsi].nIds >= 1 )

        mov [rsi].f_1_RAX,[rdi+0x10][0x8]
    .endif

    ; load bitset with flags for function 0x00000007

    .if ( [rsi].nIds >= 7 )

        mov [rsi].f_7_RAX,[rdi+0x70][0x4]
    .endif

    ; get the number of the highest valid extended ID.

    mov r8d,0x80000000
    mov eax,r8d
    xor ecx,ecx
    cpuid
    mov [rsi].nExIds,eax

    .fors ( r9 = rdi: r8d <= [rsi].nExIds: r8d++, r9 += 16 )

        mov eax,r8d
        xor ecx,ecx
        cpuid
        mov [r9+0x00],eax
        mov [r9+0x04],ebx
        mov [r9+0x08],ecx
        mov [r9+0x0C],edx
    .endf

    ; load bitset with flags for function 0x80000001

    .if ( [rsi].nExIds >= 0x80000001 )

        mov [rsi].f_81_RAX,[rdi+0x10][0x8]
    .endif

    ; Interpret CPU brand string if reported

    .if ( [rsi].nExIds >= 0x80000004 )

        lea rsi,[rdi+0x20]
        mov rdi,[rbp-24]
        sub rdi,64
        mov ecx,3*16
        rep movsb
    .endif

    assume rsi: nothing

    leave
    pop rbx
    pop rdi
    pop rsi

    exitm<>
    endm

InstructionSet_GetVendor macro this
    lea rax,vendor
    exitm<>
    endm

InstructionSet_GetBrand macro this
    lea rax,brand
    exitm<>
    endm


InstructionSetInline macro name, reg, bit, condition
 InstructionSet_Get&name& macro this
 ifnb <condition>
     bt  [this].InstructionSet.condition,0
     sbb eax,eax
     and eax,[this].InstructionSet.reg
     and eax,1 shl bit
 else
     mov eax,[this].InstructionSet.reg
     and eax,1 shl bit
 endif
     exitm<>
     endm
    endm

InstructionSetInline SSE3,          f_1_ECX,     0
InstructionSetInline PCLMULQDQ,     f_1_ECX,     1
InstructionSetInline MONITOR,       f_1_ECX,     3
InstructionSetInline SSSE3,         f_1_ECX,     9
InstructionSetInline FMA,           f_1_ECX,    12
InstructionSetInline CMPXCHG16B,    f_1_ECX,    13
InstructionSetInline SSE41,         f_1_ECX,    19
InstructionSetInline SSE42,         f_1_ECX,    20
InstructionSetInline MOVBE,         f_1_ECX,    22
InstructionSetInline POPCNT,        f_1_ECX,    23
InstructionSetInline AES,           f_1_ECX,    25
InstructionSetInline XSAVE,         f_1_ECX,    26
InstructionSetInline OSXSAVE,       f_1_ECX,    27
InstructionSetInline AVX,           f_1_ECX,    28
InstructionSetInline F16C,          f_1_ECX,    29
InstructionSetInline RDRAND,        f_1_ECX,    30
InstructionSetInline MSR,           f_1_EDX,     5
InstructionSetInline CX8,           f_1_EDX,     8
InstructionSetInline SEP,           f_1_EDX,    11
InstructionSetInline CMOV,          f_1_EDX,    15
InstructionSetInline CLFSH,         f_1_EDX,    19
InstructionSetInline MMX,           f_1_EDX,    23
InstructionSetInline FXSR,          f_1_EDX,    24
InstructionSetInline SSE,           f_1_EDX,    25
InstructionSetInline SSE2,          f_1_EDX,    26
InstructionSetInline FSGSBASE,      f_7_EBX,     0
InstructionSetInline BMI1,          f_7_EBX,     3
InstructionSetInline HLE,           f_7_EBX,     4, isIntel
InstructionSetInline AVX2,          f_7_EBX,     5
InstructionSetInline BMI2,          f_7_EBX,     8
InstructionSetInline ERMS,          f_7_EBX,     9
InstructionSetInline INVPCID,       f_7_EBX,    10
InstructionSetInline RTM,           f_7_EBX,    11, isIntel
InstructionSetInline AVX512F,       f_7_EBX,    16
InstructionSetInline RDSEED,        f_7_EBX,    18
InstructionSetInline ADX,           f_7_EBX,    19
InstructionSetInline AVX512PF,      f_7_EBX,    26
InstructionSetInline AVX512ER,      f_7_EBX,    27
InstructionSetInline AVX512CD,      f_7_EBX,    28
InstructionSetInline SHA,           f_7_EBX,    29
InstructionSetInline PREFETCHWT1,   f_7_ECX,     0
InstructionSetInline LAHF,          f_81_ECX,    0
InstructionSetInline LZCNT,         f_81_ECX,    5, isIntel
InstructionSetInline ABM,           f_81_ECX,    5, isAMD
InstructionSetInline SSE4a,         f_81_ECX,    6, isAMD
InstructionSetInline XOP,           f_81_ECX,   11, isAMD
InstructionSetInline TBM,           f_81_ECX,   21, isAMD
InstructionSetInline SYSCALL,       f_81_EDX,   11, isIntel
InstructionSetInline MMXEXT,        f_81_EDX,   22, isAMD
InstructionSetInline RDTSCP,        f_81_EDX,   27, isIntel
InstructionSetInline 3DNOWEXT,      f_81_EDX,   30, isAMD
InstructionSetInline 3DNOW,         f_81_EDX,   31, isAMD

The main code will then be the same and the INLINE (macro) versus EXTERN (proto) issue is controlled by the header.
Code: [Select]
include stdio.inc
include tchar.inc

include InstructionSet.inc

    .data
    count int_t 0

    .code

support_message proc isa_feature:string_t, is_supported:int_t

    .if is_supported

        printf( "%-16s", isa_feature )
        inc count
    .endif

    .if count == 4

        mov count,0
        printf( "\n\t" )
    .endif
    ret

support_message endp

main proc

    .new cpu:InstructionSet()

    printf(
        "\n"
        "CPU Information\n"
        "\n"
        " Vendor: %s\n", cpu.GetVendor() )
    printf(
        " Brand:  %s\n"
        "\n"
        " Supported features:\n"
        "\n\t", cpu.GetBrand() )

    support_message("MMX",         cpu.GetMMX())
    support_message("SSE",         cpu.GetSSE())
    support_message("SSE2",        cpu.GetSSE2())
    support_message("SSE3",        cpu.GetSSE3())
    support_message("SSE4.1",      cpu.GetSSE41())
    support_message("SSE4.2",      cpu.GetSSE42())
    support_message("SSE4a",       cpu.GetSSE4a())
    support_message("SSSE3",       cpu.GetSSSE3())
    support_message("AVX",         cpu.GetAVX())
    support_message("AVX2",        cpu.GetAVX2())
    support_message("AVX512CD",    cpu.GetAVX512CD())
    support_message("AVX512ER",    cpu.GetAVX512ER())
    support_message("AVX512F",     cpu.GetAVX512F())
    support_message("AVX512PF",    cpu.GetAVX512PF())
    support_message("3DNOW",       cpu.Get3DNOW())
    support_message("3DNOWEXT",    cpu.Get3DNOWEXT())
    support_message("ABM",         cpu.GetABM())
    support_message("ADX",         cpu.GetADX())
    support_message("AES",         cpu.GetAES())
    support_message("BMI1",        cpu.GetBMI1())
    support_message("BMI2",        cpu.GetBMI2())
    support_message("CLFSH",       cpu.GetCLFSH())
    support_message("CMPXCHG16B",  cpu.GetCMPXCHG16B())
    support_message("CX8",         cpu.GetCX8())
    support_message("ERMS",        cpu.GetERMS())
    support_message("F16C",        cpu.GetF16C())
    support_message("FMA",         cpu.GetFMA())
    support_message("FSGSBASE",    cpu.GetFSGSBASE())
    support_message("FXSR",        cpu.GetFXSR())
    support_message("HLE",         cpu.GetHLE())
    support_message("INVPCID",     cpu.GetINVPCID())
    support_message("LAHF",        cpu.GetLAHF())
    support_message("LZCNT",       cpu.GetLZCNT())
    support_message("MMXEXT",      cpu.GetMMXEXT())
    support_message("MONITOR",     cpu.GetMONITOR())
    support_message("MOVBE",       cpu.GetMOVBE())
    support_message("MSR",         cpu.GetMSR())
    support_message("OSXSAVE",     cpu.GetOSXSAVE())
    support_message("PCLMULQDQ",   cpu.GetPCLMULQDQ())
    support_message("POPCNT",      cpu.GetPOPCNT())
    support_message("PREFETCHWT1", cpu.GetPREFETCHWT1())
    support_message("RDRAND",      cpu.GetRDRAND())
    support_message("RDSEED",      cpu.GetRDSEED())
    support_message("RDTSCP",      cpu.GetRDTSCP())
    support_message("RTM",         cpu.GetRTM())
    support_message("SEP",         cpu.GetSEP())
    support_message("SHA",         cpu.GetSHA())
    support_message("SYSCALL",     cpu.GetSYSCALL())
    support_message("TBM",         cpu.GetTBM())
    support_message("XOP",         cpu.GetXOP())
    support_message("XSAVE",       cpu.GetXSAVE())
    printf( "\n\n" )
    ret

main endp

    end _tstart

CPU Information

 Vendor: GenuineIntel
 Brand:  Intel(R) Core(TM) i5-6500T CPU @ 2.50GHz

 Supported features:

        MMX             SSE             SSE2            SSE3
        SSE4.1          SSE4.2          SSSE3           AVX
        AVX2            ADX             AES             BMI1
        BMI2            CLFSH           CMPXCHG16B      CX8
        ERMS            F16C            FMA             FSGSBASE
        FXSR            HLE             INVPCID         LAHF
        LZCNT           MONITOR         MOVBE           MSR
        OSXSAVE         PCLMULQDQ       POPCNT          RDRAND
        RDSEED          RDTSCP          RTM             SEP
        SYSCALL         XSAVE

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #16 on: December 29, 2019, 04:05:59 AM »
Added a few extensions to the macro call and a .template directive. This is the same as CLASS and COMDEF but without any default constructor or V-table pointer.

The limits for macros is max registers in FASTCALL (4) and SYSCALL (14). Arguments are sized up according to the proto type.

.template F fastcall

    m_db db ?
    m_dw dw ?
    m_r4 real4 ?

    Init    proc :word, :byte, :real4
    .ends

.template S syscall

    m_db db ?
    m_dw dw ?
    m_dd dd ?
    m_dq dq ?
    m_r4 real4 ?

    Init    proc :word, :byte, :real4, :qword, :dword
    .ends

The arguments may then be used directly without knowing the actual value.

F_Init macro this, a, b, c          ; rcx, dx, r8b, xmm3
    assume this:ptr F
    mov [this].m_dw,a
    mov [this].m_db,b
    exitm<movss [this].m_r4,c>
    endm

S_Init macro this, a, b, c, d, e    ; rdi, si, dl, xmm0, rcx, r8d
    assume this:ptr S
    mov [this].m_dw,a
    mov [this].m_db,b
    movss [this].m_r4,c
    mov [this].m_dq,d
    exitm<mov [this].m_dd,e>
    endm

This is just regular types.

  local f:F, s:S

Arguments are parsed by the INVOKE directive.

    f.Init(s.m_dw,s.m_db,3.0)
    s.Init(f.m_dw,f.m_db,f.m_r4,4,5)

        mov     eax, 1077936128
        movd    xmm3, eax
        mov     r8b, byte ptr [rbp-20H]
        mov     dx, word ptr [rbp-1FH]
        lea     rcx, [rbp-9H]

        mov     r8d, 5
        mov     ecx, 4
        movd    xmm0, dword ptr [rbp-6H]
        mov     dl, byte ptr [rbp-9H]
        mov     si, word ptr [rbp-8H]
        lea     rdi, [rbp-20H]

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #17 on: February 21, 2020, 08:55:04 AM »
Been playing with vector definitions and translated some of the header files:

- dvect.inc

/*
 *  Definition of a C++ class interface to Intel(R) Pentium(R) 4 processor SSE2 intrinsics.
 *
 *  File name : dvec.h  class definitions
 *
 *  Concept: A C++ abstraction of Intel(R) Pentium(R) 4 processor SSE2
 *      designed to improve programmer productivity.  Speed and accuracy are
 *      sacrificed for utility.  Facilitates an easy transition to compiler
 *      intrinsics or assembly language.
 *
 */

- fvec.inc

/*
 *  Definition of a C++ class interface to Streaming SIMD Extension intrinsics.
 *
 *
 *  File name : fvec.h  Fvec class definitions
 *
 *  Concept: A C++ abstraction of Streaming SIMD Extensions designed to improve
 *
 *  programmer productivity.  Speed and accuracy are sacrificed for utility.
 *
 *  Facilitates an easy transition to compiler intrinsics
 *
 *  or assembly language.
 *
 *  F32vec4:    4 packed single precision
 *              32-bit floating point numbers
*/

In addition a simple test file: dvec.asm

To accomplish this a directive (.operator) is added and a new argument type (:ABS) for immediate values.

.OPERATOR [ name | OP ] [[ : args ]] [[ { ... } ]]

Arithmetic Operators

    Operator        Name  Description

    .operator +     radd  - Add
    .operator -     rsub  - Subtract
    .operator *     rmul  - Multiply
    .operator /     rdiv  - Divide
    .operator %     rmod  - Modulus
    .operator ++    rinc  - Increment
    .operator --    rdec  - Decrement

Bitwise Operators

    .operator &     rand  - Binary AND Operator
    .operator |     ror   - Binary OR Operator
    .operator ^     rxor  - Binary XOR Operator
    .operator ~     rnot  - Binary Ones Complement Operator
    .operator &~    randn - Binary AND NOT Operator
    .operator <<    rshl  - Binary Left Shift Operator
    .operator >>    rshr  - Binary Right Shift Operator

Assignment Operators

    .operator =     mequ  - Simple assignment operator
    .operator +=    madd  - Add AND assignment operator
    .operator -=    msub  - Subtract AND assignment operator
    .operator *=    mmul  - Multiply AND assignment operator
    .operator /=    mdiv  - Divide AND assignment operator
    .operator %=    mmod  - Modulus AND assignment operator
    .operator ~=    mnot  - Bitwise NOT assignment operator
    .operator <<=   mshl  - Left shift AND assignment operator
    .operator >>=   mshr  - Right shift AND assignment operator
    .operator &=    mand  - Bitwise AND assignment operator
    .operator &~=   mandn - Bitwise AND NOT assignment operator
    .operator ^=    mxor  - Bitwise exclusive OR and assignment operator
    .operator |=    mand  - Bitwise inclusive OR and assignment operator

The size of the three first parameters are added to the name.

    .operator = :qword, :dword { ; mequ84
        mov [this],_1
        retm<this>
        }

Inline functions are rendered as macros with fixed argument names. The name may hold a register, a memory location or immediate value depending on calling convention.

    class_mequ84 macro this, _1, _2
        mov [this],_1
        retm<this>
        endm

Immediate values must be defined as :ABS.

    .operator >> :abs { exitm<_mm_srli_epi64(xmm0, _1)> }

The classes are defined as templates and thus not a real class so the whole concept is a pure virtual construct. This means the size of the object is equal to the size of the vector used.

Example.

;; 1 element, a __m128i data type

.template M128
    vec __m128i <>

    .operator = :vec128_t {
        exitm<_mm_store_ps([this], _1)>
        }
    .operator __m128i {
        exitm<_mm_store_ps(xmm0, [this])>
        }
    .operator &= :vec128_t {
        _mm_and_si128(xmm0, _1)
        exitm<_mm_store_ps([this],xmm0)>
        }
    .operator |= :vec128_t {
        _mm_or_si128(xmm0, _1)
        exitm<_mm_store_ps([this],xmm0)>
        }
    .operator ^= :vec128_t {
        _mm_xor_si128(xmm0, _1)
        exitm<_mm_store_ps([this],xmm0)>
        }
    .operator & :vec128_t {
        exitm<_mm_and_si128(xmm0, _1)>
        }
    .operator | :vec128_t {
        exitm<_mm_or_si128(xmm0, _1)>
        }
    .operator ^ :vec128_t {
        exitm<_mm_xor_si128(xmm0, _1)>
        }
    .operator andnot :vec128_t {
        exitm<_mm_andnot_si128(xmm0, _1)>
        }
    .ends

Test case:

test_M128 proc v:ptr M128

    assume rcx:ptr M128

    [rcx].mequ16    (xmm1)
    [rcx].__m128i   ()
    [rcx].mand16    (xmm1)
    [rcx].mor16     (xmm1)
    [rcx].mxor16    (xmm1)
    [rcx].rand16    (xmm1)
    [rcx].ror16     (xmm1)
    [rcx].rxor16    (xmm1)
    [rcx].andnot    (xmm1)
    ret

test_M128 endp

Code produced:

        push    rbp                                     
        mov     rbp, rsp                               
        sub     rsp, 32                                 
        movaps  xmmword ptr [rcx], xmm1                 
        movaps  xmm0, xmmword ptr [rcx]                 
        pand    xmm0, xmm1                             
        movaps  xmmword ptr [rcx], xmm0                 
        por     xmm0, xmm1                             
        movaps  xmmword ptr [rcx], xmm0                 
        pxor    xmm0, xmm1                             
        movaps  xmmword ptr [rcx], xmm0                 
        pand    xmm0, xmm1                             
        por     xmm0, xmm1                             
        pxor    xmm0, xmm1                             
        pandn   xmm0, xmm1                             
        leave                                           
        ret                                             

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #18 on: May 08, 2020, 06:36:13 AM »
A sample from the GDI+ classes.
Code: [Select]
include windows.inc
include gdiplus.inc
include tchar.inc

    .code

WndProc proc hWnd:HWND, message:UINT, wParam:WPARAM, lParam:LPARAM

    .switch edx

    .case WM_PAINT

       .new ps:PAINTSTRUCT

        BeginPaint(rcx, &ps)

       .new G:Graphics()
        .if G.FromHDC2(ps.hdc, rax) == Ok

           .new P1:PointF(0.0, 0.0)
           .new P2:PointF(300.0, 300.0)
           .new B:LinearGradientBrush()

            B.Create(&P1, &P2, Red, Blue)
            G.FillRectangleI(&B, 0, 0, 300, 300)
            B.Release()
        .endif
        G.Release()
        EndPaint(hWnd, &ps)
        .endc

    .case WM_DESTROY
        PostQuitMessage(0)
        .endc
    .default
        .return DefWindowProc(rcx, edx, r8, r9)
    .endsw
    xor eax,eax
    ret

WndProc endp

_tWinMain proc hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPTSTR, nShowCmd:SINT

  local wc:WNDCLASSEX, msg:MSG, hwnd:HANDLE

    xor eax,eax
    mov wc.cbSize,          WNDCLASSEX
    mov wc.style,           CS_HREDRAW or CS_VREDRAW
    mov wc.cbClsExtra,      eax
    mov wc.cbWndExtra,      eax
    mov wc.hbrBackground,   COLOR_WINDOW+1
    mov wc.lpszMenuName,    rax
    mov wc.hInstance,       hInstance
    mov wc.lpfnWndProc,     &WndProc
    mov wc.lpszClassName,   &@CStr("Gradient")
    mov wc.hIcon,           LoadIcon(0, IDI_APPLICATION)
    mov wc.hIconSm,         rax
    mov wc.hCursor,         LoadCursor(0, IDC_ARROW)

    .ifd RegisterClassEx(&wc)

        .if CreateWindowEx(0, "Gradient", "gdiplus.Graphics(Gradient)", WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, 0)

            mov hwnd,rax

            ;; Initialize GDI+.
            .new gdiplus:ptr GdiPlus()

            ShowWindow(hwnd, SW_SHOWNORMAL)
            UpdateWindow(hwnd)

            .while GetMessage(&msg,0,0,0)
                TranslateMessage(&msg)
                DispatchMessage(&msg)
            .endw
            gdiplus.Release()
            mov rax,msg.wParam
        .endif
    .endif
    ret

_tWinMain endp

    end _tstart

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #19 on: May 08, 2020, 06:47:13 AM »
Another one drawing a sphere.

source for the translated samples:
http://www.johnfindlay.plus.com/pellesc/GdiPlus/GdiPlus.html
Code: [Select]
include windows.inc
include gdiplus.inc
include tchar.inc

    .code

WndProc proc hWnd:HWND, message:UINT, wParam:WPARAM, lParam:LPARAM

    .switch edx

    .case WM_PAINT

       .new ps:PAINTSTRUCT
       .new count:SINT
       .new FullTranslucent:ARGB
       .new g:Graphics()

        BeginPaint(hWnd, &ps)

        g.FromHDC(ps.hdc)

        ; Create a GraphicsPath object
       .new p:GraphicsPath()

        ; Add an ellipse to the path
        p.AddEllipse(200, 0, 200, 200)

        ; Create a path gradient based on the ellipse
       .new b:PathGradientBrush(&p)

        ; Set the middle color of the path
        b.SetCenterColor(ColorAlpha(Green, 180))

        ; Set the entire path boundary to Alpha Black using translucency
        mov count,1
        mov FullTranslucent,ColorAlpha(Black, 230)
        b.SetSurroundColors(&FullTranslucent, &count)

        ; Draw the ellipse, keeping the exact coords we defined for the path
        ; We use AntiAlias drawing mode.
        ; To get a better antialising we enlarge area (+2 and -4).
        g.SetSmoothingMode(SmoothingModeAntiAlias)
        g.FillEllipseI(&b, 200 + 2, 0 + 2, 200 - 4, 200 - 4)

        b.Release()
        p.Release()

        ; Second Sphere

       .new p:GraphicsPath()

        p.AddEllipse(200, 100, 150, 150)

       .new b:PathGradientBrush(&p)

        b.SetCenterColor(ColorAlpha(Yellow, 180))
        mov FullTranslucent,ColorAlpha(Red, 200)
        mov count,1
        b.SetSurroundColors(&FullTranslucent, &count)
        g.FillEllipseI(&b, 200 + 2, 100 + 2, 150 - 4, 150 - 4)

        b.Release()
        p.Release()
        g.Release()
        EndPaint(hWnd, &ps)
        .endc

    .case WM_DESTROY
        PostQuitMessage(0)
        .endc
    .case WM_CHAR
        .gotosw(WM_DESTROY) .if r8d == VK_ESCAPE
        .endc
    .default
        .return DefWindowProc(rcx, edx, r8, r9)
    .endsw
    xor eax,eax
    ret

WndProc endp

_tWinMain proc hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPTSTR, nShowCmd:SINT

  local wc:WNDCLASSEX, msg:MSG, hwnd:HANDLE

    xor eax,eax
    mov wc.cbSize,          WNDCLASSEX
    mov wc.style,           CS_HREDRAW or CS_VREDRAW
    mov wc.cbClsExtra,      eax
    mov wc.cbWndExtra,      eax
    mov wc.hbrBackground,   COLOR_WINDOW+1
    mov wc.lpszMenuName,    rax
    mov wc.hInstance,       hInstance
    mov wc.lpfnWndProc,     &WndProc
    mov wc.lpszClassName,   &@CStr("Sphere")
    mov wc.hIcon,           LoadIcon(0, IDI_APPLICATION)
    mov wc.hIconSm,         rax
    mov wc.hCursor,         LoadCursor(0, IDC_ARROW)

    .ifd RegisterClassEx(&wc)

        .if CreateWindowEx(0, "Sphere", "gdiplus.Graphics(Sphere)", WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, NULL, NULL, hInstance, 0)

            mov hwnd,rax

            ;; Initialize GDI+.
            .new gdiplus:ptr GdiPlus()

            ShowWindow(hwnd, SW_SHOWNORMAL)
            UpdateWindow(hwnd)

            .while GetMessage(&msg,0,0,0)
                TranslateMessage(&msg)
                DispatchMessage(&msg)
            .endw
            gdiplus.Release()
            mov rax,msg.wParam
        .endif
    .endif
    ret

_tWinMain endp

    end _tstart
« Last Edit: May 23, 2020, 11:07:03 AM by nidud »

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #20 on: May 13, 2020, 11:29:44 PM »
Some changes added to construction of classes.

- Constructors must now be added to the class and arguments definition for the type is ignored.
- Constructors added inside a class will not be a member of the class but defined as a PROTO type.

Example:

.template template

    atom        db ?

    template    proc :ptr
    Release     proc

    .ends

    template_template proto :ptr template, :ptr

    template struct
    atom db ?
    template ends

    templateVtbl struct
    Release P$0001 ?
    templateVtbl ends

A class or comdef will add a pointer:

.class class : public template

    class proc :ptr

    .ends

    class_class proto :ptr class, :ptr

    class struct 8
    lpVtbl LPCLASSVtbl ?
    template <>
    class ends

    classVtbl struct
    templateVtbl <>
    classVtbl ends

But only if lpVtbl don't exist:

.class class1 : public class

    .operator class1 :ptr {
        exitm<class(_1)>
        }

    .ends

    class1_class1 proto :ptr class1, :ptr
    class1_class1 macro this, _1
    exitm<class(_1)>
    endm

    class1 struct 8
    class <>
    class1 ends

    class1Vtbl struct
    classVtbl <>
    class1Vtbl ends

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #21 on: May 23, 2020, 10:48:58 AM »
Some new changes.

In the GDI+ classes (and others) you have duplicated names for constructors and other functions. The inline macros may now have unused arguments as normally is the case in macros in general. However, these arguments needs to be declared as :ABS for operators.

Default values may then be used, and input with the same arg-count but different size may share the same name. A test case for drawing a Path using a Pen with default values and AddLine for both float and integer values.

This sample draws a person: https://www.codemag.com/article/0305031



        Person.AddEllipse(23, 1, 14, 14)
        Person.AddLine(18, 16, 42, 16)
        Person.AddLine(50, 40, 44, 42)
        Person.AddLine(38, 25, 37, 42)
        Person.AddLine(45, 75, 37, 75)
        Person.AddLine(30, 50, 23, 75)
        Person.AddLine(16, 75, 23, 42)
        Person.AddLine(22, 25, 16, 42)
        Person.AddLine(10, 40, 18, 16)

The Pen constructor defaults to 1.0, and Path/Scale also have additional arguments.

        .new Person:GraphicsPath()
        .new p:Pen(Blue)

        g.ScaleTransform(4.0, 4.0)
        g.DrawPath(&p, &Person)
        g.ResetTransform()

jj2007

  • Member
  • *****
  • Posts: 10260
  • Assembler is fun ;-)
    • MasmBasic
Re: Object-oriented programming (OOP) in Asmc
« Reply #22 on: May 23, 2020, 08:19:14 PM »

nidud

  • Member
  • *****
  • Posts: 1923
    • https://github.com/nidud/asmc
Re: Object-oriented programming (OOP) in Asmc
« Reply #23 on: May 26, 2020, 06:16:01 AM »
Some new additions to the MACRO/PROC merger.

proc  :vararg
macro :vararg
...
    .operator :vararg {
        exitm<>
        }

This combination is difficult to reason with so the macro needs the actual arg-list here. Invoke will skip loading arguments when the vararg start so in this case only RCX will be loaded. The macro receives the list but skips the ADDR prefix of the class, so this assumes a reference to a static class.

    Pen proc :vararg
    Pen_Pen macro this, _1, _2:=<1.0>, _3:=<0>
        ifb <_1>
            this.Pen0()
        elseif typeof(_1) eq 2
            this.Pen1(_1, _2, _3, rcx)
        else
            this.Pen2(_1, _2)
        endif
        lea rax,this
        exitm<>
        endm

typeof() will now accept an ADDR prefix so typeof(_1) --> typeof(addr p) = 8.
Note that this above is not a pointer here but a reference to the actual class. This means you dont need to save it between calls. The list is passed as a regular macro list.

    echo this
    for arg,<_1>
        echo arg
        endm

The GDI+ sample above is now written as a test for this concept, using static objects, and it cleans up very well. The code size for the GDI part is 910, total of 1389 byte. So, easy to use with minimum overhead.

Very nice, and thanks for the inspiration :thumbsup:

 :biggrin:

Nice to inspire so maybe consider using a modular library too?

The code should be less than 5K but is now above 50K.
« Last Edit: May 26, 2020, 07:31:28 AM by nidud »