=============================================================================
                       =   =   =   M2Code   =   =   =

                          © Copyright  1988 by
                            Fridtjof Siebert
                              Nobileweg 67
                      7000 Stuttgart 40 (Stammheim)
                            Tel: 0711/822509
=============================================================================

M2Code ist für und mit dem Modulacompiler von TDI geschrieben. Es
ermöglicht,  PC-relative Maschinenroutinen in Modulaprogramme einzubinden.
Dies ist normalerweise nur über Libraries, oder bei kleinen Routinen durch
direktes Berechnen des Maschinencodes möglich. Nun können mit einem
Assembler (z.B. Profimat) geschriebene Assemblerprogramme leicht in Module
umgewandelt werden.

Um PC-relative Maschinenroutinen zu schreiben, muß man lediglich im Assem-
blermenü `PC-relativ' anwählen. Probleme gibt es nur, wenn man in eine ab-
solute Addresse schreiben möchte. Dazu muß man sie in ein Addressregister
laden und dann indirekt addressieren:
LEA  Addresse,Ax
MOVE yyyy,(Ax)
Möchte man in mehrere nahe beieinanderliegende Addressen schreiben, kann
man auch mit Offset addressieren.

M2Code erzeugt aus Maschinensprachecode compilierbare Definitions- und
Implementationmodule. Dabei wird der Code mit der von SYSTEM exportierten
CODE()-Funktion eingefügt.

Es ist möglich, Werte beliebiger, zum Typ ADDRESS kompatibler Typen an
beliebige Register zu übergeben und von dort zurückzuerhalten.

Mit M2Code ist es nur möglich, eine Maschinenspracheprocedure in ein Modul
umzuwandeln. Doch kann man mit leicht mit einem guten Texteditor verschie-
dene Procedures in einem Modul zusammenzufassen.

Syntax von M2Code:

M2Code Src {-cRx:TYPE|vRx:TYPE|-sRx} [-rRx:TYPE] [-sall] [-d] [-p]

Die Parameter in den geschweiften Klammern können beliebig oft angegeben
werden, die in eckigen Klammern sind optional. Die Reihenfolge der
Parameter ist egal. Wird kein Parameter angegeben, wird eine Kurzbe-
schreibung der Syntax ausgegeben.

Src  ist der Name des PC-relativ assemblierte Maschinencodes. Normal
     assemblierter, ausführbarer Code kann nicht verwendet werden. Dies
     dürfte allerdings nicht allzu schlimm sein, da PC-relativer normal-
     erweise schneller ist als absoluter Code. Die Maschinenroutine muß im
     aktuellen Directory stehen. Der erzeugte Modulname und Procedurename
     wird aus diesem Namen erzeugt, indem ein eventuelles Suffix (.xxx)
     abgeschnitten wird. Für den Namen des Definition- und
     Implementationmoduls wird .def bzw. .mod angehängt.

Rx   ist ein 68000-Register. Es kann groß und klein geschrieben werden: D2,
     a5, A2,  etc.

TYPE ist ein Modula-Variablentyp. Er muß zum Typ ADDRESS kompatibel sein,
     d.h. er muß in ihn umwandelbar sein. Beispiele sind BYTE, LONGCARD,
     INTEGER, POINTER, PROCEDURE, etc.

Die Parameter:

-c    teilt M2Code mit, daß der Maschinenroutine ein konstanter Wert vom Typ
      TYPE im Register Rx übergeben wird. Zur Übergabe wird der Wert in den
      Typ ADDRESS umgewandelt.

-v    ist das Gegenstück zu -c für variable Parameter. Nach Beendigung der
      Maschinenroutine wird der dann in Rx stehende Wert zurück in TYPE
      umgewandelt und von der Procedure in die Übergebene Variable
      geschrieben.

-r    wird für Routinen verwendet, die ein Ergebnis mit RETURN zurückgeben.
      Der Inhalt von Rx wird nach der Maschinenroutine in TYPE umgewandelt
      und mit RETURN an das aufrufende Modul übergeben.

-s    rettet das Register Rx. Damit ist es möglich, für Modula wichtige
      Register auf den Stack zu retten. Die Maschinenroutine braucht sich
      dann nicht um die Zwischenspeicherung der Register zu kümmern.
      Besonders wichtig ist hierbei A6, da es durch einen LINK-Befehl den
      Stackpointer enthält. Welche anderen Register wichtige Werte
      enthalten weiß ich leider nicht. Wahrscheinlich können jedoch D0, D1,
      A0 und A1 frei verwendet werden. Die anderen Register sollten
      sicherheitshalber gespeichert werden. Register werden zuerst geret-
      tet, bevor ihnen Parameter übergeben werden. Es ist also z. B.
      möglich, die Addresse einer Library in A6 zu übergeben, wenn man A6
      mit -sA6 rettet. Gespeicherte Register werden nach der Beendigung der
      Maschinenroutine wieder zurückgeladen.

-sall ermöglicht es, alle Register, außer A7, ohne jedes einzeln hinzu-
      schreiben, auf den Stack zu retten.

-d    löscht ein Nullwort am Ende des Maschinencodes, wenn es auf einer nicht
      durch 4 teilbaren Addresse liegt. Dies ist nötig, da Profimat die Länge
      des Maschinencodes immer auf Vielfache von 4 aufrundet. Das evt.
      angefügte Wort (ein oder drei BYTE sollten es nicht sein !!!) ist eine
      Null. Da 0000H dem Assemblerbefehl `ori.b #xx' entspricht, wird das
      erste Wort des nächsten Befehls übersprungen. Das kann verheerende
      Folgen haben. Es ist also empfehlenswert, wenn man sicher ist, daß
      das letzte Wort des wirklichen Programmes keine 0 ist, -d anzugeben.
      Ansonsten muß man das letzte Wort eventuell von Hand aus dem
      erzeugten Implementation- module entfernen.

