diff options
author | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
commit | 7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch) | |
tree | 18c05b8729df381af71b707748ce1d605e0df764 /kernel/rtlil.cc |
initial import
Diffstat (limited to 'kernel/rtlil.cc')
-rw-r--r-- | kernel/rtlil.cc | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc new file mode 100644 index 00000000..c97e2e45 --- /dev/null +++ b/kernel/rtlil.cc @@ -0,0 +1,1081 @@ +/* + * 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. + * + */ + +#include "kernel/rtlil.h" +#include <assert.h> +#include <algorithm> + +int RTLIL::autoidx = 1; + +RTLIL::Const::Const(std::string str) : str(str) +{ + for (size_t i = 0; i < str.size(); i++) { + unsigned char ch = str[i]; + for (int j = 0; j < 8; j++) { + bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0); + ch = ch >> 1; + } + } +} + +RTLIL::Const::Const(int val, int width) +{ + for (int i = 0; i < width; i++) { + bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0); + val = val >> 1; + } +} + +RTLIL::Const::Const(RTLIL::State bit, int width) +{ + for (int i = 0; i < width; i++) + bits.push_back(bit); +} + +bool RTLIL::Const::operator <(const RTLIL::Const &other) const +{ + if (bits.size() != other.bits.size()) + return bits.size() < other.bits.size(); + for (size_t i = 0; i < bits.size(); i++) + if (bits[i] != other.bits[i]) + return bits[i] < other.bits[i]; + return false; +} + +bool RTLIL::Const::operator ==(const RTLIL::Const &other) const +{ + return bits == other.bits; +} + +bool RTLIL::Const::operator !=(const RTLIL::Const &other) const +{ + return bits != other.bits; +} + +bool RTLIL::Const::as_bool() const +{ + for (size_t i = 0; i < bits.size(); i++) + if (bits[i] == RTLIL::S1) + return true; + return false; +} + +int RTLIL::Const::as_int() const +{ + int ret = 0; + for (size_t i = 0; i < bits.size() && i < 32; i++) + if (bits[i] == RTLIL::S1) + ret |= 1 << i; + return ret; +} + +std::string RTLIL::Const::as_string() const +{ + std::string ret; + for (size_t i = bits.size(); i > 0; i--) + switch (bits[i-1]) { + case S0: ret += "0"; break; + case S1: ret += "1"; break; + case Sx: ret += "x"; break; + case Sz: ret += "z"; break; + case Sa: ret += "-"; break; + case Sm: ret += "m"; break; + } + return ret; +} + +bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) +{ + if (full_selection) + return true; + if (selected_modules.count(mod_name) > 0) + return true; + if (selected_members.count(mod_name) > 0) + return true; + return false; +} + +bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) +{ + if (full_selection) + return true; + if (selected_modules.count(mod_name) > 0) + return true; + return false; +} + +bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) +{ + if (full_selection) + return true; + if (selected_modules.count(mod_name) > 0) + return true; + if (selected_members.count(mod_name) > 0) + if (selected_members[mod_name].count(memb_name) > 0) + return true; + return false; +} + +void RTLIL::Selection::optimize(RTLIL::Design *design) +{ + if (full_selection) { + selected_modules.clear(); + selected_members.clear(); + return; + } + + std::vector<RTLIL::IdString> del_list, add_list; + + del_list.clear(); + for (auto mod_name : selected_modules) { + if (design->modules.count(mod_name) == 0) + del_list.push_back(mod_name); + selected_members.erase(mod_name); + } + for (auto mod_name : del_list) + selected_modules.erase(mod_name); + + del_list.clear(); + for (auto &it : selected_members) + if (design->modules.count(it.first) == 0) + del_list.push_back(it.first); + for (auto mod_name : del_list) + selected_members.erase(mod_name); + + for (auto &it : selected_members) { + del_list.clear(); + for (auto memb_name : it.second) + if (design->modules[it.first]->count_id(memb_name) == 0) + del_list.push_back(memb_name); + for (auto memb_name : del_list) + it.second.erase(memb_name); + } + + del_list.clear(); + add_list.clear(); + for (auto &it : selected_members) + if (it.second.size() == 0) + del_list.push_back(it.first); + else if (it.second.size() == design->modules[it.first]->wires.size() + design->modules[it.first]->memories.size() + + design->modules[it.first]->cells.size() + design->modules[it.first]->processes.size()) + add_list.push_back(it.first); + for (auto mod_name : del_list) + selected_members.erase(mod_name); + for (auto mod_name : add_list) { + selected_members.erase(mod_name); + selected_modules.insert(mod_name); + } + + if (selected_modules.size() == design->modules.size()) { + full_selection = true; + selected_modules.clear(); + selected_members.clear(); + } +} + +RTLIL::Design::~Design() +{ + for (auto it = modules.begin(); it != modules.end(); it++) + delete it->second; +} + +void RTLIL::Design::check() +{ +#ifndef NDEBUG + for (auto &it : modules) { + assert(it.first == it.second->name); + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + it.second->check(); + } +#endif +} + +void RTLIL::Design::optimize() +{ + for (auto &it : modules) + it.second->optimize(); + for (auto &it : selection_stack) + it.optimize(this); + for (auto &it : selection_vars) + it.second.optimize(this); +} + +bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) +{ + if (!selected_active_module.empty() && mod_name != selected_active_module) + return false; + if (selection_stack.size() == 0) + return true; + return selection_stack.back().selected_module(mod_name); +} + +bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) +{ + if (!selected_active_module.empty() && mod_name != selected_active_module) + return false; + if (selection_stack.size() == 0) + return true; + return selection_stack.back().selected_whole_module(mod_name); +} + +bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) +{ + if (!selected_active_module.empty() && mod_name != selected_active_module) + return false; + if (selection_stack.size() == 0) + return true; + return selection_stack.back().selected_member(mod_name, memb_name); +} + +RTLIL::Module::~Module() +{ + for (auto it = wires.begin(); it != wires.end(); it++) + delete it->second; + for (auto it = memories.begin(); it != memories.end(); it++) + delete it->second; + for (auto it = cells.begin(); it != cells.end(); it++) + delete it->second; + for (auto it = processes.begin(); it != processes.end(); it++) + delete it->second; +} + +RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>) +{ + assert(!"Called derive() from module base class."); + abort(); +} + +void RTLIL::Module::update_auto_wires(std::map<RTLIL::IdString, int>) +{ + assert(!"Called update_auto_wires() from module base class."); +} + +size_t RTLIL::Module::count_id(RTLIL::IdString id) +{ + return wires.count(id) + memories.count(id) + cells.count(id) + processes.count(id); +} + +void RTLIL::Module::check() +{ +#ifndef NDEBUG + for (auto &it : wires) { + assert(it.first == it.second->name); + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + assert(it.second->width >= 0); + assert(it.second->port_id >= 0); + for (auto &it2 : it.second->attributes) { + assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + } + } + + for (auto &it : memories) { + assert(it.first == it.second->name); + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + assert(it.second->width >= 0); + assert(it.second->size >= 0); + for (auto &it2 : it.second->attributes) { + assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + } + } + + for (auto &it : cells) { + assert(it.first == it.second->name); + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + assert(it.second->type.size() > 0 && (it.second->type[0] == '\\' || it.second->type[0] == '$')); + for (auto &it2 : it.second->connections) { + assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + it2.second.check(); + } + for (auto &it2 : it.second->attributes) { + assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + } + for (auto &it2 : it.second->parameters) { + assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + } + } + + for (auto &it : processes) { + assert(it.first == it.second->name); + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + // FIXME: More checks here.. + } + + for (auto &it : connections) { + assert(it.first.width == it.second.width); + it.first.check(); + it.second.check(); + } + + for (auto &it : attributes) { + assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + } +#endif +} + +void RTLIL::Module::optimize() +{ + for (auto &it : cells) + it.second->optimize(); + for (auto &it : processes) + it.second->optimize(); + for (auto &it : connections) { + it.first.optimize(); + it.second.optimize(); + } +} + +void RTLIL::Module::add(RTLIL::Wire *wire) { + assert(!wire->name.empty()); + assert(count_id(wire->name) == 0); + wires[wire->name] = wire; +} + +void RTLIL::Module::add(RTLIL::Cell *cell) { + assert(!cell->name.empty()); + assert(count_id(cell->name) == 0); + cells[cell->name] = cell; +} + +RTLIL::Wire::Wire() +{ + width = 1; + start_offset = 0; + port_id = 0; + port_input = false; + port_output = false; + auto_width = false; +} + +RTLIL::Memory::Memory() +{ + width = 1; + size = 0; +} + +void RTLIL::Cell::optimize() +{ + for (auto &it : connections) + it.second.optimize(); +} + +RTLIL::SigChunk::SigChunk() +{ + wire = NULL; + width = 0; + offset = 0; +} + +RTLIL::SigChunk::SigChunk(const RTLIL::Const &data) +{ + wire = NULL; + this->data = data; + width = data.bits.size(); + offset = 0; +} + +RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int width, int offset) +{ + this->wire = wire; + this->width = width >= 0 ? width : wire->width; + this->offset = offset; +} + +RTLIL::SigChunk::SigChunk(const std::string &str) +{ + wire = NULL; + data = RTLIL::Const(str); + width = data.bits.size(); + offset = 0; +} + +RTLIL::SigChunk::SigChunk(int val, int width) +{ + wire = NULL; + data = RTLIL::Const(val, width); + this->width = data.bits.size(); + offset = 0; +} + +RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width) +{ + wire = NULL; + data = RTLIL::Const(bit, width); + this->width = data.bits.size(); + offset = 0; +} + +RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const +{ + RTLIL::SigChunk ret; + if (wire) { + ret.wire = wire; + ret.offset = this->offset + offset; + ret.width = length; + } else { + for (int i = 0; i < length; i++) + ret.data.bits.push_back(data.bits[offset+i]); + ret.width = length; + } + return ret; +} + +bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const +{ + if (wire && other.wire) + if (wire->name != other.wire->name) + return wire->name < other.wire->name; + if (wire != other.wire) + return wire < other.wire; + + if (offset != other.offset) + return offset < other.offset; + + if (width != other.width) + return width < other.width; + + if (data.bits != other.data.bits) + return data.bits < other.data.bits; + + return false; +} + +bool RTLIL::SigChunk::operator ==(const RTLIL::SigChunk &other) const +{ + if (wire != other.wire || width != other.width || offset != other.offset) + return false; + if (data.bits != other.data.bits) + return false; + return true; +} + +bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const +{ + if (*this == other) + return false; + return true; +} + +RTLIL::SigSpec::SigSpec() +{ + width = 0; +} + +RTLIL::SigSpec::SigSpec(const RTLIL::Const &data) +{ + chunks.push_back(RTLIL::SigChunk(data)); + width = chunks.back().width; + check(); +} + +RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) +{ + chunks.push_back(chunk); + width = chunks.back().width; + check(); +} + +RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int width, int offset) +{ + chunks.push_back(RTLIL::SigChunk(wire, width, offset)); + this->width = chunks.back().width; + check(); +} + +RTLIL::SigSpec::SigSpec(const std::string &str) +{ + chunks.push_back(RTLIL::SigChunk(str)); + width = chunks.back().width; + check(); +} + +RTLIL::SigSpec::SigSpec(int val, int width) +{ + chunks.push_back(RTLIL::SigChunk(val, width)); + this->width = chunks.back().width; + check(); +} + +RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) +{ + chunks.push_back(RTLIL::SigChunk(bit, width)); + this->width = chunks.back().width; + check(); +} + +void RTLIL::SigSpec::expand() +{ + std::vector<RTLIL::SigChunk> new_chunks; + for (size_t i = 0; i < chunks.size(); i++) { + assert(chunks[i].data.str.empty()); + for (int j = 0; j < chunks[i].width; j++) + new_chunks.push_back(chunks[i].extract(j, 1)); + } + chunks.swap(new_chunks); + check(); +} + +void RTLIL::SigSpec::optimize() +{ + for (size_t i = 0; i < chunks.size(); i++) { + if (chunks[i].wire && chunks[i].wire->auto_width) + continue; + if (chunks[i].width == 0) + chunks.erase(chunks.begin()+i--); + } + for (size_t i = 1; i < chunks.size(); i++) { + RTLIL::SigChunk &ch1 = chunks[i-1]; + RTLIL::SigChunk &ch2 = chunks[i]; + if (ch1.wire && ch1.wire->auto_width) + continue; + if (ch2.wire && ch2.wire->auto_width) + continue; + if (ch1.wire == ch2.wire) { + if (ch1.wire != NULL && ch1.offset+ch1.width == ch2.offset) { + ch1.width += ch2.width; + goto merged_with_next_chunk; + } + if (ch1.wire == NULL && ch1.data.str.empty() == ch2.data.str.empty()) { + ch1.data.str = ch2.data.str + ch1.data.str; + ch1.data.bits.insert(ch1.data.bits.end(), ch2.data.bits.begin(), ch2.data.bits.end()); + ch1.width += ch2.width; + goto merged_with_next_chunk; + } + } + if (0) { + merged_with_next_chunk: + chunks.erase(chunks.begin()+i); + i--; + } + } + check(); +} + +static bool compare_sigchunks(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b) +{ + if (a.wire != b.wire) { + if (a.wire == NULL || b.wire == NULL) + return a.wire < b.wire; + else if (a.wire->name != b.wire->name) + return a.wire->name < b.wire->name; + else + return a.wire < b.wire; + } + if (a.offset != b.offset) + return a.offset < b.offset; + if (a.width != b.width) + return a.width < b.width; + return a.data.bits < b.data.bits; +} + +void RTLIL::SigSpec::sort_and_unify() +{ + expand(); + std::sort(chunks.begin(), chunks.end(), compare_sigchunks); + for (size_t i = 1; i < chunks.size(); i++) { + RTLIL::SigChunk &ch1 = chunks[i-1]; + RTLIL::SigChunk &ch2 = chunks[i]; + if (!compare_sigchunks(ch1, ch2) && !compare_sigchunks(ch2, ch1)) { + chunks.erase(chunks.begin()+i); + width -= chunks[i].width; + i--; + } + } + optimize(); +} + +void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) +{ + replace(pattern, with, this); +} + +void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const +{ + int pos = 0, restart_pos = 0; + assert(other == NULL || width == other->width); + for (size_t i = 0; i < chunks.size(); i++) { +restart: + const RTLIL::SigChunk &ch1 = chunks[i]; + if (chunks[i].wire != NULL && pos >= restart_pos) + for (size_t j = 0, poff = 0; j < pattern.chunks.size(); j++) { + const RTLIL::SigChunk &ch2 = pattern.chunks[j]; + assert(ch2.wire != NULL); + if (ch1.wire == ch2.wire) { + int lower = std::max(ch1.offset, ch2.offset); + int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width); + if (lower < upper) { + restart_pos = pos+upper-ch1.offset; + other->replace(pos+lower-ch1.offset, with.extract(poff+lower-ch2.offset, upper-lower)); + goto restart; + } + } + poff += ch2.width; + } + pos += chunks[i].width; + } + check(); +} + +void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern) +{ + remove2(pattern, NULL); +} + +void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const +{ + RTLIL::SigSpec tmp = *this; + tmp.remove2(pattern, other); +} + +void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) +{ + int pos = 0; + assert(other == NULL || width == other->width); + for (size_t i = 0; i < chunks.size(); i++) { +restart: + const RTLIL::SigChunk &ch1 = chunks[i]; + if (chunks[i].wire != NULL) + for (size_t j = 0; j < pattern.chunks.size(); j++) { + const RTLIL::SigChunk &ch2 = pattern.chunks[j]; + assert(ch2.wire != NULL); + if (ch1.wire == ch2.wire) { + int lower = std::max(ch1.offset, ch2.offset); + int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width); + if (lower < upper) { + if (other) + other->remove(pos+lower-ch1.offset, upper-lower); + remove(pos+lower-ch1.offset, upper-lower); + if (i == chunks.size()) + break; + goto restart; + } + } + } + pos += chunks[i].width; + } + check(); +} + +RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other) const +{ + int pos = 0; + RTLIL::SigSpec ret; + pattern.sort_and_unify(); + assert(other == NULL || width == other->width); + for (size_t i = 0; i < chunks.size(); i++) { + const RTLIL::SigChunk &ch1 = chunks[i]; + if (chunks[i].wire != NULL) + for (size_t j = 0; j < pattern.chunks.size(); j++) { + RTLIL::SigChunk &ch2 = pattern.chunks[j]; + assert(ch2.wire != NULL); + if (ch1.wire == ch2.wire) { + int lower = std::max(ch1.offset, ch2.offset); + int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width); + if (lower < upper) { + if (other) + ret.append(other->extract(pos+lower-ch1.offset, upper-lower)); + else + ret.append(extract(pos+lower-ch1.offset, upper-lower)); + } + } + } + pos += chunks[i].width; + } + ret.check(); + return ret; +} + +void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) +{ + int pos = 0; + assert(offset >= 0); + assert(with.width >= 0); + assert(offset+with.width <= width); + remove(offset, with.width); + for (size_t i = 0; i < chunks.size(); i++) { + if (pos == offset) { + chunks.insert(chunks.begin()+i, with.chunks.begin(), with.chunks.end()); + width += with.width; + check(); + return; + } + pos += chunks[i].width; + } + assert(pos == offset); + chunks.insert(chunks.end(), with.chunks.begin(), with.chunks.end()); + width += with.width; + check(); +} + +void RTLIL::SigSpec::remove_const() +{ + for (size_t i = 0; i < chunks.size(); i++) { + if (chunks[i].wire != NULL) + continue; + width -= chunks[i].width; + chunks.erase(chunks.begin() + (i--)); + } + check(); +} + +void RTLIL::SigSpec::remove(int offset, int length) +{ + int pos = 0; + assert(offset >= 0); + assert(length >= 0); + assert(offset+length <= width); + for (size_t i = 0; i < chunks.size(); i++) { + int orig_width = chunks[i].width; + if (pos+chunks[i].width > offset && pos < offset+length) { + int off = offset - pos; + int len = length; + if (off < 0) { + len += off; + off = 0; + } + if (len > chunks[i].width-off) + len = chunks[i].width-off; + RTLIL::SigChunk lsb_chunk = chunks[i].extract(0, off); + RTLIL::SigChunk msb_chunk = chunks[i].extract(off+len, chunks[i].width-off-len); + if (lsb_chunk.width == 0 && msb_chunk.width == 0) { + chunks.erase(chunks.begin()+i); + i--; + } else if (lsb_chunk.width == 0 && msb_chunk.width != 0) { + chunks[i] = msb_chunk; + } else if (lsb_chunk.width != 0 && msb_chunk.width == 0) { + chunks[i] = lsb_chunk; + } else if (lsb_chunk.width != 0 && msb_chunk.width != 0) { + chunks[i] = lsb_chunk; + chunks.insert(chunks.begin()+i+1, msb_chunk); + i++; + } else + assert(0); + width -= len; + } + pos += orig_width; + } + check(); +} + +RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const +{ + int pos = 0; + RTLIL::SigSpec ret; + assert(offset >= 0); + assert(length >= 0); + assert(offset+length <= width); + for (size_t i = 0; i < chunks.size(); i++) { + if (pos+chunks[i].width > offset && pos < offset+length) { + int off = offset - pos; + int len = length; + if (off < 0) { + len += off; + off = 0; + } + if (len > chunks[i].width-off) + len = chunks[i].width-off; + ret.chunks.push_back(chunks[i].extract(off, len)); + ret.width += len; + offset += len; + length -= len; + } + pos += chunks[i].width; + } + assert(length == 0); + ret.check(); + return ret; +} + +void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) +{ + for (size_t i = 0; i < signal.chunks.size(); i++) { + chunks.push_back(signal.chunks[i]); + width += signal.chunks[i].width; + } + check(); +} + +bool RTLIL::SigSpec::combine(RTLIL::SigSpec signal, RTLIL::State freeState, bool override) +{ + bool no_collisions = true; + + assert(width == signal.width); + expand(); + signal.expand(); + + for (size_t i = 0; i < chunks.size(); i++) { + bool self_free = chunks[i].wire == NULL && chunks[i].data.bits[0] == freeState; + bool other_free = signal.chunks[i].wire == NULL && signal.chunks[i].data.bits[0] == freeState; + if (!self_free && !other_free) { + if (override) + chunks[i] = signal.chunks[i]; + else + chunks[i] = RTLIL::SigChunk(RTLIL::State::Sx, 1); + no_collisions = false; + } + if (self_free && !other_free) + chunks[i] = signal.chunks[i]; + } + + optimize(); + return no_collisions; +} + +void RTLIL::SigSpec::extend(int width, bool is_signed) +{ + if (this->width > width) + remove(width, this->width - width); + + if (this->width < width) { + RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); + if (!is_signed && padding != RTLIL::SigSpec(RTLIL::State::Sx) && padding != RTLIL::SigSpec(RTLIL::State::Sz) && + padding != RTLIL::SigSpec(RTLIL::State::Sa) && padding != RTLIL::SigSpec(RTLIL::State::Sm)) + padding = RTLIL::SigSpec(RTLIL::State::S0); + while (this->width < width) + append(padding); + } + + optimize(); +} + +void RTLIL::SigSpec::check() const +{ + int w = 0; + for (size_t i = 0; i < chunks.size(); i++) { + const RTLIL::SigChunk chunk = chunks[i]; + if (chunk.wire == NULL) { + assert(chunk.offset == 0); + assert(chunk.data.bits.size() == (size_t)chunk.width); + assert(chunk.data.str.size() == 0 || chunk.data.str.size()*8 == chunk.data.bits.size()); + } else { + assert(chunk.offset >= 0); + assert(chunk.width >= 0); + assert(chunk.offset + chunk.width <= chunk.wire->width); + assert(chunk.data.bits.size() == 0); + assert(chunk.data.str.size() == 0); + } + w += chunk.width; + } + assert(w == width); +} + +bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const +{ + if (width != other.width) + return width < other.width; + + RTLIL::SigSpec a = *this, b = other; + a.optimize(); + b.optimize(); + + if (a.chunks.size() != b.chunks.size()) + return a.chunks.size() < b.chunks.size(); + + for (size_t i = 0; i < a.chunks.size(); i++) + if (a.chunks[i] != b.chunks[i]) + return a.chunks[i] < b.chunks[i]; + + return false; +} + +bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const +{ + if (width != other.width) + return false; + + RTLIL::SigSpec a = *this, b = other; + a.optimize(); + b.optimize(); + + if (a.chunks.size() != b.chunks.size()) + return false; + + for (size_t i = 0; i < a.chunks.size(); i++) + if (a.chunks[i] != b.chunks[i]) + return false; + + return true; +} + +bool RTLIL::SigSpec::operator !=(const RTLIL::SigSpec &other) const +{ + if (*this == other) + return false; + return true; +} + +bool RTLIL::SigSpec::is_fully_const() const +{ + for (auto it = chunks.begin(); it != chunks.end(); it++) + if (it->width > 0 && it->wire != NULL) + return false; + return true; +} + +bool RTLIL::SigSpec::is_fully_def() const +{ + for (auto it = chunks.begin(); it != chunks.end(); it++) { + if (it->width > 0 && it->wire != NULL) + return false; + for (size_t i = 0; i < it->data.bits.size(); i++) + if (it->data.bits[i] != RTLIL::State::S0 && it->data.bits[i] != RTLIL::State::S1) + return false; + } + return true; +} + +bool RTLIL::SigSpec::is_fully_undef() const +{ + for (auto it = chunks.begin(); it != chunks.end(); it++) { + if (it->width > 0 && it->wire != NULL) + return false; + for (size_t i = 0; i < it->data.bits.size(); i++) + if (it->data.bits[i] != RTLIL::State::Sx && it->data.bits[i] != RTLIL::State::Sz) + return false; + } + return true; +} + +bool RTLIL::SigSpec::has_marked_bits() const +{ + for (auto it = chunks.begin(); it != chunks.end(); it++) + if (it->width > 0 && it->wire == NULL) { + for (size_t i = 0; i < it->data.bits.size(); i++) + if (it->data.bits[i] == RTLIL::State::Sm) + return true; + } + return false; +} + +bool RTLIL::SigSpec::as_bool() const +{ + assert(is_fully_const()); + SigSpec sig = *this; + sig.optimize(); + if (sig.width) + return sig.chunks[0].data.as_bool(); + return false; +} + +int RTLIL::SigSpec::as_int() const +{ + assert(is_fully_const()); + SigSpec sig = *this; + sig.optimize(); + if (sig.width) + return sig.chunks[0].data.as_int(); + return 0; +} + +std::string RTLIL::SigSpec::as_string() const +{ + std::string str; + for (size_t i = chunks.size(); i > 0; i--) { + const RTLIL::SigChunk &chunk = chunks[i-1]; + if (chunk.wire != NULL) + for (int j = 0; j < chunk.width; j++) + str += "?"; + else + str += chunk.data.as_string(); + } + return str; +} + +RTLIL::Const RTLIL::SigSpec::as_const() const +{ + assert(is_fully_const()); + SigSpec sig = *this; + sig.optimize(); + if (sig.width) + return sig.chunks[0].data; + return RTLIL::Const(); +} + +bool RTLIL::SigSpec::match(std::string pattern) const +{ + std::string str = as_string(); + assert(pattern.size() == str.size()); + + for (size_t i = 0; i < pattern.size(); i++) { + if (pattern[i] == ' ') + continue; + if (pattern[i] == '*') { + if (str[i] != 'z' && str[i] != 'x') + return false; + continue; + } + if (pattern[i] != str[i]) + return false; + } + + return true; +} + +RTLIL::CaseRule::~CaseRule() +{ + for (auto it = switches.begin(); it != switches.end(); it++) + delete *it; +} + +void RTLIL::CaseRule::optimize() +{ + for (auto it : switches) + it->optimize(); + for (auto &it : compare) + it.optimize(); + for (auto &it : actions) { + it.first.optimize(); + it.second.optimize(); + } +} + +RTLIL::SwitchRule::~SwitchRule() +{ + for (auto it = cases.begin(); it != cases.end(); it++) + delete *it; +} + +void RTLIL::SwitchRule::optimize() +{ + signal.optimize(); + for (auto it : cases) + it->optimize(); +} + +void RTLIL::SyncRule::optimize() +{ + signal.optimize(); + for (auto &it : actions) { + it.first.optimize(); + it.second.optimize(); + } +} + +RTLIL::Process::~Process() +{ + for (auto it = syncs.begin(); it != syncs.end(); it++) + delete *it; +} + +void RTLIL::Process::optimize() +{ + root_case.optimize(); + for (auto it : syncs) + it->optimize(); +} + |