Apple2000/src/Decompress.s

532 lines
14 KiB
ArmAsm

SECTION APPLEII,CODE
*** NOTE ***
* The Destination drive is chosen by putting the disk buffer address in the
* the global var Dest_Disk_Buffer !!!!!
**************************************
*
* DecompressDisk:
* This function does an entire decompression & encoding of a disk file
* compressed with "Dalton Disk Disintegrator 2.0" to the emulated 5 1/4" floppy.
*
* Inputs: D_FileSize = total length of compressedData (including header)
* CompressedData (with prodos header) at mem ptd by InstTbl_Var
*
* Output: Floppy Image in disk_Buffer memory...
*
even
DecompressDisk:
movem.l d2-d4/a2-a5,-(sp)
jsr Decomp_Init
move.l #3,d0 ;should be a 0...
bsr ReadNBitsOld
move.l #8,d0
bsr ReadNBitsOld
lea ReverseByteTbl,a0
and.l #$00ff,d0
move.b (a0,d0.w),d0 ;ReverseByte
move.l d0,D_VolumeNum
******************
move.l #0,d3 ;D3 = Track #
.lp35tk
lea .TrackBuffer,a0
bsr DecompressTrackData ;decompress track data...
move.l #15,d2 ;D2 = Sector #
.lp16 lea .TrackBuffer,a0
move.l d2,d0
mulu.w #$100,d0
lea (a0,d0.w),a0 ;get offset into track data...
bsr Nibbleize ;take page at A0 & prepare it for encoding (rtns A0)
move.l d3,d0
move.l d2,d1
bsr EncodeSector ;Encode Nibble Data into disk image...
dbf d2,.lp16 ;do all sectors on this track...
addq.b #1,d3 ;do all 35 tracks...
cmp.b #34,d3
bls.b .lp35tk
movem.l (sp)+,d2-d4/a2-a5
rts
.TrackBuffer ds.b $3000
EVEN
**************************************
* PlainDiskImage_Load:
* This function takes an plain disk image (standard Unix/PC disk file format)
* and builds a perfectly encoded 16 sector disk image in memory...
*
* Note: A "plain disk image" is exactly 143,360 bytes long, and consists of
* the normal data bytes in sequential order (tracks 0 - 34, sectors 0 - 15)
* with NO header/trailer/checksums.
*
* Inputs: Plain image in buffer pointed to by InstTbl_Var
*
* Output: Floppy Image in disk_Buffer memory...
*
EVEN
PlainDiskImage_Load:
movem.l d2-d4/a2-a5,-(sp)
jsr Decomp_Init
move.l InstTbl_Var,D_Source ;shouldn't be any headers in this file...
move.l #254,D_VolumeNum
******************
move.l #0,d3 ;d3 = Track #
.lp35tk
move.l #15,d2 ;d2 = Sector #
.lp16 move.l InstTbl_Var,a0
move.l d3,d0
mulu.w #$1000,d0 ;trk offset
lea (a0,d0.l),a0
move.l d2,d0 ;sect offset
mulu.w #$100,d0
lea (a0,d0.w),a0 ;get offset into track data...
bsr Nibbleize ;take page at A0 at prepare it for encoding
move.l d3,d0 ;trk
move.l d2,d1 ;sec
bsr EncodeSector ;Auto-Inc'ing write to floppy area...
dbf d2,.lp16 ;do all 16 sectors in each track....
addq.b #1,d3 ;do all 35 tracks...
cmp.b #34,d3
bls.b .lp35tk
movem.l (sp)+,d2-d4/a2-a5
rts
even
even
****************************************
* EncodeSector: (see dos 3.3 code at $b82a)
* Takes 342 bytes of "Nibble-ized" data and encodes data to
* disk drive. (+ sector header/trailers, etc).
*
* WARNING! This function writes sector data into a specific offset in a track,
* NOT 1st searching for an area to replace! Only use to write ALL 16 sectors of a track.
*
* Inputs: Floppy Image in disk_Buffer memory (normal)
* D_VolumeNum = disk Volume #
* A0 -> 342 bytes of Nibbilized data
* D0 = Track number (0 - 34)
* D1 = Sector number (0 - 15)
*
* Output: One sector of disk data encoded to "Dest_Buffer" !!! (either buffer 1 or 2)
* Note: Rewrite these damn routines to handle simple source/dest ptrs later!!!!!
EncodeSector:
;do any track/sector error checking here...!
movem.l d2-d4/a2-a5,-(sp)
move.l a0,a5 ;a5-> NibbleHunk Source
move.l d0,d3 ;d3 = track #
move.l d1,d4 ;d4 = sector #
move.l Dest_Disk_Buffer,a4 ;Compute Track offset
mulu.w #disk_TrackLen,d0
lea (a4,d0.l),a4
move.w (SectorReMapTbl.l,d4.w*2),d1 ;and sector offset
mulu.w #$18a,d1
lea (a4,d1.l),a4 ;a4 -> Hard sector offset in disk memory
move.w #22/2-1,d0 ;write 22 FF's (sync field) (MUST BE < 26!!)
.sync1 move.w #$ffff,(a4)+
dbf d0,.sync1
.head1 move.l #$ffd5aa96,(a4)+ ;FF + addr field header D5 AA 96 [26]
;*** 4X4 encode the following: ***
.Vol move.l D_VolumeNum,d0 ;Volume #
move.l d0,d2 ;chksum
bsr .Do4x4
.Trk move.l d3,d0 ;Track #
eor.l d0,d2
bsr.b .Do4x4
.Sec move.l d4,d0 ;Soft Sector num...
lea SectorReMapTbl,a0 ;remap soft to hard sector #
move.w (a0,d0.w*2),d0
eor.l d0,d2
bsr.b .Do4x4
.ChkSum move.l d2,d0
bsr.b .Do4x4 ;EOR'd checksum [34 bytes]
.trail1 move.l #$deaaebff,(a4)+ ;addr field trailer DE AA EB...
.sync2 move.l #$ffffffff,(a4)+ ;5 FF's (sync field, exactly 5!)
.head2 move.w #$d5aa,(a4)+ ;Data header D5 AA AD [45 bytes]
move.b #$ad,(a4)+
lea $100(a5),a2 ;a2 -> NibbleHunk2
lea EncodeLkUpTbl,a3 ;a3 -> LookUpTable (apple $ba29) (6 bit val -> disk num)
moveq.l #0,d2 ;d2 = Accumulator
moveq.l #$56,d3 ;d3 = YReg
bra.b .first ;Now go do 343 bytes of Data!!!
.lp1 move.b (a2,d3),d2 ;lda $bc00,y
.first move.b -1(a2,d3),d4 ;eor $bbff,y
eor.b d4,d2
move.b (a3,d2),(a4)+ ;tax, lda $ba29,x, write it
subq.b #1,d3 ;dey
bne.b .lp1
move.b (a2),d2 ;lda $bc00
move.l a5,a2 ;a2 -> NibbleHunk
.lp2 move.b (a2,d3),d4 ;eor $bb00,y
eor.b d4,d2
move.b (a3,d2),(a4)+ ;tax, lda $ba29,x, write it
move.b (a2,d3),d2 ;lda $bb00,y
addq.b #1,d3 ;iny
bne.b .lp2
move.b (a3,d2),(a4)+ ;tax, lda $ba29,x, write it (jsr $b8bb) last byte
.trail2 move.w #$deaa,(a4)+ ;data field trailer DE AA EB... [391 bytes]
move.b #$eb,(a4)+
move.w #$ffff,(a4)+ ;fill in the rest like dos 3.3 does... [394 bytes]
move.b #$eb,(a4)+
movem.l (sp)+,d2-d4/a2-a5
rts
.Do4x4 move.b d0,d1 ;do 4X4 encoding of byte in D0!!!
lsl.w #7,d0
move.b d1,d0
or.w #$aaaa,d0
move.w d0,(a4)+
rts
;.Do4x4 move.b d0,d1 ;OLD 4X4 encoding of byte in D0!!!
lsr.b #1,d0
or.b #$aa,d0
move.b d0,(a4)+
or.b #$aa,d1
move.b d1,(a4)+
rts
EncodeLkUpTbl: ;($ba29 - $ba68 in Dos 3.3)
dc.b $96,$97,$9A,$9B,$9D,$9E,$9F,$A6,$A7,$AB,$AC,$AD,$AE,$AF
dc.b $B2,$B3,$B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC,$BD,$BE,$BF,$CB
dc.b $CD,$CE,$CF,$D3,$D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$E5
dc.b $E6,$E7,$E9,$EA,$EB,$EC,$ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6
dc.b $F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF
SectorReMapTbl: ;(soft to hard remap, $bfb8-$bfc7 in Dos 3.3)
dc.w $00,$0d,$0b,$09,$07,$05,$03,$01,$0e,$0c,$0a,$08,$06,$04,$02,$0f
dc.w $00,$0d,$0b,$09,$07,$05,$03,$01,$0e,$0c,$0a,$08,$06,$04,$02,$0f
even
*****************************************
* Nibble-ize: (see dos 3.3 code at $b800)
* Takes a page (256 bytes) of memory & translates it into 342 bytes of "6 & 2" disk
* encoded crap as done by Apple 5 1/4" dos routines.
*
* SrcData: Nib1: Nib2: (note wrap around of sourcedata & redundant bits
* $ff-+- v (same) for first 2 entries into Nib2)
* | v
* | v $55-+- ^^o
* | ov | ^^^
* $00-+- vo $00-+- o^^
*
* Inputs: a0 = addr of page of memory
* Return: a0 = addr of 342 'nibble-ized' bytes (note: this is an internal static buffer)
Nibbleize:
movem.l d2-d4/a2-a4,-(sp)
lea .NibbleHunk,a1 ;a1-> NibbleHunk1[$00] ($100)
lea .NibbleHunk2,a2 ;a2-> NibbleHunk2[$00] ($56)
* ;*** Do 1st wrap-around case ***
moveq.l #0,d1 ;d1- shifted 2 bits from each of 3 #'s
move.b 1(a0),d0 ;First of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1 ;IGNORE these remaining 6 bits...
move.b $ab(a0),d0 ;2 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,$ab(a1) ;and keep remaining 6 bits...
move.b $55(a0),d0 ;3 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,$55(a1) ;and keep remaining 6 bits...
move.b d1,(a2)+ ;and keep those 6 packed bits...
* ;*** Do 2nd wrap-around case ***
moveq.l #0,d1 ;d1- shifted 2 bits from each of 3 #'s
move.b (a0),d0 ;First of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1 ;IGNORE remaining 6 bits...
move.b $aa(a0),d0 ;2 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,$aa(a1) ;and keep remaining 6 bits...
move.b $54(a0),d0 ;3 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,$54(a1) ;and keep remaining 6 bits...
move.b d1,(a2)+ ;and keep those 6 packed bits...
;*** And do rest of them! ***
lea .NibbleHunk+$100,a1 ;a1-> NibbleHunk1[$100]
;a2-> NibbleHunk2[$02] ($56)
lea $100(a0),a0 ;a0-> SourceByte[$100]
move.w #$54-1,d3 ;d3= countdown
.lp moveq.l #0,d1 ;d1- shifted 2 bits from each of 3 #'s
move.b -(a0),d0 ;First of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,-(a1) ;and keep remaining 6 bits...
move.b -$56(a0),d0 ;2 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,-$56(a1) ;and keep remaining 6 bits...
move.b -$56*2(a0),d0 ;3 of 3
lsr.b #1,d0
roxl.b #1,d1
lsr.b #1,d0
roxl.b #1,d1
move.b d0,-$56*2(a1) ;and keep remaining 6 bits...
move.b d1,(a2)+ ;and keep those 6 packed bits...
dbf d3,.lp
lea .NibbleHunk,a0
movem.l (sp)+,d2-d4/a2-a4
rts
even
.NibbleHunk ds.b 256 ;342 bytes of storage space...
.NibbleHunk2 ds.b 86
.NibblePadding ds.b 8
even
******************************************
*
*read into D_TrackMem
*
* Inputs: A0 -> Track Data dest buffer... (AT LEAST large enough to hold track data!)
DecompressTrackData:
movem.l d2-d4/d6/a2-a6,-(sp)
;********** Function constants ***********
move.l a0,a5 ;A5-> Track Dest ptr (for entire function)
lea ReverseByteTbl,a4 ;A4-> Reverse Byte Lookup table... (bytes[])
lea .Top_Values,a2 ;A2-> Values[] (for entire function)
move.l #16*256-1,d3 ;d4 = Num of bytes to read (incld. 0)
move.l D_Source,a6 ;A6-> DataSource (entire function)
move.l D_SourceBit,d6 ;D6 = Bit offset (entire function)
move.l #19,d2 ;*** Read 20 most frequent bytes for track ***
.vals bfextu (a6){d6:8},d0 ;Read 8 Bits from stream...
addq.l #8,d6
move.b (a4,d0.w),(a2,d2.w) ;ReverseByte & add to list...
dbf d2,.vals
.StartNextDecode
bfextu (a6){d6:1},d0 ;read first bit from stream...
addq.l #1,d6
tst.l d0
bne.b .ReadCode ;if bit=0 then read unique byte, else code...
.ReadUniqueByte
bfextu (a6){d6:8},d0 ;*** bit=0; read 8 bits as a unique byte ***
addq.l #8,d6
move.b (a4,d0.w),(a5)+ ;ReverseByte & AddByte
subq.l #1,d3 ;More to read?
bpl.b .StartNextDecode
bra.b .done
.ReadCode:
lea .CmpList,a3 ;a3 = addr of CmpList (rdCode section only)
move.l #19,d4 ;d4 = Index (of Values[]) (rdCode section only)
moveq.l #0,d0
.CodeLp move.b (a3)+,d1 ;cmpList
bpl.b .CdVal
.Cd1Bit lsl.b #1,d0 ;cmpTbl=-1 *** Read another bit into code ***
move.b d0,-(sp)
bfextu (a6){d6:1},d0 ;Read 1 Bit from stream...
addq.l #1,d6
or.b (sp)+,d0
bra.b .CodeLp ;and repeat
.CdVal cmp.b d1,d0 ;it the code so far = the val in table?
beq.b .match
subq.l #1,d4
bpl.b .CodeLp ;go again if still possible table match...
bfextu (a6){d6:1},d0 ;else read 1 last bit from stream (discarded)
addq.l #1,d6
.repeat ;*** REPEATing byte case ***
bfextu (a6){d6:8},d0 ;Read 8 Bits from stream...
addq.l #8,d6
move.b (a4,d0.w),d2 ;ReverseByte, d2 = RepeatValue
bfextu (a6){d6:8},d4 ;Read 8 Bits from stream... (into d4)
addq.l #8,d6
move.b (a4,d4.w),d4 ;ReverseByte, d4 = Count (0=255)
subq.b #1,d4 ;Prepare it for DBF countdown (to -1)
.rptLp move.b d2,(a5)+ ;AddByte
subq.l #1,d3
dbmi d4,.rptLp ;Do 'x' times or until max bytes read!
tst.l d3 ;More to read?
bpl.b .StartNextDecode
bra.b .done
.match move.b (a2,d4),(a5)+ ;else cmpList[]==code; use Values[d4] & AddByte
subq.l #1,d3 ;More to read?
bpl.b .StartNextDecode
; bra.b .done
.done
move.l d6,D_SourceBit ;D6 = Bit offset (entire function)
movem.l (sp)+,d2-d4/d6/a2-a6
rts
.Top_Values ds.b 20
.CmpList dc.b -1,-1,-1,4,1,-1,15,14,12,11,10,6,5,-1
dc.b 27,15,9,8,3,2,1,0,-1,53,29,28,-1,-2 ;-1 & -2 no longer needed...
CNOP 0,4
************************************
* Inputs: d0 = # of bits to read (normally 8, 3, 2, or 1)
* Return: d0 = bits read (low order)
ReadNBitsOld:
move.l D_Source,a0
move.l D_SourceBit,d1
add.l d0,D_SourceBit ;inc bit cntr by bits read...
bfextu (a0){d1:d0},d0
rts
ReverseByteTbl: *** This is a lookup table of bytes with bit order reversed ***
dc.b $00,$80,$40,$c0,$20,$a0,$60,$e0,$10,$90,$50,$d0,$30,$b0,$70,$f0
dc.b $08,$88,$48,$c8,$28,$a8,$68,$e8,$18,$98,$58,$d8,$38,$b8,$78,$f8
dc.b $04,$84,$44,$c4,$24,$a4,$64,$e4,$14,$94,$54,$d4,$34,$b4,$74,$f4
dc.b $0c,$8c,$4c,$cc,$2c,$ac,$6c,$ec,$1c,$9c,$5c,$dc,$3c,$bc,$7c,$fc
dc.b $02,$82,$42,$c2,$22,$a2,$62,$e2,$12,$92,$52,$d2,$32,$b2,$72,$f2
dc.b $0a,$8a,$4a,$ca,$2a,$aa,$6a,$ea,$1a,$9a,$5a,$da,$3a,$ba,$7a,$fa
dc.b $06,$86,$46,$c6,$26,$a6,$66,$e6,$16,$96,$56,$d6,$36,$b6,$76,$f6
dc.b $0e,$8e,$4e,$ce,$2e,$ae,$6e,$ee,$1e,$9e,$5e,$de,$3e,$be,$7e,$fe
dc.b $01,$81,$41,$c1,$21,$a1,$61,$e1,$11,$91,$51,$d1,$31,$b1,$71,$f1
dc.b $09,$89,$49,$c9,$29,$a9,$69,$e9,$19,$99,$59,$d9,$39,$b9,$79,$f9
dc.b $05,$85,$45,$c5,$25,$a5,$65,$e5,$15,$95,$55,$d5,$35,$b5,$75,$f5
dc.b $0d,$8d,$4d,$cd,$2d,$ad,$6d,$ed,$1d,$9d,$5d,$dd,$3d,$bd,$7d,$fd
dc.b $03,$83,$43,$c3,$23,$a3,$63,$e3,$13,$93,$53,$d3,$33,$b3,$73,$f3
dc.b $0b,$8b,$4b,$cb,$2b,$ab,$6b,$eb,$1b,$9b,$5b,$db,$3b,$bb,$7b,$fb
dc.b $07,$87,$47,$c7,$27,$a7,$67,$e7,$17,$97,$57,$d7,$37,$b7,$77,$f7
dc.b $0f,$8f,$4f,$cf,$2f,$af,$6f,$ef,$1f,$9f,$5f,$df,$3f,$bf,$7f,$ff
even
*************************************
* Inputs: "D_FileSize"
*
* Output: Sets up "D_Source" "D_SourceBit" "D_SourceBitEnd"
Decomp_Init:
move.l InstTbl_Var,D_Source
.Header move.l InstTbl_Var,a0
cmp.w #$0a47,(a0) ;first 2 bytes in ProDos header...
bne .Dos3_3
cmp.b #$4c,2(a0) ;Third byte in ProDos header...
bne .Dos3_3
.ProDos add.l #$7c,D_Source ;ProDos header; add $80 bytes...
.Dos3_3 add.l #$04,D_Source ;Dos 3.3; 4 byte header...
move.l #0,D_SourceBit
move.l D_FileSize,d0 ;do we ever set this??? FIX LATER!!!
sub.l #$80,d0
mulu.l #8,d0
move.l d0,D_SourceBitEnd
rts
* Globals for these functions... *
************************************
D_Source ds.l 1 ;Source addr of decompression data...
D_SourceBit ds.l 1 ;Source bit offset of data...
D_SourceBitEnd ds.l 1 ;Highest bit offset allowable...
D_FileSize ds.l 1 ;Size in Bytes of file read...
D_VolumeNum ds.l 1 ;Volume # of disk...
;D_TrackNum ds.l 1
;D_SectorNum ds.l 1
*************************************
even