石原 博の覚書

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

PL/MでHELLO WORLD

2021-11-06 18:13:41 | 日記

せっかく動いたPL/M。もう少し遊んで見る。

・よくあるHello worldの例

Unofficial CP/M(http://www.cpm.z80.de/source.html)の「EARLY CP/M SOURCE」内のBDOS.PLMやCCP.PLMを参考に作成

===========================================

100H:                              /* [1] */
DECLARE BDOS LITERALLY '05H';

MON1: PROCEDURE(F,A);              /* [2] */
    DECLARE F BYTE,
    A ADDRESS;
    GO TO BDOS;
    END MON1;

DECLARE
    CR LITERALLY '13',
    LF LITERALLY '10';

PRINTCHAR: PROCEDURE(CHAR);
    DECLARE CHAR BYTE;
    CALL MON1(2,CHAR);
    END PRINTCHAR;

CRLF: PROCEDURE;
    CALL PRINTCHAR(CR);
    CALL PRINTCHAR(LF);
    END CRLF;

PRINT: PROCEDURE(A);
    DECLARE A ADDRESS;
    CALL MON1(9,A);
    END PRINT;

RET$CPM: PROCEDURE;                /* [3] */
    CALL MON1(0,0);
    END RESET;

HELLO:
DO;
    CALL PRINT(.'HELLO WORLD$');   /* [4] */
    CALL CRLF;
    CALL RET$CPM;                  /* [3] */
END HELLO;                                                                      
EOF                                /* [5] */

=========================================

・注意点
  [1]スタートアドレスが必要。ないと0スタート
  [2]入出力は自前でBDOSを呼ぶ
   昔からCP/MのBDOS Callが、CとDEにパラメタを入れるのが不思議だったのだが、PL/Mはそれに合ったコードを出す
   (初期のCP/MはPL/Mで書かれていたようなので、卵が先か鶏が先かなのかもしれない)
  [3]コンパイルしたコードの最後は、EI HALTになる
   これはCP/Mから実行する場合は困る。そこでRET$CPMというCP/Mに戻るコードを加えた。
  [4]文字はUpperCaseのみ。例え文字列であってもLowerCaseはだめ(Hello worldとは書けない)
  [5]最後にEOFが必要
    [6]コンパイル時のエラーは、fort.12の最後を見ること。「1 PROGRAM ERROR」とか出ている。

・コンパイル結果と実行結果

>ddt HELLO.HEX
DDT VERS 1.4
NEXT  PC
0161 0000
-l100,160
  0100  LXI  SP,01F8
  0103  JMP  0144
  0106  LXI  H,01F9             ;MON1 固定なので再帰は出来ない
  0109  MOV  M,C                ;第1引数はBYTEで1バイト
  010A  INR  L         ;INX HではないのはHLは奇数なことを見越した最適化かな
  010B  MOV  M,E                ;第2引数はADDRESSで2バイト
  010C  INX  H
  010D  MOV  M,D
  010E  JMP  0005               ;BDOS CALL
  0111  RET  
  0112  LXI  H,01FD             ;PRINTCHAR
  0115  MOV  M,C                ;第1引数はBYTEで1バイト  メモリ経由でEレジスタへ
  0116  MVI  C,02
  0118  MOV  E,M
  0119  MVI  D,00
  011B  CALL 0106
  011E  RET  
  011F  MVI  C,0D               ;CRLF
  0121  CALL 0112
  0124  MVI  C,0A
  0126  CALL 0112
  0129  RET  
  012A  LXI  H,01FE             ;PRINT
  012D  MOV  M,C                ;第1引数はADRESSで2バイト メモリ経由でDEへ
  012E  INX  H                  ;HLは偶数なのでINX H ?
  012F  MOV  M,B
  0130  MVI  C,09
  0132  DCR  L
  0133  MOV  E,M
  0134  INR  L
  0135  MOV  D,M
  0136  CALL 0106
  0139  RET  
  013A  MVI  C,00               ;RET$CPM
  013C  MVI  E,00
  013E  MVI  D,00
  0140  CALL 0106
  0143  RET  
  0144  JMP  0153               ;メインルーチンへ
  0147  MOV  C,B
  0148  MOV  B,L
  0149  MOV  C,H
  014A  MOV  C,H
  014B  MOV  C,A
  014C  ??=  20
  014D  MOV  D,A
  014E  MOV  C,A
  014F  MOV  D,D
  0150  MOV  C,H
  0151  MOV  B,H
  0152  INR  H
  0153  LXI  B,0147             ;メインルーチン 0x147は DB 'HELLO WORLD$'のアドレス。
  0156  CALL 012A               ;PRINT
  0159  CALL 011F               ;CRLF
  015C  CALL 013A               ;RET$CPM
  015F  EI                      ;ここへは戻らない
  0160  HLT  
  0161  
-

 

>load HELLO.HEX

FIRST ADDRESS 0100
LAST  ADDRESS 0160
BYTES READ    0061
RECORDS WRITTEN 01


E>HELLO
HELLO WORLD

RunCPM Version 5.3 (CP/M 2.2 60K)