跳到主要内容
SoC设计

实习生必练小模块

数字设计实习生必练的小模块汇总

SOC 小模块

实习生必练小模块推荐

为什么从小模块开始

原因说明
代码量可控100-500 行,不会被淹没
功能独立可以单独验证,看到完整结果
面试高频几乎必问的基础模块
项目必备实际项目中到处都在用
概念全覆盖状态机、时序逻辑、跨时钟域、协议

模块难度分级

入门级 (1-2天)
├── Counter          计数器
├── Edge Detector    边沿检测
├── Debouncer        按键消抖
└── Synchronizer     跨时钟域同步

进阶级 (3-5天)
├── FIFO             先进先出队列
├── Arbitrer         仲裁器
├── UART TX/RX       串口收发
└── Timer            定时器

挑战级 (1周)
├── SPI Master       SPI 主机
├── I2C Master       I2C 主机
└── AXI4-Lite Slave  AXI 从机

1. 同步 FIFO(⭐⭐⭐⭐⭐ 最重要)

为什么必练

  • 面试几乎必考
  • 涉及指针设计、空满判断、跨时钟域
  • 实际项目中大量使用(缓冲、速率匹配)

接口定义

module sync_fifo #(
    parameter DATA_WIDTH = 8,
    parameter DEPTH      = 16
)(
    input  logic                  clk,
    input  logic                  rst_n,
    
    // 写端口
    input  logic                  wr_en,
    input  logic [DATA_WIDTH-1:0] wr_data,
    output logic                  full,
    
    // 读端口
    input  logic                  rd_en,
    output logic [DATA_WIDTH-1:0] rd_data,
    output logic                  empty,
    
    // 可选:数据计数
    output logic [$clog2(DEPTH):0] data_count
);

关键设计点

核心思想:用二进制指针 + 格雷码判断空满

写指针 (wr_ptr): 0 → 1 → 2 → ... → DEPTH-1 → 0
读指针 (rd_ptr): 0 → 1 → 2 → ... → DEPTH-1 → 0

空判断: wr_ptr == rd_ptr
满判断: wr_ptr[MSB] != rd_ptr[MSB] && wr_ptr[LSB:0] == rd_ptr[LSB:0]
       (最高位不同,其余位相同)

代码框架

// 存储器
logic [DATA_WIDTH-1:0] mem [0:DEPTH-1];

// 写指针
logic [$clog2(DEPTH):0] wr_ptr, wr_ptr_next;
// 读指针
logic [$clog2(DEPTH):0] rd_ptr, rd_ptr_next;

// 指针更新
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr <= '0;
        rd_ptr <= '0;
    end else begin
        if (wr_en && !full)  wr_ptr <= wr_ptr_next;
        if (rd_en && !empty) rd_ptr <= rd_ptr_next;
    end
end

// 写操作
always_ff @(posedge clk) begin
    if (wr_en && !full)
        mem[wr_ptr[$clog2(DEPTH)-1:0]] <= wr_data;
end

// 读操作
assign rd_data = mem[rd_ptr[$clog2(DEPTH)-1:0]];

// 空满判断
assign empty = (wr_ptr == rd_ptr);
assign full  = (wr_ptr != rd_ptr) && 
               (wr_ptr[$clog2(DEPTH)-1:0] == rd_ptr[$clog2(DEPTH)-1:0]);

进阶:异步 FIFO

// 跨时钟域需要格雷码同步
function logic [$clog2(DEPTH):0] bin2gray(input logic [$clog2(DEPTH):0] bin);
    return bin ^ (bin >> 1);
endfunction

