An optimized mux should use MOS devices not bufif devices.

The bufif devices do not correctly propagate the Z value as
required by the standard. The MOS devices do propagate a Z
value, but they do not correctly handle the case where both
inputs are Z and the select is undefined/Z. The standard
specifies that this should be X, but we produce Z. The full
MUX and %blend operator also function this way, so Icarus
may not match the standard, but it is consistent. I would
also argue that the standard is incorrect. If both inputs
are Z then the output should be Z no matter what select is.
This commit is contained in:
Cary R 2008-10-17 10:34:18 -07:00 committed by Stephen Williams
parent a654bdc169
commit de2b10b445
1 changed files with 12 additions and 31 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2008 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
@ -739,7 +739,7 @@ v }
}
}
static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
static void replace_with_mos(Design*des, NetMux*obj, NetLogic::TYPE type)
{
NetScope*scope = obj->scope();
NetLogic*tmp = new NetLogic(obj->scope(),
@ -749,7 +749,7 @@ static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
des->add_node(tmp);
connect(obj->pin_Result(), tmp->pin(0));
connect(obj->pin_Data(type==NetLogic::BUFIF0? 0 : 1), tmp->pin(1));
connect(obj->pin_Data(type==NetLogic::PMOS? 0 : 1), tmp->pin(1));
if (obj->width() == 1) {
/* Special case that the expression is 1 bit
@ -794,44 +794,26 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
return;
/* If the first input is all constant Vz, then replace the
NetMux with an array of BUFIF1 devices, with the enable
NetMux with an array of NMOS devices, with the enable
connected to the select input. */
bool flag = true;
if (! obj->pin_Data(0).nexus()->drivers_constant()) {
flag = false;
}
if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) {
flag = false;
}
if (flag) {
replace_with_bufif(des, obj, NetLogic::BUFIF1);
if (obj->pin_Data(0).nexus()->drivers_constant() &&
obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) {
replace_with_mos(des, obj, NetLogic::NMOS);
count += 1;
return;
}
/* If instead the second input is all constant Vz, replace the
NetMux with an array of BUFIF0 devices. */
flag = true;
if (! obj->pin_Data(1).nexus()->drivers_constant()) {
flag = false;
}
if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) {
flag = false;
}
if (flag) {
replace_with_bufif(des, obj, NetLogic::BUFIF0);
NetMux with an array of PMOS devices. */
if (obj->pin_Data(1).nexus()->drivers_constant() &&
obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) {
replace_with_mos(des, obj, NetLogic::PMOS);
count += 1;
return;
}
/* If the select input is constant, then replace with a BUFZ */
flag = obj->pin_Sel().nexus()->drivers_constant();
bool flag = obj->pin_Sel().nexus()->drivers_constant();
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
@ -974,4 +956,3 @@ void cprop(Design*des)
cprop_dc_functor dc;
des->functor(&dc);
}