fig-FORTH Wörter für #FujiNet.
von tschak909 » Sa 3. Apr 2021, 19:34Ich arbeite an N: Bindungen für FORTH. Hier ist eine kleine Erklärung des NOPEN-Wortes:
```forth
SCR # 9
0 ( N: OPEN )
1
2 : NOPEN ( aux2 aux1 str Nx: -- )
3 DUNIT C! ( Nx: to DUNIT )
4 ->DSPEC ( string into DSPEC )
5 DSPEC DBUF ! ( point DBUF to DSPEC )
6 DAUX1 C! ( set DAUX1 to aux1 )
7 DAUX2 C! ( set DAUX2 to aux2 )
8 71 DDEVIC C! ( DDEVIC = $71 FN N: )
9 4F DCOMND C! ( DCOMND = 'O' )
10 80 DSTATS C! ( DSTATS = $80 -> FN )
11 100 DBYT ! ( DBYT = 256 bytes )
12 F DTIMLO ! ( DTIMLO = 15 secs )
13 (DO-SIOV) ;
14
15 -->
```
Zunächst ein Beispiel für die Verwendung:
```forth
0 12 " N:TCP://bbs.fozztexx.net:23/" N1: NOPEN ok
```
NOPEN nimmt vier Parameter entgegen:
* den aux2-Wert (Übersetzungsmodus)
* der aux1-Wert (Lesen/Schreiben/etc)
* der Devicespec (wird als Inline-String angegeben)
* die Unit-Nummer (das Wort N1: ist hier ein Alias für 1)
Diese Werte werden vom Stack gepoppt und sofort den entsprechenden Adressen im Speicher zugewiesen, die dem Device Control Block (DCB) an Adresse $0300 entsprechen
Für die meisten von ihnen werden die Wörter C! und ! verwendet, um ihre Werte zu setzen, und sie nehmen beide die gleichen Parameter:
```
<value> <address> C!
<value> <address> !
```
Da diese Werte vom Stack kommen, erhält das C! neben DUNIT seinen Wert vom nächsten Wert auf dem Stack.
->DSPEC ist ein Wort, das auf dem vorherigen Bildschirm definiert wurde, um den Inline-String auf dem Stack schnell in einen 256-Byte-Puffer namens DSPEC zu übertragen (der gelöscht wird, bevor er verschoben wird)
Es ist hier definiert, zusammen mit den Worten DSPEC und CL/DSPEC, um den kleinen Puffer zu verwalten:
```forth
SCR # 8
0 ( N: DEVICESPEC WORDS )
1
2 ( BUFFER TO HOLD DEVICESPEC )
3 0 VARIABLE DSPEC 254 ALLOT
4
5 ( CLEAR DEVICESPEC )
6 : CL/DSPEC DSPEC 256 0 FILL ;
7
8 ( SET DEVICESPEC )
9 : ->DSPEC
10 CL/DSPEC
11 DSPEC <-STRING ;
12
13
14
15 -->
```
(warum 254? Variable teilt automatisch 2 Bytes zu, wir brauchen nur 254 mehr für 256).
und <-STRING ist Teil eines kleinen Satzes von String-Wörtern, die die " und <-STRING-Wörter definieren, die wir benötigen, um einfach In-Line-Strings zu erstellen und in Puffer zu legen:
```forth
SCR # 7
0 ( N: STRING WORDS )
1
2 : ["]
3 R COUNT DUP 1+ R> + >R ;
4
5 : " ( start embedded string )
6 22 STATE @ IF
7 COMPILE ["] WORD HERE C@ 1+ ALLOT
8 ELSE
9 WORD HERE DUP C@ 1+ PAD SWAP CMOVE PAD COUNT
10 THEN ; IMMEDIATE
11
12 : <-STRING ( src len dest -- )
13 2DUP + >R
14 SWAP CMOVE R> 0 SWAP C! ;
15 -->
```
Ja, Bildschirm 7 sieht furchterregend aus, aber um es so einfach wie möglich zu erklären: Sie wollen keine Zeichenketten interpretieren, Sie wollen nur, dass der Interpreter sie überspringt und zum nächsten Ding springt, das er interpretieren kann, und es lange genug im Speicher behält, um es in einen Puffer zu legen. Das ist es, was die obigen Wörter tun, wobei berücksichtigt wird, dass ein Forth-Programmierer in der Lage sein will, Inline-Strings entweder in ein Wort kompiliert oder interaktiv zu verwenden. Das ist es, was die ersten beiden Wörter implementieren. Das dritte Wort ->STRING nimmt die Adresse, die durch das " Wort erzeugt wurde, sowie deren Länge und verschiebt sie in den Zielpuffer.
Mit diesen Worten haben Sie alles, was Sie brauchen, um NOPEN zu implementieren, das einen Weg brauchte, um einen devicespec-String anzugeben.
Es bleibt nur noch die Frage, was ist (DO-SIOV)?
Es ist ein in Assembler implementiertes Wort, das den SIO-Vektor (Routinen) im Atari aufruft, der die Werte nimmt, die wir zuvor auf den DCB gelegt haben, und die angeforderte I/O-Operation ausführt.
Es ist so in Forth Assembler implementiert:
```
SCR # 3
0 ( SIOV )
1
2 CODE (DO-SIOV)
3
4 XSAVE STX, ( SAVE X REGISTER )
5 SIOV JSR, ( CALL SIOV)
6 XSAVE LDX, ( RESTORE X REGISTER )
7 NEXT JMP, ( RET TO INTERPRETER )
8
9
10
11
12
13
14
15 -->
```
Da das X-Register vom fig-FORTH-Interpreter ausgiebig genutzt wird und auch SIOV das X-Register nutzt, müssen wir den Inhalt des X-Registers an einer Stelle zwischenspeichern, die fig-FORTH für diesen Zweck bereitstellt. Ansonsten rufen wir einfach SIOV auf, stellen das X-Register wieder her und springen zurück in den Interpreter. Das CODE-Wort ist ein spezielles Wort in Forth, das anzeigt, dass das folgende Wort für Assembler-Code ist, der mit dem Forth-Assembler eingegeben werden soll. Anweisungen werden in Stack-Reihenfolge eingegeben, mit dem Operanden an erster Stelle, gefolgt von 'Ablage'-Wörtern, die mit einem Komma enden und anzeigen, dass die Anweisung am nächsten verfügbaren Byte im Speicher abgelegt werden soll.
Seltsam? Ja.
Warum mache ich das? Um zu zeigen, daß das FujiNet überall auf dem Atari eingesetzt werden kann, auch auf Systemen, die kein formales Dateisystem haben, wie z.B. fig-Forth.
-Thom
```forth
SCR # 9
0 ( N: OPEN )
1
2 : NOPEN ( aux2 aux1 str Nx: -- )
3 DUNIT C! ( Nx: to DUNIT )
4 ->DSPEC ( string into DSPEC )
5 DSPEC DBUF ! ( point DBUF to DSPEC )
6 DAUX1 C! ( set DAUX1 to aux1 )
7 DAUX2 C! ( set DAUX2 to aux2 )
8 71 DDEVIC C! ( DDEVIC = $71 FN N: )
9 4F DCOMND C! ( DCOMND = 'O' )
10 80 DSTATS C! ( DSTATS = $80 -> FN )
11 100 DBYT ! ( DBYT = 256 bytes )
12 F DTIMLO ! ( DTIMLO = 15 secs )
13 (DO-SIOV) ;
14
15 -->
```
Zunächst ein Beispiel für die Verwendung:
```forth
0 12 " N:TCP://bbs.fozztexx.net:23/" N1: NOPEN ok
```
NOPEN nimmt vier Parameter entgegen:
* den aux2-Wert (Übersetzungsmodus)
* der aux1-Wert (Lesen/Schreiben/etc)
* der Devicespec (wird als Inline-String angegeben)
* die Unit-Nummer (das Wort N1: ist hier ein Alias für 1)
Diese Werte werden vom Stack gepoppt und sofort den entsprechenden Adressen im Speicher zugewiesen, die dem Device Control Block (DCB) an Adresse $0300 entsprechen
Für die meisten von ihnen werden die Wörter C! und ! verwendet, um ihre Werte zu setzen, und sie nehmen beide die gleichen Parameter:
```
<value> <address> C!
<value> <address> !
```
Da diese Werte vom Stack kommen, erhält das C! neben DUNIT seinen Wert vom nächsten Wert auf dem Stack.
->DSPEC ist ein Wort, das auf dem vorherigen Bildschirm definiert wurde, um den Inline-String auf dem Stack schnell in einen 256-Byte-Puffer namens DSPEC zu übertragen (der gelöscht wird, bevor er verschoben wird)
Es ist hier definiert, zusammen mit den Worten DSPEC und CL/DSPEC, um den kleinen Puffer zu verwalten:
```forth
SCR # 8
0 ( N: DEVICESPEC WORDS )
1
2 ( BUFFER TO HOLD DEVICESPEC )
3 0 VARIABLE DSPEC 254 ALLOT
4
5 ( CLEAR DEVICESPEC )
6 : CL/DSPEC DSPEC 256 0 FILL ;
7
8 ( SET DEVICESPEC )
9 : ->DSPEC
10 CL/DSPEC
11 DSPEC <-STRING ;
12
13
14
15 -->
```
(warum 254? Variable teilt automatisch 2 Bytes zu, wir brauchen nur 254 mehr für 256).
und <-STRING ist Teil eines kleinen Satzes von String-Wörtern, die die " und <-STRING-Wörter definieren, die wir benötigen, um einfach In-Line-Strings zu erstellen und in Puffer zu legen:
```forth
SCR # 7
0 ( N: STRING WORDS )
1
2 : ["]
3 R COUNT DUP 1+ R> + >R ;
4
5 : " ( start embedded string )
6 22 STATE @ IF
7 COMPILE ["] WORD HERE C@ 1+ ALLOT
8 ELSE
9 WORD HERE DUP C@ 1+ PAD SWAP CMOVE PAD COUNT
10 THEN ; IMMEDIATE
11
12 : <-STRING ( src len dest -- )
13 2DUP + >R
14 SWAP CMOVE R> 0 SWAP C! ;
15 -->
```
Ja, Bildschirm 7 sieht furchterregend aus, aber um es so einfach wie möglich zu erklären: Sie wollen keine Zeichenketten interpretieren, Sie wollen nur, dass der Interpreter sie überspringt und zum nächsten Ding springt, das er interpretieren kann, und es lange genug im Speicher behält, um es in einen Puffer zu legen. Das ist es, was die obigen Wörter tun, wobei berücksichtigt wird, dass ein Forth-Programmierer in der Lage sein will, Inline-Strings entweder in ein Wort kompiliert oder interaktiv zu verwenden. Das ist es, was die ersten beiden Wörter implementieren. Das dritte Wort ->STRING nimmt die Adresse, die durch das " Wort erzeugt wurde, sowie deren Länge und verschiebt sie in den Zielpuffer.
Mit diesen Worten haben Sie alles, was Sie brauchen, um NOPEN zu implementieren, das einen Weg brauchte, um einen devicespec-String anzugeben.
Es bleibt nur noch die Frage, was ist (DO-SIOV)?
Es ist ein in Assembler implementiertes Wort, das den SIO-Vektor (Routinen) im Atari aufruft, der die Werte nimmt, die wir zuvor auf den DCB gelegt haben, und die angeforderte I/O-Operation ausführt.
Es ist so in Forth Assembler implementiert:
```
SCR # 3
0 ( SIOV )
1
2 CODE (DO-SIOV)
3
4 XSAVE STX, ( SAVE X REGISTER )
5 SIOV JSR, ( CALL SIOV)
6 XSAVE LDX, ( RESTORE X REGISTER )
7 NEXT JMP, ( RET TO INTERPRETER )
8
9
10
11
12
13
14
15 -->
```
Da das X-Register vom fig-FORTH-Interpreter ausgiebig genutzt wird und auch SIOV das X-Register nutzt, müssen wir den Inhalt des X-Registers an einer Stelle zwischenspeichern, die fig-FORTH für diesen Zweck bereitstellt. Ansonsten rufen wir einfach SIOV auf, stellen das X-Register wieder her und springen zurück in den Interpreter. Das CODE-Wort ist ein spezielles Wort in Forth, das anzeigt, dass das folgende Wort für Assembler-Code ist, der mit dem Forth-Assembler eingegeben werden soll. Anweisungen werden in Stack-Reihenfolge eingegeben, mit dem Operanden an erster Stelle, gefolgt von 'Ablage'-Wörtern, die mit einem Komma enden und anzeigen, dass die Anweisung am nächsten verfügbaren Byte im Speicher abgelegt werden soll.
Seltsam? Ja.
Warum mache ich das? Um zu zeigen, daß das FujiNet überall auf dem Atari eingesetzt werden kann, auch auf Systemen, die kein formales Dateisystem haben, wie z.B. fig-Forth.
-Thom