上一篇: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腳本,與前篇的一樣(前篇有詳細講解和代碼)
為了讓腳本更加通用,工作目錄可以通過參數的方式傳入,項目名從工作目錄里提取
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 CyanInvoke-Expression $cmdif ($LASTEXITCODE -ne 0) {Write-Host "[Error] $LASTEXITCODE" -ForegroundColor Redexit $LASTEXITCODE} }
????????任務腳本需要改一下,名稱為sythesis,命令為腳本名稱。args里是存放各種參數,逗號相當于空格,起分隔作用
{// 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},}] }
執行效果如下
添加報告
? ? ? ? 為了綜合后能顯示一些重要信息,可以在上面的ps1腳本末尾添加一些提取信息的命令,通過正則表達式匹配信息。比如可以從output_files目錄下的xxx.sta.rpt文件里提取Fmax
# 提取 Fmax 值 $reportPath = Join-Path $WORK_DIR "output_files\$PROJECT_NAME.sta.rpt" if (Test-Path $reportPath) {$content = Get-Content $reportPath -Raw$pattern = '(?s); \w+\s+\d+mV\s+(?<temp>[0-9-]+C)\s+Model Fmax Summary.*?; (?<fmax>\d+\.\d+) MHz'$matches = [regex]::Matches($content, $pattern)if ($matches.Count -gt 0) {$data = @()foreach ($match in $matches) {$temp = $match.Groups["temp"].Value -replace "C", ""$fmax = $match.Groups["fmax"].Value$data += [PSCustomObject]@{temp = $tempFmax = "$fmax MHz"}}# 修正列寬計算方式$tempWidth = [Math]::Max(4, ($data.temp | ForEach-Object { $_.ToString().Length } | Measure-Object -Maximum).Maximum)$fmaxWidth = [Math]::Max(5, ($data.Fmax | ForEach-Object { $_.ToString().Length } | Measure-Object -Maximum).Maximum)# 輸出彩色表格Write-Host "--------------------------------------------------"Write-Host "Fmax Report for $PROJECT_NAME" -ForegroundColor YellowWrite-Host "--------------------------------------------------"# 標題行Write-Host ("{0,-$tempWidth} {1,-$fmaxWidth}" -f "temp", "Fmax") -ForegroundColor CyanWrite-Host ("{0,-$tempWidth} {1,-$fmaxWidth}" -f "----", "-----------") -ForegroundColor DarkGray# 數據行foreach ($item in $data) {# 溫度用綠色,Fmax用藍色Write-Host ("{0,-$tempWidth}" -f $item.temp) -NoNewline -ForegroundColor GreenWrite-Host (" {0,-$fmaxWidth}" -f $item.Fmax) -ForegroundColor Blue}} else {Write-Host "Failed to find Fmax values in report" -ForegroundColor Red} } else {Write-Host "Report file not found: $reportPath" -ForegroundColor Red }
②查看報告
? ? ? ? 生成的報告都在output_files目錄,其中fit.map和map.rpt是我們需要關注的,在fit.map中,大概兩百多行處就是資源消耗的總結報告
? ? ? ? 由于沒有什么rpt文件相關的插件,如果想要更詳細的信息,那么還是到Quartus里查看比較好
資源消耗報告
? ? ? ? 不過既然想做一站式開發,頻繁切換開發環境并不好。因此我們可以同前面一樣,在腳本后面加一些命令來解析rpt文件獲取一些重要信息,比如掌管資源消耗的xxx.fit.rpt文件
? ? ? ? 需注意,這些腳本的路徑都是基于項目路徑,只要項目路徑傳輸正確并且output_files能正確在項目路徑里生成(這一條是由Quartus自動生成的)
# 提取 資源消耗 $reportPath = Join-Path $WORK_DIR "output_files\$PROJECT_NAME.fit.rpt" if (-not (Test-Path $reportPath)) {Write-Host "Report file not found: $reportPath" -ForegroundColor Redexit 1 }# 讀取報告內容 $content = Get-Content $reportPath -Raw# 提取頂層實體名 if ($content -match '; Top-level Entity Name\s+;\s*(?<entity>\S+)\s*;') {$topEntity = $matches.entity } else {$topEntity = "Unknown" }# 定義要提取的關鍵資源項 $resourcePatterns = @{"Total Logic Elements" = '; Total logic elements\s+;\s+(.*?)\s*;'"Total Registers" = '; Total registers\*\s+;\s+(.*?)\s*;'"I/O Pins" = '; I/O pins\s+;\s+(.*?)\s*;'"Used LABs" = '; Total LABs:\s+partially or completely used\s+;\s+(.*?)\s*;'"Global Clocks" = '; Global clocks\s+;\s+(.*?)\s*;'"Peak Interconnect Usage" = '; Peak interconnect usage.*?\s+;\s+(.*?)\s*;'"Max Fan-out" = '; Maximum fan-out\s+;\s+(.*?)\s*;'"Memory (M9Ks)" = '; M9Ks\s+;\s+(.*?)\s*;'"PLLs" = '; PLLs\s+;\s+(.*?)\s*;'"Average Interconnect Usage" = '; Average interconnect usage.*?\s+;\s+(.*?)\s*;' }# 提取數據 $resourceData = @{} foreach ($key in $resourcePatterns.Keys) {if ($content -match $resourcePatterns[$key]) {$resourceData[$key] = $matches[1].Trim()} else {$resourceData[$key] = "N/A"} }# 創建表格數據 $reportData = @() foreach ($key in $resourceData.Keys) {$reportData += [PSCustomObject]@{Resource = $keyValue = $resourceData[$key]} }# 自動調整表格列寬 $maxResourceLength = ($reportData.Resource | Measure-Object -Maximum -Property Length).Maximum $maxValueLength = ($reportData.Value | Measure-Object -Maximum -Property Length).Maximum# 輸出彩色表格 Write-Host "--------------------------------------------------" Write-Host "Fitter Resource Usage Report for [$topEntity]" -ForegroundColor Yellow Write-Host "--------------------------------------------------"# 標題行 Write-Host ("{0,-$maxResourceLength} {1,-$maxValueLength}" -f "Resource", "Value") -ForegroundColor Cyan Write-Host ("{0,-$maxResourceLength} {1,-$maxValueLength}" -f "--------------------------------", "--------------------------------") -ForegroundColor DarkGrayforeach ($item in $reportData) {# 根據資源類型設置顏色$valueColor = if ($item.Value -match "\d+%\s*\)") { "Cyan" } else { "Magenta" }Write-Host ("{0,-$maxResourceLength}" -f $item.Resource) -NoNewline -ForegroundColor GreenWrite-Host (" {0,-$maxValueLength}" -f $item.Value) -ForegroundColor $valueColor }Write-Host "--------------------------------------------------"
效果如下,需要什么效果就用正則表達式提取相應信息,生成想要的格式
3,仿真任務
????????與前篇一致,插件仿真默認使用的是iverilog,那么對sv文件的支持就相當差了,點擊爬蟲沒有反應,但對v文件有反應。
①ModelSim_GUI
? ? ? ? 那么也如前面,創建一個仿真任務,在原任務下面即可,逗號不要忘記添加
{// 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腳本
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 = $nullGet-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 = $filePathWrite-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 -sv -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","quit" )# 5. 安全寫入文件 try {$DoContent = $DoContent -join "`r`n"$DoContent | Out-File $DoScript -Encoding ASCII -ForceWrite-Host "DO script generated: $DoScript" -ForegroundColor Blue# 執行仿真if ($Config.SimTool -match "ModelSim") {Write-Host "Launching ModelSim..." -ForegroundColor BlueStart-Process vsim.exe -ArgumentList "-c -do `"$DoScript`"" -Wait -NoNewWindow} } catch {if (Test-Path $DoBackupPath) {Move-Item $DoBackupPath $DoScript -ForceWrite-Host "Restored original DO script"}throw $_ }
同前面一樣,再創建一個仿真任務
{"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文件的功能。想要生成波形,測試激勵文件里必須加上下面這句
initial begin$dumpfile("xxx.vcd");// 填寫對應的名稱$dumpvars; end
點擊生成的vcd文件后,會出現這樣的一個波形圖,此時空空如也。點擊右上角
選擇需要的信號
左邊就會出現你需要的信號,右鍵信號會有一些配置選項
此時,需要點擊信號(變亮就行,點亮后波形也更亮),再點擊紅色箭頭指向的位置,移動到最左邊,不然波形不一定能看得到(如果太短的話)
調整到合適的位置之后,箭頭所指方向,有三種不同的顯示方式,旁邊還有數值的顯示方式。想要調節,那么左邊的信號必須被點亮
第一種是數字型,第二種是離散化,第三種是模擬
其他仿真波形,“?”是高阻態,即z。“x”是未知值,紫色是數據幀
4,qsf文件的基礎分析
? ? ? ? qsf文件對于Quartus相當于CMakeLists或者makefile對于C項目的管理,而目前的自動化流程是在Quartus綜合的基礎上構建的,因此需要簡單理解一些基礎的命令來更快的輔助開發。同時為了避免過度修改導致工程出現問題,要么手動備份,要么使用版本控制。
? ? ? ? 在qsf文件中我們可以看到這樣的寫法,“#”就是行注釋,里面的命令不區分順序,并且可以出現空行,命令要頂格寫且選項參數遵循間要有空格(同時也方面ps1腳本解析)
????????這些命令不需要強記,因為這里我只要會修改即可,而且僅從“-name”后面的內容就可以看出它大概是干什么的了。比如下面,顯然,上面是芯片族,下面是具體芯片型號
set_global_assignment -name FAMILY "Cyclone IV E" set_global_assignment -name DEVICE EP4CE6E22C8
①引腳綁定
? ? ? ? qsf文件里面的命令并不一定是整齊排列的,為了便于我們管理,可以主動整理。比如引腳信號,在不確定引腳不常改變的情況下,可以先整理一下引腳,備份引腳便于下次新建工程時或者切換模塊時快速恢復引腳
? ? ? ? 配置引腳時是需要使用Quartus里的引腳綁定窗口,這里只是提供一種備份的思路
②資源文件
? ? ? ? 如果文件都放在同一目錄下,在Quartus里添加文件并不是一件方便的事。我們可以找到類似于下面這樣的命令,把它們放到一起,前面可以加上一些注釋來表明。-name后面左邊的是文件類型,右邊是對應的文件
SYSTEMVERILOG_FILE說明它是.sv文件,VERILOG_FILE自然就是.v文件,SDC_FILE是時序約束文件
set_global_assignment -name SYSTEMVERILOG_FILE xxx.sv
set_global_assignment -name VERILOG_FILE xxx.v
? ? ? ? 測試激勵文件與前面類似,不過它只有一種類型EDA_TEST_BENCH_FILE,后面緊跟著文件名(相對路徑,相對于項目根目錄),-section_id后面跟著的是名稱,需要確保測試模塊名稱、仿真文件名稱和這里的名稱相同
③頂層文件
? ? ? ? 這里的頂層文件指的不僅有模塊頂層文件,還有測試模塊文件。TOP_LEVEL_ENTITY描述的是模塊頂層文件,EDA_NATIVELINK_SIMULATION_TEST_BENCH描述的是選中的仿真文件。
? ? ? ? 需要注意的是它們都是名稱而非文件,只不過模塊名稱與文件名稱需要相同罷了
# ======================================================================== # Entity # ======================================================================== set_global_assignment -name TOP_LEVEL_ENTITY regs set_global_assignment -name EDA_NATIVELINK_SIMULATION_TEST_BENCH regs_tb -section_id eda_simulation
? ? ? ? 此外,由于前面腳本解析的原因,需要確保指定頂層模塊的命令放在前面,至少在資源文件定義前面
④測試激勵文件綁定
????????針對于一個仿真測試模塊,需要三條命令來約束
????????連著不容易看懂,可以把它們每三個按空格隔開
????????前面如果添加了這是激勵文件,這里也要同步添加名稱,這里的配置不常改,只要把三個復制一下然后改一下名稱即可