aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxpress/vlc.s
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2023-01-23 09:36:22 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2023-01-23 09:36:22 +0100
commit09f321e37fc187affa664d32e36e32c0533a7e8e (patch)
tree27f846c194d92a9f4f8e3daea4ff2317e3e66894 /libpsn00b/psxpress/vlc.s
parenta21e949c9aea98cb4b3feee48bb98579bbdfba70 (diff)
downloadpsn00bsdk-09f321e37fc187affa664d32e36e32c0533a7e8e.tar.gz
Add BS v3 decoding, fix MDEC API and strvideo example
Diffstat (limited to 'libpsn00b/psxpress/vlc.s')
-rw-r--r--libpsn00b/psxpress/vlc.s743
1 files changed, 472 insertions, 271 deletions
diff --git a/libpsn00b/psxpress/vlc.s b/libpsn00b/psxpress/vlc.s
index f3a1c67..2de22f7 100644
--- a/libpsn00b/psxpress/vlc.s
+++ b/libpsn00b/psxpress/vlc.s
@@ -1,375 +1,576 @@
# PSn00bSDK MDEC library (GTE-accelerated VLC decompressor)
-# (C) 2022 spicyjpeg - MPL licensed
+# (C) 2022-2023 spicyjpeg - MPL licensed
#
-# Register map:
-# - $a0 = ctx
-# - $a1 = output
-# - $a2 = max_size
-# - $a3 = input
-# - $t0 = window
-# - $t1 = next_window
-# - $t2 = remaining
-# - $t3 = quant_scale
-# - $t4 = is_v3
-# - $t5 = bit_offset
-# - $t6 = block_index
-# - $t7 = coeff_index
-# - $t8 = _vlc_huffman_table
-# - $t9 = &ac_jump_area
+# TODO: reduce the size of the v3 DC coefficient decoder; currently the code is
+# duplicated for each block type, but it can probably be shortened with no
+# performance impact...
-.set noreorder
+.include "gtereg.inc"
-.set VLC_Context_input, 0
-.set VLC_Context_window, 4
-.set VLC_Context_next_window, 8
-.set VLC_Context_remaining, 12
-.set VLC_Context_quant_scale, 16
-.set VLC_Context_is_v3, 18
-.set VLC_Context_bit_offset, 19
-.set VLC_Context_block_index, 20
-.set VLC_Context_coeff_index, 21
-
-.set DECDCTTAB_lut0, 0
-.set DECDCTTAB_lut2, 4
-.set DECDCTTAB_lut3, 36
-.set DECDCTTAB_lut4, 292
-.set DECDCTTAB_lut5, 308
-.set DECDCTTAB_lut7, 324
-.set DECDCTTAB_lut8, 356
-.set DECDCTTAB_lut9, 420
-.set DECDCTTAB_lut10, 484
-.set DECDCTTAB_lut11, 548
-.set DECDCTTAB_lut12, 612
+.set noreorder
+.set noat
+
+.set value, $v0
+.set length, $v1
+.set ctx, $a0
+.set output, $a1
+.set max_size, $a2
+.set input, $a3
+.set temp, $t0
+.set window, $t1
+.set next_window, $t2
+.set remaining, $t3
+.set is_v3, $t4
+.set bit_offset, $t5
+.set block_index, $t6
+.set coeff_index, $t7
+.set quant_scale, $s0
+.set last_y, $s1
+.set last_cr, $s2
+.set last_cb, $s3
+.set huffman_table, $t8
+.set ac_jump_area, $t9
+
+.set VLC_Context_input, 0x0
+.set VLC_Context_window, 0x4
+.set VLC_Context_next_window, 0x8
+.set VLC_Context_remaining, 0xc
+.set VLC_Context_is_v3, 0x10
+.set VLC_Context_bit_offset, 0x11
+.set VLC_Context_block_index, 0x12
+.set VLC_Context_coeff_index, 0x13
+.set VLC_Context_quant_scale, 0x14
+.set VLC_Context_last_y, 0x16
+.set VLC_Context_last_cr, 0x18
+.set VLC_Context_last_cb, 0x1a
+
+.set VLC_Table_ac0, 0x0
+.set VLC_Table_ac2, 0x4
+.set VLC_Table_ac3, 0x24
+.set VLC_Table_ac4, 0x124
+.set VLC_Table_ac5, 0x134
+.set VLC_Table_ac7, 0x144
+.set VLC_Table_ac8, 0x164
+.set VLC_Table_ac9, 0x1a4
+.set VLC_Table_ac10, 0x1e4
+.set VLC_Table_ac11, 0x224
+.set VLC_Table_ac12, 0x264
+.set VLC_Table_dc, 0x2a4
+.set VLC_Table_dc_len, 0x324
.section .text.DecDCTvlcStart
.global DecDCTvlcStart
.type DecDCTvlcStart, @function
DecDCTvlcStart:
+ addiu $sp, -16
+ sw $s0, 0($sp)
+ sw $s1, 4($sp)
+ sw $s2, 8($sp)
+ sw $s3, 12($sp)
+
# Create a new context on-the-fly without writing it to memory then jump
# into DecDCTvlcContinue(), skipping context loading.
- lw $t0, 8($a3) # window = (bs->data[0] << 16) | (bs->data[0] >> 16)
- nop
- srl $v0, $t0, 16
- sll $t0, 16
-
- lw $t1, 12($a3) # next_window = (bs->data[1] << 16) | (bs->data[1] >> 16)
- or $t0, $v0
- srl $v0, $t1, 16
- sll $t1, 16
-
- lhu $t2, 0($a3) # remaining = bs->uncomp_length * 2
- or $t1, $v0
-
- lhu $t3, 4($a3) # quant_scale = (bs->quant_scale & 63) << 10
- sll $t2, 1
- andi $t3, 63
-
- lhu $t4, 6($a3) # is_v3 = !(bs->version < 3)
- sll $t3, 10
- sltiu $t4, $t4, 3
- xori $t4, 1
-
- li $t5, 32 # bit_offset = 32
- li $t6, 5 # block_index = 5
- li $t7, 0 # coeff_index = 0
+ lw window, 8(input) # window = (bs->data[0] << 16) | (bs->data[0] >> 16)
+ li last_y, 0
+ srl temp, window, 16
+ sll window, 16
+ or window, temp
+
+ # next_window = (bs->data[1] << 16) | (bs->data[1] >> 16)
+ lw next_window, 12(input)
+ li last_cr, 0
+ srl temp, next_window, 16
+ sll next_window, 16
+ or next_window, temp
+
+ lhu remaining, 0(input) # remaining = bs->uncomp_length * 2
+ li last_cb, 0
+ sll remaining, 1
+
+ lw temp, 4(input) # quant_scale = (bs->quant_scale & 63) << 10
+ li bit_offset, 32
+ andi quant_scale, temp, 63
+ sll quant_scale, 10
+
+ srl temp, 16 # is_v3 = !(bs->version < 3)
+ sltiu is_v3, temp, 3
+ xori is_v3, 1
+
+ li block_index, 5
+ li coeff_index, 0
j _vlc_skip_context_load
- addiu $a3, 16 # input = &(bs->data[2])
+ addiu input, 16 # input = &(bs->data[2])
.section .text.DecDCTvlcContinue
.global DecDCTvlcContinue
.type DecDCTvlcContinue, @function
DecDCTvlcContinue:
- lw $a3, VLC_Context_input($a0)
- lw $t0, VLC_Context_window($a0)
- lw $t1, VLC_Context_next_window($a0)
- lw $t2, VLC_Context_remaining($a0)
- lhu $t3, VLC_Context_quant_scale($a0)
- lb $t4, VLC_Context_is_v3($a0)
- lb $t5, VLC_Context_bit_offset($a0)
- lb $t6, VLC_Context_block_index($a0)
- lb $t7, VLC_Context_coeff_index($a0)
+ addiu $sp, -16
+ sw $s0, 0($sp)
+ sw $s1, 4($sp)
+ sw $s2, 8($sp)
+ sw $s3, 12($sp)
+
+ lw input, VLC_Context_input(ctx)
+ lw window, VLC_Context_window(ctx)
+ lw next_window, VLC_Context_next_window(ctx)
+ lw remaining, VLC_Context_remaining(ctx)
+ lb is_v3, VLC_Context_is_v3(ctx)
+ lb bit_offset, VLC_Context_bit_offset(ctx)
+ lb block_index, VLC_Context_block_index(ctx)
+ lb coeff_index, VLC_Context_coeff_index(ctx)
+ lhu quant_scale, VLC_Context_quant_scale(ctx)
+ lh last_y, VLC_Context_last_y(ctx)
+ lh last_cr, VLC_Context_last_cr(ctx)
+ lh last_cb, VLC_Context_last_cb(ctx)
_vlc_skip_context_load:
- # Determine how many bytes to output. This whole block of code basically
- # does this:
+ # Determine how many bytes to output.
+ # if (max_size <= 0) max_size = 0x3fff0000
# max_size = min((max_size - 1) * 2, remaining)
# remaining -= max_size
- bgtz $a2, .Lmax_size_valid # if (max_size <= 0) max_size = 0x7ffe0000
- addiu $a2, -1 # else max_size = (max_size - 1) * 2
- lui $a2, 0x3fff
+ bgtz max_size, .Lmax_size_valid
+ addiu max_size, -1
+ lui max_size, 0x3fff
.Lmax_size_valid:
- sll $a2, 1
+ sll max_size, 1
- blt $a2, $t2, .Lmax_size_ok # if (max_size > remaining) max_size = remaining
- lui $v1, 0x3800
- move $a2, $t2
-.Lmax_size_ok:
- subu $t2, $a2 # remaining -= max_size
+ subu remaining, max_size
+ bgez remaining, .Lmax_size_ok
+ lui temp, 0x3800
+ addu max_size, remaining
+ li remaining, 0
+
+.Lmax_size_ok:
# Write the length of the data that will be decoded to first 4 bytes of the
# output buffer, which will be then parsed by DecDCTin().
- srl $v0, $a2, 1 # output[0] = 0x38000000 | (max_size / 2)
- or $v0, $v1
- sw $v0, 0($a1)
+ srl value, max_size, 1 # output[0] = 0x38000000 | (max_size / 2)
+ or value, temp
+ sw value, 0(output)
# Obtain the addresses of the lookup table and jump area in advance so that
# they don't have to be retrieved for each coefficient decoded.
- lw $t8, _vlc_huffman_table
- la $t9, .Lac_prefix_10
+ lw huffman_table, _vlc_huffman_table
+ la ac_jump_area, .Lac_prefix_01 - 32
- beqz $a2, .Lstop_processing
- addiu $a1, 4 # output = (uint16_t *) &output[1]
+ beqz max_size, .Lstop_processing
+ addiu output, 4
.Lprocess_next_code_loop: # while (max_size)
# This is the "hot" part of the decoder, executed for each code in the
# bitstream. The first step is to determine if the next code is a DC or AC
- # coefficient.
- bnez $t7, .Lprocess_ac_coefficient
- addiu $t7, 1 # coeff_index++
- bnez $t4, .Lprocess_dc_v3_coefficient
- li $v1, 0x01ff
+ # coefficient; at the same time the GTE is given the task of counting the
+ # number of leading zeroes/ones in the code (which takes 2 more cycles).
+ mtc2 window, C2_LZCS
+
+ bnez coeff_index, .Lprocess_ac_coefficient
+ addiu coeff_index, 1
+ bnez is_v3, .Lprocess_dc_v3_coefficient
+ li temp, 0x1ff
.Lprocess_dc_v2_coefficient: # if (!coeff_index && !is_v3)
# The DC coefficient in version 2 frames is not compressed. Value 0x1ff is
# used to signal the end of the bitstream.
- srl $v0, $t0, 22 # prefix = (window >> (32 - 10))
- beq $v0, $v1, .Lstop_processing # if (prefix == 0x1ff) break
- or $v0, $t3 # *output = prefix | quant_scale
- sll $t0, 10 # window <<= 10
- b .Lwrite_value
- addiu $t5, -10 # bit_offset -= 10
+ # prefix = window >> (32 - 10)
+ # if (prefix == 0x1ff) break
+ # *output = prefix | quant_scale
+ srl value, window, 22
+ beq value, temp, .Lstop_processing
+ or value, quant_scale
+ sll window, 10
+ addiu bit_offset, -10
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lprocess_dc_v3_coefficient: # if (!coeff_index && is_v3)
- # TODO: version 3 is currently not supported.
- jr $ra
- li $v0, -1
-
-.Lprocess_ac_coefficient: # if (coeff_index)
- # Check whether the prefix code is one of the shorter, more common ones,
- # and start counting the number of leading zeroes/ones using the GTE (which
- # takes 2 more cycles).
- srl $v0, $t0, 30
- li $v1, 3
- beq $v0, $v1, .Lac_prefix_11
- li $v1, 2
- beq $v0, $v1, .Lac_prefix_10
- li $v1, 1
- mtc2 $t0, $30
- beq $v0, $v1, .Lac_prefix_01
+ # Version 3 DC coefficients are variable-length deltas, prefixed with a
+ # Huffman code indicating their length. Since the prefix code is up to 7
+ # bits long, it makes sense to decode it with a simple 128-byte lookup
+ # table rather than using the GTE. The codes are different for luma and
+ # chroma blocks, so each table entry contains the decoded length for both
+ # block types (packed as two nibbles). Prefix 111111111 is used to signal
+ # the end of the bitstream.
+ # prefix = window >> (32 - 9)
+ # if (prefix == 0x1ff) break
+ # lengths = huffman_table->dc[prefix >> 2]
+ srl length, window, 23
+ beq length, temp, .Lstop_processing
+ srl length, 2
+ addu length, huffman_table
+
+ addiu $at, block_index, -4
+ bltz $at, .Ldc_block_y
+ lbu length, VLC_Table_dc(length)
+ beqz $at, .Ldc_block_cb
+ andi length, 15 # if (block_index >= Cb) dc_length = lengths & 15
+
+.Ldc_block_cr: # if (block_index > Cb)
+ # prefix_length = huffman_table->dc_len[dc_length] & 15
+ addu temp, length, huffman_table
+ lbu temp, VLC_Table_dc_len(temp)
+ li $at, 32
+ andi temp, 15
+
+ sllv window, window, temp
+ beqz length, .Ldc_cr_zero # if (dc_length)
+ subu bit_offset, temp
+
+ subu $at, length # value = window >> (32 - dc_length)
+ srlv value, window, $at
+
+ # Decode the sign bit, then add the decoded delta to the current value.
+ # if (!(window >> 31)) value -= (1 << dc_length) - 1
+ bltz window, .Ldc_cr_positive
+ li temp, -1
+ srlv temp, temp, $at
+ subu value, temp
+.Ldc_cr_positive:
+ addu last_cr, value
+ andi last_cr, 0x3ff
+
+.Ldc_cr_zero:
+ sll temp, last_cr, 2 # *output = (last_cr << 2) | quant_scale
+ or temp, quant_scale
+ b .Lupdate_window_dc # update_window(dc_length)
+ sh temp, 0(output)
+
+.Ldc_block_cb: # if (block_index == Cb)
+ # prefix_length = huffman_table->dc_len[dc_length] & 15
+ addu temp, length, huffman_table
+ lbu temp, VLC_Table_dc_len(temp)
+ li $at, 32
+ andi temp, 15
+
+ sllv window, window, temp
+ beqz length, .Ldc_cb_zero # if (dc_length)
+ subu bit_offset, temp
+
+ subu $at, length # value = window >> (32 - dc_length)
+ srlv value, window, $at
+
+ # Decode the sign bit, then add the decoded delta to the current value.
+ # if (!(window >> 31)) value -= (1 << dc_length) - 1
+ bltz window, .Ldc_cb_positive
+ li temp, -1
+ srlv temp, temp, $at
+ subu value, temp
+.Ldc_cb_positive:
+ addu last_cb, value
+ andi last_cb, 0x3ff
+
+.Ldc_cb_zero:
+ sll value, last_cb, 2 # *output = (last_cb << 2) | quant_scale
+ or value, quant_scale
+ b .Lupdate_window_dc # update_window(dc_length)
+ sh value, 0(output)
+
+.Ldc_block_y: # if (block_index < Cb)
nop
+ srl length, 4 # dc_length = lengths >> 4
+
+ # prefix_length = huffman_table->dc_len[dc_length] >> 4
+ addu temp, length, huffman_table
+ lbu temp, VLC_Table_dc_len(temp)
+ li $at, 32
+ srl temp, 4
+
+ sllv window, window, temp
+ beqz length, .Ldc_y_zero # if (dc_length)
+ subu bit_offset, temp
+
+ sll temp, last_y, 2
+ subu $at, length # value = window >> (32 - dc_length)
+ srlv value, window, $at
+
+ # Decode the sign bit, then add the decoded delta to the current value.
+ # if (!(window >> 31)) value -= (1 << dc_length) - 1
+ bltz window, .Ldc_y_positive
+ li temp, -1
+ srlv temp, temp, $at
+ subu value, temp
+.Ldc_y_positive:
+ addu last_y, value
+ andi last_y, 0x3ff
+
+.Ldc_y_zero:
+ sll temp, last_y, 2 # *output = (last_y << 2) | quant_scale
+ or temp, quant_scale
+ b .Lupdate_window_dc # update_window(dc_length)
+ sh temp, 0(output)
- # If the code is longer, retrieve the number of leading zeroes from the GTE
- # and use it as an index into the jump area. Each block in the area is 8
- # instructions long and handles decoding a specific prefix.
- mfc2 $v0, $31
- li $v1, 11
- bgt $v0, $v1, .Lreturn_error # if (prefix > 11) return -1
- sll $v0, 5 # jump_addr = &ac_jump_area[prefix * 8 * sizeof(u32)]
- addu $v0, $t9
- jr $v0
+.Lprocess_ac_coefficient: # if (coeff_index)
+ # Check whether the prefix code is 10 or 11 (i.e. if it starts with 1). If
+ # not, retrieve the number of leading zeroes from the GTE and use it as an
+ # index into the jump area. Each block in the area is 8 instructions long
+ # and handles decoding a specific prefix.
+ mfc2 temp, C2_LZCR
+
+ bltz window, .Lac_prefix_1 # if (!(window >> 31))
+ addiu $at, temp, -11 # if (prefix > 11) return -1
+ bgtz $at, .Lreturn_error
+ sll temp, 5 # jump_addr = &ac_jump_area[prefix * 8 * sizeof(uint32_t)]
+ addu temp, ac_jump_area
+ jr temp
nop
.Lreturn_error:
- jr $ra
+ b .Lreturn
li $v0, -1
-.Lac_prefix_11:
- # Prefix 11 is followed by a single bit.
- srl $v0, $t0, 28 # index = ((window >> (32 - 2 - 1)) & 1) * sizeof(u16)
- andi $v0, 2
- addu $v0, $t8 # value = table->lut0[index]
- lhu $v0, DECDCTTAB_lut0($v0)
- sll $t0, 3 # window <<= 3
- b .Lwrite_value
- addiu $t5, -3 # bit_offset -= 3
- #.word 0
+.Lac_prefix_1: # if (window >> 31)
+ sll window, 1
+ bltz window, .Lac_prefix_11
+ li temp, 0xfe00
.Lac_prefix_10:
# Prefix 10 marks the end of a block.
- li $v0, 0xfe00 # value = 0xfe00
- sll $t0, 2 # window <<= 2
- addiu $t5, -2 # bit_offset -= 2
- addiu $t6, -1 # block_index--
- bgez $t6, .Lwrite_value
- li $t7, 0 # coeff_index = 0
- b .Lwrite_value
- li $t6, 5 # if (block_index < 0) block_index = 5
+ # *output = 0xfe00
+ # coeff_index = 0
+ # if (--block_index < Y3) block_index = Cr
+ sll window, 1
+ addiu bit_offset, -2
+ sh temp, 0(output)
+
+ addiu block_index, -1
+ bgez block_index, .Lfeed_bitstream
+ li coeff_index, 0
+ b .Lfeed_bitstream
+ li block_index, 5
+
+.Lac_prefix_11:
+ # Prefix 11 is followed by a single bit. Note that the 10/11 prefix check
+ # already shifts the window by one bit (without updating the bit offset).
+ # index = ((window >> (32 - 1 - 1)) & 1) * sizeof(uint16_t)
+ # *output = huffman_table->ac0[index]
+ srl value, window, 29
+ andi value, 2
+ addu value, huffman_table
+ lhu value, VLC_Table_ac0(value)
+ sll window, 2
+ addiu bit_offset, -3
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_01:
# Prefix 01 can be followed by a 2-bit lookup index starting with 1, or a
# 3-bit lookup index starting with 0. A 32-bit lookup table is used,
# containing both MDEC codes and lengths.
- srl $v0, $t0, 25 # index = ((window >> (32 - 2 - 3)) & 7) * sizeof(u32)
- andi $v0, 28
- addu $v0, $t8 # value = table->lut2[index]
- lw $v0, DECDCTTAB_lut2($v0)
- b .Lupdate_window_and_write
- srl $v1, $v0, 16 # length = value >> 16
+ # index = ((window >> (32 - 2 - 3)) & 7) * sizeof(uint32_t)
+ # *output = huffman_table->ac2[index] & 0xffff
+ # length = huffman_table->ac2[index] >> 16
+ srl value, window, 25
+ andi value, 28
+ addu value, huffman_table
+ lw value, VLC_Table_ac2(value)
+
+ b .Lupdate_window_ac # update_window(value >> 16)
+ sh value, 0(output)
.word 0, 0
.Lac_prefix_001:
# Prefix 001 can be followed by a 6-bit lookup index starting with 00, or a
# 3-bit lookup index starting with 01/10/11.
- srl $v0, $t0, 21 # index = ((window >> (32 - 3 - 6)) & 63) * sizeof(u32)
- andi $v0, 252
- addu $v0, $t8 # value = table->lut3[index]
- lw $v0, DECDCTTAB_lut3($v0)
- b .Lupdate_window_and_write
- srl $v1, $v0, 16 # length = value >> 16
+ # index = ((window >> (32 - 3 - 6)) & 63) * sizeof(uint32_t)
+ # *output = huffman_table->ac3[index] & 0xffff
+ # length = huffman_table->ac3[index] >> 16
+ srl value, window, 21
+ andi value, 252
+ addu value, huffman_table
+ lw value, VLC_Table_ac3(value)
+
+ b .Lupdate_window_ac # update_window(value >> 16)
+ sh value, 0(output)
.word 0, 0
.Lac_prefix_0001:
# Prefix 0001 is followed by a 3-bit lookup index.
- srl $v0, $t0, 24 # index = ((window >> (32 - 4 - 3)) & 7) * sizeof(u16)
- andi $v0, 14
- addu $v0, $t8 # value = table->lut4[index]
- lhu $v0, DECDCTTAB_lut4($v0)
- sll $t0, 7 # window <<= 4 + 3
- b .Lwrite_value
- addiu $t5, -7 # bit_offset -= 4 + 3
- .word 0
+ # index = ((window >> (32 - 4 - 3)) & 7) * sizeof(uint16_t)
+ # *output = huffman_table->ac4[index]
+ srl value, window, 24
+ andi value, 14
+ addu value, huffman_table
+ lhu value, VLC_Table_ac4(value)
+ sll window, 7
+ addiu bit_offset, -7
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_00001:
# Prefix 00001 is followed by a 3-bit lookup index.
- srl $v0, $t0, 23 # index = ((window >> (32 - 5 - 3)) & 7) * sizeof(u16)
- andi $v0, 14
- addu $v0, $t8 # value = table->lut5[index]
- lhu $v0, DECDCTTAB_lut5($v0)
- sll $t0, 8 # window <<= 5 + 3
- b .Lwrite_value
- addiu $t5, -8 # bit_offset -= 5 + 3
- .word 0
+ # index = ((window >> (32 - 5 - 3)) & 7) * sizeof(uint16_t)
+ # *output = huffman_table->ac5[index]
+ srl value, window, 23
+ andi value, 14
+ addu value, huffman_table
+ lhu value, VLC_Table_ac5(value)
+ sll window, 8
+ addiu bit_offset, -8
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_000001:
# Prefix 000001 is an escape code followed by a full 16-bit MDEC value.
- srl $v0, $t0, 10 # value = window >> (32 - 6 - 16)
- sll $t0, 22 # window <<= 6 + 16
- b .Lwrite_value
- addiu $t5, -22 # bit_offset -= 6 + 16
- .word 0, 0, 0, 0
+ # *output = window >> (32 - 6 - 16)
+ srl value, window, 10
+ sll window, 22
+ addiu bit_offset, -22
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
+ .word 0, 0, 0
.Lac_prefix_0000001:
# Prefix 0000001 is followed by a 4-bit lookup index.
- srl $v0, $t0, 20 # index = ((window >> (32 - 7 - 4)) & 15) * sizeof(u16)
- andi $v0, 30
- addu $v0, $t8 # value = table->lut7[index]
- lhu $v0, DECDCTTAB_lut7($v0)
- sll $t0, 11 # window <<= 7 + 4
- b .Lwrite_value
- addiu $t5, -11 # bit_offset -= 7 + 4
- .word 0
+ # index = ((window >> (32 - 7 - 4)) & 15) * sizeof(uint16_t)
+ # *output = huffman_table->ac7[index]
+ srl value, window, 20
+ andi value, 30
+ addu value, huffman_table
+ lhu value, VLC_Table_ac7(value)
+ sll window, 11
+ addiu bit_offset, -11
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_00000001:
# Prefix 00000001 is followed by a 5-bit lookup index.
- srl $v0, $t0, 18 # index = ((window >> (32 - 8 - 5)) & 31) * sizeof(u16)
- andi $v0, 62
- addu $v0, $t8 # value = table->lut8[index]
- lhu $v0, DECDCTTAB_lut8($v0)
- sll $t0, 13 # window <<= 8 + 5
- b .Lwrite_value
- addiu $t5, -13 # bit_offset -= 8 + 5
- .word 0
+ # index = ((window >> (32 - 8 - 5)) & 31) * sizeof(uint16_t)
+ # *output = huffman_table->ac8[index]
+ srl value, window, 18
+ andi value, 62
+ addu value, huffman_table
+ lhu value, VLC_Table_ac8(value)
+ sll window, 13
+ addiu bit_offset, -13
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_000000001:
# Prefix 000000001 is followed by a 5-bit lookup index.
- srl $v0, $t0, 17 # index = ((window >> (32 - 9 - 5)) & 31) * sizeof(u16)
- andi $v0, 62
- addu $v0, $t8 # value = table->lut9[index]
- lhu $v0, DECDCTTAB_lut9($v0)
- sll $t0, 14 # window <<= 9 + 5
- b .Lwrite_value
- addiu $t5, -14 # bit_offset -= 9 + 5
- .word 0
+ # index = ((window >> (32 - 9 - 5)) & 31) * sizeof(uint16_t)
+ # *output = huffman_table->ac9[index]
+ srl value, window, 17
+ andi value, 62
+ addu value, huffman_table
+ lhu value, VLC_Table_ac9(value)
+ sll window, 14
+ addiu bit_offset, -14
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_0000000001:
# Prefix 0000000001 is followed by a 5-bit lookup index.
- srl $v0, $t0, 16 # index = ((window >> (32 - 10 - 5)) & 31) * sizeof(u16)
- andi $v0, 62
- addu $v0, $t8 # value = table->lut10[index]
- lhu $v0, DECDCTTAB_lut10($v0)
- sll $t0, 15 # window <<= 10 + 5
- b .Lwrite_value
- addiu $t5, -15 # bit_offset -= 10 + 5
- .word 0
+ # index = ((window >> (32 - 10 - 5)) & 31) * sizeof(uint16_t)
+ # *output = huffman_table->ac10[index]
+ srl value, window, 16
+ andi value, 62
+ addu value, huffman_table
+ lhu value, VLC_Table_ac10(value)
+ sll window, 15
+ addiu bit_offset, -15
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_00000000001:
# Prefix 00000000001 is followed by a 5-bit lookup index.
- srl $v0, $t0, 15 # index = ((window >> (32 - 11 - 5)) & 31) * sizeof(u16)
- andi $v0, 62
- addu $v0, $t8 # value = table->lut11[index]
- lhu $v0, DECDCTTAB_lut11($v0)
- sll $t0, 16 # window <<= 11 + 5
- b .Lwrite_value
- addiu $t5, -16 # bit_offset -= 11 + 5
- .word 0
+ # index = ((window >> (32 - 11 - 5)) & 31) * sizeof(uint16_t)
+ # *output = huffman_table->ac11[index]
+ srl value, window, 15
+ andi value, 62
+ addu value, huffman_table
+ lhu value, VLC_Table_ac11(value)
+ sll window, 16
+ addiu bit_offset, -16
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
.Lac_prefix_000000000001:
# Prefix 000000000001 is followed by a 5-bit lookup index.
- srl $v0, $t0, 14 # index = ((window >> (32 - 12 - 5)) & 31) * sizeof(u16)
- andi $v0, 62
- addu $v0, $t8 # value = table->lut12[index]
- lhu $v0, DECDCTTAB_lut12($v0)
- sll $t0, 17 # window <<= 12 + 5
- b .Lwrite_value
- addiu $t5, -17 # bit_offset -= 12 + 5
- .word 0
-
-.Lupdate_window_and_write:
- sllv $t0, $t0, $v1 # window <<= length
- subu $t5, $v1 # bit_offset -= length
-.Lwrite_value:
- sh $v0, 0($a1)
+ # index = ((window >> (32 - 12 - 5)) & 31) * sizeof(uint16_t)
+ # *output = huffman_table->ac12[index]
+ srl value, window, 14
+ andi value, 62
+ addu value, huffman_table
+ lhu value, VLC_Table_ac12(value)
+ sll window, 17
+ addiu bit_offset, -17
+
+ b .Lfeed_bitstream
+ sh value, 0(output)
+
+.Lupdate_window_ac:
+ srl length, value, 16
+.Lupdate_window_dc:
+ sllv window, window, length
+ subu bit_offset, length
+
.Lfeed_bitstream:
# Update the window. This makes sure the next iteration of the loop will be
# able to read up to 32 bits from the bitstream.
- bgez $t5, .Lskip_feeding # if (bit_offset < 0)
- addiu $a2, -1 # max_size--
-
- subu $v0, $0, $t5 # window = next_window << (-bit_offset)
- sllv $t0, $t1, $v0
- lw $t1, 0($a3) # next_window = (*input << 16) | (*input >> 16)
- addiu $t5, 32 # bit_offset += 32
- srl $v0, $t1, 16
- sll $t1, 16
- or $t1, $v0
- addiu $a3, 4 # input++
+ bgez bit_offset, .Lskip_feeding # if (bit_offset < 0)
+ addiu max_size, -1
+
+ subu temp, $0, bit_offset # window = next_window << (-bit_offset)
+ sllv window, next_window, temp
+ lw next_window, 0(input) # next_window = (*input << 16) | (*input >> 16)
+ addiu bit_offset, 32
+ srl temp, next_window, 16
+ sll next_window, 16
+ or next_window, temp
+ addiu input, 4
.Lskip_feeding:
- srlv $v0, $t1, $t5 # window |= next_window >> bit_offset
- or $t0, $v0
+ srlv temp, next_window, bit_offset # window |= next_window >> bit_offset
+ or window, temp
- bnez $a2, .Lprocess_next_code_loop
- addiu $a1, 2 # output++
+ bnez max_size, .Lprocess_next_code_loop
+ addiu output, 2
.Lstop_processing:
# If remaining = 0, skip flushing the context, pad the output buffer with
# end-of-block codes if necessary and return 0. Otherwise flush the context
# and return 1.
- beqz $t2, .Lpad_output_buffer
- nop
-
- sw $a3, VLC_Context_input($a0)
- sw $t0, VLC_Context_window($a0)
- sw $t1, VLC_Context_next_window($a0)
- sw $t2, VLC_Context_remaining($a0)
- sh $t3, VLC_Context_quant_scale($a0)
- sb $t4, VLC_Context_is_v3($a0)
- sb $t5, VLC_Context_bit_offset($a0)
- sb $t6, VLC_Context_block_index($a0)
- sb $t7, VLC_Context_coeff_index($a0)
-
- jr $ra
+ beqz remaining, .Lpad_output_buffer
+ li temp, 0xfe00
+
+ sw input, VLC_Context_input(ctx)
+ sw window, VLC_Context_window(ctx)
+ sw next_window, VLC_Context_next_window(ctx)
+ sw remaining, VLC_Context_remaining(ctx)
+ sb bit_offset, VLC_Context_bit_offset(ctx)
+ sb block_index, VLC_Context_block_index(ctx)
+ sb coeff_index, VLC_Context_coeff_index(ctx)
+ sh last_y, VLC_Context_last_y(ctx)
+ sh last_cr, VLC_Context_last_cr(ctx)
+ sh last_cb, VLC_Context_last_cb(ctx)
+
+ b .Lreturn
li $v0, 1
.Lpad_output_buffer:
- beqz $a2, .Lreturn_zero
- li $v0, 0xfe00
-.Lpad_output_buffer_loop: # while (max_size)
- sh $v0, 0($a1) # *output = 0xfe00
- addiu $a2, -1 # max_size--
- bnez $a2, .Lpad_output_buffer_loop
- addiu $a1, 2 # output++
+ beqz max_size, .Lreturn
+ li $v0, 0
-.Lreturn_zero:
+.Lpad_output_buffer_loop: # while (max_size)
+ sh temp, 0(output)
+ addiu max_size, -1
+ bnez max_size, .Lpad_output_buffer_loop
+ addiu output, 2
+
+.Lreturn:
+ lw $s0, 0($sp)
+ lw $s1, 4($sp)
+ lw $s2, 8($sp)
+ lw $s3, 12($sp)
jr $ra
- li $v0, 0
+ addiu $sp, 16