aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/verific/verific.h
blob: 88a6cc0ba1752fd1fa661fc18eccd2298c9766f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifdef YOSYS_ENABLE_VERIFIC

#include "DataBase.h"

YOSYS_NAMESPACE_BEGIN

extern int verific_verbose;

extern bool verific_import_pending;
extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());

extern pool<int> verific_sva_prims;

struct VerificImporter;

struct VerificClocking {
	RTLIL::Module *module = nullptr;
	Verific::Net *clock_net = nullptr;
	Verific::Net *enable_net = nullptr;
	Verific::Net *disable_net = nullptr;
	Verific::Net *body_net = nullptr;
	Verific::Net *cond_net = nullptr;
	SigBit clock_sig = State::Sx;
	SigBit enable_sig = State::S1;
	SigBit disable_sig = State::S0;
	bool posedge = true;
	bool gclk = false;

	VerificClocking() { }
	VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false);
	RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const());
	RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value);
	RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q);

	bool property_matches_sequence(const VerificClocking &seq) const {
		if (clock_net != seq.clock_net)
			return false;
		if (enable_net != seq.enable_net)
			return false;
		if (posedge != seq.posedge)
			return false;
		return true;
	}
};

struct VerificImporter
{
	RTLIL::Module *module;
	Verific::Netlist *netlist;

	std::map<Verific::Net*, RTLIL::SigBit> net_map;
	std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
	pool<Verific::Net*, hash_ptr_ops> any_all_nets;

	bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
	bool mode_autocover;

	VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover);

	RTLIL::SigBit net_map_at(Verific::Net *net);

	RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
	void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj);

	RTLIL::SigSpec operatorInput(Verific::Instance *inst);
	RTLIL::SigSpec operatorInput1(Verific::Instance *inst);
	RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
	RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
	RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr);

	bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
	bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);

	void merge_past_ffs_clock(pool<RTLIL::Cell*> &candidates, SigBit clock, bool clock_pol);
	void merge_past_ffs(pool<RTLIL::Cell*> &candidates);

	void import_netlist(RTLIL::Design *design, Verific::Netlist *nl, std::set<Verific::Netlist*> &nl_todo);
};

void verific_import_sva_assert(VerificImporter *importer, Verific::Instance *inst);
void verific_import_sva_assume(VerificImporter *importer, Verific::Instance *inst);
void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst);
void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst);
bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net);

extern int verific_sva_fsm_limit;

YOSYS_NAMESPACE_END

