石原 博の覚書

電子工作に関する日々の覚書を記載します

FOCAL

2021-07-04 10:04:59 | 日記

CP/Mが動くハードが何種類も出来たが、それだけでは面白くない。有り難いことに、インターネット上に様々なソフトがある。そこでいくつかダウンロードして動かしてみた。
CPMUG16のFOCAL.ASM

CP/M付属のASMでアセンブルするとエラー

$ ASM FOCAL
CP/M ASSEMBLER - VER 2.0
U018F 220000 SHLD O8`ad 0`a`<03< V114E 3EFF MVI A,-1<br />V12CD 2E30 MULX: MVI L,MULP1
V12D0 2E2C MVI L,MULP2
V12D3 2E28 MVI L,MULP3
V1321 2E40 MVI L,OP1S
V1324 2E4E MVI L,OP1A
V1329 2E3C MVI L,OP2S
V132C 2E4A MVI L,OP2A
V1331 2E38 MVI L,OP3S
V1334 2E46 MVI L,OP3A
V133B 2E35 MVI L,OP4S
V133E 2E43 MVI L,OP4A
V1341 2E51 MVI L,OP4X
V1487 3EFF MVI A,-1
V150D 3EFF MVI A,-1
V1515 36FF MVI M,-1
V1534 0EFF OUT10: MVI C,-1
1A32
016H USE FACTOR
END OF ASSEMBLY


-1を8ビットレジスタに入れるのは問題ないし、少しでもサイズを小さくするため、下位8ビットしか使用していないところは、このソースでは問題ない。問題は1行目で明らかに文字化け。

Webを検索すると、https://www.sol20.org/programs/FOCAL.ASM にほとんど同じソースがあり、

SHLD PC
RET

となっていた。今回はこれに変更しアセンブル。


使用感
キーワードは違うものの、下表のとおりほとんどBASIC。
ダイレクトステートメントも使えるし。

FOCAL FOCAL短縮形 BASIC コメント
WRITE ALL W A LIST WRITE行番号で該当行、該当ブループだけ印刷可
ERASE ALL E A NEW ERASE 行番号 で該当行、該当グループだけ消去可
GO 番号 G 番号 RUN 番号は開始行. 番号は省略不可
SET S LET  
TYPE T PRINT  
ASK A INPUT  
DO D GOSUB  
FOR F FOR  
COMMENT C REM  
QUIT Q STOP  


大きく違うのは行番号で、グループ番号(2桁).ステップ番号(2桁)となる。
ステップ番号00はソーステキストとしては使えない(グループを示す)

例1.
ERASE ALL
1.10 SET A="0
1.20" TYPE A,!
1.30 SET A="A+1
1.40" IF (A-10) 1.20
1.50 QUIT
*WRITE ALL
01.10 SET A="0
01.20" TYPE A,!
01.30 SET A="A+1
01.40" IF (A-10) 1.20
01.50 QUIT
*GO 1.10
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
*

IFは昔のFORTRANの算術IF分と同じで、IF (式) 文番号1,文番号2,文番号3 となる。文番号2, 文番号3は省略可で、省略時は次行へ 


例2.
ERASE ALL
1.10 FOR A="0,2,10;" TYPE A,!
1.20 QUIT
*G 1.10
0.000000
2.000000
4.000000
6.000000
8.000000
10.00000
*
ERASE ALL
1.10 FOR A="0,-2,-10;" TYPE A,!
1.20 QUIT
*G 1.10
0.000000
-2.000000
-4.000000
-6.000000
-8.000000
-10.00000
*
ERASE ALL
1.10 FOR A="0,2,10;" TYPE A; TYPE -A,!
1.20 QUIT
*G 1.10
0.000000 0.000000
2.000000 -2.000000
4.000000 -4.000000
6.000000 -6.000000
8.000000 -8.000000
10.00000 -10.00000
*

FORもBASICの FOR文と似ているがNEXTはない。同一行の後ろの部分を実行する。
大量の処理が必要な場合は、この部分にDO(BASICでいうGOSUB)を使えば良い。


ERASE ALL
1.10 DO 2.10
1.20 DO 2.20
1.30 TYPE '---',!
1.40 DO 2.00
1.50 QUIT
2.10 TYPE 'LINE 2.10',!
2.20 TYPE 'LINE 2.20',!
2.30 TYPE 'LINE 2.30',!
3.10 TYPE 'LINE 3.10',!
*W ALL
01.10 DO 2.10
01.20 DO 2.20
01.30 TYPE '---',!
01.40 DO 2.00
01.50 QUIT

02.10 TYPE 'LINE 2.10',!
02.20 TYPE 'LINE 2.20',!
02.30 TYPE 'LINE 2.30',!

03.10 TYPE 'LINE 3.10',!
*G 1.10
LINE 2.10
LINE 2.20
---
LINE 2.10
LINE 2.20
LINE 2.30
*

DOはBASICのGOSUB類似ではあるが、RETURNは必ずしも使う必要はない。
DO 行番号で、行番号の文を単独で実行しRETURN。
ただし行番号がグループ(上の例でDO 2.00)なら、2.xx のグループを実行しRETURN。
(RETURN文はあり、それでRETURNすることも出来る)

FOCALではグループは重要なので、WRITE ALLでの印字でもグループ毎に分かれているし、
WRITE 2.00とすると、2.xxのグループを印字する。(ERASE 2.00で、2.xxのグループを消すことも出来る)


関数
FABS, FSGN, FINT, FRAN, FSQT は問題ないが、その他(FRTN, FEXP, FLOG, FSIN, FCOS, FHYS)
にはバグがある。(FUSRはこのPGでは定義されていない。そのままの値を返す)
例えば

*T FSQT(2)
1.414213 正しい
*T FSIN(0.1)
1.787028E+20 何だ?
*T FCOS(0.1)
5.755383E+22 何だ?
*T FEXP(1)
1.073019E+31 何だ?
*T FLOG(1)
2.674012E+16 何だ?

調べてみると、こんなのが大量にある。(006BHはゼロページで、CP/Mのワーク。ここに書き込むのはおかしい)

0C8F 216B00  LXI H,FMACS  ;POINT TO SIGMA
0C92 77   MOV M,A    ;ZERO STORED

もともとFMACS等はこんな定義。上位8ビットは、SCRBであるべき
(MVI L, FMACSなどと、少しでもサイズを小さくする工夫をしているのだが、それが過ぎたか?)
0027 = SCR EQU SBANK AND 0FFH
0001 = SCRB EQU SBANK SHR 8
0067 = FSQRN EQU SCR+40H
006B = FSQRX EQU SCR+44H
0067 = IDVT EQU SCR+40H
0067 = FMACX EQU SCR+40H
006B = FMACS EQU SCR+44H
006F = FMACT EQU SCR+48H


修正してアセンブル。
diff --git a/FOCAL.ASM b/FOCAL.ASM
index a7b0b68..1c79eb1 100644
--- a/FOCAL.ASM
+++ b/FOCAL.ASM
@@ -876,7 +876,7 @@ START: LXI H,CFRSX ;GET PC => 0
LXI H,RECOVER
SHLD 1
SUB A
- STA OVER+SCRB ;CLEAR OVERFLOW
+ STA OVER+(SCRB SHL 8) ;CLEAR OVERFLOW^M
STA LIST3+1 ;RESET MODIFY
STA DEBGSW
MVI A,1
@@ -1415,7 +1415,7 @@ GV2B: CALL TESTC
GV2A: CALL TSTLPR
JMP NOSUB
CALL ECALL
- LXI H,ACCE+SCRB
+ LXI H,ACCE+(SCRB SHL 8)^M
CALL PUSHF
LHLD PT1
CALL LOD
@@ -1425,7 +1425,7 @@ GV2A: CALL TSTLPR
MOV D,C ;LEAST SIGNIFICANT PORTION
XCHG
SHLD TEMP
- LXI H,ACCE+SCRB
+ LXI H,ACCE+(SCRB SHL 8)^M
CALL POPF
LHLD TEMP
PUSH H
@@ -1496,7 +1496,7 @@ HC: LDA LASTV+1 ;CHECK 2ND HALF OF VARS
POP H
RET ;RETURN POINTER TO VALUE
;
-ECALL: LXI H,ACCE+SCRB ;
+ECALL: LXI H,ACCE+(SCRB SHL 8) ;^M
CALL PUSHF
LDA LASTOP
PUSH PSW
@@ -1512,7 +1512,7 @@ ECALL: LXI H,ACCE+SCRB ;
LXI H,FLAC
SHLD PT1
CALL STR
- LXI H,ACCE+SCRB
+ LXI H,ACCE+(SCRB SHL 8)^M
CALL POPF
RET
CALL GETC
@@ -1577,7 +1577,7 @@ NUMD: POP H
LXI H,FLARG
CALL LOD
JMP EDO
-EFUN: LXI H,ACCE+SCRB
+EFUN: LXI H,ACCE+(SCRB SHL 8)^M
CALL PUSHF ;SAVE ACCUM
CALL GETC
CALL GETC
@@ -1599,7 +1599,7 @@ FUN4: CALL ECALL ;EVALUATE FUNTION INPUT
LXI H,FNTBF ;ADDRESS OF FUNCTIONS
CALL SORTJ ;GOTO FUNCTION
CALL ERROR6 ;BAD FUNCTION CODE
-EFUN3: LXI H,ACCE+SCRB
+EFUN3: LXI H,ACCE+(SCRB SHL 8)^M
CALL POPF ;RETURN FROM FUNCTIONS, RESTORE ACCUM
JMP ELPR2
ETERM:
@@ -1625,7 +1625,7 @@ EFND: MOV E,M
SHLD FLOP+1
LHLD PT1
FLOP: CALL LOD
- LDA OVER+SCRB
+ LDA OVER+(SCRB SHL 8)^M
ANA A
ERM21: CNZ ERROR6 ;OVERFLOW
LDA SRTCN
@@ -1736,16 +1736,16 @@ IDV: PUSH H ;
;
; 2 LEVELS OF STACK USED BEYOND FLOATING POINT PACKAGE
FMACL: XRA A ;CLEAR A REG FOR LOG TYPE SERIES
- LXI H,FMACS ;POINT TO SIGMA
+ LXI H,FMACS + (SCRB SHL 8) ;POINT TO SIGMA^M
MOV M,A ;ZERO STORED
LXI H,FMACB ;PRESET BRANCH B
JMP FMACC ;JOINT CODE
FMACE: LHLD FONE ;MOVE 1.0 TO SIGMA FOR EXP TYPE SERIES
- SHLD FMACS
+ SHLD FMACS + (SCRB SHL 8)^M
LHLD FONE+2
- SHLD FMACS+2
+ SHLD FMACS + (SCRB SHL 8) + 2^M
LXI H,FMACA ;PRESET BRANCH A
-FMACC: SHLD FMACG ;STORE PRESET BRANCH
+FMACC: SHLD FMACG + (SCRB SHL 8) ;STORE PRESET BRANCH^M
MVI E,32 ;COUNT FOR FLOATING OF A(I)
FMACD: PUSH B ;CHAIN RULE LOOP
PUSH D ;SAVE A(I), D(A(I)), D**2(A(1))
@@ -1759,13 +1759,13 @@ FMACD: PUSH B ;CHAIN RULE LOOP
CALL LOD
MVI L,FMACS ;SIGMA SO FAR
CALL MUL
- LHLD FMACG ;CHOOSE THE BRANCH
+ LHLD FMACG + (SCRB SHL 8) ;CHOOSE THE BRANCH^M
PCHL
-FMACA: LXI H,FMACT
+FMACA: LXI H,FMACT + (SCRB SHL 8)^M
CALL DIV
LXI H,FONE ;POINTS TO 1.0
JMP FMACF ;REJOIN COMMON CODE
-FMACB: LXI H,FMACS
+FMACB: LXI H,FMACS + (SCRB SHL 8)^M
CALL STR ;X*SIGMA
LXI H,FONE ;LOAD 1.0
CALL LOD

結果
*T S\FSIN(0.1)
9.983343E-02 正しい
*T FCOS(0.1)
.9950059  正しい
*T FEXP(1)
2.718282  正しい
*T FLOG(1)
.5403025   何だ?


FLOG(自然対数)が合わない。さらに調べて見ると、関数のキーワードをチェックするテーブルでは、
最初から3Char目をチェックしているだけ。(少しでもサイズを小さくする工夫)
FABS -> B
FSGN -> G
FSIN -> I
FCOS -> O
FSQT -> Q

これで行くと、FLOG -> O つまり、FCOSとして認識している。

ソースのこの部分
FNTBF EQU $ ;FUNCTION ADDRESSES
DW XABS
DW XSGN
DW XINT
DW XRAN
DW ARTN
DW FEXP
DW FLOG
DW FSIN
DW FCOS
DW XSQT
DW XUSR
DW FHYS
FNTBL EQU $ ;LIST OF CODED FUNCTION NAMES
DB 'B'
DB 'G'
DB 'N'
DB 'A'
DB 'T'
DB 'X'
DB 'L'
DB 'I'
DB 'O'
DB 'Q'
DB 'S'
DB 'Y'
DB 0 ;END

そこで3char目をLにしてみると、
*T FFLG(1)
0.000000  正しい
*T FFLG(2)
.6931472  正しい

とは言っても3char目がLなら何でもよいので、 FxL(2)でも良いのだけど。


PDP-8でもFOCALがつかえる(というより、こちらが先)
そこで以前作ったCPLDによるPDP-8で動かしてみた
https://blog.goo.ne.jp/ishihara-h/e/1c3a7a5a6b40cb010d9ed22f3ec679f7




若干動きは異なる(WRITE ALL でなくて、WRITEだけでOKとか)が
うまく動いている(FLOGも問題ない)



参考URL
http://www.ibiblio.org/pub/academic/computer-science/history/pdp-8/FOCL69%20Files/
DEC-08-AJAD-D.pdf
DECUS-FOCAL8-17.pdf