目次

ハードウエアテスト

 今回利用するUEC、AKI80にはZ84C15が使われています。

 Z84C15には、次のペリフェラルが内蔵されています。

 他に、基板上に8080ファミリの8255があります。

 これらのペリフェラルをテストします。

 手元に、8ビットのスイッチボードとLEDボードが
 あるので、これを利用し、なるべく簡単にテスト
 します。



 このスイッチLEDボードとZ80ボードとは、10ピン
 ケーブルで接続します。



 Z80ボードに用意したコネクタは、次のように
 ピン配置を決めてあります。
  1. +5V
  2. PD7
  3. PD6
  4. PD5
  5. PD4
  6. PD3
  7. PD2
  8. PD1
  9. PD0
  10. 0V
 コネクタを介して、電源を他のハードウエアに  供給できるようにしてあります。  8ビットの入出力ピンを、接続ハードウエアに  合わせて使えるようにします。

Z80PIO関係テスト

 Z80PIOには、A、Bの2チャネルがあるので  ともに出力にし、LEDボードの8個のLEDの  点滅で、PIOをテストします。  テストプログラムは、次の仕様とします。  PIOをモード0で利用し、0〜255の数値を  8ビットで出力します。  アセンブリ言語で短く記述します。  アセンブラは、システムロードのXA80を使います。  0番地に100h番地に分岐するコードをおき  100h番地から動かします。  CP/M80のメモリの使い方と同じにし、テスト  しやすくします。  初期化をINIT_PIO、LEDの点滅をLED_FLASHという  サブルーチンで実現するとして、TOPレベルコード  を記述します。 STACKB EQU 0 org 0h jp start org 100h start: ld sp,STACKB call INIT_PIO main: call LED_FLASH jp main  Z84C15に内蔵されているZ80PIOのデータ、制御  レジスタのアドレスを、ラベル定義します。   PIO_AD EQU 1CH   PIO_AC EQU 1DH   PIO_BD EQU 1EH   PIO_BC EQU 1FH  Z80PIOを初期化します。  2つのチャネルを、モード0で利用するため  制御レジスタに、制御ワード0fをライトします。  さらに、割込みを使わないように、制御ワード  03をライトします。  DEレジスタペアに、030fを格納して、一時メモリ  として利用します。 INIT_PIO: push de push bc push af ; set control code ld de,030fh ; PIO A control ld c,PIO_AC ; set mode 0 (channel A) ld a,e out (c),a ; no interrupt (channel A) ld a,d out (c),a ; PIO B control ld c,PIO_BC ; set mode 0 (channel B) ld a,e out (c),a ; no interrupt (channel B) ld a,d out (c),a ; pop af pop bc pop de ret  LEDに、8ビットのパターンを出力します。  Bレジスタをカウンタで利用し255〜0まで  変化させます。Bレジスタの値を、Aレジスタ  に転送し、Aレジスタの値をPIOの2チャネルに  出力します。  Bレジスタをカウンタと割当てると、DJNZ命令を  使えます。 LED_FLASH: push bc push af ; set counter ld b,BMAX LED_FLASH_L: ; set channel A port ld c,PIO_AD ld a,b out (c),a ; wait call SWAIT call SWAIT call SWAIT call SWAIT call SWAIT ; set channel B port ld c,PIO_BD ld a,b out (c),a ; wait call SWAIT call SWAIT call SWAIT call SWAIT call SWAIT ; djnz LED_FLASH_L ; pop af pop bc ret  マイコンは、高速で動作するため、点滅が確認  できるように、空ループで無駄時間を作ります。  無駄時間は、SWAITサブルーチンで生成します。 SWAIT: push bc push af ; ld b,BMAX SWAITL: nop djnz SWAITL ; pop af pop bc ret  まとめます。 PIO_AD EQU 1CH PIO_AC EQU 1DH PIO_BD EQU 1EH PIO_BC EQU 1FH STACKB EQU 0 BMAX EQU 255 org 0h jp start org 100h start: ld sp,STACKB call INIT_PIO main: call LED_FLASH jp main INIT_PIO: push de push bc push af ; set control code ld de,030fh ; PIO A control ld c,PIO_AC ; set mode 0 (channel A) ld a,e out (c),a ; no interrupt (channel A) ld a,d out (c),a ; PIO B control ld c,PIO_BC ; set mode 0 (channel B) ld a,e out (c),a ; no interrupt (channel B) ld a,d out (c),a ; pop af pop bc pop de ret LED_FLASH: push bc push af ; set counter ld b,BMAX LED_FLASH_L: ; set channel A port ld c,PIO_AD ld a,b out (c),a ; wait call SWAIT call SWAIT call SWAIT call SWAIT call SWAIT ; set channel B port ld c,PIO_BD ld a,b out (c),a ; wait call SWAIT call SWAIT call SWAIT call SWAIT call SWAIT ; djnz LED_FLASH_L ; pop af pop bc ret SWAIT: push bc push af ; ld b,BMAX SWAITL: nop djnz SWAITL ; pop af pop bc ret end  このテストで、コネクタとZ84C15の接続が  正しいかを確認できます。  また、I/Oアドレスを正しく利用しているかを  確認できます。  出力を確認できたので、入出力をテストします。  Aチャネルを出力、Bチャネルを入力にします。  Aチャネルには、8ビット分のLEDを接続し  Bチャネルには、8ビット分のプッシュスイッチ  を接続して、入出力をテストします。  Bチャネルを入力に設定する制御ワードを  考えます。  入力はモード1になるので、2進数01??1111を  制御レジスタに設定します。  ??は、0でも1でも構わないので01001111と  します。  A、Bチャネルの制御ワードを設定するサブルーチン  は、次のようになります。 INIT_PIO: push de push bc push af ; set control code ld de,030fh ; PIO A control ld c,PIO_AC ; set mode 0 (channel A) ld a,e out (c),a ; no interrupt (channel A) ld a,d out (c),a ; set control code ld de,034fh ; PIO B control ld c,PIO_BC ; set mode 1 (channel B) ld a,e out (c),a ; no interrupt (channel B) ld a,d out (c),a ; pop af pop bc pop de ret  Bチャネルから入力した情報を、そのまま  Aチャネルに転送する処理を、無限ループ  で繰返します。 main: ; get data from PIO_B ld c,PIO_BD in a,(c) ; wait call SWAIT ; put data to PIO_A ld c,PIO_AD out (c),a ; wait call SWAIT ; jp main  まとめます。 PIO_AD EQU 1CH PIO_AC EQU 1DH PIO_BD EQU 1EH PIO_BC EQU 1FH BMAX EQU 255 STACKB EQU 0 org 0h jp start org 100h start: ld sp,STACKB call INIT_PIO main: ; get data from PIO_B ld c,PIO_BD in a,(c) ; wait call SWAIT ; put data to PIO_A ld c,PIO_AD out (c),a ; wait call SWAIT ; jp main INIT_PIO: push de push bc push af ; set control code ld de,030fh ; PIO A control ld c,PIO_AC ; set mode 0 (channel A) ld a,e out (c),a ; no interrupt (channel A) ld a,d out (c),a ; set control code ld de,034fh ; PIO B control ld c,PIO_BC ; set mode 1 (channel B) ld a,e out (c),a ; no interrupt (channel B) ld a,d out (c),a ; pop af pop bc pop de ret SWAIT: push bc push af ; ld b,BMAX SWAITL: nop djnz SWAITL ; pop af pop bc ret  AチャネルとBチャネルの役割を入れ替えて  テストします。 PIO_AD EQU 1CH PIO_AC EQU 1DH PIO_BD EQU 1EH PIO_BC EQU 1FH STACKB EQU 0 BMAX EQU 255 org 0h jp start org 100h start: ld sp,STACKB call INIT_PIO main: ; get data from PIO_A ld c,PIO_AD in a,(c) ; wait call SWAIT ; put data to PIO_B ld c,PIO_BD out (c),a ; wait call SWAIT ; jp main INIT_PIO: push de push bc push af ; set control code ld de,034fh ; PIO A control ld c,PIO_AC ; set mode 1 (channel A) ld a,e out (c),a ; no interrupt (channel A) ld a,d out (c),a ; set control code ld de,030fh ; PIO B control ld c,PIO_BC ; set mode 0 (channel B) ld a,e out (c),a ; no interrupt (channel B) ld a,d out (c),a ; pop af pop bc pop de ret SWAIT: push bc push af ; ld b,BMAX SWAITL: nop djnz SWAITL ; pop af pop bc ret end

