この章では、MSX turbo Rに新しく内蔵されているハードウェアについて説明します。
7.1 システムタイマー
R800は、命令の実行時間が一定ではないので、CPUの命令実行時間から、ウェイトのタイミングなどをとることができません。そこで、MSX turbo Rでは、数10μ秒〜数10m秒程度の短い時間の検出ができるように、システムタイマーが追加されました。
システムタイマーは、16ビットのクリア・データ読み出しが可能なカウンタで、10.738635MHzのシステムクロックを42分周(10.738635MHz/42=255.68KHz)したクロックでカウントアップされます。つまり、最下位ビットは3.911μ秒毎にカウントアップされることになります。なお、カウンタをクリアしてからカウントが1になるまでの時間は、0〜3.911μ秒の範囲です。
カウンタの読み出し時に、データのラッチ機能はありません。カウンタの上位・下位読み出しの間にクロックが入ると、正しいカウント値が読み出されないので注意して下さい。
表1.6 システムタイマーのI/Oポート
| I/Oポート番地 | R/W | 機能 |
| 0E6H | W | 任意のデータを書き込むと、カウンタがクリアされる。 |
| 0E6H | R | カウンタデータの下位8ビットの読み出し。 |
| 0E7H | R | カウンタデータの上位8ビットの読み出し。 |
割り込みルーチンなどから呼ばれるプログラムは、カウンタをクリアすると、フォアグラウンドで動作しているプログラムに影響を与えるので、クリアしないで下さい。
具体的には、次のサンプルプログラムのようにします。
countlow equ 0e6h ; カウンタ下位8ビット
counthigh equ 0e7h ; カウンタ上位8ビット
.z80
;
; Bレジスタで指定された時間待つ。
; 待つ時間は、B*3.911μ秒
; 誤差は、-3.911μ秒〜+0μ秒
; 0を指定してはいけない。
; 割り込みは禁止されていなければならない。
; C,A,Fの各レジスタは破壊される。
;
wait:
in a,(countlow) ; カウンタの現在値を得る
ld c,a ; それを保存する
wait_loop:
in a,(countlow) ; カウンタの現在値を得る
sub c ; 経過時間を算出する
cp b ; 指定された時間経過したか?
jr c,wait_loop ; 経過していなければループする
ret
7.2 PCM
ここでは、PCMのI/Oポートや録音・再生の手順などを解説します。
7.2.1 PCMのI/Oポート
PCM録音・再生のためのI/Oポートは以下のとおりです。
表1.7 PCMのI/Oポート
| 番地 | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
| 0A5H(Write) | 0 | 0 | 0 | SMPL | SEL | FILT | MUTE | ADDA |
| 0A5H(Read) | COMP | 0 | 0 | SMPL | SEL | FILT | MUTE | BUFF |
| 0A4H(Write) | DA7 | DA6 | DA5 | DA4 | DA3 | DA2 | DA1 | DA0 |
| 0A4H(Read) | 0 | 0 | 0 | 0 | 0 | 0 | CT1 | CT0 |
| ADDA(BUFF) | バッファモード | ||
| D/Aコンバータの出力をシングルバッファにするか、ダブルバッファにするかを指定します。D/A時にはダブルバッファに、A/D時にはシングルバッファにして下さい。 | |||
| 0 | シングルバッファ(A/D時、リセット時) | ||
| 1 | ダブルバッファ(D/A時) | ||
| MUTE | ミューティング制御 | ||
| システム全体の音声出力をON/OFFします。 | |||
| 0 | 音声出力OFF(リセット時) | ||
| 1 | 音声出力ON | ||
| FILT | サンプル・ホールド回路入力信号の選択 | ||
| A/D時にサンプル・ホールド回路に入力する信号を、フィルタの出力信号にするか、基準信号(ground level)にするかを選択します。 | |||
| 0 | 基準信号(リセット時) | ||
| 1 | フィルタ出力信号 | ||
| SEL | フィルタ入力信号の選択 | ||
| ローパスフィルタに入力する信号を、D/Aコンバータの出力信号にするか、マイクアンプの出力信号にするかを選択します。 | |||
| 0 | D/Aコンバータ出力信号(リセット時) | ||
| 1 | マイクアンプ出力信号 | ||
| SMPL | サンプルホールド信号 | ||
| 入力信号をサンプルするか、ホールドするかを選択します。 | |||
| 0 | サンプル時(リセット時) | ||
| 1 | ホールド時 | ||
| A/D時には、信号をホールドする前に、最低7μ秒はサンプルしなければなりません。 | |||
| COMP | コンパレータの出力信号 | ||
| サンプル・ホールドの出力信号と、D/Aコンバータの出力信号とをくらべて、どちらが大きいかを読み出すことができます。 | |||
| 0 | D/A出力>サンプル・ホールド出力 | ||
| 1 | D/A出力<サンプル・ホールド出力 | ||
| DA7〜DA0 | D/A出力データ | ||
| CT1、CT0 | カウンタデータ | ||
| 63.5μ秒ごとにカウントアップされます。 | |||
| D/A時(ADDAが1)には、カウントアップに同期して、0A4H番地に書かれたデータが繰り返し出力されます。0A4H番地にデータを書き込むと、カウンタはクリアされます。 | |||
| A/D時(ADDAが0)には、0A4H番地に書かれたデータはすぐに出力されます。0A4H番地にデータを書き込んでもカウンタはクリアされません。 | |||
7.2.2 PCM再生
PCMは次の手順で再生します。
- ADDAを1に、MUTEを1に、SELを0にします(I/Oポートの0A5H番地に00000011Bを出力する)。
- CT1、CT0を読んで、サンプリング周期を検出します。
- PCMデータを出力します。このとき、カウンタは自動的にクリアされます。
- データの個数回、2と3とを繰り返します。
.z80
;
; PCM再生
;
; 入力 HL = PCMデータの開始アドレス
; BC = PCMデータの長さ
; E = 再生サンプリング周期
; 1 15.75KHz
; 2 7.875KHz
; 3 5.25KHz
; 戻り値 なし
pcmdac equ 0a4h ; D/A コンバータ (Write)
pcmcnt equ 0a4h ; カウンタ (Read )
pcmcntl equ 0a5h ; PCMコントロール(Write)
pcmstat equ 0a5h ; PCMステータス (Read )
pcmplay:
ld a,00000011b
out (pcmcntl),a ; D/Aモードに設定
di ; タイミングの正確さのために、
; 割り込みを禁止する
pcmplay_loop:
in a,(pcmcnt) ; カウンタを読み取る
sub e ; 希望の値になったか?
jr c,pcmplay_loop ; そうでないならループする
ld a,(hl) ; データを読み取る
out (pcmdac),a ; DACに出力する
inc hl ; 次にデータを指し示す
dec bc ; カウンタを減らす
ld a,c ; カウンタは0か?
or b
jr nz,pcmplay_loop ; そうでないならループする
ei ; 割り込み禁止を解除
ret
7.2.3 PCM録音
PCM録音は次の手順で行います。
- ADDAを0に、MUTEを0に、FILTを1に、SELを1に、SMPLを0にします(I/Oポートの0A5H番地に00001100Bを出力して、入力アナログ信号をサンプルする)。
- CT1、CT0を読んで、サンプリング周期を検出します。
- 最低7μ秒待ちます。この7μ秒が2に含まれていれば待つ必要はありません。
- SMPLを1にして(I/Oポートの0A5H番地に00011100Bを出力する)、入力アナログ信号をホールドします。
- 逐次変換のシーケンスによって、D/Aコンバータのデータを上位ビットから変化させながら、D/Aコンバータ出力と入力アナログ信号との比較結果をCOMPから読み込んで、各ビットを決定し、データを格納します。
- SMPLを0にします(I/Oポートの0A5H番地に00001100Bを出力する)。
- 2から6を繰り返します。
.z80
;
; PCM録音
;
; 入力 HL = PCMデータの開始アドレス
; BC = PCMデータの長さ
; E = 再生サンプリング周期
; 1 15.75KHz
; 2 7.875KHz
; 3 5.25KHz
; 戻り値 なし
pcmdac equ 0a4h ; D/A コンバータ
pcmcnt equ 0a4h ; カウンタ
pcmcntl equ 0a5h ; PCMコントロール
pcmstat equ 0a5h ; PCMステータス
; 1ビットA/D変換マクロの定義
adconv macro next_bit,strip
local adconv_not_change
out (pcmdac),a ; データを出力
db 0edh,70h ; PCMSTATからデータを読み込み、
; フラグにのみ反映させる
jp m,adconv_not_change ; 入力アナログ信号の方が大きければ、
; データはそのまま
and strip ; 入力アナログ信号の方が小さいので、
; ビットを0にする
adconv_not_change:
or next_bit ; 次のビットを1にする
endm
pcmrec:
ld a,00001100b
out (pcmcntl),a ; A/Dモードに設定
ld d,0 ; カウンタ検出の初期値を設定する
di ; タイミングの正確さのために
; 割り込みを禁止する
pcmrec_loop:
in a,(pcmcnt) ; カウンタを読み取る
cp d ; 希望の値になったか?
jr nz,pcmrec_loop ; そうでないならループする
add a,e ; 次のカウンタの値を作る
and 11b
ld d,a ; それを保存する
; 上記ループにより7μ秒を満足する
exx
ld a,00011100b
out (pcmcntl),a ; データをホールドする
ld c,pcmstat ; COMPビットのポートアドレスを設定する
ld a,80h ; 出荷データを設定する
adconv 01000000b,01111111b ; 順次ビットを変換する
adconv 00100000b,00111111b
adconv 00010000b,01011111b
adconv 00001000b,01101111b
adconv 00000100b,01110111b
adconv 00000010b,01111011b
adconv 00000001b,01111101b
adconv 00000000b,01111110b
exx
ld (hl),a ; データを格納する
ld a,00001100b
out (pcmcntl),a ; データのホールドを解除する
inc hl ; 次のデータを指し示す
dec bc ; カウンタを減らす
ld a,c ; カウンタは0か?
or b
jr nz,pcmrec_loop ; そうでないならループする
ld a,00000011b
out (pcmcntl),a ; D/Aモードに設定。MUTEを解除する
ei ; 割り込み禁止を解除
ret
| 注意 | このプログラムは、Z80では速度が間に合わない場合があります。 |