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

//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:
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差值。

//從數據讀入模塊讀入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狀態是對存儲器的選擇,解碼到不同的數據時候把他對應的存儲器的值搬運到解碼用到的存儲器中,方便使用。當反量化模塊處於空閑時,轉入下個狀態。

// 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:
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:
if (zig_zagIDLE)
state<=s5;
s4狀態為過渡狀態。

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 [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,如編碼為負數,則函數一與函數而相或操作即可實現功能。

//對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:
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是最后一個狀態,對各個計數器的值進行設置。

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