8255テスト

 Z84C15には、8255を接続したので、3ポートを  出力に設定し、LEDボードの8個のLEDを点滅させ  テストします。  テストプログラムは、次の仕様とします。  8255の全ポートをモード0の出力で利用し  0〜255の数値を8ビットで出力します。  0番地に100h番地に分岐するコードをおき  100h番地から動かします。  CP/M80のメモリの使い方と同じにし、テスト  しやすくします。  初期化をINIT_8255、LEDの点滅をLED_FLASHという  サブルーチンで実現するとして、TOPレベルコード  を記述します。 org 0h jp start org 100h start: ld sp,STACKB call INIT_8255 main: call LED_FLASH jp main  8255のデータ、制御レジスタのアドレスを  ラベル定義します。   P55A EQU 00H   P55B EQU 01H   P55C EQU 02H   P55CTL EQU 03H  8255を初期化します。  8255では、入出力方向とモード指定は  制御レジスタの制御ワードだけでよい  ので、次のように書けます。 INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,80h out (c),a ; pop af pop bc ret  LEDに、8ビットのパターンを出力します。  Bレジスタをカウンタで利用し255〜0まで  変化させます。Bレジスタの値を、Aレジスタ  に転送し、Aレジスタの値を8255の3ポートに  出力します。  Bレジスタをカウンタと割当てると、DJNZ命令を  使えます。 LED_FLASH: push bc push af ; set counter ld b,BMAX LED_FLASH_L: ; load value ld a,b ; set port A address ld c,P55A out (c),a call SWAIT call SWAIT ; set port B address ld c,P55B out (c),a call SWAIT call SWAIT ; set port C address ld c,P55C out (c),a call SWAIT call SWAIT ; djnz LED_FLASH_L ; pop af pop bc ret  SWAITを無駄時間として、まとめます。 P55A EQU 00H P55B EQU 01H P55C EQU 02H P55CTL EQU 03H STACKB EQU 0 BMAX EQU 255 org 0h jp start org 100h start: ld sp,STACKB call INIT_8255 main: call LED_FLASH jp main INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,80h out (c),a ; pop af pop bc ret LED_FLASH: push bc push af ; set counter ld b,BMAX LED_FLASH_L: ; load value ld a,b ; set port A address ld c,P55A out (c),a call SWAIT call SWAIT ; set port B address ld c,P55B out (c),a call SWAIT call SWAIT ; set port C address ld c,P55C out (c),a call SWAIT call SWAIT ; djnz LED_FLASH_L ; pop af pop bc ret SWAIT: push bc push af ; ld b,BMAX SWAITL: nop djnz SWAITL ; pop af pop bc ret end  8255には、3ポートあるので入出力をテストしておきます。  1ポートを入力にし、他のポートは出力に設定します。  2つの出力ポートには、1ポートには、入力値そのものを  残りのポートには、入力値を反転した値を出力します。  の場合、初期化は、次のようになります。 INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,90h out (c),a ; pop af pop bc ret  入力値を出力する処理は、以下です。 SW_PROC: push de push bc push af ; set port A address ld c,P55A ld b,P55B ld e,P55C ; get switch state from port A in a,(c) ; put contents to port B ld c,b out (c),a ; inverse xor 0ffh ; put contents to port C ld c,e out (c),a ; pop af pop bc pop de ret  まとめます。 P55A EQU 00H P55B EQU 01H P55C EQU 02H P55CTL EQU 03H org 0h jp start org 100h start: ld a,(hl) call INIT_8255 main: call SW_PROC jp main INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,90h out (c),a ; pop af pop bc ret SW_PROC: push de push bc push af ; set port A address ld c,P55A ld b,P55B ld e,P55C ; get switch state from port A in a,(c) ; put contents to port B ld c,b out (c),a ; inverse xor 0ffh ; put contents to port C ld c,e out (c),a ; pop af pop bc pop de ret end  の場合、初期化は、次のようになります。 INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,82h out (c),a ; pop af pop bc ret  入力値を出力する処理は、以下です。 SW_PROC: push de push bc push af ; set port A address ld c,P55B ld b,P55A ld e,P55C ; get switch state from port B in a,(c) ; put contents to port A ld c,b out (c),a ; inverse xor 0ffh ; put contents to port C ld c,e out (c),a ; pop af pop bc pop de ret  まとめます。 P55A EQU 00H P55B EQU 01H P55C EQU 02H P55CTL EQU 03H org 0h jp start org 100h start: ld a,(hl) call INIT_8255 main: call SW_PROC jp main INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,82h out (c),a ; pop af pop bc ret SW_PROC: push de push bc push af ; set port A address ld c,P55B ld b,P55A ld e,P55C ; get switch state from port B in a,(c) ; put contents to port A ld c,b out (c),a ; inverse xor 0ffh ; put contents to port C ld c,e out (c),a ; pop af pop bc pop de ret end  の場合、初期化は、次のようになります。 INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,89h out (c),a ; pop af pop bc ret  入力値を出力する処理は、以下です。 SW_PROC: push de push bc push af ; set port A address ld c,P55C ld b,P55A ld e,P55B ; get switch state from port C in a,(c) ; put contents to port A ld c,b out (c),a ; inverse xor 0ffh ; put contents to port B ld c,e out (c),a ; pop af pop bc pop de ret  まとめます。 P55A EQU 00H P55B EQU 01H P55C EQU 02H P55CTL EQU 03H org 0h jp start org 100h start: ld a,(hl) call INIT_8255 main: call SW_PROC jp main INIT_8255: push bc push af ; set control address ld c,P55CTL ; set control word ld a,89h out (c),a ; pop af pop bc ret SW_PROC: push de push bc push af ; set port A address ld c,P55C ld b,P55A ld e,P55B ; get switch state from port C in a,(c) ; put contents to port A ld c,b out (c),a ; inverse xor 0ffh ; put contents to port B ld c,e out (c),a ; pop af pop bc pop de ret end

