CpcAlive is a
programming
environment
Amstrad CPC
compatible
for graphics
 animations
creation.







Cpc basic key words
( English - Español )

Cpc basic error messages

The memory

The Cpc system vectors

Diskettes management

Z80 processor opcodes and
operation

CpcAlive installer for
Windows and DosBox

CpcAlive Documentation

SmallAsm is a Z80 assembler
for Dos







Français

** CpcAlive C++ module example **


/* HELLO.CPP - This program is a CpcAlive Module and it must be compiled
only with the Borland Turbo C++ Version 3.0(1992) with the command:
tcc -mt -lt HELLO.cpp
wich produce a DosBox executable file with a .COM extension
All variables used with the inline assembler must be "global"
Loading from the Dos command line: ! HELLO.COM
Loading from a CpcAlive command file: HELLO.COM
Loading from the Cpc BASIC interpreter: |INPUT, "HELLO.COM":CALL 0
--------------------------------------------------------------------------------------
!!requires version V1.19i or more of the CpcAlive emulator!!
--------------------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>

#if defined(__TURBOC__) || defined(_MSC_VER)
    #include <conio.h>
#else
    #define _MAX_PATH 250
    #define stricmp(x,y) strcasecmp(x,y)
    #define strnicmp(x,y,z) strncasecmp(x,y,z)
#endif
#define STACK_INIPTR -2

// *****************************
// ***  Function prototypes  ***
// *****************************
CallFunctions();//C++ functions call routine
ModuleInit();    //initialisations
function01();    //function 1 - call from basic with |HELLO,param1,param2,...
void skip00();    //some jumps
void skip02();

// **************************
// ***  Global variables  ***
// **************************
//--------------------------------------------------------------------------------------
//!!! All variables used with inline assembler must be "global" !!!
int GsSeg=0;    //Data segment of the emulator CpcAlive=flag "called from emulator"
int BasicParams[32];        //32 parameters max
int nbrParam;    //number of parameters of the BASIC command
//--------------------------------------------------------------------------------------
typedef int (*PtrFunct)();    // define "type" of function pointer
PtrFunct CppVecTb[20];        // module vectors table(128 vectors max)
PtrFunct FunctionOfs;int ssBak=0;int spBak=0;//temporary values
//other ex:>>> typedef int (*PtrFunct)(int, int);

#if !defined(NO_MNEMOS)
   char MnemosBASIC[] = {        // Mnemonics call's from CPC BASIC
   'I','N','I','T'|0x80,         //CppVecTb[0]=function 0 - initialisations
   'H','E','L','L','O'|0x80,    //CppVecTb[1]=function 1 - call from basic with |HELLO,param1,param2,...
                                 //....
   '\0'};                        //mark end of table
#endif

//struct of implementation table of the module
struct X86TbStruct {    //s=string,w=word,b=byte,*=value generated by the system
  char mark[6];         // s000h mark("X86CPC")
  int X86TbVersion;     // w006h version table
  PtrFunct *CppVecTb;   // w008h entry vectors table
  int W0AH[3];          // w00Ah reserved
  char *MnemosBASIC;    // w010h offset mnemonics table for calls with Basic
  char B12H[4];         // 4 values
                        // b012h (*)receipt the X86 module area number
                        // b013h module complement number or bank Cpc block number
                        // b014h (*)reçeipt the Z80 rom number associated
                        // b015h indicator for Cpc banks or modules complements connection
  int W16H;             // w016h reserved
  char S18H[6];         // 4 values
                        // b018h reserved
                        // w019h (*)receipt the ems handle associated to the module
                        // w01Bh (*)receipt the logical number of the first 16K page of the module
                        // b01Dh reserved
  int W1EH[5];          // use the same model as functions in the CppVecTb table to program these functions
                        // w01Eh address called when the emulator exit (0=no call)
                        // w020h address called when the emulator is put in "sleep mode" (0=no call)
                        // w022h address called when the emulator return from "sleep mode" (0=no call)
                        // w024h address called when the module is load (0=no call)
                        // w026h reserved
  char S28H[3];         // 2 values
                        // b028h receipt the number of 16K pages allocated to the module (*)
                        //         (always 4 for the C++ modules)
                        // w029h reserved
  int W2BH;             // w02Bh (*)SS emulator stack segment
  int W2DH;             // w02Dh (*)SP emulator stack pointer
  char S2FH[1];            // s02FH reserved
  PtrFunct W30H;        // w030h C++ functions call offset routine
  PtrFunct W32H;        // w032h (*)receives the address of the called function
  char S34H[100];        // s034H reserved

};

struct X86TbStruct X86Tb;//implementation table of the module

struct X86TbStruct *X86TbSet(){   // init implementation table of the module
strcpy(X86Tb.mark,"X86CPC");       // s000h mark("X86CPC")
X86Tb.X86TbVersion=1;               // w006h version table
X86Tb.CppVecTb=&CppVecTb[0];  // w008h entry vectors table
#if defined(NO_MNEMOS)
    X86Tb.MnemosBASIC=0;       // w010h offset mnemonics (0=no mnemonics)
    X86Tb.W24H=&ModuleInit;    // function called when the module is load (0=no call)
#else
    X86Tb.MnemosBASIC=&MnemosBASIC[0];// w010h offset mnemonics
#endif
X86Tb.B12H[0]=-1;           // b012h (*)receipt the X86 module area number
X86Tb.B12H[1]=-1;           // b013h module complement number or bank Cpc block number
X86Tb.B12H[2]=-1;           // b014h (*)reçeipt the Z80 rom number associated
X86Tb.B12H[3]=-1;           // b015h indicator for Cpc banks or modules complements connection
X86Tb.W30H=&CallFunctions;    // w030h C++ functions call routine
return &X86Tb;//passes the offset of the module implementation table to the emulator
}

CallFunctions(){//C++ functions call routine
asm {mov bp,cs;cli;mov ss,bp;mov sp,STACK_INIPTR;sti;mov bp,sp;push ax}
FunctionOfs=X86Tb.W32H;ssBak=X86Tb.W2BH;spBak=X86Tb.W2DH;
asm {pop ax;call FunctionOfs;cli;mov ss,ssBak;mov sp,spBak;sti;retf}
}

ModuleInit(){//initialisation vector called with the CPC boot
#if !defined(NO_MNEMOS)
    printf(" HELLO    1.1\n"); // INIT message
    asm {stc}//= ok for INIT vector
#endif
}

int BasicParamInput(){//load parameters of the BASIC command
//<AL=number of parameters
//  SI=parameters pointer in Cpc Ram
//>Values collected in the BasicParams array will be pointers to the data for each
//  variables (e.g., strings), except for integer values that can be processed as is.

if (GsSeg==0){return 0;}//Data segment of the emulator CpcAlive=flag "call from emulator"
nbrParam=_AX & 0x1f;  // 32 parameters max
if (nbrParam){
    _CX=nbrParam*2;   // size block
    _AH=5;                // read block bank 0 Cpc - see Cpc memory access from C++ environment
    asm{
        mov di,offset BasicParams
        int 018h
    }
}
return nbrParam;
}

function01(){//function 1 - call from basic with |HELLO,param1,param2,...
int i;
//---------------------------------
//Free C++ area
if (BasicParamInput()!=0){//load parameters of the BASIC command
    printf("Numbers of parameters=%d\n",nbrParam);
    for (i = 0; i < nbrParam; i++){printf("0x%x=value or pointer of parameter %d\n",BasicParams[i],i);}
}
printf("HELLO CPC");
//---------------------------------
}

//passes the offset of the module implementation table to the emulator
struct X86TbStruct *main() // ---------- MAIN ------------
{
    CppVecTb[0]=&ModuleInit;// vectors of module
    CppVecTb[1]=&function01;
    //...

    GsSeg=0;    //Data segment of the emulator CpcAlive
                //=flag "called from emulator"
    asm {
        cmp byte ptr cs:[01B1h],090h    // called from emulator ?(.COM)
        jz short skip00                    // jump if yes
        cmp byte ptr cs:[0B1h],090h        // called from emulator ?(.EXE)
        jnz short skip02                // jump if not
    }

skip00:

    asm {
        db 0Fh,0A8H    //PUSH GS(Data segment of the emulator CpcAlive)
        pop GsSeg    //!=0 -> called from emulator
    }
    return X86TbSet();//passes the offset of the module implementation table to the emulator

skip02:

    //for test from DOS
    function01();//function 1

    if (getch() == 0) getch();

  return 0;

}