4
4
#include < fstream>
5
5
#include < utility>
6
6
#include < functional>
7
+ #include < unordered_set>
7
8
#include < tcl/tcl.h>
8
9
9
10
#include " globals.h"
13
14
#include " tclcpp.h"
14
15
#include " xdc_constraints.h"
15
16
17
+ #include " sdcparse.hpp"
18
+
16
19
enum class e_XDCProperty {
17
20
XDC_PROP_PACKAGE_PIN,
18
21
XDC_PROP_IOSTANDARD,
@@ -107,7 +110,7 @@ class TclPhysicalConstraintsClient : public TclClient {
107
110
if (pin_name == nullptr )
108
111
return this ->_ret_error (" set_property: pin_name of PACKAGE_PIN should be a string." );
109
112
110
- auto port_list = tcl_obj_getlist<AtomPortId>(static_cast <TclClient*>( this ) , tcl_ports);
113
+ auto port_list = tcl_obj_getlist<AtomPortId>(this , tcl_ports);
111
114
size_t port_count = port_list.size ();
112
115
if (port_count != 1 )
113
116
return this ->_ret_error (" set_property PACKAGE_PIN: Expected 1 port, got " + std::to_string (port_count) + " ." );
@@ -161,7 +164,7 @@ class TclPhysicalConstraintsClient : public TclClient {
161
164
int _set_property_iostandard (Tcl_Obj* tcl_io_standard, Tcl_Obj* tcl_ports) {
162
165
const char * io_standard = Tcl_GetString (tcl_io_standard);
163
166
164
- auto ports = tcl_obj_getlist<AtomPortId>(static_cast <TclClient*>( this ) , tcl_ports);
167
+ auto ports = tcl_obj_getlist<AtomPortId>(this , tcl_ports);
165
168
166
169
return this ->_do_set_property_iostandard (io_standard, ports);
167
170
}
@@ -190,7 +193,7 @@ class TclPhysicalConstraintsClient : public TclClient {
190
193
}
191
194
192
195
auto port_list = this ->_list <AtomPortId, decltype (port_ids)>(this , std::move (port_ids));
193
- this ->_ret_list <AtomPortId>(reinterpret_cast <void *>(this ), port_list);
196
+ return this ->_ret_list <AtomPortId>(reinterpret_cast <void *>(this ), port_list);
194
197
}
195
198
196
199
int _do_get_port (const char * pin_name, AtomPortId* port_) {
@@ -234,6 +237,53 @@ class TclPhysicalConstraintsClient : public TclClient {
234
237
}
235
238
};
236
239
240
+ class TclSDCLegacyClient : public TclClient {
241
+ public:
242
+ TclSDCLegacyClient () {
243
+ static const std::unordered_set<std::string> sdc_commands ({
244
+ " create_clock" ,
245
+ " set_input_delay" ,
246
+ " set_output_delay" ,
247
+ " set_clock_groups" ,
248
+ " set_false_path" ,
249
+ " set_max_delay " ,
250
+ " set_min_delay " ,
251
+ " set_multicycle_path" ,
252
+ " set_clock_uncertainty" ,
253
+ " set_clock_latency " ,
254
+ " set_disable_timing" ,
255
+ " set_timing_derate "
256
+ });
257
+
258
+ this ->_recognized_sdc_commands = &sdc_commands;
259
+ }
260
+
261
+ template <typename F>
262
+ void register_methods (F register_method) {
263
+ register_method (" try_sdcparse" , &TclSDCLegacyClient::try_sdcparse);
264
+ }
265
+
266
+ int try_sdcparse (int objc, Tcl_Obj* const objvp[]) {
267
+ if (objc != 2 )
268
+ this ->_ret_error (" try_sdcparse: wrong number of arguments (" + std::to_string (objc) +" ). Expected 2." );
269
+
270
+ Tcl_Obj* cmd_args_obj = objvp[1 ];
271
+
272
+ TclDynList cmd_args = tcl_obj_getdynlist (this , objvp[1 ]);
273
+ if (cmd_args.size () < 2 )
274
+ this ->_ret_error (" try_sdcparse: command contains no arguments." );
275
+
276
+ const char * cmd = Tcl_GetString (cmd_args[1 ]);
277
+ if (this ->_recognized_sdc_commands ->count (std::string (cmd)))
278
+ this ->_ret_error (std::string (cmd) + " : SDC compatibility layer is not implemented yet." );
279
+ else
280
+ this ->_ret_error (" Unrecognized comand " + std::string (cmd) + " ." );
281
+ }
282
+
283
+ protected:
284
+ const std::unordered_set<std::string>* _recognized_sdc_commands;
285
+ };
286
+
237
287
REGISTER_TCL_TYPE_W_STR_UPDATE (AtomPortId)
238
288
(Tcl_Obj* obj) {
239
289
const auto * port = tcl_obj_getptr<AtomPortId>(obj);
@@ -246,28 +296,40 @@ END_REGISTER_TCL_TYPE;
246
296
VprConstraints read_xdc_constraints_to_vpr (std::vector<XDCStream>&& xdc_streams, const t_arch& arch, AtomNetlist& netlist) {
247
297
VprConstraints constraints;
248
298
TclPhysicalConstraintsClient pc_client (constraints, arch, netlist);
299
+ TclSDCLegacyClient sdc_client;
249
300
250
301
TclCtx::with_ctx<void >([&](TclCtx& ctx) {
251
302
/*
252
303
* Tcl by default will interpret bus indices as calls to commands
253
304
* (eg. in[0] gets interpreted as call to command `i` with argument being a
254
305
* result of calling `0`). This overrides this behaviour.
306
+ *
307
+ * Additionally it attempts to call `try_sdcparse` if the command is unknown.
308
+ * This is used as a workaround for passing sdc_commands to libsdcparse.
255
309
*/
256
- std::istringstream fix_port_indexing (
310
+ std::istringstream tcl_setup (
257
311
" rename unknown _original_unknown\n "
258
312
" proc unknown args {\n "
259
313
" set result [scan [lindex $args 0] \" %d\" value]\n "
260
314
" if { $result == 1 && [llength $args] == 1 } {\n "
261
315
" return \\ [$value\\ ]\n "
262
316
" } else {\n "
263
- " uplevel 1 [list _original_unknown {*}$args]\n "
317
+ " set cmd [list _original_unknown {*}$args]\n "
318
+ " set was_sdc [try_sdcparse $cmd]\n "
319
+ " if { $was_sdc == 1 } {\n "
320
+ " return\n "
321
+ " } else {\n "
322
+ " uplevel 1 $cmd\n "
323
+ " }\n "
264
324
" }\n "
265
325
" }" );
266
- ctx.read_tcl (fix_port_indexing );
326
+ ctx.read_tcl (tcl_setup );
267
327
268
328
/* Add types and commands to handle XDC files */
269
329
ctx.add_tcl_type <AtomPortId>();
270
330
ctx.add_tcl_client <TclPhysicalConstraintsClient>(pc_client);
331
+ /* Handle unknown commands through TclSDCLegacyClient */
332
+ ctx.add_tcl_client <TclSDCLegacyClient>(sdc_client);
271
333
272
334
/* Read and interpret XDCs */
273
335
for (auto & stream : xdc_streams) {
0 commit comments