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
--------------------------------------------------------------------------------------*/

#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  ***
// *****************************
function00();//initialisations
function01();//function 1 - call from basic with |HELLO,param1,param2,...
void skip00();//some jumps
void skip02();
void skip04();

// **************************
// ***  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 x=0;int y=0;
int nbrParam=0;          //number of parameters of the BASIC command
int BasicParams[32];    //32 parameters max
//-----------------------------------------------------------

typedef int (*PtrFunct)();    // define "type" of function pointer
PtrFunct CppVecTb[20];        // module vectors table(128 vectors max)
//other ex:>>> typedef int (*PtrFunct)(int, int);PtrFunct pf;

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

//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 (*)=0 - reçeipt the first Cpc accessible address
                                       // 0=no address accessible - see
Cpc memory access from C++ environment
  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];        //(V1.19c)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 (*)
                        //       or number of pages to be allocated (if <>0 when the module is loaded)
                        //       or number of connected pages (*)
                        //       or number of pages to connect
                        // (the emulator reserved 4 pages for the C++ modules)
                        // w029h 
reserved
  int W2BH;                // w02Bh (*)SS emulator stack segment
  int W2DH;                // w02Dh (*)SP emulator stack pointer
  char S2FH[20];        // s02FH 
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

X86Tb.MnemosBASIC=&MnemosBASIC[0];// w010h offset mnemonics
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.S28H[0]=4;                // number of pages to connect(always 4 for the C++ modules)
return &X86Tb;//passes the offset of the module implementation table to the emulator


}

void BackToZ80(){//Return to Z80
//(x&y=global integers)
asm{push ax};x=X86Tb.W2BH;y=X86Tb.W2DH;asm {pop ax;cli;mov ss,x;mov sp,y;sti;retf}
}

function00(){//initialisation vector called with the CPC boot
    asm {//Init function for calls from Cpc
        mov bp,cs;cli;mov ss,bp;mov sp,STACK_INIPTR;sti;mov bp,sp
    }
    printf(" HELLO    1.0\n"); // INIT message
    asm {stc}//= ok for INIT vector
    BackToZ80();//Return to Z80
}

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"
    asm{
        and ax,01Fh        // 32 parameters max
        mov nbrParam,ax    // numbers of parameters
        mov cl,al
        xor ch,ch
        add cx,cx        // size block
        jz short skip04    // jump if no parameters
        mov di,offset BasicParams
        mov ah,5        // read block bank 0 Cpc
        int 018h
        }
skip04:
return nbrParam;
}

//this function can be called from main() for tests
function01(){//function 1 - call from basic with |HELLO,param1,param2,...
    if (GsSeg!=0){    //Data segment of the emulator CpcAlive
                    //=flag call from emulator
        asm{//Init function for call from CPC
            mov bp,cs;cli;mov ss,bp;mov sp,STACK_INIPTR;sti;mov bp,sp
        }
    }
       
    //---------------------------------
    //Free C++ area
    if (BasicParamInput()!=0){
//load parameters of the BASIC command
        printf("Numbers of parameters=%d\n",nbrParam);
    }
    printf("HELLO CPC");
    //---------------------------------

    if (GsSeg==0x0){return 0;}    //back to main() if called from main()
    BackToZ80();                //else return to Z80
}

//passes the offset of the module implementation table to the emulator
struct X86TbStruct *main() // ---------- MAIN ------------
{
    CppVecTb[0]=&function00;// 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;

}