2018-08-18 15:33:54 -07:00
|
|
|
// a decompressor for the variant of LZSS used by Bomberman 64.
|
|
|
|
// a matching compressor is available here:
|
|
|
|
// https://github.com/notwa/baku/blob/master/compressor.c
|
|
|
|
|
|
|
|
// this unsafe variant assumes that:
|
|
|
|
// * the 0x400 bytes before the destination are readable and null
|
|
|
|
// * the input data ends exactly where it is expected to
|
|
|
|
// * the input data writes exactly as many bytes as expected
|
|
|
|
// the performance gain over the safe variant is around 38%.
|
|
|
|
|
2018-08-18 15:22:24 -07:00
|
|
|
LzDecomp:
|
|
|
|
// a0: pointer to compressed data (must be RDRAM, cart is unsupported)
|
|
|
|
// a1: compressed size
|
|
|
|
// a2: output pointer
|
|
|
|
// a3: maximum uncompressed size
|
|
|
|
// v0: error code (0 is OK)
|
|
|
|
|
|
|
|
// t0: current pointer for reading
|
|
|
|
// t1: end pointer (exclusive)
|
|
|
|
// t2: current pointer for writing
|
|
|
|
// t3: end pointer (exclusive)
|
|
|
|
// t4: current code, shifted as necessary
|
|
|
|
// t5: 1 means raw, 0 means copy
|
|
|
|
// t6: either raw byte or part of copy command
|
|
|
|
// t7: current pseudo-position
|
|
|
|
// t8: match length
|
|
|
|
// t9: match position
|
|
|
|
|
|
|
|
beqz a1, LzExit // nothing to decompress? nothing to do!
|
|
|
|
lli v0, 0
|
|
|
|
|
|
|
|
blez a3, LzExit
|
|
|
|
lli v0, 1
|
|
|
|
|
|
|
|
or t0, a0, r0
|
|
|
|
addu t1, a0, a1
|
|
|
|
or t2, a2, r0
|
|
|
|
addu t3, a2, a3
|
|
|
|
|
|
|
|
lli t7, 0x3BE
|
|
|
|
|
|
|
|
LzNextCode:
|
|
|
|
// READ
|
|
|
|
lbu t4, 0(t0)
|
|
|
|
addiu t0, 1
|
|
|
|
|
|
|
|
ori t4, t4, 0x100 // add end marker
|
|
|
|
|
|
|
|
andi t5, t4, 1
|
|
|
|
LzReadCode:
|
|
|
|
beq t2, t3, LzExit
|
|
|
|
lli v0, 0
|
|
|
|
|
|
|
|
// READ
|
|
|
|
lbu t6, 0(t0)
|
|
|
|
addiu t0, 1
|
|
|
|
|
|
|
|
beqz t5, LzCopy
|
|
|
|
nop
|
|
|
|
|
|
|
|
LzRaw:
|
|
|
|
// WRITE
|
|
|
|
addiu t7, 1
|
|
|
|
andi t7, t7, 0x3FF
|
|
|
|
sb t6, 0(t2)
|
|
|
|
addiu t2, 1
|
|
|
|
|
|
|
|
// SHIFT
|
|
|
|
srl t4, 1
|
|
|
|
xori at, t4, 1
|
|
|
|
bnez at, LzReadCode // branch if t4 != 1
|
|
|
|
andi t5, t4, 1
|
|
|
|
|
|
|
|
// reiterate
|
|
|
|
bne t0, t1, LzNextCode
|
|
|
|
nop
|
|
|
|
|
|
|
|
b LzExit
|
|
|
|
lli v0, 0
|
|
|
|
|
|
|
|
LzCopy:
|
|
|
|
// READ
|
|
|
|
lbu t8, 0(t0)
|
|
|
|
addiu t0, 1
|
|
|
|
|
|
|
|
// extract match position
|
|
|
|
sll t9, t8, 2
|
|
|
|
andi t9, 0x0300
|
|
|
|
or t9, t6
|
|
|
|
|
|
|
|
// extract and prepare match length
|
|
|
|
andi t8, 0x003F
|
|
|
|
addiu t8, 3
|
|
|
|
|
|
|
|
// prepare absolute match position
|
|
|
|
subu t9, t7, t9
|
|
|
|
subiu t9, 1
|
|
|
|
andi t9, 0x03FF
|
|
|
|
addiu t9, 1
|
|
|
|
subu t9, t2, t9
|
|
|
|
|
2018-08-18 15:43:04 -07:00
|
|
|
// preemptively move pseudo-position ahead (don't need it for the loop)
|
2018-08-18 15:22:24 -07:00
|
|
|
addu t7, t8
|
|
|
|
andi t7, t7, 0x3FF
|
|
|
|
|
|
|
|
LzCopyLoop:
|
|
|
|
// repurposing t6: byte being copied
|
|
|
|
lbu t6, 0(t9)
|
|
|
|
|
|
|
|
// WRITE
|
|
|
|
subiu t8, 1
|
|
|
|
sb t6, 0(t2)
|
|
|
|
addiu t2, 1
|
|
|
|
|
|
|
|
bnez t8, LzCopyLoop
|
|
|
|
addiu t9, 1
|
|
|
|
|
|
|
|
// SHIFT
|
|
|
|
srl t4, 1
|
|
|
|
xori at, t4, 1
|
|
|
|
bnez at, LzReadCode // branch if t4 != 1
|
|
|
|
andi t5, t4, 1
|
|
|
|
|
|
|
|
// reiterate
|
|
|
|
bne t0, t1, LzNextCode
|
|
|
|
nop
|
|
|
|
|
|
|
|
b LzExit
|
|
|
|
lli v0, 0
|
|
|
|
|
|
|
|
LzExit:
|
|
|
|
jr ra
|
|
|
|
nop
|