反量化模块就是对输入的64个数据进行重新排列,64个数据为8*8的数据,即8行8列。在进行编码的时候,DCT变换实际上是将图像从色彩域转向频频域,进过DCT变换的数据要经过量化,量化是实际上是对DCT系数的一个优化过程,它是利用人眼对高频部分不敏感的特性来实现数据的大幅度简化,具体操作时把频率域上的每个成分除以一个对于该成分的常数,去四舍五入接近的整数(已经在huffman解码模块实现反量化),是一种有损压缩。量化后的数据有个很大的特点,就是数列上的相邻点在图像上也是相邻的,还有个特点是直流分量对于交流分量来说要大,而且交流分量中含有大量的0,对于量化后的数据如何进行简化,从而再更大的进行数据压缩,这是就出现了Zig_Zag排列(“Z”字编排),如下图:
这样做的特点就是后面的数据会出现多个0,方便后面的游程长度编码(RLE)。由上图可以看出编码的时候对数据并不是顺序排列的,而是一种类似Z字型排列的,那么在解码的时候对接收到的数据是不可以直接用的,必须把数据还原过来,就是一个对数据重新排列的过程,这是就要用到反量化表,如下图:
由上表可以很清楚的看到数据的排列,对来到的每个数据从表中找到与之对应的位置然后存下即可,再读出的时候一次读出就可以了。
经过分析可以知道:
1:每次来需要等到64个数据全部来齐才可以操作
2:需要一个存储器来保存这64个数据。本设计中使用了2个存储器来是为了提高速度,一个存储器用来接收数据,另个存储器用来输出数据,两个存储器实现循环操纵,如果只用一个存储器操作,则在数据输入的时候,输出必须等待64个数据全部输入完毕,在数据输出的时候出入又必须等待64个数据全部输出结束才可以接受新的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 `timescale 1ps/1ps
2 module zig_zag_mem
3 (
4 clk,
5 rst_n,
6 wr_en,
7 wr_addr,
8 data,
9
10 rd_addr,
11 q
12 );
13
14 input clk;
15 input rst_n;
16
17 input wr_en;
18 input [5:0]wr_addr;
19 input [15:0]data;
20
21 input [5:0]rd_addr;
22 output [15:0]q;
23 //--------------------------------------------
24 reg [15:0]RegData [0:63];
25 always @(posedge clk or negedge rst_n)
26 begin
27 if(!rst_n)
28 begin
29 RegData[0] <= 16'h0000;
30 RegData[1] <= 16'h0000;
31 RegData[2] <= 16'h0000;
32 RegData[3] <= 16'h0000;
33 RegData[4] <= 16'h0000;
34 RegData[5] <= 16'h0000;
35 RegData[6] <= 16'h0000;
36 RegData[7] <= 16'h0000;
37 RegData[8] <= 16'h0000;
38 RegData[9] <= 16'h0000;
39 RegData[10] <= 16'h0000;
40 RegData[11] <= 16'h0000;
41 RegData[12] <= 16'h0000;
42 RegData[13] <= 16'h0000;
43 RegData[14] <= 16'h0000;
44 RegData[15] <= 16'h0000;
45 RegData[16] <= 16'h0000;
46 RegData[17] <= 16'h0000;
47 RegData[18] <= 16'h0000;
48 RegData[19] <= 16'h0000;
49 RegData[20] <= 16'h0000;
50 RegData[21] <= 16'h0000;
51 RegData[22] <= 16'h0000;
52 RegData[23] <= 16'h0000;
53 RegData[24] <= 16'h0000;
54 RegData[25] <= 16'h0000;
55 RegData[26] <= 16'h0000;
56 RegData[27] <= 16'h0000;
57 RegData[28] <= 16'h0000;
58 RegData[29] <= 16'h0000;
59 RegData[30] <= 16'h0000;
60 RegData[31] <= 16'h0000;
61 RegData[32] <= 16'h0000;
62 RegData[33] <= 16'h0000;
63 RegData[34] <= 16'h0000;
64 RegData[35] <= 16'h0000;
65 RegData[36] <= 16'h0000;
66 RegData[37] <= 16'h0000;
67 RegData[38] <= 16'h0000;
68 RegData[39] <= 16'h0000;
69 RegData[40] <= 16'h0000;
70 RegData[41] <= 16'h0000;
71 RegData[42] <= 16'h0000;
72 RegData[43] <= 16'h0000;
73 RegData[44] <= 16'h0000;
74 RegData[45] <= 16'h0000;
75 RegData[46] <= 16'h0000;
76 RegData[47] <= 16'h0000;
77 RegData[48] <= 16'h0000;
78 RegData[49] <= 16'h0000;
79 RegData[50] <= 16'h0000;
80 RegData[51] <= 16'h0000;
81 RegData[52] <= 16'h0000;
82 RegData[53] <= 16'h0000;
83 RegData[54] <= 16'h0000;
84 RegData[55] <= 16'h0000;
85 RegData[56] <= 16'h0000;
86 RegData[57] <= 16'h0000;
87 RegData[58] <= 16'h0000;
88 RegData[59] <= 16'h0000;
89 RegData[60] <= 16'h0000;
90 RegData[61] <= 16'h0000;
91 RegData[62] <= 16'h0000;
92 RegData[63] <= 16'h0000;
93 end
94 else
95 begin
96 if(wr_en == 1'b1)
97 begin
98 RegData[wr_addr] <= data;
99 if(wr_addr == 6'h00)
100 begin
101 RegData[1] <= 16'h0000;
102 RegData[2] <= 16'h0000;
103 RegData[3] <= 16'h0000;
104 RegData[4] <= 16'h0000;
105 RegData[5] <= 16'h0000;
106 RegData[6] <= 16'h0000;
107 RegData[7] <= 16'h0000;
108 RegData[8] <= 16'h0000;
109 RegData[9] <= 16'h0000;
110 RegData[10] <= 16'h0000;
111 RegData[11] <= 16'h0000;
112 RegData[12] <= 16'h0000;
113 RegData[13] <= 16'h0000;
114 RegData[14] <= 16'h0000;
115 RegData[15] <= 16'h0000;
116 RegData[16] <= 16'h0000;
117 RegData[17] <= 16'h0000;
118 RegData[18] <= 16'h0000;
119 RegData[19] <= 16'h0000;
120 RegData[20] <= 16'h0000;
121 RegData[21] <= 16'h0000;
122 RegData[22] <= 16'h0000;
123 RegData[23] <= 16'h0000;
124 RegData[24] <= 16'h0000;
125 RegData[25] <= 16'h0000;
126 RegData[26] <= 16'h0000;
127 RegData[27] <= 16'h0000;
128 RegData[28] <= 16'h0000;
129 RegData[29] <= 16'h0000;
130 RegData[30] <= 16'h0000;
131 RegData[31] <= 16'h0000;
132 RegData[32] <= 16'h0000;
133 RegData[33] <= 16'h0000;
134 RegData[34] <= 16'h0000;
135 RegData[35] <= 16'h0000;
136 RegData[36] <= 16'h0000;
137 RegData[37] <= 16'h0000;
138 RegData[38] <= 16'h0000;
139 RegData[39] <= 16'h0000;
140 RegData[40] <= 16'h0000;
141 RegData[41] <= 16'h0000;
142 RegData[42] <= 16'h0000;
143 RegData[43] <= 16'h0000;
144 RegData[44] <= 16'h0000;
145 RegData[45] <= 16'h0000;
146 RegData[46] <= 16'h0000;
147 RegData[47] <= 16'h0000;
148 RegData[48] <= 16'h0000;
149 RegData[49] <= 16'h0000;
150 RegData[50] <= 16'h0000;
151 RegData[51] <= 16'h0000;
152 RegData[52] <= 16'h0000;
153 RegData[53] <= 16'h0000;
154 RegData[54] <= 16'h0000;
155 RegData[55] <= 16'h0000;
156 RegData[56] <= 16'h0000;
157 RegData[57] <= 16'h0000;
158 RegData[58] <= 16'h0000;
159 RegData[59] <= 16'h0000;
160 RegData[60] <= 16'h0000;
161 RegData[61] <= 16'h0000;
162 RegData[62] <= 16'h0000;
163 RegData[63] <= 16'h0000;
164 end
165 end
166 end
167 end
168
169
170 assign q = RegData [rd_addr];
171 endmodule
这是一个位宽为16位,深度为64的存储器。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 `timescale 1ps / 1ps
2 module zig_zag
3 (
4 clk,
5 rst_n,
6
7 datain_en,
8 datain_addr,
9 zig_zagIDLE,
10 datain,
11
12 unit_en,
13
14 //DataOutOver,
15 dataout_en,
16 zig_dataout
17 );
18
19 input clk;
20 input rst_n;
21
22 input datain_en;
23 input [5:0] datain_addr;
24 input [15:0] datain;
25
26 input unit_en;
27 //input DataOutOver;
28
29 output zig_zagIDLE;
30 output dataout_en;
31 output [11:0] zig_dataout;
32 //-----------------------------------------------------
33 wire [5:0] wr_addr;
34 reg [5:0] rd_addr;
35
36 //ram使能
37 reg wr_ram; //0选择ram0,1选择ram1
38 always @(posedge clk or negedge rst_n) begin
39 if(!rst_n) begin
40 wr_ram <= 1'b0;
41 end else if (unit_en == 1'b1) begin
42 wr_ram <= ~wr_ram;
43 end
44 end
45
46
47 wire wr_ram0;
48 wire wr_ram1;
49 assign wr_ram0 = (datain_en == 1'b1 & wr_ram == 1'b0);
50 assign wr_ram1 = (datain_en == 1'b1 & wr_ram == 1'b1);
51
52
53
54
55 function [5:0] result;
56 input [5:0] count;
57 case(count)
58 6'd0: result = 6'd0;
59 6'd1: result = 6'd1;
60 6'd2: result = 6'd8;
61 6'd3: result = 6'd16;
62 6'd4: result = 6'd9;
63 6'd5: result = 6'd2;
64 6'd6: result = 6'd3;
65 6'd7: result = 6'd10;
66 6'd8: result = 6'd17;
67 6'd9: result = 6'd24;
68 6'd10: result = 6'd32;
69 6'd11: result = 6'd25;
70 6'd12: result = 6'd18;
71 6'd13: result = 6'd11;
72 6'd14: result = 6'd04;
73 6'd15: result = 6'd05;
74 6'd16: result = 6'd12;
75 6'd17: result = 6'd19;
76 6'd18: result = 6'd26;
77 6'd19: result = 6'd33;
78 6'd20: result = 6'd40;
79 6'd21: result = 6'd48;
80 6'd22: result = 6'd41;
81 6'd23: result = 6'd34;
82 6'd24: result = 6'd27;
83 6'd25: result = 6'd20;
84 6'd26: result = 6'd13;
85 6'd27: result = 6'd06;
86 6'd28: result = 6'd07;
87 6'd29: result = 6'd14;
88 6'd30: result = 6'd21;
89 6'd31: result = 6'd28;
90 6'd32: result = 6'd35;
91 6'd33: result = 6'd42;
92 6'd34: result = 6'd49;
93 6'd35: result = 6'd56;
94 6'd36: result = 6'd57;
95 6'd37: result = 6'd50;
96 6'd38: result = 6'd43;
97 6'd39: result = 6'd36;
98 6'd40: result = 6'd29;
99 6'd41: result = 6'd22;
100 6'd42: result = 6'd15;
101 6'd43: result = 6'd23;
102 6'd44: result = 6'd30;
103 6'd45: result = 6'd37;
104 6'd46: result = 6'd44;
105 6'd47: result = 6'd51;
106 6'd48: result = 6'd58;
107 6'd49: result = 6'd59;
108 6'd50: result = 6'd52;
109 6'd51: result = 6'd45;
110 6'd52: result = 6'd38;
111 6'd53: result = 6'd31;
112 6'd54: result = 6'd39;
113 6'd55: result = 6'd46;
114 6'd56: result = 6'd53;
115 6'd57: result = 6'd60;
116 6'd58: result = 6'd61;
117 6'd59: result = 6'd54;
118 6'd60: result = 6'd47;
119 6'd61: result = 6'd55;
120 6'd62: result = 6'd62;
121 6'd63: result = 6'd63;
122 endcase
123 endfunction
124 //读ram选择
125 reg rd_ram;
126 always @(posedge clk or negedge rst_n) begin
127 if(!rst_n) begin
128 rd_ram <= 1'b0;
129 end else if (rd_addr == 6'd63) begin
130 rd_ram <= ~rd_ram;
131 end
132 end
133
134 assign wr_addr = result(datain_addr);
135 wire ram0_release;
136 wire ram1_release;
137 assign ram0_release = (rd_addr == 6'd63 & rd_ram == 1'b0);
138 assign ram1_release = (rd_addr == 6'd63 & rd_ram == 1'b1);
139
140 reg rd_ram0;
141 reg rd_ram1;
142
143 always @(posedge clk or negedge rst_n) begin
144 if(!rst_n)
145 begin
146 rd_ram0= 1'b0;
147 rd_ram1= 1'b0;
148 end
149 else
150 begin
151 if(rd_ram0 == 1'b0 & wr_ram == 1'b0)
152 begin
153 if(unit_en == 1'b1 & zig_zagIDLE == 1'b1)
154 rd_ram0 = 1'b1;
155 end
156 else
157 if(ram0_release == 1'b1)
158 rd_ram0 = 1'b0;
159 if(rd_ram1 == 1'b0 & wr_ram== 1'b1)
160 begin
161 if(unit_en == 1'b1 & zig_zagIDLE == 1'b1)
162 rd_ram1 = 1'b1;
163 end
164 else
165 if(ram1_release== 1'b1)
166 rd_ram1 = 1'b0;
167 end
168 end
169
170 //产生读地址
171 always @(posedge clk or negedge rst_n)
172 begin
173 if(!rst_n)
174 begin
175 rd_addr <= 6'd0;
176 end
177 else
178 begin
179 if (dataout_en == 1'b1)
180 begin
181 if (rd_addr == 6'd63)
182 begin
183 rd_addr <= 6'd0;
184 end
185 rd_addr <= rd_addr + 6'd1;
186 end
187 end
188 end
189
190
191
192
193
194
195 wire [11:0]q0;
196 wire [11:0]q1;
197 zig_zag_mem m1(
198 .clk ( clk ),
199 .rst_n ( rst_n ),
200 .wr_en ( wr_ram0 ),
201 .wr_addr( wr_addr ),
202 .data ( datain ),
203 .rd_addr( rd_addr ),
204 .q ( q0 )
205 );
206
207 zig_zag_mem m2(
208 .clk ( clk ),
209 .rst_n ( rst_n ),
210 .wr_en ( wr_ram1 ),
211 .wr_addr ( wr_addr ),
212 .data ( datain ),
213 .rd_addr ( rd_addr ),
214 .q (q1 )
215 );
216
217
218 assign zig_zagIDLE = rd_ram0 == 1'b0 | rd_ram1 == 1'b0;
219 assign dataout_en = rd_ram0 == 1'b1 | rd_ram1 == 1'b1 ;
220 assign zig_dataout = (rd_ram)?q1[11:0]:q0[11:0];
221
222 endmodule
这是Z变换的顶层模块,
36-50行是定义连个ram使能进行循环操作,unit_en信号是huffman解码输出信号,高表示解码到64的数据,然后存储器转换。
55-123行定义一个functiom,他的作用是对于输入的每个数据按照反Zig表分别计算出需要存储器的地址。
124-169行是进行读取不同的ram的设置。
170-188行是产生读地址,0-63循环操作。
195-216行是例化2个存储器。
218行是当两个ram都为空闲状态时,向huffman解码模块发出读取数据请求。
219行是产生输出使能。
220行是对输出有效数据的选择。
到这里反Z变换已经结束,接下来将讨论IDCT模块,IDCT变换模块比较灵活,方法很多种,可优化的地方也很多,由于本人水平有限,现在只先讨论一种比较简单直接的没有任何优化的IDCT变换模块。