Correctly handle separate port type declaration for `integer` and `time`

When using non-ANSI style port declarations it is possible to declare the
port direction and the data type for the port in separate statements. E.g.

```
input x;
reg x;
```

When using packed array dimensions they must match for both declarations.
E.g.

```
input [3:0] x;
reg [3:0] x;
```

But this only applies for vector types, i.e. the packed dimension is
explicitly declared. It does not apply to the `integer` and `time` types,
which have an implicit packed dimension.

The current implementation requires that even for `integer` and `time`
types the implicit dimension needs to be explicitly declared in the port
direction. E.g. the following will result in a elaboration error
complaining about a packed dimension mismatch.

```
module test;
  output x;
  integer x;
endmodule
```

Currently the parser creates a vector_type_t for `time` and `integer`. This
means that e.g. `time` and `reg [63:0]` are indistinguishable during
elaboration, even though they require different behavior.

To fix let the atom2_type_t handle `integer` and `time`. Since it no longer
exclusively handles 2-state types, rename it to atom_type_t.

This also fixes a problem with the vlog95 target unit tests. The vlog95
target translates

```
module test(output integer x);
endmodule
```

to

```
module test(x);
  output x;
  integer x;
endmodule
```

which then fails when being elaborated again. There were some regression
tests that were failing because of this that will now pass.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-03-12 21:10:19 +01:00
parent de9e3b791b
commit f6042033d0
14 changed files with 107 additions and 111 deletions

View File

