├── .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 | [](https://github.com/tancheng/CGRA-Flow/actions/workflows/main.yml)
14 | [](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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------