From 2bf3f5d1d33581bb4120c04c6e020c3a8fd0ccb6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 12 Jul 2010 16:04:22 -0700 Subject: [PATCH] Push tranif delays to the code generator. This patch pushes delays for tranif gates to the code generator. We still need to add checks for the number of delays, etc. For now an error message is printed when a tranif gate is given a non-zero delay. --- elaborate.cc | 17 ++++--- ivl.def | 1 + ivl_target.h | 1 + t-dll-api.cc | 8 +++- t-dll.cc | 100 ++++++++++-------------------------------- t-dll.h | 6 ++- tgt-vvp/draw_switch.c | 22 +++++++++- 7 files changed, 66 insertions(+), 89 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index c1df62da6..945c0d167 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -687,16 +687,15 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const cur[idx]->attribute(attrib_list[adx].key, attrib_list[adx].val); - /* The logic devices have some uniform processing. Then - all may have output delays and output drive strength. */ - if (NetLogic*log = dynamic_cast (cur[idx])) { - log->rise_time(rise_time); - log->fall_time(fall_time); - log->decay_time(decay_time); + /* 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. */ + cur[idx]->rise_time(rise_time); + cur[idx]->fall_time(fall_time); + cur[idx]->decay_time(decay_time); - log->pin(0).drive0(strength0()); - log->pin(0).drive1(strength1()); - } + cur[idx]->pin(0).drive0(strength0()); + cur[idx]->pin(0).drive1(strength1()); cur[idx]->set_line(*this); des->add_node(cur[idx]); diff --git a/ivl.def b/ivl.def index ddb57b0a1..1fd54e66e 100644 --- a/ivl.def +++ b/ivl.def @@ -255,6 +255,7 @@ ivl_stmt_sub_stmt ivl_switch_a ivl_switch_b ivl_switch_basename +ivl_switch_delay ivl_switch_enable ivl_switch_file ivl_switch_island diff --git a/ivl_target.h b/ivl_target.h index 720dfc3a3..68cf57d61 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -2039,6 +2039,7 @@ extern ivl_island_t ivl_switch_island(ivl_switch_t net); extern unsigned ivl_switch_width(ivl_switch_t net); extern unsigned ivl_switch_part(ivl_switch_t net); extern unsigned ivl_switch_offset(ivl_switch_t net); +extern ivl_expr_t ivl_switch_delay(ivl_switch_t net, unsigned transition); /* Not implemented yet extern unsigned ivl_switch_attr_cnt(ivl_switch_t net); diff --git a/t-dll-api.cc b/t-dll-api.cc index c9e8adbc4..a2dd1c157 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -564,7 +564,7 @@ extern "C" ivl_variable_type_t ivl_expr_value(ivl_expr_t net) extern "C" unsigned ivl_expr_width(ivl_expr_t net) { - assert(net); +// assert(net); return net->width_; } @@ -2451,6 +2451,12 @@ extern "C" unsigned ivl_switch_offset(ivl_switch_t net) return net->offset; } +extern "C" ivl_expr_t ivl_switch_delay(ivl_switch_t net, unsigned transition) +{ + assert(transition < 3); + return net->delay[transition]; +} + extern "C" const char* ivl_switch_file(ivl_switch_t net) { return net->file; diff --git a/t-dll.cc b/t-dll.cc index 23721efa4..e4448d69b 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -650,12 +650,11 @@ void dll_target::logic_attributes(struct ivl_net_logic_s *obj, obj->attr = fill_in_attributes(net); } -void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj, - const NetObj*net) +void dll_target::make_delays_(ivl_expr_t*delay, const NetObj*net) { - obj->delay[0] = 0; - obj->delay[1] = 0; - obj->delay[2] = 0; + delay[0] = 0; + delay[1] = 0; + delay[2] = 0; /* Translate delay expressions to ivl_target form. Try to preserve pointer equality, not as a rule but to save on @@ -663,105 +662,53 @@ void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj, if (net->rise_time()) { expr_ = 0; net->rise_time()->expr_scan(this); - obj->delay[0] = expr_; + delay[0] = expr_; expr_ = 0; } if (net->fall_time()) { if (net->fall_time() == net->rise_time()) { - obj->delay[1] = obj->delay[0]; + delay[1] = delay[0]; } else { expr_ = 0; net->fall_time()->expr_scan(this); - obj->delay[1] = expr_; + delay[1] = expr_; expr_ = 0; } } if (net->decay_time()) { if (net->decay_time() == net->rise_time()) { - obj->delay[2] = obj->delay[0]; + delay[2] = delay[0]; } else { expr_ = 0; net->decay_time()->expr_scan(this); - obj->delay[2] = expr_; + delay[2] = expr_; expr_ = 0; } } } +void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj, + const NetObj*net) +{ + make_delays_(obj->delay, net); +} + +void dll_target::make_switch_delays_(struct ivl_switch_s*obj, + const NetObj*net) +{ + make_delays_(obj->delay, net); +} + void dll_target::make_lpm_delays_(struct ivl_lpm_s*obj, const NetObj*net) { - obj->delay[0] = 0; - obj->delay[1] = 0; - obj->delay[2] = 0; - - /* Translate delay expressions to ivl_target form. Try to - preserve pointer equality, not as a rule but to save on - expression trees. */ - if (net->rise_time()) { - expr_ = 0; - net->rise_time()->expr_scan(this); - obj->delay[0] = expr_; - expr_ = 0; - } - if (net->fall_time()) { - if (net->fall_time() == net->rise_time()) { - obj->delay[1] = obj->delay[0]; - } else { - expr_ = 0; - net->fall_time()->expr_scan(this); - obj->delay[1] = expr_; - expr_ = 0; - } - } - if (net->decay_time()) { - if (net->decay_time() == net->rise_time()) { - obj->delay[2] = obj->delay[0]; - } else { - expr_ = 0; - net->decay_time()->expr_scan(this); - obj->delay[2] = expr_; - expr_ = 0; - } - } + make_delays_(obj->delay, net); } void dll_target::make_const_delays_(struct ivl_net_const_s*obj, const NetObj*net) { - obj->delay[0] = 0; - obj->delay[1] = 0; - obj->delay[2] = 0; - - /* Translate delay expressions to ivl_target form. Try to - preserve pointer equality, not as a rule but to save on - expression trees. */ - if (net->rise_time()) { - expr_ = 0; - net->rise_time()->expr_scan(this); - obj->delay[0] = expr_; - expr_ = 0; - } - if (net->fall_time()) { - if (net->fall_time() == net->rise_time()) { - obj->delay[1] = obj->delay[0]; - } else { - expr_ = 0; - net->fall_time()->expr_scan(this); - obj->delay[1] = expr_; - expr_ = 0; - } - } - if (net->decay_time()) { - if (net->decay_time() == net->rise_time()) { - obj->delay[2] = obj->delay[0]; - } else { - expr_ = 0; - net->decay_time()->expr_scan(this); - obj->delay[2] = expr_; - expr_ = 0; - } - } + make_delays_(obj->delay, net); } bool dll_target::branch(const NetBranch*net) @@ -1026,6 +973,7 @@ bool dll_target::tran(const NetTran*net) obj->lineno = net->get_lineno(); switch_attributes(obj, net); + make_switch_delays_(obj, net); scope_add_switch(obj->scope, obj); return true; diff --git a/t-dll.h b/t-dll.h index ab7670840..9625650c5 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef __t_dll_H #define __t_dll_H /* - * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-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 @@ -165,7 +165,9 @@ struct dll_target : public target_t, public expr_scan_t { void sub_off_from_expr_(long); void mul_expr_by_const_(long); + void make_delays_(ivl_expr_t*delay, const NetObj*net); void make_logic_delays_(struct ivl_net_logic_s*obj, const NetObj*net); + void make_switch_delays_(struct ivl_switch_s*obj, const NetObj*net); void make_lpm_delays_(struct ivl_lpm_s*obj, const NetObj*net); void make_const_delays_(struct ivl_net_const_s*obj, const NetObj*net); void make_scope_parameters(ivl_scope_t scope, const NetScope*net); @@ -479,6 +481,8 @@ struct ivl_switch_s { struct ivl_attribute_s*attr; unsigned nattr; + ivl_expr_t delay[3]; + ivl_nexus_t pins[3]; perm_string file; unsigned lineno; diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index 732fd0cf4..a7da8ff66 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -34,6 +34,23 @@ void draw_switch_in_scope(ivl_switch_t sw) ivl_nexus_t nex_a, nex_b, enable; const char*str_a, *str_b, *str_e; + ivl_expr_t rise_exp = ivl_switch_delay(sw, 0); + ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); + + /* We do not support tran delays. */ + if ((rise_exp || fall_exp) && + (!number_is_immediate(rise_exp, 64, 0) || + number_is_unknown(rise_exp) || + (get_number_immediate(rise_exp) != 0) || + !number_is_immediate(fall_exp, 64, 0) || + number_is_unknown(fall_exp) || + (get_number_immediate(rise_exp) != 0))) { + fprintf(stderr, "%s:%u: sorry: tranif gates with a delay are not " + "currently support.\n", + ivl_switch_file(sw), ivl_switch_lineno(sw)); + exit(1); + } + island = ivl_switch_island(sw); if (ivl_island_flag_test(island, 0) == 0) draw_tran_island(island); @@ -68,8 +85,9 @@ void draw_switch_in_scope(ivl_switch_t sw) break; default: - fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n", - ivl_switch_file(sw), ivl_switch_lineno(sw)); + fprintf(stderr, "%s:%u: sorry: resistive switch modeling is not " + "currently supported.\n", + ivl_switch_file(sw), ivl_switch_lineno(sw)); vvp_errors += 1; return; }