@ -29,16 +29,11 @@ PWire::PWire(perm_string n,
NetNet::PortType pt, NetNet::PortType pt,
ivl_variable_type_t dt) ivl_variable_type_t dt)
: name_(n), type_(t), port_type_(pt), data_type_(dt), : name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false), signed_(false),
port_set_(false), net_set_(false), is_scalar_(false), port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), uarray_type_(0), set_data_type_(0), error_cnt_(0), uarray_type_(0), set_data_type_(0),
discipline_(0) discipline_(0)
{ {
if (t == NetNet::INTEGER) {
type_ = NetNet::REG;
signed_ = true;
isint_ = true;
}
} }
NetNet::Type PWire::get_wire_type() const NetNet::Type PWire::get_wire_type() const
@ -64,18 +59,9 @@ bool PWire::set_wire_type(NetNet::Type t)
type_ = t; type_ = t;
return true; return true;
} }
if (t == NetNet::INTEGER) {
type_ = NetNet::REG;
isint_ = true;
return true;
}
if (t == NetNet::IMPLICIT_REG) return true; if (t == NetNet::IMPLICIT_REG) return true;
return false; return false;
case NetNet::REG: case NetNet::REG:
if (t == NetNet::INTEGER) {
isint_ = true;
return true;
}
if (t == NetNet::REG) return true; if (t == NetNet::REG) return true;
return false; return false;
default: default:
@ -146,18 +132,6 @@ bool PWire::get_signed() const
return signed_; return signed_;
} }
bool PWire::get_isint() const
{
if (isint_)
return true;
if (vector_type_t*tmp = dynamic_cast<vector_type_t*>(set_data_type_)) {
return tmp->integer_flag;
}
return false;
}
void PWire::set_range_scalar(PWSRType type) void PWire::set_range_scalar(PWSRType type)
{ {
is_scalar_ = true; is_scalar_ = true;
@ -267,11 +241,6 @@ void PWire::set_data_type(data_type_t*type)
{ {
assert(set_data_type_ == 0 || set_data_type_ == type); assert(set_data_type_ == 0 || set_data_type_ == type);
set_data_type_ = type; set_data_type_ = type;
if (vector_type_t*tmp = dynamic_cast<vector_type_t*>(type)) {
if (tmp->integer_flag)
isint_ = true;
}
} }
void PWire::set_discipline(ivl_discipline_t d) void PWire::set_discipline(ivl_discipline_t d)
@ -289,7 +258,6 @@ PNamedItem::SymbolType PWire::symbol_type() const
{ {
switch (type_) { switch (type_) {
case NetNet::IMPLICIT_REG: case NetNet::IMPLICIT_REG:
case NetNet::INTEGER:
case NetNet::REG: case NetNet::REG:
return VAR; return VAR;
default: default:

View File

@ -70,7 +70,6 @@ class PWire : public PNamedItem {
void set_signed(bool flag); void set_signed(bool flag);
bool get_signed() const; bool get_signed() const;
bool get_isint() const;
bool set_data_type(ivl_variable_type_t dt); bool set_data_type(ivl_variable_type_t dt);
ivl_variable_type_t get_data_type() const; ivl_variable_type_t get_data_type() const;
@ -101,7 +100,6 @@ class PWire : public PNamedItem {
NetNet::PortType port_type_; NetNet::PortType port_type_;
ivl_variable_type_t data_type_; ivl_variable_type_t data_type_;
bool signed_; bool signed_;
bool isint_; // original type of integer
// These members hold expressions for the bit width of the // These members hold expressions for the bit width of the
// wire. If they do not exist, the wire is 1 bit wide. If they // wire. If they do not exist, the wire is 1 bit wide. If they

View File

@ -942,7 +942,7 @@ ivl_type_t PWire::elaborate_type(Design*des, NetScope*scope,
dynamic_cast<string_type_t*>(set_data_type_) || dynamic_cast<string_type_t*>(set_data_type_) ||
dynamic_cast<class_type_t*>(set_data_type_) || dynamic_cast<class_type_t*>(set_data_type_) ||
dynamic_cast<parray_type_t*>(set_data_type_) || dynamic_cast<parray_type_t*>(set_data_type_) ||
dynamic_cast<atom2_type_t*>(set_data_type_)) { dynamic_cast<atom_type_t*>(set_data_type_)) {
ivl_type_t use_type = set_data_type_->elaborate_type(des, scope); ivl_type_t use_type = set_data_type_->elaborate_type(des, scope);
ivl_assert(*this, packed_dimensions.empty()); ivl_assert(*this, packed_dimensions.empty());
return use_type; return use_type;
@ -967,7 +967,6 @@ ivl_type_t PWire::elaborate_type(Design*des, NetScope*scope,
netvector_t*vec = new netvector_t(packed_dimensions, use_data_type); netvector_t*vec = new netvector_t(packed_dimensions, use_data_type);
vec->set_signed(get_signed()); vec->set_signed(get_signed());
vec->set_isint(get_isint());
return vec; return vec;
} }

View File

@ -66,28 +66,37 @@ ivl_type_t data_type_t::elaborate_type_raw(Design*des, NetScope*) const
return 0; return 0;
} }
ivl_type_t atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const ivl_type_t atom_type_t::elaborate_type_raw(Design*des, NetScope*) const
{ {
switch (type_code) { switch (type_code) {
case 64: case INTEGER:
return netvector_t::integer_type(signed_flag);
case TIME:
if (signed_flag)
return &netvector_t::time_signed;
else
return &netvector_t::time_unsigned;
case LONGINT:
if (signed_flag) if (signed_flag)
return &netvector_t::atom2s64; return &netvector_t::atom2s64;
else else
return &netvector_t::atom2u64; return &netvector_t::atom2u64;
case 32: case INT:
if (signed_flag) if (signed_flag)
return &netvector_t::atom2s32; return &netvector_t::atom2s32;
else else
return &netvector_t::atom2u32; return &netvector_t::atom2u32;
case 16: case SHORTINT:
if (signed_flag) if (signed_flag)
return &netvector_t::atom2s16; return &netvector_t::atom2s16;
else else
return &netvector_t::atom2u16; return &netvector_t::atom2u16;
case 8: case BYTE:
if (signed_flag) if (signed_flag)
return &netvector_t::atom2s8; return &netvector_t::atom2s8;
else else
@ -95,7 +104,7 @@ ivl_type_t atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const
default: default:
cerr << get_fileline() << ": internal error: " cerr << get_fileline() << ": internal error: "
<< "atom2_type_t type_code=" << type_code << "." << endl; << "atom_type_t type_code=" << type_code << "." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }

View File

@ -293,7 +293,7 @@ vector<bool> Nexus::driven_mask(void) const
// information from this node, move on. // information from this node, move on.
if (const NetNet*sig = dynamic_cast<const NetNet*> (obj)) { if (const NetNet*sig = dynamic_cast<const NetNet*> (obj)) {
NetNet::Type sig_type = sig->type(); NetNet::Type sig_type = sig->type();
if (sig_type==NetNet::INTEGER || sig_type==NetNet::REG) { if (sig_type==NetNet::REG) {
for (size_t idx = 0 ; idx < mask.size() ; idx += 1) for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true; mask[idx] = true;
return mask; return mask;

View File

@ -51,9 +51,6 @@ ostream& operator<< (ostream&o, NetNet::Type t)
case NetNet::IMPLICIT_REG: case NetNet::IMPLICIT_REG:
o << "reg /*implicit*/"; o << "reg /*implicit*/";
break; break;
case NetNet::INTEGER:
o << "integer";
break;
case NetNet::REG: case NetNet::REG:
o << "reg"; o << "reg";
break; break;

View File

@ -664,7 +664,7 @@ struct PortInfo
class NetNet : public NetObj, public PortType { class NetNet : public NetObj, public PortType {
public: public:
enum Type ENUM_UNSIGNED_INT { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1, enum Type ENUM_UNSIGNED_INT { NONE, IMPLICIT, IMPLICIT_REG, WIRE, TRI, TRI1,
SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG,
UNRESOLVED_WIRE }; UNRESOLVED_WIRE };

View File

@ -32,15 +32,18 @@ netvector_t netvector_t::atom2u16 (IVL_VT_BOOL, 15, 0, false);
netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 7, 0, true); netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 7, 0, true);
netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 7, 0, false); netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 7, 0, false);
static netvector_t* save_integer_type = 0; netvector_t netvector_t::time_signed (IVL_VT_LOGIC, 63, 0, true);
const netvector_t* netvector_t::integer_type() netvector_t netvector_t::time_unsigned (IVL_VT_LOGIC, 63, 0, false);
{
if (save_integer_type)
return save_integer_type;
save_integer_type = new netvector_t(IVL_VT_LOGIC, integer_width-1, 0, true); static netvector_t* save_integer_type[2];
save_integer_type->set_isint(true); const netvector_t* netvector_t::integer_type(bool is_signed)
return save_integer_type; {
if (save_integer_type[is_signed])
return save_integer_type[is_signed];
save_integer_type[is_signed] = new netvector_t(IVL_VT_LOGIC, integer_width-1, 0, is_signed);
save_integer_type[is_signed]->set_isint(true);
return save_integer_type[is_signed];
} }
//netvector_t netvector_t::scalar_bool (IVL_VT_BOOL); //netvector_t netvector_t::scalar_bool (IVL_VT_BOOL);

View File

@ -75,9 +75,11 @@ class netvector_t : public ivl_type_s {
static netvector_t atom2u16; static netvector_t atom2u16;
static netvector_t atom2s8; static netvector_t atom2s8;
static netvector_t atom2u8; static netvector_t atom2u8;
static netvector_t time_signed;
static netvector_t time_unsigned;
static netvector_t scalar_bool; static netvector_t scalar_bool;
static netvector_t scalar_logic; static netvector_t scalar_logic;
static const netvector_t*integer_type(); static const netvector_t*integer_type(bool is_signed = true);
private: private:
bool test_compatibility(ivl_type_t that) const; bool test_compatibility(ivl_type_t that) const;

45
parse.y
View File

@ -380,6 +380,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
char letter; char letter;
int int_val; int int_val;
enum atom_type_t::type_code atom_type;
/* text items are C strings allocated by the lexor using /* text items are C strings allocated by the lexor using
strdup. They can be put into lists with the texts type. */ strdup. They can be put into lists with the texts type. */
char*text; char*text;
@ -705,7 +707,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <real_type> non_integer_type %type <real_type> non_integer_type
%type <int_val> assert_or_assume %type <int_val> assert_or_assume
%type <int_val> deferred_mode %type <int_val> deferred_mode
%type <int_val> atom2_type %type <atom_type> atom_type
%type <int_val> module_start module_end %type <int_val> module_start module_end
%type <lifetime> lifetime lifetime_opt %type <lifetime> lifetime lifetime_opt
@ -1224,20 +1226,14 @@ simple_packed_type /* Integer and vector types */
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| atom2_type signed_unsigned_opt | atom_type signed_unsigned_opt
{ atom2_type_t*tmp = new atom2_type_t($1, $2); { atom_type_t*tmp = new atom_type_t($1, $2);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| K_integer signed_unsigned_opt
{ std::list<pform_range_t>*pd = make_range_from_width(integer_width);
vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $2, pd);
tmp->integer_flag = true;
$$ = tmp;
}
| K_time unsigned_signed_opt | K_time unsigned_signed_opt
{ std::list<pform_range_t>*pd = make_range_from_width(64); { atom_type_t*tmp = new atom_type_t(atom_type_t::TIME, $2);
vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $2, pd); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
; ;
@ -2184,20 +2180,14 @@ simple_type_or_string /* IEEE1800-2005: A.2.2.1 */
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| atom2_type | atom_type
{ atom2_type_t*tmp = new atom2_type_t($1, true); { atom_type_t*tmp = new atom_type_t($1, true);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| K_integer
{ std::list<pform_range_t>*pd = make_range_from_width(integer_width);
vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, true, pd);
tmp->integer_flag = true;
$$ = tmp;
}
| K_time | K_time
{ std::list<pform_range_t>*pd = make_range_from_width(64); { atom_type_t*tmp = new atom_type_t(atom_type_t::TIME, false);
vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, pd); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| K_string | K_string
@ -2750,7 +2740,7 @@ enum_base_type /* IEEE 1800-2012 A.2.2.1 */
} }
} }
| |
{ $$ = new atom2_type_t(32, true); { $$ = new atom_type_t(atom_type_t::INT, true);
FILE_NAME($$, @0); FILE_NAME($$, @0);
} }
; ;
@ -4604,11 +4594,12 @@ signed_unsigned_opt
* In some places we can take any of the 4 2-value atom-type * In some places we can take any of the 4 2-value atom-type
* names. All the context needs to know if that type is its width. * names. All the context needs to know if that type is its width.
*/ */
atom2_type atom_type
: K_byte { $$ = 8; } : K_byte { $$ = atom_type_t::BYTE; }
| K_shortint { $$ = 16; } | K_shortint { $$ = atom_type_t::SHORTINT; }
| K_int { $$ = 32; } | K_int { $$ = atom_type_t::INT; }
| K_longint { $$ = 64; } | K_longint { $$ = atom_type_t::LONGINT; }
| K_integer { $$ = atom_type_t::INTEGER; }
; ;
/* An lpvalue is the expression that can go on the left side of a /* An lpvalue is the expression that can go on the left side of a

View File

@ -2862,8 +2862,7 @@ static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
ivl_variable_type_t vtype, ivl_variable_type_t vtype,
bool signed_flag, bool signed_flag,
list<pform_range_t>*range, list<pform_range_t>*range,
list<pform_port_t>*ports, list<pform_port_t>*ports)
bool isint = false)
{ {
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(ports); assert(ports);
@ -2884,10 +2883,6 @@ static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
} }
curw->set_signed(signed_flag); curw->set_signed(signed_flag);
if (isint) {
bool flag = curw->set_wire_type(NetNet::INTEGER);
assert(flag);
}
/* If there is a range involved, it needs to be set. */ /* If there is a range involved, it needs to be set. */
if (range) { if (range) {
@ -2954,8 +2949,9 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
vtype = uarray->base_type; vtype = uarray->base_type;
} }
if (dynamic_cast<atom2_type_t*> (vtype)) { if (dynamic_cast<atom_type_t*> (vtype)) {
ret = do_make_task_ports(loc, pt, IVL_VT_BOOL, vtype, ports); ret = do_make_task_ports(loc, pt, vtype->figure_packed_base_type(),
vtype, ports);
} }
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) { if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
@ -2966,7 +2962,7 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
ret = pform_make_task_ports(loc, pt, base_type, ret = pform_make_task_ports(loc, pt, base_type,
vec_type->signed_flag, vec_type->signed_flag,
copy_range(vec_type->pdims.get()), copy_range(vec_type->pdims.get()),
ports, vec_type->integer_flag); ports);
} }
if (/*real_type_t*real_type = */ dynamic_cast<real_type_t*> (vtype)) { if (/*real_type_t*real_type = */ dynamic_cast<real_type_t*> (vtype)) {
@ -3440,9 +3436,6 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<pe
data_type = uarray_type->base_type; data_type = uarray_type->base_type;
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type)) { if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type)) {
if (net_type==NetNet::REG && vec_type->integer_flag)
net_type=NetNet::INTEGER;
pform_set_net_range(names, vec_type->pdims.get(), pform_set_net_range(names, vec_type->pdims.get(),
vec_type->signed_flag, 0); vec_type->signed_flag, 0);
vt = vec_type->base_type; vt = vec_type->base_type;

View File

@ -173,13 +173,36 @@ ostream& data_type_t::debug_dump(ostream&out) const
return out; return out;
} }
ostream& atom2_type_t::debug_dump(ostream&out) const ostream& atom_type_t::debug_dump(ostream&out) const
{ {
if (signed_flag) if (signed_flag)
out << "signed-"; out << "signed ";
else else
out << "unsigned-"; out << "unsigned ";
out << "int(" << type_code << ")";
switch (type_code) {
case INTEGER:
out << "integer";
break;
case TIME:
out << "time";
break;
case LONGINT:
out << "longint";
break;
case INT:
out << "int";
break;
case SHORTINT:
out << "shortint";
break;
case BYTE:
out << "byte";
break;
default:
assert(0);
break;
}
return out; return out;
} }
@ -584,9 +607,6 @@ void PWire::dump(ostream&out, unsigned ind) const
if (signed_) { if (signed_) {
out << " signed"; out << " signed";
} }
if (get_isint()) {
out << " integer";
}
if (is_scalar_) { if (is_scalar_) {
out << " scalar"; out << " scalar";
} }

View File

@ -53,12 +53,18 @@ ivl_variable_type_t enum_type_t::figure_packed_base_type() const
return base_type->figure_packed_base_type(); return base_type->figure_packed_base_type();
} }
ivl_variable_type_t atom2_type_t::figure_packed_base_type() const ivl_variable_type_t atom_type_t::figure_packed_base_type() const
{ {
return IVL_VT_BOOL; switch (type_code) {
case TIME:
case INT:
return IVL_VT_LOGIC;
default:
return IVL_VT_BOOL;
}
} }
atom2_type_t size_type (32, true); atom_type_t size_type (atom_type_t::INT, true);
PNamedItem::SymbolType enum_type_t::symbol_type() const PNamedItem::SymbolType enum_type_t::symbol_type() const
{ {

View File

@ -208,10 +208,20 @@ struct struct_type_t : public data_type_t {
std::unique_ptr< std::list<struct_member_t*> > members; std::unique_ptr< std::list<struct_member_t*> > members;
}; };
struct atom2_type_t : public data_type_t { struct atom_type_t : public data_type_t {
inline explicit atom2_type_t(int tc, bool flag) enum type_code {
: type_code(tc), signed_flag(flag) { } INTEGER,
int type_code; TIME,
BYTE,
SHORTINT,
INT,
LONGINT
};
explicit atom_type_t(enum type_code tc, bool flag) : type_code(tc),
signed_flag(flag) { }
enum type_code type_code;
bool signed_flag; bool signed_flag;
virtual std::ostream& debug_dump(std::ostream&out) const; virtual std::ostream& debug_dump(std::ostream&out) const;
@ -221,7 +231,7 @@ struct atom2_type_t : public data_type_t {
ivl_variable_type_t figure_packed_base_type() const; ivl_variable_type_t figure_packed_base_type() const;
}; };
extern atom2_type_t size_type; extern atom_type_t size_type;
/* /*
* The vector_type_t class represents types in the old Verilog * The vector_type_t class represents types in the old Verilog