This commit is contained in:
WangXuan95 2022-04-02 19:45:58 +08:00
parent e51166ce33
commit 432e4d0440
9 changed files with 194 additions and 224 deletions

View File

@ -10,7 +10,7 @@ Hard-PNG
| ![diagram](./figures/diagram.png) | | ![diagram](./figures/diagram.png) |
| :----: | | :----: |
| 图1 : Hard-PNG 原理框图 | | **图1** : Hard-PNG 原理框图 |
@ -34,37 +34,39 @@ png 图像文件的扩展名为 .png 。以本库中的 SIM/test_image/img01.png
# 使用 Hard-PNG # 使用 Hard-PNG
RTL 目录中的 hard_png.sv 是一个能够输入 png 码流输出解压后的像素的模块它的接口如图2所示。 RTL 目录中的 hard_png.sv 是一个能够输入 png 码流,输出解压后的像素的模块,它的接口如**图2**所示。
| ![接口图](./figures/interface.png) | | ![接口图](./figures/interface.png) |
| :----: | | :----: |
| 图2 : hard_png 接口图 | | **图2** : hard_png 接口图 |
hard_png 的使用方法很简单,在输入一张 png 图像的码流前,先要给模块复位(令 rstn=0 至少一个时钟周期),然后解除复位(令 rstn=1然后输入 png 码流,并从图象基本信息输出接口和像素输出接口中得到解码结果。 ## 输入码流
以 SIM/test_image/img01.png 为例我们应该以图3的时序把 png 码流中的98个字节逐一输入到 hard_png 中。其中 ivalid 和 iready 构成了握手信号: ivalid=1 时说明外部想发送一个字节给 hard_png。iready=1 时说明 hard_png 已经准备好接收一个字节。只有 ivalid 和 iready 同时=1 时ibyte 才被成功的输入 hard_png 中。 hard_png 的使用方法很简单,以 SIM/test_image/img01.png 这张图像为例,如**图3**,在输入一张图象的码流前,先要令 istart 上产生一个高电平脉冲(宽度至少为一个时钟周期),然后通过 ivalid 和 ibyte 信号来输入码流(这张图象的 png 码流有 98 字节,这 98 字节都要逐一输入给 hard_png其中 ivalid 和 iready 构成了握手信号: ivalid=1 时说明外部想发送一个字节给 hard_png。iready=1 时说明 hard_png 已经准备好接收一个字节。只有 ivalid 和 iready 同时=1 时握手才成功ibyte 才被成功的输入 hard_png 中。
| ![输入时序图](./figures/wave1.png) | | ![输入时序图](./figures/wave1.png) |
| :----: | | :----: |
| 图3 : hard_png 的输入波形图 | | **图3** : hard_png 的输入波形图 |
在输入的同时解压结果从模块中输出如图4。在一帧图象输出前newframe 信号会出现一个时钟周期的高电平脉冲,同时 colortype, width, height 有效。其中: 当一张 png 图象的码流输入结束后,可以立即或稍后输入下一张图像(也就是让 istart 上产生高电平脉冲,然后输入码流)。
- width, height 分别为图象的宽度和高度 ## 输出图像信息和像素
- colortype 为 png 图像的颜色类型,含义如下表。
| colortype | 3'd0 | 3'd1 | 3'd2 | 3'd3 | 3d4 | 在输入码流的同时,这张图象的解压结果(也就是图像基本信息和原始像素)会从模块中输出,如**图4**在图象的像素输出前ovalid 信号会出现一个时钟周期的高电平脉冲,同时 colortype, width, height 会有效。其中:
- width, height 分别是图象的宽度和高度
- colortype 是 png 图像的颜色类型,含义如下表。
| colortype 值 | 3'd0 | 3'd1 | 3'd2 | 3'd3 | 3d4 |
| :-------: | :--: | :--: | :--: | :--: | :--: | | :-------: | :--: | :--: | :--: | :--: | :--: |
| 颜色类型 | 灰度 | 灰度+A | RGB | RGB+A | 索引RGB | | 颜色类型 | 灰度 | 灰度+A | RGB | RGB+A | 索引RGB |
| 备注 | R=G=BA=0xFF | R=G=B≠A | R≠G≠BA=0xFF | R≠G≠B≠A | R≠G≠BA=0xFF | | 备注 | R=G=BA=0xFF | R=G=B≠A | R≠G≠BA=0xFF | R≠G≠B≠A | R≠G≠BA=0xFF |
然后ovalid=1 代表该时钟周期有一个像素输出,该像素的 R,G,B,A 通道分别出现在 opixelr,opixelg,opixelb,opixela 信号上。 然后ovalid=1 代表该时钟周期有一个像素输出,该像素的 R,G,B,A 通道分别出现在 opixelr,opixelg,opixelb,opixela 信号上。
| ![输出时序图](./figures/wave2.png) | | ![输出时序图](./figures/wave2.png) |
| :----: | | :----: |
| 图4 : hard_png 的输出波形图 | | **图4** : hard_png 的输出波形图 |
当一个 png 图象输入结束后,可以立即或稍后输入下一张图像(复位->解除复位->输入码流)。
@ -79,7 +81,7 @@ hard_png 的使用方法很简单,在输入一张 png 图像的码流前,先
使用 iverilog 进行仿真前,需要安装 iverilog ,见:[iverilog_usage](https://github.com/WangXuan95/WangXuan95/blob/main/iverilog_usage/iverilog_usage.md) 使用 iverilog 进行仿真前,需要安装 iverilog ,见:[iverilog_usage](https://github.com/WangXuan95/WangXuan95/blob/main/iverilog_usage/iverilog_usage.md)
然后双击 tb_hard_png_run_iverilog.bat 运行仿真,会运行大约半小时(可以中途强制关闭,但产生的仿真波形就是不全的)。 然后双击 tb_hard_png_run_iverilog.bat 即可运行仿真,会运行大约半小时(可以中途强制关闭,但产生的仿真波形就是不全的)。
仿真运行完后,可以打开生成的 dump.vcd 文件查看波形。 仿真运行完后,可以打开生成的 dump.vcd 文件查看波形。
@ -120,18 +122,19 @@ total 400 pixels validation successful!!
| FPGA 型号 | LUT | LUT(%) | FF | FF(%) | Logic | Logic(%) | BRAM | BRAM(%) | | FPGA 型号 | LUT | LUT(%) | FF | FF(%) | Logic | Logic(%) | BRAM | BRAM(%) |
| :----------------------------: | :--: | :----: | :--: | :---: | :---: | :------: | :-----: | :-----: | | :----------------------------: | :--: | :----: | :--: | :---: | :---: | :------: | :-----: | :-----: |
| Xilinx Artix-7 XC7A35T | 2581 | 13% | 2253 | 5% | - | - | 792kbit | 44% | | Xilinx Artix-7 XC7A35T | 2581 | 13% | 2253 | 5% | - | - | 792kbit | 44% |
| Altera Cyclone IV EP4CE40F23C6 | - | - | - | - | 4551 | 11% | 427kbit | 37% | | Altera Cyclone IV EP4CE40F23C6 | - | - | - | - | 4682 | 11% | 427kbit | 37% |
## 性能 ## 性能
在 Altera Cyclone IV EP4CE40F23C6 上部署 hard_png ,时钟频率= 50MHz (正好时序收敛)。根据仿真时每个图像消耗的时钟周期数,可以算出压缩图像时的性能,举例如下表。 在 Altera Cyclone IV EP4CE40F23C6 上部署 hard_png ,时钟频率= 50MHz (正好时序收敛)。根据仿真时每个图像消耗的时钟周期数,可以算出压缩图像时的性能,举例如下表。
| png文件名 | 颜色类型 | 图象长宽 | png 码流大小 (字节) | 消耗的时钟周期数 | 消耗时间 | | 文件名 | 颜色类型 | 图象长宽 | 像素数 | png 码流大小 (字节) | 时钟周期数 | 消耗时间 |
| :-----------: | :----------: | :----------: | :--------------: | :---------------: | :---------------: | | :-----------: | :----------: | :----------: | :--------------: | :---------------: | :---------------: | ------------- |
| img05.png | RGB | 300x256 | 96536 | 1105702 | 23ms | | img05.png | RGB | 300x256 | 76800 | 96536 | 1105702 | 23ms |
| img06.png | 灰度 | 300x263 | 37283 | 395335 | 8ms | | img06.png | 灰度 | 300x263 | 78900 | 37283 | 395335 | 8ms |
| img10.png | 索引RGB | 631x742 | 193489 | 2374224 | 48ms | | img09.png | RGBA | 300x263 | 78900 | 125218 | 1382303 | 28ms |
| img14.png | 索引RGB | 1920x1080 | 818885 | 10177644 | 204ms | | img10.png | 索引RGB | 631x742 | 468202 | 193489 | 2374224 | 48ms |
| img14.png | 索引RGB | 1920x1080 | 2073600 | 818885 | 10177644 | 204ms |

View File

@ -10,11 +10,12 @@ module hard_png (
input wire rstn, input wire rstn,
input wire clk, input wire clk,
// png data input stream // png data input stream
input wire istart,
input wire ivalid, input wire ivalid,
output reg iready, output reg iready,
input wire [ 7:0] ibyte, input wire [ 7:0] ibyte,
// image frame configuration output // image frame configuration output
output reg newframe, output reg ostart,
output wire [ 2:0] colortype, // 0:gray 1:gray+A 2:RGB 3:RGBA 4:RGB-plte output wire [ 2:0] colortype, // 0:gray 1:gray+A 2:RGB 3:RGBA 4:RGB-plte
output wire [13:0] width, // image width output wire [13:0] width, // image width
output wire [31:0] height, // image height output wire [31:0] height, // image height
@ -23,11 +24,9 @@ module hard_png (
output wire [ 7:0] opixelr, opixelg, opixelb, opixela output wire [ 7:0] opixelr, opixelg, opixelb, opixela
); );
initial newframe = 1'b0; initial ostart = 1'b0;
initial ovalid = 1'b0; initial ovalid = 1'b0;
reg imagevalid = '0;
reg isplte = '0; reg isplte = '0;
reg [ 1:0] bpp = '0; // bytes per pixel reg [ 1:0] bpp = '0; // bytes per pixel
@ -88,7 +87,9 @@ generate genvar ii;
if(~rstn) if(~rstn)
latchbytes[ii] <= '0; latchbytes[ii] <= '0;
else begin else begin
if(ivalid) if(istart)
latchbytes[ii] <= '0;
else if(ivalid)
latchbytes[ii] <= lastbytes[ii+1]; latchbytes[ii] <= lastbytes[ii+1];
end end
end end
@ -134,7 +135,7 @@ wire parametervalid = ( lastbytes[7]==8'h0 &&
); );
always_comb always_comb
if(imagevalid && cnt>0 && curr_name==IDAT && gapcnt==2'd0) begin if(cnt>0 && curr_name==IDAT && gapcnt==2'd0) begin
iready = pready; iready = pready;
pvalid = ivalid; pvalid = ivalid;
pbyte = ibyte; pbyte = ibyte;
@ -152,7 +153,6 @@ always @ (posedge clk or negedge rstn)
gapcnt <= '0; gapcnt <= '0;
busy <= 1'b0; busy <= 1'b0;
sizevalid <= 1'b0; sizevalid <= 1'b0;
imagevalid <= 1'b0;
curr_name <= NONE; curr_name <= NONE;
ispltetmp <= 1'b0; ispltetmp <= 1'b0;
bpptmp <= '0; bpptmp <= '0;
@ -164,18 +164,38 @@ always @ (posedge clk or negedge rstn)
ppr <= '0; ppr <= '0;
bpr <= '0; bpr <= '0;
rpf <= '0; rpf <= '0;
newframe <= 1'b0; ostart <= 1'b0;
plte_wen <= 1'b0; plte_wen <= 1'b0;
plte_waddr <= '0; plte_waddr <= '0;
plte_wdata <= '0; plte_wdata <= '0;
plte_bytecnt <= '0; plte_bytecnt <= '0;
plte_pixcnt <= '0; plte_pixcnt <= '0;
end else begin end else begin
newframe <= 1'b0; ostart <= 1'b0;
plte_wen <= 1'b0; plte_wen <= 1'b0;
plte_waddr <= '0; plte_waddr <= '0;
plte_wdata <= '0; plte_wdata <= '0;
if(ivalid) begin if(istart) begin
bcnt <= '0;
cnt <= '0;
crccnt <= '0;
gapcnt <= '0;
busy <= 1'b0;
sizevalid <= 1'b0;
curr_name <= NONE;
ispltetmp <= 1'b0;
bpptmp <= '0;
pprtmp <= '0;
bprtmp <= '0;
rpftmp <= '0;
isplte <= 1'b0;
bpp <= '0;
ppr <= '0;
bpr <= '0;
rpf <= '0;
plte_bytecnt <= '0;
plte_pixcnt <= '0;
end else if(ivalid) begin
plte_bytecnt <= '0; plte_bytecnt <= '0;
plte_pixcnt <= '0; plte_pixcnt <= '0;
if(~busy) begin if(~busy) begin
@ -190,7 +210,6 @@ always @ (posedge clk or negedge rstn)
cnt <= cnt - 1; cnt <= cnt - 1;
gapcnt <= 2'd2; gapcnt <= 2'd2;
if(cnt==6) begin if(cnt==6) begin
imagevalid <= 1'b0;
rpftmp <= l32bit; rpftmp <= l32bit;
if(h32bit[31:14]=='0) begin if(h32bit[31:14]=='0) begin
sizevalid <= 1'b1; sizevalid <= 1'b1;
@ -211,15 +230,13 @@ always @ (posedge clk or negedge rstn)
endcase endcase
end else if(cnt==1) begin end else if(cnt==1) begin
if(sizevalid && parametervalid && (bprtmp[15:14]==2'd0)) begin if(sizevalid && parametervalid && (bprtmp[15:14]==2'd0)) begin
newframe <= 1'b1; ostart <= 1'b1;
imagevalid <= 1'b1;
isplte <= ispltetmp; isplte <= ispltetmp;
bpp <= bpptmp; bpp <= bpptmp;
ppr <= pprtmp; ppr <= pprtmp;
bpr <= bprtmp[13:0]; bpr <= bprtmp[13:0];
rpf <= rpftmp; rpf <= rpftmp;
end else begin end else begin
imagevalid <= 1'b0;
isplte <= 1'b0; isplte <= 1'b0;
bpp <= '0; bpp <= '0;
ppr <= '0; ppr <= '0;
@ -230,7 +247,7 @@ always @ (posedge clk or negedge rstn)
end else if(curr_name==IDAT) begin end else if(curr_name==IDAT) begin
if(gapcnt>2'd0) if(gapcnt>2'd0)
gapcnt <= gapcnt - 2'd1; gapcnt <= gapcnt - 2'd1;
if(imagevalid && gapcnt==2'd0) begin if(gapcnt==2'd0) begin
if(pready) if(pready)
cnt <= cnt - 1; cnt <= cnt - 1;
end else begin end else begin
@ -291,36 +308,26 @@ always @ (posedge clk or negedge rstn)
// uz_inflate // uz_inflate
//----------------------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------------------
reg end_stream = '0; reg end_stream = '0;
wire huffman_ovalid; wire huffman_ovalid;
wire [7:0] huffman_obyte; wire [7:0] huffman_obyte;
reg raw_ovalid;
reg [7:0] raw_obyte;
reg raw_mode = 1'b0;
reg raw_format = '0;
reg [ 2:0] status = '0;
reg [15:0] rcnt = '0;
reg [ 2:0] uz_cnt = '0; reg [ 2:0] uz_cnt = '0;
reg [ 7:0] rbyte = '0; reg [ 7:0] rbyte = '0;
reg tvalid; reg tvalid;
wire tready; wire tready;
reg tbit; reg tbit;
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
mvalid <= 1'b0; mvalid <= 1'b0;
mbyte <= '0; mbyte <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
mvalid <= 1'b0; mvalid <= 1'b0;
mbyte <= '0; mbyte <= '0;
end else if(raw_mode) begin
mvalid <= raw_ovalid;
mbyte <= raw_obyte;
end else begin end else begin
mvalid <= huffman_ovalid; mvalid <= huffman_ovalid;
mbyte <= huffman_obyte; mbyte <= huffman_obyte;
@ -328,98 +335,33 @@ always @ (posedge clk or negedge rstn)
end end
always_comb always_comb
if(~imagevalid) begin if(uz_cnt==3'h0) begin
raw_ovalid = 1'b0; pready = tready;
raw_obyte = '0; tvalid = pvalid;
pready = 1'b0; tbit = pbyte[0];
tvalid = 1'b0;
tbit = 1'b0;
end else begin end else begin
raw_ovalid = 1'b0; pready = 1'b0;
raw_obyte = '0; tvalid = 1'b1;
if(raw_mode) begin tbit = rbyte[uz_cnt];
pready = 1'b1;
tvalid = 1'b0;
tbit = 1'b0;
if(status>=3) begin
raw_ovalid = pvalid;
raw_obyte = pbyte;
end
end if(raw_format) begin
pready = 1'b1;
tvalid = 1'b0;
tbit = 1'b0;
end else if(uz_cnt==3'h0) begin
pready = tready;
tvalid = pvalid;
tbit = pbyte[0];
end else begin
pready = 1'b0;
tvalid = 1'b1;
tbit = rbyte[uz_cnt];
end
end end
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
raw_mode <= 1'b0;
uz_cnt <= '0; uz_cnt <= '0;
rbyte <= '0; rbyte <= '0;
rcnt <= '0;
status <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
raw_mode <= 1'b0;
uz_cnt <= '0; uz_cnt <= '0;
rbyte <= '0; rbyte <= '0;
rcnt <= '0;
status <= '0;
end else if(raw_mode) begin
uz_cnt <= '0;
rbyte <= '0;
if(pvalid) begin
if (status==0) begin
rcnt[15:8] <= pbyte;
status <= status + 3'h1;
end else if(status==1) begin
status <= status + 3'h1;
end else if(status==2) begin
if(rcnt>0) begin
rcnt <= rcnt - 16'd1;
status <= status + 3'h1;
end else begin
raw_mode <= 1'b0;
status <= '0;
end
end else begin
if(rcnt>0) begin
rcnt <= rcnt - 16'd1;
end else begin
raw_mode <= 1'b0;
status <= '0;
end
end
end
end else begin end else begin
rcnt <= '0; if(uz_cnt==3'h0) begin
status <= '0; if(pvalid & tready) begin
if(raw_format) begin uz_cnt <= uz_cnt + 3'h1;
if(pvalid) begin rbyte <= pbyte;
raw_mode <= 1'b1;
rcnt[ 7:0] <= pbyte;
end end
uz_cnt <= '0;
rbyte <= '0;
end else begin end else begin
if(uz_cnt==3'h0) begin if(tready)
if(pvalid & tready) begin uz_cnt <= uz_cnt + 3'h1;
uz_cnt <= uz_cnt + 3'h1;
rbyte <= pbyte;
end
end else begin
if(tready)
uz_cnt <= uz_cnt + 3'h1;
end
end end
end end
end end
@ -440,8 +382,6 @@ reg srepeat = 1'b0;
reg symbol_valid = 1'b0; reg symbol_valid = 1'b0;
reg [7:0] symbol = '0; reg [7:0] symbol = '0;
reg decoder_new = 1'b1;
reg [ 1:0] iword = '0; reg [ 1:0] iword = '0;
reg [ 1:0] ibcnt = '0; reg [ 1:0] ibcnt = '0;
reg [ 4:0] precode_wpt = '0; reg [ 4:0] precode_wpt = '0;
@ -484,14 +424,14 @@ reg [ 3:0] dscnt=4'h0, dsmax=4'h0;
enum {T, D, R, S} huffman_status = T; enum {T, D, R, S} huffman_status = T;
wire lentree_ien = ~end_stream & ~raw_format & tvalid & lentree_done & ~lentree_codeen & (repeat_mode==REPEAT_NONE && repeat_len==8'd0) & (tree_wpt<hmax); wire lentree_ien = ~end_stream & tvalid & lentree_done & ~lentree_codeen & (repeat_mode==REPEAT_NONE && repeat_len==8'd0) & (tree_wpt<hmax);
wire codetree_ien = ~end_stream & ~raw_format & tvalid & tree_done & ~codetree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==T); wire codetree_ien = ~end_stream & tvalid & tree_done & ~codetree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==T);
wire distree_ien = ~end_stream & ~raw_format & tvalid & tree_done & ~distree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==D); wire distree_ien = ~end_stream & tvalid & tree_done & ~distree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==D);
assign tready = end_stream | (~raw_format & ( assign tready = end_stream | & (
( precode_wpt<5'd17 || lentree_wpt<hclen ) | ( precode_wpt<5'd17 || lentree_wpt<hclen ) |
( lentree_done & ~lentree_codeen & ((repeat_mode==REPEAT_NONE && repeat_len==8'd0) | repeat_code_pt>3'd0) & (tree_wpt<hmax) ) | ( lentree_done & ~lentree_codeen & ((repeat_mode==REPEAT_NONE && repeat_len==8'd0) | repeat_code_pt>3'd0) & (tree_wpt<hmax) ) |
( tree_done & ~codetree_codeen & ~distree_codeen & (huffman_status==T || huffman_status==D || (huffman_status==R && dscnt>4'd0)) ) ) ); ( tree_done & ~codetree_codeen & ~distree_codeen & (huffman_status==T || huffman_status==D || (huffman_status==R && dscnt>4'd0)) ) );
reg [ 8:0] lengthb= '0; reg [ 8:0] lengthb= '0;
reg [ 5:0] lengthe= '0; reg [ 5:0] lengthe= '0;
@ -575,20 +515,17 @@ endtask
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
{raw_format, end_stream} <= '0; end_stream <= '0;
decoder_new <= 1'b1;
reset_all_regs; reset_all_regs;
end else begin end else begin
if(raw_mode) begin if(istart) begin
{raw_format, end_stream} <= '0; end_stream <= '0;
decoder_new <= 1'b1;
reset_all_regs; reset_all_regs;
end else begin end else begin
symbol_valid <= 1'b0; symbol_valid <= 1'b0;
symbol <= '0; symbol <= '0;
irepeat <= 1'b0; irepeat <= 1'b0;
srepeat <= 1'b0; srepeat <= 1'b0;
decoder_new <= 1'b0;
lentree_write(); lentree_write();
codetree_write(); codetree_write();
distree_write(); distree_write();
@ -602,16 +539,12 @@ always @ (posedge clk or negedge rstn)
end else if(precode_wpt==1) begin end else if(precode_wpt==1) begin
bfix <= tbit; bfix <= tbit;
end else begin end else begin
case({tbit,bfix}) if( {tbit,bfix} == 2'b01 ) begin
2'b00 :
raw_format <= 1'b1;
2'b01 : begin
precode_wpt <= '1; precode_wpt <= '1;
lentree_wpt <= '1; lentree_wpt <= '1;
tree_wpt <= '1; tree_wpt <= '1;
fixed_tree <= 1'b1; fixed_tree <= 1'b1;
end end
endcase
end end
end end
end else if(precode_wpt<17) begin end else if(precode_wpt<17) begin
@ -777,6 +710,7 @@ huffman_builder #(
) lentree_builder ( ) lentree_builder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.istart ( istart ),
.wren ( lentree_wen ), .wren ( lentree_wen ),
.wraddr ( lentree_waddr ), .wraddr ( lentree_waddr ),
.wrdata ( lentree_wdata ), .wrdata ( lentree_wdata ),
@ -796,7 +730,7 @@ huffman_decoder #(
) lentree_decoder ( ) lentree_decoder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.inew ( decoder_new ), .istart ( istart ),
.ien ( lentree_ien ), .ien ( lentree_ien ),
.ibit ( tbit ), .ibit ( tbit ),
.oen ( lentree_codeen ), .oen ( lentree_codeen ),
@ -817,6 +751,7 @@ huffman_builder #(
) codetree_builder ( ) codetree_builder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.istart ( istart ),
.wren ( codetree_wen ), .wren ( codetree_wen ),
.wraddr ( codetree_waddr ), .wraddr ( codetree_waddr ),
.wrdata ( (5)'(codetree_wdata) ), .wrdata ( (5)'(codetree_wdata) ),
@ -844,7 +779,7 @@ huffman_decoder #(
) codetree_decoder ( ) codetree_decoder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.inew ( decoder_new ), .istart ( istart ),
.ien ( codetree_ien ), .ien ( codetree_ien ),
.ibit ( tbit ), .ibit ( tbit ),
.oen ( codetree_codeen), .oen ( codetree_codeen),
@ -865,9 +800,10 @@ huffman_builder #(
) distree_builder ( ) distree_builder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.istart ( istart ),
.wren ( distree_wen ), .wren ( distree_wen ),
.wraddr ( distree_waddr ), .wraddr ( distree_waddr ),
.wrdata ( (5)'(distree_wdata) ), .wrdata ( (5)'(distree_wdata) ),
.run ( tree_run ), .run ( tree_run ),
.done ( distree_done ), .done ( distree_done ),
.rdaddr ( distree_raddr ), .rdaddr ( distree_raddr ),
@ -892,7 +828,7 @@ huffman_decoder #(
) distree_decoder ( ) distree_decoder (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
.inew ( decoder_new ), .istart ( istart ),
.ien ( distree_ien ), .ien ( distree_ien ),
.ibit ( tbit ), .ibit ( tbit ),
.oen ( distree_codeen ), .oen ( distree_codeen ),
@ -923,7 +859,10 @@ always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
wptr <= '0; wptr <= '0;
else begin else begin
if(huffman_ovalid) wptr <= (wptr<(REPEAT_BUFFER_MAXLEN-16'd1)) ? wptr+16'd1 : '0; if(istart)
wptr <= '0;
else if(huffman_ovalid)
wptr <= (wptr<(REPEAT_BUFFER_MAXLEN-16'd1)) ? wptr+16'd1 : '0;
end end
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
@ -932,7 +871,11 @@ always @ (posedge clk or negedge rstn)
sptr <= '0; sptr <= '0;
eptr <= '0; eptr <= '0;
end else begin end else begin
if(srepeat) begin if(istart) begin
rptr <= '0;
sptr <= '0;
eptr <= '0;
end else if(srepeat) begin
rptr <= sptrw; rptr <= sptrw;
sptr <= sptrw; sptr <= sptrw;
eptr <= eptrw; eptr <= eptrw;
@ -948,7 +891,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
repeat_valid <= '0; repeat_valid <= '0;
else else
repeat_valid <= irepeat; repeat_valid <= istart ? '0 : irepeat;
reg [7:0] mem_repeat_buffer [REPEAT_BUFFER_MAXLEN]; reg [7:0] mem_repeat_buffer [REPEAT_BUFFER_MAXLEN];
@ -996,7 +939,7 @@ always @ (posedge clk or negedge rstn)
nfirstrow <= 1'b0; nfirstrow <= 1'b0;
col <= '0; col <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
nfirstrow <= 1'b0; nfirstrow <= 1'b0;
col <= '0; col <= '0;
end else if(mvalid) begin end else if(mvalid) begin
@ -1013,9 +956,9 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
mode <= '0; mode <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart)
mode <= '0; mode <= '0;
end else if(mvalid && col==14'h0) else if(mvalid && col==14'h0)
mode <= mbyte[2:0]; mode <= mbyte[2:0];
end end
@ -1027,7 +970,7 @@ always_comb
3'd3 : fdata = mbyte + SSdata[8:1]; 3'd3 : fdata = mbyte + SSdata[8:1];
default: fdata = mbyte + paeth( (nfirstcol ? LLdata : 8'h0), default: fdata = mbyte + paeth( (nfirstcol ? LLdata : 8'h0),
(nfirstrow ? UUdata : 8'h0), (nfirstrow ? UUdata : 8'h0),
(nfirstrow&nfirstcol ? ULdata : 8'h0) ); (nfirstrow & nfirstcol ? ULdata : 8'h0) );
endcase endcase
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
@ -1035,7 +978,7 @@ always @ (posedge clk or negedge rstn)
bvalid <= 1'b0; bvalid <= 1'b0;
bbyte <= '0; bbyte <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
bvalid <= 1'b0; bvalid <= 1'b0;
bbyte <= '0; bbyte <= '0;
end else begin end else begin
@ -1052,7 +995,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
mem_sr_currline[0] <= '0; mem_sr_currline[0] <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
mem_sr_currline[0] <= '0; mem_sr_currline[0] <= '0;
end else if(mvalid) end else if(mvalid)
mem_sr_currline[0] <= fdata; mem_sr_currline[0] <= fdata;
@ -1063,7 +1006,7 @@ generate genvar isrcl;
if(~rstn) begin if(~rstn) begin
mem_sr_currline[isrcl+1] <= '0; mem_sr_currline[isrcl+1] <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
mem_sr_currline[isrcl+1] <= '0; mem_sr_currline[isrcl+1] <= '0;
end else if(mvalid) end else if(mvalid)
mem_sr_currline[isrcl+1] <= mem_sr_currline[isrcl]; mem_sr_currline[isrcl+1] <= mem_sr_currline[isrcl];
@ -1080,7 +1023,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
mem_sr_prevline[0] <= '0; mem_sr_prevline[0] <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
mem_sr_prevline[0] <= '0; mem_sr_prevline[0] <= '0;
end else if(mvalid) end else if(mvalid)
mem_sr_prevline[0] <= UUdata; mem_sr_prevline[0] <= UUdata;
@ -1091,7 +1034,7 @@ generate genvar isrpl;
if(~rstn) begin if(~rstn) begin
mem_sr_prevline[isrpl+1] <= '0; mem_sr_prevline[isrpl+1] <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
mem_sr_prevline[isrpl+1] <= '0; mem_sr_prevline[isrpl+1] <= '0;
end else if(mvalid) end else if(mvalid)
mem_sr_prevline[isrpl+1] <= mem_sr_prevline[isrpl]; mem_sr_prevline[isrpl+1] <= mem_sr_prevline[isrpl];
@ -1111,7 +1054,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
sb_lidata <= '0; sb_lidata <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
sb_lidata <= '0; sb_lidata <= '0;
end else if(mvalid) end else if(mvalid)
sb_lidata <= fdata; sb_lidata <= fdata;
@ -1121,7 +1064,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
sb_ptr <= '0; sb_ptr <= '0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
sb_ptr <= '0; sb_ptr <= '0;
end else if(mvalid) begin end else if(mvalid) begin
if(sb_ptr < (bpr-14'd1)) if(sb_ptr < (bpr-14'd1))
@ -1136,7 +1079,7 @@ always @ (posedge clk or negedge rstn)
sb_ldata <= '0; sb_ldata <= '0;
sb_rvalid <= 1'b0; sb_rvalid <= 1'b0;
end else begin end else begin
if(~imagevalid) begin if(istart) begin
sb_ldata <= '0; sb_ldata <= '0;
sb_rvalid <= 1'b0; sb_rvalid <= 1'b0;
end else begin end else begin
@ -1177,7 +1120,7 @@ always @ (posedge clk or negedge rstn)
{pr, pg, pb, pa} <= 0; {pr, pg, pb, pa} <= 0;
end else begin end else begin
ovalid <= 1'b0; ovalid <= 1'b0;
if(newframe) begin if(istart | ostart) begin
pixcnt <= '0; pixcnt <= '0;
{pr, pg, pb, pa} <= 0; {pr, pg, pb, pa} <= 0;
end else if(bvalid) begin end else if(bvalid) begin

View File

@ -12,6 +12,7 @@ module huffman_builder #(
parameter OUTWIDTH = 10 parameter OUTWIDTH = 10
) ( ) (
rstn, clk, rstn, clk,
istart,
wren, wraddr, wrdata, wren, wraddr, wrdata,
run , done, run , done,
rdaddr, rddata rdaddr, rddata
@ -25,6 +26,7 @@ endfunction
input rstn; input rstn;
input clk; input clk;
input istart;
input wren; input wren;
input [ clogb2(NUMCODES-1)-1:0] wraddr; input [ clogb2(NUMCODES-1)-1:0] wraddr;
input [ CODEBITS -1:0] wrdata; input [ CODEBITS -1:0] wrdata;
@ -33,18 +35,19 @@ output done;
input [clogb2(2*NUMCODES-1)-1:0] rdaddr; input [clogb2(2*NUMCODES-1)-1:0] rdaddr;
output [ OUTWIDTH-1:0] rddata; output [ OUTWIDTH-1:0] rddata;
wire rstn; wire rstn;
wire clk; wire clk;
wire wren; wire istart;
wire [ clogb2(NUMCODES-1)-1:0] wraddr; wire wren;
wire [ CODEBITS -1:0] wrdata; wire [ clogb2(NUMCODES-1)-1:0] wraddr;
wire run; wire [ CODEBITS -1:0] wrdata;
wire done; wire run;
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr; wire done;
reg [ OUTWIDTH-1:0] rddata; wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
reg [ OUTWIDTH-1:0] rddata;
reg [clogb2(NUMCODES)-1:0] blcount [BITLENGTH]; reg [clogb2(NUMCODES)-1:0] blcount [BITLENGTH];
reg [ (1<<CODEBITS)-1:0] nextcode [BITLENGTH+1]; reg [ (1<<CODEBITS)-1:0] nextcode [BITLENGTH+1];
initial for(int i=0; i< BITLENGTH; i++) blcount[i] = '0; initial for(int i=0; i< BITLENGTH; i++) blcount[i] = '0;
initial for(int i=0; i<=BITLENGTH; i++) nextcode[i] = '0; initial for(int i=0; i<=BITLENGTH; i++) nextcode[i] = '0;
@ -77,18 +80,29 @@ always @ (posedge clk or negedge rstn)
lii <= '0; lii <= '0;
lnn <= '0; lnn <= '0;
end else begin end else begin
valid <= build_tree2d & nn<NUMCODES & blen>0; if(istart) begin
treepos <= ntreepos; valid <= '0;
tpos <= ntpos; treepos <= '0;
lii <= ii; tpos <= '0;
lnn <= nn; lii <= '0;
lnn <= '0;
end else begin
valid <= build_tree2d & nn<NUMCODES & blen>0;
treepos <= ntreepos;
tpos <= ntpos;
lii <= ii;
lnn <= nn;
end
end end
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
blen <= '0; blen <= '0;
else begin else begin
if(islast) blen <= blenn; if(istart)
blen <= '0;
else if(islast)
blen <= blenn;
end end
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
@ -96,7 +110,7 @@ always @ (posedge clk or negedge rstn)
for(int i=0; i<BITLENGTH; i++) for(int i=0; i<BITLENGTH; i++)
blcount[i] <= '0; blcount[i] <= '0;
end else begin end else begin
if(done) begin if(istart | done) begin
for(int i=0; i<BITLENGTH; i++) for(int i=0; i<BITLENGTH; i++)
blcount[i] <= '0; blcount[i] <= '0;
end else begin end else begin
@ -115,7 +129,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
nn <= '0; nn <= '0;
else else
nn <= nnn; nn <= istart ? '0 : nnn;
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
@ -129,7 +143,14 @@ always @ (posedge clk or negedge rstn)
end else begin end else begin
nextcode[0] <= '0; nextcode[0] <= '0;
alldone <= 1'b0; alldone <= 1'b0;
if(run) begin if(istart | ~run) begin
if(istart) for(int i=0; i<=BITLENGTH; i++) nextcode[i] <= '0;
ii <= '0;
idx <= '0;
build_tree2d <= 1'b0;
clearidx <= '0;
clear_tree2d <= 1'b0;
end else if(run) begin
if(~clear_tree2d) begin if(~clear_tree2d) begin
if( clearidx >= (clogb2(2*NUMCODES-1))'(2*NUMCODES-1) ) if( clearidx >= (clogb2(2*NUMCODES-1))'(2*NUMCODES-1) )
clear_tree2d <= 1'b1; clear_tree2d <= 1'b1;
@ -153,12 +174,6 @@ always @ (posedge clk or negedge rstn)
build_tree2d <= 1'b1; build_tree2d <= 1'b1;
end end
end end
end else begin
ii <= '0;
idx <= '0;
build_tree2d <= 1'b0;
clearidx <= '0;
clear_tree2d <= 1'b0;
end end
end end
@ -177,7 +192,9 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin if(~rstn) begin
nodefilled <= '0; nodefilled <= '0;
end else begin end else begin
if(~run) if(istart)
nodefilled <= '0;
else if(~run)
nodefilled <= (clogb2(2*NUMCODES-1))'(1); nodefilled <= (clogb2(2*NUMCODES-1))'(1);
else if(valid & rdfilled & lii>0) else if(valid & rdfilled & lii>0)
nodefilled <= nodefilled + (clogb2(2*NUMCODES-1))'(1); nodefilled <= nodefilled + (clogb2(2*NUMCODES-1))'(1);

View File

@ -10,7 +10,8 @@ module huffman_decoder #(
parameter OUTWIDTH = 10 parameter OUTWIDTH = 10
)( )(
rstn, clk, rstn, clk,
inew, ien, ibit, istart,
ien, ibit,
oen, ocode, oen, ocode,
rdaddr, rddata rdaddr, rddata
); );
@ -22,22 +23,22 @@ function automatic integer clogb2(input integer val);
endfunction endfunction
input rstn, clk; input rstn, clk;
input inew, ien, ibit; input istart, ien, ibit;
output oen; output oen;
output [ OUTWIDTH-1:0] ocode; output [ OUTWIDTH-1:0] ocode;
output [clogb2(2*NUMCODES-1)-1:0] rdaddr; output [clogb2(2*NUMCODES-1)-1:0] rdaddr;
input [ OUTWIDTH-1:0] rddata; input [ OUTWIDTH-1:0] rddata;
wire rstn, clk; wire rstn, clk;
wire inew, ien, ibit; wire istart, ien, ibit;
reg oen = 1'b0; reg oen = 1'b0;
reg [ OUTWIDTH-1:0] ocode = '0; reg [ OUTWIDTH-1:0] ocode = '0;
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr; wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
wire [ OUTWIDTH-1:0] rddata; wire [ OUTWIDTH-1:0] rddata;
reg [clogb2(2*NUMCODES-1)-2:0] tpos = '0; reg [clogb2(2*NUMCODES-1)-2:0] tpos = '0;
wire [clogb2(2*NUMCODES-1)-2:0] ntpos; wire [clogb2(2*NUMCODES-1)-2:0] ntpos;
reg ienl = 1'b0; reg ienl = 1'b0;
assign rdaddr = {ntpos, ibit}; assign rdaddr = {ntpos, ibit};
@ -47,13 +48,13 @@ always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
ienl <= '0; ienl <= '0;
else else
ienl <= inew ? '0 : ien; ienl <= istart ? '0 : ien;
always @ (posedge clk or negedge rstn) always @ (posedge clk or negedge rstn)
if(~rstn) if(~rstn)
tpos <= '0; tpos <= '0;
else else
tpos <= inew ? '0 : ntpos; tpos <= istart ? '0 : ntpos;
always_comb always_comb
if(ienl && rddata<NUMCODES) begin if(ienl && rddata<NUMCODES) begin

View File

@ -9,8 +9,8 @@
`timescale 1ps/1ps `timescale 1ps/1ps
`define START_NO 1 // first png file number to decode `define START_NO 1 // first png file number to decode
`define FINAL_NO 14 // last png file number to decode `define FINAL_NO 14 // last png file number to decode
`define IN_PNG_FILE_FOMRAT "test_image/img%02d.png" `define IN_PNG_FILE_FOMRAT "test_image/img%02d.png"
`define OUT_TXT_FILE_FORMAT "out%02d.txt" `define OUT_TXT_FILE_FORMAT "out%02d.txt"
@ -18,19 +18,22 @@
module tb_hard_png (); module tb_hard_png ();
initial $dumpvars(1, tb_hard_png); initial $dumpvars(0, tb_hard_png);
reg rstn = 1'b0; reg rstn = 1'b0;
reg clk = 1'b1; reg clk = 1'b1;
always #10000 clk = ~clk; // 50MHz always #10000 clk = ~clk; // 50MHz
initial begin repeat(4) @(posedge clk); rstn<=1'b1; end
reg [ 7:0] ibyte = '0;
reg istart = '0;
reg ivalid = 1'b0; reg ivalid = 1'b0;
wire iready; wire iready;
reg [ 7:0] ibyte = '0;
wire newframe; wire ostart;
wire [ 2:0] colortype; wire [ 2:0] colortype;
wire [13:0] width; wire [13:0] width;
wire [31:0] height; wire [31:0] height;
@ -44,11 +47,12 @@ hard_png hard_png_i (
.rstn ( rstn ), .rstn ( rstn ),
.clk ( clk ), .clk ( clk ),
// data input // data input
.istart ( istart ),
.ivalid ( ivalid ), .ivalid ( ivalid ),
.iready ( iready ), .iready ( iready ),
.ibyte ( ibyte ), .ibyte ( ibyte ),
// image size output // image size output
.newframe ( newframe ), .ostart ( ostart ),
.colortype ( colortype ), .colortype ( colortype ),
.width ( width ), .width ( width ),
.height ( height ), .height ( height ),
@ -69,14 +73,17 @@ int png_no = 0;
int txt_no = 0; int txt_no = 0;
int cyccnt = 0; int cyccnt = 0;
int bytecnt = 1; int bytecnt = 0;
initial begin initial begin
while(~rstn) @(posedge clk);
fork fork
// thread: input png file // thread: input png file
for(png_no=`START_NO; png_no<=`FINAL_NO; png_no=png_no+1) begin for(png_no=`START_NO; png_no<=`FINAL_NO; png_no=png_no+1) begin
istart <= 1'b1;
@ (posedge clk); @ (posedge clk);
rstn <= 1'b1; istart <= 1'b0;
$sformat(fname_png, `IN_PNG_FILE_FOMRAT , png_no); $sformat(fname_png, `IN_PNG_FILE_FOMRAT , png_no);
@ -86,15 +93,15 @@ initial begin
$finish; $finish;
end end
cyccnt = 0; cyccnt = 0;
bytecnt = 1; bytecnt = 0;
$display("start to decode %30s", fname_png ); $display("\nstart to decode %30s", fname_png );
ibyte <= $fgetc(fppng); ibyte <= $fgetc(fppng);
while( !$feof(fppng) ) @(posedge clk) begin while( !$feof(fppng) ) @(posedge clk) begin
if(~ivalid | iready ) begin if(~ivalid | iready ) begin
ivalid <= 1'b1; // use this to always try to input a byte to hard_png (no bubble, will get maximum throughput) ivalid <= 1'b1; // A. use this to always try to input a byte to hard_png (no bubble, will get maximum throughput)
//ivalid <= ($random % 3) == 0; // use this to add random bubbles to the input stream of hard_png. (Although the maximum throughput cannot be achieved, it allows input with mismatched rate, which is more common in the actual engineering scenarios) //ivalid <= ($random % 3) == 0; // B. use this to add random bubbles to the input stream of hard_png. (Although the maximum throughput cannot be achieved, it allows input with mismatched rate, which is more common in the actual engineering scenarios)
end end
if( ivalid & iready ) begin if( ivalid & iready ) begin
ibyte <= $fgetc(fppng); ibyte <= $fgetc(fppng);
@ -103,7 +110,6 @@ initial begin
cyccnt++; cyccnt++;
end end
ivalid <= 1'b0; ivalid <= 1'b0;
rstn <= 1'b0;
$fclose(fppng); $fclose(fppng);
$display("image %30s decode done, input %d bytes in %d cycles, throughput=%f byte/cycle", fname_png, bytecnt, cyccnt, (1.0*bytecnt)/cyccnt ); $display("image %30s decode done, input %d bytes in %d cycles, throughput=%f byte/cycle", fname_png, bytecnt, cyccnt, (1.0*bytecnt)/cyccnt );
@ -114,7 +120,7 @@ initial begin
for(txt_no=`START_NO; txt_no<=`FINAL_NO; txt_no=txt_no+1) begin for(txt_no=`START_NO; txt_no<=`FINAL_NO; txt_no=txt_no+1) begin
$sformat(fname_txt, `OUT_TXT_FILE_FORMAT , txt_no); $sformat(fname_txt, `OUT_TXT_FILE_FORMAT , txt_no);
while(~newframe) @ (posedge clk); while(~ostart) @ (posedge clk);
$display("decode result: colortype:%1d width:%1d height:%1d", colortype, width, height); $display("decode result: colortype:%1d width:%1d height:%1d", colortype, width, height);
fptxt = $fopen(fname_txt, "w"); fptxt = $fopen(fname_txt, "w");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB