update
47
README.md
@ -10,7 +10,7 @@ Hard-PNG
|
||||
|
||||
| ![diagram](./figures/diagram.png) |
|
||||
| :----: |
|
||||
| 图1 : Hard-PNG 原理框图 |
|
||||
| **图1** : Hard-PNG 原理框图 |
|
||||
|
||||
|
||||
|
||||
@ -34,37 +34,39 @@ png 图像文件的扩展名为 .png 。以本库中的 SIM/test_image/img01.png
|
||||
|
||||
# 使用 Hard-PNG
|
||||
|
||||
RTL 目录中的 hard_png.sv 是一个能够输入 png 码流,输出解压后的像素的模块,它的接口如图2所示。
|
||||
RTL 目录中的 hard_png.sv 是一个能够输入 png 码流,输出解压后的像素的模块,它的接口如**图2**所示。
|
||||
|
||||
| ![接口图](./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) |
|
||||
| :----: |
|
||||
| 图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 | 3‘d4 |
|
||||
在输入码流的同时,这张图象的解压结果(也就是图像基本信息和原始像素)会从模块中输出,如**图4**,在图象的像素输出前,ovalid 信号会出现一个时钟周期的高电平脉冲,同时 colortype, width, height 会有效。其中:
|
||||
|
||||
- width, height 分别是图象的宽度和高度
|
||||
- colortype 是 png 图像的颜色类型,含义如下表。
|
||||
|
||||
| colortype 值 | 3'd0 | 3'd1 | 3'd2 | 3'd3 | 3‘d4 |
|
||||
| :-------: | :--: | :--: | :--: | :--: | :--: |
|
||||
| 颜色类型 | 灰度 | 灰度+A | RGB | RGB+A | 索引RGB |
|
||||
| 备注 | R=G=B,A=0xFF | R=G=B≠A | R≠G≠B,A=0xFF | R≠G≠B≠A | R≠G≠B,A=0xFF |
|
||||
|
||||
然后,ovalid=1 代表该时钟周期有一个像素输出,该像素的 R,G,B,A 通道分别出现在 opixelr,opixelg,opixelb,opixela 信号上。
|
||||
然后,ovalid=1 代表该时钟周期有一个像素输出,该像素的 R,G,B,A 通道会分别出现在 opixelr,opixelg,opixelb,opixela 信号上。
|
||||
|
||||
| ![输出时序图](./figures/wave2.png) |
|
||||
| :----: |
|
||||
| 图4 : hard_png 的输出波形图 |
|
||||
|
||||
当一个 png 图象输入结束后,可以立即或稍后输入下一张图像(复位->解除复位->输入码流)。
|
||||
| **图4** : hard_png 的输出波形图 |
|
||||
|
||||
|
||||
|
||||
@ -79,7 +81,7 @@ hard_png 的使用方法很简单,在输入一张 png 图像的码流前,先
|
||||
|
||||
使用 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 文件查看波形。
|
||||
|
||||
@ -120,18 +122,19 @@ total 400 pixels validation successful!!
|
||||
| FPGA 型号 | LUT | LUT(%) | FF | FF(%) | Logic | Logic(%) | BRAM | BRAM(%) |
|
||||
| :----------------------------: | :--: | :----: | :--: | :---: | :---: | :------: | :-----: | :-----: |
|
||||
| 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 (正好时序收敛)。根据仿真时每个图像消耗的时钟周期数,可以算出压缩图像时的性能,举例如下表。
|
||||
|
||||
| png文件名 | 颜色类型 | 图象长宽 | png 码流大小 (字节) | 消耗的时钟周期数 | 消耗时间 |
|
||||
| :-----------: | :----------: | :----------: | :--------------: | :---------------: | :---------------: |
|
||||
| img05.png | RGB | 300x256 | 96536 | 1105702 | 23ms |
|
||||
| img06.png | 灰度 | 300x263 | 37283 | 395335 | 8ms |
|
||||
| img10.png | 索引RGB | 631x742 | 193489 | 2374224 | 48ms |
|
||||
| img14.png | 索引RGB | 1920x1080 | 818885 | 10177644 | 204ms |
|
||||
| 文件名 | 颜色类型 | 图象长宽 | 像素数 | png 码流大小 (字节) | 时钟周期数 | 消耗时间 |
|
||||
| :-----------: | :----------: | :----------: | :--------------: | :---------------: | :---------------: | ------------- |
|
||||
| img05.png | RGB | 300x256 | 76800 | 96536 | 1105702 | 23ms |
|
||||
| img06.png | 灰度 | 300x263 | 78900 | 37283 | 395335 | 8ms |
|
||||
| img09.png | RGBA | 300x263 | 78900 | 125218 | 1382303 | 28ms |
|
||||
| img10.png | 索引RGB | 631x742 | 468202 | 193489 | 2374224 | 48ms |
|
||||
| img14.png | 索引RGB | 1920x1080 | 2073600 | 818885 | 10177644 | 204ms |
|
||||
|
||||
|
||||
|
||||
|
237
RTL/hard_png.sv
@ -10,11 +10,12 @@ module hard_png (
|
||||
input wire rstn,
|
||||
input wire clk,
|
||||
// png data input stream
|
||||
input wire istart,
|
||||
input wire ivalid,
|
||||
output reg iready,
|
||||
input wire [ 7:0] ibyte,
|
||||
// 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 [13:0] width, // image width
|
||||
output wire [31:0] height, // image height
|
||||
@ -23,11 +24,9 @@ module hard_png (
|
||||
output wire [ 7:0] opixelr, opixelg, opixelb, opixela
|
||||
);
|
||||
|
||||
initial newframe = 1'b0;
|
||||
initial ostart = 1'b0;
|
||||
initial ovalid = 1'b0;
|
||||
|
||||
reg imagevalid = '0;
|
||||
|
||||
reg isplte = '0;
|
||||
|
||||
reg [ 1:0] bpp = '0; // bytes per pixel
|
||||
@ -88,7 +87,9 @@ generate genvar ii;
|
||||
if(~rstn)
|
||||
latchbytes[ii] <= '0;
|
||||
else begin
|
||||
if(ivalid)
|
||||
if(istart)
|
||||
latchbytes[ii] <= '0;
|
||||
else if(ivalid)
|
||||
latchbytes[ii] <= lastbytes[ii+1];
|
||||
end
|
||||
end
|
||||
@ -134,7 +135,7 @@ wire parametervalid = ( lastbytes[7]==8'h0 &&
|
||||
);
|
||||
|
||||
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;
|
||||
pvalid = ivalid;
|
||||
pbyte = ibyte;
|
||||
@ -152,7 +153,6 @@ always @ (posedge clk or negedge rstn)
|
||||
gapcnt <= '0;
|
||||
busy <= 1'b0;
|
||||
sizevalid <= 1'b0;
|
||||
imagevalid <= 1'b0;
|
||||
curr_name <= NONE;
|
||||
ispltetmp <= 1'b0;
|
||||
bpptmp <= '0;
|
||||
@ -164,18 +164,38 @@ always @ (posedge clk or negedge rstn)
|
||||
ppr <= '0;
|
||||
bpr <= '0;
|
||||
rpf <= '0;
|
||||
newframe <= 1'b0;
|
||||
ostart <= 1'b0;
|
||||
plte_wen <= 1'b0;
|
||||
plte_waddr <= '0;
|
||||
plte_wdata <= '0;
|
||||
plte_bytecnt <= '0;
|
||||
plte_pixcnt <= '0;
|
||||
end else begin
|
||||
newframe <= 1'b0;
|
||||
ostart <= 1'b0;
|
||||
plte_wen <= 1'b0;
|
||||
plte_waddr <= '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_pixcnt <= '0;
|
||||
if(~busy) begin
|
||||
@ -190,7 +210,6 @@ always @ (posedge clk or negedge rstn)
|
||||
cnt <= cnt - 1;
|
||||
gapcnt <= 2'd2;
|
||||
if(cnt==6) begin
|
||||
imagevalid <= 1'b0;
|
||||
rpftmp <= l32bit;
|
||||
if(h32bit[31:14]=='0) begin
|
||||
sizevalid <= 1'b1;
|
||||
@ -211,15 +230,13 @@ always @ (posedge clk or negedge rstn)
|
||||
endcase
|
||||
end else if(cnt==1) begin
|
||||
if(sizevalid && parametervalid && (bprtmp[15:14]==2'd0)) begin
|
||||
newframe <= 1'b1;
|
||||
imagevalid <= 1'b1;
|
||||
ostart <= 1'b1;
|
||||
isplte <= ispltetmp;
|
||||
bpp <= bpptmp;
|
||||
ppr <= pprtmp;
|
||||
bpr <= bprtmp[13:0];
|
||||
rpf <= rpftmp;
|
||||
end else begin
|
||||
imagevalid <= 1'b0;
|
||||
isplte <= 1'b0;
|
||||
bpp <= '0;
|
||||
ppr <= '0;
|
||||
@ -230,7 +247,7 @@ always @ (posedge clk or negedge rstn)
|
||||
end else if(curr_name==IDAT) begin
|
||||
if(gapcnt>2'd0)
|
||||
gapcnt <= gapcnt - 2'd1;
|
||||
if(imagevalid && gapcnt==2'd0) begin
|
||||
if(gapcnt==2'd0) begin
|
||||
if(pready)
|
||||
cnt <= cnt - 1;
|
||||
end else begin
|
||||
@ -291,36 +308,26 @@ always @ (posedge clk or negedge rstn)
|
||||
// uz_inflate
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
reg end_stream = '0;
|
||||
reg end_stream = '0;
|
||||
|
||||
wire huffman_ovalid;
|
||||
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 [ 7:0] rbyte = '0;
|
||||
|
||||
reg tvalid;
|
||||
wire tready;
|
||||
reg tbit;
|
||||
reg tvalid;
|
||||
wire tready;
|
||||
reg tbit;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
mvalid <= 1'b0;
|
||||
mbyte <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
mvalid <= 1'b0;
|
||||
mbyte <= '0;
|
||||
end else if(raw_mode) begin
|
||||
mvalid <= raw_ovalid;
|
||||
mbyte <= raw_obyte;
|
||||
end else begin
|
||||
mvalid <= huffman_ovalid;
|
||||
mbyte <= huffman_obyte;
|
||||
@ -328,98 +335,33 @@ always @ (posedge clk or negedge rstn)
|
||||
end
|
||||
|
||||
always_comb
|
||||
if(~imagevalid) begin
|
||||
raw_ovalid = 1'b0;
|
||||
raw_obyte = '0;
|
||||
pready = 1'b0;
|
||||
tvalid = 1'b0;
|
||||
tbit = 1'b0;
|
||||
if(uz_cnt==3'h0) begin
|
||||
pready = tready;
|
||||
tvalid = pvalid;
|
||||
tbit = pbyte[0];
|
||||
end else begin
|
||||
raw_ovalid = 1'b0;
|
||||
raw_obyte = '0;
|
||||
if(raw_mode) begin
|
||||
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
|
||||
pready = 1'b0;
|
||||
tvalid = 1'b1;
|
||||
tbit = rbyte[uz_cnt];
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
raw_mode <= 1'b0;
|
||||
uz_cnt <= '0;
|
||||
rbyte <= '0;
|
||||
rcnt <= '0;
|
||||
status <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
raw_mode <= 1'b0;
|
||||
if(istart) begin
|
||||
uz_cnt <= '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
|
||||
rcnt <= '0;
|
||||
status <= '0;
|
||||
if(raw_format) begin
|
||||
if(pvalid) begin
|
||||
raw_mode <= 1'b1;
|
||||
rcnt[ 7:0] <= pbyte;
|
||||
if(uz_cnt==3'h0) begin
|
||||
if(pvalid & tready) begin
|
||||
uz_cnt <= uz_cnt + 3'h1;
|
||||
rbyte <= pbyte;
|
||||
end
|
||||
uz_cnt <= '0;
|
||||
rbyte <= '0;
|
||||
end else begin
|
||||
if(uz_cnt==3'h0) begin
|
||||
if(pvalid & tready) begin
|
||||
uz_cnt <= uz_cnt + 3'h1;
|
||||
rbyte <= pbyte;
|
||||
end
|
||||
end else begin
|
||||
if(tready)
|
||||
uz_cnt <= uz_cnt + 3'h1;
|
||||
end
|
||||
if(tready)
|
||||
uz_cnt <= uz_cnt + 3'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -440,8 +382,6 @@ reg srepeat = 1'b0;
|
||||
reg symbol_valid = 1'b0;
|
||||
reg [7:0] symbol = '0;
|
||||
|
||||
reg decoder_new = 1'b1;
|
||||
|
||||
reg [ 1:0] iword = '0;
|
||||
reg [ 1:0] ibcnt = '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;
|
||||
|
||||
wire lentree_ien = ~end_stream & ~raw_format & 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 distree_ien = ~end_stream & ~raw_format & tvalid & tree_done & ~distree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==D);
|
||||
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 & tvalid & tree_done & ~codetree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (huffman_status==T);
|
||||
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 ) |
|
||||
( 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 [ 5:0] lengthe= '0;
|
||||
@ -575,20 +515,17 @@ endtask
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
{raw_format, end_stream} <= '0;
|
||||
decoder_new <= 1'b1;
|
||||
end_stream <= '0;
|
||||
reset_all_regs;
|
||||
end else begin
|
||||
if(raw_mode) begin
|
||||
{raw_format, end_stream} <= '0;
|
||||
decoder_new <= 1'b1;
|
||||
if(istart) begin
|
||||
end_stream <= '0;
|
||||
reset_all_regs;
|
||||
end else begin
|
||||
symbol_valid <= 1'b0;
|
||||
symbol <= '0;
|
||||
irepeat <= 1'b0;
|
||||
srepeat <= 1'b0;
|
||||
decoder_new <= 1'b0;
|
||||
lentree_write();
|
||||
codetree_write();
|
||||
distree_write();
|
||||
@ -602,16 +539,12 @@ always @ (posedge clk or negedge rstn)
|
||||
end else if(precode_wpt==1) begin
|
||||
bfix <= tbit;
|
||||
end else begin
|
||||
case({tbit,bfix})
|
||||
2'b00 :
|
||||
raw_format <= 1'b1;
|
||||
2'b01 : begin
|
||||
if( {tbit,bfix} == 2'b01 ) begin
|
||||
precode_wpt <= '1;
|
||||
lentree_wpt <= '1;
|
||||
tree_wpt <= '1;
|
||||
fixed_tree <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end else if(precode_wpt<17) begin
|
||||
@ -777,6 +710,7 @@ huffman_builder #(
|
||||
) lentree_builder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.istart ( istart ),
|
||||
.wren ( lentree_wen ),
|
||||
.wraddr ( lentree_waddr ),
|
||||
.wrdata ( lentree_wdata ),
|
||||
@ -796,7 +730,7 @@ huffman_decoder #(
|
||||
) lentree_decoder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.inew ( decoder_new ),
|
||||
.istart ( istart ),
|
||||
.ien ( lentree_ien ),
|
||||
.ibit ( tbit ),
|
||||
.oen ( lentree_codeen ),
|
||||
@ -817,6 +751,7 @@ huffman_builder #(
|
||||
) codetree_builder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.istart ( istart ),
|
||||
.wren ( codetree_wen ),
|
||||
.wraddr ( codetree_waddr ),
|
||||
.wrdata ( (5)'(codetree_wdata) ),
|
||||
@ -844,7 +779,7 @@ huffman_decoder #(
|
||||
) codetree_decoder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.inew ( decoder_new ),
|
||||
.istart ( istart ),
|
||||
.ien ( codetree_ien ),
|
||||
.ibit ( tbit ),
|
||||
.oen ( codetree_codeen),
|
||||
@ -865,9 +800,10 @@ huffman_builder #(
|
||||
) distree_builder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.istart ( istart ),
|
||||
.wren ( distree_wen ),
|
||||
.wraddr ( distree_waddr ),
|
||||
.wrdata ( (5)'(distree_wdata) ),
|
||||
.wrdata ( (5)'(distree_wdata) ),
|
||||
.run ( tree_run ),
|
||||
.done ( distree_done ),
|
||||
.rdaddr ( distree_raddr ),
|
||||
@ -892,7 +828,7 @@ huffman_decoder #(
|
||||
) distree_decoder (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
.inew ( decoder_new ),
|
||||
.istart ( istart ),
|
||||
.ien ( distree_ien ),
|
||||
.ibit ( tbit ),
|
||||
.oen ( distree_codeen ),
|
||||
@ -923,7 +859,10 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
wptr <= '0;
|
||||
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
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
@ -932,7 +871,11 @@ always @ (posedge clk or negedge rstn)
|
||||
sptr <= '0;
|
||||
eptr <= '0;
|
||||
end else begin
|
||||
if(srepeat) begin
|
||||
if(istart) begin
|
||||
rptr <= '0;
|
||||
sptr <= '0;
|
||||
eptr <= '0;
|
||||
end else if(srepeat) begin
|
||||
rptr <= sptrw;
|
||||
sptr <= sptrw;
|
||||
eptr <= eptrw;
|
||||
@ -948,7 +891,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
repeat_valid <= '0;
|
||||
else
|
||||
repeat_valid <= irepeat;
|
||||
repeat_valid <= istart ? '0 : irepeat;
|
||||
|
||||
reg [7:0] mem_repeat_buffer [REPEAT_BUFFER_MAXLEN];
|
||||
|
||||
@ -996,7 +939,7 @@ always @ (posedge clk or negedge rstn)
|
||||
nfirstrow <= 1'b0;
|
||||
col <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
nfirstrow <= 1'b0;
|
||||
col <= '0;
|
||||
end else if(mvalid) begin
|
||||
@ -1013,9 +956,9 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
mode <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart)
|
||||
mode <= '0;
|
||||
end else if(mvalid && col==14'h0)
|
||||
else if(mvalid && col==14'h0)
|
||||
mode <= mbyte[2:0];
|
||||
end
|
||||
|
||||
@ -1027,7 +970,7 @@ always_comb
|
||||
3'd3 : fdata = mbyte + SSdata[8:1];
|
||||
default: fdata = mbyte + paeth( (nfirstcol ? LLdata : 8'h0),
|
||||
(nfirstrow ? UUdata : 8'h0),
|
||||
(nfirstrow&nfirstcol ? ULdata : 8'h0) );
|
||||
(nfirstrow & nfirstcol ? ULdata : 8'h0) );
|
||||
endcase
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
@ -1035,7 +978,7 @@ always @ (posedge clk or negedge rstn)
|
||||
bvalid <= 1'b0;
|
||||
bbyte <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
bvalid <= 1'b0;
|
||||
bbyte <= '0;
|
||||
end else begin
|
||||
@ -1052,7 +995,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
mem_sr_currline[0] <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
mem_sr_currline[0] <= '0;
|
||||
end else if(mvalid)
|
||||
mem_sr_currline[0] <= fdata;
|
||||
@ -1063,7 +1006,7 @@ generate genvar isrcl;
|
||||
if(~rstn) begin
|
||||
mem_sr_currline[isrcl+1] <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
mem_sr_currline[isrcl+1] <= '0;
|
||||
end else if(mvalid)
|
||||
mem_sr_currline[isrcl+1] <= mem_sr_currline[isrcl];
|
||||
@ -1080,7 +1023,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
mem_sr_prevline[0] <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
mem_sr_prevline[0] <= '0;
|
||||
end else if(mvalid)
|
||||
mem_sr_prevline[0] <= UUdata;
|
||||
@ -1091,7 +1034,7 @@ generate genvar isrpl;
|
||||
if(~rstn) begin
|
||||
mem_sr_prevline[isrpl+1] <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
mem_sr_prevline[isrpl+1] <= '0;
|
||||
end else if(mvalid)
|
||||
mem_sr_prevline[isrpl+1] <= mem_sr_prevline[isrpl];
|
||||
@ -1111,7 +1054,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
sb_lidata <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
sb_lidata <= '0;
|
||||
end else if(mvalid)
|
||||
sb_lidata <= fdata;
|
||||
@ -1121,7 +1064,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
sb_ptr <= '0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
sb_ptr <= '0;
|
||||
end else if(mvalid) begin
|
||||
if(sb_ptr < (bpr-14'd1))
|
||||
@ -1136,7 +1079,7 @@ always @ (posedge clk or negedge rstn)
|
||||
sb_ldata <= '0;
|
||||
sb_rvalid <= 1'b0;
|
||||
end else begin
|
||||
if(~imagevalid) begin
|
||||
if(istart) begin
|
||||
sb_ldata <= '0;
|
||||
sb_rvalid <= 1'b0;
|
||||
end else begin
|
||||
@ -1177,7 +1120,7 @@ always @ (posedge clk or negedge rstn)
|
||||
{pr, pg, pb, pa} <= 0;
|
||||
end else begin
|
||||
ovalid <= 1'b0;
|
||||
if(newframe) begin
|
||||
if(istart | ostart) begin
|
||||
pixcnt <= '0;
|
||||
{pr, pg, pb, pa} <= 0;
|
||||
end else if(bvalid) begin
|
||||
|
@ -12,6 +12,7 @@ module huffman_builder #(
|
||||
parameter OUTWIDTH = 10
|
||||
) (
|
||||
rstn, clk,
|
||||
istart,
|
||||
wren, wraddr, wrdata,
|
||||
run , done,
|
||||
rdaddr, rddata
|
||||
@ -25,6 +26,7 @@ endfunction
|
||||
|
||||
input rstn;
|
||||
input clk;
|
||||
input istart;
|
||||
input wren;
|
||||
input [ clogb2(NUMCODES-1)-1:0] wraddr;
|
||||
input [ CODEBITS -1:0] wrdata;
|
||||
@ -33,18 +35,19 @@ output done;
|
||||
input [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
output [ OUTWIDTH-1:0] rddata;
|
||||
|
||||
wire rstn;
|
||||
wire clk;
|
||||
wire wren;
|
||||
wire [ clogb2(NUMCODES-1)-1:0] wraddr;
|
||||
wire [ CODEBITS -1:0] wrdata;
|
||||
wire run;
|
||||
wire done;
|
||||
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
reg [ OUTWIDTH-1:0] rddata;
|
||||
wire rstn;
|
||||
wire clk;
|
||||
wire istart;
|
||||
wire wren;
|
||||
wire [ clogb2(NUMCODES-1)-1:0] wraddr;
|
||||
wire [ CODEBITS -1:0] wrdata;
|
||||
wire run;
|
||||
wire done;
|
||||
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
reg [ OUTWIDTH-1:0] rddata;
|
||||
|
||||
reg [clogb2(NUMCODES)-1:0] blcount [BITLENGTH];
|
||||
reg [ (1<<CODEBITS)-1:0] nextcode [BITLENGTH+1];
|
||||
reg [clogb2(NUMCODES)-1:0] blcount [BITLENGTH];
|
||||
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++) nextcode[i] = '0;
|
||||
@ -77,18 +80,29 @@ always @ (posedge clk or negedge rstn)
|
||||
lii <= '0;
|
||||
lnn <= '0;
|
||||
end else begin
|
||||
valid <= build_tree2d & nn<NUMCODES & blen>0;
|
||||
treepos <= ntreepos;
|
||||
tpos <= ntpos;
|
||||
lii <= ii;
|
||||
lnn <= nn;
|
||||
if(istart) begin
|
||||
valid <= '0;
|
||||
treepos <= '0;
|
||||
tpos <= '0;
|
||||
lii <= '0;
|
||||
lnn <= '0;
|
||||
end else begin
|
||||
valid <= build_tree2d & nn<NUMCODES & blen>0;
|
||||
treepos <= ntreepos;
|
||||
tpos <= ntpos;
|
||||
lii <= ii;
|
||||
lnn <= nn;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
blen <= '0;
|
||||
else begin
|
||||
if(islast) blen <= blenn;
|
||||
if(istart)
|
||||
blen <= '0;
|
||||
else if(islast)
|
||||
blen <= blenn;
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
@ -96,7 +110,7 @@ always @ (posedge clk or negedge rstn)
|
||||
for(int i=0; i<BITLENGTH; i++)
|
||||
blcount[i] <= '0;
|
||||
end else begin
|
||||
if(done) begin
|
||||
if(istart | done) begin
|
||||
for(int i=0; i<BITLENGTH; i++)
|
||||
blcount[i] <= '0;
|
||||
end else begin
|
||||
@ -115,7 +129,7 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
nn <= '0;
|
||||
else
|
||||
nn <= nnn;
|
||||
nn <= istart ? '0 : nnn;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
@ -129,7 +143,14 @@ always @ (posedge clk or negedge rstn)
|
||||
end else begin
|
||||
nextcode[0] <= '0;
|
||||
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( clearidx >= (clogb2(2*NUMCODES-1))'(2*NUMCODES-1) )
|
||||
clear_tree2d <= 1'b1;
|
||||
@ -153,12 +174,6 @@ always @ (posedge clk or negedge rstn)
|
||||
build_tree2d <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
ii <= '0;
|
||||
idx <= '0;
|
||||
build_tree2d <= 1'b0;
|
||||
clearidx <= '0;
|
||||
clear_tree2d <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
@ -177,7 +192,9 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
nodefilled <= '0;
|
||||
end else begin
|
||||
if(~run)
|
||||
if(istart)
|
||||
nodefilled <= '0;
|
||||
else if(~run)
|
||||
nodefilled <= (clogb2(2*NUMCODES-1))'(1);
|
||||
else if(valid & rdfilled & lii>0)
|
||||
nodefilled <= nodefilled + (clogb2(2*NUMCODES-1))'(1);
|
||||
|
@ -10,7 +10,8 @@ module huffman_decoder #(
|
||||
parameter OUTWIDTH = 10
|
||||
)(
|
||||
rstn, clk,
|
||||
inew, ien, ibit,
|
||||
istart,
|
||||
ien, ibit,
|
||||
oen, ocode,
|
||||
rdaddr, rddata
|
||||
);
|
||||
@ -22,22 +23,22 @@ function automatic integer clogb2(input integer val);
|
||||
endfunction
|
||||
|
||||
input rstn, clk;
|
||||
input inew, ien, ibit;
|
||||
input istart, ien, ibit;
|
||||
output oen;
|
||||
output [ OUTWIDTH-1:0] ocode;
|
||||
output [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
input [ OUTWIDTH-1:0] rddata;
|
||||
|
||||
wire rstn, clk;
|
||||
wire inew, ien, ibit;
|
||||
reg oen = 1'b0;
|
||||
reg [ OUTWIDTH-1:0] ocode = '0;
|
||||
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
wire [ OUTWIDTH-1:0] rddata;
|
||||
wire rstn, clk;
|
||||
wire istart, ien, ibit;
|
||||
reg oen = 1'b0;
|
||||
reg [ OUTWIDTH-1:0] ocode = '0;
|
||||
wire [clogb2(2*NUMCODES-1)-1:0] rdaddr;
|
||||
wire [ OUTWIDTH-1:0] rddata;
|
||||
|
||||
reg [clogb2(2*NUMCODES-1)-2:0] tpos = '0;
|
||||
wire [clogb2(2*NUMCODES-1)-2:0] ntpos;
|
||||
reg ienl = 1'b0;
|
||||
reg [clogb2(2*NUMCODES-1)-2:0] tpos = '0;
|
||||
wire [clogb2(2*NUMCODES-1)-2:0] ntpos;
|
||||
reg ienl = 1'b0;
|
||||
|
||||
assign rdaddr = {ntpos, ibit};
|
||||
|
||||
@ -47,13 +48,13 @@ always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
ienl <= '0;
|
||||
else
|
||||
ienl <= inew ? '0 : ien;
|
||||
ienl <= istart ? '0 : ien;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
tpos <= '0;
|
||||
else
|
||||
tpos <= inew ? '0 : ntpos;
|
||||
tpos <= istart ? '0 : ntpos;
|
||||
|
||||
always_comb
|
||||
if(ienl && rddata<NUMCODES) begin
|
||||
|
@ -9,8 +9,8 @@
|
||||
`timescale 1ps/1ps
|
||||
|
||||
|
||||
`define START_NO 1 // first png file number to decode
|
||||
`define FINAL_NO 14 // last 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 IN_PNG_FILE_FOMRAT "test_image/img%02d.png"
|
||||
`define OUT_TXT_FILE_FORMAT "out%02d.txt"
|
||||
@ -18,19 +18,22 @@
|
||||
|
||||
module tb_hard_png ();
|
||||
|
||||
initial $dumpvars(1, tb_hard_png);
|
||||
initial $dumpvars(0, tb_hard_png);
|
||||
|
||||
|
||||
reg rstn = 1'b0;
|
||||
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;
|
||||
wire iready;
|
||||
reg [ 7:0] ibyte = '0;
|
||||
|
||||
wire newframe;
|
||||
wire ostart;
|
||||
wire [ 2:0] colortype;
|
||||
wire [13:0] width;
|
||||
wire [31:0] height;
|
||||
@ -44,11 +47,12 @@ hard_png hard_png_i (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
// data input
|
||||
.istart ( istart ),
|
||||
.ivalid ( ivalid ),
|
||||
.iready ( iready ),
|
||||
.ibyte ( ibyte ),
|
||||
// image size output
|
||||
.newframe ( newframe ),
|
||||
.ostart ( ostart ),
|
||||
.colortype ( colortype ),
|
||||
.width ( width ),
|
||||
.height ( height ),
|
||||
@ -69,14 +73,17 @@ int png_no = 0;
|
||||
int txt_no = 0;
|
||||
|
||||
int cyccnt = 0;
|
||||
int bytecnt = 1;
|
||||
int bytecnt = 0;
|
||||
|
||||
initial begin
|
||||
while(~rstn) @(posedge clk);
|
||||
|
||||
fork
|
||||
// thread: input png file
|
||||
for(png_no=`START_NO; png_no<=`FINAL_NO; png_no=png_no+1) begin
|
||||
istart <= 1'b1;
|
||||
@ (posedge clk);
|
||||
rstn <= 1'b1;
|
||||
istart <= 1'b0;
|
||||
|
||||
$sformat(fname_png, `IN_PNG_FILE_FOMRAT , png_no);
|
||||
|
||||
@ -86,15 +93,15 @@ initial begin
|
||||
$finish;
|
||||
end
|
||||
cyccnt = 0;
|
||||
bytecnt = 1;
|
||||
bytecnt = 0;
|
||||
|
||||
$display("start to decode %30s", fname_png );
|
||||
$display("\nstart to decode %30s", fname_png );
|
||||
|
||||
ibyte <= $fgetc(fppng);
|
||||
while( !$feof(fppng) ) @(posedge clk) 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 <= ($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 <= 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; // 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
|
||||
if( ivalid & iready ) begin
|
||||
ibyte <= $fgetc(fppng);
|
||||
@ -103,7 +110,6 @@ initial begin
|
||||
cyccnt++;
|
||||
end
|
||||
ivalid <= 1'b0;
|
||||
rstn <= 1'b0;
|
||||
|
||||
$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 );
|
||||
@ -114,7 +120,7 @@ initial 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);
|
||||
|
||||
while(~newframe) @ (posedge clk);
|
||||
while(~ostart) @ (posedge clk);
|
||||
$display("decode result: colortype:%1d width:%1d height:%1d", colortype, width, height);
|
||||
|
||||
fptxt = $fopen(fname_txt, "w");
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |