mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-22 04:31:30 +00:00
439 lines
12 KiB
Plaintext
439 lines
12 KiB
Plaintext
;
|
|
; File: DeCompressDefProc1.a
|
|
; By Donn Denman
|
|
;
|
|
; Contains: parts of the decompress defprocs that are common to all.
|
|
;
|
|
; Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <4> 8/14/90 DD Changed variable lookup at FetchData and assignment at
|
|
; RememberData to use unsigned word offsets.
|
|
; <3> 7/24/90 gbm Fix branches to next instruction, but don't break debug mode...
|
|
; :)
|
|
; <2> 4/18/90 DD Added RunLength Encoding and Delta Encoding variations.
|
|
; <1> 4/12/90 DD first checked in today
|
|
; BBS versions above:
|
|
;___________________________________________________________________________________________________
|
|
|
|
|
|
********************************************************************************************
|
|
*
|
|
* Procedure UnPackData(SourcePtr, DestPtr, VarTable: ptr; VarTableSize: Longint);
|
|
*
|
|
* Description: Unpack the data from the source pointer to the dest pointer.
|
|
* The unpacking is automatically terminated when the end token is reached.
|
|
*
|
|
*
|
|
********************************************************************************************
|
|
UnPackFrame Record {A6Link},Decr
|
|
SourcePtr DS.L 1
|
|
DestPtr DS.L 1
|
|
VarTablePtr DS.L 1
|
|
VarTableSize DS.L 1
|
|
ReturnAddress DS.L 1
|
|
A6Link DS.L 1
|
|
LocalSize DS.L 0
|
|
EndR
|
|
With UnpackFrame
|
|
|
|
UnPackData
|
|
Link A6,#LocalSize ;do the unpack from ptr A0 into pointer in A1.
|
|
MoveM.L D0-D3/A0-A4,-(SP)
|
|
|
|
; Set up the registers, for fast handling.
|
|
|
|
Move.L SourcePtr(A6),A4 ;input stream.
|
|
Move.L DestPtr(A6),A1 ;output stream.
|
|
Lea CodeDispatchTable,A2 ;dispatch table.
|
|
|
|
Move.L VarTablePtr(A6),A3 ;variable table.
|
|
Move.L VarTableSize(A6),D0 ; table size.
|
|
Bsr InitRemember ;init the var table.
|
|
Bra UnpackLoop ; now go to the unpack loop.
|
|
|
|
ExitUnpack
|
|
MoveM.L (SP)+,D0-D3/A0-A4
|
|
UnLk A6
|
|
Move.L (SP)+,A0
|
|
Add #SourcePtr-ReturnAddress,SP
|
|
Jmp (A0)
|
|
|
|
EndWith
|
|
|
|
********************************************************************************************
|
|
*
|
|
* GetEncodedValue
|
|
*
|
|
* Description: gets the value pointed to by A4 into D0.L. The values are encoded:
|
|
*
|
|
* Tag Range computation method
|
|
* --- ----- ------------------
|
|
* 0..127 0,127 Tag[0]
|
|
* 128..254 -16384,16127 (Tag[0]-$C0)*$100+Tag[1]
|
|
* 255 same as Long Tag[1]<<24 + Tag[2]<<16 + Tag[3]<<8 + Tag[4]
|
|
*
|
|
* Input: A4: pointer to tags.
|
|
*
|
|
* Output: A0: points past tags.
|
|
* D0: value long.
|
|
*
|
|
*
|
|
********************************************************************************************
|
|
GetEncodedValue Head
|
|
|
|
|
|
; try byte encoding, cuz it is so easy.
|
|
|
|
MoveQ #0,D0
|
|
Move.B (A4)+,D0
|
|
|
|
Bpl.S @HaveValue ;got the result already.
|
|
|
|
; is it long encoded?
|
|
|
|
Cmp.B #FourByteValue,D0 ;long?
|
|
Beq.S @FetchLong ;yep, that's fairly easy too.
|
|
|
|
; word encoded value.
|
|
|
|
Sub.W #TwoByteValue*3/2,D0 ;cut back the range, toggle the psuedo sign bit.
|
|
Asl.W #8,D0 ;shift by a byte (*256).
|
|
Asl.W #1,D0 ;shift away the top bit.
|
|
ASR.W #1,D0 ;sign extend the top bit.
|
|
Move.B (A4)+,D0 ;get the next byte.
|
|
Ext.L D0 ;sign extend to a long value.
|
|
Bra.S @HaveValue
|
|
|
|
; long encoding
|
|
|
|
@FetchLong
|
|
Move.B (A4)+,D0 ;add in the next byte.
|
|
Asl.W #8,D0 ;shift by a byte (*256).
|
|
Move.B (A4)+,D0 ;add in the next byte.
|
|
Asl.L #8,D0 ;shift by a byte (*256).
|
|
Move.B (A4)+,D0 ;add in the next byte.
|
|
Asl.L #8,D0 ;shift by a byte (*256).
|
|
Move.B (A4)+,D0 ;add in the next byte.
|
|
|
|
@HaveValue
|
|
Tail
|
|
|
|
;
|
|
; CopyWithLength - copy the data following an encoded length.
|
|
;
|
|
CopyWithLength
|
|
Bsr GetEncodedValue ;get the value into D0.
|
|
IF delta=2 THEN
|
|
Add.W D0,D0 ;double the value if we are processing word chucks.
|
|
EndIF
|
|
;BRA.S CopyData ;fall through
|
|
;
|
|
; CopyData - copy the data already knowing the word length.
|
|
;
|
|
CopyData
|
|
Bra.S @Sub1FirstTime
|
|
@CopyData
|
|
Move.B (A4)+,(A1)+ ;copy a byte.
|
|
@Sub1FirstTime
|
|
DBRA D0,@CopyData
|
|
Rts
|
|
|
|
;
|
|
; RememberLiteral - copy the data already knowing the word length.
|
|
; Also add this literal to the Var Table.
|
|
;
|
|
RememberLiteral
|
|
Bsr.S RememberData ;stuff the data pointed to by A4, for length D0 into the var table.
|
|
; fall through to CopyLiteralAndLoop
|
|
;
|
|
; CopyLiteralAndLoop - copy the data pointed to by the input into the output and loop.
|
|
;
|
|
CopyLiteralAndLoop
|
|
Bsr.S CopyData
|
|
Bra UnpackLoop
|
|
|
|
;
|
|
; RememberWithLength - copy the data preceeded by a byte length.
|
|
; Also add this literal to the Var Table.
|
|
;
|
|
RememberWithLength
|
|
Bsr GetEncodedValue ;get the value into D0.
|
|
IF delta=2 THEN
|
|
Add.W D0,D0 ;double the value if we are processing word chucks.
|
|
EndIF
|
|
Bsr.S RememberData ;stuff the data pointed to by A4, for length D0 into the var table.
|
|
Bra.S CopyData
|
|
|
|
;
|
|
; InitRemember - Init the var table.
|
|
; Entry: A3 - Var Table.
|
|
; D0 - Table size.
|
|
;
|
|
InitRemember
|
|
Move.W D0,VarsList(A3) ;first entry points to the end of the table.
|
|
Move.W #2+VarsList,NextVarIndex(A3) ;point to the next var entry.
|
|
Rts
|
|
|
|
;
|
|
; RememberData - stuff the data pointed to by A4, for length D0 into the var table.
|
|
;
|
|
; Entry: A4 - Pointer to the data.
|
|
; D0 - length of the data.
|
|
; A3 - Var Table.
|
|
;
|
|
; Exit: A1,D0 - preserved.
|
|
; A0,D1 Trashed.
|
|
;
|
|
RememberData
|
|
MoveM.L D0/A1,-(SP)
|
|
|
|
MoveQ #0,D1
|
|
Move.W NextVarIndex(A3),D1 ;get the index into the next var.
|
|
AddQ.W #2,NextVarIndex(A3) ;bump the index.
|
|
Lea -2(A3,D1.L),A0 ;point to the previous data offset.
|
|
Move.W (A0)+,D1 ;it defines where my new string must end.
|
|
Sub.W D0,D1 ;compute my new offset.
|
|
Move.W D1,(A0) ;put my offset in place.
|
|
; Debugging
|
|
IF DoDebug > 0 THEN
|
|
Lea 0(A3,D1.L),A1 ;point to my data loc.
|
|
Cmp.L A0,A1
|
|
BGT.S @NoOverFlow
|
|
BreakError 'Variable Table Over Flow!'
|
|
@NoOverFlow
|
|
ENDIF
|
|
; Debugging
|
|
|
|
Lea 0(A3,D1.L),A0 ;point to my data loc.
|
|
Move.L A4,A1
|
|
Bsr.S BlockMoveBytes
|
|
|
|
MoveM.L (SP)+,D0/A1
|
|
Rts
|
|
|
|
;
|
|
; BlockMoveBytes - block moves bytes from (A1)+ to (A0)+ for D0.W.
|
|
;
|
|
BlockMoveBytes
|
|
Bra.S @Sub1FirstTime
|
|
@CopyData
|
|
Move.B (A1)+,(A0)+ ;copy a byte.
|
|
@Sub1FirstTime
|
|
DBRA D0,@CopyData
|
|
Rts
|
|
|
|
;
|
|
; ReuseByte2Length - Reuse the data indexed by the following byte, to add 256 to.
|
|
;
|
|
ReuseByte2Length
|
|
MoveQ #0,D0
|
|
Move.B (A4)+,D0 ;get the length from the input stream
|
|
Add.W #Max1ByteReuse+256,D0 ;bump by the number of vars we can ref in one byte.
|
|
Bra.S FetchData ;call FetchData.
|
|
;
|
|
; ReuseWordLength - copy the data following a word length.
|
|
;
|
|
ReuseWordLength
|
|
MoveQ #0,D0
|
|
Move.B (A4)+,D0 ;get the length from the input stream
|
|
Asl.W #8,D0 ;shift into high byte.
|
|
Bra.S ReuseLowByte
|
|
;
|
|
; ReuseByteLength - Reuse the data indexed by the following byte.
|
|
;
|
|
ReuseByteLength
|
|
MoveQ #0,D0
|
|
ReuseLowByte
|
|
Move.B (A4)+,D0 ;get the length from the input stream
|
|
Add.W #Max1ByteReuse,D0 ;bump by the number of vars we can ref in one byte.
|
|
;Bra.S FetchData ;call FetchData.
|
|
|
|
;
|
|
; FetchData - retrieve the data from index D0 of the var table.
|
|
;
|
|
; Entry: A1 - Pointer to the output stream.
|
|
; D0 - index the data.
|
|
; A3 - Var Table.
|
|
;
|
|
; Exit: A0,D0,D1 Trashed.
|
|
;
|
|
FetchData
|
|
Add.W D0,D0 ;make the index into an offset.
|
|
; Debugging
|
|
IF DoDebug > 0 THEN
|
|
Cmp.W NextVarIndex(A3),D0 ;are we indexing too far into the table?
|
|
BLo.S @NoProblem
|
|
BreakError 'Error - Index beyond end of vars list'
|
|
@NoProblem
|
|
ENDIF
|
|
; Debugging
|
|
Lea VarsList(A3,D0),A0 ;point to the previous entry (end of this string).
|
|
Move.W (A0)+,D0 ;get the data offset of the previous entry.
|
|
MoveQ #0,D1 ;clear high word, so unsigned offsets will work.
|
|
Move.W (A0),D1 ;get the offset of this entry.
|
|
Sub.W D1,D0 ;compute the length of this entry.
|
|
Lea 0(A3,D1.L),A0 ;point to the string.
|
|
|
|
Exg A0,A1 ;point A1 to the string, A0 to the output Stream.
|
|
Bsr.S BlockMoveBytes
|
|
Move.L A0,A1 ;get output ptr back.
|
|
Rts
|
|
|
|
;
|
|
; ReuseData - Reuse the data indexed by the encoded byte.
|
|
;
|
|
ReuseData
|
|
Bsr.S FetchData ;fetch the data from the var table.
|
|
Bra UnpackLoop ; go back to the main loop.
|
|
|
|
HandleExtensions
|
|
Move.B (A4)+,D0 ;get the extension opCode.
|
|
Beq.S @JumpTableTrans
|
|
SubQ.B #RunLengthByteTransCode,D0 ; runlength encoding by bytes?
|
|
Blo.S @EntryVectorTrans ; is it an entry vector trans?
|
|
Beq RunLengthByteTrans
|
|
SubQ.B #DiffWordTransCode-RunLengthByteTransCode,D0 ;peel off the next two cases.
|
|
Blo RunLengthWordTrans
|
|
Beq DiffWordTrans
|
|
SubQ.B #DiffEncLongTransCode-DiffWordTransCode,D0 ;peel off the next two cases.
|
|
Blo DiffEncWordTrans
|
|
Beq DiffEncLongTrans
|
|
BreakError 'got an undefined Extension op-code'
|
|
Bra @Return
|
|
|
|
; EntryVector transformation
|
|
; Format is as follows:
|
|
; BranchOffset Delta NumEntries Offset0 < Offset1 Offset2 ... OffsetN >
|
|
; where each item is an encoded value.
|
|
; Offset1...OffsetN is an optional words list that is
|
|
; present only if Delta==0. If Delta != 0 then
|
|
; the Delta is added to Offset0 to create Offset1 etc.
|
|
;
|
|
@EntryVectorTrans
|
|
MoveM.L D2-D7,-(SP)
|
|
|
|
Move.W #$6100,D3
|
|
Move.W #$4EED,D5
|
|
Bsr.S GoGetEncodedValue ;get the initial branch offset.
|
|
Move.W D0,D4
|
|
Bsr.S GoGetEncodedValue ;get the Delta amount.
|
|
Move.W D0,D2
|
|
Bsr.S GoGetEncodedValue ;get the number of entries.
|
|
Move.W D0,D7
|
|
Bsr.S GoGetEncodedValue ;get the inital offset.
|
|
Move.W D0,D6
|
|
Bra.S @HaveOffset
|
|
@ExpandEntryVector
|
|
SubQ #8,D4 ;compute the next branch offset.
|
|
Tst D2 ;is there an offset list?
|
|
Beq.S @GetNextOffset ;if the delta is constant (non-zero) then
|
|
Add.W D2,D6 ; compute next offset.
|
|
Bra.S @HaveOffset
|
|
@GetNextOffset
|
|
Bsr.S GoGetEncodedValue ;get the next offset.
|
|
Move.W D0,D6
|
|
@HaveOffset
|
|
MoveM.W D3-D6,(A1) ;output the next entry vector.
|
|
AddQ #8,A1 ;move the output pointer past the entry.
|
|
DBRA D7,@ExpandEntryVector ;until all entries are done.
|
|
|
|
MoveM.L (SP)+,D2-D7
|
|
Bra.S @Return
|
|
|
|
; JumpTable transformation
|
|
; Format is as follows:
|
|
; Seg# NumEntries Delta0 Delta1 Delta2
|
|
; where each value is encoded.
|
|
;
|
|
@JumpTableTrans
|
|
MoveM.L D3-D7,-(SP)
|
|
|
|
Move.W #$3F3C,D3
|
|
Move.W #$A9F0,D5
|
|
Move.W #6,D6 ;init the offset to our bias.
|
|
Bsr.S GoGetEncodedValue ;get the segment number
|
|
Move.W D0,D4 ;remember seg
|
|
Bsr.S GoGetEncodedValue ;get the number of entries.
|
|
Move.W D0,D7
|
|
Bra.S @skipLastOffset
|
|
@StuffLoop
|
|
Bsr.S GoGetEncodedValue ;get the delta plus bias of 6.
|
|
SubQ #6,D0 ;adjust the delta by my bias (allows some small negs to be a byte).
|
|
Add.W D0,D6 ;add the delta to the last offset.
|
|
MoveM.W D3-D6,(A1) ;output the next jump table entry.
|
|
AddQ #8,A1
|
|
@skipLastOffset
|
|
DBRA D7,@StuffLoop ;until all entries are done.
|
|
MoveM.W D3-D5,(A1) ;output the next jump table entry.
|
|
AddQ #6,A1
|
|
|
|
MoveM.L (SP)+,D3-D7
|
|
@Return
|
|
Rts
|
|
|
|
GoGetEncodedValue
|
|
Bra GetEncodedValue ;get the value
|
|
|
|
RunLengthByteTrans Head
|
|
Bsr.S GoGetEncodedValue ;get the value
|
|
Move.W D0,D1 ;remember value.
|
|
Bsr.S GoGetEncodedValue ;get the rep count.
|
|
@RunLengthByte
|
|
Move.B D1,(A1)+ ;output the value.
|
|
DBRA D0,@RunLengthByte ;loop till all done.
|
|
Tail
|
|
|
|
RunLengthWordTrans Head
|
|
Bsr.S GoGetEncodedValue ;get the value
|
|
Move.W D0,D1 ;remember value.
|
|
Bsr.S GoGetEncodedValue ;get the rep count.
|
|
@RunLengthWord
|
|
Move.W D1,(A1)+ ;output the value.
|
|
DBRA D0,@RunLengthWord ;loop till all done.
|
|
Tail
|
|
|
|
DiffWordTrans Head
|
|
Bsr.S GoGetEncodedValue ;get the initial value
|
|
Move.L D0,D2 ;remember value.
|
|
Bsr.S GoGetEncodedValue ;get the rep count.
|
|
Move.L D0,D1
|
|
Bra.S @FirstTime
|
|
@DiffWord
|
|
Move.B (A4)+,D0 ;get the delta
|
|
Ext.W D0
|
|
Add.W D0,D2 ;add in the signed delta
|
|
@FirstTime
|
|
Move.W D2,(A1)+ ;output the value.
|
|
DBRA D1,@DiffWord ;loop till all done.
|
|
Tail
|
|
|
|
DiffEncWordTrans Head
|
|
Bsr.S GoGetEncodedValue ;get the initial value
|
|
Move.L D0,D2 ;remember value.
|
|
Bsr.S GoGetEncodedValue ;get the rep count.
|
|
Move.L D0,D1
|
|
Bra.S @FirstTime
|
|
@DiffWord
|
|
Bsr.S GoGetEncodedValue ;get the delta.
|
|
Add.L D0,D2 ;add in the signed delta
|
|
@FirstTime
|
|
Move.W D2,(A1)+ ;output the value.
|
|
DBRA D1,@DiffWord ;loop till all done.
|
|
Tail
|
|
|
|
DiffEncLongTrans Head
|
|
Bsr.S GoGetEncodedValue ;get the initial value
|
|
Move.L D0,D2 ;remember value.
|
|
Bsr.S GoGetEncodedValue ;get the rep count.
|
|
Move.L D0,D1
|
|
Bra.S @FirstTime
|
|
@DiffLong
|
|
Bsr.S GoGetEncodedValue ;get the delta.
|
|
Add.L D0,D2 ;add in the signed delta
|
|
@FirstTime
|
|
Move.L D2,(A1)+ ;output the value.
|
|
DBRA D1,@DiffLong ;loop till all done.
|
|
Tail
|