前回でCCP、BDOS、BIOS(途中のもの)を実機に乗せることができましたので、BDOSコールについて確認していきたいと思います。

なお、BIOSについては、CONST:のルーチンを変更したので、最後に展開しているBIOSを再度アセンブルしてください。

CPMシステムに制御が移ると、モニタに戻すことができないので、NMI端子をLowにして強制的に割り込みを発生させ、モニタにジャンプするようにしました。
ということで、CN3-12pin(NMI)に押しボタンSWを接続して押したらLowになるようにハードを追加します。

まずは、NMI端子の確認をします。
モニタのTコマンドで 64Kモードにしてから、NMI割り込みのジャンプ先である0x0066に モニタに戻ってくるように 無条件ジャンプのコードを設定します。(c3,00,01を設定)

>t Yes:                                                                                                                                                        
RAM area switching monitor                                                      
Monitor TMPZ84C015 CPU ver0.72(SPI)  by Pinecone 2019/9/6                       
>m 0066 FF c3                                                                   
>m 0067 FF 00
>m 0068 FF 01                                                             
>d 0066                                                                         
addr  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F                     
0066  C3 00 01 FF FF FF FF FF FF FF FF FF FF FF FF FF 
>                   

NMI端子に接続した押しボタンSWを押すことにより、NMI割り込みがかかり、0x0066に飛んでいき、無条件ジャンプ先である0x0100のモニタに制御が移ります。

NMI押しボタンでモニタに制御が映ることを確認したら、モニタのLコマンドでcpm.hexとbios.ihxをメモリ上に呼び込みします。

再度、0x0066にc3,00,01を設定します。

モニタのjコマンドで0xf200へジャンプしcpmを起動し、エラーになっているところをNMI押しボタンを押して、強制的にモニタに制御を移します。

ここから BDOSコールのプログラムを確認していきたいと思います。
BDOSコールは、Cレジスタにコール番号を設定し、0x0005をコールすることにより行うことができます。BDOSコール番号により、必要なレジスタの設定が異なってきます。

今回はシリアル通信関係のBDOSコールを確認していきたいと思います。

*コンソールからの入力(入力があるまで待機し、入力があればエコーバックします)                       C=0x01 (01)
*コンソールへの出力                C=0x02 (02)

下記のプログラムは、キー入力をエコーバックし、CtrlキーとCキーが押されたら、Ctrl-C key in ! と表示してモニタへ帰ります。
何故かエコーバックは、次の文字を入力した時点で表示されます。これはこのような仕様? BackSpaceなどの対応のためかな? 素直でないエコーバック!

追記:

素直でないエコーバックの原因がわかりました^^;
BIOSのCONST(コンソールステータス)の判定方法が逆になっていました。
READYのとき、本来なら0xFFを返すところ0x00に、BUSYの場合も0x00を返すところを0xffにしていました^^;
末端のBIOSのソースは本来の判定方法に修正しました。

const:	in     	a,(SIOBC)
	bit	0,a
        jr      z,con_busy			;console status
	ld	a,0x00		;READY= 0xff BUSY=0x00 out Areg
	ret
con_busy:
	ld	a,0xff
	ret
>j 8000 y:                                                                      
asdfghjkl                                                                       
Ctrl-C key in !                                                                 
Monitor TMPZ84C015 CPU ver0.72(SPI)  by Pinecone 2019/9/6                       
>

BDOS c=0x01 入力データ= Aレジスタ
BDOS c=ox02 出力データ= Eレジスタ

;;		CP/M BDOS CALL No.1 or No.2
	
		.z80

BDOS_CALL	.equ	0x0005

		.area	BDOS_CALL(ABS) 
		
		.org	0x8000
	
loop:
	ld	c,0x01		;BDOS call No.01
	call	BDOS_CALL	;input data in A reg
	
	cp	0x03		;Ctrl-C key in
	jr	z,loop_end
	jr	loop

loop_end:
	ld	hl,ctrl_c_msg
	call	msgout
	jp	0x0100		;go to monitor

msgout:
        ld      a,(hl)          ;(HL)reg is output disp at 0x00
        cp      0x00
        ret     z
	push	hl
        call    putchar
	pop	hl
        inc     hl
        jr      msgout