// 写指针格雷码同步到读时钟域
logic [$clog2(DEPTH):0] wr_ptr_gray_sync1, wr_ptr_gray_sync2;
always_ff @(posedge rd_clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr_gray_sync1 <= '0;
        wr_ptr_gray_sync2 <= '0;
    end else begin
        wr_ptr_gray_sync1 <= bin2gray(wr_ptr);
        wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
    end
end

2. UART 收发器(⭐⭐⭐⭐⭐ 最实用)

为什么必练

  • 调试必备,几乎所有项目都用
  • 涉及波特率生成、状态机、串并转换
  • 面试高频考点

接口定义

module uart_tx (
    input  logic       clk,        // 系统时钟
    input  logic       rst_n,
    input  logic [7:0] tx_data,    // 发送数据
    input  logic       tx_valid,   // 数据有效
    output logic       tx_ready,   // 发送器就绪
    output logic       tx_pin      // UART TX 引脚
);

module uart_rx (
    input  logic       clk,
    input  logic       rst_n,
    input  logic       rx_pin,     // UART RX 引脚
    output logic [7:0] rx_data,    // 接收数据
    output logic       rx_valid    // 数据有效
);

UART 帧格式

空闲态: ──────────────────────

起始位: ────────┐
               │  0
数据位:         └───D0─D1─D2─D3─D4─D5─D6─D7───
校验位:                          (可选) ──P──
停止位: ────────────────────────────────────┐
                                           │ 1
                                           └───

每帧: 1起始 + 8数据 + 0/1校验 + 1/2停止

波特率生成器

module baud_gen #(
    parameter CLK_FREQ  = 50_000_000,  // 50MHz
    parameter BAUD_RATE = 115200
)(
    input  logic clk,
    input  logic rst_n,
    output logic baud_tick  // 波特率采样脉冲
);
    localparam BAUD_DIV = CLK_FREQ / BAUD_RATE;
    
    logic [$clog2(BAUD_DIV)-1:0] cnt;
    
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= '0;
            baud_tick <= 1'b0;
        end else if (cnt == BAUD_DIV - 1) begin
            cnt <= '0;
            baud_tick <= 1'b1;
        end else begin
            cnt <= cnt + 1;
            baud_tick <= 1'b0;
        end
    end
endmodule

TX 状态机

typedef enum logic [2:0] {
    TX_IDLE,
    TX_START,
    TX_DATA,
    TX_PARITY,
    TX_STOP
} tx_state_t;

tx_state_t state, next_state;

// 状态转移
always_comb begin
    next_state = state;
    case (state)
        TX_IDLE:  if (tx_valid) next_state = TX_START;
        TX_START: if (baud_tick) next_state = TX_DATA;
        TX_DATA:  if (baud_tick && bit_cnt == 7) 
                      next_state = TX_STOP;
        TX_STOP:  if (baud_tick) next_state = TX_IDLE;
    endcase
end

3. 边沿检测器(⭐⭐⭐⭐ 基础必备)

为什么必练

  • 代码量小(20行),但概念重要
  • 消抖、按键检测、协议解析都用到
  • 理解寄存器延迟的核心概念

接口定义

module edge_detector (
    input  logic clk,
    input  logic rst_n,
    input  logic signal_in,    // 原始信号
    output logic pos_edge,     // 上升沿脉冲
    output logic neg_edge,     // 下降沿脉冲
    output logic any_edge      // 任意沿脉冲
);

代码实现

logic signal_d1, signal_d2;

// 两级寄存器(同步 + 边沿检测)
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        signal_d1 <= 1'b0;
        signal_d2 <= 1'b0;
    end else begin
        signal_d1 <= signal_in;
        signal_d2 <= signal_d1;
    end
end

// 边沿检测
assign pos_edge = signal_d1 & ~signal_d2;  // 0→1
assign neg_edge = ~signal_d1 & signal_d2;  // 1→0
assign any_edge = pos_edge | neg_edge;

时序图

clk         ──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
             └──┘  └──┘  └──┘  └──┘  └──┘

signal_in   ──────────┐              ┌───────
                      └──────────────┘

signal_d1   ────────────┐              ┌─────
                        └──────────────┘

signal_d2   ──────────────┐              ┌───
                          └──────────────┘

pos_edge    ────────┐  ┌────────────────────
                    └──┘

neg_edge    ──────────────────────┐  ┌──────
                                 └──┘

4. 按键消抖器(⭐⭐⭐⭐ 实用)

为什么必练

  • 实际工程必备
  • 涉及计数器、状态机、边沿检测
  • 理解机械抖动的物理现象

按键抖动原理

理想波形:
key_in    ────────┐              ┌────
                  └──────────────┘

实际波形(有抖动):
key_in    ────┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌──
              └┘└┘└┘└┘└┘└┘└┘└┘└┘└┘

消抖后:
key_debounced ────────┐              ┌────
                      └──────────────┘

代码实现

