CP/M Basic Input/Output System
Das BIOS ist der maschineabhängige Teil von CP/M.
Theoretisch muss nur das BIOS angepasst werden und CP/M läuft auf einer anderen Maschine.
Für den Aufruf der BIOS-Funktionen bieten sich zwei Möglichkeiten an:
Direkter Aufruf
|
Aufruf über BDOS
|
OS equ 0000h
ld hl,(OS+1) ; BIOS Basisadresse laden
ld de,3*(BIOS-Nr.-1)
add hl,de ; Adresse fuer Vektor berechnen
jp (hl) ; Und ausfuehren
|
BDOS equ 0000h
ld de,BIOSPB ; BIOS Parameterblock laden
ld c,50 ; BDOS Funktion laden
call BDOS ; Adresse fuer USERF berechnen
ret
BIOSPB:
db BIOS-Funktion ;0-32
db BIOS-A ;Bytewert fuer Akku
dw BIOS-BC ;Wortwert fuer Registerpaar BC
dw BIOS-DE ;Wortwert fuer Registerpaar DE
dw BIOS-HL ;Wortwert fuer Registerpaar HL
|
Der direkte Aufruf sollte bei einem Banksystem in der Regel nur für die Zeichenfunktionen verwendet werden.
Im anderen Falle werden Adressen angesprungen, die sich nicht in der eingestellten Bank befinden.
Dadurch kann es zu Abstürzen kommen.
|
Der Aufruf über das BDOS stellt sicher, dass alle Funktionen richtig verarbeitet werden.
Die BDOS Funktion 50 steht allerdings nur für CP/M ab Version 3 zur Verfügung,
|
Das BIOS beginnt mit den folgenden Sprunganweisungen zu den Dienstroutinen:
BIOS-Nr. | Offset [=3*(BIOS-Nr.-1)] | Beschreibung |
0 | - | JMP BOOT | ;Kaltstart Routine |
1 | 0000H | JMP WBOOT | ;Warmstart - Laden des Command Prozessors |
2 | 0003H | JMP CONST | ;Konsolstatus |
3 | 0006H | JMP CONIN | ;Konsoleingabe |
4 | 0009H | JMP CONOUT | ;Konsolausgabe |
5 | 000CH | JMP LIST | ;Druckerausgabe |
6 | 000FH | JMP PUNCH | ;Lochstreifenausgabe |
7 | 0012H | JMP READER | ;Lochstreifeneingabe |
8 | 0015H | JMP HOME | ;Disklesekopf auf Spur 0 |
9 | 0018H | JMP SELDSK | ;Laufwerk wählen |
10 | 001BH | JMP SETTRK | ;Spur wählen |
11 | 001EH | JMP SETSEC | ;Sektor wählen |
12 | 0021H | JMP SETDMA | ;DMA-Adresse festlegen |
13 | 0024H | JMP READ | ;Sektor lesen |
14 | 0027H | JMP WRITE | ;Sektor schreiben |
In CP/M 2 und höher sind noch die weiteren Sprunganweisungen vorhanden:
|
15 | 002AH | JMP LISTST | ;Druckerstatus |
16 | 002DH | JMP SECTRAN | ;Übersetzung des Sektorversatzes (Skewing) |
In CP/M 3 ist ein weiterer Satz von Sprunganweisungen vorhanden:
|
17 | 0030H | JMP CONOST | ;Status der Konsolausgabe |
18 | 0033H | JMP AUXIST | ;Status der Hilfsgeräteleingabe |
19 | 0036H | JMP AUXOST | ;Status der Hilfsgerätelausgabe |
20 | 0039H | JMP DEVTBL | ;Adresse der Gerätetabelle |
21 | 003CH | JMP DEVINI | ;Gerät initialisieren |
22 | 003FH | JMP DRVTBL | ;Adresse der Laufwerkstabelle |
23 | 0042H | JMP MULTIO | ;Lesen/Schreiben von Mehrfachsektoren |
24 | 0045H | JMP FLUSH | ;Leeren der Dateipuffer |
25 | 0048H | JMP MOVE | ;Verschieben eines Speicherblocks |
26 | 004BH | JMP TIME | ;Echtzeituhr |
27 | 004EH | JMP SELMEM | ;Speicherbank wählen |
28 | 0051H | JMP SETBNK | ;Bank für DMA-Operation wählen |
29 | 0054H | JMP XMOVE | ;Bänke für MOVE laden |
30 | 0057H | JMP USERF | ;Systemabhängige Funktionen |
31 | 005AH | JMP RESERV1 | ;Reserviert |
32 | 005DH | JMP RESERV2 | ;Reserviert |
|
Diese Funktion ist völlig abhängig von der Implementierung und sollte niemals von einem Benutzerprogramm aufgerufen werden.
Lädt sowohl den Command Prozessor als auch (an einigen Systemen) das BDOS in den Speicher.
Wie das durchgeführt wird, ist abhängig von der Implementierung;
es könnem reservierte Disksektoren oder Extraspeicher Verwendung finden.
Gibt den Status im Akku zurück; 0 falls kein Zeichen verfügbar ist 0FFh im anderen Fall.
Wartet, bis ein Zeichen von der Tastatur zur Verfügung steht und gibt es im Akku zurück.
Schreibt das Zeichen im Register C auf den Bildschirm.
Schreibt das Zeichen im Register C auf den Drucker.
Die Routine wartet, bis der Drucker bereit ist.
Schreibt das Zeichen im Register C auf den "Lochstreifenstanzer" - oder was immer sich hinter dem Hilfsgerät verbirgt.
Die Routine wartet, bis das Gerät bereit ist.
Liest ein Zeichen vom "Lochstreifenleser" - oder was immer sich hinter dem Hilfsgerät verbirgt.
Die Routine wartet, bis das Gerät bereit ist.
Das Zeichen wird im Akku zurückgegeben.
Wenn das Gerät nicht ausgeführt ist, wird das Zeichen 26 (^Z) zurückgegeben.
Das aktuelle Laufwerk wird auf Spur 0 gesetzt.
Wahl des Laufwerkes im Register C (0=A:, 1=B: ...).
Aufruf mit Register DE=0 oder FFFFh.
Ist der Wert FFFFh, wird nicht vom Laufwerk gelesen.
SELDSK gibt die Adresse eines Disc Parameter Headers im Register HL zurück.
Anwahl der Spur in Register BC - 0 relativ.
Anwahl des Sektors in Register BC.
Bei CP/M 1 und 2 lag die Sektorgröße bei 128 Bytes.
Bei CP/M 3 wird die Sektorgröße im Disk Parameter Block festgelegt.
In comp.os.cpm wurde diskutiert, ob der Wert des Parameter dieser Funktion ein Byte oder Wort ist.
Das Ergebnis (basierend auf der Untersuchung der BDOS Quellen) war, dass es ein Wort ist.
Die Adresse in Register BC bestimmt, woher Daten bei der nächsten Laufwerksoperation gelesen (oder wohin geschrieben) werden.
Lesen der aktuell eingestellten Spur und des Sektors in die aktuelle DMA Adresse.
Gibt Akku=0 (Erfolg), 1 (nicht behebbarer Fehler) oder 0FFh (Medium gewechselt) zurück.
Schreiben der aktuell eingestellten Spur und des Sektors.
Register C enthält den Freigabe Kode:
C=0 - Schreiben kann später erfolgen
C=1 - Schreiben muss sofort erfolgen
C=2 - Schreiben kann später erfolgen, ein Pre-read ist nicht notwendig.
Gibt Akku=0 (Erfolg), 1 (nicht behebbarer Fehler), 2 (Laufwerk ist schreibgeschützt) oder 0FFh (Medium gewechselt) zurück.
Status des aktuellen Druckers holen.
Gibt Akku=0 (nicht bereit) oder Akku=0FFh (bereit) zurück.
Sektornummern umsetzen unter Berücksichtigung des Sektorversatzes (Skewing).
Bei Aufruf hält Register BC die logische Sektornummer (Null basierend) und DE die Adresse der Umsetztabelle.
Zurückgegeben wird die physikalische Sektornummer im Register HL.
Status des aktuellen Bildschirmausgabegerätes holen.
Gibt Akku=0 (nicht bereit) oder Akku=0FFh (bereit) zurück.
Status des aktuellen Hilfseingabegerätes holen.
Gibt Akku=0 (nicht bereit) oder Akku=0FFh (bereit) zurück.
Status des aktuellen Hilfsausgabegerätes holen.
Gibt Akku=0 (nicht bereit) oder Akku=0FFh (bereit) zurück.
Gibt im Register HL die Adresse der Gerätetabelle zurück oder 0, wenn die Gerätetabelle nicht vorhanden ist.
Auf die Gerätetabelle kann von Programmen ohne Bankumschaltung zugegriffen werden, d.h. sie liegt im Common Memory.
Die Gerätetabelle enthält einen Eintrag für jedes Gerät.
Jeder Eintrag ist wie folgt aufgebaut:
DEFB 'NAME ' ;Name aus 6 Bytes. Ist das erste Byte Null,
;so kennzeichent diese das Ende der Tabelle.
DEFB Modus ;Bitweise Darstellung:
;Bit 0 gesetzt => Eingabe von diesem Gerät möglich
;Bit 1 gesetzt => Ausgabe auf dieses Gerät möglich
;Bit 2 gesetzt => Einstellung der Baudrate möglich
;Bit 3 gesetzt => unterstützt XON/XOFF
;Bit 4 gesetzt => benutzt XON/XOFF
;Bits 5,6,7 gesetzt auf 0.
; Amstrad Erweiterung: Ist Bit 7 gesetzt, erfolgt
;kein Time Out bei diesem Gerät.
DEFB Baudrate ;Kodierte Geschwindigkeit, 1-15 oder 0, wenn
;Geschwindigkeit nicht veränderbar ist.
;Die verfügbaren Raten sind:
; 50,75,110,134.5,150,300,600,1200,
; 1800,2400,3600,4800,7200,9600,19200.
Die maximale Anzahl von Geräten, die CP/M Plus zulässt, ist unklar.
Die Dokumentation sagt abwechselnd 12 oder 13, während der Quellkode von DEVICE.COM auf 15 hinweist.
Initialisiert erneut das Gerät mit der Nummer in Register C - Aufruf bei Veränderung der Geräteeinstellungen (Baudrate, Modus, usw.)
Gibt in Register HL die Adresse der Laufwerkstabelle zurück oder 0 (oder 0FFFFh oder 0FFFEh), wenn die Laufwerkstabelle nicht vorhanden ist.
Die Laufwerkstabelle besteht aus 16 Zeigern zu den Disc Parameter Headern der 16 Laufwerke A-P;
ist ein Zeiger 0, so existiert das entsprechende Laufwerk nicht.
Die Laufwerkstabelle liegt üblicherweise (aber nicht immer) im Common Memory (d.h. auf sie ist über Nutzerprogramme zugreifbar).
Dem BIOS anzeigen, dass das BDOS eine Anzahl von aufeinanderfolgender Disksektoren mit READ oder WRITE übertragen will.
Übergabe mit Register C = Anzahl von auszuführenden Aufrufen; bis zu 16kByte können übertragen werden.
Die Idee hinter dem MULTIO Aufruf ist, dass das BIOS wählen kann, ob alle Daten mit der ersten READ/WRITE Operation übertragen werden, und danach bei den folgenden (n-1) Operationen keine Aktivitäten durchzuführen.
Schreibt anhängige Daten auf das Laufwerk.
Gib Resultat im Akku zurück: A=0 bei Erfolg, 1 bei physikalischem Laufwerksfehler und 2, wenn das Laufwerk schreibgeschützt ist.
Diese Funktion ist nur sinnvoll, wenn das BIOS das „Deblocking" überninmmt - d.h. die physikalische Sektorgröße ist nicht die Größe, die das BIOS dem BDOS übermittelt.
Verschiebt BC Bytes im Speicher, die Startadresse steht im Register HL und die Endadresse im Register DE.
Als Ergebnis sollten in den Registern HL und DE die Adressen stehen, die nicht mehr kopiert wurden.
Wenn XMOVE vorher aufgerufen wurde, werden Daten zwischen zwei Bänken kopiert.
Laden des aktuellen Datums und der Uhrzeit in den SCB (nach Kaltstart -0Ch).
Register HL und DE müssen gerettet werden.
Wenn Register C=0FFh ist, dann wird die Uhrzeit stattdessen aus dem SCB gesetzt.
Das Format des 5 Byte Puffers ist definiert als:
DW Tag ;Der Tag 1 ist der 1.Januar 1978
DB Stunde ;gepacktes BCD
DB Minute ;gepacktes BCD
DB Sekunde ;gepacktes BCD
Setzt die aktuelle Bank auf die Nummer im Akku.
Bank 1 ist die Bank, in der Anwenderprogramme ablaufen (die TPA);
Bank 0 und weitere Bänke werden genutzt von CP/M als Diskettenpuffer oder als Speicherlaufwerk (RAM Disk).
Setzt die Bank für die nächste Lese-/Schreiboperation.
Die Bank wird im Akku übergeben.
Nach dem Aufruf von XMOVE kopiert der nächste Aufruf von MOVE Daten zwischen verschiedenen Bänken.
Bei Aufruf von XMOVE steht im Register C die Quellbank und und in B die Zielbank.
Diese Funktion ist reserviert für den Entwickler des BIOS, um einige Besonderheiten hinzuzufügen.
So greift der Aufruf z.B. bei Amstrad Rechnern auf die erweiterten BIOS Funktionen zu.
Diese Aufrufe sind reserviert und enthalten jeweils die Instruktion JMP 0
.
Letzte Änderung:
4.Juni 2004