;------------------------------------------------------------------------------
;       JView
;       Frank Lyonnet 1993
;       Huffman decoding
;       Author : Frank Lyonnet
;------------------------------------------------------------------------------

                GET     h.ASMRegs
                GET     h.SWInames

                AREA |C$$code|, CODE, READONLY


AC_TBL_SIZE     EQU     8
DC_TBL_SIZE     EQU     8
DCTSIZE2        EQU     64

                ;------------------------
                ; The HUFF_AC/DC_TBL struct
                ;------------------------

HUFF_BITS       EQU     0
HUFF_HUFFVAL    EQU     HUFF_BITS       + 17*1
HUFF_BOOL       EQU     HUFF_HUFFVAL    + 256 * 1 + 3
HUFF_EHUFCO     EQU     HUFF_BOOL       + 4
HUFF_EHUFSI     EQU     HUFF_EHUFCO     + 256 * 4
HUFF_MINCODE    EQU     HUFF_EHUFSI     + 256 * 1
HUFF_MAXCODE    EQU     HUFF_MINCODE    + 17 * 4
HUFF_VALPTR     EQU     HUFF_MAXCODE    + 18 * 4
HUFF_RAW        EQU     HUFF_VALPTR     + 17 * 4

tempo0          RN      a1
tempo1          RN      a2
tempo2          RN      a3
tempo3          RN      a4
k               RN      v1
tbl             RN      v2
bits_left       RN      v3
get_buffer      RN      v4
next_input_byte RN      v5
bytes_in_buffer RN      v6
ci              RN      fp
blkn            RN      sl

                IMPORT  |BitsLeft|
                IMPORT  |GetBuffer|
                IMPORT  |ZAG|
                IMPORT  |erreur|
                IMPORT  |NextInputByte|
                IMPORT  |ByteInBuffer|
                IMPORT  |CInfo|
                IMPORT  |ReadJpegData|
                IMPORT  |QuantTbl|
                IMPORT  |ACTbl|
                IMPORT  |DCTbl|
                IMPORT  |LastDCVal|
                IMPORT  |MCUMember|

;*****************************************************************************************************
; Macros
;*****************************************************************************************************


                ;------------------------------------
                ; GETBIT MACRO
                ;------------------------------------
                ; Input :
                ; Output :
                ;       result = bit lu
                ;------------------------------------
                MACRO
$Label          GETBIT  $result

$Label          CMP     bits_left,#0                            ;Buffer vide ?
                BLEQ    not_enough_in_bit_buffer                ;Si oui le remplir
                SUB     bits_left,bits_left,#1                  ;Sinon bits_left --
                MOV     $result,#1                              ;result = 1
                AND     $result,$result,get_buffer,LSR bits_left;result = (get_buffer >> bits_left) & 1
                MEND

                ;-------------------------------------
                ; VCALC MACRO
                ;-------------------------------------
                ; Input :
                ;       code = code lu
                ;       nbits = nombre de bits lu
                ; Output :
                ;       code = valeur
                ;-------------------------------------
                MACRO
$Label          VCALC   $code,$nbits,$tmp
                ASSERT  $code <> $nbits
                ASSERT  $code <> $tmp
                ASSERT  $nbits <> $tmp

