diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-01-23 09:36:22 +0100 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-01-23 09:36:22 +0100 |
| commit | 09f321e37fc187affa664d32e36e32c0533a7e8e (patch) | |
| tree | 27f846c194d92a9f4f8e3daea4ff2317e3e66894 /libpsn00b/psxpress/vlc.s | |
| parent | a21e949c9aea98cb4b3feee48bb98579bbdfba70 (diff) | |
| download | psn00bsdk-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.s | 743 |
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 |
