2024年7月25日木曜日

PC-8801mk2用USBキーボードアダプタ

88mk2のUSBキーボードアダプタの問い合わせが来たので、少し調べてみた。

PC-8801mk2シリーズ(PC-8801mk2/SR/TR/FR/MR)のキーボードコネクタはDIN 13pinで、雄コネクタを覗き込んだ場合、左上が1pinで右下が12pin、真ん中下が13pinの並び。

13pinが5Vで外周がGND、88mk2本体から9~12pinでスキャンラインを指定し、押されたキーを1~8pinを読み取る様子。キーマトリックスは素直でシンプル。
88mk2シリーズの場合、スキャンラインは0~11まで。
キーが押されるとビットはLow(0)になり、何も押されていない場合は全ビットがHigh(1)になりFFhが返答される。

入力と出力のピンが独立してるので、余計な回路も必要なくPicoで行けそう。

ほぼDIN13コネクタとPicoを接続するのみだが、テスト基板を作成

うちには88mk2が無いので、PC-8001mk2SRで試してみる。
80SRの背面には汎用入力インターフェイスがあって、DIN 13pinのコネクタがある

基本動作はパソピア700用USBキーボードアダプタと同じ。8個のPIOで8個のリターンピンで独立して処理することで、PC本体の読み取りタイミングに間に合うように押されたキーを応答する。
少し違うのは、パソピア700はキーのスキャンタイミングがわかるピンがあるので、その1つのピンを監視していればよかったのだが、88の場合はタイミングの信号線がないので、9~12pinのどれかがLow(0)になるまでボーリングするようにした。
実際にUSBキーボードとシリアルを接続して動作確認。
結果は以下の波形。
下の4つが88mk2本体から送られてくるスキャンライン9~12pinだが、LowになってからHighになるまでの間隔が590nsくらい。
今回はポーリング処理が入っているためタイミングによるばらつきがあるが、それでもスキャン信号が届いてから200nsちょっとで返答できている。

USBキーボードでキーを押すと、ちゃんとキー入力されている。

1つ気になる点は、PC-8001mk2SR本体側のModifierキーが無効になる。
今回作成したアダプタを本体に接続すると、CTRL/SHIFT/GRAPH/カナキーがUSBキーボード側のみ有効になり、本体側のModifierキーが無効になってしまう。
仕様かもしれないが、本物の88キーボードを持っていないので確認できず。。

あと、今回88mk2版を試すにあたりPicoのUSBライブラリを最新にしたが、安定性がかなり上がった印象。USBキーボードの抜き差しをしてもハングしにくくなったし、今まで動かなかったHub付きキーボードも動くようになった。

88mk2シリーズでも動きそうだが、本体で検証できていないので...

2024年6月17日月曜日

UOOTOY Pasopia7移植

PiO 1986年5月号 119~131ページに掲載されているMZ用のUOOTOYをパソピア7に移植。
PC-6001mkIIにも移植されている方がいて、参考にさせてもらいました。助かりました。

PiO 1986年5月号は国立国会図書館に所蔵されており、遠隔複写サービスもできるようです
札幌近郊の方は、北海道立図書館の館内でコピーすることもできます(持ち出し不可)

PiO 1986年6月号 42ページにバグ情報があり、以下のように修正するようです。
・4B97hから: 00 40 E5 E7 03 40 E7 E7 07
・5C89hから: 00 10 00 10

あと、マッチが袋小路に行った際にハングする問題も対応しました。

どれだけニーズがあるかわかりませんが、ここにパソピア7用パッチのソースとRAM PACイメージを置きます。

PiO 1986年6月号に掲載されているMZ版のダンプ2000h~5FFFhを、Pasopia7で打ち込み保存します。パソピア7は0000h~7FFFhまでBASIC ROM領域のため、別の領域に一旦打ち込みます。
例えばA000hから打ち込んだ場合、以下のように保存。
BSAVE"UTDATA",&HA000,&H4000

