フルーツフィールド_for_pc-6001mkii
差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン次のリビジョン両方とも次のリビジョン | ||
フルーツフィールド_for_pc-6001mkii [2020/12/09 08:54] – [BGM] araki | フルーツフィールド_for_pc-6001mkii [2022/09/15 17:09] – [タイマー割込みからの復帰] araki | ||
---|---|---|---|
行 137: | 行 137: | ||
* 2020/11 初版 | * 2020/11 初版 | ||
* 2020/12/09 BGMを鳴らすようにした。 | * 2020/12/09 BGMを鳴らすようにした。 | ||
+ | * 2020/12/10 ゲーム中の効果音もタイマー割込み側でならすように変更した。 | ||
===== 技術資料 | ===== 技術資料 | ||
==== メモリーマップ | ==== メモリーマップ | ||
行 163: | 行 163: | ||
|グラフィックエリア|6000H-7FFFH| | |グラフィックエリア|6000H-7FFFH| | ||
|キー入力|1061H|出力: | |キー入力|1061H|出力: | ||
+ | |ジョイパッド入力|1CA6H|出力: | ||
|キー入力|0FBCH|出力: | |キー入力|0FBCH|出力: | ||
|キーバッファクリア|1058H| | |キーバッファクリア|1058H| | ||
行 179: | 行 180: | ||
|ロード用ファイル名エリア|FED1H-FED6H|6bytes| | |ロード用ファイル名エリア|FED1H-FED6H|6bytes| | ||
|キークリック音|FA2DH|0: | |キークリック音|FA2DH|0: | ||
+ | |||
+ | ==== 開発環境 ==== | ||
+ | |||
+ | フルーツフィールドは、ローダの書き込みにN60m-BASICを利用している以外は、すべてアセンブラで開発されています。 | ||
+ | コードエディターはVisual Studio Codeを、アセンブラを含む開発ツール一式は、WSL2の上に展開したUbuntu上に用意しています。 | ||
+ | アセンブラは[[https:// | ||
+ | 普通に、'' | ||
+ | MINGWなどで、Windows版を用意してもいいかと思いますが、WSL2は慣れるともう戻れないですね。 | ||
+ | Windowsネイティブのバイナリが必要でないなら、WSL2で十分だし、便利だと思います。 | ||
+ | |||
+ | WSL2はWindowsとのファイルの交換が容易なので、ビルドしたコードを即座にWindows上のエミュレータに送り込むことができます。 | ||
+ | WSL2側からは ''/ | ||
==== ローダー | ==== ローダー | ||
行 339: | 行 352: | ||
このため、フルーツフィールドはモード5でページ数3で起動することになっています。 | このため、フルーツフィールドはモード5でページ数3で起動することになっています。 | ||
+ | なお、BASICで'' | ||
==== 文字フォント | ==== 文字フォント | ||
行 512: | 行 526: | ||
またPC-6001とX1はAY-3-8910のレジスタのマッピングが全く同じになっているため、基本的に、I/ | またPC-6001とX1はAY-3-8910のレジスタのマッピングが全く同じになっているため、基本的に、I/ | ||
- | PC-6001が'' | + | PC-6001が'' |
+ | X1はZ80の'' | ||
< | < | ||
行 591: | 行 606: | ||
|FA06H~FA07H|タイマー割込みベクタ。デフォルトは0F74H| | |FA06H~FA07H|タイマー割込みベクタ。デフォルトは0F74H| | ||
- | 割込みベクタは、標準ではPLAY文やカーソルの点滅などの処理をしているようです。 | + | 割込みベクタは、標準では'' |
- | 最初、ベクタを保存して、BASICに戻るときに保存した値を戻していたのですが、リセットなど予期せぬ処理の後だと、ベクタが初期化されないでゲーム内のハンドラーをポイントしたままになったりしていたので、構わず 0F74Hを書き戻すようにしました。 | + | 最初、ベクタを保存して、BASICに戻るときに保存した値を戻していたのですが、リセットなど予期せぬ処理の後だと、ベクタが初期化されないでゲーム内のハンドラーをポイントしたままになったりしていたので、構わず |
タイマー割込みをフックするような何かが先にいると具合が悪いですが、まあ、そこまで考える必要もないでしょう、多分。 | タイマー割込みをフックするような何かが先にいると具合が悪いですが、まあ、そこまで考える必要もないでしょう、多分。 | ||
+ | また、タイマー割込みもBASICが動いている状態では'' | ||
- | エンベロープが0.886秒ほどで0になるような形状なので、450回に一回くらいPSGをたたけばいいかと思ったのですが、実際に動かしたら64回ほどでたたく必要がありました。どこかで何かの計算を間違えたのかな? | + | BGMはエンベロープが0.886秒ほどで0になるような形状なので、450回に一回くらいPSGをたたけばいいかと思ったのですが、実際に動かしたら64回ほどでたたく必要がありました。どこかで何かの計算を間違えたのかな? |
とりあえず、BGMの再生が安定しました。 | とりあえず、BGMの再生が安定しました。 | ||
というか、ゲームでBGM鳴らす場合はみんなこんな風な処理をしているものなんですよね? | というか、ゲームでBGM鳴らす場合はみんなこんな風な処理をしているものなんですよね? | ||
+ | |||
+ | === 競合 === | ||
+ | |||
+ | ゲーム中、ビープ音的な音を鳴らすわけです。ブロックを消したときとかフルーツを取った時ですが。 | ||
+ | 元々、BGMがなかった時分には、直接そこでPSGをたたいて音を出していたのですが、タイマー割込みで、BGMを鳴らしだすと、どうやら、PSGを触っている最中に割り込まれて、おかしな動作((具体的には音が止まらない))をするようになりました。 | ||
+ | |||
+ | さて困った。 | ||
+ | |||
+ | PSGの操作は、ポート'' | ||
+ | このレジスタの選択からデータの出力までの間に割込みが入って、向こう側でもPSGをたたいてくれると、こちらで選択したはずのレジスタじゃないものが選ばれた状態で帰ってくる可能性があります。 | ||
+ | これが消音 -- ボリューム0を出力する処理 -- の最中に来たら、意図しないレジスタに0を出力してしまい、期待しない作用を引き起こす可能性がありますし、肝心のレジスタに0が出ずに音が止まらないということになります。 | ||
+ | ビープ音鳴りっぱなしはエラー感、バグバグ感たっぷりでいただけません。 | ||
+ | |||
+ | なので、最初に試したのが、レジスタの選択からデータの出力までの区間を割込み禁止 -- '' | ||
+ | が、どうもタイマー割込みはこれを無視しているようで、症状は一向に改善しません。 | ||
+ | |||
+ | じゃあ、ビープ音を鳴らしている間はタイマーを止めるか? | ||
+ | とも思ったのですが、タイマー割込み16回分くらいはビジーループで時間調整しているので、好ましくありません。 | ||
+ | 多分BGMがおかしなことになるでしょう。 | ||
+ | |||
+ | '' | ||
+ | 大体、レジスタを選択してからワークエリアを更新するまでの間に割り込まれたら何の解決にもありません。 | ||
+ | |||
+ | 割込みでPSGを操作して戻るときにチャンネルAの音量を0にするというのはよさげにも思えましたが、場合によっては音が鳴らないかもしれません。 | ||
+ | |||
+ | となったら、もう、ビープ音もタイマー割込み側でならせばいいじゃん、という結論に至りました。 | ||
+ | |||
+ | メインルーチン側では、ビープ音の音程、音量、そしてどのくらいの間鳴らすかの三つの値をワークエリアに書き込みます。 | ||
+ | 割込み側では、これらを読んで、指定された音程、音量を設定し、音の長さを0になるまで割込みごとに減算して、0になったところで音量を0にして終わります。 | ||
+ | |||
+ | 割込みは1/ | ||
+ | ビープ音を鳴らしたいタイミングから平均1ms未満の待ち時間ですので、テストプレイした限りでは、音が遅れて鳴るようなことはありませんでした。 | ||
+ | めでたし。 | ||
+ | |||
+ | 万一、鳴っている最中に、別のビープ音を鳴らす処理(値の更新)があったら、まあ、音がつながって長くなったりするだけ(のはず)なのでいいことにします。 | ||
+ | |||
+ | AY-3-8910のエンベロープには単調に減少するとか、単調に大きくなるとかはあるんですが、一定期間ONで周期が来たら0になるというようなものがないので、ビープ的な音を鳴らしたい場合には、一定期間鳴らしたらオフにするという操作がひつようになるため、まあ、こんなやり方で逃げるしかないのかな、と、いう感じです。 | ||
+ | |||
+ | なお、カウンターは手抜きで、1byteしかとっていませんので、音の長さは 1/ | ||
+ | まあ、0.5秒より長く鳴らすともうそりゃビープじゃないよな、ということで、フルーツフィールド的にはよいことにします。 | ||
+ | |||
+ | 副作用として、ビープ音のためにビジーループしていたのがなくなって、タイマー割込みでタイミングを見るようにしたので、連続してフルーツを取るのが多分少しだけ早くなっています。 | ||
+ | ==== 16bit演算 ==== | ||
+ | |||
+ | Z80は8bitのCPUなので、基本的な演算は8bitのレジスタに対して行い((特にアキュムレータであるAレジスタのみに使えるものが多い。))、16bitの演算は適宜、Cフラグなどと組み合わせて複数回にわけて行う必要があります。 | ||
+ | |||
+ | しかし、いくつかの演算については16bitレジスタペアに対しても使えます。 | ||
+ | |||
+ | ところが、8bitの演算と全く等価ではない場合があるので注意が必要です。 | ||
+ | と、いうか、失念してて、罠にはまりかけました。 | ||
+ | |||
+ | 16bitの減算処理、'' | ||
+ | なので、 | ||
+ | |||
+ | < | ||
+ | DEC HL | ||
+ | JR Z, END | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | のようなコードは動かないのです。 | ||
+ | 減算した後、別途比較を組む必要があります。 | ||
+ | |||
+ | < | ||
+ | DEC HL | ||
+ | LD A,H | ||
+ | OR L | ||
+ | JR Z, END | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | これなら動きます。 | ||
+ | が、Aレジスタを使うし、比較のためにサイクルを食うし、忘れると動かないし、気を付けないといけません。 | ||
+ | |||
+ | ==== STOPキー? ==== | ||
+ | |||
+ | BGMのON/ | ||
+ | え、なんでSTOP? | ||
+ | |||
+ | これは、ゲーム中のキーの読み取りを'' | ||
+ | |||
+ | もう、何も残っていないので、これ以上何かを追加するとしたら、思案が必要です。。。 | ||
+ | |||
+ | ^ビット^キー^ | ||
+ | |7|スペースキー| | ||
+ | |6|空き| | ||
+ | |5|←| | ||
+ | |4|→| | ||
+ | |3|↓| | ||
+ | |2|↑| | ||
+ | |1|STOPキー| | ||
+ | |0|SHIFTキー| | ||
+ | |||
+ | なお、エミュレータにおけるSTOPキーは PC-6001VX、PC-6001VWともに'' | ||
+ | ご参考まで。 | ||
+ | |||
+ | ==== タイマー割込みからの復帰 ==== | ||
+ | |||
+ | 割込みハンドラーですから、戻りは'' | ||
+ | なので、フルーツフィールド内でも同様にしていますが、とりあえず問題は起きてないので良いことにしておきます。 | ||
+ | |||
+ | ==== キー入力とジョイパッド ==== | ||
+ | |||
+ | PC-6001にはゲーム用のキー入力ルーチンがあり、Aレジスタにビットマップ値でキー入力を返してくれます。 | ||
+ | フルーツフィールドでもこれを利用していますが、[[DevTerm]]についているジョイパッドに対応するために、ジョイパッドの入力を拾うルーチンも呼び出す必要が発生しました。 | ||
+ | このルーチンもジョイパッドの操作をAレジスタにビットマップとして返してくれるのですが、このマッピングが、キー入力のそれと違うのです。 | ||
+ | NECは何を考えて異なるビットマップを返すようにしたのでしょう? | ||
+ | |||
+ | ||0|1|2|3|4|5|6|7| | ||
+ | |キー|SHIFT|STOP|↑|↓|→|←|-|SPACE| | ||
+ | |ジョイパッド|↑|↓|←|→|A|B|-|-| | ||
+ | |||
+ | 上のようなビットマップなんです。 | ||
+ | いやらしいのは、そもそも方向とトリガー相当のもののマッピングがずれているし、右左が逆になっていたりするところ。 | ||
+ | |||
+ | 都度、それぞれの処理を書くのは面倒なので、既に、キー入力に合わせて処理を組んでいるので、ジョイパッドの入力をキー入力に合わせるように変換するコードを書いて、対応しました。 | ||
+ | |||
+ | < | ||
+ | ;;; gamekeypad | ||
+ | gamekeypad: | ||
+ | call gamekey | ||
+ | and a | ||
+ | ret nz | ||
+ | |||
+ | ld a,1 | ||
+ | call joystick | ||
+ | and a | ||
+ | ret z | ||
+ | push bc | ||
+ | ld b,0 | ||
+ | ld c,a | ||
+ | rlc c | ||
+ | ld a,10h | ||
+ | and c | ||
+ | ld b,a | ||
+ | rlc c | ||
+ | ld a,0ch | ||
+ | and c | ||
+ | or b | ||
+ | ld b,a | ||
+ | rlc c | ||
+ | ld a,0a3h | ||
+ | and c | ||
+ | or b | ||
+ | pop bc | ||
+ | ret | ||
+ | </ | ||
===== 技術的ではないボヤキのようなもの | ===== 技術的ではないボヤキのようなもの | ||
行 627: | 行 790: | ||
なお、現在、X1版のBGMを移植して、鳴らせるようにしてあります。 | なお、現在、X1版のBGMを移植して、鳴らせるようにしてあります。 | ||
+ | |||
+ | ==== 感想 ==== | ||
+ | |||
+ | PC-6001mkIIにフルーツフィールドを移植してみて思ったことは、なかなかいいハードじゃないかということです。 | ||
+ | |||
+ | 画面は160x200とやや低解像度だし、VRAMがアトリビュートとグラフィックの二つに分かれていたり、兎にも角にも遅いという側面はあるものの、頑張って全速力で動かせば、ゲームを遊ぶのには十分だし、音楽もPSGではありますが、そこそこ簡単に鳴らすこともできるし、仕上がったフルーツフィールドは、PC-8001版にはなかったBGMを持ち、ドット単位で15色の色を持ち、似て非なるものになりました。 | ||
+ | |||
+ | ゲームとしての出来は、キメラ化の結果ではありますが、とてもよく仕上がったと思います。 | ||
+ | 勿論、PC-8001のハードウェアの制約を考えれば、オリジナルの出来は秀逸で、だからこそ、PC-6001mkII版があるわけですが、当時PC-6001mkII版があってもよかったなあ、と、改めて思いました。 | ||
[[start]] | [[start]] | ||
フルーツフィールド_for_pc-6001mkii.txt · 最終更新: 2022/09/15 18:40 by araki