VS Code下开发FPGA——FPGA开发体验提升__下

上一篇:IntelliJ IDEA下开发FPGA-CSDN博客

Type:Quartus

一、安装插件

在应用商店先安装Digtal IDE插件

安装后,把其他相关的Verilog插件禁用,避免可能的冲突。重启后,可能会弹出下面提示

这是插件默认要求的工具链,在扩展设置中可以选择其他几个。这里遵循默认,进入Vivado网址,下载

安装教程可参考Vivado 安装教程 - Digital Lab 2024

安装完成后,可以在VS Code的设置里,找到扩展选项,再找到安装路径设置,注意斜杠的方向

不过在使用时,经常会报下面错误,应该是VS Code的日常bug吧

二、基本使用

1,网表

在编写的模块中,点击Netlist就可以生成网表

2,文档

点击右上角,可以打开文档,里面有该模块的所有总结信息

生成的代码文档足够详细,甚至包含注释的信息

3、代码检查

在语法解析完成的情况下,对代码的检查可谓是相当给力,点击下方的提示可自动转到

而且对System Verilog文件也能进行正常检查,不必担忧中文注释

基于这个代码检查,编写模块文件和测试文件都可以使用表达能力更好的System Verilog

4,git插件

至于前篇提到的内置git不是很好用,在一些插件的帮助下,有了质的提升

5,文件纲要

6,代码格式化

右键屏幕,点击格式化文档,即可自动对齐代码

三、自动流程

1,创建任务

由于FPGA芯片为Intel类型,因此综合(或仿真)需要用到Quartus(或ModelSim)。如想达到如IntelliJ IDEA中非常方便的运行目标,需要配置任务

①创建模板

选择模板创建

选择Others

然后会自动生成配置文件

语法很简单,label是该任务的名称,type是任务的类型,command就是该任务的执行命令,也就是名为label的任务使用shell执行command。这些内容在上篇IntelliJ IDEA的配置运行目标中可以见到,只不过这里更为自由

②运行任务

此时执行任务试试

可以看到输出台上

③配置为生成任务(构建)

点击配置默认生成任务,在点击之前创建的任务即可(这里已经选择过了)

在模板里可以看到,json里添加了新的两个选项(标签)

④使用快捷键

由于VS Code的运行任务不像IntelliJ IDEA之间在上方显示,每次运行时都需要点击【运行】→【运行任务】→【xxx任务】。因此可以把需要执行的任务配置为默认生成任务,然后通过Ctrl + Shift + B快速执行

⑤任务启动插件

当然,这样依旧并不是很方便,比如现在有综合、仿真等任务,来回切换就有些不够清晰直观。为解决这个问题,首先要想的便是插件,可以看到丰富的插件

这里就随便选择一个,比如Task Manager,安装之后左边会出现一个小图标,点击之后就会显示所有任务

光标悬停在任务上面,就会出现绿色的执行键,点击执行就会出现下面图标,简单好用

2,综合任务

①编写脚本

基于上面内容,现在我们可以轻松仿照上篇中关于综合任务的配置。其基本思路是,编写一个ps1脚本,让任务目标使用shell终端来执行ps1脚本,ps1脚本里则是各种终端命令。

任务shell脚本工具命令

现在先写一个ps1脚本,与前篇的一样(前篇有详细讲解和代码)

为了让脚本更加通用,工作目录可以通过参数的方式传入,项目名从工作目录里提取

bash 复制代码
param(
    [Parameter(Mandatory=$true)] # 强制要求参数
    [string]$WORK_DIR        # 声明参数变量
)

# 设置程序路径
$QUARTUS_BIN = "E:\Tools\Develop\Embedded\intelFPGA\quartus\bin64"

# 从路径提取目录名
$PROJECT_NAME = (Get-Item $WORK_DIR).Name  

# 初始化环境
$env:PATH = "$QUARTUS_BIN;$env:PATH"
Set-Location $WORK_DIR

# 执行流程
$commands = @(
    "quartus_map --read_settings_files=on --write_settings_files=off $PROJECT_NAME -c $PROJECT_NAME",
    "quartus_fit --read_settings_files=off --write_settings_files=off $PROJECT_NAME -c $PROJECT_NAME",
    "quartus_asm --read_settings_files=off --write_settings_files=off $PROJECT_NAME -c $PROJECT_NAME",
    "quartus_sta $PROJECT_NAME -c $PROJECT_NAME",
    "quartus_eda --read_settings_files=off --write_settings_files=off $PROJECT_NAME -c $PROJECT_NAME"
)

