漢字ROM
漢字ROM
PC-9801はDOS/Vと異なり漢字(全角文字)のフォントはROMで持っています。といいますか、漢字ROMがなくてファイルからフォントを読むようになったのは、パソコンのハードディスクやメモリーの容量が上がったDOS/V(DOS5.0/V)が登場して以降であり、それ以前のPCでは普通はフォントはROMで持ってました。
現在、Windowsで多国語表示が可能なのは、各国の言語のフォントを都度ファイルから読み込む事が可能なためですが、昔のPCはハードディスクは搭載されていないか、あっても容量が少ない(20Mから100Mぐらい)ので、フォントにそんなにディスク容量を食うわけにもいかなかったのでした。
おまけにPC-9801初期の頃は今のようにRAMを多く搭載しておらず、貴重なRAMをフォントのために使うわけにもいきませんでした。
現在、Windowsで多国語表示が可能なのは、各国の言語のフォントを都度ファイルから読み込む事が可能なためですが、昔のPCはハードディスクは搭載されていないか、あっても容量が少ない(20Mから100Mぐらい)ので、フォントにそんなにディスク容量を食うわけにもいかなかったのでした。
おまけにPC-9801初期の頃は今のようにRAMを多く搭載しておらず、貴重なRAMをフォントのために使うわけにもいきませんでした。
普通の全角文字
普通の全角文字とは、つまり、外字や特殊記号以外の全角文字の事です。
7620H~7FFFH 外字
2B21H~2F7EH 特殊記号
この2つは読み出し方が普通の全角文字とは異なるので後ほど別に説明します。
まず、外字または特殊記号かどうかを判別します。
7620H~7FFFH 外字
2B21H~2F7EH 特殊記号
この2つは読み出し方が普通の全角文字とは異なるので後ほど別に説明します。
まず、外字または特殊記号かどうかを判別します。
; 全角文字の場合 MOV AH,[MOJI1] MOV AL,[MOJI2] MOV BX,AX ; 外字なら半分ずつ出す CMP BX,7620H JB PUTK1_1 CMP BX,7FFFH JA PUTK1_1 JMP GAIJI ; 特殊記号なら半分ずつ出す PUTK1_1 = $ CMP BX,2B21H JB PUTK1_2 CMP BX,2F7EH JA PUTK1_2 JMP GAIJI PUTK1_2 = $
外字または特殊記号ならばGAIJIというラベルのルーチンに行きます。(後述)
ここでは、普通の全角文字の処理、PUTK1_2について説明します。モードレジスタ(68H)にドットアクセスモードを指示します。
68H モードレジスタ
モードレジスタは、ビット7~4は常に0、ビット3~1に設定するモード、ビット0に設定値を指定します。
たとえば、ドットアクセスモードにするためには、00001011B=1+2+8=11=0BHをセットします。コードアクセスモードにすると、走査線が画面にない時を狙って漢字ROMを読まないといけなくなります。その方が画面が一瞬乱れなくて良いのですが、タイミングを誤るとフリーズしてしまう危険があるので、ここではドットアクセスモードにしています。
次にフォントのどの部分を取得するかを指定します。
A5H ラインカウンタ
次に、A1H、A3Hに漢字コードをセットします。
EGC搭載機種ではない場合はI/Oポート(A9H)から読みます。I/Oポートから読む場合は8ビットずつしか読めないので、ラインカウンタ(A5H)に「上からn番目」「右」という風に指定して8ビットずつ読むわけですが、これは非常に低速です。
そこで、ここでは対応機種を「PC-9801UX/VX以降」という事にして、CGウィンドウから読み出します。OFFSET KANPATにフォントパターンを格納する32バイトが確保されているものとします。CGウィンドウ(A4000H~A4FFFH)にフォントパターンがセットされるので、ここからフォントを読み出します。普通の全角文字の場合、「右半分」を指定すれば左右どちらもまとめて取得できます。なので、ここでは「右半分」を指定します。
先ほどのサンプルの続きです。BXレジスターに取得する漢字コード(JISコード)が入ってるものとします。
ここでは、普通の全角文字の処理、PUTK1_2について説明します。モードレジスタ(68H)にドットアクセスモードを指示します。
68H モードレジスタ
ビット7~4 | ビット3~1 | ビット0 | 意味 |
---|---|---|---|
0000 | 000 | 1 | 簡易グラフ |
0 | バーティカルライン | ||
0000 | 001 | 1 | モノクロ |
0 | カラー | ||
0000 | 010 | 1 | 40行 |
0 | 80行 | ||
0000 | 011 | 1 | 7x13 |
0 | 6x8 | ||
0000 | 100 | 1 | 200ライン |
0 | 400ライン | ||
0000 | 101 | 1 | ドットアクセスモード |
0 | コードアクセスモード | ||
0000 | 110 | 1 | 不揮発メモリ ライト不可 |
0 | 不揮発メモリ ライト可 | ||
0000 | 111 | 1 | 画面表示する |
0 | 画面表示しない |
たとえば、ドットアクセスモードにするためには、00001011B=1+2+8=11=0BHをセットします。コードアクセスモードにすると、走査線が画面にない時を狙って漢字ROMを読まないといけなくなります。その方が画面が一瞬乱れなくて良いのですが、タイミングを誤るとフリーズしてしまう危険があるので、ここではドットアクセスモードにしています。
次にフォントのどの部分を取得するかを指定します。
A5H ラインカウンタ
ビット | 意味 |
---|---|
7~6 | 未使用(常に0) |
5 | 1: 左半分 0: 右半分 |
4 | 未使用(常に0) |
0~3 | 上から何ライン目を読むか |
次に、A1H、A3Hに漢字コードをセットします。
I/Oポート | 意味 |
---|---|
A1H | JISコード下位バイト |
A3H | JISコードの上位バイトから20Hを引いたもの |
EGC搭載機種ではない場合はI/Oポート(A9H)から読みます。I/Oポートから読む場合は8ビットずつしか読めないので、ラインカウンタ(A5H)に「上からn番目」「右」という風に指定して8ビットずつ読むわけですが、これは非常に低速です。
I/Oポート | 意味 |
---|---|
A9H | READ: フォントパターン読み出し WRITE: 外字登録 |
そこで、ここでは対応機種を「PC-9801UX/VX以降」という事にして、CGウィンドウから読み出します。OFFSET KANPATにフォントパターンを格納する32バイトが確保されているものとします。CGウィンドウ(A4000H~A4FFFH)にフォントパターンがセットされるので、ここからフォントを読み出します。普通の全角文字の場合、「右半分」を指定すれば左右どちらもまとめて取得できます。なので、ここでは「右半分」を指定します。
先ほどのサンプルの続きです。BXレジスターに取得する漢字コード(JISコード)が入ってるものとします。
PUTK1_2 = $ MOV AL,0BH OUT 68H,AL MOV AL,00000000B OUT 0A5H,AL MOV AL,BH SUB AL,20H OUT 0A3H,AL MOV AL,BL OUT 0A1H,AL PUSH ES MOV AX,0A400H MOV ES,AX MOV CX,16 MOV SI,0 MOV DI,OFFSET KANPAT PUTK1B = $ MOV AX,ES:[SI] MOV [DI],AX ADD SI,2 ADD DI,2 LOOP PUTK1B POP ES MOV AL,0AH OUT 68H,AL
最後に68Hに0AHを入れてコードアクセスモードにします。ドットアクセスモードでは画面上の漢字がグラフィックキャラクターに化けてしまうので、ドットアクセスモードにするのは必要最小限の一瞬だけにしましょう。
外字、特殊記号
外字や特殊記号は、どういうわけかCGウィンドウに半分ずつしか現れてくれないので、右半分、左半分の2回に分けて読みます。
;--------外字の場合 GAIJI = $ MOV AL,0BH OUT 68H,AL ; 左 MOV AL,00100000B OUT 0A5H,AL MOV AL,BH SUB AL,20H OUT 0A3H,AL MOV AL,BL OUT 0A1H,AL PUSH ES MOV AX,0A400H MOV ES,AX MOV CX,16 MOV SI,0 MOV DI,OFFSET KANPAT GPUTK1B = $ MOV AL,ES:[SI+1] MOV [DI],AL ADD SI,2 ADD DI,2 LOOP GPUTK1B POP ES ; 右 MOV AL,00000000B OUT 0A5H,AL MOV AL,BH SUB AL,20H OUT 0A3H,AL MOV AL,BL OUT 0A1H,AL PUSH ES MOV AX,0A400H MOV ES,AX MOV CX,16 MOV SI,0 MOV DI,OFFSET KANPAT GPUTK1C = $ MOV AL,ES:[SI+1] MOV [DI+1],AL ADD SI,2 ADD DI,2 LOOP GPUTK1C POP ES MOV AL,0AH OUT 68H,AL
外字登録
外字を登録しておくと、テキスト画面に外字が表示されます。
ATOKの外字(JFGAIJ.UFO)を使っている場合、外字は自前のルーチンで登録しなくても、一瞬ATOKをオンにしてからオフにすれば自動的にATOKの方で登録してくれます。 PC-9801用のATOK8は、J-3100用と同じAPIを使う事が出来ます。詳しくはOOh!Dynaのコーナーにある「ATOKのAPI」を参考にしてください。この場合、画面右下に一瞬だけ「あ連R漢」と出てしまうのがカッコ悪いのですが、プログラムの頭に一瞬だけ出すようにすれば大丈夫でしょう。エンドユーザーもあまり気にしないでいただけるとありがたいです。
え?無理?気になる?右下に一瞬だけ「あ連R漢」と出るのは許せない?というか、そもそもATOKを使ってない?という時は仕方なく自前ルーチンで外字パターンを登録します。
ちなみに、PC-9801用のATOK7を、MS-DOS6.2で動かすと、外字登録時(つまり、初回ATOK起動時)にフリーズする場合があります。おそらくコードアクセスモードで登録を行っていて、VSYNCのタイミングがうまく取れてないのだと思います。そのため、PC-9801用のATOK8は画面が一瞬乱れるのを覚悟で、ドットアクセスモードで外字登録を行っているようです。
このようにコードアクセスモードにすると、走査線が画面にない時を狙って外字登録をしないと、ATOK7みたいに時折フリーズするようになってしまいます。しかし、そのタイミングを計るのは非常に難しく、ATOK7ですらフリーズさせてしまうほどです。そのため、ここではドットアクセスモードで行いましょう。
A5H ラインカウンタ
次に、A1H、A3Hに漢字コードをセットします。
I/Oポートを使って外字登録する場合、ラインカウンタ(A5H)に右半分・左半分の区別、上から何ライン目かを指定し、A1HにJISコードの下位バイト、A3HにJISコードの上位バイトから20Hを引いたものをセットして、A9Hにフォントパターンを1バイトWriteします。
この場合、1バイトずつラインカウンタをセットしてはA9HにWriteしなければならず面倒です。
そこで、BIOSを使って外字登録することもできます。BX:CXレジスタにフォントパターンのアドレス(セグメント:BX、オフセット:CX)、DXレジスタにJISコード、AHレジスタに1AHを入れてINT 18Hを呼びます。ただし、フォントパターンの最初の2バイトはワークエリアとして内部的に使いますので、先頭2バイトには0000Hを入れておいて、その次からの32バイトにフォントパターンを置きます。つまり、フォントデーターは34バイト必要です。
AH=1AH INT 18H 外字登録
終わったら、最後に68Hに0AHを入れてコードアクセスモードにします。ドットアクセスモードでは画面上の漢字がグラフィックキャラクターに化けてしまうので、ドットアクセスモードにするのは必要最小限の一瞬だけにしましょう。
ATOKの外字(JFGAIJ.UFO)を使っている場合、外字は自前のルーチンで登録しなくても、一瞬ATOKをオンにしてからオフにすれば自動的にATOKの方で登録してくれます。 PC-9801用のATOK8は、J-3100用と同じAPIを使う事が出来ます。詳しくはOOh!Dynaのコーナーにある「ATOKのAPI」を参考にしてください。この場合、画面右下に一瞬だけ「あ連R漢」と出てしまうのがカッコ悪いのですが、プログラムの頭に一瞬だけ出すようにすれば大丈夫でしょう。エンドユーザーもあまり気にしないでいただけるとありがたいです。
え?無理?気になる?右下に一瞬だけ「あ連R漢」と出るのは許せない?というか、そもそもATOKを使ってない?という時は仕方なく自前ルーチンで外字パターンを登録します。
ちなみに、PC-9801用のATOK7を、MS-DOS6.2で動かすと、外字登録時(つまり、初回ATOK起動時)にフリーズする場合があります。おそらくコードアクセスモードで登録を行っていて、VSYNCのタイミングがうまく取れてないのだと思います。そのため、PC-9801用のATOK8は画面が一瞬乱れるのを覚悟で、ドットアクセスモードで外字登録を行っているようです。
このようにコードアクセスモードにすると、走査線が画面にない時を狙って外字登録をしないと、ATOK7みたいに時折フリーズするようになってしまいます。しかし、そのタイミングを計るのは非常に難しく、ATOK7ですらフリーズさせてしまうほどです。そのため、ここではドットアクセスモードで行いましょう。
A5H ラインカウンタ
ビット | 意味 |
---|---|
7~6 | 未使用(常に0) |
5 | 1: 左半分 0: 右半分 |
4 | 未使用(常に0) |
0~3 | 上から何ライン目を登録するか |
次に、A1H、A3Hに漢字コードをセットします。
I/Oポート | 意味 |
---|---|
A1H | JISコード下位バイト |
A3H | JISコードの上位バイトから20Hを引いたもの |
I/Oポートを使って外字登録する場合、ラインカウンタ(A5H)に右半分・左半分の区別、上から何ライン目かを指定し、A1HにJISコードの下位バイト、A3HにJISコードの上位バイトから20Hを引いたものをセットして、A9Hにフォントパターンを1バイトWriteします。
I/Oポート | 意味 |
---|---|
A9H | READ: フォントパターン読み出し WRITE: 外字登録 |
この場合、1バイトずつラインカウンタをセットしてはA9HにWriteしなければならず面倒です。
そこで、BIOSを使って外字登録することもできます。BX:CXレジスタにフォントパターンのアドレス(セグメント:BX、オフセット:CX)、DXレジスタにJISコード、AHレジスタに1AHを入れてINT 18Hを呼びます。ただし、フォントパターンの最初の2バイトはワークエリアとして内部的に使いますので、先頭2バイトには0000Hを入れておいて、その次からの32バイトにフォントパターンを置きます。つまり、フォントデーターは34バイト必要です。
AH=1AH INT 18H 外字登録
レジスタ | 意味 |
---|---|
AH | 1AH |
BX:CX | フォントパターンのアドレス +0+1 0000Hをセット +2~+33 外字フォントパターン(32バイト) |
DX | 登録するJISコード(7621H~767EH、7721H~777EH) |
終わったら、最後に68Hに0AHを入れてコードアクセスモードにします。ドットアクセスモードでは画面上の漢字がグラフィックキャラクターに化けてしまうので、ドットアクセスモードにするのは必要最小限の一瞬だけにしましょう。
半角文字
半角文字は、A3Hにアスキーコード、A1Hに00Hを入れて、A5Hに右半分を指定します。CGウィンドウには右半分の部分にフォントが現れます。ただし、ここで注意しなければならないのは、ANKのフォントはドットアクセスモードでは読めないという事です。
つまり、ANKのフォントコードアクセスにして、走査線が画面にない時を狙って読み出さなければならないという事です。具体的には、I/Oポートの60Hを読んでビット5が0のタイミングでしか読めないという事です。これは非常に低速です。1文字や2文字ならそれでも良いのですが、全ての半角フォントを読みたい場合、その間にユーザーを待たせてしまう事になってしまいます。そんな事をしたらユーザーから「フリーズしてしまった」「バグではないのか?」などなどクレームが山のように来る事間違いなしです。
そこで、半角文字フォントは別途吸い出しプログラムを作っておき、イントール時に吸い出してファイルとして取っておいて、使う時はそのプログラムの先頭でファイルから読んでメモリーに入れておく方が良いでしょう。さいわい半角フォントは数が少ないので、全てのフォントをメモリーに読み込んでもコンベンショナルメモリーが溢れる心配はないはずです。
え?いちいちインストール時にフォントを吸い出すルーチンを走らせるのが面倒?フロッピーベースで使えない?インストール時にその作業を忘れたらどうするって?そ、それは・・・
つまり、ANKのフォントコードアクセスにして、走査線が画面にない時を狙って読み出さなければならないという事です。具体的には、I/Oポートの60Hを読んでビット5が0のタイミングでしか読めないという事です。これは非常に低速です。1文字や2文字ならそれでも良いのですが、全ての半角フォントを読みたい場合、その間にユーザーを待たせてしまう事になってしまいます。そんな事をしたらユーザーから「フリーズしてしまった」「バグではないのか?」などなどクレームが山のように来る事間違いなしです。
そこで、半角文字フォントは別途吸い出しプログラムを作っておき、イントール時に吸い出してファイルとして取っておいて、使う時はそのプログラムの先頭でファイルから読んでメモリーに入れておく方が良いでしょう。さいわい半角フォントは数が少ないので、全てのフォントをメモリーに読み込んでもコンベンショナルメモリーが溢れる心配はないはずです。
え?いちいちインストール時にフォントを吸い出すルーチンを走らせるのが面倒?フロッピーベースで使えない?インストール時にその作業を忘れたらどうするって?そ、それは・・・
終わりに
PC-9801でプログラムを作っていると、漢字ROMへのアクセス1つにしても、PC/AT互換機やJ-3100に比べるとあまりに複雑で、プログラムするのがだんだんと嫌になってきます。一度PC/AT互換機でプログラムを作った人は、もうPC-9801には戻れないでしょう。(もっとも私の場合、PC/AT互換機が先だったわけですが。)
しかし、PC-9801自体がもともとビジネス向けに作られた機種なので、アプリ層からアセンブラでV-RAMやテキストV-RAM、漢字ROMに直接アクセスする事は想定になかったのかもしれません。これは、同じくビジネス向けに設計されたFM-7が、V-RAMへのアクセスが複雑だったり、キースキャンがコントローラーを介さないとできずリアルタイムキースキャンができないのと似ていますね。
しかし、PC-9801自体がもともとビジネス向けに作られた機種なので、アプリ層からアセンブラでV-RAMやテキストV-RAM、漢字ROMに直接アクセスする事は想定になかったのかもしれません。これは、同じくビジネス向けに設計されたFM-7が、V-RAMへのアクセスが複雑だったり、キースキャンがコントローラーを介さないとできずリアルタイムキースキャンができないのと似ていますね。
参考文献
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク
このページの先頭へ
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク
広告