Skip to content

Commit 07d15e2

Browse files
committed
WIP client for handling SDC commands through libsdcparse (hack)
Signed-off-by: Krzysztof Boronski <[email protected]>
1 parent 1cec573 commit 07d15e2

File tree

1 file changed

+68
-6
lines changed

1 file changed

+68
-6
lines changed

vpr/src/base/xdc_constraints.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <fstream>
55
#include <utility>
66
#include <functional>
7+
#include <unordered_set>
78
#include <tcl/tcl.h>
89

910
#include "globals.h"
@@ -13,6 +14,8 @@
1314
#include "tclcpp.h"
1415
#include "xdc_constraints.h"
1516

17+
#include "sdcparse.hpp"
18+
1619
enum class e_XDCProperty {
1720
XDC_PROP_PACKAGE_PIN,
1821
XDC_PROP_IOSTANDARD,
@@ -107,7 +110,7 @@ class TclPhysicalConstraintsClient : public TclClient {
107110
if (pin_name == nullptr)
108111
return this->_ret_error("set_property: pin_name of PACKAGE_PIN should be a string.");
109112

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);
111114
size_t port_count = port_list.size();
112115
if (port_count != 1)
113116
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 {
161164
int _set_property_iostandard(Tcl_Obj* tcl_io_standard, Tcl_Obj* tcl_ports) {
162165
const char* io_standard = Tcl_GetString(tcl_io_standard);
163166

164-
auto ports = tcl_obj_getlist<AtomPortId>(static_cast<TclClient*>(this), tcl_ports);
167+
auto ports = tcl_obj_getlist<AtomPortId>(this, tcl_ports);
165168

166169
return this->_do_set_property_iostandard(io_standard, ports);
167170
}
@@ -190,7 +193,7 @@ class TclPhysicalConstraintsClient : public TclClient {
190193
}
191194

192195
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);
194197
}
195198

196199
int _do_get_port(const char* pin_name, AtomPortId* port_) {
@@ -234,6 +237,53 @@ class TclPhysicalConstraintsClient : public TclClient {
234237
}
235238
};
236239

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+
237287
REGISTER_TCL_TYPE_W_STR_UPDATE(AtomPortId)
238288
(Tcl_Obj* obj) {
239289
const auto* port = tcl_obj_getptr<AtomPortId>(obj);
@@ -246,28 +296,40 @@ END_REGISTER_TCL_TYPE;
246296
VprConstraints read_xdc_constraints_to_vpr(std::vector<XDCStream>&& xdc_streams, const t_arch& arch, AtomNetlist& netlist) {
247297
VprConstraints constraints;
248298
TclPhysicalConstraintsClient pc_client(constraints, arch, netlist);
299+
TclSDCLegacyClient sdc_client;
249300

250301
TclCtx::with_ctx<void>([&](TclCtx& ctx) {
251302
/*
252303
* Tcl by default will interpret bus indices as calls to commands
253304
* (eg. in[0] gets interpreted as call to command `i` with argument being a
254305
* 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.
255309
*/
256-
std::istringstream fix_port_indexing(
310+
std::istringstream tcl_setup(
257311
"rename unknown _original_unknown\n"
258312
"proc unknown args {\n"
259313
" set result [scan [lindex $args 0] \"%d\" value]\n"
260314
" if { $result == 1 && [llength $args] == 1 } {\n"
261315
" return \\[$value\\]\n"
262316
" } 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"
264324
" }\n"
265325
"}");
266-
ctx.read_tcl(fix_port_indexing);
326+
ctx.read_tcl(tcl_setup);
267327

268328
/* Add types and commands to handle XDC files */
269329
ctx.add_tcl_type<AtomPortId>();
270330
ctx.add_tcl_client<TclPhysicalConstraintsClient>(pc_client);
331+
/* Handle unknown commands through TclSDCLegacyClient */
332+
ctx.add_tcl_client<TclSDCLegacyClient>(sdc_client);
271333

272334
/* Read and interpret XDCs */
273335
for (auto& stream : xdc_streams) {

0 commit comments

Comments
 (0)