Hard-PNG/hard_png.sv

1955 lines
80 KiB
Systemverilog
Raw Normal View History

2021-11-01 15:44:10 +08:00
`timescale 1 ns/1 ns
module hard_png(
input wire rst,
input wire clk,
// png data input stream
input wire ivalid,
output wire iready,
input wire [ 7:0] ibyte,
// image frame configuration output
output wire newframe,
output wire [ 1:0] colortype, // 0:gray 1:gray+A 2:RGB 3:RGBA
output wire [13:0] width, // horizontal size / frame width / pixel per row
output wire [31:0] height, // vertical size / frame height / rows per frame
// pixel output
output wire ovalid,
output wire [ 7:0] opixelr, opixelg, opixelb, opixela
);
wire reset;
wire [13:0] bpr; // bytes per row
wire [ 1:0] bpp; // bytes per pixel
wire pvalid;
wire pready;
wire [ 7:0] pbyte;
wire mvalid;
wire [ 7:0] mbyte;
wire bvalid;
wire [ 7:0] bbyte;
wire isplte;
wire plte_wen;
wire [ 7:0] plte_waddr;
wire [23:0] plte_wdata;
wire [ 7:0] plte_raddr;
wire [23:0] plte_rdata;
assign colortype = isplte ? 2'd2 : bpp;
png_parser png_parser_i(
.rst ( rst ),
.orst ( reset ),
.clk ( clk ),
.oframe ( newframe ),
.isplte ( isplte ),
.bpp ( bpp ),
.ppr ( width ),
.bpr ( bpr ),
.rpf ( height ),
.ivalid ( ivalid ),
.iready ( iready ),
.ibyte ( ibyte ),
.ovalid ( pvalid ),
.oready ( pready ),
.obyte ( pbyte ),
.plte_wen ( plte_wen ),
.plte_waddr ( plte_waddr ),
.plte_wdata ( plte_wdata )
);
uz_inflate uz_inflate_i(
.rst ( reset ),
.clk ( clk ),
.ivalid ( pvalid ),
.iready ( pready ),
.ibyte ( pbyte ),
.ovalid ( mvalid ),
.obyte ( mbyte ),
.end_stream ( )
);
unfilter unfilter_i(
.rst ( reset ),
.clk ( clk ),
.bpp ( bpp ),
.bpr ( bpr ),
.ivalid ( mvalid ),
.idata ( mbyte ),
.ovalid ( bvalid ),
.odata ( bbyte )
);
build_pixel build_pixel_i(
.clk ( clk ),
.newframe ( newframe ),
.bpp ( bpp ),
.isplte ( isplte ),
.plte_raddr ( plte_raddr ),
.plte_rdata ( plte_rdata ),
.ivalid ( bvalid ),
.ibyte ( bbyte ),
.ovalid ( ovalid ),
.opixelr ( opixelr ),
.opixelg ( opixelg ),
.opixelb ( opixelb ),
.opixela ( opixela )
);
RamSinglePort #(
.SIZE ( 256 ),
.WIDTH ( 24 )
) ram_for_plte (
.clk ( clk ),
.wen ( plte_wen ),
.waddr ( 8'(plte_waddr) ),
.wdata ( plte_wdata ),
.raddr ( 8'(plte_raddr) ),
.rdata ( plte_rdata )
);
endmodule
module build_pixel(
input wire clk,
input wire newframe,
input wire [ 1:0] bpp,
input wire isplte,
output wire [ 7:0] plte_raddr,
input wire [23:0] plte_rdata,
input wire ivalid,
input wire [ 7:0] ibyte,
output reg ovalid,
output wire [ 7:0] opixelr, opixelg, opixelb, opixela
);
initial ovalid = 1'b0;
reg [1:0] pixcnt = '0;
reg [7:0] pr='0, pg='0, pb='0, pa='0;
assign plte_raddr = ibyte;
assign opixelr = ovalid ? (isplte ? plte_rdata[23:16] : pr) : 8'h0;
assign opixelg = ovalid ? (isplte ? plte_rdata[15: 8] : pg) : 8'h0;
assign opixelb = ovalid ? (isplte ? plte_rdata[ 7: 0] : pb) : 8'h0;
assign opixela = ovalid ? (isplte ? 8'hff : pa) : 8'h0;
always @ (posedge clk)
if(newframe) begin
pixcnt <= '0;
ovalid <= 1'b0;
{pr, pg, pb, pa} <= 0;
end else if(ivalid) begin
case(pixcnt)
2'd0 : {pr, pg, pb, pa} <= {ibyte, ibyte, ibyte, 8'hff};
2'd1 : { pa} <= { ibyte};
2'd2 : { pg, pb, pa} <= { pa, ibyte, 8'hff};
2'd3 : { pa} <= { ibyte};
endcase
if(pixcnt<bpp) begin
pixcnt <= pixcnt + 2'd1;
ovalid <= 1'b0;
end else begin
pixcnt <= 2'd0;
ovalid <= 1'b1;
end
end else
ovalid <= 1'b0;
endmodule
module png_parser(
input wire rst,
input wire clk,
// data input
input wire ivalid,
output reg iready,
input wire [ 7:0] ibyte,
// data output
output reg ovalid,
input wire oready,
output reg [ 7:0] obyte,
// image parameters out
output wire orst,
output reg oframe,
output reg isplte,
output reg [ 1:0] bpp, // bytes per pixel
output reg [13:0] ppr, // pixel per row
output reg [13:0] bpr, // bytes per row
output reg [31:0] rpf, // rows per frame
// PLTE RAM write port
output reg plte_wen,
output reg [ 7:0] plte_waddr,
output reg [23:0] plte_wdata
);
initial oframe = 1'b0;
initial isplte = 1'b0;
initial bpp = '0;
initial ppr = '0;
initial bpr = '0;
initial rpf = '0;
initial plte_wen = 1'b0;
initial plte_waddr = '0;
initial plte_wdata = '0;
wire ispltes [8]; assign ispltes[0]=1'b0; assign ispltes[1]=1'b0; assign ispltes[2]=1'b0; assign ispltes[3]=1'b1; assign ispltes[4]=1'b0; assign ispltes[5]=1'b0; assign ispltes[6]=1'b0; assign ispltes[7]=1'b0;
wire [ 1:0] bpps [8]; assign bpps[0]=2'd0; assign bpps[1]=2'd0; assign bpps[2]=2'd2; assign bpps[3]=2'd0; assign bpps[4]=2'd1; assign bpps[5]=2'd0; assign bpps[6]=2'd3; assign bpps[7]=2'd0;
wire [63:0] png_precode = 64'h89504e470d0a1a0a;
wire [31:0] ihdr_name = 32'h49484452;
wire [31:0] plte_name = 32'h504C5445;
wire [31:0] idat_name = 32'h49444154;
wire [31:0] iend_name = 32'h49454e44;
reg [ 7:0] latchbytes [7];
wire [ 7:0] lastbytes [8];
wire [63:0] lastlbytes;
wire [31:0] h32bit = lastlbytes[63:32];
wire [31:0] l32bit = lastlbytes[31: 0];
assign lastbytes[7] = ibyte;
initial {latchbytes[0],latchbytes[1],latchbytes[2],latchbytes[3],latchbytes[4],latchbytes[5],latchbytes[6]} = '0;
generate genvar ii;
for(ii=0; ii<7; ii++) begin : generate_latchbytes_connect
assign lastbytes[ii] = latchbytes[ii];
always @ (posedge clk or posedge rst)
if(rst)
latchbytes[ii] <= '0;
else begin
if(ivalid)
latchbytes[ii] <= lastbytes[ii+1];
end
end
endgenerate
assign lastlbytes[ 7: 0] = lastbytes[7];
assign lastlbytes[15: 8] = lastbytes[6];
assign lastlbytes[23:16] = lastbytes[5];
assign lastlbytes[31:24] = lastbytes[4];
assign lastlbytes[39:32] = lastbytes[3];
assign lastlbytes[47:40] = lastbytes[2];
assign lastlbytes[55:48] = lastbytes[1];
assign lastlbytes[63:56] = lastbytes[0];
reg [ 2:0] bcnt= '0;
reg [31:0] cnt = '0;
reg [ 2:0] crccnt = '0;
reg [ 2:0] gapcnt = '0;
enum {NONE, IHDR, PLTE, IDAT, IEND} curr_name = NONE;
reg busy = 1'b0;
reg sizevalid = 1'b0;
reg imagevalid = 1'b0;
reg ispltetmp = 1'b0;
reg [ 1:0] bpptmp = '0; // bytes per pixel
reg [13:0] pprtmp = '0; // pixel per row
reg [15:0] bprtmp = '0; // bytes per row
reg [31:0] rpftmp = '0; // rows per frame
reg [ 1:0] plte_bytecnt = '0;
reg [ 7:0] plte_pixcnt = '0;
assign orst = ~imagevalid;
wire parametervalid = ( lastbytes[7]==8'h0 &&
lastbytes[6]==8'h0 &&
lastbytes[5]==8'h0 &&
lastbytes[3]==8'h8 &&
( lastbytes[4]==8'h0 ||
lastbytes[4]==8'h2 ||
lastbytes[4]==8'h3 ||
lastbytes[4]==8'h4 ||
lastbytes[4]==8'h6
)
);
always_comb
if(ivalid && imagevalid && cnt>0 && curr_name==IDAT && gapcnt==2'd0) begin
ovalid <= 1'b1;
iready <= oready;
obyte <= ibyte;
end else begin
ovalid <= 1'b0;
iready <= 1'b1;
obyte <= '0;
end
always @ (posedge clk or posedge rst)
if(rst) begin
bcnt <= '0;
cnt <= '0;
crccnt <= '0;
gapcnt <= '0;
busy <= 1'b0;
sizevalid <= 1'b0;
imagevalid <= 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;
oframe <= 1'b0;
plte_wen <= 1'b0;
plte_waddr <= '0;
plte_wdata <= '0;
plte_bytecnt <= '0;
plte_pixcnt <= '0;
end else begin
oframe <= 1'b0;
plte_wen <= 1'b0;
plte_waddr <= '0;
plte_wdata <= '0;
if(ivalid) begin
plte_bytecnt <= '0;
plte_pixcnt <= '0;
if(~busy) begin
bcnt <= '0;
cnt <= '0;
crccnt <= '0;
busy <= (lastlbytes==png_precode);
end else begin
if(cnt>0) begin
bcnt <= '0;
if(curr_name==IHDR) begin
cnt <= cnt - 1;
gapcnt <= 2'd2;
if(cnt==6) begin
imagevalid <= 1'b0;
rpftmp <= l32bit;
if(h32bit[31:14]=='0) begin
sizevalid <= 1'b1;
pprtmp <= h32bit[13:0];
end else begin
sizevalid <= 1'b0;
pprtmp <= '1;
end
end else if(cnt==3) begin
ispltetmp <= ispltes[lastlbytes[10:8]];
bpptmp <= bpps[lastlbytes[10:8]];
end else if(cnt==2) begin
case(bpptmp)
2'd0 : bprtmp <= {2'b00, pprtmp};
2'd1 : bprtmp <= {1'b0, pprtmp, 1'b0};
2'd2 : bprtmp <= {1'b0, pprtmp, 1'b0} + {2'b00, pprtmp};
2'd3 : bprtmp <= {pprtmp, 2'b00};
endcase
end else if(cnt==1) begin
if(sizevalid && parametervalid && (bprtmp[15:14]==2'd0)) begin
oframe <= 1'b1;
imagevalid <= 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;
bpr <= '0;
rpf <= '0;
end
end
end else if(curr_name==IDAT) begin
if(gapcnt>2'd0)
gapcnt <= gapcnt - 2'd1;
if(imagevalid && gapcnt==2'd0) begin
if(oready)
cnt <= cnt - 1;
end else begin
cnt <= cnt - 1;
end
end else if(curr_name==PLTE) begin
plte_pixcnt <= plte_pixcnt;
case(plte_bytecnt)
2'd0 :plte_bytecnt <= 2'd1;
2'd1 :plte_bytecnt <= 2'd2;
default:begin
plte_bytecnt <= 2'd0;
plte_pixcnt <= plte_pixcnt + 8'd1;
plte_wen <= 1'b1;
plte_waddr <= plte_pixcnt;
plte_wdata <= lastlbytes[23:0];
end
endcase
cnt <= cnt - 1;
end else begin
cnt <= cnt - 1;
end
end else if(crccnt>3'd0) begin
bcnt <= '0;
cnt <= '0;
crccnt <= crccnt - 3'd1;
if(crccnt==3'd1) begin
if(curr_name==IEND) begin
busy <= 1'b0;
end
curr_name <= NONE;
end
end else begin
if(bcnt==3'd7) begin
cnt <= h32bit;
crccnt <= 3'd4;
if (l32bit==ihdr_name)
curr_name <= IHDR;
else if(l32bit==plte_name)
curr_name <= PLTE;
else if(l32bit==idat_name)
curr_name <= IDAT;
else if(l32bit==iend_name)
curr_name <= IEND;
else
curr_name <= NONE;
end
bcnt <= bcnt + 3'd1;
end
end
end
end
endmodule
module uz_inflate(
input wire rst,
input wire clk,
input wire ivalid,
output reg iready,
input wire [7:0] ibyte,
output reg ovalid,
output reg [7:0] obyte,
output wire end_stream
);
initial ovalid = 1'b0;
initial obyte = '0;
wire huffman_ovalid;
wire [7:0] huffman_obyte;
reg raw_ovalid;
reg [7:0] raw_obyte;
reg raw_mode = 1'b0;
wire raw_format;
reg [ 2:0] status = '0;
reg [15:0] rcnt = '0;
reg [ 2:0] cnt = '0;
reg [ 7:0] rbyte = '0;
reg tvalid;
wire tready;
reg tbit;
always @ (posedge clk or posedge rst)
if(rst) begin
ovalid <= 1'b0;
obyte <= '0;
end else begin
if(raw_mode) begin
ovalid <= raw_ovalid;
obyte <= raw_obyte;
end else begin
ovalid <= huffman_ovalid;
obyte <= huffman_obyte;
end
end
always_comb
if(rst) begin
raw_ovalid <= 1'b0;
raw_obyte <= '0;
iready <= 1'b0;
tvalid <= 1'b0;
tbit <= 1'b0;
end else begin
raw_ovalid <= 1'b0;
raw_obyte <= '0;
if(raw_mode) begin
iready <= 1'b1;
tvalid <= 1'b0;
tbit <= 1'b0;
if(status>=3) begin
raw_ovalid <= ivalid;
raw_obyte <= ibyte;
end
end else begin
if(raw_format) begin
iready <= 1'b1;
tvalid <= 1'b0;
tbit <= 1'b0;
end else if(cnt==3'h0) begin
iready <= tready;
tvalid <= ivalid;
tbit <= ibyte[0];
end else begin
iready <= 1'b0;
tvalid <= 1'b1;
tbit <= rbyte[cnt];
end
end
end
always @ (posedge clk or posedge rst)
if(rst) begin
raw_mode <= 1'b0;
cnt <= '0;
rbyte <= '0;
rcnt <= '0;
status <= '0;
end else begin
if(raw_mode) begin
cnt <= '0;
rbyte <= '0;
if(ivalid) begin
if (status==0) begin
rcnt[15:8] <= ibyte;
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(ivalid) begin
raw_mode <= 1'b1;
rcnt[ 7:0] <= ibyte;
end
cnt <= '0;
rbyte <= '0;
end else begin
if(cnt==3'h0) begin
if(ivalid & tready) begin
cnt <= cnt + 3'h1;
rbyte <= ibyte;
end
end else begin
if(tready)
cnt <= cnt + 3'h1;
end
end
end
end
huffman_inflate huffman_inflate_i(
.rst ( raw_mode | rst ),
.clk ( clk ),
.ivalid ( tvalid ),
.iready ( tready ),
.ibit ( tbit ),
.ovalid ( huffman_ovalid ),
.obyte ( huffman_obyte ),
.raw_format ( raw_format ),
.end_stream ( end_stream )
);
endmodule
module huffman_inflate(
input wire rst,
input wire clk,
input wire ivalid,
output wire iready,
input wire ibit,
output wire ovalid,
output wire [7:0] obyte,
output reg raw_format,
output reg end_stream
);
initial {raw_format, end_stream} = '0;
wire [ 4:0] CLCL [19]; assign CLCL[0]=5'd16; assign CLCL[1]=5'd17; assign CLCL[2]=5'd18; assign CLCL[3]=5'd0; assign CLCL[4]=5'd8; assign CLCL[5]=5'd7; assign CLCL[6]=5'd9; assign CLCL[7]=5'd6; assign CLCL[8]=5'd10; assign CLCL[9]=5'd5; assign CLCL[10]=5'd11; assign CLCL[11]=5'd4; assign CLCL[12]=5'd12; assign CLCL[13]=5'd3; assign CLCL[14]=5'd13; assign CLCL[15]=5'd2; assign CLCL[16]=5'd14; assign CLCL[17]=5'd1; assign CLCL[18]=5'd15;
wire [ 8:0] LENGTH_BASE [30]; assign LENGTH_BASE[0]=9'd0; assign LENGTH_BASE[1]=9'd3; assign LENGTH_BASE[2]=9'd4; assign LENGTH_BASE[3]=9'd5; assign LENGTH_BASE[4]=9'd6; assign LENGTH_BASE[5]=9'd7; assign LENGTH_BASE[6]=9'd8; assign LENGTH_BASE[7]=9'd9; assign LENGTH_BASE[8]=9'd10; assign LENGTH_BASE[9]=9'd11; assign LENGTH_BASE[10]=9'd13; assign LENGTH_BASE[11]=9'd15; assign LENGTH_BASE[12]=9'd17; assign LENGTH_BASE[13]=9'd19; assign LENGTH_BASE[14]=9'd23; assign LENGTH_BASE[15]=9'd27; assign LENGTH_BASE[16]=9'd31; assign LENGTH_BASE[17]=9'd35; assign LENGTH_BASE[18]=9'd43; assign LENGTH_BASE[19]=9'd51; assign LENGTH_BASE[20]=9'd59; assign LENGTH_BASE[21]=9'd67; assign LENGTH_BASE[22]=9'd83; assign LENGTH_BASE[23]=9'd99; assign LENGTH_BASE[24]=9'd115; assign LENGTH_BASE[25]=9'd131; assign LENGTH_BASE[26]=9'd163; assign LENGTH_BASE[27]=9'd195; assign LENGTH_BASE[28]=9'd227; assign LENGTH_BASE[29]=9'd258;
wire [ 2:0] LENGTH_EXTRA [30]; assign LENGTH_EXTRA[0]=3'd0; assign LENGTH_EXTRA[1]=3'd0; assign LENGTH_EXTRA[2]=3'd0; assign LENGTH_EXTRA[3]=3'd0; assign LENGTH_EXTRA[4]=3'd0; assign LENGTH_EXTRA[5]=3'd0; assign LENGTH_EXTRA[6]=3'd0; assign LENGTH_EXTRA[7]=3'd0; assign LENGTH_EXTRA[8]=3'd0; assign LENGTH_EXTRA[9]=3'd1; assign LENGTH_EXTRA[10]=3'd1; assign LENGTH_EXTRA[11]=3'd1; assign LENGTH_EXTRA[12]=3'd1; assign LENGTH_EXTRA[13]=3'd2; assign LENGTH_EXTRA[14]=3'd2; assign LENGTH_EXTRA[15]=3'd2; assign LENGTH_EXTRA[16]=3'd2; assign LENGTH_EXTRA[17]=3'd3; assign LENGTH_EXTRA[18]=3'd3; assign LENGTH_EXTRA[19]=3'd3; assign LENGTH_EXTRA[20]=3'd3; assign LENGTH_EXTRA[21]=3'd4; assign LENGTH_EXTRA[22]=3'd4; assign LENGTH_EXTRA[23]=3'd4; assign LENGTH_EXTRA[24]=3'd4; assign LENGTH_EXTRA[25]=3'd5; assign LENGTH_EXTRA[26]=3'd5; assign LENGTH_EXTRA[27]=3'd5; assign LENGTH_EXTRA[28]=3'd5; assign LENGTH_EXTRA[29]=3'd0;
wire [14:0] DISTANCE_BASE [30]; assign DISTANCE_BASE[0]=15'd1; assign DISTANCE_BASE[1]=15'd2; assign DISTANCE_BASE[2]=15'd3; assign DISTANCE_BASE[3]=15'd4; assign DISTANCE_BASE[4]=15'd5; assign DISTANCE_BASE[5]=15'd7; assign DISTANCE_BASE[6]=15'd9; assign DISTANCE_BASE[7]=15'd13; assign DISTANCE_BASE[8]=15'd17; assign DISTANCE_BASE[9]=15'd25; assign DISTANCE_BASE[10]=15'd33; assign DISTANCE_BASE[11]=15'd49; assign DISTANCE_BASE[12]=15'd65; assign DISTANCE_BASE[13]=15'd97; assign DISTANCE_BASE[14]=15'd129; assign DISTANCE_BASE[15]=15'd193; assign DISTANCE_BASE[16]=15'd257; assign DISTANCE_BASE[17]=15'd385; assign DISTANCE_BASE[18]=15'd513; assign DISTANCE_BASE[19]=15'd769; assign DISTANCE_BASE[20]=15'd1025; assign DISTANCE_BASE[21]=15'd1537; assign DISTANCE_BASE[22]=15'd2049; assign DISTANCE_BASE[23]=15'd3073; assign DISTANCE_BASE[24]=15'd4097; assign DISTANCE_BASE[25]=15'd6145; assign DISTANCE_BASE[26]=15'd8193; assign DISTANCE_BASE[27]=15'd12289; assign DISTANCE_BASE[28]=15'd16385; assign DISTANCE_BASE[29]=15'd24577;
wire [ 3:0] DISTANCE_EXTRA [30]; assign DISTANCE_EXTRA[0]=4'd0; assign DISTANCE_EXTRA[1]=4'd0; assign DISTANCE_EXTRA[2]=4'd0; assign DISTANCE_EXTRA[3]=4'd0; assign DISTANCE_EXTRA[4]=4'd1; assign DISTANCE_EXTRA[5]=4'd1; assign DISTANCE_EXTRA[6]=4'd2; assign DISTANCE_EXTRA[7]=4'd2; assign DISTANCE_EXTRA[8]=4'd3; assign DISTANCE_EXTRA[9]=4'd3; assign DISTANCE_EXTRA[10]=4'd4; assign DISTANCE_EXTRA[11]=4'd4; assign DISTANCE_EXTRA[12]=4'd5; assign DISTANCE_EXTRA[13]=4'd5; assign DISTANCE_EXTRA[14]=4'd6; assign DISTANCE_EXTRA[15]=4'd6; assign DISTANCE_EXTRA[16]=4'd7; assign DISTANCE_EXTRA[17]=4'd7; assign DISTANCE_EXTRA[18]=4'd8; assign DISTANCE_EXTRA[19]=4'd8; assign DISTANCE_EXTRA[20]=4'd9; assign DISTANCE_EXTRA[21]=4'd9; assign DISTANCE_EXTRA[22]=4'd10; assign DISTANCE_EXTRA[23]=4'd10; assign DISTANCE_EXTRA[24]=4'd11; assign DISTANCE_EXTRA[25]=4'd11; assign DISTANCE_EXTRA[26]=4'd12; assign DISTANCE_EXTRA[27]=4'd12; assign DISTANCE_EXTRA[28]=4'd13; assign DISTANCE_EXTRA[29]=4'd13;
reg irepeat = 1'b0;
reg srepeat = 1'b0;
reg symbol_valid = 1'b0;
reg [7:0] symbol = '0;
reg decoder_nreset = 1'b0;
reg [ 1:0] iword = '0;
reg [ 1:0] ibcnt = '0;
reg [ 4:0] precode_wpt = '0;
reg bfin = 1'b0;
reg bfix = 1'b0;
reg fixed_tree = 1'b0;
reg [13:0] precode_reg = '0;
wire [ 4:0] hclen = 5'd4 + {1'b0, precode_reg[13:10]};
wire [ 8:0] hlit = 9'd257 + precode_reg[ 4: 0];
wire [ 8:0] hdist = 9'd1 + {4'h0, precode_reg[ 9: 5]};
wire [ 8:0] hmax = hlit + hdist;
wire [ 8:0] hend = (hlit+9'd32>9'd288) ? hlit+9'd32 : 9'd288;
reg [ 4:0] lentree_wpt = '0;
reg [ 8:0] tree_wpt = '0;
wire lentree_codeen;
wire [ 5:0] lentree_code;
wire codetree_codeen;
wire [ 9:0] codetree_code;
wire distree_codeen;
wire [ 9:0] distree_code;
reg [ 2:0] repeat_code_pt = '0;
enum {REPEAT_NONE, REPEAT_PREVIOUS, REPEAT_ZERO_FEW, REPEAT_ZERO_MANY} repeat_mode = REPEAT_NONE;
reg [ 6:0] repeat_code='0;
reg [ 7:0] repeat_len ='0;
reg [ 5:0] repeat_val = '0;
reg lentree_run = 1'b0;
wire lentree_done;
reg tree_run = 1'b0;
wire codetree_done;
wire distree_done;
wire tree_done = (codetree_done & distree_done) | fixed_tree;
reg [ 2:0] tcnt =3'h0, tmax =3'h0;
reg [ 3:0] dscnt=4'h0, dsmax=4'h0;
enum {T, D, R, S} status = T;
wire lentree_ien = ~end_stream & ~raw_format & ivalid & lentree_done & ~lentree_codeen & (repeat_mode==REPEAT_NONE && repeat_len==8'd0) & (tree_wpt<hmax);
wire codetree_ien = ~end_stream & ~raw_format & ivalid & tree_done & ~codetree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (status==T);
wire distree_ien = ~end_stream & ~raw_format & ivalid & tree_done & ~distree_codeen & (tcnt==3'd0) & (dscnt==4'd0) & (status==D);
assign iready = end_stream | (~raw_format & (
( precode_wpt<17 || 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 & (status==T || status==D || (status==R && dscnt>4'd0)) ) ) );
reg [ 8:0] lengthb= '0;
reg [ 5:0] lengthe= '0;
wire [ 8:0] length = lengthb + lengthe;
reg [ 8:0] len_last = '0;
reg [15:0] distanceb='0;
reg [15:0] distancee='0;
wire [15:0] distance = distanceb + distancee;
reg lentree_wen = 1'b0;
reg [ 4:0] lentree_waddr = '0;
reg [ 2:0] lentree_wdata = '0;
reg codetree_wen = 1'b0;
reg [ 8:0] codetree_waddr = '0;
reg [ 5:0] codetree_wdata = '0;
reg distree_wen = 1'b0;
reg [ 4:0] distree_waddr = '0;
reg [ 5:0] distree_wdata = '0;
wire [ 5:0] lentree_raddr;
wire [ 5:0] lentree_rdata;
wire [ 9:0] codetree_raddr;
wire [ 9:0] codetree_rdata, codetree_rdata_fixed;
wire [ 5:0] distree_raddr;
wire [ 9:0] distree_rdata, distree_rdata_fixed;
task automatic lentree_write(input wen=1'b0, input [4:0] waddr='0, input [2:0] wdata='0);
lentree_wen <= wen;
lentree_waddr <= waddr;
lentree_wdata <= wdata;
endtask
task automatic codetree_write(input wen=1'b0, input [8:0] waddr='0, input [5:0] wdata='0);
codetree_wen <= wen;
codetree_waddr <= waddr;
codetree_wdata <= wdata;
endtask
task automatic distree_write(input wen=1'b0, input [4:0] waddr='0, input [5:0] wdata='0);
distree_wen <= wen;
distree_waddr <= waddr;
distree_wdata <= wdata;
endtask
task automatic reset_all_regs();
decoder_nreset <= 1'b0;
{bfin, bfix, fixed_tree} <= '0;
iword <= '0;
ibcnt <= '0;
precode_wpt <= '0;
precode_reg <= '0;
lentree_wpt <= '0;
lentree_run <= 1'b0;
tree_run <= 1'b0;
lentree_write();
codetree_write();
distree_write();
repeat_code_pt <= '0;
repeat_mode <= REPEAT_NONE;
repeat_code <= '0;
repeat_len <= '0;
repeat_val <= '0;
tree_wpt <= '0;
tcnt <= '0;
tmax <= '0;
lengthb <= '0;
lengthe <= '0;
distanceb<= '0;
distancee<= '0;
dscnt <= '0;
dsmax <= '0;
status <= T;
symbol_valid <= 1'b0;
symbol <= '0;
irepeat <= 1'b0;
srepeat <= 1'b0;
len_last <= '0;
endtask
always @ (posedge clk or posedge rst)
if(rst) begin
{raw_format, end_stream} <= '0;
reset_all_regs();
end else begin
symbol_valid <= 1'b0;
symbol <= '0;
irepeat <= 1'b0;
srepeat <= 1'b0;
decoder_nreset <= 1'b1;
lentree_write();
codetree_write();
distree_write();
if(precode_wpt<=2) begin
lentree_run <= 1'b0;
tree_run <= 1'b0;
if(ivalid) begin
precode_wpt <= precode_wpt + 5'd1;
if(precode_wpt==0) begin
bfin <= ibit;
end else if(precode_wpt==1) begin
bfix <= ibit;
end else begin
case({ibit,bfix})
2'b00 :
raw_format <= 1'b1;
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
lentree_run <= 1'b0;
tree_run <= 1'b0;
if(ivalid) begin
precode_reg <= {ibit, precode_reg[13:1]};
precode_wpt <= precode_wpt + 5'd1;
end
end else if(lentree_wpt<hclen) begin
lentree_run <= 1'b0;
tree_run <= 1'b0;
if(ivalid) begin
if(ibcnt<2'd2) begin
iword[ibcnt[0]] <= ibit;
ibcnt <= ibcnt + 2'd1;
end else begin
lentree_write(1'b1, CLCL[lentree_wpt], {ibit, iword});
ibcnt <= 2'd0;
lentree_wpt <= lentree_wpt + 5'd1;
end
end
end else if(lentree_wpt<19) begin
lentree_run <= 1'b0;
tree_run <= 1'b0;
lentree_write(1'b1, CLCL[lentree_wpt], '0);
lentree_wpt <= lentree_wpt + 5'd1;
end else if(~ (lentree_done | fixed_tree)) begin
lentree_run <= ~fixed_tree;
tree_run <= 1'b0;
end else if(tree_wpt<hmax) begin
lentree_run <= ~fixed_tree;
tree_run <= 1'b0;
if(repeat_code_pt>3'd0) begin
if(ivalid) begin
repeat_code_pt <= repeat_code_pt - 3'd1;
repeat_code[3'd7-repeat_code_pt] <= ibit;
end
end else if(repeat_mode>0) begin
case(repeat_mode)
REPEAT_PREVIOUS: begin
repeat_len <= repeat_code[6:5] + 8'd3;
end
REPEAT_ZERO_FEW: begin
repeat_len <= repeat_code[6:4] + 8'd3;
end
REPEAT_ZERO_MANY: begin
repeat_len <= repeat_code[6:0] + 8'd11;
end
default: begin
repeat_len <= 0;
end
endcase
repeat_mode <= REPEAT_NONE;
end else if(repeat_len>8'd0) begin
repeat_len <= repeat_len - 8'd1;
tree_wpt <= tree_wpt + 9'd1;
if(tree_wpt<288)
codetree_write(1'b1, tree_wpt, (tree_wpt<hlit) ? repeat_val : '0);
if(tree_wpt>=hlit && tree_wpt<(hlit+9'd32))
distree_write(1'b1, tree_wpt - hlit, (tree_wpt<hmax) ? repeat_val : '0);
end else if(lentree_codeen) begin
case(lentree_code)
16: begin // repeat previous
repeat_mode <= REPEAT_PREVIOUS;
repeat_code_pt <= 3'd2;
end
17: begin // repeat 0 for 3-10 times
repeat_mode <= REPEAT_ZERO_FEW;
repeat_val <= 0;
repeat_code_pt <= 3'd3;
end
18: begin // repeat 0 for 11-138 times
repeat_mode <= REPEAT_ZERO_MANY;
repeat_val <= 0;
repeat_code_pt <= 3'd7;
end
default: begin // normal value
repeat_mode <= REPEAT_NONE;
repeat_val <= lentree_code; // save previous code for repeat
repeat_code_pt <= 3'd0;
tree_wpt <= tree_wpt + 9'd1;
if(tree_wpt<288)
codetree_write(1'b1, tree_wpt, (tree_wpt<hlit) ? lentree_code : '0);
if(tree_wpt>=hlit && tree_wpt<(hlit+9'd32))
distree_write(1'b1, tree_wpt - hlit, (tree_wpt<hmax) ? lentree_code : '0);
end
endcase
repeat_code <= '0;
end
end else if(tree_wpt<hend) begin
lentree_run <= ~fixed_tree;
tree_run <= 1'b0;
if(tree_wpt<288)
codetree_write(1'b1, tree_wpt, '0);
if(tree_wpt>=hlit && tree_wpt<(hlit+9'd32))
distree_write(1'b1, tree_wpt - hlit, '0);
tree_wpt <= tree_wpt + 9'd1;
end else if(tree_wpt<hend+2) begin
lentree_run <= ~fixed_tree;
tree_run <= 1'b0;
tree_wpt <= tree_wpt + 9'd1;
end else if(~tree_done) begin
lentree_run <= ~fixed_tree;
tree_run <= 1'b1;
end else begin
lentree_run <= ~fixed_tree;
tree_run <= ~fixed_tree;
if(dscnt>4'd0) begin
if(ivalid) begin
dscnt <= dscnt - 4'd1;
distancee[dsmax-dscnt] <= ibit;
end
end else if(tcnt>3'd0) begin
if(ivalid) begin
tcnt <= tcnt - 3'd1;
lengthe[tmax-tcnt] <= ibit;
end
end else if(status==R) begin
status <= S;
len_last <= length;
srepeat <= 1'b1;
end else if(status==S) begin
if(len_last>0) begin
irepeat <= 1'b1;
len_last <= len_last - 9'd1;
end else
status <= T;
end else if(codetree_codeen) begin
if(codetree_code<10'd256) begin // normal symbol
symbol_valid <= 1'b1;
symbol <= codetree_code[7:0];
end else if(codetree_code==10'd256) begin // end symbol
end_stream <= bfin;
reset_all_regs();
end else begin // special symbol
lengthb<= LENGTH_BASE[codetree_code-10'd256];
lengthe<= '0;
tcnt <= LENGTH_EXTRA[codetree_code-10'd256];
tmax <= LENGTH_EXTRA[codetree_code-10'd256];
status <= D;
end
end else if(distree_codeen) begin
distanceb<= DISTANCE_BASE[distree_code];
distancee<= '0;
dscnt <= DISTANCE_EXTRA[distree_code];
dsmax <= DISTANCE_EXTRA[distree_code];
status <= R;
end
end
end
huffman_build #(
.NUMCODES ( 19 ),
.CODEBITS ( 3 ),
.BITLENGTH ( 7 ),
.OUTWIDTH ( 6 )
) lentree_builder (
.clk ( clk ),
.wren ( lentree_wen ),
.wraddr ( lentree_waddr ),
.wrdata ( lentree_wdata ),
.run ( lentree_run ),
.done ( lentree_done ),
.rdaddr ( lentree_raddr ),
.rddata ( lentree_rdata )
);
huffman_decode_symbol #(
.NUMCODES ( 19 ),
.OUTWIDTH ( 6 )
) lentree_decoder (
.rst ( ~decoder_nreset),
.clk ( clk ),
.ien ( lentree_ien ),
.ibit ( ibit ),
.oen ( lentree_codeen ),
.ocode ( lentree_code ),
.rdaddr ( lentree_raddr ),
.rddata ( lentree_rdata )
);
huffman_build #(
.NUMCODES ( 288 ),
.CODEBITS ( 5 ),
.BITLENGTH ( 15 ),
.OUTWIDTH ( 10 )
) codetree_builder (
.clk ( clk ),
.wren ( codetree_wen ),
.wraddr ( codetree_waddr ),
.wrdata ( (5)'(codetree_wdata) ),
.run ( tree_run ),
.done ( codetree_done ),
.rdaddr ( codetree_raddr ),
.rddata ( codetree_rdata )
);
fixed_codetree codetree_fixed(
.clk ( clk ),
.rdaddr ( codetree_raddr ),
.rddata ( codetree_rdata_fixed )
);
huffman_decode_symbol #(
.NUMCODES ( 288 ),
.OUTWIDTH ( 10 )
) codetree_decoder (
.rst ( ~decoder_nreset),
.clk ( clk ),
.ien ( codetree_ien ),
.ibit ( ibit ),
.oen ( codetree_codeen),
.ocode ( codetree_code ),
.rdaddr ( codetree_raddr ),
.rddata ( fixed_tree ? codetree_rdata_fixed : codetree_rdata )
);
huffman_build #(
.NUMCODES ( 32 ),
.CODEBITS ( 5 ),
.BITLENGTH ( 15 ),
.OUTWIDTH ( 10 )
) distree_builder (
.clk ( clk ),
.wren ( distree_wen ),
.wraddr ( distree_waddr ),
.wrdata ( (5)'(distree_wdata) ),
.run ( tree_run ),
.done ( distree_done ),
.rdaddr ( distree_raddr ),
.rddata ( distree_rdata )
);
fixed_distree distree_fixed(
.clk ( clk ),
.rdaddr ( distree_raddr ),
.rddata ( distree_rdata_fixed )
);
huffman_decode_symbol #(
.NUMCODES ( 32 ),
.OUTWIDTH ( 10 )
) distree_decoder (
.rst ( ~decoder_nreset),
.clk ( clk ),
.ien ( distree_ien ),
.ibit ( ibit ),
.oen ( distree_codeen ),
.ocode ( distree_code ),
.rdaddr ( distree_raddr ),
.rddata ( fixed_tree ? distree_rdata_fixed : distree_rdata )
);
repeat_buffer repeat_buffer_i(
.clk ( clk ),
.ivalid ( symbol_valid ),
.idata ( symbol ),
.repeat_en ( irepeat ),
.repeat_start ( srepeat ),
.repeat_dist ( distance ),
.ovalid ( ovalid ),
.odata ( obyte )
);
endmodule
module huffman_decode_symbol #(
parameter NUMCODES = 288,
parameter OUTWIDTH = 10
)(
rst, clk,
ien, ibit,
oen, ocode,
rdaddr, rddata
);
function automatic integer clogb2(input integer val);
integer valtmp;
valtmp = val;
for(clogb2=0; valtmp>0; clogb2=clogb2+1) valtmp = valtmp>>1;
endfunction
input rst, clk;
input ien, ibit;
output oen = 1'b0;
output [ OUTWIDTH-1:0] ocode = '0;
output [clogb2(2*NUMCODES-1)-1:0] rdaddr;
input [ OUTWIDTH-1:0] rddata;
wire rst, clk;
wire 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;
assign rdaddr = {ntpos, ibit};
assign ntpos = ienl ? (clogb2(2*NUMCODES-1)-1)'(rddata<(OUTWIDTH)'(NUMCODES) ? '0 : rddata-(OUTWIDTH)'(NUMCODES)) : tpos;
always @ (posedge clk or posedge rst)
if(rst)
ienl <= 1'b0;
else
ienl <= ien;
always @ (posedge clk or posedge rst)
if(rst)
tpos <= '0;
else
tpos <= ntpos;
always_comb
if(ienl && rddata<NUMCODES) begin
oen <= 1'b1;
ocode <= rddata;
end else begin
oen <= 1'b0;
ocode <= '0;
end
endmodule
module fixed_codetree (
input logic clk,
input logic [9:0] rdaddr,
output logic [9:0] rddata
);
wire [9:0] rom [1024]; assign rom[0]=10'd289; assign rom[1]=10'd370; assign rom[2]=10'd290; assign rom[3]=10'd307; assign rom[4]=10'd546; assign rom[5]=10'd291; assign rom[6]=10'd561; assign rom[7]=10'd292; assign rom[8]=10'd293; assign rom[9]=10'd300; assign rom[10]=10'd294; assign rom[11]=10'd297; assign rom[12]=10'd295; assign rom[13]=10'd296; assign rom[14]=10'd0; assign rom[15]=10'd1; assign rom[16]=10'd2; assign rom[17]=10'd3; assign rom[18]=10'd298; assign rom[19]=10'd299; assign rom[20]=10'd4; assign rom[21]=10'd5; assign rom[22]=10'd6; assign rom[23]=10'd7; assign rom[24]=10'd301; assign rom[25]=10'd304; assign rom[26]=10'd302; assign rom[27]=10'd303; assign rom[28]=10'd8; assign rom[29]=10'd9; assign rom[30]=10'd10; assign rom[31]=10'd11; assign rom[32]=10'd305; assign rom[33]=10'd306; assign rom[34]=10'd12; assign rom[35]=10'd13; assign rom[36]=10'd14; assign rom[37]=10'd15; assign rom[38]=10'd308; assign rom[39]=10'd339; assign rom[40]=10'd309; assign rom[41]=10'd324; assign rom[42]=10'd310; assign rom[43]=10'd317; assign rom[44]=10'd311; assign rom[45]=10'd314; assign rom[46]=10'd312; assign rom[47]=10'd313; assign rom[48]=10'd16; assign rom[49]=10'd17; assign rom[50]=10'd18; assign rom[51]=10'd19; assign rom[52]=10'd315; assign rom[53]=10'd316; assign rom[54]=10'd20; assign rom[55]=10'd21; assign rom[56]=10'd22; assign rom[57]=10'd23; assign rom[58]=10'd318; assign rom[59]=10'd321; assign rom[60]=10'd319; assign rom[61]=10'd320; assign rom[62]=10'd24; assign rom[63]=10'd25; assign rom[64]=10'd26; assign rom[65]=10'd27; assign rom[66]=10'd322; assign rom[67]=10'd323; assign rom[68]=10'd28; assign rom[69]=10'd29; assign rom[70]=10'd30; assign rom[71]=10'd31; assign rom[72]=10'd325; assign rom[73]=10'd332; assign rom[74]=10'd326; assign rom[75]=10'd329; assign rom[76]=10'd327; assign rom[77]=10'd328; assign rom[78]=10'd32; assign rom[79]=10'd33; assign rom[80]=10'd34; assign rom[81]=10'd35; assign rom[82]=10'd330; assign rom[83]=10'd331; assign rom[84]=10'd36; assign rom[85]=10'd37; assign rom[86]=10'd38; assign rom[87]=10'd39; assign rom[88]=10'd333; assign rom[89]=10'd336; assign rom[90]=10'd334; assign rom[91]=10'd335; assign rom[92]=10'd40; assign rom[93]=10'd41; assign rom[94]=10'd42; assign rom[95]=10'd43; assign rom[96]=10'd337; assign rom[97]=10'd338; assign rom[98]=10'd44; assign rom[99]=10'd45; assign rom[100]=10'd46; assign rom[101]=10'd47; assign rom[102]=10'd340; assign rom[103]=10'd355; assign rom[104]=10'd341; assign rom[105]=10'd348; assign rom[106]=10'd342; assign rom[107]=10'd345; assign rom[108]=10'd343; assign rom[109]=10'd344; assign rom[110]=10'd48; assign rom[111]=10'd49; assign rom[112]=10'd50; assign rom[113]=10'd51; assign rom[114]=10'd346; assign rom[115]=10'd347; assign rom[116]=10'd52; assign rom[117]=10'd53; assign rom[118]=10'd54; assign rom[119]=10'd55; assign rom[120]=10'd349; assign rom[121]=10'd352; assign rom[122]=10'd350; assign rom[123]=10'd351; assign rom[124]=10'd56; assign rom[125]=10'd57; assign rom[126]=10'd58; assign rom[127]=10'd59; assign rom[128]=10'd353; assign rom[129]=10'd354; assign rom[130]=10'd60; assign rom[131]=10'd61; assign rom[132]=10'd62; assign rom[133]=10'd63; assign rom[134]=10'd356; assign rom[135]=10'd363; assign rom[136]=10'd357; assign rom[137]=10'd360; assign rom[138]=10'd358; assign rom[139]=10'd359; assign rom[140]=10'd64; assign rom[141]=10'd65; assign rom[142]=10'd66; assign rom[143]=10'd67; assign rom[144]=10'd361; assign rom[145]=10'd362; assign rom[146]=10'd68; assign rom[147]=10'd69; assign rom[148]=10'd70; assign rom[149]=10'd71; assign rom[150]=10'd364; assign rom[151]=10'd367; assign rom[152]=10'd365; assign rom[153]=10'd366; assign rom[154]=10'd72; assign rom[155]=10'd73; assign rom[156]=10'd74; assign rom[157]=10'd75; assign rom[158]=10'd368; assign rom[159]=10'd369; assign rom[160]=10'd76; assign rom[161]=10'd77; assign rom[162]=10'd78; assign rom[163]=10'd79; assign rom[164]=10'd371; assign rom[165]=10'd434; assign rom[166]=10'd372; assign rom[167]=10'd403; assign rom[168]=10'd373; assign rom[169]=10'd388; assign rom[170]=10'd37
always @ (posedge clk)
rddata <= rom[rdaddr];
endmodule
module fixed_distree (
input logic clk,
input logic [5:0] rdaddr,
output logic [9:0] rddata
);
wire [9:0] rom [64]; assign rom[0]=10'd33; assign rom[1]=10'd48; assign rom[2]=10'd34; assign rom[3]=10'd41; assign rom[4]=10'd35; assign rom[5]=10'd38; assign rom[6]=10'd36; assign rom[7]=10'd37; assign rom[8]=10'd0; assign rom[9]=10'd1; assign rom[10]=10'd2; assign rom[11]=10'd3; assign rom[12]=10'd39; assign rom[13]=10'd40; assign rom[14]=10'd4; assign rom[15]=10'd5; assign rom[16]=10'd6; assign rom[17]=10'd7; assign rom[18]=10'd42; assign rom[19]=10'd45; assign rom[20]=10'd43; assign rom[21]=10'd44; assign rom[22]=10'd8; assign rom[23]=10'd9; assign rom[24]=10'd10; assign rom[25]=10'd11; assign rom[26]=10'd46; assign rom[27]=10'd47; assign rom[28]=10'd12; assign rom[29]=10'd13; assign rom[30]=10'd14; assign rom[31]=10'd15; assign rom[32]=10'd49; assign rom[33]=10'd56; assign rom[34]=10'd50; assign rom[35]=10'd53; assign rom[36]=10'd51; assign rom[37]=10'd52; assign rom[38]=10'd16; assign rom[39]=10'd17; assign rom[40]=10'd18; assign rom[41]=10'd19; assign rom[42]=10'd54; assign rom[43]=10'd55; assign rom[44]=10'd20; assign rom[45]=10'd21; assign rom[46]=10'd22; assign rom[47]=10'd23; assign rom[48]=10'd57; assign rom[49]=10'd60; assign rom[50]=10'd58; assign rom[51]=10'd59; assign rom[52]=10'd24; assign rom[53]=10'd25; assign rom[54]=10'd26; assign rom[55]=10'd27; assign rom[56]=10'd61; assign rom[57]=10'd62; assign rom[58]=10'd28; assign rom[59]=10'd29; assign rom[60]=10'd30; assign rom[61]=10'd31; assign rom[62]=10'd0; assign rom[63]=10'd0;
always @ (posedge clk)
rddata <= rom[rdaddr];
endmodule
module huffman_build #(
parameter NUMCODES = 288,
parameter CODEBITS = 5,
parameter BITLENGTH= 15,
parameter OUTWIDTH = 10
) (
clk,
wren, wraddr, wrdata,
run , done,
rdaddr, rddata
);
function automatic integer clogb2(input integer val);
integer valtmp;
valtmp = val;
for(clogb2=0; valtmp>0; clogb2=clogb2+1) valtmp = valtmp>>1;
endfunction
input clk;
input wren;
input [ clogb2(NUMCODES-1)-1:0] wraddr;
input [ CODEBITS -1:0] wrdata;
input run;
output done;
input [clogb2(2*NUMCODES-1)-1:0] rdaddr;
output [ OUTWIDTH-1:0] rddata;
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;
wire [ OUTWIDTH-1:0] rddata;
reg [clogb2(NUMCODES)-1:0] blcount [BITLENGTH];
reg [ 31:0] nextcode [BITLENGTH+1];
reg clear_tree2d = 1'b0;
reg build_tree2d = 1'b0;
reg [clogb2(BITLENGTH)-1:0] idx = '0;
reg [clogb2(2*NUMCODES+1)-1:0] clearidx = '0;
reg [ clogb2(NUMCODES)-1:0] nn='0, nnn, lnn='0;
reg [CODEBITS-1:0] ii='0, lii='0;
reg [CODEBITS-1:0] blenn, blen = '0;
wire [31:0] tree1d = nextcode[blen];
wire islast = (blen==0 || ii==0);
reg [clogb2(2*NUMCODES-1)-1:0] nodefilled = '0;
reg [clogb2(2*NUMCODES-1)-1:0] ntreepos, treepos='0;
wire [clogb2(2*NUMCODES-1) :0] ntpos= {ntreepos, tree1d[ii]};
reg [clogb2(2*NUMCODES-1) :0] tpos = '0;
wire rdfilled;
reg valid = 1'b0;
wire [OUTWIDTH-1:0] wrtree2d = (lii==0) ? lnn : nodefilled + (clogb2(2*NUMCODES-1))'(NUMCODES);
reg alldone = 1'b0;
assign done = alldone & run;
initial for(int i=0; i< BITLENGTH; i++) blcount[i] = '0;
initial for(int i=0; i<=BITLENGTH; i++) nextcode[i] = '0;
always @ (posedge clk) begin
valid <= build_tree2d & nn<NUMCODES & blen>0;
treepos <= ntreepos;
tpos <= ntpos;
lii <= ii;
lnn <= nn;
end
always @ (posedge clk)
if(islast)
blen <= blenn;
always @ (posedge clk)
if(done) begin
for(int i=0; i<BITLENGTH; i++)
blcount[i] <= '0;
end else begin
if(wren && wrdata<BITLENGTH)
blcount[wrdata] <= blcount[wrdata] + (clogb2(NUMCODES))'(1);
end
always_comb
if(build_tree2d)
nnn <= (nn<NUMCODES && islast) ? nn + (clogb2(NUMCODES))'(1) : nn;
else
nnn <= (idx<BITLENGTH) ? '1 : '0;
always @ (posedge clk)
nn <= nnn;
always @ (posedge clk) begin
nextcode[0] <= 0;
alldone <= 1'b0;
if(run) begin
if(~clear_tree2d) begin
if(clearidx<(2*NUMCODES)) begin
clearidx <= clearidx + (clogb2(2*NUMCODES+1))'(1);
end else begin
clear_tree2d <= 1'b1;
end
end else if(build_tree2d) begin
if(nn<NUMCODES) begin
if(islast) begin
ii <= blenn - (CODEBITS)'(1);
if(blen>0)
nextcode[blen] <= tree1d + 1;
end else
ii <= ii - (CODEBITS)'(1);
end else
alldone <= 1'b1;
end else begin
if(idx<BITLENGTH) begin
idx <= idx + (clogb2(BITLENGTH))'(1);
nextcode[idx+1] <= ( (nextcode[idx] + blcount[idx]) << 1 );
end else begin
ii <= blen - (CODEBITS)'(1);
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
always_comb
if(~run)
ntreepos <= 0;
else if(valid) begin
if(~rdfilled)
ntreepos <= (clogb2(2*NUMCODES-1))'(rddata) - (clogb2(2*NUMCODES-1))'(NUMCODES);
else
ntreepos <= (lii==0) ? '0 : nodefilled;
end else
ntreepos <= treepos;
always @ (posedge clk)
if(~run)
nodefilled <= 1;
else if(valid & rdfilled & lii>0)
nodefilled <= nodefilled + (clogb2(2*NUMCODES-1))'(1);
RamSinglePort #(
.SIZE ( NUMCODES ),
.WIDTH ( CODEBITS )
) ram_for_bitlens (
.clk ( clk ),
.wen ( wren ),
.waddr ( wraddr ),
.wdata ( wrdata ),
.raddr ( (clogb2(NUMCODES-1))'(nnn) + (clogb2(NUMCODES-1))'(1) ),
.rdata ( blenn )
);
RamSinglePort #(
.SIZE ( NUMCODES * 2 ),
.WIDTH ( OUTWIDTH + 1 )
) ram_for_tree2d (
.clk ( clk ),
.wen ( clearidx<(2*NUMCODES) | (valid & rdfilled) ),
.waddr ( (clogb2(2*NUMCODES-1))'(clearidx<(2*NUMCODES) ? clearidx : tpos ) ),
.wdata ( clearidx<(2*NUMCODES) ? {1'b1,{OUTWIDTH{1'b0}}} : {1'b0, wrtree2d} ),
.raddr ( (clogb2(2*NUMCODES-1))'(alldone ? rdaddr : ntpos ) ),
.rdata ( {rdfilled, rddata} )
);
endmodule
module repeat_buffer #(
parameter DWIDTH = 8
) (
input clk,
input ivalid,
input [DWIDTH-1:0] idata,
input repeat_en,
input repeat_start,
input [ 15:0] repeat_dist,
output ovalid,
output [DWIDTH-1:0] odata
);
wire [15:0] MAXLEN = 16'd33792;
reg [15:0] wptr = '0;
reg [15:0] rptr = '0;
reg [15:0] sptr = '0;
reg [15:0] eptr = '0;
wire [15:0] sptrw = (wptr<repeat_dist) ? wptr + MAXLEN - repeat_dist : wptr - repeat_dist;
wire [15:0] eptrw = (wptr<16'd1) ? wptr + MAXLEN - 16'd1 : wptr - 16'd1;
reg repeat_valid = 1'b0;
wire [DWIDTH-1:0] repeat_data;
assign ovalid = ivalid | repeat_valid;
assign odata = repeat_valid ? repeat_data : idata;
always @ (posedge clk)
if(ovalid)
wptr <= (wptr<(MAXLEN-16'd1)) ? wptr+16'd1 : '0;
always @ (posedge clk) begin
if(repeat_start) begin
rptr <= sptrw;
sptr <= sptrw;
eptr <= eptrw;
end else if(repeat_en) begin
if(rptr!=eptr)
rptr <= (rptr<(MAXLEN-16'd1)) ? rptr+16'd1 : '0;
else
rptr <= sptr;
end
end
always @ (posedge clk)
repeat_valid <= repeat_en;
RamSinglePort #(
.SIZE ( 33792 ),
.WIDTH ( DWIDTH )
) ram_for_bitlens (
.clk ( clk ),
.wen ( ovalid ),
.waddr ( wptr ),
.wdata ( odata ),
.raddr ( rptr ),
.rdata ( repeat_data )
);
endmodule
module unfilter(
input wire rst,
input wire clk,
// config parameter
input wire [ 1:0] bpp, // bytes per pixel (-1)
input wire [13:0] bpr, // bytes per row
// data input
input wire ivalid,
input wire [ 7:0] idata,
// data output
output reg ovalid,
output reg [ 7:0] odata
);
initial ovalid = 1'b0;
initial odata = '0;
function automatic logic [7:0] paeth(input [7:0] a, input [7:0] b, input [7:0] c);
automatic logic signed [10:0] sa = {3'h0, a};
automatic logic signed [10:0] sb = {3'h0, b};
automatic logic signed [10:0] sc = {3'h0, c};
automatic logic signed [10:0] p = sa + sb - sc;
automatic logic signed [10:0] pa = p > sa ? p - sa : sa - p;
automatic logic signed [10:0] pb = p > sb ? p - sb : sb - p;
automatic logic signed [10:0] pc = p > sc ? p - sc : sc - p;
if (pa <= pb && pa <= pc)
return a;
else if (pb <= pc)
return b;
else
return c;
endfunction
reg nfirstrow = 1'b0;
reg [13:0] col = '0;
reg [ 2:0] mode = '0;
reg [ 7:0] fdata;
wire [ 7:0] LLdata, UUdata, ULdata;
wire nfirstcol = col > (14'h1+bpp);
wire [ 8:0] SSdata = (nfirstcol ? {1'b0,LLdata} : 9'h0) + (nfirstrow ? {1'b0,UUdata} : 9'h0);
always @ (posedge clk or posedge rst)
if(rst) begin
nfirstrow <= 1'b0;
col <= '0;
end else begin
if(ivalid) begin
if(col<bpr) begin
col <= col + 14'h1;
end else begin
nfirstrow <= 1'b1;
col <= '0;
end
end
end
always @ (posedge clk or posedge rst)
if(rst)
mode <= '0;
else begin
if(ivalid && col==14'h0)
mode <= idata[2:0];
end
always_comb
case(mode)
3'd0 : fdata <= idata;
3'd1 : fdata <= idata + (nfirstcol ? LLdata : 8'h0);
3'd2 : fdata <= idata + (nfirstrow ? UUdata : 8'h0);
3'd3 : fdata <= idata + SSdata[8:1];
default: fdata <= idata + paeth(
(nfirstcol ? LLdata : 8'h0),
(nfirstrow ? UUdata : 8'h0),
(nfirstrow&nfirstcol ? ULdata : 8'h0)
);
endcase
always @ (posedge clk or posedge rst)
if(rst) begin
ovalid <= 1'b0;
odata <= '0;
end else begin
ovalid <= (ivalid && col!=14'h0);
if(ivalid && col!=14'h0)
odata <= fdata;
end
shift_regs #(
.MAXLEN_LEVEL ( 2 ),
.DWIDTH ( 8 )
) shift_i1 (
.rst ( rst ),
.clk ( clk ),
.length ( bpp ),
.ivalid ( ivalid ),
.idata ( fdata ),
.odata ( LLdata )
);
shift_buffer #(
.MAXLEN_LEVEL ( 14 ),
.DWIDTH ( 8 )
) shift_i2 (
.rst ( rst ),
.clk ( clk ),
.length ( bpr ),
.ivalid ( ivalid ),
.idata ( fdata ),
.odata ( UUdata )
);
shift_regs #(
.MAXLEN_LEVEL ( 2 ),
.DWIDTH ( 8 )
) shift_i3 (
.rst ( rst ),
.clk ( clk ),
.length ( bpp ),
.ivalid ( ivalid ),
.idata ( UUdata ),
.odata ( ULdata )
);
endmodule
module shift_buffer #(
parameter MAXLEN_LEVEL = 14,
parameter DWIDTH = 8
) (
input rst,
input clk,
input [MAXLEN_LEVEL-1:0] length, // length = 1 ~ (1<<MAXLEN_LEVEL)
input ivalid,
input [ DWIDTH-1:0] idata,
output [ DWIDTH-1:0] odata
);
localparam MAXLEN = 1<<MAXLEN_LEVEL;
reg rvalid = 1'b0;
wire [ DWIDTH-1:0] rdata;
reg [ DWIDTH-1:0] ldata = '0;
reg [ DWIDTH-1:0] lidata= '0;
reg [MAXLEN_LEVEL-1:0] ptr = '0;
always @ (posedge clk or posedge rst)
if(rst)
lidata <= '0;
else begin
if(ivalid)
lidata <= idata;
end
always @ (posedge clk or posedge rst)
if(rst)
ptr <= '0;
else begin
if(ivalid) begin
if(ptr<(length-1))
ptr <= ptr + (MAXLEN_LEVEL)'(1);
else
ptr <= '0;
end
end
always @ (posedge clk or posedge rst)
if(rst) begin
ldata <= '0;
rvalid <= 1'b0;
end else begin
if(rvalid)
ldata <= rdata;
rvalid <= ivalid;
end
assign odata = (length=='0) ? lidata : (rvalid ? rdata : ldata);
RamSinglePort #(
.SIZE ( MAXLEN ),
.WIDTH ( DWIDTH )
) ram_for_bitlens (
.clk ( clk ),
.wen ( ivalid ),
.waddr ( ptr ),
.wdata ( idata ),
.raddr ( ptr ),
.rdata ( rdata )
);
endmodule
module shift_regs #(
parameter MAXLEN_LEVEL = 2,
parameter DWIDTH = 8
) (
input rst,
input clk,
input [MAXLEN_LEVEL-1:0] length, // length = 1~(1<<MAXLEN_LEVEL)
input ivalid,
input [ DWIDTH-1:0] idata,
output [ DWIDTH-1:0] odata
);
localparam MAXLEN = 1<<MAXLEN_LEVEL;
reg [DWIDTH-1:0] shift_data [MAXLEN] = '{MAXLEN{'0}};
assign odata = shift_data [length];
generate
genvar ii;
for(ii=0; ii<MAXLEN; ii++) begin : generate_shift_registers
if(ii==0) begin
always @ (posedge clk or posedge rst)
if(rst) begin
shift_data[ii] <= '0;
end else begin
if(ivalid)
shift_data[ii] <= idata;
end
end else begin
always @ (posedge clk or posedge rst)
if(rst) begin
shift_data[ii] <= '0;
end else begin
if(ivalid)
shift_data[ii] <= shift_data[ii-1];
end
end
end
endgenerate
endmodule
module RamSinglePort #(
parameter SIZE = 1024,
parameter WIDTH = 32
)(
clk,
wen,
waddr,
wdata,
raddr,
rdata
);
function automatic integer clogb2(input integer val);
integer valtmp;
valtmp = val;
for(clogb2=0; valtmp>0; clogb2=clogb2+1) valtmp = valtmp>>1;
endfunction
input clk;
input wen;
input [clogb2(SIZE-1)-1:0] waddr;
input [WIDTH-1:0] wdata;
input [clogb2(SIZE-1)-1:0] raddr;
output [WIDTH-1:0] rdata;
wire clk;
wire wen;
wire [clogb2(SIZE-1)-1:0] waddr;
wire [WIDTH-1:0] wdata;
wire [clogb2(SIZE-1)-1:0] raddr;
reg [WIDTH-1:0] rdata;
reg [WIDTH-1:0] mem [SIZE];
always @ (posedge clk)
if(wen)
mem[waddr] <= wdata;
initial rdata = '0;
always @ (posedge clk)
rdata <= mem[raddr];
endmodule