From 39ee49b2524e495e4a7f1b20a178459f6c4b52ce Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Wed, 14 Mar 2012 19:49:37 +0000 Subject: [PATCH] Improved behaviour of tranif when control is 'x' or 'z'. The IEEE standard does not specify the behaviour of a tranif primitive when its control input is an 'x' or 'z'. vvp currently treats these as if the tran was turned off, but it would be better to propagate the uncertainty to the tran bi-directional ports. For compatibility with other simulators, we adopt the behaviour specified for MOS primitives. --- tgt-vvp/draw_net_input.c | 10 +++--- vvp/island_tran.cc | 69 +++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index ffc835518..5b7de3472 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -703,11 +703,13 @@ static void draw_net_input_x(ivl_nexus_t nex, if ( (sw = ivl_nexus_ptr_switch(nptr)) ) { assert(island == 0 || island == ivl_switch_island(sw)); island = ivl_switch_island(sw); - if (nex == ivl_switch_a(sw)) + if (nex == ivl_switch_a(sw)) { + nex_flags |= VVP_NEXUS_DATA_STR; island_input_flag = 0; - else if (nex == ivl_switch_b(sw)) + } else if (nex == ivl_switch_b(sw)) { + nex_flags |= VVP_NEXUS_DATA_STR; island_input_flag = 0; - else if (island_input_flag == -1) { + } else if (island_input_flag == -1) { assert(nex == ivl_switch_enable(sw)); island_input_flag = 1; } diff --git a/vvp/island_tran.cc b/vvp/island_tran.cc index 4cd0989b8..5462f02a4 100644 --- a/vvp/island_tran.cc +++ b/vvp/island_tran.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2012 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 @@ -31,6 +31,12 @@ class vvp_island_tran : public vvp_island { void run_island(); }; +enum tran_state_t { + tran_disabled, + tran_enabled, + tran_unknown +}; + struct vvp_island_branch_tran : public vvp_island_branch { vvp_island_branch_tran(vvp_net_t*en__, bool active_high__, @@ -43,7 +49,7 @@ struct vvp_island_branch_tran : public vvp_island_branch { vvp_net_t*en; unsigned width, part, offset; bool active_high; - bool enabled_flag; + tran_state_t state; }; vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__, @@ -54,7 +60,7 @@ vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__, : en(en__), width(width__), part(part__), offset(offset__), active_high(active_high__) { - enabled_flag = en__ ? false : true; + state = en__ ? tran_disabled : tran_enabled; } static inline vvp_island_branch_tran* BRANCH_TRAN(vvp_island_branch*tmp) @@ -73,7 +79,7 @@ void vvp_island_tran::run_island() { // Test to see if any of the branches are enabled. This loop // tests the enabled inputs for all the branches and caches - // the results in the enabled_flag for each branch. + // the results in the state for each branch. bool runnable = false; for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) { vvp_island_branch_tran*tmp = dynamic_cast(cur); @@ -103,7 +109,7 @@ bool vvp_island_branch_tran::run_test_enabled() // If there is no ep port (no "enabled" input) then this is a // tran branch. Assume it is always enabled. if (ep == 0) { - enabled_flag = true; + state = tran_enabled; return true; } @@ -122,7 +128,6 @@ bool vvp_island_branch_tran::run_test_enabled() // // If the outvalue is nil, then we know that this port is a // .import after all, so just read the invalue. - enabled_flag = false; vvp_bit4_t enable_val; if (ep->outvalue.size() != 0) enable_val = ep->outvalue.value(0).value(); @@ -131,14 +136,47 @@ bool vvp_island_branch_tran::run_test_enabled() else enable_val = ep->invalue.value(0).value(); - if (active_high==true && enable_val != BIT4_1) - return false; + switch (enable_val) { + case BIT4_0: + state = active_high ? tran_disabled : tran_enabled; + break; + case BIT4_1: + state = active_high ? tran_enabled : tran_disabled; + break; + default: + state = tran_unknown; + break; + } + return (state != tran_disabled); +} - if (active_high==false && enable_val != BIT4_0) - return false; +// The IEEE standard does not specify the behaviour when a tranif control +// input is 'x' or 'z'. We use the rules that are given for MOS switches. +inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a, + const vvp_vector8_t&b, + tran_state_t state) +{ + assert(a.size() == b.size()); + vvp_vector8_t out (a.size()); - enabled_flag = true; - return true; + for (unsigned idx = 0 ; idx < out.size() ; idx += 1) { + vvp_scalar_t a_bit = a.value(idx); + vvp_scalar_t b_bit = b.value(idx); + if (state == tran_unknown) { + switch (b_bit.value()) { + case BIT4_0: + b_bit = vvp_scalar_t(BIT4_X, b_bit.strength0(), 0); + break; + case BIT4_1: + b_bit = vvp_scalar_t(BIT4_X, 0, b_bit.strength1()); + break; + default: + break; + } + } + out.set_bit(idx, resolve(a_bit, b_bit)); + } + return out; } static void push_value_through_branches(const vvp_vector8_t&val, @@ -149,8 +187,8 @@ static void push_value_through_branch(const vvp_vector8_t&val, { vvp_island_branch_tran*branch = BRANCH_TRAN(cur.ptr()); - // If the branch is not enabled, skip. - if (! branch->enabled_flag) + // If the branch is disabled, skip. + if (branch->state == tran_disabled) return; unsigned src_ab = cur.port(); @@ -174,7 +212,8 @@ static void push_value_through_branch(const vvp_vector8_t&val, // previously collected (and resolved) for the port. if (branch->width == 0) { // There are no part selects. - dst_port->value = resolve(dst_port->value, val); + dst_port->value = resolve_ambiguous(dst_port->value, val, + branch->state); } else if (dst_ab == 1) { // The other side is a strict subset (part select)