#+Title: CP/M 2.2 - spezifische Worte

 * =#bs            ( -- n )= "number-backspace" - =n= ist der Ascii-Wert für Backspace.
 * =#cr            ( -- n )= "number-c-r" - =n= ist der Ascii-Wert für Carriage-Return.
 * =#esc           ( -- n )= "number-escape" - =n= ist der Ascii-Wert für Escape.
 * =#lf            ( -- n )= "number-linefeed" - =n= ist der Ascii-Wert für Linefeed.
 * =(at ( row col -- )= "paren-at" - Positioniert den Cursor in die
   Zeile =row=, Spalte =col= und setzt =OUT=. Benutzt dabei =LOCATE=.
   Siehe auch =AT=.
 * =(at? ( -- row col )= "paren-at-question" - =row= ist die aktuelle
   Zeilennummer, =col= die aktuelle Spaltennummer. Vergleiche =AT?=
 * =(blk/drv ( drv -- blocks )= "paren-blocks-per-drive" - =blocks=
   gibt an wieviele Forth-Blöcke (1kB) auf dem Laufwerk =drv= sind.
   Ist =blocks=0=, dann existiert dieses Laufwerk nicht. Siehe
   =BLK/DRV=.
 * =(cr ( -- )= "paren-c-r" - Setzt den Cursor in die erste Spalte der
   nächsten Zeile. =PAUSE= wird ausgeführt.
 * =(decode ( addr pos1 key --- addr pos2 )= "paren-decode" - Wertet
   =key= aus. =key= wird in der Speicherzelle =addr+pos1= abgelegt und
   als Echo auf dem Bildschirm ausgegeben. Die Variable =SPAN= und
   =pos1= werden inkrementiert. Folgende Tasten werden besonders
   behandelt:
    - =Control-S= und =Control-D= beeinflussen nur =pos1= und den
      Cursor.
    - =Ctrl-G= löscht das Zeichen unter dem Cursor und dekrementiert
      =SPAN=.
    - Backspace (=Control-H=) und Delete (=$7F=) löschen das Zeichen
      links vom Cursor und dekrementieren =pos1= und =SPAN=.
    - =Control T= fügt an der Cursorposition ein Leerzeichen ein.
      =SPAN= wird inkrementiert.
    - =Return= positioniert den Cursor auf das letzte Zeichen.
   Vergleiche =INPUT:= und =(EXPECT=.
 * =(del ( -- )= "paren-del" - Löscht ein Zeichen links vom Cursor.
   Benutzt dabei =CURLEFT=. Vergleiche auch =DEL=.
 * =(emit ( 8b -- )= "paren-emit" - Gib =8b= auf dem Bildschirm aus.
   Ein =PAUSE= wird ausgeführt. Alle Werte werden als Zeichen
   ausgegeben. Steuercodes sind nicht möglich, d.h. alle Werte < $20
   werden als Punkt "." ausgegeben. Vergleiche =CON!= und =EMIT=.
 * =(expect ( addr len -- )= "paren-expect" - Erwartet =len= Zeichen
   vom Eingabegerät, die ab =addr= im Speicher abgelegt werden. Ein
   Echo der Zeichen wird ausgegeben. =Return= beendet die Eingabe
   vorzeitig. Ein abschließendes Leerzeichen wird immer ausgegeben.
   Die Länge der Zeichenkette wird in der Variablen =SPAN= übergeben.
   Vergleiche =EXPECT=.
 * =(key ( -- char )= "paren-key" - Wartet auf einen Tastendruck.
   Während der Wartezeit wird =PAUSE= ausgeführt. Die untersten 7 Bit
   von =char= enthalten den Ascii-Code der gedrückten Taste.
   Steuerzeichen werden nicht ausgewertet, sondern unverändert
   abgeliefert. Vergleiche =KEY=.
 * =(key? ( -- flag )= "paren-key-question" - =flag= ist =TRUE=, wenn
   eine Taste gedrückt wurde, sonst false. Vergleiche auch =KEY?=.
 * =(page ( -- )= "paren-page" - Löscht den Bildschirm, positioniert
   den Cursor in die linke obere Ecke und setzt =OUT= auf null. Siehe
   auch =LOCATE= und =PAGE=.
 * =(r/w ( adr blk file r/wf -- flag )= "paren-r-w" - Ist =r/wf= !=
   FALSE, wird der Forth-Block mit der absoluten Blocknummer =blk= von
   der Diskette gelesen. Ist =r/wf= = FALSE so wird er geschrieben.
   =adr= gibt die Addresse des Block-Puffers an. =file= muß null sein,
   da =(r/w= den Zugriff auf Files nicht unterstützt. =flag= ist
   =TRUE= wenn ein Diskettenfehler vorlag.
 * =(type ( addr len -- )= "paren-type" - Gibt den String, der im
   Speicher bei =addr= beginnt und die Länge =len= hat, auf dem
   Blidschirm aus. Genau ein =PAUSE= wird nach der Ausgabe ausgeführt.
   Vergleiche =TYPE=, =OUTPUT:= und =(EMIT=.
 * =/drive ( blk -- blk' drv )= "per-drive" - =blk= gibt die absolute
   Nummer eines Forth-Blocks an. =/DRIVE= berechnet, auf welchem
   Laufwerk (=drv=) dieser Block zu finden ist, und welche relative
   Blocknummer (=blk'=) er zum Anfang dieses Laufwerks hat. Siehe
   =DRV?=, =>DRIVE=.
 * =>drive ( blk drv -- block' )= "to-drive" - =blk= gibt die relative
   Blocknummer eine Forth-Blocks bezüglich des Anfangs von Laufwerk
   =drv= an. =>DRIVE= berechnet daraus, unter welcher Blocknummer
   dieser Block beim momentanen Stand von =OFFSET= erreicht werden
   kann (=block'=). In gewisser Weise Umkehrung von =/DRIVE=.
 * =?drive-error ( f -- )= "question-drive-error" - Ist =f= = FALSE,
   so wird "beyond capacity" als Fehlermeldung ausgegeben.
 * =?drive ( n -- n )= "question-drive" - Überprüft, ob das Laufwerk
   =n= existiert, und gibt "beyond capacity" als Fehlermeldung aus,
   wenn dies nicht der Fall ist.
 * =b/blk ( -- b/blk )= "bytes-per-block" - Eine Konstante die angibt,
   wieviele Bytes in einen Forth-Block passen. Nach dem Forth-83
   Standard ist =B/BLK= = &1024.
 * =bios ( -- addr )= "bios" - Adresse eines 8080-Unterprogramms, das
   einen Sprung ins BIOS ausführt. Das Low-Byte der Einsprungadresse
   steht dabei in =HL=. Wird von =con!=, =(key?=, =getkey= und
   =read/write= benutzt.
 * =blk/drv ( -- #blk )= "blocks-per-drive" - =#blk= gibt die
   Kapazität des aktuellen Laufwerks (bestimmt durch =OFFSET=) in
   Forth-Blöcken (1kB) an. Siehe =(BLK/DRV=.
 * =con! ( 8b -- )= "con-store" - Gibt =8b= auf die CONsole
   (Bildschirm) aus. Ascii-Werte < $20 werden als Steuercodes
   interpretiert.
 * =curleft ( -- )= "cur-left" - Bewegt den Cursor ein Zeichen nach
   links. Eine der vordefinierten Terminalfunktionen.
 * =curoff ( -- )= "cur-off" - Schaltet den Cursor aus. Eine der
   vordefinierten Terminalfunktionen.
 * =curon ( -- )= "cur-on" - Schaltet den Cursor an. Eine der
   vordefinierten Terminalfunktionen.
 * =currite ( -- )= "cur-right" - Bewegt den Cursor ein Zeichen nach
   rechts. Eine der vordefinierten Terminalfunktionen.
 * =dark ( -- )= - "dark" - Löscht den Bildschirm. Eine der
   vordefinierten Terminalfunktionen.
 * =display ( -- )= "display" - Ein mit =OUTPUT:= definiertes Wort,
   das den Bildschirm als Ausgabegerät anwählt, wenn es ausgeführt
   wird. Die Worte =EMIT=, =CR=, =TYPE=, =DEL=, =PAGE=, =AT=, und
   =AT?= beziehen sich dann auf das aktuelle Terminal. Siehe
   TERMINAL:.
 * =dma! ( addr -- )= "d-m-a-store" - =addr= ist die Adresse des
   Diskettenpuffers, der beim nächsten Diskettenzugriff verwendet
   werden soll.
 * =drive ( n -- )= "drive" - Wählt =n= als aktuelles Laufwerk an.
   Ändert =OFFSET= entsprechend. Siehe =BLK/DRV=.
 * =drv! ( drv f -- dph )= "drive-store" - =drv= ist die Nummer des
   Diskettenlaufwerks, das als nächstes verwendet werden soll. f=0
   gibt an, ob es sich um den erste Zugriff nach einem CP/M Warmstart
   handelt. =dph= ist die Adresse des CP/M Disk-Parameter-Headders.
   (Siehe CP/M Operating System Manual) Ist =dph= = 0, so ist das
   angesprochene Laufwerk in diesem Computersystem nicht unterstützt.
 * =drv? ( blk -- drv )= "drive-question" - =blk= gibt die absolute
   Nummer eines FORTH-Blocks an, =DRV?= berechnet daraus das Laufwerk
   (=drv=) auf dem er zu finden ist. Siehe =/DRIVE=, =>DRIVE=.
 * =drv0 ( -- )= "drive-zero" - Wählt Laufwerk 0 (A) als aktuelles
   Laufwerk für =R/W= an. Siehe =DRIVE= und =>DRIVE=.
 * =drv1 ( -- )= "drive-one" - Wählt Laufwerk 1 (B) als aktuelles
   Laufwerk für =R/W= an. Siehe =DRIVE= und =>DRIVE=.
 * =drvinit ( -- )= "drive-init" - Initialisiert das
   volksFORTH-Disk-System. Die im Komputer-System vorhandenen
   Laufwerke werden der Reihe nach selektiert und deren Kapazität
   berechnet. Dann wird das CP/M Default-Laufwerk selektiert.
 * =dumb ( -- )= "dumb" - Ein mit =TERMINAL:= definiertes Wort, das
   ein ignorantes Terminal anwählt, wenn es ausgeführt wird. =CURON=,
   =CUROFF=, =CURLEFT=, =CURRITE=, =RVSON=, =RVSOFF=, =DARK= und
   =LOCATE= haben dann keine Wirkung. Mit ihnen auch die sie
   benutzenden Worte =(PAGE=, =(AT=, =(DEL=. Wenn =DISPLAY=
   eingeschaltet ist, sind also auch =PAGE=, =AT= und =DEL=
   wirkungslos. DUMB ist als aktuelles Terminal angewählt, bis die
   Installierung eines leistungsfähigeren Terminals abgeschlossen ist.
 * =getkey ( -- char )= "getkey" - die unteren 7 Bit von =char=
   enthalten den ASCII-Code des letzten Tastendrucks. Ist noch keine
   Taste gedrückt, dann wartet =getkey=. Siehe auch =KEY?= und =KEY=.
 * =home ( -- )= "home" - Der Kopf des momentan selektierte
   Diskettenlaufwerks wird auf Spur null gefahren. Spur null wird als
   nächste Spur angewählt, die verwendet werden soll. Siehe =TRK!=,
   =DRV!=.
 * =index ( from to -- )= "index" - Liest die Blocks from bis to
   einschlielich und gibt deren erste Zeilen aus. Index kann mit einer
   beliebigen Taste angehalten werden und mit =RETURN= abgebrochen
   werden. (Siehe =STOP?=) Die ersten Zeilen von Screens enthalten
   typischer Weise Kommentare, die den Inhalt chararkterisieren.
 * =keyboard ( -- )= "keyboard" - Ein mit INPUT: definiertes Wort, das
   die Tastatur als Eingabegerät anwählt. Die Worte =KEY=, =KEY?=, =DECODE=
   und =EXPECT= beziehen sich nun auf die Tastatur. Siehe =(KEY=, =(KEY?=
   =(DECODE=, =(EXPECT=.
 * =locate ( row col -- )= "locate" - Bewegt den Cursor absolut auf
   Spalte col, Zeile row. Eine der vordefinierten Terminalfunktionen.
 * =out ( -- addr )= "out" - Adresse einer Variablen, die die Anzahl
   der ausgegebenen Zeichen enthält.
 * =read/write ( r/wf sponti -- f )= "read-write" - Bewirkt das
   physikalische Lesen (r/wf = FALSE) und Schreiben (r/wf=TRUE) eines
   Sektors (=128 Bytes) von der/auf die Diskette. Das Laufwerk, die
   Spur, der Sektor sowie der Sektor-Puffer sind vorher mit =DRV!=,
   =TRK!=, =SEC!= und =DMA!= gewählt worden. =sponti= gibt an, ob beim
   Schreiben unmittelbar auf die Diskette geschrieben werden soll
   (sponti=TRUE) oder, ob der geschriebene Sektor im BIOS
   zwischengepuffert werden darf (sponti=FALSE).
 * =rvsoff ( -- )= "reverse-off" - Schaltet die Inversdarstellung aus.
   Eine der vordefinierten Terminalfunktionen.
 * =rvson ( -- )= "reverse-on" - Schaltet die Inversedarstellung ein.
   Eine der vordefinierten Terminalfunktionen.
 * =sec! ( sec -- )= "sec-store" - sec ist der beim nächsten
   Diskettenzugriff zu verwendende Sektor.
 * =Term: ( offset -- offset' )= "term-colon" - Ein definierendes Wort
   für Terminalfunktionen. Wird benutzt um die einzelnen Komponenten
   eines Terminal-Vektors zu definieren. Vordefinierte
   Terminalfunktionen sind =CURON=, =CUROFF=, =CURLEFT=, =CURRITE=, =RVSON=,
   =RVSOFF=, =DARK= und =LOCATE=. Siehe auch =TERMINAL:=
 * =Terminal: ( -- )= "terminal-colon" - Ein definierendes Wort für
   Terminals. Benutzt in der Form:
   #+begin_example
             Terminal: <name>
               newCURON newCUROFF newCURLEFT newCURRITE
               newRVSON newRVSOFF newDARK    newLOACTE ;
   #+end_example
   =TERMINAL:= erzeugt einen Kopf für <name> im Dictionary und
   kompiliert einen Vektor von Zeigern auf Worte die für die
   Ausführung von Terminalfunktionen zuständig sind. Wird <name>
   ausgeführt, so werden die Terminalfunktionen von <name> zu den
   aktuellen Terminal funktionen gemacht, das Terminal <name> ist
   damit aktiv. Terminal funktionen werden von =AT=, =PAGE=, =DEL=
   ausgeführt, wenn die Ausgabe auf =DISPLAY= geschaltet ist. Siehe
   =OUTPUT:=, =DISPLAY=, =DUMB=.
 * =trk! ( trk -- )= "track-store" - =trk= ist die beim nächsten
   Diskettenzugriff zu verwendende Spur.