#endif
pan class="n">std::string &in) { if(in == "") return L""; std::wstring out; out.resize(MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/NULL, /*cchWideChar=*/0)); int written = MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/&out[0], /*cchWideChar=*/(int)out.length()); log_assert(written == (int)out.length()); return out; } static std::string wstr2str(const std::wstring &in) { if(in == L"") return ""; std::string out; out.resize(WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/NULL, /*cbMultiByte=*/0, /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL)); int written = WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/&out[0], /*cbMultiByte=*/(int)out.length(), /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL); log_assert(written == (int)out.length()); return out; } static std::string get_last_error_str() { DWORD last_error = GetLastError(); LPWSTR out_w; DWORD size_w = FormatMessageW(/*dwFlags=*/FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS, /*lpSource=*/NULL, /*dwMessageId=*/last_error, /*dwLanguageId=*/0, /*lpBuffer=*/(LPWSTR)&out_w, /*nSize=*/0, /*Arguments=*/NULL); if (size_w == 0) return std::to_string(last_error); std::string out = wstr2str(std::wstring(out_w, size_w)); LocalFree(out_w); return out; } #endif using json11::Json; struct RpcServer { std::string name; RpcServer(const std::string &name) : name(name) { } virtual ~RpcServer() { } virtual void write(const std::string &data) = 0; virtual std::string read() = 0; Json call(const Json &json_request) { std::string request; json_request.dump(request); request += '\n'; log_debug("RPC frontend request: %s", request.c_str()); write(request); std::string response = read(); log_debug("RPC frontend response: %s", response.c_str()); std::string error; Json json_response = Json::parse(response, error); if (json_response.is_null()) log_cmd_error("parsing JSON failed: %s\n", error.c_str()); if (json_response["error"].is_string()) log_cmd_error("RPC frontend returned an error: %s\n", json_response["error"].string_value().c_str()); return json_response; } std::vector<std::string> get_module_names() { Json response = call(Json::object { { "method", "modules" }, }); bool is_valid = true; std::vector<std::string> modules; if (response["modules"].is_array()) { for (auto &json_module : response["modules"].array_items()) { if (json_module.is_string()) modules.push_back(json_module.string_value()); else is_valid = false; } } else is_valid = false; if (!is_valid) log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); return modules; } std::pair<std::string, std::string> derive_module(const std::string &module, const dict<RTLIL::IdString, RTLIL::Const> &parameters) { Json::object json_parameters; for (auto &param : parameters) { std::string type, value; if (param.second.flags & RTLIL::CONST_FLAG_REAL) { type = "real"; value = param.second.decode_string(); } else if (param.second.flags & RTLIL::CONST_FLAG_STRING) { type = "string"; value = param.second.decode_string(); } else if ((param.second.flags & ~RTLIL::CONST_FLAG_SIGNED) == RTLIL::CONST_FLAG_NONE) { type = (param.second.flags & RTLIL::CONST_FLAG_SIGNED) ? "signed" : "unsigned"; value = param.second.as_string(); } else log_cmd_error("Unserializable constant flags 0x%x\n", param.second.flags); json_parameters[param.first.str()] = Json::object { { "type", type }, { "value", value }, }; } Json response = call(Json::object { { "method", "derive" }, { "module", module }, { "parameters", json_parameters }, }); bool is_valid = true; std::string frontend, source; if (response["frontend"].is_string()) frontend = response["frontend"].string_value(); else is_valid = false; if (response["source"].is_string()) source = response["source"].string_value(); else is_valid = false; if (!is_valid) log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); return std::make_pair(frontend, source); } }; struct RpcModule : RTLIL::Module { std::shared_ptr<RpcServer> server; RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool /*mayfail*/) YS_OVERRIDE { std::string stripped_name = name.str(); if (stripped_name.compare(0, 9, "$abstract") == 0) stripped_name = stripped_name.substr(9); log_assert(stripped_name[0] == '\\'); log_header(design, "Executing RPC frontend `%s' for module `%s'.\n", server->name.c_str(), stripped_name.c_str()); std::string parameter_info; for (auto &param : parameters) { log("Parameter %s = %s\n", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); parameter_info += stringf("%s=%s", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); } std::string derived_name; if (parameters.empty()) derived_name = stripped_name; else if (parameter_info.size() > 60) derived_name = "$paramod$" + sha1(parameter_info) + stripped_name; else derived_name = "$paramod" + stripped_name + parameter_info; if (design->has(derived_name)) { log("Found cached RTLIL representation for module `%s'.\n", derived_name.c_str()); } else { std::string command, input; std::tie(command, input) = server->derive_module(stripped_name.substr(1), parameters); std::istringstream input_stream(input); RTLIL::Design *derived_design = new RTLIL::Design; Frontend::frontend_call(derived_design, &input_stream, "<rpc>" + derived_name.substr(8), command); derived_design->check(); dict<std::string, std::string> name_mangling; bool found_derived_top = false; for (auto module : derived_design->modules()) { std::string original_name = module->name.str(); if (original_name == stripped_name) { found_derived_top = true; name_mangling[original_name] = derived_name; } else { name_mangling[original_name] = derived_name + module->name.str(); } } if (!found_derived_top) log_cmd_error("RPC frontend did not return requested module `%s`!\n", stripped_name.c_str()); for (auto module : derived_design->modules()) for (auto cell : module->cells()) if (name_mangling.count(cell->type.str())) cell->type = name_mangling[cell->type.str()]; for (auto module : derived_design->modules_) { std::string mangled_name = name_mangling[module.first.str()]; log("Importing `%s' as `%s'.\n", log_id(module.first), log_id(mangled_name)); module.second->name = mangled_name; module.second->design = design; module.second->attributes.erase(ID::top); if (!module.second->has_attribute(ID::hdlname)) module.second->set_string_attribute(ID::hdlname, module.first.str()); design->modules_[mangled_name] = module.second; derived_design->modules_.erase(module.first); } delete derived_design; } return derived_name; } RTLIL::Module *clone() const YS_OVERRIDE { RpcModule *new_mod = new RpcModule; new_mod->server = server; cloneInto(new_mod); return new_mod; } }; #if defined(_WIN32) #if defined(_MSC_VER) #include <BaseTsd.h> typedef SSIZE_T ssize_t; #endif struct HandleRpcServer : RpcServer { HANDLE hsend, hrecv; HandleRpcServer(const std::string &name, HANDLE hsend, HANDLE hrecv) : RpcServer(name), hsend(hsend), hrecv(hrecv) { } void write(const std::string &data) YS_OVERRIDE { log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1); ssize_t offset = 0; do { DWORD data_written; if (!WriteFile(hsend, &data[offset], data.length() - offset, &data_written, /*lpOverlapped=*/NULL)) log_cmd_error("WriteFile failed: %s\n", get_last_error_str().c_str()); offset += data_written; } while(offset < (ssize_t)data.length()); } std::string read() YS_OVERRIDE { std::string data; ssize_t offset = 0; while (data.length() == 0 || data[data.length() - 1] != '\n') { data.resize(data.length() + 1024); DWORD data_read; if (!ReadFile(hrecv, &data[offset], data.length() - offset, &data_read, /*lpOverlapped=*/NULL)) log_cmd_error("ReadFile failed: %s\n", get_last_error_str().c_str()); offset += data_read; data.resize(offset); size_t term_pos = data.find('\n', offset);