├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── config.cfg
├── docs
├── 1_final.png
├── 1_init.png
├── 2_final.png
├── 2_init.png
├── emptymap.jpg
├── randompath_v.jpg
└── randompath_x.jpg
├── gui.html
├── main.c
├── map.c
├── map2html.c
├── parser.c
└── xmap.c
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | # Input netsfile and output result
55 | *.nets
56 |
57 | # Generated map file
58 | map.html
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Captdam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ```diff
2 | - This repo was used for my school project. It is deactived because I have finished that course.
3 | ```
4 |
5 | # Maze Router: Lee Algorithm
6 |
7 | The Lee Algorithm is a routing algorithm used to find shortest route from one point to another point in a maze. In VLSI and FPGA design, the Lee Algorithm guarantee to find the shortest path for a single net if it exists, but the cost of this algorithm is quite high.
8 |
9 | This program is an implementation of the Lee Algorithm in C language for single layer universal cost maze map.
10 |
11 | The code of this program has been tested on Windows 10 64-bit (compiled by MinGW GCC) and Ununtu 64-bit. It should work on other versions of Windows and Linux system. Web browser is required for GUI.
12 |
13 |
14 | # Using the program
15 |
16 | ## Installing
17 |
18 | This program is writing in C and compiled by GCC. The followig files are required to compile the program:
19 | - ```mian.c```: This is the main code, including config file reader and router function.
20 | - ```map.c```: This file contains map class, which is used to store the maze map.
21 | - ```xmap.c```: This file contains extra functions to work with the map.
22 | - ```map2html.c```: This is used to export map to HTML for GUI.
23 | - ```parser.c```: This is used to read netsfile.
24 |
25 | The following files are required to run the program:
26 | - ```config.cfg```: This file defines the behaviour of the program.
27 | - ```gui.html```: This HTML file is used for GUI.
28 |
29 | Assume all the files are saved in the following directory tree:
30 | ```
31 | router_root
32 | |- bin
33 | |--- (empty)
34 | |- src
35 | |--- main.c
36 | |--- map.c
37 | |--- xmap.c
38 | |--- map2html.c
39 | |--- parser.c
40 | |--- config.cfg
41 | |--- gui.html
42 | ```
43 |
44 | To install this program, first go to the router_root/src directory, and using GCC to compile the C files:
45 |
46 | ```cd src```
47 |
48 | ```gcc -o3 ./main.c -o ../bin/router```
49 |
50 | Then, copy the config file and GUI file to the same directory as the executable file. In Linux, use the following command:
51 |
52 | ```cp ./config.cfg ../bin/config.cfg```
53 |
54 | ```cp ./gui.html ../bin/gui.html```
55 |
56 | Now, there should be 3 files in the ```bin``` directory, the executable file ```router``` (or ```router.exe``` in Windows), the config file ```config.cfg``` and the GUI file ```gui.html```.
57 |
58 | ## Executing the program
59 |
60 | Before executing the program, user should first check the config file, especially the ```gui_path_command``` setting. Description is given in the config file.
61 |
62 | The program can be executed in 3 modes:
63 |
64 | | Mod | ``` gui_path_command``` | ``` gui_interresult``` | Comment |
65 | |---|---|---|---|
66 | | 1 | path_to_browser | 0 | GUI shows how the router place nets in order |
67 | | 2 | path_to_browser | 1 | GUI shows how the router place nets in order and propagate the wave |
68 | | 3 | manual | done_not_care | GUI will not open automatically |
69 |
70 | Note: In mode 3, GUI will not be opened automatically, but the result file will always be exported. Depending on the ```gui_ interresult``` setting, the program exports result every time the router place a net, or every time the router place a net and propagate the wave. This is helpful during debugging. If the user wants no GUI, it is recommended to set the ```gui_dely``` to 0. Therefore, the program will not pause every time when a result file (including intermediate result file) generated.
71 |
72 | After setting the config file, now, the program can be executed. To do so, use the following command:
73 |
74 | ```./router path_to_input.nets```
75 |
76 | The first argument of the program defines the input netsfile’s location. The net file is a human-readable text file contains map size, x-y position of obstruction and x-y position of net source and sink. An example of netsfile is given below:
77 |
78 | ```
79 | 20 //The first line defines the size of the maze map. In this case, a 10 by 10 square maze
80 | 20 x 15 //For rectangular maze, user a “x” to separate the width and height
81 | obstruction 3 12 //x position of an obstruction, y position of that obstruction
82 | obstruction 18 13
83 | net 3 12 12 5 //Net source x-y position, net sink x-y position
84 | ```
85 |
86 | If there is no second argument, the software will use a random seed (in fact, it is the current time) to define the behaviour of random number generator used in the program. To define the seed, use the following command:
87 |
88 | ``` ./router path_to_input.nets abc```
89 |
90 | In this case, the program will use the char code of the first character in the second argument as the seed. In another word, the ASCII code of character 'a' will be used to generate random number in the program.
91 |
92 | If the ```gui_path_command``` is configed correctly in the config file, a browser window should pop-up, displaying a table. As the program runs, the table will be changed to illustrate how the software finding the solution for the maze routing. If ```gui_interresult``` is configured to 1 in the config file, the GUI will show how the program propagate the wave.
93 |
94 | Although the Lee algorithm guarantees the shortest path for a single net if exist, the best solution for multiple nets is unknown. Placing one net may block another net. This problem is nP-hard. If the program found a way to connect all nets, the process will stop immediately; otherwire, the program will run for several times, depending on the amount of nets and the ```max_retry_index``` setting, then give the best result (which connects most nets).
95 |
96 | After the program finding the best solution, the best solution should be displayed in the GUI window. Meanwhile, the result will be saved as an HTML table in ```map.html``` in the same directory as the program. The result will be saved in file even if GUI is disabled. By doing so, user can use some text processing tool or software to read the result file for other programs.
97 |
98 | # Implementation
99 |
100 | ## Program Architecture
101 |
102 | This program can be divided into two parts, the back-end routing program and the front-end GUI. The back-end routing program is implemented in C, because program write in C has higher performance. When the given maze map and nets count are large, C program generally takes way less runtime compare to programs in other languages. The front-end GUI is implemented HTML with embedded CSS, because HTML/CSS GUI is extremely easy to write.
103 |
104 | When the user executes the program with GUI enabled, the program will first open the GUI. Then, the GUI will constantly be polling the result file and display the maze map and the router’s progress in the GUI window. At the same time, the program will apply the Lee Algorithm and generate result file. In this way, when there is any progress done by the back-end router, the back-end router will export the result file, and the front-end GUI poll it and display it on the screen.
105 |
106 | ```
107 | ---------- ------------ -------
108 | | Router | ---- Export result ---> | map.html | ---- Polling ---> | GUI |
109 | ---------- ------------ -------
110 | ```
111 |
112 | ## Data Structure
113 |
114 | The old terminology ```slot``` is replaced by a more precise terminology ```tile``` in this document, but the old term is still used in the code.
115 |
116 | The old terminology ```wave``` is replaced by a more precise terminology ```propagate``` in this document, but the old term is still used in the code.
117 |
118 | ### Map-object Structure
119 |
120 | Although C is not an object-orientation programming language, object-orientation programming can be manually achieved. In this program, a ```Map``` object is used to represent the maze map. The ```Map``` structures contains three elements, the height of the map, the width of the map, and the tiles of the map. The structure of ```Map``` object is given below:
121 | ```C
122 | typedef struct Map {
123 | mapaddr_t width;
124 | mapaddr_t height;
125 | mapdata_t* map;
126 | } Map;
127 | ```
128 |
129 | The map width and height are of type ```mapaddr_t``` and the tiles are of type ```mapdata_t```. User can define the type ```mapaddr_t``` and ```mapdata_t``` when compile the program to fit their own need.
130 |
131 | Type ```mapaddr_t``` is used to describe the x-y coordinates of the map tiles. When define the data type, user can use ```unsigned short int```, ```unsigned int``` or ```unsigned long long int```. This data type should be big enough to describe the x-y coordinates of any tile in the map. A ```unsigned int``` or ```uint32_t``` should be good enough since most map should be less than 4G * 4G.
132 |
133 | Type ```mapdata_t``` is used to describe the state of each map tile. This includes “free”, “obstruction”, propagate, and the ID of net using this tile. When define the data type, user can use ```unsigned short int```, ```unsigned int``` or ```unsigned long long int```. The bit length of this data type should be greater than twice of the map size or the amount of net, which is greater. User should be caution when define the data type. If this data type is too large, it consumes a lot of memory; if it is too small, it may overflow.
134 | ```
135 | 2 ^ bit_length( mapdata_t ) >= 2 * max( count( map_size ) , count( nets_size ) )
136 | ```
137 |
138 | For the structure ```Map```, its child ```map``` is used to represent the tiles of the map. ```map``` is a array (logical 2D array, but use 1D array pointer), the index of the array is used to represent the x-y position of that tile. For example, to ```map[ y * Map.width + x ]``` is used to access the tile at ```(x,y)```.
139 |
140 | Each tile can be one of the following states:
141 | - Free. Which means this tile is free to use for any net. All bits will be zero in this case.
142 | - Propagate. This is used when finding the shortest path from net source to net drain using the Lee algorithm. In this case, the first bit (MSB) will be zero, and the remaining bits represent the distance of that tile from the net source.
143 | - Obstruction. Which means this tile can not be used for any purpose. In this case, the first bit (MSB) will be one, and the remaining bits are all zero.
144 | - Used by net. This means the tile is occupied by a net. In this case, the first bit (MSB) will be one, and the remaining bits represent the net ID.
145 |
146 | An ```emun``` is used to describe those 4 situations:
147 | ```C
148 | typedef enum mapslot_type {
149 | mapslot_free,
150 | mapslot_wave,
151 | mapslot_obstruction,
152 | mapslot_net
153 | } mapslot_type;
154 | /*slot should be tile*/
155 | ```
156 |
157 | ### Map-object Method
158 |
159 | One way to implement object-oriented method is to pass a pointer of the object structure to the function. This syntax is simular to object-oriented programming using Python.
160 | ```C
161 | return_type method_name (struct object_type* object_name, params…) {…}
162 | ```
163 |
164 | In this program, there are two constructors defined for the ```Map``` object in ```map.c```. These constructors will ask the system to allocate memory to hold the maze map and return a ```Map``` object.
165 | ```C
166 | Map createMap(mapaddr_t width, mapaddr_t height); //To create an empty map, all tiles in this map are empty (not used)
167 | Map copyMapAsNew(Map srcMap); //To create a map exactly like the given map
168 | ```
169 |
170 | Because the program manually allocates (using ```malloc``` or ```calloc```) memory, a destructor is required to release the memory if a ```Map``` is no longer required. Otherwise, the program will suffer from memory leak issue.
171 | ```C
172 | void destroyMap(Map targetMap); //Destroy a map, release the map tile memory space
173 | ```
174 |
175 | The map object has a setter and a getter method used to set or get the value at any tile of the map according to its x-y position. These two methods are designed to be used internally; in another word, these are private functions, because the return value is raw unsigned number. There are two major reasons:
176 | - The main program should interactive with the ```Map``` object at an abstract level. The main program does not understand how to process those raw number, and the main program does not need to understand it.
177 | - If there is any change of the representation of the map tile, the code in main program must be changed as well. This is extremely time-consuming and error-prone.
178 | ```C
179 | mapdata_t getMapValueAt(Map readMap, mapaddr_t x, mapaddr_t y); //Get the content of a tile in the map, using x-y position
180 | void setMapValueAt(Map writeMap, mapaddr_t x, mapaddr_t y, mapdata_t value); //Set the content of a tile in the map, using x-y position
181 | ```
182 |
183 | There are some methods that are designed for main program to interact with the ```Map``` object. One thing needs to mention is, although these methods accept the ```Map``` object by value, the ```Map``` object contains a pointer to the map tiles. Therefore, the map tiles are pass by reference in fact. Modify the map tiles inside method affect the map tiles outside of the method.
184 | ```C
185 | void copyMapM2M(Map destMap, Map srcMap); //To copy the content of one map to another, without create a new one, map should be same size
186 | void setMapSlotObstruction(Map writeMap, mapaddr_t x, mapaddr_t y); //Set a tile to be obstruction
187 | void setMapSlotUsedByNet(Map writeMap, mapaddr_t x, mapaddr_t y, mapdata_t netID); //Set a tile to be used by a net
188 | void setMapSlotWave(Map writeMap, mapaddr_t x, mapaddr_t y, mapdata_t wave); //by propagate (distance)
189 | void setMapSlotFree(Map writeMap, mapaddr_t x, mapaddr_t y); //free
190 | mapslot_type getMapSlotType(Map checkMap, mapaddr_t x, mapaddr_t y); //Get map tile state (free, wave, obstruction, used by net)
191 | mapdata_t getMapSlotValue(Map checkMap, mapaddr_t x, mapaddr_t y); //After check the map tile type, get the value of it, either netID or propagate distance, or 0 for free/obstruction
192 | void cleanMap(Map map); //Clean a map, remove all propagates
193 | ```
194 |
195 | ### Map-object Neighbor Wrap Method
196 |
197 | In the Lee Algorithm, there are lot of operation that requiring the accessing of 4 neighborhood tiles of a given tile. Therefore, the ```Map``` object provides a wrap method which accept another custom method. In this wrap method, the wrap method will apply the custom method to all 4 neighborhood tiles of the given tile. To pass and retrieve data between the main function and the custom method, the wrap method accepts a pointer to a custom structure. Furthermore, the wrap method check for boundary as well. For example, if the given tile's x position is 0, the wrap will not apply the custom function to its left neighbor.
198 | ```C
199 | void applyNeighbor(Map map, mapaddr_t selfX, mapaddr_t selfY, void (*function)(), void *functionData);
200 | ```
201 |
202 | There is an example of using the wrap method:
203 | ```C
204 | struct xDataXch { //The custom structure used to pass and retrieve information
205 | mapaddr_t data1;
206 | uint8_t data2;
207 | };
208 | void xFunction(Map map, mapaddr_t x, mapaddr_t y, void* dataStruct) { //The custom method
209 | (*(struct xDataXch*)dataStruct).data1 = doSomething1();
210 | (*(struct xDataXch*)dataStruct).data2 = doSomething2();
211 | }
212 |
213 | struct xDataXch dataXch; //Init the custom structure
214 | dataXch.data2 = 0;
215 | applyNeighbor(map, 2, 3, xFunction, &dataXch); //Apply the wrap method at map(2,3)
216 |
217 | if (dataXch.data2) { //Using the data retrieved from the custom method
218 | doSomething3(dataXch.data1);
219 | }
220 | ```
221 |
222 | The wrap also comes with a random factor. In this wrap method, the wrap applies the custom method on all 4 neighbor tiles. However, if there is any conflict, the result comes from the last or first applied tile will win. Sometime, this may lead to a poor result. Consider the following situation:
223 |
224 |
225 |
226 | The router has successfully route net 1, net 2 and net3; but cannot route net 4. For net 1, assume the left-bottom is source and the right-up is the sink. As the map shows, vertical path has higher priority than horizontal path when the router place route for net 1. However, this blocks the path for net 4. If the router can place the path as the rad lines, all 4 nets can be successfully placed.
227 |
228 |
229 |
230 | With a random factor added, the router is able to place all 4 nets. The random factor can be set in the config file. Set the ```neighbor_random_index``` to zero will disable the randomization.
231 |
232 | ## Lee router
233 |
234 | This section describes the Lee router. The Lee router is a router used to route a single net. For the algorithm used to route the entire nets set, refer to the next section, the ```Main Program (Back-end router)```.
235 |
236 | The router method is in ```main.c```. The router will return true (1) if a route for the given net is found, and the route will be marked in the map. If no route can be found, this method returns false (0).
237 | ```C
238 | uint8_t router(Map map, mapdata_t netID);
239 | ```
240 |
241 | ### Step 1 - Finding Source and Sink
242 |
243 | The router method accepts two parameters, the map and the net ID.
244 |
245 | For each net, there is one source and one sink. The router will scan the entire map and find the x-y positions for both net source and sink according to the net ID paramter.
246 |
247 | ### Step 2 - Propagating
248 |
249 | Starting from the net source, the router begins to propagate. All unmarked (free) map tiles near (connected by edge, but not corner) the source will be marked "propagate 1”, all unmarked map slots near “propagate 1” will be marked as “propagate 2”, and so on. The process will continue until the net sink is reached, or no more map slots can be marked.
250 | ```
251 | run = 0;
252 | markedTiles = [source];
253 | repeat {
254 | run++;
255 | markedTiles = markedTiles.neighbor;
256 | foreach (markedTiles)
257 | markOnMap(markedTiles.elements,run);
258 | } until( markedTiles.count == 0 || markedTiles.includes(sink) );
259 | ```
260 |
261 | This method requires query, or flex-length array to story marked tiles in each run. It is easy to implement in high-level language such as JavaScript, Java or Python; however, in C, there is no such flex data structure. There are few solutions:
262 | - Using fixed-length very big array. This solution consumes a lot of memory. The term “very big” may not be big enough.
263 | - Using linked list. Hard to program, easy to have memory leak.
264 |
265 | Therefore, instead of finding neighbor of marked tiles (by using marked tiles position), the program finds tiles that are neighbor of marked tiles (by fully scan the map).
266 | ```
267 | repeat {
268 | markCount = 0;
269 | foreach(mapTiles) {
270 | if (mapTiles.element is source.neighbor) {
271 | markOnMap(mapTiles.element,1);
272 | markCount++;
273 | }
274 | else if (mapTiles.element is markedTiles.element.neighbor) {
275 | markOnMap(mapTiles.element, markedTiles.element.value + 1);
276 | markCount++;
277 | }
278 | }
279 | } until (markCount == 0 || sink.is_marked);
280 | ```
281 |
282 | The second method requires to scan the entire map in each run, but the first method (the queue/linked list method) only access those tiles modified by last run and their neighbor. In another word, the first method accesses less tiles than the second method in each run. Especially in the first run, the first method only access 4 tiles (neighbor of source), but the second method accesses all tiles in the map.
283 |
284 | However, when the map is crowd, the tiles accessed by first method will be just slightly less than the second method. In fact, flex-length array (such as linked list and hash map) has overhead. Assume the program is using linked list to implement the queue. When reading the array, the CPU needs to read the ```next``` pointer, then go to fetch the value by pointer. After each run, the program needs to walk through the linked list to destroy (release memory of) the array. Furthermore, linked list is usually saved in HEAP across different memory sectors, which means higher cache miss rate. For the second method, the CPU only need to perform a read and a pointer register increase operation. (In fact, some CPUs can increase pointer and read value in one cycle, e.g. ```LD Rd, Z+``` in AVR). The map is saved in HEAP but all in one continuous space, which means higher cache hit rate.
285 |
286 | ### Step 3 - Tracing Back
287 |
288 | After the propagate reaches the net sink, the program begins to trace back from the sink to the source to establish the route. When doing this, there may be multiple possible shortest routes, all of them has the same length. In this case, the program uses a random number to determine which path to use. Refer to the ``` Implementation --> Data Structure --> Map-object Neighbor Wrap Method``` section.
289 |
290 | ## Main Program (Back-end Router)
291 |
292 | The main program is in ```mian.c```.
293 |
294 | ### Step 1 - Initialization and Read Config
295 |
296 | When the user executes the program, the first thing the program will do is to initialize itself, including checking the user input from command line, set the random seed, and load the config file.
297 |
298 | The user must give at least one argument in the command line to the program, which is the input file’s path. If this argument is missed, the program will exit and print error information in ```stderr```.
299 |
300 | Second argument is optional, which is used to set the seed for random number generator. If the user does not provide this argument, the program will use current time as the seed of the random number generator. If the user provides this argument, the first character of this option will be used. For example, if user’s command is ```./router path_to_net_file.net abc```, then the ASCII code for character ‘a’ will be used. In another word, 0x61 is used as the seed.
301 |
302 | If the user gives more than 2 arguments in the command line, those extra arguments will be ignored.
303 |
304 | The program load config from the config file ```config.cfg``` which is in the same directory as the program. The config file is used to define the behavior of the program, such as GUI, delay, random factor etc. If the config file is missed or cannot be read by the program, the program will exit and print error information in ```stderr```.
305 |
306 | In the config file, if the ``` gui_path_command``` config is set correctly and not “manual”, the program will call the operating system to open web browser to display GUI. No matter the GUI is enabled or disabled or misconfigured, the program always export result file.
307 |
308 | ### Step 2 - Generate Empty Map
309 |
310 | The second step of the program is to read the net file and generate the empty map. The empty map is a map that contains all the obstructions and source and sinks of all nets.
311 |
312 | A parser (in ```parser.c```) is used to read the input net file. The parser will return a ```Map``` object that contains the empty map.
313 |
314 | The parser first read the first line of the input net file.
315 | - If this line contains two numbers n and m, separated by a "x", the parser will create a rectangle map with size n by m.
316 | - if this line contains only one number n, the parser will create a square map with size n by n.
317 |
318 | After the parser creating the map, the parser begins to search for nets and obstructions line by line.
319 | - If a line contains only two numbers, these two number are considered x-y position of an obstruction. In this case, the obstruction will be marked on the map.
320 | - If a line contains four numbers, the fist two number are considered x-y position for the net source, the last two number are considered x-y position for the net sink. In this case, this net will be assigned an ID (starting from 1) and marked on the map. When marking the map, there is no indication of net sink or source, because electrons can travel in both direction in route; therefore, it is not required to identify the net source and sink.
321 |
322 | For the netsfile, comments are not allowed. Number in comments may misleading the parser.
323 |
324 | The parser also counts for the number of nets, and return the net count to main program by reference.
325 |
326 | The following graph shows an empty map:
327 |
328 |
329 |
330 | ### Step 3 - Router
331 |
332 | Now, it is time to route the nets on the maze map. However, before the router begins work, the program will shuffle the net list. In another word, the order of placing nets will be different in each try.
333 |
334 | The shuffle is done by using a random number, the random factor ```priority_random_index``` can be set in the config file. Set this value to 0 will disable it. There is a very small chance that the order remains the same after shuffle due to the random number generator behavior.
335 |
336 | Then, the program will call the router method to route the maze map, one net at a time. If the router can successfully route all nets, the program will export that map as the solution and quit. If the router cannot place all nets, the program will retry for several times until the retry limit is hit or the router successfully placed all the nets. If the retry limit is hit, the program will export the result which placed most of the nets. The retry limit is determine by both the nets count and the ```max_retry_index``` in the config file.
337 |
338 | When the program retries, the program will shuffle the net list, and:
339 | - If the first net cannot be placed (for example, the source or net is separated by obstruction), the fist net to place in next try will be a random net.
340 | - Otherwise, the fist net to place in the next try will be the fail net of last try, because that net is the most difficult one to place.
341 |
342 | The reason of shuffling the net list is to find a relatively good order of placing maximum amount of net. Assume there is 5 nets, net 2 go from the most top to most bottom; net 3 go from most left to most right. In another word, net 2 and net 3 will interlock each other. Although there is some better algorithm to find the good order, such as recursive walking; using random number is the most simple way.
343 |
344 | | Try | Placement order | Comment |
345 | | --- | --- | --- |
346 | | Try 1 | 3->5->1->2 | Cannot place net 2, retry. 3 nets placed |
347 | | Try 2 | 2->1->3 | Cannot place net 3, retry. 2 nets placed |
348 | | ... | ... | ... |
349 | | Try X | 1->5->4->2->3 | Cannot place net 3, retry. 4 nets placed |
350 | | ... | ... | ... |
351 | | Try Z | ... | Retry limit reached. Give up |
352 |
353 | Try X placed maximum amount of nets, using Try X as result.
354 |
355 | ## GUI
356 |
357 | ### GUI
358 |
359 | The GUI interface is an HTML file ```gui.html```.
360 |
361 | As describe in ``` Implementation --> Program Architecture``` section, the front-end GUI of this program is a webpage. The back-end router program will route the net and generate map file; the front-end GUI will read the map file and display it on screen.
362 |
363 | However, the front-end/back-end architecture brings a critical issue. The GUI is running in web browser, which means the GUI is running in a sandbox. The GUI may read file, but it cannot write file. In another word, the back-end router GUI and the front-end GUI are communicating in a one-way link. The issue is that, the GUI cannot send signal to the router; therefore, the router may modify the result file while the GUI is reading it.
364 |
365 | The original solution is to have a JavaScript checker on the front-side. Every time when the front-end GUI reading the result file, the checker will first check the integrity of the result file. If this file is not modified by the back-end router during reading, the result will be displayed; if it is modified, the checker discards it.
366 |
367 | This solution works fine few years ago, when CORS in Firefox is not strict as today (At that time, there was CORS, but Firefox allows JavaScript program in local HTML file to read files in the same directory or subdirectories). However, nowadays, this solution is no longer available due to security reason. If a JavaScript program can read a file from local file system, it can send the local file to a remote server. This means, if a user downloads and runs an HTML file, critical information saved in downloading directory can be stolen (for example, a user may have a key file downloaded from another website). Therefore, the checker solution will not work.
368 |
369 | To accompany with the CORS policy, the only solution is to create a local web server on the user’s machine so an HTTP ```Access-Control-Allow-Origin``` can be send with the result file. However, it is not worth to pack such a complex web server with the program.
370 |
371 | The final solution is to let the back-end router to export the result as a ```