PC-6001: March 2009アーカイブ

漢字表示サンプル

| | コメント(3) | トラックバック(0)

SDカードインタフェースでファイルのseekおよび複数ファイルのオープンをサポートしたので、bookwormさんの漢字ROM&表示ルーチンをSDカード上に移植してみました。 フォントイメージはbookwormさんと同じ「美咲フォント」を利用させていただきました。

SDカードには漢字フォントが入ったファイルと表示させたいファイルを用意しておきます。

漢字1文字を表示するごとに漢字フォントファイルのseek&readを行っているので、スピードはいまいちですが、任意のファイルを表示することができます。

Kanji.jpg

こんな感じ。Screen 4だと結構にじみますね。 でも、容量無制限なので、大きなフォントや、複数のフォントの使い分けなども可能です。

こうなるとWeb browserを実装してみたくなりますね。 既にTCP/IPは移植した(SLIPだけど)し...。


Sub CPU(8049)の解析

| | コメント(0) | トラックバック(0)

もりやんさんのご協力で、8049のROMは何とかなりました。 ありがとうございます!

で、プログラムはもともと2kBしかないですし、それほど大きいものではないので、のんびり眺め始めています。 ただ、命令は1バイトまたは2バイトなので、コード密度はZ80より高いです。

けっこう原始的なプロセッサで、プログラムカウンタの変更が3つに分かれている(最上位ビット、中間3ビット、下位8ビット)など、扱いにくい点も多いプロセッサです。 そのため、たとえば割り込みの扱いがなかなかトリッキーなコードになっています。

  • 割り込みベクタ(0x003)から割り込み処理ルーチン(0x071)に飛ぶ
  • 別ページにジャンプ(0x0164)し、バスから6ビットの値を入力して、それに応じて0x100~0x13fからのベクタテーブルを引いて、0x140~0x162にジャンプする
  • さらにそこから本来の処理ルーチンに飛ぶ

割り込みを起こすバス信号で意味のあるのは、以下のもののみです。 コロンの前が入力信号、後が処理ルーチンのアドレスです。

  • 0x01: 0x51d
  • 0x02: 0x1b1
  • 0x06: 0x4a2
  • 0x0a: 0x167 RxRDY入力ハンドリングらしい
  • 0x0c: 0x173
  • 0x19: 0x617
  • 0x1a: 0x624
  • 0x1d, 0x3d: 0x725
  • 0x1e, 0x3e: 0x720
  • 0x1f: 0x629
  • 0x38: 0x700
  • 0x39: 0x716
  • 0x3a: 0x71b

データメモリ(0x20~0x7f)の利用状況はまだ把握し切れていません。 初期化時には以下が行われます。

  • 0x20~0x7fをゼロクリア
  • 0x40, 0x45, 0x5eに0x40を格納
  • 0x63~0x6eの12バイトには、プログラムメモリの0x7e8~0x7f3をコピー(実際には0x6fの値によるが、ゼロのため)

アドレッシングモードが豊富ではないので、上記のようなトリッキーなところだけ気をつければ、読むこと自体はそれほど大変ではないみたいです。 書くのは大変でしょうけど。


以前話題にした、RS-232Cポートを使って何か入出力できないもんかといろいろ試しています。

今のところわかったのは、RS-232C用のポートは単純な入出力ポートではない、ということです。

実験は、PS/2キーボードをつないでデータを入力する、ということをしてみました。

I/Oポートが固定(0x80および0x81)で割り当てられていて、データバスが出ているところまではいいのですが、問題は割り込み関係です。

PS/2キーボードからの入力があったら、割り込みをかけてキーバッファに入力をさせる独自ルーチンへ飛ぶようにしたのですが、これがうまく動作しません。 というのも、割り込みラインであるRxRDYはINTではなく8049に接続されているようなのです。

そのため、8049の動作がわからないことには全体の動作が把握できません。

また、本体のBIOSからもイニシャライズ時に入出力を行うため、これらを無視するようにする必要もあります。

8049のROMを読み出すことも不可能ではないのですが、手持ちの部品の関係ですぐには無理そうです。 だいいち、かなり面倒ですし。

なかなか思うようには行かないものですね...。


ATtiny2313で実験

| | コメント(0) | トラックバック(0)

