PC-6001の最近のブログ記事

ExpressPCBでのアートワーク、一応ほぼ完成しました。 片面基板用に頑張りましたが、ジャンパを20本ほど飛ばす必要があります。 それでもユニバーサル基板に配線することを考えたら気が遠くなりそうなので、パソコンでデザインできるのは助かります。

20090616-SD.png

結局、「PCBのデザインにあわせて回路を変える」ということを結構しましたが、なんとか形になったかな?

ジャンパ部分は反対面に描いてあるので、ほぼこのままExpressPCBで注文することも可能ではあります。 でも今回は自分で焼きます。 ちなみに、ツール上からの見積もりでは、価格は2枚で120ドル、10枚で200ドル強といったところでした。

今日さっそく焼いてみようと思ったのですが、プリンタに印刷できる透明シートがないことが判明。 クリアファイルで試してみましたが、いまうちにあるインクジェットプリンタではまったくインクが乗らないため、今日のところは諦めました。

せっかく今日はMaplinに行ってinfraredの温度計と、ついでにデジタルノギスを買ってきたのに。

なんとか今週中に1枚作って、うまくいったら来週の日本出張時に生基板を補充したいものです。

ちなみに、以下が今日買ってきた温度計(Thermometer)とノギス(Callipers)です。 どちらも電池式のデジタル。 温度計はこんなにいいものは不要だったのですが、これしかなかったのです。

Thermometer.JPG Callipers.jpg

価格は、温度計が29.99ポンド、ノギスが9.99ポンドでした。 温度計の電源はは006Pで、買うときに「これは電池が必要だけどいる? buy one get one freeだよ。つける?」と言われたので「いいよ」と言って買ったのですが、本体には最初から電池が入ってました...。 ノギスはLR44なのですが、最初から入っている上にスペアも同梱されてました。


え~ん、回路にバグ(未結線)が見つかって、ジャンパを足さなければならなくなりました。 これでジャンパはおよそ30本になります。 それ自体はいいのですが、まだ何かあるのかと思うと心配なのと、パッドを追加したことで焼付け時のショートの可能性が増したのが心配です...。


以前設計したSDカードアダプタのアートワークにチャレンジしています。

使う回路CADはフリーのものです。 どのソフトにするか、いくつか試しました。 悩みましたが、まずはExpressSCHおよびExpressPCBにしました。

  • PCBEは使いやすいが、PCBレイアウトに特化しているので回路図との連携が取れない。
  • Eagleはオートルータもあって強力だが、使い勝手に癖があり、特にカスタムコンポーネントが作りにくい。

これまで回路はBSCh3Vを使っていたので、まずは回路をExpressSCHで書き直しました。 ExpressSCHの持つ部品はあまり多くないのですが、カスタムコンポーネントは簡単に作れるようです。 ライブラリ中の似たような部品を置いて、Ungroupしたあと、ピンを編集して再びGroupすれば部品になります。 ついでにカスタムコンポーネントにしておけば、使いまわしも楽です。

ExpressPCBでは、回路図で登場した部品を自動的にボードにおいてくれることも、ラッツネットの作成もしてくれません。 これはちと面倒といえば面倒ですが、逆に自由度も増しています。 というのは、回路図とボードデザインの間は部品番号とピン番号のみで連携しているようなのです。 そのため、やはりライブラリ中から似たようなな部品を引っ張ってきてUngroupし、適当に編集すればカスタムコンポーネントを作れます。

ハンドルーティングなのでかなり面倒ですが、これは練習だと思ってがんばります。 ツール上で配線チェック(交差している、全結線したかどうか等)ができないので、目視検査となりちと大変です。

ちなみに、手持ちのキットが片面基盤なので、とりあえず部品面に回路を引いて、実回路では半田面に焼き付ける予定です。 そうすると、反転してデザインする手間が減ります。 回路が複雑なので片面基盤で出来るレベルではないですが、その辺はジャンパを飛ばすなり何なりで対処します。 でも、なるべくならプリントしてしまいたいので結線を工夫します。この辺はやってみて初めてノウハウが身につく感じですね。 引き始めは結線の多さに呆然としていましたが、少し結線を進めていくとだんだん面白くなってきます。

