在Verilog中,generate 和 endgenerate 用于在编译时生成硬件结构,实现参数化设计和代码复用。
一、基本语法
generate
// 生成语句
endgenerate
二、主要应用场景
1. 条件生成 - if/else
根据参数条件生成不同的硬件结构:
module param_mux #(
parameter WIDTH = 8,
parameter USE_REGISTERED = 1
) (
input [WIDTH-1:0] a, b,
input sel,
output reg [WIDTH-1:0] out
);
generate
if (USE_REGISTERED == 1) begin
// 生成带寄存器的输出
always @(posedge clk) begin
out <= sel ? a : b;
end
end else begin
// 生成组合逻辑输出
always @* begin
out = sel ? a : b;
end
end
endgenerate
endmodule
2. 循环生成 - for
批量生成重复的硬件结构:
module n_bit_adder #(
parameter WIDTH = 8
) (
input [WIDTH-1:0] a, b,
input cin,
output [WIDTH-1:0] sum,
output cout
);
wire [WIDTH:0] carry;
assign carry[0] = cin;
generate
genvar i;
for (i = 0; i < WIDTH; i = i + 1) begin : adder_chain
full_adder fa_inst (
.a(a[i]),
.b(b[i]),
.cin(carry[i]),
.sum(sum[i]),
.cout(carry[i+1])
);
end
endgenerate
assign cout = carry[WIDTH];
endmodule
// 全加器子模块
module full_adder(
input a, b, cin,
output sum, cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (a & cin) | (b & cin);
endmodule
3. 案例生成 - case
根据参数选择不同的实现:
module alu #(
parameter ARCH = "RIPPLE"
) (
input [7:0] a, b,
output [7:0] result
);
generate
case (ARCH)
"RIPPLE": begin
// 行波进位加法器
ripple_adder adder_inst(a, b, result);
end
"CARRY_LOOKAHEAD": begin
// 超前进位加法器
carry_lookahead_adder adder_inst(a, b, result);
end
"CLA": begin
// 另一种超前进位实现
cla_adder adder_inst(a, b, result);
end
default: begin
// 默认实现
assign result = a + b;
end
endcase
endgenerate
endmodule
三、高级用法
1. 多维数组生成
module crossbar_switch #(
parameter PORTS = 4,
parameter DATA_WIDTH = 16
) (
input [PORTS-1:0][DATA_WIDTH-1:0] data_in,
input [PORTS-1:0][$clog2(PORTS)-1:0] sel,
output [PORTS-1:0][DATA_WIDTH-1:0] data_out
);
generate
genvar i, j;
for (i = 0; i < PORTS; i = i + 1) begin : output_ports
for (j = 0; j < PORTS; j = j + 1) begin : input_ports
// 生成选择逻辑
assign data_out[i] = (sel[i] == j) ? data_in[j] : {DATA_WIDTH{1'bz}};
end
end
endgenerate
endmodule
2. 存储器生成
module param_ram #(
parameter DEPTH = 1024,
parameter WIDTH = 32,
parameter INIT_FILE = ""
) (
input clk,
input we,
input [$clog2(DEPTH)-1:0] addr,
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
// 寄存器堆实现
(* ram_style = "block" *) reg [WIDTH-1:0] memory [0:DEPTH-1];
// 初始化存储器
generate
if (INIT_FILE != "") begin
initial begin
$readmemh(INIT_FILE, memory);
end
end else begin
integer k;
initial begin
for (k = 0; k < DEPTH; k = k + 1) begin
memory[k] = {WIDTH{1'b0}};
end
end
end
endgenerate
always @(posedge clk) begin
if (we) begin
memory[addr] <= din;
end
end
assign dout = memory[addr];
endmodule
3. 层次化模块生成
module tree_adder #(
parameter WIDTH = 16
) (
input [WIDTH-1:0] data,
output [15:0] sum
);
localparam LEVELS = $clog2(WIDTH);
generate
if (WIDTH == 1) begin
// 基本情况
assign sum = data;
end else begin
// 递归分解
wire [15:0] left_sum, right_sum;
tree_adder #(.WIDTH(WIDTH/2)) left_tree (
.data(data[WIDTH/2-1:0]),
.sum(left_sum)
);
tree_adder #(.WIDTH(WIDTH-WIDTH/2)) right_tree (
.data(data[WIDTH-1:WIDTH/2]),
.sum(right_sum)
);
assign sum = left_sum + right_sum;
end
endgenerate
endmodule
四、重要注意事项
1. genvar 变量
generate
genvar i; // 必须声明为genvar类型
for (i = 0; i < 8; i = i + 1) begin : loop_name
// 每个i实例都是独立的硬件
my_module inst (.in(inputs[i]), .out(outputs[i]));
end
endgenerate
2. 必须命名生成块
generate
for (i = 0; i < 4; i = i + 1) begin : block_name // 必须命名
// 生成内容
end
endgenerate
// 引用生成块中的信号
wire [3:0] internal_sig = block_name[0].some_signal;
3. 编译时确定
// ✅ 正确 - 参数在编译时确定
generate
for (i = 0; i < PARAMETER_VALUE; i = i + 1) begin
// ...
end
endgenerate
// ❌ 错误 - 循环变量在运行时变化
generate
for (i = 0; i < some_wire_signal; i = i + 1) begin // 不允许!
// ...
end
endgenerate
五、实际应用示例
1. 可配置的移位寄存器
module param_shift_reg #(
parameter WIDTH = 8,
parameter DEPTH = 4
) (
input clk, rst,
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
reg [WIDTH-1:0] shift_reg [0:DEPTH-1];
generate
genvar i;
for (i = 0; i < DEPTH; i = i + 1) begin : shift_stage
if (i == 0) begin
// 第一级
always @(posedge clk) begin
if (rst)
shift_reg[i] <= {WIDTH{1'b0}};
else
shift_reg[i] <= din;
end
end else begin
// 后续级
always @(posedge clk) begin
if (rst)
shift_reg[i] <= {WIDTH{1'b0}};
else
shift_reg[i] <= shift_reg[i-1];
end
end
end
endgenerate
assign dout = shift_reg[DEPTH-1];
endmodule
generate 语句是Verilog中实现参数化设计和代码复用的强大工具,特别适合创建可配置的IP核和可伸缩的硬件架构。
4946

被折叠的 条评论
为什么被折叠?