私の手元にはATmega88は一個しかなく、やたら使い回ししまくって壊すのも怖いので、先日買ってきたATtiny2313で実験を始めました。

まず、ラッチを使わずにデータをハンドルできるかどうかです。 次のような試験回路を使いました。


20090318-experiment.PNG

使っているORゲートはHC32です。 この回路では3段入れているので、遅延は50nsに近くなります。 この数値は20MHzの1クロック分にもなるため、結構無視できません。 AHCなどの高速品も考慮に入れるべきでしょうね。

とりあえずPC-6001の15.7944MHzをクロックにして試した結果は次のようになりました。


  • 以前の実験でINT信号が活性化している時間はおよそ630nsである
  • 割り込みルーチンスタート後にINT信号が活性化している時間は2クロック分程度(割り込みベクタにあるrjmp命令の実行時間を除く)
  • よって、AVRの割り込み処理内ではinを2回使ってデータを読み込むのはぎりぎり可能
  • この時間ではAVRからのデータ出力は不可能。データを出力する際は、そのときだけデータバスを占有するための設定(出力設定)をしてからデータを出力しなければならないため
  • 同様の理由で、データ出力を有効にしている時間にも気を使う必要がある。短すぎると出力データを読まないし、長すぎると本体が次の命令を実行するときにコンフリクトしてハングアップする
  • 計算上は、20MHzにすると4~5クロック分になりそう
  • 処理自体は時間がかかってもそれほど問題はない。Z80が次のin/outを行うまではかなりの時間的余裕があるため


以上のことから、とりあえずAVRから見て入力側はラッチがなくてもいけそうです。 出力側はちょっと厳しそうですね。

今回はロジアナでの計測まではしていません。 いずれやるつもりです。


次に、WAIT信号(拡張スロットの7番ピン)についても調べました。 実はPC-6001のWAIT入力はちゃんと機能します。 実行時間がわかるほどのWAITを入れると、画面が乱れます。 これは、CPUが止まることによってVDG(MC6847)からのDMAも止まるためでしょう。

ただし、あまりに長時間止めると、本体がハングアップします。 これはおそらく、WAIT中はメモリリフレッシュを行わないため、DRAMの内容が消えてしまうのが原因だと思います。 まぁ、AVR内部のタイマ割り込みと組み合わせて使えば問題はないでしょう。

いずれにしても、ブートアップ時にきわめて有効に使える手段です。


と、言いたいのですが...。

ちょっとだけ追試したところ、どうもPC-6001mkIIでは有効に機能していないようです。 初代では回路上でもWAIT入力はちゃんとバッファリングするなど正式な入力端子としての扱いをしているのですが...。


A next step

| | コメント(0) | トラックバック(0)

ムービーの同時再生ですが、Audio/Videoのバイト配置を工夫することで、256x192ドット、12288Hzで12fps程度は出るようになりました。 なにせ、ファイルサイズに実質制限がないので、とても楽です。 ちなみに、現在ムービーで扱っているファイルのサイズは10MBのオーダーです。 性能はがんばればもう少しいけそうです。 まぁ、そのうち気が向いたら別のムービーでも録画してみます。

面白いことに、ニコニコ動画に出した20kHzよりも12kHz程度のほうが音質は良いみたいなんですね。 とはいっても所詮noisyではありますが。 DMAのタイミングとの関係が何かあるのかもしれません。

次のステップは、PC起動時にSDカードから起動ファイルを読み込んで自動立ち上げしたいということです。

SDOSを起動して、そのあと任意のファイルを起動してもいいですし、ベルーガのような大きなソフトが自動的に起動するというのもありです。

SDカードの転送レートは十分あるので、0x4000~0xbfffの32kBにSRAMを配置すればいいといえばいいのですが、理想的にはもっと大きなメモリを実装して、バンク切り替え可能にしたいです。 すると、ContikiなどのOSで、複数のプロセスを切り替えて使ったりできて便利です。

MSX-DOSのようにプログラムの格納番地を固定化してバンク切り替え数分のプロセスをサポートするという手もありますし、それこそelfフォーマットをAVRで解析させてリロケータブルにするというのもありでしょう。

