PC-6001初代機では、基本的に0000H-3FFFHは常時ROMになっており、バンク切り替えなどは行われません。
ということは、PC-6001mkIIのモード1でそのアドレスを裏RAMに切り替え、そこにBIOSをコピーしてしまえば、自由にBIOSをカスタマイズできるんじゃね…?
…という思いつきから始まったお遊びです。
※映像はPC-6601実機からキャプチャーしました
P6_BIOSCHG_PCG_Files.zip (2022/12/22)
PC-6001では、グラフィック画面に文字をPRINTする際に、CGROM(キャラクターのパターンデータが格納されたROM)からデータを読んで描画しています。
BIOSを書き換えて、CGROMではなくRAMからパターンデータを読むようにしてしまえば、あたかもPCG機能が搭載されているかのように、PRINT文だけで自由なパターンを表示することができます。
プログラム自体はとても簡単です。たった5行です。
List.1 P6にPCG機能を追加するプログラム(MODE1/PAGE2用)
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5
やっていることは以下の通りです。
BIOSをたった1バイト書き換えているだけですが、このプログラムを実行すると、SCREEN3 または SCREEN4 で文字をPRINTした際に、CGROM内のデータではなく同じアドレスのRAM上のデータを読んで表示するようになります。
つまり、6000H-7FFFH のRAMに任意のパターンデータをセットしてからPRINT文を使うことで、(グラフィック画面限定ですが)通常の文字以外のキャラクターを表示することができるようになる ということです。
PC-6001のフォントは縦12ドットですが、CGROM内のデータは16バイトごとに格納されており(4バイトずつ空きがある)、フォントデータが格納されているアドレスの計算式は &H6000+文字コード*16 となります。
6000H-600BH: CHR$(0) "月" のフォントデータ ( 600CH-600FH: 空き )
6010H-601BH: CHR$(1) "火" のフォントデータ ( 601CH-601FH: 空き )
6020H-602BH: CHR$(2) "水" のフォントデータ ( 602CH-602FH: 空き )
:
6400H-640BH: CHR$(64) "@" のフォントデータ ( 640CH-640FH: 空き )
6410H-641BH: CHR$(65) "A" のフォントデータ ( 641CH-641FH: 空き )
6420H-642BH: CHR$(66) "B" のフォントデータ ( 642CH-642FH: 空き )
:
6FF0H-6FFBH: CHR$(255) のフォントデータ ( 6FFCH-6FFFH: 空き )
例えば、以下のプログラムを実行してみます。
List.2 キャラクターデータを書き換えるテストプログラム(List.1の後に赤い部分を追加)
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5 100 SCREEN 4,2,2:COLOR,,2:CLS 110 PRINT"@" 120 FOR I=0 TO 11:READ A$:POKE&H6400+I,VAL("&H"+A$):NEXT 130 DATA 55,AA,55,AA,55,AA,55,AA,55,AA,55,AA 140 PRINT"@" 150 GOTO 150
するとグラフィック画面には以下のように描画されます。
110行で普通に"@" と表示した後、"@"のパターンデータが格納されている 6400H から 12バイトを書き換え、 140行でもう一度 "@" を表示しているのですが、ご覧の通り、2個目の "@" が "▓" に変わっています。
英数字のフォントをすべて書き換えてみましょう。
List.3 フォントを書き換えるプログラム(List.1の後に赤い部分を追加)
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5 100 REM CHANGE FONT ---------- 110 PRINT"SET FONT "; 120 READ A$:IF A$="END" THEN END 130 IF A$="" THEN A$=CHR$(34) 140 PRINT A$; 150 A=&H6000+ASC(A$)*16 160 FOR I=0 TO 11:B$="00" 170 IF I<8 THEN READ B$ 180 POKE A+I,VAL("&H"+B$) 190 NEXT 200 GOTO 120 990 REM FONT DATA ------------ 1000 DATA" ",00,00,00,00,00,00,00,00 1010 DATA"!",38,38,38,38,10,00,10,00 1020 DATA"" ,6C,6C,00,00,00,00,00,00 1030 DATA"#",4C,4C,FE,4C,FE,4C,4C,00 1040 DATA"$",38,7E,E0,7C,0E,FC,38,00 1050 DATA"%",E2,E4,E8,10,2E,4E,8E,00 1060 DATA"&",7C,E0,E4,7E,E4,E4,78,00 1070 DATA"'",38,38,20,00,00,00,00,00 1080 DATA"(",0E,1C,1C,1C,1C,1C,0E,00 1090 DATA")",E0,70,70,70,70,70,E0,00 1100 DATA"*",10,D6,D6,38,D6,D6,10,00 1110 DATA"+",38,38,38,FE,38,38,38,00 1120 DATA",",00,00,00,00,18,18,10,00 1130 DATA"-",00,00,00,FE,00,00,00,00 1140 DATA".",00,00,00,00,00,18,18,00 1150 DATA"/",02,04,08,10,20,40,80,00 1160 DATA"0",7C,E2,E2,E2,E2,E2,7C,00 1170 DATA"1",3C,1C,1C,1C,1C,1C,1C,00 1180 DATA"2",FC,0E,0E,7C,E0,E0,FE,00 1190 DATA"3",7C,8E,0E,7C,0E,8E,7C,00 1200 DATA"4",3C,5C,9C,9C,9C,FE,1C,00 1210 DATA"5",FE,E0,E0,FC,0E,0E,FC,00 1220 DATA"6",7E,E0,E0,FC,8E,8E,7C,00 1230 DATA"7",FE,8E,9C,1C,38,38,38,00 1240 DATA"8",7C,E2,E2,7C,8E,8E,7C,00 1250 DATA"9",7C,E2,E2,7E,0E,8E,7C,00 1260 DATA":",00,38,38,00,38,38,00,00 1270 DATA";",00,38,38,00,38,38,08,00 1280 DATA"<",0E,1C,38,70,38,1C,0E,00 1290 DATA"=",00,00,7E,00,7E,00,00,00 1300 DATA">",E0,70,38,1C,38,70,E0,00 1310 DATA"?",7C,E2,02,1C,10,00,10,00 1320 DATA"@",FC,02,72,EA,EA,E2,7C,00 1330 DATA"A",7C,8E,8E,8E,FE,8E,8E,00 1340 DATA"B",FC,E2,E2,FC,E2,E2,FC,00 1350 DATA"C",7C,E2,E0,E0,E0,E2,7C,00 1360 DATA"D",FC,8E,8E,8E,8E,8E,FC,00 1370 DATA"E",FE,E0,E0,FC,E0,E0,FE,00 1380 DATA"F",FE,E0,E0,FC,E0,E0,E0,00 1390 DATA"G",7C,8E,80,9E,8E,8E,7C,00 1400 DATA"H",E2,E2,E2,FE,E2,E2,E2,00 1410 DATA"I",38,38,38,38,38,38,38,00 1420 DATA"J",1C,1C,1C,1C,1C,1C,F8,00 1430 DATA"K",E2,E2,E2,FC,8E,8E,8E,00 1440 DATA"L",E0,E0,E0,E0,E0,E0,FE,00 1450 DATA"M",FC,B6,B6,B6,B6,B6,B6,00 1460 DATA"N",FC,8E,8E,8E,8E,8E,8E,00 1470 DATA"O",7C,E2,E2,E2,E2,E2,7C,00 1480 DATA"P",FC,E2,E2,E2,FC,E0,E0,00 1490 DATA"Q",7C,E2,E2,E2,E6,E4,7A,00 1500 DATA"R",FC,E2,E2,FC,8E,8E,8E,00 1510 DATA"S",7C,E2,E0,7C,02,E2,7C,00 1520 DATA"T",FE,38,38,38,38,38,38,00 1530 DATA"U",E2,E2,E2,E2,E2,E2,7C,00 1540 DATA"V",E2,E2,E2,E2,E2,64,38,00 1550 DATA"W",DA,DA,DA,DA,DA,DA,76,00 1560 DATA"X",E2,E2,E2,7C,8E,8E,8E,00 1570 DATA"Y",E2,E2,E2,E2,7C,38,38,00 1580 DATA"Z",FE,E2,02,7C,80,8E,FE,00 1590 DATA"[",3C,42,BD,B1,B1,BD,42,3C 1600 DATA"\",03,04,0B,0B,0B,0B,04,03 1610 DATA"]",C0,20,D0,50,D0,10,20,C0 1620 DATA"^",18,3C,24,24,24,7E,FF,FF 1630 DATA"_",00,30,30,00,00,30,30,00 1650 DATA"a",00,00,7E,8E,8E,8E,6E,00 1660 DATA"b",E0,E0,FC,E2,E2,E2,FC,00 1670 DATA"c",00,00,7C,8E,80,8E,7C,00 1680 DATA"d",0E,0E,7E,8E,8E,8E,7E,00 1690 DATA"e",00,00,7C,8E,9E,80,7E,00 1700 DATA"f",1C,20,7C,38,38,38,38,00 1710 DATA"g",00,00,7E,E2,E2,7E,0E,FE 1720 DATA"h",E0,E0,FC,8E,8E,8E,8E,00 1730 DATA"i",38,00,38,38,38,38,38,00 1740 DATA"j",38,00,38,38,38,38,F8,00 1750 DATA"k",E0,E0,E2,E2,FC,8E,8E,00 1760 DATA"l",38,38,38,38,38,38,38,00 1770 DATA"m",00,00,FC,B6,B6,B6,B6,00 1780 DATA"n",00,00,FC,8E,8E,8E,8E,00 1790 DATA"o",00,00,7C,E2,E2,E2,7C,00 1800 DATA"p",00,00,FC,E2,E2,FC,E0,E0 1810 DATA"q",00,00,7E,8E,8E,7E,0E,0E 1820 DATA"r",00,00,EE,F0,E0,E0,E0,00 1830 DATA"s",00,00,7E,E0,7C,0E,FC,00 1840 DATA"t",08,08,7C,38,38,38,38,00 1850 DATA"u",00,00,E2,E2,E2,E2,7C,00 1860 DATA"v",00,00,E2,E2,E2,64,38,00 1870 DATA"w",00,00,DA,DA,DA,DA,6E,00 1880 DATA"x",00,00,E2,E2,7C,8E,8E,00 1890 DATA"y",00,00,E2,E2,E2,7E,0E,FC 1900 DATA"z",00,00,FE,06,38,C2,FE,00 1910 DATA"END"
このプログラムを実行すると、英数字のフォントが変更されます。
ダイレクトモードで以下のように入力してみてください。
SCREEN 4,2,2:COLOR,,2:PRINT"[\]NAMCO ^_03"
PAGEを切り替えると、見たことのあるフォントが表示されているはずです。
また、グラフィック画面でもLISTコマンドは有効なので、以下のように入力してみてください。
SCREEN 4,2,2:LIST
縦8ドットのフォントなので(内蔵フォントは縦12ドット)、文字の下側の空白が広めですが、カッコイイフォントでリストが流れていくでしょう。
もう少し使いやすくするために、さらにBIOSを書き換えて、1文字のサイズを8x12ドットから8x8ドットに変更してみましょう。
SCREEN4の解像度は256x192ドットなので、表示できるのは 32x24文字、MSXやJRと同じになります。
また、グラフィック画面へのPRINTは、通常は背景に描かれたデータとの重ね合わせ演算を行って表示されますが、演算を行わずにそのまま表示するようにしました。
これによって、PRINT" "のようにスペースを表示するだけでグラフィック画面に描かれた文字を消すことができるようになりますし、若干高速化されます。
List.4 キャラクターサイズを8x8ドットにして背景と重ね合わせを行わないプログラム(List.1の後に赤い部分を追加・青い部分は動作確認用)
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5 60 POKE&H1540,&H77:POKE&H1541,&HC9 70 POKE&H14F5,8:POKE&H121B,4:POKE&H1222,8 80 POKE&H148F,0:POKE&H155F,0 90 POKE&H1CE8,&H37:POKE&H1D86,0:POKE&H2881,0 100 SCREEN 4,2,2:COLOR,,2:CONSOLE 0,24:CLS 110 REM SAMPLE --------- 120 READ A$:IF A$="END" THEN 180 130 A=&H6000+ASC(A$)*16 140 FOR I=0 TO 15:READ B$ 150 POKE A+I,VAL("&H"+B$) 160 NEXT 170 GOTO 120 180 POKE&H14A9,0 190 PRINT"123"; 200 POKE&H14A9,8 210 PRINT"123"; 220 GOTO 180 230 REM CHR -------- NORMAL ------- ------- REVERSE ------- 240 DATA"1",18,78,18,18,18,18,7E,00,E7,87,E7,E7,E7,E7,81,FF 250 DATA"2",7E,66,06,7E,60,60,7E,00,81,99,F9,81,9F,9F,81,FF 260 DATA"3",7E,66,06,1E,06,66,7E,00,81,99,F9,E1,F9,99,81,FF 270 DATA"END"
詳細は以下の通りです。
テープからCGROMのデータをロードするプログラムを載せておきます。
List.5 CGROMデータをテープからロードする
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5 110 FOR I=&HE200 TO &HE215:READ A$:POKE I,VAL("&H"+A$):NEXT 120 DATA CD,61,1A,21,00,60,01,00,10,CD,70,1A,77,23,0B,78 130 DATA B1,20,F6,C3,AA,1A 140 INPUT"READY";I$ 150 PRINT"LOADING CGROM" 160 EXEC&HE200
使い方は以下の通りです。
※Hashiさん作成のオリジナルフォントでテストさせていただきました
SCREEN3でPRINT文を使用すると、パターンデータを横に拡大して表示するなどの処理が行われるため、意図した通りにPCG機能を使うことができません。
そのため、SCREEN3でPCG機能を使いたい場合は、SCREEN4のままアトリビュートエリア(PAGE2ならE000H-E1FFH)に8CH(COLOR,,2にしたければ8EH)を書き込んでください。
List.6 キャラクターサイズを4x8ドットにして背景と重ね合わせを行わないプログラム for SCREEN3(List.4の110行目以降を削除・赤い部分を追加・青い部分は動作確認用)
10 FOR I=&HE200 TO &HE21C:READ A$:POKE I,VAL("&H"+A$):NEXT 20 DATA F3,3E,71,D3,F0,3E,04,D3,93,21,00,00,E5,D1,01,00 30 DATA 80,ED,B0,3E,05,D3,93,3E,DD,D3,F0,FB,C9 40 EXEC&HE200 50 POKE&H14F1,5 60 POKE&H1540,&H77:POKE&H1541,&HC9 70 POKE&H14F5,8:POKE&H121B,4:POKE&H1222,8 80 POKE&H148F,0:POKE&H155F,0 90 POKE&H1CE8,&H37:POKE&H1D86,0:POKE&H2881,0 100 SCREEN 4,2,2:COLOR,,2:CONSOLE 0,24:CLS 110 FOR I=&HE000 TO &HE1FF:POKEI,&H8C:NEXT 200 REM SAMPLE --------- 210 READ A$:IF A$="END" THEN 270 220 A=&H6000+ASC(A$)*16 230 FOR I=0 TO 7:READ B$ 240 POKE A+I,VAL("&H"+B$) 250 NEXT 260 GOTO 210 270 X=15:Y=20 280 LOCATEX,Y-10:PRINT"ab"; 290 LOCATEX,Y-9 :PRINT"cd"; 300 LOCATEX,Y :PRINT"ef"; 310 LOCATEX,Y+1 :PRINT"gh"; 320 S=STICK(0) 330 VX=(S=6)+(S=7)+(S=8)-(S=2)-(S=3)-(S=4) 340 VY=(S=8)+(S=1)+(S=2)-(S=4)-(S=5)-(S=6) 350 IF VX=0 AND VY=0 THEN 320 360 LOCATEX,Y-10:PRINT" "; 370 LOCATEX,Y-9 :PRINT" "; 380 LOCATEX,Y :PRINT" "; 390 LOCATEX,Y+1 :PRINT" "; 400 X=X+VX:Y=Y+VY 410 IF X<0 OR X>30 THEN X=X-VX 420 IF Y<11 OR Y>21 THEN Y=Y-VY 430 GOTO 280 440 DATA"a",21,A0,81,80,01,00,44,44 450 DATA"b",48,0A,42,02,40,00,11,11 460 DATA"c",44,44,00,01,80,81,A0,21 470 DATA"d",11,11,00,40,02,4A,0A,48 480 DATA"e",01,01,03,03,07,07,09,05 490 DATA"f",40,80,C0,C0,D0,90,A0,90 500 DATA"g",19,59,67,67,67,67,65,62 510 DATA"h",64,A5,D9,E9,D9,E9,99,89 520 DATA"END"
この機能を使って「はるみのゲーム・ライブラリー」より「MARS」をアレンジしてみました。
PC-6001シリーズは、他機種に比べてBASICプログラムでの自由度は少ないですが、mkII以降の初代機モードでは、このように簡単にカスタムBIOSを動かすことができます。
サポートされた使い方ではないですし、絶対安全とは言い切れないのですが、 「BASICしか知らなくてもPCGっぽいことができる」 「8x8ドットのキャラクターを32x24文字表示できる」 ということは、P6ユーザーにとってはなかなか魅力的だと思いますし、MSXやJR-100などのBASICプログラムも(処理速度さえなんとかなれば)移植しやすくなるでしょう。
ただ、最大の難点は、「画面上にどの文字が描かれているのか情報を取得できない」ということだと思います。
テキストモードであれば、PEEK(&HC200+Y+X*32) のように現在描かれている文字コードを取得できますが、グラフィックモードなのでそれができません。
DIM S(32,24) のように配列を用意して PRINT文を実行するたびに値を代入するのも効率が悪いですし、すべてのオブジェクトを座標のみで管理するのも大変です。
PRINT文を改造して、「同じ文字をテキスト画面にも描く」というようにすれば、このあたりも改善されると思います。どなたかチャレンジしてみてはいかがでしょうか。
…とはいえ、大きく改造するくらいならマシン語を使ったほうが速度もプログラムサイズも効率が良いわけですが(^_^;)
ちなみに今回は「PCG機能の追加」でしたが、根性さえあれば、BASICコマンドを追加したり、MMLを拡張したり、何でもできます。
mkII以降かつモード1/2限定ではありますが、実機で簡単に改造BASICが動かせるのは楽しいので、ぜひ遊んでみてください。