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個數據。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM