0.4.0 第三次测试迭代
This commit is contained in:
parent
a141f5f53c
commit
ab24f6c670
@ -71,5 +71,12 @@
|
|||||||
"info.pl.xilinx.no-need-add-files": "Keine Dateien zum Hinzufügen zum Xilinx-Projekt",
|
"info.pl.xilinx.no-need-add-files": "Keine Dateien zum Hinzufügen zum Xilinx-Projekt",
|
||||||
"info.pl.xilinx.no-need-del-files": "Es müssen keine Dateien aus Xilinx gelöscht werden.",
|
"info.pl.xilinx.no-need-del-files": "Es müssen keine Dateien aus Xilinx gelöscht werden.",
|
||||||
"error.pl.launch.not-valid-vivado-path": "Fehler beim Starten des Vivado TCL-Skriptinterpreters: {0}. Bitte überprüfen Sie, ob der Startpfad für Vivado korrekt ist. Derzeit eingestellter Startordnerpfad für Vivado: {1}",
|
"error.pl.launch.not-valid-vivado-path": "Fehler beim Starten des Vivado TCL-Skriptinterpreters: {0}. Bitte überprüfen Sie, ob der Startpfad für Vivado korrekt ist. Derzeit eingestellter Startordnerpfad für Vivado: {1}",
|
||||||
"info.pl.launch.set-vivado-path": "Zur Einstellung des Vivado-Installationspfads gehen"
|
"info.pl.launch.set-vivado-path": "Zur Einstellung des Vivado-Installationspfads gehen",
|
||||||
|
"info.monitor.current-mode": "Aktueller Monitor-Modus: {0}",
|
||||||
|
"info.simulation.create-vvp": "VVP-Datei in {0} erstellen",
|
||||||
|
"error.simulation.reason": "Grund: {0}",
|
||||||
|
"info.simulate.vvp.vcd-generate": "vcd-Datei wurde erstellt in {0}",
|
||||||
|
"error.simluate.icarus.use-primitives": "Es wurde ein Primitiv {0} erkannt, aber Icarus iverilog unterstützt keine Primitiven.",
|
||||||
|
"error.simluate.icarus.use-ip": "Es wurde die IP {0} verwendet, aber Icarus iverilog unterstützt keine IP.",
|
||||||
|
"error.simulation.error-happen-run-command": "Fehler bei der Icarus-Simulation:"
|
||||||
}
|
}
|
@ -71,5 +71,12 @@
|
|||||||
"info.pl.xilinx.no-need-add-files": "No files need to be added to the Xilinx project",
|
"info.pl.xilinx.no-need-add-files": "No files need to be added to the Xilinx project",
|
||||||
"info.pl.xilinx.no-need-del-files": "There are no files to be deleted from Xilinx.",
|
"info.pl.xilinx.no-need-del-files": "There are no files to be deleted from Xilinx.",
|
||||||
"error.pl.launch.not-valid-vivado-path": "Error encountered while starting the Vivado TCL script interpreter: {0}. Please check if your Vivado startup path is correct. Currently set Vivado startup folder path: {1}",
|
"error.pl.launch.not-valid-vivado-path": "Error encountered while starting the Vivado TCL script interpreter: {0}. Please check if your Vivado startup path is correct. Currently set Vivado startup folder path: {1}",
|
||||||
"info.pl.launch.set-vivado-path": "Go to set the Vivado installation path"
|
"info.pl.launch.set-vivado-path": "Go to set the Vivado installation path",
|
||||||
|
"info.monitor.current-mode": "Current monitor mode: {0}",
|
||||||
|
"info.simulation.create-vvp": "Create VVP file in {0}",
|
||||||
|
"error.simulation.reason": "Reason: {0}",
|
||||||
|
"info.simulate.vvp.vcd-generate": "vcd file has been generated to {0}",
|
||||||
|
"error.simluate.icarus.use-primitives": "Primitive {0} detected, but Icarus iverilog does not support primitives.",
|
||||||
|
"error.simluate.icarus.use-ip": "Detected the use of IP {0}, but Icarus iverilog does not support IP.",
|
||||||
|
"error.simulation.error-happen-run-command": "Error during Icarus simulation:"
|
||||||
}
|
}
|
@ -71,5 +71,12 @@
|
|||||||
"info.pl.xilinx.no-need-add-files": "Xilinx プロジェクトに追加するファイルはありません",
|
"info.pl.xilinx.no-need-add-files": "Xilinx プロジェクトに追加するファイルはありません",
|
||||||
"info.pl.xilinx.no-need-del-files": "Xilinx から削除するファイルはありません。",
|
"info.pl.xilinx.no-need-del-files": "Xilinx から削除するファイルはありません。",
|
||||||
"error.pl.launch.not-valid-vivado-path": "Vivado TCL スクリプトインタプリタの起動中にエラーが発生しました:{0}。Vivado の起動パスが正しいか確認してください。現在設定されている Vivado 起動フォルダパス:{1}",
|
"error.pl.launch.not-valid-vivado-path": "Vivado TCL スクリプトインタプリタの起動中にエラーが発生しました:{0}。Vivado の起動パスが正しいか確認してください。現在設定されている Vivado 起動フォルダパス:{1}",
|
||||||
"info.pl.launch.set-vivado-path": "Vivado インストールパスの設定に移動"
|
"info.pl.launch.set-vivado-path": "Vivado インストールパスの設定に移動",
|
||||||
|
"info.monitor.current-mode": "現在のモニターモード:{0}",
|
||||||
|
"info.simulation.create-vvp": "{0} で VVP ファイルを作成",
|
||||||
|
"error.simulation.reason": "理由: {0}",
|
||||||
|
"info.simulate.vvp.vcd-generate": "vcdファイルが生成されました: {0}",
|
||||||
|
"error.simluate.icarus.use-primitives": "プリミティブ {0} が検出されましたが、Icarus iverilog はプリミティブをサポートしていません。",
|
||||||
|
"error.simluate.icarus.use-ip": "IP {0} が使用されていますが、Icarus iverilog は IP をサポートしていません。",
|
||||||
|
"error.simulation.error-happen-run-command": "Icarusシミュレーション中にエラーが発生しました:"
|
||||||
}
|
}
|
@ -71,5 +71,12 @@
|
|||||||
"info.pl.xilinx.no-need-add-files": "没有需要添加到 Xilinx 工程的文件",
|
"info.pl.xilinx.no-need-add-files": "没有需要添加到 Xilinx 工程的文件",
|
||||||
"info.pl.xilinx.no-need-del-files": "没有需要从 Xilinx 中删除的文件",
|
"info.pl.xilinx.no-need-del-files": "没有需要从 Xilinx 中删除的文件",
|
||||||
"error.pl.launch.not-valid-vivado-path": "启动 Vivado TCL 脚本解释器遇到错误:{0} 。请检查你的 Vivado 启动路径是否正确,当前设置的 Vivado 启动文件夹路径:{1}",
|
"error.pl.launch.not-valid-vivado-path": "启动 Vivado TCL 脚本解释器遇到错误:{0} 。请检查你的 Vivado 启动路径是否正确,当前设置的 Vivado 启动文件夹路径:{1}",
|
||||||
"info.pl.launch.set-vivado-path": "前往设置 Vivado 安装路径"
|
"info.pl.launch.set-vivado-path": "前往设置 Vivado 安装路径",
|
||||||
|
"info.monitor.current-mode": "当前监视器模式:{0}",
|
||||||
|
"info.simulation.create-vvp": "在 {0} 创建 VVP 文件",
|
||||||
|
"error.simulation.reason": "原因: {0}",
|
||||||
|
"info.simulate.vvp.vcd-generate": "vcd 文件已经生成至 {0}",
|
||||||
|
"error.simluate.icarus.use-primitives": "检测到使用了原语 {0},但是 Icarus iverilog 并不支持原语",
|
||||||
|
"error.simluate.icarus.use-ip": "检测到使用了 IP {0},但是 Icarus iverilog 并不支持 IP",
|
||||||
|
"error.simulation.error-happen-run-command": "Icarus 仿真时,出现错误:"
|
||||||
}
|
}
|
@ -71,5 +71,12 @@
|
|||||||
"info.pl.xilinx.no-need-add-files": "沒有需要添加到 Xilinx 工程的文件",
|
"info.pl.xilinx.no-need-add-files": "沒有需要添加到 Xilinx 工程的文件",
|
||||||
"info.pl.xilinx.no-need-del-files": "沒有需要從 Xilinx 中刪除的檔案。",
|
"info.pl.xilinx.no-need-del-files": "沒有需要從 Xilinx 中刪除的檔案。",
|
||||||
"error.pl.launch.not-valid-vivado-path": "啟動 Vivado TCL 腳本解釋器遇到錯誤:{0} 。請檢查你的 Vivado 啟動路徑是否正確,目前設定的 Vivado 啟動資料夾路徑:{1}",
|
"error.pl.launch.not-valid-vivado-path": "啟動 Vivado TCL 腳本解釋器遇到錯誤:{0} 。請檢查你的 Vivado 啟動路徑是否正確,目前設定的 Vivado 啟動資料夾路徑:{1}",
|
||||||
"info.pl.launch.set-vivado-path": "前往設定 Vivado 安裝路徑"
|
"info.pl.launch.set-vivado-path": "前往設定 Vivado 安裝路徑",
|
||||||
|
"info.monitor.current-mode": "目前監視器模式:{0}",
|
||||||
|
"info.simulation.create-vvp": "在 {0} 建立 VVP 檔案",
|
||||||
|
"error.simulation.reason": "原因: {0}",
|
||||||
|
"info.simulate.vvp.vcd-generate": "vcd 檔案已生成至 {0}",
|
||||||
|
"error.simluate.icarus.use-primitives": "偵測到使用了原語 {0},但是 Icarus iverilog 並不支援原語。",
|
||||||
|
"error.simluate.icarus.use-ip": "偵測到使用了 IP {0},但是 Icarus iverilog 並不支援 IP。",
|
||||||
|
"error.simulation.error-happen-run-command": "Icarus 模擬時,出現錯誤:"
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as fspath from 'path';
|
||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
|
|
||||||
import { hdlParam } from '../../hdlParser';
|
import { hdlParam } from '../../hdlParser';
|
||||||
@ -10,6 +11,7 @@ import { HdlLangID, ToolChainType } from '../../global/enum';
|
|||||||
import { HdlFile, HdlModule } from '../../hdlParser/core';
|
import { HdlFile, HdlModule } from '../../hdlParser/core';
|
||||||
import { ModuleDataItem } from '../treeView/tree';
|
import { ModuleDataItem } from '../treeView/tree';
|
||||||
import { defaultMacro, doFastApi } from '../../hdlParser/util';
|
import { defaultMacro, doFastApi } from '../../hdlParser/util';
|
||||||
|
import { t } from '../../i18n';
|
||||||
|
|
||||||
type Path = string;
|
type Path = string;
|
||||||
|
|
||||||
@ -185,17 +187,35 @@ class IcarusSimulate extends Simulate {
|
|||||||
return args.join(' ').trim();
|
return args.join(' ').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 生成用于进行仿真的依赖项相关的参数
|
||||||
|
* @param dependences
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
private makeDependenceArguments(dependences: string[]): string {
|
private makeDependenceArguments(dependences: string[]): string {
|
||||||
// 去重
|
// 去重
|
||||||
const visitedPath = new Set<Path>;
|
const visitedPath = new Set<Path>;
|
||||||
const args = [];
|
const args = [];
|
||||||
for (const dep of dependences) {
|
for (const dep of dependences) {
|
||||||
|
// 去重
|
||||||
if (visitedPath.has(dep)) {
|
if (visitedPath.has(dep)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// icarus 不支持 原语
|
||||||
|
if (dep === 'xilinx-primitives') {
|
||||||
|
MainOutput.report(t('error.simluate.icarus.use-primitives', dep), { level: ReportType.Error });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// icarus 不支持 IP
|
||||||
|
if (dep.startsWith(opeParam.prjInfo.ipPath)) {
|
||||||
|
MainOutput.report(t('error.simluate.icarus.use-ip', dep), { level: ReportType.Error });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
args.push(makeSafeArgPath(dep));
|
args.push(makeSafeArgPath(dep));
|
||||||
visitedPath.add(dep);
|
visitedPath.add(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.join(' ').trim();
|
return args.join(' ').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,13 +235,15 @@ class IcarusSimulate extends Simulate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate acutal iverlog simulation command
|
* @description 获取 iverilog 仿真的命令
|
||||||
* @param name name of top module
|
* @param name name of top module
|
||||||
* @param path path of the simulated file
|
* @param path path of the simulated file
|
||||||
* @param dependences dependence that not specified in `include macro
|
* @param dependences dependence that not specified in `include macro
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private getCommand(name: string, path: AbsPath, dependences: string[]): string | undefined {
|
private getCommand(name: string, path: AbsPath, dependences: string[]): string | undefined {
|
||||||
|
MainOutput.clear();
|
||||||
|
|
||||||
const simConfig = this.getConfig(path, 'iverilog');
|
const simConfig = this.getConfig(path, 'iverilog');
|
||||||
if (!simConfig) {
|
if (!simConfig) {
|
||||||
return;
|
return;
|
||||||
@ -252,22 +274,14 @@ class IcarusSimulate extends Simulate {
|
|||||||
const iverilogPath = simConfig.iverilogPath;
|
const iverilogPath = simConfig.iverilogPath;
|
||||||
// default is -g2012
|
// default is -g2012
|
||||||
const argu = '-g' + iverilogCompileOptions.standard;
|
const argu = '-g' + iverilogCompileOptions.standard;
|
||||||
const outVvpPath = makeSafeArgPath(hdlPath.join(simConfig.simulationHome, 'out.vvp'));
|
const outVvpPath = makeSafeArgPath(hdlPath.join(simConfig.simulationHome, name + '.vvp'));
|
||||||
const mainPath = makeSafeArgPath(path);
|
const mainPath = makeSafeArgPath(path);
|
||||||
|
|
||||||
// console.log(macroIncludeArgs);
|
|
||||||
// console.log(thirdLibraryDirArgs);
|
|
||||||
// console.log(dependenceArgs);
|
|
||||||
// console.log(thirdLibraryFileArgs);
|
|
||||||
|
|
||||||
const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${macroIncludeArgs} ${thirdLibraryDirArgs} ${mainPath} ${dependenceArgs} ${thirdLibraryFileArgs}`;
|
const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${macroIncludeArgs} ${thirdLibraryDirArgs} ${mainPath} ${dependenceArgs} ${thirdLibraryFileArgs}`;
|
||||||
MainOutput.report(cmd, {
|
|
||||||
level: ReportType.Run
|
|
||||||
});
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private execInTerminal(command: string, cwd: AbsPath) {
|
private execInTerminal(command: string, cwd: AbsPath, hdlModule: HdlModule) {
|
||||||
// let vvp: vscode.Terminal;
|
// let vvp: vscode.Terminal;
|
||||||
// const targetTerminals = vscode.window.terminals.filter(t => t.name === 'vvp');
|
// const targetTerminals = vscode.window.terminals.filter(t => t.name === 'vvp');
|
||||||
// if (targetTerminals.length > 0) {
|
// if (targetTerminals.length > 0) {
|
||||||
@ -291,56 +305,136 @@ class IcarusSimulate extends Simulate {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private execInOutput(command: string, cwd: AbsPath) {
|
/**
|
||||||
|
* @description 在 Digital IDE 窗口中运行 iverilog 的快速仿真
|
||||||
|
* @param command
|
||||||
|
* @param cwd
|
||||||
|
* @param hdlModule
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private execInOutput(command: string, cwd: AbsPath, hdlModule: HdlModule) {
|
||||||
const simConfig = this.simConfig;
|
const simConfig = this.simConfig;
|
||||||
if (!simConfig) {
|
if (!simConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
child_process.exec(command, { cwd }, (error, stdout, stderr) => {
|
|
||||||
|
this.runIverilog(simConfig, command, cwd, hdlModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
private reportCommandError(command: string, stderr: string) {
|
||||||
|
MainOutput.report(t('error.simulation.error-happen-run-command') + command, {
|
||||||
|
level: ReportType.Error
|
||||||
|
});
|
||||||
|
MainOutput.report(t('error.simulation.reason', stderr), {
|
||||||
|
level: ReportType.Error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 运行 iverilog xxx 的命令
|
||||||
|
* @param simConfig
|
||||||
|
* @param command
|
||||||
|
* @param cwd
|
||||||
|
* @param hdlModule
|
||||||
|
*/
|
||||||
|
private runIverilog(simConfig: SimulateConfig, command: string, cwd: string, hdlModule: HdlModule) {
|
||||||
|
child_process.exec(command, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
MainOutput.report('Error took place when run ' + command, {
|
this.reportCommandError(command, stderr);
|
||||||
level: ReportType.Error
|
return;
|
||||||
});
|
}
|
||||||
MainOutput.report('Reason: ' + stderr, {
|
|
||||||
level: ReportType.Error
|
// 准备执行 vvp
|
||||||
});
|
MainOutput.report(stdout);
|
||||||
} else {
|
const generateVvpName = hdlModule.name + '.vvp';
|
||||||
MainOutput.report(stdout, {
|
|
||||||
level: ReportType.Info
|
const outVvpPath = hdlPath.join(simConfig.simulationHome, generateVvpName);
|
||||||
});
|
MainOutput.report(t('info.simulation.create-vvp', outVvpPath), {
|
||||||
const vvpOutFile = hdlPath.join(simConfig.simulationHome, 'out.vvp');
|
|
||||||
MainOutput.report("Create vvp to " + vvpOutFile, {
|
|
||||||
level: ReportType.Run
|
level: ReportType.Run
|
||||||
});
|
});
|
||||||
|
|
||||||
const outVvpPath = hdlPath.join(simConfig.simulationHome, 'out.vvp');
|
|
||||||
const vvpPath = simConfig.vvpPath;
|
const vvpPath = simConfig.vvpPath;
|
||||||
|
|
||||||
// run vvp to interrupt script
|
// 运行 vvp 文件,执行目录在生成的 vcd 的同级目录
|
||||||
|
// 对于 vvp 执行的 cwd,为了方便用户可以调用 $readmemb $fopen $dumpfile
|
||||||
|
// 这些系统调用进行 IO,所以选择 {workspace} 作为执行 vvp 的 cwd
|
||||||
|
const vvpCwd = opeParam.openMode === 'file' ? cwd: opeParam.workspacePath;
|
||||||
|
|
||||||
const vvpCommand = `${vvpPath} ${outVvpPath}`;
|
const vvpCommand = `${vvpPath} ${outVvpPath}`;
|
||||||
MainOutput.report(vvpCommand, {
|
MainOutput.report(vvpCommand, { level: ReportType.Run });
|
||||||
level: ReportType.Run
|
|
||||||
});
|
|
||||||
|
|
||||||
child_process.exec(vvpCommand, { cwd }, (error, stdout, stderr) => {
|
this.runVvp(vvpCommand, vvpCwd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 陨星 vvp xxx 的命令
|
||||||
|
* @param command
|
||||||
|
* @param cwd
|
||||||
|
*/
|
||||||
|
private runVvp(command: string, cwd: string) {
|
||||||
|
child_process.exec(command, { cwd }, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
MainOutput.report('Error took place when run ' + vvpCommand, {
|
this.reportCommandError(command, stderr);
|
||||||
level: ReportType.Error
|
return;
|
||||||
});
|
|
||||||
MainOutput.report('Reason: ' + stderr, {
|
|
||||||
level: ReportType.Error
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
MainOutput.report(stdout, {
|
|
||||||
level: ReportType.Info
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对于 vvp 的输出结果,特殊处理
|
||||||
|
this.handleVvpStdOutput(stdout, command, cwd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private exec(command: string, cwd: AbsPath) {
|
/**
|
||||||
|
* @description 处理 vvp xxx.vvp 执行后输出的标准输出
|
||||||
|
* vvp 的标准输出似乎总是一行一个的
|
||||||
|
* @param stdoutMessage vvp 执行后的标准输出窗口
|
||||||
|
* @param command 用于重新执行
|
||||||
|
* @param cwd 用于重新执行
|
||||||
|
*/
|
||||||
|
private handleVvpStdOutput(stdoutMessage: string, command: string, cwd: string) {
|
||||||
|
for (const line of stdoutMessage.split('\n').map(line => line.trim())) {
|
||||||
|
if (line.startsWith('WARNING:')) {
|
||||||
|
// 运行时警告
|
||||||
|
MainOutput.report(line.slice(8).trim(), { level: ReportType.Warn });
|
||||||
|
|
||||||
|
} else if (line.startsWith('ERROR:')) {
|
||||||
|
// 运行时错误,比如用户 $readmemb 读取的文件并不存在
|
||||||
|
MainOutput.report(line.slice(6).trim(), { level: ReportType.Error });
|
||||||
|
|
||||||
|
} else if (line.startsWith('VCD info:')) {
|
||||||
|
// 导出 VCD 的信息,用于输出
|
||||||
|
// 此处尝试提取 vcd 导出的信息,然后转换内部信息导出到屏幕上
|
||||||
|
const match = line.match(/dumpfile (.+) opened for output/);
|
||||||
|
if (match) {
|
||||||
|
const vcdPath = match[1];
|
||||||
|
const absVcdPath = hdlPath.resolve(cwd, vcdPath);
|
||||||
|
MainOutput.report(t('info.simulate.vvp.vcd-generate', absVcdPath));
|
||||||
|
} else {
|
||||||
|
MainOutput.report(line.slice(9).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (line.startsWith('VCD Error:')) {
|
||||||
|
// 出现 VCD Error 可能是因为生成地点的目录不存在,创建目录,然后再运行
|
||||||
|
const match = line.match(/Unable to open (.+) for output\./);
|
||||||
|
if (match) {
|
||||||
|
const vcdPath = match[1];
|
||||||
|
const absVcdPath = hdlPath.resolve(cwd, vcdPath);
|
||||||
|
const parentFolderPath = fspath.dirname(absVcdPath);
|
||||||
|
hdlDir.mkdir(parentFolderPath);
|
||||||
|
// 清除输出,准备第二次运行
|
||||||
|
MainOutput.clear();
|
||||||
|
this.runVvp(command, cwd);
|
||||||
|
} else {
|
||||||
|
// 没有匹配到,说明是其他错误,直接按照错误输出
|
||||||
|
MainOutput.report(line.slice(10).trim(), { level: ReportType.Error });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MainOutput.report(line, { level: ReportType.Info });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private exec(command: string, cwd: AbsPath, hdlModule: HdlModule) {
|
||||||
const simConfig = this.simConfig;
|
const simConfig = this.simConfig;
|
||||||
if (!simConfig) {
|
if (!simConfig) {
|
||||||
MainOutput.report('this.simConfig is empty when exec');
|
MainOutput.report('this.simConfig is empty when exec');
|
||||||
@ -350,10 +444,10 @@ class IcarusSimulate extends Simulate {
|
|||||||
const runInTerminal = vscode.workspace.getConfiguration().get('digital-ide.function.simulate.runInTerminal');
|
const runInTerminal = vscode.workspace.getConfiguration().get('digital-ide.function.simulate.runInTerminal');
|
||||||
|
|
||||||
if (runInTerminal) {
|
if (runInTerminal) {
|
||||||
this.execInTerminal(command, cwd);
|
this.execInTerminal(command, cwd, hdlModule);
|
||||||
} else {
|
} else {
|
||||||
MainOutput.show();
|
MainOutput.show();
|
||||||
this.execInOutput(command, cwd);
|
this.execInOutput(command, cwd, hdlModule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,11 +469,12 @@ class IcarusSimulate extends Simulate {
|
|||||||
// MainOutput.report(warningMsg, ReportType.Warn, true);
|
// MainOutput.report(warningMsg, ReportType.Warn, true);
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const dependences = this.getAllOtherDependences(path, name);
|
const dependences = this.getAllOtherDependences(path, name);
|
||||||
const simulationCommand = this.getCommand(name, path, dependences);
|
const simulationCommand = this.getCommand(name, path, dependences);
|
||||||
if (simulationCommand) {
|
if (simulationCommand) {
|
||||||
const cwd = hdlPath.resolve(path, '..');
|
const cwd = hdlPath.resolve(path, '..');
|
||||||
this.exec(simulationCommand, cwd);
|
this.exec(simulationCommand, cwd, hdlModule);
|
||||||
} else {
|
} else {
|
||||||
const errorMsg = 'Fail to generate command';
|
const errorMsg = 'Fail to generate command';
|
||||||
MainOutput.report(errorMsg, {
|
MainOutput.report(errorMsg, {
|
||||||
|
@ -133,7 +133,7 @@ async function askUserToSaveFilelist(filelist: string[]) {
|
|||||||
if (uri === undefined) {
|
if (uri === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filePath = uri.path;
|
const filePath = uri.fsPath;
|
||||||
const fileContent = filelist.join('\n');
|
const fileContent = filelist.join('\n');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -67,9 +67,6 @@ export function isSystemVerilogFile(path: AbsPath): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isHDLFile(path: AbsPath): boolean {
|
export function isHDLFile(path: AbsPath): boolean {
|
||||||
if (!isFile(path)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const ext = hdlPath.extname(path, false);
|
const ext = hdlPath.extname(path, false);
|
||||||
return hdlExts.includes(ext);
|
return hdlExts.includes(ext);
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ function toEscapePath(path: AbsPath): AbsPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toPureRelativePath(path: RelPath): RelPath {
|
function toPureRelativePath(path: RelPath): RelPath {
|
||||||
|
|
||||||
if (path.startsWith('./') || path.startsWith('.\\')) {
|
if (path.startsWith('./') || path.startsWith('.\\')) {
|
||||||
return path.slice(2);
|
return path.slice(2);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,10 @@ class HdlParam {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isTopModule(path, name)) {
|
||||||
|
console.log(module);
|
||||||
|
}
|
||||||
|
|
||||||
const dependencies : common.HdlDependence = {
|
const dependencies : common.HdlDependence = {
|
||||||
current: [],
|
current: [],
|
||||||
include: [],
|
include: [],
|
||||||
@ -497,15 +501,93 @@ class HdlParam {
|
|||||||
const hdlParam = new HdlParam();
|
const hdlParam = new HdlParam();
|
||||||
|
|
||||||
class HdlInstance {
|
class HdlInstance {
|
||||||
name: string; // name of the instance
|
/**
|
||||||
type: string; // type
|
* @description 例化的名字
|
||||||
|
*
|
||||||
|
* 对于下面的例子,唯一例化 的 name 就是 `u_tool`
|
||||||
|
* @example
|
||||||
|
* module hello()
|
||||||
|
* tool u_tool();
|
||||||
|
* endmodule
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化的模块名
|
||||||
|
*
|
||||||
|
* 对于下面的例子,唯一例化 的 type 就是 `tool`
|
||||||
|
* @example
|
||||||
|
* module hello()
|
||||||
|
* tool u_tool();
|
||||||
|
* endmodule
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化的 range
|
||||||
|
*/
|
||||||
range: common.Range; // range of instance
|
range: common.Range; // range of instance
|
||||||
instModPath: AbsPath | undefined; // path of the definition
|
|
||||||
instModPathStatus: common.InstModPathStatus; // status of the instance (current, include, others)
|
/**
|
||||||
instparams: common.InstRange; // range of params
|
* @description 例化的模块的定义路径
|
||||||
instports: common.InstRange; // range of ports
|
*
|
||||||
parentMod: HdlModule; // 例化模块例化地点的外层 module
|
* 对于下面的例子,唯一例化 的 instModPath 就是 `tool` 这个模块 `module tool` 申明所在的文件的路径
|
||||||
module: HdlModule | undefined; // 例化模块的定义模块
|
* @example
|
||||||
|
* module hello()
|
||||||
|
* tool u_tool();
|
||||||
|
* endmodule
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
instModPath: AbsPath | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 用于描述当前例化是如何被引入的,以下是三类枚举
|
||||||
|
* - current: 例化对应的模块就在当前文件中
|
||||||
|
* - include: 通过 `include
|
||||||
|
* - others: 其他
|
||||||
|
*/
|
||||||
|
instModPathStatus: common.InstModPathStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化 params 部分的 range.
|
||||||
|
* 如果是 vhdl,则是 generic map 部分的 range
|
||||||
|
*/
|
||||||
|
instparams: common.InstRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化 ports 部分的 range.
|
||||||
|
* 如果是 vhdl,则是 port map 部分的 range
|
||||||
|
*/
|
||||||
|
instports: common.InstRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化模块例化地点的外层 module
|
||||||
|
*
|
||||||
|
* 对于下面的例子, 例化 `u_tool` 的 parentMod 就是 `hello`
|
||||||
|
* @example
|
||||||
|
* module hello()
|
||||||
|
* tool u_tool();
|
||||||
|
* endmodule
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
parentMod: HdlModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 例化模块的定义模块
|
||||||
|
*
|
||||||
|
* 对于下面的例子, 例化 `u_tool` 的 `module` 就是 tool
|
||||||
|
* @example
|
||||||
|
* module hello();
|
||||||
|
* tool u_tool();
|
||||||
|
* endmodule
|
||||||
|
*
|
||||||
|
* module tool();
|
||||||
|
* ...
|
||||||
|
* endmodule
|
||||||
|
*/
|
||||||
|
module: HdlModule | undefined;
|
||||||
|
|
||||||
constructor(name: string,
|
constructor(name: string,
|
||||||
type: string,
|
type: string,
|
||||||
@ -611,7 +693,34 @@ class HdlInstance {
|
|||||||
this.instports = newInstance.instports;
|
this.instports = newInstance.instports;
|
||||||
|
|
||||||
this.instModPath = this.module?.path || '';
|
this.instModPath = this.module?.path || '';
|
||||||
this.instModPathStatus = this.parentMod.solveInstModPathStatus();
|
this.updateInstModPathStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 用于解决例化的路径引入状态,对于 A 模块,它的两个例化 u_A1 和 u_A2
|
||||||
|
* 使用 u_A1 和 u_A2 的模块需要知道 u_A1 是如何被引入的,此时需要调用 u_A1.updateInstModPathStatus() 来更新
|
||||||
|
* u_A1 的 instModPathStatus
|
||||||
|
*/
|
||||||
|
public updateInstModPathStatus() {
|
||||||
|
const module = this.module;
|
||||||
|
if (module) {
|
||||||
|
const userModule = this.parentMod;
|
||||||
|
if (userModule.path === module.path) {
|
||||||
|
this.instModPathStatus = common.InstModPathStatus.Current;
|
||||||
|
} else {
|
||||||
|
const userIncludePaths = userModule.file.macro.includes.map(
|
||||||
|
include => hdlPath.rel2abs(userModule.path, include.path)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userIncludePaths.includes(module.path)) {
|
||||||
|
this.instModPathStatus = common.InstModPathStatus.Include;
|
||||||
|
} else {
|
||||||
|
this.instModPathStatus = common.InstModPathStatus.Others;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.instModPathStatus = common.InstModPathStatus.Unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get getDoFastFileType(): DoFastFileType | undefined {
|
public get getDoFastFileType(): DoFastFileType | undefined {
|
||||||
@ -882,28 +991,6 @@ class HdlModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public solveInstModPathStatus(): common.InstModPathStatus {
|
|
||||||
// TODO: 修改这套系统,因为现在只是拿第一个例化来判断的,这是不合理的
|
|
||||||
// 应该把 common.InstModPathStatus 修改成一个可以通过析取来表示的变量
|
|
||||||
const inst = hdlParam.getUnhandleInstancesByModuleName(this.name)[0];
|
|
||||||
if (!inst) {
|
|
||||||
return common.InstModPathStatus.Unknown;
|
|
||||||
}
|
|
||||||
const userModule = inst.parentMod;
|
|
||||||
if (userModule.path === this.path) {
|
|
||||||
return common.InstModPathStatus.Current;
|
|
||||||
} else {
|
|
||||||
const userIncludePaths = userModule.file.macro.includes.map(
|
|
||||||
include => hdlPath.rel2abs(userModule.path, include.path));
|
|
||||||
|
|
||||||
if (userIncludePaths.includes(this.path)) {
|
|
||||||
return common.InstModPathStatus.Include;
|
|
||||||
} else {
|
|
||||||
return common.InstModPathStatus.Others;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 从全局寻找这个 module 的例化,并尝试修改它的状态
|
* @description 从全局寻找这个 module 的例化,并尝试修改它的状态
|
||||||
*/
|
*/
|
||||||
@ -918,7 +1005,7 @@ class HdlModule {
|
|||||||
|
|
||||||
// 解决
|
// 解决
|
||||||
instance.instModPath = this.path;
|
instance.instModPath = this.path;
|
||||||
instance.instModPathStatus = this.solveInstModPathStatus();
|
instance.updateInstModPathStatus();
|
||||||
|
|
||||||
// 找寻这个 instance 对应的真正的 module(也有可能是原语)
|
// 找寻这个 instance 对应的真正的 module(也有可能是原语)
|
||||||
// 并将这个 instance 加入这个 module 的计数器中
|
// 并将这个 instance 加入这个 module 的计数器中
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { AbsPath, opeParam } from '../global';
|
import { AbsPath, opeParam } from '../global';
|
||||||
import { hdlPath } from '../hdlFs';
|
import { hdlFile, hdlPath } from '../hdlFs';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as fspath from 'path';
|
||||||
import { minimatch } from 'minimatch';
|
import { minimatch } from 'minimatch';
|
||||||
|
import { toPureRelativePath } from '../hdlFs/path';
|
||||||
|
|
||||||
|
|
||||||
class HdlIgnore {
|
class HdlIgnore {
|
||||||
@ -19,9 +21,8 @@ class HdlIgnore {
|
|||||||
const workspace = opeParam.workspacePath;
|
const workspace = opeParam.workspacePath;
|
||||||
// 转换成相对于 ws 的相对路径,形如 ./src/test.py
|
// 转换成相对于 ws 的相对路径,形如 ./src/test.py
|
||||||
let relativePath = hdlPath.toPureRelativePath(hdlPath.relative(workspace, path));
|
let relativePath = hdlPath.toPureRelativePath(hdlPath.relative(workspace, path));
|
||||||
console.log('current path:', relativePath);
|
|
||||||
|
|
||||||
for (const pattern of this.patterns.map(p => hdlPath.toPureRelativePath(p))) {
|
for (const pattern of this.patterns) {
|
||||||
const matched = minimatch(relativePath, pattern);
|
const matched = minimatch(relativePath, pattern);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return true;
|
return true;
|
||||||
@ -55,11 +56,26 @@ class HdlIgnore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.patterns = [...validGlobStrings];
|
this.patterns = [...validGlobStrings];
|
||||||
|
this.makeClearPattern();
|
||||||
} else {
|
} else {
|
||||||
// .dideignore 不存在直接赋值为空
|
// .dideignore 不存在直接赋值为空
|
||||||
this.patterns = [];
|
this.patterns = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 构建可直接使用的 patterns
|
||||||
|
* 该操作是幂等的
|
||||||
|
*/
|
||||||
|
private makeClearPattern() {
|
||||||
|
for (let i = 0; i < this.patterns.length; ++ i) {
|
||||||
|
let pattern = this.patterns[i];
|
||||||
|
if (fspath.isAbsolute(pattern)) {
|
||||||
|
pattern = hdlPath.relative(opeParam.workspacePath, pattern);
|
||||||
|
}
|
||||||
|
this.patterns[i] = toPureRelativePath(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hdlIgnore = new HdlIgnore();
|
const hdlIgnore = new HdlIgnore();
|
||||||
|
@ -44,7 +44,6 @@ class HdlMonitor{
|
|||||||
*/
|
*/
|
||||||
public getHdlMonitor() {
|
public getHdlMonitor() {
|
||||||
const prjInfo = opeParam.prjInfo;
|
const prjInfo = opeParam.prjInfo;
|
||||||
|
|
||||||
const monitorPathSet = new PathSet();
|
const monitorPathSet = new PathSet();
|
||||||
|
|
||||||
// 在输出中展示当前的监视路径
|
// 在输出中展示当前的监视路径
|
||||||
@ -57,9 +56,15 @@ class HdlMonitor{
|
|||||||
level: ReportType.Launch
|
level: ReportType.Launch
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MainOutput.report(t('info.monitor.current-mode', opeParam.openMode));
|
||||||
|
|
||||||
|
if (opeParam.openMode === 'file') {
|
||||||
|
return this.makeMonitor([prjInfo.libCommonPath]);
|
||||||
|
} else {
|
||||||
// chokidar 4.0.0 开始不支持 glob,需要在每一个入口自己判断
|
// chokidar 4.0.0 开始不支持 glob,需要在每一个入口自己判断
|
||||||
return this.makeMonitor([opeParam.workspacePath, prjInfo.libCommonPath]);
|
return this.makeMonitor([opeParam.workspacePath, prjInfo.libCommonPath]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getIgnoreMonitor() {
|
public getIgnoreMonitor() {
|
||||||
const watcherPath = opeParam.dideignorePath;
|
const watcherPath = opeParam.dideignorePath;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user