$Label          LDR     $tmp,=HUFF_VALPTR
                ADD     $tmp,tbl,$tmp                           ;int[]
                LDR     $tmp,[$tmp,$nbits,ASL#2]                ;tmp = htbl->valptr[nbits]
                ADD     $code,$code,$tmp                        ;code = code + htbl->valptr[nbits]

                LDR     $tmp,=HUFF_MINCODE
                ADD     $tmp,tbl,$tmp                           ;int[]
                LDR     $tmp,[$tmp,$nbits,ASL#2]                ;tmp = htbl->mincode[nbits]
                SUB     $code,$code,$tmp                        ;code = code - htbl->mincode[nbits]

                ADD     $tmp,tbl,#HUFF_HUFFVAL                  ;char[]
                LDRB    $code,[$tmp,$code]                      ;code = htbl->huffval[code]
                MEND

                ;-------------------------------------
                ; WDEC MACRO
                ;-------------------------------------
                ; Input :
                ;       code = code lu
                ;       nbits = nombre de bits lu
                ; Output :
                ;       code = code lu
                ;       nbits = nombre de bits lu
                ;-------------------------------------
                MACRO
$Label          WDEC    $code,$nbits,$tmp1,$tmp2
                ASSERT  $code <> $nbits
                ASSERT  $code <> $tmp1
                ASSERT  $code <> $tmp2
                ASSERT  $nbits <> $tmp1
                ASSERT  $nbits <> $tmp2
                ASSERT  $tmp1 <> $tmp2

$Label          LDR     $tmp1,=HUFF_MAXCODE
                ADD     $tmp1,tbl,$tmp1                         ;tmp1 = htbl->maxcode
                GETBIT  $tmp2                                   ;tmp2 = get_bit()
                ORR     $code,$tmp2,$code,LSL#1                 ;code = ( code << 1) | get_bit()
90
                LDR     $tmp2,[$tmp1,$nbits,ASL#2]              ;tmp2 = htbl->maxcode[l]
                CMP     $tmp2,$code                             ;Si maxcode[l] >= code
                BGE     %f91                                    ;Alors fin du while
                GETBIT  $tmp2                                   ;tmp2 = get_bit()
                ADD     $nbits,$nbits,#1                        ;nbits++
                ORR     $code,$tmp2,$code,LSL#1                 ;code = ( code << 1) | get_bit()
                B       %b90                                    ;Boucle
91
                MEND

                ;-------------------------------------
                ; GETRAW MACRO
                ;-------------------------------------
                ; Input :
                ; Output :
                ;       rawelt = element de la table
                ;-------------------------------------
                MACRO
$Label          GETRAW  $rawelt,$tmp
                ASSERT  $rawelt <> $tmp

$Label          SUB     $rawelt,bits_left,#AC_TBL_SIZE          ;rawelt = bits_left - AC_TBL_SIZE
                MOV     $rawelt,get_buffer,LSR $rawelt          ;rawelt = get_buffer >> (bits_left - DC_TBL_SIZE);
                MOV     $rawelt,$rawelt,LSL#(32 - AC_TBL_SIZE)  ;rawelt = rawelt & bmask[DC_TBL_SIZE]
                MOV     $rawelt,$rawelt,LSR#(32 - AC_TBL_SIZE)  ;rawelt = rawindex
                LDR     $tmp,=HUFF_RAW
                ADD     $tmp,tbl,$tmp                           ;tmp = raw[]
                LDR     $rawelt,[$tmp,$rawelt,LSL#2]            ;rawelt
                MEND

                ;-------------------------------------
                ; GETCN MACRO
                ;-------------------------------------
                ; Input :
                ;       rawelt = element de la table
                ; Output :
                ;       rawelt = element de la table
                ;       code = le code
                ;       nbits = le nombre de bits
                ;-------------------------------------
                MACRO
$Label          GETCN   $rawelt,$code,$nbits
                ASSERT  $rawelt <> $code
                ASSERT  $rawelt <> $nbits
                ASSERT  $code <> $nbits

$Label          MOV     $code,$rawelt,LSR#12                    ;code = [31 - 12]
                BIC     $nbits,$rawelt,$code,LSL#12
                MOV     $nbits,$nbits,LSR#8                     ;l = [11 - 8]
                MEND

                ;-------------------------------------
                ; GETVAL MACRO
                ;-------------------------------------
                ; Input :
                ;       rawelt = element de la table
                ; Output :
                ;       rawelt = element de la table
                ;       value = la valeur
                ;-------------------------------------
                MACRO
$Label          GETVAL  $rawelt,$value
                ASSERT  $rawelt <> $value

$Label          MOV     $value,$rawelt,LSL#24                   ;value = [7 - 0]
                MOV     $value,$value,LSR#24
                MEND

                ;-------------------------------------
                ; GETRB MACRO
                ;-------------------------------------
                ; Input :
                ;       valeur = valeur brute
                ; Output :
                ;       valeur = valeur brute
                ;       runlength = ...
                ;       datalength = ...
                ;-------------------------------------
                MACRO
$Label          GETRB   $valeur,$runlength,$datalength
                ASSERT  $valeur <> $runlength
                ASSERT  $valeur <> $datalength
                ASSERT  $runlength <> $datalength

$Label          MOV     $runlength,$valeur,LSR#4                ;( la valeur ) >> 4
                AND     $datalength,$valeur,#15                 ;( la valeur ) & 15
                MEND

                ;-------------------------------------
                ; JGETC MACRO
                ;-------------------------------------
                ; Input :
                ; Output :
                ;       byte = octet lu
                ;-------------------------------------
                MACRO
$Label          JGETC   $byte

$Label          SUBS    bytes_in_buffer,bytes_in_buffer,#1      ;-- bytes_in_buffer
                BLMI    read_data                               ;Remplit le buffer
                LDRB    $byte,[next_input_byte],#1              ;next_input_byte ++
                MEND

                ;-------------------------------------
                ; JUETC MACRO
                ;-------------------------------------
                ; Input :
                ;       byte = octet a remettre
                ; Output :
                ;       byte = octet a remettre
                ;-------------------------------------
                MACRO
$Label          JUETC   $byte

$Label          ADD     bytes_in_buffer,bytes_in_buffer,#1      ;bytes_in_buffer ++
                STRB    $byte,[next_input_byte,#-1]!            ;-- next_input_byte
                MEND

                ;------------------------------------
                ; STOCKAC MACRO
                ;------------------------------------
                ; Input :
                ;       numb = bits a lire
                ; Output :
                ;------------------------------------
                MACRO
$Label          STOCKAC $numb,$tmp1,$tmp2
                ASSERT  $numb <> $tmp1
                ASSERT  $numb <> $tmp2
                ASSERT  $tmp1 <> $tmp2

$Label          CMP     bits_left,$numb                         ;Buffer pas suffisament plein ?
                BLLO    not_enough_in_bit_buffer                ;Si oui le remplir
                SUB     bits_left,bits_left,$numb               ;Sinon bits_left -= numb
                MOV     $tmp1,get_buffer,LSR bits_left          ;tmp1 = tmp1 non lus du bit_buffer
                RSB     $numb,$numb,#32                         ;numb = 32 - numb
                MOV     $tmp1,$tmp1,LSL $numb                   ;tmp1 = tmp1 & bmask[tmp1]
                TST     $tmp1,#2_10000000000000000000000000000000
                MVNEQ   $tmp1,$tmp1                             ;Si bit 32 a 1 alors inversion de la tmp1 shiftee
                MOV     $tmp1,$tmp1,LSR $numb                   ;Decallage inverse
                RSBEQ   $tmp1,$tmp1,#0                          ;Si bit 32 a 1 alors negatation de la donnee ( tempo1 )
                LDR     $tmp2,=|QuantTbl|
                LDR     $tmp2,[$tmp2,ci,LSL#2]
                LDR     $tmp2,[$tmp2,k,LSL#2]                   ;tmp2 = QuantTbl[k]
                MUL     $tmp2,$tmp1,$tmp2                       ;dequantiz
                LDR     $tmp1,=|ZAG|
                LDR     $tmp1,[$tmp1,k,LSL#2]                   ;tmp2 = ZAG[k]
                LDR     $numb,=Block
                LDR     $numb,[$numb]
                LDR     $numb,[$numb,blkn,LSL#2]                ;numb = block[]
                STRB    $tmp2,[$numb,$tmp1,LSL#1]
                MOV     $tmp2,$tmp2,ASR#8
                ADD     $numb,$numb,#1
                STRB    $tmp2,[$numb,$tmp1,LSL#1]               ;block[k] = s ( short signe )
                MEND

                ;------------------------------------
                ; FTOCKAC MACRO
                ;------------------------------------
                ; Input :
                ;       numb = bits a lire
                ; Output :
                ;------------------------------------
                MACRO
$Label          FTOCKAC $numb,$tmp1,$tmp2
                ASSERT  $numb <> $tmp1
                ASSERT  $numb <> $tmp2
                ASSERT  $tmp1 <> $tmp2

$Label          SUB     bits_left,bits_left,$numb               ;Sinon bits_left -= numb
                MOV     $tmp1,get_buffer,LSR bits_left          ;tmp1 = tmp1 non lus du bit_buffer
                RSB     $numb,$numb,#32                         ;numb = 32 - numb
                MOV     $tmp1,$tmp1,LSL $numb                   ;tmp1 = tmp1 & bmask[tmp1]
                TST     $tmp1,#2_10000000000000000000000000000000
                MVNEQ   $tmp1,$tmp1                             ;Si bit 32 a 1 alors inversion de la tmp1 shiftee
                MOV     $tmp1,$tmp1,LSR $numb                   ;Decallage inverse
                RSBEQ   $tmp1,$tmp1,#0                          ;Si bit 32 a 1 alors negatation de la donnee ( tempo1 )
                LDR     $tmp2,=|QuantTbl|
                LDR     $tmp2,[$tmp2,ci,LSL#2]
                LDR     $tmp2,[$tmp2,k,LSL#2]                   ;tmp2 = QuantTbl[k]
                MUL     $tmp2,$tmp1,$tmp2                       ;dequantiz
                LDR     $tmp1,=|ZAG|
                LDR     $tmp1,[$tmp1,k,LSL#2]                   ;tmp2 = ZAG[k]
                LDR     $numb,=Block
                LDR     $numb,[$numb]
                LDR     $numb,[$numb,blkn,LSL#2]                ;numb = block[]
                STRB    $tmp2,[$numb,$tmp1,LSL#1]
                MOV     $tmp2,$tmp2,ASR#8
                ADD     $numb,$numb,#1
                STRB    $tmp2,[$numb,$tmp1,LSL#1]               ;block[k] = s ( short signe )
                MEND

                ;------------------------------------
                ; INCDCV MACRO
                ;------------------------------------
                ; Input :
                ;       val = val to inc
                ; Output :
                ;       val = inced dcval
                ;------------------------------------
                MACRO
$Label          INCDCV $val,$tmp1,$tmp2
                ASSERT  $val <> $tmp1
                ASSERT  $val <> $tmp2
                ASSERT  $tmp1 <> $tmp2
$Label
                LDR     ip,=|LastDCVal|                         ; = INT32
                LDR     ip,[ip,ci,LSL#2]
                LDR     $tmp1,[ip]
                MOV     $tmp1,$tmp1,ASL#16
                MOV     $tmp1,$tmp1,ASR#16                      ;signed
                ADD     $val,$val,$tmp1                         ;+= LastDC
                STR     $val,[ip]                               ;Update LastDC
                MEND

                ;------------------------------------
                ; STOCKDC MACRO
                ;------------------------------------
                ; Input :
                ;       numb = bits a lire
                ; Output :
                ;------------------------------------
                MACRO
$Label          STOCKDC $numb,$tmp1,$tmp2
                ASSERT  $numb <> $tmp1
                ASSERT  $numb <> $tmp2
                ASSERT  $tmp1 <> $tmp2

$Label          CMP     $numb,#0                                ;Bits a lire ?
                BEQ     %f20                                    ;Si non ...
                CMP     bits_left,$numb                         ;Buffer pas suffisament plein ?
                BLLO    not_enough_in_bit_buffer                ;Si oui le remplir
                SUB     bits_left,bits_left,$numb               ;Sinon bits_left -= numb
                MOV     $tmp1,get_buffer,LSR bits_left          ;tmp1 = tmp1 non lus du bit_buffer
                RSB     $numb,$numb,#32                         ;numb = 32 - numb
                MOV     $tmp1,$tmp1,LSL $numb                   ;tmp1 = tmp1 & bmask[tmp1]
                TST     $tmp1,#2_10000000000000000000000000000000
                MVNEQ   $tmp1,$tmp1                             ;Si bit 32 a 1 alors inversion de la tmp1 shiftee
                MOV     $tmp1,$tmp1,LSR $numb                   ;Decallage inverse
                RSBEQ   $tmp1,$tmp1,#0                          ;Si bit 32 a 1 alors negatation de la donnee ( tempo1 )
                MOV     $numb,$tmp1                             ;Pour le branch
20
                INCDCV  $numb,$tmp1,$tmp2                       ;Incremente de la dc value
                LDR     $tmp1,=|QuantTbl|
                LDR     $tmp1,[$tmp1,ci,LSL#2]
                LDR     $tmp1,[$tmp1]                           ;tmp1 = QuantTbl[0]
                MUL     $tmp1,$numb,$tmp1                       ;dequantiz
                LDR     $numb,=Block
                LDR     $numb,[$numb]
                LDR     $numb,[$numb,blkn,LSL#2]                ;numb = block[]
                STRB    $tmp1,[$numb]
                MOV     $tmp1,$tmp1,ASR#8
                STRB    $tmp1,[$numb,#1]                        ;block[k] = s ( short signe )
                MEND


                ;------------------------------------
                ; FILLB8 MACRO
                ;------------------------------------
                ; Input :
                ; Output :
                ;------------------------------------
                MACRO
$Label          FILLB8
$Label          JGETC   ip                                      ;Get a byte
                CMP     ip,#255                                 ;Check end marker
                BLEQ    check_marker_M
                ORR     get_buffer,ip,get_buffer,LSL#8          ;Fetch byte in buffer
                ADD     bits_left,bits_left,#8                  ;bits_left += 8
                MEND


;------------------------------------------------------------------------------
;       huff_DECODE
;------------------------------------------------------------------------------
;       HUFF_AC_TBL * tbl
;       HUFF_AC_TBL * dctbl
;       JCOEF * LastDCVal
;       JCOEF * block
;       QUANT_TBL_PTR quanttbl
;       decompress_info_ptr cinfo
;       int * byte_in_buffer
;       void read_jpeg_data(cinfo)
;       char * next_input_byte
;------------------------------------------------------------------------------

                EXPORT  |huff_DECODE|
|huff_DECODE|
                MOV     ip, sp                                  ;set up a stack frame
                STMFD   sp!, {v1-v6,sl,fp,ip,lr,pc}
                SUB     fp, ip, #4

                STMFD   sp!,{sl,fp}                             ;Sauve sl,fp

                ;------------------------
                ; Recuperation des parms
                ;------------------------
                ;parm #1
                LDR     ip,=Block
                STR     a1,[ip]
                ;parm #2
                LDR     ip,=BlknLim
                STR     a2,[ip]

                ;---------------------------------
                ; Init des variables en registres
                ;---------------------------------
                ;BitsLeft
                LDR     ip,=|BitsLeft|
                LDR     bits_left,[ip]
                ;GetBuffer
                LDR     ip,=|GetBuffer|
                LDR     get_buffer,[ip]
                ;ByteInBuffer
                LDR     ip,=|ByteInBuffer|
                LDR     ip,[ip]                         ;Lecture variable
                LDR     bytes_in_buffer,[ip]            ;Enleve une indirection
                ;NextInputByte
                LDR     ip,=|NextInputByte|
                LDR     ip,[ip]                         ;Lecture variable
                LDR     next_input_byte,[ip]            ;Enleve une indirection


                ;---------------------------------
                ; Boucle blkn
                ;---------------------------------
                MOV     blkn,#0
                SUB     blkn,blkn,#1
blkn_loop
                ADD     blkn,blkn,#1
                LDR     ip,=BlknLim
                LDR     ip,[ip]
                CMP     blkn,ip
                BGE     end_huffman

                LDR     ip,=|MCUMember|                         ;Init ci
                LDR     ip,[ip]
                LDR     ci,[ip,blkn,LSL#2]

                ;---------------------------------
                ; DC Part
                ;---------------------------------
                ;tbl , ptr vers la table dc
                LDR     ip,=|DCTbl|
                LDR     tbl,[ip,ci,LSL#2]

                CMP     bits_left,#DC_TBL_SIZE
                BLLO    not_enough_in_bit_buffer
                CMP     bits_left,#DC_TBL_SIZE
                BLO     dc_lent

                GETRAW  tempo0,tempo1                           ;GETRAW  $rawelt,$tmp
                GETCN   tempo0,tempo1,tempo2                    ;GETCN   $rawelt,$code,$nbits

                CMP     tempo2,#(DC_TBL_SIZE+1)
                BEQ     dc_incomplet

                SUB     bits_left,bits_left,tempo2
                GETVAL  tempo0,tempo1                           ;GETVAL  $rawelt,$value
                STOCKDC tempo1,tempo0,tempo2                    ;STOCKDC $numb,$tmp1,$tmp2
                B       ac_part

dc_incomplet
                SUB     bits_left,bits_left,#AC_TBL_SIZE        ;bits_left -= AC_TBL_SIZE
                WDEC    tempo1,tempo2,tempo0,tempo3             ;WDEC    $code,$nbits,$tmp1,$tmp2
                CMP     tempo2,#16                              ;Si l > 16
                BHI     bad_huff_code                           ;Erreur
                VCALC   tempo1,tempo2,tempo0                    ;VCALC   $code,$nbits,$tmp
                STOCKDC tempo1,tempo0,tempo2                    ;STOCKDC $numb,$tmp1,$tmp2
                B       ac_part

dc_lent
                MOV     tempo1,#0                               ;code = 0
                MOV     tempo2,#1                               ;nbits = 1
                WDEC    tempo1,tempo2,tempo0,tempo3             ;WDEC    $code,$nbits,$tmp1,$tmp2

                CMP     tempo2,#16                              ;Si l > 16
                BHI     bad_huff_code                           ;Erreur
                VCALC   tempo1,tempo2,tempo0                    ;VCALC   $code,$nbits,$tmp
                STOCKDC tempo1,tempo0,tempo2                    ;STOCKDC $numb,$tmp1,$tmp2

                ;---------------------------------
                ; AC Part
                ;---------------------------------

ac_part
                MOV     k,#1                                    ;k = 1
                LDR     ip,=|ACTbl|                             ;tbl , ptr vers la table ac
                LDR     tbl,[ip,ci,LSL#2]
                BL      not_enough_in_bit_buffer                ;Remplissage
                CMP     bits_left,#24                           ;Assez ?
                BLO     k_loop_lent                             ;Non
                B       k_loop

k_loop_test
                CMP     tempo0,#15                              ;Test fin de boucle
                BNE     blkn_loop                               ;Sur tempo0

                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8

k_loop
                CMP     k,#DCTSIZE2                             ;Si k > = 64
                BGE     blkn_loop                               ;Fin de la boucle

                GETRAW  tempo0,tempo1                           ;GETRAW  $rawelt,$tmp
                GETCN   tempo0,tempo1,tempo2                    ;GETCN   $rawelt,$code,$nbits

                CMP     tempo2,#(AC_TBL_SIZE + 1)               ;Si nbits = (AC_TBL_SIZE + 1)
                BEQ     code_incomplet                          ;Le code est incomplet

                SUB     bits_left,bits_left,tempo2              ;bits_left -= nbits
                GETVAL  tempo0,tempo1                           ;GETVAL  $rawelt,$value
                GETRB   tempo1,tempo0,tempo2                    ;GETRB   $valeur,$runlength,$datalength

                CMP     tempo2,#0                               ;Si bits a lire = 0
                ADDEQ   k,k,#16                                 ;Saut de 15 + 1
                BEQ     k_loop_test                             ;Et continue la boucle

                ADD     k,k,tempo0                              ;Sinon k += run lenght

                FTOCKAC tempo2,tempo0,tempo1                    ;FTOCKAC  $nbits,$tmp1,$tmp2

                ADD     k,k,#1                                  ;k ++

                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                B       k_loop

code_incomplet
                SUB     bits_left,bits_left,#AC_TBL_SIZE        ;bits_left -= AC_TBL_SIZE
                WDEC    tempo1,tempo2,tempo0,tempo3             ;WDEC    $code,$nbits,$tmp1,$tmp2
                CMP     tempo2,#16                              ;Si l > 16
                BHI     bad_huff_code                           ;Erreur
                VCALC   tempo1,tempo2,tempo0                    ;VCALC   $code,$nbits,$tmp
                GETRB   tempo1,tempo0,tempo3                    ;GETRB   $valeur,$runlength,$datalength
                CMP     tempo3,#0                               ;Si bits a lire = 0
                ADDEQ   k,k,#16                                 ;Saut de 15 + 1
                BEQ     k_loop_test                             ;Et continue la boucle
                ADD     k,k,tempo0                              ;Sinon k += run lenght
                FTOCKAC tempo3,tempo0,tempo1                    ;FTOCKAC  $nbits,$tmp1,$tmp2
                ADD     k,k,#1                                  ;k ++

                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                CMP     bits_left,#25                           ;25 = MIN_GET_BITS
                BGE     k_loop                                  ;Buffer plein
                FILLB8
                B       k_loop                                  ;Buffer plein

check_marker_M
                STMFD   sp!,{ip,lr}                             ;Save ip and lr
                JGETC   ip                                      ;Get next byte
                CMP     ip,#0                                   ;Test next byte = 0
                LDMEQFD sp!,{ip,pc}                             ;If yes , skip it and return
                JUETC   ip                                      ;Sinon , marker de fin
                LDMFD   sp!,{ip,lr}                             ;On unget les 2 bytes
                JUETC   ip                                      ;Pour utilisation ulterieur
                B       k_loop_lent                             ;Boucle lente

k_loop_test_lent
                CMP     tempo0,#15                              ;Test fin de boucle
                BNE     blkn_loop                               ;Sur tempo0
k_loop_lent
                CMP     k,#DCTSIZE2                             ;Si k > = 64
                BGE     blkn_loop                               ;Fin de la boucle
                MOV     tempo1,#0                               ;code = 0
                MOV     tempo2,#1                               ;nbits = 1
                WDEC    tempo1,tempo2,tempo0,tempo3             ;WDEC    $code,$nbits,$tmp1,$tmp2
                CMP     tempo2,#16                              ;Si l > 16
                BHI     bad_huff_code                           ;Erreur
                VCALC   tempo1,tempo2,tempo0                    ;VCALC   $code,$nbits,$tmp
                GETRB   tempo1,tempo0,tempo3                    ;GETRB   $valeur,$runlength,$datalength
                CMP     tempo3,#0                               ;Si bits a lire = 0
                ADDEQ   k,k,#16                                 ;Saut de 15 + 1
                BEQ     k_loop_test_lent                        ;Et continue la boucle
                ADD     k,k,tempo0                              ;Sinon k += run lenght
                STOCKAC tempo3,tempo0,tempo1                    ;STOCKAC  $nbits,$tmp1,$tmp2
                ADD     k,k,#1                                  ;k ++
                B       k_loop_lent                             ;boucle

end_huffman
                ;---------------------------------
                ; Update des variables en registres
                ;---------------------------------
                ;BitsLeft
                LDR     ip,=|BitsLeft|
                STR     bits_left,[ip]
                ;GetBuffer
                LDR     ip,=|GetBuffer|
                STR     get_buffer,[ip]
                ;ByteInBuffer
                LDR     ip,=ByteInBuffer
                LDR     ip,[ip]                                 ;Lecture variable
                STR     bytes_in_buffer,[ip]                    ;Enleve une indirection
                ;NextInputByte
                LDR     ip,=NextInputByte
                LDR     ip,[ip]                                 ;Lecture variable
                STR     next_input_byte,[ip]                    ;Enleve une indirection

                LDMFD   sp!,{sl,fp}                             ;Restaure fp
                LDMEA   fp,{v1-v6,sl,fp,sp,pc} ; RICK 2004/01/29 removed '^'

bad_huff_code

                LDMFD   sp!,{sl,fp}                             ;Restaure fp

                STMFD   sp!,{a1-a4}
                LDR     a1,=BadHuff                             ;Bad Huff code
                BL      |erreur|                                ;Affichage
                LDMFD   sp!,{a1-a4}

                ;---------------------------------
                ; Update des variables en registres
                ;---------------------------------
                ;BitsLeft
                LDR     ip,=|BitsLeft|
                STR     bits_left,[ip]
                ;GetBuffer
                LDR     ip,=|GetBuffer|
                STR     get_buffer,[ip]
                ;ByteInBuffer
                LDR     ip,=|ByteInBuffer|
                LDR     ip,[ip]                                 ;Lecture variable
                STR     bytes_in_buffer,[ip]                    ;Enleve une indirection
                ;NextInputByte
                LDR     ip,=|NextInputByte|
                LDR     ip,[ip]                                 ;Lecture variable
                STR     next_input_byte,[ip]                    ;Enleve une indirection

                LDMEA   fp,{v1-v6,sl,fp,sp,pc} ; RICK 2004/01/29 removed '^'


;*****************************************************************************************************
; Sous routines
;*****************************************************************************************************

                ;------------------------------------
                ; not_enough_in_bit_buffer
                ;       rempli le buffer
                ;------------------------------------
                ; r0-r3 preserves
                ;------------------------------------
not_enough_in_bit_buffer
                STMFD   sp!,{lr}                                ;Corruption possible de lr

                CMP     bits_left,#25                           ;25 = MIN_GET_tmp1
                LDMGEFD sp!,{pc}                                ;Si buffer plein , fin
                JGETC   ip                                      ;Sinon Get a byte
                CMP     ip,#255                                 ;Check end marker
                BLEQ    check_marker
                ORR     get_buffer,ip,get_buffer,LSL#8          ;Fetch byte in buffer
                ADD     bits_left,bits_left,#8                  ;bits_left += 8

                CMP     bits_left,#25                           ;25 = MIN_GET_tmp1
                LDMGEFD sp!,{pc}                                ;Si buffer plein , fin
                JGETC   ip                                      ;Sinon Get a byte
                CMP     ip,#255                                 ;Check end marker
                BLEQ    check_marker
                ORR     get_buffer,ip,get_buffer,LSL#8          ;Fetch byte in buffer
                ADD     bits_left,bits_left,#8                  ;bits_left += 8

                CMP     bits_left,#25                           ;25 = MIN_GET_tmp1
                LDMGEFD sp!,{pc}                                ;Si buffer plein , fin
                JGETC   ip                                      ;Sinon Get a byte
                CMP     ip,#255                                 ;Check end marker
                BLEQ    check_marker
                ORR     get_buffer,ip,get_buffer,LSL#8          ;Fetch byte in buffer
                ADD     bits_left,bits_left,#8                  ;bits_left += 8

                CMP     bits_left,#25                           ;25 = MIN_GET_tmp1
                LDMGEFD sp!,{pc}                                ;Si buffer plein , fin
                JGETC   ip                                      ;Sinon Get a byte
                CMP     ip,#255                                 ;Check end marker
                BLEQ    check_marker
                ORR     get_buffer,ip,get_buffer,LSL#8          ;Fetch byte in buffer
                ADD     bits_left,bits_left,#8                  ;bits_left += 8

                LDMFD   sp!,{pc}                                ;retour

check_marker
                STMFD   sp!,{ip,lr}                             ;Save ip and lr
                JGETC   ip                                      ;Get next byte
                CMP     ip,#0                                   ;Test next byte = 0
                LDMEQFD sp!,{ip,pc}                             ;If yes , skip it and return
                JUETC   ip                                      ;Sinon , marker de fin
                LDMFD   sp!,{ip,lr}                             ;On unget les 2 bytes
                JUETC   ip                                      ;Pour utilisation ulterieur
                LDMFD   sp!,{pc}                                ;Fin fill

                ;------------------------------------
                ; read_data
                ;       rempli le buffer
                ;------------------------------------
                ; r0-r3 preserves
                ;------------------------------------
read_data
                ;---------------------------------
                ; Update des variables en registres
                ;---------------------------------
                ;Pas besoin car read_jpeg_data n'en a rien a foutre

                STMFD   sp!,{a1-a4,sl,fp,lr}                    ;Sauve sl,fp,lr

                LDR     ip,=|CInfo|                             ;Parm 1 = Cinfo
                LDR     a1,[ip]
                LDR     ip,=|ReadJpegData|
                LDR     ip,[ip]
                LDR     lr,=back_from_jpeg
                MOV     pc,ip                                   ;Fill byte buffer
back_from_jpeg

                ;---------------------------------
                ; Update des variables en registres
                ;---------------------------------

                ;read jpeg data a update nos variables

                ;ByteInBuffer
                LDR     ip,=|ByteInBuffer|
                LDR     ip,[ip]                                 ;Lecture variable
                LDR     bytes_in_buffer,[ip]                    ;Enleve une indirection
                ;NextInputByte
                LDR     ip,=|NextInputByte|
                LDR     ip,[ip]                                 ;Lecture variable
                LDR     next_input_byte,[ip]                    ;Enleve une indirection

                JUETC   a1                                      ;Unget un octet
                SUB     bytes_in_buffer,bytes_in_buffer,#1      ;-- bytes_in_buffer
                LDMFD   sp!,{a1-a4,sl,fp,pc}                    ;Retour,restaure fp

Block
                DCD     0
RegFP
                DCD     0
BlknLim
                DCD     0
BadHuff                 ;Attention align
                DCB     "Corrupt JPEG data: bad Huffman code",0

                END

