双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
双线性插值作为数值分析中的一种插值算法,广泛应用在信号处理,数字图像和视频处理等方面。
网上理论知识一大把,反正不喜欢看费脑。
这里简单说就是附近四个点求出中间点主要分享代码
整个代码中的除法器是使用易灵思平台,如是其它平台要将代替掉。
// An highlighted block
//wiret the code go go Interest trumps all ^_^
//设计放大外面使用两个ram
//缩小使用4个ram
//先乘再除
`define IP_UUID _24f688124f6f47f2a9a7e78597ca4ca8
`define IP_NAME_CONCAT(a,b) a``b
`define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID)
module zoom #(
parameter ORG_WIDTH = 640 , //放大前数据宽
parameter ORG_HEIGHT = 512 , //放大前数据高
parameter TAR_WIDTH = 2560 , //放大后目标数据宽
parameter TAR_HEIGHT = 2048 , //放大后目标数据高
parameter ORG_WIDTH_W = 10 , //放大前数据宽 org的位宽一致
parameter ORG_HEIGHT_H = 10 , //放大前数据高
parameter TAR_WIDTH_W = 12 , //放大后目标数据宽 tar的位宽一致
parameter TAR_HEIGHT_H = 12 , //放大后目标数据高
parameter RAM_ADDR_START1 = 0 ,
parameter RAM_ADDR_START2 = 640 ,
parameter RAM_ADDR_START3 = 1280 ,
parameter RAM_ADDR_WIDTH = 12 ,
//---------------------Non-user-definable parameters----------------------------
parameter WMULT = ORG_WIDTH_W + TAR_WIDTH_W ,
parameter HMULT = ORG_HEIGHT_H + TAR_HEIGHT_H ,
parameter WZOOM = ORG_WIDTH_W + 10 ,
parameter HZOOM = ORG_HEIGHT_H +10 ,
parameter NX0 = WZOOM+4 ,
parameter NY0 = HZOOM+4 ,
parameter NX1 = NX0 -10 ,
parameter NY1 = NY0 -10 ,
parameter DLY = WMULT ,
parameter DLY1 = WMULT+3 ,
parameter NZOOM = 11'd1024 ,
parameter nZoomFPNZOOMFPN = 8'd16
)
(
input i_clk ,
input i_rst_n ,
input i_zoom_ctrl , //1:大 0:小 //放大外置RAM只需要两个RAM
input i_ram_sel ,
input i_hsync ,
input i_hsync_pre ,
input i_vsync ,
input i_fsync ,
input [7:0] i_data11 ,
input [7:0] i_data12 ,
input [7:0] i_data21 ,
input [7:0] i_data22 ,
output reg [RAM_ADDR_WIDTH - 1:0] o_addr1 ,
output reg [RAM_ADDR_WIDTH - 1:0] o_addr2 ,
output reg [RAM_ADDR_WIDTH - 1:0] o_addr3 ,
output reg [RAM_ADDR_WIDTH - 1:0] o_addr4 ,
output [7:0] o_data ,
output reg o_hsync ,
output reg o_hsync_pre ,
output reg o_vsync ,
output reg o_fsync ,
output [ORG_HEIGHT_H - 1:0] o_vcnt ,
output o_updata_ram
);
reg flag ;
reg [3:0] cnt ;
reg [DLY1-1:0] hsync_dly ;
reg [DLY1-1:0] hsync_pre_dly ;
reg [DLY1-1:0] vsync_dly ;
reg [DLY1-1:0] fsync_dly ;
reg hsync ;
reg hsync_pre ;
reg vsync ;
reg fsync ;
reg [TAR_WIDTH_W - 1:0] hcnt_tar ;
wire add_hcnt_tar ;
wire end_hcnt_tar ;
reg [TAR_HEIGHT_H -1:0] vcnt_tar ;
wire add_vcnt_tar ;
wire end_vcnt_tar ;
reg [TAR_HEIGHT_H -1:0] vcnt_pre ;
wire add_vcnt_pre ;
wire end_vcnt_pre ;
wire [WMULT -1:0] w_mult ;
wire [WMULT -1:0] w_div_q ;
wire [TAR_WIDTH_W-1:0] w_div_r ;
wire [HMULT -1:0] h_mult ;
wire [HMULT -1:0] h_div_q ;
wire [TAR_HEIGHT_H-1:0] h_div_r ;
wire [WZOOM-1:0] zoom_w ;
wire [HZOOM-1:0] zoom_h ;
wire [WZOOM-1:0] rsz_multiple_w ;
wire [HZOOM-1:0] rsz_multiple_h ;
reg [NX0-1:0] n_x0 ;
reg [NY0-1:0] n_y0 ;
reg [NX0-1:0] n_wx0 ;
reg [NY0-1:0] n_wy0 ;
reg [NX1-1:0] n_wx1 ;
reg [NY1-1:0] n_wy1 ;
wire [7:0] n_wx2 ;
wire [7:0] n_wy2 ;
reg [(DLY*8)-1:0] n_wx1_dly ;
reg [(DLY*8)-1:0] n_wy1_dly ;
reg [(DLY*8)-1:0] n_wx2_dly ;
reg [(DLY*8)-1:0] n_wy2_dly ;
reg [15:0] data_buff1 ;
reg [15:0] data_buff2 ;
reg [15:0] data_buff ;
reg [7:0] data11_pre ;
reg [7:0] data21_pre ;
reg [7:0] n_wx1_pre,n_wx1_pre1 ;
reg [7:0] n_wy1_pre,n_wy1_pre1 ;
reg [7:0] n_wx2_pre,n_wx2_pre1 ;
reg [7:0] n_wy2_pre,n_wy2_pre1 ;
reg [RAM_ADDR_WIDTH-1:0] addr_buf ;
reg save_data ;
wire [30:0] q = ORG_WIDTH ;
wire [30:0] w = ORG_HEIGHT ;
wire [30:0] e = TAR_WIDTH ;
wire [30:0] r = TAR_HEIGHT ;
wire [30:0] t = ORG_WIDTH_W ;
wire [30:0] y = ORG_HEIGHT_H ;
wire [30:0] u = TAR_WIDTH_W ;
wire [30:0] i = TAR_HEIGHT_H ;
wire [30:0] o = RAM_ADDR_START1 ;
wire [30:0] p = RAM_ADDR_START2 ;
wire [30:0] a = RAM_ADDR_START3 ;
wire [30:0] s = RAM_ADDR_WIDTH ;
wire [30:0] f = NZOOM ;
wire [30:0] g = nZoomFPNZOOMFPN ;
wire [30:0] q1 =WMULT ;
wire [30:0] q2 =HMULT ;
//打拍 跨时钟域
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
data11_pre <= 8'd0;
data21_pre <= 8'd0;
n_wx2_pre <= 8'd0;
n_wy2_pre <= 8'd0;
n_wx1_pre <= 8'd0;
n_wy1_pre <= 8'd0;
n_wx1_pre1 <= 8'd0;
n_wy1_pre1 <= 8'd0;
n_wx2_pre1 <= 8'd0;
n_wy2_pre1 <= 8'd0;
end
else if(i_zoom_ctrl == 1'b1)begin
if(save_data)begin //WMULT+3
data11_pre <= i_data11;
data21_pre <= i_data21;
end
else begin
data11_pre <= data11_pre;
data21_pre <= data21_pre;
end
n_wx2_pre <= n_wx2_dly[(8*DLY)-1:(8*DLY)-8];
n_wy2_pre <= n_wy2_dly[(8*DLY)-1:(8*DLY)-8];
n_wx1_pre <= n_wx1_dly[(8*DLY)-1:(8*DLY)-8];
n_wy1_pre <= n_wy1_dly[(8*DLY)-1:(8*DLY)-8];
n_wx1_pre1 <= n_wx1_pre;
n_wy1_pre1 <= n_wy1_pre;
n_wx2_pre1 <= n_wx2_pre;
n_wy2_pre1 <= n_wy2_pre;
end
else begin
data11_pre <= data11_pre;
data21_pre <= data21_pre;
n_wx2_pre <= n_wx2_dly[(8*DLY)-1:(8*DLY)-8];
n_wy2_pre <= n_wy2_dly[(8*DLY)-1:(8*DLY)-8];
n_wx1_pre <= n_wx1_dly[(8*DLY)-1:(8*DLY)-8];
n_wy1_pre <= n_wy1_dly[(8*DLY)-1:(8*DLY)-8];
n_wx1_pre1 <= n_wx1_pre;
n_wy1_pre1 <= n_wy1_pre;
n_wx2_pre1 <= n_wx2_pre;
n_wy2_pre1 <= n_wy2_pre;
end
end
always @(posedge i_clk or negedge i_rst_n)begin //1
if(!i_rst_n)begin
hsync <=1'b0;
hsync_pre <=1'b0;
vsync <=1'b0;
fsync <=1'b0;
end
else begin
hsync <= i_hsync ;
hsync_pre <= i_hsync_pre;
vsync <= i_vsync ;
fsync <= i_fsync ;
end
end
always @(posedge i_clk or negedge i_rst_n)begin //1
if(!i_rst_n)begin
hsync_dly <={(DLY1){1'b0}};
hsync_pre_dly <={(DLY1){1'b0}};
vsync_dly <={(DLY1){1'b0}};
fsync_dly <={(DLY1){1'b0}};
end
else begin
hsync_dly <= {hsync_dly[DLY1-2:0], hsync };
hsync_pre_dly <= {hsync_pre_dly[DLY1-2:0],hsync_pre};
vsync_dly <= {vsync_dly[DLY1-2:0], vsync };
fsync_dly <= {fsync_dly[DLY1-2:0], fsync };
end
end
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
o_hsync <=1'b0;
o_hsync_pre <=1'b0;
o_vsync <=1'b0;
o_fsync <=1'b0;
end
else if(i_zoom_ctrl == 1'b1)begin
o_hsync <= hsync_dly[DLY1-1] ;
o_hsync_pre <= hsync_pre_dly[DLY1-1];
o_vsync <= vsync_dly[DLY1-1] ;
o_fsync <= fsync_dly[DLY1-1] ;
end
else begin
o_hsync <= hsync_dly[DLY1-1] ;
o_hsync_pre <= hsync_pre_dly[DLY1-1];
o_vsync <= vsync_dly[DLY1-1] ;
o_fsync <= fsync_dly[DLY1-1] ;
end
end
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
n_wx1_dly <={(8*DLY){1'b0}};
n_wy1_dly <={(8*DLY){1'b0}};
n_wx2_dly <={(8*DLY){1'b0}};
n_wy2_dly <={(8*DLY){1'b0}};
end
else begin
n_wx1_dly <={n_wx1_dly[(8*(DLY-1))-1:0],n_wx1[7:0]};
n_wy1_dly <={n_wy1_dly[(8*(DLY-1))-1:0],n_wy1[7:0]};
n_wx2_dly <={n_wx2_dly[(8*(DLY-1))-1:0],n_wx2};
n_wy2_dly <={n_wy2_dly[(8*(DLY-1))-1:0],n_wy2};
end
end
always @(posedge i_clk or negedge i_rst_n)begin //WMULT+2
if(!i_rst_n)begin
data_buff1 <= 16'd0;
data_buff2 <= 16'd0;
end
else if(i_zoom_ctrl == 1'b1)begin //WMULT+4
data_buff1 <= n_wy2_dly[(8*DLY)-1:(8*DLY)-8]*(n_wx2_dly[(8*DLY)-1:(8*DLY)-8]*data11_pre+n_wx1_dly[(8*DLY)-1:(8*DLY)-8]*i_data11);
data_buff2 <= n_wy1_dly[(8*DLY)-1:(8*DLY)-8]*(n_wx2_dly[(8*DLY)-1:(8*DLY)-8]*data21_pre+n_wx1_dly[(8*DLY)-1:(8*DLY)-8]*i_data12);
end
else begin
data_buff1 <= n_wy2_dly[(8*DLY)-1:(8*DLY)-8]*(n_wx2_dly[(8*DLY)-1:(8*DLY)-8]*i_data11+n_wx1_dly[(8*DLY)-1:(8*DLY)-8]*i_data12);
data_buff2 <= n_wy1_dly[(8*DLY)-1:(8*DLY)-8]*(n_wx2_dly[(8*DLY)-1:(8*DLY)-8]*i_data21+n_wx1_dly[(8*DLY)-1:(8*DLY)-8]*i_data22);
end
end
always @(posedge i_clk or negedge i_rst_n)begin //+WMULT+3
if(!i_rst_n)begin
data_buff <= 16'd0;
end
else begin
data_buff <= data_buff2 +data_buff1;
end
end
assign o_data = data_buff[15:8];
//计数器
always @(posedge i_clk or negedge i_rst_n)begin //1
if(!i_rst_n)begin
hcnt_tar <= {(TAR_WIDTH_W){1'b0}};
end
else if(fsync)begin
hcnt_tar <= {(TAR_WIDTH_W){1'b0}};
end
else if(add_hcnt_tar)begin
if(end_hcnt_tar)begin
hcnt_tar <= {(TAR_WIDTH_W){1'b0}};
end
else begin
hcnt_tar <= hcnt_tar + {{(TAR_WIDTH_W-1){1'b0}},1'b1} ;
end
end
else begin
hcnt_tar <= hcnt_tar;
end
end
assign add_hcnt_tar = vsync && hsync;
assign end_hcnt_tar = add_hcnt_tar && hcnt_tar == TAR_WIDTH -{{(TAR_WIDTH_W-1){1'b0}},1'b1} ;
always @(posedge i_clk or negedge i_rst_n)begin //1
if(!i_rst_n)begin
vcnt_tar <= {(TAR_HEIGHT_H){1'd0}};
end
else if(fsync)begin
vcnt_tar <= {(TAR_HEIGHT_H){1'd0}};
end
else if(add_vcnt_tar)begin
if(end_vcnt_tar)begin
vcnt_tar <= {(TAR_HEIGHT_H){1'd0}};
end
else begin
vcnt_tar <= vcnt_tar + {{(TAR_HEIGHT_H-1){1'd0}},1'b1};
end
end
else begin
vcnt_tar <= vcnt_tar;
end
end
assign add_vcnt_tar = end_hcnt_tar;
assign end_vcnt_tar = add_vcnt_tar && vcnt_tar == TAR_HEIGHT -{{(TAR_HEIGHT_H-1){1'd0}},1'b1};
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
vcnt_pre <= {(TAR_HEIGHT_H){1'd0}};
end
else if(fsync)begin
vcnt_pre <= {(TAR_HEIGHT_H){1'd0}};
end
else if(add_vcnt_pre)begin
if(end_vcnt_pre)begin
vcnt_pre <= {(TAR_HEIGHT_H){1'd0}};
end
else begin
vcnt_pre <= vcnt_pre + {{(TAR_HEIGHT_H-1){1'd0}},1'b1};
end
end
else begin
vcnt_pre <= vcnt_pre;
end
end
assign add_vcnt_pre = i_hsync_pre == 1'b1 && hsync_pre == 1'b0; //上升沿
assign end_vcnt_pre = add_vcnt_pre && vcnt_pre == TAR_HEIGHT -{{(TAR_HEIGHT_H-1){1'd0}},1'b1};
assign o_updata_ram = i_hsync_pre == 1'b1 && hsync_pre == 1'b0; //更新地址信号
assign o_vcnt =h_div_q[ORG_HEIGHT_H - 1:0];
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
cnt <= 4'd0;
end
else if(fsync)begin
cnt <= 4'd0;
end
else if(i_hsync == 1'b1 && hsync == 1'd0)begin
if(cnt >= 4'd2)begin
cnt <= 4'd0;
end
else begin
cnt <= 4'd1 +cnt;
end
end
else begin
cnt <= cnt;
end
end
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
flag <= 1'd0;
end
else if(fsync)begin
flag <= 1'd0;
end
else if(i_hsync == 1'b1 && hsync == 1'd0)begin
flag <= ~flag;
end
else begin
flag <= flag;
end
end
//更新横向第二个地址 //WMULT+1
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
addr_buf <= {(RAM_ADDR_WIDTH){1'b0}};
end
else if(hsync_dly[WMULT-2] == 1'b1 && hsync_dly[WMULT-1] ==1'b0)begin
addr_buf <= {(RAM_ADDR_WIDTH){1'b0}};
end
else if((addr_buf + {{(RAM_ADDR_WIDTH-1){1'b0}},1'b1} >= (ORG_WIDTH-{{(ORG_WIDTH_W-1){1'b0}},1'b1} ))&& addr_buf == w_div_q[ORG_WIDTH_W-1:0])begin
addr_buf <= (ORG_WIDTH-{{(ORG_WIDTH_W-1){1'b0}},1'b1});
end
else if(addr_buf == w_div_q[ORG_WIDTH_W-1:0])begin
addr_buf <= addr_buf + {{(RAM_ADDR_WIDTH-1){1'b0}},1'b1};
end
else begin
addr_buf <= addr_buf;
end
end
//保存前两个数据
always @(posedge i_clk or negedge i_rst_n)begin
if(!i_rst_n)begin
save_data <= 1'b0;
end
else if(addr_buf == w_div_q[ORG_WIDTH_W-1:0])begin
save_data <= 1'b1;
end
else begin
save_data <= 1'b0;
end
end
always @(posedge i_clk or negedge i_rst_n)begin //ram 1
if(!i_rst_n)begin
o_addr2 <={(RAM_ADDR_WIDTH){1'b0}};
o_addr4 <={(RAM_ADDR_WIDTH){1'b0}};
o_addr1 <={(RAM_ADDR_WIDTH){1'b0}};
o_addr3 <={(RAM_ADDR_WIDTH){1'b0}};
end
else if(i_ram_sel == 1'b1)begin
case (flag)
1'b1: begin
if(i_zoom_ctrl == 1'b1)begin //WMULT+2
o_addr2 <= RAM_ADDR_START1 + addr_buf;
o_addr4 <= RAM_ADDR_START1 + addr_buf;
o_addr1 <= RAM_ADDR_START1 + addr_buf;
o_addr3 <= RAM_ADDR_START1 + addr_buf;
end
else begin
if(w_div_q[ORG_WIDTH_W-1:0] >= (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}))begin //WMULT+1
o_addr2 <= RAM_ADDR_START1+ (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr4 <= RAM_ADDR_START1+ (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr1 <= RAM_ADDR_START1+ (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr3 <= RAM_ADDR_START1+ (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
end
else begin
o_addr2 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0] +1'b1;
o_addr4 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0] +1'b1;
o_addr1 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0];
o_addr3 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0];
end
end
end
1'b0: begin
if(i_zoom_ctrl == 1'b1)begin
o_addr2 <= RAM_ADDR_START2 + addr_buf;
o_addr4 <= RAM_ADDR_START2 + addr_buf;
o_addr1 <= RAM_ADDR_START2 + addr_buf;
o_addr3 <= RAM_ADDR_START2 + addr_buf;
end
else begin
if(w_div_q[ORG_WIDTH_W-1:0] >= (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}))begin
o_addr1 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr2 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr3 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr4 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
end
else begin
o_addr1 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0];
o_addr2 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
o_addr3 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0];
o_addr4 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
end
end
end
default: o_addr1<= o_addr1;
endcase
end
else begin
case (cnt)
4'd0:begin
if(i_zoom_ctrl == 1'b1)begin
o_addr2 <= RAM_ADDR_START3 + addr_buf;
o_addr4 <= RAM_ADDR_START3 + addr_buf;
o_addr1 <= RAM_ADDR_START3 + addr_buf;
o_addr3 <= RAM_ADDR_START3 + addr_buf;
end
else begin
if(w_div_q[ORG_WIDTH_W-1:0] >= (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}))begin
o_addr1 <= RAM_ADDR_START3+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr2 <= RAM_ADDR_START3+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr3 <= RAM_ADDR_START3+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr4 <= RAM_ADDR_START3+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
end
else begin
o_addr1 <= RAM_ADDR_START3+w_div_q[ORG_WIDTH_W-1:0];
o_addr2 <= RAM_ADDR_START3+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
o_addr3 <= RAM_ADDR_START3+w_div_q[ORG_WIDTH_W-1:0];
o_addr4 <= RAM_ADDR_START3+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
end
end
end
4'd1:begin
if(i_zoom_ctrl == 1'b1)begin
o_addr2 <= RAM_ADDR_START1 + addr_buf;
o_addr4 <= RAM_ADDR_START1 + addr_buf;
o_addr1 <= RAM_ADDR_START1 + addr_buf;
o_addr3 <= RAM_ADDR_START1 + addr_buf;
end
else
begin if(w_div_q[ORG_WIDTH_W-1:0] >= (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}))begin
o_addr1 <= RAM_ADDR_START1+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr2 <= RAM_ADDR_START1+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr3 <= RAM_ADDR_START1+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr4 <= RAM_ADDR_START1+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
end
else begin
o_addr1 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0];
o_addr2 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
o_addr3 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0];
o_addr4 <= RAM_ADDR_START1+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
end
end
end
4'd2:begin
if(i_zoom_ctrl == 1'b1)begin
o_addr2 <= RAM_ADDR_START2 + addr_buf;
o_addr4 <= RAM_ADDR_START2 + addr_buf;
o_addr1 <= RAM_ADDR_START2 + addr_buf;
o_addr3 <= RAM_ADDR_START2 + addr_buf;
end
else
begin if(w_div_q[ORG_WIDTH_W-1:0] >= (ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}))begin
o_addr1 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr2 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr3 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
o_addr4 <= RAM_ADDR_START2+(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1});
end
else begin
o_addr1 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0];
o_addr2 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
o_addr3 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0];
o_addr4 <= RAM_ADDR_START2+w_div_q[ORG_WIDTH_W-1:0]+1'b1;
end
end
end
default: o_addr4 <= o_addr4;
endcase
end
end
//权重
assign zoom_w = {(ORG_WIDTH -{{(ORG_WIDTH_W -1){1'b0}},1'b1}),10'd0};
assign zoom_h = {(ORG_HEIGHT-{{(ORG_HEIGHT_H-1){1'b0}},1'b1}),10'd0};
`IP_MODULE_NAME(divider) #(
.WIDTHN (WZOOM ),
.WIDTHD (TAR_WIDTH_W ),
.NREPRESENTATION ("UNSIGNED" ),
.DREPRESENTATION ("UNSIGNED" ),
.LATENCY (TAR_WIDTH_W ),
.PIPELINE (1 )
)
u_divider_wzoom
(
.numer ( zoom_w ),
.denom ( TAR_WIDTH-{{(TAR_WIDTH_W-1){1'b0}},1'b1} ),
.clken ( 1'b1 ),
.clk ( i_clk ),
.reset ( !i_rst_n ),
.quotient ( rsz_multiple_w ),
.remain ( )
);
`IP_MODULE_NAME(divider) #(
.WIDTHN (HZOOM ),
.WIDTHD (TAR_HEIGHT_H ),
.NREPRESENTATION ("UNSIGNED" ),
.DREPRESENTATION ("UNSIGNED" ),
.LATENCY (TAR_HEIGHT_H ),
.PIPELINE (1 )
)
u_divider_hzoom
(
.numer ( zoom_h ),
.denom ( TAR_HEIGHT-{{(TAR_HEIGHT_H-1){1'b0}},1'b1} ),
.clken ( 1'b1 ),
.clk ( i_clk ),
.reset ( !i_rst_n ),
.quotient ( rsz_multiple_h ),
.remain ( )
);
always @(posedge i_clk or negedge i_rst_n)begin //1
if(!i_rst_n)begin
n_x0 <={(NX0){1'b0}};
n_y0 <={(NY0){1'b0}};
end
else begin
n_x0 <=rsz_multiple_w*{hcnt_tar,4'd0};
n_y0 <=rsz_multiple_h*{vcnt_tar,4'd0};
end
end
always @(posedge i_clk or negedge i_rst_n)begin //2
if(!i_rst_n)begin
n_wx0 <={(NX0){1'b0}};
n_wy0 <={(NY0){1'b0}};
end
else begin
n_wx0 <=(hcnt_tar*rsz_multiple_w)>>10;
n_wy0 <=(vcnt_tar*rsz_multiple_h)>>10;
end
end
always @(posedge i_clk or negedge i_rst_n)begin //3
if(!i_rst_n)begin
n_wx1 <= {(NX1){1'b0}};
n_wy1 <= {(NY1){1'b0}};
end
else begin
n_wx1 <= n_x0[NX0-1:10]-{n_wx0,4'd0};
n_wy1 <= n_y0[NY0-1:10]-{n_wy0,4'd0};
end
end
assign n_wx2 = nZoomFPNZOOMFPN - n_wx1[7:0];
assign n_wy2 = nZoomFPNZOOMFPN - n_wy1[7:0];
//例化模块
//W
//n_rsz_multiple_w = (float)n_width / n_rsz_wid * nZoom;
// parallel_ppl_mult
// #(
// .MUL1_WIDTH (ORG_WIDTH_W ) ,//Multiplier1 width
// .MUL2_WIDTH (TAR_WIDTH_W ) ,//multiplier2 width
// .PPL_LEVEL (5 ) //pipeline levels
// )
// parallel_ppl_mult_w
// (
// .clk (i_clk ),
// .rst_n (i_rst_n ),
// .mul1 (ORG_WIDTH ),
// .mul2 (hcnt_tar ),
// .prod (w_mult )
// );
assign w_mult = (ORG_WIDTH-1'b1)*hcnt_tar; //WMULT
`IP_MODULE_NAME(divider) #(
.WIDTHN (WMULT ),
.WIDTHD (TAR_WIDTH_W ),
.NREPRESENTATION ("UNSIGNED" ),
.DREPRESENTATION ("UNSIGNED" ),
.LATENCY (WMULT ),
.PIPELINE (1 )
)
u_divider_w
(
.numer ( w_mult ),
.denom ( TAR_WIDTH-{{(TAR_WIDTH_W-1){1'b0}},1'b1} ),
.clken ( 1'b1 ),
.clk ( i_clk ),
.reset ( !i_rst_n ),
.quotient ( w_div_q ),
.remain ( w_div_r )
);
//n_rsz_multiple_h = (float)n_height / n_rsz_hei * nZoom;
//H
// parallel_ppl_mult
// #(
// .MUL1_WIDTH (ORG_HEIGHT_H ) ,//Multiplier1 width
// .MUL2_WIDTH (TAR_HEIGHT_H ) ,//multiplier2 width
// .PPL_LEVEL (5 ) //pipeline levels
// )
// parallel_ppl_mult_h_pre
// (
// .clk (i_clk ),
// .rst_n (i_rst_n ),
// .mul1 (ORG_HEIGHT ),
// .mul2 (vcnt_pre ),
// .prod (h_mult )
// );
assign h_mult =(ORG_HEIGHT -1'b1)*vcnt_pre; //TAR_HEIGHT_H
`IP_MODULE_NAME(divider) #(
.WIDTHN (HMULT ),
.WIDTHD (TAR_HEIGHT_H ),
.NREPRESENTATION ("UNSIGNED" ),
.DREPRESENTATION ("UNSIGNED" ),
.LATENCY (HMULT ),
.PIPELINE (1 )
)
u_divider_h
(
.numer ( h_mult ),
.denom ( TAR_HEIGHT-{{(TAR_HEIGHT_H-1){1'b0}},1'b1} ),
.clken ( 1'b1 ),
.clk ( i_clk ),
.reset ( !i_rst_n ),
.quotient ( h_div_q ),
.remain ( h_div_r )
);
endmodule
端口名称 | 端口命名 | 方向 | 位宽 | 说明 |
---|---|---|---|---|
时钟 | i_clk | IN | 1 | |
复位 | i_rst_n | IN | 1 | |
行有效输入 | i_hsync | IN | 1 | |
提前行有效输入 | i_hsync_pre | IN | 1 | |
场有效输入 | i_vsync | IN | 1 | |
帧有效输入 | i_fsync | IN | 1 | |
RAM更新数据信号 | o_updata_ram | OUT | 1 | |
RAM个数选择 | i_ram_sel | IN | 1 | 1:2个 0:4个 |
RAM数据更新地址 | o_vcnt | OUT | ORG_HEIGHT_H | |
RAM1读取地址 | o_addr1 | OUT | RAM_ADDR_WIDTH | |
RAM2读取地址 | o_addr1 | OUT | RAM_ADDR_WIDTH | |
RAM3读取地址 o_addr1 | OUT | RAM_ADDR_WIDTH | ||
RAM4读取地址 | o_addr1 | OUT | RAM_ADDR_WIDTH | |
RAM1读取数据 | i_data11 | IN | 8 | |
RAM2读取数据 | i_data12 | IN | 8 | |
RAM3读取数据 | i_data21 | IN | 8 | |
RAM4读取数据 | i_data22 | IN | 8 | |
RAM缓存几行数据 | i_ram_sel | IN | 1 | 1:2行 0:3行 |
行有效输出 | o_hsync | OUT | 1 | |
提前行有效输出 | o_hsync_pre | OUT | 1 | |
场有效输出 | o_vsync | OUT | 1 | |
帧有效输出 | o_fsync | OUT | 1 | |
缩放数据输出 | o_data | OUT | 8 | |
放大前图像宽 | ORG_WIDTH | |||
放大前图像高 | ORG_HEIGHT | |||
放大后图像宽 | TAR_WIDTH | |||
放大后图像高 | TAR_HEIGHT | |||
ORG_WIDTH位宽 | ORG_WIDTH_W | |||
ORG_HEIGHT位宽 | ORG_HEIGHT_H | |||
TAR_WIDTH位宽 | TAR_WIDTH_W | |||
TAR_HEIGHT位宽 | TAR_HEIGHT_H | |||
RAM第一行开始位置 | RAM_ADDR_START1 | |||
RAM第二行开始位置 | RAM_ADDR_START2 | |||
RAM第三行开始位置 | RAM_ADDR_START3 | |||
RAM地址深度 | RAM_ADDR_WIDTH |
注意: ORG_WIDTH_W、ORG_HEIGHT_H长度一样;
TAR_WIDTH_W、TAR_HEIGHT_H长度一样;
参数例化不能给位宽;
缩小必须四个RAM;
`timescale 1ps/1ps
module zoom_tb();
wire clk_50m ;
wire clk_8x ;
wire rst_n ;
wire hsync ;
wire hsync_pre ;
wire vsync ;
wire fsync ;
wire [7:0] data11 ;
wire [7:0] data12 ;
wire [7:0] data21 ;
wire [7:0] data22 ;
wire [7:0] data ;
wire data_vld ;
wire [12:0] addr1 ;
wire [12:0] addr2 ;
wire [12:0] addr3 ;
wire [12:0] addr4 ;
wire updata_ram ;
wire [11:0] vcnt ;
reg [7:0] data11_buf ;
reg [7:0] data12_buf ;
reg [7:0] data21_buf ;
reg [7:0] data22_buf ;
wire [20:0] add_r1 ;
wire [20:0] add_r2 ;
reg flag ;
reg [11:0] cnt ;
reg [2:0] shift ;
//get clk and reset
clk_rst_gen clk_rst_gen_inst
(
//INPUTS
//OUTPUTS
.clk_50m (clk_50m ),
.clk_8x (clk_8x ),
.rst_n (rst_n )
);
reg signed [7:0] SRC_RAM11[5760:0];
reg signed [7:0] SRC_RAM12[5760:0];
reg signed [7:0] SRC_RAM21[5760:0];
reg signed [7:0] SRC_RAM22[5760:0];
reg updata_ram_dly ;
reg signed [7:0] SRC_RAM1[2073600:0];
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
updata_ram_dly <= 1'b0;
end
else begin
updata_ram_dly <= updata_ram;
end
end
always @(posedge clk_50m or negedge rst_n)begin
if(!rst_n)begin
data11_buf <=8'd0;
data12_buf <=8'd0;
data21_buf <=8'd0;
data22_buf <=8'd0;
end
else begin
data11_buf <=SRC_RAM11[addr1];
data12_buf <=SRC_RAM12[addr2];
data21_buf <=SRC_RAM21[addr3];
data22_buf <=SRC_RAM22[addr4];
end
end
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b0;
end
else if(cnt == 1919)begin
flag <= 1'b0;
end
else if(updata_ram_dly == 1'b0 && updata_ram == 1'b1)begin
flag <= 1'b1;
end
else begin
flag <= flag;
end
end
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
shift <= 3'b100;
end
else if(fsync) begin
shift <= 3'b100;
end
else if(updata_ram_dly == 1'b0 && updata_ram == 1'b1)begin
shift <= {shift[1:0],shift[2]};
end
else begin
shift <= shift;
end
end
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
cnt <= 12'd0;
end
else if(flag == 1'b1)begin
if(cnt == 12'd1919)begin
cnt <= 12'd0;
end
else begin
cnt <= cnt +12'd1;
end
end
else begin
cnt <= cnt;
end
end
reg [7:0] ram11;
reg [7:0] ram12;
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
ram11 <= 8'd0;
ram12 <= 8'd0;
end
else begin
ram11 <= SRC_RAM1[add_r1 +cnt];
ram12 <= SRC_RAM1[add_r1 +cnt];
end
end
reg [12:0] addr_ram;
always @(*)begin
if(shift[0])begin
addr_ram<= cnt;
end
else if(shift[1])begin
addr_ram<= 11'd1920 +cnt;
end
else if(shift[2]) begin
addr_ram <= 13'd3840+cnt;
end
else begin
addr_ram<=addr_ram;
end
end
//assign addr_ram = shift[0] ==1'b1?cnt:(shift[1] ==1'b1?(11'd1920 +cnt):(shift[2] ==1'b1?(12'd3840+cnt):addr_ram));
always @(posedge clk_8x or negedge rst_n)begin
if(!rst_n)begin
SRC_RAM11[addr_ram] <= 8'd0;
SRC_RAM12[addr_ram] <= 8'd0;
SRC_RAM21[addr_ram] <= 8'd0;
SRC_RAM22[addr_ram] <= 8'd0;
end
// else if(shift[0])begin
// SRC_RAM11[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM12[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM21[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// SRC_RAM22[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// end
// else if(shift[1])begin
// SRC_RAM11[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM12[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM21[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// SRC_RAM22[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// end
// else if(shift[2])begin
// SRC_RAM11[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM12[addr_ram] <= SRC_RAM1[add_r1 +cnt];
// SRC_RAM21[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// SRC_RAM22[addr_ram] <= SRC_RAM1[add_r2 +cnt];
// end
else begin
SRC_RAM11[addr_ram] <=SRC_RAM1[add_r1 +cnt];
SRC_RAM12[addr_ram] <=SRC_RAM1[add_r1 +cnt];
SRC_RAM21[addr_ram] <=SRC_RAM1[add_r2 +cnt];
SRC_RAM22[addr_ram] <=SRC_RAM1[add_r2 +cnt];
end
end
// wire [21:0] addr_buf1;
// wire [21:0] addr_buf2;
// assign addr_buf1 = vcnt * 10'd640;
// assign addr_buf2 = (vcnt + 1'b1) *10'd640;
wire [23:0] add_r3;
wire [23:0] add_r4;
assign add_r3 = ((updata_ram_dly == 1'b0 && updata_ram == 1'b1) ? vcnt * 12'd1920 : add_r3) ;//+cnt;
assign add_r4 = ((updata_ram_dly == 1'b0 && updata_ram == 1'b1 ) ? (vcnt >= 12'd1079)? (12'd1079 * 12'd1920) : (vcnt + 1'b1) *12'd1920 : add_r4);// +cnt;
assign add_r1 = add_r3[20:0];
assign add_r2 = add_r4[20:0];
integer fid;
integer i;
integer s;
initial
begin
fid = $fopen("../src/test_1080p.txt","r");
for(i=0;i<2073600;i=i+1) //460*512
begin
s= $fscanf(fid,"%d",SRC_RAM1[i]);
end
$fclose(fid);
end
//这里替换掉是个灰阶
// reg flag11 ;
// reg [3:0] cnt8;
// reg [7:0] ram1_buff;
// reg [20:0] cnt20 ;
// reg [7:0] cnt88;
// always @(posedge clk_8x or negedge rst_n)begin
// if(!rst_n)begin
// flag11 <= 1'b1;
// end
// else if(cnt20 == 21'd2073600)begin
// flag11 <= 1'b0;
// end
// else begin
// flag11 <=flag11;
// end
// end
// always @(posedge clk_8x or negedge rst_n)begin
// if(!rst_n)begin
// cnt8 <= 4'd1;
// end
// else if(flag11 == 1'b1)begin
// if(cnt8 == 8'd8)begin
// cnt8 <= 4'd1;
// end
// else begin
// cnt8 <= 4'd1 +cnt8;
// end
// end
// else begin
// cnt8 <= cnt8;
// end
// end
// always @(posedge clk_8x or negedge rst_n)begin
// if(!rst_n)begin
// cnt20 <= 21'd0;
// end
// else if(flag11 == 1'b1 )begin
// cnt20 <= cnt20 +21'd1;
// end
// else begin
// cnt20 <=cnt20;
// end
// end
// always @(posedge clk_8x or negedge rst_n)begin
// if(!rst_n)begin
// cnt88 <= 8'd0;
// end
// else if(flag11 == 1'b1 && cnt8 == 4'd8)begin
// if(cnt88 == 8'd239)begin
// cnt88 <= 8'd0;
// end
// else begin
// cnt88 <= 8'd1 +cnt88;
// end
// end
// else begin
// cnt88 <= cnt88;
// end
// end
// always @(posedge clk_8x or negedge rst_n)begin
// if(!rst_n)begin
// SRC_RAM1[cnt20] <= 8'd0;
// ram1_buff <=8'd0;
// end
// else if(flag11 == 1'b1)begin
// SRC_RAM1[cnt20] <= cnt88;
// ram1_buff <=cnt88;
// end
// else begin
// ram1_buff <= ram1_buff;
// end
// end
dv_timing dv_timing_inst(
.clk (clk_50m ),
.rst_n (rst_n ),
.hsync (hsync ),
.hsync_pre (hsync_pre ),
.vsync (vsync ),
.vsync_pre ( ),
.fsync (fsync )
);
assign data11 = data11_buf;
assign data12 = data12_buf;
assign data21 = data21_buf;
assign data22 = data22_buf;
zoom #(
.ORG_WIDTH (1920 ) , //放大前数据宽
.ORG_HEIGHT (1080 ) , //放大前数据高
.TAR_WIDTH (800 ) , //放大后目标数据宽
.TAR_HEIGHT (600 ) , //放大后目标数据高
.ORG_WIDTH_W (12 ) , //放大前数据宽
.ORG_HEIGHT_H (12 ) , //放大前数据高
.TAR_WIDTH_W (10 ) , //放大后目标数据宽
.TAR_HEIGHT_H (10 ) , //放大后目标数据高
.RAM_ADDR_START1 (0 ) ,
.RAM_ADDR_START2 (1920 ) ,
.RAM_ADDR_START3 (3840 ) ,
.RAM_ADDR_WIDTH (13 ) ,
.NZOOM (1024 ) ,
.nZoomFPNZOOMFPN (16 )
)
zoom_inst
(
.i_clk (clk_50m ),
.i_rst_n (rst_n ),
.i_zoom_ctrl (1'b1), //1:大 0:小
.i_ram_sel (1'b0),
.i_hsync (hsync ),
.i_hsync_pre (hsync_pre ),
.i_vsync (vsync ),
.i_fsync (fsync ),
.i_data11 (data11 ),
.i_data12 (data12 ),
.i_data21 (data21 ),
.i_data22 (data22 ),
.o_addr1 (addr1 ),
.o_addr2 (addr2 ),
.o_addr3 (addr3 ),
.o_addr4 (addr4 ),
.o_data (data ),
.o_hsync (data_vld),
.o_hsync_pre (),
.o_vsync (),
.o_fsync (),
.o_vcnt (vcnt),
.o_updata_ram (updata_ram)
);
reg [3:0] cnt22;
reg wr_en;
always @(posedge clk_50m or negedge rst_n)begin
if(!rst_n)begin
cnt22 <= 4'd0;
end
else if(fsync)begin
cnt22 <= cnt22 +4'd1;
end
else begin
cnt22 <= cnt22;
end
end
integer fid2;
initial
begin
#1000000
fid2 = $fopen("C:/Users/li_thers/Desktop/zoom/src/test_800_600.txt","w");
wr_en=1'b1;
#24200000
wr_en=1'b0;
// $fclose(fid2) ;
end
always@(posedge clk_50m)
begin
if(data_vld && cnt22 == 4'd1)
begin
$fwrite(fid2,"%d\n",$unsigned(data));
end
end
endmodule
其它辅助模块
仿真产生时钟
下面展示一些 内联代码片
。
//============================================================
`timescale 1ps/1ps
//============================================================
// module name defination
module clk_rst_gen (
//INPUTS
//OUTPUTS
clk_50m,
clk_8x,
rst_n
);
//INPUTS
//OUTPUTS
output clk_50m;
output clk_8x;
output rst_n;
reg clk_50m; // 100Mhz
reg clk_8x; //8倍
reg rst_n;
initial
begin
clk_50m = 1'b0;
clk_8x = 1'b0;
rst_n = 1'b1;
end
always #10000 clk_50m = ~clk_50m;
always #1250 clk_8x = ~clk_8x;
initial
begin
#10000 rst_n=0;
#10000 rst_n=1;
end
endmodule
//1080p时序无有效数据
module dv_timing(
input clk ,
input rst_n ,
output hsync ,
output hsync_pre ,
output vsync ,
output vsync_pre ,
output fsync
);
//参数定义
parameter HMUN = 12'd900, // 2560
VMUN = 12'd700; // 2048
//中间信号定义
reg [11:0] vcnt;
reg [11:0] hcnt;
assign hsync = vsync && (hcnt >12'd20) && (hcnt <=12'd820);
assign hsync_pre = vsync_pre && (hcnt >12'd20) && (hcnt <=12'd820);
assign vsync = vcnt >12'd10 && vcnt <=12'd610;
assign vsync_pre = vcnt >12'd9 && vcnt <=12'd609;
assign fsync = vcnt == 12'd2 && hcnt == 12'd1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
hcnt <= 12'd1;
end
else if(hcnt == HMUN)begin
hcnt <= 12'd1;
end
else begin
hcnt <= 12'd1 + hcnt;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
vcnt <= 12'd1;
end
else if(hcnt == HMUN)begin
if(vcnt == VMUN)begin
vcnt <= 12'd1;
end
else begin
vcnt <= 12'd1 + vcnt;
end
end
else begin //hold
vcnt <= vcnt;
end
end
endmodule
do文件
vlib work
vlog ../src/dv_timing/dv_timing_copy.v
vlog ../src/clk_rst_gen/clk_rst_gen.v
vlog ../src/dis_play/zoom/*.v
vlog ../tb/zoom_tb.v
vsim -novopt work.zoom_tb
add wave sim:/zoom_tb/clk_rst_gen_inst/*
add wave sim:/zoom_tb/zoom_inst/*
#radix -dec
run 2700 us
#run 180 us
clear all
data1 = load('data_640_512.txt');
img1 = reshape(data1,640,512);
img1=flipud(img1');
figure(1);
surf(img1);
shading interp;
axis image;
view(2);
colormap(gray);
data2 = load('test_1920_1080x.txt');
img2 = reshape(data2,1920,1080);
img2=flipud(img2');
figure(2);
surf(img2);
shading interp;
axis image;
view(2);
colormap(gray);
data3 = load('test_1920_1080x1.txt');
img3 = reshape(data3,1920,1080);
img2=flipud(img3');
figure(3);
surf(img2);
shading interp;
axis image;
view(2);
colormap(gray);