また、起動時にPC本体とは無関係に(拡張)メモリにアクセスする必要がある関係上、アドレスとデータにバッファが必要になるのですが、逆にこれをうまく使えば画面書き換えをPC本体ではなくAVRに行わせることもできるでしょう。 そうすると、またいろいろと可能性が出てきそうです。

とまぁ、いろいろと可能性があって面白いんですが。

当面厄介なのは、またしても回路の実装なんですよね。 なんせアドレス線は本数がありますから...。

いい加減プリント基板を作る訓練をしなければいけないかな?


同時再生テスト

| | コメント(5) | トラックバック(0)

一応同時再生ができるようになったので、例によりニコニコ動画からムービーを適当に拾ってきて録画してみました。

TVで見ると色が付くのですが、キャプチャで録画したので本来の白黒になってしまっています。

動作環境は以下のようになっています。

  • 割り込みを禁止
  • AVRのクロックはPC本体からの15.9744MHz
  • 画像3バイトに音声1バイトを1組としてデータを構成
  • 処理速度を平均化するため、一切の圧縮なし。音声も1バイト中下位4ビットしか使ってない
  • 256x192ドット/10fpsで、1画像は6144バイト
  • 音声は1fpsあたり6144/3=2048バイト

以上から、音声は20480Hz/4ビットとなるのですが、DMAの関係で、やはり今のところ音質はどうにもなりません。 画面出力を切ると、10kHz程度でもかなりの音質になるのですが。

上記の条件から、転送レートは以下のようになります。

(6144(video) + 2048(audio)) * 10(fps) = 81920 = 80kB/s

やはり拡張スロットからAVRを介して直接入力しているだけのことはあり、かなりの転送レートが出ます。 しかも、バッファを持たない完全ストリーミングなので、PC側のメモリをほとんど消費しません。 プレイヤーのプログラムも、0.5kB程度の容量で実現できています。

以下が、プレイヤーの中心部です。

_play_loop:
	ld	hl, #0xe200	;11 (hl=VRAM position)
 	ld	d, #16		;8 -> 19 (d=counter)
