iverilog/vvp/vvp_island.cc

380 lines
9.6 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2008-2021 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2012-08-29 03:41:23 +02:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vvp_island.h"
# include "compile.h"
# include "symbols.h"
# include "schedule.h"
# include "config.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
# include <iostream>
# include <list>
# include <cassert>
# include <cstdlib>
# include <cstring>
# include "ivl_alloc.h"
using namespace std;
static bool at_EOS = false;
void island_send_value(vvp_net_t*net, const vvp_vector8_t&val)
{
vvp_island_port*fun = dynamic_cast<vvp_island_port*>(net->fun);
if (fun->outvalue .eeq(val))
return;
fun->outvalue = val;
net->send_vec8(fun->outvalue);
}
/*
* Implementations...
*/
vvp_island::vvp_island()
{
flagged_ = false;
branches_ = 0;
ports_ = 0;
anodes_ = 0;
bnodes_ = 0;
}
vvp_island::~vvp_island()
{
// We can only delete islands at the end of simulation.
if (!at_EOS) assert(0);
while (branches_) {
2021-01-01 09:19:27 +01:00
vvp_island_branch *next_br = branches_->next_branch;
delete branches_;
2021-01-01 09:19:27 +01:00
branches_ = next_br;
}
}
void vvp_island::flag_island()
{
if (flagged_ == true)
return;
schedule_generic(this, 0, false, false);
flagged_ = true;
}
/*
* This method handles the callback from the scheduler. It does basic
* housecleaning and calls the run_island() method implemented by the
* derived class.
*/
void vvp_island::run_run()
{
flagged_ = false;
run_island();
}
void vvp_island::add_port(const char*key, vvp_net_t*net)
{
if (ports_ == 0)
ports_ = new symbol_map_s<vvp_net_t>;
// each port should have a unique label
assert(ports_->sym_get_value(key) == 0);
ports_->sym_set_value(key, net);
}
void vvp_island::add_branch(vvp_island_branch*branch, const char*pa, const char*pb)
{
vvp_island_branch*cur;
2008-06-02 04:42:44 +02:00
assert(ports_);
branch->a = ports_->sym_get_value(pa);
branch->b = ports_->sym_get_value(pb);
2008-06-04 02:31:15 +02:00
assert(branch->a && branch->b);
vvp_branch_ptr_t ptra (branch, 0);
vvp_branch_ptr_t ptrb (branch, 1);
if (anodes_ == 0)
anodes_ = new symbol_map_s<vvp_island_branch>;
if (bnodes_ == 0)
bnodes_ = new symbol_map_s<vvp_island_branch>;
if ((cur = anodes_->sym_get_value(pa))) {
branch->link[0] = cur->link[0];
cur->link[0] = ptra;
} else if ((cur = bnodes_->sym_get_value(pa))) {
branch->link[0] = cur->link[1];
cur->link[1] = ptra;
} else {
branch->link[0] = ptra;
anodes_->sym_set_value(pa, branch);
}
if ((cur = anodes_->sym_get_value(pb))) {
branch->link[1] = cur->link[0];
cur->link[0] = ptrb;
} else if ((cur = bnodes_->sym_get_value(pb))) {
branch->link[1] = cur->link[1];
cur->link[1] = ptrb;
} else {
branch->link[1] = ptrb;
bnodes_->sym_set_value(pb, branch);
}
branch->next_branch = branches_;
branches_ = branch;
}
vvp_net_t* vvp_island::find_port(const char*key)
{
2008-06-02 04:42:44 +02:00
if (ports_ == 0)
return 0;
else
return ports_->sym_get_value(key);
}
void vvp_island::compile_cleanup()
{
delete ports_;
ports_ = 0;
delete anodes_;
anodes_ = 0;
delete bnodes_;
bnodes_ = 0;
}
vvp_island_port::vvp_island_port(vvp_island*ip)
: island_(ip)
{
}
vvp_island_port::~vvp_island_port()
{
}
void vvp_island_port::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&bit,
vvp_context_t)
{
vvp_vector8_t tmp (bit, 6, 6);
if (invalue .eeq(tmp))
return;
invalue = tmp;
island_->flag_island();
}
2008-06-04 02:31:15 +02:00
void vvp_island_port::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
2008-06-04 02:31:15 +02:00
{
vvp_vector8_t tmp(bit, 6, 6);
recv_vec8_pv(port, tmp, base, wid, vwid);
2008-06-04 02:31:15 +02:00
}
void vvp_island_port::recv_vec8(vvp_net_ptr_t, const vvp_vector8_t&bit)
{
if (invalue .eeq(bit))
return;
invalue = bit;
island_->flag_island();
}
void vvp_island_port::recv_vec8_pv(vvp_net_ptr_t, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
if (invalue.size() == 0) {
assert(bit.size() == wid);
invalue = part_expand(bit, vwid, base);
} else {
assert(invalue.size() == vwid);
for (unsigned idx = 0; idx < wid ; idx += 1) {
if ((base+idx) >= vwid)
break;
invalue.set_bit(base+idx, bit.value(idx));
}
}
island_->flag_island();
}
void vvp_island_port::force_flag(bool run_now)
{
if (run_now)
island_->run_island();
else
island_->flag_island();
}
vvp_island_branch::~vvp_island_branch()
{
}
void island_collect_node(list<vvp_branch_ptr_t>&conn, vvp_branch_ptr_t cur)
{
conn .push_back(cur);
for (vvp_branch_ptr_t idx = next(cur) ; idx != cur ; idx = next(idx))
conn.push_back(idx);
}
/* **** COMPILE/LINK SUPPORT **** */
/*
* We need to keep an island symbol table to make island labels to
* islands, and we need a list of the islands that we can run through
* during cleanup. After linking is done, the compile_island_cleanup() is
* called to erase the symbol table, we still need the list to cleanup the
* island memory at EOS.
*/
static symbol_map_s<vvp_island>* island_table = 0;
static vvp_island** island_list = 0;
static unsigned island_count = 0;
#ifdef CHECK_WITH_VALGRIND
void island_delete()
{
at_EOS = true;
for (unsigned idx = 0; idx < island_count; idx += 1) {
delete island_list[idx];
}
free(island_list);
island_list = 0;
island_count = 0;
}
#endif
void compile_island_base(char*label, vvp_island*use_island)
{
if (island_table == 0)
island_table = new symbol_map_s<vvp_island>;
island_table->sym_set_value(label, use_island);
island_count += 1;
island_list = (vvp_island **)realloc(island_list,
island_count*sizeof(vvp_island **));
island_list[island_count-1] = use_island;
free(label);
}
vvp_island* compile_find_island(const char*island)
{
assert(island_table);
vvp_island*use_island = island_table->sym_get_value(island);
assert(use_island);
return use_island;
}
/*
* This handles the compile of a .port record. A .port is a 2-way port
* between the island and the outside. For example,
*
* <label> .port <island> <src> ;
*
* The <src> is a label in the domain outside the island, and the
* <label> is in the domain inside the island. Since this port is
2010-10-02 20:02:27 +02:00
* bi-directional, the <label> is also available in the domain outside
* the island. The outside should use the <label> to access the nexus
* that this port represents, because the island will resolve internal
* drivers with the external driver and make the output available on
* <label>.
*/
void compile_island_port(char*label, char*island, char*src)
{
assert(island_table);
vvp_island*use_island = island_table->sym_get_value(island);
assert(use_island);
free(island);
vvp_net_t*net = new vvp_net_t;
vvp_island_port*fun = new vvp_island_port(use_island);
net->fun = fun;
// Get the source from outside the island
input_connect(net, 0, src);
// Define the functor outside the island.
define_functor_symbol(label, net);
// Also define it inside the island.
use_island->add_port(label, net);
free(label);
}
void compile_island_export(char*label, char*island)
{
fprintf(stderr, "XXXX %s .export %s;\n", label, island);
free(label);
free(island);
}
/*
* This handles the compile of a .import record. A .import is an input
* port into the island from the outside domain. For example,
*
* <label> .import <island> <src> ;
*
* The <src> is a label in the domain outside the island, and the
* <label> is in the domain inside the island. Branches within the
* island use the <label>.
*/
void compile_island_import(char*label, char*island, char*src)
{
assert(island_table);
vvp_island*use_island = island_table->sym_get_value(island);
assert(use_island);
free(island);
vvp_net_t*net = new vvp_net_t;
vvp_island_port*fun = new vvp_island_port(use_island);
net->fun = fun;
// Get the source from outside the island
input_connect(net, 0, src);
// Define the functor only inside the island.
use_island->add_port(label, net);
free(label);
}
void compile_island_cleanup(void)
{
// Call the per-island cleanup to get rid of local symbol tables.
for (unsigned idx = 0; idx < island_count; idx += 1) {
island_list[idx]->compile_cleanup();
}
// If we are not doing valgrind checking then free the list.
#ifndef CHECK_WITH_VALGRIND
free(island_list);
island_list = 0;
island_count = 0;
#endif
// Remove the island symbol table itself.
delete island_table;
island_table = 0;
}