mirror of
https://github.com/WangXuan95/Hard-PNG.git
synced 2025-01-13 20:22:52 +08:00
1216 lines
87 KiB
Systemverilog
1216 lines
87 KiB
Systemverilog
|
|
||
|
//--------------------------------------------------------------------------------------------------------
|
||
|
// Module : hard_png
|
||
|
// Type : synthesizable, IP's top
|
||
|
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||
|
// Function: png image decoder
|
||
|
//--------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
module hard_png (
|
||
|
input wire rstn,
|
||
|
input wire clk,
|
||
|
// png data input stream
|
||
|
input wire ivalid,
|
||
|
output reg iready,
|
||
|
input wire [ 7:0] ibyte,
|
||
|
// image frame configuration output
|
||
|
output reg newframe,
|
||
|
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
|
||
|
// pixel output
|
||
|
output reg ovalid,
|
||
|
output wire [ 7:0] opixelr, opixelg, opixelb, opixela
|
||
|
);
|
||
|
|
||
|
initial newframe = 1'b0;
|
||
|
initial ovalid = 1'b0;
|
||
|
|
||
|
reg imagevalid = '0;
|
||
|
|
||
|
reg isplte = '0;
|
||
|
|
||
|
reg [ 1:0] bpp = '0; // bytes per pixel
|
||
|
reg [13:0] ppr = '0; // pixel per row
|
||
|
reg [13:0] bpr = '0; // bytes per row
|
||
|
reg [31:0] rpf = '0; // rows per frame
|
||
|
|
||
|
assign colortype = isplte ? 3'd4 : {1'b0,bpp};
|
||
|
|
||
|
assign width = ppr;
|
||
|
assign height = rpf;
|
||
|
|
||
|
reg pvalid;
|
||
|
reg pready;
|
||
|
reg [ 7:0] pbyte;
|
||
|
|
||
|
reg mvalid = '0;
|
||
|
reg [ 7:0] mbyte = '0;
|
||
|
|
||
|
reg bvalid = '0;
|
||
|
reg [ 7:0] bbyte = '0;
|
||
|
|
||
|
reg plte_wen = '0;
|
||
|
reg [ 7:0] plte_waddr = '0;
|
||
|
reg [23:0] plte_wdata = '0;
|
||
|
reg [23:0] plte_rdata;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
// png parser
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
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=ii+1) begin : generate_latchbytes_connect
|
||
|
assign lastbytes[ii] = latchbytes[ii];
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn)
|
||
|
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 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;
|
||
|
|
||
|
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(imagevalid && cnt>0 && curr_name==IDAT && gapcnt==2'd0) begin
|
||
|
iready = pready;
|
||
|
pvalid = ivalid;
|
||
|
pbyte = ibyte;
|
||
|
end else begin
|
||
|
iready = 1'b1;
|
||
|
pvalid = 1'b0;
|
||
|
pbyte = '0;
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) 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;
|
||
|
newframe <= 1'b0;
|
||
|
plte_wen <= 1'b0;
|
||
|
plte_waddr <= '0;
|
||
|
plte_wdata <= '0;
|
||
|
plte_bytecnt <= '0;
|
||
|
plte_pixcnt <= '0;
|
||
|
end else begin
|
||
|
newframe <= 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
|
||
|
newframe <= 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(pready)
|
||
|
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
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
// uz_inflate
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
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;
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mvalid <= 1'b0;
|
||
|
mbyte <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) 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;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_comb
|
||
|
if(~imagevalid) begin
|
||
|
raw_ovalid = 1'b0;
|
||
|
raw_obyte = '0;
|
||
|
pready = 1'b0;
|
||
|
tvalid = 1'b0;
|
||
|
tbit = 1'b0;
|
||
|
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
|
||
|
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;
|
||
|
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;
|
||
|
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
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// huffman inflate
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
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_new = 1'b1;
|
||
|
|
||
|
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} 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);
|
||
|
|
||
|
assign tready = end_stream | (~raw_format & (
|
||
|
( 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)) ) ) );
|
||
|
|
||
|
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;
|
||
|
reg [ 9:0] codetree_rdata_fixed;
|
||
|
wire [ 5:0] distree_raddr;
|
||
|
wire [ 9:0] distree_rdata;
|
||
|
reg [ 9:0] 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;
|
||
|
{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;
|
||
|
huffman_status <= T;
|
||
|
symbol_valid <= 1'b0;
|
||
|
symbol <= '0;
|
||
|
irepeat <= 1'b0;
|
||
|
srepeat <= 1'b0;
|
||
|
len_last <= '0;
|
||
|
endtask
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
{raw_format, end_stream} <= '0;
|
||
|
decoder_new <= 1'b1;
|
||
|
reset_all_regs;
|
||
|
end else begin
|
||
|
if(raw_mode) begin
|
||
|
{raw_format, end_stream} <= '0;
|
||
|
decoder_new <= 1'b1;
|
||
|
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();
|
||
|
if(precode_wpt<=2) begin
|
||
|
lentree_run <= 1'b0;
|
||
|
tree_run <= 1'b0;
|
||
|
if(tvalid) begin
|
||
|
precode_wpt <= precode_wpt + 5'd1;
|
||
|
if(precode_wpt==0) begin
|
||
|
bfin <= tbit;
|
||
|
end else if(precode_wpt==1) begin
|
||
|
bfix <= tbit;
|
||
|
end else begin
|
||
|
case({tbit,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(tvalid) begin
|
||
|
precode_reg <= {tbit, 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(tvalid) begin
|
||
|
if(ibcnt<2'd2) begin
|
||
|
iword[ibcnt[0]] <= tbit;
|
||
|
ibcnt <= ibcnt + 2'd1;
|
||
|
end else begin
|
||
|
lentree_write(1'b1, CLCL[lentree_wpt], {tbit, 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(tvalid) begin
|
||
|
repeat_code_pt <= repeat_code_pt - 3'd1;
|
||
|
repeat_code[3'd7-repeat_code_pt] <= tbit;
|
||
|
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(tvalid) begin
|
||
|
dscnt <= dscnt - 4'd1;
|
||
|
distancee[dsmax-dscnt] <= tbit;
|
||
|
end
|
||
|
end else if(tcnt>3'd0) begin
|
||
|
if(tvalid) begin
|
||
|
tcnt <= tcnt - 3'd1;
|
||
|
lengthe[tmax-tcnt] <= tbit;
|
||
|
end
|
||
|
end else if(huffman_status==R) begin
|
||
|
huffman_status <= S;
|
||
|
len_last <= length;
|
||
|
srepeat <= 1'b1;
|
||
|
end else if(huffman_status==S) begin
|
||
|
if(len_last>0) begin
|
||
|
irepeat <= 1'b1;
|
||
|
len_last <= len_last - 9'd1;
|
||
|
end else
|
||
|
huffman_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];
|
||
|
huffman_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];
|
||
|
huffman_status <= R;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// lentree huffman builder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_builder #(
|
||
|
.NUMCODES ( 19 ),
|
||
|
.CODEBITS ( 3 ),
|
||
|
.BITLENGTH ( 7 ),
|
||
|
.OUTWIDTH ( 6 )
|
||
|
) lentree_builder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.wren ( lentree_wen ),
|
||
|
.wraddr ( lentree_waddr ),
|
||
|
.wrdata ( lentree_wdata ),
|
||
|
.run ( lentree_run ),
|
||
|
.done ( lentree_done ),
|
||
|
.rdaddr ( lentree_raddr ),
|
||
|
.rddata ( lentree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// lentree huffman decoder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_decoder #(
|
||
|
.NUMCODES ( 19 ),
|
||
|
.OUTWIDTH ( 6 )
|
||
|
) lentree_decoder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.inew ( decoder_new ),
|
||
|
.ien ( lentree_ien ),
|
||
|
.ibit ( tbit ),
|
||
|
.oen ( lentree_codeen ),
|
||
|
.ocode ( lentree_code ),
|
||
|
.rdaddr ( lentree_raddr ),
|
||
|
.rddata ( lentree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// codetree huffman builder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_builder #(
|
||
|
.NUMCODES ( 288 ),
|
||
|
.CODEBITS ( 5 ),
|
||
|
.BITLENGTH ( 15 ),
|
||
|
.OUTWIDTH ( 10 )
|
||
|
) codetree_builder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.wren ( codetree_wen ),
|
||
|
.wraddr ( codetree_waddr ),
|
||
|
.wrdata ( (5)'(codetree_wdata) ),
|
||
|
.run ( tree_run ),
|
||
|
.done ( codetree_done ),
|
||
|
.rdaddr ( codetree_raddr ),
|
||
|
.rddata ( codetree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// codetree_fixed
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
wire [9:0] rom_fixed_codetree [1024];
|
||
|
assign rom_fixed_codetree[0]=10'd289; assign rom_fixed_codetree[1]=10'd370; assign rom_fixed_codetree[2]=10'd290; assign rom_fixed_codetree[3]=10'd307; assign rom_fixed_codetree[4]=10'd546; assign rom_fixed_codetree[5]=10'd291; assign rom_fixed_codetree[6]=10'd561; assign rom_fixed_codetree[7]=10'd292; assign rom_fixed_codetree[8]=10'd293; assign rom_fixed_codetree[9]=10'd300; assign rom_fixed_codetree[10]=10'd294; assign rom_fixed_codetree[11]=10'd297; assign rom_fixed_codetree[12]=10'd295; assign rom_fixed_codetree[13]=10'd296; assign rom_fixed_codetree[14]=10'd0; assign rom_fixed_codetree[15]=10'd1; assign rom_fixed_codetree[16]=10'd2; assign rom_fixed_codetree[17]=10'd3; assign rom_fixed_codetree[18]=10'd298; assign rom_fixed_codetree[19]=10'd299; assign rom_fixed_codetree[20]=10'd4; assign rom_fixed_codetree[21]=10'd5; assign rom_fixed_codetree[22]=10'd6; assign rom_fixed_codetree[23]=10'd7; assign rom_fixed_codetree[24]=10'd301; assign rom_fixed_codetree[25]=10'd304; assign rom_fixed_codetree[26]=10'd302; assign rom_fixed_codetree[27]=10'd303; assign rom_fixed_codetree[28]=10'd8; assign rom_fixed_codetree[29]=10'd9; assign rom_fixed_codetree[30]=10'd10; assign rom_fixed_codetree[31]=10'd11; assign rom_fixed_codetree[32]=10'd305; assign rom_fixed_codetree[33]=10'd306; assign rom_fixed_codetree[34]=10'd12; assign rom_fixed_codetree[35]=10'd13; assign rom_fixed_codetree[36]=10'd14; assign rom_fixed_codetree[37]=10'd15; assign rom_fixed_codetree[38]=10'd308; assign rom_fixed_codetree[39]=10'd339; assign rom_fixed_codetree[40]=10'd309; assign rom_fixed_codetree[41]=10'd324; assign rom_fixed_codetree[42]=10'd310; assign rom_fixed_codetree[43]=10'd317; assign rom_fixed_codetree[44]=10'd311; assign rom_fixed_codetree[45]=10'd314; assign rom_fixed_codetree[46]=10'd312; assign rom_fixed_codetree[47]=10'd313; assign rom_fixed_codetree[48]=10'd16; assign rom_fixed_codetree[49]=10'd17; assign rom_fixed_codetree[50]=10'd18; assign rom_fixed_codetree[51]=10'd19; assign rom_fixed_codetree[52]=10'd315; assign rom_fixed_codetree[53]=10'd316; assign rom_fixed_codetree[54]=10'd20; assign rom_fixed_codetree[55]=10'd21; assign rom_fixed_codetree[56]=10'd22; assign rom_fixed_codetree[57]=10'd23; assign rom_fixed_codetree[58]=10'd318; assign rom_fixed_codetree[59]=10'd321; assign rom_fixed_codetree[60]=10'd319; assign rom_fixed_codetree[61]=10'd320; assign rom_fixed_codetree[62]=10'd24; assign rom_fixed_codetree[63]=10'd25; assign rom_fixed_codetree[64]=10'd26; assign rom_fixed_codetree[65]=10'd27; assign rom_fixed_codetree[66]=10'd322; assign rom_fixed_codetree[67]=10'd323; assign rom_fixed_codetree[68]=10'd28; assign rom_fixed_codetree[69]=10'd29; assign rom_fixed_codetree[70]=10'd30; assign rom_fixed_codetree[71]=10'd31; assign rom_fixed_codetree[72]=10'd325; assign rom_fixed_codetree[73]=10'd332; assign rom_fixed_codetree[74]=10'd326; assign rom_fixed_codetree[75]=10'd329; assign rom_fixed_codetree[76]=10'd327; assign rom_fixed_codetree[77]=10'd328; assign rom_fixed_codetree[78]=10'd32; assign rom_fixed_codetree[79]=10'd33; assign rom_fixed_codetree[80]=10'd34; assign rom_fixed_codetree[81]=10'd35; assign rom_fixed_codetree[82]=10'd330; assign rom_fixed_codetree[83]=10'd331; assign rom_fixed_codetree[84]=10'd36; assign rom_fixed_codetree[85]=10'd37; assign rom_fixed_codetree[86]=10'd38; assign rom_fixed_codetree[87]=10'd39; assign rom_fixed_codetree[88]=10'd333; assign rom_fixed_codetree[89]=10'd336; assign rom_fixed_codetree[90]=10'd334; assign rom_fixed_codetree[91]=10'd335; assign rom_fixed_codetree[92]=10'd40; assign rom_fixed_codetree[93]=10'd41; assign rom_fixed_codetree[94]=10'd42; assign rom_fixed_codetree[95]=10'd43; assign rom_fixed_codetree[96]=10'd337; assign rom_fixed_codetree[97]=10'd338; assign rom_fixed_codetree[98]=10'd44; assign rom_fixed_codetree[99]=10'd45; assign rom_fixed_codetree[100]=10'd46; assign rom_fixed_codetree[101]=10'd47; assign rom_fixed_codetree[102]=10'd340; assign rom_fixed_codetree[103]=10'd355; assign rom_fixed_codetree[104]=10'd341; assign rom_fixed_codetree[105]=10'd348; assign rom_fixed_codetr
|
||
|
always @ (posedge clk) codetree_rdata_fixed <= rom_fixed_codetree[codetree_raddr];
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// codetree huffman decoder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_decoder #(
|
||
|
.NUMCODES ( 288 ),
|
||
|
.OUTWIDTH ( 10 )
|
||
|
) codetree_decoder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.inew ( decoder_new ),
|
||
|
.ien ( codetree_ien ),
|
||
|
.ibit ( tbit ),
|
||
|
.oen ( codetree_codeen),
|
||
|
.ocode ( codetree_code ),
|
||
|
.rdaddr ( codetree_raddr ),
|
||
|
.rddata ( fixed_tree ? codetree_rdata_fixed : codetree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// distree huffman builder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_builder #(
|
||
|
.NUMCODES ( 32 ),
|
||
|
.CODEBITS ( 5 ),
|
||
|
.BITLENGTH ( 15 ),
|
||
|
.OUTWIDTH ( 10 )
|
||
|
) distree_builder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.wren ( distree_wen ),
|
||
|
.wraddr ( distree_waddr ),
|
||
|
.wrdata ( (5)'(distree_wdata) ),
|
||
|
.run ( tree_run ),
|
||
|
.done ( distree_done ),
|
||
|
.rdaddr ( distree_raddr ),
|
||
|
.rddata ( distree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// distree_fixed
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
wire [9:0] rom_fixed_distree [64];
|
||
|
assign rom_fixed_distree[0]=10'd33; assign rom_fixed_distree[1]=10'd48; assign rom_fixed_distree[2]=10'd34; assign rom_fixed_distree[3]=10'd41; assign rom_fixed_distree[4]=10'd35; assign rom_fixed_distree[5]=10'd38; assign rom_fixed_distree[6]=10'd36; assign rom_fixed_distree[7]=10'd37; assign rom_fixed_distree[8]=10'd0; assign rom_fixed_distree[9]=10'd1; assign rom_fixed_distree[10]=10'd2; assign rom_fixed_distree[11]=10'd3; assign rom_fixed_distree[12]=10'd39; assign rom_fixed_distree[13]=10'd40; assign rom_fixed_distree[14]=10'd4; assign rom_fixed_distree[15]=10'd5; assign rom_fixed_distree[16]=10'd6; assign rom_fixed_distree[17]=10'd7; assign rom_fixed_distree[18]=10'd42; assign rom_fixed_distree[19]=10'd45; assign rom_fixed_distree[20]=10'd43; assign rom_fixed_distree[21]=10'd44; assign rom_fixed_distree[22]=10'd8; assign rom_fixed_distree[23]=10'd9; assign rom_fixed_distree[24]=10'd10; assign rom_fixed_distree[25]=10'd11; assign rom_fixed_distree[26]=10'd46; assign rom_fixed_distree[27]=10'd47; assign rom_fixed_distree[28]=10'd12; assign rom_fixed_distree[29]=10'd13; assign rom_fixed_distree[30]=10'd14; assign rom_fixed_distree[31]=10'd15; assign rom_fixed_distree[32]=10'd49; assign rom_fixed_distree[33]=10'd56; assign rom_fixed_distree[34]=10'd50; assign rom_fixed_distree[35]=10'd53; assign rom_fixed_distree[36]=10'd51; assign rom_fixed_distree[37]=10'd52; assign rom_fixed_distree[38]=10'd16; assign rom_fixed_distree[39]=10'd17; assign rom_fixed_distree[40]=10'd18; assign rom_fixed_distree[41]=10'd19; assign rom_fixed_distree[42]=10'd54; assign rom_fixed_distree[43]=10'd55; assign rom_fixed_distree[44]=10'd20; assign rom_fixed_distree[45]=10'd21; assign rom_fixed_distree[46]=10'd22; assign rom_fixed_distree[47]=10'd23; assign rom_fixed_distree[48]=10'd57; assign rom_fixed_distree[49]=10'd60; assign rom_fixed_distree[50]=10'd58; assign rom_fixed_distree[51]=10'd59; assign rom_fixed_distree[52]=10'd24; assign rom_fixed_distree[53]=10'd25; assign rom_fixed_distree[54]=10'd26; assign rom_fixed_distree[55]=10'd27; assign rom_fixed_distree[56]=10'd61; assign rom_fixed_distree[57]=10'd62; assign rom_fixed_distree[58]=10'd28; assign rom_fixed_distree[59]=10'd29; assign rom_fixed_distree[60]=10'd30; assign rom_fixed_distree[61]=10'd31; assign rom_fixed_distree[62]=10'd0; assign rom_fixed_distree[63]=10'd0;
|
||
|
always @ (posedge clk) distree_rdata_fixed <= rom_fixed_distree[distree_raddr];
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// distree huffman decoder
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
huffman_decoder #(
|
||
|
.NUMCODES ( 32 ),
|
||
|
.OUTWIDTH ( 10 )
|
||
|
) distree_decoder (
|
||
|
.rstn ( rstn ),
|
||
|
.clk ( clk ),
|
||
|
.inew ( decoder_new ),
|
||
|
.ien ( distree_ien ),
|
||
|
.ibit ( tbit ),
|
||
|
.oen ( distree_codeen ),
|
||
|
.ocode ( distree_code ),
|
||
|
.rdaddr ( distree_raddr ),
|
||
|
.rddata ( fixed_tree ? distree_rdata_fixed : distree_rdata )
|
||
|
);
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
// repeat buffer
|
||
|
//--------------------------------------------------------------------------------------------------------------------
|
||
|
parameter [15:0] REPEAT_BUFFER_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<distance) ? wptr + REPEAT_BUFFER_MAXLEN - distance : wptr - distance;
|
||
|
wire [15:0] eptrw = (wptr<16'd1) ? wptr + REPEAT_BUFFER_MAXLEN - 16'd1 : wptr - 16'd1;
|
||
|
|
||
|
reg repeat_valid = 1'b0;
|
||
|
reg [7:0] repeat_data;
|
||
|
|
||
|
assign huffman_ovalid = symbol_valid | repeat_valid;
|
||
|
assign huffman_obyte = repeat_valid ? repeat_data : symbol;
|
||
|
|
||
|
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;
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
rptr <= '0;
|
||
|
sptr <= '0;
|
||
|
eptr <= '0;
|
||
|
end else begin
|
||
|
if(srepeat) begin
|
||
|
rptr <= sptrw;
|
||
|
sptr <= sptrw;
|
||
|
eptr <= eptrw;
|
||
|
end else if(irepeat) begin
|
||
|
if(rptr!=eptr)
|
||
|
rptr <= (rptr<(REPEAT_BUFFER_MAXLEN-16'd1)) ? rptr+16'd1 : '0;
|
||
|
else
|
||
|
rptr <= sptr;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn)
|
||
|
repeat_valid <= '0;
|
||
|
else
|
||
|
repeat_valid <= irepeat;
|
||
|
|
||
|
reg [7:0] mem_repeat_buffer [REPEAT_BUFFER_MAXLEN];
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
if(huffman_ovalid) mem_repeat_buffer[wptr] <= huffman_obyte;
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
repeat_data <= mem_repeat_buffer[rptr];
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
// unfilter
|
||
|
//-----------------------------------------------------------------------------------------------------------------------
|
||
|
function automatic logic [7:0] paeth(input [7:0] a, input [7:0] b, input [7:0] c);
|
||
|
logic signed [10:0] sa, sb, sc, p, pa, pb, pc;
|
||
|
sa = {3'h0, a};
|
||
|
sb = {3'h0, b};
|
||
|
sc = {3'h0, c};
|
||
|
p = sa + sb - sc;
|
||
|
pa = p > sa ? p - sa : sa - p;
|
||
|
pb = p > sb ? p - sb : sb - p;
|
||
|
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 negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
nfirstrow <= 1'b0;
|
||
|
col <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
nfirstrow <= 1'b0;
|
||
|
col <= '0;
|
||
|
end else if(mvalid) begin
|
||
|
if(col<bpr) begin
|
||
|
col <= col + 14'h1;
|
||
|
end else begin
|
||
|
nfirstrow <= 1'b1;
|
||
|
col <= '0;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mode <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
mode <= '0;
|
||
|
end else if(mvalid && col==14'h0)
|
||
|
mode <= mbyte[2:0];
|
||
|
end
|
||
|
|
||
|
always_comb
|
||
|
case(mode)
|
||
|
3'd0 : fdata = mbyte;
|
||
|
3'd1 : fdata = mbyte + (nfirstcol ? LLdata : 8'h0);
|
||
|
3'd2 : fdata = mbyte + (nfirstrow ? UUdata : 8'h0);
|
||
|
3'd3 : fdata = mbyte + SSdata[8:1];
|
||
|
default: fdata = mbyte + paeth( (nfirstcol ? LLdata : 8'h0),
|
||
|
(nfirstrow ? UUdata : 8'h0),
|
||
|
(nfirstrow&nfirstcol ? ULdata : 8'h0) );
|
||
|
endcase
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
bvalid <= 1'b0;
|
||
|
bbyte <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
bvalid <= 1'b0;
|
||
|
bbyte <= '0;
|
||
|
end else begin
|
||
|
bvalid <= (mvalid && col!=14'h0);
|
||
|
if(mvalid && col!=14'h0) bbyte <= fdata;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// shift reg for current line
|
||
|
reg [7:0] mem_sr_currline [4];
|
||
|
initial for(int i=0; i<4; i=i+1) mem_sr_currline[i] = '0;
|
||
|
assign LLdata = mem_sr_currline [bpp];
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mem_sr_currline[0] <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
mem_sr_currline[0] <= '0;
|
||
|
end else if(mvalid)
|
||
|
mem_sr_currline[0] <= fdata;
|
||
|
end
|
||
|
generate genvar isrcl;
|
||
|
for(isrcl=0; isrcl<3; isrcl=isrcl+1) begin : gen_sr_currline
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mem_sr_currline[isrcl+1] <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
mem_sr_currline[isrcl+1] <= '0;
|
||
|
end else if(mvalid)
|
||
|
mem_sr_currline[isrcl+1] <= mem_sr_currline[isrcl];
|
||
|
end
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
|
||
|
// shift reg for previous line
|
||
|
reg [7:0] mem_sr_prevline [4];
|
||
|
initial for(int i=0; i<4; i=i+1) mem_sr_prevline[i] = '0;
|
||
|
assign ULdata = mem_sr_prevline [bpp];
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mem_sr_prevline[0] <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
mem_sr_prevline[0] <= '0;
|
||
|
end else if(mvalid)
|
||
|
mem_sr_prevline[0] <= UUdata;
|
||
|
end
|
||
|
generate genvar isrpl;
|
||
|
for(isrpl=0; isrpl<3; isrpl=isrpl+1) begin : gen_sr_prevline
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
mem_sr_prevline[isrpl+1] <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
mem_sr_prevline[isrpl+1] <= '0;
|
||
|
end else if(mvalid)
|
||
|
mem_sr_prevline[isrpl+1] <= mem_sr_prevline[isrpl];
|
||
|
end
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
|
||
|
// shift buffer from current line to previous line
|
||
|
reg sb_rvalid = 1'b0;
|
||
|
reg [ 7:0] sb_rdata;
|
||
|
reg [ 7:0] sb_ldata = '0;
|
||
|
reg [ 7:0] sb_lidata = '0;
|
||
|
reg [13:0] sb_ptr = '0;
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
sb_lidata <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
sb_lidata <= '0;
|
||
|
end else if(mvalid)
|
||
|
sb_lidata <= fdata;
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
sb_ptr <= '0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
sb_ptr <= '0;
|
||
|
end else if(mvalid) begin
|
||
|
if(sb_ptr < (bpr-14'd1))
|
||
|
sb_ptr <= sb_ptr + 14'd1;
|
||
|
else
|
||
|
sb_ptr <= '0;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
sb_ldata <= '0;
|
||
|
sb_rvalid <= 1'b0;
|
||
|
end else begin
|
||
|
if(~imagevalid) begin
|
||
|
sb_ldata <= '0;
|
||
|
sb_rvalid <= 1'b0;
|
||
|
end else begin
|
||
|
if(sb_rvalid)
|
||
|
sb_ldata <= sb_rdata;
|
||
|
sb_rvalid <= mvalid;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
reg [7:0] mem_sb [1<<14];
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
if(mvalid)
|
||
|
mem_sb[sb_ptr] <= fdata;
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
sb_rdata <= mem_sb[sb_ptr];
|
||
|
|
||
|
assign UUdata = (bpr == '0) ? sb_lidata : (sb_rvalid ? sb_rdata : sb_ldata);
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------------------
|
||
|
// build pixel
|
||
|
//-------------------------------------------------------------------------------------------------------------
|
||
|
reg [1:0] pixcnt = '0;
|
||
|
reg [7:0] pr='0, pg='0, pb='0, pa='0;
|
||
|
|
||
|
assign opixelr = isplte ? plte_rdata[23:16] : pr;
|
||
|
assign opixelg = isplte ? plte_rdata[15: 8] : pg;
|
||
|
assign opixelb = isplte ? plte_rdata[ 7: 0] : pb;
|
||
|
assign opixela = isplte ? 8'hff : pa;
|
||
|
|
||
|
always @ (posedge clk or negedge rstn)
|
||
|
if(~rstn) begin
|
||
|
pixcnt <= '0;
|
||
|
ovalid <= 1'b0;
|
||
|
{pr, pg, pb, pa} <= 0;
|
||
|
end else begin
|
||
|
ovalid <= 1'b0;
|
||
|
if(newframe) begin
|
||
|
pixcnt <= '0;
|
||
|
{pr, pg, pb, pa} <= 0;
|
||
|
end else if(bvalid) begin
|
||
|
case(pixcnt)
|
||
|
2'd0 : {pr, pg, pb, pa} <= {bbyte, bbyte, bbyte, 8'hff};
|
||
|
2'd1 : { pa} <= { bbyte};
|
||
|
2'd2 : { pg, pb, pa} <= { pa, bbyte, 8'hff};
|
||
|
2'd3 : { pa} <= { bbyte};
|
||
|
endcase
|
||
|
if(pixcnt<bpp) begin
|
||
|
pixcnt <= pixcnt + 2'd1;
|
||
|
ovalid <= 1'b0;
|
||
|
end else begin
|
||
|
pixcnt <= 2'd0;
|
||
|
ovalid <= 1'b1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------------------
|
||
|
// PLTE mem
|
||
|
//-------------------------------------------------------------------------------------------------------------
|
||
|
reg [23:0] mem_plte [256];
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
if(plte_wen)
|
||
|
mem_plte[plte_waddr] <= plte_wdata;
|
||
|
|
||
|
always @ (posedge clk)
|
||
|
plte_rdata <= mem_plte[bbyte];
|
||
|
|
||
|
|
||
|
endmodule
|