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 解析