今のところ、SDカードの部品がないのが少々困ります。 結線用のパッドを置く位置は問題ないのですが、固定用のパッド位置が分かっていません。

結構回路規模があるので、大きさが問題になりました。 通常のカートリッジ用の基板は縦が72mm程度です。 配線幅を50mil(1.27mm)で設計すると横はともかく縦があふれます。 配線の太さはデフォルトの10mil(0.254mm)です。 電源線は太くするとしても、このくらいでないとかなり厳しいです。 このあたりはもう少し練る必要がありそうです。

エッジカード部分も片面しか作れないので、これも何とかする必要があります。 とりあえず、部品面へはパッドで接続し、イージスペンで部品面の端子を作ることにします。

設計にあたっては、西田さんに教示いただいた「なるべく基板配置を考えた回路図にする」というのがとても参考になりました。 CPLDやSRAM、244などは利用する端子に自由度があるので、これらについて最初から配線にクロスが生じにくいように設計したのですが、おかげでアートワークがかなり楽になりました。 こういうのもノウハウがいろいろあるのですね。


SDカードをFDD互換にするには、ソフトウェアでのエミュレーションもさることながら、ハードウェアの互換性も取る必要があります。

具体的には、ポート0xd0~0xd3をアクセス可能にします。 そのためには、現在の回路のアドレスデコードを変更する必要があります。 参考までに、以下が現在の回路図です。

20090503-2313.PNG

現在のアドレスデコードはCPLDで行っていますが、拡張するにはピン数が厳しいです。 回路が上記のようになっているためです。

利用している入出力は以下のとおりです。

  • アドレス(A15, A14, A7, A6, A5, A4)
  • PCデータバス(D7~D0)
  • AVRデータバス(D7~D0)
  • PC制御信号(MREQ, IORQ, RD, WR, RESET)
  • AVR制御信号(AVRWR, AVRRD, INT0, INT1)
  • メモリ制御信号(ROMEN, RAMEN)

合計33ピン。 PLCCパッケージのCPLDでは入出力ピン数が34本までしか取れません。

上記ポートをサポートするには、最低でもA1, A0を入力し、AVRに対して識別信号を出さなければいけないので、3本追加となり、2本ピン数オーバーです。 CPLDを一つ追加すれば余裕でサポートでき、244の機能も包含できますが、回路的には複雑になります。 逆に、基本ロジックでデコードの一部を出すことでCPLD1個での実現も不可能ではないですが、デコードそのものが結構複雑なため、ICが2個程度追加されることになり、あまりうまみがありません。

回路の複雑さは基板設計の複雑さに跳ね返るので、なかなか微妙なところです。


「SDカードをオリジナルのフロッピーディスクの代わりに使えたら便利いんじゃない?」と言われたので、拡張BASICをちょっと読んでみました。

基本のBASICは、それこそ8080でも動くんじゃないかというくらい基本命令ばかり使っています(実際にはldirやビット関連命令を使うので8080では走りませんが)が、拡張BASICはIXレジスタを使うほか、Z80の拡張命令を多少は積極的に使う傾向が見られます。

まぁその割には、いきなり最初で

ld	ix, (nn)

を使わずに、

ld	hl, (nn)
push	hl
pop	ix

としていたりしますが。 読みやすいソースなので気にすることではありませんね。


ディスク入出力に使うのは0xd0~0xd3のI/Oポートで、ここをうまく騙してやれば不可能ではなさそうです。

ハード的には、現在のCPLDの使い方だと入出力が最低でも1本不足します。 AVRの入出力には十分余裕があります。 複数のI/Oポートを使うためには、割り込みスピードを間に合わせるための工夫が必要ですが。

ソフト的には、ファイルをディスクイメージとして使うことになるでしょうね。 現在のFATの上に実装すれば良さそうです。


AVR Tiny2313をROMとして動作させられるかどうか、ここのところ試行しているわけですが。

どうも、20MHz動作でも必ずアクセスが成功するというわけではないようです。 ごく稀にですが、誤動作することがあります。

プログラムは以下のようになっています。

_loop:
	in	ZL, PIND	;1  7bit
	lpm			;3
	out	PORTB, r0  	;1
	rjmp	_loop		;2

