150 lines
4.1 KiB
C++
150 lines
4.1 KiB
C++
/*
|
|
* Copyright (c) 2011-2022 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
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
# include "netlist.h"
|
|
# include "netstruct.h"
|
|
# include "netvector.h"
|
|
# include <iostream>
|
|
|
|
# include "ivl_assert.h"
|
|
|
|
using namespace std;
|
|
|
|
netstruct_t::netstruct_t()
|
|
: union_(false), packed_(false), signed_(false)
|
|
{
|
|
}
|
|
|
|
netstruct_t::~netstruct_t()
|
|
{
|
|
}
|
|
|
|
void netstruct_t::union_flag(bool flag)
|
|
{
|
|
// This MUST be called before any members are pushed into the
|
|
// definition. This is because the append relies on this flag
|
|
// being accurate.
|
|
ivl_assert(*this, members_.empty());
|
|
union_ = flag;
|
|
}
|
|
|
|
void netstruct_t::packed(bool flag)
|
|
{
|
|
ivl_assert(*this, members_.empty());
|
|
packed_ = flag;
|
|
}
|
|
|
|
void netstruct_t::append_member(Design*des, const netstruct_t::member_t&val)
|
|
{
|
|
ivl_assert(*this, val.net_type);
|
|
|
|
members_.push_back(val);
|
|
if (packed_) {
|
|
if (! members_.back().net_type->packed()) {
|
|
cerr << get_fileline() << ": error: "
|
|
<< "Member " << members_.back().name
|
|
<< " of packed struct/union"
|
|
<< " must be packed." << endl;
|
|
des->errors += 1;
|
|
}
|
|
}
|
|
if (union_ && packed_ && members_.size() > 1) {
|
|
unsigned long expect_wid = members_.front().net_type->packed_width();
|
|
unsigned long got_wid = members_.back().net_type->packed_width();
|
|
if (expect_wid != got_wid) {
|
|
cerr << get_fileline() << ": error: "
|
|
<< "Member " << val.name
|
|
<< " of packed union"
|
|
<< " is " << got_wid
|
|
<< " bits, expecting " << expect_wid << " bits." << endl;
|
|
des->errors += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const
|
|
{
|
|
unsigned long count_off = 0;
|
|
for (size_t idx = members_.size() ; idx > 0 ; idx -= 1) {
|
|
if (members_[idx-1].name == name) {
|
|
off = count_off;
|
|
return &members_[idx-1];
|
|
}
|
|
// If this is not a union, then the members are lined up
|
|
// from LSB to MSB. If this is a union, then all
|
|
// members are at offset 0.
|
|
if (!union_)
|
|
count_off += members_[idx-1].net_type->packed_width();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long netstruct_t::packed_width(void) const
|
|
{
|
|
if (! packed_)
|
|
return -1;
|
|
|
|
// If this is a packed union, then all the members are the
|
|
// same width, so it is sufficient to return the width of any
|
|
// single member.
|
|
if (union_)
|
|
return members_.front().net_type->packed_width();
|
|
|
|
// The width of a packed struct is the sum of member widths.
|
|
long res = 0;
|
|
for (size_t idx = 0 ; idx < members_.size() ; idx += 1)
|
|
res += members_[idx].net_type->packed_width();
|
|
|
|
return res;
|
|
}
|
|
|
|
vector<netrange_t> netstruct_t::slice_dimensions() const
|
|
{
|
|
vector<netrange_t> tmp;
|
|
tmp .push_back(netrange_t(packed_width()-1, 0));
|
|
return tmp;
|
|
}
|
|
|
|
ivl_variable_type_t netstruct_t::base_type() const
|
|
{
|
|
if (! packed_)
|
|
return IVL_VT_NO_TYPE;
|
|
|
|
for (size_t idx = 0 ; idx < members_.size() ; idx += 1) {
|
|
if (members_[idx].data_type() != IVL_VT_BOOL)
|
|
return members_[idx].data_type();
|
|
}
|
|
|
|
return IVL_VT_BOOL;
|
|
}
|
|
|
|
bool netstruct_t::test_compatibility(ivl_type_t that) const
|
|
{
|
|
return packed_type_compatible(that);
|
|
}
|
|
|
|
bool netstruct_t::test_equivalence(ivl_type_t that) const
|
|
{
|
|
if (!packed_)
|
|
return this == that;
|
|
|
|
return packed_types_equivalent(this, that);
|
|
}
|