module debouncer #(
    parameter CLK_FREQ  = 50_000_000,
    parameter DEBOUNCE_MS = 20  // 20ms 消抖
)(
    input  logic clk,
    input  logic rst_n,
    input  logic key_in,        // 原始按键
    output logic key_debounced, // 消抖后
    output logic key_pos_edge   // 上升沿
);

    localparam CNT_MAX = CLK_FREQ / 1000 * DEBOUNCE_MS;
    
    logic [$clog2(CNT_MAX)-1:0] cnt;
    logic key_sync1, key_sync2;
    logic key_stable;
    
    // 同步器
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            key_sync1 <= 1'b1;  // 按键默认高
            key_sync2 <= 1'b1;
        end else begin
            key_sync1 <= key_in;
            key_sync2 <= key_sync1;
        end
    end
    
    // 计数器
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= '0;
            key_stable <= 1'b1;
        end else if (key_sync2 != key_stable) begin
            if (cnt == CNT_MAX - 1)
                key_stable <= key_sync2;
            else
                cnt <= cnt + 1;
        end else begin
            cnt <= '0;
        end
    end
    
    assign key_debounced = key_stable;
    
    // 边沿检测
    logic key_stable_d;
    always_ff @(posedge clk) key_stable_d <= key_stable;
    assign key_pos_edge = key_stable & ~key_stable_d;
    
endmodule

5. 跨时钟域同步器(⭐⭐⭐⭐⭐ 必须掌握)

为什么必练

  • 数字设计核心问题
  • 不同步会导致亚稳态
  • 面试必考知识点

亚稳态问题

跨时钟域传输:

CLK_A  ──┐  ┌──┐  ┌──┐  ┌──
         └──┘  └──┘  └──┘

DATA_A  ──────X─────────────  ← 在 CLK_B 上升沿变化

CLK_B  ──┐  ┌──┐  ┌──┐  ┌──
         └──┘  └──┘  └──┘

              │  采样到不稳定值 → 亚稳态!

DATA_B  ────?-──────────────

2 级同步器

module sync_2ff #(
    parameter WIDTH = 1
)(
    input  logic             clk_dst,    // 目标时钟
    input  logic             rst_n,
    input  logic [WIDTH-1:0] data_src,   // 源数据
    output logic [WIDTH-1:0] data_dst    // 同步后数据
);

    logic [WIDTH-1:0] sync_reg1;
    
    always_ff @(posedge clk_dst or negedge rst_n) begin
        if (!rst_n) begin
            sync_reg1 <= '0;
            data_dst  <= '0;
        end else begin
            sync_reg1 <= data_src;  // 第一级(可能亚稳态)
            data_dst  <= sync_reg1; // 第二级(稳定)
        end
    end
    
endmodule

握手同步

// 源端
logic req_src, ack_sync;
logic req_toggle;

always_ff @(posedge clk_src or negedge rst_n) begin
    if (!rst_n) req_toggle <= 1'b0;
    else if (req_src) req_toggle <= ~req_toggle;
end

// 目标端同步
logic req_toggle_sync1, req_toggle_sync2;
always_ff @(posedge clk_dst or negedge rst_n) begin
    if (!rst_n) begin
        req_toggle_sync1 <= 1'b0;
        req_toggle_sync2 <= 1'b0;
    end else begin
        req_toggle_sync1 <= req_toggle;
        req_toggle_sync2 <= req_toggle_sync1;
    end
end

6. 仲裁器(⭐⭐⭐⭐ 总线必备)

为什么必练

  • 总线、DMA、多端口内存都需要
  • 理解优先级、公平性
  • 状态机练习

接口定义

module arbiter #(
    parameter NUM_MASTER = 4
)(
    input  logic clk,
    input  logic rst_n,
    
    // 请求
    input  logic [NUM_MASTER-1:0] req,      // 请求信号
    output logic [NUM_MASTER-1:0] grant,    // 授权信号
    
    // 输出
    output logic [$clog2(NUM_MASTER)-1:0] sel  // 选中的主设备
);

仲裁算法

// 1. 固定优先级仲裁
always_comb begin
    grant = '0;
    sel   = '0;
    for (int i = NUM_MASTER-1; i >= 0; i--) begin
        if (req[i]) begin
            grant[i] = 1'b1;
            sel      = i[$clog2(NUM_MASTER)-1:0];
        end
    end
