目次
前
次
WonderKit_Z80_board
アマチュア無線の知人から、WonderKitのZ80基板を
貰ったので、必要な部品を実装し、動くようにして
みました。
パラレルインタフェースICのZ80PIOは、入手できず
外部に8255、8251を増設してシステムが成立つよう
にしました。
写真で見てわかるように、Z80PIOエリアにはICが
ありません。
手書きの回路図があったので、メモリとI/Oのアドレス
空間を調べると、以下。Z80ファミリICは、80hから8Fh
まで配置されています。90hから9Fhがユーザーへ開放
されています。
ROM、RAMは8kバイトの手持ちがあったので
そのまま利用しました。
I/Oの方は、Z80CTCを利用するだけに、80からの
4バイトを占めるようにアドレスデコーダの
74LS138を使っています。
50ピンのコネクタに、Z80の40ピンの信号が
出ているので、74LS138のイネーブル信号を
利用して8255と8251を配置しました。
8255を2つ配置し、90hから97hまでにアサインし
8251は、98hから9Chに接続します。
Z80には、4MHzのデバイス指定がありましたが
Z80Hを利用して6MHzで動かします。
Z80CTC、8251、8255は4MHz仕様なので、I/Oアクセス
には、ウェイトを2個入れるようにします。
WonderKitの基板が使えるかを、アセンブリ言語で
雪ダルマ式に増やしていきます。
スタックポインタ設定
擬似命令を利用して、ラベルを定義し
スタックポインタに入れ、無限ループ
でダイナミックストップをかけます。
STKTOP EQU 0h
org 0h
start:
ld hl,STKTOP
ld sp,hl
loop:
jr loop
end
8255初期化
8255を初期化するには、I/Oの回路図が必要です。
I/Oは、次のようにアドレスデコーダを設計して
います。74LSシリーズでは、入力に何も接続なし
でも、Hとされるので、入力処理を省いてます。
I/Oのアドレスデコーダから、8255を2個使っている
ので、一方を00hから03h、もう一方を04hから07hに
アサインして処理します。
P82550A EQU 90h
P82550B EQU 91h
P82550C EQU 92h
P82550R EQU 93h
P82551A EQU 94h
P82551B EQU 95h
P82551C EQU 96h
P82551R EQU 97h
8255の入出力を次のようにして、スイッチ入力
LED出力に決めて、動作テストします。
P82550A(input) switches
P82550B(output) LEDs(echo switch state)
P82550C(output) LEDs(echo switch inverse state)
P82551A(input) switches
P82551B(output) LEDs(echo switch state)
P82551C(output) LEDs(echo switch inverse state)
8255初期化は、ポートAのみ入力で、ポートB、Cを
出力に設定します。
INIT_8255:
push bc
push af
; set control register address
ld c,P82550R
ld b,P82551R
; set control word
ld a,80h
out (c),a
; resume address #1
ld c,b
; set control word
out (c),a
;
pop af
pop bc
ret
ポートAの入力値をポートBには、そのまま出力し
ポートCには反転して出力します。
main:
; set I/O address
ld c,P82550A
ld d,P82550B
ld e,P82550C
; get information #0 8255
in a,(c)
; echo
ld c,d
out (c),a
; inverse
cpl
; echo
ld c,e
out (c),a
; set I/O address
ld c,P82551A
ld d,P82551B
ld e,P82551C
; get information #1 8255
in a,(c)
; echo
ld c,d
out (c),a
; inverse
cpl
; echo
ld c,e
out (c),a
;
jr main
まとめると、以下。
STKTOP EQU 0h
P82550A EQU 90h
P82550B EQU 91h
P82550C EQU 92h
P82550R EQU 93h
P82551A EQU 94h
P82551B EQU 95h
P82551C EQU 96h
P82551R EQU 97h
org 0h
start:
ld hl,STKTOP
ld sp,hl
jp main
org 100h
main:
; set I/O address #0 8255
ld c,P82550A
ld d,P82550B
ld e,P82550C
; get information #0 8255
in a,(c)
; echo
ld c,d
out (c),a
; inverse
cpl
; echo
ld c,e
out (c),a
; set I/O address #1 8255
ld c,P82551A
ld d,P82551B
ld e,P82551C
; get information #1 8255
in a,(c)
; echo
ld c,d
out (c),a
; inverse
cpl
; echo
ld c,e
out (c),a
;
jr main
INIT_8255:
push bc
push af
; set control register address
ld c,P82550R
ld b,P82551R
; set control word
ld a,80h
out (c),a
; resume address #1
ld c,b
; set control word
out (c),a
;
pop af
pop bc
ret
end
8255とスイッチ、LEDの接続は、以下。
8251初期化
8251の初期化では、通信する前に内部レジスタに
入っているゴミを追い出すことが必要です。
データをパラレルからシリアルに変換するために
クロックが必要になります。通信速度を決定する
ために、分周回路が用意します。
分周回路は、カウンタでよいので4040を利用します。
通信速度の16倍のクロックを利用するので、1200bps
から9600bpsで、周波数がどの程度になればよいかを
計算しておきます。
AWKを利用して計算すると、以下となりました。
- 1200 → 19,200Hz
- 2400 → 38,400Hz
- 4800 → 76,800Hz
- 9600 → 153,600Hz
6MHzをシステムクロックにしているので
Z80CTCをタイマーモードにし、源になる
クロックを生成します。
8251のピンアサインは、以下。
(DTRとDSR、CTSとRTSを直結します。)
シリアルインタフェースのための回路は、トランジスタ
を利用した簡易回路で対応します。
トランジスタは、小信号のNPNであれば、何でもよいです。
8255と8251は、拡張基板の上に実装してありますが
Z80CTCは、Z80を実装した基板上にあります。
Z80CTCの動作をテストするプログラムを作成します。
CTCは、ZC/TO0、ZC/TO1、ZC/TO2の3出力に異なる
周波数のクロックを出力してチェックします。
CPUが利用しているクロックが6MHzなので、分周してと
考えましたが、4MHzのシステムクロックを利用すると
なっているので、2分周して使います。
2分周は、フリップフロップ74LS74で実現します。
3MHzをZ80CTCのφに接続して、次のように設定します。
ZC/TO0 prescaler:1/16 time constant:256 (732Hz)
ZC/TO1 prescaler:1/256 time constant:128 (92Hz)
ZC/TO2 prescaler:1/256 time constant:256 (45Hz)
CTCをタイマーモードを利用します。
CTCの制御レジスタには、次の項目を指定。
割込み 0:割込みなし 1:割込みあり
モード 0:タイマーモード 1:カウンターモード
プリスケーラ 0:1/16 1:1/256
パルスエッジ 0:falling 1:rising
起動指示 0:自動 1:トリガーパルス (タイマーモードでのみ有効)
定数 0:時間定数書込みなし 1:時間定数書込みあり
リセット 0:時間定数書込み無視 1:時間定数書込みまで待機
制御ワード 1:チャネル制御語指定
割込みを使わなければ、各チャネルの初期化は
次の手順を踏みます。
制御ワードライト
時間定数ライト
このシーケンスをチャネル回数だけ繰り返します。
制御ワードと時間定数を定義して、OUT命令で転送です。
CTCのI/Oアドレスは、次のように定義。
CTC_C0 EQU 80H
CTC_C1 EQU 81H
CTC_C2 EQU 82H
CTC_C3 EQU 83H
チャネル0から2までの制御ワードと時間定数を定義します。
C0INI EQU 15H ; 00010101
C0TCNT EQU 00H ; 00000000(256)
C1INI EQU 35H ; 00110101
C1TCNT EQU 80H ; 10000000(128)
C2INI EQU 35H ; 00110101
C2TCNT EQU 00H ; 00000000(256)
ここまで定義したなら、ダイナミックストップで
Z80CTCだけが動くようにします。
SENT EQU 0E000h
STKT EQU 0000h
; CTC I/O address
CTC_C0 EQU 80H
CTC_C1 EQU 81H
CTC_C2 EQU 82H
CTC_C3 EQU 83H
; CTC control word and time constant
C0INI EQU 15H ; 00010101
C0TCNT EQU 00H ; 00000000(256)
C1INI EQU 35H ; 00110101
C1TCNT EQU 80H ; 10000000(128)
C2INI EQU 35H ; 00110101
C2TCNT EQU 00H ; 00000000(256)
org 0h
ld sp,STKT
jp start
org 100h
start:
call INIT_CTC
main:
;
nop
;
jr main
;*****************************
INIT_CTC:
push af
push bc
; CTC channel 0
ld a,C0INI
ld c,CTC_C0
out (c),a
ld a,C0TCNT
out (c),a
; CTC channel 1
ld a,C1INI
ld c,CTC_C1
out (c),a
ld a,C1TCNT
out (c),a
; CTC channel 2
ld a,C2INI
ld c,CTC_C2
out (c),a
ld a,C2TCNT
out (c),a
;
pop bc
pop af
ret
end
手持ちのROMは、27128がありました。
アクセスタイムを見ると250nsです。
6MHzで動いているZ80CPUでは、命令を取出すときの
タイミングが間に合いません。
nWAITを利用して、2回ウェイトを入れます。
M1信号で命令を取出すフェーズになるので、この
信号を利用して、シフトレジスタでシーケンサを
作っておきます。
シーケンサは、M1が'L'になったなら、状態値を00→01と
変化させ、01→11→10→00とクロックごとに状態変化し
00で停止します。00となったときには、M1が'H'になって
いるので、'L'になるまで待機します。
タイミングチャートでみると、次のようになります。
- a M1の正論理値をラッチし、Q0は'H'、その反転でnWAITを'L'に
- b T2のfalling_edgeで、nWAITの'L'を検出し、つぎはTwに入る
- c Twのrising_edgeで、(Q1,Q0)=(H,H)に、nWAITを'L'のまま
- d Q1の反転でD0は'L'になっているので、Twのrising_edgeで(Q1,Q0)=(H,L)に
- e Twのfalling_edgeで、nWAITの'H'を検出し、つぎはT3に入る
- f (D1,D0)=(L,L)になったので、T3のrising_edgeで(Q1,Q0)に反映できる
- g T3のrising_edgeで(Q1,Q0)=(L,L)に、D0はM1信号が落ち着くと'L'に
- h T4のrising_edgeで、D0はM1信号が'L'になっているので、(Q1,Q0)=(L,L)を維持
外付けシーケンサは、M1信号だけで反応するので、通常の
リードサイクルには、影響しません。
シーケンサは、デジタル回路でマイコンのような確定した
動作をさせるために使います。
WAIT回路は、シーケンサがとる4状態(00、01、11、10)を
00→01→11→10と動かすときに、00で止めておいてM1信号
をトリガーにして00→01と状態遷移させます。01へと状態
遷移してしまうとクロックが入る度に、01→11→10→00と
状態を変えます。00に戻ると、M1信号がディセーブルに
なっているので、そこでストップモーションを繰返す仕様
にしました。M1信号が入らないと、00を保持しています。
リードサイクルでは、次のタイミングチャートになります。
6MHzでZ80CPUが動作すると、1周期は167nsになります。
アクセスタイムが250nsで問題がないかを計算してみます。
T1のfalling_edgeで、nMREQ、nRD信号がイネーブルになり
T2のrising_edgeまで83nsほど時間があります。
アドレスデコーダで83nsの半分の時間を使うとして40ns。
T3のrising_edgeまでには、167ns+40ns=207nsに。
T3のfalling_edgeまでには、207ns+83ns=283nsとなり
アクセスタイムが250nsでも30nsの余裕があります。
この計算は、ワーストケースなので30nsより大きい50ns
程度の余裕があり、充分データをROMから取出せます。
T3のfalling_edgeの30ns前にデータは確定しているので
セットアップタイムを確保できます。
この処理のために外付け回路を半田付けした後
手書きの回路図を見ると、Z80CTCからタイマー
割込みをかけるようになっていました。
Z80CTC、Z80PIOのIEI、IEOを接続してディジー
チェインで、割込みの優先順位をZ80CTC→Z80PIO
#1→Z80PIO#2→Z80PIO#3となっていました。
Z80CTCのZC/TO、CLK/TKの接続は、以下。
外部のCMOS4040で、64分周しています。
4040の出力クロックを利用し、チャネル
1、2、3では、カウンタモードで分周
していけます。チャネル3で割込み処理
ができるように設計されています。
チャネル0は、カウンタモードで動作させ
ZC/TO_0からクロックを出力できます。
4040で64分周するので、チャネル1に入る
クロックは、次式で計算できます。
φを、プリスケーラで1/16か1/256。
カウンタでの分周は、2から256。
φx1/16x(1/2から1/256)
φx1/256x(1/2から1/256)
φは4MHzで設計されていたので、プリスケーラ1/16とし
250分周すると、1kHzを生成できます。
チャネル1から3は、カウンタモードで動作させるので
分周比を2から256までの値から選んで組み合わせると
相当細かい精度をもったタイマー割込みを発生させられ
ます。
φを3MHzとして、プリスケーラを1/16に選び
75分周すると、ZC/TO_0からは2500Hzを出力
できます。
WonderKit基板に50ピンのコネクタを半田付けし
外部基板と接続できるようにし、この基板上に
WAIT回路を入れることにします。
50ピンの信号は、以下となっています。
50 A11 49 A10
48 A12 47 A9
46 A13 45 A8
44 A14 43 A7
42 A15 41 A6
40 φ 39 A5
38 D4 37 A4
36 D3 35 A3
34 D5 33 A2
32 D6 31 A1
30 Vcc 29 A0
28 D2 27 GND
26 D7 25 nRFSH
24 D0 23 nM1
22 D1 21 nRESET
20 nINT 19 nBUSRQ
18 nNMI 17 nWAIT
16 nHALT 15 nBUSAK
14 nMREQ 13 nWR
12 nIORQ 11 nRD
10 GND 9
8 GND 7 nSYSTEM_RESET
6 (nY7) 5 (nY6)
4 (nY5) 3 (nY4)
2 Vcc 1 Vcc
11から50に、Z80の信号をそのまま接続
してあります。In Circuit Emulatorを
接続するには、適した配置でしょう。
3から6のnY4からnY7は、I/Oのアドレス
デコーダのnCS信号をジャンパー線で接続
しました。
nY4からnY7を利用すると、4つのI/Oを確保
できることになります。
8255、8251を接続するには最適です。
8255、8251のリセットは、正論理なので
nRESETをトランジスタで反転しRESETに
します。
インバータなら、74LS04や74LS14で充分
ですが、14ピンのICをひとつの反転処理
に利用すると、5ゲートが余ってしまう
ので、不経済です。こういう場合、安価
に入手できるNPNトランジスタを使います。
目次
前
次