手把手教你用Verilog实现双控开关接入nvboard(附避坑指南)

从零实现Verilog双控开关与nvboard联调实战指南

开篇:为什么选择Verilog与nvboard组合?

第一次接触FPGA开发时,看到那些闪烁的LED和跳动的波形,总有种打开新世界大门的兴奋感。但随之而来的环境配置、语法错误和仿真问题,又常常让人望而却步。Verilog作为硬件描述语言的入门首选,配合南京大学开源的nvboard虚拟开发板,确实为初学者提供了极佳的学习路径。特别是在"一生一芯"这样的教学项目中,这种组合能快速验证数字电路设计,所见即所得。

本文将从一个真实的双控开关案例出发,不仅展示标准实现流程,更会重点剖析那些官方文档没写的细节问题。比如为什么引脚绑定脚本突然报错?Makefile变量究竟该怎么设置?仿真时界面显示正常但功能失效又是怎么回事?这些坑我都亲自踩过,现在把解决方案整理成可复用的经验。

1. 开发环境准备与项目初始化

1.1 工具链安装清单

开始前需要准备以下工具(以Ubuntu 20.04为例):

# 基础编译工具
sudo apt install build-essential git make

# Verilator仿真器(建议4.0以上版本)
sudo apt install verilator

# Python3及相关依赖
sudo apt install python3 python3-pip

注意:不同Linux发行版的包管理命令可能略有差异,遇到依赖问题时建议查阅对应发行版的文档。

1.2 nvboard环境配置

从GitHub克隆最新版nvboard仓库:

git clone https://github.com/NJU-ProjectN/nvboard.git

配置环境变量是第一个容易出错的地方。很多教程会建议在~/.bashrc中添加:

export NVBOARD_HOME=/path/to/nvboard

但实际使用时要注意两点:

  1. 路径必须使用绝对路径
  2. 在Makefile中引用时要用${NVBOARD_HOME}而非$(NVBOARD_HOME)

验证配置是否生效:

source ~/.bashrc
echo ${NVBOARD_HOME}

2. Verilog核心模块设计

2.1 双控开关的电路原理

双控开关的本质是一个异或逻辑:当两个开关状态相同时输出0,不同时输出1。用真值表表示如下:

开关A开关B输出
000
011
101
110

2.2 Verilog实现代码

创建vsrc/on_off_switch.v文件:

module on_off_switch(
    input wire a,
    input wire b,
    output wire f
);
    // 异或逻辑实现
    assign f = a ^ b;
endmodule

常见问题:

  • 端口信号未声明wire类型(虽然综合器能自动推断,但显式声明更规范)
  • 误用阻塞赋值=代替连续赋值assign
  • 忘记写结束的分号

2.3 顶层模块封装

创建vsrc/top.v作为顶层模块:

module top(
    input clk,
    input rst,
    input switch_a,
    input switch_b,
    output led_out
);
    on_off_switch u_switch(
        .a(switch_a),
        .b(switch_b),
        .f(led_out)
    );
endmodule

3. nvboard引脚绑定与约束文件

3.1 约束文件编写

constr/top.nxdc中定义引脚映射:

# 时钟信号
pin clk CLOCK 100000000

# 复位信号
pin rst BUTTON 1

# 两个物理开关
pin switch_a SWITCH 0
pin switch_b SWITCH 1

# LED输出
pin led_out LED 0

3.2 自动生成绑定代码

执行引脚绑定命令时,特别注意变量引用方式:

python3 ${NVBOARD_HOME}/scripts/auto_pin_bind.py \
    ${NVBOARD_HOME}/example/switch/constr/top.nxdc \
    ${NVBOARD_HOME}/example/switch/build/auto_bind.cpp

避坑指南:

  • 路径中的$NVBOARD_HOME要用花括号${}而非圆括号$()
  • 确保Python3在系统路径中
  • 如果报错"No such file",检查路径是否包含空格或特殊字符

4. Makefile配置详解

4.1 基础编译配置

创建项目Makefile,关键参数说明如下:

TOPNAME = top
NXDC_FILES = constr/top.nxdc
VERILATOR = verilator
BUILD_DIR = ./build
OBJ_DIR = $(BUILD_DIR)/obj_dir
BIN = $(BUILD_DIR)/$(TOPNAME)

default: $(BIN)

$(shell mkdir -p $(BUILD_DIR))

