CP/M intern - kurz und kompaktb 1. CCP 1.1 Wie sieht ein Filename aus? 1.2 CCP-Kommandos 1.3 CTRL-Codes 2. Programmierung 2.1 Zero-Page 2.2 Parameter-]bergabe 2.3 Der FCB 2.4 BDOS-Funktionen 2.5 BIOS-Funktionen 3. Disk-Parameter-Tabellen 3.1 DPH 3.2 DPB 4. Genie IIs-CP/M 4.1 DPB-Anhängsel 4.2 Tastatur-Codes 4.3 Bildschirm-Codes a1. CCP Der Command Console Prozessor wird direkt unter das BDOS in die TPA geladen. Er kann mit einem laufenden Programm überschrieben werden. Allerdings muß das Programm dann mit einem Warm Boot (JP 0000) beendet werden. Ansonsten kann man den CCP wieder direkt anspringen (wenn die Adresse bekannt ist). Er erwartet das Default-Laufwerk in Register C. a1.1 Wie sieht ein Filename aus?b a) bfile = bestimmter File, z.B. TURBO.COM b) ufile = unbestimmter File, '?'=beliebiger Buchstabe, '*'=Rest beliebig, z.B. TURBO.??? oder TURBO.* a1.2 CCP-Kommandos 'ERA ufile' : löscht Files 'DIR' : Inhaltsverzeichnis akt. Laufwerk anzeigen 'DIR lw' : Inhaltsverzeichnis eines bestimmten Laufwerks anzeigen 'DIR ufile' : nur bestimmte Files anzeigen 'REN bfile=bfile' : File umbennen (1. Namen in 2. umändern) 'SAVE n bfile' : n Sektoren (n dez.) je 100h ab 100h sichern 'TYPE bfile' : File anzeigen 'USER n' : auf anderen Userbereich (für alle Laufwerke gültig) umschalten, n<16 a1.3 CTRL-Codes CTRL-C: Warm-Boot (nur am Zeilenanfang) CTRL-P: Drucker-Listing an/aus CTRL-R: Zeile nochmal anzeigen CTRL-S: List-Pause, bis irgendeine Taste CTRL-Z: Ende einer Aktion, auch: EOF = Ende eines ASCII-Files (1ah) a2. Programmierung a2.1 Zero-Page 0000: Ansprung Warm-Boot 0001/2: Zeiger auf Warm-Boot-Routine (=BIOS+3) 0003: I/O-Byte: Bits: 7/6 5/4 3/2 1/0 LIST PUNCH READER CONSOLE Zuordnung: LIST PUNCH READER CONSOLE 00 TTY: TTY: TTY: TTY: 01 CRT: PTP: PTR: CRT: 10 LPT: UP1: UR1: BAT: 11 UL1: UP2: UR2: UC1: 0004: Bits 7-4: USER-Nr.; Bits 3-0: Default-Lw. 0005: Ansprung BDOS (-Funktionen) 0006/0007: Zeiger auf BDOS (bis hierhin kann jedes Programm den Speicher benutzen, wenn es mit JP 0000 endet) 005ch-007fh: FCB für Benutzer 0080h-00ffh: Sektor-Buffer für Benutzer a2.2 Parameterübergabe ]bergabe von Parametern beim Aufruf von COM-Programmen am Beispiel von: 'turbo a:abc.pas xyz.com' 1. FCB: (005ch) ff.: 01,'ABC PAS',0,0,0,0 2. FCB: (006ch) ff.: 00,'XYZ COM',0,0,0,0 (muß gerettet werden!) Rest der Zeile: (0080h) ff.: 18,' A:ABC.PAS XYZ.COM' (vom CCP in Großbuchstaben umgewandelt, (0080h)=Länge) a2.3 Der FCB Format des FCB: DR F1 F2 .. F8 T1 T2 T3 EX S1 S2 RC D0 .. DN CR R0 R1 R2 + 00 01 01 08 09 10 11 12 13 14 15 16 31 32 33 34 35 Erklärung FCB-Bytes (bzw. -Felder): DR: Lw. für Zugriff: 00=Default-Lw. 01=Lw. A .. 16=Lw. P F1..F8: Filename in Großbuchstaben T1..T3: Extension in Großbuchstaben Bit 7 von T1 gesetzt: File kann nur gelesen werden (R/O) Bit 7 von T2 gesetzt: SYS-File (bei DIR nicht angezeigt) EX: akt. Extent-Nr., vom Benutzer auf 0 zu setzen, bei File E/A 0-31 S1: reserviert S2: reserviert, bei OPEN/SEARCH/MAKE auf 0 setzen (oder gesetzt???) RC: Record-Nr. im Extent , 0-127 D0..DN: reserviert CR: akt. Record-Nr. bei sequentiellem File, vom Benutzer auf 0 zu setzen R0..R2: Record-Nr. bei Random-File, LSB=R0, MSB=R1, Overflow=R2 a2.4 BDOS-Funktionen BDOS-Funktionen: (die Funktionsnr. ist jeweils nach C zu laden; es werden keine Register gerettet) 00: sysres System-Reset, wie Warm-Boot (Rückkehr zum CCP, Lw. auf A) 01: bconin OUT: A=Tasten-Code 02: bconout IN: E=auszugebendes Zeichen 03: breader OUT: A=gelesenes Zeichen auf READER-Eingabe warten 04: bpunch IN: E=auszugebendes Zeichen auf PUNCHER ausgeben 05: blist IN: E=auszugebendes Zeichen 06: condir IN: E=0ffh: CONSOLE-Eingabe (Tastatur) <0ffh: CONSOLE-Ausgabe (Bildschirm) OUT: (nur bei E=0ffh) A=00: keine Taste >00: Tastencode 07: getio OUT: A=I/O-Byte 08: setio IN: E=I/O-Byte 09: prstr IN: DE=Zeiger auf String, der mit '$' endet String-Ausgabe auf den Bildschirm 10: getstr IN: DE=Zeiger auf Buffer (DE)=max. einzugebende Zeichen (1-255) OUT: (buffer+1): Anzahl eingebene Zeichen (buffer+2) ff.: eingebene Zeichen 11: bconst OUT: A=0ffh: Taste gedrückt =00h: keine Taste gedrückt 12: getver OUT: H=00: CP/M =01: MP/M L=Versions-Nr. (z.B. 20h=2.0, 22h=2.2) 13: resdsk Disk zurücksetzen (bei Diskettenwechsel), DMA auf 0080h, Lauf- werk A anwählen 14: bseldsk IN: E=Lw. (00h=A) das angewählte Lw. wird Default-Lw. 15: open IN: DE=Zeiger auf FCB OUT: A=0-3: alles OK 0ffh: Fehler im Filenamen auch '?' erlaubt 16: close IN: DE=Zeiger auf FCB OUT: A=Fehlerstatus (s. 15) 17: search1 IN: DE=Zeiger auf FCB OUT: A=Fehlerstatus (s. 15) DMA mit entsprechenden DIR-Sektor geladen, File-Eintrag bei DMA + A*32 wenn DR='?' wird das Default-Lw. auf allen USER-Ebenen durchsucht 18: searchn IN: DE=Zeiger auf FCB OUT: A=Fehlerstatus (s. 15) nächsten passenden Eintrag suchen, ansonsten siehe 17 19: delete IN: DE=Zeiger auf FCB OUT: A=Fehlerstatus (0ffh: nicht gefunden) Filename darf '?' enthalten, aber DR nicht, alle passenden Files werden gelöscht 20: readseq IN: DE=Zeiger auf FCB OUT: A=00: OK >00: Fehler 128-Byte-Sektor wird gelesen, CR und evtl. EX inkrementiert 21: writseq IN: DE=Zeiger auf FCB OUT: A=Fehlerstatus (s. 20) 22: make IN: DE=Zeiger auf FCB OUT: A=0ffh: Disk ist voll =0/1/2/3: OK neuen File öffnen 23: rename IN: DE=Zeiger auf FCB 1 und 2 OUT: A=0ffh: File nicht gefunden <0ffh: OK erste 16 Bytes vom FCB: vorhandener Filename zweite 16 Bytes vom FCB: neuer Filename, DR muß 00 sein 24: getlog OUT: HL=Login-Vektor welche Laufwerke wurden bisher angesprochen? (Bit 0 von L=Lw. A) 25: getdsk OUT: A=akt. Default-Lw. (00h=Lw. A) 26: setdma IN: DE=DMA-Adresse 27: getalc OUT: HL=Zeiger auf ALLOCation-Vektor 28: wpdsk akt. Lw. schreibschützen (R/O) 29: getro OUT: HL=R/O-Vektor welche Laufwerke sind schreibgeschützt? (Bit 0 von L=Lw. A) 30: setatt IN: DE=Zeiger auf FCB OUT: A=Fehler-Status (s. 15) R/O bzw. SYS eines Files neu setzen im Inhaltsverzeichnis 31: getdpb OUT: HL=Zeiger auf DPB 32: user IN: E=0ffh: hole akt. USER-Nr. =0-15: USER neu setzen OUT: (nur bei E=0ffh): A=akt. USER-Nr. 33: readrnd IN: DE=Zeiger auf FCB OUT: A=00: OK 01: nicht geschriebene Daten gelesen 03: Extent kann nicht geschlossen werden 04: Versuch, ungeschriebenen Extent zu finden 06: hinter Ende der Diskette (R2>0) bei Fehler 3: nochmal Extent 0 lesen Record-Nr. wird nicht inkrementiert 34: writrnd IN: DE=Zeiger auf FCB OUT: Fehler-Status, s. 33 A=5: neuer Extent kann nicht geöffnet werden (Inhaltsverzeichnis voll) Record-Nr. wird nicht inkrementiert 35: getsiz IN: DE=Zeiger auf FCB OUT: R0/R1/R2: File-Größe R0/R1/R2 werden auf letzte Record-Nr.+1 gesetzt 36: setrnd IN: DE=Zeiger auf FCB OUT: R0/R1/R2 R0/R1/R2 bei einem File setzen, auf den bis jetzt sequentiell zugegriffen wurde; nun Random-Zugriff möglich 37: resdrv IN: DE=Lw.-Vektor OUT: A=00 Laufwerke zurücksetzen, wenn Bits im Vektor gesetzt 40: write0 IN: DE=Zeiger auf FCB OUT: Fehlerstatus wie bei 34 Block wird vor dem Schreiben mit Nullen gefüllt, wenn er vorher unbelegt war, ansonsten wie 34 a2.5 BIOS-Funktionen so erhält man die Startadresse: (0001/2)=Zeiger auf BIOS+3 folgende Tabelle: jeweils BIOS (Basisadresse) + Offset +00: boot Kaltstart +03: wboot Warmstart +06: const Tastatur-Status, OUT: A=0ffh: Taste grdückt +09: conin auf Tastendruck warten, OUT: A=Tastencode +12: conout auf den Bildschirm ausgeben, IN: C=Zeichen +15: list auf den Drucker ausgeben, IN: C=Zeichen +18: punch auf den PUNCHER ausgeben, IN: C=Zeichen +21: reader auf Eingabe vom READER warten, OUT: A=Zeichen (1ah=EOF) +24: home angewähltes Laufwerk auf Track 0 +27: seldsk Laufwerk anwählen, IN: C=Lw. (00h=A); OUT: HL=Adresse der Sektor-]bersetzungs-Tabelle, HL=0000: Fehler +30: settrk Track anwählen, IN: BC=Track-Nr. +33: setsec Sektor anwählen, IN: BC=Sektor-Nr. +36: setdma DMA-Adresse setzen, IN: BC=DMA-Adresse +39: read Sektor lesen, OUT: A=00: OK, A=01: Fehler +42: write Sektor schreiben, IN: C=0: normales Schreiben; C=1: DIR-Sek- tor schreiben (sofort ausgeführt); C=2: 1. Sektor eines neuen Blocks; OUT: A=00: OK, A=01: Fehler +45: listst Status des Druckers abfragen, OUT: A=0ffh: READY +48: sectrn Übersetzung der Sektor-Nr., IN: BC=Sektor-Nr., DE=Adresse der Übersetzungs-Tabelle; OUT: HL=übersetzte Sektor-Nr. a3. Disk-Parameter-Tabellen a3.1 DPH (Disk Parameter Header) Format: XLT 0000 0000 0000 DIRBUF DPB CSV ALV Bytes: + 0 2 4 6 8 10 12 14 Bedeutung: XLT: Zeiger auf Sektor-Übersetzungs-Tabelle 0000: für BDOS reserviert DIRBUF: Zeiger auf einen 128-Byte-Buffer für Directory-Zugriffe kann für alle DPHs gleich sein DPB: Zeiger auf den DPB (Disk Parameter Block) für dieses Lw. CSV: Zeiger auf einen Prüfsummenblock, mit dem festgestellt werden kann, ob die Diskette gewechselt wurde; muß für jeden DPH ein anderer sein; Länge: s. DPB ALV: Zeiger auf einen Block, in dem BDOS die Diskettenbelegung fest- hält (Allocation-Vektor); muß für jeden DPH ein anderer sein; Länge: (DSM/8)+1 (DSM: s. DPB; evtl. auch: (DSM+1)/8) a3.2 DPB (Disk Paramater Block) Format: SPT BSH BLM EXM DSM DRM AL0 AL1 CKS OFF Bytes: + 0 +2 +3 +4 +5 +7 +9 +10 +11 +13 Achtung: indirekt festgelegt: BLS (Blockgröße in Bytes): 1024 * 2 hoch x wobei x von 0 bis 4 gehen darf (BLS von 1024 bis 16384) Bedeutung: SPT: Anzahl 128-Byte-Sektoren per Track BSH: x+3 (x aus BLS, s. oben), d.h.: wenn BSH=3, ist BLS=1024 usw. BLM: 2 hoch BSH - 1, d.h. wenn BSH=3, ist BLM=7 usw. EXM: hängt von DSM ab; wenn DSM<256: EXM=2 hoch x - 1, d.h.: x=0: EXM=0 usw. wenn DSM>255: EXM=2 hoch (x-1) - 1; (x=1: EXM=0) DSM: größte Blocknummer (in BLS gemessen); (DSM+1)*BLS ergibt die totale Speicherkapazität der Diskette in Bytes, ohne die Systemtracks! also: DSM=(Tracks-OFF)*SPT*128/BLS - 1 DRM: Anzahl der Directory-Einträge - 1 (d.h.: DRM=127: 128 Dir-Einträge) AL0/AL1: Bytes AL0 AL1 Bits 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 belegt: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 es sind (DSM+1)*32/BLS Bits zu belegen, angefangen von AL0, Bit 7, über AL0, Bit 0, und AL1 Bit 7, bis AL1, Bit 0; bei BLS=1024 und DRM=128 sind AL0=0f0h und AL1=00h (4 Bits belegt) CKS: Länge des Prüfblockes CSV (s. DPH); CKS=(DRM+1)/4; nur bei Disketten, nicht bei festen Speichern (RAM-Disk oder Festplatte, dann CKS=0) OFF: Anzahl der System-Tracks; sie werden am Anfang der Diskette ignoriert a4. Genie IIs-CP/M: Besonderheiten Beim Genie IIs-CP/M handelt es sich um eine CP/M-Version, die stark an das Montezuma-CP/M für das Model IV angelehnt wurde. Allerdings wurden nicht alle Features übernommen. Hier nur die für die Programmierung wichtigen Einzelheiten. a4.1 DPB-Anhängsel DPB+15: Zeiger auf DCB für das Laufwerk (WORD) DPB+17: Hardware-Byte Der DCB enthält nur drei Byte-Einträge: Select-Bits für das Laufwerk, momentaner Track (0ffh=keiner), momentane Select-Maske (mit Seitenanwahl). Das Hardware-Byte sorgt für korrektes Lesen von Fremd-Formaten. Die Bedeutung der Bits: 7-5: noch unbelegt 4: Schreibdichte (0=einfache, 1=doppelte) 3: Doppelstep (0=nein, 1=ja, für 40er-Disks in 80er-Laufwerken) 2: Track-Zählung (0=gleiche Track-Nr. auf Vorder- und Rückseite, 1=ungerade Track-Nummern auf der Rückseite) 1/0: phys. Sektorgröße (00=128, 01=256, 10=512, 11=1024 Bytes/Sektor) a4.2 Tastatur-Codes Beim IIs übernimmt die Taste "P1" die Funktion der Control-Taste. Shift P1 stellt Groß-/Kleinschreibung um. Die anderen Funktionstasten liefern folgende Codes: Taste entspricht ohne Shift mit Shift --------------------------------------------------------- Hochpfeil CTRL-K (0bh) CTRL-Ä (ESC, 1bh) Senkr.pfeil CTRL-J (LF, 0ah) CTRL-Z (EOF, 1ah) ENTER CTRL-M (CR, 0dh) CTRL-M (CR, 0dh) EOF 7fh, DEL 5fh, "_" Linkspfeil CTRL-H (BS, 08h) CTRL-X (18h) Rechtspfeil CTRL-I (TAB, 09h) CTRL-Y (TAB, 19h) CLEAR CTRL-Q (11h) CTRL-R (12h) BREAK CTRL-C (03h) CTRL-C (03h) ß 7eh, "ß" 5eh, "^" P2 - - a4.3 Bildschirm-Codes Die Bildschirm-Steuercodes entsprechen dem ADM-3A-Terminal. Sie lauten: Name Code Funktion ------------------------------------------------- BELL 7 Ton ausgeben (nicht in IIs) BS 8 Backspace TAB 9 zur nächsten Tabulator-Pos. LF 10 in die nächste Zeile VT 11 in die vorherige Zeile CRT 12 ein Zeichen nach rechts CR 13 an den Zeilenanfang INVOFF 14 Invers aus INVON 15 Invers an EOL 21 lösche bis Zeilenende INVTOG 22 Invers umschalten EOS 25 lösche bis Bildschirmende CLS 26 lösche Bildschirm u. HOME ESC 27 ESC-Sequenz einleiten (s.u.) HOME 30 Cursor an Bildschirmanfang Mit der Escape-Sequenz kann der Cursor beliebig auf dem Bildchirm positioniert werden. Nach dem ESC-Code (27) muß ein "=" (61) zum Bildschirm geschickt werden; dieses Zeichen wird nicht ausgegeben. Dann folgen zwei Angaben: zuerst die Zeile und dann die Spalte, in die der Cursor positioniert werden soll. Dabei bedeutet jeweils ein Blank (32) den Wert 0. Also wird durch die Sequenz "27,61,35,40" der Cursor in der 4. Zeile (Zeile 3 von Null an gezählt) an der 9. Stelle (Spalte 8 von Null an gezählt) ausgegeben.