• JPEG解码:huffman解码


    huffman解码是JPEG图片解码里面的关键步骤,也是最复杂的一步。在fsm模块中DHT状态下读取的不仅仅是huffman表,还有另外两个表,一个是存放1-16不同码长的最小编码的一个表,另一个是存放最小编码的地址的表。在huffman解码中需要用到这两个表,还有在本模块也集成了反量化模块。

    huffman解码的步骤:

    (1):判断解码数据的类型选择与之对应的表。

    (2):进行码长的判断。

    (3):计算DHT地址。

    (4):从DHT表中读取数据。

    (5):若为DC数据需要进行DPCM解码。

    对于一个huffman解码器应包含3个独立的存储器:

    (1):存放各个长度对应的最小编码。

    (2):存储各个长度对应码字的最小地址。

    (3):存储解码符号(DHT表)

    代码如下:

    `timescale 1ps / 1ps
    module hm_dec(
                  clk,
                  rst_n, 
                  
                  image_en, 
                  zig_zagIDLE,                       
                  datain_en,      
                  datain,   
                    
                  huffman_en,
                  huffman_color, 
                  huffman_count, 
                  huffman_mincode,    
                  huffman_mincodeaddr,
                  
               
                  dhtrd_color,          
                  dhtrd_addr,         
                  dhtrd_zero,           
                  dhtrd_width, 
                           
                  dqtrd_color,          
                  dqtrd_addr,         
                  dqtrd_data,           
          
                  unit_en,    
                  use_bit,      
                  use_width,    
                  dataout_en,          
                  dataout_count,       
                  dataout         
                  );                                 
    
    input  clk;//时钟信号
    input rst_n;//复位信号  低电平有效
    
    input           image_en;//fsm模块读到SOS,开始huffman解码
    input           zig_zagIDLE;//zig_zag模块空闲,允许解码
    input           datain_en;//输入数据使能       
    input [31:0]    datain;//输入的数据,从regdata模块得到 
          
    input           huffman_en; //huffman表使能
    input [1:0]     huffman_color;//huffman表类型
    input [3:0]     huffman_count;//huffman表的深度:0-16
    input [15:0]    huffman_mincode;//huffman表中不同长度对应的最小编码  
    input [7:0]     huffman_mincodeaddr;//huffman表的最小编码的首地址 
    
    output [1:0]    dhtrd_color;//dht表类型
    output [7:0]    dhtrd_addr;//dht表地址         
    input [3:0]     dhtrd_zero;//dht表读取的0的个数            
    input [3:0]     dhtrd_width;//dht读取的有效数据的长度           
    
    output          dqtrd_color;//dqt表的类型
    output [5:0]    dqtrd_addr;//dqt表的地址
    input [7:0]     dqtrd_data;//dqt表的数据
    
    output          use_bit;//以位传输数据
    output [6:0]    use_width;//使用数据的位宽   
         
    //output [2:0]    dataout_color;//解码数据的类型
    output [5:0]    dataout_count;//解码数据计数
    output          dataout_en;//数据输出使能
    output [15:0]   dataout;//输出数据       
    output          unit_en;//一个单元64个数据解码完成
    //--------------------------------------------------------------------------
    //huffman 存储器,一个用于存储最小的编码,一个用于存储最小编码对应的首地址
    reg [15:0]      ram0_Y_DC [0:15];  
    reg [15:0]      ram0_Y_AC [0:15];  
    reg [15:0]      ram0_C_DC [0:15];  
    reg [15:0]      ram0_C_AC [0:15];  
    
    reg [7:0]       ram1_Y_DC [0:15]; 
    reg [7:0]       ram1_Y_AC [0:15]; 
    reg [7:0]       ram1_C_DC [0:15]; 
    reg [7:0]       ram1_C_AC [0:15]; 
    
    always @(posedge clk or negedge rst_n)
     begin
            if(!rst_n) 
            begin
            	 ram0_Y_DC[0 ]<=16'd0; 
            	 ram0_Y_DC[1 ]<=16'd0; 
            	 ram0_Y_DC[2 ]<=16'd0; 
            	 ram0_Y_DC[3 ]<=16'd0; 
            	 ram0_Y_DC[4 ]<=16'd0; 
            	 ram0_Y_DC[5 ]<=16'd0; 
            	 ram0_Y_DC[6 ]<=16'd0; 
            	 ram0_Y_DC[7 ]<=16'd0; 
            	 ram0_Y_DC[8 ]<=16'd0; 
            	 ram0_Y_DC[9 ]<=16'd0; 
            	 ram0_Y_DC[10]<=16'd0; 
            	 ram0_Y_DC[11]<=16'd0; 
            	 ram0_Y_DC[12]<=16'd0; 
            	 ram0_Y_DC[13]<=16'd0; 
            	 ram0_Y_DC[14]<=16'd0; 
            	 ram0_Y_DC[15]<=16'd0; 
               
               ram0_Y_AC[0 ]<=16'd0;
               ram0_Y_AC[1 ]<=16'd0;
               ram0_Y_AC[2 ]<=16'd0;
               ram0_Y_AC[3 ]<=16'd0;
            	 ram0_Y_AC[4 ]<=16'd0; 
               ram0_Y_AC[5 ]<=16'd0;
               ram0_Y_AC[6 ]<=16'd0; 
               ram0_Y_AC[7 ]<=16'd0; 
               ram0_Y_AC[8 ]<=16'd0; 
               ram0_Y_AC[9 ]<=16'd0; 
               ram0_Y_AC[10]<=16'd0; 
               ram0_Y_AC[11]<=16'd0; 
               ram0_Y_AC[12]<=16'd0; 
               ram0_Y_AC[13]<=16'd0; 
               ram0_Y_AC[14]<=16'd0;
               ram0_Y_AC[15]<=16'd0;   
               
               ram0_C_DC[0 ]<=16'D0;
               ram0_C_DC[1 ]<=16'D0; 
               ram0_C_DC[2 ]<=16'D0; 
               ram0_C_DC[3 ]<=16'D0; 
               ram0_C_DC[4 ]<=16'D0; 
               ram0_C_DC[5 ]<=16'D0; 
               ram0_C_DC[6 ]<=16'D0; 
               ram0_C_DC[7 ]<=16'D0; 
               ram0_C_DC[8 ]<=16'D0;
               ram0_C_DC[9 ]<=16'D0; 
               ram0_C_DC[10]<=16'D0; 
               ram0_C_DC[11]<=16'D0; 
               ram0_C_DC[12]<=16'D0; 
               ram0_C_DC[13]<=16'D0; 
               ram0_C_DC[14]<=16'D0; 
               ram0_C_DC[15]<=16'D0;  
               
               ram0_C_AC[0 ]<=16'd0;
               ram0_C_AC[1 ]<=16'd0;
               ram0_C_AC[2 ]<=16'd0;
               ram0_C_AC[3 ]<=16'd0;
               ram0_C_AC[4 ]<=16'd0;
               ram0_C_AC[5 ]<=16'd0;
               ram0_C_AC[6 ]<=16'd0;
               ram0_C_AC[7 ]<=16'd0;
               ram0_C_AC[8 ]<=16'd0;
               ram0_C_AC[9 ]<=16'd0;
               ram0_C_AC[10]<=16'd0;
               ram0_C_AC[11]<=16'd0;
               ram0_C_AC[12]<=16'd0;
               ram0_C_AC[13]<=16'd0;
               ram0_C_AC[14]<=16'd0;
               ram0_C_AC[15]<=16'd0;  
               
            	 ram1_Y_DC[0 ]<=8'd0; 
            	 ram1_Y_DC[1 ]<=8'd0; 
            	 ram1_Y_DC[2 ]<=8'd0; 
            	 ram1_Y_DC[3 ]<=8'd0; 
            	 ram1_Y_DC[4 ]<=8'd0; 
            	 ram1_Y_DC[5 ]<=8'd0; 
            	 ram1_Y_DC[6 ]<=8'd0; 
            	 ram1_Y_DC[7 ]<=8'd0; 
            	 ram1_Y_DC[8 ]<=8'd0; 
            	 ram1_Y_DC[9 ]<=8'd0; 
            	 ram1_Y_DC[10]<=8'd0; 
            	 ram1_Y_DC[11]<=8'd0; 
            	 ram1_Y_DC[12]<=8'd0; 
            	 ram1_Y_DC[13]<=8'd0; 
            	 ram1_Y_DC[14]<=8'd0; 
            	 ram1_Y_DC[15]<=8'd0; 
               
               ram1_Y_AC[0 ]<=8'd0;
               ram1_Y_AC[1 ]<=8'd0;
               ram1_Y_AC[2 ]<=8'd0;
               ram1_Y_AC[3 ]<=8'd0;
            	 ram1_Y_AC[4 ]<=8'd0; 
               ram1_Y_AC[5 ]<=8'd0;
               ram1_Y_AC[6 ]<=8'd0; 
               ram1_Y_AC[7 ]<=8'd0; 
               ram1_Y_AC[8 ]<=8'd0; 
               ram1_Y_AC[9 ]<=8'd0; 
               ram1_Y_AC[10]<=8'd0; 
               ram1_Y_AC[11]<=8'd0; 
               ram1_Y_AC[12]<=8'd0; 
               ram1_Y_AC[13]<=8'd0; 
               ram1_Y_AC[14]<=8'd0;
               ram1_Y_AC[15]<=8'd0;   
               
               ram1_C_DC[0 ]<=8'D0;
               ram1_C_DC[1 ]<=8'D0; 
               ram1_C_DC[2 ]<=8'D0; 
               ram1_C_DC[3 ]<=8'D0; 
               ram1_C_DC[4 ]<=8'D0; 
               ram1_C_DC[5 ]<=8'D0; 
               ram1_C_DC[6 ]<=8'D0; 
               ram1_C_DC[7 ]<=8'D0; 
               ram1_C_DC[8 ]<=8'D0;
               ram1_C_DC[9 ]<=8'D0; 
               ram1_C_DC[10]<=8'D0; 
               ram1_C_DC[11]<=8'D0; 
               ram1_C_DC[12]<=8'D0; 
               ram1_C_DC[13]<=8'D0; 
               ram1_C_DC[14]<=8'D0; 
               ram1_C_DC[15]<=8'D0;  
               
               ram1_C_AC[0 ]<=8'd0;
               ram1_C_AC[1 ]<=8'd0;
               ram1_C_AC[2 ]<=8'd0;
               ram1_C_AC[3 ]<=8'd0;
               ram1_C_AC[4 ]<=8'd0;
               ram1_C_AC[5 ]<=8'd0;
               ram1_C_AC[6 ]<=8'd0;
               ram1_C_AC[7 ]<=8'd0;
               ram1_C_AC[8 ]<=8'd0;
               ram1_C_AC[9 ]<=8'd0;
               ram1_C_AC[10]<=8'd0;
               ram1_C_AC[11]<=8'd0;
               ram1_C_AC[12]<=8'd0;
               ram1_C_AC[13]<=8'd0;
               ram1_C_AC[14]<=8'd0;
               ram1_C_AC[15]<=8'd0; 
             end 
     
            else 
            begin
                if(huffman_en ==2'b1)    //选择table类型和设置数据
                begin
                    if(huffman_color ==2'b00)   //Y_DC
                     begin
                        ram0_Y_DC[huffman_count]  <= huffman_mincode;
                        ram1_Y_DC[huffman_count] <= huffman_mincodeaddr;
                    end 
                    else if(huffman_color ==2'b01) //Y_AC
                    begin
                        ram0_Y_AC[huffman_count]  <= huffman_mincode;
                        ram1_Y_AC[huffman_count] <= huffman_mincodeaddr;
                    end 
                    else if(huffman_color ==2'b10) //C_DC
                    begin
                        ram0_C_DC[huffman_count]  <= huffman_mincode;
                        ram1_C_DC[huffman_count] <= huffman_mincodeaddr;
                    end else 
                    begin                               //C_AC
                        ram0_C_AC[huffman_count]  <= huffman_mincode;
                        ram1_C_AC[huffman_count] <= huffman_mincodeaddr;
                    end
                end
            end
        end
        
    //--------------------------------------------------------------------------
    // fsm
    //--------------------------------------------------------------------------
    reg [3:0]   state;       
    reg [31:0]  data_reg;    
    
    
    reg [15:0]  ram0 [0:15];
    reg [7:0]   ram1 [0:15];
    
    reg [3:0]  length;       
    reg [15:0]  mincode;     
    reg [7:0]   mincodeaddr;
    reg [15:0]  data_number; 
    
    reg [2:0]   state_color;
    reg [6:0]   state_count;
    
    reg         out_en;      
    reg [3:0]   out_zero;    
    reg [15:0]  code_value;  
    wire [15:0] code_value_p;   
    
    reg [6:0]   use_width_r;      
    reg signed [31:0] pre_data [0:2];
    
    wire [15:0] sub_code;
    
    parameter Idle  = 4'h0;
    parameter s1    = 4'h1;
    parameter s2    = 4'h2;
    parameter s3    = 4'h3;
    parameter s4    = 4'h4;
    parameter s5    = 4'h5;
    parameter s6    = 4'h6;
    parameter s7    = 4'h7;
    
    function [15:0] value_sel;
            input [3:0]   dhtrd_width;
            input [31:0]  data_reg;
            begin
                case (dhtrd_width)
                    4'h0: value_sel = 16'h0000;
                    4'h1: value_sel = {15'h0000, data_reg[31]};
                    4'h2: value_sel = {14'h0000, data_reg[31:30]};
                    4'h3: value_sel = {13'h0000, data_reg[31:29]};
                    4'h4: value_sel = {12'h000,  data_reg[31:28]};
                    4'h5: value_sel = {11'h000,  data_reg[31:27]};
                    4'h6: value_sel = {10'h000,  data_reg[31:26]};
                    4'h7: value_sel = {9'h000,   data_reg[31:25]};
                    4'h8: value_sel = {8'h00,    data_reg[31:24]};
                    4'h9: value_sel = {7'h00,    data_reg[31:23]};
                    4'hA: value_sel = {6'h00,    data_reg[31:22]};
                    4'hB: value_sel = {5'h00,    data_reg[31:21]};
                    4'hC: value_sel = {4'h0,     data_reg[31:20]};
                    4'hD: value_sel = {3'h0,     data_reg[31:19]};
                    4'hE: value_sel = {2'h0,     data_reg[31:18]};
                    4'hF: value_sel = {1'h0,     data_reg[31:17]};
                endcase
            end
        endfunction
        assign code_value_p = value_sel(dhtrd_width, data_reg);
              
        function [15:0] subcode_sel;
            input [3:0]  dhtrd_width;
            begin
            case (dhtrd_width)
                4'h0: subcode_sel = 16'hFFFF;
                4'h1: subcode_sel = 16'hFFFE;
                4'h2: subcode_sel = 16'hFFFC;
                4'h3: subcode_sel = 16'hFFF8;
                4'h4: subcode_sel = 16'hFFF0;
                4'h5: subcode_sel = 16'hFFE0;
                4'h6: subcode_sel = 16'hFFC0;
                4'h7: subcode_sel = 16'hFF80;
                4'h8: subcode_sel = 16'hFF00;
                4'h9: subcode_sel = 16'hFE00;
                4'hA: subcode_sel = 16'hFC00;
                4'hB: subcode_sel = 16'hF800;
                4'hC: subcode_sel = 16'hF000;
                4'hD: subcode_sel = 16'hE000;
                4'hE: subcode_sel = 16'hC000;
                4'hF: subcode_sel = 16'h8000;
            endcase
        end
    endfunction
    assign sub_code = subcode_sel(dhtrd_width);
        
    always @(posedge clk or negedge rst_n)
     begin
            if(!rst_n) begin
                state            <= Idle;
                data_reg         <= 32'h00000000;
                state_count      <= 6'd0;
                state_color      <=3'd0;
                out_en           <= 1'b0;
                pre_data[0]      <= 32'h00000000;
                pre_data[1]      <= 32'h00000000;
                pre_data[2]      <= 32'h00000000;
                use_width_r        <= 7'h00;
                length<=4'd0;
            end 
            else 
            begin
                case (state)
                	//准备状态
                    Idle: 
                    begin
                        if(image_en == 1'b1) //开始解码
                            state <= s1;
                        else                  //设置DC的初始值
                        begin
                         pre_data[0] <= 32'h00000000;
                         pre_data[1] <= 32'h00000000;
                         pre_data[2] <= 32'h00000000;
                        end
                        out_en      <= 1'b0;
                        state_color    <= 3'b000;
                        state_count   <= 6'd0;
                    end
                    
                    //从数据读入模块读入32位需要解码的数据。判断此次解
                    //数据是DC数据还是AC数据,同时选择相应的码表
                    s1:                          
                    begin
                        if(image_en == 1'b0) 
                        begin
                            state     <= Idle;
                        end 
                        else 
                        if(datain_en == 1'b1 & zig_zagIDLE == 1'b1)//输入数据使能,并且zig_zag存储器空闲
                         begin
                            state     <= s2;
                            data_reg <= datain;
                        end
                        out_en <= 1'b0;
                        if(state_color[2] == 1'b0) //此时解码的为亮度数据
                        begin
                            if(state_count == 0)//此时解码的为DC数据
                             begin
                                ram0[0]  <= ram0_Y_DC[0];
                                ram1[0]  <= ram1_Y_DC[0];
                                ram0[1]  <= ram0_Y_DC[1];
                                ram1[1]  <= ram1_Y_DC[1];
                                ram0[2]  <= ram0_Y_DC[2];
                                ram1[2]  <= ram1_Y_DC[2];
                                ram0[3]  <= ram0_Y_DC[3];
                                ram1[3]  <= ram1_Y_DC[3];
                                ram0[4]  <= ram0_Y_DC[4];
                                ram1[4]  <= ram1_Y_DC[4];
                                ram0[5]  <= ram0_Y_DC[5];
                                ram1[5]  <= ram1_Y_DC[5];
                                ram0[6]  <= ram0_Y_DC[6];
                                ram1[6]  <= ram1_Y_DC[6];
                                ram0[7]  <= ram0_Y_DC[7];
                                ram1[7]  <= ram1_Y_DC[7];
                                ram0[8]  <= ram0_Y_DC[8];
                                ram1[8]  <= ram1_Y_DC[8];
                                ram0[9]  <= ram0_Y_DC[9];
                                ram1[9]  <= ram1_Y_DC[9];
                                ram0[10]  <= ram0_Y_DC[10];
                                ram1[10]  <= ram1_Y_DC[10];
                                ram0[11]  <= ram0_Y_DC[11];
                                ram1[11]  <= ram1_Y_DC[11];
                                ram0[12]  <= ram0_Y_DC[12];
                                ram1[12]  <= ram1_Y_DC[12];
                                ram0[13]  <= ram0_Y_DC[13];
                                ram1[13]  <= ram1_Y_DC[13];
                                ram0[14]  <= ram0_Y_DC[14];
                                ram1[14]  <= ram1_Y_DC[14];  
                                ram0[15]  <= ram0_Y_DC[15];  
                                ram1[15]  <= ram1_Y_DC[15];  
                            end
                             else //此时解码的为AC数据
                             begin
                                ram0[0]  <= ram0_Y_AC[0];
                                ram1[0]  <= ram1_Y_AC[0];
                                ram0[1]  <= ram0_Y_AC[1];
                                ram1[1]  <= ram1_Y_AC[1];
                                ram0[2]  <= ram0_Y_AC[2];
                                ram1[2]  <= ram1_Y_AC[2];
                                ram0[3]  <= ram0_Y_AC[3];
                                ram1[3]  <= ram1_Y_AC[3];
                                ram0[4]  <= ram0_Y_AC[4];
                                ram1[4]  <= ram1_Y_AC[4];
                                ram0[5]  <= ram0_Y_AC[5];
                                ram1[5]  <= ram1_Y_AC[5];
                                ram0[6]  <= ram0_Y_AC[6];
                                ram1[6]  <= ram1_Y_AC[6];
                                ram0[7]  <= ram0_Y_AC[7];
                                ram1[7]  <= ram1_Y_AC[7];
                                ram0[8]  <= ram0_Y_AC[8];
                                ram1[8]  <= ram1_Y_AC[8];
                                ram0[9]  <= ram0_Y_AC[9];
                                ram1[9]  <= ram1_Y_AC[9];
                                ram0[10]  <= ram0_Y_AC[10];
                                ram1[10]  <= ram1_Y_AC[10];
                                ram0[11]  <= ram0_Y_AC[11];
                                ram1[11]  <= ram1_Y_AC[11];
                                ram0[12]  <= ram0_Y_AC[12];
                                ram1[12]  <= ram1_Y_AC[12];
                                ram0[13]  <= ram0_Y_AC[13];
                                ram1[13]  <= ram1_Y_AC[13];
                                ram0[14]  <= ram0_Y_AC[14];
                                ram1[14]  <= ram1_Y_AC[14];  
                                ram0[15]  <= ram0_Y_AC[15];  
                                ram1[15]  <= ram1_Y_AC[15];  
                            end
                        end 
                        else //此时解码的为色度数据
                        begin
                            if(state_count == 0)//此时解码的为DC数据
                             begin
                                ram0[0]  <= ram0_C_DC[0];    
                                ram1[0]  <= ram1_C_DC[0];    
                                ram0[1]  <= ram0_C_DC[1];    
                                ram1[1]  <= ram1_C_DC[1];    
                                ram0[2]  <= ram0_C_DC[2];    
                                ram1[2]  <= ram1_C_DC[2];    
                                ram0[3]  <= ram0_C_DC[3];    
                                ram1[3]  <= ram1_C_DC[3];    
                                ram0[4]  <= ram0_C_DC[4];    
                                ram1[4]  <= ram1_C_DC[4];    
                                ram0[5]  <= ram0_C_DC[5];    
                                ram1[5]  <= ram1_C_DC[5];    
                                ram0[6]  <= ram0_C_DC[6];    
                                ram1[6]  <= ram1_C_DC[6];    
                                ram0[7]  <= ram0_C_DC[7];    
                                ram1[7]  <= ram1_C_DC[7];    
                                ram0[8]  <= ram0_C_DC[8];    
                                ram1[8]  <= ram1_C_DC[8];    
                                ram0[9]  <= ram0_C_DC[9];    
                                ram1[9]  <= ram1_C_DC[9];    
                                ram0[10]  <= ram0_C_DC[10];  
                                ram1[10]  <= ram1_C_DC[10];  
                                ram0[11]  <= ram0_C_DC[11];  
                                ram1[11]  <= ram1_C_DC[11];  
                                ram0[12]  <= ram0_C_DC[12];  
                                ram1[12]  <= ram1_C_DC[12];  
                                ram0[13]  <= ram0_C_DC[13];  
                                ram1[13]  <= ram1_C_DC[13];  
                                ram0[14]  <= ram0_C_DC[14];  
                                ram1[14]  <= ram1_C_DC[14];  
                                ram0[15]  <= ram0_C_DC[15];  
                                ram1[15]  <= ram1_C_DC[15];  
                            end
                             else //此时解码的为AC数据
                             begin
                                ram0[0]  <= ram0_C_AC[0];    
                                ram1[0]  <= ram1_C_AC[0];    
                                ram0[1]  <= ram0_C_AC[1];    
                                ram1[1]  <= ram1_C_AC[1];    
                                ram0[2]  <= ram0_C_AC[2];    
                                ram1[2]  <= ram1_C_AC[2];    
                                ram0[3]  <= ram0_C_AC[3];    
                                ram1[3]  <= ram1_C_AC[3];    
                                ram0[4]  <= ram0_C_AC[4];    
                                ram1[4]  <= ram1_C_AC[4];    
                                ram0[5]  <= ram0_C_AC[5];    
                                ram1[5]  <= ram1_C_AC[5];    
                                ram0[6]  <= ram0_C_AC[6];    
                                ram1[6]  <= ram1_C_AC[6];    
                                ram0[7]  <= ram0_C_AC[7];    
                                ram1[7]  <= ram1_C_AC[7];    
                                ram0[8]  <= ram0_C_AC[8];    
                                ram1[8]  <= ram1_C_AC[8];    
                                ram0[9]  <= ram0_C_AC[9];    
                                ram1[9]  <= ram1_C_AC[9];    
                                ram0[10]  <= ram0_C_AC[10];  
                                ram1[10]  <= ram1_C_AC[10];  
                                ram0[11]  <= ram0_C_AC[11];  
                                ram1[11]  <= ram1_C_AC[11];  
                                ram0[12]  <= ram0_C_AC[12];  
                                ram1[12]  <= ram1_C_AC[12];  
                                ram0[13]  <= ram0_C_AC[13];  
                                ram1[13]  <= ram1_C_AC[13];  
                                ram0[14]  <= ram0_C_AC[14];  
                                ram1[14]  <= ram1_C_AC[14];  
                                ram0[15]  <= ram0_C_AC[15];  
                                ram1[15]  <= ram1_C_AC[15];  
                            end
                        end
                    end
                    
                    // compare table 进行码长的判断
                    s2: 
                    begin
                        state     <= s3;
                        if(data_reg[31:16] < ram0[0])  
                                length<=1'b0;
                        else  if(data_reg[31:16] < ram0[1])  
                              length<=4'd1;
                        else  if(data_reg[31:16] < ram0[2])  
                              length<=4'd2;
                        else  if(data_reg[31:16] < ram0[3])  
                              length<=4'd3;
                        else  if(data_reg[31:16] < ram0[4]) 
                              length<=4'd4; 
                        else  if(data_reg[31:16] < ram0[5]) 
                              length<=4'd5; 
                        else  if(data_reg[31:16] < ram0[6])  
                              length<=4'd6;
                        else  if(data_reg[31:16] < ram0[7])  
                              length<=4'd7;
                        else  if(data_reg[31:16] < ram0[8])  
                              length<=4'd8;
                        else  if(data_reg[31:16] < ram0[9])  
                              length<=4'd9;
                        else  if(data_reg[31:16] < ram0[10]) 
                              length<=4'd10;
                        else  if(data_reg[31:16] < ram0[11]) 
                              length<=4'd11;
                        else  if(data_reg[31:16] < ram0[12]) 
                              length<=4'd12;
                        else  if(data_reg[31:16] < ram0[13]) 
                              length<=4'd13;
                        else  if(data_reg[31:16] < ram0[14]) 
                              length<=4'd14;
                        else  if(data_reg[31:16] < ram0[15]) 
                              length<=4'd15;
                        else  
                              length<=4'd16;                          
                    end
                    
                    // 找出同等长度的码字的最小编码和首地址
                    s3:
                    begin
                        state <= s4;
                        case (length)
                            1: 
                              begin
                                mincode     <= {15'h0000,ram0[0][15]};//同等长度的最小的码字
                                mincodeaddr <= ram1[0];              //同等码长的最小码字存储地址
                                data_number  <= {15'h0000,data_reg[31]};//数据
                                data_reg <= {data_reg[30:0],1'b0};     //把判断码长的那不部分移植出去
                            end
                            2: begin
                                mincode     <= {14'h0000,ram0[1][15:14]};
                                mincodeaddr <= ram1[1];
                                data_number  <= {14'h0000,data_reg[31:30]};
                                data_reg <= {data_reg[29:0],2'b00};
                            end
                            3: begin
                                mincode     <= {13'h0000,ram0[2][15:13]};
                                mincodeaddr <= ram1[2];
                                data_number  <= {13'h0000,data_reg[31:29]};
                                data_reg <= {data_reg[28:0],3'b000};
                            end
                            4: begin
                                mincode     <= {12'h000,ram0[3][15:12]};
                                mincodeaddr <= ram1[3];
                                data_number  <= {12'h000,data_reg[31:28]};
                                data_reg <= {data_reg[27:0],4'h0};
                            end
                            5: begin
                                mincode     <= {11'h000,ram0[4][15:11]};
                                mincodeaddr <= ram1[4];
                                data_number  <= {11'h000,data_reg[31:27]};
                                data_reg <= {data_reg[26:0],5'h00};
                            end
                            6: begin
                                mincode     <= {10'h000,ram0[5][15:10]};
                                mincodeaddr <= ram1[5];
                                data_number  <= {10'h000,data_reg[31:26]};
                                data_reg <= {data_reg[25:0],6'h00};
                            end
                            7: begin
                                mincode     <= {9'h000,ram0[6][15:9]};
                                mincodeaddr <= ram1[6];
                                data_number  <= {9'h000,data_reg[31:25]};
                                data_reg <= {data_reg[24:0],7'h00};
                            end
                            8: begin
                                mincode     <= {8'h00,ram0[7][15:8]};
                                mincodeaddr <= ram1[7];
                                data_number  <= {8'h00,data_reg[31:24]};
                                data_reg <= {data_reg[23:0],8'h00};
                            end
                            9: begin
                                mincode     <= {7'h00,ram0[8][15:7]};
                                mincodeaddr <= ram1[8];
                                data_number  <= {7'h00,data_reg[31:23]};
                                data_reg <= {data_reg[22:0],9'h000};
                            end
                            10: begin
                                mincode     <= {6'h00,ram0[9][15:6]};
                                mincodeaddr <= ram1[9];
                                data_number  <= {6'h00,data_reg[31:22]};
                                data_reg <= {data_reg[21:0],10'h000};
                            end
                            11: begin
                                mincode     <= {5'h00,ram0[10][15:5]};
                                mincodeaddr <= ram1[10];
                                data_number  <= {5'h00,data_reg[31:21]};
                                data_reg <= {data_reg[20:0],11'h000};
                            end
                            12: begin
                                mincode     <= {4'h0,ram0[11][15:4]};
                                mincodeaddr <= ram1[11];
                                data_number  <= {4'h0,data_reg[31:20]};
                                data_reg <= {data_reg[19:0],12'h000};
                            end
                            14: begin
                                mincode     <= {3'h0,ram0[12][15:3]};
                                mincodeaddr <= ram1[12];
                                data_number  <= {3'h0,data_reg[31:19]};
                                data_reg <= {data_reg[18:0],13'h0000};
                            end
                            14: begin
                                mincode     <= {2'h0,ram0[13][15:2]};
                                mincodeaddr <= ram1[13];
                                data_number  <= {2'h0,data_reg[31:18]};
                                data_reg <= {data_reg[17:0],14'h0000};
                            end
                            15: begin
                                mincode     <= {1'h0,ram0[14][15:1]};
                                mincodeaddr <= ram1[14];
                                data_number  <= {1'h0,data_reg[31:17]};
                                data_reg <= {data_reg[16:0],15'h0000};
                            end
                            16: begin
                                mincode     <= ram0[15];
                                mincodeaddr <= ram1[15];
                                data_number  <= data_reg[31:16] ;
                                data_reg <= {data_reg[15:0],16'h0000};
                            end
                        endcase
                    end
    
                    s4:
                    if (zig_zagIDLE)
                      state<=s5;
                      
                    s5:
                     begin
                        state     <= s6;
                        out_zero     <= dhtrd_zero;         //0 的个数
                        use_width_r    <= length+dhtrd_width ;//本次消耗的代码的长度
                        if(state_count == 0)            //第一个数据
                        begin
                            out_en   <= 1'b1;
                        end 
                        else 
                        begin
                            if(dhtrd_zero == 4'h0 & dhtrd_width == 4'h0) 
                            begin
                                state_count    <= 6'd63;
                                out_en       <= 1'b0;
                            end 
                            else 
                            if(dhtrd_zero == 4'hF & dhtrd_width == 4'h0)
                             begin
                                state_count    <= state_count + 6'd15;
                                out_en      <= 1'b0;
                            end 
                            else
                             begin
                                state_count    <= state_count + dhtrd_zero;
                                out_en      <= 1'b1;
                            end
                        end
                          
                        if(data_reg[31] == 1'b0 & dhtrd_width != 0) //判断符号
                        begin
                            code_value <= (code_value_p | sub_code) + 16'h0001;
                        end else begin
                            code_value <= code_value_p;
                        end
                    end
                    
                    //对DC系数解码
                    s6:
                     begin
                        state <= s7;
                        if(state_count == 0)
                         begin
                            if(state_color[2] == 1'b0)//Y:直流系数与前个系数相加的结果
                            begin
                                code_value   <= code_value + pre_data[0][15:0];
                                pre_data[0]  <= code_value + pre_data[0];
                            end 
                            else 
                            begin
                                if(state_color[0] == 1'b0) //CB:直流系数与前个系数相加的结果
                                begin
                                    code_value   <= code_value + pre_data[1][15:0];
                                    pre_data[1]  <= code_value + pre_data[1];
                                end 
                                else                          //CR:直流系数与前个系数相加的结果
                                begin
                                    code_value   <= code_value + pre_data[2][15:0];
                                    pre_data[2]  <= code_value + pre_data[2];
                                end
                            end
                        end
                    end
                    
                    s7: 
                    begin
                        out_en <= 1'b0;
                        if(state_count <6'd63) begin
                            state         <= s1;
                            state_count    <= state_count +6'd1;
                        end else begin
                            state_count  <= 6'd0;
                            if(state_color == 5) begin
                                state_color    <= 3'b000;
                                state         <= s1;
                            end else begin
                                state         <= s1;
                                state_color    <= state_color +3'd1;
                            end
                        end
                    end
                endcase
            end
        end
        
        assign dhtrd_color[1]      = state_color[2];
        assign dhtrd_color[0]      = state_count != 6'd0;
        assign dhtrd_addr        = data_number - mincode + mincodeaddr;
    
        assign dqtrd_color         = state_color[2];
        assign dqtrd_addr        = state_count[5:0];
    
        assign use_bit     = state == s6;
    
        assign dataout_en     = (out_en == 1'b1 & state == s7);
        assign dataout_count      = state_count;
        assign dataout       = dqtrd_data * code_value;
        assign use_width=use_width_r;
        assign unit_en    = (state == s7) & (state_count == 6'd63);
    
    endmodule
    
    ram
    //huffman 存储器,一个用于存储最小的编码,一个用于存储最小编码对应的首地址
    reg [15:0] ram0_Y_DC [0:15];
    reg [15:0] ram0_Y_AC [0:15];
    reg [15:0] ram0_C_DC [0:15];
    reg [15:0] ram0_C_AC [0:15];

    reg [7:0] ram1_Y_DC [0:15];
    reg [7:0] ram1_Y_AC [0:15];
    reg [7:0] ram1_C_DC [0:15];
    reg [7:0] ram1_C_AC [0:15];

    always @(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    begin
    ram0_Y_DC[0 ]<=16'd0;
    ram0_Y_DC[1 ]<=16'd0;
    ram0_Y_DC[2 ]<=16'd0;
    ram0_Y_DC[3 ]<=16'd0;
    ram0_Y_DC[4 ]<=16'd0;
    ram0_Y_DC[5 ]<=16'd0;
    ram0_Y_DC[6 ]<=16'd0;
    ram0_Y_DC[7 ]<=16'd0;
    ram0_Y_DC[8 ]<=16'd0;
    ram0_Y_DC[9 ]<=16'd0;
    ram0_Y_DC[10]<=16'd0;
    ram0_Y_DC[11]<=16'd0;
    ram0_Y_DC[12]<=16'd0;
    ram0_Y_DC[13]<=16'd0;
    ram0_Y_DC[14]<=16'd0;
    ram0_Y_DC[15]<=16'd0;

    ram0_Y_AC[0 ]<=16'd0;
    ram0_Y_AC[1 ]<=16'd0;
    ram0_Y_AC[2 ]<=16'd0;
    ram0_Y_AC[3 ]<=16'd0;
    ram0_Y_AC[4 ]<=16'd0;
    ram0_Y_AC[5 ]<=16'd0;
    ram0_Y_AC[6 ]<=16'd0;
    ram0_Y_AC[7 ]<=16'd0;
    ram0_Y_AC[8 ]<=16'd0;
    ram0_Y_AC[9 ]<=16'd0;
    ram0_Y_AC[10]<=16'd0;
    ram0_Y_AC[11]<=16'd0;
    ram0_Y_AC[12]<=16'd0;
    ram0_Y_AC[13]<=16'd0;
    ram0_Y_AC[14]<=16'd0;
    ram0_Y_AC[15]<=16'd0;

    ram0_C_DC[0 ]<=16'D0;
    ram0_C_DC[1 ]<=16'D0;
    ram0_C_DC[2 ]<=16'D0;
    ram0_C_DC[3 ]<=16'D0;
    ram0_C_DC[4 ]<=16'D0;
    ram0_C_DC[5 ]<=16'D0;
    ram0_C_DC[6 ]<=16'D0;
    ram0_C_DC[7 ]<=16'D0;
    ram0_C_DC[8 ]<=16'D0;
    ram0_C_DC[9 ]<=16'D0;
    ram0_C_DC[10]<=16'D0;
    ram0_C_DC[11]<=16'D0;
    ram0_C_DC[12]<=16'D0;
    ram0_C_DC[13]<=16'D0;
    ram0_C_DC[14]<=16'D0;
    ram0_C_DC[15]<=16'D0;

    ram0_C_AC[0 ]<=16'd0;
    ram0_C_AC[1 ]<=16'd0;
    ram0_C_AC[2 ]<=16'd0;
    ram0_C_AC[3 ]<=16'd0;
    ram0_C_AC[4 ]<=16'd0;
    ram0_C_AC[5 ]<=16'd0;
    ram0_C_AC[6 ]<=16'd0;
    ram0_C_AC[7 ]<=16'd0;
    ram0_C_AC[8 ]<=16'd0;
    ram0_C_AC[9 ]<=16'd0;
    ram0_C_AC[10]<=16'd0;
    ram0_C_AC[11]<=16'd0;
    ram0_C_AC[12]<=16'd0;
    ram0_C_AC[13]<=16'd0;
    ram0_C_AC[14]<=16'd0;
    ram0_C_AC[15]<=16'd0;

    ram1_Y_DC[0 ]<=8'd0;
    ram1_Y_DC[1 ]<=8'd0;
    ram1_Y_DC[2 ]<=8'd0;
    ram1_Y_DC[3 ]<=8'd0;
    ram1_Y_DC[4 ]<=8'd0;
    ram1_Y_DC[5 ]<=8'd0;
    ram1_Y_DC[6 ]<=8'd0;
    ram1_Y_DC[7 ]<=8'd0;
    ram1_Y_DC[8 ]<=8'd0;
    ram1_Y_DC[9 ]<=8'd0;
    ram1_Y_DC[10]<=8'd0;
    ram1_Y_DC[11]<=8'd0;
    ram1_Y_DC[12]<=8'd0;
    ram1_Y_DC[13]<=8'd0;
    ram1_Y_DC[14]<=8'd0;
    ram1_Y_DC[15]<=8'd0;

    ram1_Y_AC[0 ]<=8'd0;
    ram1_Y_AC[1 ]<=8'd0;
    ram1_Y_AC[2 ]<=8'd0;
    ram1_Y_AC[3 ]<=8'd0;
    ram1_Y_AC[4 ]<=8'd0;
    ram1_Y_AC[5 ]<=8'd0;
    ram1_Y_AC[6 ]<=8'd0;
    ram1_Y_AC[7 ]<=8'd0;
    ram1_Y_AC[8 ]<=8'd0;
    ram1_Y_AC[9 ]<=8'd0;
    ram1_Y_AC[10]<=8'd0;
    ram1_Y_AC[11]<=8'd0;
    ram1_Y_AC[12]<=8'd0;
    ram1_Y_AC[13]<=8'd0;
    ram1_Y_AC[14]<=8'd0;
    ram1_Y_AC[15]<=8'd0;

    ram1_C_DC[0 ]<=8'D0;
    ram1_C_DC[1 ]<=8'D0;
    ram1_C_DC[2 ]<=8'D0;
    ram1_C_DC[3 ]<=8'D0;
    ram1_C_DC[4 ]<=8'D0;
    ram1_C_DC[5 ]<=8'D0;
    ram1_C_DC[6 ]<=8'D0;
    ram1_C_DC[7 ]<=8'D0;
    ram1_C_DC[8 ]<=8'D0;
    ram1_C_DC[9 ]<=8'D0;
    ram1_C_DC[10]<=8'D0;
    ram1_C_DC[11]<=8'D0;
    ram1_C_DC[12]<=8'D0;
    ram1_C_DC[13]<=8'D0;
    ram1_C_DC[14]<=8'D0;
    ram1_C_DC[15]<=8'D0;

    ram1_C_AC[0 ]<=8'd0;
    ram1_C_AC[1 ]<=8'd0;
    ram1_C_AC[2 ]<=8'd0;
    ram1_C_AC[3 ]<=8'd0;
    ram1_C_AC[4 ]<=8'd0;
    ram1_C_AC[5 ]<=8'd0;
    ram1_C_AC[6 ]<=8'd0;
    ram1_C_AC[7 ]<=8'd0;
    ram1_C_AC[8 ]<=8'd0;
    ram1_C_AC[9 ]<=8'd0;
    ram1_C_AC[10]<=8'd0;
    ram1_C_AC[11]<=8'd0;
    ram1_C_AC[12]<=8'd0;
    ram1_C_AC[13]<=8'd0;
    ram1_C_AC[14]<=8'd0;
    ram1_C_AC[15]<=8'd0;
    end

    else
    begin
    if(huffman_en ==2'b1) //选择table类型和设置数据
    begin
    if(huffman_color ==2'b00) //Y_DC
    begin
    ram0_Y_DC[huffman_count] <= huffman_mincode;
    ram1_Y_DC[huffman_count] <= huffman_mincodeaddr;
    end
    else if(huffman_color ==2'b01) //Y_AC
    begin
    ram0_Y_AC[huffman_count] <= huffman_mincode;
    ram1_Y_AC[huffman_count] <= huffman_mincodeaddr;
    end
    else if(huffman_color ==2'b10) //C_DC
    begin
    ram0_C_DC[huffman_count] <= huffman_mincode;
    ram1_C_DC[huffman_count] <= huffman_mincodeaddr;
    end else
    begin //C_AC
    ram0_C_AC[huffman_count] <= huffman_mincode;
    ram1_C_AC[huffman_count] <= huffman_mincodeaddr;
    end
    end
    end
    end

    对需要用到的存储器声明,其中ram0是存放最小编码的码字,ram1是存放最小编码的地址,根据输入的数据的不同选择对应的ram。

    这里声明8个ram为4对,即亮度直流存储器,亮度交流存储器,色度直流存储器,色度交流存储器。

    IDLE
            //准备状态
    Idle:
    begin
    if(image_en == 1'b1) //开始解码
    state <= s1;
    else //设置DC的初始值
    begin
    pre_data[0] <= 32'h00000000;
    pre_data[1] <= 32'h00000000;
    pre_data[2] <= 32'h00000000;
    end
    out_en <= 1'b0;
    state_color <= 3'b000;
    state_count <= 6'd0;
    end

    就绪状态:当FSM模块读到SOS标记表示开始解码。转入下个状态。与此同时设置3个DC系数的初值。因为DC采用的是DPCM编码是一种差分编码,对于第一个DC系数保存其值,对于以后的每个DC系数不保存他的值而是保存他与前个系数的差值,所以在解码到DC系数时应加上前一个DC系数的值,但是第一个DC系数时没有前一个值的所以这里初始化3个寄存器为0,pre_data.他们分别保存的为Y,CB,CR的DC差值。

    S1
                  //从数据读入模块读入32位需要解码的数据。判断此次解
    //数据是DC数据还是AC数据,同时选择相应的码表
    s1:
    begin
    if(image_en == 1'b0)
    begin
    state <= Idle;
    end
    else
    if(datain_en == 1'b1 & zig_zagIDLE == 1'b1)//输入数据使能,并且zig_zag存储器空闲
    begin
    state <= s2;
    data_reg <= datain;
    end
    out_en <= 1'b0;
    if(state_color[2] == 1'b0) //此时解码的为亮度数据
    begin
    if(state_count == 0)//此时解码的为DC数据
    begin
    ram0[0] <= ram0_Y_DC[0];
    ram1[0] <= ram1_Y_DC[0];
    ram0[1] <= ram0_Y_DC[1];
    ram1[1] <= ram1_Y_DC[1];
    ram0[2] <= ram0_Y_DC[2];
    ram1[2] <= ram1_Y_DC[2];
    ram0[3] <= ram0_Y_DC[3];
    ram1[3] <= ram1_Y_DC[3];
    ram0[4] <= ram0_Y_DC[4];
    ram1[4] <= ram1_Y_DC[4];
    ram0[5] <= ram0_Y_DC[5];
    ram1[5] <= ram1_Y_DC[5];
    ram0[6] <= ram0_Y_DC[6];
    ram1[6] <= ram1_Y_DC[6];
    ram0[7] <= ram0_Y_DC[7];
    ram1[7] <= ram1_Y_DC[7];
    ram0[8] <= ram0_Y_DC[8];
    ram1[8] <= ram1_Y_DC[8];
    ram0[9] <= ram0_Y_DC[9];
    ram1[9] <= ram1_Y_DC[9];
    ram0[10] <= ram0_Y_DC[10];
    ram1[10] <= ram1_Y_DC[10];
    ram0[11] <= ram0_Y_DC[11];
    ram1[11] <= ram1_Y_DC[11];
    ram0[12] <= ram0_Y_DC[12];
    ram1[12] <= ram1_Y_DC[12];
    ram0[13] <= ram0_Y_DC[13];
    ram1[13] <= ram1_Y_DC[13];
    ram0[14] <= ram0_Y_DC[14];
    ram1[14] <= ram1_Y_DC[14];
    ram0[15] <= ram0_Y_DC[15];
    ram1[15] <= ram1_Y_DC[15];
    end
    else //此时解码的为AC数据
    begin
    ram0[0] <= ram0_Y_AC[0];
    ram1[0] <= ram1_Y_AC[0];
    ram0[1] <= ram0_Y_AC[1];
    ram1[1] <= ram1_Y_AC[1];
    ram0[2] <= ram0_Y_AC[2];
    ram1[2] <= ram1_Y_AC[2];
    ram0[3] <= ram0_Y_AC[3];
    ram1[3] <= ram1_Y_AC[3];
    ram0[4] <= ram0_Y_AC[4];
    ram1[4] <= ram1_Y_AC[4];
    ram0[5] <= ram0_Y_AC[5];
    ram1[5] <= ram1_Y_AC[5];
    ram0[6] <= ram0_Y_AC[6];
    ram1[6] <= ram1_Y_AC[6];
    ram0[7] <= ram0_Y_AC[7];
    ram1[7] <= ram1_Y_AC[7];
    ram0[8] <= ram0_Y_AC[8];
    ram1[8] <= ram1_Y_AC[8];
    ram0[9] <= ram0_Y_AC[9];
    ram1[9] <= ram1_Y_AC[9];
    ram0[10] <= ram0_Y_AC[10];
    ram1[10] <= ram1_Y_AC[10];
    ram0[11] <= ram0_Y_AC[11];
    ram1[11] <= ram1_Y_AC[11];
    ram0[12] <= ram0_Y_AC[12];
    ram1[12] <= ram1_Y_AC[12];
    ram0[13] <= ram0_Y_AC[13];
    ram1[13] <= ram1_Y_AC[13];
    ram0[14] <= ram0_Y_AC[14];
    ram1[14] <= ram1_Y_AC[14];
    ram0[15] <= ram0_Y_AC[15];
    ram1[15] <= ram1_Y_AC[15];
    end
    end
    else //此时解码的为色度数据
    begin
    if(state_count == 0)//此时解码的为DC数据
    begin
    ram0[0] <= ram0_C_DC[0];
    ram1[0] <= ram1_C_DC[0];
    ram0[1] <= ram0_C_DC[1];
    ram1[1] <= ram1_C_DC[1];
    ram0[2] <= ram0_C_DC[2];
    ram1[2] <= ram1_C_DC[2];
    ram0[3] <= ram0_C_DC[3];
    ram1[3] <= ram1_C_DC[3];
    ram0[4] <= ram0_C_DC[4];
    ram1[4] <= ram1_C_DC[4];
    ram0[5] <= ram0_C_DC[5];
    ram1[5] <= ram1_C_DC[5];
    ram0[6] <= ram0_C_DC[6];
    ram1[6] <= ram1_C_DC[6];
    ram0[7] <= ram0_C_DC[7];
    ram1[7] <= ram1_C_DC[7];
    ram0[8] <= ram0_C_DC[8];
    ram1[8] <= ram1_C_DC[8];
    ram0[9] <= ram0_C_DC[9];
    ram1[9] <= ram1_C_DC[9];
    ram0[10] <= ram0_C_DC[10];
    ram1[10] <= ram1_C_DC[10];
    ram0[11] <= ram0_C_DC[11];
    ram1[11] <= ram1_C_DC[11];
    ram0[12] <= ram0_C_DC[12];
    ram1[12] <= ram1_C_DC[12];
    ram0[13] <= ram0_C_DC[13];
    ram1[13] <= ram1_C_DC[13];
    ram0[14] <= ram0_C_DC[14];
    ram1[14] <= ram1_C_DC[14];
    ram0[15] <= ram0_C_DC[15];
    ram1[15] <= ram1_C_DC[15];
    end
    else //此时解码的为AC数据
    begin
    ram0[0] <= ram0_C_AC[0];
    ram1[0] <= ram1_C_AC[0];
    ram0[1] <= ram0_C_AC[1];
    ram1[1] <= ram1_C_AC[1];
    ram0[2] <= ram0_C_AC[2];
    ram1[2] <= ram1_C_AC[2];
    ram0[3] <= ram0_C_AC[3];
    ram1[3] <= ram1_C_AC[3];
    ram0[4] <= ram0_C_AC[4];
    ram1[4] <= ram1_C_AC[4];
    ram0[5] <= ram0_C_AC[5];
    ram1[5] <= ram1_C_AC[5];
    ram0[6] <= ram0_C_AC[6];
    ram1[6] <= ram1_C_AC[6];
    ram0[7] <= ram0_C_AC[7];
    ram1[7] <= ram1_C_AC[7];
    ram0[8] <= ram0_C_AC[8];
    ram1[8] <= ram1_C_AC[8];
    ram0[9] <= ram0_C_AC[9];
    ram1[9] <= ram1_C_AC[9];
    ram0[10] <= ram0_C_AC[10];
    ram1[10] <= ram1_C_AC[10];
    ram0[11] <= ram0_C_AC[11];
    ram1[11] <= ram1_C_AC[11];
    ram0[12] <= ram0_C_AC[12];
    ram1[12] <= ram1_C_AC[12];
    ram0[13] <= ram0_C_AC[13];
    ram1[13] <= ram1_C_AC[13];
    ram0[14] <= ram0_C_AC[14];
    ram1[14] <= ram1_C_AC[14];
    ram0[15] <= ram0_C_AC[15];
    ram1[15] <= ram1_C_AC[15];
    end
    end
    end

    S1状态是对存储器的选择,解码到不同的数据时候把他对应的存储器的值搬运到解码用到的存储器中,方便使用。当反量化模块处于空闲时,转入下个状态。

    S2
                    
    // compare table 进行码长的判断
    s2:
    begin
    state <= s3;
    if(data_reg[31:16] < ram0[0])
    length<=1'b0;
    else if(data_reg[31:16] < ram0[1])
    length<=4'd1;
    else if(data_reg[31:16] < ram0[2])
    length<=4'd2;
    else if(data_reg[31:16] < ram0[3])
    length<=4'd3;
    else if(data_reg[31:16] < ram0[4])
    length<=4'd4;
    else if(data_reg[31:16] < ram0[5])
    length<=4'd5;
    else if(data_reg[31:16] < ram0[6])
    length<=4'd6;
    else if(data_reg[31:16] < ram0[7])
    length<=4'd7;
    else if(data_reg[31:16] < ram0[8])
    length<=4'd8;
    else if(data_reg[31:16] < ram0[9])
    length<=4'd9;
    else if(data_reg[31:16] < ram0[10])
    length<=4'd10;
    else if(data_reg[31:16] < ram0[11])
    length<=4'd11;
    else if(data_reg[31:16] < ram0[12])
    length<=4'd12;
    else if(data_reg[31:16] < ram0[13])
    length<=4'd13;
    else if(data_reg[31:16] < ram0[14])
    length<=4'd14;
    else if(data_reg[31:16] < ram0[15])
    length<=4'd15;
    else
    length<=4'd16;
    end


    S2状态是对码长的判断,对每个不同长度的最小编码进行比较,找到解码数据的长度。例如:判断码长是否为1,先拿解码的最高位与长度为1的最小编码比较,若小于最小编码,则长度为0,如大于最小编码则长度>=1。再判断码长是否为2,拿解码的高2位与长度为2的最小编码比较,若小于最小编码则长度为1,若大于最小编码则长度>=2,以此类推,知道找到码长。

    S3
                   // 找出同等长度的码字的最小编码和首地址
    s3:
    begin
    state <= s4;
    case (length)
    1:
    begin
    mincode <= {15'h0000,ram0[0][15]};//同等长度的最小的码字
    mincodeaddr <= ram1[0]; //同等码长的最小码字存储地址
    data_number <= {15'h0000,data_reg[31]};//数据
    data_reg <= {data_reg[30:0],1'b0}; //把判断码长的那不部分移植出去
    end
    2: begin
    mincode <= {14'h0000,ram0[1][15:14]};
    mincodeaddr <= ram1[1];
    data_number <= {14'h0000,data_reg[31:30]};
    data_reg <= {data_reg[29:0],2'b00};
    end
    3: begin
    mincode <= {13'h0000,ram0[2][15:13]};
    mincodeaddr <= ram1[2];
    data_number <= {13'h0000,data_reg[31:29]};
    data_reg <= {data_reg[28:0],3'b000};
    end
    4: begin
    mincode <= {12'h000,ram0[3][15:12]};
    mincodeaddr <= ram1[3];
    data_number <= {12'h000,data_reg[31:28]};
    data_reg <= {data_reg[27:0],4'h0};
    end
    5: begin
    mincode <= {11'h000,ram0[4][15:11]};
    mincodeaddr <= ram1[4];
    data_number <= {11'h000,data_reg[31:27]};
    data_reg <= {data_reg[26:0],5'h00};
    end
    6: begin
    mincode <= {10'h000,ram0[5][15:10]};
    mincodeaddr <= ram1[5];
    data_number <= {10'h000,data_reg[31:26]};
    data_reg <= {data_reg[25:0],6'h00};
    end
    7: begin
    mincode <= {9'h000,ram0[6][15:9]};
    mincodeaddr <= ram1[6];
    data_number <= {9'h000,data_reg[31:25]};
    data_reg <= {data_reg[24:0],7'h00};
    end
    8: begin
    mincode <= {8'h00,ram0[7][15:8]};
    mincodeaddr <= ram1[7];
    data_number <= {8'h00,data_reg[31:24]};
    data_reg <= {data_reg[23:0],8'h00};
    end
    9: begin
    mincode <= {7'h00,ram0[8][15:7]};
    mincodeaddr <= ram1[8];
    data_number <= {7'h00,data_reg[31:23]};
    data_reg <= {data_reg[22:0],9'h000};
    end
    10: begin
    mincode <= {6'h00,ram0[9][15:6]};
    mincodeaddr <= ram1[9];
    data_number <= {6'h00,data_reg[31:22]};
    data_reg <= {data_reg[21:0],10'h000};
    end
    11: begin
    mincode <= {5'h00,ram0[10][15:5]};
    mincodeaddr <= ram1[10];
    data_number <= {5'h00,data_reg[31:21]};
    data_reg <= {data_reg[20:0],11'h000};
    end
    12: begin
    mincode <= {4'h0,ram0[11][15:4]};
    mincodeaddr <= ram1[11];
    data_number <= {4'h0,data_reg[31:20]};
    data_reg <= {data_reg[19:0],12'h000};
    end
    14: begin
    mincode <= {3'h0,ram0[12][15:3]};
    mincodeaddr <= ram1[12];
    data_number <= {3'h0,data_reg[31:19]};
    data_reg <= {data_reg[18:0],13'h0000};
    end
    14: begin
    mincode <= {2'h0,ram0[13][15:2]};
    mincodeaddr <= ram1[13];
    data_number <= {2'h0,data_reg[31:18]};
    data_reg <= {data_reg[17:0],14'h0000};
    end
    15: begin
    mincode <= {1'h0,ram0[14][15:1]};
    mincodeaddr <= ram1[14];
    data_number <= {1'h0,data_reg[31:17]};
    data_reg <= {data_reg[16:0],15'h0000};
    end
    16: begin
    mincode <= ram0[15];
    mincodeaddr <= ram1[15];
    data_number <= data_reg[31:16] ;
    data_reg <= {data_reg[15:0],16'h0000};
    end
    endcase
    end

    S3状态是找到与解码数据同长度的最小编码和最小编码的地址,从而解出DHT表的地址,方法为:解码数据-最小编码+最小编码的地址(data_number-mincode+mincodeaddr)

    S4
                    s4:
    if (zig_zagIDLE)
    state<=s5;

    s4状态为过渡状态。

    S5
                   s5:
    begin
    state <= s6;
    out_zero <= dhtrd_zero; //0 的个数
    use_width_r <= length+dhtrd_width ;//本次消耗的代码的长度
    if(state_count == 0) //第一个数据
    begin
    out_en <= 1'b1;
    end
    else
    begin
    if(dhtrd_zero == 4'h0 & dhtrd_width == 4'h0)
    begin
    state_count <= 6'd63;
    out_en <= 1'b0;
    end
    else
    if(dhtrd_zero == 4'hF & dhtrd_width == 4'h0)
    begin
    state_count <= state_count + 6'd15;
    out_en <= 1'b0;
    end
    else
    begin
    state_count <= state_count + dhtrd_zero;
    out_en <= 1'b1;
    end
    end

    if(data_reg[31] == 1'b0 & dhtrd_width != 0) //判断符号
    begin
    code_value <= (code_value_p | sub_code) + 16'h0001;
    end else begin
    code_value <= code_value_p;
    end
    end


    S5状态是对解码数据的符号的判断,huffman编码负数的表示与正常的表示方法不一样,例如:10编为1010,-10变为0101,正数和负数互为取反,所以在解到负数的时候要转化过来,我们知道-10在计算机中保存为 1...110(1010取反加1),为了得到正确的结果,若解码到负数,则把负数的高位设置为1,然后再加一,(code_value <= (code_value_p | sub_code) + 16'h0001),0101高位设为1变为1...101,再加上1,变为1...110,和上面结果一样,在Verilog里面定义了两个函数来实现上述操作,如下:

    function
    function [15:0] value_sel;
    input [3:0] dhtrd_width;
    input [31:0] data_reg;
    begin
    case (dhtrd_width)
    4'h0: value_sel = 16'h0000;
    4'h1: value_sel = {15'h0000, data_reg[31]};
    4'h2: value_sel = {14'h0000, data_reg[31:30]};
    4'h3: value_sel = {13'h0000, data_reg[31:29]};
    4'h4: value_sel = {12'h000, data_reg[31:28]};
    4'h5: value_sel = {11'h000, data_reg[31:27]};
    4'h6: value_sel = {10'h000, data_reg[31:26]};
    4'h7: value_sel = {9'h000, data_reg[31:25]};
    4'h8: value_sel = {8'h00, data_reg[31:24]};
    4'h9: value_sel = {7'h00, data_reg[31:23]};
    4'hA: value_sel = {6'h00, data_reg[31:22]};
    4'hB: value_sel = {5'h00, data_reg[31:21]};
    4'hC: value_sel = {4'h0, data_reg[31:20]};
    4'hD: value_sel = {3'h0, data_reg[31:19]};
    4'hE: value_sel = {2'h0, data_reg[31:18]};
    4'hF: value_sel = {1'h0, data_reg[31:17]};
    endcase
    end
    endfunction
    assign code_value_p = value_sel(dhtrd_width, data_reg);

    function [15:0] subcode_sel;
    input [3:0] dhtrd_width;
    begin
    case (dhtrd_width)
    4'h0: subcode_sel = 16'hFFFF;
    4'h1: subcode_sel = 16'hFFFE;
    4'h2: subcode_sel = 16'hFFFC;
    4'h3: subcode_sel = 16'hFFF8;
    4'h4: subcode_sel = 16'hFFF0;
    4'h5: subcode_sel = 16'hFFE0;
    4'h6: subcode_sel = 16'hFFC0;
    4'h7: subcode_sel = 16'hFF80;
    4'h8: subcode_sel = 16'hFF00;
    4'h9: subcode_sel = 16'hFE00;
    4'hA: subcode_sel = 16'hFC00;
    4'hB: subcode_sel = 16'hF800;
    4'hC: subcode_sel = 16'hF000;
    4'hD: subcode_sel = 16'hE000;
    4'hE: subcode_sel = 16'hC000;
    4'hF: subcode_sel = 16'h8000;
    endcase
    end
    endfunction
    assign sub_code = subcode_sel(dhtrd_width);


    第一个函数是取有效的编码,第二个函数是对编码的高位置1处理,只有编码为负数才用到,具体操作为:若编码的有效长度为3,则第一个函数是取数据的高三位存到32位寄存器中(本设计中数据是32位传输)的低3位,高位为0,函数2是把高29为置1,低3位置0,如编码为负数,则函数一与函数而相或操作即可实现功能。

    S6
                   //对DC系数解码
    s6:
    begin
    state <= s7;
    if(state_count == 0)
    begin
    if(state_color[2] == 1'b0)//Y:直流系数与前个系数相加的结果
    begin
    code_value <= code_value + pre_data[0][15:0];
    pre_data[0] <= code_value + pre_data[0];
    end
    else
    begin
    if(state_color[0] == 1'b0) //CB:直流系数与前个系数相加的结果
    begin
    code_value <= code_value + pre_data[1][15:0];
    pre_data[1] <= code_value + pre_data[1];
    end
    else //CR:直流系数与前个系数相加的结果
    begin
    code_value <= code_value + pre_data[2][15:0];
    pre_data[2] <= code_value + pre_data[2];
    end
    end
    end
    end

    S6是对DC系数进行DPCM解码,实际的DC系数为本次解到的DC系数与上次的DC系数相加的结果,并且保存本次实际的DC系数。

    S7
                   
    s7:
    begin
    out_en <= 1'b0;
    if(state_count <6'd63) begin
    state <= s1;
    state_count <= state_count +6'd1;
    end else begin
    state_count <= 6'd0;
    if(state_color == 5) begin
    state_color <= 3'b000;
    state <= s1;
    end else begin
    state <= s1;
    state_color <= state_color +3'd1;
    end
    end
    end

    S7是最后一个状态,对各个计数器的值进行设置。

    View Code
     1   assign dhtrd_color[1]      = state_color[2];
    2 assign dhtrd_color[0] = state_count != 6'd0;
    3 assign dhtrd_addr = data_number - mincode + mincodeaddr;
    4
    5 assign dqtrd_color = state_color[2];
    6 assign dqtrd_addr = state_count[5:0];
    7
    8 assign use_bit = state == s6;
    9
    10 assign dataout_en = (out_en == 1'b1 & state == s7);
    11 assign dataout_count = state_count;
    12 assign dataout = dqtrd_data * code_value;
    13 assign use_width=use_width_r;
    14 assign unit_en = (state == s7) & (state_count == 6'd63);

    最后对各个端口赋值,13行即完成一次反量化,解码得到数据与量化表数据相乘即可得到。
     

    在这里提一下JPEG数据的流程:压缩比为4:1:1,即每次来6个数据块为一个为一个单元,每个数据块为8*8=64个数据,来的顺序为:Y,Y,Y,Y,CB,CR.其中每个Y,CB,CR都是64个数据。

  • 相关阅读:
    Dingo/api 学习笔记
    Composer install 报错
    bootstrap4 调整元素之间距离
    css font-family常用的黑体宋体等字体中英文对照
    mac 开关机
    lodash.memoize
    Evevt Loop 事件循环
    mac 安装 XX-Net-3.12.11
    mac端口占用
    npm 安装/删除/发布/更新/撤销 发布包
  • 原文地址:https://www.cnblogs.com/tony1224/p/2404268.html
Copyright © 2020-2023  润新知