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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//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对,即亮度直流存储器,亮度交流存储器,色度直流存储器,色度交流存储器。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//准备状态
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差值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//从数据读入模块读入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状态是对存储器的选择,解码到不同的数据时候把他对应的存储器的值搬运到解码用到的存储器中,方便使用。当反量化模块处于空闲时,转入下个状态。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 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,以此类推,知道找到码长。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 找出同等长度的码字的最小编码和首地址
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)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
s4:
if (zig_zagIDLE)
state<=s5;
s4状态为过渡状态。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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里面定义了两个函数来实现上述操作,如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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,如编码为负数,则函数一与函数而相或操作即可实现功能。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//对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系数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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是最后一个状态,对各个计数器的值进行设置。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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个数据。