ここからアクセス時間が最長になってしまう状況を考えると、こうなります。 すなわち、in命令で得られたデータはまだアドレス確定前で、その直後にアドレス確定、次のinでようやく正しいアドレスが取得できる状況です。 すると、正しいデータが出るまでの最長のクロック数は、以下のようになります。

3(lpm)+1(out)+2(rjmp)+ 1(in)+3(lpm)+1(out) = 11 (clk)

これを20MHzで考えると、1clkあたり50nsなので、550nsということになります。 これは最悪の場合で、通常はここまでかからないのですが。 ただ、プログラムを読んでいるので、一回でも読み間違えれば当然のように誤動作します。

PC-6001で使われているROMのアクセスタイムは、以下のようになっています。

  • BIOS(BASIC) ROM: uPD2364 Max. 450ns (2364-45)
  • Character ROM: uPD2332 Max. 450ns (2332-45)
  • UV-EPROM: uPD2732 Max. 450ns (互換品のHN462732のデータ)

やはりこの時代の製品は450nsあたりが最大のようで、550nsでは間に合わないことがあるようです。

上記のプログラムではrjmpが無駄にクロックを消費しています。 rjmpがなければ最悪でも9clk = 450nsで動作してくれます。 そのため、in~outをたくさん並べれば誤動作の可能性は低くなります。 でもメモリは有限ですからいつかはrjmpで元に戻る必要があるため、絶対誤動作しないとは言い切れません。

誤動作といっても、ごく稀のことなのでこのまま行くか、信頼性を上げるために別の手を考えるか、悩ましいところです。


なんちゃってROMの動きを確実に確かめるために、なにかよいアプリケーションはないかと考えました。 そこで、Joystick版のSDカードアダプタからの読み込みをすることにしました。

とはいっても、Joystick版の場合、SPIの動作をすべてAY-3-8910のI/Oで実現する必要があるため、非常に多くのコードが必要になります。 たとえば、1ビットの何かを出力するためにも、