続いて6000h~8CFFhを打ち込んで保存します。A000hから打ち込んだ場合は以下の通り。
BSAVE"UTMAIN",&HA000,&H2D00

雑誌ダンプリストの入力は、bugfireさんがダンプリスト入力用のツール(DumpListEditor)を公開してくれているので、便利でお勧めです。
バイナリを直接RAM PACイメージに上書きする場合は、以下の領域です。
・2000h~5FFFhは、RAM PACイメージの0504h~4503h
・6000h~8CFFhは、RAM PACイメージの4604h~7303h

BASICは以下の通り
10 CLEAR,&HB8FF
20 PRINT"LOADING..."
30 BLOAD"UTDATA",&H2000
40 BLOAD"UTMAIN",&HB900
50 BLOAD"PATCH7",&HE600
60 SCREEN 2:WIDTH 80:CLS:A=&HE600:CALL A
RUN"UOOTOY"で起動
(STOP)キーでBASICに戻った場合、アトリビュート領域が壊れている可能性があるので、CLSで画面クリアして下さい。再起動する場合は、"RUN 60"でOKです。

武田氏のエミュレータでも動作します。
エミュレータの場合、DCSGの高音部が出力されない音があったので、それらの効果音は音程をすこし変更しています。

パソピア7実機での動画をどうぞ。

2024年6月14日金曜日

キーボードとジョイスティック

以前、パソピアのキーの信号に関する書き込みで紹介したキーマトリックス

どのキーが押されたか判断する場合、
スキャンする行(nKS 0~B)から、スキャンデータ(KSL)とキーブロック(KB)を決めて
KSL 0KSL 1KSL 2KSL 3
KB_AnKS 0nKS 1nKS 2nKS 3
KB_BnKS 4nKS 5nKS 6nKS 7
KB_CnKS 8nKS 9nKS AnKS B

KBインターフェイススキャンデータ(Port 30h)で出力

続いてKBインターフェイスリターンデータ(Port 31h)を読み込む
キーが押された場合、その列のbitが0になる。押されていない場合は1。
全て押されてない場合は、FFhが返ってくる


ジョイスティックの押されたキーを取得する場合は、ジョイスティックアダプタ入力ポート ( ポートA 19h, ポートB 1Ah)の値を読み込む
ボタンが押された場合、その列のbitが0になる。押されていない場合は1
全て押されてない場合は、FFhが返ってくる

スピタル産業のジョイスティックには、SELECTとRUNボタンが付いており、
・SELECTボタン:↑+↓
・RUNボタン:←+→
が割り当てられている

-----
UOOTOYのキー操作について
基本はMZ-2000と同じキーを使うが、いくつかキーを追加しジョイスティックをサポート。
BASICに戻るキーも追加。

パスワード入力画面
MZ-2000Pasopia7 KeyboardPasopia7 Joystick動作
A~ZA~Zパスワード入力
SPACESPACE, INS/DEL一文字戻る
CRRETURNSELECT, Aボタン, Bボタンパスワード確定
カナカナ, HOME/CLS, PF8ROOM選択画面に進む

ROOM選択画面
MZ-2000Pasopia7 KeyboardPasopia7 Joystick動作
←, 4(テンキー)←(十字キー)ROOM数デクリメント
→, 6(テンキー)→(十字キー)ROOM数インクリメント
CRRETURNSELECT, Aボタン, Bボタンゲームスタート
F2~7同時押しPF2~7同時押し隠しメッセージ
(STOP)RUNボタンBASICに戻る

ゲーム中画面
MZ-2000Pasopia7 KeyboardPasopia7 Joystick動作
4(テンキー)←, 4(テンキー)←(十字キー)左に移動
6(テンキー)→, 6(テンキー)→(十字キー)右に移動
5, 8(テンキー)↓/↑キー, 5, 8(テンキー)↑(十字キー)ジャンプ
1(!)1(!), ZBボタンブロックを積む
2(")2("), XAボタンブロックを消す
Break(STOP)RUNボタン一時停止/解除
NNSELECTボタン次の面に進む
(クリア済みの面まで)

