view docs/ccguide/basic09.appendix @ 636:94ff9d15614f

Convert to Docbook XML format
author roug
date Sun, 08 Dec 2002 11:09:09 +0000
parents 594a34d027f8
children 7fb3d02e04b0
line wrap: on
line source

<appendix>
<title>Interfacing to Basic09</title>
<para>
The object code generated by the Microware C Compiler can be made
callable from the BASIC09 "RUN" statement. Certain portions of a
BASIC09 program written in C can have a drmatic effect on execution
speed. To effectively utilize this feature, one must be familiar
with both C and BASIC09 internal data representation and procedure
calling protocol.
</para>
<para>
C type "int" and BASIC09 type "INTEGER" are identical; both are two
byte two's complement integers. C type "char" and BASIC09 type
"BYTE" and "BOOLEAN" are also identical. Keep in mind that C will
sign-extend characters for comparisons yielding the range -128 to
127.
</para>
<para>
</para>

<section>
<title>Example 1 - Simple Integer Aritmetic Case</title>
<para>
This first example illustrates a simple case. Write a C function to
add an integer value to three integer variables.
<screen>
build bt1.c
? addints(cnt,value,s1,arg1,s2,arg2,s2,arg3,s4)
? int *value,*arg1,*arg2,*arg3;
? {
?     *arg1 += *value;
?     *arg2 += *value;
?     *arg3 += *value;
? }
?
</screen>
</para>
<para>
That's the C function. The name of the function is "addints". The
name is information for C and c.link; BASIC09 will not know anything
about the name. Page 9-13 of the BASIC09 Reference manual describes
how BASIC09 passes parameters to machine language modules. Since
BASIC09 and C pass parameters in a similar fashion, it is easy to
access BASIC09 values. The first parameter on the BASIC09 stack is
a two-byte count of the number of following parameter pairs. Each
pair consists of an address and size of value. For most C
functions, the parameter count and pair size is not used. The
address, however, is the useful piece of information. The address
is declared in the C function to always be a "pointer to..." type.
BASIC09 always passes addresses to procedures, even for constant
values. The arguments cnt, s1, s2, s3 and s4 are just place holders
to indicate the presence of the parameter count and argument sizes
on the stack. These can be used to check validity of the passed
arguments if desired.
</para>
<para>
The line "int *value,*arg1,*arg2,*arg3" declares the parameters (in
this case all "pointers to int"), so the compiler will generate the
correct code to access the BASIC09 values. The remaining lines
increment each arg by the passed value. Notice that a simple
arithmetic operation is performed here (addition), so C will not
have to call a library function to do the operation.
</para>
<para>
To compile this function, the following C compiler command line is
used:
<informalexample>
<para>
cc2 bt1.c -rs
</para>
</informalexample>
CC2 uses the Level-Two compiler. Replace cc2 with cc1 if you are
using the Level-One compiler. The -r option causes the compiler to
leave bt1.r as output, ready to be linked. The -s option suppresses
the call to the stack-checking function. Since we will be making a
module for BASIC09, cstart.r will not be used. Therefore, no
initialized data, static data, or stack checking is allowed. More
on this later.
</para>
<para>
The bt1.r file must now be converted to a loadable module that
BASIC09 can link to by using a special linking technique as follows:
<informalexample>
<para>
c.link bt1.r -b=addints -o=addints
</para>
</informalexample>
This command tells the linker to read bt1.r as input. The option
"-b=addints" tells the linker to make the output file a module that
BASIC09 can link to and that the function "addints" is to be the
entrypoint in the module. You may give many input files to c.link
in this mode. It resolves references in the normal fashion. The
name given to the "-b=" option indicates which of the functions is
to be entered directly by the BASIC09 RUN command. The option
"-o=addints" says what the name of the output file is to be, in this
case "addints". This name should be the name used in the BASIC09
RUN command to call the C procedure. The name given in "-o="
option is the name of the procedure to RUN. The "-b=" option is
merely information to the linker so it can fill in the correct
module entrypoint offset.
</para>

<para>
Enter the following BASIC09 program:
<programlisting>
PROCEDURE btest
DIM i,j,k:INTEGER
i=1
j=132
k=-1033
RUN addints(4,i,j,k)
PRINT i,j,k
END
</programlisting>
When this procedure is RUN, it should print:
<screen>
5       136     -1029
</screen>
indicating that our C function worked!
</para>
</section>

<section>
<title>Example 2 - More Complex Integer Aritmetic Case</title>
<para>
</para>
</section>

<section>
<title>Example 3 - Simple String Manipulation</title>
<para>
</para>
</section>

<section>
<title>Example 4 - Quicksort</title>
<para>
The next example programs demonstrate how one might implement a
quicksort written in C to sort some BASIC09 data.
</para>
<para>
C integer quicksort program:
</para>
<programlisting>
#define swap(a,b) { int t; t=a; a=b; b=t; }

/* qsort to be called by BASIC09:
     dim d(100):INTEGER  any size INTEGER array
     run cqsort(d,100)   calling qsort.
*/

qsort(argcnt,iarray,iasize,icount,icsiz)
int  argcnt,     /* BASIC09 argument count */
     iarrary[],  /* Pointer to BASIC09 integer array */
     iasize,     /* and it's size */
     *icount,    /* Pointer to BASIC09 (sort count) */
     icsiz;      /* Size of integer */
{
     sort(iarray,0,*icount);  /* initial qsort partition */
}

