跳到主要内容

层次化设计

层次化设计是数字电路设计的重要方法,通过模块实例化和参数化设计实现代码复用和层次化管理。

模块实例化

基本实例化

// 子模块定义
module and_gate(
input a,
input b,
output y
);
assign y = a & b;
endmodule

// 父模块实例化
module top_module(
input a,
input b,
output y
);
// 实例化子模块
and_gate u_and(
.a(a),
.b(b),
.y(y)
);
endmodule

端口连接方式

命名端口连接(推荐)

module_name instance_name (
.port1(signal1),
.port2(signal2),
.port3(signal3)
);

优点:

  • 端口顺序无关
  • 可读性好
  • 易于维护

位置端口连接

module_name instance_name (signal1, signal2, signal3);

缺点:

  • 必须按照定义顺序
  • 可读性差
  • 容易出错

端口位宽匹配

module adder(
input [7:0] a,
input [7:0] b,
output [7:0] sum
);
assign sum = a + b;
endmodule

module top;
wire [15:0] data1, data2;
wire [15:0] result;

// 位宽不匹配警告
adder u_adder(
.a(data1[7:0]), // 正确:选择低 8 位
.b(data2[7:0]),
.sum(result[7:0])
);
endmodule

未连接端口

module counter(
input clk,
input reset,
input enable,
output [7:0] count,
output carry
);

module top;
wire clk, reset;
wire [7:0] count;

counter u_counter(
.clk(clk),
.reset(reset),
.enable(1'b1), // 常量连接
.count(count),
.carry() // 未连接(悬空)
);
endmodule

参数化设计

参数定义

module counter #(
parameter WIDTH = 8,
parameter MAX_COUNT = 255
)(
input clk,
input reset,
output [WIDTH-1:0] count
);
reg [WIDTH-1:0] counter;

always @(posedge clk or posedge reset) begin
if (reset)
counter <= 0;
else if (counter == MAX_COUNT)
counter <= 0;
else
counter <= counter + 1;
end

assign count = counter;
endmodule

参数覆盖

实例化时覆盖

// 位置参数覆盖
counter #(16, 65535) u_counter_16bit (
.clk(clk),
.reset(reset),
.count(count)
);

// 命名参数覆盖(推荐)
counter #(
.WIDTH(16),
.MAX_COUNT(65535)
) u_counter_16bit (
.clk(clk),
.reset(reset),
.count(count)
);

defparam 覆盖(不推荐)

counter u_counter(clk, reset, count);

defparam u_counter.WIDTH = 16;
defparam u_counter.MAX_COUNT = 65535;

参数传递

module top #(
parameter DATA_WIDTH = 8
)(
input clk,
input reset,
input [DATA_WIDTH-1:0] data_in,
output [DATA_WIDTH-1:0] data_out
);
// 将参数传递给子模块
register #(
.WIDTH(DATA_WIDTH)
) u_reg (
.clk(clk),
.reset(reset),
.enable(1'b1),
.din(data_in),
.dout(data_out)
);
endmodule

localparam

localparam 不能被外部覆盖:

module fifo #(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk,
input reset,
// ...
);
// 从其他参数计算得出
localparam ADDR_WIDTH = $clog2(DEPTH);
localparam DEPTH_MINUS_1 = DEPTH - 1;

reg [ADDR_WIDTH-1:0] wr_ptr, rd_ptr;
// ...
endmodule

生成语句

generate for

module adder_array #(
parameter WIDTH = 8,
parameter COUNT = 4
)(
input [WIDTH*COUNT-1:0] a,
input [WIDTH*COUNT-1:0] b,
output [WIDTH*COUNT-1:0] sum
);
genvar i;
generate
for (i = 0; i < COUNT; i = i + 1) begin : adder_gen
wire [WIDTH-1:0] a_slice = a[WIDTH*i +: WIDTH];
wire [WIDTH-1:0] b_slice = b[WIDTH*i +: WIDTH];
wire [WIDTH-1:0] sum_slice;

adder #(.WIDTH(WIDTH)) u_adder(
.a(a_slice),
.b(b_slice),
.sum(sum_slice)
);

assign sum[WIDTH*i +: WIDTH] = sum_slice;
end
endgenerate
endmodule

generate if

module configurable_module #(
parameter IMPLEMENTATION = "FAST"
)(
input clk,
input reset,
input [7:0] data_in,
output [7:0] data_out
);
generate
if (IMPLEMENTATION == "FAST") begin : fast_impl
// 快速实现(面积大)
pipeline_register u_reg(
.clk(clk),
.reset(reset),
.din(data_in),
.dout(data_out)
);
end else begin : small_impl
// 小面积实现(速度慢)
simple_register u_reg(
.clk(clk),
.reset(reset),
.din(data_in),
.dout(data_out)
);
end
endgenerate
endmodule

generate case

module alu #(
parameter WIDTH = 8,
parameter ALU_TYPE = "BASIC"
)(
input [WIDTH-1:0] a,
input [WIDTH-1:0] b,
input [3:0] op,
output [WIDTH-1:0] result
);
generate
case (ALU_TYPE)
"BASIC": begin : basic_alu
basic_alu u_alu(.a(a), .b(b), .op(op), .result(result));
end
"EXTENDED": begin : extended_alu
extended_alu u_alu(.a(a), .b(b), .op(op), .result(result));
end
default: begin : default_alu
basic_alu u_alu(.a(a), .b(b), .op(op), .result(result));
end
endcase
endgenerate
endmodule

层次结构访问

层次路径

module top;
wire [7:0] data;

submodule u_sub(
.data(data)
);

// 访问子模块内部信号
initial begin
$display("submodule signal: %h", top.u_sub.internal_signal);
end
endmodule