MZ版は、PiO 1986年6月号 42ページにあるパッチを当てると、ブロックを積む(カナ→1キー)、消す(1→2キー)に変更される。MZ-2500もそうだがパソピア7もカナキーが右側にあるので、1キーと2キーの方が操作しやすい。ただ上の列は間違って別のキーを押しそうなので、ZキーとXキーも割り当てておく。

パスワード入力のA~Zのキー入力はBIOSからの取得も考えたが、カナモードの制御ができず、アルファベットを入力しているつもりがカナが返ってくる可能性もあったので、I/Oポートで直接キーを読み込むロジックを作った。

あと、ゲーム中にキー入力のポチポチ音が気になったので、キーの割り込み処理を無効化
; キーボードリターン用の割り込みベクタを何もしないアドレスに変更
LD HL, (0FEF8h)
LD (0FEFAh), HL
元のアドレスは事前に保存しておき、BASICに戻る際に戻す。

2024年6月7日金曜日

メモリマップ

Pasopia7のメモリについて

ポート3Chでメモリモードの切り替え
・bit0=0, bit1=0:0000h-7FFFhがBASIC ROM
・bit0=1:4000h-7FFFhがBIOS
・bit1=1:0000h-7FFFhがRAM
・bit2=1:8000h-BFFFhがV-RAM
・bit3=1:(I/O Memory Mode) RAM(64KB)をI/O空間としてアクセス。次のI/Oアクセスのみ有効で、I/Oアクセス後に解除される。BIOSからのRAMアクセスで利用される

メモリ構成の優先順位
BASICを使わない場合、ROMの裏にあるRAM領域(いわゆる裏RAM)を利用できる。

メモリーのステータスは、ポート22hで読み込むことができる
マシン語処理が呼ばれた後にbit0とbit1の値を保持しておき、元の処理に戻る際は保存しておいたメモリモードに戻しておく。

V-RAMのプレーンは、ポート0Chで切り替える
bit7-4:各bit=1のとき、対応プレーンのV-RAMへのCPUアクセスが可能
bit3-0:各bit=1のとき、対応プレーンのV-RAMデータバスとCPUデータバス間のデータ交換が可能
以下の値をセットしてV-RAMプレーンを切り替える。
・11h:ブルー
・22h:レッド
・44h:テキスト/グリーン
複数プレーンの同時設定も可能
・77h:ブルー, レッド, テキスト/グリーン全てのプレーンにデータを書き込む
→画面の消去などで利用できる

-----
UOOTOYのメモリマップについて

MZ-2000版は2000h-8CFFhにロードした後、表示用データとメインプログラムを別の領域にコピーしている。
2色文字データは、Pasopia7のV-RAM領域(8000h-BFFFh)と重なるため、コピー先を変更
・MZ-2000版:7C90h-810Fh
・Pasopia7版:0B80h-0FFFh
コピー前コピー後内容
-0900h-09FFhビット反転テーブル
-0A00h-0AFFhV-RAMプレーン変換テーブル
-1000h-1FFFhV-RAM変換テーブル
2000h-28BFh2000h-28BFhプログラム、文字列データ、仮想画面など
2C00h-3FFFh2C00h-3FFFh面データ
4000h-4094h556Ch-5600h表示用データ:7色の棒データ
405Ch-408Bh55C8h-55F7hV-RAMコピーのロジック(Pasopia7では使用しない)
4100h-47BFh6000h-66BFh表示用データ:題字データ
4800h-4EBFh6A00h-70BFh表示用データ:32x16ドットキャラクデータ
4EC0h-57FFh70C0h-79FFh表示用データ:16x8ドットキャラクデータ
5800h-5A8Fh7A00h-7C8Fh表示用データ:1色文字データ
5A90h-5F0Fh0B80h-0FFFh表示用データ:2色文字データ
6000h-8CFFhB900h-E5FFhメインプログラム
-E600h-EB86hPasopia7用追加ロジック
-EB87h-ED94hPasopia7用Patch書き込み処理

