diff --git a/package-lock.json b/package-lock.json index b21dcae..3db6db8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "digital-ide", "version": "0.3.0", "dependencies": { + "@vscode/wasm-wasi": "^0.8.2", "chokidar": "^3.5.3", "puppeteer-core": "^19.4.1", "showdown": "^2.1.0", @@ -343,6 +344,26 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@vscode/sync-api-client": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@vscode/sync-api-client/-/sync-api-client-0.8.1.tgz", + "integrity": "sha512-82NRZpZlvRtlFoqi/J8xGw964F8ZfJJeJu2D9QMAAzq8BMDCXqkhO2qHApnyEV4gG2mQSaHtfw0f30GOPExgUg==", + "dependencies": { + "@vscode/sync-api-common": "0.8.1", + "vscode-uri": "^3.0.6" + }, + "engines": { + "node": ">=16.14.2" + } + }, + "node_modules/@vscode/sync-api-common": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@vscode/sync-api-common/-/sync-api-common-0.8.1.tgz", + "integrity": "sha512-XfanQNxkUlCpAsQ2+1SzNEdoY7jtcu48jYBR0n864ZWAWrH7m2QBK32YoNlrDN2V0eh8tdF0WH1NuHOm3Y021A==", + "engines": { + "node": ">=16.14.2" + } + }, "node_modules/@vscode/test-electron": { "version": "2.2.2", "resolved": "https://registry.npmmirror.com/@vscode/test-electron/-/test-electron-2.2.2.tgz", @@ -358,6 +379,18 @@ "node": ">=16" } }, + "node_modules/@vscode/wasm-wasi": { + "version": "0.8.2", + "resolved": "https://registry.npmmirror.com/@vscode/wasm-wasi/-/wasm-wasi-0.8.2.tgz", + "integrity": "sha512-TazXvphINUEoXVX2dEPdXhrwrQ9I6Z6t9LCDfALTmL43D/2Zmlc89KfNE/cO36n2uo+SDlPPP/6vWyF9TBbnnw==", + "dependencies": { + "@vscode/sync-api-client": "0.8.1", + "vscode-uri": "^3.0.6" + }, + "engines": { + "vscode": "^1.71.0" + } + }, "node_modules/acorn": { "version": "8.8.1", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.1.tgz", @@ -2835,6 +2868,11 @@ "resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz", "integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==" }, + "node_modules/vscode-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.0.7.tgz", + "integrity": "sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==" + }, "node_modules/wavedrom": { "version": "2.9.1", "resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz", @@ -3239,6 +3277,20 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@vscode/sync-api-client": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@vscode/sync-api-client/-/sync-api-client-0.8.1.tgz", + "integrity": "sha512-82NRZpZlvRtlFoqi/J8xGw964F8ZfJJeJu2D9QMAAzq8BMDCXqkhO2qHApnyEV4gG2mQSaHtfw0f30GOPExgUg==", + "requires": { + "@vscode/sync-api-common": "0.8.1", + "vscode-uri": "^3.0.6" + } + }, + "@vscode/sync-api-common": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@vscode/sync-api-common/-/sync-api-common-0.8.1.tgz", + "integrity": "sha512-XfanQNxkUlCpAsQ2+1SzNEdoY7jtcu48jYBR0n864ZWAWrH7m2QBK32YoNlrDN2V0eh8tdF0WH1NuHOm3Y021A==" + }, "@vscode/test-electron": { "version": "2.2.2", "resolved": "https://registry.npmmirror.com/@vscode/test-electron/-/test-electron-2.2.2.tgz", @@ -3251,6 +3303,15 @@ "unzipper": "^0.10.11" } }, + "@vscode/wasm-wasi": { + "version": "0.8.2", + "resolved": "https://registry.npmmirror.com/@vscode/wasm-wasi/-/wasm-wasi-0.8.2.tgz", + "integrity": "sha512-TazXvphINUEoXVX2dEPdXhrwrQ9I6Z6t9LCDfALTmL43D/2Zmlc89KfNE/cO36n2uo+SDlPPP/6vWyF9TBbnnw==", + "requires": { + "@vscode/sync-api-client": "0.8.1", + "vscode-uri": "^3.0.6" + } + }, "acorn": { "version": "8.8.1", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.1.tgz", @@ -5227,6 +5288,11 @@ "resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz", "integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==" }, + "vscode-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.0.7.tgz", + "integrity": "sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==" + }, "wavedrom": { "version": "2.9.1", "resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz", diff --git a/package.json b/package.json index f0a32b4..96353b6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "engines": { "vscode": "^1.72.0" }, - "keywords": [ + "keywords": [ "FPGA Develop Support", "FPGA", "ASIC", @@ -23,7 +23,7 @@ "Vivado", "Xilinx" ], - "repository": { + "repository": { "type": "git", "url": "https://github.com/Digital-EDA/Digital-IDE" }, @@ -780,7 +780,7 @@ { "language": "verilog", "scopeName": "source.verilog", - "path": "./syntaxes/verilog.json" + "path": "./syntaxes/verilog.tmLanguage.json" }, { "language": "systemverilog", @@ -956,6 +956,7 @@ "typescript": "^4.8.4" }, "dependencies": { + "@vscode/wasm-wasi": "^0.8.2", "chokidar": "^3.5.3", "puppeteer-core": "^19.4.1", "showdown": "^2.1.0", @@ -964,4 +965,4 @@ "vscode-textmate": "^9.0.0", "wavedrom": "^2.9.1" } -} \ No newline at end of file +} diff --git a/project/property-schema.json b/project/property-schema.json index d0e8a07..9bb43b9 100644 --- a/project/property-schema.json +++ b/project/property-schema.json @@ -199,7 +199,22 @@ "xc7z035ffg676-2", "xc7z020clg484-1" ] - } + }, + "iverilogCompileOptions": { + "type": "object", + "description": "options to define iverilog arguments", + "properties": { + "standard": { + "type": "string", + "description": "value of argument -g, default is -g2012", + "default": "2012" + }, + "includes": { + "type": "array", + "description": "value of argument -I" + } + } + } }, "required": [ "toolChain", diff --git a/src/function/lsp/definition/vlog.ts b/src/function/lsp/definition/vlog.ts index c5321b5..be77a98 100644 --- a/src/function/lsp/definition/vlog.ts +++ b/src/function/lsp/definition/vlog.ts @@ -1,5 +1,4 @@ import * as vscode from 'vscode'; -import * as vsctm from 'vscode-textmate'; import { hdlPath } from '../../../hdlFs'; import { hdlParam } from '../../../hdlParser'; diff --git a/src/function/lsp/docSemantic/vlog.ts b/src/function/lsp/docSemantic/vlog.ts index 3462660..80509fe 100644 --- a/src/function/lsp/docSemantic/vlog.ts +++ b/src/function/lsp/docSemantic/vlog.ts @@ -1,15 +1,51 @@ import * as vscode from 'vscode'; +import { All } from '../../../../resources/hdlParser'; +import { HdlSymbol } from '../../../hdlParser'; +import { vlogSymbolStorage } from '../core'; +import { transformRange } from '../util'; -const tokenTypes = ['class', 'interface', 'enum', 'function', 'variable']; +const tokenTypes = ['class', '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 { // TODO : finish this - // const tokensBuilder = new vscode.SemanticTokensBuilder(vlogLegend); - return null; + const tokensBuilder = new vscode.SemanticTokensBuilder(vlogLegend); + // const filePath = document.fileName; + // const vlogAll = await HdlSymbol.all(filePath); + // if (vlogAll) { + // this.prepareTokensBuilder(tokensBuilder, vlogAll); + // } + return tokensBuilder.build(); } + + private prepareTokensBuilder(builder: vscode.SemanticTokensBuilder, all: All){ + for (const rawSymbol of all.content) { + const semanticRange = transformRange(rawSymbol.range, -1, 0); + const tokenType = this.getTokenTypes(rawSymbol.type); + if (tokenType) { + builder.push(semanticRange, tokenType); + } + } + } + + private getTokenTypes(type: string): string | undefined { + switch (type) { + case 'input': + return 'variable'; + case 'output': + return 'variable'; + case 'wire': + return 'variable'; + case 'reg': + return 'variable'; + default: + return; + } + } + } const vlogDocSenmanticProvider = new VlogDocSenmanticProvider(); diff --git a/src/function/sim/simulate.ts b/src/function/sim/simulate.ts index b208d0d..88897d1 100644 --- a/src/function/sim/simulate.ts +++ b/src/function/sim/simulate.ts @@ -106,7 +106,7 @@ class Simulate { * @description 获取自带仿真库的路径 * @param toolChain */ - getSimLibArr(toolChain: ToolChainType): AbsPath[] { + public getSimLibArr(toolChain: ToolChainType): AbsPath[] { let libPath: AbsPath[] = []; const setting = vscode.workspace.getConfiguration(); @@ -146,6 +146,38 @@ class IcarusSimulate extends Simulate { this.toolChain = opeParam.prjInfo.toolChain; } + private makeMacroIncludeArguments(includes: string[]): string { + const args = []; + for (const includePath of includes) { + if(!hdlFile.isDir(includePath)) { + args.push(includePath); + } else { + args.push('-I ' + includePath); + } + } + return args.join(' ').trim(); + } + + private makeDependenceArguments(dependences: string[]): string { + const args = []; + for (const dep of dependences) { + args.push('"' + dep + '"'); + } + return args.join(' ').trim(); + } + + private makeThirdLibraryArguments(simLibPaths: string[]): string { + const args = []; + for (const libPath of simLibPaths) { + if(!hdlFile.isDir(libPath)) { + args.push(libPath); + } else { + args.push('-y ' + libPath); + } + } + return args.join(' ').trim(); + } + /** * generate acutal iverlog simulation command * @param name name of top module @@ -160,6 +192,7 @@ class IcarusSimulate extends Simulate { } this.simConfig = simConfig; const installPath = simConfig.installPath; + const iverilogCompileOptions = opeParam.prjInfo.iverilogCompileOptions; if (this.os === 'win32') { simConfig.iverilogPath += '.exe'; @@ -171,25 +204,19 @@ class IcarusSimulate extends Simulate { simConfig.vvpPath = hdlPath.join(installPath, simConfig.vvpPath); } - let dependenceArgs = ''; - dependences.forEach(d => dependenceArgs += '"' + d + '" '); - dependenceArgs = dependenceArgs.trim(); + const simLibPaths = this.getSimLibArr(this.toolChain); - let thirdLibPath = ' '; - this.getSimLibArr(this.toolChain).forEach(element => { - if(!hdlFile.isDir(element)) { - thirdLibPath += element + " "; - } else { - thirdLibPath += `-y ${element}`; - } - }); + const macroIncludeArgs = this.makeMacroIncludeArguments(iverilogCompileOptions.includes); + const dependenceArgs = this.makeDependenceArguments(dependences); + const thirdLibraryArgs = this.makeThirdLibraryArguments(simLibPaths); const iverilogPath = simConfig.iverilogPath; - const argu = '-g2012'; + // default is -g2012 + const argu = '-g' + iverilogCompileOptions.standard; const outVvpPath = '"' + hdlPath.join(simConfig.simulationHome, 'out.vvp') + '"'; const mainPath = '"' + path + '"'; - const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${mainPath} ${dependenceArgs} ${thirdLibPath}`; + const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${macroIncludeArgs} ${mainPath} ${dependenceArgs} ${thirdLibraryArgs}`; MainOutput.report(cmd, ReportType.Run); return cmd; } @@ -263,6 +290,7 @@ class IcarusSimulate extends Simulate { if (runInTerminal) { this.execInTerminal(command, cwd); } else { + MainOutput.show(); this.execInOutput(command, cwd); } } @@ -288,7 +316,7 @@ class IcarusSimulate extends Simulate { const dependences = this.getAllOtherDependences(path, name); const simulationCommand = this.getCommand(name, path, dependences); if (simulationCommand) { - const cwd = hdlPath.resolve(hdlModule.path, '..'); + const cwd = hdlPath.resolve(path, '..'); this.exec(simulationCommand, cwd); } else { const errorMsg = 'Fail to generate command'; diff --git a/src/global/outputChannel.ts b/src/global/outputChannel.ts index 5e4fc63..47138e3 100644 --- a/src/global/outputChannel.ts +++ b/src/global/outputChannel.ts @@ -67,6 +67,10 @@ class Output { } } } + + public show() { + this._output.show(true); + } } const MainOutput = new Output('Digital-IDE'); diff --git a/src/global/prjInfo.ts b/src/global/prjInfo.ts index 6f90643..901a375 100644 --- a/src/global/prjInfo.ts +++ b/src/global/prjInfo.ts @@ -79,6 +79,13 @@ const PrjInfoDefaults: PrjInfoMeta = { custom: [] } }; + }, + + get iverilogCompileOptions() { + return { + standard: "2012", + includes: [] + }; } }; @@ -108,6 +115,11 @@ interface Library { } } +interface IverilogCompileOptions { + standard: string, + includes: Path[] +} + interface RawPrjInfo extends RawPrjInfoMeta { toolChain?: ToolChainType prjName?: PrjName @@ -160,6 +172,9 @@ class PrjInfo implements PrjInfoMeta { // library to manage private readonly _library: Library = PrjInfoDefaults.library; + // compile for iverilog + private readonly _iverilogCompileOptions: IverilogCompileOptions = PrjInfoDefaults.iverilogCompileOptions; + public get toolChain(): ToolChainType { return this._toolChain; } @@ -196,6 +211,10 @@ class PrjInfo implements PrjInfoMeta { return 'microphase'; } + public get iverilogCompileOptions(): IverilogCompileOptions { + return this._iverilogCompileOptions; + } + /** * replace token like ${workspace} in path * @param path @@ -209,9 +228,9 @@ class PrjInfo implements PrjInfoMeta { const psname = this.prjName.PS; // TODO : packaging the replacer - return path.replace(new RegExp('${workspace}', 'g'), workspacePath) - .replace(new RegExp('${plname}', 'g'), plname) - .replace(new RegExp('${psname}', 'g'), psname); + return path.replace(/\$\{workspace\}/g, workspacePath) + .replace(/\$\{plname\}/g, plname) + .replace(/\$\{psname\}/g, psname); } /** @@ -452,6 +471,21 @@ class PrjInfo implements PrjInfoMeta { } } + public updateIverilogCompileOptions(iverilogCompileOptions?: IverilogCompileOptions) { + if (iverilogCompileOptions) { + if (iverilogCompileOptions.standard) { + this._iverilogCompileOptions.standard = iverilogCompileOptions.standard; + } + if (iverilogCompileOptions.includes && iverilogCompileOptions.includes instanceof Array) { + this._iverilogCompileOptions.includes = []; + for (const includePath of iverilogCompileOptions.includes) { + const realIncludePath = includePath.replace(/\$\{workspace\}/g, this._workspacePath); + this._iverilogCompileOptions.includes.push(realIncludePath); + } + } + } + } + public appendLibraryCommonPath(relPath: RelPath) { this._library.hardware.common.push(relPath); } @@ -502,6 +536,7 @@ class PrjInfo implements PrjInfoMeta { this.updateDevice(rawPrjInfo.device); this.updateArch(rawPrjInfo.arch); this.updateLibrary(rawPrjInfo.library); + this.updateIverilogCompileOptions(rawPrjInfo.iverilogCompileOptions); } /** diff --git a/src/global/propertySchema.ts b/src/global/propertySchema.ts index 7a9a4bc..258e58e 100644 --- a/src/global/propertySchema.ts +++ b/src/global/propertySchema.ts @@ -76,6 +76,10 @@ interface PrjInfoSchema { enableShowLog: Type & Desc & Default & Enum device: Type & Desc & Enum + iverilogCompileOptions: { + standard: string + includes: string[] + } }; interface PropertySchema { diff --git a/src/test/user/Hardware/src/hello.v b/src/test/user/Hardware/src/hello.v index 9d67aa1..3d0226c 100644 --- a/src/test/user/Hardware/src/hello.v +++ b/src/test/user/Hardware/src/hello.v @@ -4,7 +4,8 @@ module mux2to1( input wire a, input wire b, input wire sel, - output wire outp + output wire outp, + output wire test_port ); diff --git a/syntaxes/verilog.tmLanguage.json b/syntaxes/verilog.tmLanguage.json new file mode 100644 index 0000000..10c5d78 --- /dev/null +++ b/syntaxes/verilog.tmLanguage.json @@ -0,0 +1,361 @@ +{ + "fileTypes": [ + "v", + "vh" + ], + "keyEquivalent": "^~V", + "name": "Verilog", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#module_pattern" + }, + { + "include": "#keywords" + }, + { + "include": "#constants" + }, + { + "include": "#strings" + }, + { + "include": "#operators" + }, + { + "include": "#macro_definition" + }, + { + "include": "#macro_quote" + }, + { + "include": "#common_variable" + } + ], + "repository": { + "comments": { + "patterns": [ + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.verilog" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.verilog" + } + }, + "end": "\\n", + "name": "comment.line.double-slash.verilog" + } + ] + }, + { + "begin": "/\\*", + "end": "\\*/", + "name": "comment.block.c-style.verilog" + } + ] + }, + "constants": { + "patterns": [ + { + "match": "\\b[0-9]+'[bBoOdDhH][a-fA-F0-9_xXzZ]+\\b", + "name": "constant.numeric.sized_integer.verilog" + }, + { + "captures": { + "1": { + "name": "constant.numeric.integer.verilog" + }, + "2": { + "name": "punctuation.separator.range.verilog" + }, + "3": { + "name": "constant.numeric.integer.verilog" + } + }, + "match": "\\b(\\d+)(:)(\\d+)\\b", + "name": "meta.block.numeric.range.verilog" + }, + { + "match": "\\b\\d+(?i:e\\d+)?\\b", + "name": "constant.numeric.integer.verilog" + }, + { + "match": "\\b\\d+\\.\\d+(?i:e\\d+)?\\b", + "name": "constant.numeric.real.verilog" + }, + { + "match": "#\\d+", + "name": "constant.numeric.delay.verilog" + }, + { + "match": "\\b[01xXzZ]+\\b", + "name": "constant.numeric.logic.verilog" + } + ] + }, + "instantiation_patterns": { + "patterns": [ + { + "include": "#keywords" + }, + { + "begin": "^\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s+([a-zA-Z][a-zA-Z0-9_]*)(?)=?|(!|=)?==?|!|&&?|\\|\\|?|\\^?~|~\\^?", + "name": "keyword.operator.verilog" + } + ] + }, + "parenthetical_list": { + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.list.verilog" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.list.verilog" + } + }, + "name": "support.block.parenthetical_list.verilog", + "patterns": [ + { + "include": "#parenthetical_list" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#constants" + }, + { + "include": "#strings" + }, + { + "include": "#position_ports" + }, + { + "include": "#macro_quote" + }, + { + "include": "#common_variable" + } + ] + } + ] + }, + "position_ports": { + "patterns": [ + { + "match": "\\.[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.inst.port.verilog" + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "\"", + "end": "\"", + "name": "string.quoted.double.verilog", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.verilog" + } + ] + } + ] + }, + "macro_definition": { + "patterns": [ + { + "match": "(?<=`define\\s)\\w+", + "name": "support.function.macro.definition.verilog" + } + ] + }, + "macro_quote": { + "patterns": [ + { + "match": "`[a-zA-Z_][a-zA-Z_0-9]*", + "name": "support.function.macro.quote.verilog" + } + ] + }, + "common_variable": { + "patterns": [ + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.other.constant.verilog" + } + ] + } + }, + "scopeName": "source.verilog", + "uuid": "7F4396B3-A33E-44F0-8502-98CA6C25971F" +} \ No newline at end of file