-p    fügt ein `(*$P-*)' in das Implementation-Module ein. Dadurch wird
      beim Compilieren der normale Code zum Einsteigen und Verlassen einer
      Procedure weggelassen. LINK und UNLNK fällt weg, wodurch keine
      Variablen in der Procedure verwendet werden können. Am Ende der
      Procedure steht kein RTS. Die Assemblerroutine muß also den RTS-Befehl
      enthalten. Register mit -s nicht gespeichert und  mit -r nicht
      zurückgegeben werden, da der Rücksprung in der Routine selbst steht.
      Wird -p nicht angegeben darf die Routine kein RTS enthalten. Die
      Routine muß dann so geschrieben sein, daß der PC nach ihrer Beendigung
      hinter ihr steht.

Beispiel:

M2Code Beispiel -vA0:ADDRESS -cD0:WORD -vD3:BYTE -rA3:LONGCARD -sD3 -sA3

erzeugt folgendes Definitionmodul und speichert es als Beispiel.def:

  DEFINITION MODULE Beispiel;

  FROM SYSTEM IMPORT BYTE,WORD,LONGWORD,ADDRESS,PROCESS;

  (*------  Beispiel  ------*)

  PROCEDURE Beispiel(VAR a:ADDRESS;b:WORD;VAR c:BYTE):LONGCARD;

  END Beispiel.

Außerdem wird das Implementationmodul Beispiel.mod erzeugt:

  IMPLEMENTATION MODULE Beispiel;

  FROM SYSTEM IMPORT BYTE,WORD,LONGWORD,ADDRESS,PROCESS,CODE,SETREG,REGISTER;

  CONST
    MOVEMS = 48E7H;
    MOVEML = 4CDFH;

  (*------  Beispiel  ------*)

  PROCEDURE Beispiel(VAR a:ADDRESS;b:WORD;VAR c:BYTE):LONGCARD;

  BEGIN

    CODE(MOVEMS,01010H);

    SETREG(8,ADDRESS(a));
    SETREG(0,ADDRESS(b));
    SETREG(3,ADDRESS(c));

    CODE(0xxxxH,0yyyyH, ... ,0zzzzH);

    a := ADDRESS(REGISTER(8));
    c := BYTE(REGISTER(3));

    RETURN LONGCARD(REGISTER(11));

    CODE(MOVEML,00808H);

  END Beispiel;

  BEGIN
  END Beispiel.

Der Eingefügte CODE in der Mitte hängt von dem File `Beispiel' ab, das den
Maschinencode enthalten soll.

Die Module können jetzt compiliert und in Modulaprogramme eingebunden werden.

Im Directory M2CodeDemo befindet sich ein Beispiel für die Einbindung eines
Maschinenprogramms. DrawLines.asm ist der Assemblerquelltext für DrawLines.
DrawLines.def und DrawLines.mod wurden mit `M2Code DrawLines.prg -ca2:ADDRESS
-ca6:ADDRESS -sd2 -sd3 -sa6 -d' erzeugt. Draw.mod ist der Modula-Quellcode
für das Hauptprogramm. Es öffnet einen Screen und die Graphicslibrary. Der
DrawMode wird auf Complement gesetzt. Danach wird DrawLines aufgerufen, was
20480 Linien zeichnet. Zum Schluß schließt Draw den Screen und die Graphics-
library wieder.

Ein Demo, das sehr schön den Geschwindigkeitsunterschied zwischen Modula und
Assembler zeigt, ist im M2CodeDemo2-Directory. Sort.mod enthält eine einfache
Sortierroutine für ein CardinalFeld. AssSort.asm ist die gleiche Routine in
Assembler. Aus AssSort.prg wurden die AssSort.def und AssSort.mod-Files mit
`M2Code AssSort.prg -ca0:ADDRESS -cD0:LONGCARD -sd2 -sd3 -sd4 -d' erstellt.
Die Programme AssSortDemo und SortDemo füllen ein Feld mit 1000 zufälligen
CARDINALs. Das Feld wird danach mit AssSort bzw. SortDemo sortiert und danach
ausgegeben. Die Maschinenroutine ist fast 6x so schnell als die in Modula.
