本项目开发环境:
| 项目 | 说明 |
|---|---|
| 语言 | Verilog HDL |
| 仿真 | iverilog 12.0(make sim)/ ModelSim(可选,附 do 脚本) |
| 编辑 | VSCode + Digital-IDE 插件(内置 WaveTrace 波形查看) |
| 综合 | Quartus Prime 18.1 Lite,器件 EP4CE6F17C8 |
| 系统 | Debian13发行版(Makefile 流程) |
参数化异步 FIFO:数据位宽 / FIFO 深度可配置,默认 8bit × 256。
async_fifo/
├── src/
│ ├── sync_ff.v # N 级跨时钟域同步器
│ ├── async_fifo_mem.v # 双端口 RAM (wclk 写 / rclk 读)
│ ├── async_fifo_wr.v # 写侧: 格雷码 wptr / 满判断 / 标志
│ ├── async_fifo_rd.v # 读侧: 格雷码 rptr / 空判断 / 标志
│ ├── async_fifo.v # 参数化核心 (WIDTH=8, DEPTH=256 默认)
│ └── async_fifo_top.v # 顶层封装: 输入 wclk/rclk, 可直接例化到其它工程
├── sim/
│ ├── tb_async_fifo.v # 主验证平台 (8bit x 256)
│ ├── tb_async_fifo_config.v # 参数化验证平台 (4 组 WIDTH/DEPTH 配置)
│ ├── tb_async_fifo.do # ModelSim 一键脚本 (主验证)
│ └── tb_async_fifo_config.do # ModelSim 一键脚本 (参数化验证)
├── quartus/ # Quartus 工程 (EP4CE6F17C8)
├── scripts/ # 引脚约束脚本 (pins.csv → QSF)
├── pins.csv # 板级引脚
└── Makefile # 编译 / 仿真 / 语法检查
数据通路:
flowchart LR
subgraph W["写侧 (wclk 域)"]
WRQ["wrreq"] --> WR["async_fifo_wr<br/>写指针 + 满判断"]
WD["wdata"]
end
subgraph R["读侧 (rclk 域)"]
RDQ["rdreq"] --> RD["async_fifo_rd<br/>读指针 + 空判断"]
Q["q (读数据)"]
end
MEM["async_fifo_mem<br/>双端口 RAM"]
WR -- "waddr / wren" --> MEM
WD -- wdata --> MEM
RD -- raddr --> MEM
MEM -- q --> Q
指针通路:
flowchart LR
subgraph W["写侧 (wclk 域)"]
WPTR["格雷码 wptr (写指针)"]
WFULL["满判断 wrfull"]
end
subgraph R["读侧 (rclk 域)"]
RPTR["格雷码 rptr (读指针)"]
REMPTY["空判断 rdempty"]
end
WPTR -- "wptr_gray (2级同步)" --> REMPTY
RPTR -- "rptr_gray (2级同步)" --> WFULL
| 标志 | 公式(格雷码) | 含义 |
|---|---|---|
写满 wrfull |
wgray_next == {~rptr_sync[A:A-1], rptr_sync[A-2:0]} |
再写一次写指针将追上读指针 |
读空 rdempty |
rgray_next == wptr_sync |
再读一次读指针将追上写指针 |
async_fifo_top #(.WIDTH(8), .DEPTH(256)) u_fifo (
// 写侧 (wclk 域)
.wclk(wclk), .wrst_n(wrst_n),
.wrreq(wrreq), .wdata(wdata),
.wrfull(wrfull), .almost_full(af),
.wroverflow(wov), .wrusedw(wrusedw),
// 读侧 (rclk 域)
.rclk(rclk), .rrst_n(rrst_n),
.rdreq(rdreq), .q(q),
.rdempty(rdempty), .almost_empty(ae),
.rdunderflow(run), .rdusedw(rdusedw)
);顶层封装 async_fifo_top 与核心 async_fifo 接口一致;
wclk / rclk 为两个独立异步时钟,外部直接输入。
| 参数 | 默认 | 说明 |
|---|---|---|
WIDTH |
8 | 数据位宽 |
DEPTH |
256 | 深度,2 的幂且 >= 4 |
ALMOST_FULL_MARGIN |
2 | 剩余空间 <= 该值时 almost_full=1 |
ALMOST_EMPTY_MARGIN |
2 | 数据个数 <= 该值时 almost_empty=1 |
SYNC_STAGES |
2 | 指针同步级数 |
| 信号 | 行为 |
|---|---|
wrfull |
寄存输出。第 DEPTH 个写被接受的同一拍之后拉高;读腾出空间后约 2~3 拍(同步延迟)拉低 |
rdempty |
寄存输出。第 DEPTH 个读被接受的同一拍之后拉高;写新数据后约 2~3 拍拉低 |
almost_full |
组合输出。剩余空间 <= ALMOST_FULL_MARGIN 时为 1(含满) |
almost_empty |
组合输出。数据个数 <= ALMOST_EMPTY_MARGIN 时为 1(含空) |
wroverflow |
组合输出。满后每发一次写请求拉高一拍 |
rdunderflow |
组合输出。空后每发一次读请求拉高一拍 |
wrusedw |
写侧视角计数,同步延迟期可能偏大(保守值),静默后精确 |
rdusedw |
读侧视角计数,同步延迟期可能偏小(保守值),静默后精确 |
q |
读数据,读被接受的下一拍输出 |
满后写 / 空后读由标志门控拒绝,不会覆盖写或空读。
| 测试 | 内容 |
|---|---|
| Test1 复位初值 | rdempty=1 / wrfull=0 / usedw=0 / almost 正确 |
| Test2 写满 | wrfull 精确在第 256 个写后下一拍拉高;wrusedw=256;溢出标志 |
| Test3 读空 | 数据逐拍比对;rdempty 精确置位;下溢标志 |
| Test4 回绕 | 3 轮写满→读空,验证地址回绕 |
| Test5 随机并发 | wclk 100MHz / rclk 76.9MHz 非整数倍频+相位漂移,两轮 20000 拍随机读写;静默期标志与模型精确比对 |
| 参数化 | 8×256 / 16×64 / 32×8 / 4×16,各组不同时钟频率,完整回环验证 |
make sim TB=tb_async_fifo # 主验证 (8bit x 256)
make sim TB=tb_async_fifo_config # 参数化验证 (4 组配置)
make lint TB=tb_async_fifo # 仅语法检查, 不仿真
make clean # 清理 vcd/vvp 产物
make sim生成sim/<TB>.vcd并打印 PASS/FAIL(通过时输出>>> ALL TESTS PASSED <<<)- ModelSim 可选:
do sim/tb_async_fifo.do
- 运行
make sim TB=tb_async_fifo→ 生成sim/tb_async_fifo.vcd - 推荐:VSCode Digital-IDE(内置 WaveTrace) — 打开
.vcd即可查看,视图可存为.view - 备选:
gtkwave sim/tb_async_fifo.vcd(未安装时sudo apt install gtkwave)