HomeEmulatorsMagiC Mac specificsSTEmulator

14.2 MagiC PC interface

MagiCPC knows two interfaces with which one can call up functions of the Windows system.

14.2.1 mec0 (MPS) interface

0. General remarks

MPS = Magic_Programmier_Schnittstelle = MagiC programmer's interface

Files of the demo example:

mps_base.def The export list of the DLL, DO NOT ALTER!
mps_base.h Definition of the MPS interface, DO NOT ALTER!
mps_base.cpp Basic functions of the DLL, DO NOT ALTER!
mps_demo.h Definitions for the demo-DLL
mps_demo.cpp The MPS_functions of the demo-DLL
testmps.s Motorola - Example for calling the MPS functions of the demo

To develop your own MPS_DLLs, please use mps_base.def, mps_base.h and mps_base.cpp unaltered. You can alter/supplement mps_demo.h and mps_demo.cpp. In particular, please choose your own DLL_ID in mps_demo.h for differentiation from other MPS_DLLs.

I. Concept

Windows-side one can use dynamic link libraries (DLLs) to establish any number of functions (called 'MPS_functions' in the following) which can be called within MagiC PC (Motorola-side).

In the start-up phase MagiC PC attempts to load and start all DLLs in the MPS subdirectory. For this MagiC PC calls three functions to be exported from the DLL (in this order):

  1. mps_get_type(): Must return 0x4701!

  2. mps_get_functionlist(...): Obtains DLL_ID and MPS_functions list of the DLL.

  3. mps_magicinfo: Provides information about MagiC PC's own data and functions which the DLL may use on demand.

All functions declared in 2) can be called via special opcodes on the Motorola side. See part IV for more about the call.

II. Functions of the DLL to be exported ('Basic functions')

An MPS_DLL must export exactly 3 C functions under fixed ordinal numbers (these are also called basic functions): (see mfp_base.def, mfp_base.cpp, mfp_base.h)

III. The freely definable MPS_functions of a DLL:

MPS_functions basically have the form:

void function_blabla( MPS_motregs *motregs )

motregs here points to a list of the Motorola registers d0-a7. The contents of the registers is already in the correct Intel byte order. The Motorola registers may also have new values written to them.

With mps_get_functionlist the DLL passes the list of addresses of all such MPS_functions. The function numbers correspond to the position of the function within the list. If a number is to remain free, then its address is passed as 0xffffffff (= -1). See also mps_demo.cpp.

IV. Motorola-side call

MPS_functions are called by a Motorola-side 8-byte opcode:

    dc.w    $4fbf       * 2 bytes: Do not alter!
    dc.l    DLL_ID      * 4 bytes: DLL-specific DLL_ID
    dc.w    Fkt_no.     * 2 bytes: Function number

DLL_ID is the DLL_ID (4 bytes!) passed via mps_get_functionlist. Function number is the position of the function in the function list passed by mps_get_functionlist (count starts at 0).

V. Miscellaneous

  1. Each DLL should use an individual DLL_ID to prevent conflicts between multiple DLLs (see mps_demo.h). DLL_IDs with bit 31 set are reserved for us (Application Systems) or for allocated IDs. Therefore please do not choose a DLL_ID with set bit 31! If we are to allocate a reserved DLL_ID to you, please get in touch with Herr Hoffmann of Application Systems Heidelberg.

    The following DLL_IDs have been allocated:

    DLL_ID Program name Author
    0x003f5c66 MPCTime Robert Weiß
    0x2053434B MPCSTiK Dan Ackerman
    0x21342812 Draconis Windows Sockets
    0x44594a01 In2Cat Dimitri Junker
    0x44594a02 Win_Lnk Dimitri Junker
    0x50475752 MPC_POWR Emanuel Welter

  2. Pay attention to the displacement of the address space!! If you want to use a Motorola address on the DLL side, you should call intel_adr(..) or intel_ptr(..) respectively for conversion (see MPS_magicinfo in mps_base.h). Addresses from the DLL address space can not be used Motorola-side!

  3. Also pay attention to the different byte order between Motorola and Intel processors. WORDs and LONGwords from the Motorola address space have to be swapped so that they lie correctly in the DLL. If anything is written back then it has to be swapped once more. For this you can call the functions swap_word(..) or swap_long(..) (see MPS_magicinfo in mps_base.h). BUT: Elements of MPS_motregs (d0-a7) are already in the Intel order and do not have to be swapped. mps_base.h

