@@ -55,6 +55,7 @@ def __init__(
55
55
pad_file = None ,
56
56
additional_files = None ,
57
57
additional_files_list_add = None ,
58
+ circuit_constraint_list_add = None
58
59
):
59
60
self .task_name = task_name
60
61
self .config_dir = config_dir
@@ -81,6 +82,9 @@ def __init__(
81
82
self .pad_file = pad_file
82
83
self .additional_files = additional_files
83
84
self .additional_files_list_add = additional_files_list_add
85
+ self .circuit_constraints = parse_circuit_constraint_list (circuit_constraint_list_add ,
86
+ self .circuits ,
87
+ self .archs )
84
88
85
89
86
90
# pylint: enable=too-few-public-methods
@@ -225,7 +229,9 @@ def load_task_config(config_file) -> TaskConfig:
225
229
# Interpret the file
226
230
key_values = {}
227
231
for line in values :
228
- key , value = line .split ("=" )
232
+ # Split the key and value using only the first equal sign. This allows
233
+ # the value to have an equal sign.
234
+ key , value = line .split ("=" , 1 )
229
235
230
236
# Trim whitespace
231
237
key = key .strip ()
@@ -300,6 +306,73 @@ def check_include_fields(config_file, key_values):
300
306
)
301
307
)
302
308
309
+ def parse_circuit_constraint_list (
310
+ circuit_constraint_list , circuits_list , arch_list
311
+ ) -> dict :
312
+ """
313
+ Parse the circuit constraints passed in via the config file.
314
+ Circuit constraints are expected to have the following syntax:
315
+ (<circuit>, <constr_key>=<constr_val>)
316
+ This function generates a dictionary which can be accessed:
317
+ circuit_constraints[circuit][constr_key]
318
+ If this dictionary returns "None", then the circuit is unconstrained for
319
+ that key.
320
+ """
321
+
322
+ # Constraint keys that can be specified.
323
+ circuit_constraint_keys = set (
324
+ [
325
+ "arch" ,
326
+ "device" ,
327
+ "constraints" ,
328
+ ]
329
+ )
330
+
331
+ # Initialize the dictionary to be unconstrained for all circuits and keys.
332
+ res_circuit_constraints = {
333
+ circuit : {constraint_key : None for constraint_key in circuit_constraint_keys }
334
+ for circuit in circuits_list
335
+ }
336
+
337
+ # If there were no circuit constraints passed by the user, return dictionary
338
+ # of Nones.
339
+ if circuit_constraint_list is None :
340
+ return res_circuit_constraints
341
+
342
+ # Parse the circuit constraint list
343
+ for circuit_constraint in circuit_constraint_list :
344
+ # Remove the round brackets.
345
+ if circuit_constraint [0 ] != '(' or circuit_constraint [- 1 ] != ')' :
346
+ raise VtrError (f"Circuit constraint syntax error: \" { circuit_constraint } \" " )
347
+ circuit_constraint = circuit_constraint [1 :- 1 ]
348
+ # Split the circuit and the constraint
349
+ split_constraint_line = circuit_constraint .split (',' )
350
+ if len (split_constraint_line ) != 2 :
351
+ raise VtrError (f"Circuit constraint has too many arguments: \" { circuit_constraint } \" " )
352
+ circuit = split_constraint_line [0 ].strip ()
353
+ constraint = split_constraint_line [1 ].strip ()
354
+ # Check that the circuit actually exists.
355
+ if circuit not in circuits_list :
356
+ raise VtrError (f"Cannot constrain circuit \" { circuit } \" , circuit has not been added" )
357
+ # Parse the constraint
358
+ split_constraint = constraint .split ("=" )
359
+ if len (split_constraint ) != 2 :
360
+ raise VtrError (f"Circuit constraint syntax error: \" { circuit_constraint } \" " )
361
+ constr_key = split_constraint [0 ].strip ()
362
+ constr_val = split_constraint [1 ].strip ()
363
+ # Check that the constr_key is valid.
364
+ if constr_key not in circuit_constraint_keys :
365
+ raise VtrError (f"Invalid constraint \" { constr_key } \" used on circuit \" { circuit } \" " )
366
+ # In the case of arch constraints, make sure this arch exists.
367
+ if constr_key == "arch" and constr_val not in arch_list :
368
+ raise VtrError (f"Cannot constrain arch \" { constr_key } \" , arch has not been added" )
369
+ # Make sure this circuit is not already constrained with this constr_arg
370
+ if res_circuit_constraints [circuit ][constr_key ] is not None :
371
+ raise VtrError (f"Circuit \" { circuit } \" cannot be constrained more than once" )
372
+ # Add the constraint for this circuit
373
+ res_circuit_constraints [circuit ][constr_key ] = constr_val
374
+
375
+ return res_circuit_constraints
303
376
304
377
def shorten_task_names (configs , common_task_prefix ):
305
378
"""
@@ -496,6 +569,11 @@ def create_jobs(args, configs, after_run=False) -> List[Job]:
496
569
]
497
570
498
571
for arch , circuit , noc_traffic in combinations :
572
+ # If the circuit is constrained to only run on a specific arch, and
573
+ # this arch is not that arch, skip this combination.
574
+ circuit_arch_constraint = config .circuit_constraints [circuit ]["arch" ]
575
+ if circuit_arch_constraint is not None and circuit_arch_constraint != arch :
576
+ continue
499
577
golden_results = load_parse_results (
500
578
str (PurePath (config .config_dir ).joinpath ("golden_results.txt" ))
501
579
)
@@ -613,6 +691,10 @@ def create_job(
613
691
cmd += ["-expect_fail" , expected_vpr_status ]
614
692
current_parse_cmd = parse_cmd .copy ()
615
693
694
+ # Apply the command-line circuit constraints provided by the circuit
695
+ # constraint list in the config file.
696
+ apply_cmd_line_circuit_constraints (cmd , circuit , config )
697
+
616
698
if config .parse_file :
617
699
current_parse_cmd += [
618
700
"arch={}" .format (arch ),
@@ -697,6 +779,19 @@ def ret_expected_vpr_status(arch, circuit, golden_results, script_params=None):
697
779
698
780
return golden_metrics ["vpr_status" ]
699
781
782
+ def apply_cmd_line_circuit_constraints (cmd , circuit , config ):
783
+ """
784
+ Apply the circuit constraints to the command line. If the circuit is not
785
+ constrained for any key, this method will not do anything.
786
+ """
787
+ # Check if this circuit is constrained to a specific device.
788
+ constrained_device = config .circuit_constraints [circuit ]["device" ]
789
+ if constrained_device is not None :
790
+ cmd += ["--device" , constrained_device ]
791
+ # Check if the circuit has constrained atom locations.
792
+ circuit_vpr_constraints = config .circuit_constraints [circuit ]["constraints" ]
793
+ if circuit_vpr_constraints is not None :
794
+ cmd += ["--read_vpr_constraints" , circuit_vpr_constraints ]
700
795
701
796
def resolve_vtr_source_file (config , filename , base_dir = "" ):
702
797
"""
0 commit comments