rtlil: Make Process handling more uniform with Cell and Wire.
[yosys.git] / kernel / rtlil.cc
index c56f0dcabe0338b91cc308e1958756ef2053afe9..21ee15ac548a6cd23ba16ee31d8f204ec0ad2573 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  yosys -- Yosys Open SYnthesis Suite
  *
- *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
@@ -22,7 +22,7 @@
 #include "kernel/celltypes.h"
 #include "frontends/verilog/verilog_frontend.h"
 #include "frontends/verilog/preproc.h"
-#include "backends/ilang/ilang_backend.h"
+#include "backends/rtlil/rtlil_backend.h"
 
 #include <string.h>
 #include <algorithm>
@@ -363,6 +363,26 @@ bool RTLIL::Const::is_fully_undef() const
        return true;
 }
 
+bool RTLIL::Const::is_onehot(int *pos) const
+{
+       cover("kernel.rtlil.const.is_onehot");
+
+       bool found = false;
+       for (int i = 0; i < GetSize(*this); i++) {
+               auto &bit = bits[i];
+               if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
+                       return false;
+               if (bit == RTLIL::State::S1) {
+                       if (found)
+                               return false;
+                       if (pos)
+                               *pos = i;
+                       found = true;
+               }
+       }
+       return found;
+}
+
 bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
 {
        return attributes.count(id);
@@ -551,8 +571,8 @@ RTLIL::Design::Design()
 
 RTLIL::Design::~Design()
 {
-       for (auto it = modules_.begin(); it != modules_.end(); ++it)
-               delete it->second;
+       for (auto &pr : modules_)
+               delete pr.second;
        for (auto n : verilog_packages)
                delete n;
        for (auto n : verilog_globals)
@@ -580,6 +600,11 @@ RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
        return modules_.count(name) ? modules_.at(name) : NULL;
 }
 
+const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
+{
+       return modules_.count(name) ? modules_.at(name) : NULL;
+}
+
 RTLIL::Module *RTLIL::Design::top_module()
 {
        RTLIL::Module *module = nullptr;
@@ -613,7 +638,8 @@ void RTLIL::Design::add(RTLIL::Module *module)
 
 RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
 {
-       log_assert(modules_.count(name) == 0);
+       if (modules_.count(name) != 0)
+               log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name.c_str());
        log_assert(refcount_modules_ == 0);
 
        RTLIL::Module *module = new RTLIL::Module;
@@ -807,12 +833,12 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
        return result;
 }
 
-std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
+std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn(bool include_wb) const
 {
        std::vector<RTLIL::Module*> result;
        result.reserve(modules_.size());
        for (auto &it : modules_)
-               if (it.second->get_blackbox_attribute())
+               if (it.second->get_blackbox_attribute(include_wb))
                        continue;
                else if (selected_whole_module(it.first))
                        result.push_back(it.second);
@@ -838,14 +864,14 @@ RTLIL::Module::Module()
 
 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;
+       for (auto &pr : wires_)
+               delete pr.second;
+       for (auto &pr : memories)
+               delete pr.second;
+       for (auto &pr : cells_)
+               delete pr.second;
+       for (auto &pr : processes)
+               delete pr.second;
 #ifdef WITH_PYTHON
        RTLIL::Module::get_all_modules()->erase(hashidx_);
 #endif
@@ -923,7 +949,7 @@ namespace {
                void error(int linenr)
                {
                        std::stringstream buf;
-                       ILANG_BACKEND::dump_cell(buf, "  ", cell);
+                       RTLIL_BACKEND::dump_cell(buf, "  ", cell);
 
                        log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s",
                                        module ? module->name.c_str() : "", module ? "." : "",
@@ -1813,6 +1839,14 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
        cell->module = this;
 }
 
+void RTLIL::Module::add(RTLIL::Process *process)
+{
+       log_assert(!process->name.empty());
+       log_assert(count_id(process->name) == 0);
+       processes[process->name] = process;
+       process->module = this;
+}
+
 void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
 {
        log_assert(refcount_wires_ == 0);
@@ -1826,7 +1860,7 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
                        sig.pack();
                        for (auto &c : sig.chunks_)
                                if (c.wire != NULL && wires_p->count(c.wire)) {
-                                       c.wire = module->addWire(NEW_ID, c.width);
+                                       c.wire = module->addWire(stringf("$delete_wire$%d", autoidx++), c.width);
                                        c.offset = 0;
                                }
                }
@@ -1869,6 +1903,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell)
        delete cell;
 }
 
+void RTLIL::Module::remove(RTLIL::Process *process)
+{
+       log_assert(processes.count(process->name) != 0);
+       processes.erase(process->name);
+       delete process;
+}
+
 void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
 {
        log_assert(wires_[wire->name] == wire);
@@ -2094,11 +2135,19 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor
        return mem;
 }
 
+RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
+{
+       RTLIL::Process *proc = new RTLIL::Process;
+       proc->name = name;
+       add(proc);
+       return proc;
+}
+
 RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other)
 {
        RTLIL::Process *proc = other->clone();
        proc->name = name;
-       processes[name] = proc;
+       add(proc);
        return proc;
 }
 