end

// 2. 轮询仲裁 (Round Robin)
logic [$clog2(NUM_MASTER)-1:0] last_grant;

always_comb begin
    grant = '0;
    sel   = '0;
    for (int i = 0; i < NUM_MASTER; i++) begin
        automatic int idx = (last_grant + 1 + i) % NUM_MASTER;
        if (req[idx]) begin
            grant[idx] = 1'b1;
            sel        = idx[$clog2(NUM_MASTER)-1:0];
        end
    end
end

仲裁时序

固定优先级仲裁:

req[0]   ────┐     ┌───────────────
             └─────┘

req[1]   ──────────┐     ┌─────────
                   └─────┘

req[2]   ──────────────────────────

grant[0] ────┐     ┌───┐
             └─────┘   └────────────

grant[1] ──────────────┐     ┌─────
                       └─────┘

sel      ────0─────0───1─────1─────

7. Timer 定时器(⭐⭐⭐ 基础外设)

为什么必练

  • 嵌入式系统基础
  • PWM、看门狗、实时时钟的基础
  • 寄存器配置练习

接口定义

module timer #(
    parameter CLK_FREQ = 50_000_000
)(
    input  logic        clk,
    input  logic        rst_n,
    
    // APB 配置接口
    input  logic [3:0]  addr,
    input  logic        wr_en,
    input  logic [31:0] wr_data,
    output logic [31:0] rd_data,
    
    // 中断输出
    output logic        irq
);

寄存器映射

偏移名称读写说明
0x00CTRLR/W控制寄存器
0x04STATUSR/W状态寄存器
0x08CNTR计数器当前值
0x0CTHRESHOLDR/W阈值
0x10PRESCALER/W分频器

代码实现

// 寄存器定义
logic [31:0] ctrl, threshold, prescale;
logic [31:0] cnt;
logic        irq_pending;

// 控制寄存器位定义
localparam CTRL_ENABLE  = 0;
localparam CTRL_IRQ_EN  = 1;
localparam CTRL_AUTO_RELOAD = 2;

// 计数逻辑
logic [31:0] prescale_cnt;
logic        prescale_tick;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        prescale_cnt <= '0;
        prescale_tick <= 1'b0;
    end else if (ctrl[CTRL_ENABLE]) begin
        if (prescale_cnt == prescale) begin
            prescale_cnt <= '0;
            prescale_tick <= 1'b1;
        end else begin
            prescale_cnt <= prescale_cnt + 1;
            prescale_tick <= 1'b0;
        end
    end
end

// 主计数器
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= '0;
        irq_pending <= 1'b0;
    end else if (ctrl[CTRL_ENABLE] && prescale_tick) begin
        if (cnt >= threshold) begin
            cnt <= '0;
            irq_pending <= 1'b1;
            if (!ctrl[CTRL_AUTO_RELOAD])
                ctrl[CTRL_ENABLE] <= 1'b0;  // 停止
        end else begin
            cnt <= cnt + 1;
        end
    end
end

assign irq = irq_pending & ctrl[CTRL_IRQ_EN];

8. SPI Master(⭐⭐⭐ 常用接口)

为什么必练

  • Flash、传感器、屏幕通信都用
  • 时钟极性/相位(CPOL/CPHA)
  • 移位寄存器核心

接口定义

module spi_master (
    input  logic        clk,
    input  logic        rst_n,
    
    // 控制接口
    input  logic [7:0]  tx_data,
    input  logic        tx_valid,
    output logic        tx_ready,
    output logic [7:0]  rx_data,
    output logic        rx_valid,
    
    // SPI 接口
    output logic        sclk,       // 时钟
    output logic        mosi,       // 主出从入
    input  logic        miso,       // 主入从出
    output logic        cs_n        // 片选(低有效)
);

SPI 模式

CPOL=0, CPHA=0 (Mode 0):
SCLK  ──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
        └──┘  └──┘  └──┘  └──┘
         ↑ 采样  ↑ 变化  ↑ 采样
MOSI  ──D7─────D6─────D5─────D4───
MISO  ──Q7─────Q6─────Q5─────Q4───

