misc/adotr.s
;========================================================================================
; adotr.s
; Copyright (C) 2003-2023 Makoto Kamada
;
; This file is part of the XEiJ (X68000 Emulator in Java).
; You can use, modify and redistribute the XEiJ if the conditions are met.
; Read the XEiJ License for more details.
; https://stdkmd.net/xeij/
;========================================================================================
.include doscall.mac
.include control2.mac
.include iocscall.mac
.include misc.mac
.include push2.mac
.if STEP=1
dBLK reg d4 ;ブロックの末尾(4の倍数)
aOUT1 reg a1 ;出力ポインタ1(偶数)
aOUT2 reg a2 ;出力ポインタ2(偶数)
aIN reg a3 ;入力ポインタ(4の倍数)
aEND reg a4 ;全体の末尾(4の倍数)
;<a1.l:全体の末尾+α。長さ0は不可
step1:
clr.l d2
lea.l step1_data(pc,d2.w),aIN ;入力ポインタ(4の倍数)
add.l a1,d2
and.w #-4,d2 ;端数を切り捨てる
movea.l d2,aEND ;全体の末尾(4の倍数)
movea.l aIN,aOUT1 ;出力ポインタ1(偶数)
do
;ブロックの末尾を求める
moveq.l #4*16,dBLK
add.l aIN,dBLK ;先頭+4*16=最長の末尾
clr.l d0
add.l aEND,d0 ;全体の末尾
sub.l dBLK,d0 ;-最長の末尾
subx.l d1,d1 ;全体の末尾<最長の末尾?-1:0
and.l d1,d0 ;全体の末尾<最長の末尾?全体の末尾-最長の末尾:0
add.l d0,dBLK ;(全体の末尾<最長の末尾?全体の末尾:最長の末尾)=ブロックの末尾
;下位31ビットを変換する
; 4桁の224進数→31ビット整数。224**4=$96100000
movea.l aOUT1,aOUT2 ;出力ポインタ2(偶数)
do
move.l #-$20202020,d1
add.l (aIN)+,d1 ;4桁の224進数
clr.l d0 ;31ビット整数
moveq.l #40,d3
do
movea.l d0,a0 ;1倍
lsl.l #3,d0 ;8倍
sub.l a0,d0 ;7倍
lsl.l #5,d0 ;224倍
rol.l #8,d1 ;4桁の224進数の上位から
add.l d1,d0 ;1桁ずつ取り出して加える
sf.b d1 ;全体を加えてから
sub.l d1,d0 ;余分な桁を引き戻す
lsr.w #1,d3 ;20,10,5,2余り1
while cc
move.l d0,(aOUT1)+ ;31ビット整数
while <cmpa.l dBLK,aIN>,lo
;上位1ビットを加える
; 0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; 0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; 0xxxxxxxxxxxxxxxPQR0000000000000
; ↓
; Pxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Rxxxxxxxxxxxxxxx
move.w -(aOUT1),d1 ;最後の2バイトから
do
clr.l d0
add.w d1,d1 ;1ビットずつ取り出して
roxr.l #1,d0
add.l d0,(aOUT2)+ ;上位1ビットに加える
while <cmpa.l aOUT1,aOUT2>,lo
while <cmpa.l aEND,aIN>,lo
;キャッシュフラッシュする
lea.l 1f+(2f-1f)*2-32(pc),a0
moveq.l #-(2f-1f),d2
.cpu 68020
jmp 32(a0,d2.w*2)
.cpu 68000
1: clr.w d1
addq.w #3,d1
IOCS _SYS_STAT
2:
;実行する
;<a1.l:末尾(4の倍数+2)
.align 4,$2048 ;movea.l a0,a0
;データ
; data: エンコードされたデータ.l[]
; α($1A)
; a1:
step1_data:
.endif ;STEP=1
.if STEP=2
dOUTEND reg d3 ;.l 出力バッファの末尾
dDICBIT reg d4 ;.b 辞書のページ数のビット数。1~15
dDICEND reg d5 ;.l 辞書の末尾(偶数)
dTEMP reg d6 ;.b ビット読み出しの一時保管場所。上位dLEFTビットが残っている
dLEFT reg d7 ;.b dTEMPの残りビット数
aOUTBUF reg a1 ;.l 出力バッファの先頭(偶数)
aINPPTR reg a2 ;.l 入力ポインタ
aINPEND reg a3 ;.l 入力バッファの末尾(偶数)
aOUTPTR reg a4 ;.l 出力ポインタ
aDICBUF reg a5 ;.l 辞書の先頭(偶数)。アドレス.l,長さ.l
aDICPTR reg a6 ;.l 辞書ポインタ
;<a1.l:入力バッファの末尾。先頭の出力バッファの長さを含めて長さ4以下は不可
step2:
;出力バッファの先頭
moveq.l #1,d0 ;入力バッファの末尾を偶数に切り上げる
add.l a1,d0
and.w #-2,d0
movea.l d0,aOUTBUF ;出力バッファの先頭(偶数)
;ビット読み出しの準備
moveq.l #0,dTEMP ;ビット読み出しの一時保管場所
moveq.l #0,dLEFT ;dTEMPの残りビット数
lea.l step2_data(pc),aINPPTR ;入力バッファの先頭→入力ポインタ
;出力バッファの末尾
moveq.l #24,d1
bsr get_bits
move.l d0,dOUTEND ;出力バッファの長さ
add.l aOUTBUF,dOUTEND ;+出力バッファの先頭=出力バッファの末尾
;辞書の先頭
moveq.l #1,d0 ;出力バッファの末尾を偶数に切り上げる
add.l dOUTEND,d0
and.w #-2,d0
movea.l d0,aDICBUF ;辞書の先頭(偶数)
;辞書のページ数のビット数
moveq.l #4,d1
bsr get_bits
goto eq,data_error ;0は不可
move.b d0,dDICBIT ;辞書のページ数のビット数
;辞書の末尾(偶数)
moveq.l #8,dDICEND
lsl.l dDICBIT,dDICEND ;8*辞書のページ数=辞書の長さ
add.l aDICBUF,dDICEND ;+辞書の先頭=辞書の末尾(偶数)
;メモリを確保する
DOS _GETPDB
move.l dDICEND,d1
sub.l d0,d1
move.l d1,-(sp) ;メモリブロックの長さ
move.l d0,-(sp) ;メモリブロックの先頭
DOS _SETBLOCK
addq.l #8,sp
goto <tst.l d0>,mi,out_of_memory
;辞書を初期化する
; 未定義エントリを参照したときエラーにするため
moveq.l #0,d0
movea.l aDICBUF,a0
do
move.l d0,(a0)+
move.l d0,(a0)+
while <cmpa.l dDICEND,a0>,lo
;変数を初期化する
movea.l aOUTBUF,aOUTPTR ;出力バッファの先頭→出力ポインタ
movea.l aDICBUF,aDICPTR ;辞書の先頭→辞書ポインタ(偶数)
;解凍ループ
do
;入力バッファの末尾を踏み越えていないか
goto <cmpa.l aOUTBUF,aINPPTR>,hs,data_error
;辞書にあるか
moveq.l #1,d1
bsr get_bits
if eq ;0=辞書にない
;辞書に登録する
move.l aOUTPTR,(aDICPTR)+ ;新しい単語の先頭
moveq.l #1,d0
move.l d0,(aDICPTR)+ ;新しい単語の長さ
else ;1=辞書にある
;辞書のページ番号を読み出す
move.b dDICBIT,d1
bsr get_bits
;辞書から取り出す
lsl.l #3,d0 ;8*辞書のページ番号
move.l (aDICBUF,d0.l),a0 ;a0.l:辞書にある単語の先頭
move.l 4(aDICBUF,d0.l),d0 ;d0.l:辞書にある単語の長さ
;エントリが定義されているか
goto eq,data_error
;出力バッファの末尾を踏み越えないか
; ここで止めないとメモリブロックの末尾を踏み越える可能性がある
addq.l #1,d0 ;辞書にある単語の長さ+1
move.l d0,d1
add.l aOUTPTR,d1
goto <cmp.l dOUTEND,d1>,hi,data_error
;辞書に登録する
move.l aOUTPTR,(aDICPTR)+ ;新しい単語の先頭
move.l d0,(aDICPTR)+ ;辞書にある単語の長さ+1→新しい単語の長さ
;辞書にある単語を出力する
subq.l #2,d0 ;辞書にある単語の長さ-1
forlong d0
move.b (a0)+,(aOUTPTR)+
next
endif
;文字を出力する
move.b (aINPPTR)+,(aOUTPTR)+
;辞書ポインタを巻き戻す
if <cmpa.l dDICEND,aDICPTR>,eq
movea.l aDICBUF,aDICPTR
endif
while <cmpa.l dOUTEND,aOUTPTR>,lo
;キャッシュフラッシュする
moveq.l #-(2f-1f),d0
.cpu 68020
jmp 1f+(2f-1f)*2(pc,d0.w*2)
.cpu 68000
1: moveq.l #3,d1
IOCS _SYS_STAT
2:
;実行する
movea.l aOUTBUF,a0 ;出力バッファの先頭
jmp (a0)
print_exit:
DOS _PRINT
DOS _EXIT
out_of_memory:
pea.l @f(pc)
goto print_exit
@@: .dc.b 'out of memory',13,10,0
.even
data_error:
pea.l @f(pc)
goto print_exit
@@: .dc.b 'data error',13,10,0
.even
;<d1.b:読み出すビット数
;>d0.l:読み出したデータ
;>z:eq=0,ne=0以外
;?d1-d2
get_bits:
moveq.l #0,d0 ;読み出したデータ。上位24ビットを使う
do
if <tst.b dLEFT>,eq ;dTEMPが空
move.b (aINPPTR)+,dTEMP ;新しいdTEMP
addq.b #8,dLEFT ;dTEMPの残りビット数
endif
move.b d1,d2
if <cmp.b dLEFT,d2>,hi
move.b dLEFT,d2 ;d2.b:min(読み出すビット数,dTEMPの残りビット数)
endif
move.b dTEMP,d0 ;読み出したデータの
lsl.l d2,d0 ;下位に押し込む
lsl.b d2,dTEMP ;dTEMPの上位から押し出す
sub.b d2,dLEFT ;dTEMPの残りビット数
sub.b d2,d1 ;読み出すビット数の残り
while ne
lsr.l #8,d0 ;読み出したデータ
rts
;データ
; 入力バッファ、出力バッファ、辞書
step2_data:
.endif ;STEP=2
.if STEP=3
dLENGTH reg d3 ;.l 本体の長さ
aNAME reg a2 ;.l ファイル名
aBODY reg a3 ;.l 本体
aTABLE reg a4 ;.l CRC32テーブル
aEND reg a5 ;.l CRC32テーブルの末尾
.offset 0
NAME: .ds.b 24
DATE: .ds.l 1
CRC32: .ds.l 1
LENGTH: .ds.l 1
BODY:
.text
;バッファを構成する
lea.l step3_data(pc),aNAME ;ファイル名
move.l LENGTH-NAME(aNAME),dLENGTH ;本体の長さ
lea.l BODY-NAME(aNAME),aBODY ;本体
move.l aBODY,d0 ;本体
add.l dLENGTH,d0 ;+本体の長さ=本体の末尾
addq.l #1,d0
and.w #-2,d0 ;偶数に繰り上げる
movea.l d0,aTABLE ;CRC32テーブル
lea.l 4*256(aTABLE),aEND ;CRC32テーブルの末尾
;メモリを確保する
DOS _GETPDB
move.l aEND,d1
sub.l d0,d1
move.l d1,-(sp) ;メモリブロックの長さ
move.l d0,-(sp) ;メモリブロックの先頭
DOS _SETBLOCK
addq.l #8,sp
goto <tst.l d0>,mi,out_of_memory
;CRC32テーブルを作る
movea.l aTABLE,a0
moveq.l #0,d1
do
move.l d1,d0
moveq.l #8-1,d2
for d2
lsr.l #1,d0
if cs
eori.l #$EDB88320,d0
endif
next
move.l d0,(a0)+
addq.b #1,d1
while cc
;CRC32を計算する
movea.l aTABLE,a1
moveq.l #0,d0 ;CRC32
move.l dLENGTH,d1 ;本体の長さ
movea.l aBODY,a0 ;本体
not.l d0
forcontinuelong d1
moveq.l #0,d2
move.b (a0)+,d2
eor.b d0,d2
lsr.l #8,d0
lsl.w #2,d2
move.l (a1,d2.l),d2
eor.l d2,d0
next
not.l d0
;CRC32を比較する
goto <cmp.l CRC32-NAME(aNAME),d0>,ne,crc_error
;ファイルを作る
move.w #$0020,-(sp)
move.l aNAME,-(sp)
DOS _CREATE
addq.l #6,sp
goto <tst.l d0>,mi,cannot_write
move.l dLENGTH,-(sp)
move.l aBODY,-(sp)
move.w d0,-(sp)
DOS _WRITE
move.l d0,d1
move.l DATE-NAME(aNAME),2(sp)
DOS _FILEDATE
DOS _CLOSE
lea.l 10(sp),sp
if <cmp.l dLENGTH,d1>,ne
move.l aNAME,-(sp)
DOS _DELETE
addq.l #4,sp
goto cannot_write
endif
;正常終了
move.l aNAME,-(sp)
DOS _PRINT
pea.l @f(pc)
print_exit:
DOS _PRINT
DOS _EXIT
@@: .dc.b ' created',13,10,0
.even
out_of_memory:
pea.l @f(pc)
goto print_exit
@@: .dc.b 'out of memory',13,10,0
.even
crc_error:
pea.l @f(pc)
goto print_exit
@@: .dc.b 'crc error',13,10,0
.even
cannot_write:
pea.l @f(pc)
goto print_exit
@@: .dc.b 'cannot write',13,10,0
.even
;データ
; data: ファイル名.b[24]
; 日時.l
; 正しい本体のCRC32.l
; 本体の長さ.l
; 本体.b[本体の長さ]
; .even
; a1: CRC32テーブル
step3_data:
.endif ;STEP=3