今回はTMPZ84C015上のモニターでSDCCによるc言語でポート出力と時間稼ぎルーチンを作成・実行してみたいと思います。

まずは、ポートのイニシャライズですが、Bポートを使用して、関数の引数として、out/inを決定する値を与えるようにしました。

関数はアセンブラで作成し、out/inを設定するところで値を渡しています。基本的に、モニタで使用しているルーチンと同じです。

;;  TMPZ84C015 PIOB Initialize set mode3
;;
;;	int piob_init(uint8_t data)
;;
;;      data: 0:output  1:input
;;
PORTAD	.equ	0x1c
PORTAC	.equ	0x1d
PORTBD	.equ	0x1e
PORTBC	.equ	0x1f

_piob_init::
	ld	hl,	#0x0002
	add	hl,	sp

	ld	a,	#00		;interrupt vector word
	out	(PORTBC),a
	ld	a,	#0b11001111	;mode 3
	out	(PORTBC),a
	ld	a,(hl)			;0:output 1:input
	out	(PORTBC),a
	ld	a,	#0b00000000	;interrupt control woed
	out	(PORTBC),a
	ld	a,	#0b00000000	;mask control word
	out	(PORTBC),a
	ld	hl,	#0x0000
	ret

上記のプログラムをpiob_init.asmで保存した後、アセンブルし、piob_init.relを取得します。

$ asz80 -l -s -o piob_init.asm

次に実際にポートに値を出力するためのポート出力関数を作成します。

これもモニタで使用しているポート出力部を使用します。
引数として、ポートアドレスと、出力したい値を与えます。

;;	uint8_t	(uint8_t port,uint8_t data)

_io_out	::

	ld	hl,	#0x0002
	add	hl,	sp
	ld	c,	(hl)
	inc	hl
	ld	a,	(hl)
	out	(c),	a	
	
	ld	hl,	#0x0000

        ret
 

上記のプログラムをio_out.asmで保存した後、アセンブルし、io_out.relを取得します。

$ asz80 -l -s -o io_out.asm

ポートのイニシャライズとポート出力関数ができたので早速、C言語で、LEDをLちかしてみたいと思います。

ポートBのPB0ビット(CN3/2Pin)にLEDを接続し、1KΩを介してGNDに接続しました。

piob_initには引数として,0xfe(0bitのみ出力)を与えています。

// TMPZ84C015 	piob bit0 output:1
//
#include	<stdio.h>
#include	<stdint.h>


extern	uint8_t	io_out(uint8_t,uint8_t);
extern	uint8_t piob_init(uint8_t);

const	uint8_t PortBD = 0x1e;
const	uint8_t PortBC = 0x1f;


int	main(void){
	piob_init(0xfe);			//port PB0 output
	io_out(PortBD,0x01);		//port b bit0 High output
	return(0);
}

コンパイルします。

$ sdcc -mz80 --out-fmt-ihx --code-loc 0xa000 --no-std-crt0 -o piob_led.ihx mycrt0.rel piob_led.c io_out.rel piob_init.r
el
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA

モニタ上のlコマンドで読みこみます。A000をコールします

>l                                                                              20A000003EFEF533CD2DA033211AA0463E01F533C533CD20A0F1210000C91E1FCD1C00C938
20A02000210200394E237EED79210000C9210200393E00D31F3ECFD31F7ED31F3E00D31F5A
08A040003E00D31F210000C9FE
00000001FF
OK
>

>c a000 y:
>

つぎは、LEDの点滅を行ってみます。

時間稼ぎのルーチンとして、sleep関数を作成ました。

NOPとDJNZを使用して約1mSの時間稼ぎを行っています。
この1mSのループをDEレジスタでカウントダウンしています。

sleep(0x0001)で約1mS、sleep(0xffff)で約65535mSです。

;;	uint8_t sleep(uint16_t)
;;	TMPZ84C015 CPU
;;	24.576MHz clock sleep(0x0001) = 1mS


_sleep::

	ld	hl,	#0x0002
	add	hl,	sp
	ld	e,	(hl)
	inc	hl
	ld	d,	(hl)
loop1:
	ld	b,	#248
loop2:	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	djnz	loop2

	dec	de
	ld	a,d
	or	e
	jr	nz,	loop1
	
	ld	hl,	#0x0000

        ret

上記のプログラムをsleep.asmで保存した後、アセンブルし、sleep.relを取得します。

$ asz80 -l -s -o sleep.asm

時間稼ぎのルーチンができたので、0.5秒周期で点滅させたいと思います。

// TMPZ84C015	piob bit0 tenmetu(0.5S)
//
#include	<stdint.h>

extern	uint8_t	piob_init(uint8_t);
extern	uint8_t	io_out(uint8_t,uint8_t);
extern 	uint8_t sleep(uint16_t);

const	uint8_t PortBD = 0x1e;
const	uint8_t PortBC = 0x1f;

int	main(void){

	piob_init(0b11111110);			//port PB0 output
	while(1){
		io_out(PortBD,0b00000001);	//port b bit0 High output
		sleep(500);			// 500mS wait
		io_out(PortBD,0b00000000);	//port b bit0 low output
		sleep(500);			//500mS wait
	}
	return(0);
}

コンパイルします。
return(0)で warning が出ますが無視しています。

$ sdcc -mz80 --out-fmt-ihx --code-loc 0xa000 --no-std-crt0 -o piob_tenmetu.ihx mycrt0.rel piob_tenmetu.c io_out.rel  piob_init.rel sleep.rel
piob_tenmetu.c:21: warning 126: unreachable code
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA

モニタ上のlコマンドで読みこみます。A000をコールします

>l
20A000003EFEF533CD46A0332133A0463E01F533C533CD39A021F401E3CD61A0F12133A00B
20A0200046AFF533C533CD39A021F401E3CD61A0F118D51E1FCD3500C9210200394E237E6D
20A04000ED79210000C9210200393E00D31F3ECFD31F7ED31F3E00D31F3E00D31F21000034
1EA06000C9210200395E235606F800000000000000000010F51B7AB320EE210000C9A3
00000001FF
OK
>

>c a000 y:
無限ルーチンのためモニタには帰ってきません。

0.5秒周期でLEDが点滅します。

次回はLCDのC言語プログラムを作成したいと思います。

おすすめの記事