Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| cpm:turbo_pascal:cpm80 [2026/06/18 12:44] – angelegt volkerp | cpm:turbo_pascal:cpm80 [2026/06/18 13:44] (aktuell) – [Funktionen/Prozeduren] volkerp | ||
|---|---|---|---|
| Zeile 3: | Zeile 3: | ||
| ===== Kommandozeilen-Parameter ===== | ===== Kommandozeilen-Parameter ===== | ||
| - | Das P Kommando erlaubt Ihnen einen oder mehrere Parameter einzugeben, | + | Das **P Kommando** erlaubt Ihnen einen oder mehrere Parameter einzugeben, |
| die an Ihr Programm übergeben werden, wenn es im Memory-Modus läuft. | die an Ihr Programm übergeben werden, wenn es im Memory-Modus läuft. | ||
| Dies geschieht genauso wie bei der Eingabe von Parametern in der DOS Kommandozeile. | Dies geschieht genauso wie bei der Eingabe von Parametern in der DOS Kommandozeile. | ||
| Zeile 14: | Zeile 14: | ||
| Chain(FilVar)\\ | Chain(FilVar)\\ | ||
| Execute(FilVar) | Execute(FilVar) | ||
| + | |||
| + | Die Chain Prozedur wird nur benutzt, um spezielle .CHN TURBO Pascal Dateien | ||
| + | zu aktivieren, d.h. Dateien, die mit der cHn-Datei Option des Optionenmenüs | ||
| + | compiliert wurden. Solche Dateien enthalten nur Object- | ||
| + | Code, aber keine Pascal Library mehr. Diese wird schon mit dem Hauptprogramm | ||
| + | in den Speicher geladen und an der Startadresse des gegenwärtigen | ||
| + | Programms, d.h. der Adresse, die sich beim Compilieren dieses Programms | ||
| + | ergibt, ausgeführt. Das .CHN-File wird bei Aufruf aus dem Hauptprogramm | ||
| + | in den Speicher geladen und das Hauptprogramm muß deshalb die | ||
| + | gleiche Startadresse haben, wie das aufgerufene Programm. | ||
| + | |||
| + | Die Execute Prozedur kann zur Ausführung jeder .COM Datei verwendet werden. Die Datei wird an der Adresse $100 geladen und ausgeführt, | ||
| Daten können vom laufenden Programm zum chained (verketteten) Programm | Daten können vom laufenden Programm zum chained (verketteten) Programm | ||
| Zeile 64: | Zeile 76: | ||
| ===== Overlays ===== | ===== Overlays ===== | ||
| + | |||
| + | Das Overlay System (Overlay=Überlagerung) erlaubt Ihnen, viel größere Programme | ||
| + | zu erzeugen, als der Speicher Ihres Computers fassen kann. Die | ||
| + | Technik ist, eine Reihe von Unterprogrammen (Prozeduren und Funktionen) in | ||
| + | einer oder mehreren Dateien, getrennt von der Hauptdatei, zusammenzufassen, | ||
| + | die darin beim Programmlauf automatisch, | ||
| + | im Speicher geladen werden. | ||
| + | |||
| + | Wenn eine der Overlayprozeduren aufgerufen wird, wird diese automatisch in | ||
| + | den im Hauptprogramm reservierten Overlaybereich geladen. Diese Lücke ist | ||
| + | groß genug, um sogar die größten Overlays der Gruppe zu fassen. Der vom | ||
| + | Hauptprogramm benötigte Platz wird deshalb um etwa die Summe aller Unterprogramme | ||
| + | in der Gruppe minus des größten reduziert. | ||
| + | |||
| + | Overlay-Unterprogramme werden automatisch erzeugt, einfach indem das reservierte | ||
| + | Wort **overlay** bei der Deklaration einer beliebigen Prozedur oder | ||
| + | Funktion hinzugefügt wird. Aufeinanderfolgende Overlay-Unterprogramme werden zusammengruppiert. | ||
| + | Mit anderen Worten, solange Overlay-Unterprogramme nicht durch eine andere | ||
| + | Deklarierung getrennt werden, gehören sie zur selben Gruppe und werden | ||
| + | in dieselbe Overlaydatei plaziert. | ||
| + | |||
| + | |||
| + | Während der Ausführung erwartet das System, dass sich Overlay-Dateien auf | ||
| + | dem angemeldeten Laufwerk befinden. Die Prozedur OvrDrive kann zur Veränderung | ||
| + | dieses Werts verwendet werden. | ||
| OvrDrive(Laufwerk); | OvrDrive(Laufwerk); | ||
| Zeile 80: | Zeile 117: | ||
| end; | end; | ||
| overlay procedure ProcB; | overlay procedure ProcB; | ||
| - | hegin | + | begin |
| - | Writeln(' | + | Writeln(' |
| end; | end; | ||
| Zeile 91: | Zeile 128: | ||
| overlay procedure ProcC; | overlay procedure ProcC; | ||
| begin | begin | ||
| - | | + | |
| end; | end; | ||
| Zeile 97: | Zeile 134: | ||
| OvrDrive(2); | OvrDrive(2); | ||
| ProcA; { erste Overlay-Datei mit ProcA und ProcB } | ProcA; { erste Overlay-Datei mit ProcA und ProcB } | ||
| - | OvrDrive(0); | + | OvrDrive(0); |
| ProcC; { zweite Overlay-Datei mit ProcC } | ProcC; { zweite Overlay-Datei mit ProcC } | ||
| OvrDrive(2); | OvrDrive(2); | ||
| Zeile 129: | Zeile 166: | ||
| ===== Funktionen/ | ===== Funktionen/ | ||
| - | Addr(name) | + | | Addr(name) |
| - | MemAvail ermittelt freien Platz auf dem Heap. | + | | MemAvail |
| - | Ord(ptr) gibt die in einem Zeigerargument enthaltene Adresse als ganze Zahl aus. | + | | Ord(ptr) |
| - | Ptr(addr) wandelt sein ganzzahliges Argument in einen Zeiger um | + | | Ptr(addr) |
| - | Bdos(Func[, | + | | Bdos(Func[, |
| - | BdosHL(Func[, | + | | BdosHL(Func[, |
| - | Bios(Func[, | + | | Bios(Func[, |
| + | | BiosHL(Func[, | ||
| + | |||
| + | BDOS [[..: | ||
| + | |||
| + | bdos(26, Adresse); { Setdma } | ||
| + | bdoshl(31); { liefert DPB } | ||
| + | |||
| + | BIOS [[..: | ||
| + | |||
| + | bios(9, Spur); { SETTRK } | ||
| + | bioshl(8, Drive); { SELDSK } | ||
| Benutzergeschriebene I/O Treiber: | Benutzergeschriebene I/O Treiber: | ||
| - | Variable enthält die Adresse der | + | ^Variable |
| - | ConStrPtr function ConSt: | + | | ConStrPtr |
| - | ConInPtr procedure Conln:Char | + | | ConInPtr |
| - | ConOutPtr procedure ConOut(Ch: | + | | ConOutPtr |
| - | LstOutPtr procedure LstOut(Ch: | + | | LstOutPtr |
| - | AuxOutPtr procedure AuxOut(Ch: | + | | AuxOutPtr |
| - | AuxInPtr function Auxln:Char | + | | AuxInPtr |
| - | UsrOutPtr procedure UsrOut(Ch: | + | | UsrOutPtr |
| - | UsrInPtr function Usrin: | + | | UsrInPtr | function Usrin: |
| ===== Externe Unterprogramme ===== | ===== Externe Unterprogramme ===== | ||
| + | Schlüsselwort **external** + Adresse: | ||
| + | <code pascal> | ||
| procedure DiskReset; external $EC00; | procedure DiskReset; external $EC00; | ||
| function IOStatus: boolean; external $D123; | function IOStatus: boolean; external $D123; | ||
| + | </ | ||
| Parameter können an externe Unterprogramme übergehen werden. Die Syntax | Parameter können an externe Unterprogramme übergehen werden. Die Syntax | ||
| ist genau dieselbe, wie bei normalen Prozedur- und Funktionsaufrufen: | ist genau dieselbe, wie bei normalen Prozedur- und Funktionsaufrufen: | ||
| + | |||
| + | <code pascal> | ||
| procedure Plot(X,Y: Integer); external $F003; | procedure Plot(X,Y: Integer); external $F003; | ||
| procedure QuickSort(var List: PartNo); external $1C00; | procedure QuickSort(var List: PartNo); external $1C00; | ||
| + | </ | ||
| + | ==== Parameter ==== | ||
| - | Parameter | ||
| Parameter werden an Prozeduren und Funktionen mittels des Z-80 Stack | Parameter werden an Prozeduren und Funktionen mittels des Z-80 Stack | ||
| - | übergeben. Normalerweise braucht dies den Programmierer nicht zu interessieren, | + | übergeben. |
| - | da der von TURBO Pascal erzeugte Maschinencode automatisch Parameter | + | |
| - | vor einem Aufruf auf einen Stack schiebt (PUSH) und sie bei Beginn | + | |
| - | eines Unterprogramms holt (POP). Falls ein Programmierer externe Unterprogramme | + | |
| - | verwenden will, müssen diese selbst die Parameter vom Stack holen | + | |
| - | (POP). | + | |
| Am Eingang zu einer external Unterroutine enthält der oberste Teil des Stack | Am Eingang zu einer external Unterroutine enthält der oberste Teil des Stack | ||
| immer die Rückkehradresse (ein Wort). Die Parameter, falls vorhanden, liegen | immer die Rückkehradresse (ein Wort). Die Parameter, falls vorhanden, liegen | ||
| Zeile 176: | Zeile 225: | ||
| holen (POP), dann alle Parameter und die Rückkehradresse schließlich | holen (POP), dann alle Parameter und die Rückkehradresse schließlich | ||
| wieder abspeichern, | wieder abspeichern, | ||
| - | 22.19.1 Variabien-Parameter | + | |
| - | Bei einem Variablen VAR-Parameter wird ein Wort auf den Stack übertragen, | + | Bei einem **Variablen VAR-Parameter** wird ein Wort auf den Stack übertragen, |
| indem die absolute Speicheradresse des ersten besetzten Bytes des aktuellen | indem die absolute Speicheradresse des ersten besetzten Bytes des aktuellen | ||
| Parameters angegeben wird. | Parameters angegeben wird. | ||
| - | 22.19.2 Wert-Parameter | + | |
| - | Bei einem Wertparameter hängen die auf den Stack übertragenen Daten vom | + | Bei einem **Wertparameter** |
| Typ des Parameters ab, wie in den folgenden Abschnitten beschrieben. | Typ des Parameters ab, wie in den folgenden Abschnitten beschrieben. | ||
| - | 22.19.2.1 Skalare | + | |
| - | Inleger, Boolean, Char und deklarierte skalare Typen werden als ein Wort auf | + | **Inleger, Boolean, Char** und deklarierte skalare Typen werden als ein Wort auf |
| - | •den Stack übertragen. Wenn die Variable bei der Speicherung nur ein Byte belegt, | + | den Stack übertragen. Wenn die Variable bei der Speicherung nur ein Byte belegt, |
| ist das signifikanteste Byte des Parameters 0. Normalerweise wird ein | ist das signifikanteste Byte des Parameters 0. Normalerweise wird ein | ||
| Wort vom Stack durch eine Instruktion wie POP HL geholt. | Wort vom Stack durch eine Instruktion wie POP HL geholt. | ||
| - | 22.19.2.2 Reelle Zahlen | + | |
| - | Eine reelle Zahl wird mit 6 Bytes auf den Stack übertragen. | + | Eine **reelle Zahl** wird mit 6 Bytes auf den Stack übertragen |
| - | mit der Instruktionssequenz | + | |
| - | POP HL | + | Wenn ein **String** an der obersten Adresse des Stack ist, enthält das Byte, auf |
| - | POP DE | + | |
| - | POP BC | + | |
| - | geholt werden, dann enthält L den Exponenten, H das fünfte (am wenigsten signifikante) | + | |
| - | Byte der Mantisse, E das vierte, D das dritte, C das zweite und B | + | |
| - | das erste (signifikanteste) Byte. | + | |
| - | 22.19.2.3 Strings | + | |
| - | Wenn ein String an der obersten Adresse des Stack ist, enthält das Byte, auf | + | |
| das durch SP gezeigt wird, die Länge des Strings. Die Bytes an den Adressen | das durch SP gezeigt wird, die Länge des Strings. Die Bytes an den Adressen | ||
| - | SR+ 1 bis SP+n (wobei n die Länge des String ist) enthalten den String, wobei | + | SP+1 bis SP+n (wobei n die Länge des String ist) enthalten den String, wobei |
| das erste Zeichen an der niedrigsten Adresse gespeichert wird. Die folgenden | das erste Zeichen an der niedrigsten Adresse gespeichert wird. Die folgenden | ||
| Maschinencode-Instruktionen können benutzt werden, um den String an der | Maschinencode-Instruktionen können benutzt werden, um den String an der | ||
| Spitze des Stack zu holen (POP) und in StrBuf zu speichern. | Spitze des Stack zu holen (POP) und in StrBuf zu speichern. | ||
| + | < | ||
| LD DE, | LD DE, | ||
| LD HL,0 | LD HL,0 | ||
| Zeile 212: | Zeile 255: | ||
| LDIR | LDIR | ||
| LD SP,HL | LD SP,HL | ||
| - | 22.19.2.4 Mengen | + | </ |
| - | Eine Menge belegt immer 32 Bytes im Stack (die Mengenkompression wird | + | Eine **Menge** belegt immer 32 Bytes im Stack |
| - | nur beim Laden und Speichern von Mengen verwendet). Die folgende Maschinecode- | + | |
| - | Instruktion kann benutzt werden, um die Menge an der Spitze des | + | Ein **Zeiger** wird als ein Wort auf den Steck übertragen, |
| - | Steck zu holen (POP) und in SetBuf zu speichern. | + | |
| - | LD DE, | + | |
| - | LD HL,0 | + | |
| - | ADD IlL, | + | |
| - | LD BC,32 | + | |
| - | LDIR | + | |
| - | LD SP,HL | + | |
| - | Damit wird das am wenigsten signifikante Byte der Menge an der niedrigsten | + | |
| - | Adresse in SetBuf gespeichert. | + | |
| - | 22.19.2.5 Zeiger | + | |
| - | Ein Zeiger wird als ein Wort auf den Steck übertragen, | + | |
| Variable enthält. Der Wert NIL entspricht dem Wort Null. | Variable enthält. Der Wert NIL entspricht dem Wort Null. | ||
| - | 22.19.2.6 | + | |
| - | Auch wenn sie als Wert-Parameter verwendet | + | **Arrays und Records** werden |
| - | nicht wirklich | + | |
| wird ein Wort übertragen, | wird ein Wort übertragen, | ||
| enthält. Es liegt dann in der Verantwortlichkeit der Unterroutine, | enthält. Es liegt dann in der Verantwortlichkeit der Unterroutine, | ||
| holen (POP) und es als die Ursprungsadresse in einer Blockkopieroperation | holen (POP) und es als die Ursprungsadresse in einer Blockkopieroperation | ||
| zu benutzen. | zu benutzen. | ||
| - | 22.20 Ergebnisse von Funktionen | + | |
| + | ==== Ergebnisse von Funktionen | ||
| Vom Benutzer geschriebene external Funktionen müssen ihre Ergebnisse exakt | Vom Benutzer geschriebene external Funktionen müssen ihre Ergebnisse exakt | ||
| in folgender Weise spezifizieren. | in folgender Weise spezifizieren. | ||
| Zeile 245: | Zeile 278: | ||
| muß den Exponenten enthalten. | muß den Exponenten enthalten. | ||
| Strings und Mengen müssen an die oberste Adresse des Steck ausgegeben | Strings und Mengen müssen an die oberste Adresse des Steck ausgegeben | ||
| - | werden in Formaten, wie sie auf Seite 284 beschrieben | + | werden in Formaten, wie oben beschrieben. |
| Zeigerwerte müssen in das HL Registerpaar ausgegeben werden. | Zeigerwerte müssen in das HL Registerpaar ausgegeben werden. | ||
| Zeile 255: | Zeile 288: | ||
| einer oder mehreren Konstanten, Variablenbezeichnern oder Kommandozählerreferenzen, | einer oder mehreren Konstanten, Variablenbezeichnern oder Kommandozählerreferenzen, | ||
| die durch Schrägstriche getrennt und in Klammern eingeschlossen | die durch Schrägstriche getrennt und in Klammern eingeschlossen | ||
| - | sind. | + | sind.\\ |
| Ein Codeelement ist aus einem oder mehreren Datenelementen aufgebaut, | Ein Codeelement ist aus einem oder mehreren Datenelementen aufgebaut, | ||
| die durch (+) oder (-) Zeichen getrennt sind. Ein Datenelement ist entweder | die durch (+) oder (-) Zeichen getrennt sind. Ein Datenelement ist entweder | ||
| eine integer Konstante, ein Variablenbezeichner, | eine integer Konstante, ein Variablenbezeichner, | ||
| Funktionsbezeichner oder ein Kommandozählerwert. Ein Kommandozählerwert | Funktionsbezeichner oder ein Kommandozählerwert. Ein Kommandozählerwert | ||
| - | wird als (*) Stern geschrieben. | + | wird als (*) Stern geschrieben.\\ |
| Die Zeichen < und > können verwendet werden, um die | Die Zeichen < und > können verwendet werden, um die | ||
| automatische Größenwahl zu überschreiben. Wenn das Codeelement mit | automatische Größenwahl zu überschreiben. Wenn das Codeelement mit | ||
| Zeile 285: | Zeile 318: | ||
| beide voll interruptfähig. Interruptroutinen müssen alle benutzten Register zurückgeben. | beide voll interruptfähig. Interruptroutinen müssen alle benutzten Register zurückgeben. | ||
| Falls benötigt, können Interruptroutinen in Pascal geschrieben werden. Solche | Falls benötigt, können Interruptroutinen in Pascal geschrieben werden. Solche | ||
| - | Prozeduren sollten immer mit dem A Compilerbefehl | + | Prozeduren sollten immer mit dem A Compilerbefehl |
| Sie dürfen keine Parameter enthalten und müssen selbst sicherstellen, | Sie dürfen keine Parameter enthalten und müssen selbst sicherstellen, | ||
| - | daß alle benutzten Register aufbewahrt werden. Dies geschieht, indem eine | + | daß alle benutzten Register aufbewahrt werden. Die letzte Instruktion der inline |
| - | inline Anweisung mit den notwendigen PUSH-Instruktionen ganz zu Beginnn | + | |
| - | der Prozedur plaziert wird und eine weitere inline Anweisung mit den entsprechenden | + | |
| - | POP-Instruktionen ganz am Ende. Die letzte Instruktion der inline | + | |
| Anweisung sollte eine EI Instruktion ($FB) sein, um weitere Interrupts zu ermöglichen. | Anweisung sollte eine EI Instruktion ($FB) sein, um weitere Interrupts zu ermöglichen. | ||
| Wenn daisy chained (verkettete) Interrupts benutzt werden, kann | Wenn daisy chained (verkettete) Interrupts benutzt werden, kann | ||
| die inline Anweisung auch eine RETI Instruktion ($ED,S4D) spezifizieren, | die inline Anweisung auch eine RETI Instruktion ($ED,S4D) spezifizieren, | ||
| die durch den Compiler erzeugte RET Instruktion überschreibt. | die durch den Compiler erzeugte RET Instruktion überschreibt. | ||
| - | Die generellen Regeln für den Registergebrauch sind, daß ganzzahlige Operationen | ||
| - | nur die AF, BC, DE und HL Register verwenden können; andere Operationen | ||
| - | können IX und IV und reelle Operationen wechselnde Register verwenden. | ||
| Eine Interruptprozedur sollte keine I/O Operation mit Standardprozeduren | Eine Interruptprozedur sollte keine I/O Operation mit Standardprozeduren | ||
| oder -funktionen von TURBO Pascal benutzen, da diese Routinen nicht rückspringend | oder -funktionen von TURBO Pascal benutzen, da diese Routinen nicht rückspringend | ||
| - | sind. Dies gilt auch für BDOS-Aufrufe (und gelegentlich für BIOSAufrufe, | + | sind. Dies gilt auch für BDOS-Aufrufe (und gelegentlich für BIOS-Aufrufe, |
| - | abhängig von der spezifischen CP/M Implementation). | + | abhängig von der spezifischen CP/M Implementation).\\ |
| - | Der Programmierer kann mit den Instruktionen DI oder EI einer inline-Anwe | + | Der Programmierer kann mit den Instruktionen DI oder EI einer inline-Anweisung |
| - | sung jederzeit im Programm Interrupts außer Kraft setzen oder erlauben. | + | |
| Wenn Modus 0 (IM 0) oder Modus 1 (IM 1) Interrupts benutzt werden, liegt es | Wenn Modus 0 (IM 0) oder Modus 1 (IM 1) Interrupts benutzt werden, liegt es | ||
| in der Verantwortlichkeit des Programmierers, | in der Verantwortlichkeit des Programmierers, | ||
| Seite zu initialisieren (Beachten Sie, daß RST 0 nicht verwendet werden kann, | Seite zu initialisieren (Beachten Sie, daß RST 0 nicht verwendet werden kann, | ||
| - | da CP/M die Stellen 0 bis 7 benutzt). | + | da CP/M die Stellen 0 bis 7 benutzt).\\ |
| Wenn Modus 2 (IM 2) Interrupts verwendet werden, sollte der Programmierer | Wenn Modus 2 (IM 2) Interrupts verwendet werden, sollte der Programmierer | ||
| eine initialisierte Sprungtabelle (ein Array von integer Zahlen) an einer absoluten | eine initialisierte Sprungtabelle (ein Array von integer Zahlen) an einer absoluten | ||
| Adresse erzeugen und das Register I durch eine inline Anweisung am Anfang | Adresse erzeugen und das Register I durch eine inline Anweisung am Anfang | ||
| des Programms initialisieren. | des Programms initialisieren. | ||
| - | |||