putchar:			;1 char output
	ld	e,a		;output data E reg
	ld	c,0x02		;BDOS call No.02
	call	BDOS_CALL
	ret

ctrl_c_msg:
	.db	0x0d 
	.str    "Ctrl-C key in !"
        .db     0x0d
	.db	0x00

		.end

同じようなコンソールからの入出力で BDOSコールNo.06があります。
これは一つのBDOSコールで入力と出力を処理しています。
入力に設定するにはEレジスタに0xffを、出力に設定するときはEレジスタに出力データを設定します。したがって、0xffは出力として設定できないようです。

入力は、何も入力されていないときは、Aレジスタに0x00が帰ってきます。

下記のプログラムは、入力データがあるまで待って、入力があればエコーバックします。また。入力データが Ctrlキーとzキーが同時に押されたら、Ctrl-z key in ! と表示して、モニターに帰ります。

>j 8000 y:                                                                      
asdfghjkl                                                                       
Ctrl-z key in !                                                                 
Monitor TMPZ84C015 CPU ver0.72(SPI)  by Pinecone 2019/9/6                       
>

BDOS c=0x06 Eレジスタ=0xff 
    入力データ= Aレジスタ ただし何も入力ないとき0x00
BDOS c=ox06 出力データ= Eレジスタ(だたし0xff以外)

;;		CP/M BDOS CALL No.6

		.z80

BDOS_CALL	.equ	0x0005

		.area	BDOS_CALL(ABS)
		
		.org	0x8000
	
loop:
	ld	e,0xff		;input mode
	ld	c,0x06		;BDOS call No.06
	call	BDOS_CALL
	
	cp	0x00		;key in?
	jr	nz,loop_end
	jr	loop

loop_end:
	cp	0x1a		;Ctrl-Z key in?
	jr	z,break
	call	putchar
	jr	loop

break:	
	ld	hl,ctrl_z_msg
	call	msgout
	jp	0x0100		;go to monitor

msgout:
        ld      a,(hl)          ;(HL)reg is output disp at 0x00
        cp      0x00
        ret     z
	push	hl
        call    putchar
	pop	hl
        inc     hl
        jr      msgout

putchar:			;1 char output
	ld	e,a		;BDOS call No.06
	ld	c,0x06
	call	BDOS_CALL
	ret

ctrl_z_msg:
	.db	0x0d 
	.str    "Ctrl-z key in !"
        .db     0x0d
	.db	0x00

		.end

次も、コンソール関係のBDOSコールの続きをやっていきたいと思います。

今回使用した仮のBIOSは下記のプログラムになります。

;;z80 (TMPZ84C015) 62K cp/m V2.2 BIOS by Pinecone 2020/02/15

; TMPZ84C015 cpu
; ram 0000h -- ffffh
; External clock 20MHz


; TMPZ84C015 serial communication (CH-A)
; extemal Clock 38.4KHz
 
; assembler
;  program start 0xF200
;  main          0xF200
;
; assemblers  ASxxxx and ASlink V5.10
; file name bios204.asm
; $ asz80 -l -s -o bios204.asm
; $ aslink -i bios204
; $ tmpz84_moni71 l command Hex load jump 0xf200


	.z80

VERS	.equ	22		;Version 2.2

MSIZE	.equ	62		;CP/M memory size 
	
BIAS	.equ	(MSIZE-20)*1024
CCP	.equ	0x3400 + BIAS	;base of cpm console processor
BDOS	.equ	0x806 +	CCP	;basic dos
BIOS	.equ	CCP + 0x1600	;BIOS
CDISK	.equ	0x0004		;disk number 0=A 1=B ..
IOBYTE	.equ 	0x0003		;intel i/o byte

cpmboot	.equ	CCP

;; TMPZ84C015 serial port SIO-B CH
SIOBD	.equ	0x1A		;SIO-B CH DATA REG
SIOBC	.equ	0x1B		;SIO-B CH CONTL	REG
;; TMPZ84C015 pio port  PIO-A CH
PIOAD 		.equ 	0x1c		;PIO-A CH DATA REG
PIOAC		.equ	0x1d		;PIO-A CH CONTL	REG
;; TMPZ84C015 pio SPI OUT-PORT PIO-A CH
S_DI 		.equ 7 ;0b10000000 D7
S_CS 		.equ 6 ;0b01000000 D6
S_CLK 		.equ 5 ;0b00100000 D5
;; TMPZ84C015 pio SPI INPUT-PORT PIO-A CH
DO 		.equ 0 ;0b00000001 D0

