VOOZH about

URL: https://qiita.com/Xi80/items/3c2908fc7a08a1b8bed2

⇱ Z80でリングバッファの実装 #Z80 - Qiita


👁 Image
2

Go to list of users who liked

0

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 3 years have passed since last update.

@Xi80(Itsuki Hashimoto)

Z80でリングバッファの実装

2
Last updated at Posted at 2021-12-03

はじめに

こちらは鈴鹿高専 Advent Calendar 2021の4日目の記事です.

注意事項としては,ここで記載されているコードを他のプロダクトでそのまま使うのは禁止とします.

何かバグがあっても責任を取れないためです.

また,実際に何かを制作する際には必ず一次情報(データシートなど)を参考にしてください.

作ったもの

アセンブラでリングバッファを作りました.

シリアル通信の受信バッファとして適しています.

いきなり内容が薄くなりましたが,元々自分のホームページで公開していたものに加筆修正を施したものです.

概要

リングバッファは以下の図のようなリング状のバッファです.
👁 circularbuffer.png

先端と終端が論理的に繋がっていて古いデータは上書きされていきます.

C言語などの高級言語での実装では先端と終端の結合に%演算子を使っていることが多いのですが,アセンブラ+Z80ではいろいろしんどい(除算器がない)ので大人しく条件分岐でインデックスを先端に戻す処理をかきます.

コード

BUFFER_SIZE EQU 80H ;バッファーのサイズはここで指定
 ORG 5000H
;バッファーの初期化
;引数: なし
;破壊: なし
INIT_BUFFER: PUSH AF ;レジスタの退避
 PUSH BC
 PUSH DE
 PUSH HL
 ;
 XOR A ;ポインタの初期化
 LD (BUFFER_READ),A
 LD (BUFFER_WRITE),A
 LD (BUFFER_LENGTH),A
 ;
 LD HL,BUFFER ;バッファー領域の初期化
 LD DE,BUFFER+1
 LD BC,BUFFER_SIZE-1
 LD A,00H
 LD (HL),A
 LDIR
 ;
 POP HL ;レジスタの復帰
 POP DE
 POP BC
 POP AF
 RET
;
;バッファーへのデータ追加
;引数: D 追加するデータ
;破壊: A,F
;返り値: Z 	T:失敗(空きがない)
; F:成功
SET_BUFFER: PUSH BC ;レジスタの退避
 PUSH HL
 ;
 LD A,(BUFFER_LENGTH) ;バッファーに空きがあるか調べる
 LD B,BUFFER_SIZE
 XOR B
 JP NZ,SET_BUFFER1
 POP HL
 POP BC
 RET
 ;
SET_BUFFER1: LD HL,BUFFER ;アドレス算出
 LD B,0
 LD A,(BUFFER_WRITE)
 LD C,A
 ADD HL,BC
 ;
 LD (HL),D ;データの追加
 ;
 LD A,(BUFFER_LENGTH) ;BUFFER_LENGTH++
 INC A
 LD (BUFFER_LENGTH),A
 ;
 INC C ;BUFFER_WRITE++
 LD A,C
 LD (BUFFER_WRITE),A
 ;
 LD B,BUFFER_SIZE ;BUFFER_SIZE==BUFFER_WRITE?
 XOR B
 POP HL
 POP BC
 RET NZ ;BUFFER_SIZE!=BUFFER_WRITE
 XOR A ;BUFFER_WRITE=0
 LD (BUFFER_WRITE),A
 INC A ;Zフラグを消す
 OR A
 RET
;
;バッファーからのデータの取り出し
;引数: なし
;破壊: A,F
;返り値: D 取り出したデータ
; Z T 失敗(空)
; F 成功
GET_BUFFER: PUSH BC ;レジスタの退避
 PUSH HL
 ;
 LD A,(BUFFER_LENGTH) ;データが入っているか調べる
 LD B,0
 XOR B
 JP NZ,GET_BUFFER1
 POP HL
 POP BC
 RET
 ;
GET_BUFFER1: LD HL,BUFFER ;アドレスの算出
 LD B,0
 LD A,(BUFFER_READ)
 LD C,A
 ADD HL,BC
 ;
 LD D,(HL) ;データの取り出し
 ;
 LD A,(BUFFER_LENGTH) ;BUFFER_LENGTH--
 DEC A
 LD (BUFFER_LENGTH),A
 ;
 INC C ;BUFFER_READ++
 LD A,C
 LD (BUFFER_READ),A
 ;
 LD B,BUFFER_SIZE ;BUFFER_SIZE==BUFFER_READ?
 XOR B
 POP HL
 POP BC
 RET NZ ;BUFFER_SIZE!=BUFFER_READ
 XOR A ;BUFFER_READ=0
 LD (BUFFER_READ),A
 INC A
 OR A
 RET
;RAM AREA
 ORG 9000H
BUFFER_READ: DEFS 01H
BUFFER_WRITE: DEFS 01H
BUFFER_LENGTH: DEFS 01H
BUFFER: DEFS 80H

Z80のアセンブラは容易に読めるので,コメントと合わせれば理解は可能だと思います.

それなりに速度に気をつかってみたつもりですが最適化はまだまだできると思います.

実際の使用例

		ORG	0000H
MAIN:	CALL	INIT_BUFFER
		LD	B,4H
LOOP1:	LD	D,B
		CALL	SET_BUFFER
		DJNZ	LOOP1
		LD	B,5H
LOOP2:	LD	D,00H
		CALL	GET_BUFFER
		DJNZ	LOOP2
		HALT

こんな感じで所定のレジスタに引数を入れサブルーチンを呼び出すだけでデータの格納,取り出しが可能です.

MIDIの受信に使用するつもりで書きましたが,せっかくなので汎用性を持たせた設計にしました.

最後に

Z80は非常に優れたCPUだと思います.

みなさんも是非使ってみてください.

2

Go to list of users who liked

0
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2

Go to list of users who liked

0