├── .github └── workflows │ └── main.yml ├── .gitmodules ├── README.md ├── doc ├── debug │ ├── DEBUGGING.md │ ├── debugging.png │ └── docker_extension.png └── theme │ ├── classic_theme.png │ ├── dark_theme.png │ └── light_theme.png ├── fir.cpp ├── launch.py ├── launchUI.bash ├── mode_classic.py ├── mode_dark_light.py ├── run_mac_docker.sh └── run_windows_docker.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 11 | BUILD_TYPE: Release 12 | 13 | jobs: 14 | build: 15 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 16 | # You can convert this to a matrix build if you need cross-platform coverage. 17 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 18 | runs-on: ubuntu-20.04 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | python-version: ["3.7.13", "3.9.20", "3.12.8"] 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | with: 27 | submodules: true 28 | 29 | # Update references 30 | - name: Git Sumbodule Update 31 | run: | 32 | git submodule update --init 33 | 34 | 35 | - name: Install LLVM and Clang for CGRA-Mapper 36 | uses: egor-tensin/setup-clang@v1 37 | with: 38 | version: 12 39 | platform: x64 40 | 41 | - name: Configure CMake for CGRA-Mapper 42 | run: cd CGRA-Mapper && mkdir build && cd build && cmake .. 43 | 44 | - name: Build for CGRA-Mapper 45 | working-directory: ${{github.workspace}}/CGRA-Mapper/build 46 | run: make 47 | 48 | - name: Test for CGRA-Mapper 49 | working-directory: ${{github.workspace}}/CGRA-Mapper/test 50 | run: sudo ln -sf /usr/bin/opt-12 /usr/bin/opt && source compile.sh 51 | 52 | - name: Set up Python ${{ matrix.python-version }} for VectorCGRA 53 | uses: actions/setup-python@v3 54 | with: 55 | python-version: ${{ matrix.python-version }} 56 | - name: VectorCGRA Git Sumbodule Update 57 | run: | 58 | cd VectorCGRA 59 | git submodule update --init 60 | - name: Install Verilator for VectorCGRA 61 | run: | 62 | wget https://github.com/tancheng/pymtl-verilator/raw/master/verilator-travis-4.036.tar.gz 63 | tar -C ${HOME} -xzf verilator-travis-4.036.tar.gz 64 | echo "VERILATOR_ROOT=${HOME}/verilator" >> $GITHUB_ENV 65 | echo "PYMTL_VERILATOR_INCLUDE_DIR=${HOME}/verilator/share/verilator/include" >> $GITHUB_ENV 66 | echo "${HOME}/verilator/bin" >> $GITHUB_PATH 67 | 68 | - name: Check Verilator for VectorCGRA 69 | run: | 70 | echo ${VERILATOR_ROOT} 71 | echo ${PYMTL_VERILATOR_INCLUDE_DIR} 72 | verilator --version 73 | 74 | - name: Install dependencies for VectorCGRA 75 | run: | 76 | sudo apt-get install -y graphviz 77 | sudo apt-get install git libffi-dev 78 | python3 -m venv ${HOME}/venv 79 | source ${HOME}/venv/bin/activate 80 | pip install py==1.11.0 81 | pip install wheel 82 | pip install -U git+https://github.com/tancheng/pymtl3.1@yo-struct-list-fix 83 | pip install hypothesis 84 | pip install pytest 85 | pip list 86 | - name: Test with pytest for VectorCGRA 87 | run: | 88 | cd VectorCGRA 89 | mkdir -p build && cd build 90 | source ${HOME}/venv/bin/activate 91 | pytest .. -v --tb=short 92 | 93 | 94 | - name: Install dependencies for mflowgen 95 | run: | 96 | sudo apt-get install -y yosys 97 | 98 | - name: Build for mflowgen 99 | working-directory: ${{github.workspace}}/tools/mflowgen 100 | run: | 101 | pip install -e . 102 | 103 | - name: Test for mflowgen 104 | working-directory: ${{github.workspace}}/tools/mflowgen 105 | run: | 106 | mkdir build && cd build 107 | mflowgen run --design ../designs/GcdUnit 108 | make 3 109 | 110 | - name: Build for cacti 111 | working-directory: ${{github.workspace}}/tools/cacti 112 | run: make 113 | 114 | 115 | - name: Install dependencies for sv2v 116 | run: stack upgrade 117 | 118 | - name: Build for sv2v 119 | working-directory: ${{github.workspace}}/tools/sv2v 120 | run: make 121 | 122 | 123 | - name: Install dependencies for tkinter 124 | run: | 125 | sudo apt-get install python3-tk 126 | source ${HOME}/venv/bin/activate 127 | pip install pillow 128 | 129 | - name: Test for tkinter 130 | working-directory: ${{github.workspace}}/ 131 | run: | 132 | mkdir build && cd build 133 | source ${HOME}/venv/bin/activate 134 | 135 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "CGRA-Mapper"] 2 | path = CGRA-Mapper 3 | url = https://github.com/tancheng/CGRA-Mapper 4 | [submodule "CGRA-Benchmark"] 5 | path = CGRA-Benchmark 6 | url = https://github.com/tancheng/CGRA-Benchmark 7 | [submodule "VectorCGRA"] 8 | path = VectorCGRA 9 | url = https://github.com/tancheng/VectorCGRA.git 10 | [submodule "mlir-cgra"] 11 | path = mlir-cgra 12 | url = https://github.com/tancheng/mlir-cgra.git 13 | [submodule "tools/mflowgen"] 14 | path = tools/mflowgen 15 | url = https://github.com/tancheng/mflowgen.git 16 | [submodule "tools/sv2v"] 17 | path = tools/sv2v 18 | url = https://github.com/zachjs/sv2v.git 19 | [submodule "tools/cacti"] 20 | path = tools/cacti 21 | url = https://github.com/tancheng/cacti.git 22 | [submodule "tools/OpenROAD-flow-scripts"] 23 | path = tools/OpenROAD-flow-scripts 24 | url = https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts.git 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
  2 | ========================================================
  3 | 
  4 |    ________________  ___         ________             
  5 |   / ____/ ____/ __ \/   |       / ____/ /___ _      __
  6 |  / /   / / __/ /_/ / /| |______/ /_  / / __ \ | /| / /
  7 | / /___/ /_/ / _, _/ ___ /_____/ __/ / / /_/ / |/ |/ / 
  8 | \____/\____/_/ |_/_/  |_|    /_/   /_/\____/|__/|__/  
  9 |                                                       
 10 | 
 11 | ========================================================
 12 | 