ビット反転テーブル、V-RAMプレーン変換テーブル、V-RAM変換テーブルは、Pasopia7用追加ロジックの中で作成する

Pasopia7はF0FBh以降がスタック領域のため、この領域は使えない。
MZ版でF2xxhとF3xxhがデータ保存領域として使われていたがEExxhとEFxxhに移動する。
Pasopia7用Patch書き込み処理の中で、これらのコンバート処理も行う。

50面分の面データの後ろに使っていないエリアがある。
将来的に100面分のデータを対応することも考えていたのかもしれない。

2024年6月5日水曜日

V-RAM変換

MZ-2000からPasopia7のV-RAMアドレス変換について考えてみる

MZ-2000のV-RAMグラフィックは、アドレスC000h-FFFFhに割り当てられていて
80char(1char=8bitで640ドット)ごとに1行ずつ配置されている。
右のアドレスは+1で、1行下は+80(50h)という普通(?)の配列。

Pasopia7のV-RAMアドレスは以前も紹介したが、かなり独特。
アドレス8000h-BFFFhに割り当てられていて、キャラクタ(8バイト)単位で配置。
右のアドレスは+8、1行下は+1だがキャラクタの最終行だった場合は+633(0279h)加算される

MZ-2000のV-RAMアドレスからPasopia7のアドレスへの変換を考えてみる。
V-RAMバンク領域は16Kバイトでアドレスは2バイトなので、32Kバイトの変換テーブルを作るのが速度的には理想だが、今回は厳しいので4Kバイトの変換テーブルで考える。

変換テーブルは16char単位で作成する。1行80char÷16=5charぶんのアドレスを格納。
1画面200行なので、1000char分の変換テーブルになる。

1char分のデータは、Pasopia7のV-RAMアドレス2バイト+Y行数(0-199)1バイト+X列数(0-79)1バイトの合計4バイト

MZ-2000のV-RAMアドレスを16で割って、変換テーブルのインデックスにする。
変換テーブルから取得したアドレスに、16で割った余り×8を加算するとPasopia7のV-RAMアドレスになる。

それでも割り算などの処理が入るので、1回の変換に250clock程かかってしまう。
もっといい方法もあるかもしれないが、一旦はこれで変換ロジックは完成。
最初のV-RAMアドレスだけテーブル変換し、その後は差分の加算で対処する。

V-RAMアドレスの左右アドレスを取得する場合は、単純に±8バイト。
上下アドレスは少し面倒で、変換テーブルからY行数を取得し、bit2-0=000(0)なら上のアドレスは-633、bit2-0=111(7h or Fh)なら下のアドレスは+633、それ以外は±1で上下アドレスは取得できる。
変換テーブルにX列のデータも格納しておいたが、今回は使っていない。

あと1charデータのビット並びが逆になっているのも注意。
MZ-2000の場合はbit0が左に表示される。例えば■□□□ ■■□■の並びでデータを表示する場合、V-RAMへセットするデータはB1h(1011 0001)。
Pasopia7の場合はbit0が右。V-RAMへセットするデータは8Dh(1000 1101)。

ビット反転は、ここのサイトを参考にさせてもらいました。助かりました。
少しでも速度を確保したいので、起動時にキャラクタのデータが格納されている領域を一括してビット反転。
が、ここに悲劇がありました。
データの隙間に、ロジックを埋め込んではいけない。。


2024年6月2日日曜日

DCSGで音を鳴らす

パソピア7には、2つのSN76489Aが搭載されており、ボート3Ahと3Bhで操作する

