diff --git a/PDelays.cc b/PDelays.cc index 9ce84eb0f..c51c1f5df 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -65,6 +65,15 @@ void PDelays::set_delays(const svector*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; } diff --git a/PDelays.h b/PDelays.h index d9dffb703..78a764f36 100644 --- a/PDelays.h +++ b/PDelays.h @@ -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*del, bool delete_flag=true); + unsigned delay_count() const; + void eval_delays(Design*des, NetScope*scope, NetExpr*&rise_time, NetExpr*&fall_time, diff --git a/PGate.cc b/PGate.cc index b469bd777..e94ead88f 100644 --- a/PGate.cc +++ b/PGate.cc @@ -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*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 ""; +} + PGModule::PGModule(perm_string type, perm_string name, svector*pins) : PGate(name, pins), overrides_(0), pins_(0), npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0) diff --git a/PGate.h b/PGate.h index 6e34660c9..8f6c4713f 100644 --- a/PGate.h +++ b/PGate.h @@ -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_; diff --git a/elaborate.cc b/elaborate.cc index 945c0d167..4937bf1fc 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index e62c1623c..1bc13e741 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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"); + } } } } diff --git a/vvp/compile.cc b/vvp/compile.cc index 53bceec72..fb157a399 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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; diff --git a/vvp/compile.h b/vvp/compile.h index e0c558782..fcd82144a 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -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. diff --git a/vvp/delay.cc b/vvp/delay.cc index 32950e80d..47d178f98 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -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; diff --git a/vvp/delay.h b/vvp/delay.h index 9b6eb75e7..d5f8beefe 100644 --- a/vvp/delay.h +++ b/vvp/delay.h @@ -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_(); }; diff --git a/vvp/parse.y b/vvp/parse.y index 5660ddb89..cd09833dd 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -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 ','