mirror of
https://github.com/YosysHQ/yosys
synced 2025-10-09 17:31:59 +00:00
sdc: refactor more
This commit is contained in:
parent
5647bdeb2b
commit
329a3783e2
1 changed files with 270 additions and 204 deletions
|
@ -1,10 +1,8 @@
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/celltypes.h"
|
|
||||||
#include "kernel/rtlil.h"
|
#include "kernel/rtlil.h"
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
#include <tcl.h>
|
#include <tcl.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <regex>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -12,6 +10,76 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct TclCall {
|
||||||
|
Tcl_Interp *interp;
|
||||||
|
int objc;
|
||||||
|
Tcl_Obj* const* objv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int redirect_unknown(TclCall call);
|
||||||
|
static size_t get_node_count(Tcl_Interp* interp);
|
||||||
|
|
||||||
|
struct BitSelection {
|
||||||
|
bool all = false;
|
||||||
|
std::vector<bool> bits = {};
|
||||||
|
void set_all() {
|
||||||
|
bits.clear();
|
||||||
|
all = true;
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
bits.clear();
|
||||||
|
all = false;
|
||||||
|
}
|
||||||
|
void set(size_t idx) {
|
||||||
|
if (all)
|
||||||
|
return;
|
||||||
|
if (idx >= bits.size())
|
||||||
|
bits.resize(idx + 1);
|
||||||
|
bits[idx] = true;
|
||||||
|
}
|
||||||
|
void merge(const BitSelection& other) {
|
||||||
|
if (all)
|
||||||
|
return;
|
||||||
|
if (other.all) {
|
||||||
|
set_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.bits.size() > bits.size())
|
||||||
|
bits.resize(other.bits.size());
|
||||||
|
for (size_t other_idx = 0; other_idx < other.bits.size(); other_idx++) {
|
||||||
|
bool other_bit = other.bits[other_idx];
|
||||||
|
if (other_bit)
|
||||||
|
set(other_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump() {
|
||||||
|
if (!all) {
|
||||||
|
for (size_t i = 0; i < bits.size(); i++)
|
||||||
|
if (bits[i])
|
||||||
|
log("\t\t [%zu]\n", i);
|
||||||
|
} else {
|
||||||
|
log("\t\t FULL\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool is_set(size_t idx) const {
|
||||||
|
if (all)
|
||||||
|
return true;
|
||||||
|
if (idx >= bits.size())
|
||||||
|
return false;
|
||||||
|
return bits[idx];
|
||||||
|
}
|
||||||
|
// TODO actually use this
|
||||||
|
void compress(size_t size) {
|
||||||
|
if (bits.size() < size)
|
||||||
|
return;
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
if (!bits[i])
|
||||||
|
return;
|
||||||
|
bits.clear();
|
||||||
|
bits.shrink_to_fit();
|
||||||
|
all = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SdcObjects {
|
struct SdcObjects {
|
||||||
enum CollectMode {
|
enum CollectMode {
|
||||||
|
@ -28,74 +96,19 @@ struct SdcObjects {
|
||||||
// return a new graph node assuming unknown is overridden
|
// return a new graph node assuming unknown is overridden
|
||||||
Graph,
|
Graph,
|
||||||
} value_mode;
|
} value_mode;
|
||||||
struct BitSelection {
|
|
||||||
bool all = false;
|
|
||||||
std::vector<bool> bits = {};
|
|
||||||
void set_all() {
|
|
||||||
bits.clear();
|
|
||||||
all = true;
|
|
||||||
}
|
|
||||||
void clear() {
|
|
||||||
bits.clear();
|
|
||||||
all = false;
|
|
||||||
}
|
|
||||||
void set(size_t idx) {
|
|
||||||
if (all)
|
|
||||||
return;
|
|
||||||
if (idx >= bits.size())
|
|
||||||
bits.resize(idx + 1);
|
|
||||||
bits[idx] = true;
|
|
||||||
}
|
|
||||||
void merge(const BitSelection& other) {
|
|
||||||
if (all)
|
|
||||||
return;
|
|
||||||
if (other.all) {
|
|
||||||
set_all();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (other.bits.size() > bits.size())
|
|
||||||
bits.resize(other.bits.size());
|
|
||||||
for (size_t other_idx = 0; other_idx < other.bits.size(); other_idx++) {
|
|
||||||
bool other_bit = other.bits[other_idx];
|
|
||||||
if (other_bit)
|
|
||||||
set(other_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void dump() {
|
|
||||||
if (!all) {
|
|
||||||
for (size_t i = 0; i < bits.size(); i++)
|
|
||||||
if (bits[i])
|
|
||||||
log("\t\t [%zu]\n", i);
|
|
||||||
} else {
|
|
||||||
log("\t\t FULL\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool is_set(size_t idx) {
|
|
||||||
if (all)
|
|
||||||
return true;
|
|
||||||
if (idx >= bits.size())
|
|
||||||
return false;
|
|
||||||
return bits[idx];
|
|
||||||
}
|
|
||||||
// TODO actually use this
|
|
||||||
void compress(size_t size) {
|
|
||||||
if (bits.size() < size)
|
|
||||||
return;
|
|
||||||
for (size_t i = 0; i < size; i++)
|
|
||||||
if (!bits[i])
|
|
||||||
return;
|
|
||||||
bits.clear();
|
|
||||||
bits.shrink_to_fit();
|
|
||||||
all = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using CellPin = std::pair<Cell*, IdString>;
|
using CellPin = std::pair<Cell*, IdString>;
|
||||||
std::vector<std::pair<std::string, Wire*>> design_ports;
|
std::vector<std::pair<std::string, Wire*>> design_ports;
|
||||||
std::vector<std::pair<std::string, Cell*>> design_cells;
|
std::vector<std::pair<std::string, Cell*>> design_cells;
|
||||||
std::vector<std::pair<std::string, CellPin>> design_pins;
|
std::vector<std::pair<std::string, CellPin>> design_pins;
|
||||||
std::vector<std::pair<std::string, Wire*>> design_nets;
|
std::vector<std::pair<std::string, Wire*>> design_nets;
|
||||||
|
|
||||||
dict<std::string, BitSelection> constrained_ports;
|
using PortPattern = std::tuple<std::string, Wire*, BitSelection>;
|
||||||
|
using PinPattern = std::tuple<std::string, SdcObjects::CellPin, BitSelection>;
|
||||||
|
std::vector<std::vector<PortPattern>> resolved_port_pattern_sets;
|
||||||
|
std::vector<std::vector<PinPattern>> resolved_pin_pattern_sets;
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
dict<std::pair<std::string, Wire*>, BitSelection> constrained_ports;
|
||||||
pool<std::pair<std::string, Cell*>> constrained_cells;
|
pool<std::pair<std::string, Cell*>> constrained_cells;
|
||||||
dict<std::pair<std::string, CellPin>, BitSelection> constrained_pins;
|
dict<std::pair<std::string, CellPin>, BitSelection> constrained_pins;
|
||||||
dict<std::pair<std::string, Wire*>, BitSelection> constrained_nets;
|
dict<std::pair<std::string, Wire*>, BitSelection> constrained_nets;
|
||||||
|
@ -156,6 +169,30 @@ struct SdcObjects {
|
||||||
sniff_module(hierarchy, top);
|
sniff_module(hierarchy, top);
|
||||||
}
|
}
|
||||||
~SdcObjects() = default;
|
~SdcObjects() = default;
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
void build_normal_result(Tcl_Interp* interp, std::vector<std::tuple<std::string, T, BitSelection>>&& resolved, U& tgt, std::function<size_t(T&)> width, Tcl_Obj*& result) {
|
||||||
|
if (!result)
|
||||||
|
result = Tcl_NewListObj(resolved.size(), nullptr);
|
||||||
|
for (auto [name, obj, matching_bits] : resolved) {
|
||||||
|
for (size_t i = 0; i < width(obj); i++)
|
||||||
|
if (matching_bits.is_set(i)) {
|
||||||
|
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
size_t node_count = get_node_count(interp);
|
||||||
|
tgt.emplace_back(std::move(resolved));
|
||||||
|
log("%zu %zu\n", node_count, tgt.size());
|
||||||
|
log_assert(node_count == tgt.size());
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void merge_as_constrained(std::vector<std::tuple<std::string, T, BitSelection>>&& resolved) {
|
||||||
|
for (auto [name, obj, matching_bits] : resolved) {
|
||||||
|
merge_or_init(std::make_pair(name, obj), constrained_pins, matching_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
void dump() {
|
void dump() {
|
||||||
std::sort(design_ports.begin(), design_ports.end());
|
std::sort(design_ports.begin(), design_ports.end());
|
||||||
std::sort(design_cells.begin(), design_cells.end());
|
std::sort(design_cells.begin(), design_cells.end());
|
||||||
|
@ -186,7 +223,9 @@ struct SdcObjects {
|
||||||
// }
|
// }
|
||||||
// log("\n");
|
// log("\n");
|
||||||
log("Constrained ports:\n");
|
log("Constrained ports:\n");
|
||||||
for (auto [name, bits] : constrained_ports) {
|
for (auto [ref, bits] : constrained_ports) {
|
||||||
|
auto [name, port] = ref;
|
||||||
|
(void)port;
|
||||||
log("\t%s\n", name.c_str());
|
log("\t%s\n", name.c_str());
|
||||||
bits.dump();
|
bits.dump();
|
||||||
}
|
}
|
||||||
|
@ -213,16 +252,6 @@ struct SdcObjects {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static bool parse_flag(char* arg, const char* flag_name, T& flag_var) {
|
|
||||||
std::string expected = std::string("-") + flag_name;
|
|
||||||
if (expected == arg) {
|
|
||||||
flag_var = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO vectors
|
// TODO vectors
|
||||||
// TODO cell arrays?
|
// TODO cell arrays?
|
||||||
struct MatchConfig {
|
struct MatchConfig {
|
||||||
|
@ -241,7 +270,7 @@ struct MatchConfig {
|
||||||
hier(hierarchical_flag ? FLAT : TREE) { }
|
hier(hierarchical_flag ? FLAT : TREE) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const std::string& pat, const MatchConfig& config) {
|
static std::pair<bool, BitSelection> matches(std::string name, const std::string& pat, const MatchConfig& config) {
|
||||||
(void)config;
|
(void)config;
|
||||||
bool got_bit_index = false;;
|
bool got_bit_index = false;;
|
||||||
int bit_idx;
|
int bit_idx;
|
||||||
|
@ -258,7 +287,7 @@ static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const
|
||||||
bit_idx = std::stoi(bit_selector);
|
bit_idx = std::stoi(bit_selector);
|
||||||
|
|
||||||
}
|
}
|
||||||
SdcObjects::BitSelection bits = {};
|
BitSelection bits = {};
|
||||||
if (name == pat_base) {
|
if (name == pat_base) {
|
||||||
if (got_bit_index) {
|
if (got_bit_index) {
|
||||||
bits.set(bit_idx);
|
bits.set(bit_idx);
|
||||||
|
@ -273,33 +302,38 @@ static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int graph_node(TclCall call) {
|
||||||
|
// TODO is that it?
|
||||||
|
return redirect_unknown(call);
|
||||||
|
}
|
||||||
|
|
||||||
static int redirect_unknown(Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) {
|
static int redirect_unknown(TclCall call) {
|
||||||
Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1);
|
// TODO redirect to different command
|
||||||
auto newObjc = objc + 1;
|
Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1);
|
||||||
Tcl_Obj **newObjv = new Tcl_Obj*[newObjc];
|
auto newObjc = call.objc + 1;
|
||||||
newObjv[0] = newCmd;
|
Tcl_Obj **newObjv = new Tcl_Obj*[newObjc];
|
||||||
for (int i = 1; i < newObjc; i++) {
|
newObjv[0] = newCmd;
|
||||||
newObjv[i] = objv[i - 1];
|
for (int i = 1; i < newObjc; i++) {
|
||||||
log("newObjv %s\n", Tcl_GetString(newObjv[i]));
|
newObjv[i] = call.objv[i - 1];
|
||||||
}
|
}
|
||||||
int result = Tcl_EvalObjv(interp, newObjc, newObjv, 0);
|
int result = Tcl_EvalObjv(call.interp, newObjc, newObjv, 0);
|
||||||
Tcl_DecrRefCount(newCmd);
|
Tcl_DecrRefCount(newCmd);
|
||||||
delete[] newObjv;
|
delete[] newObjv;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct SdcGraphNode {
|
struct SdcGraphNode {
|
||||||
using Child = std::variant<SdcGraphNode*, std::string>;
|
using Child = std::variant<SdcGraphNode*, std::string>;
|
||||||
std::vector<Child> children;
|
std::vector<Child> children;
|
||||||
SdcGraphNode() = default;
|
SdcGraphNode() = default;
|
||||||
void addChild(SdcGraphNode* child) {
|
void addChild(SdcGraphNode* child) {
|
||||||
children.push_back(child);
|
children.push_back(child);
|
||||||
}
|
}
|
||||||
void addChild(std::string tcl_string) {
|
void addChild(std::string tcl_string) {
|
||||||
children.push_back(tcl_string);
|
children.push_back(tcl_string);
|
||||||
}
|
}
|
||||||
void dump(std::ostream& os) const {
|
void dump(std::ostream& os) const {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -317,13 +351,20 @@ struct SdcGraphNode {
|
||||||
log_assert(false);
|
log_assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t get_node_count(Tcl_Interp* interp) {
|
||||||
|
const char* idx_raw = Tcl_GetVar(interp, "sdc_call_index", TCL_GLOBAL_ONLY);
|
||||||
|
log_assert(idx_raw);
|
||||||
|
std::string idx(idx_raw);
|
||||||
|
for (auto c : idx)
|
||||||
|
if (!std::isdigit(c))
|
||||||
|
log_error("sdc_call_index non-numeric value %s\n", idx.c_str());
|
||||||
|
return std::stoi(idx);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) {
|
std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) {
|
||||||
const char* idx_s = Tcl_GetVar(interp, "sdc_call_index", TCL_GLOBAL_ONLY);
|
|
||||||
log_assert(idx_s);
|
|
||||||
size_t node_count = std::stoi(idx_s);
|
|
||||||
|
|
||||||
Tcl_Obj* listObj = Tcl_GetVar2Ex(interp, "sdc_calls", nullptr, TCL_GLOBAL_ONLY);
|
Tcl_Obj* listObj = Tcl_GetVar2Ex(interp, "sdc_calls", nullptr, TCL_GLOBAL_ONLY);
|
||||||
int listLength;
|
int listLength;
|
||||||
|
@ -354,7 +395,7 @@ std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) {
|
||||||
sdc_calls.push_back(subList);
|
sdc_calls.push_back(subList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log_assert(sdc_calls.size() == node_count);
|
log_assert(sdc_calls.size() == get_node_count(interp));
|
||||||
return sdc_calls;
|
return sdc_calls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,11 +453,13 @@ void inspect_globals(Tcl_Interp* interp) {
|
||||||
std::vector<SdcGraphNode> graph = build_graph(sdc_calls);
|
std::vector<SdcGraphNode> graph = build_graph(sdc_calls);
|
||||||
dump_sdc_graph(graph, node_ownership(graph));
|
dump_sdc_graph(graph, node_ownership(graph));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// patterns -> (pattern-object-bit)s
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
std::vector<std::tuple<std::string, T, SdcObjects::BitSelection>>
|
std::vector<std::tuple<std::string, T, BitSelection>>
|
||||||
find_matching(U objects, const MatchConfig& config, const std::vector<std::string> &patterns, const char* obj_type)
|
find_matching(U objects, const MatchConfig& config, const std::vector<std::string> &patterns, const char* obj_type)
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<std::string, T, SdcObjects::BitSelection>> resolved;
|
std::vector<std::tuple<std::string, T, BitSelection>> resolved;
|
||||||
for (auto pat : patterns) {
|
for (auto pat : patterns) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto [name, obj] : objects) {
|
for (auto [name, obj] : objects) {
|
||||||
|
@ -424,6 +467,7 @@ find_matching(U objects, const MatchConfig& config, const std::vector<std::strin
|
||||||
if (does_match) {
|
if (does_match) {
|
||||||
found = true;
|
found = true;
|
||||||
resolved.push_back(std::make_tuple(name, obj, matching_bits));
|
resolved.push_back(std::make_tuple(name, obj, matching_bits));
|
||||||
|
// TODO add a continue statement, conditional on config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found)
|
||||||
|
@ -431,73 +475,120 @@ find_matching(U objects, const MatchConfig& config, const std::vector<std::strin
|
||||||
}
|
}
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
|
struct GetterOpts {
|
||||||
{
|
|
||||||
auto* objects = (SdcObjects*)data;
|
|
||||||
// When this flag is present, the search for the pattern is made in all positions in the hierarchy.
|
|
||||||
bool hierarchical_flag = false;
|
bool hierarchical_flag = false;
|
||||||
bool regexp_flag = false;
|
bool regexp_flag = false;
|
||||||
bool nocase_flag = false;
|
bool nocase_flag = false;
|
||||||
std::string separator = "/";
|
std::string separator = "/";
|
||||||
Tcl_Obj* of_objects = nullptr;
|
Tcl_Obj* of_objects = nullptr;
|
||||||
std::vector<std::string> patterns;
|
std::vector<std::string> patterns = {};
|
||||||
int i = 1;
|
std::initializer_list<const char*> legals;
|
||||||
for (; i < objc; i++) {
|
const char* name;
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "hierarchical", hierarchical_flag)) continue;
|
GetterOpts(const char* name, std::initializer_list<const char*> legals) : legals(legals), name(name) {}
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "hier", hierarchical_flag)) continue;
|
bool parse_opt(Tcl_Obj* obj, const char* opt_name) {
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "regexp", regexp_flag)) continue;
|
char* arg = Tcl_GetString(obj);
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "nocase", nocase_flag)) continue;
|
std::string expected = std::string("-") + opt_name;
|
||||||
if (!strcmp(Tcl_GetString(objv[i]), "-hsc")) {
|
if (expected == arg) {
|
||||||
separator = Tcl_GetString(objv[++i]);
|
if (!std::find_if(legals.begin(), legals.end(),
|
||||||
continue;
|
[&opt_name](const char* str) { return opt_name == str; }))
|
||||||
|
log_cmd_error("Illegal argument %s for %s.\n", expected.c_str(), name);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (!strcmp(Tcl_GetString(objv[i]), "-of_objects")) {
|
return false;
|
||||||
of_objects = objv[++i];
|
}
|
||||||
continue;
|
template<typename T>
|
||||||
|
bool parse_flag(Tcl_Obj* obj, const char* flag_name, T& flag_var) {
|
||||||
|
bool ret = parse_opt(obj, flag_name);
|
||||||
|
if (ret)
|
||||||
|
flag_var = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void parse(int objc, Tcl_Obj* const objv[]) {
|
||||||
|
int i = 1;
|
||||||
|
for (; i < objc; i++) {
|
||||||
|
if (parse_flag(objv[i], "hierarchical", hierarchical_flag)) continue;
|
||||||
|
if (parse_flag(objv[i], "hier", hierarchical_flag)) continue;
|
||||||
|
if (parse_flag(objv[i], "regexp", regexp_flag)) continue;
|
||||||
|
if (parse_flag(objv[i], "nocase", nocase_flag)) continue;
|
||||||
|
if (parse_opt(objv[i], "hsc")) {
|
||||||
|
log_assert(i + 1 < objc);
|
||||||
|
separator = Tcl_GetString(objv[++i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (parse_opt(objv[i], "of_objects")) {
|
||||||
|
log_assert(i + 1 < objc);
|
||||||
|
of_objects = objv[++i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// Onto the next loop
|
for (; i < objc; i++) {
|
||||||
break;
|
patterns.push_back(Tcl_GetString(objv[i]));
|
||||||
}
|
}
|
||||||
for (; i < objc; i++) {
|
};
|
||||||
patterns.push_back(Tcl_GetString(objv[i]));
|
void check_simple() {
|
||||||
}
|
|
||||||
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) {
|
|
||||||
if (regexp_flag || hierarchical_flag || nocase_flag || separator != "/" || of_objects) {
|
if (regexp_flag || hierarchical_flag || nocase_flag || separator != "/" || of_objects) {
|
||||||
log_error("get_pins got unexpected flags in simple mode\n");
|
log_error("%s got unexpected flags in simple mode\n", name);
|
||||||
}
|
|
||||||
if (patterns.size() != 1) {
|
|
||||||
log_error("get_pins got unexpected number of patterns in simple mode\n");
|
|
||||||
}
|
}
|
||||||
|
if (patterns.size() != 1)
|
||||||
|
log_error("%s got unexpected number of patterns in simple mode: %zu\n", name, patterns.size());
|
||||||
}
|
}
|
||||||
|
void check_simple_sep() {
|
||||||
|
if (separator != "/")
|
||||||
|
log_error("Only '/' accepted as separator");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
MatchConfig config(regexp_flag, nocase_flag, hierarchical_flag);
|
// void build_normal_result(Tcl_Interp* interp, size_t list_len, size_t width, const std::string& name, Tcl_Obj*& result, const BitSelection& matching_bits) {
|
||||||
std::vector<std::tuple<std::string, SdcObjects::CellPin, SdcObjects::BitSelection>> resolved;
|
// if (!result)
|
||||||
|
// result = Tcl_NewListObj(list_len, nullptr);
|
||||||
|
// for (size_t i = 0; i < width; i++)
|
||||||
|
// if (matching_bits.is_set(i))
|
||||||
|
// Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void merge_or_init(const T& key, dict<T, BitSelection>& dst, const BitSelection& src) {
|
||||||
|
if (dst.count(key) == 0) {
|
||||||
|
dst[key] = src;
|
||||||
|
} else {
|
||||||
|
dst[key].merge(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
|
||||||
|
{
|
||||||
|
auto* objects = (SdcObjects*)data;
|
||||||
|
GetterOpts opts("get_pins", {"hierarchical", "hier", "regexp", "nocase", "hsc", "of_objects"});
|
||||||
|
opts.parse(objc, objv);
|
||||||
|
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter)
|
||||||
|
opts.check_simple();
|
||||||
|
opts.check_simple_sep();
|
||||||
|
|
||||||
|
MatchConfig config(opts.regexp_flag, opts.nocase_flag, opts.hierarchical_flag);
|
||||||
|
std::vector<std::tuple<std::string, SdcObjects::CellPin, BitSelection>> resolved;
|
||||||
const auto& pins = objects->design_pins;
|
const auto& pins = objects->design_pins;
|
||||||
resolved = find_matching<SdcObjects::CellPin, decltype(pins)>(pins, config, patterns, "pin");
|
resolved = find_matching<SdcObjects::CellPin, decltype(pins)>(pins, config, opts.patterns, "pin");
|
||||||
|
|
||||||
if (separator != "/") {
|
|
||||||
Tcl_SetResult(interp, (char *)"Only '/' accepted as separator", TCL_STATIC);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tcl_Obj *result = nullptr;
|
Tcl_Obj *result = nullptr;
|
||||||
for (auto [name, pin, matching_bits] : resolved) {
|
if (objects->value_mode == SdcObjects::ValueMode::Normal) {
|
||||||
if (objects->value_mode == SdcObjects::ValueMode::Normal) {
|
log_error("TODO normal\n");
|
||||||
if (!result)
|
auto width = [](SdcObjects::CellPin& pin) -> size_t {
|
||||||
result = Tcl_NewListObj(resolved.size(), nullptr);
|
return (size_t)pin.first->getPort(pin.second).size();
|
||||||
size_t width = (size_t)pin.first->getPort(pin.second).size();
|
};
|
||||||
for (size_t i = 0; i < width; i++)
|
objects->build_normal_result<SdcObjects::CellPin, decltype(objects->resolved_pin_pattern_sets)>(interp, std::move(resolved), objects->resolved_pin_pattern_sets, width, result);
|
||||||
if (matching_bits.is_set(i))
|
} else if (objects->value_mode == SdcObjects::ValueMode::Graph)
|
||||||
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
|
return graph_node(TclCall{interp, objc, objv});
|
||||||
}
|
|
||||||
|
|
||||||
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
||||||
objects->constrained_pins[std::make_pair(name, pin)].merge(matching_bits);
|
objects->merge_as_constrained(std::move(resolved));
|
||||||
}
|
// merge_or_init(std::make_pair(name, pin), objects->constrained_pins, matching_bits);
|
||||||
|
// TODO
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// return objects->graph_node(interp, objc, objv, std::move(resolved), objects->resolved_pin_pattern_sets);
|
||||||
|
|
||||||
if (objects->value_mode == SdcObjects::ValueMode::Graph) {
|
|
||||||
return redirect_unknown(interp, objc, objv);
|
|
||||||
}
|
|
||||||
if (result)
|
if (result)
|
||||||
Tcl_SetObjResult(interp, result);
|
Tcl_SetObjResult(interp, result);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
@ -506,57 +597,32 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O
|
||||||
static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
|
static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
|
||||||
{
|
{
|
||||||
auto* objects = (SdcObjects*)data;
|
auto* objects = (SdcObjects*)data;
|
||||||
bool regexp_flag = false;
|
GetterOpts opts("get_ports", {"regexp", "nocase"});
|
||||||
bool nocase_flag = false;
|
opts.parse(objc, objv);
|
||||||
std::vector<std::string> patterns;
|
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter)
|
||||||
int i = 1;
|
opts.check_simple();
|
||||||
for (; i < objc; i++) {
|
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "regexp", regexp_flag)) continue;
|
|
||||||
if (parse_flag(Tcl_GetString(objv[i]), "nocase", nocase_flag)) continue;
|
|
||||||
// Onto the next loop
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (; i < objc; i++) {
|
|
||||||
patterns.push_back(Tcl_GetString(objv[i]));
|
|
||||||
}
|
|
||||||
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) {
|
|
||||||
if (regexp_flag || nocase_flag) {
|
|
||||||
log_error("get_ports got unexpected flags in simple mode\n");
|
|
||||||
}
|
|
||||||
if (patterns.size() != 1) {
|
|
||||||
log_error("get_ports got unexpected number of patterns in simple mode\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MatchConfig config(regexp_flag, nocase_flag, false);
|
MatchConfig config(opts.regexp_flag, opts.nocase_flag, false);
|
||||||
std::vector<std::tuple<std::string, Wire*, SdcObjects::BitSelection>> resolved;
|
std::vector<std::tuple<std::string, Wire*, BitSelection>> resolved;
|
||||||
const auto& ports = objects->design_ports;
|
const auto& ports = objects->design_ports;
|
||||||
resolved = find_matching<Wire*, decltype(ports)>(ports, config, patterns, "port");
|
resolved = find_matching<Wire*, decltype(ports)>(ports, config, opts.patterns, "port");
|
||||||
|
|
||||||
Tcl_Obj *result = nullptr;
|
Tcl_Obj *result = nullptr;
|
||||||
for (auto [name, wire, matching_bits] : resolved) {
|
for (auto [name, wire, matching_bits] : resolved) {
|
||||||
if (objects->value_mode == SdcObjects::ValueMode::Normal) {
|
if (objects->value_mode == SdcObjects::ValueMode::Normal)
|
||||||
if (!result)
|
log_error("TODO normal\n");
|
||||||
result = Tcl_NewListObj(resolved.size(), nullptr);
|
// objects->build_normal_result(interp, resolved.size(), wire->width, name, result, matching_bits);
|
||||||
size_t width = wire->width;
|
|
||||||
for (size_t i = 0; i < width; i++)
|
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
||||||
if (matching_bits.is_set(i))
|
merge_or_init(std::make_pair(name, wire), objects->constrained_ports, matching_bits);
|
||||||
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
|
|
||||||
}
|
|
||||||
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) {
|
|
||||||
if (objects->constrained_ports.count(name) == 0) {
|
|
||||||
objects->constrained_ports[name] = matching_bits;
|
|
||||||
} else {
|
|
||||||
objects->constrained_ports[name].merge(matching_bits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects->value_mode == SdcObjects::ValueMode::Graph) {
|
if (objects->value_mode == SdcObjects::ValueMode::Graph) {
|
||||||
return redirect_unknown(interp, objc, objv);
|
return graph_node(TclCall{interp, objc, objv});
|
||||||
|
// return objects->graph_node(interp, objc, objv, std::move(resolved), objects->resolved_port_pattern_sets);
|
||||||
}
|
}
|
||||||
|
if (result)
|
||||||
Tcl_SetObjResult(interp, result);
|
Tcl_SetObjResult(interp, result);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,10 +658,10 @@ static int ys_track_typed_key_cmd(ClientData data, Tcl_Interp *interp, int objc,
|
||||||
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
|
||||||
std::string key_name = Tcl_GetString(objv[1]);
|
std::string key_name = Tcl_GetString(objv[1]);
|
||||||
Tcl_Obj* key_value = objv[2];
|
Tcl_Obj* key_value = objv[2];
|
||||||
std::string key_expect_type = Tcl_GetString(objv[3]);
|
std::string key_expect_type = Tcl_GetString(objv[3]);
|
||||||
std::string proc_name = Tcl_GetString(objv[4]);
|
std::string proc_name = Tcl_GetString(objv[4]);
|
||||||
|
|
||||||
auto track_typed = [key_expect_type, objects, proc_name, key_name](const char* str) -> void {
|
auto track_typed = [key_expect_type, objects, proc_name, key_name](const char* str) -> void {
|
||||||
auto split = split_at(str);
|
auto split = split_at(str);
|
||||||
|
@ -608,7 +674,7 @@ static int ys_track_typed_key_cmd(ClientData data, Tcl_Interp *interp, int objc,
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto [name, pin] : objects->design_pins) {
|
for (auto [name, pin] : objects->design_pins) {
|
||||||
log_error("TODO temporarily disabled due to working on a different flow\n");
|
log_error("TODO temporarily disabled due to working on a different flow\n");
|
||||||
// if (name + "/" + pin->name.str() == str) {
|
// if (name + "/" + pin.name.str() == str) {
|
||||||
// found = true;
|
// found = true;
|
||||||
// objects->constrained_pins.insert(std::make_pair(name, pin));
|
// objects->constrained_pins.insert(std::make_pair(name, pin));
|
||||||
// break; // resolved, expected unique
|
// break; // resolved, expected unique
|
||||||
|
@ -674,7 +740,7 @@ public:
|
||||||
struct SdcPass : public Pass {
|
struct SdcPass : public Pass {
|
||||||
// TODO help
|
// TODO help
|
||||||
SdcPass() : Pass("sdc", "sniff at some SDC") { }
|
SdcPass() : Pass("sdc", "sniff at some SDC") { }
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
|
||||||
log_header(design, "Executing SDC pass.\n");
|
log_header(design, "Executing SDC pass.\n");
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
std::vector<std::string> opensta_stubs_paths;
|
std::vector<std::string> opensta_stubs_paths;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue