No announcement yet.

ASM & Pointers

  • Filter
  • Time
  • Show
Clear All
new posts

  • Walt Decker
    Thank you for your time, Mr. Grant. I thought that may be the case although I was hoping that since the compiler can handle something like:

    @aPtr = @aPtr + @bPtr

    it could handle something like:

    ! mov AX,@aPtr
    ! mov Bh,@bPtr

    without choaking. Oh, well. Such is life.

    Thanks again for your time and effort.


    Leave a comment:

  • G Grant
    I've got some time to kill, so bear with me.

    As far as the inline assembler is concerned, PowerBASIC's pointer
    variables are nothing more than DWORD variables.
    To point to (and retrieve) the contents of a variable with inline ASM,
    you must specify the 32 bit segmentffset address yourself. VARPTR32
    stores the 32 bit address of a variable in a DWORD variable (which is
    basically what a pointer variable is). So in this case, there's really
    no need to use a pointer variable, unless you use it elsewhere in
    your BASIC code.

    Once you've got the address of the variable, you have to load it
    into a segmentffset register pair. Actually, inline ASM does
    recognize predefined BASIC variables and thier values. So its ok
    to use a WORD or INTEGER variable as the offset portion of an
    address. I'm using registers only for simplicity. Note that you
    MUST use a segment register for the segment portion of an address.

    Segment registers are DS, ES, CS, and SS.
    CS points to the Code Segment, which is where the program code is stored.
    SS points to the Stack Segment, and should NOT be changed.

    DS is the default Data Segment register, and it points to the 64K
    segment that will be referenced if no segment is specified (usually).
    If you change the contents of DS, be sure to restore it before the
    routine ends, else you'll likely crash. Use PUSH DS to save it and
    POP DS to restore (following the Last In First Out rule of POPing
    from the stack, meaning POP registers in the reverse order in which
    they were PUSHed, if you push more than one register).
    After changing the contents of DS, you won't be able to access your
    global (main and PUBLIC) variables by name until you restore DS, since
    PowerBASIC looks for these variables in the data segment (DS).

    ES is the Extra Segment register. As the name implies, this is a
    general purpose segment register, and can be used anywhere that
    DS can, except when using ASM string commands (it has a specific
    use in that case). Unlike DS, you'll need to specify ES if you wish
    to use it as your segment register. Just add ES: in front of the
    source or destination operand, such as:
    ! MOV ES:[DI], AX
    ! MOV AX, ES:[DI]
    Without the ES:, the data segment (DS) would be used by default.

    Offset registers are SI, DI, BX, BP, and SP.
    SP is the Stack Pointer and should NOT be changed directly (normally).

    To make one of these registers point to an address relative to its
    default segment, enclose it in brackets:
    ! MOV AX, [BX]

    The brackets tell the assembler to reference the address pointed to
    by BX (BX becomes a pointer), in the data segment (DS), since that
    is the default segment for BX.
    (Without the brackets, BX becomes a simple 16 bit data register, not
    a pointer).
    So the above is equivalent to:
    ! MOV AX, DS:[BX]

    The segment overide prefix (which is what specifying a segment is
    called) should not be used when it is already the default segment,
    because it imposes an unnecessary inefficiency.

    By default, SI, DI (usually), and BX, when used as offset registers,
    will point to an address relative to the data segment (DS).

    BP (Base Pointer), on the other hand, will, by default, point to
    an address relative to the stack segment (SS). To point to an address
    within the data segment with BP, you must specify DS as the segment
    to use.
    ! MOV AX, DS:[BP]
    BP is normally used to temporarily save and restore the SP register
    (to create what is called a stack frame of reference, for parameter
    passing and return addresses), which is why it is relative to the
    stack segment by default. But as long as you save BP before using
    it and restore it when you're done with it, it can be used like
    any other offset register (except that it's stack segment relative
    by default).
    After changing the contents of BP, you won't be able to access your
    local and paramater passed variables by name until you restore BP,
    since PowerBASIC looks for these variables using BP.

    Since I've gone this far, I'll mention the remaining registers.

    The general purpose registers are:
    AX (Accumulator. THE general purpose register)
    BX (Base register. Can be used as an offset register as shown above)
    CX (Counter register. Automatically decremented in looping or repeating instructions)
    DX (Data register. Used for I/O ports above 255 and MSW of multiplication and division)

    The general purpose registers can be referenced 8 bits at a time
    by their 8 bit counterparts:
    AX(16 bits). AL(lower 8 bits of AX). AH(upper 8 bits of AX)
    BX(16 bits). BL(lower 8 bits of BX). BH(upper 8 bits of BX)
    CX(16 bits). CL(lower 8 bits of CX). CH(upper 8 bits of CX)
    DX(16 bits). DL(lower 8 bits of DX). DH(upper 8 bits of DX)

    Now, with all that out of the way, there's an easy way to get the
    DWORD value of VARPTR32 into a 32 bit segmentffset register pair:

    LDS offset register, value
    LES offset register, value

    LDS loads DS and an offset register with the 32 bit value.
    LES loads ES and an offset register with the 32 bit value.

    If you prefer, you can use VARSEG and VARPTR to get the segment
    and offset portions of the address seperately, and then load the
    appropriate segment and/or offset registers as needed. Just remember,
    if you load DS with a value first, then you won't be able to reference
    your BASIC offset variable by name if it is a global (main or PUBLIC)
    variable until DS is restored. So load the offset value first if you
    need to use DS as your segment register (and you're using global
    variables). Also, segment registers cannot be loaded from memory or
    variables. They must be loaded from other registers. So you must
    store the segment value in a non segment register first, then load
    it from there into the segment register.

    Destination operands are on the left.
    Source operands are on the right.
    Data cannot be moved from memory to memory directly. It must move
    to or from a register.
    Registers that must be preserved are:
    SI, DI, BP, SP, DS, SS.

    So finally, here is what you might use:


    A = 15
    B = 20
    aPtr = VARPTR32(A)
    bPtr = VARPTR32(B)

    ! PUSH DS
    ! PUSH SI
    ! PUSH DI
    ! LES DI, bPtr ;address of B in ESI
    ! LDS SI, aPtr ;address of A in DS:SI
    ! MOV AX, [SI] ;this loads 16 bits, since that's the size of the destination register (AX).
    ! MOV BL, ES:[DI] ;this loads 8 bits, since that's the size of the destination register (BL).
    ! POP DI
    ! POP SI
    ! POP DS

    This is just an equivalent of your sample program, and doesn't really
    do anything but load values into registers.

    I hope that helps a little (and that I haven't bored you to tears).

    [This message has been edited by G Grant (edited February 29, 2000).]

    Leave a comment:

  • Matthew Berg
    Where can one get PBDK? I've looked in the products cataloge but have not seen it.
    Probably because it has been discontinued.

    Leave a comment:

  • Walt Decker
    started a topic ASM & Pointers

    ASM & Pointers

    How does one go about using declared 32-bit pointers with inline ASM? For example:

    DEFINT A - Z


    A = 15
    B = 20
    aPtr = VARPTR32(A)
    bPtr = VARPTR32(B)

    ! mov AX,@aPtr

    produces a pointer error (521 I think)

    PS: Where can one get PBDK? I've looked in the products cataloge but have not seen it.

    [This message has been edited by Walt Decker (edited February 28, 2000).]