Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- Peter Norton Programmer's Guide - Norton Guide http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]

  Interpreted BASIC uses a medium memory model, so subroutines are accessed
  through a far call-return sequence, and data is accessed with near
  addresses. Also, interpreted BASIC passes all parameters by reference.

  Knowing this, you can easily design assembly-language subroutines that can
  be accessed within an interpreted BASIC program.

  Be aware, however, that interpreted BASIC knows nothing about object
  files, object libraries, or linkers: You must explicitly instruct BASIC to
  load and link your subroutine. Although several loading techniques have
  been developed, the most straightforward uses BASIC's own BLOAD command to
  make a subroutine accessible to a high-level interpreted BASIC program.

  The BLOAD command loads binary data from a disk file into BASIC's default
  data segment. If you build a subroutine in the format that BLOAD will
  recognize, you can use BLOAD to place the subroutine anywhere in memory.
  In particular, you can load a subroutine into an integer array whose
  address you can call with interpreted BASIC's CALL statement.

  BLOAD loads files that are prefixed with a 7-byte header containing a
  signature byte (FDH), two words (4 bytes) of zeros, and a word that
  contains the number of bytes of data to load. Simply adding this header to
  a medium-model subroutine makes it loadable by BLOAD:

  CodeSeg         SEGMENT byte
                  ASSUME  cs:CodeSeg

  ; header for BASIC BLOAD

                  DB      0FDh            ; signature byte
                  DW      2 dup(0)        ; two 16-bit zeros
                  DW      SubroutineSize  ; size of this subroutine

  MedAbs          PROC    far             ; call with far CALL

                  push    bp
                  mov     bp,sp

                  mov     bx,[bp+6]       ; BX = address of first parameter
                  mov     ax,[bx]

                  cwd
                  xor     ax,dx
                  sub     ax,dx

                  mov     [bx],ax         ; leave result at parameter address

                  pop     bp
                  ret     2               ; far RETurn, discard
                                          ; parameter address
  MedAbs          ENDP

  SubroutineSize  EQU     $-MedAbs

  CodeSeg         ENDS

  Apart from the BLOAD header, the only difference between this version of
  MedAbs() and the earlier version is in the naming conventions: Interpreted
  BASIC doesn't use symbolic names to link a subroutine loaded with the
  BLOAD command, so you can use any names you choose.

  To convert the assembly-language source code into a form readable by
  BLOAD, use LINK and EXE2BIN. For example, if this subroutine's source file
  is named MEDABS.ASM, the following two commands convert it into
  MEDABS.BIN, a file that BLOAD can use:

  LINK MEDABS.ASM;
  EXE2BIN MEDABS;

  To link the subroutine into a high-level BASIC program, do this:

  1.  Allocate a block of memory for the subroutine by using a DIM statement
      to declare an integer variable.

  2.  Use the VARPTR function to store the memory block's address in a
      variable.

  3.  Use BLOAD to copy the subroutine into memory.

  4.  Use the CALL statement to call the subroutine through the variable
      that contains its address.

  Here's an example:

  100 DEFINT A-Z                     ' default all variables to integer type
  110 '
  120 X = 0 : Y = 0                  ' reserve RAM for all variables used
  130 SUBADDR = 0
  140 '
  150 DIM SUBAREA(16)                ' reserve RAM for the subroutine
  160 SUBADDR = VARPTR(SUBAREA(1))   ' save the address of the subroutine
  170 BLOAD "medabs.bin",SUBADDR
  180 '
  190 FOR X=-10 TO 10
  200  Y = X
  210  CALL SUBADDR(Y)               ' call the subroutine
  220  PRINT"ABS(";X;")=";Y
  230  NEXT
  240 END

  Note how the four steps of linking are carried out. The statement DIM
  SUBAREA(16) reserves 32 bytes of memory, more than enough for the
  subroutine. Then SUBADDR = VARPTR(SUBAREA(1)) stores the address of the
  memory block in the variable SUBADDR. At this point, the BLOAD command can
  load the subroutine from the binary file, and the CALL statement can call
  the subroutine through the variable SUBADDR.

  There is one tricky thing to remember about this process: Interpreted
  BASIC allocates variables and strings dynamically. Because of this, you
  should define all variables in your BASIC program before you use BLOAD to
  load the subroutine. (Lines 120 and 130 do this in our example.) If you
  don't, you may find that the address returned by VARPTR doesn't reflect
  the final location of the subroutine in memory.

  If you pass more than one parameter to a BASIC subroutine through a CALL
  statement, the parameters appear with the last parameter at [BP + 6], the
  next-to-last at [BP + 8], and so on. This is the reverse of the order used
  in C. The advantage to using this parameter order is that the subroutine
  can clean up the stack with a single RET instruction. Instead of using a
  simple far RETurn, a BASIC subroutine uses a return-and-pop instruction to
  discard the parameters. In the BASIC version of MedAbs(), for example, the
  instruction is RET 2; the value 2 is the number of bytes occupied by the
  subroutine's parameter on the stack.

Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson