シフトキーなどメタキーの入力は、同時押しの処理は必要ではなく、キーバッファから1文字読み出して、メタキーだったら即捨てる(何も処理せず、IOCSのKEYINPをコールするところにジャンプする)ことで正しく動作しました。
;*****************************************************************
;* Basic Input/Output Subsystem *
;*****************************************************************
_ccp: equ $150b8
IOCS equ $0f
B_KEYINP equ $00
B_KEYSNS equ $01
B_SFTSNS equ $02
B_BITSNS equ $04
B_PUTC equ $20
B_PRINT equ $21
B_READ equ $46
B_WRITE equ $45
B_CONSOLE equ $2E
B_CLS_ST equ $2A
nfuncs equ $17
dphlen equ $1a ; 1A=26 / disk parameter headerの長さは26
xlt0 equ 0
code equ 1
data equ 2
section code
org $1B000
_init:
move.l #traphndl,$8c ; set up trap #3 handler
;
; 表示画面を80桁×25行に変更
;
movem.l d0-d2,-(sp) ; d0,d1,d2をpush
move.l #$FFFFFFFF,d1
move.l #$004F0017,d2 ; 80(-1)×24(-1)
move.l #B_CONSOLE,d0
trap #IOCS
; 全画面をクリア
move.b #$2,d1
move.l #B_CLS_ST,d0
trap #IOCS
; オープニングメッセージを表示
movem.l (sp)+,d0-d2 ; d0,d1,d2をpop
move.l #initmsg,a6
bsr prtstr
clr.l d0 ; log on disk A, user 0
move.b #$ff,read_buffer_track ; read bufferを不活化
move.b #$ff,write_buffer_track ; write bufferを不活化
traphndl:
move.l #biosbase,a0
cmpi #nfuncs,d0
lsl #2,d0
move.l 0(a0,d0),a0
jsr (a0)
trapng:
rte
biosbase:
dc.l _init
dc.l wboot
dc.l constat
dc.l conin
dc.l conout
dc.l lstout
dc.l pun
dc.l rdr
dc.l home
dc.l seldsk
dc.l settrk
dc.l setsec
dc.l setdma
dc.l read
dc.l write
dc.l listst
dc.l sectran
dc.l setdma
dc.l getseg
dc.l getiob
dc.l setiob
dc.l flush
dc.l setexc
; nfuncs=(*-biosbase)/4 ; BIOSの関数の数
wboot:
bsr flush
move.b #$ff,read_buffer_track
move.b #$ff,write_buffer_track
jmp _ccp
constat:
moveq.l #B_KEYSNS,d0
trap #IOCS
conin:
moveq.l #B_KEYINP,d0
trap #IOCS
; move.l d0,keyboard_check
move.l d0,d1
andi.l #$0000FF00,d1
cmp.l #$00007000,d1 ; SHIFTキーの押下情報を無視
beq conin
cmp.l #$0000F000,d1 ; SHIFTキーの押下情報を無視
beq conin
cmp.l #$00005D00,d1 ; CAPSキーの押下情報を無視
beq conin
cmp.l #$00007100,d1 ; CTRLキーの押下情報を無視
beq conin
cmp.l #$0000F100,d1 ; CTRLキーの押下情報を無視
beq conin
; move.l d0,d1
; andi.l #$000000FF,d1
; cmp.l #$0000001B,d1 ; ESCキーが押された場合はエスケープシーケンスコード処理に移行する
; beq escape_sequence
andi.l #$000000ff,d0 ; IOCSの返す値からASCIIコードを抽出する
;escape_sequence:
; moveq.l #B_KEYINP,d0
; trap #IOCS
;
; andi.l #$000000FF,d0
; cmp.l #$0000002A,d0 ; "*"
; cmp.l #$00000061,d0 ; debugの為に"a"にしてある。
; move.l d0,d1
; andi.l #$0000FF00,d1
; cmp.l #$00007000,d1 ; SHIFTキーの押下情報を無視
; beq escape_sequence
; cmp.l #$00000054,d0 ; "T"
; beq es_delete_line
; bra conin
;es_delete_line:
; ; カーソル位置から右の行を削除する。
; movem.l d0-d1,-(sp) ; d0,d1をpush
; move.b #$0,d1
; move.l #B_CLS_ST,d0
; trap #IOCS
; movem.l (sp)+,d0-d1 ; d0,d1をpush
; bra conin
;es_clear_screen:
; ; 全画面をクリア
; movem.l d0-d1,-(sp) ; d0,d1をpush
; move.b #$2,d1
; move.l #B_CLS_ST,d0
; trap #IOCS
; movem.l (sp)+,d0-d1 ; d0,d1をpush
; bra conin
conout:
moveq.l #B_PUTC,d0
trap #IOCS
prtstr:
move.l a6,a1
moveq.l #B_PRINT,d0
trap #IOCS
lstout:
pun:
rdr:
listst:
move.b #$0,d0
;
; Disk Handlers for X68000(uPD72065) IOCS version
;
home:
getseg:
move.l #memrgn,d0 ; return address of mem region table
getiob:
setiob:
seldsk:
; select disk given by register d1.b
moveq #0,d0
cmp.b #maxdsk,d1 ; 2台を超えてたら、そのままエラーにする
bpl selrtn ; if no, return 0 in d0 / if plus then illegal drive no.
move.b d1,select_drive ; 正しいドライブ数なら、d1をselect_driveにセーブする
move.b select_drive,d0
mulu #dphlen,d0 ; dphlen(1Ah) * d0
add.l #dph0,d0 ; point d0 at correct dph
selrtn:
settrk:
move.b d1,track ; update current track
setsec:
move.b d1,sector
sectran:
; translate sector in d1 with translate table pointed to by d2
; result in d0
move.l d1,d0 ; 今回はセクタ変換(セクタスキュー)をしないので、d1をそのままd0に入れる
setdma:
move.l d1,dma ; CP/MのDMAはシステムが読み書きするアドレスを指している。いわゆるDMAとはもはや無関係
;
; READルーチン
;
read:
; Read one sector from requested disk, track, sector to dma address
; Retry if necessary, return in d0 00 if ok, else non-zero
bsr read_disk
move.l #$0,d0 ; エミュレータ、X68000Zは常に、この処理は成功する
;
; read 128 byte from read_buffer
;
read_disk:
move.b select_drive,d0
cmp.b read_buffer_drive,d0
bne read_disk3 ; select drive != current drive ならDISKを読み、read_bufferをCP/MのDMAの指すアドレスにコピーする
move.b track,d0
cmp.b read_buffer_track,d0
beq read_disk1 ; track == read_buffer’track ならread_bufferを読みCP/MのDMAの指すアドレスにコピーする
read_disk3:
bsr read_track
read_disk1: ; read_bufferからデータを読み、CP/MのDMAの指すアドレスにコピーする
move.b sector,d0
addq.b #1,d0 ; CP/Mはなぜか理論セクタを0から始める。足して引くという意味のないことをしている
subq.b #1,d0 ; そのうち消す予定
lsl.l #7,d0 ; 128 * sector ; 該当するsectorがread_bufferのどこにあるか計算する
lea read_buffer,a0
adda.l d0,a0
movea.l dma,a2
moveq #128,d0
read_disk2: ; 該当するsectorが記録されているread_bufferの128バイトをCP/MのDMAの指すアドレスにコピーする
move.b (a0)+,(a2)+
subq.b #1,d0
bne read_disk2
read_track:
move.l #$03000001,d2 ; sector len:3(1024), side = 0, sector = 1
move.b track,d4
move.b d4,read_buffer_track ; read_bufferがどのトラックを記録しているのかを更新する
; Side setting
andi.l #1,d4 ; d4 is side(0/1)
lsl.l #8,d4 ; left 8bit shift / side:bit 15-08
; Track setting
move.b track,d5
lsr.b #1,d5 ; d5は物理トラック番号
; Drive numver setting
move.b select_drive,d6 ; d6はドライブ番号
move.b d6,read_buffer_drive ; read_bufferがドライブ番号(のトラック番号)を記録しているのかを更新する
lsl.l #8,d6
; DO READ
move.w d5,d0 ; d5 is physical track number
swap d0 ; track:bit23-16
add.l d0,d2 ; set physical track no.
add.l d4,d2 ; set side no.
move.l #$9000,d1 ; 2HD
or.l d6,d1 ; drive number
ori.w #$0070,d1 ; 0111_0000: MFM, RETRY, SEEK
move.l #$2000,d3 ; size 8 * 1024
move.l #read_buffer,a1 ; to memory address
moveq.l #B_READ,d0
trap #IOCS
;
; WRITEルーチン
;
write:
bsr write_disk
move.l #0,d0 ; emulator says always success
;
; write 128 bytes to disk
;
write_disk:
move.b d1,write_type ; d1.bをwite_typeにセーブする。これはdirectory書き込みの時は1になる。通常書き込みの時は0になる
move.b select_drive,d0
cmp.b write_buffer_drive,d0
bne write_disk4 ; select_driveと書き込み用バッファのデータを保持ているドライブ番号(write_buffer_drive)が不一致ならwrite_disk4にジャンプ
move.b track,d0
cmp.b write_buffer_track,d0
beq write_disk1 ; trackとwrite_buffer_trackが等しければ、すでにpre-read済み。つまりライト用バッファにはデータがある。wtite_disk1にジャンプ
write_disk4:
tst.l write_flag ; write_bufferが更新されているか調べる。write_flag=1なら更新されている
beq write_disk5 ; 0ならpre-readを実行する
bsr wrtkw ; 更新されているならdiskを読み、write_bufferへ書き込む
write_disk5:
bsr pre_read ; pre-readを実行
bcc write_disk1 ; no error then go wrired1 / emulator always success.
; 該当するセクタ位置におけるwrite_bufferの128バイトをCP/Mのdmaが指すアドレスにコピーする
write_disk1:
move.b sector,d0
; subq.b #1,d0 ; セクタは0から始まるので、この処理は行わない。
lsl.l #7,d0
lea write_buffer,a0
adda.l d0,a0
movea.l dma,a2
moveq #128,d0
write_disk2:
move.b (a2)+,(a0)+
subq.b #1,d0
bne write_disk2
move.l write_flag,d0
ori.b #1,d0
move.l d0,write_flag ; write_flag = 1としてライト用バッファが更新されたことを示す
cmpi.b #1,write_type ; write_type=1ならディレクトリ書き込み。write_dirへジャンプする
bne write_disk3
bsr write_dir
write_disk3:
move.b select_drive,d0
cmp.b write_buffer_drive,d0
beq go_sync ; もしread_buffer's drive == write_buffer's driveなら、同期する必要があるかもしれない。go_syncへジャンプする
go_sync:
move.b write_buffer_track,d0
cmp.b read_buffer_track,d0
beq sync_buffer ; もしread_buffer's track == write_buffer's trackなら両方のバッファの内容を同期させる必要がある。sync_bufferへジャンプする
;
; リード用バッファとライト用バッファの内容を同期させる
;
sync_buffer:
move.b sector,d0
;* subq.b #1,d0
lsl.l #7,d0
lea write_buffer,a0
lea read_buffer,a1
adda.l d0,a1
adda.l d0,a0
moveq #32,d1
sync_buffer1:
move.l (a0)+,(a1)+
subq.b #1,d1
bne sync_buffer1
wrtkw:
move.b write_buffer_track,d0
cmp.b #$ff,d0
bne wrtkw1 ; 唯一、wbootからコールされた時だけ、d0をクリアして返る?
wrtkw1:
bsr write_track
clr.l d0 ; emulator always success
write_track:
move.l #$03000001,d2 ; sector len:3(1024), side = 0, sector = 1
move.b write_buffer_track,d4
; Side setting
andi.l #1,d4 ; d4 is side(0/1)
lsl.l #8,d4 ; left 8bit shift / side:bit 15-08
; Track setting
move.b write_buffer_track,d5
lsr.b #1,d5 ; d5 is physical track number
; Drive number setting
move.b read_buffer_drive,d6 ; d6 is drive number
lsl.l #8,d6
;* DO WRITE
move.w d5,d0 ; d5 is physical track number
swap d0 ; track:bit23-16
add.l d0,d2 ; set physical track no
add.l d4,d2 ; set side
move.l #$9000,d1 ; 2HD
or.l d6,d1 ; drive number
ori.w #$0070,d1 ; 0111_0000: MFM, RETRY, SEEK
move.l #$2000,d3 ; size 8 * 1024
move.l #write_buffer,a1 ; write_buffer to disk
moveq.l #B_WRITE,d0
trap #IOCS
;
; プリリードPre-read。指示トラック番号の内容をwrite_bufferに書き込む
;
pre_read:
move.l #$03000001,d2 ; sector len:3(1024), side = 0, sector = 1
move.b track,d3
move.b d3,write_buffer_track ; update write_buffer's track
; Side setting
move.b write_buffer_track,d4
andi.l #1,d4 ; d4 is side(0/1)
lsl.l #8,d4 ; left 8bit shift / side:bit 15-08
; Track setting
move.b write_buffer_track,d5
lsr.b #1,d5 ; d5 is physical track number
; Drive number setting
move.b select_drive,d6 ; d6 is drive number
move.b d6,write_buffer_drive ; update write_buffer's drive
lsl.l #8,d6
; DO READ
move.w d5,d0 ; d5 is physical track number
swap d0 ; track:bit23-16
add.l d0,d2 ; set physical track no
add.l d4,d2 ; set side
move.l #$9000,d1 ; 2HD
or.l d6,d1 ; drive number
ori.w #$0070,d1 ; 0111_0000: MFM, RETRY, SEEK
move.l #$2000,d3 ; size 8 * 1024
move.l #write_buffer,a1 ; to memory address
moveq.l #B_READ,d0 ; READ track to write buffer
trap #IOCS
andi #0,CCR ; clear carry flag -> mean success
;
;
write_dir:
move.l #$03000001,d2 ; sector len:3(1024), side = 0, sector = 1
move.b track,d4
; Side setting
andi.l #1,d4 ; d4 is side(0/1)
lsl.l #8,d4 ; left 8bit shift / side:bit 15-08
; Track setting
move.b track,d5
lsr.b #1,d5 ; d5 is physical track number
; Drive number setting
move.b select_drive,d6 ; d6 is drive number
lsl.l #8,d6
* DO WRITE
move.w d5,d0 ; d5 is physical track number
swap d0 ; track:bit23-16
add.l d0,d2 ; set physical track no
add.l d4,d2 ; set side
move.l #$9000,d1 ; 2HD
or.l d6,d1 ; drive number
ori.w #$0070,d1 ; 0111_0000: MFM, RETRY, SEEK
; move.l #$2000,d3 ; size 8 * 1024
move.l #$400,d3 ; size 1024 = 1 sector
move.l #write_buffer,a1 ;; to memory address
moveq.l #B_WRITE,d0
trap #IOCS
;
; FLUSH
;
flush:
tst.l write_flag ; write bufferは更新されたか? 1 is YES / 0 is NO
bne flush1 ; 更新されているのでflush1にジャンプ
clr.l d0 ; return successful
flush1:
bsr wrtkw
setexc:
; andi.l #$ff,d1 * do only for exceptions 0 - 255
; lsl #2,d1 * multiply exception number by 4
; movea.l d1,a0
; move.l d2,(a0) * insert new vector
andi.l #$ff,d1 ; do only for exceptions 0 - 255
cmpi #47,d1 ; 47d(2FH)
beq noset ; this BIOS doesn't set Trap 15
cmpi #9,d1 ; or Trace
beq noset
cmpi #45,d1 ; this BIOS doesn't set Trap #13 / CTRL+C
beq noset
lsl #2,d1 ; multiply exception number by 4
movea.l d1,a0
move.l d2,(a0) ; insert new vector
noset:
;
; section data
;
initmsg:
even
select_drive: dc.b $00 ; seldskの値(ドライブ番号)がセットされる。
track: dc.b $00 ; setrekの値(トラック番号)がセットされる。
read_buffer_track: dc.b $00 ; read_bufferはこのトラック番号の内容を保持ている。
write_buffer_track: dc.b $00 ; write bufferはこのトラック番号の内容を保持している。
read_buffer_drive: dc.b $00
write_buffer_drive: dc.b $00
even
sector: dc.w 0
dma: dc.l 0
write_type: dc.w 0
write_flag: dc.l 0
memrgn: dc.w 1 ; 1 memory region
dc.l $20000 ; starts at 30000 hex ; TPAのスタートアドレス
; dc.l $17800 ; goes until 18000 hex
dc.l $1C0000 ; goes until 1c000 hex ; TPAのメモリ量
;
; disk parameter headers
;
dph0:
dc.l xlt0
dc.w 0 ; dummy
dc.w 0
dc.w 0
dc.l dir_buffer ; pointer to directory buffer
dc.l dpb ; pointer to disk parameter block
dc.l ckv0 ; pointer to check vector
dc.l alv0 ; pointer to allocation vector
dph1:
dc.l xlt0
dc.w 0 ; dummy
dc.w 0
dc.w 0
dc.l dir_buffer ; pointer to directory buffer
dc.l dpb ; pointer to disk parameter block
dc.l ckv1 ; pointer to check vector
dc.l alv1 ; pointer to allocation vector
;
; disk parameter block
;
dpb:
dc.w 64 ; 1トラックあたりの論理セクタ数。両サイドの合計ではない。物理セクタ数でもない。
dc.b 6 ; block shiftS
dc.b 63 ; block mask
dc.b 7 ; extent mask
dc.b 0 ; dummy fill
dc.w 149 ; disk size
dc.w 127 ; 128-1 directory entries
dc.w $c000 ; directory mask
dc.w 32 ; directory check size
dc.w 4 ; track offset.CP/M-68Kのシステムサイズは約25KB。記録するには4トラック必要。
;
; sector translate table
;
;xlt:
; dc.b 1,2,3,4,5,6,7,8
; dc.b 9,10,11,12,13,14,15,16
; dc.b 17,18,19,20,21,22,23,24
; dc.b 25,26
read_buffer: ds.b $2000
write_buffer: ds.b $2000
dir_buffer: ds.b 128 ; directory buffer
ckv1: ds.b 32
alv0: ds.b 64 ; allocation vector
alv1: ds.b 64
;keyboard_check: dc.l $10
end