ld	a, #0x0f
out	(#0xa1), a
ld	a, #value
out	(#0xa2), a

といった具合に、愚直に実現すると8バイトもかかってしまいます。

なんちゃってROMに許されたアドレス空間は、アドレス線の本数の制約により128バイト。 先頭の4バイトはBIOSがROMの判別とジャンプアドレスを得るために必要なため、実際は124バイトしかありません。

そこで、ファイルを読み込むのは最初からあきらめ(FATなんてとても入らない)、セクタ0を読み込むことにしました。 もともとセクタ0の最初の446バイトは、ブートアップのためのコードを格納する領域ですしね。

それでも、電源ON->初期化->読み込みとあるため、結構大変です。 リリース済みのドライバを見てみたら、398バイトもありました。

それを削りに削りました。 エラーチェックやらレジスタの使い回しやら、それはもう、あらゆる手を使って。 で、なんとか124バイトの枠内に収めました。

で、できたものがこれです。 これから先は変態プログラムです。 よい子は見てはいけません。

SDDRV_DI  = 0x10		; output, pin8
SDDRV_CS  = 0x02		; output, pin7
CMD_READ	= 17 | 0x40	; command for read
REG		= 0xa0		; I/O port AY-3-8910 register latch
WRITE		= 0xa1		; I/O port AY-3-8910 write
READ		= 0xa2		; I/O port AY-3-8910 read
REG_SEL		= 0x07		; AY-3-8910 I/O select
REG_IOA		= 0x0e		; AY-3-8910 I/O A (input)
REG_IOB		= 0x0f		; AY-3-8910 I/O B (output)

	.org	0x4000
	.db	0x41		; 'A'
	.db	0x42		; 'B'
	.db	0x04
	.db	0x40		; start from 0x4004

	;; from 0x0083, Z=1, Cy=0, StackTop=0x0084
	;; A=0x42, B=0x00, C=0x3d, D=0xfb, E=0x61, H=0x40, L=0x04
_boot_start::
	ld	de, #0x0f08	; REG_IOB, counter
	ld	a, #REG_SEL	; 0x07
	out	(#REG), a
	rrca			; 0x83
 	out	(#WRITE), a	; setup AY-3-8910 I/O
	ld	a, d		; 0x0f
	out	(#REG), a
	ld	a, #(SDDRV_DI | SDDRV_CS) ;0x12
 	out	(#WRITE), a
_boot_init_loop:
 	out	(#WRITE), a	; DI | CS
	inc	a
 	out	(#WRITE), a	; DI | CS | CLK
	dec	a
	djnz	_boot_init_loop
	call	_boot_cmd	; H=0x40 (reset), H is set by caller
	inc	h
_boot_init_cmd1:	
	call	_boot_cmd	; H=0x41 (init)
	dec	c
	jr	nz, _boot_init_cmd1
	ld	h, #CMD_READ
	call	_boot_cmd	; H=0x52 (read)
	call	_boot_wait

	ld	h, #0xe2	; L=0
_boot_read_loop:
	call	_boot_bytein
	ld	(hl), c
	inc	l
	jr	nz, _boot_read_loop	; fall through

	;; AFBC________
	;; out C=input byte, B=0, A=0or1
_boot_bytein:
	ld	b, e
_boot_bytein_loop:
	;; 8 times of bit read
	ld	a, d		; 0x0f
	out	(#REG), a
	inc	a
	out	(#WRITE), a	; DI
	inc	a
	out	(#WRITE), a	; DI | CLK
	ld	a, #REG_IOA	; 0x0e
	out	(#REG), a
	in	a, (#READ)	; if A[0]=1, then data=1
	rrca			; A[0]->CY
	rl	c		; cy<-[7<-0]<-cy
	djnz	_boot_bytein_loop
	ret

	;; AFB_________
	;; in C=output byte
	;; out B=0, A=0x01/0x11
_boot_byteout:
	ld	b, e
_boot_byteout_loop:
 	ld	a, d		; 0x0f
 	out	(#REG), a
 	inc	a		; 0x10
	rlc	c
	jr	c, _boot_byteout_data
	xor	a
_boot_byteout_data:
 	out	(#WRITE), a	; (DI)
	inc	a
 	out	(#WRITE), a	; (DI) | CLK
	djnz	_boot_byteout_loop
	ret			; B=0, A=0x01/0x11, Cy=0, Z=0

	;; AFBC___L____
	;; in: H=cmd (must have 0x40 offset)
	;; out: C=result+1 (1, 2, 0xff), B=0, L=0, A=0x00/0x01, Z=0, Cy=0
_boot_cmd:
 	ld	c, #0xff
	call	_boot_byteout	; dummy
	ld	c, h		; A=0x11
	call	_boot_byteout	; cmd
	ld	c, b		; 0x00
	ld	l, #0x04
_boot_cmd_loop:
	call	_boot_byteout	; arg
	dec	l
	jr	nz, _boot_cmd_loop
	ld	c, #0x95
	call	_boot_byteout	; CRC (for CMD0)
_boot_wait:			; L=0, A=0x11
	call	_boot_bytein
 	inc	c
	ret	nz		; bytein != 0xff (0, 1, 0xfe), Z=0
	jr	_boot_wait

実際にはプログラムは122バイト(全体で126バイト)で済んでいます。 なお、タイムアウト判定を省略しているので、正常にSDカードが挿さっていないと無限ループします。 そのチェックは容量内ではできませんでした。 また、セクタ0の最初の256バイトのみ読んでいます。

まぁ、言うほど変態チックじゃないかな?

動かしてみると、正常に読んでいるため、20MHz動作なら問題ないみたいです。


先日のなんちゃってROMですが、Enable信号をモニタするのはスピード的に辛そうなので、バッファをつけてみました。

20090411-experiment.PNG

これだと、AVR側は入力されたアドレス線に対して出力するのみ。

_loop:
	in	ZL, PIND	;1  7bit
	lpm			;3
	out	PORTB, r0  	;1
	rjmp	_loop		;2

まさに「来たら打つ! 来たら打つ!」状態です。 実際の出力判断は244に任せていますので。

で、うまく動きます。 アドレスは7ビット分(A0-A6)なので、128バイトまでですが、ブートアップには十分な容量です。

ただ、ちょっと気になるのは、27C256(32kB UV-EPROM)を積むのとどちらがオトクかということです。 上記の回路はTiny2313(100円)+LS244(100円くらい)+XTAL+パスコン2個で、300円弱かかります。 一方、27C256は200円で買えます。

まぁ、244などジャンクを漁れば大量に出てくるので、実質買うことはないのですけど。 また、AVRはISPが使えるので、UV-EPROMよりは書き換えは楽ですね。

実際のSDカードインタフェース回路では、mega88も使うため、そこからのCLKO信号を入れることにより、XTALを省略することも可能かもしれません。

ただ、Tiny2313の仕様を見ると、外部クロックは16MHzまでとあります。 ためしにPC-6001の15.9744MHzでやってみたところ、誤動作しました。 微妙です。


設計変更をいろいろしていくうち、どうせAVR-SRAM間のDMAをしないのならSRAMのデータバスをCPLDに入出力させなくてよいことに気づきました。 SRAMはCSさえきちんとコントロールできれば、データバスは常にHi-Zなので、そのまま本体のバスに直結でも問題ないのです。 WEやOEでさえも。

ということで、SRAMのデータバスをCPLDの入出力から外したところ、CPLDの使用マクロセル数が激減(-16)しました。 それでわかったのですが、今までやたらマクロセルを消費していた犯人は、MUXのようなのです。 おそらく3-state bufferが8ビットx2、かつMUXが8ビットx2で、32マクロセル消費していたようです。 これではほとんどロジックは入れ込めませんね。 Xilinxの論理合成がヘボなのかもしれませんが。

というわけで、いま実験中のtiny2313の簡易ROM化がうまくいけば、あとはデコード等はXC9536(XL)が一つですべて賄えることがわかりました。

こちらはいざとなったら244を一つ挿入することになるかもしれませんが、そうすると副作用でISPができるようになるので(現在はデータバス直結なので無理)、悪いことばかりでもないかもしれません。 でも、この場合はプログラムフラッシュの自己プログラミングをサポートするほうが有効かな。


こんなものを試作してみました。

20090407-experiment.PNG

ATtiny2313をROM代わりに使おうというものです。 アドレスバスのピン数の都合で、64バイトまでしかハンドルできません。 あとは全部イメージになりますが、起動時だけなので問題ないでしょう。

やはりスピードがかなり厳しく、(初代)本体からのクロック(15.9744MHz)では間に合いませんでした。

20MHzの水晶でやってみましたが、やはり連続アクセスには難があるようです。 暴走こそしないものの、読み込みデータが抜けたりして、安定しません。

AVRのプログラムは今のところ以下のようになっています。

.org	0x0000
	ldi	R_TMP, LOW(RAMEND)
	out	SPL, R_TMP
	eor	R_ZERO, R_ZERO
	ldi	R_FF, 0xff
	ldi	ZH, 0x02 	; data start from 0x0100
	out	DDRD, R_ZERO
	out	PORTD, R_FF
	out	PORTB, R_ZERO
_loop:
	out	DDRB, R_ZERO	;1 4-8clk until PortB output disabled
_wait1:
	;; wait for read request
	sbic	PIND, 6		;1/2
	rjmp	_wait1		;2
	in	ZL, PIND	;1 Z = 0x0200 + PIND (PIND < 0x3f)
	lpm			;3
	out	DDRB, R_FF	;1
	out	PORTB, r0  	;1  8-11clk until data appears on the bus
_wait2:
	;; wait until read request has been cleared
	sbic	PIND, 6		;1/2
	rjmp	_loop		;2
	rjmp	_wait2		;2

	.org	0x0100
	.db	0x41, 0x42, 0x04, 0x40, 0x3e, 0x40, 0xcd, 0x75, 0x10, 0xc9

割り込みを使うとビットが連続したピンが使えなくなるため、busy loopで待ったほうが速そうなので、そうしています。 なんとかAVR側のプログラムを高速にできないか考えているのですが、これ以上は考え付きませんでした。 プログラムエリアからバイトを読むlpm命令は3クロックもかかりますが、代わりにSRAMから読むにしても2クロック、しかも入力アドレスに0x60を加算する必要があるので速くなりません。

データバスに3-state bufferをつけてしまえば、ウェイトなしでアドレス入力から垂れ流しができるので十分高速になるとは思いますが。 しかもPD6をアドレス線に使えます。 まぁ、搭載チップがひとつ増えてしまうので、なるべく避けたいところではあります。

ちなみに、どうせCS2がイネーブルになるときはROM読み込みだろうということで、CS2を直接PD6に入れてみたりもしましたが、症状は改善しませんでした。


思いついたアイデアをひとつ。

Tiny2313あたりを1個積んで、メモリバス(拡張ROM1の部分)をハンドルします。 いわゆるIPL ROM代わりで、CS2/MREQ/RD/D0-D7/A0-A5あたりを入出力させます。

本体に読み込まれるコードはmega88(I/Oバス)を経由してSDカードからブートプログラムを読み込むものです。 このコードを実行中は読み込みはTiny2313から、書き込みはSRAMに行くようにしておいて、いったん初期化が終わったらTiny2313を完全に切り離してSRAMのみアクセスするようにします。

これだとPLDを使わずとも、現在の実装の延長線上でもできそうな気がします。

問題は、データをバスに載せるのがタイミング的に間に合うかどうかですね。 Z80のデータシートを見ると、メモリリクエストが開始されてからデータを乗せるまでは3クロック程度のようです。 ROMエリアなので、おそらくWAITが入って4クロックくらいになるのかな? AVR/20MHzでは20クロック分くらいです。 別にUV-EPROMを使っても似たようなことは可能ですが、Tiny2313は書き換えが楽なのと、値段が安いのがアドバンテージかと思います。


漢字表示もできて、結構実用的に動くようになったSDカードインタフェースですが、皆さんにどのような形で使ってもらうかを悩んでいます。

今手元にあるのは、西田さんに作っていただいたone offの基板に実装したカードです。 この設計のままでも動作しますが、このカードのみではRAMが16kBしかないこと、自動起動しないことという制約があるので、公開するのに躊躇しています。

一応、ベルーガROMと一緒に挿せばこれらも可能なのですが、いまどき私を含めPC-6011を持っている人もいないでしょうし、1つの基板にしておきたいところです。

このプロジェクト(?)の大きな目的は2つあります。

  • 昔のソフトを簡単に実機で楽しむ
  • 新しいソフトを開発するプラットフォームにする

一つ目では、普通のプログラムの実行を妨げないように、0x8000より下位のエリアに、SDOS用のスタックやら作業領域用のRAMを積んでおきたいわけです。 二つ目では、アップデートが頻繁に行われる可能性があるので、やはり0x4000-のROMエリアはRAMにしておきたいわけです。

ということで、ハード的に今足りないのは、以下の点です。

  • 0x4000-0xbfffの(最低)32kB分のRAM
    これはSRAMを積めばいいので、多少のデコーダが必要だが簡単
  • 起動時に本体の動作とは無関係にロードする仕組み
    本体とのアドレスおよびデータの信号をバッファする必要がある。 また、ロード後に本体にそれを(拡張領域として)認識させなければならない。

どちらも、回路は技術的に難しいものではないのですが、データ線だけでなくアドレス線もバッファしなければならない関係で入出力が非常に多くなります。 CPLDを使うことを考えてはいますが、結構高いんですよね。 XC9572-TQ100で1,000円、XC95108-PC84で1,700円とかです。 44PLCCのものをを2個ということも考えられますが、2個にする関係で無駄になる入出力やマクロセル、そして余計な配線が増えるのでイマイチです。

まぁこの辺は以前も少し議論したことなのですが、未だにうまい解決法が見つからず、頭をぐるぐるしています。

ソフトウェアだと「まぁ作ってから考えるべ」となるのですが、ハード素人の私にはなかなか勇気が出ないのです。 プロトタイプを作るのもすごく大変ですし。


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

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

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

Kanji.jpg

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

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


もりやんさんのご協力で、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を読み出すことも不可能ではないのですが、手持ちの部品の関係ですぐには無理そうです。 だいいち、かなり面倒ですし。

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


私の手元には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入力はちゃんとバッファリングするなど正式な入力端子としての扱いをしているのですが...。


ムービーの同時再生ですが、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に行わせることもできるでしょう。 そうすると、またいろいろと可能性が出てきそうです。

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

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

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


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

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の回路図があります。 以前は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でも試してみました。

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

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


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

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


現在、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個も買っちゃったんだよなぁ...。