{{include unfinished_page}} ,{t},{BSIZE:1 0|SIZE:100%} ,{BSIZE:0}←[[5章 マシン語とのリンク]] ,{BSIZE:0|RIGHT}[[7章 プログラム開発の諸注意]] → !!6.1 PLAY文BIOS !6.1.1 概要  MSXはPSGの音楽を割り込みルーチン内で演奏しています。BASICではPLAY文がMML(Music Macro Language)を割り込みルーチンが解釈できる形に変換してキューに書き込み、あるフラグをセットします。割り込みルーチンはそのフラグを見て、キューにデータが書かれたことを知り、キューからデータを取り出して演奏します。  演奏はキューから取り出したデータがEND MARKのときに終了します。このキューは各チャンネルごとに1本ずつで、合計3本あります。 !6.1.2 キューの構造  まず、【QUEUES(0F3F3H,2)】というワークエリアがあり、これがQCB(Queue Control Block)という構造体の配列の先頭を指しています。QCB構造体の配列は、通常【QUETAB(0F959H,24)】にあり、要素数は4つです。しかし、最後の1つはPLAY文では使用しません。1つのQCBは次のような構造をしています。 '''表2.19 QCBの構造''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:80},{BSIZE:1 0|SIZE:120},{BSIZE:1 0} ,開始番地からのオフセット,用途, ,{c},{BSIZE:0|TOP},{BSIZE:0|TOP},{BSIZE:0|TOP} ,0 ,PUTオフセット,キューにデータを書き込むときのオフセット ,1 ,GETオフセット,キューからデータを読み出すときのオフセット ,2 ,バックアップキャラクタ{COLS:2} , ,キューにデータを書き込むときに一時的に使われる{COLS:2} ,3 ,キューの長さ ,実際のキューの長さ-1。取り得る値は2のn乗-1(nは2から8)。単位はバイト。通常は127 ,4、5,キューの開始番地{COLS:2} , ,実際のキューの開始番地。通常、以下のキューを指している{COLS:2} , ,チャンネル1,"【VOICAQ(0F975H,128)】" , ,チャンネル2,"【VOICBQ(0F9F5H,128)】" , ,チャンネル3,"【VOICCQ(0FA75H,128)】" !6.1.3 キューデータの解説  キューには1回の割り込み処理中に設定されるデータが可変長で入っています。最初の2バイトの上位3ビットはその割り込み処理中に処理されるデータが何バイトであるかを指定します。指定できる範囲は1から5です。残りの13ビットは次のでデータの処理するまでの時間をタイマー割り込みの回数を指定します。この2バイトのデータは上位バイトが先になります。終了はこの2バイトの代わりに、1バイトのFFHが入ります。残りのデータは次の4種類のうちのどれかが入っているかで異なります。 +音程を設定するデータ(MMLのAからG、Nに相当する) +音程を設定するデータ(Vに相当する) +エンベロープの形状を設定するデータ(Sに相当する) +エンベロープの周期を設定するデータ(Mに相当する)  各々の詳細な形式を以下で説明します。PSGに設定するデータの詳細は、「第6部 1章 PSGと音声出力」を参照してください。 '''1.音程を設定するデータ'''  音程を設定するデータは2バイトで構成されます。上位2ビットは音程を設定するデータでることを示すために、「00」とします。残りの14ビットでPSGに設定する音色をそのまま指定しますが、PSGでは下位12ビットのみ有効です。上位バイトが先になります。 '''2.音声を設定するデータ'''  音量を設定するデータは1バイトで構成されます。上位4ビットは音量を設定するデータであることを示すために、「1000」とします。残りの4ビットでPSGに設定する音量をそのまま指定します。 '''3.エンベロープの形状を設定するデータ'''  エンベロープの形状を設定するデータは1バイトで構成されます。上位4ビットはエンベロープの形状を設定するデータであることを示すために、「1001」とします。残りの4ビットでPSGに設定するエンベロープの形状をそのまま設定します。 '''4.エンベロープの周期を設定するデータ'''  エンベロープの周期を設定するデータは3バイトで構成されます。最初の1バイトはエンベロープの周期を設定するデータであることを示すために「40H」とします。残りの2バイトでPSGに設定するエンベロープの周期をそのまま指定します。この2バイトは上位バイトが先になります。 '''5.エンベロープの形状と周期を同時に設定するデータ'''  このデータは3バイトで構成されます。最初の1バイトのうち、上位4ビットは「1101」とします。下位4ビットはPSGに設定するエンベロープの形状をそのまま指定します。残りの2バイトでPSGに設定するエンベロープの周期をそのまま指定します。この2バイトは上位バイトが先になります。 !6.1.4 データの具体例  MMLで"T120L4V8O4CDE"とした場合(以下16進数) ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:20},{BSIZE:0|SIZE:80},{BSIZE:0} ,,"60,1E",3バイトのデータがあり、0.5秒間続ける ,,"88" ,音量は8 ,,"01,AC",音程は01ACH ,,"60,1E",3バイトのデータがあり、0.5秒間続ける ,,"88" ,音量は8 ,,"01,7D",音程は017DH ,,"60,1E",3バイトのデータがあり、0.5秒間続ける ,,"88" ,音量は8 ,,"01,53",音程は0153H ,,FF ,終了 !6.1.5 BIOS  BIOSはSTRTMS(0099H/MAIN)という名前のルーチンがあります。これを呼ぶことにより、演奏を始めることができます。以下のサンプルプログラムを参照してください。 '''リスト2.8 STRTMSの使用例''' strtms equ 0099h musicf equ 0fb3fh ; 音楽演奏用の割り込みフラグ plycnt equ 0fb40h ; キューされているPLAY文の数 quetab equ 0f959h ; キューテーブル qcblen equ 6 ; QCBの長さ cseg music: ld a,(musicf) ; 演奏中? or a jr nz,music ; 演奏中なら、終わるまで待つ di ld de,quetab ld hl,queini ld bc,qcblen * 3 ldir ; QCBの設定 ld a,1 ld (plycnt),a call strtms ; 演奏開始 ei ret queini: db 0ffh db 0 db 0 db 0ffh dw queue1 db 0ffh db 0 db 0 db 0ffh dw queue2 db 0ffh db 0 db 0 db 0ffh dw queue3 ; ; "T120L4V8O4CDE" queue1: db 0 ; a dummy db 60h,1eh,88h,01h,0ach ; T120L4V8C db 60h,1eh,88h,01h,7dh ; T120L4V8D db 60h,1eh,88h,01h,53h ; T120L4V8E db 0ffh ; end mark queue2: db 0 db 0ffh queue3: db 0 db 0ffh end !!6.2 ビットブロックトランスファ  ビットブロックトランスファとは、RAM、VRAM、ディスク間でデータを転送するSUB ROM内ルーチンです。本来、MSX2で拡張されたBASICのCOPY命令用のルーチンですが、完全なサブルーチンの形式になっているので、BIOSのようにユーザープログラムから利用できます。  なお、ビットブロックトランスファルーチンが使用可能な画像データは、BASICのCOPY命令で作成されたデータです。BSAVE"ファイル名",&Hxxxx,&Hxxxx,Sで作成されたデータは使用できません。 {{svg 図2.28.svg}} '''図2.28 COPY命令で作成した画像ファイルのヘッダ情報''' ,{SIZE:100|CENTER}例 COPY (0,0)-(10,20) TO "TEST.PIC" で作成したTEST.PICは、0BH、00H、15H、00H、.... となる。 !6.2.1 VRAM間の転送 ::BLTVV(0191H/SUB) ,{SIZE:100|CENTER}機能 VRAM領域内で転送を行います。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"SX(0F562H,2) " ,; 転送元基準点 X座標 ,"SY(0F564H,2) " ,; 転送元基準点 Y座標 ,"DX(0F566H,2) " ,; 転送先基準点 X座標 ,"DY(0F568H,2) " ,; 転送先基準点 Y座標 ,"NX(0F56AH,2) " ,; X方向転送ドット数 ,"NY(0F56CH,2) " ,; Y方向転送ドット数 ,"CDUMMY(0F56EH,1) " ,; ダミー(セットする必要はない) ,"ARG(0F56FH,1) " ,; 方向と拡張RAMの選択(VDPのR#45と同じ) ,"LOGOP(0F570H,1) " ,; ロジカルオペレーション ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 ; COPY (0,0)-(255,99) TO (0,100) bltvv equ 0191h extrom equ 015fh ld hl,0 ld (sx),hl ; 転送元基準点は(0,0) ld (sy),hl ld (dx),hl ; 転送先基準点は(0,100) ld l,100 ld (dy),hl ld hl,255-0+1 ; Y方向転送ドット数の設定 ld (nx),hl ld hl,99-0+1 ; X方向転送ドット数の設定 ld (ny),hl xor a ; 方向の設定 ld (arg),a ld (l_op),a ; operation is 'replace' ld hl,0f562h ld ix,bltvv call extrom : : : !6.2.2 RAMとVRAM間のデータ転送  以下のルーチンを使う場合、グラフィックのデータ領域として、スクリーンモードによって次のような大きさの領域を確保しておく必要があります。 '''表 2.20 スクリーンモード別確保領域の算出法''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:150},{BSIZE:1 0} ,スクリーンモード,領域の大きさ ,{c},{BSIZE:0},{BSIZE:0} ,6 ,X方向のドット数×Y方向のドット数÷4+4 ,5、7 ,X方向のドット数×Y方向のドット数÷2+4 ,8 ,X方向のドット数×Y方向のドット数+4 ,{SIZE:100|CENTER}注意 割り算の端数は切り上げて下さい。  なお、ディスクやRAMでは配列データと同様にサイズを示すデータが付加されます。このデータは先頭から2バイトがX方向のドット数、次の2バイトがY方向のドット数を示しています。 ::BLTVM(0195H/SUB) ,{SIZE:100|CENTER}機能 配列をVRAMに転送します。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"DPTR(0F562H,2) " ,; メモリの転送元アドレス ,"DUMMY(0F564H,2) " ,; ダミー(セットする必要はない) ,"DX(0F566H,2) " ,; 転送先基準点 X座標 ,"DY(0F568H,2) " ,; 転送先基準点 Y座標 ,"NX(0F56AH,2) " ,; X方向転送ドット数(セットする必要はない) ,"NY(0F56CH,2) " ,; Y方向転送ドット数(セットする必要はない) ,"CDUMMY(0F56EH,1) " ,; ダミー(セットする必要はない) ,"ARG(0F56FH,1) " ,; 方向と拡張RAMの選択(VDPのR#45と同じ) ,"LOGOP(0F570H,1) " ,; ロジカルオペレーション ,{SIZE:100|CENTER}戻り値 転送するデータの個数がおかしければCYフラグをセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 ; COPY TO (5,6) bltvm equ 0195h extrom equ 015fh ld hl,0b000h ld (dptr),hl ; データはB000Hにある ld hl,5 ld (dx),hl ; 転送先基準点は(5,6) inc hl ld (dy),hl xor a ; 方向の設定 ld (arg),a ld (l_op),a ; operation is 'replace' ld hl,0f562h ld ix,bltvm call extrom : : : ::BLTMV(0199H/SUB) ,{SIZE:100|CENTER}機能 VRAMから配列に転送します。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"SX(0F562H,2) " ,; 転送元基準点 X座標 ,"SY(0F564H,2) " ,; 転送元基準点 Y座標 ,"DPTR(0F566H,2) " ,; メモリの転送元アドレス ,"DUMMY(0F568H,2) " ,; ダミー(セットする必要はない) ,"NX(0F56AH,2) " ,; X方向転送ドット数 ,"NY(0F56CH,2) " ,; Y方向転送ドット数 ,"CDUMMY(0F56EH,1) " ,; ダミー(セットする必要はない) ,"ARG(0F56FH,1) " ,; 方向と拡張RAMの選択(VDPのR#45と同じ) ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 ; COPY (10,20)-(50,25) TO bltmv equ 0199h extrom equ 015fh ld hl,0b000h ld (dptr),hl ; データはB000Hにある ld hl,10 ld (sx),hl ; 転送元基準点は(10,20) ld hl,20 ld (sy),hl ld hl,50-10+1 ; Y方向転送ドット数の設定 ld (nx),hl ld hl,25-20+1 ; X方向転送ドット数の設定 ld (ny),hl xor a ; 方向の設定 ld (arg),a ld hl,0f562h ; ld ix,bltvm call extrom : : : !6.2.3 ディスクとRAM、VRAM間の転送  ディスクを使う場合、まずファイル名を設定する必要があります(ファイル名はBASICと同様に指定)。例を次に示します。 : : ld hl,fname ; ファイル名へのポインタの獲得 ld (fnptr),hl ; パラメータエリアに設定 : : fname: db 22h,'b:test.pic',22h,0 ; "TEST.PIC",end mark  ここで、何かエラーが起きれば、BASICインタープリタのエラーハンドラーへジャンプします。そのため、自分のプログラム内でエラーをハンドリングしたい場合やMSX-DOS、ROMカートリッジでこのルーチンを呼ぶ場合、フックをセットする必要があります。このフックは【ERRO(0FFB1H)】です。 ::BLTVD(019DH/SUB) ,{SIZE:100|CENTER}機能 ディスクからVRAMへ転送します。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"FNPTR(0F562H,2) " ,; ファイル名のあるアドレス ,"DUMMY(0F564H,2) " ,; ダミー(セットする必要はない) ,"DX(0F566H,2) " ,; 転送先基準点 X座標 ,"DY(0F568H,2) " ,; 転送先基準点 Y座標 ,"NX(0F56AH,2) " ,; X方向転送ドット数(セットする必要はない) ,"NY(0F56CH,2) " ,; Y方向転送ドット数(セットする必要はない) ,"CDUMMY(0F56EH,1) " ,; ダミー(セットする必要はない) ,"ARG(0F56FH,1) " ,; 方向と拡張RAMの選択(VDPのR#45と同じ) ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 ; COPY "TEST.PIC" TO (3,2) bltvd equ 019dh extrom equ 015fh ld hl,filename ld (fnptr),hl ; ファイル名へのポインタの設定 ld hl,3 ld (dx),hl ; 転送先基準点は(3,2) dec hl ld (dy),hl xor a ; 方向の設定 ld (arg),a ld (l_op),a ; operation is 'replace' ld hl,0f562h ld ix,bltvd call extrom : : filename:db 22h,'test.pic',22h,0 : : ::BLTDV(01A1H/SUB) ,{SIZE:100|CENTER}機能 VRAMからディスクへ転送します。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"FNPTR(0F562H,2) " ,; ファイル名のあるアドレス ,"DUMMY(0F564H,2) " ,; ダミー(セットする必要はない) ,"DX(0F566H,2) " ,; 転送先基準点 X座標 ,"DY(0F568H,2) " ,; 転送先基準点 Y座標 ,"NX(0F56AH,2) " ,; X方向転送ドット数 ,"NY(0F56CH,2) " ,; Y方向転送ドット数 ,"CDUMMY(0F56EH,1) " ,; ダミー(セットする必要はない) ,"ARG(0F56FH,1) " ,; 方向と拡張RAMの選択(VDPのR#45と同じ) ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 ; COPY (10,20)-(50,25) TO "A:TEST.PIC" bltdv equ 01a1h extrom equ 015fh ld hl,filename ld (fnptr),hl ; ファイル名へのポインタの設定 ld hl,10 ld (sx),hl ; 転送先基準点は(10,20) ld hl,20 ld (sy),hl ld hl,50-10+1 ; X方向転送ドット数の設定 ld (nx),hl ld hl,25-20+1 ; Y方向転送ドット数の設定 ld (ny),hl xor a ; 方向の設定 ld (arg),a ld hl,0f562h ld ix,bltdv call extrom : : filename:db 22h,'a:test.pic',22h,0 : : ::BLTMD(01A5H/SUB) ,{SIZE:100|CENTER}機能 ディスクから配列データをロードします。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"FNPTR(0F562H,2) " ,; ファイル名のあるアドレス ,"SY(0F564H,2) " ,; ダミー(セットする必要はない) ,"SPTR(0F566H,2) " ,; ロードする先頭アドレス ,"EPTR(0F568H,2) " ,; ロードする最終アドレス ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 bltmd equ 01a5h extrom equ 015fh ld hl,filename ; ファイル名へのポインタの設定 ld (fnptr),hl ld hl,8000h ; 先頭アドレスの設定 ld (sptr),hl ld hl,0afffh ; 最終アドレスの設定 ld (eptr),hl ; ld hl,0f562h ld ix,bltmd call extrom : : filename:db 22h,'test.bin',22h,0 : : ::BLTDM(01A9H/SUB) ,{SIZE:100|CENTER}機能 ディスクへ配列データをセーブします。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,HL, 0F562H さらに以下のパラメータを設定する。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:200},{BSIZE:0} ,"SPTR(0F562H,2) " ,; セーブする先頭アドレス ,"EPTR(0F564H,2) " ,; セーブする最終アドレス ,"FNPTR(0F566H,2) " ,; ファイル名のあるアドレス ,{SIZE:100|CENTER}戻り値 CYフラグをリセット ,{SIZE:100|CENTER}変更レジスタ すべて ,{SIZE:100|CENTER}例 bltmd equ 01a9h extrom equ 015fh ld hl,filename ; ファイル名へのポインタの設定 ld (fnptr),hl ld hl,8000h ; 先頭アドレスの設定 ld (sptr),hl ld hl,0afffh ; 最終アドレスの設定 ld (eptr),hl ; ld hl,0f562h ld ix,bltdm call extrom : : filename:db 22h,'a:test.bin',22h,0 : : !6.2.4 ビットブロックトランスファの利用法 '''1.BASICの環境から利用する場合'''  定められたワークエリアに値を入れて、HLレジスタが0F562Hを指すようにセットし、SUB ROM内のアドレスをコールします。  以下のサンプルプログラムは、「MSX-DOS TOOLS」を使用し、BASICの環境からマシン語のプログラムをメモリ上にロードし、実行するものです。 '''リスト2.9 BASIC環境でのビットブロックトランスファ使用例''' ; ; BLTVV.MAC sample program ; bltvv equ 0191h sx equ 0f562h sy equ 0f564h dx equ 0f566h dy equ 0f568h nx equ 0f56ah ny equ 0f56ch cdummy equ 0f56eh arg equ 0f56fh logop equ 0f570h extrom equ 015fh start:: ld de,0 ld (sx),de ; 転送元基準点は(0,0) ld (sy),de ld (dx),de ; 転送先基準点は(0,100) ld de,100 ld (dy),de ld (nx),de ; X方向転送ドット数を100に設定 ld (ny),de ; Y方向転送ドット数を100に設定 ld a,00000000b ; VRAMに対してコピーする ld (arg),a ; 方向は、X方向が右、Y方向が下 ld (logop),a ; ロジカルオペレーションはIMP ld ix,bltvv call extrom ; SUB ROM コール ret end  以下のバッチファイルは、上記のアセンブラプログラムをBASICからBLOADするバイナリプログラムにするものです。 m80 = bltvv l80 /p:c000,bltvv,bltvv /n/n/e:start bsave bltvv.hex > bltvv.bin こうして作成したバイナリファイルを実行するには、以下のBASICプログラムを使用します。 10 CLEAR 300,&HBFFF 20 BLOAD"bltvv.bin" 30 SCREEN 8:COPY "sample.pic" TO (0,0) 40 DEFUSR0=&HC000 50 A=USR(0) 60 A$=INKEY$:IF A$="" THEN GOTO 60 '''2.MSX-DOSの環境から利用する場合'''  ビットブロックトランスファルーチンは、本来BASICのCOPY命令で使用するものですから、BASIC環境での動作を前提に作られています。したがって、MSX-DOSのプログラムからビットブロックトランスファを利用する場合には、BASIC環境からアクセスする手順に加えて、以下の手続きが必要になります。 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:20|TOP},{BSIZE:0} ,1),ビットブロックトランスファルーチンは、SPと【STREND(0F6C6H)】が指す番地までをディスクアクセス時のバッファとして使用するので、STRENDに値を設定しなければならない。 ,2),ディスクをアクセスするルーチン使用時に設定するFNAMEの内容は、ページ2かページ3になければならない。 '''リスト2.10 DOS環境でのビットブロックトランスファ使用例''' ; ; BLTVD sample program ; strend equ 0f6c6h bltvd equ 019dh calslt equ 001ch exptbl equ 0fcc1h exbrsa equ 0faf8h fnptr equ 0f562h dx equ 0f566h dy equ 0f568h arg equ 0f56fh l_op equ 0f570h chgmod equ 005fh extrn _calsub ; start: ld sp,(6) ; スタックを設定 ld hl,0c000h ; STRENDをC000Hに設定 ld (strend),hl ld bc,11 ; FNAMEの内容をB000Hからにブロック転送 ld de,0b000h ld hl,fname ldir ld a,8 ; スクリーン8 ld iy,(exptbl-1) ld ix,chgmod call calslt ld hl,0b000h ; ブロック転送したアドレスを設定 ld (fnptr),hl ld de,0 ld (dx),de ld (dy),de xor a ld (arg),a ld (l_op),a ld hl,0f562h ld ix,bltvd call _calsub ld a,0 ; スクリーンをテキストモードに戻す ld iy,(exptbl-1) ld ix,chgmod call calslt jp 0 ; fname: db 22h,'test.pic',22h,0 ; end !!6.3 Math-Pack  Math-Pach とは、MSX−BASIC の数値演算ルーチンの中核をなすもので、これらをマシン語から呼び出すことにより、簡単に浮動小数点演算や三角関数ルーチンを利用することができます。  Math-Pack での実数演算はすべて BCD (Binary Coded Decimal = 2進化10進法)表現によって行われます。また、実数表現には、「単精度」と「倍精度」の2種類があり、単精度(6桁)は4バイト、倍精度(14桁)は8バイトで表現されます。(図2.29、図2.30) {{svg 図2.29.svg}} '''図2.29 BCDによる実数表現のフォーマット''' {{svg 図2.30.svg}} '''図2.30 実数の表現例'''  1つの実数は、符号部、指数部、仮数部から成り立っています。符号部とはこの仮数部の符号を表し、0ならば正、1ならば負となります。指数部はバイナリ表現であり、+63乗〜 -63乗まで表すことができます(図 2.31)。倍精度実数の有効範囲を図2.32に示します。 {{svg 図2.31.svg}} ,{BSIZE:1|SIZE:100|CENTER}注意 「×」はその値が1または0のどちらであっても関係が無いことを表します。 '''図2.31 指数部フォーマット''' {{svg 図2.32.svg}} '''図2.32 倍精度実数表現の有効範囲'''  Math-Packでは、演算の対象となるメモリがあらかじめ決められています。このメモリエリアを【DAC (Decmal ACcumlator - 0F7F6H)】と呼び、DACと演算対象となる数値を格納するエリアを【ARG(0F847H)】といいます。例えば、乗算ルーチンの場合、DACに入っている数とARGに入っている数の積が計算され、その結果がDACに入ることになります。  DACには、単精度実数、倍精度実数、2バイト整数を格納することができますが、これらのうちのどれが入っているのかを示すために【VALTYP (0F663H)】が使われ、それぞれの場合について4、8、2の値が入ります。  単精度実数と倍精度実数は、いずれもDACの先頭から数値を格納しなければなりません。ただし、2バイト整数の場合だけは、下位、上位をDAC+2、+3に格納して下さい。  演算の対象が明記されていない演算は【VALTYP(0F663H)】によって値の型を参照するので、呼び出す前に正しい型を設定して下さい。  Math-PackはBASICの内部ルーチンであるため、エラーが起きた場合(0除算やオーバーフローなど)はそれに応じたエラールーチンへ自動的に分岐し、その後BASICコマンドレベルに戻ります。それを避けたいときは、【H.ERRO (0FFB1H)】を書き換えて、アプリケーションプログラム側のエラー処理ルーチンへジャンプするようにして下さい。 !6.3.1 Math-Pack ワークエリア ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,サイズ,意味 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,VALTYP,F663H,1 ,DACに入っている数の形式を表す ,DAC ,F7F6H,16,BCD形式の浮動小数点アキュムレータ ,ARG ,F847H,16,DACの演算対象 !6.3.2 Math-Pack エントリ '''1.基本演算''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:200},{BSIZE:1 0} ,ラベル,アドレス,意味,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,DECSUB ,268CH,DAC ← DAC-ARG ,すべて ,DECADD ,269AH,DAC ← DAC+ARG ,すべて ,DECNRM ,26FAH,DAC を正規化する (*1) ,すべて ,DECROU(*2),273CH,DAC を四捨五入する ,すべて ,DECMUL ,27E6H,DAC ← DAC*DAC ,すべて ,DECDIV ,289FH,DAC ← DAC/DAC ,すべて ,{SIZE:100|CENTER}注 意 これらは、いずれも DAC, ARG にある数を倍精度実数として扱う。 '''*'''1 仮数部の不要な 0 を取り去ること (0.00123 → 0.123E-2) '''*'''2 DECROUは倍精度の値の最終桁+1(15桁目)に対して演算を行う。 <演算の例> 1.23456789012345→DECROU→1.2345678901235 1.11111111111114→DECROU→1.1111111111111 1.11111111111115→DECROU→1.1111111111112 1.99999999999999→DECROU→2.0 '''2.関数1''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:200},{BSIZE:1 0} ,ラベル,アドレス,機能,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,COS,2993H,DAC ← COS(DAC),すべて ,SIN,29ACH,DAC ← SIN(DAC),すべて ,TAN,29FBH,DAC ← TAN(DAC),すべて ,ATN,2A14H,DAC ← ATN(DAC),すべて ,LOG,2A72H,DAC ← LOG(DAC),すべて ,SQR,2AFFH,DAC ← SQR(DAC),すべて ,EXP,2B4AH,DAC ← EXP(DAC),すべて ,RND,2BDFH,DAC ← RND(DAC),すべて ,INT,30CFH,DAC ← INT(DAC),すべて ,{SIZE:100|CENTER}注意 すべて、BASICにおける同名の関数の処理ルーチン。 変化するレジスタすべてとは、A、B、C、D、E、H、Lの各レジスタを指す。 '''3.関数2''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:200},{BSIZE:1 0} ,ラベル,アドレス,機能,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,SIGN ,2E71H,A ← DAC の符号,A ,ABSFN ,2E82H,DAC ← ABS(DAC),すべて ,NEG ,2E8DH,DAC ← NEG(DAC),"A、H、L" ,SGN ,2E97H,DAC ← SGN(DAC),"A、H、L" '''4.移動''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:150},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,機能,対象,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,MAF ,2C4DH,ARG ← DAC ,倍精度,"A、B、D、E、H、L" ,MAM ,2C50H,ARG ← [HL] ,倍精度,"A、B、D、E、H、L" ,MOV8DH ,2C53H,[DE] ← [HL] ,倍精度,"A、B、D、E、H、L" ,MFA ,2C59H,DAC ← ARG ,倍精度,"A、B、D、E、H、L" ,MFM ,2C5CH,DAC ← [HL] ,倍精度,"A、B、D、E、H、L" ,MMF ,2C67H,[HL] ← DAC ,倍精度,"A、B、D、E、H、L" ,MOV8HD ,2C6AH,[HL] ← [DE] ,倍精度,"A、B、D、E、H、L" ,XTF ,2C6FH,[SP] ←→ DAC ,倍精度,"A、B、D、E、H、L" ,PHA ,2CC7H,ARG → [SP] ,倍精度,"A、B、D、E、H、L" ,PHF ,2CCCH,DAC → [SP] ,倍精度,"A、B、D、E、H、L" ,PPA ,2CDCH,[SP] → ARG ,倍精度,"A、B、D、E、H、L" ,PPF ,2CE1H,[SP] → DAC ,倍精度,"A、B、D、E、H、L" ,PUSHF ,2EB1H,DAC → [SP] ,単精度,"D、E" ,MOVFM ,2EBEH,DAC ← [HL] ,単精度,"B、C、D、E、H、L" ,MOVFR ,2EC1H,DAC ← (CBED) ,単精度,"D、E" ,MOVRF ,2ECCH,(CBED) ← DAC ,単精度,"B、C、D、E、H、L" ,MOVRMI ,2ED6H,(CBED) ← [HL],単精度,"B、C、D、E、H、L" ,MOVRM ,2EDFH,(BCDE) ← [HL],単精度,"B、C、D、E、H、L" ,MOVMF ,2EE8H,[HL] ← DAC ,単精度,"B、C、D、E、H、L" ,MOVE ,2EEBH,[HL] ← [DE] ,単精度,"B、C、D、E、H、L" ,VMOVAM ,2EEFH,ARG ← [HL] ,VALTYP,"B、C、D、E、H、L" ,MOVVFM ,2EF2H,[DE] ← [HL] ,VALTYP,"B、C、D、E、H、L" ,VMOVE ,2EF3H,[HL] ← [DE] ,VALTYP,"B、C、D、E、H、L" ,VMOVFA ,2F05H,DAC ← ARG ,VALTYP,"B、C、D、E、H、L" ,VMOVFM ,2F08H,DAC ← [HL] ,VALTYP,"B、C、D、E、H、L" ,VMOVAF ,2F0DH,ARG ← DAC ,VALTYP,"B、C、D、E、H、L" ,VMOVMF ,2F10H,[HL] ← DAC ,VALTYP,"B、C、D、E、H、L" ,{SIZE:100|CENTER}注意 [HL]、[DE]は、それぞれHL、DEレジスタが指したメモリ上の数値を示す。 ()内の4レジスタ名は、左から(符号+指数部)、(仮数部1、2桁)、(仮数部3、4桁)、(仮数部5、6桁)を示す単精度実数である。 移動の対象がVALTYPとなっているものは、【VALTYP(F663H)】に示されている型に応じた移動(2、4、8バイト)を行う。 '''5.比較''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,対象,左辺,右辺,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,FCOMP ,2F21H,単精度実数 ,CBED ,DAC ,HL ,ICOMP ,2F4DH,2バイト整数,DE ,HL ,HL ,XDCOMP ,2F5CH,倍精度実数 ,ARG ,DAC ,すべて ,{SIZE:100|CENTER}注意 結果はすべて A レジスタに入る。レジスタの意味は、 A=1 → 左辺 < 右辺 A=0 → 左辺 = 右辺 A=-1 → 左辺 > 右辺 単精度の比較で、左辺のCBEDとは各レジスタに、それぞれ単精度の(符号+指数部)、(仮数部1、2桁)、(仮数部3、4桁)、(仮数部5、6桁)が入ることを意味する。 {{br}} '''6.浮動小数点入出力''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,機能 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,FIN,3299H,浮動小数点を表す文字列を実数表現に変換して、DACに格納する。 ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,HL,文字列の先頭アドレス ,{SIZE:100|CENTER}戻り値 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,DAC ,実数 ,C ,FFH = 小数点なし、0 = 小数点あり ,B ,小数点以降の桁数 ,D ,総桁数 ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,機能 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,FOUT ,3425H,DACに入っている実数表現の数を文字列に変換する(フォーマット指定なし) ,PUFOUT,3426H,DACに入っている実数表現の数を文字列に変換する(フォーマット指定あり) ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0|SIZE:70},{BSIZE:0} ,A,変換のフォーマット{COLS:2}, , ,bit7,"0=フォーマット指定なし、1=フォーマット指定あり " , ,bit6,"0=カンマ(,)による区切りなし、1=3ごとにカンマ(,)で区切る" , ,bit5,"0=意味無し、1=先頭のスペースを「*」で埋める " , ,bit4,"0=意味無し、1=数値の前に「$」をつける " , ,bit3,"0=意味無し、1=正の場合も符号「+」をつける " , ,bit2,"0=意味無し、1=数値の後ろに符号をつける " , ,bit1,"未使用 " , ,bit0,"0=固定小数点、1=浮動小数点 " ,B,小数点を含まない、小数点以前の桁数{COLS:2}, ,C,小数点を含む、小数点以降の桁数{COLS:2}, ,{SIZE:100|CENTER}戻り値 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,HL,文字列の先頭アドレス ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0} ,ラベル,アドレス,機能 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,FOUTB,371AH,"DAC+2、+3に入っている2バイト整数を2進表現の文字列に変換する" ,FOUTO,371EH,"DAC+2、+3に入っている2バイト整数を8進表現の文字列に変換する" ,FOUTH,3722H,"DAC+2、+3に入っている2バイト整数を16進表現の文字列に変換する" ,{SIZE:100|CENTER}コール手順 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:120},{BSIZE:0} ,DAC+2 ,2バイト整数 ,VALTYP,2 ,{SIZE:100|CENTER}戻り値 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:120},{BSIZE:0} ,HL,文字列の先頭アドレス ,{SIZE:100|CENTER}注意 レジスタはいずれも保存されない。 出力ルーチンにおける文字列先頭アドレスは、通常、【FBUFFR(F7C5H〜)】内となるが、場合により先頭アドレスは前後する。 FOUTB、FOUTO、FOUTHに限らずDAC+2に入れた整数を扱うときには、【VALTYP(F663H番地)】に必ず「2」を入れなければならない。 '''7.型変換''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:300},{BSIZE:1 0} ,ラベル,アドレス,機能 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,FRCINT ,2F8AH,DACを2バイト整数にする (DAC+2、+3) ,FRCSNG ,2FB2H,DACを単精度実数にする ,FRCDBL ,303AH,DACを倍精度実数にする ,FIXER ,30BEH,DAC←SGN(DAC)×INT(ABS(DAC)) ,{SIZE:100|CENTER}注意 実行後【VALTYP(F663H)】にはDACの型を表す数(2、4、8)が入る。 レジスタはいずれも保存されない。 '''8.整数演算''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:120},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:280},{BSIZE:1 0} ,ラベル,アドレス,機能,変化するレジスタ ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,UMULT,314AH,DE←BC×DE,"A、B、C、D、E" ,ISUB ,3167H,HL←DE-HL,すべて ,IADD ,3172H,HL←DE+HL,すべて ,IMULT,3193H,HL←DE×HL,すべて ,IDIV ,31E6H,HL←DE÷HL,すべて ,IMOD ,323AH,HL←DE mod HL (DE ← DE/HL),すべて ,{SIZE:100|CENTER}注意 ISUB、IADD、IMULT、IDIV、IMODについては、演算結果はDAC+2にも入る。 '''9.べき乗''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:90},{BSIZE:1 0|SIZE:250},{BSIZE:1 0|SIZE:70},{BSIZE:1 0|SIZE:70},{BSIZE:1 0|SIZE:70} ,ラベル,アドレス,機能,基数,指数,結果 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,SNGEXP,37C8H,単精度実数のべき乗を求める ,DAC,ARG,DAC ,DBLEXP,37D7H,倍精度実数のべき乗を求める ,DAC,ARG,DAC ,INTEXP,383FH,2バイト整数のべき乗を求める,DE ,HL ,DAC ,{SIZE:100|CENTER}注意 レジスタは、いずれも保存されない。 !6.3.3 Math-PackをMSX-DOS上のプログラムから使用する方法  Math-Packはその本体の大部分はPage 0にありますが、一部のルーチンがPage 1にあるために、MSX-DOSからコールした場合に正しい計算ができません。  それを回避するためには、以下のようにします。 '''リスト2.11 Math-PackをDOS環境で使用する方法''' 406fh、4666h、4eb8h、5439hにそれぞれ以下のルーチンを置く。 calbas equ 0159h ; ; at 406fh ; ld ix,406f jp calbas ; ; at 4666h ; ld ix,4666 jp calbas ; ; at 4eb8h ; ld ix,4eb8 jp calbas ; ; at 5439h ; ld ix,5439h jp calbas 5597hに以下のルーチンを置く。 ; ; at 5597h ; getypr: ld a,(valtyp) cp 8 jr nc,double sub 3 or a scf ret ; double: sub 3 or a ret 66a7hに以下のルーチンを置く。 ; ; at 66a7h ; ppswrt: pop af ret !!6.4 MSX 漢字ドライバ  MSX漢字ドライバは、BASICやDOSで統一的に日本語入出力を行うためのシステムソフトウェアです。 !6.4.1 特徴  MSX漢字ドライバには以下のような特長があります。 +BIOSを使って文字の入出力をしているソフトウェアであれば、プログラムを変更しないで漢字の入出力ができる。 +テキスト画面で、文字ごとに色を変えることができる。 +JIS第二水準の漢字をサポートしている。 +漢字プリンタへの漢字出力をサポートしている。 +MSX-JE(MSX日本語フロントエンドプロセッサ)がなくても、単漢字変換機能で漢字の入力ができる。 +グラフィック画面に対し、LOCATE文やPRINT文で文字の表示ができる。 !6.4.2 注意点 '''1.PRINT文'''  MSX漢字ドライバでは、グラフィック画面に対して、PRINT文を使って文字を表示することができますが、以下の点を注意しなければなりません。 +LOCATE文で指定するカーソルポジションは、半角の文字単位です。 +カーソルポジションを保存しているワークエリアはひとつしかないので、SET PAGE命令でアクティブページを変更しながらPRINTすると、ほかのページで変更したカーソルポジションに続きに文字が表示されます。 +インタレースモード(KANJI2、KANJI3)で文字を表示する際には、SCREEN文でEVEN/ODDのインタレースモード(SCREEN ,,,,,3)に設定して、SET PAGE文で表示ページを奇数ページに、アクティブページを表示ページ-1に設定しなければなりません。 '''2.SCREEN文'''  従来は、SCREENモードを変更しただけでは、スプライト表示禁止ビット(VDPレジスタ8)やインタレースモード(VDPレジスタ9)は変化しませんでしたが、漢字モードでは両方ともクリアされます。ただし、インタレースモードはSCREEN文の第6パラメータを同時に指定した場合は、正しく設定されます。 '''3.ユーザーエリア'''  MSX-JEが実装されているシステムで、CALL KANJI命令を実行すると、MSX-JE用のワークエリアが確保されます。一度確保されたMSX-JE用のワークエリアはたとえ、CALL ANK命令を実行した場合でも解放することはできません。  そのため、アプリケーションプログラムによっては、メモリ不足のために漢字モードから起動できないものがあるかもしれません。その場合は、一度リセットしてANKモードで起動してください。  なお、確保されるワークエリアの大きさは、フロントエンドプロセッサによって異なります。 !6.4.3 拡張BIOS  漢字ドライバは、アプリケーションソフトウェアからその機能の一部を使用できるように、拡張BIOSを準備しています。MSX漢字ドライバの拡張BIOSでは、現在の画面モードを返したり、画面を希望するモードに変更できます。  漢字はいち文字出力のBIOSコールや、BIOSのCHPUTをコールして表示します。 '''1.拡張BIOSの使用法'''  MSX漢字ドライバの拡張BIOSは以下の手順で使用します。  スタックポインタは0C000H番地以上を指すようにしてください。 +DレジスタにMSX漢字ドライバのデバイス番号である11Hを、Eレジスタに拡張BIOSファンクション番号を入れる。 +Eレジスタにセットした拡張BIOSファンクションに必要なレジスタの設定を行う。 +0FFCAHをコールする。 !6.4.4 拡張BIOSファンクション ::モードの取得 ,{SIZE:100|CENTER}機能 現在の画面モードを数値で返します。 ,{SIZE:100|CENTER}入力 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,E,0(モードの取得) ,A,インストール検出(下記参照) ,{SIZE:100|CENTER}出力 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,A ,モード , ,0=ANK , ,1=KANJI0 , ,2=KANJI1 , ,3=KANJI2 , ,4=KANJI3 ,{SIZE:100|CENTER}解説 漢字ドライバがインストールされていない場合は[A]が不変で返ってきます。これを利用して、[A]を0FFHにして呼ぶことにより、漢字ドライバがそもそもインストールされているのか否かが判ります。単にモードが知りたいだけなら、[A]を0にして呼んでください。 ::モードの設定 ,{SIZE:100|CENTER}機能 画面モードを設定します。 ,{SIZE:100|CENTER}入力 ,{t},{BSIZE:0} ,{c},{BSIZE:0|SIZE:60},{BSIZE:0} ,E,1(モードの設定) ,A,モード , ,0=ANK , ,1=KANJI0 , ,2=KANJI1 , ,3=KANJI2 , ,4=KANJI3 ,{SIZE:100|CENTER}出力 なし ,{SIZE:100|CENTER}解説 スクリーンを指定されたモードに設定します。漢字ドライバがインストールされていないと無視されます。 !!6.5 漢字ROM !6.5.1 漢字ROMのI/Oサポート  漢字ROMは以下のI/Oポートに接続されています。 '''表2.21 漢字ROMとI/Oポート''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:100},{BSIZE:1 0|SIZE:160},{BSIZE:1 0|SIZE:160},{BSIZE:1 0} ,アドレス,用途,IN,OUT ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,第1水準, , , ,0D8H ,第1水準漢字ROM{ROWS:2},フォントデータ{ROWS:2},漢字番号の下位6ビット ,0D9H , , ,漢字番号の上位6ビット ,第2水準, , , ,0DAH ,第2水準漢字ROM{ROWS:2},フォントデータ{ROWS:2},漢字番号の下位6ビット ,0DBH , , ,漢字番号の上位6ビット !6.5.2 フォントデータの読み出し  MSXの漢字ROMは、読み出したい文字の漢字番号を1回設定した後、32回I/Oポートを読み出すとデータを獲得できます。内部にアドレスカウンタを持っているので、番号を変えてフォントデータを読み込む必要はありません。 '''1.漢字番号の計算方法''' ,{t},{BSIZE:2 0} ,{c},{BSIZE:1 0|SIZE:100},{BSIZE:1 0|SIZE:70},{BSIZE:1 0|SIZE:170} , ,区,漢字番号 ,{c},{BSIZE:0},{BSIZE:0},{BSIZE:0} ,第一水準{TOP},〜15 ,(区×96+点) , ,16〜 ,(区×96+点-512) ,{c},{BSIZE:1 0},{BSIZE:1 0},{BSIZE:1 0} ,第二水準{TOP},(区-48)×96+点){COLS:2},  フォントイメージの並び方は8バイトごとに、左上、右上、右下、右下、の順です。  また、MSXの漢字ROM仕様では、フォントの形は決まっていません。フォントパターンは各メーカーによって異なっています。しかし、MSXの漢字ROM仕様では、ある特定のフォントのパターンを規定しており、そのパターンの有無をチェックすることにより、漢字ROMがシステムに実装されているかどうかの判断を行います。  JISの句点コードで規定されていない部分は統一されていません。 '''2.第一水準漢字ROMのチェック'''  第一水準では、JISコード2140H(1区32点)の左上部分が、次のようなフォントになっています。 ○○○○○○○○ ○●○○○○○○ ○○●○○○○○ ○○○●○○○○ ○○○○●○○○ ○○○○○●○○ ○○○○○○●○ ○○○○○○○● '''3.第二水準漢字ROMのチェック'''  第二水準では、JISコード737EH(83区94点)の漢字(○の中に■)の始め8バイトのデータのチェックサムが95Hになるようになっています。 例 01 02 0C 37 C0 3B 2A 2A '''リスト2.12 第二水準漢字ROM実装のチェックプログラム''' ; ; 第二水準漢字ROMが実装されているかどうかを調べるルーチン ; .Z80 ; ; followings are definitions of Kanji ROM port addresses ; kan2w0 defl 0dah ; Kanji ROM port address of lower 6bit kan2w1 defl 0dbh ; Kanji ROM port address of higher 6bit kan2rd defl 0dbh ; Kanji ROM port address of data read ; ; このプログラムは、JISコードの737EH(83区94点)のフォントデータのうち、 ; 最初の8バイトを呼んで、チェックサムを計算します。そして、その値が95H ; であれば、Zフラグをセットしてリターンします。 ; kancod defl 737eh kanval defl 95h ; ; Calculate Kanji ROM address ; romtmp defl kancod-5000h ; Subtract offset of 1st level Knaji code romadd defl (high romtmp) * 96+(low romtmp)-20h romlog defl romadd mod 64 romhi defl romadd/64 kanchk: ld a,romlow ; Low order byte out (kan2w0),a ; Set Kanji ROM lower 6 bit address ld a,romhi ; High order byte out (kan2w1),a ; Set Kanji ROM higher 6 bit address ld c,0 ; Clera check sum accumulator ld b,8 ; Loop count chklop: in a,(kan2rd) ; Read the character data add a,c ; Calculater check sum ld c,a ; loop till all done djnz chklop ; Set zero flag if Kanji ROM found cp kanval ret end !6.5.3 デバイスイネーブル  漢字ROMを内蔵するMSXシステムは、外部スロットから漢字ROMが挿入された場合のバスの競合を避けるために、システムソフトウェアにより内蔵ROMのアクセスを制御しなくてはなりません。つまり、I/OアドレスF55H番地のビット1に0が書き込まれた場合は、外部に漢字ROMが存在することを示しているわけですから、内蔵ROMのアクセスを禁止しなければなりません。 !6.5.4 JISから区点コードへの変換例 '''リスト2.13 JISから区点コードへの変換例''' 10 DEFINT A-Z 20 DIM P(31) 30 'INPUT JIS CODE IN HEX(4 DIGITS) THEN CONVERT TO ROM CODE 40 INPUT N$:L=VAL("&H"+RIGHT$(N$,2)):H=VAL("&H"+LEFT$(N$,2)) 50 N=(H-32)*96+L-32:IF H=>&H30 THEN N=N-512 60 L=N AND 63:H=N\64 70 'ROM CODE OUT 80 OUT &HD8,L 90 OUT &HD9,H 100 PRINT "LOW =";L,"HIGH =";H 110 'GET PATTERN 120 FOR I=0 TO 31 130 P(I)=INP(&HD9) 140 NEXT I 150 'PRINT OUT PATTERN 160 FOR I=0 TO 7 170 P$=RIGHT$("00000000"+BIN$(P(I)),8):GOSUB 250 180 P$=RIGHT$("00000000"+BIN$(P(I+8)),8):GOSUB 250:PRINT 190 NEXT 200 FOR I=16 TO 23 210 P$=RIGHT$("00000000"+BIN$(P(I)),8):GOSUB 250 220 P$=RIGHT$("00000000"+BIN$(P(I+8)),8):GOSUB 250:PRINT 230 NEXT 240 GOTO 40 250 FOR J=1 TO 8 260 IF MID$(P$,J,1)="0" THEN PRINT " "; ELSE PRINT "*"; 270 NEXT J 280 RETURN !6.5.5 シフトJISからJISへの変換例  ファイル上で上位(変数H)、下位(変数L)の順番に2バイトづつデータが入っている場合、 '''リスト2.14 シフトJISからJISへの変換例''' 100 IF &H80<=H AND H<&HA0 THEN H=H-&H70:GOTO 130 110 IF &HE0<=H AND H<&HF0 THEN H=H-&HB0:GOTO 130 120 GOTO 160 130 H=H+H:IF L>=&H80 THEN L=L-1 140 IF L<&H9E THEN H=H-1 ELSE L=L-&H5E 150 L=L-&H1F 160 REN End conversion の方法を取り、HとLを16進4桁の上位、下位に変換する。 !6.5.6 サンプルプログラム  添付のフロッピーディスクに、漢字ROMをアクセスするためのサンプルプログラム(ファイル名「KANJIROM.MAC」が入っています。 ,{t},{BSIZE:1 0|SIZE:100%} ,{BSIZE:0}←[[5章 マシン語とのリンク]] ,{BSIZE:0|RIGHT}[[7章 プログラム開発の諸注意]] →