/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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. * */ #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/log.h" #include #include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc) { bool found_init = false; for (auto &sync : proc->syncs) if (sync->type == RTLIL::SyncType::STi) { found_init = true; log("Found init rule in `%s.%s'.\n", mod->name.c_str(), proc->name.c_str()); for (auto &action : sync->actions) { RTLIL::SigSpec lhs = action.first; RTLIL::SigSpec rhs = sigmap(action.second); if (!rhs.is_fully_const()) log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs)); int offset = 0; for (auto &lhs_c : lhs.chunks()) { if (lhs_c.wire != nullptr) { SigSpec valuesig = rhs.extract(offset, lhs_c.width); if (!valuesig.is_fully_const()) log_cmd_error("Non-const initialization value: %s = %s\n", log_signal(lhs_c), log_signal(valuesig)); Const value = valuesig.as_const(); Const &wireinit = lhs_c.wire->attributes[ID::init]; while (GetSize(wireinit.bits) < lhs_c.wire->width) wireinit.bits.push_back(State::Sx); for (int i = 0; i < lhs_c.width; i++) { auto &initbit = wireinit.bits[i + lhs_c.offset]; if (initbit != State::Sx && initbit != value[i]) log_cmd_error("Conflicting initialization values for %s.\n", log_signal(lhs_c)); initbit = value[i]; } log(" Set init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(wireinit)); } offset += lhs_c.width; } } sync->actions.clear(); } } struct ProcInitPass : public Pass { ProcInitPass() : Pass("proc_init", "convert initial block to init attributes") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" proc_init [selection]\n"); log("\n"); log("This pass extracts the 'init' actions from processes (generated from Verilog\n"); log("'initial' blocks) and sets the initial value to the 'init' attribute on the\n"); log("respective wire.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { log_header(design, "Executing PROC_INIT pass (extract init attributes).\n"); extra_args(args, 1, design); for (auto mod : design->modules()) if (design->selected(mod)) { SigMap sigmap(mod); for (auto &proc_it : mod->processes) if (design->selected(mod, proc_it.second)) proc_init(mod, sigmap, proc_it.second); } } } ProcInitPass; PRIVATE_NAMESPACE_END