; ==========================================================
; Export definitions for MPS MagiC PC programmer's interface   FS 15.08.96
; ==========================================================
; !! DO NOT ALTER !!
; ==================
   mps_get_type         @101
   mps_get_functionlist @102
   mps_magicinfo        @103 mps_base.def

// Tab size: 3

// Last change:  15.08.96
// Author:   FS

// ------------------------------------------------------------------------------
// The MagiC PC programmer's interface
// mps_base.h: Basic include     !! ADOPT UNALTERED !!
//                               =====================

#ifdef __cplusplus
   extern "C" {

/* =========================================================================
   The DLL functions freely definable by the user have the form:
   void mps_function(MPS_motregs *r),
   where r represents a pointer to the 16 Motorola registers, so:
   typedef struct {                 // MPS_motregs = The Motorola registers
     long d0,d1,d2,d3,d4,d5,d6,d7;
     long a0,a1,a2,a3,a4,a5,a6,a7;
     } MPS_motregs;
                                    // MPS_fuptr = Pointer to a MPS_function:
   typedef void (*MPS_fuptr)(MPS_motregs *);

/* ======================================================================
   The DLL basic function mps_info is passed the following info block
   typedef struct {
     DWORD sizeof_str;           // Size of MPS_infostr
     DWORD magic_version;        // e.g. 0x010001
     DWORD magic_date;           // e.g. 19960815  (ascending)
     BYTE  is_demo;              // Is it a demo-version?
     BYTE  uu1, uu2, uu3;        // Still unused, 0

     BYTE *(*intel_adr)(DWORD motadr); // Convert address Motorola -> Intel
     BYTE *(*intel_ptr)(DWORD motptr); // Convert pointer Motorola -> Intel (NULL stays NULL!)

     WORD (*swap_word)(WORD w);           // Swap one WORD
     DWORD (*swap_long)(DWORD dw);        // Swap one LONGword
     } MPS_magicinfo;

// =============== 3 basic functions to be exported: ==================
   int mps_get_type();                                                        // @@101
   int mps_get_functionlist(DWORD *mps_dll_id,MPS_fuptr **p_functionslist);   // @@102
   void mps_magicinfo(MPS_magicinfo *is);                                     // @@103
// See also mps_base.cpp, mps_base.def

#ifdef __cplusplus

See also: MagiC PC interface mps_base.cpp

// Tab size: 3

// Last change:  15.08.96
// Author:   FS

// ------------------------------------------------------------------------------
// Demo example for (!nolink [MagiC]) PC programmer's interface (MPS)
// Part 1: Basic functions, adopt UNCHANGED!
// =======
// ------------------------------------------------------------------------------

#include "windows.h"
#include "mps_base.h"
#include "mps_demo.h"

// The following 3 basic functions must be exported by the DLL:

// 1) Basic function @101: Type query
// ---------------------
   int mps_get_type()
// ----------------
   return(0x4701);         // Must return this value

// 2) Basic function @102: MagiC PC requests ID and function list
// -----------------------
   int mps_get_functionlist(DWORD *mps_dll_id,MPS_fuptr **p_functionslist)
// ------------------------
   *mps_dll_id = DLL_ID;              // User-defined ID, see mps_demo.h
   *p_functionslist = my_funclist;    // Enter pointer to function list

// 3) Basic function @103: MagiC PC passes MPS_magicinfo to the DLL
// -----------------------
   void mps_magicinfo(MPS_magicinfo *is)
// -------------
   m_info = *is;                    // Remember

// END basic functions -------------------------------------------------------

See also: MagiC PC interface mps_demo.h

// Tab size: 3

// Last change:  15.08.96
// Author:   FS

// ------------------------------------------------------------------------------
// Demo example for MagiC PC programmer's interface (MPS)
// Part 2: User-defined functions, change DLL_ID to your own value !!!
// =======
// ------------------------------------------------------------------------------

#define DLL_ID  0x01020304           // Change to your own value
                                     // !! Values with bit 31 set are
                                     // reserved for Appl.Systems.
                                     // ID reservation: Apply to
                                     // Appl. Systems (Herr Hoffmann)!

   extern MPS_fuptr my_funclist[];   // Function list in the demo-DLL

   extern MPS_magicinfo m_info;      // Is adopted by MagiC PC

See also: MagiC PC interface mps_demo.cpp

// Tab size: 3

// Last change:  15.08.96
// Author:   FS

// ------------------------------------------------------------------------------
// Demo example for (!nolink [MagiC]) PC programmer's interface (MPS)
// Parl 2: User-defined functions, freely alterable
// =======
// ------------------------------------------------------------------------------

#include "windows.h"
#include "mps_base.h"
#include "mps_demo.h"

   MPS_magicinfo m_info;               // Global for the DLL

// List of the user-defined functions (alter/extend as required):
// ------------------------------------------------------------------
   static void demo_0(MPS_motregs *r);
   static void demo_1(MPS_motregs *r);
   static void demo_3(MPS_motregs *r);
   static void copy_string(MPS_motregs *r);

   MPS_fuptr my_funclist[] = {
     demo_0,                       // Demo function 0
     demo_1,                       // Demo function 1
     (MPS_fuptr) -1,               // -1 (i.e function No.2 not defined)
     demo_3,                       // Demo function 3
     copy_string,                  // Demo function 4
     NULL                          // !! A NULL-entry at list end !!
     } ;

// ******************************************************************
// Here the user-defined functions:
// ================================

// Demo_0 only returns the value 1 in d0:
   static void demo_0(MPS_motregs *r)
// ----------------------
   r->d0 = 1;                       // Demo-0 sets d0 to 1

// Demo_1 adds the registers d1 and d2; result to d0:
   static void demo_1(MPS_motregs *r)
// ----------------------
   r->d0 = r->d1 + r->d2;

// Demo_3 does nothing at all!
   static void demo_3(MPS_motregs *r)
// ----------------------

// Demo routine_4 copy_string copies a string to Motorola address space:
//                -----------
// a0: Destination address,
// d0: Maximum number of characters (incl. 0)
   static void copy_string(MPS_motregs *r)
// -----------------------
   static char string[] = "This is a demo-text of copy_string(..)";

   int i, nchmax;
   char *dest;

   nchmax = (int) r->d0;
   dest = (char *) (*m_info.intel_ptr)(r->a0);
   if (nchmax<=0 || dest==NULL) return;         // Invalid?

   for (i=0; itruncate

See also: MagiC PC interface testmps.s

*                                                 FS  15.08.96
*   ===========================================================
*   Sample for the call of the MPS functions from Motorola side
*   ===========================================================
* Source Windows-side:
* --------------------
* mps_base.cpp, mps_demo.cpp
mps_code .equ  $4fbf                   * !! DO NOT ALTER !!
DLL_ID   .equ  $01020304               * Enter own DLL_ID here

* -------------------------------------- 60 bytes buffer
bufsize  .equ  60
buffer:   ds.w  bufsize
* --------------------------------------

* ------------------- Here we go: -----------------------------------
.globl _main
      moveq    #-1,d0                  * d0 to -1 (for testing)

*     ===========================      * Call function 0 (Demo_0):
      dc.w     mps_code                * = $4fbf
      dc.l     DLL_ID                  * = Own DLL_ID
      dc.w     0                       * Function number (here 0)
*     ===========================
      cmpi.l   #1,d0                   * Should return 1
      bne      finish

* Example for call with parameters (copy_string)
* ----------------------------------
      movea.l  #buffer,a0              * Pointer to buffer for string
      move.l   #bufsize,d0             * Max. string length (incl.0-byte)

*     ===========================      * Call function 4 (copy_string):
      dc.w     mps_code                * = $4fbf
      dc.l     DLL_ID                  * = Own DLL_ID
      dc.w     4                       * Function number (here 4)
*     ===========================

      bsr      put_line                * Output line (a0)
      bsr      wait                    * Wait for keypress
* --------------------- END main routine _main -----------------------

* ------------------------ Output line (a0) --------------------------
      moveq    #13,d0
      bsr      put_char
      moveq    #10,d0
      bsr      put_char
      move.b   (a0)+,d0
      bne      put_lnext

* ------------------------ Output chatacter d0 -----------------------
      movem.l  d0-d2/a0-a2,-(sp)
      move.w   d0,-(sp)
      move.w   #2,-(sp)
      move.w   #3,-(sp)
      trap     #13
      addq.l   #6,sp
      movem.l  (sp)+,d0-d2/a0-a2

* -------------------------- Wait for keypress -----------------------
      move.w   #2,-(sp)
      move.w   #2,-(sp)
      trap     #13
      addq.l   #4,sp

See also: MagiC PC interface

14.2.2 mec1 interface

  1. Concept

    The mec1 interface makes it possible to call functions predefined by the emulator in Motorola code. In principle it is similar to the mec0 (MPS) interface, though the functions are not freely definable in a DLL but already predefined by the emulator. Call: The functions are called uniformly by the opcode $43bf, followed by a function number, thus with 4 bytes total length. Example:

    dc.w $43bf,$0031

    calls the mec1 function with the number 0x31. ($43bf is the opcode for chk ,d1, with = 111111 binary, so invalid). Parameter passing is, as with mec0, via the Motorola registers.

  2. The functions

    $0001 long emu_version:

    Parameters: None
    Return: d0: Version number
      d1: Version date
      d2: Bit0: Is it a demo-version?
    $0002 long emu_enquire: Obtains diverse information

    Parameters: long d0: What do you want to know?
    Return: long d0: Value

    bisher definiert:

    was: 1: Version number
      2: Version date
      3: Is it a demo?
    $0003 void emu_getexepath: Obtains the full path (including drive, without MAGIC_PC.EXE)

    Parameters: a0: char *bufadr (Buffer)
      d0: short nb_max (Max. bytecount for buffer)
    $0004 int emu_install_newvdi:

    Parameters: a0: Byte *bufadr (New contents of NVDI_PC.DLL)
      d0: long nbytes (Length)
    Return: d0: >0: NVDI_PC.DLN sucessfully created.
      At next runup it will be automatically
      renamed to NVDI_PC.DLL, as discussed.
    $0010 void dw_addline:  ! As of 03.97

    Output text in new line in the debug window

    Parameters: a0: Pointer to the text.
    $0011 void dw_addtext:  ! As of 03.97

    Output text in debug window

    Parameters: a0: Pointer to the text
    $0011 void dw_formtxt:  ! As of 03.97

    Output text sprintf-like in debug window

    Parameters: a0: Pointer to the format-string
      d0, d1, ... Additional parameters suitable
      for the format-string. The format-string
      corresponds roughly to sprintf(format,...);
      string pointers are not allowed, however.
    $0031 int printer_open  ! As of 03.97

    printer_open Opens the standard printer and starts a new document

    Parameters: a0: char *DocName (NULL-pointer allowed)
    Return: d0>0: All OK
      d0<=0 Error
    $0032 int printer_close  ! As of 03.97

    printer_close Terminates the previously opened document and closes the printer

    Parameters: None
    Return: d0>0: All OK
      d0<=0 Error
    $0033 int printer_write  ! As of 03.97

    Parameters: a0: Byte *pData; // Pointer to the data buffer
    d0: long nBytes; // No. of bytes in buffer
    Return: d0: Number of bytes transferred
    $0040 DWORD getTickCount  ! As of 03.97

    Return: d0: TickCount (msec since start of the computer)
    $0041 DWORD getDrivePath  ! ab 02.99

    The function obtains the Windows path for a MagiC drive

    Parameters: d0: Drive No. (0 for A:, 1 for B:, ...)
      a0: Text buffer for the path
      d1: Size of the text buffer
    Return: d0: 0: Not found,
          1: Container drive,
          2: xfs drive (Windows drive)
          4: Floppy drive
    $0042 DWORD setClipboardDir  ! ab 02.99

    Parameters: a0: char *pPath // NULL: Set to default
    Return: d0: 1

            movea.l stringadr,a0    *
            dc.w    $43bf,$0042     * mec1, call function $42
            tst.l   d0              * -1: Function not implemented
            jl  nichtimplementiert
    $0043 long getMouseWheel

    Parameters: d0.l: 1: Reset position after readout
          0: Don't reset position after readout
    Return: d0.l: Current position of the mouse-wheel

            moveq   #1,d0       * Reset position after readout
            dc.w    $43bf,$0043 * mec1, call function $43
            tst.l   d0          * Position altered since last reset
            je  no_action
    $0045 long setCompiler  ! As of 17.06.99

    Parameters: d0.l: Selection; realised at present:
      d0 = 1: Switch compiler on/off:
      d1 = 0: Compiler off,
      d1 = 1: Compiler on
      d1 = -1: Query mode (from my experience
               this does not work, but it ought
               to work in the 6.20 version)
    Return: Old mode (0 or 1)

HomeEmulatorsMagiC Mac specificsSTEmulator