BUFF_DEFAULT_ADDR	.equ	0x80	;default buff address

	.area	BIOS(ABS)

	.org	BIOS

;NSECTS	.equ	(#. - CCP)/128	;warm start sector count

;;	jump vector for indiviual routines
;
	jp	boot		;cold start
wboote:	jp	wboot		;warm start
	jp	const		;console status
	jp	conin		;console character in
	jp	conout		;console character out
	jp	list		;list character out
	jp	punch		;punch character out
	jp	reader		;reader character out
	jp	home		;move head to home position
	jp	seldsk		;select disk
	jp	settrk		;set track number
	jp	setsec		;set sector number
	jp	setdma		;set dma address
	jp	read		;read disk
	jp	write		;write disk
	jp	listst		;return list status
	jp	sectran		;sector translate

;;
;;     IBN-COMPATIBLE 8 Inch DISKS
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	disk Parameter header for disk 00
dpbase:	.dw	trans, 0x0000
	.dw	0x0000, 0x0000
	.dw	dirbf, dpblk
	.dw	chk00, all00
;	disk parameter header for disk 01
	.dw	trans, 0x0000
	.dw	0x0000, 0x0000
	.dw	dirbf, dpblk
	.dw	chk01, all01
;	disk parameter header for disk 02
	.dw	trans, 0x0000
	.dw	0x0000, 0x0000
	.dw	dirbf, dpblk
	.dw	chk02, all02
;	disk parameter header for disk 03
	.dw	trans, 0x0000
	.dw	0x0000, 0x0000
	.dw	dirbf, dpblk
	.dw	chk03, all03
;
;	sector translate vector
trans:	.db	 1,  7, 13, 19	;sectors  1,  2,  3,  4
	.db	25,  5, 11, 17	;sectors  5,  6,  7,  6
	.db	23,  3,  9, 15	;sectors  9, 10, 11, 12
	.db	21,  2,  8, 14	;sectors 13, 14, 15, 16
	.db	20, 26,  6, 12	;sectors 17, 18, 19, 20
	.db	18, 24,  4, 10	;sectors 21, 22, 23, 24
	.db	16, 22		;sectors 25, 26
;
dpblk:	;disk parameter block, common to all disks
	.dw	26		;sectors per track
	.db	3		;block shift factor
	.db	7		;block mask
	.db	0		;null mask
	.dw	242		;disk size-1
	.dw	63		;directory max
	.db	192		;alloc 0
	.db	0		;alloc 1
	.dw	16		;check size
	.dw	2		;track offset
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;	disk port and commands
lf	.equ	0x0a
cr	.equ	0x0d

signon:				;signon massage ??K cp/m  ?.?	
	.db	cr,lf,lf
	.db	MSIZE/10+"0",MSIZE % 10 +"0"
	.str	"K CP/M VERS "
	.db	VERS/10+"0",".",VERS % 10 +"0"
	.db	cr,lf,0

boot:
	ld	sp,BUFF_DEFAULT_ADDR + 0x80
	call	init_io
	ld	hl,signon
	call	prmsg
	xor	a
	ld	(CDISK),a
	ld	(IOBYTE),a
	jr	gocpm

wboot:
	ret


gocpm:				;set default buff address to 0x80
	ld	bc,BUFF_DEFAULT_ADDR
	call	setdma

	ld	a,0xc3		;jump wboot address set at 0x0000
	ld	(0x0000),a
	ld	hl,wboote
	ld	(0x0001),hl

	ld	(0x0005),a	;jump BDOS address set at 0x0005
	ld	hl,BDOS
	ld	(0x0006),hl

	ld	a,(CDISK)
	ld	c,a
	jp	cpmboot

prmsg:
	ld	a,(hl)
	cp	0x00		;massage end ?
	ret	z
	ld	c,a
	call	conout
	inc	hl
	jr	prmsg

const:	in     	a,(SIOBC)
	bit	0,a
        jr      z,con_busy			;console status
	ld	a,0xff		;READY= 0xff BUSY=0x00 out Areg
	ret
con_busy:
	ld	a,0x00
	ret
conin:				;console character in
reader:
getchar:			;reader character out
	in     	a,(SIOBC)
	bit	0,a
        jr      z,getchar
	in      a,(SIOBD)
	ret		

conout:				;console character out
list:				;list character out			
punch:				;punch character out
	push	af
	ld	a,c
	call 	putchar
	pop	af
	ret

putchar:
	push	af
putchar01:
	in      a,(SIOBC)
        bit     2,a
        jr      z,putchar01
	pop	af
        out     (SIOBD),a
	ret
home:	
	ret
listst:				;return list status
	ld	a,0x00
	ret
sectran:			;sector translate
	ret
setdma:				;set dma address set bc reg
	ret
seldsk:				;c reg set disk no
	ret
settrk:				;set track address given by c
	ret
setsec:				;set sector numbar given by c
	ret
read:				;read next disk record(assuming disk/trk/sec/dma set)
	ret
init_io:			;tmpz84c015  serial siob ch/pio-a ch/spi-init
	call 	siobinit
	call	pioainit
;	call    init_spi
	ret

write:
	ret
	
siobinit:
	ld	b,12
	ld	hl,SIO_init_data
sioainit01:
	ld	a,(HL)
	out	(SIOBC),a
	inc	hl
	djnz	sioainit01
	ret

pioainit:
	ld	b,3
	ld	hl,PIO_init_data
pioainit01:
	ld	a,(HL)
	out	(PIOAC),a
	inc	hl
	djnz	pioainit01
	ret	

SIO_init_data:
	.db	0x00,0b00110000		;WR0=WR0:set ,WR0: err reset
	.db	0x01,0b00000000		;WR0=WR1:set ,WR1: all int reset
	.db	0x02,0b00000000		;WR0=WR2:set ,WR2: CH-B int set
	.db	0x03,0b11000001		;WR0=WR3:set ,WR3: RxBit=8bit Rx=ready
	.db	0x04,0b01000100		;WR0=WR4:set ,WR4: clck=exIN*1 stop=1bit parity=non
	.db	0x05,0b11101010		;WR0=WR5:set ,WR5: char=8bit hardware flow=non Tx=ready
			 
PIO_init_data:
	.db	0b11001111		;PIOAC:set 0xcf: Mode3 (bit mode)
	.db	0b00011111		;PIOAC:set 0x1f: D4-D0=input D7-D5=output
	.db	0b00000000		;PIOAC:set 0x00: interrupt disables


  
track:	.ds	2		;two bytes for expansion
sector:	.ds	2		;two bytes for expansion
dmaad:	.ds	2		;direct memory address
diskno:	.ds	1		;disk number 0-15
;
;	scratch ram area for bdos use
;begdat	equ	$	 	;beginning of data area
dirbf:	.ds	128	 	;scratch directory area
all00:	.ds	31	 	;allocation vector 0
all01:	.ds	31	 	;allocation vector 1
all02:	.ds	31	 	;allocation vector 2
all03:	.ds	31	 	;allocation vector 3
chk00:	.ds	16		;check vector 0
chk01:	.ds	16		;check vector 1
chk02:	.ds	16	 	;check vector 2
chk03:	.ds	16	 	;check vector 3

	.end
コメントを残す

BIOS, CP/M, Z80の関連記事
  • Z80(HD64180+8255)に萌えたい。5-BIOS完成
  • Z80(KL5C80B12C)に萌えたい。5-BIOS完成
  • Z80(Z80+SIO+PIO)に萌えたい。7-BIOS完成
  • Z80(Z80+8251+8255)に萌えたい。9-BIOS完成
  • Z80に萌えたい CP/M ディスク書き込み改善
  • Z80(Z8S180)に萌えたい。Z8S180でも容量拡張BIOS
おすすめの記事
Z8S180
ハード的にマイコンとの通信がUSB経由でできるようになりましたので、Z80側に通信用確認プログラムを作成して、ちゃんと通信できるか確認したい...
BIOS
今回も前回に引き続きBIOSを作成していきます。そして、実際にCP/Mを起動したいと思います。 前回まだ、未完成だったwboot:から作成し...