13 | [![Github Action](https://github.com/tancheng/CGRA-Flow/actions/workflows/main.yml/badge.svg)](https://github.com/tancheng/CGRA-Flow/actions/workflows/main.yml) 14 | [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) 15 | 16 | CGRA-Flow is an integrated framework for CGRA compilation, exploration, synthesis, and development. 17 | 18 | User Interface Snapshot/Demo 19 | -------------------------------------------------------------------------- 20 | ![20241028](https://github.com/user-attachments/assets/305fa79d-73b9-4512-ab85-0cecc6153986) 21 | 22 | A demo at repl.it (https://repl.it/@ChengTan/cgra-flow) shows some features of CGRA-Flow (the verilog generation and evaluation are not available due to *repl.it*'s limited support of python environment). To explore all the features, please setup CGRA-Flow locally or leverage the docker image. 23 | 24 | 25 | Docker 26 | -------------------------------------------------------- 27 | The docker image is available 28 | [here](https://hub.docker.com/r/cgra/cgra-flow/tags). 29 | 30 | > **Recommended machine configuration** 31 | > * CPU: >= 6 cores 32 | > * Memory: 25~30G 33 | > 34 | > **2x2 tiles run time**: 35 | > | clk_period (ps) | frequency (Hz) | time (hour) | 36 | > |-------|-------|-------| 37 | > | 1000 | 1G | ~40 | 38 | > | 10,000 | 100M | ~7 | 39 | > | 100,000 | 10M | ~7 | 40 | 41 | As CGRA-Flow requires GUI, a script is provided for setting up the display: 42 | ```sh 43 | docker pull cgra/cgra-flow:20241028 44 | 45 | # For Mac users: 46 | sh ./run_mac_docker.sh 47 | 48 | # Windows Docker customtkinter style UI (Please setup GUI (X-11) first) 49 | # In WSL, execute below script, it will enter container and config x11 DISPLAY automatically 50 | sh ./run_windows_docker.sh 51 | 52 | # Don't forget to activate the python virtual environment once you are in the container: 53 | source /WORK_REPO/venv/bin/activate 54 | ``` 55 | 56 | Otherwise, if you don't need the GUI, development can be performed in the container with the environment well set up: 57 | ```sh 58 | docker pull cgra/cgra-flow:20241028 59 | docker run -it cgra/cgra-flow:20241028 60 | source /WORK_REPO/venv/bin/activate 61 | ``` 62 | 63 | Execution 64 | -------------------------------------------------------- 65 | ```sh 66 | # Startup theme mode selector UI 67 | python launch.py 68 | ``` 69 | 70 | 71 | Mac user [debugging and troubleshooting steps doc](/doc/debug/DEBUGGING.md) 72 | -------------------------------------------------------- 73 | 74 | Installation 75 | -------------------------------------------------------- 76 | 77 | CGRA-Flow requires Python3.7. 78 | 79 | Refer to the build [scripts](https://github.com/tancheng/CGRA-Flow/blob/master/.github/workflows/main.yml) or look into specific repo for the manual installation if you don't want to use docker. 80 | 81 | 82 | Citation 83 | -------------------------------------------------------------------------- 84 | ``` 85 | @inproceedings{tan2020opencgra, 86 | title={OpenCGRA: An open-source unified framework for modeling, testing, and evaluating CGRAs}, 87 | author={Tan, Cheng and Xie, Chenhao and Li, Ang and Barker, Kevin J and Tumeo, Antonino}, 88 | booktitle={2020 IEEE 38th International Conference on Computer Design (ICCD)}, 89 | pages={381--388}, 90 | year={2020}, 91 | organization={IEEE} 92 | } 93 | ``` 94 | 95 | 96 | License 97 | -------------------------------------------------------------------------- 98 | 99 | CGRA-Flow is offered under the terms of the Open Source Initiative BSD 3-Clause License. More information about this license can be found here: 100 | 101 | - http://choosealicense.com/licenses/bsd-3-clause 102 | - http://opensource.org/licenses/BSD-3-Clause 103 | 104 | 105 | 106 | OpenAI GPT (coming soon) 107 | -------------------------------------------------------------------------- 108 | [Arch Wizard](https://chat.openai.com/g/g-fUWqOuKFe-arch-wizard). 109 | 110 | ![](https://github.com/tancheng/CGRA-Flow/assets/6756658/07db560a-65aa-4bed-8f0a-f0b3c07df893) 111 | -------------------------------------------------------------------------------- /doc/debug/DEBUGGING.md: -------------------------------------------------------------------------------- 1 | # Mac remote debugging instructions 2 | 3 | 4 | Developer shall be able to debug this repository's source code via VsCode installed in host machine. Below are some troubleshoot tips. 5 | 6 | 7 | ## debugging steps 8 | 9 | 10 | 1. Install [Docker extension](https://code.visualstudio.com/docs/devcontainers/containers) from microsoft in VsCode 11 | 12 | ![](docker_extension.png) 13 | 14 | 2. Start the docker container inside VsCode 15 | 16 | 3. Open the python file and start debugging via clicking Run/Debug button 17 | 18 | 19 | ## common issues 20 | 21 | 22 | #### 1. ```xauth command not found``` 23 | 24 | MacOS is missing XQuartz dependency 25 | 26 | ``` 27 | # install XQuartz 28 | brew install --cask xquartz 29 | # open XQuartz 30 | open -a XQuartz 31 | ``` 32 | 33 | #### 2. ```_tkinter.TclError: couldn't connect to display 10.0.0.204:xxx (Display not setup correctly)``` 34 | 35 | This can be happening for multiple reasons, including cross device display permission is not granted, display is not automatically being setup in MacOS. Try below steps: 36 | 37 | > Enable all access on host machine 38 | ``` 39 | xhost + 40 | ``` 41 | 42 | > Confirm display in host machine 43 | 44 | ``` 45 | echo $DISPLAY 46 | ``` 47 | 48 | > If display is empty or invalid, set a random display number in host machine 49 | 50 | ``` 51 | export DISPLAY=:0 52 | ``` 53 | 54 | > And modify the scripts to assign 0 as DISP_NUM (run_mac_docker.sh line 8) 55 | 56 | ``` 57 | DISP_NUM=0 58 | ``` 59 | 60 | 61 | #### 3. in VsCode terminal, an error of ```Display xx.xx.xx.xx is not found``` 62 | 63 | This is because VsCode's ssh terminal does not share the same enviorment variable with the docker container, can be resolved via manually setting the display ip and port number (same as the one from docker container) 64 | 65 | run ```export DISPLAY=xxx.xxx.xxx.xxx``` in the VsCode terminal 66 | 67 | 68 | #### 4. When setting break points and debug, an error of ```ImportError: can not import name 'Literal' from 'typing'``` 69 | 70 | 71 | This is because the container is running python 3.7 for the programme, however the VsCode ssh plugin is running its own python debug tool (debugpy) for python 3.8 enviorment. Can be resolved via force to install a lower version of debugpy. 72 | 73 | > install a lower version of debugpy 74 | 75 | ```pip install debugpy==1.6.6``` 76 | 77 | > force remove the vscode's debugpy 78 | 79 | ```rm -rf /root/.vscode-server/extensions/ms-python.debugpy-2025.0.1-linux-x64/bundled/libs/debugpy``` 80 | 81 | >system link the old debugpy to replace VsCode's 82 | 83 | ```ln -s /WORK_REPO/venv/lib/python3.7/site-packages/debugpy /root/.vscode-server/extensions/ms-python.debugpy-2025.0.1-linux-x64/bundled/libs/debugpy``` 84 | 85 | 86 | ## Happy debugging! 87 | 88 | ![](debugging.png) 89 | -------------------------------------------------------------------------------- /doc/debug/debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tancheng/CGRA-Flow/82fd6e7758b9e8d810f586f6c4d63ed57e60acd7/doc/debug/debugging.png -------------------------------------------------------------------------------- /doc/debug/docker_extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tancheng/CGRA-Flow/82fd6e7758b9e8d810f586f6c4d63ed57e60acd7/doc/debug/docker_extension.png -------------------------------------------------------------------------------- /doc/theme/classic_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tancheng/CGRA-Flow/82fd6e7758b9e8d810f586f6c4d63ed57e60acd7/doc/theme/classic_theme.png -------------------------------------------------------------------------------- /doc/theme/dark_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tancheng/CGRA-Flow/82fd6e7758b9e8d810f586f6c4d63ed57e60acd7/doc/theme/dark_theme.png -------------------------------------------------------------------------------- /doc/theme/light_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tancheng/CGRA-Flow/82fd6e7758b9e8d810f586f6c4d63ed57e60acd7/doc/theme/light_theme.png -------------------------------------------------------------------------------- /fir.cpp: -------------------------------------------------------------------------------- 1 | /* 32-tap FIR filter processing 1 point */ 2 | /* Modified to use arrays - SMP */ 3 | 4 | //#include "traps.h" 5 | 6 | #define NTAPS 32 7 | 8 | float input[NTAPS]; 9 | float output[NTAPS]; 10 | float coefficients[NTAPS] = {0.25, 1.50, 3.75, -2.25, 0.50, 0.75, -3.00, 1.25, 11 | 0.25, 1.50, 3.75, -2.25, 0.50, 0.75, -3.00, 1.25, 12 | 0.25, 1.50, 3.75, -2.25, 0.50, 0.75, -3.00, 1.25, 13 | 0.25, 1.50, 3.75, -2.25, 0.50, 0.75, -3.00, 1.25}; 14 | 15 | void kernel(float input[], float output[], float coefficient[]); 16 | 17 | int main() 18 | { 19 | 20 | // input_dsp (input, NTAPS, 0); 21 | 22 | kernel(input, output, coefficients); 23 | 24 | // output_dsp (input, NTAPS, 0); 25 | // output_dsp (coefficients, NTAPS, 0); 26 | // output_dsp (output, NTAPS, 0); 27 | return 0; 28 | } 29 | 30 | void kernel(float input[], float output[], float coefficient[]) 31 | /* input : input sample array */ 32 | /* output: output sample array */ 33 | /* coefficient: coefficient array */ 34 | { 35 | int i; 36 | float sum = 0.0; 37 | // #pragma clang loop unroll_count(4) vectorize_width(4) 38 | for (i = 0; i < NTAPS; ++i) { 39 | sum += input[i] * coefficient[i]; 40 | } 41 | output[0] = sum; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tkinter 3 | 4 | import customtkinter 5 | from PIL import Image 6 | 7 | customtkinter.set_appearance_mode("Dark") 8 | customtkinter.set_default_color_theme("dark-blue") 9 | 10 | master = customtkinter.CTk() 11 | script_dir = os.path.dirname(os.path.abspath(__file__)) 12 | image_path = os.path.join(script_dir, "doc/theme") 13 | theme_selector_dark_image = customtkinter.CTkImage(Image.open(os.path.join(image_path, "dark_theme.png")), size=(500, 410)) 14 | theme_selector_light_image = customtkinter.CTkImage(Image.open(os.path.join(image_path, "light_theme.png")), size=(500, 410)) 15 | theme_selector_classic_image = customtkinter.CTkImage(Image.open(os.path.join(image_path, "classic_theme.png")), size=(500, 410)) 16 | 17 | def launchUI(theme_radio_var): 18 | print(f'Get theme radio var: {theme_radio_var.get()}') 19 | if theme_radio_var.get() == 1: 20 | print('Activate light mode.') 21 | os.system("sh ./launchUI.bash light &") 22 | elif theme_radio_var.get() == 2: 23 | print('Activate classic mode.') 24 | os.system("sh ./launchUI.bash classic &") 25 | else: 26 | print('Activate dark mode.') 27 | os.system("sh ./launchUI.bash &") 28 | master.destroy() 29 | 30 | 31 | def switchUI(theme_radio_var, radiobutton_frame, launch_button, theme_selector_image_label): 32 | theme_selector_image_label.forget() 33 | if theme_radio_var.get() == 1: 34 | print('light mode.') 35 | customtkinter.set_appearance_mode("light") 36 | customtkinter.set_default_color_theme("dark-blue") 37 | radiobutton_frame.configure(fg_color='#D9D9D9') 38 | launch_button.configure(fg_color='#3A7EBF') 39 | theme_selector_image_label = customtkinter.CTkLabel(main_frame, text="", image=theme_selector_light_image, 40 | compound="bottom", anchor="center") 41 | theme_selector_image_label.grid(row=1, column=0) 42 | elif theme_radio_var.get() == 2: 43 | print('classic mode.') 44 | customtkinter.set_appearance_mode("light") 45 | # customtkinter.set_default_color_theme("green") 46 | radiobutton_frame.configure(fg_color='#F0F0F0') 47 | launch_button.configure(fg_color='#808080') 48 | theme_selector_image_label = customtkinter.CTkLabel(main_frame, text="", image=theme_selector_classic_image, 49 | compound="bottom", anchor="center") 50 | theme_selector_image_label.grid(row=1, column=0) 51 | else: 52 | print('dark mode.') 53 | customtkinter.set_appearance_mode("dark") 54 | customtkinter.set_default_color_theme("dark-blue") 55 | radiobutton_frame.configure(fg_color='#292929') 56 | launch_button.configure(fg_color='#1F538D') 57 | theme_selector_image_label = customtkinter.CTkLabel(main_frame, text="", image=theme_selector_dark_image, 58 | compound="bottom", anchor="center") 59 | theme_selector_image_label.grid(row=1, column=0) 60 | 61 | 62 | # configure window 63 | master.title("Startup theme selector") 64 | master.geometry(f"{500}x{500}") 65 | master.resizable(False, False) 66 | 67 | main_frame = customtkinter.CTkFrame(master) 68 | main_frame.grid(row=0, column=0, sticky="nsew") 69 | main_frame.grid_rowconfigure(0, weight=1) 70 | main_frame.grid_rowconfigure(1, weight=3) 71 | main_frame.grid_columnconfigure(0, weight=1) 72 | 73 | radiobutton_frame = customtkinter.CTkFrame(main_frame) 74 | radiobutton_frame.grid(row=0, column=0, sticky="nsew") 75 | 76 | radiobutton_frame.grid_rowconfigure(0, weight=1) 77 | radiobutton_frame.grid_rowconfigure(1, weight=2) 78 | radiobutton_frame.grid_columnconfigure(0, weight=1) 79 | radiobutton_frame.grid_columnconfigure(1, weight=1) 80 | radiobutton_frame.grid_columnconfigure(2, weight=1) 81 | 82 | theme_radio_var = tkinter.IntVar(value=0) 83 | 84 | main_frame_label = customtkinter.CTkLabel(radiobutton_frame, text='Please choose the theme mode: ', font=customtkinter.CTkFont(size=15, weight="bold")) 85 | main_frame_label.grid(row=0, column=0, columnspan=2, padx=(10, 5), pady=(10, 10), sticky="w") 86 | launch_button = customtkinter.CTkButton(master=radiobutton_frame, text='LaunchUI', command=lambda: launchUI(theme_radio_var)) 87 | launch_button.grid(row=0, column=2, pady=(10, 10), sticky="w") 88 | 89 | theme_selector_image_label = customtkinter.CTkLabel(main_frame, text="", image=theme_selector_dark_image, compound="bottom", anchor="center") 90 | theme_selector_image_label.grid(row=1, column=0) 91 | 92 | # create radiobutton frame 93 | light_theme_button = customtkinter.CTkRadioButton(master=radiobutton_frame, text='Light', variable=theme_radio_var, value=1, command=lambda: switchUI(theme_radio_var, radiobutton_frame, launch_button, theme_selector_image_label)) 94 | light_theme_button.grid(row=1, column=0, pady=(10, 10), padx=(10,0), sticky="w") 95 | dark_theme_button = customtkinter.CTkRadioButton(master=radiobutton_frame, text='Dark', variable=theme_radio_var, value=0, command=lambda: switchUI(theme_radio_var, radiobutton_frame, launch_button, theme_selector_image_label)) 96 | dark_theme_button.grid(row=1, column=1, pady=(10, 10), padx=(10,0), sticky="w") 97 | classic_theme_button = customtkinter.CTkRadioButton(master=radiobutton_frame, text='Classic', variable=theme_radio_var, value=2, command=lambda: switchUI(theme_radio_var, radiobutton_frame, launch_button, theme_selector_image_label)) 98 | classic_theme_button.grid(row=1, column=2, pady=(10, 10), padx=(10,0), sticky="w") 99 | 100 | master.mainloop() 101 | 102 | 103 | -------------------------------------------------------------------------------- /launchUI.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | input_theme=$1 4 | echo "Theme: $input_theme" 5 | 6 | cd build 7 | if [ "$input_theme" = "classic" ]; then 8 | echo "classic theme selected" 9 | #start dark theme 10 | python ../mode_classic.py 11 | elif [ "$input_theme" = "light" ]; then 12 | echo "light theme selected" 13 | #start light theme 14 | python ../mode_dark_light.py --theme light 15 | else 16 | echo "No theme selected, will start default theme (dark mode)" 17 | #start default theme (dark mode) 18 | python ../mode_dark_light.py 19 | fi 20 | 21 | -------------------------------------------------------------------------------- /mode_classic.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import time 4 | import threading 5 | import subprocess 6 | import json 7 | import math 8 | import tkinter 9 | import tkinter.messagebox 10 | from tkinter import ttk 11 | from tkinter import filedialog as fd 12 | from PIL import Image, ImageTk, ImageFile 13 | from functools import partial 14 | 15 | from VectorCGRA.cgra.translate.CGRATemplateRTL_test import * 16 | 17 | PORT_NORTH = 0 18 | PORT_SOUTH = 1 19 | PORT_WEST = 2 20 | PORT_EAST = 3 21 | PORT_NORTHWEST = 4 22 | PORT_NORTHEAST = 5 23 | PORT_SOUTHEAST = 6 24 | PORT_SOUTHWEST = 7 25 | PORT_DIRECTION_COUNTS = 8 26 | ROWS = 4 27 | COLS = 4 28 | INTERVAL = 10 29 | BORDER = 4 30 | MEM_WIDTH = 50 31 | CONFIG_MEM_SIZE = 8 32 | DATA_MEM_SIZE = 4 33 | HIGHLIGHT_THICKNESS = 1 34 | def window_size(window, width, height): 35 | window.geometry(f"{width}x{height}") 36 | master = tkinter.Tk() 37 | master.title("CGRA-Flow: An Integrated End-to-End Framework for CGRA Exploration, Compilation, and Development") 38 | 39 | 40 | fuTypeList = ["Phi", "Add", "Shift", "Ld", "Sel", "Cmp", "MAC", "St", "Ret", "Mul", "Logic", "Br"] 41 | 42 | xbarTypeList = ["W", "E", "N", "S", "NE", "NW", "SE", "SW"] 43 | 44 | xbarType2Port = {} 45 | xbarType2Port["W" ] = PORT_WEST 46 | xbarType2Port["E" ] = PORT_EAST 47 | xbarType2Port["N" ] = PORT_NORTH 48 | xbarType2Port["S" ] = PORT_SOUTH 49 | xbarType2Port["NE"] = PORT_NORTHEAST 50 | xbarType2Port["NW"] = PORT_NORTHWEST 51 | xbarType2Port["SE"] = PORT_SOUTHEAST 52 | xbarType2Port["SW"] = PORT_SOUTHWEST 53 | 54 | xbarPort2Type = {} 55 | xbarPort2Type[PORT_WEST ] = "W" 56 | xbarPort2Type[PORT_EAST ] = "E" 57 | xbarPort2Type[PORT_NORTH ] = "N" 58 | xbarPort2Type[PORT_SOUTH ] = "S" 59 | xbarPort2Type[PORT_NORTHEAST ] = "NE" 60 | xbarPort2Type[PORT_NORTHWEST ] = "NW" 61 | xbarPort2Type[PORT_SOUTHEAST ] = "SE" 62 | xbarPort2Type[PORT_SOUTHWEST ] = "SW" 63 | 64 | xbarPortOpposites = {} 65 | xbarPortOpposites[PORT_WEST ] = PORT_EAST 66 | xbarPortOpposites[PORT_EAST ] = PORT_WEST 67 | xbarPortOpposites[PORT_NORTH ] = PORT_SOUTH 68 | xbarPortOpposites[PORT_SOUTH ] = PORT_NORTH 69 | xbarPortOpposites[PORT_NORTHWEST] = PORT_SOUTHEAST 70 | xbarPortOpposites[PORT_NORTHEAST] = PORT_SOUTHWEST 71 | xbarPortOpposites[PORT_SOUTHWEST] = PORT_NORTHEAST 72 | xbarPortOpposites[PORT_SOUTHEAST] = PORT_NORTHWEST 73 | 74 | widgets = {} 75 | images = {} 76 | entireTileCheckVar = tkinter.IntVar() 77 | mappingAlgoCheckVar = tkinter.IntVar() 78 | fuCheckVars = {} 79 | fuCheckbuttons = {} 80 | xbarCheckVars = {} 81 | xbarCheckbuttons = {} 82 | kernelOptions = tkinter.StringVar() 83 | kernelOptions.set("Not selected yet") 84 | synthesisRunning = False 85 | 86 | class ParamTile: 87 | def __init__(s, ID, dimX, dimY, posX, posY, tileWidth, tileHeight): 88 | s.ID = ID 89 | s.disabled = False 90 | s.posX = posX 91 | s.posY = posY 92 | s.dimX = dimX 93 | s.dimY = dimY 94 | s.width = tileWidth 95 | s.height = tileHeight 96 | s.outLinks = {} 97 | s.inLinks = {} 98 | s.neverUsedOutPorts = set() 99 | s.fuDict = {} 100 | s.xbarDict = {} 101 | s.mapping = {} 102 | 103 | for i in range( PORT_DIRECTION_COUNTS ): 104 | s.neverUsedOutPorts.add(i) 105 | 106 | for xbarType in xbarTypeList: 107 | s.xbarDict[xbarType] = 0 108 | 109 | for fuType in fuTypeList: 110 | s.fuDict[fuType] = 1 111 | 112 | def hasFromMem(s): 113 | for link in s.inLinks.values(): 114 | if not link.disabled and link.isFromMem(): 115 | return True 116 | return False 117 | 118 | def hasToMem(s): 119 | for link in s.outLinks.values(): 120 | if not link.disabled and link.isToMem(): 121 | return True 122 | return False 123 | 124 | def getInvalidInPorts(s): 125 | invalidInPorts = set() 126 | for port in range(PORT_DIRECTION_COUNTS): 127 | if port not in s.inLinks: 128 | invalidInPorts.add(port) 129 | continue 130 | link = s.inLinks[port] 131 | if link.disabled or type(link.srcTile) == ParamSPM or link.srcTile.disabled: 132 | invalidInPorts.add(port) 133 | continue 134 | return invalidInPorts 135 | 136 | def isDefaultFus(s): 137 | for fuType in fuTypeList: 138 | if s.fuDict[fuType] != 1: 139 | return False 140 | return True 141 | 142 | def getAllValidFuTypes(s): 143 | fuTypes = set() 144 | for fuType in fuTypeList: 145 | if s.fuDict[fuType] == 1: 146 | if fuType == "Ld" or fuType == "St": 147 | fuTypes.add("Ld") 148 | else: 149 | fuTypes.add(fuType) 150 | return list(fuTypes) 151 | 152 | def getInvalidOutPorts(s): 153 | invalidOutPorts = set() 154 | for port in range(PORT_DIRECTION_COUNTS): 155 | if port not in s.outLinks: 156 | invalidOutPorts.add(port) 157 | continue 158 | link = s.outLinks[port] 159 | if link.disabled or type(link.dstTile) == ParamSPM or link.dstTile.disabled: 160 | invalidOutPorts.add(port) 161 | continue 162 | return invalidOutPorts 163 | 164 | def reset(s): 165 | s.disabled = False 166 | s.mapping = {} 167 | 168 | for i in range(PORT_DIRECTION_COUNTS): 169 | s.neverUsedOutPorts.add(i) 170 | 171 | for xbarType in xbarTypeList: 172 | s.xbarDict[xbarType] = 0 173 | 174 | for fuType in fuTypeList: 175 | s.fuDict[fuType] = 1 176 | 177 | def resetOutLink(s, portType, link): 178 | s.outLinks[portType] = link 179 | s.xbarDict[xbarPort2Type[portType]] = 1 180 | if portType in s.neverUsedOutPorts: 181 | s.neverUsedOutPorts.remove(portType) 182 | 183 | def resetInLink(s, portType, link): 184 | s.inLinks[portType] = link 185 | 186 | def setOutLink(s, portType, link): 187 | s.outLinks[portType] = link 188 | 189 | def setInLink(s, portType, link): 190 | s.resetInLink(portType, link) 191 | 192 | # position X/Y for drawing the tile 193 | def getPosXY(s, baseX=0, baseY=0): 194 | return (baseX+s.posX, baseY+s.posY) 195 | 196 | # position X/Y for connecting routing ports 197 | def getPosXYOnPort(s, portType, baseX=0, baseY=0): 198 | if portType == PORT_NORTH: 199 | return s.getNorth(baseX, baseY) 200 | elif portType == PORT_SOUTH: 201 | return s.getSouth(baseX, baseY) 202 | elif portType == PORT_WEST: 203 | return s.getWest(baseX, baseY) 204 | elif portType == PORT_EAST: 205 | return s.getEast(baseX, baseY) 206 | elif portType == PORT_NORTHEAST: 207 | return s.getNorthEast(baseX, baseY) 208 | elif portType == PORT_NORTHWEST: 209 | return s.getNorthWest(baseX, baseY) 210 | elif portType == PORT_SOUTHEAST: 211 | return s.getSouthEast(baseX, baseY) 212 | else: 213 | return s.getSouthWest(baseX, baseY) 214 | 215 | def getNorthWest(s, baseX=0, baseY=0): 216 | return (baseX+s.posX, baseY+s.posY) 217 | 218 | def getNorthEast(s, baseX=0, baseY=0): 219 | return (baseX+s.posX+s.width, baseY+s.posY) 220 | 221 | def getSouthWest(s, baseX=0, baseY=0): 222 | return (baseX+s.posX, baseY+s.posY+s.height) 223 | 224 | def getSouthEast(s, baseX=0, baseY=0): 225 | return (baseX+s.posX+s.width, baseY+s.posY+s.height) 226 | 227 | def getWest(s, baseX=0, baseY=0): 228 | return (baseX+s.posX, baseY+s.posY+s.height//2) 229 | 230 | def getEast(s, baseX=0, baseY=0): 231 | return (baseX+s.posX+s.width, baseY+s.posY+s.height//2) 232 | 233 | def getNorth(s, baseX=0, baseY=0): 234 | return (baseX+s.posX+s.width//2, baseY+s.posY) 235 | 236 | def getSouth(s, baseX=0, baseY=0): 237 | return (baseX+s.posX+s.width//2, baseY+s.posY+s.height) 238 | 239 | def getDimXY(s): 240 | return s.dimX, s.dimY 241 | 242 | def getIndex(s, tileList): 243 | if s.disabled: 244 | return -1 245 | index = 0 246 | for tile in tileList: 247 | if tile.dimY < s.dimY and not tile.disabled: 248 | index += 1 249 | elif tile.dimY == s.dimY and tile.dimX < s.dimX and not tile.disabled: 250 | index += 1 251 | return index 252 | class ParamSPM: 253 | def __init__(s, posX, numOfReadPorts, numOfWritePorts): 254 | s.posX = posX 255 | s.ID = -1 256 | s.numOfReadPorts = numOfReadPorts 257 | s.numOfWritePorts = numOfWritePorts 258 | s.disabled = False 259 | s.inLinks = {} 260 | s.outLinks = {} 261 | 262 | def getNumOfValidReadPorts(s): 263 | ports = 0 264 | for physicalPort in range(s.numOfReadPorts): 265 | if physicalPort not in s.inLinks: 266 | continue 267 | if s.inLinks[physicalPort].disabled: 268 | continue 269 | ports += 1 270 | return ports 271 | 272 | def getNumOfValidWritePorts(s): 273 | ports = 0 274 | for physicalPort in range(s.numOfWritePorts): 275 | if physicalPort not in s.outLinks: 276 | continue 277 | if s.outLinks[physicalPort].disabled: 278 | continue 279 | ports += 1 280 | return ports 281 | 282 | def getValidReadPort(s, logicalPort): 283 | port = 0 284 | for physicalPort in range(logicalPort+1): 285 | if physicalPort not in s.inLinks: 286 | continue 287 | if s.inLinks[physicalPort].disabled: 288 | continue 289 | if physicalPort == logicalPort: 290 | return port 291 | port += 1 292 | return -1 293 | 294 | def getValidWritePort(s, logicalPort): 295 | port = 0 296 | for physicalPort in range(logicalPort+1): 297 | if physicalPort not in s.outLinks: 298 | continue 299 | if s.outLinks[physicalPort].disabled: 300 | continue 301 | if physicalPort == logicalPort: 302 | return port 303 | port += 1 304 | return -1 305 | 306 | def getPosX(s, baseX): 307 | return s.posX + baseX 308 | 309 | def setInLink(s, portType, link): 310 | s.inLinks[portType] = link 311 | 312 | def resetInLink(s, portType, link): 313 | s.setInLink(portType, link) 314 | 315 | def setOutLink(s, portType, link): 316 | s.outLinks[portType] = link 317 | 318 | def resetOutLink(s, portType, link): 319 | s.setOutLink(portType, link) 320 | 321 | 322 | class ParamLink: 323 | def __init__(s, srcTile, dstTile, srcPort, dstPort): 324 | s.srcTile = srcTile 325 | s.dstTile = dstTile 326 | s.srcPort = srcPort 327 | s.dstPort = dstPort 328 | s.disabled = False 329 | s.srcTile.resetOutLink(s.srcPort, s) 330 | s.dstTile.resetInLink(s.dstPort, s) 331 | s.mapping = set() 332 | 333 | def getMemReadPort(s): 334 | if s.isFromMem(): 335 | spm = s.srcTile 336 | return spm.getValidReadPort(s.srcPort) 337 | return -1 338 | 339 | def getMemWritePort(s): 340 | if s.isToMem(): 341 | spm = s.dstTile 342 | return spm.getValidWritePort(s.dstPort) 343 | return -1 344 | 345 | def isToMem(s): 346 | return type(s.dstTile) == ParamSPM 347 | 348 | def isFromMem(s): 349 | return type(s.srcTile) == ParamSPM 350 | 351 | def getSrcXY(s, baseX=0, baseY=0): 352 | if type(s.srcTile) != ParamSPM: 353 | return s.srcTile.getPosXYOnPort(s.srcPort, baseX, baseY) 354 | else: 355 | dstPosX, dstPosY = s.dstTile.getPosXYOnPort(s.dstPort, baseX, baseY) 356 | spmPosX = s.srcTile.getPosX(baseX) 357 | return spmPosX, dstPosY 358 | 359 | def getDstXY(s, baseX=0, baseY=0): 360 | if type(s.dstTile) != ParamSPM: 361 | return s.dstTile.getPosXYOnPort(s.dstPort, baseX, baseY) 362 | else: 363 | srcPosX, srcPosY = s.srcTile.getPosXYOnPort(s.srcPort, baseX, baseY) 364 | spmPosX = s.dstTile.getPosX(baseX) 365 | return spmPosX, srcPosY 366 | 367 | class ParamCGRA: 368 | def __init__(s, rows, columns, configMemSize=CONFIG_MEM_SIZE, dataMemSize=DATA_MEM_SIZE): 369 | s.rows = rows 370 | s.columns = columns 371 | s.configMemSize = configMemSize 372 | s.dataMemSize = dataMemSize 373 | s.tiles = [] 374 | s.templateLinks = [] 375 | s.updatedLinks = [] 376 | s.targetTileID = 0 377 | s.dataSPM = None 378 | s.targetAppName = " Not selected yet" 379 | s.compilationDone = False 380 | s.verilogDone = False 381 | s.targetKernels = [] 382 | s.targetKernelName = None 383 | s.DFGNodeCount = -1 384 | s.resMII = -1 385 | s.recMII = -1 386 | 387 | # return error message if the model is not valid 388 | def getErrorMessage(s): 389 | # at least one tile can perform mem acess 390 | memExist = False 391 | # at least one tile exists 392 | tileExist = False 393 | for tile in s.tiles: 394 | if not tile.disabled: 395 | tileExist = True 396 | # a tile contains at least one FU 397 | fuExist = False 398 | # the tile connect to mem need to able to access mem 399 | if tile.hasToMem() or tile.hasFromMem(): 400 | # for now, the compiler doesn't support seperate read or write, both of them need to locate in the same tile 401 | if tile.hasToMem() and tile.hasFromMem() and tile.fuDict["Ld"] == 1 and tile.fuDict["St"] == 1: 402 | memExist = True 403 | else: 404 | return "Tile " + str(tile.ID) + " needs to contain the Load/Store functional units." 405 | 406 | for fuType in fuTypeList: 407 | if tile.fuDict[fuType] == 1: 408 | fuExist = True 409 | if not fuExist: 410 | return "At least one functional unit needs to exist in tile " + str(tile.ID) + "." 411 | 412 | if not tileExist: 413 | return "At least one tile needs to exist in the CGRA." 414 | 415 | if not memExist: 416 | return "At least one tile including a Load/Store functional unit needs to directly connect to the data SPM." 417 | 418 | return "" 419 | 420 | def getValidTiles(s): 421 | validTiles = [] 422 | for tile in s.tiles: 423 | if not tile.disabled: 424 | validTiles.append(tile) 425 | return validTiles 426 | 427 | def getValidLinks(s): 428 | validLinks = [] 429 | for link in s.updatedLinks: 430 | if not link.disabled and not link.srcTile.disabled and not link.dstTile.disabled: 431 | validLinks.append(link) 432 | return validLinks 433 | 434 | def updateFuXbarPannel(s): 435 | targetTile = s.getTileOfID(s.targetTileID) 436 | for fuType in fuTypeList: 437 | if fuType in fuCheckVars: 438 | fuCheckVars[fuType].set(targetTile.fuDict[fuType]) 439 | 440 | for xbarType in xbarTypeList: 441 | if xbarType in xbarCheckVars: 442 | xbarCheckVars[xbarType].set(targetTile.xbarDict[xbarType]) 443 | 444 | def initDataSPM(s, dataSPM): 445 | s.dataSPM = dataSPM 446 | 447 | def updateMemSize(s, configMemSize, dataMemSize): 448 | s.configMemSize = configMemSize 449 | s.dataMemSize = dataMemSize 450 | 451 | def initTiles(s, tiles): 452 | for r in range(s.rows): 453 | for c in range(s.columns): 454 | s.tiles.append(tiles[r][c]) 455 | 456 | def addTile(s, tile): 457 | s.tiles.append(tile) 458 | 459 | def initTemplateLinks(s, links): 460 | numOfLinks = s.rows*s.columns*2 + (s.rows-1)*s.columns*2 + (s.rows-1)*(s.columns-1)*2*2 461 | 462 | for link in links: 463 | s.templateLinks.append(link) 464 | 465 | def resetTiles(s): 466 | 467 | for tile in s.tiles: 468 | tile.reset() 469 | 470 | for fuType in fuTypeList: 471 | fuCheckVars[fuType].set(tile.fuDict[fuType]) 472 | fuCheckbuttons[fuType].configure(state="normal") 473 | 474 | for xbarType in xbarTypeList: 475 | xbarCheckVars[xbarType].set(tile.xbarDict[xbarType]) 476 | xbarCheckbuttons[xbarType].configure(state="normal") 477 | 478 | 479 | def enableAllTemplateLinks(s): 480 | for link in s.templateLinks: 481 | link.disabled = False 482 | 483 | def resetLinks(s): 484 | for link in s.templateLinks: 485 | link.disabled = False 486 | link.srcTile.resetOutLink(link.srcPort, link) 487 | link.dstTile.resetInLink(link.dstPort, link) 488 | link.mapping = set() 489 | 490 | s.updatedLinks = s.templateLinks[:] 491 | 492 | for portType in range( PORT_DIRECTION_COUNTS ): 493 | if portType in s.getTileOfID(s.targetTileID).neverUsedOutPorts: 494 | xbarCheckbuttons[xbarPort2Type[portType]].configure(state="disabled") 495 | 496 | def addTemplateLink(s, link): 497 | s.templateLinks.append(link) 498 | 499 | def addUpdatedLink(s, link): 500 | s.updatedLinks.append(link) 501 | 502 | def removeUpdatedLink(s, link): 503 | s.updatedLinks.remove(link) 504 | # src = link.srcTile 505 | # src.xbarDict[link.srcPort] = 0 506 | 507 | def updateFuCheckbutton(s, fuType, value): 508 | tile = s.getTileOfID(s.targetTileID) 509 | tile.fuDict[fuType] = value 510 | 511 | def updateXbarCheckbutton(s, xbarType, value): 512 | tile = s.getTileOfID(s.targetTileID) 513 | tile.xbarDict[xbarType] = value 514 | port = xbarType2Port[xbarType] 515 | if port in tile.outLinks: 516 | tile.outLinks[port].disabled = True if value == 0 else False 517 | 518 | def getTileOfID(s, ID): 519 | for tile in s.tiles: 520 | if tile.ID == ID: 521 | return tile 522 | return None 523 | 524 | def getTileOfDim(s, dimX, dimY): 525 | for tile in s.tiles: 526 | if tile.dimX == dimX and tile.dimY == dimY: 527 | return tile 528 | return None 529 | 530 | 531 | # tiles could be disabled due to the disabled links 532 | def updateTiles(s): 533 | unreachableTiles = set() 534 | for tile in s.tiles: 535 | unreachableTiles.add(tile) 536 | 537 | for link in s.updatedLinks: 538 | if link.disabled == False and type(link.dstTile) == ParamTile: 539 | if link.dstTile in unreachableTiles: 540 | unreachableTiles.remove(link.dstTile) 541 | if len(unreachableTiles) == 0: 542 | break 543 | 544 | for tile in unreachableTiles: 545 | tile.disabled = True 546 | 547 | def getUpdatedLink(s, srcTile, dstTile): 548 | for link in s.updatedLinks: 549 | if link.srcTile == srcTile and link.dstTile == dstTile: 550 | return link 551 | return None 552 | 553 | # TODO: also need to consider adding back after removing... 554 | def updateLinks(s): 555 | 556 | needRemoveLinks = set() 557 | for link in s.updatedLinks: 558 | if link.disabled: 559 | needRemoveLinks.add((link.srcTile, link.dstTile)) 560 | 561 | for link in s.templateLinks: 562 | link.srcTile.setOutLink(link.srcPort, link) 563 | link.dstTile.setInLink(link.dstPort, link) 564 | s.updatedLinks = s.templateLinks[:] 565 | 566 | for tile in s.tiles: 567 | if tile.disabled: 568 | for portType in tile.outLinks: 569 | outLink = tile.outLinks[portType] 570 | dstNeiTile = outLink.dstTile 571 | oppositePort = xbarPortOpposites[portType] 572 | if oppositePort in tile.inLinks: 573 | inLink = tile.inLinks[oppositePort] 574 | srcNeiTile = inLink.srcTile 575 | 576 | # some links can be fused as single one due to disabled tiles 577 | if not inLink.disabled and not outLink.disabled and inLink in s.updatedLinks and outLink in s.updatedLinks: 578 | updatedLink = ParamLink(srcNeiTile, dstNeiTile, inLink.srcPort, outLink.dstPort) 579 | s.addUpdatedLink(updatedLink) 580 | s.removeUpdatedLink(inLink) 581 | s.removeUpdatedLink(outLink) 582 | # links that are disabled need to be removed 583 | if inLink.disabled and inLink in s.updatedLinks: 584 | s.removeUpdatedLink(inLink) 585 | if outLink.disabled and outLink in s.updatedLinks: 586 | s.removeUpdatedLink(outLink) 587 | 588 | else: 589 | if outLink in s.updatedLinks: 590 | s.removeUpdatedLink(outLink) 591 | 592 | for portType in tile.outLinks: 593 | outLink = tile.outLinks[portType] 594 | if outLink in s.updatedLinks: 595 | s.removeUpdatedLink(outLink) 596 | 597 | 598 | for portType in tile.inLinks: 599 | inLink = tile.inLinks[portType] 600 | if inLink in s.updatedLinks: 601 | s.removeUpdatedLink(inLink) 602 | 603 | for link in s.updatedLinks: 604 | if (link.srcTile, link.dstTile) in needRemoveLinks: 605 | link.disabled = True 606 | if type(link.srcTile) == ParamTile: 607 | link.srcTile.xbarDict[xbarPort2Type[link.srcPort]] = 0 608 | 609 | 610 | 611 | class ToolTip(object): 612 | 613 | def __init__(self, widget): 614 | self.widget = widget 615 | self.tipwindow = None 616 | self.id = None 617 | self.x = self.y = 0 618 | 619 | def showtip(self, text): 620 | "Display text in tooltip window" 621 | self.text = text 622 | if self.tipwindow or not self.text: 623 | return 624 | x, y, cx, cy = self.widget.bbox("insert") 625 | x = x + self.widget.winfo_rootx() + 57 626 | y = y + cy + self.widget.winfo_rooty() +27 627 | self.tipwindow = tw = tkinter.Toplevel(self.widget) 628 | tw.wm_overrideredirect(1) 629 | tw.wm_geometry("+%d+%d" % (x, y)) 630 | label = tkinter.Label(tw, text=self.text, justify=tkinter.LEFT, 631 | background="#ffffe0", relief=tkinter.SOLID, borderwidth=1, 632 | font=("tahoma", "8", "normal")) 633 | label.pack(ipadx=1) 634 | 635 | def hidetip(self): 636 | tw = self.tipwindow 637 | self.tipwindow = None 638 | if tw: 639 | tw.destroy() 640 | 641 | def CreateToolTip(widget, text): 642 | toolTip = ToolTip(widget) 643 | def enter(event): 644 | toolTip.showtip(text) 645 | def leave(event): 646 | toolTip.hidetip() 647 | widget.bind('', enter) 648 | widget.bind('', leave) 649 | 650 | 651 | paramCGRA = ParamCGRA(ROWS, COLS, CONFIG_MEM_SIZE, DATA_MEM_SIZE) 652 | 653 | 654 | 655 | def clickTile(ID): 656 | widgets["fuConfigPannel"].config(text='Tile '+str(ID)+' functional units') 657 | widgets["xbarConfigPannel"].config(text='Tile '+str(ID)+' crossbar outgoing links') 658 | # After clicking the tile, the pannel will fill all directions 659 | widgets["xbarConfigPannel"].grid(columnspan=4, row=7, column=0, rowspan=2, sticky="nsew") 660 | widgets["entireTileCheckbutton"].config(text='Disable entire Tile '+str(ID), state="normal") 661 | widgets["spmConfigPannel"].grid_forget() 662 | paramCGRA.targetTileID = ID 663 | 664 | disabled = paramCGRA.getTileOfID(ID).disabled 665 | for fuType in fuTypeList: 666 | fuCheckVars[fuType].set(paramCGRA.tiles[ID].fuDict[fuType]) 667 | fuCheckbuttons[fuType].configure(state="disabled" if disabled else "normal") 668 | 669 | for xbarType in xbarTypeList: 670 | xbarCheckVars[xbarType].set(paramCGRA.tiles[ID].xbarDict[xbarType]) 671 | xbarCheckbuttons[xbarType].configure(state="disabled" if disabled or xbarType2Port[xbarType] in paramCGRA.tiles[ID].neverUsedOutPorts else "normal") 672 | 673 | entireTileCheckVar.set(1 if paramCGRA.getTileOfID(ID).disabled else 0) 674 | 675 | def clickSPM(): 676 | widgets["fuConfigPannel"].config(text='Tile '+str(paramCGRA.targetTileID)+' functional units') 677 | 678 | for fuType in fuTypeList: 679 | fuCheckVars[fuType].set(paramCGRA.tiles[paramCGRA.targetTileID].fuDict[fuType]) 680 | fuCheckbuttons[fuType].configure(state="disabled") 681 | 682 | widgets["xbarConfigPannel"].grid_forget() 683 | 684 | spmConfigPannel = widgets["spmConfigPannel"] 685 | spmConfigPannel.config(text='DataSPM outgoing links') 686 | # After clicking the SPM, the pannel will fill all directions 687 | spmConfigPannel.grid(row=7, column=0, rowspan=2, columnspan=4, sticky="nsew") 688 | 689 | spmEnabledListbox = widgets["spmEnabledListbox"] 690 | spmDisabledListbox = widgets["spmDisabledListbox"] 691 | 692 | widgets["entireTileCheckbutton"].config(text='Disable entire Tile '+str(paramCGRA.targetTileID), state="disabled") 693 | 694 | 695 | def clickSPMPortDisable(): 696 | spmEnabledListbox = widgets["spmEnabledListbox"] 697 | portIndex = spmEnabledListbox.curselection() 698 | if portIndex: 699 | port = spmEnabledListbox.get(portIndex) 700 | spmEnabledListbox.delete(portIndex) 701 | widgets["spmDisabledListbox"].insert(0, port) 702 | 703 | link = paramCGRA.dataSPM.outLinks[port] 704 | link.disabled = True 705 | 706 | def clickSPMPortEnable(): 707 | spmDisabledListbox = widgets["spmDisabledListbox"] 708 | portIndex = spmDisabledListbox.curselection() 709 | if portIndex: 710 | port = spmDisabledListbox.get(portIndex) 711 | spmDisabledListbox.delete(portIndex) 712 | 713 | widgets["spmEnabledListbox"].insert(0, port) 714 | 715 | link = paramCGRA.dataSPM.outLinks[port] 716 | link.disabled = False 717 | 718 | 719 | def clickEntireTileCheckbutton(): 720 | 721 | if entireTileCheckVar.get() == 1: 722 | 723 | for fuType in fuTypeList: 724 | fuCheckVars[fuType].set(0) 725 | tile = paramCGRA.getTileOfID(paramCGRA.targetTileID) 726 | tile.fuDict[fuType] = 0 727 | # clickFuCheckbutton(fuType) 728 | fuCheckbuttons[fuType].configure(state="disabled") 729 | 730 | paramCGRA.getTileOfID(paramCGRA.targetTileID).disabled = True 731 | else: 732 | for fuType in fuTypeList: 733 | fuCheckVars[fuType].set(0) 734 | tile = paramCGRA.getTileOfID(paramCGRA.targetTileID) 735 | tile.fuDict[fuType] = 0 736 | # clickFuCheckbutton(fuType) 737 | fuCheckbuttons[fuType].configure(state="normal") 738 | 739 | # paramCGRA.getTileOfID(paramCGRA.targetTileID).disabled = False 740 | 741 | 742 | def clickFuCheckbutton(fuType): 743 | if fuType == "Ld": 744 | fuCheckVars["St"].set(fuCheckVars["Ld"].get()) 745 | paramCGRA.updateFuCheckbutton("St", fuCheckVars["St"].get()) 746 | elif fuType == "St": 747 | fuCheckVars["Ld"].set(fuCheckVars["St"].get()) 748 | paramCGRA.updateFuCheckbutton("Ld", fuCheckVars["Ld"].get()) 749 | paramCGRA.updateFuCheckbutton(fuType, fuCheckVars[fuType].get()) 750 | 751 | def clickXbarCheckbutton(xbarType): 752 | paramCGRA.updateXbarCheckbutton(xbarType, xbarCheckVars[xbarType].get()) 753 | 754 | 755 | def clickUpdate(root): 756 | rows = int(widgets["rowsEntry"].get()) 757 | columns = int(widgets["columnsEntry"].get()) 758 | configMemSize = int(widgets["configMemEntry"].get()) 759 | dataMemSize = int(widgets["dataMemEntry"].get()) 760 | 761 | global paramCGRA 762 | oldCGRA = paramCGRA 763 | 764 | if paramCGRA.rows != rows or paramCGRA.columns != columns: 765 | paramCGRA = ParamCGRA(rows, columns) 766 | 767 | create_cgra_pannel(root, rows, columns) 768 | 769 | # kernel related information and be kept to avoid redundant compilation 770 | paramCGRA.updateMemSize(configMemSize, dataMemSize) 771 | paramCGRA.updateTiles() 772 | paramCGRA.updateLinks() 773 | paramCGRA.targetAppName = oldCGRA.targetAppName 774 | paramCGRA.compilationDone = oldCGRA.compilationDone 775 | paramCGRA.targetKernels = oldCGRA.targetKernels 776 | paramCGRA.targetKernelName = oldCGRA.targetKernelName 777 | paramCGRA.DFGNodeCount = oldCGRA.DFGNodeCount 778 | paramCGRA.recMII = oldCGRA.recMII 779 | paramCGRA.verilogDone = False 780 | 781 | widgets["verilogText"].delete("1.0", tkinter.END) 782 | widgets["resMIIEntry"].delete(0, tkinter.END) 783 | if len(paramCGRA.getValidTiles()) > 0 and paramCGRA.DFGNodeCount > 0: 784 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount+0.0)/len(paramCGRA.getValidTiles())) // 1 785 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 786 | else: 787 | widgets["resMIIEntry"].insert(0, 0) 788 | 789 | 790 | def clickReset(root): 791 | rows = int(widgets["rowsEntry"].get()) 792 | columns = int(widgets["columnsEntry"].get()) 793 | configMemSize = int(widgets["configMemEntry"].get()) 794 | dataMemSize = int(widgets["dataMemEntry"].get()) 795 | 796 | global paramCGRA 797 | oldCGRA = paramCGRA 798 | 799 | if paramCGRA.rows != rows or paramCGRA.columns != columns: 800 | paramCGRA = ParamCGRA(rows, columns) 801 | 802 | paramCGRA.updateMemSize(configMemSize, dataMemSize) 803 | paramCGRA.resetTiles() 804 | paramCGRA.enableAllTemplateLinks() 805 | paramCGRA.resetLinks() 806 | 807 | create_cgra_pannel(root, rows, columns) 808 | 809 | for _ in range(paramCGRA.rows): 810 | widgets["spmEnabledListbox"].delete(0) 811 | widgets["spmDisabledListbox"].delete(0) 812 | 813 | for port in paramCGRA.dataSPM.outLinks: 814 | if not paramCGRA.dataSPM.outLinks[port].disabled: 815 | widgets["spmEnabledListbox"].insert(0, port) 816 | else: 817 | widgets["spmDisabledListbox"].insert(0, port) 818 | 819 | # kernel related information and be kept to avoid redundant compilation 820 | paramCGRA.targetAppName = oldCGRA.targetAppName 821 | paramCGRA.compilationDone = oldCGRA.compilationDone 822 | paramCGRA.targetKernels = oldCGRA.targetKernels 823 | paramCGRA.targetKernelName = oldCGRA.targetKernelName 824 | paramCGRA.DFGNodeCount = oldCGRA.DFGNodeCount 825 | paramCGRA.recMII = oldCGRA.recMII 826 | 827 | widgets["verilogText"].delete(0, tkinter.END) 828 | widgets["resMIIEntry"].delete(0, tkinter.END) 829 | if len(paramCGRA.getValidTiles()) > 0 and paramCGRA.DFGNodeCount > 0: 830 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount+0.0)/len(paramCGRA.getValidTiles())) // 1 831 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 832 | else: 833 | widgets["resMIIEntry"].insert(0, 0) 834 | 835 | 836 | def clickTest(): 837 | # need to provide the paths for lib.so and kernel.bc 838 | os.system("mkdir test") 839 | # os.system("cd test") 840 | os.chdir("test") 841 | 842 | widgets["testShow"].configure(text="0%", fg="red") 843 | master.update_idletasks() 844 | 845 | # os.system("pytest ../../VectorCGRA") 846 | testProc = subprocess.Popen(["pytest ../../VectorCGRA", '-u'], stdout=subprocess.PIPE, shell=True, bufsize=1) 847 | failed = 0 848 | total = 0 849 | with testProc.stdout: 850 | for line in iter(testProc.stdout.readline, b''): 851 | outputLine = line.decode("ISO-8859-1") 852 | print(outputLine) 853 | if "%]" in outputLine: 854 | value = int(outputLine.split("[")[1].split("%]")[0]) 855 | widgets["testProgress"].configure(value=value) 856 | widgets["testShow"].configure(text=str(value)+"%", fg="red") 857 | master.update_idletasks() 858 | total += 1 859 | if ".py F" in outputLine: 860 | failed += 1 861 | 862 | widgets["testShow"].configure(text="PASSED" if failed==0 else str(total-failed)+"/"+str(total), fg="green") 863 | # (out, err) = testProc.communicate() 864 | # print("check test output:", out) 865 | 866 | os.chdir("..") 867 | 868 | 869 | def clickGenerateVerilog(): 870 | 871 | message = paramCGRA.getErrorMessage() 872 | if message != "": 873 | tkinter.messagebox.showerror(title="CGRA Model Checking", message=message) 874 | return 875 | 876 | os.system("mkdir verilog") 877 | os.chdir("verilog") 878 | 879 | # pymtl function that is used to generate synthesizable verilog 880 | test_cgra_universal(paramCGRA) 881 | 882 | widgets["verilogText"].delete("1.0", tkinter.END) 883 | found = False 884 | print(os.listdir("./")) 885 | for fileName in os.listdir("./"): 886 | if "__" in fileName and ".v" in fileName: 887 | print("Found the file: ", fileName) 888 | f = open(fileName, "r") 889 | widgets["verilogText"].insert("1.0", f.read()) 890 | found = True 891 | break 892 | 893 | paramCGRA.verilogDone = True 894 | if not found: 895 | paramCGRA.verilogDone = False 896 | widgets["verilogText"].insert(tkinter.END, "Error exists during Verilog generation") 897 | 898 | os.system("mv CGRATemplateRTL__*.v design.v") 899 | # os.system("rename s/\.v/\.log/g *") 900 | 901 | os.chdir("..") 902 | 903 | 904 | def setReportProgress(value): 905 | widgets["reportProgress"].configure(value=value) 906 | 907 | def countSynthesisTime(): 908 | global synthesisRunning 909 | timeCost = 0.0 910 | while synthesisRunning: 911 | time.sleep(0.1) 912 | widgets["synthesisTimeEntry"].delete(0, tkinter.END) 913 | widgets["synthesisTimeEntry"].insert(0, round(timeCost, 1)) 914 | timeCost += 0.1 915 | 916 | def runYosys(): 917 | global synthesisRunning 918 | os.system("make 3") 919 | 920 | statsFile = open("3-open-yosys-synthesis/stats.txt", 'r') 921 | statsLines = statsFile.readlines() 922 | 923 | tileArea = 0.0 924 | for line in statsLines: 925 | if "Chip area for module " in line: 926 | tileArea = round(float(line.split(": ")[1]) / 1000000, 2) 927 | break 928 | 929 | statsFile.close() 930 | 931 | widgets["reportTileAreaData"].delete(0, tkinter.END) 932 | widgets["reportTileAreaData"].insert(0, tileArea) 933 | 934 | widgets["reportTilePowerData"].delete(0, tkinter.END) 935 | widgets["reportTilePowerData"].insert(0, "-") 936 | 937 | widgets["reportProgress"].configure(value=100) 938 | 939 | os.chdir("../../../build") 940 | 941 | synthesisRunning = False 942 | 943 | 944 | def clickSynthesize(): 945 | 946 | global paramCGRA 947 | global synthesisRunning 948 | 949 | if synthesisRunning: 950 | return 951 | 952 | if not paramCGRA.verilogDone: 953 | tkinter.messagebox.showerror(title="Sythesis", message="The verilog generation needs to be done first.") 954 | return 955 | 956 | synthesisRunning = True 957 | synthesisTimerRun = threading.Thread(target=countSynthesisTime) 958 | synthesisTimerRun.start() 959 | 960 | os.system("mkdir verilog") 961 | os.chdir("verilog") 962 | 963 | # Cacti SPM power/area estimation: 964 | sizePattern = "[SPM_SIZE]" 965 | readPortPattern = "[READ_PORT_COUNT]" 966 | writePortPattern = "[WRITE_PORT_COUNT]" 967 | 968 | updatedSizePattern = str(paramCGRA.dataMemSize * 1024) 969 | updatedReadPortPattern = str(paramCGRA.dataSPM.getNumOfValidReadPorts()) 970 | updatedWritePortPattern = str(paramCGRA.dataSPM.getNumOfValidWritePorts()) 971 | 972 | with open(r'../../tools/cacti/spm_template.cfg', 'r') as file: 973 | data = file.read() 974 | 975 | data = data.replace(sizePattern, updatedSizePattern) 976 | data = data.replace(readPortPattern, updatedReadPortPattern) 977 | data = data.replace(writePortPattern, updatedWritePortPattern) 978 | 979 | with open(r'../../tools/cacti/spm_temp.cfg', 'w') as file: 980 | file.write(data) 981 | 982 | os.chdir("../../tools/cacti") 983 | 984 | cactiCommand = "./cacti -infile spm_temp.cfg" 985 | cactiProc = subprocess.Popen([cactiCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, bufsize=1) 986 | (out, err) = cactiProc.communicate() 987 | success = False 988 | line = out.decode("ISO-8859-1") 989 | 990 | if "Power Components:" in line: 991 | success = True 992 | strSPMPower = line.split("Data array: Total dynamic read energy/access (nJ): ")[1].split("\n")[0] 993 | strSPMTiming = line.split("Data side (with Output driver) (ns): ")[1].split("\n")[0] 994 | spmPower = float(strSPMPower) / float(strSPMTiming) * 1000 995 | 996 | widgets["reportSPMPowerData"].delete(0, tkinter.END) 997 | widgets["reportSPMPowerData"].insert(0, str(spmPower)) 998 | 999 | strSPMArea = line.split("Data array: Area (mm2): ")[1].split("\n")[0] 1000 | spmArea = float(strSPMArea) 1001 | 1002 | widgets["reportSPMAreaData"].delete(0, tkinter.END) 1003 | widgets["reportSPMAreaData"].insert(0, str(spmArea)) 1004 | 1005 | 1006 | else: 1007 | tkinter.messagebox.showerror(title="Sythesis", message="Execution of Cacti failed.") 1008 | 1009 | progress = threading.Thread(target=setReportProgress, args=[20]) 1010 | progress.start() 1011 | 1012 | os.chdir("../../build/verilog") 1013 | # mflowgen synthesis: 1014 | os.system("../../tools/sv2v/bin/sv2v design.v > design_sv2v.v") 1015 | progress = threading.Thread(target=setReportProgress, args=[40]) 1016 | progress.start() 1017 | 1018 | os.system("sed -i 's/CGRATemplateRTL__.*/CGRATemplateRTL (/g' design_sv2v.v") 1019 | progress = threading.Thread(target=setReportProgress, args=[50]) 1020 | progress.start() 1021 | 1022 | # os.system("mv design.v ../../mflowgen1/designs/cgra/rtl/outputs/design.v") 1023 | os.system("cp design_sv2v.v ../../tools/mflowgen/designs/cgra/rtl/outputs/design.v") 1024 | os.chdir("../../tools/mflowgen") 1025 | os.system("mkdir ./build") 1026 | os.chdir("./build") 1027 | os.system("rm -r ./*") 1028 | os.system("mflowgen run --design ../designs/cgra") 1029 | 1030 | os.system("make 2") 1031 | progress = threading.Thread(target=setReportProgress, args=[70]) 1032 | progress.start() 1033 | 1034 | yosysRun = threading.Thread(target=runYosys) 1035 | yosysRun.start() 1036 | 1037 | 1038 | def clickSelectApp(event): 1039 | global paramCGRA 1040 | paramCGRA.compilationDone = False 1041 | appName = fd.askopenfilename(title="choose an application", initialdir="../", filetypes=(("C/C++ file", "*.cpp"), ("C/C++ file", "*.c"), ("C/C++ file", "*.C"), ("C/C++ file", "*.CPP"))) 1042 | paramCGRA.targetAppName = appName 1043 | 1044 | # widgets["appPathEntry"].configure(state="normal") 1045 | widgets["appPathEntry"].delete(0, tkinter.END) 1046 | widgets["appPathEntry"].insert(0, paramCGRA.targetAppName) 1047 | # widgets["appPathEntry"].configure(state="disabled") 1048 | 1049 | widgets["compileAppShow"].config(text="IDLE", fg='grey') 1050 | 1051 | def clickCompileApp(): 1052 | global paramCGRA 1053 | fileName = paramCGRA.targetAppName 1054 | if not fileName or fileName == " Not selected yet": 1055 | return 1056 | 1057 | os.system("mkdir kernel") 1058 | os.chdir("kernel") 1059 | 1060 | compileCommand = "clang-12 -emit-llvm -fno-unroll-loops -O3 -o kernel.bc -c " + fileName 1061 | compileProc = subprocess.Popen([compileCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1062 | (compileOut, compileErr) = compileProc.communicate() 1063 | 1064 | disassembleCommand = "llvm-dis-12 kernel.bc -o kernel.ll" 1065 | disassembleProc = subprocess.Popen([disassembleCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1066 | (disassembleOut, disassembleErr) = disassembleProc.communicate() 1067 | 1068 | if compileErr: 1069 | widgets["compileAppShow"].config(text=u'\u2717\u2717\u2717', fg='red') 1070 | os.chdir("..") 1071 | print("Compile error message: ", compileErr) 1072 | return 1073 | if disassembleErr: 1074 | widgets["compileAppShow"].config(text=u'\u2717\u2717\u2717', fg='red') 1075 | os.chdir("..") 1076 | print("Disassemble error message: ", disassembleErr) 1077 | return 1078 | 1079 | widgets["compileAppShow"].config(text=u'\u2713\u2713\u2713', fg='green') 1080 | paramCGRA.compilationDone = True 1081 | 1082 | # collect the potentially targeting kernel/function 1083 | irFile = open('kernel.ll', 'r') 1084 | irLines = irFile.readlines() 1085 | 1086 | # Strips the newline character 1087 | paramCGRA.targetKernels = [] 1088 | for line in irLines: 1089 | if "define " in line and "{" in line and "@" in line: 1090 | funcName = line.split("@")[1].split("(")[0] 1091 | if "main" not in funcName: 1092 | paramCGRA.targetKernels.append(funcName) 1093 | 1094 | irFile.close() 1095 | 1096 | kernelNameMenu = widgets["kernelNameMenu"] 1097 | kernelNameMenu["menu"].delete(0, "end") 1098 | for kernelName in paramCGRA.targetKernels: 1099 | kernelNameMenu["menu"].add_command(label=kernelName, command=tkinter._setit(kernelOptions, kernelName)) 1100 | # options.set(my_list[0]) 1101 | 1102 | widgets["generateDFGShow"].config(text="IDLE", fg='grey') 1103 | 1104 | os.chdir("..") 1105 | 1106 | def clickKernelMenu(*args): 1107 | global paramCGRA 1108 | name = kernelOptions.get() 1109 | if name == None or name == " " or name == "Not selected yet": 1110 | return 1111 | paramCGRA.targetKernelName = name 1112 | 1113 | def dumpParamCGRA2JSON(fileName): 1114 | global paramCGRA 1115 | paramCGRAJson = {} 1116 | paramCGRAJson["tiles"] = {} 1117 | for tile in paramCGRA.tiles: 1118 | curDict = {} 1119 | if tile.disabled: 1120 | curDict["disabled"] = True 1121 | else: 1122 | curDict["disabled"] = False 1123 | if tile.isDefaultFus(): 1124 | curDict["supportAllFUs"] = True 1125 | else: 1126 | curDict["supportAllFUs"] = False 1127 | curDict["supportedFUs"] = [] 1128 | for fuType in tile.fuDict: 1129 | if tile.fuDict[fuType] == 1: 1130 | curDict["supportedFUs"].append(fuType) 1131 | 1132 | if (tile.hasFromMem() and tile.fuDict["Ld"] == 1) and\ 1133 | (tile.hasToMem() and tile.fuDict["St"] == 1): 1134 | curDict["accessMem"] = True 1135 | 1136 | paramCGRAJson["tiles"][str(tile.ID)] = curDict 1137 | 1138 | paramCGRAJson["links"] = [] 1139 | for link in paramCGRA.updatedLinks: 1140 | curDict = {} 1141 | srcTile = link.srcTile 1142 | dstTile = link.dstTile 1143 | if not link.disabled and not srcTile.disabled and not dstTile.disabled and type(srcTile) != ParamSPM and type(dstTile) != ParamSPM: 1144 | curDict["srcTile"] = srcTile.ID 1145 | curDict["dstTile"] = dstTile.ID 1146 | paramCGRAJson["links"].append(curDict) 1147 | 1148 | paramCGRAJsonObject = json.dumps(paramCGRAJson, indent=4) 1149 | 1150 | # Writing to sample.json 1151 | with open(fileName, "w") as outfile: 1152 | outfile.write(paramCGRAJsonObject) 1153 | 1154 | 1155 | 1156 | def clickShowDFG(): 1157 | os.system("mkdir kernel") 1158 | os.chdir("kernel") 1159 | fileExist = os.path.exists("kernel.bc") 1160 | global paramCGRA 1161 | 1162 | if not fileExist or not paramCGRA.compilationDone or paramCGRA.targetKernelName == None: 1163 | os.chdir("..") 1164 | tkinter.messagebox.showerror(title="DFG Generation", message="The compilation and kernel selection need to be done first.") 1165 | return 1166 | 1167 | paramCGRA.targetKernelName = kernelOptions.get() 1168 | 1169 | genDFGJson = { 1170 | "kernel" : paramCGRA.targetKernelName, 1171 | "targetFunction" : False, 1172 | "targetNested" : True, 1173 | "targetLoopsID" : [0], 1174 | "doCGRAMapping" : False, 1175 | "row" : paramCGRA.rows, 1176 | "column" : paramCGRA.columns, 1177 | "precisionAware" : False, 1178 | "heterogeneity" : False, 1179 | "isTrimmedDemo" : True, 1180 | "heuristicMapping" : True, 1181 | "parameterizableCGRA" : True, 1182 | "diagonalVectorization" : False, 1183 | "bypassConstraint" : 8, 1184 | "isStaticElasticCGRA" : False, 1185 | "ctrlMemConstraint" : 200, 1186 | "regConstraint" : 12, 1187 | } 1188 | 1189 | json_object = json.dumps(genDFGJson, indent=4) 1190 | 1191 | with open("param.json", "w") as outfile: 1192 | outfile.write(json_object) 1193 | 1194 | dumpParamCGRA2JSON("paramCGRA.json") 1195 | 1196 | genDFGCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1197 | print("trying to run opt-12") 1198 | genDFGProc = subprocess.Popen([genDFGCommand, "-u"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1199 | 1200 | with genDFGProc.stdout: 1201 | for line in iter(genDFGProc.stdout.readline, b''): 1202 | outputLine = line.decode("ISO-8859-1") 1203 | print(outputLine) 1204 | if "DFG node count: " in outputLine: 1205 | paramCGRA.DFGNodeCount = int(outputLine.split("DFG node count: ")[1].split(";")[0]) 1206 | if "[RecMII: " in outputLine: 1207 | paramCGRA.recMII = int(outputLine.split("[RecMII: ")[1].split("]")[0]) 1208 | 1209 | (out, err) = genDFGProc.communicate() 1210 | print("opt-12 out: ", out) 1211 | print("opt-12 err: ", err) 1212 | 1213 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount+0.0)/len(paramCGRA.getValidTiles())) // 1 1214 | widgets["resMIIEntry"].delete(0, tkinter.END) 1215 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 1216 | 1217 | widgets["recMIIEntry"].delete(0, tkinter.END) 1218 | widgets["recMIIEntry"].insert(0, paramCGRA.recMII) 1219 | 1220 | convertCommand = "dot -Tpng " + paramCGRA.targetKernelName + ".dot -o kernel.png" 1221 | convertProc = subprocess.Popen([convertCommand, "-u"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1222 | (out, err) = convertProc.communicate() 1223 | 1224 | # Gets the size of the whole window 1225 | master.update_idletasks() 1226 | window_width = master.winfo_width() 1227 | window_height = master.winfo_height() 1228 | 1229 | PIL_image = Image.open("kernel.png") 1230 | ImageFile.LOAD_TRUNCATED_IMAGES = True 1231 | PIL_image_stretched = PIL_image.resize((window_width // 6, window_height // 3), Image.Resampling.BILINEAR) 1232 | PIL_image_stretched = PIL_image_stretched.convert("RGBA") 1233 | datas = PIL_image_stretched.getdata() 1234 | 1235 | new_data = [] 1236 | for item in datas: 1237 | if item[0] == 255 and item[1] == 255 and item[2] == 255: 1238 | # Makes the white parts of the image white 1239 | new_data.append((255, 255, 255, 255)) 1240 | else: 1241 | new_data.append(item) 1242 | PIL_image_stretched.putdata(new_data) 1243 | 1244 | 1245 | dfgImage = ImageTk.PhotoImage(PIL_image_stretched) 1246 | images["dfgImage"] = dfgImage # This is important due to the garbage collection would remove local variable of image 1247 | widgets["dfgLabel"].config(image=dfgImage) 1248 | 1249 | widgets["generateDFGShow"].config(text=u'\u2713\u2713\u2713', fg='green') 1250 | 1251 | os.chdir("..") 1252 | 1253 | mappingProc = None 1254 | 1255 | def countMapTime(): 1256 | global mappingProc 1257 | timeCost = 0.0 1258 | while mappingProc == None or mappingProc.poll() is None: 1259 | time.sleep(0.1) 1260 | widgets["mapTimeEntry"].delete(0, tkinter.END) 1261 | widgets["mapTimeEntry"].insert(0, round(timeCost, 1)) 1262 | timeCost += 0.1 1263 | 1264 | def drawSchedule(): 1265 | global mappingProc 1266 | mappingCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1267 | mappingProc = subprocess.Popen(["exec " + mappingCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, bufsize=1) 1268 | (out, err) = mappingProc.communicate() 1269 | success = False 1270 | mappingII = -1 1271 | line = out.decode("ISO-8859-1") 1272 | if "Mapping Success" in line: 1273 | success = True 1274 | if "[Mapping II: " in line: 1275 | strMapII = line.split("[Mapping II: ")[1].split("]")[0] 1276 | mappingII = int(strMapII) 1277 | 1278 | if not success or mappingII == -1: 1279 | tkinter.messagebox.showerror(title="DFG mapping", message="Mapping failed.") 1280 | os.chdir("..") 1281 | return 1282 | 1283 | widgets["mapIIEntry"].delete(0, tkinter.END) 1284 | widgets["mapIIEntry"].insert(0, mappingII) 1285 | widgets["mapSpeedupEntry"].delete(0, tkinter.END) 1286 | widgets["mapSpeedupEntry"].insert(0, paramCGRA.DFGNodeCount/mappingII) 1287 | 1288 | # pad contains tile and links 1289 | tileWidth = paramCGRA.tiles[0].width 1290 | tileHeight = paramCGRA.tiles[0].height 1291 | padWidth = tileWidth + LINK_LENGTH 1292 | padHeight = tileHeight + LINK_LENGTH 1293 | baseX = 0 1294 | 1295 | # load schedule.json for mapping demonstration 1296 | f = open("schedule.json") 1297 | schedule = json.load(f) 1298 | 1299 | # Iterating through the json 1300 | for strTileID in schedule["tiles"]: 1301 | tileID = int(strTileID) 1302 | tile = paramCGRA.getTileOfID(tileID) 1303 | for strCycle in schedule["tiles"][strTileID]: 1304 | cycle = int(strCycle) 1305 | optID = schedule["tiles"][strTileID][strCycle] 1306 | tile.mapping[cycle] = optID[0] 1307 | 1308 | 1309 | for strSrcTileID in schedule["links"]: 1310 | for strDstTileID in schedule["links"][strSrcTileID]: 1311 | srcTile = paramCGRA.getTileOfID(int(strSrcTileID)) 1312 | dstTile = paramCGRA.getTileOfID(int(strDstTileID)) 1313 | link = paramCGRA.getUpdatedLink(srcTile, dstTile) 1314 | for cycle in schedule["links"][strSrcTileID][strDstTileID]: 1315 | link.mapping.add(cycle) 1316 | 1317 | f.close() 1318 | os.chdir("..") 1319 | 1320 | canvas = widgets["mappingCanvas"] 1321 | canvas.delete("all") 1322 | cgraWidth = GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + 20 1323 | canvas.configure(scrollregion=(0, 0, mappingII*cgraWidth, GRID_HEIGHT)) 1324 | 1325 | 1326 | for ii in range(mappingII): 1327 | # draw data memory 1328 | spmLabel = tkinter.Label(canvas, text="Data\nSPM", fg='black', bg='gray', relief='raised', bd=BORDER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1329 | canvas.create_window(baseX+BORDER, BORDER, window=spmLabel, height=GRID_HEIGHT, width=MEM_WIDTH, anchor="nw") 1330 | 1331 | 1332 | 1333 | # draw tiles 1334 | for tile in paramCGRA.tiles: 1335 | if not tile.disabled: 1336 | button = None 1337 | if ii in tile.mapping: 1338 | button = tkinter.Label(canvas, text = "Opt "+str(tile.mapping[ii]), fg="black", bg="cornflowerblue", relief="raised", bd=BORDER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1339 | else: 1340 | button = tkinter.Label(canvas, text = "Tile "+str(tile.ID), fg="black", bg="grey", relief="raised", bd=BORDER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1341 | posX, posY = tile.getPosXY(baseX+BORDER, BORDER) 1342 | canvas.create_window(posX, posY, window=button, height=tileHeight, width=tileWidth, anchor="nw") 1343 | 1344 | # draw links 1345 | for link in paramCGRA.updatedLinks: 1346 | if not link.disabled: 1347 | srcX, srcY = link.getSrcXY(baseX+BORDER, BORDER) 1348 | dstX, dstY = link.getDstXY(baseX+BORDER, BORDER) 1349 | if ii in link.mapping: 1350 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST, fill="red") 1351 | else: 1352 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST, fill="black") 1353 | 1354 | cycleLabel = tkinter.Label(canvas, text="Cycle "+str(ii)) 1355 | canvas.create_window(baseX+280, GRID_HEIGHT+10+BORDER, window=cycleLabel, height=20, width=80) 1356 | 1357 | baseX += GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + 20 1358 | canvas.create_line(baseX-5, INTERVAL, baseX-5, GRID_HEIGHT, width=2, dash=(10,2)) 1359 | 1360 | def clickTerminateMapping(): 1361 | global mappingProc 1362 | if mappingProc == None: 1363 | return 1364 | 1365 | if mappingProc.poll() is None: 1366 | mappingProc.kill() 1367 | 1368 | path = os.getcwd() 1369 | if path.split("\\")[-1] == "kernel": 1370 | os.chdir("..") 1371 | 1372 | 1373 | def clickMapDFG(): 1374 | global mappingProc 1375 | mappingProc = None 1376 | heuristic = mappingAlgoCheckVar.get() == 1 1377 | 1378 | os.system("mkdir kernel") 1379 | os.chdir("kernel") 1380 | fileExist = os.path.exists("kernel.bc") 1381 | global paramCGRA 1382 | 1383 | if not fileExist or not paramCGRA.compilationDone or paramCGRA.targetKernelName == None: 1384 | os.chdir("..") 1385 | # tkinter.messagebox.showerror(title="DFG mapping", message="The compilation and kernel selection need to be done first.") 1386 | if not fileExist: 1387 | tkinter.messagebox.showerror(title="DFG mapping", message="The kernel.bc doesn't exist.") 1388 | if not paramCGRA.compilationDone: 1389 | tkinter.messagebox.showerror(title="DFG mapping", message="The compilation needs to be done first.") 1390 | if paramCGRA.targetKernelName == None: 1391 | tkinter.messagebox.showerror(title="DFG mapping", message="The kernel name is not selected yet.") 1392 | return 1393 | 1394 | mappingJson = { 1395 | "kernel" : paramCGRA.targetKernelName, 1396 | "targetFunction" : False, 1397 | "targetNested" : True, 1398 | "targetLoopsID" : [0], 1399 | "doCGRAMapping" : True, 1400 | "row" : paramCGRA.rows, 1401 | "column" : paramCGRA.columns, 1402 | "precisionAware" : False, 1403 | "heterogeneity" : False, 1404 | "isTrimmedDemo" : True, 1405 | "heuristicMapping" : heuristic, 1406 | "parameterizableCGRA" : True, 1407 | "diagonalVectorization" : False, 1408 | "bypassConstraint" : 8, 1409 | "isStaticElasticCGRA" : False, 1410 | "ctrlMemConstraint" : paramCGRA.configMemSize, 1411 | "regConstraint" : 12, 1412 | } 1413 | 1414 | mappingJsonObject = json.dumps(mappingJson, indent=4) 1415 | 1416 | with open("param.json", "w") as outfile: 1417 | outfile.write(mappingJsonObject) 1418 | 1419 | dumpParamCGRA2JSON("paramCGRA.json") 1420 | 1421 | mappingCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1422 | 1423 | widgets["mapTimeEntry"].delete(0, tkinter.END) 1424 | widgets["mapTimeEntry"].insert(0, 0) 1425 | 1426 | drawer = threading.Thread(target=drawSchedule) 1427 | drawer.start() 1428 | timer = threading.Thread(target=countMapTime) 1429 | timer.start() 1430 | 1431 | 1432 | def create_cgra_pannel(master, rows, columns): 1433 | 1434 | ROWS = rows 1435 | COLS = columns 1436 | # Use solid black board to let the pannel look better 1437 | cgraPannel = tkinter.LabelFrame(master, text='CGRA', bd=BORDER, relief='groove') 1438 | cgraPannel.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nsew") 1439 | canvas = tkinter.Canvas(cgraPannel) 1440 | widgets["canvas"] = canvas 1441 | baseX = 0 1442 | 1443 | # construct data memory 1444 | if paramCGRA.dataSPM == None: 1445 | dataSPM = ParamSPM(MEM_WIDTH, rows, rows) 1446 | paramCGRA.initDataSPM(dataSPM) 1447 | 1448 | # pad contains tile and links 1449 | # padSize = TILE_SIZE + LINK_LENGTH 1450 | padHeight = TILE_HEIGHT + LINK_LENGTH 1451 | padWidth = TILE_WIDTH + LINK_LENGTH 1452 | 1453 | 1454 | # draw data memory 1455 | memHeight = GRID_HEIGHT 1456 | spmLabel = tkinter.Button(canvas, text = "Data\nSPM", fg = 'black', bg = 'gray', relief = 'raised', bd = BORDER, command = clickSPM, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1457 | # Data memory will be placed in the upper left corner 1458 | canvas.create_window(baseX+BORDER, BORDER, window=spmLabel, height=GRID_HEIGHT, width=MEM_WIDTH, anchor="nw") 1459 | 1460 | 1461 | # construct tiles 1462 | if len(paramCGRA.tiles) == 0: 1463 | for i in range(ROWS): 1464 | for j in range(COLS): 1465 | ID = i*COLS+j 1466 | posX = padWidth * j + MEM_WIDTH + LINK_LENGTH 1467 | posY = GRID_HEIGHT - padHeight * i - TILE_HEIGHT 1468 | 1469 | tile = ParamTile(ID, j, i, posX, posY, TILE_WIDTH, TILE_HEIGHT) 1470 | paramCGRA.addTile(tile) 1471 | 1472 | # draw tiles 1473 | for tile in paramCGRA.tiles: 1474 | if not tile.disabled: 1475 | button = tkinter.Button(canvas, text = "Tile "+str(tile.ID), fg='black', bg='gray', relief='raised', bd=BORDER, command=partial(clickTile, tile.ID), highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1476 | posX, posY = tile.getPosXY() 1477 | # Tiles will be placed near the Data memory 1478 | canvas.create_window(posX, posY, window=button, height=TILE_HEIGHT, width=TILE_WIDTH, anchor="nw") 1479 | 1480 | 1481 | # construct links 1482 | if len(paramCGRA.templateLinks) == 0: 1483 | for i in range(ROWS): 1484 | for j in range(COLS): 1485 | if j < COLS-1: 1486 | # horizontal 1487 | tile0 = paramCGRA.getTileOfDim(j, i) 1488 | tile1 = paramCGRA.getTileOfDim(j+1, i) 1489 | link0 = ParamLink(tile0, tile1, PORT_EAST, PORT_WEST) 1490 | link1 = ParamLink(tile1, tile0, PORT_WEST, PORT_EAST) 1491 | paramCGRA.addTemplateLink(link0) 1492 | paramCGRA.addTemplateLink(link1) 1493 | 1494 | if i < ROWS-1 and j < COLS-1: 1495 | # diagonal left bottom to right top 1496 | tile0 = paramCGRA.getTileOfDim(j, i) 1497 | tile1 = paramCGRA.getTileOfDim(j+1, i+1) 1498 | link0 = ParamLink(tile0, tile1, PORT_NORTHEAST, PORT_SOUTHWEST) 1499 | link1 = ParamLink(tile1, tile0, PORT_SOUTHWEST, PORT_NORTHEAST) 1500 | paramCGRA.addTemplateLink(link0) 1501 | paramCGRA.addTemplateLink(link1) 1502 | 1503 | if i < ROWS-1 and j > 0: 1504 | # diagonal left top to right bottom 1505 | tile0 = paramCGRA.getTileOfDim(j, i) 1506 | tile1 = paramCGRA.getTileOfDim(j-1, i+1) 1507 | link0 = ParamLink(tile0, tile1, PORT_NORTHWEST, PORT_SOUTHEAST) 1508 | link1 = ParamLink(tile1, tile0, PORT_SOUTHEAST, PORT_NORTHWEST) 1509 | paramCGRA.addTemplateLink(link0) 1510 | paramCGRA.addTemplateLink(link1) 1511 | 1512 | if i < ROWS-1: 1513 | # vertical 1514 | tile0 = paramCGRA.getTileOfDim(j, i) 1515 | tile1 = paramCGRA.getTileOfDim(j, i+1) 1516 | link0 = ParamLink(tile0, tile1, PORT_NORTH, PORT_SOUTH) 1517 | link1 = ParamLink(tile1, tile0, PORT_SOUTH, PORT_NORTH) 1518 | paramCGRA.addTemplateLink(link0) 1519 | paramCGRA.addTemplateLink(link1) 1520 | 1521 | if j == 0: 1522 | # connect to memory 1523 | tile0 = paramCGRA.getTileOfDim(j, i) 1524 | link0 = ParamLink(tile0, paramCGRA.dataSPM, PORT_WEST, i) 1525 | link1 = ParamLink(paramCGRA.dataSPM, tile0, i, PORT_WEST) 1526 | paramCGRA.addTemplateLink(link0) 1527 | paramCGRA.addTemplateLink(link1) 1528 | 1529 | 1530 | paramCGRA.updateLinks() 1531 | paramCGRA.updateFuXbarPannel() 1532 | 1533 | # draw links 1534 | for link in paramCGRA.updatedLinks: 1535 | if link.disabled: 1536 | pass 1537 | else: 1538 | srcX, srcY = link.getSrcXY() 1539 | dstX, dstY = link.getDstXY() 1540 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST) 1541 | 1542 | vbar = tkinter.Scrollbar(cgraPannel, orient="vertical", command=canvas.yview) 1543 | vbar.pack(side=tkinter.RIGHT, fill="y") 1544 | canvas.config(yscrollcommand=vbar.set) 1545 | canvas.config(scrollregion=canvas.bbox("all")) 1546 | canvas.pack(side="top", fill="both", expand=True) 1547 | hbar = tkinter.Scrollbar(cgraPannel, orient="horizontal", command=canvas.xview) 1548 | hbar.pack(side="bottom", fill="x") 1549 | canvas.config(xscrollcommand=hbar.set) 1550 | 1551 | 1552 | def place_fu_options(master): 1553 | fuCount = len(fuTypeList) 1554 | for i in range(len(fuTypeList)): 1555 | fuVar = tkinter.IntVar() 1556 | fuCheckVars[fuTypeList[i]] = fuVar 1557 | fuCheckbutton = tkinter.Checkbutton(master, variable=fuVar, text=fuTypeList[i], command=partial(clickFuCheckbutton, fuTypeList[i])) 1558 | fuCheckbuttons[fuTypeList[i]] = fuCheckbutton 1559 | fuCheckbutton.select() 1560 | paramCGRA.updateFuCheckbutton(fuTypeList[i], fuVar.get()) 1561 | fuCheckbutton.grid(row=i//4, column=i%4, padx=15, pady=15, sticky="nsew") 1562 | 1563 | def place_xbar_options(master): 1564 | for i in range(PORT_DIRECTION_COUNTS): 1565 | portType = i 1566 | xbarType = xbarPort2Type[i] 1567 | xbarVar = tkinter.IntVar() 1568 | xbarCheckVars[xbarType] = xbarVar 1569 | xbarCheckbutton = tkinter.Checkbutton(master, variable=xbarVar, text=xbarType, command=partial(clickXbarCheckbutton, xbarType)) 1570 | xbarCheckbuttons[xbarType] = xbarCheckbutton 1571 | 1572 | if paramCGRA.getTileOfID(0).xbarDict[xbarType] == 1: 1573 | xbarCheckbutton.select() 1574 | 1575 | paramCGRA.updateXbarCheckbutton(xbarType, xbarVar.get()) 1576 | 1577 | if portType in paramCGRA.getTileOfID(0).neverUsedOutPorts: 1578 | xbarCheckbutton.configure(state="disabled") 1579 | 1580 | xbarCheckbutton.grid(row=i//4, column=i%4, padx=15, pady=15, sticky="nsew") 1581 | 1582 | 1583 | 1584 | def create_param_pannel(master): 1585 | paramPannel = tkinter.LabelFrame(master, text='Configuration', bd=BORDER, relief='groove') 1586 | paramPannel.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="nsew") 1587 | 1588 | # Use columnconfigure and rowconfigure to partition the columns, so that each column and row will fill the corresponding space 1589 | # The 'weight' represents the weight of the corresponding row/column length 1590 | for i in range(10): 1591 | paramPannel.rowconfigure(i, weight=1) 1592 | for i in range(3): 1593 | paramPannel.columnconfigure(i, weight=1) 1594 | rowsLabel = tkinter.Label(paramPannel, text='Rows Columns:') 1595 | rowsLabel.grid(row=0, column=0) 1596 | rowsEntry = tkinter.Entry(paramPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1597 | rowsEntry.grid(row=0, column=1, padx=5, pady=5) 1598 | rowsEntry.insert(0, str(paramCGRA.rows)) 1599 | widgets["rowsEntry"] = rowsEntry 1600 | columnsEntry = tkinter.Entry(paramPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1601 | columnsEntry.grid(row=0, column=2, padx=2, pady=5) 1602 | columnsEntry.insert(0, str(paramCGRA.columns)) 1603 | widgets["columnsEntry"] = columnsEntry 1604 | 1605 | configMemLabel = tkinter.Label(paramPannel, text='Config Memory \n (entries/tile):') 1606 | configMemLabel.grid(row=2, column=0) 1607 | configMemEntry = tkinter.Entry(paramPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1608 | configMemEntry.grid(row=2, column=1, pady=5) 1609 | configMemEntry.insert(0, paramCGRA.configMemSize) 1610 | widgets["configMemEntry"] = configMemEntry 1611 | 1612 | dataMemLabel = tkinter.Label(paramPannel, text='Data SPM (KBs):') 1613 | dataMemLabel.grid(row=1, column=0) 1614 | dataMemEntry = tkinter.Entry(paramPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1615 | dataMemEntry.grid(row=1, column=1, padx=5, pady=5) 1616 | dataMemEntry.insert(0, str(paramCGRA.dataMemSize)) 1617 | widgets["dataMemEntry"] = dataMemEntry 1618 | updateButton = tkinter.Button(paramPannel, text = " Reset ", relief='raised', command = partial(clickReset, master), highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1619 | updateButton.grid(row=1, column=2, columnspan=2) 1620 | 1621 | entireTileCheckVar.set(0) 1622 | entireTileCheckbutton = tkinter.Checkbutton(paramPannel, variable=entireTileCheckVar, text="Disable entire Tile 0") 1623 | entireTileCheckbutton.grid(row=3, column=0) 1624 | widgets["entireTileCheckbutton"] = entireTileCheckbutton 1625 | resetButton = tkinter.Button(paramPannel, text = "Update", relief='raised', command = partial(clickUpdate, master), highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1626 | resetButton.grid(row=2, column=2 ,columnspan=2) 1627 | 1628 | fuConfigPannel = tkinter.LabelFrame(paramPannel, text='Tile 0 functional units', bd = BORDER, relief='groove') 1629 | fuConfigPannel.grid(columnspan=4, row=4, column=0, rowspan=3, sticky="nsew") 1630 | widgets["fuConfigPannel"] = fuConfigPannel 1631 | 1632 | # Use columnconfigure to partition the columns, so that each column fills the corresponding space 1633 | for i in range(4): 1634 | fuConfigPannel.columnconfigure(i, weight=1) 1635 | place_fu_options(fuConfigPannel) 1636 | 1637 | xbarConfigPannel = tkinter.LabelFrame(paramPannel, text='Tile 0 crossbar outgoing links', bd=BORDER, relief='groove') 1638 | xbarConfigPannel.grid(columnspan=4, row=7, column=0, rowspan=2, sticky="nsew") 1639 | widgets["xbarConfigPannel"] = xbarConfigPannel 1640 | 1641 | # Use columnconfigure to partition the columns, so that each column fills the corresponding space 1642 | for i in range(4): 1643 | xbarConfigPannel.columnconfigure(i, weight=1) 1644 | place_xbar_options(xbarConfigPannel) 1645 | 1646 | spmConfigPannel = tkinter.LabelFrame(paramPannel, text='Data SPM outgoing links', bd=BORDER, relief='groove') 1647 | spmConfigPannel.grid(row=7, column=0, rowspan=2, columnspan=4, sticky="nsew") 1648 | widgets["spmConfigPannel"] = spmConfigPannel 1649 | 1650 | # Use columnconfigure and rowconfigure to partition the columns, so that each column and row fills the corresponding space 1651 | for i in range(3): 1652 | spmConfigPannel.rowconfigure(i, weight=1) 1653 | for i in range(5): 1654 | spmConfigPannel.columnconfigure(i, weight=1) 1655 | 1656 | spmEnabledOutVar = tkinter.IntVar() 1657 | spmDisabledOutVar = tkinter.IntVar() 1658 | 1659 | spmEnabledLabel = tkinter.Label(spmConfigPannel) 1660 | spmDisabledLabel = tkinter.Label(spmConfigPannel) 1661 | 1662 | spmEnabledScrollbar = tkinter.Scrollbar(spmEnabledLabel) 1663 | spmDisabledScrollbar = tkinter.Scrollbar(spmDisabledLabel) 1664 | 1665 | spmEnabledListbox = tkinter.Listbox(spmEnabledLabel, listvariable=spmEnabledOutVar) 1666 | spmDisabledListbox = tkinter.Listbox(spmDisabledLabel, listvariable=spmDisabledOutVar) 1667 | 1668 | widgets["spmEnabledListbox"] = spmEnabledListbox 1669 | widgets["spmDisabledListbox"] = spmDisabledListbox 1670 | 1671 | spmDisableButton = tkinter.Button(spmConfigPannel, text="Disable", relief='raised', command=clickSPMPortDisable, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1672 | spmEnableButton = tkinter.Button(spmConfigPannel, text="Enable", relief='raised', command=clickSPMPortEnable, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1673 | spmEnabledScrollbar.config(command=spmEnabledListbox.yview) 1674 | spmEnabledListbox.config(yscrollcommand=spmEnabledScrollbar.set) 1675 | spmDisabledScrollbar.config(command=spmDisabledListbox.yview) 1676 | spmDisabledListbox.config(yscrollcommand=spmDisabledScrollbar.set) 1677 | spmEnabledLabel.grid(row=0, column=0, rowspan=3, sticky="nsew") 1678 | 1679 | spmEnabledScrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) 1680 | spmEnabledListbox.pack() 1681 | 1682 | spmDisableArrow0 = tkinter.Label(spmConfigPannel, text="=>") 1683 | spmDisableArrow1 = tkinter.Label(spmConfigPannel, text="=>") 1684 | spmEnableArrow0 = tkinter.Label(spmConfigPannel, text="<=") 1685 | spmEnableArrow1 = tkinter.Label(spmConfigPannel, text="<=") 1686 | 1687 | spmDisableArrow0.grid(row=0, column=1, sticky="nsew") 1688 | spmDisableButton.grid(row=0, column=2, sticky="nsew") 1689 | spmDisableArrow1.grid(row=0, column=3, sticky="nsew") 1690 | 1691 | spmEnableArrow0.grid(row=2, column=1, sticky="nsew") 1692 | spmEnableButton.grid(row=2, column=2, sticky="nsew") 1693 | spmEnableArrow1.grid(row=2, column=3, sticky="nsew") 1694 | 1695 | spmDisabledLabel.grid(row=0, column=4, rowspan=3, sticky="new") 1696 | 1697 | spmDisabledScrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) 1698 | spmDisabledListbox.pack() 1699 | 1700 | spmEnabledListbox.delete(0) 1701 | spmDisabledListbox.delete(0) 1702 | for port in paramCGRA.dataSPM.outLinks: 1703 | if not paramCGRA.dataSPM.outLinks[port].disabled: 1704 | spmEnabledListbox.insert(0, port) 1705 | 1706 | 1707 | 1708 | 1709 | 1710 | def create_test_pannel(master): 1711 | dataPannel =tkinter.LabelFrame(master) 1712 | dataPannel.grid(row=0, column=2, rowspan=1, columnspan=1, sticky="nsew") 1713 | # Increase the size of the 'SVerilog' panel 1714 | dataPannel.grid_rowconfigure(1, weight=2) 1715 | 1716 | dataPannel.grid_columnconfigure(0, weight=1) 1717 | dataPannel.grid_columnconfigure(1, weight=1) 1718 | dataPannel.grid_columnconfigure(2, weight=1) 1719 | testPannel = tkinter.LabelFrame(dataPannel, text='Verification', bd=BORDER, relief='groove') 1720 | testPannel.grid(row=0, column=0, rowspan=1, columnspan=3, sticky="nsew") 1721 | testPannel.columnconfigure(0, weight=1) 1722 | testPannel.columnconfigure(1, weight=1) 1723 | testPannel.columnconfigure(2, weight=1) 1724 | testButton = tkinter.Button(testPannel, text = "Run tests", relief='raised', command = clickTest, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1725 | testButton.grid(row=0, column=0, rowspan=1, columnspan=1) 1726 | testProgress = ttk.Progressbar(testPannel, orient='horizontal', mode='determinate') 1727 | testProgress['value'] = 0 1728 | widgets["testProgress"] = testProgress 1729 | testProgress.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="nsew") 1730 | testShow = tkinter.Label(testPannel, text = " IDLE ", fg='gray') 1731 | widgets["testShow"] = testShow 1732 | testShow.grid(row=0, column=2, sticky=tkinter.E) 1733 | 1734 | verilogPannel = tkinter.LabelFrame(dataPannel,text="SVerilog",bd=BORDER,relief="groove") 1735 | verilogPannel.grid(row=1, column=0, rowspan=1, columnspan=3, sticky="nsew") 1736 | CreateToolTip(verilogPannel, text = "The code might be too big to be copied,\nthe generated verilog can be found in\nthe 'verilog' folder.") 1737 | generateVerilogButton = tkinter.Button(verilogPannel, text="Generate", relief='raised', command=clickGenerateVerilog, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1738 | generateVerilogButton.pack(side=tkinter.BOTTOM, anchor="sw", padx=BORDER, pady=BORDER) 1739 | verilogScroll = tkinter.Scrollbar(verilogPannel, orient="vertical") 1740 | verilogScroll.pack(side=tkinter.RIGHT, fill="y") 1741 | verilogText = tkinter.Text(verilogPannel, yscrollcommand=verilogScroll.set,width=10,height=5) 1742 | verilogText.pack(side=tkinter.LEFT, fill="both", expand=True) 1743 | verilogScroll.config(command=verilogText.yview) 1744 | widgets["verilogText"] = verilogText 1745 | 1746 | reportPannel = tkinter.LabelFrame(dataPannel,text='Report area/power', bd = BORDER, relief='groove') 1747 | reportPannel.grid(row=2, column=0, rowspan=1, columnspan=3, sticky='nesw') 1748 | reportPannel.columnconfigure(0, weight=1) 1749 | reportPannel.columnconfigure(1, weight=1) 1750 | reportButton = tkinter.Button(reportPannel, text="Synthesize", relief="raised", command=clickSynthesize, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1751 | 1752 | reportProgress = ttk.Progressbar(reportPannel, orient="horizontal", mode="determinate") 1753 | reportProgress['value'] = 0 1754 | widgets["reportProgress"] = reportProgress 1755 | 1756 | synthesisTimeEntry = tkinter.Entry(reportPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1757 | widgets["synthesisTimeEntry"] = synthesisTimeEntry 1758 | 1759 | reportTimecostLabel = tkinter.Label(reportPannel, text = " Time cost:") 1760 | CreateToolTip(reportTimecostLabel, text = "Time is in s.") 1761 | 1762 | reportTileAreaLabel = tkinter.Label(reportPannel, text = " Tiles area:") 1763 | CreateToolTip(reportTileAreaLabel, text = "Area is in mm^2.") 1764 | 1765 | reportTileAreaData = tkinter.Entry(reportPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1766 | widgets["reportTileAreaData"] = reportTileAreaData 1767 | 1768 | reportTilePowerLabel = tkinter.Label(reportPannel, text = "Tiles power:") 1769 | CreateToolTip(reportTilePowerLabel, text = "Yosys is not able to provide\npower estimation.") 1770 | 1771 | reportTilePowerData = tkinter.Entry(reportPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1772 | widgets["reportTilePowerData"] = reportTilePowerData 1773 | 1774 | reportSPMAreaLabel = tkinter.Label(reportPannel, text = " SPM area:") 1775 | CreateToolTip(reportSPMAreaLabel, text = "Area is in mm^2.") 1776 | 1777 | reportSPMAreaData = tkinter.Entry(reportPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1778 | widgets["reportSPMAreaData"] = reportSPMAreaData 1779 | 1780 | reportSPMPowerLabel = tkinter.Label(reportPannel, text = "SPM power:") 1781 | CreateToolTip(reportSPMPowerLabel, text = "Power is in mW.") 1782 | 1783 | reportSPMPowerData = tkinter.Entry(reportPannel, justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1784 | widgets["reportSPMPowerData"] = reportSPMPowerData 1785 | 1786 | reportButton.grid(row=0, column=0) 1787 | reportProgress.grid(row=0, column=1) 1788 | 1789 | synthesisTimeEntry.grid(row=1, column=1, pady=10, sticky="w") 1790 | reportTimecostLabel.grid(row=1, column=0, pady=10) 1791 | 1792 | reportTileAreaLabel.grid(row=2, column=0, pady=10) 1793 | reportTileAreaData.grid(row=2, column=1, pady=10, sticky="w") 1794 | reportTilePowerLabel.grid(row=3, column=0, pady=10) 1795 | reportTilePowerData.grid(row=3, column=1, pady=10, sticky="w") 1796 | 1797 | reportSPMAreaLabel.grid(row=4, column=0, pady=10) 1798 | reportSPMAreaData.grid(row=4, column=1, pady=10, sticky="w") 1799 | reportSPMPowerLabel.grid(row=5, column=0, pady=10) 1800 | reportSPMPowerData.grid(row=5, column=1, pady=10, sticky="w") 1801 | 1802 | 1803 | 1804 | def create_layout_pannel(master): 1805 | layoutPannel = tkinter.LabelFrame(master, text='Layout', bd=BORDER, relief='groove') 1806 | layoutPannel.grid(row=0, column=3, rowspan=1, columnspan=1, sticky="nsew") 1807 | canvas = tkinter.Canvas(layoutPannel, bd=0) 1808 | scrollbar = tkinter.Scrollbar(layoutPannel, orient="horizontal", command=canvas.xview) 1809 | scrollbar.pack(side="bottom", fill="x") 1810 | canvas.config(xscrollcommand=scrollbar.set) 1811 | canvas.pack(side="top", fill="both", expand=True) 1812 | layout_frame = tkinter.Frame(canvas) 1813 | canvas.create_window((0, 0), window=layout_frame, anchor="nw") 1814 | showButton = tkinter.Button(layoutPannel, text = "Display layout", relief='raised', highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1815 | CreateToolTip(showButton, text = "The layout demonstration is\nunder development.") 1816 | showButton.place(relx=0.5, rely=0.05, anchor="center") 1817 | X = tkinter.Label(layout_frame, fg="black") 1818 | X.pack() 1819 | 1820 | def create_mapping_pannel(master): 1821 | mappingPannel = tkinter.LabelFrame(master, text='Mapping', bd=BORDER, relief='groove') 1822 | mappingPannel.grid(row=1, column=1, rowspan=1, columnspan=3, sticky="nsew") 1823 | mappingCanvas = tkinter.Canvas(mappingPannel, bd=0) 1824 | widgets["mappingCanvas"] = mappingCanvas 1825 | hbar = tkinter.Scrollbar(mappingPannel, orient="horizontal", command=mappingCanvas.xview) 1826 | hbar.pack(side="bottom", fill="x") 1827 | mappingCanvas.config(xscrollcommand=hbar.set) 1828 | vbar = tkinter.Scrollbar(mappingPannel, orient="vertical", command=mappingCanvas.yview) 1829 | vbar.pack(side=tkinter.RIGHT, fill="y") 1830 | mappingCanvas.config(yscrollcommand=vbar.set) 1831 | mappingCanvas.pack(side="top", fill="both", expand=True) 1832 | 1833 | def create_kernel_pannel(master): 1834 | kernelPannel = tkinter.LabelFrame(master, text="Kernel", bd=BORDER, relief='groove') 1835 | kernelPannel.grid(row=1, column=0, rowspan=1, columnspan=1, sticky="nsew") 1836 | for row in range(12): 1837 | kernelPannel.grid_rowconfigure(row, weight=1) 1838 | kernelPannel.grid_columnconfigure(0, weight=3) 1839 | kernelPannel.grid_columnconfigure(1, weight=2) 1840 | kernelPannel.grid_columnconfigure(2, weight=2) 1841 | kernelPannel.grid_columnconfigure(3, weight=1) 1842 | 1843 | selectAppLabel = tkinter.Label(kernelPannel, text=" Application:", fg='black') 1844 | selectAppLabel.grid(row=0, column=0, sticky="nsew") 1845 | 1846 | appPathEntry = tkinter.Entry(kernelPannel, fg="black") 1847 | widgets["appPathEntry"] = appPathEntry 1848 | appPathEntry.grid(row=0, column=1, sticky="nsew") 1849 | appPathEntry.bind("", clickSelectApp) 1850 | 1851 | compileAppButton = tkinter.Button(kernelPannel, text=" Compile app ", fg="black", command=clickCompileApp, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1852 | compileAppButton.grid(row=0, column=2, sticky="nse") 1853 | 1854 | compileAppShow = tkinter.Label(kernelPannel, text=" IDLE", fg='gray') 1855 | compileAppShow.grid(row=0, column=3, sticky="ew") 1856 | widgets["compileAppShow"] = compileAppShow 1857 | 1858 | kernelNameLabel = tkinter.Label(kernelPannel, text=" Kernel name:", fg='black') 1859 | kernelNameLabel.grid(row=1, column=0, sticky="nsew") 1860 | 1861 | tempOptions = [ "Not selected yet" ] 1862 | kernelNameMenu = tkinter.OptionMenu(kernelPannel, kernelOptions, *tempOptions) 1863 | kernelOptions.trace("w", clickKernelMenu) 1864 | widgets["kernelNameMenu"] = kernelNameMenu 1865 | kernelNameMenu.grid(row=1, column=1, sticky="nsew") 1866 | 1867 | generateDFGButton = tkinter.Button(kernelPannel, text = "Generate DFG", fg="black", command=clickShowDFG, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1868 | generateDFGButton.grid(row=1, column=2, sticky="nse") 1869 | 1870 | generateDFGShow = tkinter.Label(kernelPannel, text=" IDLE", fg='gray') 1871 | generateDFGShow.grid(row=1, column=3, sticky="ew") 1872 | widgets["generateDFGShow"] = generateDFGShow 1873 | 1874 | dfgPannel = tkinter.LabelFrame(kernelPannel, text='Data-Flow Graph', fg="black", bd=BORDER, relief='groove', highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1875 | dfgPannel.grid(row=2, column=0, rowspan=10, columnspan=2, sticky="nsew") 1876 | dfgLabel = tkinter.Label(dfgPannel) 1877 | widgets["dfgLabel"] = dfgLabel 1878 | dfgLabel.pack() 1879 | 1880 | recMIILabel = tkinter.Label(kernelPannel, text=" RecMII: ", fg='black') 1881 | recMIILabel.grid(row=2, column=2, sticky="nsew") 1882 | recMIIEntry = tkinter.Entry(kernelPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1883 | widgets["recMIIEntry"] = recMIIEntry 1884 | recMIIEntry.insert(0, "0") 1885 | recMIIEntry.grid(row=2, column=3) 1886 | resMIILabel = tkinter.Label(kernelPannel, text=" ResMII: ", fg='black') 1887 | resMIILabel.grid(row=3, column=2, sticky="nsew") 1888 | resMIIEntry = tkinter.Entry(kernelPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1889 | widgets["resMIIEntry"] = resMIIEntry 1890 | resMIIEntry.insert(0, "0") 1891 | resMIIEntry.grid(row=3, column=3) 1892 | 1893 | mappingOptionLabel = tkinter.Label(kernelPannel, text="Mapping algo:", fg='black') 1894 | mappingOptionLabel.grid(row=4, column=2, columnspan=2, sticky="nsew") 1895 | heuristicRatiobutton = tkinter.Radiobutton(kernelPannel, text="Heuristic", variable=mappingAlgoCheckVar, value=1) 1896 | widgets["heuristicRatiobutton"] = heuristicRatiobutton 1897 | heuristicRatiobutton.grid(row=5, column=2, columnspan=2, sticky="nsew") 1898 | exhaustiveRatiobutton = tkinter.Radiobutton(kernelPannel, text="Exhaustive", variable=mappingAlgoCheckVar, value=0) 1899 | widgets["exhaustiveRatiobutton"] = exhaustiveRatiobutton 1900 | exhaustiveRatiobutton.grid(row=6, column=2, columnspan=2, sticky="nsew") 1901 | 1902 | mapDFGButton = tkinter.Button(kernelPannel, text="Map DFG", fg="black", command=clickMapDFG, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1903 | mapDFGButton.grid(row=7, column=2, columnspan=2, sticky="new") 1904 | terminateMapButton = tkinter.Button(kernelPannel, text="Terminate", fg="black", command=clickTerminateMapping, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1905 | terminateMapButton.grid(row=8, column=2, columnspan=2, sticky="new") 1906 | 1907 | mapSecLabel = tkinter.Label(kernelPannel, text="Time (s): ", fg='black') 1908 | mapSecLabel.grid(row=9, column=2, sticky="nsew") 1909 | mapTimeEntry = tkinter.Entry(kernelPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1910 | widgets["mapTimeEntry"] = mapTimeEntry 1911 | mapTimeEntry.insert(0, "0") 1912 | mapTimeEntry.grid(row=9, column=3) 1913 | mapIILabel = tkinter.Label(kernelPannel, text=" Map II: ", fg='black') 1914 | mapIILabel.grid(row=10, column=2, sticky="nsew") 1915 | mapIIEntry = tkinter.Entry(kernelPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1916 | widgets["mapIIEntry"] = mapIIEntry 1917 | mapIIEntry.insert(0, "0") 1918 | mapIIEntry.grid(row=10, column=3) 1919 | 1920 | speedupLabel = tkinter.Label(kernelPannel, text="Speedup: ", fg='black') 1921 | speedupLabel.grid(row=11, column=2, sticky="nsew") 1922 | CreateToolTip(speedupLabel, text = "The speedup is the improvement of\nthe execution cycles with respect to\na single-issue in-order CPU.") 1923 | mapSpeedupEntry = tkinter.Entry(kernelPannel, fg="black", justify=tkinter.CENTER, highlightbackground="black", highlightthickness = HIGHLIGHT_THICKNESS) 1924 | widgets["mapSpeedupEntry"] = mapSpeedupEntry 1925 | mapSpeedupEntry.insert(0, "0") 1926 | mapSpeedupEntry.grid(row=11, column=3) 1927 | 1928 | #paramPadPosX = GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + INTERVAL * 3 1929 | #paramPadWidth = 270 1930 | #scriptPadPosX = paramPadPosX + paramPadWidth + INTERVAL 1931 | #scriptPadWidth = 300 1932 | #layoutPadPosX = scriptPadPosX + scriptPadWidth + INTERVAL 1933 | #layoutPadWidth = 300 1934 | #layoutPadHeight = GRID_HEIGHT 1935 | TILE_HEIGHT = 70 1936 | TILE_WIDTH = 70 1937 | LINK_LENGTH = 40 1938 | GRID_WIDTH = (TILE_WIDTH+LINK_LENGTH) * COLS - LINK_LENGTH 1939 | GRID_HEIGHT = (TILE_HEIGHT+LINK_LENGTH) * ROWS - LINK_LENGTH 1940 | create_kernel_pannel(master) 1941 | create_mapping_pannel(master) 1942 | create_cgra_pannel(master, ROWS, COLS) 1943 | create_param_pannel(master) 1944 | create_test_pannel(master) 1945 | create_layout_pannel(master) 1946 | # The width and height of the entire window 1947 | default_width = 1650 1948 | default_height = 1000 1949 | window_size(master, default_width, default_height) 1950 | #master.grid_rowconfigure(0, weight=1) 1951 | master.grid_rowconfigure(1, weight=2) 1952 | master.grid_columnconfigure(0, weight=1) 1953 | master.grid_columnconfigure(1, weight=1) 1954 | master.grid_columnconfigure(2, weight=1) 1955 | master.grid_columnconfigure(3, weight=1) 1956 | #print(master.winfo_width()) 1957 | #print(master.winfo_height()) 1958 | master.mainloop() -------------------------------------------------------------------------------- /mode_dark_light.py: -------------------------------------------------------------------------------- 1 | import json 2 | import math 3 | import os 4 | import platform 5 | import subprocess 6 | import threading 7 | import time 8 | import tkinter 9 | import tkinter.messagebox 10 | from functools import partial 11 | from tkinter import filedialog as fd 12 | 13 | import customtkinter 14 | from PIL import Image, ImageTk, ImageFile 15 | 16 | import argparse 17 | parser=argparse.ArgumentParser() 18 | parser.add_argument("--theme") 19 | args=parser.parse_args() 20 | customtkinter.set_appearance_mode("dark") # Modes: system (default), light, dark 21 | customtkinter.set_default_color_theme("dark-blue") # Themes: blue (default), dark-blue, green 22 | # CANVAS_BG_COLOR = "#2B2B2B" 23 | CANVAS_BG_COLOR = "#212121" 24 | CANVAS_LINE_COLOR = "white" 25 | 26 | if args.theme: 27 | # print(f'Input theme argument: {args.theme}') 28 | if args.theme == 'light': 29 | customtkinter.set_appearance_mode("light") # Modes: system (default), light, dark 30 | customtkinter.set_default_color_theme("dark-blue") # Themes: blue (default), dark-blue, green 31 | CANVAS_BG_COLOR = "#E5E5E5" 32 | CANVAS_LINE_COLOR = "black" 33 | 34 | from VectorCGRA.cgra.translate.CGRATemplateRTL_test import * 35 | 36 | # importing module 37 | import logging 38 | 39 | # Create and configure logger 40 | logging.basicConfig(level=logging.DEBUG, 41 | format='%(asctime)s - %(levelname)s - %(message)s') 42 | 43 | PORT_NORTH = 0 44 | PORT_SOUTH = 1 45 | PORT_WEST = 2 46 | PORT_EAST = 3 47 | PORT_NORTHWEST = 4 48 | PORT_NORTHEAST = 5 49 | PORT_SOUTHEAST = 6 50 | PORT_SOUTHWEST = 7 51 | PORT_DIRECTION_COUNTS = 8 52 | ROWS = 4 53 | COLS = 4 54 | INTERVAL = 10 55 | BORDER = 4 56 | MEM_WIDTH = 50 57 | CONFIG_MEM_SIZE = 8 58 | DATA_MEM_SIZE = 4 59 | HIGHLIGHT_THICKNESS = 1 60 | 61 | FRAME_LABEL_FONT_SIZE = 15 62 | # FRAME_LABEL_LEVEL_1_FONT_SIZE = FRAME_LABEL_LEVEL_1_FONT_SIZE - 3 63 | 64 | 65 | def window_size(window, width, height): 66 | window.geometry(f"{width}x{height}") 67 | 68 | master = customtkinter.CTk() 69 | master.title("CGRA-Flow: An Integrated End-to-End Framework for CGRA Exploration, Compilation, and Development") 70 | 71 | fuTypeList = ["Phi", "Add", "Shift", "Ld", "Sel", "Cmp", "MAC", "St", "Ret", "Mul", "Logic", "Br"] 72 | xbarTypeList = ["W", "E", "N", "S", "NE", "NW", "SE", "SW"] 73 | 74 | xbarType2Port = {} 75 | xbarType2Port["W"] = PORT_WEST 76 | xbarType2Port["E"] = PORT_EAST 77 | xbarType2Port["N"] = PORT_NORTH 78 | xbarType2Port["S"] = PORT_SOUTH 79 | xbarType2Port["NE"] = PORT_NORTHEAST 80 | xbarType2Port["NW"] = PORT_NORTHWEST 81 | xbarType2Port["SE"] = PORT_SOUTHEAST 82 | xbarType2Port["SW"] = PORT_SOUTHWEST 83 | 84 | xbarPort2Type = {} 85 | xbarPort2Type[PORT_WEST] = "W" 86 | xbarPort2Type[PORT_EAST] = "E" 87 | xbarPort2Type[PORT_NORTH] = "N" 88 | xbarPort2Type[PORT_SOUTH] = "S" 89 | xbarPort2Type[PORT_NORTHEAST] = "NE" 90 | xbarPort2Type[PORT_NORTHWEST] = "NW" 91 | xbarPort2Type[PORT_SOUTHEAST] = "SE" 92 | xbarPort2Type[PORT_SOUTHWEST] = "SW" 93 | 94 | xbarPortOpposites = {} 95 | xbarPortOpposites[PORT_WEST] = PORT_EAST 96 | xbarPortOpposites[PORT_EAST] = PORT_WEST 97 | xbarPortOpposites[PORT_NORTH] = PORT_SOUTH 98 | xbarPortOpposites[PORT_SOUTH] = PORT_NORTH 99 | xbarPortOpposites[PORT_NORTHWEST] = PORT_SOUTHEAST 100 | xbarPortOpposites[PORT_NORTHEAST] = PORT_SOUTHWEST 101 | xbarPortOpposites[PORT_SOUTHWEST] = PORT_NORTHEAST 102 | xbarPortOpposites[PORT_SOUTHEAST] = PORT_NORTHWEST 103 | 104 | widgets = {} 105 | images = {} 106 | entireTileCheckVar = tkinter.IntVar() 107 | mappingAlgoCheckVar = tkinter.IntVar() 108 | fuCheckVars = {} 109 | fuCheckbuttons = {} 110 | xbarCheckVars = {} 111 | xbarCheckbuttons = {} 112 | kernelOptions = tkinter.StringVar() 113 | kernelOptions.set("Not selected yet") 114 | synthesisRunning = False 115 | constraintFilePath = "" 116 | configFilePath = "" 117 | 118 | mapped_tile_color_list = ['#FFF113', '#75D561', '#F2CB67', '#FFAC73', '#F3993A', '#B3FF04', '#C2FFFF'] 119 | 120 | processOptions = tkinter.StringVar() 121 | processOptions.set("asap7") 122 | 123 | class ParamTile: 124 | def __init__(s, ID, dimX, dimY, posX, posY, tileWidth, tileHeight): 125 | s.ID = ID 126 | s.disabled = False 127 | s.posX = posX 128 | s.posY = posY 129 | s.dimX = dimX 130 | s.dimY = dimY 131 | s.width = tileWidth 132 | s.height = tileHeight 133 | s.outLinks = {} 134 | s.inLinks = {} 135 | s.neverUsedOutPorts = set() 136 | s.fuDict = {} 137 | s.xbarDict = {} 138 | s.mapping = {} 139 | 140 | for i in range(PORT_DIRECTION_COUNTS): 141 | s.neverUsedOutPorts.add(i) 142 | 143 | for xbarType in xbarTypeList: 144 | s.xbarDict[xbarType] = 0 145 | 146 | for fuType in fuTypeList: 147 | s.fuDict[fuType] = 1 148 | 149 | def hasFromMem(s): 150 | for link in s.inLinks.values(): 151 | if not link.disabled and link.isFromMem(): 152 | return True 153 | return False 154 | 155 | def hasToMem(s): 156 | for link in s.outLinks.values(): 157 | if not link.disabled and link.isToMem(): 158 | return True 159 | return False 160 | 161 | def getInvalidInPorts(s): 162 | invalidInPorts = set() 163 | for port in range(PORT_DIRECTION_COUNTS): 164 | if port not in s.inLinks: 165 | invalidInPorts.add(port) 166 | continue 167 | link = s.inLinks[port] 168 | if link.disabled or type(link.srcTile) == ParamSPM or link.srcTile.disabled: 169 | invalidInPorts.add(port) 170 | continue 171 | return invalidInPorts 172 | 173 | def isDefaultFus(s): 174 | for fuType in fuTypeList: 175 | if s.fuDict[fuType] != 1: 176 | return False 177 | return True 178 | 179 | def getAllValidFuTypes(s): 180 | fuTypes = set() 181 | for fuType in fuTypeList: 182 | if s.fuDict[fuType] == 1: 183 | if fuType == "Ld" or fuType == "St": 184 | fuTypes.add("Ld") 185 | else: 186 | fuTypes.add(fuType) 187 | return list(fuTypes) 188 | 189 | def getInvalidOutPorts(s): 190 | invalidOutPorts = set() 191 | for port in range(PORT_DIRECTION_COUNTS): 192 | if port not in s.outLinks: 193 | invalidOutPorts.add(port) 194 | continue 195 | link = s.outLinks[port] 196 | if link.disabled or type(link.dstTile) == ParamSPM or link.dstTile.disabled: 197 | invalidOutPorts.add(port) 198 | continue 199 | return invalidOutPorts 200 | 201 | def reset(s): 202 | s.disabled = False 203 | s.mapping = {} 204 | 205 | for i in range(PORT_DIRECTION_COUNTS): 206 | s.neverUsedOutPorts.add(i) 207 | 208 | for xbarType in xbarTypeList: 209 | s.xbarDict[xbarType] = 0 210 | 211 | for fuType in fuTypeList: 212 | s.fuDict[fuType] = 1 213 | 214 | def resetOutLink(s, portType, link): 215 | s.outLinks[portType] = link 216 | s.xbarDict[xbarPort2Type[portType]] = 1 217 | if portType in s.neverUsedOutPorts: 218 | s.neverUsedOutPorts.remove(portType) 219 | 220 | def resetInLink(s, portType, link): 221 | s.inLinks[portType] = link 222 | 223 | def setOutLink(s, portType, link): 224 | s.outLinks[portType] = link 225 | 226 | def setInLink(s, portType, link): 227 | s.resetInLink(portType, link) 228 | 229 | # position X/Y for drawing the tile 230 | def getPosXY(s, baseX=0, baseY=0): 231 | return (baseX + s.posX, baseY + s.posY) 232 | 233 | # position X/Y for connecting routing ports 234 | def getPosXYOnPort(s, portType, baseX=0, baseY=0): 235 | if portType == PORT_NORTH: 236 | return s.getNorth(baseX, baseY) 237 | elif portType == PORT_SOUTH: 238 | return s.getSouth(baseX, baseY) 239 | elif portType == PORT_WEST: 240 | return s.getWest(baseX, baseY) 241 | elif portType == PORT_EAST: 242 | return s.getEast(baseX, baseY) 243 | elif portType == PORT_NORTHEAST: 244 | return s.getNorthEast(baseX, baseY) 245 | elif portType == PORT_NORTHWEST: 246 | return s.getNorthWest(baseX, baseY) 247 | elif portType == PORT_SOUTHEAST: 248 | return s.getSouthEast(baseX, baseY) 249 | else: 250 | return s.getSouthWest(baseX, baseY) 251 | 252 | def getNorthWest(s, baseX=0, baseY=0): 253 | return (baseX + s.posX, baseY + s.posY) 254 | 255 | def getNorthEast(s, baseX=0, baseY=0): 256 | return (baseX + s.posX + s.width, baseY + s.posY) 257 | 258 | def getSouthWest(s, baseX=0, baseY=0): 259 | return (baseX + s.posX, baseY + s.posY + s.height) 260 | 261 | def getSouthEast(s, baseX=0, baseY=0): 262 | return (baseX + s.posX + s.width, baseY + s.posY + s.height) 263 | 264 | def getWest(s, baseX=0, baseY=0): 265 | return (baseX + s.posX, baseY + s.posY + s.height // 2) 266 | 267 | def getEast(s, baseX=0, baseY=0): 268 | return (baseX + s.posX + s.width, baseY + s.posY + s.height // 2) 269 | 270 | def getNorth(s, baseX=0, baseY=0): 271 | return (baseX + s.posX + s.width // 2, baseY + s.posY) 272 | 273 | def getSouth(s, baseX=0, baseY=0): 274 | return (baseX + s.posX + s.width // 2, baseY + s.posY + s.height) 275 | 276 | def getDimXY(s): 277 | return s.dimX, s.dimY 278 | 279 | def getIndex(s, tileList): 280 | if s.disabled: 281 | return -1 282 | index = 0 283 | for tile in tileList: 284 | if tile.dimY < s.dimY and not tile.disabled: 285 | index += 1 286 | elif tile.dimY == s.dimY and tile.dimX < s.dimX and not tile.disabled: 287 | index += 1 288 | return index 289 | 290 | 291 | class ParamSPM: 292 | def __init__(s, posX, numOfReadPorts, numOfWritePorts): 293 | s.posX = posX 294 | s.ID = -1 295 | s.numOfReadPorts = numOfReadPorts 296 | s.numOfWritePorts = numOfWritePorts 297 | s.disabled = False 298 | s.inLinks = {} 299 | s.outLinks = {} 300 | 301 | def getNumOfValidReadPorts(s): 302 | ports = 0 303 | for physicalPort in range(s.numOfReadPorts): 304 | if physicalPort not in s.inLinks: 305 | continue 306 | if s.inLinks[physicalPort].disabled: 307 | continue 308 | ports += 1 309 | return ports 310 | 311 | def getNumOfValidWritePorts(s): 312 | ports = 0 313 | for physicalPort in range(s.numOfWritePorts): 314 | if physicalPort not in s.outLinks: 315 | continue 316 | if s.outLinks[physicalPort].disabled: 317 | continue 318 | ports += 1 319 | return ports 320 | 321 | def getValidReadPort(s, logicalPort): 322 | port = 0 323 | for physicalPort in range(logicalPort + 1): 324 | if physicalPort not in s.inLinks: 325 | continue 326 | if s.inLinks[physicalPort].disabled: 327 | continue 328 | if physicalPort == logicalPort: 329 | return port 330 | port += 1 331 | return -1 332 | 333 | def getValidWritePort(s, logicalPort): 334 | port = 0 335 | for physicalPort in range(logicalPort + 1): 336 | if physicalPort not in s.outLinks: 337 | continue 338 | if s.outLinks[physicalPort].disabled: 339 | continue 340 | if physicalPort == logicalPort: 341 | return port 342 | port += 1 343 | return -1 344 | 345 | def getPosX(s, baseX): 346 | return s.posX + baseX 347 | 348 | def setInLink(s, portType, link): 349 | s.inLinks[portType] = link 350 | 351 | def resetInLink(s, portType, link): 352 | s.setInLink(portType, link) 353 | 354 | def setOutLink(s, portType, link): 355 | s.outLinks[portType] = link 356 | 357 | def resetOutLink(s, portType, link): 358 | s.setOutLink(portType, link) 359 | 360 | 361 | class ParamLink: 362 | def __init__(s, srcTile, dstTile, srcPort, dstPort): 363 | s.srcTile = srcTile 364 | s.dstTile = dstTile 365 | s.srcPort = srcPort 366 | s.dstPort = dstPort 367 | s.disabled = False 368 | s.srcTile.resetOutLink(s.srcPort, s) 369 | s.dstTile.resetInLink(s.dstPort, s) 370 | s.mapping = set() 371 | 372 | def getMemReadPort(s): 373 | if s.isFromMem(): 374 | spm = s.srcTile 375 | return spm.getValidReadPort(s.srcPort) 376 | return -1 377 | 378 | def getMemWritePort(s): 379 | if s.isToMem(): 380 | spm = s.dstTile 381 | return spm.getValidWritePort(s.dstPort) 382 | return -1 383 | 384 | def isToMem(s): 385 | return type(s.dstTile) == ParamSPM 386 | 387 | def isFromMem(s): 388 | return type(s.srcTile) == ParamSPM 389 | 390 | def getSrcXY(s, baseX=0, baseY=0): 391 | if type(s.srcTile) != ParamSPM: 392 | return s.srcTile.getPosXYOnPort(s.srcPort, baseX, baseY) 393 | else: 394 | dstPosX, dstPosY = s.dstTile.getPosXYOnPort(s.dstPort, baseX, baseY) 395 | spmPosX = s.srcTile.getPosX(baseX) 396 | return spmPosX, dstPosY 397 | 398 | def getDstXY(s, baseX=0, baseY=0): 399 | if type(s.dstTile) != ParamSPM: 400 | return s.dstTile.getPosXYOnPort(s.dstPort, baseX, baseY) 401 | else: 402 | srcPosX, srcPosY = s.srcTile.getPosXYOnPort(s.srcPort, baseX, baseY) 403 | spmPosX = s.dstTile.getPosX(baseX) 404 | return spmPosX, srcPosY 405 | 406 | 407 | class ParamCGRA: 408 | def __init__(s, rows, columns, configMemSize=CONFIG_MEM_SIZE, dataMemSize=DATA_MEM_SIZE): 409 | s.rows = rows 410 | s.columns = columns 411 | s.configMemSize = configMemSize 412 | s.dataMemSize = dataMemSize 413 | s.tiles = [] 414 | s.templateLinks = [] 415 | s.updatedLinks = [] 416 | s.targetTileID = 0 417 | s.dataSPM = None 418 | s.targetAppName = " Not selected yet" 419 | s.compilationDone = False 420 | s.verilogDone = False 421 | s.targetKernels = [] 422 | s.targetKernelName = None 423 | s.DFGNodeCount = -1 424 | s.resMII = -1 425 | s.recMII = -1 426 | 427 | # return error message if the model is not valid 428 | def getErrorMessage(s): 429 | # at least one tile can perform mem acess 430 | memExist = False 431 | # at least one tile exists 432 | tileExist = False 433 | for tile in s.tiles: 434 | if not tile.disabled: 435 | tileExist = True 436 | # a tile contains at least one FU 437 | fuExist = False 438 | # the tile connect to mem need to able to access mem 439 | if tile.hasToMem() or tile.hasFromMem(): 440 | # for now, the compiler doesn't support seperate read or write, both of them need to locate in the same tile 441 | if tile.hasToMem() and tile.hasFromMem() and tile.fuDict["Ld"] == 1 and tile.fuDict["St"] == 1: 442 | memExist = True 443 | else: 444 | return "Tile " + str(tile.ID) + " needs to contain the Load/Store functional units." 445 | 446 | for fuType in fuTypeList: 447 | if tile.fuDict[fuType] == 1: 448 | fuExist = True 449 | if not fuExist: 450 | return "At least one functional unit needs to exist in tile " + str(tile.ID) + "." 451 | 452 | if not tileExist: 453 | return "At least one tile needs to exist in the CGRA." 454 | 455 | if not memExist: 456 | return "At least one tile including a Load/Store functional unit needs to directly connect to the data SPM." 457 | 458 | return "" 459 | 460 | def getValidTiles(s): 461 | validTiles = [] 462 | for tile in s.tiles: 463 | if not tile.disabled: 464 | validTiles.append(tile) 465 | return validTiles 466 | 467 | def getValidLinks(s): 468 | validLinks = [] 469 | for link in s.updatedLinks: 470 | if not link.disabled and not link.srcTile.disabled and not link.dstTile.disabled: 471 | validLinks.append(link) 472 | return validLinks 473 | 474 | def updateFuXbarPannel(s): 475 | targetTile = s.getTileOfID(s.targetTileID) 476 | for fuType in fuTypeList: 477 | if fuType in fuCheckVars: 478 | fuCheckVars[fuType].set(targetTile.fuDict[fuType]) 479 | 480 | for xbarType in xbarTypeList: 481 | if xbarType in xbarCheckVars: 482 | xbarCheckVars[xbarType].set(targetTile.xbarDict[xbarType]) 483 | 484 | def initDataSPM(s, dataSPM): 485 | s.dataSPM = dataSPM 486 | 487 | def updateMemSize(s, configMemSize, dataMemSize): 488 | s.configMemSize = configMemSize 489 | s.dataMemSize = dataMemSize 490 | 491 | def initTiles(s, tiles): 492 | for r in range(s.rows): 493 | for c in range(s.columns): 494 | s.tiles.append(tiles[r][c]) 495 | 496 | def addTile(s, tile): 497 | s.tiles.append(tile) 498 | 499 | def initTemplateLinks(s, links): 500 | numOfLinks = s.rows * s.columns * 2 + (s.rows - 1) * s.columns * 2 + (s.rows - 1) * (s.columns - 1) * 2 * 2 501 | 502 | for link in links: 503 | s.templateLinks.append(link) 504 | 505 | def resetTiles(s): 506 | 507 | for tile in s.tiles: 508 | tile.reset() 509 | 510 | for fuType in fuTypeList: 511 | fuCheckVars[fuType].set(tile.fuDict[fuType]) 512 | fuCheckbuttons[fuType].configure(state="normal") 513 | 514 | for xbarType in xbarTypeList: 515 | xbarCheckVars[xbarType].set(tile.xbarDict[xbarType]) 516 | xbarCheckbuttons[xbarType].configure(state="normal") 517 | 518 | def enableAllTemplateLinks(s): 519 | for link in s.templateLinks: 520 | link.disabled = False 521 | 522 | def resetLinks(s): 523 | for link in s.templateLinks: 524 | link.disabled = False 525 | link.srcTile.resetOutLink(link.srcPort, link) 526 | link.dstTile.resetInLink(link.dstPort, link) 527 | link.mapping = set() 528 | 529 | s.updatedLinks = s.templateLinks[:] 530 | 531 | for portType in range(PORT_DIRECTION_COUNTS): 532 | if portType in s.getTileOfID(s.targetTileID).neverUsedOutPorts: 533 | xbarCheckbuttons[xbarPort2Type[portType]].configure(state="disabled") 534 | 535 | def addTemplateLink(s, link): 536 | s.templateLinks.append(link) 537 | 538 | def addUpdatedLink(s, link): 539 | s.updatedLinks.append(link) 540 | 541 | def removeUpdatedLink(s, link): 542 | s.updatedLinks.remove(link) 543 | # src = link.srcTile 544 | # src.xbarDict[link.srcPort] = 0 545 | 546 | def updateFuCheckbutton(s, fuType, value): 547 | tile = s.getTileOfID(s.targetTileID) 548 | tile.fuDict[fuType] = value 549 | 550 | def updateXbarCheckbutton(s, xbarType, value): 551 | tile = s.getTileOfID(s.targetTileID) 552 | tile.xbarDict[xbarType] = value 553 | port = xbarType2Port[xbarType] 554 | if port in tile.outLinks: 555 | tile.outLinks[port].disabled = True if value == 0 else False 556 | 557 | def getTileOfID(s, ID): 558 | for tile in s.tiles: 559 | if tile.ID == ID: 560 | return tile 561 | return None 562 | 563 | def getTileOfDim(s, dimX, dimY): 564 | for tile in s.tiles: 565 | if tile.dimX == dimX and tile.dimY == dimY: 566 | return tile 567 | return None 568 | 569 | # tiles could be disabled due to the disabled links 570 | def updateTiles(s): 571 | unreachableTiles = set() 572 | for tile in s.tiles: 573 | unreachableTiles.add(tile) 574 | 575 | for link in s.updatedLinks: 576 | if link.disabled == False and type(link.dstTile) == ParamTile: 577 | if link.dstTile in unreachableTiles: 578 | unreachableTiles.remove(link.dstTile) 579 | if len(unreachableTiles) == 0: 580 | break 581 | 582 | for tile in unreachableTiles: 583 | tile.disabled = True 584 | 585 | def getUpdatedLink(s, srcTile, dstTile): 586 | for link in s.updatedLinks: 587 | if link.srcTile == srcTile and link.dstTile == dstTile: 588 | return link 589 | return None 590 | 591 | # TODO: also need to consider adding back after removing... 592 | def updateLinks(s): 593 | needRemoveLinks = set() 594 | for link in s.updatedLinks: 595 | if link.disabled: 596 | needRemoveLinks.add((link.srcTile, link.dstTile)) 597 | 598 | for link in s.templateLinks: 599 | link.srcTile.setOutLink(link.srcPort, link) 600 | link.dstTile.setInLink(link.dstPort, link) 601 | s.updatedLinks = s.templateLinks[:] 602 | 603 | for tile in s.tiles: 604 | if tile.disabled: 605 | for portType in tile.outLinks: 606 | outLink = tile.outLinks[portType] 607 | dstNeiTile = outLink.dstTile 608 | oppositePort = xbarPortOpposites[portType] 609 | if oppositePort in tile.inLinks: 610 | inLink = tile.inLinks[oppositePort] 611 | srcNeiTile = inLink.srcTile 612 | 613 | # some links can be fused as single one due to disabled tiles 614 | if not inLink.disabled and not outLink.disabled and inLink in s.updatedLinks and outLink in s.updatedLinks: 615 | updatedLink = ParamLink(srcNeiTile, dstNeiTile, inLink.srcPort, outLink.dstPort) 616 | s.addUpdatedLink(updatedLink) 617 | s.removeUpdatedLink(inLink) 618 | s.removeUpdatedLink(outLink) 619 | # links that are disabled need to be removed 620 | if inLink.disabled and inLink in s.updatedLinks: 621 | s.removeUpdatedLink(inLink) 622 | if outLink.disabled and outLink in s.updatedLinks: 623 | s.removeUpdatedLink(outLink) 624 | 625 | else: 626 | if outLink in s.updatedLinks: 627 | s.removeUpdatedLink(outLink) 628 | 629 | for portType in tile.outLinks: 630 | outLink = tile.outLinks[portType] 631 | if outLink in s.updatedLinks: 632 | s.removeUpdatedLink(outLink) 633 | 634 | for portType in tile.inLinks: 635 | inLink = tile.inLinks[portType] 636 | if inLink in s.updatedLinks: 637 | s.removeUpdatedLink(inLink) 638 | 639 | for link in s.updatedLinks: 640 | if (link.srcTile, link.dstTile) in needRemoveLinks: 641 | link.disabled = True 642 | if type(link.srcTile) == ParamTile: 643 | link.srcTile.xbarDict[xbarPort2Type[link.srcPort]] = 0 644 | 645 | def updateSpmOutlinks(s): 646 | spmOutlinksSwitches = widgets['spmOutlinksSwitches'] 647 | spmConfigPannel = widgets["spmConfigPannel"] 648 | for switch in spmOutlinksSwitches: 649 | switch.destroy() 650 | for port in paramCGRA.dataSPM.outLinks: 651 | switch = customtkinter.CTkSwitch(spmConfigPannel, text=f"link {port}", command=switchDataSPMOutLinks) 652 | if not paramCGRA.dataSPM.outLinks[port].disabled: 653 | switch.select() 654 | switch.pack(pady=(5, 10)) 655 | spmOutlinksSwitches.insert(0, switch) 656 | 657 | class ToolTip(object): 658 | 659 | def __init__(self, widget): 660 | self.widget = widget 661 | self.tipwindow = None 662 | self.id = None 663 | self.x = self.y = 0 664 | 665 | def showtip(self, text): 666 | "Display text in tooltip window" 667 | self.text = text 668 | if self.tipwindow or not self.text: 669 | return 670 | x, y, cx, cy = self.widget.bbox("insert") 671 | x = x + self.widget.winfo_rootx() + 57 672 | y = y + cy + self.widget.winfo_rooty() + 27 673 | # self.tipwindow = tw = tkinter.Toplevel(self.widget) 674 | self.tipwindow = tw = customtkinter.CTkToplevel(self.widget) 675 | tw.wm_overrideredirect(1) 676 | tw.wm_geometry("+%d+%d" % (x, y)) 677 | # label = tkinter.Label(tw, text=self.text, justify=tkinter.LEFT, 678 | # background="#ffffe0", relief=tkinter.SOLID, borderwidth=1, 679 | # font=("tahoma", "8", "normal")) 680 | label = customtkinter.CTkLabel(tw, text=self.text) 681 | label.pack(ipadx=1) 682 | 683 | def hidetip(self): 684 | tw = self.tipwindow 685 | self.tipwindow = None 686 | if tw: 687 | tw.destroy() 688 | 689 | 690 | def CreateToolTip(widget, text): 691 | toolTip = ToolTip(widget) 692 | 693 | def enter(event): 694 | toolTip.showtip(text) 695 | 696 | def leave(event): 697 | toolTip.hidetip() 698 | 699 | widget.bind('', enter) 700 | widget.bind('', leave) 701 | 702 | 703 | paramCGRA = ParamCGRA(ROWS, COLS, CONFIG_MEM_SIZE, DATA_MEM_SIZE) 704 | 705 | 706 | def clickTile(ID): 707 | # widgets["fuConfigPannel"].configure(text='Tile ' + str(ID) + ' functional units') 708 | widgets["fuConfigPannel"].configure(label_text='Tile ' + str(ID) + '\nfunctional units') 709 | # widgets["xbarConfigPannel"].config(text='Tile ' + str(ID) + ' crossbar outgoing links') 710 | widgets["xbarConfigPannel"].configure(label_text='Tile ' + str(ID) + '\ncrossbar outgoing links') 711 | widgets["xbarCentralTilelabel"].configure(text='Tile ' + str(ID)) 712 | # print(widgets['spmOutlinksSwitches']) 713 | # After clicking the tile, the pannel will fill all directions 714 | # widgets["xbarConfigPannel"].grid(columnspan=4, row=9, column=0, rowspan=3, sticky="nsew") 715 | widgets["entireTileCheckbutton"].configure(text='Disable entire Tile ' + str(ID), state="normal") 716 | # widgets["spmConfigPannel"].grid_forget() 717 | paramCGRA.targetTileID = ID 718 | 719 | disabled = paramCGRA.getTileOfID(ID).disabled 720 | for fuType in fuTypeList: 721 | fuCheckVars[fuType].set(paramCGRA.tiles[ID].fuDict[fuType]) 722 | fuCheckbuttons[fuType].configure(state="disabled" if disabled else "normal") 723 | 724 | for xbarType in xbarTypeList: 725 | xbarCheckVars[xbarType].set(paramCGRA.tiles[ID].xbarDict[xbarType]) 726 | xbarCheckbuttons[xbarType].configure(state="disabled" if disabled or xbarType2Port[xbarType] in paramCGRA.tiles[ 727 | ID].neverUsedOutPorts else "normal") 728 | 729 | entireTileCheckVar.set(1 if paramCGRA.getTileOfID(ID).disabled else 0) 730 | 731 | 732 | def clickSPM(): 733 | print('clickSPM') 734 | # widgets["fuConfigPannel"].config(text='Tile ' + str(paramCGRA.targetTileID) + ' functional units') 735 | # widgets["fuConfigPannelLabel"].configure(text='Tile ' + str(paramCGRA.targetTileID) + ' functional units') 736 | # 737 | # for fuType in fuTypeList: 738 | # fuCheckVars[fuType].set(paramCGRA.tiles[paramCGRA.targetTileID].fuDict[fuType]) 739 | # fuCheckbuttons[fuType].configure(state="disabled") 740 | # 741 | # widgets["xbarConfigPannel"].grid_forget() 742 | # 743 | # spmConfigPannel = widgets["spmConfigPannel"] 744 | # spmConfigPannel.config(text='DataSPM outgoing links') 745 | # # After clicking the SPM, the pannel will fill all directions 746 | # spmConfigPannel.grid(row=9, column=0, rowspan=3, columnspan=4, sticky="nsew") 747 | # 748 | # spmEnabledListbox = widgets["spmEnabledListbox"] 749 | # spmDisabledListbox = widgets["spmDisabledListbox"] 750 | # 751 | # widgets["entireTileCheckbutton"].configure(text='Disable entire Tile ' + str(paramCGRA.targetTileID), state="disabled") 752 | 753 | 754 | def switchDataSPMOutLinks(): 755 | spmOutlinksSwitches = widgets['spmOutlinksSwitches'] 756 | for portIdx, switch in enumerate(spmOutlinksSwitches): 757 | link = paramCGRA.dataSPM.outLinks[portIdx] 758 | if switch.get(): 759 | link.disabled = False 760 | else: 761 | link.disabled = True 762 | 763 | 764 | 765 | 766 | 767 | def clickSPMPortDisable(): 768 | spmEnabledListbox = widgets["spmEnabledListbox"] 769 | portIndex = spmEnabledListbox.curselection() 770 | if portIndex: 771 | port = spmEnabledListbox.get(portIndex) 772 | spmEnabledListbox.delete(portIndex) 773 | widgets["spmDisabledListbox"].insert(0, port) 774 | 775 | link = paramCGRA.dataSPM.outLinks[port] 776 | link.disabled = True 777 | 778 | 779 | def clickSPMPortEnable(): 780 | spmDisabledListbox = widgets["spmDisabledListbox"] 781 | portIndex = spmDisabledListbox.curselection() 782 | if portIndex: 783 | port = spmDisabledListbox.get(portIndex) 784 | spmDisabledListbox.delete(portIndex) 785 | 786 | widgets["spmEnabledListbox"].insert(0, port) 787 | 788 | link = paramCGRA.dataSPM.outLinks[port] 789 | link.disabled = False 790 | 791 | 792 | def clickEntireTileCheckbutton(): 793 | if entireTileCheckVar.get() == 1: 794 | 795 | for fuType in fuTypeList: 796 | fuCheckVars[fuType].set(0) 797 | tile = paramCGRA.getTileOfID(paramCGRA.targetTileID) 798 | tile.fuDict[fuType] = 0 799 | # clickFuCheckbutton(fuType) 800 | fuCheckbuttons[fuType].configure(state="disabled") 801 | 802 | paramCGRA.getTileOfID(paramCGRA.targetTileID).disabled = True 803 | else: 804 | for fuType in fuTypeList: 805 | fuCheckVars[fuType].set(0) 806 | tile = paramCGRA.getTileOfID(paramCGRA.targetTileID) 807 | tile.fuDict[fuType] = 0 808 | # clickFuCheckbutton(fuType) 809 | fuCheckbuttons[fuType].configure(state="normal") 810 | 811 | # paramCGRA.getTileOfID(paramCGRA.targetTileID).disabled = False 812 | 813 | 814 | def clickFuCheckbutton(fuType): 815 | if fuType == "Ld": 816 | fuCheckVars["St"].set(fuCheckVars["Ld"].get()) 817 | paramCGRA.updateFuCheckbutton("St", fuCheckVars["St"].get()) 818 | elif fuType == "St": 819 | fuCheckVars["Ld"].set(fuCheckVars["St"].get()) 820 | paramCGRA.updateFuCheckbutton("Ld", fuCheckVars["Ld"].get()) 821 | paramCGRA.updateFuCheckbutton(fuType, fuCheckVars[fuType].get()) 822 | 823 | 824 | def clickXbarCheckbutton(xbarType): 825 | paramCGRA.updateXbarCheckbutton(xbarType, xbarCheckVars[xbarType].get()) 826 | 827 | 828 | def clickUpdate(root): 829 | rows = int(widgets["rowsEntry"].get()) 830 | columns = int(widgets["columnsEntry"].get()) 831 | configMemSize = int(widgets["configMemEntry"].get()) 832 | dataMemSize = int(widgets["dataMemEntry"].get()) 833 | 834 | global paramCGRA 835 | oldCGRA = paramCGRA 836 | 837 | old_rows_num = paramCGRA.rows 838 | if paramCGRA.rows != rows or paramCGRA.columns != columns: 839 | paramCGRA = ParamCGRA(rows, columns) 840 | 841 | # dataSPM = ParamSPM(MEM_WIDTH, rows, rows) 842 | # paramCGRA.initDataSPM(dataSPM) 843 | 844 | create_cgra_pannel(root, rows, columns) 845 | 846 | # kernel related information and be kept to avoid redundant compilation 847 | paramCGRA.updateMemSize(configMemSize, dataMemSize) 848 | paramCGRA.updateTiles() 849 | paramCGRA.updateLinks() 850 | if old_rows_num != rows: 851 | paramCGRA.updateSpmOutlinks() 852 | 853 | paramCGRA.targetAppName = oldCGRA.targetAppName 854 | paramCGRA.compilationDone = oldCGRA.compilationDone 855 | paramCGRA.targetKernels = oldCGRA.targetKernels 856 | paramCGRA.targetKernelName = oldCGRA.targetKernelName 857 | paramCGRA.DFGNodeCount = oldCGRA.DFGNodeCount 858 | paramCGRA.recMII = oldCGRA.recMII 859 | paramCGRA.verilogDone = False 860 | 861 | widgets["verilogText"].delete("1.0", tkinter.END) 862 | widgets["resMIIEntry"].delete(0, tkinter.END) 863 | if len(paramCGRA.getValidTiles()) > 0 and paramCGRA.DFGNodeCount > 0: 864 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount + 0.0) / len(paramCGRA.getValidTiles())) // 1 865 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 866 | else: 867 | widgets["resMIIEntry"].insert(0, 0) 868 | 869 | 870 | def clickReset(root): 871 | rows = int(widgets["rowsEntry"].get()) 872 | columns = int(widgets["columnsEntry"].get()) 873 | configMemSize = int(widgets["configMemEntry"].get()) 874 | dataMemSize = int(widgets["dataMemEntry"].get()) 875 | 876 | global paramCGRA 877 | oldCGRA = paramCGRA 878 | 879 | if paramCGRA.rows != rows or paramCGRA.columns != columns: 880 | paramCGRA = ParamCGRA(rows, columns) 881 | 882 | paramCGRA.updateMemSize(configMemSize, dataMemSize) 883 | paramCGRA.resetTiles() 884 | paramCGRA.enableAllTemplateLinks() 885 | paramCGRA.resetLinks() 886 | 887 | paramCGRA.updateSpmOutlinks() 888 | 889 | create_cgra_pannel(root, rows, columns) 890 | 891 | # for _ in range(paramCGRA.rows): 892 | # widgets["spmEnabledListbox"].delete(0) 893 | # widgets["spmDisabledListbox"].delete(0) 894 | 895 | # widgets['spmOutlinksSwitches'] = [] 896 | # spmOutlinksSwitches = [] 897 | # spmConfigPannel = widgets["spmConfigPannel"] 898 | # for port in paramCGRA.dataSPM.outLinks: 899 | # switch = customtkinter.CTkSwitch(spmConfigPannel, text=f"link {port}", command=switchDataSPMOutLinks) 900 | # if not paramCGRA.dataSPM.outLinks[port].disabled: 901 | # switch.select() 902 | # switch.pack(pady=(5, 10)) 903 | # spmOutlinksSwitches.insert(0, switch) 904 | # widgets['spmOutlinksSwitches'] = spmOutlinksSwitches 905 | 906 | # kernel related information and be kept to avoid redundant compilation 907 | paramCGRA.targetAppName = oldCGRA.targetAppName 908 | paramCGRA.compilationDone = oldCGRA.compilationDone 909 | paramCGRA.targetKernels = oldCGRA.targetKernels 910 | paramCGRA.targetKernelName = oldCGRA.targetKernelName 911 | paramCGRA.DFGNodeCount = oldCGRA.DFGNodeCount 912 | paramCGRA.recMII = oldCGRA.recMII 913 | 914 | widgets["verilogText"].delete(0, tkinter.END) 915 | widgets["resMIIEntry"].delete(0, tkinter.END) 916 | if len(paramCGRA.getValidTiles()) > 0 and paramCGRA.DFGNodeCount > 0: 917 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount + 0.0) / len(paramCGRA.getValidTiles())) // 1 918 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 919 | else: 920 | widgets["resMIIEntry"].insert(0, 0) 921 | 922 | 923 | def clickTest(): 924 | # need to provide the paths for lib.so and kernel.bc 925 | os.system("mkdir test") 926 | # os.system("cd test") 927 | os.chdir("test") 928 | 929 | widgets["testShow"].configure(text="0%") 930 | master.update_idletasks() 931 | 932 | # os.system("pytest ../../VectorCGRA") 933 | testProc = subprocess.Popen(["pytest ../../VectorCGRA", '-u'], stdout=subprocess.PIPE, shell=True, bufsize=1) 934 | failed = 0 935 | total = 0 936 | with testProc.stdout: 937 | for line in iter(testProc.stdout.readline, b''): 938 | outputLine = line.decode("ISO-8859-1") 939 | print(outputLine) 940 | if "%]" in outputLine: 941 | value = int(outputLine.split("[")[1].split("%]")[0]) 942 | # print(f'testProgress value: {value}') 943 | widgets["testProgress"].set(value/100) 944 | widgets["testShow"].configure(text=str(value) + "%") 945 | master.update_idletasks() 946 | total += 1 947 | if ".py F" in outputLine: 948 | failed += 1 949 | 950 | widgets["testShow"].configure(text=" PASSED " if failed == 0 else str(total - failed) + "/" + str(total)) 951 | # (out, err) = testProc.communicate() 952 | # print("check test output:", out) 953 | 954 | os.chdir("..") 955 | 956 | 957 | def clickGenerateVerilog(): 958 | message = paramCGRA.getErrorMessage() 959 | if message != "": 960 | tkinter.messagebox.showerror(title="CGRA Model Checking", message=message) 961 | return 962 | 963 | os.system("mkdir verilog") 964 | os.chdir("verilog") 965 | 966 | # pymtl function that is used to generate synthesizable verilog 967 | cmdline_opts = {'test_verilog': 'zeros', 'test_yosys_verilog': '', 'dump_textwave': False, 'dump_vcd': False, 968 | 'dump_vtb': False, 'max_cycles': None} 969 | test_cgra_universal(paramCGRA = paramCGRA) 970 | 971 | widgets["verilogText"].delete("1.0", tkinter.END) 972 | found = False 973 | print(os.listdir("./")) 974 | for fileName in os.listdir("./"): 975 | if "__" in fileName and ".v" in fileName: 976 | print("Found the file: ", fileName) 977 | f = open(fileName, "r") 978 | widgets["verilogText"].insert("1.0", f.read()) 979 | found = True 980 | break 981 | 982 | paramCGRA.verilogDone = True 983 | if not found: 984 | paramCGRA.verilogDone = False 985 | widgets["verilogText"].insert(tkinter.END, "Error exists during Verilog generation") 986 | 987 | os.system("mv CGRATemplateRTL__*.v design.v") 988 | # os.system("rename s/\.v/\.log/g *") 989 | 990 | os.chdir("..") 991 | 992 | 993 | def setReportProgress(value): 994 | # widgets["reportProgress"].configure(value=value) 995 | widgets["reportProgress"].set(value/100) 996 | 997 | 998 | def countSynthesisTime(): 999 | global synthesisRunning 1000 | timeCost = 0.0 1001 | while synthesisRunning: 1002 | time.sleep(0.1) 1003 | widgets["synthesisTimeEntry"].delete(0, tkinter.END) 1004 | widgets["synthesisTimeEntry"].insert(0, round(timeCost, 1)) 1005 | timeCost += 0.1 1006 | 1007 | 1008 | def runYosys(): 1009 | global synthesisRunning 1010 | os.system("make 3") 1011 | 1012 | statsFile = open("3-open-yosys-synthesis/stats.txt", 'r') 1013 | statsLines = statsFile.readlines() 1014 | 1015 | tileArea = 0.0 1016 | for line in statsLines: 1017 | if "Chip area for module " in line: 1018 | tileArea = round(float(line.split(": ")[1]) / 1000000, 2) 1019 | break 1020 | 1021 | statsFile.close() 1022 | 1023 | widgets["reportTileAreaData"].delete(0, tkinter.END) 1024 | widgets["reportTileAreaData"].insert(0, tileArea) 1025 | 1026 | widgets["reportTilePowerData"].delete(0, tkinter.END) 1027 | widgets["reportTilePowerData"].insert(0, "-") 1028 | 1029 | # widgets["reportProgress"].configure(value=100) 1030 | widgets["reportProgress"].set(1) 1031 | 1032 | os.chdir("../../../build") 1033 | 1034 | synthesisRunning = False 1035 | 1036 | 1037 | def clickSynthesize(): 1038 | global paramCGRA 1039 | global synthesisRunning 1040 | 1041 | if synthesisRunning: 1042 | return 1043 | 1044 | if not paramCGRA.verilogDone: 1045 | tkinter.messagebox.showerror(title="Sythesis", message="The verilog generation needs to be done first.") 1046 | return 1047 | 1048 | synthesisRunning = True 1049 | synthesisTimerRun = threading.Thread(target=countSynthesisTime) 1050 | synthesisTimerRun.start() 1051 | 1052 | os.system("mkdir verilog") 1053 | os.chdir("verilog") 1054 | 1055 | # Cacti SPM power/area estimation: 1056 | sizePattern = "[SPM_SIZE]" 1057 | readPortPattern = "[READ_PORT_COUNT]" 1058 | writePortPattern = "[WRITE_PORT_COUNT]" 1059 | 1060 | updatedSizePattern = str(paramCGRA.dataMemSize * 1024) 1061 | updatedReadPortPattern = str(paramCGRA.dataSPM.getNumOfValidReadPorts()) 1062 | updatedWritePortPattern = str(paramCGRA.dataSPM.getNumOfValidWritePorts()) 1063 | 1064 | with open(r'../../tools/cacti/spm_template.cfg', 'r') as file: 1065 | data = file.read() 1066 | 1067 | data = data.replace(sizePattern, updatedSizePattern) 1068 | data = data.replace(readPortPattern, updatedReadPortPattern) 1069 | data = data.replace(writePortPattern, updatedWritePortPattern) 1070 | 1071 | with open(r'../../tools/cacti/spm_temp.cfg', 'w') as file: 1072 | file.write(data) 1073 | 1074 | os.chdir("../../tools/cacti") 1075 | 1076 | cactiCommand = "./cacti -infile spm_temp.cfg" 1077 | cactiProc = subprocess.Popen([cactiCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, 1078 | bufsize=1) 1079 | (out, err) = cactiProc.communicate() 1080 | success = False 1081 | line = out.decode("ISO-8859-1") 1082 | 1083 | if "Power Components:" in line: 1084 | success = True 1085 | strSPMPower = line.split("Data array: Total dynamic read energy/access (nJ): ")[1].split("\n")[0] 1086 | strSPMTiming = line.split("Data side (with Output driver) (ns): ")[1].split("\n")[0] 1087 | spmPower = float(strSPMPower) / float(strSPMTiming) * 1000 1088 | 1089 | widgets["reportSPMPowerData"].delete(0, tkinter.END) 1090 | widgets["reportSPMPowerData"].insert(0, str(spmPower)) 1091 | 1092 | strSPMArea = line.split("Data array: Area (mm2): ")[1].split("\n")[0] 1093 | spmArea = float(strSPMArea) 1094 | 1095 | widgets["reportSPMAreaData"].delete(0, tkinter.END) 1096 | widgets["reportSPMAreaData"].insert(0, str(spmArea)) 1097 | 1098 | 1099 | else: 1100 | tkinter.messagebox.showerror(title="Sythesis", message="Execution of Cacti failed.") 1101 | 1102 | progress = threading.Thread(target=setReportProgress, args=[20]) 1103 | progress.start() 1104 | 1105 | os.chdir("../../build/verilog") 1106 | # mflowgen synthesis: 1107 | os.system("../../tools/sv2v/bin/sv2v design.v > design_sv2v.v") 1108 | progress = threading.Thread(target=setReportProgress, args=[40]) 1109 | progress.start() 1110 | 1111 | os.system("sed -i 's/CGRATemplateRTL__.*/CGRATemplateRTL (/g' design_sv2v.v") 1112 | progress = threading.Thread(target=setReportProgress, args=[50]) 1113 | progress.start() 1114 | 1115 | # os.system("mv design.v ../../mflowgen1/designs/cgra/rtl/outputs/design.v") 1116 | os.system("cp design_sv2v.v ../../tools/mflowgen/designs/cgra/rtl/outputs/design.v") 1117 | os.chdir("../../tools/mflowgen") 1118 | os.system("mkdir ./build") 1119 | os.chdir("./build") 1120 | os.system("rm -r ./*") 1121 | os.system("mflowgen run --design ../designs/cgra") 1122 | 1123 | os.system("make 2") 1124 | progress = threading.Thread(target=setReportProgress, args=[70]) 1125 | progress.start() 1126 | 1127 | yosysRun = threading.Thread(target=runYosys) 1128 | yosysRun.start() 1129 | 1130 | 1131 | def clickSelectApp(event): 1132 | global paramCGRA 1133 | paramCGRA.compilationDone = False 1134 | appName = fd.askopenfilename(title="choose an application", initialdir="../", filetypes=( 1135 | ("C/C++ file", "*.cpp"), ("C/C++ file", "*.c"), ("C/C++ file", "*.C"), ("C/C++ file", "*.CPP"))) 1136 | paramCGRA.targetAppName = appName 1137 | 1138 | # widgets["appPathEntry"].configure(state="normal") 1139 | widgets["appPathEntry"].delete(0, tkinter.END) 1140 | widgets["appPathEntry"].insert(0, paramCGRA.targetAppName) 1141 | # widgets["appPathEntry"].configure(state="disabled") 1142 | 1143 | widgets["compileAppShow"].configure(text="IDLE") 1144 | 1145 | 1146 | def clickCompileApp(): 1147 | global paramCGRA 1148 | fileName = paramCGRA.targetAppName 1149 | if not fileName or fileName == " Not selected yet": 1150 | return 1151 | 1152 | os.system("mkdir kernel") 1153 | os.chdir("kernel") 1154 | 1155 | compileCommand = "clang-12 -emit-llvm -fno-unroll-loops -O3 -o kernel.bc -c " + fileName 1156 | compileProc = subprocess.Popen([compileCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1157 | (compileOut, compileErr) = compileProc.communicate() 1158 | 1159 | disassembleCommand = "llvm-dis-12 kernel.bc -o kernel.ll" 1160 | disassembleProc = subprocess.Popen([disassembleCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, 1161 | shell=True) 1162 | (disassembleOut, disassembleErr) = disassembleProc.communicate() 1163 | 1164 | if compileErr: 1165 | widgets["compileAppShow"].configure(text=u'\u2717\u2717\u2717') 1166 | os.chdir("..") 1167 | print("Compile error message: ", compileErr) 1168 | return 1169 | if disassembleErr: 1170 | widgets["compileAppShow"].configure(text=u'\u2717\u2717\u2717') 1171 | os.chdir("..") 1172 | print("Disassemble error message: ", disassembleErr) 1173 | return 1174 | 1175 | widgets["compileAppShow"].configure(text=u'\u2713\u2713\u2713') 1176 | paramCGRA.compilationDone = True 1177 | 1178 | # collect the potentially targeting kernel/function 1179 | irFile = open('kernel.ll', 'r') 1180 | irLines = irFile.readlines() 1181 | 1182 | # Strips the newline character 1183 | paramCGRA.targetKernels = [] 1184 | for line in irLines: 1185 | if "define " in line and "{" in line and "@" in line: 1186 | funcName = line.split("@")[1].split("(")[0] 1187 | if "main" not in funcName: 1188 | paramCGRA.targetKernels.append(funcName) 1189 | 1190 | irFile.close() 1191 | 1192 | kernelNameMenu = widgets["kernelNameMenu"] 1193 | kernelPannel = widgets["kernelPannel"] 1194 | # kernelNameMenu["menu"].delete(0, "end") 1195 | kernelNameMenu.destroy() 1196 | kernelNameOptions = [kernelName for kernelName in paramCGRA.targetKernels] 1197 | kernelNameMenu = customtkinter.CTkOptionMenu(kernelPannel, variable=kernelOptions, values=kernelNameOptions) 1198 | kernelNameMenu.grid(row=2, column=1) 1199 | widgets["kernelNameMenu"] = kernelNameMenu 1200 | # for kernelName in paramCGRA.targetKernels: 1201 | # # kernelNameMenu["menu"].add_command(label=kernelName, command=tkinter._setit(kernelOptions, kernelName)) 1202 | # print(f'kernelName: {kernelName}') 1203 | # options.set(my_list[0]) 1204 | 1205 | widgets["generateDFGShow"].configure(text="IDLE") 1206 | 1207 | os.chdir("..") 1208 | 1209 | 1210 | def clickKernelMenu(*args): 1211 | global paramCGRA 1212 | name = kernelOptions.get() 1213 | if name == None or name == " " or name == "Not selected yet": 1214 | return 1215 | paramCGRA.targetKernelName = name 1216 | 1217 | 1218 | def dumpParamCGRA2JSON(fileName): 1219 | global paramCGRA 1220 | paramCGRAJson = {} 1221 | paramCGRAJson["tiles"] = {} 1222 | for tile in paramCGRA.tiles: 1223 | curDict = {} 1224 | if tile.disabled: 1225 | curDict["disabled"] = True 1226 | else: 1227 | curDict["disabled"] = False 1228 | if tile.isDefaultFus(): 1229 | curDict["supportAllFUs"] = True 1230 | else: 1231 | curDict["supportAllFUs"] = False 1232 | curDict["supportedFUs"] = [] 1233 | for fuType in tile.fuDict: 1234 | if tile.fuDict[fuType] == 1: 1235 | curDict["supportedFUs"].append(fuType) 1236 | 1237 | if (tile.hasFromMem() and tile.fuDict["Ld"] == 1) and \ 1238 | (tile.hasToMem() and tile.fuDict["St"] == 1): 1239 | curDict["accessMem"] = True 1240 | 1241 | paramCGRAJson["tiles"][str(tile.ID)] = curDict 1242 | 1243 | paramCGRAJson["links"] = [] 1244 | for link in paramCGRA.updatedLinks: 1245 | curDict = {} 1246 | srcTile = link.srcTile 1247 | dstTile = link.dstTile 1248 | if not link.disabled and not srcTile.disabled and not dstTile.disabled and type(srcTile) != ParamSPM and type( 1249 | dstTile) != ParamSPM: 1250 | curDict["srcTile"] = srcTile.ID 1251 | curDict["dstTile"] = dstTile.ID 1252 | paramCGRAJson["links"].append(curDict) 1253 | 1254 | paramCGRAJsonObject = json.dumps(paramCGRAJson, indent=4) 1255 | 1256 | # Writing to sample.json 1257 | with open(fileName, "w") as outfile: 1258 | outfile.write(paramCGRAJsonObject) 1259 | 1260 | 1261 | def clickShowDFG(): 1262 | os.system("mkdir kernel") 1263 | os.chdir("kernel") 1264 | fileExist = os.path.exists("kernel.bc") 1265 | global paramCGRA 1266 | 1267 | if not fileExist or not paramCGRA.compilationDone or paramCGRA.targetKernelName == None: 1268 | os.chdir("..") 1269 | tkinter.messagebox.showerror(title="DFG Generation", 1270 | message="The compilation and kernel selection need to be done first.") 1271 | return 1272 | 1273 | paramCGRA.targetKernelName = kernelOptions.get() 1274 | 1275 | genDFGJson = { 1276 | "kernel": paramCGRA.targetKernelName, 1277 | "targetFunction": False, 1278 | "targetNested": True, 1279 | "targetLoopsID": [0], 1280 | "doCGRAMapping": False, 1281 | "row": paramCGRA.rows, 1282 | "column": paramCGRA.columns, 1283 | "precisionAware": False, 1284 | "heterogeneity": False, 1285 | "isTrimmedDemo": True, 1286 | "heuristicMapping": True, 1287 | "parameterizableCGRA": True, 1288 | "diagonalVectorization": False, 1289 | "bypassConstraint": 8, 1290 | "isStaticElasticCGRA": False, 1291 | "ctrlMemConstraint": 200, 1292 | "regConstraint": 12, 1293 | } 1294 | 1295 | json_object = json.dumps(genDFGJson, indent=4) 1296 | 1297 | with open("param.json", "w") as outfile: 1298 | outfile.write(json_object) 1299 | 1300 | dumpParamCGRA2JSON("paramCGRA.json") 1301 | 1302 | genDFGCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1303 | print("trying to run opt-12") 1304 | genDFGProc = subprocess.Popen([genDFGCommand, "-u"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1305 | 1306 | with genDFGProc.stdout: 1307 | for line in iter(genDFGProc.stdout.readline, b''): 1308 | outputLine = line.decode("ISO-8859-1") 1309 | print(outputLine) 1310 | if "DFG node count: " in outputLine: 1311 | paramCGRA.DFGNodeCount = int(outputLine.split("DFG node count: ")[1].split(";")[0]) 1312 | if "[RecMII: " in outputLine: 1313 | paramCGRA.recMII = int(outputLine.split("[RecMII: ")[1].split("]")[0]) 1314 | 1315 | (out, err) = genDFGProc.communicate() 1316 | print("opt-12 out: ", out) 1317 | print("opt-12 err: ", err) 1318 | 1319 | paramCGRA.resMII = math.ceil((paramCGRA.DFGNodeCount + 0.0) / len(paramCGRA.getValidTiles())) // 1 1320 | widgets["resMIIEntry"].delete(0, tkinter.END) 1321 | widgets["resMIIEntry"].insert(0, paramCGRA.resMII) 1322 | 1323 | widgets["recMIIEntry"].delete(0, tkinter.END) 1324 | widgets["recMIIEntry"].insert(0, paramCGRA.recMII) 1325 | 1326 | convertCommand = "dot -Tpng " + paramCGRA.targetKernelName + ".dot -o kernel.png" 1327 | convertProc = subprocess.Popen([convertCommand, "-u"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 1328 | (out, err) = convertProc.communicate() 1329 | 1330 | # Gets the size of the whole window 1331 | master.update_idletasks() 1332 | window_width = master.winfo_width() 1333 | window_height = master.winfo_height() 1334 | 1335 | PIL_image = Image.open("kernel.png") 1336 | ImageFile.LOAD_TRUNCATED_IMAGES = True 1337 | PIL_image_stretched = PIL_image.resize((window_width // 6, window_height // 3), Image.Resampling.BILINEAR) 1338 | PIL_image_stretched = PIL_image_stretched.convert("RGBA") 1339 | datas = PIL_image_stretched.getdata() 1340 | 1341 | new_data = [] 1342 | for item in datas: 1343 | if item[0] == 255 and item[1] == 255 and item[2] == 255: 1344 | # Makes the white parts of the image white 1345 | new_data.append((255, 255, 255, 255)) 1346 | else: 1347 | new_data.append(item) 1348 | PIL_image_stretched.putdata(new_data) 1349 | 1350 | # dfgImage = ImageTk.PhotoImage(PIL_image_stretched) 1351 | dfgImage = customtkinter.CTkImage(PIL_image_stretched, size=(260, 380)) 1352 | images["dfgImage"] = dfgImage # This is important due to the garbage collection would remove local variable of image 1353 | widgets["dfgLabel"].configure(image=dfgImage) 1354 | 1355 | widgets["generateDFGShow"].configure(text=u'\u2713\u2713\u2713') 1356 | 1357 | os.chdir("..") 1358 | 1359 | 1360 | mappingProc = None 1361 | 1362 | 1363 | def countMapTime(): 1364 | global mappingProc 1365 | timeCost = 0.0 1366 | while mappingProc == None or mappingProc.poll() is None: 1367 | time.sleep(0.1) 1368 | widgets["mapTimeEntry"].delete(0, tkinter.END) 1369 | widgets["mapTimeEntry"].insert(0, round(timeCost, 1)) 1370 | timeCost += 0.1 1371 | 1372 | 1373 | def drawSchedule(): 1374 | global mappingProc 1375 | mappingCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1376 | mappingProc = subprocess.Popen(["exec " + mappingCommand, '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, 1377 | shell=True, bufsize=1) 1378 | (out, err) = mappingProc.communicate() 1379 | success = False 1380 | mappingII = -1 1381 | line = out.decode("ISO-8859-1") 1382 | if "Mapping Success" in line: 1383 | success = True 1384 | if "[Mapping II: " in line: 1385 | strMapII = line.split("[Mapping II: ")[1].split("]")[0] 1386 | mappingII = int(strMapII) 1387 | 1388 | if not success or mappingII == -1: 1389 | tkinter.messagebox.showerror(title="DFG mapping", message="Mapping failed.") 1390 | os.chdir("..") 1391 | return 1392 | 1393 | widgets["mapIIEntry"].delete(0, tkinter.END) 1394 | widgets["mapIIEntry"].insert(0, mappingII) 1395 | widgets["mapSpeedupEntry"].delete(0, tkinter.END) 1396 | widgets["mapSpeedupEntry"].insert(0, paramCGRA.DFGNodeCount / mappingII) 1397 | 1398 | # pad contains tile and links 1399 | tileWidth = paramCGRA.tiles[0].width 1400 | tileHeight = paramCGRA.tiles[0].height 1401 | padWidth = tileWidth + LINK_LENGTH 1402 | padHeight = tileHeight + LINK_LENGTH 1403 | baseX = 0 1404 | 1405 | # load schedule.json for mapping demonstration 1406 | f = open("schedule.json") 1407 | schedule = json.load(f) 1408 | 1409 | # Iterating through the json 1410 | for strTileID in schedule["tiles"]: 1411 | tileID = int(strTileID) 1412 | tile = paramCGRA.getTileOfID(tileID) 1413 | for strCycle in schedule["tiles"][strTileID]: 1414 | cycle = int(strCycle) 1415 | optID = schedule["tiles"][strTileID][strCycle] 1416 | tile.mapping[cycle] = optID[0] 1417 | 1418 | for strSrcTileID in schedule["links"]: 1419 | for strDstTileID in schedule["links"][strSrcTileID]: 1420 | srcTile = paramCGRA.getTileOfID(int(strSrcTileID)) 1421 | dstTile = paramCGRA.getTileOfID(int(strDstTileID)) 1422 | link = paramCGRA.getUpdatedLink(srcTile, dstTile) 1423 | for cycle in schedule["links"][strSrcTileID][strDstTileID]: 1424 | link.mapping.add(cycle) 1425 | 1426 | f.close() 1427 | os.chdir("..") 1428 | 1429 | canvas = widgets["mappingCanvas"] 1430 | canvas.delete("all") 1431 | ROWS = widgets["ROWS"] 1432 | COLS = widgets["COLS"] 1433 | GRID_WIDTH = (TILE_WIDTH + LINK_LENGTH) * COLS - LINK_LENGTH 1434 | GRID_HEIGHT = (TILE_HEIGHT + LINK_LENGTH) * ROWS - LINK_LENGTH 1435 | cgraWidth = GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + 20 1436 | canvas.configure(scrollregion=(0, 0, mappingII * cgraWidth, GRID_HEIGHT + 40 + BORDER)) 1437 | 1438 | for ii in range(mappingII): 1439 | # draw data memory 1440 | # spmLabel = tkinter.Label(canvas, text="Data\nSPM", fg='black', bg='gray', relief='raised', bd=BORDER, 1441 | # highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS) 1442 | spmLabel = customtkinter.CTkButton(canvas, text="Data\nSPM", state='disabled', text_color_disabled='white') 1443 | canvas.create_window(baseX + BORDER, BORDER, window=spmLabel, height=GRID_HEIGHT, width=MEM_WIDTH, anchor="nw") 1444 | 1445 | mapped_tile_color = mapped_tile_color_list[ii % len(mapped_tile_color_list)] 1446 | 1447 | # draw tiles 1448 | for tile in paramCGRA.tiles: 1449 | if not tile.disabled: 1450 | button = None 1451 | if ii in tile.mapping: 1452 | # button = tkinter.Label(canvas, text="Opt " + str(tile.mapping[ii]), fg="black", bg="cornflowerblue", 1453 | # relief="raised", bd=BORDER, highlightbackground="black", 1454 | # highlightthickness=HIGHLIGHT_THICKNESS) 1455 | button = customtkinter.CTkButton(canvas, text="Opt " + str(tile.mapping[ii]), state='disabled', 1456 | border_width=2, 1457 | font=customtkinter.CTkFont(weight="bold"), 1458 | text_color_disabled='black', 1459 | fg_color=mapped_tile_color, 1460 | border_color=mapped_tile_color) 1461 | else: 1462 | # button = tkinter.Label(canvas, text="Tile " + str(tile.ID), fg="black", bg="grey", relief="raised", 1463 | # bd=BORDER, highlightbackground="black", 1464 | # highlightthickness=HIGHLIGHT_THICKNESS) 1465 | button = customtkinter.CTkButton(canvas, text="Tile " + str(tile.ID), state='disabled', text_color_disabled='white') 1466 | posX, posY = tile.getPosXY(baseX + BORDER, BORDER) 1467 | canvas.create_window(posX, posY, window=button, height=tileHeight, width=tileWidth, anchor="nw") 1468 | 1469 | # draw links 1470 | for link in paramCGRA.updatedLinks: 1471 | if not link.disabled: 1472 | srcX, srcY = link.getSrcXY(baseX + BORDER, BORDER) 1473 | dstX, dstY = link.getDstXY(baseX + BORDER, BORDER) 1474 | if ii in link.mapping: 1475 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST, width=3, fill=mapped_tile_color) 1476 | else: 1477 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST, fill=CANVAS_LINE_COLOR) 1478 | 1479 | # cycleLabel = tkinter.Label(canvas, text="Cycle " + str(ii)) 1480 | cycleLabel = customtkinter.CTkLabel(canvas, text="Cycle " + str(ii) + " ", 1481 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, weight="bold")) 1482 | canvas.create_window(baseX + (cgraWidth)/2, GRID_HEIGHT + 30 + BORDER, window=cycleLabel, height=20, width=80) 1483 | 1484 | baseX += GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + 20 1485 | canvas.create_line(baseX - 5, INTERVAL, baseX - 5, GRID_HEIGHT, width=2, dash=(10, 2), fill="grey") 1486 | 1487 | 1488 | def clickTerminateMapping(): 1489 | global mappingProc 1490 | if mappingProc == None: 1491 | return 1492 | 1493 | if mappingProc.poll() is None: 1494 | mappingProc.kill() 1495 | 1496 | path = os.getcwd() 1497 | if path.split("\\")[-1] == "kernel": 1498 | os.chdir("..") 1499 | 1500 | 1501 | def clickMapDFG(): 1502 | global mappingProc 1503 | mappingProc = None 1504 | heuristic = mappingAlgoCheckVar.get() == 0 1505 | 1506 | os.system("mkdir kernel") 1507 | os.chdir("kernel") 1508 | fileExist = os.path.exists("kernel.bc") 1509 | global paramCGRA 1510 | 1511 | if not fileExist or not paramCGRA.compilationDone or paramCGRA.targetKernelName == None: 1512 | os.chdir("..") 1513 | # tkinter.messagebox.showerror(title="DFG mapping", message="The compilation and kernel selection need to be done first.") 1514 | if not fileExist: 1515 | tkinter.messagebox.showerror(title="DFG mapping", message="The kernel.bc doesn't exist.") 1516 | if not paramCGRA.compilationDone: 1517 | tkinter.messagebox.showerror(title="DFG mapping", message="The compilation needs to be done first.") 1518 | if paramCGRA.targetKernelName == None: 1519 | tkinter.messagebox.showerror(title="DFG mapping", message="The kernel name is not selected yet.") 1520 | return 1521 | 1522 | mappingJson = { 1523 | "kernel": paramCGRA.targetKernelName, 1524 | "targetFunction": False, 1525 | "targetNested": True, 1526 | "targetLoopsID": [0], 1527 | "doCGRAMapping": True, 1528 | "row": paramCGRA.rows, 1529 | "column": paramCGRA.columns, 1530 | "precisionAware": False, 1531 | "heterogeneity": False, 1532 | "isTrimmedDemo": True, 1533 | "heuristicMapping": heuristic, 1534 | "parameterizableCGRA": True, 1535 | "diagonalVectorization": False, 1536 | "bypassConstraint": 8, 1537 | "isStaticElasticCGRA": False, 1538 | "ctrlMemConstraint": paramCGRA.configMemSize, 1539 | "regConstraint": 12, 1540 | } 1541 | 1542 | mappingJsonObject = json.dumps(mappingJson, indent=4) 1543 | 1544 | with open("param.json", "w") as outfile: 1545 | outfile.write(mappingJsonObject) 1546 | 1547 | dumpParamCGRA2JSON("paramCGRA.json") 1548 | 1549 | mappingCommand = "opt-12 -load ../../CGRA-Mapper/build/src/libmapperPass.so -mapperPass ./kernel.bc" 1550 | 1551 | widgets["mapTimeEntry"].delete(0, tkinter.END) 1552 | widgets["mapTimeEntry"].insert(0, 0) 1553 | 1554 | drawer = threading.Thread(target=drawSchedule) 1555 | drawer.start() 1556 | timer = threading.Thread(target=countMapTime) 1557 | timer.start() 1558 | 1559 | 1560 | def _on_mousewheel(canvas, event): 1561 | platformSystem = platform.system() 1562 | logging.info("Current platform.system: %s", platformSystem) 1563 | if platformSystem == "Windows": 1564 | canvas.yview_scroll(int(-1*(event.delta/120)), "units") 1565 | elif platformSystem == "Linux": 1566 | canvas.yview_scroll(int(-1*(event.delta/120)), "units") 1567 | else: 1568 | canvas.yview_scroll(int(-1*event.delta), "units") 1569 | 1570 | def create_cgra_pannel(master, rows, columns): 1571 | ROWS = rows 1572 | COLS = columns 1573 | widgets["ROWS"] = ROWS 1574 | widgets["COLS"] = COLS 1575 | print(f"create_cgra_pannel - ROWS: {ROWS}, COLS: {COLS}") 1576 | # master.grid_propagate(0) 1577 | # Use solid black board to let the pannel look better 1578 | cgraPannel = customtkinter.CTkFrame(master) 1579 | # cgraPannel = tkinter.LabelFrame(master, text='CGRA', bd=BORDER, relief='groove') 1580 | # cgraPannel.pack() 1581 | # cgraPannel.grid_propagate(0) 1582 | # create label for cgraPannel 1583 | cgraLabel = customtkinter.CTkLabel(cgraPannel, text='CGRA', font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, weight="bold")) 1584 | # cgraLabel.grid(row=0, column=0, sticky="nsew") 1585 | cgraLabel.pack(anchor="w", ipadx=5) 1586 | 1587 | canvas = customtkinter.CTkCanvas(cgraPannel, bg=CANVAS_BG_COLOR, bd=0, highlightthickness=0) 1588 | # with Windows OS 1589 | # canvas.bind_all("", partial(_on_mousewheel, canvas)) 1590 | # with Linux OS 1591 | # canvas.bind_all("", partial(_on_mousewheel, canvas)) 1592 | # canvas.bind_all("", partial(_on_mousewheel, canvas)) 1593 | 1594 | widgets["canvas"] = canvas 1595 | baseX = 0 1596 | 1597 | # construct data memory 1598 | if paramCGRA.dataSPM == None: 1599 | dataSPM = ParamSPM(MEM_WIDTH, rows, rows) 1600 | paramCGRA.initDataSPM(dataSPM) 1601 | 1602 | # pad contains tile and links 1603 | # padSize = TILE_SIZE + LINK_LENGTH 1604 | padHeight = TILE_HEIGHT + LINK_LENGTH 1605 | padWidth = TILE_WIDTH + LINK_LENGTH 1606 | 1607 | GRID_HEIGHT = (TILE_HEIGHT + LINK_LENGTH) * ROWS - LINK_LENGTH 1608 | # draw data memory 1609 | memHeight = GRID_HEIGHT 1610 | # spmLabel = tkinter.Button(canvas, text="Data\nSPM", fg='black', bg='gray', relief='raised', bd=BORDER, 1611 | # command=clickSPM, highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS) 1612 | spmLabel = customtkinter.CTkButton(canvas, text="Data\nSPM", 1613 | #fg='black', bg='gray', relief='raised', bd=BORDER, 1614 | command=clickSPM#, 1615 | #highlightbackground="black", 1616 | #highlightthickness=HIGHLIGHT_THICKNESS 1617 | ) 1618 | # Data memory will be placed in the upper left corner 1619 | canvas.create_window(baseX + BORDER, BORDER, window=spmLabel, height=GRID_HEIGHT, width=MEM_WIDTH, anchor="nw") 1620 | 1621 | # construct tiles 1622 | if len(paramCGRA.tiles) == 0: 1623 | for i in range(ROWS): 1624 | for j in range(COLS): 1625 | ID = i * COLS + j 1626 | posX = padWidth * j + MEM_WIDTH + LINK_LENGTH 1627 | posY = GRID_HEIGHT - padHeight * i - TILE_HEIGHT 1628 | 1629 | tile = ParamTile(ID, j, i, posX, posY, TILE_WIDTH, TILE_HEIGHT) 1630 | paramCGRA.addTile(tile) 1631 | 1632 | # draw tiles 1633 | for tile in paramCGRA.tiles: 1634 | if not tile.disabled: 1635 | # button = tkinter.Button(canvas, text="Tile " + str(tile.ID), fg='black', bg='gray', relief='raised', 1636 | # bd=BORDER, command=partial(clickTile, tile.ID), highlightbackground="black", 1637 | # highlightthickness=HIGHLIGHT_THICKNESS) 1638 | button = customtkinter.CTkButton(canvas, text="Tile " + str(tile.ID), 1639 | # fg='black', bg='gray', relief='raised', bd=BORDER, 1640 | command=partial(clickTile, tile.ID)#, 1641 | # highlightbackground="black", 1642 | # highlightthickness=HIGHLIGHT_THICKNESS 1643 | ) 1644 | posX, posY = tile.getPosXY() 1645 | # Tiles will be placed near the Data memory 1646 | canvas.create_window(posX, posY, window=button, height=TILE_HEIGHT, width=TILE_WIDTH, anchor="nw") 1647 | 1648 | # construct links 1649 | if len(paramCGRA.templateLinks) == 0: 1650 | for i in range(ROWS): 1651 | for j in range(COLS): 1652 | if j < COLS - 1: 1653 | # horizontal 1654 | tile0 = paramCGRA.getTileOfDim(j, i) 1655 | tile1 = paramCGRA.getTileOfDim(j + 1, i) 1656 | link0 = ParamLink(tile0, tile1, PORT_EAST, PORT_WEST) 1657 | link1 = ParamLink(tile1, tile0, PORT_WEST, PORT_EAST) 1658 | paramCGRA.addTemplateLink(link0) 1659 | paramCGRA.addTemplateLink(link1) 1660 | 1661 | if i < ROWS - 1 and j < COLS - 1: 1662 | # diagonal left bottom to right top 1663 | tile0 = paramCGRA.getTileOfDim(j, i) 1664 | tile1 = paramCGRA.getTileOfDim(j + 1, i + 1) 1665 | link0 = ParamLink(tile0, tile1, PORT_NORTHEAST, PORT_SOUTHWEST) 1666 | link1 = ParamLink(tile1, tile0, PORT_SOUTHWEST, PORT_NORTHEAST) 1667 | paramCGRA.addTemplateLink(link0) 1668 | paramCGRA.addTemplateLink(link1) 1669 | 1670 | if i < ROWS - 1 and j > 0: 1671 | # diagonal left top to right bottom 1672 | tile0 = paramCGRA.getTileOfDim(j, i) 1673 | tile1 = paramCGRA.getTileOfDim(j - 1, i + 1) 1674 | link0 = ParamLink(tile0, tile1, PORT_NORTHWEST, PORT_SOUTHEAST) 1675 | link1 = ParamLink(tile1, tile0, PORT_SOUTHEAST, PORT_NORTHWEST) 1676 | paramCGRA.addTemplateLink(link0) 1677 | paramCGRA.addTemplateLink(link1) 1678 | 1679 | if i < ROWS - 1: 1680 | # vertical 1681 | tile0 = paramCGRA.getTileOfDim(j, i) 1682 | tile1 = paramCGRA.getTileOfDim(j, i + 1) 1683 | link0 = ParamLink(tile0, tile1, PORT_NORTH, PORT_SOUTH) 1684 | link1 = ParamLink(tile1, tile0, PORT_SOUTH, PORT_NORTH) 1685 | paramCGRA.addTemplateLink(link0) 1686 | paramCGRA.addTemplateLink(link1) 1687 | 1688 | if j == 0: 1689 | # connect to memory 1690 | tile0 = paramCGRA.getTileOfDim(j, i) 1691 | link0 = ParamLink(tile0, paramCGRA.dataSPM, PORT_WEST, i) 1692 | link1 = ParamLink(paramCGRA.dataSPM, tile0, i, PORT_WEST) 1693 | paramCGRA.addTemplateLink(link0) 1694 | paramCGRA.addTemplateLink(link1) 1695 | 1696 | paramCGRA.updateLinks() 1697 | paramCGRA.updateFuXbarPannel() 1698 | 1699 | # draw links 1700 | for link in paramCGRA.updatedLinks: 1701 | if link.disabled: 1702 | pass 1703 | else: 1704 | srcX, srcY = link.getSrcXY() 1705 | dstX, dstY = link.getDstXY() 1706 | canvas.create_line(srcX, srcY, dstX, dstY, arrow=tkinter.LAST, fill=CANVAS_LINE_COLOR) 1707 | 1708 | vbar = customtkinter.CTkScrollbar(cgraPannel, orientation="vertical", command=canvas.yview) 1709 | vbar.pack(side=tkinter.RIGHT, fill="y") 1710 | canvas.config(yscrollcommand=vbar.set) 1711 | canvas.config(scrollregion=canvas.bbox("all")) 1712 | canvas.pack(side="top", fill="both", expand=True) 1713 | hbar = customtkinter.CTkScrollbar(cgraPannel, orientation="horizontal", command=canvas.xview) 1714 | hbar.pack(side="bottom", fill="x") 1715 | canvas.config(xscrollcommand=hbar.set) 1716 | return cgraPannel 1717 | 1718 | 1719 | def place_fu_options(master): 1720 | fuCount = len(fuTypeList) 1721 | for i in range(len(fuTypeList)): 1722 | fuVar = tkinter.IntVar() 1723 | fuCheckVars[fuTypeList[i]] = fuVar 1724 | fuCheckbutton = customtkinter.CTkCheckBox(master, variable=fuVar, text=fuTypeList[i], 1725 | command=partial(clickFuCheckbutton, fuTypeList[i])) 1726 | fuCheckbuttons[fuTypeList[i]] = fuCheckbutton 1727 | fuCheckbutton.select() 1728 | paramCGRA.updateFuCheckbutton(fuTypeList[i], fuVar.get()) 1729 | fuCheckbutton.grid(row=(i // 2), column=i % 2, pady=6) 1730 | 1731 | 1732 | def place_xbar_options(master): 1733 | for i in range(PORT_DIRECTION_COUNTS): 1734 | portType = i 1735 | xbarType = xbarPort2Type[i] 1736 | xbarVar = tkinter.IntVar() 1737 | xbarCheckVars[xbarType] = xbarVar 1738 | xbarCheckbutton = customtkinter.CTkCheckBox(master, variable=xbarVar, text=xbarType, 1739 | command=partial(clickXbarCheckbutton, xbarType)) 1740 | xbarCheckbuttons[xbarType] = xbarCheckbutton 1741 | 1742 | if paramCGRA.getTileOfID(0).xbarDict[xbarType] == 1: 1743 | xbarCheckbutton.select() 1744 | 1745 | paramCGRA.updateXbarCheckbutton(xbarType, xbarVar.get()) 1746 | 1747 | if portType in paramCGRA.getTileOfID(0).neverUsedOutPorts: 1748 | xbarCheckbutton.configure(state="disabled") 1749 | 1750 | # xbarCheckbutton.grid(row=(i // 3)+1, column=i % 3, padx=15, pady=15, sticky="nsew") 1751 | if i== PORT_NORTH: 1752 | xbarCheckbutton.grid(row=0, column=1, padx=5, pady=(6, 25)) 1753 | elif i== PORT_SOUTH: 1754 | xbarCheckbutton.grid(row=2, column=1, padx=5, pady=25) 1755 | elif i== PORT_WEST: 1756 | xbarCheckbutton.grid(row=1, column=0, padx=5, pady=25) 1757 | elif i== PORT_EAST: 1758 | xbarCheckbutton.grid(row=1, column=2, padx=5, pady=25) 1759 | elif i== PORT_NORTHWEST: 1760 | xbarCheckbutton.grid(row=0, column=0, padx=5, pady=(6, 25)) 1761 | elif i== PORT_NORTHEAST: 1762 | xbarCheckbutton.grid(row=0, column=2, padx=5, pady=(6, 25)) 1763 | elif i== PORT_SOUTHEAST: 1764 | xbarCheckbutton.grid(row=2, column=2, padx=5, pady=25) 1765 | elif i== PORT_SOUTHWEST: 1766 | xbarCheckbutton.grid(row=2, column=0, padx=5, pady=25) 1767 | 1768 | # centralRadioButton = customtkinter.CTkRadioButton(master, text='Tile 0', variable=tkinter.IntVar(value=0)) 1769 | # centralRadioButton.configure(state="disabled") 1770 | # centralRadioButton.grid(row=1, column=1, padx=5, pady=25) 1771 | # widgets["centralRadioButton"] = centralRadioButton 1772 | xbarCentralTilelabel = customtkinter.CTkLabel(master, text='Tile 0', font=customtkinter.CTkFont(weight="bold", underline=True)) 1773 | xbarCentralTilelabel.grid(row=1, column=1, padx=(0, 5), pady=25) 1774 | widgets["xbarCentralTilelabel"] = xbarCentralTilelabel 1775 | 1776 | def create_param_pannel(master): 1777 | # paramPannel = tkinter.LabelFrame(master, text='Configuration', bd=BORDER, relief='groove') 1778 | paramPannel = customtkinter.CTkFrame(master, width=550, height=480) 1779 | 1780 | # Use columnconfigure and rowconfigure to partition the columns, so that each column and row will fill the corresponding space 1781 | # The 'weight' represents the weight of the corresponding row/column length 1782 | for i in range(9): 1783 | paramPannel.rowconfigure(i, weight=1) 1784 | for i in range(3): 1785 | paramPannel.columnconfigure(i, weight=1) 1786 | paramPannel.grid_propagate(0) 1787 | configurationLabel = customtkinter.CTkLabel(paramPannel, text='Configuration', font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, weight="bold")) 1788 | configurationLabel.grid(row=0, column=0, ipadx=5, pady=(5,0), sticky="w") 1789 | 1790 | rowsLabel = customtkinter.CTkLabel(paramPannel, text='Rows Columns:') 1791 | rowsLabel.grid(row=1, column=0) 1792 | rowsEntry = customtkinter.CTkEntry(paramPannel, justify=tkinter.CENTER#, 1793 | #highlightbackground="black", 1794 | #highlightthickness=HIGHLIGHT_THICKNESS 1795 | ) 1796 | rowsEntry.grid(row=1, column=1, padx=5, pady=5) 1797 | rowsEntry.insert(0, str(paramCGRA.rows)) 1798 | widgets["rowsEntry"] = rowsEntry 1799 | columnsEntry = customtkinter.CTkEntry(paramPannel, justify=tkinter.CENTER#, 1800 | #highlightbackground="black", 1801 | #highlightthickness=HIGHLIGHT_THICKNESS 1802 | ) 1803 | columnsEntry.grid(row=1, column=2, padx=2, pady=5) 1804 | columnsEntry.insert(0, str(paramCGRA.columns)) 1805 | widgets["columnsEntry"] = columnsEntry 1806 | 1807 | dataMemLabel = customtkinter.CTkLabel(paramPannel, text='Data SPM (KBs):') 1808 | dataMemLabel.grid(row=2, column=0) 1809 | dataMemEntry = customtkinter.CTkEntry(paramPannel, justify=tkinter.CENTER#, 1810 | #highlightbackground="black", 1811 | #highlightthickness=HIGHLIGHT_THICKNESS 1812 | ) 1813 | dataMemEntry.grid(row=2, column=1, padx=5, pady=5) 1814 | dataMemEntry.insert(0, str(paramCGRA.dataMemSize)) 1815 | widgets["dataMemEntry"] = dataMemEntry 1816 | resetButton = customtkinter.CTkButton(paramPannel, text="Reset", 1817 | #relief='raised', 1818 | command=partial(clickReset, master)#, 1819 | #highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS 1820 | ) 1821 | resetButton.grid(row=2, column=2, columnspan=2) 1822 | 1823 | 1824 | configMemLabel = customtkinter.CTkLabel(paramPannel, text='Config Memory \n (entries/tile):') 1825 | configMemLabel.grid(row=3, column=0) 1826 | configMemEntry = customtkinter.CTkEntry(paramPannel, justify=tkinter.CENTER#, 1827 | #highlightbackground="black", 1828 | #highlightthickness=HIGHLIGHT_THICKNESS 1829 | ) 1830 | configMemEntry.grid(row=3, column=1, pady=5) 1831 | configMemEntry.insert(0, paramCGRA.configMemSize) 1832 | widgets["configMemEntry"] = configMemEntry 1833 | updateButton = customtkinter.CTkButton(paramPannel, text="Update", 1834 | #relief='raised', 1835 | command=partial(clickUpdate, master)#, 1836 | #highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS 1837 | ) 1838 | updateButton.grid(row=3, column=2, columnspan=2) 1839 | 1840 | 1841 | entireTileCheckVar.set(0) 1842 | entireTileCheckbutton = customtkinter.CTkCheckBox(paramPannel, variable=entireTileCheckVar, text="Disable entire Tile 0", command=clickEntireTileCheckbutton) 1843 | entireTileCheckbutton.grid(row=4, column=0, columnspan=2, padx=(5,0), sticky="w") 1844 | widgets["entireTileCheckbutton"] = entireTileCheckbutton 1845 | 1846 | 1847 | # Data SPM outgoing links 1848 | spmConfigPannel = customtkinter.CTkScrollableFrame(paramPannel, label_text="Data SPM\noutgoing links", width=80) 1849 | spmConfigPannel.grid(row=5, column=0, rowspan=3, pady=(5,0), sticky="nsew") 1850 | widgets["spmConfigPannel"] = spmConfigPannel 1851 | # spmConfigPannel.rowconfigure(0, weight=1) 1852 | # spmConfigPannel.rowconfigure(1, weight=3) 1853 | # for i in range(4): 1854 | # spmConfigPannel.columnconfigure(i, weight=1) 1855 | # spmConfigPannel.grid_propagate(0) 1856 | # spmConfigPannelLabel = customtkinter.CTkLabel(spmConfigPannel, text='Data SPM\noutgoing links', 1857 | # font=customtkinter.CTkFont(size=FRAME_LABEL_LEVEL_1_FONT_SIZE, 1858 | # weight="bold", slant='italic')) 1859 | # spmConfigPannelLabel.grid(row=0, column=0, sticky="nsew") 1860 | # spmConfigPannelLabel.pack() 1861 | # spmConfigPannelLabel.grid_propagate(0) 1862 | # spmConfigScrollablePannel = customtkinter.CTkScrollableFrame(spmConfigPannel, height=240) 1863 | # spmConfigScrollablePannel.grid(row=1, column=0, sticky="nsew") 1864 | # spmConfigScrollablePannel.pack() 1865 | 1866 | spmOutlinksSwitches = [] 1867 | # for i in range(10): 1868 | # switch = customtkinter.CTkSwitch(spmConfigScrollablePannel, text=f"link {i}") 1869 | # switch.select() 1870 | # # switch.grid(row=i + 1, column=0, padx=5, pady=(0, 10)) 1871 | # switch.pack(pady=(5, 10)) 1872 | # scrollable_frame_switches.append(switch) 1873 | for port in paramCGRA.dataSPM.outLinks: 1874 | switch = customtkinter.CTkSwitch(spmConfigPannel, text=f"link {port}", command=switchDataSPMOutLinks) 1875 | if not paramCGRA.dataSPM.outLinks[port].disabled: 1876 | switch.select() 1877 | switch.pack(pady=(5, 10)) 1878 | spmOutlinksSwitches.insert(0, switch) 1879 | widgets['spmOutlinksSwitches'] = spmOutlinksSwitches 1880 | 1881 | 1882 | 1883 | # Tile x functional units 1884 | fuConfigPannel = customtkinter.CTkScrollableFrame(paramPannel, label_text="Tile 0\nfunctional units") 1885 | fuConfigPannel.grid(row=5, column=1, rowspan=3, padx=(5,5), pady=(5,0), sticky="nsew") 1886 | widgets["fuConfigPannel"] = fuConfigPannel 1887 | 1888 | # Use columnconfigure to partition the columns, so that each column fills the corresponding space 1889 | # for i in range(2): 1890 | # fuConfigPannel.columnconfigure(i, weight=1) 1891 | # fuConfigPannel.grid_propagate(0) 1892 | # fuConfigPannelLabel = customtkinter.CTkLabel(fuConfigPannel, text='Tile 0\nfunctional units', 1893 | # font=customtkinter.CTkFont(size=FRAME_LABEL_LEVEL_1_FONT_SIZE, 1894 | # weight="bold", slant='italic')) 1895 | # fuConfigPannelLabel.grid(row=0, column=0, sticky="nsew") 1896 | # fuConfigPannelLabel.pack() 1897 | # widgets["fuConfigPannelLabel"] = fuConfigPannelLabel 1898 | # fuConfigSubPannel = customtkinter.CTkFrame(fuConfigPannel) 1899 | for i in range(2): 1900 | fuConfigPannel.columnconfigure(i, weight=1) 1901 | place_fu_options(fuConfigPannel) 1902 | # fuConfigSubPannel.pack() 1903 | 1904 | 1905 | # Tile x crossbar outgoing links 1906 | xbarConfigPannel = customtkinter.CTkScrollableFrame(paramPannel, label_text="Tile 0\ncrossbar outgoing links") 1907 | xbarConfigPannel.grid(row=5, column=2, rowspan=3, pady=(5, 0), sticky="nsew") 1908 | widgets["xbarConfigPannel"] = xbarConfigPannel 1909 | 1910 | # Use columnconfigure to partition the columns, so that each column fills the corresponding space 1911 | # for i in range(3): 1912 | # xbarConfigPannel.columnconfigure(i, weight=1) 1913 | # for i in range(4): 1914 | # xbarConfigPannel.rowconfigure(i, weight=1) 1915 | # xbarConfigPannel.grid_propagate(0) 1916 | # xbarConfigPannelLabel = customtkinter.CTkLabel(xbarConfigPannel, text='Tile 0\ncrossbar outgoing links', 1917 | # font=customtkinter.CTkFont(size=FRAME_LABEL_LEVEL_1_FONT_SIZE, 1918 | # weight="bold", slant='italic')) 1919 | # # xbarConfigPannelLabel.grid(row=0, column=0, sticky="nsew") 1920 | # xbarConfigPannelLabel.pack() 1921 | # widgets["xbarConfigPannelLabel"] = xbarConfigPannelLabel 1922 | # xbarConfigSubPannel = customtkinter.CTkFrame(xbarConfigPannel) 1923 | for i in range(3): 1924 | xbarConfigPannel.columnconfigure(i, weight=1) 1925 | for i in range(3): 1926 | xbarConfigPannel.rowconfigure(i, weight=1) 1927 | place_xbar_options(xbarConfigPannel) 1928 | # xbarConfigSubPannel.pack() 1929 | 1930 | 1931 | 1932 | 1933 | # spmConfigPannel = tkinter.LabelFrame(paramPannel, text='Data SPM outgoing links', bd=BORDER, relief='groove') 1934 | # spmConfigPannel.grid(row=9, column=0, rowspan=3, columnspan=4, sticky="nsew") 1935 | # widgets["spmConfigPannel"] = spmConfigPannel 1936 | # 1937 | # # Use columnconfigure and rowconfigure to partition the columns, so that each column and row fills the corresponding space 1938 | # for i in range(3): 1939 | # spmConfigPannel.rowconfigure(i, weight=1) 1940 | # for i in range(5): 1941 | # spmConfigPannel.columnconfigure(i, weight=1) 1942 | # 1943 | # spmEnabledOutVar = tkinter.IntVar() 1944 | # spmDisabledOutVar = tkinter.IntVar() 1945 | # 1946 | # spmEnabledLabel = tkinter.Label(spmConfigPannel) 1947 | # spmDisabledLabel = tkinter.Label(spmConfigPannel) 1948 | # 1949 | # spmEnabledScrollbar = tkinter.Scrollbar(spmEnabledLabel) 1950 | # spmDisabledScrollbar = tkinter.Scrollbar(spmDisabledLabel) 1951 | # 1952 | # spmEnabledListbox = tkinter.Listbox(spmEnabledLabel, listvariable=spmEnabledOutVar) 1953 | # spmDisabledListbox = tkinter.Listbox(spmDisabledLabel, listvariable=spmDisabledOutVar) 1954 | # 1955 | # widgets["spmEnabledListbox"] = spmEnabledListbox 1956 | # widgets["spmDisabledListbox"] = spmDisabledListbox 1957 | # 1958 | # spmDisableButton = tkinter.Button(spmConfigPannel, text="Disable", relief='raised', command=clickSPMPortDisable, 1959 | # highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS) 1960 | # spmEnableButton = tkinter.Button(spmConfigPannel, text="Enable", relief='raised', command=clickSPMPortEnable, 1961 | # highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS) 1962 | # spmEnabledScrollbar.config(command=spmEnabledListbox.yview) 1963 | # spmEnabledListbox.config(yscrollcommand=spmEnabledScrollbar.set) 1964 | # spmDisabledScrollbar.config(command=spmDisabledListbox.yview) 1965 | # spmDisabledListbox.config(yscrollcommand=spmDisabledScrollbar.set) 1966 | # spmEnabledLabel.grid(row=0, column=0, rowspan=3, sticky="nsew") 1967 | # 1968 | # spmEnabledScrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) 1969 | # spmEnabledListbox.pack() 1970 | # 1971 | # spmDisableArrow0 = tkinter.Label(spmConfigPannel, text="=>") 1972 | # spmDisableArrow1 = tkinter.Label(spmConfigPannel, text="=>") 1973 | # spmEnableArrow0 = tkinter.Label(spmConfigPannel, text="<=") 1974 | # spmEnableArrow1 = tkinter.Label(spmConfigPannel, text="<=") 1975 | # 1976 | # spmDisableArrow0.grid(row=0, column=1, sticky="nsew") 1977 | # spmDisableButton.grid(row=0, column=2, sticky="nsew") 1978 | # spmDisableArrow1.grid(row=0, column=3, sticky="nsew") 1979 | # 1980 | # spmEnableArrow0.grid(row=2, column=1, sticky="nsew") 1981 | # spmEnableButton.grid(row=2, column=2, sticky="nsew") 1982 | # spmEnableArrow1.grid(row=2, column=3, sticky="nsew") 1983 | # 1984 | # spmDisabledLabel.grid(row=0, column=4, rowspan=3, sticky="new") 1985 | # 1986 | # spmDisabledScrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) 1987 | # spmDisabledListbox.pack() 1988 | # 1989 | # spmEnabledListbox.delete(0) 1990 | # spmDisabledListbox.delete(0) 1991 | # for port in paramCGRA.dataSPM.outLinks: 1992 | # if not paramCGRA.dataSPM.outLinks[port].disabled: 1993 | # spmEnabledListbox.insert(0, port) 1994 | return paramPannel 1995 | 1996 | 1997 | def create_test_pannel(master): 1998 | dataPannel = customtkinter.CTkFrame(master, width=280, height=480) 1999 | # Increase the size of the 'SVerilog' panel 2000 | dataPannel.grid_rowconfigure(1, weight=2) 2001 | 2002 | dataPannel.grid_columnconfigure(0, weight=1) 2003 | dataPannel.grid_columnconfigure(1, weight=1) 2004 | dataPannel.grid_columnconfigure(2, weight=1) 2005 | dataPannel.grid_propagate(0) 2006 | # testPannel = tkinter.LabelFrame(dataPannel, text='Verification', bd=BORDER, relief='groove') 2007 | testPannel = customtkinter.CTkFrame(dataPannel) 2008 | testPannel.grid(row=0, column=0, rowspan=1, columnspan=3, sticky="nsew") 2009 | testPannel.columnconfigure(0, weight=1) 2010 | testPannel.columnconfigure(1, weight=1) 2011 | testPannel.columnconfigure(2, weight=1) 2012 | testPannelLabel = customtkinter.CTkLabel(testPannel, text='Verification ', 2013 | # width=100, 2014 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, weight="bold")) 2015 | testPannelLabel.grid(row=0, column=0, columnspan=3, ipadx=5, sticky="w") 2016 | testButton = customtkinter.CTkButton(testPannel, text="Run tests", # relief='raised', 2017 | command=clickTest, 2018 | width=50 2019 | # highlightbackground="black", highlightthickness=HIGHLIGHT_THICKNESS 2020 | ) 2021 | testButton.grid(row=1, column=0, ipadx=5) 2022 | # testProgress = ttk.Progressbar(testPannel, orient='horizontal', mode='determinate') 2023 | testProgress = customtkinter.CTkProgressBar(testPannel, orientation='horizontal', mode='determinate', width=160) 2024 | testProgress.set(0) 2025 | widgets["testProgress"] = testProgress 2026 | testProgress.grid(row=1, column=1, rowspan=1, columnspan=1, padx=5, sticky="w") 2027 | testShow = customtkinter.CTkLabel(testPannel, text="IDLE ") 2028 | widgets["testShow"] = testShow 2029 | testShow.grid(row=1, column=2, sticky=tkinter.E, padx=(5, 5)) 2030 | 2031 | # verilogPannel = tkinter.LabelFrame(dataPannel, text="SVerilog", bd=BORDER, relief="groove") 2032 | verilogPannel = customtkinter.CTkFrame(dataPannel) 2033 | verilogPannel.grid(row=1, column=0, rowspan=1, columnspan=3, pady=(5,5), sticky="nsew") 2034 | verilogPannelLabel = customtkinter.CTkLabel(verilogPannel, text='SVerilog ', 2035 | # width=100, 2036 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2037 | weight="bold")) 2038 | verilogPannelLabel.pack(anchor="w", padx=(5,0)) 2039 | CreateToolTip(verilogPannel, 2040 | text="The code might be too big to be copied,\nthe generated verilog can be found in\nthe 'verilog' folder.") 2041 | generateVerilogButton = customtkinter.CTkButton(verilogPannel, text="Generate", width=50, 2042 | command=clickGenerateVerilog) 2043 | generateVerilogButton.pack(side=tkinter.BOTTOM, anchor="sw", padx=BORDER, pady=BORDER) 2044 | # verilogScroll = tkinter.Scrollbar(verilogPannel, orient="vertical") 2045 | # verilogScroll.pack(side=tkinter.RIGHT, fill="y") 2046 | # verilogText = tkinter.Text(verilogPannel, yscrollcommand=verilogScroll.set, width=10, height=5) 2047 | # verilogText.pack(side=tkinter.LEFT, fill="both", expand=True) 2048 | # verilogScroll.config(command=verilogText.yview) 2049 | verilogText = customtkinter.CTkTextbox(verilogPannel, width=10, height=5) 2050 | verilogText.pack(side=tkinter.LEFT, fill="both", expand=True) 2051 | widgets["verilogText"] = verilogText 2052 | 2053 | # reportPannel = tkinter.LabelFrame(dataPannel, text='Report area/power', bd=BORDER, relief='groove') 2054 | reportPannel = customtkinter.CTkFrame(dataPannel) 2055 | reportPannel.grid(row=2, column=0, rowspan=1, columnspan=3, sticky='nesw') 2056 | reportPannel.columnconfigure(0, weight=1) 2057 | reportPannel.columnconfigure(1, weight=1) 2058 | reportPannelLabel = customtkinter.CTkLabel(reportPannel, text='Report Area/Power ', 2059 | # width=100, 2060 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2061 | weight="bold")) 2062 | 2063 | reportButton = customtkinter.CTkButton(reportPannel, text="Synthesize", command=clickSynthesize, width=60) 2064 | 2065 | reportProgress = customtkinter.CTkProgressBar(reportPannel, orientation="horizontal", mode="determinate", width=140) 2066 | reportProgress.set(0) 2067 | widgets["reportProgress"] = reportProgress 2068 | 2069 | synthesisTimeEntry = customtkinter.CTkEntry(reportPannel, justify=tkinter.CENTER) 2070 | widgets["synthesisTimeEntry"] = synthesisTimeEntry 2071 | 2072 | reportTimecostLabel = customtkinter.CTkLabel(reportPannel, text=" Time cost:") 2073 | CreateToolTip(reportTimecostLabel, text="Time is in s.") 2074 | 2075 | reportTileAreaLabel = customtkinter.CTkLabel(reportPannel, text=" Tiles area:") 2076 | CreateToolTip(reportTileAreaLabel, text="Area is in mm^2.") 2077 | 2078 | reportTileAreaData = customtkinter.CTkEntry(reportPannel, justify=tkinter.CENTER) 2079 | widgets["reportTileAreaData"] = reportTileAreaData 2080 | 2081 | reportTilePowerLabel = customtkinter.CTkLabel(reportPannel, text="Tiles power:") 2082 | CreateToolTip(reportTilePowerLabel, text="Yosys is not able to provide\npower estimation.") 2083 | 2084 | reportTilePowerData = customtkinter.CTkEntry(reportPannel, justify=tkinter.CENTER) 2085 | widgets["reportTilePowerData"] = reportTilePowerData 2086 | 2087 | reportSPMAreaLabel = customtkinter.CTkLabel(reportPannel, text=" SPM area:") 2088 | CreateToolTip(reportSPMAreaLabel, text="Area is in mm^2.") 2089 | 2090 | reportSPMAreaData = customtkinter.CTkEntry(reportPannel, justify=tkinter.CENTER) 2091 | widgets["reportSPMAreaData"] = reportSPMAreaData 2092 | 2093 | reportSPMPowerLabel = customtkinter.CTkLabel(reportPannel, text="SPM power:") 2094 | CreateToolTip(reportSPMPowerLabel, text="Power is in mW.") 2095 | 2096 | reportSPMPowerData = customtkinter.CTkEntry(reportPannel, justify=tkinter.CENTER) 2097 | widgets["reportSPMPowerData"] = reportSPMPowerData 2098 | 2099 | reportPannelLabel.grid(row=0, column=0, columnspan=2, padx=(5,0), sticky="w") 2100 | reportButton.grid(row=1, column=0) 2101 | reportProgress.grid(row=1, column=1) 2102 | 2103 | synthesisTimeEntry.grid(row=2, column=1, pady=5) 2104 | reportTimecostLabel.grid(row=2, column=0, pady=5) 2105 | 2106 | reportTileAreaLabel.grid(row=3, column=0, pady=5) 2107 | reportTileAreaData.grid(row=3, column=1, pady=5) 2108 | reportTilePowerLabel.grid(row=4, column=0, pady=5) 2109 | reportTilePowerData.grid(row=4, column=1, pady=5) 2110 | 2111 | reportSPMAreaLabel.grid(row=5, column=0, pady=5) 2112 | reportSPMAreaData.grid(row=5, column=1, pady=5) 2113 | reportSPMPowerLabel.grid(row=6, column=0, pady=5) 2114 | reportSPMPowerData.grid(row=6, column=1, pady=5) 2115 | return dataPannel; 2116 | 2117 | def create_layout_pannel(master): 2118 | # layoutPannel = tkinter.LabelFrame(master, text='Layout', bd=BORDER, relief='groove') 2119 | layoutPannel = customtkinter.CTkFrame(master) 2120 | layoutPannelLabel = customtkinter.CTkLabel(layoutPannel, text='Layout ', 2121 | # width=100, 2122 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, weight="bold")) 2123 | layoutPannelLabel.grid(row=0, column=0, sticky="w") 2124 | 2125 | # Adds the entry for user to select constraint.sdc 2126 | constraintLabel = customtkinter.CTkLabel(layoutPannel, text="Constraint.sdc") 2127 | constraintLabel.grid(row=1, column=0, pady=(10,10), sticky="nsew") 2128 | constraintPathEntry = customtkinter.CTkEntry(layoutPannel) 2129 | constraintPathEntry.grid(row=1, column=1, padx=(10,20), pady=(10,10), sticky="nsew") 2130 | constraintPathEntry.bind("", clickSelectConstraintFile) 2131 | widgets["constraintPathEntry"] = constraintPathEntry 2132 | 2133 | # Adds the entry for user to select config.mk 2134 | configLabel = customtkinter.CTkLabel(layoutPannel, text="Config.mk") 2135 | configLabel.grid(row=1, column=2, padx=(0,10), pady=(10,10), sticky="nsew") 2136 | configPathEntry = customtkinter.CTkEntry(layoutPannel) 2137 | configPathEntry.grid(row=1, column=3, pady=(10,10), sticky="nsew") 2138 | configPathEntry.bind("", clickSelectConfigFile) 2139 | widgets["configPathEntry"] = configPathEntry 2140 | 2141 | # Adds the option menu to select process technology. 2142 | processNameLabel = customtkinter.CTkLabel(layoutPannel, text="Process:") 2143 | processNameLabel.grid(row=2, column=0, pady=(10,10), sticky="nsew") 2144 | tempOptions = [ "asap7", "nangate45", "sky130hd"] 2145 | processNameMenu = customtkinter.CTkOptionMenu(layoutPannel, variable=processOptions, values=tempOptions) 2146 | processNameMenu.grid(row=2, column=1, padx=(10,20), pady=(10,10), sticky="nsew") 2147 | 2148 | # Adds the button to trigger RTL->Layout flow. 2149 | openRoadButton = customtkinter.CTkButton(layoutPannel, text="RTL -> Layout", command=clickRTL2Layout) 2150 | openRoadButton.grid(row=2, column=2, pady=(10,10), sticky="nsew", columnspan=2) 2151 | 2152 | # Adds a placeholder to show the layout image saved from OpenRoad. 2153 | global layoutLabel 2154 | layoutLabel = customtkinter.CTkLabel(layoutPannel, text='') 2155 | layoutLabel.grid(row=3, column=0, padx=(0,10), pady=(10,10), columnspan=4) 2156 | return layoutPannel 2157 | 2158 | """ 2159 | canvas = customtkinter.CTkCanvas(layoutPannel, bg=CANVAS_BG_COLOR, bd=0, highlightthickness=0) 2160 | scrollbar = customtkinter.CTkScrollbar(layoutPannel, orientation="horizontal", command=canvas.xview) 2161 | scrollbar.pack(side="bottom", fill="x") 2162 | canvas.config(xscrollcommand=scrollbar.set) 2163 | canvas.pack(side="top", fill="both", expand=True) 2164 | layout_frame = customtkinter.CTkFrame(canvas) 2165 | canvas.create_window((0, 0), window=layout_frame, anchor="nw") 2166 | showButton = customtkinter.CTkButton(layoutPannel, text="Display layout") 2167 | CreateToolTip(showButton, text="The layout demonstration is\nunder development.") 2168 | showButton.place(relx=0.5, rely=0.1, anchor="center") 2169 | """ 2170 | 2171 | 2172 | def constructDependencyFiles(cgraflow_basepath, standard_module_name, test_platform_name, verilog_srcfile_path, mk_sdc_file_path, orfs_basePath): 2173 | # Finds the target RTL design and transforms the format. 2174 | files = os.listdir(cgraflow_basepath + "/build/verilog") 2175 | for f in files: 2176 | # Finds the generated verilog file. 2177 | if f == "design.v": 2178 | os.chdir(cgraflow_basepath + "/build/verilog") 2179 | # Manually copies design.v to design.sv to make sv2v work normally. 2180 | print("Renaming the system verilog file generated by PyMTL3.") 2181 | subprocess.run(["cp design.v design.sv"], shell=True, encoding="utf-8") 2182 | # Uses sv2v to convert system verilog to verilg. 2183 | print("Converting the system verilog file to verilog file.") 2184 | subprocess.run(["../../tools/sv2v/bin/sv2v --write=adjacent " + "design.sv"], shell=True, encoding="utf-8") 2185 | # Changes the top module name in design.v to standard_module_name. 2186 | print("Standardizing the top module name in verilog file.") 2187 | contents = "" 2188 | with open("design.v", "r", encoding="utf-8") as lines: 2189 | for line in lines: 2190 | if standard_module_name in line: 2191 | line = "module " + standard_module_name + " (" 2192 | contents += line 2193 | with open(standard_module_name + ".v", "w", encoding="utf-8") as newFile: 2194 | newFile.write(contents) 2195 | break 2196 | 2197 | # Makes directories and copies CGRATemplateRTL.v, the pre-defined config.mk, and constraint.sdc to their respective directories. 2198 | global constraintFilePath, configFilePath 2199 | os.chdir(orfs_basePath) 2200 | subprocess.run(["mkdir -p " + verilog_srcfile_path], shell=True, encoding="utf-8") 2201 | subprocess.run(["cp " + cgraflow_basepath + "/build/verilog/" + standard_module_name + ".v " + verilog_srcfile_path], shell=True, encoding="utf-8") 2202 | subprocess.run(["mkdir -p " + mk_sdc_file_path], shell=True, encoding="utf-8") 2203 | subprocess.run(["cp " + constraintFilePath + " " + mk_sdc_file_path], shell=True, encoding="utf-8") 2204 | subprocess.run(["cp " + configFilePath + " " + mk_sdc_file_path], shell=True, encoding="utf-8") 2205 | 2206 | # Updates process within the config.mk to the user selected one. 2207 | with open(mk_sdc_file_path + "config.mk", 'r') as file: 2208 | # Reads all lines within the file. 2209 | lines = file.readlines() 2210 | # Modifies the first line, replaces the PLATFORM with the user selected process technology. 2211 | lines[0] = "export PLATFORM = " + test_platform_name + "\n" 2212 | with open(mk_sdc_file_path + "config.mk", 'w') as file: 2213 | # Writes the updated content back to config.mk. 2214 | file.writelines(lines) 2215 | 2216 | def runOpenRoad(mk_sdc_file_path, cmd_path, odb_path, layout_path): 2217 | # Runs the test module from RTL to GDSII. 2218 | subprocess.run(["make DESIGN_CONFIG=./" + mk_sdc_file_path + "config.mk"], shell=True, encoding="utf-8") 2219 | # Generates a cmd.tcl file for openroad 2220 | if os.path.exists(cmd_path): 2221 | os.remove(cmd_path) 2222 | with open(cmd_path, mode="a", encoding="utf-8") as file: 2223 | # Load the test module layout file. 2224 | file.write("read_db " + odb_path + "\n") 2225 | # Saves layout to image. 2226 | file.write("save_image " + layout_path + "\n") 2227 | file.write("exit") 2228 | # Runs openroad. 2229 | subprocess.run(["openroad", cmd_path], shell=False, encoding="utf-8") 2230 | 2231 | def clickRTL2Layout(): 2232 | global constraintFilePath, configFilePath 2233 | standard_module_name = "CGRATemplateRTL" 2234 | cgraflow_basepath = os.path.dirname(os.path.abspath(__file__)) 2235 | test_platform_name = processOptions.get() 2236 | print("Test platform is %s" % (test_platform_name)) 2237 | orfs_basePath = cgraflow_basepath + "/tools/OpenROAD-flow-scripts/flow/" 2238 | layout_path = cgraflow_basepath + "/build/" + "layout.png" 2239 | odb_path = orfs_basePath + "results/" + test_platform_name + "/" + standard_module_name + "/base/6_final.odb" 2240 | cmd_path = orfs_basePath + "cmd.tcl" 2241 | verilog_srcfile_path = "designs/src/" + standard_module_name + "/" 2242 | mk_sdc_file_path = "designs/" + test_platform_name + "/" + standard_module_name + "/" 2243 | 2244 | if constraintFilePath == "" or configFilePath == "": 2245 | tkinter.messagebox.showerror(title="Missing files for RTL->Layout", 2246 | message="constraint.sdc and config.mk need to be selected first.") 2247 | return 2248 | 2249 | # Checks if layout.png of target design already exists. 2250 | # If yes, directly shows. 2251 | if os.path.exists(layout_path): 2252 | display_layout_image(layout_path) 2253 | # If not, runs the design from RTL to GDSII and saves layout.png, finally shows. 2254 | else: 2255 | # Generates all dependency files for openroad. 2256 | constructDependencyFiles(cgraflow_basepath, standard_module_name, test_platform_name, 2257 | verilog_srcfile_path, mk_sdc_file_path, orfs_basePath) 2258 | # Runs openroad. 2259 | runOpenRoad(mk_sdc_file_path, cmd_path, odb_path, layout_path) 2260 | # Shows the layout image on CGRA-Flow GUI. 2261 | display_layout_image(layout_path) 2262 | 2263 | def clickSelectConstraintFile(event): 2264 | global constraintFilePath 2265 | constraintFilePath = fd.askopenfilename(title="Chooses constraint.sdc for synthesis.", initialdir="./", filetypes=(("SDC file", "*.sdc"),)) 2266 | widgets["constraintPathEntry"].delete(0, tkinter.END) 2267 | widgets["constraintPathEntry"].insert(0, constraintFilePath) 2268 | print(constraintFilePath) 2269 | 2270 | def clickSelectConfigFile(event): 2271 | global configFilePath 2272 | configFilePath = fd.askopenfilename(title="Chooses config.mk for OpenRoad.", initialdir="./", filetypes=(("MK file", "*.mk"),)) 2273 | widgets["configPathEntry"].delete(0, tkinter.END) 2274 | widgets["configPathEntry"].insert(0, configFilePath) 2275 | print(configFilePath) 2276 | 2277 | def display_layout_image(image_path): 2278 | layoutImage = customtkinter.CTkImage(light_image=Image.open(image_path), 2279 | dark_image=Image.open(image_path), 2280 | size=(320, 320)) 2281 | layoutLabel.configure(image=layoutImage) 2282 | 2283 | def create_mapping_pannel(master): 2284 | # mappingPannel = tkinter.LabelFrame(master, text='Mapping', bd=BORDER, relief='groove') 2285 | mappingPannel = customtkinter.CTkFrame(master) 2286 | mappingPannelLabel = customtkinter.CTkLabel(mappingPannel, text='Mapping ', 2287 | # width=100, 2288 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2289 | weight="bold")) 2290 | mappingPannelLabel.pack(anchor="w", padx=(5, 0)) 2291 | mappingCanvas = customtkinter.CTkCanvas(mappingPannel, bg=CANVAS_BG_COLOR, bd=0, highlightthickness=0) 2292 | widgets["mappingCanvas"] = mappingCanvas 2293 | hbar = customtkinter.CTkScrollbar(mappingPannel, orientation="horizontal", command=mappingCanvas.xview) 2294 | hbar.pack(side="bottom", fill="x") 2295 | mappingCanvas.config(xscrollcommand=hbar.set) 2296 | vbar = customtkinter.CTkScrollbar(mappingPannel, orientation="vertical", command=mappingCanvas.yview) 2297 | vbar.pack(side=tkinter.RIGHT, fill="y") 2298 | mappingCanvas.config(yscrollcommand=vbar.set) 2299 | mappingCanvas.pack(side="top", fill="both", expand=True) 2300 | return mappingPannel 2301 | 2302 | 2303 | def create_kernel_pannel(master): 2304 | # kernelPannel = tkinter.LabelFrame(master, text="Kernel", bd=BORDER, relief='groove') 2305 | kernelPannel = customtkinter.CTkFrame(master) 2306 | for row in range(13): 2307 | kernelPannel.grid_rowconfigure(row, weight=1) 2308 | kernelPannel.grid_columnconfigure(0, weight=3) 2309 | kernelPannel.grid_columnconfigure(1, weight=2) 2310 | kernelPannel.grid_columnconfigure(2, weight=2) 2311 | kernelPannel.grid_columnconfigure(3, weight=1) 2312 | 2313 | kernelPannellLabel = customtkinter.CTkLabel(kernelPannel, text='Kernel ', 2314 | # width=100, 2315 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2316 | weight="bold")) 2317 | kernelPannellLabel.grid(row=0, column=0, padx=(5, 0), sticky="wn") 2318 | 2319 | selectAppLabel = customtkinter.CTkLabel(kernelPannel, text=" Application:") 2320 | selectAppLabel.grid(row=1, column=0, sticky="nsew") 2321 | 2322 | appPathEntry = customtkinter.CTkEntry(kernelPannel) 2323 | widgets["appPathEntry"] = appPathEntry 2324 | appPathEntry.grid(row=1, column=1) 2325 | appPathEntry.bind("", clickSelectApp) 2326 | 2327 | compileAppButton = customtkinter.CTkButton(kernelPannel, text=" Compile app ", command=clickCompileApp) 2328 | compileAppButton.grid(row=1, column=2) 2329 | 2330 | compileAppShow = customtkinter.CTkLabel(kernelPannel, text=" IDLE") 2331 | compileAppShow.grid(row=1, column=3) 2332 | widgets["compileAppShow"] = compileAppShow 2333 | 2334 | kernelNameLabel = customtkinter.CTkLabel(kernelPannel, text=" Kernel name:") 2335 | kernelNameLabel.grid(row=2, column=0) 2336 | 2337 | tempOptions = ["Not selected yet"] 2338 | # kernelNameMenu = tkinter.OptionMenu(kernelPannel, kernelOptions, *tempOptions) 2339 | kernelNameMenu = customtkinter.CTkOptionMenu(kernelPannel, variable=kernelOptions, values=tempOptions) 2340 | kernelOptions.trace("w", clickKernelMenu) 2341 | widgets["kernelNameMenu"] = kernelNameMenu 2342 | widgets["kernelPannel"] = kernelPannel 2343 | kernelNameMenu.grid(row=2, column=1) 2344 | 2345 | generateDFGButton = customtkinter.CTkButton(kernelPannel, text="Generate DFG", command=clickShowDFG) 2346 | generateDFGButton.grid(row=2, column=2) 2347 | 2348 | generateDFGShow = customtkinter.CTkLabel(kernelPannel, text=" IDLE") 2349 | generateDFGShow.grid(row=2, column=3, sticky="ew") 2350 | widgets["generateDFGShow"] = generateDFGShow 2351 | 2352 | dfgPannel = customtkinter.CTkFrame(kernelPannel) 2353 | dfgPannel.grid(row=3, column=0, rowspan=10, columnspan=2, padx=(0,5), pady=(5,0), sticky="nsew") 2354 | dfgPannelLabel = customtkinter.CTkLabel(dfgPannel, text='Data-Flow Graph ', 2355 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2356 | weight="bold")) 2357 | dfgPannelLabel.pack(anchor="w", padx=(5, 0)) 2358 | dfgLabel = customtkinter.CTkLabel(dfgPannel, text="") 2359 | widgets["dfgLabel"] = dfgLabel 2360 | dfgLabel.pack() 2361 | 2362 | recMIILabel = customtkinter.CTkLabel(kernelPannel, text=" RecMII: ") 2363 | recMIILabel.grid(row=3, column=2, sticky="nsew") 2364 | recMIIEntry = customtkinter.CTkEntry(kernelPannel, justify=tkinter.CENTER) 2365 | widgets["recMIIEntry"] = recMIIEntry 2366 | recMIIEntry.insert(0, "0") 2367 | recMIIEntry.grid(row=3, column=3) 2368 | resMIILabel = customtkinter.CTkLabel(kernelPannel, text=" ResMII: ") 2369 | resMIILabel.grid(row=4, column=2, sticky="nsew") 2370 | resMIIEntry = customtkinter.CTkEntry(kernelPannel, justify=tkinter.CENTER) 2371 | widgets["resMIIEntry"] = resMIIEntry 2372 | resMIIEntry.insert(0, "0") 2373 | resMIIEntry.grid(row=4, column=3) 2374 | 2375 | mappingAlgoPannel = customtkinter.CTkFrame(kernelPannel) 2376 | mappingAlgoPannel.grid(row=5, column=2, rowspan=3, columnspan=2, pady=(5,10), sticky="nsew") 2377 | for row in range(2): 2378 | mappingAlgoPannel.grid_rowconfigure(row, weight=1) 2379 | mappingAlgoPannel.grid_columnconfigure(0, weight=1) 2380 | mappingAlgoPannel.grid_columnconfigure(1, weight=1) 2381 | # mappingOptionLabel = customtkinter.CTkLabel(mappingAlgoPannel, text="Mapping algo:") 2382 | mappingOptionLabel = customtkinter.CTkLabel(mappingAlgoPannel, text='Mapping Algorithm', 2383 | font=customtkinter.CTkFont(size=FRAME_LABEL_FONT_SIZE, 2384 | weight="bold")) 2385 | mappingOptionLabel.grid(row=0, column=0, columnspan=2) 2386 | heuristicRadioButton = customtkinter.CTkRadioButton(mappingAlgoPannel, text="Heuristic", variable=mappingAlgoCheckVar, value=0) 2387 | widgets["heuristicRadioButton"] = heuristicRadioButton 2388 | heuristicRadioButton.grid(row=1, column=0, pady=(0, 5), sticky="nsew") 2389 | exhaustiveRadioButton = customtkinter.CTkRadioButton(mappingAlgoPannel, text="Exhaustive", variable=mappingAlgoCheckVar, value=1) 2390 | widgets["exhaustiveRadioButton"] = exhaustiveRadioButton 2391 | exhaustiveRadioButton.grid(row=1, column=1, pady=(0, 5), sticky="nsew") 2392 | 2393 | mapDFGButton = customtkinter.CTkButton(kernelPannel, text="Map DFG", command=clickMapDFG,) 2394 | mapDFGButton.grid(row=8, column=2, columnspan=2, sticky="new") 2395 | terminateMapButton = customtkinter.CTkButton(kernelPannel, text="Terminate", command=clickTerminateMapping) 2396 | terminateMapButton.grid(row=9, column=2, columnspan=2, sticky="new") 2397 | 2398 | mapSecLabel = customtkinter.CTkLabel(kernelPannel, text="Time (s): ") 2399 | mapSecLabel.grid(row=10, column=2, sticky="nsew") 2400 | mapTimeEntry = customtkinter.CTkEntry(kernelPannel, justify=tkinter.CENTER) 2401 | widgets["mapTimeEntry"] = mapTimeEntry 2402 | mapTimeEntry.insert(0, "0") 2403 | mapTimeEntry.grid(row=10, column=3) 2404 | mapIILabel = customtkinter.CTkLabel(kernelPannel, text=" Map II: ") 2405 | mapIILabel.grid(row=11, column=2, sticky="nsew") 2406 | mapIIEntry = customtkinter.CTkEntry(kernelPannel, justify=tkinter.CENTER) 2407 | widgets["mapIIEntry"] = mapIIEntry 2408 | mapIIEntry.insert(0, "0") 2409 | mapIIEntry.grid(row=11, column=3) 2410 | 2411 | speedupLabel = customtkinter.CTkLabel(kernelPannel, text="Speedup: ") 2412 | speedupLabel.grid(row=12, column=2, sticky="nsew") 2413 | CreateToolTip(speedupLabel, 2414 | text="The speedup is the improvement of\nthe execution cycles with respect to\na single-issue in-order CPU.") 2415 | mapSpeedupEntry = customtkinter.CTkEntry(kernelPannel, justify=tkinter.CENTER) 2416 | widgets["mapSpeedupEntry"] = mapSpeedupEntry 2417 | mapSpeedupEntry.insert(0, "0") 2418 | mapSpeedupEntry.grid(row=12, column=3) 2419 | return kernelPannel 2420 | 2421 | # Performs a perodical checks on whether the UI components are drawn into the screen or not. 2422 | def check_ui_ready( 2423 | master: customtkinter.CTk, 2424 | kernel_panel: customtkinter.CTkFrame, 2425 | mapping_panel: customtkinter.CTkFrame, 2426 | cgra_panel: customtkinter.CTkFrame, 2427 | param_panel: customtkinter.CTkFrame, 2428 | data_panel: customtkinter.CTkFrame, 2429 | layout_panel: customtkinter.CTkFrame, 2430 | window: customtkinter.CTkToplevel, 2431 | ): 2432 | panels = [ 2433 | kernel_panel, 2434 | mapping_panel, 2435 | cgra_panel, 2436 | param_panel, 2437 | data_panel, 2438 | layout_panel, 2439 | ] 2440 | 2441 | if all(panel.winfo_ismapped() for panel in panels): 2442 | master.after(100, window.destroy) 2443 | else: 2444 | master.after(200, lambda: check_ui_ready(master, *panels, window)) 2445 | 2446 | # Display all the UI components by calling grid() and start a periodical checks on when they are ready. 2447 | def show_all_ui(master: customtkinter.CTk, window: customtkinter.CTkToplevel): 2448 | kernelPannel = create_kernel_pannel(master) 2449 | mappingPannel = create_mapping_pannel(master) 2450 | cgraPannel = create_cgra_pannel(master, ROWS, COLS) 2451 | paramPannel = create_param_pannel(master) 2452 | dataPannel = create_test_pannel(master) 2453 | layoutPannel = create_layout_pannel(master) 2454 | kernelPannel.grid(row=1, column=0, rowspan=1, columnspan=1, padx=(0, 5), pady=(5, 0), sticky="nsew") 2455 | mappingPannel.grid(row=1, column=1, rowspan=1, columnspan=3, pady=(5, 0), sticky="nsew") 2456 | cgraPannel.grid(row=0, column=0, rowspan=1, columnspan=1, padx=(5, 5), pady=(5, 0), sticky="nsew") 2457 | paramPannel.grid(row=0, column=1, rowspan=1, columnspan=1, padx=(0, 5), sticky="nsew") 2458 | dataPannel.grid(row=0, column=2, rowspan=1, columnspan=1, pady=(5,0), sticky="nsew") 2459 | layoutPannel.grid(row=0, column=3, rowspan=1, columnspan=1, padx=(5,0), pady=(5,0), sticky="nsew") 2460 | # Once kernel is drawn stop the check loop after 100ms. 2461 | if (kernelPannel.winfo_ismapped()): 2462 | master.after(100, window.destroy()) 2463 | # Keeps checking if UI components are drawn in every 2 seconds. 2464 | else: 2465 | master.after(2000, lambda:check_ui_ready(master, kernelPannel,mappingPannel, cgraPannel, paramPannel, dataPannel, layoutPannel, window)) 2466 | 2467 | 2468 | 2469 | # paramPadPosX = GRID_WIDTH + MEM_WIDTH + LINK_LENGTH + INTERVAL * 3 2470 | # paramPadWidth = 270 2471 | # scriptPadPosX = paramPadPosX + paramPadWidth + INTERVAL 2472 | # scriptPadWidth = 300 2473 | # layoutPadPosX = scriptPadPosX + scriptPadWidth + INTERVAL 2474 | # layoutPadWidth = 300 2475 | # layoutPadHeight = GRID_HEIGHT 2476 | TILE_HEIGHT = 70 2477 | TILE_WIDTH = 70 2478 | LINK_LENGTH = 40 2479 | GRID_WIDTH = (TILE_WIDTH + LINK_LENGTH) * COLS - LINK_LENGTH 2480 | GRID_HEIGHT = (TILE_HEIGHT + LINK_LENGTH) * ROWS - LINK_LENGTH 2481 | 2482 | # Sets size first to avoid window keep resizing during loading. 2483 | w, h = master.winfo_screenwidth(), master.winfo_screenheight() 2484 | master.geometry("%dx%d" % (w-10, h-70)) 2485 | master.geometry("+%d+%d" % (0, 0)) 2486 | 2487 | main_frame = customtkinter.CTkFrame(master) 2488 | 2489 | overlay = customtkinter.CTkToplevel(master) 2490 | overlay.geometry("%dx%d" % (w-10, h-70)) 2491 | overlay.transient(master) 2492 | overlay.grab_set() 2493 | 2494 | loading_label = customtkinter.CTkLabel(overlay, text="Loading...", font=("Arial", 24, "bold")) 2495 | loading_label.place(relx=0.5, rely=0.4, anchor="center") 2496 | 2497 | progress = customtkinter.CTkProgressBar(overlay) 2498 | progress.place(relx=0.5, rely=0.5, anchor="center") 2499 | progress.start() 2500 | 2501 | # Adds other UI components in a separate thread. 2502 | threading.Thread(target=show_all_ui(master, overlay), daemon=True).start() 2503 | 2504 | # The width and height of the entire window 2505 | default_width = 1650 2506 | default_height = 1000 2507 | window_size(master, default_width, default_height) 2508 | # master.grid_rowconfigure(0, weight=1) 2509 | master.grid_rowconfigure(1, weight=2) 2510 | master.grid_columnconfigure(0, weight=2) 2511 | master.grid_columnconfigure(1, weight=1) 2512 | master.grid_columnconfigure(2, weight=1) 2513 | master.grid_columnconfigure(3, weight=1) 2514 | # print(master.winfo_width()) 2515 | # print(master.winfo_height()) 2516 | master.geometry("%dx%d" % (w-10, h-70)) 2517 | master.geometry("+%d+%d" % (0, 0)) 2518 | master.mainloop() 2519 | -------------------------------------------------------------------------------- /run_mac_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CONTAINER=cgra/cgra-flow:20241028 4 | NIC=en0 5 | 6 | # Grab the ip address of this box 7 | IPADDR=$(ifconfig $NIC | grep "inet " | awk '{print $2}') 8 | DISP_NUM=$(jot -r 1 100 200) # random display number between 100 and 200 9 | PORT_NUM=$((6000 + DISP_NUM)) # so multiple instances of the container won't interfer with eachother 10 | socat TCP-LISTEN:${PORT_NUM},reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" 2>&1 > /dev/null & 11 | 12 | XSOCK=/tmp/.X11-unix 13 | XAUTH=/tmp/.docker.xauth.$USER.$$ 14 | touch $XAUTH 15 | xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge - 16 | 17 | docker run \ 18 | -it \ 19 | --rm \ 20 | -v $XSOCK:$XSOCK:rw \ 21 | -v $XAUTH:$XAUTH:rw \ 22 | -e DISPLAY=$IPADDR:$DISP_NUM \ 23 | -e XAUTHORITY=$XAUTH \ 24 | $CONTAINER 25 | -------------------------------------------------------------------------------- /run_windows_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | IMAGE=cgra/cgra-flow:20241028 4 | 5 | CONTAINER=CGRA-Flow-OpenRoad 6 | 7 | XSOCK=/tmp/.X11-unix 8 | 9 | sudo docker run \ 10 | -it \ 11 | --name=$CONTAINER \ 12 | -v $XSOCK:$XSOCK:rw \ 13 | -e DISPLAY=unix$DISPLAY \ 14 | $IMAGE 15 | 16 | --------------------------------------------------------------------------------