SRC_AUTO_BIND = $(abspath $(BUILD_DIR)/auto_bind.cpp)
$(SRC_AUTO_BIND): $(NXDC_FILES)
    python3 ${NVBOARD_HOME}/scripts/auto_pin_bind.py $^ $@

VSRCS = $(shell find $(abspath ./vsrc) -name "*.v")
CSRCS = $(shell find $(abspath ./csrc) -name "*.c" -or -name "*.cc" -or -name "*.cpp")
CSRCS += $(SRC_AUTO_BIND)

include ${NVBOARD_HOME}/scripts/nvboard.mk

INCFLAGS = $(addprefix -I, $(INC_PATH))
CXXFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""

$(BIN): $(VSRCS) $(CSRCS) $(NVBOARD_ARCHIVE)
    @rm -rf $(OBJ_DIR)
    $(VERILATOR) $(VERILATOR_CFLAGS) \
        --top-module $(TOPNAME) $^ \
        $(addprefix -CFLAGS , $(CXXFLAGS)) \
        --Mdir $(OBJ_DIR) --exe -o $(abspath $(BIN))

run: $(BIN)
    @$^

clean:
    rm -rf $(BUILD_DIR)

.PHONY: default run clean

4.2 常见编译错误处理

错误类型可能原因解决方案
NVBOARD_HOME未定义环境变量未正确设置检查~/.bashrc并source
verilator命令未找到未安装或不在PATHapt安装并验证版本
undefined reference链接库路径错误检查nvboard.mk包含路径
语法错误Verilog代码问题用iverilog先做语法检查

5. 仿真测试与调试技巧

5.1 主循环中的关键调用

创建csrc/sim.cpp测试文件:

#include <nvboard.h>
#include "Vtop.h"

static TOP_NAME dut;

void nvboard_bind_all_pins(TOP_NAME* top);

int main() {
    nvboard_bind_all_pins(&dut);
    nvboard_init();
    
    while(1) {
        nvboard_update();
        dut.eval();  // 这个调用绝对不能少!
    }
}

血泪教训: 曾经花了三小时排查为什么开关动作没有反应,最后发现是漏掉了dut.eval()。这个函数负责更新电路状态,没有它仿真就无法进行逻辑计算。

5.2 实时调试方法

  1. printf调试:在C++测试代码中添加打印语句
  2. 波形查看:通过Verilator生成vcd波形
  3. 信号探针:在Verilog中使用$display监控信号
always @(a or b) begin
    $display("Time=%t: a=%b, b=%b, f=%b", $time, a, b, f);
end

6. 进阶优化与扩展思路

6.1 添加去抖动逻辑

机械开关实际使用时需要防抖处理:

module debounce (
    input clk,
    input button_in,
    output reg button_out
);
    reg [19:0] count;
    reg button_sync;
    
    always @(posedge clk) begin
        button_sync <= button_in;
        if (button_sync ^ button_out) begin
            count <= count + 1;
            if (&count) button_out <= ~button_out;
        end else begin
            count <= 0;
        end
    end
endmodule

6.2 多开关级联控制

扩展为三控开关只需修改逻辑:

assign f = a ^ b ^ c;

6.3 性能优化技巧

  1. 为Verilator添加-O3优化选项
  2. 减少不必要的信号更新
  3. 使用always_comb替代连续的assign
always_comb begin
    f = a ^ b;
end

7. 项目组织与版本控制建议

推荐的项目目录结构:

project/
├── vsrc/        # Verilog源代码
│   ├── top.v
│   └── on_off_switch.v
├── csrc/        # C++测试代码
│   └── sim.cpp
├── constr/      # 约束文件
│   └── top.nxdc
├── build/       # 构建输出
├── Makefile
└── README.md

在Git版本控制中应该忽略的文件:

# .gitignore内容
build/
*.vcd
*.log

8. 真实项目中的经验分享

第一次成功点亮LED时的兴奋感至今难忘,但也遇到过几个印象深刻的问题:

  1. 环境变量失效:发现终端里能识别NVBOARD_HOME但Makefile读不到,最后发现是sudo执行时环境变量不同
  2. 路径包含空格:项目放在"My Project"目录下导致脚本解析失败
  3. 版本不兼容:使用较新的Verilator 5.0时某些参数语法有变化

建议在项目README中记录以下信息:

  • 使用的工具版本号
  • 特殊的环境配置要求
  • 已知问题的解决方法

调试时的一个小技巧:先单独验证Verilog代码功能(可以用iverilog+gtkwave),再集成到nvboard中,这样能快速定位问题是出在硬件逻辑还是接口部分。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值