Add support for only two variable delays and add delay checks.

This patch adds checks that the delay count is correct for the
various gates and adds support for a missing variable decay
time. For this case the decay time is the minimum of the rise
and fall times. This is denoted by setting the decay variable
to 0 in the vvp file. vvp notes this and sets an ignore decay
time property in the base delay. This turns off the ability
to set the decay time and the minimum delay calculation will
also update the decay time.
This commit is contained in:
Cary R 2010-07-13 10:01:32 -07:00 committed by Stephen Williams
parent 6fbf47025f
commit 13fb07dc17
11 changed files with 285 additions and 45 deletions

View File

@ -65,6 +65,15 @@ void PDelays::set_delays(const svector<PExpr*>*del, bool df)
delete_flag_ = df;
}
unsigned PDelays::delay_count() const
{
unsigned dly_cnt = 0;
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
if (delay_[idx]) dly_cnt += 1;
return dly_cnt;
}
static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr)
{
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
@ -144,8 +153,6 @@ static NetExpr* calc_decay_time(NetExpr *rise, NetExpr *fall)
else return fall;
}
cerr << fall->get_fileline() << ": sorry: can not calculate the "
<< "decay time from " << *rise << " and " << *fall << endl;
return 0;
}

View File

@ -1,7 +1,7 @@
#ifndef __PDelays_H
#define __PDelays_H
/*
* Copyright (c) 1999-2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2010 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
@ -50,6 +50,8 @@ class PDelays {
void set_delay(PExpr*);
void set_delays(const svector<PExpr*>*del, bool delete_flag=true);
unsigned delay_count() const;
void eval_delays(Design*des, NetScope*scope,
NetExpr*&rise_time,
NetExpr*&fall_time,

103
PGate.cc
View File

@ -99,6 +99,11 @@ void PGate::eval_delays(Design*des, NetScope*scope,
as_net_flag);
}
unsigned PGate::delay_count() const
{
return delay_.delay_count();
}
PGAssign::PGAssign(svector<PExpr*>*pins)
: PGate(perm_string(), pins)
{
@ -143,6 +148,104 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
lsb_ = lsb;
}
const char* PGBuiltin::gate_name() const
{
switch(type_) {
case AND:
return "AND";
break;
case NAND:
return "NAND";
break;
case OR:
return "OR";
break;
case NOR:
return "NOR";
break;
case XOR:
return "XOR";
break;
case XNOR:
return "XNOR";
break;
case BUF:
return "BUF";
break;
case NOT:
return "NOT";
break;
case BUFIF0:
return "BUFIF0";
break;
case NOTIF0:
return "NOTIF0";
break;
case BUFIF1:
return "BUFIF1";
break;
case NOTIF1:
return "NOTIF1";
break;
case NMOS:
return "NMOS";
break;
case RNMOS:
return "RNMOS";
break;
case PMOS:
return "PMOS";
break;
case RPMOS:
return "RPMOS";
break;
case TRAN:
return "TRAN";
break;
case RTRAN:
return "RTRAN";
break;
case TRANIF0:
return "TRANIF0";
break;
case RTRANIF0:
return "RTRANIF0";
break;
case TRANIF1:
return "TRANIF1";
break;
case RTRANIF1:
return "RTRANIF1";
break;
case CMOS:
return "CMOS";
break;
case RCMOS:
return "RCMOS";
break;
case PULLUP:
return "PULLUP";
break;
case PULLDOWN:
return "PULLDOWN";
break;
}
return "<unknown>";
}
PGModule::PGModule(perm_string type, perm_string name, svector<PExpr*>*pins)
: PGate(name, pins), overrides_(0), pins_(0),
npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0)

View File

@ -68,6 +68,8 @@ class PGate : public LineInfo {
NetExpr*&decay_time,
bool as_net_flag =false) const;
unsigned delay_count() const;
unsigned pin_count() const { return pins_? pins_->count() : 0; }
PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
@ -149,6 +151,7 @@ class PGBuiltin : public PGate {
~PGBuiltin();
Type type() const { return type_; }
const char * gate_name() const;
void set_range(PExpr*msb, PExpr*lsb);
virtual void dump(ostream&out, unsigned ind =4) const;
@ -165,6 +168,8 @@ class PGBuiltin : public PGate {
perm_string gate_name,
unsigned instance_width) const;
bool check_delay_count(Design*des) const;
Type type_;
PExpr*msb_;
PExpr*lsb_;

View File

@ -296,7 +296,7 @@ unsigned PGBuiltin::calculate_output_count_(void) const
}
NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
perm_string gate_name,
perm_string inst_name,
unsigned instance_width) const
{
NetNode*gate = 0;
@ -309,7 +309,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::AND, instance_width);
}
break;
@ -320,7 +320,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, 2,
gate = new NetLogic(scope, inst_name, 2,
NetLogic::BUF, instance_width);
}
break;
@ -331,7 +331,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::BUFIF0, instance_width);
}
break;
@ -342,7 +342,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::BUFIF1, instance_width);
}
break;
@ -353,7 +353,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have four arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::CMOS, instance_width);
}
break;
@ -364,7 +364,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::NAND, instance_width);
}
break;
@ -375,7 +375,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::NMOS, instance_width);
}
break;
@ -386,7 +386,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::NOR, instance_width);
}
break;
@ -397,7 +397,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, 2,
gate = new NetLogic(scope, inst_name, 2,
NetLogic::NOT, instance_width);
}
break;
@ -408,7 +408,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::NOTIF0, instance_width);
}
break;
@ -419,7 +419,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::NOTIF1, instance_width);
}
break;
@ -430,7 +430,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::OR, instance_width);
}
break;
@ -441,7 +441,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have four arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::RCMOS, instance_width);
}
break;
@ -452,7 +452,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::RNMOS, instance_width);
}
break;
@ -463,7 +463,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::RPMOS, instance_width);
}
break;
@ -474,18 +474,18 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have three arguments." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::PMOS, instance_width);
}
break;
case PULLDOWN:
gate = new NetLogic(scope, gate_name, 1,
gate = new NetLogic(scope, inst_name, 1,
NetLogic::PULLDOWN, instance_width);
break;
case PULLUP:
gate = new NetLogic(scope, gate_name, 1,
gate = new NetLogic(scope, inst_name, 1,
NetLogic::PULLUP, instance_width);
break;
@ -495,7 +495,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::XNOR, instance_width);
}
break;
@ -506,7 +506,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
"primitive must have an input." << endl;
des->errors += 1;
} else {
gate = new NetLogic(scope, gate_name, pin_count(),
gate = new NetLogic(scope, inst_name, pin_count(),
NetLogic::XOR, instance_width);
}
break;
@ -517,7 +517,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tran device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_TRAN);
gate = new NetTran(scope, inst_name, IVL_SW_TRAN);
}
break;
@ -527,7 +527,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtran device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_RTRAN);
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN);
}
break;
@ -537,7 +537,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tranif0 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_TRANIF0);
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0);
}
break;
@ -547,7 +547,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtranif0 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_RTRANIF0);
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0);
}
break;
@ -557,7 +557,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tranif1 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_TRANIF1);
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1);
}
break;
@ -567,7 +567,7 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtranif1 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, gate_name, IVL_SW_RTRANIF1);
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1);
}
break;
@ -581,6 +581,102 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
return gate;
}
bool PGBuiltin::check_delay_count(Design*des) const
{
switch (type()) {
case AND:
case NAND:
case OR:
case NOR:
case XOR:
case XNOR:
case BUF:
case NOT:
if (delay_count() > 2) {
cerr << get_fileline() << ": error: More than two delays "
<< "given to a " << gate_name() << " gate." << endl;
des->errors += 1;
return true;
}
break;
case BUFIF0:
case NOTIF0:
case BUFIF1:
case NOTIF1:
if (delay_count() > 3) {
cerr << get_fileline() << ": error: More than three delays "
<< "given to a " << gate_name() << " gate." << endl;
des->errors += 1;
return true;
}
break;
case NMOS:
case RNMOS:
case PMOS:
case RPMOS:
case CMOS:
case RCMOS:
if (delay_count() > 3) {
cerr << get_fileline() << ": error: More than three delays "
<< "given to a " << gate_name() << " switch." << endl;
des->errors += 1;
return true;
}
break;
case TRAN:
case RTRAN:
if (delay_count() != 0) {
cerr << get_fileline() << ": error: A " << gate_name()
<< " switch does not take any delays." << endl;
des->errors += 1;
return true;
}
break;
case TRANIF0:
case TRANIF1:
if (delay_count() > 2) {
cerr << get_fileline() << ": error: More than two delays "
<< "given to a " << gate_name() << " switch." << endl;
des->errors += 1;
return true;
}
break;
case RTRANIF0:
case RTRANIF1:
if (delay_count() > 2) {
cerr << get_fileline() << ": error: More than two delays "
<< "given to an " << gate_name() << " switch." << endl;
des->errors += 1;
return true;
}
break;
case PULLUP:
case PULLDOWN:
if (delay_count() != 0) {
cerr << get_fileline() << ": error: A " << gate_name()
<< " source does not take any delays." << endl;
des->errors += 1;
return true;
}
break;
default:
cerr << get_fileline() << ": internal error: unhandled "
"gate type." << endl;
des->errors += 1;
return true;
break;
}
return false;
}
/*
* Elaborate a Builtin gate. These normally get translated into
* NetLogic nodes that reflect the particular logic function.
@ -655,6 +751,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
of the rise and fall times. Finally, if all three
values are given, they are taken as specified. */
if (check_delay_count(des)) return;
NetExpr* rise_time, *fall_time, *decay_time;
eval_delays(des, scope, rise_time, fall_time, decay_time);
@ -687,9 +784,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
cur[idx]->attribute(attrib_list[adx].key,
attrib_list[adx].val);
/* Set the delays and drive strength for all built in gates.
We still need to add checks to verify that the delays and
strength are consistent with the gates definition. */
/* Set the delays and drive strength for all built in gates. */
cur[idx]->rise_time(rise_time);
cur[idx]->fall_time(fall_time);
cur[idx]->decay_time(decay_time);

View File

@ -910,24 +910,31 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
ivl_signal_t sig;
// We do not currently support calculating the decay from
// the rise and fall variable delays.
assert(decay_exp != 0);
assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);
assert((decay_exp == 0) ||
(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL));
fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, dly_width, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
fprintf(vvp_out, ", %s",
draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
fprintf(vvp_out, ", %s",
draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s;\n", draw_net_input(ivl_signal_nex(sig,0)));
if (decay_exp) {
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s;\n",
draw_net_input(ivl_signal_nex(sig,0)));
} else {
fprintf(vvp_out, ", 0;\n");
}
}
}
}

View File

@ -1257,9 +1257,10 @@ void compile_delay(char*label, unsigned width,
}
void compile_delay(char*label, unsigned width,
unsigned argc, struct symb_s*argv)
unsigned argc, struct symb_s*argv, bool ignore_decay)
{
vvp_delay_t stub (0, 0, 0);
if (ignore_decay) stub.set_ignore_decay();
vvp_net_t*net = new vvp_net_t;
vvp_fun_delay*obj = new vvp_fun_delay(net, width, stub);
net->fun = obj;

View File

@ -131,7 +131,8 @@ extern void compile_compiletf(struct __vpiSysTaskCall*);
extern void compile_delay(char*label, unsigned width,
vvp_delay_t*del, struct symb_s input);
extern void compile_delay(char*label, unsigned width,
unsigned argc, struct symb_s*argv);
unsigned argc, struct symb_s*argv,
bool ignore_decay);
/*
* This is called by the parser to create a part select node.

View File

@ -35,7 +35,8 @@ void vvp_delay_t::calculate_min_delay_()
min_delay_ = rise_;
if (fall_ < min_delay_)
min_delay_ = fall_;
if (decay_ < min_delay_)
if (ignore_decay_) decay_ = min_delay_;
else if (decay_ < min_delay_)
min_delay_ = decay_;
}
@ -45,6 +46,7 @@ vvp_delay_t::vvp_delay_t(vvp_time64_t rise, vvp_time64_t fall)
fall_ = fall;
decay_= fall < rise? fall : rise;
min_delay_ = decay_;
ignore_decay_ = false;
}
vvp_delay_t::vvp_delay_t(vvp_time64_t rise, vvp_time64_t fall, vvp_time64_t decay)
@ -52,6 +54,14 @@ vvp_delay_t::vvp_delay_t(vvp_time64_t rise, vvp_time64_t fall, vvp_time64_t deca
rise_ = rise;
fall_ = fall;
decay_= decay;
ignore_decay_ = false;
calculate_min_delay_();
}
void vvp_delay_t::set_ignore_decay()
{
ignore_decay_ = true;
calculate_min_delay_();
}
@ -126,6 +136,8 @@ void vvp_delay_t::set_fall(vvp_time64_t val)
void vvp_delay_t::set_decay(vvp_time64_t val)
{
assert(!ignore_decay_);
decay_ = val;
if (val < min_delay_)
min_delay_ = val;

View File

@ -1,7 +1,7 @@
#ifndef __delay_H
#define __delay_H
/*
* Copyright 2005-2008,2010 Stephen Williams
* Copyright 2005-2010 Stephen Williams
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -48,10 +48,12 @@ class vvp_delay_t {
void set_rise(vvp_time64_t val);
void set_fall(vvp_time64_t val);
void set_decay(vvp_time64_t val);
void set_ignore_decay();
private:
vvp_time64_t rise_, fall_, decay_;
vvp_time64_t min_delay_;
bool ignore_decay_;
void calculate_min_delay_();
};

View File

@ -431,7 +431,12 @@ statement
{ compile_delay($1, $3, $4, $5); }
| T_LABEL K_DELAY T_NUMBER symbols ';'
{ struct symbv_s obj = $4;
compile_delay($1, $3, obj.cnt, obj.vect);
compile_delay($1, $3, obj.cnt, obj.vect, false);
}
| T_LABEL K_DELAY T_NUMBER symbols ',' T_NUMBER ';'
{ struct symbv_s obj = $4;
if ($6 != 0) assert(0);
compile_delay($1, $3, obj.cnt, obj.vect, true);
}
| T_LABEL K_MODPATH T_NUMBER symbol symbol ','