_read:
	ld	a, #AVRSD_READ	;8
	out	(#0x00), a	;13
	nop			;5 -> 26
_read_command_loop:
	in	a, (#0x00)	;13
	cp	e		;5 (e=BUSY)
	jp	z, _read_command_loop ;11 -> 29/loop
	or	a		;5
	jr	nz, _terminate	;8/13
	in	a, (#0x00)	;13 (size L)
	in	a, (#0x00)	;13 (size H)
	ld	b, #0x80	;8 -> 47 (b=loop counter=dec x 384)
_render_loop:
	in	a, (#0x00)	;13
	out	(#0xa1), a	;13 (audio output)
	ini			;19
	ini			;19
	ini			;19
	jp	nz, _render_loop;11 -> 94*128=12032
	dec	d		;5
	jp	nz, _read	;11
	jp	_play_loop	;11
_terminate:

ご覧のとおり、ほとんどinしているだけです。

このセッティングだと、画像:音声=3:1固定のため、fpsを上げると同時に音声周波数も上がってしまいます。 しかし、512バイトセクタ単位で読み込んでいる関係で、他の比率はなかなか難しいものがあります。

それにしても、DMA ON時の音質は何とかならないものでしょうかね...。


PC-6001の回路解析

| | コメント(0) | トラックバック(0)

私の手元には、一部欠けていて、かつ非常に不鮮明ではありますが、PC-6001の回路図があります。 以前はI/O誌の解析記事もあったはずなのですが、残念ながら一部を残して捨ててしまったようです。 手持ちの資料をよく調べてみたところ、いくつか新事実(?)がわかりました。

  • 拡張スロットの7ピンに^WAIT信号入力がある。
  • 拡張スロットの16ピンに4φ出力(15.9744MHz)がある。
  • 本体の回路にはTP(ターミナルピンか)が設けてある場所があり、ここから信号線を取り出すことが可能。

一つ目はSRAM付きSDカードインタフェースを作るときにとても役立ちそうです。 初期ロードの際にCPUを止められます。

2つ目は既にAVRのクロックに活用していますが、PC-6001mkIIでは削除されてしまっているようです。 残念。

3つ目は本体をばらさないといけないですが、見たところピン自体は普通に立っているので、本体自身に手を入れることなく信号を取り出すことができます。

わかっている範囲では、TPは次のとおりです。

  • TP1: Z80の^BUSRQ
  • TP2: Z80のCLK(3.993600MHz)
  • TP3: Z80の^WAIT
  • TP4: 電源の-5V
  • TP5: 電源のGND
  • TP6: CMT OUTのデジタル信号
  • TP7: CMTのMOTOR ON
  • TP8: Z80の^INT
  • TP9: MC6847へのCLK(3.579545MHz)
  • TP10: MC6847のY信号
  • TP11: CMT INのデジタル信号
  • TP12: CN4(RS-232C)へのRESET
  • TP13: AY-3-8910のアナログ出力(ABC)をワイヤードORしたもの
  • TP14: プリンタコネクタのBUSYを反転させたもの

当たり前かもしれませんが、この情報は無保証です。あしからず。


PC-6001mkIIの状況

| | コメント(3) | トラックバック(0)

手持ちのPC-6001mkIIでも試してみました。

なんと、cloadでデータがロードできません! 初代とは何か違うのでしょうか? それとも、故障しているのでしょうか。

これでは、実験用のプログラムが読み込めないため、ROMレスシステムが完成するまで実験ができません...。


それと、初代では拡張スロットの16ピンに、本体のクリスタル発振がそのまま出力されていたのですが、それもなくなっているようです。 初代だと、それをAVRの外部クロック入力として使うことができます。 15.9744MHzなので、かなり使えるのですが...。

なんかいろいろ面倒ですね。


[AVR] 8MHzの限界

| | コメント(3) | トラックバック(0)

現在、AVRは内蔵の8MHzクロックで動作させています。 もともと手持ちのものが古い(2世代目)ATmega8Lで、2.7V~5.5Vでの駆動が可能な代わりに8MHzまでの動作となっているためです。 姉妹品のATmega8は最高16MHzですが、4.5V~5.5Vでないと動作しません。 3.3V動作のSDカードまでバッファを介したくなかったため、これはこれで悪くないチョイスではありました。

しかし、現行のAVRは3世代目に入っており、mega8系の後継にはATmega88(他に48/168/328)があります。 これは、2.7V~5.5Vで20MHz動作が可能となっています。 さらに低電圧(1.8V~)対応版として、ATmega88Vがあります。 型名の最後にVがつくものはみなこのバージョンで、こちらは10MHzまでの動作です。

電力消費を減らしたP/PVバージョンもあるのですが、そこまでは拘らないので別にいいです。

いずれにしても、ATmega88が後継としてはいいチョイスということです。 幸い、以前日本に行ったときにためしに一つ買っておきました。

ただ、8MHz以上の周波数で動作させる場合は、必ず外部にクリスタルが必要です。

というわけで、今月頭に日本に行ったときに20MHzのクリスタルとコンデンサを少々買っておきました。

現在のSDカードドライバは、データの連続読み込み部分をかなりチューンしてありますが、1バイト読み込むためにはPC本体側で29クロック必要です。 そのため、inir(24クロック)は使えません。

また、セクタをまたぐアクセスにはそこそこ時間がかかります。 とは言っても、

  • 大部分の命令を1クロックで実行する
  • avr-gccが賢く最適化する

という感じでZ80とは根本的に異なるので、体感するようなことはほとんどないのですが。

でも、やはりZ80側をフルパワーで動作させても追従させてあげたいので、88に差し替えてみようかと思っています。 幸いI/Oも結構空いていることですし。

でも、ATmega8L、5個も買っちゃったんだよなぁ...。


ショックから気を取り直して、画像および音声の同時再生を試みました。

結果は...できたといえばできました。 現在、画像は128x96x24fps, 音声は約12kHz/4bitとなっています。

ただ、同時再生の場合、VDGからのDMAを止めるわけには行きません。 これまでに調べた限りでは、VDGのBUSREQなどのタイミングをソフトウェアから取ることは不可能そうです。 そのため、音質はかなり悪いです。

割り込みは止めていますが、それでも正確なタイミングが取れないため、きついものがあります。 以前の測定で、水平帰線ではBUSACK有効(L)期間が41.2us、無効(H)期間が22.7usでした。また、垂直帰線中の無効期間は4482usでした。 ここから計算すると、CPUの動作率は以下のようになります。

(22.7 * 192 + 4482) / ((22.7 + 41.2) * 192 + 4482) =~ 52.8 %
  

また、水平帰線中、動作が止まる時間は次のようになります。

41.2 / 1000000 * 3993600 =~ 164.5 clk
  

つまり、動作中にコントロール不能で164.5クロックも停止してしまうわけです。 これは厳しいですね。

これじゃ恥ずかしくて動画共有サイトには出せないかなぁ? 何かいい方法はないものかなぁ。


今日、AVIファイルの解析プログラムを書いていて気づいたのですが、ffmpegにはモノラル1ビットのビットマップにするオプションがあるではないですか!

ffmpeg -i <file> -f rawvideo -pix_fmt monob ...
  

さっそくそのオプションで変換し、画像部分を取り出して、圧縮も何もせず力技の再生プログラムを書いて試してみると...。

何のことはない、簡単に再生できてしまいました。 しかも色(グレイスケール)が誤差拡散されている! 以前PC-8001で見たものと同じです。あれ、どうやったんだろ、すごいなぁと思っていました(あ、もちろんPC-8001版でこれを使ったのかどうかはわかりませんし、それに関係なくすごいですよ)。

なぜこれに気づかなかったんだろう。 私は、自分でビットマップからモノクロへの変換アルゴリズムまで書いてムービーファイルを作っていたのでした...。 しかも、誤差拡散なんて面倒なのでやらないで。

まさにReinvent the wheelの極致!

ああ、私ってお馬鹿さん...。

まぁ、以前の画像データの特性(RLEがかけやすい)と作成した圧縮により、自前のアルゴリズムのほうがfps値が上がっているので、良しとしましょうか...ヒクヒク

ちなみに、さらに間抜けなことに、最初は以下のようにしていたため、できたファイル(RIFFフォーマット)からさらに自前のプログラムで加工していました。

ffmpeg -i <file> -vcodec rawvideo -pix_fmt monob ... xxx.avi

まぁこれは、もともと画像と音を同時再生するためにやっているのではあるんですが。


アホな自分へのショックが大きすぎて、立ち直りに時間がかかりそうです...。


AVR-SDカードインタフェースは調子よく動いているので、ストリーミングを試してみました。

まず転送速度ですが、SDカードからの読み込み速度は現状でおよそ30kB/s出ています。 1秒でPC-6001のフリーエリアがいっぱいになってしまいますね(苦笑)。

ムービー

これまで、256x192ドットでの動画はオンメモリで8fpsでも厳しかったのですが、アルゴリズムを見直したところ、8fpsなら特に問題なく動作するようになりました。 in命令のみでデータが読み込め、メモリアクセスが不要なのが効いています。 ちなみに、inirを連続させて生データを読み込む方法だと、理論値でもかなり厳しいのと、現在はinirのスピードにAVRが追いつきません(AVRのクロックを上げればいいだけですが)。 したがって、圧縮アルゴリズムは以前のものをそのまま使っています。

動きの激しい部分などは少々スキャンラインが見えてしまいますが、何とかがんばっている、という感じです。


音声

実はムービーより音声のほうが厄介です。 タイミングを厳密に取る必要があるためです。

  • サンプリング周波数は8000Hzおよび11025Hz
  • DMA OFF
  • 割り込み禁止
  • 1チャネルのみ使用(4ビット、実のところは2ビット程度)

上記の条件だと、そこそこクリアに聞こえますが、1セクタごとにリードコマンドを発行する関係上、ポツポツとノイズが乗ります。 リードする際の待ち時間がSDカード依存で、平準化できないためです。

ここで以前の3チャネル高品質再生ではなくて1チャネルにしているのは、ムービーとの同時再生を目論んでいるためです。

当然、同時再生をするためにはDMAをONにしなければなりません。 再生時は多少時間的余裕があるので、待ち時間を減らしてDMAをONにしてみました。

すると...かなりnoisyです。 スピードの問題というよりは、BUSACKの最中に処理ができず、再生速度にムラができてしまうためかと思います。


余談

ところで、PSGの音量は以前解説したように設定値に対して対数の関係にあるのですが、それを勘案して音量レジスタの値をエンコードしてやると、何も考えずにリニアに設定するときよりも音質が悪化します。 不思議ですが、もともと4ビットと、解像度が悪いためかもしれません。