前回で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