[net.micro.amiga] Calling C routines from AmigaBasic

cosell@BBN-PROPHET.ARPA (Bernie Cosell) (06/21/86)

Is it possible to write C routines and have them be callable from
an AmigaBasic program?  I'm doing some prototyping in AmigaBasic and
I'd like to be able to speed up some of the more stable cpu-intensive
routines by providing C versions.  I presume that if possible, it would
involve some hackery like turning the C function into something that
looked like a 'library' that Basic could call, but I haven't a clue
how to go about all that (from either side).  Any advice or examples
would be appreciated.  Thanks!

   /Bernie

Bernie Cosell                       Internet:  cosell@prophet.bbn.com
Bolt, Beranek & Newman, Inc         USENET:    bbncc5!bpc
Cambridge, MA   02238               Telco:     (617) 497-3503

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (06/26/86)

In article <8606202331.AA05635@ucbvax.Berkeley.EDU> cosell@BBN-PROPHET.ARPA (Bernie Cosell) writes:
>Is it possible to write C routines and have them be callable from
>an AmigaBasic program?  I'm doing some prototyping in AmigaBasic and
>I'd like to be able to speed up some of the more stable cpu-intensive
>routines by providing C versions.  I presume that if possible, it would
>involve some hackery like turning the C function into something that
>looked like a 'library' that Basic could call, but I haven't a clue
>how to go about all that (from either side).  Any advice or examples
>would be appreciated.  Thanks!
>

   A library is probably the best way.  I've made a library with a
couple of ml functions, made an fd file and .bmap for it, and called
the functions from AmigaBasic.  My next step is to add C-interface code
to the library and add some functions written in C.

   But meanwhile, this may help you out.  I am attaching 2 files.
Fun.c contains a couple of specially written C functions.  CFunTest is
an AmigaBasic program that LoadSeg()s and CALLs the functions.

-------------------------------------------------------------------------
/* Fun.c -- C functions to be LoadSeg()'d and called from another program.
            Compiled with no Stack checking (-v option on LC2)
            Linked only with Amiga.lib  (no startup code)
            Calling program must:
               LoadSeg the executable file of this program.
               Segment ptr returned by LoadSeg * 4 + 4 = address of main()
               Caller must allocate a LONG variable for function result
               Caller calls main() passing ptr to LONG result variable
               Main() puts address of JumpTable in result variable
               Caller may then call these functions via their addresses

            Note that first arg for each function is address of the
               LONG where return value may be stashed.

            Also note that because these are not LIBRARY functions,
               they can not be DECLARED in AmigaBasic and therefore
               cannot return a value (since CALL must be used).
               Each function must be declared as void and must
               not attempt to return a value to AmigaBasic or
               stack corruption will result.

            Fun1 moves the screen, waits, then moves it back.
            Fun2 doubles the number it is passed.
*/

#include <exec/types.h>
#include <intuition/intuition.h>

extern void Fun1(), Fun2();  /* So JumpTable can be built */

typedef void (*PFV)();
PFV JumpTable[] = { Fun1, Fun2 };    /* JumpTable of function addresses */

extern ULONG AbsExecBase;
ULONG  SysBase;
ULONG  DOSBase;
struct IntuitionBase *IntuitionBase;

void main(resultPtr)
LONG *resultPtr;
   {
   /* Set up globals SysBase and DOSBase */
   SysBase = (ULONG)AbsExecBase;
   if ((DOSBase = (ULONG)OpenLibrary("dos.library",0))==NULL)
      {
      *resultPtr = 0;
      }
   else
      {
      CloseLibrary(DOSBase);   /* We just needed the pointer */

      *resultPtr = (LONG)&JumpTable[0];
      }
   }


     
void Fun1(resultPtr,delta)
LONG *resultPtr;
LONG delta;
   {
   struct Screen *frontScreen;

   if ((IntuitionBase =
      (struct IntuitionBase *)OpenLibrary("intuition.library",0))==NULL)
      {
      *resultPtr = 0;
      }
   else
      {
      frontScreen = IntuitionBase->FirstScreen;
      MoveScreen(frontScreen,0,delta);
      Delay(50);
      MoveScreen(frontScreen,0,-delta);

      CloseLibrary(IntuitionBase);
      *resultPtr = delta;
      }
   }


     


void Fun2(resultPtr,arg1)
LONG *resultPtr;
LONG arg1;
   {
   arg1 += arg1;
   *resultPtr = arg1;
   }

----------------------------------------------------------------------------
REM - CFunTest
REM - This program shows how to
REM - use AmigaDOS library routines
REM - to load and call specially
REM - written C functions.  See
REM - Fun.c for more info.
REM - Note 1st arg for each function
REM -  is address of Result& where
REM -  return value is stored.
REM - Because non-LIBRARY functions
REM - cannot be DECLAREed, they must
REM - be CALLed and therefore cannot
REM - directly return a value.

REM *** Result& for return values ***
Result& = 0
     
DECLARE FUNCTION LoadSeg&  LIBRARY
DECLARE FUNCTION IoErr&    LIBRARY

PRINT "Looking for dos.bmap ... ";
LIBRARY "dos.library"
PRINT "found it."

REM *** LoadSeg the function code  ***
REM *** Address of InitRtn& (main) ***
REM ***  is (SegBptr& * 4) + 4     ***

Filename$ = "Fun"
Loadname$ = Filename$+CHR$(0)
SegBptr& = LoadSeg&(SADD(Loadname$))
IF (SegBptr& = 0) THEN
   PRINT "LoadSeg of "Filename$" failed"
   LoadErr% = IoErr&
   PRINT "IO error ="LoadErr%
   GOTO Fcleanup2
END IF

PRINT "SegBptr& = $"HEX$(SegBptr&)
SegAddr& = SegBptr& * 4
PRINT "SegAddr& = $"HEX$(SegAddr&)
InitRtn& = SegAddr& + 4
PRINT "InitRtn& = $"HEX$(InitRtn&)


REM *****
InputLoop:
INPUT "<t>ryFun or <q>uit";k$
IF k$ = "t" THEN GOSUB TryFun: GOTO InputLoop
IF k$ = "q" THEN GOTO Fcleanup
GOTO InputLoop


TryFun:
PRINT "Calling InitRtn& for address of FunctionTable"
CALL InitRtn&(VARPTR(Result&))
FunTable& = Result&
PRINT "Function table address = $"HEX$(FunTable&)

Fun1& = PEEKL(FunTable&)
Fun2& = PEEKL(FunTable& + 4)
PRINT "  Func 1 addr    = $"HEX$(Fun1&)
PRINT "  Func 2 addr    = $"HEX$(Fun2&)

INPUT "<c>ontinue or <q>uit";k$
IF k$ <> "c" THEN GOTO SkipFun:
PRINT
PRINT "Fun1 moves the screen"
INPUT "Press <RETURN> when ready";k$
delta& = 50
CALL Fun1&(VARPTR(Result&),delta&)
PRINT "Finished Fun1&"
PRINT
PRINT "Fun2 doubles an integer"
INPUT "   Enter an integer";k$
arg1& = VAL(k$)
PRINT "Argument ="arg1&
CALL Fun2&(VARPTR(Result&),arg1&)
PRINT "Result ="Result&
PRINT "Finished Fun2&"

SkipFun:
RETURN

Fcleanup:
CALL UnLoadSeg&(SegBptr&)
Fcleanup2:
LIBRARY CLOSE
PRINT "Done"
END

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


--
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=