module submodule(
output [7:0] data
);
reg [7:0] internal_signal;
// ...
endmodule

层次化名称

module top;
// 使用层次化名称访问
initial begin
$monitor("Counter value: %d", top.u_counter.counter);
end

counter u_counter(.clk(clk), .reset(reset), .count(count));
endmodule

设计实例

多位加法器

module adder_nbit #(
parameter N = 4
)(
input [N-1:0] a,
input [N-1:0] b,
input cin,
output [N-1:0] sum,
output cout
);
wire [N:0] carry;
assign carry[0] = cin;
assign cout = carry[N];

genvar i;
generate
for (i = 0; i < N; i = i + 1) begin : full_adder_gen
full_adder u_fa(
.a(a[i]),
.b(b[i]),
.cin(carry[i]),
.sum(sum[i]),
.cout(carry[i+1])
);
end
endgenerate
endmodule

module full_adder(
input a,
input b,
input cin,
output sum,
output cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule

参数化寄存器堆

module register_file #(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 5,
parameter NUM_REGS = 32
)(
input clk,
input wen,
input [ADDR_WIDTH-1:0] waddr,
input [DATA_WIDTH-1:0] wdata,
input [ADDR_WIDTH-1:0] raddr1,
input [ADDR_WIDTH-1:0] raddr2,
output [DATA_WIDTH-1:0] rdata1,
output [DATA_WIDTH-1:0] rdata2
);
reg [DATA_WIDTH-1:0] regs [0:NUM_REGS-1];

// 写端口
always @(posedge clk) begin
if (wen)
regs[waddr] <= wdata;
end

// 读端口
assign rdata1 = regs[raddr1];
assign rdata2 = regs[raddr2];
endmodule

参数化多路选择器

module mux_n_to_1 #(
parameter WIDTH = 8,
parameter NUM_INPUTS = 4
)(
input [WIDTH-1:0] inputs [0:NUM_INPUTS-1],
input [$clog2(NUM_INPUTS)-1:0] sel,
output [WIDTH-1:0] y
);
assign y = inputs[sel];
endmodule

// 使用示例
module top;
wire [7:0] data [0:3];
wire [1:0] sel;
wire [7:0] out;

mux_n_to_1 #(
.WIDTH(8),
.NUM_INPUTS(4)
) u_mux(
.inputs(data),
.sel(sel),
.y(out)
);
endmodule

参数化 FIFO

module sync_fifo #(
parameter DATA_WIDTH = 8,
parameter DEPTH = 16
)(
input clk,
input reset,
input wr_en,
input rd_en,
input [DATA_WIDTH-1:0] din,
output [DATA_WIDTH-1:0] dout,
output full,
output empty
);
localparam ADDR_WIDTH = $clog2(DEPTH);

reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH:0] wr_ptr;
reg [ADDR_WIDTH:0] rd_ptr;

// 写操作
always @(posedge clk) begin
if (wr_en && !full)
mem[wr_ptr[ADDR_WIDTH-1:0]] <= din;
end

// 读操作
assign dout = mem[rd_ptr[ADDR_WIDTH-1:0]];

// 指针管理
always @(posedge clk or posedge reset) begin
if (reset) begin
wr_ptr <= 0;
rd_ptr <= 0;
end else begin
if (wr_en && !full)
wr_ptr <= wr_ptr + 1;
if (rd_en && !empty)
rd_ptr <= rd_ptr + 1;
end
end

// 状态信号
assign full = (wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]);
assign empty = (wr_ptr == rd_ptr);
endmodule

设计规范

命名约定

// 模块名:小写字母,下划线分隔
module adder_8bit;

// 实例名:u_ 前缀
adder_8bit u_adder_0;

// 参数:大写字母,下划线分隔
parameter DATA_WIDTH = 8;

// 信号:小写字母,下划线分隔
wire [DATA_WIDTH-1:0] data_in;
wire [DATA_WIDTH-1:0] data_out;

// 时钟和复位
wire clk;
wire reset_n; // _n 表示低有效

// 寄存器:_reg 后缀
reg [DATA_WIDTH-1:0] counter_reg;

// 状态:_state 后缀
reg [2:0] current_state;
reg [2:0] next_state;

文件组织

project/
├── rtl/
│ ├── top.v
│ ├── submodule1.v
│ └── submodule2.v
├── tb/
│ ├── tb_top.v
│ └── testdata/
├── constraints/
│ └── top.xdc
└── sim/
└── run_sim.sh

模块结构

//============================================================================
// Module Name: module_name
// Description: 模块描述
// Author: 作者
// Date: 日期
//============================================================================
module module_name #(
// 参数定义
parameter PARAM1 = 8,
parameter PARAM2 = 16
)(
// 端口定义
input clk,
input reset,
input [PARAM1-1:0] data_in,
output [PARAM1-1:0] data_out
);
// 内部信号
wire [PARAM1-1:0] internal_signal;

// 子模块实例化
submodule #(
.WIDTH(PARAM1)
) u_submodule (
.clk(clk),
.reset(reset),
.data_in(data_in),
.data_out(internal_signal)
);

// 功能实现
assign data_out = internal_signal;

endmodule

小结

本章介绍了 Verilog 层次化设计:

  • 模块实例化:命名端口连接、位置端口连接
  • 参数化设计:parameter、localparam、参数覆盖
  • 生成语句:generate for、generate if、generate case
  • 层次结构访问:层次路径、层次化名称
  • 设计实例:多位加法器、寄存器堆、多路选择器、FIFO
  • 设计规范:命名约定、文件组织、模块结构

层次化设计是构建复杂数字系统的基础。下一章将介绍测试平台编写。