Z80CTC関係テスト

 Z80CTCには、4チャネルがあるので、タイマー  モードで、クロックを出力してテストします。  各チャネルのクロックを、周波数カウンタで  測定して、分周されていることを確認します。  全チャネルをタイマーモードにし、プリスケーラ  でソースクロックを1/16とした後、各カウンタに  分周比を設定します。  各チャネルの分周比を次のように設定します。
  1. チャネル0 128
  2. チャネル1  64
  3. チャネル2  32
  4. チャネル3  16
 初期化をINIT_CTCとして、無限ループで  CPUをダイナミックストップします。 STACKB EQU 0 org 0h jp start org 100h start: ld sp,STACKB call INIT_CTC main: nop jr main  Z80CTCの各チャネルのアドレスを  ラベル定義します。   CTC_C0 EQU 10H   CTC_C1 EQU 11H   CTC_C2 EQU 12H   CTC_C3 EQU 13H  Z80CTCを初期化します。  制御ワード、分周比の順でレジスタに  データを格納します。 INIT_CTC: push bc push af ; set default control word ld b,27h ; set channel 0 I/O address ld c,CTC_C0 ; set control word ld a,b out (c),a ; set divide count ld a,80h out (c),a ; set channel 1 I/O address ld c,CTC_C1 ; set control word ld a,b out (c),a ; set divide count ld a,40h out (c),a ; set channel 2 I/O address ld c,CTC_C2 ; set control word ld a,b out (c),a ; set divide count ld a,20h out (c),a ; set channel 0 I/O address ld c,CTC_C3 ; set control word ld a,b out (c),a ; set divide count ld a,10h out (c),a ; pop af pop bc ret  まとめます。 CTC_C0 EQU 10H CTC_C1 EQU 11H CTC_C2 EQU 12H CTC_C3 EQU 13H STACKB EQU 0 org 0h jp start org 100h start: ld sp,STACKB call INIT_CTC main: nop jr main INIT_CTC: push bc push af ; set default control word ld b,27h ; set channel 0 I/O address ld c,CTC_C0 ; set control word ld a,b out (c),a ; set divide count ld a,80h out (c),a ; set channel 1 I/O address ld c,CTC_C1 ; set control word ld a,b out (c),a ; set divide count ld a,40h out (c),a ; set channel 2 I/O address ld c,CTC_C2 ; set control word ld a,b out (c),a ; set divide count ld a,20h out (c),a ; set channel 0 I/O address ld c,CTC_C3 ; set control word ld a,b out (c),a ; set divide count ld a,10h out (c),a ; pop af pop bc ret end

