Z80ボードによるハードテスト
手元には、使わなくなったZ80ボードが4つほどあります。
SRAMは、32kバイトの容量を持つので、ちょっとした処理なら
簡単に実装できます。このSRAM容量の大きさを使い、ハード
テストをしてみました。
CPUであるZ80の能力を最大限に引き出すには、アセンブリ言語
を利用するのが、最もよいのですが、ファームウエアデバッグ
が面倒なので、C言語を利用してテストします。
Z80CPU用コンパイラは、HitechCを持っていますが、SDCCなる
フリーのCコンパイラが気になっていたので、これを使います。
Z80CPUボードは、地元の梅澤無線電機が販売しているUECを
利用します。
UECに利用されているZ80は、東芝のZ84C015です。
内蔵モジュールは、PIO、CTC、SIOで、Z80ファミリとなって
います。
Z80ファミリのペリフェラルは、モード2割込みを利用できる
ので、AVRやARMのようなマイコンに似たファームウエアを構成
できます。
ハードウエアテストなので、割込みを極力使わない方針をとります。
LEDテスト
制御基板には、個別LEDを載せているので、このLEDの点灯テスト
により、配線が正しいのかをテストします。
LEDテストの定番と言えば、Knight2000のエンブレムにある
左右のランプ点灯。これを考えます。
Cでは、配列が使えるので、7つのパターンを入れて
ループで回せば、Knight2000のエンブレム点灯処理
を実現できます。
ファームウエアを作成する前に、CUIで利用できる
Cコンパイラを使い、動作テストします。
データパターンを作るのが面倒なので、AWKを
使い、16進のパターンを作成します。
AWKスクリプトは、以下としました。
# mkdat.awk
{
result = 0 ;
for ( i = 1 ; i < 9 ; i++ ) {
result *= 2 ;
result += $i;
}
printf("%s => 0x%02x\n",$0,result);
}
データパターンは、次のコードをテキスト
ファイルに格納して対応します。
1 0 0 0 0 0 0 1
0 1 0 0 0 0 1 0
0 0 1 0 0 1 0 0
0 0 0 1 1 0 0 0
0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0
AWKスクリプトで生成すると、データパターンは
次のようになります。この16進部分を使います。
1 0 0 0 0 0 0 1 => 0x81
0 1 0 0 0 0 1 0 => 0x42
0 0 1 0 0 1 0 0 => 0x24
0 0 0 1 1 0 0 0 => 0x18
0 0 1 0 0 1 0 0 => 0x24
0 1 0 0 0 0 1 0 => 0x42
typedef unsigned char UBYTE ;
UBYTE bpat[6] = {0x81,0x42,0x24,0x18,0x24,0x42};
データをポートBから出力するとして
PIOBに、上で定義済データを出力する
コードを考えます。
シーケンスは、以下とします。
- ビットパターンを配列から取得
- PIOBにデータ出力
- 遅延
- 配列に入っているデータ位置を+1
- データ位置が6であれば、0に戻す
- 1に戻る
シーケンスは、ステートマシンと同じなので
変数stateを用意して、動作を決めます。
#define LAST 6
state = 0 ;
while ( ON ) {
/* impress */
PIO_BD = *(bpat+state) ;
/* delay */
swait();
/* update */
state++ ;
/* judge */
if ( state == LAST ) { state = 0 ; }
}
遅延は、関数を用意して実現します。
#define SLAST 256
void swait(void)
{
UWORD loop ;
for ( loop = 0 ; loop < SLAST ; loop++ ) {}
}
実機での動作が速すぎる場合、遅延を担当
する関数を何度か動かすように変更します。
I/Oの初期化は、関数を用意して対応します。
void init_pio(void)
{
/* set control code */
/* set mode 0 (channel A) */
PIO_AC = 0x0f ;
/* no interrupt (channel A) */
PIO_AC = 0x03 ;
/* set mode 0 (channel B) */
PIO_BC = 0x0f ;
/* no interrupt (channel B) */
PIO_BC = 0x03 ;
}
SDCCでは、sfr(special function register)という
概念でI/O関係のレジスタをアクセスします。
sfr指定で、次のようにI/O関係レジスタを定義します。
sfr at 0x1C PIO_AD ;
sfr at 0x1D PIO_AC ;
sfr at 0x1E PIO_BD ;
sfr at 0x1F PIO_BC ;
sfr指定は、Cソースコードの中に入れるだけで
よいようです。
Cでは、スタートアップルーチンで様々な設定を
するのが、お約束です。H8やAVRマイコンの使い
勝手に近いコンパイル環境が欲しいので、スタート
アップルーチンは、次のように定義しました。
.globl _main
;.org #0x0000
ld SP,#0x0000
call _main
ret
スタックポインタを設定後、即座にCのmain関数
に分岐します。Cのmain関数内部で、I/Oその他を
初期化します。
スタートアップルーチンのmycrt.asmはas-z80を利用し
オブジェクトファイルにして使っています。
ここまでの内容で、LEDをテストするCソースコード
は、次のようにまとめられます。
/* define my system I/O area */
sfr at 0x1C PIO_AD ;
sfr at 0x1D PIO_AC ;
sfr at 0x1E PIO_BD ;
sfr at 0x1F PIO_BC ;
/* define data types */
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
/* define constant values */
#define OFF 0
#define ON OFF+1
#define LAST 6
#define SLAST 256
/* define bit patter */
UBYTE bpat[6] = {0x81,0x42,0x24,0x18,0x24,0x42};
/* function prototype */
void init_pio(void);
void swait(void);
void main(void)
{
UBYTE state ;
/* initialize PIO */
init_pio();
/* flash LED */
state = 0 ;
while ( ON ) {
/* impress */
PIO_BD = *(bpat+state) ;
/* delay */
swait();
/* update */
state++ ;
/* judge */
if ( state == LAST ) { state = 0 ; }
}
}
void init_pio(void)
{
/* set control code */
/* set mode 0 (channel A) */
PIO_AC = 0x0f ;
/* no interrupt (channel A) */
PIO_AC = 0x03 ;
/* set mode 0 (channel B) */
PIO_BC = 0x0f ;
/* no interrupt (channel B) */
PIO_BC = 0x03 ;
}
void swait(void)
{
UWORD loop ;
for ( loop = 0 ; loop < SLAST ; loop++ ) {}
}
コンパイル、リンクには、次のバッチファイルを
利用しています。
d:\sdcc\bin\sdcc %1.c -mz80 --code-loc 0x0100 --no-std-crt0 -Wlmycrt.o
copy %1.ihx %1.hex
del %1.ihx
ROMライターが受付けるHEXファイルは、拡張子がHEX
なので、ihxからhexコピーで変換しています。
(under construction)
目次
前
次