/* standard quicksort algorithm from Horowitz-Sahni */
static sort(a,m,n)
register int *a,m,n;
{
     register i,j,x;
     
     if(m &lt; n) {
          i = m;
	  j = n + 1;
	  x = a[m];
	  for(;;) {
	       do i += 1; while(a[i] &lt; x);  /* left partition */
	       do j -= 1; while(a[j] &gt; x);  /* right partition */
	       if(i &lt; j)
	            swap(a[i],a[j])          /* swap */
		    else break;
	  }
	  swap(a[m],a[j]);
	  sort(a,m,j-1);                     /* sort left */
	  sort(a,j+1,n);                     /* sort right */
     }
}
</programlisting>
<para>
The BASIC09 program is:
</para>
<programlisting>
PROCEDURE sorter
DIM i,n,d(1000):INTEGER
n=1000
i=RND(-(PI))
FOR i=1 to n
d(i):=INT(RND(1000))
NEXT i
PRINT "Before:"
RUN prin(1,n,d)
RUN qsortb(d,n)
PRINT "After:"
RUN prin(1,n,d)
END

PROCEDURE prin
PARAM n,m,d(1000):INTEGER
DIM i:INTEGER
FOR i=n TO m
PRINT d(i); " ";
NEXT i
PRINT
END
</programlisting>
<para>
C string quicksort program:
</para>
<programlisting>
/* qsort to be called by BASIC09:
     dim cmemory:STRING[10] This should be at least as large as
                            the linker says the data size should
                            be.
     dim d(100):INTERGER    Any size INTEGER array.

     run cqsort(cmemory,d,100) calling qsort. Note that the pro-
                            cedure name run in the linked OS-9
                            subroutine module. The module name
                            need not be the name of the C func-
                            tion.
*/

int maxstr;    /* string maximum length */

static strbcmp(str1,str2)            /* basic09 string compare */
register char *str1,*str2;
{
     int maxlen;

     for (maxlen = maxstr; *str1 == *str2 ;++str1)
          if (maxlen-- >0 || *str2++ == 0xff)
               return 0;
     return (*str1 - *str2);
}

cssort(argcnt,stor,storsiz,iaarray,iasize,elemlen,elsiz,
             icount,icsiz)
int argcnt;          /* BASIC09 argument count */
char *stor;         /* Pointer to string (C data storage) */
char iarray[];      /* Pointer to BASIC09 integer array */
int  iasize,          /* and it's size */
     *elemlen,        /* Pointer integer value (string length) */
     elsiz,           /* Size of integer */
     *icount,         /* Pointer to integer (sort count) */
     icsiz;           /* Size of integer */
{
/* The following assembly code loads Y with the first
   arg provided by BASIC09.  This code MUST be the first code
   in the function after the declarations.  This code assumes the
   address of the data area is the first parameter in the BASIC09
   RUN command. */
#asm
 ldy 6,s get addr for C storage
#endasm

/* Use the C library qsort function to do the sort. Our
   own BASIC09 string compare function will compare the strings.
*/

     qsort(iarray,*icount,maxstr=*elemlen,strbcmp);
}

/* define stuff cstart.r normally defines */
#asm
_stkcheck:
 rts dummy stack check function

 vsect
errno: rmb 2 C function system error number
_flacc: rmb 8 C library float/long accumulator
 endsect
#endasm
</programlisting>
<para>
The BASIC09 calling programs:  (words file contains strings to sort)
</para>
<programlisting>
PROCEDURE ssorter
DIM a(200):STRING[20]
DIM cmemory:STRING[20]
DIM i,n:INTEGER
DIM path:INTEGER
OPEN #path,"words":READ

n=100
FOR i=1 to n
INPUT #path,a(i)
NEXT i
CLOSE #path
RUN prin(a,n)
RUN cssort(cmemory,a,20,n)
RUN prin(a,n)
END

PROCEDURE prin
PARAM a(100):STRING[20]; n:INTEGER
DIM i:INTEGER
FOR i=1 TO n
PRINT i; " "; a(i)
NEXT i
PRINT i
END
</programlisting>
</section>

<section>
<title>Example 5 - Floating Point</title>
<para>
The next example shows how to access BASIC09 reals from C functions:
</para>
<programlisting>
flmult(cnt,cmemory,cmemsiz,realarg,realsize)
</programlisting>
</section>

<section>
<title>Example 6 - Matrix Elements</title>
<para>
The last program is an example of accessing BASIC09 matrix elements.
The C program:
</para>
<programlisting>
matmult(cnt,cmemory,cmemsiz,matxaddr,matxsize,scalar,scalsize)
</programlisting>
<para>
BASIC09 calling program:
</para>
<programlisting>
PROCEDURE btest
DIM im(5,3):INTEGER
DIM i,j:INTEGER
DIM cmem:STRING[32]
FOR i=1 TO 5
    FOR j=1 TO 3
        READ im(i,j)
    NEXT j
NEXT i
DATA 11,13,7,3,4,0,5,7,2,8,15,0,0,14,4
FOR i=1 TO 5
    PRINT im(i,1),im(i,2),im(i,3)
NEXT i
PRINT
RUN matmult(cmem,im,64)
FOR i=1 TO 5
    PRINT im(i,1),im(i,2),im(i,3)
NEXT i
END
</programlisting>
</section>
</appendix>