Announcement

Collapse
No announcement yet.

Assembler notation for arrays in PowereBASIC

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Assembler notation for arrays in PowereBASIC

    I sometimes get asked about the notation used in current 32 bit Intel x86
    assembler when you get complex looking expressions in code like,
    Code:
        mov eax, [esi+ecx*4+4]
    One of the good things about PowerBASIC is its full capacity in writing
    code in direct assembler, a slightly different concept to what many other
    languages call "inline assembler".

    The basic notation mentioned above is related to dealing with addresses in
    memory. By a simple mechanism, you can obtain the "value" at a given address
    in memory by what is called "dereferencing".

    If we create a simple PowerBASIC array in 32 bit LONG integers,
    Code:
        redim Arr(0 to 3) as LONG
    and fill it with numbers,
    Code:
        Arr(0) = 10
        Arr(1) = 20
        Arr(2) = 30
        Arr(3) = 40
    We now have 4 LONG values that follow each other in memory. Getting the
    starting address is a simple function in PowerBASIC.
    Code:
        lpArr = VarPtr(Arr(0))
    We then use the assembler to copy the address into a register.
    Code:
        ! mov esi, lpArr    ; copy address into ESI
    If you check the number in ESI, it will be a DWORD size number that is an address
    in memory. To get the "value" of the number AT that address, the address must
    be "dereferenced". This is done by the following notation.
    Code:
        ! mov esi, [esi]
    If you check the contents of ESI now, it will have the number in the array element,
    Arr(0) which is 10. Note that the register that the address is "dereferenced" into
    need not be the same register withing the square brackets, it can be any available
    register.

    This is fine for the first element but there is a notation that allows access at
    any other element as well. In Intel assembler there is a build in capacity to
    produce the required offset to get any value.

    The notation is broken down as follows.

    With an instruction like,
    Code:
        ! mov eax, [esi+ecx*4+4]
    there are 4 elements that can be used to calculate the address of the member of the
    array that is required.
    Code:
        Base address    Index    Scale    Displacement
         [  ESI    +     ECX  *    4   +       4  ]
    We already have the base address in the ESI register. The "INDEX" and "SCALE" work
    together to address the array element by its number in the array multiplied by the
    size of the array element which in this case is 4 bytes. The displacement can be
    added if it is required to change the memory offset by a set amount.

    Now to get array element 2, we set the ECX register to that number and then copy the
    value at the correct location to another register.
    Code:
        ! mov ecx, 2
        ! mov eax, [esi+ecx*4]
    The register EAX now holds the value in the 3rd element of the array which is 30.

    The real use of this technique is when you have to sequentially read or write to
    members of the array. By making a loop that increments or decrements ECX, the
    members of the array can be scanned in sequence at very high speed because of the
    minimum amount of code required to do the scan.

    Scan the array forward.
    Code:
        ! xor ecx, ecx              ; set ECX to 0
      label:
        ! mov eax, [esi+ecx*4]      ; copy the value into EAX
        ! inc ecx                   ; increment ECX
        ! cmp ecx, 4                ; see if its at the end of the array
        ! jne label                 ; jump back to loop start if its not
    Scan the array in reverse.
    Code:
        ! mov ecx, 3
      label:
        ! mov eax, [esi+ecx*4]      ; copy the value into EAX
        ! dec ecx                   ; decrement ECX
        ! jnz label                 ; if ECX is NOT zero jump to label
    If you wanted to increment every member of the array, the code is very simple.
    Code:
        ! mov ecx, 4
      label:
        ! inc [esi+ecx*4]           ; increment the value in memory
        ! dec ecx                   ; decrement ECX
        ! jnz label                 ; if ECX is NOT zero jump to label
    For PowerBASIC programmers who have to work with arrays at high speed, this
    built in capacity in the inline assembler allows you to do things that can
    dramatically increase the speed of the operations being performed.

    Regards,

    [email protected]

    PS. Sorry about the typos, its getting a bit late here.

    [This message has been edited by Steve Hutchesson (edited September 11, 2001).]
    hutch at movsd dot com
    The MASM Forum

    www.masm32.com

  • #2
    Steve, I always find your little assembly tutorials not only interesting and fairly easy to understand (considering im an assembly klutz) but also very useful, thanks (again and again) for taking the time to share your amazing knowledge


    ------------------
    -

    Comment


    • #3
      Yes, I agree - thanks a lot for these valuable snippets of information,
      Steve. They are always highly apprechiated, be sure of that.


      ------------------

      Comment


      • #4
        I could not agree more. I learn more from these tutorials than
        I have from any book. Thank you very much for these postings.
        Who knows, one day I may even master MASM32.

        ------------------

        Comment


        • #5
          Here is a simple algorithm that does something useful that shows
          the technique above. It swaps the lowest member with the highest
          and in each iteration of the loop it swaps the next highest with
          the next lowest until it reaches the middle.

          Regards,

          [email protected]

          Code:
            ' #########################################################################
            
            SUB ArayReverse(ByVal Arr as LONG,ByVal cnt as LONG)
            
                #REGISTER NONE
            
                ! mov esi, Arr
                ! xor ecx, ecx      ; set ecx to zero
                ! mov edx, cnt      ; set edx to array count
                ! dec edx
            
              arLbl:
                ! mov eax, [esi+ecx*4]
                ! mov ebx, [esi+edx*4]
                ! mov [esi+edx*4], eax
                ! mov [esi+ecx*4], ebx
                ! inc ecx
                ! dec edx
                ! cmp ecx, edx
                ! jle arLbl
            
            END SUB
            
            ' #########################################################################
          PS. Thanks guys, I have always appreciated the work that many of
          the forums members do and share with other so i try when I have
          the time to contribute something back.

          ------------------


          [This message has been edited by Steve Hutchesson (edited September 11, 2001).]
          hutch at movsd dot com
          The MASM Forum

          www.masm32.com

          Comment


          • #6
            Steve,

            Would that instruction be faster than the instruction pair:

            Code:
            mov eax, [esi]
            add esi, 4
            I'm just wondering which instruction(s) would make the fastest loop. I haven't been keeping up with instruction timing for a long time.

            And thanks for your insights,


            Peter.


            ------------------
            [email protected]
            [email protected]

            Comment


            • #7
              Peter,

              The method you have suggested is quite useful but it has the
              problem that it modifies ESI which makes multiple value
              manipulation difficult to do where controlling the index allows
              different values to be manipulated without effecting the base
              address.

              I have found that INC is usually a bit faster than ADD in an
              intensive loop but in most instances it does not matter much.

              Regards,

              [email protected]

              ------------------
              hutch at movsd dot com
              The MASM Forum

              www.masm32.com

              Comment


              • #8
                Steve,
                Do you think PowerBasic is a good Basic compiler with builtin Assembler,
                or a good Assembler which happens to compile Basic too?


                ------------------
                Thanks,

                John Kovacich
                Ivory Tower Software
                www.i-tower.com

                Try MsgBoxPlus for easy MSGBOX's with custom buttons and graphic backgrounds.
                Thanks,

                John Kovacich
                Ivory Tower Software

                Comment


                • #9
                  John,

                  Funny enough I have usually referred to PowerBASIC as the best C
                  compiler I have ever used. I come from a background of assembler,
                  basic and C and it is a lot to do with why I code in PowerBASIC
                  because of its capacity to manage the architecture of all three.

                  If does the C architecture of windows well, can manage traditional
                  basic with very few problems at all and when you need it, it does
                  MASM style assembler very well.

                  Now the only problem I can see if we spread this view around too
                  much is that we may end up with Pascal, Fortran, Forth and Cobol
                  capacity as well.

                  Regards,

                  [email protected]

                  ------------------
                  hutch at movsd dot com
                  The MASM Forum

                  www.masm32.com

                  Comment

                  Working...
                  X