User Tools

Site Tools


calling_20basic_20from_20assembler_20code

Calling BASIC from assembler code

by Richard Russell, November 2008

You can't actually call BASIC from assembler code, but you can achieve an equivalent capability quite easily. What it involves is returning from the assembler code to BASIC, executing a BASIC procedure, and then re-entering the assembler code at the right place.

The first step in achieving this is to modify the way your assembler code is executed. Instead of a simple CALL statement:

        CALL code_start

Instead use the following code:

        B% = USR(code_start)
        WHILE B%
          PROC(B%)
          B% = USR(P%)
        ENDWHILE

If you prefer to call your assembler code with SYS then use code similar to the following:

        SYS code_start, parameters TO B%
        WHILE B%
          PROC(B%)
          B% = USR(P%)
        ENDWHILE

It is also necessary to adapt the assembler code entry point itself, as follows:

        DIM mystack% 255, myesp% 3, gap% 2047, mycode% 1000, L% -1
        FOR pass% = 8 TO 10 STEP 2
          P% = myesp%
          [OPT pass%
          .saved_esp dd mystack%+256
          ]
          P% = mycode%
          [OPT pass%
          .code_start
          xchg esp,[saved_esp]
          ; rest of assembler code continues here

Here a dual stack arrangement is established, where mystack% is a 256-byte memory area containing the second stack. Needless to say, you should increase (or decrease) the amount of memory allocated for the assembler code (here shown as 1000 bytes) as required.

When you want to 'call' a BASIC procedure from assembler code, do so as follows:

        mov eax,^PROCsomething
        call CallBASIC

Note that only procedures without parameters can straightforwardly be called this way. If you need to transfer data from the assembler code into the procedure(s), the easiest way to do so is via global variables. You can call as many procedures as you like, and they can be called from anywhere within the assembler code (even within a subroutine, or if values have been pushed onto the stack).

Since procedure pointers are used, the usual restriction applies that at least one PROC must have been called conventionally before the code is assembled (if the assembly routine itself is in a procedure, this is sufficient).

When you finally want to exit from the assembler code, instead of a simple ret use this code:

        mov eax,0
        xchg esp,[saved_esp]
        ret

If you need to call one of the 'OS' routines, such as oswrch, you must do so as follows:

        xchg esp,[saved_esp]
        call "oswrch"
        xchg esp,[saved_esp]

Finally, here is the CallBASIC subroutine:

        .CallBASIC
        xchg esp,[saved_esp]
        mov dword [^P%],next
        ret
        .next
        xchg esp,[saved_esp]
        ret
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
calling_20basic_20from_20assembler_20code.txt · Last modified: 2024/01/05 00:22 by 127.0.0.1