1. RTL设计基础:数字电路抽象、硬件描述语言概览、组合逻辑与时序逻辑核心区别

各位同学,欢迎来到《RTL设计与上板联调指南》的第一课。

我是你们的讲师,一个在FPGA和ASIC设计领域摸爬滚打了十几年的老工程师。今天咱们聊点最基础,但也最核心的东西。说白了,就是数字电路的“世界观”和“语言”。

你想想看,我们写的每一行RTL代码,最终都会变成实实在在的硅片上的晶体管。这中间到底发生了什么?嗯,这就是我们今天要搞明白的事。

1.1 数字电路抽象:从沙子到系统

数字电路设计,其实是一个不断“抽象”的过程。我们不需要关心每个晶体管怎么开关,我们只需要关心“0”和“1”。

我个人习惯把数字电路的抽象层次分成五层,就像盖楼一样:

  • 系统级(System Level):最顶层,描述整个芯片是干什么的。比如“这是一个视频编解码器”。
  • 寄存器传输级(RTL Level):我们工程师的主战场。描述数据如何在寄存器之间流动,以及经过什么逻辑运算。这就是我们写Verilog/VHDL的层次。
  • 门级(Gate Level):RTL代码综合后的结果。由与门、或门、非门、触发器这些基本单元组成。
  • 晶体管级(Transistor Level):用MOS管搭出来的电路。模拟工程师和版图设计师关心这个。
  • 物理级(Physical Level):光刻掩膜版上的几何图形。这是芯片制造的最后一步。

核心观点:RTL设计,就是我们在“寄存器传输级”这个抽象层次上,用硬件描述语言来描述数字电路的行为。我们不需要管底层晶体管怎么工作,但必须清楚我们写的代码会综合成什么样的门级电路。

为了让你更直观地理解,我画了一张图:

数字电路抽象层次 系统级 (System) RTL级 (我们的战场) 门级 (Gate) 晶体管级 (Transistor) 物理级 (Physical)

1.2 硬件描述语言概览:Verilog与VHDL

有了抽象层次,我们还需要一种“语言”来描述它。这就是硬件描述语言(HDL)。

目前主流的就是两种:Verilog 和 VHDL。

特性 Verilog VHDL
语法风格 类似C语言,简洁灵活 类似Ada/Pascal,严谨冗长
数据类型 reg, wire, integer等,相对简单 std_logic, std_logic_vector等,类型系统强大
设计粒度 适合从底层到顶层的设计 适合大型系统级设计
学习曲线 较平缓,上手快 较陡峭,但严谨
市场占有率 约70-80%(尤其在中国和美国) 约20-30%(欧洲军工、航天领域较多)

我的建议:如果你是初学者,我强烈建议从Verilog入手。原因很简单——资源多、社区活跃、找工作容易。我在项目中遇到过很多从VHDL转Verilog的同事,基本上一两周就能适应。反过来,从Verilog转VHDL的,往往要痛苦一两个月。

不过,语言只是工具。真正重要的是你脑子里有没有“电路感”。

1.3 组合逻辑与时序逻辑:核心区别

好,到了今天最关键的部分。很多初学者写RTL代码,写着写着就乱了,根本原因就是没搞清楚组合逻辑和时序逻辑的区别。

1.3.1 组合逻辑

定义:输出只取决于当前的输入。没有记忆功能。

特点:

  • 输入一变,输出立刻变(不考虑门延迟)
  • 没有时钟参与
  • 由与门、或门、非门、多路选择器等构成
  • 在Verilog中,用 assign 或 always @(*) 描述

举个最简单的例子——一个2输入与门:

// 组合逻辑:与门
module and_gate (
    input  wire a,
    input  wire b,
    output wire y
);
    assign y = a & b;
endmodule

这段代码综合出来,就是三个晶体管组成的一个与门。没有时钟,没有存储。

1.3.2 时序逻辑

定义:输出不仅取决于当前输入,还取决于之前的状态。有记忆功能。

特点:

  • 在时钟边沿(上升沿或下降沿)采样输入,更新输出
  • 由触发器(Flip-Flop)或锁存器(Latch)构成
  • 在Verilog中,用 always @(posedge clk) 描述

再看一个D触发器的例子:

// 时序逻辑:D触发器
module dff (
    input  wire       clk,
    input  wire       rst_n,
    input  wire       d,
    output reg        q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;  // 异步复位
        else
            q <= d;      // 时钟上升沿采样
    end
endmodule

⚠️ 避坑指南:我曾经见过一个新手,在 always @(posedge clk) 块里用了阻塞赋值 = 而不是非阻塞赋值 <=。结果仿真没问题,上板就跑飞了。记住:时序逻辑用非阻塞赋值 <=,组合逻辑用阻塞赋值 =。这是铁律,别问为什么,先记住。

1.3.3 核心区别对比

对比项 组合逻辑 时序逻辑
记忆能力 无 有(靠触发器)
时钟依赖 不依赖 依赖时钟边沿
输出变化 输入变化后立即变化 时钟边沿到来时变化
Verilog描述 assign 或 always @(*) always @(posedge clk)
赋值方式 阻塞赋值 = 非阻塞赋值 <=
综合结果 门电路(与或非等) 触发器 + 组合逻辑
典型应用 加法器、译码器、多路选择器 计数器、状态机、寄存器

1.3.4 一个混合的例子

实际设计中,组合逻辑和时序逻辑往往是混在一起的。比如一个简单的计数器:

// 4位计数器(时序 + 组合)
module counter (
    input  wire        clk,
    input  wire        rst_n,
    input  wire        en,
    output reg  [3:0]  count
);
    // 时序部分:在每个时钟上升沿更新计数值
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 4'b0;
        else if (en)
            count <= count + 1'b1;  // 这里用了加法器(组合逻辑)
    end
endmodule

你看,count + 1'b1 这个加法操作,综合出来就是一个4位加法器(组合逻辑)。而 count <= ... 这个赋值,综合出来就是4个D触发器(时序逻辑)。两者配合,才构成了一个完整的计数器。

记住这句话:时序逻辑负责“记住”状态,组合逻辑负责“计算”下一个状态。两者缺一不可。

1.4 本章小结

好,第一课的内容就到这里。我们讲了三个核心概念:

  • 数字电路抽象:从系统级到物理级,我们工作在RTL级
  • 硬件描述语言:Verilog和VHDL,我推荐你先学Verilog
  • 组合逻辑 vs 时序逻辑:一个没记忆,一个有记忆;一个用 =,一个用 <=

这些东西看起来简单,但真的非常重要。我见过太多工程师,写了几年RTL代码,还在纠结“为什么我的寄存器没更新”、“为什么仿真和上板结果不一样”。说白了,就是基础没打牢。

嗯,今天就到这里。下一节课,我们会深入讲讲Verilog的语法细节,以及如何写出“可综合”的代码。

可可精品资料库