diff --git a/passes/cmds/sdc/graph-stubs.sdc b/passes/cmds/sdc/graph-stubs.sdc index b668f4d18..a6601f7f8 100644 --- a/passes/cmds/sdc/graph-stubs.sdc +++ b/passes/cmds/sdc/graph-stubs.sdc @@ -1,4 +1,21 @@ proc unknown {args} { + # Check if it's a getter + if {[llength $args] > 0} { + set first_arg [lindex $args 0] + if {[string match "get_*" $first_arg]} { + # It's a getter, has it been redirected from specialized C++ code? + if {[llength $args] > 1} { + set second_arg [lindex $args 1] + if {$second_arg ne "-getter-validated"} { + error "Unknown getter: $first_arg" + } + } else { + error "Unknown getter: $first_arg" + } + } + } + # TODO this safety feature could be optional via a global + global sdc_call_index global sdc_calls if {![info exists sdc_call_index]} { @@ -15,4 +32,11 @@ proc unknown {args} { } proc list {args} { return [unknown "list" {*}$args] -} \ No newline at end of file +} +proc get_clocks {args} { + # get_clocks isn't a design object getter + # because clocks aren't design objects, just aliases + # so the referred to clock pin already are being tracked + # as arguments of uninterpreted create_clock command or similar + return [unknown "get_clocks" "-getter-validated" {*}$args] +} diff --git a/passes/cmds/sdc/sdc.cc b/passes/cmds/sdc/sdc.cc index 030a57c6c..1da4e0d80 100644 --- a/passes/cmds/sdc/sdc.cc +++ b/passes/cmds/sdc/sdc.cc @@ -344,9 +344,32 @@ static std::pair matches(std::string name, const std::string } } -static int graph_node(TclCall call) { - // TODO is that it? - return redirect_unknown(call); +static int getter_graph_node(TclCall call) { + // Insert -getter-validated as first argument for passing to unknown + // to distinguish resolved and unknown getters. + // For example, if call is ["get_foo", "-bar"] + // then newCall is ["get_foo", "-getter-validated", "-bar"] + Tcl_Obj* validity_tag = Tcl_NewStringObj("-getter-validated", -1); + Tcl_IncrRefCount(validity_tag); + std::vector newObjv(call.objc + 1); + log_assert(call.objc > 0); + newObjv[0] = call.objv[0]; + newObjv[1] = validity_tag; + for (int i = 1; i < call.objc; ++i) { + newObjv[i + 1] = call.objv[i]; + } + // Send the vector to the Tcl land + Tcl_Obj** allocatedObjv = new Tcl_Obj*[call.objc + 1]; + for (int i = 0; i < call.objc + 1; ++i) { + allocatedObjv[i] = newObjv[i]; + } + TclCall newCall { + .interp = call.interp, + .objc = call.objc + 1, + .objv = allocatedObjv + }; + // Finally, redirect to unknown handler + return redirect_unknown(newCall); } static int redirect_unknown(TclCall call) { @@ -610,7 +633,7 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O const auto& pins = objects->design_pins; resolved = find_matching(pins, config, opts.patterns, "pin"); - return graph_node(TclCall{interp, objc, objv}); + return getter_graph_node(TclCall{interp, objc, objv}); } static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) @@ -631,7 +654,7 @@ static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_ merge_or_init(std::make_pair(name, wire), objects->constrained_ports, matching_bits); } - return graph_node(TclCall{interp, objc, objv}); + return getter_graph_node(TclCall{interp, objc, objv}); } static int sdc_get_nets_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) @@ -652,7 +675,7 @@ static int sdc_get_nets_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O merge_or_init(std::make_pair(name, wire), objects->constrained_nets, matching_bits); } - return graph_node(TclCall{interp, objc, objv}); + return getter_graph_node(TclCall{interp, objc, objv}); } class SDCInterpreter diff --git a/tests/sdc/get_foo.sdc b/tests/sdc/get_foo.sdc new file mode 100644 index 000000000..0ea5ea34a --- /dev/null +++ b/tests/sdc/get_foo.sdc @@ -0,0 +1 @@ +get_foo -bar 1 diff --git a/tests/sdc/unknown-getter.sh b/tests/sdc/unknown-getter.sh new file mode 100755 index 000000000..9038834c6 --- /dev/null +++ b/tests/sdc/unknown-getter.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +! ../../yosys -p 'read_verilog alu_sub.v; proc; hierarchy -auto-top; sdc get_foo.sdc' 2>&1 | grep 'Unknown getter'