foreach ($cmd in $commands) {
    Write-Host "Run: $cmd" -ForegroundColor Cyan
    Invoke-Expression $cmd
    if ($LASTEXITCODE -ne 0) {
        Write-Host "[Error] $LASTEXITCODE" -ForegroundColor Red
        exit $LASTEXITCODE
    }
}

任务脚本需要改一下,名称为sythesis,命令为脚本名称。args里是存放各种参数,逗号相当于空格,起分隔作用

javascript 复制代码
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "synthesis",
            "type": "shell",
            "command": "powershell.exe",  // 显式调用 PowerShell
            "args": [
                "-ExecutionPolicy", "Bypass", // 绕过权限限制
                "-File", 
                "${workspaceFolder}/usr/scripts/powershell/synthesis.ps1", // 脚本路径
                "${workspaceFolder}"// 传入工作目录
            ],
            "options": {
                "cwd": "${workspaceFolder}" // 设置工作目录为项目根目录
            },
            // 配置为生成任务
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            },
        }
    ]
}

执行效果如下

②查看报告

生成的报告都在output_files目录,其中fit.map和map.rpt是我们需要关注的,在fit.map中,大概两百多行处就是资源消耗的总结报告

由于没有什么rpt文件相关的插件,报告方面还是到Quartus里查看比较好

3,仿真任务

与前篇一致,插件仿真默认使用的是iverilog,那么对sv文件的支持就相当差了,点击爬虫没有反应,但对v文件有反应。

①ModelSim_GUI

那么也如前面,创建一个仿真任务,在原任务下面即可,逗号不要忘记添加

javascript 复制代码
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "synthesis",
            "type": "shell",
            "command": "powershell.exe",  // 显式调用 PowerShell
            "args": [
                "-ExecutionPolicy", "Bypass", // 绕过权限限制
                "-File", 
                "${workspaceFolder}/usr/scripts/powershell/synthesis.ps1", // 脚本路径
                "${workspaceFolder}"// 传入工作目录
            ],
            "options": {
                "cwd": "${workspaceFolder}" // 设置工作目录为项目根目录
            },
            // 配置为生成任务
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            },
        },
        {
            "label": "modelsim_gui", 
            "type": "shell",
            "command": "quartus_sh",
            "args": [
                "-t",
                "E:/tools/develop/embedded/intelfpga/quartus/common/tcl/internal/nativelink/qnativesim.tcl", // TCL 脚本路径
                "--rtl_sim",
                "${workspaceFolderBasename}", 
                "${workspaceFolderBasename}"
            ],
            "options": {
                "cwd": "${workspaceFolder}", // 设置工作目录
                // 添加环境变量
                "env": {
                    "PATH": "E:/Tools/Develop/Embedded/intelFPGA/quartus/bin64;${env:PATH}"
                }
            },
            "problemMatcher": []    // 无错误匹配器
        }
    ]
}

执行效果如下

②ModelSim_CMD

此时是让ModelSim以命令行的形式运行,原流程是quartus_sh自动读取tcl脚本,然后生成对应的do脚本,再让vsim以命令行的形式执行这个do脚本。如果改写tcl脚本的话,有些麻烦,于是准备使用ps1脚本,让其直接读取qsf文件中仿真的配置,然后生成do脚本,再让vsim执行do脚本。

那么这个ps1脚本可以先使用正则表达式匹配到关键信息,再利用模板生成特定的do脚本

bash 复制代码
param(
    [string]$ProjectFloder,
    [string]$QsfPath,
    [string]$DoScript,
    [string]$VsimFloderPath,
    [string]$SimMode = "RTL"
)

# 设置环境变量
$env:PATH = "$VsimFloderPath;$env:PATH"

# 强制覆写设置(移除了备份逻辑)
if (Test-Path $DoScript) {
    Write-Host "Force overwriting existing DO script [$DoScript]"
    Remove-Item $DoScript -Force
}

