233 lines
7.7 KiB
C
233 lines
7.7 KiB
C
/*
|
||
This program is the TURBO C (ver. 1.0) implementation of the
|
||
transcendental functions. The official implementation used by SCHEME was
|
||
done under the Lattice C version. This purpose of this program is to
|
||
show you what is needed to communicate with XLI via TURBO C. The
|
||
lines containing comments that start out with @@ designate lines that
|
||
will need to be modified by you when you use this template program
|
||
for your own purpose.
|
||
|
||
Note: In order to compile this program you will need to have a path
|
||
set up to get to the Macro Assembler.
|
||
|
||
The command line to compile is:
|
||
TCC -ID:\TURBOC\INCLUDE -LD:\TURBOC\LIB -B -c TRIG_TC
|
||
|
||
The command line to link this program is:
|
||
TLINK d:\turboc\lib\c0new.obj TRIG_TC,,,d:\turboc\lib\emu
|
||
d:\turboc\lib\maths d:\turboc\lib\cs
|
||
|
||
All pathnames will need to be changed to reflect your directories. The
|
||
command for the link needs to be on one line only. The file C0NEW.OBJ
|
||
was my changed copy of the C0S.OBJ file; the changes you need to make to
|
||
it are described below.
|
||
|
||
*/
|
||
|
||
#include "dos.h"
|
||
#include "math.h"
|
||
#include "stdlib.h"
|
||
|
||
#define F_NEAR 0x0001 /* Set model flag to near. USED */
|
||
#define F_INT 0x0002 /* Set integer flag to 16 bits. NOT-USED */
|
||
#define F_REL 0x0004 /* Set release env block by extern pgm flag. N-U */
|
||
#define F_PAD 0x0008 /* Set parm blocking flag to unblocked. USED */
|
||
|
||
#define RT_INTEGER 0 /* Set return type to be an integer. NOT-USED */
|
||
#define RT_BOOLEAN 1 /* Set return type to be boolean. NOT-USED */
|
||
#define RT_STRING 2 /* Set return type to be a string. NOT-USED */
|
||
#define RT_DOUBLE 3 /* Set the return type to be a float num. USED */
|
||
|
||
typedef unsigned short WORD; /* 16-bit unsigned value */
|
||
|
||
/*
|
||
_tsize is set to the size of the program from within the Start Up Code
|
||
file called C0.ASM. You need to modify this file in order for this
|
||
variable to be set.
|
||
|
||
The file C0.ASM is supplied to you on the TURBO C diskette. It is
|
||
in assembly source form so that you can modify the Start Up Code to
|
||
do what you need it to do. In this case we will make the following
|
||
changes to capture the in-memory size of this file in paragrahps.
|
||
|
||
The following two pieces of code are extracted out of the file
|
||
C0.ASM. They show you where the changes need to be made so that _tsize
|
||
will contain the size of this, or your, program. Only two lines need
|
||
to be added to the C0.ASM file. You will then need to execute the batch
|
||
file that TURBO provides you, called BUILD-C0, in order to build a new
|
||
C0x.OBJ file, where the 'x' represents the model. To create a new small
|
||
model after making the changes shown below you would execute the batch
|
||
stream by typing BUILD-C0 SMALL.
|
||
|
||
ExcessOfMemory label near
|
||
mov bx, di
|
||
add bx, dx
|
||
mov word ptr _heapbase@ + 2, bx
|
||
mov word ptr _brklvl@ + 2, bx
|
||
mov ax, _psp@
|
||
sub bx, ax ; BX = Number of paragraphs to keep
|
||
mov _tsize@, bx ; 1st change *** Line added for XLI *****.
|
||
mov es, ax ; ES = Program Segment Prefix address
|
||
mov ah, 04Ah
|
||
int 021h
|
||
.
|
||
.
|
||
.
|
||
PubSym@ _envLng, <dw 0>, __CDECL__
|
||
PubSym@ _envseg, <dw 0>, __CDECL__
|
||
PubSym@ _envSize,<dw 0>, __CDECL__
|
||
PubSym@ _psp, <dw 0>, __CDECL__
|
||
PubSym@ _tsize, <dw 0>, __CDECL__ ; 2nd change *** line added ***.
|
||
PubSym@ _version,<label word>,__CDECL__
|
||
PubSym@ _osmajor,<db 0>, __CDECL__
|
||
.
|
||
.
|
||
.
|
||
*/
|
||
extern WORD _tsize;
|
||
|
||
|
||
/*
|
||
Xwait and xbye will contain the actual addresses, XLI entry points, that
|
||
we'll jump to when we call XLI so they need to be big enough to hold FAR
|
||
pointers.
|
||
*/
|
||
WORD xwait[2];
|
||
WORD xbye[2];
|
||
|
||
|
||
struct xli_file_struct {
|
||
WORD id;
|
||
WORD flags;
|
||
WORD table[2]; /* offset in 0, segment in 1 */
|
||
WORD parm_block[2];
|
||
WORD reserved[8];
|
||
} file_block;
|
||
|
||
struct xli_routine_struct {
|
||
WORD select;
|
||
WORD special_service;
|
||
WORD ss_args[8];
|
||
WORD reserved[8];
|
||
WORD return_type;
|
||
double return_value;
|
||
double arg1;
|
||
double arg2;
|
||
} parm_block;
|
||
|
||
char table[] =
|
||
/*
|
||
@@ The following string contains the names of the functions that can
|
||
be called from within SCHEME when this file is loaded thru XLI.
|
||
|
||
0 1 2 3 4 5 6 7 8 9 10 11 12
|
||
*/
|
||
"sqrt/sin/cos/tan/asin/acos/atan/atan2/exp/expt/ln/log10/log//";
|
||
|
||
|
||
int xli_wait()
|
||
/*
|
||
This function takes advantage of TURBO C's ability to have actual
|
||
Assembly Code inline. Its purpose is to set up the stack, call the
|
||
XLI function XWAIT, and upon returning pop the stack and return the
|
||
value in AX which will either be non-zero or zero.
|
||
*/
|
||
|
||
{
|
||
asm push _psp
|
||
asm push _tsize
|
||
asm call dword ptr [xwait]
|
||
asm pop ax
|
||
asm pop ax
|
||
return (_AX);
|
||
}
|
||
|
||
void xli_bye()
|
||
/*
|
||
This function takes advantage of TURBO C's ability to have actual
|
||
Assembly Code inline. If the previous function, XLI_WAIT, return
|
||
a zero then this function will end up being called and it will
|
||
allow XLI to clean up after us prior to the termination of Scheme.
|
||
*/
|
||
{
|
||
asm call dword ptr [xbye]
|
||
}
|
||
|
||
void main()
|
||
/*
|
||
Within the main body of code the only portions that you will need to
|
||
change are:
|
||
1) The value of the FILE-BLOCK.FLAGS and
|
||
2) The functions that you will call from within the CASE stmts.
|
||
*/
|
||
{
|
||
struct SREGS segregs;
|
||
int xli_wait();
|
||
void xli_bye();
|
||
|
||
union {
|
||
WORD far * psp_ptr;
|
||
WORD p_array[2];
|
||
} p1;
|
||
|
||
|
||
p1.p_array[0] = 0; /* The offset and */
|
||
p1.p_array[1] = _psp; /* segment address for the PSP. */
|
||
|
||
/*
|
||
The following code will initialize the File Block as needed.
|
||
*/
|
||
file_block.id = 0x4252;
|
||
file_block.flags = F_NEAR+F_PAD; /* @@ Set flags as appropriate. */
|
||
|
||
segread(&segregs); /* Get the register information */
|
||
file_block.table[0] = (WORD) table;
|
||
file_block.table[1] = segregs.ds;
|
||
file_block.parm_block[0] = (WORD) &parm_block;
|
||
file_block.parm_block[1] = segregs.ds;
|
||
|
||
|
||
/*
|
||
Establish the connection between C and the PSP.
|
||
*/
|
||
p1.psp_ptr[46] = (WORD) &file_block; /* Set into the PSP the offset and */
|
||
p1.psp_ptr[47] = segregs.ds; /* segment address of file_block */
|
||
|
||
xwait[0] = p1.psp_ptr[5]; /* Store into XWAIT the offset and the */
|
||
xwait[1] = p1.psp_ptr[6]; /* segment address of DOS's terminate routine.*/
|
||
|
||
xbye[0] = xwait[0]; /* Copy the termination offset and */
|
||
xbye[1] = xwait[1]; /* segment address from above into here. */
|
||
|
||
xwait[0] += 3; /* incr by 3 for normal call */
|
||
xbye[0] += 6; /* incr by 6 for termination */
|
||
|
||
while (xli_wait()) {
|
||
switch (parm_block.select) {
|
||
case 0: parm_block.return_value = sqrt(parm_block.arg1); break;
|
||
case 1: parm_block.return_value = sin(parm_block.arg1); break;
|
||
case 2: parm_block.return_value = cos(parm_block.arg1); break;
|
||
case 3: parm_block.return_value = tan(parm_block.arg1); break;
|
||
case 4: parm_block.return_value = asin(parm_block.arg1); break;
|
||
case 5: parm_block.return_value = acos(parm_block.arg1); break;
|
||
case 6: parm_block.return_value = atan(parm_block.arg1); break;
|
||
case 7: parm_block.return_value =
|
||
atan2(parm_block.arg1,parm_block.arg2); break;
|
||
case 8: parm_block.return_value = exp(parm_block.arg1); break;
|
||
case 9: parm_block.return_value =
|
||
pow(parm_block.arg1,parm_block.arg2); break;
|
||
case 10: parm_block.return_value = log(parm_block.arg1); break;
|
||
case 11: parm_block.return_value = log10(parm_block.arg1); break;
|
||
case 12: parm_block.return_value =
|
||
log(parm_block.arg1) / log(parm_block.arg2); break;
|
||
default: ;
|
||
} /* end switch */
|
||
|
||
parm_block.return_type = RT_DOUBLE;
|
||
|
||
} /* end while */
|
||
|
||
xli_bye();
|
||
|
||
} /* end main */
|
||
|