@@ -2894,6 +2943,13 @@ RTLIL::Memory::Memory()
 #endif
 }
 
+RTLIL::Process::Process() : module(nullptr)
+{
+       static unsigned int hashidx_count = 123456789;
+       hashidx_count = mkhash_xorshift(hashidx_count);
+       hashidx_ = hashidx_count;
+}
+
 RTLIL::Cell::Cell() : module(nullptr)
 {
        static unsigned int hashidx_count = 123456789;
@@ -3119,6 +3175,16 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
        check();
 }
 
+bool RTLIL::Cell::has_memid() const
+{
+       return type.in(ID($memwr), ID($memrd), ID($meminit));
+}
+
+bool RTLIL::Cell::is_mem_cell() const
+{
+       return type == ID($mem) || has_memid();
+}
+
 RTLIL::SigChunk::SigChunk()
 {
        wire = NULL;
@@ -3275,8 +3341,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
 {
        cover("kernel.rtlil.sigspec.init.const");
 
-       chunks_.emplace_back(value);
-       width_ = chunks_.back().width;
+       if (GetSize(value) != 0) {
+               chunks_.emplace_back(value);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3285,8 +3355,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
 {
        cover("kernel.rtlil.sigspec.init.chunk");
 
-       chunks_.emplace_back(chunk);
-       width_ = chunks_.back().width;
+       if (chunk.width != 0) {
+               chunks_.emplace_back(chunk);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3295,8 +3369,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
 {
        cover("kernel.rtlil.sigspec.init.wire");
 
-       chunks_.emplace_back(wire);
-       width_ = chunks_.back().width;
+       if (wire->width != 0) {
+               chunks_.emplace_back(wire);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3305,8 +3383,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
 {
        cover("kernel.rtlil.sigspec.init.wire_part");
 
-       chunks_.emplace_back(wire, offset, width);
-       width_ = chunks_.back().width;
+       if (width != 0) {
+               chunks_.emplace_back(wire, offset, width);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3315,8 +3397,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
 {
        cover("kernel.rtlil.sigspec.init.str");
 
-       chunks_.emplace_back(str);
-       width_ = chunks_.back().width;
+       if (str.size() != 0) {
+               chunks_.emplace_back(str);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3325,7 +3411,8 @@ RTLIL::SigSpec::SigSpec(int val, int width)
 {
        cover("kernel.rtlil.sigspec.init.int");
 
-       chunks_.emplace_back(val, width);
+       if (width != 0)
+               chunks_.emplace_back(val, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -3335,7 +3422,8 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.state");
 
-       chunks_.emplace_back(bit, width);
+       if (width != 0)
+               chunks_.emplace_back(bit, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -3345,11 +3433,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.bit");
 
-       if (bit.wire == NULL)
-               chunks_.emplace_back(bit.data, width);
-       else
-               for (int i = 0; i < width; i++)
-                       chunks_.push_back(bit);
+       if (width != 0) {
+               if (bit.wire == NULL)
+                       chunks_.emplace_back(bit.data, width);
+               else
+                       for (int i = 0; i < width; i++)
+                               chunks_.push_back(bit);
+       }
        width_ = width;
        hash_ = 0;
        check();
@@ -3794,7 +3884,13 @@ void RTLIL::SigSpec::remove_const()
                width_ = 0;
                for (auto &chunk : chunks_)
                        if (chunk.wire != NULL) {
-                               new_chunks.push_back(chunk);
+                               if (!new_chunks.empty() &&
+                                       new_chunks.back().wire == chunk.wire &&
+                                       new_chunks.back().offset + new_chunks.back().width == chunk.offset) {
+                                       new_chunks.back().width += chunk.width;
+                               } else {
+                                       new_chunks.push_back(chunk);
+                               }
                                width_ += chunk.width;
                        }
 
@@ -3954,6 +4050,7 @@ void RTLIL::SigSpec::check() const
                int w = 0;
                for (size_t i = 0; i < chunks_.size(); i++) {
                        const RTLIL::SigChunk &chunk = chunks_[i];
+                       log_assert(chunk.width != 0);
                        if (chunk.wire == NULL) {
                                if (i > 0)
                                        log_assert(chunks_[i-1].wire != NULL);
@@ -4164,6 +4261,19 @@ bool RTLIL::SigSpec::has_marked_bits() const
        return false;
 }
 
+bool RTLIL::SigSpec::is_onehot(int *pos) const
+{
+       cover("kernel.rtlil.sigspec.is_onehot");
+
+       pack();
+       if (!is_fully_const())
+               return false;
+       log_assert(GetSize(chunks_) <= 1);
+       if (width_)
+               return RTLIL::Const(chunks_[0].data).is_onehot(pos);
+       return false;
+}
+
 bool RTLIL::SigSpec::as_bool() const
 {
        cover("kernel.rtlil.sigspec.as_bool");
@@ -4537,6 +4647,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
        new_syncrule->type = type;
        new_syncrule->signal = signal;
        new_syncrule->actions = actions;
+       new_syncrule->mem_write_actions = mem_write_actions;
        return new_syncrule;
 }