# 2. 解析QSF文件
$Config = @{
    SimTool = ""    # ModelSim-Altera (SystemVerilog)
    TopEntity = "" # 顶层模块名
    TopEntityFile = ""
    ActiveTestbench = ""
    TestbenchFile = ""
}

# 解析状态跟踪
$currentSection = $null

Get-Content $QsfPath | ForEach-Object {
    # 捕获section声明
    if ($_ -match '-section_id\s+([^\s]+)') {
        $currentSection = $matches[1]
    }

    switch -regex ($_) {
        # 关键参数解析
        'set_global_assignment\s+-name\s+EDA_SIMULATION_TOOL\s+"(.+)"' {
            $Config.SimTool = $matches[1]
            Write-Host "[SimTool]: $($matches[1])" -ForegroundColor Green
        }
        # 捕获顶层模块名
        'set_global_assignment\s+-name\s+TOP_LEVEL_ENTITY\s+(.+)' {
            $Config.TopEntity = $matches[1]
            Write-Host "[TopEntity]: $($matches[1])" -ForegroundColor Green
        }
        # 捕获顶层模块文件名
        'set_global_assignment\s+-name\s+(VERILOG_FILE|SYSTEMVERILOG_FILE)\s+(.+)' {
            if($($Config.TopEntityFile) -eq "")
            {
                $filePath = $matches[2]
                $fileName = [IO.Path]::GetFileNameWithoutExtension($filePath)
                
                if ($fileName -eq $Config.TopEntity) {
                    $Config.TopEntityFile = $filePath
                    Write-Host "[TopEntityFile]: $filePath" -ForegroundColor Green
                }
            }
        }
        # 捕获激活的测试平台
        'set_global_assignment\s+-name\s+EDA_NATIVELINK_SIMULATION_TEST_BENCH\s+"?(.+?)"?\s' {
            if ($currentSection -eq 'eda_simulation') {
                $Config.ActiveTestbench = $matches[1]
                Write-Host "[ActiveTestbench]: $($matches[1])" -ForegroundColor Green
            }
            else {
                Write-Host "[Warning] Ignoring non-testbench section: $currentSection -> $($matches[1])"  -ForegroundColor Red
            }
        }
        # 捕获测试平台文件名
        'set_global_assignment\s+-name\s+EDA_TEST_BENCH_FILE\s+(.+)\s+-section_id\s+(.+)' {
            $filePath = $matches[1]
            $fileName = [IO.Path]::GetFileNameWithoutExtension($filePath)
            $testbenchName = $matches[2]

            # 测试激励文件名与测试激励名称应匹配
            if(-not $fileName -eq $testbenchName){
                throw "[Error]: Testbench file name mismatch: $fileName != $testbenchName"
            }

            # 匹配测试激励文件
            if($testbenchName -eq $($Config.ActiveTestbench))
            {
                $Config.TestbenchFile = $matches[1]
                Write-Host "[TestbenchFile]: $($matches[1])" -ForegroundColor Green
            }
        }
    }
}


# 对Config里面的内容做一次检查
if($($Config.TopEntityFile) -eq ""){
    throw "[Error]: No top entity file found in QSF file"
}

Write-Host ""

# 3. 确定测试平台文件
if (-not [string]::IsNullOrEmpty($Config.ActiveTestbench)) {
}
else {
    throw "No active testbench found in QSF file"
}

# 4. 生成DO脚本
$DoContent = @(
    "transcript on",
    "if {[file exists rtl_work]} {",
    "    vdel -lib rtl_work -all",
    "}",
    "vlib rtl_work",
    "vmap work rtl_work",
    ""
)


# 生成仿真命令
$fileDirectory = [IO.Path]::GetDirectoryName($($Config.TopEntityFile))
$logCmd1 = "vlog -vlog01compat -work work +incdir+$ProjectFloder/$fileDirectory {$ProjectFloder/$($Config.TopEntityFile)}"

$fileDirectory = [IO.Path]::GetDirectoryName($($Config.TestbenchFile))
$logCmd2 = "vlog -sv -work work +incdir+$ProjectFloder/$fileDirectory {$ProjectFloder/$($Config.TestbenchFile)}"

