编码不同参数的时序逻辑代码非常重要,这样的代码风格更加结构化。
通用寄存器模块的Verilog代码
寄存器中的数据宽度是可以变化的主要参数。因此,数据宽度可以被视为“参数”。通用代码可以取数据宽度的任何值。如果宽度为1,那么它将变成一个简单的D触发器。代码如下
input [N-1:0] a;
output reg [N-1:0] y;
input clk,reset;
always @(posedge clk)
if (reset)
y <= 0;
else
y <= a;
endmodule
一般延迟模块
当在复杂的设计中我们需要不同的延迟时,通用延迟块非常有用。在某些阶段,我们可能需要4个时钟周期的延迟,在另一个阶段,我们可能需要9个时钟周期的延迟。
因此,我们不应该编写单独的模块。一般延迟模块如下所示
parameter D = 4)(clk,reset,a,aN);
input clk,reset;
input [N-1:0] a;
output [N-1:0] aN;
wire [N-1:0] tmp [D:0];
assign tmp[0] = a;
generate
genvar p;
for (p = 1; p <= D; p = p+1) begin: General_delay
regN #(N) rg(tmp[p],clk,reset,tmp[p-1]);
end
endgenerate
assign aN = tmp[D];
endmodule
D = 4的一般延迟块的RTL示意图
模块regN是之前定义的,它在这里用于实现一拍延迟的触发器。如果我们需要4个时钟周期的延迟,那么我们将需要4个regN模块。如果参数D的值为4,则“generate”命令将生成4个regN块。模块生成将使用“genvar”命令基于一个名为“p”的变量完成。
需要注意的是,genvar变量的名称和参数的名称不应该相同。如果一个参数名称是N,genvar变量是n,那么代码将合成实际所需的结构。
一般计数器模块
在复杂的设计中,有时也需要通用计数器模块,以便一个verilog代码可以在任何地方使用。下面写有一个通用计数器模块。
这个计数器可以作为加法计数器实现,也可以作为减法计数器实现。
(count,data,load,en,clk,reset,tc,lmt
);
output [N-1:0] count;
output tc;
input [N-1:0] data,lmt;
input load, en, clk,reset;
generate
case(up)
1'b0 : counterupN #(N) u0(count,data,load,en,clk,reset,tc,lmt);
1'b1 : counterdnN #(N) u1(count,data,load,en,clk,reset,tc,lmt);
endcase
endgenerate
endmodule
module counterupN #(parameter N = 10)(count,data,load,en,clk,reset,tc,lmt);
output [N-1:0] count;
output reg tc;
input [N-1:0] data,lmt;
input load, en, clk,reset;
reg [N-1:0] count;
always @(posedge clk)
if (reset) begin
count <= 1'b0 ;
end else if (load) begin
count <= data;
end else if (en)
count <= count + 1'b1;
else count <= count;
always @*
if (count ==lmt)
tc=1;
else tc=0;
endmodule
module counterdnN #(parameter N = 10)(count,data,load,en,clk,reset,tc,lmt);
output [N-1:0] count;
output reg tc;
input [N-1:0] data,lmt;
input load, en, clk,reset;
reg [N-1:0] count;
always @(posedge clk)
if (reset) begin
count <= 1'b0 ;
end else if (load) begin
count <= data;
end else if (en)
count <= count - 1'b1;
else count <= count;
always @*
if (count ==lmt)
tc=1;
else tc=0;
endmodule```