finish reconstruct of basic function
This commit is contained in:
parent
4fd79de4e4
commit
23ca078e73
92
package.json
92
package.json
@ -142,39 +142,59 @@
|
|||||||
"description": "Select the verilog and systemverilog formatter style."
|
"description": "Select the verilog and systemverilog formatter style."
|
||||||
},
|
},
|
||||||
"function.lsp.formatter.vlog.default.args": {
|
"function.lsp.formatter.vlog.default.args": {
|
||||||
"scope": "window",
|
"scope": "window",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "Add verilog formatter arguments here (like istyle)."
|
"description": "Add verilog formatter arguments here (like istyle)."
|
||||||
},
|
},
|
||||||
"function.lsp.formatter.vhdl.default.keyword-case": {
|
"function.lsp.formatter.vhdl.default.keyword-case": {
|
||||||
"description": "Keyword case",
|
"description": "Keyword case",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "LowerCase",
|
"default": "LowerCase",
|
||||||
"enum": [
|
"enum": [
|
||||||
"LowerCase",
|
"LowerCase",
|
||||||
"UpperCase"
|
"UpperCase"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"function.lsp.formatter.vhdl.default.align-comments": {
|
"function.lsp.formatter.vhdl.default.align-comments": {
|
||||||
"description": "Align comments",
|
"description": "Align comments",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"function.lsp.formatter.vhdl.default.type-name-case": {
|
"function.lsp.formatter.vhdl.default.type-name-case": {
|
||||||
"description": "Type name case",
|
"description": "Type name case",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "LowerCase",
|
"default": "LowerCase",
|
||||||
"enum": [
|
"enum": [
|
||||||
"LowerCase",
|
"LowerCase",
|
||||||
"UpperCase"
|
"UpperCase"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"function.lsp.formatter.vhdl.default.indentation": {
|
"function.lsp.formatter.vhdl.default.indentation": {
|
||||||
"description": "Indentation",
|
"description": "Indentation",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4
|
"default": 4
|
||||||
}
|
},
|
||||||
|
"function.lsp.completion.vlog.autoAddInclude": {
|
||||||
|
"description": "`include \"xxx.v\" will be added to the top of the file automatically",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"function.lsp.completion.vlog.completeWholeInstante": {
|
||||||
|
"description": "complete everything invoking a module needs including paramters and ports",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"function.instantiation.addComment": {
|
||||||
|
"description": "add comment like // ports, // input, // output when doing instantiation, including completion for module invoking",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"function.instantiation.autoNetOutputDeclaration": {
|
||||||
|
"description": "auto declare output type nets in the scope when instantiation happens.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": [
|
"commands": [
|
||||||
@ -385,6 +405,10 @@
|
|||||||
},
|
},
|
||||||
"category": "tool",
|
"category": "tool",
|
||||||
"title": "%digital-ide.fsm.title%"
|
"title": "%digital-ide.fsm.title%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.lsp.tool.insertTextToUri",
|
||||||
|
"title": "%digital-ide.lsp.tool.insertTextToUri.title%"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
@ -797,4 +821,4 @@
|
|||||||
"vscode-textmate": "^9.0.0",
|
"vscode-textmate": "^9.0.0",
|
||||||
"wavedrom": "^2.9.1"
|
"wavedrom": "^2.9.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -35,5 +35,6 @@
|
|||||||
"digital-ide.pl.addFile.title": "add file",
|
"digital-ide.pl.addFile.title": "add file",
|
||||||
"digital-ide.pl.delFile.title": "del file",
|
"digital-ide.pl.delFile.title": "del file",
|
||||||
"digital-ide.netlist.title": "netlist",
|
"digital-ide.netlist.title": "netlist",
|
||||||
"digital-ide.fsm.title": "finite state machine"
|
"digital-ide.fsm.title": "finite state machine",
|
||||||
|
"digital-ide.lsp.tool.insertTextToUri.title": "insert text to uri"
|
||||||
}
|
}
|
@ -35,5 +35,6 @@
|
|||||||
"digital-ide.pl.addFile.title": "添加文件",
|
"digital-ide.pl.addFile.title": "添加文件",
|
||||||
"digital-ide.pl.delFile.title": "d删除文件",
|
"digital-ide.pl.delFile.title": "d删除文件",
|
||||||
"digital-ide.netlist.title": "netlist",
|
"digital-ide.netlist.title": "netlist",
|
||||||
"digital-ide.fsm.title": "有限状态机"
|
"digital-ide.fsm.title": "有限状态机",
|
||||||
|
"digital-ide.lsp.tool.insertTextToUri.title": "插入文本uri"
|
||||||
}
|
}
|
@ -28,12 +28,13 @@
|
|||||||
"digital-ide.hard.gui.title": "打開界面",
|
"digital-ide.hard.gui.title": "打開界面",
|
||||||
"digital-ide.hard.exit.title": "退出當前項目",
|
"digital-ide.hard.exit.title": "退出當前項目",
|
||||||
"digital-ide.pickLibrary.title": "從自定義選擇自由和普遍",
|
"digital-ide.pickLibrary.title": "從自定義選擇自由和普遍",
|
||||||
"digital-ide.pl.setSrcTop.title": "設置為src的文件",
|
"digital-ide.pl.setSrcTop.title": "設置為src的top",
|
||||||
"digital-ide.pl.setSimTop.title": "設置為文件的sim卡",
|
"digital-ide.pl.setSimTop.title": "設置為sim的top",
|
||||||
"digital-ide.pl.addDevice.title": "添加設備",
|
"digital-ide.pl.addDevice.title": "添加device",
|
||||||
"digital-ide.pl.delDevice.title": "德爾設備",
|
"digital-ide.pl.delDevice.title": "刪除device",
|
||||||
"digital-ide.pl.addFile.title": "添加文件",
|
"digital-ide.pl.addFile.title": "添加文件",
|
||||||
"digital-ide.pl.delFile.title": "del文件",
|
"digital-ide.pl.delFile.title": "d刪除文件",
|
||||||
"digital-ide.netlist.title": "網表",
|
"digital-ide.netlist.title": "netlist",
|
||||||
"digital-ide.fsm.title": "有限狀態機"
|
"digital-ide.fsm.title": "有限狀態機",
|
||||||
|
"digital-ide.lsp.tool.insertTextToUri.title": "插入文本uri"
|
||||||
}
|
}
|
2
resources/hdlParser/index.d.ts
vendored
2
resources/hdlParser/index.d.ts
vendored
@ -7,7 +7,7 @@ type Path = AbsPath | RelPath;
|
|||||||
|
|
||||||
interface Fast {
|
interface Fast {
|
||||||
content: RawHdlModule[]
|
content: RawHdlModule[]
|
||||||
languageId: HdlLangID
|
languageId: string
|
||||||
macro: Macro
|
macro: Macro
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,20 +2,25 @@ import * as vscode from 'vscode';
|
|||||||
|
|
||||||
import { opeParam, MainOutput, ReportType } from './global';
|
import { opeParam, MainOutput, ReportType } from './global';
|
||||||
import { hdlParam } from './hdlParser';
|
import { hdlParam } from './hdlParser';
|
||||||
import { prjManage, registerManagerCommands } from './manager';
|
import * as manager from './manager';
|
||||||
import { registerFunctionCommands, registerLsp } from './function';
|
import * as func from './function';
|
||||||
|
import { hdlMonitor } from './monitor';
|
||||||
|
|
||||||
async function registerCommand(context: vscode.ExtensionContext) {
|
async function registerCommand(context: vscode.ExtensionContext) {
|
||||||
registerFunctionCommands(context);
|
manager.registerManagerCommands(context);
|
||||||
registerManagerCommands(context);
|
|
||||||
registerLsp(context);
|
func.registerFunctionCommands(context);
|
||||||
|
func.registerLsp(context);
|
||||||
|
func.registerToolCommands(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launch(context: vscode.ExtensionContext) {
|
async function launch(context: vscode.ExtensionContext) {
|
||||||
await prjManage.initialise(context);
|
await manager.prjManage.initialise(context);
|
||||||
await registerCommand(context);
|
await registerCommand(context);
|
||||||
|
hdlMonitor.start();
|
||||||
|
|
||||||
|
console.log(hdlParam);
|
||||||
|
|
||||||
MainOutput.report('Digital-IDE has launched, Version: 0.3.0');
|
MainOutput.report('Digital-IDE has launched, Version: 0.3.0');
|
||||||
MainOutput.report('OS: ' + opeParam.os);
|
MainOutput.report('OS: ' + opeParam.os);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ class ExportFunctionItem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function registerFileDocExport(context: vscode.ExtensionContext) {
|
function registerFileDocExport(context: vscode.ExtensionContext) {
|
||||||
vscode.commands.registerCommand('digital-ide.hdlDoc.exportFile', () => {
|
vscode.commands.registerCommand('digital-ide.hdlDoc.exportFile', async () => {
|
||||||
const option = {
|
const option = {
|
||||||
placeHolder: 'Select an Export Format'
|
placeHolder: 'Select an Export Format'
|
||||||
};
|
};
|
||||||
@ -35,17 +35,16 @@ function registerFileDocExport(context: vscode.ExtensionContext) {
|
|||||||
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportCurrentFileDocAsPDF),
|
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportCurrentFileDocAsPDF),
|
||||||
new ExportFunctionItem('html', ' html', 'only support light theme', exportCurrentFileDocAsHTML)
|
new ExportFunctionItem('html', ' html', 'only support light theme', exportCurrentFileDocAsHTML)
|
||||||
];
|
];
|
||||||
|
|
||||||
vscode.window.showQuickPick(items, option).then(item => {
|
const item = await vscode.window.showQuickPick(items, option);
|
||||||
if (item) {
|
if (item) {
|
||||||
item.exportFunc();
|
item.exportFunc();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerProjectDocExport(context: vscode.ExtensionContext) {
|
function registerProjectDocExport(context: vscode.ExtensionContext) {
|
||||||
vscode.commands.registerCommand('digital-ide.hdlDoc.exportProject', () => {
|
vscode.commands.registerCommand('digital-ide.hdlDoc.exportProject', async () => {
|
||||||
const option = {
|
const option = {
|
||||||
placeHolder: 'Select an Export Format'
|
placeHolder: 'Select an Export Format'
|
||||||
};
|
};
|
||||||
@ -54,12 +53,11 @@ function registerProjectDocExport(context: vscode.ExtensionContext) {
|
|||||||
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportProjectDocAsPDF),
|
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportProjectDocAsPDF),
|
||||||
new ExportFunctionItem('html', ' html', 'only support light theme', exportProjectDocAsHTML)
|
new ExportFunctionItem('html', ' html', 'only support light theme', exportProjectDocAsHTML)
|
||||||
];
|
];
|
||||||
|
|
||||||
vscode.window.showQuickPick(items, option).then(item => {
|
const item = await vscode.window.showQuickPick(items, option);
|
||||||
if (item) {
|
if (item) {
|
||||||
item.exportFunc();
|
item.exportFunc();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ import * as lspDocSymbol from './lsp/docSymbol';
|
|||||||
import * as lspDefinition from './lsp/definition';
|
import * as lspDefinition from './lsp/definition';
|
||||||
import * as lspHover from './lsp/hover';
|
import * as lspHover from './lsp/hover';
|
||||||
import * as lspFormatter from '../../resources/formatter';
|
import * as lspFormatter from '../../resources/formatter';
|
||||||
|
import * as lspDocSemantic from './lsp/docSemantic';
|
||||||
|
|
||||||
|
import * as tool from './tool';
|
||||||
|
|
||||||
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);
|
||||||
@ -65,11 +68,18 @@ function registerLsp(context: vscode.ExtensionContext) {
|
|||||||
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogMacroCompletionProvider, '`');
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogMacroCompletionProvider, '`');
|
||||||
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogPositionPortProvider, '.');
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogPositionPortProvider, '.');
|
||||||
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogCompletionProvider);
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogCompletionProvider);
|
||||||
// vhdl lsp
|
vscode.languages.registerDocumentSemanticTokensProvider(vlogSelector, lspDocSemantic.vlogDocSenmanticProvider, lspDocSemantic.vlogLegend);
|
||||||
|
|
||||||
|
|
||||||
|
// vhdl lsp
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerToolCommands(context: vscode.ExtensionContext) {
|
||||||
|
vscode.commands.registerCommand('digital-ide.lsp.tool.insertTextToUri', tool.insertTextToUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
registerFunctionCommands,
|
registerFunctionCommands,
|
||||||
registerLsp
|
registerLsp,
|
||||||
|
registerToolCommands
|
||||||
};
|
};
|
@ -4,10 +4,11 @@ import * as fs from 'fs';
|
|||||||
import * as util from '../util';
|
import * as util from '../util';
|
||||||
import { hdlFile, hdlPath } from '../../../hdlFs';
|
import { hdlFile, hdlPath } from '../../../hdlFs';
|
||||||
import { hdlParam, HdlSymbol } from '../../../hdlParser';
|
import { hdlParam, HdlSymbol } from '../../../hdlParser';
|
||||||
import { AbsPath, MainOutput, ReportType } from '../../../global';
|
import { AbsPath, MainOutput, RelPath, ReportType } from '../../../global';
|
||||||
import { Define, Include, RawSymbol } from '../../../hdlParser/common';
|
import { Define, Include, RawSymbol } from '../../../hdlParser/common';
|
||||||
import { HdlInstance, HdlModule } from '../../../hdlParser/core';
|
import { HdlInstance, HdlModule } from '../../../hdlParser/core';
|
||||||
import { vlogKeyword } from '../util/keyword';
|
import { vlogKeyword } from '../util/keyword';
|
||||||
|
import { instanceVlogCode } from '../../sim/instance';
|
||||||
|
|
||||||
class VlogIncludeCompletionProvider implements vscode.CompletionItemProvider {
|
class VlogIncludeCompletionProvider implements vscode.CompletionItemProvider {
|
||||||
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
|
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
|
||||||
@ -176,7 +177,9 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
const filePath = hdlPath.toSlash(document.fileName);
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
|
||||||
// 1. provide keyword
|
// 1. provide keyword
|
||||||
const completions = this.getKeyWordItem();
|
const completions = this.makeKeywordItems();
|
||||||
|
completions.push(...this.makeCompilerKeywordItems());
|
||||||
|
completions.push(...this.makeSystemKeywordItems());
|
||||||
|
|
||||||
const symbolResult = await HdlSymbol.all(filePath);
|
const symbolResult = await HdlSymbol.all(filePath);
|
||||||
if (!symbolResult) {
|
if (!symbolResult) {
|
||||||
@ -199,7 +202,7 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. provide modules
|
// 3. provide modules
|
||||||
const suggestModulesPromise = this.provideModules(filePath, symbolResult.macro.includes);
|
const suggestModulesPromise = this.provideModules(document, position, filePath, symbolResult.macro.includes);
|
||||||
|
|
||||||
// 4. provide params and ports of wrapper module
|
// 4. provide params and ports of wrapper module
|
||||||
const suggestParamsPortsPromise = this.provideParamsPorts(currentModule);
|
const suggestParamsPortsPromise = this.provideParamsPorts(currentModule);
|
||||||
@ -219,7 +222,7 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getKeyWordItem(): vscode.CompletionItem[] {
|
private makeKeywordItems(): vscode.CompletionItem[] {
|
||||||
const vlogKeywordItem = [];
|
const vlogKeywordItem = [];
|
||||||
for (const keyword of vlogKeyword.keys()) {
|
for (const keyword of vlogKeyword.keys()) {
|
||||||
const clItem = this.makekeywordCompletionItem(keyword);
|
const clItem = this.makekeywordCompletionItem(keyword);
|
||||||
@ -229,6 +232,29 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
return vlogKeywordItem;
|
return vlogKeywordItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private makeCompilerKeywordItems(): vscode.CompletionItem[] {
|
||||||
|
const items = [];
|
||||||
|
for (const keyword of vlogKeyword.compilerKeys()) {
|
||||||
|
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
||||||
|
clItem.insertText = new vscode.SnippetString('`' + keyword);
|
||||||
|
clItem.detail = 'compiler directive';
|
||||||
|
items.push(clItem);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeSystemKeywordItems(): vscode.CompletionItem[] {
|
||||||
|
const items = [];
|
||||||
|
for (const keyword of vlogKeyword.systemKeys()) {
|
||||||
|
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Method);
|
||||||
|
clItem.insertText = new vscode.SnippetString('\\$' + keyword + '($1);');
|
||||||
|
clItem.detail = 'system task';
|
||||||
|
items.push(clItem);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private makekeywordCompletionItem(keyword: string): vscode.CompletionItem {
|
private makekeywordCompletionItem(keyword: string): vscode.CompletionItem {
|
||||||
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
||||||
clItem.detail = 'keyword';
|
clItem.detail = 'keyword';
|
||||||
@ -240,12 +266,53 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
return clItem;
|
return clItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async provideModules(filePath: AbsPath, includes: Include[]): Promise<vscode.CompletionItem[]> {
|
private async provideModules(document: vscode.TextDocument, position: vscode.Position, filePath: AbsPath, includes: Include[]): Promise<vscode.CompletionItem[]> {
|
||||||
const suggestModules: vscode.CompletionItem[] = [];
|
const suggestModules: vscode.CompletionItem[] = [];
|
||||||
|
|
||||||
// TODO : add `include xxx automatically
|
const lspVlogConfig = vscode.workspace.getConfiguration('function.lsp.completion.vlog');
|
||||||
for (const module of hdlParam.getAllHdlModules()) {
|
const autoAddInclude: boolean = lspVlogConfig.get('autoAddInclude', true);
|
||||||
|
const completeWholeInstante: boolean = lspVlogConfig.get('completeWholeInstante', true);
|
||||||
|
|
||||||
|
const includePaths = new Set<AbsPath>();
|
||||||
|
let lastIncludeLine = 0;
|
||||||
|
for (const include of includes) {
|
||||||
|
const absIncludePath = hdlPath.rel2abs(filePath, include.path);
|
||||||
|
includePaths.add(absIncludePath);
|
||||||
|
lastIncludeLine = Math.max(include.range.end.line, lastIncludeLine);
|
||||||
|
}
|
||||||
|
const insertPosition = new vscode.Position(lastIncludeLine, 0);
|
||||||
|
const insertRange = new vscode.Range(insertPosition, insertPosition);
|
||||||
|
const fileFolder = hdlPath.resolve(filePath, '..');
|
||||||
|
|
||||||
|
// used only when completeWholeInstante is true
|
||||||
|
let completePrefix = '';
|
||||||
|
if (completeWholeInstante) {
|
||||||
|
const wordRange = document.getWordRangeAtPosition(position);
|
||||||
|
const countStart = wordRange ? wordRange.start.character : position.character;
|
||||||
|
const spaceNumber = Math.floor(countStart / 4) * 4;
|
||||||
|
console.log(wordRange, countStart, spaceNumber);
|
||||||
|
|
||||||
|
completePrefix = ' '.repeat(spaceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (const module of hdlParam.getAllHdlModules()) {
|
||||||
const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
|
const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
|
||||||
|
|
||||||
|
// feature 1 : auto add include path if there's no corresponding include path
|
||||||
|
if (autoAddInclude && !includePaths.has(module.path)) {
|
||||||
|
const relPath: RelPath = hdlPath.relative(fileFolder, module.path);
|
||||||
|
const includeString = '`include "' + relPath + '"\n';
|
||||||
|
const textEdit = new vscode.TextEdit(insertRange, includeString);
|
||||||
|
clItem.additionalTextEdits = [textEdit];
|
||||||
|
}
|
||||||
|
|
||||||
|
// feature 2 : auto complete instance
|
||||||
|
if (completeWholeInstante) {
|
||||||
|
const snippetString = instanceVlogCode(module, '', true);
|
||||||
|
clItem.insertText = new vscode.SnippetString(snippetString);
|
||||||
|
}
|
||||||
|
|
||||||
clItem.detail = 'module';
|
clItem.detail = 'module';
|
||||||
suggestModules.push(clItem);
|
suggestModules.push(clItem);
|
||||||
}
|
}
|
||||||
@ -281,6 +348,7 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
|||||||
for (const symbol of symbols) {
|
for (const symbol of symbols) {
|
||||||
if (symbol.type === 'wire' || symbol.type === 'reg') {
|
if (symbol.type === 'wire' || symbol.type === 'reg') {
|
||||||
const clItem = new vscode.CompletionItem(symbol.name, vscode.CompletionItemKind.Variable);
|
const clItem = new vscode.CompletionItem(symbol.name, vscode.CompletionItemKind.Variable);
|
||||||
|
clItem.sortText = '';
|
||||||
clItem.detail = symbol.type;
|
clItem.detail = symbol.type;
|
||||||
suggestNets.push(clItem);
|
suggestNets.push(clItem);
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,13 @@ class VlogDefinitionProvider implements vscode.DefinitionProvider {
|
|||||||
|
|
||||||
// match `include
|
// match `include
|
||||||
const includeResult = util.matchInclude(document, position, all.macro.includes);
|
const includeResult = util.matchInclude(document, position, all.macro.includes);
|
||||||
|
|
||||||
if (includeResult) {
|
if (includeResult) {
|
||||||
const absPath = hdlPath.rel2abs(filePath, includeResult.name);
|
const absPath = hdlPath.rel2abs(filePath, includeResult.name);
|
||||||
const targetFile = vscode.Uri.file(absPath);
|
const targetFile = vscode.Uri.file(absPath);
|
||||||
const targetPosition = new vscode.Position(0, 0);
|
const targetPosition = new vscode.Position(0, 0);
|
||||||
const targetRange = new vscode.Range(targetPosition, targetPosition);
|
const targetRange = new vscode.Range(targetPosition, targetPosition);
|
||||||
const originSelectionRange = document.getWordRangeAtPosition(position, /[\."_0-9a-zA-Z]+/);
|
const originSelectionRange = document.getWordRangeAtPosition(position, /["\.\\\/_0-9A-Za-z]+/);
|
||||||
const link: vscode.LocationLink = { targetUri: targetFile, targetRange, originSelectionRange };
|
const link: vscode.LocationLink = { targetUri: targetFile, targetRange, originSelectionRange };
|
||||||
return [link];
|
return [link];
|
||||||
}
|
}
|
||||||
@ -142,10 +143,7 @@ class VlogDefinitionProvider implements vscode.DefinitionProvider {
|
|||||||
// match others
|
// match others
|
||||||
const normalResult = util.matchNormalSymbol(targetWord, scopeSymbols.symbols);
|
const normalResult = util.matchNormalSymbol(targetWord, scopeSymbols.symbols);
|
||||||
if (normalResult) {
|
if (normalResult) {
|
||||||
const targetRange = util.transformRange(normalResult.range, -1, 0);
|
const targetRange = util.transformRange(normalResult.range, -1, 0);
|
||||||
|
|
||||||
console.log(targetRange, normalResult);
|
|
||||||
|
|
||||||
const link: vscode.LocationLink = { targetUri: document.uri, targetRange };
|
const link: vscode.LocationLink = { targetUri: document.uri, targetRange };
|
||||||
return [link];
|
return [link];
|
||||||
}
|
}
|
||||||
|
6
src/function/lsp/docSemantic/index.ts
Normal file
6
src/function/lsp/docSemantic/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { vlogDocSenmanticProvider, vlogLegend } from './vlog';
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDocSenmanticProvider,
|
||||||
|
vlogLegend
|
||||||
|
};
|
21
src/function/lsp/docSemantic/vlog.ts
Normal file
21
src/function/lsp/docSemantic/vlog.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { HdlSymbol } from '../../../hdlParser';
|
||||||
|
|
||||||
|
const tokenTypes = ['class', 'interface', 'enum', 'function', 'variable'];
|
||||||
|
const tokenModifiers = ['declaration', 'documentation'];
|
||||||
|
const vlogLegend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);
|
||||||
|
|
||||||
|
class VlogDocSenmanticProvider implements vscode.DocumentSemanticTokensProvider {
|
||||||
|
public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<vscode.SemanticTokens | null | undefined> {
|
||||||
|
const tokensBuilder = new vscode.SemanticTokensBuilder(vlogLegend);
|
||||||
|
return tokensBuilder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vlogDocSenmanticProvider = new VlogDocSenmanticProvider();
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDocSenmanticProvider,
|
||||||
|
vlogLegend
|
||||||
|
};
|
@ -2,7 +2,7 @@ import * as vscode from 'vscode';
|
|||||||
|
|
||||||
import { AllowNull } from '../../../global';
|
import { AllowNull } from '../../../global';
|
||||||
import { HdlSymbol } from '../../../hdlParser';
|
import { HdlSymbol } from '../../../hdlParser';
|
||||||
import { RawSymbol, makeVscodePosition, Range } from '../../../hdlParser/common';
|
import { RawSymbol, Range } from '../../../hdlParser/common';
|
||||||
|
|
||||||
import { positionAfterEqual } from '../util';
|
import { positionAfterEqual } from '../util';
|
||||||
|
|
||||||
|
@ -159,10 +159,7 @@ class VlogHoverProvider implements vscode.HoverProvider {
|
|||||||
if (normalResult) {
|
if (normalResult) {
|
||||||
const normalComment = await util.searchCommentAround(filePath, normalResult.range);
|
const normalComment = await util.searchCommentAround(filePath, normalResult.range);
|
||||||
const normalDesc = util.makeNormalDesc(normalResult);
|
const normalDesc = util.makeNormalDesc(normalResult);
|
||||||
|
|
||||||
console.log(normalResult);
|
|
||||||
|
|
||||||
|
|
||||||
content.appendCodeblock(normalDesc, HdlLangID.Verilog);
|
content.appendCodeblock(normalDesc, HdlLangID.Verilog);
|
||||||
if (normalComment) {
|
if (normalComment) {
|
||||||
content.appendCodeblock(normalComment, HdlLangID.Verilog);
|
content.appendCodeblock(normalComment, HdlLangID.Verilog);
|
||||||
|
@ -123,7 +123,7 @@ function isInComment(document: vscode.TextDocument, position: Position, comments
|
|||||||
|
|
||||||
|
|
||||||
function matchInclude(document: vscode.TextDocument, position: vscode.Position, includes: Include[]) : AllowNull<MatchedSymbol> {
|
function matchInclude(document: vscode.TextDocument, position: vscode.Position, includes: Include[]) : AllowNull<MatchedSymbol> {
|
||||||
const selectFileRange = document.getWordRangeAtPosition(position, /[\._0-9A-Za-z]+/);
|
const selectFileRange = document.getWordRangeAtPosition(position, /[\.\\\/_0-9A-Za-z]+/);
|
||||||
const selectFileName = document.getText(selectFileRange);
|
const selectFileName = document.getText(selectFileRange);
|
||||||
|
|
||||||
if (!includes) {
|
if (!includes) {
|
||||||
@ -318,7 +318,8 @@ function makeParamDesc(param: HdlModuleParam): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeNormalDesc(normal: RawSymbol): string {
|
function makeNormalDesc(normal: RawSymbol): string {
|
||||||
const desc = normal.type + ' ' + normal.width + ' ' + normal.name;
|
const width = normal.width ? normal.width : '';
|
||||||
|
const desc = normal.type + ' ' + width + ' ' + normal.name;
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,19 +2,12 @@ import * as vscode from 'vscode';
|
|||||||
|
|
||||||
|
|
||||||
class Keywords {
|
class Keywords {
|
||||||
keywords: Set<string>;
|
private keywords: Set<string>;
|
||||||
keywordItems: vscode.CompletionItem[];
|
private compilerKeywords: string[]; // start with `
|
||||||
compilerKeywords: string[]; // start with `
|
private systemKeywords: string[]; // start with $
|
||||||
systemKeywords: string[]; // start with $
|
|
||||||
constructor(keywords: string[], compilerKeywords: string[], systemKeywords: string[]) {
|
constructor(keywords: string[], compilerKeywords: string[], systemKeywords: string[]) {
|
||||||
this.keywords = new Set(keywords);
|
this.keywords = new Set(keywords);
|
||||||
const keywordItems = [];
|
const keywordItems = [];
|
||||||
for (const keyword of keywords) {
|
|
||||||
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
|
||||||
clItem.detail = "keyword";
|
|
||||||
keywordItems.push(clItem);
|
|
||||||
}
|
|
||||||
this.keywordItems = keywordItems;
|
|
||||||
this.compilerKeywords = compilerKeywords;
|
this.compilerKeywords = compilerKeywords;
|
||||||
this.systemKeywords = systemKeywords;
|
this.systemKeywords = systemKeywords;
|
||||||
}
|
}
|
||||||
@ -23,6 +16,14 @@ class Keywords {
|
|||||||
return this.keywords;
|
return this.keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public compilerKeys(): string[] {
|
||||||
|
return this.compilerKeywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public systemKeys(): string[] {
|
||||||
|
return this.systemKeywords;
|
||||||
|
}
|
||||||
|
|
||||||
public isKeyword(word: string): boolean {
|
public isKeyword(word: string): boolean {
|
||||||
return this.keywords.has(word);
|
return this.keywords.has(word);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { HdlLangID } from '../../global/enum';
|
import { HdlLangID } from '../../global/enum';
|
||||||
import { hdlParam } from '../../hdlParser';
|
import { hdlParam } from '../../hdlParser';
|
||||||
import { HdlModulePort, HdlModuleParam } from '../../hdlParser/common';
|
import { HdlModulePort, HdlModuleParam, HdlModulePortType } from '../../hdlParser/common';
|
||||||
import { HdlModule } from '../../hdlParser/core';
|
import { HdlModule } from '../../hdlParser/core';
|
||||||
|
|
||||||
class ModuleInfoItem {
|
class ModuleInfoItem {
|
||||||
@ -28,23 +28,33 @@ class ModuleInfoItem {
|
|||||||
* @description verilog模式下生成整个例化的内容
|
* @description verilog模式下生成整个例化的内容
|
||||||
* @param module 模块信息
|
* @param module 模块信息
|
||||||
*/
|
*/
|
||||||
function instanceVlogCode(module: HdlModule) {
|
function instanceVlogCode(module: HdlModule, prefix: string = '', returnSnippetString: boolean = false): string {
|
||||||
let vlogPortStr = vlogPort(module.ports);
|
const instantiationConfig = vscode.workspace.getConfiguration('function.instantiation');
|
||||||
let vlogParamStr = vlogParam(module.params);
|
const needComment = instantiationConfig.get('addComment', true);
|
||||||
|
const autoNetOutputDeclaration = instantiationConfig.get('autoNetOutputDeclaration', true);
|
||||||
|
|
||||||
let instContent = '';
|
const content = new vscode.SnippetString();
|
||||||
instContent += vlogPortStr.wireStr;
|
|
||||||
instContent += module.name + ' ';
|
|
||||||
|
|
||||||
if (vlogParamStr !== '') {
|
// make net declaration if needed
|
||||||
instContent += `#(\n${vlogParamStr})\n`;
|
if (autoNetOutputDeclaration) {
|
||||||
|
const netDeclarationString = makeNetOutputDeclaration(module.ports, prefix, needComment);
|
||||||
|
if (netDeclarationString) {
|
||||||
|
content.appendText(netDeclarationString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instContent += `u_${module.name}(\n`;
|
content.appendText(prefix + module.name + ' ');
|
||||||
instContent += vlogPortStr.portStr;
|
if (returnSnippetString) {
|
||||||
instContent += ');\n';
|
content.appendPlaceholder('u_' + module.name);
|
||||||
|
} else {
|
||||||
|
content.appendText('u_' + module.name);
|
||||||
|
}
|
||||||
|
|
||||||
return instContent;
|
makeVlogParamAssignments(content, module.params, prefix, returnSnippetString, needComment);
|
||||||
|
makeVlogPortAssignments(content, module.ports, prefix, returnSnippetString, needComment);
|
||||||
|
|
||||||
|
const instanceString = content.value;
|
||||||
|
return instanceString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,69 +77,95 @@ function instanceVhdlCode(module: HdlModule) {
|
|||||||
return instContent;
|
return instContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeNetOutputDeclaration(ports: HdlModulePort[], prefix: string, needComment: boolean): string | null {
|
||||||
|
const maxWidthLength = Math.max(...ports.map(p => p.width.length));
|
||||||
|
|
||||||
|
let netOutputDeclaration = prefix + (needComment ? '// outports wire\n' : '');
|
||||||
|
let haveOutput = false;
|
||||||
|
for (const port of ports) {
|
||||||
|
if (port.type === HdlModulePortType.Output) {
|
||||||
|
haveOutput = true;
|
||||||
|
let portWidth = port.width ? port.width : '';
|
||||||
|
portWidth += ' '.repeat(maxWidthLength - portWidth.length + 1);
|
||||||
|
const netDeclaration = prefix + `wire ${portWidth}\t${port.name};\n`;
|
||||||
|
netOutputDeclaration += netDeclaration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveOutput) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
netOutputDeclaration += '\n';
|
||||||
|
return netOutputDeclaration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description verilog模式下对端口信息生成要例化的内容
|
* @description verilog模式下对端口信息生成要例化的内容
|
||||||
* @param ports 端口信息列表
|
* @param ports 端口信息列表
|
||||||
*/
|
*/
|
||||||
function vlogPort(ports: HdlModulePort[]) : { wireStr: string, portStr: string} {
|
function makeVlogPortAssignments(content: vscode.SnippetString, ports: HdlModulePort[], prefix: string = '', returnSnippetString: boolean, needComment: boolean) {
|
||||||
let nmax = getlmax(ports, 'name');
|
if (ports.length === 0) {
|
||||||
let wmax = getlmax(ports, 'width');
|
content.appendText('();');
|
||||||
|
return;
|
||||||
let portStr = `\t// ports\n`;
|
|
||||||
let wireStr = '// outports wire\n';
|
|
||||||
for (let i = 0; i < ports.length; i++) {
|
|
||||||
const port = ports[i];
|
|
||||||
|
|
||||||
if (port.type === 'output') {
|
|
||||||
let width = port.width;
|
|
||||||
let wpadding = wmax - width.length + 1;
|
|
||||||
width += ' '.repeat(wpadding);
|
|
||||||
// TODO: vhdl type
|
|
||||||
wireStr += `wire ${width}\t${port.name};\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = port.name;
|
|
||||||
let npadding = nmax - name.length + 1;
|
|
||||||
name += ' '.repeat(npadding);
|
|
||||||
portStr += `\t.${name}\t( ${name} )`;
|
|
||||||
if (i !== ports.length - 1) {
|
|
||||||
portStr += ',';
|
|
||||||
}
|
|
||||||
portStr += '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { wireStr, portStr };
|
|
||||||
|
|
||||||
|
const maxNameLength = Math.max(...ports.map(p => p.name.length));
|
||||||
|
|
||||||
|
content.appendText('(\n');
|
||||||
|
|
||||||
|
for (let i = 0; i < ports.length; ++ i) {
|
||||||
|
const port = ports[i];
|
||||||
|
const paddingName = port.name + ' '.repeat(maxNameLength - port.name.length + 1);
|
||||||
|
|
||||||
|
content.appendText(prefix + '\t.' + paddingName + '\t( ');
|
||||||
|
if (returnSnippetString) {
|
||||||
|
content.appendPlaceholder(port.name);
|
||||||
|
} else {
|
||||||
|
content.appendText(port.name);
|
||||||
|
}
|
||||||
|
content.appendText(' '.repeat(maxNameLength - port.name.length + 1) + ' )');
|
||||||
|
if (i < ports.length - 1) {
|
||||||
|
content.appendText(',');
|
||||||
|
}
|
||||||
|
content.appendText('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
content.appendText(prefix + ');\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description verilog模式下对参数信息生成要例化的内容
|
* @description verilog模式下对参数信息生成要例化的内容
|
||||||
* @param params 参数信息列表
|
* @param params 参数信息列表
|
||||||
*/
|
*/
|
||||||
function vlogParam(params: HdlModuleParam[]): string {
|
function makeVlogParamAssignments(content: vscode.SnippetString, params: HdlModuleParam[], prefix: string = '', returnSnippetString: boolean, needComment: boolean) {
|
||||||
let paramStr = '';
|
if (params.length === 0) {
|
||||||
let nmax = getlmax(params, 'name');
|
return;
|
||||||
let imax = getlmax(params, 'init');
|
|
||||||
|
|
||||||
// .NAME ( INIT ),
|
|
||||||
for (let i = 0; i < params.length; i++) {
|
|
||||||
let name = params[i].name;
|
|
||||||
let init = params[i].init;
|
|
||||||
|
|
||||||
let namePadding = nmax - name.length + 1;
|
|
||||||
let initPadding = imax - init.length + 1;
|
|
||||||
|
|
||||||
name +=' '.repeat(namePadding);
|
|
||||||
init +=' '.repeat(initPadding);
|
|
||||||
|
|
||||||
paramStr += `\t.${name}\t( ${init} )`;
|
|
||||||
if (i !== (params.length - 1)) {
|
|
||||||
paramStr += ',';
|
|
||||||
paramStr += '\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return paramStr;
|
const maxNameLength = Math.max(...params.map(p => p.name.length));
|
||||||
|
const maxInitLength = Math.max(...params.map(p => p.init.length));
|
||||||
|
|
||||||
|
content.appendText('#(\n');
|
||||||
|
|
||||||
|
// .NAME ( INIT ),
|
||||||
|
for (let i = 0; i < params.length; ++ i) {
|
||||||
|
const param = params[i];
|
||||||
|
const paddingName = param.name + ' '.repeat(maxNameLength - param.name.length + 1);
|
||||||
|
content.appendText(prefix + '\t.' + paddingName + '\t( ');
|
||||||
|
if (returnSnippetString) {
|
||||||
|
content.appendPlaceholder(param.init);
|
||||||
|
} else {
|
||||||
|
content.appendText(param.init);
|
||||||
|
}
|
||||||
|
content.appendText(' '.repeat(maxInitLength - param.init.length + 1) + ' )');
|
||||||
|
if (i < params.length - 1) {
|
||||||
|
content.appendText(',');
|
||||||
|
}
|
||||||
|
content.appendText('\n');
|
||||||
|
}
|
||||||
|
content.appendText(prefix + ')\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,7 +285,7 @@ async function selectModuleFromAll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function instanceByLangID(module: HdlModule): string {
|
function instanceByLangID(module: HdlModule): string {
|
||||||
switch (module.languageId) {
|
switch (module.languageId) {
|
||||||
case HdlLangID.Verilog: return instanceVlogCode(module);
|
case HdlLangID.Verilog: return instanceVlogCode(module);
|
||||||
case HdlLangID.Vhdl: return instanceVhdlCode(module);
|
case HdlLangID.Vhdl: return instanceVhdlCode(module);
|
||||||
@ -260,9 +296,11 @@ function instanceByLangID(module: HdlModule): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function instantiation() {
|
async function instantiation() {
|
||||||
const module = await selectModuleFromAll();
|
const module = await selectModuleFromAll();
|
||||||
if (module) {
|
if (module) {
|
||||||
const code = instanceByLangID(module);
|
console.log(module);
|
||||||
|
|
||||||
|
const code = instanceByLangID(module);
|
||||||
const editor = vscode.window.activeTextEditor;
|
const editor = vscode.window.activeTextEditor;
|
||||||
if (editor) {
|
if (editor) {
|
||||||
selectInsert(code, editor);
|
selectInsert(code, editor);
|
||||||
@ -271,6 +309,7 @@ async function instantiation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
instanceVlogCode,
|
||||||
instantiation,
|
instantiation,
|
||||||
instanceByLangID,
|
instanceByLangID,
|
||||||
getSelectItem
|
getSelectItem
|
||||||
|
@ -62,6 +62,8 @@ async function testbench() {
|
|||||||
if (!hdlFile.isHDLFile(path)) {
|
if (!hdlFile.isHDLFile(path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log(path);
|
||||||
|
|
||||||
const currentHdlFile = hdlParam.getHdlFile(path);
|
const currentHdlFile = hdlParam.getHdlFile(path);
|
||||||
if (!currentHdlFile) {
|
if (!currentHdlFile) {
|
||||||
vscode.window.showErrorMessage('There is no hdlFile respect to ' + path);
|
vscode.window.showErrorMessage('There is no hdlFile respect to ' + path);
|
||||||
|
18
src/function/tool.ts
Normal file
18
src/function/tool.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
async function insertTextToUri(uri: vscode.Uri, text: string, position?: vscode.Position) {
|
||||||
|
if (!position) {
|
||||||
|
position = new vscode.Position(0, 0);
|
||||||
|
}
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor) {
|
||||||
|
const edit = new vscode.WorkspaceEdit();
|
||||||
|
edit.insert(uri, position, text);
|
||||||
|
vscode.workspace.applyEdit(edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
insertTextToUri
|
||||||
|
};
|
@ -21,7 +21,7 @@ function openFileByUri(path: string, range: Range) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshArchTree(element: ModuleDataItem) {
|
function refreshArchTree(element?: ModuleDataItem) {
|
||||||
// TODO : diff and optimize
|
// TODO : diff and optimize
|
||||||
moduleTreeProvider.refresh(element);
|
moduleTreeProvider.refresh(element);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
import { Arch, PrjInfo, RawPrjInfo, resolve, toSlash } from './prjInfo';
|
import { Arch, PrjInfo, RawPrjInfo, resolve } from './prjInfo';
|
||||||
|
|
||||||
type AbsPath = string;
|
type AbsPath = string;
|
||||||
type RelPath = string;
|
type RelPath = string;
|
||||||
@ -70,14 +70,23 @@ class OpeParam {
|
|||||||
return this._prjInfo;
|
return this._prjInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path of property.json
|
||||||
|
*/
|
||||||
public get propertyJsonPath(): AbsPath {
|
public get propertyJsonPath(): AbsPath {
|
||||||
return this._propertyJsonPath;
|
return this._propertyJsonPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path of property-schema.json
|
||||||
|
*/
|
||||||
public get propertySchemaPath() : AbsPath {
|
public get propertySchemaPath() : AbsPath {
|
||||||
return this._propertySchemaPath;
|
return this._propertySchemaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path of property-init.json
|
||||||
|
*/
|
||||||
public get propertyInitPath() : AbsPath {
|
public get propertyInitPath() : AbsPath {
|
||||||
return this._propertyInitPath;
|
return this._propertyInitPath;
|
||||||
}
|
}
|
||||||
@ -156,19 +165,16 @@ class OpeParam {
|
|||||||
* get User's property.json
|
* get User's property.json
|
||||||
*/
|
*/
|
||||||
public getUserPrjInfo(): PrjInfo {
|
public getUserPrjInfo(): PrjInfo {
|
||||||
const propertyJsonPath = this.propertyJsonPath;
|
|
||||||
const userPrjInfo = new PrjInfo();
|
const userPrjInfo = new PrjInfo();
|
||||||
if (fs.existsSync(propertyJsonPath)) {
|
const rawPrjInfo = this.getRawUserPrjInfo();
|
||||||
const rawPrjInfo = readJSON(propertyJsonPath);
|
userPrjInfo.merge(rawPrjInfo);
|
||||||
userPrjInfo.merge(rawPrjInfo);
|
|
||||||
} else {
|
|
||||||
// use default config instead
|
|
||||||
const rawPrjInfo = readJSON(this.propertyInitPath);
|
|
||||||
userPrjInfo.merge(rawPrjInfo);
|
|
||||||
}
|
|
||||||
return userPrjInfo;
|
return userPrjInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get content from property.json (disk IO)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
public getRawUserPrjInfo(): RawPrjInfo {
|
public getRawUserPrjInfo(): RawPrjInfo {
|
||||||
const propertyJsonPath = this.propertyJsonPath;
|
const propertyJsonPath = this.propertyJsonPath;
|
||||||
if (fs.existsSync(propertyJsonPath)) {
|
if (fs.existsSync(propertyJsonPath)) {
|
||||||
|
@ -203,7 +203,7 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
*/
|
*/
|
||||||
public uniformisePath(path: AbsPath): AbsPath {
|
public uniformisePath(path: AbsPath): AbsPath {
|
||||||
const slashPath = toSlash(path);
|
const slashPath = toSlash(path);
|
||||||
const replacedPath = this.replacePathToken(path);
|
const replacedPath = this.replacePathToken(slashPath);
|
||||||
return replacedPath;
|
return replacedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
public updateToolChain(toolChain?: ToolChainType) {
|
public updateToolChain(toolChain?: ToolChainType) {
|
||||||
if (toolChain) {
|
if (toolChain) {
|
||||||
if (!validToolChainType(toolChain)) {
|
if (!validToolChainType(toolChain)) {
|
||||||
vscode.window.showErrorMessage('expect toolChain to be "xilinx"');
|
vscode.window.showErrorMessage('expect toolChain to be "xilinx", "intel", "custom"');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._toolChain = toolChain;
|
this._toolChain = toolChain;
|
||||||
@ -250,7 +250,7 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
public updatePathWisely<T extends string>(obj: Record<T, AbsPath | AbsPath[]>,
|
public updatePathWisely<T extends string>(obj: Record<T, AbsPath | AbsPath[]>,
|
||||||
attr: T,
|
attr: T,
|
||||||
path?: Path | Path[],
|
path?: Path | Path[],
|
||||||
root?: AbsPath) {
|
root?: AbsPath) {
|
||||||
if (path) {
|
if (path) {
|
||||||
if (path instanceof Array) {
|
if (path instanceof Array) {
|
||||||
const actualPaths = [];
|
const actualPaths = [];
|
||||||
@ -267,6 +267,8 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
obj[attr] = actualPath;
|
obj[attr] = actualPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
obj[attr] = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +337,7 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
private setDefaultValue<T extends string, K>(obj: Record<T, K>,
|
private setDefaultValue<T extends string, K>(obj: Record<T, K>,
|
||||||
attr: T,
|
attr: T,
|
||||||
defaultValue: K) {
|
defaultValue: K) {
|
||||||
const value: K = obj[attr];
|
const value: K = obj[attr];
|
||||||
let isNull = !Boolean(value);
|
let isNull = !Boolean(value);
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
isNull ||= value === 'none';
|
isNull ||= value === 'none';
|
||||||
@ -353,7 +355,6 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
|
|
||||||
public updateArch(arch?: Arch) {
|
public updateArch(arch?: Arch) {
|
||||||
const workspacePath = this._workspacePath;
|
const workspacePath = this._workspacePath;
|
||||||
|
|
||||||
if (arch) {
|
if (arch) {
|
||||||
this.updatePathWisely(this.arch, 'prjPath', arch.prjPath);
|
this.updatePathWisely(this.arch, 'prjPath', arch.prjPath);
|
||||||
if (arch.hardware) {
|
if (arch.hardware) {
|
||||||
@ -381,10 +382,10 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
this.arch.software.src = join(softwarePath, 'src');
|
this.arch.software.src = join(softwarePath, 'src');
|
||||||
this.arch.software.data = join(softwarePath, 'data');
|
this.arch.software.data = join(softwarePath, 'data');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if path is '', set as workspace
|
// // if path is '', set as workspace
|
||||||
this.setDefaultValue(this.arch.hardware, 'src', workspacePath);
|
this.setDefaultValue(this.arch.hardware, 'src', workspacePath);
|
||||||
this.setDefaultValue(this.arch.hardware, 'sim', workspacePath);
|
this.setDefaultValue(this.arch.hardware, 'sim', this.arch.hardware.src);
|
||||||
this.setDefaultValue(this.arch.hardware, 'data', workspacePath);
|
this.setDefaultValue(this.arch.hardware, 'data', workspacePath);
|
||||||
this.setDefaultValue(this.arch.software, 'src', workspacePath);
|
this.setDefaultValue(this.arch.software, 'src', workspacePath);
|
||||||
this.setDefaultValue(this.arch.software, 'data', workspacePath);
|
this.setDefaultValue(this.arch.software, 'data', workspacePath);
|
||||||
@ -454,7 +455,7 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
* reserve the value that not covered in rawPrjInfo
|
* reserve the value that not covered in rawPrjInfo
|
||||||
* @param rawPrjInfo
|
* @param rawPrjInfo
|
||||||
*/
|
*/
|
||||||
public merge(rawPrjInfo: RawPrjInfo) {
|
public merge(rawPrjInfo: RawPrjInfo) {
|
||||||
this.updateToolChain(rawPrjInfo.toolChain);
|
this.updateToolChain(rawPrjInfo.toolChain);
|
||||||
this.updatePrjName(rawPrjInfo.prjName);
|
this.updatePrjName(rawPrjInfo.prjName);
|
||||||
this.updateIP_REPO(rawPrjInfo.IP_REPO);
|
this.updateIP_REPO(rawPrjInfo.IP_REPO);
|
||||||
@ -491,6 +492,24 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
return libPath;
|
return libPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get hardwareSimPath(): AbsPath {
|
||||||
|
const simPath = this._arch.hardware.sim;
|
||||||
|
if (fspath.isAbsolute(simPath)) {
|
||||||
|
return simPath;
|
||||||
|
}
|
||||||
|
const workspace = this._workspacePath;
|
||||||
|
return hdlPath.join(workspace, simPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hardwareSrcPath(): AbsPath {
|
||||||
|
const srcPath = this._arch.hardware.src;
|
||||||
|
if (fspath.isAbsolute(srcPath)) {
|
||||||
|
return srcPath;
|
||||||
|
}
|
||||||
|
const workspace = this._workspacePath;
|
||||||
|
return hdlPath.join(workspace, srcPath);
|
||||||
|
}
|
||||||
|
|
||||||
public json(): RawPrjInfo {
|
public json(): RawPrjInfo {
|
||||||
return {
|
return {
|
||||||
toolChain: this._toolChain,
|
toolChain: this._toolChain,
|
||||||
@ -505,9 +524,6 @@ class PrjInfo implements PrjInfoMeta {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PrjInfo,
|
PrjInfo,
|
||||||
PrjInfoDefaults,
|
PrjInfoDefaults,
|
||||||
|
@ -16,7 +16,26 @@ class PathSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tell if two set are element-wise equal
|
||||||
|
* @param setA
|
||||||
|
* @param setB
|
||||||
|
*/
|
||||||
|
function isSameSet<T>(setA: Set<T>, setB: Set<T>): boolean {
|
||||||
|
if (setA.size !== setB.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const el of setB) {
|
||||||
|
if (!setA.has(el)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PathSet
|
PathSet,
|
||||||
|
isSameSet
|
||||||
};
|
};
|
@ -65,11 +65,11 @@ function isSystemVerilogFile(path: AbsPath): boolean {
|
|||||||
return systemVerilogExts.includes(ext);
|
return systemVerilogExts.includes(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isHDLFile(path: AbsPath): boolean {
|
function isHDLFile(path: AbsPath): boolean {
|
||||||
if (!isFile(path)) {
|
if (!isFile(path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const ext = hdlPath.extname(path, false);
|
const ext = hdlPath.extname(path, false);
|
||||||
return hdlExts.includes(ext);
|
return hdlExts.includes(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,13 +96,13 @@ function pickFileRecursive(path: AbsPath | AbsPath[] | Set<AbsPath>, ignores?: A
|
|||||||
|
|
||||||
const hdlFiles = [];
|
const hdlFiles = [];
|
||||||
for (const file of fs.readdirSync(path)) {
|
for (const file of fs.readdirSync(path)) {
|
||||||
const filePath = hdlPath.join(path, file);
|
const filePath = hdlPath.join(path, file);
|
||||||
if (isDir(filePath)) {
|
if (isDir(filePath)) {
|
||||||
const subHdlFiles = pickFileRecursive(filePath, ignores);
|
const subHdlFiles = pickFileRecursive(filePath, ignores, condition);
|
||||||
if (subHdlFiles.length > 0) {
|
if (subHdlFiles.length > 0) {
|
||||||
hdlFiles.push(...subHdlFiles);
|
hdlFiles.push(...subHdlFiles);
|
||||||
}
|
}
|
||||||
} else if (!condition || condition(filePath)) {
|
} else if (!condition || condition(filePath)) {
|
||||||
hdlFiles.push(filePath);
|
hdlFiles.push(filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,9 +178,7 @@ function writeFile(path: AbsPath, content: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readJSON(path: AbsPath): object {
|
function readJSON(path: AbsPath): object {
|
||||||
try {
|
try {
|
||||||
console.log(path);
|
|
||||||
|
|
||||||
const context = fs.readFileSync(path, 'utf-8');
|
const context = fs.readFileSync(path, 'utf-8');
|
||||||
return JSON.parse(context);
|
return JSON.parse(context);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -26,6 +26,15 @@ function rel2abs(curPath: AbsPath, relPath: RelPath): AbsPath {
|
|||||||
return toSlash(absPath);
|
return toSlash(absPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function relative(from: AbsPath, to: AbsPath): RelPath {
|
||||||
|
let rel = fspath.relative(from, to);
|
||||||
|
if (!rel.startsWith('.') && !rel.startsWith('./')) {
|
||||||
|
rel = './' + rel;
|
||||||
|
}
|
||||||
|
return toSlash(rel);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cat paths with '/'
|
* cat paths with '/'
|
||||||
* @param paths
|
* @param paths
|
||||||
@ -87,6 +96,7 @@ function exist(path: AbsPath | undefined): boolean {
|
|||||||
export {
|
export {
|
||||||
toSlash,
|
toSlash,
|
||||||
rel2abs,
|
rel2abs,
|
||||||
|
relative,
|
||||||
join,
|
join,
|
||||||
resolve,
|
resolve,
|
||||||
filename,
|
filename,
|
||||||
|
@ -25,7 +25,7 @@ enum HdlModulePortType {
|
|||||||
Inout = 'inout',
|
Inout = 'inout',
|
||||||
Output = 'output',
|
Output = 'output',
|
||||||
Input = 'input',
|
Input = 'input',
|
||||||
Unknown = 'Unknown'
|
Unknown = 'unknown'
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HdlModuleParamType {LocalParam, Parameter, Unknown};
|
enum HdlModuleParamType {LocalParam, Parameter, Unknown};
|
||||||
|
@ -11,7 +11,7 @@ class HdlParam {
|
|||||||
private readonly srcTopModules : Set<HdlModule> = new Set<HdlModule>();
|
private readonly srcTopModules : Set<HdlModule> = new Set<HdlModule>();
|
||||||
private readonly simTopModules : Set<HdlModule> = new Set<HdlModule>();
|
private readonly simTopModules : Set<HdlModule> = new Set<HdlModule>();
|
||||||
private readonly pathToHdlFiles : Map<AbsPath, HdlFile> = new Map<AbsPath, HdlFile>();
|
private readonly pathToHdlFiles : Map<AbsPath, HdlFile> = new Map<AbsPath, HdlFile>();
|
||||||
private readonly modules : Set<HdlModule> = new Set<HdlModule>();
|
public readonly modules : Set<HdlModule> = new Set<HdlModule>();
|
||||||
private readonly unhandleInstances : Set<HdlInstance> = new Set<HdlInstance>();
|
private readonly unhandleInstances : Set<HdlInstance> = new Set<HdlInstance>();
|
||||||
|
|
||||||
public hasHdlFile(path: AbsPath): boolean {
|
public hasHdlFile(path: AbsPath): boolean {
|
||||||
@ -34,11 +34,34 @@ class HdlParam {
|
|||||||
return hdlFiles;
|
return hdlFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used only in initialization stage
|
||||||
|
* @param hdlFile
|
||||||
|
*/
|
||||||
public addHdlFile(hdlFile: HdlFile) {
|
public addHdlFile(hdlFile: HdlFile) {
|
||||||
const path = hdlFile.path;
|
const path = hdlFile.path;
|
||||||
this.pathToHdlFiles.set(path, hdlFile);
|
this.pathToHdlFiles.set(path, hdlFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a file by path and create context
|
||||||
|
* @param path absolute path of the file to be added
|
||||||
|
*/
|
||||||
|
public async addHdlPath(path: AbsPath) {
|
||||||
|
path = hdlPath.toSlash(path);
|
||||||
|
await this.initHdlFiles([path]);
|
||||||
|
const hdlFile = this.getHdlFile(path);
|
||||||
|
if (!hdlFile) {
|
||||||
|
MainOutput.report('error happen when we attempt to add file by path: ' + path, ReportType.Error);
|
||||||
|
} else {
|
||||||
|
hdlFile.makeInstance();
|
||||||
|
// when a new file is added, retry the solution of dependency
|
||||||
|
for (const hdlModule of hdlFile.getAllHdlModules()) {
|
||||||
|
hdlModule.solveUnhandleInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public hasHdlModule(path: AbsPath | undefined, name: string): boolean {
|
public hasHdlModule(path: AbsPath | undefined, name: string): boolean {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return false;
|
return false;
|
||||||
@ -184,12 +207,28 @@ class HdlParam {
|
|||||||
this.unhandleInstances.delete(inst);
|
this.unhandleInstances.delete(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vlog -> HdlLangID.Verilog
|
||||||
|
* svlog -> HdlLangID.SystemVerilog
|
||||||
|
* vhdl -> HdlLangID.Vhdl
|
||||||
|
* @param langID
|
||||||
|
*/
|
||||||
|
private alignLanguageId(langID: string) : HdlLangID {
|
||||||
|
switch (langID) {
|
||||||
|
case 'vhdl': return HdlLangID.Vhdl;
|
||||||
|
case 'vlog': return HdlLangID.Verilog;
|
||||||
|
case 'svlog': return HdlLangID.SystemVerilog;
|
||||||
|
default: return HdlLangID.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async doHdlFast(path: AbsPath) {
|
private async doHdlFast(path: AbsPath) {
|
||||||
try {
|
try {
|
||||||
const fast = await HdlSymbol.fast(path);
|
const fast = await HdlSymbol.fast(path);
|
||||||
if (fast) {
|
if (fast) {
|
||||||
|
const languageId = this.alignLanguageId(fast.languageId);
|
||||||
new HdlFile(path,
|
new HdlFile(path,
|
||||||
fast.languageId,
|
languageId,
|
||||||
fast.macro,
|
fast.macro,
|
||||||
fast.content);
|
fast.content);
|
||||||
}
|
}
|
||||||
@ -254,6 +293,18 @@ class HdlParam {
|
|||||||
}
|
}
|
||||||
return moduleFiles;
|
return moduleFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public deleteHdlFile(path: AbsPath) {
|
||||||
|
path = hdlPath.toSlash(path);
|
||||||
|
const moduleFile = this.getHdlFile(path);
|
||||||
|
if (moduleFile) {
|
||||||
|
for (const name of moduleFile.getAllModuleNames()) {
|
||||||
|
moduleFile.deleteHdlModule(name);
|
||||||
|
}
|
||||||
|
this.pathToHdlFiles.delete(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const hdlParam = new HdlParam();
|
const hdlParam = new HdlParam();
|
||||||
@ -324,6 +375,13 @@ class HdlInstance {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public update(newInstance: common.RawHdlInstance) {
|
||||||
|
this.type = newInstance.type;
|
||||||
|
this.range = newInstance.range;
|
||||||
|
this.instparams = newInstance.instparams;
|
||||||
|
this.instports = newInstance.instports;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HdlModule {
|
class HdlModule {
|
||||||
@ -348,22 +406,10 @@ class HdlModule {
|
|||||||
this.file = file;
|
this.file = file;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.range = range;
|
this.range = range;
|
||||||
this.params = params;
|
this.params = params ? params : [];
|
||||||
this.ports = ports;
|
this.ports = ports ? ports : [];
|
||||||
|
|
||||||
if (!this.params) {
|
|
||||||
this.params = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.ports) {
|
|
||||||
this.ports = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// make instance
|
|
||||||
this.rawInstances = instances;
|
this.rawInstances = instances;
|
||||||
if (!this.rawInstances) {
|
|
||||||
this.rawInstances = [];
|
|
||||||
}
|
|
||||||
this.nameToInstances = new Map<string, HdlInstance>();
|
this.nameToInstances = new Map<string, HdlInstance>();
|
||||||
|
|
||||||
// add in hdlParam data structure
|
// add in hdlParam data structure
|
||||||
@ -431,14 +477,13 @@ class HdlModule {
|
|||||||
return hdlInstance;
|
return hdlInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public makeNameToInstances() {
|
public makeNameToInstances() {
|
||||||
|
if (this.rawInstances !== undefined) {
|
||||||
if (this.rawInstances) {
|
|
||||||
this.nameToInstances.clear();
|
this.nameToInstances.clear();
|
||||||
for (const inst of this.rawInstances) {
|
for (const inst of this.rawInstances) {
|
||||||
this.createHdlInstance(inst);
|
this.createHdlInstance(inst);
|
||||||
}
|
}
|
||||||
this.rawInstances = undefined;
|
// this.rawInstances = undefined;
|
||||||
} else {
|
} else {
|
||||||
MainOutput.report('call makeNameToInstances but this.rawInstances is undefined',
|
MainOutput.report('call makeNameToInstances but this.rawInstances is undefined',
|
||||||
ReportType.Warn);
|
ReportType.Warn);
|
||||||
@ -450,7 +495,7 @@ class HdlModule {
|
|||||||
this.deleteInstance(inst);
|
this.deleteInstance(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteInstance(inst: HdlInstance | undefined) {
|
public deleteInstance(inst?: HdlInstance) {
|
||||||
if (inst) {
|
if (inst) {
|
||||||
this.deleteUnhandleInstance(inst);
|
this.deleteUnhandleInstance(inst);
|
||||||
hdlParam.deleteUnhandleInstance(inst);
|
hdlParam.deleteUnhandleInstance(inst);
|
||||||
@ -585,13 +630,40 @@ class HdlModule {
|
|||||||
inst.locateHdlModule();
|
inst.locateHdlModule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public update(newModule: common.RawHdlModule) {
|
||||||
|
this.ports = newModule.ports;
|
||||||
|
this.params = newModule.params;
|
||||||
|
this.range = newModule.range;
|
||||||
|
// compare and make change to instance
|
||||||
|
const uncheckedInstanceNames = new Set<string>();
|
||||||
|
for (const inst of this.getAllInstances()) {
|
||||||
|
uncheckedInstanceNames.add(inst.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const newInst of newModule.instances) {
|
||||||
|
if (uncheckedInstanceNames.has(newInst.name)) {
|
||||||
|
// match exist instance, compare and update
|
||||||
|
const originalInstance = this.getInstance(newInst.name);
|
||||||
|
originalInstance?.update(newInst);
|
||||||
|
uncheckedInstanceNames.delete(newInst.name);
|
||||||
|
} else {
|
||||||
|
// unknown instance, create it
|
||||||
|
this.createHdlInstance(newInst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// delete Instance that not visited
|
||||||
|
for (const instName of uncheckedInstanceNames) {
|
||||||
|
this.deleteInstanceByName(instName);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HdlFile {
|
class HdlFile {
|
||||||
path: string;
|
public path: string;
|
||||||
languageId: HdlLangID;
|
public languageId: HdlLangID;
|
||||||
type: common.HdlFileType;
|
public type: common.HdlFileType;
|
||||||
macro: common.Macro;
|
public macro: common.Macro;
|
||||||
private readonly nameToModule: Map<string, HdlModule>;
|
private readonly nameToModule: Map<string, HdlModule>;
|
||||||
|
|
||||||
constructor(path: string,
|
constructor(path: string,
|
||||||
@ -652,7 +724,27 @@ class HdlFile {
|
|||||||
public deleteHdlModule(name: string) {
|
public deleteHdlModule(name: string) {
|
||||||
const hdlModule = this.getHdlModule(name);
|
const hdlModule = this.getHdlModule(name);
|
||||||
if (hdlModule) {
|
if (hdlModule) {
|
||||||
|
// delete child reference in the module which use this
|
||||||
|
for (const childInst of hdlModule.getAllGlobalRefers()) {
|
||||||
|
const userModule = childInst.parentMod;
|
||||||
|
childInst.module = undefined;
|
||||||
|
childInst.instModPath = undefined;
|
||||||
|
childInst.instModPathStatus = common.InstModPathStatus.Unknown;
|
||||||
|
|
||||||
|
hdlParam.addUnhandleInstance(childInst);
|
||||||
|
userModule.addUnhandleInstance(childInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all the instance in the module
|
||||||
|
for (const inst of hdlModule.getAllInstances()) {
|
||||||
|
hdlModule.deleteInstance(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete any variables containing module
|
||||||
|
hdlParam.deleteTopModule(hdlModule);
|
||||||
|
hdlParam.deleteTopModuleToSource(hdlModule);
|
||||||
|
hdlParam.modules.delete(hdlModule);
|
||||||
|
this.nameToModule.delete(hdlModule.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,6 +753,10 @@ class HdlFile {
|
|||||||
module.makeNameToInstances();
|
module.makeNameToInstances();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateMacro(macro: common.Macro) {
|
||||||
|
this.macro = macro;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,6 +87,10 @@ class PrjManage {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all the hdl files that to be parsed in the project
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
public getPrjHardwareFiles(): AbsPath[] {
|
public getPrjHardwareFiles(): AbsPath[] {
|
||||||
const searchPathSet = new PathSet();
|
const searchPathSet = new PathSet();
|
||||||
const prjInfo = opeParam.prjInfo;
|
const prjInfo = opeParam.prjInfo;
|
||||||
@ -97,24 +101,32 @@ class PrjManage {
|
|||||||
MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, ReportType.Info);
|
MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, ReportType.Info);
|
||||||
|
|
||||||
// add possible folder to search
|
// add possible folder to search
|
||||||
searchPathSet.checkAdd(hardwareInfo.src);
|
searchPathSet.checkAdd(prjInfo.hardwareSrcPath);
|
||||||
|
searchPathSet.checkAdd(prjInfo.hardwareSimPath);
|
||||||
searchPathSet.checkAdd(hardwareInfo.sim);
|
searchPathSet.checkAdd(hardwareInfo.sim);
|
||||||
searchPathSet.checkAdd(prjInfo.getLibraryCommonPaths());
|
searchPathSet.checkAdd(prjInfo.getLibraryCommonPaths());
|
||||||
searchPathSet.checkAdd(prjInfo.getLibraryCustomPaths());
|
searchPathSet.checkAdd(prjInfo.getLibraryCustomPaths());
|
||||||
|
|
||||||
|
|
||||||
|
MainOutput.report('<getPrjHardwareFiles> search folders: ', ReportType.Debug);
|
||||||
|
searchPathSet.files.forEach(p => MainOutput.report(p, ReportType.Debug));
|
||||||
|
|
||||||
// TODO : make something like .gitignore
|
// TODO : make something like .gitignore
|
||||||
const ignores = this.getIgnoreFiles();
|
const ignores = this.getIgnoreFiles();
|
||||||
|
|
||||||
// do search
|
// do search
|
||||||
const searchPaths = searchPathSet.files;
|
const searchPaths = searchPathSet.files;
|
||||||
return hdlFile.getHDLFiles(searchPaths, ignores);
|
|
||||||
|
const hdlFiles = hdlFile.getHDLFiles(searchPaths, ignores);
|
||||||
|
return hdlFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async initialise(context: vscode.ExtensionContext, countTimeCost: boolean = true) {
|
public async initialise(context: vscode.ExtensionContext, countTimeCost: boolean = true) {
|
||||||
if (countTimeCost) {
|
if (countTimeCost) {
|
||||||
console.time('launch');
|
console.time('launch');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.initOpeParam(context);
|
await this.initOpeParam(context);
|
||||||
MainOutput.report('finish initialise opeParam', ReportType.Info);
|
MainOutput.report('finish initialise opeParam', ReportType.Info);
|
||||||
|
|
||||||
|
238
src/monitor/event.ts
Normal file
238
src/monitor/event.ts
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import assert = require('assert');
|
||||||
|
import * as chokidar from 'chokidar';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { refreshArchTree } from '../function/treeView';
|
||||||
|
|
||||||
|
import { AbsPath, MainOutput, opeParam, RelPath, ReportType } from '../global';
|
||||||
|
import { isSameSet } from '../global/util';
|
||||||
|
import { hdlFile, hdlPath } from '../hdlFs';
|
||||||
|
import { hdlParam, HdlSymbol } from '../hdlParser';
|
||||||
|
import { prjManage } from '../manager';
|
||||||
|
|
||||||
|
import type { HdlMonitor } from './index';
|
||||||
|
|
||||||
|
enum Event {
|
||||||
|
Add = 'add', // emit when add file
|
||||||
|
AddDir = 'addDir', // emit when add folder
|
||||||
|
Unlink = 'unlink', // emit when delete file
|
||||||
|
UnlinkDir = 'unlinkDir', // emit when delete folder
|
||||||
|
Change = 'change', // emit when file changed
|
||||||
|
All = 'all', // all the change above
|
||||||
|
Ready = 'ready',
|
||||||
|
Raw = 'raw',
|
||||||
|
Error = 'error'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
abstract class BaseAction {
|
||||||
|
public listenChange(m: HdlMonitor) {
|
||||||
|
const fSWatcher = this.selectFSWatcher(m);
|
||||||
|
if (!fSWatcher) {
|
||||||
|
MainOutput.report("FSWatcher hasn't been made!", ReportType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSWatcher.on(Event.Change, path => this.change(path, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
public listenAdd(m: HdlMonitor) {
|
||||||
|
const fSWatcher = this.selectFSWatcher(m);
|
||||||
|
if (!fSWatcher) {
|
||||||
|
MainOutput.report("FSWatcher hasn't been made!", ReportType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSWatcher.on(Event.Add, path => this.add(path, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
public listenUnlink(m: HdlMonitor) {
|
||||||
|
const fSWatcher = this.selectFSWatcher(m);
|
||||||
|
if (!fSWatcher) {
|
||||||
|
MainOutput.report("FSWatcher hasn't been made!", ReportType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSWatcher.on(Event.Unlink, path => this.unlink(path, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract selectFSWatcher(m: HdlMonitor): chokidar.FSWatcher | undefined;
|
||||||
|
abstract change(path: AbsPath, m: HdlMonitor): Promise<void>;
|
||||||
|
abstract add(path: AbsPath, m: HdlMonitor): Promise<void>;
|
||||||
|
abstract unlink(path: AbsPath, m: HdlMonitor): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HdlAction extends BaseAction {
|
||||||
|
selectFSWatcher(m: HdlMonitor): chokidar.FSWatcher | undefined {
|
||||||
|
return m.hdlMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('HdlAction add');
|
||||||
|
|
||||||
|
path = hdlPath.toSlash(path);
|
||||||
|
// create corresponding moduleFile
|
||||||
|
hdlParam.initHdlFiles([path]);
|
||||||
|
|
||||||
|
const moduleFile = hdlParam.getHdlFile(path);
|
||||||
|
if (!moduleFile) {
|
||||||
|
console.log('error happen when create moduleFile', path);
|
||||||
|
} else {
|
||||||
|
moduleFile.makeInstance();
|
||||||
|
for (const module of moduleFile.getAllHdlModules()) {
|
||||||
|
module.solveUnhandleInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refreshArchTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
async unlink(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('HdlAction unlink');
|
||||||
|
|
||||||
|
path = hdlPath.toSlash(path);
|
||||||
|
hdlParam.deleteHdlFile(path);
|
||||||
|
refreshArchTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
async change(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('HdlAction change');
|
||||||
|
|
||||||
|
path = hdlPath.toSlash(path);
|
||||||
|
const moduleFile = hdlParam.getHdlFile(path);
|
||||||
|
|
||||||
|
if (!moduleFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fast = await HdlSymbol.fast(path);
|
||||||
|
if (!fast) {
|
||||||
|
vscode.window.showErrorMessage('error happen when parse ' + path + '\nFail to update');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. update marco directly
|
||||||
|
moduleFile.updateMacro(fast.macro);
|
||||||
|
|
||||||
|
// 2. update modules one by one
|
||||||
|
const uncheckedModuleNames = new Set<string>();
|
||||||
|
for (const name of moduleFile.getAllModuleNames()) {
|
||||||
|
uncheckedModuleNames.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const rawHdlModule of fast.content) {
|
||||||
|
const moduleName = rawHdlModule.name;
|
||||||
|
if (uncheckedModuleNames.has(moduleName)) {
|
||||||
|
// match the same module, check then
|
||||||
|
const originalModule = moduleFile.getHdlModule(moduleName);
|
||||||
|
uncheckedModuleNames.delete(moduleName);
|
||||||
|
originalModule?.update(rawHdlModule);
|
||||||
|
} else {
|
||||||
|
// no matched, create it
|
||||||
|
const newModule = moduleFile.createHdlModule(rawHdlModule);
|
||||||
|
newModule.makeNameToInstances();
|
||||||
|
newModule.solveUnhandleInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. delete module not visited yet
|
||||||
|
for (const moduleName of uncheckedModuleNames) {
|
||||||
|
moduleFile.deleteHdlModule(moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshArchTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PpyAction extends BaseAction {
|
||||||
|
selectFSWatcher(m: HdlMonitor): chokidar.FSWatcher | undefined {
|
||||||
|
return m.ppyMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('PpyAction add');
|
||||||
|
assert.equal(hdlPath.toSlash(path), opeParam.propertyJsonPath);
|
||||||
|
this.updateProperty(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
async unlink(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('PpyAction unlink');
|
||||||
|
assert.equal(hdlPath.toSlash(path), opeParam.propertyJsonPath);
|
||||||
|
this.updateProperty(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
async change(path: string, m: HdlMonitor): Promise<void> {
|
||||||
|
console.log('PpyAction change');
|
||||||
|
assert.equal(hdlPath.toSlash(path), opeParam.propertyJsonPath);
|
||||||
|
this.updateProperty(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get path set from opeParam that used to tell if need to remake HdlMonitor
|
||||||
|
private getImportantPathSet(): Set<AbsPath | RelPath> {
|
||||||
|
const pathSet = new Set<AbsPath | RelPath>();
|
||||||
|
pathSet.add(opeParam.prjInfo.arch.hardware.sim);
|
||||||
|
pathSet.add(opeParam.prjInfo.arch.hardware.src);
|
||||||
|
pathSet.add(opeParam.prjInfo.libCommonPath);
|
||||||
|
pathSet.add(opeParam.prjInfo.libCustomPath);
|
||||||
|
return pathSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateProperty(m: HdlMonitor) {
|
||||||
|
const originalPathSet = this.getImportantPathSet();
|
||||||
|
const originalHdlFiles = prjManage.getPrjHardwareFiles();
|
||||||
|
|
||||||
|
const rawPrjInfo = opeParam.getRawUserPrjInfo();
|
||||||
|
opeParam.mergePrjInfo(rawPrjInfo);
|
||||||
|
|
||||||
|
const currentPathSet = this.getImportantPathSet();
|
||||||
|
if (isSameSet(originalPathSet, currentPathSet)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options: vscode.ProgressOptions = { location: vscode.ProgressLocation.Notification, title: 'modify the project' };
|
||||||
|
vscode.window.withProgress(options, async () => await this.refreshHdlMonitor(m, originalHdlFiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async refreshHdlMonitor(m: HdlMonitor, originalHdlFiles: AbsPath[]) {
|
||||||
|
m.remakeHdlMonitor();
|
||||||
|
|
||||||
|
// update pl
|
||||||
|
const currentHdlFiles = prjManage.getPrjHardwareFiles();
|
||||||
|
await this.updatePL(originalHdlFiles, currentHdlFiles);
|
||||||
|
|
||||||
|
refreshArchTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updatePL(oldFiles: AbsPath[], newFiles: AbsPath[]) {
|
||||||
|
if (prjManage.pl) {
|
||||||
|
const uncheckHdlFileSet = new Set<AbsPath>(oldFiles);
|
||||||
|
const addFiles: AbsPath[] = [];
|
||||||
|
const delFiles: AbsPath[] = [];
|
||||||
|
|
||||||
|
for (const path of newFiles) {
|
||||||
|
if (!uncheckHdlFileSet.has(path)) {
|
||||||
|
await hdlParam.addHdlPath(path);
|
||||||
|
addFiles.push(path);
|
||||||
|
} else {
|
||||||
|
uncheckHdlFileSet.delete(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const vivadoAddPromise = prjManage.pl.addFiles(addFiles);
|
||||||
|
|
||||||
|
for (const path of uncheckHdlFileSet) {
|
||||||
|
hdlParam.deleteHdlFile(path);
|
||||||
|
delFiles.push(path);
|
||||||
|
}
|
||||||
|
const vivadoDelPromise = prjManage.pl.delFiles(delFiles);
|
||||||
|
|
||||||
|
await vivadoAddPromise;
|
||||||
|
await vivadoDelPromise;
|
||||||
|
} else {
|
||||||
|
MainOutput.report('PL is not registered', ReportType.Warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hdlAction = new HdlAction();
|
||||||
|
const ppyAction = new PpyAction();
|
||||||
|
|
||||||
|
export {
|
||||||
|
hdlAction,
|
||||||
|
ppyAction
|
||||||
|
};
|
103
src/monitor/index.ts
Normal file
103
src/monitor/index.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import * as chokidar from 'chokidar';
|
||||||
|
import { MainOutput, opeParam, ReportType } from '../global';
|
||||||
|
import { hdlExts } from '../global/lang';
|
||||||
|
import { PathSet } from '../global/util';
|
||||||
|
import { hdlPath } from '../hdlFs';
|
||||||
|
|
||||||
|
import * as Event from './event';
|
||||||
|
|
||||||
|
class HdlMonitor{
|
||||||
|
private monitorConfig: chokidar.WatchOptions;
|
||||||
|
public hdlMonitor?: chokidar.FSWatcher;
|
||||||
|
public ppyMonitor?: chokidar.FSWatcher;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// public config for monitor
|
||||||
|
this.monitorConfig = {
|
||||||
|
persistent: true,
|
||||||
|
usePolling: false,
|
||||||
|
ignoreInitial: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public makeMonitor(paths: string | string[], config?: chokidar.WatchOptions): chokidar.FSWatcher {
|
||||||
|
if (!config) {
|
||||||
|
config = this.monitorConfig;
|
||||||
|
}
|
||||||
|
return chokidar.watch(paths, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get monitor for property.json
|
||||||
|
*/
|
||||||
|
public getPpyMonitor() {
|
||||||
|
const watcherPath = opeParam.propertyJsonPath;
|
||||||
|
return this.makeMonitor(watcherPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get monitor for HDLParam update
|
||||||
|
*/
|
||||||
|
public getHdlMonitor() {
|
||||||
|
const hdlExtsGlob = `**/*.{${hdlExts.join(',')}}`;
|
||||||
|
const prjInfo = opeParam.prjInfo;
|
||||||
|
|
||||||
|
const monitorPathSet = new PathSet();
|
||||||
|
monitorPathSet.checkAdd(prjInfo.hardwareSimPath);
|
||||||
|
monitorPathSet.checkAdd(prjInfo.hardwareSrcPath);
|
||||||
|
monitorPathSet.checkAdd(prjInfo.libCommonPath);
|
||||||
|
monitorPathSet.checkAdd(prjInfo.libCustomPath);
|
||||||
|
|
||||||
|
const monitorFoldersWithGlob = [];
|
||||||
|
for (const folder of monitorPathSet.files) {
|
||||||
|
const globPath = hdlPath.join(folder, hdlExtsGlob);
|
||||||
|
monitorFoldersWithGlob.push(globPath);
|
||||||
|
}
|
||||||
|
MainOutput.report('Following folders are tracked: ');
|
||||||
|
monitorPathSet.files.forEach(p => MainOutput.report(p));
|
||||||
|
|
||||||
|
return this.makeMonitor(monitorFoldersWithGlob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.hdlMonitor?.close();
|
||||||
|
this.ppyMonitor?.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
// make monitor
|
||||||
|
this.hdlMonitor = this.getHdlMonitor();
|
||||||
|
this.ppyMonitor = this.getPpyMonitor();
|
||||||
|
|
||||||
|
this.registerHdlMonitorListener();
|
||||||
|
this.registerPpyMonitorListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public remakeHdlMonitor() {
|
||||||
|
if (this.hdlMonitor) {
|
||||||
|
this.hdlMonitor.close();
|
||||||
|
this.hdlMonitor = this.getHdlMonitor();
|
||||||
|
this.registerHdlMonitorListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerHdlMonitorListener() {
|
||||||
|
Event.hdlAction.listenAdd(this);
|
||||||
|
Event.hdlAction.listenChange(this);
|
||||||
|
Event.hdlAction.listenUnlink(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerPpyMonitorListener() {
|
||||||
|
Event.ppyAction.listenAdd(this);
|
||||||
|
Event.ppyAction.listenChange(this);
|
||||||
|
Event.ppyAction.listenUnlink(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const hdlMonitor = new HdlMonitor();
|
||||||
|
|
||||||
|
export {
|
||||||
|
hdlMonitor,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type { HdlMonitor };
|
17
src/test/monitor/.vscode/property.json
vendored
Normal file
17
src/test/monitor/.vscode/property.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"toolChain": "xilinx",
|
||||||
|
"prjName": {
|
||||||
|
"PL": "template"
|
||||||
|
},
|
||||||
|
"soc": {
|
||||||
|
"core": "none"
|
||||||
|
},
|
||||||
|
"enableShowLog": false,
|
||||||
|
"device": "none",
|
||||||
|
"arch": {
|
||||||
|
"hardware": {
|
||||||
|
"src": "./src1",
|
||||||
|
"sim": "./sim1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
src/test/monitor/sim1/testbench.v
Normal file
50
src/test/monitor/sim1/testbench.v
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
module testbench();
|
||||||
|
|
||||||
|
parameter DATA_WIDTH = 32;
|
||||||
|
parameter ADDR_WIDTH = 32;
|
||||||
|
parameter MAIN_FRE = 100; //unit MHz
|
||||||
|
reg sys_clk = 0;
|
||||||
|
reg sys_rst = 1;
|
||||||
|
reg [DATA_WIDTH-1:0] data = 0;
|
||||||
|
reg [ADDR_WIDTH-1:0] addr = 0;
|
||||||
|
|
||||||
|
always begin
|
||||||
|
#(500/MAIN_FRE) sys_clk = ~sys_clk;
|
||||||
|
end
|
||||||
|
|
||||||
|
always begin
|
||||||
|
#50 sys_rst = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge sys_clk) begin
|
||||||
|
if (sys_rst)
|
||||||
|
addr = 0;
|
||||||
|
else
|
||||||
|
addr = addr + 1;
|
||||||
|
end
|
||||||
|
always @(posedge sys_clk) begin
|
||||||
|
if (sys_rst)
|
||||||
|
data = 0;
|
||||||
|
else
|
||||||
|
data = data + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
//Instance
|
||||||
|
// outports wire
|
||||||
|
wire [8:0] c;
|
||||||
|
|
||||||
|
SimpleAdd_1 u_SimpleAdd_1(
|
||||||
|
.a ( a ),
|
||||||
|
.b ( b ),
|
||||||
|
.c ( c )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("wave.vcd");
|
||||||
|
$dumpvars(0, testbench);
|
||||||
|
#50000 $finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule //TOP
|
11
src/test/monitor/src1/add.v
Normal file
11
src/test/monitor/src1/add.v
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module SimpleAdd_1(
|
||||||
|
input [8:0] a, b,
|
||||||
|
output [8:0] c
|
||||||
|
);
|
||||||
|
|
||||||
|
assign c = a + b;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule //SimpleAdd
|
||||||
|
|
||||||
|
|
9
src/test/monitor/src2/add.v
Normal file
9
src/test/monitor/src2/add.v
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module SimpleAdd_2(
|
||||||
|
input [8:0] a, b,
|
||||||
|
output [8:0] c
|
||||||
|
);
|
||||||
|
|
||||||
|
assign c = a + b;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule //SimpleAdd
|
Loading…
x
Reference in New Issue
Block a user