CPOL=1, CPHA=1 (Mode 3):
SCLK  ────┐  ┌──┐  ┌──┐  ┌──┐  ┌─
          └──┘  └──┘  └──┘  └──┘
           ↑ 变化  ↑ 采样  ↑ 变化

代码框架

typedef enum logic [1:0] {
    SPI_IDLE,
    SPI_TRANSFER,
    SPI_DONE
} spi_state_t;

spi_state_t state;
logic [2:0] bit_cnt;
logic [7:0] shift_reg;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= SPI_IDLE;
        sclk <= 1'b0;
        cs_n <= 1'b1;
    end else begin
        case (state)
            SPI_IDLE: begin
                cs_n <= 1'b0;
                if (tx_valid) begin
                    state <= SPI_TRANSFER;
                    shift_reg <= tx_data;
                    bit_cnt <= '0;
                end
            end
            SPI_TRANSFER: begin
                if (sclk_tick) begin
                    sclk <= ~sclk;
                    if (sclk == 1'b0) begin  // 上升沿采样
                        shift_reg <= {shift_reg[6:0], miso};
                    end else begin           // 下降沿移出
                        mosi <= shift_reg[7];
                        bit_cnt <= bit_cnt + 1;
                        if (bit_cnt == 7)
                            state <= SPI_DONE;
                    end
                end
            end
            SPI_DONE: begin
                cs_n <= 1'b1;
                state <= SPI_IDLE;
            end
        endcase
    end
end

9. I2C Master(⭐⭐⭐ 常用接口)

为什么必练

  • EEPROM、传感器、实时时钟通信
  • 开漏输出、上拉电阻
  • 起始/停止条件、ACK/NACK

I2C 时序

起始条件: SDA 在 SCL 高时下降
                ┌───┐   ┌───┐   ┌───┐
SCL        ─────┘   └───┘   └───┘   └────
               ┌───────┐
SDA        ────┘       └──────────────
                   ↑ START

数据传输: SDA 在 SCL 低时变化
                ┌───┐   ┌───┐   ┌───┐
SCL        ─────┘   └───┘   └───┘   └────
            ┌───┐   ┌───┐   ┌───┐
SDA        ─┘   └───┘   └───┘   └────────
               D7       D6       D5

停止条件: SDA 在 SCL 高时上升
                ┌───┐   ┌───┐
SCL        ─────┘   └───┘   └────────────
                        ┌───────────────
SDA        ─────────────┘
                       ↑ STOP

10. AXI4-Lite Slave(⭐⭐⭐⭐⭐ 总线基础)

为什么必练

  • 理解总线协议核心
  • 寄存器映射、地址解码
  • 实际 IP 开发必备

接口定义

module axi4_lite_slave #(
    parameter ADDR_WIDTH = 8,
    parameter DATA_WIDTH = 32
)(
    input  logic aclk,
    input  logic aresetn,
    
    // AXI4-Lite 接口
    input  logic [ADDR_WIDTH-1:0]  awaddr,
    input  logic                   awvalid,
    output logic                   awready,
    
    input  logic [DATA_WIDTH-1:0]  wdata,
    input  logic [DATA_WIDTH/8-1:0] wstrb,
    input  logic                   wvalid,
    output logic                   wready,
    
    output logic [1:0]             bresp,
    output logic                   bvalid,
    input  logic                   bready,
    
    input  logic [ADDR_WIDTH-1:0]  araddr,
    input  logic                   arvalid,
    output logic                   arready,
    
    output logic [DATA_WIDTH-1:0]  rdata,
    output logic [1:0]             rresp,
    output logic                   rvalid,
    input  logic                   rready
);

写通道状态机

typedef enum logic [1:0] {
    WR_IDLE,
    WR_ADDR,
    WR_DATA,
    WR_RESP
} wr_state_t;

wr_state_t wr_state;

