Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| cpm:write_a_bios [2012/03/08 09:57] – volkerp | cpm:write_a_bios [2014/05/08 10:19] (aktuell) – volkerp | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | ====== | + | ====== |
| **howto write a bios for cp/m 2.2\\ | **howto write a bios for cp/m 2.2\\ | ||
| V. Pohlers, 2012** | V. Pohlers, 2012** | ||
| - | Zu CP/M 2.2 gibt es eine Datei cbios.asm mit, die als Ausgang für ein BIOS dienen kann. | + | Ich will versuchen, die Grundlagen zum Schreiben eines eigenen kleinen BIOS für CP/M 2.2 praxisgerecht darzustellen. Grundlagenwissen sollte man schon haben, z.B. was ein BIOS ist und welche Funktionen drin sind, wie eine Diskette aufgebaut ist u.a.m.\\ |
| - | Diesen Code habe ich hier genutzt, an Z80 angepasst | + | Detailwissen liefert [[cpm: |
| - | Das BIOS folgt unmittelbar auf CCP und BDOS. Am Anfang des BIOS steht ein | ||
| - | Sprungverteiler zu den 17 BIOS-Funktionen. | ||
| - | Die BIOS-Funktionen müssen keine Register retten. | + | |
| - | + | * [[cpm:write_a_bios:teil_2|]] Ansteuerung | |
| - | ===== Kalt- und Warmstart ===== | + | |
| - | + | ||
| - | < | + | |
| - | .Z80 | + | |
| - | ; Skeletal CBIOS for first level of CP/M 2.0 alteration | + | |
| - | ; | + | |
| - | CCP EQU xx00H ; | + | |
| - | BDOS EQU CCP+806H ; | + | |
| - | BIOS EQU CCP+1600H ; | + | |
| - | + | ||
| - | CDISK EQU 0004H ; | + | |
| - | IOBYTE EQU 0003H ; | + | |
| - | ; | + | |
| - | ORG BIOS ; | + | |
| - | + | ||
| - | ; jump vector for individual subroutines | + | |
| - | JP BOOT ; | + | |
| - | WBOOTE: | + | |
| - | JP CONST ; | + | |
| - | JP CONIN ; | + | |
| - | JP CONOUT ; | + | |
| - | JP LIST ; | + | |
| - | JP PUNCH ; | + | |
| - | JP READER ; | + | |
| - | JP HOME ; | + | |
| - | JP SELDSK ; | + | |
| - | JP SETTRK ; | + | |
| - | JP SETSEC ; | + | |
| - | JP SETDMA ; | + | |
| - | JP READ ; | + | |
| - | JP WRITE ; | + | |
| - | JP LISTST ; | + | |
| - | JP SECTRAN ; | + | |
| - | </ | + | |
| - | + | ||
| - | **BOOT** ist der Eintrittspunkt, | + | |
| - | werden sollte. Vom CP/M aus wird niemals BOOT aufgerufen. Im einfachsten Fall | + | |
| - | kann BOOT im BIOS-Bereich komplett leer bleiben, wenn die Systeminitialisierung | + | |
| - | im BOOT-Loader erfolgt. | + | |
| - | + | ||
| - | Der Kaltstart wird nur nach dem erstmaligen Laden des Betriebsystems benötigt. | + | |
| - | Der Aufruf an den Kaltstart erfolgt meist von einem speziellen Ladeprogramm, | + | |
| - | nach dem Einschalten des Rechners das BIOS von der Systemdiskette geladen hat. | + | |
| - | + | ||
| - | Aufgabe des Kaltstart ist es, die einzelnen Systemkomponenten zu initialisieren | + | |
| - | und eine Meldung über den erfolgten Systemstart auf der Console auszugeben. | + | |
| - | + | ||
| - | Normalerweise wird nach einem Kaltstart ein Warmstart ausgeführt, | + | |
| - | und das BDOS von der Diskette lädt und die Sprungbefehle einsetzt. Dann braucht | + | |
| - | nur die zuerst anzuwählende Disk- und Usernummer in die Speicheradresse | + | |
| - | 0004h eingetragen zu werden. | + | |
| - | + | ||
| - | **WBOOT** wird beim Warmstart (z.b. ^C oder JP 0000) aufgerufen. Die BDOS- | + | |
| - | Funktion 0 geht direkt zur BIOS-Funktion WBOOT weiter. | + | |
| - | + | ||
| - | WBOOT muss CCP und BDOS im Speicher restaurieren. Für ein erstes BIOS kann dies | + | |
| - | übergangen werden, solange keine Programe gestartet werden, die das CCP oder | + | |
| - | sogar CCP und BDOS überschreiben. Zum Neuladen von CCP und BDOS sind folgende Verfahren üblich: | + | |
| - | + | ||
| - | * Laden aus Systemspuren der BOOT-Diskette (meist A:) | + | |
| - | * Laden aus einer Kopie im Speicher (z.B. bei Vorhandensein von Schattenspeicher) | + | |
| - | * Erstellen einer Kopie während des BOOT-Vorgangs in eine RAM-Disk und Laden von dieser (üblicherweise auch hier aus Systemspuren) | + | |
| - | * Laden aus einer @OS-Datei von der Diskette. Dazu muss aber ein Mini-BDOS verfügbar sein, was das logische Lesen von Diskette unterstützt. Die Records dieser @OS-Datei könnten ja beliebig auf der Diskette verstreut liegen. | + | |
| - | + | ||
| - | Nach dem Neuladen von CCP und BDOS werden die Systemsprünge für JP 0000 und CALL 5 eingerichtet, | + | |
| - | das aktuelle Laufwerk wieder selektiert und die Steuerung ans CCP übergeben. | + | |
| - | + | ||
| - | < | + | |
| - | ; | + | |
| - | BOOT: | + | |
| - | XOR A ; | + | |
| - | LD (IOBYTE), | + | |
| - | LD (CDISK), | + | |
| - | JP GOCPM ; | + | |
| - | ; | + | |
| - | WBOOT: | + | |
| - | LD SP, | + | |
| - | ;... | + | |
| - | ..reread ccp+bdos into memory | + | |
| - | ;... | + | |
| - | ; | + | |
| - | ; end of load operation, set parameters and go to cp/m | + | |
| - | GOCPM: | + | |
| - | LD A, | + | |
| - | LD (0), | + | |
| - | LD HL, | + | |
| - | LD (1), | + | |
| - | ; | + | |
| - | LD (5), | + | |
| - | LD HL, | + | |
| - | LD (6), | + | |
| - | ; | + | |
| - | LD BC, | + | |
| - | CALL SETDMA | + | |
| - | ; | + | |
| - | EI ; | + | |
| - | LD A, | + | |
| - | LD C, | + | |
| - | JP CCP ; | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | ===== Zeichen-I/ | + | |
| - | + | ||
| - | Im BIOS sind die grundlegenden I/ | + | |
| - | für Konsole, Drucker, Reader, Punch enthalten. | + | |
| - | + | ||
| - | Ein einfaches BIOS braucht nur Ein- und Ausgabe für Konsole, die restl. | + | |
| - | Funktionen sind Leerfunktionen. | + | |
| - | + | ||
| - | Das **I/ | + | |
| - | lesen bzw. beschreiben direkt die Speicherzelle IOBYTE. Das Systemprogramm STAT | + | |
| - | nutzt wiederum nur diese BDOS-Funktionen. | + | |
| - | + | ||
| - | Ein I/ | + | |
| - | problemlos darauf verzichten; wenn man nicht verschiedene Geräte für die 4 I/O- | + | |
| - | Kanäle Konsole, Drucker, Reader, Punch unterstützen muss/ | + | |
| - | + | ||
| - | Die BIOS-Funktion **CONIN** darf das eingetippte Zeichen nicht auf dem Bildschirm | + | |
| - | ausgeben. | + | |
| - | + | ||
| - | Für ein minimales BIOS reicht es, die CON-Routinen zu implementieren. Drucker, Reader und Punch können Null-Routinen bleiben. | + | |
| - | + | ||
| - | < | + | |
| - | ; | + | |
| - | ; | + | |
| - | ; simple i/o handlers (must be filled in by user) | + | |
| - | ; in each case, the entry point is provided, with space reserved | + | |
| - | ; to insert your own code | + | |
| - | ; | + | |
| - | CONST: | + | |
| - | ..status subroutine | + | |
| - | LD A, | + | |
| - | RET | + | |
| - | ; | + | |
| - | CONIN: | + | |
| - | ..input routine | + | |
| - | AND 7FH ; | + | |
| - | RET | + | |
| - | ; | + | |
| - | CONOUT: | + | |
| - | LD A, | + | |
| - | ..output routine | + | |
| - | RET | + | |
| - | ; | + | |
| - | LIST: | + | |
| - | LD A, | + | |
| - | RET ; | + | |
| - | ; | + | |
| - | LISTST: | + | |
| - | XOR A ;0 is always ok to return | + | |
| - | RET | + | |
| - | ; | + | |
| - | PUNCH: | + | |
| - | LD A, | + | |
| - | RET ;null subroutine | + | |
| - | ; | + | |
| - | ; | + | |
| - | READER: | + | |
| - | LD A, | + | |
| - | AND 7FH ; | + | |
| - | RET | + | |
| - | </ | + | |
| - | + | ||
| - | ===== Diskettenfunktionen ===== | + | |
| - | + | ||
| - | Der größte Teil des BIOS besteht in Funktionen zur Diskettenarbeit. | + | |
| - | + | ||
| - | Eine Diskette besteht physikalisch aus **Spuren (Tracks)**. Diese sind in | + | |
| - | **physische Sektoren** unterteilt. Das BDOS greift immer über Track- und | + | |
| - | logische Sektornummer auf Laufwerke zu. Ein **logischer Sektor (sector, auch | + | |
| - | record)** ist immer 128 Byte lang. | + | |
| - | + | ||
| - | Eine Spur kann Werte von 0..FFFFh annehmen, ein logischer Sektor von 0..FFFFh. | + | |
| - | Üblich sind bei Disketten aber Werte von 0..80 für die Spur und 0..255 für den logischen Sektor. | + | |
| - | Viele BIOSe arbeiten deshalb auch nur mit 8-Bit-Registern für diese Werte. Damit sind immerhin | + | |
| - | 256 Tracks * 256 logische Sektoren * 128 Byte = 8 MByte adressierbar. | + | |
| - | + | ||
| - | Es ist Aufgabe des BIOS, die beiden Werte (Tracks und logischer Sektor) in | + | |
| - | + | ||
| - | * Diskettenseite | + | |
| - | * Spur | + | |
| - | * und physische Sektornummer | + | |
| - | + | ||
| - | umzusetzen. Wie das erfolgt, ist dem BIOS-Schreiber überlassen (und hängt von der Hardware ab). | + | |
| - | Beispiele folgen später. | + | |
| - | + | ||
| - | Die physischen Sektoren sind beispielsweise 1 KByte groß. Das BIOS muss einen | + | |
| - | Puffer bereitstellen, | + | |
| - | diesen in logische Sektoren aufzuteilen. Dieser Mechanismuss heiß | + | |
| - | Blocking/ | + | |
| - | deblock.asm als Vorlage. | + | |
| - | + | ||
| - | Die Routinen SETDMA, SETTRK, SETSEC speichern einfach die übergebenen Werte. | + | |
| - | Wenn die Laufwerke nur mit max 256 Spuren zu max. 256 log. Sektoren arbeiten, | + | |
| - | kann man TRACK und SECTOR als Byte belassen und nur Register C übernehmen. Das | + | |
| - | BDOS übergibt nur gültige Werte, so dass Register B in diesem Fall immer 0 ist | + | |
| - | und nicht beachtet werden muss. | + | |
| - | + | ||
| - | **HOME** selektiert Spur 0. Ein phys. Zugriff aufs Laufwerk ist nicht erforderlich. | + | |
| - | Mam spart auch CALL SETTRK und RET, wenn HOME direkt vor SETTRK steht. | + | |
| - | Diese Funktion war bei älteren Laufwerken zur exakten | + | |
| - | Positionierung des Schreib/ | + | |
| - | Da das BDOS vor jedem Diskzugriff die Spurnummer über SETTRK | + | |
| - | anwählt, ist HOME bei neueren Laufwerken überflüssig. | + | |
| - | + | ||
| - | **SETTRK** bezieht sich auf die im Registerpaar BC übergebene Spur. Diese Spurnummer | + | |
| - | errechnet sich immer aus der BDOS-internen (logischen) Spurnummer plus dem OFF- | + | |
| - | Wert im DPB. Wie auch beim SELDSK-Aufruf ist ein tatsächlicher Diskzugriff nicht | + | |
| - | garantiert. | + | |
| - | + | ||
| - | **SETSEC** bezieht sich auf den im Registerpaar | + | |
| - | BC übergebenen Sektor. Die so gesetzte Sektornummer ist immer | + | |
| - | das Ergebnis der SECTRAN-Funktion (s.u.). Auch hier ist ein | + | |
| - | tatsächlicher Diskzugriff auf diesen Sektor nicht garantiert. | + | |
| - | + | ||
| - | **SETDMA**: Alle nachfolgenden Diskzugriffe müssen die DMA-Adresse als | + | |
| - | Quell- (bei Schreibzugriffen) bzw. Zieladresse (bei Lesezugriffen) | + | |
| - | benutzen. Die DMA-Adresse zeigt immer auf einen 128-Byte großen Buffer, | + | |
| - | weshalb Diskzugriffe immer in Recordgröße erfolgen. | + | |
| - | + | ||
| - | < | + | |
| - | ; | + | |
| - | ; i/o drivers for the disk | + | |
| - | ; | + | |
| - | HOME: | + | |
| - | LD BC, | + | |
| - | ; | + | |
| - | ;RET | + | |
| - | ; | + | |
| - | SETTRK ; | + | |
| - | LD (TRACK), | + | |
| - | RET | + | |
| - | ; | + | |
| - | SETSEC ; | + | |
| - | LD (SECTOR), | + | |
| - | RET | + | |
| - | + | ||
| - | SETDMA ; | + | |
| - | LD (DMAAD), | + | |
| - | RET | + | |
| - | + | ||
| - | ; | + | |
| - | </ | + | |
| - | + | ||
| - | **SECTRAN** übernahm ursprünglich eine Sektornummertransformation bei | + | |
| - | hardsektorierten Disketten (8") anhand einer Sektorverschränkungstabelle (X- | + | |
| - | lation table XLT). Dies ist bei moderneren Laufwerken nicht mehr üblich bzw. | + | |
| - | wegen größerer physischer Sektorlänge als 128 Byte auch nicht möglich. Eine | + | |
| - | Sektorverschränkung physischer Sektoren erfolgt deshalb meist im phys. | + | |
| - | Diskettentreiber (s. unten). | + | |
| - | + | ||
| - | Im allgemeinen genügt es, einfach die im Registerpaar BC | + | |
| - | übergebene Sektornummer ins Registerpaar HL zu kopieren. | + | |
| - | + | ||
| - | im CP/A wird einfach der übergebene Wert genommen und um 1 erhöht (die Sektoren | + | |
| - | zählen in CP/A bzw. auf Diskette ab 1). Nutzt man eine allgemeine SECTRAN- | + | |
| - | Routine für alle Laufwerke, muss dies bei den phys. Laufwerkstreibern f. Read und Write beachtet werden. | + | |
| - | + | ||
| - | < | + | |
| - | SECTRAN: (allg) | + | |
| - | ;translate the sector given by BC using the | + | |
| - | ;translate table given by DE | + | |
| - | EX DE, | + | |
| - | ADD HL, | + | |
| - | LD L, | + | |
| - | LD H, | + | |
| - | RET ;with value in HL | + | |
| - | ; | + | |
| - | SECTRAN: (CP/A) | + | |
| - | ;translate the sector given by BC without translate table | + | |
| - | LD L, | + | |
| - | LD H, | + | |
| - | inc HL | + | |
| - | RET ; | + | |
| - | ; | + | |
| - | </ | + | |
| - | + | ||
| - | **SELDSK**: Das BIOS muß die im C-Register übergebene Laufwerksnummer | + | |
| - | überprüfen und, falls ein Laufwerk mit dieser Nummer existiert, | + | |
| - | in HL die Adresse des zugehörigen disk parameter header DPH zurückgeben, | + | |
| - | Im CP/M ist nicht garantiert, daß nach einem SELDSK-Aufruf | + | |
| - | auch tatsächlich auf dieses Laufwerk zugegriffen wird. | + | |
| - | Vielmehr hat der SELDSK-Aufruf nur eine ' | + | |
| - | damit sich das BDOS auf das Laufwerk einstellen kann. | + | |
| - | Das BIOS muß die Laufwerksnummer aber intern speichern, da | + | |
| - | sich nachfolgende Diskzugriffe immer auf das zuletzt selektierte | + | |
| - | Laufwerk beziehen. | + | |
| - | + | ||
| - | In einem aufwendigen BIOS kann bei SELDSK eine Analyse der Diskette erfolgen, um | + | |
| - | das konkrete **Diskettenformat automatisch zu ermitteln**. Im CP/A-BIOS gibt es eine Liste von Formaten, die hier getestet werden (z.B. 624k, 780k, 800k). Als Resultat dieser | + | |
| - | Analyse wird ein passender DPB ausgewählt (oder dynamisch zusammengestellt) | + | |
| - | und im DPH eingetragen. | + | |
| - | + | ||
| - | Die Laufwerke müssen nicht in alphabetischer Reihenfolge und durchlaufend angelegt sein. | + | |
| - | Man kann die Laufwerksbuchstaben A..P willkürlich den Laufwerken zuordnen. SELDSK muss | + | |
| - | für ein existierenes Laufwerk den passenden DPH und andernfalls 0000 zurückgeben. | + | |
| - | + | ||
| - | Für jeden Laufwerksbuchstabe, | + | |
| - | einen eigenen disk parameter header DPH geben. | + | |
| - | + | ||
| - | Ein disk parameter header DPH ist 16 Byte lang und muss im RAM stehen. BDOS | + | |
| - | beschreibt die freien Felder des DPH mit eigenen Werten. | + | |
| - | + | ||
| - | Ein DPH umfasst 8 Einträge zu je 16 Bit und hat folgende Struktur: | + | |
| - | < | + | |
| - | +-----------------------------------------------------+ | + | |
| - | | XLT | NHDE | CLTK | FSCT | DIRBUF | DPB | CSV | ALV | | + | |
| - | +-----------------------------------------------------+ | + | |
| - | Byte 0/1 | + | |
| - | </ | + | |
| - | + | ||
| - | XLT (s.o.), NHDE, CLTK, FSCT sind mit 0 vorbelegt, DIRBUF ist ein 128 Byte | + | |
| - | großer Puffer (für alle Laufwerke derselbe), DPB ist die Adresse des Disk | + | |
| - | Parameter Blocks, CSV die Adresse des Prüfsummenvektors (Check Sum Vector) und | + | |
| - | ALV die Adresse des Belegungsvektors (Allocation Vector). | + | |
| - | + | ||
| - | Der DPB enthält die Laufwerkseigenschaften und wird weiter unten beschrieben. | + | |
| - | Ein DPB kann für mehrere DPH genommen werden, wenn die Laufwerkseigenschaften | + | |
| - | gleich sind (z.B. für 2 gleiche Diskettenlaufwerke). | + | |
| - | + | ||
| - | CSV und ALV sind Speicherbereiche im RAM, | + | |
| - | deren Größe von den Laufwerkseigenschaften abhängen (s. DPB). | + | |
| - | + | ||
| - | < | + | |
| - | ; fixed data tables for four drives | + | |
| - | + | ||
| - | DPBASE: | + | |
| - | ; disk parameter header for disk 00 | + | |
| - | DPH0: | + | |
| - | DW 0000H, | + | |
| - | DW DIRBF, | + | |
| - | DW CHK00, | + | |
| - | ; disk parameter header for disk 01 | + | |
| - | DPH1: | + | |
| - | DW 0000H, | + | |
| - | DW DIRBF, | + | |
| - | DW CHK01, | + | |
| - | ; disk parameter header for disk 02 | + | |
| - | DPH2: | + | |
| - | DW 0000H, | + | |
| - | DW DIRBF, | + | |
| - | DW CHK02, | + | |
| - | ; disk parameter header for disk 03 | + | |
| - | DPH3: | + | |
| - | DW 0000H, | + | |
| - | DW DIRBF, | + | |
| - | DW CHK03, | + | |
| - | ; | + | |
| - | + | ||
| - | ; werden die Laufwerksbuchstaben durchgehend vergeben (A:..D:) und | + | |
| - | ; folgen die DPH direkt aufeinander, | + | |
| - | ; DPBASE + 16*DISKNO berechnet werden | + | |
| - | SELDSK: | + | |
| - | LD HL, | + | |
| - | LD A,C | + | |
| - | LD (DISKNO), | + | |
| - | CP 4 ; | + | |
| - | RET NC ; | + | |
| - | ; compute proper disk parameter header address | + | |
| - | LD A, | + | |
| - | LD L, | + | |
| - | LD H, | + | |
| - | ADD HL, | + | |
| - | ADD HL, | + | |
| - | ADD HL, | + | |
| - | ADD HL, | + | |
| - | LD DE, | + | |
| - | ADD HL, | + | |
| - | RET | + | |
| - | + | ||
| - | ; Alternativ: sind die Laufwerksbuchstaben nicht durchgehend vergeben, | + | |
| - | ; kann die Ermittlung auch direkt erfolgen, hier Laufwerke A:, B:, F:, P: | + | |
| - | SELDSK: | + | |
| - | LD A,C | + | |
| - | LD (DISKNO), | + | |
| - | + | ||
| - | LD HL, DPH0 | + | |
| - | CP ' | + | |
| - | RET Z | + | |
| - | LD HL, DPH1 | + | |
| - | CP ' | + | |
| - | RET Z | + | |
| - | LD HL, DPH2 | + | |
| - | CP ' | + | |
| - | RET Z | + | |
| - | LD HL, DPH3 | + | |
| - | CP ' | + | |
| - | RET Z | + | |
| - | ; | + | |
| - | LD HL, | + | |
| - | RET | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | Die **READ**-Funktion liest einen (logischen) Sektor von der Diskette in den | + | |
| - | DMA-Buffer. Die Disknummer, Spurnummer und Sektornummer sind jeweils durch die | + | |
| - | letzten SELDSK-, SETTRK- und SETSEC-Aufrufe festgelegt. | + | |
| - | + | ||
| - | Bei physikalischen Sektorlängen vom mehr als 128 Bytes muß das BIOS einen | + | |
| - | Sektorbuffer entsprechender Große selbst bereitstellen und aus diesem Buffer 128 | + | |
| - | Bytes zum zuletzt definierten DMA-Buffer kopieren. Falls ein Lesefehler | + | |
| - | auftritt, sollte das BIOS den Diskzugriff ein paar Mal wiederholen und, falls | + | |
| - | der Fehler bestehen bleibt, den Fehlercode 1 im A-Register zurückgeben. | + | |
| - | + | ||
| - | Die **WRITE**-Funktion schreibt einen (logischen) Sektor vom DMA-Buffer auf die | + | |
| - | Diskette. Die Disknummer, Spurnummer und Sektornummer sind jeweils durch die | + | |
| - | letzten SELDSK-, SETTRK- und SETSEC-Aufrufe festgelegt. | + | |
| - | + | ||
| - | Bei physikalischen Sektorlängen von mehr als 128 Bytes kann das Record-Flag zur | + | |
| - | Realisierung eines ' | + | |
| - | Schreibzugriff reicht es, den logischen Sektor nur in den BIOS-internen | + | |
| - | Sektorbuffer zu übernehmen. Dies hat den Vorteil, daß nachfolgende | + | |
| - | Schreibzugriffe auf den selben physikalischen Sektor keinen Diskettenzugriff | + | |
| - | verlangen. Erst wenn der neue logische Sektor in einem anderen physikalsichen | + | |
| - | Sektor liegt, muß der Sektorbuffer auf die Diskette geschrieben werden. | + | |
| - | Directory-Schreibzugriffe sollten immer direkt auf die Diskette geleitet werden. | + | |
| - | + | ||
| - | Je nach Laufwerkstyp (Diskette, RAM-Floppy etc.) können Read und Write völlig unterschiedlich implementiert sein. Die BIOS-Routinen READ und WRITE müssen in diesem Fall je nach Laufwerk DISKNO auf spezielle Routinen READx und WRITEx verzweigen. | + | |
| - | + | ||
| - | Man spricht von physischen Laufwerkstreibern für Read und Write, wenn diese den physischen Transfer eines (physischen) Sektors von/zum Laufwerk übernehmen. Die logischen Laufwerkstreiber übernehmen das Blocking/ | + | |
| - | + | ||
| - | Ganz einfache Routinen: | + | |
| - | < | + | |
| - | ; | + | |
| - | READ: | + | |
| - | ..read log. Sektor nach (DMAAD) | + | |
| - | ld a,0 ; keine Fehler | + | |
| - | ret | + | |
| - | ; | + | |
| - | WRITE: | + | |
| - | ..schreibe log. Sektor von (DMAAD) | + | |
| - | ld a,0 ; keine Fehler | + | |
| - | ret | + | |
| - | ; | + | |
| - | calcadr: | + | |
| - | die physikalische Position berechnen | + | |
| - | ret | + | |
| - | </ | + | |
| - | + | ||
| - | Es verbleiben die RAM-Speicherbereiche, | + | |
| - | Ende des BIOS stehen sollten, damit das BIOS in den Systemspuren nicht zu groß wird. | + | |
| - | + | ||
| - | < | + | |
| - | ; the remainder of the CBIOS is reserved uninitialized | + | |
| - | ; data area, and does not need to be a part of the | + | |
| - | ; system memory image (the space must be available, | + | |
| - | ; | + | |
| - | ; | + | |
| - | TRACK: | + | |
| - | SECTOR: | + | |
| - | DMAAD: | + | |
| - | DISKNO: | + | |
| - | ; | + | |
| - | ; scratch ram area for BDOS use | + | |
| - | DIRBF: | + | |
| - | ALL00: | + | |
| - | ALL01: | + | |
| - | ALL02: | + | |
| - | ALL03: | + | |
| - | CHK00: | + | |
| - | CHK01: | + | |
| - | CHK02: | + | |
| - | CHK03: | + | |
| - | + | ||
| - | BUFFER: | + | |
| - | ; | + | |
| - | END | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | ===== Der Disk Parameter Block ===== | + | |
| - | + | ||
| - | + | ||
| - | Ein DPB umfasst 15 Bytes in folgender Aufteilung: | + | |
| - | < | + | |
| - | +----------------------------------------------------------+ | + | |
| - | | SPT | BSH | BLM | EXM | DSM | DRM| AL0 | AL1 | CKS | OFF | | + | |
| - | +----------------------------------------------------------+ | + | |
| - | 0/1 | + | |
| - | | + | |
| - | </ | + | |
| - | + | ||
| - | Beschreibung s.a. [[:intern:systemdoku# | + | |
| - | + | ||
| - | Zur Erstellung eines DPB braucht man folgende Angaben: | + | |
| - | + | ||
| - | - Gesamtkapazität der Diskette in KByte | + | |
| - | - physischer Aufbau der Diskette | + | |
| - | - Anzahl der Spuren (Tracks) | + | |
| - | - Anzahl physischer Sektoren pro Spur | + | |
| - | - Anzahl der beschreibbaren Diskettenseiten | + | |
| - | - max. Anzahl der Direktory-Einträge | + | |
| - | - Anzahl der Systemspuren | + | |
| - | - gewünschte Blockgröße | + | |
| - | + | ||
| - | CP/M kennt keine Diskettenseiten, | + | |
| - | die Seite aus TRACK oder SECTOR ermitteln. Möglich ist z.B. bei einer Diskette | + | |
| - | mit 2 Seiten, 80 Spuren, 5 phys. Sektoren pro Spur: | + | |
| - | + | ||
| - | * gerader Track Vorderseite (0,2,4,..), ungerader Track Rückseite (1, | + | |
| - | * Track 0..79 Vorderseite, | + | |
| - | * Sektor 1..5 Vorderseite, | + | |
| - | * ... | + | |
| - | + | ||
| - | CP/A nutzt die erste Variante. | + | |
| - | + | ||
| - | Unabhängig von der physischen Sektorlänge gibt es im CP/M noch die **Blockgröße**. | + | |
| - | Das BDOS teilt jede Diskette in Blöcke (engl. Blocks) auf, um damit den | + | |
| - | Verwaltungs- und Speicheraufwand für die Belegungstabelle zu verkleinern. | + | |
| - | Die Länge eines Blocks ist 1, 2, 4, 8 oder 16 kByte. | + | |
| - | + | ||
| - | Die Disketten-Belegungstabelle wird in Blöcken geführt, somit kann das BDOS | + | |
| - | Diskettenplatz auch nur blockweise vergeben. Nachteil dieser Aufteilung ist, das | + | |
| - | ein File immer ganze Blöcke belegt, auch wenn die tatsächliche Filelänge kleiner | + | |
| - | ist. | + | |
| - | + | ||
| - | __Beispiel 1__: eine 800K Diskette mit 2 Seiten, 80 Spuren, 5 phys. Sektoren pro Spur | + | |
| - | + | ||
| - | 2 Seiten * 80 Spuren -> 160 TRACKs\\ | + | |
| - | 800 KByte / 160 -> 5 KByte / Spur \\ | + | |
| - | 5 phys. Sektoren pro Spur -> 1 KByte großer phys. Sektor\\ | + | |
| - | SPT = 5 KByte / Spur -> 5K/128 = 40 logische Sektoren (records) pro Spur | + | |
| - | + | ||
| - | Man muss sich für eine Blockgröße entscheiden. | + | |
| - | Nimmt man 2 KByte große Blöcke, gibt es insgesamt 800k/2k = 400 Blöcke. | + | |
| - | Damit braucht man 16 bit große Blocknummern. | + | |
| - | Nimmt man 4 KByte große Blöcke, gibt es insgesamt 800k/4k = 200 Blöcke. Damit | + | |
| - | braucht man nur 8 bit große Blocknummern. Aber man bekommt weniger kleine | + | |
| - | Dateien auf der Diskette unter. | + | |
| - | + | ||
| - | Allgemein sollte die Blockgröße mit der Diskettengröße wachsen. | + | |
| - | + | ||
| - | Aus Blockgröße und Blocknummeranzahl ergeben sich die Felder BSH, BLM und EXM | + | |
| - | des disk parameter blocks: | + | |
| - | + | ||
| - | **OFS** := Anzahl der Systemspuren (logische TRACKs!)\\ | + | |
| - | **SPT** := Anz.Phys.Sektoren*Größe.Phys.Sektor / 128 | + | |
| - | + | ||
| - | block size BLS in Byte (1024, 2048, .. ,16384) | + | |
| - | + | ||
| - | Gesamtkapazität := (Anzahl Spuren - Anzahl der Systemspuren) * Anz.Phys.Sektoren * Größe.Phys.Sektor | + | |
| - | + | ||
| - | **DSM** := Gesamtkapazität/ | + | |
| - | + | ||
| - | **BSH** := log2 (block size / 128)\\ | + | |
| - | **BLM** := (block size / 128) - 1\\ | + | |
| - | **EXM** := (block size / 1024) - 1 bei 8 bit-Blocknummern ( DSM/block size <= 255) bzw.\\ | + | |
| - | **EXM** := (block size / 2048) - 1 bei 16 bit-Blocknummern ( DSM/block size > 255)\\ | + | |
| - | + | ||
| - | ^ block size ^ BSH ^ BLM ^ EXM (8) ^ EXM (16) ^ | + | |
| - | ^ 1 KByte | + | |
| - | ^ 2 KByte | + | |
| - | ^ 4 KByte | + | |
| - | ^ 8 KByte | + | |
| - | ^ 16 KByte | 7 | 127 | 15 | 7 | | + | |
| - | + | ||
| - | Die Anzahl der Directory-Einträge ist frei wählbar. Es werden immer ganze Blöcke vergeben, | + | |
| - | dies gilt auch für das Directory. Maximal können 16 Blöcke genutzt werden. | + | |
| - | Ein Directory-Eintrag ist 32 Byte lang, damit sind BLS/32 Directory-Einträge pro Block möglich.\\ | + | |
| - | Die Maximal-Zahl ergibt sich zu | + | |
| - | + | ||
| - | **DRM** := Anz.Dir.Blöcke * (block size / 32) - 1 | + | |
| - | + | ||
| - | Das Verhältnis zwischen Anzahl der Directory-Einträge und Anzahl der Blöcke | + | |
| - | sollte gewahrt bleiben. Es ist wenig sinnvoll, mehr Directory-Einträge als Blöcke zu haben. | + | |
| - | DSM/ | + | |
| - | + | ||
| - | Im Beispiel ergibt sich für drei 2K-Blöcke 3 * 2048/32 = maximal mögliche 192 Einträge, | + | |
| - | das Maximum sollte man auch nutzen und DRM auf 191 setzen. | + | |
| - | + | ||
| - | ^ block size ^ Anz. Dir.Blöcke | + | |
| - | ^ ^ 1^ 2^ 3^ 4^ 5^ 6^ 7^ 8^ 9^ 10^ 11^ 12^ 13^ 14^ 15^ 16^ | + | |
| - | ^ 1 KByte| | + | |
| - | ^ 2 KByte| | + | |
| - | ^ 4 KByte| | + | |
| - | ^ 8 KByte| | + | |
| - | ^ 16 KByte| | + | |
| - | + | ||
| - | CP/M erkennt Diskettenwechsel, | + | |
| - | + | ||
| - | **CKS** := (DRM + 1) / (128 / 32) = (DRM + 1) / 4 | + | |
| - | + | ||
| - | Diese Maximalgröße muss nicht immer genommen werden; gerade bei großen Disketten | + | |
| - | oder Festplatten würde eine Prüfung zu lange dauern. Bei nicht wechselbaren | + | |
| - | Laufwerken wie Festplatten oder RAM-Disketten kann CKS auch auf 0 gesetzt werden. | + | |
| - | Damit wird nicht auf Diskettenwechsel geprüft. | + | |
| - | + | ||
| - | Im DPH (s.o.) wird für den Prüfsummenvektor Speicherplatz definiert (CHKxx). | + | |
| - | Dieser muss CKS Byte groß sein: | + | |
| - | + | ||
| - | CHK00: | + | |
| - | + | ||
| - | Der Allocation Vektor (ALV) bildet die Belegungstabelle (besser: | + | |
| - | Belegungsvektor) der Diskette. Für jeden Block der Diskette ist im ALV ein Bit | + | |
| - | vorhanden, das entsprechend auf 0 (Block frei) oder 1 (Block belegt) gesetzt | + | |
| - | wird. Die Zuordnung der Blöcke zu den Bits geschieht in absteigender | + | |
| - | Bitnummernfolge (höchstes Bit eines Bytes zuerst) und aufsteigender Bytefolge | + | |
| - | (erstes Byte des ALV zuerst). Für ALLxx muss man deshalb (DSM+1)/8 Byte bereitstellen: | + | |
| - | + | ||
| - | ALL00: | + | |
| - | + | ||
| - | Achtung: Bei automatischer Formaterkennung müssen die Speicherplätze CHKxx und | + | |
| - | ALLxx für die größtmöglichen Werte ausgelegt sein! | + | |
| - | + | ||
| - | Im disk parameter block sind die ersten beiden Byte des Allocation Vektors einzutragen. | + | |
| - | Je ein Bit ist für einen genutzten Directory-Block zu setzen: | + | |
| - | + | ||
| - | AL0,AL1 = 11..100..00b | + | |
| - | + | ||
| - | Im Beispiel gilt für 3 Directory-Blöcke | + | |
| - | + | ||
| - | AL0 = 1110000b = E0h, AL1 = 00000000b = 00h | + | |
| - | + | ||
| - | insgesamt ergibt sich für Beispiel 1 | + | |
| - | + | ||
| - | < | + | |
| - | DPB00: | + | |
| - | DB 4 ;BSF block shift factor | + | |
| - | DB 15 ; | + | |
| - | DB 0 ;EXM null mask | + | |
| - | DW 399 ; | + | |
| - | DW 191 ; | + | |
| - | DB 0E0h ; | + | |
| - | DB 00h ; | + | |
| - | DW 48 ; | + | |
| - | DW 0 ;OFS track offset | + | |
| - | + | ||
| - | CHK00: | + | |
| - | ALL00: | + | |
| - | </ | + | |
| - | + | ||
| - | die Berechnung des DPB und der Größe der Speicherbereiche kann durch ein Makro erfolgen. | + | |
| - | + | ||
| - | < | + | |
| - | MACLIB DISKDEF ;LOAD DEFINTION FOR DISKS | + | |
| - | DISKS 1 | + | |
| - | DISKDEF 0, | + | |
| - | ENDEF | + | |
| - | END | + | |
| - | </ | + | |
| - | + | ||
| - | Dieses Beispiel erzeugt genau obige Daten für Beispiel 1. | + | |
| - | + | ||
| - | Tipp: Die originale diskdef.lib funktioniert nur mit dem MAC/ | + | |