1define预定义参数的注意事项
如果要根据预定义的参数进行分类定义另一个参数的时候,不能直接用这种或方式对预定义参数进行判断。也就是说对于预定义的参数,如果是根据这个来进行判断,则需要用`ifdef来进行操作;如果是直接用这个参数的值进行计算,则`DIN_SIGNED直接使用。(但要特别注意,如果是将预定义的参数进行拼接时,要特别注意位宽,因为预定义的参数位宽是未知的,可以在预定义的时候就指定位宽,或者重新定义一个参数,规定他的位宽)
`define DIN_SIGNED 1
// 1 正确
`ifdef DIN_SIGNED
localparam DOUT_SIGNED = 1'b1;
`elsif COEF_SIGNED
localparam DOUT_SIGNED = 1'b1;
`else
localparam DOUT_SIGNED = 1'b0;
`endif
//2 错误
localparam DOUT_SIGNED = (`DIN_SIGNED || `COEF_SIGNED) ? 1'b1 : 1'b0;
//-------------------------------------------------------
//1
`define DIN_SIGNED 1
assign data_out0 = {{(2){`DIN_SIGNED}},data_in} ; //错误
assign data_out1 = data_in + `DIN_SIGNED ; //true
//2
`define DIN_SIGNED 1'b1
assign data_out0 = {{(2){`DIN_SIGNED}},data_in} ; //true
assign data_out1 = data_in + `DIN_SIGNED ; //true
2.根据预定义参数进行数据的打拍
预定义打拍数
// define "DSP_OUT_REG_L0" 不打拍
// define "DSP_OUT_REG_L1" 打一拍
// define "DSP_OUT_REG_L2" 打两拍
// define "DSP_OUT_REG_L3" 打三拍
`define DSP_OUT_REG_L2
`ifdef DSP_OUT_REG_L0
`define DOUT_REG_LEVEL 0
`elsif DSP_OUT_REG_L1
`define DOUT_REG_LEVEL 1
`elsif DSP_OUT_REG_L2
`define DOUT_REG_LEVEL 2
`elsif DSP_OUT_REG_L3
`define DOUT_REG_LEVEL 3
`else
`define DOUT_REG_LEVEL 0
`endif
第一种方式:直接对每种打拍都实现,然后根据预定义参数进行选择输出
缺点:这种方式会产生资源的浪费,如果用户并不期望打拍,但还是使用到了三级的打拍电路
优点:代码美观
reg dout_vld_temp_dl1;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl1;
reg dout_vld_temp_dl2;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl2;
reg dout_vld_temp_dl3;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl3;
always @(posedge clk) begin
if (~intl_rstn) begin
dout_vld_temp_dl1 <= 1'b0;
dout_vld_temp_dl2 <= 1'b0;
dout_vld_temp_dl3 <= 1'b0;
dout_temp_dl1 <= {DOUT_TOTAL_BITS{1'b0}};
dout_temp_dl2 <= {DOUT_TOTAL_BITS{1'b0}};
dout_temp_dl3 <= {DOUT_TOTAL_BITS{1'b0}};
end
else begin
dout_vld_temp_dl1 <= dout_vld_temp;
dout_vld_temp_dl2 <= dout_vld_temp_dl1;
dout_vld_temp_dl3 <= dout_vld_temp_dl2;
dout_temp_dl1 <= dout_temp;
dout_temp_dl2 <= dout_temp_dl1;
dout_temp_dl3 <= dout_temp_dl2;
end
end
`ifdef DSP_OUT_REG_L0
parameter DOUT_REG_LEVEL = 0;
assign dout = dout_temp;
assign dout_vld = dout_vld_temp;
`elsif DSP_OUT_REG_L1
assign dout = dout_temp_dl1;
assign dout_vld = dout_vld_temp_dl1;
`elsif DSP_OUT_REG_L2
assign dout = dout_temp_dl2;
assign dout_vld = dout_vld_temp_dl2;
`elsif DSP_OUT_REG_L3
assign dout = dout_temp_dl3;
assign dout_vld = dout_vld_temp_dl3;
`endif
第二种方式:根据预定义参数,产生不同的打拍次数,并输出
缺点:代码很多
优点:这种方式不会产生资源的浪费,
generate
if (DOUT_REG_LEVEL == 0 ) begin: L0
assign dout = dout_temp;
assign dout_vld = dout_vld_temp;
end
endgenerate
generate
if (DOUT_REG_LEVEL == 1 ) begin: L1
reg dout_vld_temp_dl1;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl1;
always @(posedge clk) begin
if (~intl_rstn) begin
dout_temp_dl1 <= {DOUT_TOTAL_BITS{1'b0}};
dout_vld_temp_dl1 <= 1'b0;
end
else begin
dout_temp_dl1 <= dout_temp;
dout_vld_temp_dl1 <= dout_vld_temp;
end
end
assign dout = dout_temp_dl1;
assign dout_vld = dout_vld_temp_dl1;
end
endgenerate
generate
if (DOUT_REG_LEVEL == 2 ) begin: L2
reg dout_vld_temp_dl1;
reg dout_vld_temp_dl2;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl1;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl2;
always @(posedge clk) begin
if (~intl_rstn) begin
dout_vld_temp_dl1 <= 1'b0;
dout_vld_temp_dl2 <= 1'b0;
dout_temp_dl1 <= {DOUT_TOTAL_BITS{1'b0}};
dout_temp_dl2 <= {DOUT_TOTAL_BITS{1'b0}};
end
else begin
dout_vld_temp_dl1 <= dout_vld_temp;
dout_vld_temp_dl2 <= dout_vld_temp_dl1;
dout_temp_dl1 <= dout_temp;
dout_temp_dl2 <= dout_temp_dl1;
end
end
assign dout = dout_temp_dl2;
assign dout_vld = dout_vld_temp_dl2;
end
endgenerate
generate
if (DOUT_REG_LEVEL == 3 ) begin: L3
reg dout_vld_temp_dl1;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl1;
reg dout_vld_temp_dl2;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl2;
reg dout_vld_temp_dl3;
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl3;
always @(posedge clk) begin
if (~intl_rstn) begin
dout_vld_temp_dl1 <= 1'b0;
dout_vld_temp_dl2 <= 1'b0;
dout_vld_temp_dl3 <= 1'b0;
dout_temp_dl1 <= {DOUT_TOTAL_BITS{1'b0}};
dout_temp_dl2 <= {DOUT_TOTAL_BITS{1'b0}};
dout_temp_dl3 <= {DOUT_TOTAL_BITS{1'b0}};
end
else begin
dout_vld_temp_dl1 <= dout_vld_temp;
dout_vld_temp_dl2 <= dout_vld_temp_dl1;
dout_vld_temp_dl3 <= dout_vld_temp_dl2;
dout_temp_dl1 <= dout_temp;
dout_temp_dl2 <= dout_temp_dl1;
dout_temp_dl3 <= dout_temp_dl2;
end
end
assign dout = dout_temp_dl2;
assign dout_vld = dout_vld_temp_dl2;
end
endgenerate
第三种方式:定义二维数组,始终生成一次打拍,其他根据预定义参数进行打拍
优点:这种方式只会最多产生一级的资源浪费
localparam DOUT_REG_LEVEL_REAL = (`DOUT_REG_LEVEL == 0) ? 0 : `DOUT_REG_LEVEL-1;
reg dout_vld_temp_dl[DOUT_REG_LEVEL_REAL:0];
reg [DOUT_TOTAL_BITS-1:0] dout_temp_dl[DOUT_REG_LEVEL_REAL:0];
always @(posedge clk) begin
if (~intl_rstn) begin
dout_vld_temp_dl[0] <= 1'b0;
dout_temp_dl[0] <= {DOUT_TOTAL_BITS{1'b0}};
end else begin
dout_vld_temp_dl[0] <= dout_vld_temp;
dout_temp_dl[0] <= dout_temp;
end
end
generate
if (DOUT_REG_LEVEL_REAL > 0) begin
genvar n;
for (n = 1; n <= `DOUT_REG_LEVEL; n = n + 1) begin : dout_buf_dl_gen
always @(posedge clk) begin
if (~intl_rstn) begin
dout_vld_temp_dl[n] <= 1'b0;
dout_temp_dl[n] <= {DOUT_TOTAL_BITS{1'b0}};
end else begin
dout_vld_temp_dl[n] <= dout_vld_temp_dl[n-1];
dout_temp_dl[n] <= dout_temp_dl[n-1];
end
end
end
end
endgenerate
//------------------------------------------1
//assign dout_vld = (`DOUT_REG_LEVEL == 0) ? dout_vld_temp : dout_vld_temp_dl[DOUT_REG_LEVEL_REAL];
//assign dout = (`DOUT_REG_LEVEL == 0) ? dout_temp : dout_temp_dl[DOUT_REG_LEVEL_REAL];
//------------------------------------------2
`ifdef DSP_OUT_REG_L0
assign dout_vld = dout_vld_temp;
assign dout = dout_temp;
`else
assign dout_vld = dout_vld_temp_dl[DOUT_REG_LEVEL_REAL];
assign dout = dout_temp_dl[DOUT_REG_LEVEL_REAL];
`endif
//------------------------------------------3
/*
generate
if (`DOUT_REG_LEVEL == 0) begin :dout_gen
assign dout_vld = dout_vld_temp;
assign dout = dout_temp;
end
else begin :dout_dl_gen
assign dout_vld = dout_vld_temp_dl[DOUT_REG_LEVEL_REAL];
assign dout = dout_temp_dl[DOUT_REG_LEVEL_REAL];
end
endgenerate*/
第一段是产生一级打拍时的电路,后面的for是为了产生二级和三级的打拍。后面的输出一共有三种方式,如果用assign会产生一个多余的输出选择电路。使用define或者generate则只会产生相应的电路。