BASCOM

マイクロソフト社のBASICコンパイラです。

00010 PRINT "HELLO WORLD"
00020 END

左が最も簡単なBASICのプログラムです。


CPMエミュレータを使って下のように コンパイル -> リンク -> 実行 を行います。

FIG06L01A.jpg(37918 byte)

このツールの入手は http://www.retroarchive.org/ の下の所からできます。

FIG06L01B.jpg(6332 byte)
 
   自作環境で使う場合

BASICコンパイラで作ったプログラムをCP/Mの外で使う 場合に問題になるのは システムコール をどうするかと言うことがあります。 INPUT文 や PRINT文 はシステムコールがあります。 システムコールを無視する場合でも5番地にRETのコードの C9 を置いて呼び出しからの戻しとします。

CP/M80ではCOMファイルが実行プログラムですがインテル へクスファイルを得る場合はリンク時に下のコマンドを 実行します。

          CPM L80 TEST,TEST/N/E/X

 
   メモリの読み書き
00010 A%=PEEK(&H1234)
00020 POKE &H1236,A%
00030 END

メモリの番地を指定しての直接の読み書きは左のよう になります。
A% は16ビットの変数です、1234hから読み出して1236hに 書き込んでいます。



BASCOM 5.30a- Copyright 1979,80,81
(C) by MICROSOFT - 31948 Bytes Free

 0014 0007      00010 A%=PEEK(&H1234)
        ** 0014'I00000: CALL    $530 
        ** 0017'L00010: 
        ** 0017'        LDA     1234
        ** 001A'        MOV     L,A
        ** 001B'        MVI     H,00
        ** 001D'        SHLD    A%
 0020 0009      00020 POKE &H1236,A%
        ** 0020'L00020: LHLD    A%
        ** 0023'        MOV     A,L
        ** 0024'        STA     1236
 0027 0009      00030 END
        ** 0027'L00030: CALL    $END 
 002A 0009      
        ** 002A'        CALL    $END 
 002F 0013      

00000 Fatal Error(s)
31831 Bytes Free

左のコンパイルリストを見ると 0014' はプログラム開始の呼び出し 0027' はプログラム終了の呼び出しで他に呼び出しを行って いません。 必要なコードは 0017' から 0024' までのコードと分かります。

このプログラムは4955バイトなのですが必要なコード は16バイトです。 このように呼び出しのないコードを書いた場合は最小 限の大きさに切り取ることができます。



 
   ポートの読み書き
00010 A%=INP(&H12)
00020 OUT &H13,A%
00030 END

ポートの番地を指定しての直接の読み書きは左のよう になります。
A% は16ビットの変数です、12hから読み出して13hに 書き込んでいます。



BASCOM 5.30a- Copyright 1979,80,81
(C) by MICROSOFT - 31948 Bytes Free

 0014 0007      00010 A%=INP(&H12)
        ** 0014'I00000: CALL    $530 
        ** 0017'L00010: 
        ** 0017'        IN      12
        ** 0019'        MOV     L,A
        ** 001A'        MVI     H,00
        ** 001C'        SHLD    A%
 001F 0009      00020 OUT &H13,A%
        ** 001F'L00020: LHLD    A%
        ** 0022'        MOV     A,L
        ** 0023'        OUT     13
 0025 0009      00030 END
        ** 0025'L00030: CALL    $END 
 0028 0009      
        ** 0028'        CALL    $END 
 002D 0013      

00000 Fatal Error(s)
31806 Bytes Free


 
   16ビットの加算
00010 A%=INP(&H12)
00020 B%=INP(&H13)
00030 C%=A%+B%
00040 OUT &H14,C%
00050 END


BASCOM 5.30a- Copyright 1979,80,81
(C) by MICROSOFT - 31948 Bytes Free

 0014 0007      00010 A%=INP(&H12)
        ** 0014'I00000: CALL    $530 
        ** 0017'L00010: 
        ** 0017'        IN      12
        ** 0019'        MOV     L,A
        ** 001A'        MVI     H,00
        ** 001C'        SHLD    A%
 001F 0009      00020 B%=INP(&H13)
        ** 001F'L00020: IN      13
        ** 0021'        MOV     L,A
        ** 0022'        MVI     H,00
        ** 0024'        SHLD    B%
 0027 000B      00030 C%=A%+B%
        ** 0027'L00030: LHLD    A%
        ** 002A'        XCHG
        ** 002B'        LHLD    B%
        ** 002E'        DAD     D
        ** 002F'        SHLD    C%
 0032 000D      00040 OUT &H14,C%
        ** 0032'L00040: LHLD    C%
        ** 0035'        MOV     A,L
        ** 0036'        OUT     14
 0038 000D      00050 END
        ** 0038'L00050: CALL    $END 
 003B 000D      
        ** 003B'        CALL    $END 
 0040 0017      

