├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── LICENSE ├── README.md ├── build.sh ├── images └── icon.png ├── language-configuration.json ├── package.json ├── snippets └── snippets.json ├── src ├── DefinitionProvider.ts ├── alignment.ts ├── extension.ts ├── hover.ts └── instantiation.ts ├── syntaxes └── systemverilog.tmLanguage ├── testfile.sv ├── toInst.sv └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | /node_modules 3 | /package-lock.json 4 | *.vsix 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | os: 4 | - linux 5 | 6 | language: node_js 7 | node_js: 8 | - "7" 9 | 10 | before_install: 11 | - if [ $TRAVIS_OS_NAME == "linux" ]; then 12 | export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; 13 | sh -e /etc/init.d/xvfb start; 14 | sleep 3; 15 | fi 16 | 17 | install: 18 | - npm install 19 | - npm run vscode:prepublish 20 | 21 | script: 22 | - npm test --silent 23 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ], 14 | "preLaunchTask": "npm" 15 | }, 16 | { 17 | "name": "Launch Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "runtimeExecutable": "${execPath}", 21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 22 | "stopOnEntry": false, 23 | "sourceMaps": true, 24 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 25 | "preLaunchTask": "npm" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | } 9 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "0.1.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // the command is a shell script 17 | "isShellCommand": true, 18 | 19 | // show the output window only if unrecognized errors occur. 20 | "showOutput": "silent", 21 | 22 | // we run the custom script "compile" as defined in package.json 23 | "args": ["run", "compile", "--loglevel", "silent"], 24 | 25 | // The tsc compiler is started in watching mode 26 | "isWatching": true, 27 | 28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 29 | "problemMatcher": "$tsc-watch" 30 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .gitignore 3 | *.vsix 4 | test/** 5 | tsconfig.json 6 | build.sh 7 | .travis.yml 8 | testfile.* 9 | 10 | .vscode-test/** 11 | out/test/** 12 | src/** 13 | **/*.map 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017 Masahiro H 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SystemVerilog support for VSCode [![Build Status](https://travis-ci.org/mshr-h/vscode-systemverilog-support.svg?branch=master)](https://travis-ci.org/mshr-h/vscode-systemverilog-support) 2 | SystemVerilog support based on [https://github.com/al8/sublimetext-Verilog](https://github.com/al8/sublimetext-Verilog) SumblieText package. 3 | 4 | ## Features 5 | 6 | ### Done 7 | - Syntax highlighting for `.sv` `.SV` files 8 | - Snippets for: 9 | - **Blocks:** `always_ff`, `always_comb`, `module`, `initial`, `function` 10 | - **Conditional blocks:** `if`, `while`, `for` 11 | - **Declaration:** `parameter`, `function` 12 | - **Pre-build:** `include`, `define` 13 | - **Special:** 14 | - `paramod` for module with parameters 15 | - `begin` to generate begin and end pair 16 | - Hover variable declaration ([PR#16](https://github.com/mshr-h/vscode-systemverilog-support/pull/16)) 17 | - Command for module instantiation ([PR#20](https://github.com/mshr-h/vscode-systemverilog-support/pull/20)) 18 | 1. Open command palette `Ctrl+Shift+P` and type `System Verilog: Instantiate Module` 19 | 1. Choose file you want to instantiate and it will insert inst at cursor location 20 | 21 | ### Known bug 22 | - `begin ... end` bracket matching not supported 23 | 24 | ## GitHub repos 25 | [mshr-h/vscode-systemverilog-support](https://github.com/mshr-h/vscode-systemverilog-support) 26 | 27 | ## Repository organization 28 | 29 | This repository is organized as follows: 30 | 31 | ``` 32 | sytnaxes/ syntax definition 33 | snippets/ code snippet 34 | src/ source code for custom feature 35 | language-configuration.json language configuration 36 | package.json package configuration 37 | LICENSE.txt license 38 | README.md readme 39 | ``` 40 | 41 | ## Contributing 42 | 1. Fork it ( [https://github.com/mshr-h/vscode-systemverilog-support](https://github.com/mshr-h/vscode-systemverilog-support) ) 43 | 2. Create your feature branch (`git checkout -b my-new-feature`) 44 | 3. Commit your changes (`git commit -am 'Add some feature'`) 45 | 4. Push to the branch (`git push origin my-new-feature`) 46 | 5. Create a new Pull Request 47 | 48 | ## See also 49 | [https://marketplace.visualstudio.com/items/mshr-h.SystemVerilog](https://marketplace.visualstudio.com/items/mshr-h.SystemVerilog) 50 | 51 | ## License 52 | 53 | [MIT](LICENSE) 54 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | vsce package -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mshr-h/vscode-systemverilog-support/5a01ee0b7a4fb59e150526381418aafd03bca340/images/icon.png -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"], 13 | ["case", "endcase"], 14 | ["class", "endclass"], 15 | ["clocking", "endclocking"], 16 | ["function", "endfunction"], 17 | ["group", "endgroup"], 18 | ["interface", "endinterface"], 19 | ["module", "endmodule"], 20 | ["package", "endpackage"], 21 | ["primitive", "endprimitive"], 22 | ["program", "endprogram"], 23 | ["property", "endproperty"], 24 | ["sequence", "endsequence"], 25 | ["task", "endtask"] 26 | ], 27 | 28 | "autoClosingPairs": [ 29 | {"open":"(", "close":")", "notIn":["string", "comment"]}, 30 | {"open":"[", "close":"]", "notIn":["string", "comment"]}, 31 | {"open":"{", "close":"}", "notIn":["string", "comment"]} 32 | ] 33 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "systemverilog", 3 | "displayName": "SystemVerilog", 4 | "description": "System Verilog support for VS Code", 5 | "version": "0.0.20", 6 | "publisher": "mshr-h", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/mshr-h/vscode-systemverilog-support.git" 10 | }, 11 | "engines": { 12 | "vscode": "^1.10.0" 13 | }, 14 | "categories": [ 15 | "Languages" 16 | ], 17 | "icon": "images/icon.png", 18 | "contributes": { 19 | "languages": [ 20 | { 21 | "id": "systemverilog", 22 | "aliases": [ 23 | "System Verilog", 24 | "systemverilog" 25 | ], 26 | "extensions": [ 27 | ".sv", 28 | ".SV" 29 | ], 30 | "configuration": "./language-configuration.json" 31 | } 32 | ], 33 | "grammars": [ 34 | { 35 | "language": "systemverilog", 36 | "scopeName": "source.systemverilog", 37 | "path": "./syntaxes/systemverilog.tmLanguage" 38 | } 39 | ], 40 | "snippets": [ 41 | { 42 | "language": "systemverilog", 43 | "path": "./snippets/snippets.json" 44 | } 45 | ], 46 | "configuration": { 47 | "title": "", 48 | "properties": { 49 | "systemverilog.instancePrefix": { 50 | "type": "string", 51 | "default": "u_", 52 | "description": "The prefix to use when instantiating a new module" 53 | }, 54 | "systemverilog.condenseBlankLines": { 55 | "type":"boolean", 56 | "default": false, 57 | "description": "When aligning code leave blank lines between lines" 58 | }, 59 | "systemverilog.alignEndOfLine": { 60 | "type": "boolean", 61 | "default": false, 62 | "description": "Align the comma at the end of the port definition" 63 | } 64 | } 65 | }, 66 | "commands": [ 67 | { 68 | "command": "extension.systemverilog.instantiateModule", 69 | "title": "System Verilog: Instantiate Module" 70 | }, 71 | { 72 | "command": "extension.systemverilog.alignment", 73 | "title": "System Verilog: alignment" 74 | } 75 | ], 76 | "menus": { 77 | "editor/context": [{ 78 | "command": "extension.systemverilog.alignment", 79 | "when": "editorHasSelection", 80 | "group": "1_modification" 81 | }] 82 | }, 83 | "keybindings": [{ 84 | "command": "extension.systemverilog.alignment", 85 | "key": "alt+=", 86 | "mac": "alt+=", 87 | "when": "editorHasSelection" 88 | }] 89 | }, 90 | "activationEvents": [ 91 | "onLanguage:systemverilog" 92 | ], 93 | "main": "./out/src/extension", 94 | "scripts": { 95 | "vscode:prepublish": "tsc -p ./", 96 | "compile": "tsc -watch -p ./", 97 | "postinstall": "node ./node_modules/vscode/bin/install" 98 | }, 99 | "devDependencies": { 100 | "typescript": "^2.0.3", 101 | "vscode": "^1.0.0", 102 | "@types/node": "*" 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "always_ff block": { 3 | "prefix": "ff", 4 | "body": [ 5 | "always_ff @( ${1:clock} ) begin : ${2:blockName}", 6 | "\t$0", 7 | "end" 8 | ], 9 | "description": "Insert an always_ff block" 10 | }, 11 | 12 | "always_comb block": { 13 | "prefix": "comb", 14 | "body": [ 15 | "always_comb begin : ${1:blockName}", 16 | "\t$0", 17 | "end" 18 | ], 19 | "description": "Insert an always_comb block" 20 | }, 21 | 22 | "module with parameters": { 23 | "prefix": "paramod", 24 | "body": [ 25 | "module ${moduleName} #(", 26 | "\t${1:parameters}", 27 | ") (", 28 | "\t${2:ports}", 29 | ");", 30 | "\t$0", 31 | "endmodule" 32 | ], 33 | "description": "Insert a module with parameter" 34 | }, 35 | 36 | "module without parameters": { 37 | "prefix": "mod", 38 | "body": [ 39 | "module ${moduleName} (", 40 | "\t${ports}", 41 | ");", 42 | "\t$0", 43 | "endmodule" 44 | ], 45 | "description": "Insert a module without parameter" 46 | }, 47 | 48 | "if block": { 49 | "prefix": "if", 50 | "body": [ 51 | "if (${1:conditions}) begin", 52 | "\t$0", 53 | "end" 54 | ], 55 | "description": "Insert a if block" 56 | }, 57 | 58 | "include": { 59 | "prefix": "inc", 60 | "body": [ 61 | "`include \"$1\"" 62 | ], 63 | "description": "`include \"..\"" 64 | }, 65 | 66 | "define": { 67 | "prefix": "def", 68 | "body": [ 69 | "`def $1 = $2" 70 | ], 71 | "description": "`define var = val" 72 | }, 73 | 74 | "parameter": { 75 | "prefix": "parameter", 76 | "body": [ 77 | "parameter $1 = $2;" 78 | ], 79 | "description": "paramter var = val;" 80 | }, 81 | 82 | "ifelse": { 83 | "prefix": "ifelse", 84 | "body": [ 85 | "if ( ${1:conditions} ) begin", 86 | "\t$2", 87 | "end else begin", 88 | "\t$3", 89 | "end" 90 | ], 91 | "description": "if (...) begin ... end else begin ... end" 92 | }, 93 | 94 | "for loop": { 95 | "prefix": "for", 96 | "body": [ 97 | "for ($1 = $2; $3; $4) begin", 98 | "\t$0", 99 | "end" 100 | ], 101 | "description": "for (...) begin ... end" 102 | }, 103 | 104 | "while loop": { 105 | "prefix": "while", 106 | "body": [ 107 | "while ($1) begin", 108 | "\t$2", 109 | "end" 110 | ], 111 | "description": "while (...) begin ... end" 112 | }, 113 | 114 | "function": { 115 | "prefix": "function", 116 | "body": [ 117 | "function $1;", 118 | " $2;", 119 | " $3", 120 | "endfunction" 121 | ], 122 | "description": "function (...) ... endfunction" 123 | }, 124 | 125 | "beginend block": { 126 | "prefix": "begin", 127 | "body": [ 128 | "begin", 129 | "\t$0", 130 | "end" 131 | ] 132 | }, 133 | 134 | "initial": { 135 | "prefix": "initial", 136 | "body": [ 137 | "initial begin", 138 | "\t$0", 139 | "end" 140 | ] 141 | }, 142 | //Add Snippets 143 | 144 | //simple keywards 145 | "bit":{ 146 | "prefix":"bit", 147 | "body":"bit" 148 | }, 149 | "int":{ 150 | "prefix":"int", 151 | "body":"int" 152 | }, 153 | "byte":{ 154 | "prefix":"byte", 155 | "body":"byte" 156 | }, 157 | "logic":{ 158 | "prefix":"logic", 159 | "body":"logic" 160 | }, 161 | "packed":{ 162 | "prefix":"packed", 163 | "body":"packed" 164 | }, 165 | "this":{ 166 | "prefix": "this", 167 | "body": "this" 168 | }, 169 | //Utils 170 | "array":{ 171 | "prefix":"array", 172 | "body":"[${1:8}:${2:0}]$0", 173 | "description":"insert [x:y]" 174 | }, 175 | "typedef struct packed":{ 176 | "prefix":"typedefstructpacked", 177 | "body":[ 178 | "typedef struct packed {", 179 | "\t$0", 180 | "} ${1:struct_name};" 181 | ], 182 | "description":"typedef struct packed { ... } name" 183 | }, 184 | "class":{ 185 | "prefix":"class", 186 | "body":[ 187 | "class ${1:className};", 188 | "\tfunction new();", 189 | "\t\t$0", 190 | "\tendfunction //new()", 191 | "endclass //${1}" 192 | ], 193 | "description":"class name; ... endclass" 194 | }, 195 | "class extends":{ 196 | "prefix":"classextends", 197 | "body":[ 198 | "class ${1:className} extends ${2:superClass};", 199 | "\tfunction new();", 200 | "\t\t$0", 201 | "\tendfunction //new()", 202 | "endclass //${1} extends ${2}" 203 | ], 204 | "description":"class name extends super; ... endclass" 205 | }, 206 | "task":{ 207 | "prefix":"task", 208 | "body":[ 209 | "task ${1:automatic} ${2:taskName}(${3:arguments});", 210 | "\t$0", 211 | "endtask //${1}" 212 | ], 213 | "description":"task name; ... endtask" 214 | }, 215 | "interface":{ 216 | "prefix":"interface", 217 | "body":[ 218 | "interface ${1:interfacename};", 219 | "\t$0", 220 | "endinterface //${1}" 221 | ], 222 | "description":"interface name; ... endinterface" 223 | }, 224 | "display":{ 225 | "prefix":"display", 226 | "body":[ 227 | "$$display(\"${1}\"$2);$0" 228 | ], 229 | "description":"$display(\"...\", params...)" 230 | }, 231 | "timescale":{ 232 | "prefix":"ts", 233 | "body":[ 234 | "`timescale ${1:1ps}/${2:1ps}$0" 235 | ] 236 | }, 237 | "set Module":{ 238 | "prefix":"setmodule", 239 | "body":[ 240 | "${1:mod_name} ${2:instance_name} (${3:.*}$0);" 241 | ], 242 | "description":"set module, mod i0 (.*);" 243 | }, 244 | "typedef enum":{ 245 | "prefix":"typedefenum", 246 | "body":[ 247 | "typedef enum ${1:data_type} { $0 } ${2:name};" 248 | ], 249 | "description":"typedef enum (data_type) { ... } name" 250 | }, 251 | "enum":{ 252 | "prefix":"enum", 253 | "body":[ 254 | "enum ${1:data_type} { $0 } ${2:name}" 255 | ], 256 | "description":"enum (data_type) { ... } name" 257 | }, 258 | "case":{ 259 | "prefix":"case", 260 | "body":[ 261 | "case(${1:param})", 262 | "\t", 263 | "\tdefault:$0", 264 | "endcase" 265 | ], 266 | "description":"case() ... endcase" 267 | }, 268 | "queue":{ 269 | "prefix":"queue", 270 | "body":"${1:data_type} ${2:queue_name}[$];", 271 | "description":"insert queue." 272 | }, 273 | "mailbox":{ 274 | "prefix":"mailbox", 275 | "body":[ 276 | "mailbox mbx", 277 | "${1:mbx = new();}" 278 | ], 279 | "description":"insert mailbox instance" 280 | }, 281 | "Associative array":{ 282 | "prefix":"AA", 283 | "body":"${1:data_type} ${2:name}[${3:index_type}];$0", 284 | "description":"insert Associative array(AA)." 285 | }, 286 | "assert":{ 287 | "prefix": "assert", 288 | "body": [ 289 | "assert (${1:condition}) ${2}", 290 | "else ${3:error_process}" 291 | ], 292 | "description": "insert assert() ... else ..." 293 | }, 294 | "fork-join":{ 295 | "prefix": "forkjoin", 296 | "body": [ 297 | "fork", 298 | "\t$0", 299 | "join" 300 | ], 301 | "description": "fork ... join" 302 | }, 303 | "forever":{ 304 | "prefix": "forever", 305 | "body": [ 306 | "forever begin", 307 | "\t$0", 308 | "end" 309 | ], 310 | "description": "forever begin ... end" 311 | } 312 | } -------------------------------------------------------------------------------- /src/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { Location, Position, TextDocument, CancellationToken, ProviderResult, Definition, DefinitionProvider } from 'vscode'; 2 | 3 | export class SystemVerilogDefinitionProvider implements DefinitionProvider { 4 | provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 5 | // get word start and end 6 | let textRange = document.getWordRangeAtPosition(position); 7 | 8 | // hover word 9 | let targetText = document.getText(textRange); 10 | 11 | if (targetText.search(this._excludedText) !== -1) { // systemverilog keywords 12 | return; 13 | } else { // find declaration 14 | let result = this._findDeclaration(document, position, targetText); 15 | if (result !== undefined) { 16 | return new Location(document.uri, result); 17 | } else { 18 | return; 19 | } 20 | } 21 | } 22 | 23 | private _excludedText: RegExp; 24 | 25 | constructor() { 26 | this._excludedText = RegExp(/\b(alias|always|always_comb|always_ff|always_latch|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|case|casex|casez|cell|chandle|class|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\b/); 27 | } 28 | 29 | private _findDeclaration(document: TextDocument, position: Position, target: string): Position { 30 | // check target is valid variable name 31 | if (target.search(/[A-Za-z_][A-Za-z0-9_]*/g) === -1) { 32 | return; 33 | } 34 | 35 | let variableType = String.raw`\b(input|output|inout|reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime|rand|randc)\b\s+`; 36 | let variableTypeStart = '^' + variableType; 37 | let paraType = String.raw`^\b(parameter|localparam)\b\s+\b${target}\b`; 38 | 39 | let regexTarget = RegExp(String.raw`\b${target}\b`); 40 | let regexVariableType = RegExp(variableType, 'g'); 41 | let regexVariableTypeStart = RegExp(variableTypeStart); 42 | let regexParaType = RegExp(paraType); 43 | 44 | // from previous line to first line 45 | for (let i = position.line - 1; i >= 0; i--) { 46 | // text at current line 47 | let line = document.lineAt(i).text; 48 | let element = line.replace(/\/\/.*/, '').trim().replace(/\s+/g, ' '); 49 | let lastChar = element.charAt(element.length - 1); 50 | if (lastChar === ',' || lastChar === ';') { // remove last ',' or ';' 51 | element = element.substring(0, element.length - 1); 52 | } 53 | 54 | // find variable declaration type 55 | if (element.search(regexVariableTypeStart) !== -1) { 56 | // replace type to '', like input, output 57 | let subText = element.replace(regexVariableType, '').trim(); 58 | 59 | // replace array to '', like [7:0] 60 | subText = subText.replace(/(\[.+?\])?/g, '').trim(); 61 | if (subText.search(regexTarget) !== -1) { 62 | return new Position(i, line.search(regexTarget)); 63 | } 64 | } 65 | 66 | // find parameter declaration type 67 | if (element.search(regexParaType) !== -1) { 68 | return new Position(i, line.search(regexParaType)); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/alignment.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | 4 | export function alignment(): void{ 5 | const editor = vscode.window.activeTextEditor; 6 | if (!editor) { 7 | return; 8 | } 9 | const selections = editor.selections; 10 | let selection = selections[0]; 11 | let range = new vscode.Range(selection.start.line, 0, selection.end.character > 0 ? selection.end.line : selection.end.line - 1, 1024); 12 | let text = editor.document.getText(range); 13 | let recontruct = test_new(text); 14 | 15 | editor.edit((editBuilder) => { 16 | editBuilder.replace(range, recontruct); 17 | }); 18 | } 19 | 20 | const declaration_regformat = [ 21 | /\/\/.*/, //line comment 22 | /((reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime|assign) *(signed)* *)/, //data_type 23 | /((<=.*)|(=.*);)|;/, //assignment 24 | /(\[[^:]*:[^:]*\])+/, //vector 25 | /(\[[^:]*:[^:]*\])+/, //array 26 | /.*/, // variable (/wo assignment) 27 | ]; 28 | const dec_or_assign = /(((reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime|assign) *(signed)* *))|((<=.*)|(=.*))/; 29 | 30 | const moduleio_regformat = /module .*\(/; 31 | 32 | const io_regformat = [ 33 | /\/\/.*/, //line comment 34 | /(input|output) *(reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime)*( *(signed)*)*/, //data_type 35 | /(\[[^:]*:[^:]*\])+/, //vector 36 | /.*/, // variable (/wo assignment) 37 | ]; 38 | 39 | 40 | function test_new(data:string): string{ 41 | if(check_type(data, moduleio_regformat)){ 42 | return io_proc(data); 43 | } 44 | else{ 45 | return declration_and_assignment_proc(data); 46 | } 47 | } 48 | 49 | function declration_and_assignment_proc(data: string): string{ 50 | let v1 = data.split('\n'); 51 | let ident = get_ident(v1, dec_or_assign); 52 | let v2 = decs_handle(v1); // split a statement into fields and do inner-field prealignment 53 | let v3 = common_format(v2, ident); // format the statements 54 | return v3; 55 | } 56 | 57 | function io_proc(data: string): string{ 58 | let statement_obj : StatementString = {str : data}; 59 | let mod = get_state_field(statement_obj, /module .*\(/); 60 | let modend = get_state_field(statement_obj, /\);/); 61 | let ss = statement_obj.str.replace(/,.*(\/\/.*)/g, '$1'); 62 | let ios = ss.split('\n'); 63 | let v2 = ios_handle(ios); 64 | let v3 = ios_format(v2); 65 | let v4 = common_format(v3, ' '.repeat(2)); 66 | v4 = mod + '\n' + v4 + '\n' + modend; 67 | return v4; 68 | } 69 | 70 | const ios_handle = function (ios: string[]): CodeLine[]{ 71 | ios = ios.map(io => io.replace(/,/g, '').trim()); 72 | if(vscode.workspace.getConfiguration("systemverilog")['condenseBlankLines']){ 73 | ios = cleanArray(ios); 74 | } 75 | else{ 76 | while(ios[0] == '') 77 | ios.shift(); 78 | 79 | while(ios[ios.length-1] == '') 80 | ios.pop(); 81 | } 82 | 83 | let ios_r = ios.map(io_split); 84 | ios_r = dec_align_vec(ios_r, 1); // align vector 85 | return ios_r.map(io => { 86 | if(io instanceof FormattedLine){ 87 | if(vscode.workspace.getConfiguration("systemverilog")['alignEndOfLine']){ 88 | io.fields[2] = io.fields[2].replace(',', ''); 89 | io.fields[3] = ','+io.fields[3]; 90 | } 91 | else{ 92 | if(io.fields[3][0] == ',') 93 | io.fields[3] = io.fields[3].slice(1); 94 | io.fields[2] = io.fields[2]+','; 95 | } 96 | } 97 | return io; 98 | }); 99 | } 100 | 101 | const io_split = function(io_i: string): CodeLine { 102 | if(io_i == '') 103 | return new UnformattedLine(io_i); 104 | else if(check_type(io_i, io_regformat[1])) {// split into list of io field 105 | let io = io_into_fields(io_i, io_regformat); 106 | // io_reg [comment, data_type, assignment, vector, array, variable] 107 | return new FormattedLine([io[1], io[2], io[3], io[0]]); 108 | } 109 | else if(!check_type(io_i, io_regformat[0])) 110 | return new FormattedLine(['', '', io_i.trim(), '']); 111 | else // unchange and marked as don't touch 112 | return new UnformattedLine(io_i); 113 | }; 114 | 115 | function io_into_fields(statement: string, fields: RegExp[]): string[]{ 116 | let statement_obj : StatementString = {str : statement}; 117 | let format_list: string[] = []; 118 | format_list.push(get_state_field_donttouch(statement_obj, fields[0])); //comment 119 | format_list.push(get_state_field(statement_obj, fields[1])); // assignment 120 | format_list.push(get_state_field(statement_obj, fields[2])); // dtype 121 | format_list.push(get_state_field(statement_obj, fields[3])); // vector 122 | format_list.push(get_state_field(statement_obj, fields[4])); // array 123 | format_list[1] = format_list[1].replace(/\binput\b/, 'input ').replace(/\binout\b/, 'inout '); 124 | return format_list; 125 | } 126 | 127 | const ios_format = function(decs: CodeLine[]): CodeLine[]{ 128 | let idx = decs.length - 1; 129 | while(!(decs[idx] instanceof FormattedLine) && idx >= 0) 130 | idx--; 131 | if(idx >= 0) 132 | (decs[idx] as FormattedLine).fields[2] = (decs[idx] as FormattedLine).fields[2].replace(',', '') 133 | return decs; 134 | } 135 | 136 | const common_format = function(declarations_infield: CodeLine[], ident: string): string{ 137 | let anchors = get_anchors(declarations_infield); 138 | let recontructs = declarations_infield.map(dec => dec.format(anchors, ident)); 139 | return recontructs.join('\n'); 140 | } 141 | 142 | const decs_handle = function (declarations: string[]): CodeLine[]{ 143 | let decs_r = declarations.map(dec_split); 144 | 145 | // dec [mask, dtype, vec, variable, array, assignment] 146 | decs_r = dec_align_vec(decs_r, 1); // align vector 147 | decs_r = dec_align_vec(decs_r, 3); // align array 148 | decs_r = dec_align_assignment(decs_r, 5); // align assignment 149 | 150 | return decs_r; 151 | } 152 | 153 | const dec_split = function(declaration: string): CodeLine { 154 | if(check_type(declaration, dec_or_assign)) {// split into list of declaration field 155 | let dec = split_into_fields(declaration, declaration_regformat); 156 | // dec_reg [flag, comment, data_type, assignment, vector, array, variable] 157 | let dec_arrange = [dec[1], dec[3], dec[5], dec[4], dec[2], dec[0]]; 158 | return new FormattedLine(dec_arrange); 159 | } 160 | else // unchange and marked as don't touch 161 | return new UnformattedLine(declaration); 162 | }; 163 | 164 | function dec_align_assignment(declarations: CodeLine[], assign_idx: number): CodeLine[]{ 165 | let rval_max = 0; 166 | for(let dec of declarations){ 167 | if(dec instanceof FormattedLine){ 168 | if(dec.fields[assign_idx].search(/(=)/) !== -1){ // is assignment 169 | dec.fields[assign_idx] = dec.fields[assign_idx].replace(/([\+\-\*]{1,2}|\/)/g, ' $1 '); 170 | dec.fields[assign_idx] = dec.fields[assign_idx].replace(/(,)/g, '$1 '); 171 | if(dec.fields[assign_idx].search(/<=/) !== -1){ 172 | dec.fields[assign_idx] = dec.fields[assign_idx].slice(2, dec.fields[assign_idx].length-1).trim(); 173 | rval_max = dec.fields[assign_idx].length > rval_max ? dec.fields[assign_idx].length : rval_max; 174 | dec.fields[assign_idx] = '<= '+ dec.fields[assign_idx]; 175 | } 176 | else { 177 | dec.fields[assign_idx] = dec.fields[assign_idx].slice(1, dec.fields[assign_idx].length-1).trim(); 178 | rval_max = dec.fields[assign_idx].length > rval_max ? dec.fields[assign_idx].length : rval_max; 179 | dec.fields[assign_idx] = '= '+ dec.fields[assign_idx]; 180 | } 181 | } 182 | else { 183 | dec.fields[assign_idx] = ''; 184 | } 185 | } 186 | } 187 | rval_max += 2; 188 | for(let dec of declarations){ 189 | if(dec instanceof FormattedLine){ 190 | if(dec.fields[assign_idx].search(/<=/) !== -1) 191 | dec.fields[assign_idx] = PadRight(dec.fields[assign_idx], rval_max+1) + ';'; 192 | else 193 | dec.fields[assign_idx] = PadRight(dec.fields[assign_idx], rval_max) + ';'; 194 | } 195 | } 196 | return declarations; 197 | } 198 | 199 | function dec_align_vec(declarations: CodeLine[], vec_field_idx: number): CodeLine[]{ 200 | let idxs = declarations.map(dec => get_vec_idxs(dec, vec_field_idx)); 201 | let rval_max = idxs.filter(a => a.length > 0) 202 | .reduce(reduce_max_array, []); 203 | let vec_strs = idxs.map(idx => gen_vec_string(idx, rval_max)); 204 | 205 | vec_strs.forEach((vec_str,i) => { 206 | let dec = declarations[i]; 207 | if(dec instanceof FormattedLine) 208 | dec.fields[vec_field_idx] = vec_str; 209 | }); 210 | 211 | return declarations; 212 | } 213 | 214 | function get_ident(declarations: string[], type: RegExp): string{ 215 | let first = declarations.find(dec => check_type(dec, type)); 216 | if(first) 217 | return first.match(/\s*/)[0]; // get ident from first statement 218 | else 219 | return ''; 220 | } 221 | 222 | function check_type(statement:string, type_identifier:RegExp): boolean{ 223 | return (statement.search(type_identifier) !== -1); 224 | } 225 | function split_into_fields(statement: string, fields: RegExp[]): string[] { 226 | let format_list = []; 227 | let statement_obj : StatementString = {str : statement}; 228 | format_list.push(get_state_field_donttouch(statement_obj, fields[0])); //comment 229 | format_list.push(get_state_field(statement_obj, fields[1])); // assignment 230 | format_list.push(get_state_field(statement_obj, fields[2])); // dtype 231 | if(format_list[1] == 'assign' || format_list[1] == ""){ //pure assignment 232 | format_list.push(""); //no vector 233 | format_list.push(""); //no array 234 | } 235 | else{ 236 | format_list.push(get_state_field(statement_obj, fields[3])); // vector 237 | format_list.push(get_state_field(statement_obj, fields[4])); // array 238 | } 239 | format_list.push(get_state_field(statement_obj, fields[5]).replace(/(,)/g, '$1 ')); // l_value or variable 240 | return format_list; 241 | } 242 | function get_anchors(statements_infield: CodeLine[]): number[]{ 243 | return statements_infield.filter(s => s instanceof FormattedLine) 244 | .map(s => (s as FormattedLine).fields) 245 | .reduce(reduce_max_array, []) 246 | .map(a_cnt => a_cnt > 0 ? a_cnt + 1: a_cnt); 247 | } 248 | function get_state_field(s_obj: StatementString, regx: RegExp): string{ 249 | let field = ''; 250 | let field_t = s_obj.str.match(regx); 251 | if(field_t){ 252 | field = field_t[0].trim().replace(/\s{2,}/g, ' '); 253 | s_obj.str = s_obj.str.replace(regx, ''); 254 | } 255 | return field; 256 | } 257 | function get_state_field_donttouch(s_obj: StatementString, regx: RegExp): string{ 258 | let field = ''; 259 | let field_t = s_obj.str.match(regx); 260 | if(field_t){ 261 | field = field_t[0]; 262 | s_obj.str = s_obj.str.replace(regx, ''); 263 | } 264 | return field; 265 | } 266 | function get_max(a, b){ 267 | return a > b ? a : b; 268 | } 269 | function cleanArray(actual: T[]): T[] { 270 | return actual.filter(act => act); 271 | } 272 | function PadLeft(str:string, width: number): string { 273 | return ' '.repeat(width - str.length) + str; 274 | } 275 | function PadRight(str:string, width: number): string { 276 | return str + ' '.repeat(width - str.length); 277 | } 278 | function reduce_max_array(acc: number[], val: string[]): number[]{ 279 | let res = acc.slice(0); 280 | for (let i = 0; i < res.length && i < val.length; i++) { 281 | if(val[i].length > acc[i]) 282 | res[i] = val[i].length; 283 | } 284 | return res.concat(val.slice(res.length).map(s => s.length)); 285 | } 286 | function get_vec_idxs(dec: CodeLine, vec_field_idx: number): string[] { 287 | if(dec instanceof FormattedLine) { 288 | if(dec.fields[vec_field_idx].search(/\[/) !== -1){ // has vector 289 | let vec_ary: string[] = dec.fields[vec_field_idx].split(/[\[\]:]/).slice(0,-1); 290 | return cleanArray(vec_ary); 291 | } 292 | else { 293 | return []; 294 | } 295 | } 296 | else{ 297 | return []; 298 | } 299 | } 300 | function gen_vec_string(idxs: string[], widths: number[]){ 301 | let restruc = ''; 302 | return idxs 303 | .map((idx,i) => i%2 == 0 ? `[${PadLeft(idx, widths[i])}:` : `${PadLeft(idx, widths[i])}]`) 304 | .join(''); 305 | } 306 | 307 | interface StatementString { str: string; } 308 | 309 | class FormattedLine { 310 | fields: string[]; 311 | constructor(fs: string[]) { 312 | this.fields = fs; 313 | } 314 | format(anchors: number[], ident): string { 315 | return this.fields 316 | .map((s,i) => `${PadRight(s, anchors[i])}`) 317 | .reduce((acc,str) => acc+str, ident); 318 | } 319 | } 320 | class UnformattedLine { 321 | line: string; 322 | constructor(text:string){ 323 | this.line = text; 324 | } 325 | format(anchors: number[], ident): string { 326 | return this.line; 327 | } 328 | } 329 | type CodeLine = FormattedLine | UnformattedLine; 330 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the necessary extensibility types to use in your code below 3 | import * as vscode from 'vscode'; 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | import * as hover from './hover'; 7 | import * as inst from './instantiation' 8 | import * as align from './alignment' 9 | import { SystemVerilogDefinitionProvider } from './DefinitionProvider' 10 | 11 | // This method is called when your extension is activated. Activation is 12 | // controlled by the activation events defined in package.json. 13 | export function activate(context: vscode.ExtensionContext) { 14 | // System Verilog Hover Provider 15 | let disposable = vscode.languages.registerHoverProvider('systemverilog', 16 | new hover.SystemVerilogHoverProvider() 17 | ); 18 | context.subscriptions.push(disposable); 19 | 20 | disposable = vscode.commands.registerCommand('extension.systemverilog.instantiateModule', 21 | inst.instantiateModuleInteract 22 | ) 23 | context.subscriptions.push(disposable); 24 | 25 | disposable = vscode.languages.registerDefinitionProvider('systemverilog', 26 | new SystemVerilogDefinitionProvider() 27 | ); 28 | 29 | disposable = vscode.commands.registerCommand('extension.systemverilog.alignment', 30 | align.alignment 31 | ) 32 | context.subscriptions.push(disposable); 33 | } 34 | -------------------------------------------------------------------------------- /src/hover.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as vscode from 'vscode'; 3 | 4 | export class SystemVerilogHoverProvider implements vscode.HoverProvider { 5 | private _excludedText: RegExp; 6 | constructor() { 7 | this._excludedText = RegExp(/\b(alias|always|always_comb|always_ff|always_latch|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|case|casex|casez|cell|chandle|class|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\b/); 8 | } 9 | 10 | public provideHover( 11 | document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): 12 | vscode.Hover { 13 | // get word start and end 14 | let textRange = document.getWordRangeAtPosition(position); 15 | 16 | // hover word 17 | let targetText = document.getText(textRange); 18 | 19 | if (targetText.search(this._excludedText) !== -1) { // systemverilog keywords 20 | return; 21 | } else { // find declaration 22 | let declarationText = this._findDeclaration(document, textRange, targetText); 23 | if (declarationText !== undefined) { 24 | return new vscode.Hover([ {language: 'systemverilog', value: declarationText.element}, declarationText.comment ]); 25 | } else { 26 | return; 27 | } 28 | } 29 | } 30 | 31 | private _findDeclaration(document: vscode.TextDocument, range: vscode.Range, target: string): {element: string, comment: string} { 32 | // check target is valid variable name 33 | if (target.search(/[A-Za-z_][A-Za-z0-9_]*/g) === -1) { 34 | return; 35 | } 36 | 37 | let position = range.start; 38 | 39 | // Check if the variable is a macro invocation (starts with `) 40 | let previousCharacter = document.getText( 41 | new vscode.Range( 42 | position.with(position.line, position.character-1), 43 | position)); 44 | if (previousCharacter === "`") { 45 | for (let i = position.line-1; i >= 0; i--) { 46 | // text at current line 47 | let line = document.lineAt(i).text; 48 | let pos = line.search(RegExp("`define.*" + target)); 49 | if (pos !== -1) { 50 | let comment = getComment(document, i); 51 | return { element: line, comment: comment }; 52 | } 53 | } 54 | return; // Couldn't find a macro definition in this file 55 | } 56 | 57 | let variableType = String.raw`\b(input|output|inout|reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime|rand|randc)\b\s+`; 58 | let variableTypeStart = '^' + variableType; 59 | let paraType = String.raw`^\b(parameter|localparam)\b\s+\b${target}\b`; 60 | 61 | let regexTarget = RegExp(String.raw`\b${target}\b`); 62 | let regexVariableType = RegExp(variableType, 'g'); 63 | let regexVariableTypeStart = RegExp(variableTypeStart); 64 | let regexParaType = RegExp(paraType); 65 | 66 | // from previous line to first line 67 | for (let i = position.line-1; i >= 0; i--) { 68 | // text at current line 69 | let line = document.lineAt(i).text; 70 | let element = line.replace(/\/\/.*/, '').trim().replace(/\s+/g, ' '); 71 | let lastChar = element.charAt(element.length - 1); 72 | if (lastChar === ',' || lastChar === ';') { // remove last ',' or ';' 73 | element = element.substring(0, element.length - 1); 74 | } 75 | 76 | // find variable declaration type 77 | if (element.search(regexVariableTypeStart) !== -1) { 78 | // replace type to '', like input, output 79 | let subText = element.replace(regexVariableType, '').trim(); 80 | 81 | // replace array to '', like [7:0] 82 | subText = subText.replace(/(\[.+?\])?/g, '').trim(); 83 | if (subText.search(regexTarget) !== -1) { 84 | let comment = getComment(document, i); 85 | return { element: element, comment: comment }; 86 | } 87 | } 88 | 89 | // find parameter declaration type 90 | if (element.search(regexParaType) !== -1) { 91 | let comment = getComment(document, i); 92 | return { element: element, comment: comment }; 93 | } 94 | } 95 | } 96 | } 97 | 98 | function getComment(document: vscode.TextDocument, lineNo: number) { 99 | let comment = getPrefixedComment(document, lineNo); 100 | if(comment) 101 | return comment; 102 | else { 103 | return getSuffixedComment(document, lineNo); 104 | } 105 | } 106 | 107 | function getPrefixedComment(document: vscode.TextDocument, lineNo: number) { 108 | if (lineNo == 0) { 109 | return undefined; 110 | } 111 | let i = lineNo - 1; 112 | let buf = ''; 113 | while (true) { 114 | let line = document.lineAt(i).text.trim(); 115 | if (!line.startsWith('//')) 116 | break; 117 | buf = line.substring(3) + '\n' + buf; 118 | i--; 119 | } 120 | return buf; 121 | } 122 | 123 | function getSuffixedComment(document: vscode.TextDocument, lineNo: number) : string { 124 | // Spearate comment after the declaration 125 | let line = document.lineAt(lineNo).text; 126 | let idx = line.indexOf("//"); 127 | if(idx !== -1) 128 | return line.substr(idx + 2).trim(); 129 | else 130 | return undefined; 131 | } 132 | -------------------------------------------------------------------------------- /src/instantiation.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | 5 | export function instantiateModuleInteract() { 6 | let filePath = path.dirname(vscode.window.activeTextEditor.document.fileName); 7 | selectFile(filePath).then(srcpath => { 8 | let inst = instantiateModule(srcpath); 9 | vscode.window.activeTextEditor.insertSnippet(inst); 10 | }); 11 | } 12 | 13 | function instantiateModule(srcpath: string) { 14 | if (!srcpath || !fs.statSync(srcpath).isFile) { 15 | return; 16 | } 17 | // remove comment 18 | let content = fs.readFileSync(srcpath, 'utf8').replace(/\/\/.*/g, '').replace(/\/\*[\s\S]*?\*\//g, ''); 19 | if (content.indexOf('module') === -1) { 20 | return; 21 | } 22 | // module 2001 style 23 | let moduleStart = content.indexOf('module'); 24 | let moduleEnd = content.indexOf(';', moduleStart); 25 | let moduleIO = content.substring(moduleStart, moduleEnd); 26 | let moduleName = moduleIO.match(/module\s+\b([A-Za-z_][A-Za-z0-9_]*)\b/)[1]; 27 | let parametersName = []; 28 | let portsName = []; 29 | let data_inst = []; 30 | let lines = moduleIO.split('\n'); 31 | 32 | // find all parameters and ports 33 | lines.forEach(line => { 34 | line = line.trim(); 35 | let matched = line.match(/parameter\s+\b([A-Za-z_][A-Za-z0-9_]*)\b/); 36 | if (matched !== null) { 37 | parametersName.push(matched[1]); 38 | } 39 | 40 | if (line.search(/^\b(input|output|inout)\b/) !== -1) { 41 | let variables = line.replace(/\b(input|output|inout|reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime)\b/g, '') 42 | .replace(/(\[.+?\])?/g, '').replace(/\s+/g, '').split(',').forEach(variable => { 43 | if (variable) { 44 | portsName.push(variable); 45 | } 46 | }); 47 | } 48 | }); 49 | 50 | if (portsName.length === 0) { 51 | return; 52 | } 53 | 54 | let prefix = 55 | vscode.workspace 56 | .getConfiguration("systemverilog")['instancePrefix']; 57 | 58 | let paramString = `` 59 | if (parametersName.length > 0) { 60 | paramString = `\n#(\n${instantiatePort(parametersName)})\n` 61 | } 62 | 63 | return new vscode.SnippetString() 64 | .appendText(moduleName + " ") 65 | .appendText(paramString) 66 | .appendPlaceholder(prefix) 67 | .appendPlaceholder(`${moduleName}(\n`) 68 | .appendText(instantiatePort(portsName)) 69 | .appendText(');\n'); 70 | } 71 | 72 | function instantiatePort(ports: string[]): string { 73 | let port = ''; 74 | let max_len = 0; 75 | for (let i=0; i max_len) 77 | max_len = ports[i].length; 78 | } 79 | // .NAME(NAME) 80 | for (let i = 0; i < ports.length; i++) { 81 | let element = ports[i]; 82 | let padding = max_len - element.length + 1; 83 | element = element + ' '.repeat(padding); 84 | port += `\t.${element}(${element})`; 85 | if (i !== ports.length - 1) { 86 | port += ','; 87 | } 88 | port += '\n'; 89 | } 90 | return port; 91 | } 92 | 93 | function selectFile(currentDir?: string): Thenable { 94 | currentDir = currentDir || vscode.workspace.rootPath; 95 | 96 | let dirs = getDirectories(currentDir); 97 | // if is subdirectory, add '../' 98 | if (currentDir !== vscode.workspace.rootPath) { 99 | dirs.unshift('..') 100 | } 101 | // all files ends with '.sv' 102 | let files = getFiles(currentDir) 103 | .filter(file => file.endsWith('.v') || file.endsWith('.sv')); 104 | 105 | // available quick pick items 106 | let items = dirs.concat(files); 107 | 108 | return vscode.window.showQuickPick(items) 109 | .then(selected => { 110 | if (!selected) { 111 | return; 112 | } 113 | 114 | // if is a directory 115 | let location = path.join(currentDir, selected); 116 | if (fs.statSync(location).isDirectory()) { 117 | return selectFile(location); 118 | } 119 | 120 | // return file path 121 | return location; 122 | }); 123 | } 124 | 125 | function getDirectories (srcpath: string): string[] { 126 | return fs.readdirSync(srcpath) 127 | .filter(file => fs.statSync(path.join(srcpath, file)).isDirectory()); 128 | } 129 | 130 | function getFiles (srcpath: string): string[] { 131 | return fs.readdirSync(srcpath) 132 | .filter(file => fs.statSync(path.join(srcpath, file)).isFile()); 133 | } -------------------------------------------------------------------------------- /syntaxes/systemverilog.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | fileTypes 8 | 9 | sv 10 | SV 11 | 12 | foldingStartMarker 13 | (begin)\s*(//.*)?$ 14 | foldingStopMarker 15 | ^\s*(begin)$ 16 | name 17 | System Verilog 18 | patterns 19 | 20 | 21 | match 22 | \b(automatic|cell|config|deassign|defparam|design|disable|edge|endconfig|endgenerate|endspecify|endtable|endtask|event|generate|genvar|ifnone|incdir|instance|liblist|library|localparam|macromodule|negedge|noshowcancelled|posedge|pulsestyle_onevent|pulsestyle_ondetect|real|realtime|scalared|showcancelled|specify|specparam|table|task|time|use|vectored|new)\b 23 | name 24 | keyword.other.systemverilog 25 | 26 | 27 | match 28 | \b(#|@|begin|end|fork|join|join_any|join_none|forkjoin|{|})\b 29 | name 30 | keyword.other.systemverilog 31 | 32 | 33 | match 34 | \b(initial|always|wait|force|release|assign|always_comb|always_ff|always_latch|forever|repeat|while|for|if|iff|else|case|casex|casez|default|endcase|return|break|continue|do|foreach|randomize|with|inside|dist|clocking|cover|coverpoint|property|bins|binsof|illegal_bins|ignore_bins|randcase|modport|matches|solve|static|assert|assume|before|expect|bind|extends|sequence|var|cross|ref|first_match|srandom|time|struct|packed|final|chandle|alias|tagged|extern|throughout|timeprecision|timeunit|priority|type|union|unique|uwire|wait_order|triggered|randsequence|import|export|context|pure|intersect|wildcard|within|virtual|local|const|typedef|enum|protected|this|super|endmodule|endfunction|endprimitive|endclass|endpackage|endsequence|endprogram|endclocking|endproperty|endgroup|endinterface)\b 35 | name 36 | keyword.control.systemverilog 37 | 38 | 39 | match 40 | \b(std)\b:: 41 | name 42 | support.class.systemverilog 43 | 44 | 45 | match 46 | \.(atob|atohex|atoi|atooct|atoreal|bintoa|hextoa|itoa|octtoa|realtoa|len|getc|putc|toupper|tolower|compare|icompare|substr|num|exists|first|last|name|index|find|find_first|find_last|find_index|find_first_index|find_last_index|min|max|unique|unique_index|sort|rsort|shuffle|reverse|sum|product|xor|status|kill|self|await|suspend|resume|get|put|peek|try_get|try_peek|try_put|data|eq|neq|next|prev|new|size|delete|empty|pop_front|pop_back|front|back|insert|insert_range|erase|erase_range|set|swap|clear|purge|start|finish)\b 47 | name 48 | support.function.systemverilog 49 | 50 | 51 | match 52 | \b(get_randstate|set_randstate)\b 53 | name 54 | support.function.systemverilog 55 | 56 | 57 | match 58 | \b(null|void)\b 59 | name 60 | support.constant.systemverilog 61 | 62 | 63 | captures 64 | 65 | 1 66 | 67 | name 68 | keyword.other.systemverilog 69 | 70 | 2 71 | 72 | name 73 | entity.name.type.include.systemverilog 74 | 75 | 76 | match 77 | ^\s*(`include)\s+(["<].*[">]) 78 | name 79 | meta.include.systemverilog 80 | 81 | 82 | match 83 | `(celldefine|default_nettype|define|else|elsif|endcelldefine|endif|ifdef|ifndef|include|line|nounconnected_drive|resetall|timescale|unconnected_drive|undef|begin_\w+|end_\w+|remove_\w+|restore_\w+)\b 84 | name 85 | constant.other.preprocessor.systemverilog 86 | 87 | 88 | match 89 | `\b([a-zA-Z_][a-zA-Z0-9_]*)\b 90 | name 91 | constant.other.define.systemverilog 92 | 93 | 94 | include 95 | #comments 96 | 97 | 98 | captures 99 | 100 | 1 101 | 102 | name 103 | storage.type.systemverilog 104 | 105 | 3 106 | 107 | name 108 | entity.name.type.class.systemverilog 109 | 110 | 111 | match 112 | \b(function)\b\s+(\[.*\])?\s+\b([a-zA-Z_][a-zA-Z0-9_]*)\b 113 | name 114 | meta.definition.systemverilog 115 | 116 | 117 | captures 118 | 119 | 1 120 | 121 | name 122 | storage.type.systemverilog 123 | 124 | 2 125 | 126 | name 127 | entity.name.type.class.systemverilog 128 | 129 | 130 | match 131 | ^\s*(module|function|primitive|class|package|constraint|interface|covergroup|program)\s+\b([a-zA-Z_][a-zA-Z0-9_]*)\b 132 | name 133 | meta.definition.systemverilog 134 | 135 | 136 | include 137 | #all-types 138 | 139 | 140 | match 141 | (==|===|!=|!==|<=|>=|<|>) 142 | name 143 | keyword.operator.comparison.systemverilog 144 | 145 | 146 | match 147 | (\-|\+|\*|\/|%) 148 | name 149 | keyword.operator.arithmetic.systemverilog 150 | 151 | 152 | match 153 | (!|&&|\|\||\bor\b) 154 | name 155 | keyword.operator.logical.systemverilog 156 | 157 | 158 | match 159 | (&|\||\^|~|{|}|<<|>>|\?|:) 160 | name 161 | keyword.operator.bitwise.systemverilog 162 | 163 | 164 | match 165 | '\s*\(.+\) 166 | name 167 | keyword.operator.staticcasting.systemverilog 168 | 169 | 170 | begin 171 | '{ 172 | beginCaptures 173 | 174 | 0 175 | 176 | name 177 | keyword.operator.unpackaedarrayassignment.begin.systemverilog 178 | 179 | 180 | end 181 | } 182 | endCaptures 183 | 184 | 0 185 | 186 | name 187 | keyword.operator.unpackaedarrayassignment.end.systemverilog 188 | 189 | 190 | name 191 | keyword.operator.unpackedarrayassignment.systemverilog 192 | patterns 193 | 194 | 195 | match 196 | . 197 | name 198 | constant.character.escape.systemverilog 199 | 200 | 201 | 202 | 203 | match 204 | \b(output|input|inout|and|nand|nor|or|xor|xnor|buf|not|bufif[01]|notif[01]|r?[npc]mos|tran|r?tranif[01]|pullup|pulldown)\b 205 | name 206 | support.type.systemverilog 207 | 208 | 209 | match 210 | (\b\d+)?'[sS]?([bB]\s*[0-1_xXzZ?]+|[oO]\s*[0-7_xXzZ?]+|[dD]\s*[0-9_xXzZ?]+|[hH]\s*[0-9a-fA-F_xXzZ?]+|[0-1xXzZ])((e|E)(\+|-)?[0-9]+)?(?!(\w|\?)) 211 | name 212 | constant.numeric.systemverilog 213 | 214 | 215 | include 216 | #strings 217 | 218 | 219 | match 220 | \$\b([a-zA-Z_][a-zA-Z0-9_]*)\b 221 | name 222 | support.function.systemverilog 223 | 224 | 225 | match 226 | \b([A-Z][A-Z0-9_]+)\b 227 | name 228 | constant.other.systemverilog 229 | 230 | 231 | repository 232 | 233 | all-types 234 | 235 | patterns 236 | 237 | 238 | include 239 | #storage-type-systemverilog 240 | 241 | 242 | include 243 | #storage-modifier-systemverilog 244 | 245 | 246 | 247 | comments 248 | 249 | patterns 250 | 251 | 252 | begin 253 | /\* 254 | captures 255 | 256 | 0 257 | 258 | name 259 | punctuation.definition.comment.systemverilog 260 | 261 | 262 | end 263 | \*/ 264 | name 265 | comment.block.systemverilog 266 | 267 | 268 | captures 269 | 270 | 1 271 | 272 | name 273 | punctuation.definition.comment.systemverilog 274 | 275 | 276 | match 277 | (//).*$\n? 278 | name 279 | comment.line.double-slash.systemverilog 280 | 281 | 282 | 283 | storage-type-systemverilog 284 | 285 | match 286 | \b(wire|tri|tri[01]|supply[01]|wand|triand|wor|trior|trireg|reg|parameter|integer|rand|randc|int|longint|shortint|logic|bit|byte|shortreal|string)\b 287 | name 288 | storage.type.systemverilog 289 | 290 | storage-modifier-systemverilog 291 | 292 | match 293 | \b(signed|unsigned|small|medium|large|supply[01]|strong[01]|pull[01]|weak[01]|highz[01])\b 294 | name 295 | storage.modifier.systemverilog 296 | 297 | strings 298 | 299 | patterns 300 | 301 | 302 | begin 303 | " 304 | beginCaptures 305 | 306 | 0 307 | 308 | name 309 | punctuation.definition.string.begin.systemverilog 310 | 311 | 312 | end 313 | " 314 | endCaptures 315 | 316 | 0 317 | 318 | name 319 | punctuation.definition.string.end.systemverilog 320 | 321 | 322 | name 323 | string.quoted.double.systemverilog 324 | patterns 325 | 326 | 327 | match 328 | \\. 329 | name 330 | constant.character.escape.systemverilog 331 | 332 | 333 | 334 | 335 | begin 336 | ' 337 | beginCaptures 338 | 339 | 0 340 | 341 | name 342 | punctuation.definition.string.begin.systemverilog 343 | 344 | 345 | end 346 | ' 347 | endCaptures 348 | 349 | 0 350 | 351 | name 352 | punctuation.definition.string.end.systemverilog 353 | 354 | 355 | name 356 | string.quoted.single.systemverilog 357 | patterns 358 | 359 | 360 | match 361 | \\. 362 | name 363 | constant.character.escape.systemverilog 364 | 365 | 366 | 367 | 368 | 369 | 370 | scopeName 371 | source.systemverilog 372 | uuid 373 | 789be04c-8b74-352e-8f37-63d336001277 374 | 375 | 376 | -------------------------------------------------------------------------------- /testfile.sv: -------------------------------------------------------------------------------- 1 | always_ff @( clock ) begin : blockName 2 | case 3 | 4 | endcase 5 | end 6 | always_comb begin : tea 7 | a = 8 | end 9 | // a is a variable 10 | reg k; // after comment 11 | 12 | always_comb begin 13 | k = 33; 14 | end 15 | 16 | toInst u_toInst( 17 | .a(a), 18 | .b(b), 19 | .c(c) 20 | ); 21 | 22 | toInst 23 | #( 24 | .width(width), 25 | .width2(width2) 26 | ) 27 | u_toInst( 28 | .a(a), 29 | .b(b), 30 | .c(c) 31 | ); 32 | 33 | mod_name instance_name (.*); 34 | toInst 35 | #( 36 | .width_sdajdads (width_sdajdads ), 37 | .width2_asdf (width2_asdf ) 38 | ) 39 | u_toInst( 40 | .aasdasd (aasdasd ), 41 | .bdasdasf (bdasdasf ), 42 | .cfafafafasf (cfafafafasf ) 43 | ); 44 | 45 | /* 46 | dasdas 47 | dasda 48 | */ 49 | // sdas 50 | reg aa=15; 51 | reg aaa= 33; 52 | 53 | wire [13:fd0] aa; 54 | wire [hkjghj-45: 0] bb; 55 | wire [fsdfsfs-255: 0] vv; //sdfsfs 56 | reg [12:ghjds+1] dd [35:15];//wire reg a = fdfds; 57 | 58 | assign a={dd[15][24:0],dd[14][64:9]} ; 59 | assign b=35848+fsfsf; 60 | 61 | 62 | always_comb begin 63 | a= 15; 64 | addfdf = 33 ; 65 | fff= 15 + gfdg; 66 | dsfs[7487:46]=fsdfs[fsdf]+fsdfs+fsfsd; 67 | end 68 | 69 | always_ff(@posedge clk)begin 70 | {a[65:314],b[fdsf:577]}<= 57; 71 | c[15:0] <= df; 72 | fsdf <= df+fsdfs; 73 | if(fsdfsd)begin 74 | dfdsf<= {df+fsdfsd, sfds[das:dasdas}; 75 | end 76 | else begin 77 | dfsdf <=fdfdsfsfs; 78 | fdsfds<=dsfsdfs ; 79 | end 80 | end 81 | 82 | aa 83 | toInst 84 | #( 85 | .width_sdajdads (width_sdajdads ), 86 | .width2_asdf (width2_asdf ) 87 | ) 88 | u_toInst( 89 | .aasdasd (aasdasd ), 90 | .bdasdasf (bdasdasf ), 91 | .cfafafafasf (cfafafafasf ) 92 | ); 93 | 94 | -------------------------------------------------------------------------------- /toInst.sv: -------------------------------------------------------------------------------- 1 | module toInst 2 | ( 3 | parameter width_sdajdads = 25, 4 | parameter width2_asdf = 30 5 | ) 6 | ( 7 | input [2-1:0] aasdasd, 8 | input [2-1:0] bdasdasf, 9 | output reg [width2_asdf-1:0] cfafafafasf 10 | ); 11 | endmodule; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "." 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | ".vscode-test" 15 | ] 16 | } --------------------------------------------------------------------------------