From 98e5de86863230ce44a6b025462d4efe8f0dbd31 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Fri, 8 Nov 2024 23:00:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E4=BA=8E=20IP=20?= =?UTF-8?q?=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/svg/dark/ip.svg | 1 + images/svg/light/ip.svg | 14 ++++++++ l10n/bundle.l10n.de.json | 3 +- l10n/bundle.l10n.en.json | 3 +- l10n/bundle.l10n.ja.json | 3 +- l10n/bundle.l10n.zh-cn.json | 3 +- l10n/bundle.l10n.zh-tw.json | 3 +- src/function/treeView/index.ts | 45 +++++++++++++++++++++--- src/function/treeView/tree.ts | 64 ++++++++++++++++++++++++++++------ src/hdlParser/core.ts | 30 ++++++++++------ src/manager/prj.ts | 6 ++-- 11 files changed, 142 insertions(+), 33 deletions(-) create mode 100644 images/svg/dark/ip.svg create mode 100644 images/svg/light/ip.svg diff --git a/images/svg/dark/ip.svg b/images/svg/dark/ip.svg new file mode 100644 index 0000000..192f42d --- /dev/null +++ b/images/svg/dark/ip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/svg/light/ip.svg b/images/svg/light/ip.svg new file mode 100644 index 0000000..6b70e8d --- /dev/null +++ b/images/svg/light/ip.svg @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index 8fade0c..6d4ae04 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -25,5 +25,6 @@ "error.vcd-viewer.unexist-direct-vcd-file": "Die von der Ansichtsdatei referenzierte vcd-Datei existiert nicht", "info.welcome.join-qq-group": "Klicken Sie auf den Link, um der QQ-Gruppe beizutreten", "info.level.test": "Dies ist ein einfaches Beispiel", - "info.progress.build-ip-module-tree": "构建 IP 模块树" + "info.progress.build-ip-module-tree": "构建 IP 模块树", + "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核" } \ No newline at end of file diff --git a/l10n/bundle.l10n.en.json b/l10n/bundle.l10n.en.json index 4dfc9cb..bcb3f74 100644 --- a/l10n/bundle.l10n.en.json +++ b/l10n/bundle.l10n.en.json @@ -25,5 +25,6 @@ "error.vcd-viewer.unexist-direct-vcd-file": "The vcd file pointed to by the view file does not exist", "info.welcome.join-qq-group": "Click the link to join the QQ group", "info.level.test": "This is a simple example", - "info.progress.build-ip-module-tree": "构建 IP 模块树" + "info.progress.build-ip-module-tree": "构建 IP 模块树", + "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核" } \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json index 52c835d..11db163 100644 --- a/l10n/bundle.l10n.ja.json +++ b/l10n/bundle.l10n.ja.json @@ -25,5 +25,6 @@ "error.vcd-viewer.unexist-direct-vcd-file": "ビューファイルが指す vcd ファイルは存在しません", "info.welcome.join-qq-group": "リンクをクリックして QQ グループに参加", "info.level.test": "これは簡単な例です", - "info.progress.build-ip-module-tree": "构建 IP 模块树" + "info.progress.build-ip-module-tree": "构建 IP 模块树", + "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 42dd382..2372182 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -25,5 +25,6 @@ "error.vcd-viewer.unexist-direct-vcd-file": "视图文件指向的 vcd 文件不存在", "info.welcome.join-qq-group": "点击链接加入 QQ 群", "info.level.test": "这是一个简单的样例", - "info.progress.build-ip-module-tree": "构建 IP 模块树" + "info.progress.build-ip-module-tree": "构建 IP 模块树", + "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-tw.json b/l10n/bundle.l10n.zh-tw.json index 6071aeb..163a249 100644 --- a/l10n/bundle.l10n.zh-tw.json +++ b/l10n/bundle.l10n.zh-tw.json @@ -25,5 +25,6 @@ "error.vcd-viewer.unexist-direct-vcd-file": "視圖文件指向的 vcd 文件不存在", "info.welcome.join-qq-group": "點擊鏈接加入 QQ 群", "info.level.test": "這是一個簡單的樣例", - "info.progress.build-ip-module-tree": "构建 IP 模块树" + "info.progress.build-ip-module-tree": "构建 IP 模块树", + "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核" } \ No newline at end of file diff --git a/src/function/treeView/index.ts b/src/function/treeView/index.ts index f35da72..172d8d0 100644 --- a/src/function/treeView/index.ts +++ b/src/function/treeView/index.ts @@ -1,12 +1,21 @@ import * as vscode from 'vscode'; -import { hdlPath } from '../../hdlFs'; +import * as fs from 'fs'; +import * as fspath from 'path'; +import { hdlFile, hdlPath } from '../../hdlFs'; import { hardwareTreeProvider, softwareTreeProvider, toolTreeProvider } from './command'; import { moduleTreeProvider, ModuleDataItem } from './tree'; import { Range } from '../../hdlParser/common'; +import { MainOutput, opeParam, ReportType } from '../../global'; -async function openFileAtPosition(uri: vscode.Uri, range: Range) { +async function openFileAtPosition(uri: vscode.Uri, range?: Range) { + if (range === undefined) { + range = { + start: { line: 0, character: 0 }, + end: { line: 0, character: 0 } + } + } const document = await vscode.workspace.openTextDocument(uri); const start = new vscode.Position(range.start.line, range.start.character); const end = new vscode.Position(range.end.line, range.end.character); @@ -19,15 +28,43 @@ async function openFileAtPosition(uri: vscode.Uri, range: Range) { ); } -function openFileByUri(path: string, range: Range) { +function openFileByUri(path: string, range: Range, element: ModuleDataItem) { + const { t } = vscode.l10n; if (range === undefined) { vscode.window.showErrorMessage(`${path} not support jump yet`); return; } - if (hdlPath.exist(path)) { + if (hdlPath.exist(path) && hdlFile.isFile(path)) { const uri = vscode.Uri.file(path); openFileAtPosition(uri, range); + return; + } else { + if (element.doFastFileType === 'ip') { + switch (opeParam.prjInfo.toolChain) { + case 'xilinx': + return gotoXilinxIPDefinition(element); + default: + break; + } + } + } + MainOutput.report("invalid jump uri triggered in treeview, el: " + JSON.stringify(element, null, ' '), ReportType.Error); +} + +function gotoXilinxIPDefinition(element: ModuleDataItem) { + const { t } = vscode.l10n; + const folderPath = element.path; + if (folderPath) { + const ipName = fspath.basename(folderPath); + const defPath = hdlPath.join(folderPath, 'synth', ipName + '.vhd'); + if (fs.existsSync(defPath)) { + openFileAtPosition(vscode.Uri.file(defPath), element.range); + } else { + vscode.window.showInformationMessage(t('info.treeview.ip-no-active.message')); + } + } else { + MainOutput.report("[gotoXilinxIPDefinition] path is undefined", ReportType.Error); } } diff --git a/src/function/treeView/tree.ts b/src/function/treeView/tree.ts index 718c538..c4b02b5 100644 --- a/src/function/treeView/tree.ts +++ b/src/function/treeView/tree.ts @@ -7,6 +7,7 @@ import { HdlFileType, Range } from '../../hdlParser/common'; import { hdlFile, hdlPath } from '../../hdlFs'; import { xilinx, itemModes, otherModes } from './common'; import { getIconConfig } from '../../hdlFs/icons'; +import { DoFastFileType } from '../../global/lsp'; let needExpand = true; @@ -14,9 +15,10 @@ interface ModuleDataItem { icon: string, // 图标 name: string, // module name type: string, - range: Range | undefined | null, + doFastFileType: DoFastFileType | undefined, + range: Range | undefined, path: AbsPath | undefined, // path of the file - parent: ModuleDataItem | null // parent file + parent: ModuleDataItem | undefined // parent file } interface FirstTopItem { @@ -65,8 +67,26 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { src: null, sim: null, }; - this.srcRootItem = {icon: 'src', type: HdlFileType.Src, name: 'src', range: null, path: '', parent: null}; - this.simRootItem = {icon: 'sim', type: HdlFileType.Sim, name: 'sim', range: null, path: '', parent: null}; + + this.srcRootItem = { + icon: 'src', + type: HdlFileType.Src, + doFastFileType: undefined, + name: 'src', + range: undefined, + path: '', + parent: undefined + }; + + this.simRootItem = { + icon: 'sim', + type: HdlFileType.Sim, + doFastFileType: undefined, + name: 'sim', + range: undefined, + path: '', + parent: undefined + }; } public refresh(element?: ModuleDataItem) { @@ -125,7 +145,7 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { treeItem.command = { title: "Open this HDL File", command: 'digital-ide.treeView.arch.openFile', - arguments: [element.path, element.range], + arguments: [element.path, element.range, element], }; return treeItem; @@ -135,7 +155,7 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { if (element) { const name = element.name; if (name === 'sim' || name === 'src') { - element.parent = null; + element.parent = undefined; return this.getTopModuleItemList(element); } else { return this.getInstanceItemList(element); @@ -158,10 +178,11 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { const hardwarePath = opeParam.prjInfo.arch.hardware; const moduleType = element.name as keyof (SrcPath & SimPath); - const topModules = hdlParam.getTopModulesByType(moduleType); + const topModules = hdlParam.getTopModulesByType(moduleType); const topModuleItemList = topModules.map(module => ({ - icon: 'top', + icon: this.judgeTopModuleIconByDoFastType(module.file.doFastType), type: moduleType, + doFastFileType: module.file.doFastType, name: module.name, range: module.range, path: module.path, @@ -180,6 +201,8 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { const icon = this.makeFirstTopIconName(type); const range = firstTop.range; const parent = element; + // TODO: check + const doFastFileType = undefined; const tops = topModuleItemList.filter(item => item.path === path && item.name === name); const adjustItemList = []; @@ -198,7 +221,7 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { } else { // mean the selected top is not an original top module // create it and add it to the head of *topModuleItemList* - const selectedTopItem: ModuleDataItem = {icon, type, name, range, path, parent}; + const selectedTopItem: ModuleDataItem = {icon, type, name, range, path, parent, doFastFileType}; adjustItemList.push(selectedTopItem); adjustItemList.push(...topModuleItemList); } @@ -219,14 +242,16 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { if (targetModule) { for (const instance of targetModule.getAllInstances()) { - // 所有的例化模块都定向到它的定义文件上 + // 所有的例化模块都定向到它的定义文件上 + const item: ModuleDataItem = { icon: 'file', type: instance.name, name: instance.type, range: instance.module?.range, path: instance.module?.path, - parent: element + parent: element, + doFastFileType: instance.getDoFastFileType }; if (item.type === element.type && // 防止递归 @@ -260,6 +285,10 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { return 'File Error'; } + if (item.doFastFileType === 'ip') { + return 'ip'; + } + if (hdlPath.exist(item.path)) { if (!item.path?.includes(workspacePath)) { return 'remote'; @@ -276,6 +305,19 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { } } + private judgeTopModuleIconByDoFastType(doFastType: DoFastFileType): string { + switch (doFastType) { + case 'common': + return 'top'; + + case 'ip': + return 'ip'; + case 'primitives': + return 'celllib'; + } + return 'top'; + } + public getItemType(item: ModuleDataItem): string | null { if (!item) { return null; diff --git a/src/hdlParser/core.ts b/src/hdlParser/core.ts index 309f137..05b16a2 100644 --- a/src/hdlParser/core.ts +++ b/src/hdlParser/core.ts @@ -230,7 +230,7 @@ class HdlParam { try { const fast = await HdlSymbol.fast(path, fileType); if (fast) { - const languageId = hdlFile.getLanguageId(path); + const languageId = this.getRealLanguageId(path, fast.fileType); new HdlFile(path, languageId, fast.macro, @@ -243,6 +243,13 @@ class HdlParam { } } + private getRealLanguageId(path: string, fileType: DoFastFileType): HdlLangID { + if (fileType === 'ip' && opeParam.prjInfo.toolChain === 'xilinx') { + return HdlLangID.Vhdl; + } + return hdlFile.getLanguageId(path); + } + public async initializeHdlFiles(hdlFiles: AbsPath[], progress: vscode.Progress) { const { t } = vscode.l10n; @@ -267,9 +274,7 @@ class HdlParam { } for (const path of hdlFiles) { - count ++; - console.log('send request: ' + path); - + count ++; const p = this.doHdlFast(path, 'common'); pools.push({ id: count, promise: p, path }); if (pools.length % parallelChunk === 0) { @@ -307,9 +312,7 @@ class HdlParam { } for (const path of IPsPath) { - count ++; - console.log('send request: ' + path); - + count ++; const p = this.doHdlFast(path, 'ip'); pools.push({ id: count, promise: p, path }); if (pools.length % parallelChunk === 0) { @@ -439,8 +442,8 @@ class HdlInstance { instModPathStatus: common.InstModPathStatus; // status of the instance (current, include, others) instparams: common.InstRange; // range of params instports: common.InstRange; // range of ports - parentMod: HdlModule; // HdlModule that the instance serves - module: HdlModule | undefined; // module + parentMod: HdlModule; // 例化模块例化地点的外层 module + module: HdlModule | undefined; // 例化模块的定义模块 constructor(name: string, type: string, @@ -511,6 +514,10 @@ class HdlInstance { this.instModPath = this.parentMod.path; this.instModPathStatus = this.parentMod.solveInstModPathStatus(); } + + public get getDoFastFileType(): DoFastFileType | undefined { + return this.module?.file.doFastType; + } }; class HdlModule { @@ -706,7 +713,10 @@ class HdlModule { // search other files in the project for (const hdlFile of hdlParam.getAllHdlFiles()) { if (!excludeFile.has(hdlFile) && hdlFile.hasHdlModule(instModName)) { - return {path: hdlFile.path, status: common.InstModPathStatus.Others}; + return { + path: hdlFile.path, + status: common.InstModPathStatus.Others + }; } } diff --git a/src/manager/prj.ts b/src/manager/prj.ts index 4c684f1..c0d0717 100644 --- a/src/manager/prj.ts +++ b/src/manager/prj.ts @@ -165,7 +165,7 @@ class PrjManage { public isValidXilinxIP(folderPath: string): boolean { const folderName = fspath.basename(folderPath); - const descriptionFile = folderName + '.vho'; + const descriptionFile = folderName + '.xci'; const descriptionFilePath = hdlPath.join(folderPath, descriptionFile); return fs.existsSync(descriptionFilePath); } @@ -182,14 +182,14 @@ class PrjManage { prjManage.refreshPrjFolder(refreshPrjConfig); // 解析 hdl 文件,构建 hdlParam - const hdlFiles = await this.getPrjHardwareFiles(); + const hdlFiles = await this.getPrjHardwareFiles(); await hdlParam.initializeHdlFiles(hdlFiles, progress); // 根据 toolchain 解析合法的 IP,构建 hdlParam const IPsPath = await this.getPrjIPs(); await hdlParam.initializeIPsPath(IPsPath, progress); - // TODO: 解析原语并构建 + // TODO: 解析原语并构建,向后端索要原语缓存 // 构建 instance 解析