X68000用CP/M-68kのBIOSをアップデートしました。以下の2点を修正しました。
- シフトキーなどメタキー入力の挙動修正
- CTRL-Cキーの挙動動作
アップデート済みのCP/M-68KディスクイメージをGoogleDrivに置きました。
通常使用に欠かせない修正となりました。これでキー入力周りは完成かと思います。
少し修正内容を書いておきます。
シフトキーなどメタキーの入力は、同時押しの処理は必要ではなく、キーバッファから1文字読み出して、メタキーだったら即捨てる(何も処理せず、IOCSのKEYINPをコールするところにジャンプする)ことで正しく動作しました。
CTRL-Cは、CP/M-68kでも様々なところで使われるキーバインドで、これが処理できないのは厳しかったのですが、CTRL-Cの例外処理であるTrap#13をCP/M-68kが設定するコードになっていたので、X68000の起動時の設定をそのまま利用するように変更したところ正常に動きました。
修正箇所だけアップしようかと思いましたが面倒なので、全コードアップします。
;*****************************************************************
;* 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
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:
;
; 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
;
; read 128 byte from read_buffer
;
read_disk:
move.b select_drive,d0
cmp.b read_buffer_drive,d0
move.b track,d0
cmp.b read_buffer_track,d0
read_disk3:
bsr read_track
; rts
move.b sector,d0
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
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
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を実行
; 該当するセクタ位置における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としてライト用バッファが更新されたことを示す
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
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
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
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
;
; ディレクトリトラックへの書き込み
;
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
; 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にジャンプ
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
; rts
andi.l #$ff,d1 ; do only for exceptions 0 - 255
cmpi #47,d1 ; 47d(2FH)
cmpi #9,d1 ; or Trace
beq noset
beq noset
lsl #2,d1 ; multiply exception number by 4
movea.l d1,a0
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
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
;
; 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
;
; 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
; section bss
read_buffer: ds.b $2000
write_buffer: ds.b $2000
dir_buffer: ds.b 128 ; directory buffer
ckv1: ds.b 32
alv1: ds.b 64
;keyboard_check: dc.l $10
end
LEAでアセンブルして、出来上がったバイナリをCPMのシステムに張り付けてCPM.SYSを作ってください。あとはブートローダーに書いたディスクの位置に書き込めば完了です。