Z80SIO関係テスト

 Z80SIOは、タイマー/カウンタ、割込み等が複雑に  絡み合って、はじめて動作するので、CTC、SIOへの  設定と割込み処理プログラムを記述してしまいます。  この後に、個々の処理が正しいことを確認します。 CTC0 EQU 10h CTC1 EQU 11h CTC2 EQU 12h CTC3 EQU 13h SIOAD EQU 18H SIOAC EQU 19H SIOBD EQU 1aH SIOBC EQU 1bH ;INT_SIO EQU 7f00h org 0h jp start org 100h start: call INIT_CTC_01 call INIT_SIO main: nop jr main INIT_SIO: push bc push af ; di ; disable interrupt im 2 ; select mode 2 interrupt ld hl,INT_SIO ld a,h ld i,a ; set upper 8 bit address to I register ; set control address ld c,SIOBC ; ld a,18h ; reset channel B out (c),a ld a,02h ; WR2 out (c),a ld hl,INT_SIO ; get interrupt vector ld a,l out (SIOBC),a ; set interrupt vector ld b,SIOBE-SIOB ; set number of data ld hl,SIOB ; set destination address otir ; set control address ld c,SIOBC ; ld a,18h ; reset channel A out (c),a ld b,SIOAE-SIOA ; set number of data ld hl,SIOA ; set destination address otir xor a ; A = 0 ld (_rx_putpa),a ; channel A initialize GET_POINTER ld (_rx_getpa),a ; channel A initialize PUT_POINTER ld (_rx_putpb),a ; channel B initialize GET_POINTER ld (_rx_getpb),a ; channel B initialize PUT_POINTER ; pop af pop bc ret INIT_CTC_01: push bc push af ; ; D7 0 disable interrupt ; D6 0 set timer mode ; D5 0 set presclaer (1/16) ; D4 0 inhibit timer wakeup with CLK/TG ; D3 0 start timer ; D2 1 set time constant ; D1 1 stop channel ; D0 1 channel control word ; Φ = (16MHz/16)/8 = 125kHz ld c,CTC3 ld a,07h out (c),a ; ; 1 / 13 ; 125kHz ; SIOA,SIOB : (1/32) ld a,13 out (c),a ; pop af pop bc ret ;################################################# ; store SIOA data to ring buffer ; if No more space then Nothing do ;################################################# _rs_rx_a: di push af push bc push hl ; ld a,(_rx_putpa); get PUT_POINTER ld c,a inc c ; set next PUT_POINTER ld a,(_rx_getpb); get GET_POINTER cp c ; if next PUT_POINTER = GET_POINTER in a,(SIOAD) ; get data jr z,ignore_data; no space ; and 7fH ; for 7 bit character ld b,0 dec c ; set current PUT_POINTER ld hl,_rx_buf_a ; get ring buffer A entry point add hl,bc ; calculate rest capacity ld (hl),a ; store data to ring buffer A ld hl,_rx_putpa ; update PUT_POINTER inc (hl) jr ignore_data ;################################################# ; store SIOB data to ring buffer ; if No more space then Nothing do ;################################################# _rs_rx_b: di push af push bc push hl ; ld a,(_rx_putpb); get PUT_POINTER ld c,a inc c ; set next PUT_POINTER ld a,(_rx_getpb); get GET_POINTER取得 cp c ; if next PUT_POINTER = GET_POINTER in a,(SIOBD) ; get data jr z,ignore_data; no capacity ; and 7fH ; for 7 bit character ld b,0 dec c ; set current PUT_POINTER ld hl,_rx_buf_b ; get ring buffer B entry point add hl,bc ; calculate rest capacity ld (hl),a ; store data to ring buffer B ld hl,_rx_putpb ; update PUT_POINTER inc (hl) ; ignore_data: pop hl pop bc pop af ei reti ;################################### ; C function handling ; get data from ring buffer A ;################################### _sioa_get: ld a,(_rx_getpa); get GET_POINTER ld c,a ld a,(_rx_putpa); get PUT_POINTER cp c ; if data exist jr z,_a_get0 ; return -1 ld b,0 ; calculate data entry point ld hl,_rx_buf_a add hl,bc ld a,(hl) ; a = data ld hl,_rx_getpa ; inc (hl) ; update GET_POINTER ld l,a ; l = data ld h,b ; h = 0 jr _a_get_e _a_get0: ld hl,-1 ; HL (return value in int type) _a_get_e: ret ;################################### ; C function handling ; get data from ring buffer B ;################################### _siob_get: ld a,(_rx_getpb); get GET_POINTER ld c,a ld a,(_rx_putpb); get PUT_POINTER cp c ; if data exist jr z,_b_get0 ; return -1 ld b,0 ; calculate data entry point ld hl,_rx_buf_b add hl,bc ld a,(hl) ; a = data ld hl,_rx_getpb ; inc (hl) ; update GET_POINTER ld l,a ; l = data ld h,b ; h = 0 jr _b_get_e _b_get0: ld hl,-1 ; HL (return value in int type) _b_get_e: ret ;################################### ; reset channel A error ;################################### _er_reset_a: di push af push bc ; ld c,SIOAC ld a,00110000B ; clear error out (c),a ; pop bc pop af ei reti ;################################### ; reset channel B error ;################################### _er_reset_b: di push af push bc ; ld c,SIOBC ld a,00110000B ; clear error out (c),a ; pop bc pop af ei reti ;################################### ; stop SIO ;################################### _sioret: jp _sioret ; STOP reti ;################################################### ; channel B ; WR4 ;    receive clock x32 / 1 stop bit / non parity ; WR3 ;   receive 8 bits / no CTS & DCD control / enable receive ; WR5 ; DTR_on / transmit 8 bits / enable transmission / RST_on ; WR1 ; receive interrupt / enable affect vector ;################################################### org 06000h SIOB: DB 14H ; WR4 & Reset DB 10000100B ; x32,S1,PN DB 03H ; WR3 DB 11000001B ; B8,Rx Enable DB 05H ; WR5 DB 11101010B ; DTR on,B8,Tx Enable,RTS on DB 01H ; WR1 DB 00010100B ; All Char Enable,Save Affect Vector SIOBE: ;############################################################ ; channel A ; WR4 ;    receive clock x32 / 1 stop bit / non parity ; WR3 ;   receive 8 bits / no CTS & DCD control / enable receive ; WR5 ; DTR_on / transmit 8 bits / enable transmission / RST_on ; WR1 ; receive interrupt ;############################################################ SIOA: DB 14H ; WR4 & Reset DB 10000100B ; x32,S1,PN DB 03H ; WR3 DB 11000001B ; B8,Rx Enable DB 05H ; WR5 DB 11101010B ; DTR on,B8,Tx Enable,RTS on DB 01H ; WR1 DB 00010000B ; All Char Enable SIOAE: INT_SIO: ; SIO interrupt vector DEFW _sioret ; channel B send DEFW _sioret ; RETINT DEFW _rs_rx_b ; channel B receive interrupt DEFW 0000h ; channel B error interrupt ;DEFW _er_reset_b ; channel B error interrupt DEFW _sioret ; channel A send DEFW _sioret ; RETINT DEFW _rs_rx_a ; channel A receive interrupt DEFW _er_reset_a ; channel A error interrupt org 8000h _rx_putpa: DEFS 1 ; Receive Put Data Pointer _rx_getpa: DEFS 1 ; Receive Get Data Pointer _rx_buf_a: DEFS 256 ; Receive Data Buffer _rx_putpb: DEFS 1 ; Receive Put Data Pointer _rx_getpb: DEFS 1 ; Receive Get Data Pointer _rx_buf_b: DEFS 256 ; Receive Data Buffer end  このコードは、Cで記述するモニタプログラムと  接続して利用します。

