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 | ||
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
*
例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
*
大量の処理が必要な場合は、この部分に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 行番号で、行番号の文を単独で実行し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 何だ?
0C8F 216B00 LXI H,FMACS ;POINT TO SIGMA
0C92 77 MOV M,A ;ZERO STORED
(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