$simCmd ="vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -voptargs=`"+acc`" $($Config.ActiveTestbench)"


$DoContent += @(
    "",
    $logCmd1,
    $logCmd2,
    $simCmd,
    "add wave *",
    "view structure",
    "view signals",
    "run -all"
)

# 5. 安全写入文件
try {
    $DoContent = $DoContent -join "`r`n"
    $DoContent | Out-File $DoScript -Encoding ASCII -Force
    Write-Host "DO script generated: $DoScript"  -ForegroundColor Blue

    # 执行仿真
    if ($Config.SimTool -match "ModelSim") {
        Write-Host "Launching ModelSim..."  -ForegroundColor Blue
        Start-Process vsim.exe -ArgumentList "-c -do `"$DoScript`"" -Wait -NoNewWindow
    }
}
catch {
    if (Test-Path $DoBackupPath) {
        Move-Item $DoBackupPath $DoScript -Force
        Write-Host "Restored original DO script"
    }
    throw $_
}

同前面一样,再创建一个仿真任务

javascript 复制代码
        {
            "label": "modelsim_cmd", 
            "type": "shell",
            "command": "powershell.exe",  // 显式调用 PowerShell
            "args": [
                "-ExecutionPolicy", "Bypass", // 绕过权限限制
                "-File", 
                "${workspaceFolder}/usr/scripts/powershell/modelsim_cmd.ps1", // 脚本路径
                "${workspaceFolder}",// 传入工作目录
                "${workspaceFolder}/${workspaceFolderBasename}.qsf",// 传入qsf文件
                "${workspaceFolder}/simulation/modelsim/modelsim.do",// 设置do脚本的路径(自己随便设,不一定要在simulation路径)
                "E:/Tools/Develop/Embedded/intelFPGA/ModelSim/modelsim_ase/win32aloem"// 传入vsim路径
            ],
            "options": {
                "cwd": "${workspaceFolder}/simulation/modelsim", // 设置工作目录
            },
        }

启动任务后,ModelSim就以命令行的形式调用,正常进行仿真

需要说明的是,这种方式只生成了do脚本,与之配套的库之类的还是依赖Quartus的tcl脚本生成,也就意味着运行do脚本的目录需要放到simulation目录里,而且前面必须至少执行过一次modelsim_gui任务(确保运行过tcl脚本在simulation目录里生成相应的库)

③查看波形

查看波形已经没必要再Surfer里去查看,因为插件自带一个查看vcd文件的功能。想要生成波形,测试激励文件里必须加上下面这句

bash 复制代码
initial begin
  $dumpfile("xxx.vcd");// 填写对应的名称
  $dumpvars;
end

点击生成的vcd文件后,会出现这样的一个波形图,此时空空如也。点击右上角

选择需要的信号

左边就会出现你需要的信号,右键信号会有一些配置选项

此时,需要点击信号(变亮就行,点亮后波形也更亮),再点击红色箭头指向的位置,移动到最左边,不然波形不一定能看得到(如果太短的话)

调整到合适的位置之后,箭头所指方向,有三种不同的显示方式,旁边还有数值的显示方式。想要调节,那么左边的信号必须被点亮

第一种是数字型,第二种是离散化,第三种是模拟

相关推荐
北城笑笑4 分钟前
FPGA 37 ,FPGA千兆以太网设计实战:RGMII接口时序实现全解析( RGMII接口时序设计,RGMII~GMII,GMII~RGMII 接口转换 )
fpga开发·fpga
爱上大米1 小时前
关闭VSCode 自动更新
ide·vscode
Lonely丶墨轩2 小时前
IDE中使用Spring Data Redis
ide·redis·spring
hweiyu002 小时前
idea在线离线安装插件教程
java·ide·intellij-idea·intellij idea
soulermax8 小时前
华为数字芯片机考2025合集2已校正
嵌入式硬件·华为·fpga开发·系统架构·硬件架构
156082072199 小时前
全国产V7-690T核心板/算法验证板/FPGA开发板
fpga开发·信号处理·v7-690t·pcie信号处理模块·jfm7vx690t
做一个优雅的美男子9 小时前
【特权FPGA】之SRAM读写
fpga开发
&Cheems11 小时前
Verilog:LED呼吸灯
fpga开发
Jennifer33K14 小时前
IDEA 调用 Generate 生成 Getter/Setter 快捷键
java·ide·intellij-idea
soulermax15 小时前
华为数字芯片机考2025合集5已校正
华为·fpga开发