00000 Fatal Error(s)
31759 Bytes Free

コンパイルリストを見ると16ビットの加算は DAD D (8080) で行われています。 これはZ80では ADD HL,DE です。



 
   文法

本稿で解説しているBASICは古い形式のものなので基本 的な情報を掲載します。 BASICコンパイラの正規の解説書は持っていないのでマ イクロソフト系のBASICの文法書から抜粋します。

 
   文字セット
 
   定数
 
   文字定数

BASICで使える文字セットを並べ、全体を引用符 ( " ) で囲って指定します。

[例]   "HELLO WORLD"

 
   数値定数

数値定数には、次の五つの形式があります。

 
   整数形式

プラス(+)またはマイナス(-)の符号に続いて一つ以上 の数字を並べたもので、プラス符号は省略することも できます。
プラス符号の付いたものを正の整数、マイナス符号の 付いたものを負の整数と呼び、整数の値の範囲は -32768から+32767 までです。

[例]
  • 1
  • +123
  • -32767
 
   固定小数点形式

符号に続いて、整数部、小数点、小数部の順に書いた もので、プラス符号は省略することができます。 整数部と小数部のうち、一方は省略できますが、両方 とも省略することはできません、小数部は ( . ) で表します。

[例]
  • 1.0
  • -123.11
  • .999
 
   浮動小数点形式

指数形式で表現された正または負の数値で、符号に続 いて、整数部、小数点、小数部、指数部の順に書いた ものです。 プラス符号は省略することができます。 また、整数部、小数部のうち、一方の省略ができます 。 指数部は単精度では E[{±}]nn で表し、倍精度では D[{±}]nn で表します。なお、 nn は整数で、0から38までです。

[例]
  • 520.18E+7
  • 108E-18
  • 0.1256E+12
  • 0.99999999D-8
 
   16進形式

プレフィックス&Hに続いて、16進数(0〜9,A〜F)を並べ て書いたものです。 先行する0を除いて4桁まで書くことができ、&H0から&HFFFF までの範囲を表すことができます。 この形式で入力された16進数は、符号無し10進数に変 換されて出力されます。

[例]
  • &H64
  • &H003F
 
   8進形式

プレフィックス&Oまたは&に続いて8進数(0〜7)を並べ て書いたものです。 先行する0を除いて6桁まで書くことができ、&O0〜&O177777 までの範囲を表すことができます、この形式で入力さ れた8進数は、符号無し10進数に変換されて出力されま す。

[例]
  • &O0123
  • &O123456
 
   単精度と倍精度の数値定数

数値定数には、単精度定数と倍精度定数があります。 単精度定数は、7桁までの精度で格納され、6桁までの 桁数で表示されます。
倍精度定数は、17桁の精度で格納され、16桁までの桁 数で表示されます。
単精度定数および倍精度定数で表現できる数値の絶対 値は、約3.0×10-39から 1.7×10+38までであり、 3.0×10-39より小さい数 は0になります。
単精度数値定数は次のいずれかに当てはまるものです 。

  1. 有効桁数が7桁以下の定数
  2. Eを用いた指数形式で表現されたもの
  3. 最後に感嘆符( ! )が書かれた定数
[例]
  • 13.6
  • -1.23E+6
  • 862.1!
  • 520

倍精度数値定数は、次のいずれかに当てはまるものです。

  1. 有効桁数が8桁以上の定数
  2. Dを用いた指数形式で表現されたもの
  3. 最後にナンバ記号( # )が書かれた定数
[例]
  • 1368792702
  • -1.5670D-12
  • 562.983#
  • 852.138269012
 
   変数

変数は、BASICのプログラムの中で使われる値を表すた めに使われる名前です。 変数はプログラムの中で値が与えられるまでは、その 値は0になっています。

 
   変数名と型宣言文字

変数名は、255文字以内の英数字で構成されますが、最 初の文字は英字でなければなりません、BASICは最初の 16文字+型宣言文字により変数名を区別します。
変数名は予約語であってはなりません、BASICで使われ るコマンド名、ステートメント名、関数名、演算子名 などのキーワードは、全て予約語です。
変数は数値、文字列のいずれをも表すことができます 。 変数名の直後に型宣言文字を付けて、その変数が表す 値の型を宣言することができ、この型宣言文字には次 のものがあります。

  •   整数変数を示し、一つの変数につき、2バイトのデータ格納域を必要とします。
  •   単精度変数を示し、一つの変数につき、4バイトのデータ格納域を必要とします。
  •   倍精度変数を示し、一つの変数につき、8バイトのデータ格納域を必要とします。
  •   文字変数を示し、最大255文字のデータを格納することができます。

型宣言もなく型宣言文字も伴わない変数名は、単精度 形式の数値を表すものとして扱われます。

[例]
  • A%          整数変数
  • PNT!      単精度変数
  • MAX#     倍精度変数
  • L$          文字変数
  • AB         単精度変数
 
   配列変数

配列は、同じ性質を持つ複数個のデータの集まりです。 配列は同一名でその要素を参照することができ、それ ぞれの要素は添字により順序付けられます。 ある変数を配列変数として宣言するためには、 DIM 文を用いて次のように行います。

   DIM 変数名 (添字の最大値[,添字の最大値]・・・・・・・)

カッコの中に書かれた添字の最大値の個数により、そ の配列変数の次元数を指定します。 配列の次元は、1次元から多次元の指定が行えます。 添字の最大値は整数形式で、0から32767の範囲でなけ ればなりません。 配列変数の一要素の参照は、各次元の添字を指定した 添字付き名で行い、その形式は次のとおりです。

   変数名 (第1次元の添字[,第2次元の添字]・・・・・・・)

変数名の直後にカッコでくくって各次元の添字を指定 します。 この中に書かれた添字の個数は、配列変数の次元数と 一致しなければなりません。 添字は数値式で、その値は0から添字の最大値までです 。 各次元の添字の結果が整数でない場合は、小数部を切 り捨てた整数に変換されます。

[例]  DIM A(2,2)
2次元の配列を宣言しています。配列の各要素の参照は次のようになります。
A(1,1)
A(1,2)
A(2,1)
A(2,2)
 
   式

式は演算の方法を示すもので、定数や変数、関数を演 算子で結んで指定します。 式には算術式、関係式、論理式および文字式があり、 この中で算術式、関係式および論理式を数値式と呼び ます。

 
   算術式

算術式は、変数、定数、関数などの数値データを算術 演算子で結んだものです。 また算術演算子のない数値データのみの場合も算術式 と呼びます。 算術演算子には次のものがあります。

  • +    加算を行います。
  • −    減算を行います。
  • *    乗算を行います。
  • /    浮動小数点除算を行います。
  • ^     ベキ乗を行います。
  • ¥    整数の除算を行います。結果は浮動小数点除算の小数点以下を切り捨てた値となります。
  • MOD  整数の除算の剰余を求めます。

整数の除算 ( ) および 、整数の剰余( MOD ) の演 算において、オペランドが整数形式でないときは、小 数部を四捨五入し、整数に変換してから演算が行われ ます。

[例]
  • 24.35 \ 6.87 = 24 \ 7 = 3
  • 10.2 MOD 4 = 10 MOD 4 = 2
 
   プログラミング

ファイル操作以外のCP/M環境を実装したZ80CPUを搭載したボードコンピュータで のプログラミングについて述べます。
Z80のメモリ空間は64Kバイトですが、現在はシリアルEEPROMの1個に記憶できる容量です。 電源投入時にプログラムをこのEEPROMからSRAMに展開すればプログラムをROMとRAMに分離 する必要が無くなりました。
よってCP/M上のコンパイラが出力するCOMファイルを変更せずにメモリに展開して実行で きるようになりました。
Z80の論理設計は当WEBにおいて論理設計を終了していますが、 いずれ大容量のPLDが低価格して同時に小ピン化すればZ80をPLDに収めても苦にならない 時が来ると思います。
CP/Mのソフトウェアはいわゆる組み込みコンピュータにおける実行ということでは制約は なにも無くなったと言えます。

 
   コンソール入出力

00010 PRINT "CONSOLE TEST"
00020 PRINT
00030 INPUT "A=",A
00040 INPUT "B=",B
00050 PRINT "A+B=";A+B
00060 GOTO 20
00150 END
 

コンソールへの出力でプログラム開始の文字列を表示してから2変数の入力を コンソールから行い足し算の結果をコンソールに出力するものです。



>HEX
>3DC2B5287CB71F677D1F6FC90600D608DAE728435A510E67
>1928E30000C3
>GO 100
CONSOLE TEST

A=12
B=34
A+B= 46

A=123
B=456
A+B= 579

A=1234
B=5678
A+B= 6912

A=1.23
B=4.56
A+B= 5.79

A=^C

STOP at address 014C

CP/M ADAPTER ver 1.0a
 

すでにCP/Mアダプタが動いているところに HEXコマンド でプログラムをダウンロードします。
L80 の出力するHEXファイルの後尾に意味不明のデータが付けられていますが プログラムの実行に支障はないようです。
GOコマンド で100番地から実行します。
プログラムはループしていますから CTRL-C を押して中断させます。
プログラムは中断の表示をしてCP/Mアダプタに戻りました。


 
   入力ポート

00010 PRINT "IN PORT TEST"
00020 PRINT
00030 PRINT "PUSH ANY KEY"
00040 PRINT
00050 A%=INP(0)                     '制御ポート読み出し
00060 A%=A% AND 1                   '受信ビットを残す
00070 IF A%=0 THEN 50               '受信しているか判断
00080 B%=INP(1)                     '受信データ読み出し
00090 IF B%=ASC(".") THEN 120       '"."なら終わり
00100 PRINT "RECEIVE DATA = ";B%
00110 GOTO 30
00120 END
 


>GO 100
IN PORT TEST

PUSH ANY KEY

RECEIVE DATA =  49
PUSH ANY KEY

RECEIVE DATA =  50
PUSH ANY KEY

RECEIVE DATA =  51
PUSH ANY KEY

CP/M ADAPTER ver 1.0a
 

PUSH ANY KEY の表示のあとに 1 , 2 , 3 と入力しています。
すると該当するASCIIコードが10進数で表示されます。
次に を入力すると実行を終了します。


 
   出力ポート

00010 PRINT "OUT PORT TEST"
00020 PRINT
00030 C=0
00040 A%=INP(0)         '制御ポート読み出し
00050 A%=A% AND 2       '送信ビットを残す
00060 IF A%<>0 THEN 40  '送信できるか判断
00070 C%=C%+1
00080 OUT 2,C%+&H30     '送信
00090 IF C%=3 THEN 120  '3なら終わり
00100 GOTO 40
00110 PRINT
00120 END
 


>GO 100
OUT PORT TEST

123

CP/M ADAPTER ver 1.0a
 

123 と出力して実行を終了しています。


 
   指定メモリ書き込み

00010 PRINT "POKE TEST"
00020 PRINT
00030 POKE &H8000,&H55
00040 POKE &H8001,&HAA
00050 POKE &H8002,1
00060 POKE &H8003,2
00070 C%=&H23
00080 POKE &H8004,C%
00090 POKE &H8005,C%+1
00100 POKE &H8006,C%+2
00110 END
 


>GO 100
POKE TEST

CP/M ADAPTER ver 1.0a

>D 8000
8000 55 AA 01 02 23 24 25 00 00 00 00 00 00 00 00 00
8010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8050 00 00 00 00 00 00 0>
>
 

プログラムの実行後に Dコマンド8000H 番地を表示しています。


 
   指定メモリ読み出し

00010 PRINT "PEEK TEST"
00020 PRINT
00030 FOR I=&H8000 TO &H800A STEP 1
00040    A=PEEK(I)
00050    PRINT HEX$(I);" = ";HEX$(A)
00060 NEXT I
00070 END
 


>GO 100
PEEK TEST

8000 = 12
8001 = 34
8002 = 56
8003 = 78
8004 = 9A
8005 = BC
8006 = DE
8007 = F0
8008 = 55
8009 = AA
800A = 0

CP/M ADAPTER ver 1.0a

>D 8000
8000 12 34 56 78 9A BC DE F0 55 AA 00 00 00 00 00 00
8010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
8030 00 >
>
 

8000H〜800AH 番地のメモリを表示して実行を終了しています。


 
   IO直接操作

FIG1.jpg(27242 byte)

FIG2.jpg(15004 byte)

CP/Mの無いところで動くことのできるシステムコールを使わないプログラムです。 5.5K バイトの大きさです。