テクニカルマニュアル61ページに周波数の計算式が示されており、
周波数f(Hz)=1.9968MHz/(16×n×2)
nは10bitのトーンカウンタ値で、n=1.9968MHz/(16×f×2)=62400/f

トーンカウンタ値n(D9-D0)をSN76489Aに設定する際には、2回に分けてポート設定。

R2とR1で、トーン番号 or ノイズを設定
R2R1
00Tone 0
01Tone 1
10Tone 2
11Noise

R0で、周波数 or アッテネーション(減衰)を設定
R0
0周波数
1Attenuation

例えば、トーン1に周波数440Hzをセットする場合、
トーンカウンタ値n=62400/440Hz=142=8Eh(00 1000 1110)
1回目(D3-D0)→2回目(D9-D4)の順番で2回続けてポート設定する必要がある
(1) 1回目(D3-D0:1110) =AEh(1010 1110)
(2) 2回目(D9-D4:001000) =08h(0000 1000)

あと音を出すにはVolumeの設定も必要。
Attenuation設定とVolumeの相関は、以前の記事を参照
例えば、トーン1にVolume=15(最大値)をセットする場合、B0h(1011 0000)
Volume=0(無音)をセットする場合、BFh(1011 1111)

BASICだと以下のようになる
10 ' Set 440Hz to Tone1
20 OUT &H3A, &HAE
30 OUT &H3A, &H08
40 ' Max Volume
50 OUT &H3A, &HB0
60 ' Wait
70 FOR I=0 TO 1000:NEXT
80 ' Stop Sound
90 OUT &H3A, &HBF

一般的にスピーカーON/OFFのパルス幅を変えることで音を鳴らすが、そのパルス幅をCPUクロックで調整して音の高さを変えるロジックから、DCSGの波形への変換を考えてみる。

例えば、以下のようにAレジスタにループ回数(n)を入れてパルス幅を調整している場合、パルス幅は16clock×n回になる
LOOP:
  DEC A            ; 4clock
  JR NZ,LOOP    ; 12clock(Jumpする場合)
スピーカーONとOFFが同じパルス幅で音を出している場合、パルス周期は16clock×n回×2

Z80の4MHzでこの周期を作る場合、音の周波数f(Hz)=4MHz/(16clock×n回×2)。
n=4MHz/(16×f×2)=125000/f
例えば周波数1000Hzの場合、n=125000/1000=125
それに対してDCSGで1000Hzを出す場合、トーンカウンタ値n=62400/1000=62.4

微妙な誤差はあるが、ループ回数の1/2をDCSGのトーンカウンタ値としてセットすると、おおむね同じ周波数で音がでるはず。

たぶん

2024年3月9日土曜日

Raspberry PI 5購入

Raspberry PI 5を購入

以前購入していたRaspberry PI 2/3用のX68000ケースに入れてみる

ケースに入れてみると、なかなかいい感じ。

Raspberry PI 5は発熱が増えたとのことで、Active Coolerも装着してみた。
Active Coolerも装着時も、上の蓋は大丈夫そう。

Active Coolerの接続ピンが干渉するため、ケースの土台を2カ所、リューターで削る。

あと、電源ボタン用の穴も用意

Raspberry PI 5は、電源コネクタとHDMIコネクタの位置が若干ずれている。
グレーがRaspberry PI 3、黒がRaspberry PI 5。

棒ヤスリでコネクタ用の窓を広げてみた
木のケースなので、加工しやすい。
ツヤあり黒で再塗装して完成。

ダイソーのMicroHDMIアダプタも入るようになった。USB電源コネクタもなんとか入る。

電源は5V3Aだが、SDカードで起動OKだった。

ツインタワー×2完成。黒の方がRaspberry PI 5

ここはやはりX68000エミュで遊んでみる
X68000すげー。超連射 68Kもすげー。