Intel系ICテスト

 Z84C15基板の外部に、8251、8255、8254を接続して使います。  各ICの動作テストをしました。  8251   8251は、シリアルインタフェースICですが、コンピュータ   と通信しながらテストするために使われました。   次の条件で利用します。    データ転送速度 9600bps    データ長    8ビット    ストップビット 1ビット    パリティ    なし    フロー制御   なし   データ転送速度は、8251のTXC、RXCピンに与えるクロックを   決めます。4MHzを分周してデータ転送速度の16倍、64倍での   クロックを与えます。計算して、次のようになりました。     4800bps 64x => 307.2kHz 13     9600bps 16x => 153.6kHz 26    19200bps 16x => 307.2kHz 13   モード設定するときには、ビットの組合せを考えます。   設定項目は、以下です。   非同期で動かすことにします。   ビットの組み合わせは、以下。    S2 S1 EP PEN L2 L1 B2 B1    (S2,S1)は、ストップビット数になるので(0,1)を指定。    (EP,PEN)は、パリティ関係で使わないので(0,0)を指定。    (L2,L1)は、データ長をつかうので8ビットとして(1,1)を指定。    (B2,B1)は、データ転送速度の16倍、64倍を決めるので16倍として(1,0)を指定。   8ビットにまとめると、01001110(4Fh)になります。   コマンド設定にも、ビットの組合せを考えます。   ビットの組み合わせは、以下。    EH IR RTS ER SBRK RXE DTR TXEN    EHは、Huntモードを使うときに1にします。(EH = 0)    IRは、Internal Resetをしたいときに1にします。(IR = 0)    RTSは、RTSピンの論理値を指定します。(RTS = 1)    ERは、Reset Error flagを使うときに1にします。(ER = 0)    SBRKは、Break Charactorを使うときに1にします。(SBRK = 0)    RXEは、受信処理する場合に1にします。(RXE = 1)    DTRは、DTRピンの論理値を指定します。(DTR = 1)    TXENは、送信処理する場合に1にします。(TXEN = 1)   8ビットにまとめると、00100111(27h)になります。   初期化処理は、次のコードになります。 URTDA EQU 80h ;8251 UART Data Port URTCNT EQU 81h ;8251 UART Control Port XOR A OUT (URTCNT),A OUT (URTCNT),A OUT (URTCNT),A LD A,40h OUT (URTCNT),A LD A,4Fh OUT (URTCNT),A LD A,27h OUT (URTCNT),A   8251は、初期化時にはレジスタをクリアします。   データ入力、出力は、次のようになります。 ; data input DAIN: IN A,(URTDA) RET ; data output DAOUT: PUSH AF ; OUT (URTDA),A ; POP AF ; RET   データ入力の場合は、ステータスを確認します。   ビットの組み合わせは、以下。    DSR SYNDET/BD FE OE PE TXEMPTY RXRDY TXRDY    DSRは、DSRピンの状態を反映しています。1でDSR=0。    SYNDET/BDは、同期の場合に使います。1にするとSYNDET/BD=1。    FEは、Framingエラーのとき1になります。       Framingエラーは、データ長が設定値と一致しないとき発生。    OEは、Overflowエラーのとき1になります。       Overflowエラーは、ストップビットを検出できないとき発生。    PEは、Parityエラーのとき1になります。       Parityを使わない場合は、無視します。    TXEMPTYは、送信バッファ(シフトレジスタ)が空のとき1になります。    RXRDYは、受信可能のときに1になります。(DTR = 1)    TXRDYは、送信可能のときに1になります。(TXEN = 1)   ステータスを使い、データ入力、出力は、次のようにします。 ; data input DAIN: IN A,(URTCNT) ; Get status byte BIT 1,A ; Check buffer full JR Z,DAIN ; no data IN A,(URTDA) RET ; data output DAOUT: PUSH AF PUSH BC ; DAOUT1: IN A,(URTCNT) ; Get status byte BIT 0,A ; Check buffer full JR Z,DAOUT1 ; not empty ; LD A,B OUT (URTDA),A ; POP BC POP AF ; RET  8255   8255は、パラレルインタフェースICです。   Z80ファミリICでパラレルインタフェースと   なるとZ80PIOがありますが、1ポートを8   ビットとして2ポート。   8255は8ビットを1ポートとするポート数が   3と多かったので、単純なパラレル入出力に   利用されていました。   ポートA、B、Cを単純な入出力で利用する   他に、グループA、Bとして使うことも可能。   ポートA、ポートCの下4ビットをグループA   として、ポートB、ポートCの上4ビットを   グループBとします。   グループA、Bとして使うのが基本のようで   制御レジスタの設定は、グループ単位となって   いました。   AVR、PICのようなワンチップマイコンなら当然   のように持っている、内蔵プルアップ抵抗もなく   外部でプルアップ、プルダウンする仕様でした。   制御、ポートのレジスタの配置は以下。   ポートの入出力には、AからCを利用しますが   グループA、Bの扱いはCONTROLレジスタでの   設定に依存します。   CONTROLレジスタのビットの組み合わせは、次のように   決められています。   D7 1:モード設定 0:ビットハンドリング   D6 groupA mode (M1) [M1,M0] = [1,1] or [1,0] mode_2   D5 groupA mode (M0) [M1,M0] = [0,1] mode_1 [M1,M0] = [0,0] mode_0   D4 PORT_A 1:inputs 0:outputs   D3 PORT_C upper nibble 1:inputs 0:outputs   D2 groupB mode 1:mode_1 0:mode_2   D1 PORT_B 1:inputs 0:outputs   D0 PORT_C lower nibble 1:inputs 0:outputs   グループA、Bともに、12ビットで動作を指定すると   考えれば、わかりやすくなります。   グループA、Bのモードと入出力設定用制御ワードは、スクリプトで   簡単に生成すればよいでしょう。   テキストファイルには、次のように記述します。 2 IN OUT 1 OUT OUT   単純な組み合わせなので、AWKでは次のように記述します。 { # groupA mode result = $1 * 4 # groupA PORT_A in or out if ( tolower($2) == "in" ) { result = result + 2 } # groupB PORT_C upper nibble in or out if ( tolower($3) == "in" ) { result = result + 1 } # shift result *= 8 # groupB mode result += $4 * 4 # groupB PORT_B in or out if ( tolower($5) == "in" ) { result = result + 2 } # groupB PORT_C upper nibble in or out if ( tolower($6) == "in" ) { result = result + 1 } # add MSB result = result + 128 # show printf("%s => 0%02Xh\n",$0,result) }   テキストファイルに、モードと入出力を定義して   実際の制御ワードがどうなるのかを見ると以下。   ビットハンドリングは、ポートCの8ビットの出力論理値を   設定します。ビットの組み合わせは、以下。   D7 0   D6 * Don't care   D5 * Don't care   D4 * Don't care   D3 bit address 2   D2 bit address 1   D1 bit address 0   D0 1:set 0:reset   ビットハンドリングの制御ワード(1バイト)を生成するのは   次のようなスクリプトを使うと簡単です。(AWKの場合)   {    result = $1 * 2 + $0    printf("%s => %02Xh\n",$0,result)   }   MSBからLSBにかけて、セット、リセットのビット位置と値を   定義したファイルを作成し、I/Oリダイレクトでコードを生成   すると、以下。   利用したテキストファイルの内容は、次のようにしました。   (ビット位置、値の並びです。) 7 0 7 1 6 0 6 1 5 0 5 1 4 0 4 1 3 0 3 1 2 0 2 1 1 0 1 1 0 0 0 1   ビットハンドリングの制御バイトは、アセンブリ言語   でも生成できます。 ; set bit location LD A,04h SLA A ; set or reset SET 0,A ; store OUT (CT8255),A   グループA、Bともに、モード0(単純入出力)に設定し   グループAを入力、グループBを出力に設定します。   グループAには12ビット分のスイッチ、グループBには   12ビット分のLEDがあるとして、動作テストさせる場合   次のコードになります。 A8255 EQU 80h B8255 EQU 81h C8255 EQU 82h CT8255 EQU 83h INIT_8255: ; PUSH AF ; control word LD A,98h ; store OUT (CT8255),A ; POP AF ; RET P8255: ; PUSH AF PUSH DE ; get from group A IN A,(C8255) AND 0F0h SRL A SRL A SRL A SRL A LD E,A IN A,(A8255) ; inverse CPL LD D,A LD A,E CPL ; put to group B OUT (C8255),A LD A,D OUT (B8255),A ; POP DE POP AF ; RET  8254   8254は、8253とピン互換、機能互換であるタイマーICです。   Z80CTCは、プリスケーラと8ビットカウンタが4チャネル   ありますが、8254は16ビットカウンタが3チャネルです。   16ビットカウンタが3チャネルで、1チャネルあたり入出力   はCLK、GATE、OUTの3ビットあります。   CLKは、16ビットカウンタへのクロック入力。   GATEは、カウンタのデクリメントを制御します。   OUTは、カウンタがゼロになったときに1か0を出力。   カウント処理は、すべてダウンカウントになります。   モードが次の6種類あります。   これらすべてのモードを利用することがないので   応用例を考えて、使うモードを限定します。   制御ワードは、次のビット構成になってます。   D7 SCI1 select channel   D6 SCI0   D5 RL1 read / load   D4 RL0   D3 M2 select mode   D2 M1   D1 M0   D0 BCD 1:BCD count 0:binary count   ビットの組合せは、以下。 (SCI1,SCI0)=(0,0) channel_0 (0,1) channel_1 (1,0) channel_2 (1,1) invalid (RL1,RL0)=(0,0) counter latch operation (0,1) read or load lower byte (1,0) read or load upper byte (1,1) read or load both byte (M2,M1,M0)=(0,0,0) mode_0 (0,0,1) mode_1 (0,1,0) mode_2 (0,1,1) mode_3 (1,0,0) mode_4 (1,0,1) mode_5 (1,1,0) invalid (1,1,1) invalid   通常カウントダウンするためのカウント値は16ビット   で指定するので、RLは固定値とし他をファイルに記述   して制御バイトを生成するスクリプトを定義します。 { result = 3 * 16 result = result + $1 * 64 result = result + $2 * 2 result = result + $3 printf("%s -> 0%02Xh\n",$0,result) }   ファイルには、チャネル、モード、BCDかどうかを   数値で記述します。 2 4 0 0 2 1   スクリプトを動かすと、次のようになります。
目次

inserted by FC2 system