This commit is contained in:
锦恢 2024-09-17 22:40:44 +08:00
commit a348b40a33
11 changed files with 239 additions and 61 deletions

View File

@ -593,7 +593,10 @@
{ {
"command": "digital-ide.tool.icarus.simulateFile", "command": "digital-ide.tool.icarus.simulateFile",
"group": "inline@1", "group": "inline@1",
"when": "view == digital-ide-treeView-arch && viewItem == file" "when": "view == digital-ide-treeView-arch && viewItem == file",
"args": {
"file": "${viewItem}"
}
}, },
{ {
"command": "digital-ide.netlist.show", "command": "digital-ide.netlist.show",

View File

@ -82,6 +82,8 @@ async function patchComment(path: AbsPath, ports: (HdlModulePort | HdlModulePara
} }
const ranges = ports.map(port => port.range); const ranges = ports.map(port => port.range);
const comments = await getSymbolComments(path, ranges); const comments = await getSymbolComments(path, ranges);
console.log(ranges);
for (let i = 0; i < ports.length; ++ i) { for (let i = 0; i < ports.length; ++ i) {
let inlineComment = comments[i].replace(/\n/, ' '); let inlineComment = comments[i].replace(/\n/, ' ');
if (inlineComment.startsWith('//') || inlineComment.startsWith('--')) { if (inlineComment.startsWith('//') || inlineComment.startsWith('--')) {

View File

@ -20,6 +20,7 @@ import * as lspCore from './lsp/core';
import * as FSM from './fsm'; import * as FSM from './fsm';
import * as Netlist from './netlist'; import * as Netlist from './netlist';
import * as WaveView from './dide-viewer'; import * as WaveView from './dide-viewer';
import { ModuleDataItem } from './treeView/tree';
function registerDocumentation(context: vscode.ExtensionContext) { function registerDocumentation(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('digital-ide.hdlDoc.showWebview', hdlDoc.showDocWebview); vscode.commands.registerCommand('digital-ide.hdlDoc.showWebview', hdlDoc.showDocWebview);
@ -30,7 +31,9 @@ function registerDocumentation(context: vscode.ExtensionContext) {
function registerSimulation(context: vscode.ExtensionContext) { function registerSimulation(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('digital-ide.tool.instance', sim.instantiation); vscode.commands.registerCommand('digital-ide.tool.instance', sim.instantiation);
vscode.commands.registerCommand('digital-ide.tool.testbench', sim.testbench); vscode.commands.registerCommand('digital-ide.tool.testbench', sim.testbench);
vscode.commands.registerCommand('digital-ide.tool.icarus.simulateFile', sim.Icarus.simulateFile); vscode.commands.registerCommand('digital-ide.tool.icarus.simulateFile', (view: ModuleDataItem) => {
sim.Icarus.simulateFile(view);
});
} }
function registerFunctionCommands(context: vscode.ExtensionContext) { function registerFunctionCommands(context: vscode.ExtensionContext) {
@ -82,10 +85,10 @@ function registerLsp(context: vscode.ExtensionContext) {
// vhdl lsp // vhdl lsp
// vscode.languages.registerDocumentSymbolProvider(vhdlSelector, lspDocSymbol.vhdlDocSymbolProvider); vscode.languages.registerDocumentSymbolProvider(vhdlSelector, lspDocSymbol.vhdlDocSymbolProvider);
// vscode.languages.registerDefinitionProvider(vhdlSelector, lspDefinition.vhdlDefinitionProvider); vscode.languages.registerDefinitionProvider(vhdlSelector, lspDefinition.vhdlDefinitionProvider);
// vscode.languages.registerHoverProvider(vhdlSelector, lspHover.vhdlHoverProvider); vscode.languages.registerHoverProvider(vhdlSelector, lspHover.vhdlHoverProvider);
// vscode.languages.registerCompletionItemProvider(vhdlSelector, lspCompletion.vhdlCompletionProvider); vscode.languages.registerCompletionItemProvider(vhdlSelector, lspCompletion.vhdlCompletionProvider);
// tcl lsp // tcl lsp

View File

@ -110,12 +110,12 @@ class VlogHoverProvider implements vscode.HoverProvider {
* *
*/ */
if (util.isPositionInput(lineText, position.character)) { if (util.isPositionInput(lineText, position.character)) {
console.log('enter position input'); // console.log('enter position input');
const currentInstResult = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule); const currentInstResult = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule);
if (!currentInstResult || !currentInstResult.instModPath) { if (!currentInstResult || !currentInstResult.instModPath) {
return null; return null;
} }
console.log(currentInstResult); // console.log(currentInstResult);
const instParamPromise = util.getInstParamByPosition(currentInstResult, position, targetWord); const instParamPromise = util.getInstParamByPosition(currentInstResult, position, targetWord);
const instPortPromise = util.getInstPortByPosition(currentInstResult, position, targetWord); const instPortPromise = util.getInstPortByPosition(currentInstResult, position, targetWord);
@ -155,7 +155,7 @@ class VlogHoverProvider implements vscode.HoverProvider {
const paramDesc = util.makeParamDesc(paramResult); const paramDesc = util.makeParamDesc(paramResult);
content.appendCodeblock(paramDesc, HdlLangID.Verilog); content.appendCodeblock(paramDesc, HdlLangID.Verilog);
if (paramComment) { if (paramComment) {
content.appendCodeblock(paramComment, HdlLangID.Verilog); content.appendMarkdown(paramComment);
} }
return new vscode.Hover(content); return new vscode.Hover(content);
} }
@ -170,7 +170,7 @@ class VlogHoverProvider implements vscode.HoverProvider {
content.appendCodeblock(portDesc, HdlLangID.Verilog); content.appendCodeblock(portDesc, HdlLangID.Verilog);
if (portComment) { if (portComment) {
content.appendCodeblock(portComment, HdlLangID.Verilog); content.appendMarkdown(portComment);
} }
return new vscode.Hover(content); return new vscode.Hover(content);
} }

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { AbsPath } from '../../../global'; import { AbsPath, LspOutput } from '../../../global';
import { HdlLangID } from '../../../global/enum'; import { HdlLangID } from '../../../global/enum';
import { hdlPath, hdlFile } from '../../../hdlFs'; import { hdlPath, hdlFile } from '../../../hdlFs';
import { Range } from '../../../hdlParser/common'; import { Range } from '../../../hdlParser/common';
@ -126,12 +126,153 @@ function bin2float(bin: string, exp: number, fra: number): number | undefined {
} }
} }
function getFullSymbolInfoVlog(document: vscode.TextDocument, range: Range) {
const comments = [];
const currentLine = range.start.line;
const currentText = document.lineAt(currentLine).text;
// 往上找到第一个非空行
let nearestFloatLine = currentLine - 1;
while (nearestFloatLine >= 0) {
const linetext = document.lineAt(nearestFloatLine).text.trim();
if (linetext.length > 0) {
break;
}
nearestFloatLine --;
}
if (nearestFloatLine >= 0) {
const floatLineText = document.lineAt(nearestFloatLine).text.trim();
// 情况 1.1:上面的单行注释
if (floatLineText.includes('//')) {
const singleLineCommentStartIndex = floatLineText.indexOf('//');
if (singleLineCommentStartIndex === 0) {
const comment = floatLineText.substring(singleLineCommentStartIndex + 2);
if (comment !== undefined && comment.length > 0) {
comments.push(comment);
}
}
}
// 情况 1.2:上面的多行注释
if (floatLineText.includes('*/')) {
const commentEndIndex = floatLineText.indexOf('*/');
if (!floatLineText.includes('/*') || floatLineText.indexOf('/*') === 0) {
let comment = '';
for (let lineno = nearestFloatLine; lineno >= 0; -- lineno) {
const linetext = document.lineAt(lineno).text;
const commentStartIndex = linetext.indexOf('/*');
if (commentStartIndex > -1 && (lineno < nearestFloatLine || commentEndIndex > commentStartIndex)) {
let clearLineText = linetext.substring(commentStartIndex + 2).trim();
if (lineno === nearestFloatLine) {
clearLineText = clearLineText.substring(0, clearLineText.indexOf('*/'));
}
if (clearLineText.startsWith('*')) {
clearLineText = clearLineText.substring(1).trim();
}
if (clearLineText.length > 0) {
comment = clearLineText + '\n\n' + comment;
}
break;
} else {
let clearLineText = linetext.trim();
if (lineno === nearestFloatLine) {
clearLineText = clearLineText.substring(0, clearLineText.indexOf('*/'));
}
if (clearLineText.startsWith('*')) {
clearLineText = clearLineText.substring(1).trim();
}
if (clearLineText.length > 0) {
comment = clearLineText + '\n\n' + comment;
}
}
}
comment = comment.trim();
if (comment.length > 0) {
comments.push(comment);
}
}
}
}
// 情况 2.1:单行注释
if (currentText.includes('//')) {
const singleLineCommentStartIndex = currentText.indexOf('//');
const comment = currentText.substring(singleLineCommentStartIndex + 2);
if (comment !== undefined && comment.length > 0) {
comments.push(comment);
}
}
// 情况 2.2:多行注释
if (currentText.includes('/*')) {
const commentStartIndex = currentText.indexOf('/*');
let comment = '';
for (let lineno = currentLine; lineno < document.lineCount; ++ lineno) {
const linetext = document.lineAt(lineno).text;
const commentEndIndex = linetext.indexOf('*/');
if (commentEndIndex > -1 && (lineno > currentLine || commentEndIndex > commentStartIndex)) {
let clearLineText = linetext.substring(0, commentEndIndex).trim();
if (lineno === currentLine) {
clearLineText = clearLineText.substring(clearLineText.indexOf('/*') + 2).trim();
}
if (clearLineText.startsWith('*')) {
clearLineText = clearLineText.substring(1).trim();
}
comment += clearLineText + '\n';
break;
} else {
let clearLineText = linetext.trim();
if (clearLineText.startsWith('*')) {
clearLineText = clearLineText.substring(1).trim();
}
comment += clearLineText + '\n';
}
}
comment = comment.trim();
if (comment.length > 0) {
comments.push(comment);
}
}
return comments;
}
function getFullSymbolInfoVhdl() {
const comments = [];
}
async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp): Promise<string> { async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp): Promise<string> {
const comments = []; const comments = [];
if (document.languageId !== 'vhdl') {
comments.push(...getFullSymbolInfoVlog(document, range));
let resultComment = '';
for (const c of comments.reverse()) {
resultComment += c.trim() + '\n';
}
return resultComment;
}
let content = ''; let content = '';
let is_b_comment = false; let is_b_comment = false;
let line = range.start.line; let line = range.start.line + 1;
// vscode 的行编号从 0 开始算 // vscode 的行编号从 0 开始算
const firstLine = range.start.line - 1; const firstLine = range.start.line - 1;
@ -139,6 +280,7 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no
while (line) { while (line) {
line --; line --;
content = document.lineAt(line).text; content = document.lineAt(line).text;
LspOutput.report(content);
// 首先判断该行是否是空白 // 首先判断该行是否是空白
if (content.trim().length === 0) { if (content.trim().length === 0) {

View File

@ -9,6 +9,7 @@ import { getSelectItem } from './instance';
import { ToolChainType } from '../../global/enum'; import { ToolChainType } from '../../global/enum';
import { HdlModule } from '../../hdlParser/core'; import { HdlModule } from '../../hdlParser/core';
import { Path } from '../../../resources/hdlParser'; import { Path } from '../../../resources/hdlParser';
import { ModuleDataItem } from '../treeView/tree';
interface SimulateConfig { interface SimulateConfig {
mod : string, // 设置的顶层模块 mod : string, // 设置的顶层模块
@ -84,7 +85,7 @@ class Simulate {
const setting = vscode.workspace.getConfiguration(); const setting = vscode.workspace.getConfiguration();
// make simulation dir // make simulation dir
const defaultSimulationDir = hdlPath.join(opeParam.prjInfo.arch.prjPath, 'simulation', 'icarus'); const defaultSimulationDir = hdlPath.join(opeParam.prjInfo.arch.prjPath, 'icarus');
simConfig.simulationHome = setting.get('digital-ide.function.simulate.simulationHome', ''); simConfig.simulationHome = setting.get('digital-ide.function.simulate.simulationHome', '');
if (!fs.existsSync(simConfig.simulationHome)) { if (!fs.existsSync(simConfig.simulationHome)) {
simConfig.simulationHome = defaultSimulationDir; simConfig.simulationHome = defaultSimulationDir;
@ -357,33 +358,24 @@ class IcarusSimulate extends Simulate {
this.simulateByHdlModule(hdlModule); this.simulateByHdlModule(hdlModule);
} }
public async simulateFile() { public async simulateFile(view: ModuleDataItem) {
const editor = vscode.window.activeTextEditor; if (!view.path) {
if (!editor) { MainOutput.report('module ' + view.name + ' is not a hdlFile', ReportType.Error, true);
return; return;
} }
const uri = editor.document.uri;
const path = hdlPath.toSlash(uri.fsPath);
const currentFile = hdlParam.getHdlFile(path); const currentFile = hdlParam.getHdlFile(view.path);
if (!currentFile) { if (!currentFile) {
MainOutput.report('path ' + path + ' is not a hdlFile', ReportType.Error, true); MainOutput.report('path ' + view.path + ' is not a hdlFile', ReportType.Error, true);
return; return;
} }
const items = getSelectItem(currentFile.getAllHdlModules());
if (items.length) { const targetModule = currentFile.getAllHdlModules().filter(mod => mod.name === view.name)[0];
let selectModule: HdlModule; if (targetModule !== undefined) {
if (items.length === 1) { this.simulateByHdlModule(targetModule);
selectModule = items[0].module; } else {
} else { MainOutput.report('There is no module named ' + view.name + ' in ' + view.path, ReportType.Error, true);
const select = await vscode.window.showQuickPick(items, {placeHolder: 'choose a top module'}); return;
if (select) {
selectModule = select.module;
} else {
return;
}
}
this.simulateByHdlModule(selectModule);
} }
} }
} }
@ -395,8 +387,8 @@ namespace Icarus {
await icarus.simulateModule(hdlModule); await icarus.simulateModule(hdlModule);
} }
export async function simulateFile() { export async function simulateFile(view: ModuleDataItem) {
await icarus.simulateFile(); await icarus.simulateFile(view);
} }
}; };

View File

@ -200,9 +200,18 @@ class ToolTreeProvider extends BaseCommandTreeProvider {
// remove prjPath & .xil // remove prjPath & .xil
const prjPath = opeParam.prjInfo.arch.prjPath; const prjPath = opeParam.prjInfo.arch.prjPath;
const xilFolder = hdlPath.join(workspacePath, '.Xil'); const xilFolder = hdlPath.join(workspacePath, '.Xil');
hdlDir.rmdir(prjPath);
hdlDir.rmdir(xilFolder); if (prjPath !== opeParam.workspacePath) {
hdlDir.rmdir(prjPath);
hdlDir.rmdir(xilFolder);
MainOutput.report("remove dir : " + prjPath);
MainOutput.report("remove dir : " + xilFolder);
} else {
vscode.window.showWarningMessage("arch.prjPath is the same as the workspace path, the clean will delete the project, please check your arch.prjPath!");
}
// move bd * ip // move bd * ip
const plName = opeParam.prjInfo.prjName.PL; const plName = opeParam.prjInfo.prjName.PL;
@ -211,13 +220,16 @@ class ToolTreeProvider extends BaseCommandTreeProvider {
const sourceBdPath = `${workspacePath}/prj/xilinx/${plName}.srcs/sources_1/bd`; const sourceBdPath = `${workspacePath}/prj/xilinx/${plName}.srcs/sources_1/bd`;
hdlDir.mvdir(sourceIpPath, targetPath, true); hdlDir.mvdir(sourceIpPath, targetPath, true);
MainOutput.report("move dir from " + sourceIpPath + " to " + targetPath);
hdlDir.mvdir(sourceBdPath, targetPath, true); hdlDir.mvdir(sourceBdPath, targetPath, true);
MainOutput.report("move dir from " + sourceBdPath + " to " + targetPath);
const ignores = hdlIgnore.getIgnoreFiles(); const ignores = hdlIgnore.getIgnoreFiles();
const strFiles = hdlFile.pickFileRecursive(workspacePath, ignores, p => p.endsWith('.str')); const strFiles = hdlFile.pickFileRecursive(workspacePath, ignores, p => p.endsWith('.str'));
for (const path of strFiles) { for (const path of strFiles) {
hdlFile.removeFile(path); hdlFile.removeFile(path);
MainOutput.report("remove file " + path);
} }
const logFiles = hdlFile.pickFileRecursive(workspacePath, ignores, p => p.endsWith('.log')); const logFiles = hdlFile.pickFileRecursive(workspacePath, ignores, p => p.endsWith('.log'));

View File

@ -14,7 +14,7 @@ interface ModuleDataItem {
icon: string, // 图标 icon: string, // 图标
name: string, // module name name: string, // module name
type: string, type: string,
range: Range | null, range: Range | undefined | null,
path: AbsPath | undefined, // path of the file path: AbsPath | undefined, // path of the file
parent: ModuleDataItem | null // parent file parent: ModuleDataItem | null // parent file
} }
@ -219,12 +219,13 @@ class ModuleTreeProvider implements vscode.TreeDataProvider<ModuleDataItem> {
if (targetModule) { if (targetModule) {
for (const instance of targetModule.getAllInstances()) { for (const instance of targetModule.getAllInstances()) {
// 所有的例化模块都定向到它的定义文件上
const item: ModuleDataItem = { const item: ModuleDataItem = {
icon: 'file', icon: 'file',
type: instance.name, type: instance.name,
name: instance.type, name: instance.type,
range: instance.range, range: instance.module?.range,
path: instance.parentMod.path, path: instance.module?.path,
parent: element parent: element
}; };

View File

@ -9,6 +9,8 @@ import { ToolChainType, LibraryState, XilinxIP,
import { PrjInfoSchema } from './propertySchema'; import { PrjInfoSchema } from './propertySchema';
import assert = require('assert'); import assert = require('assert');
import * as hdlPath from '../hdlFs/path'; import * as hdlPath from '../hdlFs/path';
import { hdlDir } from '../hdlFs';
import { MainOutput } from './outputChannel';
type AbsPath = string; type AbsPath = string;
@ -265,7 +267,9 @@ class PrjInfo implements PrjInfoMeta {
if (fs.existsSync(uniformPath)) { if (fs.existsSync(uniformPath)) {
return uniformPath; return uniformPath;
} else { } else {
vscode.window.showErrorMessage('path ' + uniformPath + ' not exist!'); hdlDir.mkdir(uniformPath);
MainOutput.report("create dir: " + uniformPath);
// vscode.window.showErrorMessage('path ' + uniformPath + ' not exist!');
return undefined; return undefined;
} }
} else { } else {

View File

@ -7,6 +7,7 @@ import { PrjInfo, RawPrjInfo } from '../global/prjInfo';
import { HdlLangID } from '../global/enum'; import { HdlLangID } from '../global/enum';
import { hdlFile, hdlPath } from '../hdlFs'; import { hdlFile, hdlPath } from '../hdlFs';
import { getIconConfig } from '../hdlFs/icons'; import { getIconConfig } from '../hdlFs/icons';
import { getLanguageId } from '../hdlFs/file';
type MissPathType = { path?: string }; type MissPathType = { path?: string };
type LibPickItem = vscode.QuickPickItem & MissPathType; type LibPickItem = vscode.QuickPickItem & MissPathType;
@ -76,14 +77,14 @@ class LibPick {
} }
private getReadmeText(path: AbsPath, fileName: string): string | undefined { private getReadmeText(path: AbsPath, fileName: string): string | undefined {
const mdPath1 = hdlPath.join(path, fileName, 'readme.md'); const allowReadmeFile = ['readme.md', 'README.md', 'readme', 'README', 'readme.txt']
if (fs.existsSync(mdPath1)) { for (const readmeFile of allowReadmeFile) {
return hdlFile.readFile(mdPath1); const mdpath = hdlPath.join(path, fileName, readmeFile);
} if (fs.existsSync(mdpath)) {
const mdPath2 = hdlPath.join(path, fileName, 'README.md'); return hdlFile.readFile(mdpath);
if (fs.existsSync(mdPath2)) { }
return hdlFile.readFile(mdPath2);
} }
return undefined; return undefined;
} }
@ -98,12 +99,30 @@ class LibPick {
for (const fileName of fs.readdirSync(path)) { for (const fileName of fs.readdirSync(path)) {
const filePath = hdlPath.join(path, fileName); const filePath = hdlPath.join(path, fileName);
const themeIcon = this.getPathIcon(filePath); if (hdlFile.isFile(filePath)) {
const label = themeIcon + " " + fileName; const fileLangId = getLanguageId(filePath);
const mdText = this.getReadmeText(path, fileName); if (fileLangId === HdlLangID.Unknown) {
const description = mdText ? mdText : ''; // 不是 hdl 直接跳过
const buttons = [{iconPath: getIconConfig('import'), tooltip: 'import everything in ' + fileName}]; continue;
items.push({label, description, path: filePath, buttons}); }
const themeIcon = this.getPathIcon(filePath);
const label = themeIcon + " " + fileName;
const buttons = [{iconPath: getIconConfig('import'), tooltip: 'import everything in ' + fileName}];
items.push({label, description: '', path: filePath, buttons});
} else if (hdlFile.isDir(filePath)) {
if (['.git', '.github', '.vscode'].includes(fileName)) {
continue;
}
const themeIcon = this.getPathIcon(filePath);
const label = themeIcon + " " + fileName;
// 寻找 fileName 下的 readmefileName 在这里是一个 文件夹
const mdText = this.getReadmeText(path, fileName);
const description = mdText ? mdText : '';
const buttons = [{iconPath: getIconConfig('import'), tooltip: 'import everything in ' + fileName}];
items.push({label, description, path: filePath, buttons});
}
} }
return items; return items;
} }