├── .gitignore ├── .no-sublime-package ├── Context.sublime-menu ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── LICENSE ├── Main.sublime-menu ├── README.md ├── Verilog Gadget.py ├── Verilog Gadget.sublime-settings ├── changelog ├── v0.6.28.txt ├── v0.8.0.txt ├── v1.0.0.md ├── v1.1.0.md ├── v1.11.0.md ├── v1.12.0.md ├── v1.2.0.md ├── v1.2.5.md ├── v1.4.0.md ├── v1.4.1.md ├── v1.5.0.md ├── v1.6.0.md ├── v1.6.2.md ├── v1.7.0.md ├── v1.8.0.md ├── v2.0.0.md ├── v2.3.0.md ├── v2.3.1.md ├── v2.4.0.md └── v2.5.0.md ├── core ├── __init__.py └── vgcore.py ├── messages.json └── template ├── modelsim-simtest.tgz ├── vcs-simtest.tgz ├── verilog_cplxm.v └── verilog_header.v /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyo 2 | -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poucotm/Verilog-Gadget/4fde7a1c7748fbfafa92df6298278dcb789fa331/.no-sublime-package -------------------------------------------------------------------------------- /Context.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "-", "id": "verilog_gadget" }, 3 | { "command": "verilog_gadget_tb_gen", "caption": "Generate Testbench" }, 4 | { "command": "verilog_gadget_tb_gen_ref_imp", "caption": "Generate Testbench Ref/Imp" }, 5 | { "command": "verilog_gadget_insert_header", "caption": "Insert Header", "args": {"args" : {"cmd":"insert"}} }, 6 | { "command": "verilog_gadget_insert_snippet", "caption": "Insert Snippet" }, 7 | { "command": "verilog_gadget_module_inst", "caption": "Instantiate Module" }, 8 | { "command": "verilog_gadget_module_wrapper", "caption": "Module Wrapper" }, 9 | { "command": "verilog_gadget_sim_template", "caption": "Simulation Template" }, 10 | { "command": "verilog_gadget_repeat_code", "caption": "Repeat Code with Numbers", "args": {"cmd" : "input"} }, 11 | { "command": "verilog_gadget_vcd_to_wavedrom", "caption": "VCD to WaveDrom" } 12 | ] 13 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+shift+insert"], "command": "verilog_gadget_insert_header", "args": {"args" : {"cmd":"insert"}} }, 3 | { "keys": ["ctrl+shift+c"], "command": "verilog_gadget_module_inst" }, 4 | { "keys": ["ctrl+f12"], "command": "verilog_gadget_repeat_code", "args": {"cmd" : "input"} }, 5 | { "keys": ["ctrl+shift+x"], "command": "verilog_gadget_align" }, 6 | { "keys": ["ctrl+shift+g"], "command": "verilog_gadget_xor_gate" }, 7 | { "keys": ["ctrl+alt+p"], "command": "verilog_gadget_insert_snippet" }, 8 | { "keys": ["ctrl+alt+v"], "command": "verilog_gadget_vcd_to_wavedrom" }, 9 | { "keys": ["alt+shift+up"], "command": "verilog_gadget_etc", "args": {"cmd" : "hex2dec"} }, 10 | { "keys": ["alt+shift+down"], "command": "verilog_gadget_etc", "args": {"cmd" : "dec2hex"} } 11 | ] 12 | -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+shift+insert"], "command": "verilog_gadget_insert_header", "args": {"args" : {"cmd":"insert"}} }, 3 | { "keys": ["ctrl+shift+c"], "command": "verilog_gadget_module_inst" }, 4 | { "keys": ["ctrl+f12"], "command": "verilog_gadget_repeat_code", "args": {"cmd" : "input"} }, 5 | { "keys": ["ctrl+shift+x"], "command": "verilog_gadget_align" }, 6 | { "keys": ["ctrl+shift+g"], "command": "verilog_gadget_xor_gate" }, 7 | { "keys": ["ctrl+shift+z"], "command": "verilog_gadget_insert_snippet" }, 8 | { "keys": ["ctrl+shift+v"], "command": "verilog_gadget_vcd_to_wavedrom" }, 9 | { "keys": ["ctrl+shift+up"], "command": "verilog_gadget_etc", "args": {"cmd" : "hex2dec"} }, 10 | { "keys": ["ctrl+shift+down"], "command": "verilog_gadget_etc", "args": {"cmd" : "dec2hex"} } 11 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+shift+insert"], "command": "verilog_gadget_insert_header", "args": {"args" : {"cmd":"insert"}} }, 3 | { "keys": ["ctrl+shift+c"], "command": "verilog_gadget_module_inst" }, 4 | { "keys": ["ctrl+f12"], "command": "verilog_gadget_repeat_code", "args": {"cmd" : "input"} }, 5 | { "keys": ["ctrl+shift+x"], "command": "verilog_gadget_align" }, 6 | { "keys": ["ctrl+shift+g"], "command": "verilog_gadget_xor_gate" }, 7 | { "keys": ["ctrl+alt+p"], "command": "verilog_gadget_insert_snippet" }, 8 | { "keys": ["ctrl+alt+v"], "command": "verilog_gadget_vcd_to_wavedrom" }, 9 | { "keys": ["alt+shift+up"], "command": "verilog_gadget_etc", "args": {"cmd" : "hex2dec"} }, 10 | { "keys": ["alt+shift+down"], "command": "verilog_gadget_etc", "args": {"cmd" : "dec2hex"} } 11 | ] -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Verilog Gadget: Generate Testbench", 4 | "command": "verilog_gadget_tb_gen" 5 | }, 6 | { 7 | "caption": "Verilog Gadget: Instantiate Module", 8 | "command": "verilog_gadget_module_inst" 9 | }, 10 | // { 11 | // "caption": "Verilog Gadget: Insert Template", 12 | // "command": "verilog_gadget_template" 13 | // }, 14 | { 15 | "caption": "Verilog Gadget: Insert Header", 16 | "command": "verilog_gadget_insert_header", 17 | "args": {"args" : {"cmd":"insert"}} 18 | }, 19 | { 20 | "caption": "Verilog Gadget: Insert Snippet", 21 | "command": "verilog_gadget_insert_snippet" 22 | }, 23 | { 24 | "caption": "Verilog Gadget: Repeat Code with Numbers", 25 | "command": "verilog_gadget_repeat_code", 26 | "args": {"cmd" : "input"} 27 | }, 28 | { 29 | "caption": "Verilog Gadget: VCD to WaveDrom", 30 | "command": "verilog_gadget_vcd_to_wavedrom" 31 | }, 32 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yongchan Jeon (Kris) 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 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "Verilog Gadget", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/Verilog Gadget/README.md"}, 21 | "caption": "README" 22 | }, 23 | { "caption": "-" }, 24 | { 25 | "caption": "Settings", 26 | "command": "edit_settings", 27 | "args": { 28 | "base_file": "${packages}/Verilog Gadget/Verilog Gadget.sublime-settings" 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Verilog Gadget for Sublime Text 2 | 3 | [![Package Control](https://img.shields.io/packagecontrol/dt/Verilog%20Gadget?logo=github&color=FF1919)][PKG] 4 | [![PayPal](https://img.shields.io/badge/paypal-donate-blue.svg)][PM] 5 | 6 | Verilog Gadget is a plugin for Sublime Text 2 and 3 designed to enhance Verilog development by providing several convenient features. 7 | These commands can be accessed through the command palette (Ctrl+Shift+P) or the context menu within .v, .vh, .sv, and .svh files. File extensions can be customized in the settings. For optimal visual experience, the [Guna theme](https://packagecontrol.io/packages/Guna) is recommended. Additionally, for linting Verilog code, the [SublimeLinter-contrib-verilator](https://packagecontrol.io/packages/SublimeLinter-contrib-verilator) plugin can be utilized. 8 | 9 | #### Verilog Gadget: Instantiate Module (ctrl+shift+c) 10 | 11 | Automatically parses module ports in the current file and generates an instance text of the module, which is copied to the clipboard for easy pasting. 12 | 13 | * It parses module ports for the currently open file 14 | * It generates an instance text of the module 15 | * It copies generated text to clipboard 16 | * Then, you can paste the text to the desired location 17 | * Supports Verilog-1995, Verilog-2001 style ports and parameters 18 | * example) 19 | 20 | ![Image][S1] 21 | 22 | #### Verilog Gadget: Generate Testbench 23 | 24 | Creates a simple testbench with an instance and signals of the module, supporting both Verilog-1995 and Verilog-2001 style ports and parameters. 25 | 26 | * It parses module ports for the currently open file 27 | * It generates a simple testbench with an instance and signals of the module 28 | * The testbench is created as a systemverilog file 29 | * Supports Verilog-1995, Verilog-2001 style ports and parameters 30 | * example) 31 | 32 | ![Image][S2] 33 | 34 | #### Verilog Gadget: Simulaton Template 35 | 36 | Generates files for simulation based on customizable templates, with support for tools like ModelSim and VCS. 37 | 38 | * It creates files for simulation based on the template 39 | * You can make your own template as a compressed file (.zip,.tar,.tgz) 40 | * You can specify the path of your template (`"simulation_template"`,`"simulation_directory`") 41 | * `'example-modelsim'` is the template for modelsim, `'example-vcs'` is the template for vcs 42 | * It automatically generates the testbench files for the current view 43 | * It changes keywords in files of the template (`{{TESTBENCH FILE}}`, `{{TESTBENCH NAME}}`, `{{MODULE FILE}}`, `{{MODULE NAME}}`,`{{MODULE PORTLIST}}`) 44 | * example) 45 | 46 | ![Image][G1] 47 | 48 | #### Verilog Gadget: Insert Header (ctrl+shift+insert) 49 | 50 | Allows insertion of a user-defined header description into files, with placeholders for current date, time, filename, and other details. 51 | 52 | * You can insert your own header-description in a format from the file specified in settings 53 | * `{YEAR}` is replaced as the current year 54 | * `{DATE}` is replaced as the create date 55 | * `{TIME}` is replaced as the create time 56 | * `{RDATE}` is replaced as the revised date 57 | * `{RTIME}` is replaced as the revised time 58 | * `{FILE}` is replaced as the file name 59 | * `{TABS}` is replaced as the tab size 60 | * `{SUBLIME_VERSION}` is replaced as the current sublime text version 61 | * example) [__header example__][L3] 62 | 63 | ![Image][S8] 64 | 65 | #### Verilog Gadget: Repeat Code with Numbers (ctrl+f12) 66 | 67 | Enables repeating selected code with formatted incremental or decremental numbers, supporting Python's format symbols for various number formats. 68 | 69 | * Select codes you want to repeat, this may include Python's format symbol, such as {...} 70 | * Enter a range in the input panel as the following : [from]~[to],[↓step],[→step] 71 | ``(e.g. 0~10 or 0~10,2 or 10~0,-1 or 0~5,1,1 ...)`` 72 | * [↓step] means the row step, default is 1, [→step] means the column step, default is 0 73 | * The code is repeated in incremental or decremental numbers 74 | * Python's format symbol supports variable formats : binary, hex, leading zeros, ... 75 | * To use '{' as it is, you must enter twice like '{{' 76 | * Refer to Python's format symbol here, [https://www.python.org/dev/peps/pep-3101/](https://www.python.org/dev/peps/pep-3101/) 77 | * For **sublime text 2 (python 2.x)**, you must put an index behind ':' in curly brackets like `foo {0:5b} bar {1:3d}` 78 | * example) 79 | 80 | ![Image][S3] 81 | 82 | * The index can be used to repeat the same number 83 | * example) 84 | 85 | ![Image][S6] 86 | 87 | * It is possible to repeat numbers with clipboard text (line by line) 88 | * Use ``{cb}`` for clipboard text 89 | * example) 90 | 91 | ![Image][S5] 92 | 93 | * The simplest way is added using multiple selection. 94 | * Select multiple strings (or blanks) using `shift + l` or `ctrl + LButton` 95 | * You can also select sparsely. 96 | * example) [] ← selected position, set a range - start = 1, step = 2 97 | ```systemverilog 98 | abc <= []; abc <= 1; 99 | def <= []; def <= 3; 100 | ghi <= []; → ghi <= 5; 101 | jkl <= []; jkl <= 7; 102 | mno <= []; mno <= 9; 103 | ``` 104 | 105 | #### Verilog Gadget: Alignment (ctrl+shift+x) 106 | 107 | * Select a range to apply the alignment to 108 | * Press the shortcut key 109 | * Alignment is based on the longest length of the left hand side in the selection 110 | * Tabs are replaced as spaces except indentation 111 | * example) 112 | 113 | ![Image][S4] 114 | 115 | #### Verilog Gadget: Insert Snippet (ctrl+alt+p) 116 | 117 | * You can make your own parameterized snippets like this [__example__][L1] 118 | * Add your snippet settings like [__this__][L2] 119 | * Run __*Insert Snippet*__ command 120 | * example) 121 | 122 | ![Image][S7] 123 | 124 | #### Verilog Gadget: Convert Digits (HEX → DEC, DEC → HEX) (alt+shift+up, alt+shift+down) 125 | 126 | * Select Digits and Press the key (alt+shift+↑) - 10 → 16 127 | * Select Digits and Press the key (alt+shift+↓) - 16 → 10 128 | 129 | #### Verilog Gadget: VCD to WaveDrom (ctrl+alt+v) 130 | 131 | * [__WaveDrom__][L4] : digital timing diagram editor 132 | * Open .vcd file (a clock should be included) 133 | * Run __*VCD to WaveDrom*__ command 134 | 135 | ![Image][S9] 136 | 137 | ### Verilog Linter (another package) 138 | 139 | [__SublimeLinter-contrib-verilator__](https://packagecontrol.io/packages/SublimeLinter-contrib-verilator) 140 | 141 | ![Image](https://raw.githubusercontent.com/poucotm/Links/master/image/SublimeLinter-Contrib-Verilator/vl-cap.gif) 142 | 143 | ### Donate 144 | 145 | [![Doate Image](https://raw.githubusercontent.com/poucotm/Links/master/image/PayPal/donate-paypal.png)][PM] 146 | 147 | If you find Verilog Gadget helpful and would like to support its continued development, consider making a donation. Your contributions are appreciated and assist in the ongoing improvement of the plugin. 148 | 149 | ### Issues 150 | 151 | When you have an issue, tell me through [https://github.com/poucotm/Verilog-Gadget/issues](https://github.com/poucotm/Verilog-Gadget/issues), or send me an e-mail poucotm@gmail.com 152 | 153 | [S1]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-inst.gif 154 | [S2]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-tbg.gif 155 | [S3]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-rep.gif 156 | [S4]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-aln.gif 157 | [S5]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-rep-clip.gif 158 | [S6]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-rep-idx.gif 159 | [S7]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-snippet.gif 160 | [S8]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-header.gif 161 | [S9]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/wavdrom.png 162 | [G1]:https://raw.githubusercontent.com/poucotm/Links/master/image/Verilog-Gadget/vg-sim.gif 163 | [L1]:https://github.com/poucotm/Verilog-Gadget/blob/master/template/verilog_cplxm.v 164 | [L2]:https://github.com/poucotm/Verilog-Gadget/blob/master/Verilog%20Gadget.sublime-settings 165 | [L3]:https://github.com/poucotm/Verilog-Gadget/blob/master/template/verilog_header.v 166 | [L4]:https://wavedrom.com 167 | [PP]:https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=89YVNDSC7DZHQ "PayPal" 168 | [PM]:https://www.paypal.me/poucotm/1.0 "PayPal" 169 | [PKG]:https://packagecontrol.io/packages/Verilog%20Gadget "Verilog Gadget" 170 | -------------------------------------------------------------------------------- /Verilog Gadget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ----------------------------------------------------------------------------- 3 | # Author : yongchan jeon (Kris) poucotm@gmail.com 4 | # File : Verilog Gadget.py 5 | # Create : 2020-01-01 20:51:05 6 | # Editor : sublime text3, tab size (4) 7 | # ----------------------------------------------------------------------------- 8 | 9 | import sublime, sublime_plugin 10 | import sys, imp 11 | import traceback 12 | import os 13 | 14 | ## sub-modules ______________________________________________ 15 | 16 | try: 17 | # reload 18 | mods = ['Verilog Gadget.core.vgcore'] 19 | for mod in mods: 20 | if any(mod == m for m in list(sys.modules)): 21 | imp.reload(sys.modules[mod]) 22 | # import 23 | from .core import vgcore 24 | from .core.vgcore import (VerilogGadgetInsertSub, VerilogGadgetModuleInst, VerilogGadgetTbGen, VerilogGadgetTbGenRefImp, VerilogGadgetSimTemplate, 25 | VerilogGadgetModuleWrapper, VerilogGadgetInsertHeader, VerilogGadgetRepeatCode, VerilogGadgetAlign, VerilogGadgetXorGate, VerilogGadgetInsertSnippet, 26 | VerilogGadgetEventListener, VerilogGadgetVcdToWavedrom, VerilogGadgetEtc) 27 | import_ok = True 28 | except Exception: 29 | print ('VERILOG GADGET : ERROR ______________________________________') 30 | traceback.print_exc() 31 | print ('=============================================================') 32 | import_ok = False 33 | 34 | # package control 35 | try: 36 | from package_control import events 37 | package_control_installed = True 38 | except Exception: 39 | package_control_installed = False 40 | 41 | 42 | ## plugin_loaded ____________________________________________ 43 | 44 | def plugin_loaded(): 45 | global import_ok 46 | if not import_ok: 47 | sublime.status_message("(*E) Verilog Gadget : Error in importing sub-modules.") 48 | return 49 | 50 | if package_control_installed and (events.install('Verilog Gadget') or events.post_upgrade('Verilog Gadget')): 51 | def installed(): 52 | vgcore.loaded() 53 | 54 | sublime.set_timeout_async(installed, 1000) 55 | else: 56 | vgcore.loaded() 57 | return 58 | -------------------------------------------------------------------------------- /Verilog Gadget.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | 3 | /* UI Configuration _________________________________________ 4 | */ 5 | 6 | "context_menu": true, 7 | "verilog_ext": [ ".v", ".vh", ".sv", ".svh" ], // for context_menu 8 | 9 | "Generate Testbench": "show", 10 | "Generate Testbench Ref/Imp": "hide", 11 | "Module Wrapper": "hide", 12 | "Simulation Template": "show", 13 | "Insert Header": "show", 14 | "Insert Snippet": "show", 15 | "Instantiate Module": "show", 16 | "Repeat Code with Numbers": "show", 17 | "VCD to WaveDrom": "show", 18 | 19 | /* Core settings ____________________________________________ 20 | */ 21 | 22 | // default prefix for a instance name 23 | "inst_prefix": "inst_", 24 | 25 | // alignment (tab or space) 26 | "tab_assignment": false, 27 | "tab_port_declaration": true, 28 | "tab_signal_declaration": true, 29 | "tab_port_connection": false, 30 | 31 | /* Header / Snippet _________________________________________ 32 | */ 33 | 34 | // header template file path 35 | "header": "example", 36 | "auto_update_header": true, 37 | 38 | // parameterized snippets 39 | "snippets" : { 40 | "Complex Multiplier" : { // example 41 | "codes" : "Packages/Verilog Gadget/template/verilog_cplxm.v", 42 | "param" : ["AB", "BB"], 43 | "evals" : ["ZB=AB+BB+1"], // simple calculation only 44 | "descr" : "INPUTA , INPUTB [ complex mult ]", 45 | "regex" : "\\s*(?P\\d+)\\s*[,.\\s]\\s*(?P\\d+)\\s*"// regex for parameter input 46 | }, 47 | /* add more snippets here */ 48 | }, 49 | 50 | /* for Testbench ____________________________________________ 51 | */ 52 | 53 | "reset" : [], // default asynchronous reset name, leave a blank not to use it 54 | "sreset" : ["srstb"], // default synchronous reset name, leave a blank not to use it 55 | "clock" : ["clk", "uclk", "cclk"], // default clock name, leave a blank not to use it 56 | "wave_type" : "fsdb", // type of waveform, one of "fsdb", "vpd", "shm", "vcd" 57 | "task_init" : true, 58 | "task_drive": true, 59 | 60 | /* Simulation Template ______________________________________ 61 | */ 62 | 63 | // specify a your own template path (compressed file - zip,tgz,tar) 64 | // there are 2 examples - example-modelsim, example-vcs 65 | "simulation_template" : "example-modelsim", 66 | "simulation_directory" : "simtest" 67 | 68 | } 69 | -------------------------------------------------------------------------------- /changelog/v0.6.28.txt: -------------------------------------------------------------------------------- 1 | Change Log: v0.6.28 2 | 3 | * Fix 4 | - Context.sublime-menu : remove last comma 5 | - Set UTF-8 encoding header (for ST2) : Verilog Gadget.py 6 | * Update 7 | - Starting change log message 8 | - Context Menu Commands : Verilog Gadget.py, Context.sublime-menu 9 | -------------------------------------------------------------------------------- /changelog/v0.8.0.txt: -------------------------------------------------------------------------------- 1 | Change Log: v0.8.0 2 | 3 | * Fix 4 | - fix up parsing `,` concatenated port declaration 5 | -------------------------------------------------------------------------------- /changelog/v1.0.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.0.0 : 9/2/2017 5 | 6 | * Update 7 | - `Insert Template` command is deprecated 8 | - Add key maps for `Instantiate Module`, `Insert Header` 9 | 10 | * New function 11 | - uses Guna's message display in status bar 12 | -------------------------------------------------------------------------------- /changelog/v1.1.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.1.0 : 9/9/2017 5 | 6 | * New function 7 | - add `Verilog Gadget : Alignment` 8 | 9 | * Bug Fix 10 | - add missed key maps for OSX/Linux 11 | 12 | -------------------------------------------------------------------------------- /changelog/v1.11.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.11.0 : 12/8/2020 5 | 6 | * Update 7 | - use multiple default resets, sresets, clocks in settings 8 | e.g.) "clock" : ["clk", "uclk", "cclk"] 9 | 10 | -------------------------------------------------------------------------------- /changelog/v1.12.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.12.0 : 12/27/2020 5 | 6 | * Update 7 | - add alignments for port declaration, signal declaration, instance port connection 8 | 9 | -------------------------------------------------------------------------------- /changelog/v1.2.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.2.0 : 9/12/2017 5 | 6 | * Bug Fix 7 | - Fix up wrong size of port signal for generate testbench 8 | -------------------------------------------------------------------------------- /changelog/v1.2.5.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.2.5 : 11/07/2017 5 | 6 | * Additional Function 7 | - add {cb} keyword for repeating codes with clipboard text 8 | -------------------------------------------------------------------------------- /changelog/v1.4.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.4.0 : 12/03/2018 5 | 6 | * New function 7 | - 'Generate Testbench Ref/Imp' 8 | 9 | * Add Option 10 | - show/hide command in the context menu 11 | -------------------------------------------------------------------------------- /changelog/v1.4.1.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.4.1 : 1/16/2019 5 | 6 | * Bug Fix 7 | - Fix up error in parsing port with default value 8 | -------------------------------------------------------------------------------- /changelog/v1.5.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.5.0 : 3/25/2019 5 | 6 | * New Feauture 7 | - add `Insert Snippet` command, it is like parameterizable template -------------------------------------------------------------------------------- /changelog/v1.6.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.6.0 : 7/20/2019 5 | 6 | * New Feauture 7 | - Smart `Insert Header` : Support revised date and time, Update header automatically when saving (or saving as) 8 | -------------------------------------------------------------------------------- /changelog/v1.6.2.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.6.2 : 7/21/2019 5 | 6 | * New Feauture 7 | - Smart `Insert Header` : Support revised date {RDATE} and time {RTIME}, 8 | Update header automatically when saving (or saving as) 9 | -------------------------------------------------------------------------------- /changelog/v1.7.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.7.0 : 4/18/2020 5 | 6 | * New Feauture 7 | - `VCD to WaveDrom` : Conversion VCD text to WaveDrom's 8 | -------------------------------------------------------------------------------- /changelog/v1.8.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v1.8.0 : 11/14/2020 5 | 6 | * New Feauture 7 | - `Simulation Template` : generates files for simulation based on your own template with a generated testbench file 8 | when you making a template, the following keywords can be used. 9 | {{TESTBENCH FILE}}, {{TESTBENCH NAME}}, {{MODULE FILE}}, {{MODULE NAME}} 10 | -------------------------------------------------------------------------------- /changelog/v2.0.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v2.0.0 : 2/25/2023 5 | 6 | * Open Core Source 7 | 8 | 9 | -------------------------------------------------------------------------------- /changelog/v2.3.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v2.3.0 : 4/9/2024 5 | 6 | * New Feauture 7 | - `Convert Digits : HEX → DEC, DEC → HEX` : Select Digits and Press 'ctrl+alt+up' = HEX → DEC, 'ctrl+alt+down' = DEC → HEX 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /changelog/v2.3.1.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v2.3.1 : 4/9/2024 5 | 6 | * New Feauture 7 | - `Convert Digits : HEX → DEC, DEC → HEX` : Select Digits and Press 'alt+shift+up' = HEX → DEC, 'alt+shift+down' = DEC → HEX 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /changelog/v2.4.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v2.4.0 : 4/12/2024 5 | 6 | * New Feauture 7 | - add simple 'repeat code w/ numbers' way using multiple selection 8 | - select strings using multiple selection, then press the shortcut key : ctrl+f12 and enter a range : start, step 9 | - e.g) start = 1, step = 2 10 | foo = []; foo = 1; 11 | foo = []; → foo = 3; 12 | foo = []; foo = 5; 13 | foo = []; foo = 7; 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /changelog/v2.5.0.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | *** 3 | 4 | #### v2.5.0 : 5/15/2024 5 | 6 | * Midify Feauture 7 | - Repeat Code with Numbers 8 | - {cb} can be used alone 9 | - e.g) 10 | 1. in the clipboard 11 | A 12 | B 13 | C 14 | 2. type just `sleep = {cb}` and run (ctrl+f12) 15 | 3. result 16 | sleep = A 17 | sleep = B 18 | sleep = C 19 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poucotm/Verilog-Gadget/4fde7a1c7748fbfafa92df6298278dcb789fa331/core/__init__.py -------------------------------------------------------------------------------- /core/vgcore.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | # ----------------------------------------------------------------------------- 3 | # Author : yongchan jeon (Kris) poucotm@gmail.com 4 | # File : vgcore.py 5 | # Create : 2018-02-09 22:47:28 6 | # Editor : sublime text3, tab size (4) 7 | # ----------------------------------------------------------------------------- 8 | 9 | import sublime 10 | import sublime_plugin 11 | import os 12 | import shutil 13 | import datetime 14 | import time 15 | import re 16 | from math import ceil 17 | import traceback 18 | import threading 19 | import hashlib 20 | import zipfile 21 | import tarfile 22 | 23 | try: 24 | from Guna.core.api import GunaApi 25 | guna_installed = True 26 | except Exception: 27 | guna_installed = False 28 | ST3 = int(sublime.version()) >= 3000 29 | cachepath = '' 30 | 31 | def get_prefs(): 32 | return sublime.load_settings('Verilog Gadget.sublime-settings') 33 | 34 | def check_ext(file_name, view_name): 35 | vgs = get_prefs() 36 | if not vgs.get("context_menu", True): 37 | return False 38 | try: 39 | _name = file_name if view_name == "" else view_name 40 | ext = os.path.splitext(_name)[1] 41 | ext = ext.lower() 42 | ext_l = vgs.get("verilog_ext") 43 | if any(ext == s for s in ext_l): 44 | return True 45 | else: 46 | return False 47 | except: 48 | return False 49 | 50 | def check_ext_cmd(file_name, view_name, cmd): 51 | vgs = get_prefs() 52 | if not vgs.get("context_menu", True): 53 | return False 54 | try: 55 | _name = file_name if view_name == "" else view_name 56 | ext = os.path.splitext(_name)[1] 57 | ext = ext.lower() 58 | ext_l = vgs.get("verilog_ext") 59 | if any(ext == s for s in ext_l): 60 | if vgs.get(cmd, 'hide') == 'show': 61 | return True 62 | else: 63 | return False 64 | else: 65 | return False 66 | except: 67 | return False 68 | 69 | def check_vcd_cmd(file_name, view_name, cmd): 70 | vgs = get_prefs() 71 | if not vgs.get("context_menu", True): 72 | return False 73 | try: 74 | _name = file_name if view_name == "" else view_name 75 | ext = os.path.splitext(_name)[1] 76 | ext = ext.lower() 77 | if ext == '.vcd': 78 | if vgs.get(cmd, 'hide') == 'show': 79 | return True 80 | else: 81 | return False 82 | else: 83 | return False 84 | except: 85 | return False 86 | 87 | def disp_msg(msg): 88 | if guna_installed: 89 | GunaApi.info_message(24, ' Verilog Gadget : ' + msg, 5, 1) 90 | else: 91 | sublime.status_message(' Verilog Gadget : ' + msg) 92 | 93 | def disp_error(msg): 94 | if guna_installed: 95 | GunaApi.alert_message(3, ' Verilog Gadget : ' + msg, 10, 1) 96 | else: 97 | sublime.status_message(' Verilog Gadget : ' + msg) 98 | 99 | def disp_exept(): 100 | print ('VERILOG GADGET : ERROR ______________________________________') 101 | traceback.print_exc() 102 | print ('=============================================================') 103 | disp_error("Error is occured. Please, see the trace-back information in Python console.") 104 | 105 | def len_tab(stxt, tabs): 106 | slen = 0 107 | for c in stxt: 108 | slen += (tabs - slen % tabs) if c == '\t' else 1 109 | return slen 110 | 111 | def get_region(view, txtr): 112 | regn = sublime.Region(view.line(txtr.begin()).begin(), view.line(txtr.end()).end()) 113 | rgnl = view.lines(regn) 114 | if regn.end() != rgnl[-1].end(): 115 | regn = sublime.Region(regn.begin(), regn.end() - 1) 116 | return regn 117 | 118 | def trim_space(text): 119 | return re.sub(re.compile(r'^\s+|\s+$'), '', text) 120 | 121 | def regex_search(pattern, text): 122 | mobj = re.compile(pattern).search(text) 123 | return mobj.group() if mobj else '' 124 | 125 | def remove_comment_line_space(codes): 126 | 127 | def remove_comments(pattern, text): 128 | txts = re.compile(pattern, re.DOTALL).findall(text) 129 | for txt in txts: 130 | if isinstance(txt, str): 131 | blnk = '\n' * (txt.count('\n')) 132 | text = text.replace(txt, blnk) 133 | elif isinstance(txt, tuple) and txt[1]: 134 | blnk = '\n' * (txt[1].count('\n')) 135 | text = text.replace(txt[1], blnk) 136 | return text 137 | codes = remove_comments(r'/\*.*?\*/', codes) 138 | codes = re.sub(re.compile(r'//.*?$', re.MULTILINE), '', codes) 139 | codes = remove_comments(r'(@\s*?\(\s*?\*\s*?\))|(\(\*.*?\*\))', codes) 140 | codes = re.sub(re.compile(r'\s*[\n]'), ' ', codes) 141 | codes = re.sub(re.compile(r';'), '; ', codes) 142 | codes = re.sub(re.compile(r'\['), ' [', codes) 143 | codes = re.sub(re.compile(r'\s+'), ' ', codes) 144 | return codes 145 | 146 | def parse_param(text, prefix, param_list): 147 | ptype = '' 148 | isprm = False 149 | try: 150 | for strl in text.split(','): 151 | p_mch = re.compile(prefix+r'(?P.*?)(?P\w+)\s*=(?P.*)').search(strl) 152 | if p_mch: 153 | ptype = trim_space(p_mch.group('type')) 154 | ptype = re.sub(re.compile(r'\s{2,}'), ' ', ptype) 155 | pname = p_mch.group('name') 156 | p_val = trim_space(p_mch.group('value')) 157 | param_list.append([prefix, ptype, pname, p_val]) 158 | isprm = True 159 | else: 160 | p_mch = re.compile(r'(?P\w+)\s*=(?P.*)').search(strl) 161 | if p_mch and isprm: 162 | pname = p_mch.group('name') 163 | p_val = trim_space(p_mch.group('value')) 164 | param_list.append([prefix, ptype, pname, p_val]) 165 | except: 166 | disp_except('Syntax error in verilog file or unexpected error occured in parsing parmeters') 167 | 168 | def parse_ports(text, ports_list): 169 | try: 170 | p_dir = '' 171 | psize = '' 172 | for strl in text.split(','): 173 | strl = re.sub(r'=.*', '', strl) 174 | stra = re.sub(r'\[.*?\]', ' ', strl) 175 | pntmp = re.compile(r'\w+').findall(stra) 176 | pname = pntmp[-1] if len(pntmp) > 0 else '' 177 | pdtmp = regex_search(r'(?\w+)').match(moddef) 210 | module = modmch.group('name') if modmch else '' 211 | prttxt = regex_search(r'(?<=\().*(?=\))', moddef) 212 | if mcodes == '' or moddef == '' or module == '': 213 | disp_error(call_from + " : Fail to find 'module'") 214 | return '', None, None, None 215 | except: 216 | disp_error(call_from + " : Fail to find 'module'") 217 | return '', None, None, None 218 | param_list = [] 219 | if prmtxt: 220 | parse_param(prmtxt, "parameter", param_list) 221 | ports_list = [] 222 | if prttxt: 223 | parse_ports(prttxt, ports_list) 224 | mcodes = re.sub(re.compile(r'module[^;]+;'), '', mcodes) 225 | portsl = re.compile(r'(? 0 else '' 234 | pdtmp = regex_search(r'(? 80: 461 | if plen > 0: 462 | string = "\t" + mod_name + " #(\n" 463 | for i, _strl in enumerate(prmonly_list): 464 | string = string + "\t" * 3 + "." + _strl[2] + "(" + _strl[2] + ")" 465 | if i != plen - 1: 466 | string = string + ",\n" 467 | else: 468 | string = string + "\n" 469 | string = string + "\t" * 2 + ") " + iprefix + mod_name + " (\n" 470 | else: 471 | string = "\t" + mod_name + " " + iprefix + mod_name + "\n" + "\t" * 2 + "(\n" 472 | for i, _strl in enumerate(port_list): 473 | sp = lmax - len(_strl[2]) 474 | if _strl[0] == 'input' and _strl[2] in clk_list: 475 | pmap = clk_list[0] 476 | elif _strl[0] == 'input' and _strl[2] in rst_list: 477 | pmap = rst_list[0] 478 | elif _strl[0] == 'input' and _strl[2] in srst_list: 479 | pmap = srst_list[0] 480 | else: 481 | pmap = _strl[2] 482 | if outx and _strl[0] == 'output': 483 | string = string + "\t" * 3 + "." + _strl[2] + " " * sp + " ()" 484 | else: 485 | string = string + "\t" * 3 + "." + _strl[2] + " " * sp + " (" + pmap + ")" 486 | if i != len(port_list) - 1: 487 | string = string + ",\n" 488 | else: 489 | string = string + "\n" 490 | string = string + "\t" * 2 + ");\n" 491 | else: 492 | if plen > 0: 493 | string = "\t" + mod_name + " #(" 494 | for i, _strl in enumerate(prmonly_list): 495 | string = string + "." + _strl[2] + "(" + _strl[2] + ")" 496 | if i != plen - 1: 497 | string = string + ", " 498 | string = string + ") " + iprefix + mod_name + " (" 499 | else: 500 | string = "\t" + mod_name + " " + iprefix + mod_name + " (" 501 | for i, _strl in enumerate(port_list): 502 | if _strl[0] == 'input' and _strl[2] in clk_list: 503 | pmap = clk_list[0] 504 | elif _strl[0] == 'input' and _strl[2] in rst_list: 505 | pmap = rst_list[0] 506 | elif _strl[0] == 'input' and _strl[2] in srst_list: 507 | pmap = srst_list[0] 508 | else: 509 | pmap = _strl[2] 510 | if outx and _strl[0] == 'output': 511 | string = string + "." + _strl[2] + "()" 512 | else: 513 | string = string + "." + _strl[2] + "(" + pmap + ")" 514 | if i != len(port_list) - 1: 515 | string = string + ", " 516 | string = string + ");\n" 517 | return string 518 | 519 | class VerilogGadgetModuleInst(sublime_plugin.TextCommand): 520 | 521 | def run(self, edit): 522 | if not check_ext(self.view.file_name(), self.view.name()): 523 | return 524 | text = self.view.substr(sublime.Region(0, self.view.size())) 525 | text = remove_comment_line_space(text) 526 | module, ports_list, param_list, clk_list, rst_list = parse_module(text, 'Instantiate Module') 527 | if not module: 528 | return 529 | vgs = get_prefs() 530 | iprefix = vgs.get("inst_prefix", "inst_") 531 | minst = module_inst(module, ports_list, param_list, [], [], [], iprefix) 532 | sublime.set_clipboard(minst) 533 | disp_msg("Instantiate Module : Copied to Clipboard") 534 | 535 | def is_visible(self): 536 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Instantiate Module') 537 | 538 | class VerilogGadgetTbGen(sublime_plugin.TextCommand): 539 | 540 | def run(self, edit, args=None): 541 | fname = self.view.file_name() 542 | if not check_ext(fname, self.view.name()): 543 | return 544 | text = self.view.substr(sublime.Region(0, self.view.size())) 545 | text = remove_comment_line_space(text) 546 | module, ports_list, param_list, clk_list, rst_list = parse_module(text, 'Generate Testbench') 547 | if not module: 548 | return 549 | vgs = get_prefs() 550 | iprefix = vgs.get("inst_prefix", "inst_") 551 | resetl = vgs.get('reset', []) 552 | sresetl = vgs.get('sreset', []) 553 | clockl = vgs.get('clock', []) 554 | resetl = resetl + rst_list 555 | sresetl = sresetl 556 | clockl = clockl + clk_list 557 | clkrstl = clockl + resetl + sresetl 558 | declp = declare_param(param_list) 559 | decls = declare_sigls(ports_list, clkrstl, 'logic') 560 | if args != None and args['cmd'] == 'refimp': 561 | minst = module_inst((module + '_ref'), ports_list, param_list, clockl, resetl, sresetl, iprefix, False) 562 | mimpl = module_inst((module + '_imp'), ports_list, param_list, clockl, resetl, sresetl, iprefix, True) 563 | minst = minst + '\n' + mimpl 564 | else: 565 | minst = module_inst(module, ports_list, param_list, clockl, resetl, sresetl, iprefix, False) 566 | str_dump = '' 567 | wtype = vgs.get("wave_type", "") 568 | if wtype == "fsdb": 569 | str_dump = """ 570 | if ( $test$plusargs("fsdb") ) begin 571 | $fsdbDumpfile("tb_""" + module + """.fsdb"); 572 | $fsdbDumpvars(0, "tb_""" + module + """", "+mda", "+functions"); 573 | end""" 574 | elif wtype == "vpd": 575 | str_dump = """ 576 | $vcdplusfile("tb_""" + module + """.vpd"); 577 | $vcdpluson(0, "tb_""" + module + """");""" 578 | elif wtype == "shm": 579 | str_dump = """ 580 | $shm_open("tb_""" + module + """.shm"); 581 | $shm_probe();""" 582 | elif wtype == "vcd": 583 | str_dump = """ 584 | if ( $test$plusargs("vcd") ) begin 585 | $dumpfile("tb_""" + module + """.vcd"); 586 | $dumpvars(0, "tb_""" + module + """"); 587 | end""" 588 | declp = '' if len(declp) == 0 else declp + '\n' 589 | decls = '' if len(decls) == 0 else decls + '\n' 590 | arstb = resetl[0] if len(resetl) > 0 else '' 591 | srstb = sresetl[0] if len(sresetl) > 0 else '' 592 | clock = clockl[0] if len(clockl) > 0 else '' 593 | sclks = '' 594 | if clock: 595 | sclks = """ 596 | // clock 597 | logic """ + clock + """; 598 | initial begin 599 | """ + clock + """ = '0; 600 | forever #(0.5) """ + clock + """ = ~""" + clock + """; 601 | end\n""" 602 | arsts = '' 603 | if arstb: 604 | arsts = """ 605 | // asynchronous reset 606 | logic """ + arstb + """; 607 | initial begin 608 | """ + arstb + """ <= '0; 609 | #10 610 | """ + arstb + """ <= '1; 611 | end\n""" 612 | srsts = '' 613 | if srstb: 614 | srsts = """ 615 | // synchronous reset 616 | logic """ + srstb + """; 617 | initial begin 618 | """ + srstb + """ <= '0; 619 | repeat(10)@(posedge """ + clock + """); 620 | """ + srstb + """ <= '1; 621 | end\n""" 622 | clkrstl = clk_list + rst_list + [arstb, srstb, clock] 623 | tskit = vgs.get('task_init', True) 624 | if tskit: 625 | taski = task_init(ports_list, clkrstl) 626 | if clock: 627 | dtski = '\n\t\tinit();\n\t\trepeat(10)@(posedge ' + clock + ');\n' 628 | else: 629 | dtski = '\t\tinit();\n\n' 630 | else: 631 | taski = '' 632 | dtski = '' 633 | tskdt = vgs.get('task_drive', True) 634 | if tskdt: 635 | taskd = task_drive(ports_list, clkrstl, clock) 636 | dtskd = '\n\t\tdrive(20);\n' 637 | else: 638 | taskd = '' 639 | dtskd = '' 640 | tbcodes =""" 641 | `timescale 1ns/1ps 642 | module tb_""" + module + """ (); /* this is automatically generated */ 643 | """ + sclks + arsts + srsts + """ 644 | // (*NOTE*) replace reset, clock, others 645 | """ + declp + decls + minst + taski + taskd +""" 646 | initial begin 647 | // do something 648 | """ + dtski + dtskd + """ 649 | repeat(10)@(posedge """ + clock + """); 650 | $finish; 651 | end 652 | // dump wave 653 | initial begin 654 | $display("random seed : %0d", $unsigned($get_initial_random_seed()));""" + str_dump + """ 655 | end 656 | endmodule 657 | """ 658 | if args != None and args['cmd'] == 'file': 659 | fpath = args['dir'] 660 | tname = os.path.join(fpath, 'tb_' + module + '.sv') 661 | with open(tname, "w", newline="", encoding="utf8") as f: 662 | f.write(tbcodes) 663 | else: 664 | v = sublime.active_window().new_file() 665 | v.set_name('tb_' + module + '.sv') 666 | v.set_scratch(True) 667 | v.insert(edit, 0, tbcodes) 668 | 669 | def is_visible(self): 670 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Generate Testbench') 671 | 672 | class VerilogGadgetTbGenRefImp(sublime_plugin.TextCommand): 673 | 674 | def run(self, edit): 675 | if not check_ext(self.view.file_name(), self.view.name()): 676 | return 677 | self.view.run_command("verilog_gadget_tb_gen", {"args": {'cmd': 'refimp'}}) 678 | 679 | def is_visible(self): 680 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Generate Testbench Ref/Imp') 681 | 682 | class VerilogGadgetModuleWrapper(sublime_plugin.TextCommand): 683 | 684 | def run(self, edit, args=None): 685 | if not check_ext(self.view.file_name(), self.view.name()): 686 | return 687 | text = self.view.substr(sublime.Region(0, self.view.size())) 688 | text = remove_comment_line_space(text) 689 | module, ports_list, param_list, clk_list, rst_list = parse_module(text, 'Module Wrapper') 690 | if not module: 691 | return 692 | vgs = get_prefs() 693 | prefx = vgs.get("inst_prefix", "inst_") 694 | clock = vgs.get('clock', []) 695 | combi = False 696 | clktf = False 697 | for p in ports_list: 698 | if p[2] in clock: 699 | clktf = True 700 | break 701 | if len(clk_list) == 0 and not clktf: 702 | combi = True 703 | wprtl = [['input','',clock[0]]] + ports_list 704 | clk_list.append(clock[0]) 705 | else: 706 | wprtl = ports_list 707 | crstl = (clk_list + rst_list) 708 | declp = declare_param(param_list, ',', 'parameter') 709 | dlocp = declare_param(param_list, ';', 'localparam') + '\n' 710 | pstrs = '#(\n' + declp + '\n)\n' if declp else '' 711 | decls = declare_ports(wprtl, crstl, combi, '_p', ',') 712 | sstrs = '(\n' + decls + '\n);\n\n' if decls else '();\n\n' 713 | declr = declare_mwsig(wprtl, crstl, combi, ';') 714 | i2reg = input_to_regs(wprtl, clk_list, rst_list, combi, '_p') 715 | minst = module_inst(module, ports_list, param_list, clk_list, [], [], prefx, False) 716 | mwcodes = """ 717 | module """ + module + """_wrp """ + pstrs + sstrs + dlocp + declr + i2reg + """ 718 | """ + minst + """ 719 | endmodule 720 | """ 721 | v = sublime.active_window().new_file() 722 | v.set_name(module + '_wrp.v') 723 | v.set_scratch(True) 724 | v.insert(edit, 0, mwcodes) 725 | 726 | def is_visible(self): 727 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Module Wrapper') 728 | 729 | class VerilogGadgetInsertHeader(sublime_plugin.TextCommand): 730 | 731 | def run(self, edit, args): 732 | if not check_ext(self.view.file_name(), self.view.name()): 733 | return 734 | vgs = get_prefs() 735 | fname = vgs.get("header", "") 736 | if fname == "example": 737 | if ST3: 738 | tptxt = sublime.load_resource('Packages/Verilog Gadget/template/verilog_header.v') 739 | else: 740 | fname = os.path.join(sublime.packages_path(), 'Verilog Gadget/template/verilog_header.v') 741 | if fname != "example": 742 | if fname.startswith('Packages'): 743 | fname = re.sub('Packages', sublime.packages_path(), fname) 744 | if not os.path.isfile(fname): 745 | disp_error("Insert Header : File not found (" + fname + ")") 746 | return '' 747 | else: 748 | with open(fname, "r", encoding="utf8") as f: 749 | tptxt = str(f.read()) 750 | tpreg = re.sub(re.compile(r'([\(\)\[\]\{\}\|\\\.\*\+\^\$\?])'), (r'\\'+r'\1'), tptxt) 751 | tpreg = tpreg.replace(r'\{YEAR\}', r'(?P[\d]{4})') 752 | tpreg = tpreg.replace(r'\{FILE\}', r'(?P[\w\d ]*\.[\w\d]*)') 753 | tpreg = tpreg.replace(r'\{DATE\}', r'(?P[\d]{4}-[\d]{2}-[\d]{2})') 754 | tpreg = tpreg.replace(r'\{TIME\}', r'(?P[\d]{2}:[\d]{2}:[\d]{2})') 755 | tpreg = tpreg.replace(r'\{RDATE\}', r'(?P[\d]{4}-[\d]{2}-[\d]{2})') 756 | tpreg = tpreg.replace(r'\{RTIME\}', r'(?P[\d]{2}:[\d]{2}:[\d]{2})') 757 | tpreg = tpreg.replace(r'\{SUBLIME_VERSION\}', r'(?P[\d])') 758 | tpreg = tpreg.replace(r'\{TABS\}', r'(?P[\d]*)') 759 | tpobj = re.compile(tpreg, re.DOTALL) 760 | vtext = self.view.substr(sublime.Region(0, self.view.size())) 761 | prevh = tpobj.search(vtext) 762 | if prevh: 763 | gregn = sublime.Region(prevh.start(), prevh.end()) 764 | cyear = time.strftime('%Y', time.localtime()) 765 | cdate = time.strftime('%Y-%m-%d', time.localtime()) 766 | ctime = time.strftime('%H:%M:%S', time.localtime()) 767 | rdate = time.strftime('%Y-%m-%d', time.localtime()) 768 | rtime = time.strftime('%H:%M:%S', time.localtime()) 769 | tabsz = str(self.view.settings().get('tab_size')) 770 | slver = sublime.version()[0] 771 | fnlst = re.compile(r"{FILE}").findall(tptxt) 772 | if fnlst: 773 | fname = self.view.file_name() 774 | if not fname: 775 | disp_msg("Insert Header : Save with name") 776 | fname = "" 777 | else: 778 | fname = os.path.split(fname)[1] 779 | if prevh and args['cmd'] != 'insert': 780 | pname = prevh.group('file') 781 | if pname == fname or self.view.settings().get('load_file_name') == self.view.file_name(): 782 | cdate = prevh.group('cdate') if prevh.group('cdate') is not None else cdate 783 | ctime = prevh.group('ctime') if prevh.group('ctime') is not None else ctime 784 | ntext = tptxt 785 | ntext = ntext.replace('{YEAR}', cyear) 786 | ntext = ntext.replace('{FILE}', fname) 787 | ntext = ntext.replace('{DATE}', cdate) 788 | ntext = ntext.replace('{TIME}', ctime) 789 | ntext = ntext.replace('{RDATE}', rdate) 790 | ntext = ntext.replace('{RTIME}', rtime) 791 | ntext = ntext.replace('{TABS}', tabsz) 792 | ntext = ntext.replace('{SUBLIME_VERSION}', slver) 793 | if prevh: 794 | self.view.replace(edit, gregn, ntext) 795 | elif args['cmd'] == 'insert': 796 | self.view.insert(edit, 0, ntext) 797 | return 798 | 799 | def is_visible(self): 800 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Insert Header') 801 | 802 | CLIPBOARD = r"--CLIPBOARD--" 803 | 804 | class VerilogGadgetRepeatCode(sublime_plugin.TextCommand): 805 | 806 | def run(self, edit, **args): 807 | if args['cmd'] == 'input': 808 | self.n_sels = len(self.view.sel()) 809 | self.txtfrm = self.view.substr(self.view.sel()[0]) 810 | m = re.compile(r'{.*?:.*?}', re.DOTALL).search(self.txtfrm) 811 | c = re.compile(r"{\s*cb\s*}").findall(self.txtfrm) 812 | if not m: 813 | if c: 814 | self.n_sels = 1 815 | clipbs = sublime.get_clipboard().splitlines() 816 | _user_ = '1~' + str(len(clipbs)) 817 | self.on_done(_user_) 818 | return 819 | else: 820 | self.txtfrm = '{:d}' 821 | if self.n_sels == 1: 822 | self.view.window().show_input_panel(u"Enter a range [from]~[to],[↓step],[→step]", "", self.on_done, None, None) 823 | elif self.n_sels > 1: 824 | self.view.window().show_input_panel(u"Enter a range [from],[↓step]", "", self.on_done, None, None) 825 | elif args['cmd'] == 'insert': 826 | r_txt = args['text'] 827 | for i, txtr in enumerate(self.view.sel()): 828 | self.view.replace(edit, txtr, r_txt[i]) 829 | return 830 | 831 | def on_done(self, _user_): 832 | if self.n_sels > 1: 833 | m = re.compile(r'(?P[-+]?\d+)\s*,\s*(?P[-+]?\d+)').search(_user_) 834 | if m: 835 | sta_n = int(m.group('range')) 836 | stp_n = int(m.group('step')) 837 | else: 838 | m = re.compile(r'(?P[-+]?\d+)').search(_user_) 839 | if m: 840 | sta_n = int(m.group('range')) 841 | stp_n = 1 842 | else: 843 | disp_error("Repeat Code : Range format error (" + _user_ + ")") 844 | return 845 | r_txt = [] 846 | for i, regn in enumerate(self.view.sel()): 847 | nmb_n = sta_n + i * stp_n 848 | r_txt.append(self.txtfrm.format(nmb_n)) 849 | self.view.run_command("verilog_gadget_repeat_code", {"cmd" : "insert", "text" : r_txt}) 850 | elif self.n_sels == 1: 851 | _frmerr_ = False 852 | _range_ = re.compile(r"[-+]?\d+").findall(_user_) 853 | _step_ = re.compile(r"(?<=,)\s*[-\d]+").findall(_user_) 854 | _rnglen_ = 0 855 | try: 856 | if len(_range_) >= 2: 857 | sta_n = int(_range_[0]) 858 | end_n = int(_range_[1]) 859 | if sta_n <= end_n: 860 | end_n = end_n + 1 861 | rsp_n = 1 862 | csp_n = 0 863 | else: 864 | end_n = end_n - 1 865 | rsp_n = -1 866 | csp_n = 0 867 | if len(_step_) > 0: 868 | rsp_n = int(_step_[0]) 869 | if len(_step_) > 1: 870 | csp_n = int(_step_[1]) 871 | else: 872 | _frmerr_ = True 873 | _rnglen_ = len(range(sta_n, end_n, rsp_n)) 874 | except: 875 | _frmerr_ = True 876 | if _rnglen_ < 1 or _frmerr_: 877 | disp_error("Repeat Code : Range format error (" + _user_ + ")") 878 | return 879 | try: 880 | clb_l = re.compile(r"{\s*cb\s*}").findall(self.txtfrm) 881 | if len(clb_l) > 0: 882 | clb_s = sublime.get_clipboard().splitlines() 883 | clb_f = True if len(clb_s) > 0 else False 884 | t_txt = re.sub(re.compile(r"{\s*cb\s*}"), CLIPBOARD, self.txtfrm) 885 | else: 886 | clb_f = False 887 | t_txt = self.txtfrm 888 | tup_l = re.compile(r"(?\s*)(?P(input|output|inout))\s*(?P(reg|wire|logic|))\s*(?P(signed|))\s*(?P(\[.*?\]|))\s*(?P.*?)\Z' 924 | REGXSDC = r'^(?P\s*)(?P(reg|wire|logic))\s*(?P(signed|))\s*(?P(\[.*?\]|))\s*(?P.*?)\Z' 925 | REGXINS = r'^(?P\s*)(?P\.\w+)\s*(?P\(.*?)\Z' 926 | 927 | class VerilogGadgetAlign(sublime_plugin.TextCommand): 928 | 929 | def run(self, edit): 930 | tabs = self.view.settings().get('tab_size') 931 | regn = self.view.sel()[0] 932 | regn = sublime.Region(self.view.line(regn.begin()).begin(), self.view.line(regn.end()).end()) 933 | tsel = self.view.substr(regn) 934 | atyp = -1 935 | for l in tsel.splitlines(): 936 | lstr = l.strip() 937 | if lstr: 938 | if re.compile(REGXPDC, re.DOTALL).search(lstr): 939 | atyp = 1 940 | elif re.compile(REGXSDC, re.DOTALL).search(lstr): 941 | atyp = 2 942 | elif re.compile(REGXINS, re.DOTALL).search(lstr): 943 | atyp = 3 944 | else: 945 | atyp = 0 946 | break 947 | if atyp == 0: 948 | mxlr = 0; 949 | for txtr in self.view.sel(): 950 | regn = get_region(self.view, txtr) 951 | txtn, mxlh = self.tab_to_space(self.view, regn, tabs) 952 | mxlr = mxlh if mxlr < mxlh else mxlr 953 | for txtr in self.view.sel(): 954 | regn = get_region(self.view, txtr) 955 | txtn, mxlh = self.tab_to_space(self.view, regn, tabs) 956 | txtn = self.alignment(txtn, mxlr, tabs) 957 | self.view.replace(edit, regn, txtn) 958 | elif atyp in [1,2,3]: 959 | mxlr = 0; 960 | for txtr in self.view.sel(): 961 | regn = get_region(self.view, txtr) 962 | if atyp == 1: 963 | txtn, mxlh = self.align_declare_port (regn, tabs, 0, False) 964 | elif atyp == 2: 965 | txtn, mxlh = self.align_declare_signal(regn, tabs, 0, False) 966 | elif atyp == 3: 967 | txtn, mxlh = self.align_instance_port (regn, tabs, 0, False) 968 | mxlr = mxlh if mxlr < mxlh else mxlr 969 | for txtr in self.view.sel(): 970 | regn = get_region(self.view, txtr) 971 | if atyp == 1: 972 | txtn, mxlh = self.align_declare_port (regn, tabs, mxlr, True) 973 | elif atyp == 2: 974 | txtn, mxlh = self.align_declare_signal(regn, tabs, mxlr, True) 975 | elif atyp == 3: 976 | txtn, mxlh = self.align_instance_port (regn, tabs, mxlr, True) 977 | self.view.replace(edit, regn, txtn) 978 | return 979 | 980 | def tab_to_space(self, view, regn, tabs): 981 | txtn = "" 982 | lend = '\n' 983 | pint = 0 984 | mxlh = 0 985 | rgnl = view.lines(regn) 986 | for idex, lreg in enumerate(rgnl): 987 | lorg = view.substr(lreg) 988 | if bool(re.match(REGXEXC, lorg)): 989 | txtn += lorg + ('' if (idex == len(rgnl) - 1) else lend) 990 | continue 991 | lhsl = re.compile(REGXLHS).findall(lorg) 992 | rhsl = re.compile(REGXRHS).findall(lorg) 993 | if len(lhsl) > 0 and len(rhsl) > 0: 994 | lnew = "" 995 | frst = True 996 | for c in lorg: 997 | if c == '\t': 998 | spce = (tabs - pint % tabs) 999 | pint += spce 1000 | lnew += '\t' if frst else ' ' * spce 1001 | else: 1002 | pint += 1 1003 | lnew += c 1004 | frst = False 1005 | txtn += lnew + ('' if (idex == len(rgnl) - 1) else lend) 1006 | lhsn = lhsl[0] 1007 | lenl = len_tab(lhsn, tabs) 1008 | if mxlh < lenl: 1009 | mxlh = lenl 1010 | else: 1011 | txtn += lorg + ('' if (idex == len(rgnl) - 1) else lend) 1012 | return txtn, mxlh 1013 | 1014 | def alignment(self, txts, mxlh, tabs): 1015 | txtn = "" 1016 | litr = len(txts.splitlines()) 1017 | for i, s in enumerate(txts.splitlines()): 1018 | lend = '' if i + 1 == litr else '\n' 1019 | if bool(re.match(REGXEXC, s)): 1020 | txtn += s + lend 1021 | continue 1022 | lhsl = re.compile(REGXLHS).findall(s) 1023 | rhsl = re.compile(REGXRHS).findall(s) 1024 | if len(lhsl) == 0 or len(rhsl) == 0: 1025 | txtn += s + lend 1026 | else: 1027 | lhsn = lhsl[0] 1028 | rhsn = rhsl[0] 1029 | lhsn = lhsn + ' ' * (mxlh - len_tab(lhsn, tabs) + 1) 1030 | txtn += lhsn + rhsn + lend 1031 | return txtn 1032 | 1033 | def tab_align(self, text, tabs, size): 1034 | tabn = ceil((size - len_tab(text, tabs)) / tabs) 1035 | return (text + '\t' * tabn) 1036 | 1037 | def space_align(self, text, tabs, size): 1038 | spcn = size - len_tab(text, tabs) 1039 | return (text + ' ' * spcn) 1040 | 1041 | def align_declare_port(self, regn, tabs, maxl, repl): 1042 | tsel = self.view.substr(regn) 1043 | mobj = re.compile(REGXPDC, re.DOTALL) 1044 | txtl = [] 1045 | maxi = 0 1046 | for l in tsel.splitlines(): 1047 | mtch = mobj.search(l) 1048 | if mtch: 1049 | txt0 = mtch.group('indent') 1050 | txt0 += mtch.group('inout') 1051 | txt0 += (' ' if mtch.group('type') else '') + mtch.group('type') 1052 | txt0 += (' ' if mtch.group('signed') else '') + mtch.group('signed') 1053 | txt0 += ('\t' if mtch.group('range') else '') + mtch.group('range') 1054 | txt1 = mtch.group('name') 1055 | txtl.append([txt0, txt1]) 1056 | slen = len_tab(txt0, tabs) 1057 | maxi = slen if maxi < slen else maxi 1058 | else: 1059 | txtl.append([l]) 1060 | if not repl: 1061 | maxl = maxi + (tabs - maxi % tabs) 1062 | return '', maxl 1063 | text = '' 1064 | for i, e in enumerate(txtl): 1065 | lend = '' if i == len(txtl) - 1 else '\n' 1066 | if len(e) > 1: 1067 | text += self.tab_align(e[0], tabs, maxl) + e[1] + lend 1068 | else: 1069 | text += e[0] + lend 1070 | return text, maxl 1071 | 1072 | def align_declare_signal(self, regn, tabs, maxl, repl): 1073 | tsel = self.view.substr(regn) 1074 | mobj = re.compile(REGXSDC, re.DOTALL) 1075 | txtl = [] 1076 | maxi = 0 1077 | for l in tsel.splitlines(): 1078 | mtch = mobj.search(l) 1079 | if mtch: 1080 | txt0 = mtch.group('indent') 1081 | txt0 += mtch.group('type') 1082 | txt0 += (' ' if mtch.group('signed') else '') + mtch.group('signed') 1083 | txt0 += ('\t' if mtch.group('range') else '') + mtch.group('range') 1084 | txt1 = mtch.group('name') 1085 | txtl.append([txt0, txt1]) 1086 | slen = len_tab(txt0, tabs) 1087 | maxi = slen if maxi < slen else maxi 1088 | else: 1089 | txtl.append([l]) 1090 | if not repl: 1091 | maxl = maxi + (tabs - maxi % tabs) 1092 | return '', maxl 1093 | text = '' 1094 | for i, e in enumerate(txtl): 1095 | lend = '' if i == len(txtl) - 1 else '\n' 1096 | if len(e) > 1: 1097 | text += self.tab_align(e[0], tabs, maxl) + e[1] + lend 1098 | else: 1099 | text += e[0] + lend 1100 | return text, maxl 1101 | 1102 | def align_instance_port(self, regn, tabs, maxl, repl): 1103 | tsel = self.view.substr(regn) 1104 | mobj = re.compile(REGXINS, re.DOTALL) 1105 | txtl = [] 1106 | maxi = 0 1107 | for l in tsel.splitlines(): 1108 | mtch = mobj.search(l) 1109 | if mtch: 1110 | txt0 = mtch.group('indent') 1111 | txt0 += mtch.group('port') 1112 | txt1 = mtch.group('conn') 1113 | txtl.append([txt0, txt1]) 1114 | slen = len_tab(txt0, tabs) 1115 | maxi = slen if maxi < slen else maxi 1116 | else: 1117 | txtl.append([l]) 1118 | if not repl: 1119 | maxl = maxi + 1 1120 | return '', maxl 1121 | text = '' 1122 | for i, e in enumerate(txtl): 1123 | lend = '' if i == len(txtl) - 1 else '\n' 1124 | if len(e) > 1: 1125 | text += self.space_align(e[0], tabs, maxl) + e[1] + lend 1126 | else: 1127 | text += e[0] + lend 1128 | return text, maxl 1129 | 1130 | SIGOBJ = re.compile(r'(?P[\w\s\[\]\{\}\(\)\,\^\&\|\~\!\+\-\*\/\%\:]+)', re.DOTALL) 1131 | 1132 | class VerilogGadgetXorGate(sublime_plugin.TextCommand): 1133 | 1134 | def run(self, edit): 1135 | txts = '' 1136 | for tsel in self.view.sel(): 1137 | regn = sublime.Region(self.view.line(tsel.begin()).begin(), self.view.line(tsel.end()).end()) 1138 | txts += self.view.substr(regn) + '\n' 1139 | lhsl, rhsl = self.alignment(txts) 1140 | lhss = [] 1141 | for e in lhsl: 1142 | mch = SIGOBJ.search(e) 1143 | if mch: 1144 | lhss.append(mch.group('sig').strip()) 1145 | rhss = [] 1146 | for e in rhsl: 1147 | mch = SIGOBJ.search(e) 1148 | if mch: 1149 | stxt = re.sub(r'^(<=|=)', '', mch.group('sig')) 1150 | rhss.append(stxt.strip()) 1151 | lxor = '{' + ', '.join(lhss) + '}' 1152 | rxor = '{' + ', '.join(rhss) + '}' 1153 | if len(lxor) + len(rxor) > 80: 1154 | txor = '\tassign cge = |(' + lxor + '\n' 1155 | txor += '\t ^ ' + rxor + ');\n' 1156 | else: 1157 | txor = '\tassign cge = |(' + lxor + ' ^ ' + rxor + ');\n' 1158 | sublime.set_clipboard(txor) 1159 | disp_msg("Xor Gating : Copied to Clipboard") 1160 | return 1161 | 1162 | def alignment(self, txts): 1163 | txtn = "" 1164 | litr = len(txts.splitlines()) 1165 | lhsl = [] 1166 | rhsl = [] 1167 | for i, s in enumerate(txts.splitlines()): 1168 | lend = '' if i + 1 == litr else '\n' 1169 | if bool(re.match(REGXEXC, s)): 1170 | txtn += s + lend 1171 | continue 1172 | lhsl += re.compile(REGXLHS).findall(s) 1173 | rhsl += re.compile(REGXRHS).findall(s) 1174 | return lhsl, rhsl 1175 | 1176 | def loaded(): 1177 | global cachepath 1178 | fpath = os.path.join(sublime.cache_path(), 'Verilog Gadget') 1179 | if not os.path.exists(fpath): 1180 | os.makedirs(fpath) 1181 | fpath = os.path.join(sublime.cache_path(), 'Verilog Gadget', '.loaded.num') 1182 | open(fpath, 'w').close() 1183 | cachepath = fpath 1184 | 1185 | class VerilogGadgetInsertSnippet(sublime_plugin.TextCommand): 1186 | 1187 | def run(self, edit): 1188 | self.vgs = get_prefs() 1189 | snipp = self.vgs.get('snippets') 1190 | self.snippl = [] 1191 | for i, k in enumerate(list(snipp.keys())): 1192 | self.snippl.append(k) 1193 | self.window = sublime.active_window() 1194 | self.window.show_quick_panel(self.snippl, self.on_select) 1195 | 1196 | def on_select(self, index): 1197 | if index == -1: 1198 | return 1199 | snipp = self.vgs.get('snippets') 1200 | self.sfile = snipp.get(self.snippl[index]).get('codes', '') 1201 | self.param = snipp.get(self.snippl[index]).get('param', []) 1202 | self.param.sort(key=len, reverse=True) 1203 | self.evals = snipp.get(self.snippl[index]).get('evals', []) 1204 | self.regex = snipp.get(self.snippl[index]).get('regex', '') 1205 | descr = u" " + snipp.get(self.snippl[index]).get('descr', '') + " : " 1206 | self.view.window().show_input_panel(descr, "", self.on_done, None, None) 1207 | 1208 | def on_done(self, user_input): 1209 | texts = sublime.load_resource(self.sfile) 1210 | matcs = re.match(self.regex, user_input) 1211 | for p in self.param: 1212 | exec('self.'+ p + '=' + matcs.group(p)) 1213 | regx = r'\d*[\+\-\*\/]*' + p + r'[\+\-\*\/]*\d*' 1214 | matc = list(set(re.findall(regx, texts))) 1215 | matc.sort(key=len, reverse=True) 1216 | for mstr in matc: 1217 | vstr = mstr.replace(p, 'self.' + p) 1218 | texts = texts.replace(mstr, str(eval(vstr))) 1219 | for estr in self.evals: 1220 | regx = r'\s*(?P[\w]+)=.*' 1221 | matc = re.match(regx, estr) 1222 | evls = matc.group('eval') 1223 | estr = estr.replace(evls, 'self.' + evls) 1224 | for p in self.param: 1225 | estr = estr.replace(p, 'self.' + p) 1226 | exec(estr) 1227 | regx = r'\d*[\+\-\*\/]*' + evls + r'[\+\-\*\/]*\d*' 1228 | matc = list(set(re.findall(regx, texts))) 1229 | matc.sort(key=len, reverse=True) 1230 | for mstr in matc: 1231 | vstr = mstr.replace(evls, 'self.' + evls) 1232 | texts = texts.replace(mstr, str(eval(vstr))) 1233 | self.view.run_command("verilog_gadget_insert_sub", {"args": {'text': texts}}) 1234 | return 1235 | 1236 | def is_visible(self): 1237 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Insert Snippet') 1238 | 1239 | class VerilogGadgetSimTemplate(sublime_plugin.TextCommand): 1240 | 1241 | def run(self, edit): 1242 | fname = self.view.file_name() 1243 | vtext = self.view.substr(sublime.Region(0, self.view.size())) 1244 | vtext = remove_comment_line_space(vtext) 1245 | module, ports_list, param_list, clk_list, rst_list = parse_module(vtext, 'Simulaton Template') 1246 | if not module: 1247 | disp_error("Verilog Gadget : Fail to find 'module'") 1248 | return 1249 | mname = module 1250 | plist = '' 1251 | for e in ports_list: 1252 | plist += 'tb_' + mname + '.' + e[2] + ' ' 1253 | plist = plist.strip() 1254 | vgs = get_prefs() 1255 | smdir = vgs.get('simulation_directory', 'simtest') 1256 | spath = os.path.join(os.path.dirname(fname), smdir) 1257 | if os.path.exists(spath): 1258 | ans = sublime.ok_cancel_dialog('\"'+smdir+'\" already exists. Do you want to overwrite ?', 'OK') 1259 | else: 1260 | ans = True 1261 | if ans: 1262 | tfine = self.copy_template(fname) 1263 | if tfine: 1264 | fname = os.path.basename(fname) 1265 | self.change_template(spath, fname, mname, plist) 1266 | self.view.run_command("verilog_gadget_tb_gen", {"args": {'cmd': 'file', 'dir': spath}}) 1267 | disp_msg("simulation files are generated") 1268 | 1269 | def copy_template(self, fname): 1270 | vgs = get_prefs() 1271 | tmplc = vgs.get('simulation_template', 'example-modelsim') 1272 | if tmplc == 'example-modelsim': 1273 | tmplc = os.path.join(sublime.packages_path(), 'Verilog Gadget/template/modelsim-simtest.tgz') 1274 | elif tmplc == 'example-vcs': 1275 | tmplc = os.path.join(sublime.packages_path(), 'Verilog Gadget/template/vcs-simtest.tgz') 1276 | if sublime.platform() == 'windows': 1277 | tmplc = re.sub(re.compile(r'\\'), '/', tmplc) 1278 | pname = os.path.basename(tmplc) 1279 | tpath = os.path.dirname(fname) 1280 | tname = os.path.join(tpath, pname) 1281 | tfine = False 1282 | try: 1283 | shutil.copy(tmplc, tname) 1284 | tfext = os.path.splitext(pname)[1].lower() 1285 | if tfext == '.tar': 1286 | tarf = tarfile.open(tname, "r:") 1287 | tarf.extractall(tpath) 1288 | tarf.close() 1289 | tfine = True 1290 | elif tfext == '.tgz': 1291 | tarf = tarfile.open(tname, "r:gz") 1292 | tarf.extractall(tpath) 1293 | tarf.close() 1294 | tfine = True 1295 | elif tfext == '.zip': 1296 | zipf = zipfile.ZipFile(tname) 1297 | zipf.extractall(tpath) 1298 | zipf.close() 1299 | tfine = True 1300 | except: 1301 | disp_exept() 1302 | finally: 1303 | if os.path.exists(tname): 1304 | os.remove(tname) 1305 | return tfine 1306 | 1307 | def change_template(self, spath, fname, mname, plist): 1308 | tbmod = 'tb_' + mname 1309 | try: 1310 | for dirs in os.walk(spath): 1311 | files = dirs[2] 1312 | for file in files: 1313 | file = os.path.join(spath, file) 1314 | with open(file, "r", encoding="utf8") as f: 1315 | tptxt = str(f.read()) 1316 | tptxt = tptxt.replace('{{TESTBENCH FILE}}', tbmod + '.sv') 1317 | tptxt = tptxt.replace('{{TESTBENCH NAME}}', tbmod) 1318 | tptxt = tptxt.replace('{{MODULE FILE}}', fname) 1319 | tptxt = tptxt.replace('{{MODULE NAME}}', mname) 1320 | tptxt = tptxt.replace('{{MODULE PORTLIST}}', plist) 1321 | with open(file, "w", newline="", encoding="utf8") as f: 1322 | f.write(tptxt) 1323 | except: 1324 | disp_exept() 1325 | 1326 | def is_visible(self): 1327 | return check_ext_cmd(self.view.file_name(), self.view.name(), 'Simulation Template') 1328 | 1329 | VCD_VALUE = set(('0', '1', 'x', 'X', 'z', 'Z')) 1330 | VCD_VALUE_CHANGE = set(('r', 'R', 'b', 'B')) 1331 | 1332 | class VerilogGadgetVcdToWavedrom(sublime_plugin.TextCommand): 1333 | 1334 | def run(self, edit): 1335 | try: 1336 | file_name = self.view.file_name() 1337 | view_name = self.view.name() 1338 | _name = file_name if view_name == "" else view_name 1339 | ext = os.path.splitext(_name)[1] 1340 | ext = ext.lower() 1341 | if ext != '.vcd': 1342 | return False 1343 | except: 1344 | return False 1345 | text = self.view.substr(sublime.Region(0, self.view.size())) 1346 | sigs, dump = self.parse_vcd(text) 1347 | iclk, pclk = self.get_clock(sigs, dump) 1348 | wtxt = self.dump2wavedrom(sigs, iclk, pclk, dump) 1349 | wviw = sublime.active_window().new_file() 1350 | name = os.path.splitext(os.path.basename(_name))[0] + '.wdrom' 1351 | wviw.set_name(name) 1352 | wviw.run_command("verilog_gadget_insert_sub", {"args": {'text': wtxt}}) 1353 | return 1354 | 1355 | def parse_vcd(self, text): 1356 | time = 0; 1357 | sigs = [] 1358 | chng = False 1359 | cval = {} 1360 | hier = [] 1361 | refs = {} 1362 | vdmp = [] 1363 | syms = set([]) 1364 | for line in text.splitlines(): 1365 | line = line.strip() 1366 | if line == '': 1367 | continue 1368 | if '$var' in line: 1369 | eles = line.split() 1370 | sym = eles[3] 1371 | name = ''.join(eles[4:-1]) 1372 | path = '.'.join(hier) 1373 | ref = path + '.' + name 1374 | sigs.append(ref) 1375 | refs[ref] = sym 1376 | if sym not in syms: 1377 | syms.add(sym) 1378 | cval[sym] = 'x' 1379 | elif '$scope' in line: 1380 | hier.append(line.split()[2]) 1381 | elif '$upscope' in line: 1382 | hier.pop() 1383 | elif line[0] in VCD_VALUE_CHANGE: 1384 | val, sym = line[1:].split() 1385 | if sym in syms: 1386 | cval[sym] = val 1387 | chng = True 1388 | elif line[0] in VCD_VALUE: 1389 | val = line[0] 1390 | sym = line[1:] 1391 | if sym in syms: 1392 | cval[sym] = val 1393 | chng = True 1394 | elif line[0] == '#': 1395 | if chng: 1396 | cvl = [] 1397 | for ref in sigs: 1398 | sym = refs[ref] 1399 | val = cval[sym] 1400 | cvl.append('{0}'.format(self.to_hex(val))) 1401 | vdmp.append(cvl) 1402 | time = int(line[1:]) 1403 | chng = False 1404 | dump = [['']*len(vdmp) for _ in range(len(vdmp[0]))] 1405 | for j,r in enumerate(vdmp): 1406 | for i, c in enumerate(r): 1407 | dump[i][j] = c 1408 | return sigs, dump 1409 | 1410 | @staticmethod 1411 | def to_hex(s): 1412 | for c in s: 1413 | if not c in '01': 1414 | return c 1415 | return hex(int(s, 2))[2:] 1416 | 1417 | def get_clock(self, sigs, dump): 1418 | pclk = [] 1419 | iclk = -1 1420 | for i,s in enumerate(sigs): 1421 | if s[-1] != ']': 1422 | tclk = True 1423 | p = "" 1424 | for j,e in enumerate(dump[i]): 1425 | if j == 0: 1426 | if e == "0" or e == "1": 1427 | pass 1428 | else: 1429 | tclk = False 1430 | break 1431 | p = e 1432 | elif (p == "0" and e == "1") or (p == "1" and e == "0"): 1433 | p = e 1434 | else: 1435 | tclk = False 1436 | break 1437 | if tclk: 1438 | pclk.append(s) 1439 | iclk = i 1440 | return iclk, pclk 1441 | 1442 | def dump2wavedrom(self, sigs, iclk, pclk, dump): 1443 | wdrom = '{signal: [\n' 1444 | maxln = len(max(sigs, key=len)) 1445 | for i,s in enumerate(sigs): 1446 | wave = "" 1447 | data = [] 1448 | p = "" 1449 | if s in pclk: 1450 | wave = "p" + "." * int(int(len(dump[i]))/2-1) 1451 | else: 1452 | for j,e in enumerate(dump[i]): 1453 | if iclk == -1 or (iclk != -1 and dump[iclk][j] == "1"): 1454 | if p == e: 1455 | wave += "." 1456 | else: 1457 | wave += "2" if s[-1] == ']' else e 1458 | data.append('\''+e+'\'') 1459 | p = e 1460 | spce = maxln - len(s) 1461 | if s[-1] == ']': 1462 | wdrom += ' {name: \'' + s + '\', ' + ' '*spce + 'wave:\'' + wave + '\', ' + 'data:[' + ','.join(data) + ']},\n' 1463 | else: 1464 | wdrom += ' {name: \'' + s + '\', ' + ' '*spce + 'wave:\'' + wave + '\'},\n' 1465 | wdrom += ']}\n' 1466 | return wdrom 1467 | 1468 | def is_visible(self): 1469 | return check_vcd_cmd(self.view.file_name(), self.view.name(), 'VCD to WaveDrom') 1470 | 1471 | class VerilogGadgetEventListener(sublime_plugin.EventListener): 1472 | 1473 | def on_load(self, view): 1474 | view.settings().set('load_file_name', view.file_name()) 1475 | return 1476 | 1477 | def on_pre_save(self, view): 1478 | vgs = get_prefs() 1479 | if not vgs.get("auto_update_header", True): 1480 | return 1481 | load_file = view.settings().get('load_file_name', '') 1482 | if view.is_dirty() or load_file != view.file_name(): 1483 | view.run_command("verilog_gadget_insert_header", {"args": {'cmd': 'update'}}) 1484 | view.settings().set('load_file_name', view.file_name()) 1485 | return 1486 | 1487 | class VerilogGadgetEtc(sublime_plugin.TextCommand): 1488 | 1489 | def run(self, edit, **args): 1490 | if args['cmd'] == 'hex2dec': 1491 | selr = self.view.sel()[0] 1492 | stxt = self.view.substr(selr) 1493 | sdec = '{:d}'.format(int(stxt, 16)) 1494 | self.view.replace(edit, selr, sdec) 1495 | msg = "Convert Digits HEX → DEC" 1496 | elif args['cmd'] == 'dec2hex': 1497 | selr = self.view.sel()[0] 1498 | stxt = self.view.substr(selr) 1499 | shex = '{:x}'.format(int(stxt)) 1500 | self.view.replace(edit, selr, shex) 1501 | msg = "Convert Digits DEC → HEX" 1502 | disp_msg(msg) 1503 | return 1504 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install" : "README.md", 3 | "v0.6.28" : "changelog/v0.6.28.txt", 4 | "v0.8.0" : "changelog/v0.8.0.txt", 5 | "v1.0.0" : "changelog/v1.0.0.md", 6 | "v1.1.0" : "changelog/v1.1.0.md", 7 | "v1.2.0" : "changelog/v1.2.0.md", 8 | "v1.2.5" : "changelog/v1.2.5.md", 9 | "v1.4.0" : "changelog/v1.4.0.md", 10 | "v1.4.1" : "changelog/v1.4.1.md", 11 | "v1.5.0" : "changelog/v1.5.0.md", 12 | "v1.6.0" : "changelog/v1.6.0.md", 13 | "v1.6.2" : "changelog/v1.6.2.md", 14 | "v1.7.0" : "changelog/v1.7.0.md", 15 | "v1.8.0" : "changelog/v1.8.0.md", 16 | "v1.11.0" : "changelog/v1.11.0.md", 17 | "v1.12.0" : "changelog/v1.12.0.md", 18 | "v2.0.0" : "changelog/v2.0.0.md", 19 | "v2.3.0" : "changelog/v2.3.0.md", 20 | "v2.3.1" : "changelog/v2.3.1.md", 21 | "v2.4.0" : "changelog/v2.4.0.md", 22 | "v2.5.0" : "changelog/v2.5.0.md", 23 | } 24 | -------------------------------------------------------------------------------- /template/modelsim-simtest.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poucotm/Verilog-Gadget/4fde7a1c7748fbfafa92df6298278dcb789fa331/template/modelsim-simtest.tgz -------------------------------------------------------------------------------- /template/vcs-simtest.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poucotm/Verilog-Gadget/4fde7a1c7748fbfafa92df6298278dcb789fa331/template/vcs-simtest.tgz -------------------------------------------------------------------------------- /template/verilog_cplxm.v: -------------------------------------------------------------------------------- 1 | //________________________________________________________ 2 | // cplx_mult (Q/I) example 3 | 4 | function automatic [2*ZB-1:0] cplx_mult; 5 | input [2*AB-1:0] ca; 6 | input [2*BB-1:0] cb; 7 | reg [ZB-1:0] cr; 8 | reg [ZB-1:0] ci; 9 | begin 10 | cr = $signed(ca[AB*0+:AB]) * $signed(cb[BB*0+:BB]) - $signed(ca[AB*1+:AB]) * $signed(cb[BB*1+:BB]); 11 | ci = $signed(ca[AB*0+:AB]) * $signed(cb[BB*1+:BB]) + $signed(ca[AB*1+:AB]) * $signed(cb[BB*0+:BB]); 12 | cplx_mult = {ci, cr}; 13 | end 14 | endfunction 15 | -------------------------------------------------------------------------------- /template/verilog_header.v: -------------------------------------------------------------------------------- 1 | // This is a simple example. 2 | // You can make a your own header file and set its path to settings. 3 | // (Preferences > Package Settings > Verilog Gadget > Settings - User) 4 | // 5 | // "header": "Packages/Verilog Gadget/template/verilog_header.v" 6 | // 7 | // ----------------------------------------------------------------------------- 8 | // Copyright (c) 2014-{YEAR} All rights reserved 9 | // ----------------------------------------------------------------------------- 10 | // Author : yongchan jeon (Kris) poucotm@gmail.com 11 | // File : {FILE} 12 | // Create : {DATE} {TIME} 13 | // Revise : {RDATE} {RTIME} 14 | // Editor : sublime text{SUBLIME_VERSION}, tab size ({TABS}) 15 | // ----------------------------------------------------------------------------- 16 | --------------------------------------------------------------------------------