├── .gitignore ├── Application ├── Generator │ ├── HDL_Database │ │ ├── verilog_database.xml │ │ └── vhdl_database.xml │ ├── TB_Database │ │ ├── verilog_tb_database.xml │ │ └── vhdl_tb_database.xml │ ├── TCL_Database │ │ └── tcl_database.xml │ ├── WCFG_Database │ │ └── wcfg_database.xml │ └── generator.py ├── HDLDesigner │ ├── Architecture │ │ ├── arch_help.md │ │ ├── arch_help.py │ │ ├── architecture.py │ │ ├── chipEnabled.py │ │ ├── concurrentstmt_dialog.py │ │ ├── instance_dialog.py │ │ ├── note_dialog.py │ │ └── process_dialog.py │ ├── ChatGPT │ │ ├── VHDLModel.py │ │ ├── VerilogModel.py │ │ ├── chatgpt.py │ │ ├── chatgpt_help.md │ │ └── chatgpt_help.py │ ├── Generate │ │ └── generation.py │ ├── IOPorts │ │ ├── io_port_dialog.py │ │ ├── io_ports.py │ │ ├── port_help.md │ │ ├── port_help.py │ │ └── sequential_dialog.py │ ├── InternalSignal │ │ ├── int_sig_dialog.py │ │ ├── internal_help.md │ │ ├── internal_help.py │ │ ├── internal_signal.py │ │ └── stateNamesDialog.py │ ├── Package │ │ ├── package.py │ │ ├── package_dialog.py │ │ ├── package_help.md │ │ └── package_help.py │ ├── Subcomponents │ │ ├── component_dialog.py │ │ ├── subcomp_help.md │ │ ├── subcomp_help.py │ │ └── subcomponents.py │ ├── comp │ │ ├── comp_details.py │ │ ├── comp_help.md │ │ └── comp_help.py │ ├── hdl_designer.py │ └── testPlan │ │ ├── testplan.py │ │ ├── testplan_help.md │ │ └── testplan_help.py ├── Help │ ├── help.md │ └── help.py ├── Home │ └── home.py ├── ProjectManager │ ├── eda_help.md │ ├── eda_help.py │ ├── language_help.md │ ├── language_help.py │ ├── projectLink.py │ ├── project_manager.py │ ├── settings_help.md │ └── settings_help.py ├── Resources │ ├── blue_logo.png │ ├── hdlgen_title_blue.png │ ├── hdlgen_title_red.png │ ├── main_menu_0.png │ ├── main_menu_1.png │ ├── processdiagram.png │ └── red_logo.png ├── Settings │ ├── VHDLModelDefault.py │ ├── VHDLTestbenchDefault.py │ ├── VerilogModelDefault.py │ ├── VerilogTestbenchDefault.py │ └── settings.py ├── main.py ├── prompts.yml └── requirements.txt ├── LICENSE.md ├── README.md ├── Sample_Projects └── Sample_Projects_Downloads.pdf └── User_Projects └── User_Projects_Downloads.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Python cache files and compiled python files/classes 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Application specific files generated at runtime 7 | # Override with "git add -f User_Projects/*" to update example User Projects 8 | **/config.ini 9 | User_Projects/ 10 | 11 | # Ignore PyCharm, VSCode and Vivado files 12 | **/.idea/ 13 | .idea/ 14 | **/.vscode/ 15 | .vscode 16 | **/*.log 17 | *.log 18 | **/*.jou 19 | *.jou -------------------------------------------------------------------------------- /Application/Generator/HDL_Database/verilog_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | module $comp_name( $signals ); $portDef $arch endmodule 16 | 17 | $sig_name 18 | $modeput $size $name; 19 | reg $int_sig_type $int_sig_name; 20 | $int_sig_declaration $arch_elements 21 | parameter $stateName = $bits; 22 | -- Package library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package arrayPackage is $arrays $Component end arrayPackage; package body arrayPackage is end arrayPackage; 23 | type $arrayName is array($arraySize downto 0) of $signalType($arrayLength downto 0); 24 | always @($input_signals) begin : $process_label$default_assignments end 25 | if ( $assignment == 1'b$lvl ) begin$default_assignments end $else 26 | else begin$default_assignments end 27 | elsif $edge(clk) then $default_assignments 28 | if (clk) then $default_assignments end if; 29 | case ( $stateType ) 30 | case ( $stateType )$whenCase default : begin end endcase 31 | $output_signal = $value; 32 | $output_signal = $value; 33 | .$output_signal ($value) 34 | assign $statement 35 | $instance $instance_label ( $portAssign ); 36 | component $model is port( $ports ); end component $model; 37 | /// $notes 38 | /// assign $output_signal = $notes; 39 | 40 | -------------------------------------------------------------------------------- /Application/Generator/HDL_Database/vhdl_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | library ieee; 17 | use ieee.std_logic_1164.all; 18 | use ieee.numeric_std.all; 19 | 20 | 21 | entity $comp_name is Port( $signals ); end entity $comp_name; 22 | 23 | $sig_name : $mode $type; 24 | 25 | architecture $arch_name of $comp_name is $int_sig_declaration begin $arch_elements end $arch_name; 26 | 27 | signal $int_sig_name : $int_sig_type; 28 | 29 | type stateType is ($stateNamesList); 30 | -- Package library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package MainPackage is $arrays $Component end MainPackage; package body MainPackage is end MainPackage; 31 | type $arrayName is array($arraySize downto 0) of $signalType($arrayLength downto 0); 32 | $process_label: process($input_signals) begin $default_assignments end process; 33 | if $edge(clk) then $default_assignments end if; 34 | if $assignment = '$value' then $default_assignments$else end if; 35 | else $default_assignments 36 | elsif $edge(clk) then $default_assignments 37 | case $stateType is 38 | case $stateType is$whenCase when others => null; end case; 39 | $output_signal <= $value; 40 | $output_signal => $value 41 | $concurrentstmt_label: $statement 42 | $instance_label: $instance port map( $portAssign ); 43 | component $model is port( $ports ); end component $model; 44 | --- $notes 45 | --- $concurrentstmt_label: $output_signal <= $notes; 46 | 47 | -------------------------------------------------------------------------------- /Application/Generator/TB_Database/verilog_tb_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | module $comp_name_TB(); 17 | 18 | $sig_name : $mode $type; 19 | 20 | $regOrwire $size $sig_name; 21 | 22 | $tbSignalDeclaration $arch_elements end endmodule 23 | 24 | signal $int_sig_name : $int_sig_type; 25 | 26 | .$sig_name ($sig_name), 27 | 28 | $output_signal <= $value; 29 | 30 | -------------------------------------------------------------------------------- /Application/Generator/TB_Database/vhdl_tb_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | library ieee; 17 | use ieee.std_logic_1164.all; 18 | use ieee.numeric_std.all; 19 | 20 | 21 | entity $comp_name_TB is end entity $comp_name_TB; 22 | 23 | $sig_name : $mode $type; 24 | 25 | signal $sig_name : $type; 26 | 27 | architecture behave of $comp_name_TB is $component_declarations component $comp_name is Port( $port ); end component; $tbSignalDeclaration begin $arch_elements end process; end behave; 28 | 29 | signal $int_sig_name : $int_sig_type; 30 | 31 | $sig_name => $sig_name, 32 | 33 | $output_signal <= $value; 34 | 35 | $concurrentstmt_label: $statement 36 | -------------------------------------------------------------------------------- /Application/Generator/TCL_Database/tcl_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | # AMD-Xilinx Vivado project start and tcl script: Create project, xc7z020clg400-1 technology, %lang model 16 | # To execute, 17 | # open cmd window 18 | # cd to project folder 19 | # start Vivado (with tcl file parameter) 20 | # e.g, for project name $proj_name 21 | # cmd 22 | # cd $proj_dir 23 | # $vivado_bat_path -source $tcl_path 24 | 25 | # Vivado tcl file $proj_name.tcl, created in AMDprj folder 26 | cd $proj_dir 27 | # Close_project Not required. Will advise that Vivado sessions should be closed. 28 | start_gui 29 | create_project $proj_name ./$lang/AMDprj -part xc7z020clg400-1 -force 30 | set_property target_language $lang [current_project] 31 | add_files -norecurse ./$lang/model/$comp_name.$ext $arrayPackage $files 32 | update_compile_order -fileset sources_1 33 | set_property SOURCE_SET sources_1 [get_filesets sim_1] 34 | add_files -fileset sim_1 -norecurse ./$lang/testbench/$tb_name.$ext 35 | update_compile_order -fileset sim_1 36 | # Remove IOBs from snthesised schematics 37 | current_run [get_runs synth_1] 38 | set_property -name {STEPS.SYNTH_DESIGN.ARGS.MORE OPTIONS} -value -no_iobuf -objects [get_runs synth_1] 39 | 40 | # Save created wcfg in project 41 | set_property SOURCE_SET sources_1 [get_filesets sim_1] 42 | add_files -fileset sim_1 -norecurse ./$lang/AMDprj/$tb_name_behav.wcfg 43 | # save_wave_config {./$lang/AMDprj/$tb_name_behav.wcfg} 44 | 45 | 46 | # Assume that the quartus executable pointer has been setup in the HDLGen settings 47 | # e.g, Quartus installation folder is 48 | # C:\intelFPGA_lite\22.1std\quartus\bin64\ 49 | # Quartus executable quartus.exe 50 | 51 | # If click HDLGen 'Generate / Open Quartus 52 | # Execute this tcl file using 53 | # C:\intelFPGA_lite\22.1std\quartus\bin64\quartus_map $comp_name.tcl 54 | 55 | # Assume 56 | # Quartus project $comp_name.qpf 57 | # Folder $proj_dirC:\2023\vicilogic\HDLGenTop\HDLGen\User_Projects\sequential\counters\$comp_name\$lang\Intelprj 58 | 59 | # To synthesise the HDL model, after executing this tcl file, open the project in Quartus, run the following 60 | # C:\intelFPGA_lite\22.1std\quartus\bin64\quartus.exe CB4CLED.qpf 61 | # The user can then synthesise the design using menu Project > Start compilation (or shortcut ctrl/L) 62 | # or use GUI Tools > Green arrow function "Start Analysis and Synthesis" or shortcut (ctrl/K) 63 | 64 | # Copyright (C) 2023 Intel Corporation. All rights reserved. 65 | # Your use of Intel Corporation's design tools, logic functions 66 | # and other software and tools, and any partner logic 67 | # functions, and any output files from any of the foregoing 68 | # (including device programming or simulation files), and any 69 | # associated documentation or information are expressly subject 70 | # to the terms and conditions of the Intel Program License 71 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 72 | # the Intel FPGA IP License Agreement, or other applicable license 73 | # agreement, including, without limitation, that your use is for 74 | # the sole purpose of programming logic devices manufactured by 75 | # Intel and sold by Intel or its authorized distributors. Please 76 | # refer to the applicable agreement for further details, at 77 | # https://fpgasoftware.intel.com/eula. 78 | 79 | # Quartus Prime: Generate Tcl File for Project 80 | 81 | # Load Quartus Prime Tcl Project package 82 | package require ::quartus::project0 83 | set need_to_close_project 0 84 | 85 | project create $comp_name 86 | project open $comp_name 87 | 88 | set make_assignments 1 89 | 90 | # Make assignments 91 | if {$make_assignments} { 92 | set_global_assignment -name FAMILY "Cyclone V" 93 | set_global_assignment -name DEVICE 5CSEBA6U23I7 94 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 22.1STD.1 95 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "08:49:38 MAY 02, 2023" 96 | set_global_assignment -name LAST_QUARTUS_VERSION "22.1std.1 Lite Edition" 97 | set_global_assignment -name $lang_FILE ../model/$comp_name.$ext 98 | set_global_assignment -name $lang_FILE ../../../../../../Package/MainPackage.vhd 99 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 100 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40" 101 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 102 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256 103 | set_global_assignment -name EDA_SIMULATION_TOOL "Questa Intel FPGA ($lang)" 104 | set_global_assignment -name EDA_TIME_SCALE "1 ps" -section_id eda_simulation 105 | set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation 106 | set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_timing 107 | set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_symbol 108 | set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_signal_integrity 109 | set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_boundary_scan 110 | } 111 | 112 | # Commit assignments 113 | export_assignments 114 | 115 | -------------------------------------------------------------------------------- /Application/Generator/WCFG_Database/wcfg_database.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | testNo 28 | testNo 29 | 30 | 31 | 32 | endOfSim 33 | endOfSim 34 | 35 | 36 | 37 | 38 | UUT 39 | label 40 | 41 | entity 42 | label 43 | 44 | 45 | 46 | 47 | [signal][size] 48 | [signal][size] 49 | 50 | 51 | 52 | 53 | 54 | internal 55 | label 56 | 57 | 58 | 59 | 60 | [signal][size] 61 | [signal][size] 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Architecture/arch_help.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | This menu enables the creation and editing of processes, concurrent statements and component instantiations 4 | 5 | - New process 6 | - Process name 7 | - suffix (_p default) 8 | - Add non-default logic 9 | - Examples 10 | if RWr = 1 11 | if rd > 0 12 | NSArray(rd) = WBDat 13 | end if 14 | end if 15 | 16 | Use nested, indented if-elsif-else-end if and case-end case stateements 17 | 18 | - sensitivity list: tick all signals which apply 19 | synchronous (clocked): clk and/or rst are automatically validated as the sensitivity list 20 | - Select 21 | - output signal 22 | - select signal 23 | - default values 24 | - select 25 | signal name or 26 | 'zero' 27 | custom value 28 | - enter custom default value 29 | - Click OK to complete 30 | 31 | 32 | - New concurrent statement 33 | - concurrent statement name 34 | - default suffix is _c 35 | - assign signal 36 | - select signal to be assigned or 37 | - 'zero' 38 | - click 'custom value' to enter custom value, e.g, equation in the custom value field 39 | - Click OK to complete 40 | 41 | - New (component) instance 42 | - instance name 43 | - suffix (_i defaul) 44 | - component list (accesses the components listed in the sub-components menu 45 | - assign input or internal signal name to the component port signals 46 | - Click OK to complete 47 | 48 | - The existing processes, concurrent statements and component instances are listed and can be edited or deleted 49 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Architecture/arch_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/Architecture/arch_help.md" 6 | 7 | 8 | class ArchHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Architecture/chipEnabled.py: -------------------------------------------------------------------------------- 1 | #Dialog called inside process_dialog. Allows user to selct what signal to use as the hcip enabled signal. 2 | from xml.dom import minidom 3 | from PySide2.QtWidgets import * 4 | from PySide2.QtGui import * 5 | import sys 6 | sys.path.append("..") 7 | from ProjectManager.project_manager import ProjectManager 8 | 9 | BLACK_COLOR = "color: black" 10 | WHITE_COLOR = "color: white" 11 | 12 | class ChipEnabledDialog(QDialog): 13 | 14 | def __init__(self, add_or_edit, ce_data = None): 15 | super().__init__() 16 | 17 | if add_or_edit == "add": 18 | self.setWindowTitle("Set Chip Enabled Signal") 19 | elif add_or_edit == "edit": 20 | self.setWindowTitle("Edit Chip Enabled Signal") 21 | title_font = QFont() 22 | title_font.setPointSize(10) 23 | title_font.setBold(True) 24 | bold_font = QFont() 25 | bold_font.setBold(True) 26 | input_font = QFont() 27 | input_font.setPointSize(10) 28 | self.internal_signals = [] 29 | self.input_signals = [] 30 | self.output_signals = [] 31 | 32 | self.input_layout = QGridLayout() 33 | 34 | self.mainLayout = QVBoxLayout() 35 | 36 | self.chipEnabled_name_label = QLabel("Chip Enabled Signal") 37 | self.chipEnabled_name_label.setFont(input_font) 38 | self.chipEnabled_name_label.setStyleSheet(WHITE_COLOR) 39 | 40 | self.chipEnabled_signals_combo = QComboBox() 41 | self.chipEnabled_signals_combo.setFont(input_font) 42 | self.chipEnabled_signals_combo.setStyleSheet("QComboBox {padding: 2px;}") 43 | 44 | self.cancel_btn = QPushButton("Cancel") 45 | self.cancel_btn.setFont(input_font) 46 | self.cancel_btn.setStyleSheet( 47 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 48 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 49 | 50 | 51 | self.ok_btn = QPushButton("Ok") 52 | self.ok_btn.setEnabled(False) 53 | self.ok_btn.setFont(input_font) 54 | self.ok_btn.setStyleSheet( 55 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 56 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 57 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 58 | 59 | self.input_frame = QFrame() 60 | 61 | self.cancelled = True 62 | 63 | self.setup_ui() 64 | 65 | self.populate_signals(ProjectManager.get_xml_data_path()) 66 | 67 | if add_or_edit == "edit" and ce_data != None: 68 | self.load_ce_data(ce_data) 69 | 70 | def setup_ui(self): 71 | 72 | self.input_layout.addWidget(self.chipEnabled_name_label, 0, 0, 1, 2) 73 | self.input_layout.addWidget(self.chipEnabled_signals_combo, 1, 0, 1, 2) 74 | self.input_layout.addItem(QSpacerItem(0, 10), 2, 0, 1, 2) 75 | self.input_layout.addWidget(self.cancel_btn, 3, 0, 2, 1, alignment=Qt.AlignRight) 76 | self.input_layout.addWidget(self.ok_btn, 3, 1, 2, 1, alignment=Qt.AlignRight) 77 | 78 | self.chipEnabled_signals_combo.currentTextChanged.connect(self.enable_ok_btn); 79 | self.input_frame.setFrameShape(QFrame.StyledPanel) 80 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 81 | self.input_frame.setContentsMargins(10, 10, 10, 10) 82 | self.input_frame.setFixedSize(400, 175) 83 | self.input_frame.setLayout(self.input_layout) 84 | self.ok_btn.clicked.connect(self.get_data) 85 | self.cancel_btn.clicked.connect(self.cancel_selected) 86 | 87 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 88 | 89 | self.setLayout(self.mainLayout) 90 | 91 | def populate_signals(self, proj_dir): 92 | if (proj_dir != None): 93 | root = minidom.parse(proj_dir) 94 | HDLGen = root.documentElement 95 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 96 | 97 | io_ports = hdlDesign[0].getElementsByTagName('entityIOPorts') 98 | signal_nodes = io_ports[0].getElementsByTagName('signal') 99 | 100 | intSignals = hdlDesign[0].getElementsByTagName('internalSignals') 101 | intSignal_nodes = intSignals[0].getElementsByTagName('signal') 102 | 103 | if len(signal_nodes) != 0 or len(intSignal_nodes) != 0: 104 | 105 | for i in range(0, len(signal_nodes)): 106 | name = signal_nodes[i].getElementsByTagName('name')[0].firstChild.data 107 | mode = signal_nodes[i].getElementsByTagName('mode')[0].firstChild.data 108 | 109 | if mode != "out": 110 | if name != "clk" and name != "rst": 111 | self.input_signals.append(name) 112 | 113 | for i in range(0, len(intSignal_nodes)): 114 | internal_signal = intSignal_nodes[i].getElementsByTagName('name')[0].firstChild.data 115 | self.internal_signals.append(internal_signal) 116 | 117 | if len(self.input_signals) != 0 or len(self.internal_signals) != 0: 118 | self.chipEnabled_signals_combo.addItem("Please select") 119 | self.chipEnabled_signals_combo.addItems(self.input_signals + self.internal_signals) 120 | 121 | 122 | def load_ce_data(self, ce_data): 123 | if ce_data in self.internal_signals or ce_data in self.input_signals: 124 | self.chipEnabled_signals_combo.setCurrentText(ce_data) 125 | else: 126 | self.chipEnabled_signals_combo.setCurrentText("Please select") 127 | def get_data(self): 128 | data = self.chipEnabled_signals_combo.currentText() 129 | self.cancelled = False 130 | self.close() 131 | return data 132 | 133 | def cancel_selected(self): 134 | self.cancelled = True 135 | self.close() 136 | def enable_ok_btn(self): 137 | if self.chipEnabled_signals_combo.currentText() != "Please select": 138 | self.ok_btn.setEnabled(True) 139 | else: 140 | self.ok_btn.setEnabled(False) 141 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Architecture/concurrentstmt_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for concurrent statement called by the architecture.py when adding or editing concurrent statement 2 | from xml.dom import minidom 3 | from PySide2.QtWidgets import * 4 | from PySide2.QtGui import * 5 | import sys 6 | import re 7 | sys.path.append("..") 8 | from ProjectManager.project_manager import ProjectManager 9 | from HDLDesigner.Architecture.note_dialog import note_Dialog 10 | 11 | BLACK_COLOR = "color: black" 12 | WHITE_COLOR = "color: white" 13 | 14 | class ConcurrentStmtDialog(QDialog): 15 | 16 | def __init__(self, add_or_edit, concNames ,conc_data = None): 17 | super().__init__() 18 | 19 | if add_or_edit == "add": 20 | self.setWindowTitle("New Concurrent Statement") 21 | elif add_or_edit == "edit": 22 | self.setWindowTitle("Edit Concurrent Statement") 23 | self.conc_names = concNames 24 | self.conc_name = "" 25 | if conc_data != None: 26 | self.conc_name = conc_data[1] 27 | title_font = QFont() 28 | title_font.setPointSize(10) 29 | title_font.setBold(True) 30 | bold_font = QFont() 31 | bold_font.setBold(True) 32 | input_font = QFont() 33 | input_font.setPointSize(10) 34 | 35 | self.internal_signals = [] 36 | self.input_signals = [] 37 | self.output_signals = [] 38 | self.conc_notes = "None" 39 | self.input_layout = QGridLayout() 40 | 41 | self.mainLayout = QVBoxLayout() 42 | 43 | self.conc_name_label = QLabel("Concurrent Statement Name*") 44 | self.conc_name_label.setStyleSheet(WHITE_COLOR) 45 | self.conc_name_label.setFont(input_font) 46 | self.conc_name_input = QLineEdit() 47 | self.conc_name_input.setFont(input_font) 48 | self.noteBox = QCheckBox("Custom Value") 49 | self.noteBox.setStyleSheet(WHITE_COLOR) 50 | self.noteBox.setFont(input_font) 51 | self.note_label = QLabel("Custom Value") 52 | self.note_label.setStyleSheet(WHITE_COLOR) 53 | self.note_label.setFont(input_font) 54 | self.note_label.setVisible(False) 55 | self.note_input = QLineEdit() 56 | self.note_input.setVisible(False) 57 | self.note_input.setFont(input_font) 58 | self.add_note_btn = QPushButton("Add Custom Value") 59 | self.add_note_btn.setFont(input_font) 60 | self.add_note_btn.setStyleSheet( 61 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 62 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 63 | self.add_note_btn.setVisible(False) 64 | 65 | self.out_sig_header_layout = QHBoxLayout() 66 | self.out_sig_label = QLabel("Assign Signal") 67 | self.out_sig_label.setFont(input_font) 68 | self.out_sig_label.setStyleSheet(WHITE_COLOR) 69 | self.options_sig_label = QLabel("Default Value") 70 | self.options_sig_label.setFont(input_font) 71 | self.options_sig_label.setStyleSheet(WHITE_COLOR) 72 | self.val_label = QLabel("Binary Value") 73 | self.val_label.setFont(input_font) 74 | self.val_label.setStyleSheet(WHITE_COLOR) 75 | self.out_sig_empty_info = QLabel("No Output Signals found!\nPlease add signal in the IO Ports") 76 | self.out_sig_empty_info.setFont(input_font) 77 | self.out_sig_empty_info.setFixedSize(400, 300) 78 | 79 | self.out_signals_combo = QComboBox() 80 | self.out_signals_combo.setFont(input_font) 81 | self.out_signals_combo.setStyleSheet("QComboBox {padding: 2px;}") 82 | self.options_signals_combo = QComboBox() 83 | self.options_signals_combo.setFont(input_font) 84 | self.options_signals_combo.setStyleSheet("QComboBox {padding: 2px;}") 85 | self.out_val_input = QLineEdit() 86 | self.out_val_input.setFont(input_font) 87 | validator = QIntValidator() 88 | self.out_val_input.setValidator(validator) 89 | 90 | self.out_sig_layout = QHBoxLayout() 91 | 92 | self.suffix_label = QLabel("Suffix") 93 | self.suffix_label.setStyleSheet(WHITE_COLOR) 94 | self.suffix_label.setFont(input_font) 95 | self.suffix_input = QLineEdit() 96 | self.suffix_input.setFont(input_font) 97 | self.suffix_input.setEnabled(False) 98 | self.suffix_input.setText("_c") 99 | 100 | self.cancel_btn = QPushButton("Cancel") 101 | self.cancel_btn.setFont(input_font) 102 | self.cancel_btn.setStyleSheet( 103 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 104 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 105 | 106 | 107 | self.ok_btn = QPushButton("Ok") 108 | self.ok_btn.setEnabled(False) 109 | self.ok_btn.setFont(input_font) 110 | self.ok_btn.setStyleSheet( 111 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 112 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 113 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 114 | 115 | self.input_frame = QFrame() 116 | 117 | self.cancelled = True 118 | 119 | self.setup_ui() 120 | 121 | self.populate_signals(ProjectManager.get_xml_data_path()) 122 | 123 | if add_or_edit == "edit" and conc_data != None: 124 | self.load_conc_data(conc_data) 125 | 126 | def setup_ui(self): 127 | 128 | self.input_layout.addWidget(self.conc_name_label, 0, 0, 1, 1) 129 | self.input_layout.addWidget(self.conc_name_input, 1, 0, 1, 1) 130 | self.input_layout.addWidget(self.suffix_label, 0, 1, 1, 1) 131 | self.input_layout.addWidget(self.suffix_input, 1, 1, 1, 1) 132 | self.input_layout.addWidget(self.noteBox, 1, 2, 1, 1) 133 | self.input_layout.addWidget(self.out_sig_label, 3, 0, 1, 1) 134 | self.input_layout.addWidget(self.out_signals_combo, 4, 0, 1, 1) 135 | self.input_layout.addWidget(self.add_note_btn, 4, 1, 1, 1) 136 | self.input_layout.addWidget(self.options_sig_label,3,1,1,1) 137 | self.input_layout.addWidget(self.options_signals_combo, 4, 1, 1, 1) 138 | self.input_layout.addItem(QSpacerItem(0, 10), 5, 0, 1, 3) 139 | self.input_layout.addWidget(self.cancel_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 140 | self.input_layout.addWidget(self.ok_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 141 | 142 | self.conc_name_input.textChanged.connect(self.enable_ok_btn); 143 | self.input_frame.setFrameShape(QFrame.StyledPanel) 144 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 145 | self.input_frame.setContentsMargins(10, 10, 10, 10) 146 | self.input_frame.setFixedSize(600, 300) 147 | self.input_frame.setLayout(self.input_layout) 148 | self.add_note_btn.clicked.connect(self.add_conc_note) 149 | self.ok_btn.clicked.connect(self.get_data) 150 | self.cancel_btn.clicked.connect(self.cancel_selected) 151 | self.noteBox.clicked.connect(self.note_checked) 152 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 153 | 154 | self.setLayout(self.mainLayout) 155 | 156 | def populate_signals(self, proj_dir): 157 | 158 | if (proj_dir != None): 159 | root = minidom.parse(proj_dir) 160 | HDLGen = root.documentElement 161 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 162 | 163 | io_ports = hdlDesign[0].getElementsByTagName('entityIOPorts') 164 | signal_nodes = io_ports[0].getElementsByTagName('signal') 165 | 166 | intSignals = hdlDesign[0].getElementsByTagName('internalSignals') 167 | intSignal_nodes = intSignals[0].getElementsByTagName('signal') 168 | 169 | if len(signal_nodes) != 0 or len(intSignal_nodes) != 0: 170 | 171 | for i in range(0, len(signal_nodes)): 172 | name = signal_nodes[i].getElementsByTagName('name')[0].firstChild.data 173 | mode = signal_nodes[i].getElementsByTagName('mode')[0].firstChild.data 174 | 175 | if mode == "out": 176 | self.output_signals.append(name) 177 | else: 178 | if name != "clk" and name != "rst": 179 | self.input_signals.append(name) 180 | 181 | for i in range(0, len(intSignal_nodes)): 182 | internal_signal = intSignal_nodes[i].getElementsByTagName('name')[0].firstChild.data 183 | self.internal_signals.append(internal_signal) 184 | 185 | if len(self.output_signals) != 0 or len(self.internal_signals) != 0: 186 | 187 | self.output_signals.insert(0, "Select signal") 188 | self.out_signals_combo.addItems(self.output_signals + self.internal_signals ) 189 | self.output_signals.pop(0) 190 | self.options_signals_combo.addItem("zero") 191 | self.options_signals_combo.addItems(self.internal_signals + self.input_signals) 192 | 193 | else: 194 | self.out_sig_layout.addWidget(self.out_sig_empty_info, alignment=Qt.AlignTop) 195 | return 196 | 197 | self.out_sig_layout.addWidget(self.out_sig_empty_info, alignment=Qt.AlignTop) 198 | 199 | def load_conc_data(self, conc_data): 200 | 201 | self.conc_name_input.setText(conc_data[1]) 202 | self.conc_notes = conc_data[3] 203 | if self.conc_notes != "None": 204 | self.noteBox.setChecked(True) 205 | self.add_note_btn.setVisible(True) 206 | self.options_sig_label.setVisible(False) 207 | self.options_signals_combo.setVisible(False) 208 | self.add_note_btn.setText("Edit Custom Value") 209 | if len(conc_data[2]) != 0: 210 | temp = conc_data[2][0].split(",") 211 | out_sig = temp[0] 212 | out_val = temp[1] 213 | self.out_signals_combo.setCurrentText(out_sig) 214 | self.options_signals_combo.setCurrentText(out_val) 215 | self.out_val_input.setEnabled(False) 216 | 217 | 218 | def get_data(self): 219 | data = [] 220 | out_sig = [] 221 | concurrentName = self.conc_name_input.text().strip().replace(" ", "") 222 | if concurrentName[-2:] != "_c": 223 | concurrentName=concurrentName+"_c" 224 | data.append(concurrentName) 225 | output = self.out_signals_combo.currentText() 226 | if self.noteBox.isChecked(): 227 | out_sig.append(output+",zero") 228 | else: 229 | self.conc_notes = "None" 230 | value = self.options_signals_combo.currentText() 231 | out_sig.append(output + "," + value) 232 | data.append(out_sig) 233 | data.append(self.conc_notes) 234 | 235 | self.cancelled = False 236 | self.close() 237 | return data 238 | 239 | def cancel_selected(self): 240 | self.cancelled = True 241 | self.close() 242 | def enable_ok_btn(self): 243 | if self.conc_name_input.text() != ""and (self.conc_name_input.text()+"_c" not in self.conc_names or self.conc_name_input.text() == self.conc_name[:-2] ) and (self.conc_name_input.text() not in self.conc_names or self.conc_name_input.text() == self.conc_name): 244 | self.ok_btn.setEnabled(True) 245 | else: 246 | self.ok_btn.setEnabled(False) 247 | 248 | def add_conc_note(self): 249 | button = self.sender() 250 | if button: 251 | if button.text() == "Edit Custom Value": 252 | add_note = note_Dialog("edit", "Concurrent Statement Custom Value",self.conc_notes) 253 | else: 254 | add_note = note_Dialog("add", "Concurrent Statement Custom Value",self.conc_notes) 255 | add_note.exec_() 256 | 257 | if not add_note.cancelled: 258 | note_data = add_note.get_data() 259 | note_data = re.sub(r'\s+', ' ', note_data) 260 | if note_data == "None": 261 | self.add_note_btn.setText("Add Custom Value") 262 | else: 263 | self.add_note_btn.setText("Edit Custom Value") 264 | self.conc_notes = note_data 265 | 266 | def note_checked(self): 267 | if self.noteBox.isChecked(): 268 | self.add_note_btn.setVisible(True) 269 | self.options_sig_label.setVisible(False) 270 | self.options_signals_combo.setVisible(False) 271 | else: 272 | self.add_note_btn.setVisible(False) 273 | self.options_sig_label.setVisible(True) 274 | self.options_signals_combo.setVisible(True) 275 | def disable_Binary_input(self): 276 | combo = self.sender() 277 | if combo: 278 | if combo.currentText() == "Binary": 279 | self.out_val_input.setEnabled(True) 280 | self.out_val_input.setPlaceholderText("Eg. 1") 281 | else: 282 | self.out_val_input.clear() 283 | self.out_val_input.setPlaceholderText("") 284 | self.out_val_input.setEnabled(False) 285 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Architecture/note_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for note called by concurrenentstmt_dialog.py or process_dialog.py 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import sys 5 | 6 | sys.path.append("..") 7 | 8 | BLACK_COLOR = "color: black" 9 | WHITE_COLOR = "color: white" 10 | 11 | 12 | class note_Dialog(QDialog): 13 | 14 | def __init__(self, add_or_edit, noteType, note_data=None): 15 | super().__init__() 16 | 17 | self.input_layout = QGridLayout() 18 | self.setWindowTitle(noteType) 19 | self.noteType = noteType 20 | title_font = QFont() 21 | title_font.setPointSize(10) 22 | title_font.setBold(True) 23 | bold_font = QFont() 24 | bold_font.setBold(True) 25 | input_font = QFont() 26 | input_font.setPointSize(10) 27 | self.mainLayout = QVBoxLayout() 28 | 29 | self.note_label = QLabel(noteType) 30 | self.note_label.setFont(input_font) 31 | self.note_label.setStyleSheet(WHITE_COLOR) 32 | self.note_input = QPlainTextEdit() 33 | self.note_input.setLineWrapMode(QPlainTextEdit.NoWrap) 34 | self.note_input.setFont(input_font) 35 | 36 | self.cancel_btn = QPushButton("Cancel") 37 | self.cancel_btn.setFont(input_font) 38 | self.cancel_btn.setStyleSheet( 39 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 40 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 41 | 42 | self.ok_btn = QPushButton("Ok") 43 | self.ok_btn.setFont(input_font) 44 | self.ok_btn.setStyleSheet( 45 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 46 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 47 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 48 | 49 | self.input_frame = QFrame() 50 | 51 | self.cancelled = True 52 | 53 | self.setup_ui() 54 | if add_or_edit == "edit" and note_data is not None: 55 | self.load_sig_data(note_data) 56 | 57 | def setup_ui(self): 58 | 59 | self.input_layout.addWidget(self.note_label, 0, 0, 1, 1) 60 | self.input_layout.addWidget(self.note_input, 1, 0, 4, 3) 61 | self.input_layout.addWidget(self.cancel_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 62 | self.input_layout.addWidget(self.ok_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 63 | 64 | self.input_frame.setFrameShape(QFrame.StyledPanel) 65 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 66 | self.input_frame.setContentsMargins(10, 10, 10, 10) 67 | self.input_frame.setLayout(self.input_layout) 68 | if self.noteType == "Concurrent Statement Custom Value": 69 | self.input_frame.setFixedSize(700, 350) 70 | else: 71 | self.input_frame.setFixedSize(700, 700) 72 | 73 | self.ok_btn.clicked.connect(self.get_data) 74 | self.cancel_btn.clicked.connect(self.cancel_selected) 75 | 76 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 77 | 78 | self.setLayout(self.mainLayout) 79 | 80 | 81 | def load_sig_data(self, note_data): 82 | if note_data == "None": 83 | note_data="" 84 | note_data = note_data.replace(" ", "\n") 85 | note_data = note_data.replace("&","&") 86 | note_data = note_data.replace("&", "&") 87 | note_data = note_data.replace(""","\"") 88 | note_data = note_data.replace("'","\'") 89 | note_data = note_data.replace("<","<") 90 | note_data = note_data.replace(" ","\t") 91 | note_data = note_data.replace(">",">") 92 | note_data = note_data.replace(",",",") 93 | self.note_input.setPlainText(note_data) 94 | 95 | def get_data(self): 96 | data = self.note_input.toPlainText().strip() 97 | cursor = self.note_input.textCursor() 98 | doc = self.note_input.document() 99 | lines = "" 100 | line = "" 101 | for i in range(doc.blockCount()): 102 | block = doc.findBlockByNumber(i) 103 | if block.isVisible(): 104 | for j in range(block.layout().lineCount()): 105 | lineStart = block.position() + block.layout().lineAt(j).textStart() 106 | lineEnd = lineStart + block.layout().lineAt(j).textLength() 107 | cursor.setPosition(lineStart) 108 | cursor.setPosition(lineEnd, QTextCursor.KeepAnchor) 109 | line += cursor.selectedText() 110 | if lineEnd == cursor.position(): 111 | lines += line + "\n" 112 | line = "" 113 | lines = lines.strip() 114 | data = lines 115 | data=data.replace("&","&") 116 | data=data.replace("\n", " ") 117 | data = data.replace("\"", """) 118 | data = data.replace("\'", "'") 119 | data = data.replace("\n", " ") 120 | data = data.replace("<", "<") 121 | data = data.replace("\t", " ") 122 | data = data.replace(">", ">") 123 | data=data.replace(",",",") 124 | if data == "": 125 | data = "None" 126 | self.cancelled = False 127 | self.close() 128 | return data 129 | 130 | def cancel_selected(self): 131 | self.cancelled = True 132 | self.close() 133 | -------------------------------------------------------------------------------- /Application/HDLDesigner/ChatGPT/VHDLModel.py: -------------------------------------------------------------------------------- 1 | #Called in generation.py used for editing the ChatGPT Prompt header 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import yaml 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VHDLModelDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT VHDL Model Command") 15 | title_font = QFont() 16 | title_font.setPointSize(10) 17 | title_font.setBold(True) 18 | bold_font = QFont() 19 | bold_font.setBold(True) 20 | input_font = QFont() 21 | input_font.setPointSize(10) 22 | self.input_layout = QGridLayout() 23 | self.mainLayout = QVBoxLayout() 24 | 25 | self.ChatGPT_model_label = QLabel("ChatGPT Model Commands") 26 | self.ChatGPT_model_label.setStyleSheet(WHITE_COLOR) 27 | self.ChatGPT_model_label.setFont(input_font) 28 | self.ChatGPT_model_input = QPlainTextEdit() 29 | self.ChatGPT_model_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 30 | self.ChatGPT_model_input.setFont(input_font) 31 | 32 | 33 | self.reset_btn = QPushButton("Reset") 34 | self.reset_btn.setFont(input_font) 35 | self.reset_btn.setStyleSheet( 36 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 37 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 38 | 39 | self.cancel_btn = QPushButton("Cancel") 40 | self.cancel_btn.setFont(input_font) 41 | self.cancel_btn.setStyleSheet( 42 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 43 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 44 | 45 | self.ok_btn = QPushButton("Ok") 46 | self.ok_btn.setFont(input_font) 47 | self.ok_btn.setStyleSheet( 48 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 49 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 50 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 51 | self.input_frame = QFrame() 52 | 53 | self.cancelled = True 54 | 55 | self.setup_ui() 56 | 57 | self.load_data() 58 | 59 | def setup_ui(self): 60 | self.input_layout.addWidget(self.ChatGPT_model_label, 0, 0, 1, 4) 61 | self.input_layout.addWidget(self.ChatGPT_model_input, 1, 0, 4, 4) 62 | self.input_layout.addWidget(self.reset_btn, 5, 1, 1, 1, alignment=Qt.AlignRight) 63 | self.input_layout.addWidget(self.cancel_btn, 5, 2, 1, 1, alignment=Qt.AlignRight) 64 | self.input_layout.addWidget(self.ok_btn, 5, 3, 1, 1, alignment=Qt.AlignRight) 65 | self.input_frame.setFrameShape(QFrame.StyledPanel) 66 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 67 | self.input_frame.setContentsMargins(10, 10, 10, 10) 68 | self.input_frame.setFixedSize(900, 800) 69 | self.input_frame.setLayout(self.input_layout) 70 | self.cancel_btn.clicked.connect(self.cancel_selected) 71 | 72 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 73 | 74 | self.setLayout(self.mainLayout) 75 | self.ok_btn.clicked.connect(self.get_data) 76 | self.reset_btn.clicked.connect(self.reset) 77 | 78 | def cancel_selected(self): 79 | self.cancelled = True 80 | self.close() 81 | 82 | def load_data(self): 83 | with open('prompts.yml', 'r') as prompts: 84 | self.config = yaml.safe_load(prompts) 85 | 86 | data = self.config["vhdlchatgptmodel"] 87 | 88 | self.ChatGPT_model_input.setPlainText(data) 89 | 90 | def get_data(self): 91 | data = self.ChatGPT_model_input.toPlainText().strip() 92 | self.cancelled = False 93 | self.close() 94 | return data 95 | 96 | def reset(self): 97 | with open('prompts.yml', 'r') as prompts: 98 | self.config = yaml.safe_load(prompts) 99 | 100 | data = self.config["vhdlchatgptmodelreset"] 101 | 102 | self.ChatGPT_model_input.setPlainText(data) -------------------------------------------------------------------------------- /Application/HDLDesigner/ChatGPT/VerilogModel.py: -------------------------------------------------------------------------------- 1 | #Called in generation.py used for editing the ChatGPT Prompt header 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import yaml 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VerilogModelDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT Verilog Model Command") 15 | title_font = QFont() 16 | title_font.setPointSize(10) 17 | title_font.setBold(True) 18 | bold_font = QFont() 19 | bold_font.setBold(True) 20 | input_font = QFont() 21 | input_font.setPointSize(10) 22 | self.input_layout = QGridLayout() 23 | self.mainLayout = QVBoxLayout() 24 | 25 | self.ChatGPT_model_label = QLabel("ChatGPT Model Commands") 26 | self.ChatGPT_model_label.setStyleSheet(WHITE_COLOR) 27 | self.ChatGPT_model_label.setFont(input_font) 28 | self.ChatGPT_model_input = QPlainTextEdit() 29 | self.ChatGPT_model_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 30 | self.ChatGPT_model_input.setFont(input_font) 31 | 32 | 33 | self.reset_btn = QPushButton("Reset") 34 | self.reset_btn.setFont(input_font) 35 | self.reset_btn.setStyleSheet( 36 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 37 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 38 | 39 | self.cancel_btn = QPushButton("Cancel") 40 | self.cancel_btn.setFont(input_font) 41 | self.cancel_btn.setStyleSheet( 42 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 43 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 44 | 45 | self.ok_btn = QPushButton("Ok") 46 | self.ok_btn.setFont(input_font) 47 | self.ok_btn.setStyleSheet( 48 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 49 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 50 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 51 | self.input_frame = QFrame() 52 | 53 | self.cancelled = True 54 | 55 | self.setup_ui() 56 | 57 | self.load_data() 58 | 59 | def setup_ui(self): 60 | self.input_layout.addWidget(self.ChatGPT_model_label, 0, 0, 1, 4) 61 | self.input_layout.addWidget(self.ChatGPT_model_input, 1, 0, 4, 4) 62 | self.input_layout.addWidget(self.reset_btn, 5, 1, 1, 1, alignment=Qt.AlignRight) 63 | self.input_layout.addWidget(self.cancel_btn, 5, 2, 1, 1, alignment=Qt.AlignRight) 64 | self.input_layout.addWidget(self.ok_btn, 5, 3, 1, 1, alignment=Qt.AlignRight) 65 | self.input_frame.setFrameShape(QFrame.StyledPanel) 66 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 67 | self.input_frame.setContentsMargins(10, 10, 10, 10) 68 | self.input_frame.setFixedSize(900, 800) 69 | self.input_frame.setLayout(self.input_layout) 70 | self.cancel_btn.clicked.connect(self.cancel_selected) 71 | 72 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 73 | 74 | self.setLayout(self.mainLayout) 75 | self.ok_btn.clicked.connect(self.get_data) 76 | self.reset_btn.clicked.connect(self.reset) 77 | 78 | def cancel_selected(self): 79 | self.cancelled = True 80 | self.close() 81 | 82 | def load_data(self): 83 | with open('prompts.yml', 'r') as prompts: 84 | self.config = yaml.safe_load(prompts) 85 | 86 | data = self.config["verilogchatgptmodel"] 87 | 88 | self.ChatGPT_model_input.setPlainText(data) 89 | 90 | def get_data(self): 91 | data = self.ChatGPT_model_input.toPlainText().strip() 92 | self.cancelled = False 93 | self.close() 94 | return data 95 | 96 | def reset(self): 97 | with open('prompts.yml', 'r') as prompts: 98 | self.config = yaml.safe_load(prompts) 99 | 100 | data = self.config["verilogchatgptmodelreset"] 101 | 102 | self.ChatGPT_model_input.setPlainText(data) -------------------------------------------------------------------------------- /Application/HDLDesigner/ChatGPT/chatgpt_help.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | - Selection of VHDL or Verilog generation is performed in the HDL Designer menu 4 | 5 | - This menu 6 | 7 | - loads and previews the default ChatGPT prompt headers 8 | - Model 9 | - enables editing of the ChatGPT prompt headers 10 | 11 | - Generates and previews HDL templates (and backups the previous version) for 12 | - HDL model 13 | - HDL testbench 14 | 15 | - Assembles, previews, copies the ChatGPT prompt, for (and backups the previous prompt) 16 | - completion of HDL model 17 | - ChatGPT prompt header elements 18 | - ChatGPT prompt header for HDL model template completion 19 | - HDLGen-ChatGPT-generated HDL model tempalte 20 | - generation of HDL testbench stim_p stimulus and signal checking 21 | - ChatGPT prompt header elements 22 | - ChatGPT prompt header for HDL testbench stim_p generation 23 | - testbench signal declarations 24 | - test plan (fromatted) 25 | 26 | - Accesses 27 | - folder 28 | - AMD simulator log files 29 | - backups and clears backup files) 30 | 31 | 32 | HDLGen-ChatGPT allows users to modify and test the ChatGPT prompt headers. 33 | This facilitates handling of any issue uncovered during HDL generation for a particular design, 34 | or accommodating any future changes which may occur in ChatGPT functionality, affecting generated HDL code output. 35 | 36 | The Edit ChatGPT Prompt Header menu opens an editor, displaying and facilitating editing of the selected 37 | ChatGPT prompt and descriptive comment (with ~ comment prefix). 38 | ChatGPT prompts in the HDL Designer > Generate menu, are used for HDL model and HDL testbench HDL generation. 39 | The user selects VHDL or Verilog in the Project Manager TAB. 40 | 41 | An issue can be detected in a generated HDL process or concurrent statement, on review of ChatGPT code or 42 | by a warning or error flagged in the EDA tool. The ChatGPT prompt header can include comments using (~) prefix, 43 | with a ChatGPT prompt instruction to ignore these comments. 44 | 45 | Prompt header comments can be used for description of the reason for the prompt, though also to filter 46 | a ChatGPT prompt to output an individual HDL section, e.g, process or concurrent statement. 47 | The user can subsequently submit focused ChatGPT prompts to query the generated code segment, and request 48 | alternative ChatGPT output. The refined HDL output segment can be pasted into the EDA tool, for further checking 49 | and processing. This incremental HDL generation approach can be very effective. Backups of all ChatGPT prompts 50 | are automatically generated and can be accessed through the HDLGen-ChatGPT generate menu. Note that the incremental 51 | approach diverges from the use of a single crafted ChatGPT prompt and requires the recording of subsequent prompts 52 | by the user, since re-running the original ChatGPT prompt over-writes the latest generated HDL. 53 | 54 | An issue can be detected in a generated HDL process or concurrent statement, on review of ChatGPT code 55 | or by a warning or error flagged in the EDA tool. The ChatGPT prompt header can include comments using (~) prefix, 56 | with a ChatGPT prompt instruction to ignore these comments. Prompt header comments can be used for description of 57 | the reason for the prompt, though also to filter a ChatGPT prompt to output an individual HDL section, e.g, process 58 | or concurrent statement. The user can subsequently submit focused ChatGPT prompts to query the generated code segment, 59 | and request alternative ChatGPT output. The refined HDL output segment can be pasted into the EDA tool, for further 60 | checking and processing. This incremental HDL generation approach can be very effective. Backups of all ChatGPT 61 | prompts are automatically generated and can be accessed through the HDLGen-ChatGPT generate menu. Note that the 62 | incremental approach diverges from the use of a single crafted ChatGPT prompt and requires the recording of subsequent 63 | prompts by the user, since re-running the original ChatGPT prompt over-writes the latest generated HDL. 64 | 65 | 66 | -------------------------------------------------------------------------------- /Application/HDLDesigner/ChatGPT/chatgpt_help.py: -------------------------------------------------------------------------------- 1 | import markdown as md 2 | from PySide2.QtWidgets import * 3 | 4 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/ChatGPT/chatgpt_help.md" 5 | 6 | 7 | class ChatGPTHelpDialog(QDialog): 8 | 9 | def __init__(self): 10 | super().__init__() 11 | self.setWindowTitle("HDLGen Help") 12 | 13 | self.markdown_view = QTextBrowser(readOnly=True) 14 | self.markdown_view.setOpenExternalLinks(True) 15 | 16 | self.mainLayout = QVBoxLayout() 17 | self.setFixedSize(800, 800) 18 | self.setup_ui() 19 | 20 | def setup_ui(self): 21 | 22 | # Writing xml file 23 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 24 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 25 | self.markdown_view.setHtml(doc) 26 | self.mainLayout.addWidget(self.markdown_view) 27 | self.setLayout(self.mainLayout) 28 | 29 | -------------------------------------------------------------------------------- /Application/HDLDesigner/IOPorts/io_port_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for adding/editing port signals called in the io_ports.py class. 2 | from xml.dom import minidom 3 | 4 | from PySide2 import QtWidgets 5 | from PySide2.QtCore import QSizeF 6 | from PySide2.QtWidgets import * 7 | from PySide2.QtGui import * 8 | 9 | BLACK_COLOR = "color: black" 10 | WHITE_COLOR = "color: white" 11 | from ProjectManager.project_manager import ProjectManager 12 | class IOPortDialog(QDialog): 13 | 14 | def __init__(self, add_or_edit, signals_names, signal_data = None): 15 | super().__init__() 16 | input_font = QFont() 17 | input_font.setPointSize(10) 18 | self.input_layout = QGridLayout() 19 | 20 | if add_or_edit == "add": 21 | self.setWindowTitle("New IO Port") 22 | elif add_or_edit == "edit": 23 | self.setWindowTitle("Edit IO Port") 24 | self.signalNames = signals_names 25 | self.signalName="" 26 | if signal_data != None: 27 | self.signalName = signal_data[0] 28 | self.mainLayout = QVBoxLayout() 29 | 30 | self.sig_name_label = QLabel("Signal Name *") 31 | self.sig_name_label.setStyleSheet(WHITE_COLOR) 32 | self.sig_name_label.setFont(input_font) 33 | self.sig_name_input = QLineEdit() 34 | self.sig_name_input.setFont(input_font) 35 | 36 | 37 | self.sig_mode_label = QLabel("Mode") 38 | self.sig_mode_label.setStyleSheet(WHITE_COLOR) 39 | self.sig_mode_label.setFont(input_font) 40 | self.sig_mode_input = QComboBox() 41 | self.sig_mode_input.setFont(input_font) 42 | self.sig_mode_input.setStyleSheet("QComboBox {padding: 2px;}") 43 | pal = self.sig_mode_input.palette() 44 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 45 | self.sig_mode_input.setPalette(pal) 46 | self.sig_mode_input.addItem("Input") 47 | self.sig_mode_input.addItem("Output") 48 | 49 | self.sig_type_label = QLabel("Type") 50 | self.sig_type_label.setStyleSheet(WHITE_COLOR) 51 | self.sig_type_label.setFont(input_font) 52 | self.sig_type_input = QComboBox() 53 | self.sig_type_input.setFont(input_font) 54 | self.sig_type_input.setStyleSheet("QComboBox {padding: 2px;}") 55 | pal = self.sig_type_input.palette() 56 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 57 | self.sig_type_input.setPalette(pal) 58 | self.sig_type_input.addItem("single bit") 59 | self.sig_type_input.addItem("bus") 60 | self.sig_type_input.addItem(("array")) 61 | 62 | self.sig_size_label = QLabel("Size (eg. 32) * ") 63 | self.sig_size_label.setStyleSheet(WHITE_COLOR) 64 | self.sig_size_label.setFont(input_font) 65 | self.sig_size_input = QLineEdit() 66 | self.sig_size_input.setFont(input_font) 67 | self.sig_size_input.setText("1") 68 | self.sig_size_input.setEnabled(False) 69 | self.sig_size_input.setFont(input_font) 70 | 71 | self.arrayName_label = QLabel("Arrays") 72 | self.arrayName_label.setStyleSheet(WHITE_COLOR) 73 | self.arrayName_label.setFont(input_font) 74 | self.arrayName_input = QComboBox() 75 | self.arrayName_input.setFont(input_font) 76 | self.arrayName_input.setStyleSheet("QComboBox {padding: 2px;}") 77 | pal = self.arrayName_input.palette() 78 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 79 | self.arrayName_input.setPalette(pal) 80 | self.arrayName_label.setVisible(False) 81 | self.arrayName_input.setVisible(False) 82 | self.arrayName_input.setCurrentText("Create in packages") 83 | 84 | self.onlyInt = QIntValidator() 85 | self.sig_size_input.setValidator(self.onlyInt) 86 | 87 | self.sig_description_label = QLabel("Signal Description") 88 | self.sig_description_label.setStyleSheet(WHITE_COLOR) 89 | self.sig_description_label.setFont(input_font) 90 | self.sig_description_input = QPlainTextEdit()#MyPlainTextEdit()#QPlainTextEdit()#QLineEdit() 91 | self.sig_description_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 92 | self.sig_description_input.setFont(input_font) 93 | 94 | self.cancel_btn = QPushButton("Cancel") 95 | self.cancel_btn.setFont(input_font) 96 | self.cancel_btn.setStyleSheet( 97 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 98 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 99 | 100 | self.ok_btn = QPushButton("Ok") 101 | self.ok_btn.setEnabled(False) 102 | self.ok_btn.setFont(input_font) 103 | self.ok_btn.setStyleSheet( 104 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 105 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 106 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 107 | 108 | self.input_frame = QFrame() 109 | 110 | self.cancelled = True 111 | self.arrays=[] 112 | self.setup_ui() 113 | mainPackageDir = ProjectManager.get_package_hdlgen() 114 | root = minidom.parse(mainPackageDir) 115 | HDLGen = root.documentElement 116 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 117 | mainPackage = hdlDesign[0].getElementsByTagName("mainPackage") 118 | array_nodes = mainPackage[0].getElementsByTagName('array') 119 | 120 | 121 | if len(array_nodes) != 0: 122 | for i in range(0, len(array_nodes)): 123 | array_name = array_nodes[i].getElementsByTagName('name')[0].firstChild.data 124 | self.arrays.append(array_name) 125 | self.arrayName_input.addItems(self.arrays) 126 | 127 | if add_or_edit == "edit" and signal_data != None: 128 | self.load_signal_data(signal_data) 129 | 130 | def setup_ui(self): 131 | self.input_layout.addWidget(self.sig_name_label, 0, 0, 1, 1) 132 | self.input_layout.addWidget(self.sig_name_input, 1, 0, 1, 1) 133 | self.input_layout.addWidget(self.sig_mode_label, 0, 1, 1, 1) 134 | self.input_layout.addWidget(self.sig_mode_input, 1, 1, 1, 1) 135 | self.input_layout.addWidget(self.sig_type_label, 2, 0, 1, 1) 136 | self.input_layout.addWidget(self.sig_type_input, 3, 0, 1, 1) 137 | self.input_layout.addWidget(self.sig_size_label, 2, 1, 1, 1) 138 | self.input_layout.addWidget(self.sig_size_input, 3, 1, 1, 1) 139 | self.input_layout.addWidget(self.arrayName_label, 2, 1, 1, 1) 140 | self.input_layout.addWidget(self.arrayName_input, 3, 1, 1, 1) 141 | self.input_layout.addWidget(self.sig_description_label, 4, 0, 1, 2) 142 | self.input_layout.addWidget(self.sig_description_input, 5, 0, 1, 2) 143 | self.input_layout.addItem(QSpacerItem(0, 20), 6, 0, 1, 2) 144 | self.input_layout.addWidget(self.cancel_btn, 7, 0, 1, 1, alignment=Qt.AlignRight) 145 | self.input_layout.addWidget(self.ok_btn, 7, 1, 1, 1, alignment=Qt.AlignRight) 146 | 147 | self.input_frame.setFrameShape(QFrame.StyledPanel) 148 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 149 | self.input_frame.setContentsMargins(10, 10, 10, 10) 150 | self.input_frame.setFixedSize(600, 600) 151 | self.input_frame.setLayout(self.input_layout) 152 | 153 | self.sig_name_input.textChanged.connect(self.enable_ok_btn); 154 | self.sig_size_input.textChanged.connect(self.enable_ok_btn); 155 | self.sig_type_input.currentTextChanged.connect(self.enable_size_option) 156 | self.sig_type_input.currentTextChanged.connect(self.sig_type_options) 157 | self.ok_btn.clicked.connect(self.get_signals) 158 | self.cancel_btn.clicked.connect(self.cancel_selected) 159 | 160 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 161 | 162 | self.setLayout(self.mainLayout) 163 | 164 | def get_signals(self): 165 | cursor = self.sig_description_input.textCursor() 166 | doc = self.sig_description_input.document() 167 | lines = "" 168 | line = "" 169 | for i in range(doc.blockCount()): 170 | block = doc.findBlockByNumber(i) 171 | if block.isVisible(): 172 | for j in range(block.layout().lineCount()): 173 | lineStart = block.position() + block.layout().lineAt(j).textStart() 174 | lineEnd = lineStart + block.layout().lineAt(j).textLength() 175 | cursor.setPosition(lineStart) 176 | cursor.setPosition(lineEnd, QTextCursor.KeepAnchor) 177 | line += cursor.selectedText() 178 | if lineEnd == cursor.position(): 179 | lines += line+"\n" 180 | line = "" 181 | lines=lines.strip() 182 | signalDescription=lines 183 | signalDescription = signalDescription.replace("&", "&") 184 | signalDescription = signalDescription.replace("\n", " ") 185 | signalDescription = signalDescription.replace("\"", """) 186 | signalDescription = signalDescription.replace("\'", "'") 187 | signalDescription = signalDescription.replace("\n", " ") 188 | signalDescription = signalDescription.replace("<", "<") 189 | signalDescription = signalDescription.replace("\t", " ") 190 | signalDescription = signalDescription.replace(">", ">") 191 | signalDescription = signalDescription.replace(",", ",") 192 | 193 | if signalDescription == "": 194 | signalDescription = "to be completed" 195 | if self.sig_type_input.currentText() == "array": 196 | typeValue= "array,"+self.arrayName_input.currentText() 197 | else: 198 | typeValue= self.sig_type_input.currentText() 199 | sig_details = [self.sig_name_input.text().strip().replace(" ", ""), 200 | self.sig_mode_input.currentText(), 201 | typeValue, 202 | self.sig_size_input.text(), 203 | signalDescription 204 | ] 205 | self.cancelled = False 206 | self.close() 207 | return sig_details 208 | 209 | def load_signal_data(self, signal_data): 210 | self.sig_name_input.setText(signal_data[0]) 211 | self.sig_mode_input.setCurrentText(signal_data[1]) 212 | sig_type=signal_data[2] 213 | if sig_type != "bus" and signal_data[2] != "single bit": 214 | sig_type = "array" 215 | arrayname = signal_data[2].split(",") 216 | self.arrayName_input.setCurrentText(arrayname[1]) 217 | self.sig_type_input.setCurrentText(sig_type) 218 | self.sig_size_input.setText(signal_data[3]) 219 | signal_data[4] = signal_data[4].replace(" ", "\n") 220 | signal_data[4] = signal_data[4].replace("&", "&") 221 | signal_data[4] = signal_data[4].replace("&", "&") 222 | signal_data[4] = signal_data[4].replace(""", "\"") 223 | signal_data[4] = signal_data[4].replace("'", "\'") 224 | signal_data[4] = signal_data[4].replace("<", "<") 225 | signal_data[4] = signal_data[4].replace(" ", "\t") 226 | signal_data[4] = signal_data[4].replace(">", ">") 227 | signal_data[4] = signal_data[4].replace(",", ",") 228 | 229 | self.sig_description_input.setPlainText(signal_data[4]) 230 | 231 | def cancel_selected(self): 232 | self.cancelled = True 233 | self.close() 234 | 235 | def enable_ok_btn(self): 236 | if self.sig_name_input.text() != "" and self.sig_size_input.text() != "" and (self.sig_name_input.text() not in self.signalNames or (self.sig_name_input.text() == self.signalName and self.sig_name_input.text() != "")): 237 | self.ok_btn.setEnabled(True) 238 | else: 239 | if self.sig_name_input.text() != "" and self.sig_type_input.currentText() == "array" and self.arrayName_input.currentText() != "": 240 | self.ok_btn.setEnabled(True) 241 | else: 242 | self.ok_btn.setEnabled(False) 243 | 244 | def enable_size_option(self): 245 | if self.sig_type_input.currentText() == "bus": 246 | self.sig_size_input.setEnabled(True) 247 | self.sig_size_input.clear() 248 | else: 249 | self.sig_size_input.setEnabled(False) 250 | self.sig_size_input.setText("1") 251 | def sig_type_options(self): 252 | if self.sig_type_input.currentText() == "array": 253 | self.arrayName_label.setVisible(True) 254 | self.arrayName_input.setVisible(True) 255 | self.sig_size_input.setVisible(False) 256 | self.sig_size_label.setVisible(False) 257 | 258 | else: 259 | self.sig_size_input.setVisible(True) 260 | self.sig_size_label.setVisible(True) 261 | self.arrayName_label.setVisible(False) 262 | self.arrayName_input.setVisible(False) 263 | -------------------------------------------------------------------------------- /Application/HDLDesigner/IOPorts/port_help.md: -------------------------------------------------------------------------------- 1 | # Port 2 | 3 | - This menu enables the creation and editing of component port signals, with 4 | - port direction: input or output 5 | - port signal type 6 | 7 | - The menu display name, mode, type and size for added port signals 8 | 9 | - If select 'combinational' 10 | - add signal 11 | - signal name 12 | - mode: input or output 13 | - type: single bit, bus, array 14 | - size (width): enter value in the field 15 | - signal description: capture the signal dictionary information fromt the design specification 16 | - Click OK to complete 17 | 18 | - If select 'RTL' 19 | - Setup clk/rst menu appears. Click to open menu. 20 | - L-H low to high active clk edge 21 | - H-L high to low active clk edge 22 | - rst 23 | - No if component does not include a rst input 24 | - Yes 25 | - rst type 26 | - Asynch: asynchronous rst 27 | - Synch: synchronous rst 28 | - active rst level 29 | - 0, asserted low 30 | - 1, asserted high 31 | - Click OK to complete 32 | 33 | - The existing port signals are listed and can be edited or deleted. -------------------------------------------------------------------------------- /Application/HDLDesigner/IOPorts/port_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/IOPorts/port_help.md" 6 | 7 | 8 | class IoHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/IOPorts/sequential_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for adding/editing rtl logic called in the io_ports.py class. 2 | import sys 3 | from xml.dom import minidom 4 | from PySide2.QtWidgets import * 5 | from PySide2.QtGui import * 6 | 7 | 8 | 9 | sys.path.append("..") 10 | 11 | BLACK_COLOR = "color: black" 12 | WHITE_COLOR = "color: white" 13 | 14 | class seqDialog(QDialog): 15 | 16 | def __init__(self, proj_dir): 17 | super().__init__() 18 | input_font = QFont() 19 | input_font.setPointSize(10) 20 | self.input_layout = QGridLayout() 21 | self.setWindowTitle("Set up clk/rst") 22 | 23 | self.mainLayout = QVBoxLayout() 24 | 25 | 26 | self.activeClkEdge_label = QLabel("Active Clk Edge") 27 | self.activeClkEdge_label.setFont(input_font) 28 | self.activeClkEdge_label.setStyleSheet(WHITE_COLOR) 29 | self.activeClkEdge_input = QComboBox() 30 | self.activeClkEdge_input.setFont(input_font) 31 | self.activeClkEdge_input.setStyleSheet("QComboBox {padding: 2px;}") 32 | pal = self.activeClkEdge_input.palette() 33 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 34 | self.activeClkEdge_input.setPalette(pal) 35 | self.activeClkEdge_input.addItem("L-H") 36 | self.activeClkEdge_input.addItem("H-L") 37 | 38 | self.rst_label = QLabel("rst") 39 | self.rst_label.setFont(input_font) 40 | self.rst_label.setStyleSheet(WHITE_COLOR) 41 | self.rst_input = QComboBox() 42 | self.rst_input.setFont(input_font) 43 | self.rst_input.setStyleSheet("QComboBox {padding: 2px;}") 44 | pal = self.rst_input.palette() 45 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 46 | self.rst_input.setPalette(pal) 47 | self.rst_input.addItem("No") 48 | self.rst_input.addItem("Yes") 49 | 50 | self.rstType_label = QLabel("rst type") 51 | self.rstType_label.setFont(input_font) 52 | self.rstType_label.setStyleSheet(WHITE_COLOR) 53 | self.rstType_label.setVisible(False) 54 | self.rstType_input = QComboBox() 55 | self.rstType_input.setFont(input_font) 56 | self.rstType_input.setStyleSheet("QComboBox {padding: 2px;}") 57 | pal = self.rstType_input.palette() 58 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 59 | self.rstType_input.setPalette(pal) 60 | self.rstType_input.addItem("asynch") 61 | self.rstType_input.addItem("synch") 62 | self.rstType_input.setVisible(False) 63 | 64 | self.activeRstLvlEq1_label = QLabel("Active rst lvl") 65 | self.activeRstLvlEq1_label.setStyleSheet(WHITE_COLOR) 66 | self.activeRstLvlEq1_label.setVisible(False) 67 | self.activeRstLvlEq1_label.setFont(input_font) 68 | self.activeRstLvlEq1_input = QComboBox() 69 | pal = self.activeRstLvlEq1_input.palette() 70 | self.activeRstLvlEq1_input.setFont(input_font) 71 | self.activeRstLvlEq1_input.setStyleSheet("QComboBox {padding: 2px;}") 72 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 73 | self.activeRstLvlEq1_input.setPalette(pal) 74 | self.activeRstLvlEq1_input.addItem("1") 75 | self.activeRstLvlEq1_input.addItem("0") 76 | self.activeRstLvlEq1_input.setVisible(False) 77 | 78 | self.cancel_btn = QPushButton("Cancel") 79 | self.cancel_btn.setFont(input_font) 80 | self.cancel_btn.setStyleSheet( 81 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 82 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 83 | 84 | self.ok_btn = QPushButton("Ok") 85 | self.ok_btn.setFont(input_font) 86 | self.ok_btn.setStyleSheet( 87 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 88 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 89 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 90 | 91 | self.input_frame = QFrame() 92 | 93 | self.cancelled = True 94 | 95 | self.setup_ui() 96 | 97 | if proj_dir != None: 98 | self.load_data(proj_dir) 99 | def setup_ui(self): 100 | self.input_layout.addWidget(self.activeClkEdge_label, 0, 0, 1, 1, alignment=Qt.AlignTop) 101 | self.input_layout.addWidget(self.activeClkEdge_input, 1, 0, 1, 1, alignment=Qt.AlignTop) 102 | self.input_layout.addWidget(self.rst_label, 0, 1, 1, 1, alignment=Qt.AlignTop) 103 | self.input_layout.addWidget(self.rst_input, 1, 1, 1, 1, alignment=Qt.AlignTop) 104 | self.input_layout.addItem(QSpacerItem(0, 100), 2, 0) 105 | self.input_layout.addWidget(self.rstType_label, 2, 0, 1, 1, alignment=Qt.AlignBottom) 106 | self.input_layout.addWidget(self.rstType_input, 3, 0, 1, 1, alignment=Qt.AlignTop) 107 | self.input_layout.addWidget(self.activeRstLvlEq1_label, 2, 1, 1, 1, alignment=Qt.AlignBottom) 108 | self.input_layout.addWidget(self.activeRstLvlEq1_input, 3, 1, 1, 1, alignment=Qt.AlignTop) 109 | self.input_layout.addItem(QSpacerItem(0, 100), 4, 0) 110 | self.input_layout.addWidget(self.cancel_btn, 5, 0, alignment=Qt.AlignRight) 111 | self.input_layout.addWidget(self.ok_btn, 5, 1, alignment=Qt.AlignRight) 112 | 113 | self.input_frame.setFrameShape(QFrame.StyledPanel) 114 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 115 | self.input_frame.setContentsMargins(10, 10, 10, 10) 116 | self.input_frame.setFixedSize(400, 400) 117 | self.input_frame.setLayout(self.input_layout) 118 | 119 | self.ok_btn.clicked.connect(self.get_clkAndRst) 120 | self.cancel_btn.clicked.connect(self.cancel_selected) 121 | self.rst_input.currentTextChanged.connect(self.rst_options) 122 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 123 | 124 | self.setLayout(self.mainLayout) 125 | 126 | def get_clkAndRst(self): 127 | if self.rst_input.currentText() == "Yes": 128 | clkAndRst_details = [self.activeClkEdge_input.currentText(), 129 | self.rst_input.currentText(), 130 | self.rstType_input.currentText(), 131 | self.activeRstLvlEq1_input.currentText() 132 | ] 133 | else: 134 | clkAndRst_details = [self.activeClkEdge_input.currentText(), 135 | self.rst_input.currentText() 136 | ] 137 | self.cancelled = False 138 | self.close() 139 | return clkAndRst_details 140 | def cancel_selected(self): 141 | self.cancelled = True 142 | self.close() 143 | 144 | 145 | 146 | def rst_options(self): 147 | if self.rst_input.currentText() == "Yes": 148 | self.rstType_label.setVisible(True) 149 | self.rstType_input.setVisible(True) 150 | self.activeRstLvlEq1_label.setVisible(True) 151 | self.activeRstLvlEq1_input.setVisible(True) 152 | else: 153 | self.rstType_label.setVisible(False) 154 | self.rstType_input.setVisible(False) 155 | self.activeRstLvlEq1_label.setVisible(False) 156 | self.activeRstLvlEq1_input.setVisible(False) 157 | 158 | def enable_size_option(self): 159 | if self.sig_type_input.currentText() == "Yes": 160 | self.sig_size_input.setEnabled(True) 161 | self.sig_size_input.clear() 162 | else: 163 | self.sig_size_input.setEnabled(False) 164 | self.sig_size_input.setText("1") 165 | 166 | def load_data(self, proj_dir): 167 | 168 | root = minidom.parse(str(proj_dir)) 169 | HDLGen = root.documentElement 170 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 171 | 172 | clkAndRst = hdlDesign[0].getElementsByTagName('clkAndRst') 173 | if clkAndRst[0].firstChild is not None: 174 | for i in range(0, len(clkAndRst)): 175 | clkEdgeValue = clkAndRst[i].getElementsByTagName('activeClkEdge')[0].firstChild.data 176 | rstValue = clkAndRst[i].getElementsByTagName('rst')[0].firstChild.data 177 | self.activeClkEdge_input.setCurrentText(clkEdgeValue) 178 | self.rst_input.setCurrentText(rstValue) 179 | if rstValue == "Yes": 180 | rstTypeValue = clkAndRst[i].getElementsByTagName('RstType')[0].firstChild.data 181 | rstLvlValue = clkAndRst[i].getElementsByTagName('ActiveRstLvl')[0].firstChild.data 182 | self.rstType_input.setCurrentText(rstTypeValue) 183 | self.activeRstLvlEq1_input.setCurrentText(rstLvlValue) 184 | -------------------------------------------------------------------------------- /Application/HDLDesigner/InternalSignal/internal_help.md: -------------------------------------------------------------------------------- 1 | # Internal Signal 2 | 3 | - This menu enables the creation and editing of internal signals 4 | 5 | - The menu display name, mode, type and size for added port signals 6 | 7 | - If select add signal 8 | - internal signal name 9 | 10 | - signal type 11 | 12 | - standard 13 | - single bit 14 | - bus 15 | - signed 16 | - unsigned 17 | - integer 18 | - signal description 19 | 20 | - state signal pair (NS/CS) 21 | - CS name 22 | - NS name 23 | - suffix 24 | - bus 25 | - size 26 | - signal description 27 | - enumerated type 28 | - add state 29 | - signal description 30 | - integer 31 | - no of values 32 | - signal description 33 | - size 34 | - signal description 35 | 36 | - array 37 | - select array name from list (created sub-components menu) 38 | - signal description 39 | 40 | - Click OK to complete 41 | 42 | - The existing internal signals are listed and can be edited or deleted 43 | -------------------------------------------------------------------------------- /Application/HDLDesigner/InternalSignal/internal_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/InternalSignal/internal_help.md" 6 | 7 | 8 | class IntHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/InternalSignal/stateNamesDialog.py: -------------------------------------------------------------------------------- 1 | #state names dialog called in int_sig_dialog.py if state name is added 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | 5 | import sys 6 | 7 | sys.path.append("..") 8 | from ProjectManager.project_manager import ProjectManager 9 | 10 | BLACK_COLOR = "color: black" 11 | WHITE_COLOR = "color: white" 12 | 13 | 14 | class state_Name_Dialog(QDialog): 15 | 16 | def __init__(self, add_or_edit, stateName_data=None): 17 | super().__init__() 18 | 19 | self.input_layout = QGridLayout() 20 | self.setWindowTitle("New State Name") 21 | 22 | title_font = QFont() 23 | title_font.setPointSize(10) 24 | title_font.setBold(True) 25 | bold_font = QFont() 26 | bold_font.setBold(True) 27 | input_font = QFont() 28 | input_font.setPointSize(10) 29 | self.mainLayout = QVBoxLayout() 30 | 31 | self.state_name_label = QLabel("State Name") 32 | self.state_name_label.setFont(input_font) 33 | self.state_name_label.setStyleSheet(WHITE_COLOR) 34 | self.state_name_input = QLineEdit() 35 | self.state_name_input.setFont(input_font) 36 | 37 | self.cancel_btn = QPushButton("Cancel") 38 | self.cancel_btn.setFont(input_font) 39 | self.cancel_btn.setStyleSheet( 40 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 41 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 42 | 43 | self.ok_btn = QPushButton("Ok") 44 | self.ok_btn.setEnabled(False) 45 | self.ok_btn.setFont(input_font) 46 | self.ok_btn.setStyleSheet( 47 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 48 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 49 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 50 | 51 | self.input_frame = QFrame() 52 | 53 | self.cancelled = True 54 | 55 | self.setup_ui() 56 | if add_or_edit == "edit" and stateName_data != None: 57 | self.load_sig_data(stateName_data) 58 | 59 | def setup_ui(self): 60 | 61 | self.input_layout.addWidget(self.state_name_label, 0, 0, 1, 1) 62 | self.input_layout.addWidget(self.state_name_input, 1, 0, 1, 3) 63 | 64 | 65 | self.input_layout.addItem(QSpacerItem(0, 20), 2, 0, 1, 3) 66 | self.input_layout.addWidget(self.cancel_btn, 3, 1, 1, 1, alignment=Qt.AlignRight) 67 | self.input_layout.addWidget(self.ok_btn, 3, 2, 1, 1, alignment=Qt.AlignRight) 68 | 69 | self.input_frame.setFrameShape(QFrame.StyledPanel) 70 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 71 | self.input_frame.setContentsMargins(10, 10, 10, 10) 72 | self.input_frame.setLayout(self.input_layout) 73 | 74 | self.state_name_input.textChanged.connect(self.enable_ok_btn); 75 | 76 | self.ok_btn.clicked.connect(self.get_data) 77 | self.cancel_btn.clicked.connect(self.cancel_selected) 78 | 79 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 80 | 81 | self.setLayout(self.mainLayout) 82 | 83 | 84 | def load_sig_data(self, stateName_data): 85 | self.state_name_input.setText(stateName_data) 86 | 87 | def get_data(self): 88 | state_name = self.state_name_input.text().strip().replace(" ", "") 89 | data = state_name 90 | self.cancelled = False 91 | self.close() 92 | return data 93 | 94 | def cancel_selected(self): 95 | self.cancelled = True 96 | self.close() 97 | 98 | def enable_ok_btn(self): 99 | if self.state_name_input.text() != "" : 100 | self.ok_btn.setEnabled(True) 101 | else: 102 | self.ok_btn.setEnabled(False) 103 | 104 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Package/package_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for adding/editing type called in the package.py class. 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import sys 5 | 6 | sys.path.append("..") 7 | 8 | BLACK_COLOR = "color: black" 9 | WHITE_COLOR = "color: white" 10 | 11 | 12 | class PackageDialog(QDialog): 13 | 14 | def __init__(self, add_or_edit, array_data=None): 15 | super().__init__() 16 | self.input_layout = QGridLayout() 17 | if add_or_edit == "add": 18 | self.setWindowTitle("New Package Signal") 19 | elif add_or_edit == "edit": 20 | self.setWindowTitle("Edit Package Signal") 21 | 22 | input_font = QFont() 23 | input_font.setPointSize(10) 24 | bold_font = QFont() 25 | bold_font.setBold(True) 26 | 27 | self.mainLayout = QVBoxLayout() 28 | self.sig_types = [ "bus", "signed", "unsigned"] 29 | self.array_name_label = QLabel("Array Name*") 30 | self.array_name_label.setStyleSheet(WHITE_COLOR) 31 | self.array_name_label.setFont(input_font) 32 | self.array_name_input = QLineEdit() 33 | self.array_name_input.setFont(input_font) 34 | 35 | self.arraySize_label = QLabel("Array Depth") 36 | self.arraySize_label.setFont(input_font) 37 | self.arraySize_label.setStyleSheet(WHITE_COLOR) 38 | self.arraySize_input = QLineEdit() 39 | self.arraySize_input.setFont(input_font) 40 | 41 | self.arrayLength_label = QLabel("Array Width") 42 | self.arrayLength_label.setStyleSheet(WHITE_COLOR) 43 | self.arrayLength_label.setFont(input_font) 44 | self.arrayLength_input = QLineEdit() 45 | self.arrayLength_input.setFont(input_font) 46 | 47 | self.sig_type_label = QLabel("Signal Type") 48 | self.sig_type_label.setFont(input_font) 49 | self.sig_type_label.setStyleSheet(WHITE_COLOR) 50 | self.sig_type_combo = QComboBox() 51 | self.sig_type_combo.setFont(input_font) 52 | self.sig_type_combo.setStyleSheet("QComboBox {padding: 2px;}") 53 | pal = self.sig_type_combo.palette() 54 | pal.setColor(QPalette.Button, QColor(255, 255, 255)) 55 | self.sig_type_combo.setPalette(pal) 56 | self.sig_type_combo.addItems(self.sig_types) 57 | 58 | self.onlyInt = QIntValidator() 59 | self.arraySize_input.setValidator(self.onlyInt) 60 | self.arrayLength_input.setValidator(self.onlyInt) 61 | 62 | self.sig_desc_label = QLabel("Signal Description") 63 | self.sig_desc_label.setFont(input_font) 64 | self.sig_desc_label.setStyleSheet(WHITE_COLOR) 65 | self.sig_desc_input = QLineEdit() 66 | self.sig_desc_input.setFont(input_font) 67 | 68 | self.cancel_btn = QPushButton("Cancel") 69 | self.cancel_btn.setFont(input_font) 70 | self.cancel_btn.setStyleSheet( 71 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 72 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 73 | 74 | self.ok_btn = QPushButton("Ok") 75 | self.ok_btn.setFont(input_font) 76 | self.ok_btn.setEnabled(False) 77 | self.ok_btn.setStyleSheet( 78 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 79 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 80 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 81 | 82 | self.input_frame = QFrame() 83 | 84 | self.cancelled = True 85 | 86 | self.setup_ui() 87 | 88 | if add_or_edit == "edit" and array_data != None: 89 | self.load_sig_data(array_data) 90 | 91 | def setup_ui(self): 92 | 93 | self.input_layout.addWidget(self.array_name_label, 0, 0) # , 1, 3) 94 | self.input_layout.addWidget(self.array_name_input, 1, 0) # , 1, 3) 95 | 96 | self.input_layout.addWidget(self.sig_type_label, 0, 1) 97 | self.input_layout.addWidget(self.sig_type_combo, 1, 1) 98 | 99 | self.input_layout.addWidget(self.arraySize_label, 2, 0, 1, 1) 100 | self.input_layout.addWidget(self.arraySize_input, 3, 0, 1, 1) 101 | 102 | self.input_layout.addWidget(self.arrayLength_label, 2, 1, 1, 1) 103 | self.input_layout.addWidget(self.arrayLength_input, 3, 1, 1, 1) 104 | 105 | self.input_layout.addItem(QSpacerItem(0, 20), 4, 0, 1, 2) 106 | self.input_layout.addWidget(self.cancel_btn, 5, 0, 1, 1, alignment=Qt.AlignRight) 107 | self.input_layout.addWidget(self.ok_btn, 5, 1, 1, 1, alignment=Qt.AlignRight) 108 | 109 | self.input_frame.setFrameShape(QFrame.StyledPanel) 110 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 111 | self.input_frame.setContentsMargins(10, 10, 10, 10) 112 | #self.input_frame.setFixedSize(600, 600) 113 | self.input_frame.setLayout(self.input_layout) 114 | 115 | self.ok_btn.clicked.connect(self.get_data) 116 | self.cancel_btn.clicked.connect(self.cancel_selected) 117 | 118 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 119 | self.arraySize_input.textChanged.connect(self.enable_ok_btn) 120 | self.arrayLength_input.textChanged.connect(self.enable_ok_btn) 121 | self.setLayout(self.mainLayout) 122 | 123 | def load_sig_data(self, array_data): 124 | self.array_name_input.setText(array_data[0]) 125 | self.arraySize_input.setText(array_data[1]) 126 | self.arrayLength_input.setText(array_data[2]) 127 | sig_type = array_data[3] 128 | if sig_type == "std_logic_vector": 129 | sig_type = "bus" 130 | self.sig_type_combo.setCurrentText(sig_type) 131 | 132 | def get_data(self): 133 | sig_type = self.sig_type_combo.currentText() 134 | if sig_type == "bus": 135 | sig_type = "std_logic_vector" 136 | data = [self.array_name_input.text().strip(), self.arraySize_input.text().strip(), self.arrayLength_input.text().strip(), sig_type] 137 | 138 | self.cancelled = False 139 | self.close() 140 | 141 | return data 142 | 143 | def cancel_selected(self): 144 | self.cancelled = True 145 | self.close() 146 | 147 | def enable_ok_btn(self): 148 | if self.array_name_input.text() != "" and self.arraySize_input.text() != "" and self.arrayLength_input.text() != "": 149 | self.ok_btn.setEnabled(True) 150 | else: 151 | self.ok_btn.setEnabled(False) 152 | def delete_clicked(self): 153 | button = self.sender() 154 | if button: 155 | print("deleting row") 156 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Package/package_help.md: -------------------------------------------------------------------------------- 1 | # Type 2 | 3 | - This menu enables the creation of bus, signed or unsigned 2-D array types 4 | 5 | - Click on 'Add type' 6 | 7 | - Menu options 8 | - Array Name 9 | - Select any name, not already used 10 | - Signal Type 11 | - Select bus, signed or unsigned type 12 | - Array Depth 13 | - Select the number of array elements, e.g, in an 8 x 32-bit array the value would be 8 14 | - Array Width 15 | - Select the array data width, e.g, in an 8 x 32-bit array the value would be 32 16 | 17 | - The existing array types are listed and can be edited or deleted. -------------------------------------------------------------------------------- /Application/HDLDesigner/Package/package_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/Package/package_help.md" 6 | 7 | 8 | class PackHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Subcomponents/component_dialog.py: -------------------------------------------------------------------------------- 1 | #Dialog box for adding/editing sub-component called in the subcomponents.py class. 2 | import re 3 | import os 4 | from PySide2.QtWidgets import * 5 | from PySide2.QtGui import * 6 | from pathlib import Path 7 | import sys 8 | 9 | sys.path.append("..") 10 | import configparser 11 | from ProjectManager.project_manager import ProjectManager 12 | from Generator.generator import Generator 13 | 14 | WHITE_COLOR = "color: white" 15 | 16 | class ComponentDialog(QDialog): 17 | def __init__(self, add_or_edit, component_data = None): 18 | super().__init__() 19 | 20 | if add_or_edit == "add": 21 | self.setWindowTitle("New component") 22 | elif add_or_edit == "edit": 23 | self.setWindowTitle("Edit component") 24 | 25 | input_font = QFont() 26 | input_font.setPointSize(10) 27 | bold_font = QFont() 28 | bold_font.setBold(True) 29 | 30 | self.internal_signals = [] 31 | self.input_signals = [] 32 | self.output_signals = [] 33 | 34 | self.input_layout = QGridLayout() 35 | 36 | self.mainLayout = QVBoxLayout() 37 | 38 | self.component_name_label = QLabel("Component Name") 39 | self.component_name_label.setStyleSheet(WHITE_COLOR) 40 | self.component_name_label.setFont(input_font) 41 | self.component_name_input = QLabel("Browse to select VHDL Model") 42 | self.component_name_input.setStyleSheet(WHITE_COLOR) 43 | self.component_name_input.setEnabled(False) 44 | self.component_name_input.setFont(input_font) 45 | 46 | self.signal_empty_info = QLabel("No Top level Signals found!\nPlease add input and output signals in Ports") 47 | self.signal_empty_info.setFont(input_font) 48 | self.signal_empty_info.setFixedSize(400, 300) 49 | self.signal_table = QTableWidget() 50 | 51 | self.signal_layout = QVBoxLayout() 52 | self.signal_frame = QFrame() 53 | 54 | self.file_path_label = QLabel("Component model file path") 55 | self.file_path_label.setFont(input_font) 56 | self.file_path_label.setStyleSheet(WHITE_COLOR) 57 | self.file_path_input = QLineEdit() 58 | self.file_path_input.setFont(input_font) 59 | 60 | self.browse_btn = QPushButton("Browse") 61 | self.browse_btn.setFont(input_font) 62 | self.browse_btn.setStyleSheet( 63 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 64 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 65 | 66 | self.cancel_btn = QPushButton("Cancel") 67 | self.cancel_btn.setFont(input_font) 68 | self.cancel_btn.setStyleSheet( 69 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 70 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 71 | 72 | self.ok_btn = QPushButton("Ok") 73 | self.ok_btn.setFont(input_font) 74 | self.ok_btn.setStyleSheet( 75 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 76 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 77 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 78 | 79 | self.input_frame = QFrame() 80 | 81 | self.cancelled = True 82 | self.generator = Generator() 83 | self.config = configparser.ConfigParser() 84 | self.setup_ui() 85 | 86 | 87 | if add_or_edit == "edit" and component_data != None: 88 | self.load_component_data(component_data) 89 | 90 | def setup_ui(self): 91 | bold_font = QFont() 92 | bold_font.setBold(True) 93 | 94 | self.signal_table.setFrameStyle(QFrame.NoFrame) 95 | self.signal_table.setColumnCount(3) 96 | self.signal_table.setShowGrid(False) 97 | self.signal_table.setHorizontalHeaderLabels(['Name', 'Mode', ' Type']) 98 | header = self.signal_table.horizontalHeader() 99 | header.setSectionsClickable(False) 100 | header.setSectionsMovable(False) 101 | self.signal_table.horizontalHeader().setFont(bold_font) 102 | self.signal_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) 103 | self.signal_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) 104 | self.signal_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) 105 | 106 | self.signal_table.setEditTriggers(QAbstractItemView.NoEditTriggers) 107 | vert = self.signal_table.verticalHeader() 108 | vert.hide() 109 | self.signal_layout.addWidget(self.signal_table) 110 | self.signal_frame.setFrameStyle(QFrame.NoFrame) 111 | self.signal_frame.setStyleSheet(".QFrame{background-color: white; border-radius: 5px;}") 112 | self.signal_frame.setLayout(self.signal_layout) 113 | self.signal_frame.setFixedSize(600, 600) 114 | 115 | self.input_layout.addWidget(self.component_name_label, 0, 0, 1, 1) 116 | self.input_layout.addWidget(self.component_name_input, 1, 0, 1, 1) 117 | self.input_layout.addWidget(self.file_path_label, 2, 0, 1, 2) 118 | self.input_layout.addWidget(self.file_path_input,3, 0, 1, 1) 119 | self.input_layout.addWidget(self.browse_btn, 3, 1, 1, 1) 120 | self.input_layout.addWidget(self.signal_frame, 4, 0, 4, 2) 121 | 122 | 123 | self.input_layout.addItem(QSpacerItem(0, 50), 6, 0, 1, 3) 124 | self.input_layout.addWidget(self.cancel_btn, 8, 0, 1, 1, alignment=Qt.AlignRight) 125 | self.input_layout.addWidget(self.ok_btn, 8, 1, 1, 1, alignment=Qt.AlignRight) 126 | 127 | self.input_frame.setFrameShape(QFrame.StyledPanel) 128 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 129 | self.input_frame.setContentsMargins(10, 10, 10, 10) 130 | self.input_frame.setLayout(self.input_layout) 131 | self.ok_btn.clicked.connect(self.get_data) 132 | self.cancel_btn.clicked.connect(self.cancel_selected) 133 | self.browse_btn.clicked.connect(self.set_comp_path) 134 | 135 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 136 | 137 | self.setLayout(self.mainLayout) 138 | 139 | def populate_signals(self, comp_dir): 140 | abs_component_path = os.path.join(ProjectManager.get_proj_environment(), comp_dir) 141 | rows = self.signal_table.rowCount() 142 | 143 | # Remove all existing rows if repopulating the signals table 144 | for i in range(rows): 145 | self.signal_table.removeRow(0) 146 | 147 | self.comp_signals, self.model, self.comp_mode = self.loadComponent(abs_component_path) 148 | 149 | for i, signal in enumerate(self.comp_signals): 150 | temp = self.comp_mode[i].split(' ') 151 | row_position = self.signal_table.rowCount() 152 | self.signal_table.insertRow(row_position) 153 | self.signal_table.setRowHeight(row_position, 5) 154 | 155 | self.signal_table.setItem(row_position, 0, QTableWidgetItem(signal)) 156 | if temp[1] == "std_logic": 157 | temp[1] = "single bit" 158 | elif temp[1][0:16] == "std_logic_vector": 159 | temp[1] = "bus "+ "["+temp[1][17:]+":0]" 160 | self.signal_table.setItem(row_position, 1, QTableWidgetItem(temp[0])) 161 | self.signal_table.setItem(row_position, 2, QTableWidgetItem(temp[1])) 162 | 163 | @staticmethod 164 | def is_subdirectory(directory, parent): 165 | # Get the common prefix of the two paths 166 | common_prefix = os.path.commonprefix([directory, parent]) 167 | 168 | # Check if the common prefix is the same as the potential parent 169 | return os.path.normpath(common_prefix) == os.path.normpath(parent) 170 | 171 | def set_comp_path(self): 172 | environment = ProjectManager.get_proj_environment() 173 | 174 | comp_path = QFileDialog.getOpenFileName(self, "Select model .vhd file", dir=str(environment), filter="VHDL files (*.vhd)") 175 | 176 | comp_path = Path(comp_path[0]) 177 | 178 | if comp_path != "" and ComponentDialog.is_subdirectory(comp_path, environment): 179 | comp_rel_path = os.path.relpath(comp_path, environment) 180 | self.file_path_input.setText(str(comp_path)) 181 | self.populate_signals(comp_rel_path) 182 | print("The directory is within the potential parent directory.") 183 | else: 184 | print("The directory is not within the potential parent directory.") 185 | msgBox = QMessageBox() 186 | msgBox.setWindowTitle("Alert") 187 | msgBox.setText("Component cannot be added!\nThe component is not part of the project environment.") 188 | msgBox.exec_() 189 | 190 | def load_component_data(self, component_data): 191 | self.component_name_input.setText(component_data[0]) 192 | self.file_path_input.setText( 193 | str(os.path.join(ProjectManager.get_proj_environment(), component_data[1])) 194 | ) 195 | signals = [] 196 | mode = [] 197 | type = [] 198 | rows = self.signal_table.rowCount() 199 | for i in range(rows): 200 | self.signal_table.removeRow(0) 201 | for signal in component_data[2]: 202 | temp = signal.split(',') 203 | signals.append(temp[0]) 204 | mode.append(temp[1]) 205 | type.append(temp[2]) 206 | i = 0 207 | for sig in signals: 208 | row_position = self.signal_table.rowCount() 209 | self.signal_table.insertRow(row_position) 210 | self.signal_table.setRowHeight(row_position, 5) 211 | self.signal_table.setItem(row_position, 0, QTableWidgetItem(sig)) 212 | self.signal_table.setItem(row_position, 1, QTableWidgetItem(mode[i])) 213 | if type[i] == "std_logic": 214 | type[i] = "single bit" 215 | elif type[i][0:16] == "std_logic_vector": 216 | type[i] = "bus "+ "["+type[i][17:] 217 | type[i] = type[i].replace(" downto ",":") 218 | type[i] = type[i].replace(")","]") 219 | self.signal_table.setItem(row_position, 2, QTableWidgetItem(type[i])) 220 | i = i+1 221 | self.signal_layout.addWidget(self.signal_table) 222 | 223 | def cancel_selected(self): 224 | self.cancelled = True 225 | self.close() 226 | 227 | def enable_ok_btn(self): 228 | if self.component_name_input.text() != "": 229 | self.ok_btn.setEnabled(True) 230 | else: 231 | self.ok_btn.setEnabled(False) 232 | 233 | def get_data(self): 234 | data = [] 235 | signals = [] 236 | 237 | for i in range(self.signal_table.rowCount()): 238 | signal = self.signal_table.item(i, 0).text() 239 | mode = self.signal_table.item(i, 1).text() 240 | type = self.signal_table.item(i, 2).text() 241 | 242 | if type == "single bit": 243 | type = "std_logic" 244 | 245 | elif type[0:3] == "bus": 246 | type = "std_logic_vector(" + type[5:] + " downto 0)" 247 | type = type.replace(":0]","") 248 | 249 | signals.append(signal + "," + mode + "," + type) 250 | 251 | data.append(self.component_name_input.text()) 252 | # When saving the component path to disk, save it as a relative path, relative to the project environment. 253 | # This keeps file paths intact if the project is moved from one disk to another. 254 | comp_path = self.file_path_input.text() 255 | environment = ProjectManager.get_proj_environment() 256 | comp_rel_path = os.path.relpath(comp_path, environment) 257 | 258 | data.append(comp_rel_path) 259 | data.append(signals) 260 | self.cancelled = False 261 | self.close() 262 | return data 263 | 264 | def loadComponent(self, comp_dir): 265 | # Open the VHDL file and read its contents 266 | with open(comp_dir, 'r') as file: 267 | vhdl_code = file.read() 268 | # Use a regular expression to match the port declarations 269 | model = os.path.splitext(os.path.basename(comp_dir))[0] 270 | start_port_pattern = re.compile(r'entity\s*' + model + '\s*is\s*Port\s*\(', re.IGNORECASE | re.DOTALL) 271 | matchStart = start_port_pattern.search(vhdl_code) 272 | startEnd = matchStart.end() 273 | startStart = matchStart.start() 274 | end_port_pattern = re.compile(r'\);\s*end\s*Entity\s*' + model, re.IGNORECASE | re.DOTALL) 275 | matchEnd = end_port_pattern.search(vhdl_code) 276 | endStart = matchEnd.start() 277 | endEnd = matchEnd.end() 278 | 279 | asign = vhdl_code[startEnd:endStart] 280 | asign = "\n".join([line for line in asign.splitlines() if line.strip()]) 281 | signal_names = [line.split(":")[0].strip() for line in asign.splitlines()] 282 | signal_mode = [line.split(":")[1].strip().replace(";","") for line in asign.splitlines()] 283 | self.component_name_input.setText(model) 284 | return signal_names, model, signal_mode 285 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Subcomponents/subcomp_help.md: -------------------------------------------------------------------------------- 1 | # Sub-component 2 | 3 | - This menue enables the creation of a component for use in hierarchical designs 4 | 5 | - Click on 'Add component' 6 | 7 | - Use the browser to find and select the component model in the folder structure 8 | - Browse to the VHDL or Verilog 'model' folder and the .vhd or .v fiel respectively 9 | - The component signal ports will appear, with signal name, mode and type 10 | - Click OK to complete 11 | 12 | - The existing components are listed and can be edited or deleted. -------------------------------------------------------------------------------- /Application/HDLDesigner/Subcomponents/subcomp_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/Subcomponents/subcomp_help.md" 6 | 7 | 8 | class SubcompHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/Subcomponents/subcomponents.py: -------------------------------------------------------------------------------- 1 | #Sub-components section in HDL Designer. This class will call component_dialog.py when adding/editing a component and subcomp_help.md if help button is clicked 2 | #This class will save all entered data to the mainPackage.hdlgen. The save happens when there is a change. 3 | import os 4 | import sys 5 | from xml.dom import minidom 6 | from PySide2.QtWidgets import * 7 | from PySide2.QtGui import * 8 | import qtawesome as qta 9 | 10 | sys.path.append("../..") 11 | from ProjectManager.project_manager import ProjectManager 12 | from HDLDesigner.Subcomponents.component_dialog import ComponentDialog 13 | from Generator.generator import Generator 14 | from HDLDesigner.Subcomponents.subcomp_help import SubcompHelpDialog 15 | 16 | BLACK_COLOR = "color: black" 17 | WHITE_COLOR = "color: white" 18 | ICONS_DIR = "../../Resources/icons/" 19 | class Subcomponents(QWidget): 20 | 21 | def __init__(self): 22 | super().__init__() 23 | small_text_font = QFont() 24 | small_text_font.setPointSize(10) 25 | title_font = QFont() 26 | title_font.setPointSize(12) 27 | title_font.setBold(True) 28 | bold_font = QFont() 29 | bold_font.setBold(True) 30 | input_font = QFont() 31 | input_font.setPointSize(10) 32 | 33 | self.all_signals = [] 34 | self.all_signals_names = [] 35 | self.arrays = [] 36 | self.arrays_names = [] 37 | self.comps = [] 38 | self.comps_names = [] 39 | 40 | self.package_heading_layout = QHBoxLayout() 41 | self.package_action_layout = QVBoxLayout() 42 | self.component_list_layout = QVBoxLayout() 43 | self.mainLayout = QVBoxLayout() 44 | 45 | self.package_label = QLabel("Sub-components") 46 | self.package_label.setFont(title_font) 47 | self.package_label.setStyleSheet(WHITE_COLOR) 48 | 49 | self.add_component_btn = QPushButton("Add component") 50 | self.add_component_btn.setFont(input_font) 51 | self.add_component_btn.setStyleSheet( 52 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain; padding: 10px;}" 53 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 54 | 55 | self.subcomp_info_btn = QPushButton() 56 | self.subcomp_info_btn.setIcon(qta.icon("mdi.help")) 57 | self.subcomp_info_btn.setFixedSize(25, 25) 58 | self.subcomp_info_btn.clicked.connect(self.subcomp_help_window) 59 | self.list_div = QFrame() 60 | self.list_div.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129);}') 61 | self.list_div.setFixedHeight(1) 62 | 63 | self.component_table = QTableWidget() 64 | 65 | self.package_list_frame = QFrame() 66 | self.component_list_frame = QFrame() 67 | self.package_action_frame = QFrame() 68 | self.generator = Generator() 69 | self.setup_ui() 70 | self.load_data() 71 | 72 | def setup_ui(self): 73 | bold_font = QFont() 74 | bold_font.setBold(True) 75 | 76 | self.package_heading_layout.addWidget(self.package_label)#, 0, 0, 1, 1) 77 | self.package_heading_layout.addWidget(self.add_component_btn, alignment=Qt.AlignRight)#, 0, 1, 1, 1) 78 | self.package_heading_layout.addWidget(self.subcomp_info_btn)#, 0, 2, 1, 1) 79 | #self.port_heading_layout.addWidget(self.add_btn, alignment=Qt.AlignRight) 80 | self.add_component_btn.clicked.connect(self.add_component) 81 | 82 | self.component_list_layout.setAlignment(Qt.AlignTop) 83 | 84 | self.component_table.setColumnCount(3) 85 | self.component_table.setShowGrid(False) 86 | self.component_table.setHorizontalHeaderLabels(['Component Name', '', '']) 87 | header = self.component_table.horizontalHeader() 88 | header.setSectionsClickable(False) 89 | header.setSectionsMovable(False) 90 | self.component_table.horizontalHeader().setFont(bold_font) 91 | self.component_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) 92 | self.component_table.setColumnWidth(1, 10) 93 | self.component_table.setColumnWidth(2, 10) 94 | self.component_table.setEditTriggers(QAbstractItemView.NoEditTriggers) 95 | vert = self.component_table.verticalHeader() 96 | vert.hide() 97 | self.component_table.setFrameStyle(QFrame.NoFrame) 98 | self.component_list_layout.addWidget(self.component_table) 99 | 100 | self.component_list_frame.setFrameShape(QFrame.StyledPanel) 101 | self.component_list_frame.setStyleSheet('.QFrame{background-color: white; border-radius: 5px;}') 102 | self.component_list_frame.setLayout(self.component_list_layout) 103 | 104 | self.package_action_layout.addLayout(self.package_heading_layout) 105 | self.package_action_layout.addSpacerItem(QSpacerItem(0, 5)) 106 | self.package_action_layout.addWidget(self.component_list_frame) 107 | self.package_action_layout.addSpacerItem(QSpacerItem(0, 5)) 108 | self.package_action_frame.setFrameShape(QFrame.StyledPanel) 109 | self.package_action_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 110 | self.package_action_frame.setLayout(self.package_action_layout) 111 | 112 | self.mainLayout.addWidget(self.package_action_frame) 113 | 114 | self.setLayout(self.mainLayout) 115 | 116 | def add_component(self): 117 | add_comp = ComponentDialog("add") 118 | add_comp.exec_() 119 | if not add_comp.cancelled: 120 | comp_data = add_comp.get_data() 121 | self.comps.append(comp_data) 122 | self.comps_names.append((comp_data[0])) 123 | delete_btn = QPushButton() 124 | delete_btn.setIcon(qta.icon("mdi.delete")) 125 | delete_btn.setFixedSize(35, 22) 126 | delete_btn.clicked.connect(self.delete_component) 127 | 128 | edit_btn = QPushButton() 129 | edit_btn.setIcon(qta.icon("mdi.pencil")) 130 | edit_btn.setFixedSize(35, 22) 131 | edit_btn.clicked.connect(self.edit_component) 132 | 133 | row_position = self.component_table.rowCount() 134 | self.component_table.insertRow(row_position) 135 | self.component_table.setRowHeight(row_position, 5) 136 | self.component_table.setItem(row_position, 0, QTableWidgetItem(comp_data[0])) 137 | self.component_table.setCellWidget(row_position, 1, edit_btn) 138 | self.component_table.setCellWidget(row_position, 2, delete_btn) 139 | self.save_data() 140 | 141 | def edit_component(self): 142 | button = self.sender() 143 | if button: 144 | row = self.component_table.indexAt(button.pos()).row() 145 | add_comp = ComponentDialog("edit", self.comps[row]) 146 | add_comp.exec_() 147 | 148 | if not add_comp.cancelled: 149 | comp_data = add_comp.get_data() 150 | self.component_table.removeRow(row) 151 | self.comps.pop(row) 152 | self.comps_names.pop(row) 153 | 154 | delete_btn = QPushButton() 155 | delete_btn.setIcon(qta.icon("mdi.delete")) 156 | delete_btn.setFixedSize(35, 22) 157 | delete_btn.clicked.connect(self.delete_component) 158 | 159 | edit_btn = QPushButton() 160 | edit_btn.setIcon(qta.icon("mdi.pencil")) 161 | edit_btn.setFixedSize(35, 22) 162 | edit_btn.clicked.connect(self.edit_component) 163 | 164 | self.comps.insert(row, comp_data) 165 | self.comps_names.insert(row, comp_data[0]) 166 | self.component_table.insertRow(row) 167 | self.component_table.setRowHeight(row, 5) 168 | self.component_table.setItem(row, 0, QTableWidgetItem(comp_data[0])) 169 | self.component_table.setCellWidget(row, 1, edit_btn) 170 | self.component_table.setCellWidget(row, 2, delete_btn) 171 | self.save_data() 172 | 173 | def subcomp_help_window(self): 174 | subcomp_help_dialog = SubcompHelpDialog() 175 | subcomp_help_dialog.exec_() 176 | 177 | def delete_component(self): 178 | button = self.sender() 179 | if button: 180 | row = self.component_table.indexAt(button.pos()).row() 181 | self.component_table.removeRow(row) 182 | self.comps.pop(row) 183 | self.comps_names.pop(row) 184 | self.save_data() 185 | 186 | def save_data(self): 187 | mainPackageDir = ProjectManager.get_package_hdlgen() 188 | 189 | root = minidom.parse(mainPackageDir) 190 | HDLGen = root.documentElement 191 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 192 | new_comp_node = root.createElement("components") 193 | 194 | for component in self.comps: 195 | comp_node = root.createElement("component") 196 | package_model_node = root.createElement("model") 197 | package_model_node.appendChild(root.createTextNode(component[0])) 198 | comp_node.appendChild(package_model_node) 199 | package_dir_node = root.createElement("dir") 200 | package_dir_node.appendChild(root.createTextNode(component[1])) 201 | comp_node.appendChild(package_dir_node) 202 | 203 | for output_signal in component[2]: 204 | port_node = root.createElement("port") 205 | temp = output_signal.split(",") 206 | ports = temp[0] + "," + temp[1] + "," + temp[2] 207 | port_node.appendChild(root.createTextNode(ports)) 208 | comp_node.appendChild(port_node) 209 | new_comp_node.appendChild(comp_node) 210 | hdlDesign[0].replaceChild(new_comp_node, hdlDesign[0].getElementsByTagName("components")[0]) 211 | # converting the doc into a string in xml format 212 | xml_str = root.toprettyxml() 213 | xml_str = '\n'.join([line for line in xml_str.splitlines() if line.strip()]) 214 | # Writing xml file 215 | with open(mainPackageDir, "w", encoding='UTF-8', newline='\n') as f: 216 | f.write(xml_str) 217 | self.generator.generate_mainPackage() 218 | print("Saved sub component") 219 | 220 | def load_data(self): 221 | if self.comps: 222 | for row in range(0, self.component_table.rowCount()): 223 | self.component_table.removeRow(0) 224 | self.comps.pop(0) 225 | self.comps_names.pop(0) 226 | 227 | mainPackageDir = ProjectManager.get_package_hdlgen() 228 | 229 | try: 230 | # Fetch component information from mainPackage.hdlgen for the project 231 | root = minidom.parse(mainPackageDir) 232 | HDLGen = root.documentElement 233 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 234 | compPackage = hdlDesign[0].getElementsByTagName("components") 235 | comp_nodes = compPackage[0].getElementsByTagName("component") 236 | 237 | # Iterate over all component instances in the package file 238 | for idx, node in enumerate(comp_nodes): 239 | # Get the model name and model .vhd path from the package file 240 | model_name = node.getElementsByTagName('model')[0].firstChild.data 241 | directory = node.getElementsByTagName('dir')[0].firstChild.data 242 | 243 | # Get port data for each in the 244 | signals = list(signal.firstChild.data for signal in node.getElementsByTagName("port")) 245 | component_data = [model_name, directory, signals] 246 | 247 | self.comps_names.append(model_name) 248 | self.comps.append(component_data) 249 | 250 | # Create Component Edit Button 251 | edit_btn = QPushButton() 252 | edit_btn.setIcon(qta.icon("mdi.pencil")) 253 | edit_btn.setFixedSize(35, 22) 254 | edit_btn.clicked.connect(self.edit_component) 255 | 256 | # Create Component Delete Button 257 | delete_btn = QPushButton() 258 | delete_btn.setIcon(qta.icon("mdi.delete")) 259 | delete_btn.setFixedSize(35, 22) 260 | delete_btn.clicked.connect(self.delete_component) 261 | 262 | # Add Component name, Edit button, Delete button to sub-components table 263 | self.component_table.insertRow(idx) 264 | self.component_table.setRowHeight(idx, 5) 265 | self.component_table.setItem(idx, 0, QTableWidgetItem(model_name)) 266 | self.component_table.setCellWidget(idx, 1, edit_btn) 267 | self.component_table.setCellWidget(idx, 2, delete_btn) 268 | 269 | except Exception as e: 270 | print(repr(e)) -------------------------------------------------------------------------------- /Application/HDLDesigner/comp/comp_details.py: -------------------------------------------------------------------------------- 1 | #Component section in HDL Designer. This class will only call comp_help.md if help button is clicked 2 | #This class will save all entered data to the .hdlgen. The save happens when there is a change. 3 | import os 4 | from xml.dom import minidom 5 | from PySide2.QtWidgets import * 6 | from PySide2.QtCore import * 7 | from PySide2.QtGui import * 8 | import sys 9 | import configparser 10 | import qtawesome as qta 11 | sys.path.append("..") 12 | from ProjectManager.project_manager import ProjectManager 13 | from HDLDesigner.comp.comp_help import CompHelpDialog 14 | 15 | 16 | WHITE_COLOR = "color: white" 17 | 18 | class CompDetails(QWidget): 19 | save_signal = Signal(bool) 20 | def __init__(self, proj_dir): 21 | super().__init__() 22 | small_text_font = QFont() 23 | small_text_font.setPointSize(10) 24 | title_font = QFont() 25 | title_font.setPointSize(12) 26 | title_font.setBold(True) 27 | self.proj_dir = proj_dir 28 | 29 | self.mainLayout = QVBoxLayout() 30 | 31 | self.input_layout = QGridLayout() 32 | self.comp_label = QLabel("Component") 33 | self.comp_label.setFont(title_font) 34 | self.comp_label.setStyleSheet(WHITE_COLOR) 35 | 36 | self.comp_name_label = QLabel("Component Name*") 37 | self.comp_name_label.setStyleSheet(WHITE_COLOR) 38 | self.comp_name_label.setFont(small_text_font) 39 | self.comp_name_input = QLineEdit() 40 | self.comp_name_input.setFont(small_text_font) 41 | 42 | self.comp_info_btn = QPushButton() 43 | self.comp_info_btn.setIcon(qta.icon("mdi.help")) 44 | self.comp_info_btn.setFixedSize(25, 25) 45 | self.comp_info_btn.clicked.connect(self.comp_help_window) 46 | 47 | self.comp_title_label = QLabel("Single Line Title") 48 | self.comp_title_label.setStyleSheet(WHITE_COLOR) 49 | self.comp_title_label.setFont(small_text_font) 50 | self.comp_title_input = QLineEdit() 51 | self.comp_title_input.setFont(small_text_font) 52 | 53 | self.comp_description_label = QLabel("Component Description") 54 | self.comp_description_label.setStyleSheet(WHITE_COLOR) 55 | self.comp_description_label.setFont(small_text_font) 56 | self.comp_description_input = QPlainTextEdit() 57 | self.comp_description_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 58 | self.comp_description_input.setFont(small_text_font) 59 | 60 | self.comp_author_label = QLabel("Authors") 61 | self.comp_author_label.setStyleSheet(WHITE_COLOR) 62 | self.comp_author_label.setFont(small_text_font) 63 | self.comp_author_input = QLineEdit() 64 | self.comp_author_input.setFont(small_text_font) 65 | 66 | self.comp_company_label = QLabel("Company") 67 | self.comp_company_label.setStyleSheet(WHITE_COLOR) 68 | self.comp_company_label.setFont(small_text_font) 69 | self.comp_company_input = QLineEdit() 70 | self.comp_company_input.setFont(small_text_font) 71 | 72 | self.comp_email_label = QLabel("Email") 73 | self.comp_email_label.setStyleSheet(WHITE_COLOR) 74 | self.comp_email_label.setFont(small_text_font) 75 | self.comp_email_input = QLineEdit() 76 | self.comp_email_input.setFont(small_text_font) 77 | 78 | self.comp_date_label = QLabel("Date") 79 | self.comp_date_label.setStyleSheet(WHITE_COLOR) 80 | self.comp_date_label.setFont(small_text_font) 81 | 82 | self.reset_btn = QPushButton("Reset") 83 | self.reset_btn.setFixedSize(60, 30) 84 | self.reset_btn.setStyleSheet( 85 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain; }" 86 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;}") 87 | 88 | self.btn_layout = QHBoxLayout() 89 | 90 | self.vspacer = QSpacerItem(30, 40) 91 | 92 | self.comp_date_picker = QDateEdit(calendarPopup=True) 93 | self.comp_date_picker.setDate(QDate.currentDate()) 94 | self.comp_date_picker.setFont(small_text_font) 95 | self.comp_date_picker.setDisplayFormat("dd/MM/yyyy") 96 | 97 | self.input_frame = QFrame() 98 | self.setup_ui() 99 | if proj_dir != None: 100 | self.load_data(proj_dir) 101 | 102 | def setup_ui(self): 103 | config = configparser.ConfigParser() 104 | config.read('config.ini') 105 | author = config.get('user', 'author').strip() 106 | email = config.get('user', 'email').strip() 107 | company = config.get('user', 'company').strip() 108 | self.comp_author_input.setText(author) 109 | 110 | self.comp_email_input.setText(email) 111 | self.comp_company_input.setText(company) 112 | self.input_layout.addWidget(self.comp_label, 0, 0,1,1) 113 | self.input_layout.addWidget(self.comp_info_btn,0,1,alignment=Qt.AlignRight) 114 | self.input_layout.addWidget(self.comp_name_label, 1, 0) 115 | self.input_layout.addWidget(self.comp_name_input, 2, 0, 1, 2) 116 | self.comp_name_input.setText(ProjectManager.get_proj_name()) 117 | self.comp_title_input.setText("To be Completed") 118 | self.input_layout.addWidget(self.comp_title_label, 3, 0) 119 | self.input_layout.addWidget(self.comp_title_input, 4, 0, 1, 2) 120 | self.comp_description_input.setPlainText("To be Completed") 121 | self.input_layout.addWidget(self.comp_description_label, 5, 0) 122 | self.input_layout.addWidget(self.comp_description_input, 6, 0, 4, 2) 123 | 124 | self.input_layout.addWidget(self.comp_author_label, 10, 0) 125 | self.input_layout.addWidget(self.comp_author_input, 11, 0, 1, 1) 126 | 127 | self.input_layout.addWidget(self.comp_company_label, 10, 1) 128 | self.input_layout.addWidget(self.comp_company_input, 11, 1, 1, 1) 129 | 130 | self.input_layout.addWidget(self.comp_email_label, 12, 0) 131 | self.input_layout.addWidget(self.comp_email_input, 13, 0, 1, 1) 132 | 133 | self.input_layout.addWidget(self.comp_date_label, 12, 1) 134 | self.input_layout.addWidget(self.comp_date_picker, 13, 1, 1, 1) 135 | 136 | self.comp_description_input.textChanged.connect(self.save_data) 137 | self.comp_author_input.textChanged.connect(self.save_data) 138 | self.comp_name_input.textChanged.connect(self.save_data) 139 | self.comp_email_input.textChanged.connect(self.save_data) 140 | self.comp_title_input.textChanged.connect(self.save_data) 141 | self.comp_company_input.textChanged.connect(self.save_data) 142 | self.comp_date_picker.dateChanged.connect(self.save_data) 143 | 144 | self.input_layout.addItem(self.vspacer, 14, 0, 1, 2) 145 | self.input_layout.addLayout(self.btn_layout, 15, 1) 146 | 147 | self.input_frame.setFrameShape(QFrame.StyledPanel) 148 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 149 | self.input_frame.setContentsMargins(30, 30, 30, 25) 150 | self.input_frame.setLayout(self.input_layout) 151 | 152 | self.mainLayout.addWidget(self.input_frame) 153 | 154 | self.setLayout(self.mainLayout) 155 | 156 | def update_comp_name(self): 157 | self.comp_name_input.setText(ProjectManager.get_proj_name()) 158 | 159 | def save_data(self): 160 | 161 | xml_data_path = ProjectManager.get_xml_data_path() 162 | 163 | root = minidom.parse(xml_data_path) 164 | HDLGen = root.documentElement 165 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 166 | 167 | comp_name = self.comp_name_input.text() 168 | if comp_name == "": 169 | comp_name = "To be completed" 170 | comp_title = self.comp_title_input.text() 171 | if comp_title == "": 172 | comp_title = "To be completed" 173 | cursor = self.comp_description_input.textCursor() 174 | doc = self.comp_description_input.document() 175 | lines = "" 176 | line = "" 177 | for i in range(doc.blockCount()): 178 | block = doc.findBlockByNumber(i) 179 | if block.isVisible(): 180 | for j in range(block.layout().lineCount()): 181 | lineStart = block.position() + block.layout().lineAt(j).textStart() 182 | lineEnd = lineStart + block.layout().lineAt(j).textLength() 183 | cursor.setPosition(lineStart) 184 | cursor.setPosition(lineEnd, QTextCursor.KeepAnchor) 185 | line += cursor.selectedText() 186 | if lineEnd == cursor.position(): 187 | lines += line + "\n" 188 | line = "" 189 | lines = lines.strip() 190 | comp_description = lines 191 | comp_authors = self.comp_author_input.text().strip() 192 | if comp_authors == "": 193 | comp_authors = "To be completed" 194 | comp_company = self.comp_company_input.text().strip() 195 | if comp_company == "": 196 | comp_company = "To be completed" 197 | comp_email = self.comp_email_input.text().strip() 198 | if comp_email == "": 199 | comp_email = "To be completed" 200 | comp_date = self.comp_date_picker.text() 201 | 202 | header = hdlDesign[0].getElementsByTagName('header') 203 | 204 | header[0].getElementsByTagName('compName')[0].firstChild.data = comp_name 205 | header[0].getElementsByTagName('title')[0].firstChild.data = comp_title 206 | 207 | if comp_description.count('\n') == 0: 208 | comp_description=self.comp_description_input.toPlainText() 209 | comp_description = comp_description.replace("&", "&") 210 | comp_description = comp_description.replace("\n", " ") 211 | comp_description = comp_description.replace("\"", """) 212 | comp_description = comp_description.replace("\'", "'") 213 | comp_description = comp_description.replace("\n", " ") 214 | comp_description = comp_description.replace("<", "<") 215 | comp_description = comp_description.replace("\t", " ") 216 | comp_description = comp_description.replace(">", ">") 217 | comp_description = comp_description.replace(",", ",") 218 | 219 | if comp_description == "": 220 | comp_description = "To be completed" 221 | header[0].getElementsByTagName('description')[0].firstChild.data = comp_description 222 | header[0].getElementsByTagName('authors')[0].firstChild.data = comp_authors 223 | header[0].getElementsByTagName('company')[0].firstChild.data = comp_company 224 | header[0].getElementsByTagName('email')[0].firstChild.data = comp_email 225 | header[0].getElementsByTagName('date')[0].firstChild.data = comp_date 226 | 227 | # converting the doc into a string in xml format 228 | xml_str = root.toprettyxml() 229 | xml_str = '\n'.join([line for line in xml_str.splitlines() if line.strip()]) 230 | 231 | # Writing xml file 232 | with open(xml_data_path, "w", encoding='UTF-8', newline='\n') as f: 233 | f.write(xml_str) 234 | hdl = False 235 | self.save_signal.emit(hdl) 236 | print("Saved Component details") 237 | 238 | def comp_help_window(self): 239 | comp_help_dialog = CompHelpDialog() 240 | comp_help_dialog.exec_() 241 | 242 | def reset_comp_details(self): 243 | 244 | self.comp_name_input.clear() 245 | self.comp_title_input.clear() 246 | self.comp_description_input.clear() 247 | self.comp_author_input.clear() 248 | self.comp_company_input.clear() 249 | self.comp_email_input.clear() 250 | self.comp_date_picker.setDate(QDate.currentDate()) 251 | 252 | def load_data(self, proj_dir): 253 | root = minidom.parse(str(proj_dir)) 254 | HDLGen = root.documentElement 255 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 256 | 257 | header = hdlDesign[0].getElementsByTagName('header') 258 | 259 | comp_name = header[0].getElementsByTagName('compName')[0].firstChild.data 260 | comp_title = header[0].getElementsByTagName('title')[0].firstChild.data 261 | comp_description = header[0].getElementsByTagName('description')[0].firstChild.data 262 | 263 | comp_authors = header[0].getElementsByTagName('authors')[0].firstChild.data 264 | comp_company = header[0].getElementsByTagName('company')[0].firstChild.data 265 | comp_email = header[0].getElementsByTagName('email')[0].firstChild.data 266 | comp_date = header[0].getElementsByTagName('date')[0].firstChild.data 267 | 268 | if comp_description != "null": 269 | comp_description = comp_description.replace(" ", "\n") 270 | comp_description = comp_description.replace("&", "&") 271 | comp_description = comp_description.replace("&", "&") 272 | comp_description = comp_description.replace(""", "\"") 273 | comp_description = comp_description.replace("'", "\'") 274 | comp_description = comp_description.replace("<", "<") 275 | comp_description = comp_description.replace(" ", "\t") 276 | comp_description = comp_description.replace(">", ">") 277 | comp_description = comp_description.replace(",", ",") 278 | self.comp_description_input.setPlainText(comp_description) 279 | 280 | if comp_name != "null": 281 | self.comp_name_input.setText(comp_name) 282 | 283 | if comp_title != "null": 284 | self.comp_title_input.setText(comp_title) 285 | 286 | if comp_authors != "null": 287 | self.comp_author_input.setText(comp_authors) 288 | 289 | if comp_company != "null": 290 | self.comp_company_input.setText(comp_company) 291 | 292 | if comp_email != "null": 293 | self.comp_email_input.setText(comp_email) 294 | 295 | if comp_date != "null": 296 | self.comp_date_picker.setDate(QDate.fromString(comp_date)) -------------------------------------------------------------------------------- /Application/HDLDesigner/comp/comp_help.md: -------------------------------------------------------------------------------- 1 | # Component 2 | 3 | - Complete the following fields, using the information in the design specification 4 | - Component name 5 | - Single line title 6 | - Component description 7 | PRovide a complete description, considering psuedo code as an efficient method of description. 8 | 9 | - Creator details can be entered on an individual project bases, though you are advised to use the project settings menu to define these values for all projects. 10 | - Close the current project 11 | - Click settings 12 | - Complete the following fields 13 | - Authors 14 | - Company 15 | - Email 16 | - These fields will be used in all subsequently created project 17 | 18 | - The date field is automatically generated 19 | 20 | -------------------------------------------------------------------------------- /Application/HDLDesigner/comp/comp_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/comp/comp_help.md" 6 | 7 | 8 | class CompHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/HDLDesigner/hdl_designer.py: -------------------------------------------------------------------------------- 1 | #This class is a tab in the home.py class of the GUI. it contains the 8 classes comp_details.py, architecture.py, io_ports.py, testplan.py, internal_signal.py, 2 | #package.py, subcomponents.py, generation.py, generator.py will also call project_manager.py to get information 3 | import os 4 | from xml.dom import minidom 5 | from PySide2.QtWidgets import * 6 | from PySide2.QtCore import * 7 | import sys 8 | sys.path.append("..") 9 | from HDLDesigner.comp.comp_details import CompDetails 10 | from HDLDesigner.IOPorts.io_ports import IOPorts 11 | from HDLDesigner.Architecture.architecture import Architecture 12 | from HDLDesigner.testPlan.testplan import TestPlan 13 | from HDLDesigner.InternalSignal.internal_signal import InternalSignal 14 | from HDLDesigner.Package.package import Package 15 | from HDLDesigner.Subcomponents.subcomponents import Subcomponents 16 | from HDLDesigner.Generate.generation import Gen 17 | from Generator.generator import Generator 18 | from ProjectManager.project_manager import ProjectManager 19 | 20 | 21 | class HDLDesigner(QWidget): 22 | 23 | def __init__(self, proj_dir, load_data): 24 | super().__init__() 25 | 26 | self.proj_dir = proj_dir 27 | self.code = "No Model Code" 28 | self.chatgpt_header = "No Header Command Entered" 29 | self.chatgpt_model = "No Model Command Entered" 30 | self.chatgpt_tb = "No Testbench" 31 | self.tb_code = "No Testbench" 32 | self.ModelCmd = "No Command Entered" 33 | self.HeaderCmd = "No Command Entered" 34 | self.hdl = "VHDL" 35 | self.mainLayout = QHBoxLayout() 36 | self.preview_pane_layout = QVBoxLayout() 37 | 38 | self.preview_label = QLabel("Preview") 39 | self.preview_window = QTextEdit() 40 | 41 | self.tabs = VerticalTabWidget() 42 | self.tabs.other_class = self 43 | # Creating a container 44 | self.container = QWidget() 45 | self.project_manager = ProjectManager(self.proj_dir, self) 46 | self.setup_ui() 47 | self.hdl = "VHDL" 48 | if load_data: 49 | if self.project_manager.vhdl_check.isChecked(): 50 | self.hdl = "VHDL" 51 | self.update_preview("VHDL") 52 | else: 53 | self.hdl = "Verilog" 54 | self.update_preview("Verilog") 55 | else: 56 | self.hdl = "VHDL" 57 | 58 | def setup_ui(self): 59 | self.compDetails = CompDetails(self.proj_dir) 60 | self.ioPorts = IOPorts(self.proj_dir) 61 | self.architecture = Architecture(self.proj_dir) 62 | self.testplan = TestPlan(self.proj_dir) 63 | self.generate = Gen(self.proj_dir) 64 | self.internalSignal = InternalSignal(self.proj_dir) 65 | self.package = Package() 66 | self.subcomponents = Subcomponents() 67 | 68 | self.preview_window.setReadOnly(True) 69 | self.preview_pane_layout.addWidget(self.preview_label) 70 | self.preview_pane_layout.addWidget(self.preview_window) 71 | 72 | self.tabs.addTab(self.compDetails, "Component") 73 | self.tabs.addTab(self.package, "Types") 74 | self.tabs.addTab(self.subcomponents, "Sub-components") 75 | self.tabs.addTab(self.ioPorts, "Ports") 76 | self.tabs.addTab(self.internalSignal, "Internal Signals") 77 | self.tabs.addTab(self.architecture, "Architecture") 78 | self.tabs.addTab(self.testplan, "Test Plan") 79 | self.tabs.addTab(self.generate, "Generate") 80 | font = self.tabs.font() 81 | font.setPointSize(12) 82 | self.tabs.setFont(font) 83 | self.mainLayout.addWidget(self.tabs) 84 | self.mainLayout.addLayout(self.preview_pane_layout) 85 | self.setLayout(self.mainLayout) 86 | 87 | self.compDetails.save_signal.connect(self.update_preview) 88 | self.ioPorts.save_signal.connect(self.update_preview) 89 | self.ioPorts.save_signal.connect(self.update_arch) 90 | self.internalSignal.save_signal.connect(self.update_preview) 91 | self.architecture.save_signal.connect(self.update_preview) 92 | self.generate.save_signal.connect(self.update_preview) 93 | self.generate.header_title_check.clicked.connect(self.update_preview) 94 | self.generate.msg_title_check.clicked.connect(self.update_preview) 95 | self.generate.header_model_check.clicked.connect(self.update_preview) 96 | self.generate.model_check.clicked.connect(self.update_preview) 97 | self.generate.msg_model_check.clicked.connect(self.update_preview) 98 | self.generate.header_testbench_check.clicked.connect(self.update_preview) 99 | self.generate.testbench_check.clicked.connect(self.update_preview) 100 | self.generate.msg_testbench_check.clicked.connect(self.update_preview) 101 | self.generate.tab_widget.currentChanged.connect(self.update_preview) 102 | 103 | def update_preview(self, hdl): 104 | root = minidom.parse(ProjectManager.get_proj_hdlgen()) 105 | HDLGen = root.documentElement 106 | hdlDesign = HDLGen.getElementsByTagName("hdlDesign") 107 | testbench_node = hdlDesign[0].getElementsByTagName('testbench') 108 | if len(testbench_node) != 0 and testbench_node[0].firstChild is not None: 109 | tb_node = testbench_node[0].getElementsByTagName('TBNote')[0] 110 | self.tbnote = tb_node.firstChild.nodeValue 111 | self.tbnote = self.tbnote.replace(" ", "\n") 112 | self.tbnote = self.tbnote.replace("&", "&") 113 | self.tbnote = self.tbnote.replace(""", "\"") 114 | self.tbnote = self.tbnote.replace("'", "\'") 115 | self.tbnote = self.tbnote.replace("<", "<") 116 | self.tbnote = self.tbnote.replace(" ", "\t") 117 | self.tbnote = self.tbnote.replace(">", ">") 118 | self.tbnote = self.tbnote.replace(",", ",") 119 | if self.tbnote == "None": 120 | self.tbnote = "No Test Plan Created" 121 | else: 122 | self.tbnote = "No Test Plan Created" 123 | 124 | if hdl != False and hdl != True and not isinstance(hdl, (int, float)): 125 | self.hdl = hdl 126 | if self.hdl == "VHDL": 127 | entity_name, self.code, instances, self.chatgpt_header, self.chatgpt_model = Generator.generate_vhdl(self) 128 | entity_name, self.tb_code, wcfg, self.chatgpt_tb = Generator.create_vhdl_testbench_code(self) 129 | chatgpt = hdlDesign[0].getElementsByTagName('chatgpt')[0] 130 | if chatgpt.hasChildNodes(): 131 | commands_node = chatgpt.getElementsByTagName('commands')[0] 132 | VHDLModel = commands_node.getElementsByTagName('VHDLModel')[0].firstChild.data 133 | VHDLModel = VHDLModel.replace(" ", "\n") 134 | VHDLModel = VHDLModel.replace("&", "&") 135 | VHDLModel = VHDLModel.replace(""", "\"") 136 | VHDLModel = VHDLModel.replace("'", "\'") 137 | VHDLModel = VHDLModel.replace("<", "<") 138 | VHDLModel = VHDLModel.replace(" ", "\t") 139 | VHDLModel = VHDLModel.replace(">", ">") 140 | VHDLModel = VHDLModel.replace(",", ",") 141 | lines = VHDLModel.split('\n') 142 | filtered_lines = [line for line in lines if not line.startswith('~')] 143 | VHDLModel = '\n'.join(filtered_lines) 144 | self.ModelCmd = VHDLModel 145 | elif self.hdl == "Verilog": 146 | entity_name,self.code, instances, self.chatgpt_header, self.chatgpt_model = Generator.generate_verilog(self) 147 | entity_name, self.tb_code, wcfg, self.chatgpt_tb = Generator.create_verilog_testbench_code(self) 148 | chatgpt = hdlDesign[0].getElementsByTagName('chatgpt')[0] 149 | if chatgpt.hasChildNodes(): 150 | commands_node = chatgpt.getElementsByTagName('commands')[0] 151 | VerilogModel = commands_node.getElementsByTagName('VerilogModel')[0].firstChild.data 152 | VerilogModel = VerilogModel.replace(" ", "\n") 153 | VerilogModel = VerilogModel.replace("&", "&") 154 | VerilogModel = VerilogModel.replace(""", "\"") 155 | VerilogModel = VerilogModel.replace("'", "\'") 156 | VerilogModel = VerilogModel.replace("<", "<") 157 | VerilogModel = VerilogModel.replace(" ", "\t") 158 | VerilogModel = VerilogModel.replace(">", ">") 159 | VerilogModel = VerilogModel.replace(",", ",") 160 | lines = VerilogModel.split('\n') 161 | filtered_lines = [line for line in lines if not line.startswith('~')] 162 | VerilogModel = '\n'.join(filtered_lines) 163 | self.ModelCmd=VerilogModel 164 | if self.tabs.currentIndex() == 6: 165 | self.preview_window.setText(self.tb_code) 166 | self.preview_label.setText("HDL Testbench Preview") 167 | elif self.tabs.currentIndex() == 7: 168 | if self.generate.tab_widget.currentIndex() == 0: 169 | if self.generate.model_check.isChecked(): 170 | self.preview_label.setText("HDL Model Preview") 171 | self.preview_window.setText(self.code) 172 | elif self.generate.header_model_check.isChecked(): 173 | self.preview_label.setText("ChatGPT Prompt Header Preview") 174 | self.preview_window.setText(self.ModelCmd) 175 | elif self.generate.msg_model_check.isChecked(): 176 | self.preview_label.setText("ChatGPT Prompt, to generate final HDL model") 177 | self.preview_window.setText(self.ModelCmd + "\n\n" +self.code) 178 | elif self.generate.tab_widget.currentIndex() == 1: 179 | if self.generate.header_testbench_check.isChecked(): 180 | self.preview_label.setText("ChatGPT Prompt Header Preview") 181 | elif self.generate.testbench_check.isChecked(): 182 | self.preview_window.setText(self.tb_code) 183 | self.preview_label.setText("HDL Testbench Preview") 184 | elif self.generate.tab_widget.currentIndex() == 2: 185 | if self.generate.header_title_check.isChecked(): 186 | self.preview_label.setText("ChatGPT Prompt Header Preview") 187 | self.preview_window.setText(self.HeaderCmd) 188 | elif self.generate.msg_title_check.isChecked(): 189 | self.preview_label.setText("ChatGPT Prompt, to generate final HDL title") 190 | self.preview_window.setText(self.HeaderCmd+ "\n\n" +self.chatgpt_header) 191 | else: 192 | self.preview_window.setText(self.code) 193 | self.preview_label.setText("HDL Model Preview") 194 | 195 | def update_arch(self): 196 | xml_data_path = ProjectManager.get_proj_hdlgen() 197 | self.architecture.updateProcessName(xml_data_path) 198 | 199 | def get_hdl(self): 200 | return self.hdl 201 | 202 | class TabBar(QTabBar): 203 | 204 | def tabSizeHint(self, index): 205 | s = QTabBar.tabSizeHint(self, index) 206 | s.transpose() 207 | return s 208 | 209 | def paintEvent(self, event): 210 | painter = QStylePainter(self) 211 | opt = QStyleOptionTab() 212 | for i in range(self.count()): 213 | self.initStyleOption(opt, i) 214 | painter.drawControl(QStyle.CE_TabBarTabShape, opt) 215 | painter.save() 216 | 217 | s = opt.rect.size() * 100 218 | s.transpose() 219 | r = QRect(QPoint(), s) 220 | r.moveCenter(opt.rect.center()) 221 | opt.rect = r 222 | 223 | c = self.tabRect(i).center() 224 | painter.translate(c) 225 | painter.rotate(90) 226 | painter.translate(-c) 227 | painter.drawControl(QStyle.CE_TabBarTabLabel, opt) 228 | painter.restore() 229 | 230 | class VerticalTabWidget(QTabWidget): 231 | def __init__(self, other_class=None, *args, **kwargs): 232 | QTabWidget.__init__(self, *args, **kwargs) 233 | self.setTabBar(TabBar()) 234 | self.setTabPosition(QTabWidget.West) 235 | self.currentChanged.connect(self.tab_changed) 236 | self.previous_index = self.currentIndex() 237 | self.other_class = other_class 238 | def tab_changed(self, index): 239 | # save state of previous tab 240 | prev_tab = self.widget(self.previous_index) 241 | if index == 6 or index == 7: 242 | if self.other_class: 243 | lang = self.other_class.get_hdl() 244 | self.other_class.update_preview(lang) 245 | if self.previous_index == 6 or self.previous_index == 7: 246 | if self.other_class: 247 | lang = self.other_class.get_hdl() 248 | self.other_class.update_preview(lang) 249 | self.previous_index = index -------------------------------------------------------------------------------- /Application/HDLDesigner/testPlan/testplan_help.md: -------------------------------------------------------------------------------- 1 | ## How to use the Test Table 2 | 3 | ### Signal Radix Format 4 | `1'b` is a 1-bit binary number (i.e. 0 or 1). 5 | Similarly, `16'b` is a 16-bit binary number. 6 | You can also specify a hexadecimal number: `16'h` represents a 16-bit hex number (e.g. `BEEF`). 7 | Decimal numbers can be specified explicitly with `d`, e.g. `16'd`, but simply writing `16` will work fine. 8 | 9 | ### Notes column 10 | The notes column can be used to describe the scenario being tested. 11 | When specified, it will appear as a comment in the generated testbench code. 12 | It is not a required field. 13 | 14 | ### Sequential Logic Components 15 | ##### The Clock Signal 16 | The testbench HDL includes a clock (Signal: `CLK`), with a default period of 20ns (50 Mhz). 17 | ##### The Reset Signal 18 | The reset signal (Signal: `RST`) is initially asserted, deasserting after `0.2 * period` after the first active clock edge. 19 | 20 | ### Delay Values 21 | The delay value is the number of periods to wait for, following the application of the test input signals, before asserting the validity of the output signals. Integer values can be specified, which will cause an N period delay, ending 0.2 periods after the active clock edge. This is due to the initial assertion of the reset signal for 0.2 periods, causing an offset. Real numbers can also be entered, e.g. 0.2, which will result in the delay ending 0.4 periods after the active clock edge (0.2 for `RST` and 0.2 for the delay). 22 | 23 | ### Editing the test table template 24 | The test table template generated by HDLGen-ChatGPT can be copied and pasted into Excel (or any other spreadsheet editor). When copied into a spreadsheet editor, you may have to set the cells to "Text" mode to prevent leading zeros from being truncated by Excel. 25 | 26 | Once the test table template has been completed, it can be copied from the spreadsheet editor and pasted back into the textbox which appears after entering "Edit Testplan". 27 | 28 | The template is generated by HDLGen-ChatGPT when the "Test Plan" tab is entered for the first time. To prevent overwriting any completed test plan work, the test plan template must be reset manually any time a signal is added or removed (Alternatively, signal columns can be added or removed from the testplan by hand, provided the testplan format is followed). 29 | 30 | The test table is a tab-separated table with each table row terminated by a newline character. -------------------------------------------------------------------------------- /Application/HDLDesigner/testPlan/testplan_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | COMP_HELP_DOC_FILE_PATH = "./HDLDesigner/testPlan/testplan_help.md" 6 | 7 | 8 | class TestPlanHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(COMP_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/Help/help.md: -------------------------------------------------------------------------------- 1 | # HDLGen-ChatGPT application 2 | - HDLGen-ChatGPT is an open-source client application, developed in the University of Galway 3 | ([Fearghal Morgan](mailto:fearghal.morgan1@gmail.com?subject=HDLGen-ChatGPT), John Patrick Byrne, Abishek Bupathi). 4 | Contact us with comments or suggestions. 5 | 6 | - Project website, with lots of links [HDLGen-ChatGPT github repository](https://github.com/HDLGen-ChatGPT/HDLGen-ChatGPT) 7 | 8 | - Our other work: 9 | [Vicilogic](https://www.vicilogic.com): online learning, assessment, remote FPGA prototying and coure builder platform 10 | 11 | 12 | - Why use HDLGen-ChatGPT and what can it do? 13 | - Many students find it difficult to develop mastery of 14 | - hardware description language (HDL) languages VHDL and Verilog 15 | modelling and testbenching for HDL simulation 16 | - complex Electronic Design Automation (EDA) tools, used for HDL 17 | simulation, synthesis, and FPGA prototyping. 18 | - HDLGen-ChatGPT and ChatGPT tools enable fast, automated 19 | - capture of digital systems design and test specification 20 | information 21 | - generation of VHDL and Verilog model templates 22 | - low level logic pseudo code 23 | - generation of VHDL and Verilog testbench templates 24 | - generation of EDA tool suite projects and folder 25 | (AMD Vivado and Intel Quartus) 26 | - ChatGPT prompts for completion of 27 | - HDL models 28 | - HDL template stimulus process and signal checking 29 | 30 | - HDLGen-ChatGPT currently supports 31 | - VHDL and Verilog hardware desciption language (HDLs) 32 | - AMD Xilinx Vivado V2019.1 FPGA EDA tool suite. [Video on V2019.1 installation instructions (same as for V2018.2)](https://vicicourse.s3.eu-west-1.amazonaws.com/AMD+Vivado/vivado2018.2Install.mp4) 33 | - Intel Quartus V21.1.1.850 FPGA EDA tool suite [3] 34 | - ChatGPT-3.5 or later 35 | -------------------------------------------------------------------------------- /Application/Help/help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | HELP_DOC_FILE_PATH = "./Help/help.md" 6 | OLD_HELP_DOC_FILE_PATH = "./Help/help(old).md" 7 | HELP_DOC_FILE_DIR = "./Help/" 8 | 9 | class Help(QWidget): 10 | 11 | def __init__(self): 12 | super().__init__() 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | self.mainLayout = QVBoxLayout() 17 | 18 | self.setup_ui() 19 | 20 | def setup_ui(self): 21 | 22 | # Writing xml file 23 | with open(HELP_DOC_FILE_PATH, "r") as f: 24 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 25 | 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | 31 | 32 | class HelpDialog(QDialog): 33 | 34 | def __init__(self): 35 | super().__init__() 36 | self.setWindowTitle("HDLGen Help") 37 | 38 | self.markdown_view = QTextBrowser(readOnly=True) 39 | self.markdown_view.setOpenExternalLinks(True) 40 | 41 | self.mainLayout = QVBoxLayout() 42 | self.setFixedSize(700, 500) 43 | self.setup_ui() 44 | 45 | def setup_ui(self): 46 | 47 | # Writing xml file 48 | with open(HELP_DOC_FILE_PATH, "r") as f: 49 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 50 | 51 | self.markdown_view.setHtml(doc) 52 | self.mainLayout.addWidget(self.markdown_view) 53 | self.setLayout(self.mainLayout) 54 | 55 | 56 | """ 57 | class WebEnginePage(QWebEnginePage): 58 | def acceptNavigationRequest(self, url, _type, isMainFrame): 59 | if _type == QWebEnginePage.NavigationTypeLinkClicked: 60 | QDesktopServices.openUrl(url); 61 | return False 62 | return True 63 | 64 | class HtmlView(QWebEngineView): 65 | def __init__(self, *args, **kwargs): 66 | QWebEngineView.__init__(self, *args, **kwargs) 67 | self.setPage(WebEnginePage(self)) 68 | """ 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Application/ProjectManager/eda_help.md: -------------------------------------------------------------------------------- 1 | # Selecting and linking to Electronic Design Automation (EDA) tool suites 2 | 3 | - For each project, setup pointers to the EDA tools path(s) 4 | - Select if using AMD Vivado EDA tool suite (use V 2019.1) or Intel Quartus, if the EDA tool suites are installed on your computer 5 | - Vivado 2019.1: browse to select the vivado.bat file in the Vivado installation folder. This is typically C:\Xilinx\Vivado\2019.1\bin\vivado.bat. 6 | 7 | - To configure pointers permanently for all projects, 8 | - Close the project (opens the splash page) 9 | - Click settings 10 | - Setup the paths to the EDA tool(s) 11 | - Click OK 12 | 13 | - If the EDA tools are not installed, you leave the fields blank. Much of ChatGPT can operate without using the EDA tools. 14 | 15 | - Video: Install AMD Vivado Vivado V2019.1 FPGA EDA tool suite. [V2019.1 installation instructions (same as for V2018.2)](https://vicicourse.s3.eu-west-1.amazonaws.com/AMD+Vivado/vivado2018.2Install.mp4)#### [Video tutorials](https://www.vicilogic.com/vicilearn/run_step/?c_id=56) -------------------------------------------------------------------------------- /Application/ProjectManager/eda_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | EDA_HELP_DOC_FILE_PATH = "./ProjectManager/eda_help.md" 6 | 7 | 8 | class EDAHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(EDA_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/ProjectManager/language_help.md: -------------------------------------------------------------------------------- 1 | # Supported Hardware Description Language 2 | 3 | - Select VHDL or Verilog HDL generation. This seletion is applied in all HDLGen-ChatGPT menus, until changed here. 4 | - The 'HDL Designer' 'Generate' menu header indicates if VHDL or Verilog language is veing generated. Return to the 'Project Manager' 'Generate' menu if you wish to modify the selected HDL language. 5 | - SystemVerilog and Chisel are not currently supported. -------------------------------------------------------------------------------- /Application/ProjectManager/language_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | VIVADO_HELP_DOC_FILE_PATH = "./ProjectManager/language_help.md" 6 | 7 | 8 | class LanguageHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(VIVADO_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/ProjectManager/projectLink.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import * 2 | from PySide2.QtGui import * 3 | import configparser 4 | 5 | BLACK_COLOR = "color: black" 6 | WHITE_COLOR = "color: white" 7 | 8 | class LinkDialog(QDialog): 9 | 10 | def __init__(self, add_or_edit, data=None): 11 | super().__init__() 12 | 13 | self.setWindowTitle("Project Information Link") 14 | title_font = QFont() 15 | title_font.setPointSize(10) 16 | title_font.setBold(True) 17 | bold_font = QFont() 18 | bold_font.setBold(True) 19 | input_font = QFont() 20 | input_font.setPointSize(10) 21 | 22 | self.input_layout = QGridLayout() 23 | self.mainLayout = QVBoxLayout() 24 | 25 | self.link_label = QLabel("Project Information Link") 26 | self.link_label.setFont(input_font) 27 | self.link_label.setStyleSheet(WHITE_COLOR) 28 | self.link_input = QLineEdit() 29 | self.link_input.setFont(input_font) 30 | 31 | 32 | self.cancel_btn = QPushButton("Cancel") 33 | self.cancel_btn.setFont(input_font) 34 | self.cancel_btn.setStyleSheet( 35 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 36 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 37 | 38 | 39 | self.ok_btn = QPushButton("Ok") 40 | self.ok_btn.setFont(input_font) 41 | self.ok_btn.setStyleSheet( 42 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 43 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 44 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 45 | self.input_frame = QFrame() 46 | 47 | self.cancelled = True 48 | self.config = configparser.ConfigParser() 49 | 50 | self.setup_ui() 51 | if add_or_edit == "edit" and data != None: 52 | self.load_data(data) 53 | def setup_ui(self): 54 | 55 | self.input_layout.addWidget(self.link_label, 0, 0, 1, 4) 56 | self.input_layout.addWidget(self.link_input, 1, 0, 1, 4) 57 | 58 | self.input_layout.addWidget(self.cancel_btn, 2, 2, 1, 1, alignment=Qt.AlignRight) 59 | self.input_layout.addWidget(self.ok_btn, 2, 3, 1, 1, alignment=Qt.AlignRight) 60 | self.input_frame.setFrameShape(QFrame.StyledPanel) 61 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 62 | self.input_frame.setContentsMargins(10, 10, 10, 10) 63 | self.input_frame.setFixedSize(500, 200) 64 | self.input_frame.setLayout(self.input_layout) 65 | self.cancel_btn.clicked.connect(self.cancel_selected) 66 | 67 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 68 | 69 | self.setLayout(self.mainLayout) 70 | self.ok_btn.clicked.connect(self.get_data) 71 | 72 | def cancel_selected(self): 73 | self.cancelled = True 74 | self.close() 75 | 76 | def load_data(self, data): 77 | if data == "None": 78 | data="" 79 | data = data.replace(" ", "\n") 80 | data = data.replace("&","&") 81 | data = data.replace("&", "&") 82 | data = data.replace(""","\"") 83 | data = data.replace("'","\'") 84 | data = data.replace("<","<") 85 | data = data.replace(" ","\t") 86 | data = data.replace(">",">") 87 | self.link_input.setText(data) 88 | def get_data(self): 89 | data = self.link_input.text().strip() 90 | data = data.replace("&", "&") 91 | data = data.replace("\n", " ") 92 | data = data.replace("\"", """) 93 | data = data.replace("\'", "'") 94 | data = data.replace("\n", " ") 95 | data = data.replace("<", "<") 96 | data = data.replace("\t", " ") 97 | data = data.replace(">", ">") 98 | data = data.replace(",", " ") 99 | if data == "": 100 | data = "None" 101 | self.cancelled = False 102 | self.close() 103 | return data -------------------------------------------------------------------------------- /Application/ProjectManager/settings_help.md: -------------------------------------------------------------------------------- 1 | # Project Settings 2 | 3 | - The fields provide details on the current project 4 | - 'Project Name' defines the HDLGen-Chat top level project folder, which may contain multiple 'Project Folders' 5 | - 'Project Folder' defines the name of the specific project folder, inside the 'Project Name' folder 6 | - 'Project Environment' defines the fodler which contains the folder 'Package', which includes VHDL package file 'MainPackage.vhd' (used in VHDL models) 7 | 8 | - HDLGen-ChatGPT will remember the previously opened project 9 | 10 | - Changing fields, and using the browser 11 | - Change the 'Project Name' field and click the 'HDL Designer' TAB, to copy the entire project to a new area, with the defined 'Project Name'. 12 | - Change the 'Project Folder' and click the 'HDL Designer' TAB, to copy the entire project to a new area, with the defined 'Project Name', and within folder 'Project Folder'. 13 | - Change the 'Project Environment' and click the 'HDL Designer' TAB to save the 'Project Folder' and 'Project Name' within the environment folder. A new 'MainPackage.vhd' file may be created (and used), within folder 'Package'. It may be necessary to use the 'HDL Designer' TAB 'Sub-Components' menu to add componentents is your design isa hierarchical. 14 | 15 | - Click the 'Close Project' button to close the project and return to the HDLGen-ChatGPT splash page -------------------------------------------------------------------------------- /Application/ProjectManager/settings_help.py: -------------------------------------------------------------------------------- 1 | #Displays the assoicated help markdown file 2 | import markdown as md 3 | from PySide2.QtWidgets import * 4 | 5 | VIVADO_HELP_DOC_FILE_PATH = "./ProjectManager/settings_help.md" 6 | 7 | 8 | class SettingsHelpDialog(QDialog): 9 | 10 | def __init__(self): 11 | super().__init__() 12 | self.setWindowTitle("HDLGen Help") 13 | 14 | self.markdown_view = QTextBrowser(readOnly=True) 15 | self.markdown_view.setOpenExternalLinks(True) 16 | 17 | self.mainLayout = QVBoxLayout() 18 | self.setFixedSize(800, 800) 19 | self.setup_ui() 20 | 21 | def setup_ui(self): 22 | 23 | # Writing xml file 24 | with open(VIVADO_HELP_DOC_FILE_PATH, "r") as f: 25 | doc = md.markdown(f.read(), extensions=['fenced_code', 'codehilite', 'tables', 'attr_list']) 26 | self.markdown_view.setHtml(doc) 27 | self.mainLayout.addWidget(self.markdown_view) 28 | self.setLayout(self.mainLayout) 29 | 30 | -------------------------------------------------------------------------------- /Application/Resources/blue_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/blue_logo.png -------------------------------------------------------------------------------- /Application/Resources/hdlgen_title_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/hdlgen_title_blue.png -------------------------------------------------------------------------------- /Application/Resources/hdlgen_title_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/hdlgen_title_red.png -------------------------------------------------------------------------------- /Application/Resources/main_menu_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/main_menu_0.png -------------------------------------------------------------------------------- /Application/Resources/main_menu_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/main_menu_1.png -------------------------------------------------------------------------------- /Application/Resources/processdiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/processdiagram.png -------------------------------------------------------------------------------- /Application/Resources/red_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicademy/HDLGen-ChatGPT/b9ea68a40cbe3dc57e04223fdd5bfdc68f64adce/Application/Resources/red_logo.png -------------------------------------------------------------------------------- /Application/Settings/VHDLModelDefault.py: -------------------------------------------------------------------------------- 1 | #Dialog box for the ChatGPT prompt from prompts.yml file. This is called from setting.py and data is exchanged. User can edit the prompts.yml file using this for the specific prompt 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import configparser 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VHDLModelDefaultDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None, resetData=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT VHDL Model Default Prompt") 15 | bold_font = QFont() 16 | bold_font.setBold(True) 17 | input_font = QFont() 18 | input_font.setPointSize(10) 19 | 20 | self.input_layout = QGridLayout() 21 | self.mainLayout = QVBoxLayout() 22 | 23 | self.ChatGPT_default_label = QLabel("ChatGPT Default Prompt") 24 | self.ChatGPT_default_label.setStyleSheet(WHITE_COLOR) 25 | self.ChatGPT_default_label.setFont(input_font) 26 | self.ChatGPT_default_input = QPlainTextEdit() 27 | self.ChatGPT_default_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 28 | self.ChatGPT_default_input.setFont(input_font) 29 | 30 | 31 | self.reset_btn = QPushButton("Reset") 32 | self.reset_btn.setFont(input_font) 33 | self.reset_btn.setStyleSheet( 34 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 35 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 36 | 37 | self.cancel_btn = QPushButton("Cancel") 38 | self.cancel_btn.setFont(input_font) 39 | self.cancel_btn.setStyleSheet( 40 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 41 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 42 | 43 | 44 | self.ok_btn = QPushButton("Ok") 45 | self.ok_btn.setFont(input_font) 46 | self.ok_btn.setStyleSheet( 47 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 48 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 49 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 50 | 51 | self.input_frame = QFrame() 52 | 53 | self.cancelled = True 54 | self.config = configparser.ConfigParser() 55 | 56 | self.setup_ui() 57 | if add_or_edit == "edit" and data != None and resetData != None: 58 | self.resetData = resetData 59 | self.ChatGPT_default_input.setPlainText(data) 60 | 61 | def setup_ui(self): 62 | self.input_layout.addWidget(self.ChatGPT_default_label, 0, 0, 1, 4) 63 | self.input_layout.addWidget(self.ChatGPT_default_input, 1, 0, 4, 4) 64 | 65 | self.input_layout.addWidget(self.reset_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 66 | self.input_layout.addWidget(self.cancel_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 67 | self.input_layout.addWidget(self.ok_btn, 6, 3, 1, 1, alignment=Qt.AlignRight) 68 | self.input_frame.setFrameShape(QFrame.StyledPanel) 69 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 70 | self.input_frame.setContentsMargins(10, 10, 10, 10) 71 | self.input_frame.setFixedSize(900, 800) 72 | self.input_frame.setLayout(self.input_layout) 73 | self.cancel_btn.clicked.connect(self.cancel_selected) 74 | 75 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 76 | 77 | self.setLayout(self.mainLayout) 78 | self.reset_btn.clicked.connect(self.reset) 79 | self.ok_btn.clicked.connect(self.get_data) 80 | 81 | def cancel_selected(self): 82 | self.cancelled = True 83 | self.close() 84 | 85 | def get_data(self): 86 | data = self.ChatGPT_default_input.toPlainText().strip() 87 | if data == "": 88 | data = "None" 89 | self.cancelled = False 90 | self.close() 91 | return data 92 | 93 | def reset(self): 94 | self.ChatGPT_default_input.setPlainText(self.resetData) -------------------------------------------------------------------------------- /Application/Settings/VHDLTestbenchDefault.py: -------------------------------------------------------------------------------- 1 | #Dialog box for the ChatGPT prompt from prompts.yml file. This is called from setting.py and data is exchanged. User can edit the prompts.yml file using this for the specific prompt 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import configparser 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VHDLTestbenchDefaultDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None, resetData=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT VHDL Testbench Default Prompt") 15 | 16 | bold_font = QFont() 17 | bold_font.setBold(True) 18 | input_font = QFont() 19 | input_font.setPointSize(10) 20 | 21 | self.input_layout = QGridLayout() 22 | self.mainLayout = QVBoxLayout() 23 | 24 | self.ChatGPT_default_label = QLabel("ChatGPT Default Prompt") 25 | self.ChatGPT_default_label.setStyleSheet(WHITE_COLOR) 26 | self.ChatGPT_default_label.setFont(input_font) 27 | self.ChatGPT_default_input = QPlainTextEdit() 28 | self.ChatGPT_default_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 29 | self.ChatGPT_default_input.setFont(input_font) 30 | 31 | self.reset_btn = QPushButton("Reset") 32 | self.reset_btn.setFont(input_font) 33 | self.reset_btn.setStyleSheet( 34 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 35 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 36 | 37 | self.cancel_btn = QPushButton("Cancel") 38 | self.cancel_btn.setFont(input_font) 39 | self.cancel_btn.setStyleSheet( 40 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 41 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 42 | 43 | self.ok_btn = QPushButton("Ok") 44 | self.ok_btn.setFont(input_font) 45 | self.ok_btn.setStyleSheet( 46 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 47 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 48 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 49 | self.input_frame = QFrame() 50 | 51 | self.cancelled = True 52 | self.config = configparser.ConfigParser() 53 | 54 | self.setup_ui() 55 | if add_or_edit == "edit" and data != None and resetData != None: 56 | self.resetData = resetData 57 | self.ChatGPT_default_input.setPlainText(data) 58 | 59 | def setup_ui(self): 60 | self.input_layout.addWidget(self.ChatGPT_default_label, 0, 0, 1, 4) 61 | self.input_layout.addWidget(self.ChatGPT_default_input, 1, 0, 4, 4) 62 | self.input_layout.addWidget(self.reset_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 63 | self.input_layout.addWidget(self.cancel_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 64 | self.input_layout.addWidget(self.ok_btn, 6, 3, 1, 1, alignment=Qt.AlignRight) 65 | self.input_frame.setFrameShape(QFrame.StyledPanel) 66 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 67 | self.input_frame.setContentsMargins(10, 10, 10, 10) 68 | self.input_frame.setFixedSize(900, 800) 69 | self.input_frame.setLayout(self.input_layout) 70 | self.cancel_btn.clicked.connect(self.cancel_selected) 71 | 72 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 73 | 74 | self.setLayout(self.mainLayout) 75 | self.reset_btn.clicked.connect(self.reset) 76 | self.ok_btn.clicked.connect(self.get_data) 77 | 78 | def cancel_selected(self): 79 | self.cancelled = True 80 | self.close() 81 | 82 | def get_data(self): 83 | data = self.ChatGPT_default_input.toPlainText().strip() 84 | if data == "": 85 | data = "None" 86 | self.cancelled = False 87 | self.close() 88 | return data 89 | 90 | def reset(self): 91 | self.ChatGPT_default_input.setPlainText(self.resetData) -------------------------------------------------------------------------------- /Application/Settings/VerilogModelDefault.py: -------------------------------------------------------------------------------- 1 | #Dialog box for the ChatGPT prompt from prompts.yml file. This is called from setting.py and data is exchanged. User can edit the prompts.yml file using this for the specific prompt 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import configparser 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VerilogModelDefaultDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None, resetData=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT Verilog Model Default Prompt") 15 | input_font = QFont() 16 | input_font.setPointSize(10) 17 | bold_font = QFont() 18 | bold_font.setBold(True) 19 | 20 | self.input_layout = QGridLayout() 21 | self.mainLayout = QVBoxLayout() 22 | 23 | self.ChatGPT_default_label = QLabel("ChatGPT Default Prompt") 24 | self.ChatGPT_default_label.setStyleSheet(WHITE_COLOR) 25 | self.ChatGPT_default_label.setFont(input_font) 26 | self.ChatGPT_default_input = QPlainTextEdit() 27 | self.ChatGPT_default_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 28 | self.ChatGPT_default_input.setFont(input_font) 29 | 30 | self.reset_btn = QPushButton("Reset") 31 | self.reset_btn.setFont(input_font) 32 | self.reset_btn.setStyleSheet( 33 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 34 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 35 | 36 | self.cancel_btn = QPushButton("Cancel") 37 | self.cancel_btn.setFont(input_font) 38 | self.cancel_btn.setStyleSheet( 39 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 40 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 41 | 42 | self.ok_btn = QPushButton("Ok") 43 | self.ok_btn.setFont(input_font) 44 | self.ok_btn.setStyleSheet( 45 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 46 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 47 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 48 | self.input_frame = QFrame() 49 | 50 | self.cancelled = True 51 | self.config = configparser.ConfigParser() 52 | 53 | self.setup_ui() 54 | if add_or_edit == "edit" and data != None and resetData != None: 55 | self.resetData = resetData 56 | self.ChatGPT_default_input.setPlainText(data) 57 | 58 | def setup_ui(self): 59 | self.input_layout.addWidget(self.ChatGPT_default_label, 0, 0, 1, 4) 60 | self.input_layout.addWidget(self.ChatGPT_default_input, 1, 0, 4, 4) 61 | self.input_layout.addWidget(self.reset_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 62 | self.input_layout.addWidget(self.cancel_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 63 | self.input_layout.addWidget(self.ok_btn, 6, 3, 1, 1, alignment=Qt.AlignRight) 64 | self.input_frame.setFrameShape(QFrame.StyledPanel) 65 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 66 | self.input_frame.setContentsMargins(10, 10, 10, 10) 67 | self.input_frame.setFixedSize(900, 800) 68 | self.input_frame.setLayout(self.input_layout) 69 | self.cancel_btn.clicked.connect(self.cancel_selected) 70 | 71 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 72 | 73 | self.setLayout(self.mainLayout) 74 | self.ok_btn.clicked.connect(self.get_data) 75 | self.reset_btn.clicked.connect(self.reset) 76 | 77 | def cancel_selected(self): 78 | self.cancelled = True 79 | self.close() 80 | 81 | def get_data(self): 82 | data = self.ChatGPT_default_input.toPlainText().strip() 83 | if data == "": 84 | data = "None" 85 | self.cancelled = False 86 | self.close() 87 | return data 88 | 89 | def reset(self): 90 | self.ChatGPT_default_input.setPlainText(self.resetData) -------------------------------------------------------------------------------- /Application/Settings/VerilogTestbenchDefault.py: -------------------------------------------------------------------------------- 1 | #Dialog box for the ChatGPT prompt from prompts.yml file. This is called from setting.py and data is exchanged. User can edit the prompts.yml file using this for the specific prompt 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import configparser 5 | 6 | BLACK_COLOR = "color: black" 7 | WHITE_COLOR = "color: white" 8 | 9 | class VerilogTestbenchDefaultDialog(QDialog): 10 | 11 | def __init__(self, add_or_edit, data=None, resetData=None): 12 | super().__init__() 13 | 14 | self.setWindowTitle("ChatGPT Verilog Testbench Default Prompt") 15 | input_font = QFont() 16 | input_font.setPointSize(10) 17 | bold_font = QFont() 18 | bold_font.setBold(True) 19 | 20 | self.input_layout = QGridLayout() 21 | self.mainLayout = QVBoxLayout() 22 | 23 | self.ChatGPT_default_label = QLabel("ChatGPT Default Prompt") 24 | self.ChatGPT_default_label.setStyleSheet(WHITE_COLOR) 25 | self.ChatGPT_default_label.setFont(input_font) 26 | self.ChatGPT_default_input = QPlainTextEdit() 27 | self.ChatGPT_default_input.setLineWrapMode(QPlainTextEdit.WidgetWidth) 28 | self.ChatGPT_default_input.setFont(input_font) 29 | 30 | self.reset_btn = QPushButton("Reset") 31 | self.reset_btn.setFont(input_font) 32 | self.reset_btn.setStyleSheet( 33 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 34 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 35 | 36 | self.cancel_btn = QPushButton("Cancel") 37 | self.cancel_btn.setFont(input_font) 38 | self.cancel_btn.setStyleSheet( 39 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 40 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 41 | 42 | self.ok_btn = QPushButton("Ok") 43 | self.ok_btn.setFont(input_font) 44 | self.ok_btn.setStyleSheet( 45 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 46 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 47 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 48 | self.input_frame = QFrame() 49 | 50 | self.cancelled = True 51 | self.config = configparser.ConfigParser() 52 | 53 | self.setup_ui() 54 | if add_or_edit == "edit" and data != None and resetData != None: 55 | self.resetData = resetData 56 | self.ChatGPT_default_input.setPlainText(data) 57 | 58 | def setup_ui(self): 59 | self.input_layout.addWidget(self.ChatGPT_default_label, 0, 0, 1, 4) 60 | self.input_layout.addWidget(self.ChatGPT_default_input, 1, 0, 4, 4) 61 | self.input_layout.addWidget(self.reset_btn, 6, 1, 1, 1, alignment=Qt.AlignRight) 62 | self.input_layout.addWidget(self.cancel_btn, 6, 2, 1, 1, alignment=Qt.AlignRight) 63 | self.input_layout.addWidget(self.ok_btn, 6, 3, 1, 1, alignment=Qt.AlignRight) 64 | self.input_frame.setFrameShape(QFrame.StyledPanel) 65 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 66 | self.input_frame.setContentsMargins(10, 10, 10, 10) 67 | self.input_frame.setFixedSize(900, 800) 68 | self.input_frame.setLayout(self.input_layout) 69 | self.cancel_btn.clicked.connect(self.cancel_selected) 70 | 71 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 72 | 73 | self.setLayout(self.mainLayout) 74 | self.ok_btn.clicked.connect(self.get_data) 75 | self.reset_btn.clicked.connect(self.reset) 76 | 77 | def cancel_selected(self): 78 | self.cancelled = True 79 | self.close() 80 | 81 | def get_data(self): 82 | data = self.ChatGPT_default_input.toPlainText().strip() 83 | if data == "": 84 | data = "None" 85 | self.cancelled = False 86 | self.close() 87 | return data 88 | 89 | def reset(self): 90 | self.ChatGPT_default_input.setPlainText(self.resetData) 91 | -------------------------------------------------------------------------------- /Application/Settings/settings.py: -------------------------------------------------------------------------------- 1 | #settings dialog box when settings is clicked in main.py. Reads/writes from config.ini file default and reusable information 2 | from PySide2.QtWidgets import * 3 | from PySide2.QtGui import * 4 | import sys, yaml, configparser 5 | # make sure to add to requirements.txt 6 | from Settings.VHDLModelDefault import VHDLModelDefaultDialog 7 | from Settings.VerilogModelDefault import VerilogModelDefaultDialog 8 | sys.path.append("..") 9 | 10 | BLACK_COLOR = "color: black" 11 | WHITE_COLOR = "color: white" 12 | 13 | class settingsDialog(QDialog): 14 | 15 | def __init__(self): 16 | super().__init__() 17 | self.commands = ["None", "None", "None", "None", "None", "None","None", "None", "None", "None"] 18 | self.setWindowTitle("Settings") 19 | title_font = QFont() 20 | title_font.setPointSize(12) 21 | title_font.setBold(True) 22 | bold_font = QFont() 23 | bold_font.setBold(True) 24 | input_font = QFont() 25 | input_font.setPointSize(10) 26 | 27 | self.input_layout = QGridLayout() 28 | self.mainLayout = QVBoxLayout() 29 | 30 | self.author_label = QLabel("Author") 31 | self.author_label.setStyleSheet(WHITE_COLOR) 32 | self.author_label.setFont(title_font) 33 | self.author_input = QLineEdit() 34 | self.author_input.setFont(input_font) 35 | 36 | self.email_label = QLabel("Email") 37 | self.email_label.setStyleSheet(WHITE_COLOR) 38 | self.email_input = QLineEdit() 39 | 40 | self.company_label = QLabel("Company") 41 | self.company_label.setStyleSheet(WHITE_COLOR) 42 | self.company_input = QLineEdit() 43 | 44 | self.vivado_label = QLabel("Vivado.bat path") 45 | self.vivado_label.setStyleSheet(WHITE_COLOR) 46 | self.vivado_input = QLineEdit() 47 | 48 | self.quartus_label = QLabel("Quartus path") 49 | self.quartus_label.setStyleSheet(WHITE_COLOR) 50 | self.quartus_input = QLineEdit() 51 | 52 | self.header_VHDL = QPushButton("VHDL Title Section Command") 53 | #self.header_VHDL.setFixedSize(200, 25) 54 | self.header_VHDL.setStyleSheet( 55 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 56 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 57 | self.model_VHDL = QPushButton("VHDL Model Command") 58 | #self.model_VHDL.setFixedSize(250, 25) 59 | self.model_VHDL.setStyleSheet( 60 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 61 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 62 | self.header_Verilog = QPushButton("Verilog Title Section Command") 63 | #self.header_Verilog.setFixedSize(200, 25) 64 | self.header_Verilog.setStyleSheet( 65 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 66 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 67 | self.model_Verilog = QPushButton("Verilog Model Command") 68 | # self.model_Verilog.setFixedSize(250, 25) 69 | self.model_Verilog.setStyleSheet( 70 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 71 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 72 | self.browse_btn = QPushButton("Browse") 73 | #self.browse_btn.setFixedSize(80, 25) 74 | self.browse_btn.setStyleSheet( 75 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 76 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 77 | self.quartus_browse_btn = QPushButton("Browse") 78 | #self.quartus_browse_btn.setFixedSize(80, 25) 79 | self.quartus_browse_btn.setStyleSheet( 80 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }" 81 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 82 | 83 | self.cancel_btn = QPushButton("Cancel") 84 | # self.cancel_btn.setFixedSize(60, 25) 85 | self.cancel_btn.setStyleSheet( 86 | "QPushButton {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 87 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}") 88 | 89 | 90 | self.ok_btn = QPushButton("Ok") 91 | #self.ok_btn.setFixedSize(60, 25) 92 | self.ok_btn.setStyleSheet( 93 | "QPushButton {background-color: rgb(169,169,169); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 94 | " QPushButton:pressed { background-color: rgb(250, 250, 250); color: black; border-radius: 8px; border-style: plain;padding: 10px;}" 95 | "QPushButton:enabled {background-color: white; color: black; border-radius: 8px; border-style: plain;padding: 10px; }") 96 | self.input_frame = QFrame() 97 | 98 | self.cancelled = True 99 | self.config = configparser.ConfigParser() 100 | self.vivado_label.setFont(title_font) 101 | self.email_label.setFont(title_font) 102 | self.company_label.setFont(title_font) 103 | self.quartus_label.setFont(title_font) 104 | self.vivado_input.setFont(input_font) 105 | self.email_input.setFont(input_font) 106 | self.company_input.setFont(input_font) 107 | self.quartus_input.setFont(input_font) 108 | self.browse_btn.setFont(input_font) 109 | self.quartus_browse_btn.setFont(input_font) 110 | self.model_VHDL.setFont(input_font) 111 | self.model_Verilog.setFont(input_font) 112 | self.ok_btn.setFont(input_font) 113 | self.cancel_btn.setFont(input_font) 114 | self.setup_ui() 115 | 116 | def setup_ui(self): 117 | self.config.read('config.ini') 118 | 119 | with open('prompts.yml', 'r') as prompts: 120 | self.prompts = yaml.safe_load(prompts) 121 | 122 | vivadoPath= self.config.get('user', 'vivado.bat') 123 | quartusPath = self.config.get('user','quartus') 124 | author = self.config.get('user', 'author') 125 | email = self.config.get('user', 'email') 126 | company = self.config.get('user', 'company') 127 | 128 | self.commands[0] = self.prompts["vhdlchatgptmodel"] 129 | self.commands[1] = self.prompts["verilogchatgptmodel"] 130 | self.commands[2] = self.prompts["vhdlchatgptmodelreset"] 131 | self.commands[3] = self.prompts["verilogchatgptmodelreset"] 132 | 133 | self.vivado_input.setText(vivadoPath.strip()) 134 | self.quartus_input.setText(quartusPath.strip()) 135 | self.author_input.setText(author.strip()) 136 | self.email_input.setText(email.strip()) 137 | self.company_input.setText(company.strip()) 138 | self.input_layout.addWidget(self.author_label, 0, 0, 1, 1) 139 | self.input_layout.addWidget(self.author_input, 1, 0, 1, 1) 140 | self.input_layout.addWidget(self.email_label, 0, 1, 1, 1) 141 | self.input_layout.addWidget(self.email_input, 1, 1, 1, 1) 142 | self.input_layout.addWidget(self.company_label, 0, 2, 1, 2) 143 | self.input_layout.addWidget(self.company_input, 1, 2, 1, 2) 144 | self.input_layout.addWidget(self.vivado_label, 2, 0, 1, 3) 145 | self.input_layout.addWidget(self.vivado_input, 3, 0, 1, 3) 146 | self.input_layout.addWidget(self.browse_btn, 3, 3, 1, 1) 147 | self.input_layout.addWidget(self.quartus_label, 4, 0, 1, 3) 148 | self.input_layout.addWidget(self.quartus_input, 5, 0, 1, 3) 149 | self.input_layout.addWidget(self.quartus_browse_btn, 5, 3, 1, 1) 150 | self.input_layout.addWidget(self.model_VHDL, 6, 0) 151 | self.input_layout.addWidget(self.model_Verilog, 6, 1) 152 | #self.header_VHDL.clicked.connect(self.vhdl_header_command) 153 | #self.header_Verilog.clicked.connect(self.verilog_header_command) 154 | self.model_VHDL.clicked.connect(self.vhdl_model_command) 155 | self.model_Verilog.clicked.connect(self.verilog_model_command) 156 | 157 | self.input_layout.addWidget(self.cancel_btn, 9, 2, 1, 1, alignment=Qt.AlignRight) 158 | self.input_layout.addWidget(self.ok_btn, 9, 3, 1, 1, alignment=Qt.AlignRight) 159 | self.input_frame.setFrameShape(QFrame.StyledPanel) 160 | self.input_frame.setStyleSheet('.QFrame{background-color: rgb(97, 107, 129); border-radius: 5px;}') 161 | self.input_frame.setContentsMargins(10, 10, 10, 10) 162 | self.input_frame.setFixedSize(1000, 500) 163 | self.input_frame.setLayout(self.input_layout) 164 | self.cancel_btn.clicked.connect(self.cancel) 165 | 166 | self.mainLayout.addWidget(self.input_frame, alignment=Qt.AlignCenter) 167 | 168 | self.setLayout(self.mainLayout) 169 | self.browse_btn.clicked.connect(self.set_vivado_bat_path) 170 | self.quartus_browse_btn.clicked.connect(self.set_quartus_exe_path) 171 | self.ok_btn.clicked.connect(self.save) 172 | 173 | def set_vivado_bat_path(self): 174 | vivado_bat_path = QFileDialog.getOpenFileName(self,"Select Xilinx Vivado Batch file (vivado.bat)","C:/", filter="Batch (*.bat)") 175 | vivado_bat_path = vivado_bat_path[0] 176 | self.vivado_input.setText(vivado_bat_path) 177 | 178 | def set_quartus_exe_path(self): 179 | quartus_exe_path = QFileDialog.getOpenFileName(self,"Select Quartus Exe file (quartus_map.exe)","C:/", filter="Batch (*.exe)") 180 | quartus_exe_path = quartus_exe_path[0] 181 | self.quartus_input.setText(quartus_exe_path) 182 | 183 | def cancel(self): 184 | self.cancelled = True 185 | self.close() 186 | 187 | def enable_ok_btn(self): 188 | if self.vivado_input.text() != "" and self.vivado_input.text() != "To be completed": 189 | self.ok_btn.setEnabled(True) 190 | else: 191 | self.ok_btn.setEnabled(False) 192 | 193 | def save(self): 194 | if self.vivado_input.text().strip() == "": 195 | self.vivado_input.setText("To be completed") 196 | if self.quartus_input.text().strip() == "": 197 | self.quartus_input.setText("To be completed") 198 | if self.author_input.text().strip() == "": 199 | self.author_input.setText("To be completed") 200 | if self.email_input.text().strip() == "": 201 | self.email_input.setText("To be completed") 202 | if self.company_input.text().strip() == "": 203 | self.company_input.setText("To be completed") 204 | 205 | self.config.set("user", "author", self.author_input.text()) 206 | self.config.set("user", "email", self.email_input.text()) 207 | self.config.set("user", "company", self.company_input.text()) 208 | self.config.set("user", "vivado.bat", self.vivado_input.text()) 209 | self.config.set("user", "quartus", self.quartus_input.text()) 210 | 211 | with open('config.ini', 'w') as configfile: 212 | self.config.write(configfile) 213 | 214 | with open('prompts.yml', 'r') as prompts: 215 | self.prompts = yaml.safe_load(prompts) 216 | 217 | self.prompts["vhdlchatgptmodel"] = self.commands[0] 218 | self.prompts["verilogchatgptmodel"] = self.commands[1] 219 | 220 | with open('prompts.yml', 'w') as prompts: 221 | yaml.dump(self.prompts, prompts) 222 | 223 | self.cancelled = False 224 | self.close() 225 | 226 | def vhdl_model_command(self): 227 | vhdl_model = VHDLModelDefaultDialog("edit", self.commands[0], self.commands[2]) 228 | vhdl_model.exec_() 229 | 230 | if not vhdl_model.cancelled: 231 | vhdl_model = vhdl_model.get_data() 232 | self.commands[0] = vhdl_model 233 | 234 | def verilog_model_command(self): 235 | verilog_model = VerilogModelDefaultDialog("edit", self.commands[1], self.commands[3]) 236 | verilog_model.exec_() 237 | 238 | if not verilog_model.cancelled: 239 | verilog_model = verilog_model.get_data() 240 | self.commands[1] = verilog_model -------------------------------------------------------------------------------- /Application/main.py: -------------------------------------------------------------------------------- 1 | #main.py is the file that is called when HDLGen-ChatGPT is started. From here the home.py, settings.py and help.py are called. This displays the splash page on start up 2 | import os 3 | from PySide2.QtGui import * 4 | from PySide2.QtWidgets import * 5 | from PySide2.QtCore import * 6 | from pathlib import Path 7 | import sys 8 | sys.path.append(".") 9 | from Home.home import Home 10 | from Help.help import HelpDialog 11 | from Settings.settings import settingsDialog 12 | import configparser 13 | 14 | 15 | APP_AUTHORS = "Created by Fearghal Morgan, Abishek Bupathi & JP Byrne" 16 | 17 | VICI_DESCRIPTION = "Online learning and assessment, Remote FPGA\nprototyping and course builder" 18 | 19 | APP_DESCRIPTION = "