always_ff @(posedge aclk or negedge aresetn) begin
    if (!aresetn) begin
        wr_state <= WR_IDLE;
        awready <= 1'b0;
        wready <= 1'b0;
        bvalid <= 1'b0;
    end else begin
        case (wr_state)
            WR_IDLE: begin
                awready <= 1'b1;
                if (awvalid && awready) begin
                    wr_state <= WR_ADDR;
                    awready <= 1'b0;
                end
            end
            WR_ADDR: begin
                wready <= 1'b1;
                if (wvalid && wready) begin
                    wr_state <= WR_DATA;
                    wready <= 1'b0;
                    // 写寄存器
                    if (wstrb[0]) reg_file[awaddr][7:0]   <= wdata[7:0];
                    if (wstrb[1]) reg_file[awaddr][15:8]  <= wdata[15:8];
                    if (wstrb[2]) reg_file[awaddr][23:16] <= wdata[23:16];
                    if (wstrb[3]) reg_file[awaddr][31:24] <= wdata[31:24];
                end
            end
            WR_DATA: begin
                bvalid <= 1'b1;
                bresp <= 2'b00;  // OKAY
                if (bready && bvalid) begin
                    bvalid <= 1'b0;
                    wr_state <= WR_IDLE;
                end
            end
        endcase
    end
end

Testbench 编写模板

基本 TB 结构

module tb_fifo;

    // 参数
    parameter DATA_WIDTH = 8;
    parameter DEPTH = 16;
    parameter CLK_PERIOD = 10;  // 10ns = 100MHz

    // 信号
    logic clk;
    logic rst_n;
    logic wr_en, rd_en;
    logic [DATA_WIDTH-1:0] wr_data, rd_data;
    logic full, empty;

    // 时钟生成
    initial clk = 0;
    always #(CLK_PERIOD/2) clk = ~clk;

    // 实例化
    sync_fifo #(
        .DATA_WIDTH(DATA_WIDTH),
        .DEPTH(DEPTH)
    ) uut (
        .clk(clk),
        .rst_n(rst_n),
        .wr_en(wr_en),
        .wr_data(wr_data),
        .full(full),
        .rd_en(rd_en),
        .rd_data(rd_data),
        .empty(empty)
    );

    // 测试序列
    initial begin
        // 初始化
        rst_n = 0;
        wr_en = 0;
        rd_en = 0;
        wr_data = 0;
        #100;
        rst_n = 1;
        #20;

        // 写入 5 个数据
        repeat(5) begin
            @(posedge clk);
            wr_en = 1;
            wr_data = $random;
            @(posedge clk);
            wr_en = 0;
        end

        // 读出 5 个数据
        repeat(5) begin
            @(posedge clk);
            rd_en = 1;
            @(posedge clk);
            rd_en = 0;
        end

        #100;
        $finish;
    end

    // 波形输出
    initial begin
        $dumpfile("fifo.vcd");
        $dumpvars(0, tb_fifo);
    end

    // 监控
    always @(posedge clk) begin
        if (wr_en && !full)
            $display("WR: %0h at time %0t", wr_data, $time);
        if (rd_en && !empty)
            $display("RD: %0h at time %0t", rd_data, $time);
    end

endmodule

学习路线建议

第 1 周: 基础模块
├── Day 1-2: 边沿检测器 + 消抖器
├── Day 3-4: 2级同步器 + 握手同步
└── Day 5:   复习 + 写 Testbench

第 2 周: 核心模块
├── Day 1-3: 同步 FIFO(重点!)
├── Day 4-5: 仲裁器
└── Day 6-7: 复习 + 对比异步 FIFO

第 3 周: 接口模块
├── Day 1-3: UART TX/RX
├── Day 4-5: Timer
└── Day 6-7: 复习 + 集成测试

第 4 周: 总线接口
├── Day 1-3: AXI4-Lite Slave
├── Day 4-5: SPI Master
└── Day 6-7: 项目实战

面试高频问题

模块常见问题
FIFO空满判断原理?异步 FIFO 如何跨时钟域?
UART波特率如何生成?帧格式是什么?
同步器为什么需要两级?亚稳态是什么?
边沿检测为什么需要两级寄存器?
仲裁器固定优先级 vs 轮询的优缺点?
状态机三段式 vs 两段式?Moore vs Mealy?

详细练习文档

进阶级模块的完整练习文档(含代码、Testbench、练习任务):

模块文档链接内容概要
同步FIFO同步FIFO.md空满判断、指针设计、格雷码同步
仲裁器仲裁器.md固定优先级、轮询仲裁、状态机
UART收发器UART收发器.md帧格式、波特率生成、16x过采样
定时器定时器.md寄存器映射、分频器、PWM输出

最后更新: 2026-07-14